blob: da499db0369dbc6b5d6a47cc46eca788797c215d [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 Spinlerc8705e22019-09-11 12:36:07 -050029namespace openpower
30{
31namespace pels
32{
33
34namespace service_name
35{
36constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050037constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050038constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050039constexpr auto logSetting = "xyz.openbmc_project.Settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050040constexpr auto hwIsolation = "org.open_power.HardwareIsolation";
Matt Spinlerc8705e22019-09-11 12:36:07 -050041} // namespace service_name
42
43namespace object_path
44{
45constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
46constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050047constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050048constexpr auto motherBoardInv =
49 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060050constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060051constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
52constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060053constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060054constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060055constexpr auto enableHostPELs =
56 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050057constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050058constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050059constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Matt Spinlerc8705e22019-09-11 12:36:07 -050060} // namespace object_path
61
62namespace interface
63{
64constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
65constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
66constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060067constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinlerb3f51862019-12-09 13:55:10 -060068constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060069constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060070constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
71constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
72constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060073constexpr auto invMotherboard =
74 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
75constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050076constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinler60c4e792020-03-13 13:45:36 -050077constexpr auto locCode = "com.ibm.ipzvpd.Location";
Matt Spinler1ab66962020-10-29 13:21:44 -050078constexpr auto compatible =
79 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050080constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050081constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050082constexpr auto operationalStatus =
83 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050084constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar76198a22021-07-15 05:59:57 -050085constexpr auto association = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050086constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
87constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050088constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Matt Spinlerc8705e22019-09-11 12:36:07 -050089} // namespace interface
90
Matt Spinlerf10068d2020-12-02 10:44:08 -060091using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
Vijay Lobo81b4dca2021-04-29 00:04:00 -050092using namespace phosphor::logging;
Matt Spinlera7d9d962019-11-06 15:01:25 -060093
Matt Spinler0d92b522021-06-16 13:28:17 -060094std::pair<std::string, std::string>
95 DataInterfaceBase::extractConnectorFromLocCode(
96 const std::string& locationCode)
97{
98 auto base = locationCode;
99 std::string connector{};
100
101 auto pos = base.find("-T");
102 if (pos != std::string::npos)
103 {
104 connector = base.substr(pos);
105 base = base.substr(0, pos);
106 }
107
108 return {base, connector};
109}
110
Matt Spinlerc8705e22019-09-11 12:36:07 -0500111DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus)
112{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600113 readBMCFWVersion();
114 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600115 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600116
Matt Spinlerf10068d2020-12-02 10:44:08 -0600117 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600118 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600119 bus, object_path::hostState, interface::bootProgress, "BootProgress",
120 *this, [this](const auto& value) {
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500121 this->_bootState = std::get<std::string>(value);
Matt Spinlerf10068d2020-12-02 10:44:08 -0600122 auto status = Progress::convertProgressStagesFromString(
123 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600124
Matt Spinlerf10068d2020-12-02 10:44:08 -0600125 if ((status == Progress::ProgressStages::SystemInitComplete) ||
126 (status == Progress::ProgressStages::OSStart) ||
127 (status == Progress::ProgressStages::OSRunning))
Matt Spinler2a28c932020-02-03 14:23:40 -0600128 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600129 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600130 }
131 else
132 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600133 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600134 }
135 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600136
137 // Watch the host PEL enable property
138 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
139 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
140 [this](const auto& value) {
141 this->_sendPELsToHost = std::get<bool>(value);
142 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600143
144 // Watch the BMCState property
145 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
146 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
147 *this, [this](const auto& value) {
148 this->_bmcState = std::get<std::string>(value);
149 }));
150
151 // Watch the chassis current and requested power state properties
152 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
153 bus, object_path::chassisState, interface::chassisState, *this,
154 [this](const auto& properties) {
155 auto state = properties.find("CurrentPowerState");
156 if (state != properties.end())
157 {
158 this->_chassisState = std::get<std::string>(state->second);
159 }
160
161 auto trans = properties.find("RequestedPowerTransition");
162 if (trans != properties.end())
163 {
164 this->_chassisTransition = std::get<std::string>(trans->second);
165 }
166 }));
167
168 // Watch the CurrentHostState property
169 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
170 bus, object_path::hostState, interface::hostState, "CurrentHostState",
171 *this, [this](const auto& value) {
172 this->_hostState = std::get<std::string>(value);
173 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500174}
175
Matt Spinler2a28c932020-02-03 14:23:40 -0600176DBusPropertyMap
177 DataInterface::getAllProperties(const std::string& service,
178 const std::string& objectPath,
179 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500180{
181 DBusPropertyMap properties;
182
183 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
184 interface::dbusProperty, "GetAll");
185 method.append(interface);
186 auto reply = _bus.call(method);
187
188 reply.read(properties);
189
190 return properties;
191}
192
Matt Spinlera7d9d962019-11-06 15:01:25 -0600193void DataInterface::getProperty(const std::string& service,
194 const std::string& objectPath,
195 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600196 const std::string& property,
197 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600198{
199
200 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
201 interface::dbusProperty, "Get");
202 method.append(interface, property);
203 auto reply = _bus.call(method);
204
205 reply.read(value);
206}
207
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600208DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
209{
210
211 auto method = _bus.new_method_call(
212 service_name::objectMapper, object_path::objectMapper,
213 interface::objectMapper, "GetSubTreePaths");
214
215 method.append(std::string{"/"}, 0, interfaces);
216
217 auto reply = _bus.call(method);
218
219 DBusPathList paths;
220 reply.read(paths);
221
222 return paths;
223}
224
Matt Spinlerc8705e22019-09-11 12:36:07 -0500225DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600226 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500227{
228 auto method = _bus.new_method_call(service_name::objectMapper,
229 object_path::objectMapper,
230 interface::objectMapper, "GetObject");
231
232 method.append(objectPath, std::vector<std::string>({interface}));
233
234 auto reply = _bus.call(method);
235
236 std::map<DBusService, DBusInterfaceList> response;
237 reply.read(response);
238
239 if (!response.empty())
240 {
241 return response.begin()->first;
242 }
243
244 return std::string{};
245}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600246
Matt Spinler677381b2020-01-23 10:04:29 -0600247void DataInterface::readBMCFWVersion()
248{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500249 _bmcFWVersion =
250 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600251}
252
253void DataInterface::readServerFWVersion()
254{
Sumit Kumarcad16202021-05-13 04:06:15 -0500255 auto value =
256 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
257 if ((value != "") && (value.find_last_of(')') != std::string::npos))
258 {
259 std::size_t pos = value.find_first_of('(') + 1;
260 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
261 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600262}
263
Matt Spinler677381b2020-01-23 10:04:29 -0600264void DataInterface::readBMCFWVersionID()
265{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500266 _bmcFWVersionID =
267 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600268}
269
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500270std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600271{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500272 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600273 try
274 {
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600275
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500276 auto service = getService(object_path::systemInv, interface::invAsset);
277 if (!service.empty())
278 {
279 DBusValue value;
280 getProperty(service, object_path::systemInv, interface::invAsset,
281 "Model", value);
282
283 model = std::get<std::string>(value);
284 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600285 }
286 catch (const std::exception& e)
287 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500288 log<level::WARNING>(fmt::format("Failed reading Model property from "
289 "Interface: {} exception: {}",
290 interface::invAsset, e.what())
291 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600292 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500293
294 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600295}
296
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500297std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600298{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500299 std::string sn;
300 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600301 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500302
303 auto service = getService(object_path::systemInv, interface::invAsset);
304 if (!service.empty())
305 {
306 DBusValue value;
307 getProperty(service, object_path::systemInv, interface::invAsset,
308 "SerialNumber", value);
309
310 sn = std::get<std::string>(value);
311 }
312 }
313 catch (const std::exception& e)
314 {
315 log<level::WARNING>(
316 fmt::format("Failed reading SerialNumber property from "
317 "Interface: {} exception: {}",
318 interface::invAsset, e.what())
319 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600320 }
321
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500322 return sn;
323}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600324
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500325std::string DataInterface::getMotherboardCCIN() const
326{
327 std::string ccin;
328
329 try
330 {
331 auto service =
332 getService(object_path::motherBoardInv, interface::viniRecordVPD);
333 if (!service.empty())
334 {
335 DBusValue value;
336 getProperty(service, object_path::motherBoardInv,
337 interface::viniRecordVPD, "CC", value);
338
339 auto cc = std::get<std::vector<uint8_t>>(value);
340 ccin = std::string{cc.begin(), cc.end()};
341 }
342 }
343 catch (const std::exception& e)
344 {
345 log<level::WARNING>(
346 fmt::format("Failed reading Motherboard CCIN property from "
347 "Interface: {} exception: {}",
348 interface::viniRecordVPD, e.what())
349 .c_str());
350 }
351
352 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600353}
354
Ben Tynere32b7e72021-05-18 12:38:40 -0500355std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
356{
357 std::vector<uint8_t> systemIM;
358
359 try
360 {
361 auto service =
362 getService(object_path::motherBoardInv, interface::vsbpRecordVPD);
363 if (!service.empty())
364 {
365 DBusValue value;
366 getProperty(service, object_path::motherBoardInv,
367 interface::vsbpRecordVPD, "IM", value);
368
369 systemIM = std::get<std::vector<uint8_t>>(value);
370 }
371 }
372 catch (const std::exception& e)
373 {
374 log<level::WARNING>(
375 fmt::format("Failed reading System IM property from "
376 "Interface: {} exception: {}",
377 interface::vsbpRecordVPD, e.what())
378 .c_str());
379 }
380
381 return systemIM;
382}
383
Matt Spinler60c4e792020-03-13 13:45:36 -0500384void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500385 std::string& fruPartNumber,
386 std::string& ccin,
387 std::string& serialNumber) const
388{
389 // For now, attempt to get all of the properties directly on the path
390 // passed in. In the future, may need to make use of an algorithm
391 // to figure out which inventory objects actually hold these
392 // interfaces in the case of non FRUs, or possibly another service
393 // will provide this info. Any missing interfaces will result
394 // in exceptions being thrown.
395
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500396 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500397
398 auto properties =
399 getAllProperties(service, inventoryPath, interface::viniRecordVPD);
400
401 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
402 fruPartNumber = std::string{value.begin(), value.end()};
403
404 value = std::get<std::vector<uint8_t>>(properties["CC"]);
405 ccin = std::string{value.begin(), value.end()};
406
407 value = std::get<std::vector<uint8_t>>(properties["SN"]);
408 serialNumber = std::string{value.begin(), value.end()};
409}
410
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500411std::string
412 DataInterface::getLocationCode(const std::string& inventoryPath) const
413{
414 auto service = getService(inventoryPath, interface::locCode);
415
416 DBusValue locCode;
417 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
418 locCode);
419
420 return std::get<std::string>(locCode);
421}
422
Matt Spinler5fb24c12020-06-04 11:21:33 -0500423std::string
424 DataInterface::addLocationCodePrefix(const std::string& locationCode)
425{
426 static const std::string locationCodePrefix{"Ufcs-"};
427
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500428 // Technically there are 2 location code prefixes, Ufcs and Umts, so
429 // if it already starts with a U then don't need to do anything.
430 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500431 {
432 return locationCodePrefix + locationCode;
433 }
434
435 return locationCode;
436}
437
438std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500439 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500440{
Matt Spinler0d92b522021-06-16 13:28:17 -0600441 // Location codes for connectors are the location code of the FRU they are
442 // on, plus a '-Tx' segment. Remove this last segment before expanding it
443 // and then add it back in afterwards. This way, the connector doesn't have
444 // to be in the model just so that it can be expanded.
445 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
446
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500447 auto method =
448 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
449 interface::vpdManager, "GetExpandedLocationCode");
450
Matt Spinler0d92b522021-06-16 13:28:17 -0600451 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500452
453 auto reply = _bus.call(method);
454
455 std::string expandedLocationCode;
456 reply.read(expandedLocationCode);
457
Matt Spinler0d92b522021-06-16 13:28:17 -0600458 if (!connectorLoc.empty())
459 {
460 expandedLocationCode += connectorLoc;
461 }
462
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500463 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500464}
465
Matt Spinler2f9225a2020-08-05 12:58:49 -0500466std::string
467 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
468 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500469{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500470 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
471 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500472
Matt Spinler0d92b522021-06-16 13:28:17 -0600473 // Remove the connector segment, if present, so that this method call
474 // returns an inventory path that getHWCalloutFields() can be used with.
475 // (The serial number, etc, aren't stored on the connector in the
476 // inventory, and may not even be modeled.)
477 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
478
Matt Spinler2f9225a2020-08-05 12:58:49 -0500479 auto method =
480 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
481 interface::vpdManager, methodName.c_str());
482
483 if (expanded)
484 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600485 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500486 }
487 else
488 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600489 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500490 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500491
492 auto reply = _bus.call(method);
493
494 std::vector<sdbusplus::message::object_path> entries;
495 reply.read(entries);
496
497 // Get the shortest entry from the paths received, as this
498 // would be the path furthest up the inventory hierarchy so
499 // would be the parent FRU. There is guaranteed to at least
500 // be one entry if the call didn't fail.
501 std::string shortest{entries[0]};
502
503 std::for_each(entries.begin(), entries.end(),
504 [&shortest](const auto& path) {
505 if (path.str.size() < shortest.size())
506 {
507 shortest = path;
508 }
509 });
510
511 return shortest;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500512}
513
Matt Spinler34a904c2020-08-05 14:53:28 -0500514void DataInterface::assertLEDGroup(const std::string& ledGroup,
515 bool value) const
516{
517 DBusValue variant = value;
518 auto method =
519 _bus.new_method_call(service_name::ledGroupManager, ledGroup.c_str(),
520 interface::dbusProperty, "Set");
521 method.append(interface::ledGroup, "Asserted", variant);
522 _bus.call(method);
523}
524
Matt Spinler993168d2021-04-07 16:05:03 -0500525void DataInterface::setFunctional(const std::string& objectPath,
526 bool value) const
527{
528 DBusValue variant = value;
529 auto service = getService(objectPath, interface::operationalStatus);
530
531 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
532 interface::dbusProperty, "Set");
533
534 method.append(interface::operationalStatus, "Functional", variant);
535 _bus.call(method);
536}
537
Sumit Kumar76198a22021-07-15 05:59:57 -0500538using AssociationTuple = std::tuple<std::string, std::string, std::string>;
539using AssociationsProperty = std::vector<AssociationTuple>;
540
541void DataInterface::setCriticalAssociation(const std::string& objectPath) const
542{
543 DBusValue getAssociationValue;
544
545 auto service = getService(objectPath, interface::association);
546
547 getProperty(service, objectPath, interface::association, "Associations",
548 getAssociationValue);
549
550 auto association = std::get<AssociationsProperty>(getAssociationValue);
551
552 AssociationTuple critAssociation{
553 "health_rollup", "critical",
554 "/xyz/openbmc_project/inventory/system/chassis"};
555
556 if (std::find(association.begin(), association.end(), critAssociation) ==
557 association.end())
558 {
559 association.push_back(critAssociation);
560 DBusValue setAssociationValue = association;
561
562 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
563 interface::dbusProperty, "Set");
564
565 method.append(interface::association, "Associations",
566 setAssociationValue);
567 _bus.call(method);
568 }
569}
570
Matt Spinler1ab66962020-10-29 13:21:44 -0500571std::vector<std::string> DataInterface::getSystemNames() const
572{
573 DBusSubTree subtree;
574 DBusValue names;
575
576 auto method = _bus.new_method_call(service_name::objectMapper,
577 object_path::objectMapper,
578 interface::objectMapper, "GetSubTree");
579 method.append(std::string{"/"}, 0,
580 std::vector<std::string>{interface::compatible});
581 auto reply = _bus.call(method);
582
583 reply.read(subtree);
584 if (subtree.empty())
585 {
586 throw std::runtime_error("Compatible interface not on D-Bus");
587 }
588
589 const auto& object = *(subtree.begin());
590 const auto& path = object.first;
591 const auto& service = object.second.begin()->first;
592
593 getProperty(service, path, interface::compatible, "Names", names);
594
595 return std::get<std::vector<std::string>>(names);
596}
597
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500598bool DataInterface::getQuiesceOnError() const
599{
600 bool ret = false;
601
602 try
603 {
604 auto service =
605 getService(object_path::logSetting, interface::logSetting);
606 if (!service.empty())
607 {
608 DBusValue value;
609 getProperty(service, object_path::logSetting, interface::logSetting,
610 "QuiesceOnHwError", value);
611
612 ret = std::get<bool>(value);
613 }
614 }
615 catch (const std::exception& e)
616 {
617 log<level::WARNING>(
618 fmt::format("Failed reading QuiesceOnHwError property from "
619 "Interface: {} exception: {}",
620 interface::logSetting, e.what())
621 .c_str());
622 }
623
624 return ret;
625}
626
Sumit Kumar9d43a722021-08-24 09:46:19 -0500627std::vector<bool>
628 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
629{
630 DBusSubTree subtree;
631 std::vector<bool> result(type.size(), false);
632
633 // Query GetSubTree for the availability of dump interface
634 auto method = _bus.new_method_call(service_name::objectMapper,
635 object_path::objectMapper,
636 interface::objectMapper, "GetSubTree");
637 method.append(std::string{"/"}, 0,
638 std::vector<std::string>{interface::dumpEntry});
639 auto reply = _bus.call(method);
640
641 reply.read(subtree);
642
643 if (subtree.empty())
644 {
645 return result;
646 }
647
648 std::vector<bool>::iterator itDumpStatus = result.begin();
649 uint8_t count = 0;
650 for (const auto& [path, serviceInfo] : subtree)
651 {
652 const auto& service = serviceInfo.begin()->first;
653 // Check for dump type on the object path
654 for (const auto& it : type)
655 {
656 if (path.find(it) != std::string::npos)
657 {
658 DBusValue value, progress;
659
660 // If dump type status is already available go for next path
661 if (*itDumpStatus)
662 {
663 break;
664 }
665
666 // Check for valid dump to be available if following
667 // conditions are met for the dump entry path -
668 // Offloaded == false and Status == Completed
669 getProperty(service, path, interface::dumpEntry, "Offloaded",
670 value);
671 getProperty(service, path, interface::dumpProgress, "Status",
672 progress);
673 auto offload = std::get<bool>(value);
674 auto status = std::get<std::string>(progress);
675 if (!offload && (status.find("Completed") != std::string::npos))
676 {
677 *itDumpStatus = true;
678 count++;
679 if (count >= type.size())
680 {
681 return result;
682 }
683 break;
684 }
685 }
686 itDumpStatus++;
687 }
688 itDumpStatus = result.begin();
689 }
690
691 return result;
692}
693
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500694void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
695 const std::string& type,
696 const std::string& logPath) const
697{
698 try
699 {
700 auto method = _bus.new_method_call(
701 service_name::hwIsolation, object_path::hwIsolation,
702 interface::hwIsolationCreate, "CreateWithEntityPath");
703 method.append(binPath, type, sdbusplus::message::object_path(logPath));
704 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
705 // api's. Making d-bus call no reply type to avoid cyclic dependency.
706 // Added minimal timeout to catch initial failures.
707 // Need to revisit this design later to avoid cyclic dependency.
708 constexpr auto dbusTimeout = 100000; // in micro seconds
709 _bus.call_noreply(method, dbusTimeout);
710 }
711
712 catch (const sdbusplus::exception::exception& e)
713 {
714 std::string errName = e.name();
715 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
716 // mentioned above. Ignoring the error.
717 if (errName != SD_BUS_ERROR_TIMEOUT)
718 {
719 log<level::ERR>(
720 fmt::format("GUARD D-Bus call exception"
721 "OBJPATH={}, INTERFACE={}, EXCEPTION={}",
722 object_path::hwIsolation,
723 interface::hwIsolationCreate, e.what())
724 .c_str());
725 }
726 }
727}
Matt Spinlerc8705e22019-09-11 12:36:07 -0500728} // namespace pels
729} // namespace openpower