diff options
author | Marri Devender Rao <devenrao@in.ibm.com> | 2017-07-01 16:11:40 -0500 |
---|---|---|
committer | Patrick Williams <patrick@stwcx.xyz> | 2017-07-25 21:03:36 +0000 |
commit | 7d9157ed0c91d2f6e76ff08e7a1c8db88bcca8c5 (patch) | |
tree | 0e267f6503f957101b62140e623d95ab849d29b9 | |
parent | 448e74e811d94a70793df9f036ec4d9a1bdb1501 (diff) | |
download | phosphor-host-ipmid-7d9157ed0c91d2f6e76ff08e7a1c8db88bcca8c5.tar.gz phosphor-host-ipmid-7d9157ed0c91d2f6e76ff08e7a1c8db88bcca8c5.zip |
construct IPMI FRU Info data based on inventory data
Change-Id: If8ee75b48323d29b568ef807d381a3e5600527d5
Signed-off-by: Marri Devender Rao <devenrao@in.ibm.com>
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | ipmi_fru_info_area.cpp | 369 | ||||
-rw-r--r-- | ipmi_fru_info_area.hpp | 27 |
3 files changed, 398 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 51e1519..f2d3bb0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -49,7 +49,8 @@ libapphandler_la_SOURCES = \ utils.cpp \ inventory-sensor-gen.cpp \ fru-read-gen.cpp \ - selutility.cpp + selutility.cpp \ + ipmi_fru_info_area.cpp libapphandler_la_LDFLAGS = $(SYSTEMD_LIBS) $(libmapper_LIBS) $(PHOSPHOR_LOGGING_LIBS) $(PHOSPHOR_DBUS_INTERFACES_LIBS) -lstdc++fs -version-info 0:0:0 -shared libapphandler_la_CXXFLAGS = $(SYSTEMD_CFLAGS) $(libmapper_CFLAGS) $(PHOSPHOR_LOGGING_CFLAGS) $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) diff --git a/ipmi_fru_info_area.cpp b/ipmi_fru_info_area.cpp new file mode 100644 index 0000000..3472f42 --- /dev/null +++ b/ipmi_fru_info_area.cpp @@ -0,0 +1,369 @@ +#include <algorithm> +#include <map> +#include <numeric> +#include "ipmi_fru_info_area.hpp" +#include <phosphor-logging/elog.hpp> +namespace ipmi +{ +namespace fru +{ +using namespace phosphor::logging; + +//Property variables +static constexpr auto partNumber = "PartNumber"; +static constexpr auto serialNumber = "SerialNumber"; +static constexpr auto manufacturer = "Manufacturer"; +static constexpr auto buildDate = "BuildDate"; +static constexpr auto model = "Model"; +static constexpr auto prettyName = "PrettyName"; +static constexpr auto version = "Version"; + +//Board info areas +static constexpr auto board = "Board"; +static constexpr auto chassis = "Chassis"; +static constexpr auto product = "Product"; + +static constexpr auto specVersion = 0x1; +static constexpr auto recordUnitOfMeasurment = 0x8; //size in bytes +static constexpr auto checksumSize = 0x1; //size in bytes +static constexpr auto recordNotPresent = 0x0; +static constexpr auto englishLanguageCode = 0x0; +static constexpr auto typeLengthByteNull = 0x0; +static constexpr auto endOfCustomFields = 0xC1; +static constexpr auto commonHeaderFormatSize = 0x8; //size in bytes +static constexpr auto manufacturingDateSize = 0x3; +static constexpr auto areaSizeOffset = 0x1; + +/** + * @brief Format Beginning of Individual IPMI FRU Data Section + * + * @param[in] langCode Language code + * @param[in/out] data FRU area data + */ +void preFormatProcessing(bool langCode, FruAreaData& data) +{ + //Add id for version of FRU Info Storage Spec used + data.emplace_back(specVersion); + + //Add Data Size - 0 as a placeholder, can edit after the data is finalized + data.emplace_back(typeLengthByteNull); + + if (langCode) + { + data.emplace_back(englishLanguageCode); + } +} + +/** + * @brief Append checksum of the FRU area data + * + * @param[in/out] data FRU area data + */ +void appendDataChecksum(FruAreaData& data) +{ + uint8_t checksumVal = std::accumulate(data.begin(), data.end(), 0); + // Push the Zero checksum as the last byte of this data + // This appears to be a simple summation of all the bytes + data.emplace_back(-checksumVal); +} + +/** + * @brief Append padding bytes for the FRU area data + * + * @param[in/out] data FRU area data + */ +void padData(FruAreaData& data) +{ + uint8_t pad = (data.size() + checksumSize) % recordUnitOfMeasurment; + if (pad) + { + data.resize((data.size() + recordUnitOfMeasurment - pad)); + } +} + +/** + * @brief Format End of Individual IPMI FRU Data Section + * + * @param[in/out] fruAreaData FRU area info data + */ +void postFormatProcessing(FruAreaData& data) +{ + //This area needs to be padded to a multiple of 8 bytes (after checksum) + padData(data); + + //Set size of data info area + data.at(areaSizeOffset) = (data.size() + checksumSize) / + (recordUnitOfMeasurment); + + //Finally add board info checksum + appendDataChecksum(data); +} + +/** + * @brief Read property value from inventory and append to the FRU area data + * + * @param[in] key key to search for in the property inventory data + * @param[in] propMap map of property values + * @param[in,out] data FRU area data to be appended + */ +void appendData(const Property& key, const PropertyMap& propMap, + FruAreaData& data) +{ + auto iter = propMap.find(key); + if (iter != propMap.end()) + { + auto value = iter->second; + //If starts with 0x or 0X remove them + //ex: 0x123a just take 123a + if ((value.compare(0, 2, "0x")) == 0 || + (value.compare(0, 2, "0X") == 0)) + { + value.erase(0, 2); + } + data.emplace_back(value.length()); + std::copy(value.begin(), value.end(), std::back_inserter(data)); + } + else + { + //set 0 size + data.emplace_back(typeLengthByteNull); + } +} + + +/** + * @brief Appends Build Date + * + * @param[in] propMap map of property values + * @param[in/out] data FRU area to add the manfufacture date + */ +void appendMfgDate(const PropertyMap& propMap, FruAreaData& data) +{ + //MFG Date/Time + auto iter = propMap.find(buildDate); + if (iter != propMap.end()) + { + auto& value = iter->second; + if (value.length() == manufacturingDateSize) + { + std::copy( + value.begin(), value.end(), std::back_inserter(data)); + return; + } + } + //Blank date + data.emplace_back(0); + data.emplace_back(0); + data.emplace_back(0); +} + +/** + * @brief Builds a section of the common header + * + * @param[in] infoAreaSize size of the FRU area to write + * @param[in] offset Current offset for data in overall record + * @param[in/out] data Common Header section data container + */ +void buildCommonHeaderSection( + const uint32_t& infoAreaSize, uint32_t& offset, FruAreaData& data) +{ + //Check if data for internal use section populated + if (infoAreaSize == 0) + { + //Indicate record not present + data.emplace_back(recordNotPresent); + } + else + { + //Place data to define offset to area data section + data.emplace_back((offset + commonHeaderFormatSize) + / recordUnitOfMeasurment); + offset += infoAreaSize; + } +} + +/** + * @brief Builds the Chassis info area data section + * + * @param[in] propMap map of properties for chassis info area + * @return FruAreaData container with chassis info area + */ +FruAreaData buildChassisInfoArea(const PropertyMap& propMap) +{ + FruAreaData fruAreaData; + if (!propMap.empty()) + { + //Set formatting data that goes at the beginning of the record + preFormatProcessing(false, fruAreaData); + + //chassis type + fruAreaData.emplace_back(0); + + //Chasiss part number, in config.yaml it is configured as model + appendData(model, propMap, fruAreaData); + + //Board serial number + appendData(serialNumber, propMap, fruAreaData); + + //Indicate End of Custom Fields + fruAreaData.emplace_back(endOfCustomFields); + + //Complete record data formatting + postFormatProcessing(fruAreaData); + } + return fruAreaData; +} + +/** + * @brief Builds the Board info area data section + * + * @param[in] propMap map of properties for board info area + * @return FruAreaData container with board info area + */ +FruAreaData buildBoardInfoArea(const PropertyMap& propMap) +{ + FruAreaData fruAreaData; + if (!propMap.empty()) + { + preFormatProcessing(true, fruAreaData); + + //Manufacturing date + appendMfgDate(propMap, fruAreaData); + + //manufacturer + appendData(manufacturer, propMap, fruAreaData); + + //Product name/Pretty name + appendData(prettyName, propMap, fruAreaData); + + //Board serial number + appendData(serialNumber, propMap, fruAreaData); + + //Board part number + appendData(partNumber, propMap, fruAreaData); + + //FRU File ID - Empty + fruAreaData.emplace_back(typeLengthByteNull); + + // Empty FRU File ID bytes + fruAreaData.emplace_back(recordNotPresent); + + //End of custom fields + fruAreaData.emplace_back(endOfCustomFields); + + postFormatProcessing(fruAreaData); + } + return fruAreaData; +} + +/** + * @brief Builds the Product info area data section + * + * @param[in] propMap map of FRU properties for Board info area + * @return FruAreaData container with product info area data + */ +FruAreaData buildProductInfoArea(const PropertyMap& propMap) +{ + FruAreaData fruAreaData; + if (!propMap.empty()) + { + //Set formatting data that goes at the beginning of the record + preFormatProcessing(true, fruAreaData); + + //manufacturer + appendData(manufacturer, propMap, fruAreaData); + + //Product name/Pretty name + appendData(prettyName, propMap, fruAreaData); + + //Product part/model number + appendData(model, propMap, fruAreaData); + + //Product version + appendData(version, propMap, fruAreaData); + + //Serial Number + appendData(serialNumber, propMap, fruAreaData); + + //Add Asset Tag + fruAreaData.emplace_back(recordNotPresent); + + //FRU File ID - Empty + fruAreaData.emplace_back(typeLengthByteNull); + + // Empty FRU File ID bytes + fruAreaData.emplace_back(recordNotPresent); + + //End of custom fields + fruAreaData.emplace_back(endOfCustomFields); + + postFormatProcessing(fruAreaData); + } + return fruAreaData; +} + +FruAreaData buildFruAreaData(const FruInventoryData& inventory) +{ + FruAreaData combFruArea; + //Now build common header with data for this FRU Inv Record + //Use this variable to increment size of header as we go along to determine + //offset for the subsequent area offsets + uint32_t curDataOffset = 0; + + //First byte is id for version of FRU Info Storage Spec used + combFruArea.emplace_back(specVersion); + + //2nd byte is offset to internal use data + combFruArea.emplace_back(recordNotPresent); + + //3rd byte is offset to chassis data + FruAreaData chassisArea; + auto chassisIt = inventory.find(chassis); + if (chassisIt != inventory.end()) + { + chassisArea = std::move(buildChassisInfoArea(chassisIt->second)); + } + buildCommonHeaderSection(chassisArea.size(), curDataOffset, combFruArea); + + //4th byte is offset to board data + FruAreaData boardArea; + auto boardIt = inventory.find(board); + if (boardIt != inventory.end()) + { + boardArea = std::move(buildBoardInfoArea(boardIt->second)); + } + + //5th byte is offset to product data + FruAreaData prodArea; + auto prodIt = inventory.find(product); + if (prodIt != inventory.end()) + { + prodArea = std::move(buildProductInfoArea(prodIt->second)); + } + buildCommonHeaderSection(prodArea.size(), curDataOffset, combFruArea); + + //6th byte is offset to multirecord data + combFruArea.emplace_back(recordNotPresent); + + //7th byte is PAD + padData(combFruArea); + + //8th (Final byte of Header Format) is the checksum + appendDataChecksum(combFruArea); + + //Combine everything into one full IPMI FRU specification Record + //add chassis use area data + combFruArea.insert( + combFruArea.end(), chassisArea.begin(), chassisArea.end()); + + //add board area data + combFruArea.insert(combFruArea.end(), boardArea.begin(), boardArea.end()); + + //add product use area data + combFruArea.insert(combFruArea.end(), prodArea.begin(), prodArea.end()); + + return combFruArea; +} + +} //fru +} //ipmi diff --git a/ipmi_fru_info_area.hpp b/ipmi_fru_info_area.hpp new file mode 100644 index 0000000..61c4e81 --- /dev/null +++ b/ipmi_fru_info_area.hpp @@ -0,0 +1,27 @@ +#pragma once
+#include <string>
+#include <vector>
+
+namespace ipmi
+{
+namespace fru
+{
+using FruAreaData = std::vector<uint8_t>;
+using Section = std::string;
+using Value = std::string;
+using Property = std::string;
+using PropertyMap = std::map<Property, Value>;
+using FruInventoryData = std::map<Section, PropertyMap>;
+
+/**
+ * @brief Builds Fru area data from inventory data
+ *
+ * @param[in] invData FRU properties values read from inventory
+ *
+ * @return FruAreaData FRU area data as per IPMI specification
+ */
+FruAreaData buildFruAreaData(const FruInventoryData& inventory);
+
+} //fru
+} //ipmi
+
|