blob: 607ba3441d2591bda4d673d719bb3b5ac0c3e64e [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{
Souvik Royc1171732025-10-16 09:27:38 +000029 uint16_t l_errCode{0};
30
31 // check VPD collection mode
32 const auto l_vpdCollectionMode =
33 commonUtility::isFieldModeEnabled()
34 ? types::VpdCollectionMode::DEFAULT_MODE
35 : commonUtility::getVpdCollectionMode(l_errCode);
36
37 if (l_errCode)
38 {
39 m_logger->logMessage(
40 "Error while trying to read VPD collection mode: " +
41 commonUtility::getErrCodeMsg(l_errCode));
Souvik Royc1171732025-10-16 09:27:38 +000042 }
43
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053044 if (dbusUtility::isChassisPowerOn())
45 {
46 // At power on, less number of FRU(s) needs collection. we can scale
47 // down the threads to reduce CPU utilization.
Souvik Royc1171732025-10-16 09:27:38 +000048 m_worker = std::make_shared<Worker>(
49 INVENTORY_JSON_DEFAULT, constants::VALUE_1, l_vpdCollectionMode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053050 }
51 else
52 {
53 // Initialize with default configuration
Souvik Royc1171732025-10-16 09:27:38 +000054 m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT,
55 constants::MAX_THREADS,
56 l_vpdCollectionMode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053057 }
58
59 // Set up minimal things that is needed before bus name is claimed.
Sunny Srivastava78a50422025-04-25 11:17:56 +053060 performInitialSetup();
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053061
Sunny Srivastavac607fe52025-11-18 20:52:23 +053062 // If the object is created, implies back up and restore took place in
63 // system VPD flow.
64 if ((m_backupAndRestoreObj == nullptr) && !m_sysCfgJsonObj.empty() &&
Rekha Aparna196e3082025-09-08 20:40:35 -050065 jsonUtility::isBackupAndRestoreRequired(m_sysCfgJsonObj, l_errCode))
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053066 {
67 try
68 {
69 m_backupAndRestoreObj =
70 std::make_shared<BackupAndRestore>(m_sysCfgJsonObj);
71 }
72 catch (const std::exception& l_ex)
73 {
74 logging::logMessage("Back up and restore instantiation failed. {" +
75 std::string(l_ex.what()) + "}");
76
77 EventLogger::createSyncPel(
78 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
79 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
80 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
81 }
82 }
Rekha Aparna196e3082025-09-08 20:40:35 -050083 else if (l_errCode)
84 {
85 logging::logMessage(
86 "Failed to check if backup & restore required. Error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +053087 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna196e3082025-09-08 20:40:35 -050088 }
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053089
Anupama B Rc7565ed2025-06-19 02:08:39 -050090 // Instantiate Listener object
Anupama B R56e45372025-06-19 12:54:44 -050091 m_eventListener = std::make_shared<Listener>(m_worker, m_asioConnection);
92 m_eventListener->registerAssetTagChangeCallback();
93 m_eventListener->registerHostStateChangeCallback();
Souvik Roy5c3a1562025-07-02 01:39:44 -050094 m_eventListener->registerPresenceChangeCallback();
Anupama B Rc7565ed2025-06-19 02:08:39 -050095
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +053096 // Instantiate GpioMonitor class
97 m_gpioMonitor =
98 std::make_shared<GpioMonitor>(m_sysCfgJsonObj, m_worker, m_ioContext);
99}
100
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530101void IbmHandler::SetTimerToDetectVpdCollectionStatus()
102{
103 // Keeping max retry for 2 minutes. TODO: Make it configurable based on
104 // system type.
105 static constexpr auto MAX_RETRY = 12;
106
107 static boost::asio::steady_timer l_timer(*m_ioContext);
108 static uint8_t l_timerRetry = 0;
109
110 auto l_asyncCancelled = l_timer.expires_after(std::chrono::seconds(10));
111
112 (l_asyncCancelled == 0)
113 ? logging::logMessage("Collection Timer started")
114 : logging::logMessage("Collection Timer re-started");
115
116 l_timer.async_wait([this](const boost::system::error_code& ec) {
117 if (ec == boost::asio::error::operation_aborted)
118 {
119 throw std::runtime_error(
120 "Timer to detect thread collection status was aborted");
121 }
122
123 if (ec)
124 {
125 throw std::runtime_error(
126 "Timer to detect thread collection failed");
127 }
128
129 if (m_worker->isAllFruCollectionDone())
130 {
131 // cancel the timer
132 l_timer.cancel();
133 processFailedEeproms();
134
135 // update VPD for powerVS system.
136 ConfigurePowerVsSystem();
137
138 std::cout << "m_worker->isSystemVPDOnDBus() completed" << std::endl;
Anupama B Rda9806b2025-08-29 02:41:10 -0500139 m_progressInterface->set_property(
140 "Status", std::string(constants::vpdCollectionCompleted));
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530141
142 if (m_backupAndRestoreObj)
143 {
144 m_backupAndRestoreObj->backupAndRestore();
145 }
Souvik Roy3d4af4a2025-06-23 04:45:27 -0500146
147 if (m_eventListener)
148 {
Souvik Roy762cdab2025-11-04 13:07:56 +0000149 // Check if system config JSON specifies
150 // correlatedPropertiesJson
151 if (m_sysCfgJsonObj.contains("correlatedPropertiesConfigPath"))
152 {
153 // register correlated properties callback with specific
154 // correlated properties JSON
155 m_eventListener->registerCorrPropCallBack(
156 m_sysCfgJsonObj["correlatedPropertiesConfigPath"]);
157 }
158 else
159 {
160 m_logger->logMessage(
161 "Correlated properties JSON path is not defined in system config JSON. Correlated properties listener is disabled.");
162 }
Souvik Roy3d4af4a2025-06-23 04:45:27 -0500163 }
Alpana Kumari138489f2025-11-10 08:59:20 -0600164#ifdef ENABLE_FILE_LOGGING
Souvik Roya5e18b82025-09-25 05:59:56 +0000165 // terminate collection logger
166 m_logger->terminateVpdCollectionLogging();
Alpana Kumari138489f2025-11-10 08:59:20 -0600167#endif
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530168 }
169 else
170 {
171 auto l_threadCount = m_worker->getActiveThreadCount();
172 if (l_timerRetry == MAX_RETRY)
173 {
174 l_timer.cancel();
175 logging::logMessage("Taking too long. Active thread = " +
176 std::to_string(l_threadCount));
Alpana Kumari138489f2025-11-10 08:59:20 -0600177#ifdef ENABLE_FILE_LOGGING
Souvik Roya5e18b82025-09-25 05:59:56 +0000178 // terminate collection logger
179 m_logger->terminateVpdCollectionLogging();
Alpana Kumari138489f2025-11-10 08:59:20 -0600180#endif
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530181 }
182 else
183 {
184 l_timerRetry++;
185 logging::logMessage("Collection is in progress for [" +
186 std::to_string(l_threadCount) + "] FRUs.");
187
188 SetTimerToDetectVpdCollectionStatus();
189 }
190 }
191 });
192}
193
194void IbmHandler::checkAndUpdatePowerVsVpd(
195 const nlohmann::json& i_powerVsJsonObj,
196 std::vector<std::string>& o_failedPathList)
197{
198 for (const auto& [l_fruPath, l_recJson] : i_powerVsJsonObj.items())
199 {
200 nlohmann::json l_sysCfgJsonObj{};
201 if (m_worker.get() != nullptr)
202 {
203 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
204 }
205
206 // The utility method will handle emty JSON case. No explicit
207 // handling required here.
Rekha Aparna017567a2025-08-13 02:07:06 -0500208 uint16_t l_errCode = 0;
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530209 auto l_inventoryPath = jsonUtility::getInventoryObjPathFromJson(
Rekha Aparna017567a2025-08-13 02:07:06 -0500210 l_sysCfgJsonObj, l_fruPath, l_errCode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530211
212 // Mark it as failed if inventory path not found in JSON.
213 if (l_inventoryPath.empty())
214 {
Rekha Aparna017567a2025-08-13 02:07:06 -0500215 if (l_errCode)
216 {
217 logging::logMessage(
218 "Failed to get inventory object path from JSON for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +0530219 l_fruPath +
220 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -0500221 }
222
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530223 o_failedPathList.push_back(l_fruPath);
224 continue;
225 }
226
227 // check if the FRU is present
228 if (!dbusUtility::isInventoryPresent(l_inventoryPath))
229 {
230 logging::logMessage(
231 "Inventory not present, skip updating part number. Path: " +
232 l_inventoryPath);
233 continue;
234 }
235
236 // check if the FRU needs CCIN check before updating PN.
237 if (l_recJson.contains("CCIN"))
238 {
239 const auto& l_ccinFromDbus =
Rekha Aparna80b674f2025-10-27 01:27:27 -0500240 vpdSpecificUtility::getCcinFromDbus(l_inventoryPath, l_errCode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530241
242 // Not an ideal situation as CCIN can't be empty.
243 if (l_ccinFromDbus.empty())
244 {
Rekha Aparna80b674f2025-10-27 01:27:27 -0500245 if (l_errCode)
246 {
247 m_logger->logMessage(
248 "Failed to get CCIN value from DBus, error : " +
249 commonUtility::getErrCodeMsg(l_errCode));
250 }
251
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530252 o_failedPathList.push_back(l_fruPath);
253 continue;
254 }
255
256 std::vector<std::string> l_ccinListFromJson = l_recJson["CCIN"];
257
258 if (find(l_ccinListFromJson.begin(), l_ccinListFromJson.end(),
259 l_ccinFromDbus) == l_ccinListFromJson.end())
260 {
261 // Don't update PN in this case.
262 continue;
263 }
264 }
265
266 for (const auto& [l_recordName, l_kwdJson] : l_recJson.items())
267 {
268 // Record name can't be CCIN, skip processing as it is there for PN
269 // update based on CCIN check.
270 if (l_recordName == constants::kwdCCIN)
271 {
272 continue;
273 }
274
275 for (const auto& [l_kwdName, l_kwdValue] : l_kwdJson.items())
276 {
277 // Is value of type array.
278 if (!l_kwdValue.is_array())
279 {
280 o_failedPathList.push_back(l_fruPath);
281 continue;
282 }
283
284 // Get current FRU Part number.
285 auto l_retVal = dbusUtility::readDbusProperty(
286 constants::pimServiceName, l_inventoryPath,
287 constants::viniInf, constants::kwdFN);
288
289 auto l_ptrToFn = std::get_if<types::BinaryVector>(&l_retVal);
290
291 if (!l_ptrToFn)
292 {
293 o_failedPathList.push_back(l_fruPath);
294 continue;
295 }
296
297 types::BinaryVector l_binaryKwdValue =
298 l_kwdValue.get<types::BinaryVector>();
299 if (l_binaryKwdValue == (*l_ptrToFn))
300 {
301 continue;
302 }
303
304 // Update part number only if required.
305 std::shared_ptr<Parser> l_parserObj =
306 std::make_shared<Parser>(l_fruPath, l_sysCfgJsonObj);
307 if (l_parserObj->updateVpdKeyword(std::make_tuple(
308 l_recordName, l_kwdName, l_binaryKwdValue)) ==
309 constants::FAILURE)
310 {
311 o_failedPathList.push_back(l_fruPath);
312 continue;
313 }
314
315 // update the Asset interface Spare part number explicitly.
316 if (!dbusUtility::callPIM(types::ObjectMap{
317 {l_inventoryPath,
318 {{constants::assetInf,
319 {{"SparePartNumber",
320 std::string(l_binaryKwdValue.begin(),
321 l_binaryKwdValue.end())}}}}}}))
322 {
323 logging::logMessage(
324 "Updating Spare Part Number under Asset interface failed for path [" +
325 l_inventoryPath + "]");
326 }
327
328 // Just needed for logging.
329 std::string l_initialPartNum((*l_ptrToFn).begin(),
330 (*l_ptrToFn).end());
331 std::string l_finalPartNum(l_binaryKwdValue.begin(),
332 l_binaryKwdValue.end());
333 logging::logMessage(
334 "FRU Part number updated for path [" + l_inventoryPath +
335 "]" + "From [" + l_initialPartNum + "]" + " to [" +
336 l_finalPartNum + "]");
337 }
338 }
339 }
340}
341
342void IbmHandler::ConfigurePowerVsSystem()
343{
344 std::vector<std::string> l_failedPathList;
345 try
346 {
347 types::BinaryVector l_imValue = dbusUtility::getImFromDbus();
348 if (l_imValue.empty())
349 {
350 throw DbusException("Invalid IM value read from Dbus");
351 }
352
Rekha Aparnaed09af82025-10-22 20:34:41 -0500353 uint16_t l_errCode = 0;
354 if (!vpdSpecificUtility::isPowerVsConfiguration(l_imValue, l_errCode))
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530355 {
356 // TODO: Should booting be blocked in case of some
357 // misconfigurations?
Rekha Aparnaed09af82025-10-22 20:34:41 -0500358 if (l_errCode)
359 {
360 logging::logMessage(
361 "Failed to check if the system is powerVs Configuration, error : " +
362 commonUtility::getErrCodeMsg(l_errCode));
363 }
364
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530365 return;
366 }
367
368 const nlohmann::json& l_powerVsJsonObj =
Rekha Aparnaadf85262025-09-09 00:41:00 -0500369 jsonUtility::getPowerVsJson(l_imValue, l_errCode);
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530370
371 if (l_powerVsJsonObj.empty())
372 {
Rekha Aparnac6159a22025-10-09 12:20:20 +0530373 throw std::runtime_error("PowerVS Json not found. Error : " +
374 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavac74c8ef2025-04-16 12:45:27 +0530375 }
376
377 checkAndUpdatePowerVsVpd(l_powerVsJsonObj, l_failedPathList);
378
379 if (!l_failedPathList.empty())
380 {
381 throw std::runtime_error(
382 "Part number update failed for following paths: ");
383 }
384 }
385 catch (const std::exception& l_ex)
386 {
387 // TODO log appropriate PEL
388 }
389}
390
391void IbmHandler::processFailedEeproms()
392{
393 if (m_worker.get() != nullptr)
394 {
395 // TODO:
396 // - iterate through list of EEPROMs for which thread creation has
397 // failed
398 // - For each failed EEPROM, trigger VPD collection
399 m_worker->getFailedEepromPaths().clear();
400 }
401}
Sunny Srivastava380efbb2025-04-25 10:28:30 +0530402
Sunny Srivastava78a50422025-04-25 11:17:56 +0530403void IbmHandler::enableMuxChips()
404{
405 if (m_sysCfgJsonObj.empty())
406 {
407 // config JSON should not be empty at this point of execution.
408 throw std::runtime_error("Config JSON is empty. Can't enable muxes");
409 return;
410 }
411
412 if (!m_sysCfgJsonObj.contains("muxes"))
413 {
414 logging::logMessage("No mux defined for the system in config JSON");
415 return;
416 }
417
418 // iterate over each MUX detail and enable them.
419 for (const auto& item : m_sysCfgJsonObj["muxes"])
420 {
Rekha Aparna719093d2025-11-13 03:13:12 -0600421 uint16_t l_errCode = 0;
Sunny Srivastava78a50422025-04-25 11:17:56 +0530422 if (item.contains("holdidlepath"))
423 {
424 std::string cmd = "echo 0 > ";
425 cmd += item["holdidlepath"];
426
427 logging::logMessage("Enabling mux with command = " + cmd);
428
Rekha Aparna719093d2025-11-13 03:13:12 -0600429 commonUtility::executeCmd(cmd, l_errCode);
430
431 if (l_errCode)
432 {
433 m_logger->logMessage(
434 "Failed to execute command [" + cmd +
435 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
436 }
437
Sunny Srivastava78a50422025-04-25 11:17:56 +0530438 continue;
439 }
440
441 logging::logMessage(
442 "Mux Entry does not have hold idle path. Can't enable the mux");
443 }
444}
445
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530446void IbmHandler::getSystemJson(std::string& o_systemJson,
447 const types::VPDMapVariant& i_parsedVpdMap)
448{
449 if (auto l_pVal = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
450 {
451 uint16_t l_errCode = 0;
452 std::string l_hwKWdValue =
453 vpdSpecificUtility::getHWVersion(*l_pVal, l_errCode);
454 if (l_hwKWdValue.empty())
455 {
456 if (l_errCode)
457 {
458 throw DataException("Failed to fetch HW value. Reason: " +
459 commonUtility::getErrCodeMsg(l_errCode));
460 }
461 throw DataException("HW value fetched is empty.");
462 }
463
464 const std::string& l_imKwdValue =
465 vpdSpecificUtility::getIMValue(*l_pVal, l_errCode);
466 if (l_imKwdValue.empty())
467 {
468 if (l_errCode)
469 {
470 throw DataException("Failed to fetch IM value. Reason: " +
471 commonUtility::getErrCodeMsg(l_errCode));
472 }
473 throw DataException("IM value fetched is empty.");
474 }
475
476 auto l_itrToIM = config::systemType.find(l_imKwdValue);
477 if (l_itrToIM == config::systemType.end())
478 {
479 throw DataException("IM keyword does not map to any system type");
480 }
481
482 const types::HWVerList l_hwVersionList = l_itrToIM->second.second;
483 if (!l_hwVersionList.empty())
484 {
485 transform(l_hwKWdValue.begin(), l_hwKWdValue.end(),
486 l_hwKWdValue.begin(), ::toupper);
487
488 auto l_itrToHW =
489 std::find_if(l_hwVersionList.begin(), l_hwVersionList.end(),
490 [&l_hwKWdValue](const auto& l_aPair) {
491 return l_aPair.first == l_hwKWdValue;
492 });
493
494 if (l_itrToHW != l_hwVersionList.end())
495 {
496 if (!(*l_itrToHW).second.empty())
497 {
498 o_systemJson += (*l_itrToIM).first + "_" +
499 (*l_itrToHW).second + ".json";
500 }
501 else
502 {
503 o_systemJson += (*l_itrToIM).first + ".json";
504 }
505 return;
506 }
507 }
508 o_systemJson += l_itrToIM->second.first + ".json";
509 return;
510 }
511
512 throw DataException(
513 "Invalid VPD type returned from Parser. Can't get system JSON.");
514}
515
516static void setEnvAndReboot(const std::string& i_key,
517 const std::string& i_value)
518{
519 // set env and reboot and break.
Rekha Aparna719093d2025-11-13 03:13:12 -0600520 uint16_t l_errCode = 0;
521 commonUtility::executeCmd("/sbin/fw_setenv", l_errCode, i_key, i_value);
522
523 if (l_errCode)
524 {
525 throw std::runtime_error(
526 "Failed to execute command [/sbin/fw_setenv " + i_key + " " +
527 i_value + "], error : " + commonUtility::getErrCodeMsg(l_errCode));
528 }
529
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530530 logging::logMessage("Rebooting BMC to pick up new device tree");
531
532 // make dbus call to reboot
533 auto l_bus = sdbusplus::bus::new_default_system();
534 auto l_method = l_bus.new_method_call(
535 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
536 "org.freedesktop.systemd1.Manager", "Reboot");
537 l_bus.call_noreply(l_method);
538}
539
540static std::string readFitConfigValue()
541{
Rekha Aparna719093d2025-11-13 03:13:12 -0600542 uint16_t l_errCode = 0;
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530543 std::vector<std::string> l_output =
Rekha Aparna719093d2025-11-13 03:13:12 -0600544 commonUtility::executeCmd("/sbin/fw_printenv", l_errCode);
545
546 if (l_errCode)
547 {
548 Logger::getLoggerInstance()->logMessage(
549 "Failed to execute command [/sbin/fw_printenv], error : " +
550 commonUtility::getErrCodeMsg(l_errCode));
551 }
552
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530553 std::string l_fitConfigValue;
554
555 for (const auto& l_entry : l_output)
556 {
557 auto l_pos = l_entry.find("=");
558 auto l_key = l_entry.substr(0, l_pos);
559 if (l_key != "fitconfig")
560 {
561 continue;
562 }
563
564 if (l_pos + 1 < l_entry.size())
565 {
566 l_fitConfigValue = l_entry.substr(l_pos + 1);
567 }
568 }
569
570 return l_fitConfigValue;
571}
572
573bool IbmHandler::isBackupOnCache()
574{
575 try
576 {
577 uint16_t l_errCode = 0;
578 std::string l_backupAndRestoreCfgFilePath =
579 m_sysCfgJsonObj.value("backupRestoreConfigPath", "");
580
581 if (l_backupAndRestoreCfgFilePath.empty())
582 {
583 m_logger->logMessage(
584 "backupRestoreConfigPath is not found in JSON. Can't determne the backup path.");
585 return false;
586 }
587
588 nlohmann::json l_backupAndRestoreCfgJsonObj =
589 jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath,
590 l_errCode);
591 if (l_backupAndRestoreCfgJsonObj.empty() || l_errCode)
592 {
593 m_logger->logMessage(
594 "JSON parsing failed for file [ " +
595 std::string(l_backupAndRestoreCfgFilePath) +
596 " ], error : " + commonUtility::getErrCodeMsg(l_errCode));
597 return false;
598 }
599
600 // check if either of "source" or "destination" has inventory path.
601 // this indicates that this sytem has System VPD on hardware
602 // and other copy on D-Bus (BMC cache).
603 if (!l_backupAndRestoreCfgJsonObj.empty() &&
604 ((l_backupAndRestoreCfgJsonObj.contains("source") &&
605 l_backupAndRestoreCfgJsonObj["source"].contains(
606 "inventoryPath")) ||
607 (l_backupAndRestoreCfgJsonObj.contains("destination") &&
608 l_backupAndRestoreCfgJsonObj["destination"].contains(
609 "inventoryPath"))))
610 {
611 return true;
612 }
613 }
614 catch (const std::exception& l_ex)
615 {
616 m_logger->logMessage(
617 "Exception while checking for backup on cache. Reason:" +
618 std::string(l_ex.what()));
619 }
620
621 // In case of any failure/ambiguity. Don't perform back up and restore.
622 return false;
623}
624
625void IbmHandler::performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap)
626{
627 try
628 {
629 m_backupAndRestoreObj =
630 std::make_shared<BackupAndRestore>(m_sysCfgJsonObj);
631 auto [l_srcVpdVariant,
632 l_dstVpdVariant] = m_backupAndRestoreObj->backupAndRestore();
633
634 // ToDo: Revisit is this check is required or not.
635 if (auto l_srcVpdMap = std::get_if<types::IPZVpdMap>(&l_srcVpdVariant);
636 l_srcVpdMap && !(*l_srcVpdMap).empty())
637 {
638 io_srcVpdMap = std::move(l_srcVpdVariant);
639 }
640 }
641 catch (const std::exception& l_ex)
642 {
643 EventLogger::createSyncPel(
644 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
645 __FILE__, __FUNCTION__, 0,
646 std::string(
647 "Exception caught while backup and restore VPD keyword's.") +
648 EventLogger::getErrorMsg(l_ex),
649 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
650 }
651}
652
Sunny Srivastava57a4ee52025-11-19 12:13:50 +0530653std::string IbmHandler::createAssetTagString(
654 const types::VPDMapVariant& i_parsedVpdMap)
655{
656 std::string l_assetTag;
657 // system VPD will be in IPZ format.
658 if (auto l_parsedVpdMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
659 {
660 auto l_itrToVsys = (*l_parsedVpdMap).find(constants::recVSYS);
661 if (l_itrToVsys != (*l_parsedVpdMap).end())
662 {
663 uint16_t l_errCode = 0;
664 const std::string l_tmKwdValue{vpdSpecificUtility::getKwVal(
665 l_itrToVsys->second, constants::kwdTM, l_errCode)};
666 if (l_tmKwdValue.empty())
667 {
668 throw std::runtime_error(
669 std::string("Failed to get value for keyword [") +
670 constants::kwdTM +
671 std::string("] while creating Asset tag. Error : " +
672 commonUtility::getErrCodeMsg(l_errCode)));
673 }
674 const std::string l_seKwdValue{vpdSpecificUtility::getKwVal(
675 l_itrToVsys->second, constants::kwdSE, l_errCode)};
676 if (l_seKwdValue.empty())
677 {
678 throw std::runtime_error(
679 std::string("Failed to get value for keyword [") +
680 constants::kwdSE +
681 std::string("] while creating Asset tag. Error : " +
682 commonUtility::getErrCodeMsg(l_errCode)));
683 }
684 l_assetTag = std::string{"Server-"} + l_tmKwdValue +
685 std::string{"-"} + l_seKwdValue;
686 }
687 else
688 {
689 throw std::runtime_error(
690 "VSYS record not found in parsed VPD map to create Asset tag.");
691 }
692 }
693 else
694 {
695 throw std::runtime_error(
696 "Invalid VPD type recieved to create Asset tag.");
697 }
698 return l_assetTag;
699}
700
701void IbmHandler::publishSystemVPD(const types::VPDMapVariant& i_parsedVpdMap)
702{
703 types::ObjectMap l_objectInterfaceMap;
704 if (std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
705 {
706 m_worker->populateDbus(i_parsedVpdMap, l_objectInterfaceMap,
707 SYSTEM_VPD_FILE_PATH);
708 try
709 {
710 // Factory reset condition will be added in subsequent commit.
711 // if (m_isFactoryResetDone)
712 //{
713 const auto& l_assetTag = createAssetTagString(i_parsedVpdMap);
714 auto l_itrToSystemPath = l_objectInterfaceMap.find(
715 sdbusplus::message::object_path(constants::systemInvPath));
716 if (l_itrToSystemPath == l_objectInterfaceMap.end())
717 {
718 throw std::runtime_error(
719 "Asset tag update failed. System Path not found in object map.");
720 }
721 types::PropertyMap l_assetTagProperty;
722 l_assetTagProperty.emplace("AssetTag", l_assetTag);
723 (l_itrToSystemPath->second)
724 .emplace(constants::assetTagInf, std::move(l_assetTagProperty));
725 //}
726 }
727 catch (const std::exception& l_ex)
728 {
729 EventLogger::createSyncPel(
730 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
731 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
732 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
733 }
734 // Notify PIM
735 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
736 {
737 throw std::runtime_error("Call to PIM failed for system VPD");
738 }
739 }
740 else
741 {
742 throw DataException("Invalid format of parsed VPD map.");
743 }
744}
745
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530746void IbmHandler::setDeviceTreeAndJson()
747{
748 // JSON is madatory for processing of this API.
749 if (m_sysCfgJsonObj.empty())
750 {
751 throw JsonException("System config JSON is empty", m_sysCfgJsonObj);
752 }
753
754 // parse system VPD
755 auto l_parsedVpdMap = m_worker->parseVpdFile(SYSTEM_VPD_FILE_PATH);
756
757 // Implies it is default JSON.
758 std::string l_systemJson{JSON_ABSOLUTE_PATH_PREFIX};
759
760 // get system JSON as per the system configuration.
761 getSystemJson(l_systemJson, l_parsedVpdMap);
762
763 if (!l_systemJson.compare(JSON_ABSOLUTE_PATH_PREFIX))
764 {
765 throw DataException(
766 "No system JSON found corresponding to IM read from VPD.");
767 }
768
769 uint16_t l_errCode = 0;
770 // re-parse the JSON once appropriate JSON has been selected.
771 m_sysCfgJsonObj = jsonUtility::getParsedJson(l_systemJson, l_errCode);
772
773 if (l_errCode)
774 {
775 throw(JsonException(
776 "JSON parsing failed for file [ " + l_systemJson +
777 " ], error : " + commonUtility::getErrCodeMsg(l_errCode),
778 l_systemJson));
779 }
780
781 m_worker->setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
782 constants::vpdCollectionInProgress);
783
784 std::string l_devTreeFromJson;
785 if (m_sysCfgJsonObj.contains("devTree"))
786 {
787 l_devTreeFromJson = m_sysCfgJsonObj["devTree"];
788
789 if (l_devTreeFromJson.empty())
790 {
791 EventLogger::createSyncPel(
792 types::ErrorType::JsonFailure, types::SeverityType::Error,
793 __FILE__, __FUNCTION__, 0,
794 "Mandatory value for device tree missing from JSON[" +
795 l_systemJson + "]",
796 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
797 }
798 }
799
800 auto l_fitConfigVal = readFitConfigValue();
801
802 if (l_devTreeFromJson.empty() ||
803 l_fitConfigVal.find(l_devTreeFromJson) != std::string::npos)
804 { // Skipping setting device tree as either devtree info is missing from
805 // Json or it is rightly set.
806
807 m_worker->setJsonSymbolicLink(l_systemJson);
808
809 const std::string& l_systemVpdInvPath =
810 jsonUtility::getInventoryObjPathFromJson(
811 m_sysCfgJsonObj, SYSTEM_VPD_FILE_PATH, l_errCode);
812
813 if (l_systemVpdInvPath.empty())
814 {
815 if (l_errCode)
816 {
817 throw JsonException(
818 "System vpd inventory path not found in JSON. Reason:" +
819 commonUtility::getErrCodeMsg(l_errCode),
820 INVENTORY_JSON_SYM_LINK);
821 }
822 throw JsonException("System vpd inventory path is missing in JSON",
823 INVENTORY_JSON_SYM_LINK);
824 }
825
826 // TODO: for backward compatibility this should also support motherboard
827 // interface.
828 std::vector<std::string> l_interfaceList{
829 constants::motherboardInterface};
830 const types::MapperGetObject& l_sysVpdObjMap =
831 dbusUtility::getObjectMap(l_systemVpdInvPath, l_interfaceList);
832
833 if (!l_sysVpdObjMap.empty())
834 {
835 if (isBackupOnCache() && jsonUtility::isBackupAndRestoreRequired(
836 m_sysCfgJsonObj, l_errCode))
837 {
838 performBackupAndRestore(l_parsedVpdMap);
839 }
840 else if (l_errCode)
841 {
842 logging::logMessage(
843 "Failed to check if backup and restore required. Reason : " +
844 commonUtility::getErrCodeMsg(l_errCode));
845 }
846 }
847
848 // proceed to publish system VPD.
Sunny Srivastava57a4ee52025-11-19 12:13:50 +0530849 publishSystemVPD(l_parsedVpdMap);
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530850 m_worker->setCollectionStatusProperty(
851 SYSTEM_VPD_FILE_PATH, constants::vpdCollectionCompleted);
852 return;
853 }
854
855 setEnvAndReboot("fitconfig", l_devTreeFromJson);
856 exit(EXIT_SUCCESS);
857}
858
Sunny Srivastava78a50422025-04-25 11:17:56 +0530859void IbmHandler::performInitialSetup()
860{
861 try
862 {
Anupama B R281e2d42025-05-05 10:05:13 -0500863 if (m_worker.get() == nullptr)
864 {
865 throw std::runtime_error(
866 "Worker object not found. Can't perform initial setup.");
867 }
868
869 m_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
Sunny Srivastava78a50422025-04-25 11:17:56 +0530870 if (!dbusUtility::isChassisPowerOn())
871 {
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530872 setDeviceTreeAndJson();
Sunny Srivastava78a50422025-04-25 11:17:56 +0530873 }
874
Anupama B R95083d42025-10-27 04:54:58 -0500875 // Update BMC postion for RBMC prototype system
876 // Ignore BMC position update in case of any error
877 uint16_t l_errCode = 0;
Anupama B R657aaa82025-10-30 04:12:24 -0500878 if (isRbmcPrototypeSystem(l_errCode))
Anupama B R95083d42025-10-27 04:54:58 -0500879 {
Anupama B R657aaa82025-10-30 04:12:24 -0500880 size_t l_bmcPosition = std::numeric_limits<size_t>::max();
881 checkAndUpdateBmcPosition(l_bmcPosition);
Anupama B R95083d42025-10-27 04:54:58 -0500882
Anupama B R657aaa82025-10-30 04:12:24 -0500883 if (dbusUtility::callPIM(types::ObjectMap{
884 {sdbusplus::message::object_path(constants::systemInvPath),
885 {{constants::rbmcPositionInterface,
886 {{"Position", l_bmcPosition}}}}}}))
887 {
888 m_logger->logMessage(
889 "Updating BMC position failed for path [" +
890 std::string(constants::systemInvPath) +
891 "], bmc position: " + std::to_string(l_bmcPosition));
892
893 // ToDo: Check is PEL required
894 }
895 }
896 else if (l_errCode != 0)
897 {
898 m_logger->logMessage(
899 "Unable to determine whether system is RBMC system or not, reason: " +
900 commonUtility::getErrCodeMsg(l_errCode));
Anupama B R95083d42025-10-27 04:54:58 -0500901 }
902
Sunny Srivastava78a50422025-04-25 11:17:56 +0530903 // Enable all mux which are used for connecting to the i2c on the
904 // pcie slots for pcie cards. These are not enabled by kernel due to
905 // an issue seen with Castello cards, where the i2c line hangs on a
906 // probe.
907 enableMuxChips();
908
909 // Nothing needs to be done. Service restarted or BMC re-booted for
910 // some reason at system power on.
Sunny Srivastava78a50422025-04-25 11:17:56 +0530911 }
912 catch (const std::exception& l_ex)
913 {
Anupama B R4c65fcd2025-09-01 08:09:00 -0500914 m_worker->setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
915 constants::vpdCollectionFailed);
Sunny Srivastava78a50422025-04-25 11:17:56 +0530916 // Any issue in system's inital set up is handled in this catch. Error
917 // will not propogate to manager.
918 EventLogger::createSyncPel(
919 EventLogger::getErrorType(l_ex), types::SeverityType::Critical,
920 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
921 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
922 }
923}
924
Anupama B R7127ab42025-06-26 01:39:08 -0500925void IbmHandler::collectAllFruVpd()
926{
927 // Setting status to "InProgress", before trigeering VPD collection.
Anupama B Rda9806b2025-08-29 02:41:10 -0500928 m_progressInterface->set_property(
929 "Status", std::string(constants::vpdCollectionInProgress));
Anupama B R7127ab42025-06-26 01:39:08 -0500930 m_worker->collectFrusFromJson();
931 SetTimerToDetectVpdCollectionStatus();
932}
Anupama B R95083d42025-10-27 04:54:58 -0500933
Anupama B R657aaa82025-10-30 04:12:24 -0500934bool IbmHandler::isRbmcPrototypeSystem(uint16_t& o_errCode) const noexcept
Anupama B R95083d42025-10-27 04:54:58 -0500935{
Anupama B R657aaa82025-10-30 04:12:24 -0500936 types::BinaryVector l_imValue = dbusUtility::getImFromDbus();
937 if (l_imValue.empty())
938 {
939 o_errCode = error_code::DBUS_FAILURE;
940 return false;
941 }
942
943 if (constants::rbmcPrototypeSystemImValue == l_imValue)
944 {
945 return true;
946 }
Anupama B R95083d42025-10-27 04:54:58 -0500947
948 return false;
949}
950
Anupama B R657aaa82025-10-30 04:12:24 -0500951void IbmHandler::checkAndUpdateBmcPosition(size_t& o_bmcPosition) const noexcept
Anupama B R95083d42025-10-27 04:54:58 -0500952{
Anupama B R657aaa82025-10-30 04:12:24 -0500953 if (m_worker.get() == nullptr)
954 {
955 m_logger->logMessage("Worker object not found");
956 return;
957 }
Anupama B R95083d42025-10-27 04:54:58 -0500958
Anupama B R657aaa82025-10-30 04:12:24 -0500959 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj();
960 if (l_sysCfgJsonObj.empty())
961 {
962 m_logger->logMessage(
963 "System config JSON is empty, unable to find BMC position");
964 return;
965 }
966
967 uint16_t l_errCode = 0;
968 std::string l_motherboardEepromPath = jsonUtility::getFruPathFromJson(
969 l_sysCfgJsonObj, constants::systemVpdInvPath, l_errCode);
970
971 if (!l_motherboardEepromPath.empty())
972 {
973 o_bmcPosition = constants::VALUE_1;
974 std::error_code l_ec;
975 if (std::filesystem::exists(l_motherboardEepromPath, l_ec))
976 {
977 o_bmcPosition = constants::VALUE_0;
978 }
979 }
980 else if (l_errCode)
981 {
982 m_logger->logMessage("Unable to determine BMC position, reason: " +
983 commonUtility::getErrCodeMsg(l_errCode));
984 }
985 else
986 {
987 m_logger->logMessage("Unable to determine BMC position, as FRU path[" +
988 std::string(constants::systemVpdInvPath) +
989 "], not found in the system config JSON.");
990 }
Anupama B R95083d42025-10-27 04:54:58 -0500991}
Sunny Srivastava867ee752025-04-15 12:24:23 +0530992} // namespace vpd