10b02be92SPatrick Venture #include "ipmi_fru_info_area.hpp" 20b02be92SPatrick Venture 37d9157edSMarri Devender Rao #include <algorithm> 40b02be92SPatrick Venture #include <ctime> 57d9157edSMarri Devender Rao #include <map> 67d9157edSMarri Devender Rao #include <numeric> 77d9157edSMarri Devender Rao #include <phosphor-logging/elog.hpp> 8b51bf9c8SPatrick Venture 97d9157edSMarri Devender Rao namespace ipmi 107d9157edSMarri Devender Rao { 117d9157edSMarri Devender Rao namespace fru 127d9157edSMarri Devender Rao { 137d9157edSMarri Devender Rao using namespace phosphor::logging; 147d9157edSMarri Devender Rao 157d9157edSMarri Devender Rao // Property variables 167d9157edSMarri Devender Rao static constexpr auto partNumber = "PartNumber"; 177d9157edSMarri Devender Rao static constexpr auto serialNumber = "SerialNumber"; 187d9157edSMarri Devender Rao static constexpr auto manufacturer = "Manufacturer"; 197d9157edSMarri Devender Rao static constexpr auto buildDate = "BuildDate"; 207d9157edSMarri Devender Rao static constexpr auto model = "Model"; 217d9157edSMarri Devender Rao static constexpr auto prettyName = "PrettyName"; 227d9157edSMarri Devender Rao static constexpr auto version = "Version"; 2340f59e2cSOskar Senft static constexpr auto type = "Type"; 247d9157edSMarri Devender Rao 257d9157edSMarri Devender Rao // Board info areas 267d9157edSMarri Devender Rao static constexpr auto board = "Board"; 277d9157edSMarri Devender Rao static constexpr auto chassis = "Chassis"; 287d9157edSMarri Devender Rao static constexpr auto product = "Product"; 297d9157edSMarri Devender Rao 307d9157edSMarri Devender Rao static constexpr auto specVersion = 0x1; 313e6a769bSRatan Gupta static constexpr auto recordUnitOfMeasurement = 0x8; // size in bytes 327d9157edSMarri Devender Rao static constexpr auto checksumSize = 0x1; // size in bytes 337d9157edSMarri Devender Rao static constexpr auto recordNotPresent = 0x0; 347d9157edSMarri Devender Rao static constexpr auto englishLanguageCode = 0x0; 357d9157edSMarri Devender Rao static constexpr auto typeLengthByteNull = 0x0; 367d9157edSMarri Devender Rao static constexpr auto endOfCustomFields = 0xC1; 377d9157edSMarri Devender Rao static constexpr auto commonHeaderFormatSize = 0x8; // size in bytes 387d9157edSMarri Devender Rao static constexpr auto manufacturingDateSize = 0x3; 397d9157edSMarri Devender Rao static constexpr auto areaSizeOffset = 0x1; 406edfc5c1SRatan Gupta static constexpr uint8_t typeASCII = 0xC0; 416edfc5c1SRatan Gupta static constexpr auto maxRecordAttributeValue = 0x1F; 427d9157edSMarri Devender Rao 437ebd2464SAndres Oportus static constexpr auto secs_from_1970_1996 = 820454400; 44b898cde6SNagaraju Goruganti static constexpr auto maxMfgDateValue = 0xFFFFFF; // 3 Byte length 457ebd2464SAndres Oportus static constexpr auto secs_per_min = 60; 460b02be92SPatrick Venture static constexpr auto secsToMaxMfgdate = 470b02be92SPatrick Venture secs_from_1970_1996 + secs_per_min * maxMfgDateValue; 487ebd2464SAndres Oportus 498b18941dSOskar Senft // Minimum size of resulting FRU blob. 508b18941dSOskar Senft // This is also the theoretical maximum size according to the spec: 518b18941dSOskar Senft // 8 bytes header + 5 areas at 0xff*8 bytes max each 528b18941dSOskar Senft // 8 + 5*0xff*8 = 0x27e0 538b18941dSOskar Senft static constexpr auto fruMinSize = 0x27E0; 548b18941dSOskar Senft 558b18941dSOskar Senft // Value to use for padding. 568b18941dSOskar Senft // Using 0xff to match the default (blank) value in a physical EEPROM. 578b18941dSOskar Senft static constexpr auto fruPadValue = 0xff; 588b18941dSOskar Senft 597d9157edSMarri Devender Rao /** 607d9157edSMarri Devender Rao * @brief Format Beginning of Individual IPMI FRU Data Section 617d9157edSMarri Devender Rao * 627d9157edSMarri Devender Rao * @param[in] langCode Language code 637d9157edSMarri Devender Rao * @param[in/out] data FRU area data 647d9157edSMarri Devender Rao */ 657d9157edSMarri Devender Rao void preFormatProcessing(bool langCode, FruAreaData& data) 667d9157edSMarri Devender Rao { 677d9157edSMarri Devender Rao // Add id for version of FRU Info Storage Spec used 687d9157edSMarri Devender Rao data.emplace_back(specVersion); 697d9157edSMarri Devender Rao 707d9157edSMarri Devender Rao // Add Data Size - 0 as a placeholder, can edit after the data is finalized 717d9157edSMarri Devender Rao data.emplace_back(typeLengthByteNull); 727d9157edSMarri Devender Rao 737d9157edSMarri Devender Rao if (langCode) 747d9157edSMarri Devender Rao { 757d9157edSMarri Devender Rao data.emplace_back(englishLanguageCode); 767d9157edSMarri Devender Rao } 777d9157edSMarri Devender Rao } 787d9157edSMarri Devender Rao 797d9157edSMarri Devender Rao /** 807d9157edSMarri Devender Rao * @brief Append checksum of the FRU area data 817d9157edSMarri Devender Rao * 827d9157edSMarri Devender Rao * @param[in/out] data FRU area data 837d9157edSMarri Devender Rao */ 847d9157edSMarri Devender Rao void appendDataChecksum(FruAreaData& data) 857d9157edSMarri Devender Rao { 867d9157edSMarri Devender Rao uint8_t checksumVal = std::accumulate(data.begin(), data.end(), 0); 877d9157edSMarri Devender Rao // Push the Zero checksum as the last byte of this data 887d9157edSMarri Devender Rao // This appears to be a simple summation of all the bytes 897d9157edSMarri Devender Rao data.emplace_back(-checksumVal); 907d9157edSMarri Devender Rao } 917d9157edSMarri Devender Rao 927d9157edSMarri Devender Rao /** 937d9157edSMarri Devender Rao * @brief Append padding bytes for the FRU area data 947d9157edSMarri Devender Rao * 957d9157edSMarri Devender Rao * @param[in/out] data FRU area data 967d9157edSMarri Devender Rao */ 977d9157edSMarri Devender Rao void padData(FruAreaData& data) 987d9157edSMarri Devender Rao { 993e6a769bSRatan Gupta uint8_t pad = (data.size() + checksumSize) % recordUnitOfMeasurement; 1007d9157edSMarri Devender Rao if (pad) 1017d9157edSMarri Devender Rao { 1023e6a769bSRatan Gupta data.resize((data.size() + recordUnitOfMeasurement - pad)); 1037d9157edSMarri Devender Rao } 1047d9157edSMarri Devender Rao } 1057d9157edSMarri Devender Rao 1067d9157edSMarri Devender Rao /** 1077d9157edSMarri Devender Rao * @brief Format End of Individual IPMI FRU Data Section 1087d9157edSMarri Devender Rao * 1097d9157edSMarri Devender Rao * @param[in/out] fruAreaData FRU area info data 1107d9157edSMarri Devender Rao */ 1117d9157edSMarri Devender Rao void postFormatProcessing(FruAreaData& data) 1127d9157edSMarri Devender Rao { 1137d9157edSMarri Devender Rao // This area needs to be padded to a multiple of 8 bytes (after checksum) 1147d9157edSMarri Devender Rao padData(data); 1157d9157edSMarri Devender Rao 1167d9157edSMarri Devender Rao // Set size of data info area 1170b02be92SPatrick Venture data.at(areaSizeOffset) = 1180b02be92SPatrick Venture (data.size() + checksumSize) / (recordUnitOfMeasurement); 1197d9157edSMarri Devender Rao 1202f66f00eSRatan Gupta // Finally add area checksum 1217d9157edSMarri Devender Rao appendDataChecksum(data); 1227d9157edSMarri Devender Rao } 1237d9157edSMarri Devender Rao 1247d9157edSMarri Devender Rao /** 12540f59e2cSOskar Senft * @brief Read chassis type property value from inventory and append to the FRU 12640f59e2cSOskar Senft * area data. 12740f59e2cSOskar Senft * 12840f59e2cSOskar Senft * @param[in] propMap map of property values 12940f59e2cSOskar Senft * @param[in,out] data FRU area data to be appended 13040f59e2cSOskar Senft */ 13140f59e2cSOskar Senft void appendChassisType(const PropertyMap& propMap, FruAreaData& data) 13240f59e2cSOskar Senft { 13340f59e2cSOskar Senft uint8_t chassisType = 0; // Not specified 13440f59e2cSOskar Senft auto iter = propMap.find(type); 13540f59e2cSOskar Senft if (iter != propMap.end()) 13640f59e2cSOskar Senft { 13740f59e2cSOskar Senft auto value = iter->second; 138*cf059392SOskar Senft try 139*cf059392SOskar Senft { 14040f59e2cSOskar Senft chassisType = std::stoi(value); 14140f59e2cSOskar Senft } 142*cf059392SOskar Senft catch (std::exception& e) 143*cf059392SOskar Senft { 144*cf059392SOskar Senft log<level::ERR>("Could not parse chassis type", 145*cf059392SOskar Senft entry("VALUE=%s", value.c_str()), 146*cf059392SOskar Senft entry("ERROR=%s", e.what())); 147*cf059392SOskar Senft chassisType = 0; 148*cf059392SOskar Senft } 149*cf059392SOskar Senft } 15040f59e2cSOskar Senft data.emplace_back(chassisType); 15140f59e2cSOskar Senft } 15240f59e2cSOskar Senft 15340f59e2cSOskar Senft /** 1547d9157edSMarri Devender Rao * @brief Read property value from inventory and append to the FRU area data 1557d9157edSMarri Devender Rao * 1567d9157edSMarri Devender Rao * @param[in] key key to search for in the property inventory data 1577d9157edSMarri Devender Rao * @param[in] propMap map of property values 1587d9157edSMarri Devender Rao * @param[in,out] data FRU area data to be appended 1597d9157edSMarri Devender Rao */ 1607d9157edSMarri Devender Rao void appendData(const Property& key, const PropertyMap& propMap, 1617d9157edSMarri Devender Rao FruAreaData& data) 1627d9157edSMarri Devender Rao { 1637d9157edSMarri Devender Rao auto iter = propMap.find(key); 1647d9157edSMarri Devender Rao if (iter != propMap.end()) 1657d9157edSMarri Devender Rao { 1667d9157edSMarri Devender Rao auto value = iter->second; 1677d9157edSMarri Devender Rao // If starts with 0x or 0X remove them 1687d9157edSMarri Devender Rao // ex: 0x123a just take 123a 1697d9157edSMarri Devender Rao if ((value.compare(0, 2, "0x")) == 0 || 1707d9157edSMarri Devender Rao (value.compare(0, 2, "0X") == 0)) 1717d9157edSMarri Devender Rao { 1727d9157edSMarri Devender Rao value.erase(0, 2); 1737d9157edSMarri Devender Rao } 1746edfc5c1SRatan Gupta 1756edfc5c1SRatan Gupta // 5 bits for length 1760b02be92SPatrick Venture // if length is greater then 31(2^5) bytes then trim the data to 31 1770b02be92SPatrick Venture // bytess. 1780b02be92SPatrick Venture auto valueLength = (value.length() > maxRecordAttributeValue) 1790b02be92SPatrick Venture ? maxRecordAttributeValue 1800b02be92SPatrick Venture : value.length(); 1816edfc5c1SRatan Gupta // 2 bits for type 1826edfc5c1SRatan Gupta // Set the type to ascii 1836edfc5c1SRatan Gupta uint8_t typeLength = valueLength | ipmi::fru::typeASCII; 1846edfc5c1SRatan Gupta 1856edfc5c1SRatan Gupta data.emplace_back(typeLength); 1860b02be92SPatrick Venture std::copy(value.begin(), value.begin() + valueLength, 1876edfc5c1SRatan Gupta std::back_inserter(data)); 1887d9157edSMarri Devender Rao } 1897d9157edSMarri Devender Rao else 1907d9157edSMarri Devender Rao { 1917d9157edSMarri Devender Rao // set 0 size 1927d9157edSMarri Devender Rao data.emplace_back(typeLengthByteNull); 1937d9157edSMarri Devender Rao } 1947d9157edSMarri Devender Rao } 1957d9157edSMarri Devender Rao 1967d9157edSMarri Devender Rao /** 1977d9157edSMarri Devender Rao * @brief Appends Build Date 1987d9157edSMarri Devender Rao * 1997d9157edSMarri Devender Rao * @param[in] propMap map of property values 2007d9157edSMarri Devender Rao * @param[in/out] data FRU area to add the manfufacture date 2017d9157edSMarri Devender Rao */ 2027d9157edSMarri Devender Rao void appendMfgDate(const PropertyMap& propMap, FruAreaData& data) 2037d9157edSMarri Devender Rao { 2047d9157edSMarri Devender Rao // MFG Date/Time 2057d9157edSMarri Devender Rao auto iter = propMap.find(buildDate); 206b898cde6SNagaraju Goruganti if ((iter != propMap.end()) && (iter->second.size() > 0)) 2077d9157edSMarri Devender Rao { 2087ebd2464SAndres Oportus tm time = {}; 2097ebd2464SAndres Oportus strptime(iter->second.c_str(), "%F - %H:%M:%S", &time); 2107ebd2464SAndres Oportus time_t raw = mktime(&time); 2117ebd2464SAndres Oportus 2127ebd2464SAndres Oportus // From FRU Spec: 2137ebd2464SAndres Oportus // "Mfg. Date / Time 2147ebd2464SAndres Oportus // Number of minutes from 0:00 hrs 1/1/96. 2157ebd2464SAndres Oportus // LSbyte first (little endian) 2167ebd2464SAndres Oportus // 00_00_00h = unspecified." 217b898cde6SNagaraju Goruganti if ((raw >= secs_from_1970_1996) && (raw <= secsToMaxMfgdate)) 2187d9157edSMarri Devender Rao { 2197ebd2464SAndres Oportus raw -= secs_from_1970_1996; 2207ebd2464SAndres Oportus raw /= secs_per_min; 2217ebd2464SAndres Oportus uint8_t fru_raw[3]; 2227ebd2464SAndres Oportus fru_raw[0] = raw & 0xFF; 2237ebd2464SAndres Oportus fru_raw[1] = (raw >> 8) & 0xFF; 2247ebd2464SAndres Oportus fru_raw[2] = (raw >> 16) & 0xFF; 2257ebd2464SAndres Oportus std::copy(fru_raw, fru_raw + 3, std::back_inserter(data)); 2267d9157edSMarri Devender Rao return; 2277d9157edSMarri Devender Rao } 228b51bf9c8SPatrick Venture std::fprintf(stderr, "MgfDate invalid date: %u secs since UNIX epoch\n", 2297ebd2464SAndres Oportus static_cast<unsigned int>(raw)); 2307d9157edSMarri Devender Rao } 2317d9157edSMarri Devender Rao // Blank date 2327d9157edSMarri Devender Rao data.emplace_back(0); 2337d9157edSMarri Devender Rao data.emplace_back(0); 2347d9157edSMarri Devender Rao data.emplace_back(0); 2357d9157edSMarri Devender Rao } 2367d9157edSMarri Devender Rao 2377d9157edSMarri Devender Rao /** 2387d9157edSMarri Devender Rao * @brief Builds a section of the common header 2397d9157edSMarri Devender Rao * 2407d9157edSMarri Devender Rao * @param[in] infoAreaSize size of the FRU area to write 2417d9157edSMarri Devender Rao * @param[in] offset Current offset for data in overall record 2427d9157edSMarri Devender Rao * @param[in/out] data Common Header section data container 2437d9157edSMarri Devender Rao */ 2440b02be92SPatrick Venture void buildCommonHeaderSection(const uint32_t& infoAreaSize, uint16_t& offset, 2450b02be92SPatrick Venture FruAreaData& data) 2467d9157edSMarri Devender Rao { 2477d9157edSMarri Devender Rao // Check if data for internal use section populated 2487d9157edSMarri Devender Rao if (infoAreaSize == 0) 2497d9157edSMarri Devender Rao { 2507d9157edSMarri Devender Rao // Indicate record not present 2517d9157edSMarri Devender Rao data.emplace_back(recordNotPresent); 2527d9157edSMarri Devender Rao } 2537d9157edSMarri Devender Rao else 2547d9157edSMarri Devender Rao { 2552f66f00eSRatan Gupta // offset should be multiple of 8. 2563e6a769bSRatan Gupta auto remainder = offset % recordUnitOfMeasurement; 2572f66f00eSRatan Gupta // add the padding bytes in the offset so that offset 2582f66f00eSRatan Gupta // will be multiple of 8 byte. 2593e6a769bSRatan Gupta offset += (remainder > 0) ? recordUnitOfMeasurement - remainder : 0; 2607d9157edSMarri Devender Rao // Place data to define offset to area data section 2613e6a769bSRatan Gupta data.emplace_back(offset / recordUnitOfMeasurement); 2622f66f00eSRatan Gupta 2637d9157edSMarri Devender Rao offset += infoAreaSize; 2647d9157edSMarri Devender Rao } 2657d9157edSMarri Devender Rao } 2667d9157edSMarri Devender Rao 2677d9157edSMarri Devender Rao /** 2687d9157edSMarri Devender Rao * @brief Builds the Chassis info area data section 2697d9157edSMarri Devender Rao * 2707d9157edSMarri Devender Rao * @param[in] propMap map of properties for chassis info area 2717d9157edSMarri Devender Rao * @return FruAreaData container with chassis info area 2727d9157edSMarri Devender Rao */ 2737d9157edSMarri Devender Rao FruAreaData buildChassisInfoArea(const PropertyMap& propMap) 2747d9157edSMarri Devender Rao { 2757d9157edSMarri Devender Rao FruAreaData fruAreaData; 2767d9157edSMarri Devender Rao if (!propMap.empty()) 2777d9157edSMarri Devender Rao { 2787d9157edSMarri Devender Rao // Set formatting data that goes at the beginning of the record 2797d9157edSMarri Devender Rao preFormatProcessing(false, fruAreaData); 2807d9157edSMarri Devender Rao 2817d9157edSMarri Devender Rao // chassis type 28240f59e2cSOskar Senft appendChassisType(propMap, fruAreaData); 2837d9157edSMarri Devender Rao 2847d9157edSMarri Devender Rao // Chasiss part number, in config.yaml it is configured as model 2857d9157edSMarri Devender Rao appendData(model, propMap, fruAreaData); 2867d9157edSMarri Devender Rao 2877d9157edSMarri Devender Rao // Board serial number 2887d9157edSMarri Devender Rao appendData(serialNumber, propMap, fruAreaData); 2897d9157edSMarri Devender Rao 2907d9157edSMarri Devender Rao // Indicate End of Custom Fields 2917d9157edSMarri Devender Rao fruAreaData.emplace_back(endOfCustomFields); 2927d9157edSMarri Devender Rao 2937d9157edSMarri Devender Rao // Complete record data formatting 2947d9157edSMarri Devender Rao postFormatProcessing(fruAreaData); 2957d9157edSMarri Devender Rao } 2967d9157edSMarri Devender Rao return fruAreaData; 2977d9157edSMarri Devender Rao } 2987d9157edSMarri Devender Rao 2997d9157edSMarri Devender Rao /** 3007d9157edSMarri Devender Rao * @brief Builds the Board info area data section 3017d9157edSMarri Devender Rao * 3027d9157edSMarri Devender Rao * @param[in] propMap map of properties for board info area 3037d9157edSMarri Devender Rao * @return FruAreaData container with board info area 3047d9157edSMarri Devender Rao */ 3057d9157edSMarri Devender Rao FruAreaData buildBoardInfoArea(const PropertyMap& propMap) 3067d9157edSMarri Devender Rao { 3077d9157edSMarri Devender Rao FruAreaData fruAreaData; 3087d9157edSMarri Devender Rao if (!propMap.empty()) 3097d9157edSMarri Devender Rao { 3107d9157edSMarri Devender Rao preFormatProcessing(true, fruAreaData); 3117d9157edSMarri Devender Rao 3127d9157edSMarri Devender Rao // Manufacturing date 3137d9157edSMarri Devender Rao appendMfgDate(propMap, fruAreaData); 3147d9157edSMarri Devender Rao 3157d9157edSMarri Devender Rao // manufacturer 3167d9157edSMarri Devender Rao appendData(manufacturer, propMap, fruAreaData); 3177d9157edSMarri Devender Rao 3187d9157edSMarri Devender Rao // Product name/Pretty name 3197d9157edSMarri Devender Rao appendData(prettyName, propMap, fruAreaData); 3207d9157edSMarri Devender Rao 3217d9157edSMarri Devender Rao // Board serial number 3227d9157edSMarri Devender Rao appendData(serialNumber, propMap, fruAreaData); 3237d9157edSMarri Devender Rao 3247d9157edSMarri Devender Rao // Board part number 3257d9157edSMarri Devender Rao appendData(partNumber, propMap, fruAreaData); 3267d9157edSMarri Devender Rao 3277d9157edSMarri Devender Rao // FRU File ID - Empty 3287d9157edSMarri Devender Rao fruAreaData.emplace_back(typeLengthByteNull); 3297d9157edSMarri Devender Rao 3307d9157edSMarri Devender Rao // Empty FRU File ID bytes 3317d9157edSMarri Devender Rao fruAreaData.emplace_back(recordNotPresent); 3327d9157edSMarri Devender Rao 3337d9157edSMarri Devender Rao // End of custom fields 3347d9157edSMarri Devender Rao fruAreaData.emplace_back(endOfCustomFields); 3357d9157edSMarri Devender Rao 3367d9157edSMarri Devender Rao postFormatProcessing(fruAreaData); 3377d9157edSMarri Devender Rao } 3387d9157edSMarri Devender Rao return fruAreaData; 3397d9157edSMarri Devender Rao } 3407d9157edSMarri Devender Rao 3417d9157edSMarri Devender Rao /** 3427d9157edSMarri Devender Rao * @brief Builds the Product info area data section 3437d9157edSMarri Devender Rao * 3447d9157edSMarri Devender Rao * @param[in] propMap map of FRU properties for Board info area 3457d9157edSMarri Devender Rao * @return FruAreaData container with product info area data 3467d9157edSMarri Devender Rao */ 3477d9157edSMarri Devender Rao FruAreaData buildProductInfoArea(const PropertyMap& propMap) 3487d9157edSMarri Devender Rao { 3497d9157edSMarri Devender Rao FruAreaData fruAreaData; 3507d9157edSMarri Devender Rao if (!propMap.empty()) 3517d9157edSMarri Devender Rao { 3527d9157edSMarri Devender Rao // Set formatting data that goes at the beginning of the record 3537d9157edSMarri Devender Rao preFormatProcessing(true, fruAreaData); 3547d9157edSMarri Devender Rao 3557d9157edSMarri Devender Rao // manufacturer 3567d9157edSMarri Devender Rao appendData(manufacturer, propMap, fruAreaData); 3577d9157edSMarri Devender Rao 3587d9157edSMarri Devender Rao // Product name/Pretty name 3597d9157edSMarri Devender Rao appendData(prettyName, propMap, fruAreaData); 3607d9157edSMarri Devender Rao 3617d9157edSMarri Devender Rao // Product part/model number 3627d9157edSMarri Devender Rao appendData(model, propMap, fruAreaData); 3637d9157edSMarri Devender Rao 3647d9157edSMarri Devender Rao // Product version 3657d9157edSMarri Devender Rao appendData(version, propMap, fruAreaData); 3667d9157edSMarri Devender Rao 3677d9157edSMarri Devender Rao // Serial Number 3687d9157edSMarri Devender Rao appendData(serialNumber, propMap, fruAreaData); 3697d9157edSMarri Devender Rao 3707d9157edSMarri Devender Rao // Add Asset Tag 3717d9157edSMarri Devender Rao fruAreaData.emplace_back(recordNotPresent); 3727d9157edSMarri Devender Rao 3737d9157edSMarri Devender Rao // FRU File ID - Empty 3747d9157edSMarri Devender Rao fruAreaData.emplace_back(typeLengthByteNull); 3757d9157edSMarri Devender Rao 3767d9157edSMarri Devender Rao // Empty FRU File ID bytes 3777d9157edSMarri Devender Rao fruAreaData.emplace_back(recordNotPresent); 3787d9157edSMarri Devender Rao 3797d9157edSMarri Devender Rao // End of custom fields 3807d9157edSMarri Devender Rao fruAreaData.emplace_back(endOfCustomFields); 3817d9157edSMarri Devender Rao 3827d9157edSMarri Devender Rao postFormatProcessing(fruAreaData); 3837d9157edSMarri Devender Rao } 3847d9157edSMarri Devender Rao return fruAreaData; 3857d9157edSMarri Devender Rao } 3867d9157edSMarri Devender Rao 3877d9157edSMarri Devender Rao FruAreaData buildFruAreaData(const FruInventoryData& inventory) 3887d9157edSMarri Devender Rao { 3892f66f00eSRatan Gupta FruAreaData combFruArea{}; 3907d9157edSMarri Devender Rao // Now build common header with data for this FRU Inv Record 3917d9157edSMarri Devender Rao // Use this variable to increment size of header as we go along to determine 3927d9157edSMarri Devender Rao // offset for the subsequent area offsets 3932f66f00eSRatan Gupta uint16_t curDataOffset = commonHeaderFormatSize; 3947d9157edSMarri Devender Rao // First byte is id for version of FRU Info Storage Spec used 3957d9157edSMarri Devender Rao combFruArea.emplace_back(specVersion); 3967d9157edSMarri Devender Rao 3977d9157edSMarri Devender Rao // 2nd byte is offset to internal use data 3987d9157edSMarri Devender Rao combFruArea.emplace_back(recordNotPresent); 3997d9157edSMarri Devender Rao 4007d9157edSMarri Devender Rao // 3rd byte is offset to chassis data 4017d9157edSMarri Devender Rao FruAreaData chassisArea; 4027d9157edSMarri Devender Rao auto chassisIt = inventory.find(chassis); 4037d9157edSMarri Devender Rao if (chassisIt != inventory.end()) 4047d9157edSMarri Devender Rao { 4057d9157edSMarri Devender Rao chassisArea = std::move(buildChassisInfoArea(chassisIt->second)); 4067d9157edSMarri Devender Rao } 4072f66f00eSRatan Gupta // update the offset to chassis data. 4087d9157edSMarri Devender Rao buildCommonHeaderSection(chassisArea.size(), curDataOffset, combFruArea); 4097d9157edSMarri Devender Rao 4107d9157edSMarri Devender Rao // 4th byte is offset to board data 4117d9157edSMarri Devender Rao FruAreaData boardArea; 4127d9157edSMarri Devender Rao auto boardIt = inventory.find(board); 4137d9157edSMarri Devender Rao if (boardIt != inventory.end()) 4147d9157edSMarri Devender Rao { 4157d9157edSMarri Devender Rao boardArea = std::move(buildBoardInfoArea(boardIt->second)); 4167d9157edSMarri Devender Rao } 4172f66f00eSRatan Gupta // update the offset to the board data. 4182f66f00eSRatan Gupta buildCommonHeaderSection(boardArea.size(), curDataOffset, combFruArea); 4197d9157edSMarri Devender Rao 4207d9157edSMarri Devender Rao // 5th byte is offset to product data 4217d9157edSMarri Devender Rao FruAreaData prodArea; 4227d9157edSMarri Devender Rao auto prodIt = inventory.find(product); 4237d9157edSMarri Devender Rao if (prodIt != inventory.end()) 4247d9157edSMarri Devender Rao { 4257d9157edSMarri Devender Rao prodArea = std::move(buildProductInfoArea(prodIt->second)); 4267d9157edSMarri Devender Rao } 4272f66f00eSRatan Gupta // update the offset to the product data. 4287d9157edSMarri Devender Rao buildCommonHeaderSection(prodArea.size(), curDataOffset, combFruArea); 4297d9157edSMarri Devender Rao 4307d9157edSMarri Devender Rao // 6th byte is offset to multirecord data 4317d9157edSMarri Devender Rao combFruArea.emplace_back(recordNotPresent); 4327d9157edSMarri Devender Rao 4337d9157edSMarri Devender Rao // 7th byte is PAD 4342f66f00eSRatan Gupta combFruArea.emplace_back(recordNotPresent); 4357d9157edSMarri Devender Rao 4367d9157edSMarri Devender Rao // 8th (Final byte of Header Format) is the checksum 4377d9157edSMarri Devender Rao appendDataChecksum(combFruArea); 4387d9157edSMarri Devender Rao 4397d9157edSMarri Devender Rao // Combine everything into one full IPMI FRU specification Record 4407d9157edSMarri Devender Rao // add chassis use area data 4410b02be92SPatrick Venture combFruArea.insert(combFruArea.end(), chassisArea.begin(), 4420b02be92SPatrick Venture chassisArea.end()); 4437d9157edSMarri Devender Rao 4447d9157edSMarri Devender Rao // add board area data 4457d9157edSMarri Devender Rao combFruArea.insert(combFruArea.end(), boardArea.begin(), boardArea.end()); 4467d9157edSMarri Devender Rao 4477d9157edSMarri Devender Rao // add product use area data 4487d9157edSMarri Devender Rao combFruArea.insert(combFruArea.end(), prodArea.begin(), prodArea.end()); 4497d9157edSMarri Devender Rao 4508b18941dSOskar Senft // If area is smaller than the minimum size, pad it. This enables ipmitool 4518b18941dSOskar Senft // to update the FRU blob with values longer than the original payload. 4528b18941dSOskar Senft if (combFruArea.size() < fruMinSize) 4538b18941dSOskar Senft { 4548b18941dSOskar Senft combFruArea.resize(fruMinSize, fruPadValue); 4558b18941dSOskar Senft } 4568b18941dSOskar Senft 4577d9157edSMarri Devender Rao return combFruArea; 4587d9157edSMarri Devender Rao } 4597d9157edSMarri Devender Rao 4600b02be92SPatrick Venture } // namespace fru 4610b02be92SPatrick Venture } // namespace ipmi 462