Parse FB Unified SEL

Parsing a special Facebook Unified SEL

Tested: Verified this sending command through ipmitool.

Change-Id: Ia954290c6d6713a0b1f47584d4a8795e02efb852
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
diff --git a/include/storagecommands.hpp b/include/storagecommands.hpp
index e51e9ca..c63bd22 100644
--- a/include/storagecommands.hpp
+++ b/include/storagecommands.hpp
@@ -109,6 +109,7 @@
 
 static constexpr auto stdErr = "Standard";
 static constexpr auto oemTSErr = "OEM timestamped";
+static constexpr auto fbUniSELErr = "Facebook Unified SEL";
 static constexpr auto oemNTSErr = "OEM non-timestamped";
 static constexpr auto unknownErr = "Unknown";
 
@@ -116,6 +117,7 @@
 static constexpr uint8_t oemTSErrTypeMin = 0xC0;
 static constexpr uint8_t oemTSErrTypeMax = 0xDF;
 static constexpr uint8_t oemNTSErrTypeMin = 0xE0;
+static constexpr uint8_t fbUniErrType = 0xFB;
 static constexpr uint8_t oemNTSErrTypeMax = 0xFF;
 
 static constexpr uint8_t unifiedPcieErr = 0;
diff --git a/src/selcommands.cpp b/src/selcommands.cpp
index f91ee07..ae98ba8 100644
--- a/src/selcommands.cpp
+++ b/src/selcommands.cpp
@@ -303,6 +303,61 @@
     return;
 }
 
+static void parseOemUnifiedSel(NtsOemSELEntry *data, std::string &errStr)
+{
+    uint8_t *ptr = data->oemData;
+    int genInfo = ptr[0];
+    int errType = genInfo & 0x0f;
+    std::vector<std::string> dimmEvent = {
+        "Memory training failure", "Memory correctable error",
+        "Memory uncorrectable error", "Reserved"};
+
+    std::stringstream tmpStream;
+    tmpStream << std::hex << std::uppercase << std::setfill('0');
+
+    switch (errType)
+    {
+        case unifiedPcieErr:
+            if (((genInfo & 0x10) >> 4) == 0) // x86
+            {
+                tmpStream << "GeneralInfo: x86/PCIeErr(0x" << std::setw(2)
+                          << genInfo << "),";
+            }
+
+            tmpStream << " Bus " << std::setw(2) << (int)(ptr[8]) << "/Dev "
+                      << std::setw(2) << (int)(ptr[7] >> 3) << "/Fun "
+                      << std::setw(2) << (int)(ptr[7] & 0x7)
+                      << ", TotalErrID1Cnt: 0x" << std::setw(4)
+                      << (int)((ptr[10] << 8) | ptr[9]) << ", ErrID2: 0x"
+                      << std::setw(2) << (int)(ptr[11]) << ", ErrID1: 0x"
+                      << std::setw(2) << (int)(ptr[12]);
+
+            break;
+        case unifiedMemErr:
+            tmpStream << "GeneralInfo: MemErr(0x" << std::setw(2) << genInfo
+                      << "), DIMM Slot Location: Sled " << std::setw(2)
+                      << (int)((ptr[5] >> 4) & 0x03) << "/Socket "
+                      << std::setw(2) << (int)(ptr[5] & 0x0f) << ", Channel "
+                      << std::setw(2) << (int)(ptr[6] & 0x0f) << ", Slot "
+                      << std::setw(2) << (int)(ptr[7] & 0x0f)
+                      << ", DIMM Failure Event: " << dimmEvent[(ptr[9] & 0x03)]
+                      << ", Major Code: 0x" << std::setw(2) << (int)(ptr[10])
+                      << ", Minor Code: 0x" << std::setw(2) << (int)(ptr[11]);
+
+            break;
+        default:
+            std::vector<uint8_t> oemData(ptr, ptr + 13);
+            std::string oemDataStr;
+            toHexStr(oemData, oemDataStr);
+            tmpStream << "Undefined Error Type(0x" << std::setw(2) << errType
+                      << "), Raw: " << oemDataStr;
+    }
+
+    errStr = tmpStream.str();
+
+    return;
+}
+
 static void parseSelData(std::vector<uint8_t> &reqData, std::string &msgLog)
 {
 
@@ -383,6 +438,13 @@
                   "), Time: " + timeStr + ", MFG ID: " + mfrIdStr +
                   ", OEM Data: (" + oemDataStr + ") " + errLog;
     }
+    else if (recType == fbUniErrType)
+    {
+        NtsOemSELEntry *data = reinterpret_cast<NtsOemSELEntry *>(&reqData[0]);
+        errType = fbUniSELErr;
+        parseOemUnifiedSel(data, errLog);
+        msgLog += errType + " (0x" + recTypeStream.str() + "), " + errLog;
+    }
     else if ((recType >= oemNTSErrTypeMin) && (recType <= oemNTSErrTypeMax))
     {
         /* Non timestamped OEM SEL records */