blob: a582d88ba51abe761f759c2bad6b1bb3c7237933 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlercad9c2b2019-12-02 15:42:01 -060016#include "config.h"
17
Matt Spinlerc8705e22019-09-11 12:36:07 -050018#include "data_interface.hpp"
19
Matt Spinlerf61f2922020-06-23 11:32:49 -050020#include "util.hpp"
21
Vijay Lobo81b4dca2021-04-29 00:04:00 -050022#include <fmt/format.h>
23
Matt Spinlercad9c2b2019-12-02 15:42:01 -060024#include <fstream>
Sumit Kumar9d43a722021-08-24 09:46:19 -050025#include <iterator>
Vijay Lobo81b4dca2021-04-29 00:04:00 -050026#include <phosphor-logging/log.hpp>
Matt Spinlerf10068d2020-12-02 10:44:08 -060027#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Matt Spinlera7d9d962019-11-06 15:01:25 -060028
Matt Spinler35a405b2022-03-02 11:42:42 -060029// Use a timeout of 10s for D-Bus calls so if there are
30// timeouts the callers of the PEL creation method won't
31// also timeout.
32constexpr auto dbusTimeout = 10000000;
33
Matt Spinlerc8705e22019-09-11 12:36:07 -050034namespace openpower
35{
36namespace pels
37{
38
39namespace service_name
40{
41constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050042constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050043constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050044constexpr auto logSetting = "xyz.openbmc_project.Settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050045constexpr auto hwIsolation = "org.open_power.HardwareIsolation";
Sumit Kumar3e274432021-09-14 06:37:56 -050046constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinlerc8705e22019-09-11 12:36:07 -050047} // namespace service_name
48
49namespace object_path
50{
51constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
52constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050053constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050054constexpr auto motherBoardInv =
55 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060056constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060057constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
58constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060059constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060060constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060061constexpr auto enableHostPELs =
62 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050063constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050064constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050065constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Sumit Kumar3e274432021-09-14 06:37:56 -050066constexpr auto bootRawSetting = "/xyz/openbmc_project/state/boot/raw0";
Matt Spinlerc8705e22019-09-11 12:36:07 -050067} // namespace object_path
68
69namespace interface
70{
71constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
72constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
73constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060074constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinlerb3f51862019-12-09 13:55:10 -060075constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060076constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060077constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
78constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
79constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060080constexpr auto invMotherboard =
81 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
82constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050083constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060084constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050085constexpr auto compatible =
86 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050087constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050088constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050089constexpr auto operationalStatus =
90 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050091constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060092constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050093constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
94constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050095constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar3e274432021-09-14 06:37:56 -050096constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Sumit Kumar027bf282022-01-24 11:25:19 -060097constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
98constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinlerc8705e22019-09-11 12:36:07 -050099} // namespace interface
100
Matt Spinlerf10068d2020-12-02 10:44:08 -0600101using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500102using namespace phosphor::logging;
Matt Spinlera7d9d962019-11-06 15:01:25 -0600103
Matt Spinler0d92b522021-06-16 13:28:17 -0600104std::pair<std::string, std::string>
105 DataInterfaceBase::extractConnectorFromLocCode(
106 const std::string& locationCode)
107{
108 auto base = locationCode;
109 std::string connector{};
110
111 auto pos = base.find("-T");
112 if (pos != std::string::npos)
113 {
114 connector = base.substr(pos);
115 base = base.substr(0, pos);
116 }
117
118 return {base, connector};
119}
120
Matt Spinlerc8705e22019-09-11 12:36:07 -0500121DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus)
122{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600123 readBMCFWVersion();
124 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600125 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600126
Matt Spinlerf10068d2020-12-02 10:44:08 -0600127 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600128 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600129 bus, object_path::hostState, interface::bootProgress, "BootProgress",
130 *this, [this](const auto& value) {
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500131 this->_bootState = std::get<std::string>(value);
Matt Spinlerf10068d2020-12-02 10:44:08 -0600132 auto status = Progress::convertProgressStagesFromString(
133 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600134
Matt Spinlerf10068d2020-12-02 10:44:08 -0600135 if ((status == Progress::ProgressStages::SystemInitComplete) ||
136 (status == Progress::ProgressStages::OSStart) ||
137 (status == Progress::ProgressStages::OSRunning))
Matt Spinler2a28c932020-02-03 14:23:40 -0600138 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600139 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600140 }
141 else
142 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600143 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600144 }
145 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600146
147 // Watch the host PEL enable property
148 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
149 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
150 [this](const auto& value) {
Matt Spinlerc6ee7c52022-01-14 13:21:53 -0600151 if (std::get<bool>(value) != this->_sendPELsToHost)
152 {
153 log<level::INFO>(
154 fmt::format("The send PELs to host setting changed to {}",
155 std::get<bool>(value))
156 .c_str());
157 }
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600158 this->_sendPELsToHost = std::get<bool>(value);
159 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600160
161 // Watch the BMCState property
162 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
163 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
164 *this, [this](const auto& value) {
165 this->_bmcState = std::get<std::string>(value);
166 }));
167
168 // Watch the chassis current and requested power state properties
169 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
170 bus, object_path::chassisState, interface::chassisState, *this,
171 [this](const auto& properties) {
172 auto state = properties.find("CurrentPowerState");
173 if (state != properties.end())
174 {
175 this->_chassisState = std::get<std::string>(state->second);
176 }
177
178 auto trans = properties.find("RequestedPowerTransition");
179 if (trans != properties.end())
180 {
181 this->_chassisTransition = std::get<std::string>(trans->second);
182 }
183 }));
184
185 // Watch the CurrentHostState property
186 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
187 bus, object_path::hostState, interface::hostState, "CurrentHostState",
188 *this, [this](const auto& value) {
189 this->_hostState = std::get<std::string>(value);
190 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500191}
192
Matt Spinler2a28c932020-02-03 14:23:40 -0600193DBusPropertyMap
194 DataInterface::getAllProperties(const std::string& service,
195 const std::string& objectPath,
196 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500197{
198 DBusPropertyMap properties;
199
200 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
201 interface::dbusProperty, "GetAll");
202 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600203 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500204
205 reply.read(properties);
206
207 return properties;
208}
209
Matt Spinlera7d9d962019-11-06 15:01:25 -0600210void DataInterface::getProperty(const std::string& service,
211 const std::string& objectPath,
212 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600213 const std::string& property,
214 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600215{
216
217 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
218 interface::dbusProperty, "Get");
219 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600220 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600221
222 reply.read(value);
223}
224
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600225DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
226{
227
228 auto method = _bus.new_method_call(
229 service_name::objectMapper, object_path::objectMapper,
230 interface::objectMapper, "GetSubTreePaths");
231
232 method.append(std::string{"/"}, 0, interfaces);
233
Matt Spinler35a405b2022-03-02 11:42:42 -0600234 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600235
236 DBusPathList paths;
237 reply.read(paths);
238
239 return paths;
240}
241
Matt Spinlerc8705e22019-09-11 12:36:07 -0500242DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600243 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500244{
245 auto method = _bus.new_method_call(service_name::objectMapper,
246 object_path::objectMapper,
247 interface::objectMapper, "GetObject");
248
249 method.append(objectPath, std::vector<std::string>({interface}));
250
Matt Spinler35a405b2022-03-02 11:42:42 -0600251 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500252
253 std::map<DBusService, DBusInterfaceList> response;
254 reply.read(response);
255
256 if (!response.empty())
257 {
258 return response.begin()->first;
259 }
260
261 return std::string{};
262}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600263
Matt Spinler677381b2020-01-23 10:04:29 -0600264void DataInterface::readBMCFWVersion()
265{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500266 _bmcFWVersion =
267 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600268}
269
270void DataInterface::readServerFWVersion()
271{
Sumit Kumarcad16202021-05-13 04:06:15 -0500272 auto value =
273 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
274 if ((value != "") && (value.find_last_of(')') != std::string::npos))
275 {
276 std::size_t pos = value.find_first_of('(') + 1;
277 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
278 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600279}
280
Matt Spinler677381b2020-01-23 10:04:29 -0600281void DataInterface::readBMCFWVersionID()
282{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500283 _bmcFWVersionID =
284 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600285}
286
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500287std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600288{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500289 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600290 try
291 {
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600292
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500293 auto service = getService(object_path::systemInv, interface::invAsset);
294 if (!service.empty())
295 {
296 DBusValue value;
297 getProperty(service, object_path::systemInv, interface::invAsset,
298 "Model", value);
299
300 model = std::get<std::string>(value);
301 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600302 }
303 catch (const std::exception& e)
304 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500305 log<level::WARNING>(fmt::format("Failed reading Model property from "
306 "Interface: {} exception: {}",
307 interface::invAsset, e.what())
308 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600309 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500310
311 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600312}
313
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500314std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600315{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500316 std::string sn;
317 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600318 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500319
320 auto service = getService(object_path::systemInv, interface::invAsset);
321 if (!service.empty())
322 {
323 DBusValue value;
324 getProperty(service, object_path::systemInv, interface::invAsset,
325 "SerialNumber", value);
326
327 sn = std::get<std::string>(value);
328 }
329 }
330 catch (const std::exception& e)
331 {
332 log<level::WARNING>(
333 fmt::format("Failed reading SerialNumber property from "
334 "Interface: {} exception: {}",
335 interface::invAsset, e.what())
336 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600337 }
338
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500339 return sn;
340}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600341
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500342std::string DataInterface::getMotherboardCCIN() const
343{
344 std::string ccin;
345
346 try
347 {
348 auto service =
349 getService(object_path::motherBoardInv, interface::viniRecordVPD);
350 if (!service.empty())
351 {
352 DBusValue value;
353 getProperty(service, object_path::motherBoardInv,
354 interface::viniRecordVPD, "CC", value);
355
356 auto cc = std::get<std::vector<uint8_t>>(value);
357 ccin = std::string{cc.begin(), cc.end()};
358 }
359 }
360 catch (const std::exception& e)
361 {
362 log<level::WARNING>(
363 fmt::format("Failed reading Motherboard CCIN property from "
364 "Interface: {} exception: {}",
365 interface::viniRecordVPD, e.what())
366 .c_str());
367 }
368
369 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600370}
371
Ben Tynere32b7e72021-05-18 12:38:40 -0500372std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
373{
374 std::vector<uint8_t> systemIM;
375
376 try
377 {
378 auto service =
379 getService(object_path::motherBoardInv, interface::vsbpRecordVPD);
380 if (!service.empty())
381 {
382 DBusValue value;
383 getProperty(service, object_path::motherBoardInv,
384 interface::vsbpRecordVPD, "IM", value);
385
386 systemIM = std::get<std::vector<uint8_t>>(value);
387 }
388 }
389 catch (const std::exception& e)
390 {
391 log<level::WARNING>(
392 fmt::format("Failed reading System IM property from "
393 "Interface: {} exception: {}",
394 interface::vsbpRecordVPD, e.what())
395 .c_str());
396 }
397
398 return systemIM;
399}
400
Matt Spinler60c4e792020-03-13 13:45:36 -0500401void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500402 std::string& fruPartNumber,
403 std::string& ccin,
404 std::string& serialNumber) const
405{
406 // For now, attempt to get all of the properties directly on the path
407 // passed in. In the future, may need to make use of an algorithm
408 // to figure out which inventory objects actually hold these
409 // interfaces in the case of non FRUs, or possibly another service
410 // will provide this info. Any missing interfaces will result
411 // in exceptions being thrown.
412
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500413 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500414
415 auto properties =
416 getAllProperties(service, inventoryPath, interface::viniRecordVPD);
417
418 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
419 fruPartNumber = std::string{value.begin(), value.end()};
420
421 value = std::get<std::vector<uint8_t>>(properties["CC"]);
422 ccin = std::string{value.begin(), value.end()};
423
424 value = std::get<std::vector<uint8_t>>(properties["SN"]);
425 serialNumber = std::string{value.begin(), value.end()};
426}
427
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500428std::string
429 DataInterface::getLocationCode(const std::string& inventoryPath) const
430{
431 auto service = getService(inventoryPath, interface::locCode);
432
433 DBusValue locCode;
434 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
435 locCode);
436
437 return std::get<std::string>(locCode);
438}
439
Matt Spinler5fb24c12020-06-04 11:21:33 -0500440std::string
441 DataInterface::addLocationCodePrefix(const std::string& locationCode)
442{
443 static const std::string locationCodePrefix{"Ufcs-"};
444
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500445 // Technically there are 2 location code prefixes, Ufcs and Umts, so
446 // if it already starts with a U then don't need to do anything.
447 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500448 {
449 return locationCodePrefix + locationCode;
450 }
451
452 return locationCode;
453}
454
455std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500456 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500457{
Matt Spinler0d92b522021-06-16 13:28:17 -0600458 // Location codes for connectors are the location code of the FRU they are
459 // on, plus a '-Tx' segment. Remove this last segment before expanding it
460 // and then add it back in afterwards. This way, the connector doesn't have
461 // to be in the model just so that it can be expanded.
462 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
463
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500464 auto method =
465 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
466 interface::vpdManager, "GetExpandedLocationCode");
467
Matt Spinler0d92b522021-06-16 13:28:17 -0600468 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500469
Matt Spinler35a405b2022-03-02 11:42:42 -0600470 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500471
472 std::string expandedLocationCode;
473 reply.read(expandedLocationCode);
474
Matt Spinler0d92b522021-06-16 13:28:17 -0600475 if (!connectorLoc.empty())
476 {
477 expandedLocationCode += connectorLoc;
478 }
479
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500480 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500481}
482
Matt Spinler2f9225a2020-08-05 12:58:49 -0500483std::string
484 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
485 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500486{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500487 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
488 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500489
Matt Spinler0d92b522021-06-16 13:28:17 -0600490 // Remove the connector segment, if present, so that this method call
491 // returns an inventory path that getHWCalloutFields() can be used with.
492 // (The serial number, etc, aren't stored on the connector in the
493 // inventory, and may not even be modeled.)
494 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
495
Matt Spinler2f9225a2020-08-05 12:58:49 -0500496 auto method =
497 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
498 interface::vpdManager, methodName.c_str());
499
500 if (expanded)
501 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600502 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500503 }
504 else
505 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600506 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500507 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500508
Matt Spinler35a405b2022-03-02 11:42:42 -0600509 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500510
511 std::vector<sdbusplus::message::object_path> entries;
512 reply.read(entries);
513
514 // Get the shortest entry from the paths received, as this
515 // would be the path furthest up the inventory hierarchy so
516 // would be the parent FRU. There is guaranteed to at least
517 // be one entry if the call didn't fail.
518 std::string shortest{entries[0]};
519
520 std::for_each(entries.begin(), entries.end(),
521 [&shortest](const auto& path) {
522 if (path.str.size() < shortest.size())
523 {
524 shortest = path;
525 }
526 });
527
528 return shortest;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500529}
530
Matt Spinler34a904c2020-08-05 14:53:28 -0500531void DataInterface::assertLEDGroup(const std::string& ledGroup,
532 bool value) const
533{
534 DBusValue variant = value;
535 auto method =
536 _bus.new_method_call(service_name::ledGroupManager, ledGroup.c_str(),
537 interface::dbusProperty, "Set");
538 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600539 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500540}
541
Matt Spinler993168d2021-04-07 16:05:03 -0500542void DataInterface::setFunctional(const std::string& objectPath,
543 bool value) const
544{
545 DBusValue variant = value;
546 auto service = getService(objectPath, interface::operationalStatus);
547
548 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
549 interface::dbusProperty, "Set");
550
551 method.append(interface::operationalStatus, "Functional", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600552 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500553}
554
Sumit Kumar76198a22021-07-15 05:59:57 -0500555using AssociationTuple = std::tuple<std::string, std::string, std::string>;
556using AssociationsProperty = std::vector<AssociationTuple>;
557
558void DataInterface::setCriticalAssociation(const std::string& objectPath) const
559{
560 DBusValue getAssociationValue;
561
Sumit Kumar027bf282022-01-24 11:25:19 -0600562 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500563
Sumit Kumar027bf282022-01-24 11:25:19 -0600564 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500565 getAssociationValue);
566
567 auto association = std::get<AssociationsProperty>(getAssociationValue);
568
569 AssociationTuple critAssociation{
570 "health_rollup", "critical",
571 "/xyz/openbmc_project/inventory/system/chassis"};
572
573 if (std::find(association.begin(), association.end(), critAssociation) ==
574 association.end())
575 {
576 association.push_back(critAssociation);
577 DBusValue setAssociationValue = association;
578
579 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
580 interface::dbusProperty, "Set");
581
Sumit Kumar027bf282022-01-24 11:25:19 -0600582 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500583 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600584 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500585 }
586}
587
Matt Spinler1ab66962020-10-29 13:21:44 -0500588std::vector<std::string> DataInterface::getSystemNames() const
589{
590 DBusSubTree subtree;
591 DBusValue names;
592
593 auto method = _bus.new_method_call(service_name::objectMapper,
594 object_path::objectMapper,
595 interface::objectMapper, "GetSubTree");
596 method.append(std::string{"/"}, 0,
597 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600598 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500599
600 reply.read(subtree);
601 if (subtree.empty())
602 {
603 throw std::runtime_error("Compatible interface not on D-Bus");
604 }
605
606 const auto& object = *(subtree.begin());
607 const auto& path = object.first;
608 const auto& service = object.second.begin()->first;
609
610 getProperty(service, path, interface::compatible, "Names", names);
611
612 return std::get<std::vector<std::string>>(names);
613}
614
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500615bool DataInterface::getQuiesceOnError() const
616{
617 bool ret = false;
618
619 try
620 {
621 auto service =
622 getService(object_path::logSetting, interface::logSetting);
623 if (!service.empty())
624 {
625 DBusValue value;
626 getProperty(service, object_path::logSetting, interface::logSetting,
627 "QuiesceOnHwError", value);
628
629 ret = std::get<bool>(value);
630 }
631 }
632 catch (const std::exception& e)
633 {
634 log<level::WARNING>(
635 fmt::format("Failed reading QuiesceOnHwError property from "
636 "Interface: {} exception: {}",
637 interface::logSetting, e.what())
638 .c_str());
639 }
640
641 return ret;
642}
643
Sumit Kumar9d43a722021-08-24 09:46:19 -0500644std::vector<bool>
645 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
646{
647 DBusSubTree subtree;
648 std::vector<bool> result(type.size(), false);
649
650 // Query GetSubTree for the availability of dump interface
651 auto method = _bus.new_method_call(service_name::objectMapper,
652 object_path::objectMapper,
653 interface::objectMapper, "GetSubTree");
654 method.append(std::string{"/"}, 0,
655 std::vector<std::string>{interface::dumpEntry});
Matt Spinler35a405b2022-03-02 11:42:42 -0600656 auto reply = _bus.call(method, dbusTimeout);
Sumit Kumar9d43a722021-08-24 09:46:19 -0500657
658 reply.read(subtree);
659
660 if (subtree.empty())
661 {
662 return result;
663 }
664
665 std::vector<bool>::iterator itDumpStatus = result.begin();
666 uint8_t count = 0;
667 for (const auto& [path, serviceInfo] : subtree)
668 {
669 const auto& service = serviceInfo.begin()->first;
670 // Check for dump type on the object path
671 for (const auto& it : type)
672 {
673 if (path.find(it) != std::string::npos)
674 {
675 DBusValue value, progress;
676
677 // If dump type status is already available go for next path
678 if (*itDumpStatus)
679 {
680 break;
681 }
682
683 // Check for valid dump to be available if following
684 // conditions are met for the dump entry path -
685 // Offloaded == false and Status == Completed
686 getProperty(service, path, interface::dumpEntry, "Offloaded",
687 value);
688 getProperty(service, path, interface::dumpProgress, "Status",
689 progress);
690 auto offload = std::get<bool>(value);
691 auto status = std::get<std::string>(progress);
692 if (!offload && (status.find("Completed") != std::string::npos))
693 {
694 *itDumpStatus = true;
695 count++;
696 if (count >= type.size())
697 {
698 return result;
699 }
700 break;
701 }
702 }
703 itDumpStatus++;
704 }
705 itDumpStatus = result.begin();
706 }
707
708 return result;
709}
710
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500711void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
712 const std::string& type,
713 const std::string& logPath) const
714{
715 try
716 {
717 auto method = _bus.new_method_call(
718 service_name::hwIsolation, object_path::hwIsolation,
719 interface::hwIsolationCreate, "CreateWithEntityPath");
720 method.append(binPath, type, sdbusplus::message::object_path(logPath));
721 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
722 // api's. Making d-bus call no reply type to avoid cyclic dependency.
723 // Added minimal timeout to catch initial failures.
724 // Need to revisit this design later to avoid cyclic dependency.
Matt Spinler35a405b2022-03-02 11:42:42 -0600725 constexpr auto hwIsolationTimeout = 100000; // in micro seconds
726 _bus.call_noreply(method, hwIsolationTimeout);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500727 }
728
729 catch (const sdbusplus::exception::exception& e)
730 {
731 std::string errName = e.name();
732 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
733 // mentioned above. Ignoring the error.
734 if (errName != SD_BUS_ERROR_TIMEOUT)
735 {
736 log<level::ERR>(
737 fmt::format("GUARD D-Bus call exception"
738 "OBJPATH={}, INTERFACE={}, EXCEPTION={}",
739 object_path::hwIsolation,
740 interface::hwIsolationCreate, e.what())
741 .c_str());
742 }
743 }
744}
Sumit Kumar3e274432021-09-14 06:37:56 -0500745
746void DataInterface::createProgressSRC(
747 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
748{
749 DBusValue variant = std::make_tuple(priSRC, srcStruct);
750
751 auto method = _bus.new_method_call(service_name::bootRawProgress,
752 object_path::bootRawSetting,
753 interface::dbusProperty, "Set");
754
755 method.append(interface::bootRawProgress, "Value", variant);
756
Matt Spinler35a405b2022-03-02 11:42:42 -0600757 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500758}
Sumit Kumar027bf282022-01-24 11:25:19 -0600759
760std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
761{
762 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
763 std::string hwErrorLog = "/isolated_hw_errorlog";
764 std::string errorLog = "/error_log";
765 DBusPathList paths;
766 std::vector<uint32_t> ids;
767
768 // Get all latest mapper associations
769 paths = getPaths(association);
770 for (auto& path : paths)
771 {
772 // Look for object path with hardware isolation entry if any
773 size_t pos = path.find(hwErrorLog);
774 if (pos != std::string::npos)
775 {
776 // Get the object path
777 std::string ph = path;
778 ph.erase(pos, hwErrorLog.length());
779 auto service = getService(ph, interface::hwIsolationEntry);
780 if (!service.empty())
781 {
782 bool status;
783 DBusValue value;
784
785 // Read the Resolved property from object path
786 getProperty(service, ph, interface::hwIsolationEntry,
787 "Resolved", value);
788
789 status = std::get<bool>(value);
790
791 // If the entry isn't resolved
792 if (!status)
793 {
794 auto service = getService(path, interface::association);
795 if (!service.empty())
796 {
797 DBusValue value;
798
799 // Read Endpoints property
800 getProperty(service, path, interface::association,
801 "endpoints", value);
802
803 auto logPath =
804 std::get<std::vector<std::string>>(value);
805 if (!logPath.empty())
806 {
807 // Get OpenBMC event log Id
808 uint32_t id = stoi(logPath[0].substr(
809 logPath[0].find_last_of('/') + 1));
810 ids.push_back(id);
811 }
812 }
813 }
814 }
815 }
816
817 // Look for object path with error_log entry if any
818 pos = path.find(errorLog);
819 if (pos != std::string::npos)
820 {
821 auto service = getService(path, interface::association);
822 if (!service.empty())
823 {
824 DBusValue value;
825
826 // Read Endpoints property
827 getProperty(service, path, interface::association, "endpoints",
828 value);
829
830 auto logPath = std::get<std::vector<std::string>>(value);
831 if (!logPath.empty())
832 {
833 // Get OpenBMC event log Id
834 uint32_t id = stoi(
835 logPath[0].substr(logPath[0].find_last_of('/') + 1));
836 ids.push_back(id);
837 }
838 }
839 }
840 }
841
842 if (ids.size() > 1)
843 {
844 // remove duplicates to have only unique ids
845 std::sort(ids.begin(), ids.end());
846 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
847 }
848 return ids;
849}
Matt Spinlerc8705e22019-09-11 12:36:07 -0500850} // namespace pels
851} // namespace openpower