blob: 3a26cffcbd3fe59b556be258da2ac48672d831ac [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();
Santosh Puranikb62f6052022-04-06 18:37:54 +053045 listenAssetTag();
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050046
47 auto event = sdeventplus::Event::get_default();
48 GpioMonitor gpioMon1(jsonFile, event);
49
50 _bus.attach_event(event.get(), SD_EVENT_PRIORITY_IMPORTANT);
51 cout << "VPD manager event loop started\n";
52 event.loop();
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060053 }
54 catch (const std::exception& e)
55 {
56 std::cerr << e.what() << "\n";
57 }
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060058}
59
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050060void Manager::listenHostState()
61{
62 static std::shared_ptr<sdbusplus::bus::match::match> hostState =
63 std::make_shared<sdbusplus::bus::match::match>(
64 _bus,
65 sdbusplus::bus::match::rules::propertiesChanged(
66 "/xyz/openbmc_project/state/host0",
67 "xyz.openbmc_project.State.Host"),
68 [this](sdbusplus::message::message& msg) {
69 hostStateCallBack(msg);
70 });
71}
72
73void Manager::hostStateCallBack(sdbusplus::message::message& msg)
74{
75 if (msg.is_method_error())
76 {
77 std::cerr << "Error in reading signal " << std::endl;
78 }
79
80 Path object;
81 PropertyMap propMap;
82 msg.read(object, propMap);
83 const auto itr = propMap.find("CurrentHostState");
84 if (itr != propMap.end())
85 {
86 if (auto hostState = std::get_if<std::string>(&(itr->second)))
87 {
88 // implies system is moving from standby to power on state
89 if (*hostState == "xyz.openbmc_project.State.Host.HostState."
90 "TransitioningToRunning")
91 {
92 // check and perfrom recollection for FRUs replaceable at
93 // standby.
94 performVPDRecollection();
95 return;
96 }
97 }
98 std::cerr << "Failed to read Host state" << std::endl;
99 }
100}
101
Santosh Puranikb62f6052022-04-06 18:37:54 +0530102void Manager::listenAssetTag()
103{
104 static std::shared_ptr<sdbusplus::bus::match::match> assetMatcher =
105 std::make_shared<sdbusplus::bus::match::match>(
106 _bus,
107 sdbusplus::bus::match::rules::propertiesChanged(
108 "/xyz/openbmc_project/inventory/system",
109 "xyz.openbmc_project.Inventory.Decorator.AssetTag"),
110 [this](sdbusplus::message::message& msg) {
111 assetTagCallback(msg);
112 });
113}
114
115void Manager::assetTagCallback(sdbusplus::message::message& msg)
116{
117 if (msg.is_method_error())
118 {
119 std::cerr << "Error in reading signal " << std::endl;
120 }
121
122 Path object;
123 PropertyMap propMap;
124 msg.read(object, propMap);
125 const auto itr = propMap.find("AssetTag");
126 if (itr != propMap.end())
127 {
128 if (auto assetTag = std::get_if<std::string>(&(itr->second)))
129 {
130 // Call Notify to persist the AssetTag
131 inventory::ObjectMap objectMap = {
132 {std::string{"/system"},
133 {{"xyz.openbmc_project.Inventory.Decorator.AssetTag",
134 {{"AssetTag", *assetTag}}}}}};
135
136 common::utility::callPIM(std::move(objectMap));
137 }
138 else
139 {
140 std::cerr << "Failed to read asset tag" << std::endl;
141 }
142 }
143}
144
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600145void Manager::processJSON()
146{
Santosh Puranik0246a4d2020-11-04 16:57:39 +0530147 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600148
149 if (!json)
150 {
151 throw std::runtime_error("json file not found");
152 }
153
154 jsonFile = nlohmann::json::parse(json);
155 if (jsonFile.find("frus") == jsonFile.end())
156 {
157 throw std::runtime_error("frus group not found in json");
158 }
159
160 const nlohmann::json& groupFRUS =
161 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
162 for (const auto& itemFRUS : groupFRUS.items())
163 {
164 const std::vector<nlohmann::json>& groupEEPROM =
165 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
166 for (const auto& itemEEPROM : groupEEPROM)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600167 {
SunnySrivastava198443306542020-04-01 02:50:20 -0500168 bool isMotherboard = false;
Santosh Puranika0b23912022-02-10 13:37:09 +0530169 std::string redundantPath;
170
SunnySrivastava198443306542020-04-01 02:50:20 -0500171 if (itemEEPROM["extraInterfaces"].find(
172 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") !=
173 itemEEPROM["extraInterfaces"].end())
174 {
175 isMotherboard = true;
176 }
Santosh Puranika0b23912022-02-10 13:37:09 +0530177 if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end())
178 {
179 redundantPath = itemEEPROM["redundantEeprom"]
180 .get_ref<const nlohmann::json::string_t&>();
181 }
182 frus.emplace(
183 itemEEPROM["inventoryPath"]
184 .get_ref<const nlohmann::json::string_t&>(),
185 std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard));
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500186
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000187 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
Alpana Kumari920408d2020-05-14 00:07:03 -0500188 itemEEPROM["extraInterfaces"].end())
189 {
190 fruLocationCode.emplace(
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000191 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
Alpana Kumari920408d2020-05-14 00:07:03 -0500192 ["LocationCode"]
193 .get_ref<const nlohmann::json::string_t&>(),
194 itemEEPROM["inventoryPath"]
195 .get_ref<const nlohmann::json::string_t&>());
196 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500197
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500198 if (itemEEPROM.value("replaceableAtStandby", false))
SunnySrivastava19849a195542020-09-07 06:04:50 -0500199 {
200 replaceableFrus.emplace_back(itemFRUS.key());
201 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600202 }
203 }
204}
205
206void Manager::writeKeyword(const sdbusplus::message::object_path path,
207 const std::string recordName,
208 const std::string keyword, const Binary value)
209{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600210 try
211 {
Santosh Puranik8c796812021-12-01 19:17:56 +0530212 std::string objPath{path};
213 // Strip any inventory prefix in path
214 if (objPath.find(INVENTORY_PATH) == 0)
215 {
216 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
217 }
218
219 if (frus.find(objPath) == frus.end())
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600220 {
221 throw std::runtime_error("Inventory path not found");
222 }
223
Santosh Puranika0b23912022-02-10 13:37:09 +0530224 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600225
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500226 // instantiate editor class to update the data
Santosh Puranik8c796812021-12-01 19:17:56 +0530227 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530228
229 uint32_t offset = 0;
230 // Setup offset, if any
231 for (const auto& item : jsonFile["frus"][vpdFilePath])
232 {
233 if (item.find("offset") != item.end())
234 {
235 offset = item["offset"];
236 break;
237 }
238 }
239
240 edit.updateKeyword(value, offset, true);
241
242 // If we have a redundant EEPROM to update, then update just the EEPROM,
243 // not the cache since that is already done when we updated the primary
244 if (!std::get<1>(frus.find(objPath)->second).empty())
245 {
246 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile,
247 recordName, keyword);
248 edit.updateKeyword(value, offset, false);
249 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600250
SunnySrivastava198443306542020-04-01 02:50:20 -0500251 // if it is a motehrboard FRU need to check for location expansion
Santosh Puranika0b23912022-02-10 13:37:09 +0530252 if (std::get<2>(frus.find(objPath)->second))
SunnySrivastava198443306542020-04-01 02:50:20 -0500253 {
254 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE"))
255 {
256 edit.expandLocationCode("fcs");
257 }
258 else if (recordName == "VSYS" &&
259 (keyword == "TM" || keyword == "SE"))
260 {
261 edit.expandLocationCode("mts");
262 }
263 }
264
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500265 return;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600266 }
267 catch (const std::exception& e)
268 {
269 std::cerr << e.what() << std::endl;
270 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600271}
272
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500273ListOfPaths
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500274 Manager::getFRUsByUnexpandedLocationCode(const LocationCode locationCode,
275 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600276{
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500277 ReaderImpl read;
278 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600279}
280
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500281ListOfPaths
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500282 Manager::getFRUsByExpandedLocationCode(const LocationCode locationCode)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600283{
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500284 ReaderImpl read;
285 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600286}
287
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500288LocationCode Manager::getExpandedLocationCode(const LocationCode locationCode,
289 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600290{
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500291 ReaderImpl read;
292 return read.getExpandedLocationCode(locationCode, nodeNumber,
293 fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600294}
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600295
SunnySrivastava19849a195542020-09-07 06:04:50 -0500296void Manager::performVPDRecollection()
297{
298 // get list of FRUs replaceable at standby
299 for (const auto& item : replaceableFrus)
300 {
301 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
302 const nlohmann::json& singleFru = groupEEPROM[0];
303
304 const string& inventoryPath =
305 singleFru["inventoryPath"]
306 .get_ref<const nlohmann::json::string_t&>();
307
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530308 bool prePostActionRequired = false;
309
310 if ((jsonFile["frus"][item].at(0)).find("preAction") !=
311 jsonFile["frus"][item].at(0).end())
312 {
313 if (!executePreAction(jsonFile, item))
314 {
315 // if the FRU has preAction defined then its execution should
316 // pass to ensure bind/unbind of data.
317 // preAction execution failed. should not call bind/unbind.
318 log<level::ERR>(
319 "Pre-Action execution failed for the FRU",
320 entry("ERROR=%s",
321 ("Inventory path: " + inventoryPath).c_str()));
322 continue;
323 }
324 prePostActionRequired = true;
325 }
326
SunnySrivastava19849a195542020-09-07 06:04:50 -0500327 if ((singleFru.find("devAddress") == singleFru.end()) ||
328 (singleFru.find("driverType") == singleFru.end()) ||
329 (singleFru.find("busType") == singleFru.end()))
330 {
331 // The FRUs is marked for replacement but missing mandatory
332 // fields for recollection. Skip to another replaceable fru.
333 log<level::ERR>(
334 "Recollection Failed as mandatory field missing in Json",
335 entry("ERROR=%s",
336 ("Recollection failed for " + inventoryPath).c_str()));
337 continue;
338 }
339
340 string str = "echo ";
341 string deviceAddress = singleFru["devAddress"];
342 const string& driverType = singleFru["driverType"];
343 const string& busType = singleFru["busType"];
344
345 // devTreeStatus flag is present in json as false to mention
346 // that the EEPROM is not mentioned in device tree. If this flag
347 // is absent consider the value to be true, i.e EEPROM is
348 // mentioned in device tree
349 if (!singleFru.value("devTreeStatus", true))
350 {
351 auto pos = deviceAddress.find('-');
352 if (pos != string::npos)
353 {
354 string busNum = deviceAddress.substr(0, pos);
355 deviceAddress =
356 "0x" + deviceAddress.substr(pos + 1, string::npos);
357
358 string deleteDevice = str + deviceAddress + " > /sys/bus/" +
359 busType + "/devices/" + busType + "-" +
360 busNum + "/delete_device";
361 executeCmd(deleteDevice);
362
363 string addDevice = str + driverType + " " + deviceAddress +
364 " > /sys/bus/" + busType + "/devices/" +
365 busType + "-" + busNum + "/new_device";
366 executeCmd(addDevice);
367 }
368 else
369 {
370 log<level::ERR>(
371 "Wrong format of device address in Json",
372 entry(
373 "ERROR=%s",
374 ("Recollection failed for " + inventoryPath).c_str()));
375 continue;
376 }
377 }
378 else
379 {
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500380 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
381 driverType, "/unbind"));
382 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
383 driverType, "/bind"));
SunnySrivastava19849a195542020-09-07 06:04:50 -0500384 }
Santosh Puranikd40e42d2022-03-23 13:58:06 +0530385
386 // this check is added to avoid file system expensive call in case not
387 // required.
388 if (prePostActionRequired)
389 {
390 // Check if device showed up (test for file)
391 if (!filesystem::exists(item))
392 {
393 // If not, then take failure postAction
394 executePostFailAction(jsonFile, item);
395 }
396 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500397 }
398}
399
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600400} // namespace manager
401} // namespace vpd
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500402} // namespace openpower