Handle response from host for soft power off request

Change-Id: Ia923eff57f855dc88cb04db13590ae1a58a502fd
Signed-off-by: Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com>
diff --git a/softoff/mainapp.cpp b/softoff/mainapp.cpp
index f5fbf18..9ed34dd 100644
--- a/softoff/mainapp.cpp
+++ b/softoff/mainapp.cpp
@@ -19,10 +19,10 @@
 #include "config.h"
 #include "timer.hpp"
 
-using namespace phosphor::logging;
-
 int main(int argc, char** argv)
 {
+    using namespace phosphor::logging;
+
     // systemd event handler
     sd_event* events = nullptr;
 
@@ -32,13 +32,14 @@
     // Add systemd object manager.
     sdbusplus::server::manager::manager(bus, SOFTOFF_OBJPATH);
 
-    // sd_event object
+    // sd_event object. StateManager wants that this applicatin return '0'
+    // always.
     auto r = sd_event_default(&events);
     if (r < 0)
     {
         log<level::ERR>("Failure to create sd_event handler",
                 entry("ERROR=%s", strerror(-r)));
-        return -1;
+        return 0;
     }
 
     // Attach the bus to sd_event to service user requests
@@ -47,12 +48,13 @@
     // Create the SoftPowerOff object.
     phosphor::ipmi::SoftPowerOff powerObj(bus, events, SOFTOFF_OBJPATH);
 
-    /** @brief Claim the bus */
+    // Claim the bus. Delaying it until sending SMS_ATN may result
+    // in a race condition between this available and IPMI trying to send
+    // message as a reponse to ack from host.
     bus.request_name(SOFTOFF_BUSNAME);
 
-    /** @brief Wait for client requests until this application has processed
-     *         at least one successful SoftPowerOff
-     */
+    // Wait for client requests until this application has processed
+    // at least one successful SoftPowerOff or we timed out
     while(!powerObj.isCompleted() && !powerObj.isTimerExpired())
     {
         // -1 denotes wait for ever
diff --git a/softoff/softoff.cpp b/softoff/softoff.cpp
index 49b6f26..e88096f 100644
--- a/softoff/softoff.cpp
+++ b/softoff/softoff.cpp
@@ -46,5 +46,42 @@
     return;
 }
 
+/** @brief Host Response handler */
+auto SoftPowerOff::responseReceived(HostResponse response) -> HostResponse
+{
+    using namespace std::chrono;
+    using namespace phosphor::logging;
+
+    if (response == HostResponse::SoftOffReceived)
+    {
+        // Need to stop the running timer and then start a new timer
+        auto time = duration_cast<microseconds>(
+                seconds(IPMI_HOST_SHUTDOWN_COMPLETE_TIMEOUT_SECS));
+        auto r = timer.startTimer(time);
+        if (r < 0)
+        {
+            log<level::ERR>("Failure to start HostQuiesce wait timer",
+                    entry("ERROR=%s", strerror(-r)));
+        }
+    }
+    else if (response == HostResponse::HostShutdown)
+    {
+        // Disable the timer since Host has quiesced and we are
+        // done with soft power off part
+        auto r = timer.setTimer(SD_EVENT_OFF);
+        if (r < 0)
+        {
+            log<level::ERR>("Failure to STOP the timer",
+                    entry("ERROR=%s", strerror(-r)));
+        }
+
+        // This marks the completion of soft power off sequence.
+        completed = true;
+    }
+
+    return sdbusplus::xyz::openbmc_project::Ipmi::Internal
+              ::server::SoftPowerOff::responseReceived(response);
+}
+
 } // namespace ipmi
 } // namespace phosphor
diff --git a/softoff/softoff.hpp b/softoff/softoff.hpp
index 06f3861..da88fc5 100644
--- a/softoff/softoff.hpp
+++ b/softoff/softoff.hpp
@@ -55,6 +55,14 @@
             return timer.isExpired();
         }
 
+        /** @brief overloaded property setter function
+         *
+         *  @param[in] value - One of SoftOffReceived / HostShutdown
+         *
+         *  @return Success or exception thrown
+         */
+        HostResponse responseReceived(HostResponse value) override;
+
     private:
         // Need this to send SMS_ATTN
         // TODO : Switch over to using mapper service in a different patch