phal: Added proc-pre-poweroff support

Changes:
-Adding new service which will be called during
chassis poweroff.

Test:
-Did poweroff to check, if the service file
is getting picked up or not and new added
procedure is getting called.

Signed-off-by: Chirag Sharma <chirshar@in.ibm.com>
Signed-off-by: Ramesh Iyyar <rameshi1@in.ibm.com>
Change-Id: Ic533433c4771216e5681b61cccf154f7ed029457
diff --git a/procedures/phal/common_utils.cpp b/procedures/phal/common_utils.cpp
new file mode 100644
index 0000000..99daa7b
--- /dev/null
+++ b/procedures/phal/common_utils.cpp
@@ -0,0 +1,49 @@
+extern "C"
+{
+#include <libpdbg.h>
+}
+
+#include "phalerror/phal_error.hpp"
+#include "procedures/phal/common_utils.hpp"
+
+#include <libekb.H>
+
+#include <phosphor-logging/log.hpp>
+
+namespace openpower
+{
+namespace phal
+{
+
+using namespace phosphor::logging;
+
+void phal_init(enum ipl_mode mode)
+{
+    // TODO: Setting boot error callback should not be in common code
+    //       because, we wont get proper reason in PEL for failure.
+    //       So, need to make code like caller of this function pass error
+    //       handling callback.
+    // add callback methods for debug traces and for boot failures
+    openpower::pel::addBootErrorCallbacks();
+
+    if (!pdbg_targets_init(NULL))
+    {
+        log<level::ERR>("pdbg_targets_init failed");
+        throw std::runtime_error("pdbg target initialization failed");
+    }
+
+    if (libekb_init())
+    {
+        log<level::ERR>("libekb_init failed");
+        throw std::runtime_error("libekb initialization failed");
+    }
+
+    if (ipl_init(mode) != 0)
+    {
+        log<level::ERR>("ipl_init failed");
+        throw std::runtime_error("libipl initialization failed");
+    }
+}
+
+} // namespace phal
+} // namespace openpower
diff --git a/procedures/phal/common_utils.hpp b/procedures/phal/common_utils.hpp
new file mode 100644
index 0000000..f9703bc
--- /dev/null
+++ b/procedures/phal/common_utils.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <libipl.H>
+
+namespace openpower
+{
+namespace phal
+{
+
+/**
+ * @brief This function will initialize required phal
+ *        libraries.
+ * Throws an exception on error.
+ *
+ * @param[in] mode - IPL mode, default IPL_AUTOBOOT
+ *
+ */
+void phal_init(enum ipl_mode mode = IPL_AUTOBOOT);
+
+} // namespace phal
+} // namespace openpower
diff --git a/procedures/phal/proc_pre_poweroff.cpp b/procedures/phal/proc_pre_poweroff.cpp
new file mode 100644
index 0000000..3997b19
--- /dev/null
+++ b/procedures/phal/proc_pre_poweroff.cpp
@@ -0,0 +1,49 @@
+#include "phalerror/phal_error.hpp"
+#include "procedures/phal/common_utils.hpp"
+#include "registration.hpp"
+
+#include <libekb.H>
+
+#include <phosphor-logging/log.hpp>
+
+namespace openpower
+{
+namespace phal
+{
+
+using namespace phosphor::logging;
+
+void prePoweroff(void)
+{
+    try
+    {
+        phal_init();
+    }
+    catch (const std::exception& ex)
+    {
+        log<level::ERR>("Exception raised during init PHAL",
+                        entry("EXCEPTION=%s", ex.what()));
+        openpower::pel::detail::processBootErrorCallback(false);
+        // Dont throw exception on failure because, we need to proceed
+        // further eventhough there is failure for proc-pre-poweroff
+        return;
+    }
+
+    // To clear trace if success
+    openpower::pel::detail::processBootErrorCallback(true);
+
+    // callback method will be called upon failure which will create the PEL
+    int rc = ipl_pre_poweroff();
+    if (rc)
+    {
+        log<level::ERR>("pre_poweroff failed");
+        // Dont throw exception on failure because, we need to proceed
+        // further eventhough there is failure for proc-pre-poweroff
+        return;
+    }
+}
+
+REGISTER_PROCEDURE("prePoweroff", prePoweroff)
+
+} // namespace phal
+} // namespace openpower
diff --git a/procedures/phal/start_host.cpp b/procedures/phal/start_host.cpp
index b82a584..c1f39a6 100644
--- a/procedures/phal/start_host.cpp
+++ b/procedures/phal/start_host.cpp
@@ -6,9 +6,9 @@
 #include "attributes_info.H"
 
 #include "phalerror/phal_error.hpp"
+#include "procedures/phal/common_utils.hpp"
 
 #include <libekb.H>
-#include <libipl.H>
 
 #include <ext_interface.hpp>
 #include <phosphor-logging/log.hpp>
@@ -120,35 +120,18 @@
  */
 void startHost(enum ipl_type iplType = IPL_TYPE_NORMAL)
 {
-    // add callback methods for debug traces and for boot failures
-    openpower::pel::addBootErrorCallbacks();
-
-    if (!pdbg_targets_init(NULL))
+    try
     {
-        log<level::ERR>("pdbg_targets_init failed");
-        openpower::pel::detail::processBootErrorCallback(false);
-        throw std::runtime_error("pdbg target initialization failed");
+        phal_init();
+        ipl_set_type(iplType);
     }
-    // To clear trace if success
-    openpower::pel::detail::processBootErrorCallback(true);
-
-    if (libekb_init())
+    catch (std::exception& ex)
     {
-        log<level::ERR>("libekb_init failed");
+        log<level::ERR>("Exception raised during init PHAL",
+                        entry("EXCEPTION=%s", ex.what()));
         openpower::pel::detail::processBootErrorCallback(false);
-        throw std::runtime_error("libekb initialization failed");
+        throw std::runtime_error("PHAL initialization failed");
     }
-    // To clear trace if success
-    openpower::pel::detail::processBootErrorCallback(true);
-
-    if (ipl_init(IPL_AUTOBOOT) != 0)
-    {
-        log<level::ERR>("ipl_init failed");
-        openpower::pel::detail::processBootErrorCallback(false);
-        throw std::runtime_error("Boot initialization failed");
-    }
-
-    ipl_set_type(iplType);
 
     // To clear trace if success
     openpower::pel::detail::processBootErrorCallback(true);