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