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