1abb87edaSPriyangaRamasamy #include "config.h" 2abb87edaSPriyangaRamasamy 36c71c9dcSSunny Srivastava #include "common_utility.hpp" 4abb87edaSPriyangaRamasamy #include "defines.hpp" 56c71c9dcSSunny Srivastava #include "ibm_vpd_utils.hpp" 6e12b181bSSunnySrivastava1984 #include "ipz_parser.hpp" 7abb87edaSPriyangaRamasamy #include "keyword_vpd_parser.hpp" 8a00936f8SAlpana Kumari #include "memory_vpd_parser.hpp" 9e12b181bSSunnySrivastava1984 #include "parser_factory.hpp" 10a20be8ecSSunnySrivastava1984 #include "vpd_exceptions.hpp" 11abb87edaSPriyangaRamasamy 129094d4f6SSunnySrivastava1984 #include <assert.h> 138ea3f6d0SAlpana Kumari #include <ctype.h> 148ea3f6d0SAlpana Kumari 15abb87edaSPriyangaRamasamy #include <CLI/CLI.hpp> 1688edeb6fSSantosh Puranik #include <algorithm> 1765b83601SAlpana Kumari #include <cstdarg> 18abb87edaSPriyangaRamasamy #include <exception> 1983a1d5deSPriyangaRamasamy #include <filesystem> 20abb87edaSPriyangaRamasamy #include <fstream> 212f793048SAlpana Kumari #include <gpiod.hpp> 22abb87edaSPriyangaRamasamy #include <iostream> 23abb87edaSPriyangaRamasamy #include <iterator> 24abb87edaSPriyangaRamasamy #include <nlohmann/json.hpp> 25280197e3SAndrew Geissler #include <phosphor-logging/log.hpp> 26abb87edaSPriyangaRamasamy 27abb87edaSPriyangaRamasamy using namespace std; 28abb87edaSPriyangaRamasamy using namespace openpower::vpd; 29abb87edaSPriyangaRamasamy using namespace CLI; 30abb87edaSPriyangaRamasamy using namespace vpd::keyword::parser; 3183a1d5deSPriyangaRamasamy using namespace openpower::vpd::constants; 3283a1d5deSPriyangaRamasamy namespace fs = filesystem; 3383a1d5deSPriyangaRamasamy using json = nlohmann::json; 34e12b181bSSunnySrivastava1984 using namespace openpower::vpd::parser::factory; 35945a02d3SSunnySrivastava1984 using namespace openpower::vpd::inventory; 36a00936f8SAlpana Kumari using namespace openpower::vpd::memory::parser; 37e12b181bSSunnySrivastava1984 using namespace openpower::vpd::parser::interface; 38a20be8ecSSunnySrivastava1984 using namespace openpower::vpd::exceptions; 39280197e3SAndrew Geissler using namespace phosphor::logging; 40abb87edaSPriyangaRamasamy 4165b83601SAlpana Kumari static const deviceTreeMap deviceTreeSystemTypeMap = { 422fe709f1SAndrew Geissler {RAINIER_2U, "conf-aspeed-bmc-ibm-rainier.dtb"}, 43f05effdbSAlpana Kumari {RAINIER_2U_V2, "conf-aspeed-bmc-ibm-rainier-v2.dtb"}, 442fe709f1SAndrew Geissler {RAINIER_4U, "conf-aspeed-bmc-ibm-rainier-4u.dtb"}, 45f05effdbSAlpana Kumari {RAINIER_4U_V2, "conf-aspeed-bmc-ibm-rainier-4u-v2.dtb"}, 462fe709f1SAndrew Geissler {RAINIER_1S4U, "conf-aspeed-bmc-ibm-rainier-1s4u.dtb"}, 472fe709f1SAndrew Geissler {EVEREST, "conf-aspeed-bmc-ibm-everest.dtb"}}; 4865b83601SAlpana Kumari 4988edeb6fSSantosh Puranik /** 508589375fSSantosh Puranik * @brief Returns the power state for chassis0 518589375fSSantosh Puranik */ 528589375fSSantosh Puranik static auto getPowerState() 538589375fSSantosh Puranik { 548589375fSSantosh Puranik // TODO: How do we handle multiple chassis? 558589375fSSantosh Puranik string powerState{}; 568589375fSSantosh Puranik auto bus = sdbusplus::bus::new_default(); 578589375fSSantosh Puranik auto properties = 588589375fSSantosh Puranik bus.new_method_call("xyz.openbmc_project.State.Chassis", 598589375fSSantosh Puranik "/xyz/openbmc_project/state/chassis0", 608589375fSSantosh Puranik "org.freedesktop.DBus.Properties", "Get"); 618589375fSSantosh Puranik properties.append("xyz.openbmc_project.State.Chassis"); 628589375fSSantosh Puranik properties.append("CurrentPowerState"); 638589375fSSantosh Puranik auto result = bus.call(properties); 648589375fSSantosh Puranik if (!result.is_method_error()) 658589375fSSantosh Puranik { 668589375fSSantosh Puranik variant<string> val; 678589375fSSantosh Puranik result.read(val); 688589375fSSantosh Puranik if (auto pVal = get_if<string>(&val)) 698589375fSSantosh Puranik { 708589375fSSantosh Puranik powerState = *pVal; 718589375fSSantosh Puranik } 728589375fSSantosh Puranik } 738589375fSSantosh Puranik cout << "Power state is: " << powerState << endl; 748589375fSSantosh Puranik return powerState; 758589375fSSantosh Puranik } 768589375fSSantosh Puranik 778589375fSSantosh Puranik /** 7888edeb6fSSantosh Puranik * @brief Expands location codes 7988edeb6fSSantosh Puranik */ 8088edeb6fSSantosh Puranik static auto expandLocationCode(const string& unexpanded, const Parsed& vpdMap, 8188edeb6fSSantosh Puranik bool isSystemVpd) 8288edeb6fSSantosh Puranik { 8388edeb6fSSantosh Puranik auto expanded{unexpanded}; 8488edeb6fSSantosh Puranik static constexpr auto SYSTEM_OBJECT = "/system/chassis/motherboard"; 8588edeb6fSSantosh Puranik static constexpr auto VCEN_IF = "com.ibm.ipzvpd.VCEN"; 8688edeb6fSSantosh Puranik static constexpr auto VSYS_IF = "com.ibm.ipzvpd.VSYS"; 8788edeb6fSSantosh Puranik size_t idx = expanded.find("fcs"); 8888edeb6fSSantosh Puranik try 8988edeb6fSSantosh Puranik { 9088edeb6fSSantosh Puranik if (idx != string::npos) 9188edeb6fSSantosh Puranik { 9288edeb6fSSantosh Puranik string fc{}; 9388edeb6fSSantosh Puranik string se{}; 9488edeb6fSSantosh Puranik if (isSystemVpd) 9588edeb6fSSantosh Puranik { 9688edeb6fSSantosh Puranik const auto& fcData = vpdMap.at("VCEN").at("FC"); 9788edeb6fSSantosh Puranik const auto& seData = vpdMap.at("VCEN").at("SE"); 9888edeb6fSSantosh Puranik fc = string(fcData.data(), fcData.size()); 9988edeb6fSSantosh Puranik se = string(seData.data(), seData.size()); 10088edeb6fSSantosh Puranik } 10188edeb6fSSantosh Puranik else 10288edeb6fSSantosh Puranik { 10388edeb6fSSantosh Puranik fc = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "FC"); 10488edeb6fSSantosh Puranik se = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "SE"); 10588edeb6fSSantosh Puranik } 10688edeb6fSSantosh Puranik 10781671f6dSAlpana Kumari // TODO: See if ND0 can be placed in the JSON 10881671f6dSAlpana Kumari expanded.replace(idx, 3, fc.substr(0, 4) + ".ND0." + se); 10988edeb6fSSantosh Puranik } 11088edeb6fSSantosh Puranik else 11188edeb6fSSantosh Puranik { 11288edeb6fSSantosh Puranik idx = expanded.find("mts"); 11388edeb6fSSantosh Puranik if (idx != string::npos) 11488edeb6fSSantosh Puranik { 11588edeb6fSSantosh Puranik string mt{}; 11688edeb6fSSantosh Puranik string se{}; 11788edeb6fSSantosh Puranik if (isSystemVpd) 11888edeb6fSSantosh Puranik { 11988edeb6fSSantosh Puranik const auto& mtData = vpdMap.at("VSYS").at("TM"); 12088edeb6fSSantosh Puranik const auto& seData = vpdMap.at("VSYS").at("SE"); 12188edeb6fSSantosh Puranik mt = string(mtData.data(), mtData.size()); 12288edeb6fSSantosh Puranik se = string(seData.data(), seData.size()); 12388edeb6fSSantosh Puranik } 12488edeb6fSSantosh Puranik else 12588edeb6fSSantosh Puranik { 12688edeb6fSSantosh Puranik mt = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "TM"); 12788edeb6fSSantosh Puranik se = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "SE"); 12888edeb6fSSantosh Puranik } 12988edeb6fSSantosh Puranik 13088edeb6fSSantosh Puranik replace(mt.begin(), mt.end(), '-', '.'); 13188edeb6fSSantosh Puranik expanded.replace(idx, 3, mt + "." + se); 13288edeb6fSSantosh Puranik } 13388edeb6fSSantosh Puranik } 13488edeb6fSSantosh Puranik } 13558e22145SAlpana Kumari catch (exception& e) 13688edeb6fSSantosh Puranik { 13758e22145SAlpana Kumari cerr << "Failed to expand location code with exception: " << e.what() 13858e22145SAlpana Kumari << "\n"; 13988edeb6fSSantosh Puranik } 14088edeb6fSSantosh Puranik return expanded; 14188edeb6fSSantosh Puranik } 1422f793048SAlpana Kumari 143abb87edaSPriyangaRamasamy /** 144abb87edaSPriyangaRamasamy * @brief Populate FRU specific interfaces. 145abb87edaSPriyangaRamasamy * 146abb87edaSPriyangaRamasamy * This is a common method which handles both 147abb87edaSPriyangaRamasamy * ipz and keyword specific interfaces thus, 148abb87edaSPriyangaRamasamy * reducing the code redundancy. 149abb87edaSPriyangaRamasamy * @param[in] map - Reference to the innermost keyword-value map. 150abb87edaSPriyangaRamasamy * @param[in] preIntrStr - Reference to the interface string. 151abb87edaSPriyangaRamasamy * @param[out] interfaces - Reference to interface map. 152abb87edaSPriyangaRamasamy */ 153abb87edaSPriyangaRamasamy template <typename T> 154abb87edaSPriyangaRamasamy static void populateFruSpecificInterfaces(const T& map, 155abb87edaSPriyangaRamasamy const string& preIntrStr, 156abb87edaSPriyangaRamasamy inventory::InterfaceMap& interfaces) 157abb87edaSPriyangaRamasamy { 158abb87edaSPriyangaRamasamy inventory::PropertyMap prop; 159abb87edaSPriyangaRamasamy 160abb87edaSPriyangaRamasamy for (const auto& kwVal : map) 161abb87edaSPriyangaRamasamy { 16258e22145SAlpana Kumari vector<uint8_t> vec(kwVal.second.begin(), kwVal.second.end()); 163abb87edaSPriyangaRamasamy 164abb87edaSPriyangaRamasamy auto kw = kwVal.first; 165abb87edaSPriyangaRamasamy 166abb87edaSPriyangaRamasamy if (kw[0] == '#') 167abb87edaSPriyangaRamasamy { 16858e22145SAlpana Kumari kw = string("PD_") + kw[1]; 169abb87edaSPriyangaRamasamy } 1708ea3f6d0SAlpana Kumari else if (isdigit(kw[0])) 1718ea3f6d0SAlpana Kumari { 17258e22145SAlpana Kumari kw = string("N_") + kw; 1738ea3f6d0SAlpana Kumari } 174abb87edaSPriyangaRamasamy prop.emplace(move(kw), move(vec)); 175abb87edaSPriyangaRamasamy } 176abb87edaSPriyangaRamasamy 177abb87edaSPriyangaRamasamy interfaces.emplace(preIntrStr, move(prop)); 178abb87edaSPriyangaRamasamy } 179abb87edaSPriyangaRamasamy 180abb87edaSPriyangaRamasamy /** 181abb87edaSPriyangaRamasamy * @brief Populate Interfaces. 182abb87edaSPriyangaRamasamy * 183abb87edaSPriyangaRamasamy * This method populates common and extra interfaces to dbus. 184abb87edaSPriyangaRamasamy * @param[in] js - json object 185abb87edaSPriyangaRamasamy * @param[out] interfaces - Reference to interface map 186abb87edaSPriyangaRamasamy * @param[in] vpdMap - Reference to the parsed vpd map. 18788edeb6fSSantosh Puranik * @param[in] isSystemVpd - Denotes whether we are collecting the system VPD. 188abb87edaSPriyangaRamasamy */ 189abb87edaSPriyangaRamasamy template <typename T> 190abb87edaSPriyangaRamasamy static void populateInterfaces(const nlohmann::json& js, 191abb87edaSPriyangaRamasamy inventory::InterfaceMap& interfaces, 19288edeb6fSSantosh Puranik const T& vpdMap, bool isSystemVpd) 193abb87edaSPriyangaRamasamy { 194abb87edaSPriyangaRamasamy for (const auto& ifs : js.items()) 195abb87edaSPriyangaRamasamy { 19688edeb6fSSantosh Puranik string inf = ifs.key(); 197abb87edaSPriyangaRamasamy inventory::PropertyMap props; 198abb87edaSPriyangaRamasamy 199abb87edaSPriyangaRamasamy for (const auto& itr : ifs.value().items()) 200abb87edaSPriyangaRamasamy { 20188edeb6fSSantosh Puranik const string& busProp = itr.key(); 20288edeb6fSSantosh Puranik 20331970dedSAlpana Kumari if (itr.value().is_boolean()) 20431970dedSAlpana Kumari { 20588edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<bool>()); 20688edeb6fSSantosh Puranik } 20788edeb6fSSantosh Puranik else if (itr.value().is_string()) 20888edeb6fSSantosh Puranik { 20958e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 21088edeb6fSSantosh Puranik { 21188edeb6fSSantosh Puranik if (busProp == "LocationCode" && 212414d5aefSAlpana Kumari inf == IBM_LOCATION_CODE_INF) 21388edeb6fSSantosh Puranik { 214414d5aefSAlpana Kumari // TODO deprecate the com.ibm interface later 21588edeb6fSSantosh Puranik auto prop = expandLocationCode( 21688edeb6fSSantosh Puranik itr.value().get<string>(), vpdMap, isSystemVpd); 21788edeb6fSSantosh Puranik props.emplace(busProp, prop); 218414d5aefSAlpana Kumari interfaces.emplace(XYZ_LOCATION_CODE_INF, props); 21988edeb6fSSantosh Puranik } 22088edeb6fSSantosh Puranik else 22188edeb6fSSantosh Puranik { 22288edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<string>()); 22388edeb6fSSantosh Puranik } 22488edeb6fSSantosh Puranik } 22588edeb6fSSantosh Puranik else 22688edeb6fSSantosh Puranik { 22788edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<string>()); 22888edeb6fSSantosh Puranik } 22931970dedSAlpana Kumari } 23031970dedSAlpana Kumari else if (itr.value().is_object()) 23131970dedSAlpana Kumari { 232abb87edaSPriyangaRamasamy const string& rec = itr.value().value("recordName", ""); 233abb87edaSPriyangaRamasamy const string& kw = itr.value().value("keywordName", ""); 234abb87edaSPriyangaRamasamy const string& encoding = itr.value().value("encoding", ""); 235abb87edaSPriyangaRamasamy 23658e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 237abb87edaSPriyangaRamasamy { 23888edeb6fSSantosh Puranik if (!rec.empty() && !kw.empty() && vpdMap.count(rec) && 23988edeb6fSSantosh Puranik vpdMap.at(rec).count(kw)) 240abb87edaSPriyangaRamasamy { 241abb87edaSPriyangaRamasamy auto encoded = 242abb87edaSPriyangaRamasamy encodeKeyword(vpdMap.at(rec).at(kw), encoding); 24388edeb6fSSantosh Puranik props.emplace(busProp, encoded); 244abb87edaSPriyangaRamasamy } 245abb87edaSPriyangaRamasamy } 24658e22145SAlpana Kumari else if constexpr (is_same<T, KeywordVpdMap>::value) 247abb87edaSPriyangaRamasamy { 248abb87edaSPriyangaRamasamy if (!kw.empty() && vpdMap.count(kw)) 249abb87edaSPriyangaRamasamy { 250abb87edaSPriyangaRamasamy auto prop = 251abb87edaSPriyangaRamasamy string(vpdMap.at(kw).begin(), vpdMap.at(kw).end()); 252abb87edaSPriyangaRamasamy auto encoded = encodeKeyword(prop, encoding); 25388edeb6fSSantosh Puranik props.emplace(busProp, encoded); 254abb87edaSPriyangaRamasamy } 255abb87edaSPriyangaRamasamy } 256abb87edaSPriyangaRamasamy } 25731970dedSAlpana Kumari } 258abb87edaSPriyangaRamasamy interfaces.emplace(inf, move(props)); 259abb87edaSPriyangaRamasamy } 260abb87edaSPriyangaRamasamy } 261abb87edaSPriyangaRamasamy 2622f793048SAlpana Kumari static Binary getVpdDataInVector(const nlohmann::json& js, const string& file) 26358e22145SAlpana Kumari { 26458e22145SAlpana Kumari uint32_t offset = 0; 26558e22145SAlpana Kumari // check if offset present? 26658e22145SAlpana Kumari for (const auto& item : js["frus"][file]) 26758e22145SAlpana Kumari { 26858e22145SAlpana Kumari if (item.find("offset") != item.end()) 26958e22145SAlpana Kumari { 27058e22145SAlpana Kumari offset = item["offset"]; 27158e22145SAlpana Kumari } 27258e22145SAlpana Kumari } 27358e22145SAlpana Kumari 27458e22145SAlpana Kumari // TODO: Figure out a better way to get max possible VPD size. 27558e22145SAlpana Kumari Binary vpdVector; 27658e22145SAlpana Kumari vpdVector.resize(65504); 27758e22145SAlpana Kumari ifstream vpdFile; 27858e22145SAlpana Kumari vpdFile.open(file, ios::binary); 27958e22145SAlpana Kumari 28058e22145SAlpana Kumari vpdFile.seekg(offset, ios_base::cur); 28158e22145SAlpana Kumari vpdFile.read(reinterpret_cast<char*>(&vpdVector[0]), 65504); 28258e22145SAlpana Kumari vpdVector.resize(vpdFile.gcount()); 28358e22145SAlpana Kumari 28458e22145SAlpana Kumari return vpdVector; 28558e22145SAlpana Kumari } 28658e22145SAlpana Kumari 2872f793048SAlpana Kumari /** This API will be called at the end of VPD collection to perform any post 2882f793048SAlpana Kumari * actions. 2892f793048SAlpana Kumari * 2902f793048SAlpana Kumari * @param[in] json - json object 2912f793048SAlpana Kumari * @param[in] file - eeprom file path 2922f793048SAlpana Kumari */ 2932f793048SAlpana Kumari static void postFailAction(const nlohmann::json& json, const string& file) 2942f793048SAlpana Kumari { 2952f793048SAlpana Kumari if ((json["frus"][file].at(0)).find("postActionFail") == 2962f793048SAlpana Kumari json["frus"][file].at(0).end()) 2972f793048SAlpana Kumari { 2982f793048SAlpana Kumari return; 2992f793048SAlpana Kumari } 3002f793048SAlpana Kumari 3012f793048SAlpana Kumari uint8_t pinValue = 0; 3022f793048SAlpana Kumari string pinName; 3032f793048SAlpana Kumari 3042f793048SAlpana Kumari for (const auto& postAction : 3052f793048SAlpana Kumari (json["frus"][file].at(0))["postActionFail"].items()) 3062f793048SAlpana Kumari { 3072f793048SAlpana Kumari if (postAction.key() == "pin") 3082f793048SAlpana Kumari { 3092f793048SAlpana Kumari pinName = postAction.value(); 3102f793048SAlpana Kumari } 3112f793048SAlpana Kumari else if (postAction.key() == "value") 3122f793048SAlpana Kumari { 3132f793048SAlpana Kumari // Get the value to set 3142f793048SAlpana Kumari pinValue = postAction.value(); 3152f793048SAlpana Kumari } 3162f793048SAlpana Kumari } 3172f793048SAlpana Kumari 3182f793048SAlpana Kumari cout << "Setting GPIO: " << pinName << " to " << (int)pinValue << endl; 3192f793048SAlpana Kumari 3202f793048SAlpana Kumari try 3212f793048SAlpana Kumari { 3222f793048SAlpana Kumari gpiod::line outputLine = gpiod::find_line(pinName); 3232f793048SAlpana Kumari 3242f793048SAlpana Kumari if (!outputLine) 3252f793048SAlpana Kumari { 3262f793048SAlpana Kumari cout << "Couldn't find output line:" << pinName 3272f793048SAlpana Kumari << " on GPIO. Skipping...\n"; 3282f793048SAlpana Kumari 3292f793048SAlpana Kumari return; 3302f793048SAlpana Kumari } 3312f793048SAlpana Kumari outputLine.request( 3322f793048SAlpana Kumari {"Disable line", ::gpiod::line_request::DIRECTION_OUTPUT, 0}, 3332f793048SAlpana Kumari pinValue); 3342f793048SAlpana Kumari } 3352f793048SAlpana Kumari catch (system_error&) 3362f793048SAlpana Kumari { 3372f793048SAlpana Kumari cerr << "Failed to set post-action GPIO" << endl; 3382f793048SAlpana Kumari } 3392f793048SAlpana Kumari } 3402f793048SAlpana Kumari 3412f793048SAlpana Kumari /** Performs any pre-action needed to get the FRU setup for collection. 3422f793048SAlpana Kumari * 3432f793048SAlpana Kumari * @param[in] json - json object 3442f793048SAlpana Kumari * @param[in] file - eeprom file path 3452f793048SAlpana Kumari */ 3462f793048SAlpana Kumari static void preAction(const nlohmann::json& json, const string& file) 3472f793048SAlpana Kumari { 3482f793048SAlpana Kumari if ((json["frus"][file].at(0)).find("preAction") == 3492f793048SAlpana Kumari json["frus"][file].at(0).end()) 3502f793048SAlpana Kumari { 3512f793048SAlpana Kumari return; 3522f793048SAlpana Kumari } 3532f793048SAlpana Kumari 3542f793048SAlpana Kumari uint8_t pinValue = 0; 3552f793048SAlpana Kumari string pinName; 3562f793048SAlpana Kumari 3572f793048SAlpana Kumari for (const auto& postAction : 3582f793048SAlpana Kumari (json["frus"][file].at(0))["preAction"].items()) 3592f793048SAlpana Kumari { 3602f793048SAlpana Kumari if (postAction.key() == "pin") 3612f793048SAlpana Kumari { 3622f793048SAlpana Kumari pinName = postAction.value(); 3632f793048SAlpana Kumari } 3642f793048SAlpana Kumari else if (postAction.key() == "value") 3652f793048SAlpana Kumari { 3662f793048SAlpana Kumari // Get the value to set 3672f793048SAlpana Kumari pinValue = postAction.value(); 3682f793048SAlpana Kumari } 3692f793048SAlpana Kumari } 3702f793048SAlpana Kumari 3712f793048SAlpana Kumari cout << "Setting GPIO: " << pinName << " to " << (int)pinValue << endl; 3722f793048SAlpana Kumari try 3732f793048SAlpana Kumari { 3742f793048SAlpana Kumari gpiod::line outputLine = gpiod::find_line(pinName); 3752f793048SAlpana Kumari 3762f793048SAlpana Kumari if (!outputLine) 3772f793048SAlpana Kumari { 3782f793048SAlpana Kumari cout << "Couldn't find output line:" << pinName 3792f793048SAlpana Kumari << " on GPIO. Skipping...\n"; 3802f793048SAlpana Kumari 3812f793048SAlpana Kumari return; 3822f793048SAlpana Kumari } 3832f793048SAlpana Kumari outputLine.request( 3842f793048SAlpana Kumari {"FRU pre-action", ::gpiod::line_request::DIRECTION_OUTPUT, 0}, 3852f793048SAlpana Kumari pinValue); 3862f793048SAlpana Kumari } 3872f793048SAlpana Kumari catch (system_error&) 3882f793048SAlpana Kumari { 3892f793048SAlpana Kumari cerr << "Failed to set pre-action GPIO" << endl; 3902f793048SAlpana Kumari return; 3912f793048SAlpana Kumari } 3922f793048SAlpana Kumari 3932f793048SAlpana Kumari // Now bind the device 3942f793048SAlpana Kumari string bind = json["frus"][file].at(0).value("bind", ""); 3952f793048SAlpana Kumari cout << "Binding device " << bind << endl; 3962f793048SAlpana Kumari string bindCmd = string("echo \"") + bind + 3972f793048SAlpana Kumari string("\" > /sys/bus/i2c/drivers/at24/bind"); 3982f793048SAlpana Kumari cout << bindCmd << endl; 3992f793048SAlpana Kumari executeCmd(bindCmd); 4002f793048SAlpana Kumari 4012f793048SAlpana Kumari // Check if device showed up (test for file) 4022f793048SAlpana Kumari if (!fs::exists(file)) 4032f793048SAlpana Kumari { 4042f793048SAlpana Kumari cout << "EEPROM " << file << " does not exist. Take failure action" 4052f793048SAlpana Kumari << endl; 4062f793048SAlpana Kumari // If not, then take failure postAction 4072f793048SAlpana Kumari postFailAction(json, file); 4082f793048SAlpana Kumari } 4092f793048SAlpana Kumari } 4102f793048SAlpana Kumari 411abb87edaSPriyangaRamasamy /** 4128e140a1cSPriyangaRamasamy * @brief Prime the Inventory 4138e140a1cSPriyangaRamasamy * Prime the inventory by populating only the location code, 4148e140a1cSPriyangaRamasamy * type interface and the inventory object for the frus 4158e140a1cSPriyangaRamasamy * which are not system vpd fru. 416abb87edaSPriyangaRamasamy * 4178e140a1cSPriyangaRamasamy * @param[in] jsObject - Reference to vpd inventory json object 4188e140a1cSPriyangaRamasamy * @param[in] vpdMap - Reference to the parsed vpd map 4198e140a1cSPriyangaRamasamy * 4208e140a1cSPriyangaRamasamy * @returns Map of items in extraInterface. 4218e140a1cSPriyangaRamasamy */ 4228e140a1cSPriyangaRamasamy template <typename T> 4238e140a1cSPriyangaRamasamy inventory::ObjectMap primeInventory(const nlohmann::json& jsObject, 4248e140a1cSPriyangaRamasamy const T& vpdMap) 4258e140a1cSPriyangaRamasamy { 4268e140a1cSPriyangaRamasamy inventory::ObjectMap objects; 4278e140a1cSPriyangaRamasamy 4288e140a1cSPriyangaRamasamy for (auto& itemFRUS : jsObject["frus"].items()) 4298e140a1cSPriyangaRamasamy { 4302f793048SAlpana Kumari // Take pre actions 4312f793048SAlpana Kumari preAction(jsObject, itemFRUS.key()); 4328e140a1cSPriyangaRamasamy for (auto& itemEEPROM : itemFRUS.value()) 4338e140a1cSPriyangaRamasamy { 4348e140a1cSPriyangaRamasamy inventory::InterfaceMap interfaces; 4358e140a1cSPriyangaRamasamy auto isSystemVpd = itemEEPROM.value("isSystemVpd", false); 4368e140a1cSPriyangaRamasamy inventory::Object object(itemEEPROM.at("inventoryPath")); 4378e140a1cSPriyangaRamasamy 4388e140a1cSPriyangaRamasamy if (!isSystemVpd && !itemEEPROM.value("noprime", false)) 4398e140a1cSPriyangaRamasamy { 440cfd7a75aSAlpana Kumari inventory::PropertyMap presProp; 441cfd7a75aSAlpana Kumari presProp.emplace("Present", false); 442cfd7a75aSAlpana Kumari interfaces.emplace("xyz.openbmc_project.Inventory.Item", 443cfd7a75aSAlpana Kumari move(presProp)); 444cfd7a75aSAlpana Kumari 4458e140a1cSPriyangaRamasamy if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end()) 4468e140a1cSPriyangaRamasamy { 4478e140a1cSPriyangaRamasamy for (const auto& eI : itemEEPROM["extraInterfaces"].items()) 4488e140a1cSPriyangaRamasamy { 4498e140a1cSPriyangaRamasamy inventory::PropertyMap props; 450414d5aefSAlpana Kumari if (eI.key() == IBM_LOCATION_CODE_INF) 4518e140a1cSPriyangaRamasamy { 4528e140a1cSPriyangaRamasamy if constexpr (std::is_same<T, Parsed>::value) 4538e140a1cSPriyangaRamasamy { 4548e140a1cSPriyangaRamasamy for (auto& lC : eI.value().items()) 4558e140a1cSPriyangaRamasamy { 4568e140a1cSPriyangaRamasamy auto propVal = expandLocationCode( 4578e140a1cSPriyangaRamasamy lC.value().get<string>(), vpdMap, true); 4588e140a1cSPriyangaRamasamy 4598e140a1cSPriyangaRamasamy props.emplace(move(lC.key()), 4608e140a1cSPriyangaRamasamy move(propVal)); 4618e140a1cSPriyangaRamasamy interfaces.emplace(move(eI.key()), 4628e140a1cSPriyangaRamasamy move(props)); 4638e140a1cSPriyangaRamasamy } 4648e140a1cSPriyangaRamasamy } 4658e140a1cSPriyangaRamasamy } 4668e140a1cSPriyangaRamasamy else if (eI.key().find("Inventory.Item.") != 4678e140a1cSPriyangaRamasamy string::npos) 4688e140a1cSPriyangaRamasamy { 4698e140a1cSPriyangaRamasamy interfaces.emplace(move(eI.key()), move(props)); 4708e140a1cSPriyangaRamasamy } 4718e140a1cSPriyangaRamasamy } 4728e140a1cSPriyangaRamasamy } 4738e140a1cSPriyangaRamasamy objects.emplace(move(object), move(interfaces)); 4748e140a1cSPriyangaRamasamy } 4758e140a1cSPriyangaRamasamy } 4768e140a1cSPriyangaRamasamy } 4778e140a1cSPriyangaRamasamy return objects; 4788e140a1cSPriyangaRamasamy } 4798e140a1cSPriyangaRamasamy 48065b83601SAlpana Kumari /** 48165b83601SAlpana Kumari * @brief This API executes command to set environment variable 48265b83601SAlpana Kumari * And then reboot the system 48365b83601SAlpana Kumari * @param[in] key -env key to set new value 48465b83601SAlpana Kumari * @param[in] value -value to set. 48565b83601SAlpana Kumari */ 48665b83601SAlpana Kumari void setEnvAndReboot(const string& key, const string& value) 48765b83601SAlpana Kumari { 48865b83601SAlpana Kumari // set env and reboot and break. 48965b83601SAlpana Kumari executeCmd("/sbin/fw_setenv", key, value); 490280197e3SAndrew Geissler log<level::INFO>("Rebooting BMC to pick up new device tree"); 49165b83601SAlpana Kumari // make dbus call to reboot 49265b83601SAlpana Kumari auto bus = sdbusplus::bus::new_default_system(); 49365b83601SAlpana Kumari auto method = bus.new_method_call( 49465b83601SAlpana Kumari "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 49565b83601SAlpana Kumari "org.freedesktop.systemd1.Manager", "Reboot"); 49665b83601SAlpana Kumari bus.call_noreply(method); 49765b83601SAlpana Kumari } 49865b83601SAlpana Kumari 49965b83601SAlpana Kumari /* 50065b83601SAlpana Kumari * @brief This API checks for env var fitconfig. 50165b83601SAlpana Kumari * If not initialised OR updated as per the current system type, 50265b83601SAlpana Kumari * update this env var and reboot the system. 50365b83601SAlpana Kumari * 50465b83601SAlpana Kumari * @param[in] systemType IM kwd in vpd tells about which system type it is. 50565b83601SAlpana Kumari * */ 50665b83601SAlpana Kumari void setDevTreeEnv(const string& systemType) 50765b83601SAlpana Kumari { 50865b83601SAlpana Kumari string newDeviceTree; 50965b83601SAlpana Kumari 51065b83601SAlpana Kumari if (deviceTreeSystemTypeMap.find(systemType) != 51165b83601SAlpana Kumari deviceTreeSystemTypeMap.end()) 51265b83601SAlpana Kumari { 51365b83601SAlpana Kumari newDeviceTree = deviceTreeSystemTypeMap.at(systemType); 51465b83601SAlpana Kumari } 51565b83601SAlpana Kumari 51665b83601SAlpana Kumari string readVarValue; 51765b83601SAlpana Kumari bool envVarFound = false; 51865b83601SAlpana Kumari 51965b83601SAlpana Kumari vector<string> output = executeCmd("/sbin/fw_printenv"); 52065b83601SAlpana Kumari for (const auto& entry : output) 52165b83601SAlpana Kumari { 52265b83601SAlpana Kumari size_t pos = entry.find("="); 52365b83601SAlpana Kumari string key = entry.substr(0, pos); 52465b83601SAlpana Kumari if (key != "fitconfig") 52565b83601SAlpana Kumari { 52665b83601SAlpana Kumari continue; 52765b83601SAlpana Kumari } 52865b83601SAlpana Kumari 52965b83601SAlpana Kumari envVarFound = true; 53065b83601SAlpana Kumari if (pos + 1 < entry.size()) 53165b83601SAlpana Kumari { 53265b83601SAlpana Kumari readVarValue = entry.substr(pos + 1); 53365b83601SAlpana Kumari if (readVarValue.find(newDeviceTree) != string::npos) 53465b83601SAlpana Kumari { 53565b83601SAlpana Kumari // fitconfig is Updated. No action needed 53665b83601SAlpana Kumari break; 53765b83601SAlpana Kumari } 53865b83601SAlpana Kumari } 53965b83601SAlpana Kumari // set env and reboot and break. 54065b83601SAlpana Kumari setEnvAndReboot(key, newDeviceTree); 54165b83601SAlpana Kumari exit(0); 54265b83601SAlpana Kumari } 54365b83601SAlpana Kumari 54465b83601SAlpana Kumari // check If env var Not found 54565b83601SAlpana Kumari if (!envVarFound) 54665b83601SAlpana Kumari { 54765b83601SAlpana Kumari setEnvAndReboot("fitconfig", newDeviceTree); 54865b83601SAlpana Kumari } 54965b83601SAlpana Kumari } 55065b83601SAlpana Kumari 5518e140a1cSPriyangaRamasamy /** 5529094d4f6SSunnySrivastava1984 * @brief API to call VPD manager to write VPD to EEPROM. 5539094d4f6SSunnySrivastava1984 * @param[in] Object path. 5549094d4f6SSunnySrivastava1984 * @param[in] record to be updated. 5559094d4f6SSunnySrivastava1984 * @param[in] keyword to be updated. 5569094d4f6SSunnySrivastava1984 * @param[in] keyword data to be updated 5579094d4f6SSunnySrivastava1984 */ 5589094d4f6SSunnySrivastava1984 void updateHardware(const string& objectName, const string& recName, 5599094d4f6SSunnySrivastava1984 const string& kwdName, const Binary& data) 5609094d4f6SSunnySrivastava1984 { 5619094d4f6SSunnySrivastava1984 try 5629094d4f6SSunnySrivastava1984 { 5639094d4f6SSunnySrivastava1984 auto bus = sdbusplus::bus::new_default(); 5649094d4f6SSunnySrivastava1984 auto properties = 5659094d4f6SSunnySrivastava1984 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword"); 5669094d4f6SSunnySrivastava1984 properties.append( 5679094d4f6SSunnySrivastava1984 static_cast<sdbusplus::message::object_path>(objectName)); 5689094d4f6SSunnySrivastava1984 properties.append(recName); 5699094d4f6SSunnySrivastava1984 properties.append(kwdName); 5709094d4f6SSunnySrivastava1984 properties.append(data); 5719094d4f6SSunnySrivastava1984 bus.call(properties); 5729094d4f6SSunnySrivastava1984 } 5739094d4f6SSunnySrivastava1984 catch (const sdbusplus::exception::SdBusError& e) 5749094d4f6SSunnySrivastava1984 { 5759094d4f6SSunnySrivastava1984 std::string what = 5769094d4f6SSunnySrivastava1984 "VPDManager WriteKeyword api failed for inventory path " + 5779094d4f6SSunnySrivastava1984 objectName; 5789094d4f6SSunnySrivastava1984 what += " record " + recName; 5799094d4f6SSunnySrivastava1984 what += " keyword " + kwdName; 5809094d4f6SSunnySrivastava1984 what += " with bus error = " + std::string(e.what()); 5819094d4f6SSunnySrivastava1984 5829094d4f6SSunnySrivastava1984 // map to hold additional data in case of logging pel 5839094d4f6SSunnySrivastava1984 PelAdditionalData additionalData{}; 5849094d4f6SSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", objectName); 5859094d4f6SSunnySrivastava1984 additionalData.emplace("DESCRIPTION", what); 5860746eeebSSunny Srivastava createPEL(additionalData, PelSeverity::WARNING, errIntfForBusFailure); 5879094d4f6SSunnySrivastava1984 } 5889094d4f6SSunnySrivastava1984 } 5899094d4f6SSunnySrivastava1984 5909094d4f6SSunnySrivastava1984 /** 5919094d4f6SSunnySrivastava1984 * @brief API to check if we need to restore system VPD 5929094d4f6SSunnySrivastava1984 * This functionality is only applicable for IPZ VPD data. 5939094d4f6SSunnySrivastava1984 * @param[in] vpdMap - IPZ vpd map 5949094d4f6SSunnySrivastava1984 * @param[in] objectPath - Object path for the FRU 5959094d4f6SSunnySrivastava1984 * @return EEPROMs with records and keywords updated at standby 5969094d4f6SSunnySrivastava1984 */ 5979094d4f6SSunnySrivastava1984 std::vector<RestoredEeproms> restoreSystemVPD(Parsed& vpdMap, 5989094d4f6SSunnySrivastava1984 const string& objectPath) 5999094d4f6SSunnySrivastava1984 { 6009094d4f6SSunnySrivastava1984 // the list of keywords for VSYS record is as per the S0 system. Should be 6019094d4f6SSunnySrivastava1984 // updated for another type of systems 6029094d4f6SSunnySrivastava1984 static std::unordered_map<std::string, std::vector<std::string>> svpdKwdMap{ 6039094d4f6SSunnySrivastava1984 {"VSYS", {"BR", "TM", "SE", "SU", "RB"}}, 6049094d4f6SSunnySrivastava1984 {"VCEN", {"FC", "SE"}}, 6059094d4f6SSunnySrivastava1984 {"LXR0", {"LX"}}}; 6069094d4f6SSunnySrivastava1984 6079094d4f6SSunnySrivastava1984 // vector to hold all the EEPROMs updated at standby 6089094d4f6SSunnySrivastava1984 std::vector<RestoredEeproms> updatedEeproms = {}; 6099094d4f6SSunnySrivastava1984 6109094d4f6SSunnySrivastava1984 for (const auto& systemRecKwdPair : svpdKwdMap) 6119094d4f6SSunnySrivastava1984 { 6129094d4f6SSunnySrivastava1984 auto it = vpdMap.find(systemRecKwdPair.first); 6139094d4f6SSunnySrivastava1984 6149094d4f6SSunnySrivastava1984 // check if record is found in map we got by parser 6159094d4f6SSunnySrivastava1984 if (it != vpdMap.end()) 6169094d4f6SSunnySrivastava1984 { 6179094d4f6SSunnySrivastava1984 const auto& kwdListForRecord = systemRecKwdPair.second; 6189094d4f6SSunnySrivastava1984 for (const auto& keyword : kwdListForRecord) 6199094d4f6SSunnySrivastava1984 { 6209094d4f6SSunnySrivastava1984 DbusPropertyMap& kwdValMap = it->second; 6219094d4f6SSunnySrivastava1984 auto iterator = kwdValMap.find(keyword); 6229094d4f6SSunnySrivastava1984 6239094d4f6SSunnySrivastava1984 if (iterator != kwdValMap.end()) 6249094d4f6SSunnySrivastava1984 { 6259094d4f6SSunnySrivastava1984 string& kwdValue = iterator->second; 6269094d4f6SSunnySrivastava1984 6279094d4f6SSunnySrivastava1984 // check bus data 6289094d4f6SSunnySrivastava1984 const string& recordName = systemRecKwdPair.first; 6299094d4f6SSunnySrivastava1984 const string& busValue = readBusProperty( 6309094d4f6SSunnySrivastava1984 objectPath, ipzVpdInf + recordName, keyword); 6319094d4f6SSunnySrivastava1984 6329094d4f6SSunnySrivastava1984 if (busValue.find_first_not_of(' ') != string::npos) 6339094d4f6SSunnySrivastava1984 { 6349094d4f6SSunnySrivastava1984 if (kwdValue.find_first_not_of(' ') != string::npos) 6359094d4f6SSunnySrivastava1984 { 6369094d4f6SSunnySrivastava1984 // both the data are present, check for mismatch 6379094d4f6SSunnySrivastava1984 if (busValue != kwdValue) 6389094d4f6SSunnySrivastava1984 { 6399094d4f6SSunnySrivastava1984 string errMsg = "VPD data mismatch on cache " 6409094d4f6SSunnySrivastava1984 "and hardware for record: "; 6419094d4f6SSunnySrivastava1984 errMsg += (*it).first; 6429094d4f6SSunnySrivastava1984 errMsg += " and keyword: "; 6439094d4f6SSunnySrivastava1984 errMsg += keyword; 6449094d4f6SSunnySrivastava1984 6459094d4f6SSunnySrivastava1984 // data mismatch 6469094d4f6SSunnySrivastava1984 PelAdditionalData additionalData; 6479094d4f6SSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 6489094d4f6SSunnySrivastava1984 objectPath); 6499094d4f6SSunnySrivastava1984 6509094d4f6SSunnySrivastava1984 additionalData.emplace("DESCRIPTION", errMsg); 6519094d4f6SSunnySrivastava1984 6520746eeebSSunny Srivastava createPEL(additionalData, PelSeverity::WARNING, 6530746eeebSSunny Srivastava errIntfForInvalidVPD); 6549094d4f6SSunnySrivastava1984 } 6559094d4f6SSunnySrivastava1984 } 6569094d4f6SSunnySrivastava1984 else 6579094d4f6SSunnySrivastava1984 { 6589094d4f6SSunnySrivastava1984 // implies hardware data is blank 6599094d4f6SSunnySrivastava1984 // update the map 6609094d4f6SSunnySrivastava1984 Binary busData(busValue.begin(), busValue.end()); 6619094d4f6SSunnySrivastava1984 6629094d4f6SSunnySrivastava1984 updatedEeproms.push_back(std::make_tuple( 6639094d4f6SSunnySrivastava1984 objectPath, recordName, keyword, busData)); 6649094d4f6SSunnySrivastava1984 } 6659094d4f6SSunnySrivastava1984 6669094d4f6SSunnySrivastava1984 // update the map as well, so that cache data is not 6679094d4f6SSunnySrivastava1984 // updated as blank while populating VPD map on Dbus in 6689094d4f6SSunnySrivastava1984 // populateDBus Api 6699094d4f6SSunnySrivastava1984 kwdValue = busValue; 6709094d4f6SSunnySrivastava1984 continue; 6719094d4f6SSunnySrivastava1984 } 6729094d4f6SSunnySrivastava1984 else if (kwdValue.find_first_not_of(' ') == string::npos) 6739094d4f6SSunnySrivastava1984 { 6749094d4f6SSunnySrivastava1984 string errMsg = "VPD is blank on both cache and " 6759094d4f6SSunnySrivastava1984 "hardware for record: "; 6769094d4f6SSunnySrivastava1984 errMsg += (*it).first; 6779094d4f6SSunnySrivastava1984 errMsg += " and keyword: "; 6789094d4f6SSunnySrivastava1984 errMsg += keyword; 6799094d4f6SSunnySrivastava1984 errMsg += ". SSR need to update hardware VPD."; 6809094d4f6SSunnySrivastava1984 6819094d4f6SSunnySrivastava1984 // both the data are blanks, log PEL 6829094d4f6SSunnySrivastava1984 PelAdditionalData additionalData; 6839094d4f6SSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 6849094d4f6SSunnySrivastava1984 objectPath); 6859094d4f6SSunnySrivastava1984 6869094d4f6SSunnySrivastava1984 additionalData.emplace("DESCRIPTION", errMsg); 6879094d4f6SSunnySrivastava1984 6889094d4f6SSunnySrivastava1984 // log PEL TODO: Block IPL 6890746eeebSSunny Srivastava createPEL(additionalData, PelSeverity::ERROR, 6900746eeebSSunny Srivastava errIntfForBlankSystemVPD); 6919094d4f6SSunnySrivastava1984 continue; 6929094d4f6SSunnySrivastava1984 } 6939094d4f6SSunnySrivastava1984 } 6949094d4f6SSunnySrivastava1984 } 6959094d4f6SSunnySrivastava1984 } 6969094d4f6SSunnySrivastava1984 } 6979094d4f6SSunnySrivastava1984 6989094d4f6SSunnySrivastava1984 return updatedEeproms; 6999094d4f6SSunnySrivastava1984 } 7009094d4f6SSunnySrivastava1984 7019094d4f6SSunnySrivastava1984 /** 7028e140a1cSPriyangaRamasamy * @brief Populate Dbus. 703abb87edaSPriyangaRamasamy * This method invokes all the populateInterface functions 704abb87edaSPriyangaRamasamy * and notifies PIM about dbus object. 7058e140a1cSPriyangaRamasamy * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the 7068e140a1cSPriyangaRamasamy * input. 707abb87edaSPriyangaRamasamy * @param[in] js - Inventory json object 708abb87edaSPriyangaRamasamy * @param[in] filePath - Path of the vpd file 709abb87edaSPriyangaRamasamy * @param[in] preIntrStr - Interface string 710abb87edaSPriyangaRamasamy */ 711abb87edaSPriyangaRamasamy template <typename T> 7129094d4f6SSunnySrivastava1984 static void populateDbus(T& vpdMap, nlohmann::json& js, const string& filePath) 713abb87edaSPriyangaRamasamy { 714abb87edaSPriyangaRamasamy inventory::InterfaceMap interfaces; 715abb87edaSPriyangaRamasamy inventory::ObjectMap objects; 716abb87edaSPriyangaRamasamy inventory::PropertyMap prop; 717abb87edaSPriyangaRamasamy 7189094d4f6SSunnySrivastava1984 // map to hold all the keywords whose value has been changed at standby 7199094d4f6SSunnySrivastava1984 vector<RestoredEeproms> updatedEeproms = {}; 7209094d4f6SSunnySrivastava1984 721e12b181bSSunnySrivastava1984 bool isSystemVpd = false; 722abb87edaSPriyangaRamasamy for (const auto& item : js["frus"][filePath]) 723abb87edaSPriyangaRamasamy { 724abb87edaSPriyangaRamasamy const auto& objectPath = item["inventoryPath"]; 725abb87edaSPriyangaRamasamy sdbusplus::message::object_path object(objectPath); 7268e140a1cSPriyangaRamasamy isSystemVpd = item.value("isSystemVpd", false); 7279094d4f6SSunnySrivastava1984 728abb87edaSPriyangaRamasamy // Populate the VPD keywords and the common interfaces only if we 729abb87edaSPriyangaRamasamy // are asked to inherit that data from the VPD, else only add the 730abb87edaSPriyangaRamasamy // extraInterfaces. 731abb87edaSPriyangaRamasamy if (item.value("inherit", true)) 732abb87edaSPriyangaRamasamy { 73358e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 734abb87edaSPriyangaRamasamy { 7359094d4f6SSunnySrivastava1984 if (isSystemVpd) 7369094d4f6SSunnySrivastava1984 { 7379094d4f6SSunnySrivastava1984 std::vector<std::string> interfaces = { 7389094d4f6SSunnySrivastava1984 motherBoardInterface}; 7399094d4f6SSunnySrivastava1984 // call mapper to check for object path creation 7409094d4f6SSunnySrivastava1984 MapperResponse subTree = 7419094d4f6SSunnySrivastava1984 getObjectSubtreeForInterfaces(pimPath, 0, interfaces); 7429094d4f6SSunnySrivastava1984 743df0a1e1eSSantosh Puranik // Attempt system VPD restore if we have a motherboard 744df0a1e1eSSantosh Puranik // object in the inventory. 745df0a1e1eSSantosh Puranik if ((subTree.size() != 0) && 7469094d4f6SSunnySrivastava1984 (subTree.find(pimPath + std::string(objectPath)) != 747df0a1e1eSSantosh Puranik subTree.end())) 748df0a1e1eSSantosh Puranik { 7499094d4f6SSunnySrivastava1984 updatedEeproms = restoreSystemVPD(vpdMap, objectPath); 7509094d4f6SSunnySrivastava1984 } 7519094d4f6SSunnySrivastava1984 else 7529094d4f6SSunnySrivastava1984 { 7539094d4f6SSunnySrivastava1984 log<level::ERR>("No object path found"); 7549094d4f6SSunnySrivastava1984 } 7559094d4f6SSunnySrivastava1984 } 7569094d4f6SSunnySrivastava1984 7578e140a1cSPriyangaRamasamy // Each record in the VPD becomes an interface and all 7588e140a1cSPriyangaRamasamy // keyword within the record are properties under that 7598e140a1cSPriyangaRamasamy // interface. 760abb87edaSPriyangaRamasamy for (const auto& record : vpdMap) 761abb87edaSPriyangaRamasamy { 762abb87edaSPriyangaRamasamy populateFruSpecificInterfaces( 763e12b181bSSunnySrivastava1984 record.second, ipzVpdInf + record.first, interfaces); 764abb87edaSPriyangaRamasamy } 765abb87edaSPriyangaRamasamy } 76658e22145SAlpana Kumari else if constexpr (is_same<T, KeywordVpdMap>::value) 767abb87edaSPriyangaRamasamy { 768e12b181bSSunnySrivastava1984 populateFruSpecificInterfaces(vpdMap, kwdVpdInf, interfaces); 769abb87edaSPriyangaRamasamy } 77088edeb6fSSantosh Puranik if (js.find("commonInterfaces") != js.end()) 77188edeb6fSSantosh Puranik { 77288edeb6fSSantosh Puranik populateInterfaces(js["commonInterfaces"], interfaces, vpdMap, 77388edeb6fSSantosh Puranik isSystemVpd); 77488edeb6fSSantosh Puranik } 775abb87edaSPriyangaRamasamy } 7760859eb65SSantosh Puranik else 7770859eb65SSantosh Puranik { 7780859eb65SSantosh Puranik // Check if we have been asked to inherit specific record(s) 77958e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 7800859eb65SSantosh Puranik { 7810859eb65SSantosh Puranik if (item.find("copyRecords") != item.end()) 7820859eb65SSantosh Puranik { 7830859eb65SSantosh Puranik for (const auto& record : item["copyRecords"]) 7840859eb65SSantosh Puranik { 7850859eb65SSantosh Puranik const string& recordName = record; 7860859eb65SSantosh Puranik if (vpdMap.find(recordName) != vpdMap.end()) 7870859eb65SSantosh Puranik { 7880859eb65SSantosh Puranik populateFruSpecificInterfaces( 789e12b181bSSunnySrivastava1984 vpdMap.at(recordName), ipzVpdInf + recordName, 7900859eb65SSantosh Puranik interfaces); 7910859eb65SSantosh Puranik } 7920859eb65SSantosh Puranik } 7930859eb65SSantosh Puranik } 7940859eb65SSantosh Puranik } 7950859eb65SSantosh Puranik } 79658e22145SAlpana Kumari if (item.value("inheritEI", true)) 79758e22145SAlpana Kumari { 798abb87edaSPriyangaRamasamy // Populate interfaces and properties that are common to every FRU 7998e140a1cSPriyangaRamasamy // and additional interface that might be defined on a per-FRU 8008e140a1cSPriyangaRamasamy // basis. 801abb87edaSPriyangaRamasamy if (item.find("extraInterfaces") != item.end()) 802abb87edaSPriyangaRamasamy { 80388edeb6fSSantosh Puranik populateInterfaces(item["extraInterfaces"], interfaces, vpdMap, 80488edeb6fSSantosh Puranik isSystemVpd); 805abb87edaSPriyangaRamasamy } 80658e22145SAlpana Kumari } 807abb87edaSPriyangaRamasamy objects.emplace(move(object), move(interfaces)); 808abb87edaSPriyangaRamasamy } 809abb87edaSPriyangaRamasamy 8108e140a1cSPriyangaRamasamy if (isSystemVpd) 8118e140a1cSPriyangaRamasamy { 812d278df11SSantosh Puranik string systemJsonName{}; 81383a1d5deSPriyangaRamasamy if constexpr (is_same<T, Parsed>::value) 81483a1d5deSPriyangaRamasamy { 815f05effdbSAlpana Kumari // pick the right system json 816d278df11SSantosh Puranik systemJsonName = getSystemsJson(vpdMap); 81783a1d5deSPriyangaRamasamy } 81883a1d5deSPriyangaRamasamy 819d278df11SSantosh Puranik fs::path target = systemJsonName; 82083a1d5deSPriyangaRamasamy fs::path link = INVENTORY_JSON_SYM_LINK; 82183a1d5deSPriyangaRamasamy 8220246a4d7SSantosh Puranik // Create the directory for hosting the symlink 8230246a4d7SSantosh Puranik fs::create_directories(VPD_FILES_PATH); 8240246a4d7SSantosh Puranik // unlink the symlink previously created (if any) 82583a1d5deSPriyangaRamasamy remove(INVENTORY_JSON_SYM_LINK); 82683a1d5deSPriyangaRamasamy // create a new symlink based on the system 82783a1d5deSPriyangaRamasamy fs::create_symlink(target, link); 82883a1d5deSPriyangaRamasamy 82983a1d5deSPriyangaRamasamy // Reloading the json 83083a1d5deSPriyangaRamasamy ifstream inventoryJson(link); 83183a1d5deSPriyangaRamasamy auto js = json::parse(inventoryJson); 83283a1d5deSPriyangaRamasamy inventoryJson.close(); 83383a1d5deSPriyangaRamasamy 8348e140a1cSPriyangaRamasamy inventory::ObjectMap primeObject = primeInventory(js, vpdMap); 8358e140a1cSPriyangaRamasamy objects.insert(primeObject.begin(), primeObject.end()); 83665b83601SAlpana Kumari 8379094d4f6SSunnySrivastava1984 // if system VPD has been restored at standby, update the EEPROM 8389094d4f6SSunnySrivastava1984 for (const auto& item : updatedEeproms) 8399094d4f6SSunnySrivastava1984 { 8409094d4f6SSunnySrivastava1984 updateHardware(get<0>(item), get<1>(item), get<2>(item), 8419094d4f6SSunnySrivastava1984 get<3>(item)); 8429094d4f6SSunnySrivastava1984 } 843f05effdbSAlpana Kumari 844f05effdbSAlpana Kumari // set the U-boot environment variable for device-tree 845f05effdbSAlpana Kumari if constexpr (is_same<T, Parsed>::value) 846f05effdbSAlpana Kumari { 847f05effdbSAlpana Kumari const string imKeyword = getIM(vpdMap); 848f05effdbSAlpana Kumari const string hwKeyword = getHW(vpdMap); 849f05effdbSAlpana Kumari string systemType = imKeyword; 850f05effdbSAlpana Kumari 851f05effdbSAlpana Kumari // check If system has constraint then append HW version to it. 852f05effdbSAlpana Kumari ifstream sysJson(SYSTEM_JSON); 853f05effdbSAlpana Kumari if (!sysJson) 854f05effdbSAlpana Kumari { 855f05effdbSAlpana Kumari throw((VpdJsonException("Failed to access Json path", 856f05effdbSAlpana Kumari SYSTEM_JSON))); 857f05effdbSAlpana Kumari } 858f05effdbSAlpana Kumari 859f05effdbSAlpana Kumari try 860f05effdbSAlpana Kumari { 861f05effdbSAlpana Kumari auto systemJson = json::parse(sysJson); 862f05effdbSAlpana Kumari if (systemJson["system"].find(imKeyword) != 863f05effdbSAlpana Kumari systemJson["system"].end()) 864f05effdbSAlpana Kumari { 865f05effdbSAlpana Kumari if (systemJson["system"][imKeyword].find("constraint") != 866f05effdbSAlpana Kumari systemJson["system"][imKeyword].end()) 867f05effdbSAlpana Kumari { 868f05effdbSAlpana Kumari systemType += "_" + hwKeyword; 869f05effdbSAlpana Kumari } 870f05effdbSAlpana Kumari } 871d278df11SSantosh Puranik } 872d278df11SSantosh Puranik catch (json::parse_error& ex) 873d278df11SSantosh Puranik { 874d278df11SSantosh Puranik throw((VpdJsonException("System Json parsing failed", 875d278df11SSantosh Puranik SYSTEM_JSON))); 876d278df11SSantosh Puranik } 877f05effdbSAlpana Kumari 878f05effdbSAlpana Kumari setDevTreeEnv(systemType); 879f05effdbSAlpana Kumari } 8808e140a1cSPriyangaRamasamy } 8818e140a1cSPriyangaRamasamy 882abb87edaSPriyangaRamasamy // Notify PIM 8836c71c9dcSSunny Srivastava common::utility::callPIM(move(objects)); 884abb87edaSPriyangaRamasamy } 885abb87edaSPriyangaRamasamy 886abb87edaSPriyangaRamasamy int main(int argc, char** argv) 887abb87edaSPriyangaRamasamy { 888abb87edaSPriyangaRamasamy int rc = 0; 889a20be8ecSSunnySrivastava1984 json js{}; 890a20be8ecSSunnySrivastava1984 891a20be8ecSSunnySrivastava1984 // map to hold additional data in case of logging pel 892a20be8ecSSunnySrivastava1984 PelAdditionalData additionalData{}; 893a20be8ecSSunnySrivastava1984 894a20be8ecSSunnySrivastava1984 // this is needed to hold base fru inventory path in case there is ECC or 895a20be8ecSSunnySrivastava1984 // vpd exception while parsing the file 896a20be8ecSSunnySrivastava1984 std::string baseFruInventoryPath = {}; 897abb87edaSPriyangaRamasamy 8980746eeebSSunny Srivastava // severity for PEL 8990746eeebSSunny Srivastava PelSeverity pelSeverity = PelSeverity::WARNING; 9000746eeebSSunny Srivastava 901abb87edaSPriyangaRamasamy try 902abb87edaSPriyangaRamasamy { 903647868edSPriyangaRamasamy string file{}; 904abb87edaSPriyangaRamasamy App app{"ibm-read-vpd - App to read IPZ format VPD, parse it and store " 905abb87edaSPriyangaRamasamy "in DBUS"}; 906abb87edaSPriyangaRamasamy 907abb87edaSPriyangaRamasamy app.add_option("-f, --file", file, "File containing VPD (IPZ/KEYWORD)") 9082f793048SAlpana Kumari ->required(); 909abb87edaSPriyangaRamasamy 910abb87edaSPriyangaRamasamy CLI11_PARSE(app, argc, argv); 911abb87edaSPriyangaRamasamy 91212e24ff3SSantosh Puranik cout << "Parser launched with file: " << file << "\n"; 91312e24ff3SSantosh Puranik 9140746eeebSSunny Srivastava // PEL severity should be ERROR in case of any system VPD failure 9150746eeebSSunny Srivastava if (file == systemVpdFilePath) 9160746eeebSSunny Srivastava { 9170746eeebSSunny Srivastava pelSeverity = PelSeverity::ERROR; 9180746eeebSSunny Srivastava } 9190746eeebSSunny Srivastava 9200246a4d7SSantosh Puranik auto jsonToParse = INVENTORY_JSON_DEFAULT; 9210246a4d7SSantosh Puranik 9220246a4d7SSantosh Puranik // If the symlink exists, it means it has been setup for us, switch the 9230246a4d7SSantosh Puranik // path 9240246a4d7SSantosh Puranik if (fs::exists(INVENTORY_JSON_SYM_LINK)) 9250246a4d7SSantosh Puranik { 9260246a4d7SSantosh Puranik jsonToParse = INVENTORY_JSON_SYM_LINK; 9270246a4d7SSantosh Puranik } 9280246a4d7SSantosh Puranik 929abb87edaSPriyangaRamasamy // Make sure that the file path we get is for a supported EEPROM 9300246a4d7SSantosh Puranik ifstream inventoryJson(jsonToParse); 931a20be8ecSSunnySrivastava1984 if (!inventoryJson) 932a20be8ecSSunnySrivastava1984 { 9330746eeebSSunny Srivastava throw(VpdJsonException("Failed to access Json path", jsonToParse)); 934a20be8ecSSunnySrivastava1984 } 935a20be8ecSSunnySrivastava1984 936a20be8ecSSunnySrivastava1984 try 937a20be8ecSSunnySrivastava1984 { 938a20be8ecSSunnySrivastava1984 js = json::parse(inventoryJson); 939a20be8ecSSunnySrivastava1984 } 940a20be8ecSSunnySrivastava1984 catch (json::parse_error& ex) 941a20be8ecSSunnySrivastava1984 { 9420746eeebSSunny Srivastava throw(VpdJsonException("Json parsing failed", jsonToParse)); 943a20be8ecSSunnySrivastava1984 } 944abb87edaSPriyangaRamasamy 94512e24ff3SSantosh Puranik // Do we have the mandatory "frus" section? 94612e24ff3SSantosh Puranik if (js.find("frus") == js.end()) 94712e24ff3SSantosh Puranik { 94812e24ff3SSantosh Puranik throw(VpdJsonException("FRUs section not found in JSON", 94912e24ff3SSantosh Puranik jsonToParse)); 95012e24ff3SSantosh Puranik } 95112e24ff3SSantosh Puranik 952647868edSPriyangaRamasamy // Check if it's a udev path - patterned as(/ahb/ahb:apb/ahb:apb:bus@) 953647868edSPriyangaRamasamy if (file.find("/ahb:apb") != string::npos) 954647868edSPriyangaRamasamy { 955647868edSPriyangaRamasamy // Translate udev path to a generic /sys/bus/.. file path. 956647868edSPriyangaRamasamy udevToGenericPath(file); 95712e24ff3SSantosh Puranik cout << "Path after translation: " << file << "\n"; 95812e24ff3SSantosh Puranik 95912e24ff3SSantosh Puranik if ((js["frus"].find(file) != js["frus"].end()) && 96012e24ff3SSantosh Puranik (js["frus"][file].at(0).value("isSystemVpd", false))) 961647868edSPriyangaRamasamy { 962647868edSPriyangaRamasamy return 0; 963647868edSPriyangaRamasamy } 964647868edSPriyangaRamasamy } 965647868edSPriyangaRamasamy 966647868edSPriyangaRamasamy if (file.empty()) 967647868edSPriyangaRamasamy { 968647868edSPriyangaRamasamy cerr << "The EEPROM path <" << file << "> is not valid."; 969647868edSPriyangaRamasamy return 0; 970647868edSPriyangaRamasamy } 97112e24ff3SSantosh Puranik if (js["frus"].find(file) == js["frus"].end()) 972abb87edaSPriyangaRamasamy { 97358e22145SAlpana Kumari cout << "Device path not in JSON, ignoring" << endl; 97488edeb6fSSantosh Puranik return 0; 975abb87edaSPriyangaRamasamy } 976abb87edaSPriyangaRamasamy 9772f793048SAlpana Kumari if (!fs::exists(file)) 9782f793048SAlpana Kumari { 9792f793048SAlpana Kumari cout << "Device path: " << file 9802f793048SAlpana Kumari << " does not exist. Spurious udev event? Exiting." << endl; 9812f793048SAlpana Kumari return 0; 9822f793048SAlpana Kumari } 9832f793048SAlpana Kumari 984a20be8ecSSunnySrivastava1984 baseFruInventoryPath = js["frus"][file][0]["inventoryPath"]; 9858589375fSSantosh Puranik // Check if we can read the VPD file based on the power state 9868589375fSSantosh Puranik if (js["frus"][file].at(0).value("powerOffOnly", false)) 9878589375fSSantosh Puranik { 9888589375fSSantosh Puranik if ("xyz.openbmc_project.State.Chassis.PowerState.On" == 9898589375fSSantosh Puranik getPowerState()) 9908589375fSSantosh Puranik { 9918589375fSSantosh Puranik cout << "This VPD cannot be read when power is ON" << endl; 9928589375fSSantosh Puranik return 0; 9938589375fSSantosh Puranik } 9948589375fSSantosh Puranik } 995a20be8ecSSunnySrivastava1984 9962f793048SAlpana Kumari try 9972f793048SAlpana Kumari { 9982f793048SAlpana Kumari Binary vpdVector = getVpdDataInVector(js, file); 999*33c61c2dSPriyangaRamasamy ParserInterface* parser = ParserFactory::getParser(vpdVector); 10002f793048SAlpana Kumari 10012f793048SAlpana Kumari variant<KeywordVpdMap, Store> parseResult; 10022f793048SAlpana Kumari parseResult = parser->parse(); 10039a19554cSSunnySrivastava1984 1004e12b181bSSunnySrivastava1984 if (auto pVal = get_if<Store>(&parseResult)) 1005abb87edaSPriyangaRamasamy { 1006e12b181bSSunnySrivastava1984 populateDbus(pVal->getVpdMap(), js, file); 1007e12b181bSSunnySrivastava1984 } 1008e12b181bSSunnySrivastava1984 else if (auto pVal = get_if<KeywordVpdMap>(&parseResult)) 1009abb87edaSPriyangaRamasamy { 1010e12b181bSSunnySrivastava1984 populateDbus(*pVal, js, file); 1011abb87edaSPriyangaRamasamy } 1012abb87edaSPriyangaRamasamy 1013e12b181bSSunnySrivastava1984 // release the parser object 1014e12b181bSSunnySrivastava1984 ParserFactory::freeParser(parser); 1015abb87edaSPriyangaRamasamy } 10162f793048SAlpana Kumari catch (exception& e) 10172f793048SAlpana Kumari { 10182f793048SAlpana Kumari postFailAction(js, file); 1019a504c3eeSPriyangaRamasamy throw; 10202f793048SAlpana Kumari } 10212f793048SAlpana Kumari } 1022a20be8ecSSunnySrivastava1984 catch (const VpdJsonException& ex) 1023a20be8ecSSunnySrivastava1984 { 1024a20be8ecSSunnySrivastava1984 additionalData.emplace("JSON_PATH", ex.getJsonPath()); 1025a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", ex.what()); 10260746eeebSSunny Srivastava createPEL(additionalData, pelSeverity, errIntfForJsonFailure); 1027a20be8ecSSunnySrivastava1984 1028a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 1029a20be8ecSSunnySrivastava1984 rc = -1; 1030a20be8ecSSunnySrivastava1984 } 1031a20be8ecSSunnySrivastava1984 catch (const VpdEccException& ex) 1032a20be8ecSSunnySrivastava1984 { 1033a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", "ECC check failed"); 1034a20be8ecSSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 1035a20be8ecSSunnySrivastava1984 INVENTORY_PATH + baseFruInventoryPath); 10360746eeebSSunny Srivastava createPEL(additionalData, pelSeverity, errIntfForEccCheckFail); 1037a20be8ecSSunnySrivastava1984 1038a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 1039a20be8ecSSunnySrivastava1984 rc = -1; 1040a20be8ecSSunnySrivastava1984 } 1041a20be8ecSSunnySrivastava1984 catch (const VpdDataException& ex) 1042a20be8ecSSunnySrivastava1984 { 1043a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", "Invalid VPD data"); 1044a20be8ecSSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 1045a20be8ecSSunnySrivastava1984 INVENTORY_PATH + baseFruInventoryPath); 10460746eeebSSunny Srivastava createPEL(additionalData, pelSeverity, errIntfForInvalidVPD); 1047a20be8ecSSunnySrivastava1984 1048a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 1049a20be8ecSSunnySrivastava1984 rc = -1; 1050a20be8ecSSunnySrivastava1984 } 1051abb87edaSPriyangaRamasamy catch (exception& e) 1052abb87edaSPriyangaRamasamy { 1053abb87edaSPriyangaRamasamy cerr << e.what() << "\n"; 1054abb87edaSPriyangaRamasamy rc = -1; 1055abb87edaSPriyangaRamasamy } 1056abb87edaSPriyangaRamasamy 1057abb87edaSPriyangaRamasamy return rc; 1058abb87edaSPriyangaRamasamy }