storagecommands: move Read and Write FRU data

Rewrite "Read and write FRU data" to new IPMI provider API.

Tested:
verified using ipmitool storage commands.
a. read fru data
b. write fru data before and after the changes.

Write Fru data:
Input Command: ipmitool raw 0x0a 0x12 0x00 0x02 0x01 0x15 0x26 0x24
               0x20 0x1a 0x10 0x01 0x02 0x03 0x5 0x43 0x55 0x66 0xaa 0xbb 0xaa
Output: 00

Read fru data:
Input Command: ipmitool raw 0x0a 0x11 0x00 0x02 0x01 0x10
Output: 10 15 26 24 20 1a 10 01 02 03 05 43 55 66 aa bb aa

Signed-off-by: jayaprakash Mutyala <mutyalax.jayaprakash@intel.com>
Change-Id: Id9e52623d262bab8fa1fe861896fc36a43c9f488
diff --git a/include/storagecommands.hpp b/include/storagecommands.hpp
index 1c709d1..c42f158 100644
--- a/include/storagecommands.hpp
+++ b/include/storagecommands.hpp
@@ -56,22 +56,6 @@
     overflow = 0x80
 };
 
-#pragma pack(push, 1)
-struct GetFRUAreaReq
-{
-    uint8_t fruDeviceID;
-    uint16_t fruInventoryOffset;
-    uint8_t countToRead;
-};
-
-struct WriteFRUDataReq
-{
-    uint8_t fruDeviceID;
-    uint16_t fruInventoryOffset;
-    uint8_t data[];
-};
-#pragma pack(pop)
-
 enum class GetFRUAreaAccessType : uint8_t
 {
     byte = 0x0,
@@ -90,8 +74,6 @@
 
 enum class IPMINetfnStorageCmds : ipmi_cmd_t
 {
-    ipmiCmdReadFRUData = 0x11,
-    ipmiCmdWriteFRUData = 0x12,
     ipmiCmdGetRepositoryInfo = 0x20,
     ipmiCmdGetSDRAllocationInfo = 0x21,
     ipmiCmdReserveSDR = 0x22,
diff --git a/src/storagecommands.cpp b/src/storagecommands.cpp
index 1db2f0d..b35ae9b 100644
--- a/src/storagecommands.cpp
+++ b/src/storagecommands.cpp
@@ -261,96 +261,92 @@
     return IPMI_CC_OK;
 }
 
-ipmi_ret_t ipmiStorageReadFRUData(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
-                                  ipmi_request_t request,
-                                  ipmi_response_t response,
-                                  ipmi_data_len_t dataLen,
-                                  ipmi_context_t context)
+/** @brief implements the read FRU data command
+ *  @param fruDeviceId        - FRU Device ID
+ *  @param fruInventoryOffset - FRU Inventory Offset to write
+ *  @param countToRead        - Count to read
+ *
+ *  @returns ipmi completion code plus response data
+ *   - countWritten  - Count written
+ */
+ipmi::RspType<uint8_t,             // Count
+              std::vector<uint8_t> // Requested data
+              >
+    ipmiStorageReadFruData(uint8_t fruDeviceId, uint16_t fruInventoryOffset,
+                           uint8_t countToRead)
 {
-    if (*dataLen != 4)
+    if (fruDeviceId == 0xFF)
     {
-        *dataLen = 0;
-        return IPMI_CC_REQ_DATA_LEN_INVALID;
-    }
-    *dataLen = 0; // default to 0 in case of an error
-
-    auto req = static_cast<GetFRUAreaReq*>(request);
-
-    if (req->countToRead > maxMessageSize - 1)
-    {
-        return IPMI_CC_INVALID_FIELD_REQUEST;
-    }
-    ipmi_ret_t status = replaceCacheFru(req->fruDeviceID);
-
-    if (status != IPMI_CC_OK)
-    {
-        return status;
+        return ipmi::responseInvalidFieldRequest();
     }
 
-    size_t fromFRUByteLen = 0;
-    if (req->countToRead + req->fruInventoryOffset < fruCache.size())
-    {
-        fromFRUByteLen = req->countToRead;
-    }
-    else if (fruCache.size() > req->fruInventoryOffset)
-    {
-        fromFRUByteLen = fruCache.size() - req->fruInventoryOffset;
-    }
-    size_t padByteLen = req->countToRead - fromFRUByteLen;
-    uint8_t* respPtr = static_cast<uint8_t*>(response);
-    *respPtr = req->countToRead;
-    std::copy(fruCache.begin() + req->fruInventoryOffset,
-              fruCache.begin() + req->fruInventoryOffset + fromFRUByteLen,
-              ++respPtr);
-    // if longer than the fru is requested, fill with 0xFF
-    if (padByteLen)
-    {
-        respPtr += fromFRUByteLen;
-        std::fill(respPtr, respPtr + padByteLen, 0xFF);
-    }
-    *dataLen = fromFRUByteLen + 1;
+    ipmi::Cc status = replaceCacheFru(fruDeviceId);
 
-    return IPMI_CC_OK;
+    if (status != ipmi::ccSuccess)
+    {
+        return ipmi::response(status);
+    }
+
+    size_t fromFruByteLen = 0;
+    if (countToRead + fruInventoryOffset < fruCache.size())
+    {
+        fromFruByteLen = countToRead;
+    }
+    else if (fruCache.size() > fruInventoryOffset)
+    {
+        fromFruByteLen = fruCache.size() - fruInventoryOffset;
+    }
+    else
+    {
+        return ipmi::responseInvalidFieldRequest();
+    }
+
+    std::vector<uint8_t> requestedData;
+
+    requestedData.insert(
+        requestedData.begin(), fruCache.begin() + fruInventoryOffset,
+        fruCache.begin() + fruInventoryOffset + fromFruByteLen);
+
+    return ipmi::responseSuccess(countToRead, requestedData);
 }
 
-ipmi_ret_t ipmiStorageWriteFRUData(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
-                                   ipmi_request_t request,
-                                   ipmi_response_t response,
-                                   ipmi_data_len_t dataLen,
-                                   ipmi_context_t context)
+/** @brief implements the write FRU data command
+ *  @param fruDeviceId        - FRU Device ID
+ *  @param fruInventoryOffset - FRU Inventory Offset to write
+ *  @param dataToWrite        - Data to write
+ *
+ *  @returns ipmi completion code plus response data
+ *   - countWritten  - Count written
+ */
+ipmi::RspType<uint8_t>
+    ipmiStorageWriteFruData(uint8_t fruDeviceId, uint16_t fruInventoryOffset,
+                            std::vector<uint8_t>& dataToWrite)
 {
-    if (*dataLen < 4 ||
-        *dataLen >=
-            0xFF + 3) // count written return is one byte, so limit to one byte
-                      // of data after the three request data bytes
+    if (fruDeviceId == 0xFF)
     {
-        *dataLen = 0;
-        return IPMI_CC_REQ_DATA_LEN_INVALID;
+        return ipmi::responseInvalidFieldRequest();
     }
 
-    auto req = static_cast<WriteFRUDataReq*>(request);
-    size_t writeLen = *dataLen - 3;
-    *dataLen = 0; // default to 0 in case of an error
+    size_t writeLen = dataToWrite.size();
 
-    ipmi_ret_t status = replaceCacheFru(req->fruDeviceID);
-    if (status != IPMI_CC_OK)
+    ipmi::Cc status = replaceCacheFru(fruDeviceId);
+    if (status != ipmi::ccSuccess)
     {
-        return status;
+        return ipmi::response(status);
     }
-    int lastWriteAddr = req->fruInventoryOffset + writeLen;
+    int lastWriteAddr = fruInventoryOffset + writeLen;
     if (fruCache.size() < lastWriteAddr)
     {
-        fruCache.resize(req->fruInventoryOffset + writeLen);
+        fruCache.resize(fruInventoryOffset + writeLen);
     }
 
-    std::copy(req->data, req->data + writeLen,
-              fruCache.begin() + req->fruInventoryOffset);
+    std::copy(dataToWrite.begin(), dataToWrite.begin() + writeLen,
+              fruCache.begin() + fruInventoryOffset);
 
     bool atEnd = false;
 
     if (fruCache.size() >= sizeof(FRUHeader))
     {
-
         FRUHeader* header = reinterpret_cast<FRUHeader*>(fruCache.data());
 
         int lastRecordStart = std::max(
@@ -374,16 +370,16 @@
             }
         }
     }
-    uint8_t* respPtr = static_cast<uint8_t*>(response);
+    uint8_t countWritten = 0;
     if (atEnd)
     {
         // cancel timer, we're at the end so might as well send it
         cacheTimer->stop();
         if (!writeFru())
         {
-            return IPMI_CC_INVALID_FIELD_REQUEST;
+            return ipmi::responseInvalidFieldRequest();
         }
-        *respPtr = std::min(fruCache.size(), static_cast<size_t>(0xFF));
+        countWritten = std::min(fruCache.size(), static_cast<size_t>(0xFF));
     }
     else
     {
@@ -392,12 +388,10 @@
         createTimer();
         cacheTimer->start(std::chrono::duration_cast<std::chrono::microseconds>(
             std::chrono::seconds(cacheTimeoutSeconds)));
-        *respPtr = 0;
+        countWritten = 0;
     }
 
-    *dataLen = 1;
-
-    return IPMI_CC_OK;
+    return ipmi::responseSuccess(countWritten);
 }
 
 /** @brief implements the get FRU inventory area info command
@@ -1085,16 +1079,14 @@
                           ipmi::storage::cmdGetFruInventoryAreaInfo,
                           ipmi::Privilege::User, ipmiStorageGetFruInvAreaInfo);
     // <READ FRU Data>
-    ipmiPrintAndRegister(
-        NETFUN_STORAGE,
-        static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdReadFRUData), NULL,
-        ipmiStorageReadFRUData, PRIVILEGE_USER);
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
+                          ipmi::storage::cmdReadFruData, ipmi::Privilege::User,
+                          ipmiStorageReadFruData);
 
     // <WRITE FRU Data>
-    ipmiPrintAndRegister(
-        NETFUN_STORAGE,
-        static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdWriteFRUData),
-        NULL, ipmiStorageWriteFRUData, PRIVILEGE_OPERATOR);
+    ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
+                          ipmi::storage::cmdWriteFruData,
+                          ipmi::Privilege::Operator, ipmiStorageWriteFruData);
 
     // <Get SEL Info>
     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,