blob: 18c2f040c74287e0fec3733ad5171eee0a5a77a3 [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 Srivastava83770862023-10-31 12:57:20 -0500389void Manager::updateSystemVPDBackUpFRU(const std::string& recordName,
390 const std::string& keyword,
391 const Binary& value)
392{
393 const std::string& systemVpdBackupPath =
394 jsonFile["frus"][systemVpdFilePath].at(0).value("systemVpdBackupPath",
395 "");
396
397 if (!systemVpdBackupPath.empty() &&
398 jsonFile["frus"][systemVpdBackupPath].at(0).contains("inventoryPath"))
399 {
400 std::string systemVpdBackupInvPath =
401 jsonFile["frus"][systemVpdBackupPath][0]["inventoryPath"]
402 .get_ref<const nlohmann::json::string_t&>();
403
404 const auto& itr = svpdKwdMap.find(recordName);
405 if (itr != svpdKwdMap.end())
406 {
407 auto systemKwdInfoList = itr->second;
408 const auto& itrToKwd = find_if(systemKwdInfoList.begin(),
409 systemKwdInfoList.end(),
410 [&keyword](const auto& kwdInfo) {
411 return (keyword == std::get<0>(kwdInfo));
412 });
413
414 if (itrToKwd != systemKwdInfoList.end())
415 {
416 EditorImpl edit(systemVpdBackupPath, jsonFile,
417 std::get<4>(*itrToKwd), std::get<5>(*itrToKwd),
418 systemVpdBackupInvPath);
419
420 // Setup offset, if any
421 uint32_t offset = 0;
422 if (jsonFile["frus"][systemVpdBackupPath].at(0).contains(
423 "offset"))
424 {
425 offset =
426 jsonFile["frus"][systemVpdBackupPath].at(0).contains(
427 "offset");
428 }
429
430 edit.updateKeyword(value, offset, true);
431 }
432 }
433 }
434 else
435 {
436 if (systemVpdBackupPath.empty())
437 {
438 throw std::runtime_error(
439 "Invalid entry for systemVpdBackupPath in JSON");
440 }
441 else
442 {
443 throw std::runtime_error(
444 "Inventory path missing for systemVpdBackupPath");
445 }
446 }
447}
448
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600449void Manager::writeKeyword(const sdbusplus::message::object_path& path,
450 const std::string& recordName,
451 const std::string& keyword, const Binary& value)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600452{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600453 try
454 {
Santosh Puranik8c796812021-12-01 19:17:56 +0530455 std::string objPath{path};
456 // Strip any inventory prefix in path
457 if (objPath.find(INVENTORY_PATH) == 0)
458 {
459 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
460 }
461
462 if (frus.find(objPath) == frus.end())
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600463 {
464 throw std::runtime_error("Inventory path not found");
465 }
466
Santosh Puranika0b23912022-02-10 13:37:09 +0530467 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600468
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500469 // instantiate editor class to update the data
Santosh Puranik8c796812021-12-01 19:17:56 +0530470 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530471
472 uint32_t offset = 0;
473 // Setup offset, if any
474 for (const auto& item : jsonFile["frus"][vpdFilePath])
475 {
476 if (item.find("offset") != item.end())
477 {
478 offset = item["offset"];
479 break;
480 }
481 }
482
483 edit.updateKeyword(value, offset, true);
484
Sunny Srivastava83770862023-10-31 12:57:20 -0500485 // If system VPD is being updated and system VPD is marked for back up
486 // on another FRU, update data on back up as well.
487 if (objPath == sdbusplus::message::object_path{SYSTEM_OBJECT} &&
488 jsonFile["frus"][systemVpdFilePath].at(0).contains(
489 "systemVpdBackupPath"))
490 {
491 updateSystemVPDBackUpFRU(recordName, keyword, value);
492 }
493
Santosh Puranika0b23912022-02-10 13:37:09 +0530494 // If we have a redundant EEPROM to update, then update just the EEPROM,
495 // not the cache since that is already done when we updated the primary
496 if (!std::get<1>(frus.find(objPath)->second).empty())
497 {
498 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile,
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500499 recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530500 edit.updateKeyword(value, offset, false);
501 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600502
SunnySrivastava198443306542020-04-01 02:50:20 -0500503 // if it is a motehrboard FRU need to check for location expansion
Santosh Puranika0b23912022-02-10 13:37:09 +0530504 if (std::get<2>(frus.find(objPath)->second))
SunnySrivastava198443306542020-04-01 02:50:20 -0500505 {
506 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE"))
507 {
508 edit.expandLocationCode("fcs");
509 }
510 else if (recordName == "VSYS" &&
511 (keyword == "TM" || keyword == "SE"))
512 {
513 edit.expandLocationCode("mts");
514 }
515 }
516
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500517 return;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600518 }
519 catch (const std::exception& e)
520 {
521 std::cerr << e.what() << std::endl;
522 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600523}
524
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500525ListOfPaths
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600526 Manager::getFRUsByUnexpandedLocationCode(const LocationCode& locationCode,
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500527 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600528{
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500529 ReaderImpl read;
530 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600531}
532
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500533ListOfPaths
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600534 Manager::getFRUsByExpandedLocationCode(const LocationCode& locationCode)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600535{
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500536 ReaderImpl read;
537 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600538}
539
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600540LocationCode Manager::getExpandedLocationCode(const LocationCode& locationCode,
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500541 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600542{
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500543 ReaderImpl read;
544 return read.getExpandedLocationCode(locationCode, nodeNumber,
545 fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600546}
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600547
SunnySrivastava19849a195542020-09-07 06:04:50 -0500548void Manager::performVPDRecollection()
549{
550 // get list of FRUs replaceable at standby
551 for (const auto& item : replaceableFrus)
552 {
553 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
554 const nlohmann::json& singleFru = groupEEPROM[0];
555
556 const string& inventoryPath =
557 singleFru["inventoryPath"]
558 .get_ref<const nlohmann::json::string_t&>();
559
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530560 bool prePostActionRequired = false;
561
562 if ((jsonFile["frus"][item].at(0)).find("preAction") !=
563 jsonFile["frus"][item].at(0).end())
564 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500565 try
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530566 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500567 if (!executePreAction(jsonFile, item))
568 {
569 // if the FRU has preAction defined then its execution
570 // should pass to ensure bind/unbind of data.
571 // preAction execution failed. should not call
572 // bind/unbind.
573 log<level::ERR>(
574 "Pre-Action execution failed for the FRU",
575 entry("ERROR=%s",
576 ("Inventory path: " + inventoryPath).c_str()));
577 continue;
578 }
579 }
580 catch (const GpioException& e)
581 {
582 log<level::ERR>(e.what());
583 PelAdditionalData additionalData{};
584 additionalData.emplace("DESCRIPTION", e.what());
585 createPEL(additionalData, PelSeverity::WARNING,
586 errIntfForGpioError, sdBus);
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530587 continue;
588 }
589 prePostActionRequired = true;
590 }
591
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500592 // unbind, bind the driver to trigger parser.
593 triggerVpdCollection(singleFru, inventoryPath);
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530594
595 // this check is added to avoid file system expensive call in case not
596 // required.
597 if (prePostActionRequired)
598 {
599 // Check if device showed up (test for file)
600 if (!filesystem::exists(item))
601 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500602 try
603 {
604 // If not, then take failure postAction
605 executePostFailAction(jsonFile, item);
606 }
607 catch (const GpioException& e)
608 {
609 PelAdditionalData additionalData{};
610 additionalData.emplace("DESCRIPTION", e.what());
611 createPEL(additionalData, PelSeverity::WARNING,
612 errIntfForGpioError, sdBus);
613 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530614 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500615 else
616 {
617 // bind the LED driver
618 string chipAddr = singleFru.value("pcaChipAddress", "");
619 cout << "performVPDRecollection: Executing driver binding for "
620 "chip "
621 "address - "
622 << chipAddr << endl;
623
624 executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c",
625 "leds-pca955x", "/bind"));
626 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530627 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500628 }
629}
630
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500631void Manager::collectFRUVPD(const sdbusplus::message::object_path& path)
632{
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500633 std::cout << "Manager called to collect vpd for fru: " << std::string{path}
634 << std::endl;
635
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500636 using InvalidArgument =
637 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
638 using Argument = xyz::openbmc_project::Common::InvalidArgument;
639
Santosh Puranikbc599472022-12-19 20:17:10 +0530640 std::string objPath{path};
641
642 // Strip any inventory prefix in path
643 if (objPath.find(INVENTORY_PATH) == 0)
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500644 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530645 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500646 }
647
Santosh Puranikbc599472022-12-19 20:17:10 +0530648 // if path not found in Json.
649 if (frus.find(objPath) == frus.end())
650 {
651 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
652 Argument::ARGUMENT_VALUE(objPath.c_str()));
653 }
654
655 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500656
657 const std::vector<nlohmann::json>& groupEEPROM =
658 jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>();
659
Sunny Srivastavaab2304d2023-01-10 23:30:05 -0600660 nlohmann::json singleFru{};
661 for (const auto& item : groupEEPROM)
662 {
663 if (item["inventoryPath"] == objPath)
664 {
665 // this is the inventory we are looking for
666 singleFru = item;
667 break;
668 }
669 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500670
671 // check if the device qualifies for CM.
672 if (singleFru.value("concurrentlyMaintainable", false))
673 {
674 bool prePostActionRequired = false;
675
676 if ((jsonFile["frus"][vpdFilePath].at(0)).find("preAction") !=
677 jsonFile["frus"][vpdFilePath].at(0).end())
678 {
679 if (!executePreAction(jsonFile, vpdFilePath))
680 {
681 // if the FRU has preAction defined then its execution should
682 // pass to ensure bind/unbind of data.
683 // preAction execution failed. should not call bind/unbind.
684 log<level::ERR>("Pre-Action execution failed for the FRU");
685 return;
686 }
687
688 prePostActionRequired = true;
689 }
690
691 // unbind, bind the driver to trigger parser.
Santosh Puranikbc599472022-12-19 20:17:10 +0530692 triggerVpdCollection(singleFru, objPath);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500693
694 // this check is added to avoid file system expensive call in case not
695 // required.
696 if (prePostActionRequired)
697 {
698 // Check if device showed up (test for file)
699 if (!filesystem::exists(vpdFilePath))
700 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530701 try
702 {
703 // If not, then take failure postAction
704 executePostFailAction(jsonFile, vpdFilePath);
705 }
706 catch (const GpioException& e)
707 {
708 PelAdditionalData additionalData{};
709 additionalData.emplace("DESCRIPTION", e.what());
710 createPEL(additionalData, PelSeverity::WARNING,
711 errIntfForGpioError, sdBus);
712 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500713 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500714 else
715 {
716 // bind the LED driver
717 string chipAddr = jsonFile["frus"][vpdFilePath].at(0).value(
718 "pcaChipAddress", "");
719 cout << "Executing driver binding for chip address - "
720 << chipAddr << endl;
721
722 executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c",
723 "leds-pca955x", "/bind"));
724 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500725 }
726 return;
727 }
728 else
729 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530730 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
731 Argument::ARGUMENT_VALUE(objPath.c_str()));
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500732 }
733}
734
735void Manager::triggerVpdCollection(const nlohmann::json& singleFru,
736 const std::string& path)
737{
738 if ((singleFru.find("devAddress") == singleFru.end()) ||
739 (singleFru.find("driverType") == singleFru.end()) ||
740 (singleFru.find("busType") == singleFru.end()))
741 {
742 // The FRUs is marked for collection but missing mandatory
743 // fields for collection. Log error and return.
744 log<level::ERR>(
745 "Collection Failed as mandatory field missing in Json",
746 entry("ERROR=%s", ("Recollection failed for " + (path)).c_str()));
747
748 return;
749 }
750
751 string deviceAddress = singleFru["devAddress"];
752 const string& driverType = singleFru["driverType"];
753 const string& busType = singleFru["busType"];
754
755 // devTreeStatus flag is present in json as false to mention
756 // that the EEPROM is not mentioned in device tree. If this flag
757 // is absent consider the value to be true, i.e EEPROM is
758 // mentioned in device tree
759 if (!singleFru.value("devTreeStatus", true))
760 {
761 auto pos = deviceAddress.find('-');
762 if (pos != string::npos)
763 {
764 string busNum = deviceAddress.substr(0, pos);
765 deviceAddress = "0x" + deviceAddress.substr(pos + 1, string::npos);
766
767 string deleteDevice = "echo" + deviceAddress + " > /sys/bus/" +
768 busType + "/devices/" + busType + "-" +
769 busNum + "/delete_device";
770 executeCmd(deleteDevice);
771
772 string addDevice = "echo" + driverType + " " + deviceAddress +
773 " > /sys/bus/" + busType + "/devices/" +
774 busType + "-" + busNum + "/new_device";
775 executeCmd(addDevice);
776 }
777 else
778 {
779 const string& inventoryPath =
780 singleFru["inventoryPath"]
781 .get_ref<const nlohmann::json::string_t&>();
782
783 log<level::ERR>(
784 "Wrong format of device address in Json",
785 entry("ERROR=%s",
786 ("Recollection failed for " + inventoryPath).c_str()));
787 }
788 }
789 else
790 {
791 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
792 driverType, "/unbind"));
793 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
794 driverType, "/bind"));
795 }
796}
797
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500798void Manager::deleteFRUVPD(const sdbusplus::message::object_path& path)
799{
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500800 std::cout << "Manager called to delete vpd for fru: " << std::string{path}
801 << std::endl;
802
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500803 using InvalidArgument =
804 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
805 using Argument = xyz::openbmc_project::Common::InvalidArgument;
806
Santosh Puranikbc599472022-12-19 20:17:10 +0530807 std::string objPath{path};
808
809 // Strip any inventory prefix in path
810 if (objPath.find(INVENTORY_PATH) == 0)
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500811 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530812 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500813 }
814
Santosh Puranikbc599472022-12-19 20:17:10 +0530815 // if path not found in Json.
816 if (frus.find(objPath) == frus.end())
817 {
818 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
819 Argument::ARGUMENT_VALUE(objPath.c_str()));
820 }
821
822 inventory::Path& vpdFilePath = std::get<0>(frus.find(objPath)->second);
Alpana Kumari41d498c2021-09-16 00:29:12 -0500823
824 string chipAddress =
825 jsonFile["frus"][vpdFilePath].at(0).value("pcaChipAddress", "");
826
827 // Unbind the LED driver for this FRU
828 cout << "Unbinding device- " << chipAddress << endl;
829 executeCmd(createBindUnbindDriverCmnd(chipAddress, "i2c", "leds-pca955x",
830 "/unbind"));
831
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500832 // if the FRU is not present then log error
Santosh Puranikbc599472022-12-19 20:17:10 +0530833 if (readBusProperty(objPath, "xyz.openbmc_project.Inventory.Item",
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500834 "Present") == "false")
835 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530836 elog<InvalidArgument>(Argument::ARGUMENT_NAME("FRU not preset"),
837 Argument::ARGUMENT_VALUE(objPath.c_str()));
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500838 }
839 else
840 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530841 // Set present property of FRU as false as it has been removed.
842 // CC data for FRU is also removed as
843 // a) FRU is not there so CC does not make sense.
844 // b) Sensors dependent on Panel uses CC data.
845 inventory::InterfaceMap interfaces{
846 {"xyz.openbmc_project.Inventory.Item", {{"Present", false}}},
847 {"com.ibm.ipzvpd.VINI", {{"CC", Binary{}}}}};
848
849 inventory::ObjectMap objectMap;
850 objectMap.emplace(objPath, move(interfaces));
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500851
852 common::utility::callPIM(move(objectMap));
853 }
854}
855
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600856} // namespace manager
857} // namespace vpd
Patrick Williamsc78d8872023-05-10 07:50:56 -0500858} // namespace openpower