blob: 2c3e144a317e2eba5c087aa5c1189fd28008e093 [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>
alpana077ce68722021-07-25 13:23:59 -050016#include <boost/algorithm/string.hpp>
Patrick Williamsc78d8872023-05-10 07:50:56 -050017#include <gpiod.hpp>
18#include <phosphor-logging/log.hpp>
19
20#include <algorithm>
Alpana Kumari65b83602020-09-01 00:24:56 -050021#include <cstdarg>
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053022#include <exception>
PriyangaRamasamy83a1d5d2020-04-30 19:15:43 +053023#include <filesystem>
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053024#include <fstream>
25#include <iostream>
26#include <iterator>
alpana077ce68722021-07-25 13:23:59 -050027#include <regex>
Santosh Puranik253fbe92022-10-06 22:38:09 +053028#include <thread>
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053029
30using namespace std;
31using namespace openpower::vpd;
32using namespace CLI;
33using namespace vpd::keyword::parser;
PriyangaRamasamy83a1d5d2020-04-30 19:15:43 +053034using namespace openpower::vpd::constants;
35namespace fs = filesystem;
36using json = nlohmann::json;
SunnySrivastava1984e12b1812020-05-26 02:23:11 -050037using namespace openpower::vpd::parser::factory;
SunnySrivastava1984945a02d2020-05-06 01:55:41 -050038using namespace openpower::vpd::inventory;
Alpana Kumaria00936f2020-04-14 07:15:46 -050039using namespace openpower::vpd::memory::parser;
SunnySrivastava1984e12b1812020-05-26 02:23:11 -050040using namespace openpower::vpd::parser::interface;
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -050041using namespace openpower::vpd::exceptions;
Andrew Geissler280197e2020-12-08 20:51:49 -060042using namespace phosphor::logging;
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +053043
Santosh Puranik88edeb62020-03-02 12:00:09 +053044/**
Santosh Puranike9c57532022-03-15 16:51:51 +053045 * @brief Returns the BMC state
46 */
47static auto getBMCState()
48{
49 std::string bmcState;
50 try
51 {
52 auto bus = sdbusplus::bus::new_default();
53 auto properties = bus.new_method_call(
54 "xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0",
55 "org.freedesktop.DBus.Properties", "Get");
56 properties.append("xyz.openbmc_project.State.BMC");
57 properties.append("CurrentBMCState");
58 auto result = bus.call(properties);
59 std::variant<std::string> val;
60 result.read(val);
61 if (auto pVal = std::get_if<std::string>(&val))
62 {
63 bmcState = *pVal;
64 }
65 }
66 catch (const sdbusplus::exception::SdBusError& e)
67 {
68 // Ignore any error
69 std::cerr << "Failed to get BMC state: " << e.what() << "\n";
70 }
71 return bmcState;
72}
73
74/**
75 * @brief Check if the FRU is in the cache
76 *
77 * Checks if the FRU associated with the supplied D-Bus object path is already
78 * on D-Bus. This can be used to test if a VPD collection is required for this
79 * FRU. It uses the "xyz.openbmc_project.Inventory.Item, Present" property to
80 * determine the presence of a FRU in the cache.
81 *
82 * @param objectPath - The D-Bus object path without the PIM prefix.
83 * @return true if the object exists on D-Bus, false otherwise.
84 */
85static auto isFruInVpdCache(const std::string& objectPath)
86{
87 try
88 {
89 auto bus = sdbusplus::bus::new_default();
90 auto invPath = std::string{pimPath} + objectPath;
91 auto props = bus.new_method_call(
92 "xyz.openbmc_project.Inventory.Manager", invPath.c_str(),
93 "org.freedesktop.DBus.Properties", "Get");
94 props.append("xyz.openbmc_project.Inventory.Item");
95 props.append("Present");
96 auto result = bus.call(props);
97 std::variant<bool> present;
98 result.read(present);
99 if (auto pVal = std::get_if<bool>(&present))
100 {
101 return *pVal;
102 }
103 return false;
104 }
105 catch (const sdbusplus::exception::SdBusError& e)
106 {
107 std::cout << "FRU: " << objectPath << " not in D-Bus\n";
108 // Assume not present in case of an error
109 return false;
110 }
111}
112
113/**
114 * @brief Check if VPD recollection is needed for the given EEPROM
115 *
116 * Not all FRUs can be swapped at BMC ready state. This function does the
117 * following:
118 * -- Check if the FRU is marked as "pluggableAtStandby" OR
119 * "concurrentlyMaintainable". If so, return true.
120 * -- Check if we are at BMC NotReady state. If we are, then return true.
121 * -- Else check if the FRU is not present in the VPD cache (to cover for VPD
122 * force collection). If not found in the cache, return true.
123 * -- Else return false.
124 *
125 * @param js - JSON Object.
126 * @param filePath - The EEPROM file.
127 * @return true if collection should be attempted, false otherwise.
128 */
129static auto needsRecollection(const nlohmann::json& js, const string& filePath)
130{
131 if (js["frus"][filePath].at(0).value("pluggableAtStandby", false) ||
132 js["frus"][filePath].at(0).value("concurrentlyMaintainable", false))
133 {
134 return true;
135 }
136 if (getBMCState() == "xyz.openbmc_project.State.BMC.BMCState.NotReady")
137 {
138 return true;
139 }
140 if (!isFruInVpdCache(js["frus"][filePath].at(0).value("inventoryPath", "")))
141 {
142 return true;
143 }
144 return false;
145}
146
147/**
Santosh Puranik88edeb62020-03-02 12:00:09 +0530148 * @brief Expands location codes
149 */
150static auto expandLocationCode(const string& unexpanded, const Parsed& vpdMap,
151 bool isSystemVpd)
152{
153 auto expanded{unexpanded};
154 static constexpr auto SYSTEM_OBJECT = "/system/chassis/motherboard";
155 static constexpr auto VCEN_IF = "com.ibm.ipzvpd.VCEN";
156 static constexpr auto VSYS_IF = "com.ibm.ipzvpd.VSYS";
157 size_t idx = expanded.find("fcs");
158 try
159 {
160 if (idx != string::npos)
161 {
162 string fc{};
163 string se{};
164 if (isSystemVpd)
165 {
166 const auto& fcData = vpdMap.at("VCEN").at("FC");
167 const auto& seData = vpdMap.at("VCEN").at("SE");
168 fc = string(fcData.data(), fcData.size());
169 se = string(seData.data(), seData.size());
170 }
171 else
172 {
173 fc = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "FC");
174 se = readBusProperty(SYSTEM_OBJECT, VCEN_IF, "SE");
175 }
176
Alpana Kumari81671f62021-02-10 02:21:59 -0600177 // TODO: See if ND0 can be placed in the JSON
178 expanded.replace(idx, 3, fc.substr(0, 4) + ".ND0." + se);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530179 }
180 else
181 {
182 idx = expanded.find("mts");
183 if (idx != string::npos)
184 {
185 string mt{};
186 string se{};
187 if (isSystemVpd)
188 {
189 const auto& mtData = vpdMap.at("VSYS").at("TM");
190 const auto& seData = vpdMap.at("VSYS").at("SE");
191 mt = string(mtData.data(), mtData.size());
192 se = string(seData.data(), seData.size());
193 }
194 else
195 {
196 mt = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "TM");
197 se = readBusProperty(SYSTEM_OBJECT, VSYS_IF, "SE");
198 }
199
200 replace(mt.begin(), mt.end(), '-', '.');
201 expanded.replace(idx, 3, mt + "." + se);
202 }
203 }
204 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500205 catch (const exception& e)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530206 {
jinuthomasf457a3e2023-04-13 12:22:48 -0500207 std::cerr << "Failed to expand location code with exception: "
208 << e.what() << "\n";
Santosh Puranik88edeb62020-03-02 12:00:09 +0530209 }
210 return expanded;
211}
Alpana Kumari2f793042020-08-18 05:51:03 -0500212
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530213/**
214 * @brief Populate FRU specific interfaces.
215 *
216 * This is a common method which handles both
217 * ipz and keyword specific interfaces thus,
218 * reducing the code redundancy.
219 * @param[in] map - Reference to the innermost keyword-value map.
220 * @param[in] preIntrStr - Reference to the interface string.
221 * @param[out] interfaces - Reference to interface map.
222 */
223template <typename T>
224static void populateFruSpecificInterfaces(const T& map,
225 const string& preIntrStr,
226 inventory::InterfaceMap& interfaces)
227{
228 inventory::PropertyMap prop;
229
230 for (const auto& kwVal : map)
231 {
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530232 auto kw = kwVal.first;
233
234 if (kw[0] == '#')
235 {
Alpana Kumari58e22142020-05-05 00:22:12 -0500236 kw = string("PD_") + kw[1];
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530237 }
Alpana Kumari8ea3f6d2020-04-02 00:26:07 -0500238 else if (isdigit(kw[0]))
239 {
Alpana Kumari58e22142020-05-05 00:22:12 -0500240 kw = string("N_") + kw;
Alpana Kumari8ea3f6d2020-04-02 00:26:07 -0500241 }
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000242 if constexpr (is_same<T, KeywordVpdMap>::value)
243 {
jinuthomasd640f692023-03-28 04:13:23 -0500244 if (auto keywordValue = get_if<Binary>(&kwVal.second))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000245 {
jinuthomasd640f692023-03-28 04:13:23 -0500246 Binary vec((*keywordValue).begin(), (*keywordValue).end());
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000247 prop.emplace(move(kw), move(vec));
248 }
jinuthomasd640f692023-03-28 04:13:23 -0500249 else if (auto keywordValue = get_if<std::string>(&kwVal.second))
250 {
251 Binary vec((*keywordValue).begin(), (*keywordValue).end());
252 prop.emplace(move(kw), move(vec));
253 }
254 else if (auto keywordValue = get_if<size_t>(&kwVal.second))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000255 {
256 if (kw == "MemorySizeInKB")
257 {
258 inventory::PropertyMap memProp;
jinuthomasd640f692023-03-28 04:13:23 -0500259 memProp.emplace(move(kw), ((*keywordValue)));
260 interfaces.emplace(
261 "xyz.openbmc_project.Inventory.Item.Dimm",
262 move(memProp));
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000263 }
jinuthomasd640f692023-03-28 04:13:23 -0500264 else
265 {
jinuthomasf457a3e2023-04-13 12:22:48 -0500266 std::cerr << "Unknown Keyword[" << kw << "] found ";
jinuthomasd640f692023-03-28 04:13:23 -0500267 }
268 }
269 else
270 {
jinuthomasf457a3e2023-04-13 12:22:48 -0500271 std::cerr << "Unknown Variant found ";
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000272 }
273 }
274 else
275 {
276 Binary vec(kwVal.second.begin(), kwVal.second.end());
277 prop.emplace(move(kw), move(vec));
278 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530279 }
280
281 interfaces.emplace(preIntrStr, move(prop));
282}
283
284/**
285 * @brief Populate Interfaces.
286 *
287 * This method populates common and extra interfaces to dbus.
288 * @param[in] js - json object
289 * @param[out] interfaces - Reference to interface map
290 * @param[in] vpdMap - Reference to the parsed vpd map.
Santosh Puranik88edeb62020-03-02 12:00:09 +0530291 * @param[in] isSystemVpd - Denotes whether we are collecting the system VPD.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530292 */
293template <typename T>
294static void populateInterfaces(const nlohmann::json& js,
295 inventory::InterfaceMap& interfaces,
Santosh Puranik88edeb62020-03-02 12:00:09 +0530296 const T& vpdMap, bool isSystemVpd)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530297{
298 for (const auto& ifs : js.items())
299 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530300 string inf = ifs.key();
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530301 inventory::PropertyMap props;
302
303 for (const auto& itr : ifs.value().items())
304 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530305 const string& busProp = itr.key();
306
Alpana Kumari31970de2020-02-17 06:49:57 -0600307 if (itr.value().is_boolean())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530308 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530309 props.emplace(busProp, itr.value().get<bool>());
310 }
311 else if (itr.value().is_string())
312 {
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600313 if (busProp == "LocationCode" && inf == IBM_LOCATION_CODE_INF)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530314 {
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600315 std::string prop;
316 if constexpr (is_same<T, Parsed>::value)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530317 {
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000318 // TODO deprecate the com.ibm interface later
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600319 prop = expandLocationCode(itr.value().get<string>(),
320 vpdMap, isSystemVpd);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530321 }
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600322 else if constexpr (is_same<T, KeywordVpdMap>::value)
Santosh Puranik88edeb62020-03-02 12:00:09 +0530323 {
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600324 // Send empty Parsed object to expandLocationCode api.
325 prop = expandLocationCode(itr.value().get<string>(),
326 Parsed{}, false);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530327 }
Priyanga Ramasamy0d61c582022-01-21 04:38:22 -0600328 props.emplace(busProp, prop);
329 interfaces.emplace(XYZ_LOCATION_CODE_INF, props);
330 interfaces.emplace(IBM_LOCATION_CODE_INF, props);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530331 }
332 else
333 {
334 props.emplace(busProp, itr.value().get<string>());
335 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530336 }
Santosh Puraniked609af2021-06-21 11:30:07 +0530337 else if (itr.value().is_array())
338 {
339 try
340 {
341 props.emplace(busProp, itr.value().get<Binary>());
342 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500343 catch (const nlohmann::detail::type_error& e)
Santosh Puraniked609af2021-06-21 11:30:07 +0530344 {
345 std::cerr << "Type exception: " << e.what() << "\n";
346 // Ignore any type errors
347 }
348 }
Alpana Kumari31970de2020-02-17 06:49:57 -0600349 else if (itr.value().is_object())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530350 {
Alpana Kumari31970de2020-02-17 06:49:57 -0600351 const string& rec = itr.value().value("recordName", "");
352 const string& kw = itr.value().value("keywordName", "");
353 const string& encoding = itr.value().value("encoding", "");
354
Alpana Kumari58e22142020-05-05 00:22:12 -0500355 if constexpr (is_same<T, Parsed>::value)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530356 {
Santosh Puranik88edeb62020-03-02 12:00:09 +0530357 if (!rec.empty() && !kw.empty() && vpdMap.count(rec) &&
358 vpdMap.at(rec).count(kw))
Alpana Kumari31970de2020-02-17 06:49:57 -0600359 {
Patrick Williamsc78d8872023-05-10 07:50:56 -0500360 auto encoded = encodeKeyword(vpdMap.at(rec).at(kw),
361 encoding);
Santosh Puranik88edeb62020-03-02 12:00:09 +0530362 props.emplace(busProp, encoded);
Alpana Kumari31970de2020-02-17 06:49:57 -0600363 }
364 }
Alpana Kumari58e22142020-05-05 00:22:12 -0500365 else if constexpr (is_same<T, KeywordVpdMap>::value)
Alpana Kumari31970de2020-02-17 06:49:57 -0600366 {
367 if (!kw.empty() && vpdMap.count(kw))
368 {
jinuthomasd640f692023-03-28 04:13:23 -0500369 if (auto kwValue = get_if<Binary>(&vpdMap.at(kw)))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000370 {
Patrick Williamsc78d8872023-05-10 07:50:56 -0500371 auto prop = string((*kwValue).begin(),
372 (*kwValue).end());
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000373
374 auto encoded = encodeKeyword(prop, encoding);
375
376 props.emplace(busProp, encoded);
377 }
jinuthomasd640f692023-03-28 04:13:23 -0500378 else if (auto kwValue =
379 get_if<std::string>(&vpdMap.at(kw)))
380 {
Patrick Williamsc78d8872023-05-10 07:50:56 -0500381 auto prop = string((*kwValue).begin(),
382 (*kwValue).end());
jinuthomasd640f692023-03-28 04:13:23 -0500383
384 auto encoded = encodeKeyword(prop, encoding);
385
386 props.emplace(busProp, encoded);
387 }
388 else if (auto uintValue =
389 get_if<size_t>(&vpdMap.at(kw)))
Alpana Kumari3ab26a72021-04-05 19:09:19 +0000390 {
391 props.emplace(busProp, *uintValue);
392 }
jinuthomasd640f692023-03-28 04:13:23 -0500393 else
394 {
395 std::cerr << " Unknown Keyword [" << kw
396 << "] Encountered";
397 }
Alpana Kumari31970de2020-02-17 06:49:57 -0600398 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530399 }
400 }
Matt Spinlerb1e64bb2021-09-08 09:57:48 -0500401 else if (itr.value().is_number())
402 {
403 // For now assume the value is a size_t. In the future it would
404 // be nice to come up with a way to get the type from the JSON.
405 props.emplace(busProp, itr.value().get<size_t>());
406 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530407 }
Priyanga Ramasamyaa8a8932022-01-27 09:12:41 -0600408 insertOrMerge(interfaces, inf, move(props));
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530409 }
410}
411
alpana075cb3b1f2021-12-16 11:19:36 -0600412/**
413 * @brief This API checks if this FRU is pcie_devices. If yes then it further
414 * checks whether it is PASS1 planar.
415 */
416static bool isThisPcieOnPass1planar(const nlohmann::json& js,
417 const string& file)
418{
419 auto isThisPCIeDev = false;
420 auto isPASS1 = false;
421
422 // Check if it is a PCIE device
423 if (js["frus"].find(file) != js["frus"].end())
424 {
Santosh Puranikc03f3902022-04-14 10:58:26 +0530425 if ((js["frus"][file].at(0).find("extraInterfaces") !=
426 js["frus"][file].at(0).end()))
alpana075cb3b1f2021-12-16 11:19:36 -0600427 {
Santosh Puranikc03f3902022-04-14 10:58:26 +0530428 if (js["frus"][file].at(0)["extraInterfaces"].find(
alpana075cb3b1f2021-12-16 11:19:36 -0600429 "xyz.openbmc_project.Inventory.Item.PCIeDevice") !=
Santosh Puranikc03f3902022-04-14 10:58:26 +0530430 js["frus"][file].at(0)["extraInterfaces"].end())
alpana075cb3b1f2021-12-16 11:19:36 -0600431 {
432 isThisPCIeDev = true;
433 }
434 }
435 }
436
437 if (isThisPCIeDev)
438 {
Alpana Kumaria6181e22022-05-12 05:01:53 -0500439 // Collect HW version and SystemType to know if it is PASS1 planar.
alpana075cb3b1f2021-12-16 11:19:36 -0600440 auto bus = sdbusplus::bus::new_default();
Alpana Kumaria6181e22022-05-12 05:01:53 -0500441 auto property1 = bus.new_method_call(
alpana075cb3b1f2021-12-16 11:19:36 -0600442 INVENTORY_MANAGER_SERVICE,
443 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
444 "org.freedesktop.DBus.Properties", "Get");
Alpana Kumaria6181e22022-05-12 05:01:53 -0500445 property1.append("com.ibm.ipzvpd.VINI");
446 property1.append("HW");
447 auto result1 = bus.call(property1);
448 inventory::Value hwVal;
449 result1.read(hwVal);
alpana075cb3b1f2021-12-16 11:19:36 -0600450
Alpana Kumaria6181e22022-05-12 05:01:53 -0500451 // SystemType
452 auto property2 = bus.new_method_call(
453 INVENTORY_MANAGER_SERVICE,
454 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
455 "org.freedesktop.DBus.Properties", "Get");
456 property2.append("com.ibm.ipzvpd.VSBP");
457 property2.append("IM");
458 auto result2 = bus.call(property2);
459 inventory::Value imVal;
460 result2.read(imVal);
461
462 auto pVal1 = get_if<Binary>(&hwVal);
463 auto pVal2 = get_if<Binary>(&imVal);
464
465 if (pVal1 && pVal2)
alpana075cb3b1f2021-12-16 11:19:36 -0600466 {
Alpana Kumaria6181e22022-05-12 05:01:53 -0500467 auto hwVersion = *pVal1;
468 auto systemType = *pVal2;
469
470 // IM kw for Everest
471 Binary everestSystem{80, 00, 48, 00};
472
473 if (systemType == everestSystem)
474 {
475 if (hwVersion[1] < 21)
476 {
477 isPASS1 = true;
478 }
479 }
480 else if (hwVersion[1] < 2)
481 {
alpana075cb3b1f2021-12-16 11:19:36 -0600482 isPASS1 = true;
Alpana Kumaria6181e22022-05-12 05:01:53 -0500483 }
alpana075cb3b1f2021-12-16 11:19:36 -0600484 }
485 }
486
487 return (isThisPCIeDev && isPASS1);
488}
489
Alpana Kumari735dee92022-03-25 01:24:40 -0500490/** Performs any pre-action needed to get the FRU setup for collection.
Alpana Kumari2f793042020-08-18 05:51:03 -0500491 *
492 * @param[in] json - json object
493 * @param[in] file - eeprom file path
494 */
495static void preAction(const nlohmann::json& json, const string& file)
496{
Alpana Kumari735dee92022-03-25 01:24:40 -0500497 if ((json["frus"][file].at(0)).find("preAction") ==
Alpana Kumari2f793042020-08-18 05:51:03 -0500498 json["frus"][file].at(0).end())
499 {
Alpana Kumari735dee92022-03-25 01:24:40 -0500500 return;
Alpana Kumari2f793042020-08-18 05:51:03 -0500501 }
502
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500503 try
Alpana Kumari2f793042020-08-18 05:51:03 -0500504 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500505 if (executePreAction(json, file))
Alpana Kumari2f793042020-08-18 05:51:03 -0500506 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500507 if (json["frus"][file].at(0).find("devAddress") !=
508 json["frus"][file].at(0).end())
Alpana Kumari40d1c192022-03-09 21:16:02 -0600509 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500510 // Now bind the device
511 string bind = json["frus"][file].at(0).value("devAddress", "");
jinuthomasf457a3e2023-04-13 12:22:48 -0500512 std::cout << "Binding device " << bind << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500513 string bindCmd = string("echo \"") + bind +
514 string("\" > /sys/bus/i2c/drivers/at24/bind");
jinuthomasf457a3e2023-04-13 12:22:48 -0500515 std::cout << bindCmd << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500516 executeCmd(bindCmd);
517
518 // Check if device showed up (test for file)
519 if (!fs::exists(file))
520 {
jinuthomasf457a3e2023-04-13 12:22:48 -0500521 std::cerr << "EEPROM " << file
522 << " does not exist. Take failure action"
523 << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500524 // If not, then take failure postAction
525 executePostFailAction(json, file);
526 }
527 }
528 else
529 {
530 // missing required informations
jinuthomasf457a3e2023-04-13 12:22:48 -0500531 std::cerr << "VPD inventory JSON missing basic informations of "
532 "preAction "
533 "for this FRU : ["
534 << file << "]. Executing executePostFailAction."
535 << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500536
537 // Take failure postAction
Alpana Kumari40d1c192022-03-09 21:16:02 -0600538 executePostFailAction(json, file);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500539 return;
Alpana Kumari40d1c192022-03-09 21:16:02 -0600540 }
541 }
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530542 else
543 {
544 // If the FRU is not there, clear the VINI/CCIN data.
545 // Enity manager probes for this keyword to look for this
546 // FRU, now if the data is persistent on BMC and FRU is
547 // removed this can lead to ambiguity. Hence clearing this
548 // Keyword if FRU is absent.
549 const auto& invPath =
550 json["frus"][file].at(0).value("inventoryPath", "");
551
552 if (!invPath.empty())
553 {
554 inventory::ObjectMap pimObjMap{
555 {invPath, {{"com.ibm.ipzvpd.VINI", {{"CC", Binary{}}}}}}};
556
557 common::utility::callPIM(move(pimObjMap));
558 }
559 else
560 {
561 throw std::runtime_error("Path empty in Json");
562 }
563 }
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500564 }
565 catch (const GpioException& e)
566 {
567 PelAdditionalData additionalData{};
568 additionalData.emplace("DESCRIPTION", e.what());
569 createPEL(additionalData, PelSeverity::WARNING, errIntfForGpioError,
570 nullptr);
Alpana Kumari2f793042020-08-18 05:51:03 -0500571 }
Alpana Kumari2f793042020-08-18 05:51:03 -0500572}
573
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530574/**
Santosh Puranikf3e69682022-03-31 17:52:38 +0530575 * @brief Fills the Decorator.AssetTag property into the interfaces map
576 *
577 * This function should only be called in cases where we did not find a JSON
578 * symlink. A missing symlink in /var/lib will be considered as a factory reset
579 * and this function will be used to default the AssetTag property.
580 *
581 * @param interfaces A possibly pre-populated map of inetrfaces to properties.
582 * @param vpdMap A VPD map of the system VPD data.
583 */
584static void fillAssetTag(inventory::InterfaceMap& interfaces,
585 const Parsed& vpdMap)
586{
587 // Read the system serial number and MTM
588 // Default asset tag is Server-MTM-System Serial
589 inventory::Interface assetIntf{
590 "xyz.openbmc_project.Inventory.Decorator.AssetTag"};
591 inventory::PropertyMap assetTagProps;
592 std::string defaultAssetTag =
593 std::string{"Server-"} + getKwVal(vpdMap, "VSYS", "TM") +
594 std::string{"-"} + getKwVal(vpdMap, "VSYS", "SE");
595 assetTagProps.emplace("AssetTag", defaultAssetTag);
596 insertOrMerge(interfaces, assetIntf, std::move(assetTagProps));
597}
598
599/**
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530600 * @brief Set certain one time properties in the inventory
601 * Use this function to insert the Functional and Enabled properties into the
602 * inventory map. This function first checks if the object in question already
603 * has these properties hosted on D-Bus, if the property is already there, it is
604 * not modified, hence the name "one time". If the property is not already
605 * present, it will be added to the map with a suitable default value (true for
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530606 * Functional and Enabled)
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530607 *
608 * @param[in] object - The inventory D-Bus obejct without the inventory prefix.
609 * @param[inout] interfaces - Reference to a map of inventory interfaces to
610 * which the properties will be attached.
611 */
612static void setOneTimeProperties(const std::string& object,
613 inventory::InterfaceMap& interfaces)
614{
615 auto bus = sdbusplus::bus::new_default();
616 auto objectPath = INVENTORY_PATH + object;
617 auto prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager",
618 objectPath.c_str(),
619 "org.freedesktop.DBus.Properties", "Get");
620 prop.append("xyz.openbmc_project.State.Decorator.OperationalStatus");
621 prop.append("Functional");
622 try
623 {
624 auto result = bus.call(prop);
625 }
626 catch (const sdbusplus::exception::SdBusError& e)
627 {
628 // Treat as property unavailable
629 inventory::PropertyMap prop;
630 prop.emplace("Functional", true);
631 interfaces.emplace(
632 "xyz.openbmc_project.State.Decorator.OperationalStatus",
633 move(prop));
634 }
635 prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager",
636 objectPath.c_str(),
637 "org.freedesktop.DBus.Properties", "Get");
638 prop.append("xyz.openbmc_project.Object.Enable");
639 prop.append("Enabled");
640 try
641 {
642 auto result = bus.call(prop);
643 }
644 catch (const sdbusplus::exception::SdBusError& e)
645 {
646 // Treat as property unavailable
647 inventory::PropertyMap prop;
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530648 prop.emplace("Enabled", true);
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530649 interfaces.emplace("xyz.openbmc_project.Object.Enable", move(prop));
650 }
651}
652
653/**
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530654 * @brief Prime the Inventory
655 * Prime the inventory by populating only the location code,
656 * type interface and the inventory object for the frus
657 * which are not system vpd fru.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +0530658 *
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530659 * @param[in] jsObject - Reference to vpd inventory json object
660 * @param[in] vpdMap - Reference to the parsed vpd map
661 *
662 * @returns Map of items in extraInterface.
663 */
664template <typename T>
665inventory::ObjectMap primeInventory(const nlohmann::json& jsObject,
666 const T& vpdMap)
667{
668 inventory::ObjectMap objects;
669
670 for (auto& itemFRUS : jsObject["frus"].items())
671 {
672 for (auto& itemEEPROM : itemFRUS.value())
673 {
Alpana Kumari2e6c6f72020-12-03 00:10:03 -0600674 // Take pre actions if needed
675 if (itemEEPROM.find("preAction") != itemEEPROM.end())
676 {
677 preAction(jsObject, itemFRUS.key());
678 }
679
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530680 inventory::InterfaceMap interfaces;
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530681 inventory::Object object(itemEEPROM.at("inventoryPath"));
682
Santosh Puranik50f60bf2021-05-26 17:55:06 +0530683 if ((itemFRUS.key() != systemVpdFilePath) &&
684 !itemEEPROM.value("noprime", false))
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530685 {
Alpana Kumaricfd7a752021-02-07 23:23:01 -0600686 inventory::PropertyMap presProp;
Priyanga Ramasamye358acb2022-03-21 14:21:50 -0500687
688 // Do not populate Present property for frus whose
Priyanga Ramasamyaca61372023-01-24 08:02:28 -0600689 // synthesized=true. synthesized=true says the fru VPD is
690 // synthesized and owned by a separate component.
691 // In some cases, the FRU has its own VPD, but still a separate
692 // application handles the FRU's presence. So VPD parser skips
693 // populating Present property by checking the JSON flag,
694 // "handlePresence".
Priyanga Ramasamye358acb2022-03-21 14:21:50 -0500695 if (!itemEEPROM.value("synthesized", false))
696 {
Priyanga Ramasamyaca61372023-01-24 08:02:28 -0600697 if (itemEEPROM.value("handlePresence", true))
698 {
699 presProp.emplace("Present", false);
700 interfaces.emplace("xyz.openbmc_project.Inventory.Item",
701 presProp);
702 }
Priyanga Ramasamye358acb2022-03-21 14:21:50 -0500703 }
Priyanga Ramasamyaca61372023-01-24 08:02:28 -0600704
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530705 setOneTimeProperties(object, interfaces);
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530706 if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end())
707 {
708 for (const auto& eI : itemEEPROM["extraInterfaces"].items())
709 {
710 inventory::PropertyMap props;
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000711 if (eI.key() == IBM_LOCATION_CODE_INF)
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530712 {
713 if constexpr (std::is_same<T, Parsed>::value)
714 {
715 for (auto& lC : eI.value().items())
716 {
717 auto propVal = expandLocationCode(
718 lC.value().get<string>(), vpdMap, true);
719
720 props.emplace(move(lC.key()),
721 move(propVal));
Santosh Puranikb0f37492021-06-21 09:42:47 +0530722 interfaces.emplace(XYZ_LOCATION_CODE_INF,
723 props);
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530724 interfaces.emplace(move(eI.key()),
725 move(props));
726 }
727 }
728 }
729 else if (eI.key().find("Inventory.Item.") !=
730 string::npos)
731 {
732 interfaces.emplace(move(eI.key()), move(props));
733 }
Santosh Puranikd3a379a2021-08-23 19:12:59 +0530734 else if (eI.key() ==
735 "xyz.openbmc_project.Inventory.Item")
736 {
737 for (auto& val : eI.value().items())
738 {
739 if (val.key() == "PrettyName")
740 {
741 presProp.emplace(val.key(),
742 val.value().get<string>());
743 }
744 }
745 // Use insert_or_assign here as we may already have
746 // inserted the present property only earlier in
747 // this function under this same interface.
748 interfaces.insert_or_assign(eI.key(),
749 move(presProp));
750 }
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530751 }
752 }
753 objects.emplace(move(object), move(interfaces));
754 }
755 }
756 }
757 return objects;
758}
759
Alpana Kumari65b83602020-09-01 00:24:56 -0500760/**
761 * @brief This API executes command to set environment variable
762 * And then reboot the system
763 * @param[in] key -env key to set new value
764 * @param[in] value -value to set.
765 */
766void setEnvAndReboot(const string& key, const string& value)
767{
768 // set env and reboot and break.
769 executeCmd("/sbin/fw_setenv", key, value);
Andrew Geissler280197e2020-12-08 20:51:49 -0600770 log<level::INFO>("Rebooting BMC to pick up new device tree");
Alpana Kumari65b83602020-09-01 00:24:56 -0500771 // make dbus call to reboot
772 auto bus = sdbusplus::bus::new_default_system();
773 auto method = bus.new_method_call(
774 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
775 "org.freedesktop.systemd1.Manager", "Reboot");
776 bus.call_noreply(method);
777}
778
779/*
780 * @brief This API checks for env var fitconfig.
781 * If not initialised OR updated as per the current system type,
782 * update this env var and reboot the system.
783 *
784 * @param[in] systemType IM kwd in vpd tells about which system type it is.
785 * */
786void setDevTreeEnv(const string& systemType)
787{
Alpana Kumari37e72702021-11-18 11:18:04 -0600788 // Init with default dtb
789 string newDeviceTree = "conf-aspeed-bmc-ibm-rainier-p1.dtb";
Santosh Puranike5f177a2022-01-24 20:14:46 +0530790 static const deviceTreeMap deviceTreeSystemTypeMap = {
791 {RAINIER_2U, "conf-aspeed-bmc-ibm-rainier-p1.dtb"},
792 {RAINIER_2U_V2, "conf-aspeed-bmc-ibm-rainier.dtb"},
793 {RAINIER_4U, "conf-aspeed-bmc-ibm-rainier-4u-p1.dtb"},
794 {RAINIER_4U_V2, "conf-aspeed-bmc-ibm-rainier-4u.dtb"},
795 {RAINIER_1S4U, "conf-aspeed-bmc-ibm-rainier-1s4u.dtb"},
Alpana Kumari1b026112022-03-02 23:41:38 -0600796 {EVEREST, "conf-aspeed-bmc-ibm-everest.dtb"},
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530797 {EVEREST_V2, "conf-aspeed-bmc-ibm-everest.dtb"},
798 {BONNELL, "conf-aspeed-bmc-ibm-bonnell.dtb"}};
Alpana Kumari65b83602020-09-01 00:24:56 -0500799
800 if (deviceTreeSystemTypeMap.find(systemType) !=
801 deviceTreeSystemTypeMap.end())
802 {
803 newDeviceTree = deviceTreeSystemTypeMap.at(systemType);
804 }
Alpana Kumari37e72702021-11-18 11:18:04 -0600805 else
806 {
807 // System type not supported
Alpana Kumariab1e22c2021-11-24 11:03:38 -0600808 string err = "This System type not found/supported in dtb table " +
809 systemType +
810 ".Please check the HW and IM keywords in the system "
811 "VPD.Breaking...";
812
813 // map to hold additional data in case of logging pel
814 PelAdditionalData additionalData{};
815 additionalData.emplace("DESCRIPTION", err);
816 createPEL(additionalData, PelSeverity::WARNING,
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500817 errIntfForInvalidSystemType, nullptr);
Alpana Kumariab1e22c2021-11-24 11:03:38 -0600818 exit(-1);
Alpana Kumari37e72702021-11-18 11:18:04 -0600819 }
Alpana Kumari65b83602020-09-01 00:24:56 -0500820
821 string readVarValue;
822 bool envVarFound = false;
823
824 vector<string> output = executeCmd("/sbin/fw_printenv");
825 for (const auto& entry : output)
826 {
827 size_t pos = entry.find("=");
828 string key = entry.substr(0, pos);
829 if (key != "fitconfig")
830 {
831 continue;
832 }
833
834 envVarFound = true;
835 if (pos + 1 < entry.size())
836 {
837 readVarValue = entry.substr(pos + 1);
838 if (readVarValue.find(newDeviceTree) != string::npos)
839 {
840 // fitconfig is Updated. No action needed
841 break;
842 }
843 }
844 // set env and reboot and break.
845 setEnvAndReboot(key, newDeviceTree);
846 exit(0);
847 }
848
849 // check If env var Not found
850 if (!envVarFound)
851 {
852 setEnvAndReboot("fitconfig", newDeviceTree);
853 }
854}
855
PriyangaRamasamy8e140a12020-04-13 19:24:03 +0530856/**
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500857 * @brief API to check if we need to restore system VPD
858 * This functionality is only applicable for IPZ VPD data.
859 * @param[in] vpdMap - IPZ vpd map
860 * @param[in] objectPath - Object path for the FRU
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500861 */
Sunny Srivastava3c244142022-01-11 08:47:04 -0600862void restoreSystemVPD(Parsed& vpdMap, const string& objectPath)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500863{
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500864 for (const auto& systemRecKwdPair : svpdKwdMap)
865 {
866 auto it = vpdMap.find(systemRecKwdPair.first);
867
868 // check if record is found in map we got by parser
869 if (it != vpdMap.end())
870 {
871 const auto& kwdListForRecord = systemRecKwdPair.second;
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600872 for (const auto& keywordInfo : kwdListForRecord)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500873 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600874 const auto keyword = get<0>(keywordInfo);
875
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500876 DbusPropertyMap& kwdValMap = it->second;
877 auto iterator = kwdValMap.find(keyword);
878
879 if (iterator != kwdValMap.end())
880 {
881 string& kwdValue = iterator->second;
882
883 // check bus data
884 const string& recordName = systemRecKwdPair.first;
885 const string& busValue = readBusProperty(
886 objectPath, ipzVpdInf + recordName, keyword);
887
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600888 const auto& defaultValue = get<1>(keywordInfo);
889 Binary busDataInBinary(busValue.begin(), busValue.end());
890 Binary kwdDataInBinary(kwdValue.begin(), kwdValue.end());
Sunny Srivastavaa559c2d2022-05-02 11:56:45 -0500891
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600892 if (busDataInBinary != defaultValue)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500893 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600894 if (kwdDataInBinary != defaultValue)
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500895 {
896 // both the data are present, check for mismatch
897 if (busValue != kwdValue)
898 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600899 string errMsg = "Mismatch found between backup "
900 "and primary VPD for record: ";
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500901 errMsg += (*it).first;
902 errMsg += " and keyword: ";
903 errMsg += keyword;
904
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530905 std::ostringstream busStream;
906 for (uint16_t byte : busValue)
907 {
908 busStream << std::setfill('0')
909 << std::setw(2) << std::hex
910 << "0x" << byte << " ";
911 }
912
913 std::ostringstream vpdStream;
914 for (uint16_t byte : kwdValue)
915 {
916 vpdStream << std::setfill('0')
917 << std::setw(2) << std::hex
918 << "0x" << byte << " ";
919 }
920
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500921 // data mismatch
922 PelAdditionalData additionalData;
923 additionalData.emplace("CALLOUT_INVENTORY_PATH",
Priyanga Ramasamyf6123682022-12-02 07:29:07 -0600924 INVENTORY_PATH +
925 objectPath);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500926
927 additionalData.emplace("DESCRIPTION", errMsg);
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530928 additionalData.emplace(
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600929 "Value read from Backup: ",
930 busStream.str());
931 additionalData.emplace(
932 "Value read from Primary: ",
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530933 vpdStream.str());
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500934
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500935 createPEL(additionalData, PelSeverity::WARNING,
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600936 errIntfForVPDMismatch, nullptr);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500937 }
938 }
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500939
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600940 // If backup data is not default, then irrespective of
941 // primary data(default or other than backup), copy the
942 // backup data to vpd map as we don't need to change the
943 // backup data in either case in the process of
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530944 // restoring system vpd.
Santosh Puranikdedb5a62022-12-19 23:58:32 +0530945 kwdValue = busValue;
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500946 }
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600947 else if (kwdDataInBinary == defaultValue &&
948 get<2>(keywordInfo)) // Check isPELRequired is true
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500949 {
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600950 string errMsg = "Found default value on both backup "
951 "and primary VPD for record: ";
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500952 errMsg += (*it).first;
953 errMsg += " and keyword: ";
954 errMsg += keyword;
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600955 errMsg += ". SSR need to update primary VPD.";
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500956
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600957 // mfg default on both backup and primary, log PEL
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500958 PelAdditionalData additionalData;
959 additionalData.emplace("CALLOUT_INVENTORY_PATH",
Priyanga Ramasamyf6123682022-12-02 07:29:07 -0600960 INVENTORY_PATH + objectPath);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500961
962 additionalData.emplace("DESCRIPTION", errMsg);
963
964 // log PEL TODO: Block IPL
Sunny Srivastava0746eee2021-03-22 13:36:54 -0500965 createPEL(additionalData, PelSeverity::ERROR,
Priyanga Ramasamy24942232023-01-05 04:54:59 -0600966 errIntfForVPDDefault, nullptr);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500967 continue;
968 }
969 }
970 }
971 }
972 }
SunnySrivastava19849094d4f2020-08-05 09:32:29 -0500973}
974
975/**
alpana077ce68722021-07-25 13:23:59 -0500976 * @brief This checks for is this FRU a processor
977 * And if yes, then checks for is this primary
978 *
979 * @param[in] js- vpd json to get the information about this FRU
980 * @param[in] filePath- FRU vpd
981 *
982 * @return true/false
983 */
984bool isThisPrimaryProcessor(nlohmann::json& js, const string& filePath)
985{
986 bool isProcessor = false;
987 bool isPrimary = false;
988
989 for (const auto& item : js["frus"][filePath])
990 {
991 if (item.find("extraInterfaces") != item.end())
992 {
993 for (const auto& eI : item["extraInterfaces"].items())
994 {
995 if (eI.key().find("Inventory.Item.Cpu") != string::npos)
996 {
997 isProcessor = true;
998 }
999 }
1000 }
1001
1002 if (isProcessor)
1003 {
1004 string cpuType = item.value("cpuType", "");
1005 if (cpuType == "primary")
1006 {
1007 isPrimary = true;
1008 }
1009 }
1010 }
1011
1012 return (isProcessor && isPrimary);
1013}
1014
1015/**
1016 * @brief This finds DIMM vpd in vpd json and enables them by binding the device
1017 * driver
1018 * @param[in] js- vpd json to iterate through and take action if it is DIMM
1019 */
1020void doEnableAllDimms(nlohmann::json& js)
1021{
1022 // iterate over each fru
1023 for (const auto& eachFru : js["frus"].items())
1024 {
1025 // skip the driver binding if eeprom already exists
1026 if (fs::exists(eachFru.key()))
1027 {
1028 continue;
1029 }
1030
1031 for (const auto& eachInventory : eachFru.value())
1032 {
1033 if (eachInventory.find("extraInterfaces") != eachInventory.end())
1034 {
1035 for (const auto& eI : eachInventory["extraInterfaces"].items())
1036 {
1037 if (eI.key().find("Inventory.Item.Dimm") != string::npos)
1038 {
1039 string dimmVpd = eachFru.key();
1040 // fetch it from
1041 // "/sys/bus/i2c/drivers/at24/414-0050/eeprom"
1042
1043 regex matchPatern("([0-9]+-[0-9]{4})");
1044 smatch matchFound;
1045 if (regex_search(dimmVpd, matchFound, matchPatern))
1046 {
1047 vector<string> i2cReg;
1048 boost::split(i2cReg, matchFound.str(0),
1049 boost::is_any_of("-"));
1050
1051 // remove 0s from begining
1052 const regex pattern("^0+(?!$)");
1053 for (auto& i : i2cReg)
1054 {
1055 i = regex_replace(i, pattern, "");
1056 }
1057
1058 if (i2cReg.size() == 2)
1059 {
1060 // echo 24c32 0x50 >
1061 // /sys/bus/i2c/devices/i2c-16/new_device
1062 string cmnd = "echo 24c32 0x" + i2cReg[1] +
1063 " > /sys/bus/i2c/devices/i2c-" +
1064 i2cReg[0] + "/new_device";
1065
1066 executeCmd(cmnd);
1067 }
1068 }
1069 }
1070 }
1071 }
1072 }
1073 }
1074}
1075
1076/**
Priyanga Ramasamy6abdeb62022-01-09 23:15:11 -06001077 * @brief Check if the given CPU is an IO only chip.
1078 * The CPU is termed as IO, whose all of the cores are bad and can never be
1079 * used. Those CPU chips can be used for IO purpose like connecting PCIe devices
1080 * etc., The CPU whose every cores are bad, can be identified from the CP00
1081 * record's PG keyword, only if all of the 8 EQs' value equals 0xE7F9FF. (1EQ
1082 * has 4 cores grouped together by sharing its cache memory.)
1083 * @param [in] pgKeyword - PG Keyword of CPU.
1084 * @return true if the given cpu is an IO, false otherwise.
1085 */
1086static bool isCPUIOGoodOnly(const string& pgKeyword)
1087{
1088 const unsigned char io[] = {0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9,
1089 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7,
1090 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF};
1091 // EQ0 index (in PG keyword) starts at 97 (with offset starting from 0).
1092 // Each EQ carries 3 bytes of data. Totally there are 8 EQs. If all EQs'
1093 // value equals 0xE7F9FF, then the cpu has no good cores and its treated as
1094 // IO.
1095 if (memcmp(io, pgKeyword.data() + 97, 24) == 0)
1096 {
1097 return true;
1098 }
1099
1100 // The CPU is not an IO
1101 return false;
1102}
1103
1104/**
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301105 * @brief Populate Dbus.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301106 * This method invokes all the populateInterface functions
1107 * and notifies PIM about dbus object.
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301108 * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the
1109 * input.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301110 * @param[in] js - Inventory json object
1111 * @param[in] filePath - Path of the vpd file
1112 * @param[in] preIntrStr - Interface string
1113 */
1114template <typename T>
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001115static void populateDbus(T& vpdMap, nlohmann::json& js, const string& filePath)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301116{
1117 inventory::InterfaceMap interfaces;
1118 inventory::ObjectMap objects;
1119 inventory::PropertyMap prop;
Shantappa Teekappanavar6aa54502021-12-09 12:59:56 -06001120 string ccinFromVpd;
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301121
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301122 bool isSystemVpd = (filePath == systemVpdFilePath);
1123 if constexpr (is_same<T, Parsed>::value)
1124 {
Shantappa Teekappanavar6aa54502021-12-09 12:59:56 -06001125 ccinFromVpd = getKwVal(vpdMap, "VINI", "CC");
1126 transform(ccinFromVpd.begin(), ccinFromVpd.end(), ccinFromVpd.begin(),
1127 ::toupper);
1128
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301129 if (isSystemVpd)
1130 {
1131 std::vector<std::string> interfaces = {motherBoardInterface};
1132 // call mapper to check for object path creation
Patrick Williamsc78d8872023-05-10 07:50:56 -05001133 MapperResponse subTree = getObjectSubtreeForInterfaces(pimPath, 0,
1134 interfaces);
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301135 string mboardPath =
1136 js["frus"][filePath].at(0).value("inventoryPath", "");
1137
1138 // Attempt system VPD restore if we have a motherboard
1139 // object in the inventory.
1140 if ((subTree.size() != 0) &&
1141 (subTree.find(pimPath + mboardPath) != subTree.end()))
1142 {
Sunny Srivastava3c244142022-01-11 08:47:04 -06001143 restoreSystemVPD(vpdMap, mboardPath);
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301144 }
1145 else
1146 {
1147 log<level::ERR>("No object path found");
1148 }
1149 }
alpana077ce68722021-07-25 13:23:59 -05001150 else
1151 {
1152 // check if it is processor vpd.
1153 auto isPrimaryCpu = isThisPrimaryProcessor(js, filePath);
1154
1155 if (isPrimaryCpu)
1156 {
1157 auto ddVersion = getKwVal(vpdMap, "CRP0", "DD");
1158
1159 auto chipVersion = atoi(ddVersion.substr(1, 2).c_str());
1160
1161 if (chipVersion >= 2)
1162 {
1163 doEnableAllDimms(js);
Santosh Puranik253fbe92022-10-06 22:38:09 +05301164 // Sleep for a few seconds to let the DIMM parses start
1165 using namespace std::chrono_literals;
1166 std::this_thread::sleep_for(5s);
alpana077ce68722021-07-25 13:23:59 -05001167 }
1168 }
1169 }
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301170 }
1171
Santosh Puranikf3e69682022-03-31 17:52:38 +05301172 auto processFactoryReset = false;
1173
Priyanga Ramasamy32c687f2022-01-04 23:14:03 -06001174 if (isSystemVpd)
1175 {
1176 string systemJsonName{};
1177 if constexpr (is_same<T, Parsed>::value)
1178 {
1179 // pick the right system json
1180 systemJsonName = getSystemsJson(vpdMap);
1181 }
1182
1183 fs::path target = systemJsonName;
1184 fs::path link = INVENTORY_JSON_SYM_LINK;
1185
Santosh Puranikf3e69682022-03-31 17:52:38 +05301186 // If the symlink does not exist, we treat that as a factory reset
1187 processFactoryReset = !fs::exists(INVENTORY_JSON_SYM_LINK);
1188
Priyanga Ramasamy32c687f2022-01-04 23:14:03 -06001189 // Create the directory for hosting the symlink
1190 fs::create_directories(VPD_FILES_PATH);
1191 // unlink the symlink previously created (if any)
1192 remove(INVENTORY_JSON_SYM_LINK);
1193 // create a new symlink based on the system
1194 fs::create_symlink(target, link);
1195
1196 // Reloading the json
1197 ifstream inventoryJson(link);
1198 js = json::parse(inventoryJson);
1199 inventoryJson.close();
1200 }
1201
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301202 for (const auto& item : js["frus"][filePath])
1203 {
1204 const auto& objectPath = item["inventoryPath"];
1205 sdbusplus::message::object_path object(objectPath);
SunnySrivastava19849094d4f2020-08-05 09:32:29 -05001206
Shantappa Teekappanavar6aa54502021-12-09 12:59:56 -06001207 vector<string> ccinList;
1208 if (item.find("ccin") != item.end())
1209 {
1210 for (const auto& cc : item["ccin"])
1211 {
1212 string ccin = cc;
1213 transform(ccin.begin(), ccin.end(), ccin.begin(), ::toupper);
1214 ccinList.push_back(ccin);
1215 }
1216 }
1217
1218 if (!ccinFromVpd.empty() && !ccinList.empty() &&
1219 (find(ccinList.begin(), ccinList.end(), ccinFromVpd) ==
1220 ccinList.end()))
1221 {
1222 continue;
1223 }
1224
Priyanga Ramasamye3fed702022-01-11 01:05:32 -06001225 if ((isSystemVpd) || (item.value("noprime", false)))
Santosh Puranikd3a379a2021-08-23 19:12:59 +05301226 {
Priyanga Ramasamye3fed702022-01-11 01:05:32 -06001227 // Populate one time properties for the system VPD and its sub-frus
1228 // and for other non-primeable frus.
Santosh Puranikd3a379a2021-08-23 19:12:59 +05301229 // For the remaining FRUs, this will get handled as a part of
1230 // priming the inventory.
1231 setOneTimeProperties(objectPath, interfaces);
1232 }
1233
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301234 // Populate the VPD keywords and the common interfaces only if we
1235 // are asked to inherit that data from the VPD, else only add the
1236 // extraInterfaces.
1237 if (item.value("inherit", true))
1238 {
Alpana Kumari58e22142020-05-05 00:22:12 -05001239 if constexpr (is_same<T, Parsed>::value)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301240 {
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301241 // Each record in the VPD becomes an interface and all
1242 // keyword within the record are properties under that
1243 // interface.
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301244 for (const auto& record : vpdMap)
1245 {
1246 populateFruSpecificInterfaces(
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05001247 record.second, ipzVpdInf + record.first, interfaces);
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301248 }
1249 }
Alpana Kumari58e22142020-05-05 00:22:12 -05001250 else if constexpr (is_same<T, KeywordVpdMap>::value)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301251 {
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05001252 populateFruSpecificInterfaces(vpdMap, kwdVpdInf, interfaces);
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301253 }
Santosh Puranik88edeb62020-03-02 12:00:09 +05301254 if (js.find("commonInterfaces") != js.end())
1255 {
1256 populateInterfaces(js["commonInterfaces"], interfaces, vpdMap,
1257 isSystemVpd);
1258 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301259 }
Santosh Puranik0859eb62020-03-16 02:56:29 -05001260 else
1261 {
1262 // Check if we have been asked to inherit specific record(s)
Alpana Kumari58e22142020-05-05 00:22:12 -05001263 if constexpr (is_same<T, Parsed>::value)
Santosh Puranik0859eb62020-03-16 02:56:29 -05001264 {
1265 if (item.find("copyRecords") != item.end())
1266 {
1267 for (const auto& record : item["copyRecords"])
1268 {
1269 const string& recordName = record;
1270 if (vpdMap.find(recordName) != vpdMap.end())
1271 {
1272 populateFruSpecificInterfaces(
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05001273 vpdMap.at(recordName), ipzVpdInf + recordName,
Santosh Puranik0859eb62020-03-16 02:56:29 -05001274 interfaces);
1275 }
1276 }
1277 }
1278 }
1279 }
Santosh Puranik32c46502022-02-10 08:55:07 +05301280 // Populate interfaces and properties that are common to every FRU
1281 // and additional interface that might be defined on a per-FRU
1282 // basis.
1283 if (item.find("extraInterfaces") != item.end())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301284 {
Santosh Puranik32c46502022-02-10 08:55:07 +05301285 populateInterfaces(item["extraInterfaces"], interfaces, vpdMap,
1286 isSystemVpd);
Priyanga Ramasamy6abdeb62022-01-09 23:15:11 -06001287 if constexpr (is_same<T, Parsed>::value)
1288 {
1289 if (item["extraInterfaces"].find(
1290 "xyz.openbmc_project.Inventory.Item.Cpu") !=
1291 item["extraInterfaces"].end())
1292 {
1293 if (isCPUIOGoodOnly(getKwVal(vpdMap, "CP00", "PG")))
1294 {
Priyanga Ramasamy2c607a92022-04-08 00:30:17 -05001295 interfaces[invItemIntf]["PrettyName"] = "IO Module";
Priyanga Ramasamy6abdeb62022-01-09 23:15:11 -06001296 }
1297 }
1298 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301299 }
Priyanga Ramasamye358acb2022-03-21 14:21:50 -05001300
1301 // embedded property(true or false) says whether the subfru is embedded
1302 // into the parent fru (or) not. VPD sets Present property only for
1303 // embedded frus. If the subfru is not an embedded FRU, the subfru may
1304 // or may not be physically present. Those non embedded frus will always
1305 // have Present=false irrespective of its physical presence or absence.
1306 // Eg: nvme drive in nvme slot is not an embedded FRU. So don't set
1307 // Present to true for such sub frus.
1308 // Eg: ethernet port is embedded into bmc card. So set Present to true
1309 // for such sub frus. Also donot populate present property for embedded
1310 // subfru which is synthesized. Currently there is no subfru which are
1311 // both embedded and synthesized. But still the case is handled here.
1312 if ((item.value("embedded", true)) &&
1313 (!item.value("synthesized", false)))
1314 {
Priyanga Ramasamyaca61372023-01-24 08:02:28 -06001315 // Check if its required to handle presence for this FRU.
1316 if (item.value("handlePresence", true))
1317 {
1318 inventory::PropertyMap presProp;
1319 presProp.emplace("Present", true);
1320 insertOrMerge(interfaces, invItemIntf, move(presProp));
1321 }
Priyanga Ramasamye358acb2022-03-21 14:21:50 -05001322 }
Priyanga Ramasamyaa8a8932022-01-27 09:12:41 -06001323
Santosh Puranikf3e69682022-03-31 17:52:38 +05301324 if constexpr (is_same<T, Parsed>::value)
1325 {
1326 // Restore asset tag, if needed
1327 if (processFactoryReset && objectPath == "/system")
1328 {
1329 fillAssetTag(interfaces, vpdMap);
1330 }
1331 }
1332
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301333 objects.emplace(move(object), move(interfaces));
1334 }
1335
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301336 if (isSystemVpd)
1337 {
1338 inventory::ObjectMap primeObject = primeInventory(js, vpdMap);
1339 objects.insert(primeObject.begin(), primeObject.end());
Alpana Kumari65b83602020-09-01 00:24:56 -05001340
Alpana Kumarif05effd2021-04-07 07:32:53 -05001341 // set the U-boot environment variable for device-tree
1342 if constexpr (is_same<T, Parsed>::value)
1343 {
Santosh Puranike5f177a2022-01-24 20:14:46 +05301344 setDevTreeEnv(fs::path(getSystemsJson(vpdMap)).filename());
Alpana Kumarif05effd2021-04-07 07:32:53 -05001345 }
PriyangaRamasamy8e140a12020-04-13 19:24:03 +05301346 }
1347
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301348 // Notify PIM
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05001349 common::utility::callPIM(move(objects));
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301350}
1351
1352int main(int argc, char** argv)
1353{
1354 int rc = 0;
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001355 json js{};
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -06001356 Binary vpdVector{};
1357 string file{};
jinuthomasf457a3e2023-04-13 12:22:48 -05001358 string driver{};
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001359 // map to hold additional data in case of logging pel
1360 PelAdditionalData additionalData{};
1361
1362 // this is needed to hold base fru inventory path in case there is ECC or
1363 // vpd exception while parsing the file
1364 std::string baseFruInventoryPath = {};
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301365
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001366 // severity for PEL
1367 PelSeverity pelSeverity = PelSeverity::WARNING;
1368
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301369 try
1370 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001371 App app{"ibm-read-vpd - App to read IPZ/Jedec format VPD, parse it and "
1372 "store it in DBUS"};
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301373
1374 app.add_option("-f, --file", file, "File containing VPD (IPZ/KEYWORD)")
Alpana Kumari2f793042020-08-18 05:51:03 -05001375 ->required();
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301376
jinuthomasf457a3e2023-04-13 12:22:48 -05001377 app.add_option("--driver", driver,
1378 "Driver used by kernel (at24,at25,ee1004)")
1379 ->required();
1380
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301381 CLI11_PARSE(app, argc, argv);
1382
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001383 // PEL severity should be ERROR in case of any system VPD failure
1384 if (file == systemVpdFilePath)
1385 {
1386 pelSeverity = PelSeverity::ERROR;
1387 }
1388
jinuthomasf457a3e2023-04-13 12:22:48 -05001389 // Check if input file is not empty.
1390 if ((file.empty()) || (driver.empty()))
1391 {
1392 std::cerr << "Encountered empty input parameter file [" << file
1393 << "] driver [" << driver << "]" << std::endl;
1394 return 0;
1395 }
1396
1397 // Check if currently supported driver or not
1398 if ((driver != at24driver) && (driver != at25driver) &&
1399 (driver != ee1004driver))
1400 {
1401 std::cerr << "The driver [" << driver << "] is not supported."
1402 << std::endl;
1403 return 0;
1404 }
1405
Santosh Puranik0246a4d2020-11-04 16:57:39 +05301406 auto jsonToParse = INVENTORY_JSON_DEFAULT;
1407
1408 // If the symlink exists, it means it has been setup for us, switch the
1409 // path
1410 if (fs::exists(INVENTORY_JSON_SYM_LINK))
1411 {
1412 jsonToParse = INVENTORY_JSON_SYM_LINK;
1413 }
1414
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301415 // Make sure that the file path we get is for a supported EEPROM
Santosh Puranik0246a4d2020-11-04 16:57:39 +05301416 ifstream inventoryJson(jsonToParse);
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001417 if (!inventoryJson)
1418 {
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001419 throw(VpdJsonException("Failed to access Json path", jsonToParse));
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001420 }
1421
1422 try
1423 {
1424 js = json::parse(inventoryJson);
1425 }
Patrick Williams8e15b932021-10-06 13:04:22 -05001426 catch (const json::parse_error& ex)
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001427 {
Sunny Srivastava0746eee2021-03-22 13:36:54 -05001428 throw(VpdJsonException("Json parsing failed", jsonToParse));
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001429 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301430
Santosh Puranik12e24ff2021-05-11 19:33:50 +05301431 // Do we have the mandatory "frus" section?
1432 if (js.find("frus") == js.end())
1433 {
1434 throw(VpdJsonException("FRUs section not found in JSON",
1435 jsonToParse));
1436 }
1437
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301438 // Check if it's a udev path - patterned as(/ahb/ahb:apb/ahb:apb:bus@)
1439 if (file.find("/ahb:apb") != string::npos)
1440 {
1441 // Translate udev path to a generic /sys/bus/.. file path.
jinuthomasf457a3e2023-04-13 12:22:48 -05001442 udevToGenericPath(file, driver);
Santosh Puranik12e24ff2021-05-11 19:33:50 +05301443
1444 if ((js["frus"].find(file) != js["frus"].end()) &&
Santosh Puranik50f60bf2021-05-26 17:55:06 +05301445 (file == systemVpdFilePath))
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301446 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001447 std::cout << "We have already collected system VPD, skiping."
1448 << std::endl;
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301449 return 0;
1450 }
1451 }
1452
1453 if (file.empty())
1454 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001455 std::cerr << "The EEPROM path <" << file << "> is not valid.";
PriyangaRamasamy647868e2020-09-08 17:03:19 +05301456 return 0;
1457 }
Santosh Puranik12e24ff2021-05-11 19:33:50 +05301458 if (js["frus"].find(file) == js["frus"].end())
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301459 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001460 std::cerr << "The EEPROM path [" << file
1461 << "] is not found in the json." << std::endl;
Santosh Puranik88edeb62020-03-02 12:00:09 +05301462 return 0;
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301463 }
1464
Alpana Kumari2f793042020-08-18 05:51:03 -05001465 if (!fs::exists(file))
1466 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001467 std::cout << "Device path: " << file
1468 << " does not exist. Spurious udev event? Exiting."
1469 << std::endl;
Alpana Kumari2f793042020-08-18 05:51:03 -05001470 return 0;
1471 }
1472
Santosh Puranikdedb5a62022-12-19 23:58:32 +05301473 // In case of system VPD it will already be filled, Don't have to
1474 // overwrite that.
1475 if (baseFruInventoryPath.empty())
1476 {
1477 baseFruInventoryPath = js["frus"][file][0]["inventoryPath"];
1478 }
1479
Santosh Puranik85893752020-11-10 21:31:43 +05301480 // Check if we can read the VPD file based on the power state
Santosh Puranik27a5e952021-10-07 22:08:01 -05001481 // We skip reading VPD when the power is ON in two scenarios:
Santosh Puranik31d50fa2022-04-04 12:04:37 +05301482 // 1) The eeprom we are trying to read is that of the system VPD and the
1483 // JSON symlink is already setup (the symlink's existence tells us we
1484 // are not coming out of a factory reset)
1485 // 2) The JSON tells us that the FRU EEPROM cannot be
1486 // read when we are powered ON.
Santosh Puranik27a5e952021-10-07 22:08:01 -05001487 if (js["frus"][file].at(0).value("powerOffOnly", false) ||
Santosh Puranik31d50fa2022-04-04 12:04:37 +05301488 (file == systemVpdFilePath && fs::exists(INVENTORY_JSON_SYM_LINK)))
Santosh Puranik85893752020-11-10 21:31:43 +05301489 {
1490 if ("xyz.openbmc_project.State.Chassis.PowerState.On" ==
1491 getPowerState())
1492 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001493 std::cout << "This VPD cannot be read when power is ON"
1494 << std::endl;
Santosh Puranik85893752020-11-10 21:31:43 +05301495 return 0;
1496 }
1497 }
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001498
Santosh Puranike9c57532022-03-15 16:51:51 +05301499 // Check if this VPD should be recollected at all
1500 if (!needsRecollection(js, file))
1501 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001502 std::cout << "Skip VPD recollection for: " << file << std::endl;
Santosh Puranike9c57532022-03-15 16:51:51 +05301503 return 0;
1504 }
1505
Alpana Kumari2f793042020-08-18 05:51:03 -05001506 try
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301507 {
girik18bb9852022-11-16 05:48:13 -06001508 uint32_t vpdStartOffset = 0;
1509 for (const auto& item : js["frus"][file])
1510 {
1511 if (item.find("offset") != item.end())
1512 {
1513 vpdStartOffset = item["offset"];
1514 }
1515 }
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -06001516 vpdVector = getVpdDataInVector(js, file);
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -05001517 ParserInterface* parser = ParserFactory::getParser(
girik18bb9852022-11-16 05:48:13 -06001518 vpdVector, (pimPath + baseFruInventoryPath), file,
1519 vpdStartOffset);
Alpana Kumari2f793042020-08-18 05:51:03 -05001520 variant<KeywordVpdMap, Store> parseResult;
1521 parseResult = parser->parse();
SunnySrivastava19849a195542020-09-07 06:04:50 -05001522
Alpana Kumari2f793042020-08-18 05:51:03 -05001523 if (auto pVal = get_if<Store>(&parseResult))
1524 {
1525 populateDbus(pVal->getVpdMap(), js, file);
1526 }
1527 else if (auto pVal = get_if<KeywordVpdMap>(&parseResult))
1528 {
1529 populateDbus(*pVal, js, file);
1530 }
1531
1532 // release the parser object
1533 ParserFactory::freeParser(parser);
1534 }
Patrick Williams8e15b932021-10-06 13:04:22 -05001535 catch (const exception& e)
Alpana Kumari2f793042020-08-18 05:51:03 -05001536 {
Alpana Kumari735dee92022-03-25 01:24:40 -05001537 executePostFailAction(js, file);
PriyangaRamasamya504c3e2020-12-06 12:14:52 -06001538 throw;
Alpana Kumari2f793042020-08-18 05:51:03 -05001539 }
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301540 }
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001541 catch (const VpdJsonException& ex)
1542 {
1543 additionalData.emplace("JSON_PATH", ex.getJsonPath());
1544 additionalData.emplace("DESCRIPTION", ex.what());
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -05001545 createPEL(additionalData, pelSeverity, errIntfForJsonFailure, nullptr);
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001546
jinuthomasf457a3e2023-04-13 12:22:48 -05001547 std::cerr << ex.what() << "\n";
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001548 rc = -1;
1549 }
1550 catch (const VpdEccException& ex)
1551 {
1552 additionalData.emplace("DESCRIPTION", "ECC check failed");
1553 additionalData.emplace("CALLOUT_INVENTORY_PATH",
1554 INVENTORY_PATH + baseFruInventoryPath);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -05001555 createPEL(additionalData, pelSeverity, errIntfForEccCheckFail, nullptr);
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -06001556 dumpBadVpd(file, vpdVector);
jinuthomasf457a3e2023-04-13 12:22:48 -05001557 std::cerr << ex.what() << "\n";
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001558 rc = -1;
1559 }
1560 catch (const VpdDataException& ex)
1561 {
alpana075cb3b1f2021-12-16 11:19:36 -06001562 if (isThisPcieOnPass1planar(js, file))
1563 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001564 std::cout << "Pcie_device [" << file
1565 << "]'s VPD is not valid on PASS1 planar.Ignoring.\n";
alpana075cb3b1f2021-12-16 11:19:36 -06001566 rc = 0;
1567 }
Santosh Puranik53b38ed2022-04-10 23:15:22 +05301568 else if (!(isPresent(js, file).value_or(true)))
1569 {
jinuthomasf457a3e2023-04-13 12:22:48 -05001570 std::cout << "FRU at: " << file
1571 << " is not detected present. Ignore parser error.\n";
Santosh Puranik53b38ed2022-04-10 23:15:22 +05301572 rc = 0;
1573 }
alpana075cb3b1f2021-12-16 11:19:36 -06001574 else
1575 {
1576 string errorMsg =
1577 "VPD file is either empty or invalid. Parser failed for [";
1578 errorMsg += file;
1579 errorMsg += "], with error = " + std::string(ex.what());
1580
1581 additionalData.emplace("DESCRIPTION", errorMsg);
1582 additionalData.emplace("CALLOUT_INVENTORY_PATH",
1583 INVENTORY_PATH + baseFruInventoryPath);
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -05001584 createPEL(additionalData, pelSeverity, errIntfForInvalidVPD,
1585 nullptr);
alpana075cb3b1f2021-12-16 11:19:36 -06001586
1587 rc = -1;
1588 }
SunnySrivastava1984a20be8e2020-08-26 02:00:50 -05001589 }
Patrick Williams8e15b932021-10-06 13:04:22 -05001590 catch (const exception& e)
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301591 {
PriyangaRamasamyc2fe40f2021-03-02 06:27:33 -06001592 dumpBadVpd(file, vpdVector);
jinuthomasf457a3e2023-04-13 12:22:48 -05001593 std::cerr << e.what() << "\n";
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301594 rc = -1;
1595 }
1596
1597 return rc;
Patrick Williamsc78d8872023-05-10 07:50:56 -05001598}