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