blob: 156bbcceb1bbe318a008ae78f66a2d41e6025c10 [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
Sunny Srivastava4788e1b2024-03-19 02:11:07 -050013#include <unistd.h>
14
SunnySrivastava19849a195542020-09-07 06:04:50 -050015#include <phosphor-logging/elog-errors.hpp>
Sunny Srivastava28abd6e2021-07-28 02:58:28 -050016#include <xyz/openbmc_project/Common/error.hpp>
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060017
Patrick Williamsc78d8872023-05-10 07:50:56 -050018#include <filesystem>
19
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060020using namespace openpower::vpd::constants;
SunnySrivastava19841356d7e2020-04-24 04:29:35 -050021using namespace openpower::vpd::inventory;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060022using namespace openpower::vpd::manager::editor;
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -050023using namespace openpower::vpd::manager::reader;
SunnySrivastava19849a195542020-09-07 06:04:50 -050024using namespace std;
25using namespace openpower::vpd::parser;
Santosh Puranik6b2b5372022-06-02 20:49:02 +053026using namespace openpower::vpd::parser::factory;
27using namespace openpower::vpd::ipz::parser;
SunnySrivastava19849a195542020-09-07 06:04:50 -050028using namespace openpower::vpd::exceptions;
29using namespace phosphor::logging;
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060030
31namespace openpower
32{
33namespace vpd
34{
35namespace manager
36{
Sunny Srivastavac6e7ea92023-11-03 21:10:43 +053037
Sunny Srivastava523af2e2022-02-14 07:30:10 -060038Manager::Manager(std::shared_ptr<boost::asio::io_context>& ioCon,
39 std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace,
40 std::shared_ptr<sdbusplus::asio::connection>& conn) :
Patrick Williams08dc31c2024-08-16 15:21:06 -040041 ioContext(ioCon), interface(iFace), conn(conn)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060042{
Sunny Srivastava523af2e2022-02-14 07:30:10 -060043 interface->register_method(
44 "WriteKeyword",
45 [this](const sdbusplus::message::object_path& path,
46 const std::string& recordName, const std::string& keyword,
47 const Binary& value) {
Patrick Williams08dc31c2024-08-16 15:21:06 -040048 this->writeKeyword(path, recordName, keyword, value);
49 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060050
51 interface->register_method(
52 "GetFRUsByUnexpandedLocationCode",
53 [this](const std::string& locationCode,
54 const uint16_t nodeNumber) -> inventory::ListOfPaths {
Patrick Williams08dc31c2024-08-16 15:21:06 -040055 return this->getFRUsByUnexpandedLocationCode(locationCode,
56 nodeNumber);
57 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060058
59 interface->register_method(
60 "GetFRUsByExpandedLocationCode",
61 [this](const std::string& locationCode) -> inventory::ListOfPaths {
Patrick Williams08dc31c2024-08-16 15:21:06 -040062 return this->getFRUsByExpandedLocationCode(locationCode);
63 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060064
65 interface->register_method(
66 "GetExpandedLocationCode",
67 [this](const std::string& locationCode,
68 const uint16_t nodeNumber) -> std::string {
Patrick Williams08dc31c2024-08-16 15:21:06 -040069 return this->getExpandedLocationCode(locationCode, nodeNumber);
70 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060071
Patrick Williams08dc31c2024-08-16 15:21:06 -040072 interface->register_method("PerformVPDRecollection", [this]() {
73 this->performVPDRecollection();
74 });
Sunny Srivastava523af2e2022-02-14 07:30:10 -060075
Sunny Srivastava28abd6e2021-07-28 02:58:28 -050076 interface->register_method(
77 "deleteFRUVPD", [this](const sdbusplus::message::object_path& path) {
Patrick Williams08dc31c2024-08-16 15:21:06 -040078 this->deleteFRUVPD(path);
79 });
Sunny Srivastava28abd6e2021-07-28 02:58:28 -050080
Sunny Srivastava6a1bd392021-06-02 04:39:24 -050081 interface->register_method(
82 "CollectFRUVPD", [this](const sdbusplus::message::object_path& path) {
Patrick Williams08dc31c2024-08-16 15:21:06 -040083 this->collectFRUVPD(path);
84 });
Sunny Srivastava6a1bd392021-06-02 04:39:24 -050085
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -050086 sd_bus_default(&sdBus);
Sunny Srivastava523af2e2022-02-14 07:30:10 -060087 initManager();
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060088}
89
Sunny Srivastava523af2e2022-02-14 07:30:10 -060090void Manager::initManager()
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060091{
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060092 try
93 {
94 processJSON();
Santosh Puranik6b2b5372022-06-02 20:49:02 +053095 restoreSystemVpd();
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050096 listenHostState();
Santosh Puranikb62f6052022-04-06 18:37:54 +053097 listenAssetTag();
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050098
Santosh Puranikf2d3b532022-04-19 06:44:07 -050099 // Create an instance of the BIOS handler
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600100 biosHandler = std::make_shared<BiosHandler>(conn, *this);
Santosh Puranikf2d3b532022-04-19 06:44:07 -0500101
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600102 // instantiate gpioMonitor class
103 gpioMon = std::make_shared<GpioMonitor>(jsonFile, ioContext);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600104 }
105 catch (const std::exception& e)
106 {
107 std::cerr << e.what() << "\n";
108 }
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600109}
110
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530111/**
112 * @brief An api to get list of blank system VPD properties.
113 * @param[in] vpdMap - IPZ vpd map.
114 * @param[in] objectPath - Object path for the FRU.
115 * @param[out] blankPropertyList - Properties which are blank in System VPD and
116 * needs to be updated as standby.
117 */
118static void
119 getListOfBlankSystemVpd(Parsed& vpdMap, const string& objectPath,
120 std::vector<RestoredEeproms>& blankPropertyList)
121{
122 for (const auto& systemRecKwdPair : svpdKwdMap)
123 {
124 auto it = vpdMap.find(systemRecKwdPair.first);
125
126 // check if record is found in map we got by parser
127 if (it != vpdMap.end())
128 {
129 const auto& kwdListForRecord = systemRecKwdPair.second;
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600130 for (const auto& keywordInfo : kwdListForRecord)
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530131 {
Priyanga Ramasamy952d6c52022-11-07 07:20:24 -0600132 const auto& keyword = get<0>(keywordInfo);
133
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530134 DbusPropertyMap& kwdValMap = it->second;
135 auto iterator = kwdValMap.find(keyword);
136
137 if (iterator != kwdValMap.end())
138 {
139 string& kwdValue = iterator->second;
140
141 // check bus data
142 const string& recordName = systemRecKwdPair.first;
143 const string& busValue = readBusProperty(
144 objectPath, ipzVpdInf + recordName, keyword);
145
Priyanga Ramasamy834c0782023-02-14 12:22:39 -0600146 const auto& defaultValue = get<1>(keywordInfo);
147
148 if (Binary(busValue.begin(), busValue.end()) !=
149 defaultValue)
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530150 {
Priyanga Ramasamy834c0782023-02-14 12:22:39 -0600151 if (Binary(kwdValue.begin(), kwdValue.end()) ==
152 defaultValue)
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530153 {
154 // implies data is blank on EEPROM but not on cache.
155 // So EEPROM vpd update is required.
156 Binary busData(busValue.begin(), busValue.end());
157
158 blankPropertyList.push_back(std::make_tuple(
159 objectPath, recordName, keyword, busData));
160 }
161 }
162 }
163 }
164 }
165 }
166}
167
168void Manager::restoreSystemVpd()
169{
170 std::cout << "Attempting system VPD restore" << std::endl;
171 ParserInterface* parser = nullptr;
172 try
173 {
174 auto vpdVector = getVpdDataInVector(jsonFile, systemVpdFilePath);
girik18bb9852022-11-16 05:48:13 -0600175 uint32_t vpdStartOffset = 0;
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500176 const auto& inventoryPath =
177 jsonFile["frus"][systemVpdFilePath][0]["inventoryPath"]
178 .get_ref<const nlohmann::json::string_t&>();
179
girik18bb9852022-11-16 05:48:13 -0600180 parser = ParserFactory::getParser(vpdVector, (pimPath + inventoryPath),
181 systemVpdFilePath, vpdStartOffset);
Santosh Puranik6b2b5372022-06-02 20:49:02 +0530182 auto parseResult = parser->parse();
183
184 if (auto pVal = std::get_if<Store>(&parseResult))
185 {
186 // map to hold all the keywords whose value is blank and
187 // needs to be updated at standby.
188 std::vector<RestoredEeproms> blankSystemVpdProperties{};
189 getListOfBlankSystemVpd(pVal->getVpdMap(), SYSTEM_OBJECT,
190 blankSystemVpdProperties);
191
192 // if system VPD restore is required, update the
193 // EEPROM
194 for (const auto& item : blankSystemVpdProperties)
195 {
196 std::cout << "Restoring keyword: " << std::get<2>(item)
197 << std::endl;
198 writeKeyword(std::get<0>(item), std::get<1>(item),
199 std::get<2>(item), std::get<3>(item));
200 }
201 }
202 else
203 {
204 std::cerr << "Not a valid format to restore system VPD"
205 << std::endl;
206 }
207 }
208 catch (const std::exception& e)
209 {
210 std::cerr << "Failed to restore system VPD due to exception: "
211 << e.what() << std::endl;
212 }
213 // release the parser object
214 ParserFactory::freeParser(parser);
215}
216
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500217void Manager::listenHostState()
218{
Patrick Williams2eb01762022-07-22 19:26:56 -0500219 static std::shared_ptr<sdbusplus::bus::match_t> hostState =
220 std::make_shared<sdbusplus::bus::match_t>(
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600221 *conn,
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500222 sdbusplus::bus::match::rules::propertiesChanged(
223 "/xyz/openbmc_project/state/host0",
224 "xyz.openbmc_project.State.Host"),
Patrick Williams2eb01762022-07-22 19:26:56 -0500225 [this](sdbusplus::message_t& msg) { hostStateCallBack(msg); });
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500226}
227
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500228void Manager::checkEssentialFrus()
229{
230 for (const auto& invPath : essentialFrus)
231 {
232 const auto res = readBusProperty(invPath, invItemIntf, "Present");
233
234 // implies the essential FRU is missing. Log PEL.
235 if (res == "false")
236 {
237 auto rc = sd_bus_call_method_async(
238 sdBus, NULL, loggerService, loggerObjectPath,
239 loggerCreateInterface, "Create", NULL, NULL, "ssa{ss}",
240 errIntfForEssentialFru,
241 "xyz.openbmc_project.Logging.Entry.Level.Warning", 2,
242 "DESCRIPTION", "Essential fru missing from the system.",
243 "CALLOUT_INVENTORY_PATH", (pimPath + invPath).c_str());
244
245 if (rc < 0)
246 {
247 log<level::ERR>("Error calling sd_bus_call_method_async",
248 entry("RC=%d", rc),
249 entry("MSG=%s", strerror(-rc)));
250 }
251 }
252 }
253}
254
Patrick Williams7a975f02022-12-07 03:19:53 -0600255void Manager::hostStateCallBack(sdbusplus::message_t& msg)
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500256{
257 if (msg.is_method_error())
258 {
259 std::cerr << "Error in reading signal " << std::endl;
260 }
261
262 Path object;
263 PropertyMap propMap;
264 msg.read(object, propMap);
265 const auto itr = propMap.find("CurrentHostState");
266 if (itr != propMap.end())
267 {
268 if (auto hostState = std::get_if<std::string>(&(itr->second)))
269 {
270 // implies system is moving from standby to power on state
271 if (*hostState == "xyz.openbmc_project.State.Host.HostState."
272 "TransitioningToRunning")
273 {
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500274 // detect if essential frus are present in the system.
275 checkEssentialFrus();
276
Manojkiran Edaaf921752024-06-17 15:10:21 +0530277 // check and perform recollection for FRUs replaceable at
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500278 // standby.
279 performVPDRecollection();
280 return;
281 }
282 }
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500283 }
284}
285
Santosh Puranikb62f6052022-04-06 18:37:54 +0530286void Manager::listenAssetTag()
287{
Patrick Williams2eb01762022-07-22 19:26:56 -0500288 static std::shared_ptr<sdbusplus::bus::match_t> assetMatcher =
289 std::make_shared<sdbusplus::bus::match_t>(
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600290 *conn,
Santosh Puranikb62f6052022-04-06 18:37:54 +0530291 sdbusplus::bus::match::rules::propertiesChanged(
292 "/xyz/openbmc_project/inventory/system",
293 "xyz.openbmc_project.Inventory.Decorator.AssetTag"),
Patrick Williams2eb01762022-07-22 19:26:56 -0500294 [this](sdbusplus::message_t& msg) { assetTagCallback(msg); });
Santosh Puranikb62f6052022-04-06 18:37:54 +0530295}
296
Patrick Williams2eb01762022-07-22 19:26:56 -0500297void Manager::assetTagCallback(sdbusplus::message_t& msg)
Santosh Puranikb62f6052022-04-06 18:37:54 +0530298{
299 if (msg.is_method_error())
300 {
301 std::cerr << "Error in reading signal " << std::endl;
302 }
303
304 Path object;
305 PropertyMap propMap;
306 msg.read(object, propMap);
307 const auto itr = propMap.find("AssetTag");
308 if (itr != propMap.end())
309 {
310 if (auto assetTag = std::get_if<std::string>(&(itr->second)))
311 {
312 // Call Notify to persist the AssetTag
313 inventory::ObjectMap objectMap = {
314 {std::string{"/system"},
315 {{"xyz.openbmc_project.Inventory.Decorator.AssetTag",
316 {{"AssetTag", *assetTag}}}}}};
317
318 common::utility::callPIM(std::move(objectMap));
319 }
320 else
321 {
322 std::cerr << "Failed to read asset tag" << std::endl;
323 }
324 }
325}
326
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600327void Manager::processJSON()
328{
Santosh Puranik0246a4d2020-11-04 16:57:39 +0530329 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600330
331 if (!json)
332 {
333 throw std::runtime_error("json file not found");
334 }
335
336 jsonFile = nlohmann::json::parse(json);
337 if (jsonFile.find("frus") == jsonFile.end())
338 {
339 throw std::runtime_error("frus group not found in json");
340 }
341
342 const nlohmann::json& groupFRUS =
343 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
344 for (const auto& itemFRUS : groupFRUS.items())
345 {
346 const std::vector<nlohmann::json>& groupEEPROM =
347 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
348 for (const auto& itemEEPROM : groupEEPROM)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600349 {
SunnySrivastava198443306542020-04-01 02:50:20 -0500350 bool isMotherboard = false;
Santosh Puranika0b23912022-02-10 13:37:09 +0530351 std::string redundantPath;
352
SunnySrivastava198443306542020-04-01 02:50:20 -0500353 if (itemEEPROM["extraInterfaces"].find(
354 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") !=
355 itemEEPROM["extraInterfaces"].end())
356 {
357 isMotherboard = true;
358 }
Santosh Puranika0b23912022-02-10 13:37:09 +0530359 if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end())
360 {
361 redundantPath = itemEEPROM["redundantEeprom"]
362 .get_ref<const nlohmann::json::string_t&>();
363 }
364 frus.emplace(
365 itemEEPROM["inventoryPath"]
366 .get_ref<const nlohmann::json::string_t&>(),
367 std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard));
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500368
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000369 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
Alpana Kumari920408d2020-05-14 00:07:03 -0500370 itemEEPROM["extraInterfaces"].end())
371 {
372 fruLocationCode.emplace(
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000373 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
Alpana Kumari920408d2020-05-14 00:07:03 -0500374 ["LocationCode"]
375 .get_ref<const nlohmann::json::string_t&>(),
376 itemEEPROM["inventoryPath"]
377 .get_ref<const nlohmann::json::string_t&>());
378 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500379
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500380 if (itemEEPROM.value("replaceableAtStandby", false))
SunnySrivastava19849a195542020-09-07 06:04:50 -0500381 {
382 replaceableFrus.emplace_back(itemFRUS.key());
383 }
Sunny Srivastavafdf9ff22022-06-15 11:15:54 -0500384
385 if (itemEEPROM.value("essentialFru", false))
386 {
387 essentialFrus.emplace_back(itemEEPROM["inventoryPath"]);
388 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600389 }
390 }
391}
392
Sunny Srivastava83770862023-10-31 12:57:20 -0500393void Manager::updateSystemVPDBackUpFRU(const std::string& recordName,
394 const std::string& keyword,
395 const Binary& value)
396{
397 const std::string& systemVpdBackupPath =
398 jsonFile["frus"][systemVpdFilePath].at(0).value("systemVpdBackupPath",
399 "");
400
401 if (!systemVpdBackupPath.empty() &&
402 jsonFile["frus"][systemVpdBackupPath].at(0).contains("inventoryPath"))
403 {
404 std::string systemVpdBackupInvPath =
405 jsonFile["frus"][systemVpdBackupPath][0]["inventoryPath"]
406 .get_ref<const nlohmann::json::string_t&>();
407
408 const auto& itr = svpdKwdMap.find(recordName);
409 if (itr != svpdKwdMap.end())
410 {
411 auto systemKwdInfoList = itr->second;
Patrick Williams08dc31c2024-08-16 15:21:06 -0400412 const auto& itrToKwd =
413 find_if(systemKwdInfoList.begin(), systemKwdInfoList.end(),
414 [&keyword](const auto& kwdInfo) {
415 return (keyword == std::get<0>(kwdInfo));
416 });
Sunny Srivastava83770862023-10-31 12:57:20 -0500417
418 if (itrToKwd != systemKwdInfoList.end())
419 {
420 EditorImpl edit(systemVpdBackupPath, jsonFile,
421 std::get<4>(*itrToKwd), std::get<5>(*itrToKwd),
422 systemVpdBackupInvPath);
423
424 // Setup offset, if any
425 uint32_t offset = 0;
426 if (jsonFile["frus"][systemVpdBackupPath].at(0).contains(
427 "offset"))
428 {
429 offset =
430 jsonFile["frus"][systemVpdBackupPath].at(0).contains(
431 "offset");
432 }
433
434 edit.updateKeyword(value, offset, true);
435 }
436 }
437 }
438 else
439 {
440 if (systemVpdBackupPath.empty())
441 {
442 throw std::runtime_error(
443 "Invalid entry for systemVpdBackupPath in JSON");
444 }
445 else
446 {
447 throw std::runtime_error(
448 "Inventory path missing for systemVpdBackupPath");
449 }
450 }
451}
452
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600453void Manager::writeKeyword(const sdbusplus::message::object_path& path,
454 const std::string& recordName,
455 const std::string& keyword, const Binary& value)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600456{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600457 try
458 {
Santosh Puranik8c796812021-12-01 19:17:56 +0530459 std::string objPath{path};
460 // Strip any inventory prefix in path
461 if (objPath.find(INVENTORY_PATH) == 0)
462 {
463 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
464 }
465
466 if (frus.find(objPath) == frus.end())
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600467 {
468 throw std::runtime_error("Inventory path not found");
469 }
470
Santosh Puranika0b23912022-02-10 13:37:09 +0530471 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600472
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500473 // instantiate editor class to update the data
Santosh Puranik8c796812021-12-01 19:17:56 +0530474 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530475
476 uint32_t offset = 0;
477 // Setup offset, if any
478 for (const auto& item : jsonFile["frus"][vpdFilePath])
479 {
480 if (item.find("offset") != item.end())
481 {
482 offset = item["offset"];
483 break;
484 }
485 }
486
487 edit.updateKeyword(value, offset, true);
488
Sunny Srivastava83770862023-10-31 12:57:20 -0500489 // If system VPD is being updated and system VPD is marked for back up
490 // on another FRU, update data on back up as well.
491 if (objPath == sdbusplus::message::object_path{SYSTEM_OBJECT} &&
492 jsonFile["frus"][systemVpdFilePath].at(0).contains(
493 "systemVpdBackupPath"))
494 {
495 updateSystemVPDBackUpFRU(recordName, keyword, value);
496 }
497
Santosh Puranika0b23912022-02-10 13:37:09 +0530498 // If we have a redundant EEPROM to update, then update just the EEPROM,
499 // not the cache since that is already done when we updated the primary
500 if (!std::get<1>(frus.find(objPath)->second).empty())
501 {
502 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile,
Sunny Srivastavaf31a91b2022-06-09 08:11:29 -0500503 recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530504 edit.updateKeyword(value, offset, false);
505 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600506
SunnySrivastava198443306542020-04-01 02:50:20 -0500507 // if it is a motehrboard FRU need to check for location expansion
Santosh Puranika0b23912022-02-10 13:37:09 +0530508 if (std::get<2>(frus.find(objPath)->second))
SunnySrivastava198443306542020-04-01 02:50:20 -0500509 {
510 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE"))
511 {
512 edit.expandLocationCode("fcs");
513 }
514 else if (recordName == "VSYS" &&
515 (keyword == "TM" || keyword == "SE"))
516 {
517 edit.expandLocationCode("mts");
518 }
519 }
520
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500521 return;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600522 }
523 catch (const std::exception& e)
524 {
525 std::cerr << e.what() << std::endl;
526 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600527}
528
Patrick Williams08dc31c2024-08-16 15:21:06 -0400529ListOfPaths Manager::getFRUsByUnexpandedLocationCode(
530 const LocationCode& locationCode, const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600531{
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500532 ReaderImpl read;
533 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600534}
535
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500536ListOfPaths
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600537 Manager::getFRUsByExpandedLocationCode(const LocationCode& locationCode)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600538{
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500539 ReaderImpl read;
540 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600541}
542
Sunny Srivastava523af2e2022-02-14 07:30:10 -0600543LocationCode Manager::getExpandedLocationCode(const LocationCode& locationCode,
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500544 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600545{
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500546 ReaderImpl read;
547 return read.getExpandedLocationCode(locationCode, nodeNumber,
548 fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600549}
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600550
SunnySrivastava19849a195542020-09-07 06:04:50 -0500551void Manager::performVPDRecollection()
552{
553 // get list of FRUs replaceable at standby
554 for (const auto& item : replaceableFrus)
555 {
556 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
557 const nlohmann::json& singleFru = groupEEPROM[0];
558
559 const string& inventoryPath =
560 singleFru["inventoryPath"]
561 .get_ref<const nlohmann::json::string_t&>();
562
Sunny Srivastavaa12c6c82024-10-14 10:49:37 +0530563 // clear VPD of FRU before re-collection.
564 inventory::InterfaceMap interfacesPropMap;
565 clearVpdOnRemoval(INVENTORY_PATH + inventoryPath, interfacesPropMap);
566
567 inventory::ObjectMap objectMap;
568 objectMap.emplace(inventoryPath, move(interfacesPropMap));
569
570 common::utility::callPIM(move(objectMap));
571
572 // check if any subtree exist under the parent path. If so clear VPD for
573 // them as well.
574 std::vector<std::string> interfaceList{
575 "xyz.openbmc_project.Inventory.Item"};
576 MapperResponse subTree = getObjectSubtreeForInterfaces(
577 INVENTORY_PATH + inventoryPath, 0, interfaceList);
578
579 for (auto [objectPath, serviceInterfaceMap] : subTree)
580 {
581 interfacesPropMap.clear();
582 clearVpdOnRemoval(objectPath, interfacesPropMap);
583
584 std::string subTreeObjPath{objectPath};
585 // Strip any inventory prefix in path
586 if (subTreeObjPath.find(INVENTORY_PATH) == 0)
587 {
588 subTreeObjPath =
589 subTreeObjPath.substr(sizeof(INVENTORY_PATH) - 1);
590 }
591
592 objectMap.clear();
593 objectMap.emplace(subTreeObjPath, move(interfacesPropMap));
594
595 common::utility::callPIM(move(objectMap));
596 }
597
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530598 bool prePostActionRequired = false;
599
600 if ((jsonFile["frus"][item].at(0)).find("preAction") !=
601 jsonFile["frus"][item].at(0).end())
602 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500603 try
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530604 {
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500605 if (!executePreAction(jsonFile, item))
606 {
607 // if the FRU has preAction defined then its execution
608 // should pass to ensure bind/unbind of data.
609 // preAction execution failed. should not call
610 // bind/unbind.
611 log<level::ERR>(
612 "Pre-Action execution failed for the FRU",
613 entry("ERROR=%s",
614 ("Inventory path: " + inventoryPath).c_str()));
615 continue;
616 }
617 }
618 catch (const GpioException& e)
619 {
620 log<level::ERR>(e.what());
621 PelAdditionalData additionalData{};
622 additionalData.emplace("DESCRIPTION", e.what());
623 createPEL(additionalData, PelSeverity::WARNING,
624 errIntfForGpioError, sdBus);
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530625 continue;
626 }
627 prePostActionRequired = true;
628 }
629
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500630 // unbind, bind the driver to trigger parser.
631 triggerVpdCollection(singleFru, inventoryPath);
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530632
633 // this check is added to avoid file system expensive call in case not
634 // required.
635 if (prePostActionRequired)
636 {
Manojkiran Edaaf921752024-06-17 15:10:21 +0530637 // The sleep of 1sec is sliced up in 10 retries of 10 milliseconds
Sunny Srivastava4788e1b2024-03-19 02:11:07 -0500638 // each.
639 for (auto retryCounter = VALUE_0; retryCounter <= VALUE_10;
640 retryCounter++)
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530641 {
Manojkiran Edaaf921752024-06-17 15:10:21 +0530642 // sleep for 10 millisecond
Sunny Srivastava4788e1b2024-03-19 02:11:07 -0500643 if (usleep(VALUE_100000) != VALUE_0)
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500644 {
Sunny Srivastava4788e1b2024-03-19 02:11:07 -0500645 std::cout << "Sleep failed before accessing the file"
646 << std::endl;
Sunny Srivastavaa2ddc962022-06-29 08:53:16 -0500647 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500648
Sunny Srivastava4788e1b2024-03-19 02:11:07 -0500649 // Check if file showed up
650 if (!filesystem::exists(item))
651 {
652 // Do we need to retry?
653 if (retryCounter < VALUE_10)
654 {
655 continue;
656 }
657
658 try
659 {
660 // If not, then take failure postAction
661 executePostFailAction(jsonFile, item);
662 }
663 catch (const GpioException& e)
664 {
665 PelAdditionalData additionalData{};
666 additionalData.emplace("DESCRIPTION", e.what());
667 createPEL(additionalData, PelSeverity::WARNING,
668 errIntfForGpioError, sdBus);
669 }
670 }
671 else
672 {
673 // bind the LED driver
674 string chipAddr = singleFru.value("pcaChipAddress", "");
675 cout
676 << "performVPDRecollection: Executing driver binding for "
677 "chip "
678 "address - "
679 << chipAddr << endl;
680
681 executeCmd(createBindUnbindDriverCmnd(
682 chipAddr, "i2c", "leds-pca955x", "/bind"));
683
684 // File has been found, kill the retry loop.
685 break;
686 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500687 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530688 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500689 }
690}
691
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500692void Manager::collectFRUVPD(const sdbusplus::message::object_path& path)
693{
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500694 std::cout << "Manager called to collect vpd for fru: " << std::string{path}
695 << std::endl;
696
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500697 using InvalidArgument =
698 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
699 using Argument = xyz::openbmc_project::Common::InvalidArgument;
700
Santosh Puranikbc599472022-12-19 20:17:10 +0530701 std::string objPath{path};
702
703 // Strip any inventory prefix in path
704 if (objPath.find(INVENTORY_PATH) == 0)
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500705 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530706 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500707 }
708
Santosh Puranikbc599472022-12-19 20:17:10 +0530709 // if path not found in Json.
710 if (frus.find(objPath) == frus.end())
711 {
712 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
713 Argument::ARGUMENT_VALUE(objPath.c_str()));
714 }
715
716 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500717
718 const std::vector<nlohmann::json>& groupEEPROM =
719 jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>();
720
Sunny Srivastavaab2304d2023-01-10 23:30:05 -0600721 nlohmann::json singleFru{};
722 for (const auto& item : groupEEPROM)
723 {
724 if (item["inventoryPath"] == objPath)
725 {
726 // this is the inventory we are looking for
727 singleFru = item;
728 break;
729 }
730 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500731
732 // check if the device qualifies for CM.
733 if (singleFru.value("concurrentlyMaintainable", false))
734 {
735 bool prePostActionRequired = false;
736
737 if ((jsonFile["frus"][vpdFilePath].at(0)).find("preAction") !=
738 jsonFile["frus"][vpdFilePath].at(0).end())
739 {
740 if (!executePreAction(jsonFile, vpdFilePath))
741 {
742 // if the FRU has preAction defined then its execution should
743 // pass to ensure bind/unbind of data.
744 // preAction execution failed. should not call bind/unbind.
745 log<level::ERR>("Pre-Action execution failed for the FRU");
746 return;
747 }
748
749 prePostActionRequired = true;
750 }
751
752 // unbind, bind the driver to trigger parser.
Santosh Puranikbc599472022-12-19 20:17:10 +0530753 triggerVpdCollection(singleFru, objPath);
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500754
755 // this check is added to avoid file system expensive call in case not
756 // required.
757 if (prePostActionRequired)
758 {
759 // Check if device showed up (test for file)
760 if (!filesystem::exists(vpdFilePath))
761 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530762 try
763 {
764 // If not, then take failure postAction
765 executePostFailAction(jsonFile, vpdFilePath);
766 }
767 catch (const GpioException& e)
768 {
769 PelAdditionalData additionalData{};
770 additionalData.emplace("DESCRIPTION", e.what());
771 createPEL(additionalData, PelSeverity::WARNING,
772 errIntfForGpioError, sdBus);
773 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500774 }
Alpana Kumari41d498c2021-09-16 00:29:12 -0500775 else
776 {
777 // bind the LED driver
778 string chipAddr = jsonFile["frus"][vpdFilePath].at(0).value(
779 "pcaChipAddress", "");
780 cout << "Executing driver binding for chip address - "
781 << chipAddr << endl;
782
783 executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c",
784 "leds-pca955x", "/bind"));
785 }
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500786 }
787 return;
788 }
789 else
790 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530791 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
792 Argument::ARGUMENT_VALUE(objPath.c_str()));
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500793 }
794}
795
796void Manager::triggerVpdCollection(const nlohmann::json& singleFru,
797 const std::string& path)
798{
799 if ((singleFru.find("devAddress") == singleFru.end()) ||
800 (singleFru.find("driverType") == singleFru.end()) ||
801 (singleFru.find("busType") == singleFru.end()))
802 {
803 // The FRUs is marked for collection but missing mandatory
804 // fields for collection. Log error and return.
805 log<level::ERR>(
806 "Collection Failed as mandatory field missing in Json",
807 entry("ERROR=%s", ("Recollection failed for " + (path)).c_str()));
808
809 return;
810 }
811
812 string deviceAddress = singleFru["devAddress"];
813 const string& driverType = singleFru["driverType"];
814 const string& busType = singleFru["busType"];
815
816 // devTreeStatus flag is present in json as false to mention
817 // that the EEPROM is not mentioned in device tree. If this flag
818 // is absent consider the value to be true, i.e EEPROM is
819 // mentioned in device tree
820 if (!singleFru.value("devTreeStatus", true))
821 {
822 auto pos = deviceAddress.find('-');
823 if (pos != string::npos)
824 {
825 string busNum = deviceAddress.substr(0, pos);
826 deviceAddress = "0x" + deviceAddress.substr(pos + 1, string::npos);
827
Patrick Williams08dc31c2024-08-16 15:21:06 -0400828 string deleteDevice =
829 "echo" + deviceAddress + " > /sys/bus/" + busType +
830 "/devices/" + busType + "-" + busNum + "/delete_device";
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500831 executeCmd(deleteDevice);
832
Patrick Williams08dc31c2024-08-16 15:21:06 -0400833 string addDevice =
834 "echo" + driverType + " " + deviceAddress + " > /sys/bus/" +
835 busType + "/devices/" + busType + "-" + busNum + "/new_device";
Sunny Srivastava6a1bd392021-06-02 04:39:24 -0500836 executeCmd(addDevice);
837 }
838 else
839 {
840 const string& inventoryPath =
841 singleFru["inventoryPath"]
842 .get_ref<const nlohmann::json::string_t&>();
843
844 log<level::ERR>(
845 "Wrong format of device address in Json",
846 entry("ERROR=%s",
847 ("Recollection failed for " + inventoryPath).c_str()));
848 }
849 }
850 else
851 {
852 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
853 driverType, "/unbind"));
854 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
855 driverType, "/bind"));
856 }
857}
858
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500859void Manager::deleteFRUVPD(const sdbusplus::message::object_path& path)
860{
Sunny Srivastava5ef6ccc2022-05-30 01:35:13 -0500861 std::cout << "Manager called to delete vpd for fru: " << std::string{path}
862 << std::endl;
863
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500864 using InvalidArgument =
865 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
866 using Argument = xyz::openbmc_project::Common::InvalidArgument;
867
Santosh Puranikbc599472022-12-19 20:17:10 +0530868 std::string objPath{path};
869
870 // Strip any inventory prefix in path
871 if (objPath.find(INVENTORY_PATH) == 0)
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500872 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530873 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500874 }
875
Santosh Puranikbc599472022-12-19 20:17:10 +0530876 // if path not found in Json.
877 if (frus.find(objPath) == frus.end())
878 {
879 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"),
880 Argument::ARGUMENT_VALUE(objPath.c_str()));
881 }
882
883 inventory::Path& vpdFilePath = std::get<0>(frus.find(objPath)->second);
Alpana Kumari41d498c2021-09-16 00:29:12 -0500884
885 string chipAddress =
886 jsonFile["frus"][vpdFilePath].at(0).value("pcaChipAddress", "");
887
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500888 // if the FRU is not present then log error
Santosh Puranikbc599472022-12-19 20:17:10 +0530889 if (readBusProperty(objPath, "xyz.openbmc_project.Inventory.Item",
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500890 "Present") == "false")
891 {
Santosh Puranikbc599472022-12-19 20:17:10 +0530892 elog<InvalidArgument>(Argument::ARGUMENT_NAME("FRU not preset"),
893 Argument::ARGUMENT_VALUE(objPath.c_str()));
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500894 }
895 else
896 {
Sunny Srivastava893bf5d2024-06-14 02:03:39 -0500897 // check if we have cxp-port populated for the given object path.
898 std::vector<std::string> interfaceList{
899 "xyz.openbmc_project.State.Decorator.OperationalStatus"};
Patrick Williams08dc31c2024-08-16 15:21:06 -0400900 MapperResponse subTree =
901 getObjectSubtreeForInterfaces(path, 0, interfaceList);
Sunny Srivastava893bf5d2024-06-14 02:03:39 -0500902
903 if (subTree.size() != 0)
904 {
905 for (auto [objectPath, serviceInterfaceMap] : subTree)
906 {
907 std::string subTreeObjPath{objectPath};
908 if (subTreeObjPath.find("cxp_top") != std::string::npos ||
909 subTreeObjPath.find("cxp_bot") != std::string::npos)
910 {
911 // Strip any inventory prefix in path
912 if (subTreeObjPath.find(INVENTORY_PATH) == 0)
913 {
914 subTreeObjPath =
915 subTreeObjPath.substr(sizeof(INVENTORY_PATH) - 1);
916 }
917
918 inventory::ObjectMap objectMap{
919 {subTreeObjPath,
920 {{"xyz.openbmc_project.State.Decorator.OperationalStatus",
921 {{"Functional", true}}}}}};
922
923 // objectMap.emplace(objectPath, move(interfaceMap));
924 common::utility::callPIM(move(objectMap));
925 }
926 }
927 }
928
929 // Unbind the LED driver for this FRU
930 cout << "Unbinding device- " << chipAddress << endl;
931 executeCmd(createBindUnbindDriverCmnd(chipAddress, "i2c",
932 "leds-pca955x", "/unbind"));
933
Sunny Srivastavac6e7ea92023-11-03 21:10:43 +0530934 inventory::InterfaceMap interfacesPropMap;
935 clearVpdOnRemoval(INVENTORY_PATH + objPath, interfacesPropMap);
Santosh Puranikbc599472022-12-19 20:17:10 +0530936
937 inventory::ObjectMap objectMap;
Sunny Srivastavac6e7ea92023-11-03 21:10:43 +0530938 objectMap.emplace(objPath, move(interfacesPropMap));
Sunny Srivastava28abd6e2021-07-28 02:58:28 -0500939
940 common::utility::callPIM(move(objectMap));
941 }
942}
943
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600944} // namespace manager
945} // namespace vpd
Patrick Williamsc78d8872023-05-10 07:50:56 -0500946} // namespace openpower