blob: 9850a9bef16c4eb39af572ca58945bf36acd3738 [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 Spinlerc8705e22019-09-11 12:36:07 -050050} // namespace service_name
51
52namespace object_path
53{
54constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
55constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050056constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050057constexpr auto motherBoardInv =
58 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060059constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060060constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
61constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060062constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060063constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060064constexpr auto enableHostPELs =
65 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050066constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050067constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050068constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Matt Spinler744d8512022-06-08 08:25:47 -050069constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050070constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0";
Matt Spinlerc8705e22019-09-11 12:36:07 -050071} // namespace object_path
72
73namespace interface
74{
75constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
76constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
77constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060078constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinlerb3f51862019-12-09 13:55:10 -060079constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060080constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060081constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
82constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
83constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060084constexpr auto invMotherboard =
85 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
86constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050087constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060088constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050089constexpr auto compatible =
90 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050091constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050092constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050093constexpr auto operationalStatus =
94 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050095constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060096constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050097constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
98constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050099constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar027bf282022-01-24 11:25:19 -0600100constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
101constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -0500102constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -0500103constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler5b423652023-05-04 13:08:44 -0500104constexpr auto invItem = "xyz.openbmc_project.Inventory.Item";
105constexpr auto invFan = "xyz.openbmc_project.Inventory.Item.Fan";
106constexpr auto invPowerSupply =
107 "xyz.openbmc_project.Inventory.Item.PowerSupply";
Matt Spinlerc8705e22019-09-11 12:36:07 -0500108} // namespace interface
109
Matt Spinlerf10068d2020-12-02 10:44:08 -0600110using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
Matt Spinler5b423652023-05-04 13:08:44 -0500111using namespace sdbusplus::xyz::openbmc_project::State::server;
Matt Spinler5b423652023-05-04 13:08:44 -0500112namespace match_rules = sdbusplus::bus::match::rules;
113
114const DBusInterfaceList hotplugInterfaces{interface::invFan,
115 interface::invPowerSupply};
Matt Spinlera7d9d962019-11-06 15:01:25 -0600116
Matt Spinler0d92b522021-06-16 13:28:17 -0600117std::pair<std::string, std::string>
118 DataInterfaceBase::extractConnectorFromLocCode(
119 const std::string& locationCode)
120{
121 auto base = locationCode;
122 std::string connector{};
123
124 auto pos = base.find("-T");
125 if (pos != std::string::npos)
126 {
127 connector = base.substr(pos);
128 base = base.substr(0, pos);
129 }
130
131 return {base, connector};
132}
133
Patrick Williams45e83522022-07-22 19:26:52 -0500134DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus)
Matt Spinlerc8705e22019-09-11 12:36:07 -0500135{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600136 readBMCFWVersion();
137 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600138 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600139
Matt Spinlerf10068d2020-12-02 10:44:08 -0600140 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600141 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600142 bus, object_path::hostState, interface::bootProgress, "BootProgress",
143 *this, [this](const auto& value) {
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500144 this->_bootState = std::get<std::string>(value);
Matt Spinlerf10068d2020-12-02 10:44:08 -0600145 auto status = Progress::convertProgressStagesFromString(
146 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600147
Matt Spinlerf10068d2020-12-02 10:44:08 -0600148 if ((status == Progress::ProgressStages::SystemInitComplete) ||
Matt Spinlerf10068d2020-12-02 10:44:08 -0600149 (status == Progress::ProgressStages::OSRunning))
Matt Spinler2a28c932020-02-03 14:23:40 -0600150 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600151 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600152 }
153 else
154 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600155 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600156 }
157 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600158
159 // Watch the host PEL enable property
160 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
161 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
162 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500163 if (std::get<bool>(value) != this->_sendPELsToHost)
164 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500165 lg2::info("The send PELs to host setting changed to {VAL}", "VAL",
166 std::get<bool>(value));
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500167 }
168 this->_sendPELsToHost = std::get<bool>(value);
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600169 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600170
171 // Watch the BMCState property
172 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
173 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
174 *this, [this](const auto& value) {
Matt Spinler5b423652023-05-04 13:08:44 -0500175 const auto& state = std::get<std::string>(value);
176 this->_bmcState = state;
177
178 // Wait for BMC ready to start watching for
179 // plugs so things calm down first.
180 if (BMC::convertBMCStateFromString(state) == BMC::BMCState::Ready)
181 {
182 startFruPlugWatch();
183 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600184 }));
185
186 // Watch the chassis current and requested power state properties
187 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
188 bus, object_path::chassisState, interface::chassisState, *this,
189 [this](const auto& properties) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500190 auto state = properties.find("CurrentPowerState");
191 if (state != properties.end())
192 {
193 this->_chassisState = std::get<std::string>(state->second);
194 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600195
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500196 auto trans = properties.find("RequestedPowerTransition");
197 if (trans != properties.end())
198 {
199 this->_chassisTransition = std::get<std::string>(trans->second);
200 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600201 }));
202
203 // Watch the CurrentHostState property
204 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
205 bus, object_path::hostState, interface::hostState, "CurrentHostState",
206 *this, [this](const auto& value) {
207 this->_hostState = std::get<std::string>(value);
208 }));
Matt Spinler744d8512022-06-08 08:25:47 -0500209
210 // Watch the BaseBIOSTable property for the hmc managed attribute
211 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
212 bus, object_path::biosConfigMgr, interface::biosConfigMgr,
213 "BaseBIOSTable", service_name::biosConfigMgr, *this,
214 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500215 const auto& attributes = std::get<BiosAttributes>(value);
Matt Spinler744d8512022-06-08 08:25:47 -0500216
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500217 auto it = attributes.find("pvm_hmc_managed");
218 if (it != attributes.end())
219 {
220 const auto& currentValVariant = std::get<5>(it->second);
221 auto currentVal = std::get_if<std::string>(&currentValVariant);
222 if (currentVal)
Matt Spinler744d8512022-06-08 08:25:47 -0500223 {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500224 this->_hmcManaged = (*currentVal == "Enabled") ? true : false;
Matt Spinler744d8512022-06-08 08:25:47 -0500225 }
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500226 }
Matt Spinler744d8512022-06-08 08:25:47 -0500227 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500228}
229
Matt Spinler2a28c932020-02-03 14:23:40 -0600230DBusPropertyMap
231 DataInterface::getAllProperties(const std::string& service,
232 const std::string& objectPath,
233 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500234{
235 DBusPropertyMap properties;
236
237 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
238 interface::dbusProperty, "GetAll");
239 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600240 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500241
242 reply.read(properties);
243
244 return properties;
245}
246
Matt Spinlera7d9d962019-11-06 15:01:25 -0600247void DataInterface::getProperty(const std::string& service,
248 const std::string& objectPath,
249 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600250 const std::string& property,
251 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600252{
Matt Spinlera7d9d962019-11-06 15:01:25 -0600253 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
254 interface::dbusProperty, "Get");
255 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600256 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600257
258 reply.read(value);
259}
260
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600261DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
262{
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600263 auto method = _bus.new_method_call(
264 service_name::objectMapper, object_path::objectMapper,
265 interface::objectMapper, "GetSubTreePaths");
266
267 method.append(std::string{"/"}, 0, interfaces);
268
Matt Spinler35a405b2022-03-02 11:42:42 -0600269 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600270
271 DBusPathList paths;
272 reply.read(paths);
273
274 return paths;
275}
276
Matt Spinlerc8705e22019-09-11 12:36:07 -0500277DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600278 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500279{
280 auto method = _bus.new_method_call(service_name::objectMapper,
281 object_path::objectMapper,
282 interface::objectMapper, "GetObject");
283
284 method.append(objectPath, std::vector<std::string>({interface}));
285
Matt Spinler35a405b2022-03-02 11:42:42 -0600286 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500287
288 std::map<DBusService, DBusInterfaceList> response;
289 reply.read(response);
290
291 if (!response.empty())
292 {
293 return response.begin()->first;
294 }
295
296 return std::string{};
297}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600298
Matt Spinler677381b2020-01-23 10:04:29 -0600299void DataInterface::readBMCFWVersion()
300{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500301 _bmcFWVersion =
302 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600303}
304
305void DataInterface::readServerFWVersion()
306{
Sumit Kumarcad16202021-05-13 04:06:15 -0500307 auto value =
308 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
309 if ((value != "") && (value.find_last_of(')') != std::string::npos))
310 {
311 std::size_t pos = value.find_first_of('(') + 1;
312 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
313 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600314}
315
Matt Spinler677381b2020-01-23 10:04:29 -0600316void DataInterface::readBMCFWVersionID()
317{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500318 _bmcFWVersionID =
319 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600320}
321
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500322std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600323{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500324 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600325 try
326 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500327 auto service = getService(object_path::systemInv, interface::invAsset);
328 if (!service.empty())
329 {
330 DBusValue value;
331 getProperty(service, object_path::systemInv, interface::invAsset,
332 "Model", value);
333
334 model = std::get<std::string>(value);
335 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600336 }
337 catch (const std::exception& e)
338 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500339 lg2::warning("Failed reading Model property from "
340 "interface: {IFACE} exception: {ERROR}",
341 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600342 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500343
344 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600345}
346
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500347std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600348{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500349 std::string sn;
350 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600351 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500352 auto service = getService(object_path::systemInv, interface::invAsset);
353 if (!service.empty())
354 {
355 DBusValue value;
356 getProperty(service, object_path::systemInv, interface::invAsset,
357 "SerialNumber", value);
358
359 sn = std::get<std::string>(value);
360 }
361 }
362 catch (const std::exception& e)
363 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500364 lg2::warning("Failed reading SerialNumber property from "
365 "interface: {IFACE} exception: {ERROR}",
366 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600367 }
368
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500369 return sn;
370}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600371
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500372std::string DataInterface::getMotherboardCCIN() const
373{
374 std::string ccin;
375
376 try
377 {
Patrick Williams2544b412022-10-04 08:41:06 -0500378 auto service = getService(object_path::motherBoardInv,
379 interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500380 if (!service.empty())
381 {
382 DBusValue value;
383 getProperty(service, object_path::motherBoardInv,
384 interface::viniRecordVPD, "CC", value);
385
386 auto cc = std::get<std::vector<uint8_t>>(value);
387 ccin = std::string{cc.begin(), cc.end()};
388 }
389 }
390 catch (const std::exception& e)
391 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500392 lg2::warning("Failed reading Motherboard CCIN property from "
393 "interface: {IFACE} exception: {ERROR}",
394 "IFACE", interface::viniRecordVPD, "ERROR", e);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500395 }
396
397 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600398}
399
Ben Tynere32b7e72021-05-18 12:38:40 -0500400std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
401{
402 std::vector<uint8_t> systemIM;
403
404 try
405 {
Patrick Williams2544b412022-10-04 08:41:06 -0500406 auto service = getService(object_path::motherBoardInv,
407 interface::vsbpRecordVPD);
Ben Tynere32b7e72021-05-18 12:38:40 -0500408 if (!service.empty())
409 {
410 DBusValue value;
411 getProperty(service, object_path::motherBoardInv,
412 interface::vsbpRecordVPD, "IM", value);
413
414 systemIM = std::get<std::vector<uint8_t>>(value);
415 }
416 }
417 catch (const std::exception& e)
418 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500419 lg2::warning("Failed reading System IM property from "
420 "interface: {IFACE} exception: {ERROR}",
421 "IFACE", interface::vsbpRecordVPD, "ERROR", e);
Ben Tynere32b7e72021-05-18 12:38:40 -0500422 }
423
424 return systemIM;
425}
426
Matt Spinler60c4e792020-03-13 13:45:36 -0500427void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500428 std::string& fruPartNumber,
429 std::string& ccin,
430 std::string& serialNumber) const
431{
432 // For now, attempt to get all of the properties directly on the path
433 // passed in. In the future, may need to make use of an algorithm
434 // to figure out which inventory objects actually hold these
435 // interfaces in the case of non FRUs, or possibly another service
436 // will provide this info. Any missing interfaces will result
437 // in exceptions being thrown.
438
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500439 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500440
Patrick Williams2544b412022-10-04 08:41:06 -0500441 auto properties = getAllProperties(service, inventoryPath,
442 interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500443
444 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
445 fruPartNumber = std::string{value.begin(), value.end()};
446
447 value = std::get<std::vector<uint8_t>>(properties["CC"]);
448 ccin = std::string{value.begin(), value.end()};
449
450 value = std::get<std::vector<uint8_t>>(properties["SN"]);
451 serialNumber = std::string{value.begin(), value.end()};
452}
453
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500454std::string
455 DataInterface::getLocationCode(const std::string& inventoryPath) const
456{
457 auto service = getService(inventoryPath, interface::locCode);
458
459 DBusValue locCode;
460 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
461 locCode);
462
463 return std::get<std::string>(locCode);
464}
465
Matt Spinler5fb24c12020-06-04 11:21:33 -0500466std::string
467 DataInterface::addLocationCodePrefix(const std::string& locationCode)
468{
469 static const std::string locationCodePrefix{"Ufcs-"};
470
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500471 // Technically there are 2 location code prefixes, Ufcs and Umts, so
472 // if it already starts with a U then don't need to do anything.
473 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500474 {
475 return locationCodePrefix + locationCode;
476 }
477
478 return locationCode;
479}
480
481std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500482 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500483{
Matt Spinler0d92b522021-06-16 13:28:17 -0600484 // Location codes for connectors are the location code of the FRU they are
485 // on, plus a '-Tx' segment. Remove this last segment before expanding it
486 // and then add it back in afterwards. This way, the connector doesn't have
487 // to be in the model just so that it can be expanded.
488 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
489
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500490 auto method =
491 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
492 interface::vpdManager, "GetExpandedLocationCode");
493
Matt Spinler0d92b522021-06-16 13:28:17 -0600494 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500495
Matt Spinler35a405b2022-03-02 11:42:42 -0600496 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500497
498 std::string expandedLocationCode;
499 reply.read(expandedLocationCode);
500
Matt Spinler0d92b522021-06-16 13:28:17 -0600501 if (!connectorLoc.empty())
502 {
503 expandedLocationCode += connectorLoc;
504 }
505
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500506 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500507}
508
Matt Spinlerbad056b2023-01-25 14:16:57 -0600509std::vector<std::string>
Matt Spinler2f9225a2020-08-05 12:58:49 -0500510 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
511 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500512{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500513 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
514 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500515
Matt Spinler0d92b522021-06-16 13:28:17 -0600516 // Remove the connector segment, if present, so that this method call
517 // returns an inventory path that getHWCalloutFields() can be used with.
518 // (The serial number, etc, aren't stored on the connector in the
519 // inventory, and may not even be modeled.)
520 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
521
Matt Spinler2f9225a2020-08-05 12:58:49 -0500522 auto method =
523 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
524 interface::vpdManager, methodName.c_str());
525
526 if (expanded)
527 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600528 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500529 }
530 else
531 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600532 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500533 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500534
Matt Spinler35a405b2022-03-02 11:42:42 -0600535 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500536
537 std::vector<sdbusplus::message::object_path> entries;
538 reply.read(entries);
539
Matt Spinlerbad056b2023-01-25 14:16:57 -0600540 std::vector<std::string> paths;
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500541
Matt Spinlerbad056b2023-01-25 14:16:57 -0600542 // Note: The D-Bus method will fail if nothing found.
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500543 std::for_each(entries.begin(), entries.end(),
Matt Spinlerbad056b2023-01-25 14:16:57 -0600544 [&paths](const auto& path) { paths.push_back(path); });
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500545
Matt Spinlerbad056b2023-01-25 14:16:57 -0600546 return paths;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500547}
548
Matt Spinler34a904c2020-08-05 14:53:28 -0500549void DataInterface::assertLEDGroup(const std::string& ledGroup,
550 bool value) const
551{
552 DBusValue variant = value;
Patrick Williams2544b412022-10-04 08:41:06 -0500553 auto method = _bus.new_method_call(service_name::ledGroupManager,
554 ledGroup.c_str(),
555 interface::dbusProperty, "Set");
Matt Spinler34a904c2020-08-05 14:53:28 -0500556 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600557 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500558}
559
Matt Spinler993168d2021-04-07 16:05:03 -0500560void DataInterface::setFunctional(const std::string& objectPath,
561 bool value) const
562{
563 DBusValue variant = value;
564 auto service = getService(objectPath, interface::operationalStatus);
565
566 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
567 interface::dbusProperty, "Set");
568
569 method.append(interface::operationalStatus, "Functional", variant);
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();
928 }) == interfaces.end())
929 {
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 Spinler5ee36052023-05-30 14:20:56 -0500978 locCode = getLocationCode(path);
Matt Spinler5b423652023-05-04 13:08:44 -0500979 }
Matt Spinler5ee36052023-05-30 14:20:56 -0500980 catch (const sdbusplus::exception_t& e)
Matt Spinler5b423652023-05-04 13:08:44 -0500981 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500982 lg2::debug("Could not get location code for {PATH}: {ERROR}", "PATH",
983 path, "ERROR", e);
Matt Spinler5ee36052023-05-30 14:20:56 -0500984 return;
Matt Spinler5b423652023-05-04 13:08:44 -0500985 }
Matt Spinler5ee36052023-05-30 14:20:56 -0500986
Matt Spinlera167a7d2023-06-30 15:14:25 -0500987 lg2::debug("Detected FRU {PATH} ({LOC}) present ", "PATH", path, "LOC",
988 locCode);
Matt Spinler5ee36052023-05-30 14:20:56 -0500989
990 // Tell the subscribers.
991 setFruPresent(locCode);
Matt Spinler5b423652023-05-04 13:08:44 -0500992}
Matt Spinlerc8705e22019-09-11 12:36:07 -0500993} // namespace pels
994} // namespace openpower