xref: /openbmc/openpower-vpd-parser/vpd-manager/manager.cpp (revision 8e15b93ada4ab399db36dec5f525ff93bacb5353)
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