blob: cdf7a631de1b2b874730bb82976f9758c26a6bb4 [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
Santosh Puranikd40e42d2022-03-23 13:58:06 +053013#include <filesystem>
SunnySrivastava19849a195542020-09-07 06:04:50 -050014#include <phosphor-logging/elog-errors.hpp>
Sunny Srivastava28abd6e2021-07-28 02:58:28 -050015#include <xyz/openbmc_project/Common/error.hpp>
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060016
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060017using namespace openpower::vpd::constants;
SunnySrivastava19841356d7e2020-04-24 04:29:35 -050018using namespace openpower::vpd::inventory;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060019using namespace openpower::vpd::manager::editor;
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -050020using namespace openpower::vpd::manager::reader;
SunnySrivastava19849a195542020-09-07 06:04:50 -050021using namespace std;
22using namespace openpower::vpd::parser;
Santosh Puranik6b2b5372022-06-02 20:49:02 +053023using namespace openpower::vpd::parser::factory;
24using namespace openpower::vpd::ipz::parser;
SunnySrivastava19849a195542020-09-07 06:04:50 -050025using namespace openpower::vpd::exceptions;
26using namespace phosphor::logging;
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060027
28namespace openpower
29{
30namespace vpd
31{
32namespace manager
33{
Sunny Srivastava523af2e2022-02-14 07:30:10 -060034Manager::Manager(std::shared_ptr<boost::asio::io_context>& ioCon,
35 std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace,
36 std::shared_ptr<sdbusplus::asio::connection>& conn) :
37 ioContext(ioCon),
38 interface(iFace), conn(conn)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060039{
Sunny Srivastava523af2e2022-02-14 07:30:10 -060040 interface->register_method(
41 "WriteKeyword",
42 [this](const sdbusplus::message::object_path& path,
43 const std::string& recordName, const std::string& keyword,
44 const Binary& value) {
45 this->writeKeyword(path, recordName, keyword, value);
46 });
47
48 interface->register_method(
49 "GetFRUsByUnexpandedLocationCode",
50 [this](const std::string& locationCode,
51 const uint16_t nodeNumber) -> inventory::ListOfPaths {
52 return this->getFRUsByUnexpandedLocationCode(locationCode,
53 nodeNumber);
54 });
55
56 interface->register_method(
57 "GetFRUsByExpandedLocationCode",
58 [this](const std::string& locationCode) -> inventory::ListOfPaths {
59 return this->getFRUsByExpandedLocationCode(locationCode);
60 });
61
62 interface->register_method(
63 "GetExpandedLocationCode",
64 [this](const std::string& locationCode,
65 const uint16_t nodeNumber) -> std::string {
66 return this->getExpandedLocationCode(locationCode, nodeNumber);
67 });
68
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) {
74 this->deleteFRUVPD(path);
75 });
76
Sunny Srivastava6a1bd392021-06-02 04:39:24 -050077 interface->register_method(
78 "CollectFRUVPD", [this](const sdbusplus::message::object_path& path) {
79 this->collectFRUVPD(path);
80 });
81
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
142 if (busValue.find_first_not_of(' ') != string::npos)
143 {
144 if (kwdValue.find_first_not_of(' ') == string::npos)
145 {
146 // implies data is blank on EEPROM but not on cache.
147 // So EEPROM vpd update is required.
148 Binary busData(busValue.begin(), busValue.end());
149
150 blankPropertyList.push_back(std::make_tuple(
151 objectPath, recordName, keyword, busData));
152 }
153 }
154 }
155 }
156 }
157 }
158}
159
160void Manager::restoreSystemVpd()
161{
162 std::cout << "Attempting system VPD restore" << std::endl;
163 ParserInterface* parser = nullptr;
164 try
165 {
166 auto vpdVector = getVpdDataInVector(jsonFile, systemVpdFilePath);
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500167 const auto& inventoryPath =
168 jsonFile["frus"][systemVpdFilePath][0]["inventoryPath"]
169 .get_ref<const nlohmann::json::string_t&>();
170
171 parser = ParserFactory::getParser(vpdVector, (pimPath + inventoryPath));
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530172 auto parseResult = parser->parse();
173
174 if (auto pVal = std::get_if<Store>(&parseResult))
175 {
176 // map to hold all the keywords whose value is blank and
177 // needs to be updated at standby.
178 std::vector<RestoredEeproms> blankSystemVpdProperties{};
179 getListOfBlankSystemVpd(pVal->getVpdMap(), SYSTEM_OBJECT,
180 blankSystemVpdProperties);
181
182 // if system VPD restore is required, update the
183 // EEPROM
184 for (const auto& item : blankSystemVpdProperties)
185 {
186 std::cout << "Restoring keyword: " << std::get<2>(item)
187 << std::endl;
188 writeKeyword(std::get<0>(item), std::get<1>(item),
189 std::get<2>(item), std::get<3>(item));
190 }
191 }
192 else
193 {
194 std::cerr << "Not a valid format to restore system VPD"
195 << std::endl;
196 }
197 }
198 catch (const std::exception& e)
199 {
200 std::cerr << "Failed to restore system VPD due to exception: "
201 << e.what() << std::endl;
202 }
203 // release the parser object
204 ParserFactory::freeParser(parser);
205}
206
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500207void Manager::listenHostState()
208{
Patrick Williams2eb01762022-07-22 19:26:56 -0500209 static std::shared_ptr<sdbusplus::bus::match_t> hostState =
210 std::make_shared<sdbusplus::bus::match_t>(
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600211 *conn,
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500212 sdbusplus::bus::match::rules::propertiesChanged(
213 "/xyz/openbmc_project/state/host0",
214 "xyz.openbmc_project.State.Host"),
Patrick Williams2eb01762022-07-22 19:26:56 -0500215 [this](sdbusplus::message_t& msg) { hostStateCallBack(msg); });
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500216}
217
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500218void Manager::checkEssentialFrus()
219{
220 for (const auto& invPath : essentialFrus)
221 {
222 const auto res = readBusProperty(invPath, invItemIntf, "Present");
223
224 // implies the essential FRU is missing. Log PEL.
225 if (res == "false")
226 {
227 auto rc = sd_bus_call_method_async(
228 sdBus, NULL, loggerService, loggerObjectPath,
229 loggerCreateInterface, "Create", NULL, NULL, "ssa{ss}",
230 errIntfForEssentialFru,
231 "xyz.openbmc_project.Logging.Entry.Level.Warning", 2,
232 "DESCRIPTION", "Essential fru missing from the system.",
233 "CALLOUT_INVENTORY_PATH", (pimPath + invPath).c_str());
234
235 if (rc < 0)
236 {
237 log<level::ERR>("Error calling sd_bus_call_method_async",
238 entry("RC=%d", rc),
239 entry("MSG=%s", strerror(-rc)));
240 }
241 }
242 }
243}
244
Patrick Williams7a975f02022-12-07 03:19:53 -0600245void Manager::hostStateCallBack(sdbusplus::message_t& msg)
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500246{
247 if (msg.is_method_error())
248 {
249 std::cerr << "Error in reading signal " << std::endl;
250 }
251
252 Path object;
253 PropertyMap propMap;
254 msg.read(object, propMap);
255 const auto itr = propMap.find("CurrentHostState");
256 if (itr != propMap.end())
257 {
258 if (auto hostState = std::get_if<std::string>(&(itr->second)))
259 {
260 // implies system is moving from standby to power on state
261 if (*hostState == "xyz.openbmc_project.State.Host.HostState."
262 "TransitioningToRunning")
263 {
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500264 // detect if essential frus are present in the system.
265 checkEssentialFrus();
266
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500267 // check and perfrom recollection for FRUs replaceable at
268 // standby.
269 performVPDRecollection();
270 return;
271 }
272 }
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500273 }
274}
275
Santosh Puranikb62f6052022-04-06 18:37:54 +0530276void Manager::listenAssetTag()
277{
Patrick Williams2eb01762022-07-22 19:26:56 -0500278 static std::shared_ptr<sdbusplus::bus::match_t> assetMatcher =
279 std::make_shared<sdbusplus::bus::match_t>(
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600280 *conn,
Santosh Puranikb62f6052022-04-06 18:37:54 +0530281 sdbusplus::bus::match::rules::propertiesChanged(
282 "/xyz/openbmc_project/inventory/system",
283 "xyz.openbmc_project.Inventory.Decorator.AssetTag"),
Patrick Williams2eb01762022-07-22 19:26:56 -0500284 [this](sdbusplus::message_t& msg) { assetTagCallback(msg); });
Santosh Puranikb62f6052022-04-06 18:37:54 +0530285}
286
Patrick Williams2eb01762022-07-22 19:26:56 -0500287void Manager::assetTagCallback(sdbusplus::message_t& msg)
Santosh Puranikb62f6052022-04-06 18:37:54 +0530288{
289 if (msg.is_method_error())
290 {
291 std::cerr << "Error in reading signal " << std::endl;
292 }
293
294 Path object;
295 PropertyMap propMap;
296 msg.read(object, propMap);
297 const auto itr = propMap.find("AssetTag");
298 if (itr != propMap.end())
299 {
300 if (auto assetTag = std::get_if<std::string>(&(itr->second)))
301 {
302 // Call Notify to persist the AssetTag
303 inventory::ObjectMap objectMap = {
304 {std::string{"/system"},
305 {{"xyz.openbmc_project.Inventory.Decorator.AssetTag",
306 {{"AssetTag", *assetTag}}}}}};
307
308 common::utility::callPIM(std::move(objectMap));
309 }
310 else
311 {
312 std::cerr << "Failed to read asset tag" << std::endl;
313 }
314 }
315}
316
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600317void Manager::processJSON()
318{
Santosh Puranik0246a4d2020-11-04 16:57:39 +0530319 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600320
321 if (!json)
322 {
323 throw std::runtime_error("json file not found");
324 }
325
326 jsonFile = nlohmann::json::parse(json);
327 if (jsonFile.find("frus") == jsonFile.end())
328 {
329 throw std::runtime_error("frus group not found in json");
330 }
331
332 const nlohmann::json& groupFRUS =
333 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
334 for (const auto& itemFRUS : groupFRUS.items())
335 {
336 const std::vector<nlohmann::json>& groupEEPROM =
337 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
338 for (const auto& itemEEPROM : groupEEPROM)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600339 {
SunnySrivastava198443306542020-04-01 02:50:20 -0500340 bool isMotherboard = false;
Santosh Puranika0b23912022-02-10 13:37:09 +0530341 std::string redundantPath;
342
SunnySrivastava198443306542020-04-01 02:50:20 -0500343 if (itemEEPROM["extraInterfaces"].find(
344 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") !=
345 itemEEPROM["extraInterfaces"].end())
346 {
347 isMotherboard = true;
348 }
Santosh Puranika0b23912022-02-10 13:37:09 +0530349 if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end())
350 {
351 redundantPath = itemEEPROM["redundantEeprom"]
352 .get_ref<const nlohmann::json::string_t&>();
353 }
354 frus.emplace(
355 itemEEPROM["inventoryPath"]
356 .get_ref<const nlohmann::json::string_t&>(),
357 std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard));
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500358
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000359 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
Alpana Kumari920408d2020-05-14 00:07:03 -0500360 itemEEPROM["extraInterfaces"].end())
361 {
362 fruLocationCode.emplace(
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000363 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
Alpana Kumari920408d2020-05-14 00:07:03 -0500364 ["LocationCode"]
365 .get_ref<const nlohmann::json::string_t&>(),
366 itemEEPROM["inventoryPath"]
367 .get_ref<const nlohmann::json::string_t&>());
368 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500369
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500370 if (itemEEPROM.value("replaceableAtStandby", false))
SunnySrivastava19849a195542020-09-07 06:04:50 -0500371 {
372 replaceableFrus.emplace_back(itemFRUS.key());
373 }
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500374
375 if (itemEEPROM.value("essentialFru", false))
376 {
377 essentialFrus.emplace_back(itemEEPROM["inventoryPath"]);
378 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600379 }
380 }
381}
382
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600383void Manager::writeKeyword(const sdbusplus::message::object_path& path,
384 const std::string& recordName,
385 const std::string& keyword, const Binary& value)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600386{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600387 try
388 {
Santosh Puranik8c796812021-12-01 19:17:56 +0530389 std::string objPath{path};
390 // Strip any inventory prefix in path
391 if (objPath.find(INVENTORY_PATH) == 0)
392 {
393 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
394 }
395
396 if (frus.find(objPath) == frus.end())
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600397 {
398 throw std::runtime_error("Inventory path not found");
399 }
400
Santosh Puranika0b23912022-02-10 13:37:09 +0530401 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600402
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500403 // instantiate editor class to update the data
Santosh Puranik8c796812021-12-01 19:17:56 +0530404 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530405
406 uint32_t offset = 0;
407 // Setup offset, if any
408 for (const auto& item : jsonFile["frus"][vpdFilePath])
409 {
410 if (item.find("offset") != item.end())
411 {
412 offset = item["offset"];
413 break;
414 }
415 }
416
417 edit.updateKeyword(value, offset, true);
418
419 // If we have a redundant EEPROM to update, then update just the EEPROM,
420 // not the cache since that is already done when we updated the primary
421 if (!std::get<1>(frus.find(objPath)->second).empty())
422 {
423 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile,
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500424 recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530425 edit.updateKeyword(value, offset, false);
426 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600427
SunnySrivastava198443306542020-04-01 02:50:20 -0500428 // if it is a motehrboard FRU need to check for location expansion
Santosh Puranika0b23912022-02-10 13:37:09 +0530429 if (std::get<2>(frus.find(objPath)->second))
SunnySrivastava198443306542020-04-01 02:50:20 -0500430 {
431 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE"))
432 {
433 edit.expandLocationCode("fcs");
434 }
435 else if (recordName == "VSYS" &&
436 (keyword == "TM" || keyword == "SE"))
437 {
438 edit.expandLocationCode("mts");
439 }
440 }
441
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500442 return;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600443 }
444 catch (const std::exception& e)
445 {
446 std::cerr << e.what() << std::endl;
447 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600448}
449
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500450ListOfPaths
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600451 Manager::getFRUsByUnexpandedLocationCode(const LocationCode& locationCode,
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500452 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600453{
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500454 ReaderImpl read;
455 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600456}
457
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500458ListOfPaths
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600459 Manager::getFRUsByExpandedLocationCode(const LocationCode& locationCode)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600460{
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500461 ReaderImpl read;
462 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600463}
464
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600465LocationCode Manager::getExpandedLocationCode(const LocationCode& locationCode,
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500466 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600467{
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500468 ReaderImpl read;
469 return read.getExpandedLocationCode(locationCode, nodeNumber,
470 fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600471}
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600472
SunnySrivastava19849a195542020-09-07 06:04:50 -0500473void Manager::performVPDRecollection()
474{
475 // get list of FRUs replaceable at standby
476 for (const auto& item : replaceableFrus)
477 {
478 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
479 const nlohmann::json& singleFru = groupEEPROM[0];
480
481 const string& inventoryPath =
482 singleFru["inventoryPath"]
483 .get_ref<const nlohmann::json::string_t&>();
484
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530485 bool prePostActionRequired = false;
486
487 if ((jsonFile["frus"][item].at(0)).find("preAction") !=
488 jsonFile["frus"][item].at(0).end())
489 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500490 try
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530491 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500492 if (!executePreAction(jsonFile, item))
493 {
494 // if the FRU has preAction defined then its execution
495 // should pass to ensure bind/unbind of data.
496 // preAction execution failed. should not call
497 // bind/unbind.
498 log<level::ERR>(
499 "Pre-Action execution failed for the FRU",
500 entry("ERROR=%s",
501 ("Inventory path: " + inventoryPath).c_str()));
502 continue;
503 }
504 }
505 catch (const GpioException& e)
506 {
507 log<level::ERR>(e.what());
508 PelAdditionalData additionalData{};
509 additionalData.emplace("DESCRIPTION", e.what());
510 createPEL(additionalData, PelSeverity::WARNING,
511 errIntfForGpioError, sdBus);
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530512 continue;
513 }
514 prePostActionRequired = true;
515 }
516
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500517 // unbind, bind the driver to trigger parser.
518 triggerVpdCollection(singleFru, inventoryPath);
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530519
520 // this check is added to avoid file system expensive call in case not
521 // required.
522 if (prePostActionRequired)
523 {
524 // Check if device showed up (test for file)
525 if (!filesystem::exists(item))
526 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500527 try
528 {
529 // If not, then take failure postAction
530 executePostFailAction(jsonFile, item);
531 }
532 catch (const GpioException& e)
533 {
534 PelAdditionalData additionalData{};
535 additionalData.emplace("DESCRIPTION", e.what());
536 createPEL(additionalData, PelSeverity::WARNING,
537 errIntfForGpioError, sdBus);
538 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530539 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500540 else
541 {
542 // bind the LED driver
543 string chipAddr = singleFru.value("pcaChipAddress", "");
544 cout << "performVPDRecollection: Executing driver binding for "
545 "chip "
546 "address - "
547 << chipAddr << endl;
548
549 executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c",
550 "leds-pca955x", "/bind"));
551 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530552 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500553 }
554}
555
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500556void Manager::collectFRUVPD(const sdbusplus::message::object_path& path)
557{
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500558 std::cout << "Manager called to collect vpd for fru: " << std::string{path}
559 << std::endl;
560
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500561 using InvalidArgument =
562 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
563 using Argument = xyz::openbmc_project::Common::InvalidArgument;
564
Santosh Puranikbc599472022-12-19 20:17:10 +0530565 std::string objPath{path};
566
567 // Strip any inventory prefix in path
568 if (objPath.find(INVENTORY_PATH) == 0)
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500569 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530570 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500571 }
572
Santosh Puranikbc599472022-12-19 20:17:10 +0530573 // if path not found in Json.
574 if (frus.find(objPath) == frus.end())
575 {
576 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
577 Argument::ARGUMENT_VALUE(objPath.c_str()));
578 }
579
580 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500581
582 const std::vector<nlohmann::json>& groupEEPROM =
583 jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>();
584
Sunny Srivastavaab2304d2023-01-10 23:30:05 -0600585 nlohmann::json singleFru{};
586 for (const auto& item : groupEEPROM)
587 {
588 if (item["inventoryPath"] == objPath)
589 {
590 // this is the inventory we are looking for
591 singleFru = item;
592 break;
593 }
594 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500595
596 // check if the device qualifies for CM.
597 if (singleFru.value("concurrentlyMaintainable", false))
598 {
599 bool prePostActionRequired = false;
600
601 if ((jsonFile["frus"][vpdFilePath].at(0)).find("preAction") !=
602 jsonFile["frus"][vpdFilePath].at(0).end())
603 {
604 if (!executePreAction(jsonFile, vpdFilePath))
605 {
606 // if the FRU has preAction defined then its execution should
607 // pass to ensure bind/unbind of data.
608 // preAction execution failed. should not call bind/unbind.
609 log<level::ERR>("Pre-Action execution failed for the FRU");
610 return;
611 }
612
613 prePostActionRequired = true;
614 }
615
616 // unbind, bind the driver to trigger parser.
Santosh Puranikbc599472022-12-19 20:17:10 +0530617 triggerVpdCollection(singleFru, objPath);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500618
619 // this check is added to avoid file system expensive call in case not
620 // required.
621 if (prePostActionRequired)
622 {
623 // Check if device showed up (test for file)
624 if (!filesystem::exists(vpdFilePath))
625 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530626 try
627 {
628 // If not, then take failure postAction
629 executePostFailAction(jsonFile, vpdFilePath);
630 }
631 catch (const GpioException& e)
632 {
633 PelAdditionalData additionalData{};
634 additionalData.emplace("DESCRIPTION", e.what());
635 createPEL(additionalData, PelSeverity::WARNING,
636 errIntfForGpioError, sdBus);
637 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500638 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500639 else
640 {
641 // bind the LED driver
642 string chipAddr = jsonFile["frus"][vpdFilePath].at(0).value(
643 "pcaChipAddress", "");
644 cout << "Executing driver binding for chip address - "
645 << chipAddr << endl;
646
647 executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c",
648 "leds-pca955x", "/bind"));
649 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500650 }
651 return;
652 }
653 else
654 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530655 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
656 Argument::ARGUMENT_VALUE(objPath.c_str()));
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500657 }
658}
659
660void Manager::triggerVpdCollection(const nlohmann::json& singleFru,
661 const std::string& path)
662{
663 if ((singleFru.find("devAddress") == singleFru.end()) ||
664 (singleFru.find("driverType") == singleFru.end()) ||
665 (singleFru.find("busType") == singleFru.end()))
666 {
667 // The FRUs is marked for collection but missing mandatory
668 // fields for collection. Log error and return.
669 log<level::ERR>(
670 "Collection Failed as mandatory field missing in Json",
671 entry("ERROR=%s", ("Recollection failed for " + (path)).c_str()));
672
673 return;
674 }
675
676 string deviceAddress = singleFru["devAddress"];
677 const string& driverType = singleFru["driverType"];
678 const string& busType = singleFru["busType"];
679
680 // devTreeStatus flag is present in json as false to mention
681 // that the EEPROM is not mentioned in device tree. If this flag
682 // is absent consider the value to be true, i.e EEPROM is
683 // mentioned in device tree
684 if (!singleFru.value("devTreeStatus", true))
685 {
686 auto pos = deviceAddress.find('-');
687 if (pos != string::npos)
688 {
689 string busNum = deviceAddress.substr(0, pos);
690 deviceAddress = "0x" + deviceAddress.substr(pos + 1, string::npos);
691
692 string deleteDevice = "echo" + deviceAddress + " > /sys/bus/" +
693 busType + "/devices/" + busType + "-" +
694 busNum + "/delete_device";
695 executeCmd(deleteDevice);
696
697 string addDevice = "echo" + driverType + " " + deviceAddress +
698 " > /sys/bus/" + busType + "/devices/" +
699 busType + "-" + busNum + "/new_device";
700 executeCmd(addDevice);
701 }
702 else
703 {
704 const string& inventoryPath =
705 singleFru["inventoryPath"]
706 .get_ref<const nlohmann::json::string_t&>();
707
708 log<level::ERR>(
709 "Wrong format of device address in Json",
710 entry("ERROR=%s",
711 ("Recollection failed for " + inventoryPath).c_str()));
712 }
713 }
714 else
715 {
716 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
717 driverType, "/unbind"));
718 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
719 driverType, "/bind"));
720 }
721}
722
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500723void Manager::deleteFRUVPD(const sdbusplus::message::object_path& path)
724{
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500725 std::cout << "Manager called to delete vpd for fru: " << std::string{path}
726 << std::endl;
727
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500728 using InvalidArgument =
729 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
730 using Argument = xyz::openbmc_project::Common::InvalidArgument;
731
Santosh Puranikbc599472022-12-19 20:17:10 +0530732 std::string objPath{path};
733
734 // Strip any inventory prefix in path
735 if (objPath.find(INVENTORY_PATH) == 0)
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500736 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530737 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500738 }
739
Santosh Puranikbc599472022-12-19 20:17:10 +0530740 // if path not found in Json.
741 if (frus.find(objPath) == frus.end())
742 {
743 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
744 Argument::ARGUMENT_VALUE(objPath.c_str()));
745 }
746
747 inventory::Path& vpdFilePath = std::get<0>(frus.find(objPath)->second);
Alpana Kumari41d498c2021-09-16 00:29:12 -0500748
749 string chipAddress =
750 jsonFile["frus"][vpdFilePath].at(0).value("pcaChipAddress", "");
751
752 // Unbind the LED driver for this FRU
753 cout << "Unbinding device- " << chipAddress << endl;
754 executeCmd(createBindUnbindDriverCmnd(chipAddress, "i2c", "leds-pca955x",
755 "/unbind"));
756
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500757 // if the FRU is not present then log error
Santosh Puranikbc599472022-12-19 20:17:10 +0530758 if (readBusProperty(objPath, "xyz.openbmc_project.Inventory.Item",
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500759 "Present") == "false")
760 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530761 elog<InvalidArgument>(Argument::ARGUMENT_NAME("FRU not preset"),
762 Argument::ARGUMENT_VALUE(objPath.c_str()));
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500763 }
764 else
765 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530766 // Set present property of FRU as false as it has been removed.
767 // CC data for FRU is also removed as
768 // a) FRU is not there so CC does not make sense.
769 // b) Sensors dependent on Panel uses CC data.
770 inventory::InterfaceMap interfaces{
771 {"xyz.openbmc_project.Inventory.Item", {{"Present", false}}},
772 {"com.ibm.ipzvpd.VINI", {{"CC", Binary{}}}}};
773
774 inventory::ObjectMap objectMap;
775 objectMap.emplace(objPath, move(interfaces));
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500776
777 common::utility::callPIM(move(objectMap));
778 }
779}
780
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600781} // namespace manager
782} // namespace vpd
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500783} // namespace openpower