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