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