PEL: enable SBE FFDC support in pel log

 FFDC Package structure and definitions are based on the
 SBE chip-op spec.
 FFDC packet Starts with a header word (Word 0) that has
 an unique magic identifier code of 0xFFDC followed by the
 length of the FFDC package including the header itself.
 Word 1 contains a sequence id , command-class and command
 fields. The sequence id field is ignored on the BMC side.
 Word 2 contains a 32 bit Return Code which acts like the
 key to the contents of subsequent FFDC Data Words (0-N).

 A FFDC package can typically contain debug data from either:
   1. A failed hardware procedure (e.g. local variable values
      at point of failure) or
   2. SBE firmware
        (e.g. traces, attributes and other information).
    ___________________________________________________________
   |        |  Byte 0   |  Byte 1  |  Byte 2    |    Byte 3   |
   |----------------------------------------------------------|
   | Word 0 | Magic Bytes : 0xFFDC | Length in words (N+4)    |
   | Word 1 | [Sequence ID]        | Command-Class | Command  |
   | Word 2 |           Return Code 0..31                     |
   | Word 3 |           FFDC Data – Word 0                    |
   |  ...                                                     |
   | Word N+3 |  FFDC Data – Word N                           |
    -----------------------------------------------------------

This commit enables SBE FFDC packet parsing for packet type
mentioned in option 1 (A failed hardware procedure). Other case
SBE provided tool based parsing is required. Not enabled in
this patch.

SBE FFDC file data added as part of PEL user data section for
future SBE tool based parsing.

Tested: Manually created SBE error with No core available for
        Boot use case.

"User Data 2": {   --> Raw SBE FFDC data
    "Section Version":          "1",
    "Sub-section type":         "203",
    "Created by":               "0x3500",
    "Data": [
        "FF DC 00 12 00 00 A1 01  00 8E CE 72 00 00 FF FE
        "00 00 00 04 00 00 00 00  00 00 00 04 00 00 00 00
        "00 00 00 00 00 00 00 01  00 00 00 00 00 00 00 02
        "00 00 00 04 00 00 00 00  00 00 00 00 00 00 00 04
        "00 00 00 00 00 00 00 00
    ]
},
"User Data 3": {   -->  callout details
    "Section Version": "1",
    "Sub-section type": "1",
    "Created by": "0x2000",
    "Data": [
        {
            "Deconfigured": false,
            "Guarded": false,
            "LocationCode": "Ufcs-P0-C24",
            "MRUs": [
                {
                    "ID": 65536,
                    "Priority": "H"
                }
            ],
            "Priority": "H"
        }
    ]
},
"User Data 4": {   -->  User Debug data.
    "Section Version": "1",
    "Sub-section type": "3",
    "Created by": "0x2000",
    "Data": [
        "HWP_RC = RC_SBE_SELECT_EX_INSUFFICIENT_ACTIVE_CORES_ERROR",
        "HWP_RC_DESC = The requested active cores were
         not able to be configured.",
        "HWP_FFDC_CHIP = 6b3a7570 306e3a30 3a30733a 00323070
         00000000 00000000 00000000 00000000 00000000 00000000
         00000000 00000000 00000000 00000000 00000000 00000000",
        "HWP_FFDC_CORE_CONFIG = 00000000",
        "HWP_FFDC_ATTR_ACTIVE_CORES_NUM = 02",
        "HWP_FFDC_ACTIVE_CORES_NUM = 00000000",
        "HWP_FFDC_ACTIVE_CORES_VEC = 00000000",
        "HWP_CDG_TGT_01_LOC_CODE = Ufcs-P0-C24",
        "HWP_CDG_TGT_01_PHYS_PATH = physical:sys-0/node-0/proc-2",
        "HWP_CDG_TGT_01_CO_REQ = true",
        "HWP_CDG_TGT_01_CO_PRIORITY = HIGH",
        "HWP_CDG_TGT_01_DECONF_REQ = false",
        "HWP_CDG_TGT_01_GUARD_REQ = false",
        "HWP_CDG_TGT_01_GUARD_TYPE = GARD_Fatal"
    ]
}

Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
Change-Id: Id94d8e10b3e0f82cb61d40bab9ef8b3f4a3beff9
diff --git a/extensions/openpower-pels/sbe_ffdc_handler.cpp b/extensions/openpower-pels/sbe_ffdc_handler.cpp
index a36b6cf..9e6a088 100644
--- a/extensions/openpower-pels/sbe_ffdc_handler.cpp
+++ b/extensions/openpower-pels/sbe_ffdc_handler.cpp
@@ -20,8 +20,10 @@
 #include "pel.hpp"
 #include "temporary_file.hpp"
 
+#include <ekb/hwpf/fapi2/include/return_code_defs.H>
 #include <fmt/format.h>
 
+#include <new>
 #include <phosphor-logging/log.hpp>
 
 namespace openpower
@@ -68,11 +70,87 @@
         if ((file.format == UserDataFormat::custom) &&
             (file.subType == sbeFFDCSubType))
         {
-            // TODO Process SBE file.
+            // Process SBE file.
+            parse(file.fd);
         }
     }
 }
 
+void SbeFFDC::parse(int fd)
+{
+    log<level::INFO>(
+        fmt::format("SBE FFDC file fd:({}), parsing started", fd).c_str());
+
+    uint32_t ffdcBufOffset = 0;
+    uint32_t pktCount = 0;
+    sbeFfdcPacketType ffdcPkt;
+
+    // get SBE FFDC data.
+    auto ffdcData = util::readFD(fd);
+    if (ffdcData.empty())
+    {
+        log<level::ERR>(
+            fmt::format("Empty SBE FFDC file fd:({}), skipping", fd).c_str());
+        return;
+    }
+
+    while ((ffdcBufOffset < ffdcData.size()) && (sbeMaxFfdcPackets != pktCount))
+    {
+        // Next un-extracted FFDC Packet
+        fapiFfdcBufType* ffdc =
+            reinterpret_cast<fapiFfdcBufType*>(ffdcData.data() + ffdcBufOffset);
+        auto magicBytes = ntohs(ffdc->magic_bytes);
+        auto lenWords = ntohs(ffdc->lengthinWords);
+        auto fapiRc = ntohl(ffdc->fapiRc);
+
+        auto msg = fmt::format("FFDC magic: {} length in words:{} Fapirc:{}",
+                               magicBytes, lenWords, fapiRc);
+        log<level::INFO>(msg.c_str());
+
+        if (magicBytes != ffdcMagicCode)
+        {
+            log<level::ERR>("Invalid FFDC magic code in Header: Skipping ");
+            return;
+        }
+        ffdcPkt.fapiRc = fapiRc;
+        // Not interested in the first 2 words (these are not ffdc)
+        auto pktLenWords = lenWords - (2 * ffdcPkgOneWord);
+        ffdcPkt.ffdcLengthInWords = pktLenWords;
+        if (pktLenWords)
+        {
+            // Memory freeing will be taking care by ffdcPkt structure
+            // destructor
+            ffdcPkt.ffdcData = new uint32_t[pktLenWords];
+            memcpy(ffdcPkt.ffdcData,
+                   ((reinterpret_cast<uint32_t*>(ffdc)) +
+                    (2 * ffdcPkgOneWord)), // skip first 2 words
+                   (pktLenWords * sizeof(uint32_t)));
+        }
+        else
+        {
+            log<level::ERR>("FFDC packet size is zero skipping");
+            return;
+        }
+
+        // SBE FFDC processing is not required for SBE Plat errors RCs.
+        // Plat errors processing is driven by SBE provided user data
+        // plugins, which need to link with PEL tool infrastructure.
+        if (ffdcPkt.fapiRc != fapi2::FAPI2_RC_PLAT_ERR_SEE_DATA)
+        {
+            process(ffdcPkt);
+        }
+        ffdcBufOffset += ffdc->lengthinWords;
+        ++pktCount;
+    }
+    if (pktCount == sbeMaxFfdcPackets)
+    {
+        log<level::ERR>(fmt::format("Received more than the limit of ({})"
+                                    " FFDC packets, processing only ({})",
+                                    sbeMaxFfdcPackets, pktCount)
+                            .c_str());
+    }
+}
+
 void SbeFFDC::process(const sbeFfdcPacketType& ffdcPkt)
 {
     using json = nlohmann::json;