blob: 8da6d8817cbe9a918c87aca6c9e466d960cf431f [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlercad9c2b2019-12-02 15:42:01 -060016#include "config.h"
17
Matt Spinlerc8705e22019-09-11 12:36:07 -050018#include "data_interface.hpp"
19
Matt Spinlerf61f2922020-06-23 11:32:49 -050020#include "util.hpp"
21
Vijay Lobo81b4dca2021-04-29 00:04:00 -050022#include <fmt/format.h>
23
Vijay Lobo81b4dca2021-04-29 00:04:00 -050024#include <phosphor-logging/log.hpp>
Matt Spinler5b423652023-05-04 13:08:44 -050025#include <xyz/openbmc_project/State/BMC/server.hpp>
Matt Spinlerf10068d2020-12-02 10:44:08 -060026#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Matt Spinlera7d9d962019-11-06 15:01:25 -060027
Patrick Williams2544b412022-10-04 08:41:06 -050028#include <fstream>
29#include <iterator>
30
Matt Spinler35a405b2022-03-02 11:42:42 -060031// Use a timeout of 10s for D-Bus calls so if there are
32// timeouts the callers of the PEL creation method won't
33// also timeout.
34constexpr auto dbusTimeout = 10000000;
35
Matt Spinlerc8705e22019-09-11 12:36:07 -050036namespace openpower
37{
38namespace pels
39{
40
41namespace service_name
42{
43constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050044constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050045constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050046constexpr auto logSetting = "xyz.openbmc_project.Settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050047constexpr auto hwIsolation = "org.open_power.HardwareIsolation";
Matt Spinler744d8512022-06-08 08:25:47 -050048constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050049constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinlerc8705e22019-09-11 12:36:07 -050050} // namespace service_name
51
52namespace object_path
53{
54constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
55constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050056constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050057constexpr auto motherBoardInv =
58 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060059constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060060constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
61constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060062constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060063constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060064constexpr auto enableHostPELs =
65 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050066constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050067constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050068constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Matt Spinler744d8512022-06-08 08:25:47 -050069constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050070constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0";
Matt Spinlerc8705e22019-09-11 12:36:07 -050071} // namespace object_path
72
73namespace interface
74{
75constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
76constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
77constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060078constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinlerb3f51862019-12-09 13:55:10 -060079constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060080constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060081constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
82constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
83constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060084constexpr auto invMotherboard =
85 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
86constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050087constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060088constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050089constexpr auto compatible =
90 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050091constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050092constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050093constexpr auto operationalStatus =
94 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050095constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060096constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050097constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
98constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050099constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar027bf282022-01-24 11:25:19 -0600100constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
101constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -0500102constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -0500103constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler5b423652023-05-04 13:08:44 -0500104constexpr auto invItem = "xyz.openbmc_project.Inventory.Item";
105constexpr auto invFan = "xyz.openbmc_project.Inventory.Item.Fan";
106constexpr auto invPowerSupply =
107 "xyz.openbmc_project.Inventory.Item.PowerSupply";
Matt Spinlerc8705e22019-09-11 12:36:07 -0500108} // namespace interface
109
Matt Spinlerf10068d2020-12-02 10:44:08 -0600110using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
Matt Spinler5b423652023-05-04 13:08:44 -0500111using namespace sdbusplus::xyz::openbmc_project::State::server;
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500112using namespace phosphor::logging;
Matt Spinler5b423652023-05-04 13:08:44 -0500113namespace match_rules = sdbusplus::bus::match::rules;
114
115const DBusInterfaceList hotplugInterfaces{interface::invFan,
116 interface::invPowerSupply};
Matt Spinlera7d9d962019-11-06 15:01:25 -0600117
Matt Spinler0d92b522021-06-16 13:28:17 -0600118std::pair<std::string, std::string>
119 DataInterfaceBase::extractConnectorFromLocCode(
120 const std::string& locationCode)
121{
122 auto base = locationCode;
123 std::string connector{};
124
125 auto pos = base.find("-T");
126 if (pos != std::string::npos)
127 {
128 connector = base.substr(pos);
129 base = base.substr(0, pos);
130 }
131
132 return {base, connector};
133}
134
Patrick Williams45e83522022-07-22 19:26:52 -0500135DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus)
Matt Spinlerc8705e22019-09-11 12:36:07 -0500136{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600137 readBMCFWVersion();
138 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600139 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600140
Matt Spinlerf10068d2020-12-02 10:44:08 -0600141 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600142 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600143 bus, object_path::hostState, interface::bootProgress, "BootProgress",
144 *this, [this](const auto& value) {
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500145 this->_bootState = std::get<std::string>(value);
Matt Spinlerf10068d2020-12-02 10:44:08 -0600146 auto status = Progress::convertProgressStagesFromString(
147 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600148
Matt Spinlerf10068d2020-12-02 10:44:08 -0600149 if ((status == Progress::ProgressStages::SystemInitComplete) ||
Matt Spinlerf10068d2020-12-02 10:44:08 -0600150 (status == Progress::ProgressStages::OSRunning))
Matt Spinler2a28c932020-02-03 14:23:40 -0600151 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600152 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600153 }
154 else
155 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600156 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600157 }
158 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600159
160 // Watch the host PEL enable property
161 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
162 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
163 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500164 if (std::get<bool>(value) != this->_sendPELsToHost)
165 {
166 log<level::INFO>(
167 fmt::format("The send PELs to host setting changed to {}",
168 std::get<bool>(value))
169 .c_str());
170 }
171 this->_sendPELsToHost = std::get<bool>(value);
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600172 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600173
174 // Watch the BMCState property
175 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
176 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
177 *this, [this](const auto& value) {
Matt Spinler5b423652023-05-04 13:08:44 -0500178 const auto& state = std::get<std::string>(value);
179 this->_bmcState = state;
180
181 // Wait for BMC ready to start watching for
182 // plugs so things calm down first.
183 if (BMC::convertBMCStateFromString(state) == BMC::BMCState::Ready)
184 {
185 startFruPlugWatch();
186 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600187 }));
188
189 // Watch the chassis current and requested power state properties
190 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
191 bus, object_path::chassisState, interface::chassisState, *this,
192 [this](const auto& properties) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500193 auto state = properties.find("CurrentPowerState");
194 if (state != properties.end())
195 {
196 this->_chassisState = std::get<std::string>(state->second);
197 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600198
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500199 auto trans = properties.find("RequestedPowerTransition");
200 if (trans != properties.end())
201 {
202 this->_chassisTransition = std::get<std::string>(trans->second);
203 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600204 }));
205
206 // Watch the CurrentHostState property
207 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
208 bus, object_path::hostState, interface::hostState, "CurrentHostState",
209 *this, [this](const auto& value) {
210 this->_hostState = std::get<std::string>(value);
211 }));
Matt Spinler744d8512022-06-08 08:25:47 -0500212
213 // Watch the BaseBIOSTable property for the hmc managed attribute
214 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
215 bus, object_path::biosConfigMgr, interface::biosConfigMgr,
216 "BaseBIOSTable", service_name::biosConfigMgr, *this,
217 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500218 const auto& attributes = std::get<BiosAttributes>(value);
Matt Spinler744d8512022-06-08 08:25:47 -0500219
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500220 auto it = attributes.find("pvm_hmc_managed");
221 if (it != attributes.end())
222 {
223 const auto& currentValVariant = std::get<5>(it->second);
224 auto currentVal = std::get_if<std::string>(&currentValVariant);
225 if (currentVal)
Matt Spinler744d8512022-06-08 08:25:47 -0500226 {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500227 this->_hmcManaged = (*currentVal == "Enabled") ? true : false;
Matt Spinler744d8512022-06-08 08:25:47 -0500228 }
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500229 }
Matt Spinler744d8512022-06-08 08:25:47 -0500230 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500231}
232
Matt Spinler2a28c932020-02-03 14:23:40 -0600233DBusPropertyMap
234 DataInterface::getAllProperties(const std::string& service,
235 const std::string& objectPath,
236 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500237{
238 DBusPropertyMap properties;
239
240 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
241 interface::dbusProperty, "GetAll");
242 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600243 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500244
245 reply.read(properties);
246
247 return properties;
248}
249
Matt Spinlera7d9d962019-11-06 15:01:25 -0600250void DataInterface::getProperty(const std::string& service,
251 const std::string& objectPath,
252 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600253 const std::string& property,
254 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600255{
Matt Spinlera7d9d962019-11-06 15:01:25 -0600256 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
257 interface::dbusProperty, "Get");
258 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600259 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600260
261 reply.read(value);
262}
263
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600264DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
265{
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600266 auto method = _bus.new_method_call(
267 service_name::objectMapper, object_path::objectMapper,
268 interface::objectMapper, "GetSubTreePaths");
269
270 method.append(std::string{"/"}, 0, interfaces);
271
Matt Spinler35a405b2022-03-02 11:42:42 -0600272 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600273
274 DBusPathList paths;
275 reply.read(paths);
276
277 return paths;
278}
279
Matt Spinlerc8705e22019-09-11 12:36:07 -0500280DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600281 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500282{
283 auto method = _bus.new_method_call(service_name::objectMapper,
284 object_path::objectMapper,
285 interface::objectMapper, "GetObject");
286
287 method.append(objectPath, std::vector<std::string>({interface}));
288
Matt Spinler35a405b2022-03-02 11:42:42 -0600289 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500290
291 std::map<DBusService, DBusInterfaceList> response;
292 reply.read(response);
293
294 if (!response.empty())
295 {
296 return response.begin()->first;
297 }
298
299 return std::string{};
300}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600301
Matt Spinler677381b2020-01-23 10:04:29 -0600302void DataInterface::readBMCFWVersion()
303{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500304 _bmcFWVersion =
305 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600306}
307
308void DataInterface::readServerFWVersion()
309{
Sumit Kumarcad16202021-05-13 04:06:15 -0500310 auto value =
311 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
312 if ((value != "") && (value.find_last_of(')') != std::string::npos))
313 {
314 std::size_t pos = value.find_first_of('(') + 1;
315 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
316 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600317}
318
Matt Spinler677381b2020-01-23 10:04:29 -0600319void DataInterface::readBMCFWVersionID()
320{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500321 _bmcFWVersionID =
322 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600323}
324
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500325std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600326{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500327 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600328 try
329 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500330 auto service = getService(object_path::systemInv, interface::invAsset);
331 if (!service.empty())
332 {
333 DBusValue value;
334 getProperty(service, object_path::systemInv, interface::invAsset,
335 "Model", value);
336
337 model = std::get<std::string>(value);
338 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600339 }
340 catch (const std::exception& e)
341 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500342 log<level::WARNING>(fmt::format("Failed reading Model property from "
343 "Interface: {} exception: {}",
344 interface::invAsset, e.what())
345 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600346 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500347
348 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600349}
350
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500351std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600352{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500353 std::string sn;
354 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600355 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500356 auto service = getService(object_path::systemInv, interface::invAsset);
357 if (!service.empty())
358 {
359 DBusValue value;
360 getProperty(service, object_path::systemInv, interface::invAsset,
361 "SerialNumber", value);
362
363 sn = std::get<std::string>(value);
364 }
365 }
366 catch (const std::exception& e)
367 {
368 log<level::WARNING>(
369 fmt::format("Failed reading SerialNumber property from "
370 "Interface: {} exception: {}",
371 interface::invAsset, e.what())
372 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600373 }
374
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500375 return sn;
376}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600377
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500378std::string DataInterface::getMotherboardCCIN() const
379{
380 std::string ccin;
381
382 try
383 {
Patrick Williams2544b412022-10-04 08:41:06 -0500384 auto service = getService(object_path::motherBoardInv,
385 interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500386 if (!service.empty())
387 {
388 DBusValue value;
389 getProperty(service, object_path::motherBoardInv,
390 interface::viniRecordVPD, "CC", value);
391
392 auto cc = std::get<std::vector<uint8_t>>(value);
393 ccin = std::string{cc.begin(), cc.end()};
394 }
395 }
396 catch (const std::exception& e)
397 {
398 log<level::WARNING>(
399 fmt::format("Failed reading Motherboard CCIN property from "
400 "Interface: {} exception: {}",
401 interface::viniRecordVPD, e.what())
402 .c_str());
403 }
404
405 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600406}
407
Ben Tynere32b7e72021-05-18 12:38:40 -0500408std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
409{
410 std::vector<uint8_t> systemIM;
411
412 try
413 {
Patrick Williams2544b412022-10-04 08:41:06 -0500414 auto service = getService(object_path::motherBoardInv,
415 interface::vsbpRecordVPD);
Ben Tynere32b7e72021-05-18 12:38:40 -0500416 if (!service.empty())
417 {
418 DBusValue value;
419 getProperty(service, object_path::motherBoardInv,
420 interface::vsbpRecordVPD, "IM", value);
421
422 systemIM = std::get<std::vector<uint8_t>>(value);
423 }
424 }
425 catch (const std::exception& e)
426 {
427 log<level::WARNING>(
428 fmt::format("Failed reading System IM property from "
429 "Interface: {} exception: {}",
430 interface::vsbpRecordVPD, e.what())
431 .c_str());
432 }
433
434 return systemIM;
435}
436
Matt Spinler60c4e792020-03-13 13:45:36 -0500437void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500438 std::string& fruPartNumber,
439 std::string& ccin,
440 std::string& serialNumber) const
441{
442 // For now, attempt to get all of the properties directly on the path
443 // passed in. In the future, may need to make use of an algorithm
444 // to figure out which inventory objects actually hold these
445 // interfaces in the case of non FRUs, or possibly another service
446 // will provide this info. Any missing interfaces will result
447 // in exceptions being thrown.
448
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500449 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500450
Patrick Williams2544b412022-10-04 08:41:06 -0500451 auto properties = getAllProperties(service, inventoryPath,
452 interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500453
454 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
455 fruPartNumber = std::string{value.begin(), value.end()};
456
457 value = std::get<std::vector<uint8_t>>(properties["CC"]);
458 ccin = std::string{value.begin(), value.end()};
459
460 value = std::get<std::vector<uint8_t>>(properties["SN"]);
461 serialNumber = std::string{value.begin(), value.end()};
462}
463
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500464std::string
465 DataInterface::getLocationCode(const std::string& inventoryPath) const
466{
467 auto service = getService(inventoryPath, interface::locCode);
468
469 DBusValue locCode;
470 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
471 locCode);
472
473 return std::get<std::string>(locCode);
474}
475
Matt Spinler5fb24c12020-06-04 11:21:33 -0500476std::string
477 DataInterface::addLocationCodePrefix(const std::string& locationCode)
478{
479 static const std::string locationCodePrefix{"Ufcs-"};
480
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500481 // Technically there are 2 location code prefixes, Ufcs and Umts, so
482 // if it already starts with a U then don't need to do anything.
483 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500484 {
485 return locationCodePrefix + locationCode;
486 }
487
488 return locationCode;
489}
490
491std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500492 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500493{
Matt Spinler0d92b522021-06-16 13:28:17 -0600494 // Location codes for connectors are the location code of the FRU they are
495 // on, plus a '-Tx' segment. Remove this last segment before expanding it
496 // and then add it back in afterwards. This way, the connector doesn't have
497 // to be in the model just so that it can be expanded.
498 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
499
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500500 auto method =
501 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
502 interface::vpdManager, "GetExpandedLocationCode");
503
Matt Spinler0d92b522021-06-16 13:28:17 -0600504 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500505
Matt Spinler35a405b2022-03-02 11:42:42 -0600506 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500507
508 std::string expandedLocationCode;
509 reply.read(expandedLocationCode);
510
Matt Spinler0d92b522021-06-16 13:28:17 -0600511 if (!connectorLoc.empty())
512 {
513 expandedLocationCode += connectorLoc;
514 }
515
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500516 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500517}
518
Matt Spinlerbad056b2023-01-25 14:16:57 -0600519std::vector<std::string>
Matt Spinler2f9225a2020-08-05 12:58:49 -0500520 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
521 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500522{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500523 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
524 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500525
Matt Spinler0d92b522021-06-16 13:28:17 -0600526 // Remove the connector segment, if present, so that this method call
527 // returns an inventory path that getHWCalloutFields() can be used with.
528 // (The serial number, etc, aren't stored on the connector in the
529 // inventory, and may not even be modeled.)
530 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
531
Matt Spinler2f9225a2020-08-05 12:58:49 -0500532 auto method =
533 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
534 interface::vpdManager, methodName.c_str());
535
536 if (expanded)
537 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600538 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500539 }
540 else
541 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600542 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500543 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500544
Matt Spinler35a405b2022-03-02 11:42:42 -0600545 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500546
547 std::vector<sdbusplus::message::object_path> entries;
548 reply.read(entries);
549
Matt Spinlerbad056b2023-01-25 14:16:57 -0600550 std::vector<std::string> paths;
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500551
Matt Spinlerbad056b2023-01-25 14:16:57 -0600552 // Note: The D-Bus method will fail if nothing found.
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500553 std::for_each(entries.begin(), entries.end(),
Matt Spinlerbad056b2023-01-25 14:16:57 -0600554 [&paths](const auto& path) { paths.push_back(path); });
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500555
Matt Spinlerbad056b2023-01-25 14:16:57 -0600556 return paths;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500557}
558
Matt Spinler34a904c2020-08-05 14:53:28 -0500559void DataInterface::assertLEDGroup(const std::string& ledGroup,
560 bool value) const
561{
562 DBusValue variant = value;
Patrick Williams2544b412022-10-04 08:41:06 -0500563 auto method = _bus.new_method_call(service_name::ledGroupManager,
564 ledGroup.c_str(),
565 interface::dbusProperty, "Set");
Matt Spinler34a904c2020-08-05 14:53:28 -0500566 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600567 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500568}
569
Matt Spinler993168d2021-04-07 16:05:03 -0500570void DataInterface::setFunctional(const std::string& objectPath,
571 bool value) const
572{
573 DBusValue variant = value;
574 auto service = getService(objectPath, interface::operationalStatus);
575
576 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
577 interface::dbusProperty, "Set");
578
579 method.append(interface::operationalStatus, "Functional", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600580 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500581}
582
Sumit Kumar76198a22021-07-15 05:59:57 -0500583using AssociationTuple = std::tuple<std::string, std::string, std::string>;
584using AssociationsProperty = std::vector<AssociationTuple>;
585
586void DataInterface::setCriticalAssociation(const std::string& objectPath) const
587{
588 DBusValue getAssociationValue;
589
Sumit Kumar027bf282022-01-24 11:25:19 -0600590 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500591
Sumit Kumar027bf282022-01-24 11:25:19 -0600592 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500593 getAssociationValue);
594
595 auto association = std::get<AssociationsProperty>(getAssociationValue);
596
597 AssociationTuple critAssociation{
598 "health_rollup", "critical",
599 "/xyz/openbmc_project/inventory/system/chassis"};
600
601 if (std::find(association.begin(), association.end(), critAssociation) ==
602 association.end())
603 {
604 association.push_back(critAssociation);
605 DBusValue setAssociationValue = association;
606
607 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
608 interface::dbusProperty, "Set");
609
Sumit Kumar027bf282022-01-24 11:25:19 -0600610 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500611 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600612 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500613 }
614}
615
Matt Spinler1ab66962020-10-29 13:21:44 -0500616std::vector<std::string> DataInterface::getSystemNames() const
617{
618 DBusSubTree subtree;
619 DBusValue names;
620
621 auto method = _bus.new_method_call(service_name::objectMapper,
622 object_path::objectMapper,
623 interface::objectMapper, "GetSubTree");
624 method.append(std::string{"/"}, 0,
625 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600626 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500627
628 reply.read(subtree);
629 if (subtree.empty())
630 {
631 throw std::runtime_error("Compatible interface not on D-Bus");
632 }
633
634 const auto& object = *(subtree.begin());
635 const auto& path = object.first;
636 const auto& service = object.second.begin()->first;
637
638 getProperty(service, path, interface::compatible, "Names", names);
639
640 return std::get<std::vector<std::string>>(names);
641}
642
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500643bool DataInterface::getQuiesceOnError() const
644{
645 bool ret = false;
646
647 try
648 {
Patrick Williams2544b412022-10-04 08:41:06 -0500649 auto service = getService(object_path::logSetting,
650 interface::logSetting);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500651 if (!service.empty())
652 {
653 DBusValue value;
654 getProperty(service, object_path::logSetting, interface::logSetting,
655 "QuiesceOnHwError", value);
656
657 ret = std::get<bool>(value);
658 }
659 }
660 catch (const std::exception& e)
661 {
662 log<level::WARNING>(
663 fmt::format("Failed reading QuiesceOnHwError property from "
664 "Interface: {} exception: {}",
665 interface::logSetting, e.what())
666 .c_str());
667 }
668
669 return ret;
670}
671
Sumit Kumar9d43a722021-08-24 09:46:19 -0500672std::vector<bool>
673 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
674{
675 DBusSubTree subtree;
676 std::vector<bool> result(type.size(), false);
677
678 // Query GetSubTree for the availability of dump interface
679 auto method = _bus.new_method_call(service_name::objectMapper,
680 object_path::objectMapper,
681 interface::objectMapper, "GetSubTree");
682 method.append(std::string{"/"}, 0,
683 std::vector<std::string>{interface::dumpEntry});
Matt Spinler35a405b2022-03-02 11:42:42 -0600684 auto reply = _bus.call(method, dbusTimeout);
Sumit Kumar9d43a722021-08-24 09:46:19 -0500685
686 reply.read(subtree);
687
688 if (subtree.empty())
689 {
690 return result;
691 }
692
693 std::vector<bool>::iterator itDumpStatus = result.begin();
694 uint8_t count = 0;
695 for (const auto& [path, serviceInfo] : subtree)
696 {
697 const auto& service = serviceInfo.begin()->first;
698 // Check for dump type on the object path
699 for (const auto& it : type)
700 {
701 if (path.find(it) != std::string::npos)
702 {
703 DBusValue value, progress;
704
705 // If dump type status is already available go for next path
706 if (*itDumpStatus)
707 {
708 break;
709 }
710
711 // Check for valid dump to be available if following
712 // conditions are met for the dump entry path -
713 // Offloaded == false and Status == Completed
714 getProperty(service, path, interface::dumpEntry, "Offloaded",
715 value);
716 getProperty(service, path, interface::dumpProgress, "Status",
717 progress);
718 auto offload = std::get<bool>(value);
719 auto status = std::get<std::string>(progress);
720 if (!offload && (status.find("Completed") != std::string::npos))
721 {
722 *itDumpStatus = true;
723 count++;
724 if (count >= type.size())
725 {
726 return result;
727 }
728 break;
729 }
730 }
Matt Spinler45796e82022-07-01 11:25:27 -0500731 ++itDumpStatus;
Sumit Kumar9d43a722021-08-24 09:46:19 -0500732 }
733 itDumpStatus = result.begin();
734 }
735
736 return result;
737}
738
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500739void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
740 const std::string& type,
741 const std::string& logPath) const
742{
743 try
744 {
745 auto method = _bus.new_method_call(
746 service_name::hwIsolation, object_path::hwIsolation,
747 interface::hwIsolationCreate, "CreateWithEntityPath");
748 method.append(binPath, type, sdbusplus::message::object_path(logPath));
749 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
750 // api's. Making d-bus call no reply type to avoid cyclic dependency.
751 // Added minimal timeout to catch initial failures.
752 // Need to revisit this design later to avoid cyclic dependency.
Matt Spinler35a405b2022-03-02 11:42:42 -0600753 constexpr auto hwIsolationTimeout = 100000; // in micro seconds
754 _bus.call_noreply(method, hwIsolationTimeout);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500755 }
756
Patrick Williams45e83522022-07-22 19:26:52 -0500757 catch (const sdbusplus::exception_t& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500758 {
759 std::string errName = e.name();
760 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
761 // mentioned above. Ignoring the error.
762 if (errName != SD_BUS_ERROR_TIMEOUT)
763 {
764 log<level::ERR>(
765 fmt::format("GUARD D-Bus call exception"
766 "OBJPATH={}, INTERFACE={}, EXCEPTION={}",
767 object_path::hwIsolation,
768 interface::hwIsolationCreate, e.what())
769 .c_str());
770 }
771 }
772}
Sumit Kumar3e274432021-09-14 06:37:56 -0500773
774void DataInterface::createProgressSRC(
775 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
776{
777 DBusValue variant = std::make_tuple(priSRC, srcStruct);
778
779 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500780 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500781 interface::dbusProperty, "Set");
782
783 method.append(interface::bootRawProgress, "Value", variant);
784
Matt Spinler35a405b2022-03-02 11:42:42 -0600785 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500786}
Sumit Kumar027bf282022-01-24 11:25:19 -0600787
788std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
789{
790 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
791 std::string hwErrorLog = "/isolated_hw_errorlog";
792 std::string errorLog = "/error_log";
793 DBusPathList paths;
794 std::vector<uint32_t> ids;
795
796 // Get all latest mapper associations
797 paths = getPaths(association);
798 for (auto& path : paths)
799 {
800 // Look for object path with hardware isolation entry if any
801 size_t pos = path.find(hwErrorLog);
802 if (pos != std::string::npos)
803 {
804 // Get the object path
805 std::string ph = path;
806 ph.erase(pos, hwErrorLog.length());
807 auto service = getService(ph, interface::hwIsolationEntry);
808 if (!service.empty())
809 {
810 bool status;
811 DBusValue value;
812
813 // Read the Resolved property from object path
814 getProperty(service, ph, interface::hwIsolationEntry,
815 "Resolved", value);
816
817 status = std::get<bool>(value);
818
819 // If the entry isn't resolved
820 if (!status)
821 {
Patrick Williams2544b412022-10-04 08:41:06 -0500822 auto assocService = getService(path,
823 interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500824 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600825 {
Matt Spinler45796e82022-07-01 11:25:27 -0500826 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600827
828 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500829 getProperty(assocService, path, interface::association,
830 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600831
832 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500833 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600834 if (!logPath.empty())
835 {
836 // Get OpenBMC event log Id
837 uint32_t id = stoi(logPath[0].substr(
838 logPath[0].find_last_of('/') + 1));
839 ids.push_back(id);
840 }
841 }
842 }
843 }
844 }
845
846 // Look for object path with error_log entry if any
847 pos = path.find(errorLog);
848 if (pos != std::string::npos)
849 {
850 auto service = getService(path, interface::association);
851 if (!service.empty())
852 {
853 DBusValue value;
854
855 // Read Endpoints property
856 getProperty(service, path, interface::association, "endpoints",
857 value);
858
859 auto logPath = std::get<std::vector<std::string>>(value);
860 if (!logPath.empty())
861 {
862 // Get OpenBMC event log Id
863 uint32_t id = stoi(
864 logPath[0].substr(logPath[0].find_last_of('/') + 1));
865 ids.push_back(id);
866 }
867 }
868 }
869 }
870
871 if (ids.size() > 1)
872 {
873 // remove duplicates to have only unique ids
874 std::sort(ids.begin(), ids.end());
875 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
876 }
877 return ids;
878}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500879
880std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
881{
882 using RawProgressProperty = std::tuple<uint64_t, std::vector<uint8_t>>;
883
884 DBusValue value;
885 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
886 interface::bootRawProgress, "Value", value);
887
888 const auto& rawProgress = std::get<RawProgressProperty>(value);
889 return std::get<1>(rawProgress);
890}
891
Matt Spinler5b423652023-05-04 13:08:44 -0500892void DataInterface::startFruPlugWatch()
893{
894 // Add a watch on inventory InterfacesAdded and then find all
895 // existing hotpluggable interfaces and add propertiesChanged
896 // watches on them.
897
898 _invIaMatch = std::make_unique<sdbusplus::bus::match_t>(
899 _bus, match_rules::interfacesAdded(object_path::baseInv),
900 std::bind(&DataInterface::inventoryIfaceAdded, this,
901 std::placeholders::_1));
902 try
903 {
904 auto paths = getPaths(hotplugInterfaces);
905
906 _invPresentMatches.clear();
907
908 std::for_each(paths.begin(), paths.end(),
909 [this](const auto& path) { addHotplugWatch(path); });
910 }
911 catch (const sdbusplus::exception_t& e)
912 {
913 log<level::WARNING>(
914 fmt::format("Failed getting FRU paths to watch: {}", e.what())
915 .c_str());
916 }
917}
918
919void DataInterface::addHotplugWatch(const std::string& path)
920{
921 if (!_invPresentMatches.contains(path))
922 {
923 _invPresentMatches.emplace(
924 path,
925 std::make_unique<sdbusplus::bus::match_t>(
926 _bus, match_rules::propertiesChanged(path, interface::invItem),
927 std::bind(&DataInterface::presenceChanged, this,
928 std::placeholders::_1)));
929 }
930}
931
932void DataInterface::inventoryIfaceAdded(sdbusplus::message_t& msg)
933{
934 sdbusplus::message::object_path path;
935 DBusInterfaceMap interfaces;
936
937 msg.read(path, interfaces);
938
939 // Check if any of the new interfaces are for hot pluggable FRUs.
940 if (std::find_if(interfaces.begin(), interfaces.end(),
941 [](const auto& interfacePair) {
942 return std::find(hotplugInterfaces.begin(), hotplugInterfaces.end(),
943 interfacePair.first) != hotplugInterfaces.end();
944 }) == interfaces.end())
945 {
946 return;
947 }
948
949 addHotplugWatch(path.str);
950
951 // If an Inventory.Item interface was also added, check presence now.
952
953 // Notes:
954 // * This assumes the Inv.Item and Inv.Fan/PS are added together which
955 // is currently the case.
956 // * If the code ever switches to something without a Present
957 // property, then the IA signal itself would probably indicate presence.
958
959 auto itemIt = interfaces.find(interface::invItem);
960 if (itemIt != interfaces.end())
961 {
962 notifyPresenceSubsribers(path.str, itemIt->second);
963 }
964}
965
966void DataInterface::presenceChanged(sdbusplus::message_t& msg)
967{
968 DBusInterface interface;
969 DBusPropertyMap properties;
970
971 msg.read(interface, properties);
972 if (interface != interface::invItem)
973 {
974 return;
975 }
976
977 std::string path = msg.get_path();
978 notifyPresenceSubsribers(path, properties);
979}
980
981void DataInterface::notifyPresenceSubsribers(const std::string& path,
982 const DBusPropertyMap& properties)
983{
984 try
985 {
986 auto prop = properties.find("Present");
987 if (prop != properties.end())
988 {
989 if (std::get<bool>(prop->second))
990 {
991 auto locCode = getLocationCode(path);
992 log<level::INFO>(
993 fmt::format("Detected FRU {} ({}) present ", path, locCode)
994 .c_str());
995 // Tell the subscribers.
996 setFruPresent(locCode);
997 }
998 }
999 }
1000 catch (const std::exception& e)
1001 {
1002 log<level::ERR>(
1003 fmt::format("Failed while processing presence for {}: {}", path,
1004 e.what())
1005 .c_str());
1006 }
1007}
Matt Spinlerc8705e22019-09-11 12:36:07 -05001008} // namespace pels
1009} // namespace openpower