blob: ead3c16e81b3a70930cdff5e5ffb4372d5ee6fc0 [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
Vijay Lobo81b4dca2021-04-29 00:04:00 -050024#include <phosphor-logging/log.hpp>
Matt Spinlerf10068d2020-12-02 10:44:08 -060025#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Matt Spinlera7d9d962019-11-06 15:01:25 -060026
Patrick Williams2544b412022-10-04 08:41:06 -050027#include <fstream>
28#include <iterator>
29
Matt Spinler35a405b2022-03-02 11:42:42 -060030// Use a timeout of 10s for D-Bus calls so if there are
31// timeouts the callers of the PEL creation method won't
32// also timeout.
33constexpr auto dbusTimeout = 10000000;
34
Matt Spinlerc8705e22019-09-11 12:36:07 -050035namespace openpower
36{
37namespace pels
38{
39
40namespace service_name
41{
42constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050043constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050044constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050045constexpr auto logSetting = "xyz.openbmc_project.Settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050046constexpr auto hwIsolation = "org.open_power.HardwareIsolation";
Matt Spinler744d8512022-06-08 08:25:47 -050047constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050048constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinlerc8705e22019-09-11 12:36:07 -050049} // namespace service_name
50
51namespace object_path
52{
53constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
54constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050055constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050056constexpr auto motherBoardInv =
57 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060058constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060059constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
60constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060061constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060062constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060063constexpr auto enableHostPELs =
64 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050065constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050066constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050067constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Matt Spinler744d8512022-06-08 08:25:47 -050068constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -050069constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0";
Matt Spinlerc8705e22019-09-11 12:36:07 -050070} // namespace object_path
71
72namespace interface
73{
74constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
75constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
76constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060077constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinlerb3f51862019-12-09 13:55:10 -060078constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060079constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060080constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
81constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
82constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060083constexpr auto invMotherboard =
84 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
85constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050086constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060087constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050088constexpr auto compatible =
89 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050090constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050091constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050092constexpr auto operationalStatus =
93 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050094constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060095constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050096constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
97constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050098constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar027bf282022-01-24 11:25:19 -060099constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
100constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -0500101constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Vijay Lobo875b6c72021-10-20 17:38:56 -0500102constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinlerc8705e22019-09-11 12:36:07 -0500103} // namespace interface
104
Matt Spinlerf10068d2020-12-02 10:44:08 -0600105using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500106using namespace phosphor::logging;
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) {
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500135 this->_bootState = std::get<std::string>(value);
Matt Spinlerf10068d2020-12-02 10:44:08 -0600136 auto status = Progress::convertProgressStagesFromString(
137 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600138
Matt Spinlerf10068d2020-12-02 10:44:08 -0600139 if ((status == Progress::ProgressStages::SystemInitComplete) ||
Matt Spinlerf10068d2020-12-02 10:44:08 -0600140 (status == Progress::ProgressStages::OSRunning))
Matt Spinler2a28c932020-02-03 14:23:40 -0600141 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600142 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600143 }
144 else
145 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600146 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600147 }
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 {
156 log<level::INFO>(
157 fmt::format("The send PELs to host setting changed to {}",
158 std::get<bool>(value))
159 .c_str());
160 }
161 this->_sendPELsToHost = std::get<bool>(value);
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600162 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600163
164 // Watch the BMCState property
165 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
166 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
167 *this, [this](const auto& value) {
168 this->_bmcState = std::get<std::string>(value);
169 }));
170
171 // Watch the chassis current and requested power state properties
172 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
173 bus, object_path::chassisState, interface::chassisState, *this,
174 [this](const auto& properties) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500175 auto state = properties.find("CurrentPowerState");
176 if (state != properties.end())
177 {
178 this->_chassisState = std::get<std::string>(state->second);
179 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600180
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500181 auto trans = properties.find("RequestedPowerTransition");
182 if (trans != properties.end())
183 {
184 this->_chassisTransition = std::get<std::string>(trans->second);
185 }
Matt Spinler4aa23a12020-02-03 15:05:09 -0600186 }));
187
188 // Watch the CurrentHostState property
189 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
190 bus, object_path::hostState, interface::hostState, "CurrentHostState",
191 *this, [this](const auto& value) {
192 this->_hostState = std::get<std::string>(value);
193 }));
Matt Spinler744d8512022-06-08 08:25:47 -0500194
195 // Watch the BaseBIOSTable property for the hmc managed attribute
196 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
197 bus, object_path::biosConfigMgr, interface::biosConfigMgr,
198 "BaseBIOSTable", service_name::biosConfigMgr, *this,
199 [this](const auto& value) {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500200 const auto& attributes = std::get<BiosAttributes>(value);
Matt Spinler744d8512022-06-08 08:25:47 -0500201
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500202 auto it = attributes.find("pvm_hmc_managed");
203 if (it != attributes.end())
204 {
205 const auto& currentValVariant = std::get<5>(it->second);
206 auto currentVal = std::get_if<std::string>(&currentValVariant);
207 if (currentVal)
Matt Spinler744d8512022-06-08 08:25:47 -0500208 {
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500209 this->_hmcManaged = (*currentVal == "Enabled") ? true : false;
Matt Spinler744d8512022-06-08 08:25:47 -0500210 }
Patrick Williamsac1ba3f2023-05-10 07:50:16 -0500211 }
Matt Spinler744d8512022-06-08 08:25:47 -0500212 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500213}
214
Matt Spinler2a28c932020-02-03 14:23:40 -0600215DBusPropertyMap
216 DataInterface::getAllProperties(const std::string& service,
217 const std::string& objectPath,
218 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500219{
220 DBusPropertyMap properties;
221
222 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
223 interface::dbusProperty, "GetAll");
224 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600225 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500226
227 reply.read(properties);
228
229 return properties;
230}
231
Matt Spinlera7d9d962019-11-06 15:01:25 -0600232void DataInterface::getProperty(const std::string& service,
233 const std::string& objectPath,
234 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600235 const std::string& property,
236 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600237{
Matt Spinlera7d9d962019-11-06 15:01:25 -0600238 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
239 interface::dbusProperty, "Get");
240 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600241 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600242
243 reply.read(value);
244}
245
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600246DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
247{
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600248 auto method = _bus.new_method_call(
249 service_name::objectMapper, object_path::objectMapper,
250 interface::objectMapper, "GetSubTreePaths");
251
252 method.append(std::string{"/"}, 0, interfaces);
253
Matt Spinler35a405b2022-03-02 11:42:42 -0600254 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600255
256 DBusPathList paths;
257 reply.read(paths);
258
259 return paths;
260}
261
Matt Spinlerc8705e22019-09-11 12:36:07 -0500262DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600263 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500264{
265 auto method = _bus.new_method_call(service_name::objectMapper,
266 object_path::objectMapper,
267 interface::objectMapper, "GetObject");
268
269 method.append(objectPath, std::vector<std::string>({interface}));
270
Matt Spinler35a405b2022-03-02 11:42:42 -0600271 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500272
273 std::map<DBusService, DBusInterfaceList> response;
274 reply.read(response);
275
276 if (!response.empty())
277 {
278 return response.begin()->first;
279 }
280
281 return std::string{};
282}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600283
Matt Spinler677381b2020-01-23 10:04:29 -0600284void DataInterface::readBMCFWVersion()
285{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500286 _bmcFWVersion =
287 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600288}
289
290void DataInterface::readServerFWVersion()
291{
Sumit Kumarcad16202021-05-13 04:06:15 -0500292 auto value =
293 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
294 if ((value != "") && (value.find_last_of(')') != std::string::npos))
295 {
296 std::size_t pos = value.find_first_of('(') + 1;
297 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
298 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600299}
300
Matt Spinler677381b2020-01-23 10:04:29 -0600301void DataInterface::readBMCFWVersionID()
302{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500303 _bmcFWVersionID =
304 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600305}
306
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500307std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600308{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500309 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600310 try
311 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500312 auto service = getService(object_path::systemInv, interface::invAsset);
313 if (!service.empty())
314 {
315 DBusValue value;
316 getProperty(service, object_path::systemInv, interface::invAsset,
317 "Model", value);
318
319 model = std::get<std::string>(value);
320 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600321 }
322 catch (const std::exception& e)
323 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500324 log<level::WARNING>(fmt::format("Failed reading Model property from "
325 "Interface: {} exception: {}",
326 interface::invAsset, e.what())
327 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600328 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500329
330 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600331}
332
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500333std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600334{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500335 std::string sn;
336 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600337 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500338 auto service = getService(object_path::systemInv, interface::invAsset);
339 if (!service.empty())
340 {
341 DBusValue value;
342 getProperty(service, object_path::systemInv, interface::invAsset,
343 "SerialNumber", value);
344
345 sn = std::get<std::string>(value);
346 }
347 }
348 catch (const std::exception& e)
349 {
350 log<level::WARNING>(
351 fmt::format("Failed reading SerialNumber property from "
352 "Interface: {} exception: {}",
353 interface::invAsset, e.what())
354 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600355 }
356
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500357 return sn;
358}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600359
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500360std::string DataInterface::getMotherboardCCIN() const
361{
362 std::string ccin;
363
364 try
365 {
Patrick Williams2544b412022-10-04 08:41:06 -0500366 auto service = getService(object_path::motherBoardInv,
367 interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500368 if (!service.empty())
369 {
370 DBusValue value;
371 getProperty(service, object_path::motherBoardInv,
372 interface::viniRecordVPD, "CC", value);
373
374 auto cc = std::get<std::vector<uint8_t>>(value);
375 ccin = std::string{cc.begin(), cc.end()};
376 }
377 }
378 catch (const std::exception& e)
379 {
380 log<level::WARNING>(
381 fmt::format("Failed reading Motherboard CCIN property from "
382 "Interface: {} exception: {}",
383 interface::viniRecordVPD, e.what())
384 .c_str());
385 }
386
387 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600388}
389
Ben Tynere32b7e72021-05-18 12:38:40 -0500390std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
391{
392 std::vector<uint8_t> systemIM;
393
394 try
395 {
Patrick Williams2544b412022-10-04 08:41:06 -0500396 auto service = getService(object_path::motherBoardInv,
397 interface::vsbpRecordVPD);
Ben Tynere32b7e72021-05-18 12:38:40 -0500398 if (!service.empty())
399 {
400 DBusValue value;
401 getProperty(service, object_path::motherBoardInv,
402 interface::vsbpRecordVPD, "IM", value);
403
404 systemIM = std::get<std::vector<uint8_t>>(value);
405 }
406 }
407 catch (const std::exception& e)
408 {
409 log<level::WARNING>(
410 fmt::format("Failed reading System IM property from "
411 "Interface: {} exception: {}",
412 interface::vsbpRecordVPD, e.what())
413 .c_str());
414 }
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{
555 DBusValue variant = value;
556 auto service = getService(objectPath, interface::operationalStatus);
557
558 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
559 interface::dbusProperty, "Set");
560
561 method.append(interface::operationalStatus, "Functional", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600562 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500563}
564
Sumit Kumar76198a22021-07-15 05:59:57 -0500565using AssociationTuple = std::tuple<std::string, std::string, std::string>;
566using AssociationsProperty = std::vector<AssociationTuple>;
567
568void DataInterface::setCriticalAssociation(const std::string& objectPath) const
569{
570 DBusValue getAssociationValue;
571
Sumit Kumar027bf282022-01-24 11:25:19 -0600572 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500573
Sumit Kumar027bf282022-01-24 11:25:19 -0600574 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500575 getAssociationValue);
576
577 auto association = std::get<AssociationsProperty>(getAssociationValue);
578
579 AssociationTuple critAssociation{
580 "health_rollup", "critical",
581 "/xyz/openbmc_project/inventory/system/chassis"};
582
583 if (std::find(association.begin(), association.end(), critAssociation) ==
584 association.end())
585 {
586 association.push_back(critAssociation);
587 DBusValue setAssociationValue = association;
588
589 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
590 interface::dbusProperty, "Set");
591
Sumit Kumar027bf282022-01-24 11:25:19 -0600592 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500593 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600594 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500595 }
596}
597
Matt Spinler1ab66962020-10-29 13:21:44 -0500598std::vector<std::string> DataInterface::getSystemNames() const
599{
600 DBusSubTree subtree;
601 DBusValue names;
602
603 auto method = _bus.new_method_call(service_name::objectMapper,
604 object_path::objectMapper,
605 interface::objectMapper, "GetSubTree");
606 method.append(std::string{"/"}, 0,
607 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600608 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500609
610 reply.read(subtree);
611 if (subtree.empty())
612 {
613 throw std::runtime_error("Compatible interface not on D-Bus");
614 }
615
616 const auto& object = *(subtree.begin());
617 const auto& path = object.first;
618 const auto& service = object.second.begin()->first;
619
620 getProperty(service, path, interface::compatible, "Names", names);
621
622 return std::get<std::vector<std::string>>(names);
623}
624
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500625bool DataInterface::getQuiesceOnError() const
626{
627 bool ret = false;
628
629 try
630 {
Patrick Williams2544b412022-10-04 08:41:06 -0500631 auto service = getService(object_path::logSetting,
632 interface::logSetting);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500633 if (!service.empty())
634 {
635 DBusValue value;
636 getProperty(service, object_path::logSetting, interface::logSetting,
637 "QuiesceOnHwError", value);
638
639 ret = std::get<bool>(value);
640 }
641 }
642 catch (const std::exception& e)
643 {
644 log<level::WARNING>(
645 fmt::format("Failed reading QuiesceOnHwError property from "
646 "Interface: {} exception: {}",
647 interface::logSetting, e.what())
648 .c_str());
649 }
650
651 return ret;
652}
653
Sumit Kumar9d43a722021-08-24 09:46:19 -0500654std::vector<bool>
655 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
656{
657 DBusSubTree subtree;
658 std::vector<bool> result(type.size(), false);
659
660 // Query GetSubTree for the availability of dump interface
661 auto method = _bus.new_method_call(service_name::objectMapper,
662 object_path::objectMapper,
663 interface::objectMapper, "GetSubTree");
664 method.append(std::string{"/"}, 0,
665 std::vector<std::string>{interface::dumpEntry});
Matt Spinler35a405b2022-03-02 11:42:42 -0600666 auto reply = _bus.call(method, dbusTimeout);
Sumit Kumar9d43a722021-08-24 09:46:19 -0500667
668 reply.read(subtree);
669
670 if (subtree.empty())
671 {
672 return result;
673 }
674
675 std::vector<bool>::iterator itDumpStatus = result.begin();
676 uint8_t count = 0;
677 for (const auto& [path, serviceInfo] : subtree)
678 {
679 const auto& service = serviceInfo.begin()->first;
680 // Check for dump type on the object path
681 for (const auto& it : type)
682 {
683 if (path.find(it) != std::string::npos)
684 {
685 DBusValue value, progress;
686
687 // If dump type status is already available go for next path
688 if (*itDumpStatus)
689 {
690 break;
691 }
692
693 // Check for valid dump to be available if following
694 // conditions are met for the dump entry path -
695 // Offloaded == false and Status == Completed
696 getProperty(service, path, interface::dumpEntry, "Offloaded",
697 value);
698 getProperty(service, path, interface::dumpProgress, "Status",
699 progress);
700 auto offload = std::get<bool>(value);
701 auto status = std::get<std::string>(progress);
702 if (!offload && (status.find("Completed") != std::string::npos))
703 {
704 *itDumpStatus = true;
705 count++;
706 if (count >= type.size())
707 {
708 return result;
709 }
710 break;
711 }
712 }
Matt Spinler45796e82022-07-01 11:25:27 -0500713 ++itDumpStatus;
Sumit Kumar9d43a722021-08-24 09:46:19 -0500714 }
715 itDumpStatus = result.begin();
716 }
717
718 return result;
719}
720
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500721void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
722 const std::string& type,
723 const std::string& logPath) const
724{
725 try
726 {
727 auto method = _bus.new_method_call(
728 service_name::hwIsolation, object_path::hwIsolation,
729 interface::hwIsolationCreate, "CreateWithEntityPath");
730 method.append(binPath, type, sdbusplus::message::object_path(logPath));
731 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
732 // api's. Making d-bus call no reply type to avoid cyclic dependency.
733 // Added minimal timeout to catch initial failures.
734 // Need to revisit this design later to avoid cyclic dependency.
Matt Spinler35a405b2022-03-02 11:42:42 -0600735 constexpr auto hwIsolationTimeout = 100000; // in micro seconds
736 _bus.call_noreply(method, hwIsolationTimeout);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500737 }
738
Patrick Williams45e83522022-07-22 19:26:52 -0500739 catch (const sdbusplus::exception_t& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500740 {
741 std::string errName = e.name();
742 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
743 // mentioned above. Ignoring the error.
744 if (errName != SD_BUS_ERROR_TIMEOUT)
745 {
746 log<level::ERR>(
747 fmt::format("GUARD D-Bus call exception"
748 "OBJPATH={}, INTERFACE={}, EXCEPTION={}",
749 object_path::hwIsolation,
750 interface::hwIsolationCreate, e.what())
751 .c_str());
752 }
753 }
754}
Sumit Kumar3e274432021-09-14 06:37:56 -0500755
756void DataInterface::createProgressSRC(
757 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
758{
759 DBusValue variant = std::make_tuple(priSRC, srcStruct);
760
761 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500762 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500763 interface::dbusProperty, "Set");
764
765 method.append(interface::bootRawProgress, "Value", variant);
766
Matt Spinler35a405b2022-03-02 11:42:42 -0600767 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500768}
Sumit Kumar027bf282022-01-24 11:25:19 -0600769
770std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
771{
772 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
773 std::string hwErrorLog = "/isolated_hw_errorlog";
774 std::string errorLog = "/error_log";
775 DBusPathList paths;
776 std::vector<uint32_t> ids;
777
778 // Get all latest mapper associations
779 paths = getPaths(association);
780 for (auto& path : paths)
781 {
782 // Look for object path with hardware isolation entry if any
783 size_t pos = path.find(hwErrorLog);
784 if (pos != std::string::npos)
785 {
786 // Get the object path
787 std::string ph = path;
788 ph.erase(pos, hwErrorLog.length());
789 auto service = getService(ph, interface::hwIsolationEntry);
790 if (!service.empty())
791 {
792 bool status;
793 DBusValue value;
794
795 // Read the Resolved property from object path
796 getProperty(service, ph, interface::hwIsolationEntry,
797 "Resolved", value);
798
799 status = std::get<bool>(value);
800
801 // If the entry isn't resolved
802 if (!status)
803 {
Patrick Williams2544b412022-10-04 08:41:06 -0500804 auto assocService = getService(path,
805 interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500806 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600807 {
Matt Spinler45796e82022-07-01 11:25:27 -0500808 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600809
810 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500811 getProperty(assocService, path, interface::association,
812 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600813
814 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500815 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600816 if (!logPath.empty())
817 {
818 // Get OpenBMC event log Id
819 uint32_t id = stoi(logPath[0].substr(
820 logPath[0].find_last_of('/') + 1));
821 ids.push_back(id);
822 }
823 }
824 }
825 }
826 }
827
828 // Look for object path with error_log entry if any
829 pos = path.find(errorLog);
830 if (pos != std::string::npos)
831 {
832 auto service = getService(path, interface::association);
833 if (!service.empty())
834 {
835 DBusValue value;
836
837 // Read Endpoints property
838 getProperty(service, path, interface::association, "endpoints",
839 value);
840
841 auto logPath = std::get<std::vector<std::string>>(value);
842 if (!logPath.empty())
843 {
844 // Get OpenBMC event log Id
845 uint32_t id = stoi(
846 logPath[0].substr(logPath[0].find_last_of('/') + 1));
847 ids.push_back(id);
848 }
849 }
850 }
851 }
852
853 if (ids.size() > 1)
854 {
855 // remove duplicates to have only unique ids
856 std::sort(ids.begin(), ids.end());
857 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
858 }
859 return ids;
860}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500861
862std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
863{
864 using RawProgressProperty = std::tuple<uint64_t, std::vector<uint8_t>>;
865
866 DBusValue value;
867 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
868 interface::bootRawProgress, "Value", value);
869
870 const auto& rawProgress = std::get<RawProgressProperty>(value);
871 return std::get<1>(rawProgress);
872}
873
Matt Spinlerc8705e22019-09-11 12:36:07 -0500874} // namespace pels
875} // namespace openpower