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> 177ce68724Salpana07 #include <boost/algorithm/string.hpp> 1865b83601SAlpana Kumari #include <cstdarg> 19abb87edaSPriyangaRamasamy #include <exception> 2083a1d5deSPriyangaRamasamy #include <filesystem> 21abb87edaSPriyangaRamasamy #include <fstream> 222f793048SAlpana Kumari #include <gpiod.hpp> 23abb87edaSPriyangaRamasamy #include <iostream> 24abb87edaSPriyangaRamasamy #include <iterator> 25abb87edaSPriyangaRamasamy #include <nlohmann/json.hpp> 26280197e3SAndrew Geissler #include <phosphor-logging/log.hpp> 277ce68724Salpana07 #include <regex> 28abb87edaSPriyangaRamasamy 29abb87edaSPriyangaRamasamy using namespace std; 30abb87edaSPriyangaRamasamy using namespace openpower::vpd; 31abb87edaSPriyangaRamasamy using namespace CLI; 32abb87edaSPriyangaRamasamy using namespace vpd::keyword::parser; 3383a1d5deSPriyangaRamasamy using namespace openpower::vpd::constants; 3483a1d5deSPriyangaRamasamy namespace fs = filesystem; 3583a1d5deSPriyangaRamasamy using json = nlohmann::json; 36e12b181bSSunnySrivastava1984 using namespace openpower::vpd::parser::factory; 37945a02d3SSunnySrivastava1984 using namespace openpower::vpd::inventory; 38a00936f8SAlpana Kumari using namespace openpower::vpd::memory::parser; 39e12b181bSSunnySrivastava1984 using namespace openpower::vpd::parser::interface; 40a20be8ecSSunnySrivastava1984 using namespace openpower::vpd::exceptions; 41280197e3SAndrew Geissler using namespace phosphor::logging; 42abb87edaSPriyangaRamasamy 433c24414fSSunny Srivastava // Map to hold record, kwd pair which can be re-stored at standby. 443c24414fSSunny Srivastava // The list of keywords for VSYS record is as per the S0 system. Should 453c24414fSSunny Srivastava // be updated for another type of systems 463c24414fSSunny Srivastava static const std::unordered_map<std::string, std::vector<std::string>> 4701e6c635SSunny Srivastava svpdKwdMap{{"VSYS", {"BR", "TM", "SE", "SU", "RB", "WN"}}, 483c24414fSSunny Srivastava {"VCEN", {"FC", "SE"}}, 493c24414fSSunny Srivastava {"LXR0", {"LX"}}}; 503c24414fSSunny Srivastava 5188edeb6fSSantosh Puranik /** 528589375fSSantosh Puranik * @brief Returns the power state for chassis0 538589375fSSantosh Puranik */ 548589375fSSantosh Puranik static auto getPowerState() 558589375fSSantosh Puranik { 568589375fSSantosh Puranik // TODO: How do we handle multiple chassis? 578589375fSSantosh Puranik string powerState{}; 588589375fSSantosh Puranik auto bus = sdbusplus::bus::new_default(); 598589375fSSantosh Puranik auto properties = 608589375fSSantosh Puranik bus.new_method_call("xyz.openbmc_project.State.Chassis", 618589375fSSantosh Puranik "/xyz/openbmc_project/state/chassis0", 628589375fSSantosh Puranik "org.freedesktop.DBus.Properties", "Get"); 638589375fSSantosh Puranik properties.append("xyz.openbmc_project.State.Chassis"); 648589375fSSantosh Puranik properties.append("CurrentPowerState"); 658589375fSSantosh Puranik auto result = bus.call(properties); 668589375fSSantosh Puranik if (!result.is_method_error()) 678589375fSSantosh Puranik { 688589375fSSantosh Puranik variant<string> val; 698589375fSSantosh Puranik result.read(val); 708589375fSSantosh Puranik if (auto pVal = get_if<string>(&val)) 718589375fSSantosh Puranik { 728589375fSSantosh Puranik powerState = *pVal; 738589375fSSantosh Puranik } 748589375fSSantosh Puranik } 758589375fSSantosh Puranik cout << "Power state is: " << powerState << endl; 768589375fSSantosh Puranik return powerState; 778589375fSSantosh Puranik } 788589375fSSantosh Puranik 798589375fSSantosh Puranik /** 80e9c57535SSantosh Puranik * @brief Returns the BMC state 81e9c57535SSantosh Puranik */ 82e9c57535SSantosh Puranik static auto getBMCState() 83e9c57535SSantosh Puranik { 84e9c57535SSantosh Puranik std::string bmcState; 85e9c57535SSantosh Puranik try 86e9c57535SSantosh Puranik { 87e9c57535SSantosh Puranik auto bus = sdbusplus::bus::new_default(); 88e9c57535SSantosh Puranik auto properties = bus.new_method_call( 89e9c57535SSantosh Puranik "xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0", 90e9c57535SSantosh Puranik "org.freedesktop.DBus.Properties", "Get"); 91e9c57535SSantosh Puranik properties.append("xyz.openbmc_project.State.BMC"); 92e9c57535SSantosh Puranik properties.append("CurrentBMCState"); 93e9c57535SSantosh Puranik auto result = bus.call(properties); 94e9c57535SSantosh Puranik std::variant<std::string> val; 95e9c57535SSantosh Puranik result.read(val); 96e9c57535SSantosh Puranik if (auto pVal = std::get_if<std::string>(&val)) 97e9c57535SSantosh Puranik { 98e9c57535SSantosh Puranik bmcState = *pVal; 99e9c57535SSantosh Puranik } 100e9c57535SSantosh Puranik } 101e9c57535SSantosh Puranik catch (const sdbusplus::exception::SdBusError& e) 102e9c57535SSantosh Puranik { 103e9c57535SSantosh Puranik // Ignore any error 104e9c57535SSantosh Puranik std::cerr << "Failed to get BMC state: " << e.what() << "\n"; 105e9c57535SSantosh Puranik } 106e9c57535SSantosh Puranik return bmcState; 107e9c57535SSantosh Puranik } 108e9c57535SSantosh Puranik 109e9c57535SSantosh Puranik /** 110e9c57535SSantosh Puranik * @brief Check if the FRU is in the cache 111e9c57535SSantosh Puranik * 112e9c57535SSantosh Puranik * Checks if the FRU associated with the supplied D-Bus object path is already 113e9c57535SSantosh Puranik * on D-Bus. This can be used to test if a VPD collection is required for this 114e9c57535SSantosh Puranik * FRU. It uses the "xyz.openbmc_project.Inventory.Item, Present" property to 115e9c57535SSantosh Puranik * determine the presence of a FRU in the cache. 116e9c57535SSantosh Puranik * 117e9c57535SSantosh Puranik * @param objectPath - The D-Bus object path without the PIM prefix. 118e9c57535SSantosh Puranik * @return true if the object exists on D-Bus, false otherwise. 119e9c57535SSantosh Puranik */ 120e9c57535SSantosh Puranik static auto isFruInVpdCache(const std::string& objectPath) 121e9c57535SSantosh Puranik { 122e9c57535SSantosh Puranik try 123e9c57535SSantosh Puranik { 124e9c57535SSantosh Puranik auto bus = sdbusplus::bus::new_default(); 125e9c57535SSantosh Puranik auto invPath = std::string{pimPath} + objectPath; 126e9c57535SSantosh Puranik auto props = bus.new_method_call( 127e9c57535SSantosh Puranik "xyz.openbmc_project.Inventory.Manager", invPath.c_str(), 128e9c57535SSantosh Puranik "org.freedesktop.DBus.Properties", "Get"); 129e9c57535SSantosh Puranik props.append("xyz.openbmc_project.Inventory.Item"); 130e9c57535SSantosh Puranik props.append("Present"); 131e9c57535SSantosh Puranik auto result = bus.call(props); 132e9c57535SSantosh Puranik std::variant<bool> present; 133e9c57535SSantosh Puranik result.read(present); 134e9c57535SSantosh Puranik if (auto pVal = std::get_if<bool>(&present)) 135e9c57535SSantosh Puranik { 136e9c57535SSantosh Puranik return *pVal; 137e9c57535SSantosh Puranik } 138e9c57535SSantosh Puranik return false; 139e9c57535SSantosh Puranik } 140e9c57535SSantosh Puranik catch (const sdbusplus::exception::SdBusError& e) 141e9c57535SSantosh Puranik { 142e9c57535SSantosh Puranik std::cout << "FRU: " << objectPath << " not in D-Bus\n"; 143e9c57535SSantosh Puranik // Assume not present in case of an error 144e9c57535SSantosh Puranik return false; 145e9c57535SSantosh Puranik } 146e9c57535SSantosh Puranik } 147e9c57535SSantosh Puranik 148e9c57535SSantosh Puranik /** 149e9c57535SSantosh Puranik * @brief Check if VPD recollection is needed for the given EEPROM 150e9c57535SSantosh Puranik * 151e9c57535SSantosh Puranik * Not all FRUs can be swapped at BMC ready state. This function does the 152e9c57535SSantosh Puranik * following: 153e9c57535SSantosh Puranik * -- Check if the FRU is marked as "pluggableAtStandby" OR 154e9c57535SSantosh Puranik * "concurrentlyMaintainable". If so, return true. 155e9c57535SSantosh Puranik * -- Check if we are at BMC NotReady state. If we are, then return true. 156e9c57535SSantosh Puranik * -- Else check if the FRU is not present in the VPD cache (to cover for VPD 157e9c57535SSantosh Puranik * force collection). If not found in the cache, return true. 158e9c57535SSantosh Puranik * -- Else return false. 159e9c57535SSantosh Puranik * 160e9c57535SSantosh Puranik * @param js - JSON Object. 161e9c57535SSantosh Puranik * @param filePath - The EEPROM file. 162e9c57535SSantosh Puranik * @return true if collection should be attempted, false otherwise. 163e9c57535SSantosh Puranik */ 164e9c57535SSantosh Puranik static auto needsRecollection(const nlohmann::json& js, const string& filePath) 165e9c57535SSantosh Puranik { 166e9c57535SSantosh Puranik if (js["frus"][filePath].at(0).value("pluggableAtStandby", false) || 167e9c57535SSantosh Puranik js["frus"][filePath].at(0).value("concurrentlyMaintainable", false)) 168e9c57535SSantosh Puranik { 169e9c57535SSantosh Puranik return true; 170e9c57535SSantosh Puranik } 171e9c57535SSantosh Puranik if (getBMCState() == "xyz.openbmc_project.State.BMC.BMCState.NotReady") 172e9c57535SSantosh Puranik { 173e9c57535SSantosh Puranik return true; 174e9c57535SSantosh Puranik } 175e9c57535SSantosh Puranik if (!isFruInVpdCache(js["frus"][filePath].at(0).value("inventoryPath", ""))) 176e9c57535SSantosh Puranik { 177e9c57535SSantosh Puranik return true; 178e9c57535SSantosh Puranik } 179e9c57535SSantosh Puranik return false; 180e9c57535SSantosh Puranik } 181e9c57535SSantosh Puranik 182e9c57535SSantosh Puranik /** 18388edeb6fSSantosh Puranik * @brief Expands location codes 18488edeb6fSSantosh Puranik */ 18588edeb6fSSantosh Puranik static auto expandLocationCode(const string& unexpanded, const Parsed& vpdMap, 18688edeb6fSSantosh Puranik bool isSystemVpd) 18788edeb6fSSantosh Puranik { 18888edeb6fSSantosh Puranik auto expanded{unexpanded}; 18988edeb6fSSantosh Puranik static constexpr auto SYSTEM_OBJECT = "/system/chassis/motherboard"; 19088edeb6fSSantosh Puranik static constexpr auto VCEN_IF = "com.ibm.ipzvpd.VCEN"; 19188edeb6fSSantosh Puranik static constexpr auto VSYS_IF = "com.ibm.ipzvpd.VSYS"; 19288edeb6fSSantosh Puranik size_t idx = expanded.find("fcs"); 19388edeb6fSSantosh Puranik try 19488edeb6fSSantosh Puranik { 19588edeb6fSSantosh Puranik if (idx != string::npos) 19688edeb6fSSantosh Puranik { 19788edeb6fSSantosh Puranik string fc{}; 19888edeb6fSSantosh Puranik string se{}; 19988edeb6fSSantosh Puranik if (isSystemVpd) 20088edeb6fSSantosh Puranik { 20188edeb6fSSantosh Puranik const auto& fcData = vpdMap.at("VCEN").at("FC"); 20288edeb6fSSantosh Puranik const auto& seData = vpdMap.at("VCEN").at("SE"); 20388edeb6fSSantosh Puranik fc = string(fcData.data(), fcData.size()); 20488edeb6fSSantosh Puranik se = string(seData.data(), seData.size()); 20588edeb6fSSantosh Puranik } 20688edeb6fSSantosh Puranik else 20788edeb6fSSantosh Puranik { 20888edeb6fSSantosh Puranik fc = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "FC"); 20988edeb6fSSantosh Puranik se = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "SE"); 21088edeb6fSSantosh Puranik } 21188edeb6fSSantosh Puranik 21281671f6dSAlpana Kumari // TODO: See if ND0 can be placed in the JSON 21381671f6dSAlpana Kumari expanded.replace(idx, 3, fc.substr(0, 4) + ".ND0." + se); 21488edeb6fSSantosh Puranik } 21588edeb6fSSantosh Puranik else 21688edeb6fSSantosh Puranik { 21788edeb6fSSantosh Puranik idx = expanded.find("mts"); 21888edeb6fSSantosh Puranik if (idx != string::npos) 21988edeb6fSSantosh Puranik { 22088edeb6fSSantosh Puranik string mt{}; 22188edeb6fSSantosh Puranik string se{}; 22288edeb6fSSantosh Puranik if (isSystemVpd) 22388edeb6fSSantosh Puranik { 22488edeb6fSSantosh Puranik const auto& mtData = vpdMap.at("VSYS").at("TM"); 22588edeb6fSSantosh Puranik const auto& seData = vpdMap.at("VSYS").at("SE"); 22688edeb6fSSantosh Puranik mt = string(mtData.data(), mtData.size()); 22788edeb6fSSantosh Puranik se = string(seData.data(), seData.size()); 22888edeb6fSSantosh Puranik } 22988edeb6fSSantosh Puranik else 23088edeb6fSSantosh Puranik { 23188edeb6fSSantosh Puranik mt = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "TM"); 23288edeb6fSSantosh Puranik se = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "SE"); 23388edeb6fSSantosh Puranik } 23488edeb6fSSantosh Puranik 23588edeb6fSSantosh Puranik replace(mt.begin(), mt.end(), '-', '.'); 23688edeb6fSSantosh Puranik expanded.replace(idx, 3, mt + "." + se); 23788edeb6fSSantosh Puranik } 23888edeb6fSSantosh Puranik } 23988edeb6fSSantosh Puranik } 2408e15b93aSPatrick Williams catch (const exception& e) 24188edeb6fSSantosh Puranik { 24258e22145SAlpana Kumari cerr << "Failed to expand location code with exception: " << e.what() 24358e22145SAlpana Kumari << "\n"; 24488edeb6fSSantosh Puranik } 24588edeb6fSSantosh Puranik return expanded; 24688edeb6fSSantosh Puranik } 2472f793048SAlpana Kumari 248abb87edaSPriyangaRamasamy /** 249abb87edaSPriyangaRamasamy * @brief Populate FRU specific interfaces. 250abb87edaSPriyangaRamasamy * 251abb87edaSPriyangaRamasamy * This is a common method which handles both 252abb87edaSPriyangaRamasamy * ipz and keyword specific interfaces thus, 253abb87edaSPriyangaRamasamy * reducing the code redundancy. 254abb87edaSPriyangaRamasamy * @param[in] map - Reference to the innermost keyword-value map. 255abb87edaSPriyangaRamasamy * @param[in] preIntrStr - Reference to the interface string. 256abb87edaSPriyangaRamasamy * @param[out] interfaces - Reference to interface map. 257abb87edaSPriyangaRamasamy */ 258abb87edaSPriyangaRamasamy template <typename T> 259abb87edaSPriyangaRamasamy static void populateFruSpecificInterfaces(const T& map, 260abb87edaSPriyangaRamasamy const string& preIntrStr, 261abb87edaSPriyangaRamasamy inventory::InterfaceMap& interfaces) 262abb87edaSPriyangaRamasamy { 263abb87edaSPriyangaRamasamy inventory::PropertyMap prop; 264abb87edaSPriyangaRamasamy 265abb87edaSPriyangaRamasamy for (const auto& kwVal : map) 266abb87edaSPriyangaRamasamy { 267abb87edaSPriyangaRamasamy auto kw = kwVal.first; 268abb87edaSPriyangaRamasamy 269abb87edaSPriyangaRamasamy if (kw[0] == '#') 270abb87edaSPriyangaRamasamy { 27158e22145SAlpana Kumari kw = string("PD_") + kw[1]; 272abb87edaSPriyangaRamasamy } 2738ea3f6d0SAlpana Kumari else if (isdigit(kw[0])) 2748ea3f6d0SAlpana Kumari { 27558e22145SAlpana Kumari kw = string("N_") + kw; 2768ea3f6d0SAlpana Kumari } 2773ab26a74SAlpana Kumari if constexpr (is_same<T, KeywordVpdMap>::value) 2783ab26a74SAlpana Kumari { 2793ab26a74SAlpana Kumari if (get_if<Binary>(&kwVal.second)) 2803ab26a74SAlpana Kumari { 2813ab26a74SAlpana Kumari Binary vec(get_if<Binary>(&kwVal.second)->begin(), 2823ab26a74SAlpana Kumari get_if<Binary>(&kwVal.second)->end()); 283abb87edaSPriyangaRamasamy prop.emplace(move(kw), move(vec)); 284abb87edaSPriyangaRamasamy } 2853ab26a74SAlpana Kumari else 2863ab26a74SAlpana Kumari { 2873ab26a74SAlpana Kumari if (kw == "MemorySizeInKB") 2883ab26a74SAlpana Kumari { 2893ab26a74SAlpana Kumari inventory::PropertyMap memProp; 2903ab26a74SAlpana Kumari auto memVal = get_if<size_t>(&kwVal.second); 2913ab26a74SAlpana Kumari if (memVal) 2923ab26a74SAlpana Kumari { 2933ab26a74SAlpana Kumari memProp.emplace(move(kw), 2943ab26a74SAlpana Kumari ((*memVal) * CONVERT_MB_TO_KB)); 2953ab26a74SAlpana Kumari interfaces.emplace( 2963ab26a74SAlpana Kumari "xyz.openbmc_project.Inventory.Item.Dimm", 2973ab26a74SAlpana Kumari move(memProp)); 2983ab26a74SAlpana Kumari } 2993ab26a74SAlpana Kumari else 3003ab26a74SAlpana Kumari { 3013ab26a74SAlpana Kumari cerr << "MemorySizeInKB value not found in vpd map\n"; 3023ab26a74SAlpana Kumari } 3033ab26a74SAlpana Kumari } 3043ab26a74SAlpana Kumari } 3053ab26a74SAlpana Kumari } 3063ab26a74SAlpana Kumari else 3073ab26a74SAlpana Kumari { 3083ab26a74SAlpana Kumari Binary vec(kwVal.second.begin(), kwVal.second.end()); 3093ab26a74SAlpana Kumari prop.emplace(move(kw), move(vec)); 3103ab26a74SAlpana Kumari } 3113ab26a74SAlpana Kumari } 312abb87edaSPriyangaRamasamy 313abb87edaSPriyangaRamasamy interfaces.emplace(preIntrStr, move(prop)); 314abb87edaSPriyangaRamasamy } 315abb87edaSPriyangaRamasamy 316abb87edaSPriyangaRamasamy /** 317abb87edaSPriyangaRamasamy * @brief Populate Interfaces. 318abb87edaSPriyangaRamasamy * 319abb87edaSPriyangaRamasamy * This method populates common and extra interfaces to dbus. 320abb87edaSPriyangaRamasamy * @param[in] js - json object 321abb87edaSPriyangaRamasamy * @param[out] interfaces - Reference to interface map 322abb87edaSPriyangaRamasamy * @param[in] vpdMap - Reference to the parsed vpd map. 32388edeb6fSSantosh Puranik * @param[in] isSystemVpd - Denotes whether we are collecting the system VPD. 324abb87edaSPriyangaRamasamy */ 325abb87edaSPriyangaRamasamy template <typename T> 326abb87edaSPriyangaRamasamy static void populateInterfaces(const nlohmann::json& js, 327abb87edaSPriyangaRamasamy inventory::InterfaceMap& interfaces, 32888edeb6fSSantosh Puranik const T& vpdMap, bool isSystemVpd) 329abb87edaSPriyangaRamasamy { 330abb87edaSPriyangaRamasamy for (const auto& ifs : js.items()) 331abb87edaSPriyangaRamasamy { 33288edeb6fSSantosh Puranik string inf = ifs.key(); 333abb87edaSPriyangaRamasamy inventory::PropertyMap props; 334abb87edaSPriyangaRamasamy 335abb87edaSPriyangaRamasamy for (const auto& itr : ifs.value().items()) 336abb87edaSPriyangaRamasamy { 33788edeb6fSSantosh Puranik const string& busProp = itr.key(); 33888edeb6fSSantosh Puranik 33931970dedSAlpana Kumari if (itr.value().is_boolean()) 34031970dedSAlpana Kumari { 34188edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<bool>()); 34288edeb6fSSantosh Puranik } 34388edeb6fSSantosh Puranik else if (itr.value().is_string()) 34488edeb6fSSantosh Puranik { 3450d61c588SPriyanga Ramasamy if (busProp == "LocationCode" && inf == IBM_LOCATION_CODE_INF) 3460d61c588SPriyanga Ramasamy { 3470d61c588SPriyanga Ramasamy std::string prop; 34858e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 34988edeb6fSSantosh Puranik { 350414d5aefSAlpana Kumari // TODO deprecate the com.ibm interface later 3510d61c588SPriyanga Ramasamy prop = expandLocationCode(itr.value().get<string>(), 3520d61c588SPriyanga Ramasamy vpdMap, isSystemVpd); 3530d61c588SPriyanga Ramasamy } 3540d61c588SPriyanga Ramasamy else if constexpr (is_same<T, KeywordVpdMap>::value) 3550d61c588SPriyanga Ramasamy { 3560d61c588SPriyanga Ramasamy // Send empty Parsed object to expandLocationCode api. 3570d61c588SPriyanga Ramasamy prop = expandLocationCode(itr.value().get<string>(), 3580d61c588SPriyanga Ramasamy Parsed{}, false); 3590d61c588SPriyanga Ramasamy } 36088edeb6fSSantosh Puranik props.emplace(busProp, prop); 361414d5aefSAlpana Kumari interfaces.emplace(XYZ_LOCATION_CODE_INF, props); 36269f76024SPriyanga Ramasamy interfaces.emplace(IBM_LOCATION_CODE_INF, props); 36388edeb6fSSantosh Puranik } 36488edeb6fSSantosh Puranik else 36588edeb6fSSantosh Puranik { 36688edeb6fSSantosh Puranik props.emplace(busProp, itr.value().get<string>()); 36788edeb6fSSantosh Puranik } 36888edeb6fSSantosh Puranik } 369ed609affSSantosh Puranik else if (itr.value().is_array()) 370ed609affSSantosh Puranik { 371ed609affSSantosh Puranik try 372ed609affSSantosh Puranik { 373ed609affSSantosh Puranik props.emplace(busProp, itr.value().get<Binary>()); 374ed609affSSantosh Puranik } 3758e15b93aSPatrick Williams catch (const nlohmann::detail::type_error& e) 376ed609affSSantosh Puranik { 377ed609affSSantosh Puranik std::cerr << "Type exception: " << e.what() << "\n"; 378ed609affSSantosh Puranik // Ignore any type errors 379ed609affSSantosh Puranik } 380ed609affSSantosh Puranik } 38131970dedSAlpana Kumari else if (itr.value().is_object()) 38231970dedSAlpana Kumari { 383abb87edaSPriyangaRamasamy const string& rec = itr.value().value("recordName", ""); 384abb87edaSPriyangaRamasamy const string& kw = itr.value().value("keywordName", ""); 385abb87edaSPriyangaRamasamy const string& encoding = itr.value().value("encoding", ""); 386abb87edaSPriyangaRamasamy 38758e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 388abb87edaSPriyangaRamasamy { 38988edeb6fSSantosh Puranik if (!rec.empty() && !kw.empty() && vpdMap.count(rec) && 39088edeb6fSSantosh Puranik vpdMap.at(rec).count(kw)) 391abb87edaSPriyangaRamasamy { 392abb87edaSPriyangaRamasamy auto encoded = 393abb87edaSPriyangaRamasamy encodeKeyword(vpdMap.at(rec).at(kw), encoding); 39488edeb6fSSantosh Puranik props.emplace(busProp, encoded); 395abb87edaSPriyangaRamasamy } 396abb87edaSPriyangaRamasamy } 39758e22145SAlpana Kumari else if constexpr (is_same<T, KeywordVpdMap>::value) 398abb87edaSPriyangaRamasamy { 399abb87edaSPriyangaRamasamy if (!kw.empty() && vpdMap.count(kw)) 400abb87edaSPriyangaRamasamy { 4013ab26a74SAlpana Kumari auto kwValue = get_if<Binary>(&vpdMap.at(kw)); 4023ab26a74SAlpana Kumari auto uintValue = get_if<size_t>(&vpdMap.at(kw)); 4033ab26a74SAlpana Kumari 4043ab26a74SAlpana Kumari if (kwValue) 4053ab26a74SAlpana Kumari { 406abb87edaSPriyangaRamasamy auto prop = 4073ab26a74SAlpana Kumari string((*kwValue).begin(), (*kwValue).end()); 4083ab26a74SAlpana Kumari 409abb87edaSPriyangaRamasamy auto encoded = encodeKeyword(prop, encoding); 4103ab26a74SAlpana Kumari 41188edeb6fSSantosh Puranik props.emplace(busProp, encoded); 412abb87edaSPriyangaRamasamy } 4133ab26a74SAlpana Kumari else if (uintValue) 4143ab26a74SAlpana Kumari { 4153ab26a74SAlpana Kumari props.emplace(busProp, *uintValue); 4163ab26a74SAlpana Kumari } 4173ab26a74SAlpana Kumari } 418abb87edaSPriyangaRamasamy } 419abb87edaSPriyangaRamasamy } 420b1e64bb6SMatt Spinler else if (itr.value().is_number()) 421b1e64bb6SMatt Spinler { 422b1e64bb6SMatt Spinler // For now assume the value is a size_t. In the future it would 423b1e64bb6SMatt Spinler // be nice to come up with a way to get the type from the JSON. 424b1e64bb6SMatt Spinler props.emplace(busProp, itr.value().get<size_t>()); 425b1e64bb6SMatt Spinler } 42631970dedSAlpana Kumari } 427aa8a893eSPriyanga Ramasamy insertOrMerge(interfaces, inf, move(props)); 428abb87edaSPriyangaRamasamy } 429abb87edaSPriyangaRamasamy } 430abb87edaSPriyangaRamasamy 43137233785SPriyanga Ramasamy /*API to reset EEPROM pointer to a safe position to avoid VPD corruption. 43237233785SPriyanga Ramasamy * Currently do reset only for DIMM VPD.*/ 43337233785SPriyanga Ramasamy static void resetEEPROMPointer(const nlohmann::json& js, const string& file, 43437233785SPriyanga Ramasamy ifstream& vpdFile) 43537233785SPriyanga Ramasamy { 43637233785SPriyanga Ramasamy for (const auto& item : js["frus"][file]) 43737233785SPriyanga Ramasamy { 43837233785SPriyanga Ramasamy if (item.find("extraInterfaces") != item.end()) 43937233785SPriyanga Ramasamy { 44037233785SPriyanga Ramasamy if (item["extraInterfaces"].find( 44137233785SPriyanga Ramasamy "xyz.openbmc_project.Inventory.Item.Dimm") != 44237233785SPriyanga Ramasamy item["extraInterfaces"].end()) 44337233785SPriyanga Ramasamy { 44437233785SPriyanga Ramasamy // moves the EEPROM pointer to 2048 'th byte. 44537233785SPriyanga Ramasamy vpdFile.seekg(2047, std::ios::beg); 44637233785SPriyanga Ramasamy // Read that byte and discard - to affirm the move 44737233785SPriyanga Ramasamy // operation. 44837233785SPriyanga Ramasamy char ch; 44937233785SPriyanga Ramasamy vpdFile.read(&ch, sizeof(ch)); 45037233785SPriyanga Ramasamy } 45137233785SPriyanga Ramasamy return; 45237233785SPriyanga Ramasamy } 45337233785SPriyanga Ramasamy } 45437233785SPriyanga Ramasamy } 45537233785SPriyanga Ramasamy 4565cb3b1f3Salpana07 /** 4575cb3b1f3Salpana07 * @brief This API checks if this FRU is pcie_devices. If yes then it further 4585cb3b1f3Salpana07 * checks whether it is PASS1 planar. 4595cb3b1f3Salpana07 */ 4605cb3b1f3Salpana07 static bool isThisPcieOnPass1planar(const nlohmann::json& js, 4615cb3b1f3Salpana07 const string& file) 4625cb3b1f3Salpana07 { 4635cb3b1f3Salpana07 auto isThisPCIeDev = false; 4645cb3b1f3Salpana07 auto isPASS1 = false; 4655cb3b1f3Salpana07 4665cb3b1f3Salpana07 // Check if it is a PCIE device 4675cb3b1f3Salpana07 if (js["frus"].find(file) != js["frus"].end()) 4685cb3b1f3Salpana07 { 469c03f3906SSantosh Puranik if ((js["frus"][file].at(0).find("extraInterfaces") != 470c03f3906SSantosh Puranik js["frus"][file].at(0).end())) 4715cb3b1f3Salpana07 { 472c03f3906SSantosh Puranik if (js["frus"][file].at(0)["extraInterfaces"].find( 4735cb3b1f3Salpana07 "xyz.openbmc_project.Inventory.Item.PCIeDevice") != 474c03f3906SSantosh Puranik js["frus"][file].at(0)["extraInterfaces"].end()) 4755cb3b1f3Salpana07 { 4765cb3b1f3Salpana07 isThisPCIeDev = true; 4775cb3b1f3Salpana07 } 4785cb3b1f3Salpana07 } 4795cb3b1f3Salpana07 } 4805cb3b1f3Salpana07 4815cb3b1f3Salpana07 if (isThisPCIeDev) 4825cb3b1f3Salpana07 { 483*a6181e22SAlpana Kumari // Collect HW version and SystemType to know if it is PASS1 planar. 4845cb3b1f3Salpana07 auto bus = sdbusplus::bus::new_default(); 485*a6181e22SAlpana Kumari auto property1 = bus.new_method_call( 4865cb3b1f3Salpana07 INVENTORY_MANAGER_SERVICE, 4875cb3b1f3Salpana07 "/xyz/openbmc_project/inventory/system/chassis/motherboard", 4885cb3b1f3Salpana07 "org.freedesktop.DBus.Properties", "Get"); 489*a6181e22SAlpana Kumari property1.append("com.ibm.ipzvpd.VINI"); 490*a6181e22SAlpana Kumari property1.append("HW"); 491*a6181e22SAlpana Kumari auto result1 = bus.call(property1); 492*a6181e22SAlpana Kumari inventory::Value hwVal; 493*a6181e22SAlpana Kumari result1.read(hwVal); 4945cb3b1f3Salpana07 495*a6181e22SAlpana Kumari // SystemType 496*a6181e22SAlpana Kumari auto property2 = bus.new_method_call( 497*a6181e22SAlpana Kumari INVENTORY_MANAGER_SERVICE, 498*a6181e22SAlpana Kumari "/xyz/openbmc_project/inventory/system/chassis/motherboard", 499*a6181e22SAlpana Kumari "org.freedesktop.DBus.Properties", "Get"); 500*a6181e22SAlpana Kumari property2.append("com.ibm.ipzvpd.VSBP"); 501*a6181e22SAlpana Kumari property2.append("IM"); 502*a6181e22SAlpana Kumari auto result2 = bus.call(property2); 503*a6181e22SAlpana Kumari inventory::Value imVal; 504*a6181e22SAlpana Kumari result2.read(imVal); 505*a6181e22SAlpana Kumari 506*a6181e22SAlpana Kumari auto pVal1 = get_if<Binary>(&hwVal); 507*a6181e22SAlpana Kumari auto pVal2 = get_if<Binary>(&imVal); 508*a6181e22SAlpana Kumari 509*a6181e22SAlpana Kumari if (pVal1 && pVal2) 5105cb3b1f3Salpana07 { 511*a6181e22SAlpana Kumari auto hwVersion = *pVal1; 512*a6181e22SAlpana Kumari auto systemType = *pVal2; 513*a6181e22SAlpana Kumari 514*a6181e22SAlpana Kumari // IM kw for Everest 515*a6181e22SAlpana Kumari Binary everestSystem{80, 00, 48, 00}; 516*a6181e22SAlpana Kumari 517*a6181e22SAlpana Kumari if (systemType == everestSystem) 518*a6181e22SAlpana Kumari { 519*a6181e22SAlpana Kumari if (hwVersion[1] < 21) 520*a6181e22SAlpana Kumari { 5215cb3b1f3Salpana07 isPASS1 = true; 5225cb3b1f3Salpana07 } 5235cb3b1f3Salpana07 } 524*a6181e22SAlpana Kumari else if (hwVersion[1] < 2) 525*a6181e22SAlpana Kumari { 526*a6181e22SAlpana Kumari isPASS1 = true; 527*a6181e22SAlpana Kumari } 528*a6181e22SAlpana Kumari } 529*a6181e22SAlpana Kumari } 5305cb3b1f3Salpana07 5315cb3b1f3Salpana07 return (isThisPCIeDev && isPASS1); 5325cb3b1f3Salpana07 } 5335cb3b1f3Salpana07 5342f793048SAlpana Kumari static Binary getVpdDataInVector(const nlohmann::json& js, const string& file) 53558e22145SAlpana Kumari { 53658e22145SAlpana Kumari uint32_t offset = 0; 53758e22145SAlpana Kumari // check if offset present? 53858e22145SAlpana Kumari for (const auto& item : js["frus"][file]) 53958e22145SAlpana Kumari { 54058e22145SAlpana Kumari if (item.find("offset") != item.end()) 54158e22145SAlpana Kumari { 54258e22145SAlpana Kumari offset = item["offset"]; 54358e22145SAlpana Kumari } 54458e22145SAlpana Kumari } 54558e22145SAlpana Kumari 54658e22145SAlpana Kumari // TODO: Figure out a better way to get max possible VPD size. 5473c2a2b9eSPriyanga Ramasamy auto maxVPDSize = std::min(std::filesystem::file_size(file), 5483c2a2b9eSPriyanga Ramasamy static_cast<uintmax_t>(65504)); 5493c2a2b9eSPriyanga Ramasamy 55058e22145SAlpana Kumari Binary vpdVector; 5513c2a2b9eSPriyanga Ramasamy vpdVector.resize(maxVPDSize); 55258e22145SAlpana Kumari ifstream vpdFile; 55358e22145SAlpana Kumari vpdFile.open(file, ios::binary); 55458e22145SAlpana Kumari 55558e22145SAlpana Kumari vpdFile.seekg(offset, ios_base::cur); 5563c2a2b9eSPriyanga Ramasamy vpdFile.read(reinterpret_cast<char*>(&vpdVector[0]), maxVPDSize); 55758e22145SAlpana Kumari vpdVector.resize(vpdFile.gcount()); 55858e22145SAlpana Kumari 55937233785SPriyanga Ramasamy resetEEPROMPointer(js, file, vpdFile); 56037233785SPriyanga Ramasamy 56158e22145SAlpana Kumari return vpdVector; 56258e22145SAlpana Kumari } 56358e22145SAlpana Kumari 564735dee9bSAlpana Kumari /** Performs any pre-action needed to get the FRU setup for collection. 5652f793048SAlpana Kumari * 5662f793048SAlpana Kumari * @param[in] json - json object 5672f793048SAlpana Kumari * @param[in] file - eeprom file path 5682f793048SAlpana Kumari */ 5692f793048SAlpana Kumari static void preAction(const nlohmann::json& json, const string& file) 5702f793048SAlpana Kumari { 571735dee9bSAlpana Kumari if ((json["frus"][file].at(0)).find("preAction") == 5722f793048SAlpana Kumari json["frus"][file].at(0).end()) 5732f793048SAlpana Kumari { 5742f793048SAlpana Kumari return; 5752f793048SAlpana Kumari } 5762f793048SAlpana Kumari 577735dee9bSAlpana Kumari if (executePreAction(json, file)) 5782f793048SAlpana Kumari { 57964b9f5f1SAlpana Kumari if (json["frus"][file].at(0).find("devAddress") != 58064b9f5f1SAlpana Kumari json["frus"][file].at(0).end()) 58164b9f5f1SAlpana Kumari { 582735dee9bSAlpana Kumari // Now bind the device 5834c3bf5beSAlpana Kumari string bind = json["frus"][file].at(0).value("devAddress", ""); 5842f793048SAlpana Kumari cout << "Binding device " << bind << endl; 5852f793048SAlpana Kumari string bindCmd = string("echo \"") + bind + 5862f793048SAlpana Kumari string("\" > /sys/bus/i2c/drivers/at24/bind"); 5872f793048SAlpana Kumari cout << bindCmd << endl; 5882f793048SAlpana Kumari executeCmd(bindCmd); 5892f793048SAlpana Kumari 5902f793048SAlpana Kumari // Check if device showed up (test for file) 5912f793048SAlpana Kumari if (!fs::exists(file)) 5922f793048SAlpana Kumari { 59340d1c196SAlpana Kumari cerr << "EEPROM " << file 59440d1c196SAlpana Kumari << " does not exist. Take failure action" << endl; 5952f793048SAlpana Kumari // If not, then take failure postAction 596735dee9bSAlpana Kumari executePostFailAction(json, file); 597735dee9bSAlpana Kumari } 5982f793048SAlpana Kumari } 59940d1c196SAlpana Kumari else 60040d1c196SAlpana Kumari { 60140d1c196SAlpana Kumari // missing required informations 60240d1c196SAlpana Kumari cerr 60340d1c196SAlpana Kumari << "VPD inventory JSON missing basic informations of preAction " 60440d1c196SAlpana Kumari "for this FRU : [" 60540d1c196SAlpana Kumari << file << "]. Executing executePostFailAction." << endl; 60640d1c196SAlpana Kumari 60740d1c196SAlpana Kumari // Take failure postAction 60840d1c196SAlpana Kumari executePostFailAction(json, file); 60940d1c196SAlpana Kumari return; 61040d1c196SAlpana Kumari } 61140d1c196SAlpana Kumari } 6122f793048SAlpana Kumari } 6132f793048SAlpana Kumari 614abb87edaSPriyangaRamasamy /** 615f3e69689SSantosh Puranik * @brief Fills the Decorator.AssetTag property into the interfaces map 616f3e69689SSantosh Puranik * 617f3e69689SSantosh Puranik * This function should only be called in cases where we did not find a JSON 618f3e69689SSantosh Puranik * symlink. A missing symlink in /var/lib will be considered as a factory reset 619f3e69689SSantosh Puranik * and this function will be used to default the AssetTag property. 620f3e69689SSantosh Puranik * 621f3e69689SSantosh Puranik * @param interfaces A possibly pre-populated map of inetrfaces to properties. 622f3e69689SSantosh Puranik * @param vpdMap A VPD map of the system VPD data. 623f3e69689SSantosh Puranik */ 624f3e69689SSantosh Puranik static void fillAssetTag(inventory::InterfaceMap& interfaces, 625f3e69689SSantosh Puranik const Parsed& vpdMap) 626f3e69689SSantosh Puranik { 627f3e69689SSantosh Puranik // Read the system serial number and MTM 628f3e69689SSantosh Puranik // Default asset tag is Server-MTM-System Serial 629f3e69689SSantosh Puranik inventory::Interface assetIntf{ 630f3e69689SSantosh Puranik "xyz.openbmc_project.Inventory.Decorator.AssetTag"}; 631f3e69689SSantosh Puranik inventory::PropertyMap assetTagProps; 632f3e69689SSantosh Puranik std::string defaultAssetTag = 633f3e69689SSantosh Puranik std::string{"Server-"} + getKwVal(vpdMap, "VSYS", "TM") + 634f3e69689SSantosh Puranik std::string{"-"} + getKwVal(vpdMap, "VSYS", "SE"); 635f3e69689SSantosh Puranik assetTagProps.emplace("AssetTag", defaultAssetTag); 636f3e69689SSantosh Puranik insertOrMerge(interfaces, assetIntf, std::move(assetTagProps)); 637f3e69689SSantosh Puranik } 638f3e69689SSantosh Puranik 639f3e69689SSantosh Puranik /** 640d3a379a6SSantosh Puranik * @brief Set certain one time properties in the inventory 641d3a379a6SSantosh Puranik * Use this function to insert the Functional and Enabled properties into the 642d3a379a6SSantosh Puranik * inventory map. This function first checks if the object in question already 643d3a379a6SSantosh Puranik * has these properties hosted on D-Bus, if the property is already there, it is 644d3a379a6SSantosh Puranik * not modified, hence the name "one time". If the property is not already 645d3a379a6SSantosh Puranik * present, it will be added to the map with a suitable default value (true for 646d3a379a6SSantosh Puranik * Functional and false for Enabled) 647d3a379a6SSantosh Puranik * 648d3a379a6SSantosh Puranik * @param[in] object - The inventory D-Bus obejct without the inventory prefix. 649d3a379a6SSantosh Puranik * @param[inout] interfaces - Reference to a map of inventory interfaces to 650d3a379a6SSantosh Puranik * which the properties will be attached. 651d3a379a6SSantosh Puranik */ 652d3a379a6SSantosh Puranik static void setOneTimeProperties(const std::string& object, 653d3a379a6SSantosh Puranik inventory::InterfaceMap& interfaces) 654d3a379a6SSantosh Puranik { 655d3a379a6SSantosh Puranik auto bus = sdbusplus::bus::new_default(); 656d3a379a6SSantosh Puranik auto objectPath = INVENTORY_PATH + object; 657d3a379a6SSantosh Puranik auto prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager", 658d3a379a6SSantosh Puranik objectPath.c_str(), 659d3a379a6SSantosh Puranik "org.freedesktop.DBus.Properties", "Get"); 660d3a379a6SSantosh Puranik prop.append("xyz.openbmc_project.State.Decorator.OperationalStatus"); 661d3a379a6SSantosh Puranik prop.append("Functional"); 662d3a379a6SSantosh Puranik try 663d3a379a6SSantosh Puranik { 664d3a379a6SSantosh Puranik auto result = bus.call(prop); 665d3a379a6SSantosh Puranik } 666d3a379a6SSantosh Puranik catch (const sdbusplus::exception::SdBusError& e) 667d3a379a6SSantosh Puranik { 668d3a379a6SSantosh Puranik // Treat as property unavailable 669d3a379a6SSantosh Puranik inventory::PropertyMap prop; 670d3a379a6SSantosh Puranik prop.emplace("Functional", true); 671d3a379a6SSantosh Puranik interfaces.emplace( 672d3a379a6SSantosh Puranik "xyz.openbmc_project.State.Decorator.OperationalStatus", 673d3a379a6SSantosh Puranik move(prop)); 674d3a379a6SSantosh Puranik } 675d3a379a6SSantosh Puranik prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager", 676d3a379a6SSantosh Puranik objectPath.c_str(), 677d3a379a6SSantosh Puranik "org.freedesktop.DBus.Properties", "Get"); 678d3a379a6SSantosh Puranik prop.append("xyz.openbmc_project.Object.Enable"); 679d3a379a6SSantosh Puranik prop.append("Enabled"); 680d3a379a6SSantosh Puranik try 681d3a379a6SSantosh Puranik { 682d3a379a6SSantosh Puranik auto result = bus.call(prop); 683d3a379a6SSantosh Puranik } 684d3a379a6SSantosh Puranik catch (const sdbusplus::exception::SdBusError& e) 685d3a379a6SSantosh Puranik { 686d3a379a6SSantosh Puranik // Treat as property unavailable 687d3a379a6SSantosh Puranik inventory::PropertyMap prop; 688d3a379a6SSantosh Puranik prop.emplace("Enabled", false); 689d3a379a6SSantosh Puranik interfaces.emplace("xyz.openbmc_project.Object.Enable", move(prop)); 690d3a379a6SSantosh Puranik } 691d3a379a6SSantosh Puranik } 692d3a379a6SSantosh Puranik 693d3a379a6SSantosh Puranik /** 6948e140a1cSPriyangaRamasamy * @brief Prime the Inventory 6958e140a1cSPriyangaRamasamy * Prime the inventory by populating only the location code, 6968e140a1cSPriyangaRamasamy * type interface and the inventory object for the frus 6978e140a1cSPriyangaRamasamy * which are not system vpd fru. 698abb87edaSPriyangaRamasamy * 6998e140a1cSPriyangaRamasamy * @param[in] jsObject - Reference to vpd inventory json object 7008e140a1cSPriyangaRamasamy * @param[in] vpdMap - Reference to the parsed vpd map 7018e140a1cSPriyangaRamasamy * 7028e140a1cSPriyangaRamasamy * @returns Map of items in extraInterface. 7038e140a1cSPriyangaRamasamy */ 7048e140a1cSPriyangaRamasamy template <typename T> 7058e140a1cSPriyangaRamasamy inventory::ObjectMap primeInventory(const nlohmann::json& jsObject, 7068e140a1cSPriyangaRamasamy const T& vpdMap) 7078e140a1cSPriyangaRamasamy { 7088e140a1cSPriyangaRamasamy inventory::ObjectMap objects; 7098e140a1cSPriyangaRamasamy 7108e140a1cSPriyangaRamasamy for (auto& itemFRUS : jsObject["frus"].items()) 7118e140a1cSPriyangaRamasamy { 7128e140a1cSPriyangaRamasamy for (auto& itemEEPROM : itemFRUS.value()) 7138e140a1cSPriyangaRamasamy { 7142e6c6f73SAlpana Kumari // Take pre actions if needed 7152e6c6f73SAlpana Kumari if (itemEEPROM.find("preAction") != itemEEPROM.end()) 7162e6c6f73SAlpana Kumari { 7172e6c6f73SAlpana Kumari preAction(jsObject, itemFRUS.key()); 7182e6c6f73SAlpana Kumari } 7192e6c6f73SAlpana Kumari 7208e140a1cSPriyangaRamasamy inventory::InterfaceMap interfaces; 7218e140a1cSPriyangaRamasamy inventory::Object object(itemEEPROM.at("inventoryPath")); 7228e140a1cSPriyangaRamasamy 72350f60bf8SSantosh Puranik if ((itemFRUS.key() != systemVpdFilePath) && 72450f60bf8SSantosh Puranik !itemEEPROM.value("noprime", false)) 7258e140a1cSPriyangaRamasamy { 726cfd7a75aSAlpana Kumari inventory::PropertyMap presProp; 727e358acbbSPriyanga Ramasamy 728e358acbbSPriyanga Ramasamy // Do not populate Present property for frus whose 729e358acbbSPriyanga Ramasamy // synthesized=true. synthesized=true says the fru is owned by 730e358acbbSPriyanga Ramasamy // some other component and not by vpd. 731e358acbbSPriyanga Ramasamy if (!itemEEPROM.value("synthesized", false)) 732e358acbbSPriyanga Ramasamy { 733cfd7a75aSAlpana Kumari presProp.emplace("Present", false); 734cfd7a75aSAlpana Kumari interfaces.emplace("xyz.openbmc_project.Inventory.Item", 735d3a379a6SSantosh Puranik presProp); 736e358acbbSPriyanga Ramasamy } 737d3a379a6SSantosh Puranik setOneTimeProperties(object, interfaces); 7388e140a1cSPriyangaRamasamy if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end()) 7398e140a1cSPriyangaRamasamy { 7408e140a1cSPriyangaRamasamy for (const auto& eI : itemEEPROM["extraInterfaces"].items()) 7418e140a1cSPriyangaRamasamy { 7428e140a1cSPriyangaRamasamy inventory::PropertyMap props; 743414d5aefSAlpana Kumari if (eI.key() == IBM_LOCATION_CODE_INF) 7448e140a1cSPriyangaRamasamy { 7458e140a1cSPriyangaRamasamy if constexpr (std::is_same<T, Parsed>::value) 7468e140a1cSPriyangaRamasamy { 7478e140a1cSPriyangaRamasamy for (auto& lC : eI.value().items()) 7488e140a1cSPriyangaRamasamy { 7498e140a1cSPriyangaRamasamy auto propVal = expandLocationCode( 7508e140a1cSPriyangaRamasamy lC.value().get<string>(), vpdMap, true); 7518e140a1cSPriyangaRamasamy 7528e140a1cSPriyangaRamasamy props.emplace(move(lC.key()), 7538e140a1cSPriyangaRamasamy move(propVal)); 754b0f3749dSSantosh Puranik interfaces.emplace(XYZ_LOCATION_CODE_INF, 755b0f3749dSSantosh Puranik props); 7568e140a1cSPriyangaRamasamy interfaces.emplace(move(eI.key()), 7578e140a1cSPriyangaRamasamy move(props)); 7588e140a1cSPriyangaRamasamy } 7598e140a1cSPriyangaRamasamy } 7608e140a1cSPriyangaRamasamy } 7618e140a1cSPriyangaRamasamy else if (eI.key().find("Inventory.Item.") != 7628e140a1cSPriyangaRamasamy string::npos) 7638e140a1cSPriyangaRamasamy { 7648e140a1cSPriyangaRamasamy interfaces.emplace(move(eI.key()), move(props)); 7658e140a1cSPriyangaRamasamy } 766d3a379a6SSantosh Puranik else if (eI.key() == 767d3a379a6SSantosh Puranik "xyz.openbmc_project.Inventory.Item") 768d3a379a6SSantosh Puranik { 769d3a379a6SSantosh Puranik for (auto& val : eI.value().items()) 770d3a379a6SSantosh Puranik { 771d3a379a6SSantosh Puranik if (val.key() == "PrettyName") 772d3a379a6SSantosh Puranik { 773d3a379a6SSantosh Puranik presProp.emplace(val.key(), 774d3a379a6SSantosh Puranik val.value().get<string>()); 775d3a379a6SSantosh Puranik } 776d3a379a6SSantosh Puranik } 777d3a379a6SSantosh Puranik // Use insert_or_assign here as we may already have 778d3a379a6SSantosh Puranik // inserted the present property only earlier in 779d3a379a6SSantosh Puranik // this function under this same interface. 780d3a379a6SSantosh Puranik interfaces.insert_or_assign(eI.key(), 781d3a379a6SSantosh Puranik move(presProp)); 782d3a379a6SSantosh Puranik } 7838e140a1cSPriyangaRamasamy } 7848e140a1cSPriyangaRamasamy } 7858e140a1cSPriyangaRamasamy objects.emplace(move(object), move(interfaces)); 7868e140a1cSPriyangaRamasamy } 7878e140a1cSPriyangaRamasamy } 7888e140a1cSPriyangaRamasamy } 7898e140a1cSPriyangaRamasamy return objects; 7908e140a1cSPriyangaRamasamy } 7918e140a1cSPriyangaRamasamy 79265b83601SAlpana Kumari /** 79365b83601SAlpana Kumari * @brief This API executes command to set environment variable 79465b83601SAlpana Kumari * And then reboot the system 79565b83601SAlpana Kumari * @param[in] key -env key to set new value 79665b83601SAlpana Kumari * @param[in] value -value to set. 79765b83601SAlpana Kumari */ 79865b83601SAlpana Kumari void setEnvAndReboot(const string& key, const string& value) 79965b83601SAlpana Kumari { 80065b83601SAlpana Kumari // set env and reboot and break. 80165b83601SAlpana Kumari executeCmd("/sbin/fw_setenv", key, value); 802280197e3SAndrew Geissler log<level::INFO>("Rebooting BMC to pick up new device tree"); 80365b83601SAlpana Kumari // make dbus call to reboot 80465b83601SAlpana Kumari auto bus = sdbusplus::bus::new_default_system(); 80565b83601SAlpana Kumari auto method = bus.new_method_call( 80665b83601SAlpana Kumari "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 80765b83601SAlpana Kumari "org.freedesktop.systemd1.Manager", "Reboot"); 80865b83601SAlpana Kumari bus.call_noreply(method); 80965b83601SAlpana Kumari } 81065b83601SAlpana Kumari 81165b83601SAlpana Kumari /* 81265b83601SAlpana Kumari * @brief This API checks for env var fitconfig. 81365b83601SAlpana Kumari * If not initialised OR updated as per the current system type, 81465b83601SAlpana Kumari * update this env var and reboot the system. 81565b83601SAlpana Kumari * 81665b83601SAlpana Kumari * @param[in] systemType IM kwd in vpd tells about which system type it is. 81765b83601SAlpana Kumari * */ 81865b83601SAlpana Kumari void setDevTreeEnv(const string& systemType) 81965b83601SAlpana Kumari { 82037e72701SAlpana Kumari // Init with default dtb 82137e72701SAlpana Kumari string newDeviceTree = "conf-aspeed-bmc-ibm-rainier-p1.dtb"; 822e5f177a5SSantosh Puranik static const deviceTreeMap deviceTreeSystemTypeMap = { 823e5f177a5SSantosh Puranik {RAINIER_2U, "conf-aspeed-bmc-ibm-rainier-p1.dtb"}, 824e5f177a5SSantosh Puranik {RAINIER_2U_V2, "conf-aspeed-bmc-ibm-rainier.dtb"}, 825e5f177a5SSantosh Puranik {RAINIER_4U, "conf-aspeed-bmc-ibm-rainier-4u-p1.dtb"}, 826e5f177a5SSantosh Puranik {RAINIER_4U_V2, "conf-aspeed-bmc-ibm-rainier-4u.dtb"}, 827e5f177a5SSantosh Puranik {RAINIER_1S4U, "conf-aspeed-bmc-ibm-rainier-1s4u.dtb"}, 8281b026119SAlpana Kumari {EVEREST, "conf-aspeed-bmc-ibm-everest.dtb"}, 8291b026119SAlpana Kumari {EVEREST_V2, "conf-aspeed-bmc-ibm-everest.dtb"}}; 83065b83601SAlpana Kumari 83165b83601SAlpana Kumari if (deviceTreeSystemTypeMap.find(systemType) != 83265b83601SAlpana Kumari deviceTreeSystemTypeMap.end()) 83365b83601SAlpana Kumari { 83465b83601SAlpana Kumari newDeviceTree = deviceTreeSystemTypeMap.at(systemType); 83565b83601SAlpana Kumari } 83637e72701SAlpana Kumari else 83737e72701SAlpana Kumari { 83837e72701SAlpana Kumari // System type not supported 839ab1e22c3SAlpana Kumari string err = "This System type not found/supported in dtb table " + 840ab1e22c3SAlpana Kumari systemType + 841ab1e22c3SAlpana Kumari ".Please check the HW and IM keywords in the system " 842ab1e22c3SAlpana Kumari "VPD.Breaking..."; 843ab1e22c3SAlpana Kumari 844ab1e22c3SAlpana Kumari // map to hold additional data in case of logging pel 845ab1e22c3SAlpana Kumari PelAdditionalData additionalData{}; 846ab1e22c3SAlpana Kumari additionalData.emplace("DESCRIPTION", err); 847ab1e22c3SAlpana Kumari createPEL(additionalData, PelSeverity::WARNING, 848ab1e22c3SAlpana Kumari errIntfForInvalidSystemType); 849ab1e22c3SAlpana Kumari exit(-1); 85037e72701SAlpana Kumari } 85165b83601SAlpana Kumari 85265b83601SAlpana Kumari string readVarValue; 85365b83601SAlpana Kumari bool envVarFound = false; 85465b83601SAlpana Kumari 85565b83601SAlpana Kumari vector<string> output = executeCmd("/sbin/fw_printenv"); 85665b83601SAlpana Kumari for (const auto& entry : output) 85765b83601SAlpana Kumari { 85865b83601SAlpana Kumari size_t pos = entry.find("="); 85965b83601SAlpana Kumari string key = entry.substr(0, pos); 86065b83601SAlpana Kumari if (key != "fitconfig") 86165b83601SAlpana Kumari { 86265b83601SAlpana Kumari continue; 86365b83601SAlpana Kumari } 86465b83601SAlpana Kumari 86565b83601SAlpana Kumari envVarFound = true; 86665b83601SAlpana Kumari if (pos + 1 < entry.size()) 86765b83601SAlpana Kumari { 86865b83601SAlpana Kumari readVarValue = entry.substr(pos + 1); 86965b83601SAlpana Kumari if (readVarValue.find(newDeviceTree) != string::npos) 87065b83601SAlpana Kumari { 87165b83601SAlpana Kumari // fitconfig is Updated. No action needed 87265b83601SAlpana Kumari break; 87365b83601SAlpana Kumari } 87465b83601SAlpana Kumari } 87565b83601SAlpana Kumari // set env and reboot and break. 87665b83601SAlpana Kumari setEnvAndReboot(key, newDeviceTree); 87765b83601SAlpana Kumari exit(0); 87865b83601SAlpana Kumari } 87965b83601SAlpana Kumari 88065b83601SAlpana Kumari // check If env var Not found 88165b83601SAlpana Kumari if (!envVarFound) 88265b83601SAlpana Kumari { 88365b83601SAlpana Kumari setEnvAndReboot("fitconfig", newDeviceTree); 88465b83601SAlpana Kumari } 88565b83601SAlpana Kumari } 88665b83601SAlpana Kumari 8878e140a1cSPriyangaRamasamy /** 8889094d4f6SSunnySrivastava1984 * @brief API to call VPD manager to write VPD to EEPROM. 8899094d4f6SSunnySrivastava1984 * @param[in] Object path. 8909094d4f6SSunnySrivastava1984 * @param[in] record to be updated. 8919094d4f6SSunnySrivastava1984 * @param[in] keyword to be updated. 8929094d4f6SSunnySrivastava1984 * @param[in] keyword data to be updated 8939094d4f6SSunnySrivastava1984 */ 8949094d4f6SSunnySrivastava1984 void updateHardware(const string& objectName, const string& recName, 8959094d4f6SSunnySrivastava1984 const string& kwdName, const Binary& data) 8969094d4f6SSunnySrivastava1984 { 8979094d4f6SSunnySrivastava1984 try 8989094d4f6SSunnySrivastava1984 { 8999094d4f6SSunnySrivastava1984 auto bus = sdbusplus::bus::new_default(); 9009094d4f6SSunnySrivastava1984 auto properties = 9019094d4f6SSunnySrivastava1984 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword"); 9029094d4f6SSunnySrivastava1984 properties.append( 9039094d4f6SSunnySrivastava1984 static_cast<sdbusplus::message::object_path>(objectName)); 9049094d4f6SSunnySrivastava1984 properties.append(recName); 9059094d4f6SSunnySrivastava1984 properties.append(kwdName); 9069094d4f6SSunnySrivastava1984 properties.append(data); 9079094d4f6SSunnySrivastava1984 bus.call(properties); 9089094d4f6SSunnySrivastava1984 } 9098be4334fSPatrick Williams catch (const sdbusplus::exception::exception& e) 9109094d4f6SSunnySrivastava1984 { 9119094d4f6SSunnySrivastava1984 std::string what = 9129094d4f6SSunnySrivastava1984 "VPDManager WriteKeyword api failed for inventory path " + 9139094d4f6SSunnySrivastava1984 objectName; 9149094d4f6SSunnySrivastava1984 what += " record " + recName; 9159094d4f6SSunnySrivastava1984 what += " keyword " + kwdName; 9169094d4f6SSunnySrivastava1984 what += " with bus error = " + std::string(e.what()); 9179094d4f6SSunnySrivastava1984 9189094d4f6SSunnySrivastava1984 // map to hold additional data in case of logging pel 9199094d4f6SSunnySrivastava1984 PelAdditionalData additionalData{}; 9209094d4f6SSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", objectName); 9219094d4f6SSunnySrivastava1984 additionalData.emplace("DESCRIPTION", what); 9220746eeebSSunny Srivastava createPEL(additionalData, PelSeverity::WARNING, errIntfForBusFailure); 9239094d4f6SSunnySrivastava1984 } 9249094d4f6SSunnySrivastava1984 } 9259094d4f6SSunnySrivastava1984 9269094d4f6SSunnySrivastava1984 /** 9273c24414fSSunny Srivastava * @brief An api to get list of blank system VPD properties. 9283c24414fSSunny Srivastava * @param[in] vpdMap - IPZ vpd map. 9293c24414fSSunny Srivastava * @param[in] objectPath - Object path for the FRU. 9303c24414fSSunny Srivastava * @param[out] blankPropertyList - Properties which are blank in System VPD and 9313c24414fSSunny Srivastava * needs to be updated as standby. 9323c24414fSSunny Srivastava */ 9333c24414fSSunny Srivastava void getListOfBlankSystemVpd(Parsed& vpdMap, const string& objectPath, 9343c24414fSSunny Srivastava std::vector<RestoredEeproms>& blankPropertyList) 9353c24414fSSunny Srivastava { 9363c24414fSSunny Srivastava for (const auto& systemRecKwdPair : svpdKwdMap) 9373c24414fSSunny Srivastava { 9383c24414fSSunny Srivastava auto it = vpdMap.find(systemRecKwdPair.first); 9393c24414fSSunny Srivastava 9403c24414fSSunny Srivastava // check if record is found in map we got by parser 9413c24414fSSunny Srivastava if (it != vpdMap.end()) 9423c24414fSSunny Srivastava { 9433c24414fSSunny Srivastava const auto& kwdListForRecord = systemRecKwdPair.second; 9443c24414fSSunny Srivastava for (const auto& keyword : kwdListForRecord) 9453c24414fSSunny Srivastava { 9463c24414fSSunny Srivastava DbusPropertyMap& kwdValMap = it->second; 9473c24414fSSunny Srivastava auto iterator = kwdValMap.find(keyword); 9483c24414fSSunny Srivastava 9493c24414fSSunny Srivastava if (iterator != kwdValMap.end()) 9503c24414fSSunny Srivastava { 9513c24414fSSunny Srivastava string& kwdValue = iterator->second; 9523c24414fSSunny Srivastava 9533c24414fSSunny Srivastava // check bus data 9543c24414fSSunny Srivastava const string& recordName = systemRecKwdPair.first; 9553c24414fSSunny Srivastava const string& busValue = readBusProperty( 9563c24414fSSunny Srivastava objectPath, ipzVpdInf + recordName, keyword); 9573c24414fSSunny Srivastava 9583c24414fSSunny Srivastava if (busValue.find_first_not_of(' ') != string::npos) 9593c24414fSSunny Srivastava { 9603c24414fSSunny Srivastava if (kwdValue.find_first_not_of(' ') == string::npos) 9613c24414fSSunny Srivastava { 9623c24414fSSunny Srivastava // implies data is blank on EEPROM but not on cache. 9633c24414fSSunny Srivastava // So EEPROM vpd update is required. 9643c24414fSSunny Srivastava Binary busData(busValue.begin(), busValue.end()); 9653c24414fSSunny Srivastava 9663c24414fSSunny Srivastava blankPropertyList.push_back(std::make_tuple( 9673c24414fSSunny Srivastava objectPath, recordName, keyword, busData)); 9683c24414fSSunny Srivastava } 9693c24414fSSunny Srivastava } 9703c24414fSSunny Srivastava } 9713c24414fSSunny Srivastava } 9723c24414fSSunny Srivastava } 9733c24414fSSunny Srivastava } 9743c24414fSSunny Srivastava } 9753c24414fSSunny Srivastava 9763c24414fSSunny Srivastava /** 9779094d4f6SSunnySrivastava1984 * @brief API to check if we need to restore system VPD 9789094d4f6SSunnySrivastava1984 * This functionality is only applicable for IPZ VPD data. 9799094d4f6SSunnySrivastava1984 * @param[in] vpdMap - IPZ vpd map 9809094d4f6SSunnySrivastava1984 * @param[in] objectPath - Object path for the FRU 9819094d4f6SSunnySrivastava1984 */ 9823c24414fSSunny Srivastava void restoreSystemVPD(Parsed& vpdMap, const string& objectPath) 9839094d4f6SSunnySrivastava1984 { 9849094d4f6SSunnySrivastava1984 for (const auto& systemRecKwdPair : svpdKwdMap) 9859094d4f6SSunnySrivastava1984 { 9869094d4f6SSunnySrivastava1984 auto it = vpdMap.find(systemRecKwdPair.first); 9879094d4f6SSunnySrivastava1984 9889094d4f6SSunnySrivastava1984 // check if record is found in map we got by parser 9899094d4f6SSunnySrivastava1984 if (it != vpdMap.end()) 9909094d4f6SSunnySrivastava1984 { 9919094d4f6SSunnySrivastava1984 const auto& kwdListForRecord = systemRecKwdPair.second; 9929094d4f6SSunnySrivastava1984 for (const auto& keyword : kwdListForRecord) 9939094d4f6SSunnySrivastava1984 { 9949094d4f6SSunnySrivastava1984 DbusPropertyMap& kwdValMap = it->second; 9959094d4f6SSunnySrivastava1984 auto iterator = kwdValMap.find(keyword); 9969094d4f6SSunnySrivastava1984 9979094d4f6SSunnySrivastava1984 if (iterator != kwdValMap.end()) 9989094d4f6SSunnySrivastava1984 { 9999094d4f6SSunnySrivastava1984 string& kwdValue = iterator->second; 10009094d4f6SSunnySrivastava1984 10019094d4f6SSunnySrivastava1984 // check bus data 10029094d4f6SSunnySrivastava1984 const string& recordName = systemRecKwdPair.first; 10039094d4f6SSunnySrivastava1984 const string& busValue = readBusProperty( 10049094d4f6SSunnySrivastava1984 objectPath, ipzVpdInf + recordName, keyword); 10059094d4f6SSunnySrivastava1984 10069094d4f6SSunnySrivastava1984 if (busValue.find_first_not_of(' ') != string::npos) 10079094d4f6SSunnySrivastava1984 { 10089094d4f6SSunnySrivastava1984 if (kwdValue.find_first_not_of(' ') != string::npos) 10099094d4f6SSunnySrivastava1984 { 10109094d4f6SSunnySrivastava1984 // both the data are present, check for mismatch 10119094d4f6SSunnySrivastava1984 if (busValue != kwdValue) 10129094d4f6SSunnySrivastava1984 { 10139094d4f6SSunnySrivastava1984 string errMsg = "VPD data mismatch on cache " 10149094d4f6SSunnySrivastava1984 "and hardware for record: "; 10159094d4f6SSunnySrivastava1984 errMsg += (*it).first; 10169094d4f6SSunnySrivastava1984 errMsg += " and keyword: "; 10179094d4f6SSunnySrivastava1984 errMsg += keyword; 10189094d4f6SSunnySrivastava1984 10199094d4f6SSunnySrivastava1984 // data mismatch 10209094d4f6SSunnySrivastava1984 PelAdditionalData additionalData; 10219094d4f6SSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 10229094d4f6SSunnySrivastava1984 objectPath); 10239094d4f6SSunnySrivastava1984 10249094d4f6SSunnySrivastava1984 additionalData.emplace("DESCRIPTION", errMsg); 10259094d4f6SSunnySrivastava1984 10260746eeebSSunny Srivastava createPEL(additionalData, PelSeverity::WARNING, 10270746eeebSSunny Srivastava errIntfForInvalidVPD); 10289094d4f6SSunnySrivastava1984 } 10299094d4f6SSunnySrivastava1984 } 10309094d4f6SSunnySrivastava1984 else 10319094d4f6SSunnySrivastava1984 { 10329094d4f6SSunnySrivastava1984 // implies hardware data is blank 10339094d4f6SSunnySrivastava1984 // update the map 10349094d4f6SSunnySrivastava1984 Binary busData(busValue.begin(), busValue.end()); 10359094d4f6SSunnySrivastava1984 10369094d4f6SSunnySrivastava1984 // update the map as well, so that cache data is not 103790a63b9bSSunny Srivastava // updated as blank while populating VPD map on Dbus 103890a63b9bSSunny Srivastava // in populateDBus Api 10399094d4f6SSunnySrivastava1984 kwdValue = busValue; 104090a63b9bSSunny Srivastava } 10419094d4f6SSunnySrivastava1984 } 10429094d4f6SSunnySrivastava1984 else if (kwdValue.find_first_not_of(' ') == string::npos) 10439094d4f6SSunnySrivastava1984 { 10449094d4f6SSunnySrivastava1984 string errMsg = "VPD is blank on both cache and " 10459094d4f6SSunnySrivastava1984 "hardware for record: "; 10469094d4f6SSunnySrivastava1984 errMsg += (*it).first; 10479094d4f6SSunnySrivastava1984 errMsg += " and keyword: "; 10489094d4f6SSunnySrivastava1984 errMsg += keyword; 10499094d4f6SSunnySrivastava1984 errMsg += ". SSR need to update hardware VPD."; 10509094d4f6SSunnySrivastava1984 10519094d4f6SSunnySrivastava1984 // both the data are blanks, log PEL 10529094d4f6SSunnySrivastava1984 PelAdditionalData additionalData; 10539094d4f6SSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 10549094d4f6SSunnySrivastava1984 objectPath); 10559094d4f6SSunnySrivastava1984 10569094d4f6SSunnySrivastava1984 additionalData.emplace("DESCRIPTION", errMsg); 10579094d4f6SSunnySrivastava1984 10589094d4f6SSunnySrivastava1984 // log PEL TODO: Block IPL 10590746eeebSSunny Srivastava createPEL(additionalData, PelSeverity::ERROR, 10600746eeebSSunny Srivastava errIntfForBlankSystemVPD); 10619094d4f6SSunnySrivastava1984 continue; 10629094d4f6SSunnySrivastava1984 } 10639094d4f6SSunnySrivastava1984 } 10649094d4f6SSunnySrivastava1984 } 10659094d4f6SSunnySrivastava1984 } 10669094d4f6SSunnySrivastava1984 } 10679094d4f6SSunnySrivastava1984 } 10689094d4f6SSunnySrivastava1984 10699094d4f6SSunnySrivastava1984 /** 10707ce68724Salpana07 * @brief This checks for is this FRU a processor 10717ce68724Salpana07 * And if yes, then checks for is this primary 10727ce68724Salpana07 * 10737ce68724Salpana07 * @param[in] js- vpd json to get the information about this FRU 10747ce68724Salpana07 * @param[in] filePath- FRU vpd 10757ce68724Salpana07 * 10767ce68724Salpana07 * @return true/false 10777ce68724Salpana07 */ 10787ce68724Salpana07 bool isThisPrimaryProcessor(nlohmann::json& js, const string& filePath) 10797ce68724Salpana07 { 10807ce68724Salpana07 bool isProcessor = false; 10817ce68724Salpana07 bool isPrimary = false; 10827ce68724Salpana07 10837ce68724Salpana07 for (const auto& item : js["frus"][filePath]) 10847ce68724Salpana07 { 10857ce68724Salpana07 if (item.find("extraInterfaces") != item.end()) 10867ce68724Salpana07 { 10877ce68724Salpana07 for (const auto& eI : item["extraInterfaces"].items()) 10887ce68724Salpana07 { 10897ce68724Salpana07 if (eI.key().find("Inventory.Item.Cpu") != string::npos) 10907ce68724Salpana07 { 10917ce68724Salpana07 isProcessor = true; 10927ce68724Salpana07 } 10937ce68724Salpana07 } 10947ce68724Salpana07 } 10957ce68724Salpana07 10967ce68724Salpana07 if (isProcessor) 10977ce68724Salpana07 { 10987ce68724Salpana07 string cpuType = item.value("cpuType", ""); 10997ce68724Salpana07 if (cpuType == "primary") 11007ce68724Salpana07 { 11017ce68724Salpana07 isPrimary = true; 11027ce68724Salpana07 } 11037ce68724Salpana07 } 11047ce68724Salpana07 } 11057ce68724Salpana07 11067ce68724Salpana07 return (isProcessor && isPrimary); 11077ce68724Salpana07 } 11087ce68724Salpana07 11097ce68724Salpana07 /** 11107ce68724Salpana07 * @brief This finds DIMM vpd in vpd json and enables them by binding the device 11117ce68724Salpana07 * driver 11127ce68724Salpana07 * @param[in] js- vpd json to iterate through and take action if it is DIMM 11137ce68724Salpana07 */ 11147ce68724Salpana07 void doEnableAllDimms(nlohmann::json& js) 11157ce68724Salpana07 { 11167ce68724Salpana07 // iterate over each fru 11177ce68724Salpana07 for (const auto& eachFru : js["frus"].items()) 11187ce68724Salpana07 { 11197ce68724Salpana07 // skip the driver binding if eeprom already exists 11207ce68724Salpana07 if (fs::exists(eachFru.key())) 11217ce68724Salpana07 { 11227ce68724Salpana07 continue; 11237ce68724Salpana07 } 11247ce68724Salpana07 11257ce68724Salpana07 for (const auto& eachInventory : eachFru.value()) 11267ce68724Salpana07 { 11277ce68724Salpana07 if (eachInventory.find("extraInterfaces") != eachInventory.end()) 11287ce68724Salpana07 { 11297ce68724Salpana07 for (const auto& eI : eachInventory["extraInterfaces"].items()) 11307ce68724Salpana07 { 11317ce68724Salpana07 if (eI.key().find("Inventory.Item.Dimm") != string::npos) 11327ce68724Salpana07 { 11337ce68724Salpana07 string dimmVpd = eachFru.key(); 11347ce68724Salpana07 // fetch it from 11357ce68724Salpana07 // "/sys/bus/i2c/drivers/at24/414-0050/eeprom" 11367ce68724Salpana07 11377ce68724Salpana07 regex matchPatern("([0-9]+-[0-9]{4})"); 11387ce68724Salpana07 smatch matchFound; 11397ce68724Salpana07 if (regex_search(dimmVpd, matchFound, matchPatern)) 11407ce68724Salpana07 { 11417ce68724Salpana07 vector<string> i2cReg; 11427ce68724Salpana07 boost::split(i2cReg, matchFound.str(0), 11437ce68724Salpana07 boost::is_any_of("-")); 11447ce68724Salpana07 11457ce68724Salpana07 // remove 0s from begining 11467ce68724Salpana07 const regex pattern("^0+(?!$)"); 11477ce68724Salpana07 for (auto& i : i2cReg) 11487ce68724Salpana07 { 11497ce68724Salpana07 i = regex_replace(i, pattern, ""); 11507ce68724Salpana07 } 11517ce68724Salpana07 11527ce68724Salpana07 if (i2cReg.size() == 2) 11537ce68724Salpana07 { 11547ce68724Salpana07 // echo 24c32 0x50 > 11557ce68724Salpana07 // /sys/bus/i2c/devices/i2c-16/new_device 11567ce68724Salpana07 string cmnd = "echo 24c32 0x" + i2cReg[1] + 11577ce68724Salpana07 " > /sys/bus/i2c/devices/i2c-" + 11587ce68724Salpana07 i2cReg[0] + "/new_device"; 11597ce68724Salpana07 11607ce68724Salpana07 executeCmd(cmnd); 11617ce68724Salpana07 } 11627ce68724Salpana07 } 11637ce68724Salpana07 } 11647ce68724Salpana07 } 11657ce68724Salpana07 } 11667ce68724Salpana07 } 11677ce68724Salpana07 } 11687ce68724Salpana07 } 11697ce68724Salpana07 11707ce68724Salpana07 /** 11716abdeb61SPriyanga Ramasamy * @brief Check if the given CPU is an IO only chip. 11726abdeb61SPriyanga Ramasamy * The CPU is termed as IO, whose all of the cores are bad and can never be 11736abdeb61SPriyanga Ramasamy * used. Those CPU chips can be used for IO purpose like connecting PCIe devices 11746abdeb61SPriyanga Ramasamy * etc., The CPU whose every cores are bad, can be identified from the CP00 11756abdeb61SPriyanga Ramasamy * record's PG keyword, only if all of the 8 EQs' value equals 0xE7F9FF. (1EQ 11766abdeb61SPriyanga Ramasamy * has 4 cores grouped together by sharing its cache memory.) 11776abdeb61SPriyanga Ramasamy * @param [in] pgKeyword - PG Keyword of CPU. 11786abdeb61SPriyanga Ramasamy * @return true if the given cpu is an IO, false otherwise. 11796abdeb61SPriyanga Ramasamy */ 11806abdeb61SPriyanga Ramasamy static bool isCPUIOGoodOnly(const string& pgKeyword) 11816abdeb61SPriyanga Ramasamy { 11826abdeb61SPriyanga Ramasamy const unsigned char io[] = {0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 11836abdeb61SPriyanga Ramasamy 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 11846abdeb61SPriyanga Ramasamy 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF}; 11856abdeb61SPriyanga Ramasamy // EQ0 index (in PG keyword) starts at 97 (with offset starting from 0). 11866abdeb61SPriyanga Ramasamy // Each EQ carries 3 bytes of data. Totally there are 8 EQs. If all EQs' 11876abdeb61SPriyanga Ramasamy // value equals 0xE7F9FF, then the cpu has no good cores and its treated as 11886abdeb61SPriyanga Ramasamy // IO. 11896abdeb61SPriyanga Ramasamy if (memcmp(io, pgKeyword.data() + 97, 24) == 0) 11906abdeb61SPriyanga Ramasamy { 11916abdeb61SPriyanga Ramasamy return true; 11926abdeb61SPriyanga Ramasamy } 11936abdeb61SPriyanga Ramasamy 11946abdeb61SPriyanga Ramasamy // The CPU is not an IO 11956abdeb61SPriyanga Ramasamy return false; 11966abdeb61SPriyanga Ramasamy } 11976abdeb61SPriyanga Ramasamy 11986abdeb61SPriyanga Ramasamy /** 11998e140a1cSPriyangaRamasamy * @brief Populate Dbus. 1200abb87edaSPriyangaRamasamy * This method invokes all the populateInterface functions 1201abb87edaSPriyangaRamasamy * and notifies PIM about dbus object. 12028e140a1cSPriyangaRamasamy * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the 12038e140a1cSPriyangaRamasamy * input. 1204abb87edaSPriyangaRamasamy * @param[in] js - Inventory json object 1205abb87edaSPriyangaRamasamy * @param[in] filePath - Path of the vpd file 1206abb87edaSPriyangaRamasamy * @param[in] preIntrStr - Interface string 1207abb87edaSPriyangaRamasamy */ 1208abb87edaSPriyangaRamasamy template <typename T> 12099094d4f6SSunnySrivastava1984 static void populateDbus(T& vpdMap, nlohmann::json& js, const string& filePath) 1210abb87edaSPriyangaRamasamy { 1211abb87edaSPriyangaRamasamy inventory::InterfaceMap interfaces; 1212abb87edaSPriyangaRamasamy inventory::ObjectMap objects; 1213abb87edaSPriyangaRamasamy inventory::PropertyMap prop; 12146aa5450eSShantappa Teekappanavar string ccinFromVpd; 1215abb87edaSPriyangaRamasamy 121650f60bf8SSantosh Puranik bool isSystemVpd = (filePath == systemVpdFilePath); 121750f60bf8SSantosh Puranik if constexpr (is_same<T, Parsed>::value) 121850f60bf8SSantosh Puranik { 12196aa5450eSShantappa Teekappanavar ccinFromVpd = getKwVal(vpdMap, "VINI", "CC"); 12206aa5450eSShantappa Teekappanavar transform(ccinFromVpd.begin(), ccinFromVpd.end(), ccinFromVpd.begin(), 12216aa5450eSShantappa Teekappanavar ::toupper); 12226aa5450eSShantappa Teekappanavar 122350f60bf8SSantosh Puranik if (isSystemVpd) 122450f60bf8SSantosh Puranik { 122550f60bf8SSantosh Puranik std::vector<std::string> interfaces = {motherBoardInterface}; 122650f60bf8SSantosh Puranik // call mapper to check for object path creation 122750f60bf8SSantosh Puranik MapperResponse subTree = 122850f60bf8SSantosh Puranik getObjectSubtreeForInterfaces(pimPath, 0, interfaces); 122950f60bf8SSantosh Puranik string mboardPath = 123050f60bf8SSantosh Puranik js["frus"][filePath].at(0).value("inventoryPath", ""); 123150f60bf8SSantosh Puranik 123250f60bf8SSantosh Puranik // Attempt system VPD restore if we have a motherboard 123350f60bf8SSantosh Puranik // object in the inventory. 123450f60bf8SSantosh Puranik if ((subTree.size() != 0) && 123550f60bf8SSantosh Puranik (subTree.find(pimPath + mboardPath) != subTree.end())) 123650f60bf8SSantosh Puranik { 12373c24414fSSunny Srivastava restoreSystemVPD(vpdMap, mboardPath); 123850f60bf8SSantosh Puranik } 123950f60bf8SSantosh Puranik else 124050f60bf8SSantosh Puranik { 124150f60bf8SSantosh Puranik log<level::ERR>("No object path found"); 124250f60bf8SSantosh Puranik } 124350f60bf8SSantosh Puranik } 12447ce68724Salpana07 else 12457ce68724Salpana07 { 12467ce68724Salpana07 // check if it is processor vpd. 12477ce68724Salpana07 auto isPrimaryCpu = isThisPrimaryProcessor(js, filePath); 12487ce68724Salpana07 12497ce68724Salpana07 if (isPrimaryCpu) 12507ce68724Salpana07 { 12517ce68724Salpana07 auto ddVersion = getKwVal(vpdMap, "CRP0", "DD"); 12527ce68724Salpana07 12537ce68724Salpana07 auto chipVersion = atoi(ddVersion.substr(1, 2).c_str()); 12547ce68724Salpana07 12557ce68724Salpana07 if (chipVersion >= 2) 12567ce68724Salpana07 { 12577ce68724Salpana07 doEnableAllDimms(js); 12587ce68724Salpana07 } 12597ce68724Salpana07 } 12607ce68724Salpana07 } 126150f60bf8SSantosh Puranik } 126250f60bf8SSantosh Puranik 1263f3e69689SSantosh Puranik auto processFactoryReset = false; 1264f3e69689SSantosh Puranik 126532c687f5SPriyanga Ramasamy if (isSystemVpd) 126632c687f5SPriyanga Ramasamy { 126732c687f5SPriyanga Ramasamy string systemJsonName{}; 126832c687f5SPriyanga Ramasamy if constexpr (is_same<T, Parsed>::value) 126932c687f5SPriyanga Ramasamy { 127032c687f5SPriyanga Ramasamy // pick the right system json 127132c687f5SPriyanga Ramasamy systemJsonName = getSystemsJson(vpdMap); 127232c687f5SPriyanga Ramasamy } 127332c687f5SPriyanga Ramasamy 127432c687f5SPriyanga Ramasamy fs::path target = systemJsonName; 127532c687f5SPriyanga Ramasamy fs::path link = INVENTORY_JSON_SYM_LINK; 127632c687f5SPriyanga Ramasamy 1277f3e69689SSantosh Puranik // If the symlink does not exist, we treat that as a factory reset 1278f3e69689SSantosh Puranik processFactoryReset = !fs::exists(INVENTORY_JSON_SYM_LINK); 1279f3e69689SSantosh Puranik 128032c687f5SPriyanga Ramasamy // Create the directory for hosting the symlink 128132c687f5SPriyanga Ramasamy fs::create_directories(VPD_FILES_PATH); 128232c687f5SPriyanga Ramasamy // unlink the symlink previously created (if any) 128332c687f5SPriyanga Ramasamy remove(INVENTORY_JSON_SYM_LINK); 128432c687f5SPriyanga Ramasamy // create a new symlink based on the system 128532c687f5SPriyanga Ramasamy fs::create_symlink(target, link); 128632c687f5SPriyanga Ramasamy 128732c687f5SPriyanga Ramasamy // Reloading the json 128832c687f5SPriyanga Ramasamy ifstream inventoryJson(link); 128932c687f5SPriyanga Ramasamy js = json::parse(inventoryJson); 129032c687f5SPriyanga Ramasamy inventoryJson.close(); 129132c687f5SPriyanga Ramasamy } 129232c687f5SPriyanga Ramasamy 1293abb87edaSPriyangaRamasamy for (const auto& item : js["frus"][filePath]) 1294abb87edaSPriyangaRamasamy { 1295abb87edaSPriyangaRamasamy const auto& objectPath = item["inventoryPath"]; 1296abb87edaSPriyangaRamasamy sdbusplus::message::object_path object(objectPath); 12979094d4f6SSunnySrivastava1984 12986aa5450eSShantappa Teekappanavar vector<string> ccinList; 12996aa5450eSShantappa Teekappanavar if (item.find("ccin") != item.end()) 13006aa5450eSShantappa Teekappanavar { 13016aa5450eSShantappa Teekappanavar for (const auto& cc : item["ccin"]) 13026aa5450eSShantappa Teekappanavar { 13036aa5450eSShantappa Teekappanavar string ccin = cc; 13046aa5450eSShantappa Teekappanavar transform(ccin.begin(), ccin.end(), ccin.begin(), ::toupper); 13056aa5450eSShantappa Teekappanavar ccinList.push_back(ccin); 13066aa5450eSShantappa Teekappanavar } 13076aa5450eSShantappa Teekappanavar } 13086aa5450eSShantappa Teekappanavar 13096aa5450eSShantappa Teekappanavar if (!ccinFromVpd.empty() && !ccinList.empty() && 13106aa5450eSShantappa Teekappanavar (find(ccinList.begin(), ccinList.end(), ccinFromVpd) == 13116aa5450eSShantappa Teekappanavar ccinList.end())) 13126aa5450eSShantappa Teekappanavar { 13136aa5450eSShantappa Teekappanavar continue; 13146aa5450eSShantappa Teekappanavar } 13156aa5450eSShantappa Teekappanavar 1316e3fed701SPriyanga Ramasamy if ((isSystemVpd) || (item.value("noprime", false))) 1317d3a379a6SSantosh Puranik { 1318e3fed701SPriyanga Ramasamy 1319e3fed701SPriyanga Ramasamy // Populate one time properties for the system VPD and its sub-frus 1320e3fed701SPriyanga Ramasamy // and for other non-primeable frus. 1321d3a379a6SSantosh Puranik // For the remaining FRUs, this will get handled as a part of 1322d3a379a6SSantosh Puranik // priming the inventory. 1323d3a379a6SSantosh Puranik setOneTimeProperties(objectPath, interfaces); 1324d3a379a6SSantosh Puranik } 1325d3a379a6SSantosh Puranik 1326abb87edaSPriyangaRamasamy // Populate the VPD keywords and the common interfaces only if we 1327abb87edaSPriyangaRamasamy // are asked to inherit that data from the VPD, else only add the 1328abb87edaSPriyangaRamasamy // extraInterfaces. 1329abb87edaSPriyangaRamasamy if (item.value("inherit", true)) 1330abb87edaSPriyangaRamasamy { 133158e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 1332abb87edaSPriyangaRamasamy { 13338e140a1cSPriyangaRamasamy // Each record in the VPD becomes an interface and all 13348e140a1cSPriyangaRamasamy // keyword within the record are properties under that 13358e140a1cSPriyangaRamasamy // interface. 1336abb87edaSPriyangaRamasamy for (const auto& record : vpdMap) 1337abb87edaSPriyangaRamasamy { 1338abb87edaSPriyangaRamasamy populateFruSpecificInterfaces( 1339e12b181bSSunnySrivastava1984 record.second, ipzVpdInf + record.first, interfaces); 1340abb87edaSPriyangaRamasamy } 1341abb87edaSPriyangaRamasamy } 134258e22145SAlpana Kumari else if constexpr (is_same<T, KeywordVpdMap>::value) 1343abb87edaSPriyangaRamasamy { 1344e12b181bSSunnySrivastava1984 populateFruSpecificInterfaces(vpdMap, kwdVpdInf, interfaces); 1345abb87edaSPriyangaRamasamy } 134688edeb6fSSantosh Puranik if (js.find("commonInterfaces") != js.end()) 134788edeb6fSSantosh Puranik { 134888edeb6fSSantosh Puranik populateInterfaces(js["commonInterfaces"], interfaces, vpdMap, 134988edeb6fSSantosh Puranik isSystemVpd); 135088edeb6fSSantosh Puranik } 1351abb87edaSPriyangaRamasamy } 13520859eb65SSantosh Puranik else 13530859eb65SSantosh Puranik { 13540859eb65SSantosh Puranik // Check if we have been asked to inherit specific record(s) 135558e22145SAlpana Kumari if constexpr (is_same<T, Parsed>::value) 13560859eb65SSantosh Puranik { 13570859eb65SSantosh Puranik if (item.find("copyRecords") != item.end()) 13580859eb65SSantosh Puranik { 13590859eb65SSantosh Puranik for (const auto& record : item["copyRecords"]) 13600859eb65SSantosh Puranik { 13610859eb65SSantosh Puranik const string& recordName = record; 13620859eb65SSantosh Puranik if (vpdMap.find(recordName) != vpdMap.end()) 13630859eb65SSantosh Puranik { 13640859eb65SSantosh Puranik populateFruSpecificInterfaces( 1365e12b181bSSunnySrivastava1984 vpdMap.at(recordName), ipzVpdInf + recordName, 13660859eb65SSantosh Puranik interfaces); 13670859eb65SSantosh Puranik } 13680859eb65SSantosh Puranik } 13690859eb65SSantosh Puranik } 13700859eb65SSantosh Puranik } 13710859eb65SSantosh Puranik } 1372abb87edaSPriyangaRamasamy // Populate interfaces and properties that are common to every FRU 13738e140a1cSPriyangaRamasamy // and additional interface that might be defined on a per-FRU 13748e140a1cSPriyangaRamasamy // basis. 1375abb87edaSPriyangaRamasamy if (item.find("extraInterfaces") != item.end()) 1376abb87edaSPriyangaRamasamy { 137788edeb6fSSantosh Puranik populateInterfaces(item["extraInterfaces"], interfaces, vpdMap, 137888edeb6fSSantosh Puranik isSystemVpd); 13796abdeb61SPriyanga Ramasamy if constexpr (is_same<T, Parsed>::value) 13806abdeb61SPriyanga Ramasamy { 13816abdeb61SPriyanga Ramasamy if (item["extraInterfaces"].find( 13826abdeb61SPriyanga Ramasamy "xyz.openbmc_project.Inventory.Item.Cpu") != 13836abdeb61SPriyanga Ramasamy item["extraInterfaces"].end()) 13846abdeb61SPriyanga Ramasamy { 13856abdeb61SPriyanga Ramasamy if (isCPUIOGoodOnly(getKwVal(vpdMap, "CP00", "PG"))) 13866abdeb61SPriyanga Ramasamy { 13872c607a98SPriyanga Ramasamy interfaces[invItemIntf]["PrettyName"] = "IO Module"; 13886abdeb61SPriyanga Ramasamy } 13896abdeb61SPriyanga Ramasamy } 13906abdeb61SPriyanga Ramasamy } 1391abb87edaSPriyangaRamasamy } 1392e358acbbSPriyanga Ramasamy 1393e358acbbSPriyanga Ramasamy // embedded property(true or false) says whether the subfru is embedded 1394e358acbbSPriyanga Ramasamy // into the parent fru (or) not. VPD sets Present property only for 1395e358acbbSPriyanga Ramasamy // embedded frus. If the subfru is not an embedded FRU, the subfru may 1396e358acbbSPriyanga Ramasamy // or may not be physically present. Those non embedded frus will always 1397e358acbbSPriyanga Ramasamy // have Present=false irrespective of its physical presence or absence. 1398e358acbbSPriyanga Ramasamy // Eg: nvme drive in nvme slot is not an embedded FRU. So don't set 1399e358acbbSPriyanga Ramasamy // Present to true for such sub frus. 1400e358acbbSPriyanga Ramasamy // Eg: ethernet port is embedded into bmc card. So set Present to true 1401e358acbbSPriyanga Ramasamy // for such sub frus. Also donot populate present property for embedded 1402e358acbbSPriyanga Ramasamy // subfru which is synthesized. Currently there is no subfru which are 1403e358acbbSPriyanga Ramasamy // both embedded and synthesized. But still the case is handled here. 1404e358acbbSPriyanga Ramasamy if ((item.value("embedded", true)) && 1405e358acbbSPriyanga Ramasamy (!item.value("synthesized", false))) 1406e358acbbSPriyanga Ramasamy { 1407aa8a893eSPriyanga Ramasamy inventory::PropertyMap presProp; 1408aa8a893eSPriyanga Ramasamy presProp.emplace("Present", true); 1409aa8a893eSPriyanga Ramasamy insertOrMerge(interfaces, invItemIntf, move(presProp)); 1410e358acbbSPriyanga Ramasamy } 1411aa8a893eSPriyanga Ramasamy 1412f3e69689SSantosh Puranik if constexpr (is_same<T, Parsed>::value) 1413f3e69689SSantosh Puranik { 1414f3e69689SSantosh Puranik // Restore asset tag, if needed 1415f3e69689SSantosh Puranik if (processFactoryReset && objectPath == "/system") 1416f3e69689SSantosh Puranik { 1417f3e69689SSantosh Puranik fillAssetTag(interfaces, vpdMap); 1418f3e69689SSantosh Puranik } 1419f3e69689SSantosh Puranik } 1420f3e69689SSantosh Puranik 1421abb87edaSPriyangaRamasamy objects.emplace(move(object), move(interfaces)); 1422abb87edaSPriyangaRamasamy } 1423abb87edaSPriyangaRamasamy 14248e140a1cSPriyangaRamasamy if (isSystemVpd) 14258e140a1cSPriyangaRamasamy { 14268e140a1cSPriyangaRamasamy inventory::ObjectMap primeObject = primeInventory(js, vpdMap); 14278e140a1cSPriyangaRamasamy objects.insert(primeObject.begin(), primeObject.end()); 142865b83601SAlpana Kumari 1429f05effdbSAlpana Kumari // set the U-boot environment variable for device-tree 1430f05effdbSAlpana Kumari if constexpr (is_same<T, Parsed>::value) 1431f05effdbSAlpana Kumari { 1432e5f177a5SSantosh Puranik setDevTreeEnv(fs::path(getSystemsJson(vpdMap)).filename()); 1433f05effdbSAlpana Kumari } 14348e140a1cSPriyangaRamasamy } 14358e140a1cSPriyangaRamasamy 1436abb87edaSPriyangaRamasamy // Notify PIM 14376c71c9dcSSunny Srivastava common::utility::callPIM(move(objects)); 1438abb87edaSPriyangaRamasamy } 1439abb87edaSPriyangaRamasamy 1440abb87edaSPriyangaRamasamy int main(int argc, char** argv) 1441abb87edaSPriyangaRamasamy { 1442abb87edaSPriyangaRamasamy int rc = 0; 1443a20be8ecSSunnySrivastava1984 json js{}; 1444c2fe40f8SPriyangaRamasamy Binary vpdVector{}; 1445c2fe40f8SPriyangaRamasamy string file{}; 1446a20be8ecSSunnySrivastava1984 // map to hold additional data in case of logging pel 1447a20be8ecSSunnySrivastava1984 PelAdditionalData additionalData{}; 1448a20be8ecSSunnySrivastava1984 1449a20be8ecSSunnySrivastava1984 // this is needed to hold base fru inventory path in case there is ECC or 1450a20be8ecSSunnySrivastava1984 // vpd exception while parsing the file 1451a20be8ecSSunnySrivastava1984 std::string baseFruInventoryPath = {}; 1452abb87edaSPriyangaRamasamy 14530746eeebSSunny Srivastava // severity for PEL 14540746eeebSSunny Srivastava PelSeverity pelSeverity = PelSeverity::WARNING; 14550746eeebSSunny Srivastava 1456abb87edaSPriyangaRamasamy try 1457abb87edaSPriyangaRamasamy { 1458abb87edaSPriyangaRamasamy App app{"ibm-read-vpd - App to read IPZ format VPD, parse it and store " 1459abb87edaSPriyangaRamasamy "in DBUS"}; 1460abb87edaSPriyangaRamasamy 1461abb87edaSPriyangaRamasamy app.add_option("-f, --file", file, "File containing VPD (IPZ/KEYWORD)") 14622f793048SAlpana Kumari ->required(); 1463abb87edaSPriyangaRamasamy 1464abb87edaSPriyangaRamasamy CLI11_PARSE(app, argc, argv); 1465abb87edaSPriyangaRamasamy 14660746eeebSSunny Srivastava // PEL severity should be ERROR in case of any system VPD failure 14670746eeebSSunny Srivastava if (file == systemVpdFilePath) 14680746eeebSSunny Srivastava { 14690746eeebSSunny Srivastava pelSeverity = PelSeverity::ERROR; 14700746eeebSSunny Srivastava } 14710746eeebSSunny Srivastava 14720246a4d7SSantosh Puranik auto jsonToParse = INVENTORY_JSON_DEFAULT; 14730246a4d7SSantosh Puranik 14740246a4d7SSantosh Puranik // If the symlink exists, it means it has been setup for us, switch the 14750246a4d7SSantosh Puranik // path 14760246a4d7SSantosh Puranik if (fs::exists(INVENTORY_JSON_SYM_LINK)) 14770246a4d7SSantosh Puranik { 14780246a4d7SSantosh Puranik jsonToParse = INVENTORY_JSON_SYM_LINK; 14790246a4d7SSantosh Puranik } 14800246a4d7SSantosh Puranik 1481abb87edaSPriyangaRamasamy // Make sure that the file path we get is for a supported EEPROM 14820246a4d7SSantosh Puranik ifstream inventoryJson(jsonToParse); 1483a20be8ecSSunnySrivastava1984 if (!inventoryJson) 1484a20be8ecSSunnySrivastava1984 { 14850746eeebSSunny Srivastava throw(VpdJsonException("Failed to access Json path", jsonToParse)); 1486a20be8ecSSunnySrivastava1984 } 1487a20be8ecSSunnySrivastava1984 1488a20be8ecSSunnySrivastava1984 try 1489a20be8ecSSunnySrivastava1984 { 1490a20be8ecSSunnySrivastava1984 js = json::parse(inventoryJson); 1491a20be8ecSSunnySrivastava1984 } 14928e15b93aSPatrick Williams catch (const json::parse_error& ex) 1493a20be8ecSSunnySrivastava1984 { 14940746eeebSSunny Srivastava throw(VpdJsonException("Json parsing failed", jsonToParse)); 1495a20be8ecSSunnySrivastava1984 } 1496abb87edaSPriyangaRamasamy 149712e24ff3SSantosh Puranik // Do we have the mandatory "frus" section? 149812e24ff3SSantosh Puranik if (js.find("frus") == js.end()) 149912e24ff3SSantosh Puranik { 150012e24ff3SSantosh Puranik throw(VpdJsonException("FRUs section not found in JSON", 150112e24ff3SSantosh Puranik jsonToParse)); 150212e24ff3SSantosh Puranik } 150312e24ff3SSantosh Puranik 1504647868edSPriyangaRamasamy // Check if it's a udev path - patterned as(/ahb/ahb:apb/ahb:apb:bus@) 1505647868edSPriyangaRamasamy if (file.find("/ahb:apb") != string::npos) 1506647868edSPriyangaRamasamy { 1507647868edSPriyangaRamasamy // Translate udev path to a generic /sys/bus/.. file path. 1508647868edSPriyangaRamasamy udevToGenericPath(file); 150912e24ff3SSantosh Puranik 151012e24ff3SSantosh Puranik if ((js["frus"].find(file) != js["frus"].end()) && 151150f60bf8SSantosh Puranik (file == systemVpdFilePath)) 1512647868edSPriyangaRamasamy { 15133c24414fSSunny Srivastava // We need manager service active to process restoring of 15143c24414fSSunny Srivastava // system VPD on hardware. So in case any system restore is 15153c24414fSSunny Srivastava // required, update hardware in the second trigger of parser 15163c24414fSSunny Srivastava // code for system vpd file path. 15173c24414fSSunny Srivastava 15183c24414fSSunny Srivastava std::vector<std::string> interfaces{motherBoardInterface}; 15193c24414fSSunny Srivastava 15203c24414fSSunny Srivastava // call mapper to check for object path creation 15213c24414fSSunny Srivastava MapperResponse subTree = 15223c24414fSSunny Srivastava getObjectSubtreeForInterfaces(pimPath, 0, interfaces); 15233c24414fSSunny Srivastava string mboardPath = 15243c24414fSSunny Srivastava js["frus"][file].at(0).value("inventoryPath", ""); 15253c24414fSSunny Srivastava 15263c24414fSSunny Srivastava // Attempt system VPD restore if we have a motherboard 15273c24414fSSunny Srivastava // object in the inventory. 15283c24414fSSunny Srivastava if ((subTree.size() != 0) && 15293c24414fSSunny Srivastava (subTree.find(pimPath + mboardPath) != subTree.end())) 15303c24414fSSunny Srivastava { 15313c24414fSSunny Srivastava vpdVector = getVpdDataInVector(js, file); 15323c24414fSSunny Srivastava ParserInterface* parser = 15333c24414fSSunny Srivastava ParserFactory::getParser(vpdVector); 15343c24414fSSunny Srivastava variant<KeywordVpdMap, Store> parseResult; 15353c24414fSSunny Srivastava parseResult = parser->parse(); 15363c24414fSSunny Srivastava 15373c24414fSSunny Srivastava if (auto pVal = get_if<Store>(&parseResult)) 15383c24414fSSunny Srivastava { 15393c24414fSSunny Srivastava // map to hold all the keywords whose value is blank and 15403c24414fSSunny Srivastava // needs to be updated at standby. 15413c24414fSSunny Srivastava vector<RestoredEeproms> blankSystemVpdProperties{}; 15423c24414fSSunny Srivastava getListOfBlankSystemVpd(pVal->getVpdMap(), mboardPath, 15433c24414fSSunny Srivastava blankSystemVpdProperties); 15443c24414fSSunny Srivastava 15453c24414fSSunny Srivastava // if system VPD restore is required, update the 15463c24414fSSunny Srivastava // EEPROM 15473c24414fSSunny Srivastava for (const auto& item : blankSystemVpdProperties) 15483c24414fSSunny Srivastava { 15493c24414fSSunny Srivastava updateHardware(get<0>(item), get<1>(item), 15503c24414fSSunny Srivastava get<2>(item), get<3>(item)); 15513c24414fSSunny Srivastava } 15523c24414fSSunny Srivastava } 15533c24414fSSunny Srivastava else 15543c24414fSSunny Srivastava { 15553c24414fSSunny Srivastava std::cout << "Not a valid format to restore system VPD" 15563c24414fSSunny Srivastava << std::endl; 15573c24414fSSunny Srivastava } 15583c24414fSSunny Srivastava // release the parser object 15593c24414fSSunny Srivastava ParserFactory::freeParser(parser); 15603c24414fSSunny Srivastava } 15613c24414fSSunny Srivastava else 15623c24414fSSunny Srivastava { 15633c24414fSSunny Srivastava log<level::ERR>("No object path found"); 15643c24414fSSunny Srivastava } 1565647868edSPriyangaRamasamy return 0; 1566647868edSPriyangaRamasamy } 1567647868edSPriyangaRamasamy } 1568647868edSPriyangaRamasamy 1569647868edSPriyangaRamasamy if (file.empty()) 1570647868edSPriyangaRamasamy { 1571647868edSPriyangaRamasamy cerr << "The EEPROM path <" << file << "> is not valid."; 1572647868edSPriyangaRamasamy return 0; 1573647868edSPriyangaRamasamy } 157412e24ff3SSantosh Puranik if (js["frus"].find(file) == js["frus"].end()) 1575abb87edaSPriyangaRamasamy { 157688edeb6fSSantosh Puranik return 0; 1577abb87edaSPriyangaRamasamy } 1578abb87edaSPriyangaRamasamy 15792f793048SAlpana Kumari if (!fs::exists(file)) 15802f793048SAlpana Kumari { 15812f793048SAlpana Kumari cout << "Device path: " << file 15822f793048SAlpana Kumari << " does not exist. Spurious udev event? Exiting." << endl; 15832f793048SAlpana Kumari return 0; 15842f793048SAlpana Kumari } 15852f793048SAlpana Kumari 1586a20be8ecSSunnySrivastava1984 baseFruInventoryPath = js["frus"][file][0]["inventoryPath"]; 15878589375fSSantosh Puranik // Check if we can read the VPD file based on the power state 158827a5e95aSSantosh Puranik // We skip reading VPD when the power is ON in two scenarios: 158931d50fa7SSantosh Puranik // 1) The eeprom we are trying to read is that of the system VPD and the 159031d50fa7SSantosh Puranik // JSON symlink is already setup (the symlink's existence tells us we 159131d50fa7SSantosh Puranik // are not coming out of a factory reset) 159231d50fa7SSantosh Puranik // 2) The JSON tells us that the FRU EEPROM cannot be 159331d50fa7SSantosh Puranik // read when we are powered ON. 159427a5e95aSSantosh Puranik if (js["frus"][file].at(0).value("powerOffOnly", false) || 159531d50fa7SSantosh Puranik (file == systemVpdFilePath && fs::exists(INVENTORY_JSON_SYM_LINK))) 15968589375fSSantosh Puranik { 15978589375fSSantosh Puranik if ("xyz.openbmc_project.State.Chassis.PowerState.On" == 15988589375fSSantosh Puranik getPowerState()) 15998589375fSSantosh Puranik { 16008589375fSSantosh Puranik cout << "This VPD cannot be read when power is ON" << endl; 16018589375fSSantosh Puranik return 0; 16028589375fSSantosh Puranik } 16038589375fSSantosh Puranik } 1604a20be8ecSSunnySrivastava1984 1605e9c57535SSantosh Puranik // Check if this VPD should be recollected at all 1606e9c57535SSantosh Puranik if (!needsRecollection(js, file)) 1607e9c57535SSantosh Puranik { 1608e9c57535SSantosh Puranik cout << "Skip VPD recollection for: " << file << endl; 1609e9c57535SSantosh Puranik return 0; 1610e9c57535SSantosh Puranik } 1611e9c57535SSantosh Puranik 16122f793048SAlpana Kumari try 16132f793048SAlpana Kumari { 1614c2fe40f8SPriyangaRamasamy vpdVector = getVpdDataInVector(js, file); 161533c61c2dSPriyangaRamasamy ParserInterface* parser = ParserFactory::getParser(vpdVector); 16162f793048SAlpana Kumari variant<KeywordVpdMap, Store> parseResult; 16172f793048SAlpana Kumari parseResult = parser->parse(); 16189a19554cSSunnySrivastava1984 1619e12b181bSSunnySrivastava1984 if (auto pVal = get_if<Store>(&parseResult)) 1620abb87edaSPriyangaRamasamy { 1621e12b181bSSunnySrivastava1984 populateDbus(pVal->getVpdMap(), js, file); 1622e12b181bSSunnySrivastava1984 } 1623e12b181bSSunnySrivastava1984 else if (auto pVal = get_if<KeywordVpdMap>(&parseResult)) 1624abb87edaSPriyangaRamasamy { 1625e12b181bSSunnySrivastava1984 populateDbus(*pVal, js, file); 1626abb87edaSPriyangaRamasamy } 1627abb87edaSPriyangaRamasamy 1628e12b181bSSunnySrivastava1984 // release the parser object 1629e12b181bSSunnySrivastava1984 ParserFactory::freeParser(parser); 1630abb87edaSPriyangaRamasamy } 16318e15b93aSPatrick Williams catch (const exception& e) 16322f793048SAlpana Kumari { 1633735dee9bSAlpana Kumari executePostFailAction(js, file); 1634a504c3eeSPriyangaRamasamy throw; 16352f793048SAlpana Kumari } 16362f793048SAlpana Kumari } 1637a20be8ecSSunnySrivastava1984 catch (const VpdJsonException& ex) 1638a20be8ecSSunnySrivastava1984 { 1639a20be8ecSSunnySrivastava1984 additionalData.emplace("JSON_PATH", ex.getJsonPath()); 1640a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", ex.what()); 16410746eeebSSunny Srivastava createPEL(additionalData, pelSeverity, errIntfForJsonFailure); 1642a20be8ecSSunnySrivastava1984 1643a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 1644a20be8ecSSunnySrivastava1984 rc = -1; 1645a20be8ecSSunnySrivastava1984 } 1646a20be8ecSSunnySrivastava1984 catch (const VpdEccException& ex) 1647a20be8ecSSunnySrivastava1984 { 1648a20be8ecSSunnySrivastava1984 additionalData.emplace("DESCRIPTION", "ECC check failed"); 1649a20be8ecSSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 1650a20be8ecSSunnySrivastava1984 INVENTORY_PATH + baseFruInventoryPath); 16510746eeebSSunny Srivastava createPEL(additionalData, pelSeverity, errIntfForEccCheckFail); 1652c2fe40f8SPriyangaRamasamy dumpBadVpd(file, vpdVector); 1653a20be8ecSSunnySrivastava1984 cerr << ex.what() << "\n"; 1654a20be8ecSSunnySrivastava1984 rc = -1; 1655a20be8ecSSunnySrivastava1984 } 1656a20be8ecSSunnySrivastava1984 catch (const VpdDataException& ex) 1657a20be8ecSSunnySrivastava1984 { 16585cb3b1f3Salpana07 if (isThisPcieOnPass1planar(js, file)) 16595cb3b1f3Salpana07 { 16605cb3b1f3Salpana07 cout << "Pcie_device [" << file 16615cb3b1f3Salpana07 << "]'s VPD is not valid on PASS1 planar.Ignoring.\n"; 16625cb3b1f3Salpana07 rc = 0; 16635cb3b1f3Salpana07 } 166453b38ed0SSantosh Puranik else if (!(isPresent(js, file).value_or(true))) 166553b38ed0SSantosh Puranik { 166653b38ed0SSantosh Puranik cout << "FRU at: " << file 166753b38ed0SSantosh Puranik << " is not detected present. Ignore parser error.\n"; 166853b38ed0SSantosh Puranik rc = 0; 166953b38ed0SSantosh Puranik } 16705cb3b1f3Salpana07 else 16715cb3b1f3Salpana07 { 16725cb3b1f3Salpana07 string errorMsg = 16735cb3b1f3Salpana07 "VPD file is either empty or invalid. Parser failed for ["; 16745cb3b1f3Salpana07 errorMsg += file; 16755cb3b1f3Salpana07 errorMsg += "], with error = " + std::string(ex.what()); 16765cb3b1f3Salpana07 16775cb3b1f3Salpana07 additionalData.emplace("DESCRIPTION", errorMsg); 1678a20be8ecSSunnySrivastava1984 additionalData.emplace("CALLOUT_INVENTORY_PATH", 1679a20be8ecSSunnySrivastava1984 INVENTORY_PATH + baseFruInventoryPath); 16800746eeebSSunny Srivastava createPEL(additionalData, pelSeverity, errIntfForInvalidVPD); 16815cb3b1f3Salpana07 1682a20be8ecSSunnySrivastava1984 rc = -1; 1683a20be8ecSSunnySrivastava1984 } 16845cb3b1f3Salpana07 } 16858e15b93aSPatrick Williams catch (const exception& e) 1686abb87edaSPriyangaRamasamy { 1687c2fe40f8SPriyangaRamasamy dumpBadVpd(file, vpdVector); 1688abb87edaSPriyangaRamasamy cerr << e.what() << "\n"; 1689abb87edaSPriyangaRamasamy rc = -1; 1690abb87edaSPriyangaRamasamy } 1691abb87edaSPriyangaRamasamy 1692abb87edaSPriyangaRamasamy return rc; 1693abb87edaSPriyangaRamasamy }