| #include "config.h" |
| |
| #include "manager.hpp" |
| |
| #include "common_utility.hpp" |
| #include "editor_impl.hpp" |
| #include "ibm_vpd_utils.hpp" |
| #include "ipz_parser.hpp" |
| #include "parser_factory.hpp" |
| #include "reader_impl.hpp" |
| #include "vpd_exceptions.hpp" |
| |
| #include <filesystem> |
| #include <phosphor-logging/elog-errors.hpp> |
| #include <xyz/openbmc_project/Common/error.hpp> |
| |
| using namespace openpower::vpd::constants; |
| using namespace openpower::vpd::inventory; |
| using namespace openpower::vpd::manager::editor; |
| using namespace openpower::vpd::manager::reader; |
| using namespace std; |
| using namespace openpower::vpd::parser; |
| using namespace openpower::vpd::parser::factory; |
| using namespace openpower::vpd::ipz::parser; |
| using namespace openpower::vpd::exceptions; |
| using namespace phosphor::logging; |
| |
| namespace openpower |
| { |
| namespace vpd |
| { |
| namespace manager |
| { |
| Manager::Manager(std::shared_ptr<boost::asio::io_context>& ioCon, |
| std::shared_ptr<sdbusplus::asio::dbus_interface>& iFace, |
| std::shared_ptr<sdbusplus::asio::connection>& conn) : |
| ioContext(ioCon), |
| interface(iFace), conn(conn) |
| { |
| interface->register_method( |
| "WriteKeyword", |
| [this](const sdbusplus::message::object_path& path, |
| const std::string& recordName, const std::string& keyword, |
| const Binary& value) { |
| this->writeKeyword(path, recordName, keyword, value); |
| }); |
| |
| interface->register_method( |
| "GetFRUsByUnexpandedLocationCode", |
| [this](const std::string& locationCode, |
| const uint16_t nodeNumber) -> inventory::ListOfPaths { |
| return this->getFRUsByUnexpandedLocationCode(locationCode, |
| nodeNumber); |
| }); |
| |
| interface->register_method( |
| "GetFRUsByExpandedLocationCode", |
| [this](const std::string& locationCode) -> inventory::ListOfPaths { |
| return this->getFRUsByExpandedLocationCode(locationCode); |
| }); |
| |
| interface->register_method( |
| "GetExpandedLocationCode", |
| [this](const std::string& locationCode, |
| const uint16_t nodeNumber) -> std::string { |
| return this->getExpandedLocationCode(locationCode, nodeNumber); |
| }); |
| |
| interface->register_method("PerformVPDRecollection", |
| [this]() { this->performVPDRecollection(); }); |
| |
| interface->register_method( |
| "deleteFRUVPD", [this](const sdbusplus::message::object_path& path) { |
| this->deleteFRUVPD(path); |
| }); |
| |
| interface->register_method( |
| "CollectFRUVPD", [this](const sdbusplus::message::object_path& path) { |
| this->collectFRUVPD(path); |
| }); |
| |
| sd_bus_default(&sdBus); |
| initManager(); |
| } |
| |
| void Manager::initManager() |
| { |
| try |
| { |
| processJSON(); |
| restoreSystemVpd(); |
| listenHostState(); |
| listenAssetTag(); |
| |
| // Create an instance of the BIOS handler |
| biosHandler = std::make_shared<BiosHandler>(conn, *this); |
| |
| // instantiate gpioMonitor class |
| gpioMon = std::make_shared<GpioMonitor>(jsonFile, ioContext); |
| } |
| catch (const std::exception& e) |
| { |
| std::cerr << e.what() << "\n"; |
| } |
| } |
| |
| /** |
| * @brief An api to get list of blank system VPD properties. |
| * @param[in] vpdMap - IPZ vpd map. |
| * @param[in] objectPath - Object path for the FRU. |
| * @param[out] blankPropertyList - Properties which are blank in System VPD and |
| * needs to be updated as standby. |
| */ |
| static void |
| getListOfBlankSystemVpd(Parsed& vpdMap, const string& objectPath, |
| std::vector<RestoredEeproms>& blankPropertyList) |
| { |
| for (const auto& systemRecKwdPair : svpdKwdMap) |
| { |
| auto it = vpdMap.find(systemRecKwdPair.first); |
| |
| // check if record is found in map we got by parser |
| if (it != vpdMap.end()) |
| { |
| const auto& kwdListForRecord = systemRecKwdPair.second; |
| for (const auto& keywordInfo : kwdListForRecord) |
| { |
| const auto& keyword = get<0>(keywordInfo); |
| |
| DbusPropertyMap& kwdValMap = it->second; |
| auto iterator = kwdValMap.find(keyword); |
| |
| if (iterator != kwdValMap.end()) |
| { |
| string& kwdValue = iterator->second; |
| |
| // check bus data |
| const string& recordName = systemRecKwdPair.first; |
| const string& busValue = readBusProperty( |
| objectPath, ipzVpdInf + recordName, keyword); |
| |
| const auto& defaultValue = get<1>(keywordInfo); |
| |
| if (Binary(busValue.begin(), busValue.end()) != |
| defaultValue) |
| { |
| if (Binary(kwdValue.begin(), kwdValue.end()) == |
| defaultValue) |
| { |
| // implies data is blank on EEPROM but not on cache. |
| // So EEPROM vpd update is required. |
| Binary busData(busValue.begin(), busValue.end()); |
| |
| blankPropertyList.push_back(std::make_tuple( |
| objectPath, recordName, keyword, busData)); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| void Manager::restoreSystemVpd() |
| { |
| std::cout << "Attempting system VPD restore" << std::endl; |
| ParserInterface* parser = nullptr; |
| try |
| { |
| auto vpdVector = getVpdDataInVector(jsonFile, systemVpdFilePath); |
| const auto& inventoryPath = |
| jsonFile["frus"][systemVpdFilePath][0]["inventoryPath"] |
| .get_ref<const nlohmann::json::string_t&>(); |
| |
| parser = ParserFactory::getParser(vpdVector, (pimPath + inventoryPath)); |
| auto parseResult = parser->parse(); |
| |
| if (auto pVal = std::get_if<Store>(&parseResult)) |
| { |
| // map to hold all the keywords whose value is blank and |
| // needs to be updated at standby. |
| std::vector<RestoredEeproms> blankSystemVpdProperties{}; |
| getListOfBlankSystemVpd(pVal->getVpdMap(), SYSTEM_OBJECT, |
| blankSystemVpdProperties); |
| |
| // if system VPD restore is required, update the |
| // EEPROM |
| for (const auto& item : blankSystemVpdProperties) |
| { |
| std::cout << "Restoring keyword: " << std::get<2>(item) |
| << std::endl; |
| writeKeyword(std::get<0>(item), std::get<1>(item), |
| std::get<2>(item), std::get<3>(item)); |
| } |
| } |
| else |
| { |
| std::cerr << "Not a valid format to restore system VPD" |
| << std::endl; |
| } |
| } |
| catch (const std::exception& e) |
| { |
| std::cerr << "Failed to restore system VPD due to exception: " |
| << e.what() << std::endl; |
| } |
| // release the parser object |
| ParserFactory::freeParser(parser); |
| } |
| |
| void Manager::listenHostState() |
| { |
| static std::shared_ptr<sdbusplus::bus::match_t> hostState = |
| std::make_shared<sdbusplus::bus::match_t>( |
| *conn, |
| sdbusplus::bus::match::rules::propertiesChanged( |
| "/xyz/openbmc_project/state/host0", |
| "xyz.openbmc_project.State.Host"), |
| [this](sdbusplus::message_t& msg) { hostStateCallBack(msg); }); |
| } |
| |
| void Manager::checkEssentialFrus() |
| { |
| for (const auto& invPath : essentialFrus) |
| { |
| const auto res = readBusProperty(invPath, invItemIntf, "Present"); |
| |
| // implies the essential FRU is missing. Log PEL. |
| if (res == "false") |
| { |
| auto rc = sd_bus_call_method_async( |
| sdBus, NULL, loggerService, loggerObjectPath, |
| loggerCreateInterface, "Create", NULL, NULL, "ssa{ss}", |
| errIntfForEssentialFru, |
| "xyz.openbmc_project.Logging.Entry.Level.Warning", 2, |
| "DESCRIPTION", "Essential fru missing from the system.", |
| "CALLOUT_INVENTORY_PATH", (pimPath + invPath).c_str()); |
| |
| if (rc < 0) |
| { |
| log<level::ERR>("Error calling sd_bus_call_method_async", |
| entry("RC=%d", rc), |
| entry("MSG=%s", strerror(-rc))); |
| } |
| } |
| } |
| } |
| |
| void Manager::hostStateCallBack(sdbusplus::message_t& msg) |
| { |
| if (msg.is_method_error()) |
| { |
| std::cerr << "Error in reading signal " << std::endl; |
| } |
| |
| Path object; |
| PropertyMap propMap; |
| msg.read(object, propMap); |
| const auto itr = propMap.find("CurrentHostState"); |
| if (itr != propMap.end()) |
| { |
| if (auto hostState = std::get_if<std::string>(&(itr->second))) |
| { |
| // implies system is moving from standby to power on state |
| if (*hostState == "xyz.openbmc_project.State.Host.HostState." |
| "TransitioningToRunning") |
| { |
| // detect if essential frus are present in the system. |
| checkEssentialFrus(); |
| |
| // check and perfrom recollection for FRUs replaceable at |
| // standby. |
| performVPDRecollection(); |
| return; |
| } |
| } |
| } |
| } |
| |
| void Manager::listenAssetTag() |
| { |
| static std::shared_ptr<sdbusplus::bus::match_t> assetMatcher = |
| std::make_shared<sdbusplus::bus::match_t>( |
| *conn, |
| sdbusplus::bus::match::rules::propertiesChanged( |
| "/xyz/openbmc_project/inventory/system", |
| "xyz.openbmc_project.Inventory.Decorator.AssetTag"), |
| [this](sdbusplus::message_t& msg) { assetTagCallback(msg); }); |
| } |
| |
| void Manager::assetTagCallback(sdbusplus::message_t& msg) |
| { |
| if (msg.is_method_error()) |
| { |
| std::cerr << "Error in reading signal " << std::endl; |
| } |
| |
| Path object; |
| PropertyMap propMap; |
| msg.read(object, propMap); |
| const auto itr = propMap.find("AssetTag"); |
| if (itr != propMap.end()) |
| { |
| if (auto assetTag = std::get_if<std::string>(&(itr->second))) |
| { |
| // Call Notify to persist the AssetTag |
| inventory::ObjectMap objectMap = { |
| {std::string{"/system"}, |
| {{"xyz.openbmc_project.Inventory.Decorator.AssetTag", |
| {{"AssetTag", *assetTag}}}}}}; |
| |
| common::utility::callPIM(std::move(objectMap)); |
| } |
| else |
| { |
| std::cerr << "Failed to read asset tag" << std::endl; |
| } |
| } |
| } |
| |
| void Manager::processJSON() |
| { |
| std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary); |
| |
| if (!json) |
| { |
| throw std::runtime_error("json file not found"); |
| } |
| |
| jsonFile = nlohmann::json::parse(json); |
| if (jsonFile.find("frus") == jsonFile.end()) |
| { |
| throw std::runtime_error("frus group not found in json"); |
| } |
| |
| const nlohmann::json& groupFRUS = |
| jsonFile["frus"].get_ref<const nlohmann::json::object_t&>(); |
| for (const auto& itemFRUS : groupFRUS.items()) |
| { |
| const std::vector<nlohmann::json>& groupEEPROM = |
| itemFRUS.value().get_ref<const nlohmann::json::array_t&>(); |
| for (const auto& itemEEPROM : groupEEPROM) |
| { |
| bool isMotherboard = false; |
| std::string redundantPath; |
| |
| if (itemEEPROM["extraInterfaces"].find( |
| "xyz.openbmc_project.Inventory.Item.Board.Motherboard") != |
| itemEEPROM["extraInterfaces"].end()) |
| { |
| isMotherboard = true; |
| } |
| if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end()) |
| { |
| redundantPath = itemEEPROM["redundantEeprom"] |
| .get_ref<const nlohmann::json::string_t&>(); |
| } |
| frus.emplace( |
| itemEEPROM["inventoryPath"] |
| .get_ref<const nlohmann::json::string_t&>(), |
| std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard)); |
| |
| if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) != |
| itemEEPROM["extraInterfaces"].end()) |
| { |
| fruLocationCode.emplace( |
| itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF] |
| ["LocationCode"] |
| .get_ref<const nlohmann::json::string_t&>(), |
| itemEEPROM["inventoryPath"] |
| .get_ref<const nlohmann::json::string_t&>()); |
| } |
| |
| if (itemEEPROM.value("replaceableAtStandby", false)) |
| { |
| replaceableFrus.emplace_back(itemFRUS.key()); |
| } |
| |
| if (itemEEPROM.value("essentialFru", false)) |
| { |
| essentialFrus.emplace_back(itemEEPROM["inventoryPath"]); |
| } |
| } |
| } |
| } |
| |
| void Manager::writeKeyword(const sdbusplus::message::object_path& path, |
| const std::string& recordName, |
| const std::string& keyword, const Binary& value) |
| { |
| try |
| { |
| std::string objPath{path}; |
| // Strip any inventory prefix in path |
| if (objPath.find(INVENTORY_PATH) == 0) |
| { |
| objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1); |
| } |
| |
| if (frus.find(objPath) == frus.end()) |
| { |
| throw std::runtime_error("Inventory path not found"); |
| } |
| |
| inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second); |
| |
| // instantiate editor class to update the data |
| EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath); |
| |
| uint32_t offset = 0; |
| // Setup offset, if any |
| for (const auto& item : jsonFile["frus"][vpdFilePath]) |
| { |
| if (item.find("offset") != item.end()) |
| { |
| offset = item["offset"]; |
| break; |
| } |
| } |
| |
| edit.updateKeyword(value, offset, true); |
| |
| // If we have a redundant EEPROM to update, then update just the EEPROM, |
| // not the cache since that is already done when we updated the primary |
| if (!std::get<1>(frus.find(objPath)->second).empty()) |
| { |
| EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile, |
| recordName, keyword, objPath); |
| edit.updateKeyword(value, offset, false); |
| } |
| |
| // if it is a motehrboard FRU need to check for location expansion |
| if (std::get<2>(frus.find(objPath)->second)) |
| { |
| if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE")) |
| { |
| edit.expandLocationCode("fcs"); |
| } |
| else if (recordName == "VSYS" && |
| (keyword == "TM" || keyword == "SE")) |
| { |
| edit.expandLocationCode("mts"); |
| } |
| } |
| |
| return; |
| } |
| catch (const std::exception& e) |
| { |
| std::cerr << e.what() << std::endl; |
| } |
| } |
| |
| ListOfPaths |
| Manager::getFRUsByUnexpandedLocationCode(const LocationCode& locationCode, |
| const NodeNumber nodeNumber) |
| { |
| ReaderImpl read; |
| return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode); |
| } |
| |
| ListOfPaths |
| Manager::getFRUsByExpandedLocationCode(const LocationCode& locationCode) |
| { |
| ReaderImpl read; |
| return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode); |
| } |
| |
| LocationCode Manager::getExpandedLocationCode(const LocationCode& locationCode, |
| const NodeNumber nodeNumber) |
| { |
| ReaderImpl read; |
| return read.getExpandedLocationCode(locationCode, nodeNumber, |
| fruLocationCode); |
| } |
| |
| void Manager::performVPDRecollection() |
| { |
| // get list of FRUs replaceable at standby |
| for (const auto& item : replaceableFrus) |
| { |
| const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item]; |
| const nlohmann::json& singleFru = groupEEPROM[0]; |
| |
| const string& inventoryPath = |
| singleFru["inventoryPath"] |
| .get_ref<const nlohmann::json::string_t&>(); |
| |
| bool prePostActionRequired = false; |
| |
| if ((jsonFile["frus"][item].at(0)).find("preAction") != |
| jsonFile["frus"][item].at(0).end()) |
| { |
| try |
| { |
| if (!executePreAction(jsonFile, item)) |
| { |
| // if the FRU has preAction defined then its execution |
| // should pass to ensure bind/unbind of data. |
| // preAction execution failed. should not call |
| // bind/unbind. |
| log<level::ERR>( |
| "Pre-Action execution failed for the FRU", |
| entry("ERROR=%s", |
| ("Inventory path: " + inventoryPath).c_str())); |
| continue; |
| } |
| } |
| catch (const GpioException& e) |
| { |
| log<level::ERR>(e.what()); |
| PelAdditionalData additionalData{}; |
| additionalData.emplace("DESCRIPTION", e.what()); |
| createPEL(additionalData, PelSeverity::WARNING, |
| errIntfForGpioError, sdBus); |
| continue; |
| } |
| prePostActionRequired = true; |
| } |
| |
| // unbind, bind the driver to trigger parser. |
| triggerVpdCollection(singleFru, inventoryPath); |
| |
| // this check is added to avoid file system expensive call in case not |
| // required. |
| if (prePostActionRequired) |
| { |
| // Check if device showed up (test for file) |
| if (!filesystem::exists(item)) |
| { |
| try |
| { |
| // If not, then take failure postAction |
| executePostFailAction(jsonFile, item); |
| } |
| catch (const GpioException& e) |
| { |
| PelAdditionalData additionalData{}; |
| additionalData.emplace("DESCRIPTION", e.what()); |
| createPEL(additionalData, PelSeverity::WARNING, |
| errIntfForGpioError, sdBus); |
| } |
| } |
| else |
| { |
| // bind the LED driver |
| string chipAddr = singleFru.value("pcaChipAddress", ""); |
| cout << "performVPDRecollection: Executing driver binding for " |
| "chip " |
| "address - " |
| << chipAddr << endl; |
| |
| executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c", |
| "leds-pca955x", "/bind")); |
| } |
| } |
| } |
| } |
| |
| void Manager::collectFRUVPD(const sdbusplus::message::object_path& path) |
| { |
| std::cout << "Manager called to collect vpd for fru: " << std::string{path} |
| << std::endl; |
| |
| using InvalidArgument = |
| sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; |
| using Argument = xyz::openbmc_project::Common::InvalidArgument; |
| |
| std::string objPath{path}; |
| |
| // Strip any inventory prefix in path |
| if (objPath.find(INVENTORY_PATH) == 0) |
| { |
| objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1); |
| } |
| |
| // if path not found in Json. |
| if (frus.find(objPath) == frus.end()) |
| { |
| elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"), |
| Argument::ARGUMENT_VALUE(objPath.c_str())); |
| } |
| |
| inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second); |
| |
| const std::vector<nlohmann::json>& groupEEPROM = |
| jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>(); |
| |
| nlohmann::json singleFru{}; |
| for (const auto& item : groupEEPROM) |
| { |
| if (item["inventoryPath"] == objPath) |
| { |
| // this is the inventory we are looking for |
| singleFru = item; |
| break; |
| } |
| } |
| |
| // check if the device qualifies for CM. |
| if (singleFru.value("concurrentlyMaintainable", false)) |
| { |
| bool prePostActionRequired = false; |
| |
| if ((jsonFile["frus"][vpdFilePath].at(0)).find("preAction") != |
| jsonFile["frus"][vpdFilePath].at(0).end()) |
| { |
| if (!executePreAction(jsonFile, vpdFilePath)) |
| { |
| // if the FRU has preAction defined then its execution should |
| // pass to ensure bind/unbind of data. |
| // preAction execution failed. should not call bind/unbind. |
| log<level::ERR>("Pre-Action execution failed for the FRU"); |
| return; |
| } |
| |
| prePostActionRequired = true; |
| } |
| |
| // unbind, bind the driver to trigger parser. |
| triggerVpdCollection(singleFru, objPath); |
| |
| // this check is added to avoid file system expensive call in case not |
| // required. |
| if (prePostActionRequired) |
| { |
| // Check if device showed up (test for file) |
| if (!filesystem::exists(vpdFilePath)) |
| { |
| try |
| { |
| // If not, then take failure postAction |
| executePostFailAction(jsonFile, vpdFilePath); |
| } |
| catch (const GpioException& e) |
| { |
| PelAdditionalData additionalData{}; |
| additionalData.emplace("DESCRIPTION", e.what()); |
| createPEL(additionalData, PelSeverity::WARNING, |
| errIntfForGpioError, sdBus); |
| } |
| } |
| else |
| { |
| // bind the LED driver |
| string chipAddr = jsonFile["frus"][vpdFilePath].at(0).value( |
| "pcaChipAddress", ""); |
| cout << "Executing driver binding for chip address - " |
| << chipAddr << endl; |
| |
| executeCmd(createBindUnbindDriverCmnd(chipAddr, "i2c", |
| "leds-pca955x", "/bind")); |
| } |
| } |
| return; |
| } |
| else |
| { |
| elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"), |
| Argument::ARGUMENT_VALUE(objPath.c_str())); |
| } |
| } |
| |
| void Manager::triggerVpdCollection(const nlohmann::json& singleFru, |
| const std::string& path) |
| { |
| if ((singleFru.find("devAddress") == singleFru.end()) || |
| (singleFru.find("driverType") == singleFru.end()) || |
| (singleFru.find("busType") == singleFru.end())) |
| { |
| // The FRUs is marked for collection but missing mandatory |
| // fields for collection. Log error and return. |
| log<level::ERR>( |
| "Collection Failed as mandatory field missing in Json", |
| entry("ERROR=%s", ("Recollection failed for " + (path)).c_str())); |
| |
| return; |
| } |
| |
| string deviceAddress = singleFru["devAddress"]; |
| const string& driverType = singleFru["driverType"]; |
| const string& busType = singleFru["busType"]; |
| |
| // devTreeStatus flag is present in json as false to mention |
| // that the EEPROM is not mentioned in device tree. If this flag |
| // is absent consider the value to be true, i.e EEPROM is |
| // mentioned in device tree |
| if (!singleFru.value("devTreeStatus", true)) |
| { |
| auto pos = deviceAddress.find('-'); |
| if (pos != string::npos) |
| { |
| string busNum = deviceAddress.substr(0, pos); |
| deviceAddress = "0x" + deviceAddress.substr(pos + 1, string::npos); |
| |
| string deleteDevice = "echo" + deviceAddress + " > /sys/bus/" + |
| busType + "/devices/" + busType + "-" + |
| busNum + "/delete_device"; |
| executeCmd(deleteDevice); |
| |
| string addDevice = "echo" + driverType + " " + deviceAddress + |
| " > /sys/bus/" + busType + "/devices/" + |
| busType + "-" + busNum + "/new_device"; |
| executeCmd(addDevice); |
| } |
| else |
| { |
| const string& inventoryPath = |
| singleFru["inventoryPath"] |
| .get_ref<const nlohmann::json::string_t&>(); |
| |
| log<level::ERR>( |
| "Wrong format of device address in Json", |
| entry("ERROR=%s", |
| ("Recollection failed for " + inventoryPath).c_str())); |
| } |
| } |
| else |
| { |
| executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType, |
| driverType, "/unbind")); |
| executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType, |
| driverType, "/bind")); |
| } |
| } |
| |
| void Manager::deleteFRUVPD(const sdbusplus::message::object_path& path) |
| { |
| std::cout << "Manager called to delete vpd for fru: " << std::string{path} |
| << std::endl; |
| |
| using InvalidArgument = |
| sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; |
| using Argument = xyz::openbmc_project::Common::InvalidArgument; |
| |
| std::string objPath{path}; |
| |
| // Strip any inventory prefix in path |
| if (objPath.find(INVENTORY_PATH) == 0) |
| { |
| objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1); |
| } |
| |
| // if path not found in Json. |
| if (frus.find(objPath) == frus.end()) |
| { |
| elog<InvalidArgument>(Argument::ARGUMENT_NAME("Object Path"), |
| Argument::ARGUMENT_VALUE(objPath.c_str())); |
| } |
| |
| inventory::Path& vpdFilePath = std::get<0>(frus.find(objPath)->second); |
| |
| string chipAddress = |
| jsonFile["frus"][vpdFilePath].at(0).value("pcaChipAddress", ""); |
| |
| // Unbind the LED driver for this FRU |
| cout << "Unbinding device- " << chipAddress << endl; |
| executeCmd(createBindUnbindDriverCmnd(chipAddress, "i2c", "leds-pca955x", |
| "/unbind")); |
| |
| // if the FRU is not present then log error |
| if (readBusProperty(objPath, "xyz.openbmc_project.Inventory.Item", |
| "Present") == "false") |
| { |
| elog<InvalidArgument>(Argument::ARGUMENT_NAME("FRU not preset"), |
| Argument::ARGUMENT_VALUE(objPath.c_str())); |
| } |
| else |
| { |
| // Set present property of FRU as false as it has been removed. |
| // CC data for FRU is also removed as |
| // a) FRU is not there so CC does not make sense. |
| // b) Sensors dependent on Panel uses CC data. |
| inventory::InterfaceMap interfaces{ |
| {"xyz.openbmc_project.Inventory.Item", {{"Present", false}}}, |
| {"com.ibm.ipzvpd.VINI", {{"CC", Binary{}}}}}; |
| |
| inventory::ObjectMap objectMap; |
| objectMap.emplace(objPath, move(interfaces)); |
| |
| common::utility::callPIM(move(objectMap)); |
| } |
| } |
| |
| } // namespace manager |
| } // namespace vpd |
| } // namespace openpower |