blob: 94b7f55de6b585881e9089f751b7d3bb06195905 [file] [log] [blame]
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301#include "config.h"
2
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05003#include "common_utility.hpp"
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05304#include "defines.hpp"
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05005#include "ibm_vpd_utils.hpp"
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05006#include "ipz_parser.hpp"
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05307#include "keyword_vpd_parser.hpp"
Alpana Kumaria00936f2020-04-14 07:15:46 -05008#include "memory_vpd_parser.hpp"
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05009#include "parser_factory.hpp"
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -050010#include "vpd_exceptions.hpp"
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053011
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050012#include <assert.h>
Alpana Kumari8ea3f6d2020-04-02 00:26:07 -050013#include <ctype.h>
14
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053015#include <CLI/CLI.hpp>
Santosh Puranik88edeb62020-03-02 12:00:09 +053016#include <algorithm>
alpana077ce68722021-07-25 13:23:59 -050017#include <boost/algorithm/string.hpp>
Alpana Kumari65b83602020-09-01 00:24:56 -050018#include <cstdarg>
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053019#include <exception>
PriyangaRamasamy83a1d5d2020-04-30 19:15:43 +053020#include <filesystem>
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053021#include <fstream>
Alpana Kumari2f793042020-08-18 05:51:03 -050022#include <gpiod.hpp>
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053023#include <iostream>
24#include <iterator>
Andrew Geissler280197e2020-12-08 20:51:49 -060025#include <phosphor-logging/log.hpp>
alpana077ce68722021-07-25 13:23:59 -050026#include <regex>
Santosh Puranik253fbe92022-10-06 22:38:09 +053027#include <thread>
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053028
29using namespace std;
30using namespace openpower::vpd;
31using namespace CLI;
32using namespace vpd::keyword::parser;
PriyangaRamasamy83a1d5d2020-04-30 19:15:43 +053033using namespace openpower::vpd::constants;
34namespace fs = filesystem;
35using json = nlohmann::json;
SunnySrivastava1984e12b1812020-05-26 02:23:11 -050036using namespace openpower::vpd::parser::factory;
SunnySrivastava1984945a02d2020-05-06 01:55:41 -050037using namespace openpower::vpd::inventory;
Alpana Kumaria00936f2020-04-14 07:15:46 -050038using namespace openpower::vpd::memory::parser;
SunnySrivastava1984e12b1812020-05-26 02:23:11 -050039using namespace openpower::vpd::parser::interface;
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -050040using namespace openpower::vpd::exceptions;
Andrew Geissler280197e2020-12-08 20:51:49 -060041using namespace phosphor::logging;
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053042
Santosh Puranik88edeb62020-03-02 12:00:09 +053043/**
Santosh Puranike9c57532022-03-15 16:51:51 +053044 * @brief Returns the BMC state
45 */
46static auto getBMCState()
47{
48 std::string bmcState;
49 try
50 {
51 auto bus = sdbusplus::bus::new_default();
52 auto properties = bus.new_method_call(
53 "xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0",
54 "org.freedesktop.DBus.Properties", "Get");
55 properties.append("xyz.openbmc_project.State.BMC");
56 properties.append("CurrentBMCState");
57 auto result = bus.call(properties);
58 std::variant<std::string> val;
59 result.read(val);
60 if (auto pVal = std::get_if<std::string>(&val))
61 {
62 bmcState = *pVal;
63 }
64 }
65 catch (const sdbusplus::exception::SdBusError& e)
66 {
67 // Ignore any error
68 std::cerr << "Failed to get BMC state: " << e.what() << "\n";
69 }
70 return bmcState;
71}
72
73/**
74 * @brief Check if the FRU is in the cache
75 *
76 * Checks if the FRU associated with the supplied D-Bus object path is already
77 * on D-Bus. This can be used to test if a VPD collection is required for this
78 * FRU. It uses the "xyz.openbmc_project.Inventory.Item, Present" property to
79 * determine the presence of a FRU in the cache.
80 *
81 * @param objectPath - The D-Bus object path without the PIM prefix.
82 * @return true if the object exists on D-Bus, false otherwise.
83 */
84static auto isFruInVpdCache(const std::string& objectPath)
85{
86 try
87 {
88 auto bus = sdbusplus::bus::new_default();
89 auto invPath = std::string{pimPath} + objectPath;
90 auto props = bus.new_method_call(
91 "xyz.openbmc_project.Inventory.Manager", invPath.c_str(),
92 "org.freedesktop.DBus.Properties", "Get");
93 props.append("xyz.openbmc_project.Inventory.Item");
94 props.append("Present");
95 auto result = bus.call(props);
96 std::variant<bool> present;
97 result.read(present);
98 if (auto pVal = std::get_if<bool>(&present))
99 {
100 return *pVal;
101 }
102 return false;
103 }
104 catch (const sdbusplus::exception::SdBusError& e)
105 {
106 std::cout << "FRU: " << objectPath << " not in D-Bus\n";
107 // Assume not present in case of an error
108 return false;
109 }
110}
111
112/**
113 * @brief Check if VPD recollection is needed for the given EEPROM
114 *
115 * Not all FRUs can be swapped at BMC ready state. This function does the
116 * following:
117 * -- Check if the FRU is marked as "pluggableAtStandby" OR
118 * "concurrentlyMaintainable". If so, return true.
119 * -- Check if we are at BMC NotReady state. If we are, then return true.
120 * -- Else check if the FRU is not present in the VPD cache (to cover for VPD
121 * force collection). If not found in the cache, return true.
122 * -- Else return false.
123 *
124 * @param js - JSON Object.
125 * @param filePath - The EEPROM file.
126 * @return true if collection should be attempted, false otherwise.
127 */
128static auto needsRecollection(const nlohmann::json& js, const string& filePath)
129{
130 if (js["frus"][filePath].at(0).value("pluggableAtStandby", false) ||
131 js["frus"][filePath].at(0).value("concurrentlyMaintainable", false))
132 {
133 return true;
134 }
135 if (getBMCState() == "xyz.openbmc_project.State.BMC.BMCState.NotReady")
136 {
137 return true;
138 }
139 if (!isFruInVpdCache(js["frus"][filePath].at(0).value("inventoryPath", "")))
140 {
141 return true;
142 }
143 return false;
144}
145
146/**
Santosh Puranik88edeb62020-03-02 12:00:09 +0530147 * @brief Expands location codes
148 */
149static auto expandLocationCode(const string& unexpanded, const Parsed& vpdMap,
150 bool isSystemVpd)
151{
152 auto expanded{unexpanded};
153 static constexpr auto SYSTEM_OBJECT = "/system/chassis/motherboard";
154 static constexpr auto VCEN_IF = "com.ibm.ipzvpd.VCEN";
155 static constexpr auto VSYS_IF = "com.ibm.ipzvpd.VSYS";
156 size_t idx = expanded.find("fcs");
157 try
158 {
159 if (idx != string::npos)
160 {
161 string fc{};
162 string se{};
163 if (isSystemVpd)
164 {
165 const auto& fcData = vpdMap.at("VCEN").at("FC");
166 const auto& seData = vpdMap.at("VCEN").at("SE");
167 fc = string(fcData.data(), fcData.size());
168 se = string(seData.data(), seData.size());
169 }
170 else
171 {
172 fc = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "FC");
173 se = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "SE");
174 }
175
Alpana Kumari81671f62021-02-10 02:21:59 -0600176 // TODO: See if ND0 can be placed in the JSON
177 expanded.replace(idx, 3, fc.substr(0, 4) + ".ND0." + se);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530178 }
179 else
180 {
181 idx = expanded.find("mts");
182 if (idx != string::npos)
183 {
184 string mt{};
185 string se{};
186 if (isSystemVpd)
187 {
188 const auto& mtData = vpdMap.at("VSYS").at("TM");
189 const auto& seData = vpdMap.at("VSYS").at("SE");
190 mt = string(mtData.data(), mtData.size());
191 se = string(seData.data(), seData.size());
192 }
193 else
194 {
195 mt = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "TM");
196 se = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "SE");
197 }
198
199 replace(mt.begin(), mt.end(), '-', '.');
200 expanded.replace(idx, 3, mt + "." + se);
201 }
202 }
203 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500204 catch (const exception& e)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530205 {
Alpana Kumari58e22142020-05-05 00:22:12 -0500206 cerr << "Failed to expand location code with exception: " << e.what()
207 << "\n";
Santosh Puranik88edeb62020-03-02 12:00:09 +0530208 }
209 return expanded;
210}
Alpana Kumari2f793042020-08-18 05:51:03 -0500211
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530212/**
213 * @brief Populate FRU specific interfaces.
214 *
215 * This is a common method which handles both
216 * ipz and keyword specific interfaces thus,
217 * reducing the code redundancy.
218 * @param[in] map - Reference to the innermost keyword-value map.
219 * @param[in] preIntrStr - Reference to the interface string.
220 * @param[out] interfaces - Reference to interface map.
221 */
222template <typename T>
223static void populateFruSpecificInterfaces(const T& map,
224 const string& preIntrStr,
225 inventory::InterfaceMap& interfaces)
226{
227 inventory::PropertyMap prop;
228
229 for (const auto& kwVal : map)
230 {
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530231 auto kw = kwVal.first;
232
233 if (kw[0] == '#')
234 {
Alpana Kumari58e22142020-05-05 00:22:12 -0500235 kw = string("PD_") + kw[1];
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530236 }
Alpana Kumari8ea3f6d2020-04-02 00:26:07 -0500237 else if (isdigit(kw[0]))
238 {
Alpana Kumari58e22142020-05-05 00:22:12 -0500239 kw = string("N_") + kw;
Alpana Kumari8ea3f6d2020-04-02 00:26:07 -0500240 }
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000241 if constexpr (is_same<T, KeywordVpdMap>::value)
242 {
jinuthomasd640f692023-03-28 04:13:23 -0500243 if (auto keywordValue = get_if<Binary>(&kwVal.second))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000244 {
jinuthomasd640f692023-03-28 04:13:23 -0500245 Binary vec((*keywordValue).begin(), (*keywordValue).end());
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000246 prop.emplace(move(kw), move(vec));
247 }
jinuthomasd640f692023-03-28 04:13:23 -0500248 else if (auto keywordValue = get_if<std::string>(&kwVal.second))
249 {
250 Binary vec((*keywordValue).begin(), (*keywordValue).end());
251 prop.emplace(move(kw), move(vec));
252 }
253 else if (auto keywordValue = get_if<size_t>(&kwVal.second))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000254 {
255 if (kw == "MemorySizeInKB")
256 {
257 inventory::PropertyMap memProp;
jinuthomasd640f692023-03-28 04:13:23 -0500258 memProp.emplace(move(kw), ((*keywordValue)));
259 interfaces.emplace(
260 "xyz.openbmc_project.Inventory.Item.Dimm",
261 move(memProp));
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000262 }
jinuthomasd640f692023-03-28 04:13:23 -0500263 else
264 {
265 cerr << "Unknown Keyword[" << kw << "] found ";
266 }
267 }
268 else
269 {
270 cerr << "Unknown Variant found ";
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000271 }
272 }
273 else
274 {
275 Binary vec(kwVal.second.begin(), kwVal.second.end());
276 prop.emplace(move(kw), move(vec));
277 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530278 }
279
280 interfaces.emplace(preIntrStr, move(prop));
281}
282
283/**
284 * @brief Populate Interfaces.
285 *
286 * This method populates common and extra interfaces to dbus.
287 * @param[in] js - json object
288 * @param[out] interfaces - Reference to interface map
289 * @param[in] vpdMap - Reference to the parsed vpd map.
Santosh Puranik88edeb62020-03-02 12:00:09 +0530290 * @param[in] isSystemVpd - Denotes whether we are collecting the system VPD.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530291 */
292template <typename T>
293static void populateInterfaces(const nlohmann::json& js,
294 inventory::InterfaceMap& interfaces,
Santosh Puranik88edeb62020-03-02 12:00:09 +0530295 const T& vpdMap, bool isSystemVpd)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530296{
297 for (const auto& ifs : js.items())
298 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530299 string inf = ifs.key();
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530300 inventory::PropertyMap props;
301
302 for (const auto& itr : ifs.value().items())
303 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530304 const string& busProp = itr.key();
305
Alpana Kumari31970de2020-02-17 06:49:57 -0600306 if (itr.value().is_boolean())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530307 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530308 props.emplace(busProp, itr.value().get<bool>());
309 }
310 else if (itr.value().is_string())
311 {
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600312 if (busProp == "LocationCode" && inf == IBM_LOCATION_CODE_INF)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530313 {
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600314 std::string prop;
315 if constexpr (is_same<T, Parsed>::value)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530316 {
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000317 // TODO deprecate the com.ibm interface later
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600318 prop = expandLocationCode(itr.value().get<string>(),
319 vpdMap, isSystemVpd);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530320 }
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600321 else if constexpr (is_same<T, KeywordVpdMap>::value)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530322 {
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600323 // Send empty Parsed object to expandLocationCode api.
324 prop = expandLocationCode(itr.value().get<string>(),
325 Parsed{}, false);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530326 }
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600327 props.emplace(busProp, prop);
328 interfaces.emplace(XYZ_LOCATION_CODE_INF, props);
329 interfaces.emplace(IBM_LOCATION_CODE_INF, props);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530330 }
331 else
332 {
333 props.emplace(busProp, itr.value().get<string>());
334 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530335 }
Santosh Puraniked609af2021-06-21 11:30:07 +0530336 else if (itr.value().is_array())
337 {
338 try
339 {
340 props.emplace(busProp, itr.value().get<Binary>());
341 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500342 catch (const nlohmann::detail::type_error& e)
Santosh Puraniked609af2021-06-21 11:30:07 +0530343 {
344 std::cerr << "Type exception: " << e.what() << "\n";
345 // Ignore any type errors
346 }
347 }
Alpana Kumari31970de2020-02-17 06:49:57 -0600348 else if (itr.value().is_object())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530349 {
Alpana Kumari31970de2020-02-17 06:49:57 -0600350 const string& rec = itr.value().value("recordName", "");
351 const string& kw = itr.value().value("keywordName", "");
352 const string& encoding = itr.value().value("encoding", "");
353
Alpana Kumari58e22142020-05-05 00:22:12 -0500354 if constexpr (is_same<T, Parsed>::value)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530355 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530356 if (!rec.empty() && !kw.empty() && vpdMap.count(rec) &&
357 vpdMap.at(rec).count(kw))
Alpana Kumari31970de2020-02-17 06:49:57 -0600358 {
359 auto encoded =
360 encodeKeyword(vpdMap.at(rec).at(kw), encoding);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530361 props.emplace(busProp, encoded);
Alpana Kumari31970de2020-02-17 06:49:57 -0600362 }
363 }
Alpana Kumari58e22142020-05-05 00:22:12 -0500364 else if constexpr (is_same<T, KeywordVpdMap>::value)
Alpana Kumari31970de2020-02-17 06:49:57 -0600365 {
366 if (!kw.empty() && vpdMap.count(kw))
367 {
jinuthomasd640f692023-03-28 04:13:23 -0500368 if (auto kwValue = get_if<Binary>(&vpdMap.at(kw)))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000369 {
370 auto prop =
371 string((*kwValue).begin(), (*kwValue).end());
372
373 auto encoded = encodeKeyword(prop, encoding);
374
375 props.emplace(busProp, encoded);
376 }
jinuthomasd640f692023-03-28 04:13:23 -0500377 else if (auto kwValue =
378 get_if<std::string>(&vpdMap.at(kw)))
379 {
380 auto prop =
381 string((*kwValue).begin(), (*kwValue).end());
382
383 auto encoded = encodeKeyword(prop, encoding);
384
385 props.emplace(busProp, encoded);
386 }
387 else if (auto uintValue =
388 get_if<size_t>(&vpdMap.at(kw)))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000389 {
390 props.emplace(busProp, *uintValue);
391 }
jinuthomasd640f692023-03-28 04:13:23 -0500392 else
393 {
394 std::cerr << " Unknown Keyword [" << kw
395 << "] Encountered";
396 }
Alpana Kumari31970de2020-02-17 06:49:57 -0600397 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530398 }
399 }
Matt Spinlerb1e64bb2021-09-08 09:57:48 -0500400 else if (itr.value().is_number())
401 {
402 // For now assume the value is a size_t. In the future it would
403 // be nice to come up with a way to get the type from the JSON.
404 props.emplace(busProp, itr.value().get<size_t>());
405 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530406 }
Priyanga Ramasamyaa8a8932022-01-27 09:12:41 -0600407 insertOrMerge(interfaces, inf, move(props));
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530408 }
409}
410
alpana075cb3b1f2021-12-16 11:19:36 -0600411/**
412 * @brief This API checks if this FRU is pcie_devices. If yes then it further
413 * checks whether it is PASS1 planar.
414 */
415static bool isThisPcieOnPass1planar(const nlohmann::json& js,
416 const string& file)
417{
418 auto isThisPCIeDev = false;
419 auto isPASS1 = false;
420
421 // Check if it is a PCIE device
422 if (js["frus"].find(file) != js["frus"].end())
423 {
Santosh Puranikc03f3902022-04-14 10:58:26 +0530424 if ((js["frus"][file].at(0).find("extraInterfaces") !=
425 js["frus"][file].at(0).end()))
alpana075cb3b1f2021-12-16 11:19:36 -0600426 {
Santosh Puranikc03f3902022-04-14 10:58:26 +0530427 if (js["frus"][file].at(0)["extraInterfaces"].find(
alpana075cb3b1f2021-12-16 11:19:36 -0600428 "xyz.openbmc_project.Inventory.Item.PCIeDevice") !=
Santosh Puranikc03f3902022-04-14 10:58:26 +0530429 js["frus"][file].at(0)["extraInterfaces"].end())
alpana075cb3b1f2021-12-16 11:19:36 -0600430 {
431 isThisPCIeDev = true;
432 }
433 }
434 }
435
436 if (isThisPCIeDev)
437 {
Alpana Kumaria6181e22022-05-12 05:01:53 -0500438 // Collect HW version and SystemType to know if it is PASS1 planar.
alpana075cb3b1f2021-12-16 11:19:36 -0600439 auto bus = sdbusplus::bus::new_default();
Alpana Kumaria6181e22022-05-12 05:01:53 -0500440 auto property1 = bus.new_method_call(
alpana075cb3b1f2021-12-16 11:19:36 -0600441 INVENTORY_MANAGER_SERVICE,
442 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
443 "org.freedesktop.DBus.Properties", "Get");
Alpana Kumaria6181e22022-05-12 05:01:53 -0500444 property1.append("com.ibm.ipzvpd.VINI");
445 property1.append("HW");
446 auto result1 = bus.call(property1);
447 inventory::Value hwVal;
448 result1.read(hwVal);
alpana075cb3b1f2021-12-16 11:19:36 -0600449
Alpana Kumaria6181e22022-05-12 05:01:53 -0500450 // SystemType
451 auto property2 = bus.new_method_call(
452 INVENTORY_MANAGER_SERVICE,
453 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
454 "org.freedesktop.DBus.Properties", "Get");
455 property2.append("com.ibm.ipzvpd.VSBP");
456 property2.append("IM");
457 auto result2 = bus.call(property2);
458 inventory::Value imVal;
459 result2.read(imVal);
460
461 auto pVal1 = get_if<Binary>(&hwVal);
462 auto pVal2 = get_if<Binary>(&imVal);
463
464 if (pVal1 && pVal2)
alpana075cb3b1f2021-12-16 11:19:36 -0600465 {
Alpana Kumaria6181e22022-05-12 05:01:53 -0500466 auto hwVersion = *pVal1;
467 auto systemType = *pVal2;
468
469 // IM kw for Everest
470 Binary everestSystem{80, 00, 48, 00};
471
472 if (systemType == everestSystem)
473 {
474 if (hwVersion[1] < 21)
475 {
476 isPASS1 = true;
477 }
478 }
479 else if (hwVersion[1] < 2)
480 {
alpana075cb3b1f2021-12-16 11:19:36 -0600481 isPASS1 = true;
Alpana Kumaria6181e22022-05-12 05:01:53 -0500482 }
alpana075cb3b1f2021-12-16 11:19:36 -0600483 }
484 }
485
486 return (isThisPCIeDev && isPASS1);
487}
488
Alpana Kumari735dee92022-03-25 01:24:40 -0500489/** Performs any pre-action needed to get the FRU setup for collection.
Alpana Kumari2f793042020-08-18 05:51:03 -0500490 *
491 * @param[in] json - json object
492 * @param[in] file - eeprom file path
493 */
494static void preAction(const nlohmann::json& json, const string& file)
495{
Alpana Kumari735dee92022-03-25 01:24:40 -0500496 if ((json["frus"][file].at(0)).find("preAction") ==
Alpana Kumari2f793042020-08-18 05:51:03 -0500497 json["frus"][file].at(0).end())
498 {
Alpana Kumari735dee92022-03-25 01:24:40 -0500499 return;
Alpana Kumari2f793042020-08-18 05:51:03 -0500500 }
501
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500502 try
Alpana Kumari2f793042020-08-18 05:51:03 -0500503 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500504 if (executePreAction(json, file))
Alpana Kumari2f793042020-08-18 05:51:03 -0500505 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500506 if (json["frus"][file].at(0).find("devAddress") !=
507 json["frus"][file].at(0).end())
Alpana Kumari40d1c192022-03-09 21:16:02 -0600508 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500509 // Now bind the device
510 string bind = json["frus"][file].at(0).value("devAddress", "");
jinuthomasd640f692023-03-28 04:13:23 -0500511 cout << "Binding device " << bind << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500512 string bindCmd = string("echo \"") + bind +
513 string("\" > /sys/bus/i2c/drivers/at24/bind");
jinuthomasd640f692023-03-28 04:13:23 -0500514 cout << bindCmd << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500515 executeCmd(bindCmd);
516
517 // Check if device showed up (test for file)
518 if (!fs::exists(file))
519 {
520 cerr << "EEPROM " << file
jinuthomasd640f692023-03-28 04:13:23 -0500521 << " does not exist. Take failure action" << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500522 // If not, then take failure postAction
523 executePostFailAction(json, file);
524 }
525 }
526 else
527 {
528 // missing required informations
529 cerr << "VPD inventory JSON missing basic informations of "
530 "preAction "
531 "for this FRU : ["
jinuthomasd640f692023-03-28 04:13:23 -0500532 << file << "]. Executing executePostFailAction."
533 << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500534
535 // Take failure postAction
Alpana Kumari40d1c192022-03-09 21:16:02 -0600536 executePostFailAction(json, file);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500537 return;
Alpana Kumari40d1c192022-03-09 21:16:02 -0600538 }
539 }
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530540 else
541 {
542 // If the FRU is not there, clear the VINI/CCIN data.
543 // Enity manager probes for this keyword to look for this
544 // FRU, now if the data is persistent on BMC and FRU is
545 // removed this can lead to ambiguity. Hence clearing this
546 // Keyword if FRU is absent.
547 const auto& invPath =
548 json["frus"][file].at(0).value("inventoryPath", "");
549
550 if (!invPath.empty())
551 {
552 inventory::ObjectMap pimObjMap{
553 {invPath, {{"com.ibm.ipzvpd.VINI", {{"CC", Binary{}}}}}}};
554
555 common::utility::callPIM(move(pimObjMap));
556 }
557 else
558 {
559 throw std::runtime_error("Path empty in Json");
560 }
561 }
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500562 }
563 catch (const GpioException& e)
564 {
565 PelAdditionalData additionalData{};
566 additionalData.emplace("DESCRIPTION", e.what());
567 createPEL(additionalData, PelSeverity::WARNING, errIntfForGpioError,
568 nullptr);
Alpana Kumari2f793042020-08-18 05:51:03 -0500569 }
Alpana Kumari2f793042020-08-18 05:51:03 -0500570}
571
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530572/**
Santosh Puranikf3e69682022-03-31 17:52:38 +0530573 * @brief Fills the Decorator.AssetTag property into the interfaces map
574 *
575 * This function should only be called in cases where we did not find a JSON
576 * symlink. A missing symlink in /var/lib will be considered as a factory reset
577 * and this function will be used to default the AssetTag property.
578 *
579 * @param interfaces A possibly pre-populated map of inetrfaces to properties.
580 * @param vpdMap A VPD map of the system VPD data.
581 */
582static void fillAssetTag(inventory::InterfaceMap& interfaces,
583 const Parsed& vpdMap)
584{
585 // Read the system serial number and MTM
586 // Default asset tag is Server-MTM-System Serial
587 inventory::Interface assetIntf{
588 "xyz.openbmc_project.Inventory.Decorator.AssetTag"};
589 inventory::PropertyMap assetTagProps;
590 std::string defaultAssetTag =
591 std::string{"Server-"} + getKwVal(vpdMap, "VSYS", "TM") +
592 std::string{"-"} + getKwVal(vpdMap, "VSYS", "SE");
593 assetTagProps.emplace("AssetTag", defaultAssetTag);
594 insertOrMerge(interfaces, assetIntf, std::move(assetTagProps));
595}
596
597/**
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530598 * @brief Set certain one time properties in the inventory
599 * Use this function to insert the Functional and Enabled properties into the
600 * inventory map. This function first checks if the object in question already
601 * has these properties hosted on D-Bus, if the property is already there, it is
602 * not modified, hence the name "one time". If the property is not already
603 * present, it will be added to the map with a suitable default value (true for
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530604 * Functional and Enabled)
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530605 *
606 * @param[in] object - The inventory D-Bus obejct without the inventory prefix.
607 * @param[inout] interfaces - Reference to a map of inventory interfaces to
608 * which the properties will be attached.
609 */
610static void setOneTimeProperties(const std::string& object,
611 inventory::InterfaceMap& interfaces)
612{
613 auto bus = sdbusplus::bus::new_default();
614 auto objectPath = INVENTORY_PATH + object;
615 auto prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager",
616 objectPath.c_str(),
617 "org.freedesktop.DBus.Properties", "Get");
618 prop.append("xyz.openbmc_project.State.Decorator.OperationalStatus");
619 prop.append("Functional");
620 try
621 {
622 auto result = bus.call(prop);
623 }
624 catch (const sdbusplus::exception::SdBusError& e)
625 {
626 // Treat as property unavailable
627 inventory::PropertyMap prop;
628 prop.emplace("Functional", true);
629 interfaces.emplace(
630 "xyz.openbmc_project.State.Decorator.OperationalStatus",
631 move(prop));
632 }
633 prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager",
634 objectPath.c_str(),
635 "org.freedesktop.DBus.Properties", "Get");
636 prop.append("xyz.openbmc_project.Object.Enable");
637 prop.append("Enabled");
638 try
639 {
640 auto result = bus.call(prop);
641 }
642 catch (const sdbusplus::exception::SdBusError& e)
643 {
644 // Treat as property unavailable
645 inventory::PropertyMap prop;
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530646 prop.emplace("Enabled", true);
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530647 interfaces.emplace("xyz.openbmc_project.Object.Enable", move(prop));
648 }
649}
650
651/**
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530652 * @brief Prime the Inventory
653 * Prime the inventory by populating only the location code,
654 * type interface and the inventory object for the frus
655 * which are not system vpd fru.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530656 *
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530657 * @param[in] jsObject - Reference to vpd inventory json object
658 * @param[in] vpdMap - Reference to the parsed vpd map
659 *
660 * @returns Map of items in extraInterface.
661 */
662template <typename T>
663inventory::ObjectMap primeInventory(const nlohmann::json& jsObject,
664 const T& vpdMap)
665{
666 inventory::ObjectMap objects;
667
668 for (auto& itemFRUS : jsObject["frus"].items())
669 {
670 for (auto& itemEEPROM : itemFRUS.value())
671 {
Alpana Kumari2e6c6f72020-12-03 00:10:03 -0600672 // Take pre actions if needed
673 if (itemEEPROM.find("preAction") != itemEEPROM.end())
674 {
675 preAction(jsObject, itemFRUS.key());
676 }
677
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530678 inventory::InterfaceMap interfaces;
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530679 inventory::Object object(itemEEPROM.at("inventoryPath"));
680
Santosh Puranik50f60bf2021-05-26 17:55:06 +0530681 if ((itemFRUS.key() != systemVpdFilePath) &&
682 !itemEEPROM.value("noprime", false))
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530683 {
Alpana Kumaricfd7a752021-02-07 23:23:01 -0600684 inventory::PropertyMap presProp;
Priyanga Ramasamye358acb2022-03-21 14:21:50 -0500685
686 // Do not populate Present property for frus whose
Priyanga Ramasamyaca61372023-01-24 08:02:28 -0600687 // synthesized=true. synthesized=true says the fru VPD is
688 // synthesized and owned by a separate component.
689 // In some cases, the FRU has its own VPD, but still a separate
690 // application handles the FRU's presence. So VPD parser skips
691 // populating Present property by checking the JSON flag,
692 // "handlePresence".
Priyanga Ramasamye358acb2022-03-21 14:21:50 -0500693 if (!itemEEPROM.value("synthesized", false))
694 {
Priyanga Ramasamyaca61372023-01-24 08:02:28 -0600695 if (itemEEPROM.value("handlePresence", true))
696 {
697 presProp.emplace("Present", false);
698 interfaces.emplace("xyz.openbmc_project.Inventory.Item",
699 presProp);
700 }
Priyanga Ramasamye358acb2022-03-21 14:21:50 -0500701 }
Priyanga Ramasamyaca61372023-01-24 08:02:28 -0600702
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530703 setOneTimeProperties(object, interfaces);
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530704 if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end())
705 {
706 for (const auto& eI : itemEEPROM["extraInterfaces"].items())
707 {
708 inventory::PropertyMap props;
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000709 if (eI.key() == IBM_LOCATION_CODE_INF)
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530710 {
711 if constexpr (std::is_same<T, Parsed>::value)
712 {
713 for (auto& lC : eI.value().items())
714 {
715 auto propVal = expandLocationCode(
716 lC.value().get<string>(), vpdMap, true);
717
718 props.emplace(move(lC.key()),
719 move(propVal));
Santosh Puranikb0f37492021-06-21 09:42:47 +0530720 interfaces.emplace(XYZ_LOCATION_CODE_INF,
721 props);
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530722 interfaces.emplace(move(eI.key()),
723 move(props));
724 }
725 }
726 }
727 else if (eI.key().find("Inventory.Item.") !=
728 string::npos)
729 {
730 interfaces.emplace(move(eI.key()), move(props));
731 }
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530732 else if (eI.key() ==
733 "xyz.openbmc_project.Inventory.Item")
734 {
735 for (auto& val : eI.value().items())
736 {
737 if (val.key() == "PrettyName")
738 {
739 presProp.emplace(val.key(),
740 val.value().get<string>());
741 }
742 }
743 // Use insert_or_assign here as we may already have
744 // inserted the present property only earlier in
745 // this function under this same interface.
746 interfaces.insert_or_assign(eI.key(),
747 move(presProp));
748 }
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530749 }
750 }
751 objects.emplace(move(object), move(interfaces));
752 }
753 }
754 }
755 return objects;
756}
757
Alpana Kumari65b83602020-09-01 00:24:56 -0500758/**
759 * @brief This API executes command to set environment variable
760 * And then reboot the system
761 * @param[in] key -env key to set new value
762 * @param[in] value -value to set.
763 */
764void setEnvAndReboot(const string& key, const string& value)
765{
766 // set env and reboot and break.
767 executeCmd("/sbin/fw_setenv", key, value);
Andrew Geissler280197e2020-12-08 20:51:49 -0600768 log<level::INFO>("Rebooting BMC to pick up new device tree");
Alpana Kumari65b83602020-09-01 00:24:56 -0500769 // make dbus call to reboot
770 auto bus = sdbusplus::bus::new_default_system();
771 auto method = bus.new_method_call(
772 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
773 "org.freedesktop.systemd1.Manager", "Reboot");
774 bus.call_noreply(method);
775}
776
777/*
778 * @brief This API checks for env var fitconfig.
779 * If not initialised OR updated as per the current system type,
780 * update this env var and reboot the system.
781 *
782 * @param[in] systemType IM kwd in vpd tells about which system type it is.
783 * */
784void setDevTreeEnv(const string& systemType)
785{
Alpana Kumari37e72702021-11-18 11:18:04 -0600786 // Init with default dtb
787 string newDeviceTree = "conf-aspeed-bmc-ibm-rainier-p1.dtb";
Santosh Puranike5f177a2022-01-24 20:14:46 +0530788 static const deviceTreeMap deviceTreeSystemTypeMap = {
789 {RAINIER_2U, "conf-aspeed-bmc-ibm-rainier-p1.dtb"},
790 {RAINIER_2U_V2, "conf-aspeed-bmc-ibm-rainier.dtb"},
791 {RAINIER_4U, "conf-aspeed-bmc-ibm-rainier-4u-p1.dtb"},
792 {RAINIER_4U_V2, "conf-aspeed-bmc-ibm-rainier-4u.dtb"},
793 {RAINIER_1S4U, "conf-aspeed-bmc-ibm-rainier-1s4u.dtb"},
Alpana Kumari1b026112022-03-02 23:41:38 -0600794 {EVEREST, "conf-aspeed-bmc-ibm-everest.dtb"},
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530795 {EVEREST_V2, "conf-aspeed-bmc-ibm-everest.dtb"},
796 {BONNELL, "conf-aspeed-bmc-ibm-bonnell.dtb"}};
Alpana Kumari65b83602020-09-01 00:24:56 -0500797
798 if (deviceTreeSystemTypeMap.find(systemType) !=
799 deviceTreeSystemTypeMap.end())
800 {
801 newDeviceTree = deviceTreeSystemTypeMap.at(systemType);
802 }
Alpana Kumari37e72702021-11-18 11:18:04 -0600803 else
804 {
805 // System type not supported
Alpana Kumariab1e22c2021-11-24 11:03:38 -0600806 string err = "This System type not found/supported in dtb table " +
807 systemType +
808 ".Please check the HW and IM keywords in the system "
809 "VPD.Breaking...";
810
811 // map to hold additional data in case of logging pel
812 PelAdditionalData additionalData{};
813 additionalData.emplace("DESCRIPTION", err);
814 createPEL(additionalData, PelSeverity::WARNING,
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500815 errIntfForInvalidSystemType, nullptr);
Alpana Kumariab1e22c2021-11-24 11:03:38 -0600816 exit(-1);
Alpana Kumari37e72702021-11-18 11:18:04 -0600817 }
Alpana Kumari65b83602020-09-01 00:24:56 -0500818
819 string readVarValue;
820 bool envVarFound = false;
821
822 vector<string> output = executeCmd("/sbin/fw_printenv");
823 for (const auto& entry : output)
824 {
825 size_t pos = entry.find("=");
826 string key = entry.substr(0, pos);
827 if (key != "fitconfig")
828 {
829 continue;
830 }
831
832 envVarFound = true;
833 if (pos + 1 < entry.size())
834 {
835 readVarValue = entry.substr(pos + 1);
836 if (readVarValue.find(newDeviceTree) != string::npos)
837 {
838 // fitconfig is Updated. No action needed
839 break;
840 }
841 }
842 // set env and reboot and break.
843 setEnvAndReboot(key, newDeviceTree);
844 exit(0);
845 }
846
847 // check If env var Not found
848 if (!envVarFound)
849 {
850 setEnvAndReboot("fitconfig", newDeviceTree);
851 }
852}
853
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530854/**
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500855 * @brief API to check if we need to restore system VPD
856 * This functionality is only applicable for IPZ VPD data.
857 * @param[in] vpdMap - IPZ vpd map
858 * @param[in] objectPath - Object path for the FRU
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500859 */
Sunny Srivastava3c244142022-01-11 08:47:04 -0600860void restoreSystemVPD(Parsed& vpdMap, const string& objectPath)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500861{
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500862 for (const auto& systemRecKwdPair : svpdKwdMap)
863 {
864 auto it = vpdMap.find(systemRecKwdPair.first);
865
866 // check if record is found in map we got by parser
867 if (it != vpdMap.end())
868 {
869 const auto& kwdListForRecord = systemRecKwdPair.second;
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600870 for (const auto& keywordInfo : kwdListForRecord)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500871 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600872 const auto keyword = get<0>(keywordInfo);
873
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500874 DbusPropertyMap& kwdValMap = it->second;
875 auto iterator = kwdValMap.find(keyword);
876
877 if (iterator != kwdValMap.end())
878 {
879 string& kwdValue = iterator->second;
880
881 // check bus data
882 const string& recordName = systemRecKwdPair.first;
883 const string& busValue = readBusProperty(
884 objectPath, ipzVpdInf + recordName, keyword);
885
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600886 const auto& defaultValue = get<1>(keywordInfo);
887 Binary busDataInBinary(busValue.begin(), busValue.end());
888 Binary kwdDataInBinary(kwdValue.begin(), kwdValue.end());
Sunny Srivastavaa559c2d2022-05-02 11:56:45 -0500889
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600890 if (busDataInBinary != defaultValue)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500891 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600892 if (kwdDataInBinary != defaultValue)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500893 {
894 // both the data are present, check for mismatch
895 if (busValue != kwdValue)
896 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600897 string errMsg = "Mismatch found between backup "
898 "and primary VPD for record: ";
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500899 errMsg += (*it).first;
900 errMsg += " and keyword: ";
901 errMsg += keyword;
902
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530903 std::ostringstream busStream;
904 for (uint16_t byte : busValue)
905 {
906 busStream << std::setfill('0')
907 << std::setw(2) << std::hex
908 << "0x" << byte << " ";
909 }
910
911 std::ostringstream vpdStream;
912 for (uint16_t byte : kwdValue)
913 {
914 vpdStream << std::setfill('0')
915 << std::setw(2) << std::hex
916 << "0x" << byte << " ";
917 }
918
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500919 // data mismatch
920 PelAdditionalData additionalData;
921 additionalData.emplace("CALLOUT_INVENTORY_PATH",
Priyanga Ramasamyf6123682022-12-02 07:29:07 -0600922 INVENTORY_PATH +
923 objectPath);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500924
925 additionalData.emplace("DESCRIPTION", errMsg);
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530926 additionalData.emplace(
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600927 "Value read from Backup: ",
928 busStream.str());
929 additionalData.emplace(
930 "Value read from Primary: ",
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530931 vpdStream.str());
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500932
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500933 createPEL(additionalData, PelSeverity::WARNING,
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600934 errIntfForVPDMismatch, nullptr);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500935 }
936 }
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500937
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600938 // If backup data is not default, then irrespective of
939 // primary data(default or other than backup), copy the
940 // backup data to vpd map as we don't need to change the
941 // backup data in either case in the process of
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530942 // restoring system vpd.
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530943 kwdValue = busValue;
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500944 }
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600945 else if (kwdDataInBinary == defaultValue &&
946 get<2>(keywordInfo)) // Check isPELRequired is true
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500947 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600948 string errMsg = "Found default value on both backup "
949 "and primary VPD for record: ";
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500950 errMsg += (*it).first;
951 errMsg += " and keyword: ";
952 errMsg += keyword;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600953 errMsg += ". SSR need to update primary VPD.";
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500954
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600955 // mfg default on both backup and primary, log PEL
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500956 PelAdditionalData additionalData;
957 additionalData.emplace("CALLOUT_INVENTORY_PATH",
Priyanga Ramasamyf6123682022-12-02 07:29:07 -0600958 INVENTORY_PATH + objectPath);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500959
960 additionalData.emplace("DESCRIPTION", errMsg);
961
962 // log PEL TODO: Block IPL
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500963 createPEL(additionalData, PelSeverity::ERROR,
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600964 errIntfForVPDDefault, nullptr);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500965 continue;
966 }
967 }
968 }
969 }
970 }
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500971}
972
973/**
alpana077ce68722021-07-25 13:23:59 -0500974 * @brief This checks for is this FRU a processor
975 * And if yes, then checks for is this primary
976 *
977 * @param[in] js- vpd json to get the information about this FRU
978 * @param[in] filePath- FRU vpd
979 *
980 * @return true/false
981 */
982bool isThisPrimaryProcessor(nlohmann::json& js, const string& filePath)
983{
984 bool isProcessor = false;
985 bool isPrimary = false;
986
987 for (const auto& item : js["frus"][filePath])
988 {
989 if (item.find("extraInterfaces") != item.end())
990 {
991 for (const auto& eI : item["extraInterfaces"].items())
992 {
993 if (eI.key().find("Inventory.Item.Cpu") != string::npos)
994 {
995 isProcessor = true;
996 }
997 }
998 }
999
1000 if (isProcessor)
1001 {
1002 string cpuType = item.value("cpuType", "");
1003 if (cpuType == "primary")
1004 {
1005 isPrimary = true;
1006 }
1007 }
1008 }
1009
1010 return (isProcessor && isPrimary);
1011}
1012
1013/**
1014 * @brief This finds DIMM vpd in vpd json and enables them by binding the device
1015 * driver
1016 * @param[in] js- vpd json to iterate through and take action if it is DIMM
1017 */
1018void doEnableAllDimms(nlohmann::json& js)
1019{
1020 // iterate over each fru
1021 for (const auto& eachFru : js["frus"].items())
1022 {
1023 // skip the driver binding if eeprom already exists
1024 if (fs::exists(eachFru.key()))
1025 {
1026 continue;
1027 }
1028
1029 for (const auto& eachInventory : eachFru.value())
1030 {
1031 if (eachInventory.find("extraInterfaces") != eachInventory.end())
1032 {
1033 for (const auto& eI : eachInventory["extraInterfaces"].items())
1034 {
1035 if (eI.key().find("Inventory.Item.Dimm") != string::npos)
1036 {
1037 string dimmVpd = eachFru.key();
1038 // fetch it from
1039 // "/sys/bus/i2c/drivers/at24/414-0050/eeprom"
1040
1041 regex matchPatern("([0-9]+-[0-9]{4})");
1042 smatch matchFound;
1043 if (regex_search(dimmVpd, matchFound, matchPatern))
1044 {
1045 vector<string> i2cReg;
1046 boost::split(i2cReg, matchFound.str(0),
1047 boost::is_any_of("-"));
1048
1049 // remove 0s from begining
1050 const regex pattern("^0+(?!$)");
1051 for (auto& i : i2cReg)
1052 {
1053 i = regex_replace(i, pattern, "");
1054 }
1055
1056 if (i2cReg.size() == 2)
1057 {
1058 // echo 24c32 0x50 >
1059 // /sys/bus/i2c/devices/i2c-16/new_device
1060 string cmnd = "echo 24c32 0x" + i2cReg[1] +
1061 " > /sys/bus/i2c/devices/i2c-" +
1062 i2cReg[0] + "/new_device";
1063
1064 executeCmd(cmnd);
1065 }
1066 }
1067 }
1068 }
1069 }
1070 }
1071 }
1072}
1073
1074/**
Priyanga Ramasamy6abdeb62022-01-09 23:15:11 -06001075 * @brief Check if the given CPU is an IO only chip.
1076 * The CPU is termed as IO, whose all of the cores are bad and can never be
1077 * used. Those CPU chips can be used for IO purpose like connecting PCIe devices
1078 * etc., The CPU whose every cores are bad, can be identified from the CP00
1079 * record's PG keyword, only if all of the 8 EQs' value equals 0xE7F9FF. (1EQ
1080 * has 4 cores grouped together by sharing its cache memory.)
1081 * @param [in] pgKeyword - PG Keyword of CPU.
1082 * @return true if the given cpu is an IO, false otherwise.
1083 */
1084static bool isCPUIOGoodOnly(const string& pgKeyword)
1085{
1086 const unsigned char io[] = {0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9,
1087 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7,
1088 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF};
1089 // EQ0 index (in PG keyword) starts at 97 (with offset starting from 0).
1090 // Each EQ carries 3 bytes of data. Totally there are 8 EQs. If all EQs'
1091 // value equals 0xE7F9FF, then the cpu has no good cores and its treated as
1092 // IO.
1093 if (memcmp(io, pgKeyword.data() + 97, 24) == 0)
1094 {
1095 return true;
1096 }
1097
1098 // The CPU is not an IO
1099 return false;
1100}
1101
1102/**
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301103 * @brief Populate Dbus.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301104 * This method invokes all the populateInterface functions
1105 * and notifies PIM about dbus object.
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301106 * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the
1107 * input.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301108 * @param[in] js - Inventory json object
1109 * @param[in] filePath - Path of the vpd file
1110 * @param[in] preIntrStr - Interface string
1111 */
1112template <typename T>
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001113static void populateDbus(T& vpdMap, nlohmann::json& js, const string& filePath)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301114{
1115 inventory::InterfaceMap interfaces;
1116 inventory::ObjectMap objects;
1117 inventory::PropertyMap prop;
Shantappa Teekappanavar6aa54502021-12-09 12:59:56 -06001118 string ccinFromVpd;
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301119
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301120 bool isSystemVpd = (filePath == systemVpdFilePath);
1121 if constexpr (is_same<T, Parsed>::value)
1122 {
Shantappa Teekappanavar6aa54502021-12-09 12:59:56 -06001123 ccinFromVpd = getKwVal(vpdMap, "VINI", "CC");
1124 transform(ccinFromVpd.begin(), ccinFromVpd.end(), ccinFromVpd.begin(),
1125 ::toupper);
1126
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301127 if (isSystemVpd)
1128 {
1129 std::vector<std::string> interfaces = {motherBoardInterface};
1130 // call mapper to check for object path creation
1131 MapperResponse subTree =
1132 getObjectSubtreeForInterfaces(pimPath, 0, interfaces);
1133 string mboardPath =
1134 js["frus"][filePath].at(0).value("inventoryPath", "");
1135
1136 // Attempt system VPD restore if we have a motherboard
1137 // object in the inventory.
1138 if ((subTree.size() != 0) &&
1139 (subTree.find(pimPath + mboardPath) != subTree.end()))
1140 {
Sunny Srivastava3c244142022-01-11 08:47:04 -06001141 restoreSystemVPD(vpdMap, mboardPath);
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301142 }
1143 else
1144 {
1145 log<level::ERR>("No object path found");
1146 }
1147 }
alpana077ce68722021-07-25 13:23:59 -05001148 else
1149 {
1150 // check if it is processor vpd.
1151 auto isPrimaryCpu = isThisPrimaryProcessor(js, filePath);
1152
1153 if (isPrimaryCpu)
1154 {
1155 auto ddVersion = getKwVal(vpdMap, "CRP0", "DD");
1156
1157 auto chipVersion = atoi(ddVersion.substr(1, 2).c_str());
1158
1159 if (chipVersion >= 2)
1160 {
1161 doEnableAllDimms(js);
Santosh Puranik253fbe92022-10-06 22:38:09 +05301162 // Sleep for a few seconds to let the DIMM parses start
1163 using namespace std::chrono_literals;
1164 std::this_thread::sleep_for(5s);
alpana077ce68722021-07-25 13:23:59 -05001165 }
1166 }
1167 }
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301168 }
1169
Santosh Puranikf3e69682022-03-31 17:52:38 +05301170 auto processFactoryReset = false;
1171
Priyanga Ramasamy32c687f2022-01-04 23:14:03 -06001172 if (isSystemVpd)
1173 {
1174 string systemJsonName{};
1175 if constexpr (is_same<T, Parsed>::value)
1176 {
1177 // pick the right system json
1178 systemJsonName = getSystemsJson(vpdMap);
1179 }
1180
1181 fs::path target = systemJsonName;
1182 fs::path link = INVENTORY_JSON_SYM_LINK;
1183
Santosh Puranikf3e69682022-03-31 17:52:38 +05301184 // If the symlink does not exist, we treat that as a factory reset
1185 processFactoryReset = !fs::exists(INVENTORY_JSON_SYM_LINK);
1186
Priyanga Ramasamy32c687f2022-01-04 23:14:03 -06001187 // Create the directory for hosting the symlink
1188 fs::create_directories(VPD_FILES_PATH);
1189 // unlink the symlink previously created (if any)
1190 remove(INVENTORY_JSON_SYM_LINK);
1191 // create a new symlink based on the system
1192 fs::create_symlink(target, link);
1193
1194 // Reloading the json
1195 ifstream inventoryJson(link);
1196 js = json::parse(inventoryJson);
1197 inventoryJson.close();
1198 }
1199
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301200 for (const auto& item : js["frus"][filePath])
1201 {
1202 const auto& objectPath = item["inventoryPath"];
1203 sdbusplus::message::object_path object(objectPath);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001204
Shantappa Teekappanavar6aa54502021-12-09 12:59:56 -06001205 vector<string> ccinList;
1206 if (item.find("ccin") != item.end())
1207 {
1208 for (const auto& cc : item["ccin"])
1209 {
1210 string ccin = cc;
1211 transform(ccin.begin(), ccin.end(), ccin.begin(), ::toupper);
1212 ccinList.push_back(ccin);
1213 }
1214 }
1215
1216 if (!ccinFromVpd.empty() && !ccinList.empty() &&
1217 (find(ccinList.begin(), ccinList.end(), ccinFromVpd) ==
1218 ccinList.end()))
1219 {
1220 continue;
1221 }
1222
Priyanga Ramasamye3fed702022-01-11 01:05:32 -06001223 if ((isSystemVpd) || (item.value("noprime", false)))
Santosh Puranikd3a379a2021-08-23 19:12:59 +05301224 {
Priyanga Ramasamye3fed702022-01-11 01:05:32 -06001225
1226 // Populate one time properties for the system VPD and its sub-frus
1227 // and for other non-primeable frus.
Santosh Puranikd3a379a2021-08-23 19:12:59 +05301228 // For the remaining FRUs, this will get handled as a part of
1229 // priming the inventory.
1230 setOneTimeProperties(objectPath, interfaces);
1231 }
1232
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301233 // Populate the VPD keywords and the common interfaces only if we
1234 // are asked to inherit that data from the VPD, else only add the
1235 // extraInterfaces.
1236 if (item.value("inherit", true))
1237 {
Alpana Kumari58e22142020-05-05 00:22:12 -05001238 if constexpr (is_same<T, Parsed>::value)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301239 {
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301240 // Each record in the VPD becomes an interface and all
1241 // keyword within the record are properties under that
1242 // interface.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301243 for (const auto& record : vpdMap)
1244 {
1245 populateFruSpecificInterfaces(
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05001246 record.second, ipzVpdInf + record.first, interfaces);
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301247 }
1248 }
Alpana Kumari58e22142020-05-05 00:22:12 -05001249 else if constexpr (is_same<T, KeywordVpdMap>::value)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301250 {
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05001251 populateFruSpecificInterfaces(vpdMap, kwdVpdInf, interfaces);
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301252 }
Santosh Puranik88edeb62020-03-02 12:00:09 +05301253 if (js.find("commonInterfaces") != js.end())
1254 {
1255 populateInterfaces(js["commonInterfaces"], interfaces, vpdMap,
1256 isSystemVpd);
1257 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301258 }
Santosh Puranik0859eb62020-03-16 02:56:29 -05001259 else
1260 {
1261 // Check if we have been asked to inherit specific record(s)
Alpana Kumari58e22142020-05-05 00:22:12 -05001262 if constexpr (is_same<T, Parsed>::value)
Santosh Puranik0859eb62020-03-16 02:56:29 -05001263 {
1264 if (item.find("copyRecords") != item.end())
1265 {
1266 for (const auto& record : item["copyRecords"])
1267 {
1268 const string& recordName = record;
1269 if (vpdMap.find(recordName) != vpdMap.end())
1270 {
1271 populateFruSpecificInterfaces(
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05001272 vpdMap.at(recordName), ipzVpdInf + recordName,
Santosh Puranik0859eb62020-03-16 02:56:29 -05001273 interfaces);
1274 }
1275 }
1276 }
1277 }
1278 }
Santosh Puranik32c46502022-02-10 08:55:07 +05301279 // Populate interfaces and properties that are common to every FRU
1280 // and additional interface that might be defined on a per-FRU
1281 // basis.
1282 if (item.find("extraInterfaces") != item.end())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301283 {
Santosh Puranik32c46502022-02-10 08:55:07 +05301284 populateInterfaces(item["extraInterfaces"], interfaces, vpdMap,
1285 isSystemVpd);
Priyanga Ramasamy6abdeb62022-01-09 23:15:11 -06001286 if constexpr (is_same<T, Parsed>::value)
1287 {
1288 if (item["extraInterfaces"].find(
1289 "xyz.openbmc_project.Inventory.Item.Cpu") !=
1290 item["extraInterfaces"].end())
1291 {
1292 if (isCPUIOGoodOnly(getKwVal(vpdMap, "CP00", "PG")))
1293 {
Priyanga Ramasamy2c607a92022-04-08 00:30:17 -05001294 interfaces[invItemIntf]["PrettyName"] = "IO Module";
Priyanga Ramasamy6abdeb62022-01-09 23:15:11 -06001295 }
1296 }
1297 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301298 }
Priyanga Ramasamye358acb2022-03-21 14:21:50 -05001299
1300 // embedded property(true or false) says whether the subfru is embedded
1301 // into the parent fru (or) not. VPD sets Present property only for
1302 // embedded frus. If the subfru is not an embedded FRU, the subfru may
1303 // or may not be physically present. Those non embedded frus will always
1304 // have Present=false irrespective of its physical presence or absence.
1305 // Eg: nvme drive in nvme slot is not an embedded FRU. So don't set
1306 // Present to true for such sub frus.
1307 // Eg: ethernet port is embedded into bmc card. So set Present to true
1308 // for such sub frus. Also donot populate present property for embedded
1309 // subfru which is synthesized. Currently there is no subfru which are
1310 // both embedded and synthesized. But still the case is handled here.
1311 if ((item.value("embedded", true)) &&
1312 (!item.value("synthesized", false)))
1313 {
Priyanga Ramasamyaca61372023-01-24 08:02:28 -06001314 // Check if its required to handle presence for this FRU.
1315 if (item.value("handlePresence", true))
1316 {
1317 inventory::PropertyMap presProp;
1318 presProp.emplace("Present", true);
1319 insertOrMerge(interfaces, invItemIntf, move(presProp));
1320 }
Priyanga Ramasamye358acb2022-03-21 14:21:50 -05001321 }
Priyanga Ramasamyaa8a8932022-01-27 09:12:41 -06001322
Santosh Puranikf3e69682022-03-31 17:52:38 +05301323 if constexpr (is_same<T, Parsed>::value)
1324 {
1325 // Restore asset tag, if needed
1326 if (processFactoryReset && objectPath == "/system")
1327 {
1328 fillAssetTag(interfaces, vpdMap);
1329 }
1330 }
1331
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301332 objects.emplace(move(object), move(interfaces));
1333 }
1334
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301335 if (isSystemVpd)
1336 {
1337 inventory::ObjectMap primeObject = primeInventory(js, vpdMap);
1338 objects.insert(primeObject.begin(), primeObject.end());
Alpana Kumari65b83602020-09-01 00:24:56 -05001339
Alpana Kumarif05effd2021-04-07 07:32:53 -05001340 // set the U-boot environment variable for device-tree
1341 if constexpr (is_same<T, Parsed>::value)
1342 {
Santosh Puranike5f177a2022-01-24 20:14:46 +05301343 setDevTreeEnv(fs::path(getSystemsJson(vpdMap)).filename());
Alpana Kumarif05effd2021-04-07 07:32:53 -05001344 }
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301345 }
1346
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301347 // Notify PIM
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05001348 common::utility::callPIM(move(objects));
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301349}
1350
1351int main(int argc, char** argv)
1352{
1353 int rc = 0;
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001354 json js{};
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -06001355 Binary vpdVector{};
1356 string file{};
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001357 // map to hold additional data in case of logging pel
1358 PelAdditionalData additionalData{};
1359
1360 // this is needed to hold base fru inventory path in case there is ECC or
1361 // vpd exception while parsing the file
1362 std::string baseFruInventoryPath = {};
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301363
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001364 // severity for PEL
1365 PelSeverity pelSeverity = PelSeverity::WARNING;
1366
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301367 try
1368 {
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301369 App app{"ibm-read-vpd - App to read IPZ format VPD, parse it and store "
1370 "in DBUS"};
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301371
1372 app.add_option("-f, --file", file, "File containing VPD (IPZ/KEYWORD)")
Alpana Kumari2f793042020-08-18 05:51:03 -05001373 ->required();
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301374
1375 CLI11_PARSE(app, argc, argv);
1376
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001377 // PEL severity should be ERROR in case of any system VPD failure
1378 if (file == systemVpdFilePath)
1379 {
1380 pelSeverity = PelSeverity::ERROR;
1381 }
1382
Santosh Puranik0246a4d2020-11-04 16:57:39 +05301383 auto jsonToParse = INVENTORY_JSON_DEFAULT;
1384
1385 // If the symlink exists, it means it has been setup for us, switch the
1386 // path
1387 if (fs::exists(INVENTORY_JSON_SYM_LINK))
1388 {
1389 jsonToParse = INVENTORY_JSON_SYM_LINK;
1390 }
1391
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301392 // Make sure that the file path we get is for a supported EEPROM
Santosh Puranik0246a4d2020-11-04 16:57:39 +05301393 ifstream inventoryJson(jsonToParse);
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001394 if (!inventoryJson)
1395 {
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001396 throw(VpdJsonException("Failed to access Json path", jsonToParse));
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001397 }
1398
1399 try
1400 {
1401 js = json::parse(inventoryJson);
1402 }
Patrick Williams8e15b932021-10-06 13:04:22 -05001403 catch (const json::parse_error& ex)
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001404 {
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001405 throw(VpdJsonException("Json parsing failed", jsonToParse));
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001406 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301407
Santosh Puranik12e24ff2021-05-11 19:33:50 +05301408 // Do we have the mandatory "frus" section?
1409 if (js.find("frus") == js.end())
1410 {
1411 throw(VpdJsonException("FRUs section not found in JSON",
1412 jsonToParse));
1413 }
1414
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301415 // Check if it's a udev path - patterned as(/ahb/ahb:apb/ahb:apb:bus@)
1416 if (file.find("/ahb:apb") != string::npos)
1417 {
1418 // Translate udev path to a generic /sys/bus/.. file path.
1419 udevToGenericPath(file);
Santosh Puranik12e24ff2021-05-11 19:33:50 +05301420
1421 if ((js["frus"].find(file) != js["frus"].end()) &&
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301422 (file == systemVpdFilePath))
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301423 {
Santosh Puranik6b2b5372022-06-02 20:49:02 +05301424 // We have already collected system VPD, skip.
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301425 return 0;
1426 }
1427 }
1428
1429 if (file.empty())
1430 {
1431 cerr << "The EEPROM path <" << file << "> is not valid.";
1432 return 0;
1433 }
Santosh Puranik12e24ff2021-05-11 19:33:50 +05301434 if (js["frus"].find(file) == js["frus"].end())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301435 {
Santosh Puranik88edeb62020-03-02 12:00:09 +05301436 return 0;
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301437 }
1438
Alpana Kumari2f793042020-08-18 05:51:03 -05001439 if (!fs::exists(file))
1440 {
1441 cout << "Device path: " << file
jinuthomasd640f692023-03-28 04:13:23 -05001442 << " does not exist. Spurious udev event? Exiting."
1443 << std::endl;
Alpana Kumari2f793042020-08-18 05:51:03 -05001444 return 0;
1445 }
1446
Santosh Puranikdedb5a62022-12-19 23:58:32 +05301447 // In case of system VPD it will already be filled, Don't have to
1448 // overwrite that.
1449 if (baseFruInventoryPath.empty())
1450 {
1451 baseFruInventoryPath = js["frus"][file][0]["inventoryPath"];
1452 }
1453
Santosh Puranik85893752020-11-10 21:31:43 +05301454 // Check if we can read the VPD file based on the power state
Santosh Puranik27a5e952021-10-07 22:08:01 -05001455 // We skip reading VPD when the power is ON in two scenarios:
Santosh Puranik31d50fa2022-04-04 12:04:37 +05301456 // 1) The eeprom we are trying to read is that of the system VPD and the
1457 // JSON symlink is already setup (the symlink's existence tells us we
1458 // are not coming out of a factory reset)
1459 // 2) The JSON tells us that the FRU EEPROM cannot be
1460 // read when we are powered ON.
Santosh Puranik27a5e952021-10-07 22:08:01 -05001461 if (js["frus"][file].at(0).value("powerOffOnly", false) ||
Santosh Puranik31d50fa2022-04-04 12:04:37 +05301462 (file == systemVpdFilePath && fs::exists(INVENTORY_JSON_SYM_LINK)))
Santosh Puranik85893752020-11-10 21:31:43 +05301463 {
1464 if ("xyz.openbmc_project.State.Chassis.PowerState.On" ==
1465 getPowerState())
1466 {
jinuthomasd640f692023-03-28 04:13:23 -05001467 cout << "This VPD cannot be read when power is ON" << std::endl;
Santosh Puranik85893752020-11-10 21:31:43 +05301468 return 0;
1469 }
1470 }
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001471
Santosh Puranike9c57532022-03-15 16:51:51 +05301472 // Check if this VPD should be recollected at all
1473 if (!needsRecollection(js, file))
1474 {
jinuthomasd640f692023-03-28 04:13:23 -05001475 cout << "Skip VPD recollection for: " << file << std::endl;
Santosh Puranike9c57532022-03-15 16:51:51 +05301476 return 0;
1477 }
1478
Alpana Kumari2f793042020-08-18 05:51:03 -05001479 try
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301480 {
girik18bb9852022-11-16 05:48:13 -06001481 uint32_t vpdStartOffset = 0;
1482 for (const auto& item : js["frus"][file])
1483 {
1484 if (item.find("offset") != item.end())
1485 {
1486 vpdStartOffset = item["offset"];
1487 }
1488 }
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -06001489 vpdVector = getVpdDataInVector(js, file);
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -05001490 ParserInterface* parser = ParserFactory::getParser(
girik18bb9852022-11-16 05:48:13 -06001491 vpdVector, (pimPath + baseFruInventoryPath), file,
1492 vpdStartOffset);
Alpana Kumari2f793042020-08-18 05:51:03 -05001493 variant<KeywordVpdMap, Store> parseResult;
1494 parseResult = parser->parse();
SunnySrivastava19849a195542020-09-07 06:04:50 -05001495
Alpana Kumari2f793042020-08-18 05:51:03 -05001496 if (auto pVal = get_if<Store>(&parseResult))
1497 {
1498 populateDbus(pVal->getVpdMap(), js, file);
1499 }
1500 else if (auto pVal = get_if<KeywordVpdMap>(&parseResult))
1501 {
1502 populateDbus(*pVal, js, file);
1503 }
1504
1505 // release the parser object
1506 ParserFactory::freeParser(parser);
1507 }
Patrick Williams8e15b932021-10-06 13:04:22 -05001508 catch (const exception& e)
Alpana Kumari2f793042020-08-18 05:51:03 -05001509 {
Alpana Kumari735dee92022-03-25 01:24:40 -05001510 executePostFailAction(js, file);
PriyangaRamasamya504c3e2020-12-06 12:14:52 -06001511 throw;
Alpana Kumari2f793042020-08-18 05:51:03 -05001512 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301513 }
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001514 catch (const VpdJsonException& ex)
1515 {
1516 additionalData.emplace("JSON_PATH", ex.getJsonPath());
1517 additionalData.emplace("DESCRIPTION", ex.what());
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -05001518 createPEL(additionalData, pelSeverity, errIntfForJsonFailure, nullptr);
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001519
1520 cerr << ex.what() << "\n";
1521 rc = -1;
1522 }
1523 catch (const VpdEccException& ex)
1524 {
1525 additionalData.emplace("DESCRIPTION", "ECC check failed");
1526 additionalData.emplace("CALLOUT_INVENTORY_PATH",
1527 INVENTORY_PATH + baseFruInventoryPath);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -05001528 createPEL(additionalData, pelSeverity, errIntfForEccCheckFail, nullptr);
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -06001529 dumpBadVpd(file, vpdVector);
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001530 cerr << ex.what() << "\n";
1531 rc = -1;
1532 }
1533 catch (const VpdDataException& ex)
1534 {
alpana075cb3b1f2021-12-16 11:19:36 -06001535 if (isThisPcieOnPass1planar(js, file))
1536 {
1537 cout << "Pcie_device [" << file
1538 << "]'s VPD is not valid on PASS1 planar.Ignoring.\n";
1539 rc = 0;
1540 }
Santosh Puranik53b38ed2022-04-10 23:15:22 +05301541 else if (!(isPresent(js, file).value_or(true)))
1542 {
1543 cout << "FRU at: " << file
1544 << " is not detected present. Ignore parser error.\n";
1545 rc = 0;
1546 }
alpana075cb3b1f2021-12-16 11:19:36 -06001547 else
1548 {
1549 string errorMsg =
1550 "VPD file is either empty or invalid. Parser failed for [";
1551 errorMsg += file;
1552 errorMsg += "], with error = " + std::string(ex.what());
1553
1554 additionalData.emplace("DESCRIPTION", errorMsg);
1555 additionalData.emplace("CALLOUT_INVENTORY_PATH",
1556 INVENTORY_PATH + baseFruInventoryPath);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -05001557 createPEL(additionalData, pelSeverity, errIntfForInvalidVPD,
1558 nullptr);
alpana075cb3b1f2021-12-16 11:19:36 -06001559
1560 rc = -1;
1561 }
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001562 }
Patrick Williams8e15b932021-10-06 13:04:22 -05001563 catch (const exception& e)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301564 {
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -06001565 dumpBadVpd(file, vpdVector);
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301566 cerr << e.what() << "\n";
1567 rc = -1;
1568 }
1569
1570 return rc;
Alpana Kumari735dee92022-03-25 01:24:40 -05001571}