1*0b02be92SPatrick Venture #include "ipmi_fru_info_area.hpp"
2*0b02be92SPatrick Venture 
37d9157edSMarri Devender Rao #include <algorithm>
4*0b02be92SPatrick Venture #include <ctime>
57d9157edSMarri Devender Rao #include <map>
67d9157edSMarri Devender Rao #include <numeric>
77d9157edSMarri Devender Rao #include <phosphor-logging/elog.hpp>
87d9157edSMarri Devender Rao namespace ipmi
97d9157edSMarri Devender Rao {
107d9157edSMarri Devender Rao namespace fru
117d9157edSMarri Devender Rao {
127d9157edSMarri Devender Rao using namespace phosphor::logging;
137d9157edSMarri Devender Rao 
147d9157edSMarri Devender Rao // Property variables
157d9157edSMarri Devender Rao static constexpr auto partNumber = "PartNumber";
167d9157edSMarri Devender Rao static constexpr auto serialNumber = "SerialNumber";
177d9157edSMarri Devender Rao static constexpr auto manufacturer = "Manufacturer";
187d9157edSMarri Devender Rao static constexpr auto buildDate = "BuildDate";
197d9157edSMarri Devender Rao static constexpr auto model = "Model";
207d9157edSMarri Devender Rao static constexpr auto prettyName = "PrettyName";
217d9157edSMarri Devender Rao static constexpr auto version = "Version";
227d9157edSMarri Devender Rao 
237d9157edSMarri Devender Rao // Board info areas
247d9157edSMarri Devender Rao static constexpr auto board = "Board";
257d9157edSMarri Devender Rao static constexpr auto chassis = "Chassis";
267d9157edSMarri Devender Rao static constexpr auto product = "Product";
277d9157edSMarri Devender Rao 
287d9157edSMarri Devender Rao static constexpr auto specVersion = 0x1;
293e6a769bSRatan Gupta static constexpr auto recordUnitOfMeasurement = 0x8; // size in bytes
307d9157edSMarri Devender Rao static constexpr auto checksumSize = 0x1;            // size in bytes
317d9157edSMarri Devender Rao static constexpr auto recordNotPresent = 0x0;
327d9157edSMarri Devender Rao static constexpr auto englishLanguageCode = 0x0;
337d9157edSMarri Devender Rao static constexpr auto typeLengthByteNull = 0x0;
347d9157edSMarri Devender Rao static constexpr auto endOfCustomFields = 0xC1;
357d9157edSMarri Devender Rao static constexpr auto commonHeaderFormatSize = 0x8; // size in bytes
367d9157edSMarri Devender Rao static constexpr auto manufacturingDateSize = 0x3;
377d9157edSMarri Devender Rao static constexpr auto areaSizeOffset = 0x1;
386edfc5c1SRatan Gupta static constexpr uint8_t typeASCII = 0xC0;
396edfc5c1SRatan Gupta static constexpr auto maxRecordAttributeValue = 0x1F;
407d9157edSMarri Devender Rao 
417ebd2464SAndres Oportus static constexpr auto secs_from_1970_1996 = 820454400;
42b898cde6SNagaraju Goruganti static constexpr auto maxMfgDateValue = 0xFFFFFF; // 3 Byte length
437ebd2464SAndres Oportus static constexpr auto secs_per_min = 60;
44*0b02be92SPatrick Venture static constexpr auto secsToMaxMfgdate =
45*0b02be92SPatrick Venture     secs_from_1970_1996 + secs_per_min * maxMfgDateValue;
467ebd2464SAndres Oportus 
477d9157edSMarri Devender Rao /**
487d9157edSMarri Devender Rao  * @brief Format Beginning of Individual IPMI FRU Data Section
497d9157edSMarri Devender Rao  *
507d9157edSMarri Devender Rao  * @param[in] langCode Language code
517d9157edSMarri Devender Rao  * @param[in/out] data FRU area data
527d9157edSMarri Devender Rao  */
537d9157edSMarri Devender Rao void preFormatProcessing(bool langCode, FruAreaData& data)
547d9157edSMarri Devender Rao {
557d9157edSMarri Devender Rao     // Add id for version of FRU Info Storage Spec used
567d9157edSMarri Devender Rao     data.emplace_back(specVersion);
577d9157edSMarri Devender Rao 
587d9157edSMarri Devender Rao     // Add Data Size - 0 as a placeholder, can edit after the data is finalized
597d9157edSMarri Devender Rao     data.emplace_back(typeLengthByteNull);
607d9157edSMarri Devender Rao 
617d9157edSMarri Devender Rao     if (langCode)
627d9157edSMarri Devender Rao     {
637d9157edSMarri Devender Rao         data.emplace_back(englishLanguageCode);
647d9157edSMarri Devender Rao     }
657d9157edSMarri Devender Rao }
667d9157edSMarri Devender Rao 
677d9157edSMarri Devender Rao /**
687d9157edSMarri Devender Rao  * @brief Append checksum of the FRU area data
697d9157edSMarri Devender Rao  *
707d9157edSMarri Devender Rao  * @param[in/out] data FRU area data
717d9157edSMarri Devender Rao  */
727d9157edSMarri Devender Rao void appendDataChecksum(FruAreaData& data)
737d9157edSMarri Devender Rao {
747d9157edSMarri Devender Rao     uint8_t checksumVal = std::accumulate(data.begin(), data.end(), 0);
757d9157edSMarri Devender Rao     // Push the Zero checksum as the last byte of this data
767d9157edSMarri Devender Rao     // This appears to be a simple summation of all the bytes
777d9157edSMarri Devender Rao     data.emplace_back(-checksumVal);
787d9157edSMarri Devender Rao }
797d9157edSMarri Devender Rao 
807d9157edSMarri Devender Rao /**
817d9157edSMarri Devender Rao  * @brief Append padding bytes for the FRU area data
827d9157edSMarri Devender Rao  *
837d9157edSMarri Devender Rao  * @param[in/out] data FRU area data
847d9157edSMarri Devender Rao  */
857d9157edSMarri Devender Rao void padData(FruAreaData& data)
867d9157edSMarri Devender Rao {
873e6a769bSRatan Gupta     uint8_t pad = (data.size() + checksumSize) % recordUnitOfMeasurement;
887d9157edSMarri Devender Rao     if (pad)
897d9157edSMarri Devender Rao     {
903e6a769bSRatan Gupta         data.resize((data.size() + recordUnitOfMeasurement - pad));
917d9157edSMarri Devender Rao     }
927d9157edSMarri Devender Rao }
937d9157edSMarri Devender Rao 
947d9157edSMarri Devender Rao /**
957d9157edSMarri Devender Rao  * @brief Format End of Individual IPMI FRU Data Section
967d9157edSMarri Devender Rao  *
977d9157edSMarri Devender Rao  * @param[in/out] fruAreaData FRU area info data
987d9157edSMarri Devender Rao  */
997d9157edSMarri Devender Rao void postFormatProcessing(FruAreaData& data)
1007d9157edSMarri Devender Rao {
1017d9157edSMarri Devender Rao     // This area needs to be padded to a multiple of 8 bytes (after checksum)
1027d9157edSMarri Devender Rao     padData(data);
1037d9157edSMarri Devender Rao 
1047d9157edSMarri Devender Rao     // Set size of data info area
105*0b02be92SPatrick Venture     data.at(areaSizeOffset) =
106*0b02be92SPatrick Venture         (data.size() + checksumSize) / (recordUnitOfMeasurement);
1077d9157edSMarri Devender Rao 
1082f66f00eSRatan Gupta     // Finally add area checksum
1097d9157edSMarri Devender Rao     appendDataChecksum(data);
1107d9157edSMarri Devender Rao }
1117d9157edSMarri Devender Rao 
1127d9157edSMarri Devender Rao /**
1137d9157edSMarri Devender Rao  * @brief Read property value from inventory and append to the FRU area data
1147d9157edSMarri Devender Rao  *
1157d9157edSMarri Devender Rao  * @param[in] key key to search for in the property inventory data
1167d9157edSMarri Devender Rao  * @param[in] propMap map of property values
1177d9157edSMarri Devender Rao  * @param[in,out] data FRU area data to be appended
1187d9157edSMarri Devender Rao  */
1197d9157edSMarri Devender Rao void appendData(const Property& key, const PropertyMap& propMap,
1207d9157edSMarri Devender Rao                 FruAreaData& data)
1217d9157edSMarri Devender Rao {
1227d9157edSMarri Devender Rao     auto iter = propMap.find(key);
1237d9157edSMarri Devender Rao     if (iter != propMap.end())
1247d9157edSMarri Devender Rao     {
1257d9157edSMarri Devender Rao         auto value = iter->second;
1267d9157edSMarri Devender Rao         // If starts with 0x or 0X remove them
1277d9157edSMarri Devender Rao         // ex: 0x123a just take 123a
1287d9157edSMarri Devender Rao         if ((value.compare(0, 2, "0x")) == 0 ||
1297d9157edSMarri Devender Rao             (value.compare(0, 2, "0X") == 0))
1307d9157edSMarri Devender Rao         {
1317d9157edSMarri Devender Rao             value.erase(0, 2);
1327d9157edSMarri Devender Rao         }
1336edfc5c1SRatan Gupta 
1346edfc5c1SRatan Gupta         // 5 bits for length
135*0b02be92SPatrick Venture         // if length is greater then 31(2^5) bytes then trim the data to 31
136*0b02be92SPatrick Venture         // bytess.
137*0b02be92SPatrick Venture         auto valueLength = (value.length() > maxRecordAttributeValue)
138*0b02be92SPatrick Venture                                ? maxRecordAttributeValue
139*0b02be92SPatrick Venture                                : value.length();
1406edfc5c1SRatan Gupta         // 2 bits for type
1416edfc5c1SRatan Gupta         // Set the type to ascii
1426edfc5c1SRatan Gupta         uint8_t typeLength = valueLength | ipmi::fru::typeASCII;
1436edfc5c1SRatan Gupta 
1446edfc5c1SRatan Gupta         data.emplace_back(typeLength);
145*0b02be92SPatrick Venture         std::copy(value.begin(), value.begin() + valueLength,
1466edfc5c1SRatan Gupta                   std::back_inserter(data));
1477d9157edSMarri Devender Rao     }
1487d9157edSMarri Devender Rao     else
1497d9157edSMarri Devender Rao     {
1507d9157edSMarri Devender Rao         // set 0 size
1517d9157edSMarri Devender Rao         data.emplace_back(typeLengthByteNull);
1527d9157edSMarri Devender Rao     }
1537d9157edSMarri Devender Rao }
1547d9157edSMarri Devender Rao 
1557d9157edSMarri Devender Rao /**
1567d9157edSMarri Devender Rao  * @brief Appends Build Date
1577d9157edSMarri Devender Rao  *
1587d9157edSMarri Devender Rao  * @param[in] propMap map of property values
1597d9157edSMarri Devender Rao  * @param[in/out] data FRU area to add the manfufacture date
1607d9157edSMarri Devender Rao  */
1617d9157edSMarri Devender Rao void appendMfgDate(const PropertyMap& propMap, FruAreaData& data)
1627d9157edSMarri Devender Rao {
1637d9157edSMarri Devender Rao     // MFG Date/Time
1647d9157edSMarri Devender Rao     auto iter = propMap.find(buildDate);
165b898cde6SNagaraju Goruganti     if ((iter != propMap.end()) && (iter->second.size() > 0))
1667d9157edSMarri Devender Rao     {
1677ebd2464SAndres Oportus         tm time = {};
1687ebd2464SAndres Oportus         strptime(iter->second.c_str(), "%F - %H:%M:%S", &time);
1697ebd2464SAndres Oportus         time_t raw = mktime(&time);
1707ebd2464SAndres Oportus 
1717ebd2464SAndres Oportus         // From FRU Spec:
1727ebd2464SAndres Oportus         // "Mfg. Date / Time
1737ebd2464SAndres Oportus         // Number of minutes from 0:00 hrs 1/1/96.
1747ebd2464SAndres Oportus         // LSbyte first (little endian)
1757ebd2464SAndres Oportus         // 00_00_00h = unspecified."
176b898cde6SNagaraju Goruganti         if ((raw >= secs_from_1970_1996) && (raw <= secsToMaxMfgdate))
1777d9157edSMarri Devender Rao         {
1787ebd2464SAndres Oportus             raw -= secs_from_1970_1996;
1797ebd2464SAndres Oportus             raw /= secs_per_min;
1807ebd2464SAndres Oportus             uint8_t fru_raw[3];
1817ebd2464SAndres Oportus             fru_raw[0] = raw & 0xFF;
1827ebd2464SAndres Oportus             fru_raw[1] = (raw >> 8) & 0xFF;
1837ebd2464SAndres Oportus             fru_raw[2] = (raw >> 16) & 0xFF;
1847ebd2464SAndres Oportus             std::copy(fru_raw, fru_raw + 3, std::back_inserter(data));
1857d9157edSMarri Devender Rao             return;
1867d9157edSMarri Devender Rao         }
1877ebd2464SAndres Oportus         fprintf(stderr, "MgfDate invalid date: %u secs since UNIX epoch\n",
1887ebd2464SAndres Oportus                 static_cast<unsigned int>(raw));
1897d9157edSMarri Devender Rao     }
1907d9157edSMarri Devender Rao     // Blank date
1917d9157edSMarri Devender Rao     data.emplace_back(0);
1927d9157edSMarri Devender Rao     data.emplace_back(0);
1937d9157edSMarri Devender Rao     data.emplace_back(0);
1947d9157edSMarri Devender Rao }
1957d9157edSMarri Devender Rao 
1967d9157edSMarri Devender Rao /**
1977d9157edSMarri Devender Rao  * @brief Builds a section of the common header
1987d9157edSMarri Devender Rao  *
1997d9157edSMarri Devender Rao  * @param[in] infoAreaSize size of the FRU area to write
2007d9157edSMarri Devender Rao  * @param[in] offset Current offset for data in overall record
2017d9157edSMarri Devender Rao  * @param[in/out] data Common Header section data container
2027d9157edSMarri Devender Rao  */
203*0b02be92SPatrick Venture void buildCommonHeaderSection(const uint32_t& infoAreaSize, uint16_t& offset,
204*0b02be92SPatrick Venture                               FruAreaData& data)
2057d9157edSMarri Devender Rao {
2067d9157edSMarri Devender Rao     // Check if data for internal use section populated
2077d9157edSMarri Devender Rao     if (infoAreaSize == 0)
2087d9157edSMarri Devender Rao     {
2097d9157edSMarri Devender Rao         // Indicate record not present
2107d9157edSMarri Devender Rao         data.emplace_back(recordNotPresent);
2117d9157edSMarri Devender Rao     }
2127d9157edSMarri Devender Rao     else
2137d9157edSMarri Devender Rao     {
2142f66f00eSRatan Gupta         // offset should be multiple of 8.
2153e6a769bSRatan Gupta         auto remainder = offset % recordUnitOfMeasurement;
2162f66f00eSRatan Gupta         // add the padding bytes in the offset so that offset
2172f66f00eSRatan Gupta         // will be multiple of 8 byte.
2183e6a769bSRatan Gupta         offset += (remainder > 0) ? recordUnitOfMeasurement - remainder : 0;
2197d9157edSMarri Devender Rao         // Place data to define offset to area data section
2203e6a769bSRatan Gupta         data.emplace_back(offset / recordUnitOfMeasurement);
2212f66f00eSRatan Gupta 
2227d9157edSMarri Devender Rao         offset += infoAreaSize;
2237d9157edSMarri Devender Rao     }
2247d9157edSMarri Devender Rao }
2257d9157edSMarri Devender Rao 
2267d9157edSMarri Devender Rao /**
2277d9157edSMarri Devender Rao  * @brief Builds the Chassis info area data section
2287d9157edSMarri Devender Rao  *
2297d9157edSMarri Devender Rao  * @param[in] propMap map of properties for chassis info area
2307d9157edSMarri Devender Rao  * @return FruAreaData container with chassis info area
2317d9157edSMarri Devender Rao  */
2327d9157edSMarri Devender Rao FruAreaData buildChassisInfoArea(const PropertyMap& propMap)
2337d9157edSMarri Devender Rao {
2347d9157edSMarri Devender Rao     FruAreaData fruAreaData;
2357d9157edSMarri Devender Rao     if (!propMap.empty())
2367d9157edSMarri Devender Rao     {
2377d9157edSMarri Devender Rao         // Set formatting data that goes at the beginning of the record
2387d9157edSMarri Devender Rao         preFormatProcessing(false, fruAreaData);
2397d9157edSMarri Devender Rao 
2407d9157edSMarri Devender Rao         // chassis type
2417d9157edSMarri Devender Rao         fruAreaData.emplace_back(0);
2427d9157edSMarri Devender Rao 
2437d9157edSMarri Devender Rao         // Chasiss part number, in config.yaml it is configured as model
2447d9157edSMarri Devender Rao         appendData(model, propMap, fruAreaData);
2457d9157edSMarri Devender Rao 
2467d9157edSMarri Devender Rao         // Board serial number
2477d9157edSMarri Devender Rao         appendData(serialNumber, propMap, fruAreaData);
2487d9157edSMarri Devender Rao 
2497d9157edSMarri Devender Rao         // Indicate End of Custom Fields
2507d9157edSMarri Devender Rao         fruAreaData.emplace_back(endOfCustomFields);
2517d9157edSMarri Devender Rao 
2527d9157edSMarri Devender Rao         // Complete record data formatting
2537d9157edSMarri Devender Rao         postFormatProcessing(fruAreaData);
2547d9157edSMarri Devender Rao     }
2557d9157edSMarri Devender Rao     return fruAreaData;
2567d9157edSMarri Devender Rao }
2577d9157edSMarri Devender Rao 
2587d9157edSMarri Devender Rao /**
2597d9157edSMarri Devender Rao  * @brief Builds the Board info area data section
2607d9157edSMarri Devender Rao  *
2617d9157edSMarri Devender Rao  * @param[in] propMap map of properties for board info area
2627d9157edSMarri Devender Rao  * @return FruAreaData container with board info area
2637d9157edSMarri Devender Rao  */
2647d9157edSMarri Devender Rao FruAreaData buildBoardInfoArea(const PropertyMap& propMap)
2657d9157edSMarri Devender Rao {
2667d9157edSMarri Devender Rao     FruAreaData fruAreaData;
2677d9157edSMarri Devender Rao     if (!propMap.empty())
2687d9157edSMarri Devender Rao     {
2697d9157edSMarri Devender Rao         preFormatProcessing(true, fruAreaData);
2707d9157edSMarri Devender Rao 
2717d9157edSMarri Devender Rao         // Manufacturing date
2727d9157edSMarri Devender Rao         appendMfgDate(propMap, fruAreaData);
2737d9157edSMarri Devender Rao 
2747d9157edSMarri Devender Rao         // manufacturer
2757d9157edSMarri Devender Rao         appendData(manufacturer, propMap, fruAreaData);
2767d9157edSMarri Devender Rao 
2777d9157edSMarri Devender Rao         // Product name/Pretty name
2787d9157edSMarri Devender Rao         appendData(prettyName, propMap, fruAreaData);
2797d9157edSMarri Devender Rao 
2807d9157edSMarri Devender Rao         // Board serial number
2817d9157edSMarri Devender Rao         appendData(serialNumber, propMap, fruAreaData);
2827d9157edSMarri Devender Rao 
2837d9157edSMarri Devender Rao         // Board part number
2847d9157edSMarri Devender Rao         appendData(partNumber, propMap, fruAreaData);
2857d9157edSMarri Devender Rao 
2867d9157edSMarri Devender Rao         // FRU File ID - Empty
2877d9157edSMarri Devender Rao         fruAreaData.emplace_back(typeLengthByteNull);
2887d9157edSMarri Devender Rao 
2897d9157edSMarri Devender Rao         // Empty FRU File ID bytes
2907d9157edSMarri Devender Rao         fruAreaData.emplace_back(recordNotPresent);
2917d9157edSMarri Devender Rao 
2927d9157edSMarri Devender Rao         // End of custom fields
2937d9157edSMarri Devender Rao         fruAreaData.emplace_back(endOfCustomFields);
2947d9157edSMarri Devender Rao 
2957d9157edSMarri Devender Rao         postFormatProcessing(fruAreaData);
2967d9157edSMarri Devender Rao     }
2977d9157edSMarri Devender Rao     return fruAreaData;
2987d9157edSMarri Devender Rao }
2997d9157edSMarri Devender Rao 
3007d9157edSMarri Devender Rao /**
3017d9157edSMarri Devender Rao  * @brief Builds the Product info area data section
3027d9157edSMarri Devender Rao  *
3037d9157edSMarri Devender Rao  * @param[in] propMap map of FRU properties for Board info area
3047d9157edSMarri Devender Rao  * @return FruAreaData container with product info area data
3057d9157edSMarri Devender Rao  */
3067d9157edSMarri Devender Rao FruAreaData buildProductInfoArea(const PropertyMap& propMap)
3077d9157edSMarri Devender Rao {
3087d9157edSMarri Devender Rao     FruAreaData fruAreaData;
3097d9157edSMarri Devender Rao     if (!propMap.empty())
3107d9157edSMarri Devender Rao     {
3117d9157edSMarri Devender Rao         // Set formatting data that goes at the beginning of the record
3127d9157edSMarri Devender Rao         preFormatProcessing(true, fruAreaData);
3137d9157edSMarri Devender Rao 
3147d9157edSMarri Devender Rao         // manufacturer
3157d9157edSMarri Devender Rao         appendData(manufacturer, propMap, fruAreaData);
3167d9157edSMarri Devender Rao 
3177d9157edSMarri Devender Rao         // Product name/Pretty name
3187d9157edSMarri Devender Rao         appendData(prettyName, propMap, fruAreaData);
3197d9157edSMarri Devender Rao 
3207d9157edSMarri Devender Rao         // Product part/model number
3217d9157edSMarri Devender Rao         appendData(model, propMap, fruAreaData);
3227d9157edSMarri Devender Rao 
3237d9157edSMarri Devender Rao         // Product version
3247d9157edSMarri Devender Rao         appendData(version, propMap, fruAreaData);
3257d9157edSMarri Devender Rao 
3267d9157edSMarri Devender Rao         // Serial Number
3277d9157edSMarri Devender Rao         appendData(serialNumber, propMap, fruAreaData);
3287d9157edSMarri Devender Rao 
3297d9157edSMarri Devender Rao         // Add Asset Tag
3307d9157edSMarri Devender Rao         fruAreaData.emplace_back(recordNotPresent);
3317d9157edSMarri Devender Rao 
3327d9157edSMarri Devender Rao         // FRU File ID - Empty
3337d9157edSMarri Devender Rao         fruAreaData.emplace_back(typeLengthByteNull);
3347d9157edSMarri Devender Rao 
3357d9157edSMarri Devender Rao         // Empty FRU File ID bytes
3367d9157edSMarri Devender Rao         fruAreaData.emplace_back(recordNotPresent);
3377d9157edSMarri Devender Rao 
3387d9157edSMarri Devender Rao         // End of custom fields
3397d9157edSMarri Devender Rao         fruAreaData.emplace_back(endOfCustomFields);
3407d9157edSMarri Devender Rao 
3417d9157edSMarri Devender Rao         postFormatProcessing(fruAreaData);
3427d9157edSMarri Devender Rao     }
3437d9157edSMarri Devender Rao     return fruAreaData;
3447d9157edSMarri Devender Rao }
3457d9157edSMarri Devender Rao 
3467d9157edSMarri Devender Rao FruAreaData buildFruAreaData(const FruInventoryData& inventory)
3477d9157edSMarri Devender Rao {
3482f66f00eSRatan Gupta     FruAreaData combFruArea{};
3497d9157edSMarri Devender Rao     // Now build common header with data for this FRU Inv Record
3507d9157edSMarri Devender Rao     // Use this variable to increment size of header as we go along to determine
3517d9157edSMarri Devender Rao     // offset for the subsequent area offsets
3522f66f00eSRatan Gupta     uint16_t curDataOffset = commonHeaderFormatSize;
3537d9157edSMarri Devender Rao     // First byte is id for version of FRU Info Storage Spec used
3547d9157edSMarri Devender Rao     combFruArea.emplace_back(specVersion);
3557d9157edSMarri Devender Rao 
3567d9157edSMarri Devender Rao     // 2nd byte is offset to internal use data
3577d9157edSMarri Devender Rao     combFruArea.emplace_back(recordNotPresent);
3587d9157edSMarri Devender Rao 
3597d9157edSMarri Devender Rao     // 3rd byte is offset to chassis data
3607d9157edSMarri Devender Rao     FruAreaData chassisArea;
3617d9157edSMarri Devender Rao     auto chassisIt = inventory.find(chassis);
3627d9157edSMarri Devender Rao     if (chassisIt != inventory.end())
3637d9157edSMarri Devender Rao     {
3647d9157edSMarri Devender Rao         chassisArea = std::move(buildChassisInfoArea(chassisIt->second));
3657d9157edSMarri Devender Rao     }
3662f66f00eSRatan Gupta     // update the offset to chassis data.
3677d9157edSMarri Devender Rao     buildCommonHeaderSection(chassisArea.size(), curDataOffset, combFruArea);
3687d9157edSMarri Devender Rao 
3697d9157edSMarri Devender Rao     // 4th byte is offset to board data
3707d9157edSMarri Devender Rao     FruAreaData boardArea;
3717d9157edSMarri Devender Rao     auto boardIt = inventory.find(board);
3727d9157edSMarri Devender Rao     if (boardIt != inventory.end())
3737d9157edSMarri Devender Rao     {
3747d9157edSMarri Devender Rao         boardArea = std::move(buildBoardInfoArea(boardIt->second));
3757d9157edSMarri Devender Rao     }
3762f66f00eSRatan Gupta     // update the offset to the board data.
3772f66f00eSRatan Gupta     buildCommonHeaderSection(boardArea.size(), curDataOffset, combFruArea);
3787d9157edSMarri Devender Rao 
3797d9157edSMarri Devender Rao     // 5th byte is offset to product data
3807d9157edSMarri Devender Rao     FruAreaData prodArea;
3817d9157edSMarri Devender Rao     auto prodIt = inventory.find(product);
3827d9157edSMarri Devender Rao     if (prodIt != inventory.end())
3837d9157edSMarri Devender Rao     {
3847d9157edSMarri Devender Rao         prodArea = std::move(buildProductInfoArea(prodIt->second));
3857d9157edSMarri Devender Rao     }
3862f66f00eSRatan Gupta     // update the offset to the product data.
3877d9157edSMarri Devender Rao     buildCommonHeaderSection(prodArea.size(), curDataOffset, combFruArea);
3887d9157edSMarri Devender Rao 
3897d9157edSMarri Devender Rao     // 6th byte is offset to multirecord data
3907d9157edSMarri Devender Rao     combFruArea.emplace_back(recordNotPresent);
3917d9157edSMarri Devender Rao 
3927d9157edSMarri Devender Rao     // 7th byte is PAD
3932f66f00eSRatan Gupta     combFruArea.emplace_back(recordNotPresent);
3947d9157edSMarri Devender Rao 
3957d9157edSMarri Devender Rao     // 8th (Final byte of Header Format) is the checksum
3967d9157edSMarri Devender Rao     appendDataChecksum(combFruArea);
3977d9157edSMarri Devender Rao 
3987d9157edSMarri Devender Rao     // Combine everything into one full IPMI FRU specification Record
3997d9157edSMarri Devender Rao     // add chassis use area data
400*0b02be92SPatrick Venture     combFruArea.insert(combFruArea.end(), chassisArea.begin(),
401*0b02be92SPatrick Venture                        chassisArea.end());
4027d9157edSMarri Devender Rao 
4037d9157edSMarri Devender Rao     // add board area data
4047d9157edSMarri Devender Rao     combFruArea.insert(combFruArea.end(), boardArea.begin(), boardArea.end());
4057d9157edSMarri Devender Rao 
4067d9157edSMarri Devender Rao     // add product use area data
4077d9157edSMarri Devender Rao     combFruArea.insert(combFruArea.end(), prodArea.begin(), prodArea.end());
4087d9157edSMarri Devender Rao 
4097d9157edSMarri Devender Rao     return combFruArea;
4107d9157edSMarri Devender Rao }
4117d9157edSMarri Devender Rao 
412*0b02be92SPatrick Venture } // namespace fru
413*0b02be92SPatrick Venture } // namespace ipmi
414