Support the MultiRecord section in FRUs

Add support for FRUs containing a MultiRecord section to
ipmiStorageWriteFruData().

Before this patch, the presence of a MultiRecord section was ignored.
lastRecordStart would point to the last section populated before the
MultiRecord section (e.g. the Product section).

Now, if there is a MultiRecord section, walk the MultiRecord headers to
find the last one and set lastRecordStart appropriately.

Tested:
I have a system with an eeprom containing a MultiRecord section with two
records. Writes to that FRU work after this change.
Signed-off-by: Peter Lundgren <peterlundgren@google.com>
Change-Id: Iea269ad386b1cbc7b4876ddeb9cfac3b9e83f541
diff --git a/src/storagecommands.cpp b/src/storagecommands.cpp
index 631d063..cc0203d 100644
--- a/src/storagecommands.cpp
+++ b/src/storagecommands.cpp
@@ -372,26 +372,48 @@
     {
         FRUHeader* header = reinterpret_cast<FRUHeader*>(fruCache.data());
 
+        int areaLength = 0;
         int lastRecordStart = std::max(
-            header->internalOffset,
-            std::max(header->chassisOffset,
-                     std::max(header->boardOffset, header->productOffset)));
-        // TODO: Handle Multi-Record FRUs?
-
+            {header->internalOffset, header->chassisOffset, header->boardOffset,
+             header->productOffset, header->multiRecordOffset});
         lastRecordStart *= 8; // header starts in are multiples of 8 bytes
 
-        // get the length of the area in multiples of 8 bytes
-        if (lastWriteAddr > (lastRecordStart + 1))
+        if (header->multiRecordOffset)
         {
-            // second byte in record area is the length
-            int areaLength(fruCache[lastRecordStart + 1]);
-            areaLength *= 8; // it is in multiples of 8 bytes
-
-            if (lastWriteAddr >= (areaLength + lastRecordStart))
+            // This FRU has a MultiRecord Area
+            uint8_t endOfList = 0;
+            // Walk the MultiRecord headers until the last record
+            while (!endOfList)
             {
-                atEnd = true;
+                // The MSB in the second byte of the MultiRecord header signals
+                // "End of list"
+                endOfList = fruCache[lastRecordStart + 1] & 0x80;
+                // Third byte in the MultiRecord header is the length
+                areaLength = fruCache[lastRecordStart + 2];
+                // This length is in bytes (not 8 bytes like other headers)
+                areaLength += 5; // The length omits the 5 byte header
+                if (!endOfList)
+                {
+                    // Next MultiRecord header
+                    lastRecordStart += areaLength;
+                }
             }
         }
+        else
+        {
+            // This FRU does not have a MultiRecord Area
+            // Get the length of the area in multiples of 8 bytes
+            if (lastWriteAddr > (lastRecordStart + 1))
+            {
+                // second byte in record area is the length
+                areaLength = fruCache[lastRecordStart + 1];
+                areaLength *= 8; // it is in multiples of 8 bytes
+            }
+        }
+        if (lastWriteAddr >= (areaLength + lastRecordStart))
+        {
+            atEnd = true;
+        }
     }
     uint8_t countWritten = 0;