blob: 50424afe2d6f67fc13b866845e8e3ff194698737 [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
271 DBusPathList paths;
272 reply.read(paths);
273
274 return paths;
275}
276
Matt Spinlerc8705e22019-09-11 12:36:07 -0500277DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600278 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500279{
280 auto method = _bus.new_method_call(service_name::objectMapper,
281 object_path::objectMapper,
282 interface::objectMapper, "GetObject");
283
284 method.append(objectPath, std::vector<std::string>({interface}));
285
Matt Spinler35a405b2022-03-02 11:42:42 -0600286 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500287
288 std::map<DBusService, DBusInterfaceList> response;
289 reply.read(response);
290
291 if (!response.empty())
292 {
293 return response.begin()->first;
294 }
295
296 return std::string{};
297}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600298
Matt Spinler677381b2020-01-23 10:04:29 -0600299void DataInterface::readBMCFWVersion()
300{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500301 _bmcFWVersion =
302 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600303}
304
305void DataInterface::readServerFWVersion()
306{
Sumit Kumarcad16202021-05-13 04:06:15 -0500307 auto value =
308 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
309 if ((value != "") && (value.find_last_of(')') != std::string::npos))
310 {
311 std::size_t pos = value.find_first_of('(') + 1;
312 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
313 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600314}
315
Matt Spinler677381b2020-01-23 10:04:29 -0600316void DataInterface::readBMCFWVersionID()
317{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500318 _bmcFWVersionID =
319 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600320}
321
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500322std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600323{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500324 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600325 try
326 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500327 auto service = getService(object_path::systemInv, interface::invAsset);
328 if (!service.empty())
329 {
330 DBusValue value;
331 getProperty(service, object_path::systemInv, interface::invAsset,
332 "Model", value);
333
334 model = std::get<std::string>(value);
335 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600336 }
337 catch (const std::exception& e)
338 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500339 lg2::warning("Failed reading Model property from "
340 "interface: {IFACE} exception: {ERROR}",
341 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600342 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500343
344 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600345}
346
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500347std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600348{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500349 std::string sn;
350 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600351 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500352 auto service = getService(object_path::systemInv, interface::invAsset);
353 if (!service.empty())
354 {
355 DBusValue value;
356 getProperty(service, object_path::systemInv, interface::invAsset,
357 "SerialNumber", value);
358
359 sn = std::get<std::string>(value);
360 }
361 }
362 catch (const std::exception& e)
363 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500364 lg2::warning("Failed reading SerialNumber property from "
365 "interface: {IFACE} exception: {ERROR}",
366 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600367 }
368
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500369 return sn;
370}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600371
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500372std::string DataInterface::getMotherboardCCIN() const
373{
374 std::string ccin;
375
376 try
377 {
Patrick Williams075c7922024-08-16 15:19:49 -0400378 auto service =
379 getService(object_path::motherBoardInv, interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500380 if (!service.empty())
381 {
382 DBusValue value;
383 getProperty(service, object_path::motherBoardInv,
384 interface::viniRecordVPD, "CC", value);
385
386 auto cc = std::get<std::vector<uint8_t>>(value);
387 ccin = std::string{cc.begin(), cc.end()};
388 }
389 }
390 catch (const std::exception& e)
391 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500392 lg2::warning("Failed reading Motherboard CCIN property from "
393 "interface: {IFACE} exception: {ERROR}",
394 "IFACE", interface::viniRecordVPD, "ERROR", e);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500395 }
396
397 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600398}
399
Ben Tynere32b7e72021-05-18 12:38:40 -0500400std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
401{
402 std::vector<uint8_t> systemIM;
403
404 try
405 {
Patrick Williams075c7922024-08-16 15:19:49 -0400406 auto service =
407 getService(object_path::motherBoardInv, interface::vsbpRecordVPD);
Ben Tynere32b7e72021-05-18 12:38:40 -0500408 if (!service.empty())
409 {
410 DBusValue value;
411 getProperty(service, object_path::motherBoardInv,
412 interface::vsbpRecordVPD, "IM", value);
413
414 systemIM = std::get<std::vector<uint8_t>>(value);
415 }
416 }
417 catch (const std::exception& e)
418 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500419 lg2::warning("Failed reading System IM property from "
420 "interface: {IFACE} exception: {ERROR}",
421 "IFACE", interface::vsbpRecordVPD, "ERROR", e);
Ben Tynere32b7e72021-05-18 12:38:40 -0500422 }
423
424 return systemIM;
425}
426
Patrick Williams075c7922024-08-16 15:19:49 -0400427void DataInterface::getHWCalloutFields(
428 const std::string& inventoryPath, std::string& fruPartNumber,
429 std::string& ccin, std::string& serialNumber) const
Matt Spinler60c4e792020-03-13 13:45:36 -0500430{
431 // For now, attempt to get all of the properties directly on the path
432 // passed in. In the future, may need to make use of an algorithm
433 // to figure out which inventory objects actually hold these
434 // interfaces in the case of non FRUs, or possibly another service
435 // will provide this info. Any missing interfaces will result
436 // in exceptions being thrown.
437
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500438 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500439
Patrick Williams075c7922024-08-16 15:19:49 -0400440 auto properties =
441 getAllProperties(service, inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500442
443 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
444 fruPartNumber = std::string{value.begin(), value.end()};
445
446 value = std::get<std::vector<uint8_t>>(properties["CC"]);
447 ccin = std::string{value.begin(), value.end()};
448
449 value = std::get<std::vector<uint8_t>>(properties["SN"]);
450 serialNumber = std::string{value.begin(), value.end()};
451}
452
Patrick Williams25291152025-02-01 08:21:42 -0500453std::string DataInterface::getLocationCode(
454 const std::string& inventoryPath) const
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500455{
456 auto service = getService(inventoryPath, interface::locCode);
457
458 DBusValue locCode;
459 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
460 locCode);
461
462 return std::get<std::string>(locCode);
463}
464
Patrick Williams25291152025-02-01 08:21:42 -0500465std::string DataInterface::addLocationCodePrefix(
466 const std::string& locationCode)
Matt Spinler5fb24c12020-06-04 11:21:33 -0500467{
468 static const std::string locationCodePrefix{"Ufcs-"};
469
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500470 // Technically there are 2 location code prefixes, Ufcs and Umts, so
471 // if it already starts with a U then don't need to do anything.
472 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500473 {
474 return locationCodePrefix + locationCode;
475 }
476
477 return locationCode;
478}
479
480std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500481 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500482{
Matt Spinler0d92b522021-06-16 13:28:17 -0600483 // Location codes for connectors are the location code of the FRU they are
484 // on, plus a '-Tx' segment. Remove this last segment before expanding it
485 // and then add it back in afterwards. This way, the connector doesn't have
486 // to be in the model just so that it can be expanded.
487 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
488
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500489 auto method =
490 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
491 interface::vpdManager, "GetExpandedLocationCode");
492
Matt Spinler0d92b522021-06-16 13:28:17 -0600493 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500494
Matt Spinler35a405b2022-03-02 11:42:42 -0600495 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500496
497 std::string expandedLocationCode;
498 reply.read(expandedLocationCode);
499
Matt Spinler0d92b522021-06-16 13:28:17 -0600500 if (!connectorLoc.empty())
501 {
502 expandedLocationCode += connectorLoc;
503 }
504
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500505 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500506}
507
Patrick Williams075c7922024-08-16 15:19:49 -0400508std::vector<std::string> DataInterface::getInventoryFromLocCode(
509 const std::string& locationCode, uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500510{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500511 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
512 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500513
Matt Spinler0d92b522021-06-16 13:28:17 -0600514 // Remove the connector segment, if present, so that this method call
515 // returns an inventory path that getHWCalloutFields() can be used with.
516 // (The serial number, etc, aren't stored on the connector in the
517 // inventory, and may not even be modeled.)
518 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
519
Matt Spinler2f9225a2020-08-05 12:58:49 -0500520 auto method =
521 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
522 interface::vpdManager, methodName.c_str());
523
524 if (expanded)
525 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600526 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500527 }
528 else
529 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600530 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500531 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500532
Matt Spinler35a405b2022-03-02 11:42:42 -0600533 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500534
535 std::vector<sdbusplus::message::object_path> entries;
536 reply.read(entries);
537
Matt Spinlerbad056b2023-01-25 14:16:57 -0600538 std::vector<std::string> paths;
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500539
Matt Spinlerbad056b2023-01-25 14:16:57 -0600540 // Note: The D-Bus method will fail if nothing found.
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500541 std::for_each(entries.begin(), entries.end(),
Matt Spinlerbad056b2023-01-25 14:16:57 -0600542 [&paths](const auto& path) { paths.push_back(path); });
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500543
Matt Spinlerbad056b2023-01-25 14:16:57 -0600544 return paths;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500545}
546
Matt Spinler34a904c2020-08-05 14:53:28 -0500547void DataInterface::assertLEDGroup(const std::string& ledGroup,
548 bool value) const
549{
550 DBusValue variant = value;
Patrick Williams075c7922024-08-16 15:19:49 -0400551 auto method =
552 _bus.new_method_call(service_name::ledGroupManager, ledGroup.c_str(),
553 interface::dbusProperty, "Set");
Matt Spinler34a904c2020-08-05 14:53:28 -0500554 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600555 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500556}
557
Matt Spinler993168d2021-04-07 16:05:03 -0500558void DataInterface::setFunctional(const std::string& objectPath,
559 bool value) const
560{
Matt Spinler412f50e2023-11-14 12:49:52 -0600561 DBusPropertyMap prop{{"Functional", value}};
562 DBusInterfaceMap iface{{interface::operationalStatus, prop}};
Matt Spinler993168d2021-04-07 16:05:03 -0500563
Matt Spinler412f50e2023-11-14 12:49:52 -0600564 // PIM takes a relative path like /system/chassis so remove
565 // /xyz/openbmc_project/inventory if present.
566 std::string path{objectPath};
567 if (path.starts_with(object_path::baseInv))
568 {
569 path = objectPath.substr(strlen(object_path::baseInv));
570 }
571 DBusObjectMap object{{path, iface}};
Matt Spinler993168d2021-04-07 16:05:03 -0500572
Matt Spinler412f50e2023-11-14 12:49:52 -0600573 auto method = _bus.new_method_call(service_name::inventoryManager,
574 object_path::baseInv,
575 interface::inventoryManager, "Notify");
576 method.append(std::move(object));
Matt Spinler35a405b2022-03-02 11:42:42 -0600577 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500578}
579
Sumit Kumar76198a22021-07-15 05:59:57 -0500580using AssociationTuple = std::tuple<std::string, std::string, std::string>;
581using AssociationsProperty = std::vector<AssociationTuple>;
582
583void DataInterface::setCriticalAssociation(const std::string& objectPath) const
584{
585 DBusValue getAssociationValue;
586
Sumit Kumar027bf282022-01-24 11:25:19 -0600587 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500588
Sumit Kumar027bf282022-01-24 11:25:19 -0600589 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500590 getAssociationValue);
591
592 auto association = std::get<AssociationsProperty>(getAssociationValue);
593
594 AssociationTuple critAssociation{
595 "health_rollup", "critical",
596 "/xyz/openbmc_project/inventory/system/chassis"};
597
598 if (std::find(association.begin(), association.end(), critAssociation) ==
599 association.end())
600 {
601 association.push_back(critAssociation);
602 DBusValue setAssociationValue = association;
603
604 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
605 interface::dbusProperty, "Set");
606
Sumit Kumar027bf282022-01-24 11:25:19 -0600607 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500608 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600609 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500610 }
611}
612
Matt Spinler1ab66962020-10-29 13:21:44 -0500613std::vector<std::string> DataInterface::getSystemNames() const
614{
615 DBusSubTree subtree;
616 DBusValue names;
617
618 auto method = _bus.new_method_call(service_name::objectMapper,
619 object_path::objectMapper,
620 interface::objectMapper, "GetSubTree");
621 method.append(std::string{"/"}, 0,
622 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600623 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500624
625 reply.read(subtree);
626 if (subtree.empty())
627 {
628 throw std::runtime_error("Compatible interface not on D-Bus");
629 }
630
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600631 for (const auto& [path, interfaceMap] : subtree)
632 {
633 auto iface = interfaceMap.find(service_name::entityManager);
634 if (iface == interfaceMap.end())
635 {
636 continue;
637 }
Matt Spinler1ab66962020-10-29 13:21:44 -0500638
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600639 getProperty(iface->first, path, interface::compatible, "Names", names);
Matt Spinler1ab66962020-10-29 13:21:44 -0500640
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600641 return std::get<std::vector<std::string>>(names);
642 }
643
644 throw std::runtime_error("EM Compatible interface not on D-Bus");
Matt Spinler1ab66962020-10-29 13:21:44 -0500645}
646
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500647bool DataInterface::getQuiesceOnError() const
648{
649 bool ret = false;
650
651 try
652 {
Patrick Williams075c7922024-08-16 15:19:49 -0400653 auto service =
654 getService(object_path::logSetting, interface::logSetting);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500655 if (!service.empty())
656 {
657 DBusValue value;
658 getProperty(service, object_path::logSetting, interface::logSetting,
659 "QuiesceOnHwError", value);
660
661 ret = std::get<bool>(value);
662 }
663 }
664 catch (const std::exception& e)
665 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500666 lg2::warning("Failed reading QuiesceOnHwError property from "
667 "interface: {IFACE} exception: {ERROR}",
668 "IFACE", interface::logSetting, "ERROR", e);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500669 }
670
671 return ret;
672}
673
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500674#ifdef PEL_ENABLE_PHAL
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500675void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500676 GardType eGardType, uint32_t plid) const
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500677{
678 try
679 {
Deepa Karthikeyanc6396da2024-11-14 04:50:25 -0600680 libguard::libguard_init(false);
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500681 libguard::create(binPath, plid, eGardType);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500682 }
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500683 catch (libguard::exception::GuardException& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500684 {
Deepa Karthikeyanc6396da2024-11-14 04:50:25 -0600685 lg2::error("Exception in libguard {ERROR}", "ERROR", e);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500686 }
687}
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500688#endif
Sumit Kumar3e274432021-09-14 06:37:56 -0500689
690void DataInterface::createProgressSRC(
Matt Spinler931cafe2025-04-22 12:31:28 -0500691 const std::vector<uint8_t>& priSRC,
692 const std::vector<uint8_t>& srcStruct) const
Sumit Kumar3e274432021-09-14 06:37:56 -0500693{
694 DBusValue variant = std::make_tuple(priSRC, srcStruct);
695
696 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500697 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500698 interface::dbusProperty, "Set");
699
700 method.append(interface::bootRawProgress, "Value", variant);
701
Matt Spinler35a405b2022-03-02 11:42:42 -0600702 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500703}
Sumit Kumar027bf282022-01-24 11:25:19 -0600704
705std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
706{
707 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
708 std::string hwErrorLog = "/isolated_hw_errorlog";
709 std::string errorLog = "/error_log";
710 DBusPathList paths;
711 std::vector<uint32_t> ids;
712
713 // Get all latest mapper associations
714 paths = getPaths(association);
715 for (auto& path : paths)
716 {
717 // Look for object path with hardware isolation entry if any
718 size_t pos = path.find(hwErrorLog);
719 if (pos != std::string::npos)
720 {
721 // Get the object path
722 std::string ph = path;
723 ph.erase(pos, hwErrorLog.length());
724 auto service = getService(ph, interface::hwIsolationEntry);
725 if (!service.empty())
726 {
727 bool status;
728 DBusValue value;
729
730 // Read the Resolved property from object path
731 getProperty(service, ph, interface::hwIsolationEntry,
732 "Resolved", value);
733
734 status = std::get<bool>(value);
735
736 // If the entry isn't resolved
737 if (!status)
738 {
Patrick Williams075c7922024-08-16 15:19:49 -0400739 auto assocService =
740 getService(path, interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500741 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600742 {
Matt Spinler45796e82022-07-01 11:25:27 -0500743 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600744
745 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500746 getProperty(assocService, path, interface::association,
747 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600748
749 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500750 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600751 if (!logPath.empty())
752 {
753 // Get OpenBMC event log Id
754 uint32_t id = stoi(logPath[0].substr(
755 logPath[0].find_last_of('/') + 1));
756 ids.push_back(id);
757 }
758 }
759 }
760 }
761 }
762
763 // Look for object path with error_log entry if any
764 pos = path.find(errorLog);
765 if (pos != std::string::npos)
766 {
767 auto service = getService(path, interface::association);
768 if (!service.empty())
769 {
770 DBusValue value;
771
772 // Read Endpoints property
773 getProperty(service, path, interface::association, "endpoints",
774 value);
775
776 auto logPath = std::get<std::vector<std::string>>(value);
777 if (!logPath.empty())
778 {
779 // Get OpenBMC event log Id
780 uint32_t id = stoi(
781 logPath[0].substr(logPath[0].find_last_of('/') + 1));
782 ids.push_back(id);
783 }
784 }
785 }
786 }
787
788 if (ids.size() > 1)
789 {
790 // remove duplicates to have only unique ids
791 std::sort(ids.begin(), ids.end());
792 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
793 }
794 return ids;
795}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500796
797std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
798{
Matt Spinler931cafe2025-04-22 12:31:28 -0500799 using RawProgressProperty =
800 std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>;
Vijay Lobo875b6c72021-10-20 17:38:56 -0500801
802 DBusValue value;
803 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
804 interface::bootRawProgress, "Value", value);
805
806 const auto& rawProgress = std::get<RawProgressProperty>(value);
807 return std::get<1>(rawProgress);
808}
809
Patrick Williams25291152025-02-01 08:21:42 -0500810std::optional<std::vector<uint8_t>> DataInterface::getDIProperty(
811 const std::string& locationCode) const
Arya K Padmand8ae6182024-07-19 06:25:10 -0500812{
813 std::vector<uint8_t> viniDI;
814
815 try
816 {
817 // Note : The hardcoded value 0 should be changed when comes to
818 // multinode system.
819 auto objectPath = getInventoryFromLocCode(locationCode, 0, true);
820
821 DBusValue value;
822 getProperty(service_name::inventoryManager, objectPath[0],
823 interface::viniRecordVPD, "DI", value);
824
825 viniDI = std::get<std::vector<uint8_t>>(value);
826 }
827 catch (const std::exception& e)
828 {
829 lg2::warning(
830 "Failed reading DI property for the location code : {LOC_CODE} from "
831 "interface: {IFACE} exception: {ERROR}",
832 "LOC_CODE", locationCode, "IFACE", interface::viniRecordVPD,
833 "ERROR", e);
834 return std::nullopt;
835 }
836
837 return viniDI;
838}
839
Patrick Williams25291152025-02-01 08:21:42 -0500840std::optional<bool> DataInterfaceBase::isDIMMLocCode(
841 const std::string& locCode) const
Arya K Padmand8ae6182024-07-19 06:25:10 -0500842{
843 if (_locationCache.contains(locCode))
844 {
845 return _locationCache.at(locCode);
846 }
847 else
848 {
849 return std::nullopt;
850 }
851}
852
853void DataInterfaceBase::addDIMMLocCode(const std::string& locCode,
854 bool isFRUDIMM)
855{
856 _locationCache.insert({locCode, isFRUDIMM});
857}
858
Arya K Padmanced8ed72024-09-02 05:18:07 -0500859bool DataInterfaceBase::isDIMM(const std::string& locCode)
Arya K Padmand8ae6182024-07-19 06:25:10 -0500860{
861 auto isDIMMType = isDIMMLocCode(locCode);
862 if (isDIMMType.has_value())
863 {
864 return isDIMMType.value();
865 }
866#ifndef PEL_ENABLE_PHAL
Arya K Padmanced8ed72024-09-02 05:18:07 -0500867 return false;
Arya K Padmand8ae6182024-07-19 06:25:10 -0500868#else
869 else
870 {
871 // Invoke pHAL API inorder to fetch the FRU Type
872 auto fruType = openpower::phal::pdbg::getFRUType(locCode);
Arya K Padmanced8ed72024-09-02 05:18:07 -0500873 bool isDIMMFRU{false};
Arya K Padmand8ae6182024-07-19 06:25:10 -0500874 if (fruType.has_value())
875 {
Arya K Padmand8ae6182024-07-19 06:25:10 -0500876 if (fruType.value() == ENUM_ATTR_TYPE_DIMM)
877 {
878 isDIMMFRU = true;
879 }
880 addDIMMLocCode(locCode, isDIMMFRU);
Arya K Padmand8ae6182024-07-19 06:25:10 -0500881 }
Arya K Padmanced8ed72024-09-02 05:18:07 -0500882 return isDIMMFRU;
Arya K Padmand8ae6182024-07-19 06:25:10 -0500883 }
884#endif
885}
886
harsh-agarwal1d763db32024-09-03 09:18:50 -0500887DBusPathList DataInterface::getAssociatedPaths(
888 const DBusPath& associatedPath, const DBusPath& subtree, int32_t depth,
889 const DBusInterfaceList& interfaces) const
890{
891 DBusPathList paths;
892 try
893 {
894 auto method = _bus.new_method_call(
895 service_name::objectMapper, object_path::objectMapper,
896 interface::objectMapper, "GetAssociatedSubTreePaths");
897 method.append(sdbusplus::message::object_path(associatedPath),
898 sdbusplus::message::object_path(subtree), depth,
899 interfaces);
900
901 auto reply = _bus.call(method, dbusTimeout);
902 reply.read(paths);
903 }
904 catch (const std::exception& e)
905 {
906 std::string ifaces(
907 std::ranges::fold_left_first(
908 interfaces,
909 [](std::string ifaces, const std::string& iface) {
910 return ifaces + ", " + iface;
911 })
912 .value_or(""));
913
914 lg2::error("Failed getting associated paths: {ERROR}. "
915 "AssociatedPath: {ASSOIC_PATH} Subtree: {SUBTREE} "
916 "Interfaces: {IFACES}",
917 "ERROR", e, "ASSOIC_PATH", associatedPath, "SUBTREE",
918 subtree, "IFACES", ifaces);
919 }
920 return paths;
921}
922
Matt Spinler5b423652023-05-04 13:08:44 -0500923void DataInterface::startFruPlugWatch()
924{
925 // Add a watch on inventory InterfacesAdded and then find all
926 // existing hotpluggable interfaces and add propertiesChanged
927 // watches on them.
928
929 _invIaMatch = std::make_unique<sdbusplus::bus::match_t>(
930 _bus, match_rules::interfacesAdded(object_path::baseInv),
931 std::bind(&DataInterface::inventoryIfaceAdded, this,
932 std::placeholders::_1));
933 try
934 {
935 auto paths = getPaths(hotplugInterfaces);
936
937 _invPresentMatches.clear();
938
939 std::for_each(paths.begin(), paths.end(),
940 [this](const auto& path) { addHotplugWatch(path); });
941 }
942 catch (const sdbusplus::exception_t& e)
943 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500944 lg2::warning("Failed getting FRU paths to watch: {ERROR}", "ERROR", e);
Matt Spinler5b423652023-05-04 13:08:44 -0500945 }
946}
947
948void DataInterface::addHotplugWatch(const std::string& path)
949{
950 if (!_invPresentMatches.contains(path))
951 {
952 _invPresentMatches.emplace(
953 path,
954 std::make_unique<sdbusplus::bus::match_t>(
955 _bus, match_rules::propertiesChanged(path, interface::invItem),
956 std::bind(&DataInterface::presenceChanged, this,
957 std::placeholders::_1)));
958 }
959}
960
961void DataInterface::inventoryIfaceAdded(sdbusplus::message_t& msg)
962{
963 sdbusplus::message::object_path path;
964 DBusInterfaceMap interfaces;
965
966 msg.read(path, interfaces);
967
968 // Check if any of the new interfaces are for hot pluggable FRUs.
969 if (std::find_if(interfaces.begin(), interfaces.end(),
970 [](const auto& interfacePair) {
Patrick Williams075c7922024-08-16 15:19:49 -0400971 return std::find(hotplugInterfaces.begin(),
972 hotplugInterfaces.end(),
973 interfacePair.first) !=
974 hotplugInterfaces.end();
975 }) == interfaces.end())
Matt Spinler5b423652023-05-04 13:08:44 -0500976 {
977 return;
978 }
979
980 addHotplugWatch(path.str);
981
982 // If an Inventory.Item interface was also added, check presence now.
983
984 // Notes:
985 // * This assumes the Inv.Item and Inv.Fan/PS are added together which
986 // is currently the case.
987 // * If the code ever switches to something without a Present
988 // property, then the IA signal itself would probably indicate presence.
989
990 auto itemIt = interfaces.find(interface::invItem);
991 if (itemIt != interfaces.end())
992 {
993 notifyPresenceSubsribers(path.str, itemIt->second);
994 }
995}
996
997void DataInterface::presenceChanged(sdbusplus::message_t& msg)
998{
999 DBusInterface interface;
1000 DBusPropertyMap properties;
1001
1002 msg.read(interface, properties);
1003 if (interface != interface::invItem)
1004 {
1005 return;
1006 }
1007
1008 std::string path = msg.get_path();
1009 notifyPresenceSubsribers(path, properties);
1010}
1011
1012void DataInterface::notifyPresenceSubsribers(const std::string& path,
1013 const DBusPropertyMap& properties)
1014{
Matt Spinler5ee36052023-05-30 14:20:56 -05001015 auto prop = properties.find("Present");
1016 if ((prop == properties.end()) || (!std::get<bool>(prop->second)))
1017 {
1018 return;
1019 }
1020
1021 std::string locCode;
1022
Matt Spinler5b423652023-05-04 13:08:44 -05001023 try
1024 {
Matt Spinler52ee3a42023-07-27 14:54:48 -05001025 auto service = getService(path, interface::locCode);
1026
1027 // If the hotplugged FRU is hosted by PLDM, then it is
1028 // in an IO expansion drawer and we don't care about it.
1029 if (service == service_name::pldm)
1030 {
1031 return;
1032 }
1033
Matt Spinler5ee36052023-05-30 14:20:56 -05001034 locCode = getLocationCode(path);
Matt Spinler5b423652023-05-04 13:08:44 -05001035 }
Matt Spinler5ee36052023-05-30 14:20:56 -05001036 catch (const sdbusplus::exception_t& e)
Matt Spinler5b423652023-05-04 13:08:44 -05001037 {
Matt Spinlera167a7d2023-06-30 15:14:25 -05001038 lg2::debug("Could not get location code for {PATH}: {ERROR}", "PATH",
1039 path, "ERROR", e);
Matt Spinler5ee36052023-05-30 14:20:56 -05001040 return;
Matt Spinler5b423652023-05-04 13:08:44 -05001041 }
Matt Spinler5ee36052023-05-30 14:20:56 -05001042
Matt Spinlera167a7d2023-06-30 15:14:25 -05001043 lg2::debug("Detected FRU {PATH} ({LOC}) present ", "PATH", path, "LOC",
1044 locCode);
Matt Spinler5ee36052023-05-30 14:20:56 -05001045
1046 // Tell the subscribers.
1047 setFruPresent(locCode);
Matt Spinler5b423652023-05-04 13:08:44 -05001048}
Arya K Padmanafba3162024-08-30 07:41:32 -05001049
Arya K Padmanafba3162024-08-30 07:41:32 -05001050bool DataInterface::isPHALDevTreeExist() const
1051{
1052 try
1053 {
1054 if (std::filesystem::exists(PDBG_DTB_PATH))
1055 {
1056 return true;
1057 }
1058 }
1059 catch (const std::exception& e)
1060 {
1061 lg2::error("Failed to check device tree {PHAL_DEVTREE_PATH} existence, "
1062 "{ERROR}",
1063 "PHAL_DEVTREE_PATH", PDBG_DTB_PATH, "ERROR", e);
1064 }
1065 return false;
1066}
1067
Arya K Padman0b758fb2024-09-06 11:59:45 -05001068#ifdef PEL_ENABLE_PHAL
Arya K Padmanafba3162024-08-30 07:41:32 -05001069void DataInterface::initPHAL()
1070{
1071 if (setenv("PDBG_DTB", PDBG_DTB_PATH, 1))
1072 {
1073 // Log message and continue,
1074 // This is to help continue creating PEL in raw format.
1075 lg2::error("Failed to set PDBG_DTB: ({ERRNO})", "ERRNO",
1076 strerror(errno));
1077 }
1078
1079 if (!pdbg_targets_init(NULL))
1080 {
1081 lg2::error("pdbg_targets_init failed");
1082 return;
1083 }
1084
1085 if (libekb_init())
1086 {
1087 lg2::error("libekb_init failed, skipping ffdc processing");
1088 return;
1089 }
1090}
Arya K Padman0b758fb2024-09-06 11:59:45 -05001091#endif
Arya K Padmanafba3162024-08-30 07:41:32 -05001092
1093void DataInterface::subscribeToSystemdSignals()
1094{
1095 try
1096 {
1097 auto method =
1098 _bus.new_method_call(service_name::systemd, object_path::systemd,
1099 interface::systemdMgr, "Subscribe");
1100 _systemdSlot = method.call_async([this](sdbusplus::message_t&& msg) {
1101 // Initializing with nullptr to indicate that it is not subscribed
1102 // to any signal.
1103 this->_systemdSlot = sdbusplus::slot_t(nullptr);
1104 if (msg.is_method_error())
1105 {
1106 auto* error = msg.get_error();
1107 lg2::error("Failed to subscribe JobRemoved systemd signal, "
Arya K Padmanea001072024-09-19 05:00:50 -05001108 "errorName: {ERR_NAME}, errorMsg: {ERR_MSG} ",
Arya K Padman0b758fb2024-09-06 11:59:45 -05001109 "ERR_NAME", error->name, "ERR_MSG", error->message);
Arya K Padmanafba3162024-08-30 07:41:32 -05001110 return;
1111 }
1112
1113 namespace sdbusRule = sdbusplus::bus::match::rules;
1114 this->_systemdMatch =
1115 std::make_unique<decltype(this->_systemdMatch)::element_type>(
1116 this->_bus,
1117 sdbusRule::type::signal() +
1118 sdbusRule::member("JobRemoved") +
1119 sdbusRule::path(object_path::systemd) +
1120 sdbusRule::interface(interface::systemdMgr),
1121 [this](sdbusplus::message_t& msg) {
1122 uint32_t jobID;
1123 sdbusplus::message::object_path jobObjPath;
1124 std::string jobUnitName, jobUnitResult;
1125
1126 msg.read(jobID, jobObjPath, jobUnitName, jobUnitResult);
Manish Tiwari215121e2025-09-24 08:44:39 -05001127 if ((jobUnitName == "obmc-recover-pnor.service") &&
Arya K Padmanafba3162024-08-30 07:41:32 -05001128 (jobUnitResult == "done"))
1129 {
Arya K Padmanea001072024-09-19 05:00:50 -05001130#ifdef PEL_ENABLE_PHAL
1131 this->initPHAL();
1132#endif
1133 // Invoke unsubscribe method to stop monitoring for
1134 // JobRemoved signals.
Arya K Padmanafba3162024-08-30 07:41:32 -05001135 this->unsubscribeFromSystemdSignals();
1136 }
1137 });
1138 });
1139 }
1140 catch (const sdbusplus::exception_t& e)
1141 {
1142 lg2::error(
1143 "Exception occured while handling JobRemoved systemd signal, "
1144 "exception: {ERROR}",
1145 "ERROR", e);
1146 }
1147}
1148
1149void DataInterface::unsubscribeFromSystemdSignals()
1150{
1151 try
1152 {
1153 auto method =
1154 _bus.new_method_call(service_name::systemd, object_path::systemd,
1155 interface::systemdMgr, "Unsubscribe");
1156 _systemdSlot = method.call_async([this](sdbusplus::message_t&& msg) {
1157 // Unsubscribing the _systemdSlot from the subscribed signal
1158 this->_systemdSlot = sdbusplus::slot_t(nullptr);
1159 if (msg.is_method_error())
1160 {
1161 auto* error = msg.get_error();
1162 lg2::error(
1163 "Failed to unsubscribe from JobRemoved systemd signal, "
Arya K Padmanea001072024-09-19 05:00:50 -05001164 "errorName: {ERR_NAME}, errorMsg: {ERR_MSG} ",
Arya K Padman0b758fb2024-09-06 11:59:45 -05001165 "ERR_NAME", error->name, "ERR_MSG", error->message);
Arya K Padmanafba3162024-08-30 07:41:32 -05001166 return;
1167 }
Arya K Padmanea001072024-09-19 05:00:50 -05001168 // Reset _systemdMatch to avoid reception of further JobRemoved
1169 // signals
1170 this->_systemdMatch.reset();
Arya K Padmanafba3162024-08-30 07:41:32 -05001171 });
1172 }
1173 catch (const sdbusplus::exception_t& e)
1174 {
1175 lg2::error(
1176 "Exception occured while unsubscribing from JobRemoved systemd signal, "
1177 "exception: {ERROR}",
1178 "ERROR", e);
1179 }
1180}
Arya K Padmanafba3162024-08-30 07:41:32 -05001181
Matt Spinlerc8705e22019-09-11 12:36:07 -05001182} // namespace pels
1183} // namespace openpower