PHAL: Log Informational error for PEL created during poweroff

1)Log informational PELS in case system state is transitioning to
power-off for IPL procedures/hardware access failures

2) Don't add callouts to PEL's created during transition to
power-off as the CEC will not be in expected state.

Tested: transition to poweroff
root@xxxbmc:/usr# peltool -lfh
{
    "0x50003BEB": {
        "SRC":                  "BD503001",
        "Message":              "Failure occurred during boot process",
        "PLID":                 "0x50003BEB",
        "CreatorID":            "BMC",
        "Subsystem":            "CEC Hardware",
        "Commit Time":          "05/23/2022 13:57:53",
        "Sev":                  "Informational Event",
        "CompID":               "0x3000"
    }
}

root@xxxbmc:~# peltool -i 0x50003be0
{
"Private Header": {
    "Section Version":          "1",
    "Sub-section type":         "0",
    "Created by":               "0x3000",
    "Created at":               "05/23/2022 13:48:12",
    "Committed at":             "05/23/2022 13:48:12",
    "Creator Subsystem":        "BMC",
    "CSSVER":                   "",
    "Platform Log Id":          "0x50003BE0",
    "Entry Id":                 "0x50003BE0",
    "BMC Event Log Id":         "510"
},
"User Header": {
    "Section Version":          "1",
    "Sub-section type":         "0",
    "Log Committed by":         "0x2000",
    "Subsystem":                "CEC Hardware",
    "Event Scope":              "Entire Platform",
    "Event Severity":           "Informational Event",
    "Event Type":               "Miscellaneous, Informational Only",
    "Action Flags": [
                                "Event not customer viewable",
                                "Report Externally"
    ],
    "Host Transmission":        "Not Sent",
    "HMC Transmission":         "Not Sent"
},

.
.
.
Tested: transition to running
root@ever8bmc:/tmp# peltool -i 0x50003CF9
{
"Private Header": {
    "Section Version":          "1",
    "Sub-section type":         "0",
    "Created by":               "0x3000",
},
"User Header": {
    "Section Version":          "1",
    "Sub-section type":         "0",
    "Log Committed by":         "0x2000",
    "Subsystem":                "CEC Hardware",
    "Event Scope":              "Entire Platform",
    "Event Severity":           "Unrecoverable Error",
},

"User Data 0": {
    "Created by": "0x2000",
    "BMCState": "Ready",
    "BootState": "Unspecified",
    "ChassisState": "On",
    "FW Version ID": "fw1020.00-57.7-2-gd86188a773",
    "HostState": "TransitioningToRunning",
    "Process Name": "/usr/bin/openpower-proc-control",
    "System IM": "50003000"
},

Signed-off-by: Marri Devender Rao <devenrao@in.ibm.com>
Change-Id: I078d5cba2e0fb705bf424d2f8f3010f2cd2063bb
diff --git a/extensions/phal/create_pel.cpp b/extensions/phal/create_pel.cpp
index 8638d5c..75ee064 100644
--- a/extensions/phal/create_pel.cpp
+++ b/extensions/phal/create_pel.cpp
@@ -79,7 +79,7 @@
 }
 
 void createErrorPEL(const std::string& event, const json& calloutData,
-                    const FFDCData& ffdcData)
+                    const FFDCData& ffdcData, const Severity severity)
 {
     std::map<std::string, std::string> additionalData;
     auto bus = sdbusplus::bus::new_default();
@@ -111,8 +111,7 @@
                                 loggingInterface, "CreateWithFFDCFiles");
         auto level =
             sdbusplus::xyz::openbmc_project::Logging::server::convertForMessage(
-                sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level::
-                    Error);
+                severity);
         method.append(event, level, additionalData, pelCalloutInfo);
         auto resp = bus.call(method);
     }
diff --git a/extensions/phal/create_pel.hpp b/extensions/phal/create_pel.hpp
index 674381b..ffd1315 100644
--- a/extensions/phal/create_pel.hpp
+++ b/extensions/phal/create_pel.hpp
@@ -29,9 +29,11 @@
  * @param[in] event - the event type
  * @param[in] calloutData - callout data to append to PEL
  * @param[in] ffdcData - failure data to append to PEL
+ * @param[in] severity - severity of the log default to Informational
  */
 void createErrorPEL(const std::string& event, const json& calloutData = {},
-                    const FFDCData& ffdcData = {});
+                    const FFDCData& ffdcData = {},
+                    const Severity severity = Severity::Informational);
 
 /**
  * @brief Create SBE boot error PEL and return id
diff --git a/extensions/phal/phal_error.cpp b/extensions/phal/phal_error.cpp
index a53ba77..8879964 100644
--- a/extensions/phal/phal_error.cpp
+++ b/extensions/phal/phal_error.cpp
@@ -7,6 +7,7 @@
 #include "dump_utils.hpp"
 #include "extensions/phal/common_utils.hpp"
 #include "phal_error.hpp"
+#include "util.hpp"
 
 #include <attributes_info.H>
 #include <fmt/format.h>
@@ -31,6 +32,7 @@
 {
 using namespace phosphor::logging;
 using namespace openpower::phal::exception;
+using Severity = sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level;
 
 /**
  * Used to pass buffer to pdbg callback api to get required target
@@ -321,7 +323,7 @@
         });
     openpower::pel::createErrorPEL(
         "org.open_power.PHAL.Error.NonFunctionalBootProc", jsonCalloutDataList,
-        pelAdditionalData);
+        pelAdditionalData, Severity::Error);
     // reset trace log and exit
     reset();
 }
@@ -387,6 +389,69 @@
     jsonCalloutDataList.emplace_back(jsonCalloutData);
 }
 
+/**
+ * @brief processPoweroffError
+ *
+ * Creates informational PEL for the PLAT/HWP error occured during poweroff
+ *
+ * Not adding callouts from FFDC as the hardware errors in the poweroff path
+ * should be non-visible.  so that we don't throw out extraneous callouts for
+ * power errors or because the CEC is just not in an expected state.
+ *
+ * @param[in] ffdc - FFDC data capturd by the HWP
+ * @param[in] ffdc_prefix - prefix string for logging the data.
+ */
+
+void processPoweroffError(FFDC* ffdc, const std::string& ffdc_prefix)
+{
+    try
+    {
+        log<level::INFO>(
+            fmt::format("processPoweroffError: Message[{}]", ffdc->message)
+                .c_str());
+
+        // To store phal trace and other additional data about ffdc.
+        FFDCData pelAdditionalData;
+
+        if (ffdc->ffdc_type == FFDC_TYPE_HWP)
+        {
+            std::string keyWithPrefix(ffdc_prefix + "RC");
+            // Adding hardware procedures return code details
+            pelAdditionalData.emplace_back(keyWithPrefix,
+                                           ffdc->hwp_errorinfo.rc);
+            keyWithPrefix = ffdc_prefix + "RC_DESC";
+            pelAdditionalData.emplace_back(keyWithPrefix,
+                                           ffdc->hwp_errorinfo.rc_desc);
+        }
+        else if ((ffdc->ffdc_type != FFDC_TYPE_NONE) &&
+                 (ffdc->ffdc_type != FFDC_TYPE_UNSUPPORTED))
+        {
+            log<level::ERR>(
+                fmt::format("Unsupported phal FFDC type to create PEL. "
+                            "MSG: {}",
+                            ffdc->message)
+                    .c_str());
+        }
+
+        // Adding collected phal logs into PEL additional data
+        for_each(traceLog.begin(), traceLog.end(),
+                 [&pelAdditionalData](
+                     std::pair<std::string, std::string>& ele) -> void {
+                     pelAdditionalData.emplace_back(ele.first, ele.second);
+                 });
+
+        openpower::pel::createErrorPEL("org.open_power.PHAL.Error.Boot", {},
+                                       pelAdditionalData,
+                                       Severity::Informational);
+    }
+    catch (const std::exception& ex)
+    {
+        reset();
+        throw ex;
+    }
+    reset();
+}
+
 void processBootErrorHelper(FFDC* ffdc, const std::string& ffdc_prefix)
 {
     log<level::INFO>("processBootErrorHelper ");
@@ -622,7 +687,8 @@
                 return true;
             });
         openpower::pel::createErrorPEL("org.open_power.PHAL.Error.Boot",
-                                       jsonCalloutDataList, pelAdditionalData);
+                                       jsonCalloutDataList, pelAdditionalData,
+                                       Severity::Error);
     }
     catch (const std::exception& ex)
     {
@@ -640,7 +706,14 @@
     FFDC* ffdc = reinterpret_cast<FFDC*>(errInfo.private_data);
     try
     {
-        processBootErrorHelper(ffdc, "PLAT_");
+        if (util::isHostPoweringOff())
+        {
+            processPoweroffError(ffdc, "PLAT_");
+        }
+        else
+        {
+            processBootErrorHelper(ffdc, "PLAT_");
+        }
     }
     catch (const std::exception& ex)
     {
@@ -661,12 +734,18 @@
         // return If no failure during hwp execution
         if (status)
             return;
-
         // Collecting ffdc details from phal
         FFDC ffdc;
         libekb_get_ffdc(ffdc);
 
-        processBootErrorHelper(&ffdc, "HWP_");
+        if (util::isHostPoweringOff())
+        {
+            processPoweroffError(&ffdc, "HWP_");
+        }
+        else
+        {
+            processBootErrorHelper(&ffdc, "HWP_");
+        }
     }
     catch (const std::exception& ex)
     {
@@ -716,7 +795,7 @@
         jsonCalloutDataList.emplace_back(jsonCalloutData);
         openpower::pel::createErrorPEL(
             "org.open_power.Processor.Error.SbeBootFailure",
-            jsonCalloutDataList);
+            jsonCalloutDataList, {}, Severity::Error);
         return;
     }
     // SBE error object.
diff --git a/meson.build b/meson.build
index a8586e1..76bc8fe 100644
--- a/meson.build
+++ b/meson.build
@@ -112,6 +112,7 @@
         'extensions/phal/phal_error.cpp',
         'extensions/phal/dump_utils.cpp',
         'temporary_file.cpp',
+        'util.cpp',
     ]
     extra_dependencies += [
         dependency('libdt-api'),
diff --git a/procedures/phal/reinit_devtree.cpp b/procedures/phal/reinit_devtree.cpp
index 60e6e49..c5ae058 100644
--- a/procedures/phal/reinit_devtree.cpp
+++ b/procedures/phal/reinit_devtree.cpp
@@ -107,6 +107,8 @@
 void reinitDevtree()
 {
     using json = nlohmann::json;
+    using Severity =
+        sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level;
 
     log<level::INFO>("reinitDevtree: started");
 
@@ -213,7 +215,8 @@
         jsonCalloutData["Priority"] = "M";
         jsonCalloutDataList.emplace_back(jsonCalloutData);
         openpower::pel::createErrorPEL(
-            "org.open_power.PHAL.Error.devtreeReinit", jsonCalloutDataList);
+            "org.open_power.PHAL.Error.devtreeReinit", jsonCalloutDataList, {},
+            Severity::Error);
     }
 
     // Step 4: Update devtree r/w file
@@ -252,7 +255,8 @@
         jsonCalloutData["Priority"] = "H";
         jsonCalloutDataList.emplace_back(jsonCalloutData);
         openpower::pel::createErrorPEL(
-            "org.open_power.PHAL.Error.devtreeReinit", jsonCalloutDataList);
+            "org.open_power.PHAL.Error.devtreeReinit", jsonCalloutDataList, {},
+            Severity::Error);
         throw;
     }
 }
diff --git a/procedures/phal/start_host.cpp b/procedures/phal/start_host.cpp
index 01cada9..fc30ecc 100644
--- a/procedures/phal/start_host.cpp
+++ b/procedures/phal/start_host.cpp
@@ -188,6 +188,8 @@
     try
     {
         using json = nlohmann::json;
+        using Severity =
+            sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level;
 
         json jsonCalloutDataList;
         jsonCalloutDataList = json::array();
@@ -197,7 +199,8 @@
         jsonCalloutDataList.emplace_back(jsonCalloutData);
 
         openpower::pel::createErrorPEL("org.open_power.PHAL.Error.Boot",
-                                       jsonCalloutDataList, additionalData);
+                                       jsonCalloutDataList, additionalData,
+                                       Severity::Error);
     }
     catch (const std::exception& e)
     {
diff --git a/procedures/phal/thread_stopall.cpp b/procedures/phal/thread_stopall.cpp
index 983a7ca..8c77690 100644
--- a/procedures/phal/thread_stopall.cpp
+++ b/procedures/phal/thread_stopall.cpp
@@ -137,7 +137,7 @@
         jsonCalloutDataList.emplace_back(jsonCalloutData);
         openpower::pel::createErrorPEL(
             "org.open_power.Processor.Error.SbeChipOpFailure",
-            jsonCalloutDataList, pelAdditionalData);
+            jsonCalloutDataList, pelAdditionalData, Severity::Informational);
         return;
     }
 }
diff --git a/util.cpp b/util.cpp
index 0c3e669..ed4eed9 100644
--- a/util.cpp
+++ b/util.cpp
@@ -43,5 +43,51 @@
     }
     return response.begin()->first;
 }
+
+bool isHostPoweringOff()
+{
+    try
+    {
+        constexpr auto object = "/xyz/openbmc_project/state/host0";
+        constexpr auto service = "xyz.openbmc_project.State.Host";
+        constexpr auto interface = "xyz.openbmc_project.State.Host";
+        constexpr auto property = "CurrentHostState";
+        auto bus = sdbusplus::bus::new_default();
+
+        std::variant<std::string> retval;
+        auto properties = bus.new_method_call(
+            service, object, "org.freedesktop.DBus.Properties", "Get");
+        properties.append(interface);
+        properties.append(property);
+        auto result = bus.call(properties);
+        result.read(retval);
+
+        const std::string* state = std::get_if<std::string>(&retval);
+        if (state == nullptr)
+        {
+            std::string err = fmt::format(
+                "CurrentHostState property is not set ({})", object);
+            log<level::ERR>(err.c_str());
+            return false;
+        }
+        if ((*state == "xyz.openbmc_project.State.Host.HostState."
+                       "TransitioningToOff") ||
+            (*state == "xyz.openbmc_project.State.Host.HostState."
+                       "Off") ||
+            (*state == "xyz.openbmc_project.State.Host.HostState."
+                       "Quiesced"))
+        {
+            return true;
+        }
+    }
+    catch (const std::exception& ex)
+    {
+        log<level::ERR>(
+            fmt::format("Failed to read CurrentHostState property ({})",
+                        ex.what())
+                .c_str());
+    }
+    return false;
+}
 } // namespace util
 } // namespace openpower
diff --git a/util.hpp b/util.hpp
index 19a162e..442bd22 100644
--- a/util.hpp
+++ b/util.hpp
@@ -19,5 +19,14 @@
  */
 std::string getService(sdbusplus::bus::bus& bus, const std::string& objectPath,
                        const std::string& interface);
+
+/**
+ * Returns true if host is in poweringoff state else false
+ *
+ * @return bool - true if host is powering off else false. if failed
+ *  to read property false will be returned.
+ */
+bool isHostPoweringOff();
+
 } // namespace util
 } // namespace openpower