blob: 4d0b1d7b2b0a445d5a8ecb61ab526d67a121d2be [file] [log] [blame]
SunnySrivastava1984b59fd092020-02-03 09:58:56 -06001#include "config.h"
2
3#include "manager.hpp"
4
Santosh Puranikbf78ed82022-04-20 13:17:04 +05305#include "common_utility.hpp"
SunnySrivastava1984d076da82020-03-05 05:33:35 -06006#include "editor_impl.hpp"
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05007#include "ibm_vpd_utils.hpp"
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05008#include "ipz_parser.hpp"
Santosh Puranik6b2b5372022-06-02 20:49:02 +05309#include "parser_factory.hpp"
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -050010#include "reader_impl.hpp"
SunnySrivastava19849a195542020-09-07 06:04:50 -050011#include "vpd_exceptions.hpp"
12
13#include <phosphor-logging/elog-errors.hpp>
Sunny Srivastava28abd6e2021-07-28 02:58:28 -050014#include <xyz/openbmc_project/Common/error.hpp>
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060015
Patrick Williamsc78d8872023-05-10 07:50:56 -050016#include <filesystem>
17
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060018using namespace openpower::vpd::constants;
SunnySrivastava19841356d7e2020-04-24 04:29:35 -050019using namespace openpower::vpd::inventory;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060020using namespace openpower::vpd::manager::editor;
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -050021using namespace openpower::vpd::manager::reader;
SunnySrivastava19849a195542020-09-07 06:04:50 -050022using namespace std;
23using namespace openpower::vpd::parser;
Santosh Puranik6b2b5372022-06-02 20:49:02 +053024using namespace openpower::vpd::parser::factory;
25using namespace openpower::vpd::ipz::parser;
SunnySrivastava19849a195542020-09-07 06:04:50 -050026using namespace openpower::vpd::exceptions;
27using namespace phosphor::logging;
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060028
29namespace openpower
30{
31namespace vpd
32{
33namespace manager
34{
Sunny Srivastava523af2e2022-02-14 07:30:10 -060035Manager::Manager(std::shared_ptr<boost::asio::io_context>& ioCon,
36 std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace,
37 std::shared_ptr<sdbusplus::asio::connection>& conn) :
38 ioContext(ioCon),
39 interface(iFace), conn(conn)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060040{
Sunny Srivastava523af2e2022-02-14 07:30:10 -060041 interface->register_method(
42 "WriteKeyword",
43 [this](const sdbusplus::message::object_path& path,
44 const std::string& recordName, const std::string& keyword,
45 const Binary& value) {
Patrick Williamsc78d8872023-05-10 07:50:56 -050046 this->writeKeyword(path, recordName, keyword, value);
Patrick Williamsb7b352a2023-10-20 11:19:19 -050047 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060048
49 interface->register_method(
50 "GetFRUsByUnexpandedLocationCode",
51 [this](const std::string& locationCode,
52 const uint16_t nodeNumber) -> inventory::ListOfPaths {
Patrick Williamsb7b352a2023-10-20 11:19:19 -050053 return this->getFRUsByUnexpandedLocationCode(locationCode, nodeNumber);
54 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060055
56 interface->register_method(
57 "GetFRUsByExpandedLocationCode",
58 [this](const std::string& locationCode) -> inventory::ListOfPaths {
Patrick Williamsb7b352a2023-10-20 11:19:19 -050059 return this->getFRUsByExpandedLocationCode(locationCode);
60 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060061
62 interface->register_method(
63 "GetExpandedLocationCode",
64 [this](const std::string& locationCode,
65 const uint16_t nodeNumber) -> std::string {
Patrick Williamsb7b352a2023-10-20 11:19:19 -050066 return this->getExpandedLocationCode(locationCode, nodeNumber);
67 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060068
69 interface->register_method("PerformVPDRecollection",
70 [this]() { this->performVPDRecollection(); });
71
Sunny Srivastava28abd6e2021-07-28 02:58:28 -050072 interface->register_method(
73 "deleteFRUVPD", [this](const sdbusplus::message::object_path& path) {
Patrick Williamsb7b352a2023-10-20 11:19:19 -050074 this->deleteFRUVPD(path);
75 });
Sunny Srivastava28abd6e2021-07-28 02:58:28 -050076
Sunny Srivastava6a1bd392021-06-02 04:39:24 -050077 interface->register_method(
78 "CollectFRUVPD", [this](const sdbusplus::message::object_path& path) {
Patrick Williamsb7b352a2023-10-20 11:19:19 -050079 this->collectFRUVPD(path);
80 });
Sunny Srivastava6a1bd392021-06-02 04:39:24 -050081
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -050082 sd_bus_default(&sdBus);
Sunny Srivastava523af2e2022-02-14 07:30:10 -060083 initManager();
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060084}
85
Sunny Srivastava523af2e2022-02-14 07:30:10 -060086void Manager::initManager()
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060087{
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060088 try
89 {
90 processJSON();
Santosh Puranik6b2b5372022-06-02 20:49:02 +053091 restoreSystemVpd();
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050092 listenHostState();
Santosh Puranikb62f6052022-04-06 18:37:54 +053093 listenAssetTag();
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050094
Santosh Puranikf2d3b532022-04-19 06:44:07 -050095 // Create an instance of the BIOS handler
Sunny Srivastava523af2e2022-02-14 07:30:10 -060096 biosHandler = std::make_shared<BiosHandler>(conn, *this);
Santosh Puranikf2d3b532022-04-19 06:44:07 -050097
Sunny Srivastava523af2e2022-02-14 07:30:10 -060098 // instantiate gpioMonitor class
99 gpioMon = std::make_shared<GpioMonitor>(jsonFile, ioContext);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600100 }
101 catch (const std::exception& e)
102 {
103 std::cerr << e.what() << "\n";
104 }
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600105}
106
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530107/**
108 * @brief An api to get list of blank system VPD properties.
109 * @param[in] vpdMap - IPZ vpd map.
110 * @param[in] objectPath - Object path for the FRU.
111 * @param[out] blankPropertyList - Properties which are blank in System VPD and
112 * needs to be updated as standby.
113 */
114static void
115 getListOfBlankSystemVpd(Parsed& vpdMap, const string& objectPath,
116 std::vector<RestoredEeproms>& blankPropertyList)
117{
118 for (const auto& systemRecKwdPair : svpdKwdMap)
119 {
120 auto it = vpdMap.find(systemRecKwdPair.first);
121
122 // check if record is found in map we got by parser
123 if (it != vpdMap.end())
124 {
125 const auto& kwdListForRecord = systemRecKwdPair.second;
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600126 for (const auto& keywordInfo : kwdListForRecord)
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530127 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600128 const auto& keyword = get<0>(keywordInfo);
129
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530130 DbusPropertyMap& kwdValMap = it->second;
131 auto iterator = kwdValMap.find(keyword);
132
133 if (iterator != kwdValMap.end())
134 {
135 string& kwdValue = iterator->second;
136
137 // check bus data
138 const string& recordName = systemRecKwdPair.first;
139 const string& busValue = readBusProperty(
140 objectPath, ipzVpdInf + recordName, keyword);
141
Priyanga Ramasamy834c0782023-02-14 12:22:39 -0600142 const auto& defaultValue = get<1>(keywordInfo);
143
144 if (Binary(busValue.begin(), busValue.end()) !=
145 defaultValue)
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530146 {
Priyanga Ramasamy834c0782023-02-14 12:22:39 -0600147 if (Binary(kwdValue.begin(), kwdValue.end()) ==
148 defaultValue)
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530149 {
150 // implies data is blank on EEPROM but not on cache.
151 // So EEPROM vpd update is required.
152 Binary busData(busValue.begin(), busValue.end());
153
154 blankPropertyList.push_back(std::make_tuple(
155 objectPath, recordName, keyword, busData));
156 }
157 }
158 }
159 }
160 }
161 }
162}
163
164void Manager::restoreSystemVpd()
165{
166 std::cout << "Attempting system VPD restore" << std::endl;
167 ParserInterface* parser = nullptr;
168 try
169 {
170 auto vpdVector = getVpdDataInVector(jsonFile, systemVpdFilePath);
girik18bb9852022-11-16 05:48:13 -0600171 uint32_t vpdStartOffset = 0;
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500172 const auto& inventoryPath =
173 jsonFile["frus"][systemVpdFilePath][0]["inventoryPath"]
174 .get_ref<const nlohmann::json::string_t&>();
175
girik18bb9852022-11-16 05:48:13 -0600176 parser = ParserFactory::getParser(vpdVector, (pimPath + inventoryPath),
177 systemVpdFilePath, vpdStartOffset);
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530178 auto parseResult = parser->parse();
179
180 if (auto pVal = std::get_if<Store>(&parseResult))
181 {
182 // map to hold all the keywords whose value is blank and
183 // needs to be updated at standby.
184 std::vector<RestoredEeproms> blankSystemVpdProperties{};
185 getListOfBlankSystemVpd(pVal->getVpdMap(), SYSTEM_OBJECT,
186 blankSystemVpdProperties);
187
188 // if system VPD restore is required, update the
189 // EEPROM
190 for (const auto& item : blankSystemVpdProperties)
191 {
192 std::cout << "Restoring keyword: " << std::get<2>(item)
193 << std::endl;
194 writeKeyword(std::get<0>(item), std::get<1>(item),
195 std::get<2>(item), std::get<3>(item));
196 }
197 }
198 else
199 {
200 std::cerr << "Not a valid format to restore system VPD"
201 << std::endl;
202 }
203 }
204 catch (const std::exception& e)
205 {
206 std::cerr << "Failed to restore system VPD due to exception: "
207 << e.what() << std::endl;
208 }
209 // release the parser object
210 ParserFactory::freeParser(parser);
211}
212
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500213void Manager::listenHostState()
214{
Patrick Williams2eb01762022-07-22 19:26:56 -0500215 static std::shared_ptr<sdbusplus::bus::match_t> hostState =
216 std::make_shared<sdbusplus::bus::match_t>(
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600217 *conn,
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500218 sdbusplus::bus::match::rules::propertiesChanged(
219 "/xyz/openbmc_project/state/host0",
220 "xyz.openbmc_project.State.Host"),
Patrick Williams2eb01762022-07-22 19:26:56 -0500221 [this](sdbusplus::message_t& msg) { hostStateCallBack(msg); });
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500222}
223
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500224void Manager::checkEssentialFrus()
225{
226 for (const auto& invPath : essentialFrus)
227 {
228 const auto res = readBusProperty(invPath, invItemIntf, "Present");
229
230 // implies the essential FRU is missing. Log PEL.
231 if (res == "false")
232 {
233 auto rc = sd_bus_call_method_async(
234 sdBus, NULL, loggerService, loggerObjectPath,
235 loggerCreateInterface, "Create", NULL, NULL, "ssa{ss}",
236 errIntfForEssentialFru,
237 "xyz.openbmc_project.Logging.Entry.Level.Warning", 2,
238 "DESCRIPTION", "Essential fru missing from the system.",
239 "CALLOUT_INVENTORY_PATH", (pimPath + invPath).c_str());
240
241 if (rc < 0)
242 {
243 log<level::ERR>("Error calling sd_bus_call_method_async",
244 entry("RC=%d", rc),
245 entry("MSG=%s", strerror(-rc)));
246 }
247 }
248 }
249}
250
Patrick Williams7a975f02022-12-07 03:19:53 -0600251void Manager::hostStateCallBack(sdbusplus::message_t& msg)
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500252{
253 if (msg.is_method_error())
254 {
255 std::cerr << "Error in reading signal " << std::endl;
256 }
257
258 Path object;
259 PropertyMap propMap;
260 msg.read(object, propMap);
261 const auto itr = propMap.find("CurrentHostState");
262 if (itr != propMap.end())
263 {
264 if (auto hostState = std::get_if<std::string>(&(itr->second)))
265 {
266 // implies system is moving from standby to power on state
267 if (*hostState == "xyz.openbmc_project.State.Host.HostState."
268 "TransitioningToRunning")
269 {
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500270 // detect if essential frus are present in the system.
271 checkEssentialFrus();
272
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500273 // check and perfrom recollection for FRUs replaceable at
274 // standby.
275 performVPDRecollection();
276 return;
277 }
278 }
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500279 }
280}
281
Santosh Puranikb62f6052022-04-06 18:37:54 +0530282void Manager::listenAssetTag()
283{
Patrick Williams2eb01762022-07-22 19:26:56 -0500284 static std::shared_ptr<sdbusplus::bus::match_t> assetMatcher =
285 std::make_shared<sdbusplus::bus::match_t>(
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600286 *conn,
Santosh Puranikb62f6052022-04-06 18:37:54 +0530287 sdbusplus::bus::match::rules::propertiesChanged(
288 "/xyz/openbmc_project/inventory/system",
289 "xyz.openbmc_project.Inventory.Decorator.AssetTag"),
Patrick Williams2eb01762022-07-22 19:26:56 -0500290 [this](sdbusplus::message_t& msg) { assetTagCallback(msg); });
Santosh Puranikb62f6052022-04-06 18:37:54 +0530291}
292
Patrick Williams2eb01762022-07-22 19:26:56 -0500293void Manager::assetTagCallback(sdbusplus::message_t& msg)
Santosh Puranikb62f6052022-04-06 18:37:54 +0530294{
295 if (msg.is_method_error())
296 {
297 std::cerr << "Error in reading signal " << std::endl;
298 }
299
300 Path object;
301 PropertyMap propMap;
302 msg.read(object, propMap);
303 const auto itr = propMap.find("AssetTag");
304 if (itr != propMap.end())
305 {
306 if (auto assetTag = std::get_if<std::string>(&(itr->second)))
307 {
308 // Call Notify to persist the AssetTag
309 inventory::ObjectMap objectMap = {
310 {std::string{"/system"},
311 {{"xyz.openbmc_project.Inventory.Decorator.AssetTag",
312 {{"AssetTag", *assetTag}}}}}};
313
314 common::utility::callPIM(std::move(objectMap));
315 }
316 else
317 {
318 std::cerr << "Failed to read asset tag" << std::endl;
319 }
320 }
321}
322
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600323void Manager::processJSON()
324{
Santosh Puranik0246a4d2020-11-04 16:57:39 +0530325 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600326
327 if (!json)
328 {
329 throw std::runtime_error("json file not found");
330 }
331
332 jsonFile = nlohmann::json::parse(json);
333 if (jsonFile.find("frus") == jsonFile.end())
334 {
335 throw std::runtime_error("frus group not found in json");
336 }
337
338 const nlohmann::json& groupFRUS =
339 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
340 for (const auto& itemFRUS : groupFRUS.items())
341 {
342 const std::vector<nlohmann::json>& groupEEPROM =
343 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
344 for (const auto& itemEEPROM : groupEEPROM)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600345 {
SunnySrivastava198443306542020-04-01 02:50:20 -0500346 bool isMotherboard = false;
Santosh Puranika0b23912022-02-10 13:37:09 +0530347 std::string redundantPath;
348
SunnySrivastava198443306542020-04-01 02:50:20 -0500349 if (itemEEPROM["extraInterfaces"].find(
350 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") !=
351 itemEEPROM["extraInterfaces"].end())
352 {
353 isMotherboard = true;
354 }
Santosh Puranika0b23912022-02-10 13:37:09 +0530355 if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end())
356 {
357 redundantPath = itemEEPROM["redundantEeprom"]
358 .get_ref<const nlohmann::json::string_t&>();
359 }
360 frus.emplace(
361 itemEEPROM["inventoryPath"]
362 .get_ref<const nlohmann::json::string_t&>(),
363 std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard));
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500364
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000365 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
Alpana Kumari920408d2020-05-14 00:07:03 -0500366 itemEEPROM["extraInterfaces"].end())
367 {
368 fruLocationCode.emplace(
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000369 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
Alpana Kumari920408d2020-05-14 00:07:03 -0500370 ["LocationCode"]
371 .get_ref<const nlohmann::json::string_t&>(),
372 itemEEPROM["inventoryPath"]
373 .get_ref<const nlohmann::json::string_t&>());
374 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500375
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500376 if (itemEEPROM.value("replaceableAtStandby", false))
SunnySrivastava19849a195542020-09-07 06:04:50 -0500377 {
378 replaceableFrus.emplace_back(itemFRUS.key());
379 }
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500380
381 if (itemEEPROM.value("essentialFru", false))
382 {
383 essentialFrus.emplace_back(itemEEPROM["inventoryPath"]);
384 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600385 }
386 }
387}
388
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600389void Manager::writeKeyword(const sdbusplus::message::object_path& path,
390 const std::string& recordName,
391 const std::string& keyword, const Binary& value)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600392{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600393 try
394 {
Santosh Puranik8c796812021-12-01 19:17:56 +0530395 std::string objPath{path};
396 // Strip any inventory prefix in path
397 if (objPath.find(INVENTORY_PATH) == 0)
398 {
399 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
400 }
401
402 if (frus.find(objPath) == frus.end())
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600403 {
404 throw std::runtime_error("Inventory path not found");
405 }
406
Santosh Puranika0b23912022-02-10 13:37:09 +0530407 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600408
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500409 // instantiate editor class to update the data
Santosh Puranik8c796812021-12-01 19:17:56 +0530410 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530411
412 uint32_t offset = 0;
413 // Setup offset, if any
414 for (const auto& item : jsonFile["frus"][vpdFilePath])
415 {
416 if (item.find("offset") != item.end())
417 {
418 offset = item["offset"];
419 break;
420 }
421 }
422
423 edit.updateKeyword(value, offset, true);
424
425 // If we have a redundant EEPROM to update, then update just the EEPROM,
426 // not the cache since that is already done when we updated the primary
427 if (!std::get<1>(frus.find(objPath)->second).empty())
428 {
429 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile,
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500430 recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530431 edit.updateKeyword(value, offset, false);
432 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600433
SunnySrivastava198443306542020-04-01 02:50:20 -0500434 // if it is a motehrboard FRU need to check for location expansion
Santosh Puranika0b23912022-02-10 13:37:09 +0530435 if (std::get<2>(frus.find(objPath)->second))
SunnySrivastava198443306542020-04-01 02:50:20 -0500436 {
437 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE"))
438 {
439 edit.expandLocationCode("fcs");
440 }
441 else if (recordName == "VSYS" &&
442 (keyword == "TM" || keyword == "SE"))
443 {
444 edit.expandLocationCode("mts");
445 }
446 }
447
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500448 return;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600449 }
450 catch (const std::exception& e)
451 {
452 std::cerr << e.what() << std::endl;
453 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600454}
455
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500456ListOfPaths
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600457 Manager::getFRUsByUnexpandedLocationCode(const LocationCode& locationCode,
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500458 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600459{
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500460 ReaderImpl read;
461 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600462}
463
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500464ListOfPaths
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600465 Manager::getFRUsByExpandedLocationCode(const LocationCode& locationCode)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600466{
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500467 ReaderImpl read;
468 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600469}
470
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600471LocationCode Manager::getExpandedLocationCode(const LocationCode& locationCode,
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500472 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600473{
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500474 ReaderImpl read;
475 return read.getExpandedLocationCode(locationCode, nodeNumber,
476 fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600477}
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600478
SunnySrivastava19849a195542020-09-07 06:04:50 -0500479void Manager::performVPDRecollection()
480{
481 // get list of FRUs replaceable at standby
482 for (const auto& item : replaceableFrus)
483 {
484 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
485 const nlohmann::json& singleFru = groupEEPROM[0];
486
487 const string& inventoryPath =
488 singleFru["inventoryPath"]
489 .get_ref<const nlohmann::json::string_t&>();
490
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530491 bool prePostActionRequired = false;
492
493 if ((jsonFile["frus"][item].at(0)).find("preAction") !=
494 jsonFile["frus"][item].at(0).end())
495 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500496 try
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530497 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500498 if (!executePreAction(jsonFile, item))
499 {
500 // if the FRU has preAction defined then its execution
501 // should pass to ensure bind/unbind of data.
502 // preAction execution failed. should not call
503 // bind/unbind.
504 log<level::ERR>(
505 "Pre-Action execution failed for the FRU",
506 entry("ERROR=%s",
507 ("Inventory path: " + inventoryPath).c_str()));
508 continue;
509 }
510 }
511 catch (const GpioException& e)
512 {
513 log<level::ERR>(e.what());
514 PelAdditionalData additionalData{};
515 additionalData.emplace("DESCRIPTION", e.what());
516 createPEL(additionalData, PelSeverity::WARNING,
517 errIntfForGpioError, sdBus);
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530518 continue;
519 }
520 prePostActionRequired = true;
521 }
522
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500523 // unbind, bind the driver to trigger parser.
524 triggerVpdCollection(singleFru, inventoryPath);
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530525
526 // this check is added to avoid file system expensive call in case not
527 // required.
528 if (prePostActionRequired)
529 {
530 // Check if device showed up (test for file)
531 if (!filesystem::exists(item))
532 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500533 try
534 {
535 // If not, then take failure postAction
536 executePostFailAction(jsonFile, item);
537 }
538 catch (const GpioException& e)
539 {
540 PelAdditionalData additionalData{};
541 additionalData.emplace("DESCRIPTION", e.what());
542 createPEL(additionalData, PelSeverity::WARNING,
543 errIntfForGpioError, sdBus);
544 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530545 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500546 else
547 {
548 // bind the LED driver
549 string chipAddr = singleFru.value("pcaChipAddress", "");
550 cout << "performVPDRecollection: Executing driver binding for "
551 "chip "
552 "address - "
553 << chipAddr << endl;
554
555 executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c",
556 "leds-pca955x", "/bind"));
557 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530558 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500559 }
560}
561
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500562void Manager::collectFRUVPD(const sdbusplus::message::object_path& path)
563{
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500564 std::cout << "Manager called to collect vpd for fru: " << std::string{path}
565 << std::endl;
566
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500567 using InvalidArgument =
568 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
569 using Argument = xyz::openbmc_project::Common::InvalidArgument;
570
Santosh Puranikbc599472022-12-19 20:17:10 +0530571 std::string objPath{path};
572
573 // Strip any inventory prefix in path
574 if (objPath.find(INVENTORY_PATH) == 0)
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500575 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530576 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500577 }
578
Santosh Puranikbc599472022-12-19 20:17:10 +0530579 // if path not found in Json.
580 if (frus.find(objPath) == frus.end())
581 {
582 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
583 Argument::ARGUMENT_VALUE(objPath.c_str()));
584 }
585
586 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500587
588 const std::vector<nlohmann::json>& groupEEPROM =
589 jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>();
590
Sunny Srivastavaab2304d2023-01-10 23:30:05 -0600591 nlohmann::json singleFru{};
592 for (const auto& item : groupEEPROM)
593 {
594 if (item["inventoryPath"] == objPath)
595 {
596 // this is the inventory we are looking for
597 singleFru = item;
598 break;
599 }
600 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500601
602 // check if the device qualifies for CM.
603 if (singleFru.value("concurrentlyMaintainable", false))
604 {
605 bool prePostActionRequired = false;
606
607 if ((jsonFile["frus"][vpdFilePath].at(0)).find("preAction") !=
608 jsonFile["frus"][vpdFilePath].at(0).end())
609 {
610 if (!executePreAction(jsonFile, vpdFilePath))
611 {
612 // if the FRU has preAction defined then its execution should
613 // pass to ensure bind/unbind of data.
614 // preAction execution failed. should not call bind/unbind.
615 log<level::ERR>("Pre-Action execution failed for the FRU");
616 return;
617 }
618
619 prePostActionRequired = true;
620 }
621
622 // unbind, bind the driver to trigger parser.
Santosh Puranikbc599472022-12-19 20:17:10 +0530623 triggerVpdCollection(singleFru, objPath);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500624
625 // this check is added to avoid file system expensive call in case not
626 // required.
627 if (prePostActionRequired)
628 {
629 // Check if device showed up (test for file)
630 if (!filesystem::exists(vpdFilePath))
631 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530632 try
633 {
634 // If not, then take failure postAction
635 executePostFailAction(jsonFile, vpdFilePath);
636 }
637 catch (const GpioException& e)
638 {
639 PelAdditionalData additionalData{};
640 additionalData.emplace("DESCRIPTION", e.what());
641 createPEL(additionalData, PelSeverity::WARNING,
642 errIntfForGpioError, sdBus);
643 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500644 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500645 else
646 {
647 // bind the LED driver
648 string chipAddr = jsonFile["frus"][vpdFilePath].at(0).value(
649 "pcaChipAddress", "");
650 cout << "Executing driver binding for chip address - "
651 << chipAddr << endl;
652
653 executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c",
654 "leds-pca955x", "/bind"));
655 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500656 }
657 return;
658 }
659 else
660 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530661 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
662 Argument::ARGUMENT_VALUE(objPath.c_str()));
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500663 }
664}
665
666void Manager::triggerVpdCollection(const nlohmann::json& singleFru,
667 const std::string& path)
668{
669 if ((singleFru.find("devAddress") == singleFru.end()) ||
670 (singleFru.find("driverType") == singleFru.end()) ||
671 (singleFru.find("busType") == singleFru.end()))
672 {
673 // The FRUs is marked for collection but missing mandatory
674 // fields for collection. Log error and return.
675 log<level::ERR>(
676 "Collection Failed as mandatory field missing in Json",
677 entry("ERROR=%s", ("Recollection failed for " + (path)).c_str()));
678
679 return;
680 }
681
682 string deviceAddress = singleFru["devAddress"];
683 const string& driverType = singleFru["driverType"];
684 const string& busType = singleFru["busType"];
685
686 // devTreeStatus flag is present in json as false to mention
687 // that the EEPROM is not mentioned in device tree. If this flag
688 // is absent consider the value to be true, i.e EEPROM is
689 // mentioned in device tree
690 if (!singleFru.value("devTreeStatus", true))
691 {
692 auto pos = deviceAddress.find('-');
693 if (pos != string::npos)
694 {
695 string busNum = deviceAddress.substr(0, pos);
696 deviceAddress = "0x" + deviceAddress.substr(pos + 1, string::npos);
697
698 string deleteDevice = "echo" + deviceAddress + " > /sys/bus/" +
699 busType + "/devices/" + busType + "-" +
700 busNum + "/delete_device";
701 executeCmd(deleteDevice);
702
703 string addDevice = "echo" + driverType + " " + deviceAddress +
704 " > /sys/bus/" + busType + "/devices/" +
705 busType + "-" + busNum + "/new_device";
706 executeCmd(addDevice);
707 }
708 else
709 {
710 const string& inventoryPath =
711 singleFru["inventoryPath"]
712 .get_ref<const nlohmann::json::string_t&>();
713
714 log<level::ERR>(
715 "Wrong format of device address in Json",
716 entry("ERROR=%s",
717 ("Recollection failed for " + inventoryPath).c_str()));
718 }
719 }
720 else
721 {
722 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
723 driverType, "/unbind"));
724 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
725 driverType, "/bind"));
726 }
727}
728
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500729void Manager::deleteFRUVPD(const sdbusplus::message::object_path& path)
730{
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500731 std::cout << "Manager called to delete vpd for fru: " << std::string{path}
732 << std::endl;
733
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500734 using InvalidArgument =
735 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
736 using Argument = xyz::openbmc_project::Common::InvalidArgument;
737
Santosh Puranikbc599472022-12-19 20:17:10 +0530738 std::string objPath{path};
739
740 // Strip any inventory prefix in path
741 if (objPath.find(INVENTORY_PATH) == 0)
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500742 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530743 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500744 }
745
Santosh Puranikbc599472022-12-19 20:17:10 +0530746 // if path not found in Json.
747 if (frus.find(objPath) == frus.end())
748 {
749 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
750 Argument::ARGUMENT_VALUE(objPath.c_str()));
751 }
752
753 inventory::Path& vpdFilePath = std::get<0>(frus.find(objPath)->second);
Alpana Kumari41d498c2021-09-16 00:29:12 -0500754
755 string chipAddress =
756 jsonFile["frus"][vpdFilePath].at(0).value("pcaChipAddress", "");
757
758 // Unbind the LED driver for this FRU
759 cout << "Unbinding device- " << chipAddress << endl;
760 executeCmd(createBindUnbindDriverCmnd(chipAddress, "i2c", "leds-pca955x",
761 "/unbind"));
762
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500763 // if the FRU is not present then log error
Santosh Puranikbc599472022-12-19 20:17:10 +0530764 if (readBusProperty(objPath, "xyz.openbmc_project.Inventory.Item",
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500765 "Present") == "false")
766 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530767 elog<InvalidArgument>(Argument::ARGUMENT_NAME("FRU not preset"),
768 Argument::ARGUMENT_VALUE(objPath.c_str()));
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500769 }
770 else
771 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530772 // Set present property of FRU as false as it has been removed.
773 // CC data for FRU is also removed as
774 // a) FRU is not there so CC does not make sense.
775 // b) Sensors dependent on Panel uses CC data.
776 inventory::InterfaceMap interfaces{
777 {"xyz.openbmc_project.Inventory.Item", {{"Present", false}}},
778 {"com.ibm.ipzvpd.VINI", {{"CC", Binary{}}}}};
779
780 inventory::ObjectMap objectMap;
781 objectMap.emplace(objPath, move(interfaces));
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500782
783 common::utility::callPIM(move(objectMap));
784 }
785}
786
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600787} // namespace manager
788} // namespace vpd
Patrick Williamsc78d8872023-05-10 07:50:56 -0500789} // namespace openpower