1*c18ec02fSPetter Reinholdtsen /* 2*c18ec02fSPetter Reinholdtsen * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. 3*c18ec02fSPetter Reinholdtsen * 4*c18ec02fSPetter Reinholdtsen * Redistribution and use in source and binary forms, with or without 5*c18ec02fSPetter Reinholdtsen * modification, are permitted provided that the following conditions 6*c18ec02fSPetter Reinholdtsen * are met: 7*c18ec02fSPetter Reinholdtsen * 8*c18ec02fSPetter Reinholdtsen * Redistribution of source code must retain the above copyright 9*c18ec02fSPetter Reinholdtsen * notice, this list of conditions and the following disclaimer. 10*c18ec02fSPetter Reinholdtsen * 11*c18ec02fSPetter Reinholdtsen * Redistribution in binary form must reproduce the above copyright 12*c18ec02fSPetter Reinholdtsen * notice, this list of conditions and the following disclaimer in the 13*c18ec02fSPetter Reinholdtsen * documentation and/or other materials provided with the distribution. 14*c18ec02fSPetter Reinholdtsen * 15*c18ec02fSPetter Reinholdtsen * Neither the name of Sun Microsystems, Inc. or the names of 16*c18ec02fSPetter Reinholdtsen * contributors may be used to endorse or promote products derived 17*c18ec02fSPetter Reinholdtsen * from this software without specific prior written permission. 18*c18ec02fSPetter Reinholdtsen * 19*c18ec02fSPetter Reinholdtsen * This software is provided "AS IS," without a warranty of any kind. 20*c18ec02fSPetter Reinholdtsen * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 21*c18ec02fSPetter Reinholdtsen * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 22*c18ec02fSPetter Reinholdtsen * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 23*c18ec02fSPetter Reinholdtsen * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE 24*c18ec02fSPetter Reinholdtsen * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 25*c18ec02fSPetter Reinholdtsen * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 26*c18ec02fSPetter Reinholdtsen * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 27*c18ec02fSPetter Reinholdtsen * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 28*c18ec02fSPetter Reinholdtsen * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 29*c18ec02fSPetter Reinholdtsen * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 30*c18ec02fSPetter Reinholdtsen * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 31*c18ec02fSPetter Reinholdtsen */ 32*c18ec02fSPetter Reinholdtsen 33*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi.h> 34*c18ec02fSPetter Reinholdtsen #include <ipmitool/log.h> 35*c18ec02fSPetter Reinholdtsen #include <ipmitool/helper.h> 36*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_intf.h> 37*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_fru.h> 38*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_mc.h> 39*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_sdr.h> 40*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_strings.h> /* IANA id strings */ 41*c18ec02fSPetter Reinholdtsen 42*c18ec02fSPetter Reinholdtsen #include <stdlib.h> 43*c18ec02fSPetter Reinholdtsen #include <string.h> 44*c18ec02fSPetter Reinholdtsen #include <time.h> 45*c18ec02fSPetter Reinholdtsen #include <errno.h> 46*c18ec02fSPetter Reinholdtsen 47*c18ec02fSPetter Reinholdtsen #if HAVE_CONFIG_H 48*c18ec02fSPetter Reinholdtsen # include <config.h> 49*c18ec02fSPetter Reinholdtsen #endif 50*c18ec02fSPetter Reinholdtsen 51*c18ec02fSPetter Reinholdtsen #define FRU_MULTIREC_CHUNK_SIZE (255 + sizeof(struct fru_multirec_header)) 52*c18ec02fSPetter Reinholdtsen 53*c18ec02fSPetter Reinholdtsen extern int verbose; 54*c18ec02fSPetter Reinholdtsen 55*c18ec02fSPetter Reinholdtsen static void ipmi_fru_read_to_bin(struct ipmi_intf * intf, char * pFileName, uint8_t fruId); 56*c18ec02fSPetter Reinholdtsen static void ipmi_fru_write_from_bin(struct ipmi_intf * intf, char * pFileName, uint8_t fruId); 57*c18ec02fSPetter Reinholdtsen static int ipmi_fru_upg_ekeying(struct ipmi_intf * intf, char * pFileName, uint8_t fruId); 58*c18ec02fSPetter Reinholdtsen static int ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf, uint8_t fruId, 59*c18ec02fSPetter Reinholdtsen struct fru_info *pFruInfo, uint32_t * pRetLocation, 60*c18ec02fSPetter Reinholdtsen uint32_t * pRetSize); 61*c18ec02fSPetter Reinholdtsen static int ipmi_fru_get_multirec_from_file(char * pFileName, uint8_t * pBufArea, 62*c18ec02fSPetter Reinholdtsen uint32_t size, uint32_t offset); 63*c18ec02fSPetter Reinholdtsen static int ipmi_fru_get_multirec_size_from_file(char * pFileName, uint32_t * pSize, uint32_t * pOffset); 64*c18ec02fSPetter Reinholdtsen int ipmi_fru_get_adjust_size_from_buffer(uint8_t *pBufArea, uint32_t *pSize); 65*c18ec02fSPetter Reinholdtsen static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length); 66*c18ec02fSPetter Reinholdtsen 67*c18ec02fSPetter Reinholdtsen static int ipmi_fru_set_field_string(struct ipmi_intf * intf, unsigned 68*c18ec02fSPetter Reinholdtsen char fruId, uint8_t f_type, uint8_t f_index, char *f_string); 69*c18ec02fSPetter Reinholdtsen static int 70*c18ec02fSPetter Reinholdtsen ipmi_fru_set_field_string_rebuild(struct ipmi_intf * intf, uint8_t fruId, 71*c18ec02fSPetter Reinholdtsen struct fru_info fru, struct fru_header header, 72*c18ec02fSPetter Reinholdtsen uint8_t f_type, uint8_t f_index, char *f_string); 73*c18ec02fSPetter Reinholdtsen 74*c18ec02fSPetter Reinholdtsen static void 75*c18ec02fSPetter Reinholdtsen fru_area_print_multirec_bloc(struct ipmi_intf * intf, struct fru_info * fru, 76*c18ec02fSPetter Reinholdtsen uint8_t id, uint32_t offset); 77*c18ec02fSPetter Reinholdtsen int 78*c18ec02fSPetter Reinholdtsen read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, 79*c18ec02fSPetter Reinholdtsen uint32_t offset, uint32_t length, uint8_t *frubuf); 80*c18ec02fSPetter Reinholdtsen void free_fru_bloc(t_ipmi_fru_bloc *bloc); 81*c18ec02fSPetter Reinholdtsen 82*c18ec02fSPetter Reinholdtsen /* get_fru_area_str - Parse FRU area string from raw data 83*c18ec02fSPetter Reinholdtsen * 84*c18ec02fSPetter Reinholdtsen * @data: raw FRU data 85*c18ec02fSPetter Reinholdtsen * @offset: offset into data for area 86*c18ec02fSPetter Reinholdtsen * 87*c18ec02fSPetter Reinholdtsen * returns pointer to FRU area string 88*c18ec02fSPetter Reinholdtsen */ 89*c18ec02fSPetter Reinholdtsen char * get_fru_area_str(uint8_t * data, uint32_t * offset) 90*c18ec02fSPetter Reinholdtsen { 91*c18ec02fSPetter Reinholdtsen static const char bcd_plus[] = "0123456789 -.:,_"; 92*c18ec02fSPetter Reinholdtsen char * str; 93*c18ec02fSPetter Reinholdtsen int len, off, size, i, j, k, typecode; 94*c18ec02fSPetter Reinholdtsen union { 95*c18ec02fSPetter Reinholdtsen uint32_t bits; 96*c18ec02fSPetter Reinholdtsen char chars[4]; 97*c18ec02fSPetter Reinholdtsen } u; 98*c18ec02fSPetter Reinholdtsen 99*c18ec02fSPetter Reinholdtsen size = 0; 100*c18ec02fSPetter Reinholdtsen off = *offset; 101*c18ec02fSPetter Reinholdtsen 102*c18ec02fSPetter Reinholdtsen /* bits 6:7 contain format */ 103*c18ec02fSPetter Reinholdtsen typecode = ((data[off] & 0xC0) >> 6); 104*c18ec02fSPetter Reinholdtsen 105*c18ec02fSPetter Reinholdtsen // printf("Typecode:%i\n", typecode); 106*c18ec02fSPetter Reinholdtsen /* bits 0:5 contain length */ 107*c18ec02fSPetter Reinholdtsen len = data[off++]; 108*c18ec02fSPetter Reinholdtsen len &= 0x3f; 109*c18ec02fSPetter Reinholdtsen 110*c18ec02fSPetter Reinholdtsen switch (typecode) { 111*c18ec02fSPetter Reinholdtsen case 0: /* 00b: binary/unspecified */ 112*c18ec02fSPetter Reinholdtsen /* hex dump -> 2x length */ 113*c18ec02fSPetter Reinholdtsen size = (len*2); 114*c18ec02fSPetter Reinholdtsen break; 115*c18ec02fSPetter Reinholdtsen case 2: /* 10b: 6-bit ASCII */ 116*c18ec02fSPetter Reinholdtsen /* 4 chars per group of 1-3 bytes */ 117*c18ec02fSPetter Reinholdtsen size = ((((len+2)*4)/3) & ~3); 118*c18ec02fSPetter Reinholdtsen break; 119*c18ec02fSPetter Reinholdtsen case 3: /* 11b: 8-bit ASCII */ 120*c18ec02fSPetter Reinholdtsen case 1: /* 01b: BCD plus */ 121*c18ec02fSPetter Reinholdtsen /* no length adjustment */ 122*c18ec02fSPetter Reinholdtsen size = len; 123*c18ec02fSPetter Reinholdtsen break; 124*c18ec02fSPetter Reinholdtsen } 125*c18ec02fSPetter Reinholdtsen 126*c18ec02fSPetter Reinholdtsen if (size < 1) { 127*c18ec02fSPetter Reinholdtsen *offset = off; 128*c18ec02fSPetter Reinholdtsen return NULL; 129*c18ec02fSPetter Reinholdtsen } 130*c18ec02fSPetter Reinholdtsen str = malloc(size+1); 131*c18ec02fSPetter Reinholdtsen if (str == NULL) 132*c18ec02fSPetter Reinholdtsen return NULL; 133*c18ec02fSPetter Reinholdtsen memset(str, 0, size+1); 134*c18ec02fSPetter Reinholdtsen 135*c18ec02fSPetter Reinholdtsen if (len == 0) { 136*c18ec02fSPetter Reinholdtsen str[0] = '\0'; 137*c18ec02fSPetter Reinholdtsen *offset = off; 138*c18ec02fSPetter Reinholdtsen return str; 139*c18ec02fSPetter Reinholdtsen } 140*c18ec02fSPetter Reinholdtsen 141*c18ec02fSPetter Reinholdtsen switch (typecode) { 142*c18ec02fSPetter Reinholdtsen case 0: /* Binary */ 143*c18ec02fSPetter Reinholdtsen strncpy(str, buf2str(&data[off], len), len*2); 144*c18ec02fSPetter Reinholdtsen break; 145*c18ec02fSPetter Reinholdtsen 146*c18ec02fSPetter Reinholdtsen case 1: /* BCD plus */ 147*c18ec02fSPetter Reinholdtsen for (k=0; k<len; k++) 148*c18ec02fSPetter Reinholdtsen str[k] = bcd_plus[(data[off+k] & 0x0f)]; 149*c18ec02fSPetter Reinholdtsen str[k] = '\0'; 150*c18ec02fSPetter Reinholdtsen break; 151*c18ec02fSPetter Reinholdtsen 152*c18ec02fSPetter Reinholdtsen case 2: /* 6-bit ASCII */ 153*c18ec02fSPetter Reinholdtsen for (i=j=0; i<len; i+=3) { 154*c18ec02fSPetter Reinholdtsen u.bits = 0; 155*c18ec02fSPetter Reinholdtsen k = ((len-i) < 3 ? (len-i) : 3); 156*c18ec02fSPetter Reinholdtsen #if WORDS_BIGENDIAN 157*c18ec02fSPetter Reinholdtsen u.chars[3] = data[off+i]; 158*c18ec02fSPetter Reinholdtsen u.chars[2] = (k > 1 ? data[off+i+1] : 0); 159*c18ec02fSPetter Reinholdtsen u.chars[1] = (k > 2 ? data[off+i+2] : 0); 160*c18ec02fSPetter Reinholdtsen #define CHAR_IDX 3 161*c18ec02fSPetter Reinholdtsen #else 162*c18ec02fSPetter Reinholdtsen memcpy((void *)&u.bits, &data[off+i], k); 163*c18ec02fSPetter Reinholdtsen #define CHAR_IDX 0 164*c18ec02fSPetter Reinholdtsen #endif 165*c18ec02fSPetter Reinholdtsen for (k=0; k<4; k++) { 166*c18ec02fSPetter Reinholdtsen str[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20); 167*c18ec02fSPetter Reinholdtsen u.bits >>= 6; 168*c18ec02fSPetter Reinholdtsen } 169*c18ec02fSPetter Reinholdtsen } 170*c18ec02fSPetter Reinholdtsen str[j] = '\0'; 171*c18ec02fSPetter Reinholdtsen break; 172*c18ec02fSPetter Reinholdtsen 173*c18ec02fSPetter Reinholdtsen case 3: 174*c18ec02fSPetter Reinholdtsen memcpy(str, &data[off], len); 175*c18ec02fSPetter Reinholdtsen str[len] = '\0'; 176*c18ec02fSPetter Reinholdtsen break; 177*c18ec02fSPetter Reinholdtsen } 178*c18ec02fSPetter Reinholdtsen 179*c18ec02fSPetter Reinholdtsen off += len; 180*c18ec02fSPetter Reinholdtsen *offset = off; 181*c18ec02fSPetter Reinholdtsen 182*c18ec02fSPetter Reinholdtsen return str; 183*c18ec02fSPetter Reinholdtsen } 184*c18ec02fSPetter Reinholdtsen 185*c18ec02fSPetter Reinholdtsen /* is_valid_filename - checks file/path supplied by user 186*c18ec02fSPetter Reinholdtsen * 187*c18ec02fSPetter Reinholdtsen * input_filename - user input string 188*c18ec02fSPetter Reinholdtsen * 189*c18ec02fSPetter Reinholdtsen * returns 0 if path is ok 190*c18ec02fSPetter Reinholdtsen * returns (-1) if path is NULL 191*c18ec02fSPetter Reinholdtsen * returns (-2) if path is too short 192*c18ec02fSPetter Reinholdtsen * returns (-3) if path is too long 193*c18ec02fSPetter Reinholdtsen */ 194*c18ec02fSPetter Reinholdtsen int 195*c18ec02fSPetter Reinholdtsen is_valid_filename(const char *input_filename) 196*c18ec02fSPetter Reinholdtsen { 197*c18ec02fSPetter Reinholdtsen if (input_filename == NULL) { 198*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ERROR: NULL pointer passed."); 199*c18ec02fSPetter Reinholdtsen return (-1); 200*c18ec02fSPetter Reinholdtsen } 201*c18ec02fSPetter Reinholdtsen 202*c18ec02fSPetter Reinholdtsen if (strlen(input_filename) < 1) { 203*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "File/path is invalid."); 204*c18ec02fSPetter Reinholdtsen return (-2); 205*c18ec02fSPetter Reinholdtsen } 206*c18ec02fSPetter Reinholdtsen 207*c18ec02fSPetter Reinholdtsen if (strlen(input_filename) >= 512) { 208*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "File/path must be shorter than 512 bytes."); 209*c18ec02fSPetter Reinholdtsen return (-3); 210*c18ec02fSPetter Reinholdtsen } 211*c18ec02fSPetter Reinholdtsen 212*c18ec02fSPetter Reinholdtsen return 0; 213*c18ec02fSPetter Reinholdtsen } /* is_valid_filename() */ 214*c18ec02fSPetter Reinholdtsen 215*c18ec02fSPetter Reinholdtsen /* build_fru_bloc - build fru bloc for write protection 216*c18ec02fSPetter Reinholdtsen * 217*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 218*c18ec02fSPetter Reinholdtsen * @fru_info: information about FRU device 219*c18ec02fSPetter Reinholdtsen * @id : Fru id 220*c18ec02fSPetter Reinholdtsen * @soffset : Source offset (from buffer) 221*c18ec02fSPetter Reinholdtsen * @doffset : Destination offset (in device) 222*c18ec02fSPetter Reinholdtsen * @length : Size of data to write (in bytes) 223*c18ec02fSPetter Reinholdtsen * @pFrubuf : Pointer on data to write 224*c18ec02fSPetter Reinholdtsen * 225*c18ec02fSPetter Reinholdtsen * returns 0 on success 226*c18ec02fSPetter Reinholdtsen * returns -1 on error 227*c18ec02fSPetter Reinholdtsen */ 228*c18ec02fSPetter Reinholdtsen #define FRU_NUM_BLOC_COMMON_HEADER 6 229*c18ec02fSPetter Reinholdtsen t_ipmi_fru_bloc * 230*c18ec02fSPetter Reinholdtsen build_fru_bloc(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id) 231*c18ec02fSPetter Reinholdtsen { 232*c18ec02fSPetter Reinholdtsen t_ipmi_fru_bloc * p_first, * p_bloc, * p_new; 233*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 234*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 235*c18ec02fSPetter Reinholdtsen struct fru_header header; 236*c18ec02fSPetter Reinholdtsen struct fru_multirec_header rec_hdr; 237*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 238*c18ec02fSPetter Reinholdtsen uint32_t off; 239*c18ec02fSPetter Reinholdtsen uint16_t i; 240*c18ec02fSPetter Reinholdtsen 241*c18ec02fSPetter Reinholdtsen /* 242*c18ec02fSPetter Reinholdtsen * get COMMON Header format 243*c18ec02fSPetter Reinholdtsen */ 244*c18ec02fSPetter Reinholdtsen msg_data[0] = id; 245*c18ec02fSPetter Reinholdtsen msg_data[1] = 0; 246*c18ec02fSPetter Reinholdtsen msg_data[2] = 0; 247*c18ec02fSPetter Reinholdtsen msg_data[3] = 8; 248*c18ec02fSPetter Reinholdtsen 249*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 250*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 251*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_DATA; 252*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 253*c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 254*c18ec02fSPetter Reinholdtsen 255*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 256*c18ec02fSPetter Reinholdtsen 257*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 258*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Device not present (No Response)"); 259*c18ec02fSPetter Reinholdtsen return NULL; 260*c18ec02fSPetter Reinholdtsen } 261*c18ec02fSPetter Reinholdtsen 262*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 263*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR," Device not present (%s)", 264*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 265*c18ec02fSPetter Reinholdtsen return NULL; 266*c18ec02fSPetter Reinholdtsen } 267*c18ec02fSPetter Reinholdtsen 268*c18ec02fSPetter Reinholdtsen if (verbose > 1) { 269*c18ec02fSPetter Reinholdtsen printbuf(rsp->data, rsp->data_len, "FRU DATA"); 270*c18ec02fSPetter Reinholdtsen } 271*c18ec02fSPetter Reinholdtsen 272*c18ec02fSPetter Reinholdtsen memcpy(&header, rsp->data + 1, 8); 273*c18ec02fSPetter Reinholdtsen 274*c18ec02fSPetter Reinholdtsen /* verify header checksum */ 275*c18ec02fSPetter Reinholdtsen if (ipmi_csum((uint8_t *)&header, 8)) { 276*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Bad header checksum"); 277*c18ec02fSPetter Reinholdtsen return NULL; 278*c18ec02fSPetter Reinholdtsen } 279*c18ec02fSPetter Reinholdtsen 280*c18ec02fSPetter Reinholdtsen if (header.version != 1) { 281*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", header.version); 282*c18ec02fSPetter Reinholdtsen return NULL; 283*c18ec02fSPetter Reinholdtsen } 284*c18ec02fSPetter Reinholdtsen 285*c18ec02fSPetter Reinholdtsen /****************************************** 286*c18ec02fSPetter Reinholdtsen Malloc and fill up the bloc contents 287*c18ec02fSPetter Reinholdtsen *******************************************/ 288*c18ec02fSPetter Reinholdtsen 289*c18ec02fSPetter Reinholdtsen // Common header 290*c18ec02fSPetter Reinholdtsen p_first = malloc(sizeof(struct ipmi_fru_bloc)); 291*c18ec02fSPetter Reinholdtsen if (!p_first) { 292*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 293*c18ec02fSPetter Reinholdtsen return NULL; 294*c18ec02fSPetter Reinholdtsen } 295*c18ec02fSPetter Reinholdtsen 296*c18ec02fSPetter Reinholdtsen p_bloc = p_first; 297*c18ec02fSPetter Reinholdtsen p_bloc->next = NULL; 298*c18ec02fSPetter Reinholdtsen p_bloc->start= 0; 299*c18ec02fSPetter Reinholdtsen p_bloc->size = fru->size; 300*c18ec02fSPetter Reinholdtsen strcpy((char *)p_bloc->blocId, "Common Header Section"); 301*c18ec02fSPetter Reinholdtsen 302*c18ec02fSPetter Reinholdtsen for (i = 0; i < 4; i++) { 303*c18ec02fSPetter Reinholdtsen if (header.offsets[i]) { 304*c18ec02fSPetter Reinholdtsen p_new = malloc(sizeof(struct ipmi_fru_bloc)); 305*c18ec02fSPetter Reinholdtsen if (!p_new) { 306*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 307*c18ec02fSPetter Reinholdtsen free_fru_bloc(p_first); 308*c18ec02fSPetter Reinholdtsen return NULL; 309*c18ec02fSPetter Reinholdtsen } 310*c18ec02fSPetter Reinholdtsen 311*c18ec02fSPetter Reinholdtsen p_new->next = NULL; 312*c18ec02fSPetter Reinholdtsen p_new->start = header.offsets[i] * 8; 313*c18ec02fSPetter Reinholdtsen p_new->size = fru->size - p_new->start; 314*c18ec02fSPetter Reinholdtsen 315*c18ec02fSPetter Reinholdtsen strncpy((char *)p_new->blocId, section_id[i], sizeof(p_new->blocId)); 316*c18ec02fSPetter Reinholdtsen /* Make sure string is null terminated */ 317*c18ec02fSPetter Reinholdtsen p_new->blocId[sizeof(p_new->blocId)-1] = 0; 318*c18ec02fSPetter Reinholdtsen 319*c18ec02fSPetter Reinholdtsen p_bloc->next = p_new; 320*c18ec02fSPetter Reinholdtsen p_bloc->size = p_new->start - p_bloc->start; 321*c18ec02fSPetter Reinholdtsen p_bloc = p_new; 322*c18ec02fSPetter Reinholdtsen } 323*c18ec02fSPetter Reinholdtsen } 324*c18ec02fSPetter Reinholdtsen 325*c18ec02fSPetter Reinholdtsen // Multi 326*c18ec02fSPetter Reinholdtsen if (header.offset.multi) { 327*c18ec02fSPetter Reinholdtsen off = header.offset.multi * 8; 328*c18ec02fSPetter Reinholdtsen 329*c18ec02fSPetter Reinholdtsen do { 330*c18ec02fSPetter Reinholdtsen /* 331*c18ec02fSPetter Reinholdtsen * check for odd offset for the case of fru devices 332*c18ec02fSPetter Reinholdtsen * accessed by words 333*c18ec02fSPetter Reinholdtsen */ 334*c18ec02fSPetter Reinholdtsen if (fru->access && (off & 1)) { 335*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Unaligned offset for a block: %d", off); 336*c18ec02fSPetter Reinholdtsen /* increment offset */ 337*c18ec02fSPetter Reinholdtsen off++; 338*c18ec02fSPetter Reinholdtsen break; 339*c18ec02fSPetter Reinholdtsen } 340*c18ec02fSPetter Reinholdtsen 341*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, fru, id, off, 5, 342*c18ec02fSPetter Reinholdtsen (uint8_t *) &rec_hdr) < 0) { 343*c18ec02fSPetter Reinholdtsen break; 344*c18ec02fSPetter Reinholdtsen } 345*c18ec02fSPetter Reinholdtsen 346*c18ec02fSPetter Reinholdtsen p_new = malloc(sizeof(struct ipmi_fru_bloc)); 347*c18ec02fSPetter Reinholdtsen if (!p_new) { 348*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 349*c18ec02fSPetter Reinholdtsen free_fru_bloc(p_first); 350*c18ec02fSPetter Reinholdtsen return NULL; 351*c18ec02fSPetter Reinholdtsen } 352*c18ec02fSPetter Reinholdtsen 353*c18ec02fSPetter Reinholdtsen p_new->next = NULL; 354*c18ec02fSPetter Reinholdtsen p_new->start = off; 355*c18ec02fSPetter Reinholdtsen p_new->size = fru->size - p_new->start; 356*c18ec02fSPetter Reinholdtsen sprintf((char *)p_new->blocId, "Multi-Rec Area: Type %i", 357*c18ec02fSPetter Reinholdtsen rec_hdr.type); 358*c18ec02fSPetter Reinholdtsen 359*c18ec02fSPetter Reinholdtsen p_bloc->next = p_new; 360*c18ec02fSPetter Reinholdtsen p_bloc->size = p_new->start - p_bloc->start; 361*c18ec02fSPetter Reinholdtsen p_bloc = p_new; 362*c18ec02fSPetter Reinholdtsen 363*c18ec02fSPetter Reinholdtsen off += rec_hdr.len + sizeof(struct fru_multirec_header); 364*c18ec02fSPetter Reinholdtsen 365*c18ec02fSPetter Reinholdtsen /* verify record header */ 366*c18ec02fSPetter Reinholdtsen if (ipmi_csum((uint8_t *)&rec_hdr, 367*c18ec02fSPetter Reinholdtsen sizeof(struct fru_multirec_header))) { 368*c18ec02fSPetter Reinholdtsen /* can't reliably judge for the rest space */ 369*c18ec02fSPetter Reinholdtsen break; 370*c18ec02fSPetter Reinholdtsen } 371*c18ec02fSPetter Reinholdtsen } while (!(rec_hdr.format & 0x80) && (off < fru->size)); 372*c18ec02fSPetter Reinholdtsen 373*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG,"Multi-Record area ends at: %i (%xh)", off, off); 374*c18ec02fSPetter Reinholdtsen 375*c18ec02fSPetter Reinholdtsen if (fru->size > off) { 376*c18ec02fSPetter Reinholdtsen // Bloc for remaining space 377*c18ec02fSPetter Reinholdtsen p_new = malloc(sizeof(struct ipmi_fru_bloc)); 378*c18ec02fSPetter Reinholdtsen if (!p_new) { 379*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 380*c18ec02fSPetter Reinholdtsen free_fru_bloc(p_first); 381*c18ec02fSPetter Reinholdtsen return NULL; 382*c18ec02fSPetter Reinholdtsen } 383*c18ec02fSPetter Reinholdtsen 384*c18ec02fSPetter Reinholdtsen p_new->next = NULL; 385*c18ec02fSPetter Reinholdtsen p_new->start = off; 386*c18ec02fSPetter Reinholdtsen p_new->size = fru->size - p_new->start; 387*c18ec02fSPetter Reinholdtsen strcpy((char *)p_new->blocId, "Unused space"); 388*c18ec02fSPetter Reinholdtsen 389*c18ec02fSPetter Reinholdtsen p_bloc->next = p_new; 390*c18ec02fSPetter Reinholdtsen p_bloc->size = p_new->start - p_bloc->start; 391*c18ec02fSPetter Reinholdtsen } 392*c18ec02fSPetter Reinholdtsen } 393*c18ec02fSPetter Reinholdtsen 394*c18ec02fSPetter Reinholdtsen /* Dump blocs */ 395*c18ec02fSPetter Reinholdtsen for(p_bloc = p_first, i = 0; p_bloc; p_bloc = p_bloc->next) { 396*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG ,"Bloc Numb : %i", i++); 397*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG ,"Bloc Id : %s", p_bloc->blocId); 398*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG ,"Bloc Start: %i", p_bloc->start); 399*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG ,"Bloc Size : %i", p_bloc->size); 400*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG ,""); 401*c18ec02fSPetter Reinholdtsen } 402*c18ec02fSPetter Reinholdtsen 403*c18ec02fSPetter Reinholdtsen return p_first; 404*c18ec02fSPetter Reinholdtsen } 405*c18ec02fSPetter Reinholdtsen 406*c18ec02fSPetter Reinholdtsen void 407*c18ec02fSPetter Reinholdtsen free_fru_bloc(t_ipmi_fru_bloc *bloc) 408*c18ec02fSPetter Reinholdtsen { 409*c18ec02fSPetter Reinholdtsen t_ipmi_fru_bloc * del; 410*c18ec02fSPetter Reinholdtsen 411*c18ec02fSPetter Reinholdtsen while (bloc) { 412*c18ec02fSPetter Reinholdtsen del = bloc; 413*c18ec02fSPetter Reinholdtsen bloc = bloc->next; 414*c18ec02fSPetter Reinholdtsen free(del); 415*c18ec02fSPetter Reinholdtsen del = NULL; 416*c18ec02fSPetter Reinholdtsen } 417*c18ec02fSPetter Reinholdtsen } 418*c18ec02fSPetter Reinholdtsen 419*c18ec02fSPetter Reinholdtsen /* 420*c18ec02fSPetter Reinholdtsen * write FRU[doffset:length] from the pFrubuf[soffset:length] 421*c18ec02fSPetter Reinholdtsen * rc=1 on success 422*c18ec02fSPetter Reinholdtsen **/ 423*c18ec02fSPetter Reinholdtsen int 424*c18ec02fSPetter Reinholdtsen write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, 425*c18ec02fSPetter Reinholdtsen uint16_t soffset, uint16_t doffset, 426*c18ec02fSPetter Reinholdtsen uint16_t length, uint8_t *pFrubuf) 427*c18ec02fSPetter Reinholdtsen { 428*c18ec02fSPetter Reinholdtsen uint16_t tmp, finish; 429*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 430*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 431*c18ec02fSPetter Reinholdtsen uint8_t msg_data[255+3]; 432*c18ec02fSPetter Reinholdtsen uint16_t writeLength; 433*c18ec02fSPetter Reinholdtsen uint16_t found_bloc = 0; 434*c18ec02fSPetter Reinholdtsen 435*c18ec02fSPetter Reinholdtsen finish = doffset + length; /* destination offset */ 436*c18ec02fSPetter Reinholdtsen if (finish > fru->size) 437*c18ec02fSPetter Reinholdtsen { 438*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERROR, "Return error"); 439*c18ec02fSPetter Reinholdtsen return -1; 440*c18ec02fSPetter Reinholdtsen } 441*c18ec02fSPetter Reinholdtsen 442*c18ec02fSPetter Reinholdtsen if (fru->access && ((doffset & 1) || (length & 1))) { 443*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERROR, "Odd offset or length specified"); 444*c18ec02fSPetter Reinholdtsen return (-1); 445*c18ec02fSPetter Reinholdtsen } 446*c18ec02fSPetter Reinholdtsen 447*c18ec02fSPetter Reinholdtsen t_ipmi_fru_bloc * fru_bloc = build_fru_bloc(intf, fru, id); 448*c18ec02fSPetter Reinholdtsen t_ipmi_fru_bloc * saved_fru_bloc = fru_bloc; 449*c18ec02fSPetter Reinholdtsen 450*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 451*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 452*c18ec02fSPetter Reinholdtsen req.msg.cmd = SET_FRU_DATA; 453*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 454*c18ec02fSPetter Reinholdtsen 455*c18ec02fSPetter Reinholdtsen /* initialize request size only once */ 456*c18ec02fSPetter Reinholdtsen if (fru->max_write_size == 0) { 457*c18ec02fSPetter Reinholdtsen if (intf->channel_buf_size != 0) { 458*c18ec02fSPetter Reinholdtsen /* subtract 1 byte for FRU ID an 2 bytes for offset */ 459*c18ec02fSPetter Reinholdtsen fru->max_write_size = intf->channel_buf_size - 3; 460*c18ec02fSPetter Reinholdtsen } else { 461*c18ec02fSPetter Reinholdtsen /* subtract 1 byte for FRU ID an 2 bytes for offset */ 462*c18ec02fSPetter Reinholdtsen fru->max_write_size = 32 - 3; 463*c18ec02fSPetter Reinholdtsen } 464*c18ec02fSPetter Reinholdtsen 465*c18ec02fSPetter Reinholdtsen /* check word access */ 466*c18ec02fSPetter Reinholdtsen if (fru->access) { 467*c18ec02fSPetter Reinholdtsen fru->max_write_size &= ~1; 468*c18ec02fSPetter Reinholdtsen } 469*c18ec02fSPetter Reinholdtsen } 470*c18ec02fSPetter Reinholdtsen 471*c18ec02fSPetter Reinholdtsen do { 472*c18ec02fSPetter Reinholdtsen uint16_t end_bloc; 473*c18ec02fSPetter Reinholdtsen uint8_t protected_bloc = 0; 474*c18ec02fSPetter Reinholdtsen 475*c18ec02fSPetter Reinholdtsen /* Write per bloc, try to find the end of a bloc*/ 476*c18ec02fSPetter Reinholdtsen while (fru_bloc && fru_bloc->start + fru_bloc->size <= doffset) { 477*c18ec02fSPetter Reinholdtsen fru_bloc = fru_bloc->next; 478*c18ec02fSPetter Reinholdtsen found_bloc++; 479*c18ec02fSPetter Reinholdtsen } 480*c18ec02fSPetter Reinholdtsen 481*c18ec02fSPetter Reinholdtsen if (fru_bloc && fru_bloc->start + fru_bloc->size < finish) { 482*c18ec02fSPetter Reinholdtsen end_bloc = fru_bloc->start + fru_bloc->size; 483*c18ec02fSPetter Reinholdtsen } else { 484*c18ec02fSPetter Reinholdtsen end_bloc = finish; 485*c18ec02fSPetter Reinholdtsen } 486*c18ec02fSPetter Reinholdtsen 487*c18ec02fSPetter Reinholdtsen /* calculate write length */ 488*c18ec02fSPetter Reinholdtsen tmp = end_bloc - doffset; 489*c18ec02fSPetter Reinholdtsen 490*c18ec02fSPetter Reinholdtsen /* check that write length is more than maximum request size */ 491*c18ec02fSPetter Reinholdtsen if (tmp > fru->max_write_size) { 492*c18ec02fSPetter Reinholdtsen writeLength = fru->max_write_size; 493*c18ec02fSPetter Reinholdtsen } else { 494*c18ec02fSPetter Reinholdtsen writeLength = tmp; 495*c18ec02fSPetter Reinholdtsen } 496*c18ec02fSPetter Reinholdtsen 497*c18ec02fSPetter Reinholdtsen /* copy fru data */ 498*c18ec02fSPetter Reinholdtsen memcpy(&msg_data[3], pFrubuf + soffset, writeLength); 499*c18ec02fSPetter Reinholdtsen 500*c18ec02fSPetter Reinholdtsen /* check word access */ 501*c18ec02fSPetter Reinholdtsen if (fru->access) { 502*c18ec02fSPetter Reinholdtsen writeLength &= ~1; 503*c18ec02fSPetter Reinholdtsen } 504*c18ec02fSPetter Reinholdtsen 505*c18ec02fSPetter Reinholdtsen tmp = doffset; 506*c18ec02fSPetter Reinholdtsen if (fru->access) { 507*c18ec02fSPetter Reinholdtsen tmp >>= 1; 508*c18ec02fSPetter Reinholdtsen } 509*c18ec02fSPetter Reinholdtsen 510*c18ec02fSPetter Reinholdtsen msg_data[0] = id; 511*c18ec02fSPetter Reinholdtsen msg_data[1] = (uint8_t)tmp; 512*c18ec02fSPetter Reinholdtsen msg_data[2] = (uint8_t)(tmp >> 8); 513*c18ec02fSPetter Reinholdtsen req.msg.data_len = writeLength + 3; 514*c18ec02fSPetter Reinholdtsen 515*c18ec02fSPetter Reinholdtsen if(fru_bloc) { 516*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO,"Writing %d bytes (Bloc #%i: %s)", 517*c18ec02fSPetter Reinholdtsen writeLength, found_bloc, fru_bloc->blocId); 518*c18ec02fSPetter Reinholdtsen } else { 519*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO,"Writing %d bytes", writeLength); 520*c18ec02fSPetter Reinholdtsen } 521*c18ec02fSPetter Reinholdtsen 522*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 523*c18ec02fSPetter Reinholdtsen if (!rsp) { 524*c18ec02fSPetter Reinholdtsen break; 525*c18ec02fSPetter Reinholdtsen } 526*c18ec02fSPetter Reinholdtsen 527*c18ec02fSPetter Reinholdtsen if (rsp->ccode == 0xc7 || rsp->ccode == 0xc8 || rsp->ccode == 0xca) { 528*c18ec02fSPetter Reinholdtsen if (fru->max_write_size > 8) { 529*c18ec02fSPetter Reinholdtsen fru->max_write_size -= 8; 530*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO, "Retrying FRU write with request size %d", 531*c18ec02fSPetter Reinholdtsen fru->max_write_size); 532*c18ec02fSPetter Reinholdtsen continue; 533*c18ec02fSPetter Reinholdtsen } 534*c18ec02fSPetter Reinholdtsen } else if(rsp->ccode == 0x80) { 535*c18ec02fSPetter Reinholdtsen rsp->ccode = 0; 536*c18ec02fSPetter Reinholdtsen // Write protected section 537*c18ec02fSPetter Reinholdtsen protected_bloc = 1; 538*c18ec02fSPetter Reinholdtsen } 539*c18ec02fSPetter Reinholdtsen 540*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) 541*c18ec02fSPetter Reinholdtsen break; 542*c18ec02fSPetter Reinholdtsen 543*c18ec02fSPetter Reinholdtsen if (protected_bloc == 0) { 544*c18ec02fSPetter Reinholdtsen // Write OK, bloc not protected, continue 545*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO,"Wrote %d bytes", writeLength); 546*c18ec02fSPetter Reinholdtsen doffset += writeLength; 547*c18ec02fSPetter Reinholdtsen soffset += writeLength; 548*c18ec02fSPetter Reinholdtsen } else { 549*c18ec02fSPetter Reinholdtsen if(fru_bloc) { 550*c18ec02fSPetter Reinholdtsen // Bloc protected, advise user and jump over protected bloc 551*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO, 552*c18ec02fSPetter Reinholdtsen "Bloc [%s] protected at offset: %i (size %i bytes)", 553*c18ec02fSPetter Reinholdtsen fru_bloc->blocId, fru_bloc->start, fru_bloc->size); 554*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO,"Jumping over this bloc"); 555*c18ec02fSPetter Reinholdtsen } else { 556*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO, 557*c18ec02fSPetter Reinholdtsen "Remaining FRU is protected following offset: %i", 558*c18ec02fSPetter Reinholdtsen doffset); 559*c18ec02fSPetter Reinholdtsen } 560*c18ec02fSPetter Reinholdtsen soffset += end_bloc - doffset; 561*c18ec02fSPetter Reinholdtsen doffset = end_bloc; 562*c18ec02fSPetter Reinholdtsen } 563*c18ec02fSPetter Reinholdtsen } while (doffset < finish); 564*c18ec02fSPetter Reinholdtsen 565*c18ec02fSPetter Reinholdtsen if (saved_fru_bloc) { 566*c18ec02fSPetter Reinholdtsen free_fru_bloc(saved_fru_bloc); 567*c18ec02fSPetter Reinholdtsen } 568*c18ec02fSPetter Reinholdtsen 569*c18ec02fSPetter Reinholdtsen return doffset >= finish; 570*c18ec02fSPetter Reinholdtsen } 571*c18ec02fSPetter Reinholdtsen 572*c18ec02fSPetter Reinholdtsen /* read_fru_area - fill in frubuf[offset:length] from the FRU[offset:length] 573*c18ec02fSPetter Reinholdtsen * 574*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 575*c18ec02fSPetter Reinholdtsen * @fru: fru info 576*c18ec02fSPetter Reinholdtsen * @id: fru id 577*c18ec02fSPetter Reinholdtsen * @offset: offset into buffer 578*c18ec02fSPetter Reinholdtsen * @length: how much to read 579*c18ec02fSPetter Reinholdtsen * @frubuf: buffer read into 580*c18ec02fSPetter Reinholdtsen * 581*c18ec02fSPetter Reinholdtsen * returns -1 on error 582*c18ec02fSPetter Reinholdtsen * returns 0 if successful 583*c18ec02fSPetter Reinholdtsen */ 584*c18ec02fSPetter Reinholdtsen int 585*c18ec02fSPetter Reinholdtsen read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, 586*c18ec02fSPetter Reinholdtsen uint32_t offset, uint32_t length, uint8_t *frubuf) 587*c18ec02fSPetter Reinholdtsen { 588*c18ec02fSPetter Reinholdtsen uint32_t off = offset, tmp, finish; 589*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 590*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 591*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 592*c18ec02fSPetter Reinholdtsen 593*c18ec02fSPetter Reinholdtsen if (offset > fru->size) { 594*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Read FRU Area offset incorrect: %d > %d", 595*c18ec02fSPetter Reinholdtsen offset, fru->size); 596*c18ec02fSPetter Reinholdtsen return -1; 597*c18ec02fSPetter Reinholdtsen } 598*c18ec02fSPetter Reinholdtsen 599*c18ec02fSPetter Reinholdtsen finish = offset + length; 600*c18ec02fSPetter Reinholdtsen if (finish > fru->size) { 601*c18ec02fSPetter Reinholdtsen finish = fru->size; 602*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "Read FRU Area length %d too large, " 603*c18ec02fSPetter Reinholdtsen "Adjusting to %d", 604*c18ec02fSPetter Reinholdtsen offset + length, finish - offset); 605*c18ec02fSPetter Reinholdtsen } 606*c18ec02fSPetter Reinholdtsen 607*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 608*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 609*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_DATA; 610*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 611*c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 612*c18ec02fSPetter Reinholdtsen 613*c18ec02fSPetter Reinholdtsen if (fru->max_read_size == 0) { 614*c18ec02fSPetter Reinholdtsen /* subtract 1 byte for completion code and 1 for byte count */ 615*c18ec02fSPetter Reinholdtsen fru->max_read_size = 32 - 2; 616*c18ec02fSPetter Reinholdtsen 617*c18ec02fSPetter Reinholdtsen /* check word access */ 618*c18ec02fSPetter Reinholdtsen if (fru->access) { 619*c18ec02fSPetter Reinholdtsen fru->max_read_size &= ~1; 620*c18ec02fSPetter Reinholdtsen } 621*c18ec02fSPetter Reinholdtsen } 622*c18ec02fSPetter Reinholdtsen 623*c18ec02fSPetter Reinholdtsen do { 624*c18ec02fSPetter Reinholdtsen tmp = fru->access ? off >> 1 : off; 625*c18ec02fSPetter Reinholdtsen msg_data[0] = id; 626*c18ec02fSPetter Reinholdtsen msg_data[1] = (uint8_t)(tmp & 0xff); 627*c18ec02fSPetter Reinholdtsen msg_data[2] = (uint8_t)(tmp >> 8); 628*c18ec02fSPetter Reinholdtsen tmp = finish - off; 629*c18ec02fSPetter Reinholdtsen if (tmp > fru->max_read_size) 630*c18ec02fSPetter Reinholdtsen msg_data[3] = (uint8_t)fru->max_read_size; 631*c18ec02fSPetter Reinholdtsen else 632*c18ec02fSPetter Reinholdtsen msg_data[3] = (uint8_t)tmp; 633*c18ec02fSPetter Reinholdtsen 634*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 635*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 636*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "FRU Read failed"); 637*c18ec02fSPetter Reinholdtsen break; 638*c18ec02fSPetter Reinholdtsen } 639*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 640*c18ec02fSPetter Reinholdtsen /* if we get C8h or CAh completion code then we requested too 641*c18ec02fSPetter Reinholdtsen * many bytes at once so try again with smaller size */ 642*c18ec02fSPetter Reinholdtsen if ((rsp->ccode == 0xc8 || rsp->ccode == 0xca) 643*c18ec02fSPetter Reinholdtsen && fru->max_read_size > 8) { 644*c18ec02fSPetter Reinholdtsen if (fru->max_read_size > 32) { 645*c18ec02fSPetter Reinholdtsen /* subtract read length more aggressively */ 646*c18ec02fSPetter Reinholdtsen fru->max_read_size -= 8; 647*c18ec02fSPetter Reinholdtsen } else { 648*c18ec02fSPetter Reinholdtsen /* subtract length less aggressively */ 649*c18ec02fSPetter Reinholdtsen fru->max_read_size--; 650*c18ec02fSPetter Reinholdtsen } 651*c18ec02fSPetter Reinholdtsen 652*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO, "Retrying FRU read with request size %d", 653*c18ec02fSPetter Reinholdtsen fru->max_read_size); 654*c18ec02fSPetter Reinholdtsen continue; 655*c18ec02fSPetter Reinholdtsen } 656*c18ec02fSPetter Reinholdtsen 657*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "FRU Read failed: %s", 658*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 659*c18ec02fSPetter Reinholdtsen break; 660*c18ec02fSPetter Reinholdtsen } 661*c18ec02fSPetter Reinholdtsen 662*c18ec02fSPetter Reinholdtsen tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0]; 663*c18ec02fSPetter Reinholdtsen memcpy(frubuf, rsp->data + 1, tmp); 664*c18ec02fSPetter Reinholdtsen off += tmp; 665*c18ec02fSPetter Reinholdtsen frubuf += tmp; 666*c18ec02fSPetter Reinholdtsen /* sometimes the size returned in the Info command 667*c18ec02fSPetter Reinholdtsen * is too large. return 0 so higher level function 668*c18ec02fSPetter Reinholdtsen * still attempts to parse what was returned */ 669*c18ec02fSPetter Reinholdtsen if (tmp == 0 && off < finish) { 670*c18ec02fSPetter Reinholdtsen return 0; 671*c18ec02fSPetter Reinholdtsen } 672*c18ec02fSPetter Reinholdtsen } while (off < finish); 673*c18ec02fSPetter Reinholdtsen 674*c18ec02fSPetter Reinholdtsen if (off < finish) { 675*c18ec02fSPetter Reinholdtsen return -1; 676*c18ec02fSPetter Reinholdtsen } 677*c18ec02fSPetter Reinholdtsen 678*c18ec02fSPetter Reinholdtsen return 0; 679*c18ec02fSPetter Reinholdtsen } 680*c18ec02fSPetter Reinholdtsen 681*c18ec02fSPetter Reinholdtsen /* read_fru_area - fill in frubuf[offset:length] from the FRU[offset:length] 682*c18ec02fSPetter Reinholdtsen * 683*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 684*c18ec02fSPetter Reinholdtsen * @fru: fru info 685*c18ec02fSPetter Reinholdtsen * @id: fru id 686*c18ec02fSPetter Reinholdtsen * @offset: offset into buffer 687*c18ec02fSPetter Reinholdtsen * @length: how much to read 688*c18ec02fSPetter Reinholdtsen * @frubuf: buffer read into 689*c18ec02fSPetter Reinholdtsen * 690*c18ec02fSPetter Reinholdtsen * returns -1 on error 691*c18ec02fSPetter Reinholdtsen * returns 0 if successful 692*c18ec02fSPetter Reinholdtsen */ 693*c18ec02fSPetter Reinholdtsen int 694*c18ec02fSPetter Reinholdtsen read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id, 695*c18ec02fSPetter Reinholdtsen uint32_t offset, uint32_t length, uint8_t *frubuf) 696*c18ec02fSPetter Reinholdtsen { 697*c18ec02fSPetter Reinholdtsen static uint32_t fru_data_rqst_size = 20; 698*c18ec02fSPetter Reinholdtsen uint32_t off = offset, tmp, finish; 699*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 700*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 701*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 702*c18ec02fSPetter Reinholdtsen 703*c18ec02fSPetter Reinholdtsen if (offset > fru->size) { 704*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Read FRU Area offset incorrect: %d > %d", 705*c18ec02fSPetter Reinholdtsen offset, fru->size); 706*c18ec02fSPetter Reinholdtsen return -1; 707*c18ec02fSPetter Reinholdtsen } 708*c18ec02fSPetter Reinholdtsen 709*c18ec02fSPetter Reinholdtsen finish = offset + length; 710*c18ec02fSPetter Reinholdtsen if (finish > fru->size) { 711*c18ec02fSPetter Reinholdtsen finish = fru->size; 712*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "Read FRU Area length %d too large, " 713*c18ec02fSPetter Reinholdtsen "Adjusting to %d", 714*c18ec02fSPetter Reinholdtsen offset + length, finish - offset); 715*c18ec02fSPetter Reinholdtsen } 716*c18ec02fSPetter Reinholdtsen 717*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 718*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 719*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_DATA; 720*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 721*c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 722*c18ec02fSPetter Reinholdtsen 723*c18ec02fSPetter Reinholdtsen #ifdef LIMIT_ALL_REQUEST_SIZE 724*c18ec02fSPetter Reinholdtsen if (fru_data_rqst_size > 16) 725*c18ec02fSPetter Reinholdtsen #else 726*c18ec02fSPetter Reinholdtsen if (fru->access && fru_data_rqst_size > 16) 727*c18ec02fSPetter Reinholdtsen #endif 728*c18ec02fSPetter Reinholdtsen fru_data_rqst_size = 16; 729*c18ec02fSPetter Reinholdtsen do { 730*c18ec02fSPetter Reinholdtsen tmp = fru->access ? off >> 1 : off; 731*c18ec02fSPetter Reinholdtsen msg_data[0] = id; 732*c18ec02fSPetter Reinholdtsen msg_data[1] = (uint8_t)(tmp & 0xff); 733*c18ec02fSPetter Reinholdtsen msg_data[2] = (uint8_t)(tmp >> 8); 734*c18ec02fSPetter Reinholdtsen tmp = finish - off; 735*c18ec02fSPetter Reinholdtsen if (tmp > fru_data_rqst_size) 736*c18ec02fSPetter Reinholdtsen msg_data[3] = (uint8_t)fru_data_rqst_size; 737*c18ec02fSPetter Reinholdtsen else 738*c18ec02fSPetter Reinholdtsen msg_data[3] = (uint8_t)tmp; 739*c18ec02fSPetter Reinholdtsen 740*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 741*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 742*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "FRU Read failed"); 743*c18ec02fSPetter Reinholdtsen break; 744*c18ec02fSPetter Reinholdtsen } 745*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 746*c18ec02fSPetter Reinholdtsen /* if we get C7 or C8 or CA return code then we requested too 747*c18ec02fSPetter Reinholdtsen * many bytes at once so try again with smaller size */ 748*c18ec02fSPetter Reinholdtsen if ((rsp->ccode == 0xc7 || rsp->ccode == 0xc8 || rsp->ccode == 0xca) && 749*c18ec02fSPetter Reinholdtsen (--fru_data_rqst_size > 8)) { 750*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO, "Retrying FRU read with request size %d", 751*c18ec02fSPetter Reinholdtsen fru_data_rqst_size); 752*c18ec02fSPetter Reinholdtsen continue; 753*c18ec02fSPetter Reinholdtsen } 754*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "FRU Read failed: %s", 755*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 756*c18ec02fSPetter Reinholdtsen break; 757*c18ec02fSPetter Reinholdtsen } 758*c18ec02fSPetter Reinholdtsen 759*c18ec02fSPetter Reinholdtsen tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0]; 760*c18ec02fSPetter Reinholdtsen memcpy((frubuf + off)-offset, rsp->data + 1, tmp); 761*c18ec02fSPetter Reinholdtsen off += tmp; 762*c18ec02fSPetter Reinholdtsen 763*c18ec02fSPetter Reinholdtsen /* sometimes the size returned in the Info command 764*c18ec02fSPetter Reinholdtsen * is too large. return 0 so higher level function 765*c18ec02fSPetter Reinholdtsen * still attempts to parse what was returned */ 766*c18ec02fSPetter Reinholdtsen if (tmp == 0 && off < finish) 767*c18ec02fSPetter Reinholdtsen return 0; 768*c18ec02fSPetter Reinholdtsen 769*c18ec02fSPetter Reinholdtsen } while (off < finish); 770*c18ec02fSPetter Reinholdtsen 771*c18ec02fSPetter Reinholdtsen if (off < finish) 772*c18ec02fSPetter Reinholdtsen return -1; 773*c18ec02fSPetter Reinholdtsen 774*c18ec02fSPetter Reinholdtsen return 0; 775*c18ec02fSPetter Reinholdtsen } 776*c18ec02fSPetter Reinholdtsen 777*c18ec02fSPetter Reinholdtsen 778*c18ec02fSPetter Reinholdtsen static void 779*c18ec02fSPetter Reinholdtsen fru_area_print_multirec_bloc(struct ipmi_intf * intf, struct fru_info * fru, 780*c18ec02fSPetter Reinholdtsen uint8_t id, uint32_t offset) 781*c18ec02fSPetter Reinholdtsen { 782*c18ec02fSPetter Reinholdtsen uint8_t * fru_data = NULL; 783*c18ec02fSPetter Reinholdtsen uint32_t fru_len, i; 784*c18ec02fSPetter Reinholdtsen struct fru_multirec_header * h; 785*c18ec02fSPetter Reinholdtsen uint32_t last_off, len; 786*c18ec02fSPetter Reinholdtsen 787*c18ec02fSPetter Reinholdtsen i = last_off = offset; 788*c18ec02fSPetter Reinholdtsen fru_len = 0; 789*c18ec02fSPetter Reinholdtsen 790*c18ec02fSPetter Reinholdtsen fru_data = malloc(fru->size + 1); 791*c18ec02fSPetter Reinholdtsen if (fru_data == NULL) { 792*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Out of memory!"); 793*c18ec02fSPetter Reinholdtsen return; 794*c18ec02fSPetter Reinholdtsen } 795*c18ec02fSPetter Reinholdtsen 796*c18ec02fSPetter Reinholdtsen memset(fru_data, 0, fru->size + 1); 797*c18ec02fSPetter Reinholdtsen 798*c18ec02fSPetter Reinholdtsen do { 799*c18ec02fSPetter Reinholdtsen h = (struct fru_multirec_header *) (fru_data + i); 800*c18ec02fSPetter Reinholdtsen 801*c18ec02fSPetter Reinholdtsen // read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time 802*c18ec02fSPetter Reinholdtsen if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len))) 803*c18ec02fSPetter Reinholdtsen { 804*c18ec02fSPetter Reinholdtsen len = fru->size - last_off; 805*c18ec02fSPetter Reinholdtsen if (len > FRU_MULTIREC_CHUNK_SIZE) 806*c18ec02fSPetter Reinholdtsen len = FRU_MULTIREC_CHUNK_SIZE; 807*c18ec02fSPetter Reinholdtsen 808*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, fru, id, last_off, len, fru_data) < 0) 809*c18ec02fSPetter Reinholdtsen break; 810*c18ec02fSPetter Reinholdtsen 811*c18ec02fSPetter Reinholdtsen last_off += len; 812*c18ec02fSPetter Reinholdtsen } 813*c18ec02fSPetter Reinholdtsen 814*c18ec02fSPetter Reinholdtsen //printf("Bloc Numb : %i\n", counter); 815*c18ec02fSPetter Reinholdtsen printf("Bloc Start: %i\n", i); 816*c18ec02fSPetter Reinholdtsen printf("Bloc Size : %i\n", h->len); 817*c18ec02fSPetter Reinholdtsen printf("\n"); 818*c18ec02fSPetter Reinholdtsen 819*c18ec02fSPetter Reinholdtsen i += h->len + sizeof (struct fru_multirec_header); 820*c18ec02fSPetter Reinholdtsen } while (!(h->format & 0x80)); 821*c18ec02fSPetter Reinholdtsen 822*c18ec02fSPetter Reinholdtsen i = offset; 823*c18ec02fSPetter Reinholdtsen do { 824*c18ec02fSPetter Reinholdtsen h = (struct fru_multirec_header *) (fru_data + i); 825*c18ec02fSPetter Reinholdtsen 826*c18ec02fSPetter Reinholdtsen printf("Bloc Start: %i\n", i); 827*c18ec02fSPetter Reinholdtsen printf("Bloc Size : %i\n", h->len); 828*c18ec02fSPetter Reinholdtsen printf("\n"); 829*c18ec02fSPetter Reinholdtsen 830*c18ec02fSPetter Reinholdtsen i += h->len + sizeof (struct fru_multirec_header); 831*c18ec02fSPetter Reinholdtsen } while (!(h->format & 0x80)); 832*c18ec02fSPetter Reinholdtsen 833*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i); 834*c18ec02fSPetter Reinholdtsen 835*c18ec02fSPetter Reinholdtsen free(fru_data); 836*c18ec02fSPetter Reinholdtsen fru_data = NULL; 837*c18ec02fSPetter Reinholdtsen } 838*c18ec02fSPetter Reinholdtsen 839*c18ec02fSPetter Reinholdtsen 840*c18ec02fSPetter Reinholdtsen /* fru_area_print_chassis - Print FRU Chassis Area 841*c18ec02fSPetter Reinholdtsen * 842*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 843*c18ec02fSPetter Reinholdtsen * @fru: fru info 844*c18ec02fSPetter Reinholdtsen * @id: fru id 845*c18ec02fSPetter Reinholdtsen * @offset: offset pointer 846*c18ec02fSPetter Reinholdtsen */ 847*c18ec02fSPetter Reinholdtsen static void 848*c18ec02fSPetter Reinholdtsen fru_area_print_chassis(struct ipmi_intf * intf, struct fru_info * fru, 849*c18ec02fSPetter Reinholdtsen uint8_t id, uint32_t offset) 850*c18ec02fSPetter Reinholdtsen { 851*c18ec02fSPetter Reinholdtsen char * fru_area; 852*c18ec02fSPetter Reinholdtsen uint8_t * fru_data; 853*c18ec02fSPetter Reinholdtsen uint32_t fru_len, i; 854*c18ec02fSPetter Reinholdtsen uint8_t tmp[2]; 855*c18ec02fSPetter Reinholdtsen 856*c18ec02fSPetter Reinholdtsen fru_len = 0; 857*c18ec02fSPetter Reinholdtsen 858*c18ec02fSPetter Reinholdtsen /* read enough to check length field */ 859*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) { 860*c18ec02fSPetter Reinholdtsen fru_len = 8 * tmp[1]; 861*c18ec02fSPetter Reinholdtsen } 862*c18ec02fSPetter Reinholdtsen 863*c18ec02fSPetter Reinholdtsen if (fru_len == 0) { 864*c18ec02fSPetter Reinholdtsen return; 865*c18ec02fSPetter Reinholdtsen } 866*c18ec02fSPetter Reinholdtsen 867*c18ec02fSPetter Reinholdtsen fru_data = malloc(fru_len); 868*c18ec02fSPetter Reinholdtsen if (fru_data == NULL) { 869*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 870*c18ec02fSPetter Reinholdtsen return; 871*c18ec02fSPetter Reinholdtsen } 872*c18ec02fSPetter Reinholdtsen 873*c18ec02fSPetter Reinholdtsen memset(fru_data, 0, fru_len); 874*c18ec02fSPetter Reinholdtsen 875*c18ec02fSPetter Reinholdtsen /* read in the full fru */ 876*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) { 877*c18ec02fSPetter Reinholdtsen free(fru_data); 878*c18ec02fSPetter Reinholdtsen fru_data = NULL; 879*c18ec02fSPetter Reinholdtsen return; 880*c18ec02fSPetter Reinholdtsen } 881*c18ec02fSPetter Reinholdtsen 882*c18ec02fSPetter Reinholdtsen /* 883*c18ec02fSPetter Reinholdtsen * skip first two bytes which specify 884*c18ec02fSPetter Reinholdtsen * fru area version and fru area length 885*c18ec02fSPetter Reinholdtsen */ 886*c18ec02fSPetter Reinholdtsen i = 2; 887*c18ec02fSPetter Reinholdtsen 888*c18ec02fSPetter Reinholdtsen printf(" Chassis Type : %s\n", 889*c18ec02fSPetter Reinholdtsen chassis_type_desc[fru_data[i] > 890*c18ec02fSPetter Reinholdtsen (sizeof(chassis_type_desc)/sizeof(chassis_type_desc[0])) - 1 ? 891*c18ec02fSPetter Reinholdtsen 2 : fru_data[i]]); 892*c18ec02fSPetter Reinholdtsen 893*c18ec02fSPetter Reinholdtsen i++; 894*c18ec02fSPetter Reinholdtsen 895*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 896*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 897*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 898*c18ec02fSPetter Reinholdtsen printf(" Chassis Part Number : %s\n", fru_area); 899*c18ec02fSPetter Reinholdtsen } 900*c18ec02fSPetter Reinholdtsen free(fru_area); 901*c18ec02fSPetter Reinholdtsen fru_area = NULL; 902*c18ec02fSPetter Reinholdtsen } 903*c18ec02fSPetter Reinholdtsen 904*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 905*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 906*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 907*c18ec02fSPetter Reinholdtsen printf(" Chassis Serial : %s\n", fru_area); 908*c18ec02fSPetter Reinholdtsen } 909*c18ec02fSPetter Reinholdtsen free(fru_area); 910*c18ec02fSPetter Reinholdtsen fru_area = NULL; 911*c18ec02fSPetter Reinholdtsen } 912*c18ec02fSPetter Reinholdtsen 913*c18ec02fSPetter Reinholdtsen /* read any extra fields */ 914*c18ec02fSPetter Reinholdtsen while ((fru_data[i] != 0xc1) && (i < fru_len)) 915*c18ec02fSPetter Reinholdtsen { 916*c18ec02fSPetter Reinholdtsen int j = i; 917*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 918*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 919*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 920*c18ec02fSPetter Reinholdtsen printf(" Chassis Extra : %s\n", fru_area); 921*c18ec02fSPetter Reinholdtsen } 922*c18ec02fSPetter Reinholdtsen free(fru_area); 923*c18ec02fSPetter Reinholdtsen fru_area = NULL; 924*c18ec02fSPetter Reinholdtsen } 925*c18ec02fSPetter Reinholdtsen 926*c18ec02fSPetter Reinholdtsen if (i == j) { 927*c18ec02fSPetter Reinholdtsen break; 928*c18ec02fSPetter Reinholdtsen } 929*c18ec02fSPetter Reinholdtsen } 930*c18ec02fSPetter Reinholdtsen 931*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 932*c18ec02fSPetter Reinholdtsen free(fru_data); 933*c18ec02fSPetter Reinholdtsen fru_data = NULL; 934*c18ec02fSPetter Reinholdtsen } 935*c18ec02fSPetter Reinholdtsen } 936*c18ec02fSPetter Reinholdtsen 937*c18ec02fSPetter Reinholdtsen /* fru_area_print_board - Print FRU Board Area 938*c18ec02fSPetter Reinholdtsen * 939*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 940*c18ec02fSPetter Reinholdtsen * @fru: fru info 941*c18ec02fSPetter Reinholdtsen * @id: fru id 942*c18ec02fSPetter Reinholdtsen * @offset: offset pointer 943*c18ec02fSPetter Reinholdtsen */ 944*c18ec02fSPetter Reinholdtsen static void 945*c18ec02fSPetter Reinholdtsen fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru, 946*c18ec02fSPetter Reinholdtsen uint8_t id, uint32_t offset) 947*c18ec02fSPetter Reinholdtsen { 948*c18ec02fSPetter Reinholdtsen char * fru_area; 949*c18ec02fSPetter Reinholdtsen uint8_t * fru_data; 950*c18ec02fSPetter Reinholdtsen uint32_t fru_len; 951*c18ec02fSPetter Reinholdtsen uint32_t i; 952*c18ec02fSPetter Reinholdtsen time_t tval; 953*c18ec02fSPetter Reinholdtsen uint8_t tmp[2]; 954*c18ec02fSPetter Reinholdtsen 955*c18ec02fSPetter Reinholdtsen fru_len = 0; 956*c18ec02fSPetter Reinholdtsen 957*c18ec02fSPetter Reinholdtsen /* read enough to check length field */ 958*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) { 959*c18ec02fSPetter Reinholdtsen fru_len = 8 * tmp[1]; 960*c18ec02fSPetter Reinholdtsen } 961*c18ec02fSPetter Reinholdtsen 962*c18ec02fSPetter Reinholdtsen if (fru_len <= 0) { 963*c18ec02fSPetter Reinholdtsen return; 964*c18ec02fSPetter Reinholdtsen } 965*c18ec02fSPetter Reinholdtsen 966*c18ec02fSPetter Reinholdtsen fru_data = malloc(fru_len); 967*c18ec02fSPetter Reinholdtsen if (fru_data == NULL) { 968*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 969*c18ec02fSPetter Reinholdtsen return; 970*c18ec02fSPetter Reinholdtsen } 971*c18ec02fSPetter Reinholdtsen 972*c18ec02fSPetter Reinholdtsen memset(fru_data, 0, fru_len); 973*c18ec02fSPetter Reinholdtsen 974*c18ec02fSPetter Reinholdtsen /* read in the full fru */ 975*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) { 976*c18ec02fSPetter Reinholdtsen free(fru_data); 977*c18ec02fSPetter Reinholdtsen fru_data = NULL; 978*c18ec02fSPetter Reinholdtsen return; 979*c18ec02fSPetter Reinholdtsen } 980*c18ec02fSPetter Reinholdtsen 981*c18ec02fSPetter Reinholdtsen /* 982*c18ec02fSPetter Reinholdtsen * skip first three bytes which specify 983*c18ec02fSPetter Reinholdtsen * fru area version, fru area length 984*c18ec02fSPetter Reinholdtsen * and fru board language 985*c18ec02fSPetter Reinholdtsen */ 986*c18ec02fSPetter Reinholdtsen i = 3; 987*c18ec02fSPetter Reinholdtsen 988*c18ec02fSPetter Reinholdtsen tval=((fru_data[i+2] << 16) + (fru_data[i+1] << 8) + (fru_data[i])); 989*c18ec02fSPetter Reinholdtsen tval=tval * 60; 990*c18ec02fSPetter Reinholdtsen tval=tval + secs_from_1970_1996; 991*c18ec02fSPetter Reinholdtsen printf(" Board Mfg Date : %s", asctime(localtime(&tval))); 992*c18ec02fSPetter Reinholdtsen i += 3; /* skip mfg. date time */ 993*c18ec02fSPetter Reinholdtsen 994*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 995*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 996*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 997*c18ec02fSPetter Reinholdtsen printf(" Board Mfg : %s\n", fru_area); 998*c18ec02fSPetter Reinholdtsen } 999*c18ec02fSPetter Reinholdtsen free(fru_area); 1000*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1001*c18ec02fSPetter Reinholdtsen } 1002*c18ec02fSPetter Reinholdtsen 1003*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1004*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1005*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1006*c18ec02fSPetter Reinholdtsen printf(" Board Product : %s\n", fru_area); 1007*c18ec02fSPetter Reinholdtsen } 1008*c18ec02fSPetter Reinholdtsen free(fru_area); 1009*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1010*c18ec02fSPetter Reinholdtsen } 1011*c18ec02fSPetter Reinholdtsen 1012*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1013*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1014*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1015*c18ec02fSPetter Reinholdtsen printf(" Board Serial : %s\n", fru_area); 1016*c18ec02fSPetter Reinholdtsen } 1017*c18ec02fSPetter Reinholdtsen free(fru_area); 1018*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1019*c18ec02fSPetter Reinholdtsen } 1020*c18ec02fSPetter Reinholdtsen 1021*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1022*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1023*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1024*c18ec02fSPetter Reinholdtsen printf(" Board Part Number : %s\n", fru_area); 1025*c18ec02fSPetter Reinholdtsen } 1026*c18ec02fSPetter Reinholdtsen free(fru_area); 1027*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1028*c18ec02fSPetter Reinholdtsen } 1029*c18ec02fSPetter Reinholdtsen 1030*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1031*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1032*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0 && verbose > 0) { 1033*c18ec02fSPetter Reinholdtsen printf(" Board FRU ID : %s\n", fru_area); 1034*c18ec02fSPetter Reinholdtsen } 1035*c18ec02fSPetter Reinholdtsen free(fru_area); 1036*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1037*c18ec02fSPetter Reinholdtsen } 1038*c18ec02fSPetter Reinholdtsen 1039*c18ec02fSPetter Reinholdtsen /* read any extra fields */ 1040*c18ec02fSPetter Reinholdtsen while ((fru_data[i] != 0xc1) && (i < fru_len)) 1041*c18ec02fSPetter Reinholdtsen { 1042*c18ec02fSPetter Reinholdtsen int j = i; 1043*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1044*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1045*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1046*c18ec02fSPetter Reinholdtsen printf(" Board Extra : %s\n", fru_area); 1047*c18ec02fSPetter Reinholdtsen } 1048*c18ec02fSPetter Reinholdtsen free(fru_area); 1049*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1050*c18ec02fSPetter Reinholdtsen } 1051*c18ec02fSPetter Reinholdtsen if (i == j) 1052*c18ec02fSPetter Reinholdtsen break; 1053*c18ec02fSPetter Reinholdtsen } 1054*c18ec02fSPetter Reinholdtsen 1055*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1056*c18ec02fSPetter Reinholdtsen free(fru_data); 1057*c18ec02fSPetter Reinholdtsen fru_data = NULL; 1058*c18ec02fSPetter Reinholdtsen } 1059*c18ec02fSPetter Reinholdtsen } 1060*c18ec02fSPetter Reinholdtsen 1061*c18ec02fSPetter Reinholdtsen /* fru_area_print_product - Print FRU Product Area 1062*c18ec02fSPetter Reinholdtsen * 1063*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 1064*c18ec02fSPetter Reinholdtsen * @fru: fru info 1065*c18ec02fSPetter Reinholdtsen * @id: fru id 1066*c18ec02fSPetter Reinholdtsen * @offset: offset pointer 1067*c18ec02fSPetter Reinholdtsen */ 1068*c18ec02fSPetter Reinholdtsen static void 1069*c18ec02fSPetter Reinholdtsen fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru, 1070*c18ec02fSPetter Reinholdtsen uint8_t id, uint32_t offset) 1071*c18ec02fSPetter Reinholdtsen { 1072*c18ec02fSPetter Reinholdtsen char * fru_area; 1073*c18ec02fSPetter Reinholdtsen uint8_t * fru_data; 1074*c18ec02fSPetter Reinholdtsen uint32_t fru_len, i; 1075*c18ec02fSPetter Reinholdtsen uint8_t tmp[2]; 1076*c18ec02fSPetter Reinholdtsen 1077*c18ec02fSPetter Reinholdtsen fru_len = 0; 1078*c18ec02fSPetter Reinholdtsen 1079*c18ec02fSPetter Reinholdtsen /* read enough to check length field */ 1080*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) { 1081*c18ec02fSPetter Reinholdtsen fru_len = 8 * tmp[1]; 1082*c18ec02fSPetter Reinholdtsen } 1083*c18ec02fSPetter Reinholdtsen 1084*c18ec02fSPetter Reinholdtsen if (fru_len == 0) { 1085*c18ec02fSPetter Reinholdtsen return; 1086*c18ec02fSPetter Reinholdtsen } 1087*c18ec02fSPetter Reinholdtsen 1088*c18ec02fSPetter Reinholdtsen fru_data = malloc(fru_len); 1089*c18ec02fSPetter Reinholdtsen if (fru_data == NULL) { 1090*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 1091*c18ec02fSPetter Reinholdtsen return; 1092*c18ec02fSPetter Reinholdtsen } 1093*c18ec02fSPetter Reinholdtsen 1094*c18ec02fSPetter Reinholdtsen memset(fru_data, 0, fru_len); 1095*c18ec02fSPetter Reinholdtsen 1096*c18ec02fSPetter Reinholdtsen 1097*c18ec02fSPetter Reinholdtsen /* read in the full fru */ 1098*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) { 1099*c18ec02fSPetter Reinholdtsen free(fru_data); 1100*c18ec02fSPetter Reinholdtsen fru_data = NULL; 1101*c18ec02fSPetter Reinholdtsen return; 1102*c18ec02fSPetter Reinholdtsen } 1103*c18ec02fSPetter Reinholdtsen 1104*c18ec02fSPetter Reinholdtsen /* 1105*c18ec02fSPetter Reinholdtsen * skip first three bytes which specify 1106*c18ec02fSPetter Reinholdtsen * fru area version, fru area length 1107*c18ec02fSPetter Reinholdtsen * and fru board language 1108*c18ec02fSPetter Reinholdtsen */ 1109*c18ec02fSPetter Reinholdtsen i = 3; 1110*c18ec02fSPetter Reinholdtsen 1111*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1112*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1113*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1114*c18ec02fSPetter Reinholdtsen printf(" Product Manufacturer : %s\n", fru_area); 1115*c18ec02fSPetter Reinholdtsen } 1116*c18ec02fSPetter Reinholdtsen free(fru_area); 1117*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1118*c18ec02fSPetter Reinholdtsen } 1119*c18ec02fSPetter Reinholdtsen 1120*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1121*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1122*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1123*c18ec02fSPetter Reinholdtsen printf(" Product Name : %s\n", fru_area); 1124*c18ec02fSPetter Reinholdtsen } 1125*c18ec02fSPetter Reinholdtsen free(fru_area); 1126*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1127*c18ec02fSPetter Reinholdtsen } 1128*c18ec02fSPetter Reinholdtsen 1129*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1130*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1131*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1132*c18ec02fSPetter Reinholdtsen printf(" Product Part Number : %s\n", fru_area); 1133*c18ec02fSPetter Reinholdtsen } 1134*c18ec02fSPetter Reinholdtsen free(fru_area); 1135*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1136*c18ec02fSPetter Reinholdtsen } 1137*c18ec02fSPetter Reinholdtsen 1138*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1139*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1140*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1141*c18ec02fSPetter Reinholdtsen printf(" Product Version : %s\n", fru_area); 1142*c18ec02fSPetter Reinholdtsen } 1143*c18ec02fSPetter Reinholdtsen free(fru_area); 1144*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1145*c18ec02fSPetter Reinholdtsen } 1146*c18ec02fSPetter Reinholdtsen 1147*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1148*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1149*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1150*c18ec02fSPetter Reinholdtsen printf(" Product Serial : %s\n", fru_area); 1151*c18ec02fSPetter Reinholdtsen } 1152*c18ec02fSPetter Reinholdtsen free(fru_area); 1153*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1154*c18ec02fSPetter Reinholdtsen } 1155*c18ec02fSPetter Reinholdtsen 1156*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1157*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1158*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1159*c18ec02fSPetter Reinholdtsen printf(" Product Asset Tag : %s\n", fru_area); 1160*c18ec02fSPetter Reinholdtsen } 1161*c18ec02fSPetter Reinholdtsen free(fru_area); 1162*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1163*c18ec02fSPetter Reinholdtsen } 1164*c18ec02fSPetter Reinholdtsen 1165*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1166*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1167*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0 && verbose > 0) { 1168*c18ec02fSPetter Reinholdtsen printf(" Product FRU ID : %s\n", fru_area); 1169*c18ec02fSPetter Reinholdtsen } 1170*c18ec02fSPetter Reinholdtsen free(fru_area); 1171*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1172*c18ec02fSPetter Reinholdtsen } 1173*c18ec02fSPetter Reinholdtsen 1174*c18ec02fSPetter Reinholdtsen /* read any extra fields */ 1175*c18ec02fSPetter Reinholdtsen while ((fru_data[i] != 0xc1) && (i < fru_len)) 1176*c18ec02fSPetter Reinholdtsen { 1177*c18ec02fSPetter Reinholdtsen int j = i; 1178*c18ec02fSPetter Reinholdtsen fru_area = get_fru_area_str(fru_data, &i); 1179*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1180*c18ec02fSPetter Reinholdtsen if (strlen(fru_area) > 0) { 1181*c18ec02fSPetter Reinholdtsen printf(" Product Extra : %s\n", fru_area); 1182*c18ec02fSPetter Reinholdtsen } 1183*c18ec02fSPetter Reinholdtsen free(fru_area); 1184*c18ec02fSPetter Reinholdtsen fru_area = NULL; 1185*c18ec02fSPetter Reinholdtsen } 1186*c18ec02fSPetter Reinholdtsen if (i == j) 1187*c18ec02fSPetter Reinholdtsen break; 1188*c18ec02fSPetter Reinholdtsen } 1189*c18ec02fSPetter Reinholdtsen 1190*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 1191*c18ec02fSPetter Reinholdtsen free(fru_data); 1192*c18ec02fSPetter Reinholdtsen fru_data = NULL; 1193*c18ec02fSPetter Reinholdtsen } 1194*c18ec02fSPetter Reinholdtsen } 1195*c18ec02fSPetter Reinholdtsen 1196*c18ec02fSPetter Reinholdtsen /* fru_area_print_multirec - Print FRU Multi Record Area 1197*c18ec02fSPetter Reinholdtsen * 1198*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 1199*c18ec02fSPetter Reinholdtsen * @fru: fru info 1200*c18ec02fSPetter Reinholdtsen * @id: fru id 1201*c18ec02fSPetter Reinholdtsen * @offset: offset pointer 1202*c18ec02fSPetter Reinholdtsen */ 1203*c18ec02fSPetter Reinholdtsen static void 1204*c18ec02fSPetter Reinholdtsen fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru, 1205*c18ec02fSPetter Reinholdtsen uint8_t id, uint32_t offset) 1206*c18ec02fSPetter Reinholdtsen { 1207*c18ec02fSPetter Reinholdtsen uint8_t * fru_data; 1208*c18ec02fSPetter Reinholdtsen struct fru_multirec_header * h; 1209*c18ec02fSPetter Reinholdtsen struct fru_multirec_powersupply * ps; 1210*c18ec02fSPetter Reinholdtsen struct fru_multirec_dcoutput * dc; 1211*c18ec02fSPetter Reinholdtsen struct fru_multirec_dcload * dl; 1212*c18ec02fSPetter Reinholdtsen uint16_t peak_capacity; 1213*c18ec02fSPetter Reinholdtsen uint8_t peak_hold_up_time; 1214*c18ec02fSPetter Reinholdtsen uint32_t last_off; 1215*c18ec02fSPetter Reinholdtsen 1216*c18ec02fSPetter Reinholdtsen last_off = offset; 1217*c18ec02fSPetter Reinholdtsen 1218*c18ec02fSPetter Reinholdtsen fru_data = malloc(FRU_MULTIREC_CHUNK_SIZE); 1219*c18ec02fSPetter Reinholdtsen if (fru_data == NULL) { 1220*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 1221*c18ec02fSPetter Reinholdtsen return; 1222*c18ec02fSPetter Reinholdtsen } 1223*c18ec02fSPetter Reinholdtsen 1224*c18ec02fSPetter Reinholdtsen memset(fru_data, 0, FRU_MULTIREC_CHUNK_SIZE); 1225*c18ec02fSPetter Reinholdtsen 1226*c18ec02fSPetter Reinholdtsen h = (struct fru_multirec_header *) (fru_data); 1227*c18ec02fSPetter Reinholdtsen 1228*c18ec02fSPetter Reinholdtsen do { 1229*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, fru, id, last_off, sizeof(*h), fru_data) < 0) { 1230*c18ec02fSPetter Reinholdtsen break; 1231*c18ec02fSPetter Reinholdtsen } 1232*c18ec02fSPetter Reinholdtsen 1233*c18ec02fSPetter Reinholdtsen if (h->len && read_fru_area(intf, fru, id, 1234*c18ec02fSPetter Reinholdtsen last_off + sizeof(*h), h->len, fru_data + sizeof(*h)) < 0) { 1235*c18ec02fSPetter Reinholdtsen break; 1236*c18ec02fSPetter Reinholdtsen } 1237*c18ec02fSPetter Reinholdtsen 1238*c18ec02fSPetter Reinholdtsen last_off += h->len + sizeof(*h); 1239*c18ec02fSPetter Reinholdtsen 1240*c18ec02fSPetter Reinholdtsen switch (h->type) { 1241*c18ec02fSPetter Reinholdtsen case FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION: 1242*c18ec02fSPetter Reinholdtsen ps = (struct fru_multirec_powersupply *) 1243*c18ec02fSPetter Reinholdtsen (fru_data + sizeof(struct fru_multirec_header)); 1244*c18ec02fSPetter Reinholdtsen 1245*c18ec02fSPetter Reinholdtsen #if WORDS_BIGENDIAN 1246*c18ec02fSPetter Reinholdtsen ps->capacity = BSWAP_16(ps->capacity); 1247*c18ec02fSPetter Reinholdtsen ps->peak_va = BSWAP_16(ps->peak_va); 1248*c18ec02fSPetter Reinholdtsen ps->lowend_input1 = BSWAP_16(ps->lowend_input1); 1249*c18ec02fSPetter Reinholdtsen ps->highend_input1 = BSWAP_16(ps->highend_input1); 1250*c18ec02fSPetter Reinholdtsen ps->lowend_input2 = BSWAP_16(ps->lowend_input2); 1251*c18ec02fSPetter Reinholdtsen ps->highend_input2 = BSWAP_16(ps->highend_input2); 1252*c18ec02fSPetter Reinholdtsen ps->combined_capacity = BSWAP_16(ps->combined_capacity); 1253*c18ec02fSPetter Reinholdtsen ps->peak_cap_ht = BSWAP_16(ps->peak_cap_ht); 1254*c18ec02fSPetter Reinholdtsen #endif 1255*c18ec02fSPetter Reinholdtsen peak_hold_up_time = (ps->peak_cap_ht & 0xf000) >> 12; 1256*c18ec02fSPetter Reinholdtsen peak_capacity = ps->peak_cap_ht & 0x0fff; 1257*c18ec02fSPetter Reinholdtsen 1258*c18ec02fSPetter Reinholdtsen printf (" Power Supply Record\n"); 1259*c18ec02fSPetter Reinholdtsen printf (" Capacity : %d W\n", 1260*c18ec02fSPetter Reinholdtsen ps->capacity); 1261*c18ec02fSPetter Reinholdtsen printf (" Peak VA : %d VA\n", 1262*c18ec02fSPetter Reinholdtsen ps->peak_va); 1263*c18ec02fSPetter Reinholdtsen printf (" Inrush Current : %d A\n", 1264*c18ec02fSPetter Reinholdtsen ps->inrush_current); 1265*c18ec02fSPetter Reinholdtsen printf (" Inrush Interval : %d ms\n", 1266*c18ec02fSPetter Reinholdtsen ps->inrush_interval); 1267*c18ec02fSPetter Reinholdtsen printf (" Input Voltage Range 1 : %d-%d V\n", 1268*c18ec02fSPetter Reinholdtsen ps->lowend_input1 / 100, ps->highend_input1 / 100); 1269*c18ec02fSPetter Reinholdtsen printf (" Input Voltage Range 2 : %d-%d V\n", 1270*c18ec02fSPetter Reinholdtsen ps->lowend_input2 / 100, ps->highend_input2 / 100); 1271*c18ec02fSPetter Reinholdtsen printf (" Input Frequency Range : %d-%d Hz\n", 1272*c18ec02fSPetter Reinholdtsen ps->lowend_freq, ps->highend_freq); 1273*c18ec02fSPetter Reinholdtsen printf (" A/C Dropout Tolerance : %d ms\n", 1274*c18ec02fSPetter Reinholdtsen ps->dropout_tolerance); 1275*c18ec02fSPetter Reinholdtsen printf (" Flags : %s%s%s%s%s\n", 1276*c18ec02fSPetter Reinholdtsen ps->predictive_fail ? "'Predictive fail' " : "", 1277*c18ec02fSPetter Reinholdtsen ps->pfc ? "'Power factor correction' " : "", 1278*c18ec02fSPetter Reinholdtsen ps->autoswitch ? "'Autoswitch voltage' " : "", 1279*c18ec02fSPetter Reinholdtsen ps->hotswap ? "'Hot swap' " : "", 1280*c18ec02fSPetter Reinholdtsen ps->predictive_fail ? ps->rps_threshold ? 1281*c18ec02fSPetter Reinholdtsen ps->tach ? "'Two pulses per rotation'" : "'One pulse per rotation'" : 1282*c18ec02fSPetter Reinholdtsen ps->tach ? "'Failure on pin de-assertion'" : "'Failure on pin assertion'" : ""); 1283*c18ec02fSPetter Reinholdtsen printf (" Peak capacity : %d W\n", 1284*c18ec02fSPetter Reinholdtsen peak_capacity); 1285*c18ec02fSPetter Reinholdtsen printf (" Peak capacity holdup : %d s\n", 1286*c18ec02fSPetter Reinholdtsen peak_hold_up_time); 1287*c18ec02fSPetter Reinholdtsen if (ps->combined_capacity == 0) 1288*c18ec02fSPetter Reinholdtsen printf (" Combined capacity : not specified\n"); 1289*c18ec02fSPetter Reinholdtsen else 1290*c18ec02fSPetter Reinholdtsen printf (" Combined capacity : %d W (%s and %s)\n", 1291*c18ec02fSPetter Reinholdtsen ps->combined_capacity, 1292*c18ec02fSPetter Reinholdtsen combined_voltage_desc [ps->combined_voltage1], 1293*c18ec02fSPetter Reinholdtsen combined_voltage_desc [ps->combined_voltage2]); 1294*c18ec02fSPetter Reinholdtsen if (ps->predictive_fail) 1295*c18ec02fSPetter Reinholdtsen printf (" Fan lower threshold : %d RPS\n", 1296*c18ec02fSPetter Reinholdtsen ps->rps_threshold); 1297*c18ec02fSPetter Reinholdtsen break; 1298*c18ec02fSPetter Reinholdtsen 1299*c18ec02fSPetter Reinholdtsen case FRU_RECORD_TYPE_DC_OUTPUT: 1300*c18ec02fSPetter Reinholdtsen dc = (struct fru_multirec_dcoutput *) 1301*c18ec02fSPetter Reinholdtsen (fru_data + sizeof(struct fru_multirec_header)); 1302*c18ec02fSPetter Reinholdtsen 1303*c18ec02fSPetter Reinholdtsen #if WORDS_BIGENDIAN 1304*c18ec02fSPetter Reinholdtsen dc->nominal_voltage = BSWAP_16(dc->nominal_voltage); 1305*c18ec02fSPetter Reinholdtsen dc->max_neg_dev = BSWAP_16(dc->max_neg_dev); 1306*c18ec02fSPetter Reinholdtsen dc->max_pos_dev = BSWAP_16(dc->max_pos_dev); 1307*c18ec02fSPetter Reinholdtsen dc->ripple_and_noise = BSWAP_16(dc->ripple_and_noise); 1308*c18ec02fSPetter Reinholdtsen dc->min_current = BSWAP_16(dc->min_current); 1309*c18ec02fSPetter Reinholdtsen dc->max_current = BSWAP_16(dc->max_current); 1310*c18ec02fSPetter Reinholdtsen #endif 1311*c18ec02fSPetter Reinholdtsen 1312*c18ec02fSPetter Reinholdtsen printf (" DC Output Record\n"); 1313*c18ec02fSPetter Reinholdtsen printf (" Output Number : %d\n", 1314*c18ec02fSPetter Reinholdtsen dc->output_number); 1315*c18ec02fSPetter Reinholdtsen printf (" Standby power : %s\n", 1316*c18ec02fSPetter Reinholdtsen dc->standby ? "Yes" : "No"); 1317*c18ec02fSPetter Reinholdtsen printf (" Nominal voltage : %.2f V\n", 1318*c18ec02fSPetter Reinholdtsen (double) dc->nominal_voltage / 100); 1319*c18ec02fSPetter Reinholdtsen printf (" Max negative deviation : %.2f V\n", 1320*c18ec02fSPetter Reinholdtsen (double) dc->max_neg_dev / 100); 1321*c18ec02fSPetter Reinholdtsen printf (" Max positive deviation : %.2f V\n", 1322*c18ec02fSPetter Reinholdtsen (double) dc->max_pos_dev / 100); 1323*c18ec02fSPetter Reinholdtsen printf (" Ripple and noise pk-pk : %d mV\n", 1324*c18ec02fSPetter Reinholdtsen dc->ripple_and_noise); 1325*c18ec02fSPetter Reinholdtsen printf (" Minimum current draw : %.3f A\n", 1326*c18ec02fSPetter Reinholdtsen (double) dc->min_current / 1000); 1327*c18ec02fSPetter Reinholdtsen printf (" Maximum current draw : %.3f A\n", 1328*c18ec02fSPetter Reinholdtsen (double) dc->max_current / 1000); 1329*c18ec02fSPetter Reinholdtsen break; 1330*c18ec02fSPetter Reinholdtsen 1331*c18ec02fSPetter Reinholdtsen case FRU_RECORD_TYPE_DC_LOAD: 1332*c18ec02fSPetter Reinholdtsen dl = (struct fru_multirec_dcload *) 1333*c18ec02fSPetter Reinholdtsen (fru_data + sizeof(struct fru_multirec_header)); 1334*c18ec02fSPetter Reinholdtsen 1335*c18ec02fSPetter Reinholdtsen #if WORDS_BIGENDIAN 1336*c18ec02fSPetter Reinholdtsen dl->nominal_voltage = BSWAP_16(dl->nominal_voltage); 1337*c18ec02fSPetter Reinholdtsen dl->min_voltage = BSWAP_16(dl->min_voltage); 1338*c18ec02fSPetter Reinholdtsen dl->max_voltage = BSWAP_16(dl->max_voltage); 1339*c18ec02fSPetter Reinholdtsen dl->ripple_and_noise = BSWAP_16(dl->ripple_and_noise); 1340*c18ec02fSPetter Reinholdtsen dl->min_current = BSWAP_16(dl->min_current); 1341*c18ec02fSPetter Reinholdtsen dl->max_current = BSWAP_16(dl->max_current); 1342*c18ec02fSPetter Reinholdtsen #endif 1343*c18ec02fSPetter Reinholdtsen 1344*c18ec02fSPetter Reinholdtsen printf (" DC Load Record\n"); 1345*c18ec02fSPetter Reinholdtsen printf (" Output Number : %d\n", 1346*c18ec02fSPetter Reinholdtsen dl->output_number); 1347*c18ec02fSPetter Reinholdtsen printf (" Nominal voltage : %.2f V\n", 1348*c18ec02fSPetter Reinholdtsen (double) dl->nominal_voltage / 100); 1349*c18ec02fSPetter Reinholdtsen printf (" Min voltage allowed : %.2f V\n", 1350*c18ec02fSPetter Reinholdtsen (double) dl->min_voltage / 100); 1351*c18ec02fSPetter Reinholdtsen printf (" Max voltage allowed : %.2f V\n", 1352*c18ec02fSPetter Reinholdtsen (double) dl->max_voltage / 100); 1353*c18ec02fSPetter Reinholdtsen printf (" Ripple and noise pk-pk : %d mV\n", 1354*c18ec02fSPetter Reinholdtsen dl->ripple_and_noise); 1355*c18ec02fSPetter Reinholdtsen printf (" Minimum current load : %.3f A\n", 1356*c18ec02fSPetter Reinholdtsen (double) dl->min_current / 1000); 1357*c18ec02fSPetter Reinholdtsen printf (" Maximum current load : %.3f A\n", 1358*c18ec02fSPetter Reinholdtsen (double) dl->max_current / 1000); 1359*c18ec02fSPetter Reinholdtsen break; 1360*c18ec02fSPetter Reinholdtsen case FRU_RECORD_TYPE_OEM_EXTENSION: 1361*c18ec02fSPetter Reinholdtsen { 1362*c18ec02fSPetter Reinholdtsen struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *) 1363*c18ec02fSPetter Reinholdtsen &fru_data[sizeof(struct fru_multirec_header)]; 1364*c18ec02fSPetter Reinholdtsen uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16; 1365*c18ec02fSPetter Reinholdtsen 1366*c18ec02fSPetter Reinholdtsen /* Now makes sure this is really PICMG record */ 1367*c18ec02fSPetter Reinholdtsen 1368*c18ec02fSPetter Reinholdtsen if( iana == IPMI_OEM_PICMG ){ 1369*c18ec02fSPetter Reinholdtsen printf(" PICMG Extension Record\n"); 1370*c18ec02fSPetter Reinholdtsen ipmi_fru_picmg_ext_print(fru_data, 1371*c18ec02fSPetter Reinholdtsen sizeof(struct fru_multirec_header), 1372*c18ec02fSPetter Reinholdtsen h->len); 1373*c18ec02fSPetter Reinholdtsen } 1374*c18ec02fSPetter Reinholdtsen /* FIXME: Add OEM record support here */ 1375*c18ec02fSPetter Reinholdtsen else{ 1376*c18ec02fSPetter Reinholdtsen printf(" OEM (%s) Record\n", val2str( iana, ipmi_oem_info)); 1377*c18ec02fSPetter Reinholdtsen } 1378*c18ec02fSPetter Reinholdtsen } 1379*c18ec02fSPetter Reinholdtsen break; 1380*c18ec02fSPetter Reinholdtsen } 1381*c18ec02fSPetter Reinholdtsen } while (!(h->format & 0x80)); 1382*c18ec02fSPetter Reinholdtsen 1383*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)", last_off, last_off); 1384*c18ec02fSPetter Reinholdtsen 1385*c18ec02fSPetter Reinholdtsen free(fru_data); 1386*c18ec02fSPetter Reinholdtsen } 1387*c18ec02fSPetter Reinholdtsen 1388*c18ec02fSPetter Reinholdtsen /* ipmi_fru_query_new_value - Query new values to replace original FRU content 1389*c18ec02fSPetter Reinholdtsen * 1390*c18ec02fSPetter Reinholdtsen * @data: FRU data 1391*c18ec02fSPetter Reinholdtsen * @offset: offset of the bytes to be modified in data 1392*c18ec02fSPetter Reinholdtsen * @len: size of the modified data 1393*c18ec02fSPetter Reinholdtsen * 1394*c18ec02fSPetter Reinholdtsen * returns : TRUE if data changed 1395*c18ec02fSPetter Reinholdtsen * returns : FALSE if data not changed 1396*c18ec02fSPetter Reinholdtsen */ 1397*c18ec02fSPetter Reinholdtsen int ipmi_fru_query_new_value(uint8_t *data,int offset, size_t len) 1398*c18ec02fSPetter Reinholdtsen { 1399*c18ec02fSPetter Reinholdtsen int status=FALSE; 1400*c18ec02fSPetter Reinholdtsen int ret; 1401*c18ec02fSPetter Reinholdtsen char answer; 1402*c18ec02fSPetter Reinholdtsen 1403*c18ec02fSPetter Reinholdtsen printf("Would you like to change this value <y/n> ? "); 1404*c18ec02fSPetter Reinholdtsen ret = scanf("%c", &answer); 1405*c18ec02fSPetter Reinholdtsen if (ret != 1) { 1406*c18ec02fSPetter Reinholdtsen return FALSE; 1407*c18ec02fSPetter Reinholdtsen } 1408*c18ec02fSPetter Reinholdtsen 1409*c18ec02fSPetter Reinholdtsen if( answer == 'y' || answer == 'Y' ){ 1410*c18ec02fSPetter Reinholdtsen int i; 1411*c18ec02fSPetter Reinholdtsen unsigned int *holder; 1412*c18ec02fSPetter Reinholdtsen 1413*c18ec02fSPetter Reinholdtsen holder = malloc(len); 1414*c18ec02fSPetter Reinholdtsen printf( 1415*c18ec02fSPetter Reinholdtsen "Enter hex values for each of the %d entries (lsb first), " 1416*c18ec02fSPetter Reinholdtsen "hit <enter> between entries\n", (int)len); 1417*c18ec02fSPetter Reinholdtsen 1418*c18ec02fSPetter Reinholdtsen /* I can't assign scanf' %x into a single char */ 1419*c18ec02fSPetter Reinholdtsen for( i=0;i<len;i++ ){ 1420*c18ec02fSPetter Reinholdtsen ret = scanf("%x", holder+i); 1421*c18ec02fSPetter Reinholdtsen if (ret != 1) { 1422*c18ec02fSPetter Reinholdtsen free(holder); 1423*c18ec02fSPetter Reinholdtsen return FALSE; 1424*c18ec02fSPetter Reinholdtsen } 1425*c18ec02fSPetter Reinholdtsen } 1426*c18ec02fSPetter Reinholdtsen for( i=0;i<len;i++ ){ 1427*c18ec02fSPetter Reinholdtsen data[offset++] = (unsigned char) *(holder+i); 1428*c18ec02fSPetter Reinholdtsen } 1429*c18ec02fSPetter Reinholdtsen /* &data[offset++] */ 1430*c18ec02fSPetter Reinholdtsen free(holder); 1431*c18ec02fSPetter Reinholdtsen holder = NULL; 1432*c18ec02fSPetter Reinholdtsen status = TRUE; 1433*c18ec02fSPetter Reinholdtsen } 1434*c18ec02fSPetter Reinholdtsen else{ 1435*c18ec02fSPetter Reinholdtsen printf("Entered %c\n",answer); 1436*c18ec02fSPetter Reinholdtsen } 1437*c18ec02fSPetter Reinholdtsen 1438*c18ec02fSPetter Reinholdtsen return status; 1439*c18ec02fSPetter Reinholdtsen } 1440*c18ec02fSPetter Reinholdtsen 1441*c18ec02fSPetter Reinholdtsen /* ipmi_fru_oemkontron_edit - 1442*c18ec02fSPetter Reinholdtsen * Query new values to replace original FRU content 1443*c18ec02fSPetter Reinholdtsen * This is a generic enough to support any type of 'OEM' record 1444*c18ec02fSPetter Reinholdtsen * because the user supplies 'IANA number' , 'record Id' and 'record' version' 1445*c18ec02fSPetter Reinholdtsen * 1446*c18ec02fSPetter Reinholdtsen * However, the parser must have 'apriori' knowledge of the record format 1447*c18ec02fSPetter Reinholdtsen * The currently supported record is : 1448*c18ec02fSPetter Reinholdtsen * 1449*c18ec02fSPetter Reinholdtsen * IANA : 15000 (Kontron) 1450*c18ec02fSPetter Reinholdtsen * RECORD ID : 3 1451*c18ec02fSPetter Reinholdtsen * RECORD VERSION: 0 (or 1) 1452*c18ec02fSPetter Reinholdtsen * 1453*c18ec02fSPetter Reinholdtsen * I would have like to put that stuff in an OEM specific file, but apart for 1454*c18ec02fSPetter Reinholdtsen * the record format information, all commands are really standard 'FRU' command 1455*c18ec02fSPetter Reinholdtsen * 1456*c18ec02fSPetter Reinholdtsen * 1457*c18ec02fSPetter Reinholdtsen * @data: FRU data 1458*c18ec02fSPetter Reinholdtsen * @offset: start of the current multi record (start of header) 1459*c18ec02fSPetter Reinholdtsen * @len: len of the current record (excluding header) 1460*c18ec02fSPetter Reinholdtsen * @h: pointer to record header 1461*c18ec02fSPetter Reinholdtsen * @oh: pointer to OEM /PICMG header 1462*c18ec02fSPetter Reinholdtsen * 1463*c18ec02fSPetter Reinholdtsen * returns: TRUE if data changed 1464*c18ec02fSPetter Reinholdtsen * returns: FALSE if data not changed 1465*c18ec02fSPetter Reinholdtsen */ 1466*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_INFORMATION_RECORD 3 1467*c18ec02fSPetter Reinholdtsen 1468*c18ec02fSPetter Reinholdtsen #define EDIT_OEM_KONTRON_COMPLETE_ARG_COUNT 12 1469*c18ec02fSPetter Reinholdtsen #define GET_OEM_KONTRON_COMPLETE_ARG_COUNT 5 1470*c18ec02fSPetter Reinholdtsen /* 1471*c18ec02fSPetter Reinholdtsen ./src/ipmitool fru edit 0 1472*c18ec02fSPetter Reinholdtsen oem 15000 3 0 name instance FIELD1 FIELD2 FIELD3 crc32 1473*c18ec02fSPetter Reinholdtsen */ 1474*c18ec02fSPetter Reinholdtsen 1475*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_SUBCOMMAND_ARG_POS 2 1476*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_IANA_ARG_POS 3 1477*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_RECORDID_ARG_POS 4 1478*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_FORMAT_ARG_POS 5 1479*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_NAME_ARG_POS 6 1480*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_INSTANCE_ARG_POS 7 1481*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_VERSION_ARG_POS 8 1482*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_BUILDDATE_ARG_POS 9 1483*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_UPDATEDATE_ARG_POS 10 1484*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_CRC32_ARG_POS 11 1485*c18ec02fSPetter Reinholdtsen 1486*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_FIELD_SIZE 8 1487*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_VERSION_FIELD_SIZE 10 1488*c18ec02fSPetter Reinholdtsen 1489*c18ec02fSPetter Reinholdtsen #ifdef HAVE_PRAGMA_PACK 1490*c18ec02fSPetter Reinholdtsen #pragma pack(1) 1491*c18ec02fSPetter Reinholdtsen #endif 1492*c18ec02fSPetter Reinholdtsen typedef struct OemKontronInformationRecordV0{ 1493*c18ec02fSPetter Reinholdtsen uint8_t field1TypeLength; 1494*c18ec02fSPetter Reinholdtsen uint8_t field1[OEM_KONTRON_FIELD_SIZE]; 1495*c18ec02fSPetter Reinholdtsen uint8_t field2TypeLength; 1496*c18ec02fSPetter Reinholdtsen uint8_t field2[OEM_KONTRON_FIELD_SIZE]; 1497*c18ec02fSPetter Reinholdtsen uint8_t field3TypeLength; 1498*c18ec02fSPetter Reinholdtsen uint8_t field3[OEM_KONTRON_FIELD_SIZE]; 1499*c18ec02fSPetter Reinholdtsen uint8_t crcTypeLength; 1500*c18ec02fSPetter Reinholdtsen uint8_t crc32[OEM_KONTRON_FIELD_SIZE]; 1501*c18ec02fSPetter Reinholdtsen }tOemKontronInformationRecordV0; 1502*c18ec02fSPetter Reinholdtsen #ifdef HAVE_PRAGMA_PACK 1503*c18ec02fSPetter Reinholdtsen #pragma pack(0) 1504*c18ec02fSPetter Reinholdtsen #endif 1505*c18ec02fSPetter Reinholdtsen 1506*c18ec02fSPetter Reinholdtsen 1507*c18ec02fSPetter Reinholdtsen #ifdef HAVE_PRAGMA_PACK 1508*c18ec02fSPetter Reinholdtsen #pragma pack(1) 1509*c18ec02fSPetter Reinholdtsen #endif 1510*c18ec02fSPetter Reinholdtsen typedef struct OemKontronInformationRecordV1{ 1511*c18ec02fSPetter Reinholdtsen uint8_t field1TypeLength; 1512*c18ec02fSPetter Reinholdtsen uint8_t field1[OEM_KONTRON_VERSION_FIELD_SIZE]; 1513*c18ec02fSPetter Reinholdtsen uint8_t field2TypeLength; 1514*c18ec02fSPetter Reinholdtsen uint8_t field2[OEM_KONTRON_FIELD_SIZE]; 1515*c18ec02fSPetter Reinholdtsen uint8_t field3TypeLength; 1516*c18ec02fSPetter Reinholdtsen uint8_t field3[OEM_KONTRON_FIELD_SIZE]; 1517*c18ec02fSPetter Reinholdtsen uint8_t crcTypeLength; 1518*c18ec02fSPetter Reinholdtsen uint8_t crc32[OEM_KONTRON_FIELD_SIZE]; 1519*c18ec02fSPetter Reinholdtsen }tOemKontronInformationRecordV1; 1520*c18ec02fSPetter Reinholdtsen #ifdef HAVE_PRAGMA_PACK 1521*c18ec02fSPetter Reinholdtsen #pragma pack(0) 1522*c18ec02fSPetter Reinholdtsen #endif 1523*c18ec02fSPetter Reinholdtsen 1524*c18ec02fSPetter Reinholdtsen /* 1525*c18ec02fSPetter Reinholdtsen ./src/ipmitool fru get 0 oem iana 3 1526*c18ec02fSPetter Reinholdtsen 1527*c18ec02fSPetter Reinholdtsen */ 1528*c18ec02fSPetter Reinholdtsen 1529*c18ec02fSPetter Reinholdtsen static void ipmi_fru_oemkontron_get( int argc, char ** argv,uint8_t * fru_data, 1530*c18ec02fSPetter Reinholdtsen int off,int len, 1531*c18ec02fSPetter Reinholdtsen struct fru_multirec_header *h, 1532*c18ec02fSPetter Reinholdtsen struct fru_multirec_oem_header *oh) 1533*c18ec02fSPetter Reinholdtsen { 1534*c18ec02fSPetter Reinholdtsen static int badParams=FALSE; 1535*c18ec02fSPetter Reinholdtsen int start = off; 1536*c18ec02fSPetter Reinholdtsen int offset = start; 1537*c18ec02fSPetter Reinholdtsen int length = len; 1538*c18ec02fSPetter Reinholdtsen int i; 1539*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_multirec_oem_header); 1540*c18ec02fSPetter Reinholdtsen 1541*c18ec02fSPetter Reinholdtsen if(!badParams){ 1542*c18ec02fSPetter Reinholdtsen /* the 'OEM' field is already checked in caller */ 1543*c18ec02fSPetter Reinholdtsen if( argc > OEM_KONTRON_SUBCOMMAND_ARG_POS ){ 1544*c18ec02fSPetter Reinholdtsen if(strncmp("oem", argv[OEM_KONTRON_SUBCOMMAND_ARG_POS],3)){ 1545*c18ec02fSPetter Reinholdtsen printf("usage: fru get <id> <oem>\n"); 1546*c18ec02fSPetter Reinholdtsen badParams = TRUE; 1547*c18ec02fSPetter Reinholdtsen return; 1548*c18ec02fSPetter Reinholdtsen } 1549*c18ec02fSPetter Reinholdtsen } 1550*c18ec02fSPetter Reinholdtsen if( argc<GET_OEM_KONTRON_COMPLETE_ARG_COUNT ){ 1551*c18ec02fSPetter Reinholdtsen printf("usage: oem <iana> <recordid>\n"); 1552*c18ec02fSPetter Reinholdtsen printf("usage: oem 15000 3\n"); 1553*c18ec02fSPetter Reinholdtsen badParams = TRUE; 1554*c18ec02fSPetter Reinholdtsen return; 1555*c18ec02fSPetter Reinholdtsen } 1556*c18ec02fSPetter Reinholdtsen } 1557*c18ec02fSPetter Reinholdtsen 1558*c18ec02fSPetter Reinholdtsen if(!badParams){ 1559*c18ec02fSPetter Reinholdtsen 1560*c18ec02fSPetter Reinholdtsen if(oh->record_id == OEM_KONTRON_INFORMATION_RECORD ) { 1561*c18ec02fSPetter Reinholdtsen 1562*c18ec02fSPetter Reinholdtsen uint8_t version; 1563*c18ec02fSPetter Reinholdtsen 1564*c18ec02fSPetter Reinholdtsen printf("Kontron OEM Information Record\n"); 1565*c18ec02fSPetter Reinholdtsen version = oh->record_version; 1566*c18ec02fSPetter Reinholdtsen 1567*c18ec02fSPetter Reinholdtsen int blockstart; 1568*c18ec02fSPetter Reinholdtsen uint8_t blockCount; 1569*c18ec02fSPetter Reinholdtsen uint8_t blockIndex=0; 1570*c18ec02fSPetter Reinholdtsen 1571*c18ec02fSPetter Reinholdtsen unsigned int matchInstance = 0; 1572*c18ec02fSPetter Reinholdtsen uint8_t instance = 0; 1573*c18ec02fSPetter Reinholdtsen 1574*c18ec02fSPetter Reinholdtsen if (str2uchar(argv[OEM_KONTRON_INSTANCE_ARG_POS], &instance) != 0) { 1575*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, 1576*c18ec02fSPetter Reinholdtsen "Instance argument '%s' is either invalid or out of range.", 1577*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_INSTANCE_ARG_POS]); 1578*c18ec02fSPetter Reinholdtsen badParams = TRUE; 1579*c18ec02fSPetter Reinholdtsen return; 1580*c18ec02fSPetter Reinholdtsen } 1581*c18ec02fSPetter Reinholdtsen 1582*c18ec02fSPetter Reinholdtsen blockCount = fru_data[offset++]; 1583*c18ec02fSPetter Reinholdtsen 1584*c18ec02fSPetter Reinholdtsen for(blockIndex=0;blockIndex<blockCount;blockIndex++){ 1585*c18ec02fSPetter Reinholdtsen void * pRecordData; 1586*c18ec02fSPetter Reinholdtsen uint8_t nameLen; 1587*c18ec02fSPetter Reinholdtsen 1588*c18ec02fSPetter Reinholdtsen blockstart = offset; 1589*c18ec02fSPetter Reinholdtsen nameLen = ( fru_data[offset++] &= 0x3F ); 1590*c18ec02fSPetter Reinholdtsen printf(" Name: %*.*s\n",nameLen, nameLen, (const char *)(fru_data+offset)); 1591*c18ec02fSPetter Reinholdtsen 1592*c18ec02fSPetter Reinholdtsen offset+=nameLen; 1593*c18ec02fSPetter Reinholdtsen 1594*c18ec02fSPetter Reinholdtsen pRecordData = &fru_data[offset]; 1595*c18ec02fSPetter Reinholdtsen 1596*c18ec02fSPetter Reinholdtsen printf(" Record Version: %d\n", version); 1597*c18ec02fSPetter Reinholdtsen if( version == 0 ) 1598*c18ec02fSPetter Reinholdtsen { 1599*c18ec02fSPetter Reinholdtsen printf(" Version: %*.*s\n", 1600*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1601*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1602*c18ec02fSPetter Reinholdtsen ((tOemKontronInformationRecordV0 *) pRecordData)->field1); 1603*c18ec02fSPetter Reinholdtsen printf(" Build Date: %*.*s\n", 1604*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1605*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1606*c18ec02fSPetter Reinholdtsen ((tOemKontronInformationRecordV0 *) pRecordData)->field2); 1607*c18ec02fSPetter Reinholdtsen printf(" Update Date: %*.*s\n", 1608*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1609*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1610*c18ec02fSPetter Reinholdtsen ((tOemKontronInformationRecordV0 *) pRecordData)->field3); 1611*c18ec02fSPetter Reinholdtsen printf(" Checksum: %*.*s\n\n", 1612*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1613*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1614*c18ec02fSPetter Reinholdtsen ((tOemKontronInformationRecordV0 *) pRecordData)->crc32); 1615*c18ec02fSPetter Reinholdtsen matchInstance++; 1616*c18ec02fSPetter Reinholdtsen offset+= sizeof(tOemKontronInformationRecordV0); 1617*c18ec02fSPetter Reinholdtsen offset++; 1618*c18ec02fSPetter Reinholdtsen } 1619*c18ec02fSPetter Reinholdtsen else if ( version == 1 ) 1620*c18ec02fSPetter Reinholdtsen { 1621*c18ec02fSPetter Reinholdtsen printf(" Version: %*.*s\n", 1622*c18ec02fSPetter Reinholdtsen OEM_KONTRON_VERSION_FIELD_SIZE, 1623*c18ec02fSPetter Reinholdtsen OEM_KONTRON_VERSION_FIELD_SIZE, 1624*c18ec02fSPetter Reinholdtsen ((tOemKontronInformationRecordV1 *) pRecordData)->field1); 1625*c18ec02fSPetter Reinholdtsen printf(" Build Date: %*.*s\n", 1626*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1627*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1628*c18ec02fSPetter Reinholdtsen ((tOemKontronInformationRecordV1 *) pRecordData)->field2); 1629*c18ec02fSPetter Reinholdtsen printf(" Update Date: %*.*s\n", 1630*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1631*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1632*c18ec02fSPetter Reinholdtsen ((tOemKontronInformationRecordV1 *) pRecordData)->field3); 1633*c18ec02fSPetter Reinholdtsen printf(" Checksum: %*.*s\n\n", 1634*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1635*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE, 1636*c18ec02fSPetter Reinholdtsen ((tOemKontronInformationRecordV1 *) pRecordData)->crc32); 1637*c18ec02fSPetter Reinholdtsen matchInstance++; 1638*c18ec02fSPetter Reinholdtsen offset+= sizeof(tOemKontronInformationRecordV1); 1639*c18ec02fSPetter Reinholdtsen offset++; 1640*c18ec02fSPetter Reinholdtsen } 1641*c18ec02fSPetter Reinholdtsen else 1642*c18ec02fSPetter Reinholdtsen { 1643*c18ec02fSPetter Reinholdtsen printf (" Unsupported version %d\n",version); 1644*c18ec02fSPetter Reinholdtsen } 1645*c18ec02fSPetter Reinholdtsen } 1646*c18ec02fSPetter Reinholdtsen } 1647*c18ec02fSPetter Reinholdtsen } 1648*c18ec02fSPetter Reinholdtsen } 1649*c18ec02fSPetter Reinholdtsen 1650*c18ec02fSPetter Reinholdtsen static int ipmi_fru_oemkontron_edit( int argc, char ** argv,uint8_t * fru_data, 1651*c18ec02fSPetter Reinholdtsen int off,int len, 1652*c18ec02fSPetter Reinholdtsen struct fru_multirec_header *h, 1653*c18ec02fSPetter Reinholdtsen struct fru_multirec_oem_header *oh) 1654*c18ec02fSPetter Reinholdtsen { 1655*c18ec02fSPetter Reinholdtsen static int badParams=FALSE; 1656*c18ec02fSPetter Reinholdtsen int hasChanged = FALSE; 1657*c18ec02fSPetter Reinholdtsen int start = off; 1658*c18ec02fSPetter Reinholdtsen int offset = start; 1659*c18ec02fSPetter Reinholdtsen int length = len; 1660*c18ec02fSPetter Reinholdtsen int i; 1661*c18ec02fSPetter Reinholdtsen uint8_t record_id = 0; 1662*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_multirec_oem_header); 1663*c18ec02fSPetter Reinholdtsen 1664*c18ec02fSPetter Reinholdtsen if(!badParams){ 1665*c18ec02fSPetter Reinholdtsen /* the 'OEM' field is already checked in caller */ 1666*c18ec02fSPetter Reinholdtsen if( argc > OEM_KONTRON_SUBCOMMAND_ARG_POS ){ 1667*c18ec02fSPetter Reinholdtsen if(strncmp("oem", argv[OEM_KONTRON_SUBCOMMAND_ARG_POS],3)){ 1668*c18ec02fSPetter Reinholdtsen printf("usage: fru edit <id> <oem> <args...>\n"); 1669*c18ec02fSPetter Reinholdtsen badParams = TRUE; 1670*c18ec02fSPetter Reinholdtsen return hasChanged; 1671*c18ec02fSPetter Reinholdtsen } 1672*c18ec02fSPetter Reinholdtsen } 1673*c18ec02fSPetter Reinholdtsen if( argc<EDIT_OEM_KONTRON_COMPLETE_ARG_COUNT ){ 1674*c18ec02fSPetter Reinholdtsen printf("usage: oem <iana> <recordid> <format> <args...>\n"); 1675*c18ec02fSPetter Reinholdtsen printf("usage: oem 15000 3 0 <name> <instance> <field1>"\ 1676*c18ec02fSPetter Reinholdtsen " <field2> <field3> <crc32>\n"); 1677*c18ec02fSPetter Reinholdtsen badParams = TRUE; 1678*c18ec02fSPetter Reinholdtsen return hasChanged; 1679*c18ec02fSPetter Reinholdtsen } 1680*c18ec02fSPetter Reinholdtsen if (str2uchar(argv[OEM_KONTRON_RECORDID_ARG_POS], &record_id) != 0) { 1681*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, 1682*c18ec02fSPetter Reinholdtsen "Record ID argument '%s' is either invalid or out of range.", 1683*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_RECORDID_ARG_POS]); 1684*c18ec02fSPetter Reinholdtsen badParams = TRUE; 1685*c18ec02fSPetter Reinholdtsen return hasChanged; 1686*c18ec02fSPetter Reinholdtsen } 1687*c18ec02fSPetter Reinholdtsen if (record_id == OEM_KONTRON_INFORMATION_RECORD) { 1688*c18ec02fSPetter Reinholdtsen for(i=OEM_KONTRON_VERSION_ARG_POS;i<=OEM_KONTRON_CRC32_ARG_POS;i++){ 1689*c18ec02fSPetter Reinholdtsen if( (strlen(argv[i]) != OEM_KONTRON_FIELD_SIZE) && 1690*c18ec02fSPetter Reinholdtsen (strlen(argv[i]) != OEM_KONTRON_VERSION_FIELD_SIZE)) { 1691*c18ec02fSPetter Reinholdtsen printf("error: version fields must have %d characters\n", 1692*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE); 1693*c18ec02fSPetter Reinholdtsen badParams = TRUE; 1694*c18ec02fSPetter Reinholdtsen return hasChanged; 1695*c18ec02fSPetter Reinholdtsen } 1696*c18ec02fSPetter Reinholdtsen } 1697*c18ec02fSPetter Reinholdtsen } 1698*c18ec02fSPetter Reinholdtsen } 1699*c18ec02fSPetter Reinholdtsen 1700*c18ec02fSPetter Reinholdtsen if(!badParams){ 1701*c18ec02fSPetter Reinholdtsen 1702*c18ec02fSPetter Reinholdtsen if(oh->record_id == OEM_KONTRON_INFORMATION_RECORD ) { 1703*c18ec02fSPetter Reinholdtsen uint8_t formatVersion = 0; 1704*c18ec02fSPetter Reinholdtsen uint8_t version; 1705*c18ec02fSPetter Reinholdtsen 1706*c18ec02fSPetter Reinholdtsen if (str2uchar(argv[OEM_KONTRON_FORMAT_ARG_POS], &formatVersion) != 0) { 1707*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, 1708*c18ec02fSPetter Reinholdtsen "Format argument '%s' is either invalid or out of range.", 1709*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_FORMAT_ARG_POS]); 1710*c18ec02fSPetter Reinholdtsen badParams = TRUE; 1711*c18ec02fSPetter Reinholdtsen return hasChanged; 1712*c18ec02fSPetter Reinholdtsen } 1713*c18ec02fSPetter Reinholdtsen 1714*c18ec02fSPetter Reinholdtsen printf(" Kontron OEM Information Record\n"); 1715*c18ec02fSPetter Reinholdtsen version = oh->record_version; 1716*c18ec02fSPetter Reinholdtsen 1717*c18ec02fSPetter Reinholdtsen if( version == formatVersion ){ 1718*c18ec02fSPetter Reinholdtsen int blockstart; 1719*c18ec02fSPetter Reinholdtsen uint8_t blockCount; 1720*c18ec02fSPetter Reinholdtsen uint8_t blockIndex=0; 1721*c18ec02fSPetter Reinholdtsen 1722*c18ec02fSPetter Reinholdtsen uint8_t matchInstance = 0; 1723*c18ec02fSPetter Reinholdtsen uint8_t instance = 0; 1724*c18ec02fSPetter Reinholdtsen 1725*c18ec02fSPetter Reinholdtsen if (str2uchar(argv[OEM_KONTRON_INSTANCE_ARG_POS], &instance) != 0) { 1726*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, 1727*c18ec02fSPetter Reinholdtsen "Instance argument '%s' is either invalid or out of range.", 1728*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_INSTANCE_ARG_POS]); 1729*c18ec02fSPetter Reinholdtsen badParams = TRUE; 1730*c18ec02fSPetter Reinholdtsen return hasChanged; 1731*c18ec02fSPetter Reinholdtsen } 1732*c18ec02fSPetter Reinholdtsen 1733*c18ec02fSPetter Reinholdtsen blockCount = fru_data[offset++]; 1734*c18ec02fSPetter Reinholdtsen printf(" blockCount: %d\n",blockCount); 1735*c18ec02fSPetter Reinholdtsen 1736*c18ec02fSPetter Reinholdtsen for(blockIndex=0;blockIndex<blockCount;blockIndex++){ 1737*c18ec02fSPetter Reinholdtsen void * pRecordData; 1738*c18ec02fSPetter Reinholdtsen uint8_t nameLen; 1739*c18ec02fSPetter Reinholdtsen 1740*c18ec02fSPetter Reinholdtsen blockstart = offset; 1741*c18ec02fSPetter Reinholdtsen 1742*c18ec02fSPetter Reinholdtsen nameLen = ( fru_data[offset++] & 0x3F ); 1743*c18ec02fSPetter Reinholdtsen 1744*c18ec02fSPetter Reinholdtsen if( version == 0 || version == 1 ) 1745*c18ec02fSPetter Reinholdtsen { 1746*c18ec02fSPetter Reinholdtsen if(!strncmp((char *)argv[OEM_KONTRON_NAME_ARG_POS], 1747*c18ec02fSPetter Reinholdtsen (const char *)(fru_data+offset),nameLen)&& (matchInstance == instance)){ 1748*c18ec02fSPetter Reinholdtsen 1749*c18ec02fSPetter Reinholdtsen printf ("Found : %s\n",argv[OEM_KONTRON_NAME_ARG_POS]); 1750*c18ec02fSPetter Reinholdtsen offset+=nameLen; 1751*c18ec02fSPetter Reinholdtsen 1752*c18ec02fSPetter Reinholdtsen pRecordData = &fru_data[offset]; 1753*c18ec02fSPetter Reinholdtsen 1754*c18ec02fSPetter Reinholdtsen if( version == 0 ) 1755*c18ec02fSPetter Reinholdtsen { 1756*c18ec02fSPetter Reinholdtsen memcpy( ((tOemKontronInformationRecordV0 *) 1757*c18ec02fSPetter Reinholdtsen pRecordData)->field1 , 1758*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_VERSION_ARG_POS] , 1759*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE); 1760*c18ec02fSPetter Reinholdtsen memcpy( ((tOemKontronInformationRecordV0 *) 1761*c18ec02fSPetter Reinholdtsen pRecordData)->field2 , 1762*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_BUILDDATE_ARG_POS], 1763*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE); 1764*c18ec02fSPetter Reinholdtsen memcpy( ((tOemKontronInformationRecordV0 *) 1765*c18ec02fSPetter Reinholdtsen pRecordData)->field3 , 1766*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_UPDATEDATE_ARG_POS], 1767*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE); 1768*c18ec02fSPetter Reinholdtsen memcpy( ((tOemKontronInformationRecordV0 *) 1769*c18ec02fSPetter Reinholdtsen pRecordData)->crc32 , 1770*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_CRC32_ARG_POS] , 1771*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE); 1772*c18ec02fSPetter Reinholdtsen } 1773*c18ec02fSPetter Reinholdtsen else 1774*c18ec02fSPetter Reinholdtsen { 1775*c18ec02fSPetter Reinholdtsen memcpy( ((tOemKontronInformationRecordV1 *) 1776*c18ec02fSPetter Reinholdtsen pRecordData)->field1 , 1777*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_VERSION_ARG_POS] , 1778*c18ec02fSPetter Reinholdtsen OEM_KONTRON_VERSION_FIELD_SIZE); 1779*c18ec02fSPetter Reinholdtsen memcpy( ((tOemKontronInformationRecordV1 *) 1780*c18ec02fSPetter Reinholdtsen pRecordData)->field2 , 1781*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_BUILDDATE_ARG_POS], 1782*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE); 1783*c18ec02fSPetter Reinholdtsen memcpy( ((tOemKontronInformationRecordV1 *) 1784*c18ec02fSPetter Reinholdtsen pRecordData)->field3 , 1785*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_UPDATEDATE_ARG_POS], 1786*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE); 1787*c18ec02fSPetter Reinholdtsen memcpy( ((tOemKontronInformationRecordV1 *) 1788*c18ec02fSPetter Reinholdtsen pRecordData)->crc32 , 1789*c18ec02fSPetter Reinholdtsen argv[OEM_KONTRON_CRC32_ARG_POS] , 1790*c18ec02fSPetter Reinholdtsen OEM_KONTRON_FIELD_SIZE); 1791*c18ec02fSPetter Reinholdtsen } 1792*c18ec02fSPetter Reinholdtsen 1793*c18ec02fSPetter Reinholdtsen matchInstance++; 1794*c18ec02fSPetter Reinholdtsen hasChanged = TRUE; 1795*c18ec02fSPetter Reinholdtsen } 1796*c18ec02fSPetter Reinholdtsen else if(!strncmp((char *)argv[OEM_KONTRON_NAME_ARG_POS], 1797*c18ec02fSPetter Reinholdtsen (const char *)(fru_data+offset), nameLen)){ 1798*c18ec02fSPetter Reinholdtsen printf ("Skipped : %s [instance %d]\n",argv[OEM_KONTRON_NAME_ARG_POS], 1799*c18ec02fSPetter Reinholdtsen (unsigned int)matchInstance); 1800*c18ec02fSPetter Reinholdtsen matchInstance++; 1801*c18ec02fSPetter Reinholdtsen offset+=nameLen; 1802*c18ec02fSPetter Reinholdtsen } 1803*c18ec02fSPetter Reinholdtsen else { 1804*c18ec02fSPetter Reinholdtsen offset+=nameLen; 1805*c18ec02fSPetter Reinholdtsen } 1806*c18ec02fSPetter Reinholdtsen 1807*c18ec02fSPetter Reinholdtsen if( version == 0 ) 1808*c18ec02fSPetter Reinholdtsen { 1809*c18ec02fSPetter Reinholdtsen offset+= sizeof(tOemKontronInformationRecordV0); 1810*c18ec02fSPetter Reinholdtsen } 1811*c18ec02fSPetter Reinholdtsen else 1812*c18ec02fSPetter Reinholdtsen { 1813*c18ec02fSPetter Reinholdtsen offset+= sizeof(tOemKontronInformationRecordV1); 1814*c18ec02fSPetter Reinholdtsen } 1815*c18ec02fSPetter Reinholdtsen offset++; 1816*c18ec02fSPetter Reinholdtsen } 1817*c18ec02fSPetter Reinholdtsen else 1818*c18ec02fSPetter Reinholdtsen { 1819*c18ec02fSPetter Reinholdtsen printf (" Unsupported version %d\n",version); 1820*c18ec02fSPetter Reinholdtsen } 1821*c18ec02fSPetter Reinholdtsen } 1822*c18ec02fSPetter Reinholdtsen } 1823*c18ec02fSPetter Reinholdtsen else{ 1824*c18ec02fSPetter Reinholdtsen printf(" Version: %d\n",version); 1825*c18ec02fSPetter Reinholdtsen } 1826*c18ec02fSPetter Reinholdtsen } 1827*c18ec02fSPetter Reinholdtsen if( hasChanged ){ 1828*c18ec02fSPetter Reinholdtsen 1829*c18ec02fSPetter Reinholdtsen uint8_t record_checksum =0; 1830*c18ec02fSPetter Reinholdtsen uint8_t header_checksum =0; 1831*c18ec02fSPetter Reinholdtsen int index; 1832*c18ec02fSPetter Reinholdtsen 1833*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG,"Initial record checksum : %x",h->record_checksum); 1834*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG,"Initial header checksum : %x",h->header_checksum); 1835*c18ec02fSPetter Reinholdtsen for(index=0;index<length;index++){ 1836*c18ec02fSPetter Reinholdtsen record_checksum+= fru_data[start+index]; 1837*c18ec02fSPetter Reinholdtsen } 1838*c18ec02fSPetter Reinholdtsen /* Update Record checksum */ 1839*c18ec02fSPetter Reinholdtsen h->record_checksum = ~record_checksum + 1; 1840*c18ec02fSPetter Reinholdtsen 1841*c18ec02fSPetter Reinholdtsen 1842*c18ec02fSPetter Reinholdtsen for(index=0;index<(sizeof(struct fru_multirec_header) -1);index++){ 1843*c18ec02fSPetter Reinholdtsen uint8_t data= *( (uint8_t *)h+ index); 1844*c18ec02fSPetter Reinholdtsen header_checksum+=data; 1845*c18ec02fSPetter Reinholdtsen } 1846*c18ec02fSPetter Reinholdtsen /* Update header checksum */ 1847*c18ec02fSPetter Reinholdtsen h->header_checksum = ~header_checksum + 1; 1848*c18ec02fSPetter Reinholdtsen 1849*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG,"Final record checksum : %x",h->record_checksum); 1850*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG,"Final header checksum : %x",h->header_checksum); 1851*c18ec02fSPetter Reinholdtsen 1852*c18ec02fSPetter Reinholdtsen /* write back data */ 1853*c18ec02fSPetter Reinholdtsen } 1854*c18ec02fSPetter Reinholdtsen } 1855*c18ec02fSPetter Reinholdtsen 1856*c18ec02fSPetter Reinholdtsen return hasChanged; 1857*c18ec02fSPetter Reinholdtsen } 1858*c18ec02fSPetter Reinholdtsen 1859*c18ec02fSPetter Reinholdtsen /* ipmi_fru_picmg_ext_edit - Query new values to replace original FRU content 1860*c18ec02fSPetter Reinholdtsen * 1861*c18ec02fSPetter Reinholdtsen * @data: FRU data 1862*c18ec02fSPetter Reinholdtsen * @offset: start of the current multi record (start of header) 1863*c18ec02fSPetter Reinholdtsen * @len: len of the current record (excluding header) 1864*c18ec02fSPetter Reinholdtsen * @h: pointer to record header 1865*c18ec02fSPetter Reinholdtsen * @oh: pointer to OEM /PICMG header 1866*c18ec02fSPetter Reinholdtsen * 1867*c18ec02fSPetter Reinholdtsen * returns: TRUE if data changed 1868*c18ec02fSPetter Reinholdtsen * returns: FALSE if data not changed 1869*c18ec02fSPetter Reinholdtsen */ 1870*c18ec02fSPetter Reinholdtsen static int ipmi_fru_picmg_ext_edit(uint8_t * fru_data, 1871*c18ec02fSPetter Reinholdtsen int off,int len, 1872*c18ec02fSPetter Reinholdtsen struct fru_multirec_header *h, 1873*c18ec02fSPetter Reinholdtsen struct fru_multirec_oem_header *oh) 1874*c18ec02fSPetter Reinholdtsen { 1875*c18ec02fSPetter Reinholdtsen int hasChanged = FALSE; 1876*c18ec02fSPetter Reinholdtsen int start = off; 1877*c18ec02fSPetter Reinholdtsen int offset = start; 1878*c18ec02fSPetter Reinholdtsen int length = len; 1879*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_multirec_oem_header); 1880*c18ec02fSPetter Reinholdtsen 1881*c18ec02fSPetter Reinholdtsen switch (oh->record_id) 1882*c18ec02fSPetter Reinholdtsen { 1883*c18ec02fSPetter Reinholdtsen case FRU_AMC_ACTIVATION: 1884*c18ec02fSPetter Reinholdtsen printf(" FRU_AMC_ACTIVATION\n"); 1885*c18ec02fSPetter Reinholdtsen { 1886*c18ec02fSPetter Reinholdtsen int index=offset; 1887*c18ec02fSPetter Reinholdtsen uint16_t max_current; 1888*c18ec02fSPetter Reinholdtsen 1889*c18ec02fSPetter Reinholdtsen max_current = fru_data[offset]; 1890*c18ec02fSPetter Reinholdtsen max_current |= fru_data[++offset]<<8; 1891*c18ec02fSPetter Reinholdtsen 1892*c18ec02fSPetter Reinholdtsen printf(" Maximum Internal Current(@12V): %.2f A (0x%02x)\n", 1893*c18ec02fSPetter Reinholdtsen (float)max_current / 10.0f, max_current); 1894*c18ec02fSPetter Reinholdtsen 1895*c18ec02fSPetter Reinholdtsen if( ipmi_fru_query_new_value(fru_data,index,2) ){ 1896*c18ec02fSPetter Reinholdtsen max_current = fru_data[index]; 1897*c18ec02fSPetter Reinholdtsen max_current |= fru_data[++index]<<8; 1898*c18ec02fSPetter Reinholdtsen printf(" New Maximum Internal Current(@12V): %.2f A (0x%02x)\n", 1899*c18ec02fSPetter Reinholdtsen (float)max_current / 10.0f, max_current); 1900*c18ec02fSPetter Reinholdtsen hasChanged = TRUE; 1901*c18ec02fSPetter Reinholdtsen 1902*c18ec02fSPetter Reinholdtsen } 1903*c18ec02fSPetter Reinholdtsen 1904*c18ec02fSPetter Reinholdtsen printf(" Module Activation Readiness: %i sec.\n", fru_data[++offset]); 1905*c18ec02fSPetter Reinholdtsen printf(" Descriptor Count: %i\n", fru_data[++offset]); 1906*c18ec02fSPetter Reinholdtsen printf("\n"); 1907*c18ec02fSPetter Reinholdtsen 1908*c18ec02fSPetter Reinholdtsen for (++offset; 1909*c18ec02fSPetter Reinholdtsen offset < (off + length); 1910*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_picmgext_activation_record)) { 1911*c18ec02fSPetter Reinholdtsen struct fru_picmgext_activation_record * a = 1912*c18ec02fSPetter Reinholdtsen (struct fru_picmgext_activation_record *) &fru_data[offset]; 1913*c18ec02fSPetter Reinholdtsen 1914*c18ec02fSPetter Reinholdtsen printf(" IPMB-Address: 0x%x\n", a->ibmb_addr); 1915*c18ec02fSPetter Reinholdtsen printf(" Max. Module Current: %.2f A\n", (float)a->max_module_curr / 10.0f); 1916*c18ec02fSPetter Reinholdtsen 1917*c18ec02fSPetter Reinholdtsen printf("\n"); 1918*c18ec02fSPetter Reinholdtsen } 1919*c18ec02fSPetter Reinholdtsen } 1920*c18ec02fSPetter Reinholdtsen break; 1921*c18ec02fSPetter Reinholdtsen 1922*c18ec02fSPetter Reinholdtsen case FRU_AMC_CURRENT: 1923*c18ec02fSPetter Reinholdtsen printf(" FRU_AMC_CURRENT\n"); 1924*c18ec02fSPetter Reinholdtsen { 1925*c18ec02fSPetter Reinholdtsen int index=offset; 1926*c18ec02fSPetter Reinholdtsen unsigned char current; 1927*c18ec02fSPetter Reinholdtsen 1928*c18ec02fSPetter Reinholdtsen current = fru_data[index]; 1929*c18ec02fSPetter Reinholdtsen 1930*c18ec02fSPetter Reinholdtsen printf(" Current draw(@12V): %.2f A (0x%02x)\n", 1931*c18ec02fSPetter Reinholdtsen (float)current / 10.0f, current); 1932*c18ec02fSPetter Reinholdtsen 1933*c18ec02fSPetter Reinholdtsen if( ipmi_fru_query_new_value(fru_data, index, 1) ){ 1934*c18ec02fSPetter Reinholdtsen current = fru_data[index]; 1935*c18ec02fSPetter Reinholdtsen 1936*c18ec02fSPetter Reinholdtsen printf(" New Current draw(@12V): %.2f A (0x%02x)\n", 1937*c18ec02fSPetter Reinholdtsen (float)current / 10.0f, current); 1938*c18ec02fSPetter Reinholdtsen hasChanged = TRUE; 1939*c18ec02fSPetter Reinholdtsen } 1940*c18ec02fSPetter Reinholdtsen } 1941*c18ec02fSPetter Reinholdtsen break; 1942*c18ec02fSPetter Reinholdtsen } 1943*c18ec02fSPetter Reinholdtsen 1944*c18ec02fSPetter Reinholdtsen if( hasChanged ){ 1945*c18ec02fSPetter Reinholdtsen 1946*c18ec02fSPetter Reinholdtsen uint8_t record_checksum =0; 1947*c18ec02fSPetter Reinholdtsen uint8_t header_checksum =0; 1948*c18ec02fSPetter Reinholdtsen int index; 1949*c18ec02fSPetter Reinholdtsen 1950*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG,"Initial record checksum : %x",h->record_checksum); 1951*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG,"Initial header checksum : %x",h->header_checksum); 1952*c18ec02fSPetter Reinholdtsen for(index=0;index<length;index++){ 1953*c18ec02fSPetter Reinholdtsen record_checksum+= fru_data[start+index]; 1954*c18ec02fSPetter Reinholdtsen } 1955*c18ec02fSPetter Reinholdtsen /* Update Record checksum */ 1956*c18ec02fSPetter Reinholdtsen h->record_checksum = ~record_checksum + 1; 1957*c18ec02fSPetter Reinholdtsen 1958*c18ec02fSPetter Reinholdtsen 1959*c18ec02fSPetter Reinholdtsen for(index=0;index<(sizeof(struct fru_multirec_header) -1);index++){ 1960*c18ec02fSPetter Reinholdtsen uint8_t data= *( (uint8_t *)h+ index); 1961*c18ec02fSPetter Reinholdtsen header_checksum+=data; 1962*c18ec02fSPetter Reinholdtsen } 1963*c18ec02fSPetter Reinholdtsen /* Update header checksum */ 1964*c18ec02fSPetter Reinholdtsen h->header_checksum = ~header_checksum + 1; 1965*c18ec02fSPetter Reinholdtsen 1966*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG,"Final record checksum : %x",h->record_checksum); 1967*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG,"Final header checksum : %x",h->header_checksum); 1968*c18ec02fSPetter Reinholdtsen 1969*c18ec02fSPetter Reinholdtsen /* write back data */ 1970*c18ec02fSPetter Reinholdtsen } 1971*c18ec02fSPetter Reinholdtsen 1972*c18ec02fSPetter Reinholdtsen return hasChanged; 1973*c18ec02fSPetter Reinholdtsen } 1974*c18ec02fSPetter Reinholdtsen 1975*c18ec02fSPetter Reinholdtsen /* ipmi_fru_picmg_ext_print - prints OEM fru record (PICMG) 1976*c18ec02fSPetter Reinholdtsen * 1977*c18ec02fSPetter Reinholdtsen * @fru_data: FRU data 1978*c18ec02fSPetter Reinholdtsen * @offset: offset of the bytes to be modified in data 1979*c18ec02fSPetter Reinholdtsen * @length: size of the record 1980*c18ec02fSPetter Reinholdtsen * 1981*c18ec02fSPetter Reinholdtsen * returns : n/a 1982*c18ec02fSPetter Reinholdtsen */ 1983*c18ec02fSPetter Reinholdtsen static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length) 1984*c18ec02fSPetter Reinholdtsen { 1985*c18ec02fSPetter Reinholdtsen struct fru_multirec_oem_header *h; 1986*c18ec02fSPetter Reinholdtsen int guid_count; 1987*c18ec02fSPetter Reinholdtsen int offset = off; 1988*c18ec02fSPetter Reinholdtsen int start_offset = off; 1989*c18ec02fSPetter Reinholdtsen int i; 1990*c18ec02fSPetter Reinholdtsen 1991*c18ec02fSPetter Reinholdtsen h = (struct fru_multirec_oem_header *) &fru_data[offset]; 1992*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_multirec_oem_header); 1993*c18ec02fSPetter Reinholdtsen 1994*c18ec02fSPetter Reinholdtsen switch (h->record_id) 1995*c18ec02fSPetter Reinholdtsen { 1996*c18ec02fSPetter Reinholdtsen case FRU_PICMG_BACKPLANE_P2P: 1997*c18ec02fSPetter Reinholdtsen { 1998*c18ec02fSPetter Reinholdtsen uint8_t index; 1999*c18ec02fSPetter Reinholdtsen unsigned int data; 2000*c18ec02fSPetter Reinholdtsen struct fru_picmgext_slot_desc *slot_d; 2001*c18ec02fSPetter Reinholdtsen 2002*c18ec02fSPetter Reinholdtsen slot_d = 2003*c18ec02fSPetter Reinholdtsen (struct fru_picmgext_slot_desc*)&fru_data[offset]; 2004*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_picmgext_slot_desc); 2005*c18ec02fSPetter Reinholdtsen printf(" FRU_PICMG_BACKPLANE_P2P\n"); 2006*c18ec02fSPetter Reinholdtsen 2007*c18ec02fSPetter Reinholdtsen while (offset <= (start_offset+length)) { 2008*c18ec02fSPetter Reinholdtsen printf("\n"); 2009*c18ec02fSPetter Reinholdtsen printf(" Channel Type: "); 2010*c18ec02fSPetter Reinholdtsen switch (slot_d->chan_type) 2011*c18ec02fSPetter Reinholdtsen { 2012*c18ec02fSPetter Reinholdtsen case 0x00: 2013*c18ec02fSPetter Reinholdtsen case 0x07: 2014*c18ec02fSPetter Reinholdtsen printf("PICMG 2.9\n"); 2015*c18ec02fSPetter Reinholdtsen break; 2016*c18ec02fSPetter Reinholdtsen case 0x08: 2017*c18ec02fSPetter Reinholdtsen printf("Single Port Fabric IF\n"); 2018*c18ec02fSPetter Reinholdtsen break; 2019*c18ec02fSPetter Reinholdtsen case 0x09: 2020*c18ec02fSPetter Reinholdtsen printf("Double Port Fabric IF\n"); 2021*c18ec02fSPetter Reinholdtsen break; 2022*c18ec02fSPetter Reinholdtsen case 0x0a: 2023*c18ec02fSPetter Reinholdtsen printf("Full Channel Fabric IF\n"); 2024*c18ec02fSPetter Reinholdtsen break; 2025*c18ec02fSPetter Reinholdtsen case 0x0b: 2026*c18ec02fSPetter Reinholdtsen printf("Base IF\n"); 2027*c18ec02fSPetter Reinholdtsen break; 2028*c18ec02fSPetter Reinholdtsen case 0x0c: 2029*c18ec02fSPetter Reinholdtsen printf("Update Channel IF\n"); 2030*c18ec02fSPetter Reinholdtsen break; 2031*c18ec02fSPetter Reinholdtsen case 0x0d: 2032*c18ec02fSPetter Reinholdtsen printf("ShMC Cross Connect\n"); 2033*c18ec02fSPetter Reinholdtsen break; 2034*c18ec02fSPetter Reinholdtsen default: 2035*c18ec02fSPetter Reinholdtsen printf("Unknown IF (0x%x)\n", 2036*c18ec02fSPetter Reinholdtsen slot_d->chan_type); 2037*c18ec02fSPetter Reinholdtsen break; 2038*c18ec02fSPetter Reinholdtsen } 2039*c18ec02fSPetter Reinholdtsen printf(" Slot Addr. : %02x\n", 2040*c18ec02fSPetter Reinholdtsen slot_d->slot_addr ); 2041*c18ec02fSPetter Reinholdtsen printf(" Channel Count: %i\n", 2042*c18ec02fSPetter Reinholdtsen slot_d->chn_count); 2043*c18ec02fSPetter Reinholdtsen 2044*c18ec02fSPetter Reinholdtsen for (index = 0; 2045*c18ec02fSPetter Reinholdtsen index < (slot_d->chn_count); 2046*c18ec02fSPetter Reinholdtsen index++) { 2047*c18ec02fSPetter Reinholdtsen struct fru_picmgext_chn_desc *d; 2048*c18ec02fSPetter Reinholdtsen data = (fru_data[offset+0]) | 2049*c18ec02fSPetter Reinholdtsen (fru_data[offset+1] << 8) | 2050*c18ec02fSPetter Reinholdtsen (fru_data[offset+2] << 16); 2051*c18ec02fSPetter Reinholdtsen d = (struct fru_picmgext_chn_desc *)&data; 2052*c18ec02fSPetter Reinholdtsen if (verbose) { 2053*c18ec02fSPetter Reinholdtsen printf( " " 2054*c18ec02fSPetter Reinholdtsen "Chn: %02x -> " 2055*c18ec02fSPetter Reinholdtsen "Chn: %02x in " 2056*c18ec02fSPetter Reinholdtsen "Slot: %02x\n", 2057*c18ec02fSPetter Reinholdtsen d->local_chn, 2058*c18ec02fSPetter Reinholdtsen d->remote_chn, 2059*c18ec02fSPetter Reinholdtsen d->remote_slot); 2060*c18ec02fSPetter Reinholdtsen } 2061*c18ec02fSPetter Reinholdtsen offset += FRU_PICMGEXT_CHN_DESC_RECORD_SIZE; 2062*c18ec02fSPetter Reinholdtsen } 2063*c18ec02fSPetter Reinholdtsen slot_d = (struct fru_picmgext_slot_desc*)&fru_data[offset]; 2064*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_picmgext_slot_desc); 2065*c18ec02fSPetter Reinholdtsen } 2066*c18ec02fSPetter Reinholdtsen } 2067*c18ec02fSPetter Reinholdtsen break; 2068*c18ec02fSPetter Reinholdtsen 2069*c18ec02fSPetter Reinholdtsen case FRU_PICMG_ADDRESS_TABLE: 2070*c18ec02fSPetter Reinholdtsen { 2071*c18ec02fSPetter Reinholdtsen unsigned int hwaddr; 2072*c18ec02fSPetter Reinholdtsen unsigned int sitetype; 2073*c18ec02fSPetter Reinholdtsen unsigned int sitenum; 2074*c18ec02fSPetter Reinholdtsen unsigned int entries; 2075*c18ec02fSPetter Reinholdtsen unsigned int i; 2076*c18ec02fSPetter Reinholdtsen char *picmg_site_type_strings[] = { 2077*c18ec02fSPetter Reinholdtsen "AdvancedTCA Board", 2078*c18ec02fSPetter Reinholdtsen "Power Entry", 2079*c18ec02fSPetter Reinholdtsen "Shelf FRU Information", 2080*c18ec02fSPetter Reinholdtsen "Dedicated ShMC", 2081*c18ec02fSPetter Reinholdtsen "Fan Tray", 2082*c18ec02fSPetter Reinholdtsen "Fan Filter Tray", 2083*c18ec02fSPetter Reinholdtsen "Alarm", 2084*c18ec02fSPetter Reinholdtsen "AdvancedMC Module", 2085*c18ec02fSPetter Reinholdtsen "PMC", 2086*c18ec02fSPetter Reinholdtsen "Rear Transition Module"}; 2087*c18ec02fSPetter Reinholdtsen 2088*c18ec02fSPetter Reinholdtsen 2089*c18ec02fSPetter Reinholdtsen printf(" FRU_PICMG_ADDRESS_TABLE\n"); 2090*c18ec02fSPetter Reinholdtsen printf(" Type/Len: 0x%02x\n", fru_data[offset++]); 2091*c18ec02fSPetter Reinholdtsen printf(" Shelf Addr: "); 2092*c18ec02fSPetter Reinholdtsen for (i=0;i<20;i++) { 2093*c18ec02fSPetter Reinholdtsen printf("0x%02x ", fru_data[offset++]); 2094*c18ec02fSPetter Reinholdtsen } 2095*c18ec02fSPetter Reinholdtsen printf("\n"); 2096*c18ec02fSPetter Reinholdtsen 2097*c18ec02fSPetter Reinholdtsen entries = fru_data[offset++]; 2098*c18ec02fSPetter Reinholdtsen printf(" Addr Table Entries: 0x%02x\n", entries); 2099*c18ec02fSPetter Reinholdtsen 2100*c18ec02fSPetter Reinholdtsen for (i=0; i<entries; i++) { 2101*c18ec02fSPetter Reinholdtsen hwaddr = fru_data[offset]; 2102*c18ec02fSPetter Reinholdtsen sitenum = fru_data[offset + 1]; 2103*c18ec02fSPetter Reinholdtsen sitetype = fru_data[offset + 2]; 2104*c18ec02fSPetter Reinholdtsen printf( 2105*c18ec02fSPetter Reinholdtsen " HWAddr: 0x%02x (0x%02x) SiteNum: %d SiteType: 0x%02x %s\n", 2106*c18ec02fSPetter Reinholdtsen hwaddr, hwaddr * 2, 2107*c18ec02fSPetter Reinholdtsen sitenum, sitetype, 2108*c18ec02fSPetter Reinholdtsen (sitetype < 0xa) ? 2109*c18ec02fSPetter Reinholdtsen picmg_site_type_strings[sitetype] : 2110*c18ec02fSPetter Reinholdtsen "Reserved"); 2111*c18ec02fSPetter Reinholdtsen offset += 3; 2112*c18ec02fSPetter Reinholdtsen } 2113*c18ec02fSPetter Reinholdtsen } 2114*c18ec02fSPetter Reinholdtsen break; 2115*c18ec02fSPetter Reinholdtsen 2116*c18ec02fSPetter Reinholdtsen case FRU_PICMG_SHELF_POWER_DIST: 2117*c18ec02fSPetter Reinholdtsen { 2118*c18ec02fSPetter Reinholdtsen unsigned int entries; 2119*c18ec02fSPetter Reinholdtsen unsigned int feeds; 2120*c18ec02fSPetter Reinholdtsen unsigned int feedcnt; 2121*c18ec02fSPetter Reinholdtsen unsigned int hwaddr; 2122*c18ec02fSPetter Reinholdtsen unsigned int i; 2123*c18ec02fSPetter Reinholdtsen unsigned int id; 2124*c18ec02fSPetter Reinholdtsen unsigned int j; 2125*c18ec02fSPetter Reinholdtsen unsigned int maxext; 2126*c18ec02fSPetter Reinholdtsen unsigned int maxint; 2127*c18ec02fSPetter Reinholdtsen unsigned int minexp; 2128*c18ec02fSPetter Reinholdtsen 2129*c18ec02fSPetter Reinholdtsen printf(" FRU_PICMG_SHELF_POWER_DIST\n"); 2130*c18ec02fSPetter Reinholdtsen 2131*c18ec02fSPetter Reinholdtsen feeds = fru_data[offset++]; 2132*c18ec02fSPetter Reinholdtsen printf(" Number of Power Feeds: 0x%02x\n", 2133*c18ec02fSPetter Reinholdtsen feeds); 2134*c18ec02fSPetter Reinholdtsen 2135*c18ec02fSPetter Reinholdtsen for (i=0; i<feeds; i++) { 2136*c18ec02fSPetter Reinholdtsen printf(" Feed %d:\n", i); 2137*c18ec02fSPetter Reinholdtsen maxext = fru_data[offset] | 2138*c18ec02fSPetter Reinholdtsen (fru_data[offset+1] << 8); 2139*c18ec02fSPetter Reinholdtsen offset += 2; 2140*c18ec02fSPetter Reinholdtsen maxint = fru_data[offset] | 2141*c18ec02fSPetter Reinholdtsen (fru_data[offset+1] << 8); 2142*c18ec02fSPetter Reinholdtsen offset += 2; 2143*c18ec02fSPetter Reinholdtsen minexp = fru_data[offset]; 2144*c18ec02fSPetter Reinholdtsen offset += 1; 2145*c18ec02fSPetter Reinholdtsen entries = fru_data[offset]; 2146*c18ec02fSPetter Reinholdtsen offset += 1; 2147*c18ec02fSPetter Reinholdtsen 2148*c18ec02fSPetter Reinholdtsen printf( 2149*c18ec02fSPetter Reinholdtsen " Max External Current: %d.%d Amps (0x%04x)\n", 2150*c18ec02fSPetter Reinholdtsen maxext / 10, maxext % 10, maxext); 2151*c18ec02fSPetter Reinholdtsen if (maxint < 0xffff) { 2152*c18ec02fSPetter Reinholdtsen printf( 2153*c18ec02fSPetter Reinholdtsen " Max Internal Current: %d.%d Amps (0x%04x)\n", 2154*c18ec02fSPetter Reinholdtsen maxint / 10, maxint % 10, 2155*c18ec02fSPetter Reinholdtsen maxint); 2156*c18ec02fSPetter Reinholdtsen } else { 2157*c18ec02fSPetter Reinholdtsen printf( 2158*c18ec02fSPetter Reinholdtsen " Max Internal Current: Not Specified\n"); 2159*c18ec02fSPetter Reinholdtsen } 2160*c18ec02fSPetter Reinholdtsen 2161*c18ec02fSPetter Reinholdtsen if (minexp >= 0x48 && minexp <= 0x90) { 2162*c18ec02fSPetter Reinholdtsen printf( 2163*c18ec02fSPetter Reinholdtsen " Min Expected Voltage: -%02d.%dV\n", 2164*c18ec02fSPetter Reinholdtsen minexp / 2, (minexp % 2) * 5); 2165*c18ec02fSPetter Reinholdtsen } else { 2166*c18ec02fSPetter Reinholdtsen printf( 2167*c18ec02fSPetter Reinholdtsen " Min Expected Voltage: -%dV (actual invalid value 0x%x)\n", 2168*c18ec02fSPetter Reinholdtsen 36, minexp); 2169*c18ec02fSPetter Reinholdtsen } 2170*c18ec02fSPetter Reinholdtsen for (j=0; j < entries; j++) { 2171*c18ec02fSPetter Reinholdtsen hwaddr = fru_data[offset++]; 2172*c18ec02fSPetter Reinholdtsen id = fru_data[offset++]; 2173*c18ec02fSPetter Reinholdtsen printf( 2174*c18ec02fSPetter Reinholdtsen " FRU HW Addr: 0x%02x (0x%02x)", 2175*c18ec02fSPetter Reinholdtsen hwaddr, hwaddr * 2); 2176*c18ec02fSPetter Reinholdtsen printf( 2177*c18ec02fSPetter Reinholdtsen " FRU ID: 0x%02x\n", 2178*c18ec02fSPetter Reinholdtsen id); 2179*c18ec02fSPetter Reinholdtsen } 2180*c18ec02fSPetter Reinholdtsen } 2181*c18ec02fSPetter Reinholdtsen } 2182*c18ec02fSPetter Reinholdtsen break; 2183*c18ec02fSPetter Reinholdtsen 2184*c18ec02fSPetter Reinholdtsen case FRU_PICMG_SHELF_ACTIVATION: 2185*c18ec02fSPetter Reinholdtsen { 2186*c18ec02fSPetter Reinholdtsen unsigned int i; 2187*c18ec02fSPetter Reinholdtsen unsigned int count = 0; 2188*c18ec02fSPetter Reinholdtsen 2189*c18ec02fSPetter Reinholdtsen printf(" FRU_PICMG_SHELF_ACTIVATION\n"); 2190*c18ec02fSPetter Reinholdtsen printf( 2191*c18ec02fSPetter Reinholdtsen " Allowance for FRU Act Readiness: 0x%02x\n", 2192*c18ec02fSPetter Reinholdtsen fru_data[offset++]); 2193*c18ec02fSPetter Reinholdtsen 2194*c18ec02fSPetter Reinholdtsen count = fru_data[offset++]; 2195*c18ec02fSPetter Reinholdtsen printf( 2196*c18ec02fSPetter Reinholdtsen " FRU activation and Power Desc Cnt: 0x%02x\n", 2197*c18ec02fSPetter Reinholdtsen count); 2198*c18ec02fSPetter Reinholdtsen 2199*c18ec02fSPetter Reinholdtsen for (i=0; i<count; i++) { 2200*c18ec02fSPetter Reinholdtsen printf(" HW Addr: 0x%02x ", 2201*c18ec02fSPetter Reinholdtsen fru_data[offset++]); 2202*c18ec02fSPetter Reinholdtsen printf(" FRU ID: 0x%02x ", 2203*c18ec02fSPetter Reinholdtsen fru_data[offset++]); 2204*c18ec02fSPetter Reinholdtsen printf(" Max FRU Power: 0x%04x ", 2205*c18ec02fSPetter Reinholdtsen fru_data[offset+0] | 2206*c18ec02fSPetter Reinholdtsen (fru_data[offset+1]<<8)); 2207*c18ec02fSPetter Reinholdtsen offset += 2; 2208*c18ec02fSPetter Reinholdtsen printf(" Config: 0x%02x \n", 2209*c18ec02fSPetter Reinholdtsen fru_data[offset++]); 2210*c18ec02fSPetter Reinholdtsen } 2211*c18ec02fSPetter Reinholdtsen } 2212*c18ec02fSPetter Reinholdtsen break; 2213*c18ec02fSPetter Reinholdtsen 2214*c18ec02fSPetter Reinholdtsen case FRU_PICMG_SHMC_IP_CONN: 2215*c18ec02fSPetter Reinholdtsen printf(" FRU_PICMG_SHMC_IP_CONN\n"); 2216*c18ec02fSPetter Reinholdtsen break; 2217*c18ec02fSPetter Reinholdtsen 2218*c18ec02fSPetter Reinholdtsen case FRU_PICMG_BOARD_P2P: 2219*c18ec02fSPetter Reinholdtsen printf(" FRU_PICMG_BOARD_P2P\n"); 2220*c18ec02fSPetter Reinholdtsen 2221*c18ec02fSPetter Reinholdtsen guid_count = fru_data[offset++]; 2222*c18ec02fSPetter Reinholdtsen printf(" GUID count: %2d\n", guid_count); 2223*c18ec02fSPetter Reinholdtsen for (i = 0 ; i < guid_count; i++ ) { 2224*c18ec02fSPetter Reinholdtsen int j; 2225*c18ec02fSPetter Reinholdtsen printf(" GUID [%2d]: 0x", i); 2226*c18ec02fSPetter Reinholdtsen 2227*c18ec02fSPetter Reinholdtsen for (j=0; j < sizeof(struct fru_picmgext_guid); 2228*c18ec02fSPetter Reinholdtsen j++) { 2229*c18ec02fSPetter Reinholdtsen printf("%02x", fru_data[offset+j]); 2230*c18ec02fSPetter Reinholdtsen } 2231*c18ec02fSPetter Reinholdtsen 2232*c18ec02fSPetter Reinholdtsen printf("\n"); 2233*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_picmgext_guid); 2234*c18ec02fSPetter Reinholdtsen } 2235*c18ec02fSPetter Reinholdtsen printf("\n"); 2236*c18ec02fSPetter Reinholdtsen 2237*c18ec02fSPetter Reinholdtsen for (; offset < off + length; 2238*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_picmgext_link_desc)) { 2239*c18ec02fSPetter Reinholdtsen 2240*c18ec02fSPetter Reinholdtsen /* to solve little endian /big endian problem */ 2241*c18ec02fSPetter Reinholdtsen struct fru_picmgext_link_desc *d; 2242*c18ec02fSPetter Reinholdtsen unsigned int data = (fru_data[offset+0]) | 2243*c18ec02fSPetter Reinholdtsen (fru_data[offset+1] << 8) | 2244*c18ec02fSPetter Reinholdtsen (fru_data[offset+2] << 16) | 2245*c18ec02fSPetter Reinholdtsen (fru_data[offset+3] << 24); 2246*c18ec02fSPetter Reinholdtsen d = (struct fru_picmgext_link_desc *) &data; 2247*c18ec02fSPetter Reinholdtsen 2248*c18ec02fSPetter Reinholdtsen printf(" Link Grouping ID: 0x%02x\n", 2249*c18ec02fSPetter Reinholdtsen d->grouping); 2250*c18ec02fSPetter Reinholdtsen printf(" Link Type Extension: 0x%02x - ", 2251*c18ec02fSPetter Reinholdtsen d->ext); 2252*c18ec02fSPetter Reinholdtsen if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE) { 2253*c18ec02fSPetter Reinholdtsen switch (d->ext) 2254*c18ec02fSPetter Reinholdtsen { 2255*c18ec02fSPetter Reinholdtsen case 0: 2256*c18ec02fSPetter Reinholdtsen printf("10/100/1000BASE-T Link (four-pair)\n"); 2257*c18ec02fSPetter Reinholdtsen break; 2258*c18ec02fSPetter Reinholdtsen case 1: 2259*c18ec02fSPetter Reinholdtsen printf("ShMC Cross-connect (two-pair)\n"); 2260*c18ec02fSPetter Reinholdtsen break; 2261*c18ec02fSPetter Reinholdtsen default: 2262*c18ec02fSPetter Reinholdtsen printf("Unknwon\n"); 2263*c18ec02fSPetter Reinholdtsen break; 2264*c18ec02fSPetter Reinholdtsen } 2265*c18ec02fSPetter Reinholdtsen } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET) { 2266*c18ec02fSPetter Reinholdtsen switch (d->ext) 2267*c18ec02fSPetter Reinholdtsen { 2268*c18ec02fSPetter Reinholdtsen case 0: 2269*c18ec02fSPetter Reinholdtsen printf("Fixed 1000Base-BX\n"); 2270*c18ec02fSPetter Reinholdtsen break; 2271*c18ec02fSPetter Reinholdtsen case 1: 2272*c18ec02fSPetter Reinholdtsen printf("Fixed 10GBASE-BX4 [XAUI]\n"); 2273*c18ec02fSPetter Reinholdtsen break; 2274*c18ec02fSPetter Reinholdtsen case 2: 2275*c18ec02fSPetter Reinholdtsen printf("FC-PI\n"); 2276*c18ec02fSPetter Reinholdtsen break; 2277*c18ec02fSPetter Reinholdtsen default: 2278*c18ec02fSPetter Reinholdtsen printf("Unknwon\n"); 2279*c18ec02fSPetter Reinholdtsen break; 2280*c18ec02fSPetter Reinholdtsen } 2281*c18ec02fSPetter Reinholdtsen } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND) { 2282*c18ec02fSPetter Reinholdtsen printf("Unknwon\n"); 2283*c18ec02fSPetter Reinholdtsen } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR) { 2284*c18ec02fSPetter Reinholdtsen printf("Unknwon\n"); 2285*c18ec02fSPetter Reinholdtsen } else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE) { 2286*c18ec02fSPetter Reinholdtsen printf("Unknwon\n"); 2287*c18ec02fSPetter Reinholdtsen } else { 2288*c18ec02fSPetter Reinholdtsen printf("Unknwon\n"); 2289*c18ec02fSPetter Reinholdtsen } 2290*c18ec02fSPetter Reinholdtsen 2291*c18ec02fSPetter Reinholdtsen printf(" Link Type: 0x%02x - ", 2292*c18ec02fSPetter Reinholdtsen d->type); 2293*c18ec02fSPetter Reinholdtsen if (d->type == 0 || d->type == 0xff) { 2294*c18ec02fSPetter Reinholdtsen printf("Reserved\n"); 2295*c18ec02fSPetter Reinholdtsen } 2296*c18ec02fSPetter Reinholdtsen else if (d->type >= 0x06 && d->type <= 0xef) { 2297*c18ec02fSPetter Reinholdtsen printf("Reserved\n"); 2298*c18ec02fSPetter Reinholdtsen } 2299*c18ec02fSPetter Reinholdtsen else if (d->type >= 0xf0 && d->type <= 0xfe) { 2300*c18ec02fSPetter Reinholdtsen printf("OEM GUID Definition\n"); 2301*c18ec02fSPetter Reinholdtsen } 2302*c18ec02fSPetter Reinholdtsen else { 2303*c18ec02fSPetter Reinholdtsen switch (d->type) 2304*c18ec02fSPetter Reinholdtsen { 2305*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_LINK_TYPE_BASE: 2306*c18ec02fSPetter Reinholdtsen printf("PICMG 3.0 Base Interface 10/100/1000\n"); 2307*c18ec02fSPetter Reinholdtsen break; 2308*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: 2309*c18ec02fSPetter Reinholdtsen printf("PICMG 3.1 Ethernet Fabric Interface\n"); 2310*c18ec02fSPetter Reinholdtsen break; 2311*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: 2312*c18ec02fSPetter Reinholdtsen printf("PICMG 3.2 Infiniband Fabric Interface\n"); 2313*c18ec02fSPetter Reinholdtsen break; 2314*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: 2315*c18ec02fSPetter Reinholdtsen printf("PICMG 3.3 Star Fabric Interface\n"); 2316*c18ec02fSPetter Reinholdtsen break; 2317*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_LINK_TYPE_PCIE: 2318*c18ec02fSPetter Reinholdtsen printf("PICMG 3.4 PCI Express Fabric Interface\n"); 2319*c18ec02fSPetter Reinholdtsen break; 2320*c18ec02fSPetter Reinholdtsen default: 2321*c18ec02fSPetter Reinholdtsen printf("Invalid\n"); 2322*c18ec02fSPetter Reinholdtsen break; 2323*c18ec02fSPetter Reinholdtsen } 2324*c18ec02fSPetter Reinholdtsen } 2325*c18ec02fSPetter Reinholdtsen printf(" Link Designator: \n"); 2326*c18ec02fSPetter Reinholdtsen printf(" Port Flag: 0x%02x\n", 2327*c18ec02fSPetter Reinholdtsen d->desig_port); 2328*c18ec02fSPetter Reinholdtsen printf(" Interface: 0x%02x - ", 2329*c18ec02fSPetter Reinholdtsen d->desig_if); 2330*c18ec02fSPetter Reinholdtsen switch (d->desig_if) 2331*c18ec02fSPetter Reinholdtsen { 2332*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_DESIGN_IF_BASE: 2333*c18ec02fSPetter Reinholdtsen printf("Base Interface\n"); 2334*c18ec02fSPetter Reinholdtsen break; 2335*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_DESIGN_IF_FABRIC: 2336*c18ec02fSPetter Reinholdtsen printf("Fabric Interface\n"); 2337*c18ec02fSPetter Reinholdtsen break; 2338*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: 2339*c18ec02fSPetter Reinholdtsen printf("Update Channel\n"); 2340*c18ec02fSPetter Reinholdtsen break; 2341*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_DESIGN_IF_RESERVED: 2342*c18ec02fSPetter Reinholdtsen printf("Reserved\n"); 2343*c18ec02fSPetter Reinholdtsen break; 2344*c18ec02fSPetter Reinholdtsen default: 2345*c18ec02fSPetter Reinholdtsen printf("Invalid"); 2346*c18ec02fSPetter Reinholdtsen break; 2347*c18ec02fSPetter Reinholdtsen } 2348*c18ec02fSPetter Reinholdtsen printf(" Channel Number: 0x%02x\n", 2349*c18ec02fSPetter Reinholdtsen d->desig_channel); 2350*c18ec02fSPetter Reinholdtsen printf("\n"); 2351*c18ec02fSPetter Reinholdtsen } 2352*c18ec02fSPetter Reinholdtsen 2353*c18ec02fSPetter Reinholdtsen break; 2354*c18ec02fSPetter Reinholdtsen 2355*c18ec02fSPetter Reinholdtsen case FRU_AMC_CURRENT: 2356*c18ec02fSPetter Reinholdtsen { 2357*c18ec02fSPetter Reinholdtsen unsigned char current; 2358*c18ec02fSPetter Reinholdtsen printf(" FRU_AMC_CURRENT\n"); 2359*c18ec02fSPetter Reinholdtsen 2360*c18ec02fSPetter Reinholdtsen current = fru_data[offset]; 2361*c18ec02fSPetter Reinholdtsen printf(" Current draw(@12V): %.2f A [ %.2f Watt ]\n", 2362*c18ec02fSPetter Reinholdtsen (float)current / 10.0f, 2363*c18ec02fSPetter Reinholdtsen (float)current / 10.0f * 12.0f); 2364*c18ec02fSPetter Reinholdtsen printf("\n"); 2365*c18ec02fSPetter Reinholdtsen } 2366*c18ec02fSPetter Reinholdtsen break; 2367*c18ec02fSPetter Reinholdtsen 2368*c18ec02fSPetter Reinholdtsen case FRU_AMC_ACTIVATION: 2369*c18ec02fSPetter Reinholdtsen printf(" FRU_AMC_ACTIVATION\n"); 2370*c18ec02fSPetter Reinholdtsen { 2371*c18ec02fSPetter Reinholdtsen uint16_t max_current; 2372*c18ec02fSPetter Reinholdtsen 2373*c18ec02fSPetter Reinholdtsen max_current = fru_data[offset]; 2374*c18ec02fSPetter Reinholdtsen max_current |= fru_data[++offset]<<8; 2375*c18ec02fSPetter Reinholdtsen printf(" Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n", 2376*c18ec02fSPetter Reinholdtsen (float)max_current / 10.0f, 2377*c18ec02fSPetter Reinholdtsen (float)max_current / 10.0f * 12.0f); 2378*c18ec02fSPetter Reinholdtsen 2379*c18ec02fSPetter Reinholdtsen printf(" Module Activation Readiness: %i sec.\n", fru_data[++offset]); 2380*c18ec02fSPetter Reinholdtsen printf(" Descriptor Count: %i\n", fru_data[++offset]); 2381*c18ec02fSPetter Reinholdtsen printf("\n"); 2382*c18ec02fSPetter Reinholdtsen 2383*c18ec02fSPetter Reinholdtsen for(++offset; offset < off + length; 2384*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_picmgext_activation_record)) 2385*c18ec02fSPetter Reinholdtsen { 2386*c18ec02fSPetter Reinholdtsen struct fru_picmgext_activation_record *a; 2387*c18ec02fSPetter Reinholdtsen a = (struct fru_picmgext_activation_record *)&fru_data[offset]; 2388*c18ec02fSPetter Reinholdtsen printf(" IPMB-Address: 0x%x\n", 2389*c18ec02fSPetter Reinholdtsen a->ibmb_addr); 2390*c18ec02fSPetter Reinholdtsen printf(" Max. Module Current: %.2f A\n", 2391*c18ec02fSPetter Reinholdtsen (float)a->max_module_curr / 10.0f); 2392*c18ec02fSPetter Reinholdtsen printf("\n"); 2393*c18ec02fSPetter Reinholdtsen } 2394*c18ec02fSPetter Reinholdtsen } 2395*c18ec02fSPetter Reinholdtsen break; 2396*c18ec02fSPetter Reinholdtsen 2397*c18ec02fSPetter Reinholdtsen case FRU_AMC_CARRIER_P2P: 2398*c18ec02fSPetter Reinholdtsen { 2399*c18ec02fSPetter Reinholdtsen uint16_t index; 2400*c18ec02fSPetter Reinholdtsen printf(" FRU_CARRIER_P2P\n"); 2401*c18ec02fSPetter Reinholdtsen for(; offset < off + length; ) { 2402*c18ec02fSPetter Reinholdtsen struct fru_picmgext_carrier_p2p_record * h = 2403*c18ec02fSPetter Reinholdtsen (struct fru_picmgext_carrier_p2p_record *)&fru_data[offset]; 2404*c18ec02fSPetter Reinholdtsen printf("\n"); 2405*c18ec02fSPetter Reinholdtsen printf(" Resource ID: %i", 2406*c18ec02fSPetter Reinholdtsen (h->resource_id & 0x07)); 2407*c18ec02fSPetter Reinholdtsen printf(" Type: "); 2408*c18ec02fSPetter Reinholdtsen if ((h->resource_id>>7) == 1) { 2409*c18ec02fSPetter Reinholdtsen printf("AMC\n"); 2410*c18ec02fSPetter Reinholdtsen } else { 2411*c18ec02fSPetter Reinholdtsen printf("Local\n"); 2412*c18ec02fSPetter Reinholdtsen } 2413*c18ec02fSPetter Reinholdtsen printf(" Descriptor Count: %i\n", 2414*c18ec02fSPetter Reinholdtsen h->p2p_count); 2415*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_picmgext_carrier_p2p_record); 2416*c18ec02fSPetter Reinholdtsen for (index = 0; index < h->p2p_count; index++) { 2417*c18ec02fSPetter Reinholdtsen /* to solve little endian /big endian problem */ 2418*c18ec02fSPetter Reinholdtsen unsigned char data[3]; 2419*c18ec02fSPetter Reinholdtsen struct fru_picmgext_carrier_p2p_descriptor * desc; 2420*c18ec02fSPetter Reinholdtsen # ifndef WORDS_BIGENDIAN 2421*c18ec02fSPetter Reinholdtsen data[0] = fru_data[offset+0]; 2422*c18ec02fSPetter Reinholdtsen data[1] = fru_data[offset+1]; 2423*c18ec02fSPetter Reinholdtsen data[2] = fru_data[offset+2]; 2424*c18ec02fSPetter Reinholdtsen # else 2425*c18ec02fSPetter Reinholdtsen data[0] = fru_data[offset+2]; 2426*c18ec02fSPetter Reinholdtsen data[1] = fru_data[offset+1]; 2427*c18ec02fSPetter Reinholdtsen data[2] = fru_data[offset+0]; 2428*c18ec02fSPetter Reinholdtsen # endif 2429*c18ec02fSPetter Reinholdtsen desc = (struct fru_picmgext_carrier_p2p_descriptor*)&data; 2430*c18ec02fSPetter Reinholdtsen printf(" Port: %02d\t-> Remote Port: %02d\t", 2431*c18ec02fSPetter Reinholdtsen desc->local_port, desc->remote_port); 2432*c18ec02fSPetter Reinholdtsen if ((desc->remote_resource_id >> 7) == 1) { 2433*c18ec02fSPetter Reinholdtsen printf("[ AMC ID: %02d ]\n", 2434*c18ec02fSPetter Reinholdtsen desc->remote_resource_id & 0x0F); 2435*c18ec02fSPetter Reinholdtsen } else { 2436*c18ec02fSPetter Reinholdtsen printf("[ local ID: %02d ]\n", 2437*c18ec02fSPetter Reinholdtsen desc->remote_resource_id & 0x0F); 2438*c18ec02fSPetter Reinholdtsen } 2439*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_picmgext_carrier_p2p_descriptor); 2440*c18ec02fSPetter Reinholdtsen } 2441*c18ec02fSPetter Reinholdtsen } 2442*c18ec02fSPetter Reinholdtsen } 2443*c18ec02fSPetter Reinholdtsen break; 2444*c18ec02fSPetter Reinholdtsen 2445*c18ec02fSPetter Reinholdtsen case FRU_AMC_P2P: 2446*c18ec02fSPetter Reinholdtsen { 2447*c18ec02fSPetter Reinholdtsen unsigned int index; 2448*c18ec02fSPetter Reinholdtsen unsigned char channel_count; 2449*c18ec02fSPetter Reinholdtsen struct fru_picmgext_amc_p2p_record * h; 2450*c18ec02fSPetter Reinholdtsen printf(" FRU_AMC_P2P\n"); 2451*c18ec02fSPetter Reinholdtsen guid_count = fru_data[offset]; 2452*c18ec02fSPetter Reinholdtsen printf(" GUID count: %2d\n", guid_count); 2453*c18ec02fSPetter Reinholdtsen for (i = 0 ; i < guid_count; i++) { 2454*c18ec02fSPetter Reinholdtsen int j; 2455*c18ec02fSPetter Reinholdtsen printf(" GUID %2d: ", i); 2456*c18ec02fSPetter Reinholdtsen for (j=0; j < sizeof(struct fru_picmgext_guid); 2457*c18ec02fSPetter Reinholdtsen j++) { 2458*c18ec02fSPetter Reinholdtsen printf("%02x", fru_data[offset+j]); 2459*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_picmgext_guid); 2460*c18ec02fSPetter Reinholdtsen printf("\n"); 2461*c18ec02fSPetter Reinholdtsen } 2462*c18ec02fSPetter Reinholdtsen h = (struct fru_picmgext_amc_p2p_record *)&fru_data[++offset]; 2463*c18ec02fSPetter Reinholdtsen printf(" %s", 2464*c18ec02fSPetter Reinholdtsen (h->record_type ? 2465*c18ec02fSPetter Reinholdtsen "AMC Module:" : "On-Carrier Device")); 2466*c18ec02fSPetter Reinholdtsen printf(" Resource ID: %i\n", h->resource_id); 2467*c18ec02fSPetter Reinholdtsen offset += sizeof(struct fru_picmgext_amc_p2p_record); 2468*c18ec02fSPetter Reinholdtsen channel_count = fru_data[offset++]; 2469*c18ec02fSPetter Reinholdtsen printf(" Descriptor Count: %i\n", 2470*c18ec02fSPetter Reinholdtsen channel_count); 2471*c18ec02fSPetter Reinholdtsen for (index = 0; index < channel_count; index++) { 2472*c18ec02fSPetter Reinholdtsen unsigned int data; 2473*c18ec02fSPetter Reinholdtsen struct fru_picmgext_amc_channel_desc_record *d; 2474*c18ec02fSPetter Reinholdtsen /* pack the data in little endian format. 2475*c18ec02fSPetter Reinholdtsen * Stupid intel... 2476*c18ec02fSPetter Reinholdtsen */ 2477*c18ec02fSPetter Reinholdtsen data = fru_data[offset] | 2478*c18ec02fSPetter Reinholdtsen (fru_data[offset + 1] << 8) | 2479*c18ec02fSPetter Reinholdtsen (fru_data[offset + 2] << 16); 2480*c18ec02fSPetter Reinholdtsen d = (struct fru_picmgext_amc_channel_desc_record *)&data; 2481*c18ec02fSPetter Reinholdtsen printf(" Lane 0 Port: %i\n", 2482*c18ec02fSPetter Reinholdtsen d->lane0port); 2483*c18ec02fSPetter Reinholdtsen printf(" Lane 1 Port: %i\n", 2484*c18ec02fSPetter Reinholdtsen d->lane1port); 2485*c18ec02fSPetter Reinholdtsen printf(" Lane 2 Port: %i\n", 2486*c18ec02fSPetter Reinholdtsen d->lane2port); 2487*c18ec02fSPetter Reinholdtsen printf(" Lane 3 Port: %i\n\n", 2488*c18ec02fSPetter Reinholdtsen d->lane3port); 2489*c18ec02fSPetter Reinholdtsen offset += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE; 2490*c18ec02fSPetter Reinholdtsen } 2491*c18ec02fSPetter Reinholdtsen for (; offset < off + length;) { 2492*c18ec02fSPetter Reinholdtsen unsigned int data[2]; 2493*c18ec02fSPetter Reinholdtsen struct fru_picmgext_amc_link_desc_record *l; 2494*c18ec02fSPetter Reinholdtsen l = (struct fru_picmgext_amc_link_desc_record *)&data[0]; 2495*c18ec02fSPetter Reinholdtsen data[0] = fru_data[offset] | 2496*c18ec02fSPetter Reinholdtsen (fru_data[offset + 1] << 8) | 2497*c18ec02fSPetter Reinholdtsen (fru_data[offset + 2] << 16) | 2498*c18ec02fSPetter Reinholdtsen (fru_data[offset + 3] << 24); 2499*c18ec02fSPetter Reinholdtsen data[1] = fru_data[offset + 4]; 2500*c18ec02fSPetter Reinholdtsen printf( " Link Designator: Channel ID: %i\n" 2501*c18ec02fSPetter Reinholdtsen " Port Flag 0: %s%s%s%s\n", 2502*c18ec02fSPetter Reinholdtsen l->channel_id, 2503*c18ec02fSPetter Reinholdtsen (l->port_flag_0)?"o":"-", 2504*c18ec02fSPetter Reinholdtsen (l->port_flag_1)?"o":"-", 2505*c18ec02fSPetter Reinholdtsen (l->port_flag_2)?"o":"-", 2506*c18ec02fSPetter Reinholdtsen (l->port_flag_3)?"o":"-" ); 2507*c18ec02fSPetter Reinholdtsen switch (l->type) { 2508*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: 2509*c18ec02fSPetter Reinholdtsen /* AMC.1 */ 2510*c18ec02fSPetter Reinholdtsen printf( " Link Type: %02x - " 2511*c18ec02fSPetter Reinholdtsen "AMC.1 PCI Express\n", l->type); 2512*c18ec02fSPetter Reinholdtsen switch (l->type_ext) { 2513*c18ec02fSPetter Reinholdtsen case AMC_LINK_TYPE_EXT_PCIE_G1_NSSC: 2514*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2515*c18ec02fSPetter Reinholdtsen " Gen 1 capable - non SSC\n", 2516*c18ec02fSPetter Reinholdtsen l->type_ext); 2517*c18ec02fSPetter Reinholdtsen break; 2518*c18ec02fSPetter Reinholdtsen case AMC_LINK_TYPE_EXT_PCIE_G1_SSC: 2519*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2520*c18ec02fSPetter Reinholdtsen " Gen 1 capable - SSC\n", 2521*c18ec02fSPetter Reinholdtsen l->type_ext); 2522*c18ec02fSPetter Reinholdtsen break; 2523*c18ec02fSPetter Reinholdtsen case AMC_LINK_TYPE_EXT_PCIE_G2_NSSC: 2524*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2525*c18ec02fSPetter Reinholdtsen " Gen 2 capable - non SSC\n", 2526*c18ec02fSPetter Reinholdtsen l->type_ext); 2527*c18ec02fSPetter Reinholdtsen break; 2528*c18ec02fSPetter Reinholdtsen case AMC_LINK_TYPE_EXT_PCIE_G2_SSC: 2529*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2530*c18ec02fSPetter Reinholdtsen " Gen 2 capable - SSC\n", 2531*c18ec02fSPetter Reinholdtsen l->type_ext); 2532*c18ec02fSPetter Reinholdtsen break; 2533*c18ec02fSPetter Reinholdtsen default: 2534*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2535*c18ec02fSPetter Reinholdtsen " Invalid\n", 2536*c18ec02fSPetter Reinholdtsen l->type_ext); 2537*c18ec02fSPetter Reinholdtsen break; 2538*c18ec02fSPetter Reinholdtsen } 2539*c18ec02fSPetter Reinholdtsen break; 2540*c18ec02fSPetter Reinholdtsen 2541*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: 2542*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: 2543*c18ec02fSPetter Reinholdtsen /* AMC.1 */ 2544*c18ec02fSPetter Reinholdtsen printf( " Link Type: %02x - " 2545*c18ec02fSPetter Reinholdtsen "AMC.1 PCI Express Advanced Switching\n", 2546*c18ec02fSPetter Reinholdtsen l->type); 2547*c18ec02fSPetter Reinholdtsen printf(" Link Type Ext: %i\n", 2548*c18ec02fSPetter Reinholdtsen l->type_ext); 2549*c18ec02fSPetter Reinholdtsen break; 2550*c18ec02fSPetter Reinholdtsen 2551*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: 2552*c18ec02fSPetter Reinholdtsen /* AMC.2 */ 2553*c18ec02fSPetter Reinholdtsen printf( " Link Type: %02x - " 2554*c18ec02fSPetter Reinholdtsen "AMC.2 Ethernet\n", 2555*c18ec02fSPetter Reinholdtsen l->type); 2556*c18ec02fSPetter Reinholdtsen switch (l->type_ext) { 2557*c18ec02fSPetter Reinholdtsen case AMC_LINK_TYPE_EXT_ETH_1000_BX: 2558*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2559*c18ec02fSPetter Reinholdtsen " 1000Base-Bx (SerDES Gigabit) Ethernet Link\n", 2560*c18ec02fSPetter Reinholdtsen l->type_ext); 2561*c18ec02fSPetter Reinholdtsen break; 2562*c18ec02fSPetter Reinholdtsen 2563*c18ec02fSPetter Reinholdtsen case AMC_LINK_TYPE_EXT_ETH_10G_XAUI: 2564*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2565*c18ec02fSPetter Reinholdtsen " 10Gbit XAUI Ethernet Link\n", 2566*c18ec02fSPetter Reinholdtsen l->type_ext); 2567*c18ec02fSPetter Reinholdtsen break; 2568*c18ec02fSPetter Reinholdtsen 2569*c18ec02fSPetter Reinholdtsen default: 2570*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2571*c18ec02fSPetter Reinholdtsen " Invalid\n", 2572*c18ec02fSPetter Reinholdtsen l->type_ext); 2573*c18ec02fSPetter Reinholdtsen break; 2574*c18ec02fSPetter Reinholdtsen } 2575*c18ec02fSPetter Reinholdtsen break; 2576*c18ec02fSPetter Reinholdtsen 2577*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: 2578*c18ec02fSPetter Reinholdtsen /* AMC.3 */ 2579*c18ec02fSPetter Reinholdtsen printf( " Link Type: %02x - " 2580*c18ec02fSPetter Reinholdtsen "AMC.3 Storage\n", 2581*c18ec02fSPetter Reinholdtsen l->type); 2582*c18ec02fSPetter Reinholdtsen switch (l->type_ext) { 2583*c18ec02fSPetter Reinholdtsen case AMC_LINK_TYPE_EXT_STORAGE_FC: 2584*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2585*c18ec02fSPetter Reinholdtsen " Fibre Channel\n", 2586*c18ec02fSPetter Reinholdtsen l->type_ext); 2587*c18ec02fSPetter Reinholdtsen break; 2588*c18ec02fSPetter Reinholdtsen 2589*c18ec02fSPetter Reinholdtsen case AMC_LINK_TYPE_EXT_STORAGE_SATA: 2590*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2591*c18ec02fSPetter Reinholdtsen " Serial ATA\n", 2592*c18ec02fSPetter Reinholdtsen l->type_ext); 2593*c18ec02fSPetter Reinholdtsen break; 2594*c18ec02fSPetter Reinholdtsen 2595*c18ec02fSPetter Reinholdtsen case AMC_LINK_TYPE_EXT_STORAGE_SAS: 2596*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2597*c18ec02fSPetter Reinholdtsen " Serial Attached SCSI\n", 2598*c18ec02fSPetter Reinholdtsen l->type_ext); 2599*c18ec02fSPetter Reinholdtsen break; 2600*c18ec02fSPetter Reinholdtsen 2601*c18ec02fSPetter Reinholdtsen default: 2602*c18ec02fSPetter Reinholdtsen printf( " Link Type Ext: %i - " 2603*c18ec02fSPetter Reinholdtsen " Invalid\n", 2604*c18ec02fSPetter Reinholdtsen l->type_ext); 2605*c18ec02fSPetter Reinholdtsen break; 2606*c18ec02fSPetter Reinholdtsen } 2607*c18ec02fSPetter Reinholdtsen break; 2608*c18ec02fSPetter Reinholdtsen 2609*c18ec02fSPetter Reinholdtsen case FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO: 2610*c18ec02fSPetter Reinholdtsen /* AMC.4 */ 2611*c18ec02fSPetter Reinholdtsen printf( " Link Type: %02x - " 2612*c18ec02fSPetter Reinholdtsen "AMC.4 Serial Rapid IO\n", 2613*c18ec02fSPetter Reinholdtsen l->type); 2614*c18ec02fSPetter Reinholdtsen printf(" Link Type Ext: %i\n", 2615*c18ec02fSPetter Reinholdtsen l->type_ext); 2616*c18ec02fSPetter Reinholdtsen break; 2617*c18ec02fSPetter Reinholdtsen 2618*c18ec02fSPetter Reinholdtsen default: 2619*c18ec02fSPetter Reinholdtsen printf( " Link Type: %02x - " 2620*c18ec02fSPetter Reinholdtsen "reserved or OEM GUID", 2621*c18ec02fSPetter Reinholdtsen l->type); 2622*c18ec02fSPetter Reinholdtsen printf(" Link Type Ext: %i\n", 2623*c18ec02fSPetter Reinholdtsen l->type_ext); 2624*c18ec02fSPetter Reinholdtsen break; 2625*c18ec02fSPetter Reinholdtsen } 2626*c18ec02fSPetter Reinholdtsen 2627*c18ec02fSPetter Reinholdtsen printf(" Link group Id: %i\n", 2628*c18ec02fSPetter Reinholdtsen l->group_id); 2629*c18ec02fSPetter Reinholdtsen printf(" Link Asym Match: %i\n\n", 2630*c18ec02fSPetter Reinholdtsen l->asym_match); 2631*c18ec02fSPetter Reinholdtsen offset += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE; 2632*c18ec02fSPetter Reinholdtsen } 2633*c18ec02fSPetter Reinholdtsen } 2634*c18ec02fSPetter Reinholdtsen } 2635*c18ec02fSPetter Reinholdtsen break; 2636*c18ec02fSPetter Reinholdtsen 2637*c18ec02fSPetter Reinholdtsen case FRU_AMC_CARRIER_INFO: 2638*c18ec02fSPetter Reinholdtsen { 2639*c18ec02fSPetter Reinholdtsen unsigned char extVersion; 2640*c18ec02fSPetter Reinholdtsen unsigned char siteCount; 2641*c18ec02fSPetter Reinholdtsen 2642*c18ec02fSPetter Reinholdtsen printf(" FRU_CARRIER_INFO\n"); 2643*c18ec02fSPetter Reinholdtsen 2644*c18ec02fSPetter Reinholdtsen extVersion = fru_data[offset++]; 2645*c18ec02fSPetter Reinholdtsen siteCount = fru_data[offset++]; 2646*c18ec02fSPetter Reinholdtsen 2647*c18ec02fSPetter Reinholdtsen printf(" AMC.0 extension version: R%d.%d\n", 2648*c18ec02fSPetter Reinholdtsen (extVersion >> 0)& 0x0F, 2649*c18ec02fSPetter Reinholdtsen (extVersion >> 4)& 0x0F ); 2650*c18ec02fSPetter Reinholdtsen printf(" Carrier Sie Number Cnt: %d\n", siteCount); 2651*c18ec02fSPetter Reinholdtsen 2652*c18ec02fSPetter Reinholdtsen for (i = 0 ; i < siteCount; i++ ){ 2653*c18ec02fSPetter Reinholdtsen printf(" Site ID: %i \n", fru_data[offset++]); 2654*c18ec02fSPetter Reinholdtsen } 2655*c18ec02fSPetter Reinholdtsen printf("\n"); 2656*c18ec02fSPetter Reinholdtsen } 2657*c18ec02fSPetter Reinholdtsen break; 2658*c18ec02fSPetter Reinholdtsen case FRU_PICMG_CLK_CARRIER_P2P: 2659*c18ec02fSPetter Reinholdtsen { 2660*c18ec02fSPetter Reinholdtsen unsigned char desc_count; 2661*c18ec02fSPetter Reinholdtsen int i,j; 2662*c18ec02fSPetter Reinholdtsen 2663*c18ec02fSPetter Reinholdtsen printf(" FRU_PICMG_CLK_CARRIER_P2P\n"); 2664*c18ec02fSPetter Reinholdtsen 2665*c18ec02fSPetter Reinholdtsen desc_count = fru_data[offset++]; 2666*c18ec02fSPetter Reinholdtsen 2667*c18ec02fSPetter Reinholdtsen for(i=0; i<desc_count; i++){ 2668*c18ec02fSPetter Reinholdtsen unsigned char resource_id; 2669*c18ec02fSPetter Reinholdtsen unsigned char channel_count; 2670*c18ec02fSPetter Reinholdtsen 2671*c18ec02fSPetter Reinholdtsen resource_id = fru_data[offset++]; 2672*c18ec02fSPetter Reinholdtsen channel_count = fru_data[offset++]; 2673*c18ec02fSPetter Reinholdtsen 2674*c18ec02fSPetter Reinholdtsen printf("\n"); 2675*c18ec02fSPetter Reinholdtsen printf(" Clock Resource ID: 0x%02x Type: ", resource_id); 2676*c18ec02fSPetter Reinholdtsen if((resource_id & 0xC0)>>6 == 0) {printf("On-Carrier-Device\n");} 2677*c18ec02fSPetter Reinholdtsen else if((resource_id & 0xC0)>>6 == 1) {printf("AMC slot\n");} 2678*c18ec02fSPetter Reinholdtsen else if((resource_id & 0xC0)>>6 == 2) {printf("Backplane\n");} 2679*c18ec02fSPetter Reinholdtsen else{ printf("reserved\n");} 2680*c18ec02fSPetter Reinholdtsen printf(" Channel Count: 0x%02x\n", channel_count); 2681*c18ec02fSPetter Reinholdtsen 2682*c18ec02fSPetter Reinholdtsen for(j=0; j<channel_count; j++){ 2683*c18ec02fSPetter Reinholdtsen unsigned char loc_channel, rem_channel, rem_resource; 2684*c18ec02fSPetter Reinholdtsen 2685*c18ec02fSPetter Reinholdtsen loc_channel = fru_data[offset++]; 2686*c18ec02fSPetter Reinholdtsen rem_channel = fru_data[offset++]; 2687*c18ec02fSPetter Reinholdtsen rem_resource = fru_data[offset++]; 2688*c18ec02fSPetter Reinholdtsen 2689*c18ec02fSPetter Reinholdtsen printf(" CLK-ID: 0x%02x ->", loc_channel); 2690*c18ec02fSPetter Reinholdtsen printf(" remote CLKID: 0x%02x ", rem_channel); 2691*c18ec02fSPetter Reinholdtsen if((rem_resource & 0xC0)>>6 == 0) {printf("[ Carrier-Dev");} 2692*c18ec02fSPetter Reinholdtsen else if((rem_resource & 0xC0)>>6 == 1) {printf("[ AMC slot ");} 2693*c18ec02fSPetter Reinholdtsen else if((rem_resource & 0xC0)>>6 == 2) {printf("[ Backplane ");} 2694*c18ec02fSPetter Reinholdtsen else{ printf("reserved ");} 2695*c18ec02fSPetter Reinholdtsen printf(" 0x%02x ]\n", rem_resource&0xF); 2696*c18ec02fSPetter Reinholdtsen } 2697*c18ec02fSPetter Reinholdtsen } 2698*c18ec02fSPetter Reinholdtsen printf("\n"); 2699*c18ec02fSPetter Reinholdtsen } 2700*c18ec02fSPetter Reinholdtsen break; 2701*c18ec02fSPetter Reinholdtsen case FRU_PICMG_CLK_CONFIG: 2702*c18ec02fSPetter Reinholdtsen { 2703*c18ec02fSPetter Reinholdtsen unsigned char resource_id, descr_count; 2704*c18ec02fSPetter Reinholdtsen int i,j; 2705*c18ec02fSPetter Reinholdtsen 2706*c18ec02fSPetter Reinholdtsen printf(" FRU_PICMG_CLK_CONFIG\n"); 2707*c18ec02fSPetter Reinholdtsen 2708*c18ec02fSPetter Reinholdtsen resource_id = fru_data[offset++]; 2709*c18ec02fSPetter Reinholdtsen descr_count = fru_data[offset++]; 2710*c18ec02fSPetter Reinholdtsen 2711*c18ec02fSPetter Reinholdtsen printf("\n"); 2712*c18ec02fSPetter Reinholdtsen printf(" Clock Resource ID: 0x%02x\n", resource_id); 2713*c18ec02fSPetter Reinholdtsen printf(" Descr. Count: 0x%02x\n", descr_count); 2714*c18ec02fSPetter Reinholdtsen 2715*c18ec02fSPetter Reinholdtsen for(i=0; i<descr_count; i++){ 2716*c18ec02fSPetter Reinholdtsen unsigned char channel_id, control; 2717*c18ec02fSPetter Reinholdtsen unsigned char indirect_cnt, direct_cnt; 2718*c18ec02fSPetter Reinholdtsen 2719*c18ec02fSPetter Reinholdtsen channel_id = fru_data[offset++]; 2720*c18ec02fSPetter Reinholdtsen control = fru_data[offset++]; 2721*c18ec02fSPetter Reinholdtsen printf(" CLK-ID: 0x%02x - ", channel_id); 2722*c18ec02fSPetter Reinholdtsen printf("CTRL 0x%02x [ %12s ]\n", 2723*c18ec02fSPetter Reinholdtsen control, 2724*c18ec02fSPetter Reinholdtsen ((control&0x1)==0)?"Carrier IPMC":"Application"); 2725*c18ec02fSPetter Reinholdtsen 2726*c18ec02fSPetter Reinholdtsen indirect_cnt = fru_data[offset++]; 2727*c18ec02fSPetter Reinholdtsen direct_cnt = fru_data[offset++]; 2728*c18ec02fSPetter Reinholdtsen printf(" Cnt: Indirect 0x%02x / Direct 0x%02x\n", 2729*c18ec02fSPetter Reinholdtsen indirect_cnt, 2730*c18ec02fSPetter Reinholdtsen direct_cnt); 2731*c18ec02fSPetter Reinholdtsen 2732*c18ec02fSPetter Reinholdtsen /* indirect desc */ 2733*c18ec02fSPetter Reinholdtsen for(j=0; j<indirect_cnt; j++){ 2734*c18ec02fSPetter Reinholdtsen unsigned char feature; 2735*c18ec02fSPetter Reinholdtsen unsigned char dep_chn_id; 2736*c18ec02fSPetter Reinholdtsen 2737*c18ec02fSPetter Reinholdtsen feature = fru_data[offset++]; 2738*c18ec02fSPetter Reinholdtsen dep_chn_id = fru_data[offset++]; 2739*c18ec02fSPetter Reinholdtsen 2740*c18ec02fSPetter Reinholdtsen printf(" Feature: 0x%02x [%8s] - ", feature, (feature&0x1)==1?"Source":"Receiver"); 2741*c18ec02fSPetter Reinholdtsen printf(" Dep. CLK-ID: 0x%02x\n", dep_chn_id); 2742*c18ec02fSPetter Reinholdtsen } 2743*c18ec02fSPetter Reinholdtsen 2744*c18ec02fSPetter Reinholdtsen /* direct desc */ 2745*c18ec02fSPetter Reinholdtsen for(j=0; j<direct_cnt; j++){ 2746*c18ec02fSPetter Reinholdtsen unsigned char feature, family, accuracy; 2747*c18ec02fSPetter Reinholdtsen unsigned int freq, min_freq, max_freq; 2748*c18ec02fSPetter Reinholdtsen 2749*c18ec02fSPetter Reinholdtsen feature = fru_data[offset++]; 2750*c18ec02fSPetter Reinholdtsen family = fru_data[offset++]; 2751*c18ec02fSPetter Reinholdtsen accuracy = fru_data[offset++]; 2752*c18ec02fSPetter Reinholdtsen freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 ) 2753*c18ec02fSPetter Reinholdtsen | (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24); 2754*c18ec02fSPetter Reinholdtsen offset += 4; 2755*c18ec02fSPetter Reinholdtsen min_freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 ) 2756*c18ec02fSPetter Reinholdtsen | (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24); 2757*c18ec02fSPetter Reinholdtsen offset += 4; 2758*c18ec02fSPetter Reinholdtsen max_freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 ) 2759*c18ec02fSPetter Reinholdtsen | (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24); 2760*c18ec02fSPetter Reinholdtsen offset += 4; 2761*c18ec02fSPetter Reinholdtsen 2762*c18ec02fSPetter Reinholdtsen printf(" - Feature: 0x%02x - PLL: %x / Asym: %s\n", 2763*c18ec02fSPetter Reinholdtsen feature, 2764*c18ec02fSPetter Reinholdtsen (feature > 1) & 1, 2765*c18ec02fSPetter Reinholdtsen (feature&1)?"Source":"Receiver"); 2766*c18ec02fSPetter Reinholdtsen printf(" Family: 0x%02x - AccLVL: 0x%02x\n", family, accuracy); 2767*c18ec02fSPetter Reinholdtsen printf(" FRQ: %-9ld - min: %-9ld - max: %-9ld\n", 2768*c18ec02fSPetter Reinholdtsen freq, min_freq, max_freq); 2769*c18ec02fSPetter Reinholdtsen } 2770*c18ec02fSPetter Reinholdtsen printf("\n"); 2771*c18ec02fSPetter Reinholdtsen } 2772*c18ec02fSPetter Reinholdtsen printf("\n"); 2773*c18ec02fSPetter Reinholdtsen } 2774*c18ec02fSPetter Reinholdtsen break; 2775*c18ec02fSPetter Reinholdtsen 2776*c18ec02fSPetter Reinholdtsen case FRU_UTCA_FRU_INFO_TABLE: 2777*c18ec02fSPetter Reinholdtsen case FRU_UTCA_CARRIER_MNG_IP: 2778*c18ec02fSPetter Reinholdtsen case FRU_UTCA_CARRIER_INFO: 2779*c18ec02fSPetter Reinholdtsen case FRU_UTCA_CARRIER_LOCATION: 2780*c18ec02fSPetter Reinholdtsen case FRU_UTCA_SHMC_IP_LINK: 2781*c18ec02fSPetter Reinholdtsen case FRU_UTCA_POWER_POLICY: 2782*c18ec02fSPetter Reinholdtsen case FRU_UTCA_ACTIVATION: 2783*c18ec02fSPetter Reinholdtsen case FRU_UTCA_PM_CAPABILTY: 2784*c18ec02fSPetter Reinholdtsen case FRU_UTCA_FAN_GEOGRAPHY: 2785*c18ec02fSPetter Reinholdtsen case FRU_UTCA_CLOCK_MAPPING: 2786*c18ec02fSPetter Reinholdtsen case FRU_UTCA_MSG_BRIDGE_POLICY: 2787*c18ec02fSPetter Reinholdtsen case FRU_UTCA_OEM_MODULE_DESC: 2788*c18ec02fSPetter Reinholdtsen printf(" Not implemented yet. uTCA specific record found!!\n"); 2789*c18ec02fSPetter Reinholdtsen printf(" - Record ID: 0x%02x\n", h->record_id); 2790*c18ec02fSPetter Reinholdtsen break; 2791*c18ec02fSPetter Reinholdtsen 2792*c18ec02fSPetter Reinholdtsen default: 2793*c18ec02fSPetter Reinholdtsen printf(" Unknown OEM Extension Record ID: %x\n", h->record_id); 2794*c18ec02fSPetter Reinholdtsen break; 2795*c18ec02fSPetter Reinholdtsen 2796*c18ec02fSPetter Reinholdtsen } 2797*c18ec02fSPetter Reinholdtsen } 2798*c18ec02fSPetter Reinholdtsen 2799*c18ec02fSPetter Reinholdtsen 2800*c18ec02fSPetter Reinholdtsen /* __ipmi_fru_print - Do actual work to print a FRU by its ID 2801*c18ec02fSPetter Reinholdtsen * 2802*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 2803*c18ec02fSPetter Reinholdtsen * @id: fru id 2804*c18ec02fSPetter Reinholdtsen * 2805*c18ec02fSPetter Reinholdtsen * returns -1 on error 2806*c18ec02fSPetter Reinholdtsen * returns 0 if successful 2807*c18ec02fSPetter Reinholdtsen * returns 1 if device not present 2808*c18ec02fSPetter Reinholdtsen */ 2809*c18ec02fSPetter Reinholdtsen static int 2810*c18ec02fSPetter Reinholdtsen __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id) 2811*c18ec02fSPetter Reinholdtsen { 2812*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 2813*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 2814*c18ec02fSPetter Reinholdtsen struct fru_info fru; 2815*c18ec02fSPetter Reinholdtsen struct fru_header header; 2816*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 2817*c18ec02fSPetter Reinholdtsen 2818*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(struct fru_info)); 2819*c18ec02fSPetter Reinholdtsen memset(&header, 0, sizeof(struct fru_header)); 2820*c18ec02fSPetter Reinholdtsen 2821*c18ec02fSPetter Reinholdtsen /* 2822*c18ec02fSPetter Reinholdtsen * get info about this FRU 2823*c18ec02fSPetter Reinholdtsen */ 2824*c18ec02fSPetter Reinholdtsen memset(msg_data, 0, 4); 2825*c18ec02fSPetter Reinholdtsen msg_data[0] = id; 2826*c18ec02fSPetter Reinholdtsen 2827*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 2828*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 2829*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_INFO; 2830*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 2831*c18ec02fSPetter Reinholdtsen req.msg.data_len = 1; 2832*c18ec02fSPetter Reinholdtsen 2833*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 2834*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 2835*c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 2836*c18ec02fSPetter Reinholdtsen return -1; 2837*c18ec02fSPetter Reinholdtsen } 2838*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 2839*c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 2840*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 2841*c18ec02fSPetter Reinholdtsen return -1; 2842*c18ec02fSPetter Reinholdtsen } 2843*c18ec02fSPetter Reinholdtsen 2844*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(fru)); 2845*c18ec02fSPetter Reinholdtsen fru.size = (rsp->data[1] << 8) | rsp->data[0]; 2846*c18ec02fSPetter Reinholdtsen fru.access = rsp->data[2] & 0x1; 2847*c18ec02fSPetter Reinholdtsen 2848*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)", 2849*c18ec02fSPetter Reinholdtsen fru.size, fru.access ? "words" : "bytes"); 2850*c18ec02fSPetter Reinholdtsen 2851*c18ec02fSPetter Reinholdtsen if (fru.size < 1) { 2852*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Invalid FRU size %d", fru.size); 2853*c18ec02fSPetter Reinholdtsen return -1; 2854*c18ec02fSPetter Reinholdtsen } 2855*c18ec02fSPetter Reinholdtsen 2856*c18ec02fSPetter Reinholdtsen /* 2857*c18ec02fSPetter Reinholdtsen * retrieve the FRU header 2858*c18ec02fSPetter Reinholdtsen */ 2859*c18ec02fSPetter Reinholdtsen msg_data[0] = id; 2860*c18ec02fSPetter Reinholdtsen msg_data[1] = 0; 2861*c18ec02fSPetter Reinholdtsen msg_data[2] = 0; 2862*c18ec02fSPetter Reinholdtsen msg_data[3] = 8; 2863*c18ec02fSPetter Reinholdtsen 2864*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 2865*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 2866*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_DATA; 2867*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 2868*c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 2869*c18ec02fSPetter Reinholdtsen 2870*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 2871*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 2872*c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 2873*c18ec02fSPetter Reinholdtsen return 1; 2874*c18ec02fSPetter Reinholdtsen } 2875*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 2876*c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 2877*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 2878*c18ec02fSPetter Reinholdtsen return 1; 2879*c18ec02fSPetter Reinholdtsen } 2880*c18ec02fSPetter Reinholdtsen 2881*c18ec02fSPetter Reinholdtsen if (verbose > 1) 2882*c18ec02fSPetter Reinholdtsen printbuf(rsp->data, rsp->data_len, "FRU DATA"); 2883*c18ec02fSPetter Reinholdtsen 2884*c18ec02fSPetter Reinholdtsen memcpy(&header, rsp->data + 1, 8); 2885*c18ec02fSPetter Reinholdtsen 2886*c18ec02fSPetter Reinholdtsen if (header.version != 1) { 2887*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", 2888*c18ec02fSPetter Reinholdtsen header.version); 2889*c18ec02fSPetter Reinholdtsen return -1; 2890*c18ec02fSPetter Reinholdtsen } 2891*c18ec02fSPetter Reinholdtsen 2892*c18ec02fSPetter Reinholdtsen /* offsets need converted to bytes 2893*c18ec02fSPetter Reinholdtsen * but that conversion is not done to the structure 2894*c18ec02fSPetter Reinholdtsen * because we may end up with offset > 255 2895*c18ec02fSPetter Reinholdtsen * which would overflow our 1-byte offset field */ 2896*c18ec02fSPetter Reinholdtsen 2897*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.version: 0x%x", 2898*c18ec02fSPetter Reinholdtsen header.version); 2899*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.offset.internal: 0x%x", 2900*c18ec02fSPetter Reinholdtsen header.offset.internal * 8); 2901*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.offset.chassis: 0x%x", 2902*c18ec02fSPetter Reinholdtsen header.offset.chassis * 8); 2903*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.offset.board: 0x%x", 2904*c18ec02fSPetter Reinholdtsen header.offset.board * 8); 2905*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.offset.product: 0x%x", 2906*c18ec02fSPetter Reinholdtsen header.offset.product * 8); 2907*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.offset.multi: 0x%x", 2908*c18ec02fSPetter Reinholdtsen header.offset.multi * 8); 2909*c18ec02fSPetter Reinholdtsen 2910*c18ec02fSPetter Reinholdtsen /* 2911*c18ec02fSPetter Reinholdtsen * rather than reading the entire part 2912*c18ec02fSPetter Reinholdtsen * only read the areas we'll format 2913*c18ec02fSPetter Reinholdtsen */ 2914*c18ec02fSPetter Reinholdtsen /* chassis area */ 2915*c18ec02fSPetter Reinholdtsen if ((header.offset.chassis*8) >= sizeof(struct fru_header)) 2916*c18ec02fSPetter Reinholdtsen fru_area_print_chassis(intf, &fru, id, header.offset.chassis*8); 2917*c18ec02fSPetter Reinholdtsen 2918*c18ec02fSPetter Reinholdtsen /* board area */ 2919*c18ec02fSPetter Reinholdtsen if ((header.offset.board*8) >= sizeof(struct fru_header)) 2920*c18ec02fSPetter Reinholdtsen fru_area_print_board(intf, &fru, id, header.offset.board*8); 2921*c18ec02fSPetter Reinholdtsen 2922*c18ec02fSPetter Reinholdtsen /* product area */ 2923*c18ec02fSPetter Reinholdtsen if ((header.offset.product*8) >= sizeof(struct fru_header)) 2924*c18ec02fSPetter Reinholdtsen fru_area_print_product(intf, &fru, id, header.offset.product*8); 2925*c18ec02fSPetter Reinholdtsen 2926*c18ec02fSPetter Reinholdtsen /* multirecord area */ 2927*c18ec02fSPetter Reinholdtsen if( verbose==0 ) /* scipp parsing multirecord */ 2928*c18ec02fSPetter Reinholdtsen return 0; 2929*c18ec02fSPetter Reinholdtsen 2930*c18ec02fSPetter Reinholdtsen if ((header.offset.multi*8) >= sizeof(struct fru_header)) 2931*c18ec02fSPetter Reinholdtsen fru_area_print_multirec(intf, &fru, id, header.offset.multi*8); 2932*c18ec02fSPetter Reinholdtsen 2933*c18ec02fSPetter Reinholdtsen return 0; 2934*c18ec02fSPetter Reinholdtsen } 2935*c18ec02fSPetter Reinholdtsen 2936*c18ec02fSPetter Reinholdtsen /* ipmi_fru_print - Print a FRU from its SDR locator record 2937*c18ec02fSPetter Reinholdtsen * 2938*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 2939*c18ec02fSPetter Reinholdtsen * @fru: SDR FRU Locator Record 2940*c18ec02fSPetter Reinholdtsen * 2941*c18ec02fSPetter Reinholdtsen * returns -1 on error 2942*c18ec02fSPetter Reinholdtsen */ 2943*c18ec02fSPetter Reinholdtsen int 2944*c18ec02fSPetter Reinholdtsen ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru) 2945*c18ec02fSPetter Reinholdtsen { 2946*c18ec02fSPetter Reinholdtsen char desc[17]; 2947*c18ec02fSPetter Reinholdtsen uint8_t bridged_request = 0; 2948*c18ec02fSPetter Reinholdtsen uint32_t save_addr; 2949*c18ec02fSPetter Reinholdtsen uint32_t save_channel; 2950*c18ec02fSPetter Reinholdtsen int rc = 0; 2951*c18ec02fSPetter Reinholdtsen 2952*c18ec02fSPetter Reinholdtsen if (fru == NULL) 2953*c18ec02fSPetter Reinholdtsen return __ipmi_fru_print(intf, 0); 2954*c18ec02fSPetter Reinholdtsen 2955*c18ec02fSPetter Reinholdtsen /* Logical FRU Device 2956*c18ec02fSPetter Reinholdtsen * dev_type == 0x10 2957*c18ec02fSPetter Reinholdtsen * modifier 2958*c18ec02fSPetter Reinholdtsen * 0x00 = IPMI FRU Inventory 2959*c18ec02fSPetter Reinholdtsen * 0x01 = DIMM Memory ID 2960*c18ec02fSPetter Reinholdtsen * 0x02 = IPMI FRU Inventory 2961*c18ec02fSPetter Reinholdtsen * 0x03 = System Processor FRU 2962*c18ec02fSPetter Reinholdtsen * 0xff = unspecified 2963*c18ec02fSPetter Reinholdtsen * 2964*c18ec02fSPetter Reinholdtsen * EEPROM 24C01 or equivalent 2965*c18ec02fSPetter Reinholdtsen * dev_type >= 0x08 && dev_type <= 0x0f 2966*c18ec02fSPetter Reinholdtsen * modifier 2967*c18ec02fSPetter Reinholdtsen * 0x00 = unspecified 2968*c18ec02fSPetter Reinholdtsen * 0x01 = DIMM Memory ID 2969*c18ec02fSPetter Reinholdtsen * 0x02 = IPMI FRU Inventory 2970*c18ec02fSPetter Reinholdtsen * 0x03 = System Processor Cartridge 2971*c18ec02fSPetter Reinholdtsen */ 2972*c18ec02fSPetter Reinholdtsen if (fru->dev_type != 0x10 && 2973*c18ec02fSPetter Reinholdtsen (fru->dev_type_modifier != 0x02 || 2974*c18ec02fSPetter Reinholdtsen fru->dev_type < 0x08 || fru->dev_type > 0x0f)) 2975*c18ec02fSPetter Reinholdtsen return -1; 2976*c18ec02fSPetter Reinholdtsen 2977*c18ec02fSPetter Reinholdtsen if (fru->dev_slave_addr == IPMI_BMC_SLAVE_ADDR && 2978*c18ec02fSPetter Reinholdtsen fru->device_id == 0) 2979*c18ec02fSPetter Reinholdtsen return 0; 2980*c18ec02fSPetter Reinholdtsen 2981*c18ec02fSPetter Reinholdtsen memset(desc, 0, sizeof(desc)); 2982*c18ec02fSPetter Reinholdtsen memcpy(desc, fru->id_string, fru->id_code & 0x01f); 2983*c18ec02fSPetter Reinholdtsen desc[fru->id_code & 0x01f] = 0; 2984*c18ec02fSPetter Reinholdtsen printf("FRU Device Description : %s (ID %d)\n", desc, fru->device_id); 2985*c18ec02fSPetter Reinholdtsen 2986*c18ec02fSPetter Reinholdtsen switch (fru->dev_type_modifier) { 2987*c18ec02fSPetter Reinholdtsen case 0x00: 2988*c18ec02fSPetter Reinholdtsen case 0x02: 2989*c18ec02fSPetter Reinholdtsen if (BRIDGE_TO_SENSOR(intf, fru->dev_slave_addr, 2990*c18ec02fSPetter Reinholdtsen fru->channel_num)) { 2991*c18ec02fSPetter Reinholdtsen bridged_request = 1; 2992*c18ec02fSPetter Reinholdtsen save_addr = intf->target_addr; 2993*c18ec02fSPetter Reinholdtsen intf->target_addr = fru->dev_slave_addr; 2994*c18ec02fSPetter Reinholdtsen save_channel = intf->target_channel; 2995*c18ec02fSPetter Reinholdtsen intf->target_channel = fru->channel_num; 2996*c18ec02fSPetter Reinholdtsen } 2997*c18ec02fSPetter Reinholdtsen /* print FRU */ 2998*c18ec02fSPetter Reinholdtsen rc = __ipmi_fru_print(intf, fru->device_id); 2999*c18ec02fSPetter Reinholdtsen if (bridged_request) { 3000*c18ec02fSPetter Reinholdtsen intf->target_addr = save_addr; 3001*c18ec02fSPetter Reinholdtsen intf->target_channel = save_channel; 3002*c18ec02fSPetter Reinholdtsen } 3003*c18ec02fSPetter Reinholdtsen break; 3004*c18ec02fSPetter Reinholdtsen case 0x01: 3005*c18ec02fSPetter Reinholdtsen rc = ipmi_spd_print_fru(intf, fru->device_id); 3006*c18ec02fSPetter Reinholdtsen break; 3007*c18ec02fSPetter Reinholdtsen default: 3008*c18ec02fSPetter Reinholdtsen if (verbose) 3009*c18ec02fSPetter Reinholdtsen printf(" Unsupported device 0x%02x " 3010*c18ec02fSPetter Reinholdtsen "type 0x%02x with modifier 0x%02x\n", 3011*c18ec02fSPetter Reinholdtsen fru->device_id, fru->dev_type, 3012*c18ec02fSPetter Reinholdtsen fru->dev_type_modifier); 3013*c18ec02fSPetter Reinholdtsen else 3014*c18ec02fSPetter Reinholdtsen printf(" Unsupported device\n"); 3015*c18ec02fSPetter Reinholdtsen } 3016*c18ec02fSPetter Reinholdtsen printf("\n"); 3017*c18ec02fSPetter Reinholdtsen 3018*c18ec02fSPetter Reinholdtsen return rc; 3019*c18ec02fSPetter Reinholdtsen } 3020*c18ec02fSPetter Reinholdtsen 3021*c18ec02fSPetter Reinholdtsen /* ipmi_fru_print_all - Print builtin FRU + SDR FRU Locator records 3022*c18ec02fSPetter Reinholdtsen * 3023*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 3024*c18ec02fSPetter Reinholdtsen * 3025*c18ec02fSPetter Reinholdtsen * returns -1 on error 3026*c18ec02fSPetter Reinholdtsen */ 3027*c18ec02fSPetter Reinholdtsen static int 3028*c18ec02fSPetter Reinholdtsen ipmi_fru_print_all(struct ipmi_intf * intf) 3029*c18ec02fSPetter Reinholdtsen { 3030*c18ec02fSPetter Reinholdtsen struct ipmi_sdr_iterator * itr; 3031*c18ec02fSPetter Reinholdtsen struct sdr_get_rs * header; 3032*c18ec02fSPetter Reinholdtsen struct sdr_record_fru_locator * fru; 3033*c18ec02fSPetter Reinholdtsen int rc; 3034*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 3035*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 3036*c18ec02fSPetter Reinholdtsen struct ipm_devid_rsp *devid; 3037*c18ec02fSPetter Reinholdtsen struct sdr_record_mc_locator * mc; 3038*c18ec02fSPetter Reinholdtsen uint32_t save_addr; 3039*c18ec02fSPetter Reinholdtsen 3040*c18ec02fSPetter Reinholdtsen printf("FRU Device Description : Builtin FRU Device (ID 0)\n"); 3041*c18ec02fSPetter Reinholdtsen /* TODO: Figure out if FRU device 0 may show up in SDR records. */ 3042*c18ec02fSPetter Reinholdtsen 3043*c18ec02fSPetter Reinholdtsen /* Do a Get Device ID command to determine device support */ 3044*c18ec02fSPetter Reinholdtsen memset (&req, 0, sizeof(req)); 3045*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_APP; 3046*c18ec02fSPetter Reinholdtsen req.msg.cmd = BMC_GET_DEVICE_ID; 3047*c18ec02fSPetter Reinholdtsen req.msg.data_len = 0; 3048*c18ec02fSPetter Reinholdtsen 3049*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 3050*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 3051*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Get Device ID command failed"); 3052*c18ec02fSPetter Reinholdtsen return -1; 3053*c18ec02fSPetter Reinholdtsen } 3054*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 3055*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Get Device ID command failed: %s", 3056*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 3057*c18ec02fSPetter Reinholdtsen return -1; 3058*c18ec02fSPetter Reinholdtsen } 3059*c18ec02fSPetter Reinholdtsen 3060*c18ec02fSPetter Reinholdtsen devid = (struct ipm_devid_rsp *) rsp->data; 3061*c18ec02fSPetter Reinholdtsen 3062*c18ec02fSPetter Reinholdtsen /* Check the FRU inventory device bit to decide whether various */ 3063*c18ec02fSPetter Reinholdtsen /* FRU commands can be issued to FRU device #0 LUN 0 */ 3064*c18ec02fSPetter Reinholdtsen 3065*c18ec02fSPetter Reinholdtsen if (devid->adtl_device_support & 0x08) { /* FRU Inventory Device bit? */ 3066*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_print(intf, NULL); 3067*c18ec02fSPetter Reinholdtsen printf("\n"); 3068*c18ec02fSPetter Reinholdtsen } 3069*c18ec02fSPetter Reinholdtsen 3070*c18ec02fSPetter Reinholdtsen if ((itr = ipmi_sdr_start(intf, 0)) == NULL) 3071*c18ec02fSPetter Reinholdtsen return -1; 3072*c18ec02fSPetter Reinholdtsen 3073*c18ec02fSPetter Reinholdtsen /* Walk the SDRs looking for FRU Devices and Management Controller Devices. */ 3074*c18ec02fSPetter Reinholdtsen /* For FRU devices, print the FRU from the SDR locator record. */ 3075*c18ec02fSPetter Reinholdtsen /* For MC devices, issue FRU commands to the satellite controller to print */ 3076*c18ec02fSPetter Reinholdtsen /* FRU data. */ 3077*c18ec02fSPetter Reinholdtsen while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) 3078*c18ec02fSPetter Reinholdtsen { 3079*c18ec02fSPetter Reinholdtsen if (header->type == SDR_RECORD_TYPE_MC_DEVICE_LOCATOR ) { 3080*c18ec02fSPetter Reinholdtsen /* Check the capabilities of the Management Controller Device */ 3081*c18ec02fSPetter Reinholdtsen mc = (struct sdr_record_mc_locator *) 3082*c18ec02fSPetter Reinholdtsen ipmi_sdr_get_record(intf, header, itr); 3083*c18ec02fSPetter Reinholdtsen /* Does this MC device support FRU inventory device? */ 3084*c18ec02fSPetter Reinholdtsen if (mc && (mc->dev_support & 0x08)) { /* FRU inventory device? */ 3085*c18ec02fSPetter Reinholdtsen /* Yes. Prepare to issue FRU commands to FRU device #0 LUN 0 */ 3086*c18ec02fSPetter Reinholdtsen /* using the slave address specified in the MC record. */ 3087*c18ec02fSPetter Reinholdtsen 3088*c18ec02fSPetter Reinholdtsen /* save current target address */ 3089*c18ec02fSPetter Reinholdtsen save_addr = intf->target_addr; 3090*c18ec02fSPetter Reinholdtsen 3091*c18ec02fSPetter Reinholdtsen /* set new target address to satellite controller */ 3092*c18ec02fSPetter Reinholdtsen intf->target_addr = mc->dev_slave_addr; 3093*c18ec02fSPetter Reinholdtsen 3094*c18ec02fSPetter Reinholdtsen printf("FRU Device Description : %-16s\n", mc->id_string); 3095*c18ec02fSPetter Reinholdtsen 3096*c18ec02fSPetter Reinholdtsen /* print the FRU by issuing FRU commands to the satellite */ 3097*c18ec02fSPetter Reinholdtsen /* controller. */ 3098*c18ec02fSPetter Reinholdtsen rc = __ipmi_fru_print(intf, 0); 3099*c18ec02fSPetter Reinholdtsen 3100*c18ec02fSPetter Reinholdtsen printf("\n"); 3101*c18ec02fSPetter Reinholdtsen 3102*c18ec02fSPetter Reinholdtsen /* restore previous target */ 3103*c18ec02fSPetter Reinholdtsen intf->target_addr = save_addr; 3104*c18ec02fSPetter Reinholdtsen } 3105*c18ec02fSPetter Reinholdtsen 3106*c18ec02fSPetter Reinholdtsen if (mc) { 3107*c18ec02fSPetter Reinholdtsen free(mc); 3108*c18ec02fSPetter Reinholdtsen mc = NULL; 3109*c18ec02fSPetter Reinholdtsen } 3110*c18ec02fSPetter Reinholdtsen 3111*c18ec02fSPetter Reinholdtsen continue; 3112*c18ec02fSPetter Reinholdtsen } 3113*c18ec02fSPetter Reinholdtsen 3114*c18ec02fSPetter Reinholdtsen if (header->type != SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR) 3115*c18ec02fSPetter Reinholdtsen continue; 3116*c18ec02fSPetter Reinholdtsen 3117*c18ec02fSPetter Reinholdtsen /* Print the FRU from the SDR locator record. */ 3118*c18ec02fSPetter Reinholdtsen fru = (struct sdr_record_fru_locator *) 3119*c18ec02fSPetter Reinholdtsen ipmi_sdr_get_record(intf, header, itr); 3120*c18ec02fSPetter Reinholdtsen if (fru == NULL || !fru->logical) { 3121*c18ec02fSPetter Reinholdtsen if (fru) { 3122*c18ec02fSPetter Reinholdtsen free(fru); 3123*c18ec02fSPetter Reinholdtsen fru = NULL; 3124*c18ec02fSPetter Reinholdtsen } 3125*c18ec02fSPetter Reinholdtsen continue; 3126*c18ec02fSPetter Reinholdtsen } 3127*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_print(intf, fru); 3128*c18ec02fSPetter Reinholdtsen free(fru); 3129*c18ec02fSPetter Reinholdtsen fru = NULL; 3130*c18ec02fSPetter Reinholdtsen } 3131*c18ec02fSPetter Reinholdtsen 3132*c18ec02fSPetter Reinholdtsen ipmi_sdr_end(intf, itr); 3133*c18ec02fSPetter Reinholdtsen 3134*c18ec02fSPetter Reinholdtsen return rc; 3135*c18ec02fSPetter Reinholdtsen } 3136*c18ec02fSPetter Reinholdtsen 3137*c18ec02fSPetter Reinholdtsen /* ipmi_fru_read_help() - print help text for 'read' 3138*c18ec02fSPetter Reinholdtsen * 3139*c18ec02fSPetter Reinholdtsen * returns void 3140*c18ec02fSPetter Reinholdtsen */ 3141*c18ec02fSPetter Reinholdtsen void 3142*c18ec02fSPetter Reinholdtsen ipmi_fru_read_help() 3143*c18ec02fSPetter Reinholdtsen { 3144*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "fru read <fru id> <fru file>"); 3145*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified."); 3146*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "Example: ipmitool fru read 0 /root/fru.bin"); 3147*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_read_help() */ 3148*c18ec02fSPetter Reinholdtsen 3149*c18ec02fSPetter Reinholdtsen static void 3150*c18ec02fSPetter Reinholdtsen ipmi_fru_read_to_bin(struct ipmi_intf * intf, 3151*c18ec02fSPetter Reinholdtsen char * pFileName, 3152*c18ec02fSPetter Reinholdtsen uint8_t fruId) 3153*c18ec02fSPetter Reinholdtsen { 3154*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 3155*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 3156*c18ec02fSPetter Reinholdtsen struct fru_info fru; 3157*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 3158*c18ec02fSPetter Reinholdtsen uint8_t * pFruBuf; 3159*c18ec02fSPetter Reinholdtsen 3160*c18ec02fSPetter Reinholdtsen msg_data[0] = fruId; 3161*c18ec02fSPetter Reinholdtsen 3162*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 3163*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 3164*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_INFO; 3165*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 3166*c18ec02fSPetter Reinholdtsen req.msg.data_len = 1; 3167*c18ec02fSPetter Reinholdtsen 3168*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 3169*c18ec02fSPetter Reinholdtsen if (!rsp) 3170*c18ec02fSPetter Reinholdtsen return; 3171*c18ec02fSPetter Reinholdtsen 3172*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 3173*c18ec02fSPetter Reinholdtsen if (rsp->ccode == 0xc3) 3174*c18ec02fSPetter Reinholdtsen printf (" Timeout accessing FRU info. (Device not present?)\n"); 3175*c18ec02fSPetter Reinholdtsen return; 3176*c18ec02fSPetter Reinholdtsen } 3177*c18ec02fSPetter Reinholdtsen 3178*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(fru)); 3179*c18ec02fSPetter Reinholdtsen fru.size = (rsp->data[1] << 8) | rsp->data[0]; 3180*c18ec02fSPetter Reinholdtsen fru.access = rsp->data[2] & 0x1; 3181*c18ec02fSPetter Reinholdtsen 3182*c18ec02fSPetter Reinholdtsen if (verbose) { 3183*c18ec02fSPetter Reinholdtsen printf("Fru Size = %d bytes\n",fru.size); 3184*c18ec02fSPetter Reinholdtsen printf("Fru Access = %xh\n", fru.access); 3185*c18ec02fSPetter Reinholdtsen } 3186*c18ec02fSPetter Reinholdtsen 3187*c18ec02fSPetter Reinholdtsen pFruBuf = malloc(fru.size); 3188*c18ec02fSPetter Reinholdtsen if (pFruBuf != NULL) { 3189*c18ec02fSPetter Reinholdtsen printf("Fru Size : %d bytes\n",fru.size); 3190*c18ec02fSPetter Reinholdtsen read_fru_area(intf, &fru, fruId, 0, fru.size, pFruBuf); 3191*c18ec02fSPetter Reinholdtsen } else { 3192*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Cannot allocate %d bytes\n", fru.size); 3193*c18ec02fSPetter Reinholdtsen return; 3194*c18ec02fSPetter Reinholdtsen } 3195*c18ec02fSPetter Reinholdtsen 3196*c18ec02fSPetter Reinholdtsen if(pFruBuf != NULL) 3197*c18ec02fSPetter Reinholdtsen { 3198*c18ec02fSPetter Reinholdtsen FILE * pFile; 3199*c18ec02fSPetter Reinholdtsen pFile = fopen(pFileName,"wb"); 3200*c18ec02fSPetter Reinholdtsen if (pFile) { 3201*c18ec02fSPetter Reinholdtsen fwrite(pFruBuf, fru.size, 1, pFile); 3202*c18ec02fSPetter Reinholdtsen printf("Done\n"); 3203*c18ec02fSPetter Reinholdtsen } else { 3204*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Error opening file %s\n", pFileName); 3205*c18ec02fSPetter Reinholdtsen free(pFruBuf); 3206*c18ec02fSPetter Reinholdtsen pFruBuf = NULL; 3207*c18ec02fSPetter Reinholdtsen return; 3208*c18ec02fSPetter Reinholdtsen } 3209*c18ec02fSPetter Reinholdtsen fclose(pFile); 3210*c18ec02fSPetter Reinholdtsen } 3211*c18ec02fSPetter Reinholdtsen free(pFruBuf); 3212*c18ec02fSPetter Reinholdtsen pFruBuf = NULL; 3213*c18ec02fSPetter Reinholdtsen } 3214*c18ec02fSPetter Reinholdtsen 3215*c18ec02fSPetter Reinholdtsen static void 3216*c18ec02fSPetter Reinholdtsen ipmi_fru_write_from_bin(struct ipmi_intf * intf, 3217*c18ec02fSPetter Reinholdtsen char * pFileName, 3218*c18ec02fSPetter Reinholdtsen uint8_t fruId) 3219*c18ec02fSPetter Reinholdtsen { 3220*c18ec02fSPetter Reinholdtsen struct ipmi_rs *rsp; 3221*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 3222*c18ec02fSPetter Reinholdtsen struct fru_info fru; 3223*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 3224*c18ec02fSPetter Reinholdtsen uint8_t *pFruBuf; 3225*c18ec02fSPetter Reinholdtsen uint16_t len = 0; 3226*c18ec02fSPetter Reinholdtsen FILE *pFile; 3227*c18ec02fSPetter Reinholdtsen 3228*c18ec02fSPetter Reinholdtsen msg_data[0] = fruId; 3229*c18ec02fSPetter Reinholdtsen 3230*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof (req)); 3231*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 3232*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_INFO; 3233*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 3234*c18ec02fSPetter Reinholdtsen req.msg.data_len = 1; 3235*c18ec02fSPetter Reinholdtsen 3236*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 3237*c18ec02fSPetter Reinholdtsen if (!rsp) 3238*c18ec02fSPetter Reinholdtsen return; 3239*c18ec02fSPetter Reinholdtsen 3240*c18ec02fSPetter Reinholdtsen if (rsp->ccode) { 3241*c18ec02fSPetter Reinholdtsen if (rsp->ccode == 0xc3) 3242*c18ec02fSPetter Reinholdtsen printf(" Timeout accessing FRU info. (Device not present?)\n"); 3243*c18ec02fSPetter Reinholdtsen return; 3244*c18ec02fSPetter Reinholdtsen } 3245*c18ec02fSPetter Reinholdtsen 3246*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(fru)); 3247*c18ec02fSPetter Reinholdtsen fru.size = (rsp->data[1] << 8) | rsp->data[0]; 3248*c18ec02fSPetter Reinholdtsen fru.access = rsp->data[2] & 0x1; 3249*c18ec02fSPetter Reinholdtsen 3250*c18ec02fSPetter Reinholdtsen if (verbose) { 3251*c18ec02fSPetter Reinholdtsen printf("Fru Size = %d bytes\n", fru.size); 3252*c18ec02fSPetter Reinholdtsen printf("Fru Access = %xh\n", fru.access); 3253*c18ec02fSPetter Reinholdtsen } 3254*c18ec02fSPetter Reinholdtsen 3255*c18ec02fSPetter Reinholdtsen pFruBuf = malloc(fru.size); 3256*c18ec02fSPetter Reinholdtsen if (pFruBuf == NULL) { 3257*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Cannot allocate %d bytes\n", fru.size); 3258*c18ec02fSPetter Reinholdtsen return; 3259*c18ec02fSPetter Reinholdtsen } 3260*c18ec02fSPetter Reinholdtsen 3261*c18ec02fSPetter Reinholdtsen pFile = fopen(pFileName, "rb"); 3262*c18ec02fSPetter Reinholdtsen if (pFile != NULL) { 3263*c18ec02fSPetter Reinholdtsen len = fread(pFruBuf, 1, fru.size, pFile); 3264*c18ec02fSPetter Reinholdtsen printf("Fru Size : %d bytes\n", fru.size); 3265*c18ec02fSPetter Reinholdtsen printf("Size to Write : %d bytes\n", len); 3266*c18ec02fSPetter Reinholdtsen fclose(pFile); 3267*c18ec02fSPetter Reinholdtsen } else { 3268*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Error opening file %s\n", pFileName); 3269*c18ec02fSPetter Reinholdtsen } 3270*c18ec02fSPetter Reinholdtsen 3271*c18ec02fSPetter Reinholdtsen if (len != 0) { 3272*c18ec02fSPetter Reinholdtsen write_fru_area(intf, &fru, fruId,0, 0, len, pFruBuf); 3273*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO,"Done"); 3274*c18ec02fSPetter Reinholdtsen } 3275*c18ec02fSPetter Reinholdtsen 3276*c18ec02fSPetter Reinholdtsen free(pFruBuf); 3277*c18ec02fSPetter Reinholdtsen pFruBuf = NULL; 3278*c18ec02fSPetter Reinholdtsen } 3279*c18ec02fSPetter Reinholdtsen 3280*c18ec02fSPetter Reinholdtsen /* ipmi_fru_write_help() - print help text for 'write' 3281*c18ec02fSPetter Reinholdtsen * 3282*c18ec02fSPetter Reinholdtsen * retruns void 3283*c18ec02fSPetter Reinholdtsen */ 3284*c18ec02fSPetter Reinholdtsen void 3285*c18ec02fSPetter Reinholdtsen ipmi_fru_write_help() 3286*c18ec02fSPetter Reinholdtsen { 3287*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "fru write <fru id> <fru file>"); 3288*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified."); 3289*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "Example: ipmitool fru write 0 /root/fru.bin"); 3290*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_write_help() */ 3291*c18ec02fSPetter Reinholdtsen 3292*c18ec02fSPetter Reinholdtsen /* ipmi_fru_edit_help - print help text for 'fru edit' command 3293*c18ec02fSPetter Reinholdtsen * 3294*c18ec02fSPetter Reinholdtsen * returns void 3295*c18ec02fSPetter Reinholdtsen */ 3296*c18ec02fSPetter Reinholdtsen void 3297*c18ec02fSPetter Reinholdtsen ipmi_fru_edit_help() 3298*c18ec02fSPetter Reinholdtsen { 3299*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, 3300*c18ec02fSPetter Reinholdtsen "fru edit <fruid> field <section> <index> <string> - edit FRU string"); 3301*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, 3302*c18ec02fSPetter Reinholdtsen "fru edit <fruid> oem iana <record> <format> <args> - limited OEM support"); 3303*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_edit_help() */ 3304*c18ec02fSPetter Reinholdtsen 3305*c18ec02fSPetter Reinholdtsen /* ipmi_fru_edit_multirec - Query new values to replace original FRU content 3306*c18ec02fSPetter Reinholdtsen * 3307*c18ec02fSPetter Reinholdtsen * @intf: interface to use 3308*c18ec02fSPetter Reinholdtsen * @id: FRU id to work on 3309*c18ec02fSPetter Reinholdtsen * 3310*c18ec02fSPetter Reinholdtsen * returns: nothing 3311*c18ec02fSPetter Reinholdtsen */ 3312*c18ec02fSPetter Reinholdtsen /* Work in progress, copy paste most of the stuff for other functions in this 3313*c18ec02fSPetter Reinholdtsen file ... not elegant yet */ 3314*c18ec02fSPetter Reinholdtsen static int 3315*c18ec02fSPetter Reinholdtsen ipmi_fru_edit_multirec(struct ipmi_intf * intf, uint8_t id , 3316*c18ec02fSPetter Reinholdtsen int argc, char ** argv) 3317*c18ec02fSPetter Reinholdtsen { 3318*c18ec02fSPetter Reinholdtsen 3319*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 3320*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 3321*c18ec02fSPetter Reinholdtsen struct fru_info fru; 3322*c18ec02fSPetter Reinholdtsen struct fru_header header; 3323*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 3324*c18ec02fSPetter Reinholdtsen 3325*c18ec02fSPetter Reinholdtsen uint16_t retStatus = 0; 3326*c18ec02fSPetter Reinholdtsen uint32_t offFruMultiRec; 3327*c18ec02fSPetter Reinholdtsen uint32_t fruMultiRecSize = 0; 3328*c18ec02fSPetter Reinholdtsen struct fru_info fruInfo; 3329*c18ec02fSPetter Reinholdtsen retStatus = ipmi_fru_get_multirec_location_from_fru(intf, id, &fruInfo, 3330*c18ec02fSPetter Reinholdtsen &offFruMultiRec, 3331*c18ec02fSPetter Reinholdtsen &fruMultiRecSize); 3332*c18ec02fSPetter Reinholdtsen 3333*c18ec02fSPetter Reinholdtsen 3334*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "FRU Size : %lu\n", fruMultiRecSize); 3335*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec); 3336*c18ec02fSPetter Reinholdtsen 3337*c18ec02fSPetter Reinholdtsen { 3338*c18ec02fSPetter Reinholdtsen 3339*c18ec02fSPetter Reinholdtsen 3340*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(struct fru_info)); 3341*c18ec02fSPetter Reinholdtsen memset(&header, 0, sizeof(struct fru_header)); 3342*c18ec02fSPetter Reinholdtsen 3343*c18ec02fSPetter Reinholdtsen /* 3344*c18ec02fSPetter Reinholdtsen * get info about this FRU 3345*c18ec02fSPetter Reinholdtsen */ 3346*c18ec02fSPetter Reinholdtsen memset(msg_data, 0, 4); 3347*c18ec02fSPetter Reinholdtsen msg_data[0] = id; 3348*c18ec02fSPetter Reinholdtsen 3349*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 3350*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 3351*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_INFO; 3352*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 3353*c18ec02fSPetter Reinholdtsen req.msg.data_len = 1; 3354*c18ec02fSPetter Reinholdtsen 3355*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 3356*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 3357*c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 3358*c18ec02fSPetter Reinholdtsen return -1; 3359*c18ec02fSPetter Reinholdtsen } 3360*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 3361*c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 3362*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 3363*c18ec02fSPetter Reinholdtsen return -1; 3364*c18ec02fSPetter Reinholdtsen } 3365*c18ec02fSPetter Reinholdtsen 3366*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(fru)); 3367*c18ec02fSPetter Reinholdtsen fru.size = (rsp->data[1] << 8) | rsp->data[0]; 3368*c18ec02fSPetter Reinholdtsen fru.access = rsp->data[2] & 0x1; 3369*c18ec02fSPetter Reinholdtsen 3370*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)", 3371*c18ec02fSPetter Reinholdtsen fru.size, fru.access ? "words" : "bytes"); 3372*c18ec02fSPetter Reinholdtsen 3373*c18ec02fSPetter Reinholdtsen if (fru.size < 1) { 3374*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Invalid FRU size %d", fru.size); 3375*c18ec02fSPetter Reinholdtsen return -1; 3376*c18ec02fSPetter Reinholdtsen } 3377*c18ec02fSPetter Reinholdtsen } 3378*c18ec02fSPetter Reinholdtsen 3379*c18ec02fSPetter Reinholdtsen { 3380*c18ec02fSPetter Reinholdtsen uint8_t * fru_data; 3381*c18ec02fSPetter Reinholdtsen uint32_t fru_len, i; 3382*c18ec02fSPetter Reinholdtsen uint32_t offset= offFruMultiRec; 3383*c18ec02fSPetter Reinholdtsen struct fru_multirec_header * h; 3384*c18ec02fSPetter Reinholdtsen uint32_t last_off, len; 3385*c18ec02fSPetter Reinholdtsen uint8_t error=0; 3386*c18ec02fSPetter Reinholdtsen 3387*c18ec02fSPetter Reinholdtsen i = last_off = offset; 3388*c18ec02fSPetter Reinholdtsen fru_len = 0; 3389*c18ec02fSPetter Reinholdtsen 3390*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(fru)); 3391*c18ec02fSPetter Reinholdtsen fru_data = malloc(fru.size + 1); 3392*c18ec02fSPetter Reinholdtsen if (fru_data == NULL) { 3393*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Out of memory!"); 3394*c18ec02fSPetter Reinholdtsen return -1; 3395*c18ec02fSPetter Reinholdtsen } 3396*c18ec02fSPetter Reinholdtsen memset(fru_data, 0, fru.size + 1); 3397*c18ec02fSPetter Reinholdtsen 3398*c18ec02fSPetter Reinholdtsen do { 3399*c18ec02fSPetter Reinholdtsen h = (struct fru_multirec_header *) (fru_data + i); 3400*c18ec02fSPetter Reinholdtsen 3401*c18ec02fSPetter Reinholdtsen /* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */ 3402*c18ec02fSPetter Reinholdtsen if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len))) 3403*c18ec02fSPetter Reinholdtsen { 3404*c18ec02fSPetter Reinholdtsen len = fru.size - last_off; 3405*c18ec02fSPetter Reinholdtsen if (len > FRU_MULTIREC_CHUNK_SIZE) 3406*c18ec02fSPetter Reinholdtsen len = FRU_MULTIREC_CHUNK_SIZE; 3407*c18ec02fSPetter Reinholdtsen 3408*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, &fru, id, last_off, len, fru_data) < 0) 3409*c18ec02fSPetter Reinholdtsen break; 3410*c18ec02fSPetter Reinholdtsen 3411*c18ec02fSPetter Reinholdtsen last_off += len; 3412*c18ec02fSPetter Reinholdtsen } 3413*c18ec02fSPetter Reinholdtsen if( h->type == FRU_RECORD_TYPE_OEM_EXTENSION ){ 3414*c18ec02fSPetter Reinholdtsen 3415*c18ec02fSPetter Reinholdtsen struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *) 3416*c18ec02fSPetter Reinholdtsen &fru_data[i + sizeof(struct fru_multirec_header)]; 3417*c18ec02fSPetter Reinholdtsen uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16; 3418*c18ec02fSPetter Reinholdtsen 3419*c18ec02fSPetter Reinholdtsen uint32_t suppliedIana = 0 ; 3420*c18ec02fSPetter Reinholdtsen /* Now makes sure this is really PICMG record */ 3421*c18ec02fSPetter Reinholdtsen 3422*c18ec02fSPetter Reinholdtsen /* Default to PICMG for backward compatibility */ 3423*c18ec02fSPetter Reinholdtsen if( argc <=2 ) { 3424*c18ec02fSPetter Reinholdtsen suppliedIana = IPMI_OEM_PICMG; 3425*c18ec02fSPetter Reinholdtsen } else { 3426*c18ec02fSPetter Reinholdtsen if( !strncmp( argv[2] , "oem" , 3 )) { 3427*c18ec02fSPetter Reinholdtsen /* Expect IANA number next */ 3428*c18ec02fSPetter Reinholdtsen if( argc <= 3 ) { 3429*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "oem iana <record> <format> [<args>]"); 3430*c18ec02fSPetter Reinholdtsen error = 1; 3431*c18ec02fSPetter Reinholdtsen } else { 3432*c18ec02fSPetter Reinholdtsen if (str2uint(argv[3], &suppliedIana) == 0) { 3433*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, 3434*c18ec02fSPetter Reinholdtsen "using iana: %d", 3435*c18ec02fSPetter Reinholdtsen suppliedIana); 3436*c18ec02fSPetter Reinholdtsen } else { 3437*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, 3438*c18ec02fSPetter Reinholdtsen "Given IANA '%s' is invalid.", 3439*c18ec02fSPetter Reinholdtsen argv[3]); 3440*c18ec02fSPetter Reinholdtsen error = 1; 3441*c18ec02fSPetter Reinholdtsen } 3442*c18ec02fSPetter Reinholdtsen } 3443*c18ec02fSPetter Reinholdtsen } 3444*c18ec02fSPetter Reinholdtsen } 3445*c18ec02fSPetter Reinholdtsen 3446*c18ec02fSPetter Reinholdtsen if( suppliedIana == iana ) { 3447*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "Matching record found" ); 3448*c18ec02fSPetter Reinholdtsen 3449*c18ec02fSPetter Reinholdtsen if( iana == IPMI_OEM_PICMG ){ 3450*c18ec02fSPetter Reinholdtsen if( ipmi_fru_picmg_ext_edit(fru_data, 3451*c18ec02fSPetter Reinholdtsen i + sizeof(struct fru_multirec_header), 3452*c18ec02fSPetter Reinholdtsen h->len, h, oh )){ 3453*c18ec02fSPetter Reinholdtsen /* The fru changed */ 3454*c18ec02fSPetter Reinholdtsen write_fru_area(intf,&fru,id, i,i, 3455*c18ec02fSPetter Reinholdtsen h->len+ sizeof(struct fru_multirec_header), fru_data); 3456*c18ec02fSPetter Reinholdtsen } 3457*c18ec02fSPetter Reinholdtsen } 3458*c18ec02fSPetter Reinholdtsen else if( iana == IPMI_OEM_KONTRON ) { 3459*c18ec02fSPetter Reinholdtsen if( ipmi_fru_oemkontron_edit( argc,argv,fru_data, 3460*c18ec02fSPetter Reinholdtsen i + sizeof(struct fru_multirec_header), 3461*c18ec02fSPetter Reinholdtsen h->len, h, oh )){ 3462*c18ec02fSPetter Reinholdtsen /* The fru changed */ 3463*c18ec02fSPetter Reinholdtsen write_fru_area(intf,&fru,id, i,i, 3464*c18ec02fSPetter Reinholdtsen h->len+ sizeof(struct fru_multirec_header), fru_data); 3465*c18ec02fSPetter Reinholdtsen } 3466*c18ec02fSPetter Reinholdtsen } 3467*c18ec02fSPetter Reinholdtsen /* FIXME: Add OEM record support here */ 3468*c18ec02fSPetter Reinholdtsen else{ 3469*c18ec02fSPetter Reinholdtsen printf(" OEM IANA (%s) Record not support in this mode\n", 3470*c18ec02fSPetter Reinholdtsen val2str( iana, ipmi_oem_info)); 3471*c18ec02fSPetter Reinholdtsen error = 1; 3472*c18ec02fSPetter Reinholdtsen } 3473*c18ec02fSPetter Reinholdtsen } 3474*c18ec02fSPetter Reinholdtsen } 3475*c18ec02fSPetter Reinholdtsen i += h->len + sizeof (struct fru_multirec_header); 3476*c18ec02fSPetter Reinholdtsen } while (!(h->format & 0x80) && (error != 1)); 3477*c18ec02fSPetter Reinholdtsen 3478*c18ec02fSPetter Reinholdtsen free(fru_data); 3479*c18ec02fSPetter Reinholdtsen fru_data = NULL; 3480*c18ec02fSPetter Reinholdtsen } 3481*c18ec02fSPetter Reinholdtsen return 0; 3482*c18ec02fSPetter Reinholdtsen } 3483*c18ec02fSPetter Reinholdtsen 3484*c18ec02fSPetter Reinholdtsen /* ipmi_fru_get_help - print help text for 'fru get' 3485*c18ec02fSPetter Reinholdtsen * 3486*c18ec02fSPetter Reinholdtsen * returns void 3487*c18ec02fSPetter Reinholdtsen */ 3488*c18ec02fSPetter Reinholdtsen void 3489*c18ec02fSPetter Reinholdtsen ipmi_fru_get_help() 3490*c18ec02fSPetter Reinholdtsen { 3491*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, 3492*c18ec02fSPetter Reinholdtsen "fru get <fruid> oem iana <record> <format> <args> - limited OEM support"); 3493*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_get_help() */ 3494*c18ec02fSPetter Reinholdtsen 3495*c18ec02fSPetter Reinholdtsen void 3496*c18ec02fSPetter Reinholdtsen ipmi_fru_internaluse_help() 3497*c18ec02fSPetter Reinholdtsen { 3498*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, 3499*c18ec02fSPetter Reinholdtsen "fru internaluse <fru id> info - get internal use area size"); 3500*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, 3501*c18ec02fSPetter Reinholdtsen "fru internaluse <fru id> print - print internal use area in hex"); 3502*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, 3503*c18ec02fSPetter Reinholdtsen "fru internaluse <fru id> read <fru file> - read internal use area to file"); 3504*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, 3505*c18ec02fSPetter Reinholdtsen "fru internaluse <fru id> write <fru file> - write internal use area from file"); 3506*c18ec02fSPetter Reinholdtsen } /* void ipmi_fru_internaluse_help() */ 3507*c18ec02fSPetter Reinholdtsen 3508*c18ec02fSPetter Reinholdtsen /* ipmi_fru_get_multirec - Query new values to replace original FRU content 3509*c18ec02fSPetter Reinholdtsen * 3510*c18ec02fSPetter Reinholdtsen * @intf: interface to use 3511*c18ec02fSPetter Reinholdtsen * @id: FRU id to work on 3512*c18ec02fSPetter Reinholdtsen * 3513*c18ec02fSPetter Reinholdtsen * returns: nothing 3514*c18ec02fSPetter Reinholdtsen */ 3515*c18ec02fSPetter Reinholdtsen /* Work in progress, copy paste most of the stuff for other functions in this 3516*c18ec02fSPetter Reinholdtsen file ... not elegant yet */ 3517*c18ec02fSPetter Reinholdtsen static int 3518*c18ec02fSPetter Reinholdtsen ipmi_fru_get_multirec(struct ipmi_intf * intf, uint8_t id , 3519*c18ec02fSPetter Reinholdtsen int argc, char ** argv) 3520*c18ec02fSPetter Reinholdtsen { 3521*c18ec02fSPetter Reinholdtsen 3522*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 3523*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 3524*c18ec02fSPetter Reinholdtsen struct fru_info fru; 3525*c18ec02fSPetter Reinholdtsen struct fru_header header; 3526*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 3527*c18ec02fSPetter Reinholdtsen 3528*c18ec02fSPetter Reinholdtsen uint16_t retStatus = 0; 3529*c18ec02fSPetter Reinholdtsen uint32_t offFruMultiRec; 3530*c18ec02fSPetter Reinholdtsen uint32_t fruMultiRecSize = 0; 3531*c18ec02fSPetter Reinholdtsen struct fru_info fruInfo; 3532*c18ec02fSPetter Reinholdtsen retStatus = ipmi_fru_get_multirec_location_from_fru(intf, id, &fruInfo, 3533*c18ec02fSPetter Reinholdtsen &offFruMultiRec, 3534*c18ec02fSPetter Reinholdtsen &fruMultiRecSize); 3535*c18ec02fSPetter Reinholdtsen 3536*c18ec02fSPetter Reinholdtsen 3537*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "FRU Size : %lu\n", fruMultiRecSize); 3538*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec); 3539*c18ec02fSPetter Reinholdtsen 3540*c18ec02fSPetter Reinholdtsen { 3541*c18ec02fSPetter Reinholdtsen 3542*c18ec02fSPetter Reinholdtsen 3543*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(struct fru_info)); 3544*c18ec02fSPetter Reinholdtsen memset(&header, 0, sizeof(struct fru_header)); 3545*c18ec02fSPetter Reinholdtsen 3546*c18ec02fSPetter Reinholdtsen /* 3547*c18ec02fSPetter Reinholdtsen * get info about this FRU 3548*c18ec02fSPetter Reinholdtsen */ 3549*c18ec02fSPetter Reinholdtsen memset(msg_data, 0, 4); 3550*c18ec02fSPetter Reinholdtsen msg_data[0] = id; 3551*c18ec02fSPetter Reinholdtsen 3552*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 3553*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 3554*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_INFO; 3555*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 3556*c18ec02fSPetter Reinholdtsen req.msg.data_len = 1; 3557*c18ec02fSPetter Reinholdtsen 3558*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 3559*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 3560*c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 3561*c18ec02fSPetter Reinholdtsen return -1; 3562*c18ec02fSPetter Reinholdtsen } 3563*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 3564*c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 3565*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 3566*c18ec02fSPetter Reinholdtsen return -1; 3567*c18ec02fSPetter Reinholdtsen } 3568*c18ec02fSPetter Reinholdtsen 3569*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(fru)); 3570*c18ec02fSPetter Reinholdtsen fru.size = (rsp->data[1] << 8) | rsp->data[0]; 3571*c18ec02fSPetter Reinholdtsen fru.access = rsp->data[2] & 0x1; 3572*c18ec02fSPetter Reinholdtsen 3573*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)", 3574*c18ec02fSPetter Reinholdtsen fru.size, fru.access ? "words" : "bytes"); 3575*c18ec02fSPetter Reinholdtsen 3576*c18ec02fSPetter Reinholdtsen if (fru.size < 1) { 3577*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Invalid FRU size %d", fru.size); 3578*c18ec02fSPetter Reinholdtsen return -1; 3579*c18ec02fSPetter Reinholdtsen } 3580*c18ec02fSPetter Reinholdtsen } 3581*c18ec02fSPetter Reinholdtsen 3582*c18ec02fSPetter Reinholdtsen { 3583*c18ec02fSPetter Reinholdtsen uint8_t * fru_data; 3584*c18ec02fSPetter Reinholdtsen uint32_t fru_len, i; 3585*c18ec02fSPetter Reinholdtsen uint32_t offset= offFruMultiRec; 3586*c18ec02fSPetter Reinholdtsen struct fru_multirec_header * h; 3587*c18ec02fSPetter Reinholdtsen uint32_t last_off, len; 3588*c18ec02fSPetter Reinholdtsen uint8_t error=0; 3589*c18ec02fSPetter Reinholdtsen 3590*c18ec02fSPetter Reinholdtsen i = last_off = offset; 3591*c18ec02fSPetter Reinholdtsen fru_len = 0; 3592*c18ec02fSPetter Reinholdtsen 3593*c18ec02fSPetter Reinholdtsen fru_data = malloc(fru.size + 1); 3594*c18ec02fSPetter Reinholdtsen if (fru_data == NULL) { 3595*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Out of memory!"); 3596*c18ec02fSPetter Reinholdtsen return -1; 3597*c18ec02fSPetter Reinholdtsen } 3598*c18ec02fSPetter Reinholdtsen memset(fru_data, 0, fru.size + 1); 3599*c18ec02fSPetter Reinholdtsen 3600*c18ec02fSPetter Reinholdtsen do { 3601*c18ec02fSPetter Reinholdtsen h = (struct fru_multirec_header *) (fru_data + i); 3602*c18ec02fSPetter Reinholdtsen 3603*c18ec02fSPetter Reinholdtsen /* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */ 3604*c18ec02fSPetter Reinholdtsen if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len))) 3605*c18ec02fSPetter Reinholdtsen { 3606*c18ec02fSPetter Reinholdtsen len = fru.size - last_off; 3607*c18ec02fSPetter Reinholdtsen if (len > FRU_MULTIREC_CHUNK_SIZE) 3608*c18ec02fSPetter Reinholdtsen len = FRU_MULTIREC_CHUNK_SIZE; 3609*c18ec02fSPetter Reinholdtsen 3610*c18ec02fSPetter Reinholdtsen if (read_fru_area(intf, &fru, id, last_off, len, fru_data) < 0) 3611*c18ec02fSPetter Reinholdtsen break; 3612*c18ec02fSPetter Reinholdtsen 3613*c18ec02fSPetter Reinholdtsen last_off += len; 3614*c18ec02fSPetter Reinholdtsen } 3615*c18ec02fSPetter Reinholdtsen if( h->type == FRU_RECORD_TYPE_OEM_EXTENSION ){ 3616*c18ec02fSPetter Reinholdtsen 3617*c18ec02fSPetter Reinholdtsen struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *) 3618*c18ec02fSPetter Reinholdtsen &fru_data[i + sizeof(struct fru_multirec_header)]; 3619*c18ec02fSPetter Reinholdtsen uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16; 3620*c18ec02fSPetter Reinholdtsen 3621*c18ec02fSPetter Reinholdtsen uint32_t suppliedIana = 0 ; 3622*c18ec02fSPetter Reinholdtsen /* Now makes sure this is really PICMG record */ 3623*c18ec02fSPetter Reinholdtsen if( !strncmp( argv[2] , "oem" , 3 )) { 3624*c18ec02fSPetter Reinholdtsen /* Expect IANA number next */ 3625*c18ec02fSPetter Reinholdtsen if( argc <= 3 ) { 3626*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "oem iana <record> <format>"); 3627*c18ec02fSPetter Reinholdtsen error = 1; 3628*c18ec02fSPetter Reinholdtsen } else { 3629*c18ec02fSPetter Reinholdtsen if (str2uint(argv[3], &suppliedIana) == 0) { 3630*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, 3631*c18ec02fSPetter Reinholdtsen "using iana: %d", 3632*c18ec02fSPetter Reinholdtsen suppliedIana); 3633*c18ec02fSPetter Reinholdtsen } else { 3634*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, 3635*c18ec02fSPetter Reinholdtsen "Given IANA '%s' is invalid.", 3636*c18ec02fSPetter Reinholdtsen argv[3]); 3637*c18ec02fSPetter Reinholdtsen error = 1; 3638*c18ec02fSPetter Reinholdtsen } 3639*c18ec02fSPetter Reinholdtsen } 3640*c18ec02fSPetter Reinholdtsen } 3641*c18ec02fSPetter Reinholdtsen 3642*c18ec02fSPetter Reinholdtsen if( suppliedIana == iana ) { 3643*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "Matching record found" ); 3644*c18ec02fSPetter Reinholdtsen 3645*c18ec02fSPetter Reinholdtsen if( iana == IPMI_OEM_KONTRON ) { 3646*c18ec02fSPetter Reinholdtsen ipmi_fru_oemkontron_get( argc,argv,fru_data, 3647*c18ec02fSPetter Reinholdtsen i + sizeof(struct fru_multirec_header), 3648*c18ec02fSPetter Reinholdtsen h->len, h, oh ); 3649*c18ec02fSPetter Reinholdtsen } 3650*c18ec02fSPetter Reinholdtsen /* FIXME: Add OEM record support here */ 3651*c18ec02fSPetter Reinholdtsen else{ 3652*c18ec02fSPetter Reinholdtsen printf(" OEM IANA (%s) Record not supported in this mode\n", 3653*c18ec02fSPetter Reinholdtsen val2str( iana, ipmi_oem_info)); 3654*c18ec02fSPetter Reinholdtsen error = 1; 3655*c18ec02fSPetter Reinholdtsen } 3656*c18ec02fSPetter Reinholdtsen } 3657*c18ec02fSPetter Reinholdtsen } 3658*c18ec02fSPetter Reinholdtsen i += h->len + sizeof (struct fru_multirec_header); 3659*c18ec02fSPetter Reinholdtsen } while (!(h->format & 0x80) && (error != 1)); 3660*c18ec02fSPetter Reinholdtsen 3661*c18ec02fSPetter Reinholdtsen free(fru_data); 3662*c18ec02fSPetter Reinholdtsen fru_data = NULL; 3663*c18ec02fSPetter Reinholdtsen } 3664*c18ec02fSPetter Reinholdtsen return 0; 3665*c18ec02fSPetter Reinholdtsen } 3666*c18ec02fSPetter Reinholdtsen 3667*c18ec02fSPetter Reinholdtsen static int 3668*c18ec02fSPetter Reinholdtsen ipmi_fru_upg_ekeying(struct ipmi_intf * intf, 3669*c18ec02fSPetter Reinholdtsen char * pFileName, 3670*c18ec02fSPetter Reinholdtsen uint8_t fruId) 3671*c18ec02fSPetter Reinholdtsen { 3672*c18ec02fSPetter Reinholdtsen struct fru_info fruInfo; 3673*c18ec02fSPetter Reinholdtsen uint8_t *buf = NULL; 3674*c18ec02fSPetter Reinholdtsen uint32_t offFruMultiRec = 0; 3675*c18ec02fSPetter Reinholdtsen uint32_t fruMultiRecSize = 0; 3676*c18ec02fSPetter Reinholdtsen uint32_t offFileMultiRec = 0; 3677*c18ec02fSPetter Reinholdtsen uint32_t fileMultiRecSize = 0; 3678*c18ec02fSPetter Reinholdtsen if (pFileName == NULL) { 3679*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "File expected, but none given."); 3680*c18ec02fSPetter Reinholdtsen return (-1); 3681*c18ec02fSPetter Reinholdtsen } 3682*c18ec02fSPetter Reinholdtsen if (ipmi_fru_get_multirec_location_from_fru(intf, fruId, &fruInfo, 3683*c18ec02fSPetter Reinholdtsen &offFruMultiRec, &fruMultiRecSize) != 0) { 3684*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Failed to get multirec location from FRU."); 3685*c18ec02fSPetter Reinholdtsen return (-1); 3686*c18ec02fSPetter Reinholdtsen } 3687*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "FRU Size : %lu\n", fruMultiRecSize); 3688*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec); 3689*c18ec02fSPetter Reinholdtsen if (ipmi_fru_get_multirec_size_from_file(pFileName, &fileMultiRecSize, 3690*c18ec02fSPetter Reinholdtsen &offFileMultiRec) != 0) { 3691*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Failed to get multirec size from file '%s'.", pFileName); 3692*c18ec02fSPetter Reinholdtsen return (-1); 3693*c18ec02fSPetter Reinholdtsen } 3694*c18ec02fSPetter Reinholdtsen buf = malloc(fileMultiRecSize); 3695*c18ec02fSPetter Reinholdtsen if (buf == NULL) { 3696*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "ipmitool: malloc failure"); 3697*c18ec02fSPetter Reinholdtsen return (-1); 3698*c18ec02fSPetter Reinholdtsen } 3699*c18ec02fSPetter Reinholdtsen if (ipmi_fru_get_multirec_from_file(pFileName, buf, fileMultiRecSize, 3700*c18ec02fSPetter Reinholdtsen offFileMultiRec) != 0) { 3701*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Failed to get multirec from file '%s'.", pFileName); 3702*c18ec02fSPetter Reinholdtsen if (buf != NULL) { 3703*c18ec02fSPetter Reinholdtsen free(buf); 3704*c18ec02fSPetter Reinholdtsen buf = NULL; 3705*c18ec02fSPetter Reinholdtsen } 3706*c18ec02fSPetter Reinholdtsen return (-1); 3707*c18ec02fSPetter Reinholdtsen } 3708*c18ec02fSPetter Reinholdtsen if (ipmi_fru_get_adjust_size_from_buffer(buf, &fileMultiRecSize) != 0) { 3709*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Failed to adjust size from buffer."); 3710*c18ec02fSPetter Reinholdtsen if (buf != NULL) { 3711*c18ec02fSPetter Reinholdtsen free(buf); 3712*c18ec02fSPetter Reinholdtsen buf = NULL; 3713*c18ec02fSPetter Reinholdtsen } 3714*c18ec02fSPetter Reinholdtsen return (-1); 3715*c18ec02fSPetter Reinholdtsen } 3716*c18ec02fSPetter Reinholdtsen if (write_fru_area(intf, &fruInfo, fruId, 0, offFruMultiRec, 3717*c18ec02fSPetter Reinholdtsen fileMultiRecSize, buf) != 0) { 3718*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Failed to write FRU area."); 3719*c18ec02fSPetter Reinholdtsen if (buf != NULL) { 3720*c18ec02fSPetter Reinholdtsen free(buf); 3721*c18ec02fSPetter Reinholdtsen buf = NULL; 3722*c18ec02fSPetter Reinholdtsen } 3723*c18ec02fSPetter Reinholdtsen return (-1); 3724*c18ec02fSPetter Reinholdtsen } 3725*c18ec02fSPetter Reinholdtsen if (buf != NULL) { 3726*c18ec02fSPetter Reinholdtsen free(buf); 3727*c18ec02fSPetter Reinholdtsen buf = NULL; 3728*c18ec02fSPetter Reinholdtsen } 3729*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO, "Done upgrading Ekey."); 3730*c18ec02fSPetter Reinholdtsen return 0; 3731*c18ec02fSPetter Reinholdtsen } 3732*c18ec02fSPetter Reinholdtsen 3733*c18ec02fSPetter Reinholdtsen /* ipmi_fru_upgekey_help - print help text for 'upgEkey' 3734*c18ec02fSPetter Reinholdtsen * 3735*c18ec02fSPetter Reinholdtsen * returns void 3736*c18ec02fSPetter Reinholdtsen */ 3737*c18ec02fSPetter Reinholdtsen void 3738*c18ec02fSPetter Reinholdtsen ipmi_fru_upgekey_help() 3739*c18ec02fSPetter Reinholdtsen { 3740*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "fru upgEkey <fru id> <fru file>"); 3741*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified."); 3742*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "Example: ipmitool fru upgEkey 0 /root/fru.bin"); 3743*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_upgekey_help() */ 3744*c18ec02fSPetter Reinholdtsen 3745*c18ec02fSPetter Reinholdtsen static int 3746*c18ec02fSPetter Reinholdtsen ipmi_fru_get_multirec_size_from_file(char * pFileName, 3747*c18ec02fSPetter Reinholdtsen uint32_t * pSize, 3748*c18ec02fSPetter Reinholdtsen uint32_t * pOffset) 3749*c18ec02fSPetter Reinholdtsen { 3750*c18ec02fSPetter Reinholdtsen struct fru_header header; 3751*c18ec02fSPetter Reinholdtsen FILE * pFile; 3752*c18ec02fSPetter Reinholdtsen uint8_t len = 0; 3753*c18ec02fSPetter Reinholdtsen uint32_t end = 0; 3754*c18ec02fSPetter Reinholdtsen *pSize = 0; 3755*c18ec02fSPetter Reinholdtsen 3756*c18ec02fSPetter Reinholdtsen pFile = fopen(pFileName,"rb"); 3757*c18ec02fSPetter Reinholdtsen if (pFile) { 3758*c18ec02fSPetter Reinholdtsen rewind(pFile); 3759*c18ec02fSPetter Reinholdtsen len = fread(&header, 1, 8, pFile); 3760*c18ec02fSPetter Reinholdtsen fseek(pFile, 0, SEEK_END); 3761*c18ec02fSPetter Reinholdtsen end = ftell(pFile); 3762*c18ec02fSPetter Reinholdtsen fclose(pFile); 3763*c18ec02fSPetter Reinholdtsen } 3764*c18ec02fSPetter Reinholdtsen 3765*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "File Size = %lu\n", end); 3766*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "Len = %u\n", len); 3767*c18ec02fSPetter Reinholdtsen 3768*c18ec02fSPetter Reinholdtsen if (len != 8) { 3769*c18ec02fSPetter Reinholdtsen printf("Error with file %s in getting size\n", pFileName); 3770*c18ec02fSPetter Reinholdtsen return -1; 3771*c18ec02fSPetter Reinholdtsen } 3772*c18ec02fSPetter Reinholdtsen 3773*c18ec02fSPetter Reinholdtsen if (header.version != 0x01) { 3774*c18ec02fSPetter Reinholdtsen printf ("Unknown FRU header version %02x.\n", header.version); 3775*c18ec02fSPetter Reinholdtsen return -1; 3776*c18ec02fSPetter Reinholdtsen } 3777*c18ec02fSPetter Reinholdtsen 3778*c18ec02fSPetter Reinholdtsen /* Retreive length */ 3779*c18ec02fSPetter Reinholdtsen if (((header.offset.internal * 8) > (header.offset.internal * 8)) && 3780*c18ec02fSPetter Reinholdtsen ((header.offset.internal * 8) < end)) 3781*c18ec02fSPetter Reinholdtsen end = (header.offset.internal * 8); 3782*c18ec02fSPetter Reinholdtsen 3783*c18ec02fSPetter Reinholdtsen if (((header.offset.chassis * 8) > (header.offset.chassis * 8)) && 3784*c18ec02fSPetter Reinholdtsen ((header.offset.chassis * 8) < end)) 3785*c18ec02fSPetter Reinholdtsen end = (header.offset.chassis * 8); 3786*c18ec02fSPetter Reinholdtsen 3787*c18ec02fSPetter Reinholdtsen if (((header.offset.board * 8) > (header.offset.board * 8)) && 3788*c18ec02fSPetter Reinholdtsen ((header.offset.board * 8) < end)) 3789*c18ec02fSPetter Reinholdtsen end = (header.offset.board * 8); 3790*c18ec02fSPetter Reinholdtsen 3791*c18ec02fSPetter Reinholdtsen if (((header.offset.product * 8) > (header.offset.product * 8)) && 3792*c18ec02fSPetter Reinholdtsen ((header.offset.product * 8) < end)) 3793*c18ec02fSPetter Reinholdtsen end = (header.offset.product * 8); 3794*c18ec02fSPetter Reinholdtsen 3795*c18ec02fSPetter Reinholdtsen *pSize = end - (header.offset.multi * 8); 3796*c18ec02fSPetter Reinholdtsen *pOffset = (header.offset.multi * 8); 3797*c18ec02fSPetter Reinholdtsen 3798*c18ec02fSPetter Reinholdtsen return 0; 3799*c18ec02fSPetter Reinholdtsen } 3800*c18ec02fSPetter Reinholdtsen 3801*c18ec02fSPetter Reinholdtsen int 3802*c18ec02fSPetter Reinholdtsen ipmi_fru_get_adjust_size_from_buffer(uint8_t * fru_data, uint32_t *pSize) 3803*c18ec02fSPetter Reinholdtsen { 3804*c18ec02fSPetter Reinholdtsen struct fru_multirec_header * head; 3805*c18ec02fSPetter Reinholdtsen int status = 0; 3806*c18ec02fSPetter Reinholdtsen uint8_t checksum = 0; 3807*c18ec02fSPetter Reinholdtsen uint8_t counter = 0; 3808*c18ec02fSPetter Reinholdtsen uint16_t count = 0; 3809*c18ec02fSPetter Reinholdtsen do { 3810*c18ec02fSPetter Reinholdtsen checksum = 0; 3811*c18ec02fSPetter Reinholdtsen head = (struct fru_multirec_header *) (fru_data + count); 3812*c18ec02fSPetter Reinholdtsen if (verbose) { 3813*c18ec02fSPetter Reinholdtsen printf("Adding ("); 3814*c18ec02fSPetter Reinholdtsen } 3815*c18ec02fSPetter Reinholdtsen for (counter = 0; counter < sizeof(struct fru_multirec_header); counter++) { 3816*c18ec02fSPetter Reinholdtsen if (verbose) { 3817*c18ec02fSPetter Reinholdtsen printf(" %02X", *(fru_data + count + counter)); 3818*c18ec02fSPetter Reinholdtsen } 3819*c18ec02fSPetter Reinholdtsen checksum += *(fru_data + count + counter); 3820*c18ec02fSPetter Reinholdtsen } 3821*c18ec02fSPetter Reinholdtsen if (verbose) { 3822*c18ec02fSPetter Reinholdtsen printf(")"); 3823*c18ec02fSPetter Reinholdtsen } 3824*c18ec02fSPetter Reinholdtsen if (checksum != 0) { 3825*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Bad checksum in Multi Records"); 3826*c18ec02fSPetter Reinholdtsen status = (-1); 3827*c18ec02fSPetter Reinholdtsen if (verbose) { 3828*c18ec02fSPetter Reinholdtsen printf("--> FAIL"); 3829*c18ec02fSPetter Reinholdtsen } 3830*c18ec02fSPetter Reinholdtsen } else if (verbose) { 3831*c18ec02fSPetter Reinholdtsen printf("--> OK"); 3832*c18ec02fSPetter Reinholdtsen } 3833*c18ec02fSPetter Reinholdtsen if (verbose > 1 && checksum == 0) { 3834*c18ec02fSPetter Reinholdtsen for (counter = 0; counter < head->len; counter++) { 3835*c18ec02fSPetter Reinholdtsen printf(" %02X", *(fru_data + count + counter 3836*c18ec02fSPetter Reinholdtsen + sizeof(struct fru_multirec_header))); 3837*c18ec02fSPetter Reinholdtsen } 3838*c18ec02fSPetter Reinholdtsen } 3839*c18ec02fSPetter Reinholdtsen if (verbose) { 3840*c18ec02fSPetter Reinholdtsen printf("\n"); 3841*c18ec02fSPetter Reinholdtsen } 3842*c18ec02fSPetter Reinholdtsen count += head->len + sizeof (struct fru_multirec_header); 3843*c18ec02fSPetter Reinholdtsen } while ((!(head->format & 0x80)) && (status == 0)); 3844*c18ec02fSPetter Reinholdtsen 3845*c18ec02fSPetter Reinholdtsen *pSize = count; 3846*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "Size of multirec: %lu\n", *pSize); 3847*c18ec02fSPetter Reinholdtsen return status; 3848*c18ec02fSPetter Reinholdtsen } 3849*c18ec02fSPetter Reinholdtsen 3850*c18ec02fSPetter Reinholdtsen static int 3851*c18ec02fSPetter Reinholdtsen ipmi_fru_get_multirec_from_file(char * pFileName, uint8_t * pBufArea, 3852*c18ec02fSPetter Reinholdtsen uint32_t size, uint32_t offset) 3853*c18ec02fSPetter Reinholdtsen { 3854*c18ec02fSPetter Reinholdtsen FILE * pFile; 3855*c18ec02fSPetter Reinholdtsen uint32_t len = 0; 3856*c18ec02fSPetter Reinholdtsen if (pFileName == NULL) { 3857*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Invalid file name given."); 3858*c18ec02fSPetter Reinholdtsen return (-1); 3859*c18ec02fSPetter Reinholdtsen } 3860*c18ec02fSPetter Reinholdtsen 3861*c18ec02fSPetter Reinholdtsen errno = 0; 3862*c18ec02fSPetter Reinholdtsen pFile = fopen(pFileName, "rb"); 3863*c18ec02fSPetter Reinholdtsen if (!pFile) { 3864*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Error opening file '%s': %i -> %s.", pFileName, errno, 3865*c18ec02fSPetter Reinholdtsen strerror(errno)); 3866*c18ec02fSPetter Reinholdtsen return (-1); 3867*c18ec02fSPetter Reinholdtsen } 3868*c18ec02fSPetter Reinholdtsen errno = 0; 3869*c18ec02fSPetter Reinholdtsen if (fseek(pFile, offset, SEEK_SET) != 0) { 3870*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Failed to seek in file '%s': %i -> %s.", pFileName, errno, 3871*c18ec02fSPetter Reinholdtsen strerror(errno)); 3872*c18ec02fSPetter Reinholdtsen fclose(pFile); 3873*c18ec02fSPetter Reinholdtsen return (-1); 3874*c18ec02fSPetter Reinholdtsen } 3875*c18ec02fSPetter Reinholdtsen len = fread(pBufArea, size, 1, pFile); 3876*c18ec02fSPetter Reinholdtsen fclose(pFile); 3877*c18ec02fSPetter Reinholdtsen 3878*c18ec02fSPetter Reinholdtsen if (len != 1) { 3879*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Error in file '%s'.", pFileName); 3880*c18ec02fSPetter Reinholdtsen return (-1); 3881*c18ec02fSPetter Reinholdtsen } 3882*c18ec02fSPetter Reinholdtsen return 0; 3883*c18ec02fSPetter Reinholdtsen } 3884*c18ec02fSPetter Reinholdtsen 3885*c18ec02fSPetter Reinholdtsen static int 3886*c18ec02fSPetter Reinholdtsen ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf, 3887*c18ec02fSPetter Reinholdtsen uint8_t fruId, 3888*c18ec02fSPetter Reinholdtsen struct fru_info *pFruInfo, 3889*c18ec02fSPetter Reinholdtsen uint32_t * pRetLocation, 3890*c18ec02fSPetter Reinholdtsen uint32_t * pRetSize) 3891*c18ec02fSPetter Reinholdtsen { 3892*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 3893*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 3894*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 3895*c18ec02fSPetter Reinholdtsen uint32_t end; 3896*c18ec02fSPetter Reinholdtsen struct fru_header header; 3897*c18ec02fSPetter Reinholdtsen 3898*c18ec02fSPetter Reinholdtsen *pRetLocation = 0; 3899*c18ec02fSPetter Reinholdtsen 3900*c18ec02fSPetter Reinholdtsen msg_data[0] = fruId; 3901*c18ec02fSPetter Reinholdtsen 3902*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 3903*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 3904*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_INFO; 3905*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 3906*c18ec02fSPetter Reinholdtsen req.msg.data_len = 1; 3907*c18ec02fSPetter Reinholdtsen 3908*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 3909*c18ec02fSPetter Reinholdtsen if (!rsp) { 3910*c18ec02fSPetter Reinholdtsen if (verbose > 1) 3911*c18ec02fSPetter Reinholdtsen printf("no response\n"); 3912*c18ec02fSPetter Reinholdtsen return -1; 3913*c18ec02fSPetter Reinholdtsen } 3914*c18ec02fSPetter Reinholdtsen 3915*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 3916*c18ec02fSPetter Reinholdtsen if (rsp->ccode == 0xc3) 3917*c18ec02fSPetter Reinholdtsen printf (" Timeout accessing FRU info. (Device not present?)\n"); 3918*c18ec02fSPetter Reinholdtsen else 3919*c18ec02fSPetter Reinholdtsen printf (" CCODE = 0x%02x\n", rsp->ccode); 3920*c18ec02fSPetter Reinholdtsen return -1; 3921*c18ec02fSPetter Reinholdtsen } 3922*c18ec02fSPetter Reinholdtsen pFruInfo->size = (rsp->data[1] << 8) | rsp->data[0]; 3923*c18ec02fSPetter Reinholdtsen pFruInfo->access = rsp->data[2] & 0x1; 3924*c18ec02fSPetter Reinholdtsen 3925*c18ec02fSPetter Reinholdtsen if (verbose > 1) 3926*c18ec02fSPetter Reinholdtsen printf("pFruInfo->size = %d bytes (accessed by %s)\n", 3927*c18ec02fSPetter Reinholdtsen pFruInfo->size, pFruInfo->access ? "words" : "bytes"); 3928*c18ec02fSPetter Reinholdtsen 3929*c18ec02fSPetter Reinholdtsen if (!pFruInfo->size) 3930*c18ec02fSPetter Reinholdtsen return -1; 3931*c18ec02fSPetter Reinholdtsen 3932*c18ec02fSPetter Reinholdtsen msg_data[0] = fruId; 3933*c18ec02fSPetter Reinholdtsen msg_data[1] = 0; 3934*c18ec02fSPetter Reinholdtsen msg_data[2] = 0; 3935*c18ec02fSPetter Reinholdtsen msg_data[3] = 8; 3936*c18ec02fSPetter Reinholdtsen 3937*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 3938*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 3939*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_DATA; 3940*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 3941*c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 3942*c18ec02fSPetter Reinholdtsen 3943*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 3944*c18ec02fSPetter Reinholdtsen 3945*c18ec02fSPetter Reinholdtsen if (!rsp) 3946*c18ec02fSPetter Reinholdtsen return -1; 3947*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 3948*c18ec02fSPetter Reinholdtsen if (rsp->ccode == 0xc3) 3949*c18ec02fSPetter Reinholdtsen printf (" Timeout while reading FRU data. (Device not present?)\n"); 3950*c18ec02fSPetter Reinholdtsen return -1; 3951*c18ec02fSPetter Reinholdtsen } 3952*c18ec02fSPetter Reinholdtsen 3953*c18ec02fSPetter Reinholdtsen if (verbose > 1) 3954*c18ec02fSPetter Reinholdtsen printbuf(rsp->data, rsp->data_len, "FRU DATA"); 3955*c18ec02fSPetter Reinholdtsen 3956*c18ec02fSPetter Reinholdtsen memcpy(&header, rsp->data + 1, 8); 3957*c18ec02fSPetter Reinholdtsen 3958*c18ec02fSPetter Reinholdtsen if (header.version != 0x01) { 3959*c18ec02fSPetter Reinholdtsen printf (" Unknown FRU header version %02x.\n", header.version); 3960*c18ec02fSPetter Reinholdtsen return -1; 3961*c18ec02fSPetter Reinholdtsen } 3962*c18ec02fSPetter Reinholdtsen 3963*c18ec02fSPetter Reinholdtsen end = pFruInfo->size; 3964*c18ec02fSPetter Reinholdtsen 3965*c18ec02fSPetter Reinholdtsen /* Retreive length */ 3966*c18ec02fSPetter Reinholdtsen if (((header.offset.internal * 8) > (header.offset.internal * 8)) && 3967*c18ec02fSPetter Reinholdtsen ((header.offset.internal * 8) < end)) 3968*c18ec02fSPetter Reinholdtsen end = (header.offset.internal * 8); 3969*c18ec02fSPetter Reinholdtsen 3970*c18ec02fSPetter Reinholdtsen if (((header.offset.chassis * 8) > (header.offset.chassis * 8)) && 3971*c18ec02fSPetter Reinholdtsen ((header.offset.chassis * 8) < end)) 3972*c18ec02fSPetter Reinholdtsen end = (header.offset.chassis * 8); 3973*c18ec02fSPetter Reinholdtsen 3974*c18ec02fSPetter Reinholdtsen if (((header.offset.board * 8) > (header.offset.board * 8)) && 3975*c18ec02fSPetter Reinholdtsen ((header.offset.board * 8) < end)) 3976*c18ec02fSPetter Reinholdtsen end = (header.offset.board * 8); 3977*c18ec02fSPetter Reinholdtsen 3978*c18ec02fSPetter Reinholdtsen if (((header.offset.product * 8) > (header.offset.product * 8)) && 3979*c18ec02fSPetter Reinholdtsen ((header.offset.product * 8) < end)) 3980*c18ec02fSPetter Reinholdtsen end = (header.offset.product * 8); 3981*c18ec02fSPetter Reinholdtsen 3982*c18ec02fSPetter Reinholdtsen *pRetSize = end; 3983*c18ec02fSPetter Reinholdtsen *pRetLocation = 8 * header.offset.multi; 3984*c18ec02fSPetter Reinholdtsen 3985*c18ec02fSPetter Reinholdtsen return 0; 3986*c18ec02fSPetter Reinholdtsen } 3987*c18ec02fSPetter Reinholdtsen 3988*c18ec02fSPetter Reinholdtsen /* ipmi_fru_get_internal_use_offset - Retreive internal use offset 3989*c18ec02fSPetter Reinholdtsen * 3990*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 3991*c18ec02fSPetter Reinholdtsen * @id: fru id 3992*c18ec02fSPetter Reinholdtsen * 3993*c18ec02fSPetter Reinholdtsen * returns -1 on error 3994*c18ec02fSPetter Reinholdtsen * returns 0 if successful 3995*c18ec02fSPetter Reinholdtsen * returns 1 if device not present 3996*c18ec02fSPetter Reinholdtsen */ 3997*c18ec02fSPetter Reinholdtsen static int 3998*c18ec02fSPetter Reinholdtsen ipmi_fru_get_internal_use_info( struct ipmi_intf * intf, 3999*c18ec02fSPetter Reinholdtsen uint8_t id, 4000*c18ec02fSPetter Reinholdtsen struct fru_info * fru, 4001*c18ec02fSPetter Reinholdtsen uint16_t * size, 4002*c18ec02fSPetter Reinholdtsen uint16_t * offset) 4003*c18ec02fSPetter Reinholdtsen { 4004*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 4005*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 4006*c18ec02fSPetter Reinholdtsen struct fru_header header; 4007*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 4008*c18ec02fSPetter Reinholdtsen 4009*c18ec02fSPetter Reinholdtsen // Init output value 4010*c18ec02fSPetter Reinholdtsen * offset = 0; 4011*c18ec02fSPetter Reinholdtsen * size = 0; 4012*c18ec02fSPetter Reinholdtsen 4013*c18ec02fSPetter Reinholdtsen memset(fru, 0, sizeof(struct fru_info)); 4014*c18ec02fSPetter Reinholdtsen memset(&header, 0, sizeof(struct fru_header)); 4015*c18ec02fSPetter Reinholdtsen 4016*c18ec02fSPetter Reinholdtsen /* 4017*c18ec02fSPetter Reinholdtsen * get info about this FRU 4018*c18ec02fSPetter Reinholdtsen */ 4019*c18ec02fSPetter Reinholdtsen memset(msg_data, 0, 4); 4020*c18ec02fSPetter Reinholdtsen msg_data[0] = id; 4021*c18ec02fSPetter Reinholdtsen 4022*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 4023*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 4024*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_INFO; 4025*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 4026*c18ec02fSPetter Reinholdtsen req.msg.data_len = 1; 4027*c18ec02fSPetter Reinholdtsen 4028*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 4029*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 4030*c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 4031*c18ec02fSPetter Reinholdtsen return -1; 4032*c18ec02fSPetter Reinholdtsen } 4033*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 4034*c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 4035*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 4036*c18ec02fSPetter Reinholdtsen return -1; 4037*c18ec02fSPetter Reinholdtsen } 4038*c18ec02fSPetter Reinholdtsen 4039*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(fru)); 4040*c18ec02fSPetter Reinholdtsen fru->size = (rsp->data[1] << 8) | rsp->data[0]; 4041*c18ec02fSPetter Reinholdtsen fru->access = rsp->data[2] & 0x1; 4042*c18ec02fSPetter Reinholdtsen 4043*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)", 4044*c18ec02fSPetter Reinholdtsen fru->size, fru->access ? "words" : "bytes"); 4045*c18ec02fSPetter Reinholdtsen 4046*c18ec02fSPetter Reinholdtsen if (fru->size < 1) { 4047*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Invalid FRU size %d", fru->size); 4048*c18ec02fSPetter Reinholdtsen return -1; 4049*c18ec02fSPetter Reinholdtsen } 4050*c18ec02fSPetter Reinholdtsen 4051*c18ec02fSPetter Reinholdtsen /* 4052*c18ec02fSPetter Reinholdtsen * retrieve the FRU header 4053*c18ec02fSPetter Reinholdtsen */ 4054*c18ec02fSPetter Reinholdtsen msg_data[0] = id; 4055*c18ec02fSPetter Reinholdtsen msg_data[1] = 0; 4056*c18ec02fSPetter Reinholdtsen msg_data[2] = 0; 4057*c18ec02fSPetter Reinholdtsen msg_data[3] = 8; 4058*c18ec02fSPetter Reinholdtsen 4059*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 4060*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 4061*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_DATA; 4062*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 4063*c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 4064*c18ec02fSPetter Reinholdtsen 4065*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 4066*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 4067*c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 4068*c18ec02fSPetter Reinholdtsen return 1; 4069*c18ec02fSPetter Reinholdtsen } 4070*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 4071*c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 4072*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 4073*c18ec02fSPetter Reinholdtsen return 1; 4074*c18ec02fSPetter Reinholdtsen } 4075*c18ec02fSPetter Reinholdtsen 4076*c18ec02fSPetter Reinholdtsen if (verbose > 1) 4077*c18ec02fSPetter Reinholdtsen printbuf(rsp->data, rsp->data_len, "FRU DATA"); 4078*c18ec02fSPetter Reinholdtsen 4079*c18ec02fSPetter Reinholdtsen memcpy(&header, rsp->data + 1, 8); 4080*c18ec02fSPetter Reinholdtsen 4081*c18ec02fSPetter Reinholdtsen if (header.version != 1) { 4082*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", 4083*c18ec02fSPetter Reinholdtsen header.version); 4084*c18ec02fSPetter Reinholdtsen return -1; 4085*c18ec02fSPetter Reinholdtsen } 4086*c18ec02fSPetter Reinholdtsen 4087*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.version: 0x%x", 4088*c18ec02fSPetter Reinholdtsen header.version); 4089*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.offset.internal: 0x%x", 4090*c18ec02fSPetter Reinholdtsen header.offset.internal * 8); 4091*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.offset.chassis: 0x%x", 4092*c18ec02fSPetter Reinholdtsen header.offset.chassis * 8); 4093*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.offset.board: 0x%x", 4094*c18ec02fSPetter Reinholdtsen header.offset.board * 8); 4095*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.offset.product: 0x%x", 4096*c18ec02fSPetter Reinholdtsen header.offset.product * 8); 4097*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "fru.header.offset.multi: 0x%x", 4098*c18ec02fSPetter Reinholdtsen header.offset.multi * 8); 4099*c18ec02fSPetter Reinholdtsen 4100*c18ec02fSPetter Reinholdtsen if((header.offset.internal*8) == 0) 4101*c18ec02fSPetter Reinholdtsen { 4102*c18ec02fSPetter Reinholdtsen * size = 0; 4103*c18ec02fSPetter Reinholdtsen * offset = 0; 4104*c18ec02fSPetter Reinholdtsen } 4105*c18ec02fSPetter Reinholdtsen else 4106*c18ec02fSPetter Reinholdtsen { 4107*c18ec02fSPetter Reinholdtsen (* offset) = (header.offset.internal*8); 4108*c18ec02fSPetter Reinholdtsen 4109*c18ec02fSPetter Reinholdtsen if(header.offset.chassis != 0) 4110*c18ec02fSPetter Reinholdtsen { 4111*c18ec02fSPetter Reinholdtsen (* size) = ((header.offset.chassis*8)-(* offset)); 4112*c18ec02fSPetter Reinholdtsen } 4113*c18ec02fSPetter Reinholdtsen else if(header.offset.board != 0) 4114*c18ec02fSPetter Reinholdtsen { 4115*c18ec02fSPetter Reinholdtsen (* size) = ((header.offset.board*8)-(* offset)); 4116*c18ec02fSPetter Reinholdtsen } 4117*c18ec02fSPetter Reinholdtsen else if(header.offset.product != 0) 4118*c18ec02fSPetter Reinholdtsen { 4119*c18ec02fSPetter Reinholdtsen (* size) = ((header.offset.product*8)-(* offset)); 4120*c18ec02fSPetter Reinholdtsen } 4121*c18ec02fSPetter Reinholdtsen else if(header.offset.multi != 0) 4122*c18ec02fSPetter Reinholdtsen { 4123*c18ec02fSPetter Reinholdtsen (* size) = ((header.offset.multi*8)-(* offset)); 4124*c18ec02fSPetter Reinholdtsen } 4125*c18ec02fSPetter Reinholdtsen else 4126*c18ec02fSPetter Reinholdtsen { 4127*c18ec02fSPetter Reinholdtsen (* size) = (fru->size - (* offset)); 4128*c18ec02fSPetter Reinholdtsen } 4129*c18ec02fSPetter Reinholdtsen } 4130*c18ec02fSPetter Reinholdtsen return 0; 4131*c18ec02fSPetter Reinholdtsen } 4132*c18ec02fSPetter Reinholdtsen 4133*c18ec02fSPetter Reinholdtsen /* ipmi_fru_info_internal_use - print internal use info 4134*c18ec02fSPetter Reinholdtsen * 4135*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 4136*c18ec02fSPetter Reinholdtsen * @id: fru id 4137*c18ec02fSPetter Reinholdtsen * 4138*c18ec02fSPetter Reinholdtsen * returns -1 on error 4139*c18ec02fSPetter Reinholdtsen * returns 0 if successful 4140*c18ec02fSPetter Reinholdtsen * returns 1 if device not present 4141*c18ec02fSPetter Reinholdtsen */ 4142*c18ec02fSPetter Reinholdtsen static int 4143*c18ec02fSPetter Reinholdtsen ipmi_fru_info_internal_use(struct ipmi_intf * intf, uint8_t id) 4144*c18ec02fSPetter Reinholdtsen { 4145*c18ec02fSPetter Reinholdtsen struct fru_info fru; 4146*c18ec02fSPetter Reinholdtsen uint16_t size; 4147*c18ec02fSPetter Reinholdtsen uint16_t offset; 4148*c18ec02fSPetter Reinholdtsen int rc = 0; 4149*c18ec02fSPetter Reinholdtsen 4150*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset); 4151*c18ec02fSPetter Reinholdtsen 4152*c18ec02fSPetter Reinholdtsen if(rc == 0) 4153*c18ec02fSPetter Reinholdtsen { 4154*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset); 4155*c18ec02fSPetter Reinholdtsen printf( "Internal Use Area Size : %i\n", size); 4156*c18ec02fSPetter Reinholdtsen } 4157*c18ec02fSPetter Reinholdtsen else 4158*c18ec02fSPetter Reinholdtsen { 4159*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Cannot access internal use area"); 4160*c18ec02fSPetter Reinholdtsen return -1; 4161*c18ec02fSPetter Reinholdtsen } 4162*c18ec02fSPetter Reinholdtsen return 0; 4163*c18ec02fSPetter Reinholdtsen } 4164*c18ec02fSPetter Reinholdtsen 4165*c18ec02fSPetter Reinholdtsen /* ipmi_fru_help - print help text for FRU subcommand 4166*c18ec02fSPetter Reinholdtsen * 4167*c18ec02fSPetter Reinholdtsen * returns void 4168*c18ec02fSPetter Reinholdtsen */ 4169*c18ec02fSPetter Reinholdtsen void 4170*c18ec02fSPetter Reinholdtsen ipmi_fru_help() 4171*c18ec02fSPetter Reinholdtsen { 4172*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, 4173*c18ec02fSPetter Reinholdtsen "FRU Commands: print read write upgEkey edit internaluse get"); 4174*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_help() */ 4175*c18ec02fSPetter Reinholdtsen 4176*c18ec02fSPetter Reinholdtsen /* ipmi_fru_read_internal_use - print internal use are in hex or file 4177*c18ec02fSPetter Reinholdtsen * 4178*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 4179*c18ec02fSPetter Reinholdtsen * @id: fru id 4180*c18ec02fSPetter Reinholdtsen * 4181*c18ec02fSPetter Reinholdtsen * returns -1 on error 4182*c18ec02fSPetter Reinholdtsen * returns 0 if successful 4183*c18ec02fSPetter Reinholdtsen * returns 1 if device not present 4184*c18ec02fSPetter Reinholdtsen */ 4185*c18ec02fSPetter Reinholdtsen static int 4186*c18ec02fSPetter Reinholdtsen ipmi_fru_read_internal_use(struct ipmi_intf * intf, uint8_t id, char * pFileName) 4187*c18ec02fSPetter Reinholdtsen { 4188*c18ec02fSPetter Reinholdtsen struct fru_info fru; 4189*c18ec02fSPetter Reinholdtsen uint16_t size; 4190*c18ec02fSPetter Reinholdtsen uint16_t offset; 4191*c18ec02fSPetter Reinholdtsen int rc = 0; 4192*c18ec02fSPetter Reinholdtsen 4193*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset); 4194*c18ec02fSPetter Reinholdtsen 4195*c18ec02fSPetter Reinholdtsen if(rc == 0) 4196*c18ec02fSPetter Reinholdtsen { 4197*c18ec02fSPetter Reinholdtsen uint8_t * frubuf; 4198*c18ec02fSPetter Reinholdtsen 4199*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset); 4200*c18ec02fSPetter Reinholdtsen printf( "Internal Use Area Size : %i\n", size); 4201*c18ec02fSPetter Reinholdtsen 4202*c18ec02fSPetter Reinholdtsen frubuf = malloc( size ); 4203*c18ec02fSPetter Reinholdtsen if(frubuf) 4204*c18ec02fSPetter Reinholdtsen { 4205*c18ec02fSPetter Reinholdtsen rc = read_fru_area_section(intf, &fru, id, offset, size, frubuf); 4206*c18ec02fSPetter Reinholdtsen 4207*c18ec02fSPetter Reinholdtsen if(rc == 0) 4208*c18ec02fSPetter Reinholdtsen { 4209*c18ec02fSPetter Reinholdtsen if(pFileName == NULL) 4210*c18ec02fSPetter Reinholdtsen { 4211*c18ec02fSPetter Reinholdtsen uint16_t counter; 4212*c18ec02fSPetter Reinholdtsen for(counter = 0; counter < size; counter ++) 4213*c18ec02fSPetter Reinholdtsen { 4214*c18ec02fSPetter Reinholdtsen if((counter % 16) == 0) 4215*c18ec02fSPetter Reinholdtsen printf("\n%02i- ", (counter / 16)); 4216*c18ec02fSPetter Reinholdtsen printf("%02X ", frubuf[counter]); 4217*c18ec02fSPetter Reinholdtsen } 4218*c18ec02fSPetter Reinholdtsen } 4219*c18ec02fSPetter Reinholdtsen else 4220*c18ec02fSPetter Reinholdtsen { 4221*c18ec02fSPetter Reinholdtsen FILE * pFile; 4222*c18ec02fSPetter Reinholdtsen pFile = fopen(pFileName,"wb"); 4223*c18ec02fSPetter Reinholdtsen if (pFile) 4224*c18ec02fSPetter Reinholdtsen { 4225*c18ec02fSPetter Reinholdtsen fwrite(frubuf, size, 1, pFile); 4226*c18ec02fSPetter Reinholdtsen printf("Done\n"); 4227*c18ec02fSPetter Reinholdtsen } 4228*c18ec02fSPetter Reinholdtsen else 4229*c18ec02fSPetter Reinholdtsen { 4230*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Error opening file %s\n", pFileName); 4231*c18ec02fSPetter Reinholdtsen free(frubuf); 4232*c18ec02fSPetter Reinholdtsen frubuf = NULL; 4233*c18ec02fSPetter Reinholdtsen return -1; 4234*c18ec02fSPetter Reinholdtsen } 4235*c18ec02fSPetter Reinholdtsen fclose(pFile); 4236*c18ec02fSPetter Reinholdtsen } 4237*c18ec02fSPetter Reinholdtsen } 4238*c18ec02fSPetter Reinholdtsen printf("\n"); 4239*c18ec02fSPetter Reinholdtsen 4240*c18ec02fSPetter Reinholdtsen free(frubuf); 4241*c18ec02fSPetter Reinholdtsen frubuf = NULL; 4242*c18ec02fSPetter Reinholdtsen } 4243*c18ec02fSPetter Reinholdtsen 4244*c18ec02fSPetter Reinholdtsen } 4245*c18ec02fSPetter Reinholdtsen else 4246*c18ec02fSPetter Reinholdtsen { 4247*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Cannot access internal use area"); 4248*c18ec02fSPetter Reinholdtsen } 4249*c18ec02fSPetter Reinholdtsen return 0; 4250*c18ec02fSPetter Reinholdtsen } 4251*c18ec02fSPetter Reinholdtsen 4252*c18ec02fSPetter Reinholdtsen /* ipmi_fru_write_internal_use - print internal use are in hex or file 4253*c18ec02fSPetter Reinholdtsen * 4254*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 4255*c18ec02fSPetter Reinholdtsen * @id: fru id 4256*c18ec02fSPetter Reinholdtsen * 4257*c18ec02fSPetter Reinholdtsen * returns -1 on error 4258*c18ec02fSPetter Reinholdtsen * returns 0 if successful 4259*c18ec02fSPetter Reinholdtsen * returns 1 if device not present 4260*c18ec02fSPetter Reinholdtsen */ 4261*c18ec02fSPetter Reinholdtsen static int 4262*c18ec02fSPetter Reinholdtsen ipmi_fru_write_internal_use(struct ipmi_intf * intf, uint8_t id, char * pFileName) 4263*c18ec02fSPetter Reinholdtsen { 4264*c18ec02fSPetter Reinholdtsen struct fru_info fru; 4265*c18ec02fSPetter Reinholdtsen uint16_t size; 4266*c18ec02fSPetter Reinholdtsen uint16_t offset; 4267*c18ec02fSPetter Reinholdtsen int rc = 0; 4268*c18ec02fSPetter Reinholdtsen 4269*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset); 4270*c18ec02fSPetter Reinholdtsen 4271*c18ec02fSPetter Reinholdtsen if(rc == 0) 4272*c18ec02fSPetter Reinholdtsen { 4273*c18ec02fSPetter Reinholdtsen uint8_t * frubuf; 4274*c18ec02fSPetter Reinholdtsen FILE * fp; 4275*c18ec02fSPetter Reinholdtsen uint32_t fileLength = 0; 4276*c18ec02fSPetter Reinholdtsen 4277*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset); 4278*c18ec02fSPetter Reinholdtsen printf( "Internal Use Area Size : %i\n", size); 4279*c18ec02fSPetter Reinholdtsen 4280*c18ec02fSPetter Reinholdtsen fp = fopen(pFileName, "r"); 4281*c18ec02fSPetter Reinholdtsen 4282*c18ec02fSPetter Reinholdtsen if(fp) 4283*c18ec02fSPetter Reinholdtsen { 4284*c18ec02fSPetter Reinholdtsen /* Retreive file length, check if it's fits the Eeprom Size */ 4285*c18ec02fSPetter Reinholdtsen fseek(fp, 0 ,SEEK_END); 4286*c18ec02fSPetter Reinholdtsen fileLength = ftell(fp); 4287*c18ec02fSPetter Reinholdtsen 4288*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "File Size: %i", fileLength); 4289*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Area Size: %i", size); 4290*c18ec02fSPetter Reinholdtsen if(fileLength != size) 4291*c18ec02fSPetter Reinholdtsen { 4292*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "File size does not fit Eeprom Size"); 4293*c18ec02fSPetter Reinholdtsen fclose(fp); 4294*c18ec02fSPetter Reinholdtsen fp = NULL; 4295*c18ec02fSPetter Reinholdtsen } 4296*c18ec02fSPetter Reinholdtsen else 4297*c18ec02fSPetter Reinholdtsen { 4298*c18ec02fSPetter Reinholdtsen fseek(fp, 0 ,SEEK_SET); 4299*c18ec02fSPetter Reinholdtsen } 4300*c18ec02fSPetter Reinholdtsen } 4301*c18ec02fSPetter Reinholdtsen 4302*c18ec02fSPetter Reinholdtsen if(fp) 4303*c18ec02fSPetter Reinholdtsen { 4304*c18ec02fSPetter Reinholdtsen frubuf = malloc( size ); 4305*c18ec02fSPetter Reinholdtsen if(frubuf) 4306*c18ec02fSPetter Reinholdtsen { 4307*c18ec02fSPetter Reinholdtsen uint16_t fru_read_size; 4308*c18ec02fSPetter Reinholdtsen fru_read_size = fread(frubuf, 1, size, fp); 4309*c18ec02fSPetter Reinholdtsen 4310*c18ec02fSPetter Reinholdtsen if(fru_read_size == size) 4311*c18ec02fSPetter Reinholdtsen { 4312*c18ec02fSPetter Reinholdtsen rc = write_fru_area(intf, &fru, id, 0, offset, size, frubuf); 4313*c18ec02fSPetter Reinholdtsen 4314*c18ec02fSPetter Reinholdtsen if(rc == 0) 4315*c18ec02fSPetter Reinholdtsen { 4316*c18ec02fSPetter Reinholdtsen lprintf(LOG_INFO, "Done\n"); 4317*c18ec02fSPetter Reinholdtsen } 4318*c18ec02fSPetter Reinholdtsen } 4319*c18ec02fSPetter Reinholdtsen else 4320*c18ec02fSPetter Reinholdtsen { 4321*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Unable to read file: %i\n", fru_read_size); 4322*c18ec02fSPetter Reinholdtsen } 4323*c18ec02fSPetter Reinholdtsen 4324*c18ec02fSPetter Reinholdtsen free(frubuf); 4325*c18ec02fSPetter Reinholdtsen frubuf = NULL; 4326*c18ec02fSPetter Reinholdtsen } 4327*c18ec02fSPetter Reinholdtsen fclose(fp); 4328*c18ec02fSPetter Reinholdtsen fp = NULL; 4329*c18ec02fSPetter Reinholdtsen } 4330*c18ec02fSPetter Reinholdtsen } 4331*c18ec02fSPetter Reinholdtsen else 4332*c18ec02fSPetter Reinholdtsen { 4333*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Cannot access internal use area"); 4334*c18ec02fSPetter Reinholdtsen } 4335*c18ec02fSPetter Reinholdtsen return 0; 4336*c18ec02fSPetter Reinholdtsen } 4337*c18ec02fSPetter Reinholdtsen 4338*c18ec02fSPetter Reinholdtsen int 4339*c18ec02fSPetter Reinholdtsen ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv) 4340*c18ec02fSPetter Reinholdtsen { 4341*c18ec02fSPetter Reinholdtsen int rc = 0; 4342*c18ec02fSPetter Reinholdtsen uint8_t fru_id = 0; 4343*c18ec02fSPetter Reinholdtsen 4344*c18ec02fSPetter Reinholdtsen if (argc < 1) { 4345*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_print_all(intf); 4346*c18ec02fSPetter Reinholdtsen } 4347*c18ec02fSPetter Reinholdtsen else if (strncmp(argv[0], "help", 4) == 0) { 4348*c18ec02fSPetter Reinholdtsen ipmi_fru_help(); 4349*c18ec02fSPetter Reinholdtsen return 0; 4350*c18ec02fSPetter Reinholdtsen } 4351*c18ec02fSPetter Reinholdtsen else if (strncmp(argv[0], "print", 5) == 0 || 4352*c18ec02fSPetter Reinholdtsen strncmp(argv[0], "list", 4) == 0) { 4353*c18ec02fSPetter Reinholdtsen if (argc > 1) { 4354*c18ec02fSPetter Reinholdtsen if (strcmp(argv[1], "help") == 0) { 4355*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "fru print [fru id] - print information about FRU(s)"); 4356*c18ec02fSPetter Reinholdtsen return 0; 4357*c18ec02fSPetter Reinholdtsen } 4358*c18ec02fSPetter Reinholdtsen 4359*c18ec02fSPetter Reinholdtsen if (is_fru_id(argv[1], &fru_id) != 0) 4360*c18ec02fSPetter Reinholdtsen return (-1); 4361*c18ec02fSPetter Reinholdtsen 4362*c18ec02fSPetter Reinholdtsen rc = __ipmi_fru_print(intf, fru_id); 4363*c18ec02fSPetter Reinholdtsen } else { 4364*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_print_all(intf); 4365*c18ec02fSPetter Reinholdtsen } 4366*c18ec02fSPetter Reinholdtsen } 4367*c18ec02fSPetter Reinholdtsen else if (!strncmp(argv[0], "read", 5)) { 4368*c18ec02fSPetter Reinholdtsen if (argc > 1 && strcmp(argv[1], "help") == 0) { 4369*c18ec02fSPetter Reinholdtsen ipmi_fru_read_help(); 4370*c18ec02fSPetter Reinholdtsen return 0; 4371*c18ec02fSPetter Reinholdtsen } else if (argc < 3) { 4372*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Not enough parameters given."); 4373*c18ec02fSPetter Reinholdtsen ipmi_fru_read_help(); 4374*c18ec02fSPetter Reinholdtsen return (-1); 4375*c18ec02fSPetter Reinholdtsen } 4376*c18ec02fSPetter Reinholdtsen 4377*c18ec02fSPetter Reinholdtsen if (is_fru_id(argv[1], &fru_id) != 0) 4378*c18ec02fSPetter Reinholdtsen return (-1); 4379*c18ec02fSPetter Reinholdtsen 4380*c18ec02fSPetter Reinholdtsen /* There is a file name in the parameters */ 4381*c18ec02fSPetter Reinholdtsen if (is_valid_filename(argv[2]) != 0) 4382*c18ec02fSPetter Reinholdtsen return (-1); 4383*c18ec02fSPetter Reinholdtsen 4384*c18ec02fSPetter Reinholdtsen if (verbose) { 4385*c18ec02fSPetter Reinholdtsen printf("FRU ID : %d\n", fru_id); 4386*c18ec02fSPetter Reinholdtsen printf("FRU File : %s\n", argv[2]); 4387*c18ec02fSPetter Reinholdtsen } 4388*c18ec02fSPetter Reinholdtsen /* TODO - rc is missing */ 4389*c18ec02fSPetter Reinholdtsen ipmi_fru_read_to_bin(intf, argv[2], fru_id); 4390*c18ec02fSPetter Reinholdtsen } 4391*c18ec02fSPetter Reinholdtsen else if (!strncmp(argv[0], "write", 5)) { 4392*c18ec02fSPetter Reinholdtsen if (argc > 1 && strcmp(argv[1], "help") == 0) { 4393*c18ec02fSPetter Reinholdtsen ipmi_fru_write_help(); 4394*c18ec02fSPetter Reinholdtsen return 0; 4395*c18ec02fSPetter Reinholdtsen } else if (argc < 3) { 4396*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Not enough parameters given."); 4397*c18ec02fSPetter Reinholdtsen ipmi_fru_write_help(); 4398*c18ec02fSPetter Reinholdtsen return (-1); 4399*c18ec02fSPetter Reinholdtsen } 4400*c18ec02fSPetter Reinholdtsen 4401*c18ec02fSPetter Reinholdtsen if (is_fru_id(argv[1], &fru_id) != 0) 4402*c18ec02fSPetter Reinholdtsen return (-1); 4403*c18ec02fSPetter Reinholdtsen 4404*c18ec02fSPetter Reinholdtsen /* There is a file name in the parameters */ 4405*c18ec02fSPetter Reinholdtsen if (is_valid_filename(argv[2]) != 0) 4406*c18ec02fSPetter Reinholdtsen return (-1); 4407*c18ec02fSPetter Reinholdtsen 4408*c18ec02fSPetter Reinholdtsen if (verbose) { 4409*c18ec02fSPetter Reinholdtsen printf("FRU ID : %d\n", fru_id); 4410*c18ec02fSPetter Reinholdtsen printf("FRU File : %s\n", argv[2]); 4411*c18ec02fSPetter Reinholdtsen } 4412*c18ec02fSPetter Reinholdtsen /* TODO - rc is missing */ 4413*c18ec02fSPetter Reinholdtsen ipmi_fru_write_from_bin(intf, argv[2], fru_id); 4414*c18ec02fSPetter Reinholdtsen } 4415*c18ec02fSPetter Reinholdtsen else if (!strncmp(argv[0], "upgEkey", 7)) { 4416*c18ec02fSPetter Reinholdtsen if (argc > 1 && strcmp(argv[1], "help") == 0) { 4417*c18ec02fSPetter Reinholdtsen ipmi_fru_upgekey_help(); 4418*c18ec02fSPetter Reinholdtsen return 0; 4419*c18ec02fSPetter Reinholdtsen } else if (argc < 3) { 4420*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Not enough parameters given."); 4421*c18ec02fSPetter Reinholdtsen ipmi_fru_upgekey_help(); 4422*c18ec02fSPetter Reinholdtsen return (-1); 4423*c18ec02fSPetter Reinholdtsen } 4424*c18ec02fSPetter Reinholdtsen 4425*c18ec02fSPetter Reinholdtsen if (is_fru_id(argv[1], &fru_id) != 0) 4426*c18ec02fSPetter Reinholdtsen return (-1); 4427*c18ec02fSPetter Reinholdtsen 4428*c18ec02fSPetter Reinholdtsen /* There is a file name in the parameters */ 4429*c18ec02fSPetter Reinholdtsen if (is_valid_filename(argv[2]) != 0) 4430*c18ec02fSPetter Reinholdtsen return (-1); 4431*c18ec02fSPetter Reinholdtsen 4432*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_upg_ekeying(intf, argv[2], fru_id); 4433*c18ec02fSPetter Reinholdtsen } 4434*c18ec02fSPetter Reinholdtsen else if (!strncmp(argv[0], "internaluse", 11)) { 4435*c18ec02fSPetter Reinholdtsen if (argc > 1 && strcmp(argv[1], "help") == 0) { 4436*c18ec02fSPetter Reinholdtsen ipmi_fru_internaluse_help(); 4437*c18ec02fSPetter Reinholdtsen return 0; 4438*c18ec02fSPetter Reinholdtsen } 4439*c18ec02fSPetter Reinholdtsen 4440*c18ec02fSPetter Reinholdtsen if ( (argc >= 3) && (!strncmp(argv[2], "info", 4)) ) { 4441*c18ec02fSPetter Reinholdtsen 4442*c18ec02fSPetter Reinholdtsen if (is_fru_id(argv[1], &fru_id) != 0) 4443*c18ec02fSPetter Reinholdtsen return (-1); 4444*c18ec02fSPetter Reinholdtsen 4445*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_info_internal_use(intf, fru_id); 4446*c18ec02fSPetter Reinholdtsen } 4447*c18ec02fSPetter Reinholdtsen else if ( (argc >= 3) && (!strncmp(argv[2], "print", 5)) ) { 4448*c18ec02fSPetter Reinholdtsen 4449*c18ec02fSPetter Reinholdtsen if (is_fru_id(argv[1], &fru_id) != 0) 4450*c18ec02fSPetter Reinholdtsen return (-1); 4451*c18ec02fSPetter Reinholdtsen 4452*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_read_internal_use(intf, fru_id, NULL); 4453*c18ec02fSPetter Reinholdtsen } 4454*c18ec02fSPetter Reinholdtsen else if ( (argc >= 4) && (!strncmp(argv[2], "read", 4)) ) { 4455*c18ec02fSPetter Reinholdtsen 4456*c18ec02fSPetter Reinholdtsen if (is_fru_id(argv[1], &fru_id) != 0) 4457*c18ec02fSPetter Reinholdtsen return (-1); 4458*c18ec02fSPetter Reinholdtsen 4459*c18ec02fSPetter Reinholdtsen /* There is a file name in the parameters */ 4460*c18ec02fSPetter Reinholdtsen if (is_valid_filename(argv[3]) != 0) 4461*c18ec02fSPetter Reinholdtsen return (-1); 4462*c18ec02fSPetter Reinholdtsen 4463*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "FRU ID : %d", fru_id); 4464*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "FRU File : %s", argv[3]); 4465*c18ec02fSPetter Reinholdtsen 4466*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_read_internal_use(intf, fru_id, argv[3]); 4467*c18ec02fSPetter Reinholdtsen } 4468*c18ec02fSPetter Reinholdtsen else if ( (argc >= 4) && (!strncmp(argv[2], "write", 5)) ) { 4469*c18ec02fSPetter Reinholdtsen 4470*c18ec02fSPetter Reinholdtsen if (is_fru_id(argv[1], &fru_id) != 0) 4471*c18ec02fSPetter Reinholdtsen return (-1); 4472*c18ec02fSPetter Reinholdtsen 4473*c18ec02fSPetter Reinholdtsen /* There is a file name in the parameters */ 4474*c18ec02fSPetter Reinholdtsen if (is_valid_filename(argv[3]) != 0) 4475*c18ec02fSPetter Reinholdtsen return (-1); 4476*c18ec02fSPetter Reinholdtsen 4477*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "FRU ID : %d", fru_id); 4478*c18ec02fSPetter Reinholdtsen lprintf(LOG_DEBUG, "FRU File : %s", argv[3]); 4479*c18ec02fSPetter Reinholdtsen 4480*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_write_internal_use(intf, fru_id, argv[3]); 4481*c18ec02fSPetter Reinholdtsen } else { 4482*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, 4483*c18ec02fSPetter Reinholdtsen "Either unknown command or not enough parameters given."); 4484*c18ec02fSPetter Reinholdtsen ipmi_fru_internaluse_help(); 4485*c18ec02fSPetter Reinholdtsen return (-1); 4486*c18ec02fSPetter Reinholdtsen } 4487*c18ec02fSPetter Reinholdtsen } 4488*c18ec02fSPetter Reinholdtsen else if (!strncmp(argv[0], "edit", 4)) { 4489*c18ec02fSPetter Reinholdtsen if (argc > 1 && strcmp(argv[1], "help") == 0) { 4490*c18ec02fSPetter Reinholdtsen ipmi_fru_edit_help(); 4491*c18ec02fSPetter Reinholdtsen return 0; 4492*c18ec02fSPetter Reinholdtsen } else if (argc < 2) { 4493*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Not enough parameters given."); 4494*c18ec02fSPetter Reinholdtsen ipmi_fru_edit_help(); 4495*c18ec02fSPetter Reinholdtsen return (-1); 4496*c18ec02fSPetter Reinholdtsen } 4497*c18ec02fSPetter Reinholdtsen 4498*c18ec02fSPetter Reinholdtsen if (argc >= 2) { 4499*c18ec02fSPetter Reinholdtsen if (is_fru_id(argv[1], &fru_id) != 0) 4500*c18ec02fSPetter Reinholdtsen return (-1); 4501*c18ec02fSPetter Reinholdtsen 4502*c18ec02fSPetter Reinholdtsen if (verbose) { 4503*c18ec02fSPetter Reinholdtsen printf("FRU ID : %d\n", fru_id); 4504*c18ec02fSPetter Reinholdtsen } 4505*c18ec02fSPetter Reinholdtsen } else { 4506*c18ec02fSPetter Reinholdtsen printf("Using default FRU ID: %d\n", fru_id); 4507*c18ec02fSPetter Reinholdtsen } 4508*c18ec02fSPetter Reinholdtsen 4509*c18ec02fSPetter Reinholdtsen if (argc >= 3) { 4510*c18ec02fSPetter Reinholdtsen if (!strncmp(argv[2], "field", 5)) { 4511*c18ec02fSPetter Reinholdtsen if (argc != 6) { 4512*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Not enough parameters given."); 4513*c18ec02fSPetter Reinholdtsen ipmi_fru_edit_help(); 4514*c18ec02fSPetter Reinholdtsen return (-1); 4515*c18ec02fSPetter Reinholdtsen } 4516*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_set_field_string(intf, fru_id, *argv[3], *argv[4], 4517*c18ec02fSPetter Reinholdtsen (char *) argv[5]); 4518*c18ec02fSPetter Reinholdtsen } else if (!strncmp(argv[2], "oem", 3)) { 4519*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_edit_multirec(intf, fru_id, argc, argv); 4520*c18ec02fSPetter Reinholdtsen } else { 4521*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Invalid command: %s", argv[2]); 4522*c18ec02fSPetter Reinholdtsen ipmi_fru_edit_help(); 4523*c18ec02fSPetter Reinholdtsen return (-1); 4524*c18ec02fSPetter Reinholdtsen } 4525*c18ec02fSPetter Reinholdtsen } else { 4526*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_edit_multirec(intf, fru_id, argc, argv); 4527*c18ec02fSPetter Reinholdtsen } 4528*c18ec02fSPetter Reinholdtsen } 4529*c18ec02fSPetter Reinholdtsen else if (!strncmp(argv[0], "get", 4)) { 4530*c18ec02fSPetter Reinholdtsen if (argc > 1 && (strncmp(argv[1], "help", 4) == 0)) { 4531*c18ec02fSPetter Reinholdtsen ipmi_fru_get_help(); 4532*c18ec02fSPetter Reinholdtsen return 0; 4533*c18ec02fSPetter Reinholdtsen } else if (argc < 2) { 4534*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Not enough parameters given."); 4535*c18ec02fSPetter Reinholdtsen ipmi_fru_get_help(); 4536*c18ec02fSPetter Reinholdtsen return (-1); 4537*c18ec02fSPetter Reinholdtsen } 4538*c18ec02fSPetter Reinholdtsen 4539*c18ec02fSPetter Reinholdtsen if (argc >= 2) { 4540*c18ec02fSPetter Reinholdtsen if (is_fru_id(argv[1], &fru_id) != 0) 4541*c18ec02fSPetter Reinholdtsen return (-1); 4542*c18ec02fSPetter Reinholdtsen 4543*c18ec02fSPetter Reinholdtsen if (verbose) { 4544*c18ec02fSPetter Reinholdtsen printf("FRU ID : %d\n", fru_id); 4545*c18ec02fSPetter Reinholdtsen } 4546*c18ec02fSPetter Reinholdtsen } else { 4547*c18ec02fSPetter Reinholdtsen printf("Using default FRU ID: %d\n", fru_id); 4548*c18ec02fSPetter Reinholdtsen } 4549*c18ec02fSPetter Reinholdtsen 4550*c18ec02fSPetter Reinholdtsen if (argc >= 3) { 4551*c18ec02fSPetter Reinholdtsen if (!strncmp(argv[2], "oem", 3)) { 4552*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_get_multirec(intf, fru_id, argc, argv); 4553*c18ec02fSPetter Reinholdtsen } else { 4554*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Invalid command: %s", argv[2]); 4555*c18ec02fSPetter Reinholdtsen ipmi_fru_get_help(); 4556*c18ec02fSPetter Reinholdtsen return (-1); 4557*c18ec02fSPetter Reinholdtsen } 4558*c18ec02fSPetter Reinholdtsen } else { 4559*c18ec02fSPetter Reinholdtsen rc = ipmi_fru_get_multirec(intf, fru_id, argc, argv); 4560*c18ec02fSPetter Reinholdtsen } 4561*c18ec02fSPetter Reinholdtsen } 4562*c18ec02fSPetter Reinholdtsen else { 4563*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Invalid FRU command: %s", argv[0]); 4564*c18ec02fSPetter Reinholdtsen ipmi_fru_help(); 4565*c18ec02fSPetter Reinholdtsen return (-1); 4566*c18ec02fSPetter Reinholdtsen } 4567*c18ec02fSPetter Reinholdtsen 4568*c18ec02fSPetter Reinholdtsen return rc; 4569*c18ec02fSPetter Reinholdtsen } 4570*c18ec02fSPetter Reinholdtsen 4571*c18ec02fSPetter Reinholdtsen /* ipmi_fru_set_field_string - Set a field string to a new value, Need to be the same size. If 4572*c18ec02fSPetter Reinholdtsen * size if not equal, the function ipmi_fru_set_field_string_rebuild 4573*c18ec02fSPetter Reinholdtsen * will be called. 4574*c18ec02fSPetter Reinholdtsen * 4575*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 4576*c18ec02fSPetter Reinholdtsen * @id: fru id 4577*c18ec02fSPetter Reinholdtsen * @f_type: Type of the Field : c=Chassis b=Board p=Product 4578*c18ec02fSPetter Reinholdtsen * @f_index: findex of the field, zero indexed. 4579*c18ec02fSPetter Reinholdtsen * @f_string: NULL terminated string 4580*c18ec02fSPetter Reinholdtsen * 4581*c18ec02fSPetter Reinholdtsen * returns -1 on error 4582*c18ec02fSPetter Reinholdtsen * returns 1 if successful 4583*c18ec02fSPetter Reinholdtsen */ 4584*c18ec02fSPetter Reinholdtsen static int 4585*c18ec02fSPetter Reinholdtsen ipmi_fru_set_field_string(struct ipmi_intf * intf, uint8_t fruId, uint8_t 4586*c18ec02fSPetter Reinholdtsen f_type, uint8_t f_index, char *f_string) 4587*c18ec02fSPetter Reinholdtsen { 4588*c18ec02fSPetter Reinholdtsen struct ipmi_rs *rsp; 4589*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 4590*c18ec02fSPetter Reinholdtsen 4591*c18ec02fSPetter Reinholdtsen struct fru_info fru; 4592*c18ec02fSPetter Reinholdtsen struct fru_header header; 4593*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 4594*c18ec02fSPetter Reinholdtsen uint8_t checksum; 4595*c18ec02fSPetter Reinholdtsen int i = 0; 4596*c18ec02fSPetter Reinholdtsen int rc = 1; 4597*c18ec02fSPetter Reinholdtsen uint8_t *fru_data = NULL; 4598*c18ec02fSPetter Reinholdtsen uint8_t *fru_area = NULL; 4599*c18ec02fSPetter Reinholdtsen uint32_t fru_field_offset, fru_field_offset_tmp; 4600*c18ec02fSPetter Reinholdtsen uint32_t fru_section_len, header_offset; 4601*c18ec02fSPetter Reinholdtsen 4602*c18ec02fSPetter Reinholdtsen memset(msg_data, 0, 4); 4603*c18ec02fSPetter Reinholdtsen msg_data[0] = fruId; 4604*c18ec02fSPetter Reinholdtsen 4605*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 4606*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 4607*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_INFO; 4608*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 4609*c18ec02fSPetter Reinholdtsen req.msg.data_len = 1; 4610*c18ec02fSPetter Reinholdtsen 4611*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 4612*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 4613*c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 4614*c18ec02fSPetter Reinholdtsen rc = (-1); 4615*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4616*c18ec02fSPetter Reinholdtsen } 4617*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 4618*c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 4619*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 4620*c18ec02fSPetter Reinholdtsen rc = (-1); 4621*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4622*c18ec02fSPetter Reinholdtsen } 4623*c18ec02fSPetter Reinholdtsen 4624*c18ec02fSPetter Reinholdtsen memset(&fru, 0, sizeof(fru)); 4625*c18ec02fSPetter Reinholdtsen fru.size = (rsp->data[1] << 8) | rsp->data[0]; 4626*c18ec02fSPetter Reinholdtsen fru.access = rsp->data[2] & 0x1; 4627*c18ec02fSPetter Reinholdtsen 4628*c18ec02fSPetter Reinholdtsen if (fru.size < 1) { 4629*c18ec02fSPetter Reinholdtsen printf(" Invalid FRU size %d", fru.size); 4630*c18ec02fSPetter Reinholdtsen rc = (-1); 4631*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4632*c18ec02fSPetter Reinholdtsen } 4633*c18ec02fSPetter Reinholdtsen /* 4634*c18ec02fSPetter Reinholdtsen * retrieve the FRU header 4635*c18ec02fSPetter Reinholdtsen */ 4636*c18ec02fSPetter Reinholdtsen msg_data[0] = fruId; 4637*c18ec02fSPetter Reinholdtsen msg_data[1] = 0; 4638*c18ec02fSPetter Reinholdtsen msg_data[2] = 0; 4639*c18ec02fSPetter Reinholdtsen msg_data[3] = 8; 4640*c18ec02fSPetter Reinholdtsen 4641*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(req)); 4642*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_STORAGE; 4643*c18ec02fSPetter Reinholdtsen req.msg.cmd = GET_FRU_DATA; 4644*c18ec02fSPetter Reinholdtsen req.msg.data = msg_data; 4645*c18ec02fSPetter Reinholdtsen req.msg.data_len = 4; 4646*c18ec02fSPetter Reinholdtsen 4647*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 4648*c18ec02fSPetter Reinholdtsen if (rsp == NULL) 4649*c18ec02fSPetter Reinholdtsen { 4650*c18ec02fSPetter Reinholdtsen printf(" Device not present (No Response)\n"); 4651*c18ec02fSPetter Reinholdtsen rc = (-1); 4652*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4653*c18ec02fSPetter Reinholdtsen } 4654*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) 4655*c18ec02fSPetter Reinholdtsen { 4656*c18ec02fSPetter Reinholdtsen printf(" Device not present (%s)\n", 4657*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 4658*c18ec02fSPetter Reinholdtsen rc = (-1); 4659*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4660*c18ec02fSPetter Reinholdtsen } 4661*c18ec02fSPetter Reinholdtsen 4662*c18ec02fSPetter Reinholdtsen if (verbose > 1) 4663*c18ec02fSPetter Reinholdtsen printbuf(rsp->data, rsp->data_len, "FRU DATA"); 4664*c18ec02fSPetter Reinholdtsen 4665*c18ec02fSPetter Reinholdtsen memcpy(&header, rsp->data + 1, 8); 4666*c18ec02fSPetter Reinholdtsen 4667*c18ec02fSPetter Reinholdtsen if (header.version != 1) 4668*c18ec02fSPetter Reinholdtsen { 4669*c18ec02fSPetter Reinholdtsen printf(" Unknown FRU header version 0x%02x", 4670*c18ec02fSPetter Reinholdtsen header.version); 4671*c18ec02fSPetter Reinholdtsen rc = (-1); 4672*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4673*c18ec02fSPetter Reinholdtsen } 4674*c18ec02fSPetter Reinholdtsen 4675*c18ec02fSPetter Reinholdtsen fru_data = malloc( fru.size ); 4676*c18ec02fSPetter Reinholdtsen 4677*c18ec02fSPetter Reinholdtsen if( fru_data == NULL ) 4678*c18ec02fSPetter Reinholdtsen { 4679*c18ec02fSPetter Reinholdtsen printf("Out of memory!\n"); 4680*c18ec02fSPetter Reinholdtsen rc = (-1); 4681*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4682*c18ec02fSPetter Reinholdtsen } 4683*c18ec02fSPetter Reinholdtsen 4684*c18ec02fSPetter Reinholdtsen /* Setup offset from the field type */ 4685*c18ec02fSPetter Reinholdtsen 4686*c18ec02fSPetter Reinholdtsen /* Chassis type field */ 4687*c18ec02fSPetter Reinholdtsen if (f_type == 'c' ) { 4688*c18ec02fSPetter Reinholdtsen header_offset = (header.offset.chassis * 8); 4689*c18ec02fSPetter Reinholdtsen read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data); 4690*c18ec02fSPetter Reinholdtsen fru_field_offset = (header.offset.chassis * 8) + 3; 4691*c18ec02fSPetter Reinholdtsen fru_section_len = *(fru_data + header_offset + 1) * 8; 4692*c18ec02fSPetter Reinholdtsen } 4693*c18ec02fSPetter Reinholdtsen /* Board type field */ 4694*c18ec02fSPetter Reinholdtsen else if (f_type == 'b' ) { 4695*c18ec02fSPetter Reinholdtsen header_offset = (header.offset.board * 8); 4696*c18ec02fSPetter Reinholdtsen read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data); 4697*c18ec02fSPetter Reinholdtsen fru_field_offset = (header.offset.board * 8) + 6; 4698*c18ec02fSPetter Reinholdtsen fru_section_len = *(fru_data + header_offset + 1) * 8; 4699*c18ec02fSPetter Reinholdtsen } 4700*c18ec02fSPetter Reinholdtsen /* Product type field */ 4701*c18ec02fSPetter Reinholdtsen else if (f_type == 'p' ) { 4702*c18ec02fSPetter Reinholdtsen header_offset = (header.offset.product * 8); 4703*c18ec02fSPetter Reinholdtsen read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data); 4704*c18ec02fSPetter Reinholdtsen fru_field_offset = (header.offset.product * 8) + 3; 4705*c18ec02fSPetter Reinholdtsen fru_section_len = *(fru_data + header_offset + 1) * 8; 4706*c18ec02fSPetter Reinholdtsen } 4707*c18ec02fSPetter Reinholdtsen else 4708*c18ec02fSPetter Reinholdtsen { 4709*c18ec02fSPetter Reinholdtsen printf("Wrong field type."); 4710*c18ec02fSPetter Reinholdtsen rc = (-1); 4711*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4712*c18ec02fSPetter Reinholdtsen } 4713*c18ec02fSPetter Reinholdtsen memset(fru_data, 0, fru.size); 4714*c18ec02fSPetter Reinholdtsen if( read_fru_area(intf ,&fru, fruId, header_offset , 4715*c18ec02fSPetter Reinholdtsen fru_section_len , fru_data) < 0 ) 4716*c18ec02fSPetter Reinholdtsen { 4717*c18ec02fSPetter Reinholdtsen rc = (-1); 4718*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4719*c18ec02fSPetter Reinholdtsen } 4720*c18ec02fSPetter Reinholdtsen /* Convert index from character to decimal */ 4721*c18ec02fSPetter Reinholdtsen f_index= f_index - 0x30; 4722*c18ec02fSPetter Reinholdtsen 4723*c18ec02fSPetter Reinholdtsen /*Seek to field index */ 4724*c18ec02fSPetter Reinholdtsen for (i=0; i <= f_index; i++) { 4725*c18ec02fSPetter Reinholdtsen fru_field_offset_tmp = fru_field_offset; 4726*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 4727*c18ec02fSPetter Reinholdtsen free(fru_area); 4728*c18ec02fSPetter Reinholdtsen fru_area = NULL; 4729*c18ec02fSPetter Reinholdtsen } 4730*c18ec02fSPetter Reinholdtsen fru_area = (uint8_t *) get_fru_area_str(fru_data, &fru_field_offset); 4731*c18ec02fSPetter Reinholdtsen } 4732*c18ec02fSPetter Reinholdtsen 4733*c18ec02fSPetter Reinholdtsen if( (fru_area == NULL ) || strlen((const char *)fru_area) == 0 ) { 4734*c18ec02fSPetter Reinholdtsen printf("Field not found !\n"); 4735*c18ec02fSPetter Reinholdtsen rc = (-1); 4736*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4737*c18ec02fSPetter Reinholdtsen } 4738*c18ec02fSPetter Reinholdtsen 4739*c18ec02fSPetter Reinholdtsen if ( strlen((const char *)fru_area) == strlen((const char *)f_string) ) 4740*c18ec02fSPetter Reinholdtsen { 4741*c18ec02fSPetter Reinholdtsen printf("Updating Field '%s' with '%s' ...\n", fru_area, f_string ); 4742*c18ec02fSPetter Reinholdtsen memcpy(fru_data + fru_field_offset_tmp + 1, 4743*c18ec02fSPetter Reinholdtsen f_string, strlen(f_string)); 4744*c18ec02fSPetter Reinholdtsen 4745*c18ec02fSPetter Reinholdtsen checksum = 0; 4746*c18ec02fSPetter Reinholdtsen /* Calculate Header Checksum */ 4747*c18ec02fSPetter Reinholdtsen for( i = header_offset; i < header_offset 4748*c18ec02fSPetter Reinholdtsen + fru_section_len - 1; i ++ ) 4749*c18ec02fSPetter Reinholdtsen { 4750*c18ec02fSPetter Reinholdtsen checksum += fru_data[i]; 4751*c18ec02fSPetter Reinholdtsen } 4752*c18ec02fSPetter Reinholdtsen checksum = (~checksum) + 1; 4753*c18ec02fSPetter Reinholdtsen fru_data[header_offset + fru_section_len - 1] = checksum; 4754*c18ec02fSPetter Reinholdtsen 4755*c18ec02fSPetter Reinholdtsen /* Write the updated section to the FRU data */ 4756*c18ec02fSPetter Reinholdtsen if( write_fru_area(intf, &fru, fruId, header_offset, 4757*c18ec02fSPetter Reinholdtsen header_offset, fru_section_len, fru_data) < 0 ) 4758*c18ec02fSPetter Reinholdtsen { 4759*c18ec02fSPetter Reinholdtsen printf("Write to FRU data failed.\n"); 4760*c18ec02fSPetter Reinholdtsen rc = (-1); 4761*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4762*c18ec02fSPetter Reinholdtsen } 4763*c18ec02fSPetter Reinholdtsen } 4764*c18ec02fSPetter Reinholdtsen else { 4765*c18ec02fSPetter Reinholdtsen printf("String size are not equal, resizing fru to fit new string\n"); 4766*c18ec02fSPetter Reinholdtsen if( 4767*c18ec02fSPetter Reinholdtsen ipmi_fru_set_field_string_rebuild(intf,fruId,fru,header,f_type,f_index,f_string) 4768*c18ec02fSPetter Reinholdtsen ) 4769*c18ec02fSPetter Reinholdtsen { 4770*c18ec02fSPetter Reinholdtsen rc = (-1); 4771*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_out; 4772*c18ec02fSPetter Reinholdtsen } 4773*c18ec02fSPetter Reinholdtsen } 4774*c18ec02fSPetter Reinholdtsen 4775*c18ec02fSPetter Reinholdtsen ipmi_fru_set_field_string_out: 4776*c18ec02fSPetter Reinholdtsen if (fru_data != NULL) { 4777*c18ec02fSPetter Reinholdtsen free(fru_data); 4778*c18ec02fSPetter Reinholdtsen fru_data = NULL; 4779*c18ec02fSPetter Reinholdtsen } 4780*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 4781*c18ec02fSPetter Reinholdtsen free(fru_area); 4782*c18ec02fSPetter Reinholdtsen fru_area = NULL; 4783*c18ec02fSPetter Reinholdtsen } 4784*c18ec02fSPetter Reinholdtsen 4785*c18ec02fSPetter Reinholdtsen return rc; 4786*c18ec02fSPetter Reinholdtsen } 4787*c18ec02fSPetter Reinholdtsen 4788*c18ec02fSPetter Reinholdtsen /* 4789*c18ec02fSPetter Reinholdtsen This function can update a string within of the following section when the size is not equal: 4790*c18ec02fSPetter Reinholdtsen 4791*c18ec02fSPetter Reinholdtsen Chassis 4792*c18ec02fSPetter Reinholdtsen Product 4793*c18ec02fSPetter Reinholdtsen Board 4794*c18ec02fSPetter Reinholdtsen */ 4795*c18ec02fSPetter Reinholdtsen /* ipmi_fru_set_field_string_rebuild - Set a field string to a new value, When size are not 4796*c18ec02fSPetter Reinholdtsen * the same size. 4797*c18ec02fSPetter Reinholdtsen * 4798*c18ec02fSPetter Reinholdtsen * This function can update a string within of the following section when the size is not equal: 4799*c18ec02fSPetter Reinholdtsen * 4800*c18ec02fSPetter Reinholdtsen * - Chassis 4801*c18ec02fSPetter Reinholdtsen * - Product 4802*c18ec02fSPetter Reinholdtsen * - Board 4803*c18ec02fSPetter Reinholdtsen * 4804*c18ec02fSPetter Reinholdtsen * @intf: ipmi interface 4805*c18ec02fSPetter Reinholdtsen * @fruId: fru id 4806*c18ec02fSPetter Reinholdtsen * @fru: info about fru 4807*c18ec02fSPetter Reinholdtsen * @header: contain the header of the FRU 4808*c18ec02fSPetter Reinholdtsen * @f_type: Type of the Field : c=Chassis b=Board p=Product 4809*c18ec02fSPetter Reinholdtsen * @f_index: findex of the field, zero indexed. 4810*c18ec02fSPetter Reinholdtsen * @f_string: NULL terminated string 4811*c18ec02fSPetter Reinholdtsen * 4812*c18ec02fSPetter Reinholdtsen * returns -1 on error 4813*c18ec02fSPetter Reinholdtsen * returns 1 if successful 4814*c18ec02fSPetter Reinholdtsen */ 4815*c18ec02fSPetter Reinholdtsen 4816*c18ec02fSPetter Reinholdtsen #define DBG_RESIZE_FRU 4817*c18ec02fSPetter Reinholdtsen static int 4818*c18ec02fSPetter Reinholdtsen ipmi_fru_set_field_string_rebuild(struct ipmi_intf * intf, uint8_t fruId, 4819*c18ec02fSPetter Reinholdtsen struct fru_info fru, struct fru_header header, 4820*c18ec02fSPetter Reinholdtsen uint8_t f_type, uint8_t f_index, char *f_string) 4821*c18ec02fSPetter Reinholdtsen { 4822*c18ec02fSPetter Reinholdtsen uint8_t msg_data[4]; 4823*c18ec02fSPetter Reinholdtsen uint8_t checksum; 4824*c18ec02fSPetter Reinholdtsen int i = 0; 4825*c18ec02fSPetter Reinholdtsen uint8_t *fru_data_old = NULL; 4826*c18ec02fSPetter Reinholdtsen uint8_t *fru_data_new = NULL; 4827*c18ec02fSPetter Reinholdtsen uint8_t *fru_area = NULL; 4828*c18ec02fSPetter Reinholdtsen uint32_t fru_field_offset, fru_field_offset_tmp; 4829*c18ec02fSPetter Reinholdtsen uint32_t fru_section_len, old_section_len, header_offset; 4830*c18ec02fSPetter Reinholdtsen uint32_t chassis_offset, board_offset, product_offset; 4831*c18ec02fSPetter Reinholdtsen uint32_t chassis_len, board_len, product_len, product_len_new; 4832*c18ec02fSPetter Reinholdtsen int num_byte_change = 0, padding_len = 0; 4833*c18ec02fSPetter Reinholdtsen uint32_t counter; 4834*c18ec02fSPetter Reinholdtsen unsigned char cksum; 4835*c18ec02fSPetter Reinholdtsen int rc = 1; 4836*c18ec02fSPetter Reinholdtsen 4837*c18ec02fSPetter Reinholdtsen fru_data_old = calloc( fru.size, sizeof(uint8_t) ); 4838*c18ec02fSPetter Reinholdtsen 4839*c18ec02fSPetter Reinholdtsen fru_data_new = malloc( fru.size ); 4840*c18ec02fSPetter Reinholdtsen 4841*c18ec02fSPetter Reinholdtsen if( fru_data_old == NULL || fru_data_new == NULL ) 4842*c18ec02fSPetter Reinholdtsen { 4843*c18ec02fSPetter Reinholdtsen printf("Out of memory!\n"); 4844*c18ec02fSPetter Reinholdtsen rc = (-1); 4845*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_rebuild_out; 4846*c18ec02fSPetter Reinholdtsen } 4847*c18ec02fSPetter Reinholdtsen 4848*c18ec02fSPetter Reinholdtsen /************************* 4849*c18ec02fSPetter Reinholdtsen 1) Read ALL FRU */ 4850*c18ec02fSPetter Reinholdtsen printf("Read All FRU area\n"); 4851*c18ec02fSPetter Reinholdtsen printf("Fru Size : %u bytes\n", fru.size); 4852*c18ec02fSPetter Reinholdtsen 4853*c18ec02fSPetter Reinholdtsen /* Read current fru data */ 4854*c18ec02fSPetter Reinholdtsen read_fru_area(intf ,&fru, fruId, 0, fru.size , fru_data_old); 4855*c18ec02fSPetter Reinholdtsen 4856*c18ec02fSPetter Reinholdtsen #ifdef DBG_RESIZE_FRU 4857*c18ec02fSPetter Reinholdtsen printf("Copy to new FRU\n"); 4858*c18ec02fSPetter Reinholdtsen #endif 4859*c18ec02fSPetter Reinholdtsen 4860*c18ec02fSPetter Reinholdtsen /************************* 4861*c18ec02fSPetter Reinholdtsen 2) Copy all FRU to new FRU */ 4862*c18ec02fSPetter Reinholdtsen memcpy(fru_data_new, fru_data_old, fru.size); 4863*c18ec02fSPetter Reinholdtsen 4864*c18ec02fSPetter Reinholdtsen /* Build location of all modifiable components */ 4865*c18ec02fSPetter Reinholdtsen chassis_offset = (header.offset.chassis * 8); 4866*c18ec02fSPetter Reinholdtsen board_offset = (header.offset.board * 8); 4867*c18ec02fSPetter Reinholdtsen product_offset = (header.offset.product * 8); 4868*c18ec02fSPetter Reinholdtsen 4869*c18ec02fSPetter Reinholdtsen /* Retrieve length of all modifiable components */ 4870*c18ec02fSPetter Reinholdtsen chassis_len = *(fru_data_old + chassis_offset + 1) * 8; 4871*c18ec02fSPetter Reinholdtsen board_len = *(fru_data_old + board_offset + 1) * 8; 4872*c18ec02fSPetter Reinholdtsen product_len = *(fru_data_old + product_offset + 1) * 8; 4873*c18ec02fSPetter Reinholdtsen product_len_new = product_len; 4874*c18ec02fSPetter Reinholdtsen 4875*c18ec02fSPetter Reinholdtsen /* Chassis type field */ 4876*c18ec02fSPetter Reinholdtsen if (f_type == 'c' ) 4877*c18ec02fSPetter Reinholdtsen { 4878*c18ec02fSPetter Reinholdtsen header_offset = chassis_offset; 4879*c18ec02fSPetter Reinholdtsen fru_field_offset = chassis_offset + 3; 4880*c18ec02fSPetter Reinholdtsen fru_section_len = chassis_len; 4881*c18ec02fSPetter Reinholdtsen } 4882*c18ec02fSPetter Reinholdtsen /* Board type field */ 4883*c18ec02fSPetter Reinholdtsen else if (f_type == 'b' ) 4884*c18ec02fSPetter Reinholdtsen { 4885*c18ec02fSPetter Reinholdtsen header_offset = board_offset; 4886*c18ec02fSPetter Reinholdtsen fru_field_offset = board_offset + 6; 4887*c18ec02fSPetter Reinholdtsen fru_section_len = board_len; 4888*c18ec02fSPetter Reinholdtsen } 4889*c18ec02fSPetter Reinholdtsen /* Product type field */ 4890*c18ec02fSPetter Reinholdtsen else if (f_type == 'p' ) 4891*c18ec02fSPetter Reinholdtsen { 4892*c18ec02fSPetter Reinholdtsen header_offset = product_offset; 4893*c18ec02fSPetter Reinholdtsen fru_field_offset = product_offset + 3; 4894*c18ec02fSPetter Reinholdtsen fru_section_len = product_len; 4895*c18ec02fSPetter Reinholdtsen } 4896*c18ec02fSPetter Reinholdtsen else 4897*c18ec02fSPetter Reinholdtsen { 4898*c18ec02fSPetter Reinholdtsen printf("Wrong field type."); 4899*c18ec02fSPetter Reinholdtsen rc = (-1); 4900*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_rebuild_out; 4901*c18ec02fSPetter Reinholdtsen } 4902*c18ec02fSPetter Reinholdtsen 4903*c18ec02fSPetter Reinholdtsen /* Keep length for future old section display */ 4904*c18ec02fSPetter Reinholdtsen old_section_len = fru_section_len; 4905*c18ec02fSPetter Reinholdtsen 4906*c18ec02fSPetter Reinholdtsen /************************* 4907*c18ec02fSPetter Reinholdtsen 3) Seek to field index */ 4908*c18ec02fSPetter Reinholdtsen for (i = 0;i <= f_index; i++) { 4909*c18ec02fSPetter Reinholdtsen fru_field_offset_tmp = fru_field_offset; 4910*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 4911*c18ec02fSPetter Reinholdtsen free(fru_area); 4912*c18ec02fSPetter Reinholdtsen fru_area = NULL; 4913*c18ec02fSPetter Reinholdtsen } 4914*c18ec02fSPetter Reinholdtsen fru_area = (uint8_t *) get_fru_area_str(fru_data_old, &fru_field_offset); 4915*c18ec02fSPetter Reinholdtsen } 4916*c18ec02fSPetter Reinholdtsen 4917*c18ec02fSPetter Reinholdtsen if( (fru_area == NULL ) || strlen((const char *)fru_area) == 0 ) { 4918*c18ec02fSPetter Reinholdtsen printf("Field not found (1)!\n"); 4919*c18ec02fSPetter Reinholdtsen rc = (-1); 4920*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_rebuild_out; 4921*c18ec02fSPetter Reinholdtsen } 4922*c18ec02fSPetter Reinholdtsen 4923*c18ec02fSPetter Reinholdtsen #ifdef DBG_RESIZE_FRU 4924*c18ec02fSPetter Reinholdtsen printf("Section Length: %u\n", fru_section_len); 4925*c18ec02fSPetter Reinholdtsen #endif 4926*c18ec02fSPetter Reinholdtsen 4927*c18ec02fSPetter Reinholdtsen /************************* 4928*c18ec02fSPetter Reinholdtsen 4) Check number of padding bytes and bytes changed */ 4929*c18ec02fSPetter Reinholdtsen for(counter = 2; counter < fru_section_len; counter ++) 4930*c18ec02fSPetter Reinholdtsen { 4931*c18ec02fSPetter Reinholdtsen if(*(fru_data_old + (header_offset + fru_section_len - counter)) == 0) 4932*c18ec02fSPetter Reinholdtsen padding_len ++; 4933*c18ec02fSPetter Reinholdtsen else 4934*c18ec02fSPetter Reinholdtsen break; 4935*c18ec02fSPetter Reinholdtsen } 4936*c18ec02fSPetter Reinholdtsen num_byte_change = strlen(f_string) - strlen(fru_area); 4937*c18ec02fSPetter Reinholdtsen 4938*c18ec02fSPetter Reinholdtsen #ifdef DBG_RESIZE_FRU 4939*c18ec02fSPetter Reinholdtsen printf("Padding Length: %u\n", padding_len); 4940*c18ec02fSPetter Reinholdtsen printf("NumByte Change: %i\n", num_byte_change); 4941*c18ec02fSPetter Reinholdtsen printf("Start SecChnge: %x\n", *(fru_data_old + fru_field_offset_tmp)); 4942*c18ec02fSPetter Reinholdtsen printf("End SecChnge : %x\n", *(fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1)); 4943*c18ec02fSPetter Reinholdtsen 4944*c18ec02fSPetter Reinholdtsen printf("Start Section : %x\n", *(fru_data_old + header_offset)); 4945*c18ec02fSPetter Reinholdtsen printf("End Sec wo Pad: %x\n", *(fru_data_old + header_offset + fru_section_len - 2 - padding_len)); 4946*c18ec02fSPetter Reinholdtsen printf("End Section : %x\n", *(fru_data_old + header_offset + fru_section_len - 1)); 4947*c18ec02fSPetter Reinholdtsen #endif 4948*c18ec02fSPetter Reinholdtsen 4949*c18ec02fSPetter Reinholdtsen /* Calculate New Padding Length */ 4950*c18ec02fSPetter Reinholdtsen padding_len -= num_byte_change; 4951*c18ec02fSPetter Reinholdtsen 4952*c18ec02fSPetter Reinholdtsen #ifdef DBG_RESIZE_FRU 4953*c18ec02fSPetter Reinholdtsen printf("New Padding Length: %i\n", padding_len); 4954*c18ec02fSPetter Reinholdtsen #endif 4955*c18ec02fSPetter Reinholdtsen 4956*c18ec02fSPetter Reinholdtsen /************************* 4957*c18ec02fSPetter Reinholdtsen 5) Check if section must be resize. This occur when padding length is not between 0 and 7 */ 4958*c18ec02fSPetter Reinholdtsen if( (padding_len < 0) || (padding_len >= 8)) 4959*c18ec02fSPetter Reinholdtsen { 4960*c18ec02fSPetter Reinholdtsen uint32_t remaining_offset = ((header.offset.product * 8) + product_len); 4961*c18ec02fSPetter Reinholdtsen int change_size_by_8; 4962*c18ec02fSPetter Reinholdtsen 4963*c18ec02fSPetter Reinholdtsen if(padding_len >= 8) 4964*c18ec02fSPetter Reinholdtsen { 4965*c18ec02fSPetter Reinholdtsen /* Section must be set smaller */ 4966*c18ec02fSPetter Reinholdtsen change_size_by_8 = ((padding_len) / 8) * (-1); 4967*c18ec02fSPetter Reinholdtsen } 4968*c18ec02fSPetter Reinholdtsen else 4969*c18ec02fSPetter Reinholdtsen { 4970*c18ec02fSPetter Reinholdtsen /* Section must be set bigger */ 4971*c18ec02fSPetter Reinholdtsen change_size_by_8 = 1 + (((padding_len+1) / 8) * (-1)); 4972*c18ec02fSPetter Reinholdtsen } 4973*c18ec02fSPetter Reinholdtsen 4974*c18ec02fSPetter Reinholdtsen /* Recalculate padding and section length base on the section changes */ 4975*c18ec02fSPetter Reinholdtsen fru_section_len += (change_size_by_8 * 8); 4976*c18ec02fSPetter Reinholdtsen padding_len += (change_size_by_8 * 8); 4977*c18ec02fSPetter Reinholdtsen 4978*c18ec02fSPetter Reinholdtsen #ifdef DBG_RESIZE_FRU 4979*c18ec02fSPetter Reinholdtsen printf("change_size_by_8: %i\n", change_size_by_8); 4980*c18ec02fSPetter Reinholdtsen printf("New Padding Length: %i\n", padding_len); 4981*c18ec02fSPetter Reinholdtsen printf("change_size_by_8: %i\n", change_size_by_8); 4982*c18ec02fSPetter Reinholdtsen printf("header.offset.board: %i\n", header.offset.board); 4983*c18ec02fSPetter Reinholdtsen #endif 4984*c18ec02fSPetter Reinholdtsen 4985*c18ec02fSPetter Reinholdtsen /* Must move sections */ 4986*c18ec02fSPetter Reinholdtsen /* Section that can be modified are as follow 4987*c18ec02fSPetter Reinholdtsen Chassis 4988*c18ec02fSPetter Reinholdtsen Board 4989*c18ec02fSPetter Reinholdtsen product */ 4990*c18ec02fSPetter Reinholdtsen 4991*c18ec02fSPetter Reinholdtsen /* Chassis type field */ 4992*c18ec02fSPetter Reinholdtsen if (f_type == 'c' ) 4993*c18ec02fSPetter Reinholdtsen { 4994*c18ec02fSPetter Reinholdtsen printf("Moving Section Chassis, from %i to %i\n", 4995*c18ec02fSPetter Reinholdtsen ((header.offset.board) * 8), 4996*c18ec02fSPetter Reinholdtsen ((header.offset.board + change_size_by_8) * 8) 4997*c18ec02fSPetter Reinholdtsen ); 4998*c18ec02fSPetter Reinholdtsen memcpy( 4999*c18ec02fSPetter Reinholdtsen (fru_data_new + ((header.offset.board + change_size_by_8) * 8)), 5000*c18ec02fSPetter Reinholdtsen (fru_data_old + (header.offset.board) * 8), 5001*c18ec02fSPetter Reinholdtsen board_len 5002*c18ec02fSPetter Reinholdtsen ); 5003*c18ec02fSPetter Reinholdtsen header.offset.board += change_size_by_8; 5004*c18ec02fSPetter Reinholdtsen } 5005*c18ec02fSPetter Reinholdtsen /* Board type field */ 5006*c18ec02fSPetter Reinholdtsen if ((f_type == 'c' ) || (f_type == 'b' )) 5007*c18ec02fSPetter Reinholdtsen { 5008*c18ec02fSPetter Reinholdtsen printf("Moving Section Product, from %i to %i\n", 5009*c18ec02fSPetter Reinholdtsen ((header.offset.product) * 8), 5010*c18ec02fSPetter Reinholdtsen ((header.offset.product + change_size_by_8) * 8) 5011*c18ec02fSPetter Reinholdtsen ); 5012*c18ec02fSPetter Reinholdtsen memcpy( 5013*c18ec02fSPetter Reinholdtsen (fru_data_new + ((header.offset.product + change_size_by_8) * 8)), 5014*c18ec02fSPetter Reinholdtsen (fru_data_old + (header.offset.product) * 8), 5015*c18ec02fSPetter Reinholdtsen product_len 5016*c18ec02fSPetter Reinholdtsen ); 5017*c18ec02fSPetter Reinholdtsen header.offset.product += change_size_by_8; 5018*c18ec02fSPetter Reinholdtsen } 5019*c18ec02fSPetter Reinholdtsen 5020*c18ec02fSPetter Reinholdtsen /* Adjust length of the section */ 5021*c18ec02fSPetter Reinholdtsen if (f_type == 'c') 5022*c18ec02fSPetter Reinholdtsen { 5023*c18ec02fSPetter Reinholdtsen *(fru_data_new + chassis_offset + 1) += change_size_by_8; 5024*c18ec02fSPetter Reinholdtsen } 5025*c18ec02fSPetter Reinholdtsen else if( f_type == 'b') 5026*c18ec02fSPetter Reinholdtsen { 5027*c18ec02fSPetter Reinholdtsen *(fru_data_new + board_offset + 1) += change_size_by_8; 5028*c18ec02fSPetter Reinholdtsen } 5029*c18ec02fSPetter Reinholdtsen else if( f_type == 'p') 5030*c18ec02fSPetter Reinholdtsen { 5031*c18ec02fSPetter Reinholdtsen *(fru_data_new + product_offset + 1) += change_size_by_8; 5032*c18ec02fSPetter Reinholdtsen product_len_new = *(fru_data_new + product_offset + 1) * 8; 5033*c18ec02fSPetter Reinholdtsen } 5034*c18ec02fSPetter Reinholdtsen 5035*c18ec02fSPetter Reinholdtsen /* Rebuild Header checksum */ 5036*c18ec02fSPetter Reinholdtsen { 5037*c18ec02fSPetter Reinholdtsen unsigned char * pfru_header = (unsigned char *) &header; 5038*c18ec02fSPetter Reinholdtsen header.checksum = 0; 5039*c18ec02fSPetter Reinholdtsen for(counter = 0; counter < (sizeof(struct fru_header) -1); counter ++) 5040*c18ec02fSPetter Reinholdtsen { 5041*c18ec02fSPetter Reinholdtsen header.checksum += pfru_header[counter]; 5042*c18ec02fSPetter Reinholdtsen } 5043*c18ec02fSPetter Reinholdtsen header.checksum = (0 - header.checksum); 5044*c18ec02fSPetter Reinholdtsen memcpy(fru_data_new, pfru_header, sizeof(struct fru_header)); 5045*c18ec02fSPetter Reinholdtsen } 5046*c18ec02fSPetter Reinholdtsen 5047*c18ec02fSPetter Reinholdtsen /* Move remaining sections in 1 copy */ 5048*c18ec02fSPetter Reinholdtsen printf("Moving Remaining Bytes (Multi-Rec , etc..), from %i to %i\n", 5049*c18ec02fSPetter Reinholdtsen remaining_offset, 5050*c18ec02fSPetter Reinholdtsen ((header.offset.product) * 8) + product_len_new 5051*c18ec02fSPetter Reinholdtsen ); 5052*c18ec02fSPetter Reinholdtsen if(((header.offset.product * 8) + product_len_new - remaining_offset) < 0) 5053*c18ec02fSPetter Reinholdtsen { 5054*c18ec02fSPetter Reinholdtsen memcpy( 5055*c18ec02fSPetter Reinholdtsen fru_data_new + (header.offset.product * 8) + product_len_new, 5056*c18ec02fSPetter Reinholdtsen fru_data_old + remaining_offset, 5057*c18ec02fSPetter Reinholdtsen fru.size - remaining_offset 5058*c18ec02fSPetter Reinholdtsen ); 5059*c18ec02fSPetter Reinholdtsen } 5060*c18ec02fSPetter Reinholdtsen else 5061*c18ec02fSPetter Reinholdtsen { 5062*c18ec02fSPetter Reinholdtsen memcpy( 5063*c18ec02fSPetter Reinholdtsen fru_data_new + (header.offset.product * 8) + product_len_new, 5064*c18ec02fSPetter Reinholdtsen fru_data_old + remaining_offset, 5065*c18ec02fSPetter Reinholdtsen fru.size - ((header.offset.product * 8) + product_len_new) 5066*c18ec02fSPetter Reinholdtsen ); 5067*c18ec02fSPetter Reinholdtsen } 5068*c18ec02fSPetter Reinholdtsen } 5069*c18ec02fSPetter Reinholdtsen 5070*c18ec02fSPetter Reinholdtsen /* Update only if it's fits padding length as defined in the spec, otherwise, it's an internal 5071*c18ec02fSPetter Reinholdtsen error */ 5072*c18ec02fSPetter Reinholdtsen /************************* 5073*c18ec02fSPetter Reinholdtsen 6) Update Field and sections */ 5074*c18ec02fSPetter Reinholdtsen if( (padding_len >=0) && (padding_len < 8)) 5075*c18ec02fSPetter Reinholdtsen { 5076*c18ec02fSPetter Reinholdtsen /* Do not requires any change in other section */ 5077*c18ec02fSPetter Reinholdtsen 5078*c18ec02fSPetter Reinholdtsen /* Change field length */ 5079*c18ec02fSPetter Reinholdtsen printf( 5080*c18ec02fSPetter Reinholdtsen "Updating Field : '%s' with '%s' ... (Length from '%d' to '%d')\n", 5081*c18ec02fSPetter Reinholdtsen fru_area, f_string, 5082*c18ec02fSPetter Reinholdtsen (int)*(fru_data_old + fru_field_offset_tmp), 5083*c18ec02fSPetter Reinholdtsen (int)(0xc0 + strlen(f_string))); 5084*c18ec02fSPetter Reinholdtsen *(fru_data_new + fru_field_offset_tmp) = (0xc0 + strlen(f_string)); 5085*c18ec02fSPetter Reinholdtsen memcpy(fru_data_new + fru_field_offset_tmp + 1, f_string, strlen(f_string)); 5086*c18ec02fSPetter Reinholdtsen 5087*c18ec02fSPetter Reinholdtsen /* Copy remaing bytes in section */ 5088*c18ec02fSPetter Reinholdtsen #ifdef DBG_RESIZE_FRU 5089*c18ec02fSPetter Reinholdtsen printf("Copying remaining of sections: %d \n", 5090*c18ec02fSPetter Reinholdtsen (int)((fru_data_old + header_offset + fru_section_len - 1) - 5091*c18ec02fSPetter Reinholdtsen (fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1))); 5092*c18ec02fSPetter Reinholdtsen #endif 5093*c18ec02fSPetter Reinholdtsen 5094*c18ec02fSPetter Reinholdtsen memcpy((fru_data_new + fru_field_offset_tmp + 1 + 5095*c18ec02fSPetter Reinholdtsen strlen(f_string)), 5096*c18ec02fSPetter Reinholdtsen (fru_data_old + fru_field_offset_tmp + 1 + 5097*c18ec02fSPetter Reinholdtsen strlen(fru_area)), 5098*c18ec02fSPetter Reinholdtsen ((fru_data_old + header_offset + fru_section_len - 1) - 5099*c18ec02fSPetter Reinholdtsen (fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1))); 5100*c18ec02fSPetter Reinholdtsen 5101*c18ec02fSPetter Reinholdtsen /* Add Padding if required */ 5102*c18ec02fSPetter Reinholdtsen for(counter = 0; counter < padding_len; counter ++) 5103*c18ec02fSPetter Reinholdtsen { 5104*c18ec02fSPetter Reinholdtsen *(fru_data_new + header_offset + fru_section_len - 1 - 5105*c18ec02fSPetter Reinholdtsen padding_len + counter) = 0; 5106*c18ec02fSPetter Reinholdtsen } 5107*c18ec02fSPetter Reinholdtsen 5108*c18ec02fSPetter Reinholdtsen /* Calculate New Checksum */ 5109*c18ec02fSPetter Reinholdtsen cksum = 0; 5110*c18ec02fSPetter Reinholdtsen for( counter = 0; counter <fru_section_len-1; counter ++ ) 5111*c18ec02fSPetter Reinholdtsen { 5112*c18ec02fSPetter Reinholdtsen cksum += *(fru_data_new + header_offset + counter); 5113*c18ec02fSPetter Reinholdtsen } 5114*c18ec02fSPetter Reinholdtsen *(fru_data_new + header_offset + fru_section_len - 1) = (0 - cksum); 5115*c18ec02fSPetter Reinholdtsen 5116*c18ec02fSPetter Reinholdtsen #ifdef DBG_RESIZE_FRU 5117*c18ec02fSPetter Reinholdtsen printf("Calculate New Checksum: %x\n", (0 - cksum)); 5118*c18ec02fSPetter Reinholdtsen #endif 5119*c18ec02fSPetter Reinholdtsen 5120*c18ec02fSPetter Reinholdtsen /****** ENABLE to show section modified before and after ********/ 5121*c18ec02fSPetter Reinholdtsen #if 0 5122*c18ec02fSPetter Reinholdtsen printf("Section: "); 5123*c18ec02fSPetter Reinholdtsen for( counter = 0; counter <old_section_len; counter ++ ) 5124*c18ec02fSPetter Reinholdtsen { 5125*c18ec02fSPetter Reinholdtsen if((counter %16) == 0) 5126*c18ec02fSPetter Reinholdtsen { 5127*c18ec02fSPetter Reinholdtsen printf("\n"); 5128*c18ec02fSPetter Reinholdtsen } 5129*c18ec02fSPetter Reinholdtsen printf( "%02X ", *(fru_data_old + header_offset + counter) ); 5130*c18ec02fSPetter Reinholdtsen } 5131*c18ec02fSPetter Reinholdtsen printf("\n"); 5132*c18ec02fSPetter Reinholdtsen 5133*c18ec02fSPetter Reinholdtsen printf("Section: "); 5134*c18ec02fSPetter Reinholdtsen for( counter = 0; counter <fru_section_len; counter ++ ) 5135*c18ec02fSPetter Reinholdtsen { 5136*c18ec02fSPetter Reinholdtsen if((counter %16) == 0) 5137*c18ec02fSPetter Reinholdtsen { 5138*c18ec02fSPetter Reinholdtsen printf("\n"); 5139*c18ec02fSPetter Reinholdtsen } 5140*c18ec02fSPetter Reinholdtsen printf( "%02X ", *(fru_data_new + header_offset + counter) ); 5141*c18ec02fSPetter Reinholdtsen } 5142*c18ec02fSPetter Reinholdtsen printf("\n"); 5143*c18ec02fSPetter Reinholdtsen #endif 5144*c18ec02fSPetter Reinholdtsen } 5145*c18ec02fSPetter Reinholdtsen else 5146*c18ec02fSPetter Reinholdtsen { 5147*c18ec02fSPetter Reinholdtsen printf( "Internal error, padding length %i (must be from 0 to 7) ", padding_len ); 5148*c18ec02fSPetter Reinholdtsen rc = (-1); 5149*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_rebuild_out; 5150*c18ec02fSPetter Reinholdtsen } 5151*c18ec02fSPetter Reinholdtsen 5152*c18ec02fSPetter Reinholdtsen /************************* 5153*c18ec02fSPetter Reinholdtsen 7) Finally, write new FRU */ 5154*c18ec02fSPetter Reinholdtsen printf("Writing new FRU.\n"); 5155*c18ec02fSPetter Reinholdtsen if( write_fru_area( intf, &fru, fruId, 0, 0, fru.size, fru_data_new ) < 0 ) 5156*c18ec02fSPetter Reinholdtsen { 5157*c18ec02fSPetter Reinholdtsen printf("Write to FRU data failed.\n"); 5158*c18ec02fSPetter Reinholdtsen rc = (-1); 5159*c18ec02fSPetter Reinholdtsen goto ipmi_fru_set_field_string_rebuild_out; 5160*c18ec02fSPetter Reinholdtsen } 5161*c18ec02fSPetter Reinholdtsen 5162*c18ec02fSPetter Reinholdtsen printf("Done.\n"); 5163*c18ec02fSPetter Reinholdtsen 5164*c18ec02fSPetter Reinholdtsen ipmi_fru_set_field_string_rebuild_out: 5165*c18ec02fSPetter Reinholdtsen if (fru_area != NULL) { 5166*c18ec02fSPetter Reinholdtsen free(fru_area); 5167*c18ec02fSPetter Reinholdtsen fru_area = NULL; 5168*c18ec02fSPetter Reinholdtsen } 5169*c18ec02fSPetter Reinholdtsen if (fru_data_new != NULL) { 5170*c18ec02fSPetter Reinholdtsen free(fru_data_new); 5171*c18ec02fSPetter Reinholdtsen fru_data_new = NULL; 5172*c18ec02fSPetter Reinholdtsen } 5173*c18ec02fSPetter Reinholdtsen if (fru_data_old != NULL) { 5174*c18ec02fSPetter Reinholdtsen free(fru_data_old); 5175*c18ec02fSPetter Reinholdtsen fru_data_old = NULL; 5176*c18ec02fSPetter Reinholdtsen } 5177*c18ec02fSPetter Reinholdtsen 5178*c18ec02fSPetter Reinholdtsen return rc; 5179*c18ec02fSPetter Reinholdtsen } 5180