blob: 0e31b0ee3541bbaed7ad3f2e2bb80fc95bfe6a33 [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) ||
140 (status == Progress::ProgressStages::OSStart) ||
141 (status == Progress::ProgressStages::OSRunning))
Matt Spinler2a28c932020-02-03 14:23:40 -0600142 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600143 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600144 }
145 else
146 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600147 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600148 }
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) {
Matt Spinlerc6ee7c52022-01-14 13:21:53 -0600155 if (std::get<bool>(value) != this->_sendPELsToHost)
156 {
157 log<level::INFO>(
158 fmt::format("The send PELs to host setting changed to {}",
159 std::get<bool>(value))
160 .c_str());
161 }
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600162 this->_sendPELsToHost = std::get<bool>(value);
163 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600164
165 // Watch the BMCState property
166 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
167 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
168 *this, [this](const auto& value) {
169 this->_bmcState = std::get<std::string>(value);
170 }));
171
172 // Watch the chassis current and requested power state properties
173 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
174 bus, object_path::chassisState, interface::chassisState, *this,
175 [this](const auto& properties) {
176 auto state = properties.find("CurrentPowerState");
177 if (state != properties.end())
178 {
179 this->_chassisState = std::get<std::string>(state->second);
180 }
181
182 auto trans = properties.find("RequestedPowerTransition");
183 if (trans != properties.end())
184 {
185 this->_chassisTransition = std::get<std::string>(trans->second);
186 }
187 }));
188
189 // Watch the CurrentHostState property
190 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
191 bus, object_path::hostState, interface::hostState, "CurrentHostState",
192 *this, [this](const auto& value) {
193 this->_hostState = std::get<std::string>(value);
194 }));
Matt Spinler744d8512022-06-08 08:25:47 -0500195
196 // Watch the BaseBIOSTable property for the hmc managed attribute
197 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
198 bus, object_path::biosConfigMgr, interface::biosConfigMgr,
199 "BaseBIOSTable", service_name::biosConfigMgr, *this,
200 [this](const auto& value) {
201 const auto& attributes = std::get<BiosAttributes>(value);
202
203 auto it = attributes.find("pvm_hmc_managed");
204 if (it != attributes.end())
205 {
206 const auto& currentValVariant = std::get<5>(it->second);
207 auto currentVal = std::get_if<std::string>(&currentValVariant);
208 if (currentVal)
209 {
Patrick Williams2544b412022-10-04 08:41:06 -0500210 this->_hmcManaged = (*currentVal == "Enabled") ? true
211 : false;
Matt Spinler744d8512022-06-08 08:25:47 -0500212 }
213 }
214 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500215}
216
Matt Spinler2a28c932020-02-03 14:23:40 -0600217DBusPropertyMap
218 DataInterface::getAllProperties(const std::string& service,
219 const std::string& objectPath,
220 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500221{
222 DBusPropertyMap properties;
223
224 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
225 interface::dbusProperty, "GetAll");
226 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600227 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500228
229 reply.read(properties);
230
231 return properties;
232}
233
Matt Spinlera7d9d962019-11-06 15:01:25 -0600234void DataInterface::getProperty(const std::string& service,
235 const std::string& objectPath,
236 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600237 const std::string& property,
238 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600239{
Matt Spinlera7d9d962019-11-06 15:01:25 -0600240 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
241 interface::dbusProperty, "Get");
242 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600243 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600244
245 reply.read(value);
246}
247
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600248DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
249{
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600250 auto method = _bus.new_method_call(
251 service_name::objectMapper, object_path::objectMapper,
252 interface::objectMapper, "GetSubTreePaths");
253
254 method.append(std::string{"/"}, 0, interfaces);
255
Matt Spinler35a405b2022-03-02 11:42:42 -0600256 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600257
258 DBusPathList paths;
259 reply.read(paths);
260
261 return paths;
262}
263
Matt Spinlerc8705e22019-09-11 12:36:07 -0500264DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600265 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500266{
267 auto method = _bus.new_method_call(service_name::objectMapper,
268 object_path::objectMapper,
269 interface::objectMapper, "GetObject");
270
271 method.append(objectPath, std::vector<std::string>({interface}));
272
Matt Spinler35a405b2022-03-02 11:42:42 -0600273 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500274
275 std::map<DBusService, DBusInterfaceList> response;
276 reply.read(response);
277
278 if (!response.empty())
279 {
280 return response.begin()->first;
281 }
282
283 return std::string{};
284}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600285
Matt Spinler677381b2020-01-23 10:04:29 -0600286void DataInterface::readBMCFWVersion()
287{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500288 _bmcFWVersion =
289 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600290}
291
292void DataInterface::readServerFWVersion()
293{
Sumit Kumarcad16202021-05-13 04:06:15 -0500294 auto value =
295 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
296 if ((value != "") && (value.find_last_of(')') != std::string::npos))
297 {
298 std::size_t pos = value.find_first_of('(') + 1;
299 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
300 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600301}
302
Matt Spinler677381b2020-01-23 10:04:29 -0600303void DataInterface::readBMCFWVersionID()
304{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500305 _bmcFWVersionID =
306 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600307}
308
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500309std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600310{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500311 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600312 try
313 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500314 auto service = getService(object_path::systemInv, interface::invAsset);
315 if (!service.empty())
316 {
317 DBusValue value;
318 getProperty(service, object_path::systemInv, interface::invAsset,
319 "Model", value);
320
321 model = std::get<std::string>(value);
322 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600323 }
324 catch (const std::exception& e)
325 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500326 log<level::WARNING>(fmt::format("Failed reading Model property from "
327 "Interface: {} exception: {}",
328 interface::invAsset, e.what())
329 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600330 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500331
332 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600333}
334
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500335std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600336{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500337 std::string sn;
338 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600339 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500340 auto service = getService(object_path::systemInv, interface::invAsset);
341 if (!service.empty())
342 {
343 DBusValue value;
344 getProperty(service, object_path::systemInv, interface::invAsset,
345 "SerialNumber", value);
346
347 sn = std::get<std::string>(value);
348 }
349 }
350 catch (const std::exception& e)
351 {
352 log<level::WARNING>(
353 fmt::format("Failed reading SerialNumber property from "
354 "Interface: {} exception: {}",
355 interface::invAsset, e.what())
356 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600357 }
358
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500359 return sn;
360}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600361
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500362std::string DataInterface::getMotherboardCCIN() const
363{
364 std::string ccin;
365
366 try
367 {
Patrick Williams2544b412022-10-04 08:41:06 -0500368 auto service = getService(object_path::motherBoardInv,
369 interface::viniRecordVPD);
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500370 if (!service.empty())
371 {
372 DBusValue value;
373 getProperty(service, object_path::motherBoardInv,
374 interface::viniRecordVPD, "CC", value);
375
376 auto cc = std::get<std::vector<uint8_t>>(value);
377 ccin = std::string{cc.begin(), cc.end()};
378 }
379 }
380 catch (const std::exception& e)
381 {
382 log<level::WARNING>(
383 fmt::format("Failed reading Motherboard CCIN property from "
384 "Interface: {} exception: {}",
385 interface::viniRecordVPD, e.what())
386 .c_str());
387 }
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 {
411 log<level::WARNING>(
412 fmt::format("Failed reading System IM property from "
413 "Interface: {} exception: {}",
414 interface::vsbpRecordVPD, e.what())
415 .c_str());
416 }
417
418 return systemIM;
419}
420
Matt Spinler60c4e792020-03-13 13:45:36 -0500421void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500422 std::string& fruPartNumber,
423 std::string& ccin,
424 std::string& serialNumber) const
425{
426 // For now, attempt to get all of the properties directly on the path
427 // passed in. In the future, may need to make use of an algorithm
428 // to figure out which inventory objects actually hold these
429 // interfaces in the case of non FRUs, or possibly another service
430 // will provide this info. Any missing interfaces will result
431 // in exceptions being thrown.
432
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500433 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500434
Patrick Williams2544b412022-10-04 08:41:06 -0500435 auto properties = getAllProperties(service, inventoryPath,
436 interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500437
438 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
439 fruPartNumber = std::string{value.begin(), value.end()};
440
441 value = std::get<std::vector<uint8_t>>(properties["CC"]);
442 ccin = std::string{value.begin(), value.end()};
443
444 value = std::get<std::vector<uint8_t>>(properties["SN"]);
445 serialNumber = std::string{value.begin(), value.end()};
446}
447
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500448std::string
449 DataInterface::getLocationCode(const std::string& inventoryPath) const
450{
451 auto service = getService(inventoryPath, interface::locCode);
452
453 DBusValue locCode;
454 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
455 locCode);
456
457 return std::get<std::string>(locCode);
458}
459
Matt Spinler5fb24c12020-06-04 11:21:33 -0500460std::string
461 DataInterface::addLocationCodePrefix(const std::string& locationCode)
462{
463 static const std::string locationCodePrefix{"Ufcs-"};
464
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500465 // Technically there are 2 location code prefixes, Ufcs and Umts, so
466 // if it already starts with a U then don't need to do anything.
467 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500468 {
469 return locationCodePrefix + locationCode;
470 }
471
472 return locationCode;
473}
474
475std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500476 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500477{
Matt Spinler0d92b522021-06-16 13:28:17 -0600478 // Location codes for connectors are the location code of the FRU they are
479 // on, plus a '-Tx' segment. Remove this last segment before expanding it
480 // and then add it back in afterwards. This way, the connector doesn't have
481 // to be in the model just so that it can be expanded.
482 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
483
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500484 auto method =
485 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
486 interface::vpdManager, "GetExpandedLocationCode");
487
Matt Spinler0d92b522021-06-16 13:28:17 -0600488 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500489
Matt Spinler35a405b2022-03-02 11:42:42 -0600490 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500491
492 std::string expandedLocationCode;
493 reply.read(expandedLocationCode);
494
Matt Spinler0d92b522021-06-16 13:28:17 -0600495 if (!connectorLoc.empty())
496 {
497 expandedLocationCode += connectorLoc;
498 }
499
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500500 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500501}
502
Matt Spinler2f9225a2020-08-05 12:58:49 -0500503std::string
504 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
505 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500506{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500507 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
508 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500509
Matt Spinler0d92b522021-06-16 13:28:17 -0600510 // Remove the connector segment, if present, so that this method call
511 // returns an inventory path that getHWCalloutFields() can be used with.
512 // (The serial number, etc, aren't stored on the connector in the
513 // inventory, and may not even be modeled.)
514 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
515
Matt Spinler2f9225a2020-08-05 12:58:49 -0500516 auto method =
517 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
518 interface::vpdManager, methodName.c_str());
519
520 if (expanded)
521 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600522 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500523 }
524 else
525 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600526 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500527 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500528
Matt Spinler35a405b2022-03-02 11:42:42 -0600529 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500530
531 std::vector<sdbusplus::message::object_path> entries;
532 reply.read(entries);
533
534 // Get the shortest entry from the paths received, as this
535 // would be the path furthest up the inventory hierarchy so
536 // would be the parent FRU. There is guaranteed to at least
537 // be one entry if the call didn't fail.
538 std::string shortest{entries[0]};
539
540 std::for_each(entries.begin(), entries.end(),
541 [&shortest](const auto& path) {
542 if (path.str.size() < shortest.size())
543 {
544 shortest = path;
545 }
546 });
547
548 return shortest;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500549}
550
Matt Spinler34a904c2020-08-05 14:53:28 -0500551void DataInterface::assertLEDGroup(const std::string& ledGroup,
552 bool value) const
553{
554 DBusValue variant = value;
Patrick Williams2544b412022-10-04 08:41:06 -0500555 auto method = _bus.new_method_call(service_name::ledGroupManager,
556 ledGroup.c_str(),
557 interface::dbusProperty, "Set");
Matt Spinler34a904c2020-08-05 14:53:28 -0500558 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600559 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500560}
561
Matt Spinler993168d2021-04-07 16:05:03 -0500562void DataInterface::setFunctional(const std::string& objectPath,
563 bool value) const
564{
565 DBusValue variant = value;
566 auto service = getService(objectPath, interface::operationalStatus);
567
568 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
569 interface::dbusProperty, "Set");
570
571 method.append(interface::operationalStatus, "Functional", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600572 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500573}
574
Sumit Kumar76198a22021-07-15 05:59:57 -0500575using AssociationTuple = std::tuple<std::string, std::string, std::string>;
576using AssociationsProperty = std::vector<AssociationTuple>;
577
578void DataInterface::setCriticalAssociation(const std::string& objectPath) const
579{
580 DBusValue getAssociationValue;
581
Sumit Kumar027bf282022-01-24 11:25:19 -0600582 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500583
Sumit Kumar027bf282022-01-24 11:25:19 -0600584 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500585 getAssociationValue);
586
587 auto association = std::get<AssociationsProperty>(getAssociationValue);
588
589 AssociationTuple critAssociation{
590 "health_rollup", "critical",
591 "/xyz/openbmc_project/inventory/system/chassis"};
592
593 if (std::find(association.begin(), association.end(), critAssociation) ==
594 association.end())
595 {
596 association.push_back(critAssociation);
597 DBusValue setAssociationValue = association;
598
599 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
600 interface::dbusProperty, "Set");
601
Sumit Kumar027bf282022-01-24 11:25:19 -0600602 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500603 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600604 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500605 }
606}
607
Matt Spinler1ab66962020-10-29 13:21:44 -0500608std::vector<std::string> DataInterface::getSystemNames() const
609{
610 DBusSubTree subtree;
611 DBusValue names;
612
613 auto method = _bus.new_method_call(service_name::objectMapper,
614 object_path::objectMapper,
615 interface::objectMapper, "GetSubTree");
616 method.append(std::string{"/"}, 0,
617 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600618 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500619
620 reply.read(subtree);
621 if (subtree.empty())
622 {
623 throw std::runtime_error("Compatible interface not on D-Bus");
624 }
625
626 const auto& object = *(subtree.begin());
627 const auto& path = object.first;
628 const auto& service = object.second.begin()->first;
629
630 getProperty(service, path, interface::compatible, "Names", names);
631
632 return std::get<std::vector<std::string>>(names);
633}
634
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500635bool DataInterface::getQuiesceOnError() const
636{
637 bool ret = false;
638
639 try
640 {
Patrick Williams2544b412022-10-04 08:41:06 -0500641 auto service = getService(object_path::logSetting,
642 interface::logSetting);
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500643 if (!service.empty())
644 {
645 DBusValue value;
646 getProperty(service, object_path::logSetting, interface::logSetting,
647 "QuiesceOnHwError", value);
648
649 ret = std::get<bool>(value);
650 }
651 }
652 catch (const std::exception& e)
653 {
654 log<level::WARNING>(
655 fmt::format("Failed reading QuiesceOnHwError property from "
656 "Interface: {} exception: {}",
657 interface::logSetting, e.what())
658 .c_str());
659 }
660
661 return ret;
662}
663
Sumit Kumar9d43a722021-08-24 09:46:19 -0500664std::vector<bool>
665 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
666{
667 DBusSubTree subtree;
668 std::vector<bool> result(type.size(), false);
669
670 // Query GetSubTree for the availability of dump interface
671 auto method = _bus.new_method_call(service_name::objectMapper,
672 object_path::objectMapper,
673 interface::objectMapper, "GetSubTree");
674 method.append(std::string{"/"}, 0,
675 std::vector<std::string>{interface::dumpEntry});
Matt Spinler35a405b2022-03-02 11:42:42 -0600676 auto reply = _bus.call(method, dbusTimeout);
Sumit Kumar9d43a722021-08-24 09:46:19 -0500677
678 reply.read(subtree);
679
680 if (subtree.empty())
681 {
682 return result;
683 }
684
685 std::vector<bool>::iterator itDumpStatus = result.begin();
686 uint8_t count = 0;
687 for (const auto& [path, serviceInfo] : subtree)
688 {
689 const auto& service = serviceInfo.begin()->first;
690 // Check for dump type on the object path
691 for (const auto& it : type)
692 {
693 if (path.find(it) != std::string::npos)
694 {
695 DBusValue value, progress;
696
697 // If dump type status is already available go for next path
698 if (*itDumpStatus)
699 {
700 break;
701 }
702
703 // Check for valid dump to be available if following
704 // conditions are met for the dump entry path -
705 // Offloaded == false and Status == Completed
706 getProperty(service, path, interface::dumpEntry, "Offloaded",
707 value);
708 getProperty(service, path, interface::dumpProgress, "Status",
709 progress);
710 auto offload = std::get<bool>(value);
711 auto status = std::get<std::string>(progress);
712 if (!offload && (status.find("Completed") != std::string::npos))
713 {
714 *itDumpStatus = true;
715 count++;
716 if (count >= type.size())
717 {
718 return result;
719 }
720 break;
721 }
722 }
Matt Spinler45796e82022-07-01 11:25:27 -0500723 ++itDumpStatus;
Sumit Kumar9d43a722021-08-24 09:46:19 -0500724 }
725 itDumpStatus = result.begin();
726 }
727
728 return result;
729}
730
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500731void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
732 const std::string& type,
733 const std::string& logPath) const
734{
735 try
736 {
737 auto method = _bus.new_method_call(
738 service_name::hwIsolation, object_path::hwIsolation,
739 interface::hwIsolationCreate, "CreateWithEntityPath");
740 method.append(binPath, type, sdbusplus::message::object_path(logPath));
741 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
742 // api's. Making d-bus call no reply type to avoid cyclic dependency.
743 // Added minimal timeout to catch initial failures.
744 // Need to revisit this design later to avoid cyclic dependency.
Matt Spinler35a405b2022-03-02 11:42:42 -0600745 constexpr auto hwIsolationTimeout = 100000; // in micro seconds
746 _bus.call_noreply(method, hwIsolationTimeout);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500747 }
748
Patrick Williams45e83522022-07-22 19:26:52 -0500749 catch (const sdbusplus::exception_t& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500750 {
751 std::string errName = e.name();
752 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
753 // mentioned above. Ignoring the error.
754 if (errName != SD_BUS_ERROR_TIMEOUT)
755 {
756 log<level::ERR>(
757 fmt::format("GUARD D-Bus call exception"
758 "OBJPATH={}, INTERFACE={}, EXCEPTION={}",
759 object_path::hwIsolation,
760 interface::hwIsolationCreate, e.what())
761 .c_str());
762 }
763 }
764}
Sumit Kumar3e274432021-09-14 06:37:56 -0500765
766void DataInterface::createProgressSRC(
767 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
768{
769 DBusValue variant = std::make_tuple(priSRC, srcStruct);
770
771 auto method = _bus.new_method_call(service_name::bootRawProgress,
Vijay Lobo875b6c72021-10-20 17:38:56 -0500772 object_path::bootRawProgress,
Sumit Kumar3e274432021-09-14 06:37:56 -0500773 interface::dbusProperty, "Set");
774
775 method.append(interface::bootRawProgress, "Value", variant);
776
Matt Spinler35a405b2022-03-02 11:42:42 -0600777 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500778}
Sumit Kumar027bf282022-01-24 11:25:19 -0600779
780std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
781{
782 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
783 std::string hwErrorLog = "/isolated_hw_errorlog";
784 std::string errorLog = "/error_log";
785 DBusPathList paths;
786 std::vector<uint32_t> ids;
787
788 // Get all latest mapper associations
789 paths = getPaths(association);
790 for (auto& path : paths)
791 {
792 // Look for object path with hardware isolation entry if any
793 size_t pos = path.find(hwErrorLog);
794 if (pos != std::string::npos)
795 {
796 // Get the object path
797 std::string ph = path;
798 ph.erase(pos, hwErrorLog.length());
799 auto service = getService(ph, interface::hwIsolationEntry);
800 if (!service.empty())
801 {
802 bool status;
803 DBusValue value;
804
805 // Read the Resolved property from object path
806 getProperty(service, ph, interface::hwIsolationEntry,
807 "Resolved", value);
808
809 status = std::get<bool>(value);
810
811 // If the entry isn't resolved
812 if (!status)
813 {
Patrick Williams2544b412022-10-04 08:41:06 -0500814 auto assocService = getService(path,
815 interface::association);
Matt Spinler45796e82022-07-01 11:25:27 -0500816 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600817 {
Matt Spinler45796e82022-07-01 11:25:27 -0500818 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600819
820 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500821 getProperty(assocService, path, interface::association,
822 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600823
824 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500825 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600826 if (!logPath.empty())
827 {
828 // Get OpenBMC event log Id
829 uint32_t id = stoi(logPath[0].substr(
830 logPath[0].find_last_of('/') + 1));
831 ids.push_back(id);
832 }
833 }
834 }
835 }
836 }
837
838 // Look for object path with error_log entry if any
839 pos = path.find(errorLog);
840 if (pos != std::string::npos)
841 {
842 auto service = getService(path, interface::association);
843 if (!service.empty())
844 {
845 DBusValue value;
846
847 // Read Endpoints property
848 getProperty(service, path, interface::association, "endpoints",
849 value);
850
851 auto logPath = std::get<std::vector<std::string>>(value);
852 if (!logPath.empty())
853 {
854 // Get OpenBMC event log Id
855 uint32_t id = stoi(
856 logPath[0].substr(logPath[0].find_last_of('/') + 1));
857 ids.push_back(id);
858 }
859 }
860 }
861 }
862
863 if (ids.size() > 1)
864 {
865 // remove duplicates to have only unique ids
866 std::sort(ids.begin(), ids.end());
867 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
868 }
869 return ids;
870}
Vijay Lobo875b6c72021-10-20 17:38:56 -0500871
872std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
873{
874 using RawProgressProperty = std::tuple<uint64_t, std::vector<uint8_t>>;
875
876 DBusValue value;
877 getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
878 interface::bootRawProgress, "Value", value);
879
880 const auto& rawProgress = std::get<RawProgressProperty>(value);
881 return std::get<1>(rawProgress);
882}
883
Matt Spinlerc8705e22019-09-11 12:36:07 -0500884} // namespace pels
885} // namespace openpower