Implement Get POH Counter command

It returns a counter value proportional to the system operating
power-on hours.

Partially Resolves openbmc/openbmc#2979

Change-Id: Ib0cd43fe5cbc055ae84991577d766bedae58d775
Signed-off-by: Nagaraju Goruganti <ngorugan@in.ibm.com>
diff --git a/chassishandler.cpp b/chassishandler.cpp
index 0ee593c..2e892b9 100644
--- a/chassishandler.cpp
+++ b/chassishandler.cpp
@@ -33,6 +33,7 @@
 #include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
 #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
 #include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
+#include <xyz/openbmc_project/State/PowerOnHours/server.hpp>
 
 #include "config.h"
 
@@ -79,6 +80,11 @@
 constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
 constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
 
+static constexpr auto chassisStateRoot = "/xyz/openbmc_project/state";
+static constexpr auto chassisPOHStateIntf =
+                                    "xyz.openbmc_project.State.PowerOnHours";
+static constexpr auto pOHCounterProperty = "POHCounter";
+static constexpr auto match = "chassis0";
 
 typedef struct
 {
@@ -98,6 +104,15 @@
     uint8_t front_panel_button_cap_status;
 }__attribute__((packed)) ipmi_get_chassis_status_t;
 
+/**
+ * @struct Get POH counter command response data
+ */
+struct GetPOHCountResponse
+{
+    uint8_t minPerCount; ///< Minutes per count
+    uint8_t counterReading[4]; ///< Counter reading
+}__attribute__((packed));
+
 // Phosphor Host State manager
 namespace State = sdbusplus::xyz::openbmc_project::State::server;
 
@@ -127,6 +142,13 @@
 } // namespace internal
 } // namespace chassis
 
+namespace poh
+{
+
+constexpr auto minutesPerCount = 60;
+
+} // namespace poh
+
 //TODO : Can remove the below function as we have
 //       new functions which uses sdbusplus.
 //
@@ -581,6 +603,23 @@
     return 0;
 }
 
+uint32_t getPOHCounter()
+{
+    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+
+    auto chassisStateObj = ipmi::getDbusObject(bus, chassisPOHStateIntf,
+                                               chassisStateRoot, match);
+
+    auto service = ipmi::getService(bus, chassisPOHStateIntf,
+                                    chassisStateObj.first);
+
+    auto propValue = ipmi::getDbusProperty(bus, service, chassisStateObj.first,
+                                           chassisPOHStateIntf,
+                                           pOHCounterProperty);
+
+    return propValue.get<uint32_t>();
+}
+
 ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                                  ipmi_request_t request,
                                  ipmi_response_t response,
@@ -1505,6 +1544,35 @@
     return rc;
 }
 
+ipmi_ret_t ipmiGetPOHCounter(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+                             ipmi_request_t request, ipmi_response_t response,
+                             ipmi_data_len_t data_len, ipmi_context_t context)
+{
+    // sd_bus error
+    ipmi_ret_t rc = IPMI_CC_OK;
+
+    auto resptr = reinterpret_cast<GetPOHCountResponse*>(response);
+
+    try
+    {
+        auto pohCounter = getPOHCounter();
+        resptr->counterReading[0] = pohCounter;
+        resptr->counterReading[1] = pohCounter >> 8;
+        resptr->counterReading[2] = pohCounter >> 16;
+        resptr->counterReading[3] = pohCounter >> 24;
+    }
+    catch (std::exception& e)
+    {
+        log<level::ERR>(e.what());
+        return IPMI_CC_UNSPECIFIED_ERROR;
+    }
+
+    resptr->minPerCount = poh::minutesPerCount;
+    *data_len = sizeof(GetPOHCountResponse);
+
+    return rc;
+}
+
 void register_netfn_chassis_functions()
 {
     // <Wildcard Command>
@@ -1534,4 +1602,7 @@
     // <Set System Boot Options>
     ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL,
                            ipmi_chassis_set_sys_boot_options, PRIVILEGE_OPERATOR);
+    // <Get POH Counter>
+    ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_POH_COUNTER, NULL,
+                           ipmiGetPOHCounter, PRIVILEGE_USER);
 }
diff --git a/chassishandler.h b/chassishandler.h
index c0e82a1..8643ae4 100644
--- a/chassishandler.h
+++ b/chassishandler.h
@@ -16,6 +16,7 @@
     // Get capability bits
     IPMI_CMD_SET_SYS_BOOT_OPTIONS = 0x08,
     IPMI_CMD_GET_SYS_BOOT_OPTIONS = 0x09,
+    IPMI_CMD_GET_POH_COUNTER      = 0x0F,
 };
 
 // Command specific completion codes
diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf
index 0111b9b..a95e99e 100644
--- a/host-ipmid-whitelist.conf
+++ b/host-ipmid-whitelist.conf
@@ -4,6 +4,7 @@
 0x00:0x02    //<Chassis>:<Chassis Control>
 0x00:0x08    //<Chassis>:<Set System Boot Options>
 0x00:0x09    //<Chassis>:<Get System Boot Options>
+0x00:0x0F    //<Chassis>:<Get POH Counter Command>
 0x04:0x2D    //<Sensor/Event>:<Get Sensor Reading>
 0x04:0x2F    //<Sensor/Event>:<Get Sensor Type>
 0x04:0x30    //<Sensor/Event>:<Set Sensor Reading and Event Status>