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