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