PHAL: Additional callout support for sbe timeout error

Sbe Boot timeout or chip-op timeout case BMC should run
sbe_extract_rc procedure to identify the correct callout
and service action. Currently this procedure based callout
handling is not place. Adding callout recommended by RAS
team till the actual callout code in place.

Tested:

   "Callout Count":        "2",
        "Callouts": [{
            "FRU Type":         "Maintenance Procedure Required",
            "Priority":         "Mandatory, replace all with this type as a unit",
            "Procedure":        "BMC0002"
        }, {
            "FRU Type":         "Normal Hardware FRU",
            "Priority":         "Medium Priority",
            "Location Code":    "xxx",  --> processor callout
            "Part Number":      "xxx",
            "CCIN":             "xxx",
            "Serial Number":    "xxx"

Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
Change-Id: I40444eb5da1a5f329b09dea1bce15e1bab53e1d8
diff --git a/extensions/phal/create_pel.cpp b/extensions/phal/create_pel.cpp
index 13be9ba..8638d5c 100644
--- a/extensions/phal/create_pel.cpp
+++ b/extensions/phal/create_pel.cpp
@@ -1,10 +1,13 @@
 #include "create_pel.hpp"
 
+#include "attributes_info.H"
+
 #include "util.hpp"
 
 #include <fcntl.h>
 #include <fmt/format.h>
 #include <libekb.H>
+#include <libphal.H>
 #include <unistd.h>
 
 #include <phosphor-logging/elog.hpp>
@@ -32,6 +35,49 @@
 constexpr auto loggingInterface = "xyz.openbmc_project.Logging.Create";
 constexpr auto opLoggingInterface = "org.open_power.Logging.PEL";
 
+/**
+ * @brief get SBE special callout information
+ *
+ *        This function add the special sbe callout in the user provided
+ *        json callout list. includes BMC0002 procedure callout with
+ *        high priority and processor callout with medium priority.
+ *
+ * @param[in] procTarget - pdbg processor target
+ * @param[out] jsonCalloutDataList - reference to json callout list
+ */
+static void getSBECallout(struct pdbg_target* procTarget,
+                          json& jsonCalloutDataList)
+{
+    using namespace openpower::phal::pdbg;
+
+    json jsonProcedCallout;
+
+    // Add procedure callout
+    jsonProcedCallout["Procedure"] = "BMC0002";
+    jsonProcedCallout["Priority"] = "H";
+    jsonCalloutDataList.emplace_back(std::move(jsonProcedCallout));
+    try
+    {
+        ATTR_LOCATION_CODE_Type locationCode;
+        // Initialize with default data.
+        memset(&locationCode, '\0', sizeof(locationCode));
+        // Get location code information
+        openpower::phal::pdbg::getLocationCode(procTarget, locationCode);
+        json jsonProcCallout;
+        jsonProcCallout["LocationCode"] = locationCode;
+        jsonProcCallout["Deconfigured"] = false;
+        jsonProcCallout["Guarded"] = false;
+        jsonProcCallout["Priority"] = "M";
+        jsonCalloutDataList.emplace_back(std::move(jsonProcCallout));
+    }
+    catch (const std::exception& e)
+    {
+        log<level::ERR>(fmt::format("getLocationCode({}): Exception({})",
+                                    pdbg_target_path(procTarget), e.what())
+                            .c_str());
+    }
+}
+
 void createErrorPEL(const std::string& event, const json& calloutData,
                     const FFDCData& ffdcData)
 {
@@ -87,7 +133,9 @@
 }
 
 uint32_t createSbeErrorPEL(const std::string& event, const sbeError_t& sbeError,
-                           const FFDCData& ffdcData, const Severity severity)
+                           const FFDCData& ffdcData,
+                           struct pdbg_target* procTarget,
+                           const Severity severity)
 {
     uint32_t plid = 0;
     std::map<std::string, std::string> additionalData;
@@ -123,6 +171,38 @@
                             static_cast<uint8_t>(0xCB),
                             static_cast<uint8_t>(0x01), sbeError.getFd()));
     }
+
+    // Workaround : currently sbe_extract_rc hwp procedure based callout
+    // handling is not available. openbmc issue #2917
+    // As per discussion with RAS team adding additional callout for
+    // SBE timeout error case, till this hwp based error handling in place.
+    // Note: PEL needs ffdcFile file till pel creation. This is forced to
+    // define ffdcFile function level scope.
+    std::unique_ptr<FFDCFile> FFDCFilePtr;
+    try
+    {
+        if ((event == "org.open_power.Processor.Error.SbeBootTimeout") &&
+            (severity == Severity::Error))
+        {
+            json jsonCalloutDataList;
+            jsonCalloutDataList = json::array();
+            getSBECallout(procTarget, jsonCalloutDataList);
+            FFDCFilePtr = std::make_unique<FFDCFile>(jsonCalloutDataList);
+            pelFFDCInfo.push_back(std::make_tuple(
+                sdbusplus::xyz::openbmc_project::Logging::server::Create::
+                    FFDCFormat::JSON,
+                static_cast<uint8_t>(0xCA), static_cast<uint8_t>(0x01),
+                FFDCFilePtr->getFileFD()));
+        }
+    }
+    catch (const std::exception& e)
+    {
+        log<level::ERR>(
+            fmt::format("Skipping SBE special callout due to Exception({})",
+                        e.what())
+                .c_str());
+    }
+
     try
     {
         std::string service =
@@ -157,7 +237,6 @@
     {
         throw e;
     }
-
     return plid;
 }
 
diff --git a/extensions/phal/create_pel.hpp b/extensions/phal/create_pel.hpp
index 53b8751..674381b 100644
--- a/extensions/phal/create_pel.hpp
+++ b/extensions/phal/create_pel.hpp
@@ -8,6 +8,11 @@
 
 #include <string>
 #include <vector>
+
+extern "C"
+{
+#include <libpdbg.h>
+}
 namespace openpower
 {
 namespace pel
@@ -34,11 +39,13 @@
  * @param[in] event - the event type
  * @param[in] sbeError - SBE error object
  * @param[in] ffdcData - failure data to append to PEL
+ * @param[in] procTarget - pdbg processor target
  * @param[in] severity - severity of the log
  * @return Platform log id
  */
 uint32_t createSbeErrorPEL(const std::string& event, const sbeError_t& sbeError,
                            const FFDCData& ffdcData,
+                           struct pdbg_target* procTarget,
                            const Severity severity = Severity::Error);
 
 /**
diff --git a/extensions/phal/phal_error.cpp b/extensions/phal/phal_error.cpp
index 354210f..5bfd9f0 100644
--- a/extensions/phal/phal_error.cpp
+++ b/extensions/phal/phal_error.cpp
@@ -684,7 +684,8 @@
     uint32_t index = pdbg_target_index(procTarget);
     pelAdditionalData.emplace_back("SRC6", std::to_string(index << 16));
     // Create SBE Error with FFDC data.
-    auto logId = createSbeErrorPEL(event, sbeError, pelAdditionalData);
+    auto logId =
+        createSbeErrorPEL(event, sbeError, pelAdditionalData, procTarget);
 
     if (dumpIsRequired)
     {
diff --git a/meson.build b/meson.build
index 8af1f98..889109d 100644
--- a/meson.build
+++ b/meson.build
@@ -186,6 +186,7 @@
             dependency('fmt'),
             dependency('phosphor-dbus-interfaces'),
             cxx.find_library('pdbg'),
+            cxx.find_library('phal'),
        ],
        install: true
    )
diff --git a/procedures/phal/enter_mpreboot.cpp b/procedures/phal/enter_mpreboot.cpp
index f71144f..c901be3 100644
--- a/procedures/phal/enter_mpreboot.cpp
+++ b/procedures/phal/enter_mpreboot.cpp
@@ -101,7 +101,7 @@
         FFDCData pelAdditionalData;
         pelAdditionalData.emplace_back("SRC6",
                                        std::to_string((index << 16) | cmd));
-        auto logId = createSbeErrorPEL(event, sbeError, pelAdditionalData);
+        auto logId = createSbeErrorPEL(event, sbeError, pelAdditionalData, tgt);
 
         if (dumpIsRequired)
         {
diff --git a/procedures/phal/thread_stopall.cpp b/procedures/phal/thread_stopall.cpp
index 476b893..983a7ca 100644
--- a/procedures/phal/thread_stopall.cpp
+++ b/procedures/phal/thread_stopall.cpp
@@ -92,7 +92,8 @@
                     // Create informational error log.
                     createSbeErrorPEL(
                         "org.open_power.Processor.Error.SbeChipOpFailure",
-                        sbeError, pelAdditionalData, Severity::Informational);
+                        sbeError, pelAdditionalData, procTarget,
+                        Severity::Informational);
                 }
                 else
                 {