Add NM discovery SDR support

NM discovery is an Intel OEM SDR,
it is used by external SW to check the NM functionality

Tested:
ipmitool sdr dump sdr.bin
The new added sdr is included at the end of the .bin file:
51 c0 0b 57 01  00 0d 01 2c 60 19 18 1a 1b

Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
Change-Id: I2b7e8059908791dcc6853be5ba2b9e22210eb736
diff --git a/src/sensorcommands.cpp b/src/sensorcommands.cpp
index d500a00..f58f0e2 100644
--- a/src/sensorcommands.cpp
+++ b/src/sensorcommands.cpp
@@ -1170,8 +1170,9 @@
         return ipmi::response(ret);
     }
 
-    size_t lastRecord =
-        sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
+    size_t lastRecord = sensorTree.size() + fruCount +
+                        ipmi::storage::type12Count +
+                        ipmi::storage::nmDiscoverySDRCount - 1;
     if (recordID == lastRecordIndex)
     {
         recordID = lastRecord;
@@ -1187,7 +1188,28 @@
     {
         std::vector<uint8_t> recordData;
         size_t fruIndex = recordID - sensorTree.size();
-        if (fruIndex >= fruCount)
+        size_t type12End = fruCount + ipmi::storage::type12Count;
+
+        if (fruIndex >= type12End)
+        {
+            // NM discovery SDR
+            size_t nmDiscoveryIndex = fruIndex - type12End;
+            if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount ||
+                offset > sizeof(NMDiscoveryRecord))
+            {
+                return ipmi::responseInvalidFieldRequest();
+            }
+
+            std::vector<uint8_t> record =
+                ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
+            if (record.size() < (offset + bytesToRead))
+            {
+                bytesToRead = record.size() - offset;
+            }
+            recordData.insert(recordData.end(), record.begin() + offset,
+                              record.begin() + offset + bytesToRead);
+        }
+        else if (fruIndex >= fruCount)
         {
             // handle type 12 hardcoded records
             size_t type12Index = fruIndex - fruCount;
diff --git a/src/storagecommands.cpp b/src/storagecommands.cpp
index f398980..631d063 100644
--- a/src/storagecommands.cpp
+++ b/src/storagecommands.cpp
@@ -1175,6 +1175,41 @@
     return resp;
 }
 
+std::vector<uint8_t> getNMDiscoverySDR(uint16_t index, uint16_t recordId)
+{
+    std::vector<uint8_t> resp;
+    if (index == 0)
+    {
+        NMDiscoveryRecord nm = {};
+        nm.header.record_id_lsb = recordId;
+        nm.header.record_id_msb = recordId >> 8;
+        nm.header.sdr_version = ipmiSdrVersion;
+        nm.header.record_type = 0xC0;
+        nm.header.record_length = 0xB;
+        nm.oemID0 = 0x57;
+        nm.oemID1 = 0x1;
+        nm.oemID2 = 0x0;
+        nm.subType = 0x0D;
+        nm.version = 0x1;
+        nm.slaveAddress = 0x2C;
+        nm.channelNumber = 0x60;
+        nm.healthEventSensor = 0x19;
+        nm.exceptionEventSensor = 0x18;
+        nm.operationalCapSensor = 0x1A;
+        nm.thresholdExceededSensor = 0x1B;
+
+        uint8_t* nmPtr = reinterpret_cast<uint8_t*>(&nm);
+        resp.insert(resp.end(), nmPtr, nmPtr + sizeof(NMDiscoveryRecord));
+    }
+    else
+    {
+        throw std::runtime_error("getNMDiscoverySDR:: Illegal index " +
+                                 std::to_string(index));
+    }
+
+    return resp;
+}
+
 void registerStorageFunctions()
 {
     createTimers();