blob: 1c3357993a971970d499bbb27a154380fd398b8e [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlercad9c2b2019-12-02 15:42:01 -060016#include "config.h"
17
Matt Spinlerc8705e22019-09-11 12:36:07 -050018#include "data_interface.hpp"
19
Matt Spinlerf61f2922020-06-23 11:32:49 -050020#include "util.hpp"
21
Vijay Lobo81b4dca2021-04-29 00:04:00 -050022#include <fmt/format.h>
23
Matt Spinlercad9c2b2019-12-02 15:42:01 -060024#include <fstream>
Sumit Kumar9d43a722021-08-24 09:46:19 -050025#include <iterator>
Vijay Lobo81b4dca2021-04-29 00:04:00 -050026#include <phosphor-logging/log.hpp>
Matt Spinlerf10068d2020-12-02 10:44:08 -060027#include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
Matt Spinlera7d9d962019-11-06 15:01:25 -060028
Matt Spinler35a405b2022-03-02 11:42:42 -060029// Use a timeout of 10s for D-Bus calls so if there are
30// timeouts the callers of the PEL creation method won't
31// also timeout.
32constexpr auto dbusTimeout = 10000000;
33
Matt Spinlerc8705e22019-09-11 12:36:07 -050034namespace openpower
35{
36namespace pels
37{
38
39namespace service_name
40{
41constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050042constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050043constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050044constexpr auto logSetting = "xyz.openbmc_project.Settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050045constexpr auto hwIsolation = "org.open_power.HardwareIsolation";
Sumit Kumar3e274432021-09-14 06:37:56 -050046constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Matt Spinler744d8512022-06-08 08:25:47 -050047constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager";
Matt Spinlerc8705e22019-09-11 12:36:07 -050048} // namespace service_name
49
50namespace object_path
51{
52constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
53constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
Matt Spinler6ea4d5f2020-05-20 13:31:07 -050054constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
Vijay Lobo81b4dca2021-04-29 00:04:00 -050055constexpr auto motherBoardInv =
56 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060057constexpr auto baseInv = "/xyz/openbmc_project/inventory";
Matt Spinler4aa23a12020-02-03 15:05:09 -060058constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
59constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
Matt Spinlera7d9d962019-11-06 15:01:25 -060060constexpr auto hostState = "/xyz/openbmc_project/state/host0";
Matt Spinlerb3f51862019-12-09 13:55:10 -060061constexpr auto pldm = "/xyz/openbmc_project/pldm";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060062constexpr auto enableHostPELs =
63 "/xyz/openbmc_project/logging/send_event_logs_to_host";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050064constexpr auto vpdManager = "/com/ibm/VPD/Manager";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050065constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050066constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
Sumit Kumar3e274432021-09-14 06:37:56 -050067constexpr auto bootRawSetting = "/xyz/openbmc_project/state/boot/raw0";
Matt Spinler744d8512022-06-08 08:25:47 -050068constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
Matt Spinlerc8705e22019-09-11 12:36:07 -050069} // namespace object_path
70
71namespace interface
72{
73constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
74constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
75constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
Matt Spinlerf10068d2020-12-02 10:44:08 -060076constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
Matt Spinlerb3f51862019-12-09 13:55:10 -060077constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
Matt Spinler9cf3cfd2020-02-03 14:41:55 -060078constexpr auto enable = "xyz.openbmc_project.Object.Enable";
Matt Spinler4aa23a12020-02-03 15:05:09 -060079constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
80constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
81constexpr auto hostState = "xyz.openbmc_project.State.Host";
Matt Spinlerb3d488f2020-02-21 15:30:46 -060082constexpr auto invMotherboard =
83 "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
84constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
Ben Tynere32b7e72021-05-18 12:38:40 -050085constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
Matt Spinlercc8b1112021-12-15 09:30:35 -060086constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
Matt Spinler1ab66962020-10-29 13:21:44 -050087constexpr auto compatible =
88 "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -050089constexpr auto vpdManager = "com.ibm.VPD.Manager";
Matt Spinler34a904c2020-08-05 14:53:28 -050090constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
Matt Spinler993168d2021-04-07 16:05:03 -050091constexpr auto operationalStatus =
92 "xyz.openbmc_project.State.Decorator.OperationalStatus";
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -050093constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
Sumit Kumar027bf282022-01-24 11:25:19 -060094constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
Sumit Kumar9d43a722021-08-24 09:46:19 -050095constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
96constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -050097constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
Sumit Kumar3e274432021-09-14 06:37:56 -050098constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
Sumit Kumar027bf282022-01-24 11:25:19 -060099constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
100constexpr auto association = "xyz.openbmc_project.Association";
Matt Spinler744d8512022-06-08 08:25:47 -0500101constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
Matt Spinlerc8705e22019-09-11 12:36:07 -0500102} // namespace interface
103
Matt Spinlerf10068d2020-12-02 10:44:08 -0600104using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500105using namespace phosphor::logging;
Matt Spinlera7d9d962019-11-06 15:01:25 -0600106
Matt Spinler0d92b522021-06-16 13:28:17 -0600107std::pair<std::string, std::string>
108 DataInterfaceBase::extractConnectorFromLocCode(
109 const std::string& locationCode)
110{
111 auto base = locationCode;
112 std::string connector{};
113
114 auto pos = base.find("-T");
115 if (pos != std::string::npos)
116 {
117 connector = base.substr(pos);
118 base = base.substr(0, pos);
119 }
120
121 return {base, connector};
122}
123
Patrick Williams45e83522022-07-22 19:26:52 -0500124DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus)
Matt Spinlerc8705e22019-09-11 12:36:07 -0500125{
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600126 readBMCFWVersion();
127 readServerFWVersion();
Matt Spinler677381b2020-01-23 10:04:29 -0600128 readBMCFWVersionID();
Matt Spinler2a28c932020-02-03 14:23:40 -0600129
Matt Spinlerf10068d2020-12-02 10:44:08 -0600130 // Watch the BootProgress property
Matt Spinler2a28c932020-02-03 14:23:40 -0600131 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
Matt Spinlerf10068d2020-12-02 10:44:08 -0600132 bus, object_path::hostState, interface::bootProgress, "BootProgress",
133 *this, [this](const auto& value) {
Sumit Kumar2c36fdd2021-09-21 03:12:11 -0500134 this->_bootState = std::get<std::string>(value);
Matt Spinlerf10068d2020-12-02 10:44:08 -0600135 auto status = Progress::convertProgressStagesFromString(
136 std::get<std::string>(value));
Matt Spinler2a28c932020-02-03 14:23:40 -0600137
Matt Spinlerf10068d2020-12-02 10:44:08 -0600138 if ((status == Progress::ProgressStages::SystemInitComplete) ||
139 (status == Progress::ProgressStages::OSStart) ||
140 (status == Progress::ProgressStages::OSRunning))
Matt Spinler2a28c932020-02-03 14:23:40 -0600141 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600142 setHostUp(true);
Matt Spinler2a28c932020-02-03 14:23:40 -0600143 }
144 else
145 {
Matt Spinler4aa23a12020-02-03 15:05:09 -0600146 setHostUp(false);
Matt Spinler2a28c932020-02-03 14:23:40 -0600147 }
148 }));
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600149
150 // Watch the host PEL enable property
151 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
152 bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
153 [this](const auto& value) {
Matt Spinlerc6ee7c52022-01-14 13:21:53 -0600154 if (std::get<bool>(value) != this->_sendPELsToHost)
155 {
156 log<level::INFO>(
157 fmt::format("The send PELs to host setting changed to {}",
158 std::get<bool>(value))
159 .c_str());
160 }
Matt Spinler9cf3cfd2020-02-03 14:41:55 -0600161 this->_sendPELsToHost = std::get<bool>(value);
162 }));
Matt Spinler4aa23a12020-02-03 15:05:09 -0600163
164 // Watch the BMCState property
165 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
166 bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
167 *this, [this](const auto& value) {
168 this->_bmcState = std::get<std::string>(value);
169 }));
170
171 // Watch the chassis current and requested power state properties
172 _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
173 bus, object_path::chassisState, interface::chassisState, *this,
174 [this](const auto& properties) {
175 auto state = properties.find("CurrentPowerState");
176 if (state != properties.end())
177 {
178 this->_chassisState = std::get<std::string>(state->second);
179 }
180
181 auto trans = properties.find("RequestedPowerTransition");
182 if (trans != properties.end())
183 {
184 this->_chassisTransition = std::get<std::string>(trans->second);
185 }
186 }));
187
188 // Watch the CurrentHostState property
189 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
190 bus, object_path::hostState, interface::hostState, "CurrentHostState",
191 *this, [this](const auto& value) {
192 this->_hostState = std::get<std::string>(value);
193 }));
Matt Spinler744d8512022-06-08 08:25:47 -0500194
195 // Watch the BaseBIOSTable property for the hmc managed attribute
196 _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
197 bus, object_path::biosConfigMgr, interface::biosConfigMgr,
198 "BaseBIOSTable", service_name::biosConfigMgr, *this,
199 [this](const auto& value) {
200 const auto& attributes = std::get<BiosAttributes>(value);
201
202 auto it = attributes.find("pvm_hmc_managed");
203 if (it != attributes.end())
204 {
205 const auto& currentValVariant = std::get<5>(it->second);
206 auto currentVal = std::get_if<std::string>(&currentValVariant);
207 if (currentVal)
208 {
209 this->_hmcManaged =
210 (*currentVal == "Enabled") ? true : false;
211 }
212 }
213 }));
Matt Spinlerc8705e22019-09-11 12:36:07 -0500214}
215
Matt Spinler2a28c932020-02-03 14:23:40 -0600216DBusPropertyMap
217 DataInterface::getAllProperties(const std::string& service,
218 const std::string& objectPath,
219 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500220{
221 DBusPropertyMap properties;
222
223 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
224 interface::dbusProperty, "GetAll");
225 method.append(interface);
Matt Spinler35a405b2022-03-02 11:42:42 -0600226 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500227
228 reply.read(properties);
229
230 return properties;
231}
232
Matt Spinlera7d9d962019-11-06 15:01:25 -0600233void DataInterface::getProperty(const std::string& service,
234 const std::string& objectPath,
235 const std::string& interface,
Matt Spinler2a28c932020-02-03 14:23:40 -0600236 const std::string& property,
237 DBusValue& value) const
Matt Spinlera7d9d962019-11-06 15:01:25 -0600238{
239
240 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
241 interface::dbusProperty, "Get");
242 method.append(interface, property);
Matt Spinler35a405b2022-03-02 11:42:42 -0600243 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlera7d9d962019-11-06 15:01:25 -0600244
245 reply.read(value);
246}
247
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600248DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
249{
250
251 auto method = _bus.new_method_call(
252 service_name::objectMapper, object_path::objectMapper,
253 interface::objectMapper, "GetSubTreePaths");
254
255 method.append(std::string{"/"}, 0, interfaces);
256
Matt Spinler35a405b2022-03-02 11:42:42 -0600257 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600258
259 DBusPathList paths;
260 reply.read(paths);
261
262 return paths;
263}
264
Matt Spinlerc8705e22019-09-11 12:36:07 -0500265DBusService DataInterface::getService(const std::string& objectPath,
Matt Spinlerb3f51862019-12-09 13:55:10 -0600266 const std::string& interface) const
Matt Spinlerc8705e22019-09-11 12:36:07 -0500267{
268 auto method = _bus.new_method_call(service_name::objectMapper,
269 object_path::objectMapper,
270 interface::objectMapper, "GetObject");
271
272 method.append(objectPath, std::vector<std::string>({interface}));
273
Matt Spinler35a405b2022-03-02 11:42:42 -0600274 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerc8705e22019-09-11 12:36:07 -0500275
276 std::map<DBusService, DBusInterfaceList> response;
277 reply.read(response);
278
279 if (!response.empty())
280 {
281 return response.begin()->first;
282 }
283
284 return std::string{};
285}
Matt Spinlera7d9d962019-11-06 15:01:25 -0600286
Matt Spinler677381b2020-01-23 10:04:29 -0600287void DataInterface::readBMCFWVersion()
288{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500289 _bmcFWVersion =
290 phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600291}
292
293void DataInterface::readServerFWVersion()
294{
Sumit Kumarcad16202021-05-13 04:06:15 -0500295 auto value =
296 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
297 if ((value != "") && (value.find_last_of(')') != std::string::npos))
298 {
299 std::size_t pos = value.find_first_of('(') + 1;
300 _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
301 }
Matt Spinlercad9c2b2019-12-02 15:42:01 -0600302}
303
Matt Spinler677381b2020-01-23 10:04:29 -0600304void DataInterface::readBMCFWVersionID()
305{
Matt Spinlerf61f2922020-06-23 11:32:49 -0500306 _bmcFWVersionID =
307 phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
Matt Spinler677381b2020-01-23 10:04:29 -0600308}
309
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500310std::string DataInterface::getMachineTypeModel() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600311{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500312 std::string model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600313 try
314 {
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600315
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500316 auto service = getService(object_path::systemInv, interface::invAsset);
317 if (!service.empty())
318 {
319 DBusValue value;
320 getProperty(service, object_path::systemInv, interface::invAsset,
321 "Model", value);
322
323 model = std::get<std::string>(value);
324 }
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600325 }
326 catch (const std::exception& e)
327 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500328 log<level::WARNING>(fmt::format("Failed reading Model property from "
329 "Interface: {} exception: {}",
330 interface::invAsset, e.what())
331 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600332 }
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500333
334 return model;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600335}
336
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500337std::string DataInterface::getMachineSerialNumber() const
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600338{
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500339 std::string sn;
340 try
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600341 {
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500342
343 auto service = getService(object_path::systemInv, interface::invAsset);
344 if (!service.empty())
345 {
346 DBusValue value;
347 getProperty(service, object_path::systemInv, interface::invAsset,
348 "SerialNumber", value);
349
350 sn = std::get<std::string>(value);
351 }
352 }
353 catch (const std::exception& e)
354 {
355 log<level::WARNING>(
356 fmt::format("Failed reading SerialNumber property from "
357 "Interface: {} exception: {}",
358 interface::invAsset, e.what())
359 .c_str());
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600360 }
361
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500362 return sn;
363}
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600364
Vijay Lobo81b4dca2021-04-29 00:04:00 -0500365std::string DataInterface::getMotherboardCCIN() const
366{
367 std::string ccin;
368
369 try
370 {
371 auto service =
372 getService(object_path::motherBoardInv, interface::viniRecordVPD);
373 if (!service.empty())
374 {
375 DBusValue value;
376 getProperty(service, object_path::motherBoardInv,
377 interface::viniRecordVPD, "CC", value);
378
379 auto cc = std::get<std::vector<uint8_t>>(value);
380 ccin = std::string{cc.begin(), cc.end()};
381 }
382 }
383 catch (const std::exception& e)
384 {
385 log<level::WARNING>(
386 fmt::format("Failed reading Motherboard CCIN property from "
387 "Interface: {} exception: {}",
388 interface::viniRecordVPD, e.what())
389 .c_str());
390 }
391
392 return ccin;
Matt Spinlerb3d488f2020-02-21 15:30:46 -0600393}
394
Ben Tynere32b7e72021-05-18 12:38:40 -0500395std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
396{
397 std::vector<uint8_t> systemIM;
398
399 try
400 {
401 auto service =
402 getService(object_path::motherBoardInv, interface::vsbpRecordVPD);
403 if (!service.empty())
404 {
405 DBusValue value;
406 getProperty(service, object_path::motherBoardInv,
407 interface::vsbpRecordVPD, "IM", value);
408
409 systemIM = std::get<std::vector<uint8_t>>(value);
410 }
411 }
412 catch (const std::exception& e)
413 {
414 log<level::WARNING>(
415 fmt::format("Failed reading System IM property from "
416 "Interface: {} exception: {}",
417 interface::vsbpRecordVPD, e.what())
418 .c_str());
419 }
420
421 return systemIM;
422}
423
Matt Spinler60c4e792020-03-13 13:45:36 -0500424void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
Matt Spinler60c4e792020-03-13 13:45:36 -0500425 std::string& fruPartNumber,
426 std::string& ccin,
427 std::string& serialNumber) const
428{
429 // For now, attempt to get all of the properties directly on the path
430 // passed in. In the future, may need to make use of an algorithm
431 // to figure out which inventory objects actually hold these
432 // interfaces in the case of non FRUs, or possibly another service
433 // will provide this info. Any missing interfaces will result
434 // in exceptions being thrown.
435
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500436 auto service = getService(inventoryPath, interface::viniRecordVPD);
Matt Spinler60c4e792020-03-13 13:45:36 -0500437
438 auto properties =
439 getAllProperties(service, inventoryPath, interface::viniRecordVPD);
440
441 auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
442 fruPartNumber = std::string{value.begin(), value.end()};
443
444 value = std::get<std::vector<uint8_t>>(properties["CC"]);
445 ccin = std::string{value.begin(), value.end()};
446
447 value = std::get<std::vector<uint8_t>>(properties["SN"]);
448 serialNumber = std::string{value.begin(), value.end()};
449}
450
Matt Spinler9b90e2a2020-04-14 10:59:04 -0500451std::string
452 DataInterface::getLocationCode(const std::string& inventoryPath) const
453{
454 auto service = getService(inventoryPath, interface::locCode);
455
456 DBusValue locCode;
457 getProperty(service, inventoryPath, interface::locCode, "LocationCode",
458 locCode);
459
460 return std::get<std::string>(locCode);
461}
462
Matt Spinler5fb24c12020-06-04 11:21:33 -0500463std::string
464 DataInterface::addLocationCodePrefix(const std::string& locationCode)
465{
466 static const std::string locationCodePrefix{"Ufcs-"};
467
Matt Spinler0e4d72e2020-08-05 12:36:53 -0500468 // Technically there are 2 location code prefixes, Ufcs and Umts, so
469 // if it already starts with a U then don't need to do anything.
470 if (locationCode.front() != 'U')
Matt Spinler5fb24c12020-06-04 11:21:33 -0500471 {
472 return locationCodePrefix + locationCode;
473 }
474
475 return locationCode;
476}
477
478std::string DataInterface::expandLocationCode(const std::string& locationCode,
Patrick Williamsd26fa3e2021-04-21 15:22:23 -0500479 uint16_t /*node*/) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500480{
Matt Spinler0d92b522021-06-16 13:28:17 -0600481 // Location codes for connectors are the location code of the FRU they are
482 // on, plus a '-Tx' segment. Remove this last segment before expanding it
483 // and then add it back in afterwards. This way, the connector doesn't have
484 // to be in the model just so that it can be expanded.
485 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
486
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500487 auto method =
488 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
489 interface::vpdManager, "GetExpandedLocationCode");
490
Matt Spinler0d92b522021-06-16 13:28:17 -0600491 method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500492
Matt Spinler35a405b2022-03-02 11:42:42 -0600493 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500494
495 std::string expandedLocationCode;
496 reply.read(expandedLocationCode);
497
Matt Spinler0d92b522021-06-16 13:28:17 -0600498 if (!connectorLoc.empty())
499 {
500 expandedLocationCode += connectorLoc;
501 }
502
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500503 return expandedLocationCode;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500504}
505
Matt Spinler2f9225a2020-08-05 12:58:49 -0500506std::string
507 DataInterface::getInventoryFromLocCode(const std::string& locationCode,
508 uint16_t node, bool expanded) const
Matt Spinler5fb24c12020-06-04 11:21:33 -0500509{
Matt Spinler2f9225a2020-08-05 12:58:49 -0500510 std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
511 : "GetFRUsByUnexpandedLocationCode";
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500512
Matt Spinler0d92b522021-06-16 13:28:17 -0600513 // Remove the connector segment, if present, so that this method call
514 // returns an inventory path that getHWCalloutFields() can be used with.
515 // (The serial number, etc, aren't stored on the connector in the
516 // inventory, and may not even be modeled.)
517 auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
518
Matt Spinler2f9225a2020-08-05 12:58:49 -0500519 auto method =
520 _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
521 interface::vpdManager, methodName.c_str());
522
523 if (expanded)
524 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600525 method.append(baseLoc);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500526 }
527 else
528 {
Matt Spinler0d92b522021-06-16 13:28:17 -0600529 method.append(addLocationCodePrefix(baseLoc), node);
Matt Spinler2f9225a2020-08-05 12:58:49 -0500530 }
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500531
Matt Spinler35a405b2022-03-02 11:42:42 -0600532 auto reply = _bus.call(method, dbusTimeout);
Matt Spinlerfcf9a3f2020-07-28 13:21:07 -0500533
534 std::vector<sdbusplus::message::object_path> entries;
535 reply.read(entries);
536
537 // Get the shortest entry from the paths received, as this
538 // would be the path furthest up the inventory hierarchy so
539 // would be the parent FRU. There is guaranteed to at least
540 // be one entry if the call didn't fail.
541 std::string shortest{entries[0]};
542
543 std::for_each(entries.begin(), entries.end(),
544 [&shortest](const auto& path) {
545 if (path.str.size() < shortest.size())
546 {
547 shortest = path;
548 }
549 });
550
551 return shortest;
Matt Spinler5fb24c12020-06-04 11:21:33 -0500552}
553
Matt Spinler34a904c2020-08-05 14:53:28 -0500554void DataInterface::assertLEDGroup(const std::string& ledGroup,
555 bool value) const
556{
557 DBusValue variant = value;
558 auto method =
559 _bus.new_method_call(service_name::ledGroupManager, ledGroup.c_str(),
560 interface::dbusProperty, "Set");
561 method.append(interface::ledGroup, "Asserted", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600562 _bus.call(method, dbusTimeout);
Matt Spinler34a904c2020-08-05 14:53:28 -0500563}
564
Matt Spinler993168d2021-04-07 16:05:03 -0500565void DataInterface::setFunctional(const std::string& objectPath,
566 bool value) const
567{
568 DBusValue variant = value;
569 auto service = getService(objectPath, interface::operationalStatus);
570
571 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
572 interface::dbusProperty, "Set");
573
574 method.append(interface::operationalStatus, "Functional", variant);
Matt Spinler35a405b2022-03-02 11:42:42 -0600575 _bus.call(method, dbusTimeout);
Matt Spinler993168d2021-04-07 16:05:03 -0500576}
577
Sumit Kumar76198a22021-07-15 05:59:57 -0500578using AssociationTuple = std::tuple<std::string, std::string, std::string>;
579using AssociationsProperty = std::vector<AssociationTuple>;
580
581void DataInterface::setCriticalAssociation(const std::string& objectPath) const
582{
583 DBusValue getAssociationValue;
584
Sumit Kumar027bf282022-01-24 11:25:19 -0600585 auto service = getService(objectPath, interface::associationDef);
Sumit Kumar76198a22021-07-15 05:59:57 -0500586
Sumit Kumar027bf282022-01-24 11:25:19 -0600587 getProperty(service, objectPath, interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500588 getAssociationValue);
589
590 auto association = std::get<AssociationsProperty>(getAssociationValue);
591
592 AssociationTuple critAssociation{
593 "health_rollup", "critical",
594 "/xyz/openbmc_project/inventory/system/chassis"};
595
596 if (std::find(association.begin(), association.end(), critAssociation) ==
597 association.end())
598 {
599 association.push_back(critAssociation);
600 DBusValue setAssociationValue = association;
601
602 auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
603 interface::dbusProperty, "Set");
604
Sumit Kumar027bf282022-01-24 11:25:19 -0600605 method.append(interface::associationDef, "Associations",
Sumit Kumar76198a22021-07-15 05:59:57 -0500606 setAssociationValue);
Matt Spinler35a405b2022-03-02 11:42:42 -0600607 _bus.call(method, dbusTimeout);
Sumit Kumar76198a22021-07-15 05:59:57 -0500608 }
609}
610
Matt Spinler1ab66962020-10-29 13:21:44 -0500611std::vector<std::string> DataInterface::getSystemNames() const
612{
613 DBusSubTree subtree;
614 DBusValue names;
615
616 auto method = _bus.new_method_call(service_name::objectMapper,
617 object_path::objectMapper,
618 interface::objectMapper, "GetSubTree");
619 method.append(std::string{"/"}, 0,
620 std::vector<std::string>{interface::compatible});
Matt Spinler35a405b2022-03-02 11:42:42 -0600621 auto reply = _bus.call(method, dbusTimeout);
Matt Spinler1ab66962020-10-29 13:21:44 -0500622
623 reply.read(subtree);
624 if (subtree.empty())
625 {
626 throw std::runtime_error("Compatible interface not on D-Bus");
627 }
628
629 const auto& object = *(subtree.begin());
630 const auto& path = object.first;
631 const auto& service = object.second.begin()->first;
632
633 getProperty(service, path, interface::compatible, "Names", names);
634
635 return std::get<std::vector<std::string>>(names);
636}
637
Sumit Kumar3b8ed7f2021-05-18 12:38:35 -0500638bool DataInterface::getQuiesceOnError() const
639{
640 bool ret = false;
641
642 try
643 {
644 auto service =
645 getService(object_path::logSetting, interface::logSetting);
646 if (!service.empty())
647 {
648 DBusValue value;
649 getProperty(service, object_path::logSetting, interface::logSetting,
650 "QuiesceOnHwError", value);
651
652 ret = std::get<bool>(value);
653 }
654 }
655 catch (const std::exception& e)
656 {
657 log<level::WARNING>(
658 fmt::format("Failed reading QuiesceOnHwError property from "
659 "Interface: {} exception: {}",
660 interface::logSetting, e.what())
661 .c_str());
662 }
663
664 return ret;
665}
666
Sumit Kumar9d43a722021-08-24 09:46:19 -0500667std::vector<bool>
668 DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
669{
670 DBusSubTree subtree;
671 std::vector<bool> result(type.size(), false);
672
673 // Query GetSubTree for the availability of dump interface
674 auto method = _bus.new_method_call(service_name::objectMapper,
675 object_path::objectMapper,
676 interface::objectMapper, "GetSubTree");
677 method.append(std::string{"/"}, 0,
678 std::vector<std::string>{interface::dumpEntry});
Matt Spinler35a405b2022-03-02 11:42:42 -0600679 auto reply = _bus.call(method, dbusTimeout);
Sumit Kumar9d43a722021-08-24 09:46:19 -0500680
681 reply.read(subtree);
682
683 if (subtree.empty())
684 {
685 return result;
686 }
687
688 std::vector<bool>::iterator itDumpStatus = result.begin();
689 uint8_t count = 0;
690 for (const auto& [path, serviceInfo] : subtree)
691 {
692 const auto& service = serviceInfo.begin()->first;
693 // Check for dump type on the object path
694 for (const auto& it : type)
695 {
696 if (path.find(it) != std::string::npos)
697 {
698 DBusValue value, progress;
699
700 // If dump type status is already available go for next path
701 if (*itDumpStatus)
702 {
703 break;
704 }
705
706 // Check for valid dump to be available if following
707 // conditions are met for the dump entry path -
708 // Offloaded == false and Status == Completed
709 getProperty(service, path, interface::dumpEntry, "Offloaded",
710 value);
711 getProperty(service, path, interface::dumpProgress, "Status",
712 progress);
713 auto offload = std::get<bool>(value);
714 auto status = std::get<std::string>(progress);
715 if (!offload && (status.find("Completed") != std::string::npos))
716 {
717 *itDumpStatus = true;
718 count++;
719 if (count >= type.size())
720 {
721 return result;
722 }
723 break;
724 }
725 }
Matt Spinler45796e82022-07-01 11:25:27 -0500726 ++itDumpStatus;
Sumit Kumar9d43a722021-08-24 09:46:19 -0500727 }
728 itDumpStatus = result.begin();
729 }
730
731 return result;
732}
733
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500734void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
735 const std::string& type,
736 const std::string& logPath) const
737{
738 try
739 {
740 auto method = _bus.new_method_call(
741 service_name::hwIsolation, object_path::hwIsolation,
742 interface::hwIsolationCreate, "CreateWithEntityPath");
743 method.append(binPath, type, sdbusplus::message::object_path(logPath));
744 // Note: hw isolation "CreateWithEntityPath" got dependency on logging
745 // api's. Making d-bus call no reply type to avoid cyclic dependency.
746 // Added minimal timeout to catch initial failures.
747 // Need to revisit this design later to avoid cyclic dependency.
Matt Spinler35a405b2022-03-02 11:42:42 -0600748 constexpr auto hwIsolationTimeout = 100000; // in micro seconds
749 _bus.call_noreply(method, hwIsolationTimeout);
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500750 }
751
Patrick Williams45e83522022-07-22 19:26:52 -0500752 catch (const sdbusplus::exception_t& e)
Jayanth Othayothecaa2fc2021-11-05 02:02:52 -0500753 {
754 std::string errName = e.name();
755 // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
756 // mentioned above. Ignoring the error.
757 if (errName != SD_BUS_ERROR_TIMEOUT)
758 {
759 log<level::ERR>(
760 fmt::format("GUARD D-Bus call exception"
761 "OBJPATH={}, INTERFACE={}, EXCEPTION={}",
762 object_path::hwIsolation,
763 interface::hwIsolationCreate, e.what())
764 .c_str());
765 }
766 }
767}
Sumit Kumar3e274432021-09-14 06:37:56 -0500768
769void DataInterface::createProgressSRC(
770 const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
771{
772 DBusValue variant = std::make_tuple(priSRC, srcStruct);
773
774 auto method = _bus.new_method_call(service_name::bootRawProgress,
775 object_path::bootRawSetting,
776 interface::dbusProperty, "Set");
777
778 method.append(interface::bootRawProgress, "Value", variant);
779
Matt Spinler35a405b2022-03-02 11:42:42 -0600780 _bus.call(method, dbusTimeout);
Sumit Kumar3e274432021-09-14 06:37:56 -0500781}
Sumit Kumar027bf282022-01-24 11:25:19 -0600782
783std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
784{
785 std::vector<std::string> association = {"xyz.openbmc_project.Association"};
786 std::string hwErrorLog = "/isolated_hw_errorlog";
787 std::string errorLog = "/error_log";
788 DBusPathList paths;
789 std::vector<uint32_t> ids;
790
791 // Get all latest mapper associations
792 paths = getPaths(association);
793 for (auto& path : paths)
794 {
795 // Look for object path with hardware isolation entry if any
796 size_t pos = path.find(hwErrorLog);
797 if (pos != std::string::npos)
798 {
799 // Get the object path
800 std::string ph = path;
801 ph.erase(pos, hwErrorLog.length());
802 auto service = getService(ph, interface::hwIsolationEntry);
803 if (!service.empty())
804 {
805 bool status;
806 DBusValue value;
807
808 // Read the Resolved property from object path
809 getProperty(service, ph, interface::hwIsolationEntry,
810 "Resolved", value);
811
812 status = std::get<bool>(value);
813
814 // If the entry isn't resolved
815 if (!status)
816 {
Matt Spinler45796e82022-07-01 11:25:27 -0500817 auto assocService =
818 getService(path, interface::association);
819 if (!assocService.empty())
Sumit Kumar027bf282022-01-24 11:25:19 -0600820 {
Matt Spinler45796e82022-07-01 11:25:27 -0500821 DBusValue endpoints;
Sumit Kumar027bf282022-01-24 11:25:19 -0600822
823 // Read Endpoints property
Matt Spinler45796e82022-07-01 11:25:27 -0500824 getProperty(assocService, path, interface::association,
825 "endpoints", endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600826
827 auto logPath =
Matt Spinler45796e82022-07-01 11:25:27 -0500828 std::get<std::vector<std::string>>(endpoints);
Sumit Kumar027bf282022-01-24 11:25:19 -0600829 if (!logPath.empty())
830 {
831 // Get OpenBMC event log Id
832 uint32_t id = stoi(logPath[0].substr(
833 logPath[0].find_last_of('/') + 1));
834 ids.push_back(id);
835 }
836 }
837 }
838 }
839 }
840
841 // Look for object path with error_log entry if any
842 pos = path.find(errorLog);
843 if (pos != std::string::npos)
844 {
845 auto service = getService(path, interface::association);
846 if (!service.empty())
847 {
848 DBusValue value;
849
850 // Read Endpoints property
851 getProperty(service, path, interface::association, "endpoints",
852 value);
853
854 auto logPath = std::get<std::vector<std::string>>(value);
855 if (!logPath.empty())
856 {
857 // Get OpenBMC event log Id
858 uint32_t id = stoi(
859 logPath[0].substr(logPath[0].find_last_of('/') + 1));
860 ids.push_back(id);
861 }
862 }
863 }
864 }
865
866 if (ids.size() > 1)
867 {
868 // remove duplicates to have only unique ids
869 std::sort(ids.begin(), ids.end());
870 ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
871 }
872 return ids;
873}
Matt Spinlerc8705e22019-09-11 12:36:07 -0500874} // namespace pels
875} // namespace openpower