blob: 0df9f80393ca2d10a97e0b1cde60947399c28dbb [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#include "config.h"
2
3#include "manager.hpp"
4
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05005#include "constants.hpp"
6#include "exceptions.hpp"
7#include "logger.hpp"
8#include "parser.hpp"
9#include "parser_factory.hpp"
10#include "parser_interface.hpp"
Rekha Aparnaffdff312025-03-25 01:10:56 -050011#include "single_fab.hpp"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050012#include "types.hpp"
13#include "utility/dbus_utility.hpp"
14#include "utility/json_utility.hpp"
15#include "utility/vpd_specific_utility.hpp"
16
17#include <boost/asio/steady_timer.hpp>
18#include <sdbusplus/bus/match.hpp>
19#include <sdbusplus/message.hpp>
20
21namespace vpd
22{
23Manager::Manager(
24 const std::shared_ptr<boost::asio::io_context>& ioCon,
25 const std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace,
26 const std::shared_ptr<sdbusplus::asio::connection>& asioConnection) :
27 m_ioContext(ioCon), m_interface(iFace), m_asioConnection(asioConnection)
28{
Jinu Joy Thomas3419f5d2025-04-09 04:04:18 -050029#ifdef IBM_SYSTEM
Rekha Aparnaffdff312025-03-25 01:10:56 -050030 if (!dbusUtility::isChassisPowerOn())
31 {
32 SingleFab l_singleFab;
33 const int& l_rc = l_singleFab.singleFabImOverride();
34
35 if (l_rc == constants::FAILURE)
36 {
37 throw std::runtime_error(
38 std::string(__FUNCTION__) +
39 " : Found an invalid system configuration. Needs manual intervention. BMC is being quiesced.");
40 }
41 }
42#endif
43
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050044 try
45 {
46#ifdef IBM_SYSTEM
Sunny Srivastava765cf7b2025-02-04 05:24:11 -060047 if (dbusUtility::isChassisPowerOn())
48 {
49 // At power on, less number of FRU(s) needs collection. we can scale
50 // down the threads to reduce CPU utilization.
51 m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT,
52 constants::VALUE_1);
53 }
54 else
55 {
56 // Initialize with default configuration
57 m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT);
58 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050059
60 // Set up minimal things that is needed before bus name is claimed.
61 m_worker->performInitialSetup();
62
Anupama B R8dedd1e2025-03-24 07:43:47 -050063 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
64 if (!m_worker->getSysCfgJsonObj().empty() &&
65 jsonUtility::isBackupAndRestoreRequired(l_sysCfgJsonObj))
66 {
Sunny Srivastava47f11c22025-04-13 12:35:47 +053067 try
68 {
69 m_backupAndRestoreObj =
70 std::make_shared<BackupAndRestore>(l_sysCfgJsonObj);
71 }
72 catch (const std::exception& l_ex)
73 {
74 logging::logMessage(
75 "Back up and restore instantiation failed. {" +
76 std::string(l_ex.what()) + "}");
77
78 EventLogger::createSyncPel(
79 EventLogger::getErrorType(l_ex),
80 types::SeverityType::Warning, __FILE__, __FUNCTION__, 0,
81 EventLogger::getErrorMsg(l_ex), std::nullopt, std::nullopt,
82 std::nullopt, std::nullopt);
83 }
Anupama B R8dedd1e2025-03-24 07:43:47 -050084 }
85
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050086 // set callback to detect any asset tag change
87 registerAssetTagChangeCallback();
88
89 // set async timer to detect if system VPD is published on D-Bus.
90 SetTimerToDetectSVPDOnDbus();
91
92 // set async timer to detect if VPD collection is done.
93 SetTimerToDetectVpdCollectionStatus();
94
95 // Instantiate GpioMonitor class
96 m_gpioMonitor = std::make_shared<GpioMonitor>(
97 m_worker->getSysCfgJsonObj(), m_worker, m_ioContext);
98
99#endif
100 // set callback to detect host state change.
101 registerHostStateChangeCallback();
102
103 // For backward compatibility. Should be depricated.
104 iFace->register_method(
105 "WriteKeyword",
106 [this](const sdbusplus::message::object_path i_path,
107 const std::string i_recordName, const std::string i_keyword,
108 const types::BinaryVector i_value) -> int {
109 return this->updateKeyword(
110 i_path, std::make_tuple(i_recordName, i_keyword, i_value));
111 });
112
113 // Register methods under com.ibm.VPD.Manager interface
114 iFace->register_method(
115 "UpdateKeyword",
116 [this](const types::Path i_vpdPath,
117 const types::WriteVpdParams i_paramsToWriteData) -> int {
118 return this->updateKeyword(i_vpdPath, i_paramsToWriteData);
119 });
120
121 iFace->register_method(
122 "WriteKeywordOnHardware",
123 [this](const types::Path i_fruPath,
124 const types::WriteVpdParams i_paramsToWriteData) -> int {
125 return this->updateKeywordOnHardware(i_fruPath,
126 i_paramsToWriteData);
127 });
128
129 iFace->register_method(
130 "ReadKeyword",
131 [this](const types::Path i_fruPath,
132 const types::ReadVpdParams i_paramsToReadData)
133 -> types::DbusVariantType {
134 return this->readKeyword(i_fruPath, i_paramsToReadData);
135 });
136
137 iFace->register_method(
138 "CollectFRUVPD",
139 [this](const sdbusplus::message::object_path& i_dbusObjPath) {
140 this->collectSingleFruVpd(i_dbusObjPath);
141 });
142
143 iFace->register_method(
144 "deleteFRUVPD",
145 [this](const sdbusplus::message::object_path& i_dbusObjPath) {
146 this->deleteSingleFruVpd(i_dbusObjPath);
147 });
148
149 iFace->register_method(
150 "GetExpandedLocationCode",
151 [this](const std::string& i_unexpandedLocationCode,
152 uint16_t& i_nodeNumber) -> std::string {
153 return this->getExpandedLocationCode(i_unexpandedLocationCode,
154 i_nodeNumber);
155 });
156
157 iFace->register_method("GetFRUsByExpandedLocationCode",
158 [this](const std::string& i_expandedLocationCode)
159 -> types::ListOfPaths {
160 return this->getFrusByExpandedLocationCode(
161 i_expandedLocationCode);
162 });
163
164 iFace->register_method(
165 "GetFRUsByUnexpandedLocationCode",
166 [this](const std::string& i_unexpandedLocationCode,
167 uint16_t& i_nodeNumber) -> types::ListOfPaths {
168 return this->getFrusByUnexpandedLocationCode(
169 i_unexpandedLocationCode, i_nodeNumber);
170 });
171
172 iFace->register_method(
173 "GetHardwarePath",
174 [this](const sdbusplus::message::object_path& i_dbusObjPath)
175 -> std::string { return this->getHwPath(i_dbusObjPath); });
176
177 iFace->register_method("PerformVPDRecollection", [this]() {
178 this->performVpdRecollection();
179 });
180
181 // Indicates FRU VPD collection for the system has not started.
182 iFace->register_property_rw<std::string>(
183 "CollectionStatus", sdbusplus::vtable::property_::emits_change,
184 [this](const std::string l_currStatus, const auto&) {
185 m_vpdCollectionStatus = l_currStatus;
186 return 0;
187 },
188 [this](const auto&) { return m_vpdCollectionStatus; });
189 }
190 catch (const std::exception& e)
191 {
192 logging::logMessage(
Sunny Srivastava4c509c22025-03-25 12:43:40 +0530193 "Manager class instantiation failed. " + std::string(e.what()));
194
195 vpd::EventLogger::createSyncPel(
196 vpd::EventLogger::getErrorType(e), vpd::types::SeverityType::Error,
197 __FILE__, __FUNCTION__, 0, vpd::EventLogger::getErrorMsg(e),
198 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500199 }
200}
201
202#ifdef IBM_SYSTEM
203void Manager::registerAssetTagChangeCallback()
204{
205 static std::shared_ptr<sdbusplus::bus::match_t> l_assetMatch =
206 std::make_shared<sdbusplus::bus::match_t>(
207 *m_asioConnection,
208 sdbusplus::bus::match::rules::propertiesChanged(
209 constants::systemInvPath, constants::assetTagInf),
210 [this](sdbusplus::message_t& l_msg) {
211 processAssetTagChangeCallback(l_msg);
212 });
213}
214
215void Manager::processAssetTagChangeCallback(sdbusplus::message_t& i_msg)
216{
217 try
218 {
219 if (i_msg.is_method_error())
220 {
221 throw std::runtime_error(
222 "Error reading callback msg for asset tag.");
223 }
224
225 std::string l_objectPath;
226 types::PropertyMap l_propMap;
227 i_msg.read(l_objectPath, l_propMap);
228
229 const auto& l_itrToAssetTag = l_propMap.find("AssetTag");
230 if (l_itrToAssetTag != l_propMap.end())
231 {
232 if (auto l_assetTag =
233 std::get_if<std::string>(&(l_itrToAssetTag->second)))
234 {
235 // Call Notify to persist the AssetTag
236 types::ObjectMap l_objectMap = {
237 {sdbusplus::message::object_path(constants::systemInvPath),
238 {{constants::assetTagInf, {{"AssetTag", *l_assetTag}}}}}};
239
240 // Notify PIM
241 if (!dbusUtility::callPIM(move(l_objectMap)))
242 {
243 throw std::runtime_error(
244 "Call to PIM failed for asset tag update.");
245 }
246 }
247 }
248 else
249 {
250 throw std::runtime_error(
251 "Could not find asset tag in callback message.");
252 }
253 }
254 catch (const std::exception& l_ex)
255 {
256 // TODO: Log PEL with below description.
257 logging::logMessage("Asset tag callback update failed with error: " +
258 std::string(l_ex.what()));
259 }
260}
261
262void Manager::SetTimerToDetectSVPDOnDbus()
263{
Sunny Srivastava58057c12025-03-19 10:41:34 +0530264 try
265 {
266 static boost::asio::steady_timer timer(*m_ioContext);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500267
Sunny Srivastava58057c12025-03-19 10:41:34 +0530268 // timer for 2 seconds
269 auto asyncCancelled = timer.expires_after(std::chrono::seconds(2));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500270
Sunny Srivastava58057c12025-03-19 10:41:34 +0530271 (asyncCancelled == 0) ? logging::logMessage("Timer started")
272 : logging::logMessage("Timer re-started");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500273
Sunny Srivastava58057c12025-03-19 10:41:34 +0530274 timer.async_wait([this](const boost::system::error_code& ec) {
275 if (ec == boost::asio::error::operation_aborted)
276 {
277 throw std::runtime_error(
278 std::string(__FUNCTION__) +
279 ": Timer to detect system VPD collection status was aborted.");
280 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500281
Sunny Srivastava58057c12025-03-19 10:41:34 +0530282 if (ec)
283 {
284 throw std::runtime_error(
285 std::string(__FUNCTION__) +
286 ": Timer to detect System VPD collection failed");
287 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500288
Sunny Srivastava58057c12025-03-19 10:41:34 +0530289 if (m_worker->isSystemVPDOnDBus())
290 {
291 // cancel the timer
292 timer.cancel();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500293
Sunny Srivastava58057c12025-03-19 10:41:34 +0530294 // Triggering FRU VPD collection. Setting status to "In
295 // Progress".
296 m_interface->set_property("CollectionStatus",
297 std::string("InProgress"));
298 m_worker->collectFrusFromJson();
299 }
300 });
301 }
302 catch (const std::exception& l_ex)
303 {
304 EventLogger::createAsyncPel(
305 EventLogger::getErrorType(l_ex), types::SeverityType::Critical,
306 __FILE__, __FUNCTION__, 0,
307 std::string("Collection for FRUs failed with reason:") +
308 EventLogger::getErrorMsg(l_ex),
309 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
310 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500311}
312
313void Manager::SetTimerToDetectVpdCollectionStatus()
314{
Sunny Srivastava59f91a82025-02-12 13:19:04 -0600315 // Keeping max retry for 2 minutes. TODO: Make it configurable based on
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500316 // system type.
Sunny Srivastava59f91a82025-02-12 13:19:04 -0600317 static constexpr auto MAX_RETRY = 12;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500318
319 static boost::asio::steady_timer l_timer(*m_ioContext);
320 static uint8_t l_timerRetry = 0;
321
Sunny Srivastava59f91a82025-02-12 13:19:04 -0600322 auto l_asyncCancelled = l_timer.expires_after(std::chrono::seconds(10));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500323
324 (l_asyncCancelled == 0)
325 ? logging::logMessage("Collection Timer started")
326 : logging::logMessage("Collection Timer re-started");
327
328 l_timer.async_wait([this](const boost::system::error_code& ec) {
329 if (ec == boost::asio::error::operation_aborted)
330 {
331 throw std::runtime_error(
332 "Timer to detect thread collection status was aborted");
333 }
334
335 if (ec)
336 {
337 throw std::runtime_error(
338 "Timer to detect thread collection failed");
339 }
340
341 if (m_worker->isAllFruCollectionDone())
342 {
343 // cancel the timer
344 l_timer.cancel();
Souvik Roy1f4c8f82025-01-23 00:37:43 -0600345 processFailedEeproms();
Sunny Srivastava4c7798a2025-02-19 18:50:34 +0530346
347 // update VPD for powerVS system.
348 ConfigurePowerVsSystem();
349
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500350 m_interface->set_property("CollectionStatus",
351 std::string("Completed"));
352
Anupama B R8dedd1e2025-03-24 07:43:47 -0500353 if (m_backupAndRestoreObj)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500354 {
Anupama B R8dedd1e2025-03-24 07:43:47 -0500355 m_backupAndRestoreObj->backupAndRestore();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500356 }
357 }
358 else
359 {
360 auto l_threadCount = m_worker->getActiveThreadCount();
361 if (l_timerRetry == MAX_RETRY)
362 {
363 l_timer.cancel();
364 logging::logMessage("Taking too long. Active thread = " +
365 std::to_string(l_threadCount));
366 }
367 else
368 {
369 l_timerRetry++;
Sunny Srivastava59f91a82025-02-12 13:19:04 -0600370 logging::logMessage("Collection is in progress for [" +
371 std::to_string(l_threadCount) + "] FRUs.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500372
373 SetTimerToDetectVpdCollectionStatus();
374 }
375 }
376 });
377}
Sunny Srivastava4c7798a2025-02-19 18:50:34 +0530378
Sunny Srivastava022112b2025-02-19 19:53:29 +0530379void Manager::checkAndUpdatePowerVsVpd(
380 const nlohmann::json& i_powerVsJsonObj,
381 std::vector<std::string>& o_failedPathList)
382{
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530383 for (const auto& [l_fruPath, l_recJson] : i_powerVsJsonObj.items())
384 {
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530385 nlohmann::json l_sysCfgJsonObj{};
386 if (m_worker.get() != nullptr)
387 {
388 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
389 }
390
391 // The utility method will handle emty JSON case. No explicit
392 // handling required here.
393 auto l_inventoryPath = jsonUtility::getInventoryObjPathFromJson(
394 l_sysCfgJsonObj, l_fruPath);
395
396 // Mark it as failed if inventory path not found in JSON.
397 if (l_inventoryPath.empty())
398 {
399 o_failedPathList.push_back(l_fruPath);
400 continue;
401 }
402
403 // check if the FRU is present
404 if (!dbusUtility::isInventoryPresent(l_inventoryPath))
405 {
406 logging::logMessage(
407 "Inventory not present, skip updating part number. Path: " +
408 l_inventoryPath);
409 continue;
410 }
411
412 // check if the FRU needs CCIN check before updating PN.
413 if (l_recJson.contains("CCIN"))
414 {
415 const auto& l_ccinFromDbus =
416 vpdSpecificUtility::getCcinFromDbus(l_inventoryPath);
417
418 // Not an ideal situation as CCIN can't be empty.
419 if (l_ccinFromDbus.empty())
420 {
421 o_failedPathList.push_back(l_fruPath);
422 continue;
423 }
424
425 std::vector<std::string> l_ccinListFromJson = l_recJson["CCIN"];
426
427 if (find(l_ccinListFromJson.begin(), l_ccinListFromJson.end(),
428 l_ccinFromDbus) == l_ccinListFromJson.end())
429 {
430 // Don't update PN in this case.
431 continue;
432 }
433 }
434
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530435 for (const auto& [l_recordName, l_kwdJson] : l_recJson.items())
436 {
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530437 // Record name can't be CCIN, skip processing as it is there for PN
438 // update based on CCIN check.
439 if (l_recordName == constants::kwdCCIN)
440 {
441 continue;
442 }
443
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530444 for (const auto& [l_kwdName, l_kwdValue] : l_kwdJson.items())
445 {
446 // Is value of type array.
447 if (!l_kwdValue.is_array())
448 {
449 o_failedPathList.push_back(l_fruPath);
450 continue;
451 }
452
Sunny Srivastava22793832025-03-20 12:09:09 +0530453 // Get current FRU Part number.
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530454 auto l_retVal = dbusUtility::readDbusProperty(
455 constants::pimServiceName, l_inventoryPath,
Sunny Srivastava22793832025-03-20 12:09:09 +0530456 constants::viniInf, constants::kwdFN);
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530457
Sunny Srivastava22793832025-03-20 12:09:09 +0530458 auto l_ptrToFn = std::get_if<types::BinaryVector>(&l_retVal);
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530459
Sunny Srivastava22793832025-03-20 12:09:09 +0530460 if (!l_ptrToFn)
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530461 {
462 o_failedPathList.push_back(l_fruPath);
463 continue;
464 }
465
466 types::BinaryVector l_binaryKwdValue =
467 l_kwdValue.get<types::BinaryVector>();
Sunny Srivastava22793832025-03-20 12:09:09 +0530468 if (l_binaryKwdValue == (*l_ptrToFn))
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530469 {
470 continue;
471 }
472
473 // Update part number only if required.
474 if (updateKeyword(
475 l_fruPath,
476 std::make_tuple(l_recordName, l_kwdName, l_kwdValue)) ==
477 constants::FAILURE)
478 {
479 o_failedPathList.push_back(l_fruPath);
480 continue;
481 }
482
Sunny Srivastava22793832025-03-20 12:09:09 +0530483 // update the Asset interface Spare part number explicitly.
Sunny Srivastavab83cb352025-03-06 14:41:27 +0530484 if (!dbusUtility::callPIM(types::ObjectMap{
485 {l_inventoryPath,
Sunny Srivastava22793832025-03-20 12:09:09 +0530486 {{constants::assetInf,
487 {{"SparePartNumber",
Sunny Srivastavab83cb352025-03-06 14:41:27 +0530488 std::string(l_binaryKwdValue.begin(),
489 l_binaryKwdValue.end())}}}}}}))
490 {
491 logging::logMessage(
Sunny Srivastava22793832025-03-20 12:09:09 +0530492 "Updating Spare Part Number under Asset interface failed for path [" +
Sunny Srivastavab83cb352025-03-06 14:41:27 +0530493 l_inventoryPath + "]");
494 }
495
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530496 // Just needed for logging.
Sunny Srivastava22793832025-03-20 12:09:09 +0530497 std::string l_initialPartNum((*l_ptrToFn).begin(),
498 (*l_ptrToFn).end());
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530499 std::string l_finalPartNum(l_binaryKwdValue.begin(),
500 l_binaryKwdValue.end());
501 logging::logMessage(
Sunny Srivastava22793832025-03-20 12:09:09 +0530502 "FRU Part number updated for path [" + l_inventoryPath +
503 "]" + "From [" + l_initialPartNum + "]" + " to [" +
Sunny Srivastava0cd15e12025-02-20 00:01:02 +0530504 l_finalPartNum + "]");
505 }
506 }
507 }
Sunny Srivastava022112b2025-02-19 19:53:29 +0530508}
509
Sunny Srivastava4c7798a2025-02-19 18:50:34 +0530510void Manager::ConfigurePowerVsSystem()
511{
Sunny Srivastava022112b2025-02-19 19:53:29 +0530512 std::vector<std::string> l_failedPathList;
Sunny Srivastava1a48f0c2025-02-19 19:02:03 +0530513 try
514 {
515 types::BinaryVector l_imValue = dbusUtility::getImFromDbus();
516 if (l_imValue.empty())
517 {
518 throw DbusException("Invalid IM value read from Dbus");
519 }
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530520
521 if (!vpdSpecificUtility::isPowerVsConfiguration(l_imValue))
522 {
523 // TODO: Should booting be blocked in case of some
524 // misconfigurations?
525 return;
526 }
Sunny Srivastava022112b2025-02-19 19:53:29 +0530527
528 const nlohmann::json& l_powerVsJsonObj =
529 jsonUtility::getPowerVsJson(l_imValue);
530
531 if (l_powerVsJsonObj.empty())
532 {
533 throw std::runtime_error("PowerVS Json not found");
534 }
535
536 checkAndUpdatePowerVsVpd(l_powerVsJsonObj, l_failedPathList);
537
538 if (!l_failedPathList.empty())
539 {
540 throw std::runtime_error(
541 "Part number update failed for following paths: ");
542 }
Sunny Srivastava1a48f0c2025-02-19 19:02:03 +0530543 }
544 catch (const std::exception& l_ex)
545 {
546 // TODO log appropriate PEL
547 }
Sunny Srivastava4c7798a2025-02-19 18:50:34 +0530548}
Sunny Srivastava46f29812025-02-25 11:36:17 +0530549
550void Manager::processFailedEeproms()
551{
552 if (m_worker.get() != nullptr)
553 {
554 // TODO:
555 // - iterate through list of EEPROMs for which thread creation has
556 // failed
557 // - For each failed EEPROM, trigger VPD collection
558 m_worker->getFailedEepromPaths().clear();
559 }
560}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500561#endif
562
563int Manager::updateKeyword(const types::Path i_vpdPath,
564 const types::WriteVpdParams i_paramsToWriteData)
565{
566 if (i_vpdPath.empty())
567 {
568 logging::logMessage("Given VPD path is empty.");
569 return -1;
570 }
571
572 types::Path l_fruPath;
573 nlohmann::json l_sysCfgJsonObj{};
574
575 if (m_worker.get() != nullptr)
576 {
577 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
578
579 // Get the EEPROM path
580 if (!l_sysCfgJsonObj.empty())
581 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600582 l_fruPath =
583 jsonUtility::getFruPathFromJson(l_sysCfgJsonObj, i_vpdPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500584 }
585 }
586
587 if (l_fruPath.empty())
588 {
589 l_fruPath = i_vpdPath;
590 }
591
592 try
593 {
594 std::shared_ptr<Parser> l_parserObj =
595 std::make_shared<Parser>(l_fruPath, l_sysCfgJsonObj);
Anupama B R8dedd1e2025-03-24 07:43:47 -0500596 auto l_rc = l_parserObj->updateVpdKeyword(i_paramsToWriteData);
597
598 if (l_rc != constants::FAILURE && m_backupAndRestoreObj)
599 {
600 if (m_backupAndRestoreObj->updateKeywordOnPrimaryOrBackupPath(
601 l_fruPath, i_paramsToWriteData) < constants::VALUE_0)
602 {
603 logging::logMessage(
604 "Write success, but backup and restore failed for file[" +
605 l_fruPath + "]");
606 }
607 }
608 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500609 }
610 catch (const std::exception& l_exception)
611 {
612 // TODO:: error log needed
613 logging::logMessage("Update keyword failed for file[" + i_vpdPath +
614 "], reason: " + std::string(l_exception.what()));
615 return -1;
616 }
617}
618
619int Manager::updateKeywordOnHardware(
620 const types::Path i_fruPath,
621 const types::WriteVpdParams i_paramsToWriteData) noexcept
622{
623 try
624 {
625 if (i_fruPath.empty())
626 {
627 throw std::runtime_error("Given FRU path is empty");
628 }
629
630 nlohmann::json l_sysCfgJsonObj{};
631
632 if (m_worker.get() != nullptr)
633 {
634 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
635 }
636
637 std::shared_ptr<Parser> l_parserObj =
638 std::make_shared<Parser>(i_fruPath, l_sysCfgJsonObj);
639 return l_parserObj->updateVpdKeywordOnHardware(i_paramsToWriteData);
640 }
641 catch (const std::exception& l_exception)
642 {
643 EventLogger::createAsyncPel(
644 types::ErrorType::InvalidEeprom, types::SeverityType::Informational,
645 __FILE__, __FUNCTION__, 0,
646 "Update keyword on hardware failed for file[" + i_fruPath +
647 "], reason: " + std::string(l_exception.what()),
648 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
649
650 return constants::FAILURE;
651 }
652}
653
654types::DbusVariantType Manager::readKeyword(
655 const types::Path i_fruPath, const types::ReadVpdParams i_paramsToReadData)
656{
657 try
658 {
659 nlohmann::json l_jsonObj{};
660
661 if (m_worker.get() != nullptr)
662 {
663 l_jsonObj = m_worker->getSysCfgJsonObj();
664 }
665
666 std::error_code ec;
667
668 // Check if given path is filesystem path
669 if (!std::filesystem::exists(i_fruPath, ec) && (ec))
670 {
671 throw std::runtime_error(
672 "Given file path " + i_fruPath + " not found.");
673 }
674
675 logging::logMessage("Performing VPD read on " + i_fruPath);
676
677 std::shared_ptr<vpd::Parser> l_parserObj =
678 std::make_shared<vpd::Parser>(i_fruPath, l_jsonObj);
679
680 std::shared_ptr<vpd::ParserInterface> l_vpdParserInstance =
681 l_parserObj->getVpdParserInstance();
682
683 return (
684 l_vpdParserInstance->readKeywordFromHardware(i_paramsToReadData));
685 }
686 catch (const std::exception& e)
687 {
688 logging::logMessage(
689 e.what() + std::string(". VPD manager read operation failed for ") +
690 i_fruPath);
691 throw types::DeviceError::ReadFailure();
692 }
693}
694
695void Manager::collectSingleFruVpd(
696 const sdbusplus::message::object_path& i_dbusObjPath)
697{
698 try
699 {
700 if (m_vpdCollectionStatus != "Completed")
701 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600702 logging::logMessage(
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500703 "Currently VPD CollectionStatus is not completed. Cannot perform single FRU VPD collection for " +
704 std::string(i_dbusObjPath));
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600705 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500706 }
707
708 // Get system config JSON object from worker class
709 nlohmann::json l_sysCfgJsonObj{};
710
711 if (m_worker.get() != nullptr)
712 {
713 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
714 }
715
716 // Check if system config JSON is present
717 if (l_sysCfgJsonObj.empty())
718 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600719 logging::logMessage(
720 "System config JSON object not present. Single FRU VPD collection is not performed for " +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500721 std::string(i_dbusObjPath));
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600722 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500723 }
724
725 // Get FRU path for the given D-bus object path from JSON
726 const std::string& l_fruPath =
727 jsonUtility::getFruPathFromJson(l_sysCfgJsonObj, i_dbusObjPath);
728
729 if (l_fruPath.empty())
730 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600731 logging::logMessage(
732 "D-bus object path not present in JSON. Single FRU VPD collection is not performed for " +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500733 std::string(i_dbusObjPath));
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600734 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500735 }
736
737 // Check if host is up and running
738 if (dbusUtility::isHostRunning())
739 {
740 if (!jsonUtility::isFruReplaceableAtRuntime(l_sysCfgJsonObj,
741 l_fruPath))
742 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600743 logging::logMessage(
744 "Given FRU is not replaceable at host runtime. Single FRU VPD collection is not performed for " +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500745 std::string(i_dbusObjPath));
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600746 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500747 }
748 }
749 else if (dbusUtility::isBMCReady())
750 {
751 if (!jsonUtility::isFruReplaceableAtStandby(l_sysCfgJsonObj,
752 l_fruPath) &&
753 (!jsonUtility::isFruReplaceableAtRuntime(l_sysCfgJsonObj,
754 l_fruPath)))
755 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600756 logging::logMessage(
757 "Given FRU is neither replaceable at standby nor replaceable at runtime. Single FRU VPD collection is not performed for " +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500758 std::string(i_dbusObjPath));
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600759 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500760 }
761 }
762
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600763 // Set CollectionStatus as InProgress. Since it's an intermediate state
764 // D-bus set-property call is good enough to update the status.
RekhaAparna01c532b182025-02-19 19:56:49 -0600765 const std::string& l_collStatusProp = "CollectionStatus";
766
767 if (!dbusUtility::writeDbusProperty(
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600768 jsonUtility::getServiceName(l_sysCfgJsonObj,
769 std::string(i_dbusObjPath)),
770 std::string(i_dbusObjPath), constants::vpdCollectionInterface,
771 l_collStatusProp,
RekhaAparna01c532b182025-02-19 19:56:49 -0600772 types::DbusVariantType{constants::vpdCollectionInProgress}))
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600773 {
774 logging::logMessage(
775 "Unable to set CollectionStatus as InProgress for " +
776 std::string(i_dbusObjPath) +
777 ". Continue single FRU VPD collection.");
778 }
779
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500780 // Parse VPD
781 types::VPDMapVariant l_parsedVpd = m_worker->parseVpdFile(l_fruPath);
782
783 // If l_parsedVpd is pointing to std::monostate
784 if (l_parsedVpd.index() == 0)
785 {
786 throw std::runtime_error(
787 "VPD parsing failed for " + std::string(i_dbusObjPath));
788 }
789
790 // Get D-bus object map from worker class
791 types::ObjectMap l_dbusObjectMap;
792 m_worker->populateDbus(l_parsedVpd, l_dbusObjectMap, l_fruPath);
793
794 if (l_dbusObjectMap.empty())
795 {
796 throw std::runtime_error(
797 "Failed to create D-bus object map. Single FRU VPD collection failed for " +
798 std::string(i_dbusObjPath));
799 }
800
801 // Call PIM's Notify method
802 if (!dbusUtility::callPIM(move(l_dbusObjectMap)))
803 {
804 throw std::runtime_error(
805 "Notify PIM failed. Single FRU VPD collection failed for " +
806 std::string(i_dbusObjPath));
807 }
808 }
809 catch (const std::exception& l_error)
810 {
Priyanga Ramasamy46b73d92025-01-09 10:52:07 -0600811 // Notify FRU's VPD CollectionStatus as Failure
812 if (!dbusUtility::notifyFRUCollectionStatus(
813 std::string(i_dbusObjPath), constants::vpdCollectionFailure))
814 {
815 logging::logMessage(
816 "Call to PIM Notify method failed to update Collection status as Failure for " +
817 std::string(i_dbusObjPath));
818 }
819
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500820 // TODO: Log PEL
821 logging::logMessage(std::string(l_error.what()));
822 }
823}
824
825void Manager::deleteSingleFruVpd(
826 const sdbusplus::message::object_path& i_dbusObjPath)
827{
828 try
829 {
830 if (std::string(i_dbusObjPath).empty())
831 {
832 throw std::runtime_error(
833 "Given DBus object path is empty. Aborting FRU VPD deletion.");
834 }
835
836 if (m_worker.get() == nullptr)
837 {
838 throw std::runtime_error(
839 "Worker object not found, can't perform FRU VPD deletion for: " +
840 std::string(i_dbusObjPath));
841 }
842
843 m_worker->deleteFruVpd(std::string(i_dbusObjPath));
844 }
845 catch (const std::exception& l_ex)
846 {
847 // TODO: Log PEL
848 logging::logMessage(l_ex.what());
849 }
850}
851
852bool Manager::isValidUnexpandedLocationCode(
853 const std::string& i_unexpandedLocationCode)
854{
855 if ((i_unexpandedLocationCode.length() <
856 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) ||
857 ((i_unexpandedLocationCode.compare(0, 4, "Ufcs") !=
858 constants::STR_CMP_SUCCESS) &&
859 (i_unexpandedLocationCode.compare(0, 4, "Umts") !=
860 constants::STR_CMP_SUCCESS)) ||
861 ((i_unexpandedLocationCode.length() >
862 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) &&
863 (i_unexpandedLocationCode.find("-") != 4)))
864 {
865 return false;
866 }
867
868 return true;
869}
870
871std::string Manager::getExpandedLocationCode(
872 const std::string& i_unexpandedLocationCode,
873 [[maybe_unused]] const uint16_t i_nodeNumber)
874{
875 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
876 {
877 phosphor::logging::elog<types::DbusInvalidArgument>(
878 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
879 types::InvalidArgument::ARGUMENT_VALUE(
880 i_unexpandedLocationCode.c_str()));
881 }
882
883 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
884 if (!l_sysCfgJsonObj.contains("frus"))
885 {
886 logging::logMessage("Missing frus tag in system config JSON");
887 }
888
889 const nlohmann::json& l_listOfFrus =
890 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
891
892 for (const auto& l_frus : l_listOfFrus.items())
893 {
894 for (const auto& l_aFru : l_frus.value())
895 {
896 if (l_aFru["extraInterfaces"].contains(
897 constants::locationCodeInf) &&
898 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
899 "LocationCode", "") == i_unexpandedLocationCode)
900 {
901 return std::get<std::string>(dbusUtility::readDbusProperty(
902 l_aFru["serviceName"], l_aFru["inventoryPath"],
903 constants::locationCodeInf, "LocationCode"));
904 }
905 }
906 }
907 phosphor::logging::elog<types::DbusInvalidArgument>(
908 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
909 types::InvalidArgument::ARGUMENT_VALUE(
910 i_unexpandedLocationCode.c_str()));
911}
912
913types::ListOfPaths Manager::getFrusByUnexpandedLocationCode(
914 const std::string& i_unexpandedLocationCode,
915 [[maybe_unused]] const uint16_t i_nodeNumber)
916{
917 types::ListOfPaths l_inventoryPaths;
918
919 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode))
920 {
921 phosphor::logging::elog<types::DbusInvalidArgument>(
922 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
923 types::InvalidArgument::ARGUMENT_VALUE(
924 i_unexpandedLocationCode.c_str()));
925 }
926
927 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
928 if (!l_sysCfgJsonObj.contains("frus"))
929 {
930 logging::logMessage("Missing frus tag in system config JSON");
931 }
932
933 const nlohmann::json& l_listOfFrus =
934 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
935
936 for (const auto& l_frus : l_listOfFrus.items())
937 {
938 for (const auto& l_aFru : l_frus.value())
939 {
940 if (l_aFru["extraInterfaces"].contains(
941 constants::locationCodeInf) &&
942 l_aFru["extraInterfaces"][constants::locationCodeInf].value(
943 "LocationCode", "") == i_unexpandedLocationCode)
944 {
945 l_inventoryPaths.push_back(
946 l_aFru.at("inventoryPath")
947 .get_ref<const nlohmann::json::string_t&>());
948 }
949 }
950 }
951
952 if (l_inventoryPaths.empty())
953 {
954 phosphor::logging::elog<types::DbusInvalidArgument>(
955 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
956 types::InvalidArgument::ARGUMENT_VALUE(
957 i_unexpandedLocationCode.c_str()));
958 }
959
960 return l_inventoryPaths;
961}
962
Patrick Williams43fedab2025-02-03 14:28:05 -0500963std::string Manager::getHwPath(
964 const sdbusplus::message::object_path& i_dbusObjPath)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500965{
966 // Dummy code to supress unused variable warning. To be removed.
967 logging::logMessage(std::string(i_dbusObjPath));
968
969 return std::string{};
970}
971
972std::tuple<std::string, uint16_t> Manager::getUnexpandedLocationCode(
973 const std::string& i_expandedLocationCode)
974{
975 /**
976 * Location code should always start with U and fulfil minimum length
977 * criteria.
978 */
979 if (i_expandedLocationCode[0] != 'U' ||
980 i_expandedLocationCode.length() <
981 constants::EXP_LOCATION_CODE_MIN_LENGTH)
982 {
983 phosphor::logging::elog<types::DbusInvalidArgument>(
984 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
985 types::InvalidArgument::ARGUMENT_VALUE(
986 i_expandedLocationCode.c_str()));
987 }
988
989 std::string l_fcKwd;
990
991 auto l_fcKwdValue = dbusUtility::readDbusProperty(
992 "xyz.openbmc_project.Inventory.Manager",
993 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
994 "com.ibm.ipzvpd.VCEN", "FC");
995
996 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_fcKwdValue))
997 {
998 l_fcKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
999 }
1000
1001 // Get the first part of expanded location code to check for FC or TM.
1002 std::string l_firstKwd = i_expandedLocationCode.substr(1, 4);
1003
1004 std::string l_unexpandedLocationCode{};
1005 uint16_t l_nodeNummber = constants::INVALID_NODE_NUMBER;
1006
1007 // Check if this value matches the value of FC keyword.
1008 if (l_fcKwd.substr(0, 4) == l_firstKwd)
1009 {
1010 /**
1011 * Period(.) should be there in expanded location code to seggregate
1012 * FC, node number and SE values.
1013 */
1014 size_t l_nodeStartPos = i_expandedLocationCode.find('.');
1015 if (l_nodeStartPos == std::string::npos)
1016 {
1017 phosphor::logging::elog<types::DbusInvalidArgument>(
1018 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
1019 types::InvalidArgument::ARGUMENT_VALUE(
1020 i_expandedLocationCode.c_str()));
1021 }
1022
1023 size_t l_nodeEndPos =
1024 i_expandedLocationCode.find('.', l_nodeStartPos + 1);
1025 if (l_nodeEndPos == std::string::npos)
1026 {
1027 phosphor::logging::elog<types::DbusInvalidArgument>(
1028 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
1029 types::InvalidArgument::ARGUMENT_VALUE(
1030 i_expandedLocationCode.c_str()));
1031 }
1032
1033 // Skip 3 bytes for '.ND'
1034 l_nodeNummber = std::stoi(i_expandedLocationCode.substr(
1035 l_nodeStartPos + 3, (l_nodeEndPos - l_nodeStartPos - 3)));
1036
1037 /**
1038 * Confirm if there are other details apart FC, node number and SE
1039 * in location code
1040 */
1041 if (i_expandedLocationCode.length() >
1042 constants::EXP_LOCATION_CODE_MIN_LENGTH)
1043 {
1044 l_unexpandedLocationCode =
1045 i_expandedLocationCode[0] + std::string("fcs") +
1046 i_expandedLocationCode.substr(
1047 l_nodeEndPos + 1 + constants::SE_KWD_LENGTH,
1048 std::string::npos);
1049 }
1050 else
1051 {
1052 l_unexpandedLocationCode = "Ufcs";
1053 }
1054 }
1055 else
1056 {
1057 std::string l_tmKwd;
1058 // Read TM keyword value.
1059 auto l_tmKwdValue = dbusUtility::readDbusProperty(
1060 "xyz.openbmc_project.Inventory.Manager",
1061 "/xyz/openbmc_project/inventory/system/chassis/motherboard",
1062 "com.ibm.ipzvpd.VSYS", "TM");
1063
1064 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_tmKwdValue))
1065 {
1066 l_tmKwd.assign(l_kwdValue->begin(), l_kwdValue->end());
1067 }
1068
1069 // Check if the substr matches to TM keyword value.
1070 if (l_tmKwd.substr(0, 4) == l_firstKwd)
1071 {
1072 /**
1073 * System location code will not have node number and any other
1074 * details.
1075 */
1076 l_unexpandedLocationCode = "Umts";
1077 }
1078 // The given location code is neither "fcs" or "mts".
1079 else
1080 {
1081 phosphor::logging::elog<types::DbusInvalidArgument>(
1082 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"),
1083 types::InvalidArgument::ARGUMENT_VALUE(
1084 i_expandedLocationCode.c_str()));
1085 }
1086 }
1087
1088 return std::make_tuple(l_unexpandedLocationCode, l_nodeNummber);
1089}
1090
1091types::ListOfPaths Manager::getFrusByExpandedLocationCode(
1092 const std::string& i_expandedLocationCode)
1093{
1094 std::tuple<std::string, uint16_t> l_locationAndNodePair =
1095 getUnexpandedLocationCode(i_expandedLocationCode);
1096
1097 return getFrusByUnexpandedLocationCode(std::get<0>(l_locationAndNodePair),
1098 std::get<1>(l_locationAndNodePair));
1099}
1100
1101void Manager::registerHostStateChangeCallback()
1102{
1103 static std::shared_ptr<sdbusplus::bus::match_t> l_hostState =
1104 std::make_shared<sdbusplus::bus::match_t>(
1105 *m_asioConnection,
1106 sdbusplus::bus::match::rules::propertiesChanged(
1107 constants::hostObjectPath, constants::hostInterface),
1108 [this](sdbusplus::message_t& i_msg) {
1109 hostStateChangeCallBack(i_msg);
1110 });
1111}
1112
1113void Manager::hostStateChangeCallBack(sdbusplus::message_t& i_msg)
1114{
1115 try
1116 {
1117 if (i_msg.is_method_error())
1118 {
1119 throw std::runtime_error(
1120 "Error reading callback message for host state");
1121 }
1122
1123 std::string l_objectPath;
1124 types::PropertyMap l_propMap;
1125 i_msg.read(l_objectPath, l_propMap);
1126
1127 const auto l_itr = l_propMap.find("CurrentHostState");
1128
1129 if (l_itr == l_propMap.end())
1130 {
1131 throw std::runtime_error(
1132 "CurrentHostState field is missing in callback message");
1133 }
1134
1135 if (auto l_hostState = std::get_if<std::string>(&(l_itr->second)))
1136 {
1137 // implies system is moving from standby to power on state
1138 if (*l_hostState == "xyz.openbmc_project.State.Host.HostState."
1139 "TransitioningToRunning")
1140 {
1141 // TODO: check for all the essential FRUs in the system.
1142
1143 // Perform recollection.
1144 performVpdRecollection();
1145 return;
1146 }
1147 }
1148 else
1149 {
1150 throw std::runtime_error(
1151 "Invalid type recieved in variant for host state.");
1152 }
1153 }
1154 catch (const std::exception& l_ex)
1155 {
1156 // TODO: Log PEL.
1157 logging::logMessage(l_ex.what());
1158 }
1159}
1160
1161void Manager::performVpdRecollection()
1162{
1163 try
1164 {
1165 if (m_worker.get() != nullptr)
1166 {
1167 nlohmann::json l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
1168
1169 // Check if system config JSON is present
1170 if (l_sysCfgJsonObj.empty())
1171 {
1172 throw std::runtime_error(
1173 "System config json object is empty, can't process recollection.");
1174 }
1175
1176 const auto& l_frusReplaceableAtStandby =
1177 jsonUtility::getListOfFrusReplaceableAtStandby(l_sysCfgJsonObj);
1178
1179 for (const auto& l_fruInventoryPath : l_frusReplaceableAtStandby)
1180 {
1181 // ToDo: Add some logic/trace to know the flow to
1182 // collectSingleFruVpd has been directed via
1183 // performVpdRecollection.
1184 collectSingleFruVpd(l_fruInventoryPath);
1185 }
1186 return;
1187 }
1188
1189 throw std::runtime_error(
1190 "Worker object not found can't process recollection");
1191 }
1192 catch (const std::exception& l_ex)
1193 {
1194 // TODO Log PEL
1195 logging::logMessage(
1196 "VPD recollection failed with error: " + std::string(l_ex.what()));
1197 }
1198}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001199} // namespace vpd