blob: 554092e967688fb17f9e520acbc916f81e629206 [file] [log] [blame]
SunnySrivastava198443306542020-04-01 02:50:20 -05001#include "config.h"
2
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05003#include "ibm_vpd_utils.hpp"
Patrick Venturec83c4dc2018-11-01 16:29:18 -07004
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05005#include "common_utility.hpp"
SunnySrivastava1984d076da82020-03-05 05:33:35 -06006#include "defines.hpp"
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +05307#include "vpd_exceptions.hpp"
SunnySrivastava1984d076da82020-03-05 05:33:35 -06008
Alpana Kumari6bd095f2022-02-23 10:20:20 -06009#include <boost/algorithm/string.hpp>
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -060010#include <filesystem>
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053011#include <fstream>
Alpana Kumari735dee92022-03-25 01:24:40 -050012#include <gpiod.hpp>
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053013#include <iomanip>
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -050014#include <nlohmann/json.hpp>
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050015#include <phosphor-logging/elog-errors.hpp>
Patrick Venturec83c4dc2018-11-01 16:29:18 -070016#include <phosphor-logging/log.hpp>
PriyangaRamasamy647868e2020-09-08 17:03:19 +053017#include <regex>
Patrick Venturec83c4dc2018-11-01 16:29:18 -070018#include <sdbusplus/server.hpp>
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053019#include <sstream>
20#include <vector>
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050021#include <xyz/openbmc_project/Common/error.hpp>
Deepak Kodihalli76794492017-02-16 23:48:18 -060022
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053023using json = nlohmann::json;
24
Deepak Kodihalli76794492017-02-16 23:48:18 -060025namespace openpower
26{
27namespace vpd
28{
SunnySrivastava1984945a02d2020-05-06 01:55:41 -050029using namespace openpower::vpd::constants;
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -050030using namespace inventory;
31using namespace phosphor::logging;
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050032using namespace sdbusplus::xyz::openbmc_project::Common::Error;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053033using namespace record;
34using namespace openpower::vpd::exceptions;
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -050035using namespace common::utility;
Sunny Srivastava0746eee2021-03-22 13:36:54 -050036using Severity = openpower::vpd::constants::PelSeverity;
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -060037namespace fs = std::filesystem;
Sunny Srivastava0746eee2021-03-22 13:36:54 -050038
39// mapping of severity enum to severity interface
40static std::unordered_map<Severity, std::string> sevMap = {
41 {Severity::INFORMATIONAL,
42 "xyz.openbmc_project.Logging.Entry.Level.Informational"},
43 {Severity::DEBUG, "xyz.openbmc_project.Logging.Entry.Level.Debug"},
44 {Severity::NOTICE, "xyz.openbmc_project.Logging.Entry.Level.Notice"},
45 {Severity::WARNING, "xyz.openbmc_project.Logging.Entry.Level.Warning"},
46 {Severity::CRITICAL, "xyz.openbmc_project.Logging.Entry.Level.Critical"},
47 {Severity::EMERGENCY, "xyz.openbmc_project.Logging.Entry.Level.Emergency"},
48 {Severity::ERROR, "xyz.openbmc_project.Logging.Entry.Level.Error"},
49 {Severity::ALERT, "xyz.openbmc_project.Logging.Entry.Level.Alert"}};
50
Deepak Kodihalli76794492017-02-16 23:48:18 -060051namespace inventory
52{
53
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050054MapperResponse
55 getObjectSubtreeForInterfaces(const std::string& root, const int32_t depth,
56 const std::vector<std::string>& interfaces)
57{
58 auto bus = sdbusplus::bus::new_default();
59 auto mapperCall = bus.new_method_call(mapperDestination, mapperObjectPath,
60 mapperInterface, "GetSubTree");
61 mapperCall.append(root);
62 mapperCall.append(depth);
63 mapperCall.append(interfaces);
64
65 MapperResponse result = {};
66
67 try
68 {
69 auto response = bus.call(mapperCall);
70
71 response.read(result);
72 }
Patrick Williams8be43342021-09-02 09:33:36 -050073 catch (const sdbusplus::exception::exception& e)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050074 {
75 log<level::ERR>("Error in mapper GetSubTree",
76 entry("ERROR=%s", e.what()));
77 }
78
79 return result;
80}
81
Deepak Kodihalli76794492017-02-16 23:48:18 -060082} // namespace inventory
83
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060084LE2ByteData readUInt16LE(Binary::const_iterator iterator)
85{
86 LE2ByteData lowByte = *iterator;
87 LE2ByteData highByte = *(iterator + 1);
88 lowByte |= (highByte << 8);
89 return lowByte;
90}
91
SunnySrivastava1984d076da82020-03-05 05:33:35 -060092/** @brief Encodes a keyword for D-Bus.
93 */
94string encodeKeyword(const string& kw, const string& encoding)
95{
96 if (encoding == "MAC")
97 {
98 string res{};
99 size_t first = kw[0];
100 res += toHex(first >> 4);
101 res += toHex(first & 0x0f);
102 for (size_t i = 1; i < kw.size(); ++i)
103 {
104 res += ":";
105 res += toHex(kw[i] >> 4);
106 res += toHex(kw[i] & 0x0f);
107 }
108 return res;
109 }
110 else if (encoding == "DATE")
111 {
112 // Date, represent as
113 // <year>-<month>-<day> <hour>:<min>
114 string res{};
115 static constexpr uint8_t skipPrefix = 3;
116
117 auto strItr = kw.begin();
118 advance(strItr, skipPrefix);
119 for_each(strItr, kw.end(), [&res](size_t c) { res += c; });
120
121 res.insert(BD_YEAR_END, 1, '-');
122 res.insert(BD_MONTH_END, 1, '-');
123 res.insert(BD_DAY_END, 1, ' ');
124 res.insert(BD_HOUR_END, 1, ':');
125
126 return res;
127 }
128 else // default to string encoding
129 {
130 return string(kw.begin(), kw.end());
131 }
132}
SunnySrivastava198443306542020-04-01 02:50:20 -0500133
134string readBusProperty(const string& obj, const string& inf, const string& prop)
135{
136 std::string propVal{};
137 std::string object = INVENTORY_PATH + obj;
138 auto bus = sdbusplus::bus::new_default();
139 auto properties = bus.new_method_call(
140 "xyz.openbmc_project.Inventory.Manager", object.c_str(),
141 "org.freedesktop.DBus.Properties", "Get");
142 properties.append(inf);
143 properties.append(prop);
144 auto result = bus.call(properties);
145 if (!result.is_method_error())
146 {
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500147 variant<Binary, string> val;
SunnySrivastava198443306542020-04-01 02:50:20 -0500148 result.read(val);
SunnySrivastava198443306542020-04-01 02:50:20 -0500149 if (auto pVal = get_if<Binary>(&val))
150 {
151 propVal.assign(reinterpret_cast<const char*>(pVal->data()),
152 pVal->size());
153 }
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500154 else if (auto pVal = get_if<string>(&val))
155 {
156 propVal.assign(pVal->data(), pVal->size());
157 }
SunnySrivastava198443306542020-04-01 02:50:20 -0500158 }
159 return propVal;
160}
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500161
162void createPEL(const std::map<std::string, std::string>& additionalData,
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500163 const Severity& sev, const std::string& errIntf)
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500164{
165 try
166 {
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500167 std::string pelSeverity =
168 "xyz.openbmc_project.Logging.Entry.Level.Error";
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500169 auto bus = sdbusplus::bus::new_default();
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500170 auto service = getService(bus, loggerObjectPath, loggerCreateInterface);
171 auto method = bus.new_method_call(service.c_str(), loggerObjectPath,
172 loggerCreateInterface, "Create");
173
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500174 auto itr = sevMap.find(sev);
175 if (itr != sevMap.end())
176 {
177 pelSeverity = itr->second;
178 }
179
180 method.append(errIntf, pelSeverity, additionalData);
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500181 auto resp = bus.call(method);
182 }
Patrick Williams8be43342021-09-02 09:33:36 -0500183 catch (const sdbusplus::exception::exception& e)
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -0500184 {
185 throw std::runtime_error(
186 "Error in invoking D-Bus logging create interface to register PEL");
187 }
188}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530189
190inventory::VPDfilepath getVpdFilePath(const string& jsonFile,
191 const std::string& ObjPath)
192{
193 ifstream inventoryJson(jsonFile);
194 const auto& jsonObject = json::parse(inventoryJson);
195 inventory::VPDfilepath filePath{};
196
197 if (jsonObject.find("frus") == jsonObject.end())
198 {
199 throw(VpdJsonException(
200 "Invalid JSON structure - frus{} object not found in ", jsonFile));
201 }
202
203 const nlohmann::json& groupFRUS =
204 jsonObject["frus"].get_ref<const nlohmann::json::object_t&>();
205 for (const auto& itemFRUS : groupFRUS.items())
206 {
207 const std::vector<nlohmann::json>& groupEEPROM =
208 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
209 for (const auto& itemEEPROM : groupEEPROM)
210 {
211 if (itemEEPROM["inventoryPath"]
212 .get_ref<const nlohmann::json::string_t&>() == ObjPath)
213 {
214 filePath = itemFRUS.key();
215 return filePath;
216 }
217 }
218 }
219
220 return filePath;
221}
222
223bool isPathInJson(const std::string& eepromPath)
224{
225 bool present = false;
226 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
227
228 try
229 {
230 auto js = json::parse(inventoryJson);
231 if (js.find("frus") == js.end())
232 {
233 throw(VpdJsonException(
234 "Invalid JSON structure - frus{} object not found in ",
235 INVENTORY_JSON_SYM_LINK));
236 }
237 json fruJson = js["frus"];
238
239 if (fruJson.find(eepromPath) != fruJson.end())
240 {
241 present = true;
242 }
243 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500244 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530245 {
246 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
247 }
248 return present;
249}
250
251bool isRecKwInDbusJson(const std::string& recordName,
252 const std::string& keyword)
253{
254 ifstream propertyJson(DBUS_PROP_JSON);
255 json dbusProperty;
256 bool present = false;
257
258 if (propertyJson.is_open())
259 {
260 try
261 {
262 auto dbusPropertyJson = json::parse(propertyJson);
263 if (dbusPropertyJson.find("dbusProperties") ==
264 dbusPropertyJson.end())
265 {
266 throw(VpdJsonException("dbusProperties{} object not found in "
267 "DbusProperties json : ",
268 DBUS_PROP_JSON));
269 }
270
271 dbusProperty = dbusPropertyJson["dbusProperties"];
272 if (dbusProperty.contains(recordName))
273 {
274 const vector<string>& kwdsToPublish = dbusProperty[recordName];
275 if (find(kwdsToPublish.begin(), kwdsToPublish.end(), keyword) !=
276 kwdsToPublish.end()) // present
277 {
278 present = true;
279 }
280 }
281 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500282 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530283 {
284 throw(VpdJsonException("Json Parsing failed", DBUS_PROP_JSON));
285 }
286 }
287 else
288 {
289 // If dbus properties json is not available, we assume the given
290 // record-keyword is part of dbus-properties json. So setting the bool
291 // variable to true.
292 present = true;
293 }
294 return present;
295}
296
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -0500297vpdType vpdTypeCheck(const Binary& vpdVector)
298{
299 // Read first 3 Bytes to check the 11S bar code format
300 std::string is11SFormat = "";
301 for (uint8_t i = 0; i < FORMAT_11S_LEN; i++)
302 {
303 is11SFormat += vpdVector[MEMORY_VPD_DATA_START + i];
304 }
305
306 if (vpdVector[IPZ_DATA_START] == KW_VAL_PAIR_START_TAG)
307 {
308 // IPZ VPD FORMAT
309 return vpdType::IPZ_VPD;
310 }
311 else if (vpdVector[KW_VPD_DATA_START] == KW_VPD_START_TAG)
312 {
313 // KEYWORD VPD FORMAT
314 return vpdType::KEYWORD_VPD;
315 }
316 else if (is11SFormat.compare(MEMORY_VPD_START_TAG) == 0)
317 {
318 // Memory VPD format
319 return vpdType::MEMORY_VPD;
320 }
321
322 // INVALID VPD FORMAT
323 return vpdType::INVALID_VPD_FORMAT;
324}
325
Alpana Kumarif05effd2021-04-07 07:32:53 -0500326const string getIM(const Parsed& vpdMap)
327{
328 Binary imVal;
329 auto property = vpdMap.find("VSBP");
330 if (property != vpdMap.end())
331 {
332 auto kw = (property->second).find("IM");
333 if (kw != (property->second).end())
334 {
335 copy(kw->second.begin(), kw->second.end(), back_inserter(imVal));
336 }
337 }
338
339 ostringstream oss;
340 for (auto& i : imVal)
341 {
342 oss << setw(2) << setfill('0') << hex << static_cast<int>(i);
343 }
344
345 return oss.str();
346}
347
348const string getHW(const Parsed& vpdMap)
349{
350 Binary hwVal;
351 auto prop = vpdMap.find("VINI");
352 if (prop != vpdMap.end())
353 {
354 auto kw = (prop->second).find("HW");
355 if (kw != (prop->second).end())
356 {
357 copy(kw->second.begin(), kw->second.end(), back_inserter(hwVal));
358 }
359 }
360
Alpana Kumari88d2ae82021-11-10 03:23:31 -0600361 // The planar pass only comes from the LSB of the HW keyword,
362 // where as the MSB is used for other purposes such as signifying clock
363 // termination.
364 hwVal[0] = 0x00;
365
Alpana Kumarif05effd2021-04-07 07:32:53 -0500366 ostringstream hwString;
367 for (auto& i : hwVal)
368 {
369 hwString << setw(2) << setfill('0') << hex << static_cast<int>(i);
370 }
371
372 return hwString.str();
373}
374
375string getSystemsJson(const Parsed& vpdMap)
376{
377 string jsonPath = "/usr/share/vpd/";
378 string jsonName{};
379
380 ifstream systemJson(SYSTEM_JSON);
381 if (!systemJson)
382 {
383 throw((VpdJsonException("Failed to access Json path", SYSTEM_JSON)));
384 }
385
386 try
387 {
388 auto js = json::parse(systemJson);
389
Alpana Kumari1b026112022-03-02 23:41:38 -0600390 string hwKeyword = getHW(vpdMap);
Alpana Kumarif05effd2021-04-07 07:32:53 -0500391 const string imKeyword = getIM(vpdMap);
392
Alpana Kumari1b026112022-03-02 23:41:38 -0600393 transform(hwKeyword.begin(), hwKeyword.end(), hwKeyword.begin(),
394 ::toupper);
395
Alpana Kumarif05effd2021-04-07 07:32:53 -0500396 if (js.find("system") == js.end())
397 {
398 throw runtime_error("Invalid systems Json");
399 }
400
401 if (js["system"].find(imKeyword) == js["system"].end())
402 {
403 throw runtime_error(
404 "Invalid system. This system type is not present "
405 "in the systemsJson. IM: " +
406 imKeyword);
407 }
408
409 if ((js["system"][imKeyword].find("constraint") !=
410 js["system"][imKeyword].end()) &&
Alpana Kumari1b026112022-03-02 23:41:38 -0600411 js["system"][imKeyword]["constraint"].find("HW") !=
412 js["system"][imKeyword]["constraint"].end())
Alpana Kumarif05effd2021-04-07 07:32:53 -0500413 {
Alpana Kumari1b026112022-03-02 23:41:38 -0600414 // collect hw versions from json, and check hwKeyword is part of it
415 // if hwKeyword is found there then load respective json
416 // otherwise load default one.
417 for (const auto& hwVersion :
418 js["system"][imKeyword]["constraint"]["HW"])
419 {
420 string hw = hwVersion;
421 transform(hw.begin(), hw.end(), hw.begin(), ::toupper);
422
423 if (hw == hwKeyword)
424 {
425 jsonName = js["system"][imKeyword]["constraint"]["json"];
426 break;
427 }
428 }
429
430 if (jsonName.empty() && js["system"][imKeyword].find("default") !=
431 js["system"][imKeyword].end())
432 {
433 jsonName = js["system"][imKeyword]["default"];
434 }
Alpana Kumarif05effd2021-04-07 07:32:53 -0500435 }
436 else if (js["system"][imKeyword].find("default") !=
437 js["system"][imKeyword].end())
438 {
439 jsonName = js["system"][imKeyword]["default"];
440 }
441 else
442 {
443 throw runtime_error(
444 "Bad System json. Neither constraint nor default found");
445 }
446
447 jsonPath += jsonName;
448 }
449
Patrick Williams8e15b932021-10-06 13:04:22 -0500450 catch (const json::parse_error& ex)
Alpana Kumarif05effd2021-04-07 07:32:53 -0500451 {
452 throw(VpdJsonException("Json Parsing failed", SYSTEM_JSON));
453 }
454 return jsonPath;
455}
456
PriyangaRamasamy647868e2020-09-08 17:03:19 +0530457void udevToGenericPath(string& file)
458{
459 // Sample udevEvent i2c path :
460 // "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem"
461 // find if the path contains the word i2c in it.
462 if (file.find("i2c") != string::npos)
463 {
464 string i2cBusAddr{};
465
466 // Every udev i2c path should have the common pattern
467 // "i2c-bus_number/bus_number-vpd_address". Search for
468 // "bus_number-vpd_address".
469 regex i2cPattern("((i2c)-[0-9]+\\/)([0-9]+-[0-9]{4})");
470 smatch match;
471 if (regex_search(file, match, i2cPattern))
472 {
473 i2cBusAddr = match.str(3);
474 }
475 else
476 {
477 cerr << "The given udev path < " << file
478 << " > doesn't match the required pattern. Skipping VPD "
479 "collection."
480 << endl;
481 exit(EXIT_SUCCESS);
482 }
483 // Forming the generic file path
484 file = i2cPathPrefix + i2cBusAddr + "/eeprom";
485 }
486 // Sample udevEvent spi path :
487 // "/sys/devices/platform/ahb/ahb:apb/1e79b000.fsi/fsi-master/fsi0/slave@00:00/00:00:00:04/spi_master/spi2/spi2.0/spi2.00/nvmem"
488 // find if the path contains the word spi in it.
489 else if (file.find("spi") != string::npos)
490 {
491 // Every udev spi path will have common pattern "spi<Digit>/", which
492 // describes the spi bus number at which the fru is connected; Followed
493 // by a slash following the vpd address of the fru. Taking the above
494 // input as a common key, we try to search for the pattern "spi<Digit>/"
495 // using regular expression.
496 regex spiPattern("((spi)[0-9]+)(\\/)");
497 string spiBus{};
498 smatch match;
499 if (regex_search(file, match, spiPattern))
500 {
501 spiBus = match.str(1);
502 }
503 else
504 {
505 cerr << "The given udev path < " << file
506 << " > doesn't match the required pattern. Skipping VPD "
507 "collection."
508 << endl;
509 exit(EXIT_SUCCESS);
510 }
511 // Forming the generic path
512 file = spiPathPrefix + spiBus + ".0/eeprom";
513 }
514 else
515 {
516 cerr << "\n The given EEPROM path < " << file
517 << " > is not valid. It's neither I2C nor "
518 "SPI path. Skipping VPD collection.."
519 << endl;
520 exit(EXIT_SUCCESS);
521 }
522}
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -0600523string getBadVpdName(const string& file)
524{
525 string badVpd = BAD_VPD_DIR;
526 if (file.find("i2c") != string::npos)
527 {
528 badVpd += "i2c-";
529 regex i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
530 smatch match;
531 if (regex_search(file, match, i2cPattern))
532 {
533 badVpd += match.str(2);
534 }
535 }
536 else if (file.find("spi") != string::npos)
537 {
538 regex spiPattern("((spi)[0-9]+)(.0)");
539 smatch match;
540 if (regex_search(file, match, spiPattern))
541 {
542 badVpd += match.str(1);
543 }
544 }
545 return badVpd;
546}
547
548void dumpBadVpd(const string& file, const Binary& vpdVector)
549{
550 fs::path badVpdDir = BAD_VPD_DIR;
551 fs::create_directory(badVpdDir);
552 string badVpdPath = getBadVpdName(file);
553 if (fs::exists(badVpdPath))
554 {
555 std::error_code ec;
556 fs::remove(badVpdPath, ec);
557 if (ec) // error code
558 {
559 string error = "Error removing the existing broken vpd in ";
560 error += badVpdPath;
561 error += ". Error code : ";
562 error += ec.value();
563 error += ". Error message : ";
564 error += ec.message();
565 throw runtime_error(error);
566 }
567 }
568 ofstream badVpdFileStream(badVpdPath, ofstream::binary);
569 if (!badVpdFileStream)
570 {
571 throw runtime_error("Failed to open bad vpd file path in /tmp/bad-vpd. "
572 "Unable to dump the broken/bad vpd file.");
573 }
574 badVpdFileStream.write(reinterpret_cast<const char*>(vpdVector.data()),
575 vpdVector.size());
576}
alpana077ce68722021-07-25 13:23:59 -0500577
578const string getKwVal(const Parsed& vpdMap, const string& rec,
579 const string& kwd)
580{
581 string kwVal{};
582
583 auto findRec = vpdMap.find(rec);
584
585 // check if record is found in map we got by parser
586 if (findRec != vpdMap.end())
587 {
588 auto findKwd = findRec->second.find(kwd);
589
590 if (findKwd != findRec->second.end())
591 {
592 kwVal = findKwd->second;
593 }
594 }
595
596 return kwVal;
597}
598
Priyanga Ramasamyc9ecf8e2021-10-08 02:28:52 -0500599string byteArrayToHexString(const Binary& vec)
600{
601 stringstream ss;
602 string hexRep = "0x";
603 ss << hexRep;
604 string str = ss.str();
605
606 // convert Decimal to Hex string
607 for (auto& v : vec)
608 {
609 ss << setfill('0') << setw(2) << hex << (int)v;
610 str = ss.str();
611 }
612 return str;
613}
614
615string getPrintableValue(const Binary& vec)
Priyanga Ramasamy02434932021-10-07 16:26:05 -0500616{
617 string str{};
Priyanga Ramasamy02434932021-10-07 16:26:05 -0500618
Priyanga Ramasamyc9ecf8e2021-10-08 02:28:52 -0500619 // find for a non printable value in the vector
620 const auto it = std::find_if(vec.begin(), vec.end(),
621 [](const auto& ele) { return !isprint(ele); });
Priyanga Ramasamy02434932021-10-07 16:26:05 -0500622
Priyanga Ramasamyc9ecf8e2021-10-08 02:28:52 -0500623 if (it != vec.end()) // if the given vector has any non printable value
624 {
625 for (auto itr = it; itr != vec.end(); itr++)
Priyanga Ramasamy02434932021-10-07 16:26:05 -0500626 {
Priyanga Ramasamyc9ecf8e2021-10-08 02:28:52 -0500627 if (*itr != 0x00)
628 {
629 str = byteArrayToHexString(vec);
630 return str;
631 }
Priyanga Ramasamy02434932021-10-07 16:26:05 -0500632 }
Priyanga Ramasamyc9ecf8e2021-10-08 02:28:52 -0500633 str = string(vec.begin(), it);
Priyanga Ramasamy02434932021-10-07 16:26:05 -0500634 }
635 else
636 {
637 str = string(vec.begin(), vec.end());
638 }
639 return str;
640}
641
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600642/*
643 * @brief Log PEL for GPIO exception
644 *
645 * @param[in] gpioErr gpioError type exception
646 * @param[in] i2cBusAddr I2C bus and address
647 */
648void logGpioPel(const string& gpioErr, const string& i2cBusAddr)
649{
650 // Get the IIC details
651 vector<string> i2cReg;
652 boost::split(i2cReg, i2cBusAddr, boost::is_any_of("-"));
653
654 PelAdditionalData additionalData{};
655 if (i2cReg.size() == 2)
656 {
657 additionalData.emplace("CALLOUT_IIC_BUS", i2cReg[0]);
658 additionalData.emplace("CALLOUT_IIC_ADDR", "0x" + i2cReg[1]);
659 }
660
661 additionalData.emplace("DESCRIPTION", gpioErr);
662 createPEL(additionalData, PelSeverity::WARNING, errIntfForGpioError);
663}
664
Alpana Kumari735dee92022-03-25 01:24:40 -0500665void executePostFailAction(const nlohmann::json& json, const string& file)
666{
667 if ((json["frus"][file].at(0)).find("postActionFail") ==
668 json["frus"][file].at(0).end())
669 {
670 return;
671 }
672
673 uint8_t pinValue = 0;
674 string pinName;
675
676 for (const auto& postAction :
677 (json["frus"][file].at(0))["postActionFail"].items())
678 {
679 if (postAction.key() == "pin")
680 {
681 pinName = postAction.value();
682 }
683 else if (postAction.key() == "value")
684 {
685 // Get the value to set
686 pinValue = postAction.value();
687 }
688 }
689
690 cout << "Setting GPIO: " << pinName << " to " << (int)pinValue << endl;
691
692 try
693 {
694 gpiod::line outputLine = gpiod::find_line(pinName);
695
696 if (!outputLine)
697 {
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600698 throw runtime_error(
699 "Couldn't find output line for the GPIO. Skipping "
700 "this GPIO action.");
Alpana Kumari735dee92022-03-25 01:24:40 -0500701 }
702 outputLine.request(
703 {"Disable line", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
704 pinValue);
705 }
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600706 catch (const exception& e)
Alpana Kumari735dee92022-03-25 01:24:40 -0500707 {
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600708 string i2cBusAddr;
709 string errMsg = e.what();
710 errMsg += "\nGPIO: " + pinName;
711
712 if ((json["frus"][file].at(0)["postActionFail"].find(
713 "gpioI2CAddress")) !=
714 json["frus"][file].at(0)["postActionFail"].end())
715 {
716 i2cBusAddr =
717 json["frus"][file].at(0)["postActionFail"]["gpioI2CAddress"];
718 }
719
720 logGpioPel(errMsg, i2cBusAddr);
Alpana Kumari735dee92022-03-25 01:24:40 -0500721 }
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600722
723 return;
Alpana Kumari735dee92022-03-25 01:24:40 -0500724}
725
Santosh Puranik53b38ed2022-04-10 23:15:22 +0530726std::optional<bool> isPresent(const nlohmann::json& json, const string& file)
727
Alpana Kumari735dee92022-03-25 01:24:40 -0500728{
729 if ((json["frus"][file].at(0)).find("presence") !=
730 json["frus"][file].at(0).end())
731 {
732 if (((json["frus"][file].at(0)["presence"]).find("pin") !=
733 json["frus"][file].at(0)["presence"].end()) &&
734 ((json["frus"][file].at(0)["presence"]).find("value") !=
735 json["frus"][file].at(0)["presence"].end()))
736 {
737 string presPinName = json["frus"][file].at(0)["presence"]["pin"];
738 Byte presPinValue = json["frus"][file].at(0)["presence"]["value"];
739
740 try
741 {
742 gpiod::line presenceLine = gpiod::find_line(presPinName);
743
744 if (!presenceLine)
745 {
Alpana Kumari40d1c192022-03-09 21:16:02 -0600746 cerr << "Couldn't find the presence line for - "
747 << presPinName << endl;
748
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600749 throw runtime_error(
750 "Couldn't find the presence line for the "
751 "GPIO. Skipping this GPIO action.");
Alpana Kumari735dee92022-03-25 01:24:40 -0500752 }
753
754 presenceLine.request({"Read the presence line",
755 gpiod::line_request::DIRECTION_INPUT, 0});
756
757 Byte gpioData = presenceLine.get_value();
758
Santosh Puranik53b38ed2022-04-10 23:15:22 +0530759 return (gpioData == presPinValue);
Alpana Kumari735dee92022-03-25 01:24:40 -0500760 }
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600761 catch (const exception& e)
Alpana Kumari735dee92022-03-25 01:24:40 -0500762 {
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600763 string i2cBusAddr;
764 string errMsg = e.what();
765 errMsg += " GPIO : " + presPinName;
766
767 if ((json["frus"][file].at(0)["presence"])
768 .find("gpioI2CAddress") !=
769 json["frus"][file].at(0)["presence"].end())
770 {
771 i2cBusAddr =
772 json["frus"][file].at(0)["presence"]["gpioI2CAddress"];
773 }
774
775 logGpioPel(errMsg, i2cBusAddr);
Alpana Kumari40d1c192022-03-09 21:16:02 -0600776 // Take failure postAction
777 executePostFailAction(json, file);
Alpana Kumari735dee92022-03-25 01:24:40 -0500778 return false;
779 }
780 }
Alpana Kumari40d1c192022-03-09 21:16:02 -0600781 else
782 {
783 // missing required informations
784 cerr << "VPD inventory JSON missing basic informations of presence "
785 "for this FRU : ["
786 << file << "]. Executing executePostFailAction." << endl;
787
788 // Take failure postAction
789 executePostFailAction(json, file);
790
791 return false;
792 }
Alpana Kumari735dee92022-03-25 01:24:40 -0500793 }
Santosh Puranik53b38ed2022-04-10 23:15:22 +0530794 return std::optional<bool>{};
795}
796
797bool executePreAction(const nlohmann::json& json, const string& file)
798{
799 auto present = isPresent(json, file);
800 if (present && !present.value())
801 {
802 executePostFailAction(json, file);
803 return false;
804 }
Alpana Kumari735dee92022-03-25 01:24:40 -0500805
806 if ((json["frus"][file].at(0)).find("preAction") !=
807 json["frus"][file].at(0).end())
808 {
809 if (((json["frus"][file].at(0)["preAction"]).find("pin") !=
810 json["frus"][file].at(0)["preAction"].end()) &&
811 ((json["frus"][file].at(0)["preAction"]).find("value") !=
812 json["frus"][file].at(0)["preAction"].end()))
813 {
814 string pinName = json["frus"][file].at(0)["preAction"]["pin"];
815 // Get the value to set
816 Byte pinValue = json["frus"][file].at(0)["preAction"]["value"];
817
818 cout << "Setting GPIO: " << pinName << " to " << (int)pinValue
819 << endl;
820 try
821 {
822 gpiod::line outputLine = gpiod::find_line(pinName);
823
824 if (!outputLine)
825 {
Alpana Kumari40d1c192022-03-09 21:16:02 -0600826 cerr << "Couldn't find the line for output pin - "
827 << pinName << endl;
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600828 throw runtime_error(
829 "Couldn't find output line for the GPIO. "
830 "Skipping this GPIO action.");
Alpana Kumari735dee92022-03-25 01:24:40 -0500831 }
832 outputLine.request({"FRU pre-action",
833 ::gpiod::line_request::DIRECTION_OUTPUT, 0},
834 pinValue);
835 }
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600836 catch (const exception& e)
Alpana Kumari735dee92022-03-25 01:24:40 -0500837 {
Alpana Kumari6bd095f2022-02-23 10:20:20 -0600838 string i2cBusAddr;
839 string errMsg = e.what();
840 errMsg += " GPIO : " + pinName;
841
842 if ((json["frus"][file].at(0)["preAction"])
843 .find("gpioI2CAddress") !=
844 json["frus"][file].at(0)["preAction"].end())
845 {
846 i2cBusAddr =
847 json["frus"][file].at(0)["preAction"]["gpioI2CAddress"];
848 }
849
850 logGpioPel(errMsg, i2cBusAddr);
Alpana Kumari40d1c192022-03-09 21:16:02 -0600851
852 // Take failure postAction
853 executePostFailAction(json, file);
854
Alpana Kumari735dee92022-03-25 01:24:40 -0500855 return false;
856 }
857 }
Alpana Kumari40d1c192022-03-09 21:16:02 -0600858 else
859 {
860 // missing required informations
861 cerr
862 << "VPD inventory JSON missing basic informations of preAction "
863 "for this FRU : ["
864 << file << "]. Executing executePostFailAction." << endl;
865
866 // Take failure postAction
867 executePostFailAction(json, file);
868
869 return false;
870 }
Alpana Kumari735dee92022-03-25 01:24:40 -0500871 }
872 return true;
873}
874
Priyanga Ramasamyaa8a8932022-01-27 09:12:41 -0600875void insertOrMerge(inventory::InterfaceMap& map,
876 const inventory::Interface& interface,
877 inventory::PropertyMap&& property)
878{
879 if (map.find(interface) != map.end())
880 {
881 auto& prop = map.at(interface);
882 prop.insert(property.begin(), property.end());
883 }
884 else
885 {
886 map.emplace(interface, property);
887 }
888}
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500889
890BIOSAttrValueType readBIOSAttribute(const std::string& attrName)
891{
892 std::tuple<std::string, BIOSAttrValueType, BIOSAttrValueType> attrVal;
893 auto bus = sdbusplus::bus::new_default();
894 auto method = bus.new_method_call(
895 "xyz.openbmc_project.BIOSConfigManager",
896 "/xyz/openbmc_project/bios_config/manager",
897 "xyz.openbmc_project.BIOSConfig.Manager", "GetAttribute");
898 method.append(attrName);
899 try
900 {
901 auto result = bus.call(method);
902 result.read(std::get<0>(attrVal), std::get<1>(attrVal),
903 std::get<2>(attrVal));
904 }
905 catch (const sdbusplus::exception::SdBusError& e)
906 {
907 std::cerr << "Failed to read BIOS Attribute: " << attrName << std::endl;
908 std::cerr << e.what() << std::endl;
909 }
910 return std::get<1>(attrVal);
911}
Priyanga Ramasamy335873f2022-05-18 01:31:54 -0500912
913std::string getPowerState()
914{
915 // TODO: How do we handle multiple chassis?
916 string powerState{};
917 auto bus = sdbusplus::bus::new_default();
918 auto properties =
919 bus.new_method_call("xyz.openbmc_project.State.Chassis",
920 "/xyz/openbmc_project/state/chassis0",
921 "org.freedesktop.DBus.Properties", "Get");
922 properties.append("xyz.openbmc_project.State.Chassis");
923 properties.append("CurrentPowerState");
924 auto result = bus.call(properties);
925 if (!result.is_method_error())
926 {
927 variant<string> val;
928 result.read(val);
929 if (auto pVal = get_if<string>(&val))
930 {
931 powerState = *pVal;
932 }
933 }
934 cout << "Power state is: " << powerState << endl;
935 return powerState;
936}
Patrick Venturec83c4dc2018-11-01 16:29:18 -0700937} // namespace vpd
Alpana Kumari735dee92022-03-25 01:24:40 -0500938} // namespace openpower