blob: 98e92384bf9347935df02b50fcb776bd52b5261c [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 Srivastavac6e7ea92023-11-03 21:10:43 +053035
Sunny Srivastava523af2e2022-02-14 07:30:10 -060036Manager::Manager(std::shared_ptr<boost::asio::io_context>& ioCon,
37 std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace,
38 std::shared_ptr<sdbusplus::asio::connection>& conn) :
39 ioContext(ioCon),
40 interface(iFace), conn(conn)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060041{
Sunny Srivastava523af2e2022-02-14 07:30:10 -060042 interface->register_method(
43 "WriteKeyword",
44 [this](const sdbusplus::message::object_path& path,
45 const std::string& recordName, const std::string& keyword,
46 const Binary& value) {
Patrick Williamsc78d8872023-05-10 07:50:56 -050047 this->writeKeyword(path, recordName, keyword, value);
Patrick Williamsb7b352a2023-10-20 11:19:19 -050048 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060049
50 interface->register_method(
51 "GetFRUsByUnexpandedLocationCode",
52 [this](const std::string& locationCode,
53 const uint16_t nodeNumber) -> inventory::ListOfPaths {
Patrick Williamsb7b352a2023-10-20 11:19:19 -050054 return this->getFRUsByUnexpandedLocationCode(locationCode, nodeNumber);
55 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060056
57 interface->register_method(
58 "GetFRUsByExpandedLocationCode",
59 [this](const std::string& locationCode) -> inventory::ListOfPaths {
Patrick Williamsb7b352a2023-10-20 11:19:19 -050060 return this->getFRUsByExpandedLocationCode(locationCode);
61 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060062
63 interface->register_method(
64 "GetExpandedLocationCode",
65 [this](const std::string& locationCode,
66 const uint16_t nodeNumber) -> std::string {
Patrick Williamsb7b352a2023-10-20 11:19:19 -050067 return this->getExpandedLocationCode(locationCode, nodeNumber);
68 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060069
70 interface->register_method("PerformVPDRecollection",
71 [this]() { this->performVPDRecollection(); });
72
Sunny Srivastava28abd6e2021-07-28 02:58:28 -050073 interface->register_method(
74 "deleteFRUVPD", [this](const sdbusplus::message::object_path& path) {
Patrick Williamsb7b352a2023-10-20 11:19:19 -050075 this->deleteFRUVPD(path);
76 });
Sunny Srivastava28abd6e2021-07-28 02:58:28 -050077
Sunny Srivastava6a1bd392021-06-02 04:39:24 -050078 interface->register_method(
79 "CollectFRUVPD", [this](const sdbusplus::message::object_path& path) {
Patrick Williamsb7b352a2023-10-20 11:19:19 -050080 this->collectFRUVPD(path);
81 });
Sunny Srivastava6a1bd392021-06-02 04:39:24 -050082
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -050083 sd_bus_default(&sdBus);
Sunny Srivastava523af2e2022-02-14 07:30:10 -060084 initManager();
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060085}
86
Sunny Srivastava523af2e2022-02-14 07:30:10 -060087void Manager::initManager()
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060088{
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060089 try
90 {
91 processJSON();
Santosh Puranik6b2b5372022-06-02 20:49:02 +053092 restoreSystemVpd();
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050093 listenHostState();
Santosh Puranikb62f6052022-04-06 18:37:54 +053094 listenAssetTag();
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050095
Santosh Puranikf2d3b532022-04-19 06:44:07 -050096 // Create an instance of the BIOS handler
Sunny Srivastava523af2e2022-02-14 07:30:10 -060097 biosHandler = std::make_shared<BiosHandler>(conn, *this);
Santosh Puranikf2d3b532022-04-19 06:44:07 -050098
Sunny Srivastava523af2e2022-02-14 07:30:10 -060099 // instantiate gpioMonitor class
100 gpioMon = std::make_shared<GpioMonitor>(jsonFile, ioContext);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600101 }
102 catch (const std::exception& e)
103 {
104 std::cerr << e.what() << "\n";
105 }
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600106}
107
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530108/**
109 * @brief An api to get list of blank system VPD properties.
110 * @param[in] vpdMap - IPZ vpd map.
111 * @param[in] objectPath - Object path for the FRU.
112 * @param[out] blankPropertyList - Properties which are blank in System VPD and
113 * needs to be updated as standby.
114 */
115static void
116 getListOfBlankSystemVpd(Parsed& vpdMap, const string& objectPath,
117 std::vector<RestoredEeproms>& blankPropertyList)
118{
119 for (const auto& systemRecKwdPair : svpdKwdMap)
120 {
121 auto it = vpdMap.find(systemRecKwdPair.first);
122
123 // check if record is found in map we got by parser
124 if (it != vpdMap.end())
125 {
126 const auto& kwdListForRecord = systemRecKwdPair.second;
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600127 for (const auto& keywordInfo : kwdListForRecord)
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530128 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600129 const auto& keyword = get<0>(keywordInfo);
130
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530131 DbusPropertyMap& kwdValMap = it->second;
132 auto iterator = kwdValMap.find(keyword);
133
134 if (iterator != kwdValMap.end())
135 {
136 string& kwdValue = iterator->second;
137
138 // check bus data
139 const string& recordName = systemRecKwdPair.first;
140 const string& busValue = readBusProperty(
141 objectPath, ipzVpdInf + recordName, keyword);
142
Priyanga Ramasamy834c0782023-02-14 12:22:39 -0600143 const auto& defaultValue = get<1>(keywordInfo);
144
145 if (Binary(busValue.begin(), busValue.end()) !=
146 defaultValue)
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530147 {
Priyanga Ramasamy834c0782023-02-14 12:22:39 -0600148 if (Binary(kwdValue.begin(), kwdValue.end()) ==
149 defaultValue)
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530150 {
151 // implies data is blank on EEPROM but not on cache.
152 // So EEPROM vpd update is required.
153 Binary busData(busValue.begin(), busValue.end());
154
155 blankPropertyList.push_back(std::make_tuple(
156 objectPath, recordName, keyword, busData));
157 }
158 }
159 }
160 }
161 }
162 }
163}
164
165void Manager::restoreSystemVpd()
166{
167 std::cout << "Attempting system VPD restore" << std::endl;
168 ParserInterface* parser = nullptr;
169 try
170 {
171 auto vpdVector = getVpdDataInVector(jsonFile, systemVpdFilePath);
girik18bb9852022-11-16 05:48:13 -0600172 uint32_t vpdStartOffset = 0;
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500173 const auto& inventoryPath =
174 jsonFile["frus"][systemVpdFilePath][0]["inventoryPath"]
175 .get_ref<const nlohmann::json::string_t&>();
176
girik18bb9852022-11-16 05:48:13 -0600177 parser = ParserFactory::getParser(vpdVector, (pimPath + inventoryPath),
178 systemVpdFilePath, vpdStartOffset);
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530179 auto parseResult = parser->parse();
180
181 if (auto pVal = std::get_if<Store>(&parseResult))
182 {
183 // map to hold all the keywords whose value is blank and
184 // needs to be updated at standby.
185 std::vector<RestoredEeproms> blankSystemVpdProperties{};
186 getListOfBlankSystemVpd(pVal->getVpdMap(), SYSTEM_OBJECT,
187 blankSystemVpdProperties);
188
189 // if system VPD restore is required, update the
190 // EEPROM
191 for (const auto& item : blankSystemVpdProperties)
192 {
193 std::cout << "Restoring keyword: " << std::get<2>(item)
194 << std::endl;
195 writeKeyword(std::get<0>(item), std::get<1>(item),
196 std::get<2>(item), std::get<3>(item));
197 }
198 }
199 else
200 {
201 std::cerr << "Not a valid format to restore system VPD"
202 << std::endl;
203 }
204 }
205 catch (const std::exception& e)
206 {
207 std::cerr << "Failed to restore system VPD due to exception: "
208 << e.what() << std::endl;
209 }
210 // release the parser object
211 ParserFactory::freeParser(parser);
212}
213
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500214void Manager::listenHostState()
215{
Patrick Williams2eb01762022-07-22 19:26:56 -0500216 static std::shared_ptr<sdbusplus::bus::match_t> hostState =
217 std::make_shared<sdbusplus::bus::match_t>(
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600218 *conn,
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500219 sdbusplus::bus::match::rules::propertiesChanged(
220 "/xyz/openbmc_project/state/host0",
221 "xyz.openbmc_project.State.Host"),
Patrick Williams2eb01762022-07-22 19:26:56 -0500222 [this](sdbusplus::message_t& msg) { hostStateCallBack(msg); });
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500223}
224
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500225void Manager::checkEssentialFrus()
226{
227 for (const auto& invPath : essentialFrus)
228 {
229 const auto res = readBusProperty(invPath, invItemIntf, "Present");
230
231 // implies the essential FRU is missing. Log PEL.
232 if (res == "false")
233 {
234 auto rc = sd_bus_call_method_async(
235 sdBus, NULL, loggerService, loggerObjectPath,
236 loggerCreateInterface, "Create", NULL, NULL, "ssa{ss}",
237 errIntfForEssentialFru,
238 "xyz.openbmc_project.Logging.Entry.Level.Warning", 2,
239 "DESCRIPTION", "Essential fru missing from the system.",
240 "CALLOUT_INVENTORY_PATH", (pimPath + invPath).c_str());
241
242 if (rc < 0)
243 {
244 log<level::ERR>("Error calling sd_bus_call_method_async",
245 entry("RC=%d", rc),
246 entry("MSG=%s", strerror(-rc)));
247 }
248 }
249 }
250}
251
Patrick Williams7a975f02022-12-07 03:19:53 -0600252void Manager::hostStateCallBack(sdbusplus::message_t& msg)
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500253{
254 if (msg.is_method_error())
255 {
256 std::cerr << "Error in reading signal " << std::endl;
257 }
258
259 Path object;
260 PropertyMap propMap;
261 msg.read(object, propMap);
262 const auto itr = propMap.find("CurrentHostState");
263 if (itr != propMap.end())
264 {
265 if (auto hostState = std::get_if<std::string>(&(itr->second)))
266 {
267 // implies system is moving from standby to power on state
268 if (*hostState == "xyz.openbmc_project.State.Host.HostState."
269 "TransitioningToRunning")
270 {
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500271 // detect if essential frus are present in the system.
272 checkEssentialFrus();
273
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500274 // check and perfrom recollection for FRUs replaceable at
275 // standby.
276 performVPDRecollection();
277 return;
278 }
279 }
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500280 }
281}
282
Santosh Puranikb62f6052022-04-06 18:37:54 +0530283void Manager::listenAssetTag()
284{
Patrick Williams2eb01762022-07-22 19:26:56 -0500285 static std::shared_ptr<sdbusplus::bus::match_t> assetMatcher =
286 std::make_shared<sdbusplus::bus::match_t>(
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600287 *conn,
Santosh Puranikb62f6052022-04-06 18:37:54 +0530288 sdbusplus::bus::match::rules::propertiesChanged(
289 "/xyz/openbmc_project/inventory/system",
290 "xyz.openbmc_project.Inventory.Decorator.AssetTag"),
Patrick Williams2eb01762022-07-22 19:26:56 -0500291 [this](sdbusplus::message_t& msg) { assetTagCallback(msg); });
Santosh Puranikb62f6052022-04-06 18:37:54 +0530292}
293
Patrick Williams2eb01762022-07-22 19:26:56 -0500294void Manager::assetTagCallback(sdbusplus::message_t& msg)
Santosh Puranikb62f6052022-04-06 18:37:54 +0530295{
296 if (msg.is_method_error())
297 {
298 std::cerr << "Error in reading signal " << std::endl;
299 }
300
301 Path object;
302 PropertyMap propMap;
303 msg.read(object, propMap);
304 const auto itr = propMap.find("AssetTag");
305 if (itr != propMap.end())
306 {
307 if (auto assetTag = std::get_if<std::string>(&(itr->second)))
308 {
309 // Call Notify to persist the AssetTag
310 inventory::ObjectMap objectMap = {
311 {std::string{"/system"},
312 {{"xyz.openbmc_project.Inventory.Decorator.AssetTag",
313 {{"AssetTag", *assetTag}}}}}};
314
315 common::utility::callPIM(std::move(objectMap));
316 }
317 else
318 {
319 std::cerr << "Failed to read asset tag" << std::endl;
320 }
321 }
322}
323
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600324void Manager::processJSON()
325{
Santosh Puranik0246a4d2020-11-04 16:57:39 +0530326 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600327
328 if (!json)
329 {
330 throw std::runtime_error("json file not found");
331 }
332
333 jsonFile = nlohmann::json::parse(json);
334 if (jsonFile.find("frus") == jsonFile.end())
335 {
336 throw std::runtime_error("frus group not found in json");
337 }
338
339 const nlohmann::json& groupFRUS =
340 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
341 for (const auto& itemFRUS : groupFRUS.items())
342 {
343 const std::vector<nlohmann::json>& groupEEPROM =
344 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
345 for (const auto& itemEEPROM : groupEEPROM)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600346 {
SunnySrivastava198443306542020-04-01 02:50:20 -0500347 bool isMotherboard = false;
Santosh Puranika0b23912022-02-10 13:37:09 +0530348 std::string redundantPath;
349
SunnySrivastava198443306542020-04-01 02:50:20 -0500350 if (itemEEPROM["extraInterfaces"].find(
351 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") !=
352 itemEEPROM["extraInterfaces"].end())
353 {
354 isMotherboard = true;
355 }
Santosh Puranika0b23912022-02-10 13:37:09 +0530356 if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end())
357 {
358 redundantPath = itemEEPROM["redundantEeprom"]
359 .get_ref<const nlohmann::json::string_t&>();
360 }
361 frus.emplace(
362 itemEEPROM["inventoryPath"]
363 .get_ref<const nlohmann::json::string_t&>(),
364 std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard));
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500365
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000366 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
Alpana Kumari920408d2020-05-14 00:07:03 -0500367 itemEEPROM["extraInterfaces"].end())
368 {
369 fruLocationCode.emplace(
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000370 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
Alpana Kumari920408d2020-05-14 00:07:03 -0500371 ["LocationCode"]
372 .get_ref<const nlohmann::json::string_t&>(),
373 itemEEPROM["inventoryPath"]
374 .get_ref<const nlohmann::json::string_t&>());
375 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500376
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500377 if (itemEEPROM.value("replaceableAtStandby", false))
SunnySrivastava19849a195542020-09-07 06:04:50 -0500378 {
379 replaceableFrus.emplace_back(itemFRUS.key());
380 }
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500381
382 if (itemEEPROM.value("essentialFru", false))
383 {
384 essentialFrus.emplace_back(itemEEPROM["inventoryPath"]);
385 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600386 }
387 }
388}
389
Sunny Srivastava83770862023-10-31 12:57:20 -0500390void Manager::updateSystemVPDBackUpFRU(const std::string& recordName,
391 const std::string& keyword,
392 const Binary& value)
393{
394 const std::string& systemVpdBackupPath =
395 jsonFile["frus"][systemVpdFilePath].at(0).value("systemVpdBackupPath",
396 "");
397
398 if (!systemVpdBackupPath.empty() &&
399 jsonFile["frus"][systemVpdBackupPath].at(0).contains("inventoryPath"))
400 {
401 std::string systemVpdBackupInvPath =
402 jsonFile["frus"][systemVpdBackupPath][0]["inventoryPath"]
403 .get_ref<const nlohmann::json::string_t&>();
404
405 const auto& itr = svpdKwdMap.find(recordName);
406 if (itr != svpdKwdMap.end())
407 {
408 auto systemKwdInfoList = itr->second;
409 const auto& itrToKwd = find_if(systemKwdInfoList.begin(),
410 systemKwdInfoList.end(),
411 [&keyword](const auto& kwdInfo) {
412 return (keyword == std::get<0>(kwdInfo));
413 });
414
415 if (itrToKwd != systemKwdInfoList.end())
416 {
417 EditorImpl edit(systemVpdBackupPath, jsonFile,
418 std::get<4>(*itrToKwd), std::get<5>(*itrToKwd),
419 systemVpdBackupInvPath);
420
421 // Setup offset, if any
422 uint32_t offset = 0;
423 if (jsonFile["frus"][systemVpdBackupPath].at(0).contains(
424 "offset"))
425 {
426 offset =
427 jsonFile["frus"][systemVpdBackupPath].at(0).contains(
428 "offset");
429 }
430
431 edit.updateKeyword(value, offset, true);
432 }
433 }
434 }
435 else
436 {
437 if (systemVpdBackupPath.empty())
438 {
439 throw std::runtime_error(
440 "Invalid entry for systemVpdBackupPath in JSON");
441 }
442 else
443 {
444 throw std::runtime_error(
445 "Inventory path missing for systemVpdBackupPath");
446 }
447 }
448}
449
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600450void Manager::writeKeyword(const sdbusplus::message::object_path& path,
451 const std::string& recordName,
452 const std::string& keyword, const Binary& value)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600453{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600454 try
455 {
Santosh Puranik8c796812021-12-01 19:17:56 +0530456 std::string objPath{path};
457 // Strip any inventory prefix in path
458 if (objPath.find(INVENTORY_PATH) == 0)
459 {
460 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
461 }
462
463 if (frus.find(objPath) == frus.end())
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600464 {
465 throw std::runtime_error("Inventory path not found");
466 }
467
Santosh Puranika0b23912022-02-10 13:37:09 +0530468 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600469
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500470 // instantiate editor class to update the data
Santosh Puranik8c796812021-12-01 19:17:56 +0530471 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530472
473 uint32_t offset = 0;
474 // Setup offset, if any
475 for (const auto& item : jsonFile["frus"][vpdFilePath])
476 {
477 if (item.find("offset") != item.end())
478 {
479 offset = item["offset"];
480 break;
481 }
482 }
483
484 edit.updateKeyword(value, offset, true);
485
Sunny Srivastava83770862023-10-31 12:57:20 -0500486 // If system VPD is being updated and system VPD is marked for back up
487 // on another FRU, update data on back up as well.
488 if (objPath == sdbusplus::message::object_path{SYSTEM_OBJECT} &&
489 jsonFile["frus"][systemVpdFilePath].at(0).contains(
490 "systemVpdBackupPath"))
491 {
492 updateSystemVPDBackUpFRU(recordName, keyword, value);
493 }
494
Santosh Puranika0b23912022-02-10 13:37:09 +0530495 // If we have a redundant EEPROM to update, then update just the EEPROM,
496 // not the cache since that is already done when we updated the primary
497 if (!std::get<1>(frus.find(objPath)->second).empty())
498 {
499 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile,
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500500 recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530501 edit.updateKeyword(value, offset, false);
502 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600503
SunnySrivastava198443306542020-04-01 02:50:20 -0500504 // if it is a motehrboard FRU need to check for location expansion
Santosh Puranika0b23912022-02-10 13:37:09 +0530505 if (std::get<2>(frus.find(objPath)->second))
SunnySrivastava198443306542020-04-01 02:50:20 -0500506 {
507 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE"))
508 {
509 edit.expandLocationCode("fcs");
510 }
511 else if (recordName == "VSYS" &&
512 (keyword == "TM" || keyword == "SE"))
513 {
514 edit.expandLocationCode("mts");
515 }
516 }
517
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500518 return;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600519 }
520 catch (const std::exception& e)
521 {
522 std::cerr << e.what() << std::endl;
523 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600524}
525
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500526ListOfPaths
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600527 Manager::getFRUsByUnexpandedLocationCode(const LocationCode& locationCode,
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500528 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600529{
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500530 ReaderImpl read;
531 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600532}
533
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500534ListOfPaths
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600535 Manager::getFRUsByExpandedLocationCode(const LocationCode& locationCode)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600536{
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500537 ReaderImpl read;
538 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600539}
540
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600541LocationCode Manager::getExpandedLocationCode(const LocationCode& locationCode,
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500542 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600543{
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500544 ReaderImpl read;
545 return read.getExpandedLocationCode(locationCode, nodeNumber,
546 fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600547}
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600548
SunnySrivastava19849a195542020-09-07 06:04:50 -0500549void Manager::performVPDRecollection()
550{
551 // get list of FRUs replaceable at standby
552 for (const auto& item : replaceableFrus)
553 {
554 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
555 const nlohmann::json& singleFru = groupEEPROM[0];
556
557 const string& inventoryPath =
558 singleFru["inventoryPath"]
559 .get_ref<const nlohmann::json::string_t&>();
560
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530561 bool prePostActionRequired = false;
562
563 if ((jsonFile["frus"][item].at(0)).find("preAction") !=
564 jsonFile["frus"][item].at(0).end())
565 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500566 try
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530567 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500568 if (!executePreAction(jsonFile, item))
569 {
570 // if the FRU has preAction defined then its execution
571 // should pass to ensure bind/unbind of data.
572 // preAction execution failed. should not call
573 // bind/unbind.
574 log<level::ERR>(
575 "Pre-Action execution failed for the FRU",
576 entry("ERROR=%s",
577 ("Inventory path: " + inventoryPath).c_str()));
578 continue;
579 }
580 }
581 catch (const GpioException& e)
582 {
583 log<level::ERR>(e.what());
584 PelAdditionalData additionalData{};
585 additionalData.emplace("DESCRIPTION", e.what());
586 createPEL(additionalData, PelSeverity::WARNING,
587 errIntfForGpioError, sdBus);
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530588 continue;
589 }
590 prePostActionRequired = true;
591 }
592
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500593 // unbind, bind the driver to trigger parser.
594 triggerVpdCollection(singleFru, inventoryPath);
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530595
596 // this check is added to avoid file system expensive call in case not
597 // required.
598 if (prePostActionRequired)
599 {
600 // Check if device showed up (test for file)
601 if (!filesystem::exists(item))
602 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500603 try
604 {
605 // If not, then take failure postAction
606 executePostFailAction(jsonFile, item);
607 }
608 catch (const GpioException& e)
609 {
610 PelAdditionalData additionalData{};
611 additionalData.emplace("DESCRIPTION", e.what());
612 createPEL(additionalData, PelSeverity::WARNING,
613 errIntfForGpioError, sdBus);
614 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530615 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500616 else
617 {
618 // bind the LED driver
619 string chipAddr = singleFru.value("pcaChipAddress", "");
620 cout << "performVPDRecollection: Executing driver binding for "
621 "chip "
622 "address - "
623 << chipAddr << endl;
624
625 executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c",
626 "leds-pca955x", "/bind"));
627 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530628 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500629 }
630}
631
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500632void Manager::collectFRUVPD(const sdbusplus::message::object_path& path)
633{
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500634 std::cout << "Manager called to collect vpd for fru: " << std::string{path}
635 << std::endl;
636
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500637 using InvalidArgument =
638 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
639 using Argument = xyz::openbmc_project::Common::InvalidArgument;
640
Santosh Puranikbc599472022-12-19 20:17:10 +0530641 std::string objPath{path};
642
643 // Strip any inventory prefix in path
644 if (objPath.find(INVENTORY_PATH) == 0)
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500645 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530646 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500647 }
648
Santosh Puranikbc599472022-12-19 20:17:10 +0530649 // if path not found in Json.
650 if (frus.find(objPath) == frus.end())
651 {
652 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
653 Argument::ARGUMENT_VALUE(objPath.c_str()));
654 }
655
656 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500657
658 const std::vector<nlohmann::json>& groupEEPROM =
659 jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>();
660
Sunny Srivastavaab2304d2023-01-10 23:30:05 -0600661 nlohmann::json singleFru{};
662 for (const auto& item : groupEEPROM)
663 {
664 if (item["inventoryPath"] == objPath)
665 {
666 // this is the inventory we are looking for
667 singleFru = item;
668 break;
669 }
670 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500671
672 // check if the device qualifies for CM.
673 if (singleFru.value("concurrentlyMaintainable", false))
674 {
675 bool prePostActionRequired = false;
676
677 if ((jsonFile["frus"][vpdFilePath].at(0)).find("preAction") !=
678 jsonFile["frus"][vpdFilePath].at(0).end())
679 {
680 if (!executePreAction(jsonFile, vpdFilePath))
681 {
682 // if the FRU has preAction defined then its execution should
683 // pass to ensure bind/unbind of data.
684 // preAction execution failed. should not call bind/unbind.
685 log<level::ERR>("Pre-Action execution failed for the FRU");
686 return;
687 }
688
689 prePostActionRequired = true;
690 }
691
692 // unbind, bind the driver to trigger parser.
Santosh Puranikbc599472022-12-19 20:17:10 +0530693 triggerVpdCollection(singleFru, objPath);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500694
695 // this check is added to avoid file system expensive call in case not
696 // required.
697 if (prePostActionRequired)
698 {
699 // Check if device showed up (test for file)
700 if (!filesystem::exists(vpdFilePath))
701 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530702 try
703 {
704 // If not, then take failure postAction
705 executePostFailAction(jsonFile, vpdFilePath);
706 }
707 catch (const GpioException& e)
708 {
709 PelAdditionalData additionalData{};
710 additionalData.emplace("DESCRIPTION", e.what());
711 createPEL(additionalData, PelSeverity::WARNING,
712 errIntfForGpioError, sdBus);
713 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500714 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500715 else
716 {
717 // bind the LED driver
718 string chipAddr = jsonFile["frus"][vpdFilePath].at(0).value(
719 "pcaChipAddress", "");
720 cout << "Executing driver binding for chip address - "
721 << chipAddr << endl;
722
723 executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c",
724 "leds-pca955x", "/bind"));
725 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500726 }
727 return;
728 }
729 else
730 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530731 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
732 Argument::ARGUMENT_VALUE(objPath.c_str()));
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500733 }
734}
735
736void Manager::triggerVpdCollection(const nlohmann::json& singleFru,
737 const std::string& path)
738{
739 if ((singleFru.find("devAddress") == singleFru.end()) ||
740 (singleFru.find("driverType") == singleFru.end()) ||
741 (singleFru.find("busType") == singleFru.end()))
742 {
743 // The FRUs is marked for collection but missing mandatory
744 // fields for collection. Log error and return.
745 log<level::ERR>(
746 "Collection Failed as mandatory field missing in Json",
747 entry("ERROR=%s", ("Recollection failed for " + (path)).c_str()));
748
749 return;
750 }
751
752 string deviceAddress = singleFru["devAddress"];
753 const string& driverType = singleFru["driverType"];
754 const string& busType = singleFru["busType"];
755
756 // devTreeStatus flag is present in json as false to mention
757 // that the EEPROM is not mentioned in device tree. If this flag
758 // is absent consider the value to be true, i.e EEPROM is
759 // mentioned in device tree
760 if (!singleFru.value("devTreeStatus", true))
761 {
762 auto pos = deviceAddress.find('-');
763 if (pos != string::npos)
764 {
765 string busNum = deviceAddress.substr(0, pos);
766 deviceAddress = "0x" + deviceAddress.substr(pos + 1, string::npos);
767
768 string deleteDevice = "echo" + deviceAddress + " > /sys/bus/" +
769 busType + "/devices/" + busType + "-" +
770 busNum + "/delete_device";
771 executeCmd(deleteDevice);
772
773 string addDevice = "echo" + driverType + " " + deviceAddress +
774 " > /sys/bus/" + busType + "/devices/" +
775 busType + "-" + busNum + "/new_device";
776 executeCmd(addDevice);
777 }
778 else
779 {
780 const string& inventoryPath =
781 singleFru["inventoryPath"]
782 .get_ref<const nlohmann::json::string_t&>();
783
784 log<level::ERR>(
785 "Wrong format of device address in Json",
786 entry("ERROR=%s",
787 ("Recollection failed for " + inventoryPath).c_str()));
788 }
789 }
790 else
791 {
792 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
793 driverType, "/unbind"));
794 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
795 driverType, "/bind"));
796 }
797}
798
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500799void Manager::deleteFRUVPD(const sdbusplus::message::object_path& path)
800{
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500801 std::cout << "Manager called to delete vpd for fru: " << std::string{path}
802 << std::endl;
803
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500804 using InvalidArgument =
805 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
806 using Argument = xyz::openbmc_project::Common::InvalidArgument;
807
Santosh Puranikbc599472022-12-19 20:17:10 +0530808 std::string objPath{path};
809
810 // Strip any inventory prefix in path
811 if (objPath.find(INVENTORY_PATH) == 0)
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500812 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530813 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500814 }
815
Santosh Puranikbc599472022-12-19 20:17:10 +0530816 // if path not found in Json.
817 if (frus.find(objPath) == frus.end())
818 {
819 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
820 Argument::ARGUMENT_VALUE(objPath.c_str()));
821 }
822
823 inventory::Path& vpdFilePath = std::get<0>(frus.find(objPath)->second);
Alpana Kumari41d498c2021-09-16 00:29:12 -0500824
825 string chipAddress =
826 jsonFile["frus"][vpdFilePath].at(0).value("pcaChipAddress", "");
827
828 // Unbind the LED driver for this FRU
829 cout << "Unbinding device- " << chipAddress << endl;
830 executeCmd(createBindUnbindDriverCmnd(chipAddress, "i2c", "leds-pca955x",
831 "/unbind"));
832
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500833 // if the FRU is not present then log error
Santosh Puranikbc599472022-12-19 20:17:10 +0530834 if (readBusProperty(objPath, "xyz.openbmc_project.Inventory.Item",
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500835 "Present") == "false")
836 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530837 elog<InvalidArgument>(Argument::ARGUMENT_NAME("FRU not preset"),
838 Argument::ARGUMENT_VALUE(objPath.c_str()));
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500839 }
840 else
841 {
Sunny Srivastavac6e7ea92023-11-03 21:10:43 +0530842 inventory::InterfaceMap interfacesPropMap;
843 clearVpdOnRemoval(INVENTORY_PATH + objPath, interfacesPropMap);
Santosh Puranikbc599472022-12-19 20:17:10 +0530844
845 inventory::ObjectMap objectMap;
Sunny Srivastavac6e7ea92023-11-03 21:10:43 +0530846 objectMap.emplace(objPath, move(interfacesPropMap));
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500847
848 common::utility::callPIM(move(objectMap));
849 }
850}
851
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600852} // namespace manager
853} // namespace vpd
Patrick Williamsc78d8872023-05-10 07:50:56 -0500854} // namespace openpower