blob: 4fc553d519c25d621e6f3264365f05a6f3b8c51f [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#pragma once
2
3#include "config.h"
4
5#include "constants.hpp"
Souvik Roy815c6022025-02-20 00:54:24 -06006#include "event_logger.hpp"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05007#include "exceptions.hpp"
8#include "logger.hpp"
9#include "types.hpp"
10
11#include <nlohmann/json.hpp>
12#include <utility/common_utility.hpp>
13#include <utility/dbus_utility.hpp>
14
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.
32 *
33 * @return On success, returns generated file name, otherwise returns empty
34 * string.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050035 */
Souvik Roy8fc12522025-02-19 01:28:38 -060036inline std::string generateBadVPDFileName(
37 const std::string& i_vpdFilePath) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050038{
Souvik Roy8fc12522025-02-19 01:28:38 -060039 std::string l_badVpdFileName{BAD_VPD_DIR};
40 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050041 {
Souvik Roy8fc12522025-02-19 01:28:38 -060042 if (i_vpdFilePath.find("i2c") != std::string::npos)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050043 {
Souvik Roy8fc12522025-02-19 01:28:38 -060044 l_badVpdFileName += "i2c-";
45 std::regex l_i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
46 std::smatch l_match;
47 if (std::regex_search(i_vpdFilePath, l_match, l_i2cPattern))
48 {
49 l_badVpdFileName += l_match.str(2);
50 }
51 }
52 else if (i_vpdFilePath.find("spi") != std::string::npos)
53 {
54 std::regex l_spiPattern("((spi)[0-9]+)(.0)");
55 std::smatch l_match;
56 if (std::regex_search(i_vpdFilePath, l_match, l_spiPattern))
57 {
58 l_badVpdFileName += l_match.str(1);
59 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050060 }
61 }
Souvik Roy8fc12522025-02-19 01:28:38 -060062 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050063 {
Souvik Roy8fc12522025-02-19 01:28:38 -060064 l_badVpdFileName.clear();
65 logging::logMessage("Failed to generate bad VPD file name for [" +
66 i_vpdFilePath + "]. Error: " + l_ex.what());
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050067 }
Souvik Roy8fc12522025-02-19 01:28:38 -060068 return l_badVpdFileName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050069}
70
71/**
72 * @brief API which dumps the broken/bad vpd in a directory.
73 * When the vpd is bad, this API places the bad vpd file inside
74 * "/tmp/bad-vpd" in BMC, in order to collect bad VPD data as a part of user
75 * initiated BMC dump.
76 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050077 *
Souvik Roy8fc12522025-02-19 01:28:38 -060078 * @param[in] i_vpdFilePath - vpd file path
79 * @param[in] i_vpdVector - vpd vector
80 *
81 * @return On success returns 0, otherwise returns -1.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050082 */
Souvik Roy8fc12522025-02-19 01:28:38 -060083inline int dumpBadVpd(const std::string& i_vpdFilePath,
84 const types::BinaryVector& i_vpdVector) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050085{
Souvik Roy8fc12522025-02-19 01:28:38 -060086 int l_rc{constants::FAILURE};
87 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050088 {
Souvik Roy8fc12522025-02-19 01:28:38 -060089 std::filesystem::create_directory(BAD_VPD_DIR);
90 auto l_badVpdPath = generateBadVPDFileName(i_vpdFilePath);
91
92 if (l_badVpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050093 {
Souvik Roy8fc12522025-02-19 01:28:38 -060094 throw std::runtime_error("Failed to generate bad VPD file name");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050095 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050096
Souvik Roy8fc12522025-02-19 01:28:38 -060097 if (std::filesystem::exists(l_badVpdPath))
98 {
99 std::error_code l_ec;
100 std::filesystem::remove(l_badVpdPath, l_ec);
101 if (l_ec) // error code
102 {
103 const std::string l_errorMsg{
104 "Error removing the existing broken vpd in " +
105 l_badVpdPath +
106 ". Error code : " + std::to_string(l_ec.value()) +
107 ". Error message : " + l_ec.message()};
108
109 throw std::runtime_error(l_errorMsg);
110 }
111 }
112
113 std::ofstream l_badVpdFileStream(l_badVpdPath, std::ofstream::binary);
114 if (!l_badVpdFileStream.is_open())
115 {
116 throw std::runtime_error(
117 "Failed to open bad vpd file path in /tmp/bad-vpd. "
118 "Unable to dump the broken/bad vpd file.");
119 }
120
121 l_badVpdFileStream.write(
122 reinterpret_cast<const char*>(i_vpdVector.data()),
123 i_vpdVector.size());
124
125 l_rc = constants::SUCCESS;
126 }
127 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500128 {
Souvik Roy8fc12522025-02-19 01:28:38 -0600129 logging::logMessage("Failed to dump bad VPD for [" + i_vpdFilePath +
130 "]. Error: " + l_ex.what());
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500131 }
Souvik Roy8fc12522025-02-19 01:28:38 -0600132 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500133}
134
135/**
136 * @brief An API to read value of a keyword.
137 *
138 * Note: Throws exception. Caller needs to handle.
139 *
140 * @param[in] kwdValueMap - A map having Kwd value pair.
141 * @param[in] kwd - keyword name.
142 * @param[out] kwdValue - Value of the keyword read from map.
143 */
144inline void getKwVal(const types::IPZKwdValueMap& kwdValueMap,
145 const std::string& kwd, std::string& kwdValue)
146{
147 if (kwd.empty())
148 {
149 logging::logMessage("Invalid parameters");
150 throw std::runtime_error("Invalid parameters");
151 }
152
153 auto itrToKwd = kwdValueMap.find(kwd);
154 if (itrToKwd != kwdValueMap.end())
155 {
156 kwdValue = itrToKwd->second;
157 return;
158 }
159
160 throw std::runtime_error("Keyword not found");
161}
162
163/**
164 * @brief An API to process encoding of a keyword.
165 *
Souvik Royf277d6a2025-02-20 00:08:43 -0600166 * @param[in] i_keyword - Keyword to be processed.
167 * @param[in] i_encoding - Type of encoding.
168 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500169 * @return Value after being processed for encoded type.
170 */
Souvik Royf277d6a2025-02-20 00:08:43 -0600171inline std::string encodeKeyword(const std::string& i_keyword,
172 const std::string& i_encoding) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500173{
174 // Default value is keyword value
Souvik Royf277d6a2025-02-20 00:08:43 -0600175 std::string l_result(i_keyword.begin(), i_keyword.end());
176 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500177 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600178 if (i_encoding == "MAC")
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500179 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600180 l_result.clear();
181 size_t l_firstByte = i_keyword[0];
182 l_result += commonUtility::toHex(l_firstByte >> 4);
183 l_result += commonUtility::toHex(l_firstByte & 0x0f);
184 for (size_t i = 1; i < i_keyword.size(); ++i)
185 {
186 l_result += ":";
187 l_result += commonUtility::toHex(i_keyword[i] >> 4);
188 l_result += commonUtility::toHex(i_keyword[i] & 0x0f);
189 }
190 }
191 else if (i_encoding == "DATE")
192 {
193 // Date, represent as
194 // <year>-<month>-<day> <hour>:<min>
195 l_result.clear();
196 static constexpr uint8_t skipPrefix = 3;
197
198 auto strItr = i_keyword.begin();
199 advance(strItr, skipPrefix);
200 for_each(strItr, i_keyword.end(),
201 [&l_result](size_t c) { l_result += c; });
202
203 l_result.insert(constants::BD_YEAR_END, 1, '-');
204 l_result.insert(constants::BD_MONTH_END, 1, '-');
205 l_result.insert(constants::BD_DAY_END, 1, ' ');
206 l_result.insert(constants::BD_HOUR_END, 1, ':');
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500207 }
208 }
Souvik Royf277d6a2025-02-20 00:08:43 -0600209 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500210 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600211 l_result.clear();
212 logging::logMessage("Failed to encode keyword [" + i_keyword +
213 "]. Error: " + l_ex.what());
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500214 }
215
Souvik Royf277d6a2025-02-20 00:08:43 -0600216 return l_result;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500217}
218
219/**
220 * @brief Helper function to insert or merge in map.
221 *
222 * This method checks in an interface if the given interface exists. If the
223 * interface key already exists, property map is inserted corresponding to it.
224 * If the key does'nt exist then given interface and property map pair is newly
225 * created. If the property present in propertymap already exist in the
226 * InterfaceMap, then the new property value is ignored.
227 *
Souvik Royfa47e6c2025-02-20 00:17:25 -0600228 * @param[in,out] io_map - Interface map.
229 * @param[in] i_interface - Interface to be processed.
230 * @param[in] i_propertyMap - new property map that needs to be emplaced.
231 *
232 * @return On success returns 0, otherwise returns -1.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500233 */
Souvik Royfa47e6c2025-02-20 00:17:25 -0600234inline int insertOrMerge(types::InterfaceMap& io_map,
235 const std::string& i_interface,
236 types::PropertyMap&& i_propertyMap) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500237{
Souvik Royfa47e6c2025-02-20 00:17:25 -0600238 int l_rc{constants::FAILURE};
239 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500240 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600241 if (io_map.find(i_interface) != io_map.end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500242 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600243 auto& l_prop = io_map.at(i_interface);
244 std::for_each(i_propertyMap.begin(), i_propertyMap.end(),
245 [&l_prop](auto l_keyValue) {
246 l_prop[l_keyValue.first] = l_keyValue.second;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500247 });
248 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600249 else
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500250 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600251 io_map.emplace(i_interface, i_propertyMap);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500252 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600253
254 l_rc = constants::SUCCESS;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500255 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600256 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500257 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600258 // ToDo:: Log PEL
259 logging::logMessage(
260 "Inserting properties into interface[" + i_interface +
261 "] map failed, reason: " + std::string(l_ex.what()));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500262 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600263 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500264}
265
266/**
267 * @brief API to expand unpanded location code.
268 *
269 * Note: The API handles all the exception internally, in case of any error
270 * unexpanded location code will be returned as it is.
271 *
272 * @param[in] unexpandedLocationCode - Unexpanded location code.
273 * @param[in] parsedVpdMap - Parsed VPD map.
274 * @return Expanded location code. In case of any error, unexpanded is returned
275 * as it is.
276 */
Patrick Williams43fedab2025-02-03 14:28:05 -0500277inline std::string getExpandedLocationCode(
278 const std::string& unexpandedLocationCode,
279 const types::VPDMapVariant& parsedVpdMap)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500280{
281 auto expanded{unexpandedLocationCode};
282
283 try
284 {
285 // Expanded location code is formed by combining two keywords
286 // depending on type in unexpanded one. Second one is always "SE".
287 std::string kwd1, kwd2{constants::kwdSE};
288
289 // interface to search for required keywords;
290 std::string kwdInterface;
291
292 // record which holds the required keywords.
293 std::string recordName;
294
295 auto pos = unexpandedLocationCode.find("fcs");
296 if (pos != std::string::npos)
297 {
298 kwd1 = constants::kwdFC;
299 kwdInterface = constants::vcenInf;
300 recordName = constants::recVCEN;
301 }
302 else
303 {
304 pos = unexpandedLocationCode.find("mts");
305 if (pos != std::string::npos)
306 {
307 kwd1 = constants::kwdTM;
308 kwdInterface = constants::vsysInf;
309 recordName = constants::recVSYS;
310 }
311 else
312 {
313 throw std::runtime_error(
314 "Error detecting type of unexpanded location code.");
315 }
316 }
317
318 std::string firstKwdValue, secondKwdValue;
319
320 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap);
321 ipzVpdMap && (*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
322 {
323 auto itrToVCEN = (*ipzVpdMap).find(recordName);
324 // The exceptions will be cautght at end.
325 getKwVal(itrToVCEN->second, kwd1, firstKwdValue);
326 getKwVal(itrToVCEN->second, kwd2, secondKwdValue);
327 }
328 else
329 {
330 std::array<const char*, 1> interfaceList = {kwdInterface.c_str()};
331
332 types::MapperGetObject mapperRetValue = dbusUtility::getObjectMap(
333 std::string(constants::systemVpdInvPath), interfaceList);
334
335 if (mapperRetValue.empty())
336 {
337 throw std::runtime_error("Mapper failed to get service");
338 }
339
340 const std::string& serviceName = std::get<0>(mapperRetValue.at(0));
341
342 auto retVal = dbusUtility::readDbusProperty(
343 serviceName, std::string(constants::systemVpdInvPath),
344 kwdInterface, kwd1);
345
346 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
347 {
348 firstKwdValue.assign(
349 reinterpret_cast<const char*>(kwdVal->data()),
350 kwdVal->size());
351 }
352 else
353 {
354 throw std::runtime_error(
355 "Failed to read value of " + kwd1 + " from Bus");
356 }
357
358 retVal = dbusUtility::readDbusProperty(
359 serviceName, std::string(constants::systemVpdInvPath),
360 kwdInterface, kwd2);
361
362 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
363 {
364 secondKwdValue.assign(
365 reinterpret_cast<const char*>(kwdVal->data()),
366 kwdVal->size());
367 }
368 else
369 {
370 throw std::runtime_error(
371 "Failed to read value of " + kwd2 + " from Bus");
372 }
373 }
374
375 if (unexpandedLocationCode.find("fcs") != std::string::npos)
376 {
377 // TODO: See if ND0 can be placed in the JSON
378 expanded.replace(
379 pos, 3, firstKwdValue.substr(0, 4) + ".ND0." + secondKwdValue);
380 }
381 else
382 {
383 replace(firstKwdValue.begin(), firstKwdValue.end(), '-', '.');
384 expanded.replace(pos, 3, firstKwdValue + "." + secondKwdValue);
385 }
386 }
387 catch (const std::exception& ex)
388 {
389 logging::logMessage("Failed to expand location code with exception: " +
390 std::string(ex.what()));
391 }
392
393 return expanded;
394}
395
396/**
397 * @brief An API to get VPD in a vector.
398 *
399 * The vector is required by the respective parser to fill the VPD map.
400 * Note: API throws exception in case of failure. Caller needs to handle.
401 *
402 * @param[in] vpdFilePath - EEPROM path of the FRU.
403 * @param[out] vpdVector - VPD in vector form.
404 * @param[in] vpdStartOffset - Offset of VPD data in EEPROM.
405 */
406inline void getVpdDataInVector(const std::string& vpdFilePath,
407 types::BinaryVector& vpdVector,
408 size_t& vpdStartOffset)
409{
410 try
411 {
412 std::fstream vpdFileStream;
413 vpdFileStream.exceptions(
414 std::ifstream::badbit | std::ifstream::failbit);
415 vpdFileStream.open(vpdFilePath, std::ios::in | std::ios::binary);
416 auto vpdSizeToRead = std::min(std::filesystem::file_size(vpdFilePath),
417 static_cast<uintmax_t>(65504));
418 vpdVector.resize(vpdSizeToRead);
419
420 vpdFileStream.seekg(vpdStartOffset, std::ios_base::beg);
421 vpdFileStream.read(reinterpret_cast<char*>(&vpdVector[0]),
422 vpdSizeToRead);
423
424 vpdVector.resize(vpdFileStream.gcount());
425 vpdFileStream.clear(std::ios_base::eofbit);
426 }
427 catch (const std::ifstream::failure& fail)
428 {
429 std::cerr << "Exception in file handling [" << vpdFilePath
430 << "] error : " << fail.what();
431 throw;
432 }
433}
434
435/**
436 * @brief An API to get D-bus representation of given VPD keyword.
437 *
438 * @param[in] i_keywordName - VPD keyword name.
439 *
440 * @return D-bus representation of given keyword.
441 */
442inline std::string getDbusPropNameForGivenKw(const std::string& i_keywordName)
443{
444 // Check for "#" prefixed VPD keyword.
445 if ((i_keywordName.size() == vpd::constants::TWO_BYTES) &&
446 (i_keywordName.at(0) == constants::POUND_KW))
447 {
448 // D-bus doesn't support "#". Replace "#" with "PD_" for those "#"
449 // prefixed keywords.
450 return (std::string(constants::POUND_KW_PREFIX) +
451 i_keywordName.substr(1));
452 }
453
454 // Return the keyword name back, if D-bus representation is same as the VPD
455 // keyword name.
456 return i_keywordName;
457}
458
459/**
460 * @brief API to find CCIN in parsed VPD map.
461 *
462 * Few FRUs need some special handling. To identify those FRUs CCIN are used.
463 * The API will check from parsed VPD map if the FRU is the one with desired
464 * CCIN.
465 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500466 * @param[in] i_JsonObject - Any JSON which contains CCIN tag to match.
467 * @param[in] i_parsedVpdMap - Parsed VPD map.
Souvik Roy815c6022025-02-20 00:54:24 -0600468 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500469 * @return True if found, false otherwise.
470 */
471inline bool findCcinInVpd(const nlohmann::json& i_JsonObject,
Souvik Roy815c6022025-02-20 00:54:24 -0600472 const types::VPDMapVariant& i_parsedVpdMap) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500473{
Souvik Roy815c6022025-02-20 00:54:24 -0600474 bool l_rc{false};
475 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500476 {
Souvik Roy815c6022025-02-20 00:54:24 -0600477 if (i_JsonObject.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500478 {
Souvik Roy815c6022025-02-20 00:54:24 -0600479 throw std::runtime_error("Json object is empty. Can't find CCIN");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500480 }
481
Souvik Roy815c6022025-02-20 00:54:24 -0600482 if (auto l_ipzVPDMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500483 {
Souvik Roy815c6022025-02-20 00:54:24 -0600484 auto l_itrToRec = (*l_ipzVPDMap).find("VINI");
485 if (l_itrToRec == (*l_ipzVPDMap).end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500486 {
Souvik Roy815c6022025-02-20 00:54:24 -0600487 throw DataException(
488 "VINI record not found in parsed VPD. Can't find CCIN");
489 }
490
491 std::string l_ccinFromVpd;
492 vpdSpecificUtility::getKwVal(l_itrToRec->second, "CC",
493 l_ccinFromVpd);
494 if (l_ccinFromVpd.empty())
495 {
496 throw DataException(
497 "Empty CCIN value in VPD map. Can't find CCIN");
498 }
499
500 transform(l_ccinFromVpd.begin(), l_ccinFromVpd.end(),
501 l_ccinFromVpd.begin(), ::toupper);
502
503 for (std::string l_ccinValue : i_JsonObject["ccin"])
504 {
505 transform(l_ccinValue.begin(), l_ccinValue.end(),
506 l_ccinValue.begin(), ::toupper);
507
508 if (l_ccinValue.compare(l_ccinFromVpd) ==
509 constants::STR_CMP_SUCCESS)
510 {
511 // CCIN found
512 l_rc = true;
513 }
514 }
515
516 if (!l_rc)
517 {
518 logging::logMessage("No match found for CCIN");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500519 }
520 }
Souvik Roy815c6022025-02-20 00:54:24 -0600521 else
522 {
523 logging::logMessage("VPD type not supported. Can't find CCIN");
524 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500525 }
Souvik Roy815c6022025-02-20 00:54:24 -0600526 catch (const std::exception& l_ex)
527 {
528 const std::string l_errMsg{
529 "Failed to find CCIN in VPD. Error : " + std::string(l_ex.what())};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500530
Souvik Roy815c6022025-02-20 00:54:24 -0600531 if (typeid(l_ex) == std::type_index(typeid(DataException)))
532 {
533 EventLogger::createSyncPel(
534 types::ErrorType::InvalidVpdMessage,
535 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
536 l_errMsg, std::nullopt, std::nullopt, std::nullopt,
537 std::nullopt);
538 }
539
540 logging::logMessage(l_errMsg);
541 }
542 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500543}
544
545/**
546 * @brief API to reset data of a FRU populated under PIM.
547 *
548 * This API resets the data for particular interfaces of a FRU under PIM.
549 *
550 * @param[in] i_objectPath - DBus object path of the FRU.
551 * @param[in] io_interfaceMap - Interface and its properties map.
552 */
553inline void resetDataUnderPIM(const std::string& i_objectPath,
554 types::InterfaceMap& io_interfaceMap)
555{
556 try
557 {
558 std::array<const char*, 0> l_interfaces;
559 const types::MapperGetObject& l_getObjectMap =
560 dbusUtility::getObjectMap(i_objectPath, l_interfaces);
561
562 const std::vector<std::string>& l_vpdRelatedInterfaces{
563 constants::operationalStatusInf, constants::inventoryItemInf,
564 constants::assetInf};
565
566 for (const auto& [l_service, l_interfaceList] : l_getObjectMap)
567 {
568 if (l_service.compare(constants::pimServiceName) !=
569 constants::STR_CMP_SUCCESS)
570 {
571 continue;
572 }
573
574 for (const auto& l_interface : l_interfaceList)
575 {
576 if ((l_interface.find(constants::ipzVpdInf) !=
577 std::string::npos) ||
578 ((std::find(l_vpdRelatedInterfaces.begin(),
579 l_vpdRelatedInterfaces.end(), l_interface)) !=
580 l_vpdRelatedInterfaces.end()))
581 {
582 const types::PropertyMap& l_propertyValueMap =
583 dbusUtility::getPropertyMap(l_service, i_objectPath,
584 l_interface);
585
586 types::PropertyMap l_propertyMap;
587
588 for (const auto& l_aProperty : l_propertyValueMap)
589 {
590 const std::string& l_propertyName = l_aProperty.first;
591 const auto& l_propertyValue = l_aProperty.second;
592
593 if (std::holds_alternative<types::BinaryVector>(
594 l_propertyValue))
595 {
596 l_propertyMap.emplace(l_propertyName,
597 types::BinaryVector{});
598 }
599 else if (std::holds_alternative<std::string>(
600 l_propertyValue))
601 {
602 l_propertyMap.emplace(l_propertyName,
603 std::string{});
604 }
605 else if (std::holds_alternative<bool>(l_propertyValue))
606 {
607 // ToDo -- Update the functional status property
608 // to true.
609 if (l_propertyName.compare("Present") ==
610 constants::STR_CMP_SUCCESS)
611 {
612 l_propertyMap.emplace(l_propertyName, false);
613 }
614 }
615 }
616 io_interfaceMap.emplace(l_interface,
617 std::move(l_propertyMap));
618 }
619 }
620 }
621 }
622 catch (const std::exception& l_ex)
623 {
624 logging::logMessage("Failed to remove VPD for FRU: " + i_objectPath +
625 " with error: " + std::string(l_ex.what()));
626 }
627}
Sunny Srivastava78c91072025-02-05 14:09:50 +0530628
629/**
630 * @brief API to detect pass1 planar type.
631 *
632 * Based on HW version and IM keyword, This API detects is it is a pass1 planar
633 * or not.
634 *
635 * @return True if pass 1 planar, false otherwise.
636 */
Souvik Roy094a7352025-02-20 01:31:45 -0600637inline bool isPass1Planar() noexcept
Sunny Srivastava78c91072025-02-05 14:09:50 +0530638{
Souvik Roy094a7352025-02-20 01:31:45 -0600639 bool l_rc{false};
640 try
Sunny Srivastava78c91072025-02-05 14:09:50 +0530641 {
Souvik Roy094a7352025-02-20 01:31:45 -0600642 auto l_retVal = dbusUtility::readDbusProperty(
643 constants::pimServiceName, constants::systemVpdInvPath,
644 constants::viniInf, constants::kwdHW);
Sunny Srivastava78c91072025-02-05 14:09:50 +0530645
Souvik Roy094a7352025-02-20 01:31:45 -0600646 auto l_hwVer = std::get_if<types::BinaryVector>(&l_retVal);
647
648 l_retVal = dbusUtility::readDbusProperty(
649 constants::pimServiceName, constants::systemInvPath,
650 constants::vsbpInf, constants::kwdIM);
651
652 auto l_imValue = std::get_if<types::BinaryVector>(&l_retVal);
653
654 if (l_hwVer && l_imValue)
Sunny Srivastava78c91072025-02-05 14:09:50 +0530655 {
Souvik Roy094a7352025-02-20 01:31:45 -0600656 if (l_hwVer->size() != constants::VALUE_2)
Sunny Srivastava78c91072025-02-05 14:09:50 +0530657 {
Souvik Roy094a7352025-02-20 01:31:45 -0600658 throw std::runtime_error("Invalid HW keyword length.");
659 }
660
661 if (l_imValue->size() != constants::VALUE_4)
662 {
663 throw std::runtime_error("Invalid IM keyword length.");
664 }
665
666 const types::BinaryVector l_everest{80, 00, 48, 00};
667 const types::BinaryVector l_fuji{96, 00, 32, 00};
668
669 if (((*l_imValue) == l_everest) || ((*l_imValue) == l_fuji))
670 {
671 if ((*l_hwVer).at(1) < constants::VALUE_21)
672 {
673 l_rc = true;
674 }
675 }
676 else if ((*l_hwVer).at(1) < constants::VALUE_2)
677 {
678 l_rc = true;
Sunny Srivastava78c91072025-02-05 14:09:50 +0530679 }
680 }
Souvik Roy094a7352025-02-20 01:31:45 -0600681 }
682 catch (const std::exception& l_ex)
683 {
684 logging::logMessage("Failed to check for pass 1 planar. Error: " +
685 std::string(l_ex.what()));
Sunny Srivastava78c91072025-02-05 14:09:50 +0530686 }
687
Souvik Roy094a7352025-02-20 01:31:45 -0600688 return l_rc;
Sunny Srivastava78c91072025-02-05 14:09:50 +0530689}
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530690
691/**
692 * @brief API to detect if system configuration is that of PowerVS system.
693 *
694 * @param[in] i_imValue - IM value of the system.
695 * @return true if it is PowerVS configuration, false otherwise.
696 */
697inline bool isPowerVsConfiguration(const types::BinaryVector& i_imValue)
698{
699 if (i_imValue.empty() || i_imValue.size() != constants::VALUE_4)
700 {
701 return false;
702 }
703
704 // Should be a 0x5000XX series system.
705 if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
706 i_imValue.at(1) == constants::HEX_VALUE_00)
707 {
708 std::string l_imagePrefix = dbusUtility::getImagePrefix();
709
710 // Check image for 0x500030XX series.
711 if ((i_imValue.at(2) == constants::HEX_VALUE_30) &&
712 ((l_imagePrefix == constants::powerVsImagePrefix_MY) ||
713 (l_imagePrefix == constants::powerVsImagePrefix_NY)))
714 {
715 logging::logMessage("PowerVS configuration");
716 return true;
717 }
718
719 // Check image for 0X500010XX series.
720 if ((i_imValue.at(2) == constants::HEX_VALUE_10) &&
721 ((l_imagePrefix == constants::powerVsImagePrefix_MZ) ||
722 (l_imagePrefix == constants::powerVsImagePrefix_NZ)))
723 {
724 logging::logMessage("PowerVS configuration");
725 return true;
726 }
727 }
728 return false;
729}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500730} // namespace vpdSpecificUtility
731} // namespace vpd