PEL: Fill in host command response handler

If notifying the host of a new PEL was successful, then it
will modify the PEL's host transmission state to 'sent' and
add it to the list of sent PELs.

If there was a failure, then a timer will be started so a
retry can be done.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I77000c603a18726d4cdbb3920ca349e69198fb7f
diff --git a/extensions/openpower-pels/host_notifier.cpp b/extensions/openpower-pels/host_notifier.cpp
index 2956b66..b935f7e 100644
--- a/extensions/openpower-pels/host_notifier.cpp
+++ b/extensions/openpower-pels/host_notifier.cpp
@@ -27,7 +27,9 @@
 HostNotifier::HostNotifier(Repository& repo, DataInterfaceBase& dataIface,
                            std::unique_ptr<HostInterface> hostIface) :
     _repo(repo),
-    _dataIface(dataIface), _hostIface(std::move(hostIface))
+    _dataIface(dataIface), _hostIface(std::move(hostIface)),
+    _retryTimer(_hostIface->getEvent(),
+                std::bind(std::mem_fn(&HostNotifier::retryTimerExpired), this))
 {
     // Subscribe to be told about new PELs.
     _repo.subscribeToAdds(subscriptionName,
@@ -130,6 +132,41 @@
 
 void HostNotifier::commandResponse(ResponseStatus status)
 {
+    auto id = _inProgressPEL;
+    _inProgressPEL = 0;
+
+    if (status == ResponseStatus::success)
+    {
+        _retryCount = 0;
+
+        _sentPELs.push_back(id);
+
+        _repo.setPELHostTransState(id, TransmissionState::sent);
+
+        if (!_pelQueue.empty())
+        {
+            doNewLogNotify();
+        }
+    }
+    else
+    {
+        log<level::ERR>("PLDM command response failure",
+                        entry("PEL_ID=0x%X", id));
+        // Retry
+        _pelQueue.push_front(id);
+        _retryTimer.restartOnce(_hostIface->getReceiveRetryDelay());
+    }
+}
+
+void HostNotifier::retryTimerExpired()
+{
+    if (_dataIface.isHostUp())
+    {
+        log<level::INFO>("Attempting command retry",
+                         entry("PEL_ID=0x%X", _pelQueue.front()));
+        _retryCount++;
+        doNewLogNotify();
+    }
 }
 
 } // namespace openpower::pels
diff --git a/extensions/openpower-pels/host_notifier.hpp b/extensions/openpower-pels/host_notifier.hpp
index 19ed64d..8436e06 100644
--- a/extensions/openpower-pels/host_notifier.hpp
+++ b/extensions/openpower-pels/host_notifier.hpp
@@ -5,6 +5,8 @@
 #include "repository.hpp"
 
 #include <deque>
+#include <sdeventplus/clock.hpp>
+#include <sdeventplus/utility/timer.hpp>
 
 namespace openpower::pels
 {
@@ -102,11 +104,26 @@
      * @brief The callback function invoked after the asynchronous
      *        PLDM receive function is complete.
      *
+     * If the command was successful, the state of that PEL will
+     * be set to 'sent', and the next send will be triggered.
+     *
+     * If the command failed, a retry timer will be started so it
+     * can be sent again.
+     *
      * @param[in] status - The response status
      */
     void commandResponse(ResponseStatus status);
 
     /**
+     * @brief The function called when the command failure retry
+     *        time is up.
+     *
+     * It will issue a send of the previous PEL and increment the
+     * retry count.
+     */
+    void retryTimerExpired();
+
+    /**
      * @brief The PEL repository object
      */
     Repository& _repo;
@@ -125,6 +142,30 @@
      * @brief The list of PEL IDs that need to be sent.
      */
     std::deque<uint32_t> _pelQueue;
+
+    /**
+     * @brief The list of IDs that were sent, but not acked yet.
+     *
+     * These move back to _pelQueue on a power off.
+     */
+    std::vector<uint32_t> _sentPELs;
+
+    /**
+     * @brief The ID the PEL where the notification has
+     *        been kicked off but the asynchronous response
+     *        hasn't been received yet.
+     */
+    uint32_t _inProgressPEL = 0;
+
+    /**
+     * @brief The command retry count
+     */
+    size_t _retryCount = 0;
+
+    /**
+     * @brief The command retry timer.
+     */
+    sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> _retryTimer;
 };
 
 } // namespace openpower::pels