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