blob: 9f0a218615f75ac0ca20f48c20e958e830611f52 [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";
Sumit Kumar3e274432021-09-14 06:37:56 -050041constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinlerc8705e22019-09-11 12:36:07 -050042} // namespace service_name
43
44namespace object_path
45{
46constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
47constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050048constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050049constexpr auto motherBoardInv =
50 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060051constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060052constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
53constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060054constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060055constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060056constexpr auto enableHostPELs =
57 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050058constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050059constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050060constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Sumit Kumar3e274432021-09-14 06:37:56 -050061constexpr auto bootRawSetting = "/xyz/openbmc_project/state/boot/raw0";
Matt Spinlerc8705e22019-09-11 12:36:07 -050062} // namespace object_path
63
64namespace interface
65{
66constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
67constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
68constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060069constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinlerb3f51862019-12-09 13:55:10 -060070constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060071constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060072constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
73constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
74constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060075constexpr auto invMotherboard =
76 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
77constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050078constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060079constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050080constexpr auto compatible =
81 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050082constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050083constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050084constexpr auto operationalStatus =
85 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050086constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar76198a22021-07-15 05:59:57 -050087constexpr auto association = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050088constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
89constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050090constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar3e274432021-09-14 06:37:56 -050091constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinlerc8705e22019-09-11 12:36:07 -050092} // namespace interface
93
Matt Spinlerf10068d2020-12-02 10:44:08 -060094using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
Vijay Lobo81b4dca2021-04-29 00:04:00 -050095using namespace phosphor::logging;
Matt Spinlera7d9d962019-11-06 15:01:25 -060096
Matt Spinler0d92b522021-06-16 13:28:17 -060097std::pair<std::string, std::string>
98 DataInterfaceBase::extractConnectorFromLocCode(
99 const std::string& locationCode)
100{
101 auto base = locationCode;
102 std::string connector{};
103
104 auto pos = base.find("-T");
105 if (pos != std::string::npos)
106 {
107 connector = base.substr(pos);
108 base = base.substr(0, pos);
109 }
110
111 return {base, connector};
112}
113
Matt Spinlerc8705e22019-09-11 12:36:07 -0500114DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus)
115{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600116 readBMCFWVersion();
117 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600118 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600119
Matt Spinlerf10068d2020-12-02 10:44:08 -0600120 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600121 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600122 bus, object_path::hostState, interface::bootProgress, "BootProgress",
123 *this, [this](const auto& value) {
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500124 this->_bootState = std::get<std::string>(value);
Matt Spinlerf10068d2020-12-02 10:44:08 -0600125 auto status = Progress::convertProgressStagesFromString(
126 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600127
Matt Spinlerf10068d2020-12-02 10:44:08 -0600128 if ((status == Progress::ProgressStages::SystemInitComplete) ||
129 (status == Progress::ProgressStages::OSStart) ||
130 (status == Progress::ProgressStages::OSRunning))
Matt Spinler2a28c932020-02-03 14:23:40 -0600131 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600132 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600133 }
134 else
135 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600136 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600137 }
138 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600139
140 // Watch the host PEL enable property
141 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
142 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
143 [this](const auto& value) {
Matt Spinlerc6ee7c52022-01-14 13:21:53 -0600144 if (std::get<bool>(value) != this->_sendPELsToHost)
145 {
146 log<level::INFO>(
147 fmt::format("The send PELs to host setting changed to {}",
148 std::get<bool>(value))
149 .c_str());
150 }
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600151 this->_sendPELsToHost = std::get<bool>(value);
152 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600153
154 // Watch the BMCState property
155 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
156 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
157 *this, [this](const auto& value) {
158 this->_bmcState = std::get<std::string>(value);
159 }));
160
161 // Watch the chassis current and requested power state properties
162 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
163 bus, object_path::chassisState, interface::chassisState, *this,
164 [this](const auto& properties) {
165 auto state = properties.find("CurrentPowerState");
166 if (state != properties.end())
167 {
168 this->_chassisState = std::get<std::string>(state->second);
169 }
170
171 auto trans = properties.find("RequestedPowerTransition");
172 if (trans != properties.end())
173 {
174 this->_chassisTransition = std::get<std::string>(trans->second);
175 }
176 }));
177
178 // Watch the CurrentHostState property
179 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
180 bus, object_path::hostState, interface::hostState, "CurrentHostState",
181 *this, [this](const auto& value) {
182 this->_hostState = std::get<std::string>(value);
183 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500184}
185
Matt Spinler2a28c932020-02-03 14:23:40 -0600186DBusPropertyMap
187 DataInterface::getAllProperties(const std::string& service,
188 const std::string& objectPath,
189 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500190{
191 DBusPropertyMap properties;
192
193 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
194 interface::dbusProperty, "GetAll");
195 method.append(interface);
196 auto reply = _bus.call(method);
197
198 reply.read(properties);
199
200 return properties;
201}
202
Matt Spinlera7d9d962019-11-06 15:01:25 -0600203void DataInterface::getProperty(const std::string& service,
204 const std::string& objectPath,
205 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600206 const std::string& property,
207 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600208{
209
210 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
211 interface::dbusProperty, "Get");
212 method.append(interface, property);
213 auto reply = _bus.call(method);
214
215 reply.read(value);
216}
217
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600218DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
219{
220
221 auto method = _bus.new_method_call(
222 service_name::objectMapper, object_path::objectMapper,
223 interface::objectMapper, "GetSubTreePaths");
224
225 method.append(std::string{"/"}, 0, interfaces);
226
227 auto reply = _bus.call(method);
228
229 DBusPathList paths;
230 reply.read(paths);
231
232 return paths;
233}
234
Matt Spinlerc8705e22019-09-11 12:36:07 -0500235DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600236 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500237{
238 auto method = _bus.new_method_call(service_name::objectMapper,
239 object_path::objectMapper,
240 interface::objectMapper, "GetObject");
241
242 method.append(objectPath, std::vector<std::string>({interface}));
243
244 auto reply = _bus.call(method);
245
246 std::map<DBusService, DBusInterfaceList> response;
247 reply.read(response);
248
249 if (!response.empty())
250 {
251 return response.begin()->first;
252 }
253
254 return std::string{};
255}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600256
Matt Spinler677381b2020-01-23 10:04:29 -0600257void DataInterface::readBMCFWVersion()
258{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500259 _bmcFWVersion =
260 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600261}
262
263void DataInterface::readServerFWVersion()
264{
Sumit Kumarcad16202021-05-13 04:06:15 -0500265 auto value =
266 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
267 if ((value != "") && (value.find_last_of(')') != std::string::npos))
268 {
269 std::size_t pos = value.find_first_of('(') + 1;
270 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
271 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600272}
273
Matt Spinler677381b2020-01-23 10:04:29 -0600274void DataInterface::readBMCFWVersionID()
275{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500276 _bmcFWVersionID =
277 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600278}
279
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500280std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600281{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500282 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600283 try
284 {
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600285
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500286 auto service = getService(object_path::systemInv, interface::invAsset);
287 if (!service.empty())
288 {
289 DBusValue value;
290 getProperty(service, object_path::systemInv, interface::invAsset,
291 "Model", value);
292
293 model = std::get<std::string>(value);
294 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600295 }
296 catch (const std::exception& e)
297 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500298 log<level::WARNING>(fmt::format("Failed reading Model property from "
299 "Interface: {} exception: {}",
300 interface::invAsset, e.what())
301 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600302 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500303
304 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600305}
306
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500307std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600308{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500309 std::string sn;
310 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600311 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500312
313 auto service = getService(object_path::systemInv, interface::invAsset);
314 if (!service.empty())
315 {
316 DBusValue value;
317 getProperty(service, object_path::systemInv, interface::invAsset,
318 "SerialNumber", value);
319
320 sn = std::get<std::string>(value);
321 }
322 }
323 catch (const std::exception& e)
324 {
325 log<level::WARNING>(
326 fmt::format("Failed reading SerialNumber property from "
327 "Interface: {} exception: {}",
328 interface::invAsset, e.what())
329 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600330 }
331
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500332 return sn;
333}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600334
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500335std::string DataInterface::getMotherboardCCIN() const
336{
337 std::string ccin;
338
339 try
340 {
341 auto service =
342 getService(object_path::motherBoardInv, interface::viniRecordVPD);
343 if (!service.empty())
344 {
345 DBusValue value;
346 getProperty(service, object_path::motherBoardInv,
347 interface::viniRecordVPD, "CC", value);
348
349 auto cc = std::get<std::vector<uint8_t>>(value);
350 ccin = std::string{cc.begin(), cc.end()};
351 }
352 }
353 catch (const std::exception& e)
354 {
355 log<level::WARNING>(
356 fmt::format("Failed reading Motherboard CCIN property from "
357 "Interface: {} exception: {}",
358 interface::viniRecordVPD, e.what())
359 .c_str());
360 }
361
362 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600363}
364
Ben Tynere32b7e72021-05-18 12:38:40 -0500365std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
366{
367 std::vector<uint8_t> systemIM;
368
369 try
370 {
371 auto service =
372 getService(object_path::motherBoardInv, interface::vsbpRecordVPD);
373 if (!service.empty())
374 {
375 DBusValue value;
376 getProperty(service, object_path::motherBoardInv,
377 interface::vsbpRecordVPD, "IM", value);
378
379 systemIM = std::get<std::vector<uint8_t>>(value);
380 }
381 }
382 catch (const std::exception& e)
383 {
384 log<level::WARNING>(
385 fmt::format("Failed reading System IM property from "
386 "Interface: {} exception: {}",
387 interface::vsbpRecordVPD, e.what())
388 .c_str());
389 }
390
391 return systemIM;
392}
393
Matt Spinler60c4e792020-03-13 13:45:36 -0500394void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500395 std::string& fruPartNumber,
396 std::string& ccin,
397 std::string& serialNumber) const
398{
399 // For now, attempt to get all of the properties directly on the path
400 // passed in. In the future, may need to make use of an algorithm
401 // to figure out which inventory objects actually hold these
402 // interfaces in the case of non FRUs, or possibly another service
403 // will provide this info. Any missing interfaces will result
404 // in exceptions being thrown.
405
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500406 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500407
408 auto properties =
409 getAllProperties(service, inventoryPath, interface::viniRecordVPD);
410
411 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
412 fruPartNumber = std::string{value.begin(), value.end()};
413
414 value = std::get<std::vector<uint8_t>>(properties["CC"]);
415 ccin = std::string{value.begin(), value.end()};
416
417 value = std::get<std::vector<uint8_t>>(properties["SN"]);
418 serialNumber = std::string{value.begin(), value.end()};
419}
420
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500421std::string
422 DataInterface::getLocationCode(const std::string& inventoryPath) const
423{
424 auto service = getService(inventoryPath, interface::locCode);
425
426 DBusValue locCode;
427 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
428 locCode);
429
430 return std::get<std::string>(locCode);
431}
432
Matt Spinler5fb24c12020-06-04 11:21:33 -0500433std::string
434 DataInterface::addLocationCodePrefix(const std::string& locationCode)
435{
436 static const std::string locationCodePrefix{"Ufcs-"};
437
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500438 // Technically there are 2 location code prefixes, Ufcs and Umts, so
439 // if it already starts with a U then don't need to do anything.
440 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500441 {
442 return locationCodePrefix + locationCode;
443 }
444
445 return locationCode;
446}
447
448std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500449 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500450{
Matt Spinler0d92b522021-06-16 13:28:17 -0600451 // Location codes for connectors are the location code of the FRU they are
452 // on, plus a '-Tx' segment. Remove this last segment before expanding it
453 // and then add it back in afterwards. This way, the connector doesn't have
454 // to be in the model just so that it can be expanded.
455 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
456
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500457 auto method =
458 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
459 interface::vpdManager, "GetExpandedLocationCode");
460
Matt Spinler0d92b522021-06-16 13:28:17 -0600461 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500462
463 auto reply = _bus.call(method);
464
465 std::string expandedLocationCode;
466 reply.read(expandedLocationCode);
467
Matt Spinler0d92b522021-06-16 13:28:17 -0600468 if (!connectorLoc.empty())
469 {
470 expandedLocationCode += connectorLoc;
471 }
472
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500473 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500474}
475
Matt Spinler2f9225a2020-08-05 12:58:49 -0500476std::string
477 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
478 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500479{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500480 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
481 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500482
Matt Spinler0d92b522021-06-16 13:28:17 -0600483 // Remove the connector segment, if present, so that this method call
484 // returns an inventory path that getHWCalloutFields() can be used with.
485 // (The serial number, etc, aren't stored on the connector in the
486 // inventory, and may not even be modeled.)
487 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
488
Matt Spinler2f9225a2020-08-05 12:58:49 -0500489 auto method =
490 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
491 interface::vpdManager, methodName.c_str());
492
493 if (expanded)
494 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600495 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500496 }
497 else
498 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600499 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500500 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500501
502 auto reply = _bus.call(method);
503
504 std::vector<sdbusplus::message::object_path> entries;
505 reply.read(entries);
506
507 // Get the shortest entry from the paths received, as this
508 // would be the path furthest up the inventory hierarchy so
509 // would be the parent FRU. There is guaranteed to at least
510 // be one entry if the call didn't fail.
511 std::string shortest{entries[0]};
512
513 std::for_each(entries.begin(), entries.end(),
514 [&shortest](const auto& path) {
515 if (path.str.size() < shortest.size())
516 {
517 shortest = path;
518 }
519 });
520
521 return shortest;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500522}
523
Matt Spinler34a904c2020-08-05 14:53:28 -0500524void DataInterface::assertLEDGroup(const std::string& ledGroup,
525 bool value) const
526{
527 DBusValue variant = value;
528 auto method =
529 _bus.new_method_call(service_name::ledGroupManager, ledGroup.c_str(),
530 interface::dbusProperty, "Set");
531 method.append(interface::ledGroup, "Asserted", variant);
532 _bus.call(method);
533}
534
Matt Spinler993168d2021-04-07 16:05:03 -0500535void DataInterface::setFunctional(const std::string& objectPath,
536 bool value) const
537{
538 DBusValue variant = value;
539 auto service = getService(objectPath, interface::operationalStatus);
540
541 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
542 interface::dbusProperty, "Set");
543
544 method.append(interface::operationalStatus, "Functional", variant);
545 _bus.call(method);
546}
547
Sumit Kumar76198a22021-07-15 05:59:57 -0500548using AssociationTuple = std::tuple<std::string, std::string, std::string>;
549using AssociationsProperty = std::vector<AssociationTuple>;
550
551void DataInterface::setCriticalAssociation(const std::string& objectPath) const
552{
553 DBusValue getAssociationValue;
554
555 auto service = getService(objectPath, interface::association);
556
557 getProperty(service, objectPath, interface::association, "Associations",
558 getAssociationValue);
559
560 auto association = std::get<AssociationsProperty>(getAssociationValue);
561
562 AssociationTuple critAssociation{
563 "health_rollup", "critical",
564 "/xyz/openbmc_project/inventory/system/chassis"};
565
566 if (std::find(association.begin(), association.end(), critAssociation) ==
567 association.end())
568 {
569 association.push_back(critAssociation);
570 DBusValue setAssociationValue = association;
571
572 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
573 interface::dbusProperty, "Set");
574
575 method.append(interface::association, "Associations",
576 setAssociationValue);
577 _bus.call(method);
578 }
579}
580
Matt Spinler1ab66962020-10-29 13:21:44 -0500581std::vector<std::string> DataInterface::getSystemNames() const
582{
583 DBusSubTree subtree;
584 DBusValue names;
585
586 auto method = _bus.new_method_call(service_name::objectMapper,
587 object_path::objectMapper,
588 interface::objectMapper, "GetSubTree");
589 method.append(std::string{"/"}, 0,
590 std::vector<std::string>{interface::compatible});
591 auto reply = _bus.call(method);
592
593 reply.read(subtree);
594 if (subtree.empty())
595 {
596 throw std::runtime_error("Compatible interface not on D-Bus");
597 }
598
599 const auto& object = *(subtree.begin());
600 const auto& path = object.first;
601 const auto& service = object.second.begin()->first;
602
603 getProperty(service, path, interface::compatible, "Names", names);
604
605 return std::get<std::vector<std::string>>(names);
606}
607
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500608bool DataInterface::getQuiesceOnError() const
609{
610 bool ret = false;
611
612 try
613 {
614 auto service =
615 getService(object_path::logSetting, interface::logSetting);
616 if (!service.empty())
617 {
618 DBusValue value;
619 getProperty(service, object_path::logSetting, interface::logSetting,
620 "QuiesceOnHwError", value);
621
622 ret = std::get<bool>(value);
623 }
624 }
625 catch (const std::exception& e)
626 {
627 log<level::WARNING>(
628 fmt::format("Failed reading QuiesceOnHwError property from "
629 "Interface: {} exception: {}",
630 interface::logSetting, e.what())
631 .c_str());
632 }
633
634 return ret;
635}
636
Sumit Kumar9d43a722021-08-24 09:46:19 -0500637std::vector<bool>
638 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
639{
640 DBusSubTree subtree;
641 std::vector<bool> result(type.size(), false);
642
643 // Query GetSubTree for the availability of dump interface
644 auto method = _bus.new_method_call(service_name::objectMapper,
645 object_path::objectMapper,
646 interface::objectMapper, "GetSubTree");
647 method.append(std::string{"/"}, 0,
648 std::vector<std::string>{interface::dumpEntry});
649 auto reply = _bus.call(method);
650
651 reply.read(subtree);
652
653 if (subtree.empty())
654 {
655 return result;
656 }
657
658 std::vector<bool>::iterator itDumpStatus = result.begin();
659 uint8_t count = 0;
660 for (const auto& [path, serviceInfo] : subtree)
661 {
662 const auto& service = serviceInfo.begin()->first;
663 // Check for dump type on the object path
664 for (const auto& it : type)
665 {
666 if (path.find(it) != std::string::npos)
667 {
668 DBusValue value, progress;
669
670 // If dump type status is already available go for next path
671 if (*itDumpStatus)
672 {
673 break;
674 }
675
676 // Check for valid dump to be available if following
677 // conditions are met for the dump entry path -
678 // Offloaded == false and Status == Completed
679 getProperty(service, path, interface::dumpEntry, "Offloaded",
680 value);
681 getProperty(service, path, interface::dumpProgress, "Status",
682 progress);
683 auto offload = std::get<bool>(value);
684 auto status = std::get<std::string>(progress);
685 if (!offload && (status.find("Completed") != std::string::npos))
686 {
687 *itDumpStatus = true;
688 count++;
689 if (count >= type.size())
690 {
691 return result;
692 }
693 break;
694 }
695 }
696 itDumpStatus++;
697 }
698 itDumpStatus = result.begin();
699 }
700
701 return result;
702}
703
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500704void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
705 const std::string& type,
706 const std::string& logPath) const
707{
708 try
709 {
710 auto method = _bus.new_method_call(
711 service_name::hwIsolation, object_path::hwIsolation,
712 interface::hwIsolationCreate, "CreateWithEntityPath");
713 method.append(binPath, type, sdbusplus::message::object_path(logPath));
714 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
715 // api's. Making d-bus call no reply type to avoid cyclic dependency.
716 // Added minimal timeout to catch initial failures.
717 // Need to revisit this design later to avoid cyclic dependency.
718 constexpr auto dbusTimeout = 100000; // in micro seconds
719 _bus.call_noreply(method, dbusTimeout);
720 }
721
722 catch (const sdbusplus::exception::exception& e)
723 {
724 std::string errName = e.name();
725 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
726 // mentioned above. Ignoring the error.
727 if (errName != SD_BUS_ERROR_TIMEOUT)
728 {
729 log<level::ERR>(
730 fmt::format("GUARD D-Bus call exception"
731 "OBJPATH={}, INTERFACE={}, EXCEPTION={}",
732 object_path::hwIsolation,
733 interface::hwIsolationCreate, e.what())
734 .c_str());
735 }
736 }
737}
Sumit Kumar3e274432021-09-14 06:37:56 -0500738
739void DataInterface::createProgressSRC(
740 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
741{
742 DBusValue variant = std::make_tuple(priSRC, srcStruct);
743
744 auto method = _bus.new_method_call(service_name::bootRawProgress,
745 object_path::bootRawSetting,
746 interface::dbusProperty, "Set");
747
748 method.append(interface::bootRawProgress, "Value", variant);
749
750 _bus.call(method);
751}
Matt Spinlerc8705e22019-09-11 12:36:07 -0500752} // namespace pels
753} // namespace openpower