Add type 12h sdr records

This adds support for BMC and ME type 12 records.

Tested:

ipmitool sdr list mcloc

Device ID              : �Basbrd Mgmt Ctl
Entity ID              : 0.46 (Unspecified)
Device Slave Address   : 20h
Channel Number         : 0h
ACPI System P/S Notif  : Not Required
ACPI Device P/S Notif  : Not Required
Controller Presence    : Dynamic
Logs Init Agent Errors : No
Event Message Gen      : Enable
Device Capabilities
 Chassis Device        : Yes
 Bridge                : No
 IPMB Event Generator  : Yes
 IPMB Event Receiver   : Yes
 FRU Inventory Device  : Yes
 SEL Device            : Yes
 SDR Repository        : Yes
 Sensor Device         : Yes

Device ID              : �Mgmt Engin
Entity ID              : 0.46 (Unspecified)
Device Slave Address   : 2Ch
Channel Number         : 6h
ACPI System P/S Notif  : Not Required
ACPI Device P/S Notif  : Not Required
Controller Presence    : Static
Logs Init Agent Errors : No
Event Message Gen      : Enable
Device Capabilities
 Chassis Device        : No
 Bridge                : No
 IPMB Event Generator  : Yes
 IPMB Event Receiver   : No
 FRU Inventory Device  : No
 SEL Device            : No
 SDR Repository        : No
 Sensor Device         : Yes

Change-Id: I3d015ca2f61ab07be18ba46239c3d6a919f0298b
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/include/storagecommands.hpp b/include/storagecommands.hpp
index 1a2d281..1c709d1 100644
--- a/include/storagecommands.hpp
+++ b/include/storagecommands.hpp
@@ -35,17 +35,6 @@
 } // namespace intel_oem::ipmi::sel
 
 #pragma pack(push, 1)
-struct GetSDRInfoResp
-{
-    uint8_t sdrVersion;
-    uint8_t recordCountLS;
-    uint8_t recordCountMS;
-    uint8_t freeSpace[2];
-    uint32_t mostRecentAddition;
-    uint32_t mostRecentErase;
-    uint8_t operationSupport;
-};
-
 struct GetSDRReq
 {
     uint16_t reservationID;
@@ -123,12 +112,33 @@
 };
 #pragma pack(pop)
 
+#pragma pack(push, 1)
+struct Type12Record
+{
+    get_sdr::SensorDataRecordHeader header;
+    uint8_t slaveAddress;
+    uint8_t channelNumber;
+    uint8_t powerStateNotification;
+    uint8_t deviceCapabilities;
+    uint24_t reserved;
+    uint8_t entityID;
+    uint8_t entityInstance;
+    uint8_t oem;
+    uint8_t typeLengthCode;
+    char name[16];
+};
+#pragma pack(pop)
+
 namespace ipmi
 {
 namespace storage
 {
+
+constexpr const size_t type12Count = 2;
 ipmi_ret_t getFruSdrs(size_t index, get_sdr::SensorDataFruRecord& resp);
 
 ipmi_ret_t getFruSdrCount(size_t& count);
+
+std::vector<uint8_t> getType12SDRs(uint16_t index, uint16_t recordId);
 } // namespace storage
 } // namespace ipmi
diff --git a/src/sensorcommands.cpp b/src/sensorcommands.cpp
index b24ac7e..28d68f4 100644
--- a/src/sensorcommands.cpp
+++ b/src/sensorcommands.cpp
@@ -1053,52 +1053,41 @@
 
 /* storage commands */
 
-ipmi_ret_t ipmiStorageGetSDRRepositoryInfo(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)
+ipmi::RspType<uint8_t,  // sdr version
+              uint16_t, // record count
+              uint16_t, // free space
+              uint32_t, // most recent addition
+              uint32_t, // most recent erase
+              uint8_t   // operationSupport
+              >
+    ipmiStorageGetSDRRepositoryInfo(void)
 {
-    printCommand(+netfn, +cmd);
-
-    if (*dataLen)
-    {
-        *dataLen = 0;
-        return IPMI_CC_REQ_DATA_LEN_INVALID;
-    }
-    *dataLen = 0; // default to 0 in case of an error
-
+    constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
     if (sensorTree.empty() && !getSensorSubtree(sensorTree))
     {
-        return IPMI_CC_RESPONSE_ERROR;
+        return ipmi::responseResponseError();
     }
 
-    // zero out response buff
-    auto responseClear = static_cast<uint8_t *>(response);
-    std::fill(responseClear, responseClear + sizeof(GetSDRInfoResp), 0);
+    size_t fruCount = 0;
+    ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
+    if (ret != ipmi::ccSuccess)
+    {
+        return ipmi::response(ret);
+    }
 
-    auto resp = static_cast<GetSDRInfoResp *>(response);
-    resp->sdrVersion = ipmiSdrVersion;
-    uint16_t recordCount = sensorTree.size();
+    uint16_t recordCount =
+        sensorTree.size() + fruCount + ipmi::storage::type12Count;
 
-    // todo: for now, sdr count is number of sensors
-    resp->recordCountLS = recordCount & 0xFF;
-    resp->recordCountMS = recordCount >> 8;
-
-    // free space unspcified
-    resp->freeSpace[0] = 0xFF;
-    resp->freeSpace[1] = 0xFF;
-
-    resp->mostRecentAddition = sdrLastAdd;
-    resp->mostRecentErase = sdrLastRemove;
-    resp->operationSupport = static_cast<uint8_t>(
+    uint8_t operationSupport = static_cast<uint8_t>(
         SdrRepositoryInfoOps::overflow); // write not supported
-    resp->operationSupport |=
+
+    operationSupport |=
         static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
-    resp->operationSupport |= static_cast<uint8_t>(
+    operationSupport |= static_cast<uint8_t>(
         SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
-    *dataLen = sizeof(GetSDRInfoResp);
-    return IPMI_CC_OK;
+    return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
+                                 unspecifiedFreeSpace, sdrLastAdd,
+                                 sdrLastRemove, operationSupport);
 }
 
 /** @brief implements the get SDR allocation info command
@@ -1166,13 +1155,14 @@
     }
 
     size_t fruCount = 0;
-    ipmi_ret_t ret = ipmi::storage::getFruSdrCount(fruCount);
-    if (ret != IPMI_CC_OK)
+    ipmi::Cc ret = ipmi::storage::getFruSdrCount(fruCount);
+    if (ret != ipmi::ccSuccess)
     {
         return ipmi::response(ret);
     }
 
-    size_t lastRecord = sensorTree.size() + fruCount - 1;
+    size_t lastRecord =
+        sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
     if (recordID == lastRecordIndex)
     {
         recordID = lastRecord;
@@ -1186,30 +1176,51 @@
 
     if (recordID >= sensorTree.size())
     {
+        std::vector<uint8_t> recordData;
         size_t fruIndex = recordID - sensorTree.size();
         if (fruIndex >= fruCount)
         {
-            return ipmi::responseInvalidFieldRequest();
-        }
-        get_sdr::SensorDataFruRecord data;
-        if (offset > sizeof(data))
-        {
-            return ipmi::responseInvalidFieldRequest();
-        }
-        ret = ipmi::storage::getFruSdrs(fruIndex, data);
-        if (ret != IPMI_CC_OK)
-        {
-            return ipmi::response(ret);
-        }
-        data.header.record_id_msb = recordID << 8;
-        data.header.record_id_lsb = recordID & 0xFF;
-        if (sizeof(data) < (offset + bytesToRead))
-        {
-            bytesToRead = sizeof(data) - offset;
-        }
+            // handle type 12 hardcoded records
+            size_t type12Index = fruIndex - fruCount;
+            if (type12Index >= ipmi::storage::type12Count ||
+                offset > sizeof(Type12Record))
+            {
+                return ipmi::responseInvalidFieldRequest();
+            }
+            std::vector<uint8_t> record =
+                ipmi::storage::getType12SDRs(type12Index, recordID);
+            if (record.size() < (offset + bytesToRead))
+            {
+                bytesToRead = record.size() - offset;
+            }
 
-        uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
-        std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
+            recordData.insert(recordData.end(), record.begin() + offset,
+                              record.begin() + offset + bytesToRead);
+        }
+        else
+        {
+            // handle fru records
+            get_sdr::SensorDataFruRecord data;
+            if (offset > sizeof(data))
+            {
+                return ipmi::responseInvalidFieldRequest();
+            }
+            ret = ipmi::storage::getFruSdrs(fruIndex, data);
+            if (ret != IPMI_CC_OK)
+            {
+                return ipmi::response(ret);
+            }
+            data.header.record_id_msb = recordID << 8;
+            data.header.record_id_lsb = recordID & 0xFF;
+            if (sizeof(data) < (offset + bytesToRead))
+            {
+                bytesToRead = sizeof(data) - offset;
+            }
+
+            uint8_t *respStart = reinterpret_cast<uint8_t *>(&data) + offset;
+            recordData.insert(recordData.end(), respStart,
+                              respStart + bytesToRead);
+        }
 
         return ipmi::responseSuccess(nextRecordId, recordData);
     }
@@ -1491,10 +1502,10 @@
     // versions
 
     // <Get SDR Repository Info>
-    ipmiPrintAndRegister(
-        NETFUN_STORAGE,
-        static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetRepositoryInfo),
-        nullptr, ipmiStorageGetSDRRepositoryInfo, PRIVILEGE_USER);
+    ipmi::registerHandler(
+        ipmi::prioOemBase, NETFUN_STORAGE,
+        static_cast<ipmi::Cmd>(IPMINetfnStorageCmds::ipmiCmdGetRepositoryInfo),
+        ipmi::Privilege::User, ipmiStorageGetSDRRepositoryInfo);
 
     // <Get SDR Allocation Info>
     ipmi::registerHandler(
diff --git a/src/storagecommands.cpp b/src/storagecommands.cpp
index 39405c5..8c716c2 100644
--- a/src/storagecommands.cpp
+++ b/src/storagecommands.cpp
@@ -1022,6 +1022,62 @@
     return ipmi::responseInvalidCommand();
 }
 
+std::vector<uint8_t> getType12SDRs(uint16_t index, uint16_t recordId)
+{
+    std::vector<uint8_t> resp;
+    if (index == 0)
+    {
+        Type12Record bmc = {};
+        bmc.header.record_id_lsb = recordId;
+        bmc.header.record_id_msb = recordId >> 8;
+        bmc.header.sdr_version = ipmiSdrVersion;
+        bmc.header.record_type = 0x12;
+        bmc.header.record_length = 0x1b;
+        bmc.slaveAddress = 0x20;
+        bmc.channelNumber = 0;
+        bmc.powerStateNotification = 0;
+        bmc.deviceCapabilities = 0xBF;
+        bmc.reserved = 0;
+        bmc.entityID = 0x2E;
+        bmc.entityInstance = 1;
+        bmc.oem = 0;
+        bmc.typeLengthCode = 0xD0;
+        std::string bmcName = "Basbrd Mgmt Ctlr";
+        std::copy(bmcName.begin(), bmcName.end(), bmc.name);
+        uint8_t* bmcPtr = reinterpret_cast<uint8_t*>(&bmc);
+        resp.insert(resp.end(), bmcPtr, bmcPtr + sizeof(Type12Record));
+    }
+    else if (index == 1)
+    {
+        Type12Record me = {};
+        me.header.record_id_lsb = recordId;
+        me.header.record_id_msb = recordId >> 8;
+        me.header.sdr_version = ipmiSdrVersion;
+        me.header.record_type = 0x12;
+        me.header.record_length = 0x16;
+        me.slaveAddress = 0x2C;
+        me.channelNumber = 6;
+        me.powerStateNotification = 0x24;
+        me.deviceCapabilities = 0x21;
+        me.reserved = 0;
+        me.entityID = 0x2E;
+        me.entityInstance = 2;
+        me.oem = 0;
+        me.typeLengthCode = 0xCB;
+        std::string meName = "Mgmt Engine";
+        std::copy(meName.begin(), meName.end(), me.name);
+        uint8_t* mePtr = reinterpret_cast<uint8_t*>(&me);
+        resp.insert(resp.end(), mePtr, mePtr + sizeof(Type12Record));
+    }
+    else
+    {
+        throw std::runtime_error("getType12SDRs:: Illegal index " +
+                                 std::to_string(index));
+    }
+
+    return resp;
+}
+
 void registerStorageFunctions()
 {
     // <Get FRU Inventory Area Info>