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