blob: de40edf3c73285423050857b96f30a3304d88411 [file] [log] [blame]
SunnySrivastava1984b59fd092020-02-03 09:58:56 -06001#include "config.h"
2
3#include "manager.hpp"
4
Santosh Puranikf2d3b532022-04-19 06:44:07 -05005#include "bios_handler.hpp"
Santosh Puranikbf78ed82022-04-20 13:17:04 +05306#include "common_utility.hpp"
SunnySrivastava1984d076da82020-03-05 05:33:35 -06007#include "editor_impl.hpp"
Alpana Kumarib17dd3b2020-10-01 00:18:10 -05008#include "gpioMonitor.hpp"
Sunny Srivastava6c71c9d2021-04-15 04:43:54 -05009#include "ibm_vpd_utils.hpp"
SunnySrivastava1984e12b1812020-05-26 02:23:11 -050010#include "ipz_parser.hpp"
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -050011#include "reader_impl.hpp"
SunnySrivastava19849a195542020-09-07 06:04:50 -050012#include "vpd_exceptions.hpp"
13
Santosh Puranikd40e42d2022-03-23 13:58:06 +053014#include <filesystem>
SunnySrivastava19849a195542020-09-07 06:04:50 -050015#include <phosphor-logging/elog-errors.hpp>
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060016
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050017using namespace openpower::vpd::manager;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060018using namespace openpower::vpd::constants;
SunnySrivastava19841356d7e2020-04-24 04:29:35 -050019using namespace openpower::vpd::inventory;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060020using namespace openpower::vpd::manager::editor;
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -050021using namespace openpower::vpd::manager::reader;
SunnySrivastava19849a195542020-09-07 06:04:50 -050022using namespace std;
23using namespace openpower::vpd::parser;
24using namespace openpower::vpd::exceptions;
25using namespace phosphor::logging;
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060026
27namespace openpower
28{
29namespace vpd
30{
31namespace manager
32{
33Manager::Manager(sdbusplus::bus::bus&& bus, const char* busName,
Priyanga Ramasamy9d149342020-07-16 23:41:26 +053034 const char* objPath, const char* /*iFace*/) :
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060035 ServerObject<ManagerIface>(bus, objPath),
36 _bus(std::move(bus)), _manager(_bus, objPath)
37{
38 _bus.request_name(busName);
39}
40
41void Manager::run()
42{
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060043 try
44 {
45 processJSON();
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050046 listenHostState();
Santosh Puranikb62f6052022-04-06 18:37:54 +053047 listenAssetTag();
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050048
Santosh Puranikf2d3b532022-04-19 06:44:07 -050049 // Create an instance of the BIOS handler
50 BiosHandler biosHandler{_bus, *this};
51
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050052 auto event = sdeventplus::Event::get_default();
53 GpioMonitor gpioMon1(jsonFile, event);
54
55 _bus.attach_event(event.get(), SD_EVENT_PRIORITY_IMPORTANT);
56 cout << "VPD manager event loop started\n";
57 event.loop();
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060058 }
59 catch (const std::exception& e)
60 {
61 std::cerr << e.what() << "\n";
62 }
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060063}
64
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050065void Manager::listenHostState()
66{
67 static std::shared_ptr<sdbusplus::bus::match::match> hostState =
68 std::make_shared<sdbusplus::bus::match::match>(
69 _bus,
70 sdbusplus::bus::match::rules::propertiesChanged(
71 "/xyz/openbmc_project/state/host0",
72 "xyz.openbmc_project.State.Host"),
73 [this](sdbusplus::message::message& msg) {
74 hostStateCallBack(msg);
75 });
76}
77
78void Manager::hostStateCallBack(sdbusplus::message::message& msg)
79{
80 if (msg.is_method_error())
81 {
82 std::cerr << "Error in reading signal " << std::endl;
83 }
84
85 Path object;
86 PropertyMap propMap;
87 msg.read(object, propMap);
88 const auto itr = propMap.find("CurrentHostState");
89 if (itr != propMap.end())
90 {
91 if (auto hostState = std::get_if<std::string>(&(itr->second)))
92 {
93 // implies system is moving from standby to power on state
94 if (*hostState == "xyz.openbmc_project.State.Host.HostState."
95 "TransitioningToRunning")
96 {
97 // check and perfrom recollection for FRUs replaceable at
98 // standby.
99 performVPDRecollection();
100 return;
101 }
102 }
103 std::cerr << "Failed to read Host state" << std::endl;
104 }
105}
106
Santosh Puranikb62f6052022-04-06 18:37:54 +0530107void Manager::listenAssetTag()
108{
109 static std::shared_ptr<sdbusplus::bus::match::match> assetMatcher =
110 std::make_shared<sdbusplus::bus::match::match>(
111 _bus,
112 sdbusplus::bus::match::rules::propertiesChanged(
113 "/xyz/openbmc_project/inventory/system",
114 "xyz.openbmc_project.Inventory.Decorator.AssetTag"),
115 [this](sdbusplus::message::message& msg) {
116 assetTagCallback(msg);
117 });
118}
119
120void Manager::assetTagCallback(sdbusplus::message::message& msg)
121{
122 if (msg.is_method_error())
123 {
124 std::cerr << "Error in reading signal " << std::endl;
125 }
126
127 Path object;
128 PropertyMap propMap;
129 msg.read(object, propMap);
130 const auto itr = propMap.find("AssetTag");
131 if (itr != propMap.end())
132 {
133 if (auto assetTag = std::get_if<std::string>(&(itr->second)))
134 {
135 // Call Notify to persist the AssetTag
136 inventory::ObjectMap objectMap = {
137 {std::string{"/system"},
138 {{"xyz.openbmc_project.Inventory.Decorator.AssetTag",
139 {{"AssetTag", *assetTag}}}}}};
140
141 common::utility::callPIM(std::move(objectMap));
142 }
143 else
144 {
145 std::cerr << "Failed to read asset tag" << std::endl;
146 }
147 }
148}
149
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600150void Manager::processJSON()
151{
Santosh Puranik0246a4d2020-11-04 16:57:39 +0530152 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600153
154 if (!json)
155 {
156 throw std::runtime_error("json file not found");
157 }
158
159 jsonFile = nlohmann::json::parse(json);
160 if (jsonFile.find("frus") == jsonFile.end())
161 {
162 throw std::runtime_error("frus group not found in json");
163 }
164
165 const nlohmann::json& groupFRUS =
166 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
167 for (const auto& itemFRUS : groupFRUS.items())
168 {
169 const std::vector<nlohmann::json>& groupEEPROM =
170 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
171 for (const auto& itemEEPROM : groupEEPROM)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600172 {
SunnySrivastava198443306542020-04-01 02:50:20 -0500173 bool isMotherboard = false;
Santosh Puranika0b23912022-02-10 13:37:09 +0530174 std::string redundantPath;
175
SunnySrivastava198443306542020-04-01 02:50:20 -0500176 if (itemEEPROM["extraInterfaces"].find(
177 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") !=
178 itemEEPROM["extraInterfaces"].end())
179 {
180 isMotherboard = true;
181 }
Santosh Puranika0b23912022-02-10 13:37:09 +0530182 if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end())
183 {
184 redundantPath = itemEEPROM["redundantEeprom"]
185 .get_ref<const nlohmann::json::string_t&>();
186 }
187 frus.emplace(
188 itemEEPROM["inventoryPath"]
189 .get_ref<const nlohmann::json::string_t&>(),
190 std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard));
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500191
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000192 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
Alpana Kumari920408d2020-05-14 00:07:03 -0500193 itemEEPROM["extraInterfaces"].end())
194 {
195 fruLocationCode.emplace(
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000196 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
Alpana Kumari920408d2020-05-14 00:07:03 -0500197 ["LocationCode"]
198 .get_ref<const nlohmann::json::string_t&>(),
199 itemEEPROM["inventoryPath"]
200 .get_ref<const nlohmann::json::string_t&>());
201 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500202
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500203 if (itemEEPROM.value("replaceableAtStandby", false))
SunnySrivastava19849a195542020-09-07 06:04:50 -0500204 {
205 replaceableFrus.emplace_back(itemFRUS.key());
206 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600207 }
208 }
209}
210
211void Manager::writeKeyword(const sdbusplus::message::object_path path,
212 const std::string recordName,
213 const std::string keyword, const Binary value)
214{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600215 try
216 {
Santosh Puranik8c796812021-12-01 19:17:56 +0530217 std::string objPath{path};
218 // Strip any inventory prefix in path
219 if (objPath.find(INVENTORY_PATH) == 0)
220 {
221 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
222 }
223
224 if (frus.find(objPath) == frus.end())
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600225 {
226 throw std::runtime_error("Inventory path not found");
227 }
228
Santosh Puranika0b23912022-02-10 13:37:09 +0530229 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600230
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500231 // instantiate editor class to update the data
Santosh Puranik8c796812021-12-01 19:17:56 +0530232 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530233
234 uint32_t offset = 0;
235 // Setup offset, if any
236 for (const auto& item : jsonFile["frus"][vpdFilePath])
237 {
238 if (item.find("offset") != item.end())
239 {
240 offset = item["offset"];
241 break;
242 }
243 }
244
245 edit.updateKeyword(value, offset, true);
246
247 // If we have a redundant EEPROM to update, then update just the EEPROM,
248 // not the cache since that is already done when we updated the primary
249 if (!std::get<1>(frus.find(objPath)->second).empty())
250 {
251 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile,
252 recordName, keyword);
253 edit.updateKeyword(value, offset, false);
254 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600255
SunnySrivastava198443306542020-04-01 02:50:20 -0500256 // if it is a motehrboard FRU need to check for location expansion
Santosh Puranika0b23912022-02-10 13:37:09 +0530257 if (std::get<2>(frus.find(objPath)->second))
SunnySrivastava198443306542020-04-01 02:50:20 -0500258 {
259 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE"))
260 {
261 edit.expandLocationCode("fcs");
262 }
263 else if (recordName == "VSYS" &&
264 (keyword == "TM" || keyword == "SE"))
265 {
266 edit.expandLocationCode("mts");
267 }
268 }
269
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500270 return;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600271 }
272 catch (const std::exception& e)
273 {
274 std::cerr << e.what() << std::endl;
275 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600276}
277
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500278ListOfPaths
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500279 Manager::getFRUsByUnexpandedLocationCode(const LocationCode locationCode,
280 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600281{
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500282 ReaderImpl read;
283 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600284}
285
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500286ListOfPaths
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500287 Manager::getFRUsByExpandedLocationCode(const LocationCode locationCode)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600288{
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500289 ReaderImpl read;
290 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600291}
292
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500293LocationCode Manager::getExpandedLocationCode(const LocationCode locationCode,
294 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600295{
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500296 ReaderImpl read;
297 return read.getExpandedLocationCode(locationCode, nodeNumber,
298 fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600299}
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600300
SunnySrivastava19849a195542020-09-07 06:04:50 -0500301void Manager::performVPDRecollection()
302{
303 // get list of FRUs replaceable at standby
304 for (const auto& item : replaceableFrus)
305 {
306 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
307 const nlohmann::json& singleFru = groupEEPROM[0];
308
309 const string& inventoryPath =
310 singleFru["inventoryPath"]
311 .get_ref<const nlohmann::json::string_t&>();
312
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530313 bool prePostActionRequired = false;
314
315 if ((jsonFile["frus"][item].at(0)).find("preAction") !=
316 jsonFile["frus"][item].at(0).end())
317 {
318 if (!executePreAction(jsonFile, item))
319 {
320 // if the FRU has preAction defined then its execution should
321 // pass to ensure bind/unbind of data.
322 // preAction execution failed. should not call bind/unbind.
323 log<level::ERR>(
324 "Pre-Action execution failed for the FRU",
325 entry("ERROR=%s",
326 ("Inventory path: " + inventoryPath).c_str()));
327 continue;
328 }
329 prePostActionRequired = true;
330 }
331
SunnySrivastava19849a195542020-09-07 06:04:50 -0500332 if ((singleFru.find("devAddress") == singleFru.end()) ||
333 (singleFru.find("driverType") == singleFru.end()) ||
334 (singleFru.find("busType") == singleFru.end()))
335 {
336 // The FRUs is marked for replacement but missing mandatory
337 // fields for recollection. Skip to another replaceable fru.
338 log<level::ERR>(
339 "Recollection Failed as mandatory field missing in Json",
340 entry("ERROR=%s",
341 ("Recollection failed for " + inventoryPath).c_str()));
342 continue;
343 }
344
345 string str = "echo ";
346 string deviceAddress = singleFru["devAddress"];
347 const string& driverType = singleFru["driverType"];
348 const string& busType = singleFru["busType"];
349
350 // devTreeStatus flag is present in json as false to mention
351 // that the EEPROM is not mentioned in device tree. If this flag
352 // is absent consider the value to be true, i.e EEPROM is
353 // mentioned in device tree
354 if (!singleFru.value("devTreeStatus", true))
355 {
356 auto pos = deviceAddress.find('-');
357 if (pos != string::npos)
358 {
359 string busNum = deviceAddress.substr(0, pos);
360 deviceAddress =
361 "0x" + deviceAddress.substr(pos + 1, string::npos);
362
363 string deleteDevice = str + deviceAddress + " > /sys/bus/" +
364 busType + "/devices/" + busType + "-" +
365 busNum + "/delete_device";
366 executeCmd(deleteDevice);
367
368 string addDevice = str + driverType + " " + deviceAddress +
369 " > /sys/bus/" + busType + "/devices/" +
370 busType + "-" + busNum + "/new_device";
371 executeCmd(addDevice);
372 }
373 else
374 {
375 log<level::ERR>(
376 "Wrong format of device address in Json",
377 entry(
378 "ERROR=%s",
379 ("Recollection failed for " + inventoryPath).c_str()));
380 continue;
381 }
382 }
383 else
384 {
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500385 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
386 driverType, "/unbind"));
387 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
388 driverType, "/bind"));
SunnySrivastava19849a195542020-09-07 06:04:50 -0500389 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530390
391 // this check is added to avoid file system expensive call in case not
392 // required.
393 if (prePostActionRequired)
394 {
395 // Check if device showed up (test for file)
396 if (!filesystem::exists(item))
397 {
398 // If not, then take failure postAction
399 executePostFailAction(jsonFile, item);
400 }
401 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500402 }
403}
404
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600405} // namespace manager
406} // namespace vpd
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500407} // namespace openpower