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 "manager.hpp" 17 18 #include "additional_data.hpp" 19 #include "json_utils.hpp" 20 #include "pel.hpp" 21 #include "service_indicators.hpp" 22 23 #include <fmt/format.h> 24 #include <sys/inotify.h> 25 #include <unistd.h> 26 27 #include <filesystem> 28 #include <fstream> 29 #include <xyz/openbmc_project/Common/error.hpp> 30 #include <xyz/openbmc_project/Logging/Create/server.hpp> 31 32 namespace openpower 33 { 34 namespace pels 35 { 36 37 using namespace phosphor::logging; 38 namespace fs = std::filesystem; 39 namespace rg = openpower::pels::message; 40 41 namespace common_error = sdbusplus::xyz::openbmc_project::Common::Error; 42 43 using Create = sdbusplus::xyz::openbmc_project::Logging::server::Create; 44 45 namespace additional_data 46 { 47 constexpr auto rawPEL = "RAWPEL"; 48 constexpr auto esel = "ESEL"; 49 constexpr auto error = "ERROR_NAME"; 50 } // namespace additional_data 51 52 constexpr auto defaultLogMessage = "xyz.openbmc_project.Logging.Error.Default"; 53 54 Manager::~Manager() 55 { 56 if (_pelFileDeleteFD != -1) 57 { 58 if (_pelFileDeleteWatchFD != -1) 59 { 60 inotify_rm_watch(_pelFileDeleteFD, _pelFileDeleteWatchFD); 61 } 62 close(_pelFileDeleteFD); 63 } 64 } 65 66 void Manager::create(const std::string& message, uint32_t obmcLogID, 67 uint64_t timestamp, Entry::Level severity, 68 const std::vector<std::string>& additionalData, 69 const std::vector<std::string>& associations, 70 const FFDCEntries& ffdc) 71 { 72 AdditionalData ad{additionalData}; 73 74 // If a PEL was passed in via a filename or in an ESEL, 75 // use that. Otherwise, create one. 76 auto rawPelPath = ad.getValue(additional_data::rawPEL); 77 if (rawPelPath) 78 { 79 addRawPEL(*rawPelPath, obmcLogID); 80 } 81 else 82 { 83 auto esel = ad.getValue(additional_data::esel); 84 if (esel) 85 { 86 addESELPEL(*esel, obmcLogID); 87 } 88 else 89 { 90 createPEL(message, obmcLogID, timestamp, severity, additionalData, 91 associations, ffdc); 92 } 93 } 94 95 setEntryPath(obmcLogID); 96 setServiceProviderNotifyFlag(obmcLogID); 97 } 98 99 void Manager::addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID) 100 { 101 if (fs::exists(rawPelPath)) 102 { 103 std::ifstream file(rawPelPath, std::ios::in | std::ios::binary); 104 105 auto data = std::vector<uint8_t>(std::istreambuf_iterator<char>(file), 106 std::istreambuf_iterator<char>()); 107 if (file.fail()) 108 { 109 log<level::ERR>("Filesystem error reading a raw PEL", 110 entry("PELFILE=%s", rawPelPath.c_str()), 111 entry("OBMCLOGID=%d", obmcLogID)); 112 // TODO, Decide what to do here. Maybe nothing. 113 return; 114 } 115 116 file.close(); 117 118 addPEL(data, obmcLogID); 119 120 std::error_code ec; 121 fs::remove(rawPelPath, ec); 122 } 123 else 124 { 125 log<level::ERR>("Raw PEL file from BMC event log does not exist", 126 entry("PELFILE=%s", (rawPelPath).c_str()), 127 entry("OBMCLOGID=%d", obmcLogID)); 128 } 129 } 130 131 void Manager::addPEL(std::vector<uint8_t>& pelData, uint32_t obmcLogID) 132 { 133 auto pel = std::make_unique<openpower::pels::PEL>(pelData, obmcLogID); 134 if (pel->valid()) 135 { 136 // Assign Id other than to Hostbot PEL 137 if ((pel->privateHeader()).creatorID() != 138 static_cast<uint8_t>(CreatorID::hostboot)) 139 { 140 pel->assignID(); 141 } 142 else 143 { 144 const Repository::LogID id{Repository::LogID::Pel(pel->id())}; 145 auto result = _repo.hasPEL(id); 146 if (result) 147 { 148 log<level::WARNING>( 149 fmt::format("Duplicate HostBoot PEL Id {:#X} found; " 150 "moving it to archive folder", 151 pel->id()) 152 .c_str()); 153 154 _repo.archivePEL(*pel); 155 return; 156 } 157 } 158 159 // PELs created by others still need this field set by us. 160 pel->setCommitTime(); 161 162 // Update System Info to Extended User Data 163 pel->updateSysInfoInExtendedUserDataSection(*_dataIface); 164 165 try 166 { 167 log<level::DEBUG>( 168 fmt::format("Adding external PEL {:#x} (BMC ID {}) to repo", 169 pel->id(), obmcLogID) 170 .c_str()); 171 172 _repo.add(pel); 173 174 if (_repo.sizeWarning()) 175 { 176 scheduleRepoPrune(); 177 } 178 179 // Activate any resulting service indicators if necessary 180 auto policy = service_indicators::getPolicy(*_dataIface); 181 policy->activate(*pel); 182 } 183 catch (std::exception& e) 184 { 185 // Probably a full or r/o filesystem, not much we can do. 186 log<level::ERR>("Unable to add PEL to Repository", 187 entry("PEL_ID=0x%X", pel->id())); 188 } 189 190 // Check if firmware should quiesce system due to error 191 checkPelAndQuiesce(pel); 192 updateEventId(pel); 193 updateResolution(pel); 194 createPELEntry(obmcLogID); 195 } 196 else 197 { 198 log<level::ERR>("Invalid PEL received from the host", 199 entry("OBMCLOGID=%d", obmcLogID)); 200 201 AdditionalData ad; 202 ad.add("PLID", getNumberString("0x%08X", pel->plid())); 203 ad.add("OBMC_LOG_ID", std::to_string(obmcLogID)); 204 ad.add("PEL_SIZE", std::to_string(pelData.size())); 205 206 std::string asciiString; 207 auto src = pel->primarySRC(); 208 if (src) 209 { 210 asciiString = (*src)->asciiString(); 211 } 212 213 ad.add("SRC", asciiString); 214 215 _eventLogger.log("org.open_power.Logging.Error.BadHostPEL", 216 Entry::Level::Error, ad); 217 218 // Save it to a file for debug in the lab. Just keep the latest. 219 // Not adding it to the PEL because it could already be max size 220 // and don't want to truncate an already invalid PEL. 221 std::ofstream pelFile{getPELRepoPath() / "badPEL"}; 222 pelFile.write(reinterpret_cast<const char*>(pelData.data()), 223 pelData.size()); 224 } 225 } 226 227 void Manager::addESELPEL(const std::string& esel, uint32_t obmcLogID) 228 { 229 std::vector<uint8_t> data; 230 231 log<level::DEBUG>("Adding PEL from ESEL", 232 entry("OBMC_LOG_ID=%d", obmcLogID)); 233 234 try 235 { 236 data = std::move(eselToRawData(esel)); 237 } 238 catch (std::exception& e) 239 { 240 // Try to add it below anyway, so it follows the usual bad data path. 241 log<level::ERR>("Problems converting ESEL string to a byte vector"); 242 } 243 244 addPEL(data, obmcLogID); 245 } 246 247 std::vector<uint8_t> Manager::eselToRawData(const std::string& esel) 248 { 249 std::vector<uint8_t> data; 250 std::string byteString; 251 252 // As the eSEL string looks like: "50 48 00 ab ..." there are 3 253 // characters per raw byte, and since the actual PEL data starts 254 // at the 16th byte, the code will grab the PEL data starting at 255 // offset 48 in the string. 256 static constexpr size_t pelStart = 16 * 3; 257 258 if (esel.size() <= pelStart) 259 { 260 log<level::ERR>("ESEL data too short", 261 entry("ESEL_SIZE=%d", esel.size())); 262 263 throw std::length_error("ESEL data too short"); 264 } 265 266 for (size_t i = pelStart; i < esel.size(); i += 3) 267 { 268 if (i + 1 < esel.size()) 269 { 270 byteString = esel.substr(i, 2); 271 data.push_back(std::stoi(byteString, nullptr, 16)); 272 } 273 else 274 { 275 log<level::ERR>("ESEL data too short", 276 entry("ESEL_SIZE=%d", esel.size())); 277 throw std::length_error("ESEL data too short"); 278 } 279 } 280 281 return data; 282 } 283 284 void Manager::erase(uint32_t obmcLogID) 285 { 286 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)}; 287 288 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID); 289 _pelEntries.erase(path); 290 _repo.remove(id); 291 } 292 293 bool Manager::isDeleteProhibited(uint32_t /*obmcLogID*/) 294 { 295 return false; 296 } 297 298 PelFFDC Manager::convertToPelFFDC(const FFDCEntries& ffdc) 299 { 300 PelFFDC pelFFDC; 301 302 std::for_each(ffdc.begin(), ffdc.end(), [&pelFFDC](const auto& f) { 303 PelFFDCfile pf; 304 pf.subType = std::get<ffdcSubtypePos>(f); 305 pf.version = std::get<ffdcVersionPos>(f); 306 pf.fd = std::get<ffdcFDPos>(f); 307 308 switch (std::get<ffdcFormatPos>(f)) 309 { 310 case Create::FFDCFormat::JSON: 311 pf.format = UserDataFormat::json; 312 break; 313 case Create::FFDCFormat::CBOR: 314 pf.format = UserDataFormat::cbor; 315 break; 316 case Create::FFDCFormat::Text: 317 pf.format = UserDataFormat::text; 318 break; 319 case Create::FFDCFormat::Custom: 320 pf.format = UserDataFormat::custom; 321 break; 322 } 323 324 pelFFDC.push_back(pf); 325 }); 326 327 return pelFFDC; 328 } 329 330 void Manager::createPEL(const std::string& message, uint32_t obmcLogID, 331 uint64_t timestamp, 332 phosphor::logging::Entry::Level severity, 333 const std::vector<std::string>& additionalData, 334 const std::vector<std::string>& /*associations*/, 335 const FFDCEntries& ffdc) 336 { 337 auto entry = _registry.lookup(message, rg::LookupType::name); 338 auto pelFFDC = convertToPelFFDC(ffdc); 339 AdditionalData ad{additionalData}; 340 std::string msg; 341 342 if (!entry) 343 { 344 // Instead, get the default entry that means there is no 345 // other matching entry. This error will still use the 346 // AdditionalData values of the original error, and this 347 // code will add the error message value that wasn't found 348 // to this AD. This way, there will at least be a PEL, 349 // possibly with callouts, to allow users to debug the 350 // issue that caused the error even without its own PEL. 351 msg = "Event not found in PEL message registry: " + message; 352 log<level::INFO>(msg.c_str()); 353 354 entry = _registry.lookup(defaultLogMessage, rg::LookupType::name); 355 if (!entry) 356 { 357 log<level::ERR>("Default event not found in PEL message registry"); 358 return; 359 } 360 361 ad.add(additional_data::error, message); 362 } 363 364 auto pel = std::make_unique<openpower::pels::PEL>( 365 *entry, obmcLogID, timestamp, severity, ad, pelFFDC, *_dataIface); 366 367 _repo.add(pel); 368 369 if (_repo.sizeWarning()) 370 { 371 scheduleRepoPrune(); 372 } 373 374 auto src = pel->primarySRC(); 375 if (src) 376 { 377 auto msg = 378 fmt::format("Created PEL {:#x} (BMC ID {}) with SRC {}", pel->id(), 379 pel->obmcLogID(), (*src)->asciiString()); 380 while (msg.back() == ' ') 381 { 382 msg.pop_back(); 383 } 384 log<level::INFO>(msg.c_str()); 385 } 386 387 // Activate any resulting service indicators if necessary 388 auto policy = service_indicators::getPolicy(*_dataIface); 389 policy->activate(*pel); 390 391 // Check if firmware should quiesce system due to error 392 checkPelAndQuiesce(pel); 393 updateEventId(pel); 394 updateResolution(pel); 395 createPELEntry(obmcLogID); 396 } 397 398 sdbusplus::message::unix_fd Manager::getPEL(uint32_t pelID) 399 { 400 Repository::LogID id{Repository::LogID::Pel(pelID)}; 401 std::optional<int> fd; 402 403 log<level::DEBUG>("getPEL", entry("PEL_ID=0x%X", pelID)); 404 405 try 406 { 407 fd = _repo.getPELFD(id); 408 } 409 catch (std::exception& e) 410 { 411 throw common_error::InternalFailure(); 412 } 413 414 if (!fd) 415 { 416 throw common_error::InvalidArgument(); 417 } 418 419 scheduleFDClose(*fd); 420 421 return *fd; 422 } 423 424 void Manager::scheduleFDClose(int fd) 425 { 426 _fdCloserEventSource = std::make_unique<sdeventplus::source::Defer>( 427 _event, std::bind(std::mem_fn(&Manager::closeFD), this, fd, 428 std::placeholders::_1)); 429 } 430 431 void Manager::closeFD(int fd, sdeventplus::source::EventBase& /*source*/) 432 { 433 close(fd); 434 _fdCloserEventSource.reset(); 435 } 436 437 std::vector<uint8_t> Manager::getPELFromOBMCID(uint32_t obmcLogID) 438 { 439 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)}; 440 std::optional<std::vector<uint8_t>> data; 441 442 log<level::DEBUG>("getPELFromOBMCID", entry("OBMC_LOG_ID=%d", obmcLogID)); 443 444 try 445 { 446 data = _repo.getPELData(id); 447 } 448 catch (std::exception& e) 449 { 450 throw common_error::InternalFailure(); 451 } 452 453 if (!data) 454 { 455 throw common_error::InvalidArgument(); 456 } 457 458 return *data; 459 } 460 461 void Manager::hostAck(uint32_t pelID) 462 { 463 Repository::LogID id{Repository::LogID::Pel(pelID)}; 464 465 log<level::DEBUG>("HostAck", entry("PEL_ID=0x%X", pelID)); 466 467 if (!_repo.hasPEL(id)) 468 { 469 throw common_error::InvalidArgument(); 470 } 471 472 if (_hostNotifier) 473 { 474 _hostNotifier->ackPEL(pelID); 475 } 476 } 477 478 void Manager::hostReject(uint32_t pelID, RejectionReason reason) 479 { 480 Repository::LogID id{Repository::LogID::Pel(pelID)}; 481 482 log<level::DEBUG>("HostReject", entry("PEL_ID=0x%X", pelID), 483 entry("REASON=%d", static_cast<int>(reason))); 484 485 if (!_repo.hasPEL(id)) 486 { 487 throw common_error::InvalidArgument(); 488 } 489 490 if (reason == RejectionReason::BadPEL) 491 { 492 AdditionalData data; 493 data.add("BAD_ID", getNumberString("0x%08X", pelID)); 494 _eventLogger.log("org.open_power.Logging.Error.SentBadPELToHost", 495 Entry::Level::Informational, data); 496 if (_hostNotifier) 497 { 498 _hostNotifier->setBadPEL(pelID); 499 } 500 } 501 else if ((reason == RejectionReason::HostFull) && _hostNotifier) 502 { 503 _hostNotifier->setHostFull(pelID); 504 } 505 } 506 507 void Manager::scheduleRepoPrune() 508 { 509 _repoPrunerEventSource = std::make_unique<sdeventplus::source::Defer>( 510 _event, std::bind(std::mem_fn(&Manager::pruneRepo), this, 511 std::placeholders::_1)); 512 } 513 514 void Manager::pruneRepo(sdeventplus::source::EventBase& /*source*/) 515 { 516 auto idsToDelete = _repo.prune(); 517 518 // Remove the OpenBMC event logs for the PELs that were just removed. 519 std::for_each(idsToDelete.begin(), idsToDelete.end(), 520 [this](auto id) { this->_logManager.erase(id); }); 521 522 _repoPrunerEventSource.reset(); 523 } 524 525 void Manager::setupPELDeleteWatch() 526 { 527 _pelFileDeleteFD = inotify_init1(IN_NONBLOCK); 528 if (-1 == _pelFileDeleteFD) 529 { 530 auto e = errno; 531 std::string msg = 532 "inotify_init1 failed with errno " + std::to_string(e); 533 log<level::ERR>(msg.c_str()); 534 abort(); 535 } 536 537 _pelFileDeleteWatchFD = inotify_add_watch( 538 _pelFileDeleteFD, _repo.repoPath().c_str(), IN_DELETE); 539 if (-1 == _pelFileDeleteWatchFD) 540 { 541 auto e = errno; 542 std::string msg = 543 "inotify_add_watch failed with error " + std::to_string(e); 544 log<level::ERR>(msg.c_str()); 545 abort(); 546 } 547 548 _pelFileDeleteEventSource = std::make_unique<sdeventplus::source::IO>( 549 _event, _pelFileDeleteFD, EPOLLIN, 550 std::bind(std::mem_fn(&Manager::pelFileDeleted), this, 551 std::placeholders::_1, std::placeholders::_2, 552 std::placeholders::_3)); 553 } 554 555 void Manager::pelFileDeleted(sdeventplus::source::IO& /*io*/, int /*fd*/, 556 uint32_t revents) 557 { 558 if (!(revents & EPOLLIN)) 559 { 560 return; 561 } 562 563 // An event for 1 PEL uses 48B. When all PELs are deleted at once, 564 // as many events as there is room for can be handled in one callback. 565 // A size of 2000 will allow 41 to be processed, with additional 566 // callbacks being needed to process the remaining ones. 567 std::array<uint8_t, 2000> data{}; 568 auto bytesRead = read(_pelFileDeleteFD, data.data(), data.size()); 569 if (bytesRead < 0) 570 { 571 auto e = errno; 572 std::string msg = "Failed reading data from inotify event, errno = " + 573 std::to_string(e); 574 log<level::ERR>(msg.c_str()); 575 abort(); 576 } 577 578 auto offset = 0; 579 while (offset < bytesRead) 580 { 581 auto event = reinterpret_cast<inotify_event*>(&data[offset]); 582 if (event->mask & IN_DELETE) 583 { 584 std::string filename{event->name}; 585 586 // Get the PEL ID from the filename and tell the 587 // repo it's been removed, and then delete the BMC 588 // event log if it's there. 589 auto pos = filename.find_first_of('_'); 590 if (pos != std::string::npos) 591 { 592 try 593 { 594 auto idString = filename.substr(pos + 1); 595 auto pelID = std::stoul(idString, nullptr, 16); 596 597 Repository::LogID id{Repository::LogID::Pel(pelID)}; 598 auto removedLogID = _repo.remove(id); 599 if (removedLogID) 600 { 601 _logManager.erase(removedLogID->obmcID.id); 602 } 603 } 604 catch (const std::exception& e) 605 { 606 log<level::INFO>("Could not find PEL ID from its filename", 607 entry("FILENAME=%s", filename.c_str())); 608 } 609 } 610 } 611 612 offset += offsetof(inotify_event, name) + event->len; 613 } 614 } 615 616 std::tuple<uint32_t, uint32_t> Manager::createPELWithFFDCFiles( 617 std::string message, Entry::Level severity, 618 std::map<std::string, std::string> additionalData, 619 std::vector<std::tuple< 620 sdbusplus::xyz::openbmc_project::Logging::server::Create::FFDCFormat, 621 uint8_t, uint8_t, sdbusplus::message::unix_fd>> 622 fFDC) 623 { 624 _logManager.createWithFFDC(message, severity, additionalData, fFDC); 625 626 return {_logManager.lastEntryID(), _repo.lastPelID()}; 627 } 628 629 void Manager::checkPelAndQuiesce(std::unique_ptr<openpower::pels::PEL>& pel) 630 { 631 if ((pel->userHeader().severity() == 632 static_cast<uint8_t>(SeverityType::nonError)) || 633 (pel->userHeader().severity() == 634 static_cast<uint8_t>(SeverityType::recovered))) 635 { 636 log<level::DEBUG>( 637 "PEL severity informational or recovered. no quiesce needed"); 638 return; 639 } 640 if (!_logManager.isQuiesceOnErrorEnabled()) 641 { 642 log<level::DEBUG>("QuiesceOnHwError not enabled, no quiesce needed"); 643 return; 644 } 645 646 // Now check if it has any type of callout 647 if (pel->isCalloutPresent()) 648 { 649 log<level::INFO>( 650 "QuiesceOnHwError enabled, PEL severity not nonError or recovered, " 651 "and callout is present"); 652 653 _logManager.quiesceOnError(pel->obmcLogID()); 654 } 655 } 656 657 std::string Manager::getEventId(const openpower::pels::PEL& pel) const 658 { 659 std::string str; 660 auto src = pel.primarySRC(); 661 if (src) 662 { 663 const auto& hexwords = (*src)->hexwordData(); 664 665 std::string refcode = (*src)->asciiString(); 666 size_t pos = refcode.find_last_not_of(0x20); 667 if (pos != std::string::npos) 668 { 669 refcode.erase(pos + 1); 670 } 671 str = refcode; 672 673 for (auto& value : hexwords) 674 { 675 str += " "; 676 str += getNumberString("%08X", value); 677 } 678 } 679 return str; 680 } 681 682 void Manager::updateEventId(std::unique_ptr<openpower::pels::PEL>& pel) 683 { 684 std::string eventIdStr = getEventId(*pel); 685 686 auto entryN = _logManager.entries.find(pel->obmcLogID()); 687 if (entryN != _logManager.entries.end()) 688 { 689 entryN->second->eventId(eventIdStr); 690 } 691 } 692 693 std::string Manager::getResolution(const openpower::pels::PEL& pel) const 694 { 695 std::string str; 696 std::string resolution; 697 auto src = pel.primarySRC(); 698 if (src) 699 { 700 // First extract the callout pointer and then go through 701 const auto& callouts = (*src)->callouts(); 702 namespace pv = openpower::pels::pel_values; 703 // All PELs dont have callout, check before parsing callout data 704 if (callouts) 705 { 706 const auto& entries = callouts->callouts(); 707 // Entry starts with index 1 708 uint8_t index = 1; 709 for (auto& entry : entries) 710 { 711 resolution += std::to_string(index) + ". "; 712 // Adding Location code to resolution 713 if (!entry->locationCode().empty()) 714 resolution += 715 "Location Code: " + entry->locationCode() + ", "; 716 if (entry->fruIdentity()) 717 { 718 // Get priority and set the resolution string 719 str = pv::getValue(entry->priority(), 720 pel_values::calloutPriorityValues, 721 pel_values::registryNamePos); 722 str[0] = toupper(str[0]); 723 resolution += "Priority: " + str + ", "; 724 if (entry->fruIdentity()->getPN().has_value()) 725 { 726 resolution += 727 "PN: " + entry->fruIdentity()->getPN().value() + 728 ", "; 729 } 730 if (entry->fruIdentity()->getSN().has_value()) 731 { 732 resolution += 733 "SN: " + entry->fruIdentity()->getSN().value() + 734 ", "; 735 } 736 if (entry->fruIdentity()->getCCIN().has_value()) 737 { 738 resolution += 739 "CCIN: " + entry->fruIdentity()->getCCIN().value() + 740 ", "; 741 } 742 // Add the maintenance procedure 743 if (entry->fruIdentity()->getMaintProc().has_value()) 744 { 745 resolution += 746 "Procedure: " + 747 entry->fruIdentity()->getMaintProc().value() + ", "; 748 } 749 } 750 resolution.resize(resolution.size() - 2); 751 resolution += "\n"; 752 index++; 753 } 754 } 755 } 756 return resolution; 757 } 758 759 void Manager::updateResolution(std::unique_ptr<openpower::pels::PEL>& pel) 760 { 761 std::string callouts = getResolution(*pel); 762 auto entryN = _logManager.entries.find(pel->obmcLogID()); 763 if (entryN != _logManager.entries.end()) 764 { 765 entryN->second->resolution(callouts); 766 } 767 } 768 769 void Manager::setEntryPath(uint32_t obmcLogID) 770 { 771 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)}; 772 if (auto attributes = _repo.getPELAttributes(id); attributes) 773 { 774 auto& attr = attributes.value().get(); 775 auto entry = _logManager.entries.find(obmcLogID); 776 if (entry != _logManager.entries.end()) 777 { 778 entry->second->path(attr.path); 779 } 780 } 781 } 782 783 void Manager::setServiceProviderNotifyFlag(uint32_t obmcLogID) 784 { 785 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)}; 786 if (auto attributes = _repo.getPELAttributes(id); attributes) 787 { 788 auto& attr = attributes.value().get(); 789 auto entry = _logManager.entries.find(obmcLogID); 790 if (entry != _logManager.entries.end()) 791 { 792 entry->second->serviceProviderNotify( 793 attr.actionFlags.test(callHomeFlagBit)); 794 } 795 } 796 } 797 798 void Manager::createPELEntry(uint32_t obmcLogID) 799 { 800 std::map<std::string, PropertiesVariant> varData; 801 Repository::LogID id{Repository::LogID::Obmc(obmcLogID)}; 802 if (auto attributes = _repo.getPELAttributes(id); attributes) 803 { 804 namespace pv = openpower::pels::pel_values; 805 auto& attr = attributes.value().get(); 806 varData.emplace(std::string("Hidden"), 807 attr.actionFlags.test(hiddenFlagBit)); 808 varData.emplace( 809 std::string("Subsystem"), 810 pv::getValue(attr.subsystem, pel_values::subsystemValues)); 811 // Path to create PELEntry Interface is same as PEL 812 auto path = std::string(OBJ_ENTRY) + '/' + std::to_string(obmcLogID); 813 // Create Interface for PELEntry and set properties 814 auto pelEntry = std::make_unique<PELEntry>(_logManager.getBus(), 815 path.c_str(), varData); 816 _pelEntries.emplace(std::move(path), std::move(pelEntry)); 817 } 818 } 819 820 uint32_t Manager::getPELIdFromBMCLogId(uint32_t bmcLogId) 821 { 822 Repository::LogID id{Repository::LogID::Obmc(bmcLogId)}; 823 if (auto logId = _repo.getLogID(id); !logId.has_value()) 824 { 825 throw common_error::InvalidArgument(); 826 } 827 else 828 { 829 return logId->pelID.id; 830 } 831 } 832 833 uint32_t Manager::getBMCLogIdFromPELId(uint32_t pelId) 834 { 835 Repository::LogID id{Repository::LogID::Pel(pelId)}; 836 if (auto logId = _repo.getLogID(id); !logId.has_value()) 837 { 838 throw common_error::InvalidArgument(); 839 } 840 else 841 { 842 return logId->obmcID.id; 843 } 844 } 845 846 } // namespace pels 847 } // namespace openpower 848