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 /* Yes. Prepare to issue FRU commands to FRU device #0 LUN 0 */ 3116 /* using the slave address specified in the MC record. */ 3117 3118 /* save current target address */ 3119 save_addr = intf->target_addr; 3120 3121 /* set new target address to satellite controller */ 3122 intf->target_addr = mc->dev_slave_addr; 3123 3124 printf("FRU Device Description : %-16s\n", mc->id_string); 3125 3126 /* print the FRU by issuing FRU commands to the satellite */ 3127 /* controller. */ 3128 rc = __ipmi_fru_print(intf, 0); 3129 3130 printf("\n"); 3131 3132 /* restore previous target */ 3133 intf->target_addr = save_addr; 3134 } 3135 3136 if (mc) { 3137 free(mc); 3138 mc = NULL; 3139 } 3140 3141 continue; 3142 } 3143 3144 if (header->type != SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR) 3145 continue; 3146 3147 /* Print the FRU from the SDR locator record. */ 3148 fru = (struct sdr_record_fru_locator *) 3149 ipmi_sdr_get_record(intf, header, itr); 3150 if (fru == NULL || !fru->logical) { 3151 if (fru) { 3152 free(fru); 3153 fru = NULL; 3154 } 3155 continue; 3156 } 3157 rc = ipmi_fru_print(intf, fru); 3158 free(fru); 3159 fru = NULL; 3160 } 3161 3162 ipmi_sdr_end(intf, itr); 3163 3164 return rc; 3165 } 3166 3167 /* ipmi_fru_read_help() - print help text for 'read' 3168 * 3169 * returns void 3170 */ 3171 void 3172 ipmi_fru_read_help() 3173 { 3174 lprintf(LOG_NOTICE, "fru read <fru id> <fru file>"); 3175 lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified."); 3176 lprintf(LOG_NOTICE, "Example: ipmitool fru read 0 /root/fru.bin"); 3177 } /* ipmi_fru_read_help() */ 3178 3179 static void 3180 ipmi_fru_read_to_bin(struct ipmi_intf * intf, 3181 char * pFileName, 3182 uint8_t fruId) 3183 { 3184 struct ipmi_rs * rsp; 3185 struct ipmi_rq req; 3186 struct fru_info fru; 3187 uint8_t msg_data[4]; 3188 uint8_t * pFruBuf; 3189 3190 msg_data[0] = fruId; 3191 3192 memset(&req, 0, sizeof(req)); 3193 req.msg.netfn = IPMI_NETFN_STORAGE; 3194 req.msg.cmd = GET_FRU_INFO; 3195 req.msg.data = msg_data; 3196 req.msg.data_len = 1; 3197 3198 rsp = intf->sendrecv(intf, &req); 3199 if (!rsp) 3200 return; 3201 3202 if (rsp->ccode > 0) { 3203 if (rsp->ccode == 0xc3) 3204 printf (" Timeout accessing FRU info. (Device not present?)\n"); 3205 return; 3206 } 3207 3208 memset(&fru, 0, sizeof(fru)); 3209 fru.size = (rsp->data[1] << 8) | rsp->data[0]; 3210 fru.access = rsp->data[2] & 0x1; 3211 3212 if (verbose) { 3213 printf("Fru Size = %d bytes\n",fru.size); 3214 printf("Fru Access = %xh\n", fru.access); 3215 } 3216 3217 pFruBuf = malloc(fru.size); 3218 if (pFruBuf != NULL) { 3219 printf("Fru Size : %d bytes\n",fru.size); 3220 read_fru_area(intf, &fru, fruId, 0, fru.size, pFruBuf); 3221 } else { 3222 lprintf(LOG_ERR, "Cannot allocate %d bytes\n", fru.size); 3223 return; 3224 } 3225 3226 if(pFruBuf != NULL) 3227 { 3228 FILE * pFile; 3229 pFile = fopen(pFileName,"wb"); 3230 if (pFile) { 3231 fwrite(pFruBuf, fru.size, 1, pFile); 3232 printf("Done\n"); 3233 } else { 3234 lprintf(LOG_ERR, "Error opening file %s\n", pFileName); 3235 free(pFruBuf); 3236 pFruBuf = NULL; 3237 return; 3238 } 3239 fclose(pFile); 3240 } 3241 free(pFruBuf); 3242 pFruBuf = NULL; 3243 } 3244 3245 static void 3246 ipmi_fru_write_from_bin(struct ipmi_intf * intf, 3247 char * pFileName, 3248 uint8_t fruId) 3249 { 3250 struct ipmi_rs *rsp; 3251 struct ipmi_rq req; 3252 struct fru_info fru; 3253 uint8_t msg_data[4]; 3254 uint8_t *pFruBuf; 3255 uint16_t len = 0; 3256 FILE *pFile; 3257 3258 msg_data[0] = fruId; 3259 3260 memset(&req, 0, sizeof (req)); 3261 req.msg.netfn = IPMI_NETFN_STORAGE; 3262 req.msg.cmd = GET_FRU_INFO; 3263 req.msg.data = msg_data; 3264 req.msg.data_len = 1; 3265 3266 rsp = intf->sendrecv(intf, &req); 3267 if (!rsp) 3268 return; 3269 3270 if (rsp->ccode) { 3271 if (rsp->ccode == 0xc3) 3272 printf(" Timeout accessing FRU info. (Device not present?)\n"); 3273 return; 3274 } 3275 3276 memset(&fru, 0, sizeof(fru)); 3277 fru.size = (rsp->data[1] << 8) | rsp->data[0]; 3278 fru.access = rsp->data[2] & 0x1; 3279 3280 if (verbose) { 3281 printf("Fru Size = %d bytes\n", fru.size); 3282 printf("Fru Access = %xh\n", fru.access); 3283 } 3284 3285 pFruBuf = malloc(fru.size); 3286 if (pFruBuf == NULL) { 3287 lprintf(LOG_ERR, "Cannot allocate %d bytes\n", fru.size); 3288 return; 3289 } 3290 3291 pFile = fopen(pFileName, "rb"); 3292 if (pFile != NULL) { 3293 len = fread(pFruBuf, 1, fru.size, pFile); 3294 printf("Fru Size : %d bytes\n", fru.size); 3295 printf("Size to Write : %d bytes\n", len); 3296 fclose(pFile); 3297 } else { 3298 lprintf(LOG_ERR, "Error opening file %s\n", pFileName); 3299 } 3300 3301 if (len != 0) { 3302 write_fru_area(intf, &fru, fruId,0, 0, len, pFruBuf); 3303 lprintf(LOG_INFO,"Done"); 3304 } 3305 3306 free(pFruBuf); 3307 pFruBuf = NULL; 3308 } 3309 3310 /* ipmi_fru_write_help() - print help text for 'write' 3311 * 3312 * retruns void 3313 */ 3314 void 3315 ipmi_fru_write_help() 3316 { 3317 lprintf(LOG_NOTICE, "fru write <fru id> <fru file>"); 3318 lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified."); 3319 lprintf(LOG_NOTICE, "Example: ipmitool fru write 0 /root/fru.bin"); 3320 } /* ipmi_fru_write_help() */ 3321 3322 /* ipmi_fru_edit_help - print help text for 'fru edit' command 3323 * 3324 * returns void 3325 */ 3326 void 3327 ipmi_fru_edit_help() 3328 { 3329 lprintf(LOG_NOTICE, 3330 "fru edit <fruid> field <section> <index> <string> - edit FRU string"); 3331 lprintf(LOG_NOTICE, 3332 "fru edit <fruid> oem iana <record> <format> <args> - limited OEM support"); 3333 } /* ipmi_fru_edit_help() */ 3334 3335 /* ipmi_fru_edit_multirec - Query new values to replace original FRU content 3336 * 3337 * @intf: interface to use 3338 * @id: FRU id to work on 3339 * 3340 * returns: nothing 3341 */ 3342 /* Work in progress, copy paste most of the stuff for other functions in this 3343 file ... not elegant yet */ 3344 static int 3345 ipmi_fru_edit_multirec(struct ipmi_intf * intf, uint8_t id , 3346 int argc, char ** argv) 3347 { 3348 3349 struct ipmi_rs * rsp; 3350 struct ipmi_rq req; 3351 struct fru_info fru; 3352 struct fru_header header; 3353 uint8_t msg_data[4]; 3354 3355 uint16_t retStatus = 0; 3356 uint32_t offFruMultiRec; 3357 uint32_t fruMultiRecSize = 0; 3358 struct fru_info fruInfo; 3359 retStatus = ipmi_fru_get_multirec_location_from_fru(intf, id, &fruInfo, 3360 &offFruMultiRec, 3361 &fruMultiRecSize); 3362 3363 3364 lprintf(LOG_DEBUG, "FRU Size : %lu\n", fruMultiRecSize); 3365 lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec); 3366 3367 { 3368 3369 3370 memset(&fru, 0, sizeof(struct fru_info)); 3371 memset(&header, 0, sizeof(struct fru_header)); 3372 3373 /* 3374 * get info about this FRU 3375 */ 3376 memset(msg_data, 0, 4); 3377 msg_data[0] = id; 3378 3379 memset(&req, 0, sizeof(req)); 3380 req.msg.netfn = IPMI_NETFN_STORAGE; 3381 req.msg.cmd = GET_FRU_INFO; 3382 req.msg.data = msg_data; 3383 req.msg.data_len = 1; 3384 3385 rsp = intf->sendrecv(intf, &req); 3386 if (rsp == NULL) { 3387 printf(" Device not present (No Response)\n"); 3388 return -1; 3389 } 3390 if (rsp->ccode > 0) { 3391 printf(" Device not present (%s)\n", 3392 val2str(rsp->ccode, completion_code_vals)); 3393 return -1; 3394 } 3395 3396 memset(&fru, 0, sizeof(fru)); 3397 fru.size = (rsp->data[1] << 8) | rsp->data[0]; 3398 fru.access = rsp->data[2] & 0x1; 3399 3400 lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)", 3401 fru.size, fru.access ? "words" : "bytes"); 3402 3403 if (fru.size < 1) { 3404 lprintf(LOG_ERR, " Invalid FRU size %d", fru.size); 3405 return -1; 3406 } 3407 } 3408 3409 { 3410 uint8_t * fru_data; 3411 uint32_t fru_len, i; 3412 uint32_t offset= offFruMultiRec; 3413 struct fru_multirec_header * h; 3414 uint32_t last_off, len; 3415 uint8_t error=0; 3416 3417 i = last_off = offset; 3418 fru_len = 0; 3419 3420 memset(&fru, 0, sizeof(fru)); 3421 fru_data = malloc(fru.size + 1); 3422 if (fru_data == NULL) { 3423 lprintf(LOG_ERR, " Out of memory!"); 3424 return -1; 3425 } 3426 memset(fru_data, 0, fru.size + 1); 3427 3428 do { 3429 h = (struct fru_multirec_header *) (fru_data + i); 3430 3431 /* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */ 3432 if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len))) 3433 { 3434 len = fru.size - last_off; 3435 if (len > FRU_MULTIREC_CHUNK_SIZE) 3436 len = FRU_MULTIREC_CHUNK_SIZE; 3437 3438 if (read_fru_area(intf, &fru, id, last_off, len, fru_data) < 0) 3439 break; 3440 3441 last_off += len; 3442 } 3443 if( h->type == FRU_RECORD_TYPE_OEM_EXTENSION ){ 3444 3445 struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *) 3446 &fru_data[i + sizeof(struct fru_multirec_header)]; 3447 uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16; 3448 3449 uint32_t suppliedIana = 0 ; 3450 /* Now makes sure this is really PICMG record */ 3451 3452 /* Default to PICMG for backward compatibility */ 3453 if( argc <=2 ) { 3454 suppliedIana = IPMI_OEM_PICMG; 3455 } else { 3456 if( !strncmp( argv[2] , "oem" , 3 )) { 3457 /* Expect IANA number next */ 3458 if( argc <= 3 ) { 3459 lprintf(LOG_ERR, "oem iana <record> <format> [<args>]"); 3460 error = 1; 3461 } else { 3462 if (str2uint(argv[3], &suppliedIana) == 0) { 3463 lprintf(LOG_DEBUG, 3464 "using iana: %d", 3465 suppliedIana); 3466 } else { 3467 lprintf(LOG_ERR, 3468 "Given IANA '%s' is invalid.", 3469 argv[3]); 3470 error = 1; 3471 } 3472 } 3473 } 3474 } 3475 3476 if( suppliedIana == iana ) { 3477 lprintf(LOG_DEBUG, "Matching record found" ); 3478 3479 if( iana == IPMI_OEM_PICMG ){ 3480 if( ipmi_fru_picmg_ext_edit(fru_data, 3481 i + sizeof(struct fru_multirec_header), 3482 h->len, h, oh )){ 3483 /* The fru changed */ 3484 write_fru_area(intf,&fru,id, i,i, 3485 h->len+ sizeof(struct fru_multirec_header), fru_data); 3486 } 3487 } 3488 else if( iana == IPMI_OEM_KONTRON ) { 3489 if( ipmi_fru_oemkontron_edit( argc,argv,fru_data, 3490 i + sizeof(struct fru_multirec_header), 3491 h->len, h, oh )){ 3492 /* The fru changed */ 3493 write_fru_area(intf,&fru,id, i,i, 3494 h->len+ sizeof(struct fru_multirec_header), fru_data); 3495 } 3496 } 3497 /* FIXME: Add OEM record support here */ 3498 else{ 3499 printf(" OEM IANA (%s) Record not support in this mode\n", 3500 val2str( iana, ipmi_oem_info)); 3501 error = 1; 3502 } 3503 } 3504 } 3505 i += h->len + sizeof (struct fru_multirec_header); 3506 } while (!(h->format & 0x80) && (error != 1)); 3507 3508 free(fru_data); 3509 fru_data = NULL; 3510 } 3511 return 0; 3512 } 3513 3514 /* ipmi_fru_get_help - print help text for 'fru get' 3515 * 3516 * returns void 3517 */ 3518 void 3519 ipmi_fru_get_help() 3520 { 3521 lprintf(LOG_NOTICE, 3522 "fru get <fruid> oem iana <record> <format> <args> - limited OEM support"); 3523 } /* ipmi_fru_get_help() */ 3524 3525 void 3526 ipmi_fru_internaluse_help() 3527 { 3528 lprintf(LOG_NOTICE, 3529 "fru internaluse <fru id> info - get internal use area size"); 3530 lprintf(LOG_NOTICE, 3531 "fru internaluse <fru id> print - print internal use area in hex"); 3532 lprintf(LOG_NOTICE, 3533 "fru internaluse <fru id> read <fru file> - read internal use area to file"); 3534 lprintf(LOG_NOTICE, 3535 "fru internaluse <fru id> write <fru file> - write internal use area from file"); 3536 } /* void ipmi_fru_internaluse_help() */ 3537 3538 /* ipmi_fru_get_multirec - Query new values to replace original FRU content 3539 * 3540 * @intf: interface to use 3541 * @id: FRU id to work on 3542 * 3543 * returns: nothing 3544 */ 3545 /* Work in progress, copy paste most of the stuff for other functions in this 3546 file ... not elegant yet */ 3547 static int 3548 ipmi_fru_get_multirec(struct ipmi_intf * intf, uint8_t id , 3549 int argc, char ** argv) 3550 { 3551 3552 struct ipmi_rs * rsp; 3553 struct ipmi_rq req; 3554 struct fru_info fru; 3555 struct fru_header header; 3556 uint8_t msg_data[4]; 3557 3558 uint16_t retStatus = 0; 3559 uint32_t offFruMultiRec; 3560 uint32_t fruMultiRecSize = 0; 3561 struct fru_info fruInfo; 3562 retStatus = ipmi_fru_get_multirec_location_from_fru(intf, id, &fruInfo, 3563 &offFruMultiRec, 3564 &fruMultiRecSize); 3565 3566 3567 lprintf(LOG_DEBUG, "FRU Size : %lu\n", fruMultiRecSize); 3568 lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec); 3569 3570 { 3571 3572 3573 memset(&fru, 0, sizeof(struct fru_info)); 3574 memset(&header, 0, sizeof(struct fru_header)); 3575 3576 /* 3577 * get info about this FRU 3578 */ 3579 memset(msg_data, 0, 4); 3580 msg_data[0] = id; 3581 3582 memset(&req, 0, sizeof(req)); 3583 req.msg.netfn = IPMI_NETFN_STORAGE; 3584 req.msg.cmd = GET_FRU_INFO; 3585 req.msg.data = msg_data; 3586 req.msg.data_len = 1; 3587 3588 rsp = intf->sendrecv(intf, &req); 3589 if (rsp == NULL) { 3590 printf(" Device not present (No Response)\n"); 3591 return -1; 3592 } 3593 if (rsp->ccode > 0) { 3594 printf(" Device not present (%s)\n", 3595 val2str(rsp->ccode, completion_code_vals)); 3596 return -1; 3597 } 3598 3599 memset(&fru, 0, sizeof(fru)); 3600 fru.size = (rsp->data[1] << 8) | rsp->data[0]; 3601 fru.access = rsp->data[2] & 0x1; 3602 3603 lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)", 3604 fru.size, fru.access ? "words" : "bytes"); 3605 3606 if (fru.size < 1) { 3607 lprintf(LOG_ERR, " Invalid FRU size %d", fru.size); 3608 return -1; 3609 } 3610 } 3611 3612 { 3613 uint8_t * fru_data; 3614 uint32_t fru_len, i; 3615 uint32_t offset= offFruMultiRec; 3616 struct fru_multirec_header * h; 3617 uint32_t last_off, len; 3618 uint8_t error=0; 3619 3620 i = last_off = offset; 3621 fru_len = 0; 3622 3623 fru_data = malloc(fru.size + 1); 3624 if (fru_data == NULL) { 3625 lprintf(LOG_ERR, " Out of memory!"); 3626 return -1; 3627 } 3628 memset(fru_data, 0, fru.size + 1); 3629 3630 do { 3631 h = (struct fru_multirec_header *) (fru_data + i); 3632 3633 /* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */ 3634 if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len))) 3635 { 3636 len = fru.size - last_off; 3637 if (len > FRU_MULTIREC_CHUNK_SIZE) 3638 len = FRU_MULTIREC_CHUNK_SIZE; 3639 3640 if (read_fru_area(intf, &fru, id, last_off, len, fru_data) < 0) 3641 break; 3642 3643 last_off += len; 3644 } 3645 if( h->type == FRU_RECORD_TYPE_OEM_EXTENSION ){ 3646 3647 struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *) 3648 &fru_data[i + sizeof(struct fru_multirec_header)]; 3649 uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16; 3650 3651 uint32_t suppliedIana = 0 ; 3652 /* Now makes sure this is really PICMG record */ 3653 if( !strncmp( argv[2] , "oem" , 3 )) { 3654 /* Expect IANA number next */ 3655 if( argc <= 3 ) { 3656 lprintf(LOG_ERR, "oem iana <record> <format>"); 3657 error = 1; 3658 } else { 3659 if (str2uint(argv[3], &suppliedIana) == 0) { 3660 lprintf(LOG_DEBUG, 3661 "using iana: %d", 3662 suppliedIana); 3663 } else { 3664 lprintf(LOG_ERR, 3665 "Given IANA '%s' is invalid.", 3666 argv[3]); 3667 error = 1; 3668 } 3669 } 3670 } 3671 3672 if( suppliedIana == iana ) { 3673 lprintf(LOG_DEBUG, "Matching record found" ); 3674 3675 if( iana == IPMI_OEM_KONTRON ) { 3676 ipmi_fru_oemkontron_get( argc,argv,fru_data, 3677 i + sizeof(struct fru_multirec_header), 3678 h->len, h, oh ); 3679 } 3680 /* FIXME: Add OEM record support here */ 3681 else{ 3682 printf(" OEM IANA (%s) Record not supported in this mode\n", 3683 val2str( iana, ipmi_oem_info)); 3684 error = 1; 3685 } 3686 } 3687 } 3688 i += h->len + sizeof (struct fru_multirec_header); 3689 } while (!(h->format & 0x80) && (error != 1)); 3690 3691 free(fru_data); 3692 fru_data = NULL; 3693 } 3694 return 0; 3695 } 3696 3697 static int 3698 ipmi_fru_upg_ekeying(struct ipmi_intf * intf, 3699 char * pFileName, 3700 uint8_t fruId) 3701 { 3702 struct fru_info fruInfo; 3703 uint8_t *buf = NULL; 3704 uint32_t offFruMultiRec = 0; 3705 uint32_t fruMultiRecSize = 0; 3706 uint32_t offFileMultiRec = 0; 3707 uint32_t fileMultiRecSize = 0; 3708 if (pFileName == NULL) { 3709 lprintf(LOG_ERR, "File expected, but none given."); 3710 return (-1); 3711 } 3712 if (ipmi_fru_get_multirec_location_from_fru(intf, fruId, &fruInfo, 3713 &offFruMultiRec, &fruMultiRecSize) != 0) { 3714 lprintf(LOG_ERR, "Failed to get multirec location from FRU."); 3715 return (-1); 3716 } 3717 lprintf(LOG_DEBUG, "FRU Size : %lu\n", fruMultiRecSize); 3718 lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec); 3719 if (ipmi_fru_get_multirec_size_from_file(pFileName, &fileMultiRecSize, 3720 &offFileMultiRec) != 0) { 3721 lprintf(LOG_ERR, "Failed to get multirec size from file '%s'.", pFileName); 3722 return (-1); 3723 } 3724 buf = malloc(fileMultiRecSize); 3725 if (buf == NULL) { 3726 lprintf(LOG_ERR, "ipmitool: malloc failure"); 3727 return (-1); 3728 } 3729 if (ipmi_fru_get_multirec_from_file(pFileName, buf, fileMultiRecSize, 3730 offFileMultiRec) != 0) { 3731 lprintf(LOG_ERR, "Failed to get multirec from file '%s'.", pFileName); 3732 if (buf != NULL) { 3733 free(buf); 3734 buf = NULL; 3735 } 3736 return (-1); 3737 } 3738 if (ipmi_fru_get_adjust_size_from_buffer(buf, &fileMultiRecSize) != 0) { 3739 lprintf(LOG_ERR, "Failed to adjust size from buffer."); 3740 if (buf != NULL) { 3741 free(buf); 3742 buf = NULL; 3743 } 3744 return (-1); 3745 } 3746 if (write_fru_area(intf, &fruInfo, fruId, 0, offFruMultiRec, 3747 fileMultiRecSize, buf) != 0) { 3748 lprintf(LOG_ERR, "Failed to write FRU area."); 3749 if (buf != NULL) { 3750 free(buf); 3751 buf = NULL; 3752 } 3753 return (-1); 3754 } 3755 if (buf != NULL) { 3756 free(buf); 3757 buf = NULL; 3758 } 3759 lprintf(LOG_INFO, "Done upgrading Ekey."); 3760 return 0; 3761 } 3762 3763 /* ipmi_fru_upgekey_help - print help text for 'upgEkey' 3764 * 3765 * returns void 3766 */ 3767 void 3768 ipmi_fru_upgekey_help() 3769 { 3770 lprintf(LOG_NOTICE, "fru upgEkey <fru id> <fru file>"); 3771 lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified."); 3772 lprintf(LOG_NOTICE, "Example: ipmitool fru upgEkey 0 /root/fru.bin"); 3773 } /* ipmi_fru_upgekey_help() */ 3774 3775 static int 3776 ipmi_fru_get_multirec_size_from_file(char * pFileName, 3777 uint32_t * pSize, 3778 uint32_t * pOffset) 3779 { 3780 struct fru_header header; 3781 FILE * pFile; 3782 uint8_t len = 0; 3783 uint32_t end = 0; 3784 *pSize = 0; 3785 3786 pFile = fopen(pFileName,"rb"); 3787 if (pFile) { 3788 rewind(pFile); 3789 len = fread(&header, 1, 8, pFile); 3790 fseek(pFile, 0, SEEK_END); 3791 end = ftell(pFile); 3792 fclose(pFile); 3793 } 3794 3795 lprintf(LOG_DEBUG, "File Size = %lu\n", end); 3796 lprintf(LOG_DEBUG, "Len = %u\n", len); 3797 3798 if (len != 8) { 3799 printf("Error with file %s in getting size\n", pFileName); 3800 return -1; 3801 } 3802 3803 if (header.version != 0x01) { 3804 printf ("Unknown FRU header version %02x.\n", header.version); 3805 return -1; 3806 } 3807 3808 /* Retreive length */ 3809 if (((header.offset.internal * 8) > (header.offset.internal * 8)) && 3810 ((header.offset.internal * 8) < end)) 3811 end = (header.offset.internal * 8); 3812 3813 if (((header.offset.chassis * 8) > (header.offset.chassis * 8)) && 3814 ((header.offset.chassis * 8) < end)) 3815 end = (header.offset.chassis * 8); 3816 3817 if (((header.offset.board * 8) > (header.offset.board * 8)) && 3818 ((header.offset.board * 8) < end)) 3819 end = (header.offset.board * 8); 3820 3821 if (((header.offset.product * 8) > (header.offset.product * 8)) && 3822 ((header.offset.product * 8) < end)) 3823 end = (header.offset.product * 8); 3824 3825 *pSize = end - (header.offset.multi * 8); 3826 *pOffset = (header.offset.multi * 8); 3827 3828 return 0; 3829 } 3830 3831 int 3832 ipmi_fru_get_adjust_size_from_buffer(uint8_t * fru_data, uint32_t *pSize) 3833 { 3834 struct fru_multirec_header * head; 3835 int status = 0; 3836 uint8_t checksum = 0; 3837 uint8_t counter = 0; 3838 uint16_t count = 0; 3839 do { 3840 checksum = 0; 3841 head = (struct fru_multirec_header *) (fru_data + count); 3842 if (verbose) { 3843 printf("Adding ("); 3844 } 3845 for (counter = 0; counter < sizeof(struct fru_multirec_header); counter++) { 3846 if (verbose) { 3847 printf(" %02X", *(fru_data + count + counter)); 3848 } 3849 checksum += *(fru_data + count + counter); 3850 } 3851 if (verbose) { 3852 printf(")"); 3853 } 3854 if (checksum != 0) { 3855 lprintf(LOG_ERR, "Bad checksum in Multi Records"); 3856 status = (-1); 3857 if (verbose) { 3858 printf("--> FAIL"); 3859 } 3860 } else if (verbose) { 3861 printf("--> OK"); 3862 } 3863 if (verbose > 1 && checksum == 0) { 3864 for (counter = 0; counter < head->len; counter++) { 3865 printf(" %02X", *(fru_data + count + counter 3866 + sizeof(struct fru_multirec_header))); 3867 } 3868 } 3869 if (verbose) { 3870 printf("\n"); 3871 } 3872 count += head->len + sizeof (struct fru_multirec_header); 3873 } while ((!(head->format & 0x80)) && (status == 0)); 3874 3875 *pSize = count; 3876 lprintf(LOG_DEBUG, "Size of multirec: %lu\n", *pSize); 3877 return status; 3878 } 3879 3880 static int 3881 ipmi_fru_get_multirec_from_file(char * pFileName, uint8_t * pBufArea, 3882 uint32_t size, uint32_t offset) 3883 { 3884 FILE * pFile; 3885 uint32_t len = 0; 3886 if (pFileName == NULL) { 3887 lprintf(LOG_ERR, "Invalid file name given."); 3888 return (-1); 3889 } 3890 3891 errno = 0; 3892 pFile = fopen(pFileName, "rb"); 3893 if (!pFile) { 3894 lprintf(LOG_ERR, "Error opening file '%s': %i -> %s.", pFileName, errno, 3895 strerror(errno)); 3896 return (-1); 3897 } 3898 errno = 0; 3899 if (fseek(pFile, offset, SEEK_SET) != 0) { 3900 lprintf(LOG_ERR, "Failed to seek in file '%s': %i -> %s.", pFileName, errno, 3901 strerror(errno)); 3902 fclose(pFile); 3903 return (-1); 3904 } 3905 len = fread(pBufArea, size, 1, pFile); 3906 fclose(pFile); 3907 3908 if (len != 1) { 3909 lprintf(LOG_ERR, "Error in file '%s'.", pFileName); 3910 return (-1); 3911 } 3912 return 0; 3913 } 3914 3915 static int 3916 ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf, 3917 uint8_t fruId, 3918 struct fru_info *pFruInfo, 3919 uint32_t * pRetLocation, 3920 uint32_t * pRetSize) 3921 { 3922 struct ipmi_rs * rsp; 3923 struct ipmi_rq req; 3924 uint8_t msg_data[4]; 3925 uint32_t end; 3926 struct fru_header header; 3927 3928 *pRetLocation = 0; 3929 3930 msg_data[0] = fruId; 3931 3932 memset(&req, 0, sizeof(req)); 3933 req.msg.netfn = IPMI_NETFN_STORAGE; 3934 req.msg.cmd = GET_FRU_INFO; 3935 req.msg.data = msg_data; 3936 req.msg.data_len = 1; 3937 3938 rsp = intf->sendrecv(intf, &req); 3939 if (!rsp) { 3940 if (verbose > 1) 3941 printf("no response\n"); 3942 return -1; 3943 } 3944 3945 if (rsp->ccode > 0) { 3946 if (rsp->ccode == 0xc3) 3947 printf (" Timeout accessing FRU info. (Device not present?)\n"); 3948 else 3949 printf (" CCODE = 0x%02x\n", rsp->ccode); 3950 return -1; 3951 } 3952 pFruInfo->size = (rsp->data[1] << 8) | rsp->data[0]; 3953 pFruInfo->access = rsp->data[2] & 0x1; 3954 3955 if (verbose > 1) 3956 printf("pFruInfo->size = %d bytes (accessed by %s)\n", 3957 pFruInfo->size, pFruInfo->access ? "words" : "bytes"); 3958 3959 if (!pFruInfo->size) 3960 return -1; 3961 3962 msg_data[0] = fruId; 3963 msg_data[1] = 0; 3964 msg_data[2] = 0; 3965 msg_data[3] = 8; 3966 3967 memset(&req, 0, sizeof(req)); 3968 req.msg.netfn = IPMI_NETFN_STORAGE; 3969 req.msg.cmd = GET_FRU_DATA; 3970 req.msg.data = msg_data; 3971 req.msg.data_len = 4; 3972 3973 rsp = intf->sendrecv(intf, &req); 3974 3975 if (!rsp) 3976 return -1; 3977 if (rsp->ccode > 0) { 3978 if (rsp->ccode == 0xc3) 3979 printf (" Timeout while reading FRU data. (Device not present?)\n"); 3980 return -1; 3981 } 3982 3983 if (verbose > 1) 3984 printbuf(rsp->data, rsp->data_len, "FRU DATA"); 3985 3986 memcpy(&header, rsp->data + 1, 8); 3987 3988 if (header.version != 0x01) { 3989 printf (" Unknown FRU header version %02x.\n", header.version); 3990 return -1; 3991 } 3992 3993 end = pFruInfo->size; 3994 3995 /* Retreive length */ 3996 if (((header.offset.internal * 8) > (header.offset.internal * 8)) && 3997 ((header.offset.internal * 8) < end)) 3998 end = (header.offset.internal * 8); 3999 4000 if (((header.offset.chassis * 8) > (header.offset.chassis * 8)) && 4001 ((header.offset.chassis * 8) < end)) 4002 end = (header.offset.chassis * 8); 4003 4004 if (((header.offset.board * 8) > (header.offset.board * 8)) && 4005 ((header.offset.board * 8) < end)) 4006 end = (header.offset.board * 8); 4007 4008 if (((header.offset.product * 8) > (header.offset.product * 8)) && 4009 ((header.offset.product * 8) < end)) 4010 end = (header.offset.product * 8); 4011 4012 *pRetSize = end; 4013 *pRetLocation = 8 * header.offset.multi; 4014 4015 return 0; 4016 } 4017 4018 /* ipmi_fru_get_internal_use_offset - Retreive internal use offset 4019 * 4020 * @intf: ipmi interface 4021 * @id: fru id 4022 * 4023 * returns -1 on error 4024 * returns 0 if successful 4025 * returns 1 if device not present 4026 */ 4027 static int 4028 ipmi_fru_get_internal_use_info( struct ipmi_intf * intf, 4029 uint8_t id, 4030 struct fru_info * fru, 4031 uint16_t * size, 4032 uint16_t * offset) 4033 { 4034 struct ipmi_rs * rsp; 4035 struct ipmi_rq req; 4036 struct fru_header header; 4037 uint8_t msg_data[4]; 4038 4039 // Init output value 4040 * offset = 0; 4041 * size = 0; 4042 4043 memset(fru, 0, sizeof(struct fru_info)); 4044 memset(&header, 0, sizeof(struct fru_header)); 4045 4046 /* 4047 * get info about this FRU 4048 */ 4049 memset(msg_data, 0, 4); 4050 msg_data[0] = id; 4051 4052 memset(&req, 0, sizeof(req)); 4053 req.msg.netfn = IPMI_NETFN_STORAGE; 4054 req.msg.cmd = GET_FRU_INFO; 4055 req.msg.data = msg_data; 4056 req.msg.data_len = 1; 4057 4058 rsp = intf->sendrecv(intf, &req); 4059 if (rsp == NULL) { 4060 printf(" Device not present (No Response)\n"); 4061 return -1; 4062 } 4063 if (rsp->ccode > 0) { 4064 printf(" Device not present (%s)\n", 4065 val2str(rsp->ccode, completion_code_vals)); 4066 return -1; 4067 } 4068 4069 memset(&fru, 0, sizeof(fru)); 4070 fru->size = (rsp->data[1] << 8) | rsp->data[0]; 4071 fru->access = rsp->data[2] & 0x1; 4072 4073 lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)", 4074 fru->size, fru->access ? "words" : "bytes"); 4075 4076 if (fru->size < 1) { 4077 lprintf(LOG_ERR, " Invalid FRU size %d", fru->size); 4078 return -1; 4079 } 4080 4081 /* 4082 * retrieve the FRU header 4083 */ 4084 msg_data[0] = id; 4085 msg_data[1] = 0; 4086 msg_data[2] = 0; 4087 msg_data[3] = 8; 4088 4089 memset(&req, 0, sizeof(req)); 4090 req.msg.netfn = IPMI_NETFN_STORAGE; 4091 req.msg.cmd = GET_FRU_DATA; 4092 req.msg.data = msg_data; 4093 req.msg.data_len = 4; 4094 4095 rsp = intf->sendrecv(intf, &req); 4096 if (rsp == NULL) { 4097 printf(" Device not present (No Response)\n"); 4098 return 1; 4099 } 4100 if (rsp->ccode > 0) { 4101 printf(" Device not present (%s)\n", 4102 val2str(rsp->ccode, completion_code_vals)); 4103 return 1; 4104 } 4105 4106 if (verbose > 1) 4107 printbuf(rsp->data, rsp->data_len, "FRU DATA"); 4108 4109 memcpy(&header, rsp->data + 1, 8); 4110 4111 if (header.version != 1) { 4112 lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", 4113 header.version); 4114 return -1; 4115 } 4116 4117 lprintf(LOG_DEBUG, "fru.header.version: 0x%x", 4118 header.version); 4119 lprintf(LOG_DEBUG, "fru.header.offset.internal: 0x%x", 4120 header.offset.internal * 8); 4121 lprintf(LOG_DEBUG, "fru.header.offset.chassis: 0x%x", 4122 header.offset.chassis * 8); 4123 lprintf(LOG_DEBUG, "fru.header.offset.board: 0x%x", 4124 header.offset.board * 8); 4125 lprintf(LOG_DEBUG, "fru.header.offset.product: 0x%x", 4126 header.offset.product * 8); 4127 lprintf(LOG_DEBUG, "fru.header.offset.multi: 0x%x", 4128 header.offset.multi * 8); 4129 4130 if((header.offset.internal*8) == 0) 4131 { 4132 * size = 0; 4133 * offset = 0; 4134 } 4135 else 4136 { 4137 (* offset) = (header.offset.internal*8); 4138 4139 if(header.offset.chassis != 0) 4140 { 4141 (* size) = ((header.offset.chassis*8)-(* offset)); 4142 } 4143 else if(header.offset.board != 0) 4144 { 4145 (* size) = ((header.offset.board*8)-(* offset)); 4146 } 4147 else if(header.offset.product != 0) 4148 { 4149 (* size) = ((header.offset.product*8)-(* offset)); 4150 } 4151 else if(header.offset.multi != 0) 4152 { 4153 (* size) = ((header.offset.multi*8)-(* offset)); 4154 } 4155 else 4156 { 4157 (* size) = (fru->size - (* offset)); 4158 } 4159 } 4160 return 0; 4161 } 4162 4163 /* ipmi_fru_info_internal_use - print internal use info 4164 * 4165 * @intf: ipmi interface 4166 * @id: fru id 4167 * 4168 * returns -1 on error 4169 * returns 0 if successful 4170 * returns 1 if device not present 4171 */ 4172 static int 4173 ipmi_fru_info_internal_use(struct ipmi_intf * intf, uint8_t id) 4174 { 4175 struct fru_info fru; 4176 uint16_t size; 4177 uint16_t offset; 4178 int rc = 0; 4179 4180 rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset); 4181 4182 if(rc == 0) 4183 { 4184 lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset); 4185 printf( "Internal Use Area Size : %i\n", size); 4186 } 4187 else 4188 { 4189 lprintf(LOG_ERR, "Cannot access internal use area"); 4190 return -1; 4191 } 4192 return 0; 4193 } 4194 4195 /* ipmi_fru_help - print help text for FRU subcommand 4196 * 4197 * returns void 4198 */ 4199 void 4200 ipmi_fru_help() 4201 { 4202 lprintf(LOG_NOTICE, 4203 "FRU Commands: print read write upgEkey edit internaluse get"); 4204 } /* ipmi_fru_help() */ 4205 4206 /* ipmi_fru_read_internal_use - print internal use are in hex or file 4207 * 4208 * @intf: ipmi interface 4209 * @id: fru id 4210 * 4211 * returns -1 on error 4212 * returns 0 if successful 4213 * returns 1 if device not present 4214 */ 4215 static int 4216 ipmi_fru_read_internal_use(struct ipmi_intf * intf, uint8_t id, char * pFileName) 4217 { 4218 struct fru_info fru; 4219 uint16_t size; 4220 uint16_t offset; 4221 int rc = 0; 4222 4223 rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset); 4224 4225 if(rc == 0) 4226 { 4227 uint8_t * frubuf; 4228 4229 lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset); 4230 printf( "Internal Use Area Size : %i\n", size); 4231 4232 frubuf = malloc( size ); 4233 if(frubuf) 4234 { 4235 rc = read_fru_area_section(intf, &fru, id, offset, size, frubuf); 4236 4237 if(rc == 0) 4238 { 4239 if(pFileName == NULL) 4240 { 4241 uint16_t counter; 4242 for(counter = 0; counter < size; counter ++) 4243 { 4244 if((counter % 16) == 0) 4245 printf("\n%02i- ", (counter / 16)); 4246 printf("%02X ", frubuf[counter]); 4247 } 4248 } 4249 else 4250 { 4251 FILE * pFile; 4252 pFile = fopen(pFileName,"wb"); 4253 if (pFile) 4254 { 4255 fwrite(frubuf, size, 1, pFile); 4256 printf("Done\n"); 4257 } 4258 else 4259 { 4260 lprintf(LOG_ERR, "Error opening file %s\n", pFileName); 4261 free(frubuf); 4262 frubuf = NULL; 4263 return -1; 4264 } 4265 fclose(pFile); 4266 } 4267 } 4268 printf("\n"); 4269 4270 free(frubuf); 4271 frubuf = NULL; 4272 } 4273 4274 } 4275 else 4276 { 4277 lprintf(LOG_ERR, "Cannot access internal use area"); 4278 } 4279 return 0; 4280 } 4281 4282 /* ipmi_fru_write_internal_use - print internal use are in hex or file 4283 * 4284 * @intf: ipmi interface 4285 * @id: fru id 4286 * 4287 * returns -1 on error 4288 * returns 0 if successful 4289 * returns 1 if device not present 4290 */ 4291 static int 4292 ipmi_fru_write_internal_use(struct ipmi_intf * intf, uint8_t id, char * pFileName) 4293 { 4294 struct fru_info fru; 4295 uint16_t size; 4296 uint16_t offset; 4297 int rc = 0; 4298 4299 rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset); 4300 4301 if(rc == 0) 4302 { 4303 uint8_t * frubuf; 4304 FILE * fp; 4305 uint32_t fileLength = 0; 4306 4307 lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset); 4308 printf( "Internal Use Area Size : %i\n", size); 4309 4310 fp = fopen(pFileName, "r"); 4311 4312 if(fp) 4313 { 4314 /* Retreive file length, check if it's fits the Eeprom Size */ 4315 fseek(fp, 0 ,SEEK_END); 4316 fileLength = ftell(fp); 4317 4318 lprintf(LOG_ERR, "File Size: %i", fileLength); 4319 lprintf(LOG_ERR, "Area Size: %i", size); 4320 if(fileLength != size) 4321 { 4322 lprintf(LOG_ERR, "File size does not fit Eeprom Size"); 4323 fclose(fp); 4324 fp = NULL; 4325 } 4326 else 4327 { 4328 fseek(fp, 0 ,SEEK_SET); 4329 } 4330 } 4331 4332 if(fp) 4333 { 4334 frubuf = malloc( size ); 4335 if(frubuf) 4336 { 4337 uint16_t fru_read_size; 4338 fru_read_size = fread(frubuf, 1, size, fp); 4339 4340 if(fru_read_size == size) 4341 { 4342 rc = write_fru_area(intf, &fru, id, 0, offset, size, frubuf); 4343 4344 if(rc == 0) 4345 { 4346 lprintf(LOG_INFO, "Done\n"); 4347 } 4348 } 4349 else 4350 { 4351 lprintf(LOG_ERR, "Unable to read file: %i\n", fru_read_size); 4352 } 4353 4354 free(frubuf); 4355 frubuf = NULL; 4356 } 4357 fclose(fp); 4358 fp = NULL; 4359 } 4360 } 4361 else 4362 { 4363 lprintf(LOG_ERR, "Cannot access internal use area"); 4364 } 4365 return 0; 4366 } 4367 4368 int 4369 ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv) 4370 { 4371 int rc = 0; 4372 uint8_t fru_id = 0; 4373 4374 if (argc < 1) { 4375 rc = ipmi_fru_print_all(intf); 4376 } 4377 else if (strncmp(argv[0], "help", 4) == 0) { 4378 ipmi_fru_help(); 4379 return 0; 4380 } 4381 else if (strncmp(argv[0], "print", 5) == 0 || 4382 strncmp(argv[0], "list", 4) == 0) { 4383 if (argc > 1) { 4384 if (strcmp(argv[1], "help") == 0) { 4385 lprintf(LOG_NOTICE, "fru print [fru id] - print information about FRU(s)"); 4386 return 0; 4387 } 4388 4389 if (is_fru_id(argv[1], &fru_id) != 0) 4390 return (-1); 4391 4392 rc = __ipmi_fru_print(intf, fru_id); 4393 } else { 4394 rc = ipmi_fru_print_all(intf); 4395 } 4396 } 4397 else if (!strncmp(argv[0], "read", 5)) { 4398 if (argc > 1 && strcmp(argv[1], "help") == 0) { 4399 ipmi_fru_read_help(); 4400 return 0; 4401 } else if (argc < 3) { 4402 lprintf(LOG_ERR, "Not enough parameters given."); 4403 ipmi_fru_read_help(); 4404 return (-1); 4405 } 4406 4407 if (is_fru_id(argv[1], &fru_id) != 0) 4408 return (-1); 4409 4410 /* There is a file name in the parameters */ 4411 if (is_valid_filename(argv[2]) != 0) 4412 return (-1); 4413 4414 if (verbose) { 4415 printf("FRU ID : %d\n", fru_id); 4416 printf("FRU File : %s\n", argv[2]); 4417 } 4418 /* TODO - rc is missing */ 4419 ipmi_fru_read_to_bin(intf, argv[2], fru_id); 4420 } 4421 else if (!strncmp(argv[0], "write", 5)) { 4422 if (argc > 1 && strcmp(argv[1], "help") == 0) { 4423 ipmi_fru_write_help(); 4424 return 0; 4425 } else if (argc < 3) { 4426 lprintf(LOG_ERR, "Not enough parameters given."); 4427 ipmi_fru_write_help(); 4428 return (-1); 4429 } 4430 4431 if (is_fru_id(argv[1], &fru_id) != 0) 4432 return (-1); 4433 4434 /* There is a file name in the parameters */ 4435 if (is_valid_filename(argv[2]) != 0) 4436 return (-1); 4437 4438 if (verbose) { 4439 printf("FRU ID : %d\n", fru_id); 4440 printf("FRU File : %s\n", argv[2]); 4441 } 4442 /* TODO - rc is missing */ 4443 ipmi_fru_write_from_bin(intf, argv[2], fru_id); 4444 } 4445 else if (!strncmp(argv[0], "upgEkey", 7)) { 4446 if (argc > 1 && strcmp(argv[1], "help") == 0) { 4447 ipmi_fru_upgekey_help(); 4448 return 0; 4449 } else if (argc < 3) { 4450 lprintf(LOG_ERR, "Not enough parameters given."); 4451 ipmi_fru_upgekey_help(); 4452 return (-1); 4453 } 4454 4455 if (is_fru_id(argv[1], &fru_id) != 0) 4456 return (-1); 4457 4458 /* There is a file name in the parameters */ 4459 if (is_valid_filename(argv[2]) != 0) 4460 return (-1); 4461 4462 rc = ipmi_fru_upg_ekeying(intf, argv[2], fru_id); 4463 } 4464 else if (!strncmp(argv[0], "internaluse", 11)) { 4465 if (argc > 1 && strcmp(argv[1], "help") == 0) { 4466 ipmi_fru_internaluse_help(); 4467 return 0; 4468 } 4469 4470 if ( (argc >= 3) && (!strncmp(argv[2], "info", 4)) ) { 4471 4472 if (is_fru_id(argv[1], &fru_id) != 0) 4473 return (-1); 4474 4475 rc = ipmi_fru_info_internal_use(intf, fru_id); 4476 } 4477 else if ( (argc >= 3) && (!strncmp(argv[2], "print", 5)) ) { 4478 4479 if (is_fru_id(argv[1], &fru_id) != 0) 4480 return (-1); 4481 4482 rc = ipmi_fru_read_internal_use(intf, fru_id, NULL); 4483 } 4484 else if ( (argc >= 4) && (!strncmp(argv[2], "read", 4)) ) { 4485 4486 if (is_fru_id(argv[1], &fru_id) != 0) 4487 return (-1); 4488 4489 /* There is a file name in the parameters */ 4490 if (is_valid_filename(argv[3]) != 0) 4491 return (-1); 4492 4493 lprintf(LOG_DEBUG, "FRU ID : %d", fru_id); 4494 lprintf(LOG_DEBUG, "FRU File : %s", argv[3]); 4495 4496 rc = ipmi_fru_read_internal_use(intf, fru_id, argv[3]); 4497 } 4498 else if ( (argc >= 4) && (!strncmp(argv[2], "write", 5)) ) { 4499 4500 if (is_fru_id(argv[1], &fru_id) != 0) 4501 return (-1); 4502 4503 /* There is a file name in the parameters */ 4504 if (is_valid_filename(argv[3]) != 0) 4505 return (-1); 4506 4507 lprintf(LOG_DEBUG, "FRU ID : %d", fru_id); 4508 lprintf(LOG_DEBUG, "FRU File : %s", argv[3]); 4509 4510 rc = ipmi_fru_write_internal_use(intf, fru_id, argv[3]); 4511 } else { 4512 lprintf(LOG_ERR, 4513 "Either unknown command or not enough parameters given."); 4514 ipmi_fru_internaluse_help(); 4515 return (-1); 4516 } 4517 } 4518 else if (!strncmp(argv[0], "edit", 4)) { 4519 if (argc > 1 && strcmp(argv[1], "help") == 0) { 4520 ipmi_fru_edit_help(); 4521 return 0; 4522 } else if (argc < 2) { 4523 lprintf(LOG_ERR, "Not enough parameters given."); 4524 ipmi_fru_edit_help(); 4525 return (-1); 4526 } 4527 4528 if (argc >= 2) { 4529 if (is_fru_id(argv[1], &fru_id) != 0) 4530 return (-1); 4531 4532 if (verbose) { 4533 printf("FRU ID : %d\n", fru_id); 4534 } 4535 } else { 4536 printf("Using default FRU ID: %d\n", fru_id); 4537 } 4538 4539 if (argc >= 3) { 4540 if (!strncmp(argv[2], "field", 5)) { 4541 if (argc != 6) { 4542 lprintf(LOG_ERR, "Not enough parameters given."); 4543 ipmi_fru_edit_help(); 4544 return (-1); 4545 } 4546 rc = ipmi_fru_set_field_string(intf, fru_id, *argv[3], *argv[4], 4547 (char *) argv[5]); 4548 } else if (!strncmp(argv[2], "oem", 3)) { 4549 rc = ipmi_fru_edit_multirec(intf, fru_id, argc, argv); 4550 } else { 4551 lprintf(LOG_ERR, "Invalid command: %s", argv[2]); 4552 ipmi_fru_edit_help(); 4553 return (-1); 4554 } 4555 } else { 4556 rc = ipmi_fru_edit_multirec(intf, fru_id, argc, argv); 4557 } 4558 } 4559 else if (!strncmp(argv[0], "get", 4)) { 4560 if (argc > 1 && (strncmp(argv[1], "help", 4) == 0)) { 4561 ipmi_fru_get_help(); 4562 return 0; 4563 } else if (argc < 2) { 4564 lprintf(LOG_ERR, "Not enough parameters given."); 4565 ipmi_fru_get_help(); 4566 return (-1); 4567 } 4568 4569 if (argc >= 2) { 4570 if (is_fru_id(argv[1], &fru_id) != 0) 4571 return (-1); 4572 4573 if (verbose) { 4574 printf("FRU ID : %d\n", fru_id); 4575 } 4576 } else { 4577 printf("Using default FRU ID: %d\n", fru_id); 4578 } 4579 4580 if (argc >= 3) { 4581 if (!strncmp(argv[2], "oem", 3)) { 4582 rc = ipmi_fru_get_multirec(intf, fru_id, argc, argv); 4583 } else { 4584 lprintf(LOG_ERR, "Invalid command: %s", argv[2]); 4585 ipmi_fru_get_help(); 4586 return (-1); 4587 } 4588 } else { 4589 rc = ipmi_fru_get_multirec(intf, fru_id, argc, argv); 4590 } 4591 } 4592 else { 4593 lprintf(LOG_ERR, "Invalid FRU command: %s", argv[0]); 4594 ipmi_fru_help(); 4595 return (-1); 4596 } 4597 4598 return rc; 4599 } 4600 4601 /* ipmi_fru_set_field_string - Set a field string to a new value, Need to be the same size. If 4602 * size if not equal, the function ipmi_fru_set_field_string_rebuild 4603 * will be called. 4604 * 4605 * @intf: ipmi interface 4606 * @id: fru id 4607 * @f_type: Type of the Field : c=Chassis b=Board p=Product 4608 * @f_index: findex of the field, zero indexed. 4609 * @f_string: NULL terminated string 4610 * 4611 * returns -1 on error 4612 * returns 1 if successful 4613 */ 4614 static int 4615 ipmi_fru_set_field_string(struct ipmi_intf * intf, uint8_t fruId, uint8_t 4616 f_type, uint8_t f_index, char *f_string) 4617 { 4618 struct ipmi_rs *rsp; 4619 struct ipmi_rq req; 4620 4621 struct fru_info fru; 4622 struct fru_header header; 4623 uint8_t msg_data[4]; 4624 uint8_t checksum; 4625 int i = 0; 4626 int rc = 1; 4627 uint8_t *fru_data = NULL; 4628 uint8_t *fru_area = NULL; 4629 uint32_t fru_field_offset, fru_field_offset_tmp; 4630 uint32_t fru_section_len, header_offset; 4631 4632 memset(msg_data, 0, 4); 4633 msg_data[0] = fruId; 4634 4635 memset(&req, 0, sizeof(req)); 4636 req.msg.netfn = IPMI_NETFN_STORAGE; 4637 req.msg.cmd = GET_FRU_INFO; 4638 req.msg.data = msg_data; 4639 req.msg.data_len = 1; 4640 4641 rsp = intf->sendrecv(intf, &req); 4642 if (rsp == NULL) { 4643 printf(" Device not present (No Response)\n"); 4644 rc = (-1); 4645 goto ipmi_fru_set_field_string_out; 4646 } 4647 if (rsp->ccode > 0) { 4648 printf(" Device not present (%s)\n", 4649 val2str(rsp->ccode, completion_code_vals)); 4650 rc = (-1); 4651 goto ipmi_fru_set_field_string_out; 4652 } 4653 4654 memset(&fru, 0, sizeof(fru)); 4655 fru.size = (rsp->data[1] << 8) | rsp->data[0]; 4656 fru.access = rsp->data[2] & 0x1; 4657 4658 if (fru.size < 1) { 4659 printf(" Invalid FRU size %d", fru.size); 4660 rc = (-1); 4661 goto ipmi_fru_set_field_string_out; 4662 } 4663 /* 4664 * retrieve the FRU header 4665 */ 4666 msg_data[0] = fruId; 4667 msg_data[1] = 0; 4668 msg_data[2] = 0; 4669 msg_data[3] = 8; 4670 4671 memset(&req, 0, sizeof(req)); 4672 req.msg.netfn = IPMI_NETFN_STORAGE; 4673 req.msg.cmd = GET_FRU_DATA; 4674 req.msg.data = msg_data; 4675 req.msg.data_len = 4; 4676 4677 rsp = intf->sendrecv(intf, &req); 4678 if (rsp == NULL) 4679 { 4680 printf(" Device not present (No Response)\n"); 4681 rc = (-1); 4682 goto ipmi_fru_set_field_string_out; 4683 } 4684 if (rsp->ccode > 0) 4685 { 4686 printf(" Device not present (%s)\n", 4687 val2str(rsp->ccode, completion_code_vals)); 4688 rc = (-1); 4689 goto ipmi_fru_set_field_string_out; 4690 } 4691 4692 if (verbose > 1) 4693 printbuf(rsp->data, rsp->data_len, "FRU DATA"); 4694 4695 memcpy(&header, rsp->data + 1, 8); 4696 4697 if (header.version != 1) 4698 { 4699 printf(" Unknown FRU header version 0x%02x", 4700 header.version); 4701 rc = (-1); 4702 goto ipmi_fru_set_field_string_out; 4703 } 4704 4705 fru_data = malloc( fru.size ); 4706 4707 if( fru_data == NULL ) 4708 { 4709 printf("Out of memory!\n"); 4710 rc = (-1); 4711 goto ipmi_fru_set_field_string_out; 4712 } 4713 4714 /* Setup offset from the field type */ 4715 4716 /* Chassis type field */ 4717 if (f_type == 'c' ) { 4718 header_offset = (header.offset.chassis * 8); 4719 read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data); 4720 fru_field_offset = 3; 4721 fru_section_len = *(fru_data + 1) * 8; 4722 } 4723 /* Board type field */ 4724 else if (f_type == 'b' ) { 4725 header_offset = (header.offset.board * 8); 4726 read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data); 4727 fru_field_offset = 6; 4728 fru_section_len = *(fru_data + 1) * 8; 4729 } 4730 /* Product type field */ 4731 else if (f_type == 'p' ) { 4732 header_offset = (header.offset.product * 8); 4733 read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data); 4734 fru_field_offset = 3; 4735 fru_section_len = *(fru_data + 1) * 8; 4736 } 4737 else 4738 { 4739 printf("Wrong field type."); 4740 rc = (-1); 4741 goto ipmi_fru_set_field_string_out; 4742 } 4743 memset(fru_data, 0, fru.size); 4744 if( read_fru_area(intf ,&fru, fruId, header_offset , 4745 fru_section_len , fru_data) < 0 ) 4746 { 4747 rc = (-1); 4748 goto ipmi_fru_set_field_string_out; 4749 } 4750 /* Convert index from character to decimal */ 4751 f_index= f_index - 0x30; 4752 4753 /*Seek to field index */ 4754 for (i=0; i <= f_index; i++) { 4755 fru_field_offset_tmp = fru_field_offset; 4756 if (fru_area != NULL) { 4757 free(fru_area); 4758 fru_area = NULL; 4759 } 4760 fru_area = (uint8_t *) get_fru_area_str(fru_data, &fru_field_offset); 4761 } 4762 4763 if( (fru_area == NULL ) || strlen((const char *)fru_area) == 0 ) { 4764 printf("Field not found !\n"); 4765 rc = (-1); 4766 goto ipmi_fru_set_field_string_out; 4767 } 4768 4769 if ( strlen((const char *)fru_area) == strlen((const char *)f_string) ) 4770 { 4771 printf("Updating Field '%s' with '%s' ...\n", fru_area, f_string ); 4772 memcpy(fru_data + fru_field_offset_tmp + 1, 4773 f_string, strlen(f_string)); 4774 4775 checksum = 0; 4776 /* Calculate Header Checksum */ 4777 for( i = header_offset; i < header_offset 4778 + fru_section_len - 1; i ++ ) 4779 { 4780 checksum += fru_data[i]; 4781 } 4782 checksum = (~checksum) + 1; 4783 fru_data[header_offset + fru_section_len - 1] = checksum; 4784 4785 /* Write the updated section to the FRU data; source offset => 0 */ 4786 if( write_fru_area(intf, &fru, fruId, 0, 4787 header_offset, fru_section_len, fru_data) < 0 ) 4788 { 4789 printf("Write to FRU data failed.\n"); 4790 rc = (-1); 4791 goto ipmi_fru_set_field_string_out; 4792 } 4793 } 4794 else { 4795 printf("String size are not equal, resizing fru to fit new string\n"); 4796 if( 4797 ipmi_fru_set_field_string_rebuild(intf,fruId,fru,header,f_type,f_index,f_string) 4798 ) 4799 { 4800 rc = (-1); 4801 goto ipmi_fru_set_field_string_out; 4802 } 4803 } 4804 4805 ipmi_fru_set_field_string_out: 4806 if (fru_data != NULL) { 4807 free(fru_data); 4808 fru_data = NULL; 4809 } 4810 if (fru_area != NULL) { 4811 free(fru_area); 4812 fru_area = NULL; 4813 } 4814 4815 return rc; 4816 } 4817 4818 /* 4819 This function can update a string within of the following section when the size is not equal: 4820 4821 Chassis 4822 Product 4823 Board 4824 */ 4825 /* ipmi_fru_set_field_string_rebuild - Set a field string to a new value, When size are not 4826 * the same size. 4827 * 4828 * This function can update a string within of the following section when the size is not equal: 4829 * 4830 * - Chassis 4831 * - Product 4832 * - Board 4833 * 4834 * @intf: ipmi interface 4835 * @fruId: fru id 4836 * @fru: info about fru 4837 * @header: contain the header of the FRU 4838 * @f_type: Type of the Field : c=Chassis b=Board p=Product 4839 * @f_index: findex of the field, zero indexed. 4840 * @f_string: NULL terminated string 4841 * 4842 * returns -1 on error 4843 * returns 1 if successful 4844 */ 4845 4846 #define DBG_RESIZE_FRU 4847 static int 4848 ipmi_fru_set_field_string_rebuild(struct ipmi_intf * intf, uint8_t fruId, 4849 struct fru_info fru, struct fru_header header, 4850 uint8_t f_type, uint8_t f_index, char *f_string) 4851 { 4852 uint8_t msg_data[4]; 4853 uint8_t checksum; 4854 int i = 0; 4855 uint8_t *fru_data_old = NULL; 4856 uint8_t *fru_data_new = NULL; 4857 uint8_t *fru_area = NULL; 4858 uint32_t fru_field_offset, fru_field_offset_tmp; 4859 uint32_t fru_section_len, old_section_len, header_offset; 4860 uint32_t chassis_offset, board_offset, product_offset; 4861 uint32_t chassis_len, board_len, product_len, product_len_new; 4862 int num_byte_change = 0, padding_len = 0; 4863 uint32_t counter; 4864 unsigned char cksum; 4865 int rc = 1; 4866 4867 fru_data_old = calloc( fru.size, sizeof(uint8_t) ); 4868 4869 fru_data_new = malloc( fru.size ); 4870 4871 if( fru_data_old == NULL || fru_data_new == NULL ) 4872 { 4873 printf("Out of memory!\n"); 4874 rc = (-1); 4875 goto ipmi_fru_set_field_string_rebuild_out; 4876 } 4877 4878 /************************* 4879 1) Read ALL FRU */ 4880 printf("Read All FRU area\n"); 4881 printf("Fru Size : %u bytes\n", fru.size); 4882 4883 /* Read current fru data */ 4884 read_fru_area(intf ,&fru, fruId, 0, fru.size , fru_data_old); 4885 4886 #ifdef DBG_RESIZE_FRU 4887 printf("Copy to new FRU\n"); 4888 #endif 4889 4890 /************************* 4891 2) Copy all FRU to new FRU */ 4892 memcpy(fru_data_new, fru_data_old, fru.size); 4893 4894 /* Build location of all modifiable components */ 4895 chassis_offset = (header.offset.chassis * 8); 4896 board_offset = (header.offset.board * 8); 4897 product_offset = (header.offset.product * 8); 4898 4899 /* Retrieve length of all modifiable components */ 4900 chassis_len = *(fru_data_old + chassis_offset + 1) * 8; 4901 board_len = *(fru_data_old + board_offset + 1) * 8; 4902 product_len = *(fru_data_old + product_offset + 1) * 8; 4903 product_len_new = product_len; 4904 4905 /* Chassis type field */ 4906 if (f_type == 'c' ) 4907 { 4908 header_offset = chassis_offset; 4909 fru_field_offset = chassis_offset + 3; 4910 fru_section_len = chassis_len; 4911 } 4912 /* Board type field */ 4913 else if (f_type == 'b' ) 4914 { 4915 header_offset = board_offset; 4916 fru_field_offset = board_offset + 6; 4917 fru_section_len = board_len; 4918 } 4919 /* Product type field */ 4920 else if (f_type == 'p' ) 4921 { 4922 header_offset = product_offset; 4923 fru_field_offset = product_offset + 3; 4924 fru_section_len = product_len; 4925 } 4926 else 4927 { 4928 printf("Wrong field type."); 4929 rc = (-1); 4930 goto ipmi_fru_set_field_string_rebuild_out; 4931 } 4932 4933 /* Keep length for future old section display */ 4934 old_section_len = fru_section_len; 4935 4936 /************************* 4937 3) Seek to field index */ 4938 for (i = 0;i <= f_index; i++) { 4939 fru_field_offset_tmp = fru_field_offset; 4940 if (fru_area != NULL) { 4941 free(fru_area); 4942 fru_area = NULL; 4943 } 4944 fru_area = (uint8_t *) get_fru_area_str(fru_data_old, &fru_field_offset); 4945 } 4946 4947 if( (fru_area == NULL ) || strlen((const char *)fru_area) == 0 ) { 4948 printf("Field not found (1)!\n"); 4949 rc = (-1); 4950 goto ipmi_fru_set_field_string_rebuild_out; 4951 } 4952 4953 #ifdef DBG_RESIZE_FRU 4954 printf("Section Length: %u\n", fru_section_len); 4955 #endif 4956 4957 /************************* 4958 4) Check number of padding bytes and bytes changed */ 4959 for(counter = 2; counter < fru_section_len; counter ++) 4960 { 4961 if(*(fru_data_old + (header_offset + fru_section_len - counter)) == 0) 4962 padding_len ++; 4963 else 4964 break; 4965 } 4966 num_byte_change = strlen(f_string) - strlen(fru_area); 4967 4968 #ifdef DBG_RESIZE_FRU 4969 printf("Padding Length: %u\n", padding_len); 4970 printf("NumByte Change: %i\n", num_byte_change); 4971 printf("Start SecChnge: %x\n", *(fru_data_old + fru_field_offset_tmp)); 4972 printf("End SecChnge : %x\n", *(fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1)); 4973 4974 printf("Start Section : %x\n", *(fru_data_old + header_offset)); 4975 printf("End Sec wo Pad: %x\n", *(fru_data_old + header_offset + fru_section_len - 2 - padding_len)); 4976 printf("End Section : %x\n", *(fru_data_old + header_offset + fru_section_len - 1)); 4977 #endif 4978 4979 /* Calculate New Padding Length */ 4980 padding_len -= num_byte_change; 4981 4982 #ifdef DBG_RESIZE_FRU 4983 printf("New Padding Length: %i\n", padding_len); 4984 #endif 4985 4986 /************************* 4987 5) Check if section must be resize. This occur when padding length is not between 0 and 7 */ 4988 if( (padding_len < 0) || (padding_len >= 8)) 4989 { 4990 uint32_t remaining_offset = ((header.offset.product * 8) + product_len); 4991 int change_size_by_8; 4992 4993 if(padding_len >= 8) 4994 { 4995 /* Section must be set smaller */ 4996 change_size_by_8 = ((padding_len) / 8) * (-1); 4997 } 4998 else 4999 { 5000 /* Section must be set bigger */ 5001 change_size_by_8 = 1 + (((padding_len+1) / 8) * (-1)); 5002 } 5003 5004 /* Recalculate padding and section length base on the section changes */ 5005 fru_section_len += (change_size_by_8 * 8); 5006 padding_len += (change_size_by_8 * 8); 5007 5008 #ifdef DBG_RESIZE_FRU 5009 printf("change_size_by_8: %i\n", change_size_by_8); 5010 printf("New Padding Length: %i\n", padding_len); 5011 printf("change_size_by_8: %i\n", change_size_by_8); 5012 printf("header.offset.board: %i\n", header.offset.board); 5013 #endif 5014 5015 /* Must move sections */ 5016 /* Section that can be modified are as follow 5017 Chassis 5018 Board 5019 product */ 5020 5021 /* Chassis type field */ 5022 if (f_type == 'c' ) 5023 { 5024 printf("Moving Section Chassis, from %i to %i\n", 5025 ((header.offset.board) * 8), 5026 ((header.offset.board + change_size_by_8) * 8) 5027 ); 5028 memcpy( 5029 (fru_data_new + ((header.offset.board + change_size_by_8) * 8)), 5030 (fru_data_old + (header.offset.board) * 8), 5031 board_len 5032 ); 5033 header.offset.board += change_size_by_8; 5034 } 5035 /* Board type field */ 5036 if ((f_type == 'c' ) || (f_type == 'b' )) 5037 { 5038 printf("Moving Section Product, from %i to %i\n", 5039 ((header.offset.product) * 8), 5040 ((header.offset.product + change_size_by_8) * 8) 5041 ); 5042 memcpy( 5043 (fru_data_new + ((header.offset.product + change_size_by_8) * 8)), 5044 (fru_data_old + (header.offset.product) * 8), 5045 product_len 5046 ); 5047 header.offset.product += change_size_by_8; 5048 } 5049 5050 /* Adjust length of the section */ 5051 if (f_type == 'c') 5052 { 5053 *(fru_data_new + chassis_offset + 1) += change_size_by_8; 5054 } 5055 else if( f_type == 'b') 5056 { 5057 *(fru_data_new + board_offset + 1) += change_size_by_8; 5058 } 5059 else if( f_type == 'p') 5060 { 5061 *(fru_data_new + product_offset + 1) += change_size_by_8; 5062 product_len_new = *(fru_data_new + product_offset + 1) * 8; 5063 } 5064 5065 /* Rebuild Header checksum */ 5066 { 5067 unsigned char * pfru_header = (unsigned char *) &header; 5068 header.checksum = 0; 5069 for(counter = 0; counter < (sizeof(struct fru_header) -1); counter ++) 5070 { 5071 header.checksum += pfru_header[counter]; 5072 } 5073 header.checksum = (0 - header.checksum); 5074 memcpy(fru_data_new, pfru_header, sizeof(struct fru_header)); 5075 } 5076 5077 /* Move remaining sections in 1 copy */ 5078 printf("Moving Remaining Bytes (Multi-Rec , etc..), from %i to %i\n", 5079 remaining_offset, 5080 ((header.offset.product) * 8) + product_len_new 5081 ); 5082 if(((header.offset.product * 8) + product_len_new - remaining_offset) < 0) 5083 { 5084 memcpy( 5085 fru_data_new + (header.offset.product * 8) + product_len_new, 5086 fru_data_old + remaining_offset, 5087 fru.size - remaining_offset 5088 ); 5089 } 5090 else 5091 { 5092 memcpy( 5093 fru_data_new + (header.offset.product * 8) + product_len_new, 5094 fru_data_old + remaining_offset, 5095 fru.size - ((header.offset.product * 8) + product_len_new) 5096 ); 5097 } 5098 } 5099 5100 /* Update only if it's fits padding length as defined in the spec, otherwise, it's an internal 5101 error */ 5102 /************************* 5103 6) Update Field and sections */ 5104 if( (padding_len >=0) && (padding_len < 8)) 5105 { 5106 /* Do not requires any change in other section */ 5107 5108 /* Change field length */ 5109 printf( 5110 "Updating Field : '%s' with '%s' ... (Length from '%d' to '%d')\n", 5111 fru_area, f_string, 5112 (int)*(fru_data_old + fru_field_offset_tmp), 5113 (int)(0xc0 + strlen(f_string))); 5114 *(fru_data_new + fru_field_offset_tmp) = (0xc0 + strlen(f_string)); 5115 memcpy(fru_data_new + fru_field_offset_tmp + 1, f_string, strlen(f_string)); 5116 5117 /* Copy remaing bytes in section */ 5118 #ifdef DBG_RESIZE_FRU 5119 printf("Copying remaining of sections: %d \n", 5120 (int)((fru_data_old + header_offset + fru_section_len - 1) - 5121 (fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1))); 5122 #endif 5123 5124 memcpy((fru_data_new + fru_field_offset_tmp + 1 + 5125 strlen(f_string)), 5126 (fru_data_old + fru_field_offset_tmp + 1 + 5127 strlen(fru_area)), 5128 ((fru_data_old + header_offset + fru_section_len - 1) - 5129 (fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1))); 5130 5131 /* Add Padding if required */ 5132 for(counter = 0; counter < padding_len; counter ++) 5133 { 5134 *(fru_data_new + header_offset + fru_section_len - 1 - 5135 padding_len + counter) = 0; 5136 } 5137 5138 /* Calculate New Checksum */ 5139 cksum = 0; 5140 for( counter = 0; counter <fru_section_len-1; counter ++ ) 5141 { 5142 cksum += *(fru_data_new + header_offset + counter); 5143 } 5144 *(fru_data_new + header_offset + fru_section_len - 1) = (0 - cksum); 5145 5146 #ifdef DBG_RESIZE_FRU 5147 printf("Calculate New Checksum: %x\n", (0 - cksum)); 5148 #endif 5149 5150 /****** ENABLE to show section modified before and after ********/ 5151 #if 0 5152 printf("Section: "); 5153 for( counter = 0; counter <old_section_len; counter ++ ) 5154 { 5155 if((counter %16) == 0) 5156 { 5157 printf("\n"); 5158 } 5159 printf( "%02X ", *(fru_data_old + header_offset + counter) ); 5160 } 5161 printf("\n"); 5162 5163 printf("Section: "); 5164 for( counter = 0; counter <fru_section_len; counter ++ ) 5165 { 5166 if((counter %16) == 0) 5167 { 5168 printf("\n"); 5169 } 5170 printf( "%02X ", *(fru_data_new + header_offset + counter) ); 5171 } 5172 printf("\n"); 5173 #endif 5174 } 5175 else 5176 { 5177 printf( "Internal error, padding length %i (must be from 0 to 7) ", padding_len ); 5178 rc = (-1); 5179 goto ipmi_fru_set_field_string_rebuild_out; 5180 } 5181 5182 /************************* 5183 7) Finally, write new FRU */ 5184 printf("Writing new FRU.\n"); 5185 if( write_fru_area( intf, &fru, fruId, 0, 0, fru.size, fru_data_new ) < 0 ) 5186 { 5187 printf("Write to FRU data failed.\n"); 5188 rc = (-1); 5189 goto ipmi_fru_set_field_string_rebuild_out; 5190 } 5191 5192 printf("Done.\n"); 5193 5194 ipmi_fru_set_field_string_rebuild_out: 5195 if (fru_area != NULL) { 5196 free(fru_area); 5197 fru_area = NULL; 5198 } 5199 if (fru_data_new != NULL) { 5200 free(fru_data_new); 5201 fru_data_new = NULL; 5202 } 5203 if (fru_data_old != NULL) { 5204 free(fru_data_old); 5205 fru_data_old = NULL; 5206 } 5207 5208 return rc; 5209 } 5210