blob: c9a944ce7ec646dfdc0cff96b9176502b25ae59f [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 Spinlerbbc11ef2024-01-11 16:26:51 -060045constexpr auto entityManager = "xyz.openbmc_project.EntityManager";
Matt Spinlerc8705e22019-09-11 12:36:07 -050046} // namespace service_name
47
48namespace object_path
49{
50constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
51constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050052constexpr auto motherBoardInv =
53 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060054constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060055constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
56constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060057constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060058constexpr auto enableHostPELs =
59 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050060constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050061constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050062constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Matt Spinler744d8512022-06-08 08:25:47 -050063constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050064constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0";
Matt Spinlerc8705e22019-09-11 12:36:07 -050065} // namespace object_path
66
67namespace interface
68{
69constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
70constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
71constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060072constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060073constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060074constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
75constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
76constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060077constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050078constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060079constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050080constexpr auto compatible =
Matt Spinlerbbc11ef2024-01-11 16:26:51 -060081 "xyz.openbmc_project.Inventory.Decorator.Compatible";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050082constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050083constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050084constexpr auto operationalStatus =
85 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050086constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060087constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050088constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
89constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050090constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar027bf282022-01-24 11:25:19 -060091constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
92constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -050093constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050094constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler5b423652023-05-04 13:08:44 -050095constexpr auto invItem = "xyz.openbmc_project.Inventory.Item";
96constexpr auto invFan = "xyz.openbmc_project.Inventory.Item.Fan";
97constexpr auto invPowerSupply =
98 "xyz.openbmc_project.Inventory.Item.PowerSupply";
Matt Spinler412f50e2023-11-14 12:49:52 -060099constexpr auto inventoryManager = "xyz.openbmc_project.Inventory.Manager";
Matt Spinlerc8705e22019-09-11 12:36:07 -0500100} // namespace interface
101
Willy Tu6ddbf692023-09-05 10:54:16 -0700102using namespace sdbusplus::server::xyz::openbmc_project::state::boot;
103using namespace sdbusplus::server::xyz::openbmc_project::state;
Matt Spinler5b423652023-05-04 13:08:44 -0500104namespace match_rules = sdbusplus::bus::match::rules;
105
106const DBusInterfaceList hotplugInterfaces{interface::invFan,
107 interface::invPowerSupply};
Matt Spinlera7d9d962019-11-06 15:01:25 -0600108
Matt Spinler0d92b522021-06-16 13:28:17 -0600109std::pair<std::string, std::string>
110 DataInterfaceBase::extractConnectorFromLocCode(
111 const std::string& locationCode)
112{
113 auto base = locationCode;
114 std::string connector{};
115
116 auto pos = base.find("-T");
117 if (pos != std::string::npos)
118 {
119 connector = base.substr(pos);
120 base = base.substr(0, pos);
121 }
122
123 return {base, connector};
124}
125
Patrick Williams45e83522022-07-22 19:26:52 -0500126DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus)
Matt Spinlerc8705e22019-09-11 12:36:07 -0500127{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600128 readBMCFWVersion();
129 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600130 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600131
Matt Spinlerf10068d2020-12-02 10:44:08 -0600132 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600133 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600134 bus, object_path::hostState, interface::bootProgress, "BootProgress",
135 *this, [this](const auto& value) {
Patrick Williams5fb575a2023-10-20 11:18:21 -0500136 this->_bootState = std::get<std::string>(value);
137 auto status = Progress::convertProgressStagesFromString(
138 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600139
Patrick Williams5fb575a2023-10-20 11:18:21 -0500140 if ((status == Progress::ProgressStages::SystemInitComplete) ||
141 (status == Progress::ProgressStages::OSRunning))
142 {
143 setHostUp(true);
144 }
145 else
146 {
147 setHostUp(false);
148 }
149 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600150
151 // Watch the host PEL enable property
152 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
153 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
154 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500155 if (std::get<bool>(value) != this->_sendPELsToHost)
156 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500157 lg2::info("The send PELs to host setting changed to {VAL}", "VAL",
158 std::get<bool>(value));
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500159 }
160 this->_sendPELsToHost = std::get<bool>(value);
Patrick Williams5fb575a2023-10-20 11:18:21 -0500161 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600162
163 // Watch the BMCState property
164 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
165 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
166 *this, [this](const auto& value) {
Patrick Williams5fb575a2023-10-20 11:18:21 -0500167 const auto& state = std::get<std::string>(value);
168 this->_bmcState = state;
Matt Spinler5b423652023-05-04 13:08:44 -0500169
Patrick Williams5fb575a2023-10-20 11:18:21 -0500170 // Wait for BMC ready to start watching for
171 // plugs so things calm down first.
172 if (BMC::convertBMCStateFromString(state) == BMC::BMCState::Ready)
173 {
174 startFruPlugWatch();
175 }
176 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600177
178 // Watch the chassis current and requested power state properties
179 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
180 bus, object_path::chassisState, interface::chassisState, *this,
181 [this](const auto& properties) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500182 auto state = properties.find("CurrentPowerState");
183 if (state != properties.end())
184 {
185 this->_chassisState = std::get<std::string>(state->second);
186 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600187
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500188 auto trans = properties.find("RequestedPowerTransition");
189 if (trans != properties.end())
190 {
191 this->_chassisTransition = std::get<std::string>(trans->second);
192 }
Patrick Williams5fb575a2023-10-20 11:18:21 -0500193 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600194
195 // Watch the CurrentHostState property
196 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
197 bus, object_path::hostState, interface::hostState, "CurrentHostState",
198 *this, [this](const auto& value) {
Patrick Williams5fb575a2023-10-20 11:18:21 -0500199 this->_hostState = std::get<std::string>(value);
200 }));
Matt Spinler744d8512022-06-08 08:25:47 -0500201
202 // Watch the BaseBIOSTable property for the hmc managed attribute
203 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
204 bus, object_path::biosConfigMgr, interface::biosConfigMgr,
205 "BaseBIOSTable", service_name::biosConfigMgr, *this,
206 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500207 const auto& attributes = std::get<BiosAttributes>(value);
Matt Spinler744d8512022-06-08 08:25:47 -0500208
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500209 auto it = attributes.find("pvm_hmc_managed");
210 if (it != attributes.end())
211 {
212 const auto& currentValVariant = std::get<5>(it->second);
213 auto currentVal = std::get_if<std::string>(&currentValVariant);
214 if (currentVal)
Matt Spinler744d8512022-06-08 08:25:47 -0500215 {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500216 this->_hmcManaged = (*currentVal == "Enabled") ? true : false;
Matt Spinler744d8512022-06-08 08:25:47 -0500217 }
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500218 }
Patrick Williams5fb575a2023-10-20 11:18:21 -0500219 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500220}
221
Matt Spinler2a28c932020-02-03 14:23:40 -0600222DBusPropertyMap
223 DataInterface::getAllProperties(const std::string& service,
224 const std::string& objectPath,
225 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500226{
227 DBusPropertyMap properties;
228
229 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
230 interface::dbusProperty, "GetAll");
231 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600232 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500233
234 reply.read(properties);
235
236 return properties;
237}
238
Matt Spinlera7d9d962019-11-06 15:01:25 -0600239void DataInterface::getProperty(const std::string& service,
240 const std::string& objectPath,
241 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600242 const std::string& property,
243 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600244{
Matt Spinlera7d9d962019-11-06 15:01:25 -0600245 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
246 interface::dbusProperty, "Get");
247 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600248 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600249
250 reply.read(value);
251}
252
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600253DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
254{
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600255 auto method = _bus.new_method_call(
256 service_name::objectMapper, object_path::objectMapper,
257 interface::objectMapper, "GetSubTreePaths");
258
259 method.append(std::string{"/"}, 0, interfaces);
260
Matt Spinler35a405b2022-03-02 11:42:42 -0600261 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600262
263 DBusPathList paths;
264 reply.read(paths);
265
266 return paths;
267}
268
Matt Spinlerc8705e22019-09-11 12:36:07 -0500269DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600270 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500271{
272 auto method = _bus.new_method_call(service_name::objectMapper,
273 object_path::objectMapper,
274 interface::objectMapper, "GetObject");
275
276 method.append(objectPath, std::vector<std::string>({interface}));
277
Matt Spinler35a405b2022-03-02 11:42:42 -0600278 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500279
280 std::map<DBusService, DBusInterfaceList> response;
281 reply.read(response);
282
283 if (!response.empty())
284 {
285 return response.begin()->first;
286 }
287
288 return std::string{};
289}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600290
Matt Spinler677381b2020-01-23 10:04:29 -0600291void DataInterface::readBMCFWVersion()
292{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500293 _bmcFWVersion =
294 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600295}
296
297void DataInterface::readServerFWVersion()
298{
Sumit Kumarcad16202021-05-13 04:06:15 -0500299 auto value =
300 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
301 if ((value != "") && (value.find_last_of(')') != std::string::npos))
302 {
303 std::size_t pos = value.find_first_of('(') + 1;
304 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
305 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600306}
307
Matt Spinler677381b2020-01-23 10:04:29 -0600308void DataInterface::readBMCFWVersionID()
309{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500310 _bmcFWVersionID =
311 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600312}
313
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500314std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600315{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500316 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600317 try
318 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500319 auto service = getService(object_path::systemInv, interface::invAsset);
320 if (!service.empty())
321 {
322 DBusValue value;
323 getProperty(service, object_path::systemInv, interface::invAsset,
324 "Model", value);
325
326 model = std::get<std::string>(value);
327 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600328 }
329 catch (const std::exception& e)
330 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500331 lg2::warning("Failed reading Model property from "
332 "interface: {IFACE} exception: {ERROR}",
333 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600334 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500335
336 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600337}
338
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500339std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600340{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500341 std::string sn;
342 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600343 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500344 auto service = getService(object_path::systemInv, interface::invAsset);
345 if (!service.empty())
346 {
347 DBusValue value;
348 getProperty(service, object_path::systemInv, interface::invAsset,
349 "SerialNumber", value);
350
351 sn = std::get<std::string>(value);
352 }
353 }
354 catch (const std::exception& e)
355 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500356 lg2::warning("Failed reading SerialNumber property from "
357 "interface: {IFACE} exception: {ERROR}",
358 "IFACE", interface::invAsset, "ERROR", e);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600359 }
360
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500361 return sn;
362}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600363
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500364std::string DataInterface::getMotherboardCCIN() const
365{
366 std::string ccin;
367
368 try
369 {
Patrick Williams2544b412022-10-04 08:41:06 -0500370 auto service = getService(object_path::motherBoardInv,
371 interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500372 if (!service.empty())
373 {
374 DBusValue value;
375 getProperty(service, object_path::motherBoardInv,
376 interface::viniRecordVPD, "CC", value);
377
378 auto cc = std::get<std::vector<uint8_t>>(value);
379 ccin = std::string{cc.begin(), cc.end()};
380 }
381 }
382 catch (const std::exception& e)
383 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500384 lg2::warning("Failed reading Motherboard CCIN property from "
385 "interface: {IFACE} exception: {ERROR}",
386 "IFACE", interface::viniRecordVPD, "ERROR", e);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500387 }
388
389 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600390}
391
Ben Tynere32b7e72021-05-18 12:38:40 -0500392std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
393{
394 std::vector<uint8_t> systemIM;
395
396 try
397 {
Patrick Williams2544b412022-10-04 08:41:06 -0500398 auto service = getService(object_path::motherBoardInv,
399 interface::vsbpRecordVPD);
Ben Tynere32b7e72021-05-18 12:38:40 -0500400 if (!service.empty())
401 {
402 DBusValue value;
403 getProperty(service, object_path::motherBoardInv,
404 interface::vsbpRecordVPD, "IM", value);
405
406 systemIM = std::get<std::vector<uint8_t>>(value);
407 }
408 }
409 catch (const std::exception& e)
410 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500411 lg2::warning("Failed reading System IM property from "
412 "interface: {IFACE} exception: {ERROR}",
413 "IFACE", interface::vsbpRecordVPD, "ERROR", e);
Ben Tynere32b7e72021-05-18 12:38:40 -0500414 }
415
416 return systemIM;
417}
418
Matt Spinler60c4e792020-03-13 13:45:36 -0500419void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500420 std::string& fruPartNumber,
421 std::string& ccin,
422 std::string& serialNumber) const
423{
424 // For now, attempt to get all of the properties directly on the path
425 // passed in. In the future, may need to make use of an algorithm
426 // to figure out which inventory objects actually hold these
427 // interfaces in the case of non FRUs, or possibly another service
428 // will provide this info. Any missing interfaces will result
429 // in exceptions being thrown.
430
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500431 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500432
Patrick Williams2544b412022-10-04 08:41:06 -0500433 auto properties = getAllProperties(service, inventoryPath,
434 interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500435
436 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
437 fruPartNumber = std::string{value.begin(), value.end()};
438
439 value = std::get<std::vector<uint8_t>>(properties["CC"]);
440 ccin = std::string{value.begin(), value.end()};
441
442 value = std::get<std::vector<uint8_t>>(properties["SN"]);
443 serialNumber = std::string{value.begin(), value.end()};
444}
445
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500446std::string
447 DataInterface::getLocationCode(const std::string& inventoryPath) const
448{
449 auto service = getService(inventoryPath, interface::locCode);
450
451 DBusValue locCode;
452 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
453 locCode);
454
455 return std::get<std::string>(locCode);
456}
457
Matt Spinler5fb24c12020-06-04 11:21:33 -0500458std::string
459 DataInterface::addLocationCodePrefix(const std::string& locationCode)
460{
461 static const std::string locationCodePrefix{"Ufcs-"};
462
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500463 // Technically there are 2 location code prefixes, Ufcs and Umts, so
464 // if it already starts with a U then don't need to do anything.
465 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500466 {
467 return locationCodePrefix + locationCode;
468 }
469
470 return locationCode;
471}
472
473std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500474 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500475{
Matt Spinler0d92b522021-06-16 13:28:17 -0600476 // Location codes for connectors are the location code of the FRU they are
477 // on, plus a '-Tx' segment. Remove this last segment before expanding it
478 // and then add it back in afterwards. This way, the connector doesn't have
479 // to be in the model just so that it can be expanded.
480 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
481
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500482 auto method =
483 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
484 interface::vpdManager, "GetExpandedLocationCode");
485
Matt Spinler0d92b522021-06-16 13:28:17 -0600486 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500487
Matt Spinler35a405b2022-03-02 11:42:42 -0600488 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500489
490 std::string expandedLocationCode;
491 reply.read(expandedLocationCode);
492
Matt Spinler0d92b522021-06-16 13:28:17 -0600493 if (!connectorLoc.empty())
494 {
495 expandedLocationCode += connectorLoc;
496 }
497
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500498 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500499}
500
Matt Spinlerbad056b2023-01-25 14:16:57 -0600501std::vector<std::string>
Matt Spinler2f9225a2020-08-05 12:58:49 -0500502 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
503 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500504{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500505 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
506 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500507
Matt Spinler0d92b522021-06-16 13:28:17 -0600508 // Remove the connector segment, if present, so that this method call
509 // returns an inventory path that getHWCalloutFields() can be used with.
510 // (The serial number, etc, aren't stored on the connector in the
511 // inventory, and may not even be modeled.)
512 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
513
Matt Spinler2f9225a2020-08-05 12:58:49 -0500514 auto method =
515 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
516 interface::vpdManager, methodName.c_str());
517
518 if (expanded)
519 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600520 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500521 }
522 else
523 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600524 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500525 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500526
Matt Spinler35a405b2022-03-02 11:42:42 -0600527 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500528
529 std::vector<sdbusplus::message::object_path> entries;
530 reply.read(entries);
531
Matt Spinlerbad056b2023-01-25 14:16:57 -0600532 std::vector<std::string> paths;
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500533
Matt Spinlerbad056b2023-01-25 14:16:57 -0600534 // Note: The D-Bus method will fail if nothing found.
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500535 std::for_each(entries.begin(), entries.end(),
Matt Spinlerbad056b2023-01-25 14:16:57 -0600536 [&paths](const auto& path) { paths.push_back(path); });
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500537
Matt Spinlerbad056b2023-01-25 14:16:57 -0600538 return paths;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500539}
540
Matt Spinler34a904c2020-08-05 14:53:28 -0500541void DataInterface::assertLEDGroup(const std::string& ledGroup,
542 bool value) const
543{
544 DBusValue variant = value;
Patrick Williams2544b412022-10-04 08:41:06 -0500545 auto method = _bus.new_method_call(service_name::ledGroupManager,
546 ledGroup.c_str(),
547 interface::dbusProperty, "Set");
Matt Spinler34a904c2020-08-05 14:53:28 -0500548 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600549 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500550}
551
Matt Spinler993168d2021-04-07 16:05:03 -0500552void DataInterface::setFunctional(const std::string& objectPath,
553 bool value) const
554{
Matt Spinler412f50e2023-11-14 12:49:52 -0600555 DBusPropertyMap prop{{"Functional", value}};
556 DBusInterfaceMap iface{{interface::operationalStatus, prop}};
Matt Spinler993168d2021-04-07 16:05:03 -0500557
Matt Spinler412f50e2023-11-14 12:49:52 -0600558 // PIM takes a relative path like /system/chassis so remove
559 // /xyz/openbmc_project/inventory if present.
560 std::string path{objectPath};
561 if (path.starts_with(object_path::baseInv))
562 {
563 path = objectPath.substr(strlen(object_path::baseInv));
564 }
565 DBusObjectMap object{{path, iface}};
Matt Spinler993168d2021-04-07 16:05:03 -0500566
Matt Spinler412f50e2023-11-14 12:49:52 -0600567 auto method = _bus.new_method_call(service_name::inventoryManager,
568 object_path::baseInv,
569 interface::inventoryManager, "Notify");
570 method.append(std::move(object));
Matt Spinler35a405b2022-03-02 11:42:42 -0600571 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500572}
573
Sumit Kumar76198a22021-07-15 05:59:57 -0500574using AssociationTuple = std::tuple<std::string, std::string, std::string>;
575using AssociationsProperty = std::vector<AssociationTuple>;
576
577void DataInterface::setCriticalAssociation(const std::string& objectPath) const
578{
579 DBusValue getAssociationValue;
580
Sumit Kumar027bf282022-01-24 11:25:19 -0600581 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500582
Sumit Kumar027bf282022-01-24 11:25:19 -0600583 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500584 getAssociationValue);
585
586 auto association = std::get<AssociationsProperty>(getAssociationValue);
587
588 AssociationTuple critAssociation{
589 "health_rollup", "critical",
590 "/xyz/openbmc_project/inventory/system/chassis"};
591
592 if (std::find(association.begin(), association.end(), critAssociation) ==
593 association.end())
594 {
595 association.push_back(critAssociation);
596 DBusValue setAssociationValue = association;
597
598 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
599 interface::dbusProperty, "Set");
600
Sumit Kumar027bf282022-01-24 11:25:19 -0600601 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500602 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600603 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500604 }
605}
606
Matt Spinler1ab66962020-10-29 13:21:44 -0500607std::vector<std::string> DataInterface::getSystemNames() const
608{
609 DBusSubTree subtree;
610 DBusValue names;
611
612 auto method = _bus.new_method_call(service_name::objectMapper,
613 object_path::objectMapper,
614 interface::objectMapper, "GetSubTree");
615 method.append(std::string{"/"}, 0,
616 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600617 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500618
619 reply.read(subtree);
620 if (subtree.empty())
621 {
622 throw std::runtime_error("Compatible interface not on D-Bus");
623 }
624
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600625 for (const auto& [path, interfaceMap] : subtree)
626 {
627 auto iface = interfaceMap.find(service_name::entityManager);
628 if (iface == interfaceMap.end())
629 {
630 continue;
631 }
Matt Spinler1ab66962020-10-29 13:21:44 -0500632
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600633 getProperty(iface->first, path, interface::compatible, "Names", names);
Matt Spinler1ab66962020-10-29 13:21:44 -0500634
Matt Spinlerbbc11ef2024-01-11 16:26:51 -0600635 return std::get<std::vector<std::string>>(names);
636 }
637
638 throw std::runtime_error("EM Compatible interface not on D-Bus");
Matt Spinler1ab66962020-10-29 13:21:44 -0500639}
640
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500641bool DataInterface::getQuiesceOnError() const
642{
643 bool ret = false;
644
645 try
646 {
Patrick Williams2544b412022-10-04 08:41:06 -0500647 auto service = getService(object_path::logSetting,
648 interface::logSetting);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500649 if (!service.empty())
650 {
651 DBusValue value;
652 getProperty(service, object_path::logSetting, interface::logSetting,
653 "QuiesceOnHwError", value);
654
655 ret = std::get<bool>(value);
656 }
657 }
658 catch (const std::exception& e)
659 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500660 lg2::warning("Failed reading QuiesceOnHwError property from "
661 "interface: {IFACE} exception: {ERROR}",
662 "IFACE", interface::logSetting, "ERROR", e);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500663 }
664
665 return ret;
666}
667
Sumit Kumar9d43a722021-08-24 09:46:19 -0500668std::vector<bool>
669 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
670{
671 DBusSubTree subtree;
672 std::vector<bool> result(type.size(), false);
673
674 // Query GetSubTree for the availability of dump interface
675 auto method = _bus.new_method_call(service_name::objectMapper,
676 object_path::objectMapper,
677 interface::objectMapper, "GetSubTree");
678 method.append(std::string{"/"}, 0,
679 std::vector<std::string>{interface::dumpEntry});
Matt Spinler35a405b2022-03-02 11:42:42 -0600680 auto reply = _bus.call(method, dbusTimeout);
Sumit Kumar9d43a722021-08-24 09:46:19 -0500681
682 reply.read(subtree);
683
684 if (subtree.empty())
685 {
686 return result;
687 }
688
689 std::vector<bool>::iterator itDumpStatus = result.begin();
690 uint8_t count = 0;
691 for (const auto& [path, serviceInfo] : subtree)
692 {
693 const auto& service = serviceInfo.begin()->first;
694 // Check for dump type on the object path
695 for (const auto& it : type)
696 {
697 if (path.find(it) != std::string::npos)
698 {
699 DBusValue value, progress;
700
701 // If dump type status is already available go for next path
702 if (*itDumpStatus)
703 {
704 break;
705 }
706
707 // Check for valid dump to be available if following
708 // conditions are met for the dump entry path -
709 // Offloaded == false and Status == Completed
710 getProperty(service, path, interface::dumpEntry, "Offloaded",
711 value);
712 getProperty(service, path, interface::dumpProgress, "Status",
713 progress);
714 auto offload = std::get<bool>(value);
715 auto status = std::get<std::string>(progress);
716 if (!offload && (status.find("Completed") != std::string::npos))
717 {
718 *itDumpStatus = true;
719 count++;
720 if (count >= type.size())
721 {
722 return result;
723 }
724 break;
725 }
726 }
Matt Spinler45796e82022-07-01 11:25:27 -0500727 ++itDumpStatus;
Sumit Kumar9d43a722021-08-24 09:46:19 -0500728 }
729 itDumpStatus = result.begin();
730 }
731
732 return result;
733}
734
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500735void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
736 const std::string& type,
737 const std::string& logPath) const
738{
739 try
740 {
741 auto method = _bus.new_method_call(
742 service_name::hwIsolation, object_path::hwIsolation,
743 interface::hwIsolationCreate, "CreateWithEntityPath");
744 method.append(binPath, type, sdbusplus::message::object_path(logPath));
745 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
746 // api's. Making d-bus call no reply type to avoid cyclic dependency.
747 // Added minimal timeout to catch initial failures.
748 // Need to revisit this design later to avoid cyclic dependency.
Matt Spinler35a405b2022-03-02 11:42:42 -0600749 constexpr auto hwIsolationTimeout = 100000; // in micro seconds
750 _bus.call_noreply(method, hwIsolationTimeout);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500751 }
752
Patrick Williams45e83522022-07-22 19:26:52 -0500753 catch (const sdbusplus::exception_t& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500754 {
755 std::string errName = e.name();
756 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
757 // mentioned above. Ignoring the error.
758 if (errName != SD_BUS_ERROR_TIMEOUT)
759 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500760 lg2::error("GUARD D-Bus call exception. Path={PATH}, "
761 "interface = {IFACE}, exception = {ERROR}",
762 "PATH", object_path::hwIsolation, "IFACE",
763 interface::hwIsolationCreate, "ERROR", e);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500764 }
765 }
766}
Sumit Kumar3e274432021-09-14 06:37:56 -0500767
768void DataInterface::createProgressSRC(
769 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
770{
771 DBusValue variant = std::make_tuple(priSRC, srcStruct);
772
773 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500774 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500775 interface::dbusProperty, "Set");
776
777 method.append(interface::bootRawProgress, "Value", variant);
778
Matt Spinler35a405b2022-03-02 11:42:42 -0600779 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500780}
Sumit Kumar027bf282022-01-24 11:25:19 -0600781
782std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
783{
784 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
785 std::string hwErrorLog = "/isolated_hw_errorlog";
786 std::string errorLog = "/error_log";
787 DBusPathList paths;
788 std::vector<uint32_t> ids;
789
790 // Get all latest mapper associations
791 paths = getPaths(association);
792 for (auto& path : paths)
793 {
794 // Look for object path with hardware isolation entry if any
795 size_t pos = path.find(hwErrorLog);
796 if (pos != std::string::npos)
797 {
798 // Get the object path
799 std::string ph = path;
800 ph.erase(pos, hwErrorLog.length());
801 auto service = getService(ph, interface::hwIsolationEntry);
802 if (!service.empty())
803 {
804 bool status;
805 DBusValue value;
806
807 // Read the Resolved property from object path
808 getProperty(service, ph, interface::hwIsolationEntry,
809 "Resolved", value);
810
811 status = std::get<bool>(value);
812
813 // If the entry isn't resolved
814 if (!status)
815 {
Patrick Williams2544b412022-10-04 08:41:06 -0500816 auto assocService = getService(path,
817 interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500818 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600819 {
Matt Spinler45796e82022-07-01 11:25:27 -0500820 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600821
822 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500823 getProperty(assocService, path, interface::association,
824 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600825
826 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500827 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600828 if (!logPath.empty())
829 {
830 // Get OpenBMC event log Id
831 uint32_t id = stoi(logPath[0].substr(
832 logPath[0].find_last_of('/') + 1));
833 ids.push_back(id);
834 }
835 }
836 }
837 }
838 }
839
840 // Look for object path with error_log entry if any
841 pos = path.find(errorLog);
842 if (pos != std::string::npos)
843 {
844 auto service = getService(path, interface::association);
845 if (!service.empty())
846 {
847 DBusValue value;
848
849 // Read Endpoints property
850 getProperty(service, path, interface::association, "endpoints",
851 value);
852
853 auto logPath = std::get<std::vector<std::string>>(value);
854 if (!logPath.empty())
855 {
856 // Get OpenBMC event log Id
857 uint32_t id = stoi(
858 logPath[0].substr(logPath[0].find_last_of('/') + 1));
859 ids.push_back(id);
860 }
861 }
862 }
863 }
864
865 if (ids.size() > 1)
866 {
867 // remove duplicates to have only unique ids
868 std::sort(ids.begin(), ids.end());
869 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
870 }
871 return ids;
872}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500873
874std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
875{
876 using RawProgressProperty = std::tuple<uint64_t, std::vector<uint8_t>>;
877
878 DBusValue value;
879 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
880 interface::bootRawProgress, "Value", value);
881
882 const auto& rawProgress = std::get<RawProgressProperty>(value);
883 return std::get<1>(rawProgress);
884}
885
Matt Spinler5b423652023-05-04 13:08:44 -0500886void DataInterface::startFruPlugWatch()
887{
888 // Add a watch on inventory InterfacesAdded and then find all
889 // existing hotpluggable interfaces and add propertiesChanged
890 // watches on them.
891
892 _invIaMatch = std::make_unique<sdbusplus::bus::match_t>(
893 _bus, match_rules::interfacesAdded(object_path::baseInv),
894 std::bind(&DataInterface::inventoryIfaceAdded, this,
895 std::placeholders::_1));
896 try
897 {
898 auto paths = getPaths(hotplugInterfaces);
899
900 _invPresentMatches.clear();
901
902 std::for_each(paths.begin(), paths.end(),
903 [this](const auto& path) { addHotplugWatch(path); });
904 }
905 catch (const sdbusplus::exception_t& e)
906 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500907 lg2::warning("Failed getting FRU paths to watch: {ERROR}", "ERROR", e);
Matt Spinler5b423652023-05-04 13:08:44 -0500908 }
909}
910
911void DataInterface::addHotplugWatch(const std::string& path)
912{
913 if (!_invPresentMatches.contains(path))
914 {
915 _invPresentMatches.emplace(
916 path,
917 std::make_unique<sdbusplus::bus::match_t>(
918 _bus, match_rules::propertiesChanged(path, interface::invItem),
919 std::bind(&DataInterface::presenceChanged, this,
920 std::placeholders::_1)));
921 }
922}
923
924void DataInterface::inventoryIfaceAdded(sdbusplus::message_t& msg)
925{
926 sdbusplus::message::object_path path;
927 DBusInterfaceMap interfaces;
928
929 msg.read(path, interfaces);
930
931 // Check if any of the new interfaces are for hot pluggable FRUs.
932 if (std::find_if(interfaces.begin(), interfaces.end(),
933 [](const auto& interfacePair) {
934 return std::find(hotplugInterfaces.begin(), hotplugInterfaces.end(),
935 interfacePair.first) != hotplugInterfaces.end();
Patrick Williams5fb575a2023-10-20 11:18:21 -0500936 }) == interfaces.end())
Matt Spinler5b423652023-05-04 13:08:44 -0500937 {
938 return;
939 }
940
941 addHotplugWatch(path.str);
942
943 // If an Inventory.Item interface was also added, check presence now.
944
945 // Notes:
946 // * This assumes the Inv.Item and Inv.Fan/PS are added together which
947 // is currently the case.
948 // * If the code ever switches to something without a Present
949 // property, then the IA signal itself would probably indicate presence.
950
951 auto itemIt = interfaces.find(interface::invItem);
952 if (itemIt != interfaces.end())
953 {
954 notifyPresenceSubsribers(path.str, itemIt->second);
955 }
956}
957
958void DataInterface::presenceChanged(sdbusplus::message_t& msg)
959{
960 DBusInterface interface;
961 DBusPropertyMap properties;
962
963 msg.read(interface, properties);
964 if (interface != interface::invItem)
965 {
966 return;
967 }
968
969 std::string path = msg.get_path();
970 notifyPresenceSubsribers(path, properties);
971}
972
973void DataInterface::notifyPresenceSubsribers(const std::string& path,
974 const DBusPropertyMap& properties)
975{
Matt Spinler5ee36052023-05-30 14:20:56 -0500976 auto prop = properties.find("Present");
977 if ((prop == properties.end()) || (!std::get<bool>(prop->second)))
978 {
979 return;
980 }
981
982 std::string locCode;
983
Matt Spinler5b423652023-05-04 13:08:44 -0500984 try
985 {
Matt Spinler52ee3a42023-07-27 14:54:48 -0500986 auto service = getService(path, interface::locCode);
987
988 // If the hotplugged FRU is hosted by PLDM, then it is
989 // in an IO expansion drawer and we don't care about it.
990 if (service == service_name::pldm)
991 {
992 return;
993 }
994
Matt Spinler5ee36052023-05-30 14:20:56 -0500995 locCode = getLocationCode(path);
Matt Spinler5b423652023-05-04 13:08:44 -0500996 }
Matt Spinler5ee36052023-05-30 14:20:56 -0500997 catch (const sdbusplus::exception_t& e)
Matt Spinler5b423652023-05-04 13:08:44 -0500998 {
Matt Spinlera167a7d2023-06-30 15:14:25 -0500999 lg2::debug("Could not get location code for {PATH}: {ERROR}", "PATH",
1000 path, "ERROR", e);
Matt Spinler5ee36052023-05-30 14:20:56 -05001001 return;
Matt Spinler5b423652023-05-04 13:08:44 -05001002 }
Matt Spinler5ee36052023-05-30 14:20:56 -05001003
Matt Spinlera167a7d2023-06-30 15:14:25 -05001004 lg2::debug("Detected FRU {PATH} ({LOC}) present ", "PATH", path, "LOC",
1005 locCode);
Matt Spinler5ee36052023-05-30 14:20:56 -05001006
1007 // Tell the subscribers.
1008 setFruPresent(locCode);
Matt Spinler5b423652023-05-04 13:08:44 -05001009}
Matt Spinlerc8705e22019-09-11 12:36:07 -05001010} // namespace pels
1011} // namespace openpower