blob: fa3f0645827e010e7f1a98abd1e1f72eb535b702 [file] [log] [blame]
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +05301#include "config.h"
2
Sunny Srivastava867ee752025-04-15 12:24:23 +05303#include "ibm_handler.hpp"
4
Sunny Srivastavac607fe52025-11-18 20:52:23 +05305#include "configuration.hpp"
Anupama B R56e45372025-06-19 12:54:44 -05006#include "listener.hpp"
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +05307#include "parser.hpp"
8
Sunny Srivastava78a50422025-04-25 11:17:56 +05309#include <utility/common_utility.hpp>
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053010#include <utility/dbus_utility.hpp>
11#include <utility/json_utility.hpp>
12#include <utility/vpd_specific_utility.hpp>
13
Sunny Srivastava867ee752025-04-15 12:24:23 +053014namespace vpd
15{
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053016IbmHandler::IbmHandler(
17 std::shared_ptr<Worker>& o_worker,
18 std::shared_ptr<BackupAndRestore>& o_backupAndRestoreObj,
19 const std::shared_ptr<sdbusplus::asio::dbus_interface>& i_iFace,
Anupama B Rda9806b2025-08-29 02:41:10 -050020 const std::shared_ptr<sdbusplus::asio::dbus_interface>& i_progressiFace,
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053021 const std::shared_ptr<boost::asio::io_context>& i_ioCon,
22 const std::shared_ptr<sdbusplus::asio::connection>& i_asioConnection) :
23 m_worker(o_worker), m_backupAndRestoreObj(o_backupAndRestoreObj),
Anupama B Rda9806b2025-08-29 02:41:10 -050024 m_interface(i_iFace), m_progressInterface(i_progressiFace),
Souvik Roya5e18b82025-09-25 05:59:56 +000025 m_ioContext(i_ioCon), m_asioConnection(i_asioConnection),
26 m_logger(Logger::getLoggerInstance())
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053027{
Souvik Royc1171732025-10-16 09:27:38 +000028 uint16_t l_errCode{0};
29
30 // check VPD collection mode
31 const auto l_vpdCollectionMode =
32 commonUtility::isFieldModeEnabled()
33 ? types::VpdCollectionMode::DEFAULT_MODE
34 : commonUtility::getVpdCollectionMode(l_errCode);
35
36 if (l_errCode)
37 {
38 m_logger->logMessage(
39 "Error while trying to read VPD collection mode: " +
40 commonUtility::getErrCodeMsg(l_errCode));
Souvik Royc1171732025-10-16 09:27:38 +000041 }
42
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053043 if (dbusUtility::isChassisPowerOn())
44 {
45 // At power on, less number of FRU(s) needs collection. we can scale
46 // down the threads to reduce CPU utilization.
Souvik Royc1171732025-10-16 09:27:38 +000047 m_worker = std::make_shared<Worker>(
48 INVENTORY_JSON_DEFAULT, constants::VALUE_1, l_vpdCollectionMode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053049 }
50 else
51 {
52 // Initialize with default configuration
Souvik Royc1171732025-10-16 09:27:38 +000053 m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT,
54 constants::MAX_THREADS,
55 l_vpdCollectionMode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053056 }
57
58 // Set up minimal things that is needed before bus name is claimed.
Sunny Srivastava78a50422025-04-25 11:17:56 +053059 performInitialSetup();
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053060
Sunny Srivastavac607fe52025-11-18 20:52:23 +053061 // If the object is created, implies back up and restore took place in
62 // system VPD flow.
63 if ((m_backupAndRestoreObj == nullptr) && !m_sysCfgJsonObj.empty() &&
Rekha Aparna196e3082025-09-08 20:40:35 -050064 jsonUtility::isBackupAndRestoreRequired(m_sysCfgJsonObj, l_errCode))
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053065 {
66 try
67 {
68 m_backupAndRestoreObj =
69 std::make_shared<BackupAndRestore>(m_sysCfgJsonObj);
70 }
71 catch (const std::exception& l_ex)
72 {
73 logging::logMessage("Back up and restore instantiation failed. {" +
74 std::string(l_ex.what()) + "}");
75
76 EventLogger::createSyncPel(
77 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
78 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
79 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
80 }
81 }
Rekha Aparna196e3082025-09-08 20:40:35 -050082 else if (l_errCode)
83 {
84 logging::logMessage(
85 "Failed to check if backup & restore required. Error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +053086 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna196e3082025-09-08 20:40:35 -050087 }
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053088
Anupama B Rc7565ed2025-06-19 02:08:39 -050089 // Instantiate Listener object
Anupama B R56e45372025-06-19 12:54:44 -050090 m_eventListener = std::make_shared<Listener>(m_worker, m_asioConnection);
91 m_eventListener->registerAssetTagChangeCallback();
92 m_eventListener->registerHostStateChangeCallback();
Souvik Roy5c3a1562025-07-02 01:39:44 -050093 m_eventListener->registerPresenceChangeCallback();
Anupama B Rc7565ed2025-06-19 02:08:39 -050094
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053095 // Instantiate GpioMonitor class
96 m_gpioMonitor =
97 std::make_shared<GpioMonitor>(m_sysCfgJsonObj, m_worker, m_ioContext);
98}
99
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530100void IbmHandler::SetTimerToDetectVpdCollectionStatus()
101{
102 // Keeping max retry for 2 minutes. TODO: Make it configurable based on
103 // system type.
104 static constexpr auto MAX_RETRY = 12;
105
106 static boost::asio::steady_timer l_timer(*m_ioContext);
107 static uint8_t l_timerRetry = 0;
108
109 auto l_asyncCancelled = l_timer.expires_after(std::chrono::seconds(10));
110
111 (l_asyncCancelled == 0)
112 ? logging::logMessage("Collection Timer started")
113 : logging::logMessage("Collection Timer re-started");
114
115 l_timer.async_wait([this](const boost::system::error_code& ec) {
116 if (ec == boost::asio::error::operation_aborted)
117 {
118 throw std::runtime_error(
119 "Timer to detect thread collection status was aborted");
120 }
121
122 if (ec)
123 {
124 throw std::runtime_error(
125 "Timer to detect thread collection failed");
126 }
127
128 if (m_worker->isAllFruCollectionDone())
129 {
130 // cancel the timer
131 l_timer.cancel();
132 processFailedEeproms();
133
134 // update VPD for powerVS system.
135 ConfigurePowerVsSystem();
136
137 std::cout << "m_worker->isSystemVPDOnDBus() completed" << std::endl;
Anupama B Rda9806b2025-08-29 02:41:10 -0500138 m_progressInterface->set_property(
139 "Status", std::string(constants::vpdCollectionCompleted));
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530140
141 if (m_backupAndRestoreObj)
142 {
143 m_backupAndRestoreObj->backupAndRestore();
144 }
Souvik Roy3d4af4a2025-06-23 04:45:27 -0500145
146 if (m_eventListener)
147 {
Souvik Roy762cdab2025-11-04 13:07:56 +0000148 // Check if system config JSON specifies
149 // correlatedPropertiesJson
150 if (m_sysCfgJsonObj.contains("correlatedPropertiesConfigPath"))
151 {
152 // register correlated properties callback with specific
153 // correlated properties JSON
154 m_eventListener->registerCorrPropCallBack(
155 m_sysCfgJsonObj["correlatedPropertiesConfigPath"]);
156 }
157 else
158 {
159 m_logger->logMessage(
160 "Correlated properties JSON path is not defined in system config JSON. Correlated properties listener is disabled.");
161 }
Souvik Roy3d4af4a2025-06-23 04:45:27 -0500162 }
Alpana Kumari138489f2025-11-10 08:59:20 -0600163#ifdef ENABLE_FILE_LOGGING
Souvik Roya5e18b82025-09-25 05:59:56 +0000164 // terminate collection logger
165 m_logger->terminateVpdCollectionLogging();
Alpana Kumari138489f2025-11-10 08:59:20 -0600166#endif
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530167 }
168 else
169 {
170 auto l_threadCount = m_worker->getActiveThreadCount();
171 if (l_timerRetry == MAX_RETRY)
172 {
173 l_timer.cancel();
174 logging::logMessage("Taking too long. Active thread = " +
175 std::to_string(l_threadCount));
Alpana Kumari138489f2025-11-10 08:59:20 -0600176#ifdef ENABLE_FILE_LOGGING
Souvik Roya5e18b82025-09-25 05:59:56 +0000177 // terminate collection logger
178 m_logger->terminateVpdCollectionLogging();
Alpana Kumari138489f2025-11-10 08:59:20 -0600179#endif
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530180 }
181 else
182 {
183 l_timerRetry++;
184 logging::logMessage("Collection is in progress for [" +
185 std::to_string(l_threadCount) + "] FRUs.");
186
187 SetTimerToDetectVpdCollectionStatus();
188 }
189 }
190 });
191}
192
193void IbmHandler::checkAndUpdatePowerVsVpd(
194 const nlohmann::json& i_powerVsJsonObj,
195 std::vector<std::string>& o_failedPathList)
196{
197 for (const auto& [l_fruPath, l_recJson] : i_powerVsJsonObj.items())
198 {
199 nlohmann::json l_sysCfgJsonObj{};
200 if (m_worker.get() != nullptr)
201 {
202 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
203 }
204
205 // The utility method will handle emty JSON case. No explicit
206 // handling required here.
Rekha Aparna017567a2025-08-13 02:07:06 -0500207 uint16_t l_errCode = 0;
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530208 auto l_inventoryPath = jsonUtility::getInventoryObjPathFromJson(
Rekha Aparna017567a2025-08-13 02:07:06 -0500209 l_sysCfgJsonObj, l_fruPath, l_errCode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530210
211 // Mark it as failed if inventory path not found in JSON.
212 if (l_inventoryPath.empty())
213 {
Rekha Aparna017567a2025-08-13 02:07:06 -0500214 if (l_errCode)
215 {
216 logging::logMessage(
217 "Failed to get inventory object path from JSON for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +0530218 l_fruPath +
219 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -0500220 }
221
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530222 o_failedPathList.push_back(l_fruPath);
223 continue;
224 }
225
226 // check if the FRU is present
227 if (!dbusUtility::isInventoryPresent(l_inventoryPath))
228 {
229 logging::logMessage(
230 "Inventory not present, skip updating part number. Path: " +
231 l_inventoryPath);
232 continue;
233 }
234
235 // check if the FRU needs CCIN check before updating PN.
236 if (l_recJson.contains("CCIN"))
237 {
238 const auto& l_ccinFromDbus =
Rekha Aparna80b674f2025-10-27 01:27:27 -0500239 vpdSpecificUtility::getCcinFromDbus(l_inventoryPath, l_errCode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530240
241 // Not an ideal situation as CCIN can't be empty.
242 if (l_ccinFromDbus.empty())
243 {
Rekha Aparna80b674f2025-10-27 01:27:27 -0500244 if (l_errCode)
245 {
246 m_logger->logMessage(
247 "Failed to get CCIN value from DBus, error : " +
248 commonUtility::getErrCodeMsg(l_errCode));
249 }
250
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530251 o_failedPathList.push_back(l_fruPath);
252 continue;
253 }
254
255 std::vector<std::string> l_ccinListFromJson = l_recJson["CCIN"];
256
257 if (find(l_ccinListFromJson.begin(), l_ccinListFromJson.end(),
258 l_ccinFromDbus) == l_ccinListFromJson.end())
259 {
260 // Don't update PN in this case.
261 continue;
262 }
263 }
264
265 for (const auto& [l_recordName, l_kwdJson] : l_recJson.items())
266 {
267 // Record name can't be CCIN, skip processing as it is there for PN
268 // update based on CCIN check.
269 if (l_recordName == constants::kwdCCIN)
270 {
271 continue;
272 }
273
274 for (const auto& [l_kwdName, l_kwdValue] : l_kwdJson.items())
275 {
276 // Is value of type array.
277 if (!l_kwdValue.is_array())
278 {
279 o_failedPathList.push_back(l_fruPath);
280 continue;
281 }
282
283 // Get current FRU Part number.
284 auto l_retVal = dbusUtility::readDbusProperty(
285 constants::pimServiceName, l_inventoryPath,
286 constants::viniInf, constants::kwdFN);
287
288 auto l_ptrToFn = std::get_if<types::BinaryVector>(&l_retVal);
289
290 if (!l_ptrToFn)
291 {
292 o_failedPathList.push_back(l_fruPath);
293 continue;
294 }
295
296 types::BinaryVector l_binaryKwdValue =
297 l_kwdValue.get<types::BinaryVector>();
298 if (l_binaryKwdValue == (*l_ptrToFn))
299 {
300 continue;
301 }
302
303 // Update part number only if required.
304 std::shared_ptr<Parser> l_parserObj =
305 std::make_shared<Parser>(l_fruPath, l_sysCfgJsonObj);
306 if (l_parserObj->updateVpdKeyword(std::make_tuple(
307 l_recordName, l_kwdName, l_binaryKwdValue)) ==
308 constants::FAILURE)
309 {
310 o_failedPathList.push_back(l_fruPath);
311 continue;
312 }
313
314 // update the Asset interface Spare part number explicitly.
315 if (!dbusUtility::callPIM(types::ObjectMap{
316 {l_inventoryPath,
317 {{constants::assetInf,
318 {{"SparePartNumber",
319 std::string(l_binaryKwdValue.begin(),
320 l_binaryKwdValue.end())}}}}}}))
321 {
322 logging::logMessage(
323 "Updating Spare Part Number under Asset interface failed for path [" +
324 l_inventoryPath + "]");
325 }
326
327 // Just needed for logging.
328 std::string l_initialPartNum((*l_ptrToFn).begin(),
329 (*l_ptrToFn).end());
330 std::string l_finalPartNum(l_binaryKwdValue.begin(),
331 l_binaryKwdValue.end());
332 logging::logMessage(
333 "FRU Part number updated for path [" + l_inventoryPath +
334 "]" + "From [" + l_initialPartNum + "]" + " to [" +
335 l_finalPartNum + "]");
336 }
337 }
338 }
339}
340
341void IbmHandler::ConfigurePowerVsSystem()
342{
343 std::vector<std::string> l_failedPathList;
344 try
345 {
346 types::BinaryVector l_imValue = dbusUtility::getImFromDbus();
347 if (l_imValue.empty())
348 {
349 throw DbusException("Invalid IM value read from Dbus");
350 }
351
Rekha Aparnaed09af82025-10-22 20:34:41 -0500352 uint16_t l_errCode = 0;
353 if (!vpdSpecificUtility::isPowerVsConfiguration(l_imValue, l_errCode))
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530354 {
355 // TODO: Should booting be blocked in case of some
356 // misconfigurations?
Rekha Aparnaed09af82025-10-22 20:34:41 -0500357 if (l_errCode)
358 {
359 logging::logMessage(
360 "Failed to check if the system is powerVs Configuration, error : " +
361 commonUtility::getErrCodeMsg(l_errCode));
362 }
363
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530364 return;
365 }
366
367 const nlohmann::json& l_powerVsJsonObj =
Rekha Aparnaadf85262025-09-09 00:41:00 -0500368 jsonUtility::getPowerVsJson(l_imValue, l_errCode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530369
370 if (l_powerVsJsonObj.empty())
371 {
Rekha Aparnac6159a22025-10-09 12:20:20 +0530372 throw std::runtime_error("PowerVS Json not found. Error : " +
373 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530374 }
375
376 checkAndUpdatePowerVsVpd(l_powerVsJsonObj, l_failedPathList);
377
378 if (!l_failedPathList.empty())
379 {
380 throw std::runtime_error(
381 "Part number update failed for following paths: ");
382 }
383 }
384 catch (const std::exception& l_ex)
385 {
386 // TODO log appropriate PEL
387 }
388}
389
390void IbmHandler::processFailedEeproms()
391{
392 if (m_worker.get() != nullptr)
393 {
394 // TODO:
395 // - iterate through list of EEPROMs for which thread creation has
396 // failed
397 // - For each failed EEPROM, trigger VPD collection
398 m_worker->getFailedEepromPaths().clear();
399 }
400}
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530401
Sunny Srivastava78a50422025-04-25 11:17:56 +0530402void IbmHandler::enableMuxChips()
403{
404 if (m_sysCfgJsonObj.empty())
405 {
406 // config JSON should not be empty at this point of execution.
407 throw std::runtime_error("Config JSON is empty. Can't enable muxes");
408 return;
409 }
410
411 if (!m_sysCfgJsonObj.contains("muxes"))
412 {
413 logging::logMessage("No mux defined for the system in config JSON");
414 return;
415 }
416
417 // iterate over each MUX detail and enable them.
418 for (const auto& item : m_sysCfgJsonObj["muxes"])
419 {
420 if (item.contains("holdidlepath"))
421 {
422 std::string cmd = "echo 0 > ";
423 cmd += item["holdidlepath"];
424
425 logging::logMessage("Enabling mux with command = " + cmd);
426
427 commonUtility::executeCmd(cmd);
428 continue;
429 }
430
431 logging::logMessage(
432 "Mux Entry does not have hold idle path. Can't enable the mux");
433 }
434}
435
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530436void IbmHandler::getSystemJson(std::string& o_systemJson,
437 const types::VPDMapVariant& i_parsedVpdMap)
438{
439 if (auto l_pVal = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
440 {
441 uint16_t l_errCode = 0;
442 std::string l_hwKWdValue =
443 vpdSpecificUtility::getHWVersion(*l_pVal, l_errCode);
444 if (l_hwKWdValue.empty())
445 {
446 if (l_errCode)
447 {
448 throw DataException("Failed to fetch HW value. Reason: " +
449 commonUtility::getErrCodeMsg(l_errCode));
450 }
451 throw DataException("HW value fetched is empty.");
452 }
453
454 const std::string& l_imKwdValue =
455 vpdSpecificUtility::getIMValue(*l_pVal, l_errCode);
456 if (l_imKwdValue.empty())
457 {
458 if (l_errCode)
459 {
460 throw DataException("Failed to fetch IM value. Reason: " +
461 commonUtility::getErrCodeMsg(l_errCode));
462 }
463 throw DataException("IM value fetched is empty.");
464 }
465
466 auto l_itrToIM = config::systemType.find(l_imKwdValue);
467 if (l_itrToIM == config::systemType.end())
468 {
469 throw DataException("IM keyword does not map to any system type");
470 }
471
472 const types::HWVerList l_hwVersionList = l_itrToIM->second.second;
473 if (!l_hwVersionList.empty())
474 {
475 transform(l_hwKWdValue.begin(), l_hwKWdValue.end(),
476 l_hwKWdValue.begin(), ::toupper);
477
478 auto l_itrToHW =
479 std::find_if(l_hwVersionList.begin(), l_hwVersionList.end(),
480 [&l_hwKWdValue](const auto& l_aPair) {
481 return l_aPair.first == l_hwKWdValue;
482 });
483
484 if (l_itrToHW != l_hwVersionList.end())
485 {
486 if (!(*l_itrToHW).second.empty())
487 {
488 o_systemJson += (*l_itrToIM).first + "_" +
489 (*l_itrToHW).second + ".json";
490 }
491 else
492 {
493 o_systemJson += (*l_itrToIM).first + ".json";
494 }
495 return;
496 }
497 }
498 o_systemJson += l_itrToIM->second.first + ".json";
499 return;
500 }
501
502 throw DataException(
503 "Invalid VPD type returned from Parser. Can't get system JSON.");
504}
505
506static void setEnvAndReboot(const std::string& i_key,
507 const std::string& i_value)
508{
509 // set env and reboot and break.
510 commonUtility::executeCmd("/sbin/fw_setenv", i_key, i_value);
511 logging::logMessage("Rebooting BMC to pick up new device tree");
512
513 // make dbus call to reboot
514 auto l_bus = sdbusplus::bus::new_default_system();
515 auto l_method = l_bus.new_method_call(
516 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
517 "org.freedesktop.systemd1.Manager", "Reboot");
518 l_bus.call_noreply(l_method);
519}
520
521static std::string readFitConfigValue()
522{
523 std::vector<std::string> l_output =
524 commonUtility::executeCmd("/sbin/fw_printenv");
525 std::string l_fitConfigValue;
526
527 for (const auto& l_entry : l_output)
528 {
529 auto l_pos = l_entry.find("=");
530 auto l_key = l_entry.substr(0, l_pos);
531 if (l_key != "fitconfig")
532 {
533 continue;
534 }
535
536 if (l_pos + 1 < l_entry.size())
537 {
538 l_fitConfigValue = l_entry.substr(l_pos + 1);
539 }
540 }
541
542 return l_fitConfigValue;
543}
544
545bool IbmHandler::isBackupOnCache()
546{
547 try
548 {
549 uint16_t l_errCode = 0;
550 std::string l_backupAndRestoreCfgFilePath =
551 m_sysCfgJsonObj.value("backupRestoreConfigPath", "");
552
553 if (l_backupAndRestoreCfgFilePath.empty())
554 {
555 m_logger->logMessage(
556 "backupRestoreConfigPath is not found in JSON. Can't determne the backup path.");
557 return false;
558 }
559
560 nlohmann::json l_backupAndRestoreCfgJsonObj =
561 jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath,
562 l_errCode);
563 if (l_backupAndRestoreCfgJsonObj.empty() || l_errCode)
564 {
565 m_logger->logMessage(
566 "JSON parsing failed for file [ " +
567 std::string(l_backupAndRestoreCfgFilePath) +
568 " ], error : " + commonUtility::getErrCodeMsg(l_errCode));
569 return false;
570 }
571
572 // check if either of "source" or "destination" has inventory path.
573 // this indicates that this sytem has System VPD on hardware
574 // and other copy on D-Bus (BMC cache).
575 if (!l_backupAndRestoreCfgJsonObj.empty() &&
576 ((l_backupAndRestoreCfgJsonObj.contains("source") &&
577 l_backupAndRestoreCfgJsonObj["source"].contains(
578 "inventoryPath")) ||
579 (l_backupAndRestoreCfgJsonObj.contains("destination") &&
580 l_backupAndRestoreCfgJsonObj["destination"].contains(
581 "inventoryPath"))))
582 {
583 return true;
584 }
585 }
586 catch (const std::exception& l_ex)
587 {
588 m_logger->logMessage(
589 "Exception while checking for backup on cache. Reason:" +
590 std::string(l_ex.what()));
591 }
592
593 // In case of any failure/ambiguity. Don't perform back up and restore.
594 return false;
595}
596
597void IbmHandler::performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap)
598{
599 try
600 {
601 m_backupAndRestoreObj =
602 std::make_shared<BackupAndRestore>(m_sysCfgJsonObj);
603 auto [l_srcVpdVariant,
604 l_dstVpdVariant] = m_backupAndRestoreObj->backupAndRestore();
605
606 // ToDo: Revisit is this check is required or not.
607 if (auto l_srcVpdMap = std::get_if<types::IPZVpdMap>(&l_srcVpdVariant);
608 l_srcVpdMap && !(*l_srcVpdMap).empty())
609 {
610 io_srcVpdMap = std::move(l_srcVpdVariant);
611 }
612 }
613 catch (const std::exception& l_ex)
614 {
615 EventLogger::createSyncPel(
616 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
617 __FILE__, __FUNCTION__, 0,
618 std::string(
619 "Exception caught while backup and restore VPD keyword's.") +
620 EventLogger::getErrorMsg(l_ex),
621 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
622 }
623}
624
625void IbmHandler::setDeviceTreeAndJson()
626{
627 // JSON is madatory for processing of this API.
628 if (m_sysCfgJsonObj.empty())
629 {
630 throw JsonException("System config JSON is empty", m_sysCfgJsonObj);
631 }
632
633 // parse system VPD
634 auto l_parsedVpdMap = m_worker->parseVpdFile(SYSTEM_VPD_FILE_PATH);
635
636 // Implies it is default JSON.
637 std::string l_systemJson{JSON_ABSOLUTE_PATH_PREFIX};
638
639 // get system JSON as per the system configuration.
640 getSystemJson(l_systemJson, l_parsedVpdMap);
641
642 if (!l_systemJson.compare(JSON_ABSOLUTE_PATH_PREFIX))
643 {
644 throw DataException(
645 "No system JSON found corresponding to IM read from VPD.");
646 }
647
648 uint16_t l_errCode = 0;
649 // re-parse the JSON once appropriate JSON has been selected.
650 m_sysCfgJsonObj = jsonUtility::getParsedJson(l_systemJson, l_errCode);
651
652 if (l_errCode)
653 {
654 throw(JsonException(
655 "JSON parsing failed for file [ " + l_systemJson +
656 " ], error : " + commonUtility::getErrCodeMsg(l_errCode),
657 l_systemJson));
658 }
659
660 m_worker->setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
661 constants::vpdCollectionInProgress);
662
663 std::string l_devTreeFromJson;
664 if (m_sysCfgJsonObj.contains("devTree"))
665 {
666 l_devTreeFromJson = m_sysCfgJsonObj["devTree"];
667
668 if (l_devTreeFromJson.empty())
669 {
670 EventLogger::createSyncPel(
671 types::ErrorType::JsonFailure, types::SeverityType::Error,
672 __FILE__, __FUNCTION__, 0,
673 "Mandatory value for device tree missing from JSON[" +
674 l_systemJson + "]",
675 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
676 }
677 }
678
679 auto l_fitConfigVal = readFitConfigValue();
680
681 if (l_devTreeFromJson.empty() ||
682 l_fitConfigVal.find(l_devTreeFromJson) != std::string::npos)
683 { // Skipping setting device tree as either devtree info is missing from
684 // Json or it is rightly set.
685
686 m_worker->setJsonSymbolicLink(l_systemJson);
687
688 const std::string& l_systemVpdInvPath =
689 jsonUtility::getInventoryObjPathFromJson(
690 m_sysCfgJsonObj, SYSTEM_VPD_FILE_PATH, l_errCode);
691
692 if (l_systemVpdInvPath.empty())
693 {
694 if (l_errCode)
695 {
696 throw JsonException(
697 "System vpd inventory path not found in JSON. Reason:" +
698 commonUtility::getErrCodeMsg(l_errCode),
699 INVENTORY_JSON_SYM_LINK);
700 }
701 throw JsonException("System vpd inventory path is missing in JSON",
702 INVENTORY_JSON_SYM_LINK);
703 }
704
705 // TODO: for backward compatibility this should also support motherboard
706 // interface.
707 std::vector<std::string> l_interfaceList{
708 constants::motherboardInterface};
709 const types::MapperGetObject& l_sysVpdObjMap =
710 dbusUtility::getObjectMap(l_systemVpdInvPath, l_interfaceList);
711
712 if (!l_sysVpdObjMap.empty())
713 {
714 if (isBackupOnCache() && jsonUtility::isBackupAndRestoreRequired(
715 m_sysCfgJsonObj, l_errCode))
716 {
717 performBackupAndRestore(l_parsedVpdMap);
718 }
719 else if (l_errCode)
720 {
721 logging::logMessage(
722 "Failed to check if backup and restore required. Reason : " +
723 commonUtility::getErrCodeMsg(l_errCode));
724 }
725 }
726
727 // proceed to publish system VPD.
728 m_worker->publishSystemVPD(l_parsedVpdMap);
729 m_worker->setCollectionStatusProperty(
730 SYSTEM_VPD_FILE_PATH, constants::vpdCollectionCompleted);
731 return;
732 }
733
734 setEnvAndReboot("fitconfig", l_devTreeFromJson);
735 exit(EXIT_SUCCESS);
736}
737
Sunny Srivastava78a50422025-04-25 11:17:56 +0530738void IbmHandler::performInitialSetup()
739{
740 try
741 {
Anupama B R281e2d42025-05-05 10:05:13 -0500742 if (m_worker.get() == nullptr)
743 {
744 throw std::runtime_error(
745 "Worker object not found. Can't perform initial setup.");
746 }
747
748 m_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
Sunny Srivastava78a50422025-04-25 11:17:56 +0530749 if (!dbusUtility::isChassisPowerOn())
750 {
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530751 setDeviceTreeAndJson();
Sunny Srivastava78a50422025-04-25 11:17:56 +0530752 }
753
Anupama B R95083d42025-10-27 04:54:58 -0500754 // Update BMC postion for RBMC prototype system
755 // Ignore BMC position update in case of any error
756 uint16_t l_errCode = 0;
Anupama B R657aaa82025-10-30 04:12:24 -0500757 if (isRbmcPrototypeSystem(l_errCode))
Anupama B R95083d42025-10-27 04:54:58 -0500758 {
Anupama B R657aaa82025-10-30 04:12:24 -0500759 size_t l_bmcPosition = std::numeric_limits<size_t>::max();
760 checkAndUpdateBmcPosition(l_bmcPosition);
Anupama B R95083d42025-10-27 04:54:58 -0500761
Anupama B R657aaa82025-10-30 04:12:24 -0500762 if (dbusUtility::callPIM(types::ObjectMap{
763 {sdbusplus::message::object_path(constants::systemInvPath),
764 {{constants::rbmcPositionInterface,
765 {{"Position", l_bmcPosition}}}}}}))
766 {
767 m_logger->logMessage(
768 "Updating BMC position failed for path [" +
769 std::string(constants::systemInvPath) +
770 "], bmc position: " + std::to_string(l_bmcPosition));
771
772 // ToDo: Check is PEL required
773 }
774 }
775 else if (l_errCode != 0)
776 {
777 m_logger->logMessage(
778 "Unable to determine whether system is RBMC system or not, reason: " +
779 commonUtility::getErrCodeMsg(l_errCode));
Anupama B R95083d42025-10-27 04:54:58 -0500780 }
781
Sunny Srivastava78a50422025-04-25 11:17:56 +0530782 // Enable all mux which are used for connecting to the i2c on the
783 // pcie slots for pcie cards. These are not enabled by kernel due to
784 // an issue seen with Castello cards, where the i2c line hangs on a
785 // probe.
786 enableMuxChips();
787
788 // Nothing needs to be done. Service restarted or BMC re-booted for
789 // some reason at system power on.
Sunny Srivastava78a50422025-04-25 11:17:56 +0530790 }
791 catch (const std::exception& l_ex)
792 {
Anupama B R4c65fcd2025-09-01 08:09:00 -0500793 m_worker->setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
794 constants::vpdCollectionFailed);
Sunny Srivastava78a50422025-04-25 11:17:56 +0530795 // Any issue in system's inital set up is handled in this catch. Error
796 // will not propogate to manager.
797 EventLogger::createSyncPel(
798 EventLogger::getErrorType(l_ex), types::SeverityType::Critical,
799 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
800 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
801 }
802}
803
Anupama B R7127ab42025-06-26 01:39:08 -0500804void IbmHandler::collectAllFruVpd()
805{
806 // Setting status to "InProgress", before trigeering VPD collection.
Anupama B Rda9806b2025-08-29 02:41:10 -0500807 m_progressInterface->set_property(
808 "Status", std::string(constants::vpdCollectionInProgress));
Anupama B R7127ab42025-06-26 01:39:08 -0500809 m_worker->collectFrusFromJson();
810 SetTimerToDetectVpdCollectionStatus();
811}
Anupama B R95083d42025-10-27 04:54:58 -0500812
Anupama B R657aaa82025-10-30 04:12:24 -0500813bool IbmHandler::isRbmcPrototypeSystem(uint16_t& o_errCode) const noexcept
Anupama B R95083d42025-10-27 04:54:58 -0500814{
Anupama B R657aaa82025-10-30 04:12:24 -0500815 types::BinaryVector l_imValue = dbusUtility::getImFromDbus();
816 if (l_imValue.empty())
817 {
818 o_errCode = error_code::DBUS_FAILURE;
819 return false;
820 }
821
822 if (constants::rbmcPrototypeSystemImValue == l_imValue)
823 {
824 return true;
825 }
Anupama B R95083d42025-10-27 04:54:58 -0500826
827 return false;
828}
829
Anupama B R657aaa82025-10-30 04:12:24 -0500830void IbmHandler::checkAndUpdateBmcPosition(size_t& o_bmcPosition) const noexcept
Anupama B R95083d42025-10-27 04:54:58 -0500831{
Anupama B R657aaa82025-10-30 04:12:24 -0500832 if (m_worker.get() == nullptr)
833 {
834 m_logger->logMessage("Worker object not found");
835 return;
836 }
Anupama B R95083d42025-10-27 04:54:58 -0500837
Anupama B R657aaa82025-10-30 04:12:24 -0500838 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
839 if (l_sysCfgJsonObj.empty())
840 {
841 m_logger->logMessage(
842 "System config JSON is empty, unable to find BMC position");
843 return;
844 }
845
846 uint16_t l_errCode = 0;
847 std::string l_motherboardEepromPath = jsonUtility::getFruPathFromJson(
848 l_sysCfgJsonObj, constants::systemVpdInvPath, l_errCode);
849
850 if (!l_motherboardEepromPath.empty())
851 {
852 o_bmcPosition = constants::VALUE_1;
853 std::error_code l_ec;
854 if (std::filesystem::exists(l_motherboardEepromPath, l_ec))
855 {
856 o_bmcPosition = constants::VALUE_0;
857 }
858 }
859 else if (l_errCode)
860 {
861 m_logger->logMessage("Unable to determine BMC position, reason: " +
862 commonUtility::getErrCodeMsg(l_errCode));
863 }
864 else
865 {
866 m_logger->logMessage("Unable to determine BMC position, as FRU path[" +
867 std::string(constants::systemVpdInvPath) +
868 "], not found in the system config JSON.");
869 }
Anupama B R95083d42025-10-27 04:54:58 -0500870}
Sunny Srivastava867ee752025-04-15 12:24:23 +0530871} // namespace vpd