Add hooks to route BIOS events to Redfish

This adds a hook to check the content of an IPMI SEL record
before it is added to the SEL.  If it comes from the BIOS,
the message will be logged as a Redfish event instead of
an IPMI SEL.

Change-Id: Ib6e6acfefc9f0a26e0e70f0712e1a5eb804edba4
Signed-off-by: Jason M. Bills <jason.m.bills@linux.intel.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 630a696..5ab4157 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -93,7 +93,7 @@
     src/storagecommands.cpp src/multinodecommands.cpp src/firmware-update.cpp
     src/smbioshandler.cpp src/smbiosmdrv2handler.cpp
     src/manufacturingcommands.cpp src/bmccontrolservices.cpp
-    src/bridgingcommands.cpp
+    src/bridgingcommands.cpp src/ipmi_to_redfish_hooks.cpp
 )
 set_target_properties (zinteloemcmds PROPERTIES VERSION "0.1.0")
 set_target_properties (zinteloemcmds PROPERTIES SOVERSION "0")
diff --git a/include/ipmi_to_redfish_hooks.hpp b/include/ipmi_to_redfish_hooks.hpp
new file mode 100644
index 0000000..91cf82e
--- /dev/null
+++ b/include/ipmi_to_redfish_hooks.hpp
@@ -0,0 +1,74 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#pragma once
+#include <storagecommands.hpp>
+
+namespace intel_oem::ipmi::sel
+{
+bool checkRedfishHooks(AddSELRequest* selRequest);
+bool checkRedfishHooks(uint8_t generatorID, uint8_t evmRev, uint8_t sensorType,
+                       uint8_t sensorNum, uint8_t eventType, uint8_t eventData1,
+                       uint8_t eventData2, uint8_t eventData3);
+namespace redfish_hooks
+{
+struct SELData
+{
+    int generatorID;
+    int sensorNum;
+    int eventType;
+    int offset;
+    int eventData2;
+    int eventData3;
+};
+
+enum class BIOSSensors
+{
+    memoryRASConfigStatus = 0x02,
+    biosPOSTError = 0x06,
+    intelUPILinkWidthReduced = 0x09,
+    memoryRASModeSelect = 0x12,
+    bootEvent = 0x83,
+};
+
+enum class BIOSSMISensors
+{
+    mirroringRedundancyState = 0x01,
+    memoryECCError = 0x02,
+    legacyPCIError = 0x03,
+    pcieFatalError = 0x04,
+    pcieCorrectableError = 0x05,
+    sparingRedundancyState = 0x11,
+    memoryParityError = 0x13,
+    pcieFatalError2 = 0x14,
+    biosRecovery = 0x15,
+    adddcError = 0x20,
+};
+
+enum class BIOSEventTypes
+{
+    digitalDiscrete = 0x09,
+    discreteRedundancyStates = 0x0b,
+    sensorSpecificOffset = 0x6f,
+    oemDiscrete0 = 0x70,
+    oemDiscrete1 = 0x71,
+    oemDiscrete6 = 0x76,
+    oemDiscrete7 = 0x77,
+    reservedA0 = 0xa0,
+    reservedF0 = 0xf0,
+};
+} // namespace redfish_hooks
+} // namespace intel_oem::ipmi::sel
diff --git a/src/ipmi_to_redfish_hooks.cpp b/src/ipmi_to_redfish_hooks.cpp
new file mode 100644
index 0000000..ff85081
--- /dev/null
+++ b/src/ipmi_to_redfish_hooks.cpp
@@ -0,0 +1,937 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+
+#include <boost/algorithm/string/join.hpp>
+#include <boost/beast/core/span.hpp>
+#include <iomanip>
+#include <ipmi_to_redfish_hooks.hpp>
+#include <phosphor-logging/log.hpp>
+#include <sstream>
+#include <storagecommands.hpp>
+#include <string_view>
+
+namespace intel_oem::ipmi::sel
+{
+
+namespace redfish_hooks
+{
+static void toHexStr(const boost::beast::span<uint8_t> bytes,
+                     std::string& hexStr)
+{
+    std::stringstream stream;
+    stream << std::hex << std::uppercase << std::setfill('0');
+    for (const uint8_t& byte : bytes)
+    {
+        stream << std::setw(2) << static_cast<int>(byte);
+    }
+    hexStr = stream.str();
+}
+
+// Record a BIOS message as a Redfish message instead of a SEL record
+static bool biosMessageHook(const SELData& selData, const std::string& ipmiRaw)
+{
+    // This is a BIOS message, so record it as a Redfish message instead
+    // of a SEL record
+
+    // Walk through the SEL request record to build the appropriate Redfish
+    // message
+    static constexpr std::string_view openBMCMessageRegistryVersion = "0.1";
+    std::string messageID =
+        "OpenBMC." + std::string(openBMCMessageRegistryVersion);
+    std::vector<std::string> messageArgs;
+    BIOSSensors sensor = static_cast<BIOSSensors>(selData.sensorNum);
+    BIOSEventTypes eventType = static_cast<BIOSEventTypes>(selData.eventType);
+    switch (sensor)
+    {
+        case BIOSSensors::memoryRASConfigStatus:
+            switch (eventType)
+            {
+                case BIOSEventTypes::digitalDiscrete:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x00:
+                            messageID += ".MemoryRASConfigurationDisabled";
+                            break;
+                        case 0x01:
+                            messageID += ".MemoryRASConfigurationEnabled";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    // error = eventData2 bits [3:0]
+                    int error = selData.eventData2 & 0x0F;
+
+                    // mode = eventData3 bits [3:0]
+                    int mode = selData.eventData3 & 0x0F;
+
+                    // Save the messageArgs
+                    switch (error)
+                    {
+                        case 0x00:
+                            messageArgs.push_back("None");
+                            break;
+                        case 0x03:
+                            messageArgs.push_back("Invalid DIMM Config");
+                            break;
+                        default:
+                            messageArgs.push_back(std::to_string(error));
+                            break;
+                    }
+                    switch (mode)
+                    {
+                        case 0x00:
+                            messageArgs.push_back("None");
+                            break;
+                        case 0x01:
+                            messageArgs.push_back("Mirroring");
+                            break;
+                        case 0x02:
+                            messageArgs.push_back("Lockstep");
+                            break;
+                        case 0x04:
+                            messageArgs.push_back("Rank Sparing");
+                            break;
+                        default:
+                            messageArgs.push_back(std::to_string(mode));
+                            break;
+                    }
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSensors::biosPOSTError:
+            switch (eventType)
+            {
+                case BIOSEventTypes::sensorSpecificOffset:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x00:
+                            messageID += ".BIOSPOSTError";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    std::array<uint8_t, 2> post;
+                    // post LSB = eventData2 bits [7:0]
+                    post[1] = selData.eventData2;
+                    // post MSB = eventData3 bits [7:0]
+                    post[0] = selData.eventData3;
+
+                    // Save the messageArgs
+                    messageArgs.emplace_back();
+                    std::string& postStr = messageArgs.back();
+                    toHexStr(boost::beast::span<uint8_t>(post), postStr);
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSensors::intelUPILinkWidthReduced:
+            switch (eventType)
+            {
+                case BIOSEventTypes::oemDiscrete7:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x01:
+                            messageID += ".IntelUPILinkWidthReducedToHalf";
+                            break;
+                        case 0x02:
+                            messageID += ".IntelUPILinkWidthReducedToQuarter";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2
+
+                    // Node ID = eventData2 bits [7:0]
+                    int node = selData.eventData2;
+
+                    // Save the messageArgs
+                    messageArgs.push_back(std::to_string(node + 1));
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSensors::memoryRASModeSelect:
+            switch (eventType)
+            {
+                case BIOSEventTypes::digitalDiscrete:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x00:
+                            messageID += ".MemoryRASModeDisabled";
+                            break;
+                        case 0x01:
+                            messageID += ".MemoryRASModeEnabled";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    // prior mode = eventData2 bits [3:0]
+                    int priorMode = selData.eventData2 & 0x0F;
+
+                    // selected mode = eventData3 bits [3:0]
+                    int selectedMode = selData.eventData3 & 0x0F;
+
+                    // Save the messageArgs
+                    switch (priorMode)
+                    {
+                        case 0x00:
+                            messageArgs.push_back("None");
+                            break;
+                        case 0x01:
+                            messageArgs.push_back("Mirroring");
+                            break;
+                        case 0x02:
+                            messageArgs.push_back("Lockstep");
+                            break;
+                        case 0x04:
+                            messageArgs.push_back("Rank Sparing");
+                            break;
+                        default:
+                            messageArgs.push_back(std::to_string(priorMode));
+                            break;
+                    }
+                    switch (selectedMode)
+                    {
+                        case 0x00:
+                            messageArgs.push_back("None");
+                            break;
+                        case 0x01:
+                            messageArgs.push_back("Mirroring");
+                            break;
+                        case 0x02:
+                            messageArgs.push_back("Lockstep");
+                            break;
+                        case 0x04:
+                            messageArgs.push_back("Rank Sparing");
+                            break;
+                        default:
+                            messageArgs.push_back(std::to_string(selectedMode));
+                            break;
+                    }
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSensors::bootEvent:
+            switch (eventType)
+            {
+                case BIOSEventTypes::sensorSpecificOffset:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x01:
+                            messageID += ".BIOSBoot";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        default:
+            messageID += ".Unknown";
+            messageArgs.push_back(ipmiRaw);
+            break;
+    }
+
+    // Log the Redfish message to the journal with the appropriate metadata
+    std::string journalMsg = "BIOS POST IPMI event: " + ipmiRaw;
+    if (messageArgs.empty())
+    {
+        phosphor::logging::log<phosphor::logging::level::INFO>(
+            journalMsg.c_str(),
+            phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
+                                     messageID.c_str()));
+    }
+    else
+    {
+        std::string messageArgsString =
+            boost::algorithm::join(messageArgs, ",");
+        phosphor::logging::log<phosphor::logging::level::INFO>(
+            journalMsg.c_str(),
+            phosphor::logging::entry("REDFISH_MESSAGE_ID=%s",
+                                     messageID.c_str()),
+            phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s",
+                                     messageArgsString.c_str()));
+    }
+
+    return true;
+}
+
+// Record a BIOS SMI message as a Redfish message instead of a SEL record
+static bool biosSMIMessageHook(const SELData& selData,
+                               const std::string& ipmiRaw)
+{
+    // This is a BIOS SMI message, so record it as a Redfish message instead
+    // of a SEL record
+
+    // Walk through the SEL request record to build the appropriate Redfish
+    // message
+    static constexpr std::string_view openBMCMessageRegistryVersion = "0.1";
+    std::string messageID =
+        "OpenBMC." + std::string(openBMCMessageRegistryVersion);
+    std::vector<std::string> messageArgs;
+    BIOSSMISensors sensor = static_cast<BIOSSMISensors>(selData.sensorNum);
+    BIOSEventTypes eventType = static_cast<BIOSEventTypes>(selData.eventType);
+    switch (sensor)
+    {
+        case BIOSSMISensors::mirroringRedundancyState:
+            switch (eventType)
+            {
+                case BIOSEventTypes::discreteRedundancyStates:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x00:
+                            messageID += ".MirroringRedundancyFull";
+                            break;
+                        case 0x02:
+                            messageID += ".MirroringRedundancyDegraded";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    // pair = eventData2 bits [7:4]
+                    int pair = selData.eventData2 >> 4 & 0x0F;
+                    // rank = eventData2 bits [1:0]
+                    int rank = selData.eventData2 & 0x03;
+
+                    // Socket ID = eventData3 bits [7:5]
+                    int socket = selData.eventData3 >> 5 & 0x07;
+                    // Channel = eventData3 bits [4:2]
+                    int channel = selData.eventData3 >> 2 & 0x07;
+                    char channelLetter[4] = {'A'};
+                    channelLetter[0] += channel;
+                    // DIMM = eventData3 bits [1:0]
+                    int dimm = selData.eventData3 & 0x03;
+
+                    // Save the messageArgs
+                    messageArgs.push_back(std::to_string(socket + 1));
+                    messageArgs.push_back(std::string(channelLetter));
+                    messageArgs.push_back(std::to_string(dimm + 1));
+                    messageArgs.push_back(std::to_string(pair));
+                    messageArgs.push_back(std::to_string(rank));
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSMISensors::memoryECCError:
+            switch (eventType)
+            {
+                case BIOSEventTypes::sensorSpecificOffset:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x00:
+                            messageID += ".MemoryECCCorrectable";
+                            break;
+                        case 0x01:
+                            messageID += ".MemoryECCUncorrectable";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    // dimm = eventData2 bits [7:4]
+                    int dimm = selData.eventData2 >> 4 & 0x0F;
+                    // rank = eventData2 bits [3:0]
+                    int rank = selData.eventData2 & 0x0F;
+
+                    // Socket ID = eventData3 bits [7:4]
+                    int socket = selData.eventData3 >> 4 & 0x0F;
+                    // Channel = eventData3 bits [3:0]
+                    int channel = selData.eventData3 & 0x0F;
+                    char channelLetter[4] = {'A'};
+                    channelLetter[0] += channel;
+
+                    // Save the messageArgs
+                    messageArgs.push_back(std::to_string(socket + 1));
+                    messageArgs.push_back(std::string(channelLetter));
+                    messageArgs.push_back(std::to_string(dimm));
+                    messageArgs.push_back(std::to_string(rank));
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSMISensors::legacyPCIError:
+            switch (eventType)
+            {
+                case BIOSEventTypes::sensorSpecificOffset:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x04:
+                            messageID += ".LegacyPCIPERR";
+                            break;
+                        case 0x05:
+                            messageID += ".LegacyPCISERR";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    // Bus = eventData2 bits [7:0]
+                    int bus = selData.eventData2;
+                    // Device = eventData3 bits [7:3]
+                    int device = selData.eventData3 >> 3 & 0x1F;
+                    // Function = eventData3 bits [2:0]
+                    int function = selData.eventData3 >> 0x07;
+
+                    // Save the messageArgs
+                    messageArgs.push_back(std::to_string(bus));
+                    messageArgs.push_back(std::to_string(device));
+                    messageArgs.push_back(std::to_string(function));
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSMISensors::pcieFatalError:
+            switch (eventType)
+            {
+                case BIOSEventTypes::oemDiscrete0:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x00:
+                            messageID += ".PCIeFatalDataLinkLayerProtocol";
+                            break;
+                        case 0x01:
+                            messageID += ".PCIeFatalSurpriseLinkDown";
+                            break;
+                        case 0x02:
+                            messageID += ".PCIeFatalCompleterAbort";
+                            break;
+                        case 0x03:
+                            messageID += ".PCIeFatalUnsupportedRequest";
+                            break;
+                        case 0x04:
+                            messageID += ".PCIeFatalPoisonedTLP";
+                            break;
+                        case 0x05:
+                            messageID += ".PCIeFatalFlowControlProtocol";
+                            break;
+                        case 0x06:
+                            messageID += ".PCIeFatalCompletionTimeout";
+                            break;
+                        case 0x07:
+                            messageID += ".PCIeFatalReceiverBufferOverflow";
+                            break;
+                        case 0x08:
+                            messageID += ".PCIeFatalACSViolation";
+                            break;
+                        case 0x09:
+                            messageID += ".PCIeFatalMalformedTLP";
+                            break;
+                        case 0x0a:
+                            messageID += ".PCIeFatalECRCError";
+                            break;
+                        case 0x0b:
+                            messageID +=
+                                ".PCIeFatalReceivedFatalMessageFromDownstream";
+                            break;
+                        case 0x0c:
+                            messageID += ".PCIeFatalUnexpectedCompletion";
+                            break;
+                        case 0x0d:
+                            messageID +=
+                                ".PCIeFatalReceivedERR_NONFATALMessage";
+                            break;
+                        case 0x0e:
+                            messageID += ".PCIeFatalUncorrectableInternal";
+                            break;
+                        case 0x0f:
+                            messageID += ".PCIeFatalMCBlockedTLP";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    // Bus = eventData2 bits [7:0]
+                    int bus = selData.eventData2;
+                    // Device = eventData3 bits [7:3]
+                    int device = selData.eventData3 >> 3 & 0x1F;
+                    // Function = eventData3 bits [2:0]
+                    int function = selData.eventData3 >> 0x07;
+
+                    // Save the messageArgs
+                    messageArgs.push_back(std::to_string(bus));
+                    messageArgs.push_back(std::to_string(device));
+                    messageArgs.push_back(std::to_string(function));
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSMISensors::pcieCorrectableError:
+            switch (eventType)
+            {
+                case BIOSEventTypes::oemDiscrete1:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x00:
+                            messageID += ".PCIeCorrectableReceiverError";
+                            break;
+                        case 0x01:
+                            messageID += ".PCIeCorrectableBadDLLP";
+                            break;
+                        case 0x02:
+                            messageID += ".PCIeCorrectableBadTLP";
+                            break;
+                        case 0x03:
+                            messageID += ".PCIeCorrectableReplayNumRollover";
+                            break;
+                        case 0x04:
+                            messageID += ".PCIeCorrectableReplayTimerTimeout";
+                            break;
+                        case 0x05:
+                            messageID += ".PCIeCorrectableAdvisoryNonFatal";
+                            break;
+                        case 0x06:
+                            messageID += ".PCIeCorrectableLinkBWChanged";
+                            break;
+                        case 0x07:
+                            messageID += ".PCIeCorrectableInternal";
+                            break;
+                        case 0x08:
+                            messageID += ".PCIeCorrectableHeaderLogOverflow";
+                            break;
+                        case 0x0f:
+                            messageID += ".PCIeCorrectableUnspecifiedAERError";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    // Bus = eventData2 bits [7:0]
+                    int bus = selData.eventData2;
+                    // Device = eventData3 bits [7:3]
+                    int device = selData.eventData3 >> 3 & 0x1F;
+                    // Function = eventData3 bits [2:0]
+                    int function = selData.eventData3 >> 0x07;
+
+                    // Save the messageArgs
+                    messageArgs.push_back(std::to_string(bus));
+                    messageArgs.push_back(std::to_string(device));
+                    messageArgs.push_back(std::to_string(function));
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSMISensors::sparingRedundancyState:
+            switch (eventType)
+            {
+                case BIOSEventTypes::discreteRedundancyStates:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x00:
+                            messageID += ".SparingRedundancyFull";
+                            break;
+                        case 0x02:
+                            messageID += ".SparingRedundancyDegraded";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    // domain = eventData2 bits [7:4]
+                    int domain = selData.eventData2 >> 4 & 0x0F;
+                    char domainLetter[4] = {'A'};
+                    domainLetter[0] += domain;
+                    // rank = eventData2 bits [1:0]
+                    int rank = selData.eventData2 & 0x03;
+
+                    // Socket ID = eventData3 bits [7:5]
+                    int socket = selData.eventData3 >> 5 & 0x07;
+                    // Channel = eventData3 bits [4:2]
+                    int channel = selData.eventData3 >> 2 & 0x07;
+                    char channelLetter[4] = {'A'};
+                    channelLetter[0] += channel;
+                    // DIMM = eventData3 bits [1:0]
+                    int dimm = selData.eventData3 & 0x03;
+
+                    // Save the messageArgs
+                    messageArgs.push_back(std::to_string(socket + 1));
+                    messageArgs.push_back(std::string(channelLetter));
+                    messageArgs.push_back(std::to_string(dimm + 1));
+                    messageArgs.push_back(std::string(domainLetter));
+                    messageArgs.push_back(std::to_string(rank));
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSMISensors::memoryParityError:
+            switch (eventType)
+            {
+                case BIOSEventTypes::sensorSpecificOffset:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x03:
+                        {
+                            // type = eventData2 bits [2:0]
+                            int type = selData.eventData2 & 0x07;
+                            switch (type)
+                            {
+                                case 0x00:
+                                    messageID += ".MemoryParityNotKnown";
+                                    break;
+                                case 0x03:
+                                    messageID +=
+                                        ".MemoryParityCommandAndAddress";
+                                    break;
+                                default:
+                                    messageID += ".Unknown";
+                                    messageArgs.push_back(ipmiRaw);
+                                    break;
+                            }
+                            break;
+                        }
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    // channelValid = eventData2 bit [4]
+                    int channelValid = selData.eventData2 >> 4 & 0x01;
+                    // dimmValid = eventData2 bit [3]
+                    int dimmValid = selData.eventData2 >> 3 & 0x01;
+
+                    // Socket ID = eventData3 bits [7:5]
+                    int socket = selData.eventData3 >> 5 & 0x07;
+                    // Channel = eventData3 bits [4:2]
+                    int channel = selData.eventData3 >> 2 & 0x07;
+                    char channelLetter[4] = {'A'};
+                    channelLetter[0] += channel;
+                    // DIMM = eventData3 bits [1:0]
+                    int dimm = selData.eventData3 & 0x03;
+
+                    // Save the messageArgs
+                    messageArgs.push_back(std::to_string(socket + 1));
+                    messageArgs.push_back(std::string(channelLetter));
+                    messageArgs.push_back(std::to_string(dimm + 1));
+                    messageArgs.push_back(std::to_string(channelValid));
+                    messageArgs.push_back(std::to_string(dimmValid));
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSMISensors::pcieFatalError2:
+            switch (eventType)
+            {
+                case BIOSEventTypes::oemDiscrete6:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x00:
+                            messageID += ".PCIeFatalAtomicEgressBlocked";
+                            break;
+                        case 0x01:
+                            messageID += ".PCIeFatalTLPPrefixBlocked";
+                            break;
+                        case 0x0f:
+                            messageID +=
+                                ".PCIeFatalUnspecifiedNonAERFatalError";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    // Get the message data from eventData2 and eventData3
+
+                    // Bus = eventData2 bits [7:0]
+                    int bus = selData.eventData2;
+                    // Device = eventData3 bits [7:3]
+                    int device = selData.eventData3 >> 3 & 0x1F;
+                    // Function = eventData3 bits [2:0]
+                    int function = selData.eventData3 >> 0x07;
+
+                    // Save the messageArgs
+                    messageArgs.push_back(std::to_string(bus));
+                    messageArgs.push_back(std::to_string(device));
+                    messageArgs.push_back(std::to_string(function));
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSMISensors::biosRecovery:
+            switch (eventType)
+            {
+                case BIOSEventTypes::oemDiscrete0:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x01:
+                            messageID += ".BIOSRecoveryStart";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    break;
+                }
+                case BIOSEventTypes::reservedF0:
+                {
+                    switch (selData.offset)
+                    {
+                        case 0x01:
+                            messageID += ".BIOSRecoveryComplete";
+                            break;
+                        default:
+                            messageID += ".Unknown";
+                            messageArgs.push_back(ipmiRaw);
+                            break;
+                    }
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        case BIOSSMISensors::adddcError:
+            switch (eventType)
+            {
+                case BIOSEventTypes::reservedA0:
+                {
+                    messageID += ".ADDDCCorrectable";
+
+                    // Get the message data from eventData2 and eventData3
+
+                    // dimm = eventData2 bits [7:4]
+                    int dimm = selData.eventData2 >> 4 & 0x0F;
+                    // rank = eventData2 bits [3:0]
+                    int rank = selData.eventData2 & 0x0F;
+
+                    // Socket ID = eventData3 bits [7:4]
+                    int socket = selData.eventData3 >> 4 & 0x0F;
+                    // Channel = eventData3 bits [3:0]
+                    int channel = selData.eventData3 & 0x0F;
+                    char channelLetter[4] = {'A'};
+                    channelLetter[0] += channel;
+
+                    // Save the messageArgs
+                    messageArgs.push_back(std::to_string(socket + 1));
+                    messageArgs.push_back(std::string(channelLetter));
+                    messageArgs.push_back(std::to_string(dimm));
+                    messageArgs.push_back(std::to_string(rank));
+
+                    break;
+                }
+                default:
+                    messageID += ".Unknown";
+                    messageArgs.push_back(ipmiRaw);
+                    break;
+            }
+            break;
+        default:
+            messageID += ".Unknown";
+            messageArgs.push_back(ipmiRaw);
+            break;
+    }
+
+    // Log the Redfish message to the journal with the appropriate metadata
+    std::string journalMsg = "BIOS SMI IPMI event: " + ipmiRaw;
+    std::string messageArgsString = boost::algorithm::join(messageArgs, ",");
+    phosphor::logging::log<phosphor::logging::level::INFO>(
+        journalMsg.c_str(),
+        phosphor::logging::entry("REDFISH_MESSAGE_ID=%s", messageID.c_str()),
+        phosphor::logging::entry("REDFISH_MESSAGE_ARGS=%s",
+                                 messageArgsString.c_str()));
+
+    return true;
+}
+
+static bool startRedfishHook(const SELData& selData, const std::string& ipmiRaw)
+{
+    switch (selData.generatorID)
+    {
+        case 0x01: // Check if this message is from the BIOS Generator ID
+            // Let the BIOS hook handle this request
+            return biosMessageHook(selData, ipmiRaw);
+            break;
+
+        case 0x33: // Check if this message is from the BIOS SMI Generator ID
+            // Let the BIOS SMI hook handle this request
+            return biosSMIMessageHook(selData, ipmiRaw);
+            break;
+    }
+
+    // No hooks handled the request, so let it go to the SEL
+    return false;
+}
+} // namespace redfish_hooks
+
+bool checkRedfishHooks(AddSELRequest* selRequest)
+{
+    // First check that this is a system event record type since that
+    // determines the definition of the rest of the data
+    if (selRequest->recordType != ipmi::sel::systemEvent)
+    {
+        // OEM record type, so let it go to the SEL
+        return false;
+    }
+
+    // Save the raw IPMI string of the request
+    std::string ipmiRaw;
+    const boost::beast::span<uint8_t> selBytes(
+        reinterpret_cast<uint8_t*>(selRequest), sizeof(AddSELRequest));
+    redfish_hooks::toHexStr(selBytes, ipmiRaw);
+
+    // Extract the SEL data for the hook
+    redfish_hooks::SELData selData = {
+        .generatorID = selRequest->record.system.generatorID,
+        .sensorNum = selRequest->record.system.sensorNum,
+        .eventType = selRequest->record.system.eventType,
+        .offset = selRequest->record.system.eventData[0] & 0x0F,
+        .eventData2 = selRequest->record.system.eventData[1],
+        .eventData3 = selRequest->record.system.eventData[2]};
+
+    return redfish_hooks::startRedfishHook(selData, ipmiRaw);
+}
+
+bool checkRedfishHooks(uint8_t generatorID, uint8_t evmRev, uint8_t sensorType,
+                       uint8_t sensorNum, uint8_t eventType, uint8_t eventData1,
+                       uint8_t eventData2, uint8_t eventData3)
+{
+    // Save the raw IPMI string of the selData
+    std::string ipmiRaw;
+    std::array selBytes = {generatorID, evmRev,     sensorType, sensorNum,
+                           eventType,   eventData1, eventData2, eventData3};
+    redfish_hooks::toHexStr(boost::beast::span<uint8_t>(selBytes), ipmiRaw);
+
+    // Extract the SEL data for the hook
+    redfish_hooks::SELData selData = {.generatorID = generatorID,
+                                      .sensorNum = sensorNum,
+                                      .eventType = eventType,
+                                      .offset = eventData1 & 0x0F,
+                                      .eventData2 = eventData2,
+                                      .eventData3 = eventData3};
+
+    return redfish_hooks::startRedfishHook(selData, ipmiRaw);
+}
+
+} // namespace intel_oem::ipmi::sel
diff --git a/src/sensorcommands.cpp b/src/sensorcommands.cpp
index bf1f430..ba64fe4 100644
--- a/src/sensorcommands.cpp
+++ b/src/sensorcommands.cpp
@@ -20,6 +20,7 @@
 #include <cmath>
 #include <commandutils.hpp>
 #include <iostream>
+#include <ipmi_to_redfish_hooks.hpp>
 #include <ipmid/api.hpp>
 #include <ipmid/utils.hpp>
 #include <phosphor-logging/log.hpp>
@@ -311,6 +312,16 @@
         return ipmi::responseReqDataLenInvalid();
     }
 
+    // Send this request to the Redfish hooks to see if it should be a
+    // Redfish message instead.  If so, no need to add it to the SEL, so
+    // just return success.
+    if (intel_oem::ipmi::sel::checkRedfishHooks(
+            generatorID, evmRev, sensorType, sensorNum, eventType, eventData1,
+            eventData2.value_or(0xFF), eventData3.value_or(0xFF)))
+    {
+        return ipmi::responseSuccess();
+    }
+
     bool assert = eventType & directionMask ? false : true;
     std::vector<uint8_t> eventData;
     eventData.push_back(eventData1);
diff --git a/src/storagecommands.cpp b/src/storagecommands.cpp
index 5efdf66..7aa8950 100644
--- a/src/storagecommands.cpp
+++ b/src/storagecommands.cpp
@@ -20,6 +20,7 @@
 #include <commandutils.hpp>
 #include <filesystem>
 #include <iostream>
+#include <ipmi_to_redfish_hooks.hpp>
 #include <ipmid/api.hpp>
 #include <phosphor-ipmi-host/selutility.hpp>
 #include <phosphor-logging/log.hpp>
@@ -922,6 +923,16 @@
     // added
     cancelSELReservation();
 
+    // Send this request to the Redfish hooks to see if it should be a Redfish
+    // message instead.  If so, no need to add it to the SEL, so just return
+    // success.
+    if (intel_oem::ipmi::sel::checkRedfishHooks(req))
+    {
+        *static_cast<uint16_t*>(response) = 0xFFFF;
+        *data_len = sizeof(recordID);
+        return IPMI_CC_OK;
+    }
+
     if (req->recordType == intel_oem::ipmi::sel::systemEvent)
     {
         std::string sensorPath =