blob: cdebc21e6e3ffa6432e76ad804032a4448d0b86f [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlercad9c2b2019-12-02 15:42:01 -060016
Matt Spinlerc8705e22019-09-11 12:36:07 -050017#include "data_interface.hpp"
18
Matt Spinlerf61f2922020-06-23 11:32:49 -050019#include "util.hpp"
20
Matt Spinlera167a7d2023-06-30 15:14:25 -050021#include <phosphor-logging/lg2.hpp>
Matt Spinler5b423652023-05-04 13:08:44 -050022#include <xyz/openbmc_project/State/BMC/server.hpp>
Matt Spinlerf10068d2020-12-02 10:44:08 -060023#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Matt Spinlera7d9d962019-11-06 15:01:25 -060024
Matt Spinler35a405b2022-03-02 11:42:42 -060025// Use a timeout of 10s for D-Bus calls so if there are
26// timeouts the callers of the PEL creation method won't
27// also timeout.
28constexpr auto dbusTimeout = 10000000;
29
Matt Spinlerc8705e22019-09-11 12:36:07 -050030namespace openpower
31{
32namespace pels
33{
34
35namespace service_name
36{
37constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050038constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050039constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050040constexpr auto hwIsolation = "org.open_power.HardwareIsolation";
Matt Spinler744d8512022-06-08 08:25:47 -050041constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050042constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler52ee3a42023-07-27 14:54:48 -050043constexpr auto pldm = "xyz.openbmc_project.PLDM";
Matt Spinler412f50e2023-11-14 12:49:52 -060044constexpr auto inventoryManager = "xyz.openbmc_project.Inventory.Manager";
Matt Spinlerc8705e22019-09-11 12:36:07 -050045} // namespace service_name
46
47namespace object_path
48{
49constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
50constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050051constexpr auto motherBoardInv =
52 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060053constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060054constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
55constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060056constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060057constexpr auto enableHostPELs =
58 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050059constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050060constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050061constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Matt Spinler744d8512022-06-08 08:25:47 -050062constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050063constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0";
Matt Spinlerc8705e22019-09-11 12:36:07 -050064} // namespace object_path
65
66namespace interface
67{
68constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
69constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
70constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060071constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060072constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060073constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
74constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
75constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060076constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050077constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060078constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050079constexpr auto compatible =
80 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050081constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050082constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050083constexpr auto operationalStatus =
84 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050085constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060086constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050087constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
88constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050089constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar027bf282022-01-24 11:25:19 -060090constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
91constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -050092constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050093constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler5b423652023-05-04 13:08:44 -050094constexpr auto invItem = "xyz.openbmc_project.Inventory.Item";
95constexpr auto invFan = "xyz.openbmc_project.Inventory.Item.Fan";
96constexpr auto invPowerSupply =
97 "xyz.openbmc_project.Inventory.Item.PowerSupply";
Matt Spinler412f50e2023-11-14 12:49:52 -060098constexpr auto inventoryManager = "xyz.openbmc_project.Inventory.Manager";
Matt Spinlerc8705e22019-09-11 12:36:07 -050099} // namespace interface
100
Willy Tu6ddbf692023-09-05 10:54:16 -0700101using namespace sdbusplus::server::xyz::openbmc_project::state::boot;
102using namespace sdbusplus::server::xyz::openbmc_project::state;
Matt Spinler5b423652023-05-04 13:08:44 -0500103namespace match_rules = sdbusplus::bus::match::rules;
104
105const DBusInterfaceList hotplugInterfaces{interface::invFan,
106 interface::invPowerSupply};
Matt Spinlera7d9d962019-11-06 15:01:25 -0600107
Matt Spinler0d92b522021-06-16 13:28:17 -0600108std::pair<std::string, std::string>
109 DataInterfaceBase::extractConnectorFromLocCode(
110 const std::string& locationCode)
111{
112 auto base = locationCode;
113 std::string connector{};
114
115 auto pos = base.find("-T");
116 if (pos != std::string::npos)
117 {
118 connector = base.substr(pos);
119 base = base.substr(0, pos);
120 }
121
122 return {base, connector};
123}
124
Patrick Williams45e83522022-07-22 19:26:52 -0500125DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus)
Matt Spinlerc8705e22019-09-11 12:36:07 -0500126{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600127 readBMCFWVersion();
128 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600129 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600130
Matt Spinlerf10068d2020-12-02 10:44:08 -0600131 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600132 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600133 bus, object_path::hostState, interface::bootProgress, "BootProgress",
134 *this, [this](const auto& value) {
Patrick Williams5fb575a2023-10-20 11:18:21 -0500135 this->_bootState = std::get<std::string>(value);
136 auto status = Progress::convertProgressStagesFromString(
137 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600138
Patrick Williams5fb575a2023-10-20 11:18:21 -0500139 if ((status == Progress::ProgressStages::SystemInitComplete) ||
140 (status == Progress::ProgressStages::OSRunning))
141 {
142 setHostUp(true);
143 }
144 else
145 {
146 setHostUp(false);
147 }
148 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600149
150 // Watch the host PEL enable property
151 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
152 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
153 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500154 if (std::get<bool>(value) != this->_sendPELsToHost)
155 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500156 lg2::info("The send PELs to host setting changed to {VAL}", "VAL",
157 std::get<bool>(value));
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500158 }
159 this->_sendPELsToHost = std::get<bool>(value);
Patrick Williams5fb575a2023-10-20 11:18:21 -0500160 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600161
162 // Watch the BMCState property
163 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
164 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
165 *this, [this](const auto& value) {
Patrick Williams5fb575a2023-10-20 11:18:21 -0500166 const auto& state = std::get<std::string>(value);
167 this->_bmcState = state;
Matt Spinler5b423652023-05-04 13:08:44 -0500168
Patrick Williams5fb575a2023-10-20 11:18:21 -0500169 // Wait for BMC ready to start watching for
170 // plugs so things calm down first.
171 if (BMC::convertBMCStateFromString(state) == BMC::BMCState::Ready)
172 {
173 startFruPlugWatch();
174 }
175 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600176
177 // Watch the chassis current and requested power state properties
178 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
179 bus, object_path::chassisState, interface::chassisState, *this,
180 [this](const auto& properties) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500181 auto state = properties.find("CurrentPowerState");
182 if (state != properties.end())
183 {
184 this->_chassisState = std::get<std::string>(state->second);
185 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600186
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500187 auto trans = properties.find("RequestedPowerTransition");
188 if (trans != properties.end())
189 {
190 this->_chassisTransition = std::get<std::string>(trans->second);
191 }
Patrick Williams5fb575a2023-10-20 11:18:21 -0500192 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600193
194 // Watch the CurrentHostState property
195 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
196 bus, object_path::hostState, interface::hostState, "CurrentHostState",
197 *this, [this](const auto& value) {
Patrick Williams5fb575a2023-10-20 11:18:21 -0500198 this->_hostState = std::get<std::string>(value);
199 }));
Matt Spinler744d8512022-06-08 08:25:47 -0500200
201 // Watch the BaseBIOSTable property for the hmc managed attribute
202 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
203 bus, object_path::biosConfigMgr, interface::biosConfigMgr,
204 "BaseBIOSTable", service_name::biosConfigMgr, *this,
205 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500206 const auto& attributes = std::get<BiosAttributes>(value);
Matt Spinler744d8512022-06-08 08:25:47 -0500207
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500208 auto it = attributes.find("pvm_hmc_managed");
209 if (it != attributes.end())
210 {
211 const auto& currentValVariant = std::get<5>(it->second);
212 auto currentVal = std::get_if<std::string>(&currentValVariant);
213 if (currentVal)
Matt Spinler744d8512022-06-08 08:25:47 -0500214 {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500215 this->_hmcManaged = (*currentVal == "Enabled") ? true : false;
Matt Spinler744d8512022-06-08 08:25:47 -0500216 }
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500217 }
Patrick Williams5fb575a2023-10-20 11:18:21 -0500218 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500219}
220
Matt Spinler2a28c932020-02-03 14:23:40 -0600221DBusPropertyMap
222 DataInterface::getAllProperties(const std::string& service,
223 const std::string& objectPath,
224 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500225{
226 DBusPropertyMap properties;
227
228 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
229 interface::dbusProperty, "GetAll");
230 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600231 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500232
233 reply.read(properties);
234
235 return properties;
236}
237
Matt Spinlera7d9d962019-11-06 15:01:25 -0600238void DataInterface::getProperty(const std::string& service,
239 const std::string& objectPath,
240 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600241 const std::string& property,
242 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600243{
Matt Spinlera7d9d962019-11-06 15:01:25 -0600244 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
245 interface::dbusProperty, "Get");
246 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600247 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600248
249 reply.read(value);
250}
251
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600252DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
253{
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600254 auto method = _bus.new_method_call(
255 service_name::objectMapper, object_path::objectMapper,
256 interface::objectMapper, "GetSubTreePaths");
257
258 method.append(std::string{"/"}, 0, interfaces);
259
Matt Spinler35a405b2022-03-02 11:42:42 -0600260 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600261
262 DBusPathList paths;
263 reply.read(paths);
264
265 return paths;
266}
267
Matt Spinlerc8705e22019-09-11 12:36:07 -0500268DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600269 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500270{
271 auto method = _bus.new_method_call(service_name::objectMapper,
272 object_path::objectMapper,
273 interface::objectMapper, "GetObject");
274
275 method.append(objectPath, std::vector<std::string>({interface}));
276
Matt Spinler35a405b2022-03-02 11:42:42 -0600277 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500278
279 std::map<DBusService, DBusInterfaceList> response;
280 reply.read(response);
281
282 if (!response.empty())
283 {
284 return response.begin()->first;
285 }
286
287 return std::string{};
288}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600289
Matt Spinler677381b2020-01-23 10:04:29 -0600290void DataInterface::readBMCFWVersion()
291{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500292 _bmcFWVersion =
293 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600294}
295
296void DataInterface::readServerFWVersion()
297{
Sumit Kumarcad16202021-05-13 04:06:15 -0500298 auto value =
299 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
300 if ((value != "") && (value.find_last_of(')') != std::string::npos))
301 {
302 std::size_t pos = value.find_first_of('(') + 1;
303 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
304 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600305}
306
Matt Spinler677381b2020-01-23 10:04:29 -0600307void DataInterface::readBMCFWVersionID()
308{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500309 _bmcFWVersionID =
310 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600311}
312
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500313std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600314{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500315 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600316 try
317 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500318 auto service = getService(object_path::systemInv, interface::invAsset);
319 if (!service.empty())
320 {
321 DBusValue value;
322 getProperty(service, object_path::systemInv, interface::invAsset,
323 "Model", value);
324
325 model = std::get<std::string>(value);
326 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600327 }
328 catch (const std::exception& e)
329 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500330 lg2::warning("Failed reading Model property from "
331 "interface: {IFACE} exception: {ERROR}",
332 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600333 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500334
335 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600336}
337
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500338std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600339{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500340 std::string sn;
341 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600342 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500343 auto service = getService(object_path::systemInv, interface::invAsset);
344 if (!service.empty())
345 {
346 DBusValue value;
347 getProperty(service, object_path::systemInv, interface::invAsset,
348 "SerialNumber", value);
349
350 sn = std::get<std::string>(value);
351 }
352 }
353 catch (const std::exception& e)
354 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500355 lg2::warning("Failed reading SerialNumber property from "
356 "interface: {IFACE} exception: {ERROR}",
357 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600358 }
359
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500360 return sn;
361}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600362
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500363std::string DataInterface::getMotherboardCCIN() const
364{
365 std::string ccin;
366
367 try
368 {
Patrick Williams2544b412022-10-04 08:41:06 -0500369 auto service = getService(object_path::motherBoardInv,
370 interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500371 if (!service.empty())
372 {
373 DBusValue value;
374 getProperty(service, object_path::motherBoardInv,
375 interface::viniRecordVPD, "CC", value);
376
377 auto cc = std::get<std::vector<uint8_t>>(value);
378 ccin = std::string{cc.begin(), cc.end()};
379 }
380 }
381 catch (const std::exception& e)
382 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500383 lg2::warning("Failed reading Motherboard CCIN property from "
384 "interface: {IFACE} exception: {ERROR}",
385 "IFACE", interface::viniRecordVPD, "ERROR", e);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500386 }
387
388 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600389}
390
Ben Tynere32b7e72021-05-18 12:38:40 -0500391std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
392{
393 std::vector<uint8_t> systemIM;
394
395 try
396 {
Patrick Williams2544b412022-10-04 08:41:06 -0500397 auto service = getService(object_path::motherBoardInv,
398 interface::vsbpRecordVPD);
Ben Tynere32b7e72021-05-18 12:38:40 -0500399 if (!service.empty())
400 {
401 DBusValue value;
402 getProperty(service, object_path::motherBoardInv,
403 interface::vsbpRecordVPD, "IM", value);
404
405 systemIM = std::get<std::vector<uint8_t>>(value);
406 }
407 }
408 catch (const std::exception& e)
409 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500410 lg2::warning("Failed reading System IM property from "
411 "interface: {IFACE} exception: {ERROR}",
412 "IFACE", interface::vsbpRecordVPD, "ERROR", e);
Ben Tynere32b7e72021-05-18 12:38:40 -0500413 }
414
415 return systemIM;
416}
417
Matt Spinler60c4e792020-03-13 13:45:36 -0500418void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500419 std::string& fruPartNumber,
420 std::string& ccin,
421 std::string& serialNumber) const
422{
423 // For now, attempt to get all of the properties directly on the path
424 // passed in. In the future, may need to make use of an algorithm
425 // to figure out which inventory objects actually hold these
426 // interfaces in the case of non FRUs, or possibly another service
427 // will provide this info. Any missing interfaces will result
428 // in exceptions being thrown.
429
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500430 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500431
Patrick Williams2544b412022-10-04 08:41:06 -0500432 auto properties = getAllProperties(service, inventoryPath,
433 interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500434
435 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
436 fruPartNumber = std::string{value.begin(), value.end()};
437
438 value = std::get<std::vector<uint8_t>>(properties["CC"]);
439 ccin = std::string{value.begin(), value.end()};
440
441 value = std::get<std::vector<uint8_t>>(properties["SN"]);
442 serialNumber = std::string{value.begin(), value.end()};
443}
444
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500445std::string
446 DataInterface::getLocationCode(const std::string& inventoryPath) const
447{
448 auto service = getService(inventoryPath, interface::locCode);
449
450 DBusValue locCode;
451 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
452 locCode);
453
454 return std::get<std::string>(locCode);
455}
456
Matt Spinler5fb24c12020-06-04 11:21:33 -0500457std::string
458 DataInterface::addLocationCodePrefix(const std::string& locationCode)
459{
460 static const std::string locationCodePrefix{"Ufcs-"};
461
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500462 // Technically there are 2 location code prefixes, Ufcs and Umts, so
463 // if it already starts with a U then don't need to do anything.
464 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500465 {
466 return locationCodePrefix + locationCode;
467 }
468
469 return locationCode;
470}
471
472std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500473 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500474{
Matt Spinler0d92b522021-06-16 13:28:17 -0600475 // Location codes for connectors are the location code of the FRU they are
476 // on, plus a '-Tx' segment. Remove this last segment before expanding it
477 // and then add it back in afterwards. This way, the connector doesn't have
478 // to be in the model just so that it can be expanded.
479 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
480
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500481 auto method =
482 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
483 interface::vpdManager, "GetExpandedLocationCode");
484
Matt Spinler0d92b522021-06-16 13:28:17 -0600485 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500486
Matt Spinler35a405b2022-03-02 11:42:42 -0600487 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500488
489 std::string expandedLocationCode;
490 reply.read(expandedLocationCode);
491
Matt Spinler0d92b522021-06-16 13:28:17 -0600492 if (!connectorLoc.empty())
493 {
494 expandedLocationCode += connectorLoc;
495 }
496
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500497 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500498}
499
Matt Spinlerbad056b2023-01-25 14:16:57 -0600500std::vector<std::string>
Matt Spinler2f9225a2020-08-05 12:58:49 -0500501 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
502 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500503{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500504 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
505 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500506
Matt Spinler0d92b522021-06-16 13:28:17 -0600507 // Remove the connector segment, if present, so that this method call
508 // returns an inventory path that getHWCalloutFields() can be used with.
509 // (The serial number, etc, aren't stored on the connector in the
510 // inventory, and may not even be modeled.)
511 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
512
Matt Spinler2f9225a2020-08-05 12:58:49 -0500513 auto method =
514 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
515 interface::vpdManager, methodName.c_str());
516
517 if (expanded)
518 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600519 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500520 }
521 else
522 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600523 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500524 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500525
Matt Spinler35a405b2022-03-02 11:42:42 -0600526 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500527
528 std::vector<sdbusplus::message::object_path> entries;
529 reply.read(entries);
530
Matt Spinlerbad056b2023-01-25 14:16:57 -0600531 std::vector<std::string> paths;
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500532
Matt Spinlerbad056b2023-01-25 14:16:57 -0600533 // Note: The D-Bus method will fail if nothing found.
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500534 std::for_each(entries.begin(), entries.end(),
Matt Spinlerbad056b2023-01-25 14:16:57 -0600535 [&paths](const auto& path) { paths.push_back(path); });
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500536
Matt Spinlerbad056b2023-01-25 14:16:57 -0600537 return paths;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500538}
539
Matt Spinler34a904c2020-08-05 14:53:28 -0500540void DataInterface::assertLEDGroup(const std::string& ledGroup,
541 bool value) const
542{
543 DBusValue variant = value;
Patrick Williams2544b412022-10-04 08:41:06 -0500544 auto method = _bus.new_method_call(service_name::ledGroupManager,
545 ledGroup.c_str(),
546 interface::dbusProperty, "Set");
Matt Spinler34a904c2020-08-05 14:53:28 -0500547 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600548 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500549}
550
Matt Spinler993168d2021-04-07 16:05:03 -0500551void DataInterface::setFunctional(const std::string& objectPath,
552 bool value) const
553{
Matt Spinler412f50e2023-11-14 12:49:52 -0600554 DBusPropertyMap prop{{"Functional", value}};
555 DBusInterfaceMap iface{{interface::operationalStatus, prop}};
Matt Spinler993168d2021-04-07 16:05:03 -0500556
Matt Spinler412f50e2023-11-14 12:49:52 -0600557 // PIM takes a relative path like /system/chassis so remove
558 // /xyz/openbmc_project/inventory if present.
559 std::string path{objectPath};
560 if (path.starts_with(object_path::baseInv))
561 {
562 path = objectPath.substr(strlen(object_path::baseInv));
563 }
564 DBusObjectMap object{{path, iface}};
Matt Spinler993168d2021-04-07 16:05:03 -0500565
Matt Spinler412f50e2023-11-14 12:49:52 -0600566 auto method = _bus.new_method_call(service_name::inventoryManager,
567 object_path::baseInv,
568 interface::inventoryManager, "Notify");
569 method.append(std::move(object));
Matt Spinler35a405b2022-03-02 11:42:42 -0600570 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500571}
572
Sumit Kumar76198a22021-07-15 05:59:57 -0500573using AssociationTuple = std::tuple<std::string, std::string, std::string>;
574using AssociationsProperty = std::vector<AssociationTuple>;
575
576void DataInterface::setCriticalAssociation(const std::string& objectPath) const
577{
578 DBusValue getAssociationValue;
579
Sumit Kumar027bf282022-01-24 11:25:19 -0600580 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500581
Sumit Kumar027bf282022-01-24 11:25:19 -0600582 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500583 getAssociationValue);
584
585 auto association = std::get<AssociationsProperty>(getAssociationValue);
586
587 AssociationTuple critAssociation{
588 "health_rollup", "critical",
589 "/xyz/openbmc_project/inventory/system/chassis"};
590
591 if (std::find(association.begin(), association.end(), critAssociation) ==
592 association.end())
593 {
594 association.push_back(critAssociation);
595 DBusValue setAssociationValue = association;
596
597 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
598 interface::dbusProperty, "Set");
599
Sumit Kumar027bf282022-01-24 11:25:19 -0600600 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500601 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600602 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500603 }
604}
605
Matt Spinler1ab66962020-10-29 13:21:44 -0500606std::vector<std::string> DataInterface::getSystemNames() const
607{
608 DBusSubTree subtree;
609 DBusValue names;
610
611 auto method = _bus.new_method_call(service_name::objectMapper,
612 object_path::objectMapper,
613 interface::objectMapper, "GetSubTree");
614 method.append(std::string{"/"}, 0,
615 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600616 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500617
618 reply.read(subtree);
619 if (subtree.empty())
620 {
621 throw std::runtime_error("Compatible interface not on D-Bus");
622 }
623
624 const auto& object = *(subtree.begin());
625 const auto& path = object.first;
626 const auto& service = object.second.begin()->first;
627
628 getProperty(service, path, interface::compatible, "Names", names);
629
630 return std::get<std::vector<std::string>>(names);
631}
632
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500633bool DataInterface::getQuiesceOnError() const
634{
635 bool ret = false;
636
637 try
638 {
Patrick Williams2544b412022-10-04 08:41:06 -0500639 auto service = getService(object_path::logSetting,
640 interface::logSetting);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500641 if (!service.empty())
642 {
643 DBusValue value;
644 getProperty(service, object_path::logSetting, interface::logSetting,
645 "QuiesceOnHwError", value);
646
647 ret = std::get<bool>(value);
648 }
649 }
650 catch (const std::exception& e)
651 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500652 lg2::warning("Failed reading QuiesceOnHwError property from "
653 "interface: {IFACE} exception: {ERROR}",
654 "IFACE", interface::logSetting, "ERROR", e);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500655 }
656
657 return ret;
658}
659
Sumit Kumar9d43a722021-08-24 09:46:19 -0500660std::vector<bool>
661 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
662{
663 DBusSubTree subtree;
664 std::vector<bool> result(type.size(), false);
665
666 // Query GetSubTree for the availability of dump interface
667 auto method = _bus.new_method_call(service_name::objectMapper,
668 object_path::objectMapper,
669 interface::objectMapper, "GetSubTree");
670 method.append(std::string{"/"}, 0,
671 std::vector<std::string>{interface::dumpEntry});
Matt Spinler35a405b2022-03-02 11:42:42 -0600672 auto reply = _bus.call(method, dbusTimeout);
Sumit Kumar9d43a722021-08-24 09:46:19 -0500673
674 reply.read(subtree);
675
676 if (subtree.empty())
677 {
678 return result;
679 }
680
681 std::vector<bool>::iterator itDumpStatus = result.begin();
682 uint8_t count = 0;
683 for (const auto& [path, serviceInfo] : subtree)
684 {
685 const auto& service = serviceInfo.begin()->first;
686 // Check for dump type on the object path
687 for (const auto& it : type)
688 {
689 if (path.find(it) != std::string::npos)
690 {
691 DBusValue value, progress;
692
693 // If dump type status is already available go for next path
694 if (*itDumpStatus)
695 {
696 break;
697 }
698
699 // Check for valid dump to be available if following
700 // conditions are met for the dump entry path -
701 // Offloaded == false and Status == Completed
702 getProperty(service, path, interface::dumpEntry, "Offloaded",
703 value);
704 getProperty(service, path, interface::dumpProgress, "Status",
705 progress);
706 auto offload = std::get<bool>(value);
707 auto status = std::get<std::string>(progress);
708 if (!offload && (status.find("Completed") != std::string::npos))
709 {
710 *itDumpStatus = true;
711 count++;
712 if (count >= type.size())
713 {
714 return result;
715 }
716 break;
717 }
718 }
Matt Spinler45796e82022-07-01 11:25:27 -0500719 ++itDumpStatus;
Sumit Kumar9d43a722021-08-24 09:46:19 -0500720 }
721 itDumpStatus = result.begin();
722 }
723
724 return result;
725}
726
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500727void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
728 const std::string& type,
729 const std::string& logPath) const
730{
731 try
732 {
733 auto method = _bus.new_method_call(
734 service_name::hwIsolation, object_path::hwIsolation,
735 interface::hwIsolationCreate, "CreateWithEntityPath");
736 method.append(binPath, type, sdbusplus::message::object_path(logPath));
737 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
738 // api's. Making d-bus call no reply type to avoid cyclic dependency.
739 // Added minimal timeout to catch initial failures.
740 // Need to revisit this design later to avoid cyclic dependency.
Matt Spinler35a405b2022-03-02 11:42:42 -0600741 constexpr auto hwIsolationTimeout = 100000; // in micro seconds
742 _bus.call_noreply(method, hwIsolationTimeout);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500743 }
744
Patrick Williams45e83522022-07-22 19:26:52 -0500745 catch (const sdbusplus::exception_t& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500746 {
747 std::string errName = e.name();
748 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
749 // mentioned above. Ignoring the error.
750 if (errName != SD_BUS_ERROR_TIMEOUT)
751 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500752 lg2::error("GUARD D-Bus call exception. Path={PATH}, "
753 "interface = {IFACE}, exception = {ERROR}",
754 "PATH", object_path::hwIsolation, "IFACE",
755 interface::hwIsolationCreate, "ERROR", e);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500756 }
757 }
758}
Sumit Kumar3e274432021-09-14 06:37:56 -0500759
760void DataInterface::createProgressSRC(
761 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
762{
763 DBusValue variant = std::make_tuple(priSRC, srcStruct);
764
765 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500766 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500767 interface::dbusProperty, "Set");
768
769 method.append(interface::bootRawProgress, "Value", variant);
770
Matt Spinler35a405b2022-03-02 11:42:42 -0600771 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500772}
Sumit Kumar027bf282022-01-24 11:25:19 -0600773
774std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
775{
776 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
777 std::string hwErrorLog = "/isolated_hw_errorlog";
778 std::string errorLog = "/error_log";
779 DBusPathList paths;
780 std::vector<uint32_t> ids;
781
782 // Get all latest mapper associations
783 paths = getPaths(association);
784 for (auto& path : paths)
785 {
786 // Look for object path with hardware isolation entry if any
787 size_t pos = path.find(hwErrorLog);
788 if (pos != std::string::npos)
789 {
790 // Get the object path
791 std::string ph = path;
792 ph.erase(pos, hwErrorLog.length());
793 auto service = getService(ph, interface::hwIsolationEntry);
794 if (!service.empty())
795 {
796 bool status;
797 DBusValue value;
798
799 // Read the Resolved property from object path
800 getProperty(service, ph, interface::hwIsolationEntry,
801 "Resolved", value);
802
803 status = std::get<bool>(value);
804
805 // If the entry isn't resolved
806 if (!status)
807 {
Patrick Williams2544b412022-10-04 08:41:06 -0500808 auto assocService = getService(path,
809 interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500810 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600811 {
Matt Spinler45796e82022-07-01 11:25:27 -0500812 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600813
814 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500815 getProperty(assocService, path, interface::association,
816 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600817
818 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500819 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600820 if (!logPath.empty())
821 {
822 // Get OpenBMC event log Id
823 uint32_t id = stoi(logPath[0].substr(
824 logPath[0].find_last_of('/') + 1));
825 ids.push_back(id);
826 }
827 }
828 }
829 }
830 }
831
832 // Look for object path with error_log entry if any
833 pos = path.find(errorLog);
834 if (pos != std::string::npos)
835 {
836 auto service = getService(path, interface::association);
837 if (!service.empty())
838 {
839 DBusValue value;
840
841 // Read Endpoints property
842 getProperty(service, path, interface::association, "endpoints",
843 value);
844
845 auto logPath = std::get<std::vector<std::string>>(value);
846 if (!logPath.empty())
847 {
848 // Get OpenBMC event log Id
849 uint32_t id = stoi(
850 logPath[0].substr(logPath[0].find_last_of('/') + 1));
851 ids.push_back(id);
852 }
853 }
854 }
855 }
856
857 if (ids.size() > 1)
858 {
859 // remove duplicates to have only unique ids
860 std::sort(ids.begin(), ids.end());
861 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
862 }
863 return ids;
864}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500865
866std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
867{
868 using RawProgressProperty = std::tuple<uint64_t, std::vector<uint8_t>>;
869
870 DBusValue value;
871 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
872 interface::bootRawProgress, "Value", value);
873
874 const auto& rawProgress = std::get<RawProgressProperty>(value);
875 return std::get<1>(rawProgress);
876}
877
Matt Spinler5b423652023-05-04 13:08:44 -0500878void DataInterface::startFruPlugWatch()
879{
880 // Add a watch on inventory InterfacesAdded and then find all
881 // existing hotpluggable interfaces and add propertiesChanged
882 // watches on them.
883
884 _invIaMatch = std::make_unique<sdbusplus::bus::match_t>(
885 _bus, match_rules::interfacesAdded(object_path::baseInv),
886 std::bind(&DataInterface::inventoryIfaceAdded, this,
887 std::placeholders::_1));
888 try
889 {
890 auto paths = getPaths(hotplugInterfaces);
891
892 _invPresentMatches.clear();
893
894 std::for_each(paths.begin(), paths.end(),
895 [this](const auto& path) { addHotplugWatch(path); });
896 }
897 catch (const sdbusplus::exception_t& e)
898 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500899 lg2::warning("Failed getting FRU paths to watch: {ERROR}", "ERROR", e);
Matt Spinler5b423652023-05-04 13:08:44 -0500900 }
901}
902
903void DataInterface::addHotplugWatch(const std::string& path)
904{
905 if (!_invPresentMatches.contains(path))
906 {
907 _invPresentMatches.emplace(
908 path,
909 std::make_unique<sdbusplus::bus::match_t>(
910 _bus, match_rules::propertiesChanged(path, interface::invItem),
911 std::bind(&DataInterface::presenceChanged, this,
912 std::placeholders::_1)));
913 }
914}
915
916void DataInterface::inventoryIfaceAdded(sdbusplus::message_t& msg)
917{
918 sdbusplus::message::object_path path;
919 DBusInterfaceMap interfaces;
920
921 msg.read(path, interfaces);
922
923 // Check if any of the new interfaces are for hot pluggable FRUs.
924 if (std::find_if(interfaces.begin(), interfaces.end(),
925 [](const auto& interfacePair) {
926 return std::find(hotplugInterfaces.begin(), hotplugInterfaces.end(),
927 interfacePair.first) != hotplugInterfaces.end();
Patrick Williams5fb575a2023-10-20 11:18:21 -0500928 }) == interfaces.end())
Matt Spinler5b423652023-05-04 13:08:44 -0500929 {
930 return;
931 }
932
933 addHotplugWatch(path.str);
934
935 // If an Inventory.Item interface was also added, check presence now.
936
937 // Notes:
938 // * This assumes the Inv.Item and Inv.Fan/PS are added together which
939 // is currently the case.
940 // * If the code ever switches to something without a Present
941 // property, then the IA signal itself would probably indicate presence.
942
943 auto itemIt = interfaces.find(interface::invItem);
944 if (itemIt != interfaces.end())
945 {
946 notifyPresenceSubsribers(path.str, itemIt->second);
947 }
948}
949
950void DataInterface::presenceChanged(sdbusplus::message_t& msg)
951{
952 DBusInterface interface;
953 DBusPropertyMap properties;
954
955 msg.read(interface, properties);
956 if (interface != interface::invItem)
957 {
958 return;
959 }
960
961 std::string path = msg.get_path();
962 notifyPresenceSubsribers(path, properties);
963}
964
965void DataInterface::notifyPresenceSubsribers(const std::string& path,
966 const DBusPropertyMap& properties)
967{
Matt Spinler5ee36052023-05-30 14:20:56 -0500968 auto prop = properties.find("Present");
969 if ((prop == properties.end()) || (!std::get<bool>(prop->second)))
970 {
971 return;
972 }
973
974 std::string locCode;
975
Matt Spinler5b423652023-05-04 13:08:44 -0500976 try
977 {
Matt Spinler52ee3a42023-07-27 14:54:48 -0500978 auto service = getService(path, interface::locCode);
979
980 // If the hotplugged FRU is hosted by PLDM, then it is
981 // in an IO expansion drawer and we don't care about it.
982 if (service == service_name::pldm)
983 {
984 return;
985 }
986
Matt Spinler5ee36052023-05-30 14:20:56 -0500987 locCode = getLocationCode(path);
Matt Spinler5b423652023-05-04 13:08:44 -0500988 }
Matt Spinler5ee36052023-05-30 14:20:56 -0500989 catch (const sdbusplus::exception_t& e)
Matt Spinler5b423652023-05-04 13:08:44 -0500990 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500991 lg2::debug("Could not get location code for {PATH}: {ERROR}", "PATH",
992 path, "ERROR", e);
Matt Spinler5ee36052023-05-30 14:20:56 -0500993 return;
Matt Spinler5b423652023-05-04 13:08:44 -0500994 }
Matt Spinler5ee36052023-05-30 14:20:56 -0500995
Matt Spinlera167a7d2023-06-30 15:14:25 -0500996 lg2::debug("Detected FRU {PATH} ({LOC}) present ", "PATH", path, "LOC",
997 locCode);
Matt Spinler5ee36052023-05-30 14:20:56 -0500998
999 // Tell the subscribers.
1000 setFruPresent(locCode);
Matt Spinler5b423652023-05-04 13:08:44 -05001001}
Matt Spinlerc8705e22019-09-11 12:36:07 -05001002} // namespace pels
1003} // namespace openpower