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