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