1abb87edaSPriyangaRamasamy #include "config.h"
2abb87edaSPriyangaRamasamy 
36c71c9dcSSunny Srivastava #include "common_utility.hpp"
4abb87edaSPriyangaRamasamy #include "defines.hpp"
538ee9c8dSKantesh Nagaradder #include "editor_impl.hpp"
66c71c9dcSSunny Srivastava #include "ibm_vpd_utils.hpp"
7e12b181bSSunnySrivastava1984 #include "ipz_parser.hpp"
8abb87edaSPriyangaRamasamy #include "keyword_vpd_parser.hpp"
9a00936f8SAlpana Kumari #include "memory_vpd_parser.hpp"
10e12b181bSSunnySrivastava1984 #include "parser_factory.hpp"
11a20be8ecSSunnySrivastava1984 #include "vpd_exceptions.hpp"
12abb87edaSPriyangaRamasamy 
139094d4f6SSunnySrivastava1984 #include <assert.h>
148ea3f6d0SAlpana Kumari #include <ctype.h>
158ea3f6d0SAlpana Kumari 
16abb87edaSPriyangaRamasamy #include <CLI/CLI.hpp>
177ce68724Salpana07 #include <boost/algorithm/string.hpp>
18c78d887cSPatrick Williams #include <gpiod.hpp>
19c78d887cSPatrick Williams #include <phosphor-logging/log.hpp>
20c78d887cSPatrick Williams 
21c78d887cSPatrick Williams #include <algorithm>
2265b83601SAlpana Kumari #include <cstdarg>
23abb87edaSPriyangaRamasamy #include <exception>
2483a1d5deSPriyangaRamasamy #include <filesystem>
25abb87edaSPriyangaRamasamy #include <fstream>
26abb87edaSPriyangaRamasamy #include <iostream>
27abb87edaSPriyangaRamasamy #include <iterator>
287ce68724Salpana07 #include <regex>
29253fbe9fSSantosh Puranik #include <thread>
30abb87edaSPriyangaRamasamy 
31abb87edaSPriyangaRamasamy using namespace std;
32abb87edaSPriyangaRamasamy using namespace openpower::vpd;
33abb87edaSPriyangaRamasamy using namespace CLI;
34abb87edaSPriyangaRamasamy using namespace vpd::keyword::parser;
3583a1d5deSPriyangaRamasamy using namespace openpower::vpd::constants;
3683a1d5deSPriyangaRamasamy namespace fs = filesystem;
3783a1d5deSPriyangaRamasamy using json = nlohmann::json;
38e12b181bSSunnySrivastava1984 using namespace openpower::vpd::parser::factory;
39945a02d3SSunnySrivastava1984 using namespace openpower::vpd::inventory;
40a00936f8SAlpana Kumari using namespace openpower::vpd::memory::parser;
41e12b181bSSunnySrivastava1984 using namespace openpower::vpd::parser::interface;
42a20be8ecSSunnySrivastava1984 using namespace openpower::vpd::exceptions;
43280197e3SAndrew Geissler using namespace phosphor::logging;
4438ee9c8dSKantesh Nagaradder using namespace openpower::vpd::manager::editor;
45abb87edaSPriyangaRamasamy 
4688edeb6fSSantosh Puranik /**
4737992a65SSunny Srivastava  * @brief API declaration, Populate Dbus.
4837992a65SSunny Srivastava  *
4937992a65SSunny Srivastava  * This method invokes all the populateInterface functions
5037992a65SSunny Srivastava  * and notifies PIM about dbus object.
5137992a65SSunny Srivastava  *
5237992a65SSunny Srivastava  * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the
5337992a65SSunny Srivastava  * input.
5437992a65SSunny Srivastava  * @param[in] js - Inventory json object
5537992a65SSunny Srivastava  * @param[in] filePath - Path of the vpd file
5637992a65SSunny Srivastava  * @param[in] preIntrStr - Interface string
5737992a65SSunny Srivastava  */
5837992a65SSunny Srivastava template <typename T>
5937992a65SSunny Srivastava static void populateDbus(T& vpdMap, nlohmann::json& js, const string& filePath);
6037992a65SSunny Srivastava 
6137992a65SSunny Srivastava /**
62e9c57535SSantosh Puranik  * @brief Returns the BMC state
63e9c57535SSantosh Puranik  */
getBMCState()64e9c57535SSantosh Puranik static auto getBMCState()
65e9c57535SSantosh Puranik {
66e9c57535SSantosh Puranik     std::string bmcState;
67e9c57535SSantosh Puranik     try
68e9c57535SSantosh Puranik     {
69e9c57535SSantosh Puranik         auto bus = sdbusplus::bus::new_default();
70e9c57535SSantosh Puranik         auto properties = bus.new_method_call(
71e9c57535SSantosh Puranik             "xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0",
72e9c57535SSantosh Puranik             "org.freedesktop.DBus.Properties", "Get");
73e9c57535SSantosh Puranik         properties.append("xyz.openbmc_project.State.BMC");
74e9c57535SSantosh Puranik         properties.append("CurrentBMCState");
75e9c57535SSantosh Puranik         auto result = bus.call(properties);
76e9c57535SSantosh Puranik         std::variant<std::string> val;
77e9c57535SSantosh Puranik         result.read(val);
78e9c57535SSantosh Puranik         if (auto pVal = std::get_if<std::string>(&val))
79e9c57535SSantosh Puranik         {
80e9c57535SSantosh Puranik             bmcState = *pVal;
81e9c57535SSantosh Puranik         }
82e9c57535SSantosh Puranik     }
83e9c57535SSantosh Puranik     catch (const sdbusplus::exception::SdBusError& e)
84e9c57535SSantosh Puranik     {
85e9c57535SSantosh Puranik         // Ignore any error
86e9c57535SSantosh Puranik         std::cerr << "Failed to get BMC state: " << e.what() << "\n";
870b33b34fSJinu Joy Thomas         // Since we failed set to not ready state
880b33b34fSJinu Joy Thomas         bmcState = "xyz.openbmc_project.State.BMC.BMCState.NotReady";
89e9c57535SSantosh Puranik     }
90e9c57535SSantosh Puranik     return bmcState;
91e9c57535SSantosh Puranik }
92e9c57535SSantosh Puranik 
93e9c57535SSantosh Puranik /**
94e9c57535SSantosh Puranik  * @brief Check if the FRU is in the cache
95e9c57535SSantosh Puranik  *
96e9c57535SSantosh Puranik  * Checks if the FRU associated with the supplied D-Bus object path is already
97e9c57535SSantosh Puranik  * on D-Bus. This can be used to test if a VPD collection is required for this
98e9c57535SSantosh Puranik  * FRU. It uses the "xyz.openbmc_project.Inventory.Item, Present" property to
99e9c57535SSantosh Puranik  * determine the presence of a FRU in the cache.
100e9c57535SSantosh Puranik  *
101e9c57535SSantosh Puranik  * @param objectPath - The D-Bus object path without the PIM prefix.
102e9c57535SSantosh Puranik  * @return true if the object exists on D-Bus, false otherwise.
103e9c57535SSantosh Puranik  */
isFruInVpdCache(const std::string & objectPath)104e9c57535SSantosh Puranik static auto isFruInVpdCache(const std::string& objectPath)
105e9c57535SSantosh Puranik {
106e9c57535SSantosh Puranik     try
107e9c57535SSantosh Puranik     {
108e9c57535SSantosh Puranik         auto bus = sdbusplus::bus::new_default();
109e9c57535SSantosh Puranik         auto invPath = std::string{pimPath} + objectPath;
110e9c57535SSantosh Puranik         auto props = bus.new_method_call(
111e9c57535SSantosh Puranik             "xyz.openbmc_project.Inventory.Manager", invPath.c_str(),
112e9c57535SSantosh Puranik             "org.freedesktop.DBus.Properties", "Get");
113e9c57535SSantosh Puranik         props.append("xyz.openbmc_project.Inventory.Item");
114e9c57535SSantosh Puranik         props.append("Present");
115e9c57535SSantosh Puranik         auto result = bus.call(props);
116e9c57535SSantosh Puranik         std::variant<bool> present;
117e9c57535SSantosh Puranik         result.read(present);
118e9c57535SSantosh Puranik         if (auto pVal = std::get_if<bool>(&present))
119e9c57535SSantosh Puranik         {
120e9c57535SSantosh Puranik             return *pVal;
121e9c57535SSantosh Puranik         }
122e9c57535SSantosh Puranik         return false;
123e9c57535SSantosh Puranik     }
124e9c57535SSantosh Puranik     catch (const sdbusplus::exception::SdBusError& e)
125e9c57535SSantosh Puranik     {
126e9c57535SSantosh Puranik         std::cout << "FRU: " << objectPath << " not in D-Bus\n";
127e9c57535SSantosh Puranik         // Assume not present in case of an error
128e9c57535SSantosh Puranik         return false;
129e9c57535SSantosh Puranik     }
130e9c57535SSantosh Puranik }
131e9c57535SSantosh Puranik 
132e9c57535SSantosh Puranik /**
133e9c57535SSantosh Puranik  * @brief Check if VPD recollection is needed for the given EEPROM
134e9c57535SSantosh Puranik  *
135e9c57535SSantosh Puranik  * Not all FRUs can be swapped at BMC ready state. This function does the
136e9c57535SSantosh Puranik  * following:
137e9c57535SSantosh Puranik  * -- Check if the FRU is marked as "pluggableAtStandby" OR
138e9c57535SSantosh Puranik  *    "concurrentlyMaintainable". If so, return true.
139e9c57535SSantosh Puranik  * -- Check if we are at BMC NotReady state. If we are, then return true.
140e9c57535SSantosh Puranik  * -- Else check if the FRU is not present in the VPD cache (to cover for VPD
141e9c57535SSantosh Puranik  *    force collection). If not found in the cache, return true.
142e9c57535SSantosh Puranik  * -- Else return false.
143e9c57535SSantosh Puranik  *
144e9c57535SSantosh Puranik  * @param js - JSON Object.
145e9c57535SSantosh Puranik  * @param filePath - The EEPROM file.
146e9c57535SSantosh Puranik  * @return true if collection should be attempted, false otherwise.
147e9c57535SSantosh Puranik  */
needsRecollection(const nlohmann::json & js,const string & filePath)148e9c57535SSantosh Puranik static auto needsRecollection(const nlohmann::json& js, const string& filePath)
149e9c57535SSantosh Puranik {
150e9c57535SSantosh Puranik     if (js["frus"][filePath].at(0).value("pluggableAtStandby", false) ||
151e9c57535SSantosh Puranik         js["frus"][filePath].at(0).value("concurrentlyMaintainable", false))
152e9c57535SSantosh Puranik     {
153e9c57535SSantosh Puranik         return true;
154e9c57535SSantosh Puranik     }
155e9c57535SSantosh Puranik     if (getBMCState() == "xyz.openbmc_project.State.BMC.BMCState.NotReady")
156e9c57535SSantosh Puranik     {
157e9c57535SSantosh Puranik         return true;
158e9c57535SSantosh Puranik     }
159e9c57535SSantosh Puranik     if (!isFruInVpdCache(js["frus"][filePath].at(0).value("inventoryPath", "")))
160e9c57535SSantosh Puranik     {
161e9c57535SSantosh Puranik         return true;
162e9c57535SSantosh Puranik     }
163e9c57535SSantosh Puranik     return false;
164e9c57535SSantosh Puranik }
165e9c57535SSantosh Puranik 
166e9c57535SSantosh Puranik /**
16788edeb6fSSantosh Puranik  * @brief Expands location codes
16888edeb6fSSantosh Puranik  */
expandLocationCode(const string & unexpanded,const Parsed & vpdMap,bool isSystemVpd)16988edeb6fSSantosh Puranik static auto expandLocationCode(const string& unexpanded, const Parsed& vpdMap,
17088edeb6fSSantosh Puranik                                bool isSystemVpd)
17188edeb6fSSantosh Puranik {
17288edeb6fSSantosh Puranik     auto expanded{unexpanded};
17388edeb6fSSantosh Puranik     static constexpr auto SYSTEM_OBJECT = "/system/chassis/motherboard";
17488edeb6fSSantosh Puranik     static constexpr auto VCEN_IF = "com.ibm.ipzvpd.VCEN";
17588edeb6fSSantosh Puranik     static constexpr auto VSYS_IF = "com.ibm.ipzvpd.VSYS";
17688edeb6fSSantosh Puranik     size_t idx = expanded.find("fcs");
17788edeb6fSSantosh Puranik     try
17888edeb6fSSantosh Puranik     {
17988edeb6fSSantosh Puranik         if (idx != string::npos)
18088edeb6fSSantosh Puranik         {
18188edeb6fSSantosh Puranik             string fc{};
18288edeb6fSSantosh Puranik             string se{};
18388edeb6fSSantosh Puranik             if (isSystemVpd)
18488edeb6fSSantosh Puranik             {
18588edeb6fSSantosh Puranik                 const auto& fcData = vpdMap.at("VCEN").at("FC");
18688edeb6fSSantosh Puranik                 const auto& seData = vpdMap.at("VCEN").at("SE");
18788edeb6fSSantosh Puranik                 fc = string(fcData.data(), fcData.size());
18888edeb6fSSantosh Puranik                 se = string(seData.data(), seData.size());
18988edeb6fSSantosh Puranik             }
19088edeb6fSSantosh Puranik             else
19188edeb6fSSantosh Puranik             {
19288edeb6fSSantosh Puranik                 fc = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "FC");
19388edeb6fSSantosh Puranik                 se = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "SE");
19488edeb6fSSantosh Puranik             }
19588edeb6fSSantosh Puranik 
19681671f6dSAlpana Kumari             // TODO: See if ND0 can be placed in the JSON
19781671f6dSAlpana Kumari             expanded.replace(idx, 3, fc.substr(0, 4) + ".ND0." + se);
19888edeb6fSSantosh Puranik         }
19988edeb6fSSantosh Puranik         else
20088edeb6fSSantosh Puranik         {
20188edeb6fSSantosh Puranik             idx = expanded.find("mts");
20288edeb6fSSantosh Puranik             if (idx != string::npos)
20388edeb6fSSantosh Puranik             {
20488edeb6fSSantosh Puranik                 string mt{};
20588edeb6fSSantosh Puranik                 string se{};
20688edeb6fSSantosh Puranik                 if (isSystemVpd)
20788edeb6fSSantosh Puranik                 {
20888edeb6fSSantosh Puranik                     const auto& mtData = vpdMap.at("VSYS").at("TM");
20988edeb6fSSantosh Puranik                     const auto& seData = vpdMap.at("VSYS").at("SE");
21088edeb6fSSantosh Puranik                     mt = string(mtData.data(), mtData.size());
21188edeb6fSSantosh Puranik                     se = string(seData.data(), seData.size());
21288edeb6fSSantosh Puranik                 }
21388edeb6fSSantosh Puranik                 else
21488edeb6fSSantosh Puranik                 {
21588edeb6fSSantosh Puranik                     mt = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "TM");
21688edeb6fSSantosh Puranik                     se = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "SE");
21788edeb6fSSantosh Puranik                 }
21888edeb6fSSantosh Puranik 
21988edeb6fSSantosh Puranik                 replace(mt.begin(), mt.end(), '-', '.');
22088edeb6fSSantosh Puranik                 expanded.replace(idx, 3, mt + "." + se);
22188edeb6fSSantosh Puranik             }
22288edeb6fSSantosh Puranik         }
22388edeb6fSSantosh Puranik     }
2248e15b93aSPatrick Williams     catch (const exception& e)
22588edeb6fSSantosh Puranik     {
226f457a3efSjinuthomas         std::cerr << "Failed to expand location code with exception: "
227f457a3efSjinuthomas                   << e.what() << "\n";
22888edeb6fSSantosh Puranik     }
22988edeb6fSSantosh Puranik     return expanded;
23088edeb6fSSantosh Puranik }
2312f793048SAlpana Kumari 
232abb87edaSPriyangaRamasamy /**
233abb87edaSPriyangaRamasamy  * @brief Populate FRU specific interfaces.
234abb87edaSPriyangaRamasamy  *
235abb87edaSPriyangaRamasamy  * This is a common method which handles both
236abb87edaSPriyangaRamasamy  * ipz and keyword specific interfaces thus,
237abb87edaSPriyangaRamasamy  * reducing the code redundancy.
238abb87edaSPriyangaRamasamy  * @param[in] map - Reference to the innermost keyword-value map.
239abb87edaSPriyangaRamasamy  * @param[in] preIntrStr - Reference to the interface string.
240abb87edaSPriyangaRamasamy  * @param[out] interfaces - Reference to interface map.
241abb87edaSPriyangaRamasamy  */
242abb87edaSPriyangaRamasamy template <typename T>
populateFruSpecificInterfaces(const T & map,const string & preIntrStr,inventory::InterfaceMap & interfaces)243abb87edaSPriyangaRamasamy static void populateFruSpecificInterfaces(const T& map,
244abb87edaSPriyangaRamasamy                                           const string& preIntrStr,
245abb87edaSPriyangaRamasamy                                           inventory::InterfaceMap& interfaces)
246abb87edaSPriyangaRamasamy {
247abb87edaSPriyangaRamasamy     inventory::PropertyMap prop;
248abb87edaSPriyangaRamasamy 
249abb87edaSPriyangaRamasamy     for (const auto& kwVal : map)
250abb87edaSPriyangaRamasamy     {
251abb87edaSPriyangaRamasamy         auto kw = kwVal.first;
252abb87edaSPriyangaRamasamy 
253abb87edaSPriyangaRamasamy         if (kw[0] == '#')
254abb87edaSPriyangaRamasamy         {
25558e22145SAlpana Kumari             kw = string("PD_") + kw[1];
256abb87edaSPriyangaRamasamy         }
2578ea3f6d0SAlpana Kumari         else if (isdigit(kw[0]))
2588ea3f6d0SAlpana Kumari         {
25958e22145SAlpana Kumari             kw = string("N_") + kw;
2608ea3f6d0SAlpana Kumari         }
2613ab26a74SAlpana Kumari         if constexpr (is_same<T, KeywordVpdMap>::value)
2623ab26a74SAlpana Kumari         {
263d640f696Sjinuthomas             if (auto keywordValue = get_if<Binary>(&kwVal.second))
2643ab26a74SAlpana Kumari             {
265d640f696Sjinuthomas                 Binary vec((*keywordValue).begin(), (*keywordValue).end());
266abb87edaSPriyangaRamasamy                 prop.emplace(move(kw), move(vec));
267abb87edaSPriyangaRamasamy             }
268d640f696Sjinuthomas             else if (auto keywordValue = get_if<std::string>(&kwVal.second))
269d640f696Sjinuthomas             {
270d640f696Sjinuthomas                 Binary vec((*keywordValue).begin(), (*keywordValue).end());
271d640f696Sjinuthomas                 prop.emplace(move(kw), move(vec));
272d640f696Sjinuthomas             }
273d640f696Sjinuthomas             else if (auto keywordValue = get_if<size_t>(&kwVal.second))
2743ab26a74SAlpana Kumari             {
2753ab26a74SAlpana Kumari                 if (kw == "MemorySizeInKB")
2763ab26a74SAlpana Kumari                 {
2773ab26a74SAlpana Kumari                     inventory::PropertyMap memProp;
278d640f696Sjinuthomas                     memProp.emplace(move(kw), ((*keywordValue)));
2793ab26a74SAlpana Kumari                     interfaces.emplace(
2803ab26a74SAlpana Kumari                         "xyz.openbmc_project.Inventory.Item.Dimm",
2813ab26a74SAlpana Kumari                         move(memProp));
2823ab26a74SAlpana Kumari                 }
2833ab26a74SAlpana Kumari                 else
2843ab26a74SAlpana Kumari                 {
285f457a3efSjinuthomas                     std::cerr << "Unknown Keyword[" << kw << "] found ";
2863ab26a74SAlpana Kumari                 }
2873ab26a74SAlpana Kumari             }
288d640f696Sjinuthomas             else
289d640f696Sjinuthomas             {
290f457a3efSjinuthomas                 std::cerr << "Unknown Variant found ";
2913ab26a74SAlpana Kumari             }
2923ab26a74SAlpana Kumari         }
2933ab26a74SAlpana Kumari         else
2943ab26a74SAlpana Kumari         {
2953ab26a74SAlpana Kumari             Binary vec(kwVal.second.begin(), kwVal.second.end());
2963ab26a74SAlpana Kumari             prop.emplace(move(kw), move(vec));
2973ab26a74SAlpana Kumari         }
2983ab26a74SAlpana Kumari     }
299abb87edaSPriyangaRamasamy 
300abb87edaSPriyangaRamasamy     interfaces.emplace(preIntrStr, move(prop));
301abb87edaSPriyangaRamasamy }
302abb87edaSPriyangaRamasamy 
303abb87edaSPriyangaRamasamy /**
304abb87edaSPriyangaRamasamy  * @brief Populate Interfaces.
305abb87edaSPriyangaRamasamy  *
306abb87edaSPriyangaRamasamy  * This method populates common and extra interfaces to dbus.
307abb87edaSPriyangaRamasamy  * @param[in] js - json object
308abb87edaSPriyangaRamasamy  * @param[out] interfaces - Reference to interface map
309abb87edaSPriyangaRamasamy  * @param[in] vpdMap - Reference to the parsed vpd map.
31088edeb6fSSantosh Puranik  * @param[in] isSystemVpd - Denotes whether we are collecting the system VPD.
311abb87edaSPriyangaRamasamy  */
312abb87edaSPriyangaRamasamy template <typename T>
populateInterfaces(const nlohmann::json & js,inventory::InterfaceMap & interfaces,const T & vpdMap,bool isSystemVpd)313abb87edaSPriyangaRamasamy static void populateInterfaces(const nlohmann::json& js,
314abb87edaSPriyangaRamasamy                                inventory::InterfaceMap& interfaces,
31588edeb6fSSantosh Puranik                                const T& vpdMap, bool isSystemVpd)
316abb87edaSPriyangaRamasamy {
317abb87edaSPriyangaRamasamy     for (const auto& ifs : js.items())
318abb87edaSPriyangaRamasamy     {
31988edeb6fSSantosh Puranik         string inf = ifs.key();
320abb87edaSPriyangaRamasamy         inventory::PropertyMap props;
321abb87edaSPriyangaRamasamy 
322abb87edaSPriyangaRamasamy         for (const auto& itr : ifs.value().items())
323abb87edaSPriyangaRamasamy         {
32488edeb6fSSantosh Puranik             const string& busProp = itr.key();
32588edeb6fSSantosh Puranik 
32631970dedSAlpana Kumari             if (itr.value().is_boolean())
32731970dedSAlpana Kumari             {
32888edeb6fSSantosh Puranik                 props.emplace(busProp, itr.value().get<bool>());
32988edeb6fSSantosh Puranik             }
33088edeb6fSSantosh Puranik             else if (itr.value().is_string())
33188edeb6fSSantosh Puranik             {
3320d61c588SPriyanga Ramasamy                 if (busProp == "LocationCode" && inf == IBM_LOCATION_CODE_INF)
3330d61c588SPriyanga Ramasamy                 {
3340d61c588SPriyanga Ramasamy                     std::string prop;
33558e22145SAlpana Kumari                     if constexpr (is_same<T, Parsed>::value)
33688edeb6fSSantosh Puranik                     {
337414d5aefSAlpana Kumari                         // TODO deprecate the com.ibm interface later
3380d61c588SPriyanga Ramasamy                         prop = expandLocationCode(itr.value().get<string>(),
3390d61c588SPriyanga Ramasamy                                                   vpdMap, isSystemVpd);
3400d61c588SPriyanga Ramasamy                     }
3410d61c588SPriyanga Ramasamy                     else if constexpr (is_same<T, KeywordVpdMap>::value)
3420d61c588SPriyanga Ramasamy                     {
3430d61c588SPriyanga Ramasamy                         // Send empty Parsed object to expandLocationCode api.
3440d61c588SPriyanga Ramasamy                         prop = expandLocationCode(itr.value().get<string>(),
3450d61c588SPriyanga Ramasamy                                                   Parsed{}, false);
3460d61c588SPriyanga Ramasamy                     }
34788edeb6fSSantosh Puranik                     props.emplace(busProp, prop);
348414d5aefSAlpana Kumari                     interfaces.emplace(XYZ_LOCATION_CODE_INF, props);
34969f76024SPriyanga Ramasamy                     interfaces.emplace(IBM_LOCATION_CODE_INF, props);
35088edeb6fSSantosh Puranik                 }
35188edeb6fSSantosh Puranik                 else
35288edeb6fSSantosh Puranik                 {
35388edeb6fSSantosh Puranik                     props.emplace(busProp, itr.value().get<string>());
35488edeb6fSSantosh Puranik                 }
35588edeb6fSSantosh Puranik             }
356ed609affSSantosh Puranik             else if (itr.value().is_array())
357ed609affSSantosh Puranik             {
358ed609affSSantosh Puranik                 try
359ed609affSSantosh Puranik                 {
360ed609affSSantosh Puranik                     props.emplace(busProp, itr.value().get<Binary>());
361ed609affSSantosh Puranik                 }
3628e15b93aSPatrick Williams                 catch (const nlohmann::detail::type_error& e)
363ed609affSSantosh Puranik                 {
364ed609affSSantosh Puranik                     std::cerr << "Type exception: " << e.what() << "\n";
365ed609affSSantosh Puranik                     // Ignore any type errors
366ed609affSSantosh Puranik                 }
367ed609affSSantosh Puranik             }
36831970dedSAlpana Kumari             else if (itr.value().is_object())
36931970dedSAlpana Kumari             {
370abb87edaSPriyangaRamasamy                 const string& rec = itr.value().value("recordName", "");
371abb87edaSPriyangaRamasamy                 const string& kw = itr.value().value("keywordName", "");
372abb87edaSPriyangaRamasamy                 const string& encoding = itr.value().value("encoding", "");
373abb87edaSPriyangaRamasamy 
37458e22145SAlpana Kumari                 if constexpr (is_same<T, Parsed>::value)
375abb87edaSPriyangaRamasamy                 {
37688edeb6fSSantosh Puranik                     if (!rec.empty() && !kw.empty() && vpdMap.count(rec) &&
37788edeb6fSSantosh Puranik                         vpdMap.at(rec).count(kw))
378abb87edaSPriyangaRamasamy                     {
379c78d887cSPatrick Williams                         auto encoded = encodeKeyword(vpdMap.at(rec).at(kw),
380c78d887cSPatrick Williams                                                      encoding);
38188edeb6fSSantosh Puranik                         props.emplace(busProp, encoded);
382abb87edaSPriyangaRamasamy                     }
383abb87edaSPriyangaRamasamy                 }
38458e22145SAlpana Kumari                 else if constexpr (is_same<T, KeywordVpdMap>::value)
385abb87edaSPriyangaRamasamy                 {
386abb87edaSPriyangaRamasamy                     if (!kw.empty() && vpdMap.count(kw))
387abb87edaSPriyangaRamasamy                     {
388d640f696Sjinuthomas                         if (auto kwValue = get_if<Binary>(&vpdMap.at(kw)))
3893ab26a74SAlpana Kumari                         {
390c78d887cSPatrick Williams                             auto prop = string((*kwValue).begin(),
391c78d887cSPatrick Williams                                                (*kwValue).end());
3923ab26a74SAlpana Kumari 
393abb87edaSPriyangaRamasamy                             auto encoded = encodeKeyword(prop, encoding);
3943ab26a74SAlpana Kumari 
39588edeb6fSSantosh Puranik                             props.emplace(busProp, encoded);
396abb87edaSPriyangaRamasamy                         }
397d640f696Sjinuthomas                         else if (auto kwValue =
398d640f696Sjinuthomas                                      get_if<std::string>(&vpdMap.at(kw)))
399d640f696Sjinuthomas                         {
400c78d887cSPatrick Williams                             auto prop = string((*kwValue).begin(),
401c78d887cSPatrick Williams                                                (*kwValue).end());
402d640f696Sjinuthomas 
403d640f696Sjinuthomas                             auto encoded = encodeKeyword(prop, encoding);
404d640f696Sjinuthomas 
405d640f696Sjinuthomas                             props.emplace(busProp, encoded);
406d640f696Sjinuthomas                         }
407d640f696Sjinuthomas                         else if (auto uintValue =
408d640f696Sjinuthomas                                      get_if<size_t>(&vpdMap.at(kw)))
4093ab26a74SAlpana Kumari                         {
4103ab26a74SAlpana Kumari                             props.emplace(busProp, *uintValue);
4113ab26a74SAlpana Kumari                         }
412d640f696Sjinuthomas                         else
413d640f696Sjinuthomas                         {
414d640f696Sjinuthomas                             std::cerr << " Unknown Keyword [" << kw
415d640f696Sjinuthomas                                       << "] Encountered";
416d640f696Sjinuthomas                         }
4173ab26a74SAlpana Kumari                     }
418abb87edaSPriyangaRamasamy                 }
419abb87edaSPriyangaRamasamy             }
420b1e64bb6SMatt Spinler             else if (itr.value().is_number())
421b1e64bb6SMatt Spinler             {
422b1e64bb6SMatt Spinler                 // For now assume the value is a size_t.  In the future it would
423b1e64bb6SMatt Spinler                 // be nice to come up with a way to get the type from the JSON.
424b1e64bb6SMatt Spinler                 props.emplace(busProp, itr.value().get<size_t>());
425b1e64bb6SMatt Spinler             }
42631970dedSAlpana Kumari         }
427aa8a893eSPriyanga Ramasamy         insertOrMerge(interfaces, inf, move(props));
428abb87edaSPriyangaRamasamy     }
429abb87edaSPriyangaRamasamy }
430abb87edaSPriyangaRamasamy 
4315cb3b1f3Salpana07 /**
4325cb3b1f3Salpana07  * @brief This API checks if this FRU is pcie_devices. If yes then it further
4335cb3b1f3Salpana07  *        checks whether it is PASS1 planar.
4345cb3b1f3Salpana07  */
isThisPcieOnPass1planar(const nlohmann::json & js,const string & file)4355cb3b1f3Salpana07 static bool isThisPcieOnPass1planar(const nlohmann::json& js,
4365cb3b1f3Salpana07                                     const string& file)
4375cb3b1f3Salpana07 {
4385cb3b1f3Salpana07     auto isThisPCIeDev = false;
4395cb3b1f3Salpana07     auto isPASS1 = false;
4405cb3b1f3Salpana07 
4415cb3b1f3Salpana07     // Check if it is a PCIE device
4425cb3b1f3Salpana07     if (js["frus"].find(file) != js["frus"].end())
4435cb3b1f3Salpana07     {
444c03f3906SSantosh Puranik         if ((js["frus"][file].at(0).find("extraInterfaces") !=
445c03f3906SSantosh Puranik              js["frus"][file].at(0).end()))
4465cb3b1f3Salpana07         {
447c03f3906SSantosh Puranik             if (js["frus"][file].at(0)["extraInterfaces"].find(
4485cb3b1f3Salpana07                     "xyz.openbmc_project.Inventory.Item.PCIeDevice") !=
449c03f3906SSantosh Puranik                 js["frus"][file].at(0)["extraInterfaces"].end())
4505cb3b1f3Salpana07             {
4515cb3b1f3Salpana07                 isThisPCIeDev = true;
4525cb3b1f3Salpana07             }
4535cb3b1f3Salpana07         }
4545cb3b1f3Salpana07     }
4555cb3b1f3Salpana07 
4565cb3b1f3Salpana07     if (isThisPCIeDev)
4575cb3b1f3Salpana07     {
458a6181e22SAlpana Kumari         // Collect HW version and SystemType to know if it is PASS1 planar.
4595cb3b1f3Salpana07         auto bus = sdbusplus::bus::new_default();
460a6181e22SAlpana Kumari         auto property1 = bus.new_method_call(
4615cb3b1f3Salpana07             INVENTORY_MANAGER_SERVICE,
4625cb3b1f3Salpana07             "/xyz/openbmc_project/inventory/system/chassis/motherboard",
4635cb3b1f3Salpana07             "org.freedesktop.DBus.Properties", "Get");
464a6181e22SAlpana Kumari         property1.append("com.ibm.ipzvpd.VINI");
465a6181e22SAlpana Kumari         property1.append("HW");
466a6181e22SAlpana Kumari         auto result1 = bus.call(property1);
467a6181e22SAlpana Kumari         inventory::Value hwVal;
468a6181e22SAlpana Kumari         result1.read(hwVal);
4695cb3b1f3Salpana07 
470a6181e22SAlpana Kumari         // SystemType
471a6181e22SAlpana Kumari         auto property2 = bus.new_method_call(
472a6181e22SAlpana Kumari             INVENTORY_MANAGER_SERVICE,
473a6181e22SAlpana Kumari             "/xyz/openbmc_project/inventory/system/chassis/motherboard",
474a6181e22SAlpana Kumari             "org.freedesktop.DBus.Properties", "Get");
475a6181e22SAlpana Kumari         property2.append("com.ibm.ipzvpd.VSBP");
476a6181e22SAlpana Kumari         property2.append("IM");
477a6181e22SAlpana Kumari         auto result2 = bus.call(property2);
478a6181e22SAlpana Kumari         inventory::Value imVal;
479a6181e22SAlpana Kumari         result2.read(imVal);
480a6181e22SAlpana Kumari 
481a6181e22SAlpana Kumari         auto pVal1 = get_if<Binary>(&hwVal);
482a6181e22SAlpana Kumari         auto pVal2 = get_if<Binary>(&imVal);
483a6181e22SAlpana Kumari 
484a6181e22SAlpana Kumari         if (pVal1 && pVal2)
4855cb3b1f3Salpana07         {
486a6181e22SAlpana Kumari             auto hwVersion = *pVal1;
487a6181e22SAlpana Kumari             auto systemType = *pVal2;
488a6181e22SAlpana Kumari 
489a6181e22SAlpana Kumari             // IM kw for Everest
490a6181e22SAlpana Kumari             Binary everestSystem{80, 00, 48, 00};
491a6181e22SAlpana Kumari 
492a6181e22SAlpana Kumari             if (systemType == everestSystem)
493a6181e22SAlpana Kumari             {
494a6181e22SAlpana Kumari                 if (hwVersion[1] < 21)
495a6181e22SAlpana Kumari                 {
4965cb3b1f3Salpana07                     isPASS1 = true;
4975cb3b1f3Salpana07                 }
4985cb3b1f3Salpana07             }
499a6181e22SAlpana Kumari             else if (hwVersion[1] < 2)
500a6181e22SAlpana Kumari             {
501a6181e22SAlpana Kumari                 isPASS1 = true;
502a6181e22SAlpana Kumari             }
503a6181e22SAlpana Kumari         }
504a6181e22SAlpana Kumari     }
5055cb3b1f3Salpana07 
5065cb3b1f3Salpana07     return (isThisPCIeDev && isPASS1);
5075cb3b1f3Salpana07 }
5085cb3b1f3Salpana07 
509735dee9bSAlpana Kumari /** Performs any pre-action needed to get the FRU setup for collection.
5102f793048SAlpana Kumari  *
5112f793048SAlpana Kumari  * @param[in] json - json object
5122f793048SAlpana Kumari  * @param[in] file - eeprom file path
5132f793048SAlpana Kumari  */
preAction(const nlohmann::json & json,const string & file)5142f793048SAlpana Kumari static void preAction(const nlohmann::json& json, const string& file)
5152f793048SAlpana Kumari {
516735dee9bSAlpana Kumari     if ((json["frus"][file].at(0)).find("preAction") ==
5172f793048SAlpana Kumari         json["frus"][file].at(0).end())
5182f793048SAlpana Kumari     {
5192f793048SAlpana Kumari         return;
5202f793048SAlpana Kumari     }
5212f793048SAlpana Kumari 
522a2ddc96eSSunny Srivastava     try
523a2ddc96eSSunny Srivastava     {
524735dee9bSAlpana Kumari         if (executePreAction(json, file))
5252f793048SAlpana Kumari         {
52664b9f5f1SAlpana Kumari             if (json["frus"][file].at(0).find("devAddress") !=
52764b9f5f1SAlpana Kumari                 json["frus"][file].at(0).end())
52864b9f5f1SAlpana Kumari             {
529735dee9bSAlpana Kumari                 // Now bind the device
5304c3bf5beSAlpana Kumari                 string bind = json["frus"][file].at(0).value("devAddress", "");
531f457a3efSjinuthomas                 std::cout << "Binding device " << bind << std::endl;
5322f793048SAlpana Kumari                 string bindCmd = string("echo \"") + bind +
5332f793048SAlpana Kumari                                  string("\" > /sys/bus/i2c/drivers/at24/bind");
534f457a3efSjinuthomas                 std::cout << bindCmd << std::endl;
5352f793048SAlpana Kumari                 executeCmd(bindCmd);
5362f793048SAlpana Kumari 
5372f793048SAlpana Kumari                 // Check if device showed up (test for file)
5382f793048SAlpana Kumari                 if (!fs::exists(file))
5392f793048SAlpana Kumari                 {
540f457a3efSjinuthomas                     std::cerr << "EEPROM " << file
541f457a3efSjinuthomas                               << " does not exist. Take failure action"
542f457a3efSjinuthomas                               << std::endl;
5432f793048SAlpana Kumari                     // If not, then take failure postAction
544735dee9bSAlpana Kumari                     executePostFailAction(json, file);
545735dee9bSAlpana Kumari                 }
5462f793048SAlpana Kumari             }
54740d1c196SAlpana Kumari             else
54840d1c196SAlpana Kumari             {
549*af921756SManojkiran Eda                 // missing required information
550*af921756SManojkiran Eda                 std::cerr << "VPD inventory JSON missing basic information of "
551a2ddc96eSSunny Srivastava                              "preAction "
55240d1c196SAlpana Kumari                              "for this FRU : ["
553d640f696Sjinuthomas                           << file << "]. Executing executePostFailAction."
554d640f696Sjinuthomas                           << std::endl;
55540d1c196SAlpana Kumari 
55640d1c196SAlpana Kumari                 // Take failure postAction
55740d1c196SAlpana Kumari                 executePostFailAction(json, file);
55840d1c196SAlpana Kumari                 return;
55940d1c196SAlpana Kumari             }
56040d1c196SAlpana Kumari         }
561dedb5a63SSantosh Puranik         else
562dedb5a63SSantosh Puranik         {
563dedb5a63SSantosh Puranik             // If the FRU is not there, clear the VINI/CCIN data.
564*af921756SManojkiran Eda             // Entity manager probes for this keyword to look for this
565dedb5a63SSantosh Puranik             // FRU, now if the data is persistent on BMC and FRU is
566dedb5a63SSantosh Puranik             // removed this can lead to ambiguity. Hence clearing this
567dedb5a63SSantosh Puranik             // Keyword if FRU is absent.
568dedb5a63SSantosh Puranik             const auto& invPath =
569dedb5a63SSantosh Puranik                 json["frus"][file].at(0).value("inventoryPath", "");
570dedb5a63SSantosh Puranik 
571dedb5a63SSantosh Puranik             if (!invPath.empty())
572dedb5a63SSantosh Puranik             {
573dedb5a63SSantosh Puranik                 inventory::ObjectMap pimObjMap{
574dedb5a63SSantosh Puranik                     {invPath, {{"com.ibm.ipzvpd.VINI", {{"CC", Binary{}}}}}}};
575dedb5a63SSantosh Puranik 
576dedb5a63SSantosh Puranik                 common::utility::callPIM(move(pimObjMap));
577dedb5a63SSantosh Puranik             }
578dedb5a63SSantosh Puranik             else
579dedb5a63SSantosh Puranik             {
580dedb5a63SSantosh Puranik                 throw std::runtime_error("Path empty in Json");
581dedb5a63SSantosh Puranik             }
582dedb5a63SSantosh Puranik         }
5832f793048SAlpana Kumari     }
584a2ddc96eSSunny Srivastava     catch (const GpioException& e)
585a2ddc96eSSunny Srivastava     {
586a2ddc96eSSunny Srivastava         PelAdditionalData additionalData{};
587a2ddc96eSSunny Srivastava         additionalData.emplace("DESCRIPTION", e.what());
588a2ddc96eSSunny Srivastava         createPEL(additionalData, PelSeverity::WARNING, errIntfForGpioError,
589a2ddc96eSSunny Srivastava                   nullptr);
590a2ddc96eSSunny Srivastava     }
591a2ddc96eSSunny Srivastava }
5922f793048SAlpana Kumari 
593abb87edaSPriyangaRamasamy /**
594f3e69689SSantosh Puranik  * @brief Fills the Decorator.AssetTag property into the interfaces map
595f3e69689SSantosh Puranik  *
596f3e69689SSantosh Puranik  * This function should only be called in cases where we did not find a JSON
597f3e69689SSantosh Puranik  * symlink. A missing symlink in /var/lib will be considered as a factory reset
598f3e69689SSantosh Puranik  * and this function will be used to default the AssetTag property.
599f3e69689SSantosh Puranik  *
600f3e69689SSantosh Puranik  * @param interfaces A possibly pre-populated map of inetrfaces to properties.
601f3e69689SSantosh Puranik  * @param vpdMap A VPD map of the system VPD data.
602f3e69689SSantosh Puranik  */
fillAssetTag(inventory::InterfaceMap & interfaces,const Parsed & vpdMap)603f3e69689SSantosh Puranik static void fillAssetTag(inventory::InterfaceMap& interfaces,
604f3e69689SSantosh Puranik                          const Parsed& vpdMap)
605f3e69689SSantosh Puranik {
606f3e69689SSantosh Puranik     // Read the system serial number and MTM
607f3e69689SSantosh Puranik     // Default asset tag is Server-MTM-System Serial
608f3e69689SSantosh Puranik     inventory::Interface assetIntf{
609f3e69689SSantosh Puranik         "xyz.openbmc_project.Inventory.Decorator.AssetTag"};
610f3e69689SSantosh Puranik     inventory::PropertyMap assetTagProps;
611f3e69689SSantosh Puranik     std::string defaultAssetTag =
612f3e69689SSantosh Puranik         std::string{"Server-"} + getKwVal(vpdMap, "VSYS", "TM") +
613f3e69689SSantosh Puranik         std::string{"-"} + getKwVal(vpdMap, "VSYS", "SE");
614f3e69689SSantosh Puranik     assetTagProps.emplace("AssetTag", defaultAssetTag);
615f3e69689SSantosh Puranik     insertOrMerge(interfaces, assetIntf, std::move(assetTagProps));
616f3e69689SSantosh Puranik }
617f3e69689SSantosh Puranik 
618f3e69689SSantosh Puranik /**
619d3a379a6SSantosh Puranik  * @brief Set certain one time properties in the inventory
620d3a379a6SSantosh Puranik  * Use this function to insert the Functional and Enabled properties into the
621d3a379a6SSantosh Puranik  * inventory map. This function first checks if the object in question already
622d3a379a6SSantosh Puranik  * has these properties hosted on D-Bus, if the property is already there, it is
623d3a379a6SSantosh Puranik  * not modified, hence the name "one time". If the property is not already
624d3a379a6SSantosh Puranik  * present, it will be added to the map with a suitable default value (true for
625dedb5a63SSantosh Puranik  * Functional and Enabled)
626d3a379a6SSantosh Puranik  *
627*af921756SManojkiran Eda  * @param[in] object - The inventory D-Bus object without the inventory prefix.
628*af921756SManojkiran Eda  * @param[in,out] interfaces - Reference to a map of inventory interfaces to
629d3a379a6SSantosh Puranik  * which the properties will be attached.
630d3a379a6SSantosh Puranik  */
setOneTimeProperties(const std::string & object,inventory::InterfaceMap & interfaces)631d3a379a6SSantosh Puranik static void setOneTimeProperties(const std::string& object,
632d3a379a6SSantosh Puranik                                  inventory::InterfaceMap& interfaces)
633d3a379a6SSantosh Puranik {
634d3a379a6SSantosh Puranik     auto bus = sdbusplus::bus::new_default();
635d3a379a6SSantosh Puranik     auto objectPath = INVENTORY_PATH + object;
636d3a379a6SSantosh Puranik     auto prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager",
637d3a379a6SSantosh Puranik                                     objectPath.c_str(),
638d3a379a6SSantosh Puranik                                     "org.freedesktop.DBus.Properties", "Get");
639d3a379a6SSantosh Puranik     prop.append("xyz.openbmc_project.State.Decorator.OperationalStatus");
640d3a379a6SSantosh Puranik     prop.append("Functional");
641d3a379a6SSantosh Puranik     try
642d3a379a6SSantosh Puranik     {
643d3a379a6SSantosh Puranik         auto result = bus.call(prop);
644d3a379a6SSantosh Puranik     }
645d3a379a6SSantosh Puranik     catch (const sdbusplus::exception::SdBusError& e)
646d3a379a6SSantosh Puranik     {
647d3a379a6SSantosh Puranik         // Treat as property unavailable
648d3a379a6SSantosh Puranik         inventory::PropertyMap prop;
649d3a379a6SSantosh Puranik         prop.emplace("Functional", true);
650d3a379a6SSantosh Puranik         interfaces.emplace(
651d3a379a6SSantosh Puranik             "xyz.openbmc_project.State.Decorator.OperationalStatus",
652d3a379a6SSantosh Puranik             move(prop));
653d3a379a6SSantosh Puranik     }
654d3a379a6SSantosh Puranik     prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager",
655d3a379a6SSantosh Puranik                                objectPath.c_str(),
656d3a379a6SSantosh Puranik                                "org.freedesktop.DBus.Properties", "Get");
657d3a379a6SSantosh Puranik     prop.append("xyz.openbmc_project.Object.Enable");
658d3a379a6SSantosh Puranik     prop.append("Enabled");
659d3a379a6SSantosh Puranik     try
660d3a379a6SSantosh Puranik     {
661d3a379a6SSantosh Puranik         auto result = bus.call(prop);
662d3a379a6SSantosh Puranik     }
663d3a379a6SSantosh Puranik     catch (const sdbusplus::exception::SdBusError& e)
664d3a379a6SSantosh Puranik     {
665d3a379a6SSantosh Puranik         // Treat as property unavailable
666d3a379a6SSantosh Puranik         inventory::PropertyMap prop;
667dedb5a63SSantosh Puranik         prop.emplace("Enabled", true);
668d3a379a6SSantosh Puranik         interfaces.emplace("xyz.openbmc_project.Object.Enable", move(prop));
669d3a379a6SSantosh Puranik     }
670d3a379a6SSantosh Puranik }
671d3a379a6SSantosh Puranik 
672d3a379a6SSantosh Puranik /**
6738e140a1cSPriyangaRamasamy  * @brief Prime the Inventory
6748e140a1cSPriyangaRamasamy  * Prime the inventory by populating only the location code,
6758e140a1cSPriyangaRamasamy  * type interface and the inventory object for the frus
6768e140a1cSPriyangaRamasamy  * which are not system vpd fru.
677abb87edaSPriyangaRamasamy  *
6788e140a1cSPriyangaRamasamy  * @param[in] jsObject - Reference to vpd inventory json object
6798e140a1cSPriyangaRamasamy  * @param[in] vpdMap -  Reference to the parsed vpd map
6808e140a1cSPriyangaRamasamy  *
6818e140a1cSPriyangaRamasamy  * @returns Map of items in extraInterface.
6828e140a1cSPriyangaRamasamy  */
6838e140a1cSPriyangaRamasamy template <typename T>
primeInventory(const nlohmann::json & jsObject,const T & vpdMap)6848e140a1cSPriyangaRamasamy inventory::ObjectMap primeInventory(const nlohmann::json& jsObject,
6858e140a1cSPriyangaRamasamy                                     const T& vpdMap)
6868e140a1cSPriyangaRamasamy {
6878e140a1cSPriyangaRamasamy     inventory::ObjectMap objects;
6888e140a1cSPriyangaRamasamy 
6898e140a1cSPriyangaRamasamy     for (auto& itemFRUS : jsObject["frus"].items())
6908e140a1cSPriyangaRamasamy     {
6918e140a1cSPriyangaRamasamy         for (auto& itemEEPROM : itemFRUS.value())
6928e140a1cSPriyangaRamasamy         {
6932e6c6f73SAlpana Kumari             // Take pre actions if needed
6942e6c6f73SAlpana Kumari             if (itemEEPROM.find("preAction") != itemEEPROM.end())
6952e6c6f73SAlpana Kumari             {
6962e6c6f73SAlpana Kumari                 preAction(jsObject, itemFRUS.key());
6972e6c6f73SAlpana Kumari             }
6982e6c6f73SAlpana Kumari 
6998e140a1cSPriyangaRamasamy             inventory::InterfaceMap interfaces;
7008e140a1cSPriyangaRamasamy             inventory::Object object(itemEEPROM.at("inventoryPath"));
7018e140a1cSPriyangaRamasamy 
70250f60bf8SSantosh Puranik             if ((itemFRUS.key() != systemVpdFilePath) &&
70350f60bf8SSantosh Puranik                 !itemEEPROM.value("noprime", false))
7048e140a1cSPriyangaRamasamy             {
705cfd7a75aSAlpana Kumari                 inventory::PropertyMap presProp;
706e358acbbSPriyanga Ramasamy 
707e358acbbSPriyanga Ramasamy                 // Do not populate Present property for frus whose
708aca61373SPriyanga Ramasamy                 // synthesized=true. synthesized=true says the fru VPD is
709aca61373SPriyanga Ramasamy                 // synthesized and owned by a separate component.
710aca61373SPriyanga Ramasamy                 // In some cases, the FRU has its own VPD, but still a separate
711aca61373SPriyanga Ramasamy                 // application handles the FRU's presence. So VPD parser skips
712aca61373SPriyanga Ramasamy                 // populating Present property by checking the JSON flag,
713aca61373SPriyanga Ramasamy                 // "handlePresence".
714e358acbbSPriyanga Ramasamy                 if (!itemEEPROM.value("synthesized", false))
715e358acbbSPriyanga Ramasamy                 {
716aca61373SPriyanga Ramasamy                     if (itemEEPROM.value("handlePresence", true))
717aca61373SPriyanga Ramasamy                     {
718cfd7a75aSAlpana Kumari                         presProp.emplace("Present", false);
719cfd7a75aSAlpana Kumari                         interfaces.emplace("xyz.openbmc_project.Inventory.Item",
720d3a379a6SSantosh Puranik                                            presProp);
721e358acbbSPriyanga Ramasamy                     }
722aca61373SPriyanga Ramasamy                 }
723aca61373SPriyanga Ramasamy 
724d3a379a6SSantosh Puranik                 setOneTimeProperties(object, interfaces);
7258e140a1cSPriyangaRamasamy                 if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end())
7268e140a1cSPriyangaRamasamy                 {
7278e140a1cSPriyangaRamasamy                     for (const auto& eI : itemEEPROM["extraInterfaces"].items())
7288e140a1cSPriyangaRamasamy                     {
7298e140a1cSPriyangaRamasamy                         inventory::PropertyMap props;
730414d5aefSAlpana Kumari                         if (eI.key() == IBM_LOCATION_CODE_INF)
7318e140a1cSPriyangaRamasamy                         {
7328e140a1cSPriyangaRamasamy                             if constexpr (std::is_same<T, Parsed>::value)
7338e140a1cSPriyangaRamasamy                             {
7348e140a1cSPriyangaRamasamy                                 for (auto& lC : eI.value().items())
7358e140a1cSPriyangaRamasamy                                 {
7368e140a1cSPriyangaRamasamy                                     auto propVal = expandLocationCode(
7378e140a1cSPriyangaRamasamy                                         lC.value().get<string>(), vpdMap, true);
7388e140a1cSPriyangaRamasamy 
7398e140a1cSPriyangaRamasamy                                     props.emplace(move(lC.key()),
7408e140a1cSPriyangaRamasamy                                                   move(propVal));
741b0f3749dSSantosh Puranik                                     interfaces.emplace(XYZ_LOCATION_CODE_INF,
742b0f3749dSSantosh Puranik                                                        props);
7438e140a1cSPriyangaRamasamy                                     interfaces.emplace(move(eI.key()),
7448e140a1cSPriyangaRamasamy                                                        move(props));
7458e140a1cSPriyangaRamasamy                                 }
7468e140a1cSPriyangaRamasamy                             }
7478e140a1cSPriyangaRamasamy                         }
748d3a379a6SSantosh Puranik                         else if (eI.key() ==
749d3a379a6SSantosh Puranik                                  "xyz.openbmc_project.Inventory.Item")
750d3a379a6SSantosh Puranik                         {
751d3a379a6SSantosh Puranik                             for (auto& val : eI.value().items())
752d3a379a6SSantosh Puranik                             {
753d3a379a6SSantosh Puranik                                 if (val.key() == "PrettyName")
754d3a379a6SSantosh Puranik                                 {
755d3a379a6SSantosh Puranik                                     presProp.emplace(val.key(),
756d3a379a6SSantosh Puranik                                                      val.value().get<string>());
757d3a379a6SSantosh Puranik                                 }
758d3a379a6SSantosh Puranik                             }
759d3a379a6SSantosh Puranik                             // Use insert_or_assign here as we may already have
760d3a379a6SSantosh Puranik                             // inserted the present property only earlier in
761d3a379a6SSantosh Puranik                             // this function under this same interface.
762d3a379a6SSantosh Puranik                             interfaces.insert_or_assign(eI.key(),
763d3a379a6SSantosh Puranik                                                         move(presProp));
764d3a379a6SSantosh Puranik                         }
7651bb8716bSSunny Srivastava                         else
7661bb8716bSSunny Srivastava                         {
7671bb8716bSSunny Srivastava                             interfaces.emplace(move(eI.key()), move(props));
7681bb8716bSSunny Srivastava                         }
7698e140a1cSPriyangaRamasamy                     }
7708e140a1cSPriyangaRamasamy                 }
7718e140a1cSPriyangaRamasamy                 objects.emplace(move(object), move(interfaces));
7728e140a1cSPriyangaRamasamy             }
7738e140a1cSPriyangaRamasamy         }
7748e140a1cSPriyangaRamasamy     }
7758e140a1cSPriyangaRamasamy     return objects;
7768e140a1cSPriyangaRamasamy }
7778e140a1cSPriyangaRamasamy 
77865b83601SAlpana Kumari /**
77965b83601SAlpana Kumari  * @brief This API executes command to set environment variable
78065b83601SAlpana Kumari  *        And then reboot the system
78165b83601SAlpana Kumari  * @param[in] key   -env key to set new value
78265b83601SAlpana Kumari  * @param[in] value -value to set.
78365b83601SAlpana Kumari  */
setEnvAndReboot(const string & key,const string & value)78465b83601SAlpana Kumari void setEnvAndReboot(const string& key, const string& value)
78565b83601SAlpana Kumari {
78665b83601SAlpana Kumari     // set env and reboot and break.
78765b83601SAlpana Kumari     executeCmd("/sbin/fw_setenv", key, value);
788280197e3SAndrew Geissler     log<level::INFO>("Rebooting BMC to pick up new device tree");
78965b83601SAlpana Kumari     // make dbus call to reboot
79065b83601SAlpana Kumari     auto bus = sdbusplus::bus::new_default_system();
79165b83601SAlpana Kumari     auto method = bus.new_method_call(
79265b83601SAlpana Kumari         "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
79365b83601SAlpana Kumari         "org.freedesktop.systemd1.Manager", "Reboot");
79465b83601SAlpana Kumari     bus.call_noreply(method);
79565b83601SAlpana Kumari }
79665b83601SAlpana Kumari 
79765b83601SAlpana Kumari /*
79865b83601SAlpana Kumari  * @brief This API checks for env var fitconfig.
79965b83601SAlpana Kumari  *        If not initialised OR updated as per the current system type,
80065b83601SAlpana Kumari  *        update this env var and reboot the system.
80165b83601SAlpana Kumari  *
80265b83601SAlpana Kumari  * @param[in] systemType IM kwd in vpd tells about which system type it is.
80365b83601SAlpana Kumari  * */
setDevTreeEnv(const string & systemType)80465b83601SAlpana Kumari void setDevTreeEnv(const string& systemType)
80565b83601SAlpana Kumari {
80637e72701SAlpana Kumari     // Init with default dtb
80737e72701SAlpana Kumari     string newDeviceTree = "conf-aspeed-bmc-ibm-rainier-p1.dtb";
808e5f177a5SSantosh Puranik     static const deviceTreeMap deviceTreeSystemTypeMap = {
809e5f177a5SSantosh Puranik         {RAINIER_2U, "conf-aspeed-bmc-ibm-rainier-p1.dtb"},
810e5f177a5SSantosh Puranik         {RAINIER_2U_V2, "conf-aspeed-bmc-ibm-rainier.dtb"},
811e5f177a5SSantosh Puranik         {RAINIER_4U, "conf-aspeed-bmc-ibm-rainier-4u-p1.dtb"},
812e5f177a5SSantosh Puranik         {RAINIER_4U_V2, "conf-aspeed-bmc-ibm-rainier-4u.dtb"},
813e5f177a5SSantosh Puranik         {RAINIER_1S4U, "conf-aspeed-bmc-ibm-rainier-1s4u.dtb"},
8141b026119SAlpana Kumari         {EVEREST, "conf-aspeed-bmc-ibm-everest.dtb"},
815dedb5a63SSantosh Puranik         {EVEREST_V2, "conf-aspeed-bmc-ibm-everest.dtb"},
816dedb5a63SSantosh Puranik         {BONNELL, "conf-aspeed-bmc-ibm-bonnell.dtb"}};
81765b83601SAlpana Kumari 
81865b83601SAlpana Kumari     if (deviceTreeSystemTypeMap.find(systemType) !=
81965b83601SAlpana Kumari         deviceTreeSystemTypeMap.end())
82065b83601SAlpana Kumari     {
82165b83601SAlpana Kumari         newDeviceTree = deviceTreeSystemTypeMap.at(systemType);
82265b83601SAlpana Kumari     }
82337e72701SAlpana Kumari     else
82437e72701SAlpana Kumari     {
82537e72701SAlpana Kumari         // System type not supported
826ab1e22c3SAlpana Kumari         string err = "This System type not found/supported in dtb table " +
827ab1e22c3SAlpana Kumari                      systemType +
828ab1e22c3SAlpana Kumari                      ".Please check the HW and IM keywords in the system "
829ab1e22c3SAlpana Kumari                      "VPD.Breaking...";
830ab1e22c3SAlpana Kumari 
831ab1e22c3SAlpana Kumari         // map to hold additional data in case of logging pel
832ab1e22c3SAlpana Kumari         PelAdditionalData additionalData{};
833ab1e22c3SAlpana Kumari         additionalData.emplace("DESCRIPTION", err);
834ab1e22c3SAlpana Kumari         createPEL(additionalData, PelSeverity::WARNING,
835a2ddc96eSSunny Srivastava                   errIntfForInvalidSystemType, nullptr);
836ab1e22c3SAlpana Kumari         exit(-1);
83737e72701SAlpana Kumari     }
83865b83601SAlpana Kumari 
83965b83601SAlpana Kumari     string readVarValue;
84065b83601SAlpana Kumari     bool envVarFound = false;
84165b83601SAlpana Kumari 
84265b83601SAlpana Kumari     vector<string> output = executeCmd("/sbin/fw_printenv");
84365b83601SAlpana Kumari     for (const auto& entry : output)
84465b83601SAlpana Kumari     {
84565b83601SAlpana Kumari         size_t pos = entry.find("=");
84665b83601SAlpana Kumari         string key = entry.substr(0, pos);
84765b83601SAlpana Kumari         if (key != "fitconfig")
84865b83601SAlpana Kumari         {
84965b83601SAlpana Kumari             continue;
85065b83601SAlpana Kumari         }
85165b83601SAlpana Kumari 
85265b83601SAlpana Kumari         envVarFound = true;
85365b83601SAlpana Kumari         if (pos + 1 < entry.size())
85465b83601SAlpana Kumari         {
85565b83601SAlpana Kumari             readVarValue = entry.substr(pos + 1);
85665b83601SAlpana Kumari             if (readVarValue.find(newDeviceTree) != string::npos)
85765b83601SAlpana Kumari             {
85865b83601SAlpana Kumari                 // fitconfig is Updated. No action needed
85965b83601SAlpana Kumari                 break;
86065b83601SAlpana Kumari             }
86165b83601SAlpana Kumari         }
86265b83601SAlpana Kumari         // set env and reboot and break.
86365b83601SAlpana Kumari         setEnvAndReboot(key, newDeviceTree);
86465b83601SAlpana Kumari         exit(0);
86565b83601SAlpana Kumari     }
86665b83601SAlpana Kumari 
86765b83601SAlpana Kumari     // check If env var Not found
86865b83601SAlpana Kumari     if (!envVarFound)
86965b83601SAlpana Kumari     {
87065b83601SAlpana Kumari         setEnvAndReboot("fitconfig", newDeviceTree);
87165b83601SAlpana Kumari     }
87265b83601SAlpana Kumari }
87365b83601SAlpana Kumari 
8748e140a1cSPriyangaRamasamy /**
87538ee9c8dSKantesh Nagaradder  * @brief Parse the given EEPROM file.
87638ee9c8dSKantesh Nagaradder  *
87738ee9c8dSKantesh Nagaradder  * @param[in] vpdFilePath - Path of EEPROM file
87838ee9c8dSKantesh Nagaradder  * @param[in] js- Reference to vpd inventory json object
87938ee9c8dSKantesh Nagaradder  * @return Parsed VPD map
88038ee9c8dSKantesh Nagaradder  */
88138ee9c8dSKantesh Nagaradder std::variant<KeywordVpdMap, openpower::vpd::Store>
parseVpdFile(const std::string & vpdFilePath,const nlohmann::json & js)88237992a65SSunny Srivastava     parseVpdFile(const std::string& vpdFilePath, const nlohmann::json& js)
88338ee9c8dSKantesh Nagaradder {
88438ee9c8dSKantesh Nagaradder     uint32_t vpdStartOffset = 0;
88538ee9c8dSKantesh Nagaradder     for (const auto& item : js["frus"][vpdFilePath])
88638ee9c8dSKantesh Nagaradder     {
88738ee9c8dSKantesh Nagaradder         if (item.find("offset") != item.end())
88838ee9c8dSKantesh Nagaradder         {
88938ee9c8dSKantesh Nagaradder             vpdStartOffset = item["offset"];
89037992a65SSunny Srivastava             break;
89138ee9c8dSKantesh Nagaradder         }
89238ee9c8dSKantesh Nagaradder     }
89338ee9c8dSKantesh Nagaradder 
89438ee9c8dSKantesh Nagaradder     Binary vpdVector = getVpdDataInVector(js, vpdFilePath);
89538ee9c8dSKantesh Nagaradder 
89638ee9c8dSKantesh Nagaradder     ParserInterface* parser = ParserFactory::getParser(
89737992a65SSunny Srivastava         vpdVector,
89837992a65SSunny Srivastava         (pimPath + js["frus"][vpdFilePath][0]["inventoryPath"]
89937992a65SSunny Srivastava                        .get_ref<const nlohmann::json::string_t&>()),
90037992a65SSunny Srivastava         vpdFilePath, vpdStartOffset);
90138ee9c8dSKantesh Nagaradder 
90238ee9c8dSKantesh Nagaradder     auto parseResult = parser->parse();
90338ee9c8dSKantesh Nagaradder 
90438ee9c8dSKantesh Nagaradder     // release the parser object
90538ee9c8dSKantesh Nagaradder     ParserFactory::freeParser(parser);
90638ee9c8dSKantesh Nagaradder 
90738ee9c8dSKantesh Nagaradder     return parseResult;
90838ee9c8dSKantesh Nagaradder }
90938ee9c8dSKantesh Nagaradder 
91038ee9c8dSKantesh Nagaradder /*
91138ee9c8dSKantesh Nagaradder  * @brief This API retrieves the hardware backup in map
91238ee9c8dSKantesh Nagaradder  *
91338ee9c8dSKantesh Nagaradder  * @param[in] systemVpdBackupPath - The path that backs up the system VPD.
91438ee9c8dSKantesh Nagaradder  * @param[in] backupVpdInvPath - FRU inventory path.
91538ee9c8dSKantesh Nagaradder  * @param[in] js - JSON object.
91638ee9c8dSKantesh Nagaradder  * @param[out] backupVpdMap - An IPZ VPD map containing the parsed backup VPD.
91738ee9c8dSKantesh Nagaradder  *
91838ee9c8dSKantesh Nagaradder  * */
getBackupVpdInMap(const string & systemVpdBackupPath,const string & backupVpdInvPath,const nlohmann::json & js,Parsed & backupVpdMap)91938ee9c8dSKantesh Nagaradder void getBackupVpdInMap(const string& systemVpdBackupPath,
92038ee9c8dSKantesh Nagaradder                        const string& backupVpdInvPath, const nlohmann::json& js,
92138ee9c8dSKantesh Nagaradder                        Parsed& backupVpdMap)
92238ee9c8dSKantesh Nagaradder {
92338ee9c8dSKantesh Nagaradder     PelAdditionalData additionalData{};
92438ee9c8dSKantesh Nagaradder 
92538ee9c8dSKantesh Nagaradder     if (!fs::exists(systemVpdBackupPath))
92638ee9c8dSKantesh Nagaradder     {
92738ee9c8dSKantesh Nagaradder         string errorMsg = "Device path ";
92838ee9c8dSKantesh Nagaradder         errorMsg += systemVpdBackupPath;
92938ee9c8dSKantesh Nagaradder         errorMsg += " does not exist";
93038ee9c8dSKantesh Nagaradder 
93138ee9c8dSKantesh Nagaradder         additionalData.emplace("DESCRIPTION", errorMsg);
93238ee9c8dSKantesh Nagaradder 
93338ee9c8dSKantesh Nagaradder         additionalData.emplace("CALLOUT_INVENTORY_PATH",
93438ee9c8dSKantesh Nagaradder                                INVENTORY_PATH + backupVpdInvPath);
93538ee9c8dSKantesh Nagaradder 
93638ee9c8dSKantesh Nagaradder         createPEL(additionalData, PelSeverity::ERROR, errIntfForStreamFail,
93738ee9c8dSKantesh Nagaradder                   nullptr);
93838ee9c8dSKantesh Nagaradder     }
93938ee9c8dSKantesh Nagaradder     else
94038ee9c8dSKantesh Nagaradder     {
94137992a65SSunny Srivastava         auto backupVpdParsedResult = parseVpdFile(systemVpdBackupPath, js);
94238ee9c8dSKantesh Nagaradder 
94338ee9c8dSKantesh Nagaradder         if (auto pVal = get_if<Store>(&backupVpdParsedResult))
94438ee9c8dSKantesh Nagaradder         {
94538ee9c8dSKantesh Nagaradder             backupVpdMap = pVal->getVpdMap();
94638ee9c8dSKantesh Nagaradder         }
94737992a65SSunny Srivastava         else
94837992a65SSunny Srivastava         {
94937992a65SSunny Srivastava             std::cerr << "Invalid format of VPD in back up. Restore aborted."
95037992a65SSunny Srivastava                       << std::endl;
95137992a65SSunny Srivastava         }
95238ee9c8dSKantesh Nagaradder     }
95338ee9c8dSKantesh Nagaradder }
95438ee9c8dSKantesh Nagaradder 
updateVpdDataOnHw(const std::string & vpdFilePath,nlohmann::json & js,const std::string & recName,const std::string & kwName,const Binary & kwdData)95538ee9c8dSKantesh Nagaradder void updateVpdDataOnHw(const std::string& vpdFilePath, nlohmann::json& js,
95638ee9c8dSKantesh Nagaradder                        const std::string& recName, const std::string& kwName,
95738ee9c8dSKantesh Nagaradder                        const Binary& kwdData)
95838ee9c8dSKantesh Nagaradder {
95938ee9c8dSKantesh Nagaradder     const std::string& fruInvPath =
96038ee9c8dSKantesh Nagaradder         js["frus"][vpdFilePath][0]["inventoryPath"]
96138ee9c8dSKantesh Nagaradder             .get_ref<const nlohmann::json::string_t&>();
96238ee9c8dSKantesh Nagaradder 
96338ee9c8dSKantesh Nagaradder     EditorImpl edit(vpdFilePath, js, recName, kwName, fruInvPath);
96438ee9c8dSKantesh Nagaradder 
96538ee9c8dSKantesh Nagaradder     uint32_t offset = 0;
96638ee9c8dSKantesh Nagaradder     // Setup offset, if any
96738ee9c8dSKantesh Nagaradder     for (const auto& item : js["frus"][vpdFilePath])
96838ee9c8dSKantesh Nagaradder     {
96938ee9c8dSKantesh Nagaradder         if (item.find("offset") != item.end())
97038ee9c8dSKantesh Nagaradder         {
97138ee9c8dSKantesh Nagaradder             offset = item["offset"];
97238ee9c8dSKantesh Nagaradder             break;
97338ee9c8dSKantesh Nagaradder         }
97438ee9c8dSKantesh Nagaradder     }
97538ee9c8dSKantesh Nagaradder 
97638ee9c8dSKantesh Nagaradder     // update keyword data on to EEPROM file
97738ee9c8dSKantesh Nagaradder     // Note: Updating keyword data on cache is
97838ee9c8dSKantesh Nagaradder     // handled via PIM Notify call hence passing
97938ee9c8dSKantesh Nagaradder     // the updCache flag value as false here.
98038ee9c8dSKantesh Nagaradder     edit.updateKeyword(kwdData, offset, false);
98138ee9c8dSKantesh Nagaradder }
98238ee9c8dSKantesh Nagaradder 
98338ee9c8dSKantesh Nagaradder /**
9849094d4f6SSunnySrivastava1984  * @brief API to check if we need to restore system VPD
9859094d4f6SSunnySrivastava1984  * This functionality is only applicable for IPZ VPD data.
98638ee9c8dSKantesh Nagaradder 
9879094d4f6SSunnySrivastava1984  * @param[in] vpdMap - IPZ vpd map
9889094d4f6SSunnySrivastava1984  * @param[in] objectPath - Object path for the FRU
98938ee9c8dSKantesh Nagaradder  * @param[in] js - JSON Object
99038ee9c8dSKantesh Nagaradder  * @param[in] isBackupOnCache - Denotes whether the backup is on cache/hardware
9919094d4f6SSunnySrivastava1984  */
restoreSystemVPD(Parsed & vpdMap,const string & objectPath,nlohmann::json & js,bool isBackupOnCache=true)99238ee9c8dSKantesh Nagaradder void restoreSystemVPD(Parsed& vpdMap, const string& objectPath,
99338ee9c8dSKantesh Nagaradder                       nlohmann::json& js, bool isBackupOnCache = true)
9949094d4f6SSunnySrivastava1984 {
99538ee9c8dSKantesh Nagaradder     std::string systemVpdBackupPath{};
99638ee9c8dSKantesh Nagaradder     std::string backupVpdInvPath{};
99738ee9c8dSKantesh Nagaradder     Parsed backupVpdMap{};
99838ee9c8dSKantesh Nagaradder 
99938ee9c8dSKantesh Nagaradder     if (!isBackupOnCache)
100038ee9c8dSKantesh Nagaradder     {
100138ee9c8dSKantesh Nagaradder         // Get the value of systemvpdBackupPath field from json
100238ee9c8dSKantesh Nagaradder         systemVpdBackupPath = js["frus"][systemVpdFilePath].at(0).value(
100338ee9c8dSKantesh Nagaradder             "systemVpdBackupPath", "");
100438ee9c8dSKantesh Nagaradder 
100538ee9c8dSKantesh Nagaradder         backupVpdInvPath = js["frus"][systemVpdBackupPath][0]["inventoryPath"]
100638ee9c8dSKantesh Nagaradder                                .get_ref<const nlohmann::json::string_t&>();
100738ee9c8dSKantesh Nagaradder 
100838ee9c8dSKantesh Nagaradder         getBackupVpdInMap(systemVpdBackupPath, backupVpdInvPath, js,
100938ee9c8dSKantesh Nagaradder                           backupVpdMap);
101038ee9c8dSKantesh Nagaradder 
101138ee9c8dSKantesh Nagaradder         if (backupVpdMap.empty())
101238ee9c8dSKantesh Nagaradder         {
101337992a65SSunny Srivastava             std::cerr << "Backup VPD map is empty" << std::endl;
101438ee9c8dSKantesh Nagaradder             return;
101538ee9c8dSKantesh Nagaradder         }
101638ee9c8dSKantesh Nagaradder     }
101738ee9c8dSKantesh Nagaradder 
10189094d4f6SSunnySrivastava1984     for (const auto& systemRecKwdPair : svpdKwdMap)
10199094d4f6SSunnySrivastava1984     {
102038ee9c8dSKantesh Nagaradder         const string& recordName = systemRecKwdPair.first;
102138ee9c8dSKantesh Nagaradder         auto it = vpdMap.find(recordName);
10229094d4f6SSunnySrivastava1984 
10239094d4f6SSunnySrivastava1984         // check if record is found in map we got by parser
10249094d4f6SSunnySrivastava1984         if (it != vpdMap.end())
10259094d4f6SSunnySrivastava1984         {
10269094d4f6SSunnySrivastava1984             const auto& kwdListForRecord = systemRecKwdPair.second;
1027952d6c58SPriyanga Ramasamy             for (const auto& keywordInfo : kwdListForRecord)
10289094d4f6SSunnySrivastava1984             {
102938ee9c8dSKantesh Nagaradder                 const auto keywordName = get<0>(keywordInfo);
1030952d6c58SPriyanga Ramasamy 
10319094d4f6SSunnySrivastava1984                 DbusPropertyMap& kwdValMap = it->second;
103238ee9c8dSKantesh Nagaradder                 auto iterator = kwdValMap.find(keywordName);
10339094d4f6SSunnySrivastava1984 
10349094d4f6SSunnySrivastava1984                 if (iterator != kwdValMap.end())
10359094d4f6SSunnySrivastava1984                 {
10369094d4f6SSunnySrivastava1984                     string& kwdValue = iterator->second;
10379094d4f6SSunnySrivastava1984 
103838ee9c8dSKantesh Nagaradder                     std::string backupValue{};
1039952d6c58SPriyanga Ramasamy                     const auto& defaultValue = get<1>(keywordInfo);
104038ee9c8dSKantesh Nagaradder                     const auto& backupVpdRecName = get<4>(keywordInfo);
104138ee9c8dSKantesh Nagaradder                     const auto& backupVpdKwName = get<5>(keywordInfo);
104238ee9c8dSKantesh Nagaradder 
104338ee9c8dSKantesh Nagaradder                     // If the 'isBackupOnCache' flag is false, we need
104438ee9c8dSKantesh Nagaradder                     // to backup the systemVPD on the specified fru's eeprom
104538ee9c8dSKantesh Nagaradder                     // path or restore it from the specified fru's eeprom path.
104638ee9c8dSKantesh Nagaradder                     if (isBackupOnCache)
104738ee9c8dSKantesh Nagaradder                     {
104838ee9c8dSKantesh Nagaradder                         // check bus data
104938ee9c8dSKantesh Nagaradder                         backupValue = readBusProperty(
105038ee9c8dSKantesh Nagaradder                             objectPath, ipzVpdInf + recordName, keywordName);
105138ee9c8dSKantesh Nagaradder                     }
105238ee9c8dSKantesh Nagaradder                     else
105338ee9c8dSKantesh Nagaradder                     {
105437992a65SSunny Srivastava                         backupValue = getKwVal(backupVpdMap, backupVpdRecName,
105537992a65SSunny Srivastava                                                backupVpdKwName);
105637992a65SSunny Srivastava 
105737992a65SSunny Srivastava                         if (backupValue.empty())
105838ee9c8dSKantesh Nagaradder                         {
105937992a65SSunny Srivastava                             string errorMsg{};
106037992a65SSunny Srivastava                             if (backupVpdMap.find(backupVpdRecName) ==
106137992a65SSunny Srivastava                                 backupVpdMap.end())
106237992a65SSunny Srivastava                             {
106337992a65SSunny Srivastava                                 errorMsg = backupVpdRecName +
106438ee9c8dSKantesh Nagaradder                                            " Record does not exist in "
106538ee9c8dSKantesh Nagaradder                                            "the EEPROM file ";
106638ee9c8dSKantesh Nagaradder                             }
106738ee9c8dSKantesh Nagaradder                             else
106838ee9c8dSKantesh Nagaradder                             {
106937992a65SSunny Srivastava                                 errorMsg = backupVpdKwName +
107037992a65SSunny Srivastava                                            " Keyword not found or empty.";
107137992a65SSunny Srivastava                             }
107238ee9c8dSKantesh Nagaradder 
107338ee9c8dSKantesh Nagaradder                             errorMsg += systemVpdBackupPath;
107438ee9c8dSKantesh Nagaradder 
107538ee9c8dSKantesh Nagaradder                             PelAdditionalData additionalData;
107638ee9c8dSKantesh Nagaradder                             additionalData.emplace("DESCRIPTION", errorMsg);
107738ee9c8dSKantesh Nagaradder 
107838ee9c8dSKantesh Nagaradder                             createPEL(additionalData, PelSeverity::ERROR,
107938ee9c8dSKantesh Nagaradder                                       errIntfForInvalidVPD, nullptr);
108037992a65SSunny Srivastava 
108138ee9c8dSKantesh Nagaradder                             continue;
108238ee9c8dSKantesh Nagaradder                         }
108338ee9c8dSKantesh Nagaradder                     }
108438ee9c8dSKantesh Nagaradder 
108538ee9c8dSKantesh Nagaradder                     Binary backupDataInBinary(backupValue.begin(),
108638ee9c8dSKantesh Nagaradder                                               backupValue.end());
108738ee9c8dSKantesh Nagaradder 
1088952d6c58SPriyanga Ramasamy                     Binary kwdDataInBinary(kwdValue.begin(), kwdValue.end());
1089a559c2d6SSunny Srivastava 
109038ee9c8dSKantesh Nagaradder                     if (backupDataInBinary != defaultValue)
10919094d4f6SSunnySrivastava1984                     {
1092952d6c58SPriyanga Ramasamy                         if (kwdDataInBinary != defaultValue)
10939094d4f6SSunnySrivastava1984                         {
10949094d4f6SSunnySrivastava1984                             // both the data are present, check for mismatch
109538ee9c8dSKantesh Nagaradder                             if (backupValue != kwdValue)
10969094d4f6SSunnySrivastava1984                             {
109724942235SPriyanga Ramasamy                                 string errMsg = "Mismatch found between backup "
109824942235SPriyanga Ramasamy                                                 "and primary VPD for record: ";
10999094d4f6SSunnySrivastava1984                                 errMsg += (*it).first;
11009094d4f6SSunnySrivastava1984                                 errMsg += " and keyword: ";
110138ee9c8dSKantesh Nagaradder                                 errMsg += keywordName;
11029094d4f6SSunnySrivastava1984 
1103dedb5a63SSantosh Puranik                                 std::ostringstream busStream;
110438ee9c8dSKantesh Nagaradder                                 for (uint16_t byte : backupValue)
1105dedb5a63SSantosh Puranik                                 {
1106dedb5a63SSantosh Puranik                                     busStream << std::setfill('0')
1107dedb5a63SSantosh Puranik                                               << std::setw(2) << std::hex
1108dedb5a63SSantosh Puranik                                               << "0x" << byte << " ";
1109dedb5a63SSantosh Puranik                                 }
1110dedb5a63SSantosh Puranik 
1111dedb5a63SSantosh Puranik                                 std::ostringstream vpdStream;
1112dedb5a63SSantosh Puranik                                 for (uint16_t byte : kwdValue)
1113dedb5a63SSantosh Puranik                                 {
1114dedb5a63SSantosh Puranik                                     vpdStream << std::setfill('0')
1115dedb5a63SSantosh Puranik                                               << std::setw(2) << std::hex
1116dedb5a63SSantosh Puranik                                               << "0x" << byte << " ";
1117dedb5a63SSantosh Puranik                                 }
1118dedb5a63SSantosh Puranik 
11199094d4f6SSunnySrivastava1984                                 // data mismatch
11209094d4f6SSunnySrivastava1984                                 PelAdditionalData additionalData;
11219094d4f6SSunnySrivastava1984 
11229094d4f6SSunnySrivastava1984                                 additionalData.emplace("DESCRIPTION", errMsg);
112324942235SPriyanga Ramasamy                                 additionalData.emplace(
112424942235SPriyanga Ramasamy                                     "Value read from Backup: ",
1125dedb5a63SSantosh Puranik                                     busStream.str());
1126dedb5a63SSantosh Puranik                                 additionalData.emplace(
112724942235SPriyanga Ramasamy                                     "Value read from Primary: ",
1128dedb5a63SSantosh Puranik                                     vpdStream.str());
11299094d4f6SSunnySrivastava1984 
11300746eeebSSunny Srivastava                                 createPEL(additionalData, PelSeverity::WARNING,
113124942235SPriyanga Ramasamy                                           errIntfForVPDMismatch, nullptr);
113238ee9c8dSKantesh Nagaradder 
113338ee9c8dSKantesh Nagaradder                                 if (!isBackupOnCache)
113438ee9c8dSKantesh Nagaradder                                 {
113538ee9c8dSKantesh Nagaradder                                     // Backing up or restoring from a hardware
113638ee9c8dSKantesh Nagaradder                                     // path does not requires copying the backup
113738ee9c8dSKantesh Nagaradder                                     // data to the VPD map, as this will result
113838ee9c8dSKantesh Nagaradder                                     // in a mismatch between the primary VPD and
113938ee9c8dSKantesh Nagaradder                                     // its cache.
114038ee9c8dSKantesh Nagaradder                                     continue;
114138ee9c8dSKantesh Nagaradder                                 }
11429094d4f6SSunnySrivastava1984                             }
114337992a65SSunny Srivastava                             else
114437992a65SSunny Srivastava                             {
114537992a65SSunny Srivastava                                 // both the backup and primary data is
114637992a65SSunny Srivastava                                 // non-default and same. Nothing needs to be
114737992a65SSunny Srivastava                                 // done.
114837992a65SSunny Srivastava                                 continue;
114937992a65SSunny Srivastava                             }
11509094d4f6SSunnySrivastava1984                         }
11519094d4f6SSunnySrivastava1984 
115238ee9c8dSKantesh Nagaradder                         // If the backup is on the cache we need to copy the
115338ee9c8dSKantesh Nagaradder                         // backup data to the VPD map to ensure there is no
1154*af921756SManojkiran Eda                         // mismatch b/n them. So if backup data is not default,
115538ee9c8dSKantesh Nagaradder                         // then irrespective of primary data(default or other
115638ee9c8dSKantesh Nagaradder                         // than backup), copy the backup data to vpd map as we
115738ee9c8dSKantesh Nagaradder                         // don't need to change the backup data in either case
115838ee9c8dSKantesh Nagaradder                         // in the process of restoring system vpd.
115938ee9c8dSKantesh Nagaradder                         kwdValue = backupValue;
116038ee9c8dSKantesh Nagaradder 
116138ee9c8dSKantesh Nagaradder                         // If the backup data is on the base panel the restoring
116238ee9c8dSKantesh Nagaradder                         // of Backup VPD on to the system backplane VPD
116338ee9c8dSKantesh Nagaradder                         // file is done here not through the VPD manager code
116438ee9c8dSKantesh Nagaradder                         // path. This is to have the logic of restoring data on
116538ee9c8dSKantesh Nagaradder                         // to the cache & hardware in the same code path.
116638ee9c8dSKantesh Nagaradder                         if (!isBackupOnCache)
116738ee9c8dSKantesh Nagaradder                         {
116838ee9c8dSKantesh Nagaradder                             // copy backup VPD on to system backplane
116938ee9c8dSKantesh Nagaradder                             // EEPROM  file.
117038ee9c8dSKantesh Nagaradder                             updateVpdDataOnHw(systemVpdFilePath, js, recordName,
117138ee9c8dSKantesh Nagaradder                                               keywordName, backupDataInBinary);
117238ee9c8dSKantesh Nagaradder                         }
117390a63b9bSSunny Srivastava                     }
1174952d6c58SPriyanga Ramasamy                     else if (kwdDataInBinary == defaultValue &&
1175952d6c58SPriyanga Ramasamy                              get<2>(keywordInfo)) // Check isPELRequired is true
11769094d4f6SSunnySrivastava1984                     {
117724942235SPriyanga Ramasamy                         string errMsg = "Found default value on both backup "
117824942235SPriyanga Ramasamy                                         "and primary VPD for record: ";
11799094d4f6SSunnySrivastava1984                         errMsg += (*it).first;
11809094d4f6SSunnySrivastava1984                         errMsg += " and keyword: ";
118138ee9c8dSKantesh Nagaradder                         errMsg += keywordName;
118237992a65SSunny Srivastava                         errMsg += ". Update primary VPD.";
11839094d4f6SSunnySrivastava1984 
118424942235SPriyanga Ramasamy                         // mfg default on both backup and primary, log PEL
11859094d4f6SSunnySrivastava1984                         PelAdditionalData additionalData;
11869094d4f6SSunnySrivastava1984                         additionalData.emplace("DESCRIPTION", errMsg);
11879094d4f6SSunnySrivastava1984 
11880746eeebSSunny Srivastava                         createPEL(additionalData, PelSeverity::ERROR,
118924942235SPriyanga Ramasamy                                   errIntfForVPDDefault, nullptr);
119038ee9c8dSKantesh Nagaradder 
11919094d4f6SSunnySrivastava1984                         continue;
11929094d4f6SSunnySrivastava1984                     }
119338ee9c8dSKantesh Nagaradder                     else if ((kwdDataInBinary != defaultValue) &&
119438ee9c8dSKantesh Nagaradder                              (!isBackupOnCache))
119538ee9c8dSKantesh Nagaradder                     {
119638ee9c8dSKantesh Nagaradder                         // update primary VPD on to backup VPD file
119738ee9c8dSKantesh Nagaradder                         updateVpdDataOnHw(systemVpdBackupPath, js,
119838ee9c8dSKantesh Nagaradder                                           backupVpdRecName, backupVpdKwName,
119938ee9c8dSKantesh Nagaradder                                           kwdDataInBinary);
120038ee9c8dSKantesh Nagaradder 
120138ee9c8dSKantesh Nagaradder                         // copy primary VPD to backup VPD to publish on
120238ee9c8dSKantesh Nagaradder                         // DBus
120338ee9c8dSKantesh Nagaradder                         backupVpdMap.find(backupVpdRecName)
120438ee9c8dSKantesh Nagaradder                             ->second.find(backupVpdKwName)
120538ee9c8dSKantesh Nagaradder                             ->second = kwdValue;
12069094d4f6SSunnySrivastava1984                     }
12079094d4f6SSunnySrivastava1984                 }
12089094d4f6SSunnySrivastava1984             }
12099094d4f6SSunnySrivastava1984         }
12109094d4f6SSunnySrivastava1984     }
121138ee9c8dSKantesh Nagaradder }
121238ee9c8dSKantesh Nagaradder 
12139094d4f6SSunnySrivastava1984 /**
12147ce68724Salpana07  * @brief This checks for is this FRU a processor
12157ce68724Salpana07  *        And if yes, then checks for is this primary
12167ce68724Salpana07  *
12177ce68724Salpana07  * @param[in] js- vpd json to get the information about this FRU
12187ce68724Salpana07  * @param[in] filePath- FRU vpd
12197ce68724Salpana07  *
12207ce68724Salpana07  * @return true/false
12217ce68724Salpana07  */
isThisPrimaryProcessor(nlohmann::json & js,const string & filePath)12227ce68724Salpana07 bool isThisPrimaryProcessor(nlohmann::json& js, const string& filePath)
12237ce68724Salpana07 {
12247ce68724Salpana07     bool isProcessor = false;
12257ce68724Salpana07     bool isPrimary = false;
12267ce68724Salpana07 
12277ce68724Salpana07     for (const auto& item : js["frus"][filePath])
12287ce68724Salpana07     {
12297ce68724Salpana07         if (item.find("extraInterfaces") != item.end())
12307ce68724Salpana07         {
12317ce68724Salpana07             for (const auto& eI : item["extraInterfaces"].items())
12327ce68724Salpana07             {
12337ce68724Salpana07                 if (eI.key().find("Inventory.Item.Cpu") != string::npos)
12347ce68724Salpana07                 {
12357ce68724Salpana07                     isProcessor = true;
12367ce68724Salpana07                 }
12377ce68724Salpana07             }
12387ce68724Salpana07         }
12397ce68724Salpana07 
12407ce68724Salpana07         if (isProcessor)
12417ce68724Salpana07         {
12427ce68724Salpana07             string cpuType = item.value("cpuType", "");
12437ce68724Salpana07             if (cpuType == "primary")
12447ce68724Salpana07             {
12457ce68724Salpana07                 isPrimary = true;
12467ce68724Salpana07             }
12477ce68724Salpana07         }
12487ce68724Salpana07     }
12497ce68724Salpana07 
12507ce68724Salpana07     return (isProcessor && isPrimary);
12517ce68724Salpana07 }
12527ce68724Salpana07 
12537ce68724Salpana07 /**
12547ce68724Salpana07  * @brief This finds DIMM vpd in vpd json and enables them by binding the device
12557ce68724Salpana07  *        driver
12567ce68724Salpana07  * @param[in] js- vpd json to iterate through and take action if it is DIMM
12577ce68724Salpana07  */
doEnableAllDimms(nlohmann::json & js)12587ce68724Salpana07 void doEnableAllDimms(nlohmann::json& js)
12597ce68724Salpana07 {
12607ce68724Salpana07     // iterate over each fru
12617ce68724Salpana07     for (const auto& eachFru : js["frus"].items())
12627ce68724Salpana07     {
12637ce68724Salpana07         // skip the driver binding if eeprom already exists
12647ce68724Salpana07         if (fs::exists(eachFru.key()))
12657ce68724Salpana07         {
12667ce68724Salpana07             continue;
12677ce68724Salpana07         }
12687ce68724Salpana07 
12697ce68724Salpana07         for (const auto& eachInventory : eachFru.value())
12707ce68724Salpana07         {
12717ce68724Salpana07             if (eachInventory.find("extraInterfaces") != eachInventory.end())
12727ce68724Salpana07             {
12737ce68724Salpana07                 for (const auto& eI : eachInventory["extraInterfaces"].items())
12747ce68724Salpana07                 {
12757ce68724Salpana07                     if (eI.key().find("Inventory.Item.Dimm") != string::npos)
12767ce68724Salpana07                     {
12777ce68724Salpana07                         string dimmVpd = eachFru.key();
12787ce68724Salpana07                         // fetch it from
12797ce68724Salpana07                         // "/sys/bus/i2c/drivers/at24/414-0050/eeprom"
12807ce68724Salpana07 
12817ce68724Salpana07                         regex matchPatern("([0-9]+-[0-9]{4})");
12827ce68724Salpana07                         smatch matchFound;
12837ce68724Salpana07                         if (regex_search(dimmVpd, matchFound, matchPatern))
12847ce68724Salpana07                         {
12857ce68724Salpana07                             vector<string> i2cReg;
12867ce68724Salpana07                             boost::split(i2cReg, matchFound.str(0),
12877ce68724Salpana07                                          boost::is_any_of("-"));
12887ce68724Salpana07 
1289*af921756SManojkiran Eda                             // remove 0s from beginning
12907ce68724Salpana07                             const regex pattern("^0+(?!$)");
12917ce68724Salpana07                             for (auto& i : i2cReg)
12927ce68724Salpana07                             {
12937ce68724Salpana07                                 i = regex_replace(i, pattern, "");
12947ce68724Salpana07                             }
12957ce68724Salpana07 
129663cce0ffSJinu Joy Thomas                             // For ISDIMM which uses ee1004 driver
129763cce0ffSJinu Joy Thomas                             // the below is done
129863cce0ffSJinu Joy Thomas                             size_t stringFound = dimmVpd.find("ee1004");
129963cce0ffSJinu Joy Thomas                             if (stringFound != string::npos)
130063cce0ffSJinu Joy Thomas                             {
130163cce0ffSJinu Joy Thomas                                 // echo ee1004 0x50 >
130263cce0ffSJinu Joy Thomas                                 // /sys/bus/i2c/devices/i2c-110/new_device
130363cce0ffSJinu Joy Thomas                                 string cmnd = "echo ee1004 0x" + i2cReg[1] +
130463cce0ffSJinu Joy Thomas                                               " > /sys/bus/i2c/devices/i2c-" +
130563cce0ffSJinu Joy Thomas                                               i2cReg[0] + "/new_device";
130663cce0ffSJinu Joy Thomas                                 executeCmd(cmnd);
130763cce0ffSJinu Joy Thomas                             }
130863cce0ffSJinu Joy Thomas                             else if (i2cReg.size() == 2)
13097ce68724Salpana07                             {
13107ce68724Salpana07                                 // echo 24c32 0x50 >
13117ce68724Salpana07                                 // /sys/bus/i2c/devices/i2c-16/new_device
13127ce68724Salpana07                                 string cmnd = "echo 24c32 0x" + i2cReg[1] +
13137ce68724Salpana07                                               " > /sys/bus/i2c/devices/i2c-" +
13147ce68724Salpana07                                               i2cReg[0] + "/new_device";
13157ce68724Salpana07                                 executeCmd(cmnd);
13167ce68724Salpana07                             }
13177ce68724Salpana07                         }
13187ce68724Salpana07                     }
13197ce68724Salpana07                 }
13207ce68724Salpana07             }
13217ce68724Salpana07         }
13227ce68724Salpana07     }
13237ce68724Salpana07 }
13247ce68724Salpana07 
13257ce68724Salpana07 /**
13266abdeb61SPriyanga Ramasamy  * @brief Check if the given CPU is an IO only chip.
13276abdeb61SPriyanga Ramasamy  * The CPU is termed as IO, whose all of the cores are bad and can never be
13286abdeb61SPriyanga Ramasamy  * used. Those CPU chips can be used for IO purpose like connecting PCIe devices
13296abdeb61SPriyanga Ramasamy  * etc., The CPU whose every cores are bad, can be identified from the CP00
13306abdeb61SPriyanga Ramasamy  * record's PG keyword, only if all of the 8 EQs' value equals 0xE7F9FF. (1EQ
13316abdeb61SPriyanga Ramasamy  * has 4 cores grouped together by sharing its cache memory.)
13326abdeb61SPriyanga Ramasamy  * @param [in] pgKeyword - PG Keyword of CPU.
13336abdeb61SPriyanga Ramasamy  * @return true if the given cpu is an IO, false otherwise.
13346abdeb61SPriyanga Ramasamy  */
isCPUIOGoodOnly(const string & pgKeyword)13356abdeb61SPriyanga Ramasamy static bool isCPUIOGoodOnly(const string& pgKeyword)
13366abdeb61SPriyanga Ramasamy {
13376abdeb61SPriyanga Ramasamy     const unsigned char io[] = {0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9,
13386abdeb61SPriyanga Ramasamy                                 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7,
13396abdeb61SPriyanga Ramasamy                                 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF};
13406abdeb61SPriyanga Ramasamy     // EQ0 index (in PG keyword) starts at 97 (with offset starting from 0).
13416abdeb61SPriyanga Ramasamy     // Each EQ carries 3 bytes of data. Totally there are 8 EQs. If all EQs'
13426abdeb61SPriyanga Ramasamy     // value equals 0xE7F9FF, then the cpu has no good cores and its treated as
13436abdeb61SPriyanga Ramasamy     // IO.
13446abdeb61SPriyanga Ramasamy     if (memcmp(io, pgKeyword.data() + 97, 24) == 0)
13456abdeb61SPriyanga Ramasamy     {
13466abdeb61SPriyanga Ramasamy         return true;
13476abdeb61SPriyanga Ramasamy     }
13486abdeb61SPriyanga Ramasamy 
13496abdeb61SPriyanga Ramasamy     // The CPU is not an IO
13506abdeb61SPriyanga Ramasamy     return false;
13516abdeb61SPriyanga Ramasamy }
13526abdeb61SPriyanga Ramasamy 
13536abdeb61SPriyanga Ramasamy /**
13549a60c8b4SJinu Joy Thomas  * @brief Function to bring MUX out of idle state
13559a60c8b4SJinu Joy Thomas  *
13569a60c8b4SJinu Joy Thomas  *        This finds All the MUX defined in the system json and enables
13579a60c8b4SJinu Joy Thomas  *        them by setting the holdidle parameter to 0.
13589a60c8b4SJinu Joy Thomas  * @param[in] js- system json to iterate through and take action
13599a60c8b4SJinu Joy Thomas  */
doEnableAllMuxChips(const nlohmann::json & js)13609a60c8b4SJinu Joy Thomas void doEnableAllMuxChips(const nlohmann::json& js)
13619a60c8b4SJinu Joy Thomas {
13629a60c8b4SJinu Joy Thomas     // Do we have the mandatory "muxes" section?
13639a60c8b4SJinu Joy Thomas     if (js.find("muxes") != js.end())
13649a60c8b4SJinu Joy Thomas     {
13659a60c8b4SJinu Joy Thomas         std::cout << "Enabling all the MUX on the system " << std::endl;
13669a60c8b4SJinu Joy Thomas         // iterate over each MUX detail and enable them
13679a60c8b4SJinu Joy Thomas         for (const auto& item : js["muxes"])
13689a60c8b4SJinu Joy Thomas         {
13699a60c8b4SJinu Joy Thomas             if (item.find("holdidlepath") != item.end())
13709a60c8b4SJinu Joy Thomas             {
137163cce0ffSJinu Joy Thomas                 const std::string& holdidle = item["holdidlepath"];
13729a60c8b4SJinu Joy Thomas                 std::cout << "Setting holdidle state for " << holdidle
13739a60c8b4SJinu Joy Thomas                           << "to 0 " << std::endl;
13749a60c8b4SJinu Joy Thomas                 string cmd = "echo 0 > " + holdidle;
13759a60c8b4SJinu Joy Thomas                 executeCmd(cmd);
13769a60c8b4SJinu Joy Thomas             }
13779a60c8b4SJinu Joy Thomas         }
13789a60c8b4SJinu Joy Thomas         std::cout << "Completed enabling all the MUX on the system "
13799a60c8b4SJinu Joy Thomas                   << std::endl;
13809a60c8b4SJinu Joy Thomas     }
13819a60c8b4SJinu Joy Thomas     else
13829a60c8b4SJinu Joy Thomas     {
13839a60c8b4SJinu Joy Thomas         std::cout << "No MUX was defined for the system" << std::endl;
13849a60c8b4SJinu Joy Thomas     }
13859a60c8b4SJinu Joy Thomas }
13869a60c8b4SJinu Joy Thomas 
13879a60c8b4SJinu Joy Thomas /**
13888e140a1cSPriyangaRamasamy  * @brief Populate Dbus.
1389abb87edaSPriyangaRamasamy  * This method invokes all the populateInterface functions
1390abb87edaSPriyangaRamasamy  * and notifies PIM about dbus object.
13918e140a1cSPriyangaRamasamy  * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the
13928e140a1cSPriyangaRamasamy  * input.
1393abb87edaSPriyangaRamasamy  * @param[in] js - Inventory json object
1394abb87edaSPriyangaRamasamy  * @param[in] filePath - Path of the vpd file
1395abb87edaSPriyangaRamasamy  * @param[in] preIntrStr - Interface string
1396abb87edaSPriyangaRamasamy  */
1397abb87edaSPriyangaRamasamy template <typename T>
populateDbus(T & vpdMap,nlohmann::json & js,const string & filePath)13989094d4f6SSunnySrivastava1984 static void populateDbus(T& vpdMap, nlohmann::json& js, const string& filePath)
1399abb87edaSPriyangaRamasamy {
1400abb87edaSPriyangaRamasamy     inventory::InterfaceMap interfaces;
1401abb87edaSPriyangaRamasamy     inventory::ObjectMap objects;
1402abb87edaSPriyangaRamasamy     inventory::PropertyMap prop;
14036aa5450eSShantappa Teekappanavar     string ccinFromVpd;
1404abb87edaSPriyangaRamasamy 
140550f60bf8SSantosh Puranik     bool isSystemVpd = (filePath == systemVpdFilePath);
140650f60bf8SSantosh Puranik     if constexpr (is_same<T, Parsed>::value)
140750f60bf8SSantosh Puranik     {
14086aa5450eSShantappa Teekappanavar         ccinFromVpd = getKwVal(vpdMap, "VINI", "CC");
14096aa5450eSShantappa Teekappanavar         transform(ccinFromVpd.begin(), ccinFromVpd.end(), ccinFromVpd.begin(),
14106aa5450eSShantappa Teekappanavar                   ::toupper);
14116aa5450eSShantappa Teekappanavar 
141250f60bf8SSantosh Puranik         if (isSystemVpd)
141350f60bf8SSantosh Puranik         {
141450f60bf8SSantosh Puranik             string mboardPath =
141550f60bf8SSantosh Puranik                 js["frus"][filePath].at(0).value("inventoryPath", "");
141650f60bf8SSantosh Puranik 
141738ee9c8dSKantesh Nagaradder             // Get the value of systemvpdBackupPath field from json
141838ee9c8dSKantesh Nagaradder             const std::string& systemVpdBackupPath =
141938ee9c8dSKantesh Nagaradder                 js["frus"][filePath].at(0).value("systemVpdBackupPath", "");
142038ee9c8dSKantesh Nagaradder 
142138ee9c8dSKantesh Nagaradder             if (systemVpdBackupPath.empty())
142238ee9c8dSKantesh Nagaradder             {
142338ee9c8dSKantesh Nagaradder                 std::vector<std::string> interfaces = {motherBoardInterface};
142438ee9c8dSKantesh Nagaradder                 // call mapper to check for object path creation
142538ee9c8dSKantesh Nagaradder                 MapperResponse subTree =
142638ee9c8dSKantesh Nagaradder                     getObjectSubtreeForInterfaces(pimPath, 0, interfaces);
142738ee9c8dSKantesh Nagaradder 
142850f60bf8SSantosh Puranik                 // Attempt system VPD restore if we have a motherboard
142950f60bf8SSantosh Puranik                 // object in the inventory.
143050f60bf8SSantosh Puranik                 if ((subTree.size() != 0) &&
143150f60bf8SSantosh Puranik                     (subTree.find(pimPath + mboardPath) != subTree.end()))
143250f60bf8SSantosh Puranik                 {
143338ee9c8dSKantesh Nagaradder                     restoreSystemVPD(vpdMap, mboardPath, js);
143450f60bf8SSantosh Puranik                 }
143550f60bf8SSantosh Puranik                 else
143650f60bf8SSantosh Puranik                 {
143750f60bf8SSantosh Puranik                     log<level::ERR>("No object path found");
143850f60bf8SSantosh Puranik                 }
143950f60bf8SSantosh Puranik             }
14407ce68724Salpana07             else
14417ce68724Salpana07             {
144238ee9c8dSKantesh Nagaradder                 restoreSystemVPD(vpdMap, mboardPath, js, false);
144338ee9c8dSKantesh Nagaradder             }
144438ee9c8dSKantesh Nagaradder         }
144538ee9c8dSKantesh Nagaradder         else
144638ee9c8dSKantesh Nagaradder         {
14477ce68724Salpana07             // check if it is processor vpd.
14487ce68724Salpana07             auto isPrimaryCpu = isThisPrimaryProcessor(js, filePath);
14497ce68724Salpana07 
14507ce68724Salpana07             if (isPrimaryCpu)
14517ce68724Salpana07             {
14527ce68724Salpana07                 auto ddVersion = getKwVal(vpdMap, "CRP0", "DD");
14537ce68724Salpana07 
14547ce68724Salpana07                 auto chipVersion = atoi(ddVersion.substr(1, 2).c_str());
14557ce68724Salpana07 
14567ce68724Salpana07                 if (chipVersion >= 2)
14577ce68724Salpana07                 {
14587ce68724Salpana07                     doEnableAllDimms(js);
1459253fbe9fSSantosh Puranik                     // Sleep for a few seconds to let the DIMM parses start
1460253fbe9fSSantosh Puranik                     using namespace std::chrono_literals;
1461253fbe9fSSantosh Puranik                     std::this_thread::sleep_for(5s);
14627ce68724Salpana07                 }
14637ce68724Salpana07             }
14647ce68724Salpana07         }
146550f60bf8SSantosh Puranik     }
146650f60bf8SSantosh Puranik 
1467f3e69689SSantosh Puranik     auto processFactoryReset = false;
1468f3e69689SSantosh Puranik 
146932c687f5SPriyanga Ramasamy     if (isSystemVpd)
147032c687f5SPriyanga Ramasamy     {
147132c687f5SPriyanga Ramasamy         string systemJsonName{};
147232c687f5SPriyanga Ramasamy         if constexpr (is_same<T, Parsed>::value)
147332c687f5SPriyanga Ramasamy         {
147432c687f5SPriyanga Ramasamy             // pick the right system json
147532c687f5SPriyanga Ramasamy             systemJsonName = getSystemsJson(vpdMap);
147632c687f5SPriyanga Ramasamy         }
147732c687f5SPriyanga Ramasamy 
147832c687f5SPriyanga Ramasamy         fs::path target = systemJsonName;
147932c687f5SPriyanga Ramasamy         fs::path link = INVENTORY_JSON_SYM_LINK;
148032c687f5SPriyanga Ramasamy 
1481f3e69689SSantosh Puranik         // If the symlink does not exist, we treat that as a factory reset
1482f3e69689SSantosh Puranik         processFactoryReset = !fs::exists(INVENTORY_JSON_SYM_LINK);
1483f3e69689SSantosh Puranik 
148432c687f5SPriyanga Ramasamy         // Create the directory for hosting the symlink
148532c687f5SPriyanga Ramasamy         fs::create_directories(VPD_FILES_PATH);
148632c687f5SPriyanga Ramasamy         // unlink the symlink previously created (if any)
148732c687f5SPriyanga Ramasamy         remove(INVENTORY_JSON_SYM_LINK);
148832c687f5SPriyanga Ramasamy         // create a new symlink based on the system
148932c687f5SPriyanga Ramasamy         fs::create_symlink(target, link);
149032c687f5SPriyanga Ramasamy 
149132c687f5SPriyanga Ramasamy         // Reloading the json
149232c687f5SPriyanga Ramasamy         ifstream inventoryJson(link);
149332c687f5SPriyanga Ramasamy         js = json::parse(inventoryJson);
149432c687f5SPriyanga Ramasamy         inventoryJson.close();
14957ef9c8cdSSunny Srivastava 
14967ef9c8cdSSunny Srivastava         // enable the muxes again here to cover the case where during first boot
14977ef9c8cdSSunny Srivastava         // after reset, system would have come up with default JSON
14987ef9c8cdSSunny Srivastava         // configuration and have skipped enabling mux at the beginning.
14997ef9c8cdSSunny Srivastava         // Default config JSON does not have mux entries.
15007ef9c8cdSSunny Srivastava         doEnableAllMuxChips(js);
150132c687f5SPriyanga Ramasamy     }
150232c687f5SPriyanga Ramasamy 
1503abb87edaSPriyangaRamasamy     for (const auto& item : js["frus"][filePath])
1504abb87edaSPriyangaRamasamy     {
1505abb87edaSPriyangaRamasamy         const auto& objectPath = item["inventoryPath"];
1506abb87edaSPriyangaRamasamy         sdbusplus::message::object_path object(objectPath);
15079094d4f6SSunnySrivastava1984 
15086aa5450eSShantappa Teekappanavar         vector<string> ccinList;
15096aa5450eSShantappa Teekappanavar         if (item.find("ccin") != item.end())
15106aa5450eSShantappa Teekappanavar         {
15116aa5450eSShantappa Teekappanavar             for (const auto& cc : item["ccin"])
15126aa5450eSShantappa Teekappanavar             {
15136aa5450eSShantappa Teekappanavar                 string ccin = cc;
15146aa5450eSShantappa Teekappanavar                 transform(ccin.begin(), ccin.end(), ccin.begin(), ::toupper);
15156aa5450eSShantappa Teekappanavar                 ccinList.push_back(ccin);
15166aa5450eSShantappa Teekappanavar             }
15176aa5450eSShantappa Teekappanavar         }
15186aa5450eSShantappa Teekappanavar 
15196aa5450eSShantappa Teekappanavar         if (!ccinFromVpd.empty() && !ccinList.empty() &&
15206aa5450eSShantappa Teekappanavar             (find(ccinList.begin(), ccinList.end(), ccinFromVpd) ==
15216aa5450eSShantappa Teekappanavar              ccinList.end()))
15226aa5450eSShantappa Teekappanavar         {
15236aa5450eSShantappa Teekappanavar             continue;
15246aa5450eSShantappa Teekappanavar         }
15256aa5450eSShantappa Teekappanavar 
1526e3fed701SPriyanga Ramasamy         if ((isSystemVpd) || (item.value("noprime", false)))
1527d3a379a6SSantosh Puranik         {
1528e3fed701SPriyanga Ramasamy             // Populate one time properties for the system VPD and its sub-frus
1529e3fed701SPriyanga Ramasamy             // and for other non-primeable frus.
1530d3a379a6SSantosh Puranik             // For the remaining FRUs, this will get handled as a part of
1531d3a379a6SSantosh Puranik             // priming the inventory.
1532d3a379a6SSantosh Puranik             setOneTimeProperties(objectPath, interfaces);
1533d3a379a6SSantosh Puranik         }
1534d3a379a6SSantosh Puranik 
1535abb87edaSPriyangaRamasamy         // Populate the VPD keywords and the common interfaces only if we
1536abb87edaSPriyangaRamasamy         // are asked to inherit that data from the VPD, else only add the
1537abb87edaSPriyangaRamasamy         // extraInterfaces.
1538abb87edaSPriyangaRamasamy         if (item.value("inherit", true))
1539abb87edaSPriyangaRamasamy         {
154058e22145SAlpana Kumari             if constexpr (is_same<T, Parsed>::value)
1541abb87edaSPriyangaRamasamy             {
15428e140a1cSPriyangaRamasamy                 // Each record in the VPD becomes an interface and all
15438e140a1cSPriyangaRamasamy                 // keyword within the record are properties under that
15448e140a1cSPriyangaRamasamy                 // interface.
1545abb87edaSPriyangaRamasamy                 for (const auto& record : vpdMap)
1546abb87edaSPriyangaRamasamy                 {
1547abb87edaSPriyangaRamasamy                     populateFruSpecificInterfaces(
1548e12b181bSSunnySrivastava1984                         record.second, ipzVpdInf + record.first, interfaces);
1549abb87edaSPriyangaRamasamy                 }
1550abb87edaSPriyangaRamasamy             }
155158e22145SAlpana Kumari             else if constexpr (is_same<T, KeywordVpdMap>::value)
1552abb87edaSPriyangaRamasamy             {
1553e12b181bSSunnySrivastava1984                 populateFruSpecificInterfaces(vpdMap, kwdVpdInf, interfaces);
1554abb87edaSPriyangaRamasamy             }
155588edeb6fSSantosh Puranik             if (js.find("commonInterfaces") != js.end())
155688edeb6fSSantosh Puranik             {
155788edeb6fSSantosh Puranik                 populateInterfaces(js["commonInterfaces"], interfaces, vpdMap,
155888edeb6fSSantosh Puranik                                    isSystemVpd);
155988edeb6fSSantosh Puranik             }
1560abb87edaSPriyangaRamasamy         }
15610859eb65SSantosh Puranik         else
15620859eb65SSantosh Puranik         {
15630859eb65SSantosh Puranik             // Check if we have been asked to inherit specific record(s)
156458e22145SAlpana Kumari             if constexpr (is_same<T, Parsed>::value)
15650859eb65SSantosh Puranik             {
15660859eb65SSantosh Puranik                 if (item.find("copyRecords") != item.end())
15670859eb65SSantosh Puranik                 {
15680859eb65SSantosh Puranik                     for (const auto& record : item["copyRecords"])
15690859eb65SSantosh Puranik                     {
15700859eb65SSantosh Puranik                         const string& recordName = record;
15710859eb65SSantosh Puranik                         if (vpdMap.find(recordName) != vpdMap.end())
15720859eb65SSantosh Puranik                         {
15730859eb65SSantosh Puranik                             populateFruSpecificInterfaces(
1574e12b181bSSunnySrivastava1984                                 vpdMap.at(recordName), ipzVpdInf + recordName,
15750859eb65SSantosh Puranik                                 interfaces);
15760859eb65SSantosh Puranik                         }
15770859eb65SSantosh Puranik                     }
15780859eb65SSantosh Puranik                 }
15790859eb65SSantosh Puranik             }
15800859eb65SSantosh Puranik         }
1581abb87edaSPriyangaRamasamy         // Populate interfaces and properties that are common to every FRU
15828e140a1cSPriyangaRamasamy         // and additional interface that might be defined on a per-FRU
15838e140a1cSPriyangaRamasamy         // basis.
1584abb87edaSPriyangaRamasamy         if (item.find("extraInterfaces") != item.end())
1585abb87edaSPriyangaRamasamy         {
158688edeb6fSSantosh Puranik             populateInterfaces(item["extraInterfaces"], interfaces, vpdMap,
158788edeb6fSSantosh Puranik                                isSystemVpd);
15886abdeb61SPriyanga Ramasamy             if constexpr (is_same<T, Parsed>::value)
15896abdeb61SPriyanga Ramasamy             {
15906abdeb61SPriyanga Ramasamy                 if (item["extraInterfaces"].find(
15916abdeb61SPriyanga Ramasamy                         "xyz.openbmc_project.Inventory.Item.Cpu") !=
15926abdeb61SPriyanga Ramasamy                     item["extraInterfaces"].end())
15936abdeb61SPriyanga Ramasamy                 {
15946abdeb61SPriyanga Ramasamy                     if (isCPUIOGoodOnly(getKwVal(vpdMap, "CP00", "PG")))
15956abdeb61SPriyanga Ramasamy                     {
15962c607a98SPriyanga Ramasamy                         interfaces[invItemIntf]["PrettyName"] = "IO Module";
15976abdeb61SPriyanga Ramasamy                     }
15986abdeb61SPriyanga Ramasamy                 }
15996abdeb61SPriyanga Ramasamy             }
1600abb87edaSPriyangaRamasamy         }
1601e358acbbSPriyanga Ramasamy 
1602e358acbbSPriyanga Ramasamy         // embedded property(true or false) says whether the subfru is embedded
1603e358acbbSPriyanga Ramasamy         // into the parent fru (or) not. VPD sets Present property only for
1604e358acbbSPriyanga Ramasamy         // embedded frus. If the subfru is not an embedded FRU, the subfru may
1605e358acbbSPriyanga Ramasamy         // or may not be physically present. Those non embedded frus will always
1606e358acbbSPriyanga Ramasamy         // have Present=false irrespective of its physical presence or absence.
1607e358acbbSPriyanga Ramasamy         // Eg: nvme drive in nvme slot is not an embedded FRU. So don't set
1608e358acbbSPriyanga Ramasamy         // Present to true for such sub frus.
1609e358acbbSPriyanga Ramasamy         // Eg: ethernet port is embedded into bmc card. So set Present to true
1610e358acbbSPriyanga Ramasamy         // for such sub frus. Also do not populate present property for embedded
1611e358acbbSPriyanga Ramasamy         // subfru which is synthesized. Currently there is no subfru which are
1612e358acbbSPriyanga Ramasamy         // both embedded and synthesized. But still the case is handled here.
1613e358acbbSPriyanga Ramasamy         if ((item.value("embedded", true)) &&
1614e358acbbSPriyanga Ramasamy             (!item.value("synthesized", false)))
1615e358acbbSPriyanga Ramasamy         {
1616aca61373SPriyanga Ramasamy             // Check if its required to handle presence for this FRU.
1617aca61373SPriyanga Ramasamy             if (item.value("handlePresence", true))
1618aca61373SPriyanga Ramasamy             {
1619aa8a893eSPriyanga Ramasamy                 inventory::PropertyMap presProp;
1620aa8a893eSPriyanga Ramasamy                 presProp.emplace("Present", true);
1621aa8a893eSPriyanga Ramasamy                 insertOrMerge(interfaces, invItemIntf, move(presProp));
1622e358acbbSPriyanga Ramasamy             }
1623aca61373SPriyanga Ramasamy         }
1624aa8a893eSPriyanga Ramasamy 
1625f3e69689SSantosh Puranik         if constexpr (is_same<T, Parsed>::value)
1626f3e69689SSantosh Puranik         {
1627f3e69689SSantosh Puranik             // Restore asset tag, if needed
1628f3e69689SSantosh Puranik             if (processFactoryReset && objectPath == "/system")
1629f3e69689SSantosh Puranik             {
1630f3e69689SSantosh Puranik                 fillAssetTag(interfaces, vpdMap);
1631f3e69689SSantosh Puranik             }
1632f3e69689SSantosh Puranik         }
1633f3e69689SSantosh Puranik 
1634abb87edaSPriyangaRamasamy         objects.emplace(move(object), move(interfaces));
1635abb87edaSPriyangaRamasamy     }
1636abb87edaSPriyangaRamasamy 
16378e140a1cSPriyangaRamasamy     if (isSystemVpd)
16388e140a1cSPriyangaRamasamy     {
16398e140a1cSPriyangaRamasamy         inventory::ObjectMap primeObject = primeInventory(js, vpdMap);
16408e140a1cSPriyangaRamasamy         objects.insert(primeObject.begin(), primeObject.end());
164165b83601SAlpana Kumari 
1642f05effdbSAlpana Kumari         // set the U-boot environment variable for device-tree
1643f05effdbSAlpana Kumari         if constexpr (is_same<T, Parsed>::value)
1644f05effdbSAlpana Kumari         {
1645e5f177a5SSantosh Puranik             setDevTreeEnv(fs::path(getSystemsJson(vpdMap)).filename());
1646f05effdbSAlpana Kumari         }
16478e140a1cSPriyangaRamasamy     }
16488e140a1cSPriyangaRamasamy 
1649abb87edaSPriyangaRamasamy     // Notify PIM
16506c71c9dcSSunny Srivastava     common::utility::callPIM(move(objects));
1651abb87edaSPriyangaRamasamy }
1652abb87edaSPriyangaRamasamy 
main(int argc,char ** argv)1653abb87edaSPriyangaRamasamy int main(int argc, char** argv)
1654abb87edaSPriyangaRamasamy {
1655abb87edaSPriyangaRamasamy     int rc = 0;
1656a20be8ecSSunnySrivastava1984     json js{};
1657c2fe40f8SPriyangaRamasamy     Binary vpdVector{};
1658c2fe40f8SPriyangaRamasamy     string file{};
1659f457a3efSjinuthomas     string driver{};
1660a20be8ecSSunnySrivastava1984     // map to hold additional data in case of logging pel
1661a20be8ecSSunnySrivastava1984     PelAdditionalData additionalData{};
1662a20be8ecSSunnySrivastava1984 
1663a20be8ecSSunnySrivastava1984     // this is needed to hold base fru inventory path in case there is ECC or
1664a20be8ecSSunnySrivastava1984     // vpd exception while parsing the file
1665a20be8ecSSunnySrivastava1984     std::string baseFruInventoryPath = {};
1666abb87edaSPriyangaRamasamy 
166738ee9c8dSKantesh Nagaradder     // It holds the backup EEPROM file path for the system backplane's critical
166838ee9c8dSKantesh Nagaradder     // data
166938ee9c8dSKantesh Nagaradder     std::string systemVpdBackupPath{};
167038ee9c8dSKantesh Nagaradder 
167138ee9c8dSKantesh Nagaradder     // It holds the inventory path of backup EEPROM file
167238ee9c8dSKantesh Nagaradder     std::string backupVpdInvPath{};
167338ee9c8dSKantesh Nagaradder 
167438ee9c8dSKantesh Nagaradder     bool isSystemVpd = false;
167538ee9c8dSKantesh Nagaradder 
16760746eeebSSunny Srivastava     // severity for PEL
16770746eeebSSunny Srivastava     PelSeverity pelSeverity = PelSeverity::WARNING;
16780746eeebSSunny Srivastava 
1679abb87edaSPriyangaRamasamy     try
1680abb87edaSPriyangaRamasamy     {
1681f457a3efSjinuthomas         App app{"ibm-read-vpd - App to read IPZ/Jedec format VPD, parse it and "
1682f457a3efSjinuthomas                 "store it in DBUS"};
1683abb87edaSPriyangaRamasamy 
1684abb87edaSPriyangaRamasamy         app.add_option("-f, --file", file, "File containing VPD (IPZ/KEYWORD)")
16852f793048SAlpana Kumari             ->required();
1686abb87edaSPriyangaRamasamy 
1687f457a3efSjinuthomas         app.add_option("--driver", driver,
1688f457a3efSjinuthomas                        "Driver used by kernel (at24,at25,ee1004)")
1689f457a3efSjinuthomas             ->required();
1690f457a3efSjinuthomas 
1691abb87edaSPriyangaRamasamy         CLI11_PARSE(app, argc, argv);
1692abb87edaSPriyangaRamasamy 
16930746eeebSSunny Srivastava         // PEL severity should be ERROR in case of any system VPD failure
16940746eeebSSunny Srivastava         if (file == systemVpdFilePath)
16950746eeebSSunny Srivastava         {
16960746eeebSSunny Srivastava             pelSeverity = PelSeverity::ERROR;
169738ee9c8dSKantesh Nagaradder             isSystemVpd = true;
16980746eeebSSunny Srivastava         }
16990746eeebSSunny Srivastava 
1700f457a3efSjinuthomas         // Check if input file is not empty.
1701f457a3efSjinuthomas         if ((file.empty()) || (driver.empty()))
1702f457a3efSjinuthomas         {
1703f457a3efSjinuthomas             std::cerr << "Encountered empty input parameter file [" << file
1704f457a3efSjinuthomas                       << "] driver [" << driver << "]" << std::endl;
1705f457a3efSjinuthomas             return 0;
1706f457a3efSjinuthomas         }
1707f457a3efSjinuthomas 
1708f457a3efSjinuthomas         // Check if currently supported driver or not
1709f457a3efSjinuthomas         if ((driver != at24driver) && (driver != at25driver) &&
1710f457a3efSjinuthomas             (driver != ee1004driver))
1711f457a3efSjinuthomas         {
1712f457a3efSjinuthomas             std::cerr << "The driver [" << driver << "] is not supported."
1713f457a3efSjinuthomas                       << std::endl;
1714f457a3efSjinuthomas             return 0;
1715f457a3efSjinuthomas         }
1716f457a3efSjinuthomas 
17170246a4d7SSantosh Puranik         auto jsonToParse = INVENTORY_JSON_DEFAULT;
17180246a4d7SSantosh Puranik 
17190246a4d7SSantosh Puranik         // If the symlink exists, it means it has been setup for us, switch the
17200246a4d7SSantosh Puranik         // path
17210246a4d7SSantosh Puranik         if (fs::exists(INVENTORY_JSON_SYM_LINK))
17220246a4d7SSantosh Puranik         {
17230246a4d7SSantosh Puranik             jsonToParse = INVENTORY_JSON_SYM_LINK;
17240246a4d7SSantosh Puranik         }
17250246a4d7SSantosh Puranik 
1726abb87edaSPriyangaRamasamy         // Make sure that the file path we get is for a supported EEPROM
17270246a4d7SSantosh Puranik         ifstream inventoryJson(jsonToParse);
1728a20be8ecSSunnySrivastava1984         if (!inventoryJson)
1729a20be8ecSSunnySrivastava1984         {
17300746eeebSSunny Srivastava             throw(VpdJsonException("Failed to access Json path", jsonToParse));
1731a20be8ecSSunnySrivastava1984         }
1732a20be8ecSSunnySrivastava1984 
1733a20be8ecSSunnySrivastava1984         try
1734a20be8ecSSunnySrivastava1984         {
1735a20be8ecSSunnySrivastava1984             js = json::parse(inventoryJson);
1736a20be8ecSSunnySrivastava1984         }
17378e15b93aSPatrick Williams         catch (const json::parse_error& ex)
1738a20be8ecSSunnySrivastava1984         {
17390746eeebSSunny Srivastava             throw(VpdJsonException("Json parsing failed", jsonToParse));
1740a20be8ecSSunnySrivastava1984         }
1741abb87edaSPriyangaRamasamy 
174212e24ff3SSantosh Puranik         // Do we have the mandatory "frus" section?
174312e24ff3SSantosh Puranik         if (js.find("frus") == js.end())
174412e24ff3SSantosh Puranik         {
174512e24ff3SSantosh Puranik             throw(VpdJsonException("FRUs section not found in JSON",
174612e24ff3SSantosh Puranik                                    jsonToParse));
174712e24ff3SSantosh Puranik         }
174812e24ff3SSantosh Puranik 
1749647868edSPriyangaRamasamy         // Check if it's a udev path - patterned as(/ahb/ahb:apb/ahb:apb:bus@)
1750647868edSPriyangaRamasamy         if (file.find("/ahb:apb") != string::npos)
1751647868edSPriyangaRamasamy         {
1752647868edSPriyangaRamasamy             // Translate udev path to a generic /sys/bus/.. file path.
1753f457a3efSjinuthomas             udevToGenericPath(file, driver);
175412e24ff3SSantosh Puranik 
175512e24ff3SSantosh Puranik             if ((js["frus"].find(file) != js["frus"].end()) &&
175650f60bf8SSantosh Puranik                 (file == systemVpdFilePath))
1757647868edSPriyangaRamasamy             {
1758*af921756SManojkiran Eda                 std::cout << "We have already collected system VPD, skipping."
1759f457a3efSjinuthomas                           << std::endl;
1760647868edSPriyangaRamasamy                 return 0;
1761647868edSPriyangaRamasamy             }
1762647868edSPriyangaRamasamy         }
1763647868edSPriyangaRamasamy 
17642cb6769eSJinu Joy Thomas         // Enable all mux which are used for connecting to the i2c on the pcie
17652cb6769eSJinu Joy Thomas         // slots for pcie cards. These are not enabled by kernel due to an issue
17662cb6769eSJinu Joy Thomas         // seen with Castello cards, where the i2c line hangs on a probe.
17672cb6769eSJinu Joy Thomas         // To run it only once have kept it under System vpd check.
17682cb6769eSJinu Joy Thomas         // we need to run this on all BMC reboots so kept here
17692cb6769eSJinu Joy Thomas         if (file == systemVpdFilePath)
17702cb6769eSJinu Joy Thomas         {
17712cb6769eSJinu Joy Thomas             doEnableAllMuxChips(js);
17722cb6769eSJinu Joy Thomas         }
17732cb6769eSJinu Joy Thomas 
1774647868edSPriyangaRamasamy         if (file.empty())
1775647868edSPriyangaRamasamy         {
1776f457a3efSjinuthomas             std::cerr << "The EEPROM path <" << file << "> is not valid.";
1777647868edSPriyangaRamasamy             return 0;
1778647868edSPriyangaRamasamy         }
177912e24ff3SSantosh Puranik         if (js["frus"].find(file) == js["frus"].end())
1780abb87edaSPriyangaRamasamy         {
1781f457a3efSjinuthomas             std::cerr << "The EEPROM path [" << file
1782f457a3efSjinuthomas                       << "] is not found in the json." << std::endl;
178388edeb6fSSantosh Puranik             return 0;
1784abb87edaSPriyangaRamasamy         }
1785abb87edaSPriyangaRamasamy 
17862f793048SAlpana Kumari         if (!fs::exists(file))
17872f793048SAlpana Kumari         {
1788f457a3efSjinuthomas             std::cout << "Device path: " << file
1789d640f696Sjinuthomas                       << " does not exist. Spurious udev event? Exiting."
1790d640f696Sjinuthomas                       << std::endl;
17912f793048SAlpana Kumari             return 0;
17922f793048SAlpana Kumari         }
17932f793048SAlpana Kumari 
1794dedb5a63SSantosh Puranik         // In case of system VPD it will already be filled, Don't have to
1795dedb5a63SSantosh Puranik         // overwrite that.
1796dedb5a63SSantosh Puranik         if (baseFruInventoryPath.empty())
1797dedb5a63SSantosh Puranik         {
1798a20be8ecSSunnySrivastava1984             baseFruInventoryPath = js["frus"][file][0]["inventoryPath"];
1799dedb5a63SSantosh Puranik         }
1800dedb5a63SSantosh Puranik 
18018589375fSSantosh Puranik         // Check if we can read the VPD file based on the power state
180227a5e95aSSantosh Puranik         // We skip reading VPD when the power is ON in two scenarios:
180331d50fa7SSantosh Puranik         // 1) The eeprom we are trying to read is that of the system VPD and the
180431d50fa7SSantosh Puranik         // JSON symlink is already setup (the symlink's existence tells us we
180531d50fa7SSantosh Puranik         // are not coming out of a factory reset)
180631d50fa7SSantosh Puranik         // 2) The JSON tells us that the FRU EEPROM cannot be
180731d50fa7SSantosh Puranik         // read when we are powered ON.
180827a5e95aSSantosh Puranik         if (js["frus"][file].at(0).value("powerOffOnly", false) ||
180931d50fa7SSantosh Puranik             (file == systemVpdFilePath && fs::exists(INVENTORY_JSON_SYM_LINK)))
18108589375fSSantosh Puranik         {
18118589375fSSantosh Puranik             if ("xyz.openbmc_project.State.Chassis.PowerState.On" ==
18128589375fSSantosh Puranik                 getPowerState())
18138589375fSSantosh Puranik             {
1814f457a3efSjinuthomas                 std::cout << "This VPD cannot be read when power is ON"
1815f457a3efSjinuthomas                           << std::endl;
18168589375fSSantosh Puranik                 return 0;
18178589375fSSantosh Puranik             }
18188589375fSSantosh Puranik         }
1819a20be8ecSSunnySrivastava1984 
1820e9c57535SSantosh Puranik         // Check if this VPD should be recollected at all
1821e9c57535SSantosh Puranik         if (!needsRecollection(js, file))
1822e9c57535SSantosh Puranik         {
1823f457a3efSjinuthomas             std::cout << "Skip VPD recollection for: " << file << std::endl;
1824e9c57535SSantosh Puranik             return 0;
1825e9c57535SSantosh Puranik         }
1826e9c57535SSantosh Puranik 
18272f793048SAlpana Kumari         try
18282f793048SAlpana Kumari         {
18292f793048SAlpana Kumari             variant<KeywordVpdMap, Store> parseResult;
183037992a65SSunny Srivastava             parseResult = parseVpdFile(file, js);
183138ee9c8dSKantesh Nagaradder 
183238ee9c8dSKantesh Nagaradder             if (isSystemVpd)
183338ee9c8dSKantesh Nagaradder             {
183438ee9c8dSKantesh Nagaradder                 // Get the value of systemVpdBackupPath field from json
183538ee9c8dSKantesh Nagaradder                 systemVpdBackupPath = js["frus"][systemVpdFilePath].at(0).value(
183638ee9c8dSKantesh Nagaradder                     "systemVpdBackupPath", "");
183738ee9c8dSKantesh Nagaradder 
183838ee9c8dSKantesh Nagaradder                 if (!systemVpdBackupPath.empty())
183938ee9c8dSKantesh Nagaradder                 {
184038ee9c8dSKantesh Nagaradder                     backupVpdInvPath =
184138ee9c8dSKantesh Nagaradder                         js["frus"][systemVpdBackupPath][0]["inventoryPath"]
184238ee9c8dSKantesh Nagaradder                             .get_ref<const nlohmann::json::string_t&>();
184338ee9c8dSKantesh Nagaradder                 }
184438ee9c8dSKantesh Nagaradder             }
18459a19554cSSunnySrivastava1984 
1846e12b181bSSunnySrivastava1984             if (auto pVal = get_if<Store>(&parseResult))
1847abb87edaSPriyangaRamasamy             {
1848e12b181bSSunnySrivastava1984                 populateDbus(pVal->getVpdMap(), js, file);
1849e12b181bSSunnySrivastava1984             }
1850e12b181bSSunnySrivastava1984             else if (auto pVal = get_if<KeywordVpdMap>(&parseResult))
1851abb87edaSPriyangaRamasamy             {
1852e12b181bSSunnySrivastava1984                 populateDbus(*pVal, js, file);
1853abb87edaSPriyangaRamasamy             }
1854abb87edaSPriyangaRamasamy         }
18558e15b93aSPatrick Williams         catch (const exception& e)
18562f793048SAlpana Kumari         {
185737992a65SSunny Srivastava             if (!systemVpdBackupPath.empty())
185837992a65SSunny Srivastava             {
185937992a65SSunny Srivastava                 file = systemVpdBackupPath;
186037992a65SSunny Srivastava                 baseFruInventoryPath = backupVpdInvPath;
186137992a65SSunny Srivastava             }
186237992a65SSunny Srivastava 
1863735dee9bSAlpana Kumari             executePostFailAction(js, file);
1864a504c3eeSPriyangaRamasamy             throw;
18652f793048SAlpana Kumari         }
18662f793048SAlpana Kumari     }
1867a20be8ecSSunnySrivastava1984     catch (const VpdJsonException& ex)
1868a20be8ecSSunnySrivastava1984     {
1869a20be8ecSSunnySrivastava1984         additionalData.emplace("JSON_PATH", ex.getJsonPath());
1870a20be8ecSSunnySrivastava1984         additionalData.emplace("DESCRIPTION", ex.what());
1871a2ddc96eSSunny Srivastava         createPEL(additionalData, pelSeverity, errIntfForJsonFailure, nullptr);
1872a20be8ecSSunnySrivastava1984 
1873f457a3efSjinuthomas         std::cerr << ex.what() << "\n";
1874a20be8ecSSunnySrivastava1984         rc = -1;
1875a20be8ecSSunnySrivastava1984     }
1876a20be8ecSSunnySrivastava1984     catch (const VpdEccException& ex)
1877a20be8ecSSunnySrivastava1984     {
1878a20be8ecSSunnySrivastava1984         additionalData.emplace("DESCRIPTION", "ECC check failed");
1879a20be8ecSSunnySrivastava1984         additionalData.emplace("CALLOUT_INVENTORY_PATH",
1880a20be8ecSSunnySrivastava1984                                INVENTORY_PATH + baseFruInventoryPath);
1881a2ddc96eSSunny Srivastava         createPEL(additionalData, pelSeverity, errIntfForEccCheckFail, nullptr);
188238ee9c8dSKantesh Nagaradder 
188338ee9c8dSKantesh Nagaradder         if (systemVpdBackupPath.empty())
188438ee9c8dSKantesh Nagaradder         {
1885c2fe40f8SPriyangaRamasamy             dumpBadVpd(file, vpdVector);
188638ee9c8dSKantesh Nagaradder         }
188738ee9c8dSKantesh Nagaradder 
1888f457a3efSjinuthomas         std::cerr << ex.what() << "\n";
1889a20be8ecSSunnySrivastava1984         rc = -1;
1890a20be8ecSSunnySrivastava1984     }
1891a20be8ecSSunnySrivastava1984     catch (const VpdDataException& ex)
1892a20be8ecSSunnySrivastava1984     {
18935cb3b1f3Salpana07         if (isThisPcieOnPass1planar(js, file))
18945cb3b1f3Salpana07         {
1895f457a3efSjinuthomas             std::cout << "Pcie_device  [" << file
18965cb3b1f3Salpana07                       << "]'s VPD is not valid on PASS1 planar.Ignoring.\n";
18975cb3b1f3Salpana07             rc = 0;
18985cb3b1f3Salpana07         }
189953b38ed0SSantosh Puranik         else if (!(isPresent(js, file).value_or(true)))
190053b38ed0SSantosh Puranik         {
1901f457a3efSjinuthomas             std::cout << "FRU at: " << file
190253b38ed0SSantosh Puranik                       << " is not detected present. Ignore parser error.\n";
190353b38ed0SSantosh Puranik             rc = 0;
190453b38ed0SSantosh Puranik         }
19055cb3b1f3Salpana07         else
19065cb3b1f3Salpana07         {
19075cb3b1f3Salpana07             string errorMsg =
19085cb3b1f3Salpana07                 "VPD file is either empty or invalid. Parser failed for [";
19095cb3b1f3Salpana07             errorMsg += file;
19105cb3b1f3Salpana07             errorMsg += "], with error = " + std::string(ex.what());
19115cb3b1f3Salpana07 
19125cb3b1f3Salpana07             additionalData.emplace("DESCRIPTION", errorMsg);
1913a20be8ecSSunnySrivastava1984             additionalData.emplace("CALLOUT_INVENTORY_PATH",
1914a20be8ecSSunnySrivastava1984                                    INVENTORY_PATH + baseFruInventoryPath);
1915a2ddc96eSSunny Srivastava             createPEL(additionalData, pelSeverity, errIntfForInvalidVPD,
1916a2ddc96eSSunny Srivastava                       nullptr);
19175cb3b1f3Salpana07 
1918a20be8ecSSunnySrivastava1984             rc = -1;
1919a20be8ecSSunnySrivastava1984         }
19205cb3b1f3Salpana07     }
19218e15b93aSPatrick Williams     catch (const exception& e)
1922abb87edaSPriyangaRamasamy     {
1923c2fe40f8SPriyangaRamasamy         dumpBadVpd(file, vpdVector);
1924f457a3efSjinuthomas         std::cerr << e.what() << "\n";
1925abb87edaSPriyangaRamasamy         rc = -1;
1926abb87edaSPriyangaRamasamy     }
1927abb87edaSPriyangaRamasamy 
1928abb87edaSPriyangaRamasamy     return rc;
1929abb87edaSPriyangaRamasamy }
1930