Trigger periodic OCC POLL commands when the OCCs are running

The OCC control app will periodically trigger kernel poll commands
to the OCC when the OCCs are active.
Code change also adds an interface to allow any OCC command to be
sent to an OCC. The pass-through interface was also updated to
use the new command object.

Tested: I did several IPLs on multiple Rainier systems to verify
the changes. I forced OCC resets to ensure polling stopped when
OCCs were disabled and restarted after it came out of reset.

Change-Id: I56970e781a988bb94f17ac38173ace8a68bb5fad
Signed-off-by: Chris Cain <cjcain@us.ibm.com>
diff --git a/occ_status.cpp b/occ_status.cpp
index 502783d..1bf9330 100644
--- a/occ_status.cpp
+++ b/occ_status.cpp
@@ -3,17 +3,23 @@
 #include "occ_sensor.hpp"
 #include "utils.hpp"
 
+#include <fmt/core.h>
+
 #include <phosphor-logging/log.hpp>
 namespace open_power
 {
 namespace occ
 {
+using namespace phosphor::logging;
 
 // Handles updates to occActive property
 bool Status::occActive(bool value)
 {
     if (value != this->occActive())
     {
+        log<level::INFO>(fmt::format("Status::occActive OCC{} changed to {}",
+                                     instance, value)
+                             .c_str());
         if (value)
         {
             // Bind the device
@@ -22,6 +28,9 @@
             // Start watching for errors
             addErrorWatch();
 
+            // Reset last OCC state
+            lastState = 0;
+
             // Call into Manager to let know that we have bound
             if (this->callBack)
             {
@@ -93,13 +102,16 @@
 // Sends message to host control command handler to reset OCC
 void Status::resetOCC()
 {
+    log<level::INFO>(
+        fmt::format(">>Status::resetOCC() - requesting reset for OCC{}",
+                    instance)
+            .c_str());
 #ifdef PLDM
     if (resetCallBack)
     {
         this->resetCallBack(instance);
     }
 #else
-    using namespace phosphor::logging;
     constexpr auto CONTROL_HOST_PATH = "/org/open_power/control/host0";
     constexpr auto CONTROL_HOST_INTF = "org.open_power.Control.Host";
 
@@ -148,5 +160,44 @@
     return;
 }
 
+void Status::readOccState()
+{
+    unsigned int state;
+    const fs::path filename =
+        fs::path(DEV_PATH) /
+        fs::path(sysfsName + "." + std::to_string(instance + 1)) / "occ_state";
+
+    log<level::DEBUG>(
+        fmt::format("Status::readOccState: reading OCC{} state from {}",
+                    instance, filename.c_str())
+            .c_str());
+
+    std::ifstream file(filename, std::ios::in);
+    const int open_errno = errno;
+    if (file)
+    {
+        file >> state;
+        if (state != lastState)
+        {
+            // Trace OCC state changes
+            log<level::INFO>(
+                fmt::format("Status::readOccState: OCC{} state 0x{:02X}",
+                            instance, state)
+                    .c_str());
+            lastState = state;
+        }
+        file.close();
+    }
+    else
+    {
+        // If not able to read, OCC may be offline
+        log<level::DEBUG>(
+            fmt::format("Status::readOccState: open failed (errno={})",
+                        open_errno)
+                .c_str());
+        lastState = 0;
+    }
+}
+
 } // namespace occ
 } // namespace open_power