blob: 3d4a298a648b52c6d53b290fdfa1fccda2b32015 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlercad9c2b2019-12-02 15:42:01 -060016#include "config.h"
17
Matt Spinlerc8705e22019-09-11 12:36:07 -050018#include "data_interface.hpp"
19
Matt Spinlerf61f2922020-06-23 11:32:49 -050020#include "util.hpp"
21
Vijay Lobo81b4dca2021-04-29 00:04:00 -050022#include <fmt/format.h>
23
Matt Spinlera167a7d2023-06-30 15:14:25 -050024#include <phosphor-logging/lg2.hpp>
Matt Spinler5b423652023-05-04 13:08:44 -050025#include <xyz/openbmc_project/State/BMC/server.hpp>
Matt Spinlerf10068d2020-12-02 10:44:08 -060026#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Matt Spinlera7d9d962019-11-06 15:01:25 -060027
Patrick Williams2544b412022-10-04 08:41:06 -050028#include <fstream>
29#include <iterator>
30
Matt Spinler35a405b2022-03-02 11:42:42 -060031// Use a timeout of 10s for D-Bus calls so if there are
32// timeouts the callers of the PEL creation method won't
33// also timeout.
34constexpr auto dbusTimeout = 10000000;
35
Matt Spinlerc8705e22019-09-11 12:36:07 -050036namespace openpower
37{
38namespace pels
39{
40
41namespace service_name
42{
43constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050044constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050045constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050046constexpr auto logSetting = "xyz.openbmc_project.Settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050047constexpr auto hwIsolation = "org.open_power.HardwareIsolation";
Matt Spinler744d8512022-06-08 08:25:47 -050048constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050049constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler52ee3a42023-07-27 14:54:48 -050050constexpr auto pldm = "xyz.openbmc_project.PLDM";
Matt Spinlerc8705e22019-09-11 12:36:07 -050051} // namespace service_name
52
53namespace object_path
54{
55constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
56constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050057constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050058constexpr auto motherBoardInv =
59 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060060constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060061constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
62constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060063constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060064constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060065constexpr auto enableHostPELs =
66 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050067constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050068constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050069constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
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";
Matt Spinlerc8705e22019-09-11 12:36:07 -050072} // namespace object_path
73
74namespace interface
75{
76constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
77constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
78constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060079constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinlerb3f51862019-12-09 13:55:10 -060080constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
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 invMotherboard =
86 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
87constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050088constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060089constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050090constexpr auto compatible =
91 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050092constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050093constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050094constexpr auto operationalStatus =
95 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050096constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060097constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050098constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
99constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500100constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar027bf282022-01-24 11:25:19 -0600101constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
102constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -0500103constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -0500104constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler5b423652023-05-04 13:08:44 -0500105constexpr auto invItem = "xyz.openbmc_project.Inventory.Item";
106constexpr auto invFan = "xyz.openbmc_project.Inventory.Item.Fan";
107constexpr auto invPowerSupply =
108 "xyz.openbmc_project.Inventory.Item.PowerSupply";
Matt Spinlerc8705e22019-09-11 12:36:07 -0500109} // namespace interface
110
Matt Spinlerf10068d2020-12-02 10:44:08 -0600111using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
Matt Spinler5b423652023-05-04 13:08:44 -0500112using namespace sdbusplus::xyz::openbmc_project::State::server;
Matt Spinler5b423652023-05-04 13:08:44 -0500113namespace match_rules = sdbusplus::bus::match::rules;
114
115const DBusInterfaceList hotplugInterfaces{interface::invFan,
116 interface::invPowerSupply};
Matt Spinlera7d9d962019-11-06 15:01:25 -0600117
Matt Spinler0d92b522021-06-16 13:28:17 -0600118std::pair<std::string, std::string>
119 DataInterfaceBase::extractConnectorFromLocCode(
120 const std::string& locationCode)
121{
122 auto base = locationCode;
123 std::string connector{};
124
125 auto pos = base.find("-T");
126 if (pos != std::string::npos)
127 {
128 connector = base.substr(pos);
129 base = base.substr(0, pos);
130 }
131
132 return {base, connector};
133}
134
Patrick Williams45e83522022-07-22 19:26:52 -0500135DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus)
Matt Spinlerc8705e22019-09-11 12:36:07 -0500136{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600137 readBMCFWVersion();
138 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600139 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600140
Matt Spinlerf10068d2020-12-02 10:44:08 -0600141 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600142 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600143 bus, object_path::hostState, interface::bootProgress, "BootProgress",
144 *this, [this](const auto& value) {
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500145 this->_bootState = std::get<std::string>(value);
Matt Spinlerf10068d2020-12-02 10:44:08 -0600146 auto status = Progress::convertProgressStagesFromString(
147 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600148
Matt Spinlerf10068d2020-12-02 10:44:08 -0600149 if ((status == Progress::ProgressStages::SystemInitComplete) ||
Matt Spinlerf10068d2020-12-02 10:44:08 -0600150 (status == Progress::ProgressStages::OSRunning))
Matt Spinler2a28c932020-02-03 14:23:40 -0600151 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600152 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600153 }
154 else
155 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600156 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600157 }
158 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600159
160 // Watch the host PEL enable property
161 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
162 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
163 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500164 if (std::get<bool>(value) != this->_sendPELsToHost)
165 {
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);
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600170 }));
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) {
Matt Spinler5b423652023-05-04 13:08:44 -0500176 const auto& state = std::get<std::string>(value);
177 this->_bmcState = state;
178
179 // 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 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600185 }));
186
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 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600202 }));
203
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) {
208 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 }
Matt Spinler744d8512022-06-08 08:25:47 -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{
564 DBusValue variant = value;
565 auto service = getService(objectPath, interface::operationalStatus);
566
567 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
568 interface::dbusProperty, "Set");
569
570 method.append(interface::operationalStatus, "Functional", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600571 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500572}
573
Sumit Kumar76198a22021-07-15 05:59:57 -0500574using AssociationTuple = std::tuple<std::string, std::string, std::string>;
575using AssociationsProperty = std::vector<AssociationTuple>;
576
577void DataInterface::setCriticalAssociation(const std::string& objectPath) const
578{
579 DBusValue getAssociationValue;
580
Sumit Kumar027bf282022-01-24 11:25:19 -0600581 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500582
Sumit Kumar027bf282022-01-24 11:25:19 -0600583 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500584 getAssociationValue);
585
586 auto association = std::get<AssociationsProperty>(getAssociationValue);
587
588 AssociationTuple critAssociation{
589 "health_rollup", "critical",
590 "/xyz/openbmc_project/inventory/system/chassis"};
591
592 if (std::find(association.begin(), association.end(), critAssociation) ==
593 association.end())
594 {
595 association.push_back(critAssociation);
596 DBusValue setAssociationValue = association;
597
598 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
599 interface::dbusProperty, "Set");
600
Sumit Kumar027bf282022-01-24 11:25:19 -0600601 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500602 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600603 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500604 }
605}
606
Matt Spinler1ab66962020-10-29 13:21:44 -0500607std::vector<std::string> DataInterface::getSystemNames() const
608{
609 DBusSubTree subtree;
610 DBusValue names;
611
612 auto method = _bus.new_method_call(service_name::objectMapper,
613 object_path::objectMapper,
614 interface::objectMapper, "GetSubTree");
615 method.append(std::string{"/"}, 0,
616 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600617 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500618
619 reply.read(subtree);
620 if (subtree.empty())
621 {
622 throw std::runtime_error("Compatible interface not on D-Bus");
623 }
624
625 const auto& object = *(subtree.begin());
626 const auto& path = object.first;
627 const auto& service = object.second.begin()->first;
628
629 getProperty(service, path, interface::compatible, "Names", names);
630
631 return std::get<std::vector<std::string>>(names);
632}
633
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500634bool DataInterface::getQuiesceOnError() const
635{
636 bool ret = false;
637
638 try
639 {
Patrick Williams2544b412022-10-04 08:41:06 -0500640 auto service = getService(object_path::logSetting,
641 interface::logSetting);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500642 if (!service.empty())
643 {
644 DBusValue value;
645 getProperty(service, object_path::logSetting, interface::logSetting,
646 "QuiesceOnHwError", value);
647
648 ret = std::get<bool>(value);
649 }
650 }
651 catch (const std::exception& e)
652 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500653 lg2::warning("Failed reading QuiesceOnHwError property from "
654 "interface: {IFACE} exception: {ERROR}",
655 "IFACE", interface::logSetting, "ERROR", e);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500656 }
657
658 return ret;
659}
660
Sumit Kumar9d43a722021-08-24 09:46:19 -0500661std::vector<bool>
662 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
663{
664 DBusSubTree subtree;
665 std::vector<bool> result(type.size(), false);
666
667 // Query GetSubTree for the availability of dump interface
668 auto method = _bus.new_method_call(service_name::objectMapper,
669 object_path::objectMapper,
670 interface::objectMapper, "GetSubTree");
671 method.append(std::string{"/"}, 0,
672 std::vector<std::string>{interface::dumpEntry});
Matt Spinler35a405b2022-03-02 11:42:42 -0600673 auto reply = _bus.call(method, dbusTimeout);
Sumit Kumar9d43a722021-08-24 09:46:19 -0500674
675 reply.read(subtree);
676
677 if (subtree.empty())
678 {
679 return result;
680 }
681
682 std::vector<bool>::iterator itDumpStatus = result.begin();
683 uint8_t count = 0;
684 for (const auto& [path, serviceInfo] : subtree)
685 {
686 const auto& service = serviceInfo.begin()->first;
687 // Check for dump type on the object path
688 for (const auto& it : type)
689 {
690 if (path.find(it) != std::string::npos)
691 {
692 DBusValue value, progress;
693
694 // If dump type status is already available go for next path
695 if (*itDumpStatus)
696 {
697 break;
698 }
699
700 // Check for valid dump to be available if following
701 // conditions are met for the dump entry path -
702 // Offloaded == false and Status == Completed
703 getProperty(service, path, interface::dumpEntry, "Offloaded",
704 value);
705 getProperty(service, path, interface::dumpProgress, "Status",
706 progress);
707 auto offload = std::get<bool>(value);
708 auto status = std::get<std::string>(progress);
709 if (!offload && (status.find("Completed") != std::string::npos))
710 {
711 *itDumpStatus = true;
712 count++;
713 if (count >= type.size())
714 {
715 return result;
716 }
717 break;
718 }
719 }
Matt Spinler45796e82022-07-01 11:25:27 -0500720 ++itDumpStatus;
Sumit Kumar9d43a722021-08-24 09:46:19 -0500721 }
722 itDumpStatus = result.begin();
723 }
724
725 return result;
726}
727
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500728void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
729 const std::string& type,
730 const std::string& logPath) const
731{
732 try
733 {
734 auto method = _bus.new_method_call(
735 service_name::hwIsolation, object_path::hwIsolation,
736 interface::hwIsolationCreate, "CreateWithEntityPath");
737 method.append(binPath, type, sdbusplus::message::object_path(logPath));
738 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
739 // api's. Making d-bus call no reply type to avoid cyclic dependency.
740 // Added minimal timeout to catch initial failures.
741 // Need to revisit this design later to avoid cyclic dependency.
Matt Spinler35a405b2022-03-02 11:42:42 -0600742 constexpr auto hwIsolationTimeout = 100000; // in micro seconds
743 _bus.call_noreply(method, hwIsolationTimeout);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500744 }
745
Patrick Williams45e83522022-07-22 19:26:52 -0500746 catch (const sdbusplus::exception_t& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500747 {
748 std::string errName = e.name();
749 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
750 // mentioned above. Ignoring the error.
751 if (errName != SD_BUS_ERROR_TIMEOUT)
752 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500753 lg2::error("GUARD D-Bus call exception. Path={PATH}, "
754 "interface = {IFACE}, exception = {ERROR}",
755 "PATH", object_path::hwIsolation, "IFACE",
756 interface::hwIsolationCreate, "ERROR", e);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500757 }
758 }
759}
Sumit Kumar3e274432021-09-14 06:37:56 -0500760
761void DataInterface::createProgressSRC(
762 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
763{
764 DBusValue variant = std::make_tuple(priSRC, srcStruct);
765
766 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500767 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500768 interface::dbusProperty, "Set");
769
770 method.append(interface::bootRawProgress, "Value", variant);
771
Matt Spinler35a405b2022-03-02 11:42:42 -0600772 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500773}
Sumit Kumar027bf282022-01-24 11:25:19 -0600774
775std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
776{
777 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
778 std::string hwErrorLog = "/isolated_hw_errorlog";
779 std::string errorLog = "/error_log";
780 DBusPathList paths;
781 std::vector<uint32_t> ids;
782
783 // Get all latest mapper associations
784 paths = getPaths(association);
785 for (auto& path : paths)
786 {
787 // Look for object path with hardware isolation entry if any
788 size_t pos = path.find(hwErrorLog);
789 if (pos != std::string::npos)
790 {
791 // Get the object path
792 std::string ph = path;
793 ph.erase(pos, hwErrorLog.length());
794 auto service = getService(ph, interface::hwIsolationEntry);
795 if (!service.empty())
796 {
797 bool status;
798 DBusValue value;
799
800 // Read the Resolved property from object path
801 getProperty(service, ph, interface::hwIsolationEntry,
802 "Resolved", value);
803
804 status = std::get<bool>(value);
805
806 // If the entry isn't resolved
807 if (!status)
808 {
Patrick Williams2544b412022-10-04 08:41:06 -0500809 auto assocService = getService(path,
810 interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500811 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600812 {
Matt Spinler45796e82022-07-01 11:25:27 -0500813 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600814
815 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500816 getProperty(assocService, path, interface::association,
817 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600818
819 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500820 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600821 if (!logPath.empty())
822 {
823 // Get OpenBMC event log Id
824 uint32_t id = stoi(logPath[0].substr(
825 logPath[0].find_last_of('/') + 1));
826 ids.push_back(id);
827 }
828 }
829 }
830 }
831 }
832
833 // Look for object path with error_log entry if any
834 pos = path.find(errorLog);
835 if (pos != std::string::npos)
836 {
837 auto service = getService(path, interface::association);
838 if (!service.empty())
839 {
840 DBusValue value;
841
842 // Read Endpoints property
843 getProperty(service, path, interface::association, "endpoints",
844 value);
845
846 auto logPath = std::get<std::vector<std::string>>(value);
847 if (!logPath.empty())
848 {
849 // Get OpenBMC event log Id
850 uint32_t id = stoi(
851 logPath[0].substr(logPath[0].find_last_of('/') + 1));
852 ids.push_back(id);
853 }
854 }
855 }
856 }
857
858 if (ids.size() > 1)
859 {
860 // remove duplicates to have only unique ids
861 std::sort(ids.begin(), ids.end());
862 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
863 }
864 return ids;
865}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500866
867std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
868{
869 using RawProgressProperty = std::tuple<uint64_t, std::vector<uint8_t>>;
870
871 DBusValue value;
872 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
873 interface::bootRawProgress, "Value", value);
874
875 const auto& rawProgress = std::get<RawProgressProperty>(value);
876 return std::get<1>(rawProgress);
877}
878
Matt Spinler5b423652023-05-04 13:08:44 -0500879void DataInterface::startFruPlugWatch()
880{
881 // Add a watch on inventory InterfacesAdded and then find all
882 // existing hotpluggable interfaces and add propertiesChanged
883 // watches on them.
884
885 _invIaMatch = std::make_unique<sdbusplus::bus::match_t>(
886 _bus, match_rules::interfacesAdded(object_path::baseInv),
887 std::bind(&DataInterface::inventoryIfaceAdded, this,
888 std::placeholders::_1));
889 try
890 {
891 auto paths = getPaths(hotplugInterfaces);
892
893 _invPresentMatches.clear();
894
895 std::for_each(paths.begin(), paths.end(),
896 [this](const auto& path) { addHotplugWatch(path); });
897 }
898 catch (const sdbusplus::exception_t& e)
899 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500900 lg2::warning("Failed getting FRU paths to watch: {ERROR}", "ERROR", e);
Matt Spinler5b423652023-05-04 13:08:44 -0500901 }
902}
903
904void DataInterface::addHotplugWatch(const std::string& path)
905{
906 if (!_invPresentMatches.contains(path))
907 {
908 _invPresentMatches.emplace(
909 path,
910 std::make_unique<sdbusplus::bus::match_t>(
911 _bus, match_rules::propertiesChanged(path, interface::invItem),
912 std::bind(&DataInterface::presenceChanged, this,
913 std::placeholders::_1)));
914 }
915}
916
917void DataInterface::inventoryIfaceAdded(sdbusplus::message_t& msg)
918{
919 sdbusplus::message::object_path path;
920 DBusInterfaceMap interfaces;
921
922 msg.read(path, interfaces);
923
924 // Check if any of the new interfaces are for hot pluggable FRUs.
925 if (std::find_if(interfaces.begin(), interfaces.end(),
926 [](const auto& interfacePair) {
927 return std::find(hotplugInterfaces.begin(), hotplugInterfaces.end(),
928 interfacePair.first) != hotplugInterfaces.end();
929 }) == interfaces.end())
930 {
931 return;
932 }
933
934 addHotplugWatch(path.str);
935
936 // If an Inventory.Item interface was also added, check presence now.
937
938 // Notes:
939 // * This assumes the Inv.Item and Inv.Fan/PS are added together which
940 // is currently the case.
941 // * If the code ever switches to something without a Present
942 // property, then the IA signal itself would probably indicate presence.
943
944 auto itemIt = interfaces.find(interface::invItem);
945 if (itemIt != interfaces.end())
946 {
947 notifyPresenceSubsribers(path.str, itemIt->second);
948 }
949}
950
951void DataInterface::presenceChanged(sdbusplus::message_t& msg)
952{
953 DBusInterface interface;
954 DBusPropertyMap properties;
955
956 msg.read(interface, properties);
957 if (interface != interface::invItem)
958 {
959 return;
960 }
961
962 std::string path = msg.get_path();
963 notifyPresenceSubsribers(path, properties);
964}
965
966void DataInterface::notifyPresenceSubsribers(const std::string& path,
967 const DBusPropertyMap& properties)
968{
Matt Spinler5ee36052023-05-30 14:20:56 -0500969 auto prop = properties.find("Present");
970 if ((prop == properties.end()) || (!std::get<bool>(prop->second)))
971 {
972 return;
973 }
974
975 std::string locCode;
976
Matt Spinler5b423652023-05-04 13:08:44 -0500977 try
978 {
Matt Spinler52ee3a42023-07-27 14:54:48 -0500979 auto service = getService(path, interface::locCode);
980
981 // If the hotplugged FRU is hosted by PLDM, then it is
982 // in an IO expansion drawer and we don't care about it.
983 if (service == service_name::pldm)
984 {
985 return;
986 }
987
Matt Spinler5ee36052023-05-30 14:20:56 -0500988 locCode = getLocationCode(path);
Matt Spinler5b423652023-05-04 13:08:44 -0500989 }
Matt Spinler5ee36052023-05-30 14:20:56 -0500990 catch (const sdbusplus::exception_t& e)
Matt Spinler5b423652023-05-04 13:08:44 -0500991 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500992 lg2::debug("Could not get location code for {PATH}: {ERROR}", "PATH",
993 path, "ERROR", e);
Matt Spinler5ee36052023-05-30 14:20:56 -0500994 return;
Matt Spinler5b423652023-05-04 13:08:44 -0500995 }
Matt Spinler5ee36052023-05-30 14:20:56 -0500996
Matt Spinlera167a7d2023-06-30 15:14:25 -0500997 lg2::debug("Detected FRU {PATH} ({LOC}) present ", "PATH", path, "LOC",
998 locCode);
Matt Spinler5ee36052023-05-30 14:20:56 -0500999
1000 // Tell the subscribers.
1001 setFruPresent(locCode);
Matt Spinler5b423652023-05-04 13:08:44 -05001002}
Matt Spinlerc8705e22019-09-11 12:36:07 -05001003} // namespace pels
1004} // namespace openpower