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