blob: 7f711abc5ec28e88f658b73f069f85a41b801cc7 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlercad9c2b2019-12-02 15:42:01 -060016
Matt Spinlerc8705e22019-09-11 12:36:07 -050017#include "data_interface.hpp"
18
Matt Spinlerf61f2922020-06-23 11:32:49 -050019#include "util.hpp"
20
Matt Spinlera167a7d2023-06-30 15:14:25 -050021#include <phosphor-logging/lg2.hpp>
Matt Spinler5b423652023-05-04 13:08:44 -050022#include <xyz/openbmc_project/State/BMC/server.hpp>
Matt Spinlerf10068d2020-12-02 10:44:08 -060023#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Matt Spinlera7d9d962019-11-06 15:01:25 -060024
Arya K Padmanafba3162024-08-30 07:41:32 -050025#include <filesystem>
26
Arya K Padmand8ae6182024-07-19 06:25:10 -050027#ifdef PEL_ENABLE_PHAL
Arya K Padmanafba3162024-08-30 07:41:32 -050028#include <libekb.H>
29#include <libpdbg.h>
Arya K Padmand8ae6182024-07-19 06:25:10 -050030#include <libphal.H>
31#endif
32
Matt Spinler35a405b2022-03-02 11:42:42 -060033// Use a timeout of 10s for D-Bus calls so if there are
34// timeouts the callers of the PEL creation method won't
35// also timeout.
36constexpr auto dbusTimeout = 10000000;
37
Matt Spinlerc8705e22019-09-11 12:36:07 -050038namespace openpower
39{
40namespace pels
41{
42
43namespace service_name
44{
45constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050046constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050047constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
Matt Spinler744d8512022-06-08 08:25:47 -050048constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050049constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler52ee3a42023-07-27 14:54:48 -050050constexpr auto pldm = "xyz.openbmc_project.PLDM";
Matt Spinler412f50e2023-11-14 12:49:52 -060051constexpr auto inventoryManager = "xyz.openbmc_project.Inventory.Manager";
Matt Spinlerbbc11ef2024-01-11 16:26:51 -060052constexpr auto entityManager = "xyz.openbmc_project.EntityManager";
Arya K Padmanafba3162024-08-30 07:41:32 -050053constexpr auto systemd = "org.freedesktop.systemd1";
Matt Spinlerc8705e22019-09-11 12:36:07 -050054} // namespace service_name
55
56namespace object_path
57{
58constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
59constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050060constexpr auto motherBoardInv =
61 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060062constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060063constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
64constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060065constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060066constexpr auto enableHostPELs =
67 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050068constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050069constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Matt Spinler744d8512022-06-08 08:25:47 -050070constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050071constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0";
Arya K Padmanafba3162024-08-30 07:41:32 -050072constexpr auto systemd = "/org/freedesktop/systemd1";
Matt Spinlerc8705e22019-09-11 12:36:07 -050073} // namespace object_path
74
75namespace interface
76{
77constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
78constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
79constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060080constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060081constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060082constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
83constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
84constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060085constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050086constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060087constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050088constexpr auto compatible =
Matt Spinlerbbc11ef2024-01-11 16:26:51 -060089 "xyz.openbmc_project.Inventory.Decorator.Compatible";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050090constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050091constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050092constexpr auto operationalStatus =
93 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050094constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060095constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar027bf282022-01-24 11:25:19 -060096constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
97constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -050098constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050099constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler5b423652023-05-04 13:08:44 -0500100constexpr auto invItem = "xyz.openbmc_project.Inventory.Item";
101constexpr auto invFan = "xyz.openbmc_project.Inventory.Item.Fan";
102constexpr auto invPowerSupply =
103 "xyz.openbmc_project.Inventory.Item.PowerSupply";
Matt Spinler412f50e2023-11-14 12:49:52 -0600104constexpr auto inventoryManager = "xyz.openbmc_project.Inventory.Manager";
Arya K Padmanafba3162024-08-30 07:41:32 -0500105constexpr auto systemdMgr = "org.freedesktop.systemd1.Manager";
Matt Spinlerc8705e22019-09-11 12:36:07 -0500106} // namespace interface
107
Willy Tu6ddbf692023-09-05 10:54:16 -0700108using namespace sdbusplus::server::xyz::openbmc_project::state::boot;
109using namespace sdbusplus::server::xyz::openbmc_project::state;
Matt Spinler5b423652023-05-04 13:08:44 -0500110namespace match_rules = sdbusplus::bus::match::rules;
111
112const DBusInterfaceList hotplugInterfaces{interface::invFan,
113 interface::invPowerSupply};
Arya K Padmanafba3162024-08-30 07:41:32 -0500114static constexpr auto PDBG_DTB_PATH =
115 "/var/lib/phosphor-software-manager/hostfw/running/DEVTREE";
Matt Spinlera7d9d962019-11-06 15:01:25 -0600116
Matt Spinler0d92b522021-06-16 13:28:17 -0600117std::pair<std::string, std::string>
118 DataInterfaceBase::extractConnectorFromLocCode(
119 const std::string& locationCode)
120{
121 auto base = locationCode;
122 std::string connector{};
123
124 auto pos = base.find("-T");
125 if (pos != std::string::npos)
126 {
127 connector = base.substr(pos);
128 base = base.substr(0, pos);
129 }
130
131 return {base, connector};
132}
133
Arya K Padmanafba3162024-08-30 07:41:32 -0500134DataInterface::DataInterface(sdbusplus::bus_t& bus) :
135 _bus(bus), _systemdSlot(nullptr)
Matt Spinlerc8705e22019-09-11 12:36:07 -0500136{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600137 readBMCFWVersion();
138 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600139 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600140
Matt Spinlerf10068d2020-12-02 10:44:08 -0600141 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600142 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600143 bus, object_path::hostState, interface::bootProgress, "BootProgress",
144 *this, [this](const auto& value) {
Patrick Williams075c7922024-08-16 15:19:49 -0400145 this->_bootState = std::get<std::string>(value);
146 auto status = Progress::convertProgressStagesFromString(
147 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600148
Patrick Williams075c7922024-08-16 15:19:49 -0400149 if ((status == Progress::ProgressStages::SystemInitComplete) ||
150 (status == Progress::ProgressStages::OSRunning))
151 {
152 setHostUp(true);
153 }
154 else
155 {
156 setHostUp(false);
157 }
158 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600159
160 // Watch the host PEL enable property
161 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
162 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
163 [this](const auto& value) {
Patrick Williams075c7922024-08-16 15:19:49 -0400164 if (std::get<bool>(value) != this->_sendPELsToHost)
165 {
166 lg2::info("The send PELs to host setting changed to {VAL}",
167 "VAL", std::get<bool>(value));
168 }
169 this->_sendPELsToHost = std::get<bool>(value);
170 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600171
172 // Watch the BMCState property
173 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
174 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
175 *this, [this](const auto& value) {
Patrick Williams075c7922024-08-16 15:19:49 -0400176 const auto& state = std::get<std::string>(value);
177 this->_bmcState = state;
Matt Spinler5b423652023-05-04 13:08:44 -0500178
Patrick Williams075c7922024-08-16 15:19:49 -0400179 // Wait for BMC ready to start watching for
180 // plugs so things calm down first.
181 if (BMC::convertBMCStateFromString(state) == BMC::BMCState::Ready)
182 {
183 startFruPlugWatch();
184 }
185 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600186
187 // Watch the chassis current and requested power state properties
188 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
189 bus, object_path::chassisState, interface::chassisState, *this,
190 [this](const auto& properties) {
Patrick Williams075c7922024-08-16 15:19:49 -0400191 auto state = properties.find("CurrentPowerState");
192 if (state != properties.end())
193 {
194 this->_chassisState = std::get<std::string>(state->second);
195 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600196
Patrick Williams075c7922024-08-16 15:19:49 -0400197 auto trans = properties.find("RequestedPowerTransition");
198 if (trans != properties.end())
199 {
200 this->_chassisTransition = std::get<std::string>(trans->second);
201 }
202 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600203
204 // Watch the CurrentHostState property
205 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
206 bus, object_path::hostState, interface::hostState, "CurrentHostState",
207 *this, [this](const auto& value) {
Patrick Williams075c7922024-08-16 15:19:49 -0400208 this->_hostState = std::get<std::string>(value);
209 }));
Matt Spinler744d8512022-06-08 08:25:47 -0500210
211 // Watch the BaseBIOSTable property for the hmc managed attribute
212 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
213 bus, object_path::biosConfigMgr, interface::biosConfigMgr,
214 "BaseBIOSTable", service_name::biosConfigMgr, *this,
215 [this](const auto& value) {
Patrick Williams075c7922024-08-16 15:19:49 -0400216 const auto& attributes = std::get<BiosAttributes>(value);
Matt Spinler744d8512022-06-08 08:25:47 -0500217
Patrick Williams075c7922024-08-16 15:19:49 -0400218 auto it = attributes.find("pvm_hmc_managed");
219 if (it != attributes.end())
Matt Spinler744d8512022-06-08 08:25:47 -0500220 {
Patrick Williams075c7922024-08-16 15:19:49 -0400221 const auto& currentValVariant = std::get<5>(it->second);
222 auto currentVal = std::get_if<std::string>(&currentValVariant);
223 if (currentVal)
224 {
225 this->_hmcManaged =
226 (*currentVal == "Enabled") ? true : false;
227 }
Matt Spinler744d8512022-06-08 08:25:47 -0500228 }
Patrick Williams075c7922024-08-16 15:19:49 -0400229 }));
Arya K Padmanafba3162024-08-30 07:41:32 -0500230
Arya K Padmanafba3162024-08-30 07:41:32 -0500231 if (isPHALDevTreeExist())
232 {
Arya K Padman0b758fb2024-09-06 11:59:45 -0500233#ifdef PEL_ENABLE_PHAL
Arya K Padmanafba3162024-08-30 07:41:32 -0500234 initPHAL();
Arya K Padman0b758fb2024-09-06 11:59:45 -0500235#endif
Arya K Padmanafba3162024-08-30 07:41:32 -0500236 }
237 else
238 {
239 // Watch the "openpower-update-bios-attr-table" service to init
240 // PHAL libraries
241 subscribeToSystemdSignals();
242 }
Matt Spinlerc8705e22019-09-11 12:36:07 -0500243}
244
Patrick Williams075c7922024-08-16 15:19:49 -0400245DBusPropertyMap DataInterface::getAllProperties(
246 const std::string& service, const std::string& objectPath,
247 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500248{
249 DBusPropertyMap properties;
250
251 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
252 interface::dbusProperty, "GetAll");
253 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600254 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500255
256 reply.read(properties);
257
258 return properties;
259}
260
Patrick Williams075c7922024-08-16 15:19:49 -0400261void DataInterface::getProperty(
262 const std::string& service, const std::string& objectPath,
263 const std::string& interface, const std::string& property,
264 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600265{
Matt Spinlera7d9d962019-11-06 15:01:25 -0600266 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
267 interface::dbusProperty, "Get");
268 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600269 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600270
271 reply.read(value);
272}
273
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600274DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
275{
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600276 auto method = _bus.new_method_call(
277 service_name::objectMapper, object_path::objectMapper,
278 interface::objectMapper, "GetSubTreePaths");
279
280 method.append(std::string{"/"}, 0, interfaces);
281
Matt Spinler35a405b2022-03-02 11:42:42 -0600282 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600283
284 DBusPathList paths;
285 reply.read(paths);
286
287 return paths;
288}
289
Matt Spinlerc8705e22019-09-11 12:36:07 -0500290DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600291 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500292{
293 auto method = _bus.new_method_call(service_name::objectMapper,
294 object_path::objectMapper,
295 interface::objectMapper, "GetObject");
296
297 method.append(objectPath, std::vector<std::string>({interface}));
298
Matt Spinler35a405b2022-03-02 11:42:42 -0600299 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500300
301 std::map<DBusService, DBusInterfaceList> response;
302 reply.read(response);
303
304 if (!response.empty())
305 {
306 return response.begin()->first;
307 }
308
309 return std::string{};
310}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600311
Matt Spinler677381b2020-01-23 10:04:29 -0600312void DataInterface::readBMCFWVersion()
313{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500314 _bmcFWVersion =
315 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600316}
317
318void DataInterface::readServerFWVersion()
319{
Sumit Kumarcad16202021-05-13 04:06:15 -0500320 auto value =
321 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
322 if ((value != "") && (value.find_last_of(')') != std::string::npos))
323 {
324 std::size_t pos = value.find_first_of('(') + 1;
325 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
326 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600327}
328
Matt Spinler677381b2020-01-23 10:04:29 -0600329void DataInterface::readBMCFWVersionID()
330{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500331 _bmcFWVersionID =
332 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600333}
334
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500335std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600336{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500337 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600338 try
339 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500340 auto service = getService(object_path::systemInv, interface::invAsset);
341 if (!service.empty())
342 {
343 DBusValue value;
344 getProperty(service, object_path::systemInv, interface::invAsset,
345 "Model", value);
346
347 model = std::get<std::string>(value);
348 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600349 }
350 catch (const std::exception& e)
351 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500352 lg2::warning("Failed reading Model property from "
353 "interface: {IFACE} exception: {ERROR}",
354 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600355 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500356
357 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600358}
359
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500360std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600361{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500362 std::string sn;
363 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600364 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500365 auto service = getService(object_path::systemInv, interface::invAsset);
366 if (!service.empty())
367 {
368 DBusValue value;
369 getProperty(service, object_path::systemInv, interface::invAsset,
370 "SerialNumber", value);
371
372 sn = std::get<std::string>(value);
373 }
374 }
375 catch (const std::exception& e)
376 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500377 lg2::warning("Failed reading SerialNumber property from "
378 "interface: {IFACE} exception: {ERROR}",
379 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600380 }
381
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500382 return sn;
383}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600384
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500385std::string DataInterface::getMotherboardCCIN() const
386{
387 std::string ccin;
388
389 try
390 {
Patrick Williams075c7922024-08-16 15:19:49 -0400391 auto service =
392 getService(object_path::motherBoardInv, interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500393 if (!service.empty())
394 {
395 DBusValue value;
396 getProperty(service, object_path::motherBoardInv,
397 interface::viniRecordVPD, "CC", value);
398
399 auto cc = std::get<std::vector<uint8_t>>(value);
400 ccin = std::string{cc.begin(), cc.end()};
401 }
402 }
403 catch (const std::exception& e)
404 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500405 lg2::warning("Failed reading Motherboard CCIN property from "
406 "interface: {IFACE} exception: {ERROR}",
407 "IFACE", interface::viniRecordVPD, "ERROR", e);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500408 }
409
410 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600411}
412
Ben Tynere32b7e72021-05-18 12:38:40 -0500413std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
414{
415 std::vector<uint8_t> systemIM;
416
417 try
418 {
Patrick Williams075c7922024-08-16 15:19:49 -0400419 auto service =
420 getService(object_path::motherBoardInv, interface::vsbpRecordVPD);
Ben Tynere32b7e72021-05-18 12:38:40 -0500421 if (!service.empty())
422 {
423 DBusValue value;
424 getProperty(service, object_path::motherBoardInv,
425 interface::vsbpRecordVPD, "IM", value);
426
427 systemIM = std::get<std::vector<uint8_t>>(value);
428 }
429 }
430 catch (const std::exception& e)
431 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500432 lg2::warning("Failed reading System IM property from "
433 "interface: {IFACE} exception: {ERROR}",
434 "IFACE", interface::vsbpRecordVPD, "ERROR", e);
Ben Tynere32b7e72021-05-18 12:38:40 -0500435 }
436
437 return systemIM;
438}
439
Patrick Williams075c7922024-08-16 15:19:49 -0400440void DataInterface::getHWCalloutFields(
441 const std::string& inventoryPath, std::string& fruPartNumber,
442 std::string& ccin, std::string& serialNumber) const
Matt Spinler60c4e792020-03-13 13:45:36 -0500443{
444 // For now, attempt to get all of the properties directly on the path
445 // passed in. In the future, may need to make use of an algorithm
446 // to figure out which inventory objects actually hold these
447 // interfaces in the case of non FRUs, or possibly another service
448 // will provide this info. Any missing interfaces will result
449 // in exceptions being thrown.
450
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500451 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500452
Patrick Williams075c7922024-08-16 15:19:49 -0400453 auto properties =
454 getAllProperties(service, inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500455
456 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
457 fruPartNumber = std::string{value.begin(), value.end()};
458
459 value = std::get<std::vector<uint8_t>>(properties["CC"]);
460 ccin = std::string{value.begin(), value.end()};
461
462 value = std::get<std::vector<uint8_t>>(properties["SN"]);
463 serialNumber = std::string{value.begin(), value.end()};
464}
465
Patrick Williams25291152025-02-01 08:21:42 -0500466std::string DataInterface::getLocationCode(
467 const std::string& inventoryPath) const
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500468{
469 auto service = getService(inventoryPath, interface::locCode);
470
471 DBusValue locCode;
472 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
473 locCode);
474
475 return std::get<std::string>(locCode);
476}
477
Patrick Williams25291152025-02-01 08:21:42 -0500478std::string DataInterface::addLocationCodePrefix(
479 const std::string& locationCode)
Matt Spinler5fb24c12020-06-04 11:21:33 -0500480{
481 static const std::string locationCodePrefix{"Ufcs-"};
482
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500483 // Technically there are 2 location code prefixes, Ufcs and Umts, so
484 // if it already starts with a U then don't need to do anything.
485 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500486 {
487 return locationCodePrefix + locationCode;
488 }
489
490 return locationCode;
491}
492
493std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500494 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500495{
Matt Spinler0d92b522021-06-16 13:28:17 -0600496 // Location codes for connectors are the location code of the FRU they are
497 // on, plus a '-Tx' segment. Remove this last segment before expanding it
498 // and then add it back in afterwards. This way, the connector doesn't have
499 // to be in the model just so that it can be expanded.
500 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
501
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500502 auto method =
503 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
504 interface::vpdManager, "GetExpandedLocationCode");
505
Matt Spinler0d92b522021-06-16 13:28:17 -0600506 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500507
Matt Spinler35a405b2022-03-02 11:42:42 -0600508 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500509
510 std::string expandedLocationCode;
511 reply.read(expandedLocationCode);
512
Matt Spinler0d92b522021-06-16 13:28:17 -0600513 if (!connectorLoc.empty())
514 {
515 expandedLocationCode += connectorLoc;
516 }
517
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500518 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500519}
520
Patrick Williams075c7922024-08-16 15:19:49 -0400521std::vector<std::string> DataInterface::getInventoryFromLocCode(
522 const std::string& locationCode, uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500523{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500524 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
525 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500526
Matt Spinler0d92b522021-06-16 13:28:17 -0600527 // Remove the connector segment, if present, so that this method call
528 // returns an inventory path that getHWCalloutFields() can be used with.
529 // (The serial number, etc, aren't stored on the connector in the
530 // inventory, and may not even be modeled.)
531 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
532
Matt Spinler2f9225a2020-08-05 12:58:49 -0500533 auto method =
534 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
535 interface::vpdManager, methodName.c_str());
536
537 if (expanded)
538 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600539 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500540 }
541 else
542 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600543 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500544 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500545
Matt Spinler35a405b2022-03-02 11:42:42 -0600546 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500547
548 std::vector<sdbusplus::message::object_path> entries;
549 reply.read(entries);
550
Matt Spinlerbad056b2023-01-25 14:16:57 -0600551 std::vector<std::string> paths;
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500552
Matt Spinlerbad056b2023-01-25 14:16:57 -0600553 // Note: The D-Bus method will fail if nothing found.
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500554 std::for_each(entries.begin(), entries.end(),
Matt Spinlerbad056b2023-01-25 14:16:57 -0600555 [&paths](const auto& path) { paths.push_back(path); });
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500556
Matt Spinlerbad056b2023-01-25 14:16:57 -0600557 return paths;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500558}
559
Matt Spinler34a904c2020-08-05 14:53:28 -0500560void DataInterface::assertLEDGroup(const std::string& ledGroup,
561 bool value) const
562{
563 DBusValue variant = value;
Patrick Williams075c7922024-08-16 15:19:49 -0400564 auto method =
565 _bus.new_method_call(service_name::ledGroupManager, ledGroup.c_str(),
566 interface::dbusProperty, "Set");
Matt Spinler34a904c2020-08-05 14:53:28 -0500567 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600568 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500569}
570
Matt Spinler993168d2021-04-07 16:05:03 -0500571void DataInterface::setFunctional(const std::string& objectPath,
572 bool value) const
573{
Matt Spinler412f50e2023-11-14 12:49:52 -0600574 DBusPropertyMap prop{{"Functional", value}};
575 DBusInterfaceMap iface{{interface::operationalStatus, prop}};
Matt Spinler993168d2021-04-07 16:05:03 -0500576
Matt Spinler412f50e2023-11-14 12:49:52 -0600577 // PIM takes a relative path like /system/chassis so remove
578 // /xyz/openbmc_project/inventory if present.
579 std::string path{objectPath};
580 if (path.starts_with(object_path::baseInv))
581 {
582 path = objectPath.substr(strlen(object_path::baseInv));
583 }
584 DBusObjectMap object{{path, iface}};
Matt Spinler993168d2021-04-07 16:05:03 -0500585
Matt Spinler412f50e2023-11-14 12:49:52 -0600586 auto method = _bus.new_method_call(service_name::inventoryManager,
587 object_path::baseInv,
588 interface::inventoryManager, "Notify");
589 method.append(std::move(object));
Matt Spinler35a405b2022-03-02 11:42:42 -0600590 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500591}
592
Sumit Kumar76198a22021-07-15 05:59:57 -0500593using AssociationTuple = std::tuple<std::string, std::string, std::string>;
594using AssociationsProperty = std::vector<AssociationTuple>;
595
596void DataInterface::setCriticalAssociation(const std::string& objectPath) const
597{
598 DBusValue getAssociationValue;
599
Sumit Kumar027bf282022-01-24 11:25:19 -0600600 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500601
Sumit Kumar027bf282022-01-24 11:25:19 -0600602 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500603 getAssociationValue);
604
605 auto association = std::get<AssociationsProperty>(getAssociationValue);
606
607 AssociationTuple critAssociation{
608 "health_rollup", "critical",
609 "/xyz/openbmc_project/inventory/system/chassis"};
610
611 if (std::find(association.begin(), association.end(), critAssociation) ==
612 association.end())
613 {
614 association.push_back(critAssociation);
615 DBusValue setAssociationValue = association;
616
617 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
618 interface::dbusProperty, "Set");
619
Sumit Kumar027bf282022-01-24 11:25:19 -0600620 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500621 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600622 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500623 }
624}
625
Matt Spinler1ab66962020-10-29 13:21:44 -0500626std::vector<std::string> DataInterface::getSystemNames() const
627{
628 DBusSubTree subtree;
629 DBusValue names;
630
631 auto method = _bus.new_method_call(service_name::objectMapper,
632 object_path::objectMapper,
633 interface::objectMapper, "GetSubTree");
634 method.append(std::string{"/"}, 0,
635 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600636 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500637
638 reply.read(subtree);
639 if (subtree.empty())
640 {
641 throw std::runtime_error("Compatible interface not on D-Bus");
642 }
643
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600644 for (const auto& [path, interfaceMap] : subtree)
645 {
646 auto iface = interfaceMap.find(service_name::entityManager);
647 if (iface == interfaceMap.end())
648 {
649 continue;
650 }
Matt Spinler1ab66962020-10-29 13:21:44 -0500651
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600652 getProperty(iface->first, path, interface::compatible, "Names", names);
Matt Spinler1ab66962020-10-29 13:21:44 -0500653
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600654 return std::get<std::vector<std::string>>(names);
655 }
656
657 throw std::runtime_error("EM Compatible interface not on D-Bus");
Matt Spinler1ab66962020-10-29 13:21:44 -0500658}
659
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500660bool DataInterface::getQuiesceOnError() const
661{
662 bool ret = false;
663
664 try
665 {
Patrick Williams075c7922024-08-16 15:19:49 -0400666 auto service =
667 getService(object_path::logSetting, interface::logSetting);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500668 if (!service.empty())
669 {
670 DBusValue value;
671 getProperty(service, object_path::logSetting, interface::logSetting,
672 "QuiesceOnHwError", value);
673
674 ret = std::get<bool>(value);
675 }
676 }
677 catch (const std::exception& e)
678 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500679 lg2::warning("Failed reading QuiesceOnHwError property from "
680 "interface: {IFACE} exception: {ERROR}",
681 "IFACE", interface::logSetting, "ERROR", e);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500682 }
683
684 return ret;
685}
686
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500687#ifdef PEL_ENABLE_PHAL
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500688void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500689 GardType eGardType, uint32_t plid) const
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500690{
691 try
692 {
Deepa Karthikeyanc6396da2024-11-14 04:50:25 -0600693 libguard::libguard_init(false);
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500694 libguard::create(binPath, plid, eGardType);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500695 }
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500696 catch (libguard::exception::GuardException& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500697 {
Deepa Karthikeyanc6396da2024-11-14 04:50:25 -0600698 lg2::error("Exception in libguard {ERROR}", "ERROR", e);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500699 }
700}
Deepa Karthikeyanff35be32024-10-15 09:10:49 -0500701#endif
Sumit Kumar3e274432021-09-14 06:37:56 -0500702
703void DataInterface::createProgressSRC(
Matt Spinler931cafe2025-04-22 12:31:28 -0500704 const std::vector<uint8_t>& priSRC,
705 const std::vector<uint8_t>& srcStruct) const
Sumit Kumar3e274432021-09-14 06:37:56 -0500706{
707 DBusValue variant = std::make_tuple(priSRC, srcStruct);
708
709 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500710 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500711 interface::dbusProperty, "Set");
712
713 method.append(interface::bootRawProgress, "Value", variant);
714
Matt Spinler35a405b2022-03-02 11:42:42 -0600715 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500716}
Sumit Kumar027bf282022-01-24 11:25:19 -0600717
718std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
719{
720 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
721 std::string hwErrorLog = "/isolated_hw_errorlog";
722 std::string errorLog = "/error_log";
723 DBusPathList paths;
724 std::vector<uint32_t> ids;
725
726 // Get all latest mapper associations
727 paths = getPaths(association);
728 for (auto& path : paths)
729 {
730 // Look for object path with hardware isolation entry if any
731 size_t pos = path.find(hwErrorLog);
732 if (pos != std::string::npos)
733 {
734 // Get the object path
735 std::string ph = path;
736 ph.erase(pos, hwErrorLog.length());
737 auto service = getService(ph, interface::hwIsolationEntry);
738 if (!service.empty())
739 {
740 bool status;
741 DBusValue value;
742
743 // Read the Resolved property from object path
744 getProperty(service, ph, interface::hwIsolationEntry,
745 "Resolved", value);
746
747 status = std::get<bool>(value);
748
749 // If the entry isn't resolved
750 if (!status)
751 {
Patrick Williams075c7922024-08-16 15:19:49 -0400752 auto assocService =
753 getService(path, interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500754 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600755 {
Matt Spinler45796e82022-07-01 11:25:27 -0500756 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600757
758 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500759 getProperty(assocService, path, interface::association,
760 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600761
762 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500763 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600764 if (!logPath.empty())
765 {
766 // Get OpenBMC event log Id
767 uint32_t id = stoi(logPath[0].substr(
768 logPath[0].find_last_of('/') + 1));
769 ids.push_back(id);
770 }
771 }
772 }
773 }
774 }
775
776 // Look for object path with error_log entry if any
777 pos = path.find(errorLog);
778 if (pos != std::string::npos)
779 {
780 auto service = getService(path, interface::association);
781 if (!service.empty())
782 {
783 DBusValue value;
784
785 // Read Endpoints property
786 getProperty(service, path, interface::association, "endpoints",
787 value);
788
789 auto logPath = std::get<std::vector<std::string>>(value);
790 if (!logPath.empty())
791 {
792 // Get OpenBMC event log Id
793 uint32_t id = stoi(
794 logPath[0].substr(logPath[0].find_last_of('/') + 1));
795 ids.push_back(id);
796 }
797 }
798 }
799 }
800
801 if (ids.size() > 1)
802 {
803 // remove duplicates to have only unique ids
804 std::sort(ids.begin(), ids.end());
805 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
806 }
807 return ids;
808}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500809
810std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
811{
Matt Spinler931cafe2025-04-22 12:31:28 -0500812 using RawProgressProperty =
813 std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>;
Vijay Lobo875b6c72021-10-20 17:38:56 -0500814
815 DBusValue value;
816 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
817 interface::bootRawProgress, "Value", value);
818
819 const auto& rawProgress = std::get<RawProgressProperty>(value);
820 return std::get<1>(rawProgress);
821}
822
Patrick Williams25291152025-02-01 08:21:42 -0500823std::optional<std::vector<uint8_t>> DataInterface::getDIProperty(
824 const std::string& locationCode) const
Arya K Padmand8ae6182024-07-19 06:25:10 -0500825{
826 std::vector<uint8_t> viniDI;
827
828 try
829 {
830 // Note : The hardcoded value 0 should be changed when comes to
831 // multinode system.
832 auto objectPath = getInventoryFromLocCode(locationCode, 0, true);
833
834 DBusValue value;
835 getProperty(service_name::inventoryManager, objectPath[0],
836 interface::viniRecordVPD, "DI", value);
837
838 viniDI = std::get<std::vector<uint8_t>>(value);
839 }
840 catch (const std::exception& e)
841 {
842 lg2::warning(
843 "Failed reading DI property for the location code : {LOC_CODE} from "
844 "interface: {IFACE} exception: {ERROR}",
845 "LOC_CODE", locationCode, "IFACE", interface::viniRecordVPD,
846 "ERROR", e);
847 return std::nullopt;
848 }
849
850 return viniDI;
851}
852
Patrick Williams25291152025-02-01 08:21:42 -0500853std::optional<bool> DataInterfaceBase::isDIMMLocCode(
854 const std::string& locCode) const
Arya K Padmand8ae6182024-07-19 06:25:10 -0500855{
856 if (_locationCache.contains(locCode))
857 {
858 return _locationCache.at(locCode);
859 }
860 else
861 {
862 return std::nullopt;
863 }
864}
865
866void DataInterfaceBase::addDIMMLocCode(const std::string& locCode,
867 bool isFRUDIMM)
868{
869 _locationCache.insert({locCode, isFRUDIMM});
870}
871
Arya K Padmanced8ed72024-09-02 05:18:07 -0500872bool DataInterfaceBase::isDIMM(const std::string& locCode)
Arya K Padmand8ae6182024-07-19 06:25:10 -0500873{
874 auto isDIMMType = isDIMMLocCode(locCode);
875 if (isDIMMType.has_value())
876 {
877 return isDIMMType.value();
878 }
879#ifndef PEL_ENABLE_PHAL
Arya K Padmanced8ed72024-09-02 05:18:07 -0500880 return false;
Arya K Padmand8ae6182024-07-19 06:25:10 -0500881#else
882 else
883 {
884 // Invoke pHAL API inorder to fetch the FRU Type
885 auto fruType = openpower::phal::pdbg::getFRUType(locCode);
Arya K Padmanced8ed72024-09-02 05:18:07 -0500886 bool isDIMMFRU{false};
Arya K Padmand8ae6182024-07-19 06:25:10 -0500887 if (fruType.has_value())
888 {
Arya K Padmand8ae6182024-07-19 06:25:10 -0500889 if (fruType.value() == ENUM_ATTR_TYPE_DIMM)
890 {
891 isDIMMFRU = true;
892 }
893 addDIMMLocCode(locCode, isDIMMFRU);
Arya K Padmand8ae6182024-07-19 06:25:10 -0500894 }
Arya K Padmanced8ed72024-09-02 05:18:07 -0500895 return isDIMMFRU;
Arya K Padmand8ae6182024-07-19 06:25:10 -0500896 }
897#endif
898}
899
harsh-agarwal1d763db32024-09-03 09:18:50 -0500900DBusPathList DataInterface::getAssociatedPaths(
901 const DBusPath& associatedPath, const DBusPath& subtree, int32_t depth,
902 const DBusInterfaceList& interfaces) const
903{
904 DBusPathList paths;
905 try
906 {
907 auto method = _bus.new_method_call(
908 service_name::objectMapper, object_path::objectMapper,
909 interface::objectMapper, "GetAssociatedSubTreePaths");
910 method.append(sdbusplus::message::object_path(associatedPath),
911 sdbusplus::message::object_path(subtree), depth,
912 interfaces);
913
914 auto reply = _bus.call(method, dbusTimeout);
915 reply.read(paths);
916 }
917 catch (const std::exception& e)
918 {
919 std::string ifaces(
920 std::ranges::fold_left_first(
921 interfaces,
922 [](std::string ifaces, const std::string& iface) {
923 return ifaces + ", " + iface;
924 })
925 .value_or(""));
926
927 lg2::error("Failed getting associated paths: {ERROR}. "
928 "AssociatedPath: {ASSOIC_PATH} Subtree: {SUBTREE} "
929 "Interfaces: {IFACES}",
930 "ERROR", e, "ASSOIC_PATH", associatedPath, "SUBTREE",
931 subtree, "IFACES", ifaces);
932 }
933 return paths;
934}
935
Matt Spinler5b423652023-05-04 13:08:44 -0500936void DataInterface::startFruPlugWatch()
937{
938 // Add a watch on inventory InterfacesAdded and then find all
939 // existing hotpluggable interfaces and add propertiesChanged
940 // watches on them.
941
942 _invIaMatch = std::make_unique<sdbusplus::bus::match_t>(
943 _bus, match_rules::interfacesAdded(object_path::baseInv),
944 std::bind(&DataInterface::inventoryIfaceAdded, this,
945 std::placeholders::_1));
946 try
947 {
948 auto paths = getPaths(hotplugInterfaces);
949
950 _invPresentMatches.clear();
951
952 std::for_each(paths.begin(), paths.end(),
953 [this](const auto& path) { addHotplugWatch(path); });
954 }
955 catch (const sdbusplus::exception_t& e)
956 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500957 lg2::warning("Failed getting FRU paths to watch: {ERROR}", "ERROR", e);
Matt Spinler5b423652023-05-04 13:08:44 -0500958 }
959}
960
961void DataInterface::addHotplugWatch(const std::string& path)
962{
963 if (!_invPresentMatches.contains(path))
964 {
965 _invPresentMatches.emplace(
966 path,
967 std::make_unique<sdbusplus::bus::match_t>(
968 _bus, match_rules::propertiesChanged(path, interface::invItem),
969 std::bind(&DataInterface::presenceChanged, this,
970 std::placeholders::_1)));
971 }
972}
973
974void DataInterface::inventoryIfaceAdded(sdbusplus::message_t& msg)
975{
976 sdbusplus::message::object_path path;
977 DBusInterfaceMap interfaces;
978
979 msg.read(path, interfaces);
980
981 // Check if any of the new interfaces are for hot pluggable FRUs.
982 if (std::find_if(interfaces.begin(), interfaces.end(),
983 [](const auto& interfacePair) {
Patrick Williams075c7922024-08-16 15:19:49 -0400984 return std::find(hotplugInterfaces.begin(),
985 hotplugInterfaces.end(),
986 interfacePair.first) !=
987 hotplugInterfaces.end();
988 }) == interfaces.end())
Matt Spinler5b423652023-05-04 13:08:44 -0500989 {
990 return;
991 }
992
993 addHotplugWatch(path.str);
994
995 // If an Inventory.Item interface was also added, check presence now.
996
997 // Notes:
998 // * This assumes the Inv.Item and Inv.Fan/PS are added together which
999 // is currently the case.
1000 // * If the code ever switches to something without a Present
1001 // property, then the IA signal itself would probably indicate presence.
1002
1003 auto itemIt = interfaces.find(interface::invItem);
1004 if (itemIt != interfaces.end())
1005 {
1006 notifyPresenceSubsribers(path.str, itemIt->second);
1007 }
1008}
1009
1010void DataInterface::presenceChanged(sdbusplus::message_t& msg)
1011{
1012 DBusInterface interface;
1013 DBusPropertyMap properties;
1014
1015 msg.read(interface, properties);
1016 if (interface != interface::invItem)
1017 {
1018 return;
1019 }
1020
1021 std::string path = msg.get_path();
1022 notifyPresenceSubsribers(path, properties);
1023}
1024
1025void DataInterface::notifyPresenceSubsribers(const std::string& path,
1026 const DBusPropertyMap& properties)
1027{
Matt Spinler5ee36052023-05-30 14:20:56 -05001028 auto prop = properties.find("Present");
1029 if ((prop == properties.end()) || (!std::get<bool>(prop->second)))
1030 {
1031 return;
1032 }
1033
1034 std::string locCode;
1035
Matt Spinler5b423652023-05-04 13:08:44 -05001036 try
1037 {
Matt Spinler52ee3a42023-07-27 14:54:48 -05001038 auto service = getService(path, interface::locCode);
1039
1040 // If the hotplugged FRU is hosted by PLDM, then it is
1041 // in an IO expansion drawer and we don't care about it.
1042 if (service == service_name::pldm)
1043 {
1044 return;
1045 }
1046
Matt Spinler5ee36052023-05-30 14:20:56 -05001047 locCode = getLocationCode(path);
Matt Spinler5b423652023-05-04 13:08:44 -05001048 }
Matt Spinler5ee36052023-05-30 14:20:56 -05001049 catch (const sdbusplus::exception_t& e)
Matt Spinler5b423652023-05-04 13:08:44 -05001050 {
Matt Spinlera167a7d2023-06-30 15:14:25 -05001051 lg2::debug("Could not get location code for {PATH}: {ERROR}", "PATH",
1052 path, "ERROR", e);
Matt Spinler5ee36052023-05-30 14:20:56 -05001053 return;
Matt Spinler5b423652023-05-04 13:08:44 -05001054 }
Matt Spinler5ee36052023-05-30 14:20:56 -05001055
Matt Spinlera167a7d2023-06-30 15:14:25 -05001056 lg2::debug("Detected FRU {PATH} ({LOC}) present ", "PATH", path, "LOC",
1057 locCode);
Matt Spinler5ee36052023-05-30 14:20:56 -05001058
1059 // Tell the subscribers.
1060 setFruPresent(locCode);
Matt Spinler5b423652023-05-04 13:08:44 -05001061}
Arya K Padmanafba3162024-08-30 07:41:32 -05001062
Arya K Padmanafba3162024-08-30 07:41:32 -05001063bool DataInterface::isPHALDevTreeExist() const
1064{
1065 try
1066 {
1067 if (std::filesystem::exists(PDBG_DTB_PATH))
1068 {
1069 return true;
1070 }
1071 }
1072 catch (const std::exception& e)
1073 {
1074 lg2::error("Failed to check device tree {PHAL_DEVTREE_PATH} existence, "
1075 "{ERROR}",
1076 "PHAL_DEVTREE_PATH", PDBG_DTB_PATH, "ERROR", e);
1077 }
1078 return false;
1079}
1080
Arya K Padman0b758fb2024-09-06 11:59:45 -05001081#ifdef PEL_ENABLE_PHAL
Arya K Padmanafba3162024-08-30 07:41:32 -05001082void DataInterface::initPHAL()
1083{
1084 if (setenv("PDBG_DTB", PDBG_DTB_PATH, 1))
1085 {
1086 // Log message and continue,
1087 // This is to help continue creating PEL in raw format.
1088 lg2::error("Failed to set PDBG_DTB: ({ERRNO})", "ERRNO",
1089 strerror(errno));
1090 }
1091
1092 if (!pdbg_targets_init(NULL))
1093 {
1094 lg2::error("pdbg_targets_init failed");
1095 return;
1096 }
1097
1098 if (libekb_init())
1099 {
1100 lg2::error("libekb_init failed, skipping ffdc processing");
1101 return;
1102 }
1103}
Arya K Padman0b758fb2024-09-06 11:59:45 -05001104#endif
Arya K Padmanafba3162024-08-30 07:41:32 -05001105
1106void DataInterface::subscribeToSystemdSignals()
1107{
1108 try
1109 {
1110 auto method =
1111 _bus.new_method_call(service_name::systemd, object_path::systemd,
1112 interface::systemdMgr, "Subscribe");
1113 _systemdSlot = method.call_async([this](sdbusplus::message_t&& msg) {
1114 // Initializing with nullptr to indicate that it is not subscribed
1115 // to any signal.
1116 this->_systemdSlot = sdbusplus::slot_t(nullptr);
1117 if (msg.is_method_error())
1118 {
1119 auto* error = msg.get_error();
1120 lg2::error("Failed to subscribe JobRemoved systemd signal, "
Arya K Padmanea001072024-09-19 05:00:50 -05001121 "errorName: {ERR_NAME}, errorMsg: {ERR_MSG} ",
Arya K Padman0b758fb2024-09-06 11:59:45 -05001122 "ERR_NAME", error->name, "ERR_MSG", error->message);
Arya K Padmanafba3162024-08-30 07:41:32 -05001123 return;
1124 }
1125
1126 namespace sdbusRule = sdbusplus::bus::match::rules;
1127 this->_systemdMatch =
1128 std::make_unique<decltype(this->_systemdMatch)::element_type>(
1129 this->_bus,
1130 sdbusRule::type::signal() +
1131 sdbusRule::member("JobRemoved") +
1132 sdbusRule::path(object_path::systemd) +
1133 sdbusRule::interface(interface::systemdMgr),
1134 [this](sdbusplus::message_t& msg) {
1135 uint32_t jobID;
1136 sdbusplus::message::object_path jobObjPath;
1137 std::string jobUnitName, jobUnitResult;
1138
1139 msg.read(jobID, jobObjPath, jobUnitName, jobUnitResult);
1140 if ((jobUnitName ==
1141 "openpower-update-bios-attr-table.service") &&
1142 (jobUnitResult == "done"))
1143 {
Arya K Padmanea001072024-09-19 05:00:50 -05001144#ifdef PEL_ENABLE_PHAL
1145 this->initPHAL();
1146#endif
1147 // Invoke unsubscribe method to stop monitoring for
1148 // JobRemoved signals.
Arya K Padmanafba3162024-08-30 07:41:32 -05001149 this->unsubscribeFromSystemdSignals();
1150 }
1151 });
1152 });
1153 }
1154 catch (const sdbusplus::exception_t& e)
1155 {
1156 lg2::error(
1157 "Exception occured while handling JobRemoved systemd signal, "
1158 "exception: {ERROR}",
1159 "ERROR", e);
1160 }
1161}
1162
1163void DataInterface::unsubscribeFromSystemdSignals()
1164{
1165 try
1166 {
1167 auto method =
1168 _bus.new_method_call(service_name::systemd, object_path::systemd,
1169 interface::systemdMgr, "Unsubscribe");
1170 _systemdSlot = method.call_async([this](sdbusplus::message_t&& msg) {
1171 // Unsubscribing the _systemdSlot from the subscribed signal
1172 this->_systemdSlot = sdbusplus::slot_t(nullptr);
1173 if (msg.is_method_error())
1174 {
1175 auto* error = msg.get_error();
1176 lg2::error(
1177 "Failed to unsubscribe from JobRemoved systemd signal, "
Arya K Padmanea001072024-09-19 05:00:50 -05001178 "errorName: {ERR_NAME}, errorMsg: {ERR_MSG} ",
Arya K Padman0b758fb2024-09-06 11:59:45 -05001179 "ERR_NAME", error->name, "ERR_MSG", error->message);
Arya K Padmanafba3162024-08-30 07:41:32 -05001180 return;
1181 }
Arya K Padmanea001072024-09-19 05:00:50 -05001182 // Reset _systemdMatch to avoid reception of further JobRemoved
1183 // signals
1184 this->_systemdMatch.reset();
Arya K Padmanafba3162024-08-30 07:41:32 -05001185 });
1186 }
1187 catch (const sdbusplus::exception_t& e)
1188 {
1189 lg2::error(
1190 "Exception occured while unsubscribing from JobRemoved systemd signal, "
1191 "exception: {ERROR}",
1192 "ERROR", e);
1193 }
1194}
Arya K Padmanafba3162024-08-30 07:41:32 -05001195
Matt Spinlerc8705e22019-09-11 12:36:07 -05001196} // namespace pels
1197} // namespace openpower