blob: d391a0bdf5a8d754c5b3492751ac0d285ac5f41f [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
12#include <phosphor-logging/elog-errors.hpp>
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060013
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050014using namespace openpower::vpd::manager;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060015using namespace openpower::vpd::constants;
SunnySrivastava19841356d7e2020-04-24 04:29:35 -050016using namespace openpower::vpd::inventory;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -060017using namespace openpower::vpd::manager::editor;
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -050018using namespace openpower::vpd::manager::reader;
SunnySrivastava19849a195542020-09-07 06:04:50 -050019using namespace std;
20using namespace openpower::vpd::parser;
21using namespace openpower::vpd::exceptions;
22using namespace phosphor::logging;
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060023
24namespace openpower
25{
26namespace vpd
27{
28namespace manager
29{
30Manager::Manager(sdbusplus::bus::bus&& bus, const char* busName,
Priyanga Ramasamy9d149342020-07-16 23:41:26 +053031 const char* objPath, const char* /*iFace*/) :
SunnySrivastava1984b59fd092020-02-03 09:58:56 -060032 ServerObject<ManagerIface>(bus, objPath),
33 _bus(std::move(bus)), _manager(_bus, objPath)
34{
35 _bus.request_name(busName);
36}
37
38void Manager::run()
39{
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060040 try
41 {
42 processJSON();
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050043 listenHostState();
Alpana Kumarib17dd3b2020-10-01 00:18:10 -050044
45 auto event = sdeventplus::Event::get_default();
46 GpioMonitor gpioMon1(jsonFile, event);
47
48 _bus.attach_event(event.get(), SD_EVENT_PRIORITY_IMPORTANT);
49 cout << "VPD manager event loop started\n";
50 event.loop();
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060051 }
52 catch (const std::exception& e)
53 {
54 std::cerr << e.what() << "\n";
55 }
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -060056}
57
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -050058void Manager::listenHostState()
59{
60 static std::shared_ptr<sdbusplus::bus::match::match> hostState =
61 std::make_shared<sdbusplus::bus::match::match>(
62 _bus,
63 sdbusplus::bus::match::rules::propertiesChanged(
64 "/xyz/openbmc_project/state/host0",
65 "xyz.openbmc_project.State.Host"),
66 [this](sdbusplus::message::message& msg) {
67 hostStateCallBack(msg);
68 });
69}
70
71void Manager::hostStateCallBack(sdbusplus::message::message& msg)
72{
73 if (msg.is_method_error())
74 {
75 std::cerr << "Error in reading signal " << std::endl;
76 }
77
78 Path object;
79 PropertyMap propMap;
80 msg.read(object, propMap);
81 const auto itr = propMap.find("CurrentHostState");
82 if (itr != propMap.end())
83 {
84 if (auto hostState = std::get_if<std::string>(&(itr->second)))
85 {
86 // implies system is moving from standby to power on state
87 if (*hostState == "xyz.openbmc_project.State.Host.HostState."
88 "TransitioningToRunning")
89 {
90 // check and perfrom recollection for FRUs replaceable at
91 // standby.
92 performVPDRecollection();
93 return;
94 }
95 }
96 std::cerr << "Failed to read Host state" << std::endl;
97 }
98}
99
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600100void Manager::processJSON()
101{
Santosh Puranik0246a4d2020-11-04 16:57:39 +0530102 std::ifstream json(INVENTORY_JSON_SYM_LINK, std::ios::binary);
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600103
104 if (!json)
105 {
106 throw std::runtime_error("json file not found");
107 }
108
109 jsonFile = nlohmann::json::parse(json);
110 if (jsonFile.find("frus") == jsonFile.end())
111 {
112 throw std::runtime_error("frus group not found in json");
113 }
114
115 const nlohmann::json& groupFRUS =
116 jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
117 for (const auto& itemFRUS : groupFRUS.items())
118 {
119 const std::vector<nlohmann::json>& groupEEPROM =
120 itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
121 for (const auto& itemEEPROM : groupEEPROM)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600122 {
SunnySrivastava198443306542020-04-01 02:50:20 -0500123 bool isMotherboard = false;
Santosh Puranika0b23912022-02-10 13:37:09 +0530124 std::string redundantPath;
125
SunnySrivastava198443306542020-04-01 02:50:20 -0500126 if (itemEEPROM["extraInterfaces"].find(
127 "xyz.openbmc_project.Inventory.Item.Board.Motherboard") !=
128 itemEEPROM["extraInterfaces"].end())
129 {
130 isMotherboard = true;
131 }
Santosh Puranika0b23912022-02-10 13:37:09 +0530132 if (itemEEPROM.find("redundantEeprom") != itemEEPROM.end())
133 {
134 redundantPath = itemEEPROM["redundantEeprom"]
135 .get_ref<const nlohmann::json::string_t&>();
136 }
137 frus.emplace(
138 itemEEPROM["inventoryPath"]
139 .get_ref<const nlohmann::json::string_t&>(),
140 std::make_tuple(itemFRUS.key(), redundantPath, isMotherboard));
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500141
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000142 if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
Alpana Kumari920408d2020-05-14 00:07:03 -0500143 itemEEPROM["extraInterfaces"].end())
144 {
145 fruLocationCode.emplace(
Alpana Kumari414d5ae2021-03-04 21:06:35 +0000146 itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
Alpana Kumari920408d2020-05-14 00:07:03 -0500147 ["LocationCode"]
148 .get_ref<const nlohmann::json::string_t&>(),
149 itemEEPROM["inventoryPath"]
150 .get_ref<const nlohmann::json::string_t&>());
151 }
SunnySrivastava19849a195542020-09-07 06:04:50 -0500152
Sunny Srivastavaecb5c7d2021-09-02 07:20:24 -0500153 if (itemEEPROM.value("replaceableAtStandby", false))
SunnySrivastava19849a195542020-09-07 06:04:50 -0500154 {
155 replaceableFrus.emplace_back(itemFRUS.key());
156 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600157 }
158 }
159}
160
161void Manager::writeKeyword(const sdbusplus::message::object_path path,
162 const std::string recordName,
163 const std::string keyword, const Binary value)
164{
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600165 try
166 {
Santosh Puranik8c796812021-12-01 19:17:56 +0530167 std::string objPath{path};
168 // Strip any inventory prefix in path
169 if (objPath.find(INVENTORY_PATH) == 0)
170 {
171 objPath = objPath.substr(sizeof(INVENTORY_PATH) - 1);
172 }
173
174 if (frus.find(objPath) == frus.end())
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600175 {
176 throw std::runtime_error("Inventory path not found");
177 }
178
Santosh Puranika0b23912022-02-10 13:37:09 +0530179 inventory::Path vpdFilePath = std::get<0>(frus.find(objPath)->second);
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600180
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500181 // instantiate editor class to update the data
Santosh Puranik8c796812021-12-01 19:17:56 +0530182 EditorImpl edit(vpdFilePath, jsonFile, recordName, keyword, objPath);
Santosh Puranika0b23912022-02-10 13:37:09 +0530183
184 uint32_t offset = 0;
185 // Setup offset, if any
186 for (const auto& item : jsonFile["frus"][vpdFilePath])
187 {
188 if (item.find("offset") != item.end())
189 {
190 offset = item["offset"];
191 break;
192 }
193 }
194
195 edit.updateKeyword(value, offset, true);
196
197 // If we have a redundant EEPROM to update, then update just the EEPROM,
198 // not the cache since that is already done when we updated the primary
199 if (!std::get<1>(frus.find(objPath)->second).empty())
200 {
201 EditorImpl edit(std::get<1>(frus.find(objPath)->second), jsonFile,
202 recordName, keyword);
203 edit.updateKeyword(value, offset, false);
204 }
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600205
SunnySrivastava198443306542020-04-01 02:50:20 -0500206 // if it is a motehrboard FRU need to check for location expansion
Santosh Puranika0b23912022-02-10 13:37:09 +0530207 if (std::get<2>(frus.find(objPath)->second))
SunnySrivastava198443306542020-04-01 02:50:20 -0500208 {
209 if (recordName == "VCEN" && (keyword == "FC" || keyword == "SE"))
210 {
211 edit.expandLocationCode("fcs");
212 }
213 else if (recordName == "VSYS" &&
214 (keyword == "TM" || keyword == "SE"))
215 {
216 edit.expandLocationCode("mts");
217 }
218 }
219
SunnySrivastava19846d8314d2020-05-15 09:34:58 -0500220 return;
SunnySrivastava1984f6d541e2020-02-04 12:50:40 -0600221 }
222 catch (const std::exception& e)
223 {
224 std::cerr << e.what() << std::endl;
225 }
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600226}
227
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500228ListOfPaths
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500229 Manager::getFRUsByUnexpandedLocationCode(const LocationCode locationCode,
230 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600231{
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500232 ReaderImpl read;
233 return read.getFrusAtLocation(locationCode, nodeNumber, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600234}
235
SunnySrivastava19841356d7e2020-04-24 04:29:35 -0500236ListOfPaths
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500237 Manager::getFRUsByExpandedLocationCode(const LocationCode locationCode)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600238{
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500239 ReaderImpl read;
240 return read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600241}
242
SunnySrivastava1984fb5815a2020-04-24 08:03:52 -0500243LocationCode Manager::getExpandedLocationCode(const LocationCode locationCode,
244 const NodeNumber nodeNumber)
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600245{
SunnySrivastava1984bca5aaa2020-04-21 05:31:04 -0500246 ReaderImpl read;
247 return read.getExpandedLocationCode(locationCode, nodeNumber,
248 fruLocationCode);
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600249}
SunnySrivastava1984de3c60d2020-02-03 10:34:33 -0600250
SunnySrivastava19849a195542020-09-07 06:04:50 -0500251void Manager::performVPDRecollection()
252{
253 // get list of FRUs replaceable at standby
254 for (const auto& item : replaceableFrus)
255 {
256 const vector<nlohmann::json>& groupEEPROM = jsonFile["frus"][item];
257 const nlohmann::json& singleFru = groupEEPROM[0];
258
259 const string& inventoryPath =
260 singleFru["inventoryPath"]
261 .get_ref<const nlohmann::json::string_t&>();
262
263 if ((singleFru.find("devAddress") == singleFru.end()) ||
264 (singleFru.find("driverType") == singleFru.end()) ||
265 (singleFru.find("busType") == singleFru.end()))
266 {
267 // The FRUs is marked for replacement but missing mandatory
268 // fields for recollection. Skip to another replaceable fru.
269 log<level::ERR>(
270 "Recollection Failed as mandatory field missing in Json",
271 entry("ERROR=%s",
272 ("Recollection failed for " + inventoryPath).c_str()));
273 continue;
274 }
275
276 string str = "echo ";
277 string deviceAddress = singleFru["devAddress"];
278 const string& driverType = singleFru["driverType"];
279 const string& busType = singleFru["busType"];
280
281 // devTreeStatus flag is present in json as false to mention
282 // that the EEPROM is not mentioned in device tree. If this flag
283 // is absent consider the value to be true, i.e EEPROM is
284 // mentioned in device tree
285 if (!singleFru.value("devTreeStatus", true))
286 {
287 auto pos = deviceAddress.find('-');
288 if (pos != string::npos)
289 {
290 string busNum = deviceAddress.substr(0, pos);
291 deviceAddress =
292 "0x" + deviceAddress.substr(pos + 1, string::npos);
293
294 string deleteDevice = str + deviceAddress + " > /sys/bus/" +
295 busType + "/devices/" + busType + "-" +
296 busNum + "/delete_device";
297 executeCmd(deleteDevice);
298
299 string addDevice = str + driverType + " " + deviceAddress +
300 " > /sys/bus/" + busType + "/devices/" +
301 busType + "-" + busNum + "/new_device";
302 executeCmd(addDevice);
303 }
304 else
305 {
306 log<level::ERR>(
307 "Wrong format of device address in Json",
308 entry(
309 "ERROR=%s",
310 ("Recollection failed for " + inventoryPath).c_str()));
311 continue;
312 }
313 }
314 else
315 {
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500316 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
317 driverType, "/unbind"));
318 executeCmd(createBindUnbindDriverCmnd(deviceAddress, busType,
319 driverType, "/bind"));
SunnySrivastava19849a195542020-09-07 06:04:50 -0500320 }
321 }
322}
323
SunnySrivastava1984b59fd092020-02-03 09:58:56 -0600324} // namespace manager
325} // namespace vpd
Alpana Kumarib17dd3b2020-10-01 00:18:10 -0500326} // namespace openpower