IPMI OEM BIC - Get Bios Flash Size

Register an IPMI command handler with NetFn: 0x38 Cmd: 0x19
send this command to BIC through IPMB to get the Bios flash
size.

TESTED : Verified in YosemiteV2 platform and able to get
bios flash size.

Signed-off-by: Kumar Thangavel <thangavel.k@hcl.com>
Change-Id: I8a82f2495c1c7d4fefb49de471052cd9d740e75d
diff --git a/include/biccommands.hpp b/include/biccommands.hpp
index 8702380..1520702 100644
--- a/include/biccommands.hpp
+++ b/include/biccommands.hpp
@@ -5,8 +5,12 @@
     CMD_OEM_GET_BIC_GPIO_STATE = 0x3,
     CMD_OEM_SEND_POST_BUFFER_TO_BMC = 0x8,
     CMD_OEM_SET_HOST_POWER_STATE = 0x0C,
+    CMD_OEM_GET_FLASH_SIZE = 0x19,
 };
 
+// Flash size response length
+constexpr uint8_t flashSizeRespLen = 0x7;
+
 const char* dbusObj = "/xyz/openbmc_project/state/boot/raw";
 
 const char* dbusService = "xyz.openbmc_project.State.Boot.Raw";
diff --git a/include/commandutils.hpp b/include/commandutils.hpp
index d51c0e8..b9290d0 100644
--- a/include/commandutils.hpp
+++ b/include/commandutils.hpp
@@ -23,6 +23,7 @@
 static constexpr bool debug = false;
 
 using IanaType = std::array<uint8_t, 3>;
+using flashSize = std::array<uint8_t, 4>;
 
 static constexpr IanaType iana = {0x15, 0xA0, 0x0}; // Meta's IANA
 
diff --git a/src/biccommands.cpp b/src/biccommands.cpp
index 13907e1..91416ad 100644
--- a/src/biccommands.cpp
+++ b/src/biccommands.cpp
@@ -29,6 +29,9 @@
 namespace ipmi
 {
 
+int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
+               std::vector<uint8_t>&);
+
 using namespace phosphor::logging;
 
 #ifdef BIC_ENABLED
@@ -206,6 +209,59 @@
     return ipmi::responseSuccess(reqIana);
 }
 
+//----------------------------------------------------------------------
+// ipmiOemGetBiosFlashSize (CMD_OEM_GET_FLASH_SIZE)
+// This Function will return the bios flash size
+// netfn=0x38 and cmd=0x19 send the response back to the sender.
+//----------------------------------------------------------------------
+
+ipmi::RspType<IanaType, flashSize>
+    ipmiOemGetBiosFlashSize(ipmi::Context::ptr ctx, IanaType ianaReq,
+                            uint8_t target)
+{
+    if (iana != ianaReq)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "Invalid IANA ID length received");
+        return ipmi::responseReqDataLenInvalid();
+    }
+
+    std::vector<uint8_t> respData;
+    uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
+    std::vector<uint8_t> reqData(ianaReq.begin(), ianaReq.end());
+    reqData.emplace_back(target);
+
+    if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
+    {
+        return ipmi::responseUnspecifiedError();
+    }
+
+    if (respData.size() != flashSizeRespLen)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "Invalid Response Data length received");
+        return ipmi::responseReqDataLenInvalid();
+    }
+
+    IanaType ianaResp;
+    std::copy_n(respData.begin(), ianaResp.size(), ianaResp.begin());
+
+    if (iana != ianaResp)
+    {
+        phosphor::logging::log<phosphor::logging::level::ERR>(
+            "Invalid IANA ID received");
+        return ipmi::responseInvalidCommand();
+    }
+
+    flashSize flashResp;
+    std::vector<uint8_t>::iterator respDataIter = respData.begin();
+    std::advance(respDataIter, ianaResp.size());
+    std::copy_n(respDataIter, flashResp.size(), flashResp.begin());
+
+    // sending the success response.
+    return ipmi::responseSuccess(ianaResp, flashResp);
+}
+
 [[maybe_unused]] static void registerBICFunctions(void)
 {
 
@@ -227,6 +283,9 @@
         ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
         static_cast<Cmd>(fb_bic_cmds::CMD_OEM_SET_HOST_POWER_STATE),
         ipmi::Privilege::User, ipmiOemSetHostPowerState);
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFive,
+                          static_cast<Cmd>(fb_bic_cmds::CMD_OEM_GET_FLASH_SIZE),
+                          ipmi::Privilege::User, ipmiOemGetBiosFlashSize);
     return;
 }