blob: dcb0dddfe140f6bf1b5b5574256465b307a16130 [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"
Rekha Aparna719093d2025-11-13 03:13:12 -06007#include "logger.hpp"
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +05308#include "parser.hpp"
9
Sunny Srivastava78a50422025-04-25 11:17:56 +053010#include <utility/common_utility.hpp>
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053011#include <utility/dbus_utility.hpp>
12#include <utility/json_utility.hpp>
13#include <utility/vpd_specific_utility.hpp>
14
Sunny Srivastava867ee752025-04-15 12:24:23 +053015namespace vpd
16{
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053017IbmHandler::IbmHandler(
18 std::shared_ptr<Worker>& o_worker,
19 std::shared_ptr<BackupAndRestore>& o_backupAndRestoreObj,
20 const std::shared_ptr<sdbusplus::asio::dbus_interface>& i_iFace,
Anupama B Rda9806b2025-08-29 02:41:10 -050021 const std::shared_ptr<sdbusplus::asio::dbus_interface>& i_progressiFace,
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053022 const std::shared_ptr<boost::asio::io_context>& i_ioCon,
23 const std::shared_ptr<sdbusplus::asio::connection>& i_asioConnection) :
24 m_worker(o_worker), m_backupAndRestoreObj(o_backupAndRestoreObj),
Anupama B Rda9806b2025-08-29 02:41:10 -050025 m_interface(i_iFace), m_progressInterface(i_progressiFace),
Souvik Roya5e18b82025-09-25 05:59:56 +000026 m_ioContext(i_ioCon), m_asioConnection(i_asioConnection),
27 m_logger(Logger::getLoggerInstance())
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053028{
Sunny Srivastavab1698ae2025-11-25 11:19:29 +053029 readVpdCollectionMode();
Souvik Royc1171732025-10-16 09:27:38 +000030
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053031 if (dbusUtility::isChassisPowerOn())
32 {
33 // At power on, less number of FRU(s) needs collection. we can scale
34 // down the threads to reduce CPU utilization.
Souvik Royc1171732025-10-16 09:27:38 +000035 m_worker = std::make_shared<Worker>(
Sunny Srivastavab1698ae2025-11-25 11:19:29 +053036 INVENTORY_JSON_DEFAULT, constants::VALUE_1, m_vpdCollectionMode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053037 }
38 else
39 {
40 // Initialize with default configuration
Souvik Royc1171732025-10-16 09:27:38 +000041 m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT,
42 constants::MAX_THREADS,
Sunny Srivastavab1698ae2025-11-25 11:19:29 +053043 m_vpdCollectionMode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053044 }
45
46 // Set up minimal things that is needed before bus name is claimed.
Sunny Srivastava78a50422025-04-25 11:17:56 +053047 performInitialSetup();
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053048
Sunny Srivastavab1698ae2025-11-25 11:19:29 +053049 uint16_t l_errCode{0};
Sunny Srivastavac607fe52025-11-18 20:52:23 +053050 // If the object is created, implies back up and restore took place in
51 // system VPD flow.
52 if ((m_backupAndRestoreObj == nullptr) && !m_sysCfgJsonObj.empty() &&
Rekha Aparna196e3082025-09-08 20:40:35 -050053 jsonUtility::isBackupAndRestoreRequired(m_sysCfgJsonObj, l_errCode))
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053054 {
55 try
56 {
57 m_backupAndRestoreObj =
58 std::make_shared<BackupAndRestore>(m_sysCfgJsonObj);
59 }
60 catch (const std::exception& l_ex)
61 {
62 logging::logMessage("Back up and restore instantiation failed. {" +
63 std::string(l_ex.what()) + "}");
64
65 EventLogger::createSyncPel(
66 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
67 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
68 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
69 }
70 }
Rekha Aparna196e3082025-09-08 20:40:35 -050071 else if (l_errCode)
72 {
73 logging::logMessage(
74 "Failed to check if backup & restore required. Error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +053075 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna196e3082025-09-08 20:40:35 -050076 }
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053077
Anupama B Rc7565ed2025-06-19 02:08:39 -050078 // Instantiate Listener object
Anupama B R56e45372025-06-19 12:54:44 -050079 m_eventListener = std::make_shared<Listener>(m_worker, m_asioConnection);
80 m_eventListener->registerAssetTagChangeCallback();
81 m_eventListener->registerHostStateChangeCallback();
Souvik Roy5c3a1562025-07-02 01:39:44 -050082 m_eventListener->registerPresenceChangeCallback();
Anupama B Rc7565ed2025-06-19 02:08:39 -050083
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053084 // Instantiate GpioMonitor class
85 m_gpioMonitor =
86 std::make_shared<GpioMonitor>(m_sysCfgJsonObj, m_worker, m_ioContext);
87}
88
Sunny Srivastavab1698ae2025-11-25 11:19:29 +053089void IbmHandler::readVpdCollectionMode() noexcept
90{
91 uint16_t l_errCode{0};
92 // check VPD collection mode
93 m_vpdCollectionMode = commonUtility::isFieldModeEnabled()
94 ? types::VpdCollectionMode::DEFAULT_MODE
95 : commonUtility::getVpdCollectionMode(l_errCode);
96
97 if (l_errCode)
98 {
99 m_logger->logMessage(
100 "Default mode set. Error while trying to read VPD collection mode: " +
101 commonUtility::getErrCodeMsg(l_errCode));
102 }
103}
104
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530105void IbmHandler::SetTimerToDetectVpdCollectionStatus()
106{
107 // Keeping max retry for 2 minutes. TODO: Make it configurable based on
108 // system type.
109 static constexpr auto MAX_RETRY = 12;
110
111 static boost::asio::steady_timer l_timer(*m_ioContext);
112 static uint8_t l_timerRetry = 0;
113
114 auto l_asyncCancelled = l_timer.expires_after(std::chrono::seconds(10));
115
116 (l_asyncCancelled == 0)
117 ? logging::logMessage("Collection Timer started")
118 : logging::logMessage("Collection Timer re-started");
119
120 l_timer.async_wait([this](const boost::system::error_code& ec) {
121 if (ec == boost::asio::error::operation_aborted)
122 {
123 throw std::runtime_error(
124 "Timer to detect thread collection status was aborted");
125 }
126
127 if (ec)
128 {
129 throw std::runtime_error(
130 "Timer to detect thread collection failed");
131 }
132
133 if (m_worker->isAllFruCollectionDone())
134 {
135 // cancel the timer
136 l_timer.cancel();
137 processFailedEeproms();
138
139 // update VPD for powerVS system.
140 ConfigurePowerVsSystem();
141
142 std::cout << "m_worker->isSystemVPDOnDBus() completed" << std::endl;
Anupama B Rda9806b2025-08-29 02:41:10 -0500143 m_progressInterface->set_property(
144 "Status", std::string(constants::vpdCollectionCompleted));
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530145
146 if (m_backupAndRestoreObj)
147 {
148 m_backupAndRestoreObj->backupAndRestore();
149 }
Souvik Roy3d4af4a2025-06-23 04:45:27 -0500150
151 if (m_eventListener)
152 {
Souvik Roy762cdab2025-11-04 13:07:56 +0000153 // Check if system config JSON specifies
154 // correlatedPropertiesJson
155 if (m_sysCfgJsonObj.contains("correlatedPropertiesConfigPath"))
156 {
157 // register correlated properties callback with specific
158 // correlated properties JSON
159 m_eventListener->registerCorrPropCallBack(
160 m_sysCfgJsonObj["correlatedPropertiesConfigPath"]);
161 }
162 else
163 {
164 m_logger->logMessage(
165 "Correlated properties JSON path is not defined in system config JSON. Correlated properties listener is disabled.");
166 }
Souvik Roy3d4af4a2025-06-23 04:45:27 -0500167 }
Alpana Kumari138489f2025-11-10 08:59:20 -0600168#ifdef ENABLE_FILE_LOGGING
Souvik Roya5e18b82025-09-25 05:59:56 +0000169 // terminate collection logger
170 m_logger->terminateVpdCollectionLogging();
Alpana Kumari138489f2025-11-10 08:59:20 -0600171#endif
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530172 }
173 else
174 {
175 auto l_threadCount = m_worker->getActiveThreadCount();
176 if (l_timerRetry == MAX_RETRY)
177 {
178 l_timer.cancel();
179 logging::logMessage("Taking too long. Active thread = " +
180 std::to_string(l_threadCount));
Alpana Kumari138489f2025-11-10 08:59:20 -0600181#ifdef ENABLE_FILE_LOGGING
Souvik Roya5e18b82025-09-25 05:59:56 +0000182 // terminate collection logger
183 m_logger->terminateVpdCollectionLogging();
Alpana Kumari138489f2025-11-10 08:59:20 -0600184#endif
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530185 }
186 else
187 {
188 l_timerRetry++;
189 logging::logMessage("Collection is in progress for [" +
190 std::to_string(l_threadCount) + "] FRUs.");
191
192 SetTimerToDetectVpdCollectionStatus();
193 }
194 }
195 });
196}
197
198void IbmHandler::checkAndUpdatePowerVsVpd(
199 const nlohmann::json& i_powerVsJsonObj,
200 std::vector<std::string>& o_failedPathList)
201{
202 for (const auto& [l_fruPath, l_recJson] : i_powerVsJsonObj.items())
203 {
204 nlohmann::json l_sysCfgJsonObj{};
205 if (m_worker.get() != nullptr)
206 {
207 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
208 }
209
210 // The utility method will handle emty JSON case. No explicit
211 // handling required here.
Rekha Aparna017567a2025-08-13 02:07:06 -0500212 uint16_t l_errCode = 0;
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530213 auto l_inventoryPath = jsonUtility::getInventoryObjPathFromJson(
Rekha Aparna017567a2025-08-13 02:07:06 -0500214 l_sysCfgJsonObj, l_fruPath, l_errCode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530215
216 // Mark it as failed if inventory path not found in JSON.
217 if (l_inventoryPath.empty())
218 {
Rekha Aparna017567a2025-08-13 02:07:06 -0500219 if (l_errCode)
220 {
221 logging::logMessage(
222 "Failed to get inventory object path from JSON for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +0530223 l_fruPath +
224 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -0500225 }
226
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530227 o_failedPathList.push_back(l_fruPath);
228 continue;
229 }
230
231 // check if the FRU is present
232 if (!dbusUtility::isInventoryPresent(l_inventoryPath))
233 {
234 logging::logMessage(
235 "Inventory not present, skip updating part number. Path: " +
236 l_inventoryPath);
237 continue;
238 }
239
240 // check if the FRU needs CCIN check before updating PN.
241 if (l_recJson.contains("CCIN"))
242 {
243 const auto& l_ccinFromDbus =
Rekha Aparna80b674f2025-10-27 01:27:27 -0500244 vpdSpecificUtility::getCcinFromDbus(l_inventoryPath, l_errCode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530245
246 // Not an ideal situation as CCIN can't be empty.
247 if (l_ccinFromDbus.empty())
248 {
Rekha Aparna80b674f2025-10-27 01:27:27 -0500249 if (l_errCode)
250 {
251 m_logger->logMessage(
252 "Failed to get CCIN value from DBus, error : " +
253 commonUtility::getErrCodeMsg(l_errCode));
254 }
255
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530256 o_failedPathList.push_back(l_fruPath);
257 continue;
258 }
259
260 std::vector<std::string> l_ccinListFromJson = l_recJson["CCIN"];
261
262 if (find(l_ccinListFromJson.begin(), l_ccinListFromJson.end(),
263 l_ccinFromDbus) == l_ccinListFromJson.end())
264 {
265 // Don't update PN in this case.
266 continue;
267 }
268 }
269
270 for (const auto& [l_recordName, l_kwdJson] : l_recJson.items())
271 {
272 // Record name can't be CCIN, skip processing as it is there for PN
273 // update based on CCIN check.
274 if (l_recordName == constants::kwdCCIN)
275 {
276 continue;
277 }
278
279 for (const auto& [l_kwdName, l_kwdValue] : l_kwdJson.items())
280 {
281 // Is value of type array.
282 if (!l_kwdValue.is_array())
283 {
284 o_failedPathList.push_back(l_fruPath);
285 continue;
286 }
287
288 // Get current FRU Part number.
289 auto l_retVal = dbusUtility::readDbusProperty(
290 constants::pimServiceName, l_inventoryPath,
291 constants::viniInf, constants::kwdFN);
292
293 auto l_ptrToFn = std::get_if<types::BinaryVector>(&l_retVal);
294
295 if (!l_ptrToFn)
296 {
297 o_failedPathList.push_back(l_fruPath);
298 continue;
299 }
300
301 types::BinaryVector l_binaryKwdValue =
302 l_kwdValue.get<types::BinaryVector>();
303 if (l_binaryKwdValue == (*l_ptrToFn))
304 {
305 continue;
306 }
307
308 // Update part number only if required.
309 std::shared_ptr<Parser> l_parserObj =
310 std::make_shared<Parser>(l_fruPath, l_sysCfgJsonObj);
311 if (l_parserObj->updateVpdKeyword(std::make_tuple(
312 l_recordName, l_kwdName, l_binaryKwdValue)) ==
313 constants::FAILURE)
314 {
315 o_failedPathList.push_back(l_fruPath);
316 continue;
317 }
318
319 // update the Asset interface Spare part number explicitly.
320 if (!dbusUtility::callPIM(types::ObjectMap{
321 {l_inventoryPath,
322 {{constants::assetInf,
323 {{"SparePartNumber",
324 std::string(l_binaryKwdValue.begin(),
325 l_binaryKwdValue.end())}}}}}}))
326 {
327 logging::logMessage(
328 "Updating Spare Part Number under Asset interface failed for path [" +
329 l_inventoryPath + "]");
330 }
331
332 // Just needed for logging.
333 std::string l_initialPartNum((*l_ptrToFn).begin(),
334 (*l_ptrToFn).end());
335 std::string l_finalPartNum(l_binaryKwdValue.begin(),
336 l_binaryKwdValue.end());
337 logging::logMessage(
338 "FRU Part number updated for path [" + l_inventoryPath +
339 "]" + "From [" + l_initialPartNum + "]" + " to [" +
340 l_finalPartNum + "]");
341 }
342 }
343 }
344}
345
346void IbmHandler::ConfigurePowerVsSystem()
347{
348 std::vector<std::string> l_failedPathList;
349 try
350 {
351 types::BinaryVector l_imValue = dbusUtility::getImFromDbus();
352 if (l_imValue.empty())
353 {
354 throw DbusException("Invalid IM value read from Dbus");
355 }
356
Rekha Aparnaed09af82025-10-22 20:34:41 -0500357 uint16_t l_errCode = 0;
358 if (!vpdSpecificUtility::isPowerVsConfiguration(l_imValue, l_errCode))
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530359 {
360 // TODO: Should booting be blocked in case of some
361 // misconfigurations?
Rekha Aparnaed09af82025-10-22 20:34:41 -0500362 if (l_errCode)
363 {
364 logging::logMessage(
365 "Failed to check if the system is powerVs Configuration, error : " +
366 commonUtility::getErrCodeMsg(l_errCode));
367 }
368
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530369 return;
370 }
371
372 const nlohmann::json& l_powerVsJsonObj =
Rekha Aparnaadf85262025-09-09 00:41:00 -0500373 jsonUtility::getPowerVsJson(l_imValue, l_errCode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530374
375 if (l_powerVsJsonObj.empty())
376 {
Rekha Aparnac6159a22025-10-09 12:20:20 +0530377 throw std::runtime_error("PowerVS Json not found. Error : " +
378 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530379 }
380
381 checkAndUpdatePowerVsVpd(l_powerVsJsonObj, l_failedPathList);
382
383 if (!l_failedPathList.empty())
384 {
385 throw std::runtime_error(
386 "Part number update failed for following paths: ");
387 }
388 }
389 catch (const std::exception& l_ex)
390 {
391 // TODO log appropriate PEL
392 }
393}
394
395void IbmHandler::processFailedEeproms()
396{
397 if (m_worker.get() != nullptr)
398 {
399 // TODO:
400 // - iterate through list of EEPROMs for which thread creation has
401 // failed
402 // - For each failed EEPROM, trigger VPD collection
403 m_worker->getFailedEepromPaths().clear();
404 }
405}
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530406
Sunny Srivastava78a50422025-04-25 11:17:56 +0530407void IbmHandler::enableMuxChips()
408{
409 if (m_sysCfgJsonObj.empty())
410 {
411 // config JSON should not be empty at this point of execution.
412 throw std::runtime_error("Config JSON is empty. Can't enable muxes");
413 return;
414 }
415
416 if (!m_sysCfgJsonObj.contains("muxes"))
417 {
418 logging::logMessage("No mux defined for the system in config JSON");
419 return;
420 }
421
422 // iterate over each MUX detail and enable them.
423 for (const auto& item : m_sysCfgJsonObj["muxes"])
424 {
Rekha Aparna719093d2025-11-13 03:13:12 -0600425 uint16_t l_errCode = 0;
Sunny Srivastava78a50422025-04-25 11:17:56 +0530426 if (item.contains("holdidlepath"))
427 {
428 std::string cmd = "echo 0 > ";
429 cmd += item["holdidlepath"];
430
431 logging::logMessage("Enabling mux with command = " + cmd);
432
Rekha Aparna719093d2025-11-13 03:13:12 -0600433 commonUtility::executeCmd(cmd, l_errCode);
434
435 if (l_errCode)
436 {
437 m_logger->logMessage(
438 "Failed to execute command [" + cmd +
439 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
440 }
441
Sunny Srivastava78a50422025-04-25 11:17:56 +0530442 continue;
443 }
444
445 logging::logMessage(
446 "Mux Entry does not have hold idle path. Can't enable the mux");
447 }
448}
449
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530450void IbmHandler::getSystemJson(std::string& o_systemJson,
451 const types::VPDMapVariant& i_parsedVpdMap)
452{
453 if (auto l_pVal = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
454 {
455 uint16_t l_errCode = 0;
456 std::string l_hwKWdValue =
457 vpdSpecificUtility::getHWVersion(*l_pVal, l_errCode);
458 if (l_hwKWdValue.empty())
459 {
460 if (l_errCode)
461 {
462 throw DataException("Failed to fetch HW value. Reason: " +
463 commonUtility::getErrCodeMsg(l_errCode));
464 }
465 throw DataException("HW value fetched is empty.");
466 }
467
468 const std::string& l_imKwdValue =
469 vpdSpecificUtility::getIMValue(*l_pVal, l_errCode);
470 if (l_imKwdValue.empty())
471 {
472 if (l_errCode)
473 {
474 throw DataException("Failed to fetch IM value. Reason: " +
475 commonUtility::getErrCodeMsg(l_errCode));
476 }
477 throw DataException("IM value fetched is empty.");
478 }
479
480 auto l_itrToIM = config::systemType.find(l_imKwdValue);
481 if (l_itrToIM == config::systemType.end())
482 {
483 throw DataException("IM keyword does not map to any system type");
484 }
485
486 const types::HWVerList l_hwVersionList = l_itrToIM->second.second;
487 if (!l_hwVersionList.empty())
488 {
489 transform(l_hwKWdValue.begin(), l_hwKWdValue.end(),
490 l_hwKWdValue.begin(), ::toupper);
491
492 auto l_itrToHW =
493 std::find_if(l_hwVersionList.begin(), l_hwVersionList.end(),
494 [&l_hwKWdValue](const auto& l_aPair) {
495 return l_aPair.first == l_hwKWdValue;
496 });
497
498 if (l_itrToHW != l_hwVersionList.end())
499 {
500 if (!(*l_itrToHW).second.empty())
501 {
502 o_systemJson += (*l_itrToIM).first + "_" +
503 (*l_itrToHW).second + ".json";
504 }
505 else
506 {
507 o_systemJson += (*l_itrToIM).first + ".json";
508 }
509 return;
510 }
511 }
512 o_systemJson += l_itrToIM->second.first + ".json";
513 return;
514 }
515
516 throw DataException(
517 "Invalid VPD type returned from Parser. Can't get system JSON.");
518}
519
520static void setEnvAndReboot(const std::string& i_key,
521 const std::string& i_value)
522{
523 // set env and reboot and break.
Rekha Aparna719093d2025-11-13 03:13:12 -0600524 uint16_t l_errCode = 0;
525 commonUtility::executeCmd("/sbin/fw_setenv", l_errCode, i_key, i_value);
526
527 if (l_errCode)
528 {
529 throw std::runtime_error(
530 "Failed to execute command [/sbin/fw_setenv " + i_key + " " +
531 i_value + "], error : " + commonUtility::getErrCodeMsg(l_errCode));
532 }
533
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530534 logging::logMessage("Rebooting BMC to pick up new device tree");
535
536 // make dbus call to reboot
537 auto l_bus = sdbusplus::bus::new_default_system();
538 auto l_method = l_bus.new_method_call(
539 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
540 "org.freedesktop.systemd1.Manager", "Reboot");
541 l_bus.call_noreply(l_method);
542}
543
544static std::string readFitConfigValue()
545{
Rekha Aparna719093d2025-11-13 03:13:12 -0600546 uint16_t l_errCode = 0;
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530547 std::vector<std::string> l_output =
Rekha Aparna719093d2025-11-13 03:13:12 -0600548 commonUtility::executeCmd("/sbin/fw_printenv", l_errCode);
549
550 if (l_errCode)
551 {
552 Logger::getLoggerInstance()->logMessage(
553 "Failed to execute command [/sbin/fw_printenv], error : " +
554 commonUtility::getErrCodeMsg(l_errCode));
555 }
556
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530557 std::string l_fitConfigValue;
558
559 for (const auto& l_entry : l_output)
560 {
561 auto l_pos = l_entry.find("=");
562 auto l_key = l_entry.substr(0, l_pos);
563 if (l_key != "fitconfig")
564 {
565 continue;
566 }
567
568 if (l_pos + 1 < l_entry.size())
569 {
570 l_fitConfigValue = l_entry.substr(l_pos + 1);
571 }
572 }
573
574 return l_fitConfigValue;
575}
576
577bool IbmHandler::isBackupOnCache()
578{
579 try
580 {
581 uint16_t l_errCode = 0;
582 std::string l_backupAndRestoreCfgFilePath =
583 m_sysCfgJsonObj.value("backupRestoreConfigPath", "");
584
585 if (l_backupAndRestoreCfgFilePath.empty())
586 {
587 m_logger->logMessage(
588 "backupRestoreConfigPath is not found in JSON. Can't determne the backup path.");
589 return false;
590 }
591
592 nlohmann::json l_backupAndRestoreCfgJsonObj =
593 jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath,
594 l_errCode);
595 if (l_backupAndRestoreCfgJsonObj.empty() || l_errCode)
596 {
597 m_logger->logMessage(
598 "JSON parsing failed for file [ " +
599 std::string(l_backupAndRestoreCfgFilePath) +
600 " ], error : " + commonUtility::getErrCodeMsg(l_errCode));
601 return false;
602 }
603
604 // check if either of "source" or "destination" has inventory path.
605 // this indicates that this sytem has System VPD on hardware
606 // and other copy on D-Bus (BMC cache).
607 if (!l_backupAndRestoreCfgJsonObj.empty() &&
608 ((l_backupAndRestoreCfgJsonObj.contains("source") &&
609 l_backupAndRestoreCfgJsonObj["source"].contains(
610 "inventoryPath")) ||
611 (l_backupAndRestoreCfgJsonObj.contains("destination") &&
612 l_backupAndRestoreCfgJsonObj["destination"].contains(
613 "inventoryPath"))))
614 {
615 return true;
616 }
617 }
618 catch (const std::exception& l_ex)
619 {
620 m_logger->logMessage(
621 "Exception while checking for backup on cache. Reason:" +
622 std::string(l_ex.what()));
623 }
624
625 // In case of any failure/ambiguity. Don't perform back up and restore.
626 return false;
627}
628
629void IbmHandler::performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap)
630{
631 try
632 {
633 m_backupAndRestoreObj =
634 std::make_shared<BackupAndRestore>(m_sysCfgJsonObj);
635 auto [l_srcVpdVariant,
636 l_dstVpdVariant] = m_backupAndRestoreObj->backupAndRestore();
637
638 // ToDo: Revisit is this check is required or not.
639 if (auto l_srcVpdMap = std::get_if<types::IPZVpdMap>(&l_srcVpdVariant);
640 l_srcVpdMap && !(*l_srcVpdMap).empty())
641 {
642 io_srcVpdMap = std::move(l_srcVpdVariant);
643 }
644 }
645 catch (const std::exception& l_ex)
646 {
647 EventLogger::createSyncPel(
648 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
649 __FILE__, __FUNCTION__, 0,
650 std::string(
651 "Exception caught while backup and restore VPD keyword's.") +
652 EventLogger::getErrorMsg(l_ex),
653 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
654 }
655}
656
Sunny Srivastava57a4ee52025-11-19 12:13:50 +0530657std::string IbmHandler::createAssetTagString(
658 const types::VPDMapVariant& i_parsedVpdMap)
659{
660 std::string l_assetTag;
661 // system VPD will be in IPZ format.
662 if (auto l_parsedVpdMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
663 {
664 auto l_itrToVsys = (*l_parsedVpdMap).find(constants::recVSYS);
665 if (l_itrToVsys != (*l_parsedVpdMap).end())
666 {
667 uint16_t l_errCode = 0;
668 const std::string l_tmKwdValue{vpdSpecificUtility::getKwVal(
669 l_itrToVsys->second, constants::kwdTM, l_errCode)};
670 if (l_tmKwdValue.empty())
671 {
672 throw std::runtime_error(
673 std::string("Failed to get value for keyword [") +
674 constants::kwdTM +
675 std::string("] while creating Asset tag. Error : " +
676 commonUtility::getErrCodeMsg(l_errCode)));
677 }
678 const std::string l_seKwdValue{vpdSpecificUtility::getKwVal(
679 l_itrToVsys->second, constants::kwdSE, l_errCode)};
680 if (l_seKwdValue.empty())
681 {
682 throw std::runtime_error(
683 std::string("Failed to get value for keyword [") +
684 constants::kwdSE +
685 std::string("] while creating Asset tag. Error : " +
686 commonUtility::getErrCodeMsg(l_errCode)));
687 }
688 l_assetTag = std::string{"Server-"} + l_tmKwdValue +
689 std::string{"-"} + l_seKwdValue;
690 }
691 else
692 {
693 throw std::runtime_error(
694 "VSYS record not found in parsed VPD map to create Asset tag.");
695 }
696 }
697 else
698 {
699 throw std::runtime_error(
700 "Invalid VPD type recieved to create Asset tag.");
701 }
702 return l_assetTag;
703}
704
705void IbmHandler::publishSystemVPD(const types::VPDMapVariant& i_parsedVpdMap)
706{
707 types::ObjectMap l_objectInterfaceMap;
708 if (std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
709 {
710 m_worker->populateDbus(i_parsedVpdMap, l_objectInterfaceMap,
711 SYSTEM_VPD_FILE_PATH);
712 try
713 {
714 // Factory reset condition will be added in subsequent commit.
715 // if (m_isFactoryResetDone)
716 //{
717 const auto& l_assetTag = createAssetTagString(i_parsedVpdMap);
718 auto l_itrToSystemPath = l_objectInterfaceMap.find(
719 sdbusplus::message::object_path(constants::systemInvPath));
720 if (l_itrToSystemPath == l_objectInterfaceMap.end())
721 {
722 throw std::runtime_error(
723 "Asset tag update failed. System Path not found in object map.");
724 }
725 types::PropertyMap l_assetTagProperty;
726 l_assetTagProperty.emplace("AssetTag", l_assetTag);
727 (l_itrToSystemPath->second)
728 .emplace(constants::assetTagInf, std::move(l_assetTagProperty));
729 //}
730 }
731 catch (const std::exception& l_ex)
732 {
733 EventLogger::createSyncPel(
734 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
735 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
736 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
737 }
738 // Notify PIM
739 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
740 {
741 throw std::runtime_error("Call to PIM failed for system VPD");
742 }
743 }
744 else
745 {
746 throw DataException("Invalid format of parsed VPD map.");
747 }
748}
749
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530750void IbmHandler::setDeviceTreeAndJson()
751{
752 // JSON is madatory for processing of this API.
753 if (m_sysCfgJsonObj.empty())
754 {
755 throw JsonException("System config JSON is empty", m_sysCfgJsonObj);
756 }
757
758 // parse system VPD
759 auto l_parsedVpdMap = m_worker->parseVpdFile(SYSTEM_VPD_FILE_PATH);
760
761 // Implies it is default JSON.
762 std::string l_systemJson{JSON_ABSOLUTE_PATH_PREFIX};
763
764 // get system JSON as per the system configuration.
765 getSystemJson(l_systemJson, l_parsedVpdMap);
766
767 if (!l_systemJson.compare(JSON_ABSOLUTE_PATH_PREFIX))
768 {
769 throw DataException(
770 "No system JSON found corresponding to IM read from VPD.");
771 }
772
773 uint16_t l_errCode = 0;
774 // re-parse the JSON once appropriate JSON has been selected.
775 m_sysCfgJsonObj = jsonUtility::getParsedJson(l_systemJson, l_errCode);
776
777 if (l_errCode)
778 {
779 throw(JsonException(
780 "JSON parsing failed for file [ " + l_systemJson +
781 " ], error : " + commonUtility::getErrCodeMsg(l_errCode),
782 l_systemJson));
783 }
784
785 m_worker->setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
786 constants::vpdCollectionInProgress);
787
788 std::string l_devTreeFromJson;
789 if (m_sysCfgJsonObj.contains("devTree"))
790 {
791 l_devTreeFromJson = m_sysCfgJsonObj["devTree"];
792
793 if (l_devTreeFromJson.empty())
794 {
795 EventLogger::createSyncPel(
796 types::ErrorType::JsonFailure, types::SeverityType::Error,
797 __FILE__, __FUNCTION__, 0,
798 "Mandatory value for device tree missing from JSON[" +
799 l_systemJson + "]",
800 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
801 }
802 }
803
804 auto l_fitConfigVal = readFitConfigValue();
805
806 if (l_devTreeFromJson.empty() ||
807 l_fitConfigVal.find(l_devTreeFromJson) != std::string::npos)
808 { // Skipping setting device tree as either devtree info is missing from
809 // Json or it is rightly set.
810
811 m_worker->setJsonSymbolicLink(l_systemJson);
812
813 const std::string& l_systemVpdInvPath =
814 jsonUtility::getInventoryObjPathFromJson(
815 m_sysCfgJsonObj, SYSTEM_VPD_FILE_PATH, l_errCode);
816
817 if (l_systemVpdInvPath.empty())
818 {
819 if (l_errCode)
820 {
821 throw JsonException(
822 "System vpd inventory path not found in JSON. Reason:" +
823 commonUtility::getErrCodeMsg(l_errCode),
824 INVENTORY_JSON_SYM_LINK);
825 }
826 throw JsonException("System vpd inventory path is missing in JSON",
827 INVENTORY_JSON_SYM_LINK);
828 }
829
830 // TODO: for backward compatibility this should also support motherboard
831 // interface.
832 std::vector<std::string> l_interfaceList{
833 constants::motherboardInterface};
834 const types::MapperGetObject& l_sysVpdObjMap =
835 dbusUtility::getObjectMap(l_systemVpdInvPath, l_interfaceList);
836
837 if (!l_sysVpdObjMap.empty())
838 {
839 if (isBackupOnCache() && jsonUtility::isBackupAndRestoreRequired(
840 m_sysCfgJsonObj, l_errCode))
841 {
842 performBackupAndRestore(l_parsedVpdMap);
843 }
844 else if (l_errCode)
845 {
846 logging::logMessage(
847 "Failed to check if backup and restore required. Reason : " +
848 commonUtility::getErrCodeMsg(l_errCode));
849 }
850 }
851
852 // proceed to publish system VPD.
Sunny Srivastava57a4ee52025-11-19 12:13:50 +0530853 publishSystemVPD(l_parsedVpdMap);
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530854 m_worker->setCollectionStatusProperty(
855 SYSTEM_VPD_FILE_PATH, constants::vpdCollectionCompleted);
856 return;
857 }
858
859 setEnvAndReboot("fitconfig", l_devTreeFromJson);
860 exit(EXIT_SUCCESS);
861}
862
Sunny Srivastava78a50422025-04-25 11:17:56 +0530863void IbmHandler::performInitialSetup()
864{
865 try
866 {
Anupama B R281e2d42025-05-05 10:05:13 -0500867 if (m_worker.get() == nullptr)
868 {
869 throw std::runtime_error(
870 "Worker object not found. Can't perform initial setup.");
871 }
872
873 m_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
Sunny Srivastava78a50422025-04-25 11:17:56 +0530874 if (!dbusUtility::isChassisPowerOn())
875 {
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530876 setDeviceTreeAndJson();
Sunny Srivastava78a50422025-04-25 11:17:56 +0530877 }
878
Anupama B R95083d42025-10-27 04:54:58 -0500879 // Update BMC postion for RBMC prototype system
880 // Ignore BMC position update in case of any error
881 uint16_t l_errCode = 0;
Anupama B R657aaa82025-10-30 04:12:24 -0500882 if (isRbmcPrototypeSystem(l_errCode))
Anupama B R95083d42025-10-27 04:54:58 -0500883 {
Anupama B R657aaa82025-10-30 04:12:24 -0500884 size_t l_bmcPosition = std::numeric_limits<size_t>::max();
885 checkAndUpdateBmcPosition(l_bmcPosition);
Anupama B R95083d42025-10-27 04:54:58 -0500886
Anupama B R657aaa82025-10-30 04:12:24 -0500887 if (dbusUtility::callPIM(types::ObjectMap{
888 {sdbusplus::message::object_path(constants::systemInvPath),
889 {{constants::rbmcPositionInterface,
890 {{"Position", l_bmcPosition}}}}}}))
891 {
892 m_logger->logMessage(
893 "Updating BMC position failed for path [" +
894 std::string(constants::systemInvPath) +
895 "], bmc position: " + std::to_string(l_bmcPosition));
896
897 // ToDo: Check is PEL required
898 }
899 }
900 else if (l_errCode != 0)
901 {
902 m_logger->logMessage(
903 "Unable to determine whether system is RBMC system or not, reason: " +
904 commonUtility::getErrCodeMsg(l_errCode));
Anupama B R95083d42025-10-27 04:54:58 -0500905 }
906
Sunny Srivastava78a50422025-04-25 11:17:56 +0530907 // Enable all mux which are used for connecting to the i2c on the
908 // pcie slots for pcie cards. These are not enabled by kernel due to
909 // an issue seen with Castello cards, where the i2c line hangs on a
910 // probe.
911 enableMuxChips();
912
913 // Nothing needs to be done. Service restarted or BMC re-booted for
914 // some reason at system power on.
Sunny Srivastava78a50422025-04-25 11:17:56 +0530915 }
916 catch (const std::exception& l_ex)
917 {
Anupama B R4c65fcd2025-09-01 08:09:00 -0500918 m_worker->setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
919 constants::vpdCollectionFailed);
Sunny Srivastava78a50422025-04-25 11:17:56 +0530920 // Any issue in system's inital set up is handled in this catch. Error
921 // will not propogate to manager.
922 EventLogger::createSyncPel(
923 EventLogger::getErrorType(l_ex), types::SeverityType::Critical,
924 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
925 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
926 }
927}
928
Anupama B R7127ab42025-06-26 01:39:08 -0500929void IbmHandler::collectAllFruVpd()
930{
931 // Setting status to "InProgress", before trigeering VPD collection.
Anupama B Rda9806b2025-08-29 02:41:10 -0500932 m_progressInterface->set_property(
933 "Status", std::string(constants::vpdCollectionInProgress));
Anupama B R7127ab42025-06-26 01:39:08 -0500934 m_worker->collectFrusFromJson();
935 SetTimerToDetectVpdCollectionStatus();
936}
Anupama B R95083d42025-10-27 04:54:58 -0500937
Anupama B R657aaa82025-10-30 04:12:24 -0500938bool IbmHandler::isRbmcPrototypeSystem(uint16_t& o_errCode) const noexcept
Anupama B R95083d42025-10-27 04:54:58 -0500939{
Anupama B R657aaa82025-10-30 04:12:24 -0500940 types::BinaryVector l_imValue = dbusUtility::getImFromDbus();
941 if (l_imValue.empty())
942 {
943 o_errCode = error_code::DBUS_FAILURE;
944 return false;
945 }
946
947 if (constants::rbmcPrototypeSystemImValue == l_imValue)
948 {
949 return true;
950 }
Anupama B R95083d42025-10-27 04:54:58 -0500951
952 return false;
953}
954
Anupama B R657aaa82025-10-30 04:12:24 -0500955void IbmHandler::checkAndUpdateBmcPosition(size_t& o_bmcPosition) const noexcept
Anupama B R95083d42025-10-27 04:54:58 -0500956{
Anupama B R657aaa82025-10-30 04:12:24 -0500957 if (m_worker.get() == nullptr)
958 {
959 m_logger->logMessage("Worker object not found");
960 return;
961 }
Anupama B R95083d42025-10-27 04:54:58 -0500962
Anupama B R657aaa82025-10-30 04:12:24 -0500963 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
964 if (l_sysCfgJsonObj.empty())
965 {
966 m_logger->logMessage(
967 "System config JSON is empty, unable to find BMC position");
968 return;
969 }
970
971 uint16_t l_errCode = 0;
972 std::string l_motherboardEepromPath = jsonUtility::getFruPathFromJson(
973 l_sysCfgJsonObj, constants::systemVpdInvPath, l_errCode);
974
975 if (!l_motherboardEepromPath.empty())
976 {
977 o_bmcPosition = constants::VALUE_1;
978 std::error_code l_ec;
979 if (std::filesystem::exists(l_motherboardEepromPath, l_ec))
980 {
981 o_bmcPosition = constants::VALUE_0;
982 }
983 }
984 else if (l_errCode)
985 {
986 m_logger->logMessage("Unable to determine BMC position, reason: " +
987 commonUtility::getErrCodeMsg(l_errCode));
988 }
989 else
990 {
991 m_logger->logMessage("Unable to determine BMC position, as FRU path[" +
992 std::string(constants::systemVpdInvPath) +
993 "], not found in the system config JSON.");
994 }
Anupama B R95083d42025-10-27 04:54:58 -0500995}
Sunny Srivastava867ee752025-04-15 12:24:23 +0530996} // namespace vpd