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_pass_through.cpp b/occ_pass_through.cpp
index cecad37..11ef469 100644
--- a/occ_pass_through.cpp
+++ b/occ_pass_through.cpp
@@ -6,6 +6,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <fmt/core.h>
 #include <unistd.h>
 
 #include <algorithm>
@@ -14,6 +15,7 @@
 #include <phosphor-logging/elog.hpp>
 #include <phosphor-logging/log.hpp>
 #include <string>
+
 namespace open_power
 {
 namespace occ
@@ -22,115 +24,76 @@
 PassThrough::PassThrough(sdbusplus::bus::bus& bus, const char* path) :
     Iface(bus, path), path(path),
     devicePath(OCC_DEV_PATH + std::to_string((this->path.back() - '0') + 1)),
+    occInstance(this->path.back() - '0'),
     activeStatusSignal(
         bus, sdbusRule::propertiesChanged(path, "org.open_power.OCC.Status"),
         std::bind(std::mem_fn(&PassThrough::activeStatusEvent), this,
-                  std::placeholders::_1))
+                  std::placeholders::_1)),
+    occCmd(occInstance, bus, path)
 {
     // Nothing to do.
 }
 
-void PassThrough::openDevice()
-{
-    using namespace phosphor::logging;
-    using namespace sdbusplus::org::open_power::OCC::Device::Error;
-
-    if (!occActive)
-    {
-        log<level::INFO>("OCC is inactive; cannot perform pass-through");
-        return;
-    }
-
-    fd = open(devicePath.c_str(), O_RDWR | O_NONBLOCK);
-    if (fd < 0)
-    {
-        // This would log and terminate since its not handled.
-        elog<OpenFailure>(
-            phosphor::logging::org::open_power::OCC::Device::OpenFailure::
-                CALLOUT_ERRNO(errno),
-            phosphor::logging::org::open_power::OCC::Device::OpenFailure::
-                CALLOUT_DEVICE_PATH(devicePath.c_str()));
-    }
-    return;
-}
-
-void PassThrough::closeDevice()
-{
-    if (fd >= 0)
-    {
-        close(fd);
-        fd = -1;
-    }
-}
-
 std::vector<int32_t> PassThrough::send(std::vector<int32_t> command)
 {
-    using namespace phosphor::logging;
-    using namespace sdbusplus::org::open_power::OCC::Device::Error;
-
     std::vector<int32_t> response{};
 
-    openDevice();
-
-    if (fd < 0)
-    {
-        // OCC is inactive; empty response
-        return response;
-    }
-
     // OCC only understands [bytes] so need array of bytes. Doing this
     // because rest-server currently treats all int* as 32 bit integer.
-    std::vector<uint8_t> cmdInBytes;
+    std::vector<uint8_t> cmdInBytes, rsp;
     cmdInBytes.resize(command.size());
 
     // Populate uint8_t version of vector.
     std::transform(command.begin(), command.end(), cmdInBytes.begin(),
                    [](decltype(cmdInBytes)::value_type x) { return x; });
 
-    ssize_t size = cmdInBytes.size() * sizeof(decltype(cmdInBytes)::value_type);
-    auto rc = write(fd, cmdInBytes.data(), size);
-    if (rc < 0 || (rc != size))
-    {
-        // This would log and terminate since its not handled.
-        elog<WriteFailure>(
-            phosphor::logging::org::open_power::OCC::Device::WriteFailure::
-                CALLOUT_ERRNO(errno),
-            phosphor::logging::org::open_power::OCC::Device::WriteFailure::
-                CALLOUT_DEVICE_PATH(devicePath.c_str()));
-    }
+    rsp = send(cmdInBytes);
 
-    // Now read the response. This would be the content of occ-sram
-    while (1)
+    response.resize(rsp.size());
+    std::transform(rsp.begin(), rsp.end(), response.begin(),
+                   [](decltype(response)::value_type x) { return x; });
+
+    return response;
+}
+
+std::vector<uint8_t> PassThrough::send(std::vector<uint8_t> command)
+{
+    using namespace phosphor::logging;
+    using namespace sdbusplus::org::open_power::OCC::Device::Error;
+
+    std::vector<uint8_t> response{};
+
+    log<level::DEBUG>(
+        fmt::format("PassThrough::send() Sending 0x{:02X} command to OCC{}",
+                    command.front(), occInstance)
+            .c_str());
+    CmdStatus status = occCmd.send(command, response);
+    if (status == CmdStatus::SUCCESS)
     {
-        uint8_t data{};
-        auto len = read(fd, &data, sizeof(data));
-        if (len > 0)
+        if (response.size() >= 5)
         {
-            response.emplace_back(data);
-        }
-        else if (len < 0 && errno == EAGAIN)
-        {
-            // We may have data coming still.
-            // This driver does not need a sleep for a retry.
-            continue;
-        }
-        else if (len == 0)
-        {
-            // We have read all that we can.
-            break;
+            log<level::DEBUG>(fmt::format("PassThrough::send() "
+                                          "response had {} bytes",
+                                          response.size())
+                                  .c_str());
         }
         else
         {
-            // This would log and terminate since its not handled.
-            elog<ReadFailure>(
-                phosphor::logging::org::open_power::OCC::Device::ReadFailure::
-                    CALLOUT_ERRNO(errno),
-                phosphor::logging::org::open_power::OCC::Device::ReadFailure::
-                    CALLOUT_DEVICE_PATH(devicePath.c_str()));
+            log<level::ERR>("PassThrough::send() Invalid OCC response");
+            dump_hex(response);
         }
     }
-
-    closeDevice();
+    else
+    {
+        if (status == CmdStatus::OPEN_FAILURE)
+        {
+            log<level::WARNING>("PassThrough::send() - OCC not active yet");
+        }
+        else
+        {
+            log<level::ERR>("PassThrough::send() - OCC command failed!");
+        }
+    }
 
     return response;
 }
@@ -153,7 +116,6 @@
         else
         {
             occActive = false;
-            this->closeDevice();
         }
     }
     return;