1 /**
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  */
16 #include "config.h"
17 
18 #include "data_interface.hpp"
19 
20 #include "util.hpp"
21 
22 #include <fmt/format.h>
23 
24 #include <phosphor-logging/log.hpp>
25 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
26 
27 #include <fstream>
28 #include <iterator>
29 
30 // Use a timeout of 10s for D-Bus calls so if there are
31 // timeouts the callers of the PEL creation method won't
32 // also timeout.
33 constexpr auto dbusTimeout = 10000000;
34 
35 namespace openpower
36 {
37 namespace pels
38 {
39 
40 namespace service_name
41 {
42 constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
43 constexpr auto vpdManager = "com.ibm.VPD.Manager";
44 constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
45 constexpr auto logSetting = "xyz.openbmc_project.Settings";
46 constexpr auto hwIsolation = "org.open_power.HardwareIsolation";
47 constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager";
48 constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
49 } // namespace service_name
50 
51 namespace object_path
52 {
53 constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
54 constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
55 constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
56 constexpr auto motherBoardInv =
57     "/xyz/openbmc_project/inventory/system/chassis/motherboard";
58 constexpr auto baseInv = "/xyz/openbmc_project/inventory";
59 constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
60 constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
61 constexpr auto hostState = "/xyz/openbmc_project/state/host0";
62 constexpr auto pldm = "/xyz/openbmc_project/pldm";
63 constexpr auto enableHostPELs =
64     "/xyz/openbmc_project/logging/send_event_logs_to_host";
65 constexpr auto vpdManager = "/com/ibm/VPD/Manager";
66 constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
67 constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
68 constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
69 constexpr auto bootRawProgress = "/xyz/openbmc_project/state/boot/raw0";
70 } // namespace object_path
71 
72 namespace interface
73 {
74 constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
75 constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
76 constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
77 constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
78 constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
79 constexpr auto enable = "xyz.openbmc_project.Object.Enable";
80 constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
81 constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
82 constexpr auto hostState = "xyz.openbmc_project.State.Host";
83 constexpr auto invMotherboard =
84     "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
85 constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
86 constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
87 constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
88 constexpr auto compatible =
89     "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
90 constexpr auto vpdManager = "com.ibm.VPD.Manager";
91 constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
92 constexpr auto operationalStatus =
93     "xyz.openbmc_project.State.Decorator.OperationalStatus";
94 constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
95 constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
96 constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
97 constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
98 constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
99 constexpr auto hwIsolationEntry = "xyz.openbmc_project.HardwareIsolation.Entry";
100 constexpr auto association = "xyz.openbmc_project.Association";
101 constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfig.Manager";
102 constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
103 } // namespace interface
104 
105 using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
106 using namespace phosphor::logging;
107 
108 std::pair<std::string, std::string>
109     DataInterfaceBase::extractConnectorFromLocCode(
110         const std::string& locationCode)
111 {
112     auto base = locationCode;
113     std::string connector{};
114 
115     auto pos = base.find("-T");
116     if (pos != std::string::npos)
117     {
118         connector = base.substr(pos);
119         base = base.substr(0, pos);
120     }
121 
122     return {base, connector};
123 }
124 
125 DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus)
126 {
127     readBMCFWVersion();
128     readServerFWVersion();
129     readBMCFWVersionID();
130 
131     // Watch the BootProgress property
132     _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
133         bus, object_path::hostState, interface::bootProgress, "BootProgress",
134         *this, [this](const auto& value) {
135             this->_bootState = std::get<std::string>(value);
136             auto status = Progress::convertProgressStagesFromString(
137                 std::get<std::string>(value));
138 
139             if ((status == Progress::ProgressStages::SystemInitComplete) ||
140                 (status == Progress::ProgressStages::OSStart) ||
141                 (status == Progress::ProgressStages::OSRunning))
142             {
143                 setHostUp(true);
144             }
145             else
146             {
147                 setHostUp(false);
148             }
149         }));
150 
151     // Watch the host PEL enable property
152     _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
153         bus, object_path::enableHostPELs, interface::enable, "Enabled", *this,
154         [this](const auto& value) {
155             if (std::get<bool>(value) != this->_sendPELsToHost)
156             {
157                 log<level::INFO>(
158                     fmt::format("The send PELs to host setting changed to {}",
159                                 std::get<bool>(value))
160                         .c_str());
161             }
162             this->_sendPELsToHost = std::get<bool>(value);
163         }));
164 
165     // Watch the BMCState property
166     _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
167         bus, object_path::bmcState, interface::bmcState, "CurrentBMCState",
168         *this, [this](const auto& value) {
169             this->_bmcState = std::get<std::string>(value);
170         }));
171 
172     // Watch the chassis current and requested power state properties
173     _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
174         bus, object_path::chassisState, interface::chassisState, *this,
175         [this](const auto& properties) {
176             auto state = properties.find("CurrentPowerState");
177             if (state != properties.end())
178             {
179                 this->_chassisState = std::get<std::string>(state->second);
180             }
181 
182             auto trans = properties.find("RequestedPowerTransition");
183             if (trans != properties.end())
184             {
185                 this->_chassisTransition = std::get<std::string>(trans->second);
186             }
187         }));
188 
189     // Watch the CurrentHostState property
190     _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
191         bus, object_path::hostState, interface::hostState, "CurrentHostState",
192         *this, [this](const auto& value) {
193             this->_hostState = std::get<std::string>(value);
194         }));
195 
196     // Watch the BaseBIOSTable property for the hmc managed attribute
197     _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
198         bus, object_path::biosConfigMgr, interface::biosConfigMgr,
199         "BaseBIOSTable", service_name::biosConfigMgr, *this,
200         [this](const auto& value) {
201             const auto& attributes = std::get<BiosAttributes>(value);
202 
203             auto it = attributes.find("pvm_hmc_managed");
204             if (it != attributes.end())
205             {
206                 const auto& currentValVariant = std::get<5>(it->second);
207                 auto currentVal = std::get_if<std::string>(&currentValVariant);
208                 if (currentVal)
209                 {
210                     this->_hmcManaged = (*currentVal == "Enabled") ? true
211                                                                    : false;
212                 }
213             }
214         }));
215 }
216 
217 DBusPropertyMap
218     DataInterface::getAllProperties(const std::string& service,
219                                     const std::string& objectPath,
220                                     const std::string& interface) const
221 {
222     DBusPropertyMap properties;
223 
224     auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
225                                        interface::dbusProperty, "GetAll");
226     method.append(interface);
227     auto reply = _bus.call(method, dbusTimeout);
228 
229     reply.read(properties);
230 
231     return properties;
232 }
233 
234 void DataInterface::getProperty(const std::string& service,
235                                 const std::string& objectPath,
236                                 const std::string& interface,
237                                 const std::string& property,
238                                 DBusValue& value) const
239 {
240     auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
241                                        interface::dbusProperty, "Get");
242     method.append(interface, property);
243     auto reply = _bus.call(method, dbusTimeout);
244 
245     reply.read(value);
246 }
247 
248 DBusPathList DataInterface::getPaths(const DBusInterfaceList& interfaces) const
249 {
250     auto method = _bus.new_method_call(
251         service_name::objectMapper, object_path::objectMapper,
252         interface::objectMapper, "GetSubTreePaths");
253 
254     method.append(std::string{"/"}, 0, interfaces);
255 
256     auto reply = _bus.call(method, dbusTimeout);
257 
258     DBusPathList paths;
259     reply.read(paths);
260 
261     return paths;
262 }
263 
264 DBusService DataInterface::getService(const std::string& objectPath,
265                                       const std::string& interface) const
266 {
267     auto method = _bus.new_method_call(service_name::objectMapper,
268                                        object_path::objectMapper,
269                                        interface::objectMapper, "GetObject");
270 
271     method.append(objectPath, std::vector<std::string>({interface}));
272 
273     auto reply = _bus.call(method, dbusTimeout);
274 
275     std::map<DBusService, DBusInterfaceList> response;
276     reply.read(response);
277 
278     if (!response.empty())
279     {
280         return response.begin()->first;
281     }
282 
283     return std::string{};
284 }
285 
286 void DataInterface::readBMCFWVersion()
287 {
288     _bmcFWVersion =
289         phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
290 }
291 
292 void DataInterface::readServerFWVersion()
293 {
294     auto value =
295         phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
296     if ((value != "") && (value.find_last_of(')') != std::string::npos))
297     {
298         std::size_t pos = value.find_first_of('(') + 1;
299         _serverFWVersion = value.substr(pos, value.find_last_of(')') - pos);
300     }
301 }
302 
303 void DataInterface::readBMCFWVersionID()
304 {
305     _bmcFWVersionID =
306         phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
307 }
308 
309 std::string DataInterface::getMachineTypeModel() const
310 {
311     std::string model;
312     try
313     {
314         auto service = getService(object_path::systemInv, interface::invAsset);
315         if (!service.empty())
316         {
317             DBusValue value;
318             getProperty(service, object_path::systemInv, interface::invAsset,
319                         "Model", value);
320 
321             model = std::get<std::string>(value);
322         }
323     }
324     catch (const std::exception& e)
325     {
326         log<level::WARNING>(fmt::format("Failed reading Model property from "
327                                         "Interface: {} exception: {}",
328                                         interface::invAsset, e.what())
329                                 .c_str());
330     }
331 
332     return model;
333 }
334 
335 std::string DataInterface::getMachineSerialNumber() const
336 {
337     std::string sn;
338     try
339     {
340         auto service = getService(object_path::systemInv, interface::invAsset);
341         if (!service.empty())
342         {
343             DBusValue value;
344             getProperty(service, object_path::systemInv, interface::invAsset,
345                         "SerialNumber", value);
346 
347             sn = std::get<std::string>(value);
348         }
349     }
350     catch (const std::exception& e)
351     {
352         log<level::WARNING>(
353             fmt::format("Failed reading SerialNumber property from "
354                         "Interface: {} exception: {}",
355                         interface::invAsset, e.what())
356                 .c_str());
357     }
358 
359     return sn;
360 }
361 
362 std::string DataInterface::getMotherboardCCIN() const
363 {
364     std::string ccin;
365 
366     try
367     {
368         auto service = getService(object_path::motherBoardInv,
369                                   interface::viniRecordVPD);
370         if (!service.empty())
371         {
372             DBusValue value;
373             getProperty(service, object_path::motherBoardInv,
374                         interface::viniRecordVPD, "CC", value);
375 
376             auto cc = std::get<std::vector<uint8_t>>(value);
377             ccin = std::string{cc.begin(), cc.end()};
378         }
379     }
380     catch (const std::exception& e)
381     {
382         log<level::WARNING>(
383             fmt::format("Failed reading Motherboard CCIN property from "
384                         "Interface: {} exception: {}",
385                         interface::viniRecordVPD, e.what())
386                 .c_str());
387     }
388 
389     return ccin;
390 }
391 
392 std::vector<uint8_t> DataInterface::getSystemIMKeyword() const
393 {
394     std::vector<uint8_t> systemIM;
395 
396     try
397     {
398         auto service = getService(object_path::motherBoardInv,
399                                   interface::vsbpRecordVPD);
400         if (!service.empty())
401         {
402             DBusValue value;
403             getProperty(service, object_path::motherBoardInv,
404                         interface::vsbpRecordVPD, "IM", value);
405 
406             systemIM = std::get<std::vector<uint8_t>>(value);
407         }
408     }
409     catch (const std::exception& e)
410     {
411         log<level::WARNING>(
412             fmt::format("Failed reading System IM property from "
413                         "Interface: {} exception: {}",
414                         interface::vsbpRecordVPD, e.what())
415                 .c_str());
416     }
417 
418     return systemIM;
419 }
420 
421 void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
422                                        std::string& fruPartNumber,
423                                        std::string& ccin,
424                                        std::string& serialNumber) const
425 {
426     // For now, attempt to get all of the properties directly on the path
427     // passed in.  In the future, may need to make use of an algorithm
428     // to figure out which inventory objects actually hold these
429     // interfaces in the case of non FRUs, or possibly another service
430     // will provide this info.  Any missing interfaces will result
431     // in exceptions being thrown.
432 
433     auto service = getService(inventoryPath, interface::viniRecordVPD);
434 
435     auto properties = getAllProperties(service, inventoryPath,
436                                        interface::viniRecordVPD);
437 
438     auto value = std::get<std::vector<uint8_t>>(properties["FN"]);
439     fruPartNumber = std::string{value.begin(), value.end()};
440 
441     value = std::get<std::vector<uint8_t>>(properties["CC"]);
442     ccin = std::string{value.begin(), value.end()};
443 
444     value = std::get<std::vector<uint8_t>>(properties["SN"]);
445     serialNumber = std::string{value.begin(), value.end()};
446 }
447 
448 std::string
449     DataInterface::getLocationCode(const std::string& inventoryPath) const
450 {
451     auto service = getService(inventoryPath, interface::locCode);
452 
453     DBusValue locCode;
454     getProperty(service, inventoryPath, interface::locCode, "LocationCode",
455                 locCode);
456 
457     return std::get<std::string>(locCode);
458 }
459 
460 std::string
461     DataInterface::addLocationCodePrefix(const std::string& locationCode)
462 {
463     static const std::string locationCodePrefix{"Ufcs-"};
464 
465     // Technically there are 2 location code prefixes, Ufcs and Umts, so
466     // if it already starts with a U then don't need to do anything.
467     if (locationCode.front() != 'U')
468     {
469         return locationCodePrefix + locationCode;
470     }
471 
472     return locationCode;
473 }
474 
475 std::string DataInterface::expandLocationCode(const std::string& locationCode,
476                                               uint16_t /*node*/) const
477 {
478     // Location codes for connectors are the location code of the FRU they are
479     // on, plus a '-Tx' segment.  Remove this last segment before expanding it
480     // and then add it back in afterwards.  This way, the connector doesn't have
481     // to be in the model just so that it can be expanded.
482     auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
483 
484     auto method =
485         _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
486                              interface::vpdManager, "GetExpandedLocationCode");
487 
488     method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
489 
490     auto reply = _bus.call(method, dbusTimeout);
491 
492     std::string expandedLocationCode;
493     reply.read(expandedLocationCode);
494 
495     if (!connectorLoc.empty())
496     {
497         expandedLocationCode += connectorLoc;
498     }
499 
500     return expandedLocationCode;
501 }
502 
503 std::string
504     DataInterface::getInventoryFromLocCode(const std::string& locationCode,
505                                            uint16_t node, bool expanded) const
506 {
507     std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
508                                       : "GetFRUsByUnexpandedLocationCode";
509 
510     // Remove the connector segment, if present, so that this method call
511     // returns an inventory path that getHWCalloutFields() can be used with.
512     // (The serial number, etc, aren't stored on the connector in the
513     // inventory, and may not even be modeled.)
514     auto [baseLoc, connectorLoc] = extractConnectorFromLocCode(locationCode);
515 
516     auto method =
517         _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
518                              interface::vpdManager, methodName.c_str());
519 
520     if (expanded)
521     {
522         method.append(baseLoc);
523     }
524     else
525     {
526         method.append(addLocationCodePrefix(baseLoc), node);
527     }
528 
529     auto reply = _bus.call(method, dbusTimeout);
530 
531     std::vector<sdbusplus::message::object_path> entries;
532     reply.read(entries);
533 
534     // Get the shortest entry from the paths received, as this
535     // would be the path furthest up the inventory hierarchy so
536     // would be the parent FRU.  There is guaranteed to at least
537     // be one entry if the call didn't fail.
538     std::string shortest{entries[0]};
539 
540     std::for_each(entries.begin(), entries.end(),
541                   [&shortest](const auto& path) {
542                       if (path.str.size() < shortest.size())
543                       {
544                           shortest = path;
545                       }
546                   });
547 
548     return shortest;
549 }
550 
551 void DataInterface::assertLEDGroup(const std::string& ledGroup,
552                                    bool value) const
553 {
554     DBusValue variant = value;
555     auto method = _bus.new_method_call(service_name::ledGroupManager,
556                                        ledGroup.c_str(),
557                                        interface::dbusProperty, "Set");
558     method.append(interface::ledGroup, "Asserted", variant);
559     _bus.call(method, dbusTimeout);
560 }
561 
562 void DataInterface::setFunctional(const std::string& objectPath,
563                                   bool value) const
564 {
565     DBusValue variant = value;
566     auto service = getService(objectPath, interface::operationalStatus);
567 
568     auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
569                                        interface::dbusProperty, "Set");
570 
571     method.append(interface::operationalStatus, "Functional", variant);
572     _bus.call(method, dbusTimeout);
573 }
574 
575 using AssociationTuple = std::tuple<std::string, std::string, std::string>;
576 using AssociationsProperty = std::vector<AssociationTuple>;
577 
578 void DataInterface::setCriticalAssociation(const std::string& objectPath) const
579 {
580     DBusValue getAssociationValue;
581 
582     auto service = getService(objectPath, interface::associationDef);
583 
584     getProperty(service, objectPath, interface::associationDef, "Associations",
585                 getAssociationValue);
586 
587     auto association = std::get<AssociationsProperty>(getAssociationValue);
588 
589     AssociationTuple critAssociation{
590         "health_rollup", "critical",
591         "/xyz/openbmc_project/inventory/system/chassis"};
592 
593     if (std::find(association.begin(), association.end(), critAssociation) ==
594         association.end())
595     {
596         association.push_back(critAssociation);
597         DBusValue setAssociationValue = association;
598 
599         auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
600                                            interface::dbusProperty, "Set");
601 
602         method.append(interface::associationDef, "Associations",
603                       setAssociationValue);
604         _bus.call(method, dbusTimeout);
605     }
606 }
607 
608 std::vector<std::string> DataInterface::getSystemNames() const
609 {
610     DBusSubTree subtree;
611     DBusValue names;
612 
613     auto method = _bus.new_method_call(service_name::objectMapper,
614                                        object_path::objectMapper,
615                                        interface::objectMapper, "GetSubTree");
616     method.append(std::string{"/"}, 0,
617                   std::vector<std::string>{interface::compatible});
618     auto reply = _bus.call(method, dbusTimeout);
619 
620     reply.read(subtree);
621     if (subtree.empty())
622     {
623         throw std::runtime_error("Compatible interface not on D-Bus");
624     }
625 
626     const auto& object = *(subtree.begin());
627     const auto& path = object.first;
628     const auto& service = object.second.begin()->first;
629 
630     getProperty(service, path, interface::compatible, "Names", names);
631 
632     return std::get<std::vector<std::string>>(names);
633 }
634 
635 bool DataInterface::getQuiesceOnError() const
636 {
637     bool ret = false;
638 
639     try
640     {
641         auto service = getService(object_path::logSetting,
642                                   interface::logSetting);
643         if (!service.empty())
644         {
645             DBusValue value;
646             getProperty(service, object_path::logSetting, interface::logSetting,
647                         "QuiesceOnHwError", value);
648 
649             ret = std::get<bool>(value);
650         }
651     }
652     catch (const std::exception& e)
653     {
654         log<level::WARNING>(
655             fmt::format("Failed reading QuiesceOnHwError property from "
656                         "Interface: {} exception: {}",
657                         interface::logSetting, e.what())
658                 .c_str());
659     }
660 
661     return ret;
662 }
663 
664 std::vector<bool>
665     DataInterface::checkDumpStatus(const std::vector<std::string>& type) const
666 {
667     DBusSubTree subtree;
668     std::vector<bool> result(type.size(), false);
669 
670     // Query GetSubTree for the availability of dump interface
671     auto method = _bus.new_method_call(service_name::objectMapper,
672                                        object_path::objectMapper,
673                                        interface::objectMapper, "GetSubTree");
674     method.append(std::string{"/"}, 0,
675                   std::vector<std::string>{interface::dumpEntry});
676     auto reply = _bus.call(method, dbusTimeout);
677 
678     reply.read(subtree);
679 
680     if (subtree.empty())
681     {
682         return result;
683     }
684 
685     std::vector<bool>::iterator itDumpStatus = result.begin();
686     uint8_t count = 0;
687     for (const auto& [path, serviceInfo] : subtree)
688     {
689         const auto& service = serviceInfo.begin()->first;
690         // Check for dump type on the object path
691         for (const auto& it : type)
692         {
693             if (path.find(it) != std::string::npos)
694             {
695                 DBusValue value, progress;
696 
697                 // If dump type status is already available go for next path
698                 if (*itDumpStatus)
699                 {
700                     break;
701                 }
702 
703                 // Check for valid dump to be available if following
704                 // conditions are met for the dump entry path -
705                 // Offloaded == false and Status == Completed
706                 getProperty(service, path, interface::dumpEntry, "Offloaded",
707                             value);
708                 getProperty(service, path, interface::dumpProgress, "Status",
709                             progress);
710                 auto offload = std::get<bool>(value);
711                 auto status = std::get<std::string>(progress);
712                 if (!offload && (status.find("Completed") != std::string::npos))
713                 {
714                     *itDumpStatus = true;
715                     count++;
716                     if (count >= type.size())
717                     {
718                         return result;
719                     }
720                     break;
721                 }
722             }
723             ++itDumpStatus;
724         }
725         itDumpStatus = result.begin();
726     }
727 
728     return result;
729 }
730 
731 void DataInterface::createGuardRecord(const std::vector<uint8_t>& binPath,
732                                       const std::string& type,
733                                       const std::string& logPath) const
734 {
735     try
736     {
737         auto method = _bus.new_method_call(
738             service_name::hwIsolation, object_path::hwIsolation,
739             interface::hwIsolationCreate, "CreateWithEntityPath");
740         method.append(binPath, type, sdbusplus::message::object_path(logPath));
741         // Note: hw isolation "CreateWithEntityPath" got dependency on logging
742         // api's. Making d-bus call no reply type to avoid cyclic dependency.
743         // Added minimal timeout to catch initial failures.
744         // Need to revisit this design later to avoid cyclic dependency.
745         constexpr auto hwIsolationTimeout = 100000; // in micro seconds
746         _bus.call_noreply(method, hwIsolationTimeout);
747     }
748 
749     catch (const sdbusplus::exception_t& e)
750     {
751         std::string errName = e.name();
752         // SD_BUS_ERROR_TIMEOUT error is expected, due to PEL api dependency
753         // mentioned above. Ignoring the error.
754         if (errName != SD_BUS_ERROR_TIMEOUT)
755         {
756             log<level::ERR>(
757                 fmt::format("GUARD D-Bus call exception"
758                             "OBJPATH={}, INTERFACE={}, EXCEPTION={}",
759                             object_path::hwIsolation,
760                             interface::hwIsolationCreate, e.what())
761                     .c_str());
762         }
763     }
764 }
765 
766 void DataInterface::createProgressSRC(
767     const uint64_t& priSRC, const std::vector<uint8_t>& srcStruct) const
768 {
769     DBusValue variant = std::make_tuple(priSRC, srcStruct);
770 
771     auto method = _bus.new_method_call(service_name::bootRawProgress,
772                                        object_path::bootRawProgress,
773                                        interface::dbusProperty, "Set");
774 
775     method.append(interface::bootRawProgress, "Value", variant);
776 
777     _bus.call(method, dbusTimeout);
778 }
779 
780 std::vector<uint32_t> DataInterface::getLogIDWithHwIsolation() const
781 {
782     std::vector<std::string> association = {"xyz.openbmc_project.Association"};
783     std::string hwErrorLog = "/isolated_hw_errorlog";
784     std::string errorLog = "/error_log";
785     DBusPathList paths;
786     std::vector<uint32_t> ids;
787 
788     // Get all latest mapper associations
789     paths = getPaths(association);
790     for (auto& path : paths)
791     {
792         // Look for object path with hardware isolation entry if any
793         size_t pos = path.find(hwErrorLog);
794         if (pos != std::string::npos)
795         {
796             // Get the object path
797             std::string ph = path;
798             ph.erase(pos, hwErrorLog.length());
799             auto service = getService(ph, interface::hwIsolationEntry);
800             if (!service.empty())
801             {
802                 bool status;
803                 DBusValue value;
804 
805                 // Read the Resolved property from object path
806                 getProperty(service, ph, interface::hwIsolationEntry,
807                             "Resolved", value);
808 
809                 status = std::get<bool>(value);
810 
811                 // If the entry isn't resolved
812                 if (!status)
813                 {
814                     auto assocService = getService(path,
815                                                    interface::association);
816                     if (!assocService.empty())
817                     {
818                         DBusValue endpoints;
819 
820                         // Read Endpoints property
821                         getProperty(assocService, path, interface::association,
822                                     "endpoints", endpoints);
823 
824                         auto logPath =
825                             std::get<std::vector<std::string>>(endpoints);
826                         if (!logPath.empty())
827                         {
828                             // Get OpenBMC event log Id
829                             uint32_t id = stoi(logPath[0].substr(
830                                 logPath[0].find_last_of('/') + 1));
831                             ids.push_back(id);
832                         }
833                     }
834                 }
835             }
836         }
837 
838         // Look for object path with error_log entry if any
839         pos = path.find(errorLog);
840         if (pos != std::string::npos)
841         {
842             auto service = getService(path, interface::association);
843             if (!service.empty())
844             {
845                 DBusValue value;
846 
847                 // Read Endpoints property
848                 getProperty(service, path, interface::association, "endpoints",
849                             value);
850 
851                 auto logPath = std::get<std::vector<std::string>>(value);
852                 if (!logPath.empty())
853                 {
854                     // Get OpenBMC event log Id
855                     uint32_t id = stoi(
856                         logPath[0].substr(logPath[0].find_last_of('/') + 1));
857                     ids.push_back(id);
858                 }
859             }
860         }
861     }
862 
863     if (ids.size() > 1)
864     {
865         // remove duplicates to have only unique ids
866         std::sort(ids.begin(), ids.end());
867         ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
868     }
869     return ids;
870 }
871 
872 std::vector<uint8_t> DataInterface::getRawProgressSRC(void) const
873 {
874     using RawProgressProperty = std::tuple<uint64_t, std::vector<uint8_t>>;
875 
876     DBusValue value;
877     getProperty(service_name::bootRawProgress, object_path::bootRawProgress,
878                 interface::bootRawProgress, "Value", value);
879 
880     const auto& rawProgress = std::get<RawProgressProperty>(value);
881     return std::get<1>(rawProgress);
882 }
883 
884 } // namespace pels
885 } // namespace openpower
886