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>(¤tValVariant); 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 service = getService(path, interface::association); 818 if (!service.empty()) 819 { 820 DBusValue value; 821 822 // Read Endpoints property 823 getProperty(service, path, interface::association, 824 "endpoints", value); 825 826 auto logPath = 827 std::get<std::vector<std::string>>(value); 828 if (!logPath.empty()) 829 { 830 // Get OpenBMC event log Id 831 uint32_t id = stoi(logPath[0].substr( 832 logPath[0].find_last_of('/') + 1)); 833 ids.push_back(id); 834 } 835 } 836 } 837 } 838 } 839 840 // Look for object path with error_log entry if any 841 pos = path.find(errorLog); 842 if (pos != std::string::npos) 843 { 844 auto service = getService(path, interface::association); 845 if (!service.empty()) 846 { 847 DBusValue value; 848 849 // Read Endpoints property 850 getProperty(service, path, interface::association, "endpoints", 851 value); 852 853 auto logPath = std::get<std::vector<std::string>>(value); 854 if (!logPath.empty()) 855 { 856 // Get OpenBMC event log Id 857 uint32_t id = stoi( 858 logPath[0].substr(logPath[0].find_last_of('/') + 1)); 859 ids.push_back(id); 860 } 861 } 862 } 863 } 864 865 if (ids.size() > 1) 866 { 867 // remove duplicates to have only unique ids 868 std::sort(ids.begin(), ids.end()); 869 ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); 870 } 871 return ids; 872 } 873 } // namespace pels 874 } // namespace openpower 875