blob: eaedcff9b5819f3573a2efd9e4f3a58f68fac253 [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 Spinlerc8705e22019-09-11 12:36:07 -050049} // namespace service_name
50
51namespace object_path
52{
53constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
54constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050055constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050056constexpr auto motherBoardInv =
57 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060058constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060059constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
60constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060061constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060062constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060063constexpr auto enableHostPELs =
64 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050065constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050066constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050067constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Matt Spinler744d8512022-06-08 08:25:47 -050068constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050069constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0";
Matt Spinlerc8705e22019-09-11 12:36:07 -050070} // namespace object_path
71
72namespace interface
73{
74constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
75constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
76constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060077constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinlerb3f51862019-12-09 13:55:10 -060078constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060079constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060080constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
81constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
82constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060083constexpr auto invMotherboard =
84 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
85constexpr 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 =
89 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
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 Kumar9d43a722021-08-24 09:46:19 -050096constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
97constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050098constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar027bf282022-01-24 11:25:19 -060099constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
100constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -0500101constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -0500102constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler5b423652023-05-04 13:08:44 -0500103constexpr auto invItem = "xyz.openbmc_project.Inventory.Item";
104constexpr auto invFan = "xyz.openbmc_project.Inventory.Item.Fan";
105constexpr auto invPowerSupply =
106 "xyz.openbmc_project.Inventory.Item.PowerSupply";
Matt Spinlerc8705e22019-09-11 12:36:07 -0500107} // namespace interface
108
Matt Spinlerf10068d2020-12-02 10:44:08 -0600109using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
Matt Spinler5b423652023-05-04 13:08:44 -0500110using namespace sdbusplus::xyz::openbmc_project::State::server;
Matt Spinler5b423652023-05-04 13:08:44 -0500111namespace match_rules = sdbusplus::bus::match::rules;
112
113const DBusInterfaceList hotplugInterfaces{interface::invFan,
114 interface::invPowerSupply};
Matt Spinlera7d9d962019-11-06 15:01:25 -0600115
Matt Spinler0d92b522021-06-16 13:28:17 -0600116std::pair<std::string, std::string>
117 DataInterfaceBase::extractConnectorFromLocCode(
118 const std::string& locationCode)
119{
120 auto base = locationCode;
121 std::string connector{};
122
123 auto pos = base.find("-T");
124 if (pos != std::string::npos)
125 {
126 connector = base.substr(pos);
127 base = base.substr(0, pos);
128 }
129
130 return {base, connector};
131}
132
Patrick Williams45e83522022-07-22 19:26:52 -0500133DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus)
Matt Spinlerc8705e22019-09-11 12:36:07 -0500134{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600135 readBMCFWVersion();
136 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600137 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600138
Matt Spinlerf10068d2020-12-02 10:44:08 -0600139 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600140 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600141 bus, object_path::hostState, interface::bootProgress, "BootProgress",
142 *this, [this](const auto& value) {
Patrick Williams5fb575a2023-10-20 11:18:21 -0500143 this->_bootState = std::get<std::string>(value);
144 auto status = Progress::convertProgressStagesFromString(
145 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600146
Patrick Williams5fb575a2023-10-20 11:18:21 -0500147 if ((status == Progress::ProgressStages::SystemInitComplete) ||
148 (status == Progress::ProgressStages::OSRunning))
149 {
150 setHostUp(true);
151 }
152 else
153 {
154 setHostUp(false);
155 }
156 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600157
158 // Watch the host PEL enable property
159 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
160 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
161 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500162 if (std::get<bool>(value) != this->_sendPELsToHost)
163 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500164 lg2::info("The send PELs to host setting changed to {VAL}", "VAL",
165 std::get<bool>(value));
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500166 }
167 this->_sendPELsToHost = std::get<bool>(value);
Patrick Williams5fb575a2023-10-20 11:18:21 -0500168 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600169
170 // Watch the BMCState property
171 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
172 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
173 *this, [this](const auto& value) {
Patrick Williams5fb575a2023-10-20 11:18:21 -0500174 const auto& state = std::get<std::string>(value);
175 this->_bmcState = state;
Matt Spinler5b423652023-05-04 13:08:44 -0500176
Patrick Williams5fb575a2023-10-20 11:18:21 -0500177 // Wait for BMC ready to start watching for
178 // plugs so things calm down first.
179 if (BMC::convertBMCStateFromString(state) == BMC::BMCState::Ready)
180 {
181 startFruPlugWatch();
182 }
183 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600184
185 // Watch the chassis current and requested power state properties
186 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
187 bus, object_path::chassisState, interface::chassisState, *this,
188 [this](const auto& properties) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500189 auto state = properties.find("CurrentPowerState");
190 if (state != properties.end())
191 {
192 this->_chassisState = std::get<std::string>(state->second);
193 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600194
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500195 auto trans = properties.find("RequestedPowerTransition");
196 if (trans != properties.end())
197 {
198 this->_chassisTransition = std::get<std::string>(trans->second);
199 }
Patrick Williams5fb575a2023-10-20 11:18:21 -0500200 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600201
202 // Watch the CurrentHostState property
203 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
204 bus, object_path::hostState, interface::hostState, "CurrentHostState",
205 *this, [this](const auto& value) {
Patrick Williams5fb575a2023-10-20 11:18:21 -0500206 this->_hostState = std::get<std::string>(value);
207 }));
Matt Spinler744d8512022-06-08 08:25:47 -0500208
209 // Watch the BaseBIOSTable property for the hmc managed attribute
210 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
211 bus, object_path::biosConfigMgr, interface::biosConfigMgr,
212 "BaseBIOSTable", service_name::biosConfigMgr, *this,
213 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500214 const auto& attributes = std::get<BiosAttributes>(value);
Matt Spinler744d8512022-06-08 08:25:47 -0500215
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500216 auto it = attributes.find("pvm_hmc_managed");
217 if (it != attributes.end())
218 {
219 const auto& currentValVariant = std::get<5>(it->second);
220 auto currentVal = std::get_if<std::string>(&currentValVariant);
221 if (currentVal)
Matt Spinler744d8512022-06-08 08:25:47 -0500222 {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500223 this->_hmcManaged = (*currentVal == "Enabled") ? true : false;
Matt Spinler744d8512022-06-08 08:25:47 -0500224 }
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500225 }
Patrick Williams5fb575a2023-10-20 11:18:21 -0500226 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500227}
228
Matt Spinler2a28c932020-02-03 14:23:40 -0600229DBusPropertyMap
230 DataInterface::getAllProperties(const std::string& service,
231 const std::string& objectPath,
232 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500233{
234 DBusPropertyMap properties;
235
236 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
237 interface::dbusProperty, "GetAll");
238 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600239 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500240
241 reply.read(properties);
242
243 return properties;
244}
245
Matt Spinlera7d9d962019-11-06 15:01:25 -0600246void DataInterface::getProperty(const std::string& service,
247 const std::string& objectPath,
248 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600249 const std::string& property,
250 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600251{
Matt Spinlera7d9d962019-11-06 15:01:25 -0600252 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
253 interface::dbusProperty, "Get");
254 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600255 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600256
257 reply.read(value);
258}
259
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600260DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
261{
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600262 auto method = _bus.new_method_call(
263 service_name::objectMapper, object_path::objectMapper,
264 interface::objectMapper, "GetSubTreePaths");
265
266 method.append(std::string{"/"}, 0, interfaces);
267
Matt Spinler35a405b2022-03-02 11:42:42 -0600268 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600269
270 DBusPathList paths;
271 reply.read(paths);
272
273 return paths;
274}
275
Matt Spinlerc8705e22019-09-11 12:36:07 -0500276DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600277 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500278{
279 auto method = _bus.new_method_call(service_name::objectMapper,
280 object_path::objectMapper,
281 interface::objectMapper, "GetObject");
282
283 method.append(objectPath, std::vector<std::string>({interface}));
284
Matt Spinler35a405b2022-03-02 11:42:42 -0600285 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500286
287 std::map<DBusService, DBusInterfaceList> response;
288 reply.read(response);
289
290 if (!response.empty())
291 {
292 return response.begin()->first;
293 }
294
295 return std::string{};
296}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600297
Matt Spinler677381b2020-01-23 10:04:29 -0600298void DataInterface::readBMCFWVersion()
299{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500300 _bmcFWVersion =
301 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600302}
303
304void DataInterface::readServerFWVersion()
305{
Sumit Kumarcad16202021-05-13 04:06:15 -0500306 auto value =
307 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
308 if ((value != "") && (value.find_last_of(')') != std::string::npos))
309 {
310 std::size_t pos = value.find_first_of('(') + 1;
311 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
312 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600313}
314
Matt Spinler677381b2020-01-23 10:04:29 -0600315void DataInterface::readBMCFWVersionID()
316{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500317 _bmcFWVersionID =
318 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600319}
320
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500321std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600322{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500323 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600324 try
325 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500326 auto service = getService(object_path::systemInv, interface::invAsset);
327 if (!service.empty())
328 {
329 DBusValue value;
330 getProperty(service, object_path::systemInv, interface::invAsset,
331 "Model", value);
332
333 model = std::get<std::string>(value);
334 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600335 }
336 catch (const std::exception& e)
337 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500338 lg2::warning("Failed reading Model property from "
339 "interface: {IFACE} exception: {ERROR}",
340 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600341 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500342
343 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600344}
345
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500346std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600347{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500348 std::string sn;
349 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600350 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500351 auto service = getService(object_path::systemInv, interface::invAsset);
352 if (!service.empty())
353 {
354 DBusValue value;
355 getProperty(service, object_path::systemInv, interface::invAsset,
356 "SerialNumber", value);
357
358 sn = std::get<std::string>(value);
359 }
360 }
361 catch (const std::exception& e)
362 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500363 lg2::warning("Failed reading SerialNumber property from "
364 "interface: {IFACE} exception: {ERROR}",
365 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600366 }
367
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500368 return sn;
369}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600370
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500371std::string DataInterface::getMotherboardCCIN() const
372{
373 std::string ccin;
374
375 try
376 {
Patrick Williams2544b412022-10-04 08:41:06 -0500377 auto service = getService(object_path::motherBoardInv,
378 interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500379 if (!service.empty())
380 {
381 DBusValue value;
382 getProperty(service, object_path::motherBoardInv,
383 interface::viniRecordVPD, "CC", value);
384
385 auto cc = std::get<std::vector<uint8_t>>(value);
386 ccin = std::string{cc.begin(), cc.end()};
387 }
388 }
389 catch (const std::exception& e)
390 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500391 lg2::warning("Failed reading Motherboard CCIN property from "
392 "interface: {IFACE} exception: {ERROR}",
393 "IFACE", interface::viniRecordVPD, "ERROR", e);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500394 }
395
396 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600397}
398
Ben Tynere32b7e72021-05-18 12:38:40 -0500399std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
400{
401 std::vector<uint8_t> systemIM;
402
403 try
404 {
Patrick Williams2544b412022-10-04 08:41:06 -0500405 auto service = getService(object_path::motherBoardInv,
406 interface::vsbpRecordVPD);
Ben Tynere32b7e72021-05-18 12:38:40 -0500407 if (!service.empty())
408 {
409 DBusValue value;
410 getProperty(service, object_path::motherBoardInv,
411 interface::vsbpRecordVPD, "IM", value);
412
413 systemIM = std::get<std::vector<uint8_t>>(value);
414 }
415 }
416 catch (const std::exception& e)
417 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500418 lg2::warning("Failed reading System IM property from "
419 "interface: {IFACE} exception: {ERROR}",
420 "IFACE", interface::vsbpRecordVPD, "ERROR", e);
Ben Tynere32b7e72021-05-18 12:38:40 -0500421 }
422
423 return systemIM;
424}
425
Matt Spinler60c4e792020-03-13 13:45:36 -0500426void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500427 std::string& fruPartNumber,
428 std::string& ccin,
429 std::string& serialNumber) const
430{
431 // For now, attempt to get all of the properties directly on the path
432 // passed in. In the future, may need to make use of an algorithm
433 // to figure out which inventory objects actually hold these
434 // interfaces in the case of non FRUs, or possibly another service
435 // will provide this info. Any missing interfaces will result
436 // in exceptions being thrown.
437
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500438 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500439
Patrick Williams2544b412022-10-04 08:41:06 -0500440 auto properties = getAllProperties(service, inventoryPath,
441 interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500442
443 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
444 fruPartNumber = std::string{value.begin(), value.end()};
445
446 value = std::get<std::vector<uint8_t>>(properties["CC"]);
447 ccin = std::string{value.begin(), value.end()};
448
449 value = std::get<std::vector<uint8_t>>(properties["SN"]);
450 serialNumber = std::string{value.begin(), value.end()};
451}
452
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500453std::string
454 DataInterface::getLocationCode(const std::string& inventoryPath) const
455{
456 auto service = getService(inventoryPath, interface::locCode);
457
458 DBusValue locCode;
459 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
460 locCode);
461
462 return std::get<std::string>(locCode);
463}
464
Matt Spinler5fb24c12020-06-04 11:21:33 -0500465std::string
466 DataInterface::addLocationCodePrefix(const std::string& locationCode)
467{
468 static const std::string locationCodePrefix{"Ufcs-"};
469
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500470 // Technically there are 2 location code prefixes, Ufcs and Umts, so
471 // if it already starts with a U then don't need to do anything.
472 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500473 {
474 return locationCodePrefix + locationCode;
475 }
476
477 return locationCode;
478}
479
480std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500481 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500482{
Matt Spinler0d92b522021-06-16 13:28:17 -0600483 // Location codes for connectors are the location code of the FRU they are
484 // on, plus a '-Tx' segment. Remove this last segment before expanding it
485 // and then add it back in afterwards. This way, the connector doesn't have
486 // to be in the model just so that it can be expanded.
487 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
488
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500489 auto method =
490 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
491 interface::vpdManager, "GetExpandedLocationCode");
492
Matt Spinler0d92b522021-06-16 13:28:17 -0600493 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500494
Matt Spinler35a405b2022-03-02 11:42:42 -0600495 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500496
497 std::string expandedLocationCode;
498 reply.read(expandedLocationCode);
499
Matt Spinler0d92b522021-06-16 13:28:17 -0600500 if (!connectorLoc.empty())
501 {
502 expandedLocationCode += connectorLoc;
503 }
504
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500505 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500506}
507
Matt Spinlerbad056b2023-01-25 14:16:57 -0600508std::vector<std::string>
Matt Spinler2f9225a2020-08-05 12:58:49 -0500509 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
510 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500511{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500512 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
513 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500514
Matt Spinler0d92b522021-06-16 13:28:17 -0600515 // Remove the connector segment, if present, so that this method call
516 // returns an inventory path that getHWCalloutFields() can be used with.
517 // (The serial number, etc, aren't stored on the connector in the
518 // inventory, and may not even be modeled.)
519 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
520
Matt Spinler2f9225a2020-08-05 12:58:49 -0500521 auto method =
522 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
523 interface::vpdManager, methodName.c_str());
524
525 if (expanded)
526 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600527 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500528 }
529 else
530 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600531 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500532 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500533
Matt Spinler35a405b2022-03-02 11:42:42 -0600534 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500535
536 std::vector<sdbusplus::message::object_path> entries;
537 reply.read(entries);
538
Matt Spinlerbad056b2023-01-25 14:16:57 -0600539 std::vector<std::string> paths;
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500540
Matt Spinlerbad056b2023-01-25 14:16:57 -0600541 // Note: The D-Bus method will fail if nothing found.
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500542 std::for_each(entries.begin(), entries.end(),
Matt Spinlerbad056b2023-01-25 14:16:57 -0600543 [&paths](const auto& path) { paths.push_back(path); });
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500544
Matt Spinlerbad056b2023-01-25 14:16:57 -0600545 return paths;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500546}
547
Matt Spinler34a904c2020-08-05 14:53:28 -0500548void DataInterface::assertLEDGroup(const std::string& ledGroup,
549 bool value) const
550{
551 DBusValue variant = value;
Patrick Williams2544b412022-10-04 08:41:06 -0500552 auto method = _bus.new_method_call(service_name::ledGroupManager,
553 ledGroup.c_str(),
554 interface::dbusProperty, "Set");
Matt Spinler34a904c2020-08-05 14:53:28 -0500555 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600556 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500557}
558
Matt Spinler993168d2021-04-07 16:05:03 -0500559void DataInterface::setFunctional(const std::string& objectPath,
560 bool value) const
561{
562 DBusValue variant = value;
563 auto service = getService(objectPath, interface::operationalStatus);
564
565 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
566 interface::dbusProperty, "Set");
567
568 method.append(interface::operationalStatus, "Functional", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600569 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500570}
571
Sumit Kumar76198a22021-07-15 05:59:57 -0500572using AssociationTuple = std::tuple<std::string, std::string, std::string>;
573using AssociationsProperty = std::vector<AssociationTuple>;
574
575void DataInterface::setCriticalAssociation(const std::string& objectPath) const
576{
577 DBusValue getAssociationValue;
578
Sumit Kumar027bf282022-01-24 11:25:19 -0600579 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500580
Sumit Kumar027bf282022-01-24 11:25:19 -0600581 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500582 getAssociationValue);
583
584 auto association = std::get<AssociationsProperty>(getAssociationValue);
585
586 AssociationTuple critAssociation{
587 "health_rollup", "critical",
588 "/xyz/openbmc_project/inventory/system/chassis"};
589
590 if (std::find(association.begin(), association.end(), critAssociation) ==
591 association.end())
592 {
593 association.push_back(critAssociation);
594 DBusValue setAssociationValue = association;
595
596 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
597 interface::dbusProperty, "Set");
598
Sumit Kumar027bf282022-01-24 11:25:19 -0600599 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500600 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600601 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500602 }
603}
604
Matt Spinler1ab66962020-10-29 13:21:44 -0500605std::vector<std::string> DataInterface::getSystemNames() const
606{
607 DBusSubTree subtree;
608 DBusValue names;
609
610 auto method = _bus.new_method_call(service_name::objectMapper,
611 object_path::objectMapper,
612 interface::objectMapper, "GetSubTree");
613 method.append(std::string{"/"}, 0,
614 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600615 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500616
617 reply.read(subtree);
618 if (subtree.empty())
619 {
620 throw std::runtime_error("Compatible interface not on D-Bus");
621 }
622
623 const auto& object = *(subtree.begin());
624 const auto& path = object.first;
625 const auto& service = object.second.begin()->first;
626
627 getProperty(service, path, interface::compatible, "Names", names);
628
629 return std::get<std::vector<std::string>>(names);
630}
631
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500632bool DataInterface::getQuiesceOnError() const
633{
634 bool ret = false;
635
636 try
637 {
Patrick Williams2544b412022-10-04 08:41:06 -0500638 auto service = getService(object_path::logSetting,
639 interface::logSetting);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500640 if (!service.empty())
641 {
642 DBusValue value;
643 getProperty(service, object_path::logSetting, interface::logSetting,
644 "QuiesceOnHwError", value);
645
646 ret = std::get<bool>(value);
647 }
648 }
649 catch (const std::exception& e)
650 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500651 lg2::warning("Failed reading QuiesceOnHwError property from "
652 "interface: {IFACE} exception: {ERROR}",
653 "IFACE", interface::logSetting, "ERROR", e);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500654 }
655
656 return ret;
657}
658
Sumit Kumar9d43a722021-08-24 09:46:19 -0500659std::vector<bool>
660 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
661{
662 DBusSubTree subtree;
663 std::vector<bool> result(type.size(), false);
664
665 // Query GetSubTree for the availability of dump interface
666 auto method = _bus.new_method_call(service_name::objectMapper,
667 object_path::objectMapper,
668 interface::objectMapper, "GetSubTree");
669 method.append(std::string{"/"}, 0,
670 std::vector<std::string>{interface::dumpEntry});
Matt Spinler35a405b2022-03-02 11:42:42 -0600671 auto reply = _bus.call(method, dbusTimeout);
Sumit Kumar9d43a722021-08-24 09:46:19 -0500672
673 reply.read(subtree);
674
675 if (subtree.empty())
676 {
677 return result;
678 }
679
680 std::vector<bool>::iterator itDumpStatus = result.begin();
681 uint8_t count = 0;
682 for (const auto& [path, serviceInfo] : subtree)
683 {
684 const auto& service = serviceInfo.begin()->first;
685 // Check for dump type on the object path
686 for (const auto& it : type)
687 {
688 if (path.find(it) != std::string::npos)
689 {
690 DBusValue value, progress;
691
692 // If dump type status is already available go for next path
693 if (*itDumpStatus)
694 {
695 break;
696 }
697
698 // Check for valid dump to be available if following
699 // conditions are met for the dump entry path -
700 // Offloaded == false and Status == Completed
701 getProperty(service, path, interface::dumpEntry, "Offloaded",
702 value);
703 getProperty(service, path, interface::dumpProgress, "Status",
704 progress);
705 auto offload = std::get<bool>(value);
706 auto status = std::get<std::string>(progress);
707 if (!offload && (status.find("Completed") != std::string::npos))
708 {
709 *itDumpStatus = true;
710 count++;
711 if (count >= type.size())
712 {
713 return result;
714 }
715 break;
716 }
717 }
Matt Spinler45796e82022-07-01 11:25:27 -0500718 ++itDumpStatus;
Sumit Kumar9d43a722021-08-24 09:46:19 -0500719 }
720 itDumpStatus = result.begin();
721 }
722
723 return result;
724}
725
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500726void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
727 const std::string& type,
728 const std::string& logPath) const
729{
730 try
731 {
732 auto method = _bus.new_method_call(
733 service_name::hwIsolation, object_path::hwIsolation,
734 interface::hwIsolationCreate, "CreateWithEntityPath");
735 method.append(binPath, type, sdbusplus::message::object_path(logPath));
736 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
737 // api's. Making d-bus call no reply type to avoid cyclic dependency.
738 // Added minimal timeout to catch initial failures.
739 // Need to revisit this design later to avoid cyclic dependency.
Matt Spinler35a405b2022-03-02 11:42:42 -0600740 constexpr auto hwIsolationTimeout = 100000; // in micro seconds
741 _bus.call_noreply(method, hwIsolationTimeout);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500742 }
743
Patrick Williams45e83522022-07-22 19:26:52 -0500744 catch (const sdbusplus::exception_t& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500745 {
746 std::string errName = e.name();
747 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
748 // mentioned above. Ignoring the error.
749 if (errName != SD_BUS_ERROR_TIMEOUT)
750 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500751 lg2::error("GUARD D-Bus call exception. Path={PATH}, "
752 "interface = {IFACE}, exception = {ERROR}",
753 "PATH", object_path::hwIsolation, "IFACE",
754 interface::hwIsolationCreate, "ERROR", e);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500755 }
756 }
757}
Sumit Kumar3e274432021-09-14 06:37:56 -0500758
759void DataInterface::createProgressSRC(
760 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
761{
762 DBusValue variant = std::make_tuple(priSRC, srcStruct);
763
764 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500765 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500766 interface::dbusProperty, "Set");
767
768 method.append(interface::bootRawProgress, "Value", variant);
769
Matt Spinler35a405b2022-03-02 11:42:42 -0600770 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500771}
Sumit Kumar027bf282022-01-24 11:25:19 -0600772
773std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
774{
775 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
776 std::string hwErrorLog = "/isolated_hw_errorlog";
777 std::string errorLog = "/error_log";
778 DBusPathList paths;
779 std::vector<uint32_t> ids;
780
781 // Get all latest mapper associations
782 paths = getPaths(association);
783 for (auto& path : paths)
784 {
785 // Look for object path with hardware isolation entry if any
786 size_t pos = path.find(hwErrorLog);
787 if (pos != std::string::npos)
788 {
789 // Get the object path
790 std::string ph = path;
791 ph.erase(pos, hwErrorLog.length());
792 auto service = getService(ph, interface::hwIsolationEntry);
793 if (!service.empty())
794 {
795 bool status;
796 DBusValue value;
797
798 // Read the Resolved property from object path
799 getProperty(service, ph, interface::hwIsolationEntry,
800 "Resolved", value);
801
802 status = std::get<bool>(value);
803
804 // If the entry isn't resolved
805 if (!status)
806 {
Patrick Williams2544b412022-10-04 08:41:06 -0500807 auto assocService = getService(path,
808 interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500809 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600810 {
Matt Spinler45796e82022-07-01 11:25:27 -0500811 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600812
813 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500814 getProperty(assocService, path, interface::association,
815 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600816
817 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500818 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600819 if (!logPath.empty())
820 {
821 // Get OpenBMC event log Id
822 uint32_t id = stoi(logPath[0].substr(
823 logPath[0].find_last_of('/') + 1));
824 ids.push_back(id);
825 }
826 }
827 }
828 }
829 }
830
831 // Look for object path with error_log entry if any
832 pos = path.find(errorLog);
833 if (pos != std::string::npos)
834 {
835 auto service = getService(path, interface::association);
836 if (!service.empty())
837 {
838 DBusValue value;
839
840 // Read Endpoints property
841 getProperty(service, path, interface::association, "endpoints",
842 value);
843
844 auto logPath = std::get<std::vector<std::string>>(value);
845 if (!logPath.empty())
846 {
847 // Get OpenBMC event log Id
848 uint32_t id = stoi(
849 logPath[0].substr(logPath[0].find_last_of('/') + 1));
850 ids.push_back(id);
851 }
852 }
853 }
854 }
855
856 if (ids.size() > 1)
857 {
858 // remove duplicates to have only unique ids
859 std::sort(ids.begin(), ids.end());
860 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
861 }
862 return ids;
863}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500864
865std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
866{
867 using RawProgressProperty = std::tuple<uint64_t, std::vector<uint8_t>>;
868
869 DBusValue value;
870 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
871 interface::bootRawProgress, "Value", value);
872
873 const auto& rawProgress = std::get<RawProgressProperty>(value);
874 return std::get<1>(rawProgress);
875}
876
Matt Spinler5b423652023-05-04 13:08:44 -0500877void DataInterface::startFruPlugWatch()
878{
879 // Add a watch on inventory InterfacesAdded and then find all
880 // existing hotpluggable interfaces and add propertiesChanged
881 // watches on them.
882
883 _invIaMatch = std::make_unique<sdbusplus::bus::match_t>(
884 _bus, match_rules::interfacesAdded(object_path::baseInv),
885 std::bind(&DataInterface::inventoryIfaceAdded, this,
886 std::placeholders::_1));
887 try
888 {
889 auto paths = getPaths(hotplugInterfaces);
890
891 _invPresentMatches.clear();
892
893 std::for_each(paths.begin(), paths.end(),
894 [this](const auto& path) { addHotplugWatch(path); });
895 }
896 catch (const sdbusplus::exception_t& e)
897 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500898 lg2::warning("Failed getting FRU paths to watch: {ERROR}", "ERROR", e);
Matt Spinler5b423652023-05-04 13:08:44 -0500899 }
900}
901
902void DataInterface::addHotplugWatch(const std::string& path)
903{
904 if (!_invPresentMatches.contains(path))
905 {
906 _invPresentMatches.emplace(
907 path,
908 std::make_unique<sdbusplus::bus::match_t>(
909 _bus, match_rules::propertiesChanged(path, interface::invItem),
910 std::bind(&DataInterface::presenceChanged, this,
911 std::placeholders::_1)));
912 }
913}
914
915void DataInterface::inventoryIfaceAdded(sdbusplus::message_t& msg)
916{
917 sdbusplus::message::object_path path;
918 DBusInterfaceMap interfaces;
919
920 msg.read(path, interfaces);
921
922 // Check if any of the new interfaces are for hot pluggable FRUs.
923 if (std::find_if(interfaces.begin(), interfaces.end(),
924 [](const auto& interfacePair) {
925 return std::find(hotplugInterfaces.begin(), hotplugInterfaces.end(),
926 interfacePair.first) != hotplugInterfaces.end();
Patrick Williams5fb575a2023-10-20 11:18:21 -0500927 }) == interfaces.end())
Matt Spinler5b423652023-05-04 13:08:44 -0500928 {
929 return;
930 }
931
932 addHotplugWatch(path.str);
933
934 // If an Inventory.Item interface was also added, check presence now.
935
936 // Notes:
937 // * This assumes the Inv.Item and Inv.Fan/PS are added together which
938 // is currently the case.
939 // * If the code ever switches to something without a Present
940 // property, then the IA signal itself would probably indicate presence.
941
942 auto itemIt = interfaces.find(interface::invItem);
943 if (itemIt != interfaces.end())
944 {
945 notifyPresenceSubsribers(path.str, itemIt->second);
946 }
947}
948
949void DataInterface::presenceChanged(sdbusplus::message_t& msg)
950{
951 DBusInterface interface;
952 DBusPropertyMap properties;
953
954 msg.read(interface, properties);
955 if (interface != interface::invItem)
956 {
957 return;
958 }
959
960 std::string path = msg.get_path();
961 notifyPresenceSubsribers(path, properties);
962}
963
964void DataInterface::notifyPresenceSubsribers(const std::string& path,
965 const DBusPropertyMap& properties)
966{
Matt Spinler5ee36052023-05-30 14:20:56 -0500967 auto prop = properties.find("Present");
968 if ((prop == properties.end()) || (!std::get<bool>(prop->second)))
969 {
970 return;
971 }
972
973 std::string locCode;
974
Matt Spinler5b423652023-05-04 13:08:44 -0500975 try
976 {
Matt Spinler52ee3a42023-07-27 14:54:48 -0500977 auto service = getService(path, interface::locCode);
978
979 // If the hotplugged FRU is hosted by PLDM, then it is
980 // in an IO expansion drawer and we don't care about it.
981 if (service == service_name::pldm)
982 {
983 return;
984 }
985
Matt Spinler5ee36052023-05-30 14:20:56 -0500986 locCode = getLocationCode(path);
Matt Spinler5b423652023-05-04 13:08:44 -0500987 }
Matt Spinler5ee36052023-05-30 14:20:56 -0500988 catch (const sdbusplus::exception_t& e)
Matt Spinler5b423652023-05-04 13:08:44 -0500989 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500990 lg2::debug("Could not get location code for {PATH}: {ERROR}", "PATH",
991 path, "ERROR", e);
Matt Spinler5ee36052023-05-30 14:20:56 -0500992 return;
Matt Spinler5b423652023-05-04 13:08:44 -0500993 }
Matt Spinler5ee36052023-05-30 14:20:56 -0500994
Matt Spinlera167a7d2023-06-30 15:14:25 -0500995 lg2::debug("Detected FRU {PATH} ({LOC}) present ", "PATH", path, "LOC",
996 locCode);
Matt Spinler5ee36052023-05-30 14:20:56 -0500997
998 // Tell the subscribers.
999 setFruPresent(locCode);
Matt Spinler5b423652023-05-04 13:08:44 -05001000}
Matt Spinlerc8705e22019-09-11 12:36:07 -05001001} // namespace pels
1002} // namespace openpower