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 <fstream>
25 #include <iterator>
26 #include <phosphor-logging/log.hpp>
27 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
28 
29 // 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.
32 constexpr auto dbusTimeout = 10000000;
33 
34 namespace openpower
35 {
36 namespace pels
37 {
38 
39 namespace service_name
40 {
41 constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
42 constexpr auto vpdManager = "com.ibm.VPD.Manager";
43 constexpr auto ledGroupManager = "xyz.openbmc_project.LED.GroupManager";
44 constexpr auto logSetting = "xyz.openbmc_project.Settings";
45 constexpr auto hwIsolation = "org.open_power.HardwareIsolation";
46 constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
47 constexpr auto biosConfigMgr = "xyz.openbmc_project.BIOSConfigManager";
48 } // namespace service_name
49 
50 namespace object_path
51 {
52 constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper";
53 constexpr auto systemInv = "/xyz/openbmc_project/inventory/system";
54 constexpr auto chassisInv = "/xyz/openbmc_project/inventory/system/chassis";
55 constexpr auto motherBoardInv =
56     "/xyz/openbmc_project/inventory/system/chassis/motherboard";
57 constexpr auto baseInv = "/xyz/openbmc_project/inventory";
58 constexpr auto bmcState = "/xyz/openbmc_project/state/bmc0";
59 constexpr auto chassisState = "/xyz/openbmc_project/state/chassis0";
60 constexpr auto hostState = "/xyz/openbmc_project/state/host0";
61 constexpr auto pldm = "/xyz/openbmc_project/pldm";
62 constexpr auto enableHostPELs =
63     "/xyz/openbmc_project/logging/send_event_logs_to_host";
64 constexpr auto vpdManager = "/com/ibm/VPD/Manager";
65 constexpr auto logSetting = "/xyz/openbmc_project/logging/settings";
66 constexpr auto hwIsolation = "/xyz/openbmc_project/hardware_isolation";
67 constexpr auto bootRawSetting = "/xyz/openbmc_project/state/boot/raw0";
68 constexpr auto biosConfigMgr = "/xyz/openbmc_project/bios_config/manager";
69 } // namespace object_path
70 
71 namespace interface
72 {
73 constexpr auto dbusProperty = "org.freedesktop.DBus.Properties";
74 constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper";
75 constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset";
76 constexpr auto bootProgress = "xyz.openbmc_project.State.Boot.Progress";
77 constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
78 constexpr auto enable = "xyz.openbmc_project.Object.Enable";
79 constexpr auto bmcState = "xyz.openbmc_project.State.BMC";
80 constexpr auto chassisState = "xyz.openbmc_project.State.Chassis";
81 constexpr auto hostState = "xyz.openbmc_project.State.Host";
82 constexpr auto invMotherboard =
83     "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
84 constexpr auto viniRecordVPD = "com.ibm.ipzvpd.VINI";
85 constexpr auto vsbpRecordVPD = "com.ibm.ipzvpd.VSBP";
86 constexpr auto locCode = "xyz.openbmc_project.Inventory.Decorator.LocationCode";
87 constexpr auto compatible =
88     "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
89 constexpr auto vpdManager = "com.ibm.VPD.Manager";
90 constexpr auto ledGroup = "xyz.openbmc_project.Led.Group";
91 constexpr auto operationalStatus =
92     "xyz.openbmc_project.State.Decorator.OperationalStatus";
93 constexpr auto logSetting = "xyz.openbmc_project.Logging.Settings";
94 constexpr auto associationDef = "xyz.openbmc_project.Association.Definitions";
95 constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
96 constexpr auto dumpProgress = "xyz.openbmc_project.Common.Progress";
97 constexpr auto hwIsolationCreate = "org.open_power.HardwareIsolation.Create";
98 constexpr auto bootRawProgress = "xyz.openbmc_project.State.Boot.Raw";
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 } // namespace interface
103 
104 using namespace sdbusplus::xyz::openbmc_project::State::Boot::server;
105 using namespace phosphor::logging;
106 
107 std::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 
124 DataInterface::DataInterface(sdbusplus::bus_t& bus) : _bus(bus)
125 {
126     readBMCFWVersion();
127     readServerFWVersion();
128     readBMCFWVersionID();
129 
130     // Watch the BootProgress property
131     _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
132         bus, object_path::hostState, interface::bootProgress, "BootProgress",
133         *this, [this](const auto& value) {
134             this->_bootState = std::get<std::string>(value);
135             auto status = Progress::convertProgressStagesFromString(
136                 std::get<std::string>(value));
137 
138             if ((status == Progress::ProgressStages::SystemInitComplete) ||
139                 (status == Progress::ProgressStages::OSStart) ||
140                 (status == Progress::ProgressStages::OSRunning))
141             {
142                 setHostUp(true);
143             }
144             else
145             {
146                 setHostUp(false);
147             }
148         }));
149 
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) {
154             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             }
161             this->_sendPELsToHost = std::get<bool>(value);
162         }));
163 
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         }));
194 
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         }));
214 }
215 
216 DBusPropertyMap
217     DataInterface::getAllProperties(const std::string& service,
218                                     const std::string& objectPath,
219                                     const std::string& interface) const
220 {
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);
226     auto reply = _bus.call(method, dbusTimeout);
227 
228     reply.read(properties);
229 
230     return properties;
231 }
232 
233 void DataInterface::getProperty(const std::string& service,
234                                 const std::string& objectPath,
235                                 const std::string& interface,
236                                 const std::string& property,
237                                 DBusValue& value) const
238 {
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 
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 
257     auto reply = _bus.call(method, dbusTimeout);
258 
259     DBusPathList paths;
260     reply.read(paths);
261 
262     return paths;
263 }
264 
265 DBusService DataInterface::getService(const std::string& objectPath,
266                                       const std::string& interface) const
267 {
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 
274     auto reply = _bus.call(method, dbusTimeout);
275 
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 }
286 
287 void DataInterface::readBMCFWVersion()
288 {
289     _bmcFWVersion =
290         phosphor::logging::util::getOSReleaseValue("VERSION").value_or("");
291 }
292 
293 void DataInterface::readServerFWVersion()
294 {
295     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     }
302 }
303 
304 void DataInterface::readBMCFWVersionID()
305 {
306     _bmcFWVersionID =
307         phosphor::logging::util::getOSReleaseValue("VERSION_ID").value_or("");
308 }
309 
310 std::string DataInterface::getMachineTypeModel() const
311 {
312     std::string model;
313     try
314     {
315 
316         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         }
325     }
326     catch (const std::exception& e)
327     {
328         log<level::WARNING>(fmt::format("Failed reading Model property from "
329                                         "Interface: {} exception: {}",
330                                         interface::invAsset, e.what())
331                                 .c_str());
332     }
333 
334     return model;
335 }
336 
337 std::string DataInterface::getMachineSerialNumber() const
338 {
339     std::string sn;
340     try
341     {
342 
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());
360     }
361 
362     return sn;
363 }
364 
365 std::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;
393 }
394 
395 std::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 
424 void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
425                                        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 
436     auto service = getService(inventoryPath, interface::viniRecordVPD);
437 
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 
451 std::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 
463 std::string
464     DataInterface::addLocationCodePrefix(const std::string& locationCode)
465 {
466     static const std::string locationCodePrefix{"Ufcs-"};
467 
468     // 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')
471     {
472         return locationCodePrefix + locationCode;
473     }
474 
475     return locationCode;
476 }
477 
478 std::string DataInterface::expandLocationCode(const std::string& locationCode,
479                                               uint16_t /*node*/) const
480 {
481     // 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 
487     auto method =
488         _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
489                              interface::vpdManager, "GetExpandedLocationCode");
490 
491     method.append(addLocationCodePrefix(baseLoc), static_cast<uint16_t>(0));
492 
493     auto reply = _bus.call(method, dbusTimeout);
494 
495     std::string expandedLocationCode;
496     reply.read(expandedLocationCode);
497 
498     if (!connectorLoc.empty())
499     {
500         expandedLocationCode += connectorLoc;
501     }
502 
503     return expandedLocationCode;
504 }
505 
506 std::string
507     DataInterface::getInventoryFromLocCode(const std::string& locationCode,
508                                            uint16_t node, bool expanded) const
509 {
510     std::string methodName = expanded ? "GetFRUsByExpandedLocationCode"
511                                       : "GetFRUsByUnexpandedLocationCode";
512 
513     // 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 
519     auto method =
520         _bus.new_method_call(service_name::vpdManager, object_path::vpdManager,
521                              interface::vpdManager, methodName.c_str());
522 
523     if (expanded)
524     {
525         method.append(baseLoc);
526     }
527     else
528     {
529         method.append(addLocationCodePrefix(baseLoc), node);
530     }
531 
532     auto reply = _bus.call(method, dbusTimeout);
533 
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;
552 }
553 
554 void 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);
562     _bus.call(method, dbusTimeout);
563 }
564 
565 void 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);
575     _bus.call(method, dbusTimeout);
576 }
577 
578 using AssociationTuple = std::tuple<std::string, std::string, std::string>;
579 using AssociationsProperty = std::vector<AssociationTuple>;
580 
581 void DataInterface::setCriticalAssociation(const std::string& objectPath) const
582 {
583     DBusValue getAssociationValue;
584 
585     auto service = getService(objectPath, interface::associationDef);
586 
587     getProperty(service, objectPath, interface::associationDef, "Associations",
588                 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 
605         method.append(interface::associationDef, "Associations",
606                       setAssociationValue);
607         _bus.call(method, dbusTimeout);
608     }
609 }
610 
611 std::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});
621     auto reply = _bus.call(method, dbusTimeout);
622 
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 
638 bool 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 
667 std::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});
679     auto reply = _bus.call(method, dbusTimeout);
680 
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             }
726             ++itDumpStatus;
727         }
728         itDumpStatus = result.begin();
729     }
730 
731     return result;
732 }
733 
734 void 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.
748         constexpr auto hwIsolationTimeout = 100000; // in micro seconds
749         _bus.call_noreply(method, hwIsolationTimeout);
750     }
751 
752     catch (const sdbusplus::exception_t& e)
753     {
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 }
768 
769 void 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 
780     _bus.call(method, dbusTimeout);
781 }
782 
783 std::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                 {
817                     auto assocService =
818                         getService(path, interface::association);
819                     if (!assocService.empty())
820                     {
821                         DBusValue endpoints;
822 
823                         // Read Endpoints property
824                         getProperty(assocService, path, interface::association,
825                                     "endpoints", endpoints);
826 
827                         auto logPath =
828                             std::get<std::vector<std::string>>(endpoints);
829                         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 }
874 } // namespace pels
875 } // namespace openpower
876