1 /* 2 // Copyright (c) 2019 Intel 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 17 #include <boost/algorithm/string/join.hpp> 18 #include <boost/beast/core/span.hpp> 19 #include <iomanip> 20 #include <ipmi_to_redfish_hooks.hpp> 21 #include <phosphor-logging/log.hpp> 22 #include <sstream> 23 #include <storagecommands.hpp> 24 #include <string_view> 25 26 namespace intel_oem::ipmi::sel 27 { 28 29 namespace redfish_hooks 30 { 31 static void toHexStr(const boost::beast::span<uint8_t> bytes, 32 std::string& hexStr) 33 { 34 std::stringstream stream; 35 stream << std::hex << std::uppercase << std::setfill('0'); 36 for (const uint8_t& byte : bytes) 37 { 38 stream << std::setw(2) << static_cast<int>(byte); 39 } 40 hexStr = stream.str(); 41 } 42 43 static bool defaultMessageHook(const std::string& ipmiRaw) 44 { 45 // Log the record as a default Redfish message instead of a SEL record 46 47 static const std::string openBMCMessageRegistryVersion("0.1"); 48 std::string messageID = 49 "OpenBMC." + openBMCMessageRegistryVersion + ".SELEntryAdded"; 50 51 std::vector<std::string> messageArgs; 52 messageArgs.push_back(ipmiRaw); 53 54 // Log the Redfish message to the journal with the appropriate metadata 55 std::string journalMsg = "SEL Entry Added: " + ipmiRaw; 56 std::string messageArgsString = boost::algorithm::join(messageArgs, ","); 57 phosphor::logging::log<phosphor::logging::level::INFO>( 58 journalMsg.c_str(), 59 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageID.c_str()), 60 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s", 61 messageArgsString.c_str())); 62 63 return true; 64 } 65 66 // Record a BIOS message as a Redfish message instead of a SEL record 67 static bool biosMessageHook(const SELData& selData, const std::string& ipmiRaw) 68 { 69 // This is a BIOS message, so record it as a Redfish message instead 70 // of a SEL record 71 72 // Walk through the SEL request record to build the appropriate Redfish 73 // message 74 static constexpr std::string_view openBMCMessageRegistryVersion = "0.1"; 75 std::string messageID = 76 "OpenBMC." + std::string(openBMCMessageRegistryVersion); 77 std::vector<std::string> messageArgs; 78 BIOSSensors sensor = static_cast<BIOSSensors>(selData.sensorNum); 79 BIOSEventTypes eventType = static_cast<BIOSEventTypes>(selData.eventType); 80 switch (sensor) 81 { 82 case BIOSSensors::memoryRASConfigStatus: 83 switch (eventType) 84 { 85 case BIOSEventTypes::digitalDiscrete: 86 { 87 switch (selData.offset) 88 { 89 case 0x00: 90 messageID += ".MemoryRASConfigurationDisabled"; 91 break; 92 case 0x01: 93 messageID += ".MemoryRASConfigurationEnabled"; 94 break; 95 default: 96 return defaultMessageHook(ipmiRaw); 97 break; 98 } 99 // Get the message data from eventData2 and eventData3 100 101 // error = eventData2 bits [3:0] 102 int error = selData.eventData2 & 0x0F; 103 104 // mode = eventData3 bits [3:0] 105 int mode = selData.eventData3 & 0x0F; 106 107 // Save the messageArgs 108 switch (error) 109 { 110 case 0x00: 111 messageArgs.push_back("None"); 112 break; 113 case 0x03: 114 messageArgs.push_back("Invalid DIMM Config"); 115 break; 116 default: 117 messageArgs.push_back(std::to_string(error)); 118 break; 119 } 120 switch (mode) 121 { 122 case 0x00: 123 messageArgs.push_back("None"); 124 break; 125 case 0x01: 126 messageArgs.push_back("Mirroring"); 127 break; 128 case 0x02: 129 messageArgs.push_back("Lockstep"); 130 break; 131 case 0x04: 132 messageArgs.push_back("Rank Sparing"); 133 break; 134 default: 135 messageArgs.push_back(std::to_string(mode)); 136 break; 137 } 138 139 break; 140 } 141 default: 142 return defaultMessageHook(ipmiRaw); 143 break; 144 } 145 break; 146 case BIOSSensors::biosPOSTError: 147 switch (eventType) 148 { 149 case BIOSEventTypes::sensorSpecificOffset: 150 { 151 switch (selData.offset) 152 { 153 case 0x00: 154 messageID += ".BIOSPOSTError"; 155 break; 156 default: 157 return defaultMessageHook(ipmiRaw); 158 break; 159 } 160 // Get the message data from eventData2 and eventData3 161 162 std::array<uint8_t, 2> post; 163 // post LSB = eventData2 bits [7:0] 164 post[1] = selData.eventData2; 165 // post MSB = eventData3 bits [7:0] 166 post[0] = selData.eventData3; 167 168 // Save the messageArgs 169 messageArgs.emplace_back(); 170 std::string& postStr = messageArgs.back(); 171 toHexStr(boost::beast::span<uint8_t>(post), postStr); 172 173 break; 174 } 175 default: 176 return defaultMessageHook(ipmiRaw); 177 break; 178 } 179 break; 180 case BIOSSensors::intelUPILinkWidthReduced: 181 switch (eventType) 182 { 183 case BIOSEventTypes::oemDiscrete7: 184 { 185 switch (selData.offset) 186 { 187 case 0x01: 188 messageID += ".IntelUPILinkWidthReducedToHalf"; 189 break; 190 case 0x02: 191 messageID += ".IntelUPILinkWidthReducedToQuarter"; 192 break; 193 default: 194 return defaultMessageHook(ipmiRaw); 195 break; 196 } 197 // Get the message data from eventData2 198 199 // Node ID = eventData2 bits [7:0] 200 int node = selData.eventData2; 201 202 // Save the messageArgs 203 messageArgs.push_back(std::to_string(node + 1)); 204 205 break; 206 } 207 default: 208 return defaultMessageHook(ipmiRaw); 209 break; 210 } 211 break; 212 case BIOSSensors::memoryRASModeSelect: 213 switch (eventType) 214 { 215 case BIOSEventTypes::digitalDiscrete: 216 { 217 switch (selData.offset) 218 { 219 case 0x00: 220 messageID += ".MemoryRASModeDisabled"; 221 break; 222 case 0x01: 223 messageID += ".MemoryRASModeEnabled"; 224 break; 225 default: 226 return defaultMessageHook(ipmiRaw); 227 break; 228 } 229 // Get the message data from eventData2 and eventData3 230 231 // prior mode = eventData2 bits [3:0] 232 int priorMode = selData.eventData2 & 0x0F; 233 234 // selected mode = eventData3 bits [3:0] 235 int selectedMode = selData.eventData3 & 0x0F; 236 237 // Save the messageArgs 238 switch (priorMode) 239 { 240 case 0x00: 241 messageArgs.push_back("None"); 242 break; 243 case 0x01: 244 messageArgs.push_back("Mirroring"); 245 break; 246 case 0x02: 247 messageArgs.push_back("Lockstep"); 248 break; 249 case 0x04: 250 messageArgs.push_back("Rank Sparing"); 251 break; 252 default: 253 messageArgs.push_back(std::to_string(priorMode)); 254 break; 255 } 256 switch (selectedMode) 257 { 258 case 0x00: 259 messageArgs.push_back("None"); 260 break; 261 case 0x01: 262 messageArgs.push_back("Mirroring"); 263 break; 264 case 0x02: 265 messageArgs.push_back("Lockstep"); 266 break; 267 case 0x04: 268 messageArgs.push_back("Rank Sparing"); 269 break; 270 default: 271 messageArgs.push_back(std::to_string(selectedMode)); 272 break; 273 } 274 275 break; 276 } 277 default: 278 return defaultMessageHook(ipmiRaw); 279 break; 280 } 281 break; 282 case BIOSSensors::bootEvent: 283 switch (eventType) 284 { 285 case BIOSEventTypes::sensorSpecificOffset: 286 { 287 switch (selData.offset) 288 { 289 case 0x01: 290 messageID += ".BIOSBoot"; 291 break; 292 default: 293 return defaultMessageHook(ipmiRaw); 294 break; 295 } 296 break; 297 } 298 default: 299 return defaultMessageHook(ipmiRaw); 300 break; 301 } 302 break; 303 default: 304 return defaultMessageHook(ipmiRaw); 305 break; 306 } 307 308 // Log the Redfish message to the journal with the appropriate metadata 309 std::string journalMsg = "BIOS POST IPMI event: " + ipmiRaw; 310 if (messageArgs.empty()) 311 { 312 phosphor::logging::log<phosphor::logging::level::INFO>( 313 journalMsg.c_str(), 314 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", 315 messageID.c_str())); 316 } 317 else 318 { 319 std::string messageArgsString = 320 boost::algorithm::join(messageArgs, ","); 321 phosphor::logging::log<phosphor::logging::level::INFO>( 322 journalMsg.c_str(), 323 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", 324 messageID.c_str()), 325 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s", 326 messageArgsString.c_str())); 327 } 328 329 return true; 330 } 331 332 // Record a BIOS SMI message as a Redfish message instead of a SEL record 333 static bool biosSMIMessageHook(const SELData& selData, 334 const std::string& ipmiRaw) 335 { 336 // This is a BIOS SMI message, so record it as a Redfish message instead 337 // of a SEL record 338 339 // Walk through the SEL request record to build the appropriate Redfish 340 // message 341 static constexpr std::string_view openBMCMessageRegistryVersion = "0.1"; 342 std::string messageID = 343 "OpenBMC." + std::string(openBMCMessageRegistryVersion); 344 std::vector<std::string> messageArgs; 345 BIOSSMISensors sensor = static_cast<BIOSSMISensors>(selData.sensorNum); 346 BIOSEventTypes eventType = static_cast<BIOSEventTypes>(selData.eventType); 347 switch (sensor) 348 { 349 case BIOSSMISensors::mirroringRedundancyState: 350 switch (eventType) 351 { 352 case BIOSEventTypes::discreteRedundancyStates: 353 { 354 switch (selData.offset) 355 { 356 case 0x00: 357 messageID += ".MirroringRedundancyFull"; 358 break; 359 case 0x02: 360 messageID += ".MirroringRedundancyDegraded"; 361 break; 362 default: 363 return defaultMessageHook(ipmiRaw); 364 break; 365 } 366 // Get the message data from eventData2 and eventData3 367 368 // pair = eventData2 bits [7:4] 369 int pair = selData.eventData2 >> 4 & 0x0F; 370 // rank = eventData2 bits [1:0] 371 int rank = selData.eventData2 & 0x03; 372 373 // Socket ID = eventData3 bits [7:5] 374 int socket = selData.eventData3 >> 5 & 0x07; 375 // Channel = eventData3 bits [4:2] 376 int channel = selData.eventData3 >> 2 & 0x07; 377 char channelLetter[4] = {'A'}; 378 channelLetter[0] += channel; 379 // DIMM = eventData3 bits [1:0] 380 int dimm = selData.eventData3 & 0x03; 381 382 // Save the messageArgs 383 messageArgs.push_back(std::to_string(socket + 1)); 384 messageArgs.push_back(std::string(channelLetter)); 385 messageArgs.push_back(std::to_string(dimm + 1)); 386 messageArgs.push_back(std::to_string(pair)); 387 messageArgs.push_back(std::to_string(rank)); 388 389 break; 390 } 391 default: 392 return defaultMessageHook(ipmiRaw); 393 break; 394 } 395 break; 396 case BIOSSMISensors::memoryECCError: 397 switch (eventType) 398 { 399 case BIOSEventTypes::sensorSpecificOffset: 400 { 401 switch (selData.offset) 402 { 403 case 0x00: 404 messageID += ".MemoryECCCorrectable"; 405 break; 406 case 0x01: 407 messageID += ".MemoryECCUncorrectable"; 408 break; 409 default: 410 return defaultMessageHook(ipmiRaw); 411 break; 412 } 413 // Get the message data from eventData2 and eventData3 414 415 // dimm = eventData2 bits [7:4] 416 int dimm = selData.eventData2 >> 4 & 0x0F; 417 // rank = eventData2 bits [3:0] 418 int rank = selData.eventData2 & 0x0F; 419 420 // Socket ID = eventData3 bits [7:4] 421 int socket = selData.eventData3 >> 4 & 0x0F; 422 // Channel = eventData3 bits [3:0] 423 int channel = selData.eventData3 & 0x0F; 424 char channelLetter[4] = {'A'}; 425 channelLetter[0] += channel; 426 427 // Save the messageArgs 428 messageArgs.push_back(std::to_string(socket + 1)); 429 messageArgs.push_back(std::string(channelLetter)); 430 messageArgs.push_back(std::to_string(dimm)); 431 messageArgs.push_back(std::to_string(rank)); 432 433 break; 434 } 435 default: 436 return defaultMessageHook(ipmiRaw); 437 break; 438 } 439 break; 440 case BIOSSMISensors::legacyPCIError: 441 switch (eventType) 442 { 443 case BIOSEventTypes::sensorSpecificOffset: 444 { 445 switch (selData.offset) 446 { 447 case 0x04: 448 messageID += ".LegacyPCIPERR"; 449 break; 450 case 0x05: 451 messageID += ".LegacyPCISERR"; 452 break; 453 default: 454 return defaultMessageHook(ipmiRaw); 455 break; 456 } 457 // Get the message data from eventData2 and eventData3 458 459 // Bus = eventData2 bits [7:0] 460 int bus = selData.eventData2; 461 // Device = eventData3 bits [7:3] 462 int device = selData.eventData3 >> 3 & 0x1F; 463 // Function = eventData3 bits [2:0] 464 int function = selData.eventData3 >> 0x07; 465 466 // Save the messageArgs 467 messageArgs.push_back(std::to_string(bus)); 468 messageArgs.push_back(std::to_string(device)); 469 messageArgs.push_back(std::to_string(function)); 470 471 break; 472 } 473 default: 474 return defaultMessageHook(ipmiRaw); 475 break; 476 } 477 break; 478 case BIOSSMISensors::pcieFatalError: 479 switch (eventType) 480 { 481 case BIOSEventTypes::oemDiscrete0: 482 { 483 switch (selData.offset) 484 { 485 case 0x00: 486 messageID += ".PCIeFatalDataLinkLayerProtocol"; 487 break; 488 case 0x01: 489 messageID += ".PCIeFatalSurpriseLinkDown"; 490 break; 491 case 0x02: 492 messageID += ".PCIeFatalCompleterAbort"; 493 break; 494 case 0x03: 495 messageID += ".PCIeFatalUnsupportedRequest"; 496 break; 497 case 0x04: 498 messageID += ".PCIeFatalPoisonedTLP"; 499 break; 500 case 0x05: 501 messageID += ".PCIeFatalFlowControlProtocol"; 502 break; 503 case 0x06: 504 messageID += ".PCIeFatalCompletionTimeout"; 505 break; 506 case 0x07: 507 messageID += ".PCIeFatalReceiverBufferOverflow"; 508 break; 509 case 0x08: 510 messageID += ".PCIeFatalACSViolation"; 511 break; 512 case 0x09: 513 messageID += ".PCIeFatalMalformedTLP"; 514 break; 515 case 0x0a: 516 messageID += ".PCIeFatalECRCError"; 517 break; 518 case 0x0b: 519 messageID += 520 ".PCIeFatalReceivedFatalMessageFromDownstream"; 521 break; 522 case 0x0c: 523 messageID += ".PCIeFatalUnexpectedCompletion"; 524 break; 525 case 0x0d: 526 messageID += ".PCIeFatalReceivedErrNonFatalMessage"; 527 break; 528 case 0x0e: 529 messageID += ".PCIeFatalUncorrectableInternal"; 530 break; 531 case 0x0f: 532 messageID += ".PCIeFatalMCBlockedTLP"; 533 break; 534 default: 535 return defaultMessageHook(ipmiRaw); 536 break; 537 } 538 // Get the message data from eventData2 and eventData3 539 540 // Bus = eventData2 bits [7:0] 541 int bus = selData.eventData2; 542 // Device = eventData3 bits [7:3] 543 int device = selData.eventData3 >> 3 & 0x1F; 544 // Function = eventData3 bits [2:0] 545 int function = selData.eventData3 >> 0x07; 546 547 // Save the messageArgs 548 messageArgs.push_back(std::to_string(bus)); 549 messageArgs.push_back(std::to_string(device)); 550 messageArgs.push_back(std::to_string(function)); 551 552 break; 553 } 554 default: 555 return defaultMessageHook(ipmiRaw); 556 break; 557 } 558 break; 559 case BIOSSMISensors::pcieCorrectableError: 560 switch (eventType) 561 { 562 case BIOSEventTypes::oemDiscrete1: 563 { 564 switch (selData.offset) 565 { 566 case 0x00: 567 messageID += ".PCIeCorrectableReceiverError"; 568 break; 569 case 0x01: 570 messageID += ".PCIeCorrectableBadDLLP"; 571 break; 572 case 0x02: 573 messageID += ".PCIeCorrectableBadTLP"; 574 break; 575 case 0x03: 576 messageID += ".PCIeCorrectableReplayNumRollover"; 577 break; 578 case 0x04: 579 messageID += ".PCIeCorrectableReplayTimerTimeout"; 580 break; 581 case 0x05: 582 messageID += ".PCIeCorrectableAdvisoryNonFatal"; 583 break; 584 case 0x06: 585 messageID += ".PCIeCorrectableLinkBWChanged"; 586 break; 587 case 0x07: 588 messageID += ".PCIeCorrectableInternal"; 589 break; 590 case 0x08: 591 messageID += ".PCIeCorrectableHeaderLogOverflow"; 592 break; 593 case 0x0f: 594 messageID += ".PCIeCorrectableUnspecifiedAERError"; 595 break; 596 default: 597 return defaultMessageHook(ipmiRaw); 598 break; 599 } 600 // Get the message data from eventData2 and eventData3 601 602 // Bus = eventData2 bits [7:0] 603 int bus = selData.eventData2; 604 // Device = eventData3 bits [7:3] 605 int device = selData.eventData3 >> 3 & 0x1F; 606 // Function = eventData3 bits [2:0] 607 int function = selData.eventData3 >> 0x07; 608 609 // Save the messageArgs 610 messageArgs.push_back(std::to_string(bus)); 611 messageArgs.push_back(std::to_string(device)); 612 messageArgs.push_back(std::to_string(function)); 613 614 break; 615 } 616 default: 617 return defaultMessageHook(ipmiRaw); 618 break; 619 } 620 break; 621 case BIOSSMISensors::sparingRedundancyState: 622 switch (eventType) 623 { 624 case BIOSEventTypes::discreteRedundancyStates: 625 { 626 switch (selData.offset) 627 { 628 case 0x00: 629 messageID += ".SparingRedundancyFull"; 630 break; 631 case 0x02: 632 messageID += ".SparingRedundancyDegraded"; 633 break; 634 default: 635 return defaultMessageHook(ipmiRaw); 636 break; 637 } 638 // Get the message data from eventData2 and eventData3 639 640 // domain = eventData2 bits [7:4] 641 int domain = selData.eventData2 >> 4 & 0x0F; 642 char domainLetter[4] = {'A'}; 643 domainLetter[0] += domain; 644 // rank = eventData2 bits [1:0] 645 int rank = selData.eventData2 & 0x03; 646 647 // Socket ID = eventData3 bits [7:5] 648 int socket = selData.eventData3 >> 5 & 0x07; 649 // Channel = eventData3 bits [4:2] 650 int channel = selData.eventData3 >> 2 & 0x07; 651 char channelLetter[4] = {'A'}; 652 channelLetter[0] += channel; 653 // DIMM = eventData3 bits [1:0] 654 int dimm = selData.eventData3 & 0x03; 655 656 // Save the messageArgs 657 messageArgs.push_back(std::to_string(socket + 1)); 658 messageArgs.push_back(std::string(channelLetter)); 659 messageArgs.push_back(std::to_string(dimm + 1)); 660 messageArgs.push_back(std::string(domainLetter)); 661 messageArgs.push_back(std::to_string(rank)); 662 663 break; 664 } 665 default: 666 return defaultMessageHook(ipmiRaw); 667 break; 668 } 669 break; 670 case BIOSSMISensors::memoryParityError: 671 switch (eventType) 672 { 673 case BIOSEventTypes::sensorSpecificOffset: 674 { 675 switch (selData.offset) 676 { 677 case 0x03: 678 { 679 // type = eventData2 bits [2:0] 680 int type = selData.eventData2 & 0x07; 681 switch (type) 682 { 683 case 0x00: 684 messageID += ".MemoryParityNotKnown"; 685 break; 686 case 0x03: 687 messageID += 688 ".MemoryParityCommandAndAddress"; 689 break; 690 default: 691 return defaultMessageHook(ipmiRaw); 692 break; 693 } 694 break; 695 } 696 default: 697 return defaultMessageHook(ipmiRaw); 698 break; 699 } 700 // Get the message data from eventData2 and eventData3 701 702 // channelValid = eventData2 bit [4] 703 int channelValid = selData.eventData2 >> 4 & 0x01; 704 // dimmValid = eventData2 bit [3] 705 int dimmValid = selData.eventData2 >> 3 & 0x01; 706 707 // Socket ID = eventData3 bits [7:5] 708 int socket = selData.eventData3 >> 5 & 0x07; 709 // Channel = eventData3 bits [4:2] 710 int channel = selData.eventData3 >> 2 & 0x07; 711 char channelLetter[4] = {'A'}; 712 channelLetter[0] += channel; 713 // DIMM = eventData3 bits [1:0] 714 int dimm = selData.eventData3 & 0x03; 715 716 // Save the messageArgs 717 messageArgs.push_back(std::to_string(socket + 1)); 718 messageArgs.push_back(std::string(channelLetter)); 719 messageArgs.push_back(std::to_string(dimm + 1)); 720 messageArgs.push_back(std::to_string(channelValid)); 721 messageArgs.push_back(std::to_string(dimmValid)); 722 723 break; 724 } 725 default: 726 return defaultMessageHook(ipmiRaw); 727 break; 728 } 729 break; 730 case BIOSSMISensors::pcieFatalError2: 731 switch (eventType) 732 { 733 case BIOSEventTypes::oemDiscrete6: 734 { 735 switch (selData.offset) 736 { 737 case 0x00: 738 messageID += ".PCIeFatalAtomicEgressBlocked"; 739 break; 740 case 0x01: 741 messageID += ".PCIeFatalTLPPrefixBlocked"; 742 break; 743 case 0x0f: 744 messageID += 745 ".PCIeFatalUnspecifiedNonAERFatalError"; 746 break; 747 default: 748 return defaultMessageHook(ipmiRaw); 749 break; 750 } 751 // Get the message data from eventData2 and eventData3 752 753 // Bus = eventData2 bits [7:0] 754 int bus = selData.eventData2; 755 // Device = eventData3 bits [7:3] 756 int device = selData.eventData3 >> 3 & 0x1F; 757 // Function = eventData3 bits [2:0] 758 int function = selData.eventData3 >> 0x07; 759 760 // Save the messageArgs 761 messageArgs.push_back(std::to_string(bus)); 762 messageArgs.push_back(std::to_string(device)); 763 messageArgs.push_back(std::to_string(function)); 764 765 break; 766 } 767 default: 768 return defaultMessageHook(ipmiRaw); 769 break; 770 } 771 break; 772 case BIOSSMISensors::biosRecovery: 773 switch (eventType) 774 { 775 case BIOSEventTypes::oemDiscrete0: 776 { 777 switch (selData.offset) 778 { 779 case 0x01: 780 messageID += ".BIOSRecoveryStart"; 781 break; 782 default: 783 return defaultMessageHook(ipmiRaw); 784 break; 785 } 786 break; 787 } 788 case BIOSEventTypes::reservedF0: 789 { 790 switch (selData.offset) 791 { 792 case 0x01: 793 messageID += ".BIOSRecoveryComplete"; 794 break; 795 default: 796 return defaultMessageHook(ipmiRaw); 797 break; 798 } 799 break; 800 } 801 default: 802 return defaultMessageHook(ipmiRaw); 803 break; 804 } 805 break; 806 case BIOSSMISensors::adddcError: 807 switch (eventType) 808 { 809 case BIOSEventTypes::reservedA0: 810 { 811 messageID += ".ADDDCCorrectable"; 812 813 // Get the message data from eventData2 and eventData3 814 815 // dimm = eventData2 bits [7:4] 816 int dimm = selData.eventData2 >> 4 & 0x0F; 817 // rank = eventData2 bits [3:0] 818 int rank = selData.eventData2 & 0x0F; 819 820 // Socket ID = eventData3 bits [7:4] 821 int socket = selData.eventData3 >> 4 & 0x0F; 822 // Channel = eventData3 bits [3:0] 823 int channel = selData.eventData3 & 0x0F; 824 char channelLetter[4] = {'A'}; 825 channelLetter[0] += channel; 826 827 // Save the messageArgs 828 messageArgs.push_back(std::to_string(socket + 1)); 829 messageArgs.push_back(std::string(channelLetter)); 830 messageArgs.push_back(std::to_string(dimm)); 831 messageArgs.push_back(std::to_string(rank)); 832 833 break; 834 } 835 default: 836 return defaultMessageHook(ipmiRaw); 837 break; 838 } 839 break; 840 default: 841 return defaultMessageHook(ipmiRaw); 842 break; 843 } 844 845 // Log the Redfish message to the journal with the appropriate metadata 846 std::string journalMsg = "BIOS SMI IPMI event: " + ipmiRaw; 847 std::string messageArgsString = boost::algorithm::join(messageArgs, ","); 848 phosphor::logging::log<phosphor::logging::level::INFO>( 849 journalMsg.c_str(), 850 phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageID.c_str()), 851 phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s", 852 messageArgsString.c_str())); 853 854 return true; 855 } 856 857 static bool startRedfishHook(const SELData& selData, const std::string& ipmiRaw) 858 { 859 switch (selData.generatorID) 860 { 861 case 0x01: // Check if this message is from the BIOS Generator ID 862 // Let the BIOS hook handle this request 863 return biosMessageHook(selData, ipmiRaw); 864 break; 865 866 case 0x33: // Check if this message is from the BIOS SMI Generator ID 867 // Let the BIOS SMI hook handle this request 868 return biosSMIMessageHook(selData, ipmiRaw); 869 break; 870 } 871 872 // No hooks handled the request, so let it go to default 873 return defaultMessageHook(ipmiRaw); 874 } 875 } // namespace redfish_hooks 876 877 bool checkRedfishHooks(uint16_t recordID, uint8_t recordType, 878 uint32_t timestamp, uint16_t generatorID, uint8_t evmRev, 879 uint8_t sensorType, uint8_t sensorNum, uint8_t eventType, 880 uint8_t eventData1, uint8_t eventData2, 881 uint8_t eventData3) 882 { 883 // Save the raw IPMI string of the request 884 std::string ipmiRaw; 885 std::array selBytes = {static_cast<uint8_t>(recordID), 886 static_cast<uint8_t>(recordID >> 8), 887 recordType, 888 static_cast<uint8_t>(timestamp), 889 static_cast<uint8_t>(timestamp >> 8), 890 static_cast<uint8_t>(timestamp >> 16), 891 static_cast<uint8_t>(timestamp >> 24), 892 static_cast<uint8_t>(generatorID), 893 static_cast<uint8_t>(generatorID >> 8), 894 evmRev, 895 sensorType, 896 sensorNum, 897 eventType, 898 eventData1, 899 eventData2, 900 eventData3}; 901 redfish_hooks::toHexStr(boost::beast::span<uint8_t>(selBytes), ipmiRaw); 902 903 // First check that this is a system event record type since that 904 // determines the definition of the rest of the data 905 if (recordType != ipmi::sel::systemEvent) 906 { 907 // OEM record type, so let it go to the SEL 908 return redfish_hooks::defaultMessageHook(ipmiRaw); 909 } 910 911 // Extract the SEL data for the hook 912 redfish_hooks::SELData selData = {.generatorID = generatorID, 913 .sensorNum = sensorNum, 914 .eventType = eventType, 915 .offset = eventData1 & 0x0F, 916 .eventData2 = eventData2, 917 .eventData3 = eventData3}; 918 919 return redfish_hooks::startRedfishHook(selData, ipmiRaw); 920 } 921 922 bool checkRedfishHooks(uint8_t generatorID, uint8_t evmRev, uint8_t sensorType, 923 uint8_t sensorNum, uint8_t eventType, uint8_t eventData1, 924 uint8_t eventData2, uint8_t eventData3) 925 { 926 // Save the raw IPMI string of the selData 927 std::string ipmiRaw; 928 std::array selBytes = {generatorID, evmRev, sensorType, sensorNum, 929 eventType, eventData1, eventData2, eventData3}; 930 redfish_hooks::toHexStr(boost::beast::span<uint8_t>(selBytes), ipmiRaw); 931 932 // Extract the SEL data for the hook 933 redfish_hooks::SELData selData = {.generatorID = generatorID, 934 .sensorNum = sensorNum, 935 .eventType = eventType, 936 .offset = eventData1 & 0x0F, 937 .eventData2 = eventData2, 938 .eventData3 = eventData3}; 939 940 return redfish_hooks::startRedfishHook(selData, ipmiRaw); 941 } 942 943 } // namespace intel_oem::ipmi::sel 944