1 #include "config.h" 2 3 #include "manager.hpp" 4 5 #include "editor_impl.hpp" 6 #include "gpioMonitor.hpp" 7 #include "ibm_vpd_utils.hpp" 8 #include "ipz_parser.hpp" 9 #include "reader_impl.hpp" 10 #include "vpd_exceptions.hpp" 11 12 #include <phosphor-logging/elog-errors.hpp> 13 14 using namespace openpower::vpd::manager; 15 using namespace openpower::vpd::constants; 16 using namespace openpower::vpd::inventory; 17 using namespace openpower::vpd::manager::editor; 18 using namespace openpower::vpd::manager::reader; 19 using namespace std; 20 using namespace openpower::vpd::parser; 21 using namespace openpower::vpd::exceptions; 22 using namespace phosphor::logging; 23 24 namespace openpower 25 { 26 namespace vpd 27 { 28 namespace manager 29 { 30 Manager::Manager(sdbusplus::bus::bus&& bus, const char* busName, 31 const char* objPath, const char* /*iFace*/) : 32 ServerObject<ManagerIface>(bus, objPath), 33 _bus(std::move(bus)), _manager(_bus, objPath) 34 { 35 _bus.request_name(busName); 36 } 37 38 void Manager::run() 39 { 40 try 41 { 42 processJSON(); 43 44 auto event = sdeventplus::Event::get_default(); 45 GpioMonitor gpioMon1(jsonFile, event); 46 47 _bus.attach_event(event.get(), SD_EVENT_PRIORITY_IMPORTANT); 48 cout << "VPD manager event loop started\n"; 49 event.loop(); 50 } 51 catch (const std::exception& e) 52 { 53 std::cerr << e.what() << "\n"; 54 } 55 } 56 57 void Manager::processJSON() 58 { 59 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary); 60 61 if (!json) 62 { 63 throw std::runtime_error("json file not found"); 64 } 65 66 jsonFile = nlohmann::json::parse(json); 67 if (jsonFile.find("frus") == jsonFile.end()) 68 { 69 throw std::runtime_error("frus group not found in json"); 70 } 71 72 const nlohmann::json& groupFRUS = 73 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>(); 74 for (const auto& itemFRUS : groupFRUS.items()) 75 { 76 const std::vector<nlohmann::json>& groupEEPROM = 77 itemFRUS.value().get_ref<const nlohmann::json::array_t&>(); 78 for (const auto& itemEEPROM : groupEEPROM) 79 { 80 bool isMotherboard = false; 81 if (itemEEPROM["extraInterfaces"].find( 82 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") != 83 itemEEPROM["extraInterfaces"].end()) 84 { 85 isMotherboard = true; 86 } 87 frus.emplace(itemEEPROM["inventoryPath"] 88 .get_ref<const nlohmann::json::string_t&>(), 89 std::make_pair(itemFRUS.key(), isMotherboard)); 90 91 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) != 92 itemEEPROM["extraInterfaces"].end()) 93 { 94 fruLocationCode.emplace( 95 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF] 96 ["LocationCode"] 97 .get_ref<const nlohmann::json::string_t&>(), 98 itemEEPROM["inventoryPath"] 99 .get_ref<const nlohmann::json::string_t&>()); 100 } 101 102 if (itemEEPROM.value("isReplaceable", false)) 103 { 104 replaceableFrus.emplace_back(itemFRUS.key()); 105 } 106 } 107 } 108 } 109 110 void Manager::writeKeyword(const sdbusplus::message::object_path path, 111 const std::string recordName, 112 const std::string keyword, const Binary value) 113 { 114 try 115 { 116 if (frus.find(path) == frus.end()) 117 { 118 throw std::runtime_error("Inventory path not found"); 119 } 120 121 inventory::Path vpdFilePath = frus.find(path)->second.first; 122 123 // instantiate editor class to update the data 124 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, path); 125 edit.updateKeyword(value, true); 126 127 // if it is a motehrboard FRU need to check for location expansion 128 if (frus.find(path)->second.second) 129 { 130 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE")) 131 { 132 edit.expandLocationCode("fcs"); 133 } 134 else if (recordName == "VSYS" && 135 (keyword == "TM" || keyword == "SE")) 136 { 137 edit.expandLocationCode("mts"); 138 } 139 } 140 141 return; 142 } 143 catch (const std::exception& e) 144 { 145 std::cerr << e.what() << std::endl; 146 } 147 } 148 149 ListOfPaths 150 Manager::getFRUsByUnexpandedLocationCode(const LocationCode locationCode, 151 const NodeNumber nodeNumber) 152 { 153 ReaderImpl read; 154 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode); 155 } 156 157 ListOfPaths 158 Manager::getFRUsByExpandedLocationCode(const LocationCode locationCode) 159 { 160 ReaderImpl read; 161 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode); 162 } 163 164 LocationCode Manager::getExpandedLocationCode(const LocationCode locationCode, 165 const NodeNumber nodeNumber) 166 { 167 ReaderImpl read; 168 return read.getExpandedLocationCode(locationCode, nodeNumber, 169 fruLocationCode); 170 } 171 172 void Manager::performVPDRecollection() 173 { 174 // get list of FRUs replaceable at standby 175 for (const auto& item : replaceableFrus) 176 { 177 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item]; 178 const nlohmann::json& singleFru = groupEEPROM[0]; 179 180 const string& inventoryPath = 181 singleFru["inventoryPath"] 182 .get_ref<const nlohmann::json::string_t&>(); 183 184 if ((singleFru.find("devAddress") == singleFru.end()) || 185 (singleFru.find("driverType") == singleFru.end()) || 186 (singleFru.find("busType") == singleFru.end())) 187 { 188 // The FRUs is marked for replacement but missing mandatory 189 // fields for recollection. Skip to another replaceable fru. 190 log<level::ERR>( 191 "Recollection Failed as mandatory field missing in Json", 192 entry("ERROR=%s", 193 ("Recollection failed for " + inventoryPath).c_str())); 194 continue; 195 } 196 197 string str = "echo "; 198 string deviceAddress = singleFru["devAddress"]; 199 const string& driverType = singleFru["driverType"]; 200 const string& busType = singleFru["busType"]; 201 202 // devTreeStatus flag is present in json as false to mention 203 // that the EEPROM is not mentioned in device tree. If this flag 204 // is absent consider the value to be true, i.e EEPROM is 205 // mentioned in device tree 206 if (!singleFru.value("devTreeStatus", true)) 207 { 208 auto pos = deviceAddress.find('-'); 209 if (pos != string::npos) 210 { 211 string busNum = deviceAddress.substr(0, pos); 212 deviceAddress = 213 "0x" + deviceAddress.substr(pos + 1, string::npos); 214 215 string deleteDevice = str + deviceAddress + " > /sys/bus/" + 216 busType + "/devices/" + busType + "-" + 217 busNum + "/delete_device"; 218 executeCmd(deleteDevice); 219 220 string addDevice = str + driverType + " " + deviceAddress + 221 " > /sys/bus/" + busType + "/devices/" + 222 busType + "-" + busNum + "/new_device"; 223 executeCmd(addDevice); 224 } 225 else 226 { 227 log<level::ERR>( 228 "Wrong format of device address in Json", 229 entry( 230 "ERROR=%s", 231 ("Recollection failed for " + inventoryPath).c_str())); 232 continue; 233 } 234 } 235 else 236 { 237 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType, 238 driverType, "/unbind")); 239 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType, 240 driverType, "/bind")); 241 } 242 } 243 } 244 245 } // namespace manager 246 } // namespace vpd 247 } // namespace openpower