blob: 98b8f31c72a6bb925d2623a958113c4189150e56 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlercad9c2b2019-12-02 15:42:01 -060016#include "config.h"
17
Matt Spinlerc8705e22019-09-11 12:36:07 -050018#include "data_interface.hpp"
19
Matt Spinlerf61f2922020-06-23 11:32:49 -050020#include "util.hpp"
21
Matt Spinlera167a7d2023-06-30 15:14:25 -050022#include <phosphor-logging/lg2.hpp>
Matt Spinler5b423652023-05-04 13:08:44 -050023#include <xyz/openbmc_project/State/BMC/server.hpp>
Matt Spinlerf10068d2020-12-02 10:44:08 -060024#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Matt Spinlera7d9d962019-11-06 15:01:25 -060025
Patrick Williams2544b412022-10-04 08:41:06 -050026#include <fstream>
27#include <iterator>
28
Matt Spinler35a405b2022-03-02 11:42:42 -060029// Use a timeout of 10s for D-Bus calls so if there are
30// timeouts the callers of the PEL creation method won't
31// also timeout.
32constexpr auto dbusTimeout = 10000000;
33
Matt Spinlerc8705e22019-09-11 12:36:07 -050034namespace openpower
35{
36namespace pels
37{
38
39namespace service_name
40{
41constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050042constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050043constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050044constexpr auto logSetting = "xyz.openbmc_project.Settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050045constexpr auto hwIsolation = "org.open_power.HardwareIsolation";
Matt Spinler744d8512022-06-08 08:25:47 -050046constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050047constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler52ee3a42023-07-27 14:54:48 -050048constexpr auto pldm = "xyz.openbmc_project.PLDM";
Matt Spinler412f50e2023-11-14 12:49:52 -060049constexpr auto inventoryManager = "xyz.openbmc_project.Inventory.Manager";
Matt Spinlerc8705e22019-09-11 12:36:07 -050050} // namespace service_name
51
52namespace object_path
53{
54constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
55constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050056constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050057constexpr auto motherBoardInv =
58 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060059constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060060constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
61constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060062constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060063constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060064constexpr auto enableHostPELs =
65 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050066constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050067constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050068constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Matt Spinler744d8512022-06-08 08:25:47 -050069constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050070constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0";
Matt Spinlerc8705e22019-09-11 12:36:07 -050071} // namespace object_path
72
73namespace interface
74{
75constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
76constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
77constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060078constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinlerb3f51862019-12-09 13:55:10 -060079constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060080constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060081constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
82constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
83constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060084constexpr auto invMotherboard =
85 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
86constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050087constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060088constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050089constexpr auto compatible =
90 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050091constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050092constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050093constexpr auto operationalStatus =
94 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050095constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060096constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050097constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
98constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050099constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar027bf282022-01-24 11:25:19 -0600100constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
101constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -0500102constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -0500103constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler5b423652023-05-04 13:08:44 -0500104constexpr auto invItem = "xyz.openbmc_project.Inventory.Item";
105constexpr auto invFan = "xyz.openbmc_project.Inventory.Item.Fan";
106constexpr auto invPowerSupply =
107 "xyz.openbmc_project.Inventory.Item.PowerSupply";
Matt Spinler412f50e2023-11-14 12:49:52 -0600108constexpr auto inventoryManager = "xyz.openbmc_project.Inventory.Manager";
Matt Spinlerc8705e22019-09-11 12:36:07 -0500109} // namespace interface
110
Willy Tu6ddbf692023-09-05 10:54:16 -0700111using namespace sdbusplus::server::xyz::openbmc_project::state::boot;
112using namespace sdbusplus::server::xyz::openbmc_project::state;
Matt Spinler5b423652023-05-04 13:08:44 -0500113namespace match_rules = sdbusplus::bus::match::rules;
114
115const DBusInterfaceList hotplugInterfaces{interface::invFan,
116 interface::invPowerSupply};
Matt Spinlera7d9d962019-11-06 15:01:25 -0600117
Matt Spinler0d92b522021-06-16 13:28:17 -0600118std::pair<std::string, std::string>
119 DataInterfaceBase::extractConnectorFromLocCode(
120 const std::string& locationCode)
121{
122 auto base = locationCode;
123 std::string connector{};
124
125 auto pos = base.find("-T");
126 if (pos != std::string::npos)
127 {
128 connector = base.substr(pos);
129 base = base.substr(0, pos);
130 }
131
132 return {base, connector};
133}
134
Patrick Williams45e83522022-07-22 19:26:52 -0500135DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus)
Matt Spinlerc8705e22019-09-11 12:36:07 -0500136{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600137 readBMCFWVersion();
138 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600139 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600140
Matt Spinlerf10068d2020-12-02 10:44:08 -0600141 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600142 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600143 bus, object_path::hostState, interface::bootProgress, "BootProgress",
144 *this, [this](const auto& value) {
Patrick Williams5fb575a2023-10-20 11:18:21 -0500145 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 Williams5fb575a2023-10-20 11:18:21 -0500149 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 Williamsac1ba3f2023-05-10 07:50:16 -0500164 if (std::get<bool>(value) != this->_sendPELsToHost)
165 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500166 lg2::info("The send PELs to host setting changed to {VAL}", "VAL",
167 std::get<bool>(value));
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500168 }
169 this->_sendPELsToHost = std::get<bool>(value);
Patrick Williams5fb575a2023-10-20 11:18:21 -0500170 }));
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 Williams5fb575a2023-10-20 11:18:21 -0500176 const auto& state = std::get<std::string>(value);
177 this->_bmcState = state;
Matt Spinler5b423652023-05-04 13:08:44 -0500178
Patrick Williams5fb575a2023-10-20 11:18:21 -0500179 // 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 Williamsac1ba3f2023-05-10 07:50:16 -0500191 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 Williamsac1ba3f2023-05-10 07:50:16 -0500197 auto trans = properties.find("RequestedPowerTransition");
198 if (trans != properties.end())
199 {
200 this->_chassisTransition = std::get<std::string>(trans->second);
201 }
Patrick Williams5fb575a2023-10-20 11:18:21 -0500202 }));
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 Williams5fb575a2023-10-20 11:18:21 -0500208 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 Williamsac1ba3f2023-05-10 07:50:16 -0500216 const auto& attributes = std::get<BiosAttributes>(value);
Matt Spinler744d8512022-06-08 08:25:47 -0500217
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500218 auto it = attributes.find("pvm_hmc_managed");
219 if (it != attributes.end())
220 {
221 const auto& currentValVariant = std::get<5>(it->second);
222 auto currentVal = std::get_if<std::string>(&currentValVariant);
223 if (currentVal)
Matt Spinler744d8512022-06-08 08:25:47 -0500224 {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500225 this->_hmcManaged = (*currentVal == "Enabled") ? true : false;
Matt Spinler744d8512022-06-08 08:25:47 -0500226 }
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500227 }
Patrick Williams5fb575a2023-10-20 11:18:21 -0500228 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500229}
230
Matt Spinler2a28c932020-02-03 14:23:40 -0600231DBusPropertyMap
232 DataInterface::getAllProperties(const std::string& service,
233 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
Matt Spinlera7d9d962019-11-06 15:01:25 -0600248void DataInterface::getProperty(const std::string& service,
249 const std::string& objectPath,
250 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600251 const std::string& property,
252 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600253{
Matt Spinlera7d9d962019-11-06 15:01:25 -0600254 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
255 interface::dbusProperty, "Get");
256 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600257 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600258
259 reply.read(value);
260}
261
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600262DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
263{
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600264 auto method = _bus.new_method_call(
265 service_name::objectMapper, object_path::objectMapper,
266 interface::objectMapper, "GetSubTreePaths");
267
268 method.append(std::string{"/"}, 0, interfaces);
269
Matt Spinler35a405b2022-03-02 11:42:42 -0600270 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600271
272 DBusPathList paths;
273 reply.read(paths);
274
275 return paths;
276}
277
Matt Spinlerc8705e22019-09-11 12:36:07 -0500278DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600279 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500280{
281 auto method = _bus.new_method_call(service_name::objectMapper,
282 object_path::objectMapper,
283 interface::objectMapper, "GetObject");
284
285 method.append(objectPath, std::vector<std::string>({interface}));
286
Matt Spinler35a405b2022-03-02 11:42:42 -0600287 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500288
289 std::map<DBusService, DBusInterfaceList> response;
290 reply.read(response);
291
292 if (!response.empty())
293 {
294 return response.begin()->first;
295 }
296
297 return std::string{};
298}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600299
Matt Spinler677381b2020-01-23 10:04:29 -0600300void DataInterface::readBMCFWVersion()
301{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500302 _bmcFWVersion =
303 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600304}
305
306void DataInterface::readServerFWVersion()
307{
Sumit Kumarcad16202021-05-13 04:06:15 -0500308 auto value =
309 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
310 if ((value != "") && (value.find_last_of(')') != std::string::npos))
311 {
312 std::size_t pos = value.find_first_of('(') + 1;
313 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
314 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600315}
316
Matt Spinler677381b2020-01-23 10:04:29 -0600317void DataInterface::readBMCFWVersionID()
318{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500319 _bmcFWVersionID =
320 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600321}
322
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500323std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600324{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500325 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600326 try
327 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500328 auto service = getService(object_path::systemInv, interface::invAsset);
329 if (!service.empty())
330 {
331 DBusValue value;
332 getProperty(service, object_path::systemInv, interface::invAsset,
333 "Model", value);
334
335 model = std::get<std::string>(value);
336 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600337 }
338 catch (const std::exception& e)
339 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500340 lg2::warning("Failed reading Model property from "
341 "interface: {IFACE} exception: {ERROR}",
342 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600343 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500344
345 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600346}
347
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500348std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600349{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500350 std::string sn;
351 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600352 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500353 auto service = getService(object_path::systemInv, interface::invAsset);
354 if (!service.empty())
355 {
356 DBusValue value;
357 getProperty(service, object_path::systemInv, interface::invAsset,
358 "SerialNumber", value);
359
360 sn = std::get<std::string>(value);
361 }
362 }
363 catch (const std::exception& e)
364 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500365 lg2::warning("Failed reading SerialNumber property from "
366 "interface: {IFACE} exception: {ERROR}",
367 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600368 }
369
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500370 return sn;
371}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600372
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500373std::string DataInterface::getMotherboardCCIN() const
374{
375 std::string ccin;
376
377 try
378 {
Patrick Williams2544b412022-10-04 08:41:06 -0500379 auto service = getService(object_path::motherBoardInv,
380 interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500381 if (!service.empty())
382 {
383 DBusValue value;
384 getProperty(service, object_path::motherBoardInv,
385 interface::viniRecordVPD, "CC", value);
386
387 auto cc = std::get<std::vector<uint8_t>>(value);
388 ccin = std::string{cc.begin(), cc.end()};
389 }
390 }
391 catch (const std::exception& e)
392 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500393 lg2::warning("Failed reading Motherboard CCIN property from "
394 "interface: {IFACE} exception: {ERROR}",
395 "IFACE", interface::viniRecordVPD, "ERROR", e);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500396 }
397
398 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600399}
400
Ben Tynere32b7e72021-05-18 12:38:40 -0500401std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
402{
403 std::vector<uint8_t> systemIM;
404
405 try
406 {
Patrick Williams2544b412022-10-04 08:41:06 -0500407 auto service = getService(object_path::motherBoardInv,
408 interface::vsbpRecordVPD);
Ben Tynere32b7e72021-05-18 12:38:40 -0500409 if (!service.empty())
410 {
411 DBusValue value;
412 getProperty(service, object_path::motherBoardInv,
413 interface::vsbpRecordVPD, "IM", value);
414
415 systemIM = std::get<std::vector<uint8_t>>(value);
416 }
417 }
418 catch (const std::exception& e)
419 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500420 lg2::warning("Failed reading System IM property from "
421 "interface: {IFACE} exception: {ERROR}",
422 "IFACE", interface::vsbpRecordVPD, "ERROR", e);
Ben Tynere32b7e72021-05-18 12:38:40 -0500423 }
424
425 return systemIM;
426}
427
Matt Spinler60c4e792020-03-13 13:45:36 -0500428void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500429 std::string& fruPartNumber,
430 std::string& ccin,
431 std::string& serialNumber) const
432{
433 // For now, attempt to get all of the properties directly on the path
434 // passed in. In the future, may need to make use of an algorithm
435 // to figure out which inventory objects actually hold these
436 // interfaces in the case of non FRUs, or possibly another service
437 // will provide this info. Any missing interfaces will result
438 // in exceptions being thrown.
439
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500440 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500441
Patrick Williams2544b412022-10-04 08:41:06 -0500442 auto properties = getAllProperties(service, inventoryPath,
443 interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500444
445 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
446 fruPartNumber = std::string{value.begin(), value.end()};
447
448 value = std::get<std::vector<uint8_t>>(properties["CC"]);
449 ccin = std::string{value.begin(), value.end()};
450
451 value = std::get<std::vector<uint8_t>>(properties["SN"]);
452 serialNumber = std::string{value.begin(), value.end()};
453}
454
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500455std::string
456 DataInterface::getLocationCode(const std::string& inventoryPath) const
457{
458 auto service = getService(inventoryPath, interface::locCode);
459
460 DBusValue locCode;
461 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
462 locCode);
463
464 return std::get<std::string>(locCode);
465}
466
Matt Spinler5fb24c12020-06-04 11:21:33 -0500467std::string
468 DataInterface::addLocationCodePrefix(const std::string& locationCode)
469{
470 static const std::string locationCodePrefix{"Ufcs-"};
471
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500472 // Technically there are 2 location code prefixes, Ufcs and Umts, so
473 // if it already starts with a U then don't need to do anything.
474 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500475 {
476 return locationCodePrefix + locationCode;
477 }
478
479 return locationCode;
480}
481
482std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500483 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500484{
Matt Spinler0d92b522021-06-16 13:28:17 -0600485 // Location codes for connectors are the location code of the FRU they are
486 // on, plus a '-Tx' segment. Remove this last segment before expanding it
487 // and then add it back in afterwards. This way, the connector doesn't have
488 // to be in the model just so that it can be expanded.
489 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
490
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500491 auto method =
492 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
493 interface::vpdManager, "GetExpandedLocationCode");
494
Matt Spinler0d92b522021-06-16 13:28:17 -0600495 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500496
Matt Spinler35a405b2022-03-02 11:42:42 -0600497 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500498
499 std::string expandedLocationCode;
500 reply.read(expandedLocationCode);
501
Matt Spinler0d92b522021-06-16 13:28:17 -0600502 if (!connectorLoc.empty())
503 {
504 expandedLocationCode += connectorLoc;
505 }
506
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500507 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500508}
509
Matt Spinlerbad056b2023-01-25 14:16:57 -0600510std::vector<std::string>
Matt Spinler2f9225a2020-08-05 12:58:49 -0500511 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
512 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500513{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500514 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
515 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500516
Matt Spinler0d92b522021-06-16 13:28:17 -0600517 // Remove the connector segment, if present, so that this method call
518 // returns an inventory path that getHWCalloutFields() can be used with.
519 // (The serial number, etc, aren't stored on the connector in the
520 // inventory, and may not even be modeled.)
521 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
522
Matt Spinler2f9225a2020-08-05 12:58:49 -0500523 auto method =
524 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
525 interface::vpdManager, methodName.c_str());
526
527 if (expanded)
528 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600529 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500530 }
531 else
532 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600533 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500534 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500535
Matt Spinler35a405b2022-03-02 11:42:42 -0600536 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500537
538 std::vector<sdbusplus::message::object_path> entries;
539 reply.read(entries);
540
Matt Spinlerbad056b2023-01-25 14:16:57 -0600541 std::vector<std::string> paths;
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500542
Matt Spinlerbad056b2023-01-25 14:16:57 -0600543 // Note: The D-Bus method will fail if nothing found.
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500544 std::for_each(entries.begin(), entries.end(),
Matt Spinlerbad056b2023-01-25 14:16:57 -0600545 [&paths](const auto& path) { paths.push_back(path); });
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500546
Matt Spinlerbad056b2023-01-25 14:16:57 -0600547 return paths;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500548}
549
Matt Spinler34a904c2020-08-05 14:53:28 -0500550void DataInterface::assertLEDGroup(const std::string& ledGroup,
551 bool value) const
552{
553 DBusValue variant = value;
Patrick Williams2544b412022-10-04 08:41:06 -0500554 auto method = _bus.new_method_call(service_name::ledGroupManager,
555 ledGroup.c_str(),
556 interface::dbusProperty, "Set");
Matt Spinler34a904c2020-08-05 14:53:28 -0500557 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600558 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500559}
560
Matt Spinler993168d2021-04-07 16:05:03 -0500561void DataInterface::setFunctional(const std::string& objectPath,
562 bool value) const
563{
Matt Spinler412f50e2023-11-14 12:49:52 -0600564 DBusPropertyMap prop{{"Functional", value}};
565 DBusInterfaceMap iface{{interface::operationalStatus, prop}};
Matt Spinler993168d2021-04-07 16:05:03 -0500566
Matt Spinler412f50e2023-11-14 12:49:52 -0600567 // PIM takes a relative path like /system/chassis so remove
568 // /xyz/openbmc_project/inventory if present.
569 std::string path{objectPath};
570 if (path.starts_with(object_path::baseInv))
571 {
572 path = objectPath.substr(strlen(object_path::baseInv));
573 }
574 DBusObjectMap object{{path, iface}};
Matt Spinler993168d2021-04-07 16:05:03 -0500575
Matt Spinler412f50e2023-11-14 12:49:52 -0600576 auto method = _bus.new_method_call(service_name::inventoryManager,
577 object_path::baseInv,
578 interface::inventoryManager, "Notify");
579 method.append(std::move(object));
Matt Spinler35a405b2022-03-02 11:42:42 -0600580 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500581}
582
Sumit Kumar76198a22021-07-15 05:59:57 -0500583using AssociationTuple = std::tuple<std::string, std::string, std::string>;
584using AssociationsProperty = std::vector<AssociationTuple>;
585
586void DataInterface::setCriticalAssociation(const std::string& objectPath) const
587{
588 DBusValue getAssociationValue;
589
Sumit Kumar027bf282022-01-24 11:25:19 -0600590 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500591
Sumit Kumar027bf282022-01-24 11:25:19 -0600592 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500593 getAssociationValue);
594
595 auto association = std::get<AssociationsProperty>(getAssociationValue);
596
597 AssociationTuple critAssociation{
598 "health_rollup", "critical",
599 "/xyz/openbmc_project/inventory/system/chassis"};
600
601 if (std::find(association.begin(), association.end(), critAssociation) ==
602 association.end())
603 {
604 association.push_back(critAssociation);
605 DBusValue setAssociationValue = association;
606
607 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
608 interface::dbusProperty, "Set");
609
Sumit Kumar027bf282022-01-24 11:25:19 -0600610 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500611 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600612 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500613 }
614}
615
Matt Spinler1ab66962020-10-29 13:21:44 -0500616std::vector<std::string> DataInterface::getSystemNames() const
617{
618 DBusSubTree subtree;
619 DBusValue names;
620
621 auto method = _bus.new_method_call(service_name::objectMapper,
622 object_path::objectMapper,
623 interface::objectMapper, "GetSubTree");
624 method.append(std::string{"/"}, 0,
625 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600626 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500627
628 reply.read(subtree);
629 if (subtree.empty())
630 {
631 throw std::runtime_error("Compatible interface not on D-Bus");
632 }
633
634 const auto& object = *(subtree.begin());
635 const auto& path = object.first;
636 const auto& service = object.second.begin()->first;
637
638 getProperty(service, path, interface::compatible, "Names", names);
639
640 return std::get<std::vector<std::string>>(names);
641}
642
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500643bool DataInterface::getQuiesceOnError() const
644{
645 bool ret = false;
646
647 try
648 {
Patrick Williams2544b412022-10-04 08:41:06 -0500649 auto service = getService(object_path::logSetting,
650 interface::logSetting);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500651 if (!service.empty())
652 {
653 DBusValue value;
654 getProperty(service, object_path::logSetting, interface::logSetting,
655 "QuiesceOnHwError", value);
656
657 ret = std::get<bool>(value);
658 }
659 }
660 catch (const std::exception& e)
661 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500662 lg2::warning("Failed reading QuiesceOnHwError property from "
663 "interface: {IFACE} exception: {ERROR}",
664 "IFACE", interface::logSetting, "ERROR", e);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500665 }
666
667 return ret;
668}
669
Sumit Kumar9d43a722021-08-24 09:46:19 -0500670std::vector<bool>
671 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
672{
673 DBusSubTree subtree;
674 std::vector<bool> result(type.size(), false);
675
676 // Query GetSubTree for the availability of dump interface
677 auto method = _bus.new_method_call(service_name::objectMapper,
678 object_path::objectMapper,
679 interface::objectMapper, "GetSubTree");
680 method.append(std::string{"/"}, 0,
681 std::vector<std::string>{interface::dumpEntry});
Matt Spinler35a405b2022-03-02 11:42:42 -0600682 auto reply = _bus.call(method, dbusTimeout);
Sumit Kumar9d43a722021-08-24 09:46:19 -0500683
684 reply.read(subtree);
685
686 if (subtree.empty())
687 {
688 return result;
689 }
690
691 std::vector<bool>::iterator itDumpStatus = result.begin();
692 uint8_t count = 0;
693 for (const auto& [path, serviceInfo] : subtree)
694 {
695 const auto& service = serviceInfo.begin()->first;
696 // Check for dump type on the object path
697 for (const auto& it : type)
698 {
699 if (path.find(it) != std::string::npos)
700 {
701 DBusValue value, progress;
702
703 // If dump type status is already available go for next path
704 if (*itDumpStatus)
705 {
706 break;
707 }
708
709 // Check for valid dump to be available if following
710 // conditions are met for the dump entry path -
711 // Offloaded == false and Status == Completed
712 getProperty(service, path, interface::dumpEntry, "Offloaded",
713 value);
714 getProperty(service, path, interface::dumpProgress, "Status",
715 progress);
716 auto offload = std::get<bool>(value);
717 auto status = std::get<std::string>(progress);
718 if (!offload && (status.find("Completed") != std::string::npos))
719 {
720 *itDumpStatus = true;
721 count++;
722 if (count >= type.size())
723 {
724 return result;
725 }
726 break;
727 }
728 }
Matt Spinler45796e82022-07-01 11:25:27 -0500729 ++itDumpStatus;
Sumit Kumar9d43a722021-08-24 09:46:19 -0500730 }
731 itDumpStatus = result.begin();
732 }
733
734 return result;
735}
736
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500737void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
738 const std::string& type,
739 const std::string& logPath) const
740{
741 try
742 {
743 auto method = _bus.new_method_call(
744 service_name::hwIsolation, object_path::hwIsolation,
745 interface::hwIsolationCreate, "CreateWithEntityPath");
746 method.append(binPath, type, sdbusplus::message::object_path(logPath));
747 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
748 // api's. Making d-bus call no reply type to avoid cyclic dependency.
749 // Added minimal timeout to catch initial failures.
750 // Need to revisit this design later to avoid cyclic dependency.
Matt Spinler35a405b2022-03-02 11:42:42 -0600751 constexpr auto hwIsolationTimeout = 100000; // in micro seconds
752 _bus.call_noreply(method, hwIsolationTimeout);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500753 }
754
Patrick Williams45e83522022-07-22 19:26:52 -0500755 catch (const sdbusplus::exception_t& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500756 {
757 std::string errName = e.name();
758 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
759 // mentioned above. Ignoring the error.
760 if (errName != SD_BUS_ERROR_TIMEOUT)
761 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500762 lg2::error("GUARD D-Bus call exception. Path={PATH}, "
763 "interface = {IFACE}, exception = {ERROR}",
764 "PATH", object_path::hwIsolation, "IFACE",
765 interface::hwIsolationCreate, "ERROR", e);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500766 }
767 }
768}
Sumit Kumar3e274432021-09-14 06:37:56 -0500769
770void DataInterface::createProgressSRC(
771 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
772{
773 DBusValue variant = std::make_tuple(priSRC, srcStruct);
774
775 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500776 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500777 interface::dbusProperty, "Set");
778
779 method.append(interface::bootRawProgress, "Value", variant);
780
Matt Spinler35a405b2022-03-02 11:42:42 -0600781 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500782}
Sumit Kumar027bf282022-01-24 11:25:19 -0600783
784std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
785{
786 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
787 std::string hwErrorLog = "/isolated_hw_errorlog";
788 std::string errorLog = "/error_log";
789 DBusPathList paths;
790 std::vector<uint32_t> ids;
791
792 // Get all latest mapper associations
793 paths = getPaths(association);
794 for (auto& path : paths)
795 {
796 // Look for object path with hardware isolation entry if any
797 size_t pos = path.find(hwErrorLog);
798 if (pos != std::string::npos)
799 {
800 // Get the object path
801 std::string ph = path;
802 ph.erase(pos, hwErrorLog.length());
803 auto service = getService(ph, interface::hwIsolationEntry);
804 if (!service.empty())
805 {
806 bool status;
807 DBusValue value;
808
809 // Read the Resolved property from object path
810 getProperty(service, ph, interface::hwIsolationEntry,
811 "Resolved", value);
812
813 status = std::get<bool>(value);
814
815 // If the entry isn't resolved
816 if (!status)
817 {
Patrick Williams2544b412022-10-04 08:41:06 -0500818 auto assocService = getService(path,
819 interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500820 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600821 {
Matt Spinler45796e82022-07-01 11:25:27 -0500822 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600823
824 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500825 getProperty(assocService, path, interface::association,
826 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600827
828 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500829 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600830 if (!logPath.empty())
831 {
832 // Get OpenBMC event log Id
833 uint32_t id = stoi(logPath[0].substr(
834 logPath[0].find_last_of('/') + 1));
835 ids.push_back(id);
836 }
837 }
838 }
839 }
840 }
841
842 // Look for object path with error_log entry if any
843 pos = path.find(errorLog);
844 if (pos != std::string::npos)
845 {
846 auto service = getService(path, interface::association);
847 if (!service.empty())
848 {
849 DBusValue value;
850
851 // Read Endpoints property
852 getProperty(service, path, interface::association, "endpoints",
853 value);
854
855 auto logPath = std::get<std::vector<std::string>>(value);
856 if (!logPath.empty())
857 {
858 // Get OpenBMC event log Id
859 uint32_t id = stoi(
860 logPath[0].substr(logPath[0].find_last_of('/') + 1));
861 ids.push_back(id);
862 }
863 }
864 }
865 }
866
867 if (ids.size() > 1)
868 {
869 // remove duplicates to have only unique ids
870 std::sort(ids.begin(), ids.end());
871 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
872 }
873 return ids;
874}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500875
876std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
877{
878 using RawProgressProperty = std::tuple<uint64_t, std::vector<uint8_t>>;
879
880 DBusValue value;
881 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
882 interface::bootRawProgress, "Value", value);
883
884 const auto& rawProgress = std::get<RawProgressProperty>(value);
885 return std::get<1>(rawProgress);
886}
887
Matt Spinler5b423652023-05-04 13:08:44 -0500888void DataInterface::startFruPlugWatch()
889{
890 // Add a watch on inventory InterfacesAdded and then find all
891 // existing hotpluggable interfaces and add propertiesChanged
892 // watches on them.
893
894 _invIaMatch = std::make_unique<sdbusplus::bus::match_t>(
895 _bus, match_rules::interfacesAdded(object_path::baseInv),
896 std::bind(&DataInterface::inventoryIfaceAdded, this,
897 std::placeholders::_1));
898 try
899 {
900 auto paths = getPaths(hotplugInterfaces);
901
902 _invPresentMatches.clear();
903
904 std::for_each(paths.begin(), paths.end(),
905 [this](const auto& path) { addHotplugWatch(path); });
906 }
907 catch (const sdbusplus::exception_t& e)
908 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500909 lg2::warning("Failed getting FRU paths to watch: {ERROR}", "ERROR", e);
Matt Spinler5b423652023-05-04 13:08:44 -0500910 }
911}
912
913void DataInterface::addHotplugWatch(const std::string& path)
914{
915 if (!_invPresentMatches.contains(path))
916 {
917 _invPresentMatches.emplace(
918 path,
919 std::make_unique<sdbusplus::bus::match_t>(
920 _bus, match_rules::propertiesChanged(path, interface::invItem),
921 std::bind(&DataInterface::presenceChanged, this,
922 std::placeholders::_1)));
923 }
924}
925
926void DataInterface::inventoryIfaceAdded(sdbusplus::message_t& msg)
927{
928 sdbusplus::message::object_path path;
929 DBusInterfaceMap interfaces;
930
931 msg.read(path, interfaces);
932
933 // Check if any of the new interfaces are for hot pluggable FRUs.
934 if (std::find_if(interfaces.begin(), interfaces.end(),
935 [](const auto& interfacePair) {
936 return std::find(hotplugInterfaces.begin(), hotplugInterfaces.end(),
937 interfacePair.first) != hotplugInterfaces.end();
Patrick Williams5fb575a2023-10-20 11:18:21 -0500938 }) == interfaces.end())
Matt Spinler5b423652023-05-04 13:08:44 -0500939 {
940 return;
941 }
942
943 addHotplugWatch(path.str);
944
945 // If an Inventory.Item interface was also added, check presence now.
946
947 // Notes:
948 // * This assumes the Inv.Item and Inv.Fan/PS are added together which
949 // is currently the case.
950 // * If the code ever switches to something without a Present
951 // property, then the IA signal itself would probably indicate presence.
952
953 auto itemIt = interfaces.find(interface::invItem);
954 if (itemIt != interfaces.end())
955 {
956 notifyPresenceSubsribers(path.str, itemIt->second);
957 }
958}
959
960void DataInterface::presenceChanged(sdbusplus::message_t& msg)
961{
962 DBusInterface interface;
963 DBusPropertyMap properties;
964
965 msg.read(interface, properties);
966 if (interface != interface::invItem)
967 {
968 return;
969 }
970
971 std::string path = msg.get_path();
972 notifyPresenceSubsribers(path, properties);
973}
974
975void DataInterface::notifyPresenceSubsribers(const std::string& path,
976 const DBusPropertyMap& properties)
977{
Matt Spinler5ee36052023-05-30 14:20:56 -0500978 auto prop = properties.find("Present");
979 if ((prop == properties.end()) || (!std::get<bool>(prop->second)))
980 {
981 return;
982 }
983
984 std::string locCode;
985
Matt Spinler5b423652023-05-04 13:08:44 -0500986 try
987 {
Matt Spinler52ee3a42023-07-27 14:54:48 -0500988 auto service = getService(path, interface::locCode);
989
990 // If the hotplugged FRU is hosted by PLDM, then it is
991 // in an IO expansion drawer and we don't care about it.
992 if (service == service_name::pldm)
993 {
994 return;
995 }
996
Matt Spinler5ee36052023-05-30 14:20:56 -0500997 locCode = getLocationCode(path);
Matt Spinler5b423652023-05-04 13:08:44 -0500998 }
Matt Spinler5ee36052023-05-30 14:20:56 -0500999 catch (const sdbusplus::exception_t& e)
Matt Spinler5b423652023-05-04 13:08:44 -05001000 {
Matt Spinlera167a7d2023-06-30 15:14:25 -05001001 lg2::debug("Could not get location code for {PATH}: {ERROR}", "PATH",
1002 path, "ERROR", e);
Matt Spinler5ee36052023-05-30 14:20:56 -05001003 return;
Matt Spinler5b423652023-05-04 13:08:44 -05001004 }
Matt Spinler5ee36052023-05-30 14:20:56 -05001005
Matt Spinlera167a7d2023-06-30 15:14:25 -05001006 lg2::debug("Detected FRU {PATH} ({LOC}) present ", "PATH", path, "LOC",
1007 locCode);
Matt Spinler5ee36052023-05-30 14:20:56 -05001008
1009 // Tell the subscribers.
1010 setFruPresent(locCode);
Matt Spinler5b423652023-05-04 13:08:44 -05001011}
Matt Spinlerc8705e22019-09-11 12:36:07 -05001012} // namespace pels
1013} // namespace openpower