blob: 932cc9dfb924e970507e6e728c8ab43602fd26fa [file] [log] [blame]
SunnySrivastava1984b59fd092020-02-03 09:58:56 -06001#include "config.h"
2
3#include "manager.hpp"
4
Santosh Puranikbf78ed82022-04-20 13:17:04 +05305#include "common_utility.hpp"
SunnySrivastava1984d076da82020-03-05 05:33:35 -06006#include "editor_impl.hpp"
Alpana Kumarib17dd3b2020-10-01 00:18:10 -05007#include "gpioMonitor.hpp"
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05008#include "ibm_vpd_utils.hpp"
SunnySrivastava1984e12b1812020-05-26 02:23:11 -05009#include "ipz_parser.hpp"
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -050010#include "reader_impl.hpp"
SunnySrivastava19849a195542020-09-07 06:04:50 -050011#include "vpd_exceptions.hpp"
12
Santosh Puranikd40e42d2022-03-23 13:58:06 +053013#include <filesystem>
SunnySrivastava19849a195542020-09-07 06:04:50 -050014#include <phosphor-logging/elog-errors.hpp>
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060015
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050016using namespace openpower::vpd::manager;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060017using namespace openpower::vpd::constants;
SunnySrivastava19841356d7e2020-04-24 04:29:35 -050018using namespace openpower::vpd::inventory;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060019using namespace openpower::vpd::manager::editor;
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -050020using namespace openpower::vpd::manager::reader;
SunnySrivastava19849a195542020-09-07 06:04:50 -050021using namespace std;
22using namespace openpower::vpd::parser;
23using namespace openpower::vpd::exceptions;
24using namespace phosphor::logging;
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060025
26namespace openpower
27{
28namespace vpd
29{
30namespace manager
31{
32Manager::Manager(sdbusplus::bus::bus&& bus, const char* busName,
Priyanga Ramasamy9d149342020-07-16 23:41:26 +053033 const char* objPath, const char* /*iFace*/) :
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060034 ServerObject<ManagerIface>(bus, objPath),
35 _bus(std::move(bus)), _manager(_bus, objPath)
36{
37 _bus.request_name(busName);
38}
39
40void Manager::run()
41{
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060042 try
43 {
44 processJSON();
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050045 listenHostState();
Santosh Puranikb62f6052022-04-06 18:37:54 +053046 listenAssetTag();
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050047
48 auto event = sdeventplus::Event::get_default();
49 GpioMonitor gpioMon1(jsonFile, event);
50
51 _bus.attach_event(event.get(), SD_EVENT_PRIORITY_IMPORTANT);
52 cout << "VPD manager event loop started\n";
53 event.loop();
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060054 }
55 catch (const std::exception& e)
56 {
57 std::cerr << e.what() << "\n";
58 }
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060059}
60
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050061void Manager::listenHostState()
62{
63 static std::shared_ptr<sdbusplus::bus::match::match> hostState =
64 std::make_shared<sdbusplus::bus::match::match>(
65 _bus,
66 sdbusplus::bus::match::rules::propertiesChanged(
67 "/xyz/openbmc_project/state/host0",
68 "xyz.openbmc_project.State.Host"),
69 [this](sdbusplus::message::message& msg) {
70 hostStateCallBack(msg);
71 });
72}
73
74void Manager::hostStateCallBack(sdbusplus::message::message& msg)
75{
76 if (msg.is_method_error())
77 {
78 std::cerr << "Error in reading signal " << std::endl;
79 }
80
81 Path object;
82 PropertyMap propMap;
83 msg.read(object, propMap);
84 const auto itr = propMap.find("CurrentHostState");
85 if (itr != propMap.end())
86 {
87 if (auto hostState = std::get_if<std::string>(&(itr->second)))
88 {
89 // implies system is moving from standby to power on state
90 if (*hostState == "xyz.openbmc_project.State.Host.HostState."
91 "TransitioningToRunning")
92 {
93 // check and perfrom recollection for FRUs replaceable at
94 // standby.
95 performVPDRecollection();
96 return;
97 }
98 }
99 std::cerr << "Failed to read Host state" << std::endl;
100 }
101}
102
Santosh Puranikb62f6052022-04-06 18:37:54 +0530103void Manager::listenAssetTag()
104{
105 static std::shared_ptr<sdbusplus::bus::match::match> assetMatcher =
106 std::make_shared<sdbusplus::bus::match::match>(
107 _bus,
108 sdbusplus::bus::match::rules::propertiesChanged(
109 "/xyz/openbmc_project/inventory/system",
110 "xyz.openbmc_project.Inventory.Decorator.AssetTag"),
111 [this](sdbusplus::message::message& msg) {
112 assetTagCallback(msg);
113 });
114}
115
116void Manager::assetTagCallback(sdbusplus::message::message& msg)
117{
118 if (msg.is_method_error())
119 {
120 std::cerr << "Error in reading signal " << std::endl;
121 }
122
123 Path object;
124 PropertyMap propMap;
125 msg.read(object, propMap);
126 const auto itr = propMap.find("AssetTag");
127 if (itr != propMap.end())
128 {
129 if (auto assetTag = std::get_if<std::string>(&(itr->second)))
130 {
131 // Call Notify to persist the AssetTag
132 inventory::ObjectMap objectMap = {
133 {std::string{"/system"},
134 {{"xyz.openbmc_project.Inventory.Decorator.AssetTag",
135 {{"AssetTag", *assetTag}}}}}};
136
137 common::utility::callPIM(std::move(objectMap));
138 }
139 else
140 {
141 std::cerr << "Failed to read asset tag" << std::endl;
142 }
143 }
144}
145
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600146void Manager::processJSON()
147{
Santosh Puranik0246a4d2020-11-04 16:57:39 +0530148 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600149
150 if (!json)
151 {
152 throw std::runtime_error("json file not found");
153 }
154
155 jsonFile = nlohmann::json::parse(json);
156 if (jsonFile.find("frus") == jsonFile.end())
157 {
158 throw std::runtime_error("frus group not found in json");
159 }
160
161 const nlohmann::json& groupFRUS =
162 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
163 for (const auto& itemFRUS : groupFRUS.items())
164 {
165 const std::vector<nlohmann::json>& groupEEPROM =
166 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
167 for (const auto& itemEEPROM : groupEEPROM)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600168 {
SunnySrivastava198443306542020-04-01 02:50:20 -0500169 bool isMotherboard = false;
Santosh Puranika0b23912022-02-10 13:37:09 +0530170 std::string redundantPath;
171
SunnySrivastava198443306542020-04-01 02:50:20 -0500172 if (itemEEPROM["extraInterfaces"].find(
173 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") !=
174 itemEEPROM["extraInterfaces"].end())
175 {
176 isMotherboard = true;
177 }
Santosh Puranika0b23912022-02-10 13:37:09 +0530178 if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end())
179 {
180 redundantPath = itemEEPROM["redundantEeprom"]
181 .get_ref<const nlohmann::json::string_t&>();
182 }
183 frus.emplace(
184 itemEEPROM["inventoryPath"]
185 .get_ref<const nlohmann::json::string_t&>(),
186 std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard));
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500187
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000188 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
Alpana Kumari920408d2020-05-14 00:07:03 -0500189 itemEEPROM["extraInterfaces"].end())
190 {
191 fruLocationCode.emplace(
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000192 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
Alpana Kumari920408d2020-05-14 00:07:03 -0500193 ["LocationCode"]
194 .get_ref<const nlohmann::json::string_t&>(),
195 itemEEPROM["inventoryPath"]
196 .get_ref<const nlohmann::json::string_t&>());
197 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500198
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500199 if (itemEEPROM.value("replaceableAtStandby", false))
SunnySrivastava19849a195542020-09-07 06:04:50 -0500200 {
201 replaceableFrus.emplace_back(itemFRUS.key());
202 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600203 }
204 }
205}
206
207void Manager::writeKeyword(const sdbusplus::message::object_path path,
208 const std::string recordName,
209 const std::string keyword, const Binary value)
210{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600211 try
212 {
Santosh Puranik8c796812021-12-01 19:17:56 +0530213 std::string objPath{path};
214 // Strip any inventory prefix in path
215 if (objPath.find(INVENTORY_PATH) == 0)
216 {
217 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
218 }
219
220 if (frus.find(objPath) == frus.end())
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600221 {
222 throw std::runtime_error("Inventory path not found");
223 }
224
Santosh Puranika0b23912022-02-10 13:37:09 +0530225 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600226
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500227 // instantiate editor class to update the data
Santosh Puranik8c796812021-12-01 19:17:56 +0530228 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530229
230 uint32_t offset = 0;
231 // Setup offset, if any
232 for (const auto& item : jsonFile["frus"][vpdFilePath])
233 {
234 if (item.find("offset") != item.end())
235 {
236 offset = item["offset"];
237 break;
238 }
239 }
240
241 edit.updateKeyword(value, offset, true);
242
243 // If we have a redundant EEPROM to update, then update just the EEPROM,
244 // not the cache since that is already done when we updated the primary
245 if (!std::get<1>(frus.find(objPath)->second).empty())
246 {
247 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile,
248 recordName, keyword);
249 edit.updateKeyword(value, offset, false);
250 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600251
SunnySrivastava198443306542020-04-01 02:50:20 -0500252 // if it is a motehrboard FRU need to check for location expansion
Santosh Puranika0b23912022-02-10 13:37:09 +0530253 if (std::get<2>(frus.find(objPath)->second))
SunnySrivastava198443306542020-04-01 02:50:20 -0500254 {
255 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE"))
256 {
257 edit.expandLocationCode("fcs");
258 }
259 else if (recordName == "VSYS" &&
260 (keyword == "TM" || keyword == "SE"))
261 {
262 edit.expandLocationCode("mts");
263 }
264 }
265
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500266 return;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600267 }
268 catch (const std::exception& e)
269 {
270 std::cerr << e.what() << std::endl;
271 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600272}
273
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500274ListOfPaths
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500275 Manager::getFRUsByUnexpandedLocationCode(const LocationCode locationCode,
276 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600277{
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500278 ReaderImpl read;
279 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600280}
281
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500282ListOfPaths
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500283 Manager::getFRUsByExpandedLocationCode(const LocationCode locationCode)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600284{
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500285 ReaderImpl read;
286 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600287}
288
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500289LocationCode Manager::getExpandedLocationCode(const LocationCode locationCode,
290 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600291{
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500292 ReaderImpl read;
293 return read.getExpandedLocationCode(locationCode, nodeNumber,
294 fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600295}
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600296
SunnySrivastava19849a195542020-09-07 06:04:50 -0500297void Manager::performVPDRecollection()
298{
299 // get list of FRUs replaceable at standby
300 for (const auto& item : replaceableFrus)
301 {
302 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
303 const nlohmann::json& singleFru = groupEEPROM[0];
304
305 const string& inventoryPath =
306 singleFru["inventoryPath"]
307 .get_ref<const nlohmann::json::string_t&>();
308
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530309 bool prePostActionRequired = false;
310
311 if ((jsonFile["frus"][item].at(0)).find("preAction") !=
312 jsonFile["frus"][item].at(0).end())
313 {
314 if (!executePreAction(jsonFile, item))
315 {
316 // if the FRU has preAction defined then its execution should
317 // pass to ensure bind/unbind of data.
318 // preAction execution failed. should not call bind/unbind.
319 log<level::ERR>(
320 "Pre-Action execution failed for the FRU",
321 entry("ERROR=%s",
322 ("Inventory path: " + inventoryPath).c_str()));
323 continue;
324 }
325 prePostActionRequired = true;
326 }
327
SunnySrivastava19849a195542020-09-07 06:04:50 -0500328 if ((singleFru.find("devAddress") == singleFru.end()) ||
329 (singleFru.find("driverType") == singleFru.end()) ||
330 (singleFru.find("busType") == singleFru.end()))
331 {
332 // The FRUs is marked for replacement but missing mandatory
333 // fields for recollection. Skip to another replaceable fru.
334 log<level::ERR>(
335 "Recollection Failed as mandatory field missing in Json",
336 entry("ERROR=%s",
337 ("Recollection failed for " + inventoryPath).c_str()));
338 continue;
339 }
340
341 string str = "echo ";
342 string deviceAddress = singleFru["devAddress"];
343 const string& driverType = singleFru["driverType"];
344 const string& busType = singleFru["busType"];
345
346 // devTreeStatus flag is present in json as false to mention
347 // that the EEPROM is not mentioned in device tree. If this flag
348 // is absent consider the value to be true, i.e EEPROM is
349 // mentioned in device tree
350 if (!singleFru.value("devTreeStatus", true))
351 {
352 auto pos = deviceAddress.find('-');
353 if (pos != string::npos)
354 {
355 string busNum = deviceAddress.substr(0, pos);
356 deviceAddress =
357 "0x" + deviceAddress.substr(pos + 1, string::npos);
358
359 string deleteDevice = str + deviceAddress + " > /sys/bus/" +
360 busType + "/devices/" + busType + "-" +
361 busNum + "/delete_device";
362 executeCmd(deleteDevice);
363
364 string addDevice = str + driverType + " " + deviceAddress +
365 " > /sys/bus/" + busType + "/devices/" +
366 busType + "-" + busNum + "/new_device";
367 executeCmd(addDevice);
368 }
369 else
370 {
371 log<level::ERR>(
372 "Wrong format of device address in Json",
373 entry(
374 "ERROR=%s",
375 ("Recollection failed for " + inventoryPath).c_str()));
376 continue;
377 }
378 }
379 else
380 {
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500381 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
382 driverType, "/unbind"));
383 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
384 driverType, "/bind"));
SunnySrivastava19849a195542020-09-07 06:04:50 -0500385 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530386
387 // this check is added to avoid file system expensive call in case not
388 // required.
389 if (prePostActionRequired)
390 {
391 // Check if device showed up (test for file)
392 if (!filesystem::exists(item))
393 {
394 // If not, then take failure postAction
395 executePostFailAction(jsonFile, item);
396 }
397 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500398 }
399}
400
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600401} // namespace manager
402} // namespace vpd
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500403} // namespace openpower