1abb87edaSPriyangaRamasamy #include "config.h" 2abb87edaSPriyangaRamasamy 3abb87edaSPriyangaRamasamy #include "defines.hpp" 4e12b181bSSunnySrivastava1984 #include "ipz_parser.hpp" 5abb87edaSPriyangaRamasamy #include "keyword_vpd_parser.hpp" 6a00936f8SAlpana Kumari #include "memory_vpd_parser.hpp" 7e12b181bSSunnySrivastava1984 #include "parser_factory.hpp" 8abb87edaSPriyangaRamasamy #include "utils.hpp" 9a20be8ecSSunnySrivastava1984 #include "vpd_exceptions.hpp" 10abb87edaSPriyangaRamasamy 119094d4f6SSunnySrivastava1984 #include <assert.h> 128ea3f6d0SAlpana Kumari #include <ctype.h> 138ea3f6d0SAlpana Kumari 14abb87edaSPriyangaRamasamy #include <CLI/CLI.hpp> 1588edeb6fSSantosh Puranik #include <algorithm> 1665b83601SAlpana Kumari #include <cstdarg> 17abb87edaSPriyangaRamasamy #include <exception> 1883a1d5deSPriyangaRamasamy #include <filesystem> 19abb87edaSPriyangaRamasamy #include <fstream> 202f793048SAlpana Kumari #include <gpiod.hpp> 21abb87edaSPriyangaRamasamy #include <iostream> 22abb87edaSPriyangaRamasamy #include <iterator> 23abb87edaSPriyangaRamasamy #include <nlohmann/json.hpp> 24280197e3SAndrew Geissler #include <phosphor-logging/log.hpp> 25abb87edaSPriyangaRamasamy 26abb87edaSPriyangaRamasamy using namespace std; 27abb87edaSPriyangaRamasamy using namespace openpower::vpd; 28abb87edaSPriyangaRamasamy using namespace CLI; 29abb87edaSPriyangaRamasamy using namespace vpd::keyword::parser; 3083a1d5deSPriyangaRamasamy using namespace openpower::vpd::constants; 3183a1d5deSPriyangaRamasamy namespace fs = filesystem; 3283a1d5deSPriyangaRamasamy using json = nlohmann::json; 33e12b181bSSunnySrivastava1984 using namespace openpower::vpd::parser::factory; 34945a02d3SSunnySrivastava1984 using namespace openpower::vpd::inventory; 35a00936f8SAlpana Kumari using namespace openpower::vpd::memory::parser; 36e12b181bSSunnySrivastava1984 using namespace openpower::vpd::parser::interface; 37a20be8ecSSunnySrivastava1984 using namespace openpower::vpd::exceptions; 38280197e3SAndrew Geissler using namespace phosphor::logging; 39abb87edaSPriyangaRamasamy 4065b83601SAlpana Kumari static const deviceTreeMap deviceTreeSystemTypeMap = { 414641bff5SSantosh Puranik {RAINIER_2U, "conf@aspeed-bmc-ibm-rainier.dtb"}, 424641bff5SSantosh Puranik {RAINIER_4U, "conf@aspeed-bmc-ibm-rainier-4u.dtb"}, 43*7c9cddf7SAndrew Geissler {RAINIER_1S4U, "conf@aspeed-bmc-ibm-rainier-1s4u.dtb"}, 444641bff5SSantosh Puranik {EVEREST, "conf@aspeed-bmc-ibm-everest.dtb"}}; 4565b83601SAlpana Kumari 4688edeb6fSSantosh Puranik /** 478589375fSSantosh Puranik * @brief Returns the power state for chassis0 488589375fSSantosh Puranik */ 498589375fSSantosh Puranik static auto getPowerState() 508589375fSSantosh Puranik { 518589375fSSantosh Puranik // TODO: How do we handle multiple chassis? 528589375fSSantosh Puranik string powerState{}; 538589375fSSantosh Puranik auto bus = sdbusplus::bus::new_default(); 548589375fSSantosh Puranik auto properties = 558589375fSSantosh Puranik bus.new_method_call("xyz.openbmc_project.State.Chassis", 568589375fSSantosh Puranik "/xyz/openbmc_project/state/chassis0", 578589375fSSantosh Puranik "org.freedesktop.DBus.Properties", "Get"); 588589375fSSantosh Puranik properties.append("xyz.openbmc_project.State.Chassis"); 598589375fSSantosh Puranik properties.append("CurrentPowerState"); 608589375fSSantosh Puranik auto result = bus.call(properties); 618589375fSSantosh Puranik if (!result.is_method_error()) 628589375fSSantosh Puranik { 638589375fSSantosh Puranik variant<string> val; 648589375fSSantosh Puranik result.read(val); 658589375fSSantosh Puranik if (auto pVal = get_if<string>(&val)) 668589375fSSantosh Puranik { 678589375fSSantosh Puranik powerState = *pVal; 688589375fSSantosh Puranik } 698589375fSSantosh Puranik } 708589375fSSantosh Puranik cout << "Power state is: " << powerState << endl; 718589375fSSantosh Puranik return powerState; 728589375fSSantosh Puranik } 738589375fSSantosh Puranik 748589375fSSantosh Puranik /** 7588edeb6fSSantosh Puranik * @brief Expands location codes 7688edeb6fSSantosh Puranik */ 7788edeb6fSSantosh Puranik static auto expandLocationCode(const string& unexpanded, const Parsed& vpdMap, 7888edeb6fSSantosh Puranik bool isSystemVpd) 7988edeb6fSSantosh Puranik { 8088edeb6fSSantosh Puranik auto expanded{unexpanded}; 8188edeb6fSSantosh Puranik static constexpr auto SYSTEM_OBJECT = "/system/chassis/motherboard"; 8288edeb6fSSantosh Puranik static constexpr auto VCEN_IF = "com.ibm.ipzvpd.VCEN"; 8388edeb6fSSantosh Puranik static constexpr auto VSYS_IF = "com.ibm.ipzvpd.VSYS"; 8488edeb6fSSantosh Puranik size_t idx = expanded.find("fcs"); 8588edeb6fSSantosh Puranik try 8688edeb6fSSantosh Puranik { 8788edeb6fSSantosh Puranik if (idx != string::npos) 8888edeb6fSSantosh Puranik { 8988edeb6fSSantosh Puranik string fc{}; 9088edeb6fSSantosh Puranik string se{}; 9188edeb6fSSantosh Puranik if (isSystemVpd) 9288edeb6fSSantosh Puranik { 9388edeb6fSSantosh Puranik const auto& fcData = vpdMap.at("VCEN").at("FC"); 9488edeb6fSSantosh Puranik const auto& seData = vpdMap.at("VCEN").at("SE"); 9588edeb6fSSantosh Puranik fc = string(fcData.data(), fcData.size()); 9688edeb6fSSantosh Puranik se = string(seData.data(), seData.size()); 9788edeb6fSSantosh Puranik } 9888edeb6fSSantosh Puranik else 9988edeb6fSSantosh Puranik { 10088edeb6fSSantosh Puranik fc = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "FC"); 10188edeb6fSSantosh Puranik se = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "SE"); 10288edeb6fSSantosh Puranik } 10388edeb6fSSantosh Puranik 10481671f6dSAlpana Kumari // TODO: See if ND0 can be placed in the JSON 10581671f6dSAlpana Kumari expanded.replace(idx, 3, fc.substr(0, 4) + ".ND0." + se); 10688edeb6fSSantosh Puranik } 10788edeb6fSSantosh Puranik else 10888edeb6fSSantosh Puranik { 10988edeb6fSSantosh Puranik idx = expanded.find("mts"); 11088edeb6fSSantosh Puranik if (idx != string::npos) 11188edeb6fSSantosh Puranik { 11288edeb6fSSantosh Puranik string mt{}; 11388edeb6fSSantosh Puranik string se{}; 11488edeb6fSSantosh Puranik if (isSystemVpd) 11588edeb6fSSantosh Puranik { 11688edeb6fSSantosh Puranik const auto& mtData = vpdMap.at("VSYS").at("TM"); 11788edeb6fSSantosh Puranik const auto& seData = vpdMap.at("VSYS").at("SE"); 11888edeb6fSSantosh Puranik mt = string(mtData.data(), mtData.size()); 11988edeb6fSSantosh Puranik se = string(seData.data(), seData.size()); 12088edeb6fSSantosh Puranik } 12188edeb6fSSantosh Puranik else 12288edeb6fSSantosh Puranik { 12388edeb6fSSantosh Puranik mt = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "TM"); 12488edeb6fSSantosh Puranik se = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "SE"); 12588edeb6fSSantosh Puranik } 12688edeb6fSSantosh Puranik 12788edeb6fSSantosh Puranik replace(mt.begin(), mt.end(), '-', '.'); 12888edeb6fSSantosh Puranik expanded.replace(idx, 3, mt + "." + se); 12988edeb6fSSantosh Puranik } 13088edeb6fSSantosh Puranik } 13188edeb6fSSantosh Puranik } 13258e22145SAlpana Kumari catch (exception& e) 13388edeb6fSSantosh Puranik { 13458e22145SAlpana Kumari cerr << "Failed to expand location code with exception: " << e.what() 13558e22145SAlpana Kumari << "\n"; 13688edeb6fSSantosh Puranik } 13788edeb6fSSantosh Puranik return expanded; 13888edeb6fSSantosh Puranik } 1392f793048SAlpana Kumari 140abb87edaSPriyangaRamasamy /** 141abb87edaSPriyangaRamasamy * @brief Populate FRU specific interfaces. 142abb87edaSPriyangaRamasamy * 143abb87edaSPriyangaRamasamy * This is a common method which handles both 144abb87edaSPriyangaRamasamy * ipz and keyword specific interfaces thus, 145abb87edaSPriyangaRamasamy * reducing the code redundancy. 146abb87edaSPriyangaRamasamy * @param[in] map - Reference to the innermost keyword-value map. 147abb87edaSPriyangaRamasamy * @param[in] preIntrStr - Reference to the interface string. 148abb87edaSPriyangaRamasamy * @param[out] interfaces - Reference to interface map. 149abb87edaSPriyangaRamasamy */ 150abb87edaSPriyangaRamasamy template <typename T> 151abb87edaSPriyangaRamasamy static void populateFruSpecificInterfaces(const T& map, 152abb87edaSPriyangaRamasamy const string& preIntrStr, 153abb87edaSPriyangaRamasamy inventory::InterfaceMap& interfaces) 154abb87edaSPriyangaRamasamy { 155abb87edaSPriyangaRamasamy inventory::PropertyMap prop; 156abb87edaSPriyangaRamasamy 157abb87edaSPriyangaRamasamy for (const auto& kwVal : map) 158abb87edaSPriyangaRamasamy { 15958e22145SAlpana Kumari vector<uint8_t> vec(kwVal.second.begin(), kwVal.second.end()); 160abb87edaSPriyangaRamasamy 161abb87edaSPriyangaRamasamy auto kw = kwVal.first; 162abb87edaSPriyangaRamasamy 163abb87edaSPriyangaRamasamy if (kw[0] == '#') 164abb87edaSPriyangaRamasamy { 16558e22145SAlpana Kumari kw = string("PD_") + kw[1]; 166abb87edaSPriyangaRamasamy } 1678ea3f6d0SAlpana Kumari else if (isdigit(kw[0])) 1688ea3f6d0SAlpana Kumari { 16958e22145SAlpana Kumari kw = string("N_") + kw; 1708ea3f6d0SAlpana Kumari } 171abb87edaSPriyangaRamasamy prop.emplace(move(kw), move(vec)); 172abb87edaSPriyangaRamasamy } 173abb87edaSPriyangaRamasamy 174abb87edaSPriyangaRamasamy interfaces.emplace(preIntrStr, move(prop)); 175abb87edaSPriyangaRamasamy } 176abb87edaSPriyangaRamasamy 177abb87edaSPriyangaRamasamy /** 178abb87edaSPriyangaRamasamy * @brief Populate Interfaces. 179abb87edaSPriyangaRamasamy * 180abb87edaSPriyangaRamasamy * This method populates common and extra interfaces to dbus. 181abb87edaSPriyangaRamasamy * @param[in] js - json object 182abb87edaSPriyangaRamasamy * @param[out] interfaces - Reference to interface map 183abb87edaSPriyangaRamasamy * @param[in] vpdMap - Reference to the parsed vpd map. 18488edeb6fSSantosh Puranik * @param[in] isSystemVpd - Denotes whether we are collecting the system VPD. 185abb87edaSPriyangaRamasamy */ 186abb87edaSPriyangaRamasamy template <typename T> 187abb87edaSPriyangaRamasamy static void populateInterfaces(const nlohmann::json& js, 188abb87edaSPriyangaRamasamy inventory::InterfaceMap& interfaces, 18988edeb6fSSantosh Puranik const T& vpdMap, bool isSystemVpd) 190abb87edaSPriyangaRamasamy { 191abb87edaSPriyangaRamasamy for (const auto& ifs : js.items()) 192abb87edaSPriyangaRamasamy { 19388edeb6fSSantosh Puranik string inf = ifs.key(); 194abb87edaSPriyangaRamasamy inventory::PropertyMap props; 195abb87edaSPriyangaRamasamy 196abb87edaSPriyangaRamasamy for (const auto& itr : ifs.value().items()) 197abb87edaSPriyangaRamasamy { 19888edeb6fSSantosh Puranik const string& busProp = itr.key(); 19988edeb6fSSantosh Puranik 20031970dedSAlpana Kumari if (itr.value().is_boolean()) 20131970dedSAlpana Kumari { 20288edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<bool>()); 20388edeb6fSSantosh Puranik } 20488edeb6fSSantosh Puranik else if (itr.value().is_string()) 20588edeb6fSSantosh Puranik { 20658e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 20788edeb6fSSantosh Puranik { 20888edeb6fSSantosh Puranik if (busProp == "LocationCode" && 20988edeb6fSSantosh Puranik inf == "com.ibm.ipzvpd.Location") 21088edeb6fSSantosh Puranik { 21188edeb6fSSantosh Puranik auto prop = expandLocationCode( 21288edeb6fSSantosh Puranik itr.value().get<string>(), vpdMap, isSystemVpd); 21388edeb6fSSantosh Puranik props.emplace(busProp, prop); 21488edeb6fSSantosh Puranik } 21588edeb6fSSantosh Puranik else 21688edeb6fSSantosh Puranik { 21788edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<string>()); 21888edeb6fSSantosh Puranik } 21988edeb6fSSantosh Puranik } 22088edeb6fSSantosh Puranik else 22188edeb6fSSantosh Puranik { 22288edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<string>()); 22388edeb6fSSantosh Puranik } 22431970dedSAlpana Kumari } 22531970dedSAlpana Kumari else if (itr.value().is_object()) 22631970dedSAlpana Kumari { 227abb87edaSPriyangaRamasamy const string& rec = itr.value().value("recordName", ""); 228abb87edaSPriyangaRamasamy const string& kw = itr.value().value("keywordName", ""); 229abb87edaSPriyangaRamasamy const string& encoding = itr.value().value("encoding", ""); 230abb87edaSPriyangaRamasamy 23158e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 232abb87edaSPriyangaRamasamy { 23388edeb6fSSantosh Puranik if (!rec.empty() && !kw.empty() && vpdMap.count(rec) && 23488edeb6fSSantosh Puranik vpdMap.at(rec).count(kw)) 235abb87edaSPriyangaRamasamy { 236abb87edaSPriyangaRamasamy auto encoded = 237abb87edaSPriyangaRamasamy encodeKeyword(vpdMap.at(rec).at(kw), encoding); 23888edeb6fSSantosh Puranik props.emplace(busProp, encoded); 239abb87edaSPriyangaRamasamy } 240abb87edaSPriyangaRamasamy } 24158e22145SAlpana Kumari else if constexpr (is_same<T, KeywordVpdMap>::value) 242abb87edaSPriyangaRamasamy { 243abb87edaSPriyangaRamasamy if (!kw.empty() && vpdMap.count(kw)) 244abb87edaSPriyangaRamasamy { 245abb87edaSPriyangaRamasamy auto prop = 246abb87edaSPriyangaRamasamy string(vpdMap.at(kw).begin(), vpdMap.at(kw).end()); 247abb87edaSPriyangaRamasamy auto encoded = encodeKeyword(prop, encoding); 24888edeb6fSSantosh Puranik props.emplace(busProp, encoded); 249abb87edaSPriyangaRamasamy } 250abb87edaSPriyangaRamasamy } 251abb87edaSPriyangaRamasamy } 25231970dedSAlpana Kumari } 253abb87edaSPriyangaRamasamy interfaces.emplace(inf, move(props)); 254abb87edaSPriyangaRamasamy } 255abb87edaSPriyangaRamasamy } 256abb87edaSPriyangaRamasamy 2572f793048SAlpana Kumari static Binary getVpdDataInVector(const nlohmann::json& js, const string& file) 25858e22145SAlpana Kumari { 25958e22145SAlpana Kumari uint32_t offset = 0; 26058e22145SAlpana Kumari // check if offset present? 26158e22145SAlpana Kumari for (const auto& item : js["frus"][file]) 26258e22145SAlpana Kumari { 26358e22145SAlpana Kumari if (item.find("offset") != item.end()) 26458e22145SAlpana Kumari { 26558e22145SAlpana Kumari offset = item["offset"]; 26658e22145SAlpana Kumari } 26758e22145SAlpana Kumari } 26858e22145SAlpana Kumari 26958e22145SAlpana Kumari // TODO: Figure out a better way to get max possible VPD size. 27058e22145SAlpana Kumari Binary vpdVector; 27158e22145SAlpana Kumari vpdVector.resize(65504); 27258e22145SAlpana Kumari ifstream vpdFile; 27358e22145SAlpana Kumari vpdFile.open(file, ios::binary); 27458e22145SAlpana Kumari 27558e22145SAlpana Kumari vpdFile.seekg(offset, ios_base::cur); 27658e22145SAlpana Kumari vpdFile.read(reinterpret_cast<char*>(&vpdVector[0]), 65504); 27758e22145SAlpana Kumari vpdVector.resize(vpdFile.gcount()); 27858e22145SAlpana Kumari 27958e22145SAlpana Kumari return vpdVector; 28058e22145SAlpana Kumari } 28158e22145SAlpana Kumari 2822f793048SAlpana Kumari /* It does nothing. Just an empty function to return null 2832f793048SAlpana Kumari * at the end of variadic template args 2842f793048SAlpana Kumari */ 2852f793048SAlpana Kumari static string getCommand() 2862f793048SAlpana Kumari { 2872f793048SAlpana Kumari return ""; 2882f793048SAlpana Kumari } 2892f793048SAlpana Kumari 2902f793048SAlpana Kumari /* This function to arrange all arguments to make command 2912f793048SAlpana Kumari */ 2922f793048SAlpana Kumari template <typename T, typename... Types> 2932f793048SAlpana Kumari static string getCommand(T arg1, Types... args) 2942f793048SAlpana Kumari { 2952f793048SAlpana Kumari string cmd = " " + arg1 + getCommand(args...); 2962f793048SAlpana Kumari 2972f793048SAlpana Kumari return cmd; 2982f793048SAlpana Kumari } 2992f793048SAlpana Kumari 3002f793048SAlpana Kumari /* This API takes arguments and run that command 3012f793048SAlpana Kumari * returns output of that command 3022f793048SAlpana Kumari */ 3032f793048SAlpana Kumari template <typename T, typename... Types> 3042f793048SAlpana Kumari static vector<string> executeCmd(T&& path, Types... args) 3052f793048SAlpana Kumari { 3062f793048SAlpana Kumari vector<string> stdOutput; 3072f793048SAlpana Kumari array<char, 128> buffer; 3082f793048SAlpana Kumari 3092f793048SAlpana Kumari string cmd = path + getCommand(args...); 3102f793048SAlpana Kumari 3112f793048SAlpana Kumari unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose); 3122f793048SAlpana Kumari if (!pipe) 3132f793048SAlpana Kumari { 3142f793048SAlpana Kumari throw runtime_error("popen() failed!"); 3152f793048SAlpana Kumari } 3162f793048SAlpana Kumari while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) 3172f793048SAlpana Kumari { 3182f793048SAlpana Kumari stdOutput.emplace_back(buffer.data()); 3192f793048SAlpana Kumari } 3202f793048SAlpana Kumari 3212f793048SAlpana Kumari return stdOutput; 3222f793048SAlpana Kumari } 3232f793048SAlpana Kumari 3242f793048SAlpana Kumari /** This API will be called at the end of VPD collection to perform any post 3252f793048SAlpana Kumari * actions. 3262f793048SAlpana Kumari * 3272f793048SAlpana Kumari * @param[in] json - json object 3282f793048SAlpana Kumari * @param[in] file - eeprom file path 3292f793048SAlpana Kumari */ 3302f793048SAlpana Kumari static void postFailAction(const nlohmann::json& json, const string& file) 3312f793048SAlpana Kumari { 3322f793048SAlpana Kumari if ((json["frus"][file].at(0)).find("postActionFail") == 3332f793048SAlpana Kumari json["frus"][file].at(0).end()) 3342f793048SAlpana Kumari { 3352f793048SAlpana Kumari return; 3362f793048SAlpana Kumari } 3372f793048SAlpana Kumari 3382f793048SAlpana Kumari uint8_t pinValue = 0; 3392f793048SAlpana Kumari string pinName; 3402f793048SAlpana Kumari 3412f793048SAlpana Kumari for (const auto& postAction : 3422f793048SAlpana Kumari (json["frus"][file].at(0))["postActionFail"].items()) 3432f793048SAlpana Kumari { 3442f793048SAlpana Kumari if (postAction.key() == "pin") 3452f793048SAlpana Kumari { 3462f793048SAlpana Kumari pinName = postAction.value(); 3472f793048SAlpana Kumari } 3482f793048SAlpana Kumari else if (postAction.key() == "value") 3492f793048SAlpana Kumari { 3502f793048SAlpana Kumari // Get the value to set 3512f793048SAlpana Kumari pinValue = postAction.value(); 3522f793048SAlpana Kumari } 3532f793048SAlpana Kumari } 3542f793048SAlpana Kumari 3552f793048SAlpana Kumari cout << "Setting GPIO: " << pinName << " to " << (int)pinValue << endl; 3562f793048SAlpana Kumari 3572f793048SAlpana Kumari try 3582f793048SAlpana Kumari { 3592f793048SAlpana Kumari gpiod::line outputLine = gpiod::find_line(pinName); 3602f793048SAlpana Kumari 3612f793048SAlpana Kumari if (!outputLine) 3622f793048SAlpana Kumari { 3632f793048SAlpana Kumari cout << "Couldn't find output line:" << pinName 3642f793048SAlpana Kumari << " on GPIO. Skipping...\n"; 3652f793048SAlpana Kumari 3662f793048SAlpana Kumari return; 3672f793048SAlpana Kumari } 3682f793048SAlpana Kumari outputLine.request( 3692f793048SAlpana Kumari {"Disable line", ::gpiod::line_request::DIRECTION_OUTPUT, 0}, 3702f793048SAlpana Kumari pinValue); 3712f793048SAlpana Kumari } 3722f793048SAlpana Kumari catch (system_error&) 3732f793048SAlpana Kumari { 3742f793048SAlpana Kumari cerr << "Failed to set post-action GPIO" << endl; 3752f793048SAlpana Kumari } 3762f793048SAlpana Kumari } 3772f793048SAlpana Kumari 3782f793048SAlpana Kumari /** Performs any pre-action needed to get the FRU setup for collection. 3792f793048SAlpana Kumari * 3802f793048SAlpana Kumari * @param[in] json - json object 3812f793048SAlpana Kumari * @param[in] file - eeprom file path 3822f793048SAlpana Kumari */ 3832f793048SAlpana Kumari static void preAction(const nlohmann::json& json, const string& file) 3842f793048SAlpana Kumari { 3852f793048SAlpana Kumari if ((json["frus"][file].at(0)).find("preAction") == 3862f793048SAlpana Kumari json["frus"][file].at(0).end()) 3872f793048SAlpana Kumari { 3882f793048SAlpana Kumari return; 3892f793048SAlpana Kumari } 3902f793048SAlpana Kumari 3912f793048SAlpana Kumari uint8_t pinValue = 0; 3922f793048SAlpana Kumari string pinName; 3932f793048SAlpana Kumari 3942f793048SAlpana Kumari for (const auto& postAction : 3952f793048SAlpana Kumari (json["frus"][file].at(0))["preAction"].items()) 3962f793048SAlpana Kumari { 3972f793048SAlpana Kumari if (postAction.key() == "pin") 3982f793048SAlpana Kumari { 3992f793048SAlpana Kumari pinName = postAction.value(); 4002f793048SAlpana Kumari } 4012f793048SAlpana Kumari else if (postAction.key() == "value") 4022f793048SAlpana Kumari { 4032f793048SAlpana Kumari // Get the value to set 4042f793048SAlpana Kumari pinValue = postAction.value(); 4052f793048SAlpana Kumari } 4062f793048SAlpana Kumari } 4072f793048SAlpana Kumari 4082f793048SAlpana Kumari cout << "Setting GPIO: " << pinName << " to " << (int)pinValue << endl; 4092f793048SAlpana Kumari try 4102f793048SAlpana Kumari { 4112f793048SAlpana Kumari gpiod::line outputLine = gpiod::find_line(pinName); 4122f793048SAlpana Kumari 4132f793048SAlpana Kumari if (!outputLine) 4142f793048SAlpana Kumari { 4152f793048SAlpana Kumari cout << "Couldn't find output line:" << pinName 4162f793048SAlpana Kumari << " on GPIO. Skipping...\n"; 4172f793048SAlpana Kumari 4182f793048SAlpana Kumari return; 4192f793048SAlpana Kumari } 4202f793048SAlpana Kumari outputLine.request( 4212f793048SAlpana Kumari {"FRU pre-action", ::gpiod::line_request::DIRECTION_OUTPUT, 0}, 4222f793048SAlpana Kumari pinValue); 4232f793048SAlpana Kumari } 4242f793048SAlpana Kumari catch (system_error&) 4252f793048SAlpana Kumari { 4262f793048SAlpana Kumari cerr << "Failed to set pre-action GPIO" << endl; 4272f793048SAlpana Kumari return; 4282f793048SAlpana Kumari } 4292f793048SAlpana Kumari 4302f793048SAlpana Kumari // Now bind the device 4312f793048SAlpana Kumari string bind = json["frus"][file].at(0).value("bind", ""); 4322f793048SAlpana Kumari cout << "Binding device " << bind << endl; 4332f793048SAlpana Kumari string bindCmd = string("echo \"") + bind + 4342f793048SAlpana Kumari string("\" > /sys/bus/i2c/drivers/at24/bind"); 4352f793048SAlpana Kumari cout << bindCmd << endl; 4362f793048SAlpana Kumari executeCmd(bindCmd); 4372f793048SAlpana Kumari 4382f793048SAlpana Kumari // Check if device showed up (test for file) 4392f793048SAlpana Kumari if (!fs::exists(file)) 4402f793048SAlpana Kumari { 4412f793048SAlpana Kumari cout << "EEPROM " << file << " does not exist. Take failure action" 4422f793048SAlpana Kumari << endl; 4432f793048SAlpana Kumari // If not, then take failure postAction 4442f793048SAlpana Kumari postFailAction(json, file); 4452f793048SAlpana Kumari } 4462f793048SAlpana Kumari } 4472f793048SAlpana Kumari 448abb87edaSPriyangaRamasamy /** 4498e140a1cSPriyangaRamasamy * @brief Prime the Inventory 4508e140a1cSPriyangaRamasamy * Prime the inventory by populating only the location code, 4518e140a1cSPriyangaRamasamy * type interface and the inventory object for the frus 4528e140a1cSPriyangaRamasamy * which are not system vpd fru. 453abb87edaSPriyangaRamasamy * 4548e140a1cSPriyangaRamasamy * @param[in] jsObject - Reference to vpd inventory json object 4558e140a1cSPriyangaRamasamy * @param[in] vpdMap - Reference to the parsed vpd map 4568e140a1cSPriyangaRamasamy * 4578e140a1cSPriyangaRamasamy * @returns Map of items in extraInterface. 4588e140a1cSPriyangaRamasamy */ 4598e140a1cSPriyangaRamasamy template <typename T> 4608e140a1cSPriyangaRamasamy inventory::ObjectMap primeInventory(const nlohmann::json& jsObject, 4618e140a1cSPriyangaRamasamy const T& vpdMap) 4628e140a1cSPriyangaRamasamy { 4638e140a1cSPriyangaRamasamy inventory::ObjectMap objects; 4648e140a1cSPriyangaRamasamy 4658e140a1cSPriyangaRamasamy for (auto& itemFRUS : jsObject["frus"].items()) 4668e140a1cSPriyangaRamasamy { 4672f793048SAlpana Kumari // Take pre actions 4682f793048SAlpana Kumari preAction(jsObject, itemFRUS.key()); 4698e140a1cSPriyangaRamasamy for (auto& itemEEPROM : itemFRUS.value()) 4708e140a1cSPriyangaRamasamy { 4718e140a1cSPriyangaRamasamy inventory::InterfaceMap interfaces; 4728e140a1cSPriyangaRamasamy auto isSystemVpd = itemEEPROM.value("isSystemVpd", false); 4738e140a1cSPriyangaRamasamy inventory::Object object(itemEEPROM.at("inventoryPath")); 4748e140a1cSPriyangaRamasamy 4758e140a1cSPriyangaRamasamy if (!isSystemVpd && !itemEEPROM.value("noprime", false)) 4768e140a1cSPriyangaRamasamy { 477cfd7a75aSAlpana Kumari inventory::PropertyMap presProp; 478cfd7a75aSAlpana Kumari presProp.emplace("Present", false); 479cfd7a75aSAlpana Kumari interfaces.emplace("xyz.openbmc_project.Inventory.Item", 480cfd7a75aSAlpana Kumari move(presProp)); 481cfd7a75aSAlpana Kumari 4828e140a1cSPriyangaRamasamy if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end()) 4838e140a1cSPriyangaRamasamy { 4848e140a1cSPriyangaRamasamy for (const auto& eI : itemEEPROM["extraInterfaces"].items()) 4858e140a1cSPriyangaRamasamy { 4868e140a1cSPriyangaRamasamy inventory::PropertyMap props; 4878e140a1cSPriyangaRamasamy if (eI.key() == 4888e140a1cSPriyangaRamasamy openpower::vpd::constants::LOCATION_CODE_INF) 4898e140a1cSPriyangaRamasamy { 4908e140a1cSPriyangaRamasamy if constexpr (std::is_same<T, Parsed>::value) 4918e140a1cSPriyangaRamasamy { 4928e140a1cSPriyangaRamasamy for (auto& lC : eI.value().items()) 4938e140a1cSPriyangaRamasamy { 4948e140a1cSPriyangaRamasamy auto propVal = expandLocationCode( 4958e140a1cSPriyangaRamasamy lC.value().get<string>(), vpdMap, true); 4968e140a1cSPriyangaRamasamy 4978e140a1cSPriyangaRamasamy props.emplace(move(lC.key()), 4988e140a1cSPriyangaRamasamy move(propVal)); 4998e140a1cSPriyangaRamasamy interfaces.emplace(move(eI.key()), 5008e140a1cSPriyangaRamasamy move(props)); 5018e140a1cSPriyangaRamasamy } 5028e140a1cSPriyangaRamasamy } 5038e140a1cSPriyangaRamasamy } 5048e140a1cSPriyangaRamasamy else if (eI.key().find("Inventory.Item.") != 5058e140a1cSPriyangaRamasamy string::npos) 5068e140a1cSPriyangaRamasamy { 5078e140a1cSPriyangaRamasamy interfaces.emplace(move(eI.key()), move(props)); 5088e140a1cSPriyangaRamasamy } 5098e140a1cSPriyangaRamasamy } 5108e140a1cSPriyangaRamasamy } 5118e140a1cSPriyangaRamasamy objects.emplace(move(object), move(interfaces)); 5128e140a1cSPriyangaRamasamy } 5138e140a1cSPriyangaRamasamy } 5148e140a1cSPriyangaRamasamy } 5158e140a1cSPriyangaRamasamy return objects; 5168e140a1cSPriyangaRamasamy } 5178e140a1cSPriyangaRamasamy 51865b83601SAlpana Kumari /** 51965b83601SAlpana Kumari * @brief This API executes command to set environment variable 52065b83601SAlpana Kumari * And then reboot the system 52165b83601SAlpana Kumari * @param[in] key -env key to set new value 52265b83601SAlpana Kumari * @param[in] value -value to set. 52365b83601SAlpana Kumari */ 52465b83601SAlpana Kumari void setEnvAndReboot(const string& key, const string& value) 52565b83601SAlpana Kumari { 52665b83601SAlpana Kumari // set env and reboot and break. 52765b83601SAlpana Kumari executeCmd("/sbin/fw_setenv", key, value); 528280197e3SAndrew Geissler log<level::INFO>("Rebooting BMC to pick up new device tree"); 52965b83601SAlpana Kumari // make dbus call to reboot 53065b83601SAlpana Kumari auto bus = sdbusplus::bus::new_default_system(); 53165b83601SAlpana Kumari auto method = bus.new_method_call( 53265b83601SAlpana Kumari "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 53365b83601SAlpana Kumari "org.freedesktop.systemd1.Manager", "Reboot"); 53465b83601SAlpana Kumari bus.call_noreply(method); 53565b83601SAlpana Kumari } 53665b83601SAlpana Kumari 53765b83601SAlpana Kumari /* 53865b83601SAlpana Kumari * @brief This API checks for env var fitconfig. 53965b83601SAlpana Kumari * If not initialised OR updated as per the current system type, 54065b83601SAlpana Kumari * update this env var and reboot the system. 54165b83601SAlpana Kumari * 54265b83601SAlpana Kumari * @param[in] systemType IM kwd in vpd tells about which system type it is. 54365b83601SAlpana Kumari * */ 54465b83601SAlpana Kumari void setDevTreeEnv(const string& systemType) 54565b83601SAlpana Kumari { 54665b83601SAlpana Kumari string newDeviceTree; 54765b83601SAlpana Kumari 54865b83601SAlpana Kumari if (deviceTreeSystemTypeMap.find(systemType) != 54965b83601SAlpana Kumari deviceTreeSystemTypeMap.end()) 55065b83601SAlpana Kumari { 55165b83601SAlpana Kumari newDeviceTree = deviceTreeSystemTypeMap.at(systemType); 55265b83601SAlpana Kumari } 55365b83601SAlpana Kumari 55465b83601SAlpana Kumari string readVarValue; 55565b83601SAlpana Kumari bool envVarFound = false; 55665b83601SAlpana Kumari 55765b83601SAlpana Kumari vector<string> output = executeCmd("/sbin/fw_printenv"); 55865b83601SAlpana Kumari for (const auto& entry : output) 55965b83601SAlpana Kumari { 56065b83601SAlpana Kumari size_t pos = entry.find("="); 56165b83601SAlpana Kumari string key = entry.substr(0, pos); 56265b83601SAlpana Kumari if (key != "fitconfig") 56365b83601SAlpana Kumari { 56465b83601SAlpana Kumari continue; 56565b83601SAlpana Kumari } 56665b83601SAlpana Kumari 56765b83601SAlpana Kumari envVarFound = true; 56865b83601SAlpana Kumari if (pos + 1 < entry.size()) 56965b83601SAlpana Kumari { 57065b83601SAlpana Kumari readVarValue = entry.substr(pos + 1); 57165b83601SAlpana Kumari if (readVarValue.find(newDeviceTree) != string::npos) 57265b83601SAlpana Kumari { 57365b83601SAlpana Kumari // fitconfig is Updated. No action needed 57465b83601SAlpana Kumari break; 57565b83601SAlpana Kumari } 57665b83601SAlpana Kumari } 57765b83601SAlpana Kumari // set env and reboot and break. 57865b83601SAlpana Kumari setEnvAndReboot(key, newDeviceTree); 57965b83601SAlpana Kumari exit(0); 58065b83601SAlpana Kumari } 58165b83601SAlpana Kumari 58265b83601SAlpana Kumari // check If env var Not found 58365b83601SAlpana Kumari if (!envVarFound) 58465b83601SAlpana Kumari { 58565b83601SAlpana Kumari setEnvAndReboot("fitconfig", newDeviceTree); 58665b83601SAlpana Kumari } 58765b83601SAlpana Kumari } 58865b83601SAlpana Kumari 5898e140a1cSPriyangaRamasamy /** 5909094d4f6SSunnySrivastava1984 * @brief API to call VPD manager to write VPD to EEPROM. 5919094d4f6SSunnySrivastava1984 * @param[in] Object path. 5929094d4f6SSunnySrivastava1984 * @param[in] record to be updated. 5939094d4f6SSunnySrivastava1984 * @param[in] keyword to be updated. 5949094d4f6SSunnySrivastava1984 * @param[in] keyword data to be updated 5959094d4f6SSunnySrivastava1984 */ 5969094d4f6SSunnySrivastava1984 void updateHardware(const string& objectName, const string& recName, 5979094d4f6SSunnySrivastava1984 const string& kwdName, const Binary& data) 5989094d4f6SSunnySrivastava1984 { 5999094d4f6SSunnySrivastava1984 try 6009094d4f6SSunnySrivastava1984 { 6019094d4f6SSunnySrivastava1984 auto bus = sdbusplus::bus::new_default(); 6029094d4f6SSunnySrivastava1984 auto properties = 6039094d4f6SSunnySrivastava1984 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword"); 6049094d4f6SSunnySrivastava1984 properties.append( 6059094d4f6SSunnySrivastava1984 static_cast<sdbusplus::message::object_path>(objectName)); 6069094d4f6SSunnySrivastava1984 properties.append(recName); 6079094d4f6SSunnySrivastava1984 properties.append(kwdName); 6089094d4f6SSunnySrivastava1984 properties.append(data); 6099094d4f6SSunnySrivastava1984 bus.call(properties); 6109094d4f6SSunnySrivastava1984 } 6119094d4f6SSunnySrivastava1984 catch (const sdbusplus::exception::SdBusError& e) 6129094d4f6SSunnySrivastava1984 { 6139094d4f6SSunnySrivastava1984 std::string what = 6149094d4f6SSunnySrivastava1984 "VPDManager WriteKeyword api failed for inventory path " + 6159094d4f6SSunnySrivastava1984 objectName; 6169094d4f6SSunnySrivastava1984 what += " record " + recName; 6179094d4f6SSunnySrivastava1984 what += " keyword " + kwdName; 6189094d4f6SSunnySrivastava1984 what += " with bus error = " + std::string(e.what()); 6199094d4f6SSunnySrivastava1984 6209094d4f6SSunnySrivastava1984 // map to hold additional data in case of logging pel 6219094d4f6SSunnySrivastava1984 PelAdditionalData additionalData{}; 6229094d4f6SSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", objectName); 6239094d4f6SSunnySrivastava1984 additionalData.emplace("DESCRIPTION", what); 6249094d4f6SSunnySrivastava1984 createPEL(additionalData, errIntfForBusFailure); 6259094d4f6SSunnySrivastava1984 } 6269094d4f6SSunnySrivastava1984 } 6279094d4f6SSunnySrivastava1984 6289094d4f6SSunnySrivastava1984 /** 6299094d4f6SSunnySrivastava1984 * @brief API to check if we need to restore system VPD 6309094d4f6SSunnySrivastava1984 * This functionality is only applicable for IPZ VPD data. 6319094d4f6SSunnySrivastava1984 * @param[in] vpdMap - IPZ vpd map 6329094d4f6SSunnySrivastava1984 * @param[in] objectPath - Object path for the FRU 6339094d4f6SSunnySrivastava1984 * @return EEPROMs with records and keywords updated at standby 6349094d4f6SSunnySrivastava1984 */ 6359094d4f6SSunnySrivastava1984 std::vector<RestoredEeproms> restoreSystemVPD(Parsed& vpdMap, 6369094d4f6SSunnySrivastava1984 const string& objectPath) 6379094d4f6SSunnySrivastava1984 { 6389094d4f6SSunnySrivastava1984 // the list of keywords for VSYS record is as per the S0 system. Should be 6399094d4f6SSunnySrivastava1984 // updated for another type of systems 6409094d4f6SSunnySrivastava1984 static std::unordered_map<std::string, std::vector<std::string>> svpdKwdMap{ 6419094d4f6SSunnySrivastava1984 {"VSYS", {"BR", "TM", "SE", "SU", "RB"}}, 6429094d4f6SSunnySrivastava1984 {"VCEN", {"FC", "SE"}}, 6439094d4f6SSunnySrivastava1984 {"LXR0", {"LX"}}}; 6449094d4f6SSunnySrivastava1984 6459094d4f6SSunnySrivastava1984 // vector to hold all the EEPROMs updated at standby 6469094d4f6SSunnySrivastava1984 std::vector<RestoredEeproms> updatedEeproms = {}; 6479094d4f6SSunnySrivastava1984 6489094d4f6SSunnySrivastava1984 for (const auto& systemRecKwdPair : svpdKwdMap) 6499094d4f6SSunnySrivastava1984 { 6509094d4f6SSunnySrivastava1984 auto it = vpdMap.find(systemRecKwdPair.first); 6519094d4f6SSunnySrivastava1984 6529094d4f6SSunnySrivastava1984 // check if record is found in map we got by parser 6539094d4f6SSunnySrivastava1984 if (it != vpdMap.end()) 6549094d4f6SSunnySrivastava1984 { 6559094d4f6SSunnySrivastava1984 const auto& kwdListForRecord = systemRecKwdPair.second; 6569094d4f6SSunnySrivastava1984 for (const auto& keyword : kwdListForRecord) 6579094d4f6SSunnySrivastava1984 { 6589094d4f6SSunnySrivastava1984 DbusPropertyMap& kwdValMap = it->second; 6599094d4f6SSunnySrivastava1984 auto iterator = kwdValMap.find(keyword); 6609094d4f6SSunnySrivastava1984 6619094d4f6SSunnySrivastava1984 if (iterator != kwdValMap.end()) 6629094d4f6SSunnySrivastava1984 { 6639094d4f6SSunnySrivastava1984 string& kwdValue = iterator->second; 6649094d4f6SSunnySrivastava1984 6659094d4f6SSunnySrivastava1984 // check bus data 6669094d4f6SSunnySrivastava1984 const string& recordName = systemRecKwdPair.first; 6679094d4f6SSunnySrivastava1984 const string& busValue = readBusProperty( 6689094d4f6SSunnySrivastava1984 objectPath, ipzVpdInf + recordName, keyword); 6699094d4f6SSunnySrivastava1984 6709094d4f6SSunnySrivastava1984 if (busValue.find_first_not_of(' ') != string::npos) 6719094d4f6SSunnySrivastava1984 { 6729094d4f6SSunnySrivastava1984 if (kwdValue.find_first_not_of(' ') != string::npos) 6739094d4f6SSunnySrivastava1984 { 6749094d4f6SSunnySrivastava1984 // both the data are present, check for mismatch 6759094d4f6SSunnySrivastava1984 if (busValue != kwdValue) 6769094d4f6SSunnySrivastava1984 { 6779094d4f6SSunnySrivastava1984 string errMsg = "VPD data mismatch on cache " 6789094d4f6SSunnySrivastava1984 "and hardware for record: "; 6799094d4f6SSunnySrivastava1984 errMsg += (*it).first; 6809094d4f6SSunnySrivastava1984 errMsg += " and keyword: "; 6819094d4f6SSunnySrivastava1984 errMsg += keyword; 6829094d4f6SSunnySrivastava1984 6839094d4f6SSunnySrivastava1984 // data mismatch 6849094d4f6SSunnySrivastava1984 PelAdditionalData additionalData; 6859094d4f6SSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 6869094d4f6SSunnySrivastava1984 objectPath); 6879094d4f6SSunnySrivastava1984 6889094d4f6SSunnySrivastava1984 additionalData.emplace("DESCRIPTION", errMsg); 6899094d4f6SSunnySrivastava1984 6909094d4f6SSunnySrivastava1984 createPEL(additionalData, errIntfForInvalidVPD); 6919094d4f6SSunnySrivastava1984 } 6929094d4f6SSunnySrivastava1984 } 6939094d4f6SSunnySrivastava1984 else 6949094d4f6SSunnySrivastava1984 { 6959094d4f6SSunnySrivastava1984 // implies hardware data is blank 6969094d4f6SSunnySrivastava1984 // update the map 6979094d4f6SSunnySrivastava1984 Binary busData(busValue.begin(), busValue.end()); 6989094d4f6SSunnySrivastava1984 6999094d4f6SSunnySrivastava1984 updatedEeproms.push_back(std::make_tuple( 7009094d4f6SSunnySrivastava1984 objectPath, recordName, keyword, busData)); 7019094d4f6SSunnySrivastava1984 } 7029094d4f6SSunnySrivastava1984 7039094d4f6SSunnySrivastava1984 // update the map as well, so that cache data is not 7049094d4f6SSunnySrivastava1984 // updated as blank while populating VPD map on Dbus in 7059094d4f6SSunnySrivastava1984 // populateDBus Api 7069094d4f6SSunnySrivastava1984 kwdValue = busValue; 7079094d4f6SSunnySrivastava1984 continue; 7089094d4f6SSunnySrivastava1984 } 7099094d4f6SSunnySrivastava1984 else if (kwdValue.find_first_not_of(' ') == string::npos) 7109094d4f6SSunnySrivastava1984 { 7119094d4f6SSunnySrivastava1984 string errMsg = "VPD is blank on both cache and " 7129094d4f6SSunnySrivastava1984 "hardware for record: "; 7139094d4f6SSunnySrivastava1984 errMsg += (*it).first; 7149094d4f6SSunnySrivastava1984 errMsg += " and keyword: "; 7159094d4f6SSunnySrivastava1984 errMsg += keyword; 7169094d4f6SSunnySrivastava1984 errMsg += ". SSR need to update hardware VPD."; 7179094d4f6SSunnySrivastava1984 7189094d4f6SSunnySrivastava1984 // both the data are blanks, log PEL 7199094d4f6SSunnySrivastava1984 PelAdditionalData additionalData; 7209094d4f6SSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 7219094d4f6SSunnySrivastava1984 objectPath); 7229094d4f6SSunnySrivastava1984 7239094d4f6SSunnySrivastava1984 additionalData.emplace("DESCRIPTION", errMsg); 7249094d4f6SSunnySrivastava1984 7259094d4f6SSunnySrivastava1984 // log PEL TODO: Block IPL 7269094d4f6SSunnySrivastava1984 createPEL(additionalData, errIntfForBlankSystemVPD); 7279094d4f6SSunnySrivastava1984 continue; 7289094d4f6SSunnySrivastava1984 } 7299094d4f6SSunnySrivastava1984 } 7309094d4f6SSunnySrivastava1984 } 7319094d4f6SSunnySrivastava1984 } 7329094d4f6SSunnySrivastava1984 } 7339094d4f6SSunnySrivastava1984 7349094d4f6SSunnySrivastava1984 return updatedEeproms; 7359094d4f6SSunnySrivastava1984 } 7369094d4f6SSunnySrivastava1984 7379094d4f6SSunnySrivastava1984 /** 7388e140a1cSPriyangaRamasamy * @brief Populate Dbus. 739abb87edaSPriyangaRamasamy * This method invokes all the populateInterface functions 740abb87edaSPriyangaRamasamy * and notifies PIM about dbus object. 7418e140a1cSPriyangaRamasamy * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the 7428e140a1cSPriyangaRamasamy * input. 743abb87edaSPriyangaRamasamy * @param[in] js - Inventory json object 744abb87edaSPriyangaRamasamy * @param[in] filePath - Path of the vpd file 745abb87edaSPriyangaRamasamy * @param[in] preIntrStr - Interface string 746abb87edaSPriyangaRamasamy */ 747abb87edaSPriyangaRamasamy template <typename T> 7489094d4f6SSunnySrivastava1984 static void populateDbus(T& vpdMap, nlohmann::json& js, const string& filePath) 749abb87edaSPriyangaRamasamy { 750abb87edaSPriyangaRamasamy inventory::InterfaceMap interfaces; 751abb87edaSPriyangaRamasamy inventory::ObjectMap objects; 752abb87edaSPriyangaRamasamy inventory::PropertyMap prop; 753abb87edaSPriyangaRamasamy 7549094d4f6SSunnySrivastava1984 // map to hold all the keywords whose value has been changed at standby 7559094d4f6SSunnySrivastava1984 vector<RestoredEeproms> updatedEeproms = {}; 7569094d4f6SSunnySrivastava1984 757e12b181bSSunnySrivastava1984 bool isSystemVpd = false; 758abb87edaSPriyangaRamasamy for (const auto& item : js["frus"][filePath]) 759abb87edaSPriyangaRamasamy { 760abb87edaSPriyangaRamasamy const auto& objectPath = item["inventoryPath"]; 761abb87edaSPriyangaRamasamy sdbusplus::message::object_path object(objectPath); 7628e140a1cSPriyangaRamasamy isSystemVpd = item.value("isSystemVpd", false); 7639094d4f6SSunnySrivastava1984 764abb87edaSPriyangaRamasamy // Populate the VPD keywords and the common interfaces only if we 765abb87edaSPriyangaRamasamy // are asked to inherit that data from the VPD, else only add the 766abb87edaSPriyangaRamasamy // extraInterfaces. 767abb87edaSPriyangaRamasamy if (item.value("inherit", true)) 768abb87edaSPriyangaRamasamy { 76958e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 770abb87edaSPriyangaRamasamy { 7719094d4f6SSunnySrivastava1984 if (isSystemVpd) 7729094d4f6SSunnySrivastava1984 { 7739094d4f6SSunnySrivastava1984 std::vector<std::string> interfaces = { 7749094d4f6SSunnySrivastava1984 motherBoardInterface}; 7759094d4f6SSunnySrivastava1984 // call mapper to check for object path creation 7769094d4f6SSunnySrivastava1984 MapperResponse subTree = 7779094d4f6SSunnySrivastava1984 getObjectSubtreeForInterfaces(pimPath, 0, interfaces); 7789094d4f6SSunnySrivastava1984 7799094d4f6SSunnySrivastava1984 // Skip system vpd restore if object path is not generated 7809094d4f6SSunnySrivastava1984 // for motherboard, Implies first boot. 7819094d4f6SSunnySrivastava1984 if (subTree.size() != 0) 7829094d4f6SSunnySrivastava1984 { 7839094d4f6SSunnySrivastava1984 assert( 7849094d4f6SSunnySrivastava1984 (subTree.find(pimPath + std::string(objectPath)) != 7859094d4f6SSunnySrivastava1984 subTree.end())); 7869094d4f6SSunnySrivastava1984 7879094d4f6SSunnySrivastava1984 updatedEeproms = restoreSystemVPD(vpdMap, objectPath); 7889094d4f6SSunnySrivastava1984 } 7899094d4f6SSunnySrivastava1984 else 7909094d4f6SSunnySrivastava1984 { 7919094d4f6SSunnySrivastava1984 log<level::ERR>("No object path found"); 7929094d4f6SSunnySrivastava1984 } 7939094d4f6SSunnySrivastava1984 } 7949094d4f6SSunnySrivastava1984 7958e140a1cSPriyangaRamasamy // Each record in the VPD becomes an interface and all 7968e140a1cSPriyangaRamasamy // keyword within the record are properties under that 7978e140a1cSPriyangaRamasamy // interface. 798abb87edaSPriyangaRamasamy for (const auto& record : vpdMap) 799abb87edaSPriyangaRamasamy { 800abb87edaSPriyangaRamasamy populateFruSpecificInterfaces( 801e12b181bSSunnySrivastava1984 record.second, ipzVpdInf + record.first, interfaces); 802abb87edaSPriyangaRamasamy } 803abb87edaSPriyangaRamasamy } 80458e22145SAlpana Kumari else if constexpr (is_same<T, KeywordVpdMap>::value) 805abb87edaSPriyangaRamasamy { 806e12b181bSSunnySrivastava1984 populateFruSpecificInterfaces(vpdMap, kwdVpdInf, interfaces); 807abb87edaSPriyangaRamasamy } 80888edeb6fSSantosh Puranik if (js.find("commonInterfaces") != js.end()) 80988edeb6fSSantosh Puranik { 81088edeb6fSSantosh Puranik populateInterfaces(js["commonInterfaces"], interfaces, vpdMap, 81188edeb6fSSantosh Puranik isSystemVpd); 81288edeb6fSSantosh Puranik } 813abb87edaSPriyangaRamasamy } 8140859eb65SSantosh Puranik else 8150859eb65SSantosh Puranik { 8160859eb65SSantosh Puranik // Check if we have been asked to inherit specific record(s) 81758e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 8180859eb65SSantosh Puranik { 8190859eb65SSantosh Puranik if (item.find("copyRecords") != item.end()) 8200859eb65SSantosh Puranik { 8210859eb65SSantosh Puranik for (const auto& record : item["copyRecords"]) 8220859eb65SSantosh Puranik { 8230859eb65SSantosh Puranik const string& recordName = record; 8240859eb65SSantosh Puranik if (vpdMap.find(recordName) != vpdMap.end()) 8250859eb65SSantosh Puranik { 8260859eb65SSantosh Puranik populateFruSpecificInterfaces( 827e12b181bSSunnySrivastava1984 vpdMap.at(recordName), ipzVpdInf + recordName, 8280859eb65SSantosh Puranik interfaces); 8290859eb65SSantosh Puranik } 8300859eb65SSantosh Puranik } 8310859eb65SSantosh Puranik } 8320859eb65SSantosh Puranik } 8330859eb65SSantosh Puranik } 83458e22145SAlpana Kumari if (item.value("inheritEI", true)) 83558e22145SAlpana Kumari { 836abb87edaSPriyangaRamasamy // Populate interfaces and properties that are common to every FRU 8378e140a1cSPriyangaRamasamy // and additional interface that might be defined on a per-FRU 8388e140a1cSPriyangaRamasamy // basis. 839abb87edaSPriyangaRamasamy if (item.find("extraInterfaces") != item.end()) 840abb87edaSPriyangaRamasamy { 84188edeb6fSSantosh Puranik populateInterfaces(item["extraInterfaces"], interfaces, vpdMap, 84288edeb6fSSantosh Puranik isSystemVpd); 843abb87edaSPriyangaRamasamy } 84458e22145SAlpana Kumari } 845abb87edaSPriyangaRamasamy objects.emplace(move(object), move(interfaces)); 846abb87edaSPriyangaRamasamy } 847abb87edaSPriyangaRamasamy 8488e140a1cSPriyangaRamasamy if (isSystemVpd) 8498e140a1cSPriyangaRamasamy { 85083a1d5deSPriyangaRamasamy vector<uint8_t> imVal; 85183a1d5deSPriyangaRamasamy if constexpr (is_same<T, Parsed>::value) 85283a1d5deSPriyangaRamasamy { 85383a1d5deSPriyangaRamasamy auto property = vpdMap.find("VSBP"); 85483a1d5deSPriyangaRamasamy if (property != vpdMap.end()) 85583a1d5deSPriyangaRamasamy { 85683a1d5deSPriyangaRamasamy auto value = (property->second).find("IM"); 85783a1d5deSPriyangaRamasamy if (value != (property->second).end()) 85883a1d5deSPriyangaRamasamy { 85983a1d5deSPriyangaRamasamy copy(value->second.begin(), value->second.end(), 86083a1d5deSPriyangaRamasamy back_inserter(imVal)); 86183a1d5deSPriyangaRamasamy } 86283a1d5deSPriyangaRamasamy } 86383a1d5deSPriyangaRamasamy } 86483a1d5deSPriyangaRamasamy 86583a1d5deSPriyangaRamasamy fs::path target; 86683a1d5deSPriyangaRamasamy fs::path link = INVENTORY_JSON_SYM_LINK; 86783a1d5deSPriyangaRamasamy 86883a1d5deSPriyangaRamasamy ostringstream oss; 86983a1d5deSPriyangaRamasamy for (auto& i : imVal) 87083a1d5deSPriyangaRamasamy { 87183a1d5deSPriyangaRamasamy oss << setw(2) << setfill('0') << hex << static_cast<int>(i); 87283a1d5deSPriyangaRamasamy } 87383a1d5deSPriyangaRamasamy string imValStr = oss.str(); 87483a1d5deSPriyangaRamasamy 875*7c9cddf7SAndrew Geissler if ((imValStr == RAINIER_4U) || // 4U 876*7c9cddf7SAndrew Geissler (imValStr == RAINIER_1S4U)) 87783a1d5deSPriyangaRamasamy { 87883a1d5deSPriyangaRamasamy target = INVENTORY_JSON_4U; 87983a1d5deSPriyangaRamasamy } 88065b83601SAlpana Kumari else if (imValStr == RAINIER_2U) // 2U 88183a1d5deSPriyangaRamasamy { 88283a1d5deSPriyangaRamasamy target = INVENTORY_JSON_2U; 88383a1d5deSPriyangaRamasamy } 8844641bff5SSantosh Puranik else if (imValStr == EVEREST) 8854641bff5SSantosh Puranik { 8864641bff5SSantosh Puranik target = INVENTORY_JSON_EVEREST; 8874641bff5SSantosh Puranik } 88883a1d5deSPriyangaRamasamy 8890246a4d7SSantosh Puranik // Create the directory for hosting the symlink 8900246a4d7SSantosh Puranik fs::create_directories(VPD_FILES_PATH); 8910246a4d7SSantosh Puranik // unlink the symlink previously created (if any) 89283a1d5deSPriyangaRamasamy remove(INVENTORY_JSON_SYM_LINK); 89383a1d5deSPriyangaRamasamy // create a new symlink based on the system 89483a1d5deSPriyangaRamasamy fs::create_symlink(target, link); 89583a1d5deSPriyangaRamasamy 89683a1d5deSPriyangaRamasamy // Reloading the json 89783a1d5deSPriyangaRamasamy ifstream inventoryJson(link); 89883a1d5deSPriyangaRamasamy auto js = json::parse(inventoryJson); 89983a1d5deSPriyangaRamasamy inventoryJson.close(); 90083a1d5deSPriyangaRamasamy 9018e140a1cSPriyangaRamasamy inventory::ObjectMap primeObject = primeInventory(js, vpdMap); 9028e140a1cSPriyangaRamasamy objects.insert(primeObject.begin(), primeObject.end()); 90365b83601SAlpana Kumari 90465b83601SAlpana Kumari // set the U-boot environment variable for device-tree 90565b83601SAlpana Kumari setDevTreeEnv(imValStr); 9069094d4f6SSunnySrivastava1984 9079094d4f6SSunnySrivastava1984 // if system VPD has been restored at standby, update the EEPROM 9089094d4f6SSunnySrivastava1984 for (const auto& item : updatedEeproms) 9099094d4f6SSunnySrivastava1984 { 9109094d4f6SSunnySrivastava1984 updateHardware(get<0>(item), get<1>(item), get<2>(item), 9119094d4f6SSunnySrivastava1984 get<3>(item)); 9129094d4f6SSunnySrivastava1984 } 9138e140a1cSPriyangaRamasamy } 9148e140a1cSPriyangaRamasamy 915abb87edaSPriyangaRamasamy // Notify PIM 916abb87edaSPriyangaRamasamy inventory::callPIM(move(objects)); 917abb87edaSPriyangaRamasamy } 918abb87edaSPriyangaRamasamy 919abb87edaSPriyangaRamasamy int main(int argc, char** argv) 920abb87edaSPriyangaRamasamy { 921abb87edaSPriyangaRamasamy int rc = 0; 922a20be8ecSSunnySrivastava1984 string file{}; 923a20be8ecSSunnySrivastava1984 json js{}; 924a20be8ecSSunnySrivastava1984 925a20be8ecSSunnySrivastava1984 // map to hold additional data in case of logging pel 926a20be8ecSSunnySrivastava1984 PelAdditionalData additionalData{}; 927a20be8ecSSunnySrivastava1984 928a20be8ecSSunnySrivastava1984 // this is needed to hold base fru inventory path in case there is ECC or 929a20be8ecSSunnySrivastava1984 // vpd exception while parsing the file 930a20be8ecSSunnySrivastava1984 std::string baseFruInventoryPath = {}; 931abb87edaSPriyangaRamasamy 932abb87edaSPriyangaRamasamy try 933abb87edaSPriyangaRamasamy { 934abb87edaSPriyangaRamasamy App app{"ibm-read-vpd - App to read IPZ format VPD, parse it and store " 935abb87edaSPriyangaRamasamy "in DBUS"}; 936abb87edaSPriyangaRamasamy string file{}; 937abb87edaSPriyangaRamasamy 938abb87edaSPriyangaRamasamy app.add_option("-f, --file", file, "File containing VPD (IPZ/KEYWORD)") 9392f793048SAlpana Kumari ->required(); 940abb87edaSPriyangaRamasamy 941abb87edaSPriyangaRamasamy CLI11_PARSE(app, argc, argv); 942abb87edaSPriyangaRamasamy 9430246a4d7SSantosh Puranik auto jsonToParse = INVENTORY_JSON_DEFAULT; 9440246a4d7SSantosh Puranik 9450246a4d7SSantosh Puranik // If the symlink exists, it means it has been setup for us, switch the 9460246a4d7SSantosh Puranik // path 9470246a4d7SSantosh Puranik if (fs::exists(INVENTORY_JSON_SYM_LINK)) 9480246a4d7SSantosh Puranik { 9490246a4d7SSantosh Puranik jsonToParse = INVENTORY_JSON_SYM_LINK; 9500246a4d7SSantosh Puranik } 9510246a4d7SSantosh Puranik 952abb87edaSPriyangaRamasamy // Make sure that the file path we get is for a supported EEPROM 9530246a4d7SSantosh Puranik ifstream inventoryJson(jsonToParse); 954a20be8ecSSunnySrivastava1984 if (!inventoryJson) 955a20be8ecSSunnySrivastava1984 { 956a20be8ecSSunnySrivastava1984 throw( 957a20be8ecSSunnySrivastava1984 (VpdJsonException("Failed to access Json path", jsonToParse))); 958a20be8ecSSunnySrivastava1984 } 959a20be8ecSSunnySrivastava1984 960a20be8ecSSunnySrivastava1984 try 961a20be8ecSSunnySrivastava1984 { 962a20be8ecSSunnySrivastava1984 js = json::parse(inventoryJson); 963a20be8ecSSunnySrivastava1984 } 964a20be8ecSSunnySrivastava1984 catch (json::parse_error& ex) 965a20be8ecSSunnySrivastava1984 { 966a20be8ecSSunnySrivastava1984 throw((VpdJsonException("Json parsing failed", jsonToParse))); 967a20be8ecSSunnySrivastava1984 } 968abb87edaSPriyangaRamasamy 969abb87edaSPriyangaRamasamy if ((js.find("frus") == js.end()) || 970abb87edaSPriyangaRamasamy (js["frus"].find(file) == js["frus"].end())) 971abb87edaSPriyangaRamasamy { 97258e22145SAlpana Kumari cout << "Device path not in JSON, ignoring" << endl; 97388edeb6fSSantosh Puranik return 0; 974abb87edaSPriyangaRamasamy } 975abb87edaSPriyangaRamasamy 9762f793048SAlpana Kumari if (!fs::exists(file)) 9772f793048SAlpana Kumari { 9782f793048SAlpana Kumari cout << "Device path: " << file 9792f793048SAlpana Kumari << " does not exist. Spurious udev event? Exiting." << endl; 9802f793048SAlpana Kumari return 0; 9812f793048SAlpana Kumari } 9822f793048SAlpana Kumari 983a20be8ecSSunnySrivastava1984 baseFruInventoryPath = js["frus"][file][0]["inventoryPath"]; 9848589375fSSantosh Puranik // Check if we can read the VPD file based on the power state 9858589375fSSantosh Puranik if (js["frus"][file].at(0).value("powerOffOnly", false)) 9868589375fSSantosh Puranik { 9878589375fSSantosh Puranik if ("xyz.openbmc_project.State.Chassis.PowerState.On" == 9888589375fSSantosh Puranik getPowerState()) 9898589375fSSantosh Puranik { 9908589375fSSantosh Puranik cout << "This VPD cannot be read when power is ON" << endl; 9918589375fSSantosh Puranik return 0; 9928589375fSSantosh Puranik } 9938589375fSSantosh Puranik } 994a20be8ecSSunnySrivastava1984 9952f793048SAlpana Kumari try 9962f793048SAlpana Kumari { 9972f793048SAlpana Kumari Binary vpdVector = getVpdDataInVector(js, file); 9982f793048SAlpana Kumari ParserInterface* parser = ParserFactory::getParser(move(vpdVector)); 9992f793048SAlpana Kumari 10002f793048SAlpana Kumari variant<KeywordVpdMap, Store> parseResult; 10012f793048SAlpana Kumari parseResult = parser->parse(); 1002e12b181bSSunnySrivastava1984 if (auto pVal = get_if<Store>(&parseResult)) 1003abb87edaSPriyangaRamasamy { 1004e12b181bSSunnySrivastava1984 populateDbus(pVal->getVpdMap(), js, file); 1005e12b181bSSunnySrivastava1984 } 1006e12b181bSSunnySrivastava1984 else if (auto pVal = get_if<KeywordVpdMap>(&parseResult)) 1007abb87edaSPriyangaRamasamy { 1008e12b181bSSunnySrivastava1984 populateDbus(*pVal, js, file); 1009abb87edaSPriyangaRamasamy } 1010abb87edaSPriyangaRamasamy 1011e12b181bSSunnySrivastava1984 // release the parser object 1012e12b181bSSunnySrivastava1984 ParserFactory::freeParser(parser); 1013abb87edaSPriyangaRamasamy } 10142f793048SAlpana Kumari catch (exception& e) 10152f793048SAlpana Kumari { 10162f793048SAlpana Kumari postFailAction(js, file); 10172f793048SAlpana Kumari throw e; 10182f793048SAlpana Kumari } 10192f793048SAlpana Kumari } 1020a20be8ecSSunnySrivastava1984 catch (const VpdJsonException& ex) 1021a20be8ecSSunnySrivastava1984 { 1022a20be8ecSSunnySrivastava1984 additionalData.emplace("JSON_PATH", ex.getJsonPath()); 1023a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", ex.what()); 1024a20be8ecSSunnySrivastava1984 createPEL(additionalData, errIntfForJsonFailure); 1025a20be8ecSSunnySrivastava1984 1026a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 1027a20be8ecSSunnySrivastava1984 rc = -1; 1028a20be8ecSSunnySrivastava1984 } 1029a20be8ecSSunnySrivastava1984 catch (const VpdEccException& ex) 1030a20be8ecSSunnySrivastava1984 { 1031a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", "ECC check failed"); 1032a20be8ecSSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 1033a20be8ecSSunnySrivastava1984 INVENTORY_PATH + baseFruInventoryPath); 1034a20be8ecSSunnySrivastava1984 createPEL(additionalData, errIntfForEccCheckFail); 1035a20be8ecSSunnySrivastava1984 1036a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 1037a20be8ecSSunnySrivastava1984 rc = -1; 1038a20be8ecSSunnySrivastava1984 } 1039a20be8ecSSunnySrivastava1984 catch (const VpdDataException& ex) 1040a20be8ecSSunnySrivastava1984 { 1041a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", "Invalid VPD data"); 1042a20be8ecSSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 1043a20be8ecSSunnySrivastava1984 INVENTORY_PATH + baseFruInventoryPath); 1044a20be8ecSSunnySrivastava1984 createPEL(additionalData, errIntfForInvalidVPD); 1045a20be8ecSSunnySrivastava1984 1046a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 1047a20be8ecSSunnySrivastava1984 rc = -1; 1048a20be8ecSSunnySrivastava1984 } 1049abb87edaSPriyangaRamasamy catch (exception& e) 1050abb87edaSPriyangaRamasamy { 1051abb87edaSPriyangaRamasamy cerr << e.what() << "\n"; 1052abb87edaSPriyangaRamasamy rc = -1; 1053abb87edaSPriyangaRamasamy } 1054abb87edaSPriyangaRamasamy 1055abb87edaSPriyangaRamasamy return rc; 1056abb87edaSPriyangaRamasamy } 1057