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