blob: 97999829696d615ffde459858339ee76b9e62a4d [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"
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05005#include "editor_impl.hpp"
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05006#include "ibm_vpd_utils.hpp"
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05007#include "ipz_parser.hpp"
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05308#include "keyword_vpd_parser.hpp"
Alpana Kumaria00936f2020-04-14 07:15:46 -05009#include "memory_vpd_parser.hpp"
SunnySrivastava1984e12b1812020-05-26 02:23:11 -050010#include "parser_factory.hpp"
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -050011#include "vpd_exceptions.hpp"
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053012
SunnySrivastava19849094d4f2020-08-05 09:32:29 -050013#include <assert.h>
Alpana Kumari8ea3f6d2020-04-02 00:26:07 -050014#include <ctype.h>
15
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053016#include <CLI/CLI.hpp>
alpana077ce68722021-07-25 13:23:59 -050017#include <boost/algorithm/string.hpp>
Patrick Williamsc78d8872023-05-10 07:50:56 -050018#include <gpiod.hpp>
19#include <phosphor-logging/log.hpp>
20
21#include <algorithm>
Alpana Kumari65b83602020-09-01 00:24:56 -050022#include <cstdarg>
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053023#include <exception>
PriyangaRamasamy83a1d5d2020-04-30 19:15:43 +053024#include <filesystem>
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053025#include <fstream>
26#include <iostream>
27#include <iterator>
alpana077ce68722021-07-25 13:23:59 -050028#include <regex>
Santosh Puranik253fbe92022-10-06 22:38:09 +053029#include <thread>
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053030
31using namespace std;
32using namespace openpower::vpd;
33using namespace CLI;
34using namespace vpd::keyword::parser;
PriyangaRamasamy83a1d5d2020-04-30 19:15:43 +053035using namespace openpower::vpd::constants;
36namespace fs = filesystem;
37using json = nlohmann::json;
SunnySrivastava1984e12b1812020-05-26 02:23:11 -050038using namespace openpower::vpd::parser::factory;
SunnySrivastava1984945a02d2020-05-06 01:55:41 -050039using namespace openpower::vpd::inventory;
Alpana Kumaria00936f2020-04-14 07:15:46 -050040using namespace openpower::vpd::memory::parser;
SunnySrivastava1984e12b1812020-05-26 02:23:11 -050041using namespace openpower::vpd::parser::interface;
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -050042using namespace openpower::vpd::exceptions;
Andrew Geissler280197e2020-12-08 20:51:49 -060043using namespace phosphor::logging;
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -050044using namespace openpower::vpd::manager::editor;
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053045
Santosh Puranik88edeb62020-03-02 12:00:09 +053046/**
Santosh Puranike9c57532022-03-15 16:51:51 +053047 * @brief Returns the BMC state
48 */
49static auto getBMCState()
50{
51 std::string bmcState;
52 try
53 {
54 auto bus = sdbusplus::bus::new_default();
55 auto properties = bus.new_method_call(
56 "xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0",
57 "org.freedesktop.DBus.Properties", "Get");
58 properties.append("xyz.openbmc_project.State.BMC");
59 properties.append("CurrentBMCState");
60 auto result = bus.call(properties);
61 std::variant<std::string> val;
62 result.read(val);
63 if (auto pVal = std::get_if<std::string>(&val))
64 {
65 bmcState = *pVal;
66 }
67 }
68 catch (const sdbusplus::exception::SdBusError& e)
69 {
70 // Ignore any error
71 std::cerr << "Failed to get BMC state: " << e.what() << "\n";
72 }
73 return bmcState;
74}
75
76/**
77 * @brief Check if the FRU is in the cache
78 *
79 * Checks if the FRU associated with the supplied D-Bus object path is already
80 * on D-Bus. This can be used to test if a VPD collection is required for this
81 * FRU. It uses the "xyz.openbmc_project.Inventory.Item, Present" property to
82 * determine the presence of a FRU in the cache.
83 *
84 * @param objectPath - The D-Bus object path without the PIM prefix.
85 * @return true if the object exists on D-Bus, false otherwise.
86 */
87static auto isFruInVpdCache(const std::string& objectPath)
88{
89 try
90 {
91 auto bus = sdbusplus::bus::new_default();
92 auto invPath = std::string{pimPath} + objectPath;
93 auto props = bus.new_method_call(
94 "xyz.openbmc_project.Inventory.Manager", invPath.c_str(),
95 "org.freedesktop.DBus.Properties", "Get");
96 props.append("xyz.openbmc_project.Inventory.Item");
97 props.append("Present");
98 auto result = bus.call(props);
99 std::variant<bool> present;
100 result.read(present);
101 if (auto pVal = std::get_if<bool>(&present))
102 {
103 return *pVal;
104 }
105 return false;
106 }
107 catch (const sdbusplus::exception::SdBusError& e)
108 {
109 std::cout << "FRU: " << objectPath << " not in D-Bus\n";
110 // Assume not present in case of an error
111 return false;
112 }
113}
114
115/**
116 * @brief Check if VPD recollection is needed for the given EEPROM
117 *
118 * Not all FRUs can be swapped at BMC ready state. This function does the
119 * following:
120 * -- Check if the FRU is marked as "pluggableAtStandby" OR
121 * "concurrentlyMaintainable". If so, return true.
122 * -- Check if we are at BMC NotReady state. If we are, then return true.
123 * -- Else check if the FRU is not present in the VPD cache (to cover for VPD
124 * force collection). If not found in the cache, return true.
125 * -- Else return false.
126 *
127 * @param js - JSON Object.
128 * @param filePath - The EEPROM file.
129 * @return true if collection should be attempted, false otherwise.
130 */
131static auto needsRecollection(const nlohmann::json& js, const string& filePath)
132{
133 if (js["frus"][filePath].at(0).value("pluggableAtStandby", false) ||
134 js["frus"][filePath].at(0).value("concurrentlyMaintainable", false))
135 {
136 return true;
137 }
138 if (getBMCState() == "xyz.openbmc_project.State.BMC.BMCState.NotReady")
139 {
140 return true;
141 }
142 if (!isFruInVpdCache(js["frus"][filePath].at(0).value("inventoryPath", "")))
143 {
144 return true;
145 }
146 return false;
147}
148
149/**
Santosh Puranik88edeb62020-03-02 12:00:09 +0530150 * @brief Expands location codes
151 */
152static auto expandLocationCode(const string& unexpanded, const Parsed& vpdMap,
153 bool isSystemVpd)
154{
155 auto expanded{unexpanded};
156 static constexpr auto SYSTEM_OBJECT = "/system/chassis/motherboard";
157 static constexpr auto VCEN_IF = "com.ibm.ipzvpd.VCEN";
158 static constexpr auto VSYS_IF = "com.ibm.ipzvpd.VSYS";
159 size_t idx = expanded.find("fcs");
160 try
161 {
162 if (idx != string::npos)
163 {
164 string fc{};
165 string se{};
166 if (isSystemVpd)
167 {
168 const auto& fcData = vpdMap.at("VCEN").at("FC");
169 const auto& seData = vpdMap.at("VCEN").at("SE");
170 fc = string(fcData.data(), fcData.size());
171 se = string(seData.data(), seData.size());
172 }
173 else
174 {
175 fc = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "FC");
176 se = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "SE");
177 }
178
Alpana Kumari81671f62021-02-10 02:21:59 -0600179 // TODO: See if ND0 can be placed in the JSON
180 expanded.replace(idx, 3, fc.substr(0, 4) + ".ND0." + se);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530181 }
182 else
183 {
184 idx = expanded.find("mts");
185 if (idx != string::npos)
186 {
187 string mt{};
188 string se{};
189 if (isSystemVpd)
190 {
191 const auto& mtData = vpdMap.at("VSYS").at("TM");
192 const auto& seData = vpdMap.at("VSYS").at("SE");
193 mt = string(mtData.data(), mtData.size());
194 se = string(seData.data(), seData.size());
195 }
196 else
197 {
198 mt = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "TM");
199 se = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "SE");
200 }
201
202 replace(mt.begin(), mt.end(), '-', '.');
203 expanded.replace(idx, 3, mt + "." + se);
204 }
205 }
206 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500207 catch (const exception& e)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530208 {
jinuthomasf457a3e2023-04-13 12:22:48 -0500209 std::cerr << "Failed to expand location code with exception: "
210 << e.what() << "\n";
Santosh Puranik88edeb62020-03-02 12:00:09 +0530211 }
212 return expanded;
213}
Alpana Kumari2f793042020-08-18 05:51:03 -0500214
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530215/**
216 * @brief Populate FRU specific interfaces.
217 *
218 * This is a common method which handles both
219 * ipz and keyword specific interfaces thus,
220 * reducing the code redundancy.
221 * @param[in] map - Reference to the innermost keyword-value map.
222 * @param[in] preIntrStr - Reference to the interface string.
223 * @param[out] interfaces - Reference to interface map.
224 */
225template <typename T>
226static void populateFruSpecificInterfaces(const T& map,
227 const string& preIntrStr,
228 inventory::InterfaceMap& interfaces)
229{
230 inventory::PropertyMap prop;
231
232 for (const auto& kwVal : map)
233 {
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530234 auto kw = kwVal.first;
235
236 if (kw[0] == '#')
237 {
Alpana Kumari58e22142020-05-05 00:22:12 -0500238 kw = string("PD_") + kw[1];
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530239 }
Alpana Kumari8ea3f6d2020-04-02 00:26:07 -0500240 else if (isdigit(kw[0]))
241 {
Alpana Kumari58e22142020-05-05 00:22:12 -0500242 kw = string("N_") + kw;
Alpana Kumari8ea3f6d2020-04-02 00:26:07 -0500243 }
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000244 if constexpr (is_same<T, KeywordVpdMap>::value)
245 {
jinuthomasd640f692023-03-28 04:13:23 -0500246 if (auto keywordValue = get_if<Binary>(&kwVal.second))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000247 {
jinuthomasd640f692023-03-28 04:13:23 -0500248 Binary vec((*keywordValue).begin(), (*keywordValue).end());
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000249 prop.emplace(move(kw), move(vec));
250 }
jinuthomasd640f692023-03-28 04:13:23 -0500251 else if (auto keywordValue = get_if<std::string>(&kwVal.second))
252 {
253 Binary vec((*keywordValue).begin(), (*keywordValue).end());
254 prop.emplace(move(kw), move(vec));
255 }
256 else if (auto keywordValue = get_if<size_t>(&kwVal.second))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000257 {
258 if (kw == "MemorySizeInKB")
259 {
260 inventory::PropertyMap memProp;
jinuthomasd640f692023-03-28 04:13:23 -0500261 memProp.emplace(move(kw), ((*keywordValue)));
262 interfaces.emplace(
263 "xyz.openbmc_project.Inventory.Item.Dimm",
264 move(memProp));
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000265 }
jinuthomasd640f692023-03-28 04:13:23 -0500266 else
267 {
jinuthomasf457a3e2023-04-13 12:22:48 -0500268 std::cerr << "Unknown Keyword[" << kw << "] found ";
jinuthomasd640f692023-03-28 04:13:23 -0500269 }
270 }
271 else
272 {
jinuthomasf457a3e2023-04-13 12:22:48 -0500273 std::cerr << "Unknown Variant found ";
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000274 }
275 }
276 else
277 {
278 Binary vec(kwVal.second.begin(), kwVal.second.end());
279 prop.emplace(move(kw), move(vec));
280 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530281 }
282
283 interfaces.emplace(preIntrStr, move(prop));
284}
285
286/**
287 * @brief Populate Interfaces.
288 *
289 * This method populates common and extra interfaces to dbus.
290 * @param[in] js - json object
291 * @param[out] interfaces - Reference to interface map
292 * @param[in] vpdMap - Reference to the parsed vpd map.
Santosh Puranik88edeb62020-03-02 12:00:09 +0530293 * @param[in] isSystemVpd - Denotes whether we are collecting the system VPD.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530294 */
295template <typename T>
296static void populateInterfaces(const nlohmann::json& js,
297 inventory::InterfaceMap& interfaces,
Santosh Puranik88edeb62020-03-02 12:00:09 +0530298 const T& vpdMap, bool isSystemVpd)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530299{
300 for (const auto& ifs : js.items())
301 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530302 string inf = ifs.key();
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530303 inventory::PropertyMap props;
304
305 for (const auto& itr : ifs.value().items())
306 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530307 const string& busProp = itr.key();
308
Alpana Kumari31970de2020-02-17 06:49:57 -0600309 if (itr.value().is_boolean())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530310 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530311 props.emplace(busProp, itr.value().get<bool>());
312 }
313 else if (itr.value().is_string())
314 {
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600315 if (busProp == "LocationCode" && inf == IBM_LOCATION_CODE_INF)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530316 {
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600317 std::string prop;
318 if constexpr (is_same<T, Parsed>::value)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530319 {
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000320 // TODO deprecate the com.ibm interface later
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600321 prop = expandLocationCode(itr.value().get<string>(),
322 vpdMap, isSystemVpd);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530323 }
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600324 else if constexpr (is_same<T, KeywordVpdMap>::value)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530325 {
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600326 // Send empty Parsed object to expandLocationCode api.
327 prop = expandLocationCode(itr.value().get<string>(),
328 Parsed{}, false);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530329 }
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600330 props.emplace(busProp, prop);
331 interfaces.emplace(XYZ_LOCATION_CODE_INF, props);
332 interfaces.emplace(IBM_LOCATION_CODE_INF, props);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530333 }
334 else
335 {
336 props.emplace(busProp, itr.value().get<string>());
337 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530338 }
Santosh Puraniked609af2021-06-21 11:30:07 +0530339 else if (itr.value().is_array())
340 {
341 try
342 {
343 props.emplace(busProp, itr.value().get<Binary>());
344 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500345 catch (const nlohmann::detail::type_error& e)
Santosh Puraniked609af2021-06-21 11:30:07 +0530346 {
347 std::cerr << "Type exception: " << e.what() << "\n";
348 // Ignore any type errors
349 }
350 }
Alpana Kumari31970de2020-02-17 06:49:57 -0600351 else if (itr.value().is_object())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530352 {
Alpana Kumari31970de2020-02-17 06:49:57 -0600353 const string& rec = itr.value().value("recordName", "");
354 const string& kw = itr.value().value("keywordName", "");
355 const string& encoding = itr.value().value("encoding", "");
356
Alpana Kumari58e22142020-05-05 00:22:12 -0500357 if constexpr (is_same<T, Parsed>::value)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530358 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530359 if (!rec.empty() && !kw.empty() && vpdMap.count(rec) &&
360 vpdMap.at(rec).count(kw))
Alpana Kumari31970de2020-02-17 06:49:57 -0600361 {
Patrick Williamsc78d8872023-05-10 07:50:56 -0500362 auto encoded = encodeKeyword(vpdMap.at(rec).at(kw),
363 encoding);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530364 props.emplace(busProp, encoded);
Alpana Kumari31970de2020-02-17 06:49:57 -0600365 }
366 }
Alpana Kumari58e22142020-05-05 00:22:12 -0500367 else if constexpr (is_same<T, KeywordVpdMap>::value)
Alpana Kumari31970de2020-02-17 06:49:57 -0600368 {
369 if (!kw.empty() && vpdMap.count(kw))
370 {
jinuthomasd640f692023-03-28 04:13:23 -0500371 if (auto kwValue = get_if<Binary>(&vpdMap.at(kw)))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000372 {
Patrick Williamsc78d8872023-05-10 07:50:56 -0500373 auto prop = string((*kwValue).begin(),
374 (*kwValue).end());
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000375
376 auto encoded = encodeKeyword(prop, encoding);
377
378 props.emplace(busProp, encoded);
379 }
jinuthomasd640f692023-03-28 04:13:23 -0500380 else if (auto kwValue =
381 get_if<std::string>(&vpdMap.at(kw)))
382 {
Patrick Williamsc78d8872023-05-10 07:50:56 -0500383 auto prop = string((*kwValue).begin(),
384 (*kwValue).end());
jinuthomasd640f692023-03-28 04:13:23 -0500385
386 auto encoded = encodeKeyword(prop, encoding);
387
388 props.emplace(busProp, encoded);
389 }
390 else if (auto uintValue =
391 get_if<size_t>(&vpdMap.at(kw)))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000392 {
393 props.emplace(busProp, *uintValue);
394 }
jinuthomasd640f692023-03-28 04:13:23 -0500395 else
396 {
397 std::cerr << " Unknown Keyword [" << kw
398 << "] Encountered";
399 }
Alpana Kumari31970de2020-02-17 06:49:57 -0600400 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530401 }
402 }
Matt Spinlerb1e64bb2021-09-08 09:57:48 -0500403 else if (itr.value().is_number())
404 {
405 // For now assume the value is a size_t. In the future it would
406 // be nice to come up with a way to get the type from the JSON.
407 props.emplace(busProp, itr.value().get<size_t>());
408 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530409 }
Priyanga Ramasamyaa8a8932022-01-27 09:12:41 -0600410 insertOrMerge(interfaces, inf, move(props));
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530411 }
412}
413
alpana075cb3b1f2021-12-16 11:19:36 -0600414/**
415 * @brief This API checks if this FRU is pcie_devices. If yes then it further
416 * checks whether it is PASS1 planar.
417 */
418static bool isThisPcieOnPass1planar(const nlohmann::json& js,
419 const string& file)
420{
421 auto isThisPCIeDev = false;
422 auto isPASS1 = false;
423
424 // Check if it is a PCIE device
425 if (js["frus"].find(file) != js["frus"].end())
426 {
Santosh Puranikc03f3902022-04-14 10:58:26 +0530427 if ((js["frus"][file].at(0).find("extraInterfaces") !=
428 js["frus"][file].at(0).end()))
alpana075cb3b1f2021-12-16 11:19:36 -0600429 {
Santosh Puranikc03f3902022-04-14 10:58:26 +0530430 if (js["frus"][file].at(0)["extraInterfaces"].find(
alpana075cb3b1f2021-12-16 11:19:36 -0600431 "xyz.openbmc_project.Inventory.Item.PCIeDevice") !=
Santosh Puranikc03f3902022-04-14 10:58:26 +0530432 js["frus"][file].at(0)["extraInterfaces"].end())
alpana075cb3b1f2021-12-16 11:19:36 -0600433 {
434 isThisPCIeDev = true;
435 }
436 }
437 }
438
439 if (isThisPCIeDev)
440 {
Alpana Kumaria6181e22022-05-12 05:01:53 -0500441 // Collect HW version and SystemType to know if it is PASS1 planar.
alpana075cb3b1f2021-12-16 11:19:36 -0600442 auto bus = sdbusplus::bus::new_default();
Alpana Kumaria6181e22022-05-12 05:01:53 -0500443 auto property1 = bus.new_method_call(
alpana075cb3b1f2021-12-16 11:19:36 -0600444 INVENTORY_MANAGER_SERVICE,
445 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
446 "org.freedesktop.DBus.Properties", "Get");
Alpana Kumaria6181e22022-05-12 05:01:53 -0500447 property1.append("com.ibm.ipzvpd.VINI");
448 property1.append("HW");
449 auto result1 = bus.call(property1);
450 inventory::Value hwVal;
451 result1.read(hwVal);
alpana075cb3b1f2021-12-16 11:19:36 -0600452
Alpana Kumaria6181e22022-05-12 05:01:53 -0500453 // SystemType
454 auto property2 = bus.new_method_call(
455 INVENTORY_MANAGER_SERVICE,
456 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
457 "org.freedesktop.DBus.Properties", "Get");
458 property2.append("com.ibm.ipzvpd.VSBP");
459 property2.append("IM");
460 auto result2 = bus.call(property2);
461 inventory::Value imVal;
462 result2.read(imVal);
463
464 auto pVal1 = get_if<Binary>(&hwVal);
465 auto pVal2 = get_if<Binary>(&imVal);
466
467 if (pVal1 && pVal2)
alpana075cb3b1f2021-12-16 11:19:36 -0600468 {
Alpana Kumaria6181e22022-05-12 05:01:53 -0500469 auto hwVersion = *pVal1;
470 auto systemType = *pVal2;
471
472 // IM kw for Everest
473 Binary everestSystem{80, 00, 48, 00};
474
475 if (systemType == everestSystem)
476 {
477 if (hwVersion[1] < 21)
478 {
479 isPASS1 = true;
480 }
481 }
482 else if (hwVersion[1] < 2)
483 {
alpana075cb3b1f2021-12-16 11:19:36 -0600484 isPASS1 = true;
Alpana Kumaria6181e22022-05-12 05:01:53 -0500485 }
alpana075cb3b1f2021-12-16 11:19:36 -0600486 }
487 }
488
489 return (isThisPCIeDev && isPASS1);
490}
491
Alpana Kumari735dee92022-03-25 01:24:40 -0500492/** Performs any pre-action needed to get the FRU setup for collection.
Alpana Kumari2f793042020-08-18 05:51:03 -0500493 *
494 * @param[in] json - json object
495 * @param[in] file - eeprom file path
496 */
497static void preAction(const nlohmann::json& json, const string& file)
498{
Alpana Kumari735dee92022-03-25 01:24:40 -0500499 if ((json["frus"][file].at(0)).find("preAction") ==
Alpana Kumari2f793042020-08-18 05:51:03 -0500500 json["frus"][file].at(0).end())
501 {
Alpana Kumari735dee92022-03-25 01:24:40 -0500502 return;
Alpana Kumari2f793042020-08-18 05:51:03 -0500503 }
504
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500505 try
Alpana Kumari2f793042020-08-18 05:51:03 -0500506 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500507 if (executePreAction(json, file))
Alpana Kumari2f793042020-08-18 05:51:03 -0500508 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500509 if (json["frus"][file].at(0).find("devAddress") !=
510 json["frus"][file].at(0).end())
Alpana Kumari40d1c192022-03-09 21:16:02 -0600511 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500512 // Now bind the device
513 string bind = json["frus"][file].at(0).value("devAddress", "");
jinuthomasf457a3e2023-04-13 12:22:48 -0500514 std::cout << "Binding device " << bind << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500515 string bindCmd = string("echo \"") + bind +
516 string("\" > /sys/bus/i2c/drivers/at24/bind");
jinuthomasf457a3e2023-04-13 12:22:48 -0500517 std::cout << bindCmd << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500518 executeCmd(bindCmd);
519
520 // Check if device showed up (test for file)
521 if (!fs::exists(file))
522 {
jinuthomasf457a3e2023-04-13 12:22:48 -0500523 std::cerr << "EEPROM " << file
524 << " does not exist. Take failure action"
525 << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500526 // If not, then take failure postAction
527 executePostFailAction(json, file);
528 }
529 }
530 else
531 {
532 // missing required informations
jinuthomasf457a3e2023-04-13 12:22:48 -0500533 std::cerr << "VPD inventory JSON missing basic informations of "
534 "preAction "
535 "for this FRU : ["
536 << file << "]. Executing executePostFailAction."
537 << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500538
539 // Take failure postAction
Alpana Kumari40d1c192022-03-09 21:16:02 -0600540 executePostFailAction(json, file);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500541 return;
Alpana Kumari40d1c192022-03-09 21:16:02 -0600542 }
543 }
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530544 else
545 {
546 // If the FRU is not there, clear the VINI/CCIN data.
547 // Enity manager probes for this keyword to look for this
548 // FRU, now if the data is persistent on BMC and FRU is
549 // removed this can lead to ambiguity. Hence clearing this
550 // Keyword if FRU is absent.
551 const auto& invPath =
552 json["frus"][file].at(0).value("inventoryPath", "");
553
554 if (!invPath.empty())
555 {
556 inventory::ObjectMap pimObjMap{
557 {invPath, {{"com.ibm.ipzvpd.VINI", {{"CC", Binary{}}}}}}};
558
559 common::utility::callPIM(move(pimObjMap));
560 }
561 else
562 {
563 throw std::runtime_error("Path empty in Json");
564 }
565 }
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500566 }
567 catch (const GpioException& e)
568 {
569 PelAdditionalData additionalData{};
570 additionalData.emplace("DESCRIPTION", e.what());
571 createPEL(additionalData, PelSeverity::WARNING, errIntfForGpioError,
572 nullptr);
Alpana Kumari2f793042020-08-18 05:51:03 -0500573 }
Alpana Kumari2f793042020-08-18 05:51:03 -0500574}
575
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530576/**
Santosh Puranikf3e69682022-03-31 17:52:38 +0530577 * @brief Fills the Decorator.AssetTag property into the interfaces map
578 *
579 * This function should only be called in cases where we did not find a JSON
580 * symlink. A missing symlink in /var/lib will be considered as a factory reset
581 * and this function will be used to default the AssetTag property.
582 *
583 * @param interfaces A possibly pre-populated map of inetrfaces to properties.
584 * @param vpdMap A VPD map of the system VPD data.
585 */
586static void fillAssetTag(inventory::InterfaceMap& interfaces,
587 const Parsed& vpdMap)
588{
589 // Read the system serial number and MTM
590 // Default asset tag is Server-MTM-System Serial
591 inventory::Interface assetIntf{
592 "xyz.openbmc_project.Inventory.Decorator.AssetTag"};
593 inventory::PropertyMap assetTagProps;
594 std::string defaultAssetTag =
595 std::string{"Server-"} + getKwVal(vpdMap, "VSYS", "TM") +
596 std::string{"-"} + getKwVal(vpdMap, "VSYS", "SE");
597 assetTagProps.emplace("AssetTag", defaultAssetTag);
598 insertOrMerge(interfaces, assetIntf, std::move(assetTagProps));
599}
600
601/**
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530602 * @brief Set certain one time properties in the inventory
603 * Use this function to insert the Functional and Enabled properties into the
604 * inventory map. This function first checks if the object in question already
605 * has these properties hosted on D-Bus, if the property is already there, it is
606 * not modified, hence the name "one time". If the property is not already
607 * present, it will be added to the map with a suitable default value (true for
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530608 * Functional and Enabled)
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530609 *
610 * @param[in] object - The inventory D-Bus obejct without the inventory prefix.
611 * @param[inout] interfaces - Reference to a map of inventory interfaces to
612 * which the properties will be attached.
613 */
614static void setOneTimeProperties(const std::string& object,
615 inventory::InterfaceMap& interfaces)
616{
617 auto bus = sdbusplus::bus::new_default();
618 auto objectPath = INVENTORY_PATH + object;
619 auto prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager",
620 objectPath.c_str(),
621 "org.freedesktop.DBus.Properties", "Get");
622 prop.append("xyz.openbmc_project.State.Decorator.OperationalStatus");
623 prop.append("Functional");
624 try
625 {
626 auto result = bus.call(prop);
627 }
628 catch (const sdbusplus::exception::SdBusError& e)
629 {
630 // Treat as property unavailable
631 inventory::PropertyMap prop;
632 prop.emplace("Functional", true);
633 interfaces.emplace(
634 "xyz.openbmc_project.State.Decorator.OperationalStatus",
635 move(prop));
636 }
637 prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager",
638 objectPath.c_str(),
639 "org.freedesktop.DBus.Properties", "Get");
640 prop.append("xyz.openbmc_project.Object.Enable");
641 prop.append("Enabled");
642 try
643 {
644 auto result = bus.call(prop);
645 }
646 catch (const sdbusplus::exception::SdBusError& e)
647 {
648 // Treat as property unavailable
649 inventory::PropertyMap prop;
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530650 prop.emplace("Enabled", true);
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530651 interfaces.emplace("xyz.openbmc_project.Object.Enable", move(prop));
652 }
653}
654
655/**
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530656 * @brief Prime the Inventory
657 * Prime the inventory by populating only the location code,
658 * type interface and the inventory object for the frus
659 * which are not system vpd fru.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530660 *
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530661 * @param[in] jsObject - Reference to vpd inventory json object
662 * @param[in] vpdMap - Reference to the parsed vpd map
663 *
664 * @returns Map of items in extraInterface.
665 */
666template <typename T>
667inventory::ObjectMap primeInventory(const nlohmann::json& jsObject,
668 const T& vpdMap)
669{
670 inventory::ObjectMap objects;
671
672 for (auto& itemFRUS : jsObject["frus"].items())
673 {
674 for (auto& itemEEPROM : itemFRUS.value())
675 {
Alpana Kumari2e6c6f72020-12-03 00:10:03 -0600676 // Take pre actions if needed
677 if (itemEEPROM.find("preAction") != itemEEPROM.end())
678 {
679 preAction(jsObject, itemFRUS.key());
680 }
681
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530682 inventory::InterfaceMap interfaces;
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530683 inventory::Object object(itemEEPROM.at("inventoryPath"));
684
Santosh Puranik50f60bf2021-05-26 17:55:06 +0530685 if ((itemFRUS.key() != systemVpdFilePath) &&
686 !itemEEPROM.value("noprime", false))
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530687 {
Alpana Kumaricfd7a752021-02-07 23:23:01 -0600688 inventory::PropertyMap presProp;
Priyanga Ramasamye358acb2022-03-21 14:21:50 -0500689
690 // Do not populate Present property for frus whose
Priyanga Ramasamyaca61372023-01-24 08:02:28 -0600691 // synthesized=true. synthesized=true says the fru VPD is
692 // synthesized and owned by a separate component.
693 // In some cases, the FRU has its own VPD, but still a separate
694 // application handles the FRU's presence. So VPD parser skips
695 // populating Present property by checking the JSON flag,
696 // "handlePresence".
Priyanga Ramasamye358acb2022-03-21 14:21:50 -0500697 if (!itemEEPROM.value("synthesized", false))
698 {
Priyanga Ramasamyaca61372023-01-24 08:02:28 -0600699 if (itemEEPROM.value("handlePresence", true))
700 {
701 presProp.emplace("Present", false);
702 interfaces.emplace("xyz.openbmc_project.Inventory.Item",
703 presProp);
704 }
Priyanga Ramasamye358acb2022-03-21 14:21:50 -0500705 }
Priyanga Ramasamyaca61372023-01-24 08:02:28 -0600706
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530707 setOneTimeProperties(object, interfaces);
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530708 if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end())
709 {
710 for (const auto& eI : itemEEPROM["extraInterfaces"].items())
711 {
712 inventory::PropertyMap props;
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000713 if (eI.key() == IBM_LOCATION_CODE_INF)
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530714 {
715 if constexpr (std::is_same<T, Parsed>::value)
716 {
717 for (auto& lC : eI.value().items())
718 {
719 auto propVal = expandLocationCode(
720 lC.value().get<string>(), vpdMap, true);
721
722 props.emplace(move(lC.key()),
723 move(propVal));
Santosh Puranikb0f37492021-06-21 09:42:47 +0530724 interfaces.emplace(XYZ_LOCATION_CODE_INF,
725 props);
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530726 interfaces.emplace(move(eI.key()),
727 move(props));
728 }
729 }
730 }
731 else if (eI.key().find("Inventory.Item.") !=
732 string::npos)
733 {
734 interfaces.emplace(move(eI.key()), move(props));
735 }
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530736 else if (eI.key() ==
737 "xyz.openbmc_project.Inventory.Item")
738 {
739 for (auto& val : eI.value().items())
740 {
741 if (val.key() == "PrettyName")
742 {
743 presProp.emplace(val.key(),
744 val.value().get<string>());
745 }
746 }
747 // Use insert_or_assign here as we may already have
748 // inserted the present property only earlier in
749 // this function under this same interface.
750 interfaces.insert_or_assign(eI.key(),
751 move(presProp));
752 }
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530753 }
754 }
755 objects.emplace(move(object), move(interfaces));
756 }
757 }
758 }
759 return objects;
760}
761
Alpana Kumari65b83602020-09-01 00:24:56 -0500762/**
763 * @brief This API executes command to set environment variable
764 * And then reboot the system
765 * @param[in] key -env key to set new value
766 * @param[in] value -value to set.
767 */
768void setEnvAndReboot(const string& key, const string& value)
769{
770 // set env and reboot and break.
771 executeCmd("/sbin/fw_setenv", key, value);
Andrew Geissler280197e2020-12-08 20:51:49 -0600772 log<level::INFO>("Rebooting BMC to pick up new device tree");
Alpana Kumari65b83602020-09-01 00:24:56 -0500773 // make dbus call to reboot
774 auto bus = sdbusplus::bus::new_default_system();
775 auto method = bus.new_method_call(
776 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
777 "org.freedesktop.systemd1.Manager", "Reboot");
778 bus.call_noreply(method);
779}
780
781/*
782 * @brief This API checks for env var fitconfig.
783 * If not initialised OR updated as per the current system type,
784 * update this env var and reboot the system.
785 *
786 * @param[in] systemType IM kwd in vpd tells about which system type it is.
787 * */
788void setDevTreeEnv(const string& systemType)
789{
Alpana Kumari37e72702021-11-18 11:18:04 -0600790 // Init with default dtb
791 string newDeviceTree = "conf-aspeed-bmc-ibm-rainier-p1.dtb";
Santosh Puranike5f177a2022-01-24 20:14:46 +0530792 static const deviceTreeMap deviceTreeSystemTypeMap = {
793 {RAINIER_2U, "conf-aspeed-bmc-ibm-rainier-p1.dtb"},
794 {RAINIER_2U_V2, "conf-aspeed-bmc-ibm-rainier.dtb"},
795 {RAINIER_4U, "conf-aspeed-bmc-ibm-rainier-4u-p1.dtb"},
796 {RAINIER_4U_V2, "conf-aspeed-bmc-ibm-rainier-4u.dtb"},
797 {RAINIER_1S4U, "conf-aspeed-bmc-ibm-rainier-1s4u.dtb"},
Alpana Kumari1b026112022-03-02 23:41:38 -0600798 {EVEREST, "conf-aspeed-bmc-ibm-everest.dtb"},
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530799 {EVEREST_V2, "conf-aspeed-bmc-ibm-everest.dtb"},
800 {BONNELL, "conf-aspeed-bmc-ibm-bonnell.dtb"}};
Alpana Kumari65b83602020-09-01 00:24:56 -0500801
802 if (deviceTreeSystemTypeMap.find(systemType) !=
803 deviceTreeSystemTypeMap.end())
804 {
805 newDeviceTree = deviceTreeSystemTypeMap.at(systemType);
806 }
Alpana Kumari37e72702021-11-18 11:18:04 -0600807 else
808 {
809 // System type not supported
Alpana Kumariab1e22c2021-11-24 11:03:38 -0600810 string err = "This System type not found/supported in dtb table " +
811 systemType +
812 ".Please check the HW and IM keywords in the system "
813 "VPD.Breaking...";
814
815 // map to hold additional data in case of logging pel
816 PelAdditionalData additionalData{};
817 additionalData.emplace("DESCRIPTION", err);
818 createPEL(additionalData, PelSeverity::WARNING,
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500819 errIntfForInvalidSystemType, nullptr);
Alpana Kumariab1e22c2021-11-24 11:03:38 -0600820 exit(-1);
Alpana Kumari37e72702021-11-18 11:18:04 -0600821 }
Alpana Kumari65b83602020-09-01 00:24:56 -0500822
823 string readVarValue;
824 bool envVarFound = false;
825
826 vector<string> output = executeCmd("/sbin/fw_printenv");
827 for (const auto& entry : output)
828 {
829 size_t pos = entry.find("=");
830 string key = entry.substr(0, pos);
831 if (key != "fitconfig")
832 {
833 continue;
834 }
835
836 envVarFound = true;
837 if (pos + 1 < entry.size())
838 {
839 readVarValue = entry.substr(pos + 1);
840 if (readVarValue.find(newDeviceTree) != string::npos)
841 {
842 // fitconfig is Updated. No action needed
843 break;
844 }
845 }
846 // set env and reboot and break.
847 setEnvAndReboot(key, newDeviceTree);
848 exit(0);
849 }
850
851 // check If env var Not found
852 if (!envVarFound)
853 {
854 setEnvAndReboot("fitconfig", newDeviceTree);
855 }
856}
857
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530858/**
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -0500859 * @brief Parse the given EEPROM file.
860 *
861 * @param[in] vpdFilePath - Path of EEPROM file
862 * @param[in] invPath - Path of inventory object
863 * @param[in] js- Reference to vpd inventory json object
864 *
865 * @return Parsed VPD map
866 */
867std::variant<KeywordVpdMap, openpower::vpd::Store>
868 parseVpdFile(const std::string& vpdFilePath, const std::string& invPath,
869 const nlohmann::json& js)
870{
871 uint32_t vpdStartOffset = 0;
872 for (const auto& item : js["frus"][vpdFilePath])
873 {
874 if (item.find("offset") != item.end())
875 {
876 vpdStartOffset = item["offset"];
877 }
878 }
879
880 Binary vpdVector = getVpdDataInVector(js, vpdFilePath);
881
882 ParserInterface* parser = ParserFactory::getParser(
883 vpdVector, (pimPath + invPath), vpdFilePath, vpdStartOffset);
884
885 auto parseResult = parser->parse();
886
887 // release the parser object
888 ParserFactory::freeParser(parser);
889
890 return parseResult;
891}
892
893/*
894 * @brief This API retrieves the hardware backup in map
895 *
896 * @param[in] systemVpdBackupPath - The path that backs up the system VPD.
897 * @param[in] backupVpdInvPath - FRU inventory path.
898 * @param[in] js - JSON object.
899 * @param[out] backupVpdMap - An IPZ VPD map containing the parsed backup VPD.
900 *
901 * */
902void getBackupVpdInMap(const string& systemVpdBackupPath,
903 const string& backupVpdInvPath, const nlohmann::json& js,
904 Parsed& backupVpdMap)
905{
906 PelAdditionalData additionalData{};
907
908 if (!fs::exists(systemVpdBackupPath))
909 {
910 string errorMsg = "Device path ";
911 errorMsg += systemVpdBackupPath;
912 errorMsg += " does not exist";
913
914 additionalData.emplace("DESCRIPTION", errorMsg);
915
916 additionalData.emplace("CALLOUT_INVENTORY_PATH",
917 INVENTORY_PATH + backupVpdInvPath);
918
919 createPEL(additionalData, PelSeverity::ERROR, errIntfForStreamFail,
920 nullptr);
921 }
922 else
923 {
924 auto backupVpdParsedResult = parseVpdFile(systemVpdBackupPath,
925 backupVpdInvPath, js);
926
927 if (auto pVal = get_if<Store>(&backupVpdParsedResult))
928 {
929 backupVpdMap = pVal->getVpdMap();
930 }
931 }
932}
933
934void updateVpdDataOnHw(const std::string& vpdFilePath, nlohmann::json& js,
935 const std::string& recName, const std::string& kwName,
936 const Binary& kwdData)
937{
938 const std::string& fruInvPath =
939 js["frus"][vpdFilePath][0]["inventoryPath"]
940 .get_ref<const nlohmann::json::string_t&>();
941
942 EditorImpl edit(vpdFilePath, js, recName, kwName, fruInvPath);
943
944 uint32_t offset = 0;
945 // Setup offset, if any
946 for (const auto& item : js["frus"][vpdFilePath])
947 {
948 if (item.find("offset") != item.end())
949 {
950 offset = item["offset"];
951 break;
952 }
953 }
954
955 // update keyword data on to EEPROM file
956 // Note: Updating keyword data on cache is
957 // handled via PIM Notify call hence passing
958 // the updCache flag value as false here.
959 edit.updateKeyword(kwdData, offset, false);
960}
961
962/**
963 * @brief Populate base panel object on dbus.
964
965 * This method invokes all the populateInterface functions
966 * and notifies PIM about base panel dbus object.
967
968 * @param[in] vpdMap - Base panel vpd map in IPZ format
969 * @param[in] js - Inventory json object
970 * @param[in] filePath - Path of the base panel vpd file
971 */
972void populateBasePanelObjectOnDBus(const Parsed& vpdMap, nlohmann::json& js,
973 const string& filePath)
974{
975 inventory::InterfaceMap interfaces;
976 inventory::ObjectMap objects;
977 inventory::PropertyMap prop;
978
979 string ccinFromVpd = getKwVal(vpdMap, "VINI", "CC");
980 transform(ccinFromVpd.begin(), ccinFromVpd.end(), ccinFromVpd.begin(),
981 ::toupper);
982
983 for (const auto& item : js["frus"][filePath])
984 {
985 const auto& objectPath = item["inventoryPath"];
986 sdbusplus::message::object_path object(objectPath);
987
988 vector<string> ccinList;
989 if (item.find("ccin") != item.end())
990 {
991 for (const auto& cc : item["ccin"])
992 {
993 string ccin = cc;
994 transform(ccin.begin(), ccin.end(), ccin.begin(), ::toupper);
995 ccinList.push_back(ccin);
996 }
997 }
998
999 if (!ccinFromVpd.empty() && !ccinList.empty() &&
1000 (find(ccinList.begin(), ccinList.end(), ccinFromVpd) ==
1001 ccinList.end()))
1002 {
1003 continue;
1004 }
1005
1006 if ((item.value("noprime", false)))
1007 {
1008 // Populate one time properties for non-primeable frus.
1009 // For the remaining FRUs, this will get handled as a part of
1010 // priming the inventory.
1011 setOneTimeProperties(objectPath, interfaces);
1012 }
1013
1014 // Populate the VPD keywords and the common interfaces only if we
1015 // are asked to inherit that data from the VPD, else only add the
1016 // extraInterfaces.
1017 if (item.value("inherit", true))
1018 {
1019 // Each record in the VPD becomes an interface and all
1020 // keyword within the record are properties under that
1021 // interface.
1022 for (const auto& record : vpdMap)
1023 {
1024 populateFruSpecificInterfaces(
1025 record.second, ipzVpdInf + record.first, interfaces);
1026 }
1027
1028 if (js.find("commonInterfaces") != js.end())
1029 {
1030 populateInterfaces(js["commonInterfaces"], interfaces, vpdMap,
1031 false);
1032 }
1033 }
1034 else
1035 {
1036 // Check if we have been asked to inherit specific record(s)
1037 if (item.find("copyRecords") != item.end())
1038 {
1039 for (const auto& record : item["copyRecords"])
1040 {
1041 const string& recordName = record;
1042 if (vpdMap.find(recordName) != vpdMap.end())
1043 {
1044 populateFruSpecificInterfaces(vpdMap.at(recordName),
1045 ipzVpdInf + recordName,
1046 interfaces);
1047 }
1048 }
1049 }
1050 }
1051
1052 // Populate interfaces and properties that are common to every FRU
1053 // and additional interface that might be defined on a per-FRU
1054 // basis.
1055 if (item.find("extraInterfaces") != item.end())
1056 {
1057 populateInterfaces(item["extraInterfaces"], interfaces, vpdMap,
1058 false);
1059 }
1060
1061 // embedded property(true or false) says whether the subfru is embedded
1062 // into the parent fru (or) not. VPD sets Present property only for
1063 // embedded frus. If the subfru is not an embedded FRU, the subfru may
1064 // or may not be physically present. Those non embedded frus will always
1065 // have Present=false irrespective of its physical presence or absence.
1066 // Eg: nvme drive in nvme slot is not an embedded FRU. So don't set
1067 // Present to true for such sub frus.
1068 // Eg: ethernet port is embedded into bmc card. So set Present to true
1069 // for such sub frus. Also donot populate present property for embedded
1070 // subfru which is synthesized. Currently there is no subfru which are
1071 // both embedded and synthesized. But still the case is handled here.
1072 if ((item.value("embedded", true)) &&
1073 (!item.value("synthesized", false)))
1074 {
1075 // Check if its required to handle presence for this FRU.
1076 if (item.value("handlePresence", true))
1077 {
1078 inventory::PropertyMap presProp;
1079 presProp.emplace("Present", true);
1080 insertOrMerge(interfaces, invItemIntf, move(presProp));
1081 }
1082 }
1083
1084 objects.emplace(move(object), move(interfaces));
1085 }
1086
1087 // Notify PIM
1088 common::utility::callPIM(move(objects));
1089}
1090
1091/**
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001092 * @brief API to check if we need to restore system VPD
1093 * This functionality is only applicable for IPZ VPD data.
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001094
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001095 * @param[in] vpdMap - IPZ vpd map
1096 * @param[in] objectPath - Object path for the FRU
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001097 * @param[in] js - JSON Object
1098 * @param[in] isBackupOnCache - Denotes whether the backup is on cache/hardware
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001099 */
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001100void restoreSystemVPD(Parsed& vpdMap, const string& objectPath,
1101 nlohmann::json& js, bool isBackupOnCache = true)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001102{
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001103 std::string systemVpdBackupPath{};
1104 std::string backupVpdInvPath{};
1105 Parsed backupVpdMap{};
1106
1107 if (!isBackupOnCache)
1108 {
1109 // Get the value of systemvpdBackupPath field from json
1110 systemVpdBackupPath = js["frus"][systemVpdFilePath].at(0).value(
1111 "systemVpdBackupPath", "");
1112
1113 backupVpdInvPath = js["frus"][systemVpdBackupPath][0]["inventoryPath"]
1114 .get_ref<const nlohmann::json::string_t&>();
1115
1116 getBackupVpdInMap(systemVpdBackupPath, backupVpdInvPath, js,
1117 backupVpdMap);
1118
1119 if (backupVpdMap.empty())
1120 {
1121 return;
1122 }
1123 }
1124
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001125 for (const auto& systemRecKwdPair : svpdKwdMap)
1126 {
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001127 const string& recordName = systemRecKwdPair.first;
1128 auto it = vpdMap.find(recordName);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001129
1130 // check if record is found in map we got by parser
1131 if (it != vpdMap.end())
1132 {
1133 const auto& kwdListForRecord = systemRecKwdPair.second;
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -06001134 for (const auto& keywordInfo : kwdListForRecord)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001135 {
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001136 const auto keywordName = get<0>(keywordInfo);
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -06001137
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001138 DbusPropertyMap& kwdValMap = it->second;
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001139 auto iterator = kwdValMap.find(keywordName);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001140
1141 if (iterator != kwdValMap.end())
1142 {
1143 string& kwdValue = iterator->second;
1144
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001145 std::string backupValue{};
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -06001146 const auto& defaultValue = get<1>(keywordInfo);
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001147 const auto& backupVpdRecName = get<4>(keywordInfo);
1148 const auto& backupVpdKwName = get<5>(keywordInfo);
1149
1150 // If the 'isBackupOnCache' flag is false, we need
1151 // to backup the systemVPD on the specified fru's eeprom
1152 // path or restore it from the specified fru's eeprom path.
1153 if (isBackupOnCache)
1154 {
1155 // check bus data
1156 backupValue = readBusProperty(
1157 objectPath, ipzVpdInf + recordName, keywordName);
1158 }
1159 else
1160 {
1161 auto recItr = backupVpdMap.find(backupVpdRecName);
1162 if (recItr != backupVpdMap.end())
1163 {
1164 string errorMsg = backupVpdRecName +
1165 " Record does not exist in "
1166 "the EEPROM file ";
1167
1168 errorMsg += systemVpdBackupPath;
1169
1170 PelAdditionalData additionalData;
1171 additionalData.emplace("DESCRIPTION", errorMsg);
1172
1173 additionalData.emplace("CALLOUT_INVENTORY_PATH",
1174 INVENTORY_PATH +
1175 backupVpdInvPath);
1176
1177 createPEL(additionalData, PelSeverity::ERROR,
1178 errIntfForInvalidVPD, nullptr);
1179
1180 continue;
1181 }
1182 else
1183 {
1184 backupValue = getKwVal(backupVpdMap,
1185 backupVpdRecName,
1186 backupVpdKwName);
1187 if (backupValue.empty())
1188 {
1189 string errorMsg = backupVpdKwName +
1190 " Keyword not found in "
1191 "the backup VPD file ";
1192
1193 errorMsg += systemVpdBackupPath;
1194
1195 PelAdditionalData additionalData;
1196 additionalData.emplace("DESCRIPTION", errorMsg);
1197
1198 additionalData.emplace("CALLOUT_INVENTORY_PATH",
1199 INVENTORY_PATH +
1200 backupVpdInvPath);
1201
1202 createPEL(additionalData, PelSeverity::ERROR,
1203 errIntfForInvalidVPD, nullptr);
1204 continue;
1205 }
1206 }
1207 }
1208
1209 Binary backupDataInBinary(backupValue.begin(),
1210 backupValue.end());
1211
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -06001212 Binary kwdDataInBinary(kwdValue.begin(), kwdValue.end());
Sunny Srivastavaa559c2d2022-05-02 11:56:45 -05001213
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001214 if (backupDataInBinary != defaultValue)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001215 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -06001216 if (kwdDataInBinary != defaultValue)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001217 {
1218 // both the data are present, check for mismatch
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001219 if (backupValue != kwdValue)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001220 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -06001221 string errMsg = "Mismatch found between backup "
1222 "and primary VPD for record: ";
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001223 errMsg += (*it).first;
1224 errMsg += " and keyword: ";
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001225 errMsg += keywordName;
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001226
Santosh Puranikdedb5a62022-12-19 23:58:32 +05301227 std::ostringstream busStream;
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001228 for (uint16_t byte : backupValue)
Santosh Puranikdedb5a62022-12-19 23:58:32 +05301229 {
1230 busStream << std::setfill('0')
1231 << std::setw(2) << std::hex
1232 << "0x" << byte << " ";
1233 }
1234
1235 std::ostringstream vpdStream;
1236 for (uint16_t byte : kwdValue)
1237 {
1238 vpdStream << std::setfill('0')
1239 << std::setw(2) << std::hex
1240 << "0x" << byte << " ";
1241 }
1242
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001243 // data mismatch
1244 PelAdditionalData additionalData;
1245 additionalData.emplace("CALLOUT_INVENTORY_PATH",
Priyanga Ramasamyf6123682022-12-02 07:29:07 -06001246 INVENTORY_PATH +
1247 objectPath);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001248
1249 additionalData.emplace("DESCRIPTION", errMsg);
Santosh Puranikdedb5a62022-12-19 23:58:32 +05301250 additionalData.emplace(
Priyanga Ramasamy24942232023-01-05 04:54:59 -06001251 "Value read from Backup: ",
1252 busStream.str());
1253 additionalData.emplace(
1254 "Value read from Primary: ",
Santosh Puranikdedb5a62022-12-19 23:58:32 +05301255 vpdStream.str());
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001256
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001257 createPEL(additionalData, PelSeverity::WARNING,
Priyanga Ramasamy24942232023-01-05 04:54:59 -06001258 errIntfForVPDMismatch, nullptr);
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001259
1260 if (!isBackupOnCache)
1261 {
1262 // Backing up or restoring from a hardware
1263 // path does not requires copying the backup
1264 // data to the VPD map, as this will result
1265 // in a mismatch between the primary VPD and
1266 // its cache.
1267 continue;
1268 }
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001269 }
1270 }
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001271
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001272 // If the backup is on the cache we need to copy the
1273 // backup data to the VPD map to ensure there is no
1274 // mimatch b/n them. So if backup data is not default,
1275 // then irrespective of primary data(default or other
1276 // than backup), copy the backup data to vpd map as we
1277 // don't need to change the backup data in either case
1278 // in the process of restoring system vpd.
1279 kwdValue = backupValue;
1280
1281 // If the backup data is on the base panel the restoring
1282 // of Backup VPD on to the system backplane VPD
1283 // file is done here not through the VPD manager code
1284 // path. This is to have the logic of restoring data on
1285 // to the cache & hardware in the same code path.
1286 if (!isBackupOnCache)
1287 {
1288 // copy backup VPD on to system backplane
1289 // EEPROM file.
1290 updateVpdDataOnHw(systemVpdFilePath, js, recordName,
1291 keywordName, backupDataInBinary);
1292 }
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001293 }
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -06001294 else if (kwdDataInBinary == defaultValue &&
1295 get<2>(keywordInfo)) // Check isPELRequired is true
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001296 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -06001297 string errMsg = "Found default value on both backup "
1298 "and primary VPD for record: ";
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001299 errMsg += (*it).first;
1300 errMsg += " and keyword: ";
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001301 errMsg += keywordName;
Priyanga Ramasamy24942232023-01-05 04:54:59 -06001302 errMsg += ". SSR need to update primary VPD.";
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001303
Priyanga Ramasamy24942232023-01-05 04:54:59 -06001304 // mfg default on both backup and primary, log PEL
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001305 PelAdditionalData additionalData;
1306 additionalData.emplace("CALLOUT_INVENTORY_PATH",
Priyanga Ramasamyf6123682022-12-02 07:29:07 -06001307 INVENTORY_PATH + objectPath);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001308
1309 additionalData.emplace("DESCRIPTION", errMsg);
1310
1311 // log PEL TODO: Block IPL
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001312 createPEL(additionalData, PelSeverity::ERROR,
Priyanga Ramasamy24942232023-01-05 04:54:59 -06001313 errIntfForVPDDefault, nullptr);
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001314
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001315 continue;
1316 }
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001317 else if ((kwdDataInBinary != defaultValue) &&
1318 (!isBackupOnCache))
1319 {
1320 // update primary VPD on to backup VPD file
1321 updateVpdDataOnHw(systemVpdBackupPath, js,
1322 backupVpdRecName, backupVpdKwName,
1323 kwdDataInBinary);
1324
1325 // copy primary VPD to backup VPD to publish on
1326 // DBus
1327 backupVpdMap.find(backupVpdRecName)
1328 ->second.find(backupVpdKwName)
1329 ->second = kwdValue;
1330 }
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001331 }
1332 }
1333 }
1334 }
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001335
1336 if (!isBackupOnCache)
1337 {
1338 populateBasePanelObjectOnDBus(backupVpdMap, js, systemVpdBackupPath);
1339 }
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001340}
1341
1342/**
alpana077ce68722021-07-25 13:23:59 -05001343 * @brief This checks for is this FRU a processor
1344 * And if yes, then checks for is this primary
1345 *
1346 * @param[in] js- vpd json to get the information about this FRU
1347 * @param[in] filePath- FRU vpd
1348 *
1349 * @return true/false
1350 */
1351bool isThisPrimaryProcessor(nlohmann::json& js, const string& filePath)
1352{
1353 bool isProcessor = false;
1354 bool isPrimary = false;
1355
1356 for (const auto& item : js["frus"][filePath])
1357 {
1358 if (item.find("extraInterfaces") != item.end())
1359 {
1360 for (const auto& eI : item["extraInterfaces"].items())
1361 {
1362 if (eI.key().find("Inventory.Item.Cpu") != string::npos)
1363 {
1364 isProcessor = true;
1365 }
1366 }
1367 }
1368
1369 if (isProcessor)
1370 {
1371 string cpuType = item.value("cpuType", "");
1372 if (cpuType == "primary")
1373 {
1374 isPrimary = true;
1375 }
1376 }
1377 }
1378
1379 return (isProcessor && isPrimary);
1380}
1381
1382/**
1383 * @brief This finds DIMM vpd in vpd json and enables them by binding the device
1384 * driver
1385 * @param[in] js- vpd json to iterate through and take action if it is DIMM
1386 */
1387void doEnableAllDimms(nlohmann::json& js)
1388{
1389 // iterate over each fru
1390 for (const auto& eachFru : js["frus"].items())
1391 {
1392 // skip the driver binding if eeprom already exists
1393 if (fs::exists(eachFru.key()))
1394 {
1395 continue;
1396 }
1397
1398 for (const auto& eachInventory : eachFru.value())
1399 {
1400 if (eachInventory.find("extraInterfaces") != eachInventory.end())
1401 {
1402 for (const auto& eI : eachInventory["extraInterfaces"].items())
1403 {
1404 if (eI.key().find("Inventory.Item.Dimm") != string::npos)
1405 {
1406 string dimmVpd = eachFru.key();
1407 // fetch it from
1408 // "/sys/bus/i2c/drivers/at24/414-0050/eeprom"
1409
1410 regex matchPatern("([0-9]+-[0-9]{4})");
1411 smatch matchFound;
1412 if (regex_search(dimmVpd, matchFound, matchPatern))
1413 {
1414 vector<string> i2cReg;
1415 boost::split(i2cReg, matchFound.str(0),
1416 boost::is_any_of("-"));
1417
1418 // remove 0s from begining
1419 const regex pattern("^0+(?!$)");
1420 for (auto& i : i2cReg)
1421 {
1422 i = regex_replace(i, pattern, "");
1423 }
1424
1425 if (i2cReg.size() == 2)
1426 {
1427 // echo 24c32 0x50 >
1428 // /sys/bus/i2c/devices/i2c-16/new_device
1429 string cmnd = "echo 24c32 0x" + i2cReg[1] +
1430 " > /sys/bus/i2c/devices/i2c-" +
1431 i2cReg[0] + "/new_device";
1432
1433 executeCmd(cmnd);
1434 }
1435 }
1436 }
1437 }
1438 }
1439 }
1440 }
1441}
1442
1443/**
Priyanga Ramasamy6abdeb62022-01-09 23:15:11 -06001444 * @brief Check if the given CPU is an IO only chip.
1445 * The CPU is termed as IO, whose all of the cores are bad and can never be
1446 * used. Those CPU chips can be used for IO purpose like connecting PCIe devices
1447 * etc., The CPU whose every cores are bad, can be identified from the CP00
1448 * record's PG keyword, only if all of the 8 EQs' value equals 0xE7F9FF. (1EQ
1449 * has 4 cores grouped together by sharing its cache memory.)
1450 * @param [in] pgKeyword - PG Keyword of CPU.
1451 * @return true if the given cpu is an IO, false otherwise.
1452 */
1453static bool isCPUIOGoodOnly(const string& pgKeyword)
1454{
1455 const unsigned char io[] = {0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9,
1456 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7,
1457 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF};
1458 // EQ0 index (in PG keyword) starts at 97 (with offset starting from 0).
1459 // Each EQ carries 3 bytes of data. Totally there are 8 EQs. If all EQs'
1460 // value equals 0xE7F9FF, then the cpu has no good cores and its treated as
1461 // IO.
1462 if (memcmp(io, pgKeyword.data() + 97, 24) == 0)
1463 {
1464 return true;
1465 }
1466
1467 // The CPU is not an IO
1468 return false;
1469}
1470
1471/**
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301472 * @brief Populate Dbus.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301473 * This method invokes all the populateInterface functions
1474 * and notifies PIM about dbus object.
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301475 * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the
1476 * input.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301477 * @param[in] js - Inventory json object
1478 * @param[in] filePath - Path of the vpd file
1479 * @param[in] preIntrStr - Interface string
1480 */
1481template <typename T>
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001482static void populateDbus(T& vpdMap, nlohmann::json& js, const string& filePath)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301483{
1484 inventory::InterfaceMap interfaces;
1485 inventory::ObjectMap objects;
1486 inventory::PropertyMap prop;
Shantappa Teekappanavar6aa54502021-12-09 12:59:56 -06001487 string ccinFromVpd;
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301488
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301489 bool isSystemVpd = (filePath == systemVpdFilePath);
1490 if constexpr (is_same<T, Parsed>::value)
1491 {
Shantappa Teekappanavar6aa54502021-12-09 12:59:56 -06001492 ccinFromVpd = getKwVal(vpdMap, "VINI", "CC");
1493 transform(ccinFromVpd.begin(), ccinFromVpd.end(), ccinFromVpd.begin(),
1494 ::toupper);
1495
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301496 if (isSystemVpd)
1497 {
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301498 string mboardPath =
1499 js["frus"][filePath].at(0).value("inventoryPath", "");
1500
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001501 // Get the value of systemvpdBackupPath field from json
1502 const std::string& systemVpdBackupPath =
1503 js["frus"][filePath].at(0).value("systemVpdBackupPath", "");
1504
1505 if (systemVpdBackupPath.empty())
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301506 {
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001507 std::vector<std::string> interfaces = {motherBoardInterface};
1508 // call mapper to check for object path creation
1509 MapperResponse subTree =
1510 getObjectSubtreeForInterfaces(pimPath, 0, interfaces);
1511
1512 // Attempt system VPD restore if we have a motherboard
1513 // object in the inventory.
1514 if ((subTree.size() != 0) &&
1515 (subTree.find(pimPath + mboardPath) != subTree.end()))
1516 {
1517 restoreSystemVPD(vpdMap, mboardPath, js);
1518 }
1519 else
1520 {
1521 log<level::ERR>("No object path found");
1522 }
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301523 }
1524 else
1525 {
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001526 restoreSystemVPD(vpdMap, mboardPath, js, false);
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301527 }
1528 }
alpana077ce68722021-07-25 13:23:59 -05001529 else
1530 {
1531 // check if it is processor vpd.
1532 auto isPrimaryCpu = isThisPrimaryProcessor(js, filePath);
1533
1534 if (isPrimaryCpu)
1535 {
1536 auto ddVersion = getKwVal(vpdMap, "CRP0", "DD");
1537
1538 auto chipVersion = atoi(ddVersion.substr(1, 2).c_str());
1539
1540 if (chipVersion >= 2)
1541 {
1542 doEnableAllDimms(js);
Santosh Puranik253fbe92022-10-06 22:38:09 +05301543 // Sleep for a few seconds to let the DIMM parses start
1544 using namespace std::chrono_literals;
1545 std::this_thread::sleep_for(5s);
alpana077ce68722021-07-25 13:23:59 -05001546 }
1547 }
1548 }
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301549 }
1550
Santosh Puranikf3e69682022-03-31 17:52:38 +05301551 auto processFactoryReset = false;
1552
Priyanga Ramasamy32c687f2022-01-04 23:14:03 -06001553 if (isSystemVpd)
1554 {
1555 string systemJsonName{};
1556 if constexpr (is_same<T, Parsed>::value)
1557 {
1558 // pick the right system json
1559 systemJsonName = getSystemsJson(vpdMap);
1560 }
1561
1562 fs::path target = systemJsonName;
1563 fs::path link = INVENTORY_JSON_SYM_LINK;
1564
Santosh Puranikf3e69682022-03-31 17:52:38 +05301565 // If the symlink does not exist, we treat that as a factory reset
1566 processFactoryReset = !fs::exists(INVENTORY_JSON_SYM_LINK);
1567
Priyanga Ramasamy32c687f2022-01-04 23:14:03 -06001568 // Create the directory for hosting the symlink
1569 fs::create_directories(VPD_FILES_PATH);
1570 // unlink the symlink previously created (if any)
1571 remove(INVENTORY_JSON_SYM_LINK);
1572 // create a new symlink based on the system
1573 fs::create_symlink(target, link);
1574
1575 // Reloading the json
1576 ifstream inventoryJson(link);
1577 js = json::parse(inventoryJson);
1578 inventoryJson.close();
1579 }
1580
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301581 for (const auto& item : js["frus"][filePath])
1582 {
1583 const auto& objectPath = item["inventoryPath"];
1584 sdbusplus::message::object_path object(objectPath);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001585
Shantappa Teekappanavar6aa54502021-12-09 12:59:56 -06001586 vector<string> ccinList;
1587 if (item.find("ccin") != item.end())
1588 {
1589 for (const auto& cc : item["ccin"])
1590 {
1591 string ccin = cc;
1592 transform(ccin.begin(), ccin.end(), ccin.begin(), ::toupper);
1593 ccinList.push_back(ccin);
1594 }
1595 }
1596
1597 if (!ccinFromVpd.empty() && !ccinList.empty() &&
1598 (find(ccinList.begin(), ccinList.end(), ccinFromVpd) ==
1599 ccinList.end()))
1600 {
1601 continue;
1602 }
1603
Priyanga Ramasamye3fed702022-01-11 01:05:32 -06001604 if ((isSystemVpd) || (item.value("noprime", false)))
Santosh Puranikd3a379a2021-08-23 19:12:59 +05301605 {
Priyanga Ramasamye3fed702022-01-11 01:05:32 -06001606 // Populate one time properties for the system VPD and its sub-frus
1607 // and for other non-primeable frus.
Santosh Puranikd3a379a2021-08-23 19:12:59 +05301608 // For the remaining FRUs, this will get handled as a part of
1609 // priming the inventory.
1610 setOneTimeProperties(objectPath, interfaces);
1611 }
1612
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301613 // Populate the VPD keywords and the common interfaces only if we
1614 // are asked to inherit that data from the VPD, else only add the
1615 // extraInterfaces.
1616 if (item.value("inherit", true))
1617 {
Alpana Kumari58e22142020-05-05 00:22:12 -05001618 if constexpr (is_same<T, Parsed>::value)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301619 {
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301620 // Each record in the VPD becomes an interface and all
1621 // keyword within the record are properties under that
1622 // interface.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301623 for (const auto& record : vpdMap)
1624 {
1625 populateFruSpecificInterfaces(
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05001626 record.second, ipzVpdInf + record.first, interfaces);
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301627 }
1628 }
Alpana Kumari58e22142020-05-05 00:22:12 -05001629 else if constexpr (is_same<T, KeywordVpdMap>::value)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301630 {
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05001631 populateFruSpecificInterfaces(vpdMap, kwdVpdInf, interfaces);
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301632 }
Santosh Puranik88edeb62020-03-02 12:00:09 +05301633 if (js.find("commonInterfaces") != js.end())
1634 {
1635 populateInterfaces(js["commonInterfaces"], interfaces, vpdMap,
1636 isSystemVpd);
1637 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301638 }
Santosh Puranik0859eb62020-03-16 02:56:29 -05001639 else
1640 {
1641 // Check if we have been asked to inherit specific record(s)
Alpana Kumari58e22142020-05-05 00:22:12 -05001642 if constexpr (is_same<T, Parsed>::value)
Santosh Puranik0859eb62020-03-16 02:56:29 -05001643 {
1644 if (item.find("copyRecords") != item.end())
1645 {
1646 for (const auto& record : item["copyRecords"])
1647 {
1648 const string& recordName = record;
1649 if (vpdMap.find(recordName) != vpdMap.end())
1650 {
1651 populateFruSpecificInterfaces(
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05001652 vpdMap.at(recordName), ipzVpdInf + recordName,
Santosh Puranik0859eb62020-03-16 02:56:29 -05001653 interfaces);
1654 }
1655 }
1656 }
1657 }
1658 }
Santosh Puranik32c46502022-02-10 08:55:07 +05301659 // Populate interfaces and properties that are common to every FRU
1660 // and additional interface that might be defined on a per-FRU
1661 // basis.
1662 if (item.find("extraInterfaces") != item.end())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301663 {
Santosh Puranik32c46502022-02-10 08:55:07 +05301664 populateInterfaces(item["extraInterfaces"], interfaces, vpdMap,
1665 isSystemVpd);
Priyanga Ramasamy6abdeb62022-01-09 23:15:11 -06001666 if constexpr (is_same<T, Parsed>::value)
1667 {
1668 if (item["extraInterfaces"].find(
1669 "xyz.openbmc_project.Inventory.Item.Cpu") !=
1670 item["extraInterfaces"].end())
1671 {
1672 if (isCPUIOGoodOnly(getKwVal(vpdMap, "CP00", "PG")))
1673 {
Priyanga Ramasamy2c607a92022-04-08 00:30:17 -05001674 interfaces[invItemIntf]["PrettyName"] = "IO Module";
Priyanga Ramasamy6abdeb62022-01-09 23:15:11 -06001675 }
1676 }
1677 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301678 }
Priyanga Ramasamye358acb2022-03-21 14:21:50 -05001679
1680 // embedded property(true or false) says whether the subfru is embedded
1681 // into the parent fru (or) not. VPD sets Present property only for
1682 // embedded frus. If the subfru is not an embedded FRU, the subfru may
1683 // or may not be physically present. Those non embedded frus will always
1684 // have Present=false irrespective of its physical presence or absence.
1685 // Eg: nvme drive in nvme slot is not an embedded FRU. So don't set
1686 // Present to true for such sub frus.
1687 // Eg: ethernet port is embedded into bmc card. So set Present to true
1688 // for such sub frus. Also donot populate present property for embedded
1689 // subfru which is synthesized. Currently there is no subfru which are
1690 // both embedded and synthesized. But still the case is handled here.
1691 if ((item.value("embedded", true)) &&
1692 (!item.value("synthesized", false)))
1693 {
Priyanga Ramasamyaca61372023-01-24 08:02:28 -06001694 // Check if its required to handle presence for this FRU.
1695 if (item.value("handlePresence", true))
1696 {
1697 inventory::PropertyMap presProp;
1698 presProp.emplace("Present", true);
1699 insertOrMerge(interfaces, invItemIntf, move(presProp));
1700 }
Priyanga Ramasamye358acb2022-03-21 14:21:50 -05001701 }
Priyanga Ramasamyaa8a8932022-01-27 09:12:41 -06001702
Santosh Puranikf3e69682022-03-31 17:52:38 +05301703 if constexpr (is_same<T, Parsed>::value)
1704 {
1705 // Restore asset tag, if needed
1706 if (processFactoryReset && objectPath == "/system")
1707 {
1708 fillAssetTag(interfaces, vpdMap);
1709 }
1710 }
1711
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301712 objects.emplace(move(object), move(interfaces));
1713 }
1714
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301715 if (isSystemVpd)
1716 {
1717 inventory::ObjectMap primeObject = primeInventory(js, vpdMap);
1718 objects.insert(primeObject.begin(), primeObject.end());
Alpana Kumari65b83602020-09-01 00:24:56 -05001719
Alpana Kumarif05effd2021-04-07 07:32:53 -05001720 // set the U-boot environment variable for device-tree
1721 if constexpr (is_same<T, Parsed>::value)
1722 {
Santosh Puranike5f177a2022-01-24 20:14:46 +05301723 setDevTreeEnv(fs::path(getSystemsJson(vpdMap)).filename());
Alpana Kumarif05effd2021-04-07 07:32:53 -05001724 }
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301725 }
1726
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301727 // Notify PIM
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05001728 common::utility::callPIM(move(objects));
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301729}
1730
1731int main(int argc, char** argv)
1732{
1733 int rc = 0;
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001734 json js{};
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -06001735 Binary vpdVector{};
1736 string file{};
jinuthomasf457a3e2023-04-13 12:22:48 -05001737 string driver{};
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001738 // map to hold additional data in case of logging pel
1739 PelAdditionalData additionalData{};
1740
1741 // this is needed to hold base fru inventory path in case there is ECC or
1742 // vpd exception while parsing the file
1743 std::string baseFruInventoryPath = {};
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301744
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001745 // It holds the backup EEPROM file path for the system backplane's critical
1746 // data
1747 std::string systemVpdBackupPath{};
1748
1749 // It holds the inventory path of backup EEPROM file
1750 std::string backupVpdInvPath{};
1751
1752 bool isSystemVpd = false;
1753
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001754 // severity for PEL
1755 PelSeverity pelSeverity = PelSeverity::WARNING;
1756
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301757 try
1758 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001759 App app{"ibm-read-vpd - App to read IPZ/Jedec format VPD, parse it and "
1760 "store it in DBUS"};
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301761
1762 app.add_option("-f, --file", file, "File containing VPD (IPZ/KEYWORD)")
Alpana Kumari2f793042020-08-18 05:51:03 -05001763 ->required();
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301764
jinuthomasf457a3e2023-04-13 12:22:48 -05001765 app.add_option("--driver", driver,
1766 "Driver used by kernel (at24,at25,ee1004)")
1767 ->required();
1768
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301769 CLI11_PARSE(app, argc, argv);
1770
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001771 // PEL severity should be ERROR in case of any system VPD failure
1772 if (file == systemVpdFilePath)
1773 {
1774 pelSeverity = PelSeverity::ERROR;
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001775 isSystemVpd = true;
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001776 }
1777
jinuthomasf457a3e2023-04-13 12:22:48 -05001778 // Check if input file is not empty.
1779 if ((file.empty()) || (driver.empty()))
1780 {
1781 std::cerr << "Encountered empty input parameter file [" << file
1782 << "] driver [" << driver << "]" << std::endl;
1783 return 0;
1784 }
1785
1786 // Check if currently supported driver or not
1787 if ((driver != at24driver) && (driver != at25driver) &&
1788 (driver != ee1004driver))
1789 {
1790 std::cerr << "The driver [" << driver << "] is not supported."
1791 << std::endl;
1792 return 0;
1793 }
1794
Santosh Puranik0246a4d2020-11-04 16:57:39 +05301795 auto jsonToParse = INVENTORY_JSON_DEFAULT;
1796
1797 // If the symlink exists, it means it has been setup for us, switch the
1798 // path
1799 if (fs::exists(INVENTORY_JSON_SYM_LINK))
1800 {
1801 jsonToParse = INVENTORY_JSON_SYM_LINK;
1802 }
1803
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301804 // Make sure that the file path we get is for a supported EEPROM
Santosh Puranik0246a4d2020-11-04 16:57:39 +05301805 ifstream inventoryJson(jsonToParse);
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001806 if (!inventoryJson)
1807 {
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001808 throw(VpdJsonException("Failed to access Json path", jsonToParse));
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001809 }
1810
1811 try
1812 {
1813 js = json::parse(inventoryJson);
1814 }
Patrick Williams8e15b932021-10-06 13:04:22 -05001815 catch (const json::parse_error& ex)
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001816 {
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001817 throw(VpdJsonException("Json parsing failed", jsonToParse));
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001818 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301819
Santosh Puranik12e24ff2021-05-11 19:33:50 +05301820 // Do we have the mandatory "frus" section?
1821 if (js.find("frus") == js.end())
1822 {
1823 throw(VpdJsonException("FRUs section not found in JSON",
1824 jsonToParse));
1825 }
1826
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301827 // Check if it's a udev path - patterned as(/ahb/ahb:apb/ahb:apb:bus@)
1828 if (file.find("/ahb:apb") != string::npos)
1829 {
1830 // Translate udev path to a generic /sys/bus/.. file path.
jinuthomasf457a3e2023-04-13 12:22:48 -05001831 udevToGenericPath(file, driver);
Santosh Puranik12e24ff2021-05-11 19:33:50 +05301832
1833 if ((js["frus"].find(file) != js["frus"].end()) &&
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301834 (file == systemVpdFilePath))
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301835 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001836 std::cout << "We have already collected system VPD, skiping."
1837 << std::endl;
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301838 return 0;
1839 }
1840 }
1841
1842 if (file.empty())
1843 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001844 std::cerr << "The EEPROM path <" << file << "> is not valid.";
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301845 return 0;
1846 }
Santosh Puranik12e24ff2021-05-11 19:33:50 +05301847 if (js["frus"].find(file) == js["frus"].end())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301848 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001849 std::cerr << "The EEPROM path [" << file
1850 << "] is not found in the json." << std::endl;
Santosh Puranik88edeb62020-03-02 12:00:09 +05301851 return 0;
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301852 }
1853
Alpana Kumari2f793042020-08-18 05:51:03 -05001854 if (!fs::exists(file))
1855 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001856 std::cout << "Device path: " << file
1857 << " does not exist. Spurious udev event? Exiting."
1858 << std::endl;
Alpana Kumari2f793042020-08-18 05:51:03 -05001859 return 0;
1860 }
1861
Santosh Puranikdedb5a62022-12-19 23:58:32 +05301862 // In case of system VPD it will already be filled, Don't have to
1863 // overwrite that.
1864 if (baseFruInventoryPath.empty())
1865 {
1866 baseFruInventoryPath = js["frus"][file][0]["inventoryPath"];
1867 }
1868
Santosh Puranik85893752020-11-10 21:31:43 +05301869 // Check if we can read the VPD file based on the power state
Santosh Puranik27a5e952021-10-07 22:08:01 -05001870 // We skip reading VPD when the power is ON in two scenarios:
Santosh Puranik31d50fa2022-04-04 12:04:37 +05301871 // 1) The eeprom we are trying to read is that of the system VPD and the
1872 // JSON symlink is already setup (the symlink's existence tells us we
1873 // are not coming out of a factory reset)
1874 // 2) The JSON tells us that the FRU EEPROM cannot be
1875 // read when we are powered ON.
Santosh Puranik27a5e952021-10-07 22:08:01 -05001876 if (js["frus"][file].at(0).value("powerOffOnly", false) ||
Santosh Puranik31d50fa2022-04-04 12:04:37 +05301877 (file == systemVpdFilePath && fs::exists(INVENTORY_JSON_SYM_LINK)))
Santosh Puranik85893752020-11-10 21:31:43 +05301878 {
1879 if ("xyz.openbmc_project.State.Chassis.PowerState.On" ==
1880 getPowerState())
1881 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001882 std::cout << "This VPD cannot be read when power is ON"
1883 << std::endl;
Santosh Puranik85893752020-11-10 21:31:43 +05301884 return 0;
1885 }
1886 }
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001887
Santosh Puranike9c57532022-03-15 16:51:51 +05301888 // Check if this VPD should be recollected at all
1889 if (!needsRecollection(js, file))
1890 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001891 std::cout << "Skip VPD recollection for: " << file << std::endl;
Santosh Puranike9c57532022-03-15 16:51:51 +05301892 return 0;
1893 }
1894
Alpana Kumari2f793042020-08-18 05:51:03 -05001895 try
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301896 {
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001897 variant<KeywordVpdMap, Store> parseResult;
1898
1899 parseResult = parseVpdFile(file, baseFruInventoryPath, js);
1900
1901 if (isSystemVpd)
girik18bb9852022-11-16 05:48:13 -06001902 {
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001903 // Get the value of systemVpdBackupPath field from json
1904 systemVpdBackupPath = js["frus"][systemVpdFilePath].at(0).value(
1905 "systemVpdBackupPath", "");
1906
1907 if (!systemVpdBackupPath.empty())
girik18bb9852022-11-16 05:48:13 -06001908 {
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001909 backupVpdInvPath =
1910 js["frus"][systemVpdBackupPath][0]["inventoryPath"]
1911 .get_ref<const nlohmann::json::string_t&>();
girik18bb9852022-11-16 05:48:13 -06001912 }
1913 }
SunnySrivastava19849a195542020-09-07 06:04:50 -05001914
Alpana Kumari2f793042020-08-18 05:51:03 -05001915 if (auto pVal = get_if<Store>(&parseResult))
1916 {
1917 populateDbus(pVal->getVpdMap(), js, file);
1918 }
1919 else if (auto pVal = get_if<KeywordVpdMap>(&parseResult))
1920 {
1921 populateDbus(*pVal, js, file);
1922 }
Alpana Kumari2f793042020-08-18 05:51:03 -05001923 }
Patrick Williams8e15b932021-10-06 13:04:22 -05001924 catch (const exception& e)
Alpana Kumari2f793042020-08-18 05:51:03 -05001925 {
Alpana Kumari735dee92022-03-25 01:24:40 -05001926 executePostFailAction(js, file);
PriyangaRamasamya504c3e2020-12-06 12:14:52 -06001927 throw;
Alpana Kumari2f793042020-08-18 05:51:03 -05001928 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301929 }
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001930 catch (const VpdJsonException& ex)
1931 {
1932 additionalData.emplace("JSON_PATH", ex.getJsonPath());
1933 additionalData.emplace("DESCRIPTION", ex.what());
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -05001934 createPEL(additionalData, pelSeverity, errIntfForJsonFailure, nullptr);
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001935
jinuthomasf457a3e2023-04-13 12:22:48 -05001936 std::cerr << ex.what() << "\n";
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001937 rc = -1;
1938 }
1939 catch (const VpdEccException& ex)
1940 {
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001941 if (!systemVpdBackupPath.empty())
1942 {
1943 baseFruInventoryPath = backupVpdInvPath;
1944 }
1945
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001946 additionalData.emplace("DESCRIPTION", "ECC check failed");
1947 additionalData.emplace("CALLOUT_INVENTORY_PATH",
1948 INVENTORY_PATH + baseFruInventoryPath);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -05001949 createPEL(additionalData, pelSeverity, errIntfForEccCheckFail, nullptr);
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001950
1951 if (systemVpdBackupPath.empty())
1952 {
1953 dumpBadVpd(file, vpdVector);
1954 }
1955
jinuthomasf457a3e2023-04-13 12:22:48 -05001956 std::cerr << ex.what() << "\n";
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001957 rc = -1;
1958 }
1959 catch (const VpdDataException& ex)
1960 {
Kantesh Nagaradder38ee9c82023-04-07 00:58:12 -05001961 if (!systemVpdBackupPath.empty())
1962 {
1963 file = systemVpdBackupPath;
1964 baseFruInventoryPath = backupVpdInvPath;
1965 }
1966
alpana075cb3b1f2021-12-16 11:19:36 -06001967 if (isThisPcieOnPass1planar(js, file))
1968 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001969 std::cout << "Pcie_device [" << file
1970 << "]'s VPD is not valid on PASS1 planar.Ignoring.\n";
alpana075cb3b1f2021-12-16 11:19:36 -06001971 rc = 0;
1972 }
Santosh Puranik53b38ed2022-04-10 23:15:22 +05301973 else if (!(isPresent(js, file).value_or(true)))
1974 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001975 std::cout << "FRU at: " << file
1976 << " is not detected present. Ignore parser error.\n";
Santosh Puranik53b38ed2022-04-10 23:15:22 +05301977 rc = 0;
1978 }
alpana075cb3b1f2021-12-16 11:19:36 -06001979 else
1980 {
1981 string errorMsg =
1982 "VPD file is either empty or invalid. Parser failed for [";
1983 errorMsg += file;
1984 errorMsg += "], with error = " + std::string(ex.what());
1985
1986 additionalData.emplace("DESCRIPTION", errorMsg);
1987 additionalData.emplace("CALLOUT_INVENTORY_PATH",
1988 INVENTORY_PATH + baseFruInventoryPath);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -05001989 createPEL(additionalData, pelSeverity, errIntfForInvalidVPD,
1990 nullptr);
alpana075cb3b1f2021-12-16 11:19:36 -06001991
1992 rc = -1;
1993 }
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001994 }
Patrick Williams8e15b932021-10-06 13:04:22 -05001995 catch (const exception& e)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301996 {
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -06001997 dumpBadVpd(file, vpdVector);
jinuthomasf457a3e2023-04-13 12:22:48 -05001998 std::cerr << e.what() << "\n";
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301999 rc = -1;
2000 }
2001
2002 return rc;
Patrick Williamsc78d8872023-05-10 07:50:56 -05002003}