From c2d7946a5ba027fe3cc88de953d17383bfdfed23 Mon Sep 17 00:00:00 2001 From: Hariharasubramanian R Date: Fri, 16 Oct 2015 06:47:56 -0500 Subject: Add interface to parse fru data into a dictionary. --- frup.c | 428 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- frup.h | 11 ++ 2 files changed, 423 insertions(+), 16 deletions(-) diff --git a/frup.c b/frup.c index d3471ff..d280a99 100644 --- a/frup.c +++ b/frup.c @@ -43,12 +43,25 @@ #include #include #include +#include +#define IPMI_FRU_PARSER_DEBUG 1 #define uint8_t unsigned char #define uint32_t unsigned int -#define ASSERT(x) if(!(x)) return -1; - +#define TEXTSTR(a) #a +# define ASSERT(x) \ +do { \ +if (0 == (x)) { \ +fprintf(stderr, \ +"Assertion failed: %s, " \ +"%d at \'%s\'\n", \ +__FILE__, \ +__LINE__, \ +TEXTSTR(a)); \ +return -1; \ +} \ +} while (0) #define IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX 512 #define IPMI_FRU_SENTINEL_VALUE 0xC1 @@ -57,6 +70,16 @@ #define IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK 0x3F #define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE 0x03 +/* OpenBMC defines for Parser */ +#define IPMI_FRU_AREA_INTERNAL_USE 0x00 +#define IPMI_FRU_AREA_CHASSIS_INFO 0x01 +#define IPMI_FRU_AREA_BOARD_INFO 0x02 +#define IPMI_FRU_AREA_PRODUCT_INFO 0x03 +#define IPMI_FRU_AREA_MULTI_RECORD 0x04 +#define IPMI_FRU_AREA_TYPE_MAX 0x05 + +#define OPENBMC_VPD_KEY_LEN 64 +#define OPENBMC_VPD_VAL_LEN 512 struct ipmi_fru_field { @@ -66,7 +89,93 @@ struct ipmi_fru_field }; typedef struct ipmi_fru_field ipmi_fru_field_t; +/* + * FRU Parser + */ + +typedef struct ipmi_fru_area_info +{ + uint8_t off; + uint8_t len; +} ipmi_fru_area_info_t; + +typedef struct ipmi_fru_common_hdr +{ + uint8_t fmtver; + uint8_t internal; + uint8_t chassis; + uint8_t board; + uint8_t product; + uint8_t multirec; +} __attribute__((packed)) ipmi_fru_common_hdr_t; + +enum openbmc_vpd_key_id +{ + OPENBMC_VPD_KEY_CHASSIS_TYPE = 1, /* not a type/len */ + OPENBMC_VPD_KEY_CHASSIS_PART_NUM, + OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM, + OPENBMC_VPD_KEY_CHASSIS_MAX = OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM, + /* TODO: chassis_custom_fields */ + + OPENBMC_VPD_KEY_BOARD_MFG_DATE, /* not a type/len */ + OPENBMC_VPD_KEY_BOARD_MFR, + OPENBMC_VPD_KEY_BOARD_NAME, + OPENBMC_VPD_KEY_BOARD_SERIAL_NUM, + OPENBMC_VPD_KEY_BOARD_PART_NUM, + OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID, + OPENBMC_VPD_KEY_BOARD_MAX = OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID, + /* TODO: board_custom_fields */ + + OPENBMC_VPD_KEY_PRODUCT_MFR, + OPENBMC_VPD_KEY_PRODUCT_NAME, + OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM, + OPENBMC_VPD_KEY_PRODUCT_VER, + OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM, + OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG, + OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID, + OPENBMC_VPD_KEY_PRODUCT_MAX = OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID, + /* TODO: product_custom_fields */ + + OPENBMC_VPD_KEY_MAX, + +}; + +const char* vpd_key_names [] = +{ + "Key Names Table Start", + "Chassis Type", /*OPENBMC_VPD_KEY_CHASSIS_TYPE*/ + "Chassis Part Number", /*OPENBMC_VPD_KEY_CHASSIS_PART_NUM,*/ + "Chassis Serial Number", /*OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,*/ + + /* TODO: chassis_custom_fields */ + + "Board Mfg Date", /* OPENBMC_VPD_KEY_BOARD_MFG_DATE, */ /* not a type/len */ + "Board Manufacturer", /* OPENBMC_VPD_KEY_BOARD_MFR, */ + "Board Name", /* OPENBMC_VPD_KEY_BOARD_NAME, */ + "Board Serial Number", /* OPENBMC_VPD_KEY_BOARD_SERIAL_NUM, */ + "Board Part Number", /* OPENBMC_VPD_KEY_BOARD_PART_NUM, */ + "Board FRU File ID", /* OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID, */ + /* TODO: board_custom_fields */ + + "Product Manufacturer", /* OPENBMC_VPD_KEY_PRODUCT_MFR, */ + "Product Name", /* OPENBMC_VPD_KEY_PRODUCT_NAME, */ + "Product Model Number", /* OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM, */ + "Product Version", /* OPENBMC_VPD_KEY_PRODUCT_VER, */ + "Product Serial Number", /* OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM, */ + "Product Asset Tag", /* OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG, */ + "Product FRU File ID", /* OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID, */ + /* TODO: product_custom_fields */ + + "Key Names Table End" /*OPENBMC_VPD_KEY_MAX,*/ +}; + +/* + * -------------------------------------------------------------------- + * + * -------------------------------------------------------------------- + */ +/* private method to parse type/length */ static int _parse_type_length (const void *areabuf, unsigned int areabuflen, @@ -84,14 +193,14 @@ _parse_type_length (const void *areabuf, type_length = areabufptr[current_area_offset]; - /* IPMI Workaround + /* ipmi workaround * - * Dell P weredge R610 + * dell p weredge r610 * - * My reading of the FRU Spec is that all non-custom fields are - * required to be listed by the vendor. However, on this + * my reading of the fru spec is that all non-custom fields are + * required to be listed by the vendor. however, on this * motherboard, some areas list this, indicating that there is - * no more data to be parsed. So now, for "required" fields, I + * no more data to be parsed. so now, for "required" fields, i * check to see if the type-length field is a sentinel before * calling this function. */ @@ -101,8 +210,8 @@ _parse_type_length (const void *areabuf, type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >> IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT; (*number_of_data_bytes) = type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK; - /* Special Case: This shouldn't be a length of 0x01 (see type/length - * byte format in FRU Information Storage Definition). + /* special case: this shouldn't be a length of 0x01 (see type/length + * byte format in fru information storage definition). */ if (type_code == IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE && (*number_of_data_bytes) == 0x01) @@ -294,19 +403,19 @@ ipmi_fru_board_info_area (const void *areabuf, /* mfg_date_time is in minutes, so multiple by 60 to get seconds */ mfg_date_time_tmp *= 60; - /* Posix says individual calls need not clear/set all portions of + /* posix says individual calls need not clear/set all portions of * 'struct tm', thus passing 'struct tm' between functions could - * have issues. So we need to memset. + * have issues. so we need to memset. */ memset (&tm, '\0', sizeof(struct tm)); - /* In FRU, epoch is 0:00 hrs 1/1/96 + /* in fru, epoch is 0:00 hrs 1/1/96 * - * So convert into ansi epoch + * so convert into ansi epoch */ tm.tm_year = 96; /* years since 1900 */ - tm.tm_mon = 0; /* months since January */ + tm.tm_mon = 0; /* months since january */ tm.tm_mday = 1; /* 1-31 */ tm.tm_hour = 0; tm.tm_min = 0; @@ -363,8 +472,7 @@ ipmi_fru_board_info_area (const void *areabuf, if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE) goto out; - if (_parse_type_length ( - areabufptr, + if (_parse_type_length (areabufptr, areabuflen, area_offset, &number_of_data_bytes, @@ -597,3 +705,291 @@ ipmi_fru_product_info_area (const void *areabuf, cleanup: return (rv); } + + +int +parse_fru (const void* msgbuf, sd_bus_message* vpdtbl) +{ + int ret = 0; + int rv = -1; + int i = 0; + ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ]; + ipmi_fru_common_hdr_t* chdr = NULL; + uint8_t* hdr = NULL; + + + ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ]; + /*char ipmi_fru_field_str [ IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX ]; + uint32_t len=0;*/ + const uint8_t* ipmi_fru_field_str; + + /* Chassis */ + uint8_t chassis_type; + + /* Board */ + uint32_t mfg_date_time; + + /* Product */ + unsigned int product_custom_fields_len; + + ASSERT (msgbuf); + ASSERT (vpdtbl); + + for (i=0; iinternal; + fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].off = chdr->chassis; + fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].off = chdr->board; + fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].off = chdr->product; + fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].off = chdr->multirec; + + if (chdr->internal) + { + fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].len = 8*(*(hdr+8*chdr->internal+1)); + + /* TODO: Parse internal use area */ + } + + if (chdr->chassis) + { + fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len = 8*(*(hdr+8*chdr->chassis+1)); + ipmi_fru_chassis_info_area (hdr+8*chdr->chassis+2, + fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len, + &chassis_type, + &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM], + &vpd_info [OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM], + NULL, 0); + } + + if (chdr->board) + { + fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len = 8*(*(hdr+8*chdr->board+1)); + ipmi_fru_board_info_area (hdr+8*chdr->board+2, + fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len, + NULL, + &mfg_date_time, + &vpd_info [OPENBMC_VPD_KEY_BOARD_MFR], + &vpd_info [OPENBMC_VPD_KEY_BOARD_NAME], + &vpd_info [OPENBMC_VPD_KEY_BOARD_SERIAL_NUM], + &vpd_info [OPENBMC_VPD_KEY_BOARD_PART_NUM], + &vpd_info [OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID], + NULL, 0); + } + + if (chdr->product) + { + fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len = 8*(*(hdr+8*chdr->product+1)); + ipmi_fru_product_info_area (hdr+8*chdr->product+2, + fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len, + NULL, + &vpd_info [OPENBMC_VPD_KEY_PRODUCT_MFR], + &vpd_info [OPENBMC_VPD_KEY_PRODUCT_NAME], + &vpd_info [OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM], + &vpd_info [OPENBMC_VPD_KEY_PRODUCT_VER], + &vpd_info [OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM], + &vpd_info [OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG], + &vpd_info [OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID], + NULL, 0); + } + + if (chdr->multirec) + { + fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].len = 8*(*(hdr+8*chdr->multirec+1)); + /* TODO: Parse multi record area */ + } + + for (i=0; i