blob: 1602473b5ba7d35e399ba8a82d1b7d29930f3a90 [file] [log] [blame]
SunnySrivastava1984b59fd092020-02-03 09:58:56 -06001#include "config.h"
2
3#include "manager.hpp"
4
SunnySrivastava1984d076da82020-03-05 05:33:35 -06005#include "editor_impl.hpp"
Alpana Kumarib17dd3b2020-10-01 00:18:10 -05006#include "gpioMonitor.hpp"
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05007#include "ibm_vpd_utils.hpp"
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05008#include "ipz_parser.hpp"
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -05009#include "reader_impl.hpp"
SunnySrivastava19849a195542020-09-07 06:04:50 -050010#include "vpd_exceptions.hpp"
11
Santosh Puranikd40e42d2022-03-23 13:58:06 +053012#include <filesystem>
SunnySrivastava19849a195542020-09-07 06:04:50 -050013#include <phosphor-logging/elog-errors.hpp>
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060014
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050015using namespace openpower::vpd::manager;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060016using namespace openpower::vpd::constants;
SunnySrivastava19841356d7e2020-04-24 04:29:35 -050017using namespace openpower::vpd::inventory;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060018using namespace openpower::vpd::manager::editor;
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -050019using namespace openpower::vpd::manager::reader;
SunnySrivastava19849a195542020-09-07 06:04:50 -050020using namespace std;
21using namespace openpower::vpd::parser;
22using namespace openpower::vpd::exceptions;
23using namespace phosphor::logging;
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060024
25namespace openpower
26{
27namespace vpd
28{
29namespace manager
30{
31Manager::Manager(sdbusplus::bus::bus&& bus, const char* busName,
Priyanga Ramasamy9d149342020-07-16 23:41:26 +053032 const char* objPath, const char* /*iFace*/) :
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060033 ServerObject<ManagerIface>(bus, objPath),
34 _bus(std::move(bus)), _manager(_bus, objPath)
35{
36 _bus.request_name(busName);
37}
38
39void Manager::run()
40{
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060041 try
42 {
43 processJSON();
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050044 listenHostState();
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050045
46 auto event = sdeventplus::Event::get_default();
47 GpioMonitor gpioMon1(jsonFile, event);
48
49 _bus.attach_event(event.get(), SD_EVENT_PRIORITY_IMPORTANT);
50 cout << "VPD manager event loop started\n";
51 event.loop();
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060052 }
53 catch (const std::exception& e)
54 {
55 std::cerr << e.what() << "\n";
56 }
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060057}
58
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050059void Manager::listenHostState()
60{
61 static std::shared_ptr<sdbusplus::bus::match::match> hostState =
62 std::make_shared<sdbusplus::bus::match::match>(
63 _bus,
64 sdbusplus::bus::match::rules::propertiesChanged(
65 "/xyz/openbmc_project/state/host0",
66 "xyz.openbmc_project.State.Host"),
67 [this](sdbusplus::message::message& msg) {
68 hostStateCallBack(msg);
69 });
70}
71
72void Manager::hostStateCallBack(sdbusplus::message::message& msg)
73{
74 if (msg.is_method_error())
75 {
76 std::cerr << "Error in reading signal " << std::endl;
77 }
78
79 Path object;
80 PropertyMap propMap;
81 msg.read(object, propMap);
82 const auto itr = propMap.find("CurrentHostState");
83 if (itr != propMap.end())
84 {
85 if (auto hostState = std::get_if<std::string>(&(itr->second)))
86 {
87 // implies system is moving from standby to power on state
88 if (*hostState == "xyz.openbmc_project.State.Host.HostState."
89 "TransitioningToRunning")
90 {
91 // check and perfrom recollection for FRUs replaceable at
92 // standby.
93 performVPDRecollection();
94 return;
95 }
96 }
97 std::cerr << "Failed to read Host state" << std::endl;
98 }
99}
100
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600101void Manager::processJSON()
102{
Santosh Puranik0246a4d2020-11-04 16:57:39 +0530103 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600104
105 if (!json)
106 {
107 throw std::runtime_error("json file not found");
108 }
109
110 jsonFile = nlohmann::json::parse(json);
111 if (jsonFile.find("frus") == jsonFile.end())
112 {
113 throw std::runtime_error("frus group not found in json");
114 }
115
116 const nlohmann::json& groupFRUS =
117 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
118 for (const auto& itemFRUS : groupFRUS.items())
119 {
120 const std::vector<nlohmann::json>& groupEEPROM =
121 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
122 for (const auto& itemEEPROM : groupEEPROM)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600123 {
SunnySrivastava198443306542020-04-01 02:50:20 -0500124 bool isMotherboard = false;
Santosh Puranika0b23912022-02-10 13:37:09 +0530125 std::string redundantPath;
126
SunnySrivastava198443306542020-04-01 02:50:20 -0500127 if (itemEEPROM["extraInterfaces"].find(
128 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") !=
129 itemEEPROM["extraInterfaces"].end())
130 {
131 isMotherboard = true;
132 }
Santosh Puranika0b23912022-02-10 13:37:09 +0530133 if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end())
134 {
135 redundantPath = itemEEPROM["redundantEeprom"]
136 .get_ref<const nlohmann::json::string_t&>();
137 }
138 frus.emplace(
139 itemEEPROM["inventoryPath"]
140 .get_ref<const nlohmann::json::string_t&>(),
141 std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard));
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500142
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000143 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
Alpana Kumari920408d2020-05-14 00:07:03 -0500144 itemEEPROM["extraInterfaces"].end())
145 {
146 fruLocationCode.emplace(
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000147 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
Alpana Kumari920408d2020-05-14 00:07:03 -0500148 ["LocationCode"]
149 .get_ref<const nlohmann::json::string_t&>(),
150 itemEEPROM["inventoryPath"]
151 .get_ref<const nlohmann::json::string_t&>());
152 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500153
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500154 if (itemEEPROM.value("replaceableAtStandby", false))
SunnySrivastava19849a195542020-09-07 06:04:50 -0500155 {
156 replaceableFrus.emplace_back(itemFRUS.key());
157 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600158 }
159 }
160}
161
162void Manager::writeKeyword(const sdbusplus::message::object_path path,
163 const std::string recordName,
164 const std::string keyword, const Binary value)
165{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600166 try
167 {
Santosh Puranik8c796812021-12-01 19:17:56 +0530168 std::string objPath{path};
169 // Strip any inventory prefix in path
170 if (objPath.find(INVENTORY_PATH) == 0)
171 {
172 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
173 }
174
175 if (frus.find(objPath) == frus.end())
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600176 {
177 throw std::runtime_error("Inventory path not found");
178 }
179
Santosh Puranika0b23912022-02-10 13:37:09 +0530180 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600181
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500182 // instantiate editor class to update the data
Santosh Puranik8c796812021-12-01 19:17:56 +0530183 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530184
185 uint32_t offset = 0;
186 // Setup offset, if any
187 for (const auto& item : jsonFile["frus"][vpdFilePath])
188 {
189 if (item.find("offset") != item.end())
190 {
191 offset = item["offset"];
192 break;
193 }
194 }
195
196 edit.updateKeyword(value, offset, true);
197
198 // If we have a redundant EEPROM to update, then update just the EEPROM,
199 // not the cache since that is already done when we updated the primary
200 if (!std::get<1>(frus.find(objPath)->second).empty())
201 {
202 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile,
203 recordName, keyword);
204 edit.updateKeyword(value, offset, false);
205 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600206
SunnySrivastava198443306542020-04-01 02:50:20 -0500207 // if it is a motehrboard FRU need to check for location expansion
Santosh Puranika0b23912022-02-10 13:37:09 +0530208 if (std::get<2>(frus.find(objPath)->second))
SunnySrivastava198443306542020-04-01 02:50:20 -0500209 {
210 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE"))
211 {
212 edit.expandLocationCode("fcs");
213 }
214 else if (recordName == "VSYS" &&
215 (keyword == "TM" || keyword == "SE"))
216 {
217 edit.expandLocationCode("mts");
218 }
219 }
220
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500221 return;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600222 }
223 catch (const std::exception& e)
224 {
225 std::cerr << e.what() << std::endl;
226 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600227}
228
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500229ListOfPaths
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500230 Manager::getFRUsByUnexpandedLocationCode(const LocationCode locationCode,
231 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600232{
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500233 ReaderImpl read;
234 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600235}
236
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500237ListOfPaths
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500238 Manager::getFRUsByExpandedLocationCode(const LocationCode locationCode)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600239{
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500240 ReaderImpl read;
241 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600242}
243
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500244LocationCode Manager::getExpandedLocationCode(const LocationCode locationCode,
245 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600246{
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500247 ReaderImpl read;
248 return read.getExpandedLocationCode(locationCode, nodeNumber,
249 fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600250}
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600251
SunnySrivastava19849a195542020-09-07 06:04:50 -0500252void Manager::performVPDRecollection()
253{
254 // get list of FRUs replaceable at standby
255 for (const auto& item : replaceableFrus)
256 {
257 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
258 const nlohmann::json& singleFru = groupEEPROM[0];
259
260 const string& inventoryPath =
261 singleFru["inventoryPath"]
262 .get_ref<const nlohmann::json::string_t&>();
263
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530264 bool prePostActionRequired = false;
265
266 if ((jsonFile["frus"][item].at(0)).find("preAction") !=
267 jsonFile["frus"][item].at(0).end())
268 {
269 if (!executePreAction(jsonFile, item))
270 {
271 // if the FRU has preAction defined then its execution should
272 // pass to ensure bind/unbind of data.
273 // preAction execution failed. should not call bind/unbind.
274 log<level::ERR>(
275 "Pre-Action execution failed for the FRU",
276 entry("ERROR=%s",
277 ("Inventory path: " + inventoryPath).c_str()));
278 continue;
279 }
280 prePostActionRequired = true;
281 }
282
SunnySrivastava19849a195542020-09-07 06:04:50 -0500283 if ((singleFru.find("devAddress") == singleFru.end()) ||
284 (singleFru.find("driverType") == singleFru.end()) ||
285 (singleFru.find("busType") == singleFru.end()))
286 {
287 // The FRUs is marked for replacement but missing mandatory
288 // fields for recollection. Skip to another replaceable fru.
289 log<level::ERR>(
290 "Recollection Failed as mandatory field missing in Json",
291 entry("ERROR=%s",
292 ("Recollection failed for " + inventoryPath).c_str()));
293 continue;
294 }
295
296 string str = "echo ";
297 string deviceAddress = singleFru["devAddress"];
298 const string& driverType = singleFru["driverType"];
299 const string& busType = singleFru["busType"];
300
301 // devTreeStatus flag is present in json as false to mention
302 // that the EEPROM is not mentioned in device tree. If this flag
303 // is absent consider the value to be true, i.e EEPROM is
304 // mentioned in device tree
305 if (!singleFru.value("devTreeStatus", true))
306 {
307 auto pos = deviceAddress.find('-');
308 if (pos != string::npos)
309 {
310 string busNum = deviceAddress.substr(0, pos);
311 deviceAddress =
312 "0x" + deviceAddress.substr(pos + 1, string::npos);
313
314 string deleteDevice = str + deviceAddress + " > /sys/bus/" +
315 busType + "/devices/" + busType + "-" +
316 busNum + "/delete_device";
317 executeCmd(deleteDevice);
318
319 string addDevice = str + driverType + " " + deviceAddress +
320 " > /sys/bus/" + busType + "/devices/" +
321 busType + "-" + busNum + "/new_device";
322 executeCmd(addDevice);
323 }
324 else
325 {
326 log<level::ERR>(
327 "Wrong format of device address in Json",
328 entry(
329 "ERROR=%s",
330 ("Recollection failed for " + inventoryPath).c_str()));
331 continue;
332 }
333 }
334 else
335 {
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500336 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
337 driverType, "/unbind"));
338 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
339 driverType, "/bind"));
SunnySrivastava19849a195542020-09-07 06:04:50 -0500340 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530341
342 // this check is added to avoid file system expensive call in case not
343 // required.
344 if (prePostActionRequired)
345 {
346 // Check if device showed up (test for file)
347 if (!filesystem::exists(item))
348 {
349 // If not, then take failure postAction
350 executePostFailAction(jsonFile, item);
351 }
352 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500353 }
354}
355
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600356} // namespace manager
357} // namespace vpd
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500358} // namespace openpower