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