1 #include "config.h" 2 3 #include "manager.hpp" 4 5 #include "common_utility.hpp" 6 #include "editor_impl.hpp" 7 #include "ibm_vpd_utils.hpp" 8 #include "ipz_parser.hpp" 9 #include "parser_factory.hpp" 10 #include "reader_impl.hpp" 11 #include "vpd_exceptions.hpp" 12 13 #include <unistd.h> 14 15 #include <phosphor-logging/elog-errors.hpp> 16 #include <xyz/openbmc_project/Common/error.hpp> 17 18 #include <filesystem> 19 20 using namespace openpower::vpd::constants; 21 using namespace openpower::vpd::inventory; 22 using namespace openpower::vpd::manager::editor; 23 using namespace openpower::vpd::manager::reader; 24 using namespace std; 25 using namespace openpower::vpd::parser; 26 using namespace openpower::vpd::parser::factory; 27 using namespace openpower::vpd::ipz::parser; 28 using namespace openpower::vpd::exceptions; 29 using namespace phosphor::logging; 30 31 namespace openpower 32 { 33 namespace vpd 34 { 35 namespace manager 36 { 37 38 Manager::Manager(std::shared_ptr<boost::asio::io_context>& ioCon, 39 std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace, 40 std::shared_ptr<sdbusplus::asio::connection>& conn) : 41 ioContext(ioCon), 42 interface(iFace), conn(conn) 43 { 44 interface->register_method( 45 "WriteKeyword", 46 [this](const sdbusplus::message::object_path& path, 47 const std::string& recordName, const std::string& keyword, 48 const Binary& value) { 49 this->writeKeyword(path, recordName, keyword, value); 50 }); 51 52 interface->register_method( 53 "GetFRUsByUnexpandedLocationCode", 54 [this](const std::string& locationCode, 55 const uint16_t nodeNumber) -> inventory::ListOfPaths { 56 return this->getFRUsByUnexpandedLocationCode(locationCode, nodeNumber); 57 }); 58 59 interface->register_method( 60 "GetFRUsByExpandedLocationCode", 61 [this](const std::string& locationCode) -> inventory::ListOfPaths { 62 return this->getFRUsByExpandedLocationCode(locationCode); 63 }); 64 65 interface->register_method( 66 "GetExpandedLocationCode", 67 [this](const std::string& locationCode, 68 const uint16_t nodeNumber) -> std::string { 69 return this->getExpandedLocationCode(locationCode, nodeNumber); 70 }); 71 72 interface->register_method("PerformVPDRecollection", 73 [this]() { this->performVPDRecollection(); }); 74 75 interface->register_method( 76 "deleteFRUVPD", [this](const sdbusplus::message::object_path& path) { 77 this->deleteFRUVPD(path); 78 }); 79 80 interface->register_method( 81 "CollectFRUVPD", [this](const sdbusplus::message::object_path& path) { 82 this->collectFRUVPD(path); 83 }); 84 85 sd_bus_default(&sdBus); 86 initManager(); 87 } 88 89 void Manager::initManager() 90 { 91 try 92 { 93 processJSON(); 94 restoreSystemVpd(); 95 listenHostState(); 96 listenAssetTag(); 97 98 // Create an instance of the BIOS handler 99 biosHandler = std::make_shared<BiosHandler>(conn, *this); 100 101 // instantiate gpioMonitor class 102 gpioMon = std::make_shared<GpioMonitor>(jsonFile, ioContext); 103 } 104 catch (const std::exception& e) 105 { 106 std::cerr << e.what() << "\n"; 107 } 108 } 109 110 /** 111 * @brief An api to get list of blank system VPD properties. 112 * @param[in] vpdMap - IPZ vpd map. 113 * @param[in] objectPath - Object path for the FRU. 114 * @param[out] blankPropertyList - Properties which are blank in System VPD and 115 * needs to be updated as standby. 116 */ 117 static void 118 getListOfBlankSystemVpd(Parsed& vpdMap, const string& objectPath, 119 std::vector<RestoredEeproms>& blankPropertyList) 120 { 121 for (const auto& systemRecKwdPair : svpdKwdMap) 122 { 123 auto it = vpdMap.find(systemRecKwdPair.first); 124 125 // check if record is found in map we got by parser 126 if (it != vpdMap.end()) 127 { 128 const auto& kwdListForRecord = systemRecKwdPair.second; 129 for (const auto& keywordInfo : kwdListForRecord) 130 { 131 const auto& keyword = get<0>(keywordInfo); 132 133 DbusPropertyMap& kwdValMap = it->second; 134 auto iterator = kwdValMap.find(keyword); 135 136 if (iterator != kwdValMap.end()) 137 { 138 string& kwdValue = iterator->second; 139 140 // check bus data 141 const string& recordName = systemRecKwdPair.first; 142 const string& busValue = readBusProperty( 143 objectPath, ipzVpdInf + recordName, keyword); 144 145 const auto& defaultValue = get<1>(keywordInfo); 146 147 if (Binary(busValue.begin(), busValue.end()) != 148 defaultValue) 149 { 150 if (Binary(kwdValue.begin(), kwdValue.end()) == 151 defaultValue) 152 { 153 // implies data is blank on EEPROM but not on cache. 154 // So EEPROM vpd update is required. 155 Binary busData(busValue.begin(), busValue.end()); 156 157 blankPropertyList.push_back(std::make_tuple( 158 objectPath, recordName, keyword, busData)); 159 } 160 } 161 } 162 } 163 } 164 } 165 } 166 167 void Manager::restoreSystemVpd() 168 { 169 std::cout << "Attempting system VPD restore" << std::endl; 170 ParserInterface* parser = nullptr; 171 try 172 { 173 auto vpdVector = getVpdDataInVector(jsonFile, systemVpdFilePath); 174 uint32_t vpdStartOffset = 0; 175 const auto& inventoryPath = 176 jsonFile["frus"][systemVpdFilePath][0]["inventoryPath"] 177 .get_ref<const nlohmann::json::string_t&>(); 178 179 parser = ParserFactory::getParser(vpdVector, (pimPath + inventoryPath), 180 systemVpdFilePath, vpdStartOffset); 181 auto parseResult = parser->parse(); 182 183 if (auto pVal = std::get_if<Store>(&parseResult)) 184 { 185 // map to hold all the keywords whose value is blank and 186 // needs to be updated at standby. 187 std::vector<RestoredEeproms> blankSystemVpdProperties{}; 188 getListOfBlankSystemVpd(pVal->getVpdMap(), SYSTEM_OBJECT, 189 blankSystemVpdProperties); 190 191 // if system VPD restore is required, update the 192 // EEPROM 193 for (const auto& item : blankSystemVpdProperties) 194 { 195 std::cout << "Restoring keyword: " << std::get<2>(item) 196 << std::endl; 197 writeKeyword(std::get<0>(item), std::get<1>(item), 198 std::get<2>(item), std::get<3>(item)); 199 } 200 } 201 else 202 { 203 std::cerr << "Not a valid format to restore system VPD" 204 << std::endl; 205 } 206 } 207 catch (const std::exception& e) 208 { 209 std::cerr << "Failed to restore system VPD due to exception: " 210 << e.what() << std::endl; 211 } 212 // release the parser object 213 ParserFactory::freeParser(parser); 214 } 215 216 void Manager::listenHostState() 217 { 218 static std::shared_ptr<sdbusplus::bus::match_t> hostState = 219 std::make_shared<sdbusplus::bus::match_t>( 220 *conn, 221 sdbusplus::bus::match::rules::propertiesChanged( 222 "/xyz/openbmc_project/state/host0", 223 "xyz.openbmc_project.State.Host"), 224 [this](sdbusplus::message_t& msg) { hostStateCallBack(msg); }); 225 } 226 227 void Manager::checkEssentialFrus() 228 { 229 for (const auto& invPath : essentialFrus) 230 { 231 const auto res = readBusProperty(invPath, invItemIntf, "Present"); 232 233 // implies the essential FRU is missing. Log PEL. 234 if (res == "false") 235 { 236 auto rc = sd_bus_call_method_async( 237 sdBus, NULL, loggerService, loggerObjectPath, 238 loggerCreateInterface, "Create", NULL, NULL, "ssa{ss}", 239 errIntfForEssentialFru, 240 "xyz.openbmc_project.Logging.Entry.Level.Warning", 2, 241 "DESCRIPTION", "Essential fru missing from the system.", 242 "CALLOUT_INVENTORY_PATH", (pimPath + invPath).c_str()); 243 244 if (rc < 0) 245 { 246 log<level::ERR>("Error calling sd_bus_call_method_async", 247 entry("RC=%d", rc), 248 entry("MSG=%s", strerror(-rc))); 249 } 250 } 251 } 252 } 253 254 void Manager::hostStateCallBack(sdbusplus::message_t& msg) 255 { 256 if (msg.is_method_error()) 257 { 258 std::cerr << "Error in reading signal " << std::endl; 259 } 260 261 Path object; 262 PropertyMap propMap; 263 msg.read(object, propMap); 264 const auto itr = propMap.find("CurrentHostState"); 265 if (itr != propMap.end()) 266 { 267 if (auto hostState = std::get_if<std::string>(&(itr->second))) 268 { 269 // implies system is moving from standby to power on state 270 if (*hostState == "xyz.openbmc_project.State.Host.HostState." 271 "TransitioningToRunning") 272 { 273 // detect if essential frus are present in the system. 274 checkEssentialFrus(); 275 276 // check and perfrom recollection for FRUs replaceable at 277 // standby. 278 performVPDRecollection(); 279 return; 280 } 281 } 282 } 283 } 284 285 void Manager::listenAssetTag() 286 { 287 static std::shared_ptr<sdbusplus::bus::match_t> assetMatcher = 288 std::make_shared<sdbusplus::bus::match_t>( 289 *conn, 290 sdbusplus::bus::match::rules::propertiesChanged( 291 "/xyz/openbmc_project/inventory/system", 292 "xyz.openbmc_project.Inventory.Decorator.AssetTag"), 293 [this](sdbusplus::message_t& msg) { assetTagCallback(msg); }); 294 } 295 296 void Manager::assetTagCallback(sdbusplus::message_t& msg) 297 { 298 if (msg.is_method_error()) 299 { 300 std::cerr << "Error in reading signal " << std::endl; 301 } 302 303 Path object; 304 PropertyMap propMap; 305 msg.read(object, propMap); 306 const auto itr = propMap.find("AssetTag"); 307 if (itr != propMap.end()) 308 { 309 if (auto assetTag = std::get_if<std::string>(&(itr->second))) 310 { 311 // Call Notify to persist the AssetTag 312 inventory::ObjectMap objectMap = { 313 {std::string{"/system"}, 314 {{"xyz.openbmc_project.Inventory.Decorator.AssetTag", 315 {{"AssetTag", *assetTag}}}}}}; 316 317 common::utility::callPIM(std::move(objectMap)); 318 } 319 else 320 { 321 std::cerr << "Failed to read asset tag" << std::endl; 322 } 323 } 324 } 325 326 void Manager::processJSON() 327 { 328 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary); 329 330 if (!json) 331 { 332 throw std::runtime_error("json file not found"); 333 } 334 335 jsonFile = nlohmann::json::parse(json); 336 if (jsonFile.find("frus") == jsonFile.end()) 337 { 338 throw std::runtime_error("frus group not found in json"); 339 } 340 341 const nlohmann::json& groupFRUS = 342 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>(); 343 for (const auto& itemFRUS : groupFRUS.items()) 344 { 345 const std::vector<nlohmann::json>& groupEEPROM = 346 itemFRUS.value().get_ref<const nlohmann::json::array_t&>(); 347 for (const auto& itemEEPROM : groupEEPROM) 348 { 349 bool isMotherboard = false; 350 std::string redundantPath; 351 352 if (itemEEPROM["extraInterfaces"].find( 353 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") != 354 itemEEPROM["extraInterfaces"].end()) 355 { 356 isMotherboard = true; 357 } 358 if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end()) 359 { 360 redundantPath = itemEEPROM["redundantEeprom"] 361 .get_ref<const nlohmann::json::string_t&>(); 362 } 363 frus.emplace( 364 itemEEPROM["inventoryPath"] 365 .get_ref<const nlohmann::json::string_t&>(), 366 std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard)); 367 368 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) != 369 itemEEPROM["extraInterfaces"].end()) 370 { 371 fruLocationCode.emplace( 372 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF] 373 ["LocationCode"] 374 .get_ref<const nlohmann::json::string_t&>(), 375 itemEEPROM["inventoryPath"] 376 .get_ref<const nlohmann::json::string_t&>()); 377 } 378 379 if (itemEEPROM.value("replaceableAtStandby", false)) 380 { 381 replaceableFrus.emplace_back(itemFRUS.key()); 382 } 383 384 if (itemEEPROM.value("essentialFru", false)) 385 { 386 essentialFrus.emplace_back(itemEEPROM["inventoryPath"]); 387 } 388 } 389 } 390 } 391 392 void Manager::updateSystemVPDBackUpFRU(const std::string& recordName, 393 const std::string& keyword, 394 const Binary& value) 395 { 396 const std::string& systemVpdBackupPath = 397 jsonFile["frus"][systemVpdFilePath].at(0).value("systemVpdBackupPath", 398 ""); 399 400 if (!systemVpdBackupPath.empty() && 401 jsonFile["frus"][systemVpdBackupPath].at(0).contains("inventoryPath")) 402 { 403 std::string systemVpdBackupInvPath = 404 jsonFile["frus"][systemVpdBackupPath][0]["inventoryPath"] 405 .get_ref<const nlohmann::json::string_t&>(); 406 407 const auto& itr = svpdKwdMap.find(recordName); 408 if (itr != svpdKwdMap.end()) 409 { 410 auto systemKwdInfoList = itr->second; 411 const auto& itrToKwd = find_if(systemKwdInfoList.begin(), 412 systemKwdInfoList.end(), 413 [&keyword](const auto& kwdInfo) { 414 return (keyword == std::get<0>(kwdInfo)); 415 }); 416 417 if (itrToKwd != systemKwdInfoList.end()) 418 { 419 EditorImpl edit(systemVpdBackupPath, jsonFile, 420 std::get<4>(*itrToKwd), std::get<5>(*itrToKwd), 421 systemVpdBackupInvPath); 422 423 // Setup offset, if any 424 uint32_t offset = 0; 425 if (jsonFile["frus"][systemVpdBackupPath].at(0).contains( 426 "offset")) 427 { 428 offset = 429 jsonFile["frus"][systemVpdBackupPath].at(0).contains( 430 "offset"); 431 } 432 433 edit.updateKeyword(value, offset, true); 434 } 435 } 436 } 437 else 438 { 439 if (systemVpdBackupPath.empty()) 440 { 441 throw std::runtime_error( 442 "Invalid entry for systemVpdBackupPath in JSON"); 443 } 444 else 445 { 446 throw std::runtime_error( 447 "Inventory path missing for systemVpdBackupPath"); 448 } 449 } 450 } 451 452 void Manager::writeKeyword(const sdbusplus::message::object_path& path, 453 const std::string& recordName, 454 const std::string& keyword, const Binary& value) 455 { 456 try 457 { 458 std::string objPath{path}; 459 // Strip any inventory prefix in path 460 if (objPath.find(INVENTORY_PATH) == 0) 461 { 462 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1); 463 } 464 465 if (frus.find(objPath) == frus.end()) 466 { 467 throw std::runtime_error("Inventory path not found"); 468 } 469 470 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second); 471 472 // instantiate editor class to update the data 473 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath); 474 475 uint32_t offset = 0; 476 // Setup offset, if any 477 for (const auto& item : jsonFile["frus"][vpdFilePath]) 478 { 479 if (item.find("offset") != item.end()) 480 { 481 offset = item["offset"]; 482 break; 483 } 484 } 485 486 edit.updateKeyword(value, offset, true); 487 488 // If system VPD is being updated and system VPD is marked for back up 489 // on another FRU, update data on back up as well. 490 if (objPath == sdbusplus::message::object_path{SYSTEM_OBJECT} && 491 jsonFile["frus"][systemVpdFilePath].at(0).contains( 492 "systemVpdBackupPath")) 493 { 494 updateSystemVPDBackUpFRU(recordName, keyword, value); 495 } 496 497 // If we have a redundant EEPROM to update, then update just the EEPROM, 498 // not the cache since that is already done when we updated the primary 499 if (!std::get<1>(frus.find(objPath)->second).empty()) 500 { 501 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile, 502 recordName, keyword, objPath); 503 edit.updateKeyword(value, offset, false); 504 } 505 506 // if it is a motehrboard FRU need to check for location expansion 507 if (std::get<2>(frus.find(objPath)->second)) 508 { 509 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE")) 510 { 511 edit.expandLocationCode("fcs"); 512 } 513 else if (recordName == "VSYS" && 514 (keyword == "TM" || keyword == "SE")) 515 { 516 edit.expandLocationCode("mts"); 517 } 518 } 519 520 return; 521 } 522 catch (const std::exception& e) 523 { 524 std::cerr << e.what() << std::endl; 525 } 526 } 527 528 ListOfPaths 529 Manager::getFRUsByUnexpandedLocationCode(const LocationCode& locationCode, 530 const NodeNumber nodeNumber) 531 { 532 ReaderImpl read; 533 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode); 534 } 535 536 ListOfPaths 537 Manager::getFRUsByExpandedLocationCode(const LocationCode& locationCode) 538 { 539 ReaderImpl read; 540 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode); 541 } 542 543 LocationCode Manager::getExpandedLocationCode(const LocationCode& locationCode, 544 const NodeNumber nodeNumber) 545 { 546 ReaderImpl read; 547 return read.getExpandedLocationCode(locationCode, nodeNumber, 548 fruLocationCode); 549 } 550 551 void Manager::performVPDRecollection() 552 { 553 // get list of FRUs replaceable at standby 554 for (const auto& item : replaceableFrus) 555 { 556 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item]; 557 const nlohmann::json& singleFru = groupEEPROM[0]; 558 559 const string& inventoryPath = 560 singleFru["inventoryPath"] 561 .get_ref<const nlohmann::json::string_t&>(); 562 563 bool prePostActionRequired = false; 564 565 if ((jsonFile["frus"][item].at(0)).find("preAction") != 566 jsonFile["frus"][item].at(0).end()) 567 { 568 try 569 { 570 if (!executePreAction(jsonFile, item)) 571 { 572 // if the FRU has preAction defined then its execution 573 // should pass to ensure bind/unbind of data. 574 // preAction execution failed. should not call 575 // bind/unbind. 576 log<level::ERR>( 577 "Pre-Action execution failed for the FRU", 578 entry("ERROR=%s", 579 ("Inventory path: " + inventoryPath).c_str())); 580 continue; 581 } 582 } 583 catch (const GpioException& e) 584 { 585 log<level::ERR>(e.what()); 586 PelAdditionalData additionalData{}; 587 additionalData.emplace("DESCRIPTION", e.what()); 588 createPEL(additionalData, PelSeverity::WARNING, 589 errIntfForGpioError, sdBus); 590 continue; 591 } 592 prePostActionRequired = true; 593 } 594 595 // unbind, bind the driver to trigger parser. 596 triggerVpdCollection(singleFru, inventoryPath); 597 598 // this check is added to avoid file system expensive call in case not 599 // required. 600 if (prePostActionRequired) 601 { 602 // The sleep of 1sec is sliced up in 10 retries of 10 miliseconds 603 // each. 604 for (auto retryCounter = VALUE_0; retryCounter <= VALUE_10; 605 retryCounter++) 606 { 607 // sleep for 10 milisecond 608 if (usleep(VALUE_100000) != VALUE_0) 609 { 610 std::cout << "Sleep failed before accessing the file" 611 << std::endl; 612 } 613 614 // Check if file showed up 615 if (!filesystem::exists(item)) 616 { 617 // Do we need to retry? 618 if (retryCounter < VALUE_10) 619 { 620 continue; 621 } 622 623 try 624 { 625 // If not, then take failure postAction 626 executePostFailAction(jsonFile, item); 627 } 628 catch (const GpioException& e) 629 { 630 PelAdditionalData additionalData{}; 631 additionalData.emplace("DESCRIPTION", e.what()); 632 createPEL(additionalData, PelSeverity::WARNING, 633 errIntfForGpioError, sdBus); 634 } 635 } 636 else 637 { 638 // bind the LED driver 639 string chipAddr = singleFru.value("pcaChipAddress", ""); 640 cout 641 << "performVPDRecollection: Executing driver binding for " 642 "chip " 643 "address - " 644 << chipAddr << endl; 645 646 executeCmd(createBindUnbindDriverCmnd( 647 chipAddr, "i2c", "leds-pca955x", "/bind")); 648 649 // File has been found, kill the retry loop. 650 break; 651 } 652 } 653 } 654 } 655 } 656 657 void Manager::collectFRUVPD(const sdbusplus::message::object_path& path) 658 { 659 std::cout << "Manager called to collect vpd for fru: " << std::string{path} 660 << std::endl; 661 662 using InvalidArgument = 663 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; 664 using Argument = xyz::openbmc_project::Common::InvalidArgument; 665 666 std::string objPath{path}; 667 668 // Strip any inventory prefix in path 669 if (objPath.find(INVENTORY_PATH) == 0) 670 { 671 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1); 672 } 673 674 // if path not found in Json. 675 if (frus.find(objPath) == frus.end()) 676 { 677 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"), 678 Argument::ARGUMENT_VALUE(objPath.c_str())); 679 } 680 681 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second); 682 683 const std::vector<nlohmann::json>& groupEEPROM = 684 jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>(); 685 686 nlohmann::json singleFru{}; 687 for (const auto& item : groupEEPROM) 688 { 689 if (item["inventoryPath"] == objPath) 690 { 691 // this is the inventory we are looking for 692 singleFru = item; 693 break; 694 } 695 } 696 697 // check if the device qualifies for CM. 698 if (singleFru.value("concurrentlyMaintainable", false)) 699 { 700 bool prePostActionRequired = false; 701 702 if ((jsonFile["frus"][vpdFilePath].at(0)).find("preAction") != 703 jsonFile["frus"][vpdFilePath].at(0).end()) 704 { 705 if (!executePreAction(jsonFile, vpdFilePath)) 706 { 707 // if the FRU has preAction defined then its execution should 708 // pass to ensure bind/unbind of data. 709 // preAction execution failed. should not call bind/unbind. 710 log<level::ERR>("Pre-Action execution failed for the FRU"); 711 return; 712 } 713 714 prePostActionRequired = true; 715 } 716 717 // unbind, bind the driver to trigger parser. 718 triggerVpdCollection(singleFru, objPath); 719 720 // this check is added to avoid file system expensive call in case not 721 // required. 722 if (prePostActionRequired) 723 { 724 // Check if device showed up (test for file) 725 if (!filesystem::exists(vpdFilePath)) 726 { 727 try 728 { 729 // If not, then take failure postAction 730 executePostFailAction(jsonFile, vpdFilePath); 731 } 732 catch (const GpioException& e) 733 { 734 PelAdditionalData additionalData{}; 735 additionalData.emplace("DESCRIPTION", e.what()); 736 createPEL(additionalData, PelSeverity::WARNING, 737 errIntfForGpioError, sdBus); 738 } 739 } 740 else 741 { 742 // bind the LED driver 743 string chipAddr = jsonFile["frus"][vpdFilePath].at(0).value( 744 "pcaChipAddress", ""); 745 cout << "Executing driver binding for chip address - " 746 << chipAddr << endl; 747 748 executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c", 749 "leds-pca955x", "/bind")); 750 } 751 } 752 return; 753 } 754 else 755 { 756 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"), 757 Argument::ARGUMENT_VALUE(objPath.c_str())); 758 } 759 } 760 761 void Manager::triggerVpdCollection(const nlohmann::json& singleFru, 762 const std::string& path) 763 { 764 if ((singleFru.find("devAddress") == singleFru.end()) || 765 (singleFru.find("driverType") == singleFru.end()) || 766 (singleFru.find("busType") == singleFru.end())) 767 { 768 // The FRUs is marked for collection but missing mandatory 769 // fields for collection. Log error and return. 770 log<level::ERR>( 771 "Collection Failed as mandatory field missing in Json", 772 entry("ERROR=%s", ("Recollection failed for " + (path)).c_str())); 773 774 return; 775 } 776 777 string deviceAddress = singleFru["devAddress"]; 778 const string& driverType = singleFru["driverType"]; 779 const string& busType = singleFru["busType"]; 780 781 // devTreeStatus flag is present in json as false to mention 782 // that the EEPROM is not mentioned in device tree. If this flag 783 // is absent consider the value to be true, i.e EEPROM is 784 // mentioned in device tree 785 if (!singleFru.value("devTreeStatus", true)) 786 { 787 auto pos = deviceAddress.find('-'); 788 if (pos != string::npos) 789 { 790 string busNum = deviceAddress.substr(0, pos); 791 deviceAddress = "0x" + deviceAddress.substr(pos + 1, string::npos); 792 793 string deleteDevice = "echo" + deviceAddress + " > /sys/bus/" + 794 busType + "/devices/" + busType + "-" + 795 busNum + "/delete_device"; 796 executeCmd(deleteDevice); 797 798 string addDevice = "echo" + driverType + " " + deviceAddress + 799 " > /sys/bus/" + busType + "/devices/" + 800 busType + "-" + busNum + "/new_device"; 801 executeCmd(addDevice); 802 } 803 else 804 { 805 const string& inventoryPath = 806 singleFru["inventoryPath"] 807 .get_ref<const nlohmann::json::string_t&>(); 808 809 log<level::ERR>( 810 "Wrong format of device address in Json", 811 entry("ERROR=%s", 812 ("Recollection failed for " + inventoryPath).c_str())); 813 } 814 } 815 else 816 { 817 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType, 818 driverType, "/unbind")); 819 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType, 820 driverType, "/bind")); 821 } 822 } 823 824 void Manager::deleteFRUVPD(const sdbusplus::message::object_path& path) 825 { 826 std::cout << "Manager called to delete vpd for fru: " << std::string{path} 827 << std::endl; 828 829 using InvalidArgument = 830 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; 831 using Argument = xyz::openbmc_project::Common::InvalidArgument; 832 833 std::string objPath{path}; 834 835 // Strip any inventory prefix in path 836 if (objPath.find(INVENTORY_PATH) == 0) 837 { 838 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1); 839 } 840 841 // if path not found in Json. 842 if (frus.find(objPath) == frus.end()) 843 { 844 elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"), 845 Argument::ARGUMENT_VALUE(objPath.c_str())); 846 } 847 848 inventory::Path& vpdFilePath = std::get<0>(frus.find(objPath)->second); 849 850 string chipAddress = 851 jsonFile["frus"][vpdFilePath].at(0).value("pcaChipAddress", ""); 852 853 // Unbind the LED driver for this FRU 854 cout << "Unbinding device- " << chipAddress << endl; 855 executeCmd(createBindUnbindDriverCmnd(chipAddress, "i2c", "leds-pca955x", 856 "/unbind")); 857 858 // if the FRU is not present then log error 859 if (readBusProperty(objPath, "xyz.openbmc_project.Inventory.Item", 860 "Present") == "false") 861 { 862 elog<InvalidArgument>(Argument::ARGUMENT_NAME("FRU not preset"), 863 Argument::ARGUMENT_VALUE(objPath.c_str())); 864 } 865 else 866 { 867 inventory::InterfaceMap interfacesPropMap; 868 clearVpdOnRemoval(INVENTORY_PATH + objPath, interfacesPropMap); 869 870 inventory::ObjectMap objectMap; 871 objectMap.emplace(objPath, move(interfacesPropMap)); 872 873 common::utility::callPIM(move(objectMap)); 874 } 875 } 876 877 } // namespace manager 878 } // namespace vpd 879 } // namespace openpower 880