blob: fecaa49d23279504530af5fa4f50e3e2f358b7b0 [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) {
144 this->_sendPELsToHost = std::get<bool>(value);
145 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600146
147 // Watch the BMCState property
148 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
149 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
150 *this, [this](const auto& value) {
151 this->_bmcState = std::get<std::string>(value);
152 }));
153
154 // Watch the chassis current and requested power state properties
155 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
156 bus, object_path::chassisState, interface::chassisState, *this,
157 [this](const auto& properties) {
158 auto state = properties.find("CurrentPowerState");
159 if (state != properties.end())
160 {
161 this->_chassisState = std::get<std::string>(state->second);
162 }
163
164 auto trans = properties.find("RequestedPowerTransition");
165 if (trans != properties.end())
166 {
167 this->_chassisTransition = std::get<std::string>(trans->second);
168 }
169 }));
170
171 // Watch the CurrentHostState property
172 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
173 bus, object_path::hostState, interface::hostState, "CurrentHostState",
174 *this, [this](const auto& value) {
175 this->_hostState = std::get<std::string>(value);
176 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500177}
178
Matt Spinler2a28c932020-02-03 14:23:40 -0600179DBusPropertyMap
180 DataInterface::getAllProperties(const std::string& service,
181 const std::string& objectPath,
182 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500183{
184 DBusPropertyMap properties;
185
186 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
187 interface::dbusProperty, "GetAll");
188 method.append(interface);
189 auto reply = _bus.call(method);
190
191 reply.read(properties);
192
193 return properties;
194}
195
Matt Spinlera7d9d962019-11-06 15:01:25 -0600196void DataInterface::getProperty(const std::string& service,
197 const std::string& objectPath,
198 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600199 const std::string& property,
200 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600201{
202
203 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
204 interface::dbusProperty, "Get");
205 method.append(interface, property);
206 auto reply = _bus.call(method);
207
208 reply.read(value);
209}
210
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600211DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
212{
213
214 auto method = _bus.new_method_call(
215 service_name::objectMapper, object_path::objectMapper,
216 interface::objectMapper, "GetSubTreePaths");
217
218 method.append(std::string{"/"}, 0, interfaces);
219
220 auto reply = _bus.call(method);
221
222 DBusPathList paths;
223 reply.read(paths);
224
225 return paths;
226}
227
Matt Spinlerc8705e22019-09-11 12:36:07 -0500228DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600229 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500230{
231 auto method = _bus.new_method_call(service_name::objectMapper,
232 object_path::objectMapper,
233 interface::objectMapper, "GetObject");
234
235 method.append(objectPath, std::vector<std::string>({interface}));
236
237 auto reply = _bus.call(method);
238
239 std::map<DBusService, DBusInterfaceList> response;
240 reply.read(response);
241
242 if (!response.empty())
243 {
244 return response.begin()->first;
245 }
246
247 return std::string{};
248}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600249
Matt Spinler677381b2020-01-23 10:04:29 -0600250void DataInterface::readBMCFWVersion()
251{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500252 _bmcFWVersion =
253 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600254}
255
256void DataInterface::readServerFWVersion()
257{
Sumit Kumarcad16202021-05-13 04:06:15 -0500258 auto value =
259 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
260 if ((value != "") && (value.find_last_of(')') != std::string::npos))
261 {
262 std::size_t pos = value.find_first_of('(') + 1;
263 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
264 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600265}
266
Matt Spinler677381b2020-01-23 10:04:29 -0600267void DataInterface::readBMCFWVersionID()
268{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500269 _bmcFWVersionID =
270 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600271}
272
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500273std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600274{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500275 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600276 try
277 {
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600278
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500279 auto service = getService(object_path::systemInv, interface::invAsset);
280 if (!service.empty())
281 {
282 DBusValue value;
283 getProperty(service, object_path::systemInv, interface::invAsset,
284 "Model", value);
285
286 model = std::get<std::string>(value);
287 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600288 }
289 catch (const std::exception& e)
290 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500291 log<level::WARNING>(fmt::format("Failed reading Model property from "
292 "Interface: {} exception: {}",
293 interface::invAsset, e.what())
294 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600295 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500296
297 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600298}
299
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500300std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600301{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500302 std::string sn;
303 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600304 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500305
306 auto service = getService(object_path::systemInv, interface::invAsset);
307 if (!service.empty())
308 {
309 DBusValue value;
310 getProperty(service, object_path::systemInv, interface::invAsset,
311 "SerialNumber", value);
312
313 sn = std::get<std::string>(value);
314 }
315 }
316 catch (const std::exception& e)
317 {
318 log<level::WARNING>(
319 fmt::format("Failed reading SerialNumber property from "
320 "Interface: {} exception: {}",
321 interface::invAsset, e.what())
322 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600323 }
324
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500325 return sn;
326}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600327
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500328std::string DataInterface::getMotherboardCCIN() const
329{
330 std::string ccin;
331
332 try
333 {
334 auto service =
335 getService(object_path::motherBoardInv, interface::viniRecordVPD);
336 if (!service.empty())
337 {
338 DBusValue value;
339 getProperty(service, object_path::motherBoardInv,
340 interface::viniRecordVPD, "CC", value);
341
342 auto cc = std::get<std::vector<uint8_t>>(value);
343 ccin = std::string{cc.begin(), cc.end()};
344 }
345 }
346 catch (const std::exception& e)
347 {
348 log<level::WARNING>(
349 fmt::format("Failed reading Motherboard CCIN property from "
350 "Interface: {} exception: {}",
351 interface::viniRecordVPD, e.what())
352 .c_str());
353 }
354
355 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600356}
357
Ben Tynere32b7e72021-05-18 12:38:40 -0500358std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
359{
360 std::vector<uint8_t> systemIM;
361
362 try
363 {
364 auto service =
365 getService(object_path::motherBoardInv, interface::vsbpRecordVPD);
366 if (!service.empty())
367 {
368 DBusValue value;
369 getProperty(service, object_path::motherBoardInv,
370 interface::vsbpRecordVPD, "IM", value);
371
372 systemIM = std::get<std::vector<uint8_t>>(value);
373 }
374 }
375 catch (const std::exception& e)
376 {
377 log<level::WARNING>(
378 fmt::format("Failed reading System IM property from "
379 "Interface: {} exception: {}",
380 interface::vsbpRecordVPD, e.what())
381 .c_str());
382 }
383
384 return systemIM;
385}
386
Matt Spinler60c4e792020-03-13 13:45:36 -0500387void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500388 std::string& fruPartNumber,
389 std::string& ccin,
390 std::string& serialNumber) const
391{
392 // For now, attempt to get all of the properties directly on the path
393 // passed in. In the future, may need to make use of an algorithm
394 // to figure out which inventory objects actually hold these
395 // interfaces in the case of non FRUs, or possibly another service
396 // will provide this info. Any missing interfaces will result
397 // in exceptions being thrown.
398
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500399 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500400
401 auto properties =
402 getAllProperties(service, inventoryPath, interface::viniRecordVPD);
403
404 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
405 fruPartNumber = std::string{value.begin(), value.end()};
406
407 value = std::get<std::vector<uint8_t>>(properties["CC"]);
408 ccin = std::string{value.begin(), value.end()};
409
410 value = std::get<std::vector<uint8_t>>(properties["SN"]);
411 serialNumber = std::string{value.begin(), value.end()};
412}
413
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500414std::string
415 DataInterface::getLocationCode(const std::string& inventoryPath) const
416{
417 auto service = getService(inventoryPath, interface::locCode);
418
419 DBusValue locCode;
420 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
421 locCode);
422
423 return std::get<std::string>(locCode);
424}
425
Matt Spinler5fb24c12020-06-04 11:21:33 -0500426std::string
427 DataInterface::addLocationCodePrefix(const std::string& locationCode)
428{
429 static const std::string locationCodePrefix{"Ufcs-"};
430
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500431 // Technically there are 2 location code prefixes, Ufcs and Umts, so
432 // if it already starts with a U then don't need to do anything.
433 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500434 {
435 return locationCodePrefix + locationCode;
436 }
437
438 return locationCode;
439}
440
441std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500442 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500443{
Matt Spinler0d92b522021-06-16 13:28:17 -0600444 // Location codes for connectors are the location code of the FRU they are
445 // on, plus a '-Tx' segment. Remove this last segment before expanding it
446 // and then add it back in afterwards. This way, the connector doesn't have
447 // to be in the model just so that it can be expanded.
448 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
449
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500450 auto method =
451 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
452 interface::vpdManager, "GetExpandedLocationCode");
453
Matt Spinler0d92b522021-06-16 13:28:17 -0600454 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500455
456 auto reply = _bus.call(method);
457
458 std::string expandedLocationCode;
459 reply.read(expandedLocationCode);
460
Matt Spinler0d92b522021-06-16 13:28:17 -0600461 if (!connectorLoc.empty())
462 {
463 expandedLocationCode += connectorLoc;
464 }
465
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500466 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500467}
468
Matt Spinler2f9225a2020-08-05 12:58:49 -0500469std::string
470 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
471 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500472{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500473 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
474 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500475
Matt Spinler0d92b522021-06-16 13:28:17 -0600476 // Remove the connector segment, if present, so that this method call
477 // returns an inventory path that getHWCalloutFields() can be used with.
478 // (The serial number, etc, aren't stored on the connector in the
479 // inventory, and may not even be modeled.)
480 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
481
Matt Spinler2f9225a2020-08-05 12:58:49 -0500482 auto method =
483 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
484 interface::vpdManager, methodName.c_str());
485
486 if (expanded)
487 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600488 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500489 }
490 else
491 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600492 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500493 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500494
495 auto reply = _bus.call(method);
496
497 std::vector<sdbusplus::message::object_path> entries;
498 reply.read(entries);
499
500 // Get the shortest entry from the paths received, as this
501 // would be the path furthest up the inventory hierarchy so
502 // would be the parent FRU. There is guaranteed to at least
503 // be one entry if the call didn't fail.
504 std::string shortest{entries[0]};
505
506 std::for_each(entries.begin(), entries.end(),
507 [&shortest](const auto& path) {
508 if (path.str.size() < shortest.size())
509 {
510 shortest = path;
511 }
512 });
513
514 return shortest;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500515}
516
Matt Spinler34a904c2020-08-05 14:53:28 -0500517void DataInterface::assertLEDGroup(const std::string& ledGroup,
518 bool value) const
519{
520 DBusValue variant = value;
521 auto method =
522 _bus.new_method_call(service_name::ledGroupManager, ledGroup.c_str(),
523 interface::dbusProperty, "Set");
524 method.append(interface::ledGroup, "Asserted", variant);
525 _bus.call(method);
526}
527
Matt Spinler993168d2021-04-07 16:05:03 -0500528void DataInterface::setFunctional(const std::string& objectPath,
529 bool value) const
530{
531 DBusValue variant = value;
532 auto service = getService(objectPath, interface::operationalStatus);
533
534 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
535 interface::dbusProperty, "Set");
536
537 method.append(interface::operationalStatus, "Functional", variant);
538 _bus.call(method);
539}
540
Sumit Kumar76198a22021-07-15 05:59:57 -0500541using AssociationTuple = std::tuple<std::string, std::string, std::string>;
542using AssociationsProperty = std::vector<AssociationTuple>;
543
544void DataInterface::setCriticalAssociation(const std::string& objectPath) const
545{
546 DBusValue getAssociationValue;
547
548 auto service = getService(objectPath, interface::association);
549
550 getProperty(service, objectPath, interface::association, "Associations",
551 getAssociationValue);
552
553 auto association = std::get<AssociationsProperty>(getAssociationValue);
554
555 AssociationTuple critAssociation{
556 "health_rollup", "critical",
557 "/xyz/openbmc_project/inventory/system/chassis"};
558
559 if (std::find(association.begin(), association.end(), critAssociation) ==
560 association.end())
561 {
562 association.push_back(critAssociation);
563 DBusValue setAssociationValue = association;
564
565 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
566 interface::dbusProperty, "Set");
567
568 method.append(interface::association, "Associations",
569 setAssociationValue);
570 _bus.call(method);
571 }
572}
573
Matt Spinler1ab66962020-10-29 13:21:44 -0500574std::vector<std::string> DataInterface::getSystemNames() const
575{
576 DBusSubTree subtree;
577 DBusValue names;
578
579 auto method = _bus.new_method_call(service_name::objectMapper,
580 object_path::objectMapper,
581 interface::objectMapper, "GetSubTree");
582 method.append(std::string{"/"}, 0,
583 std::vector<std::string>{interface::compatible});
584 auto reply = _bus.call(method);
585
586 reply.read(subtree);
587 if (subtree.empty())
588 {
589 throw std::runtime_error("Compatible interface not on D-Bus");
590 }
591
592 const auto& object = *(subtree.begin());
593 const auto& path = object.first;
594 const auto& service = object.second.begin()->first;
595
596 getProperty(service, path, interface::compatible, "Names", names);
597
598 return std::get<std::vector<std::string>>(names);
599}
600
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500601bool DataInterface::getQuiesceOnError() const
602{
603 bool ret = false;
604
605 try
606 {
607 auto service =
608 getService(object_path::logSetting, interface::logSetting);
609 if (!service.empty())
610 {
611 DBusValue value;
612 getProperty(service, object_path::logSetting, interface::logSetting,
613 "QuiesceOnHwError", value);
614
615 ret = std::get<bool>(value);
616 }
617 }
618 catch (const std::exception& e)
619 {
620 log<level::WARNING>(
621 fmt::format("Failed reading QuiesceOnHwError property from "
622 "Interface: {} exception: {}",
623 interface::logSetting, e.what())
624 .c_str());
625 }
626
627 return ret;
628}
629
Sumit Kumar9d43a722021-08-24 09:46:19 -0500630std::vector<bool>
631 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
632{
633 DBusSubTree subtree;
634 std::vector<bool> result(type.size(), false);
635
636 // Query GetSubTree for the availability of dump interface
637 auto method = _bus.new_method_call(service_name::objectMapper,
638 object_path::objectMapper,
639 interface::objectMapper, "GetSubTree");
640 method.append(std::string{"/"}, 0,
641 std::vector<std::string>{interface::dumpEntry});
642 auto reply = _bus.call(method);
643
644 reply.read(subtree);
645
646 if (subtree.empty())
647 {
648 return result;
649 }
650
651 std::vector<bool>::iterator itDumpStatus = result.begin();
652 uint8_t count = 0;
653 for (const auto& [path, serviceInfo] : subtree)
654 {
655 const auto& service = serviceInfo.begin()->first;
656 // Check for dump type on the object path
657 for (const auto& it : type)
658 {
659 if (path.find(it) != std::string::npos)
660 {
661 DBusValue value, progress;
662
663 // If dump type status is already available go for next path
664 if (*itDumpStatus)
665 {
666 break;
667 }
668
669 // Check for valid dump to be available if following
670 // conditions are met for the dump entry path -
671 // Offloaded == false and Status == Completed
672 getProperty(service, path, interface::dumpEntry, "Offloaded",
673 value);
674 getProperty(service, path, interface::dumpProgress, "Status",
675 progress);
676 auto offload = std::get<bool>(value);
677 auto status = std::get<std::string>(progress);
678 if (!offload && (status.find("Completed") != std::string::npos))
679 {
680 *itDumpStatus = true;
681 count++;
682 if (count >= type.size())
683 {
684 return result;
685 }
686 break;
687 }
688 }
689 itDumpStatus++;
690 }
691 itDumpStatus = result.begin();
692 }
693
694 return result;
695}
696
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500697void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
698 const std::string& type,
699 const std::string& logPath) const
700{
701 try
702 {
703 auto method = _bus.new_method_call(
704 service_name::hwIsolation, object_path::hwIsolation,
705 interface::hwIsolationCreate, "CreateWithEntityPath");
706 method.append(binPath, type, sdbusplus::message::object_path(logPath));
707 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
708 // api's. Making d-bus call no reply type to avoid cyclic dependency.
709 // Added minimal timeout to catch initial failures.
710 // Need to revisit this design later to avoid cyclic dependency.
711 constexpr auto dbusTimeout = 100000; // in micro seconds
712 _bus.call_noreply(method, dbusTimeout);
713 }
714
715 catch (const sdbusplus::exception::exception& e)
716 {
717 std::string errName = e.name();
718 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
719 // mentioned above. Ignoring the error.
720 if (errName != SD_BUS_ERROR_TIMEOUT)
721 {
722 log<level::ERR>(
723 fmt::format("GUARD D-Bus call exception"
724 "OBJPATH={}, INTERFACE={}, EXCEPTION={}",
725 object_path::hwIsolation,
726 interface::hwIsolationCreate, e.what())
727 .c_str());
728 }
729 }
730}
Sumit Kumar3e274432021-09-14 06:37:56 -0500731
732void DataInterface::createProgressSRC(
733 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
734{
735 DBusValue variant = std::make_tuple(priSRC, srcStruct);
736
737 auto method = _bus.new_method_call(service_name::bootRawProgress,
738 object_path::bootRawSetting,
739 interface::dbusProperty, "Set");
740
741 method.append(interface::bootRawProgress, "Value", variant);
742
743 _bus.call(method);
744}
Matt Spinlerc8705e22019-09-11 12:36:07 -0500745} // namespace pels
746} // namespace openpower