| #include "config.h" | 
 |  | 
 | #include "manager.hpp" | 
 |  | 
 | #include "editor_impl.hpp" | 
 | #include "gpioMonitor.hpp" | 
 | #include "ibm_vpd_utils.hpp" | 
 | #include "ipz_parser.hpp" | 
 | #include "reader_impl.hpp" | 
 | #include "vpd_exceptions.hpp" | 
 |  | 
 | #include <phosphor-logging/elog-errors.hpp> | 
 |  | 
 | using namespace openpower::vpd::manager; | 
 | 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::exceptions; | 
 | using namespace phosphor::logging; | 
 |  | 
 | namespace openpower | 
 | { | 
 | namespace vpd | 
 | { | 
 | namespace manager | 
 | { | 
 | Manager::Manager(sdbusplus::bus::bus&& bus, const char* busName, | 
 |                  const char* objPath, const char* /*iFace*/) : | 
 |     ServerObject<ManagerIface>(bus, objPath), | 
 |     _bus(std::move(bus)), _manager(_bus, objPath) | 
 | { | 
 |     _bus.request_name(busName); | 
 | } | 
 |  | 
 | void Manager::run() | 
 | { | 
 |     try | 
 |     { | 
 |         processJSON(); | 
 |  | 
 |         auto event = sdeventplus::Event::get_default(); | 
 |         GpioMonitor gpioMon1(jsonFile, event); | 
 |  | 
 |         _bus.attach_event(event.get(), SD_EVENT_PRIORITY_IMPORTANT); | 
 |         cout << "VPD manager event loop started\n"; | 
 |         event.loop(); | 
 |     } | 
 |     catch (const std::exception& e) | 
 |     { | 
 |         std::cerr << e.what() << "\n"; | 
 |     } | 
 | } | 
 |  | 
 | 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; | 
 |             if (itemEEPROM["extraInterfaces"].find( | 
 |                     "xyz.openbmc_project.Inventory.Item.Board.Motherboard") != | 
 |                 itemEEPROM["extraInterfaces"].end()) | 
 |             { | 
 |                 isMotherboard = true; | 
 |             } | 
 |             frus.emplace(itemEEPROM["inventoryPath"] | 
 |                              .get_ref<const nlohmann::json::string_t&>(), | 
 |                          std::make_pair(itemFRUS.key(), 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("isReplaceable", false)) | 
 |             { | 
 |                 replaceableFrus.emplace_back(itemFRUS.key()); | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | void Manager::writeKeyword(const sdbusplus::message::object_path path, | 
 |                            const std::string recordName, | 
 |                            const std::string keyword, const Binary value) | 
 | { | 
 |     try | 
 |     { | 
 |         if (frus.find(path) == frus.end()) | 
 |         { | 
 |             throw std::runtime_error("Inventory path not found"); | 
 |         } | 
 |  | 
 |         inventory::Path vpdFilePath = frus.find(path)->second.first; | 
 |  | 
 |         // instantiate editor class to update the data | 
 |         EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, path); | 
 |         edit.updateKeyword(value, true); | 
 |  | 
 |         // if it is a motehrboard FRU need to check for location expansion | 
 |         if (frus.find(path)->second.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&>(); | 
 |  | 
 |         if ((singleFru.find("devAddress") == singleFru.end()) || | 
 |             (singleFru.find("driverType") == singleFru.end()) || | 
 |             (singleFru.find("busType") == singleFru.end())) | 
 |         { | 
 |             // The FRUs is marked for replacement but missing mandatory | 
 |             // fields for recollection. Skip to another replaceable fru. | 
 |             log<level::ERR>( | 
 |                 "Recollection Failed as mandatory field missing in Json", | 
 |                 entry("ERROR=%s", | 
 |                       ("Recollection failed for " + inventoryPath).c_str())); | 
 |             continue; | 
 |         } | 
 |  | 
 |         string str = "echo "; | 
 |         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 = str + deviceAddress + " > /sys/bus/" + | 
 |                                       busType + "/devices/" + busType + "-" + | 
 |                                       busNum + "/delete_device"; | 
 |                 executeCmd(deleteDevice); | 
 |  | 
 |                 string addDevice = str + driverType + " " + deviceAddress + | 
 |                                    " > /sys/bus/" + busType + "/devices/" + | 
 |                                    busType + "-" + busNum + "/new_device"; | 
 |                 executeCmd(addDevice); | 
 |             } | 
 |             else | 
 |             { | 
 |                 log<level::ERR>( | 
 |                     "Wrong format of device address in Json", | 
 |                     entry( | 
 |                         "ERROR=%s", | 
 |                         ("Recollection failed for " + inventoryPath).c_str())); | 
 |                 continue; | 
 |             } | 
 |         } | 
 |         else | 
 |         { | 
 |             executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType, | 
 |                                                   driverType, "/unbind")); | 
 |             executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType, | 
 |                                                   driverType, "/bind")); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | } // namespace manager | 
 | } // namespace vpd | 
 | } // namespace openpower |