blob: b812e976301b72bdf51919f236a1750eea2a4198 [file] [log] [blame]
Alexander Hansen40fb5492025-10-28 17:56:12 +01001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
Matt Spinlercad9c2b2019-12-02 15:42:01 -06003
Matt Spinlerc8705e22019-09-11 12:36:07 -05004#include "data_interface.hpp"
5
Matt Spinlerf61f2922020-06-23 11:32:49 -05006#include "util.hpp"
7
Matt Spinlera167a7d2023-06-30 15:14:25 -05008#include <phosphor-logging/lg2.hpp>
Matt Spinler5b423652023-05-04 13:08:44 -05009#include <xyz/openbmc_project/State/BMC/server.hpp>
Matt Spinlerf10068d2020-12-02 10:44:08 -060010#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Matt Spinlera7d9d962019-11-06 15:01:25 -060011
Arya K Padmanafba3162024-08-30 07:41:32 -050012#include <filesystem>
13
Arya K Padmand8ae6182024-07-19 06:25:10 -050014#ifdef PEL_ENABLE_PHAL
Arya K Padmanafba3162024-08-30 07:41:32 -050015#include <libekb.H>
16#include <libpdbg.h>
Arya K Padmand8ae6182024-07-19 06:25:10 -050017#include <libphal.H>
18#endif
19
Matt Spinler35a405b2022-03-02 11:42:42 -060020// Use a timeout of 10s for D-Bus calls so if there are
21// timeouts the callers of the PEL creation method won't
22// also timeout.
23constexpr auto dbusTimeout = 10000000;
24
Matt Spinlerc8705e22019-09-11 12:36:07 -050025namespace openpower
26{
27namespace pels
28{
29
30namespace service_name
31{
32constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050033constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050034constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
Matt Spinler744d8512022-06-08 08:25:47 -050035constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050036constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler52ee3a42023-07-27 14:54:48 -050037constexpr auto pldm = "xyz.openbmc_project.PLDM";
Matt Spinler412f50e2023-11-14 12:49:52 -060038constexpr auto inventoryManager = "xyz.openbmc_project.Inventory.Manager";
Matt Spinlerbbc11ef2024-01-11 16:26:51 -060039constexpr auto entityManager = "xyz.openbmc_project.EntityManager";
Arya K Padmanafba3162024-08-30 07:41:32 -050040constexpr auto systemd = "org.freedesktop.systemd1";
Matt Spinlerc8705e22019-09-11 12:36:07 -050041} // namespace service_name
42
43namespace object_path
44{
45constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
46constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050047constexpr auto motherBoardInv =
48 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060049constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060050constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
51constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060052constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060053constexpr auto enableHostPELs =
54 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050055constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050056constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Matt Spinler744d8512022-06-08 08:25:47 -050057constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050058constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0";
Arya K Padmanafba3162024-08-30 07:41:32 -050059constexpr auto systemd = "/org/freedesktop/systemd1";
Matt Spinlerc8705e22019-09-11 12:36:07 -050060} // namespace object_path
61
62namespace interface
63{
64constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
65constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
66constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060067constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060068constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060069constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
70constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
71constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060072constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050073constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060074constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050075constexpr auto compatible =
Matt Spinlerbbc11ef2024-01-11 16:26:51 -060076 "xyz.openbmc_project.Inventory.Decorator.Compatible";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050077constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050078constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050079constexpr auto operationalStatus =
80 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050081constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060082constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar027bf282022-01-24 11:25:19 -060083constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
84constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -050085constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050086constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler5b423652023-05-04 13:08:44 -050087constexpr auto invItem = "xyz.openbmc_project.Inventory.Item";
88constexpr auto invFan = "xyz.openbmc_project.Inventory.Item.Fan";
89constexpr auto invPowerSupply =
90 "xyz.openbmc_project.Inventory.Item.PowerSupply";
Matt Spinler412f50e2023-11-14 12:49:52 -060091constexpr auto inventoryManager = "xyz.openbmc_project.Inventory.Manager";
Arya K Padmanafba3162024-08-30 07:41:32 -050092constexpr auto systemdMgr = "org.freedesktop.systemd1.Manager";
Matt Spinlerc8705e22019-09-11 12:36:07 -050093} // namespace interface
94
Willy Tu6ddbf692023-09-05 10:54:16 -070095using namespace sdbusplus::server::xyz::openbmc_project::state::boot;
96using namespace sdbusplus::server::xyz::openbmc_project::state;
Matt Spinler5b423652023-05-04 13:08:44 -050097namespace match_rules = sdbusplus::bus::match::rules;
98
99const DBusInterfaceList hotplugInterfaces{interface::invFan,
100 interface::invPowerSupply};
Arya K Padmanafba3162024-08-30 07:41:32 -0500101static constexpr auto PDBG_DTB_PATH =
102 "/var/lib/phosphor-software-manager/hostfw/running/DEVTREE";
Matt Spinlera7d9d962019-11-06 15:01:25 -0600103
Matt Spinler0d92b522021-06-16 13:28:17 -0600104std::pair<std::string, std::string>
105 DataInterfaceBase::extractConnectorFromLocCode(
106 const std::string& locationCode)
107{
108 auto base = locationCode;
109 std::string connector{};
110
111 auto pos = base.find("-T");
112 if (pos != std::string::npos)
113 {
114 connector = base.substr(pos);
115 base = base.substr(0, pos);
116 }
117
118 return {base, connector};
119}
120
Arya K Padmanafba3162024-08-30 07:41:32 -0500121DataInterface::DataInterface(sdbusplus::bus_t& bus) :
122 _bus(bus), _systemdSlot(nullptr)
Matt Spinlerc8705e22019-09-11 12:36:07 -0500123{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600124 readBMCFWVersion();
125 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600126 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600127
Matt Spinlerf10068d2020-12-02 10:44:08 -0600128 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600129 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600130 bus, object_path::hostState, interface::bootProgress, "BootProgress",
131 *this, [this](const auto& value) {
Patrick Williams075c7922024-08-16 15:19:49 -0400132 this->_bootState = std::get<std::string>(value);
133 auto status = Progress::convertProgressStagesFromString(
134 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600135
Patrick Williams075c7922024-08-16 15:19:49 -0400136 if ((status == Progress::ProgressStages::SystemInitComplete) ||
137 (status == Progress::ProgressStages::OSRunning))
138 {
139 setHostUp(true);
140 }
141 else
142 {
143 setHostUp(false);
144 }
145 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600146
147 // Watch the host PEL enable property
148 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
149 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
150 [this](const auto& value) {
Patrick Williams075c7922024-08-16 15:19:49 -0400151 if (std::get<bool>(value) != this->_sendPELsToHost)
152 {
153 lg2::info("The send PELs to host setting changed to {VAL}",
154 "VAL", std::get<bool>(value));
155 }
156 this->_sendPELsToHost = std::get<bool>(value);
157 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600158
159 // Watch the BMCState property
160 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
161 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
162 *this, [this](const auto& value) {
Patrick Williams075c7922024-08-16 15:19:49 -0400163 const auto& state = std::get<std::string>(value);
164 this->_bmcState = state;
Matt Spinler5b423652023-05-04 13:08:44 -0500165
Patrick Williams075c7922024-08-16 15:19:49 -0400166 // Wait for BMC ready to start watching for
167 // plugs so things calm down first.
168 if (BMC::convertBMCStateFromString(state) == BMC::BMCState::Ready)
169 {
170 startFruPlugWatch();
171 }
172 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600173
174 // Watch the chassis current and requested power state properties
175 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
176 bus, object_path::chassisState, interface::chassisState, *this,
177 [this](const auto& properties) {
Patrick Williams075c7922024-08-16 15:19:49 -0400178 auto state = properties.find("CurrentPowerState");
179 if (state != properties.end())
180 {
181 this->_chassisState = std::get<std::string>(state->second);
182 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600183
Patrick Williams075c7922024-08-16 15:19:49 -0400184 auto trans = properties.find("RequestedPowerTransition");
185 if (trans != properties.end())
186 {
187 this->_chassisTransition = std::get<std::string>(trans->second);
188 }
189 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600190
191 // Watch the CurrentHostState property
192 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
193 bus, object_path::hostState, interface::hostState, "CurrentHostState",
194 *this, [this](const auto& value) {
Patrick Williams075c7922024-08-16 15:19:49 -0400195 this->_hostState = std::get<std::string>(value);
196 }));
Matt Spinler744d8512022-06-08 08:25:47 -0500197
198 // Watch the BaseBIOSTable property for the hmc managed attribute
199 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
200 bus, object_path::biosConfigMgr, interface::biosConfigMgr,
201 "BaseBIOSTable", service_name::biosConfigMgr, *this,
202 [this](const auto& value) {
Patrick Williams075c7922024-08-16 15:19:49 -0400203 const auto& attributes = std::get<BiosAttributes>(value);
Matt Spinler744d8512022-06-08 08:25:47 -0500204
Patrick Williams075c7922024-08-16 15:19:49 -0400205 auto it = attributes.find("pvm_hmc_managed");
206 if (it != attributes.end())
Matt Spinler744d8512022-06-08 08:25:47 -0500207 {
Patrick Williams075c7922024-08-16 15:19:49 -0400208 const auto& currentValVariant = std::get<5>(it->second);
209 auto currentVal = std::get_if<std::string>(&currentValVariant);
210 if (currentVal)
211 {
212 this->_hmcManaged =
213 (*currentVal == "Enabled") ? true : false;
214 }
Matt Spinler744d8512022-06-08 08:25:47 -0500215 }
Patrick Williams075c7922024-08-16 15:19:49 -0400216 }));
Arya K Padmanafba3162024-08-30 07:41:32 -0500217
Arya K Padmanafba3162024-08-30 07:41:32 -0500218 if (isPHALDevTreeExist())
219 {
Arya K Padman0b758fb2024-09-06 11:59:45 -0500220#ifdef PEL_ENABLE_PHAL
Arya K Padmanafba3162024-08-30 07:41:32 -0500221 initPHAL();
Arya K Padman0b758fb2024-09-06 11:59:45 -0500222#endif
Arya K Padmanafba3162024-08-30 07:41:32 -0500223 }
224 else
225 {
226 // Watch the "openpower-update-bios-attr-table" service to init
227 // PHAL libraries
228 subscribeToSystemdSignals();
229 }
Matt Spinlerc8705e22019-09-11 12:36:07 -0500230}
231
Patrick Williams075c7922024-08-16 15:19:49 -0400232DBusPropertyMap DataInterface::getAllProperties(
233 const std::string& service, const std::string& objectPath,
234 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500235{
236 DBusPropertyMap properties;
237
238 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
239 interface::dbusProperty, "GetAll");
240 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600241 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500242
243 reply.read(properties);
244
245 return properties;
246}
247
Patrick Williams075c7922024-08-16 15:19:49 -0400248void DataInterface::getProperty(
249 const std::string& service, const std::string& objectPath,
250 const std::string& interface, const std::string& property,
251 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600252{
Matt Spinlera7d9d962019-11-06 15:01:25 -0600253 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
254 interface::dbusProperty, "Get");
255 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600256 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600257
258 reply.read(value);
259}
260
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600261DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
262{
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600263 auto method = _bus.new_method_call(
264 service_name::objectMapper, object_path::objectMapper,
265 interface::objectMapper, "GetSubTreePaths");
266
267 method.append(std::string{"/"}, 0, interfaces);
268
Matt Spinler35a405b2022-03-02 11:42:42 -0600269 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600270
Patrick Williamsb05e07c2025-11-05 00:03:06 -0500271 auto paths = reply.unpack<DBusPathList>();
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600272
273 return paths;
274}
275
Matt Spinlerc8705e22019-09-11 12:36:07 -0500276DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600277 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500278{
279 auto method = _bus.new_method_call(service_name::objectMapper,
280 object_path::objectMapper,
281 interface::objectMapper, "GetObject");
282
283 method.append(objectPath, std::vector<std::string>({interface}));
284
Matt Spinler35a405b2022-03-02 11:42:42 -0600285 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500286
Patrick Williamsb05e07c2025-11-05 00:03:06 -0500287 auto response = reply.unpack<std::map<DBusService, DBusInterfaceList>>();
Matt Spinlerc8705e22019-09-11 12:36:07 -0500288
289 if (!response.empty())
290 {
291 return response.begin()->first;
292 }
293
294 return std::string{};
295}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600296
Matt Spinler677381b2020-01-23 10:04:29 -0600297void DataInterface::readBMCFWVersion()
298{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500299 _bmcFWVersion =
300 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600301}
302
303void DataInterface::readServerFWVersion()
304{
Sumit Kumarcad16202021-05-13 04:06:15 -0500305 auto value =
306 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
307 if ((value != "") && (value.find_last_of(')') != std::string::npos))
308 {
309 std::size_t pos = value.find_first_of('(') + 1;
310 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
311 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600312}
313
Matt Spinler677381b2020-01-23 10:04:29 -0600314void DataInterface::readBMCFWVersionID()
315{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500316 _bmcFWVersionID =
317 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600318}
319
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500320std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600321{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500322 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600323 try
324 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500325 auto service = getService(object_path::systemInv, interface::invAsset);
326 if (!service.empty())
327 {
328 DBusValue value;
329 getProperty(service, object_path::systemInv, interface::invAsset,
330 "Model", value);
331
332 model = std::get<std::string>(value);
333 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600334 }
335 catch (const std::exception& e)
336 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500337 lg2::warning("Failed reading Model property from "
338 "interface: {IFACE} exception: {ERROR}",
339 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600340 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500341
342 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600343}
344
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500345std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600346{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500347 std::string sn;
348 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600349 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500350 auto service = getService(object_path::systemInv, interface::invAsset);
351 if (!service.empty())
352 {
353 DBusValue value;
354 getProperty(service, object_path::systemInv, interface::invAsset,
355 "SerialNumber", value);
356
357 sn = std::get<std::string>(value);
358 }
359 }
360 catch (const std::exception& e)
361 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500362 lg2::warning("Failed reading SerialNumber property from "
363 "interface: {IFACE} exception: {ERROR}",
364 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600365 }
366
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500367 return sn;
368}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600369
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500370std::string DataInterface::getMotherboardCCIN() const
371{
372 std::string ccin;
373
374 try
375 {
Patrick Williams075c7922024-08-16 15:19:49 -0400376 auto service =
377 getService(object_path::motherBoardInv, interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500378 if (!service.empty())
379 {
380 DBusValue value;
381 getProperty(service, object_path::motherBoardInv,
382 interface::viniRecordVPD, "CC", value);
383
384 auto cc = std::get<std::vector<uint8_t>>(value);
385 ccin = std::string{cc.begin(), cc.end()};
386 }
387 }
388 catch (const std::exception& e)
389 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500390 lg2::warning("Failed reading Motherboard CCIN property from "
391 "interface: {IFACE} exception: {ERROR}",
392 "IFACE", interface::viniRecordVPD, "ERROR", e);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500393 }
394
395 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600396}
397
Ben Tynere32b7e72021-05-18 12:38:40 -0500398std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
399{
400 std::vector<uint8_t> systemIM;
401
402 try
403 {
Patrick Williams075c7922024-08-16 15:19:49 -0400404 auto service =
405 getService(object_path::motherBoardInv, interface::vsbpRecordVPD);
Ben Tynere32b7e72021-05-18 12:38:40 -0500406 if (!service.empty())
407 {
408 DBusValue value;
409 getProperty(service, object_path::motherBoardInv,
410 interface::vsbpRecordVPD, "IM", value);
411
412 systemIM = std::get<std::vector<uint8_t>>(value);
413 }
414 }
415 catch (const std::exception& e)
416 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500417 lg2::warning("Failed reading System IM property from "
418 "interface: {IFACE} exception: {ERROR}",
419 "IFACE", interface::vsbpRecordVPD, "ERROR", e);
Ben Tynere32b7e72021-05-18 12:38:40 -0500420 }
421
422 return systemIM;
423}
424
Patrick Williams075c7922024-08-16 15:19:49 -0400425void DataInterface::getHWCalloutFields(
426 const std::string& inventoryPath, std::string& fruPartNumber,
427 std::string& ccin, std::string& serialNumber) const
Matt Spinler60c4e792020-03-13 13:45:36 -0500428{
429 // For now, attempt to get all of the properties directly on the path
430 // passed in. In the future, may need to make use of an algorithm
431 // to figure out which inventory objects actually hold these
432 // interfaces in the case of non FRUs, or possibly another service
433 // will provide this info. Any missing interfaces will result
434 // in exceptions being thrown.
435
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500436 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500437
Patrick Williams075c7922024-08-16 15:19:49 -0400438 auto properties =
439 getAllProperties(service, inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500440
441 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
442 fruPartNumber = std::string{value.begin(), value.end()};
443
444 value = std::get<std::vector<uint8_t>>(properties["CC"]);
445 ccin = std::string{value.begin(), value.end()};
446
447 value = std::get<std::vector<uint8_t>>(properties["SN"]);
448 serialNumber = std::string{value.begin(), value.end()};
449}
450
Patrick Williams25291152025-02-01 08:21:42 -0500451std::string DataInterface::getLocationCode(
452 const std::string& inventoryPath) const
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500453{
454 auto service = getService(inventoryPath, interface::locCode);
455
456 DBusValue locCode;
457 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
458 locCode);
459
460 return std::get<std::string>(locCode);
461}
462
Patrick Williams25291152025-02-01 08:21:42 -0500463std::string DataInterface::addLocationCodePrefix(
464 const std::string& locationCode)
Matt Spinler5fb24c12020-06-04 11:21:33 -0500465{
466 static const std::string locationCodePrefix{"Ufcs-"};
467
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500468 // Technically there are 2 location code prefixes, Ufcs and Umts, so
469 // if it already starts with a U then don't need to do anything.
470 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500471 {
472 return locationCodePrefix + locationCode;
473 }
474
475 return locationCode;
476}
477
478std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500479 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500480{
Matt Spinler0d92b522021-06-16 13:28:17 -0600481 // Location codes for connectors are the location code of the FRU they are
482 // on, plus a '-Tx' segment. Remove this last segment before expanding it
483 // and then add it back in afterwards. This way, the connector doesn't have
484 // to be in the model just so that it can be expanded.
485 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
486
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500487 auto method =
488 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
489 interface::vpdManager, "GetExpandedLocationCode");
490
Matt Spinler0d92b522021-06-16 13:28:17 -0600491 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500492
Matt Spinler35a405b2022-03-02 11:42:42 -0600493 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500494
Patrick Williamsb05e07c2025-11-05 00:03:06 -0500495 auto expandedLocationCode = reply.unpack<std::string>();
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500496
Matt Spinler0d92b522021-06-16 13:28:17 -0600497 if (!connectorLoc.empty())
498 {
499 expandedLocationCode += connectorLoc;
500 }
501
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500502 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500503}
504
Patrick Williams075c7922024-08-16 15:19:49 -0400505std::vector<std::string> DataInterface::getInventoryFromLocCode(
506 const std::string& locationCode, uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500507{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500508 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
509 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500510
Matt Spinler0d92b522021-06-16 13:28:17 -0600511 // Remove the connector segment, if present, so that this method call
512 // returns an inventory path that getHWCalloutFields() can be used with.
513 // (The serial number, etc, aren't stored on the connector in the
514 // inventory, and may not even be modeled.)
515 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
516
Matt Spinler2f9225a2020-08-05 12:58:49 -0500517 auto method =
518 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
519 interface::vpdManager, methodName.c_str());
520
521 if (expanded)
522 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600523 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500524 }
525 else
526 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600527 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500528 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500529
Matt Spinler35a405b2022-03-02 11:42:42 -0600530 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500531
Patrick Williamsb05e07c2025-11-05 00:03:06 -0500532 auto entries = reply.unpack<std::vector<sdbusplus::message::object_path>>();
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500533
Matt Spinlerbad056b2023-01-25 14:16:57 -0600534 std::vector<std::string> paths;
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500535
Matt Spinlerbad056b2023-01-25 14:16:57 -0600536 // Note: The D-Bus method will fail if nothing found.
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500537 std::for_each(entries.begin(), entries.end(),
Matt Spinlerbad056b2023-01-25 14:16:57 -0600538 [&paths](const auto& path) { paths.push_back(path); });
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500539
Matt Spinlerbad056b2023-01-25 14:16:57 -0600540 return paths;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500541}
542
Matt Spinler34a904c2020-08-05 14:53:28 -0500543void DataInterface::assertLEDGroup(const std::string& ledGroup,
544 bool value) const
545{
546 DBusValue variant = value;
Patrick Williams075c7922024-08-16 15:19:49 -0400547 auto method =
548 _bus.new_method_call(service_name::ledGroupManager, ledGroup.c_str(),
549 interface::dbusProperty, "Set");
Matt Spinler34a904c2020-08-05 14:53:28 -0500550 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600551 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500552}
553
Matt Spinler993168d2021-04-07 16:05:03 -0500554void DataInterface::setFunctional(const std::string& objectPath,
555 bool value) const
556{
Matt Spinler412f50e2023-11-14 12:49:52 -0600557 DBusPropertyMap prop{{"Functional", value}};
558 DBusInterfaceMap iface{{interface::operationalStatus, prop}};
Matt Spinler993168d2021-04-07 16:05:03 -0500559
Matt Spinler412f50e2023-11-14 12:49:52 -0600560 // PIM takes a relative path like /system/chassis so remove
561 // /xyz/openbmc_project/inventory if present.
562 std::string path{objectPath};
563 if (path.starts_with(object_path::baseInv))
564 {
565 path = objectPath.substr(strlen(object_path::baseInv));
566 }
567 DBusObjectMap object{{path, iface}};
Matt Spinler993168d2021-04-07 16:05:03 -0500568
Matt Spinler412f50e2023-11-14 12:49:52 -0600569 auto method = _bus.new_method_call(service_name::inventoryManager,
570 object_path::baseInv,
571 interface::inventoryManager, "Notify");
572 method.append(std::move(object));
Matt Spinler35a405b2022-03-02 11:42:42 -0600573 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500574}
575
Sumit Kumar76198a22021-07-15 05:59:57 -0500576using AssociationTuple = std::tuple<std::string, std::string, std::string>;
577using AssociationsProperty = std::vector<AssociationTuple>;
578
579void DataInterface::setCriticalAssociation(const std::string& objectPath) const
580{
581 DBusValue getAssociationValue;
582
Sumit Kumar027bf282022-01-24 11:25:19 -0600583 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500584
Sumit Kumar027bf282022-01-24 11:25:19 -0600585 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500586 getAssociationValue);
587
588 auto association = std::get<AssociationsProperty>(getAssociationValue);
589
590 AssociationTuple critAssociation{
591 "health_rollup", "critical",
592 "/xyz/openbmc_project/inventory/system/chassis"};
593
594 if (std::find(association.begin(), association.end(), critAssociation) ==
595 association.end())
596 {
597 association.push_back(critAssociation);
598 DBusValue setAssociationValue = association;
599
600 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
601 interface::dbusProperty, "Set");
602
Sumit Kumar027bf282022-01-24 11:25:19 -0600603 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500604 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600605 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500606 }
607}
608
Matt Spinler1ab66962020-10-29 13:21:44 -0500609std::vector<std::string> DataInterface::getSystemNames() const
610{
611 DBusSubTree subtree;
612 DBusValue names;
613
614 auto method = _bus.new_method_call(service_name::objectMapper,
615 object_path::objectMapper,
616 interface::objectMapper, "GetSubTree");
617 method.append(std::string{"/"}, 0,
618 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600619 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500620
621 reply.read(subtree);
622 if (subtree.empty())
623 {
624 throw std::runtime_error("Compatible interface not on D-Bus");
625 }
626
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600627 for (const auto& [path, interfaceMap] : subtree)
628 {
629 auto iface = interfaceMap.find(service_name::entityManager);
630 if (iface == interfaceMap.end())
631 {
632 continue;
633 }
Matt Spinler1ab66962020-10-29 13:21:44 -0500634
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600635 getProperty(iface->first, path, interface::compatible, "Names", names);
Matt Spinler1ab66962020-10-29 13:21:44 -0500636
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600637 return std::get<std::vector<std::string>>(names);
638 }
639
640 throw std::runtime_error("EM Compatible interface not on D-Bus");
Matt Spinler1ab66962020-10-29 13:21:44 -0500641}
642
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500643bool DataInterface::getQuiesceOnError() const
644{
645 bool ret = false;
646
647 try
648 {
Patrick Williams075c7922024-08-16 15:19:49 -0400649 auto service =
650 getService(object_path::logSetting, 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 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500662 lg2::warning("Failed reading QuiesceOnHwError property from "
663 "interface: {IFACE} exception: {ERROR}",
664 "IFACE", interface::logSetting, "ERROR", e);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500665 }
666
667 return ret;
668}
669
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500670#ifdef PEL_ENABLE_PHAL
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500671void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500672 GardType eGardType, uint32_t plid) const
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500673{
674 try
675 {
Deepa Karthikeyanc6396da2024-11-14 04:50:25 -0600676 libguard::libguard_init(false);
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500677 libguard::create(binPath, plid, eGardType);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500678 }
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500679 catch (libguard::exception::GuardException& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500680 {
Deepa Karthikeyanc6396da2024-11-14 04:50:25 -0600681 lg2::error("Exception in libguard {ERROR}", "ERROR", e);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500682 }
683}
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500684#endif
Sumit Kumar3e274432021-09-14 06:37:56 -0500685
686void DataInterface::createProgressSRC(
Matt Spinler931cafe2025-04-22 12:31:28 -0500687 const std::vector<uint8_t>& priSRC,
688 const std::vector<uint8_t>& srcStruct) const
Sumit Kumar3e274432021-09-14 06:37:56 -0500689{
690 DBusValue variant = std::make_tuple(priSRC, srcStruct);
691
692 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500693 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500694 interface::dbusProperty, "Set");
695
696 method.append(interface::bootRawProgress, "Value", variant);
697
Matt Spinler35a405b2022-03-02 11:42:42 -0600698 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500699}
Sumit Kumar027bf282022-01-24 11:25:19 -0600700
701std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
702{
703 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
704 std::string hwErrorLog = "/isolated_hw_errorlog";
705 std::string errorLog = "/error_log";
706 DBusPathList paths;
707 std::vector<uint32_t> ids;
708
709 // Get all latest mapper associations
710 paths = getPaths(association);
711 for (auto& path : paths)
712 {
713 // Look for object path with hardware isolation entry if any
714 size_t pos = path.find(hwErrorLog);
715 if (pos != std::string::npos)
716 {
717 // Get the object path
718 std::string ph = path;
719 ph.erase(pos, hwErrorLog.length());
720 auto service = getService(ph, interface::hwIsolationEntry);
721 if (!service.empty())
722 {
723 bool status;
724 DBusValue value;
725
726 // Read the Resolved property from object path
727 getProperty(service, ph, interface::hwIsolationEntry,
728 "Resolved", value);
729
730 status = std::get<bool>(value);
731
732 // If the entry isn't resolved
733 if (!status)
734 {
Patrick Williams075c7922024-08-16 15:19:49 -0400735 auto assocService =
736 getService(path, interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500737 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600738 {
Matt Spinler45796e82022-07-01 11:25:27 -0500739 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600740
741 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500742 getProperty(assocService, path, interface::association,
743 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600744
745 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500746 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600747 if (!logPath.empty())
748 {
749 // Get OpenBMC event log Id
750 uint32_t id = stoi(logPath[0].substr(
751 logPath[0].find_last_of('/') + 1));
752 ids.push_back(id);
753 }
754 }
755 }
756 }
757 }
758
759 // Look for object path with error_log entry if any
760 pos = path.find(errorLog);
761 if (pos != std::string::npos)
762 {
763 auto service = getService(path, interface::association);
764 if (!service.empty())
765 {
766 DBusValue value;
767
768 // Read Endpoints property
769 getProperty(service, path, interface::association, "endpoints",
770 value);
771
772 auto logPath = std::get<std::vector<std::string>>(value);
773 if (!logPath.empty())
774 {
775 // Get OpenBMC event log Id
776 uint32_t id = stoi(
777 logPath[0].substr(logPath[0].find_last_of('/') + 1));
778 ids.push_back(id);
779 }
780 }
781 }
782 }
783
784 if (ids.size() > 1)
785 {
786 // remove duplicates to have only unique ids
787 std::sort(ids.begin(), ids.end());
788 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
789 }
790 return ids;
791}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500792
793std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
794{
Matt Spinler931cafe2025-04-22 12:31:28 -0500795 using RawProgressProperty =
796 std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>;
Vijay Lobo875b6c72021-10-20 17:38:56 -0500797
798 DBusValue value;
799 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
800 interface::bootRawProgress, "Value", value);
801
802 const auto& rawProgress = std::get<RawProgressProperty>(value);
803 return std::get<1>(rawProgress);
804}
805
Patrick Williams25291152025-02-01 08:21:42 -0500806std::optional<std::vector<uint8_t>> DataInterface::getDIProperty(
807 const std::string& locationCode) const
Arya K Padmand8ae6182024-07-19 06:25:10 -0500808{
809 std::vector<uint8_t> viniDI;
810
811 try
812 {
813 // Note : The hardcoded value 0 should be changed when comes to
814 // multinode system.
815 auto objectPath = getInventoryFromLocCode(locationCode, 0, true);
816
817 DBusValue value;
818 getProperty(service_name::inventoryManager, objectPath[0],
819 interface::viniRecordVPD, "DI", value);
820
821 viniDI = std::get<std::vector<uint8_t>>(value);
822 }
823 catch (const std::exception& e)
824 {
825 lg2::warning(
826 "Failed reading DI property for the location code : {LOC_CODE} from "
827 "interface: {IFACE} exception: {ERROR}",
828 "LOC_CODE", locationCode, "IFACE", interface::viniRecordVPD,
829 "ERROR", e);
830 return std::nullopt;
831 }
832
833 return viniDI;
834}
835
Patrick Williams25291152025-02-01 08:21:42 -0500836std::optional<bool> DataInterfaceBase::isDIMMLocCode(
837 const std::string& locCode) const
Arya K Padmand8ae6182024-07-19 06:25:10 -0500838{
839 if (_locationCache.contains(locCode))
840 {
841 return _locationCache.at(locCode);
842 }
843 else
844 {
845 return std::nullopt;
846 }
847}
848
849void DataInterfaceBase::addDIMMLocCode(const std::string& locCode,
850 bool isFRUDIMM)
851{
852 _locationCache.insert({locCode, isFRUDIMM});
853}
854
Arya K Padmanced8ed72024-09-02 05:18:07 -0500855bool DataInterfaceBase::isDIMM(const std::string& locCode)
Arya K Padmand8ae6182024-07-19 06:25:10 -0500856{
857 auto isDIMMType = isDIMMLocCode(locCode);
858 if (isDIMMType.has_value())
859 {
860 return isDIMMType.value();
861 }
862#ifndef PEL_ENABLE_PHAL
Arya K Padmanced8ed72024-09-02 05:18:07 -0500863 return false;
Arya K Padmand8ae6182024-07-19 06:25:10 -0500864#else
865 else
866 {
867 // Invoke pHAL API inorder to fetch the FRU Type
868 auto fruType = openpower::phal::pdbg::getFRUType(locCode);
Arya K Padmanced8ed72024-09-02 05:18:07 -0500869 bool isDIMMFRU{false};
Arya K Padmand8ae6182024-07-19 06:25:10 -0500870 if (fruType.has_value())
871 {
Arya K Padmand8ae6182024-07-19 06:25:10 -0500872 if (fruType.value() == ENUM_ATTR_TYPE_DIMM)
873 {
874 isDIMMFRU = true;
875 }
876 addDIMMLocCode(locCode, isDIMMFRU);
Arya K Padmand8ae6182024-07-19 06:25:10 -0500877 }
Arya K Padmanced8ed72024-09-02 05:18:07 -0500878 return isDIMMFRU;
Arya K Padmand8ae6182024-07-19 06:25:10 -0500879 }
880#endif
881}
882
harsh-agarwal1d763db32024-09-03 09:18:50 -0500883DBusPathList DataInterface::getAssociatedPaths(
884 const DBusPath& associatedPath, const DBusPath& subtree, int32_t depth,
885 const DBusInterfaceList& interfaces) const
886{
887 DBusPathList paths;
888 try
889 {
890 auto method = _bus.new_method_call(
891 service_name::objectMapper, object_path::objectMapper,
892 interface::objectMapper, "GetAssociatedSubTreePaths");
893 method.append(sdbusplus::message::object_path(associatedPath),
894 sdbusplus::message::object_path(subtree), depth,
895 interfaces);
896
897 auto reply = _bus.call(method, dbusTimeout);
898 reply.read(paths);
899 }
900 catch (const std::exception& e)
901 {
902 std::string ifaces(
903 std::ranges::fold_left_first(
904 interfaces,
905 [](std::string ifaces, const std::string& iface) {
906 return ifaces + ", " + iface;
907 })
908 .value_or(""));
909
910 lg2::error("Failed getting associated paths: {ERROR}. "
911 "AssociatedPath: {ASSOIC_PATH} Subtree: {SUBTREE} "
912 "Interfaces: {IFACES}",
913 "ERROR", e, "ASSOIC_PATH", associatedPath, "SUBTREE",
914 subtree, "IFACES", ifaces);
915 }
916 return paths;
917}
918
Matt Spinler5b423652023-05-04 13:08:44 -0500919void DataInterface::startFruPlugWatch()
920{
921 // Add a watch on inventory InterfacesAdded and then find all
922 // existing hotpluggable interfaces and add propertiesChanged
923 // watches on them.
924
925 _invIaMatch = std::make_unique<sdbusplus::bus::match_t>(
926 _bus, match_rules::interfacesAdded(object_path::baseInv),
927 std::bind(&DataInterface::inventoryIfaceAdded, this,
928 std::placeholders::_1));
929 try
930 {
931 auto paths = getPaths(hotplugInterfaces);
932
933 _invPresentMatches.clear();
934
935 std::for_each(paths.begin(), paths.end(),
936 [this](const auto& path) { addHotplugWatch(path); });
937 }
938 catch (const sdbusplus::exception_t& e)
939 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500940 lg2::warning("Failed getting FRU paths to watch: {ERROR}", "ERROR", e);
Matt Spinler5b423652023-05-04 13:08:44 -0500941 }
942}
943
944void DataInterface::addHotplugWatch(const std::string& path)
945{
946 if (!_invPresentMatches.contains(path))
947 {
948 _invPresentMatches.emplace(
949 path,
950 std::make_unique<sdbusplus::bus::match_t>(
951 _bus, match_rules::propertiesChanged(path, interface::invItem),
952 std::bind(&DataInterface::presenceChanged, this,
953 std::placeholders::_1)));
954 }
955}
956
957void DataInterface::inventoryIfaceAdded(sdbusplus::message_t& msg)
958{
959 sdbusplus::message::object_path path;
960 DBusInterfaceMap interfaces;
961
962 msg.read(path, interfaces);
963
964 // Check if any of the new interfaces are for hot pluggable FRUs.
965 if (std::find_if(interfaces.begin(), interfaces.end(),
966 [](const auto& interfacePair) {
Patrick Williams075c7922024-08-16 15:19:49 -0400967 return std::find(hotplugInterfaces.begin(),
968 hotplugInterfaces.end(),
969 interfacePair.first) !=
970 hotplugInterfaces.end();
971 }) == interfaces.end())
Matt Spinler5b423652023-05-04 13:08:44 -0500972 {
973 return;
974 }
975
976 addHotplugWatch(path.str);
977
978 // If an Inventory.Item interface was also added, check presence now.
979
980 // Notes:
981 // * This assumes the Inv.Item and Inv.Fan/PS are added together which
982 // is currently the case.
983 // * If the code ever switches to something without a Present
984 // property, then the IA signal itself would probably indicate presence.
985
986 auto itemIt = interfaces.find(interface::invItem);
987 if (itemIt != interfaces.end())
988 {
989 notifyPresenceSubsribers(path.str, itemIt->second);
990 }
991}
992
993void DataInterface::presenceChanged(sdbusplus::message_t& msg)
994{
995 DBusInterface interface;
996 DBusPropertyMap properties;
997
998 msg.read(interface, properties);
999 if (interface != interface::invItem)
1000 {
1001 return;
1002 }
1003
1004 std::string path = msg.get_path();
1005 notifyPresenceSubsribers(path, properties);
1006}
1007
1008void DataInterface::notifyPresenceSubsribers(const std::string& path,
1009 const DBusPropertyMap& properties)
1010{
Matt Spinler5ee36052023-05-30 14:20:56 -05001011 auto prop = properties.find("Present");
1012 if ((prop == properties.end()) || (!std::get<bool>(prop->second)))
1013 {
1014 return;
1015 }
1016
1017 std::string locCode;
1018
Matt Spinler5b423652023-05-04 13:08:44 -05001019 try
1020 {
Matt Spinler52ee3a42023-07-27 14:54:48 -05001021 auto service = getService(path, interface::locCode);
1022
1023 // If the hotplugged FRU is hosted by PLDM, then it is
1024 // in an IO expansion drawer and we don't care about it.
1025 if (service == service_name::pldm)
1026 {
1027 return;
1028 }
1029
Matt Spinler5ee36052023-05-30 14:20:56 -05001030 locCode = getLocationCode(path);
Matt Spinler5b423652023-05-04 13:08:44 -05001031 }
Matt Spinler5ee36052023-05-30 14:20:56 -05001032 catch (const sdbusplus::exception_t& e)
Matt Spinler5b423652023-05-04 13:08:44 -05001033 {
Matt Spinlera167a7d2023-06-30 15:14:25 -05001034 lg2::debug("Could not get location code for {PATH}: {ERROR}", "PATH",
1035 path, "ERROR", e);
Matt Spinler5ee36052023-05-30 14:20:56 -05001036 return;
Matt Spinler5b423652023-05-04 13:08:44 -05001037 }
Matt Spinler5ee36052023-05-30 14:20:56 -05001038
Matt Spinlera167a7d2023-06-30 15:14:25 -05001039 lg2::debug("Detected FRU {PATH} ({LOC}) present ", "PATH", path, "LOC",
1040 locCode);
Matt Spinler5ee36052023-05-30 14:20:56 -05001041
1042 // Tell the subscribers.
1043 setFruPresent(locCode);
Matt Spinler5b423652023-05-04 13:08:44 -05001044}
Arya K Padmanafba3162024-08-30 07:41:32 -05001045
Arya K Padmanafba3162024-08-30 07:41:32 -05001046bool DataInterface::isPHALDevTreeExist() const
1047{
1048 try
1049 {
1050 if (std::filesystem::exists(PDBG_DTB_PATH))
1051 {
1052 return true;
1053 }
1054 }
1055 catch (const std::exception& e)
1056 {
1057 lg2::error("Failed to check device tree {PHAL_DEVTREE_PATH} existence, "
1058 "{ERROR}",
1059 "PHAL_DEVTREE_PATH", PDBG_DTB_PATH, "ERROR", e);
1060 }
1061 return false;
1062}
1063
Arya K Padman0b758fb2024-09-06 11:59:45 -05001064#ifdef PEL_ENABLE_PHAL
Arya K Padmanafba3162024-08-30 07:41:32 -05001065void DataInterface::initPHAL()
1066{
1067 if (setenv("PDBG_DTB", PDBG_DTB_PATH, 1))
1068 {
1069 // Log message and continue,
1070 // This is to help continue creating PEL in raw format.
1071 lg2::error("Failed to set PDBG_DTB: ({ERRNO})", "ERRNO",
1072 strerror(errno));
1073 }
1074
1075 if (!pdbg_targets_init(NULL))
1076 {
1077 lg2::error("pdbg_targets_init failed");
1078 return;
1079 }
1080
1081 if (libekb_init())
1082 {
1083 lg2::error("libekb_init failed, skipping ffdc processing");
1084 return;
1085 }
1086}
Arya K Padman0b758fb2024-09-06 11:59:45 -05001087#endif
Arya K Padmanafba3162024-08-30 07:41:32 -05001088
1089void DataInterface::subscribeToSystemdSignals()
1090{
1091 try
1092 {
1093 auto method =
1094 _bus.new_method_call(service_name::systemd, object_path::systemd,
1095 interface::systemdMgr, "Subscribe");
1096 _systemdSlot = method.call_async([this](sdbusplus::message_t&& msg) {
1097 // Initializing with nullptr to indicate that it is not subscribed
1098 // to any signal.
1099 this->_systemdSlot = sdbusplus::slot_t(nullptr);
1100 if (msg.is_method_error())
1101 {
1102 auto* error = msg.get_error();
1103 lg2::error("Failed to subscribe JobRemoved systemd signal, "
Arya K Padmanea001072024-09-19 05:00:50 -05001104 "errorName: {ERR_NAME}, errorMsg: {ERR_MSG} ",
Arya K Padman0b758fb2024-09-06 11:59:45 -05001105 "ERR_NAME", error->name, "ERR_MSG", error->message);
Arya K Padmanafba3162024-08-30 07:41:32 -05001106 return;
1107 }
1108
1109 namespace sdbusRule = sdbusplus::bus::match::rules;
1110 this->_systemdMatch =
1111 std::make_unique<decltype(this->_systemdMatch)::element_type>(
1112 this->_bus,
1113 sdbusRule::type::signal() +
1114 sdbusRule::member("JobRemoved") +
1115 sdbusRule::path(object_path::systemd) +
1116 sdbusRule::interface(interface::systemdMgr),
1117 [this](sdbusplus::message_t& msg) {
1118 uint32_t jobID;
1119 sdbusplus::message::object_path jobObjPath;
1120 std::string jobUnitName, jobUnitResult;
1121
1122 msg.read(jobID, jobObjPath, jobUnitName, jobUnitResult);
Manish Tiwari215121e2025-09-24 08:44:39 -05001123 if ((jobUnitName == "obmc-recover-pnor.service") &&
Arya K Padmanafba3162024-08-30 07:41:32 -05001124 (jobUnitResult == "done"))
1125 {
Arya K Padmanea001072024-09-19 05:00:50 -05001126#ifdef PEL_ENABLE_PHAL
1127 this->initPHAL();
1128#endif
1129 // Invoke unsubscribe method to stop monitoring for
1130 // JobRemoved signals.
Arya K Padmanafba3162024-08-30 07:41:32 -05001131 this->unsubscribeFromSystemdSignals();
1132 }
1133 });
1134 });
1135 }
1136 catch (const sdbusplus::exception_t& e)
1137 {
1138 lg2::error(
1139 "Exception occured while handling JobRemoved systemd signal, "
1140 "exception: {ERROR}",
1141 "ERROR", e);
1142 }
1143}
1144
1145void DataInterface::unsubscribeFromSystemdSignals()
1146{
1147 try
1148 {
1149 auto method =
1150 _bus.new_method_call(service_name::systemd, object_path::systemd,
1151 interface::systemdMgr, "Unsubscribe");
1152 _systemdSlot = method.call_async([this](sdbusplus::message_t&& msg) {
1153 // Unsubscribing the _systemdSlot from the subscribed signal
1154 this->_systemdSlot = sdbusplus::slot_t(nullptr);
1155 if (msg.is_method_error())
1156 {
1157 auto* error = msg.get_error();
1158 lg2::error(
1159 "Failed to unsubscribe from JobRemoved systemd signal, "
Arya K Padmanea001072024-09-19 05:00:50 -05001160 "errorName: {ERR_NAME}, errorMsg: {ERR_MSG} ",
Arya K Padman0b758fb2024-09-06 11:59:45 -05001161 "ERR_NAME", error->name, "ERR_MSG", error->message);
Arya K Padmanafba3162024-08-30 07:41:32 -05001162 return;
1163 }
Arya K Padmanea001072024-09-19 05:00:50 -05001164 // Reset _systemdMatch to avoid reception of further JobRemoved
1165 // signals
1166 this->_systemdMatch.reset();
Arya K Padmanafba3162024-08-30 07:41:32 -05001167 });
1168 }
1169 catch (const sdbusplus::exception_t& e)
1170 {
1171 lg2::error(
1172 "Exception occured while unsubscribing from JobRemoved systemd signal, "
1173 "exception: {ERROR}",
1174 "ERROR", e);
1175 }
1176}
Arya K Padmanafba3162024-08-30 07:41:32 -05001177
Matt Spinlerc8705e22019-09-11 12:36:07 -05001178} // namespace pels
1179} // namespace openpower