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