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