blob: fa7b0871905b3693d19023076482e05dec2491b2 [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 Kumar027bf282022-01-24 11:25:19 -060087constexpr auto associationDef = "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";
Sumit Kumar027bf282022-01-24 11:25:19 -060092constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
93constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinlerc8705e22019-09-11 12:36:07 -050094} // namespace interface
95
Matt Spinlerf10068d2020-12-02 10:44:08 -060096using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
Vijay Lobo81b4dca2021-04-29 00:04:00 -050097using namespace phosphor::logging;
Matt Spinlera7d9d962019-11-06 15:01:25 -060098
Matt Spinler0d92b522021-06-16 13:28:17 -060099std::pair<std::string, std::string>
100 DataInterfaceBase::extractConnectorFromLocCode(
101 const std::string& locationCode)
102{
103 auto base = locationCode;
104 std::string connector{};
105
106 auto pos = base.find("-T");
107 if (pos != std::string::npos)
108 {
109 connector = base.substr(pos);
110 base = base.substr(0, pos);
111 }
112
113 return {base, connector};
114}
115
Matt Spinlerc8705e22019-09-11 12:36:07 -0500116DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus)
117{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600118 readBMCFWVersion();
119 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600120 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600121
Matt Spinlerf10068d2020-12-02 10:44:08 -0600122 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600123 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600124 bus, object_path::hostState, interface::bootProgress, "BootProgress",
125 *this, [this](const auto& value) {
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500126 this->_bootState = std::get<std::string>(value);
Matt Spinlerf10068d2020-12-02 10:44:08 -0600127 auto status = Progress::convertProgressStagesFromString(
128 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600129
Matt Spinlerf10068d2020-12-02 10:44:08 -0600130 if ((status == Progress::ProgressStages::SystemInitComplete) ||
131 (status == Progress::ProgressStages::OSStart) ||
132 (status == Progress::ProgressStages::OSRunning))
Matt Spinler2a28c932020-02-03 14:23:40 -0600133 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600134 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600135 }
136 else
137 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600138 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600139 }
140 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600141
142 // Watch the host PEL enable property
143 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
144 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
145 [this](const auto& value) {
Matt Spinlerc6ee7c52022-01-14 13:21:53 -0600146 if (std::get<bool>(value) != this->_sendPELsToHost)
147 {
148 log<level::INFO>(
149 fmt::format("The send PELs to host setting changed to {}",
150 std::get<bool>(value))
151 .c_str());
152 }
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600153 this->_sendPELsToHost = std::get<bool>(value);
154 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600155
156 // Watch the BMCState property
157 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
158 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
159 *this, [this](const auto& value) {
160 this->_bmcState = std::get<std::string>(value);
161 }));
162
163 // Watch the chassis current and requested power state properties
164 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
165 bus, object_path::chassisState, interface::chassisState, *this,
166 [this](const auto& properties) {
167 auto state = properties.find("CurrentPowerState");
168 if (state != properties.end())
169 {
170 this->_chassisState = std::get<std::string>(state->second);
171 }
172
173 auto trans = properties.find("RequestedPowerTransition");
174 if (trans != properties.end())
175 {
176 this->_chassisTransition = std::get<std::string>(trans->second);
177 }
178 }));
179
180 // Watch the CurrentHostState property
181 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
182 bus, object_path::hostState, interface::hostState, "CurrentHostState",
183 *this, [this](const auto& value) {
184 this->_hostState = std::get<std::string>(value);
185 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500186}
187
Matt Spinler2a28c932020-02-03 14:23:40 -0600188DBusPropertyMap
189 DataInterface::getAllProperties(const std::string& service,
190 const std::string& objectPath,
191 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500192{
193 DBusPropertyMap properties;
194
195 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
196 interface::dbusProperty, "GetAll");
197 method.append(interface);
198 auto reply = _bus.call(method);
199
200 reply.read(properties);
201
202 return properties;
203}
204
Matt Spinlera7d9d962019-11-06 15:01:25 -0600205void DataInterface::getProperty(const std::string& service,
206 const std::string& objectPath,
207 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600208 const std::string& property,
209 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600210{
211
212 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
213 interface::dbusProperty, "Get");
214 method.append(interface, property);
215 auto reply = _bus.call(method);
216
217 reply.read(value);
218}
219
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600220DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
221{
222
223 auto method = _bus.new_method_call(
224 service_name::objectMapper, object_path::objectMapper,
225 interface::objectMapper, "GetSubTreePaths");
226
227 method.append(std::string{"/"}, 0, interfaces);
228
229 auto reply = _bus.call(method);
230
231 DBusPathList paths;
232 reply.read(paths);
233
234 return paths;
235}
236
Matt Spinlerc8705e22019-09-11 12:36:07 -0500237DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600238 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500239{
240 auto method = _bus.new_method_call(service_name::objectMapper,
241 object_path::objectMapper,
242 interface::objectMapper, "GetObject");
243
244 method.append(objectPath, std::vector<std::string>({interface}));
245
246 auto reply = _bus.call(method);
247
248 std::map<DBusService, DBusInterfaceList> response;
249 reply.read(response);
250
251 if (!response.empty())
252 {
253 return response.begin()->first;
254 }
255
256 return std::string{};
257}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600258
Matt Spinler677381b2020-01-23 10:04:29 -0600259void DataInterface::readBMCFWVersion()
260{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500261 _bmcFWVersion =
262 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600263}
264
265void DataInterface::readServerFWVersion()
266{
Sumit Kumarcad16202021-05-13 04:06:15 -0500267 auto value =
268 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
269 if ((value != "") && (value.find_last_of(')') != std::string::npos))
270 {
271 std::size_t pos = value.find_first_of('(') + 1;
272 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
273 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600274}
275
Matt Spinler677381b2020-01-23 10:04:29 -0600276void DataInterface::readBMCFWVersionID()
277{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500278 _bmcFWVersionID =
279 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600280}
281
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500282std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600283{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500284 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600285 try
286 {
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600287
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500288 auto service = getService(object_path::systemInv, interface::invAsset);
289 if (!service.empty())
290 {
291 DBusValue value;
292 getProperty(service, object_path::systemInv, interface::invAsset,
293 "Model", value);
294
295 model = std::get<std::string>(value);
296 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600297 }
298 catch (const std::exception& e)
299 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500300 log<level::WARNING>(fmt::format("Failed reading Model property from "
301 "Interface: {} exception: {}",
302 interface::invAsset, e.what())
303 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600304 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500305
306 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600307}
308
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500309std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600310{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500311 std::string sn;
312 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600313 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500314
315 auto service = getService(object_path::systemInv, interface::invAsset);
316 if (!service.empty())
317 {
318 DBusValue value;
319 getProperty(service, object_path::systemInv, interface::invAsset,
320 "SerialNumber", value);
321
322 sn = std::get<std::string>(value);
323 }
324 }
325 catch (const std::exception& e)
326 {
327 log<level::WARNING>(
328 fmt::format("Failed reading SerialNumber property from "
329 "Interface: {} exception: {}",
330 interface::invAsset, e.what())
331 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600332 }
333
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500334 return sn;
335}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600336
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500337std::string DataInterface::getMotherboardCCIN() const
338{
339 std::string ccin;
340
341 try
342 {
343 auto service =
344 getService(object_path::motherBoardInv, interface::viniRecordVPD);
345 if (!service.empty())
346 {
347 DBusValue value;
348 getProperty(service, object_path::motherBoardInv,
349 interface::viniRecordVPD, "CC", value);
350
351 auto cc = std::get<std::vector<uint8_t>>(value);
352 ccin = std::string{cc.begin(), cc.end()};
353 }
354 }
355 catch (const std::exception& e)
356 {
357 log<level::WARNING>(
358 fmt::format("Failed reading Motherboard CCIN property from "
359 "Interface: {} exception: {}",
360 interface::viniRecordVPD, e.what())
361 .c_str());
362 }
363
364 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600365}
366
Ben Tynere32b7e72021-05-18 12:38:40 -0500367std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
368{
369 std::vector<uint8_t> systemIM;
370
371 try
372 {
373 auto service =
374 getService(object_path::motherBoardInv, interface::vsbpRecordVPD);
375 if (!service.empty())
376 {
377 DBusValue value;
378 getProperty(service, object_path::motherBoardInv,
379 interface::vsbpRecordVPD, "IM", value);
380
381 systemIM = std::get<std::vector<uint8_t>>(value);
382 }
383 }
384 catch (const std::exception& e)
385 {
386 log<level::WARNING>(
387 fmt::format("Failed reading System IM property from "
388 "Interface: {} exception: {}",
389 interface::vsbpRecordVPD, e.what())
390 .c_str());
391 }
392
393 return systemIM;
394}
395
Matt Spinler60c4e792020-03-13 13:45:36 -0500396void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500397 std::string& fruPartNumber,
398 std::string& ccin,
399 std::string& serialNumber) const
400{
401 // For now, attempt to get all of the properties directly on the path
402 // passed in. In the future, may need to make use of an algorithm
403 // to figure out which inventory objects actually hold these
404 // interfaces in the case of non FRUs, or possibly another service
405 // will provide this info. Any missing interfaces will result
406 // in exceptions being thrown.
407
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500408 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500409
410 auto properties =
411 getAllProperties(service, inventoryPath, interface::viniRecordVPD);
412
413 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
414 fruPartNumber = std::string{value.begin(), value.end()};
415
416 value = std::get<std::vector<uint8_t>>(properties["CC"]);
417 ccin = std::string{value.begin(), value.end()};
418
419 value = std::get<std::vector<uint8_t>>(properties["SN"]);
420 serialNumber = std::string{value.begin(), value.end()};
421}
422
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500423std::string
424 DataInterface::getLocationCode(const std::string& inventoryPath) const
425{
426 auto service = getService(inventoryPath, interface::locCode);
427
428 DBusValue locCode;
429 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
430 locCode);
431
432 return std::get<std::string>(locCode);
433}
434
Matt Spinler5fb24c12020-06-04 11:21:33 -0500435std::string
436 DataInterface::addLocationCodePrefix(const std::string& locationCode)
437{
438 static const std::string locationCodePrefix{"Ufcs-"};
439
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500440 // Technically there are 2 location code prefixes, Ufcs and Umts, so
441 // if it already starts with a U then don't need to do anything.
442 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500443 {
444 return locationCodePrefix + locationCode;
445 }
446
447 return locationCode;
448}
449
450std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500451 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500452{
Matt Spinler0d92b522021-06-16 13:28:17 -0600453 // Location codes for connectors are the location code of the FRU they are
454 // on, plus a '-Tx' segment. Remove this last segment before expanding it
455 // and then add it back in afterwards. This way, the connector doesn't have
456 // to be in the model just so that it can be expanded.
457 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
458
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500459 auto method =
460 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
461 interface::vpdManager, "GetExpandedLocationCode");
462
Matt Spinler0d92b522021-06-16 13:28:17 -0600463 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500464
465 auto reply = _bus.call(method);
466
467 std::string expandedLocationCode;
468 reply.read(expandedLocationCode);
469
Matt Spinler0d92b522021-06-16 13:28:17 -0600470 if (!connectorLoc.empty())
471 {
472 expandedLocationCode += connectorLoc;
473 }
474
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500475 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500476}
477
Matt Spinler2f9225a2020-08-05 12:58:49 -0500478std::string
479 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
480 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500481{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500482 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
483 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500484
Matt Spinler0d92b522021-06-16 13:28:17 -0600485 // Remove the connector segment, if present, so that this method call
486 // returns an inventory path that getHWCalloutFields() can be used with.
487 // (The serial number, etc, aren't stored on the connector in the
488 // inventory, and may not even be modeled.)
489 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
490
Matt Spinler2f9225a2020-08-05 12:58:49 -0500491 auto method =
492 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
493 interface::vpdManager, methodName.c_str());
494
495 if (expanded)
496 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600497 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500498 }
499 else
500 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600501 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500502 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500503
504 auto reply = _bus.call(method);
505
506 std::vector<sdbusplus::message::object_path> entries;
507 reply.read(entries);
508
509 // Get the shortest entry from the paths received, as this
510 // would be the path furthest up the inventory hierarchy so
511 // would be the parent FRU. There is guaranteed to at least
512 // be one entry if the call didn't fail.
513 std::string shortest{entries[0]};
514
515 std::for_each(entries.begin(), entries.end(),
516 [&shortest](const auto& path) {
517 if (path.str.size() < shortest.size())
518 {
519 shortest = path;
520 }
521 });
522
523 return shortest;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500524}
525
Matt Spinler34a904c2020-08-05 14:53:28 -0500526void DataInterface::assertLEDGroup(const std::string& ledGroup,
527 bool value) const
528{
529 DBusValue variant = value;
530 auto method =
531 _bus.new_method_call(service_name::ledGroupManager, ledGroup.c_str(),
532 interface::dbusProperty, "Set");
533 method.append(interface::ledGroup, "Asserted", variant);
534 _bus.call(method);
535}
536
Matt Spinler993168d2021-04-07 16:05:03 -0500537void DataInterface::setFunctional(const std::string& objectPath,
538 bool value) const
539{
540 DBusValue variant = value;
541 auto service = getService(objectPath, interface::operationalStatus);
542
543 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
544 interface::dbusProperty, "Set");
545
546 method.append(interface::operationalStatus, "Functional", variant);
547 _bus.call(method);
548}
549
Sumit Kumar76198a22021-07-15 05:59:57 -0500550using AssociationTuple = std::tuple<std::string, std::string, std::string>;
551using AssociationsProperty = std::vector<AssociationTuple>;
552
553void DataInterface::setCriticalAssociation(const std::string& objectPath) const
554{
555 DBusValue getAssociationValue;
556
Sumit Kumar027bf282022-01-24 11:25:19 -0600557 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500558
Sumit Kumar027bf282022-01-24 11:25:19 -0600559 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500560 getAssociationValue);
561
562 auto association = std::get<AssociationsProperty>(getAssociationValue);
563
564 AssociationTuple critAssociation{
565 "health_rollup", "critical",
566 "/xyz/openbmc_project/inventory/system/chassis"};
567
568 if (std::find(association.begin(), association.end(), critAssociation) ==
569 association.end())
570 {
571 association.push_back(critAssociation);
572 DBusValue setAssociationValue = association;
573
574 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
575 interface::dbusProperty, "Set");
576
Sumit Kumar027bf282022-01-24 11:25:19 -0600577 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500578 setAssociationValue);
579 _bus.call(method);
580 }
581}
582
Matt Spinler1ab66962020-10-29 13:21:44 -0500583std::vector<std::string> DataInterface::getSystemNames() const
584{
585 DBusSubTree subtree;
586 DBusValue names;
587
588 auto method = _bus.new_method_call(service_name::objectMapper,
589 object_path::objectMapper,
590 interface::objectMapper, "GetSubTree");
591 method.append(std::string{"/"}, 0,
592 std::vector<std::string>{interface::compatible});
593 auto reply = _bus.call(method);
594
595 reply.read(subtree);
596 if (subtree.empty())
597 {
598 throw std::runtime_error("Compatible interface not on D-Bus");
599 }
600
601 const auto& object = *(subtree.begin());
602 const auto& path = object.first;
603 const auto& service = object.second.begin()->first;
604
605 getProperty(service, path, interface::compatible, "Names", names);
606
607 return std::get<std::vector<std::string>>(names);
608}
609
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500610bool DataInterface::getQuiesceOnError() const
611{
612 bool ret = false;
613
614 try
615 {
616 auto service =
617 getService(object_path::logSetting, interface::logSetting);
618 if (!service.empty())
619 {
620 DBusValue value;
621 getProperty(service, object_path::logSetting, interface::logSetting,
622 "QuiesceOnHwError", value);
623
624 ret = std::get<bool>(value);
625 }
626 }
627 catch (const std::exception& e)
628 {
629 log<level::WARNING>(
630 fmt::format("Failed reading QuiesceOnHwError property from "
631 "Interface: {} exception: {}",
632 interface::logSetting, e.what())
633 .c_str());
634 }
635
636 return ret;
637}
638
Sumit Kumar9d43a722021-08-24 09:46:19 -0500639std::vector<bool>
640 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
641{
642 DBusSubTree subtree;
643 std::vector<bool> result(type.size(), false);
644
645 // Query GetSubTree for the availability of dump interface
646 auto method = _bus.new_method_call(service_name::objectMapper,
647 object_path::objectMapper,
648 interface::objectMapper, "GetSubTree");
649 method.append(std::string{"/"}, 0,
650 std::vector<std::string>{interface::dumpEntry});
651 auto reply = _bus.call(method);
652
653 reply.read(subtree);
654
655 if (subtree.empty())
656 {
657 return result;
658 }
659
660 std::vector<bool>::iterator itDumpStatus = result.begin();
661 uint8_t count = 0;
662 for (const auto& [path, serviceInfo] : subtree)
663 {
664 const auto& service = serviceInfo.begin()->first;
665 // Check for dump type on the object path
666 for (const auto& it : type)
667 {
668 if (path.find(it) != std::string::npos)
669 {
670 DBusValue value, progress;
671
672 // If dump type status is already available go for next path
673 if (*itDumpStatus)
674 {
675 break;
676 }
677
678 // Check for valid dump to be available if following
679 // conditions are met for the dump entry path -
680 // Offloaded == false and Status == Completed
681 getProperty(service, path, interface::dumpEntry, "Offloaded",
682 value);
683 getProperty(service, path, interface::dumpProgress, "Status",
684 progress);
685 auto offload = std::get<bool>(value);
686 auto status = std::get<std::string>(progress);
687 if (!offload && (status.find("Completed") != std::string::npos))
688 {
689 *itDumpStatus = true;
690 count++;
691 if (count >= type.size())
692 {
693 return result;
694 }
695 break;
696 }
697 }
698 itDumpStatus++;
699 }
700 itDumpStatus = result.begin();
701 }
702
703 return result;
704}
705
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500706void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
707 const std::string& type,
708 const std::string& logPath) const
709{
710 try
711 {
712 auto method = _bus.new_method_call(
713 service_name::hwIsolation, object_path::hwIsolation,
714 interface::hwIsolationCreate, "CreateWithEntityPath");
715 method.append(binPath, type, sdbusplus::message::object_path(logPath));
716 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
717 // api's. Making d-bus call no reply type to avoid cyclic dependency.
718 // Added minimal timeout to catch initial failures.
719 // Need to revisit this design later to avoid cyclic dependency.
720 constexpr auto dbusTimeout = 100000; // in micro seconds
721 _bus.call_noreply(method, dbusTimeout);
722 }
723
724 catch (const sdbusplus::exception::exception& e)
725 {
726 std::string errName = e.name();
727 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
728 // mentioned above. Ignoring the error.
729 if (errName != SD_BUS_ERROR_TIMEOUT)
730 {
731 log<level::ERR>(
732 fmt::format("GUARD D-Bus call exception"
733 "OBJPATH={}, INTERFACE={}, EXCEPTION={}",
734 object_path::hwIsolation,
735 interface::hwIsolationCreate, e.what())
736 .c_str());
737 }
738 }
739}
Sumit Kumar3e274432021-09-14 06:37:56 -0500740
741void DataInterface::createProgressSRC(
742 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
743{
744 DBusValue variant = std::make_tuple(priSRC, srcStruct);
745
746 auto method = _bus.new_method_call(service_name::bootRawProgress,
747 object_path::bootRawSetting,
748 interface::dbusProperty, "Set");
749
750 method.append(interface::bootRawProgress, "Value", variant);
751
752 _bus.call(method);
753}
Sumit Kumar027bf282022-01-24 11:25:19 -0600754
755std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
756{
757 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
758 std::string hwErrorLog = "/isolated_hw_errorlog";
759 std::string errorLog = "/error_log";
760 DBusPathList paths;
761 std::vector<uint32_t> ids;
762
763 // Get all latest mapper associations
764 paths = getPaths(association);
765 for (auto& path : paths)
766 {
767 // Look for object path with hardware isolation entry if any
768 size_t pos = path.find(hwErrorLog);
769 if (pos != std::string::npos)
770 {
771 // Get the object path
772 std::string ph = path;
773 ph.erase(pos, hwErrorLog.length());
774 auto service = getService(ph, interface::hwIsolationEntry);
775 if (!service.empty())
776 {
777 bool status;
778 DBusValue value;
779
780 // Read the Resolved property from object path
781 getProperty(service, ph, interface::hwIsolationEntry,
782 "Resolved", value);
783
784 status = std::get<bool>(value);
785
786 // If the entry isn't resolved
787 if (!status)
788 {
789 auto service = getService(path, interface::association);
790 if (!service.empty())
791 {
792 DBusValue value;
793
794 // Read Endpoints property
795 getProperty(service, path, interface::association,
796 "endpoints", value);
797
798 auto logPath =
799 std::get<std::vector<std::string>>(value);
800 if (!logPath.empty())
801 {
802 // Get OpenBMC event log Id
803 uint32_t id = stoi(logPath[0].substr(
804 logPath[0].find_last_of('/') + 1));
805 ids.push_back(id);
806 }
807 }
808 }
809 }
810 }
811
812 // Look for object path with error_log entry if any
813 pos = path.find(errorLog);
814 if (pos != std::string::npos)
815 {
816 auto service = getService(path, interface::association);
817 if (!service.empty())
818 {
819 DBusValue value;
820
821 // Read Endpoints property
822 getProperty(service, path, interface::association, "endpoints",
823 value);
824
825 auto logPath = std::get<std::vector<std::string>>(value);
826 if (!logPath.empty())
827 {
828 // Get OpenBMC event log Id
829 uint32_t id = stoi(
830 logPath[0].substr(logPath[0].find_last_of('/') + 1));
831 ids.push_back(id);
832 }
833 }
834 }
835 }
836
837 if (ids.size() > 1)
838 {
839 // remove duplicates to have only unique ids
840 std::sort(ids.begin(), ids.end());
841 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
842 }
843 return ids;
844}
Matt Spinlerc8705e22019-09-11 12:36:07 -0500845} // namespace pels
846} // namespace openpower