1 #include "config.h" 2 3 #include "manager.hpp" 4 5 #include "constants.hpp" 6 #include "exceptions.hpp" 7 #include "logger.hpp" 8 #include "parser.hpp" 9 #include "parser_factory.hpp" 10 #include "parser_interface.hpp" 11 #include "single_fab.hpp" 12 #include "types.hpp" 13 #include "utility/dbus_utility.hpp" 14 #include "utility/json_utility.hpp" 15 #include "utility/vpd_specific_utility.hpp" 16 17 #include <boost/asio/steady_timer.hpp> 18 #include <sdbusplus/bus/match.hpp> 19 #include <sdbusplus/message.hpp> 20 21 namespace vpd 22 { 23 Manager::Manager( 24 const std::shared_ptr<boost::asio::io_context>& ioCon, 25 const std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace, 26 const std::shared_ptr<sdbusplus::asio::dbus_interface>& progressiFace, 27 const std::shared_ptr<sdbusplus::asio::connection>& asioConnection) : 28 m_ioContext(ioCon), m_interface(iFace), m_progressInterface(progressiFace), 29 m_asioConnection(asioConnection) 30 { 31 #ifdef IBM_SYSTEM 32 if (!dbusUtility::isChassisPowerOn()) 33 { 34 SingleFab l_singleFab; 35 const int& l_rc = l_singleFab.singleFabImOverride(); 36 37 if (l_rc == constants::FAILURE) 38 { 39 throw std::runtime_error( 40 std::string(__FUNCTION__) + 41 " : Found an invalid system configuration. Needs manual intervention. BMC is being quiesced."); 42 } 43 } 44 #endif 45 46 try 47 { 48 // For backward compatibility. Should be depricated. 49 iFace->register_method( 50 "WriteKeyword", 51 [this](const sdbusplus::message::object_path i_path, 52 const std::string i_recordName, const std::string i_keyword, 53 const types::BinaryVector i_value) -> int { 54 return this->updateKeyword( 55 i_path, std::make_tuple(i_recordName, i_keyword, i_value)); 56 }); 57 58 // Register methods under com.ibm.VPD.Manager interface 59 iFace->register_method( 60 "UpdateKeyword", 61 [this](const types::Path i_vpdPath, 62 const types::WriteVpdParams i_paramsToWriteData) -> int { 63 return this->updateKeyword(i_vpdPath, i_paramsToWriteData); 64 }); 65 66 iFace->register_method( 67 "WriteKeywordOnHardware", 68 [this](const types::Path i_fruPath, 69 const types::WriteVpdParams i_paramsToWriteData) -> int { 70 return this->updateKeywordOnHardware(i_fruPath, 71 i_paramsToWriteData); 72 }); 73 74 iFace->register_method( 75 "ReadKeyword", 76 [this](const types::Path i_fruPath, 77 const types::ReadVpdParams i_paramsToReadData) 78 -> types::DbusVariantType { 79 return this->readKeyword(i_fruPath, i_paramsToReadData); 80 }); 81 82 iFace->register_method( 83 "CollectFRUVPD", 84 [this](const sdbusplus::message::object_path& i_dbusObjPath) { 85 this->collectSingleFruVpd(i_dbusObjPath); 86 }); 87 88 iFace->register_method( 89 "deleteFRUVPD", 90 [this](const sdbusplus::message::object_path& i_dbusObjPath) { 91 this->deleteSingleFruVpd(i_dbusObjPath); 92 }); 93 94 iFace->register_method( 95 "GetExpandedLocationCode", 96 [this](const std::string& i_unexpandedLocationCode, 97 uint16_t& i_nodeNumber) -> std::string { 98 return this->getExpandedLocationCode(i_unexpandedLocationCode, 99 i_nodeNumber); 100 }); 101 102 iFace->register_method("GetFRUsByExpandedLocationCode", 103 [this](const std::string& i_expandedLocationCode) 104 -> types::ListOfPaths { 105 return this->getFrusByExpandedLocationCode( 106 i_expandedLocationCode); 107 }); 108 109 iFace->register_method( 110 "GetFRUsByUnexpandedLocationCode", 111 [this](const std::string& i_unexpandedLocationCode, 112 uint16_t& i_nodeNumber) -> types::ListOfPaths { 113 return this->getFrusByUnexpandedLocationCode( 114 i_unexpandedLocationCode, i_nodeNumber); 115 }); 116 117 iFace->register_method( 118 "GetHardwarePath", 119 [this](const sdbusplus::message::object_path& i_dbusObjPath) 120 -> std::string { return this->getHwPath(i_dbusObjPath); }); 121 122 iFace->register_method("PerformVPDRecollection", [this]() { 123 this->performVpdRecollection(); 124 }); 125 126 iFace->register_method("CollectAllFRUVPD", [this]() -> bool { 127 return this->collectAllFruVpd(); 128 }); 129 130 // Indicates FRU VPD collection for the system has not started. 131 progressiFace->register_property_rw<std::string>( 132 "Status", sdbusplus::vtable::property_::emits_change, 133 [this](const std::string& l_currStatus, const auto&) { 134 if (m_vpdCollectionStatus != l_currStatus) 135 { 136 m_vpdCollectionStatus = l_currStatus; 137 m_interface->signal_property("Status"); 138 } 139 return true; 140 }, 141 [this](const auto&) { return m_vpdCollectionStatus; }); 142 143 // If required, instantiate OEM specific handler here. 144 #ifdef IBM_SYSTEM 145 m_ibmHandler = std::make_shared<IbmHandler>( 146 m_worker, m_backupAndRestoreObj, m_interface, m_progressInterface, 147 m_ioContext, m_asioConnection); 148 #else 149 m_worker = std::make_shared<Worker>(INVENTORY_JSON_DEFAULT); 150 m_progressInterface->set_property( 151 "Status", std::string(constants::vpdCollectionCompleted)); 152 #endif 153 } 154 catch (const std::exception& e) 155 { 156 logging::logMessage( 157 "Manager class instantiation failed. " + std::string(e.what())); 158 159 vpd::EventLogger::createSyncPel( 160 vpd::EventLogger::getErrorType(e), vpd::types::SeverityType::Error, 161 __FILE__, __FUNCTION__, 0, vpd::EventLogger::getErrorMsg(e), 162 std::nullopt, std::nullopt, std::nullopt, std::nullopt); 163 } 164 } 165 166 int Manager::updateKeyword(const types::Path i_vpdPath, 167 const types::WriteVpdParams i_paramsToWriteData) 168 { 169 if (i_vpdPath.empty()) 170 { 171 logging::logMessage("Given VPD path is empty."); 172 return -1; 173 } 174 175 types::Path l_fruPath; 176 nlohmann::json l_sysCfgJsonObj{}; 177 178 if (m_worker.get() != nullptr) 179 { 180 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj(); 181 182 // Get the EEPROM path 183 if (!l_sysCfgJsonObj.empty()) 184 { 185 l_fruPath = 186 jsonUtility::getFruPathFromJson(l_sysCfgJsonObj, i_vpdPath); 187 } 188 } 189 190 if (l_fruPath.empty()) 191 { 192 l_fruPath = i_vpdPath; 193 } 194 195 try 196 { 197 std::shared_ptr<Parser> l_parserObj = 198 std::make_shared<Parser>(l_fruPath, l_sysCfgJsonObj); 199 200 types::DbusVariantType l_updatedValue; 201 auto l_rc = 202 l_parserObj->updateVpdKeyword(i_paramsToWriteData, l_updatedValue); 203 204 if (l_rc != constants::FAILURE && m_backupAndRestoreObj) 205 { 206 if (m_backupAndRestoreObj->updateKeywordOnPrimaryOrBackupPath( 207 l_fruPath, i_paramsToWriteData) < constants::VALUE_0) 208 { 209 logging::logMessage( 210 "Write success, but backup and restore failed for file[" + 211 l_fruPath + "]"); 212 } 213 } 214 215 types::WriteVpdParams l_writeParams; 216 types::BinaryVector l_valueToUpdate; 217 218 if (const types::IpzData* l_ipzData = 219 std::get_if<types::IpzData>(&i_paramsToWriteData)) 220 { 221 if (const types::BinaryVector* l_val = 222 std::get_if<types::BinaryVector>(&l_updatedValue)) 223 { 224 l_valueToUpdate = *l_val; 225 } 226 else 227 { 228 l_valueToUpdate = std::get<2>(*l_ipzData); 229 } 230 l_writeParams = 231 std::make_tuple(std::get<0>(*l_ipzData), 232 std::get<1>(*l_ipzData), l_valueToUpdate); 233 } 234 else if (const types::KwData* l_kwData = 235 std::get_if<types::KwData>(&i_paramsToWriteData)) 236 { 237 if (const types::BinaryVector* l_val = 238 std::get_if<types::BinaryVector>(&l_updatedValue)) 239 { 240 l_valueToUpdate = *l_val; 241 } 242 else 243 { 244 l_valueToUpdate = std::get<1>(*l_kwData); 245 } 246 247 l_writeParams = 248 std::make_tuple(std::get<0>(*l_kwData), l_valueToUpdate); 249 } 250 251 // update keyword in inherited FRUs 252 if (l_rc != constants::FAILURE) 253 { 254 vpdSpecificUtility::updateKwdOnInheritedFrus( 255 l_fruPath, l_writeParams, l_sysCfgJsonObj); 256 } 257 258 // update common interface(s) properties 259 if (l_rc != constants::FAILURE) 260 { 261 vpdSpecificUtility::updateCiPropertyOfInheritedFrus( 262 l_fruPath, l_writeParams, l_sysCfgJsonObj); 263 } 264 265 return l_rc; 266 } 267 catch (const std::exception& l_exception) 268 { 269 // TODO:: error log needed 270 logging::logMessage("Update keyword failed for file[" + i_vpdPath + 271 "], reason: " + std::string(l_exception.what())); 272 return -1; 273 } 274 } 275 276 int Manager::updateKeywordOnHardware( 277 const types::Path i_fruPath, 278 const types::WriteVpdParams i_paramsToWriteData) noexcept 279 { 280 try 281 { 282 if (i_fruPath.empty()) 283 { 284 throw std::runtime_error("Given FRU path is empty"); 285 } 286 287 nlohmann::json l_sysCfgJsonObj{}; 288 289 if (m_worker.get() != nullptr) 290 { 291 l_sysCfgJsonObj = m_worker->getSysCfgJsonObj(); 292 } 293 294 std::shared_ptr<Parser> l_parserObj = 295 std::make_shared<Parser>(i_fruPath, l_sysCfgJsonObj); 296 return l_parserObj->updateVpdKeywordOnHardware(i_paramsToWriteData); 297 } 298 catch (const std::exception& l_exception) 299 { 300 EventLogger::createAsyncPel( 301 types::ErrorType::InvalidEeprom, types::SeverityType::Informational, 302 __FILE__, __FUNCTION__, 0, 303 "Update keyword on hardware failed for file[" + i_fruPath + 304 "], reason: " + std::string(l_exception.what()), 305 std::nullopt, std::nullopt, std::nullopt, std::nullopt); 306 307 return constants::FAILURE; 308 } 309 } 310 311 types::DbusVariantType Manager::readKeyword( 312 const types::Path i_fruPath, const types::ReadVpdParams i_paramsToReadData) 313 { 314 try 315 { 316 nlohmann::json l_jsonObj{}; 317 318 if (m_worker.get() != nullptr) 319 { 320 l_jsonObj = m_worker->getSysCfgJsonObj(); 321 } 322 323 std::error_code ec; 324 325 // Check if given path is filesystem path 326 if (!std::filesystem::exists(i_fruPath, ec) && (ec)) 327 { 328 throw std::runtime_error( 329 "Given file path " + i_fruPath + " not found."); 330 } 331 332 std::shared_ptr<vpd::Parser> l_parserObj = 333 std::make_shared<vpd::Parser>(i_fruPath, l_jsonObj); 334 335 std::shared_ptr<vpd::ParserInterface> l_vpdParserInstance = 336 l_parserObj->getVpdParserInstance(); 337 338 return ( 339 l_vpdParserInstance->readKeywordFromHardware(i_paramsToReadData)); 340 } 341 catch (const std::exception& e) 342 { 343 logging::logMessage( 344 e.what() + std::string(". VPD manager read operation failed for ") + 345 i_fruPath); 346 throw types::DeviceError::ReadFailure(); 347 } 348 } 349 350 void Manager::collectSingleFruVpd( 351 const sdbusplus::message::object_path& i_dbusObjPath) 352 { 353 if (m_vpdCollectionStatus != constants::vpdCollectionCompleted) 354 { 355 logging::logMessage( 356 "Currently VPD CollectionStatus is not completed. Cannot perform single FRU VPD collection for " + 357 std::string(i_dbusObjPath)); 358 return; 359 } 360 361 if (m_worker.get() != nullptr) 362 { 363 m_worker->collectSingleFruVpd(i_dbusObjPath); 364 } 365 } 366 367 void Manager::deleteSingleFruVpd( 368 const sdbusplus::message::object_path& i_dbusObjPath) 369 { 370 try 371 { 372 if (std::string(i_dbusObjPath).empty()) 373 { 374 throw std::runtime_error( 375 "Given DBus object path is empty. Aborting FRU VPD deletion."); 376 } 377 378 if (m_worker.get() == nullptr) 379 { 380 throw std::runtime_error( 381 "Worker object not found, can't perform FRU VPD deletion for: " + 382 std::string(i_dbusObjPath)); 383 } 384 385 m_worker->deleteFruVpd(std::string(i_dbusObjPath)); 386 } 387 catch (const std::exception& l_ex) 388 { 389 // TODO: Log PEL 390 logging::logMessage(l_ex.what()); 391 } 392 } 393 394 bool Manager::isValidUnexpandedLocationCode( 395 const std::string& i_unexpandedLocationCode) 396 { 397 if ((i_unexpandedLocationCode.length() < 398 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) || 399 ((i_unexpandedLocationCode.compare(0, 4, "Ufcs") != 400 constants::STR_CMP_SUCCESS) && 401 (i_unexpandedLocationCode.compare(0, 4, "Umts") != 402 constants::STR_CMP_SUCCESS)) || 403 ((i_unexpandedLocationCode.length() > 404 constants::UNEXP_LOCATION_CODE_MIN_LENGTH) && 405 (i_unexpandedLocationCode.find("-") != 4))) 406 { 407 return false; 408 } 409 410 return true; 411 } 412 413 std::string Manager::getExpandedLocationCode( 414 const std::string& i_unexpandedLocationCode, 415 [[maybe_unused]] const uint16_t i_nodeNumber) 416 { 417 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode)) 418 { 419 phosphor::logging::elog<types::DbusInvalidArgument>( 420 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"), 421 types::InvalidArgument::ARGUMENT_VALUE( 422 i_unexpandedLocationCode.c_str())); 423 } 424 425 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj(); 426 if (!l_sysCfgJsonObj.contains("frus")) 427 { 428 logging::logMessage("Missing frus tag in system config JSON"); 429 } 430 431 const nlohmann::json& l_listOfFrus = 432 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>(); 433 434 for (const auto& l_frus : l_listOfFrus.items()) 435 { 436 for (const auto& l_aFru : l_frus.value()) 437 { 438 if (l_aFru["extraInterfaces"].contains( 439 constants::locationCodeInf) && 440 l_aFru["extraInterfaces"][constants::locationCodeInf].value( 441 "LocationCode", "") == i_unexpandedLocationCode) 442 { 443 return std::get<std::string>(dbusUtility::readDbusProperty( 444 l_aFru["serviceName"], l_aFru["inventoryPath"], 445 constants::locationCodeInf, "LocationCode")); 446 } 447 } 448 } 449 phosphor::logging::elog<types::DbusInvalidArgument>( 450 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"), 451 types::InvalidArgument::ARGUMENT_VALUE( 452 i_unexpandedLocationCode.c_str())); 453 } 454 455 types::ListOfPaths Manager::getFrusByUnexpandedLocationCode( 456 const std::string& i_unexpandedLocationCode, 457 [[maybe_unused]] const uint16_t i_nodeNumber) 458 { 459 types::ListOfPaths l_inventoryPaths; 460 461 if (!isValidUnexpandedLocationCode(i_unexpandedLocationCode)) 462 { 463 phosphor::logging::elog<types::DbusInvalidArgument>( 464 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"), 465 types::InvalidArgument::ARGUMENT_VALUE( 466 i_unexpandedLocationCode.c_str())); 467 } 468 469 const nlohmann::json& l_sysCfgJsonObj = m_worker->getSysCfgJsonObj(); 470 if (!l_sysCfgJsonObj.contains("frus")) 471 { 472 logging::logMessage("Missing frus tag in system config JSON"); 473 } 474 475 const nlohmann::json& l_listOfFrus = 476 l_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>(); 477 478 for (const auto& l_frus : l_listOfFrus.items()) 479 { 480 for (const auto& l_aFru : l_frus.value()) 481 { 482 if (l_aFru["extraInterfaces"].contains( 483 constants::locationCodeInf) && 484 l_aFru["extraInterfaces"][constants::locationCodeInf].value( 485 "LocationCode", "") == i_unexpandedLocationCode) 486 { 487 l_inventoryPaths.push_back( 488 l_aFru.at("inventoryPath") 489 .get_ref<const nlohmann::json::string_t&>()); 490 } 491 } 492 } 493 494 if (l_inventoryPaths.empty()) 495 { 496 phosphor::logging::elog<types::DbusInvalidArgument>( 497 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"), 498 types::InvalidArgument::ARGUMENT_VALUE( 499 i_unexpandedLocationCode.c_str())); 500 } 501 502 return l_inventoryPaths; 503 } 504 505 std::string Manager::getHwPath( 506 const sdbusplus::message::object_path& i_dbusObjPath) 507 { 508 // Dummy code to supress unused variable warning. To be removed. 509 logging::logMessage(std::string(i_dbusObjPath)); 510 511 return std::string{}; 512 } 513 514 std::tuple<std::string, uint16_t> Manager::getUnexpandedLocationCode( 515 const std::string& i_expandedLocationCode) 516 { 517 /** 518 * Location code should always start with U and fulfil minimum length 519 * criteria. 520 */ 521 if (i_expandedLocationCode[0] != 'U' || 522 i_expandedLocationCode.length() < 523 constants::EXP_LOCATION_CODE_MIN_LENGTH) 524 { 525 phosphor::logging::elog<types::DbusInvalidArgument>( 526 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"), 527 types::InvalidArgument::ARGUMENT_VALUE( 528 i_expandedLocationCode.c_str())); 529 } 530 531 std::string l_fcKwd; 532 533 auto l_fcKwdValue = dbusUtility::readDbusProperty( 534 "xyz.openbmc_project.Inventory.Manager", 535 "/xyz/openbmc_project/inventory/system/chassis/motherboard", 536 "com.ibm.ipzvpd.VCEN", "FC"); 537 538 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_fcKwdValue)) 539 { 540 l_fcKwd.assign(l_kwdValue->begin(), l_kwdValue->end()); 541 } 542 543 // Get the first part of expanded location code to check for FC or TM. 544 std::string l_firstKwd = i_expandedLocationCode.substr(1, 4); 545 546 std::string l_unexpandedLocationCode{}; 547 uint16_t l_nodeNummber = constants::INVALID_NODE_NUMBER; 548 549 // Check if this value matches the value of FC keyword. 550 if (l_fcKwd.substr(0, 4) == l_firstKwd) 551 { 552 /** 553 * Period(.) should be there in expanded location code to seggregate 554 * FC, node number and SE values. 555 */ 556 size_t l_nodeStartPos = i_expandedLocationCode.find('.'); 557 if (l_nodeStartPos == std::string::npos) 558 { 559 phosphor::logging::elog<types::DbusInvalidArgument>( 560 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"), 561 types::InvalidArgument::ARGUMENT_VALUE( 562 i_expandedLocationCode.c_str())); 563 } 564 565 size_t l_nodeEndPos = 566 i_expandedLocationCode.find('.', l_nodeStartPos + 1); 567 if (l_nodeEndPos == std::string::npos) 568 { 569 phosphor::logging::elog<types::DbusInvalidArgument>( 570 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"), 571 types::InvalidArgument::ARGUMENT_VALUE( 572 i_expandedLocationCode.c_str())); 573 } 574 575 // Skip 3 bytes for '.ND' 576 l_nodeNummber = std::stoi(i_expandedLocationCode.substr( 577 l_nodeStartPos + 3, (l_nodeEndPos - l_nodeStartPos - 3))); 578 579 /** 580 * Confirm if there are other details apart FC, node number and SE 581 * in location code 582 */ 583 if (i_expandedLocationCode.length() > 584 constants::EXP_LOCATION_CODE_MIN_LENGTH) 585 { 586 l_unexpandedLocationCode = 587 i_expandedLocationCode[0] + std::string("fcs") + 588 i_expandedLocationCode.substr( 589 l_nodeEndPos + 1 + constants::SE_KWD_LENGTH, 590 std::string::npos); 591 } 592 else 593 { 594 l_unexpandedLocationCode = "Ufcs"; 595 } 596 } 597 else 598 { 599 std::string l_tmKwd; 600 // Read TM keyword value. 601 auto l_tmKwdValue = dbusUtility::readDbusProperty( 602 "xyz.openbmc_project.Inventory.Manager", 603 "/xyz/openbmc_project/inventory/system/chassis/motherboard", 604 "com.ibm.ipzvpd.VSYS", "TM"); 605 606 if (auto l_kwdValue = std::get_if<types::BinaryVector>(&l_tmKwdValue)) 607 { 608 l_tmKwd.assign(l_kwdValue->begin(), l_kwdValue->end()); 609 } 610 611 // Check if the substr matches to TM keyword value. 612 if (l_tmKwd.substr(0, 4) == l_firstKwd) 613 { 614 /** 615 * System location code will not have node number and any other 616 * details. 617 */ 618 l_unexpandedLocationCode = "Umts"; 619 } 620 // The given location code is neither "fcs" or "mts". 621 else 622 { 623 phosphor::logging::elog<types::DbusInvalidArgument>( 624 types::InvalidArgument::ARGUMENT_NAME("LOCATIONCODE"), 625 types::InvalidArgument::ARGUMENT_VALUE( 626 i_expandedLocationCode.c_str())); 627 } 628 } 629 630 return std::make_tuple(l_unexpandedLocationCode, l_nodeNummber); 631 } 632 633 types::ListOfPaths Manager::getFrusByExpandedLocationCode( 634 const std::string& i_expandedLocationCode) 635 { 636 std::tuple<std::string, uint16_t> l_locationAndNodePair = 637 getUnexpandedLocationCode(i_expandedLocationCode); 638 639 return getFrusByUnexpandedLocationCode(std::get<0>(l_locationAndNodePair), 640 std::get<1>(l_locationAndNodePair)); 641 } 642 643 void Manager::performVpdRecollection() 644 { 645 if (m_worker.get() != nullptr) 646 { 647 m_worker->performVpdRecollection(); 648 } 649 } 650 651 bool Manager::collectAllFruVpd() const noexcept 652 { 653 try 654 { 655 types::SeverityType l_severityType; 656 if (m_vpdCollectionStatus == constants::vpdCollectionNotStarted) 657 { 658 l_severityType = types::SeverityType::Informational; 659 } 660 else if (m_vpdCollectionStatus == constants::vpdCollectionCompleted || 661 m_vpdCollectionStatus == constants::vpdCollectionFailed) 662 { 663 l_severityType = types::SeverityType::Warning; 664 } 665 else 666 { 667 throw std::runtime_error( 668 "Invalid collection status " + m_vpdCollectionStatus + 669 ". Aborting all FRUs VPD collection."); 670 } 671 672 EventLogger::createSyncPel( 673 types::ErrorType::FirmwareError, l_severityType, __FILE__, 674 __FUNCTION__, 0, "Collect all FRUs VPD is requested.", std::nullopt, 675 std::nullopt, std::nullopt, std::nullopt); 676 677 // ToDo: Handle with OEM interface 678 #ifdef IBM_SYSTEM 679 if (m_ibmHandler.get() != nullptr) 680 { 681 m_ibmHandler->collectAllFruVpd(); 682 return true; 683 } 684 else 685 { 686 throw std::runtime_error( 687 "Not found any OEM handler to collect all FRUs VPD."); 688 } 689 #endif 690 } 691 catch (const std::exception& l_ex) 692 { 693 EventLogger::createSyncPel( 694 EventLogger::getErrorType(l_ex), types::SeverityType::Warning, 695 __FILE__, __FUNCTION__, 0, std::string(l_ex.what()), std::nullopt, 696 std::nullopt, std::nullopt, std::nullopt); 697 } 698 return false; 699 } 700 } // namespace vpd 701