Get Device ID: Add handling of availability bit

Make "Device available" bit in Firmware Version 1 field
reflect the ready state of BMC as indicated in DBus by
CurrentBMCState property of xyz.openbmc_project.State.BMC
interface.

Change-Id: Ic108507882c68d6cc70b40849668732f7b759ef6
Signed-off-by: Alexander Amelkin <a.amelkin@yadro.com>
Signed-off-by: Alexander Filippov <a.filippov@yadro.com>
diff --git a/apphandler.cpp b/apphandler.cpp
index d59c6ac..3abac14 100644
--- a/apphandler.cpp
+++ b/apphandler.cpp
@@ -39,9 +39,12 @@
 #include <xyz/openbmc_project/Common/error.hpp>
 #include <xyz/openbmc_project/Software/Activation/server.hpp>
 #include <xyz/openbmc_project/Software/Version/server.hpp>
+#include <xyz/openbmc_project/State/BMC/server.hpp>
 
 extern sd_bus* bus;
 
+constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC";
+constexpr auto bmc_state_property = "CurrentBMCState";
 constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc";
 constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID";
 constexpr auto bmc_guid_property = "UUID";
@@ -61,6 +64,7 @@
 using Version = sdbusplus::xyz::openbmc_project::Software::server::Version;
 using Activation =
     sdbusplus::xyz::openbmc_project::Software::server::Activation;
+using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC;
 namespace fs = std::filesystem;
 
 // Offset in get device id command.
@@ -151,6 +155,22 @@
     return revision;
 }
 
+bool getCurrentBmcState()
+{
+    sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
+
+    // Get the Inventory object implementing the BMC interface
+    ipmi::DbusObjectInfo bmcObject =
+        ipmi::getDbusObject(bus, bmc_state_interface);
+    auto variant =
+        ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
+                              bmc_state_interface, bmc_state_property);
+
+    return variant.is<std::string>() &&
+           BMC::convertBMCStateFromString(variant.get<std::string>()) ==
+               BMC::BMCState::Ready;
+}
+
 ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                                          ipmi_request_t request,
                                          ipmi_response_t response,
@@ -272,6 +292,8 @@
     static ipmi_device_id_t dev_id{};
     static bool dev_id_initialized = false;
     const char* filename = "/usr/share/ipmi-providers/dev_id.json";
+    constexpr auto ipmiDevIdStateShift = 7;
+    constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift);
 
     // Data length
     *data_len = sizeof(dev_id);
@@ -294,8 +316,9 @@
             // 0=normal operation
             // 1=device firmware, SDR update,
             // or self-initialization in progress.
-            // our SDR is normal working condition, so mask:
-            dev_id.fw[0] = 0x7F & rev.major;
+            // The availability may change in run time, so mask here
+            // and initialize later.
+            dev_id.fw[0] = rev.major & ipmiDevIdFw1Mask;
 
             rev.minor = (rev.minor > 99 ? 99 : rev.minor);
             dev_id.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
@@ -340,6 +363,13 @@
         }
     }
 
+    // Set availability to the actual current BMC state
+    dev_id.fw[0] &= ipmiDevIdFw1Mask;
+    if (!getCurrentBmcState())
+    {
+        dev_id.fw[0] |= (1 << ipmiDevIdStateShift);
+    }
+
     // Pack the actual response
     memcpy(response, &dev_id, *data_len);