From 6514de2b139f58620bc08ef0659816c6b6ef44ef Mon Sep 17 00:00:00 2001 From: Francois Isabelle Date: Tue, 12 Jul 2005 13:15:02 +0000 Subject: [PATCH] added read/write support and PICMG ekey support --- ipmitool/include/ipmitool/ipmi_fru.h | 216 ++-- ipmitool/lib/ipmi_fru.c | 1512 ++++++++++++++++++-------- 2 files changed, 1181 insertions(+), 547 deletions(-) diff --git a/ipmitool/include/ipmitool/ipmi_fru.h b/ipmitool/include/ipmitool/ipmi_fru.h index 0324bdf..6acf0b5 100644 --- a/ipmitool/include/ipmitool/ipmi_fru.h +++ b/ipmitool/include/ipmitool/ipmi_fru.h @@ -66,7 +66,7 @@ enum { struct fru_info { uint16_t size; - uint8_t access : 1; + uint8_t access:1; } __attribute__ ((packed)); struct fru_header { @@ -86,8 +86,8 @@ struct fru_area_chassis { uint8_t area_ver; uint8_t type; uint16_t area_len; - char * part; - char * serial; + char *part; + char *serial; }; struct fru_area_board { @@ -95,24 +95,24 @@ struct fru_area_board { uint8_t lang; uint16_t area_len; uint32_t mfg_date_time; - char * mfg; - char * prod; - char * serial; - char * part; - char * fru; + char *mfg; + char *prod; + char *serial; + char *part; + char *fru; }; struct fru_area_product { uint8_t area_ver; uint8_t lang; uint16_t area_len; - char * mfg; - char * name; - char * part; - char * version; - char * serial; - char * asset; - char * fru; + char *mfg; + char *name; + char *part; + char *version; + char *serial; + char *asset; + char *fru; }; struct fru_multirec_header { @@ -134,59 +134,58 @@ struct fru_multirec_powersupply { #if WORDS_BIGENDIAN uint16_t capacity; #else - uint16_t capacity : 12; - uint16_t __reserved1 : 4; + uint16_t capacity:12; + uint16_t __reserved1:4; #endif uint16_t peak_va; - uint8_t inrush_current; - uint8_t inrush_interval; + uint8_t inrush_current; + uint8_t inrush_interval; uint16_t lowend_input1; uint16_t highend_input1; uint16_t lowend_input2; uint16_t highend_input2; - uint8_t lowend_freq; - uint8_t highend_freq; - uint8_t dropout_tolerance; + uint8_t lowend_freq; + uint8_t highend_freq; + uint8_t dropout_tolerance; #if WORDS_BIGENDIAN - uint8_t __reserved2 : 3; - uint8_t tach : 1; - uint8_t hotswap : 1; - uint8_t autoswitch : 1; - uint8_t pfc : 1; - uint8_t predictive_fail : 1; + uint8_t __reserved2:3; + uint8_t tach:1; + uint8_t hotswap:1; + uint8_t autoswitch:1; + uint8_t pfc:1; + uint8_t predictive_fail:1; #else - uint8_t predictive_fail : 1; - uint8_t pfc : 1; - uint8_t autoswitch : 1; - uint8_t hotswap : 1; - uint8_t tach : 1; - uint8_t __reserved2 : 3; + uint8_t predictive_fail:1; + uint8_t pfc:1; + uint8_t autoswitch:1; + uint8_t hotswap:1; + uint8_t tach:1; + uint8_t __reserved2:3; #endif uint16_t peak_cap_ht; #if WORDS_BIGENDIAN - uint8_t combined_voltage1 : 4; - uint8_t combined_voltage2 : 4; + uint8_t combined_voltage1:4; + uint8_t combined_voltage2:4; #else - uint8_t combined_voltage2 : 4; - uint8_t combined_voltage1 : 4; + uint8_t combined_voltage2:4; + uint8_t combined_voltage1:4; #endif uint16_t combined_capacity; - uint8_t rps_threshold; + uint8_t rps_threshold; } __attribute__ ((packed)); -static const char * combined_voltage_desc[] __attribute__((unused)) = { - "12 V", "-12 V", "5 V", "3.3 V" -}; +static const char *combined_voltage_desc[] __attribute__ ((unused)) = { +"12 V", "-12 V", "5 V", "3.3 V"}; struct fru_multirec_dcoutput { #if WORDS_BIGENDIAN - uint8_t standby : 1; - uint8_t __reserved : 3; - uint8_t output_number : 4; + uint8_t standby:1; + uint8_t __reserved:3; + uint8_t output_number:4; #else - uint8_t output_number : 4; - uint8_t __reserved : 3; - uint8_t standby : 1; + uint8_t output_number:4; + uint8_t __reserved:3; + uint8_t standby:1; #endif short nominal_voltage; short max_neg_dev; @@ -198,11 +197,11 @@ struct fru_multirec_dcoutput { struct fru_multirec_dcload { #if WORDS_BIGENDIAN - uint8_t __reserved : 4; - uint8_t output_number : 4; + uint8_t __reserved:4; + uint8_t output_number:4; #else - uint8_t output_number : 4; - uint8_t __reserved : 4; + uint8_t output_number:4; + uint8_t __reserved:4; #endif short nominal_voltage; short min_voltage; @@ -214,17 +213,17 @@ struct fru_multirec_dcload { struct fru_multirec_picmgext_header { unsigned char mfg_id[3]; - #define FRU_PICMG_BACKPLANE_P2P 0x04 - #define FRU_PICMG_ADDRESS_TABLE 0x10 - #define FRU_PICMG_SHELF_POWER_DIST 0x11 - #define FRU_PICMG_SHELF_ACTIVATION 0x12 - #define FRU_PICMG_SHMC_IP_CONN 0x13 - #define FRU_PICMG_BOARD_P2P 0x14 - #define FRU_AMC_CURRENT 0x16 - #define FRU_AMC_ACTIVATION 0x17 - #define FRU_AMC_CARRIER_P2P 0x18 - #define FRU_AMC_P2P 0x19 - #define FRU_AMC_CARRIER_INFO 0x1a +#define FRU_PICMG_BACKPLANE_P2P 0x04 +#define FRU_PICMG_ADDRESS_TABLE 0x10 +#define FRU_PICMG_SHELF_POWER_DIST 0x11 +#define FRU_PICMG_SHELF_ACTIVATION 0x12 +#define FRU_PICMG_SHMC_IP_CONN 0x13 +#define FRU_PICMG_BOARD_P2P 0x14 +#define FRU_AMC_CURRENT 0x16 +#define FRU_AMC_ACTIVATION 0x17 +#define FRU_AMC_CARRIER_P2P 0x18 +#define FRU_AMC_P2P 0x19 +#define FRU_AMC_CARRIER_INFO 0x1a unsigned char record_id; unsigned char record_version; } __attribute__ ((packed)); @@ -235,39 +234,39 @@ struct fru_picmgext_guid { struct fru_picmgext_link_desc { #ifndef WORDS_BIGENDIAN - unsigned int designator : 12; - #define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 - #define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 - #define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 - #define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 - #define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 - unsigned int type : 8; - unsigned int ext : 4; - unsigned int grouping : 8; + unsigned int designator:12; +#define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 +#define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 + unsigned int type:8; + unsigned int ext:4; + unsigned int grouping:8; #else - unsigned int grouping : 8; - unsigned int ext : 4; - #define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 - #define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 - #define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 - #define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 - #define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 - unsigned int type : 8; - unsigned int designator : 12; + unsigned int grouping:8; + unsigned int ext:4; +#define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 +#define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 + unsigned int type:8; + unsigned int designator:12; #endif } __attribute__ ((packed)); struct fru_picmgext_chn_desc { #ifndef WORDS_BIGENDIAN - unsigned char remote_slot : 8; - unsigned char remote_chn : 5; - unsigned char local_chn : 5; - unsigned char : 6; + unsigned char remote_slot:8; + unsigned char remote_chn:5; + unsigned char local_chn:5; + unsigned char:6; #else - unsigned char : 6; - unsigned char local_chn : 5; - unsigned char remote_chn : 5; - unsigned char remote_slot : 8; + unsigned char:6; + unsigned char local_chn:5; + unsigned char remote_chn:5; + unsigned char remote_slot:8; #endif } __attribute__ ((packed)); @@ -277,7 +276,6 @@ struct fru_picmgext_slot_desc { unsigned char chn_count; } __attribute__ ((packed)); - #define FRU_PICMGEXT_DESIGN_IF_BASE 0x00 #define FRU_PICMGEXT_DESIGN_IF_FABRIC 0x01 #define FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL 0x02 @@ -297,30 +295,28 @@ struct fru_picmgext_carrier_p2p_record { struct fru_picmgext_carrier_p2p_descriptor { #ifndef WORDS_BIGENDIAN unsigned char remote_resource_id; - unsigned short remote_port : 5; - unsigned short local_port : 5; - unsigned short reserved : 6; + unsigned short remote_port:5; + unsigned short local_port:5; + unsigned short reserved:6; #else - unsigned short reserved : 6; - unsigned short local_port : 5; - unsigned short remote_port : 5; + unsigned short reserved:6; + unsigned short local_port:5; + unsigned short remote_port:5; unsigned char remote_resource_id; #endif } __attribute__ ((packed)); +static const char *chassis_type_desc[] __attribute__ ((unused)) = { +"Unspecified", "Other", "Unknown", + "Desktop", "Low Profile Desktop", "Pizza Box", + "Mini Tower", "Tower", + "Portable", "LapTop", "Notebook", "Hand Held", + "Docking Station", "All in One", "Sub Notebook", + "Space-saving", "Lunch Box", "Main Server Chassis", + "Expansion Chassis", "SubChassis", "Bus Expansion Chassis", + "Peripheral Chassis", "RAID Chassis", "Rack Mount Chassis"}; -static const char * chassis_type_desc[] __attribute__((unused)) = { - "Unspecified", "Other", "Unknown", - "Desktop", "Low Profile Desktop", "Pizza Box", - "Mini Tower", "Tower", - "Portable", "LapTop", "Notebook", "Hand Held", "Docking Station", - "All in One", "Sub Notebook", "Space-saving", "Lunch Box", - "Main Server Chassis", "Expansion Chassis", "SubChassis", - "Bus Expansion Chassis", "Peripheral Chassis", "RAID Chassis", - "Rack Mount Chassis" -}; +int ipmi_fru_main(struct ipmi_intf *intf, int argc, char **argv); +int ipmi_fru_print(struct ipmi_intf *intf, struct sdr_record_fru_locator *fru); -int ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv); -int ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru); - -#endif /* IPMI_FRU_H */ +#endif /* IPMI_FRU_H */ diff --git a/ipmitool/lib/ipmi_fru.c b/ipmitool/lib/ipmi_fru.c index 6da78dd..70b54d8 100644 --- a/ipmitool/lib/ipmi_fru.c +++ b/ipmitool/lib/ipmi_fru.c @@ -49,7 +49,34 @@ #endif extern int verbose; -extern int ipmi_spd_print(struct ipmi_intf * intf, uint8_t id); +extern int ipmi_spd_print(struct ipmi_intf *intf, uint8_t id); +static void ipmi_fru_read_to_bin(struct ipmi_intf *intf, + unsigned char *pFileName, unsigned char fruId); +static void ipmi_fru_write_from_bin(struct ipmi_intf *intf, + unsigned char *pFileName, + unsigned char fruId); +static int ipmi_fru_upg_ekeying(struct ipmi_intf *intf, + unsigned char *pFileName, unsigned char fruId); +static int ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf *intf, + unsigned char fruId, + struct fru_info *pFruInfo, + unsigned long *pRetLocation, + unsigned long *pRetSize); + +static int ipmi_fru_get_multirec_from_file(unsigned char *pFileName, + unsigned char *pBufArea, + unsigned long size, + unsigned long offset); +static int ipmi_fru_get_multirec_size_from_file(unsigned char *pFileName, + unsigned long *pSize, + unsigned long *pOffset); +static int ipmi_fru_get_adjust_size_from_buffer(unsigned char *pBufArea, + unsigned long *pSize); + +static unsigned char fileName[512]; + +static void ipmi_fru_picmg_ext_print(unsigned char *fru_data, int off, + int length); /* get_fru_area_str - Parse FRU area string from raw data * @@ -62,7 +89,7 @@ static char * get_fru_area_str(uint8_t * data, uint32_t * offset) { static const char bcd_plus[] = "0123456789 -.:,_"; - char * str; + char *str; int len, off, size, i, j, k, typecode; union { uint32_t bits; @@ -80,30 +107,29 @@ get_fru_area_str(uint8_t * data, uint32_t * offset) len &= 0x3f; switch (typecode) { - case 0: /* 00b: binary/unspecified */ + case 0: /* 00b: binary/unspecified */ /* hex dump -> 2x length */ - size = (len*2); + size = (len * 2); break; - case 2: /* 10b: 6-bit ASCII */ + case 2: /* 10b: 6-bit ASCII */ /* 4 chars per group of 1-3 bytes */ - size = ((((len+2)*4)/3) & ~3); + size = ((((len + 2) * 4) / 3) & ~3); break; - case 3: /* 11b: 8-bit ASCII */ - case 1: /* 01b: BCD plus */ + case 3: /* 11b: 8-bit ASCII */ + case 1: /* 01b: BCD plus */ /* no length adjustment */ size = len; break; } - if (size < 1) - { + if (size < 1) { *offset = off; return NULL; } - str = malloc(size+1); + str = malloc(size + 1); if (str == NULL) return NULL; - memset(str, 0, size+1); + memset(str, 0, size + 1); if (len == 0) { str[0] = '\0'; @@ -112,30 +138,30 @@ get_fru_area_str(uint8_t * data, uint32_t * offset) } switch (typecode) { - case 0: /* Binary */ - strncpy(str, buf2str(&data[off], len), len*2); + case 0: /* Binary */ + strncpy(str, buf2str(&data[off], len), len * 2); break; - case 1: /* BCD plus */ - for (k=0; k 1 ? data[off+i+1] : 0); - u.chars[1] = (k > 2 ? data[off+i+2] : 0); + u.chars[3] = data[off + i]; + u.chars[2] = (k > 1 ? data[off + i + 1] : 0); + u.chars[1] = (k > 2 ? data[off + i + 2] : 0); #define CHAR_IDX 3 #else - memcpy((void *)&u.bits, &data[off+i], k); + memcpy((void *) &u.bits, &data[off + i], k); #define CHAR_IDX 0 #endif - for (k=0; k<4; k++) { + for (k = 0; k < 4; k++) { str[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20); u.bits >>= 6; } @@ -155,6 +181,80 @@ get_fru_area_str(uint8_t * data, uint32_t * offset) return str; } +/* read_fru_area - fill in frubuf[offset:length] from the FRU[offset:length] + * + * @intf: ipmi interface + * @fru: fru info + * @id: fru id + * @offset: offset into buffer + * @length: how much to write + * @frubuf: buffer write from + * + * returns -1 on error + * returns 0 if successful + */ +static int +write_fru_area(struct ipmi_intf *intf, struct fru_info *fru, unsigned char id, + unsigned int offset, unsigned int length, unsigned char *pFrubuf) +{ /* + // fill in frubuf[offset:length] from the FRU[offset:length] + // rc=1 on success + */ + static unsigned int fru_data_rqst_size = 32; + unsigned int off = offset, tmp, finish; + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char msg_data[25]; + unsigned char writeLength; + + finish = offset + length; + if (finish > fru->size) { + printf("Return error\n"); + return -1; + } + memset(&req, 0, sizeof (req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = SET_FRU_DATA; + req.msg.data = msg_data; + + if (fru->access && fru_data_rqst_size > 16) + fru_data_rqst_size = 16; + do { + tmp = fru->access ? off >> 1 : off; + msg_data[0] = id; + msg_data[1] = (unsigned char) tmp; + msg_data[2] = (unsigned char) (tmp >> 8); + tmp = finish - off; + if (tmp > 16) { + lprintf(LOG_DEBUG, "Writting 16 bytes\n"); + memcpy(&msg_data[3], (pFrubuf + off), 16); + req.msg.data_len = 16 + 3; + } else { + lprintf(LOG_DEBUG, "Writting %d bytes\n", tmp); + memcpy(&msg_data[3], (pFrubuf + off), + (unsigned char) tmp); + req.msg.data_len = tmp + 3; + } + + writeLength = req.msg.data_len - 3; + + rsp = intf->sendrecv(intf, &req); + if (!rsp) + break; + if ((rsp->ccode == 0xc7 || rsp->ccode == 0xc8 + || rsp->ccode == 0xca) && --fru_data_rqst_size > 8) { + printf("Bad CC -> %x\n", rsp->ccode); + break; /*continue; */ + } + if (rsp->ccode) + break; + + off += writeLength; + } while (off < finish); + + return (off >= finish); +} + /* read_fru_area - fill in frubuf[offset:length] from the FRU[offset:length] * * @intf: ipmi interface @@ -168,12 +268,12 @@ get_fru_area_str(uint8_t * data, uint32_t * offset) * returns 0 if successful */ static int -read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, - uint32_t offset, uint32_t length, uint8_t *frubuf) +read_fru_area(struct ipmi_intf *intf, struct fru_info *fru, uint8_t id, + uint32_t offset, uint32_t length, uint8_t * frubuf) { static uint32_t fru_data_rqst_size = 32; uint32_t off = offset, tmp, finish; - struct ipmi_rs * rsp; + struct ipmi_rs *rsp; struct ipmi_rq req; uint8_t msg_data[4]; @@ -187,11 +287,10 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, if (finish > fru->size) { finish = fru->size; lprintf(LOG_NOTICE, "Read FRU Area length %d too large, " - "Adjusting to %d", - offset + length, finish - offset); + "Adjusting to %d", offset + length, finish - offset); } - memset(&req, 0, sizeof(req)); + memset(&req, 0, sizeof (req)); req.msg.netfn = IPMI_NETFN_STORAGE; req.msg.cmd = GET_FRU_DATA; req.msg.data = msg_data; @@ -202,13 +301,13 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, do { tmp = fru->access ? off >> 1 : off; msg_data[0] = id; - msg_data[1] = (uint8_t)(tmp & 0xff); - msg_data[2] = (uint8_t)(tmp >> 8); + msg_data[1] = (uint8_t) (tmp & 0xff); + msg_data[2] = (uint8_t) (tmp >> 8); tmp = finish - off; if (tmp > fru_data_rqst_size) - msg_data[3] = (uint8_t)fru_data_rqst_size; + msg_data[3] = (uint8_t) fru_data_rqst_size; else - msg_data[3] = (uint8_t)tmp; + msg_data[3] = (uint8_t) tmp; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { @@ -218,11 +317,13 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, if (rsp->ccode > 0) { lprintf(LOG_NOTICE, "FRU Read failed: %s", val2str(rsp->ccode, completion_code_vals)); - /* if we get C7 or C8 return code then we requested too + /* if we get C7 or C8 or CA return code then we requested too * many bytes at once so try again with smaller size */ - if ((rsp->ccode == 0xc7 || rsp->ccode == 0xc8) && - (--fru_data_rqst_size > 8)) { - lprintf(LOG_INFO, "Retrying FRU read with request size %d", + if ((rsp->ccode == 0xc7 || rsp->ccode == 0xc8 + || rsp->ccode == 0xca) + && (--fru_data_rqst_size > 8)) { + lprintf(LOG_INFO, + "Retrying FRU read with request size %d", fru_data_rqst_size); continue; } @@ -255,10 +356,10 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, * @offset: offset pointer */ static void -fru_area_print_chassis(struct ipmi_intf * intf, struct fru_info * fru, - uint8_t id, uint32_t offset) +fru_area_print_chassis(struct ipmi_intf *intf, struct fru_info *fru, + uint8_t id, uint32_t offset) { - uint8_t * fru_area, * fru_data; + uint8_t *fru_area, *fru_data; uint32_t fru_len, area_len, i; i = offset; @@ -285,8 +386,8 @@ fru_area_print_chassis(struct ipmi_intf * intf, struct fru_info * fru, return; } - i++; /* skip fru area version */ - area_len = fru_data[i++] * 8; /* fru area length */ + i++; /* skip fru area version */ + area_len = fru_data[i++] * 8; /* fru area length */ printf(" Chassis Type : %s\n", chassis_type_desc[fru_data[i++]]); @@ -304,8 +405,7 @@ fru_area_print_chassis(struct ipmi_intf * intf, struct fru_info * fru, } /* read any extra fields */ - while ((fru_data[i] != 0xc1) && (i < offset + area_len)) - { + while ((fru_data[i] != 0xc1) && (i < offset + area_len)) { int j = i; fru_area = get_fru_area_str(fru_data, &i); if (fru_area != NULL && strlen(fru_area) > 0) { @@ -327,10 +427,10 @@ fru_area_print_chassis(struct ipmi_intf * intf, struct fru_info * fru, * @offset: offset pointer */ static void -fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru, +fru_area_print_board(struct ipmi_intf *intf, struct fru_info *fru, uint8_t id, uint32_t offset) { - uint8_t * fru_area, * fru_data; + uint8_t *fru_area, *fru_data; uint32_t fru_len, area_len, i; i = offset; @@ -357,11 +457,10 @@ fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru, return; } - i++; /* skip fru area version */ - area_len = fru_data[i++] * 8; /* fru area length */ - i++; /* skip fru board language */ - i += 3; /* skip mfg. date time */ - + i++; /* skip fru area version */ + area_len = fru_data[i++] * 8; /* fru area length */ + i++; /* skip fru board language */ + i += 3; /* skip mfg. date time */ fru_area = get_fru_area_str(fru_data, &i); if (fru_area != NULL && strlen(fru_area) > 0) { @@ -395,8 +494,7 @@ fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru, } /* read any extra fields */ - while ((fru_data[i] != 0xc1) && (i < offset + area_len)) - { + while ((fru_data[i] != 0xc1) && (i < offset + area_len)) { int j = i; fru_area = get_fru_area_str(fru_data, &i); if (fru_area != NULL && strlen(fru_area) > 0) { @@ -418,10 +516,10 @@ fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru, * @offset: offset pointer */ static void -fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru, +fru_area_print_product(struct ipmi_intf *intf, struct fru_info *fru, uint8_t id, uint32_t offset) { - uint8_t * fru_area, * fru_data; + uint8_t *fru_area, *fru_data; uint32_t fru_len, area_len, i; i = offset; @@ -448,9 +546,9 @@ fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru, return; } - i++; /* skip fru area version */ - area_len = fru_data[i++] * 8; /* fru area length */ - i++; /* skip fru board language */ + i++; /* skip fru area version */ + area_len = fru_data[i++] * 8; /* fru area length */ + i++; /* skip fru board language */ fru_area = get_fru_area_str(fru_data, &i); if (fru_area != NULL && strlen(fru_area) > 0) { @@ -496,8 +594,7 @@ fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru, } /* read any extra fields */ - while ((fru_data[i] != 0xc1) && (i < offset + area_len)) - { + while ((fru_data[i] != 0xc1) && (i < offset + area_len)) { int j = i; fru_area = get_fru_area_str(fru_data, &i); if (fru_area != NULL && strlen(fru_area) > 0) { @@ -521,15 +618,15 @@ fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru, * @offset: offset pointer */ static void -fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru, +fru_area_print_multirec(struct ipmi_intf *intf, struct fru_info *fru, uint8_t id, uint32_t offset) { - uint8_t * fru_data; + uint8_t *fru_data; uint32_t fru_len, i; - struct fru_multirec_header * h; - struct fru_multirec_powersupply * ps; - struct fru_multirec_dcoutput * dc; - struct fru_multirec_dcload * dl; + struct fru_multirec_header *h; + struct fru_multirec_powersupply *ps; + struct fru_multirec_dcoutput *dc; + struct fru_multirec_dcload *dl; uint16_t peak_capacity; uint8_t peak_hold_up_time; uint32_t last_off, len; @@ -548,146 +645,159 @@ fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru, h = (struct fru_multirec_header *) (fru_data + i); /* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */ - if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len))) - { + if ((last_off < (i + sizeof (*h))) || (last_off < (i + h->len))) { len = fru->size - last_off; if (len > FRU_MULTIREC_CHUNK_SIZE) len = FRU_MULTIREC_CHUNK_SIZE; - if (read_fru_area(intf, fru, id, last_off, len, fru_data) < 0) + if (read_fru_area + (intf, fru, id, last_off, len, fru_data) < 0) break; last_off += len; } - switch (h->type) - { + switch (h->type) { case FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION: ps = (struct fru_multirec_powersupply *) - (fru_data + i + sizeof (struct fru_multirec_header)); + (fru_data + i + + sizeof (struct fru_multirec_header)); #if WORDS_BIGENDIAN - ps->capacity = BSWAP_16(ps->capacity); - ps->peak_va = BSWAP_16(ps->peak_va); - ps->lowend_input1 = BSWAP_16(ps->lowend_input1); - ps->highend_input1 = BSWAP_16(ps->highend_input1); - ps->lowend_input2 = BSWAP_16(ps->lowend_input2); - ps->highend_input2 = BSWAP_16(ps->highend_input2); - ps->combined_capacity = BSWAP_16(ps->combined_capacity); - ps->peak_cap_ht = BSWAP_16(ps->peak_cap_ht); + ps->capacity = BSWAP_16(ps->capacity); + ps->peak_va = BSWAP_16(ps->peak_va); + ps->lowend_input1 = BSWAP_16(ps->lowend_input1); + ps->highend_input1 = BSWAP_16(ps->highend_input1); + ps->lowend_input2 = BSWAP_16(ps->lowend_input2); + ps->highend_input2 = BSWAP_16(ps->highend_input2); + ps->combined_capacity = BSWAP_16(ps->combined_capacity); + ps->peak_cap_ht = BSWAP_16(ps->peak_cap_ht); #endif - peak_hold_up_time = (ps->peak_cap_ht & 0xf000) >> 12; - peak_capacity = ps->peak_cap_ht & 0x0fff; + peak_hold_up_time = (ps->peak_cap_ht & 0xf000) >> 12; + peak_capacity = ps->peak_cap_ht & 0x0fff; - printf (" Power Supply Record\n"); - printf (" Capacity : %d W\n", - ps->capacity); - printf (" Peak VA : %d VA\n", - ps->peak_va); - printf (" Inrush Current : %d A\n", - ps->inrush_current); - printf (" Inrush Interval : %d ms\n", - ps->inrush_interval); - printf (" Input Voltage Range 1 : %d-%d V\n", - ps->lowend_input1 / 100, ps->highend_input1 / 100); - printf (" Input Voltage Range 2 : %d-%d V\n", - ps->lowend_input2 / 100, ps->highend_input2 / 100); - printf (" Input Frequency Range : %d-%d Hz\n", - ps->lowend_freq, ps->highend_freq); - printf (" A/C Dropout Tolerance : %d ms\n", - ps->dropout_tolerance); - printf (" Flags : %s%s%s%s%s\n", - ps->predictive_fail ? "'Predictive fail' " : "", - ps->pfc ? "'Power factor correction' " : "", - ps->autoswitch ? "'Autoswitch voltage' " : "", - ps->hotswap ? "'Hot swap' " : "", - ps->predictive_fail ? ps->rps_threshold ? - ps->tach ? "'Two pulses per rotation'" : "'One pulse per rotation'" : - ps->tach ? "'Failure on pin de-assertion'" : "'Failure on pin assertion'" : ""); - printf (" Peak capacity : %d W\n", - peak_capacity); - printf (" Peak capacity holdup : %d s\n", - peak_hold_up_time); + printf(" Power Supply Record\n"); + printf(" Capacity : %d W\n", + ps->capacity); + printf(" Peak VA : %d VA\n", + ps->peak_va); + printf(" Inrush Current : %d A\n", + ps->inrush_current); + printf(" Inrush Interval : %d ms\n", + ps->inrush_interval); + printf(" Input Voltage Range 1 : %d-%d V\n", + ps->lowend_input1 / 100, + ps->highend_input1 / 100); + printf(" Input Voltage Range 2 : %d-%d V\n", + ps->lowend_input2 / 100, + ps->highend_input2 / 100); + printf(" Input Frequency Range : %d-%d Hz\n", + ps->lowend_freq, ps->highend_freq); + printf(" A/C Dropout Tolerance : %d ms\n", + ps->dropout_tolerance); + printf(" Flags : %s%s%s%s%s\n", + ps->predictive_fail ? "'Predictive fail' " : "", + ps->pfc ? "'Power factor correction' " : "", + ps->autoswitch ? "'Autoswitch voltage' " : "", + ps->hotswap ? "'Hot swap' " : "", + ps->predictive_fail ? ps->rps_threshold ? ps-> + tach ? "'Two pulses per rotation'" : + "'One pulse per rotation'" : ps-> + tach ? "'Failure on pin de-assertion'" : + "'Failure on pin assertion'" : ""); + printf(" Peak capacity : %d W\n", + peak_capacity); + printf(" Peak capacity holdup : %d s\n", + peak_hold_up_time); if (ps->combined_capacity == 0) - printf (" Combined capacity : not specified\n"); + printf + (" Combined capacity : not specified\n"); else - printf (" Combined capacity : %d W (%s and %s)\n", - ps->combined_capacity, - combined_voltage_desc [ps->combined_voltage1], - combined_voltage_desc [ps->combined_voltage2]); + printf + (" Combined capacity : %d W (%s and %s)\n", + ps->combined_capacity, + combined_voltage_desc[ps-> + combined_voltage1], + combined_voltage_desc[ps-> + combined_voltage2]); if (ps->predictive_fail) - printf (" Fan lower threshold : %d RPS\n", - ps->rps_threshold); + printf + (" Fan lower threshold : %d RPS\n", + ps->rps_threshold); break; case FRU_RECORD_TYPE_DC_OUTPUT: dc = (struct fru_multirec_dcoutput *) - (fru_data + i + sizeof (struct fru_multirec_header)); + (fru_data + i + + sizeof (struct fru_multirec_header)); #if WORDS_BIGENDIAN - dc->nominal_voltage = BSWAP_16(dc->nominal_voltage); - dc->max_neg_dev = BSWAP_16(dc->max_neg_dev); - dc->max_pos_dev = BSWAP_16(dc->max_pos_dev); - dc->ripple_and_noise = BSWAP_16(dc->ripple_and_noise); - dc->min_current = BSWAP_16(dc->min_current); - dc->max_current = BSWAP_16(dc->max_current); + dc->nominal_voltage = BSWAP_16(dc->nominal_voltage); + dc->max_neg_dev = BSWAP_16(dc->max_neg_dev); + dc->max_pos_dev = BSWAP_16(dc->max_pos_dev); + dc->ripple_and_noise = BSWAP_16(dc->ripple_and_noise); + dc->min_current = BSWAP_16(dc->min_current); + dc->max_current = BSWAP_16(dc->max_current); #endif - printf (" DC Output Record\n"); - printf (" Output Number : %d\n", - dc->output_number); - printf (" Standby power : %s\n", - dc->standby ? "Yes" : "No"); - printf (" Nominal voltage : %.2f V\n", - (double) dc->nominal_voltage / 100); - printf (" Max negative deviation : %.2f V\n", - (double) dc->max_neg_dev / 100); - printf (" Max positive deviation : %.2f V\n", - (double) dc->max_pos_dev / 100); - printf (" Ripple and noise pk-pk : %d mV\n", - dc->ripple_and_noise); - printf (" Minimum current draw : %.3f A\n", - (double) dc->min_current / 1000); - printf (" Maximum current draw : %.3f A\n", - (double) dc->max_current / 1000); + printf(" DC Output Record\n"); + printf(" Output Number : %d\n", + dc->output_number); + printf(" Standby power : %s\n", + dc->standby ? "Yes" : "No"); + printf(" Nominal voltage : %.2f V\n", + (double) dc->nominal_voltage / 100); + printf(" Max negative deviation : %.2f V\n", + (double) dc->max_neg_dev / 100); + printf(" Max positive deviation : %.2f V\n", + (double) dc->max_pos_dev / 100); + printf(" Ripple and noise pk-pk : %d mV\n", + dc->ripple_and_noise); + printf(" Minimum current draw : %.3f A\n", + (double) dc->min_current / 1000); + printf(" Maximum current draw : %.3f A\n", + (double) dc->max_current / 1000); break; case FRU_RECORD_TYPE_DC_LOAD: dl = (struct fru_multirec_dcload *) - (fru_data + i + sizeof (struct fru_multirec_header)); + (fru_data + i + + sizeof (struct fru_multirec_header)); #if WORDS_BIGENDIAN - dl->nominal_voltage = BSWAP_16(dl->nominal_voltage); - dl->min_voltage = BSWAP_16(dl->min_voltage); - dl->max_voltage = BSWAP_16(dl->max_voltage); - dl->ripple_and_noise = BSWAP_16(dl->ripple_and_noise); - dl->min_current = BSWAP_16(dl->min_current); - dl->max_current = BSWAP_16(dl->max_current); + dl->nominal_voltage = BSWAP_16(dl->nominal_voltage); + dl->min_voltage = BSWAP_16(dl->min_voltage); + dl->max_voltage = BSWAP_16(dl->max_voltage); + dl->ripple_and_noise = BSWAP_16(dl->ripple_and_noise); + dl->min_current = BSWAP_16(dl->min_current); + dl->max_current = BSWAP_16(dl->max_current); #endif - printf (" DC Load Record\n"); - printf (" Output Number : %d\n", - dl->output_number); - printf (" Nominal voltage : %.2f V\n", - (double) dl->nominal_voltage / 100); - printf (" Min voltage allowed : %.2f V\n", - (double) dl->min_voltage / 100); - printf (" Max voltage allowed : %.2f V\n", - (double) dl->max_voltage / 100); - printf (" Ripple and noise pk-pk : %d mV\n", - dl->ripple_and_noise); - printf (" Minimum current load : %.3f A\n", - (double) dl->min_current / 1000); - printf (" Maximum current load : %.3f A\n", - (double) dl->max_current / 1000); + printf(" DC Load Record\n"); + printf(" Output Number : %d\n", + dl->output_number); + printf(" Nominal voltage : %.2f V\n", + (double) dl->nominal_voltage / 100); + printf(" Min voltage allowed : %.2f V\n", + (double) dl->min_voltage / 100); + printf(" Max voltage allowed : %.2f V\n", + (double) dl->max_voltage / 100); + printf(" Ripple and noise pk-pk : %d mV\n", + dl->ripple_and_noise); + printf(" Minimum current load : %.3f A\n", + (double) dl->min_current / 1000); + printf(" Maximum current load : %.3f A\n", + (double) dl->max_current / 1000); break; - case FRU_RECORD_TYPE_PICMG_EXTENSION: - printf(" PICMG Extension Record\n"); - ipmi_fru_picmg_ext_print(fru_data, - i + sizeof(struct fru_multirec_header), - h->len); + case FRU_RECORD_TYPE_PICMG_EXTENSION: + printf(" PICMG Extension Record\n"); + ipmi_fru_picmg_ext_print(fru_data, + i + + sizeof (struct + fru_multirec_header), + h->len); - break; + break; } i += h->len + sizeof (struct fru_multirec_header); } while (!(h->format & 0x80)); @@ -695,267 +805,299 @@ fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru, free(fru_data); } - -static void ipmi_fru_picmg_ext_print(unsigned char * fru_data, int off, int length) +/* ipmi_fru_picmg_ext_print - Print FRU PICMG Multi Record Area + * + * @fru_data: data buffer containing the FRU data + * @int: offset into buffer where the record start + * @int: length of the record + */ +static void +ipmi_fru_picmg_ext_print(unsigned char *fru_data, int off, int length) { - struct fru_multirec_picmgext_header *h; - int guid_count; - int offset = off; - int start_offset = off; - int i; + struct fru_multirec_picmgext_header *h; + int guid_count; + int offset = off; + int start_offset = off; + int i; - h = (struct fru_multirec_picmgext_header *) &fru_data[offset]; - offset += sizeof(struct fru_multirec_picmgext_header); - - switch (h->record_id) - { + h = (struct fru_multirec_picmgext_header *) &fru_data[offset]; + offset += sizeof (struct fru_multirec_picmgext_header); - case FRU_PICMG_BACKPLANE_P2P: - { - unsigned char index, index2; - struct fru_picmgext_slot_desc * slot_d - = (struct fru_picmgext_slot_desc*) &fru_data[offset]; + switch (h->record_id) { - offset += sizeof(struct fru_picmgext_slot_desc); - printf(" FRU_PICMG_BACKPLANE_P2P\n"); + case FRU_PICMG_BACKPLANE_P2P: + { + unsigned char index, index2; + struct fru_picmgext_slot_desc *slot_d + = + (struct fru_picmgext_slot_desc *) &fru_data[offset]; - for ( ; offset <= (start_offset+length) ; ) - { - printf("\n"); - printf(" Channel Type: "); - switch ( slot_d -> chan_type ) - { - case 0x00: - case 0x07: - printf("PICMG 2.9\n"); - break; - case 0x08: - printf("Single Port Fabric IF\n"); - break; - case 0x09: - printf("Double Port Fabric IF\n"); - break; - case 0x0a: - printf("Full Channel Fabric IF\n"); - break; - case 0x0b: - printf("Base IF\n"); - break; - case 0x0c: - printf("Update Channel IF\n"); - break; - default: - printf("Unknown IF\n"); - break; - } - printf(" Slot Addr. : %02x\n", slot_d -> slot_addr ); - printf(" Channel Count: %i\n", slot_d -> chn_count); + offset += sizeof (struct fru_picmgext_slot_desc); + printf(" FRU_PICMG_BACKPLANE_P2P\n"); - for ( index = 0 ; index < (slot_d -> chn_count) ; index++ ) - { - struct fru_picmgext_chn_desc * d - = (struct fru_picmgext_chn_desc *) &fru_data[offset]; + for (; offset <= (start_offset + length);) { + printf("\n"); + printf(" Channel Type: "); + switch (slot_d->chan_type) { + case 0x00: + case 0x07: + printf("PICMG 2.9\n"); + break; + case 0x08: + printf("Single Port Fabric IF\n"); + break; + case 0x09: + printf("Double Port Fabric IF\n"); + break; + case 0x0a: + printf("Full Channel Fabric IF\n"); + break; + case 0x0b: + printf("Base IF\n"); + break; + case 0x0c: + printf("Update Channel IF\n"); + break; + default: + printf("Unknown IF\n"); + break; + } + printf(" Slot Addr. : %02x\n", + slot_d->slot_addr); + printf(" Channel Count: %i\n", + slot_d->chn_count); - if (verbose) - printf( " " - "Chn: %02x -> " - "Chn: %02x in " - "Slot: %02x\n", - d->local_chn, d->remote_chn, d->remote_slot); + for (index = 0; index < (slot_d->chn_count); + index++) { + struct fru_picmgext_chn_desc *d = + (struct fru_picmgext_chn_desc *) + &fru_data[offset]; - offset += sizeof(struct fru_picmgext_chn_desc); - } + if (verbose) + printf(" " + "Chn: %02x -> " + "Chn: %02x in " + "Slot: %02x\n", + d->local_chn, + d->remote_chn, + d->remote_slot); - slot_d = (struct fru_picmgext_slot_desc*) &fru_data[offset]; - offset += sizeof(struct fru_picmgext_slot_desc); - } - } - break; + offset += + sizeof (struct + fru_picmgext_chn_desc); + } - case FRU_PICMG_ADDRESS_TABLE: - printf(" FRU_PICMG_ADDRESS_TABLE\n"); - break; + slot_d = (struct fru_picmgext_slot_desc *) + &fru_data[offset]; + offset += + sizeof (struct fru_picmgext_slot_desc); + } + } + break; - case FRU_PICMG_SHELF_POWER_DIST: - printf(" FRU_PICMG_SHELF_POWER_DIST\n"); - break; + case FRU_PICMG_ADDRESS_TABLE: + printf(" FRU_PICMG_ADDRESS_TABLE\n"); + break; - case FRU_PICMG_SHELF_ACTIVATION: - printf(" FRU_PICMG_SHELF_ACTIVATION\n"); - break; + case FRU_PICMG_SHELF_POWER_DIST: + printf(" FRU_PICMG_SHELF_POWER_DIST\n"); + break; - case FRU_PICMG_SHMC_IP_CONN: - printf(" FRU_PICMG_SHMC_IP_CONN\n"); - break; + case FRU_PICMG_SHELF_ACTIVATION: + printf(" FRU_PICMG_SHELF_ACTIVATION\n"); + break; - case FRU_PICMG_BOARD_P2P: - printf(" FRU_PICMG_BOARD_P2P\n"); - - guid_count = fru_data[offset]; - printf(" GUID count: %2d\n", guid_count); - for (i = 0 ; i < guid_count; i++ ) - { - printf(" GUID %2d:\n", i); - offset += sizeof(struct fru_picmgext_guid); - } + case FRU_PICMG_SHMC_IP_CONN: + printf(" FRU_PICMG_SHMC_IP_CONN\n"); + break; - for ( - ++offset; - offset < off + length; - offset += sizeof(struct fru_picmgext_link_desc) - ) - { - struct fru_picmgext_link_desc * d = - (struct fru_picmgext_link_desc *) &fru_data[offset]; + case FRU_PICMG_BOARD_P2P: + printf(" FRU_PICMG_BOARD_P2P\n"); - printf(" Link Grouping ID: 0x%02x\n", d->grouping); - printf(" Link Type Extension: 0x%02x\n", d->ext); - printf(" Link Type: "); - if (d->type == 0 || d->type == 0xff) - { - printf("Reserved\n"); - } - else if (d->type >= 0x06 && d->type <= 0xef) - { - printf("Reserved\n"); - } - else if (d->type >= 0xf0 && d->type <= 0xfe) - { - printf("OEM GUID Definition\n"); - } - else - { - switch (d->type) - { - case FRU_PICMGEXT_LINK_TYPE_BASE: - printf("PICMG 3.0 Base Interface 10/100/1000\n"); - break; - case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: - printf("PICMG 3.1 Ethernet Fabric Interface\n"); - break; - case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: - printf("PICMG 3.2 Infiniband Fabric Interface\n"); - break; - case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: - printf("PICMG 3.3 Star Fabric Interface\n"); - break; - case FRU_PICMGEXT_LINK_TYPE_PCIE: - printf("PCI Express Fabric Interface\n"); - default: - printf("Invalid\n"); - } - } - printf(" Link Designator: 0x%03x\n", d->designator); - printf(" Port Flag: 0x%02x\n", d->designator >> 8); - printf(" Interface: "); - switch ((d->designator & 0xff) >> 6) - { - case FRU_PICMGEXT_DESIGN_IF_BASE: - printf("Base Interface\n"); - break; - case FRU_PICMGEXT_DESIGN_IF_FABRIC: - printf("Fabric Interface\n"); - break; - case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: - printf("Update Channel\n"); - break; - case FRU_PICMGEXT_DESIGN_IF_RESERVED: - printf("Reserved\n"); - default: - printf("Invalid"); - } - printf(" Channel Number: 0x%02x\n", d->designator & 0x1f); - printf("\n"); - } - - break; + guid_count = fru_data[offset]; + printf(" GUID count: %2d\n", guid_count); + for (i = 0; i < guid_count; i++) { + printf(" GUID %2d:\n", i); + offset += sizeof (struct fru_picmgext_guid); + } - case FRU_AMC_CURRENT: - printf(" FRU_AMC_CURRENT\n"); - break; - - case FRU_AMC_ACTIVATION: - printf(" FRU_AMC_ACTIVATION\n"); - { - unsigned short max_current; - - max_current = fru_data[offset]; - max_current |= fru_data[++offset]<<8; - printf(" Maximum Internal Current(@12V): %i A\n", max_current / 10); - printf(" Module Activation Rediness: %i sec.\n", fru_data[++offset]); + for (++offset; + offset < off + length; + offset += sizeof (struct fru_picmgext_link_desc) + ) { + struct fru_picmgext_link_desc *d = + (struct fru_picmgext_link_desc *) &fru_data[offset]; - printf(" Descriptor Count: %i\n", fru_data[++offset]); - printf("\n"); - - for(++offset; offset < off + length; offset += sizeof(struct fru_picmgext_activation_record)) - { - struct fru_picmgext_activation_record * a = - (struct fru_picmgext_activation_record *) &fru_data[offset]; - - printf(" IPMB-Address: 0x%x\n", a->ibmb_addr); - printf(" Max. Module Current: %i A\n", a->max_module_curr/10); - printf("\n"); - } - } - break; + printf(" Link Grouping ID: 0x%02x\n", + d->grouping); + printf(" Link Type Extension: 0x%02x\n", d->ext); + printf(" Link Type: "); + if (d->type == 0 || d->type == 0xff) { + printf("Reserved\n"); + } else if (d->type >= 0x06 && d->type <= 0xef) { + printf("Reserved\n"); + } else if (d->type >= 0xf0 && d->type <= 0xfe) { + printf("OEM GUID Definition\n"); + } else { + switch (d->type) { + case FRU_PICMGEXT_LINK_TYPE_BASE: + printf + ("PICMG 3.0 Base Interface 10/100/1000\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: + printf + ("PICMG 3.1 Ethernet Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: + printf + ("PICMG 3.2 Infiniband Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: + printf + ("PICMG 3.3 Star Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_PCIE: + printf + ("PCI Express Fabric Interface\n"); + default: + printf("Invalid\n"); + } + } + printf(" Link Designator: 0x%03x\n", + d->designator); + printf(" Port Flag: 0x%02x\n", + d->designator >> 8); + printf(" Interface: "); + switch ((d->designator & 0xff) >> 6) { + case FRU_PICMGEXT_DESIGN_IF_BASE: + printf("Base Interface\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_FABRIC: + printf("Fabric Interface\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: + printf("Update Channel\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_RESERVED: + printf("Reserved\n"); + default: + printf("Invalid"); + } + printf(" Channel Number: 0x%02x\n", + d->designator & 0x1f); + printf("\n"); + } - case FRU_AMC_CARRIER_P2P: - printf(" FRU_CARRIER_P2P\n"); - { - unsigned int index; - - for(offset; offset < off + length; ) - { - struct fru_picmgext_carrier_p2p_record * h = - (struct fru_picmgext_carrier_p2p_record *) &fru_data[offset]; - - printf("\n"); - printf(" Resource ID: %i", h->resource_id & 0x07); - printf(" Type: "); - if ((h->resource_id>>7) == 1) { - printf("AMC\n"); - } else { - printf("Local\n"); - } - printf(" Descriptor Count: %i\n", h->p2p_count); + break; - offset += sizeof(struct fru_picmgext_carrier_p2p_record); - - for (index = 0; index < h->p2p_count; index++) - { - struct fru_picmgext_carrier_p2p_descriptor * d = - (struct fru_picmgext_carrier_p2p_descriptor*)&fru_data[offset]; - - printf(" Port: %02d\t-> Remote Port: %02d\t", - d->local_port, d->remote_port); - if((d->remote_resource_id >> 7) == 1) - printf("[ AMC ID: %02d ]\n", d->remote_resource_id & 0x07); - else - printf("[ local ID: %02d ]\n", d->remote_resource_id & 0x07); + case FRU_AMC_CURRENT: + printf(" FRU_AMC_CURRENT\n"); + break; - offset += sizeof(struct fru_picmgext_carrier_p2p_descriptor); - - } - } - } - break; + case FRU_AMC_ACTIVATION: + printf(" FRU_AMC_ACTIVATION\n"); + { + unsigned short max_current; - case FRU_AMC_P2P: - printf(" FRU_AMC_P2P\n"); - break; + max_current = fru_data[offset]; + max_current |= fru_data[++offset] << 8; + printf(" Maximum Internal Current(@12V): %i A\n", + max_current / 10); + printf + (" Module Activation Rediness: %i sec.\n", + fru_data[++offset]); - case FRU_AMC_CARRIER_INFO: - printf(" FRU_CARRIER_INFO\n"); - break; + printf(" Descriptor Count: %i\n", + fru_data[++offset]); + printf("\n"); - default: - printf(" Unknown PICMG Extension Record ID: %x\n", h->record_id); - break; + for (++offset; offset < off + length; + offset += + sizeof (struct fru_picmgext_activation_record)) { + struct fru_picmgext_activation_record *a = + (struct fru_picmgext_activation_record *) + &fru_data[offset]; - } + printf(" IPMB-Address: 0x%x\n", + a->ibmb_addr); + printf(" Max. Module Current: %i A\n", + a->max_module_curr / 10); + printf("\n"); + } + } + break; + + case FRU_AMC_CARRIER_P2P: + printf(" FRU_CARRIER_P2P\n"); + { + unsigned int index; + + for (offset; offset < off + length;) { + struct fru_picmgext_carrier_p2p_record *h = + (struct fru_picmgext_carrier_p2p_record *) + &fru_data[offset]; + + printf("\n"); + printf(" Resource ID: %i", + h->resource_id & 0x07); + printf(" Type: "); + if ((h->resource_id >> 7) == 1) { + printf("AMC\n"); + } else { + printf("Local\n"); + } + printf(" Descriptor Count: %i\n", + h->p2p_count); + + offset += + sizeof (struct + fru_picmgext_carrier_p2p_record); + + for (index = 0; index < h->p2p_count; index++) { + struct + fru_picmgext_carrier_p2p_descriptor + *d = (struct + fru_picmgext_carrier_p2p_descriptor + *) &fru_data[offset]; + printf + (" Port: %02d\t-> Remote Port: %02d\t", + d->local_port, d->remote_port); + if ((d->remote_resource_id >> 7) == 1) + printf("[ AMC ID: %02d ]\n", + d-> + remote_resource_id & + 0x07); + else + printf("[ local ID: %02d ]\n", + d-> + remote_resource_id & + 0x07); + + offset += + sizeof (struct + fru_picmgext_carrier_p2p_descriptor); + + } + } + } + break; + + case FRU_AMC_P2P: + printf(" FRU_AMC_P2P\n"); + break; + + case FRU_AMC_CARRIER_INFO: + printf(" FRU_CARRIER_INFO\n"); + break; + + default: + printf(" Unknown PICMG Extension Record ID: %x\n", + h->record_id); + break; + + } } - /* __ipmi_fru_print - Do actual work to print a FRU by its ID * * @intf: ipmi interface @@ -966,16 +1108,16 @@ static void ipmi_fru_picmg_ext_print(unsigned char * fru_data, int off, int leng * returns 1 if device not present */ static int -__ipmi_fru_print(struct ipmi_intf * intf, uint8_t id) +__ipmi_fru_print(struct ipmi_intf *intf, uint8_t id) { - struct ipmi_rs * rsp; + struct ipmi_rs *rsp; struct ipmi_rq req; struct fru_info fru; struct fru_header header; uint8_t msg_data[4]; - memset(&fru, 0, sizeof(struct fru_info)); - memset(&header, 0, sizeof(struct fru_header)); + memset(&fru, 0, sizeof (struct fru_info)); + memset(&header, 0, sizeof (struct fru_header)); /* * get info about this FRU @@ -983,7 +1125,7 @@ __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id) memset(msg_data, 0, 4); msg_data[0] = id; - memset(&req, 0, sizeof(req)); + memset(&req, 0, sizeof (req)); req.msg.netfn = IPMI_NETFN_STORAGE; req.msg.cmd = GET_FRU_INFO; req.msg.data = msg_data; @@ -996,7 +1138,7 @@ __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id) } if (rsp->ccode > 0) { printf(" Device not present (%s)\n", - val2str(rsp->ccode, completion_code_vals)); + val2str(rsp->ccode, completion_code_vals)); return -1; } @@ -1019,7 +1161,7 @@ __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id) msg_data[2] = 0; msg_data[3] = 8; - memset(&req, 0, sizeof(req)); + memset(&req, 0, sizeof (req)); req.msg.netfn = IPMI_NETFN_STORAGE; req.msg.cmd = GET_FRU_DATA; req.msg.data = msg_data; @@ -1052,8 +1194,7 @@ __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id) * because we may end up with offset > 255 * which would overflow our 1-byte offset field */ - lprintf(LOG_DEBUG, "fru.header.version: 0x%x", - header.version); + lprintf(LOG_DEBUG, "fru.header.version: 0x%x", header.version); lprintf(LOG_DEBUG, "fru.header.offset.internal: 0x%x", header.offset.internal); lprintf(LOG_DEBUG, "fru.header.offset.chassis: 0x%x", @@ -1071,20 +1212,23 @@ __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id) */ /* chassis area */ - if ((header.offset.chassis*8) >= sizeof(struct fru_header)) - fru_area_print_chassis(intf, &fru, id, header.offset.chassis*8); + if ((header.offset.chassis * 8) >= sizeof (struct fru_header)) + fru_area_print_chassis(intf, &fru, id, + header.offset.chassis * 8); /* board area */ - if ((header.offset.board*8) >= sizeof(struct fru_header)) - fru_area_print_board(intf, &fru, id, header.offset.board*8); + if ((header.offset.board * 8) >= sizeof (struct fru_header)) + fru_area_print_board(intf, &fru, id, header.offset.board * 8); /* product area */ - if ((header.offset.product*8) >= sizeof(struct fru_header)) - fru_area_print_product(intf, &fru, id, header.offset.product*8); + if ((header.offset.product * 8) >= sizeof (struct fru_header)) + fru_area_print_product(intf, &fru, id, + header.offset.product * 8); /* multirecord area */ - if ((header.offset.multi*8) >= sizeof(struct fru_header)) - fru_area_print_multirec(intf, &fru, id, header.offset.multi*8); + if ((header.offset.multi * 8) >= sizeof (struct fru_header)) + fru_area_print_multirec(intf, &fru, id, + header.offset.multi * 8); return 0; } @@ -1097,7 +1241,7 @@ __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id) * returns -1 on error */ int -ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru) +ipmi_fru_print(struct ipmi_intf *intf, struct sdr_record_fru_locator *fru) { char desc[17]; uint8_t save_addr; @@ -1128,7 +1272,7 @@ ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru) fru->dev_type < 0x08 || fru->dev_type > 0x0f)) return -1; - memset(desc, 0, sizeof(desc)); + memset(desc, 0, sizeof (desc)); memcpy(desc, fru->id_string, fru->id_code & 0x01f); desc[fru->id_code & 0x01f] = 0; printf("FRU Device Description : %s (ID %d)\n", desc, fru->device_id); @@ -1174,11 +1318,11 @@ ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru) * returns -1 on error */ static int -ipmi_fru_print_all(struct ipmi_intf * intf) +ipmi_fru_print_all(struct ipmi_intf *intf) { - struct ipmi_sdr_iterator * itr; - struct sdr_get_rs * header; - struct sdr_record_fru_locator * fru; + struct ipmi_sdr_iterator *itr; + struct sdr_get_rs *header; + struct sdr_record_fru_locator *fru; int rc; printf("FRU Device Description : Builtin FRU Device (ID 0)\n"); @@ -1189,13 +1333,12 @@ ipmi_fru_print_all(struct ipmi_intf * intf) if ((itr = ipmi_sdr_start(intf)) == NULL) return -1; - while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) - { + while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) { if (header->type != SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR) continue; fru = (struct sdr_record_fru_locator *) - ipmi_sdr_get_record(intf, header, itr); + ipmi_sdr_get_record(intf, header, itr); if (fru == NULL) continue; rc = ipmi_fru_print(intf, fru); @@ -1208,18 +1351,75 @@ ipmi_fru_print_all(struct ipmi_intf * intf) } int -ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv) +ipmi_fru_main(struct ipmi_intf *intf, int argc, char **argv) { int rc = 0; if (argc == 0) rc = ipmi_fru_print_all(intf); else if (strncmp(argv[0], "help", 4) == 0) - lprintf(LOG_ERR, "FRU Commands: print"); + lprintf(LOG_ERR, "FRU Commands: print read write upgEkey"); else if (strncmp(argv[0], "print", 5) == 0 || - strncmp(argv[0], "list", 4) == 0) - rc = ipmi_fru_print_all(intf); - else { + strncmp(argv[0], "list", 4) == 0) { + if (argc > 1) { + rc = __ipmi_fru_print(intf, strtol(argv[1], NULL, 0)); + } else { + rc = ipmi_fru_print_all(intf); + } + } else if (!strncmp(argv[0], "read", 5)) { + unsigned char fruId = 0; + if ((argc >= 3) && (strlen(argv[2]) > 0)) { + /* There is a file name in the parameters */ + if (strlen(argv[2]) < 512) { + fruId = atoi(argv[1]); + strcpy(fileName, argv[2]); + if (verbose) { + printf("Fru Id : %d\n", + fruId); + printf("Fru File : %s\n", + fileName); + } + ipmi_fru_read_to_bin(intf, fileName, fruId); + } else { + fprintf(stderr, + "File name must be smaller than 512 bytes\n"); + } + } else { + printf("fru read \n"); + } + } else if (!strncmp(argv[0], "write", 5)) { + unsigned char fruId = 0; + if ((argc >= 3) && (strlen(argv[2]) > 0)) { + /* There is a file name in the parameters */ + if (strlen(argv[2]) < 512) { + fruId = atoi(argv[1]); + strcpy(fileName, argv[2]); + if (verbose) { + printf("Fru Id : %d\n", + fruId); + printf("Fru File : %s\n", + fileName); + } + ipmi_fru_write_from_bin(intf, fileName, fruId); + } else { + fprintf(stderr, + "File name must be smaller than 512 bytes\n"); + } + } else { + fprintf(stderr, + "A Fru Id and a path/file name must be specified\n"); + fprintf(stderr, + "Ex.: ipmitool fru write 0 /root/fru.bin\n"); + } + } else if (!strncmp(argv[0], "upgEkey", 7)) { + if ((argc >= 3) && (strlen(argv[2]) > 0)) { + strcpy(fileName, argv[2]); + ipmi_fru_upg_ekeying(intf, fileName, atoi(argv[1])); + + } else { + printf("fru upgEkey \n"); + } + } else { lprintf(LOG_ERR, "Invalid FRU command: %s", argv[0]); lprintf(LOG_ERR, "FRU Commands: print"); rc = -1; @@ -1227,3 +1427,441 @@ ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv) return rc; } + +static void +ipmi_fru_read_to_bin(struct ipmi_intf *intf, unsigned char *pFileName, + unsigned char fruId) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char *fru_data; + struct fru_info fru; + unsigned char msg_data[4]; + + unsigned char *pFruBuf; + unsigned int counter; + unsigned int len; + + msg_data[0] = fruId; + + memset(&req, 0, sizeof (req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_INFO; + req.msg.data = msg_data; + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); + if (!rsp) + return; + + if (rsp->ccode) { + if (rsp->ccode == 0xc3) + printf + (" Timeout accessing FRU info. (Device not present?)\n"); + return; + } + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + + if (verbose) { + printf("Fru Size = %d bytes\n", fru.size); + printf("Fru Access = %xh\n", fru.access); + } + + pFruBuf = malloc(fru.size); + if (pFruBuf != NULL) { + printf("Fru Size : %d bytes\n", fru.size); + read_fru_area(intf, &fru, fruId, 0, fru.size, pFruBuf); + } else { + fprintf(stderr, "Cannot allocate %d bytes\n", fru.size); + } + + if (pFruBuf != NULL) { + FILE *pFile; + pFile = fopen(pFileName, "wb"); + if (pFile != NULL) { + fwrite(pFruBuf, fru.size, 1, pFile); + } else { + fprintf(stderr, "Error opening file %s\n", pFileName); + } + fclose(pFile); + } + free(pFruBuf); +} + +static void +ipmi_fru_write_from_bin(struct ipmi_intf *intf, + unsigned char *pFileName, unsigned char fruId) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char *fru_data; + struct fru_info fru; + unsigned char msg_data[4]; + + unsigned char *pFruBuf; + unsigned int len = 0; + + msg_data[0] = fruId; + + memset(&req, 0, sizeof (req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_INFO; + req.msg.data = msg_data; + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); + if (!rsp) + return; + + if (rsp->ccode) { + if (rsp->ccode == 0xc3) + printf + (" Timeout accessing FRU info. (Device not present?)\n"); + return; + } + fru.size = (rsp->data[1] << 8) | rsp->data[0]; + fru.access = rsp->data[2] & 0x1; + + if (verbose) { + printf("Fru Size = %d bytes\n", fru.size); + printf("Fru Access = %xh\n", fru.access); + } + + pFruBuf = malloc(fru.size); + + if (pFruBuf != NULL) { + FILE *pFile; + pFile = fopen(pFileName, "rb"); + if (pFile != NULL) { + len = fread(pFruBuf, 1, fru.size, pFile); + printf("Fru Size : %d bytes\n", fru.size); + printf("Size to Write : %d bytes\n", len); + fclose(pFile); + } else { + fprintf(stderr, "Error opening file %s\n", pFileName); + } + + if (len != 0) { + write_fru_area(intf, &fru, fruId, 0, len, pFruBuf); + } + } else { + fprintf(stderr, "Cannot allocate %d bytes\n", fru.size); + } + free(pFruBuf); +} + +static int +ipmi_fru_upg_ekeying(struct ipmi_intf *intf, unsigned char *pFileName, + unsigned char fruId) +{ + unsigned int retStatus = 0; + unsigned long offFruMultiRec; + unsigned long fruMultiRecSize = 0; + unsigned long offFileMultiRec; + unsigned long fileMultiRecSize = 0; + struct fru_info fruInfo; + unsigned char *buf = NULL; + retStatus = + ipmi_fru_get_multirec_location_from_fru(intf, fruId, &fruInfo, + &offFruMultiRec, + &fruMultiRecSize); + + if (verbose) { + printf("FRU Size : %u\n\r", fruMultiRecSize); + printf("Multi Rec offset: %u\n\r", offFruMultiRec); + } + + if (retStatus == 0) { + retStatus = + ipmi_fru_get_multirec_size_from_file(pFileName, + &fileMultiRecSize, + &offFileMultiRec); + } + + if (retStatus == 0) { + buf = malloc(fileMultiRecSize); + if (buf) { + retStatus = + ipmi_fru_get_multirec_from_file(pFileName, buf, + fileMultiRecSize, + offFileMultiRec); + + } else { + printf("Error allocating memory for multirec buffer\n"); + retStatus = -1; + } + } + + ipmi_fru_get_adjust_size_from_buffer(buf, &fileMultiRecSize); + + if ((retStatus == 0) && (buf)) { + write_fru_area(intf, &fruInfo, fruId, offFruMultiRec, + fileMultiRecSize, buf); + + } + if (buf) { + free(buf); + } +} + +static int +ipmi_fru_get_multirec_size_from_file(unsigned char *pFileName, + unsigned long *pSize, + unsigned long *pOffset) +{ + struct fru_header header; + FILE *pFile; + unsigned char len = 0; + unsigned long end; + + *pSize = 0; + + pFile = fopen(pFileName, "rb"); + if (pFile != NULL) { + rewind(pFile); + len = fread(&header, 1, 8, pFile); + fseek(pFile, 0, SEEK_END); + end = ftell(pFile); + fclose(pFile); + } + + if (verbose) { + printf("File Size = %lu\n", end); + printf("Len = %lu\n", len); + } + + if (len != 8) { + printf("Error with file %s in getting size\n", pFileName); + return -1; + } + + if (header.version != 0x01) { + printf("Unknown FRU header version %02x.\n", header.version); + return -1; + } + + /* Retreive length */ + if (((header.offset.internal * 8) > (header.offset.internal * 8)) && + ((header.offset.internal * 8) < end) + ) { + end = (header.offset.internal * 8); + } + if (((header.offset.chassis * 8) > (header.offset.chassis * 8)) && + ((header.offset.chassis * 8) < end) + ) { + end = (header.offset.chassis * 8); + } + if (((header.offset.board * 8) > (header.offset.board * 8)) && + ((header.offset.board * 8) < end) + ) { + end = (header.offset.board * 8); + } + if (((header.offset.product * 8) > (header.offset.product * 8)) && + ((header.offset.product * 8) < end) + ) { + end = (header.offset.product * 8); + } + + *pSize = end - (header.offset.multi * 8); + *pOffset = (header.offset.multi * 8); + + return 0; +} + +static int +ipmi_fru_get_adjust_size_from_buffer(unsigned char *fru_data, + unsigned long *pSize) +{ + struct fru_multirec_header *head; + unsigned int last_off; +#define CHUNK_SIZE (255 + sizeof(struct fru_multirec_header)) + unsigned int count = 0; + unsigned int status = 0; + unsigned char counter; + unsigned char checksum = 0; + + do { + checksum = 0; + head = (struct fru_multirec_header *) (fru_data + count); + + if (verbose) { + printf("Adding ("); + } + + for (counter = 0; + counter < sizeof (struct fru_multirec_header); counter++) { + if (verbose) { + printf(" %02X", *(fru_data + count + counter)); + } + checksum += *(fru_data + count + counter); + + } + if (verbose) { + printf(")"); + } + + if (checksum != 0) { + printf("Bad checksum in Multi Records\n"); + status = -1; + } else if (verbose) { + printf("--> OK"); + } + + if ((verbose > 1) && (checksum == 0)) { + for (counter = 0; counter < head->len; counter++) { + printf(" %02X", *(fru_data + count + counter + + sizeof (struct + fru_multirec_header))); + } + } + if (verbose) { + printf("\n"); + } + count += head->len + sizeof (struct fru_multirec_header); + } while ((!(head->format & 0x80)) && (status == 0)); + + *pSize = count; +} + +static int +ipmi_fru_get_multirec_from_file(unsigned char *pFileName, + unsigned char *pBufArea, + unsigned long size, unsigned long offset) +{ + struct fru_header header; + FILE *pFile; + unsigned long len = 0; + + pFile = fopen(pFileName, "rb"); + if (pFile != NULL) { + fseek(pFile, offset, SEEK_SET); + len = fread(pBufArea, size, 1, pFile); + fclose(pFile); + } else { + printf("Error opening file\n"); + } + + if (len != 1) { + printf("Error with file %s\n", pFileName); + return -1; + } + + return 0; +} + +static int +ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf *intf, + unsigned char fruId, + struct fru_info *pFruInfo, + unsigned long *pRetLocation, + unsigned long *pRetSize) +{ + struct ipmi_rs *rsp; + struct ipmi_rq req; + unsigned char *fru_data; + unsigned char msg_data[4]; + int i, len; + unsigned long end; + + struct fru_header header; + + *pRetLocation = 0; + + msg_data[0] = fruId; + + memset(&req, 0, sizeof (req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_INFO; + req.msg.data = msg_data; + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); + if (!rsp) { + if (verbose > 1) { + printf("no response\n"); + } + return -1; + } + + if (rsp->ccode) { + if (rsp->ccode == 0xc3) { + printf + (" Timeout accessing FRU info. (Device not present?)\n"); + } else { + printf(" CCODE = 0x%02x\n", rsp->ccode); + } + return -1; + } + pFruInfo->size = (rsp->data[1] << 8) | rsp->data[0]; + pFruInfo->access = rsp->data[2] & 0x1; + + if (verbose > 1) + printf("pFruInfo->size = %d bytes (accessed by %s)\n", + pFruInfo->size, pFruInfo->access ? "words" : "bytes"); + if (!pFruInfo->size) { + return -1; + } + + msg_data[0] = fruId; + msg_data[1] = 0; + msg_data[2] = 0; + msg_data[3] = 8; + + memset(&req, 0, sizeof (req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_DATA; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rsp = intf->sendrecv(intf, &req); + + if (!rsp) + return -1; + + if (rsp->ccode) { + if (rsp->ccode == 0xc3) { + printf + (" Timeout while reading FRU data. (Device not present?)\n"); + } + return -1; + } + + if (verbose > 1) + printbuf(rsp->data, rsp->data_len, "FRU DATA"); + + memcpy(&header, rsp->data + 1, 8); + + if (header.version != 0x01) { + printf(" Unknown FRU header version %02x.\n", header.version); + return -1; + } + + end = pFruInfo->size; + + /* Retreive length */ + if (((header.offset.internal * 8) > (header.offset.internal * 8)) && + ((header.offset.internal * 8) < end) + ) { + end = (header.offset.internal * 8); + } + if (((header.offset.chassis * 8) > (header.offset.chassis * 8)) && + ((header.offset.chassis * 8) < end) + ) { + end = (header.offset.chassis * 8); + } + if (((header.offset.board * 8) > (header.offset.board * 8)) && + ((header.offset.board * 8) < end) + ) { + end = (header.offset.board * 8); + } + if (((header.offset.product * 8) > (header.offset.product * 8)) && + ((header.offset.product * 8) < end) + ) { + end = (header.offset.product * 8); + } + + *pRetSize = end; + *pRetLocation = 8 * header.offset.multi; + return 0; +}