16c71c9dcSSunny Srivastava #include "config.h" 26c71c9dcSSunny Srivastava 36c71c9dcSSunny Srivastava #include "ibm_vpd_utils.hpp" 46c71c9dcSSunny Srivastava 56c71c9dcSSunny Srivastava #include "common_utility.hpp" 66c71c9dcSSunny Srivastava #include "defines.hpp" 76c71c9dcSSunny Srivastava #include "vpd_exceptions.hpp" 86c71c9dcSSunny Srivastava 96bd095f9SAlpana Kumari #include <boost/algorithm/string.hpp> 10735dee9bSAlpana Kumari #include <gpiod.hpp> 116c71c9dcSSunny Srivastava #include <nlohmann/json.hpp> 126c71c9dcSSunny Srivastava #include <phosphor-logging/elog-errors.hpp> 136c71c9dcSSunny Srivastava #include <phosphor-logging/log.hpp> 146c71c9dcSSunny Srivastava #include <sdbusplus/server.hpp> 15*c78d887cSPatrick Williams #include <xyz/openbmc_project/Common/error.hpp> 16*c78d887cSPatrick Williams 17*c78d887cSPatrick Williams #include <filesystem> 18*c78d887cSPatrick Williams #include <fstream> 19*c78d887cSPatrick Williams #include <iomanip> 20*c78d887cSPatrick Williams #include <regex> 216c71c9dcSSunny Srivastava #include <sstream> 226c71c9dcSSunny Srivastava #include <vector> 236c71c9dcSSunny Srivastava 246c71c9dcSSunny Srivastava using json = nlohmann::json; 256c71c9dcSSunny Srivastava 266c71c9dcSSunny Srivastava namespace openpower 276c71c9dcSSunny Srivastava { 286c71c9dcSSunny Srivastava namespace vpd 296c71c9dcSSunny Srivastava { 306c71c9dcSSunny Srivastava using namespace openpower::vpd::constants; 316c71c9dcSSunny Srivastava using namespace inventory; 326c71c9dcSSunny Srivastava using namespace phosphor::logging; 336c71c9dcSSunny Srivastava using namespace sdbusplus::xyz::openbmc_project::Common::Error; 346c71c9dcSSunny Srivastava using namespace record; 356c71c9dcSSunny Srivastava using namespace openpower::vpd::exceptions; 366c71c9dcSSunny Srivastava using namespace common::utility; 370746eeebSSunny Srivastava using Severity = openpower::vpd::constants::PelSeverity; 38c2fe40f8SPriyangaRamasamy namespace fs = std::filesystem; 390746eeebSSunny Srivastava 400746eeebSSunny Srivastava // mapping of severity enum to severity interface 410746eeebSSunny Srivastava static std::unordered_map<Severity, std::string> sevMap = { 420746eeebSSunny Srivastava {Severity::INFORMATIONAL, 430746eeebSSunny Srivastava "xyz.openbmc_project.Logging.Entry.Level.Informational"}, 440746eeebSSunny Srivastava {Severity::DEBUG, "xyz.openbmc_project.Logging.Entry.Level.Debug"}, 450746eeebSSunny Srivastava {Severity::NOTICE, "xyz.openbmc_project.Logging.Entry.Level.Notice"}, 460746eeebSSunny Srivastava {Severity::WARNING, "xyz.openbmc_project.Logging.Entry.Level.Warning"}, 470746eeebSSunny Srivastava {Severity::CRITICAL, "xyz.openbmc_project.Logging.Entry.Level.Critical"}, 480746eeebSSunny Srivastava {Severity::EMERGENCY, "xyz.openbmc_project.Logging.Entry.Level.Emergency"}, 490746eeebSSunny Srivastava {Severity::ERROR, "xyz.openbmc_project.Logging.Entry.Level.Error"}, 500746eeebSSunny Srivastava {Severity::ALERT, "xyz.openbmc_project.Logging.Entry.Level.Alert"}}; 510746eeebSSunny Srivastava 526c71c9dcSSunny Srivastava namespace inventory 536c71c9dcSSunny Srivastava { 546c71c9dcSSunny Srivastava 556c71c9dcSSunny Srivastava MapperResponse 566c71c9dcSSunny Srivastava getObjectSubtreeForInterfaces(const std::string& root, const int32_t depth, 576c71c9dcSSunny Srivastava const std::vector<std::string>& interfaces) 586c71c9dcSSunny Srivastava { 596c71c9dcSSunny Srivastava auto bus = sdbusplus::bus::new_default(); 606c71c9dcSSunny Srivastava auto mapperCall = bus.new_method_call(mapperDestination, mapperObjectPath, 616c71c9dcSSunny Srivastava mapperInterface, "GetSubTree"); 626c71c9dcSSunny Srivastava mapperCall.append(root); 636c71c9dcSSunny Srivastava mapperCall.append(depth); 646c71c9dcSSunny Srivastava mapperCall.append(interfaces); 656c71c9dcSSunny Srivastava 666c71c9dcSSunny Srivastava MapperResponse result = {}; 676c71c9dcSSunny Srivastava 686c71c9dcSSunny Srivastava try 696c71c9dcSSunny Srivastava { 706c71c9dcSSunny Srivastava auto response = bus.call(mapperCall); 716c71c9dcSSunny Srivastava 726c71c9dcSSunny Srivastava response.read(result); 736c71c9dcSSunny Srivastava } 742eb0176cSPatrick Williams catch (const sdbusplus::exception_t& e) 756c71c9dcSSunny Srivastava { 766c71c9dcSSunny Srivastava log<level::ERR>("Error in mapper GetSubTree", 776c71c9dcSSunny Srivastava entry("ERROR=%s", e.what())); 786c71c9dcSSunny Srivastava } 796c71c9dcSSunny Srivastava 806c71c9dcSSunny Srivastava return result; 816c71c9dcSSunny Srivastava } 826c71c9dcSSunny Srivastava 836c71c9dcSSunny Srivastava } // namespace inventory 846c71c9dcSSunny Srivastava 856c71c9dcSSunny Srivastava LE2ByteData readUInt16LE(Binary::const_iterator iterator) 866c71c9dcSSunny Srivastava { 876c71c9dcSSunny Srivastava LE2ByteData lowByte = *iterator; 886c71c9dcSSunny Srivastava LE2ByteData highByte = *(iterator + 1); 896c71c9dcSSunny Srivastava lowByte |= (highByte << 8); 906c71c9dcSSunny Srivastava return lowByte; 916c71c9dcSSunny Srivastava } 926c71c9dcSSunny Srivastava 936c71c9dcSSunny Srivastava /** @brief Encodes a keyword for D-Bus. 946c71c9dcSSunny Srivastava */ 95e008432aSPriyanga Ramasamy std::string encodeKeyword(const std::string& kw, const std::string& encoding) 966c71c9dcSSunny Srivastava { 976c71c9dcSSunny Srivastava if (encoding == "MAC") 986c71c9dcSSunny Srivastava { 99e008432aSPriyanga Ramasamy std::string res{}; 1006c71c9dcSSunny Srivastava size_t first = kw[0]; 1016c71c9dcSSunny Srivastava res += toHex(first >> 4); 1026c71c9dcSSunny Srivastava res += toHex(first & 0x0f); 1036c71c9dcSSunny Srivastava for (size_t i = 1; i < kw.size(); ++i) 1046c71c9dcSSunny Srivastava { 1056c71c9dcSSunny Srivastava res += ":"; 1066c71c9dcSSunny Srivastava res += toHex(kw[i] >> 4); 1076c71c9dcSSunny Srivastava res += toHex(kw[i] & 0x0f); 1086c71c9dcSSunny Srivastava } 1096c71c9dcSSunny Srivastava return res; 1106c71c9dcSSunny Srivastava } 1116c71c9dcSSunny Srivastava else if (encoding == "DATE") 1126c71c9dcSSunny Srivastava { 1136c71c9dcSSunny Srivastava // Date, represent as 1146c71c9dcSSunny Srivastava // <year>-<month>-<day> <hour>:<min> 115e008432aSPriyanga Ramasamy std::string res{}; 1166c71c9dcSSunny Srivastava static constexpr uint8_t skipPrefix = 3; 1176c71c9dcSSunny Srivastava 1186c71c9dcSSunny Srivastava auto strItr = kw.begin(); 1196c71c9dcSSunny Srivastava advance(strItr, skipPrefix); 1206c71c9dcSSunny Srivastava for_each(strItr, kw.end(), [&res](size_t c) { res += c; }); 1216c71c9dcSSunny Srivastava 1226c71c9dcSSunny Srivastava res.insert(BD_YEAR_END, 1, '-'); 1236c71c9dcSSunny Srivastava res.insert(BD_MONTH_END, 1, '-'); 1246c71c9dcSSunny Srivastava res.insert(BD_DAY_END, 1, ' '); 1256c71c9dcSSunny Srivastava res.insert(BD_HOUR_END, 1, ':'); 1266c71c9dcSSunny Srivastava 1276c71c9dcSSunny Srivastava return res; 1286c71c9dcSSunny Srivastava } 1296c71c9dcSSunny Srivastava else // default to string encoding 1306c71c9dcSSunny Srivastava { 131e008432aSPriyanga Ramasamy return std::string(kw.begin(), kw.end()); 1326c71c9dcSSunny Srivastava } 1336c71c9dcSSunny Srivastava } 1346c71c9dcSSunny Srivastava 135e008432aSPriyanga Ramasamy std::string readBusProperty(const std::string& obj, const std::string& inf, 136e008432aSPriyanga Ramasamy const std::string& prop) 1376c71c9dcSSunny Srivastava { 1386c71c9dcSSunny Srivastava std::string propVal{}; 1396c71c9dcSSunny Srivastava std::string object = INVENTORY_PATH + obj; 1406c71c9dcSSunny Srivastava auto bus = sdbusplus::bus::new_default(); 1416c71c9dcSSunny Srivastava auto properties = bus.new_method_call( 1426c71c9dcSSunny Srivastava "xyz.openbmc_project.Inventory.Manager", object.c_str(), 1436c71c9dcSSunny Srivastava "org.freedesktop.DBus.Properties", "Get"); 1446c71c9dcSSunny Srivastava properties.append(inf); 1456c71c9dcSSunny Srivastava properties.append(prop); 1466c71c9dcSSunny Srivastava auto result = bus.call(properties); 1476c71c9dcSSunny Srivastava if (!result.is_method_error()) 1486c71c9dcSSunny Srivastava { 14928abd6e4SSunny Srivastava inventory::Value val; 1506c71c9dcSSunny Srivastava result.read(val); 151e008432aSPriyanga Ramasamy if (auto pVal = std::get_if<Binary>(&val)) 1526c71c9dcSSunny Srivastava { 1536c71c9dcSSunny Srivastava propVal.assign(reinterpret_cast<const char*>(pVal->data()), 1546c71c9dcSSunny Srivastava pVal->size()); 1556c71c9dcSSunny Srivastava } 156e008432aSPriyanga Ramasamy else if (auto pVal = std::get_if<std::string>(&val)) 1576c71c9dcSSunny Srivastava { 1586c71c9dcSSunny Srivastava propVal.assign(pVal->data(), pVal->size()); 1596c71c9dcSSunny Srivastava } 16028abd6e4SSunny Srivastava else if (auto pVal = get_if<bool>(&val)) 16128abd6e4SSunny Srivastava { 16228abd6e4SSunny Srivastava if (*pVal == false) 16328abd6e4SSunny Srivastava { 16428abd6e4SSunny Srivastava propVal = "false"; 16528abd6e4SSunny Srivastava } 16628abd6e4SSunny Srivastava else 16728abd6e4SSunny Srivastava { 16828abd6e4SSunny Srivastava propVal = "true"; 16928abd6e4SSunny Srivastava } 17028abd6e4SSunny Srivastava } 1716c71c9dcSSunny Srivastava } 1726c71c9dcSSunny Srivastava return propVal; 1736c71c9dcSSunny Srivastava } 1746c71c9dcSSunny Srivastava 1756c71c9dcSSunny Srivastava void createPEL(const std::map<std::string, std::string>& additionalData, 176a2ddc96eSSunny Srivastava const Severity& sev, const std::string& errIntf, sd_bus* sdBus) 177a2ddc96eSSunny Srivastava { 178a2ddc96eSSunny Srivastava // This pointer will be NULL in case the call is made from ibm-read-vpd. In 179a2ddc96eSSunny Srivastava // that case a sync call will do. 180a2ddc96eSSunny Srivastava if (sdBus == nullptr) 181a2ddc96eSSunny Srivastava { 182a2ddc96eSSunny Srivastava createSyncPEL(additionalData, sev, errIntf); 183a2ddc96eSSunny Srivastava } 184a2ddc96eSSunny Srivastava else 185a2ddc96eSSunny Srivastava { 186a2ddc96eSSunny Srivastava std::string errDescription{}; 187a2ddc96eSSunny Srivastava auto pos = additionalData.find("DESCRIPTION"); 188a2ddc96eSSunny Srivastava if (pos != additionalData.end()) 189a2ddc96eSSunny Srivastava { 190a2ddc96eSSunny Srivastava errDescription = pos->second; 191a2ddc96eSSunny Srivastava } 192a2ddc96eSSunny Srivastava else 193a2ddc96eSSunny Srivastava { 194a2ddc96eSSunny Srivastava errDescription = "Description field missing in additional data"; 195a2ddc96eSSunny Srivastava } 196a2ddc96eSSunny Srivastava 197a2ddc96eSSunny Srivastava std::string pelSeverity = 198a2ddc96eSSunny Srivastava "xyz.openbmc_project.Logging.Entry.Level.Error"; 199a2ddc96eSSunny Srivastava auto itr = sevMap.find(sev); 200a2ddc96eSSunny Srivastava if (itr != sevMap.end()) 201a2ddc96eSSunny Srivastava { 202a2ddc96eSSunny Srivastava pelSeverity = itr->second; 203a2ddc96eSSunny Srivastava } 204a2ddc96eSSunny Srivastava 205a2ddc96eSSunny Srivastava // Implies this is a call from Manager. Hence we need to make an async 206a2ddc96eSSunny Srivastava // call to avoid deadlock with Phosphor-logging. 207a2ddc96eSSunny Srivastava auto rc = sd_bus_call_method_async( 208a2ddc96eSSunny Srivastava sdBus, NULL, loggerService, loggerObjectPath, loggerCreateInterface, 209a2ddc96eSSunny Srivastava "Create", NULL, NULL, "ssa{ss}", errIntf.c_str(), 210a2ddc96eSSunny Srivastava pelSeverity.c_str(), 1, "DESCRIPTION", errDescription.c_str()); 211a2ddc96eSSunny Srivastava 212a2ddc96eSSunny Srivastava if (rc < 0) 213a2ddc96eSSunny Srivastava { 214a2ddc96eSSunny Srivastava log<level::ERR>("Error calling sd_bus_call_method_async", 215a2ddc96eSSunny Srivastava entry("RC=%d", rc), entry("MSG=%s", strerror(-rc))); 216a2ddc96eSSunny Srivastava } 217a2ddc96eSSunny Srivastava } 218a2ddc96eSSunny Srivastava } 219a2ddc96eSSunny Srivastava 220a2ddc96eSSunny Srivastava void createSyncPEL(const std::map<std::string, std::string>& additionalData, 2210746eeebSSunny Srivastava const Severity& sev, const std::string& errIntf) 2226c71c9dcSSunny Srivastava { 2236c71c9dcSSunny Srivastava try 2246c71c9dcSSunny Srivastava { 2250746eeebSSunny Srivastava std::string pelSeverity = 2260746eeebSSunny Srivastava "xyz.openbmc_project.Logging.Entry.Level.Error"; 2276c71c9dcSSunny Srivastava auto bus = sdbusplus::bus::new_default(); 2286c71c9dcSSunny Srivastava auto service = getService(bus, loggerObjectPath, loggerCreateInterface); 2296c71c9dcSSunny Srivastava auto method = bus.new_method_call(service.c_str(), loggerObjectPath, 2306c71c9dcSSunny Srivastava loggerCreateInterface, "Create"); 2316c71c9dcSSunny Srivastava 2320746eeebSSunny Srivastava auto itr = sevMap.find(sev); 2330746eeebSSunny Srivastava if (itr != sevMap.end()) 2340746eeebSSunny Srivastava { 2350746eeebSSunny Srivastava pelSeverity = itr->second; 2360746eeebSSunny Srivastava } 2370746eeebSSunny Srivastava 2380746eeebSSunny Srivastava method.append(errIntf, pelSeverity, additionalData); 2396c71c9dcSSunny Srivastava auto resp = bus.call(method); 2406c71c9dcSSunny Srivastava } 2412eb0176cSPatrick Williams catch (const sdbusplus::exception_t& e) 2426c71c9dcSSunny Srivastava { 2435ef6ccc0SSunny Srivastava std::cerr << "Dbus call to phosphor-logging Create failed. Reason:" 2445ef6ccc0SSunny Srivastava << e.what(); 2456c71c9dcSSunny Srivastava } 2466c71c9dcSSunny Srivastava } 2476c71c9dcSSunny Srivastava 248e008432aSPriyanga Ramasamy inventory::VPDfilepath getVpdFilePath(const std::string& jsonFile, 2496c71c9dcSSunny Srivastava const std::string& ObjPath) 2506c71c9dcSSunny Srivastava { 251e008432aSPriyanga Ramasamy std::ifstream inventoryJson(jsonFile); 2526c71c9dcSSunny Srivastava const auto& jsonObject = json::parse(inventoryJson); 2536c71c9dcSSunny Srivastava inventory::VPDfilepath filePath{}; 2546c71c9dcSSunny Srivastava 2556c71c9dcSSunny Srivastava if (jsonObject.find("frus") == jsonObject.end()) 2566c71c9dcSSunny Srivastava { 2576c71c9dcSSunny Srivastava throw(VpdJsonException( 2586c71c9dcSSunny Srivastava "Invalid JSON structure - frus{} object not found in ", jsonFile)); 2596c71c9dcSSunny Srivastava } 2606c71c9dcSSunny Srivastava 2616c71c9dcSSunny Srivastava const nlohmann::json& groupFRUS = 2626c71c9dcSSunny Srivastava jsonObject["frus"].get_ref<const nlohmann::json::object_t&>(); 2636c71c9dcSSunny Srivastava for (const auto& itemFRUS : groupFRUS.items()) 2646c71c9dcSSunny Srivastava { 2656c71c9dcSSunny Srivastava const std::vector<nlohmann::json>& groupEEPROM = 2666c71c9dcSSunny Srivastava itemFRUS.value().get_ref<const nlohmann::json::array_t&>(); 2676c71c9dcSSunny Srivastava for (const auto& itemEEPROM : groupEEPROM) 2686c71c9dcSSunny Srivastava { 2696c71c9dcSSunny Srivastava if (itemEEPROM["inventoryPath"] 2706c71c9dcSSunny Srivastava .get_ref<const nlohmann::json::string_t&>() == ObjPath) 2716c71c9dcSSunny Srivastava { 2726c71c9dcSSunny Srivastava filePath = itemFRUS.key(); 2736c71c9dcSSunny Srivastava return filePath; 2746c71c9dcSSunny Srivastava } 2756c71c9dcSSunny Srivastava } 2766c71c9dcSSunny Srivastava } 2776c71c9dcSSunny Srivastava 2786c71c9dcSSunny Srivastava return filePath; 2796c71c9dcSSunny Srivastava } 2806c71c9dcSSunny Srivastava 2816c71c9dcSSunny Srivastava bool isPathInJson(const std::string& eepromPath) 2826c71c9dcSSunny Srivastava { 2836c71c9dcSSunny Srivastava bool present = false; 284e008432aSPriyanga Ramasamy std::ifstream inventoryJson(INVENTORY_JSON_SYM_LINK); 2856c71c9dcSSunny Srivastava 2866c71c9dcSSunny Srivastava try 2876c71c9dcSSunny Srivastava { 2886c71c9dcSSunny Srivastava auto js = json::parse(inventoryJson); 2896c71c9dcSSunny Srivastava if (js.find("frus") == js.end()) 2906c71c9dcSSunny Srivastava { 2916c71c9dcSSunny Srivastava throw(VpdJsonException( 2926c71c9dcSSunny Srivastava "Invalid JSON structure - frus{} object not found in ", 2936c71c9dcSSunny Srivastava INVENTORY_JSON_SYM_LINK)); 2946c71c9dcSSunny Srivastava } 2956c71c9dcSSunny Srivastava json fruJson = js["frus"]; 2966c71c9dcSSunny Srivastava 2976c71c9dcSSunny Srivastava if (fruJson.find(eepromPath) != fruJson.end()) 2986c71c9dcSSunny Srivastava { 2996c71c9dcSSunny Srivastava present = true; 3006c71c9dcSSunny Srivastava } 3016c71c9dcSSunny Srivastava } 3028e15b93aSPatrick Williams catch (const json::parse_error& ex) 3036c71c9dcSSunny Srivastava { 3046c71c9dcSSunny Srivastava throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK)); 3056c71c9dcSSunny Srivastava } 3066c71c9dcSSunny Srivastava return present; 3076c71c9dcSSunny Srivastava } 3086c71c9dcSSunny Srivastava 3096c71c9dcSSunny Srivastava bool isRecKwInDbusJson(const std::string& recordName, 3106c71c9dcSSunny Srivastava const std::string& keyword) 3116c71c9dcSSunny Srivastava { 312e008432aSPriyanga Ramasamy std::ifstream propertyJson(DBUS_PROP_JSON); 3136c71c9dcSSunny Srivastava json dbusProperty; 3146c71c9dcSSunny Srivastava bool present = false; 3156c71c9dcSSunny Srivastava 3166c71c9dcSSunny Srivastava if (propertyJson.is_open()) 3176c71c9dcSSunny Srivastava { 3186c71c9dcSSunny Srivastava try 3196c71c9dcSSunny Srivastava { 3206c71c9dcSSunny Srivastava auto dbusPropertyJson = json::parse(propertyJson); 3216c71c9dcSSunny Srivastava if (dbusPropertyJson.find("dbusProperties") == 3226c71c9dcSSunny Srivastava dbusPropertyJson.end()) 3236c71c9dcSSunny Srivastava { 3246c71c9dcSSunny Srivastava throw(VpdJsonException("dbusProperties{} object not found in " 3256c71c9dcSSunny Srivastava "DbusProperties json : ", 3266c71c9dcSSunny Srivastava DBUS_PROP_JSON)); 3276c71c9dcSSunny Srivastava } 3286c71c9dcSSunny Srivastava 3296c71c9dcSSunny Srivastava dbusProperty = dbusPropertyJson["dbusProperties"]; 3306c71c9dcSSunny Srivastava if (dbusProperty.contains(recordName)) 3316c71c9dcSSunny Srivastava { 332e008432aSPriyanga Ramasamy const std::vector<std::string>& kwdsToPublish = 333e008432aSPriyanga Ramasamy dbusProperty[recordName]; 3346c71c9dcSSunny Srivastava if (find(kwdsToPublish.begin(), kwdsToPublish.end(), keyword) != 3356c71c9dcSSunny Srivastava kwdsToPublish.end()) // present 3366c71c9dcSSunny Srivastava { 3376c71c9dcSSunny Srivastava present = true; 3386c71c9dcSSunny Srivastava } 3396c71c9dcSSunny Srivastava } 3406c71c9dcSSunny Srivastava } 3418e15b93aSPatrick Williams catch (const json::parse_error& ex) 3426c71c9dcSSunny Srivastava { 3436c71c9dcSSunny Srivastava throw(VpdJsonException("Json Parsing failed", DBUS_PROP_JSON)); 3446c71c9dcSSunny Srivastava } 3456c71c9dcSSunny Srivastava } 3466c71c9dcSSunny Srivastava else 3476c71c9dcSSunny Srivastava { 3486c71c9dcSSunny Srivastava // If dbus properties json is not available, we assume the given 3496c71c9dcSSunny Srivastava // record-keyword is part of dbus-properties json. So setting the bool 3506c71c9dcSSunny Srivastava // variable to true. 3516c71c9dcSSunny Srivastava present = true; 3526c71c9dcSSunny Srivastava } 3536c71c9dcSSunny Srivastava return present; 3546c71c9dcSSunny Srivastava } 3556c71c9dcSSunny Srivastava 3566c71c9dcSSunny Srivastava vpdType vpdTypeCheck(const Binary& vpdVector) 3576c71c9dcSSunny Srivastava { 3586c71c9dcSSunny Srivastava // Read first 3 Bytes to check the 11S bar code format 3596c71c9dcSSunny Srivastava std::string is11SFormat = ""; 3606c71c9dcSSunny Srivastava for (uint8_t i = 0; i < FORMAT_11S_LEN; i++) 3616c71c9dcSSunny Srivastava { 3626c71c9dcSSunny Srivastava is11SFormat += vpdVector[MEMORY_VPD_DATA_START + i]; 3636c71c9dcSSunny Srivastava } 3646c71c9dcSSunny Srivastava 3656c71c9dcSSunny Srivastava if (vpdVector[IPZ_DATA_START] == KW_VAL_PAIR_START_TAG) 3666c71c9dcSSunny Srivastava { 3676c71c9dcSSunny Srivastava // IPZ VPD FORMAT 3686c71c9dcSSunny Srivastava return vpdType::IPZ_VPD; 3696c71c9dcSSunny Srivastava } 3706c71c9dcSSunny Srivastava else if (vpdVector[KW_VPD_DATA_START] == KW_VPD_START_TAG) 3716c71c9dcSSunny Srivastava { 3726c71c9dcSSunny Srivastava // KEYWORD VPD FORMAT 3736c71c9dcSSunny Srivastava return vpdType::KEYWORD_VPD; 3746c71c9dcSSunny Srivastava } 3756555e7efSjinuthomas else if (((vpdVector[SPD_BYTE_3] & SPD_BYTE_BIT_0_3_MASK) == 3766555e7efSjinuthomas SPD_MODULE_TYPE_DDIMM) && 3770abbb9c9Sjinuthomas (is11SFormat.compare(MEMORY_VPD_START_TAG) == 0)) 3786c71c9dcSSunny Srivastava { 3796555e7efSjinuthomas // DDIMM Memory VPD format 3806555e7efSjinuthomas if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR5) 3816555e7efSjinuthomas { 3826555e7efSjinuthomas return vpdType::DDR5_DDIMM_MEMORY_VPD; 3836555e7efSjinuthomas } 3846555e7efSjinuthomas else if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR4) 3856555e7efSjinuthomas { 3866555e7efSjinuthomas return vpdType::DDR4_DDIMM_MEMORY_VPD; 3876555e7efSjinuthomas } 3886555e7efSjinuthomas } 3896555e7efSjinuthomas else if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR5) 3906555e7efSjinuthomas { 3916555e7efSjinuthomas // ISDIMM Memory VPD format 3926555e7efSjinuthomas return vpdType::DDR5_ISDIMM_MEMORY_VPD; 3936555e7efSjinuthomas } 3946555e7efSjinuthomas else if ((vpdVector[SPD_BYTE_2] & SPD_BYTE_MASK) == SPD_DRAM_TYPE_DDR4) 3956555e7efSjinuthomas { 3966555e7efSjinuthomas // ISDIMM Memory VPD format 3976555e7efSjinuthomas return vpdType::DDR4_ISDIMM_MEMORY_VPD; 3986c71c9dcSSunny Srivastava } 3996c71c9dcSSunny Srivastava 4006c71c9dcSSunny Srivastava // INVALID VPD FORMAT 4016c71c9dcSSunny Srivastava return vpdType::INVALID_VPD_FORMAT; 4026c71c9dcSSunny Srivastava } 4036c71c9dcSSunny Srivastava 404e008432aSPriyanga Ramasamy const std::string getIM(const Parsed& vpdMap) 405f05effdbSAlpana Kumari { 406f05effdbSAlpana Kumari Binary imVal; 407f05effdbSAlpana Kumari auto property = vpdMap.find("VSBP"); 408f05effdbSAlpana Kumari if (property != vpdMap.end()) 409f05effdbSAlpana Kumari { 410f05effdbSAlpana Kumari auto kw = (property->second).find("IM"); 411f05effdbSAlpana Kumari if (kw != (property->second).end()) 412f05effdbSAlpana Kumari { 413f05effdbSAlpana Kumari copy(kw->second.begin(), kw->second.end(), back_inserter(imVal)); 414f05effdbSAlpana Kumari } 415f05effdbSAlpana Kumari } 416f05effdbSAlpana Kumari 417e008432aSPriyanga Ramasamy std::ostringstream oss; 418f05effdbSAlpana Kumari for (auto& i : imVal) 419f05effdbSAlpana Kumari { 420e008432aSPriyanga Ramasamy oss << std::setw(2) << std::setfill('0') << std::hex 421e008432aSPriyanga Ramasamy << static_cast<int>(i); 422f05effdbSAlpana Kumari } 423f05effdbSAlpana Kumari 424f05effdbSAlpana Kumari return oss.str(); 425f05effdbSAlpana Kumari } 426f05effdbSAlpana Kumari 427e008432aSPriyanga Ramasamy const std::string getHW(const Parsed& vpdMap) 428f05effdbSAlpana Kumari { 429f05effdbSAlpana Kumari Binary hwVal; 430f05effdbSAlpana Kumari auto prop = vpdMap.find("VINI"); 431f05effdbSAlpana Kumari if (prop != vpdMap.end()) 432f05effdbSAlpana Kumari { 433f05effdbSAlpana Kumari auto kw = (prop->second).find("HW"); 434f05effdbSAlpana Kumari if (kw != (prop->second).end()) 435f05effdbSAlpana Kumari { 436f05effdbSAlpana Kumari copy(kw->second.begin(), kw->second.end(), back_inserter(hwVal)); 437f05effdbSAlpana Kumari } 438f05effdbSAlpana Kumari } 439f05effdbSAlpana Kumari 44088d2ae82SAlpana Kumari // The planar pass only comes from the LSB of the HW keyword, 44188d2ae82SAlpana Kumari // where as the MSB is used for other purposes such as signifying clock 44288d2ae82SAlpana Kumari // termination. 44388d2ae82SAlpana Kumari hwVal[0] = 0x00; 44488d2ae82SAlpana Kumari 445e008432aSPriyanga Ramasamy std::ostringstream hwString; 446f05effdbSAlpana Kumari for (auto& i : hwVal) 447f05effdbSAlpana Kumari { 448e008432aSPriyanga Ramasamy hwString << std::setw(2) << std::setfill('0') << std::hex 449e008432aSPriyanga Ramasamy << static_cast<int>(i); 450f05effdbSAlpana Kumari } 451f05effdbSAlpana Kumari 452f05effdbSAlpana Kumari return hwString.str(); 453f05effdbSAlpana Kumari } 454f05effdbSAlpana Kumari 455e008432aSPriyanga Ramasamy std::string getSystemsJson(const Parsed& vpdMap) 456f05effdbSAlpana Kumari { 457e008432aSPriyanga Ramasamy std::string jsonPath = "/usr/share/vpd/"; 458e008432aSPriyanga Ramasamy std::string jsonName{}; 459f05effdbSAlpana Kumari 460e008432aSPriyanga Ramasamy std::ifstream systemJson(SYSTEM_JSON); 461f05effdbSAlpana Kumari if (!systemJson) 462f05effdbSAlpana Kumari { 463f05effdbSAlpana Kumari throw((VpdJsonException("Failed to access Json path", SYSTEM_JSON))); 464f05effdbSAlpana Kumari } 465f05effdbSAlpana Kumari 466f05effdbSAlpana Kumari try 467f05effdbSAlpana Kumari { 468f05effdbSAlpana Kumari auto js = json::parse(systemJson); 469f05effdbSAlpana Kumari 470e008432aSPriyanga Ramasamy std::string hwKeyword = getHW(vpdMap); 471e008432aSPriyanga Ramasamy const std::string imKeyword = getIM(vpdMap); 472f05effdbSAlpana Kumari 4731b026119SAlpana Kumari transform(hwKeyword.begin(), hwKeyword.end(), hwKeyword.begin(), 4741b026119SAlpana Kumari ::toupper); 4751b026119SAlpana Kumari 476f05effdbSAlpana Kumari if (js.find("system") == js.end()) 477f05effdbSAlpana Kumari { 478e008432aSPriyanga Ramasamy throw std::runtime_error("Invalid systems Json"); 479f05effdbSAlpana Kumari } 480f05effdbSAlpana Kumari 481f05effdbSAlpana Kumari if (js["system"].find(imKeyword) == js["system"].end()) 482f05effdbSAlpana Kumari { 483e008432aSPriyanga Ramasamy throw std::runtime_error( 484f05effdbSAlpana Kumari "Invalid system. This system type is not present " 485f05effdbSAlpana Kumari "in the systemsJson. IM: " + 486f05effdbSAlpana Kumari imKeyword); 487f05effdbSAlpana Kumari } 488f05effdbSAlpana Kumari 489f05effdbSAlpana Kumari if ((js["system"][imKeyword].find("constraint") != 490f05effdbSAlpana Kumari js["system"][imKeyword].end()) && 4911b026119SAlpana Kumari js["system"][imKeyword]["constraint"].find("HW") != 4921b026119SAlpana Kumari js["system"][imKeyword]["constraint"].end()) 4931b026119SAlpana Kumari { 4941b026119SAlpana Kumari // collect hw versions from json, and check hwKeyword is part of it 4951b026119SAlpana Kumari // if hwKeyword is found there then load respective json 4961b026119SAlpana Kumari // otherwise load default one. 4971b026119SAlpana Kumari for (const auto& hwVersion : 4981b026119SAlpana Kumari js["system"][imKeyword]["constraint"]["HW"]) 4991b026119SAlpana Kumari { 500e008432aSPriyanga Ramasamy std::string hw = hwVersion; 5011b026119SAlpana Kumari transform(hw.begin(), hw.end(), hw.begin(), ::toupper); 5021b026119SAlpana Kumari 5031b026119SAlpana Kumari if (hw == hwKeyword) 504f05effdbSAlpana Kumari { 505f05effdbSAlpana Kumari jsonName = js["system"][imKeyword]["constraint"]["json"]; 5061b026119SAlpana Kumari break; 5071b026119SAlpana Kumari } 5081b026119SAlpana Kumari } 5091b026119SAlpana Kumari 5101b026119SAlpana Kumari if (jsonName.empty() && js["system"][imKeyword].find("default") != 5111b026119SAlpana Kumari js["system"][imKeyword].end()) 5121b026119SAlpana Kumari { 5131b026119SAlpana Kumari jsonName = js["system"][imKeyword]["default"]; 5141b026119SAlpana Kumari } 515f05effdbSAlpana Kumari } 516f05effdbSAlpana Kumari else if (js["system"][imKeyword].find("default") != 517f05effdbSAlpana Kumari js["system"][imKeyword].end()) 518f05effdbSAlpana Kumari { 519f05effdbSAlpana Kumari jsonName = js["system"][imKeyword]["default"]; 520f05effdbSAlpana Kumari } 521f05effdbSAlpana Kumari else 522f05effdbSAlpana Kumari { 523e008432aSPriyanga Ramasamy throw std::runtime_error( 524f05effdbSAlpana Kumari "Bad System json. Neither constraint nor default found"); 525f05effdbSAlpana Kumari } 526f05effdbSAlpana Kumari 527f05effdbSAlpana Kumari jsonPath += jsonName; 528f05effdbSAlpana Kumari } 529f05effdbSAlpana Kumari 5308e15b93aSPatrick Williams catch (const json::parse_error& ex) 531f05effdbSAlpana Kumari { 532f05effdbSAlpana Kumari throw(VpdJsonException("Json Parsing failed", SYSTEM_JSON)); 533f05effdbSAlpana Kumari } 534f05effdbSAlpana Kumari return jsonPath; 535f05effdbSAlpana Kumari } 536f05effdbSAlpana Kumari 537f457a3efSjinuthomas void udevToGenericPath(std::string& file, const std::string& driver) 538647868edSPriyangaRamasamy { 539647868edSPriyangaRamasamy // Sample udevEvent i2c path : 540647868edSPriyangaRamasamy // "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem" 541647868edSPriyangaRamasamy // find if the path contains the word i2c in it. 542e008432aSPriyanga Ramasamy if (file.find("i2c") != std::string::npos) 543647868edSPriyangaRamasamy { 544e008432aSPriyanga Ramasamy std::string i2cBusAddr{}; 545647868edSPriyangaRamasamy 546647868edSPriyangaRamasamy // Every udev i2c path should have the common pattern 547647868edSPriyangaRamasamy // "i2c-bus_number/bus_number-vpd_address". Search for 548647868edSPriyangaRamasamy // "bus_number-vpd_address". 549e008432aSPriyanga Ramasamy std::regex i2cPattern("((i2c)-[0-9]+\\/)([0-9]+-[0-9]{4})"); 550e008432aSPriyanga Ramasamy std::smatch match; 551e008432aSPriyanga Ramasamy if (std::regex_search(file, match, i2cPattern)) 552647868edSPriyangaRamasamy { 553647868edSPriyangaRamasamy i2cBusAddr = match.str(3); 554647868edSPriyangaRamasamy } 555647868edSPriyangaRamasamy else 556647868edSPriyangaRamasamy { 557e008432aSPriyanga Ramasamy std::cerr << "The given udev path < " << file 558647868edSPriyangaRamasamy << " > doesn't match the required pattern. Skipping VPD " 559647868edSPriyangaRamasamy "collection." 560e008432aSPriyanga Ramasamy << std::endl; 561647868edSPriyangaRamasamy exit(EXIT_SUCCESS); 562647868edSPriyangaRamasamy } 563647868edSPriyangaRamasamy // Forming the generic file path 564f457a3efSjinuthomas file = i2cPathPrefix + driver + "/" + i2cBusAddr + "/eeprom"; 565647868edSPriyangaRamasamy } 566647868edSPriyangaRamasamy // Sample udevEvent spi path : 567647868edSPriyangaRamasamy // "/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" 568647868edSPriyangaRamasamy // find if the path contains the word spi in it. 569e008432aSPriyanga Ramasamy else if (file.find("spi") != std::string::npos) 570647868edSPriyangaRamasamy { 571647868edSPriyangaRamasamy // Every udev spi path will have common pattern "spi<Digit>/", which 572647868edSPriyangaRamasamy // describes the spi bus number at which the fru is connected; Followed 573647868edSPriyangaRamasamy // by a slash following the vpd address of the fru. Taking the above 574647868edSPriyangaRamasamy // input as a common key, we try to search for the pattern "spi<Digit>/" 575647868edSPriyangaRamasamy // using regular expression. 576e008432aSPriyanga Ramasamy std::regex spiPattern("((spi)[0-9]+)(\\/)"); 577e008432aSPriyanga Ramasamy std::string spiBus{}; 578e008432aSPriyanga Ramasamy std::smatch match; 579e008432aSPriyanga Ramasamy if (std::regex_search(file, match, spiPattern)) 580647868edSPriyangaRamasamy { 581647868edSPriyangaRamasamy spiBus = match.str(1); 582647868edSPriyangaRamasamy } 583647868edSPriyangaRamasamy else 584647868edSPriyangaRamasamy { 585e008432aSPriyanga Ramasamy std::cerr << "The given udev path < " << file 586647868edSPriyangaRamasamy << " > doesn't match the required pattern. Skipping VPD " 587647868edSPriyangaRamasamy "collection." 588e008432aSPriyanga Ramasamy << std::endl; 589647868edSPriyangaRamasamy exit(EXIT_SUCCESS); 590647868edSPriyangaRamasamy } 591647868edSPriyangaRamasamy // Forming the generic path 592f457a3efSjinuthomas file = spiPathPrefix + driver + "/" + spiBus + ".0/eeprom"; 593647868edSPriyangaRamasamy } 594647868edSPriyangaRamasamy else 595647868edSPriyangaRamasamy { 596e008432aSPriyanga Ramasamy std::cerr << "\n The given EEPROM path < " << file 597647868edSPriyangaRamasamy << " > is not valid. It's neither I2C nor " 598647868edSPriyangaRamasamy "SPI path. Skipping VPD collection.." 599e008432aSPriyanga Ramasamy << std::endl; 600647868edSPriyangaRamasamy exit(EXIT_SUCCESS); 601647868edSPriyangaRamasamy } 602647868edSPriyangaRamasamy } 603e008432aSPriyanga Ramasamy std::string getBadVpdName(const std::string& file) 604c2fe40f8SPriyangaRamasamy { 605e008432aSPriyanga Ramasamy std::string badVpd = BAD_VPD_DIR; 606e008432aSPriyanga Ramasamy if (file.find("i2c") != std::string::npos) 607c2fe40f8SPriyangaRamasamy { 608c2fe40f8SPriyangaRamasamy badVpd += "i2c-"; 609e008432aSPriyanga Ramasamy std::regex i2cPattern("(at24/)([0-9]+-[0-9]+)\\/"); 610e008432aSPriyanga Ramasamy std::smatch match; 611e008432aSPriyanga Ramasamy if (std::regex_search(file, match, i2cPattern)) 612c2fe40f8SPriyangaRamasamy { 613c2fe40f8SPriyangaRamasamy badVpd += match.str(2); 614c2fe40f8SPriyangaRamasamy } 615c2fe40f8SPriyangaRamasamy } 616e008432aSPriyanga Ramasamy else if (file.find("spi") != std::string::npos) 617c2fe40f8SPriyangaRamasamy { 618e008432aSPriyanga Ramasamy std::regex spiPattern("((spi)[0-9]+)(.0)"); 619e008432aSPriyanga Ramasamy std::smatch match; 620e008432aSPriyanga Ramasamy if (std::regex_search(file, match, spiPattern)) 621c2fe40f8SPriyangaRamasamy { 622c2fe40f8SPriyangaRamasamy badVpd += match.str(1); 623c2fe40f8SPriyangaRamasamy } 624c2fe40f8SPriyangaRamasamy } 625c2fe40f8SPriyangaRamasamy return badVpd; 626c2fe40f8SPriyangaRamasamy } 627c2fe40f8SPriyangaRamasamy 628e008432aSPriyanga Ramasamy void dumpBadVpd(const std::string& file, const Binary& vpdVector) 629c2fe40f8SPriyangaRamasamy { 630c2fe40f8SPriyangaRamasamy fs::path badVpdDir = BAD_VPD_DIR; 631c2fe40f8SPriyangaRamasamy fs::create_directory(badVpdDir); 632e008432aSPriyanga Ramasamy std::string badVpdPath = getBadVpdName(file); 633c2fe40f8SPriyangaRamasamy if (fs::exists(badVpdPath)) 634c2fe40f8SPriyangaRamasamy { 635c2fe40f8SPriyangaRamasamy std::error_code ec; 636c2fe40f8SPriyangaRamasamy fs::remove(badVpdPath, ec); 637c2fe40f8SPriyangaRamasamy if (ec) // error code 638c2fe40f8SPriyangaRamasamy { 639e008432aSPriyanga Ramasamy std::string error = "Error removing the existing broken vpd in "; 640c2fe40f8SPriyangaRamasamy error += badVpdPath; 641c2fe40f8SPriyangaRamasamy error += ". Error code : "; 642c2fe40f8SPriyangaRamasamy error += ec.value(); 643c2fe40f8SPriyangaRamasamy error += ". Error message : "; 644c2fe40f8SPriyangaRamasamy error += ec.message(); 645e008432aSPriyanga Ramasamy throw std::runtime_error(error); 646c2fe40f8SPriyangaRamasamy } 647c2fe40f8SPriyangaRamasamy } 648e008432aSPriyanga Ramasamy std::ofstream badVpdFileStream(badVpdPath, std::ofstream::binary); 649c2fe40f8SPriyangaRamasamy if (!badVpdFileStream) 650c2fe40f8SPriyangaRamasamy { 651e008432aSPriyanga Ramasamy throw std::runtime_error( 652e008432aSPriyanga Ramasamy "Failed to open bad vpd file path in /tmp/bad-vpd. " 653c2fe40f8SPriyangaRamasamy "Unable to dump the broken/bad vpd file."); 654c2fe40f8SPriyangaRamasamy } 655c2fe40f8SPriyangaRamasamy badVpdFileStream.write(reinterpret_cast<const char*>(vpdVector.data()), 656c2fe40f8SPriyangaRamasamy vpdVector.size()); 657c2fe40f8SPriyangaRamasamy } 6587ce68724Salpana07 659e008432aSPriyanga Ramasamy const std::string getKwVal(const Parsed& vpdMap, const std::string& rec, 660e008432aSPriyanga Ramasamy const std::string& kwd) 6617ce68724Salpana07 { 662e008432aSPriyanga Ramasamy std::string kwVal{}; 6637ce68724Salpana07 6647ce68724Salpana07 auto findRec = vpdMap.find(rec); 6657ce68724Salpana07 6667ce68724Salpana07 // check if record is found in map we got by parser 6677ce68724Salpana07 if (findRec != vpdMap.end()) 6687ce68724Salpana07 { 6697ce68724Salpana07 auto findKwd = findRec->second.find(kwd); 6707ce68724Salpana07 6717ce68724Salpana07 if (findKwd != findRec->second.end()) 6727ce68724Salpana07 { 6737ce68724Salpana07 kwVal = findKwd->second; 6747ce68724Salpana07 } 6757ce68724Salpana07 } 6767ce68724Salpana07 6777ce68724Salpana07 return kwVal; 6787ce68724Salpana07 } 6797ce68724Salpana07 68063639101SGiridhariKrishnan std::string hexString(const std::variant<Binary, std::string>& kw) 68163639101SGiridhariKrishnan { 68263639101SGiridhariKrishnan std::string hexString; 68363639101SGiridhariKrishnan std::visit( 68463639101SGiridhariKrishnan [&hexString](auto&& kw) { 685e008432aSPriyanga Ramasamy std::stringstream ss; 686e008432aSPriyanga Ramasamy std::string hexRep = "0x"; 68702434931SPriyanga Ramasamy ss << hexRep; 688b498cd3cSgirik for (auto& kwVal : kw) 689b498cd3cSgirik { 69063639101SGiridhariKrishnan ss << std::setfill('0') << std::setw(2) << std::hex 69163639101SGiridhariKrishnan << static_cast<int>(kwVal); 69202434931SPriyanga Ramasamy } 693b498cd3cSgirik hexString = ss.str(); 69463639101SGiridhariKrishnan }, 69563639101SGiridhariKrishnan kw); 69663639101SGiridhariKrishnan return hexString; 697c9ecf8eaSPriyanga Ramasamy } 698c9ecf8eaSPriyanga Ramasamy 69963639101SGiridhariKrishnan std::string getPrintableValue(const std::variant<Binary, std::string>& kwVal) 700c9ecf8eaSPriyanga Ramasamy { 70163639101SGiridhariKrishnan std::string kwString{}; 70263639101SGiridhariKrishnan std::visit( 70363639101SGiridhariKrishnan [&kwString](auto&& kwVal) { 70463639101SGiridhariKrishnan const auto it = 70563639101SGiridhariKrishnan std::find_if(kwVal.begin(), kwVal.end(), 70663639101SGiridhariKrishnan [](const auto& kw) { return !isprint(kw); }); 70763639101SGiridhariKrishnan if (it != kwVal.end()) 708c9ecf8eaSPriyanga Ramasamy { 70963639101SGiridhariKrishnan bool printable = true; 71063639101SGiridhariKrishnan for (auto itr = it; itr != kwVal.end(); itr++) 711c9ecf8eaSPriyanga Ramasamy { 712c9ecf8eaSPriyanga Ramasamy if (*itr != 0x00) 713c9ecf8eaSPriyanga Ramasamy { 71463639101SGiridhariKrishnan kwString = hexString(kwVal); 71563639101SGiridhariKrishnan printable = false; 71663639101SGiridhariKrishnan break; 717c9ecf8eaSPriyanga Ramasamy } 718c9ecf8eaSPriyanga Ramasamy } 71963639101SGiridhariKrishnan if (printable) 72063639101SGiridhariKrishnan { 72163639101SGiridhariKrishnan kwString = std::string(kwVal.begin(), it); 72263639101SGiridhariKrishnan } 72302434931SPriyanga Ramasamy } 72402434931SPriyanga Ramasamy else 72502434931SPriyanga Ramasamy { 72663639101SGiridhariKrishnan kwString = std::string(kwVal.begin(), kwVal.end()); 72702434931SPriyanga Ramasamy } 72863639101SGiridhariKrishnan }, 72963639101SGiridhariKrishnan kwVal); 73063639101SGiridhariKrishnan return kwString; 73102434931SPriyanga Ramasamy } 73202434931SPriyanga Ramasamy 733e008432aSPriyanga Ramasamy void executePostFailAction(const nlohmann::json& json, const std::string& file) 734735dee9bSAlpana Kumari { 735735dee9bSAlpana Kumari if ((json["frus"][file].at(0)).find("postActionFail") == 736735dee9bSAlpana Kumari json["frus"][file].at(0).end()) 737735dee9bSAlpana Kumari { 738735dee9bSAlpana Kumari return; 739735dee9bSAlpana Kumari } 740735dee9bSAlpana Kumari 741735dee9bSAlpana Kumari uint8_t pinValue = 0; 742e008432aSPriyanga Ramasamy std::string pinName; 743735dee9bSAlpana Kumari 744735dee9bSAlpana Kumari for (const auto& postAction : 745735dee9bSAlpana Kumari (json["frus"][file].at(0))["postActionFail"].items()) 746735dee9bSAlpana Kumari { 747735dee9bSAlpana Kumari if (postAction.key() == "pin") 748735dee9bSAlpana Kumari { 749735dee9bSAlpana Kumari pinName = postAction.value(); 750735dee9bSAlpana Kumari } 751735dee9bSAlpana Kumari else if (postAction.key() == "value") 752735dee9bSAlpana Kumari { 753735dee9bSAlpana Kumari // Get the value to set 754735dee9bSAlpana Kumari pinValue = postAction.value(); 755735dee9bSAlpana Kumari } 756735dee9bSAlpana Kumari } 757735dee9bSAlpana Kumari 758e008432aSPriyanga Ramasamy std::cout << "Setting GPIO: " << pinName << " to " << (int)pinValue 759e008432aSPriyanga Ramasamy << std::endl; 760735dee9bSAlpana Kumari 761735dee9bSAlpana Kumari try 762735dee9bSAlpana Kumari { 763735dee9bSAlpana Kumari gpiod::line outputLine = gpiod::find_line(pinName); 764735dee9bSAlpana Kumari 765735dee9bSAlpana Kumari if (!outputLine) 766735dee9bSAlpana Kumari { 767a2ddc96eSSunny Srivastava throw GpioException( 7686bd095f9SAlpana Kumari "Couldn't find output line for the GPIO. Skipping " 7696bd095f9SAlpana Kumari "this GPIO action."); 770735dee9bSAlpana Kumari } 771735dee9bSAlpana Kumari outputLine.request( 772735dee9bSAlpana Kumari {"Disable line", ::gpiod::line_request::DIRECTION_OUTPUT, 0}, 773735dee9bSAlpana Kumari pinValue); 774735dee9bSAlpana Kumari } 775e008432aSPriyanga Ramasamy catch (const std::exception& e) 776735dee9bSAlpana Kumari { 777e008432aSPriyanga Ramasamy std::string i2cBusAddr; 778e008432aSPriyanga Ramasamy std::string errMsg = e.what(); 7796bd095f9SAlpana Kumari errMsg += "\nGPIO: " + pinName; 7806bd095f9SAlpana Kumari 7816bd095f9SAlpana Kumari if ((json["frus"][file].at(0)["postActionFail"].find( 7826bd095f9SAlpana Kumari "gpioI2CAddress")) != 7836bd095f9SAlpana Kumari json["frus"][file].at(0)["postActionFail"].end()) 7846bd095f9SAlpana Kumari { 7856bd095f9SAlpana Kumari i2cBusAddr = 7866bd095f9SAlpana Kumari json["frus"][file].at(0)["postActionFail"]["gpioI2CAddress"]; 787fdf9ff2aSSunny Srivastava errMsg += " i2cBusAddress: " + i2cBusAddr; 788735dee9bSAlpana Kumari } 7896bd095f9SAlpana Kumari 790a2ddc96eSSunny Srivastava throw GpioException(e.what()); 7916bd095f9SAlpana Kumari } 7926bd095f9SAlpana Kumari 7936bd095f9SAlpana Kumari return; 794735dee9bSAlpana Kumari } 795735dee9bSAlpana Kumari 796e008432aSPriyanga Ramasamy std::optional<bool> isPresent(const nlohmann::json& json, 797e008432aSPriyanga Ramasamy const std::string& file) 79853b38ed0SSantosh Puranik 799735dee9bSAlpana Kumari { 800735dee9bSAlpana Kumari if ((json["frus"][file].at(0)).find("presence") != 801735dee9bSAlpana Kumari json["frus"][file].at(0).end()) 802735dee9bSAlpana Kumari { 803735dee9bSAlpana Kumari if (((json["frus"][file].at(0)["presence"]).find("pin") != 804735dee9bSAlpana Kumari json["frus"][file].at(0)["presence"].end()) && 805735dee9bSAlpana Kumari ((json["frus"][file].at(0)["presence"]).find("value") != 806735dee9bSAlpana Kumari json["frus"][file].at(0)["presence"].end())) 807735dee9bSAlpana Kumari { 808e008432aSPriyanga Ramasamy std::string presPinName = 809e008432aSPriyanga Ramasamy json["frus"][file].at(0)["presence"]["pin"]; 810735dee9bSAlpana Kumari Byte presPinValue = json["frus"][file].at(0)["presence"]["value"]; 811735dee9bSAlpana Kumari 812735dee9bSAlpana Kumari try 813735dee9bSAlpana Kumari { 814735dee9bSAlpana Kumari gpiod::line presenceLine = gpiod::find_line(presPinName); 815735dee9bSAlpana Kumari 816735dee9bSAlpana Kumari if (!presenceLine) 817735dee9bSAlpana Kumari { 818e008432aSPriyanga Ramasamy std::cerr << "Couldn't find the presence line for - " 819e008432aSPriyanga Ramasamy << presPinName << std::endl; 82040d1c196SAlpana Kumari 821a2ddc96eSSunny Srivastava throw GpioException( 8226bd095f9SAlpana Kumari "Couldn't find the presence line for the " 8236bd095f9SAlpana Kumari "GPIO. Skipping this GPIO action."); 824735dee9bSAlpana Kumari } 825735dee9bSAlpana Kumari 826735dee9bSAlpana Kumari presenceLine.request({"Read the presence line", 827735dee9bSAlpana Kumari gpiod::line_request::DIRECTION_INPUT, 0}); 828735dee9bSAlpana Kumari 829735dee9bSAlpana Kumari Byte gpioData = presenceLine.get_value(); 830735dee9bSAlpana Kumari 83153b38ed0SSantosh Puranik return (gpioData == presPinValue); 832735dee9bSAlpana Kumari } 833e008432aSPriyanga Ramasamy catch (const std::exception& e) 834735dee9bSAlpana Kumari { 835e008432aSPriyanga Ramasamy std::string i2cBusAddr; 836e008432aSPriyanga Ramasamy std::string errMsg = e.what(); 8376bd095f9SAlpana Kumari errMsg += " GPIO : " + presPinName; 8386bd095f9SAlpana Kumari 8396bd095f9SAlpana Kumari if ((json["frus"][file].at(0)["presence"]) 8406bd095f9SAlpana Kumari .find("gpioI2CAddress") != 8416bd095f9SAlpana Kumari json["frus"][file].at(0)["presence"].end()) 8426bd095f9SAlpana Kumari { 8436bd095f9SAlpana Kumari i2cBusAddr = 8446bd095f9SAlpana Kumari json["frus"][file].at(0)["presence"]["gpioI2CAddress"]; 845fdf9ff2aSSunny Srivastava errMsg += " i2cBusAddress: " + i2cBusAddr; 8466bd095f9SAlpana Kumari } 8476bd095f9SAlpana Kumari 84840d1c196SAlpana Kumari // Take failure postAction 84940d1c196SAlpana Kumari executePostFailAction(json, file); 850a2ddc96eSSunny Srivastava throw GpioException(errMsg); 851735dee9bSAlpana Kumari } 852735dee9bSAlpana Kumari } 85340d1c196SAlpana Kumari else 85440d1c196SAlpana Kumari { 85540d1c196SAlpana Kumari // missing required informations 856e008432aSPriyanga Ramasamy std::cerr 857e008432aSPriyanga Ramasamy << "VPD inventory JSON missing basic informations of presence " 85840d1c196SAlpana Kumari "for this FRU : [" 859e008432aSPriyanga Ramasamy << file << "]. Executing executePostFailAction." << std::endl; 86040d1c196SAlpana Kumari 86140d1c196SAlpana Kumari // Take failure postAction 86240d1c196SAlpana Kumari executePostFailAction(json, file); 86340d1c196SAlpana Kumari 86440d1c196SAlpana Kumari return false; 86540d1c196SAlpana Kumari } 866735dee9bSAlpana Kumari } 86753b38ed0SSantosh Puranik return std::optional<bool>{}; 86853b38ed0SSantosh Puranik } 86953b38ed0SSantosh Puranik 870e008432aSPriyanga Ramasamy bool executePreAction(const nlohmann::json& json, const std::string& file) 87153b38ed0SSantosh Puranik { 87253b38ed0SSantosh Puranik auto present = isPresent(json, file); 87353b38ed0SSantosh Puranik if (present && !present.value()) 87453b38ed0SSantosh Puranik { 87553b38ed0SSantosh Puranik executePostFailAction(json, file); 87653b38ed0SSantosh Puranik return false; 87753b38ed0SSantosh Puranik } 878735dee9bSAlpana Kumari 879735dee9bSAlpana Kumari if ((json["frus"][file].at(0)).find("preAction") != 880735dee9bSAlpana Kumari json["frus"][file].at(0).end()) 881735dee9bSAlpana Kumari { 882735dee9bSAlpana Kumari if (((json["frus"][file].at(0)["preAction"]).find("pin") != 883735dee9bSAlpana Kumari json["frus"][file].at(0)["preAction"].end()) && 884735dee9bSAlpana Kumari ((json["frus"][file].at(0)["preAction"]).find("value") != 885735dee9bSAlpana Kumari json["frus"][file].at(0)["preAction"].end())) 886735dee9bSAlpana Kumari { 887e008432aSPriyanga Ramasamy std::string pinName = json["frus"][file].at(0)["preAction"]["pin"]; 888735dee9bSAlpana Kumari // Get the value to set 889735dee9bSAlpana Kumari Byte pinValue = json["frus"][file].at(0)["preAction"]["value"]; 890735dee9bSAlpana Kumari 891e008432aSPriyanga Ramasamy std::cout << "Setting GPIO: " << pinName << " to " << (int)pinValue 892e008432aSPriyanga Ramasamy << std::endl; 893735dee9bSAlpana Kumari try 894735dee9bSAlpana Kumari { 895735dee9bSAlpana Kumari gpiod::line outputLine = gpiod::find_line(pinName); 896735dee9bSAlpana Kumari 897735dee9bSAlpana Kumari if (!outputLine) 898735dee9bSAlpana Kumari { 899e008432aSPriyanga Ramasamy std::cerr << "Couldn't find the line for output pin - " 900e008432aSPriyanga Ramasamy << pinName << std::endl; 901a2ddc96eSSunny Srivastava throw GpioException( 9026bd095f9SAlpana Kumari "Couldn't find output line for the GPIO. " 9036bd095f9SAlpana Kumari "Skipping this GPIO action."); 904735dee9bSAlpana Kumari } 905735dee9bSAlpana Kumari outputLine.request({"FRU pre-action", 906735dee9bSAlpana Kumari ::gpiod::line_request::DIRECTION_OUTPUT, 0}, 907735dee9bSAlpana Kumari pinValue); 908735dee9bSAlpana Kumari } 909e008432aSPriyanga Ramasamy catch (const std::exception& e) 910735dee9bSAlpana Kumari { 911e008432aSPriyanga Ramasamy std::string i2cBusAddr; 912e008432aSPriyanga Ramasamy std::string errMsg = e.what(); 9136bd095f9SAlpana Kumari errMsg += " GPIO : " + pinName; 9146bd095f9SAlpana Kumari 9156bd095f9SAlpana Kumari if ((json["frus"][file].at(0)["preAction"]) 9166bd095f9SAlpana Kumari .find("gpioI2CAddress") != 9176bd095f9SAlpana Kumari json["frus"][file].at(0)["preAction"].end()) 9186bd095f9SAlpana Kumari { 9196bd095f9SAlpana Kumari i2cBusAddr = 9206bd095f9SAlpana Kumari json["frus"][file].at(0)["preAction"]["gpioI2CAddress"]; 921fdf9ff2aSSunny Srivastava errMsg += " i2cBusAddress: " + i2cBusAddr; 9226bd095f9SAlpana Kumari } 9236bd095f9SAlpana Kumari 92440d1c196SAlpana Kumari // Take failure postAction 92540d1c196SAlpana Kumari executePostFailAction(json, file); 926a2ddc96eSSunny Srivastava throw GpioException(errMsg); 927735dee9bSAlpana Kumari } 928735dee9bSAlpana Kumari } 92940d1c196SAlpana Kumari else 93040d1c196SAlpana Kumari { 93140d1c196SAlpana Kumari // missing required informations 932e008432aSPriyanga Ramasamy std::cerr 93340d1c196SAlpana Kumari << "VPD inventory JSON missing basic informations of preAction " 93440d1c196SAlpana Kumari "for this FRU : [" 935e008432aSPriyanga Ramasamy << file << "]. Executing executePostFailAction." << std::endl; 93640d1c196SAlpana Kumari 93740d1c196SAlpana Kumari // Take failure postAction 93840d1c196SAlpana Kumari executePostFailAction(json, file); 93940d1c196SAlpana Kumari return false; 94040d1c196SAlpana Kumari } 941735dee9bSAlpana Kumari } 942735dee9bSAlpana Kumari return true; 943735dee9bSAlpana Kumari } 944735dee9bSAlpana Kumari 945aa8a893eSPriyanga Ramasamy void insertOrMerge(inventory::InterfaceMap& map, 946aa8a893eSPriyanga Ramasamy const inventory::Interface& interface, 947aa8a893eSPriyanga Ramasamy inventory::PropertyMap&& property) 948aa8a893eSPriyanga Ramasamy { 949aa8a893eSPriyanga Ramasamy if (map.find(interface) != map.end()) 950aa8a893eSPriyanga Ramasamy { 951aa8a893eSPriyanga Ramasamy auto& prop = map.at(interface); 952aa8a893eSPriyanga Ramasamy prop.insert(property.begin(), property.end()); 953aa8a893eSPriyanga Ramasamy } 954aa8a893eSPriyanga Ramasamy else 955aa8a893eSPriyanga Ramasamy { 956aa8a893eSPriyanga Ramasamy map.emplace(interface, property); 957aa8a893eSPriyanga Ramasamy } 958aa8a893eSPriyanga Ramasamy } 959f2d3b53dSSantosh Puranik 960f2d3b53dSSantosh Puranik BIOSAttrValueType readBIOSAttribute(const std::string& attrName) 961f2d3b53dSSantosh Puranik { 962f2d3b53dSSantosh Puranik std::tuple<std::string, BIOSAttrValueType, BIOSAttrValueType> attrVal; 963f2d3b53dSSantosh Puranik auto bus = sdbusplus::bus::new_default(); 964f2d3b53dSSantosh Puranik auto method = bus.new_method_call( 965f2d3b53dSSantosh Puranik "xyz.openbmc_project.BIOSConfigManager", 966f2d3b53dSSantosh Puranik "/xyz/openbmc_project/bios_config/manager", 967f2d3b53dSSantosh Puranik "xyz.openbmc_project.BIOSConfig.Manager", "GetAttribute"); 968f2d3b53dSSantosh Puranik method.append(attrName); 969f2d3b53dSSantosh Puranik try 970f2d3b53dSSantosh Puranik { 971f2d3b53dSSantosh Puranik auto result = bus.call(method); 972f2d3b53dSSantosh Puranik result.read(std::get<0>(attrVal), std::get<1>(attrVal), 973f2d3b53dSSantosh Puranik std::get<2>(attrVal)); 974f2d3b53dSSantosh Puranik } 975f2d3b53dSSantosh Puranik catch (const sdbusplus::exception::SdBusError& e) 976f2d3b53dSSantosh Puranik { 977f2d3b53dSSantosh Puranik std::cerr << "Failed to read BIOS Attribute: " << attrName << std::endl; 978f2d3b53dSSantosh Puranik std::cerr << e.what() << std::endl; 979f2d3b53dSSantosh Puranik } 980f2d3b53dSSantosh Puranik return std::get<1>(attrVal); 981f2d3b53dSSantosh Puranik } 982335873f6SPriyanga Ramasamy 983335873f6SPriyanga Ramasamy std::string getPowerState() 984335873f6SPriyanga Ramasamy { 985335873f6SPriyanga Ramasamy // TODO: How do we handle multiple chassis? 986e008432aSPriyanga Ramasamy std::string powerState{}; 987335873f6SPriyanga Ramasamy auto bus = sdbusplus::bus::new_default(); 988*c78d887cSPatrick Williams auto properties = bus.new_method_call("xyz.openbmc_project.State.Chassis", 989335873f6SPriyanga Ramasamy "/xyz/openbmc_project/state/chassis0", 990*c78d887cSPatrick Williams "org.freedesktop.DBus.Properties", 991*c78d887cSPatrick Williams "Get"); 992335873f6SPriyanga Ramasamy properties.append("xyz.openbmc_project.State.Chassis"); 993335873f6SPriyanga Ramasamy properties.append("CurrentPowerState"); 994335873f6SPriyanga Ramasamy auto result = bus.call(properties); 995335873f6SPriyanga Ramasamy if (!result.is_method_error()) 996335873f6SPriyanga Ramasamy { 997e008432aSPriyanga Ramasamy std::variant<std::string> val; 998335873f6SPriyanga Ramasamy result.read(val); 999e008432aSPriyanga Ramasamy if (auto pVal = std::get_if<std::string>(&val)) 1000335873f6SPriyanga Ramasamy { 1001335873f6SPriyanga Ramasamy powerState = *pVal; 1002335873f6SPriyanga Ramasamy } 1003335873f6SPriyanga Ramasamy } 1004e008432aSPriyanga Ramasamy std::cout << "Power state is: " << powerState << std::endl; 1005335873f6SPriyanga Ramasamy return powerState; 1006335873f6SPriyanga Ramasamy } 10076b2b5374SSantosh Puranik 10086b2b5374SSantosh Puranik Binary getVpdDataInVector(const nlohmann::json& js, const std::string& file) 10096b2b5374SSantosh Puranik { 10106b2b5374SSantosh Puranik uint32_t offset = 0; 10116b2b5374SSantosh Puranik // check if offset present? 10126b2b5374SSantosh Puranik for (const auto& item : js["frus"][file]) 10136b2b5374SSantosh Puranik { 10146b2b5374SSantosh Puranik if (item.find("offset") != item.end()) 10156b2b5374SSantosh Puranik { 10166b2b5374SSantosh Puranik offset = item["offset"]; 10176b2b5374SSantosh Puranik } 10186b2b5374SSantosh Puranik } 10196b2b5374SSantosh Puranik 10206b2b5374SSantosh Puranik // TODO: Figure out a better way to get max possible VPD size. 10216b2b5374SSantosh Puranik auto maxVPDSize = std::min(std::filesystem::file_size(file), 10226b2b5374SSantosh Puranik static_cast<uintmax_t>(65504)); 10236b2b5374SSantosh Puranik 10246b2b5374SSantosh Puranik Binary vpdVector; 10256b2b5374SSantosh Puranik vpdVector.resize(maxVPDSize); 1026e008432aSPriyanga Ramasamy std::ifstream vpdFile; 1027e008432aSPriyanga Ramasamy vpdFile.open(file, std::ios::binary); 10286b2b5374SSantosh Puranik 1029e008432aSPriyanga Ramasamy vpdFile.seekg(offset, std::ios_base::cur); 10306b2b5374SSantosh Puranik vpdFile.read(reinterpret_cast<char*>(&vpdVector[0]), maxVPDSize); 10316b2b5374SSantosh Puranik vpdVector.resize(vpdFile.gcount()); 10326b2b5374SSantosh Puranik 10336b2b5374SSantosh Puranik // Make sure we reset the EEPROM pointer to a "safe" location if it was DIMM 10346b2b5374SSantosh Puranik // SPD that we just read. 10356b2b5374SSantosh Puranik for (const auto& item : js["frus"][file]) 10366b2b5374SSantosh Puranik { 10376b2b5374SSantosh Puranik if (item.find("extraInterfaces") != item.end()) 10386b2b5374SSantosh Puranik { 10396b2b5374SSantosh Puranik if (item["extraInterfaces"].find( 10406b2b5374SSantosh Puranik "xyz.openbmc_project.Inventory.Item.Dimm") != 10416b2b5374SSantosh Puranik item["extraInterfaces"].end()) 10426b2b5374SSantosh Puranik { 10436b2b5374SSantosh Puranik // moves the EEPROM pointer to 2048 'th byte. 10446b2b5374SSantosh Puranik vpdFile.seekg(2047, std::ios::beg); 10456b2b5374SSantosh Puranik // Read that byte and discard - to affirm the move 10466b2b5374SSantosh Puranik // operation. 10476b2b5374SSantosh Puranik char ch; 10486b2b5374SSantosh Puranik vpdFile.read(&ch, sizeof(ch)); 10496b2b5374SSantosh Puranik break; 10506b2b5374SSantosh Puranik } 10516b2b5374SSantosh Puranik } 10526b2b5374SSantosh Puranik } 10536b2b5374SSantosh Puranik 10546b2b5374SSantosh Puranik return vpdVector; 10556b2b5374SSantosh Puranik } 10565629fbc0SPriyanga Ramasamy 10575629fbc0SPriyanga Ramasamy std::string getDbusNameForThisKw(const std::string& keyword) 10585629fbc0SPriyanga Ramasamy { 10595629fbc0SPriyanga Ramasamy if (keyword[0] == constants::POUND_KW) 10605629fbc0SPriyanga Ramasamy { 10615629fbc0SPriyanga Ramasamy return (std::string(constants::POUND_KW_PREFIX) + keyword[1]); 10625629fbc0SPriyanga Ramasamy } 10635629fbc0SPriyanga Ramasamy else if (isdigit(keyword[0])) 10645629fbc0SPriyanga Ramasamy { 10655629fbc0SPriyanga Ramasamy return (std::string(constants::NUMERIC_KW_PREFIX) + keyword); 10665629fbc0SPriyanga Ramasamy } 10675629fbc0SPriyanga Ramasamy return keyword; 10685629fbc0SPriyanga Ramasamy } 10695629fbc0SPriyanga Ramasamy 10706c71c9dcSSunny Srivastava } // namespace vpd 10716c71c9dcSSunny Srivastava } // namespace openpower 1072