blob: 09dc80c95f61dd517eccd6d3eaddadd2eaf6a27e [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#pragma once
2
3#include "config.h"
4
5#include "constants.hpp"
6#include "exceptions.hpp"
7#include "logger.hpp"
8#include "types.hpp"
9
10#include <nlohmann/json.hpp>
11#include <utility/common_utility.hpp>
12#include <utility/dbus_utility.hpp>
Rekha Aparnaa39aafa2025-11-04 00:06:12 -060013#include <utility/event_logger_utility.hpp>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050014
15#include <filesystem>
16#include <fstream>
17#include <regex>
Souvik Roy815c6022025-02-20 00:54:24 -060018#include <typeindex>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050019
20namespace vpd
21{
22namespace vpdSpecificUtility
23{
24/**
25 * @brief API to generate file name for bad VPD.
26 *
27 * For i2c eeproms - the pattern of the vpd-name will be
28 * i2c-<bus-number>-<eeprom-address>.
29 * For spi eeproms - the pattern of the vpd-name will be spi-<spi-number>.
30 *
Souvik Roy8fc12522025-02-19 01:28:38 -060031 * @param[in] i_vpdFilePath - file path of the vpd.
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050032 * @param[out] o_errCode - to set error code in case of error.
Souvik Roy8fc12522025-02-19 01:28:38 -060033 *
34 * @return On success, returns generated file name, otherwise returns empty
35 * string.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050036 */
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050037inline std::string generateBadVPDFileName(const std::string& i_vpdFilePath,
38 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050039{
Sunny Srivastavab86675d2025-11-05 18:31:46 +053040 o_errCode = 0;
Souvik Roy0f370432025-04-08 01:55:58 -050041 std::string l_badVpdFileName{constants::badVpdDir};
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050042
43 if (i_vpdFilePath.empty())
44 {
45 o_errCode = error_code::INVALID_INPUT_PARAMETER;
46 return l_badVpdFileName;
47 }
48
Souvik Roy8fc12522025-02-19 01:28:38 -060049 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050050 {
Souvik Roy8fc12522025-02-19 01:28:38 -060051 if (i_vpdFilePath.find("i2c") != std::string::npos)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050052 {
Souvik Roy8fc12522025-02-19 01:28:38 -060053 l_badVpdFileName += "i2c-";
54 std::regex l_i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
55 std::smatch l_match;
56 if (std::regex_search(i_vpdFilePath, l_match, l_i2cPattern))
57 {
58 l_badVpdFileName += l_match.str(2);
59 }
60 }
61 else if (i_vpdFilePath.find("spi") != std::string::npos)
62 {
63 std::regex l_spiPattern("((spi)[0-9]+)(.0)");
64 std::smatch l_match;
65 if (std::regex_search(i_vpdFilePath, l_match, l_spiPattern))
66 {
67 l_badVpdFileName += l_match.str(1);
68 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050069 }
70 }
Souvik Roy8fc12522025-02-19 01:28:38 -060071 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050072 {
Souvik Roy8fc12522025-02-19 01:28:38 -060073 l_badVpdFileName.clear();
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050074 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050075 }
Souvik Roy8fc12522025-02-19 01:28:38 -060076 return l_badVpdFileName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050077}
78
79/**
80 * @brief API which dumps the broken/bad vpd in a directory.
81 * When the vpd is bad, this API places the bad vpd file inside
Souvik Roy0f370432025-04-08 01:55:58 -050082 * "/var/lib/vpd/dumps" in BMC, in order to collect bad VPD data as a part of
83 * user initiated BMC dump.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050084 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050085 *
Souvik Roy8fc12522025-02-19 01:28:38 -060086 * @param[in] i_vpdFilePath - vpd file path
87 * @param[in] i_vpdVector - vpd vector
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050088 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy8fc12522025-02-19 01:28:38 -060089 *
90 * @return On success returns 0, otherwise returns -1.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050091 */
Souvik Roy8fc12522025-02-19 01:28:38 -060092inline int dumpBadVpd(const std::string& i_vpdFilePath,
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050093 const types::BinaryVector& i_vpdVector,
94 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050095{
Sunny Srivastavab86675d2025-11-05 18:31:46 +053096 o_errCode = 0;
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050097 if (i_vpdFilePath.empty() || i_vpdVector.empty())
98 {
99 o_errCode = error_code::INVALID_INPUT_PARAMETER;
100 return constants::FAILURE;
101 }
102
Souvik Roy8fc12522025-02-19 01:28:38 -0600103 int l_rc{constants::FAILURE};
104 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500105 {
Souvik Roy0f370432025-04-08 01:55:58 -0500106 std::filesystem::create_directory(constants::badVpdDir);
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -0500107 auto l_badVpdPath = generateBadVPDFileName(i_vpdFilePath, o_errCode);
Souvik Roy8fc12522025-02-19 01:28:38 -0600108
109 if (l_badVpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500110 {
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -0500111 if (o_errCode)
112 {
113 logging::logMessage("Failed to create bad VPD file name : " +
114 commonUtility::getErrCodeMsg(o_errCode));
115 }
116
117 return constants::FAILURE;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500118 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500119
Souvik Roy8fc12522025-02-19 01:28:38 -0600120 if (std::filesystem::exists(l_badVpdPath))
121 {
122 std::error_code l_ec;
123 std::filesystem::remove(l_badVpdPath, l_ec);
124 if (l_ec) // error code
125 {
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -0500126 o_errCode = error_code::FILE_SYSTEM_ERROR;
127 return constants::FAILURE;
Souvik Roy8fc12522025-02-19 01:28:38 -0600128 }
129 }
130
131 std::ofstream l_badVpdFileStream(l_badVpdPath, std::ofstream::binary);
132 if (!l_badVpdFileStream.is_open())
133 {
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -0500134 o_errCode = error_code::FILE_ACCESS_ERROR;
135 return constants::FAILURE;
Souvik Roy8fc12522025-02-19 01:28:38 -0600136 }
137
138 l_badVpdFileStream.write(
139 reinterpret_cast<const char*>(i_vpdVector.data()),
140 i_vpdVector.size());
141
142 l_rc = constants::SUCCESS;
143 }
144 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500145 {
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -0500146 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500147 }
Souvik Roy8fc12522025-02-19 01:28:38 -0600148 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500149}
150
151/**
152 * @brief An API to read value of a keyword.
153 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500154 *
Souvik Roya55fcca2025-02-19 01:33:58 -0600155 * @param[in] i_kwdValueMap - A map having Kwd value pair.
156 * @param[in] i_kwd - keyword name.
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500157 * @param[out] o_errCode - To set error code in case of error.
Souvik Roya55fcca2025-02-19 01:33:58 -0600158 *
159 * @return On success returns value of the keyword read from map, otherwise
160 * returns empty string.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500161 */
Souvik Roya55fcca2025-02-19 01:33:58 -0600162inline std::string getKwVal(const types::IPZKwdValueMap& i_kwdValueMap,
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500163 const std::string& i_kwd,
164 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500165{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530166 o_errCode = 0;
Souvik Roya55fcca2025-02-19 01:33:58 -0600167 std::string l_kwdValue;
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500168 if (i_kwd.empty() || i_kwdValueMap.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500169 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500170 o_errCode = error_code::INVALID_INPUT_PARAMETER;
171 return l_kwdValue;
172 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500173
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500174 auto l_itrToKwd = i_kwdValueMap.find(i_kwd);
175 if (l_itrToKwd != i_kwdValueMap.end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500176 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500177 l_kwdValue = l_itrToKwd->second;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500178 }
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500179 else
180 {
181 o_errCode = error_code::KEYWORD_NOT_FOUND;
182 }
183
Souvik Roya55fcca2025-02-19 01:33:58 -0600184 return l_kwdValue;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500185}
186
187/**
188 * @brief An API to process encoding of a keyword.
189 *
Souvik Royf277d6a2025-02-20 00:08:43 -0600190 * @param[in] i_keyword - Keyword to be processed.
191 * @param[in] i_encoding - Type of encoding.
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500192 * @param[out] o_errCode - To set error code in case of error.
Souvik Royf277d6a2025-02-20 00:08:43 -0600193 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500194 * @return Value after being processed for encoded type.
195 */
Souvik Royf277d6a2025-02-20 00:08:43 -0600196inline std::string encodeKeyword(const std::string& i_keyword,
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500197 const std::string& i_encoding,
198 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500199{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530200 o_errCode = 0;
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500201 if (i_keyword.empty())
202 {
203 o_errCode = error_code::INVALID_INPUT_PARAMETER;
204 return std::string{};
205 }
206
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500207 // Default value is keyword value
Souvik Royf277d6a2025-02-20 00:08:43 -0600208 std::string l_result(i_keyword.begin(), i_keyword.end());
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500209
210 if (i_encoding.empty())
211 {
212 return l_result;
213 }
214
Souvik Royf277d6a2025-02-20 00:08:43 -0600215 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500216 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600217 if (i_encoding == "MAC")
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500218 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600219 l_result.clear();
220 size_t l_firstByte = i_keyword[0];
Rekha Aparnabffecd92025-04-08 13:01:41 -0500221
222 auto l_hexValue = commonUtility::toHex(l_firstByte >> 4);
223
224 if (!l_hexValue)
225 {
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500226 o_errCode = error_code::OUT_OF_BOUND_EXCEPTION;
227 return std::string{};
Rekha Aparnabffecd92025-04-08 13:01:41 -0500228 }
229
230 l_result += l_hexValue;
231
232 l_hexValue = commonUtility::toHex(l_firstByte & 0x0f);
233
234 if (!l_hexValue)
235 {
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500236 o_errCode = error_code::OUT_OF_BOUND_EXCEPTION;
237 return std::string{};
Rekha Aparnabffecd92025-04-08 13:01:41 -0500238 }
239
240 l_result += l_hexValue;
241
Souvik Royf277d6a2025-02-20 00:08:43 -0600242 for (size_t i = 1; i < i_keyword.size(); ++i)
243 {
244 l_result += ":";
Rekha Aparnabffecd92025-04-08 13:01:41 -0500245
246 l_hexValue = commonUtility::toHex(i_keyword[i] >> 4);
247
248 if (!l_hexValue)
249 {
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500250 o_errCode = error_code::OUT_OF_BOUND_EXCEPTION;
251 return std::string{};
Rekha Aparnabffecd92025-04-08 13:01:41 -0500252 }
253
254 l_result += l_hexValue;
255
256 l_hexValue = commonUtility::toHex(i_keyword[i] & 0x0f);
257
258 if (!l_hexValue)
259 {
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500260 o_errCode = error_code::OUT_OF_BOUND_EXCEPTION;
261 return std::string{};
Rekha Aparnabffecd92025-04-08 13:01:41 -0500262 }
263
264 l_result += l_hexValue;
Souvik Royf277d6a2025-02-20 00:08:43 -0600265 }
266 }
267 else if (i_encoding == "DATE")
268 {
269 // Date, represent as
270 // <year>-<month>-<day> <hour>:<min>
271 l_result.clear();
272 static constexpr uint8_t skipPrefix = 3;
273
274 auto strItr = i_keyword.begin();
275 advance(strItr, skipPrefix);
276 for_each(strItr, i_keyword.end(),
277 [&l_result](size_t c) { l_result += c; });
278
279 l_result.insert(constants::BD_YEAR_END, 1, '-');
280 l_result.insert(constants::BD_MONTH_END, 1, '-');
281 l_result.insert(constants::BD_DAY_END, 1, ' ');
282 l_result.insert(constants::BD_HOUR_END, 1, ':');
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500283 }
284 }
Souvik Royf277d6a2025-02-20 00:08:43 -0600285 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500286 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600287 l_result.clear();
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500288 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500289 }
290
Souvik Royf277d6a2025-02-20 00:08:43 -0600291 return l_result;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500292}
293
294/**
295 * @brief Helper function to insert or merge in map.
296 *
297 * This method checks in an interface if the given interface exists. If the
298 * interface key already exists, property map is inserted corresponding to it.
299 * If the key does'nt exist then given interface and property map pair is newly
300 * created. If the property present in propertymap already exist in the
301 * InterfaceMap, then the new property value is ignored.
302 *
Souvik Royfa47e6c2025-02-20 00:17:25 -0600303 * @param[in,out] io_map - Interface map.
304 * @param[in] i_interface - Interface to be processed.
305 * @param[in] i_propertyMap - new property map that needs to be emplaced.
Rekha Aparnad3662222025-10-14 10:33:17 -0500306 * @param[out] o_errCode - To set error code in case of error.
Souvik Royfa47e6c2025-02-20 00:17:25 -0600307 *
308 * @return On success returns 0, otherwise returns -1.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500309 */
Souvik Royfa47e6c2025-02-20 00:17:25 -0600310inline int insertOrMerge(types::InterfaceMap& io_map,
311 const std::string& i_interface,
Rekha Aparnad3662222025-10-14 10:33:17 -0500312 types::PropertyMap&& i_propertyMap,
313 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500314{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530315 o_errCode = 0;
Souvik Royfa47e6c2025-02-20 00:17:25 -0600316 int l_rc{constants::FAILURE};
Rekha Aparnad3662222025-10-14 10:33:17 -0500317
Souvik Royfa47e6c2025-02-20 00:17:25 -0600318 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500319 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600320 if (io_map.find(i_interface) != io_map.end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500321 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600322 auto& l_prop = io_map.at(i_interface);
323 std::for_each(i_propertyMap.begin(), i_propertyMap.end(),
324 [&l_prop](auto l_keyValue) {
325 l_prop[l_keyValue.first] = l_keyValue.second;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500326 });
327 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600328 else
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500329 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600330 io_map.emplace(i_interface, i_propertyMap);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500331 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600332
333 l_rc = constants::SUCCESS;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500334 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600335 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500336 {
Rekha Aparnad3662222025-10-14 10:33:17 -0500337 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500338 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600339 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500340}
341
342/**
343 * @brief API to expand unpanded location code.
344 *
345 * Note: The API handles all the exception internally, in case of any error
346 * unexpanded location code will be returned as it is.
347 *
348 * @param[in] unexpandedLocationCode - Unexpanded location code.
349 * @param[in] parsedVpdMap - Parsed VPD map.
Rekha Aparna6256db92025-10-17 09:58:49 -0500350 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500351 * @return Expanded location code. In case of any error, unexpanded is returned
352 * as it is.
353 */
Patrick Williams43fedab2025-02-03 14:28:05 -0500354inline std::string getExpandedLocationCode(
355 const std::string& unexpandedLocationCode,
Rekha Aparna6256db92025-10-17 09:58:49 -0500356 const types::VPDMapVariant& parsedVpdMap, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500357{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530358 o_errCode = 0;
Rekha Aparna6256db92025-10-17 09:58:49 -0500359 if (unexpandedLocationCode.empty() ||
360 std::holds_alternative<std::monostate>(parsedVpdMap))
361 {
362 o_errCode = error_code::INVALID_INPUT_PARAMETER;
363 return unexpandedLocationCode;
364 }
365
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500366 auto expanded{unexpandedLocationCode};
367
368 try
369 {
370 // Expanded location code is formed by combining two keywords
371 // depending on type in unexpanded one. Second one is always "SE".
372 std::string kwd1, kwd2{constants::kwdSE};
373
374 // interface to search for required keywords;
375 std::string kwdInterface;
376
377 // record which holds the required keywords.
378 std::string recordName;
379
380 auto pos = unexpandedLocationCode.find("fcs");
381 if (pos != std::string::npos)
382 {
383 kwd1 = constants::kwdFC;
384 kwdInterface = constants::vcenInf;
385 recordName = constants::recVCEN;
386 }
387 else
388 {
389 pos = unexpandedLocationCode.find("mts");
390 if (pos != std::string::npos)
391 {
392 kwd1 = constants::kwdTM;
393 kwdInterface = constants::vsysInf;
394 recordName = constants::recVSYS;
395 }
396 else
397 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500398 o_errCode = error_code::FAILED_TO_DETECT_LOCATION_CODE_TYPE;
399 return expanded;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500400 }
401 }
402
403 std::string firstKwdValue, secondKwdValue;
404
405 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap);
406 ipzVpdMap && (*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
407 {
408 auto itrToVCEN = (*ipzVpdMap).find(recordName);
Rekha Aparna6256db92025-10-17 09:58:49 -0500409 firstKwdValue = getKwVal(itrToVCEN->second, kwd1, o_errCode);
Souvik Roya55fcca2025-02-19 01:33:58 -0600410 if (firstKwdValue.empty())
411 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500412 o_errCode = error_code::KEYWORD_NOT_FOUND;
413 return expanded;
Souvik Roya55fcca2025-02-19 01:33:58 -0600414 }
415
Rekha Aparna6256db92025-10-17 09:58:49 -0500416 secondKwdValue = getKwVal(itrToVCEN->second, kwd2, o_errCode);
Souvik Roya55fcca2025-02-19 01:33:58 -0600417 if (secondKwdValue.empty())
418 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500419 o_errCode = error_code::KEYWORD_NOT_FOUND;
420 return expanded;
Souvik Roya55fcca2025-02-19 01:33:58 -0600421 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500422 }
423 else
424 {
Anupama B R68a70432025-09-25 02:09:37 -0500425 std::vector<std::string> interfaceList = {kwdInterface};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500426
427 types::MapperGetObject mapperRetValue = dbusUtility::getObjectMap(
428 std::string(constants::systemVpdInvPath), interfaceList);
429
430 if (mapperRetValue.empty())
431 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500432 o_errCode = error_code::DBUS_FAILURE;
433 return expanded;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500434 }
435
436 const std::string& serviceName = std::get<0>(mapperRetValue.at(0));
437
438 auto retVal = dbusUtility::readDbusProperty(
439 serviceName, std::string(constants::systemVpdInvPath),
440 kwdInterface, kwd1);
441
442 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
443 {
444 firstKwdValue.assign(
445 reinterpret_cast<const char*>(kwdVal->data()),
446 kwdVal->size());
447 }
448 else
449 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500450 o_errCode = error_code::RECEIVED_INVALID_KWD_TYPE_FROM_DBUS;
451 return expanded;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500452 }
453
454 retVal = dbusUtility::readDbusProperty(
455 serviceName, std::string(constants::systemVpdInvPath),
456 kwdInterface, kwd2);
457
458 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
459 {
460 secondKwdValue.assign(
461 reinterpret_cast<const char*>(kwdVal->data()),
462 kwdVal->size());
463 }
464 else
465 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500466 o_errCode = error_code::RECEIVED_INVALID_KWD_TYPE_FROM_DBUS;
467 return expanded;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500468 }
469 }
470
471 if (unexpandedLocationCode.find("fcs") != std::string::npos)
472 {
473 // TODO: See if ND0 can be placed in the JSON
474 expanded.replace(
475 pos, 3, firstKwdValue.substr(0, 4) + ".ND0." + secondKwdValue);
476 }
477 else
478 {
479 replace(firstKwdValue.begin(), firstKwdValue.end(), '-', '.');
480 expanded.replace(pos, 3, firstKwdValue + "." + secondKwdValue);
481 }
482 }
483 catch (const std::exception& ex)
484 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500485 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500486 }
487
488 return expanded;
489}
490
491/**
492 * @brief An API to get VPD in a vector.
493 *
494 * The vector is required by the respective parser to fill the VPD map.
495 * Note: API throws exception in case of failure. Caller needs to handle.
496 *
497 * @param[in] vpdFilePath - EEPROM path of the FRU.
498 * @param[out] vpdVector - VPD in vector form.
499 * @param[in] vpdStartOffset - Offset of VPD data in EEPROM.
Rekha Aparna769d6572025-10-22 09:50:35 -0500500 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500501 */
502inline void getVpdDataInVector(const std::string& vpdFilePath,
503 types::BinaryVector& vpdVector,
Rekha Aparna769d6572025-10-22 09:50:35 -0500504 size_t& vpdStartOffset, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500505{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530506 o_errCode = 0;
Rekha Aparna769d6572025-10-22 09:50:35 -0500507 if (vpdFilePath.empty())
508 {
509 o_errCode = error_code::INVALID_INPUT_PARAMETER;
510 return;
511 }
512
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500513 try
514 {
515 std::fstream vpdFileStream;
516 vpdFileStream.exceptions(
517 std::ifstream::badbit | std::ifstream::failbit);
518 vpdFileStream.open(vpdFilePath, std::ios::in | std::ios::binary);
519 auto vpdSizeToRead = std::min(std::filesystem::file_size(vpdFilePath),
520 static_cast<uintmax_t>(65504));
521 vpdVector.resize(vpdSizeToRead);
522
523 vpdFileStream.seekg(vpdStartOffset, std::ios_base::beg);
524 vpdFileStream.read(reinterpret_cast<char*>(&vpdVector[0]),
525 vpdSizeToRead);
526
527 vpdVector.resize(vpdFileStream.gcount());
528 vpdFileStream.clear(std::ios_base::eofbit);
529 }
530 catch (const std::ifstream::failure& fail)
531 {
Rekha Aparna769d6572025-10-22 09:50:35 -0500532 o_errCode = error_code::FILE_SYSTEM_ERROR;
533 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500534 }
535}
536
537/**
538 * @brief An API to get D-bus representation of given VPD keyword.
539 *
540 * @param[in] i_keywordName - VPD keyword name.
Rekha Aparna769d6572025-10-22 09:50:35 -0500541 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500542 *
543 * @return D-bus representation of given keyword.
544 */
Rekha Aparna769d6572025-10-22 09:50:35 -0500545inline std::string getDbusPropNameForGivenKw(const std::string& i_keywordName,
546 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500547{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530548 o_errCode = 0;
Rekha Aparna769d6572025-10-22 09:50:35 -0500549 if (i_keywordName.empty())
550 {
551 o_errCode = error_code::INVALID_INPUT_PARAMETER;
552 return std::string{};
553 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500554 // Check for "#" prefixed VPD keyword.
555 if ((i_keywordName.size() == vpd::constants::TWO_BYTES) &&
556 (i_keywordName.at(0) == constants::POUND_KW))
557 {
558 // D-bus doesn't support "#". Replace "#" with "PD_" for those "#"
559 // prefixed keywords.
560 return (std::string(constants::POUND_KW_PREFIX) +
561 i_keywordName.substr(1));
562 }
563
564 // Return the keyword name back, if D-bus representation is same as the VPD
565 // keyword name.
566 return i_keywordName;
567}
568
569/**
570 * @brief API to find CCIN in parsed VPD map.
571 *
572 * Few FRUs need some special handling. To identify those FRUs CCIN are used.
573 * The API will check from parsed VPD map if the FRU is the one with desired
574 * CCIN.
575 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500576 * @param[in] i_JsonObject - Any JSON which contains CCIN tag to match.
577 * @param[in] i_parsedVpdMap - Parsed VPD map.
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500578 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy815c6022025-02-20 00:54:24 -0600579 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500580 * @return True if found, false otherwise.
581 */
582inline bool findCcinInVpd(const nlohmann::json& i_JsonObject,
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500583 const types::VPDMapVariant& i_parsedVpdMap,
584 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500585{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530586 o_errCode = 0;
Souvik Roy815c6022025-02-20 00:54:24 -0600587 bool l_rc{false};
588 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500589 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500590 if (i_JsonObject.empty() ||
591 std::holds_alternative<std::monostate>(i_parsedVpdMap))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500592 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500593 o_errCode = error_code::INVALID_INPUT_PARAMETER;
594 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500595 }
596
Souvik Roy815c6022025-02-20 00:54:24 -0600597 if (auto l_ipzVPDMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500598 {
Souvik Roy815c6022025-02-20 00:54:24 -0600599 auto l_itrToRec = (*l_ipzVPDMap).find("VINI");
600 if (l_itrToRec == (*l_ipzVPDMap).end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500601 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500602 o_errCode = error_code::RECORD_NOT_FOUND;
603 return l_rc;
Souvik Roy815c6022025-02-20 00:54:24 -0600604 }
605
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500606 std::string l_ccinFromVpd{vpdSpecificUtility::getKwVal(
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500607 l_itrToRec->second, "CC", o_errCode)};
Souvik Roy815c6022025-02-20 00:54:24 -0600608 if (l_ccinFromVpd.empty())
609 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500610 o_errCode = error_code::KEYWORD_NOT_FOUND;
611 return l_rc;
Souvik Roy815c6022025-02-20 00:54:24 -0600612 }
613
614 transform(l_ccinFromVpd.begin(), l_ccinFromVpd.end(),
615 l_ccinFromVpd.begin(), ::toupper);
616
617 for (std::string l_ccinValue : i_JsonObject["ccin"])
618 {
619 transform(l_ccinValue.begin(), l_ccinValue.end(),
620 l_ccinValue.begin(), ::toupper);
621
622 if (l_ccinValue.compare(l_ccinFromVpd) ==
623 constants::STR_CMP_SUCCESS)
624 {
625 // CCIN found
626 l_rc = true;
627 }
628 }
629
630 if (!l_rc)
631 {
632 logging::logMessage("No match found for CCIN");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500633 }
634 }
Souvik Roy815c6022025-02-20 00:54:24 -0600635 else
636 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500637 o_errCode = error_code::UNSUPPORTED_VPD_TYPE;
Souvik Roy815c6022025-02-20 00:54:24 -0600638 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500639 }
Souvik Roy815c6022025-02-20 00:54:24 -0600640 catch (const std::exception& l_ex)
641 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500642 o_errCode = error_code::STANDARD_EXCEPTION;
Souvik Roy815c6022025-02-20 00:54:24 -0600643 }
644 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500645}
646
647/**
648 * @brief API to reset data of a FRU populated under PIM.
649 *
650 * This API resets the data for particular interfaces of a FRU under PIM.
651 *
652 * @param[in] i_objectPath - DBus object path of the FRU.
653 * @param[in] io_interfaceMap - Interface and its properties map.
Rekha Aparna2c04eeb2025-10-22 22:15:07 -0500654 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500655 */
656inline void resetDataUnderPIM(const std::string& i_objectPath,
Rekha Aparna2c04eeb2025-10-22 22:15:07 -0500657 types::InterfaceMap& io_interfaceMap,
658 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500659{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530660 o_errCode = 0;
Rekha Aparna2c04eeb2025-10-22 22:15:07 -0500661 if (i_objectPath.empty())
662 {
663 o_errCode = error_code::INVALID_INPUT_PARAMETER;
664 return;
665 }
666
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500667 try
668 {
Anupama B R68a70432025-09-25 02:09:37 -0500669 std::vector<std::string> l_interfaces;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500670 const types::MapperGetObject& l_getObjectMap =
671 dbusUtility::getObjectMap(i_objectPath, l_interfaces);
672
673 const std::vector<std::string>& l_vpdRelatedInterfaces{
674 constants::operationalStatusInf, constants::inventoryItemInf,
Anupama B Rffa488f2025-05-22 07:34:00 -0500675 constants::assetInf, constants::vpdCollectionInterface};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500676
677 for (const auto& [l_service, l_interfaceList] : l_getObjectMap)
678 {
679 if (l_service.compare(constants::pimServiceName) !=
680 constants::STR_CMP_SUCCESS)
681 {
682 continue;
683 }
684
685 for (const auto& l_interface : l_interfaceList)
686 {
687 if ((l_interface.find(constants::ipzVpdInf) !=
Anupama B R4ed13db2025-11-10 00:54:35 -0600688 std::string::npos &&
689 l_interface != constants::locationCodeInf) ||
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500690 ((std::find(l_vpdRelatedInterfaces.begin(),
691 l_vpdRelatedInterfaces.end(), l_interface)) !=
692 l_vpdRelatedInterfaces.end()))
693 {
694 const types::PropertyMap& l_propertyValueMap =
695 dbusUtility::getPropertyMap(l_service, i_objectPath,
696 l_interface);
697
698 types::PropertyMap l_propertyMap;
699
700 for (const auto& l_aProperty : l_propertyValueMap)
701 {
702 const std::string& l_propertyName = l_aProperty.first;
703 const auto& l_propertyValue = l_aProperty.second;
704
705 if (std::holds_alternative<types::BinaryVector>(
706 l_propertyValue))
707 {
708 l_propertyMap.emplace(l_propertyName,
709 types::BinaryVector{});
710 }
711 else if (std::holds_alternative<std::string>(
712 l_propertyValue))
713 {
Anupama B R5cd1b2d2025-08-05 04:57:40 -0500714 if (l_propertyName.compare("Status") ==
Anupama B Rffa488f2025-05-22 07:34:00 -0500715 constants::STR_CMP_SUCCESS)
716 {
717 l_propertyMap.emplace(
718 l_propertyName,
719 constants::vpdCollectionNotStarted);
Anupama B R4c65fcd2025-09-01 08:09:00 -0500720 l_propertyMap.emplace("StartTime", 0);
721 l_propertyMap.emplace("CompletedTime", 0);
Anupama B Rffa488f2025-05-22 07:34:00 -0500722 }
723 else
724 {
725 l_propertyMap.emplace(l_propertyName,
726 std::string{});
727 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500728 }
729 else if (std::holds_alternative<bool>(l_propertyValue))
730 {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500731 if (l_propertyName.compare("Present") ==
732 constants::STR_CMP_SUCCESS)
733 {
734 l_propertyMap.emplace(l_propertyName, false);
735 }
Rekha Aparna4f722062025-05-02 03:39:32 -0500736 else if (l_propertyName.compare("Functional") ==
737 constants::STR_CMP_SUCCESS)
738 {
739 // Since FRU is not present functional property
740 // is considered as true.
741 l_propertyMap.emplace(l_propertyName, true);
742 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500743 }
744 }
745 io_interfaceMap.emplace(l_interface,
746 std::move(l_propertyMap));
747 }
748 }
749 }
750 }
751 catch (const std::exception& l_ex)
752 {
Rekha Aparna2c04eeb2025-10-22 22:15:07 -0500753 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500754 }
755}
Sunny Srivastava78c91072025-02-05 14:09:50 +0530756
757/**
758 * @brief API to detect pass1 planar type.
759 *
760 * Based on HW version and IM keyword, This API detects is it is a pass1 planar
761 * or not.
Rekha Aparna715eaff2025-10-23 02:06:50 -0500762 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastava78c91072025-02-05 14:09:50 +0530763 *
764 * @return True if pass 1 planar, false otherwise.
765 */
Rekha Aparna715eaff2025-10-23 02:06:50 -0500766inline bool isPass1Planar(uint16_t& o_errCode) noexcept
Sunny Srivastava78c91072025-02-05 14:09:50 +0530767{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530768 o_errCode = 0;
Souvik Roy094a7352025-02-20 01:31:45 -0600769 bool l_rc{false};
Rekha Aparna715eaff2025-10-23 02:06:50 -0500770 auto l_retVal = dbusUtility::readDbusProperty(
771 constants::pimServiceName, constants::systemVpdInvPath,
772 constants::viniInf, constants::kwdHW);
773
774 auto l_hwVer = std::get_if<types::BinaryVector>(&l_retVal);
775
776 l_retVal = dbusUtility::readDbusProperty(
777 constants::pimServiceName, constants::systemInvPath, constants::vsbpInf,
778 constants::kwdIM);
779
780 auto l_imValue = std::get_if<types::BinaryVector>(&l_retVal);
781
782 if (l_hwVer && l_imValue)
Sunny Srivastava78c91072025-02-05 14:09:50 +0530783 {
Rekha Aparna715eaff2025-10-23 02:06:50 -0500784 if (l_hwVer->size() != constants::VALUE_2)
Sunny Srivastava78c91072025-02-05 14:09:50 +0530785 {
Rekha Aparna715eaff2025-10-23 02:06:50 -0500786 o_errCode = error_code::INVALID_KEYWORD_LENGTH;
787 return l_rc;
788 }
Souvik Roy094a7352025-02-20 01:31:45 -0600789
Rekha Aparna715eaff2025-10-23 02:06:50 -0500790 if (l_imValue->size() != constants::VALUE_4)
791 {
792 o_errCode = error_code::INVALID_KEYWORD_LENGTH;
793 return l_rc;
794 }
Souvik Roy094a7352025-02-20 01:31:45 -0600795
Rekha Aparna715eaff2025-10-23 02:06:50 -0500796 const types::BinaryVector l_everest{80, 00, 48, 00};
797 const types::BinaryVector l_fuji{96, 00, 32, 00};
Souvik Roy094a7352025-02-20 01:31:45 -0600798
Rekha Aparna715eaff2025-10-23 02:06:50 -0500799 if (((*l_imValue) == l_everest) || ((*l_imValue) == l_fuji))
800 {
801 if ((*l_hwVer).at(1) < constants::VALUE_21)
Souvik Roy094a7352025-02-20 01:31:45 -0600802 {
803 l_rc = true;
Sunny Srivastava78c91072025-02-05 14:09:50 +0530804 }
805 }
Rekha Aparna715eaff2025-10-23 02:06:50 -0500806 else if ((*l_hwVer).at(1) < constants::VALUE_2)
807 {
808 l_rc = true;
809 }
Sunny Srivastava78c91072025-02-05 14:09:50 +0530810 }
811
Souvik Roy094a7352025-02-20 01:31:45 -0600812 return l_rc;
Sunny Srivastava78c91072025-02-05 14:09:50 +0530813}
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530814
815/**
816 * @brief API to detect if system configuration is that of PowerVS system.
817 *
818 * @param[in] i_imValue - IM value of the system.
Rekha Aparnaed09af82025-10-22 20:34:41 -0500819 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530820 * @return true if it is PowerVS configuration, false otherwise.
821 */
Rekha Aparnaed09af82025-10-22 20:34:41 -0500822inline bool isPowerVsConfiguration(const types::BinaryVector& i_imValue,
823 uint16_t& o_errCode)
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530824{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530825 o_errCode = 0;
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530826 if (i_imValue.empty() || i_imValue.size() != constants::VALUE_4)
827 {
Rekha Aparnaed09af82025-10-22 20:34:41 -0500828 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530829 return false;
830 }
831
832 // Should be a 0x5000XX series system.
833 if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
834 i_imValue.at(1) == constants::HEX_VALUE_00)
835 {
836 std::string l_imagePrefix = dbusUtility::getImagePrefix();
837
838 // Check image for 0x500030XX series.
839 if ((i_imValue.at(2) == constants::HEX_VALUE_30) &&
840 ((l_imagePrefix == constants::powerVsImagePrefix_MY) ||
841 (l_imagePrefix == constants::powerVsImagePrefix_NY)))
842 {
843 logging::logMessage("PowerVS configuration");
844 return true;
845 }
846
847 // Check image for 0X500010XX series.
848 if ((i_imValue.at(2) == constants::HEX_VALUE_10) &&
849 ((l_imagePrefix == constants::powerVsImagePrefix_MZ) ||
850 (l_imagePrefix == constants::powerVsImagePrefix_NZ)))
851 {
852 logging::logMessage("PowerVS configuration");
853 return true;
854 }
855 }
856 return false;
857}
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530858
859/**
860 * @brief API to get CCIN for a given FRU from DBus.
861 *
862 * The API reads the CCIN for a FRU based on its inventory path.
863 *
864 * @param[in] i_invObjPath - Inventory path of the FRU.
Rekha Aparna80b674f2025-10-27 01:27:27 -0500865 * @param[out] o_errCode - To set error code in case of error.
866 *
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530867 * @return CCIN of the FRU on success, empty string otherwise.
868 */
Rekha Aparna80b674f2025-10-27 01:27:27 -0500869inline std::string getCcinFromDbus(const std::string& i_invObjPath,
870 uint16_t& o_errCode)
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530871{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530872 o_errCode = 0;
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530873 try
874 {
875 if (i_invObjPath.empty())
876 {
Rekha Aparna80b674f2025-10-27 01:27:27 -0500877 o_errCode = error_code::INVALID_INPUT_PARAMETER;
878 return std::string{};
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530879 }
880
881 const auto& l_retValue = dbusUtility::readDbusProperty(
882 constants::pimServiceName, i_invObjPath, constants::viniInf,
883 constants::kwdCCIN);
884
885 auto l_ptrCcin = std::get_if<types::BinaryVector>(&l_retValue);
Rekha Aparna80b674f2025-10-27 01:27:27 -0500886
887 if (!l_ptrCcin)
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530888 {
Rekha Aparna80b674f2025-10-27 01:27:27 -0500889 o_errCode = error_code::RECEIVED_INVALID_KWD_TYPE_FROM_DBUS;
890 return std::string{};
891 }
892
893 if ((*l_ptrCcin).size() != constants::VALUE_4)
894 {
895 o_errCode = error_code::INVALID_VALUE_READ_FROM_DBUS;
896 return std::string{};
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530897 }
898
899 return std::string((*l_ptrCcin).begin(), (*l_ptrCcin).end());
900 }
901 catch (const std::exception& l_ex)
902 {
Rekha Aparna80b674f2025-10-27 01:27:27 -0500903 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530904 return std::string{};
905 }
906}
Sunny Srivastavaecfaa212025-03-24 13:02:13 +0530907
908/**
909 * @brief API to check if the current running image is a powerVS image.
910 *
911 * @return true if it is PowerVS image, false otherwise.
912 */
913inline bool isPowerVsImage()
914{
915 std::string l_imagePrefix = dbusUtility::getImagePrefix();
916
917 if ((l_imagePrefix == constants::powerVsImagePrefix_MY) ||
918 (l_imagePrefix == constants::powerVsImagePrefix_NY) ||
919 (l_imagePrefix == constants::powerVsImagePrefix_MZ) ||
920 (l_imagePrefix == constants::powerVsImagePrefix_NZ))
921 {
922 return true;
923 }
924 return false;
925}
Souvik Roy2ee8a212025-04-24 02:37:59 -0500926
927/**
928 * @brief API to sync keyword update to inherited FRUs.
929 *
930 * For a given keyword update on a EEPROM path, this API syncs the keyword
931 * update to all inherited FRUs' respective interface, property on PIM.
932 *
933 * @param[in] i_fruPath - EEPROM path of FRU.
934 * @param[in] i_paramsToWriteData - Input details.
935 * @param[in] i_sysCfgJsonObj - System config JSON.
Rekha Aparna1324ed52025-10-27 03:26:33 -0500936 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy2ee8a212025-04-24 02:37:59 -0500937 *
938 */
939inline void updateKwdOnInheritedFrus(
940 const std::string& i_fruPath,
941 const types::WriteVpdParams& i_paramsToWriteData,
Rekha Aparna1324ed52025-10-27 03:26:33 -0500942 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) noexcept
Souvik Roy2ee8a212025-04-24 02:37:59 -0500943{
Sunny Srivastavab86675d2025-11-05 18:31:46 +0530944 o_errCode = 0;
Souvik Roy2ee8a212025-04-24 02:37:59 -0500945 try
946 {
Rekha Aparna1324ed52025-10-27 03:26:33 -0500947 if (i_fruPath.empty() || i_sysCfgJsonObj.empty())
948 {
949 o_errCode = error_code::INVALID_INPUT_PARAMETER;
950 return;
951 }
952
Souvik Roy2ee8a212025-04-24 02:37:59 -0500953 if (!i_sysCfgJsonObj.contains("frus"))
954 {
Rekha Aparna1324ed52025-10-27 03:26:33 -0500955 o_errCode = error_code::INVALID_JSON;
956 return;
Souvik Roy2ee8a212025-04-24 02:37:59 -0500957 }
958
959 if (!i_sysCfgJsonObj["frus"].contains(i_fruPath))
960 {
Rekha Aparna1324ed52025-10-27 03:26:33 -0500961 o_errCode = error_code::FRU_PATH_NOT_FOUND;
962 return;
Souvik Roy2ee8a212025-04-24 02:37:59 -0500963 }
964
965 const types::IpzData* l_ipzData =
966 std::get_if<types::IpzData>(&i_paramsToWriteData);
967
968 if (!l_ipzData)
969 {
Rekha Aparna1324ed52025-10-27 03:26:33 -0500970 o_errCode = error_code::UNSUPPORTED_VPD_TYPE;
971 return;
Souvik Roy2ee8a212025-04-24 02:37:59 -0500972 }
973 // iterate through all inventory paths for given EEPROM path,
974 // except the base FRU.
975 // if for an inventory path, "inherit" tag is true,
976 // update the inventory path's com.ibm.ipzvpd.<record>,keyword
977 // property
978
979 types::ObjectMap l_objectInterfaceMap;
980
981 auto l_populateInterfaceMap =
982 [&l_objectInterfaceMap,
983 &l_ipzData = std::as_const(l_ipzData)](const auto& l_Fru) {
984 // update inherited FRUs only
985 if (l_Fru.value("inherit", true))
986 {
987 l_objectInterfaceMap.emplace(
988 sdbusplus::message::object_path{l_Fru["inventoryPath"]},
989 types::InterfaceMap{
990 {std::string{constants::ipzVpdInf +
991 std::get<0>(*l_ipzData)},
992 types::PropertyMap{{std::get<1>(*l_ipzData),
993 std::get<2>(*l_ipzData)}}}});
994 }
995 };
996
997 // iterate through all FRUs except the base FRU
998 std::for_each(
999 i_sysCfgJsonObj["frus"][i_fruPath].begin() + constants::VALUE_1,
1000 i_sysCfgJsonObj["frus"][i_fruPath].end(), l_populateInterfaceMap);
1001
1002 if (!l_objectInterfaceMap.empty())
1003 {
1004 // notify PIM
1005 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
1006 {
Rekha Aparna1324ed52025-10-27 03:26:33 -05001007 o_errCode = error_code::DBUS_FAILURE;
1008 return;
Souvik Roy2ee8a212025-04-24 02:37:59 -05001009 }
1010 }
1011 }
1012 catch (const std::exception& l_ex)
1013 {
Rekha Aparna1324ed52025-10-27 03:26:33 -05001014 o_errCode = error_code::STANDARD_EXCEPTION;
1015 return;
Souvik Roy2ee8a212025-04-24 02:37:59 -05001016 }
1017}
Souvik Roy96ebe962025-04-29 04:01:07 -05001018
1019/**
1020 * @brief API to get common interface(s) properties corresponding to given
1021 * record and keyword.
1022 *
1023 * For a given record and keyword, this API finds the corresponding common
1024 * interfaces(s) properties from the system config JSON and populates an
1025 * interface map with the respective properties and values.
1026 *
1027 * @param[in] i_paramsToWriteData - Input details.
1028 * @param[in] i_commonInterfaceJson - Common interface JSON object.
Rekha Aparna3fcad142025-10-24 08:16:44 -05001029 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy96ebe962025-04-29 04:01:07 -05001030 *
1031 * @return Returns a map of common interface(s) and properties corresponding to
1032 * the record and keyword. An empty map is returned if no such common
1033 * interface(s) and properties are found.
1034 */
1035inline types::InterfaceMap getCommonInterfaceProperties(
1036 const types::WriteVpdParams& i_paramsToWriteData,
Rekha Aparna3fcad142025-10-24 08:16:44 -05001037 const nlohmann::json& i_commonInterfaceJson, uint16_t& o_errCode) noexcept
Souvik Roy96ebe962025-04-29 04:01:07 -05001038{
1039 types::InterfaceMap l_interfaceMap;
Sunny Srivastavab86675d2025-11-05 18:31:46 +05301040 o_errCode = 0;
Souvik Roy96ebe962025-04-29 04:01:07 -05001041 try
1042 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001043 if (i_commonInterfaceJson.empty())
1044 {
1045 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1046 return l_interfaceMap;
1047 }
1048
Souvik Roy96ebe962025-04-29 04:01:07 -05001049 const types::IpzData* l_ipzData =
1050 std::get_if<types::IpzData>(&i_paramsToWriteData);
1051
1052 if (!l_ipzData)
1053 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001054 o_errCode = error_code::UNSUPPORTED_VPD_TYPE;
1055 return l_interfaceMap;
Souvik Roy96ebe962025-04-29 04:01:07 -05001056 }
1057
1058 auto l_populateInterfaceMap = [&l_ipzData = std::as_const(l_ipzData),
Rekha Aparna3fcad142025-10-24 08:16:44 -05001059 &l_interfaceMap, &o_errCode](
Souvik Roy96ebe962025-04-29 04:01:07 -05001060 const auto& l_interfacesPropPair) {
Souvik Roy9654e032025-09-17 17:18:42 +00001061 if (l_interfacesPropPair.value().empty())
1062 {
1063 return;
1064 }
1065
Souvik Roy96ebe962025-04-29 04:01:07 -05001066 // find matching property value pair
1067 const auto l_matchPropValuePairIt = std::find_if(
1068 l_interfacesPropPair.value().items().begin(),
1069 l_interfacesPropPair.value().items().end(),
1070 [&l_ipzData](const auto& l_propValuePair) {
1071 return (l_propValuePair.value().value("recordName", "") ==
1072 std::get<0>(*l_ipzData) &&
1073 l_propValuePair.value().value("keywordName", "") ==
1074 std::get<1>(*l_ipzData));
1075 });
1076
1077 if (l_matchPropValuePairIt !=
1078 l_interfacesPropPair.value().items().end())
1079 {
Rekha Aparna17ddfb52025-10-09 20:45:53 -05001080 std::string l_kwd = std::string(std::get<2>(*l_ipzData).begin(),
1081 std::get<2>(*l_ipzData).end());
1082
1083 std::string l_encodedValue = vpdSpecificUtility::encodeKeyword(
1084 l_kwd, l_matchPropValuePairIt.value().value("encoding", ""),
Rekha Aparna3fcad142025-10-24 08:16:44 -05001085 o_errCode);
Rekha Aparna17ddfb52025-10-09 20:45:53 -05001086
Rekha Aparna3fcad142025-10-24 08:16:44 -05001087 if (l_encodedValue.empty() && o_errCode)
Rekha Aparna17ddfb52025-10-09 20:45:53 -05001088 {
1089 logging::logMessage(
Rekha Aparna3fcad142025-10-24 08:16:44 -05001090 "Failed to get encoded value for keyword : " + l_kwd +
1091 ", error : " + commonUtility::getErrCodeMsg(o_errCode));
Rekha Aparna17ddfb52025-10-09 20:45:53 -05001092 }
1093
Souvik Roy96ebe962025-04-29 04:01:07 -05001094 // add property map to interface map
1095 l_interfaceMap.emplace(
1096 l_interfacesPropPair.key(),
1097 types::PropertyMap{
Rekha Aparna17ddfb52025-10-09 20:45:53 -05001098 {l_matchPropValuePairIt.key(), l_encodedValue}});
Souvik Roy96ebe962025-04-29 04:01:07 -05001099 }
1100 };
1101
Sunny Srivastava89fbd2d2025-09-03 02:03:48 -05001102 if (!i_commonInterfaceJson.empty())
1103 {
1104 // iterate through all common interfaces and populate interface map
1105 std::for_each(i_commonInterfaceJson.items().begin(),
1106 i_commonInterfaceJson.items().end(),
1107 l_populateInterfaceMap);
1108 }
Souvik Roy96ebe962025-04-29 04:01:07 -05001109 }
1110 catch (const std::exception& l_ex)
1111 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001112 o_errCode = error_code::STANDARD_EXCEPTION;
Souvik Roy96ebe962025-04-29 04:01:07 -05001113 }
1114 return l_interfaceMap;
1115}
1116
1117/**
1118 * @brief API to update common interface(s) properties when keyword is updated.
1119 *
1120 * For a given keyword update on a EEPROM path, this API syncs the keyword
1121 * update to respective common interface(s) properties of the base FRU and all
1122 * inherited FRUs.
1123 *
1124 * @param[in] i_fruPath - EEPROM path of FRU.
1125 * @param[in] i_paramsToWriteData - Input details.
1126 * @param[in] i_sysCfgJsonObj - System config JSON.
Rekha Aparna3fcad142025-10-24 08:16:44 -05001127 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy96ebe962025-04-29 04:01:07 -05001128 */
1129inline void updateCiPropertyOfInheritedFrus(
1130 const std::string& i_fruPath,
1131 const types::WriteVpdParams& i_paramsToWriteData,
Rekha Aparna3fcad142025-10-24 08:16:44 -05001132 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) noexcept
Souvik Roy96ebe962025-04-29 04:01:07 -05001133{
Sunny Srivastavab86675d2025-11-05 18:31:46 +05301134 o_errCode = 0;
Souvik Roy96ebe962025-04-29 04:01:07 -05001135 try
1136 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001137 if (i_fruPath.empty() || i_sysCfgJsonObj.empty())
1138 {
1139 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1140 return;
1141 }
1142
Souvik Roy96ebe962025-04-29 04:01:07 -05001143 if (!i_sysCfgJsonObj.contains("commonInterfaces"))
1144 {
1145 // no common interfaces in JSON, nothing to do
1146 return;
1147 }
1148
1149 if (!i_sysCfgJsonObj.contains("frus"))
1150 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001151 o_errCode = error_code::INVALID_JSON;
1152 return;
Souvik Roy96ebe962025-04-29 04:01:07 -05001153 }
1154
1155 if (!i_sysCfgJsonObj["frus"].contains(i_fruPath))
1156 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001157 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1158 return;
Souvik Roy96ebe962025-04-29 04:01:07 -05001159 }
1160
1161 if (!std::get_if<types::IpzData>(&i_paramsToWriteData))
1162 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001163 o_errCode = error_code::UNSUPPORTED_VPD_TYPE;
1164 return;
Souvik Roy96ebe962025-04-29 04:01:07 -05001165 }
1166
1167 // iterate through all inventory paths for given EEPROM path,
1168 // if for an inventory path, "inherit" tag is true,
1169 // update the inventory path's com.ibm.ipzvpd.<record>,keyword
1170 // property
1171
1172 types::ObjectMap l_objectInterfaceMap;
1173
1174 const types::InterfaceMap l_interfaceMap = getCommonInterfaceProperties(
Rekha Aparna3fcad142025-10-24 08:16:44 -05001175 i_paramsToWriteData, i_sysCfgJsonObj["commonInterfaces"],
1176 o_errCode);
Souvik Roy96ebe962025-04-29 04:01:07 -05001177
1178 if (l_interfaceMap.empty())
1179 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001180 if (o_errCode)
1181 {
1182 logging::logMessage(
1183 "Failed to get common interface property list, error : " +
1184 commonUtility::getErrCodeMsg(o_errCode));
1185 }
Souvik Roy96ebe962025-04-29 04:01:07 -05001186 // nothing to do
1187 return;
1188 }
1189
1190 auto l_populateObjectInterfaceMap =
1191 [&l_objectInterfaceMap, &l_interfaceMap = std::as_const(
1192 l_interfaceMap)](const auto& l_Fru) {
1193 if (l_Fru.value("inherit", true) &&
1194 l_Fru.contains("inventoryPath"))
1195 {
1196 l_objectInterfaceMap.emplace(
1197 sdbusplus::message::object_path{l_Fru["inventoryPath"]},
1198 l_interfaceMap);
1199 }
1200 };
1201
1202 std::for_each(i_sysCfgJsonObj["frus"][i_fruPath].begin(),
1203 i_sysCfgJsonObj["frus"][i_fruPath].end(),
1204 l_populateObjectInterfaceMap);
1205
1206 if (!l_objectInterfaceMap.empty())
1207 {
1208 // notify PIM
1209 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
1210 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001211 o_errCode = error_code::DBUS_FAILURE;
1212 return;
Souvik Roy96ebe962025-04-29 04:01:07 -05001213 }
1214 }
1215 }
1216 catch (const std::exception& l_ex)
1217 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001218 o_errCode = error_code::STANDARD_EXCEPTION;
Souvik Roy96ebe962025-04-29 04:01:07 -05001219 }
1220}
Sunny Srivastava995e1c22025-08-28 03:13:00 -05001221
1222/**
Souvik Royd7c7cb52025-07-30 06:31:02 +00001223 * @brief API to convert write VPD parameters to a string.
1224 *
1225 * @param[in] i_paramsToWriteData - write VPD parameters.
1226 * @param[out] o_errCode - To set error code in case of error.
1227 *
1228 * @return On success returns string representation of write VPD parameters,
1229 * otherwise returns an empty string.
1230 */
1231inline const std::string convertWriteVpdParamsToString(
1232 const types::WriteVpdParams& i_paramsToWriteData,
1233 uint16_t& o_errCode) noexcept
1234{
Sunny Srivastavab86675d2025-11-05 18:31:46 +05301235 o_errCode = 0;
Souvik Royd7c7cb52025-07-30 06:31:02 +00001236 try
1237 {
1238 if (const types::IpzData* l_ipzDataPtr =
1239 std::get_if<types::IpzData>(&i_paramsToWriteData))
1240 {
1241 return std::string{
1242 "Record: " + std::get<0>(*l_ipzDataPtr) +
1243 " Keyword: " + std::get<1>(*l_ipzDataPtr) + " Value: " +
1244 commonUtility::convertByteVectorToHex(
1245 std::get<2>(*l_ipzDataPtr))};
1246 }
1247 else if (const types::KwData* l_kwDataPtr =
1248 std::get_if<types::KwData>(&i_paramsToWriteData))
1249 {
1250 return std::string{
1251 "Keyword: " + std::get<0>(*l_kwDataPtr) + " Value: " +
1252 commonUtility::convertByteVectorToHex(
1253 std::get<1>(*l_kwDataPtr))};
1254 }
1255 else
1256 {
1257 o_errCode = error_code::UNSUPPORTED_VPD_TYPE;
1258 }
1259 }
1260 catch (const std::exception& l_ex)
1261 {
1262 o_errCode = error_code::STANDARD_EXCEPTION;
1263 }
1264 return std::string{};
1265}
1266
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001267} // namespace vpdSpecificUtility
1268} // namespace vpd