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