10b02be92SPatrick Venture #include "ipmi_fru_info_area.hpp"
20b02be92SPatrick Venture
3fbc6c9d7SPatrick Williams #include <phosphor-logging/elog.hpp>
4fbc6c9d7SPatrick Williams
57d9157edSMarri Devender Rao #include <algorithm>
60b02be92SPatrick Venture #include <ctime>
724c771c8SPatrick Venture #include <iomanip>
87d9157edSMarri Devender Rao #include <map>
97d9157edSMarri Devender Rao #include <numeric>
1024c771c8SPatrick Venture #include <sstream>
11b51bf9c8SPatrick Venture
127d9157edSMarri Devender Rao namespace ipmi
137d9157edSMarri Devender Rao {
147d9157edSMarri Devender Rao namespace fru
157d9157edSMarri Devender Rao {
167d9157edSMarri Devender Rao using namespace phosphor::logging;
177d9157edSMarri Devender Rao
187d9157edSMarri Devender Rao // Property variables
197d9157edSMarri Devender Rao static constexpr auto partNumber = "Part Number";
207d9157edSMarri Devender Rao static constexpr auto serialNumber = "Serial Number";
217d9157edSMarri Devender Rao static constexpr auto manufacturer = "Manufacturer";
2245e93cbaSPatrick Venture static constexpr auto buildDate = "Mfg Date";
23ecd9f378SWilliam A. Kennington III static constexpr auto modelNumber = "Model Number";
2445e93cbaSPatrick Venture static constexpr auto prettyName = "Name";
257d9157edSMarri Devender Rao static constexpr auto version = "Version";
2640f59e2cSOskar Senft static constexpr auto type = "Type";
277d9157edSMarri Devender Rao
287d9157edSMarri Devender Rao // Board info areas
297d9157edSMarri Devender Rao static constexpr auto board = "Board";
307d9157edSMarri Devender Rao static constexpr auto chassis = "Chassis";
317d9157edSMarri Devender Rao static constexpr auto product = "Product";
327d9157edSMarri Devender Rao
337d9157edSMarri Devender Rao static constexpr auto specVersion = 0x1;
343e6a769bSRatan Gupta static constexpr auto recordUnitOfMeasurement = 0x8; // size in bytes
357d9157edSMarri Devender Rao static constexpr auto checksumSize = 0x1; // size in bytes
367d9157edSMarri Devender Rao static constexpr auto recordNotPresent = 0x0;
377d9157edSMarri Devender Rao static constexpr auto englishLanguageCode = 0x0;
387d9157edSMarri Devender Rao static constexpr auto typeLengthByteNull = 0x0;
397d9157edSMarri Devender Rao static constexpr auto endOfCustomFields = 0xC1;
407d9157edSMarri Devender Rao static constexpr auto commonHeaderFormatSize = 0x8; // size in bytes
417d9157edSMarri Devender Rao static constexpr auto manufacturingDateSize = 0x3;
427d9157edSMarri Devender Rao static constexpr auto areaSizeOffset = 0x1;
436edfc5c1SRatan Gupta static constexpr uint8_t typeASCII = 0xC0;
44e1160cb2SKirill Pakhomov static constexpr auto maxRecordAttributeValue = 0x3F;
457d9157edSMarri Devender Rao
467ebd2464SAndres Oportus static constexpr auto secs_from_1970_1996 = 820454400;
47b898cde6SNagaraju Goruganti static constexpr auto maxMfgDateValue = 0xFFFFFF; // 3 Byte length
487ebd2464SAndres Oportus static constexpr auto secs_per_min = 60;
49fbc6c9d7SPatrick Williams static constexpr auto secsToMaxMfgdate = secs_from_1970_1996 +
50fbc6c9d7SPatrick Williams secs_per_min * maxMfgDateValue;
517ebd2464SAndres Oportus
528b18941dSOskar Senft // Minimum size of resulting FRU blob.
538b18941dSOskar Senft // This is also the theoretical maximum size according to the spec:
548b18941dSOskar Senft // 8 bytes header + 5 areas at 0xff*8 bytes max each
558b18941dSOskar Senft // 8 + 5*0xff*8 = 0x27e0
568b18941dSOskar Senft static constexpr auto fruMinSize = 0x27E0;
578b18941dSOskar Senft
588b18941dSOskar Senft // Value to use for padding.
598b18941dSOskar Senft // Using 0xff to match the default (blank) value in a physical EEPROM.
608b18941dSOskar Senft static constexpr auto fruPadValue = 0xff;
618b18941dSOskar Senft
627d9157edSMarri Devender Rao /**
637d9157edSMarri Devender Rao * @brief Format Beginning of Individual IPMI FRU Data Section
647d9157edSMarri Devender Rao *
657d9157edSMarri Devender Rao * @param[in] langCode Language code
667d9157edSMarri Devender Rao * @param[in/out] data FRU area data
677d9157edSMarri Devender Rao */
preFormatProcessing(bool langCode,FruAreaData & data)687d9157edSMarri Devender Rao void preFormatProcessing(bool langCode, FruAreaData& data)
697d9157edSMarri Devender Rao {
707d9157edSMarri Devender Rao // Add id for version of FRU Info Storage Spec used
717d9157edSMarri Devender Rao data.emplace_back(specVersion);
727d9157edSMarri Devender Rao
737d9157edSMarri Devender Rao // Add Data Size - 0 as a placeholder, can edit after the data is finalized
747d9157edSMarri Devender Rao data.emplace_back(typeLengthByteNull);
757d9157edSMarri Devender Rao
767d9157edSMarri Devender Rao if (langCode)
777d9157edSMarri Devender Rao {
787d9157edSMarri Devender Rao data.emplace_back(englishLanguageCode);
797d9157edSMarri Devender Rao }
807d9157edSMarri Devender Rao }
817d9157edSMarri Devender Rao
827d9157edSMarri Devender Rao /**
837d9157edSMarri Devender Rao * @brief Append checksum of the FRU area data
847d9157edSMarri Devender Rao *
857d9157edSMarri Devender Rao * @param[in/out] data FRU area data
867d9157edSMarri Devender Rao */
appendDataChecksum(FruAreaData & data)877d9157edSMarri Devender Rao void appendDataChecksum(FruAreaData& data)
887d9157edSMarri Devender Rao {
897d9157edSMarri Devender Rao uint8_t checksumVal = std::accumulate(data.begin(), data.end(), 0);
907d9157edSMarri Devender Rao // Push the Zero checksum as the last byte of this data
917d9157edSMarri Devender Rao // This appears to be a simple summation of all the bytes
927d9157edSMarri Devender Rao data.emplace_back(-checksumVal);
937d9157edSMarri Devender Rao }
947d9157edSMarri Devender Rao
957d9157edSMarri Devender Rao /**
967d9157edSMarri Devender Rao * @brief Append padding bytes for the FRU area data
977d9157edSMarri Devender Rao *
987d9157edSMarri Devender Rao * @param[in/out] data FRU area data
997d9157edSMarri Devender Rao */
padData(FruAreaData & data)1007d9157edSMarri Devender Rao void padData(FruAreaData& data)
1017d9157edSMarri Devender Rao {
1023e6a769bSRatan Gupta uint8_t pad = (data.size() + checksumSize) % recordUnitOfMeasurement;
1037d9157edSMarri Devender Rao if (pad)
1047d9157edSMarri Devender Rao {
1053e6a769bSRatan Gupta data.resize((data.size() + recordUnitOfMeasurement - pad));
1067d9157edSMarri Devender Rao }
1077d9157edSMarri Devender Rao }
1087d9157edSMarri Devender Rao
1097d9157edSMarri Devender Rao /**
1107d9157edSMarri Devender Rao * @brief Format End of Individual IPMI FRU Data Section
1117d9157edSMarri Devender Rao *
1127d9157edSMarri Devender Rao * @param[in/out] fruAreaData FRU area info data
1137d9157edSMarri Devender Rao */
postFormatProcessing(FruAreaData & data)1147d9157edSMarri Devender Rao void postFormatProcessing(FruAreaData& data)
1157d9157edSMarri Devender Rao {
1167d9157edSMarri Devender Rao // This area needs to be padded to a multiple of 8 bytes (after checksum)
1177d9157edSMarri Devender Rao padData(data);
1187d9157edSMarri Devender Rao
1197d9157edSMarri Devender Rao // Set size of data info area
120fbc6c9d7SPatrick Williams data.at(areaSizeOffset) = (data.size() + checksumSize) /
121fbc6c9d7SPatrick Williams (recordUnitOfMeasurement);
1227d9157edSMarri Devender Rao
1232f66f00eSRatan Gupta // Finally add area checksum
1247d9157edSMarri Devender Rao appendDataChecksum(data);
1257d9157edSMarri Devender Rao }
1267d9157edSMarri Devender Rao
1277d9157edSMarri Devender Rao /**
12840f59e2cSOskar Senft * @brief Read chassis type property value from inventory and append to the FRU
12940f59e2cSOskar Senft * area data.
13040f59e2cSOskar Senft *
13140f59e2cSOskar Senft * @param[in] propMap map of property values
13240f59e2cSOskar Senft * @param[in,out] data FRU area data to be appended
13340f59e2cSOskar Senft */
appendChassisType(const PropertyMap & propMap,FruAreaData & data)13440f59e2cSOskar Senft void appendChassisType(const PropertyMap& propMap, FruAreaData& data)
13540f59e2cSOskar Senft {
13640f59e2cSOskar Senft uint8_t chassisType = 0; // Not specified
13740f59e2cSOskar Senft auto iter = propMap.find(type);
13840f59e2cSOskar Senft if (iter != propMap.end())
13940f59e2cSOskar Senft {
14040f59e2cSOskar Senft auto value = iter->second;
141cf059392SOskar Senft try
142cf059392SOskar Senft {
14340f59e2cSOskar Senft chassisType = std::stoi(value);
14440f59e2cSOskar Senft }
145a2ad2da8SPatrick Williams catch (const std::exception& e)
146cf059392SOskar Senft {
147cf059392SOskar Senft log<level::ERR>("Could not parse chassis type",
148cf059392SOskar Senft entry("VALUE=%s", value.c_str()),
149cf059392SOskar Senft entry("ERROR=%s", e.what()));
150cf059392SOskar Senft chassisType = 0;
151cf059392SOskar Senft }
152cf059392SOskar Senft }
15340f59e2cSOskar Senft data.emplace_back(chassisType);
15440f59e2cSOskar Senft }
15540f59e2cSOskar Senft
15640f59e2cSOskar Senft /**
1577d9157edSMarri Devender Rao * @brief Read property value from inventory and append to the FRU area data
1587d9157edSMarri Devender Rao *
1597d9157edSMarri Devender Rao * @param[in] key key to search for in the property inventory data
1607d9157edSMarri Devender Rao * @param[in] propMap map of property values
1617d9157edSMarri Devender Rao * @param[in,out] data FRU area data to be appended
1627d9157edSMarri Devender Rao */
appendData(const Property & key,const PropertyMap & propMap,FruAreaData & data)1637d9157edSMarri Devender Rao void appendData(const Property& key, const PropertyMap& propMap,
1647d9157edSMarri Devender Rao FruAreaData& data)
1657d9157edSMarri Devender Rao {
1667d9157edSMarri Devender Rao auto iter = propMap.find(key);
1677d9157edSMarri Devender Rao if (iter != propMap.end())
1687d9157edSMarri Devender Rao {
1697d9157edSMarri Devender Rao auto value = iter->second;
1707d9157edSMarri Devender Rao // If starts with 0x or 0X remove them
1717d9157edSMarri Devender Rao // ex: 0x123a just take 123a
1727d9157edSMarri Devender Rao if ((value.compare(0, 2, "0x")) == 0 ||
1737d9157edSMarri Devender Rao (value.compare(0, 2, "0X") == 0))
1747d9157edSMarri Devender Rao {
1757d9157edSMarri Devender Rao value.erase(0, 2);
1767d9157edSMarri Devender Rao }
1776edfc5c1SRatan Gupta
178e1160cb2SKirill Pakhomov // 6 bits for length as per FRU spec v1.0
179e1160cb2SKirill Pakhomov // if length is greater then 63(2^6) bytes then trim the data to 63
1800b02be92SPatrick Venture // bytess.
1810b02be92SPatrick Venture auto valueLength = (value.length() > maxRecordAttributeValue)
1820b02be92SPatrick Venture ? maxRecordAttributeValue
1830b02be92SPatrick Venture : value.length();
1846edfc5c1SRatan Gupta // 2 bits for type
1856edfc5c1SRatan Gupta // Set the type to ascii
1866edfc5c1SRatan Gupta uint8_t typeLength = valueLength | ipmi::fru::typeASCII;
1876edfc5c1SRatan Gupta
1886edfc5c1SRatan Gupta data.emplace_back(typeLength);
1890b02be92SPatrick Venture std::copy(value.begin(), value.begin() + valueLength,
1906edfc5c1SRatan Gupta std::back_inserter(data));
1917d9157edSMarri Devender Rao }
1927d9157edSMarri Devender Rao else
1937d9157edSMarri Devender Rao {
1947d9157edSMarri Devender Rao // set 0 size
1957d9157edSMarri Devender Rao data.emplace_back(typeLengthByteNull);
1967d9157edSMarri Devender Rao }
1977d9157edSMarri Devender Rao }
1987d9157edSMarri Devender Rao
timeStringToRaw(const std::string & input)19924c771c8SPatrick Venture std::time_t timeStringToRaw(const std::string& input)
20024c771c8SPatrick Venture {
20124c771c8SPatrick Venture // TODO: For non-US region timestamps, pass in region information for the
20224c771c8SPatrick Venture // FRU to avoid the month/day swap.
20324c771c8SPatrick Venture // 2017-02-24 - 13:59:00, Tue Nov 20 23:08:00 2018
20424c771c8SPatrick Venture static const std::vector<std::string> patterns = {"%Y-%m-%d - %H:%M:%S",
20524c771c8SPatrick Venture "%a %b %d %H:%M:%S %Y"};
20624c771c8SPatrick Venture
20724c771c8SPatrick Venture std::tm time = {};
20824c771c8SPatrick Venture
20924c771c8SPatrick Venture for (const auto& pattern : patterns)
21024c771c8SPatrick Venture {
21124c771c8SPatrick Venture std::istringstream timeStream(input);
21224c771c8SPatrick Venture timeStream >> std::get_time(&time, pattern.c_str());
21324c771c8SPatrick Venture if (!timeStream.fail())
21424c771c8SPatrick Venture {
21524c771c8SPatrick Venture break;
21624c771c8SPatrick Venture }
21724c771c8SPatrick Venture }
21824c771c8SPatrick Venture
219*b2411303SWilly Tu return timegm(&time);
22024c771c8SPatrick Venture }
22124c771c8SPatrick Venture
2227d9157edSMarri Devender Rao /**
2237d9157edSMarri Devender Rao * @brief Appends Build Date
2247d9157edSMarri Devender Rao *
2257d9157edSMarri Devender Rao * @param[in] propMap map of property values
2267d9157edSMarri Devender Rao * @param[in/out] data FRU area to add the manfufacture date
2277d9157edSMarri Devender Rao */
appendMfgDate(const PropertyMap & propMap,FruAreaData & data)2287d9157edSMarri Devender Rao void appendMfgDate(const PropertyMap& propMap, FruAreaData& data)
2297d9157edSMarri Devender Rao {
2307d9157edSMarri Devender Rao // MFG Date/Time
2317d9157edSMarri Devender Rao auto iter = propMap.find(buildDate);
232b898cde6SNagaraju Goruganti if ((iter != propMap.end()) && (iter->second.size() > 0))
2337d9157edSMarri Devender Rao {
23424c771c8SPatrick Venture std::time_t raw = timeStringToRaw(iter->second);
2357ebd2464SAndres Oportus
2367ebd2464SAndres Oportus // From FRU Spec:
2377ebd2464SAndres Oportus // "Mfg. Date / Time
2387ebd2464SAndres Oportus // Number of minutes from 0:00 hrs 1/1/96.
2397ebd2464SAndres Oportus // LSbyte first (little endian)
2407ebd2464SAndres Oportus // 00_00_00h = unspecified."
241b898cde6SNagaraju Goruganti if ((raw >= secs_from_1970_1996) && (raw <= secsToMaxMfgdate))
2427d9157edSMarri Devender Rao {
2437ebd2464SAndres Oportus raw -= secs_from_1970_1996;
2447ebd2464SAndres Oportus raw /= secs_per_min;
2457ebd2464SAndres Oportus uint8_t fru_raw[3];
2467ebd2464SAndres Oportus fru_raw[0] = raw & 0xFF;
2477ebd2464SAndres Oportus fru_raw[1] = (raw >> 8) & 0xFF;
2487ebd2464SAndres Oportus fru_raw[2] = (raw >> 16) & 0xFF;
2497ebd2464SAndres Oportus std::copy(fru_raw, fru_raw + 3, std::back_inserter(data));
2507d9157edSMarri Devender Rao return;
2517d9157edSMarri Devender Rao }
252b51bf9c8SPatrick Venture std::fprintf(stderr, "MgfDate invalid date: %u secs since UNIX epoch\n",
2537ebd2464SAndres Oportus static_cast<unsigned int>(raw));
2547d9157edSMarri Devender Rao }
2557d9157edSMarri Devender Rao // Blank date
2567d9157edSMarri Devender Rao data.emplace_back(0);
2577d9157edSMarri Devender Rao data.emplace_back(0);
2587d9157edSMarri Devender Rao data.emplace_back(0);
2597d9157edSMarri Devender Rao }
2607d9157edSMarri Devender Rao
2617d9157edSMarri Devender Rao /**
2627d9157edSMarri Devender Rao * @brief Builds a section of the common header
2637d9157edSMarri Devender Rao *
2647d9157edSMarri Devender Rao * @param[in] infoAreaSize size of the FRU area to write
2657d9157edSMarri Devender Rao * @param[in] offset Current offset for data in overall record
2667d9157edSMarri Devender Rao * @param[in/out] data Common Header section data container
2677d9157edSMarri Devender Rao */
buildCommonHeaderSection(const uint32_t & infoAreaSize,uint16_t & offset,FruAreaData & data)2680b02be92SPatrick Venture void buildCommonHeaderSection(const uint32_t& infoAreaSize, uint16_t& offset,
2690b02be92SPatrick Venture FruAreaData& data)
2707d9157edSMarri Devender Rao {
2717d9157edSMarri Devender Rao // Check if data for internal use section populated
2727d9157edSMarri Devender Rao if (infoAreaSize == 0)
2737d9157edSMarri Devender Rao {
2747d9157edSMarri Devender Rao // Indicate record not present
2757d9157edSMarri Devender Rao data.emplace_back(recordNotPresent);
2767d9157edSMarri Devender Rao }
2777d9157edSMarri Devender Rao else
2787d9157edSMarri Devender Rao {
2792f66f00eSRatan Gupta // offset should be multiple of 8.
2803e6a769bSRatan Gupta auto remainder = offset % recordUnitOfMeasurement;
2812f66f00eSRatan Gupta // add the padding bytes in the offset so that offset
2822f66f00eSRatan Gupta // will be multiple of 8 byte.
2833e6a769bSRatan Gupta offset += (remainder > 0) ? recordUnitOfMeasurement - remainder : 0;
2847d9157edSMarri Devender Rao // Place data to define offset to area data section
2853e6a769bSRatan Gupta data.emplace_back(offset / recordUnitOfMeasurement);
2862f66f00eSRatan Gupta
2877d9157edSMarri Devender Rao offset += infoAreaSize;
2887d9157edSMarri Devender Rao }
2897d9157edSMarri Devender Rao }
2907d9157edSMarri Devender Rao
2917d9157edSMarri Devender Rao /**
2927d9157edSMarri Devender Rao * @brief Builds the Chassis info area data section
2937d9157edSMarri Devender Rao *
2947d9157edSMarri Devender Rao * @param[in] propMap map of properties for chassis info area
2957d9157edSMarri Devender Rao * @return FruAreaData container with chassis info area
2967d9157edSMarri Devender Rao */
buildChassisInfoArea(const PropertyMap & propMap)2977d9157edSMarri Devender Rao FruAreaData buildChassisInfoArea(const PropertyMap& propMap)
2987d9157edSMarri Devender Rao {
2997d9157edSMarri Devender Rao FruAreaData fruAreaData;
3007d9157edSMarri Devender Rao if (!propMap.empty())
3017d9157edSMarri Devender Rao {
3027d9157edSMarri Devender Rao // Set formatting data that goes at the beginning of the record
3037d9157edSMarri Devender Rao preFormatProcessing(false, fruAreaData);
3047d9157edSMarri Devender Rao
3057d9157edSMarri Devender Rao // chassis type
30640f59e2cSOskar Senft appendChassisType(propMap, fruAreaData);
3077d9157edSMarri Devender Rao
3087d9157edSMarri Devender Rao // Chasiss part number, in config.yaml it is configured as model
309ecd9f378SWilliam A. Kennington III appendData(modelNumber, propMap, fruAreaData);
3107d9157edSMarri Devender Rao
3117d9157edSMarri Devender Rao // Board serial number
3127d9157edSMarri Devender Rao appendData(serialNumber, propMap, fruAreaData);
3137d9157edSMarri Devender Rao
3147d9157edSMarri Devender Rao // Indicate End of Custom Fields
3157d9157edSMarri Devender Rao fruAreaData.emplace_back(endOfCustomFields);
3167d9157edSMarri Devender Rao
3177d9157edSMarri Devender Rao // Complete record data formatting
3187d9157edSMarri Devender Rao postFormatProcessing(fruAreaData);
3197d9157edSMarri Devender Rao }
3207d9157edSMarri Devender Rao return fruAreaData;
3217d9157edSMarri Devender Rao }
3227d9157edSMarri Devender Rao
3237d9157edSMarri Devender Rao /**
3247d9157edSMarri Devender Rao * @brief Builds the Board info area data section
3257d9157edSMarri Devender Rao *
3267d9157edSMarri Devender Rao * @param[in] propMap map of properties for board info area
3277d9157edSMarri Devender Rao * @return FruAreaData container with board info area
3287d9157edSMarri Devender Rao */
buildBoardInfoArea(const PropertyMap & propMap)3297d9157edSMarri Devender Rao FruAreaData buildBoardInfoArea(const PropertyMap& propMap)
3307d9157edSMarri Devender Rao {
3317d9157edSMarri Devender Rao FruAreaData fruAreaData;
3327d9157edSMarri Devender Rao if (!propMap.empty())
3337d9157edSMarri Devender Rao {
3347d9157edSMarri Devender Rao preFormatProcessing(true, fruAreaData);
3357d9157edSMarri Devender Rao
3367d9157edSMarri Devender Rao // Manufacturing date
3377d9157edSMarri Devender Rao appendMfgDate(propMap, fruAreaData);
3387d9157edSMarri Devender Rao
3397d9157edSMarri Devender Rao // manufacturer
3407d9157edSMarri Devender Rao appendData(manufacturer, propMap, fruAreaData);
3417d9157edSMarri Devender Rao
3427d9157edSMarri Devender Rao // Product name/Pretty name
3437d9157edSMarri Devender Rao appendData(prettyName, propMap, fruAreaData);
3447d9157edSMarri Devender Rao
3457d9157edSMarri Devender Rao // Board serial number
3467d9157edSMarri Devender Rao appendData(serialNumber, propMap, fruAreaData);
3477d9157edSMarri Devender Rao
3487d9157edSMarri Devender Rao // Board part number
3497d9157edSMarri Devender Rao appendData(partNumber, propMap, fruAreaData);
3507d9157edSMarri Devender Rao
3517d9157edSMarri Devender Rao // FRU File ID - Empty
3527d9157edSMarri Devender Rao fruAreaData.emplace_back(typeLengthByteNull);
3537d9157edSMarri Devender Rao
3547d9157edSMarri Devender Rao // Empty FRU File ID bytes
3557d9157edSMarri Devender Rao fruAreaData.emplace_back(recordNotPresent);
3567d9157edSMarri Devender Rao
3577d9157edSMarri Devender Rao // End of custom fields
3587d9157edSMarri Devender Rao fruAreaData.emplace_back(endOfCustomFields);
3597d9157edSMarri Devender Rao
3607d9157edSMarri Devender Rao postFormatProcessing(fruAreaData);
3617d9157edSMarri Devender Rao }
3627d9157edSMarri Devender Rao return fruAreaData;
3637d9157edSMarri Devender Rao }
3647d9157edSMarri Devender Rao
3657d9157edSMarri Devender Rao /**
3667d9157edSMarri Devender Rao * @brief Builds the Product info area data section
3677d9157edSMarri Devender Rao *
3687d9157edSMarri Devender Rao * @param[in] propMap map of FRU properties for Board info area
3697d9157edSMarri Devender Rao * @return FruAreaData container with product info area data
3707d9157edSMarri Devender Rao */
buildProductInfoArea(const PropertyMap & propMap)3717d9157edSMarri Devender Rao FruAreaData buildProductInfoArea(const PropertyMap& propMap)
3727d9157edSMarri Devender Rao {
3737d9157edSMarri Devender Rao FruAreaData fruAreaData;
3747d9157edSMarri Devender Rao if (!propMap.empty())
3757d9157edSMarri Devender Rao {
3767d9157edSMarri Devender Rao // Set formatting data that goes at the beginning of the record
3777d9157edSMarri Devender Rao preFormatProcessing(true, fruAreaData);
3787d9157edSMarri Devender Rao
3797d9157edSMarri Devender Rao // manufacturer
3807d9157edSMarri Devender Rao appendData(manufacturer, propMap, fruAreaData);
3817d9157edSMarri Devender Rao
3827d9157edSMarri Devender Rao // Product name/Pretty name
3837d9157edSMarri Devender Rao appendData(prettyName, propMap, fruAreaData);
3847d9157edSMarri Devender Rao
3857d9157edSMarri Devender Rao // Product part/model number
386ecd9f378SWilliam A. Kennington III appendData(modelNumber, propMap, fruAreaData);
3877d9157edSMarri Devender Rao
3887d9157edSMarri Devender Rao // Product version
3897d9157edSMarri Devender Rao appendData(version, propMap, fruAreaData);
3907d9157edSMarri Devender Rao
3917d9157edSMarri Devender Rao // Serial Number
3927d9157edSMarri Devender Rao appendData(serialNumber, propMap, fruAreaData);
3937d9157edSMarri Devender Rao
3947d9157edSMarri Devender Rao // Add Asset Tag
3957d9157edSMarri Devender Rao fruAreaData.emplace_back(recordNotPresent);
3967d9157edSMarri Devender Rao
3977d9157edSMarri Devender Rao // FRU File ID - Empty
3987d9157edSMarri Devender Rao fruAreaData.emplace_back(typeLengthByteNull);
3997d9157edSMarri Devender Rao
4007d9157edSMarri Devender Rao // Empty FRU File ID bytes
4017d9157edSMarri Devender Rao fruAreaData.emplace_back(recordNotPresent);
4027d9157edSMarri Devender Rao
4037d9157edSMarri Devender Rao // End of custom fields
4047d9157edSMarri Devender Rao fruAreaData.emplace_back(endOfCustomFields);
4057d9157edSMarri Devender Rao
4067d9157edSMarri Devender Rao postFormatProcessing(fruAreaData);
4077d9157edSMarri Devender Rao }
4087d9157edSMarri Devender Rao return fruAreaData;
4097d9157edSMarri Devender Rao }
4107d9157edSMarri Devender Rao
buildFruAreaData(const FruInventoryData & inventory)4117d9157edSMarri Devender Rao FruAreaData buildFruAreaData(const FruInventoryData& inventory)
4127d9157edSMarri Devender Rao {
4132f66f00eSRatan Gupta FruAreaData combFruArea{};
4147d9157edSMarri Devender Rao // Now build common header with data for this FRU Inv Record
4157d9157edSMarri Devender Rao // Use this variable to increment size of header as we go along to determine
4167d9157edSMarri Devender Rao // offset for the subsequent area offsets
4172f66f00eSRatan Gupta uint16_t curDataOffset = commonHeaderFormatSize;
4187d9157edSMarri Devender Rao // First byte is id for version of FRU Info Storage Spec used
4197d9157edSMarri Devender Rao combFruArea.emplace_back(specVersion);
4207d9157edSMarri Devender Rao
4217d9157edSMarri Devender Rao // 2nd byte is offset to internal use data
4227d9157edSMarri Devender Rao combFruArea.emplace_back(recordNotPresent);
4237d9157edSMarri Devender Rao
4247d9157edSMarri Devender Rao // 3rd byte is offset to chassis data
4257d9157edSMarri Devender Rao FruAreaData chassisArea;
4267d9157edSMarri Devender Rao auto chassisIt = inventory.find(chassis);
4277d9157edSMarri Devender Rao if (chassisIt != inventory.end())
4287d9157edSMarri Devender Rao {
4292e529ee9SPatrick Venture chassisArea = buildChassisInfoArea(chassisIt->second);
4307d9157edSMarri Devender Rao }
4312f66f00eSRatan Gupta // update the offset to chassis data.
4327d9157edSMarri Devender Rao buildCommonHeaderSection(chassisArea.size(), curDataOffset, combFruArea);
4337d9157edSMarri Devender Rao
4347d9157edSMarri Devender Rao // 4th byte is offset to board data
4357d9157edSMarri Devender Rao FruAreaData boardArea;
4367d9157edSMarri Devender Rao auto boardIt = inventory.find(board);
4377d9157edSMarri Devender Rao if (boardIt != inventory.end())
4387d9157edSMarri Devender Rao {
4392e529ee9SPatrick Venture boardArea = buildBoardInfoArea(boardIt->second);
4407d9157edSMarri Devender Rao }
4412f66f00eSRatan Gupta // update the offset to the board data.
4422f66f00eSRatan Gupta buildCommonHeaderSection(boardArea.size(), curDataOffset, combFruArea);
4437d9157edSMarri Devender Rao
4447d9157edSMarri Devender Rao // 5th byte is offset to product data
4457d9157edSMarri Devender Rao FruAreaData prodArea;
4467d9157edSMarri Devender Rao auto prodIt = inventory.find(product);
4477d9157edSMarri Devender Rao if (prodIt != inventory.end())
4487d9157edSMarri Devender Rao {
4492e529ee9SPatrick Venture prodArea = buildProductInfoArea(prodIt->second);
4507d9157edSMarri Devender Rao }
4512f66f00eSRatan Gupta // update the offset to the product data.
4527d9157edSMarri Devender Rao buildCommonHeaderSection(prodArea.size(), curDataOffset, combFruArea);
4537d9157edSMarri Devender Rao
4547d9157edSMarri Devender Rao // 6th byte is offset to multirecord data
4557d9157edSMarri Devender Rao combFruArea.emplace_back(recordNotPresent);
4567d9157edSMarri Devender Rao
4577d9157edSMarri Devender Rao // 7th byte is PAD
4582f66f00eSRatan Gupta combFruArea.emplace_back(recordNotPresent);
4597d9157edSMarri Devender Rao
4607d9157edSMarri Devender Rao // 8th (Final byte of Header Format) is the checksum
4617d9157edSMarri Devender Rao appendDataChecksum(combFruArea);
4627d9157edSMarri Devender Rao
4637d9157edSMarri Devender Rao // Combine everything into one full IPMI FRU specification Record
4647d9157edSMarri Devender Rao // add chassis use area data
4650b02be92SPatrick Venture combFruArea.insert(combFruArea.end(), chassisArea.begin(),
4660b02be92SPatrick Venture chassisArea.end());
4677d9157edSMarri Devender Rao
4687d9157edSMarri Devender Rao // add board area data
4697d9157edSMarri Devender Rao combFruArea.insert(combFruArea.end(), boardArea.begin(), boardArea.end());
4707d9157edSMarri Devender Rao
4717d9157edSMarri Devender Rao // add product use area data
4727d9157edSMarri Devender Rao combFruArea.insert(combFruArea.end(), prodArea.begin(), prodArea.end());
4737d9157edSMarri Devender Rao
4748b18941dSOskar Senft // If area is smaller than the minimum size, pad it. This enables ipmitool
4758b18941dSOskar Senft // to update the FRU blob with values longer than the original payload.
4768b18941dSOskar Senft if (combFruArea.size() < fruMinSize)
4778b18941dSOskar Senft {
4788b18941dSOskar Senft combFruArea.resize(fruMinSize, fruPadValue);
4798b18941dSOskar Senft }
4808b18941dSOskar Senft
4817d9157edSMarri Devender Rao return combFruArea;
4827d9157edSMarri Devender Rao }
4837d9157edSMarri Devender Rao
4840b02be92SPatrick Venture } // namespace fru
4850b02be92SPatrick Venture } // namespace ipmi
486