1 /* 2 * Copyright (c) 2007 Kontron Canada, Inc. All Rights Reserved. 3 * 4 * Base on code from 5 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * Redistribution of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * Redistribution in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * Neither the name of Sun Microsystems, Inc. or the names of 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * This software is provided "AS IS," without a warranty of any kind. 23 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 24 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 25 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 26 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE 27 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 28 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 29 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 30 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 31 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 32 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 33 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 34 */ 35 36 #include <ipmitool/ipmi_ekanalyzer.h> 37 #include <ipmitool/log.h> 38 #include <ipmitool/helper.h> 39 #include <ipmitool/ipmi_strings.h> 40 41 #include <stdlib.h> 42 #include <string.h> 43 #include <time.h> 44 45 #define NO_MORE_INFO_FIELD 0xc1 46 #define TYPE_CODE 0xc0 /*Language code*/ 47 48 /* 49 * CONSTANT 50 */ 51 const int ERROR_STATUS = -1; 52 const int OK_STATUS = 0; 53 54 const char * STAR_LINE_LIMITER = 55 "*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"; 56 const char * EQUAL_LINE_LIMITER = 57 "================================================================="; 58 const int SIZE_OF_FILE_TYPE = 3; 59 const unsigned char AMC_MODULE = 0x80; 60 const int PICMG_ID_OFFSET = 3; 61 const unsigned int COMPARE_CANDIDATE = 2; 62 /* In AMC.0 or PICMG 3.0 specification offset start from 0 with 3 bytes of 63 * Mfg.ID, 1 byte of Picmg record Id, and 64 * 1 byte of format version, so the data offset start from 5 65 */ 66 const int START_DATA_OFFSET = 5; 67 const int LOWER_OEM_TYPE = 0xf0; 68 const int UPPER_OEM_TYPE = 0xfe; 69 const unsigned char DISABLE_PORT = 0x1f; 70 71 const struct valstr ipmi_ekanalyzer_module_type[] = { 72 { ON_CARRIER_FRU_FILE, "On-Carrier Device" }, 73 { A1_AMC_FRU_FILE, "AMC slot A1" }, 74 { A2_AMC_FRU_FILE, "AMC slot A2" }, 75 { A3_AMC_FRU_FILE, "AMC slot A3" }, 76 { A4_AMC_FRU_FILE, "AMC slot A4" }, 77 { B1_AMC_FRU_FILE, "AMC slot B1" }, 78 { B2_AMC_FRU_FILE, "AMC slot B2" }, 79 { B3_AMC_FRU_FILE, "AMC slot B3" }, 80 { B4_AMC_FRU_FILE, "AMC slot B4" }, 81 { RTM_FRU_FILE, "RTM" }, /*This is OEM specific module*/ 82 { CONFIG_FILE, "Configuration file" }, 83 { SHELF_MANAGER_FRU_FILE, "Shelf Manager" }, 84 { 0xffff , NULL }, 85 }; 86 87 const struct valstr ipmi_ekanalyzer_IPMBL_addr[] = { 88 { 0x72, "AMC slot A1" }, 89 { 0x74, "AMC slot A2" }, 90 { 0x76, "AMC slot A3" }, 91 { 0x78, "AMC slot A4" }, 92 { 0x7a, "AMC slot B1" }, 93 { 0x7c, "AMC slot B2" }, 94 { 0x7e, "AMC slot B3" }, 95 { 0x80, "AMC slot B4" }, 96 { 0x90, "RTM"}, /*This is OEM specific module*/ 97 { 0xffff , NULL }, 98 }; 99 100 const struct valstr ipmi_ekanalyzer_link_type[] = { 101 { 0x00, "Reserved" }, 102 { 0x01, "Reserved" }, 103 { 0x02, "AMC.1 PCI Express" }, 104 { 0x03, "AMC.1 PCI Express Advanced Switching" }, 105 { 0x04, "AMC.1 PCI Express Advanced Switching" }, 106 { 0x05, "AMC.2 Ethernet" }, 107 { 0x06, "AMC.4 Serial RapidIO" }, 108 { 0x07, "AMC.3 Storage" }, 109 /*This is OEM specific module*/ 110 { 0xf0, "OEM Type 0"}, 111 { 0xf1, "OEM Type 1"}, 112 { 0xf2, "OEM Type 2"}, 113 { 0xf3, "OEM Type 3"}, 114 { 0xf4, "OEM Type 4"}, 115 { 0xf5, "OEM Type 5"}, 116 { 0xf6, "OEM Type 6"}, 117 { 0xf7, "OEM Type 7"}, 118 { 0xf8, "OEM Type 8"}, 119 { 0xf9, "OEM Type 9"}, 120 { 0xfa, "OEM Type 10"}, 121 { 0xfb, "OEM Type 11"}, 122 { 0xfc, "OEM Type 12"}, 123 { 0xfd, "OEM Type 13"}, 124 { 0xfe, "OEM Type 14"}, 125 { 0xff , "Reserved" }, 126 }; 127 128 /*Reference: AMC.1 specification*/ 129 const struct valstr ipmi_ekanalyzer_extension_PCIE[] = { 130 { 0x00, "Gen 1 capable - non SSC" }, 131 { 0x01, "Gen 1 capable - SSC" }, 132 { 0x02, "Gen 2 capable - non SSC" }, 133 { 0x03, "Gen 3 capable - SSC" }, 134 { 0x0f, "Reserved"}, 135 }; 136 /*Reference: AMC.2 specification*/ 137 const struct valstr ipmi_ekanalyzer_extension_ETHERNET[] = { 138 { 0x00, "1000BASE-BX (SerDES Gigabit) Ethernet link" }, 139 { 0x01, "10GBASE-BX4 10 Gigabit Ethernet link" }, 140 }; 141 /*Reference: AMC.3 specification*/ 142 const struct valstr ipmi_ekanalyzer_extension_STORAGE[] = { 143 { 0x00, "Fibre Channel (FC)" }, 144 { 0x01, "Serial ATA (SATA)" }, 145 { 0x02, "Serial Attached SCSI (SAS/SATA)" }, 146 }; 147 148 const struct valstr ipmi_ekanalyzer_asym_PCIE[] = { 149 { 0x00, "exact match"}, 150 { 0x01, "provides a Primary PCI Express Port" }, 151 { 0x02, "provides a Secondary PCI Express Port" }, 152 }; 153 154 const struct valstr ipmi_ekanalyzer_asym_STORAGE[] = { 155 { 0x00, "FC or SAS interface {exact match}" }, 156 { 0x01, "SATA Server interface" }, 157 { 0x02, "SATA Client interface" }, 158 { 0x03, "Reserved" }, 159 }; 160 161 const struct valstr ipmi_ekanalyzer_picmg_record_id[] = { 162 { 0x04, "Backplane Point to Point Connectivity Record" }, 163 { 0x10, "Address Table Record" }, 164 { 0x11, "Shelf Power Distribution Record" }, 165 { 0x12, "Shelf Activation and Power Management Record" }, 166 { 0x13, "Shelf Manager IP Connection Record" }, 167 { 0x14, "Board Point to Point Connectivity Record" }, 168 { 0x15, "Radial IPMB-0 Link Mapping Record" }, 169 { 0x16, "Module Current Requirements Record" }, 170 { 0x17, "Carrier Activation and Power Management Record" }, 171 { 0x18, "Carrier Point-to-Point Connectivity Record" }, 172 { 0x19, "AdvancedMC Point-to-Point Connectivity Record" }, 173 { 0x1a, "Carrier Information Table" }, 174 { 0x1b, "Shelf Fan Geography Record" }, 175 { 0x2c, "Carrier Clock Point-to-Point Connectivity Record" }, 176 { 0x2d, "Clock Configuration Record" }, 177 }; 178 179 extern int verbose; 180 181 struct ipmi_ek_multi_header { 182 struct fru_multirec_header header; 183 unsigned char * data; 184 struct ipmi_ek_multi_header * prev; 185 struct ipmi_ek_multi_header * next; 186 }; 187 188 struct ipmi_ek_amc_p2p_connectivity_record{ 189 unsigned char guid_count; 190 struct fru_picmgext_guid * oem_guid; 191 unsigned char rsc_id; 192 unsigned char ch_count; 193 struct fru_picmgext_amc_channel_desc_record * ch_desc; 194 unsigned char link_desc_count; 195 struct fru_picmgext_amc_link_desc_record * link_desc; 196 int * matching_result; /*For link descriptor comparision*/ 197 }; 198 199 /***************************************************************************** 200 * Function prototype 201 ******************************************************************************/ 202 /**************************************************************************** 203 * command Functions 204 *****************************************************************************/ 205 static int ipmi_ekanalyzer_print( int argc, char * opt, 206 char ** filename, int * file_type ); 207 208 static tboolean ipmi_ekanalyzer_ekeying_match( int argc, char * opt, 209 char ** filename, int * file_type ); 210 211 /**************************************************************************** 212 * Linked list Functions 213 *****************************************************************************/ 214 static void ipmi_ek_add_record2list( struct ipmi_ek_multi_header ** record, 215 struct ipmi_ek_multi_header ** list_head, 216 struct ipmi_ek_multi_header ** list_last ); 217 218 static void ipmi_ek_display_record( struct ipmi_ek_multi_header * record, 219 struct ipmi_ek_multi_header * list_head, 220 struct ipmi_ek_multi_header * list_last ); 221 222 static void ipmi_ek_remove_record_from_list( 223 struct ipmi_ek_multi_header * record, 224 struct ipmi_ek_multi_header ** list_head, 225 struct ipmi_ek_multi_header ** list_last ); 226 227 static int ipmi_ekanalyzer_fru_file2structure( char * filename, 228 struct ipmi_ek_multi_header ** list_head, 229 struct ipmi_ek_multi_header ** list_record, 230 struct ipmi_ek_multi_header ** list_last ); 231 232 /**************************************************************************** 233 * Ekeying match Functions 234 *****************************************************************************/ 235 static int ipmi_ek_matching_process( int * file_type, int index1, int index2, 236 struct ipmi_ek_multi_header ** list_head, 237 struct ipmi_ek_multi_header ** list_last, char * opt, 238 struct ipmi_ek_multi_header * pphysical ); 239 240 static int ipmi_ek_get_resource_descriptor( int port_count, int index, 241 struct fru_picmgext_carrier_p2p_descriptor * port_desc, 242 struct ipmi_ek_multi_header * record ); 243 244 static int ipmi_ek_create_amc_p2p_record( struct ipmi_ek_multi_header * record, 245 struct ipmi_ek_amc_p2p_connectivity_record * amc_record ); 246 247 static int ipmi_ek_compare_link( struct ipmi_ek_multi_header * physic_record, 248 struct ipmi_ek_amc_p2p_connectivity_record record1, 249 struct ipmi_ek_amc_p2p_connectivity_record record2, 250 char * opt, int file_type1, int file_type2 ); 251 252 static tboolean ipmi_ek_compare_channel_descriptor( 253 struct fru_picmgext_amc_channel_desc_record ch_desc1, 254 struct fru_picmgext_amc_channel_desc_record ch_desc2, 255 struct fru_picmgext_carrier_p2p_descriptor * port_desc, 256 int index_port, unsigned char rsc_id ); 257 258 static int ipmi_ek_compare_link_descriptor( 259 struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, 260 struct ipmi_ek_amc_p2p_connectivity_record record2, int index2 ); 261 262 static int ipmi_ek_compare_asym( unsigned char asym[COMPARE_CANDIDATE] ); 263 264 static int ipmi_ek_compare_number_of_enable_port( 265 struct fru_picmgext_amc_link_desc_record link_desc[COMPARE_CANDIDATE] ); 266 267 static int ipmi_ek_check_physical_connectivity( 268 struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, 269 struct ipmi_ek_amc_p2p_connectivity_record record2, int index2, 270 struct ipmi_ek_multi_header * record, 271 int filetype1, int filetype2, char * option ); 272 273 /**************************************************************************** 274 * Display Functions 275 *****************************************************************************/ 276 static int ipmi_ek_display_fru_header( char * filename ); 277 278 static int ipmi_ek_display_fru_header_detail(char * filename); 279 280 static int ipmi_ek_display_chassis_info_area(FILE * input_file, long offset); 281 282 static size_t ipmi_ek_display_board_info_area( FILE * input_file, 283 char * board_type, unsigned int * board_length ); 284 285 static int ipmi_ek_display_product_info_area(FILE * input_file, long offset); 286 287 static tboolean ipmi_ek_display_link_descriptor( int file_type, 288 unsigned char rsc_id, char * str, 289 struct fru_picmgext_amc_link_desc_record link_desc ); 290 291 static void ipmi_ek_display_oem_guid( 292 struct ipmi_ek_amc_p2p_connectivity_record amc_record1 ); 293 294 static int ipmi_ek_display_carrier_connectivity( 295 struct ipmi_ek_multi_header * record ); 296 297 static int ipmi_ek_display_power( int argc, char * opt, 298 char ** filename, int * file_type ); 299 300 static void ipmi_ek_display_current_descriptor( 301 struct fru_picmgext_carrier_activation_record car, 302 struct fru_picmgext_activation_record * cur_desc, char * filename ); 303 304 static void ipmi_ek_display_backplane_p2p_record( 305 struct ipmi_ek_multi_header * record ); 306 307 static void ipmi_ek_display_address_table_record( 308 struct ipmi_ek_multi_header * record ); 309 310 static void ipmi_ek_display_shelf_power_distribution_record( 311 struct ipmi_ek_multi_header * record ); 312 313 static void ipmi_ek_display_shelf_activation_record( 314 struct ipmi_ek_multi_header * record ); 315 316 static void ipmi_ek_display_shelf_ip_connection_record( 317 struct ipmi_ek_multi_header * record ); 318 319 static void ipmi_ek_display_shelf_fan_geography_record( 320 struct ipmi_ek_multi_header * record ); 321 322 static void ipmi_ek_display_board_p2p_record( 323 struct ipmi_ek_multi_header * record ); 324 325 static void ipmi_ek_display_radial_ipmb0_record( 326 struct ipmi_ek_multi_header * record ); 327 328 static void ipmi_ek_display_amc_current_record( 329 struct ipmi_ek_multi_header * record ); 330 331 static void ipmi_ek_display_amc_activation_record ( 332 struct ipmi_ek_multi_header * record ); 333 334 static void ipmi_ek_display_amc_p2p_record( 335 struct ipmi_ek_multi_header * record ); 336 337 static void ipmi_ek_display_amc_carrier_info_record( 338 struct ipmi_ek_multi_header * record ); 339 340 static void ipmi_ek_display_clock_carrier_p2p_record( 341 struct ipmi_ek_multi_header * record ); 342 343 static void ipmi_ek_display_clock_config_record( 344 struct ipmi_ek_multi_header * record ); 345 346 /************************************************************************** 347 * 348 * Function name: ipmi_ekanalyzer_usage 349 * 350 * Description : Print the usage (help menu) of ekeying analyzer tool 351 * 352 * Restriction : None 353 * 354 * Input : None 355 * 356 * Output : None 357 * 358 * Global : None 359 * 360 * Return : None 361 * 362 ***************************************************************************/ 363 static void 364 ipmi_ekanalyzer_usage(void) 365 { 366 lprintf(LOG_NOTICE, 367 "Ekeying analyzer tool version 1.00"); 368 lprintf(LOG_NOTICE, 369 "ekanalyzer Commands:"); 370 lprintf(LOG_NOTICE, 371 " print [carrier | power | all] <oc=filename1> <b1=filename2>..."); 372 lprintf(LOG_NOTICE, 373 " frushow <b2=filename>"); 374 lprintf(LOG_NOTICE, 375 " summary [match | unmatch | all] <oc=filename1> <b1=filename2>..."); 376 } 377 378 /************************************************************************** 379 * 380 * Function name: ipmi_ek_get_file_type 381 * 382 * Description: this function takes an argument, then xtract the file type and 383 * convert into module type (on carrier, AMC,...) value. 384 * 385 * 386 * Restriction: None 387 * 388 * Input: argument: strings contain the type and the name of the file 389 * together 390 * 391 * Output: None 392 * 393 * Global: None 394 * 395 * Return: Return value of module type: On carrier FRU file, A1 FRUM file... 396 * if the file type is invalid, it return -1. See structure 397 * ipmi_ekanalyzer_module_type for a list of valid type. 398 ***************************************************************************/ 399 static int 400 ipmi_ek_get_file_type(char *argument) 401 { 402 int index_name=0; 403 int filetype = ERROR_STATUS; 404 if (strlen(argument) <= MIN_ARGUMENT) { 405 return filetype; 406 } 407 if (strncmp(argument, "oc=", SIZE_OF_FILE_TYPE) == 0) { 408 filetype = ON_CARRIER_FRU_FILE; 409 } else if (strncmp(argument, "a1=", SIZE_OF_FILE_TYPE) == 0) { 410 filetype = A1_AMC_FRU_FILE; 411 } else if (strncmp(argument, "a2=", SIZE_OF_FILE_TYPE) == 0) { 412 filetype = A2_AMC_FRU_FILE; 413 } else if (strncmp(argument, "a3=", SIZE_OF_FILE_TYPE) == 0) { 414 filetype = A3_AMC_FRU_FILE; 415 } else if (strncmp(argument, "a4=", SIZE_OF_FILE_TYPE) == 0) { 416 filetype = A4_AMC_FRU_FILE; 417 } else if (strncmp(argument, "b1=", SIZE_OF_FILE_TYPE) == 0) { 418 filetype = B1_AMC_FRU_FILE; 419 } else if (strncmp(argument, "b2=", SIZE_OF_FILE_TYPE) == 0) { 420 filetype = B2_AMC_FRU_FILE; 421 } else if (strncmp(argument, "b3=", SIZE_OF_FILE_TYPE) == 0) { 422 filetype = B3_AMC_FRU_FILE; 423 } else if (strncmp(argument, "b4=", SIZE_OF_FILE_TYPE) == 0) { 424 filetype = B4_AMC_FRU_FILE; 425 } else if (strncmp(argument, "rt=", SIZE_OF_FILE_TYPE) == 0) { 426 filetype = RTM_FRU_FILE; 427 } else if (strncmp(argument, "rc=", SIZE_OF_FILE_TYPE) == 0) { 428 filetype = CONFIG_FILE; 429 } else if (strncmp(argument, "sm=", SIZE_OF_FILE_TYPE) == 0) { 430 filetype = SHELF_MANAGER_FRU_FILE; 431 } else { 432 filetype = ERROR_STATUS; 433 } 434 return filetype; 435 } 436 437 /************************************************************************** 438 * 439 * Function name: ipmi_ekanalyzer_main 440 * 441 * Description: Main program of ekeying analyzer. It calls the appropriate 442 * function according to the command received. 443 * 444 * Restriction: None 445 * 446 * Input: ipmi_intf * intf: ? 447 * int argc : number of argument received 448 * int ** argv: argument strings 449 * 450 * Output: None 451 * 452 * Global: None 453 * 454 * Return: OK_STATUS as succes or ERROR_STATUS as error 455 * 456 ***************************************************************************/ 457 int 458 ipmi_ekanalyzer_main(struct ipmi_intf *intf, int argc, char **argv) 459 { 460 int rc = ERROR_STATUS; 461 int file_type[MAX_FILE_NUMBER]; 462 int tmp_ret = 0; 463 char *filename[MAX_FILE_NUMBER]; 464 unsigned int argument_offset = 0; 465 unsigned int type_offset = 0; 466 /* list des multi record */ 467 struct ipmi_ek_multi_header *list_head = NULL; 468 struct ipmi_ek_multi_header *list_record = NULL; 469 struct ipmi_ek_multi_header *list_last = NULL; 470 471 if (argc == 0) { 472 lprintf(LOG_ERR, "Not enough parameters given."); 473 ipmi_ekanalyzer_usage(); 474 return (-1); 475 } else if ((argc - 1) > MAX_FILE_NUMBER) { 476 lprintf(LOG_ERR, "Too too many parameters given."); 477 return (-1); 478 } 479 480 if (strcmp(argv[argument_offset], "help") == 0) { 481 ipmi_ekanalyzer_usage(); 482 return 0; 483 } else if ((strcmp(argv[argument_offset], "frushow") == 0) 484 && (argc > (MIN_ARGUMENT-1))) { 485 for (type_offset = 0; type_offset < (argc-1); type_offset++ ) { 486 argument_offset++; 487 file_type[type_offset] = ipmi_ek_get_file_type(argv[argument_offset]); 488 if (file_type[type_offset] == ERROR_STATUS 489 || file_type[type_offset] == CONFIG_FILE) { 490 lprintf(LOG_ERR, "Invalid file type!"); 491 lprintf(LOG_ERR, " ekanalyzer frushow <xx=frufile> ..."); 492 return (-1); 493 } 494 /* because of strlen doesn't count '\0', 495 * we need to add 1 byte for this character 496 * to filename size 497 */ 498 filename[type_offset] = malloc(strlen(argv[argument_offset]) 499 + 1 - SIZE_OF_FILE_TYPE); 500 if (filename[type_offset] == NULL) { 501 lprintf(LOG_ERR, "malloc failure"); 502 return (-1); 503 } 504 strcpy(filename[type_offset], 505 &argv[argument_offset][SIZE_OF_FILE_TYPE]); 506 printf("Start converting file '%s'...\n", 507 filename[type_offset]); 508 /* Display FRU header offset */ 509 rc = ipmi_ek_display_fru_header (filename[type_offset]); 510 if (rc != ERROR_STATUS) { 511 /* Display FRU header info in detail record */ 512 tmp_ret = ipmi_ek_display_fru_header_detail(filename[type_offset]); 513 /* Convert from binary data into multi record structure */ 514 rc = ipmi_ekanalyzer_fru_file2structure (filename[type_offset], 515 &list_head, &list_record, &list_last ); 516 ipmi_ek_display_record(list_record, list_head, list_last); 517 /* Remove record of list */ 518 while (list_head != NULL) { 519 ipmi_ek_remove_record_from_list(list_head, 520 &list_head,&list_last ); 521 if (verbose > 1) { 522 printf("record has been removed!\n"); 523 } 524 } 525 } 526 free(filename[type_offset]); 527 filename[type_offset] = NULL; 528 } 529 } else if ((strcmp(argv[argument_offset], "print") == 0) 530 || (strcmp(argv[argument_offset], "summary") == 0)) { 531 /* Display help text for corresponding command 532 * if not enough parameters were given. 533 */ 534 char * option; 535 /* index=1 indicates start position of first file 536 * name in command line 537 */ 538 int index = 1; 539 int filename_size=0; 540 if (argc < MIN_ARGUMENT) { 541 lprintf(LOG_ERR, "Not enough parameters given."); 542 if (strcmp(argv[argument_offset], "print") == 0) { 543 lprintf(LOG_ERR, 544 " ekanalyzer print [carrier/power/all]" 545 " <xx=frufile> <xx=frufile> [xx=frufile]"); 546 } else { 547 lprintf(LOG_ERR, 548 " ekanalyzer summary [match/ unmatch/ all]" 549 " <xx=frufile> <xx=frufile> [xx=frufile]"); 550 } 551 return ERROR_STATUS; 552 } 553 argument_offset++; 554 if ((strcmp(argv[argument_offset], "carrier") == 0) 555 || (strcmp(argv[argument_offset], "power") == 0) 556 || (strcmp(argv[argument_offset], "all") == 0)) { 557 option = argv[argument_offset]; 558 index ++; 559 argc--; 560 } else if ((strcmp(argv[argument_offset], "match") == 0) 561 || ( strcmp(argv[argument_offset], "unmatch") == 0)) { 562 option = argv[argument_offset]; 563 index ++; 564 argc--; 565 } else if ( strncmp(&argv[argument_offset][2], "=", 1) == 0) { 566 /* since the command line must receive xx=filename, 567 * so the position of "=" sign is 2 568 */ 569 option = "default"; 570 /* Since there is no option from user, the first argument 571 * becomes first file type 572 */ 573 index = 1; /* index of argument */ 574 } else { 575 option = "invalid"; 576 printf("Invalid option '%s'\n", argv[argument_offset]); 577 argument_offset--; 578 if (strcmp(argv[0], "print") == 0) { 579 lprintf (LOG_ERR, 580 " ekanalyzer print [carrier/power/all]" 581 " <xx=frufile> <xx=frufile> [xx=frufile]"); 582 } else { 583 lprintf (LOG_ERR, 584 " ekanalyzer summary [match/ unmatch/ all]" 585 " <xx=frufile> <xx=frufile> [xx=frufile]"); 586 } 587 rc = ERROR_STATUS; 588 } 589 if (strcmp(option, "invalid") != 0) { 590 int i=0; 591 for (i = 0; i < (argc-1); i++) { 592 file_type[i] = ipmi_ek_get_file_type (argv[index]); 593 if (file_type[i] == ERROR_STATUS) { 594 /* display the first 2 charactors (file type) of argument */ 595 lprintf(LOG_ERR, "Invalid file type: %c%c\n", 596 argv[index][0], 597 argv[index][1]); 598 ipmi_ekanalyzer_usage(); 599 rc = ERROR_STATUS; 600 break; 601 } 602 /* size is equal to string size minus 3 bytes of file type plus 603 * 1 byte of '\0' since the strlen doesn't count the '\0' 604 */ 605 filename_size = strlen(argv[index]) - SIZE_OF_FILE_TYPE + 1; 606 if (filename_size > 0) { 607 /* TODO - check malloc() retval */ 608 filename[i] = malloc( filename_size ); 609 if (filename[i] != NULL) { 610 strcpy(filename[i], &argv[index][SIZE_OF_FILE_TYPE]); 611 } 612 } 613 rc = OK_STATUS; 614 index++; 615 } 616 if (rc != ERROR_STATUS) { 617 if (verbose > 0) { 618 for (i = 0; i < (argc-1); i++) { 619 printf ("Type: %s, ", 620 val2str(file_type[i], 621 ipmi_ekanalyzer_module_type)); 622 printf("file name: %s\n", filename[i]); 623 } 624 } 625 if (strcmp(argv[0], "print") == 0) { 626 rc = ipmi_ekanalyzer_print((argc-1), 627 option, filename, file_type); 628 } else { 629 rc = ipmi_ekanalyzer_ekeying_match((argc-1), 630 option, filename, file_type); 631 } 632 for (i = 0; i < (argc-1); i++) { 633 if (filename[i] != NULL) { 634 free(filename[i]); 635 filename[i] = NULL; 636 } 637 } 638 } /* End of ERROR_STATUS */ 639 } /* End of comparison of invalid option */ 640 } else { 641 lprintf(LOG_ERR, "Invalid ekanalyzer command: %s", argv[0]); 642 ipmi_ekanalyzer_usage(); 643 rc = ERROR_STATUS; 644 } 645 return rc; 646 } 647 648 /************************************************************************** 649 * 650 * Function name: ipmi_ekanalyzer_print 651 * 652 * Description: this function will display the topology, power or both 653 * information together according to the option that it received. 654 * 655 * Restriction: None 656 * 657 * Input: int argc: number of the argument received 658 * char* opt: option string that will tell what to display 659 * char** filename: strings that contained filename of FRU data binary file 660 * int* file_type: a pointer that contain file type (on carrier file, 661 * a1 file, b1 file...). See structure 662 * ipmi_ekanalyzer_module_type for a list of valid type 663 * 664 * Output: None 665 * 666 * Global: None 667 * 668 * Return: return 0 as success and -1 as error. 669 * 670 ***************************************************************************/ 671 static int 672 ipmi_ekanalyzer_print(int argc, char *opt, char **filename, int *file_type) 673 { 674 int return_value = OK_STATUS; 675 /* Display carrier topology */ 676 if ((strcmp(opt, "carrier") == 0) || (strcmp(opt, "default") == 0)) { 677 tboolean found_flag = FALSE; 678 int index = 0; 679 int index_name[argc]; 680 int list = 0; 681 /* list of multi record */ 682 struct ipmi_ek_multi_header *list_head[argc]; 683 struct ipmi_ek_multi_header *list_record[argc]; 684 struct ipmi_ek_multi_header *list_last[argc]; 685 686 for (list=0; list < argc; list++) { 687 list_head[list] = NULL; 688 list_record[list] = NULL; 689 list_last[list] = NULL; 690 } 691 /* reset list count */ 692 list = 0; 693 for (index = 0; index < argc; index++) { 694 if (file_type[index] != ON_CARRIER_FRU_FILE) { 695 continue; 696 } 697 index_name[list] = index; 698 return_value = ipmi_ekanalyzer_fru_file2structure(filename[index], 699 &list_head[list], 700 &list_record[list], 701 &list_last[list]); 702 list++; 703 found_flag = TRUE; 704 } 705 if (!found_flag) { 706 printf("No carrier file has been found\n"); 707 return_value = ERROR_STATUS; 708 } else { 709 int i = 0; 710 for (i = 0; i < argc; i++) { 711 /* this is a flag to advoid displaying 712 * the same data multiple time 713 */ 714 tboolean first_data = TRUE; 715 for (list_record[i] = list_head[i]; 716 list_record[i] != NULL; 717 list_record[i] = list_record[i]->next) { 718 if (list_record[i]->data[PICMG_ID_OFFSET] == FRU_AMC_CARRIER_P2P) { 719 if (first_data) { 720 printf("%s\n", STAR_LINE_LIMITER); 721 printf("From Carrier file: %s\n", filename[index_name[i]]); 722 first_data = FALSE; 723 } 724 return_value = ipmi_ek_display_carrier_connectivity(list_record[i]); 725 } else if (list_record[i]->data[PICMG_ID_OFFSET] == FRU_AMC_CARRIER_INFO) { 726 /*See AMC.0 specification Table3-3 for mor detail*/ 727 #define COUNT_OFFSET 6 728 if (first_data) { 729 printf("From Carrier file: %s\n", filename[index_name[i]]); 730 first_data = FALSE; 731 } 732 printf(" Number of AMC bays supported by Carrier: %d\n", 733 list_record[i]->data[COUNT_OFFSET]); 734 } 735 } 736 } 737 /*Destroy the list of record*/ 738 for (i = 0; i < argc; i++) { 739 while (list_head[i] != NULL) { 740 ipmi_ek_remove_record_from_list(list_head[i], 741 &list_head[i], &list_last[i]); 742 } 743 /* display deleted result when we 744 * reach the last record 745 */ 746 if ((i == (list-1)) && verbose) { 747 printf("Record list has been removed successfully\n"); 748 } 749 } 750 } 751 } else if (strcmp(opt, "power") == 0) { 752 printf("Print power information\n"); 753 return_value = ipmi_ek_display_power(argc, opt, filename, file_type); 754 } else if (strcmp(opt, "all") == 0) { 755 printf("Print all information\n"); 756 return_value = ipmi_ek_display_power(argc, opt, filename, file_type); 757 } else { 758 lprintf(LOG_ERR, "Invalid option %s", opt); 759 return_value = ERROR_STATUS; 760 } 761 return return_value; 762 } 763 764 /************************************************************************** 765 * 766 * Function name: ipmi_ek_display_carrier_connectivity 767 * 768 * Description: Display the topology between a Carrier and all AMC modules by 769 * using carrier p2p connectivity record 770 * 771 * Restriction: Ref: AMC.0 Specification: Table 3-13 and Table 3-14 772 * 773 * Input: struct ipmi_ek_multi_header* record: a pointer to the carrier p2p 774 * connectivity record. 775 * 776 * Output: None 777 * 778 * Global: None 779 * 780 * Return: return 0 on success and -1 if the record doesn't exist. 781 * 782 ***************************************************************************/ 783 static int 784 ipmi_ek_display_carrier_connectivity(struct ipmi_ek_multi_header *record) 785 { 786 int offset = START_DATA_OFFSET; 787 struct fru_picmgext_carrier_p2p_record rsc_desc; 788 struct fru_picmgext_carrier_p2p_descriptor *port_desc; 789 if (record == NULL) { 790 lprintf(LOG_ERR, "P2P connectivity record is invalid\n"); 791 return ERROR_STATUS; 792 } 793 if (verbose > 1) { 794 int k = 0; 795 printf("Binary data of Carrier p2p connectivity"\ 796 " record starting from mfg id\n"); 797 for (k = 0; k < (record->header.len); k++) { 798 printf("%02x ", record->data[k]); 799 } 800 printf("\n"); 801 } 802 while (offset <= (record->header.len - START_DATA_OFFSET)) { 803 rsc_desc.resource_id = record->data[offset++]; 804 rsc_desc.p2p_count = record->data[offset++]; 805 if (verbose > 0) { 806 printf("resource id= %02x port count= %d\n", 807 rsc_desc.resource_id, rsc_desc.p2p_count); 808 } 809 /* check if it is an AMC Module */ 810 if ((rsc_desc.resource_id & AMC_MODULE) == AMC_MODULE) { 811 /* check if it is an RTM module */ 812 if (rsc_desc.resource_id == AMC_MODULE) { 813 printf(" %s topology:\n", 814 val2str(RTM_IPMB_L, 815 ipmi_ekanalyzer_IPMBL_addr)); 816 } else { 817 /* The last four bits of resource ID 818 * represent site number (mask = 0x0f) 819 */ 820 printf(" %s topology:\n", 821 val2str((rsc_desc.resource_id & 0x0f), 822 ipmi_ekanalyzer_module_type)); 823 } 824 } else { 825 printf(" On Carrier Device ID %d topology: \n", 826 (rsc_desc.resource_id & 0x0f)); 827 } 828 while (rsc_desc.p2p_count > 0) { 829 unsigned char data[3]; 830 # ifndef WORDS_BIGENDIAN 831 data[0] = record->data[offset + 0]; 832 data[1] = record->data[offset + 1]; 833 data[2] = record->data[offset + 2]; 834 # else 835 data[0] = record->data[offset + 2]; 836 data[1] = record->data[offset + 1]; 837 data[2] = record->data[offset + 0]; 838 # endif 839 port_desc = (struct fru_picmgext_carrier_p2p_descriptor*)data; 840 offset += sizeof(struct fru_picmgext_carrier_p2p_descriptor); 841 if ((port_desc->remote_resource_id & AMC_MODULE) == AMC_MODULE) { 842 printf("\tPort %d =====> %s, Port %d\n", 843 port_desc->local_port, 844 val2str((port_desc->remote_resource_id & 0x0f), 845 ipmi_ekanalyzer_module_type), 846 port_desc->remote_port); 847 } else { 848 printf("\tPort %d =====> On Carrier Device ID %d, Port %d\n", 849 port_desc->local_port, 850 (port_desc->remote_resource_id & 0x0f), 851 port_desc->remote_port); 852 } 853 rsc_desc.p2p_count--; 854 } 855 } 856 return OK_STATUS; 857 } 858 859 /************************************************************************** 860 * 861 * Function name: ipmi_ek_display_power 862 * 863 * Description: Display the power management of the Carrier and AMC module by 864 * using current management record. If the display option equal to all, 865 * it will display power and carrier topology together. 866 * 867 * Restriction: Reference: AMC.0 Specification, Table 3-11 868 * 869 * Input: int argc: number of the argument received 870 * char* opt: option string that will tell what to display 871 * char** filename: strings that contained filename of FRU data binary file 872 * int* file_type: a pointer that contain file type (on carrier file, 873 * a1 file, b1 file...) 874 * 875 * Output: None 876 * 877 * Global: None 878 * 879 * Return: return 0 on success and -1 if the record doesn't exist. 880 * 881 ***************************************************************************/ 882 static int 883 ipmi_ek_display_power( int argc, char * opt, char ** filename, int * file_type ) 884 { 885 int num_file=0; 886 int return_value = ERROR_STATUS; 887 int index = 0; 888 889 /*list des multi record*/ 890 struct ipmi_ek_multi_header * list_head[argc]; 891 struct ipmi_ek_multi_header * list_record[argc]; 892 struct ipmi_ek_multi_header * list_last[argc]; 893 894 for ( num_file = 0; num_file < argc; num_file++ ){ 895 list_head[num_file] = NULL; 896 list_record[num_file] = NULL; 897 list_last[num_file] = NULL; 898 } 899 900 for ( num_file = 0; num_file < argc; num_file++ ){ 901 tboolean is_first_data = TRUE; 902 if ( file_type[num_file] == CONFIG_FILE ){ 903 num_file++; 904 } 905 906 if ( is_first_data ){ 907 printf("%s\n", STAR_LINE_LIMITER); 908 printf("\nFrom %s file '%s'\n", 909 val2str( file_type[num_file], ipmi_ekanalyzer_module_type), 910 filename[num_file]); 911 is_first_data = FALSE; 912 } 913 914 return_value = ipmi_ekanalyzer_fru_file2structure( filename[num_file], 915 &list_head[num_file], &list_record[num_file], &list_last[num_file]); 916 917 if ( list_head[num_file] != NULL ){ 918 for ( list_record[num_file] = list_head[num_file]; 919 list_record[num_file] != NULL; 920 list_record[num_file] = list_record[num_file]->next 921 ){ 922 if ( ( strcmp(opt, "all") == 0 ) 923 && ( file_type[num_file] == ON_CARRIER_FRU_FILE ) 924 ){ 925 if ( list_record[num_file]->data[PICMG_ID_OFFSET] 926 == 927 FRU_AMC_CARRIER_P2P 928 ){ 929 return_value = ipmi_ek_display_carrier_connectivity( 930 list_record[num_file] ); 931 } 932 else if ( list_record[num_file]->data[PICMG_ID_OFFSET] 933 == 934 FRU_AMC_CARRIER_INFO 935 ){ 936 /*Ref: See AMC.0 Specification Table 3-3: Carrier Information 937 * Table about offset value 938 */ 939 printf( " Number of AMC bays supported by Carrier: %d\n", 940 list_record[num_file]->data[START_DATA_OFFSET+1] ); 941 } 942 } 943 /*Ref: AMC.0 Specification: Table 3-11 944 * Carrier Activation and Current Management Record 945 */ 946 if ( list_record[num_file]->data[PICMG_ID_OFFSET] 947 == 948 FRU_AMC_ACTIVATION 949 ){ 950 int index_data = START_DATA_OFFSET; 951 struct fru_picmgext_carrier_activation_record car; 952 struct fru_picmgext_activation_record * cur_desc; 953 954 memcpy ( &car, &list_record[num_file]->data[index_data], 955 sizeof (struct fru_picmgext_carrier_activation_record) ); 956 index_data += 957 sizeof (struct fru_picmgext_carrier_activation_record); 958 cur_desc = malloc (car.module_activation_record_count * \ 959 sizeof (struct fru_picmgext_activation_record) ); 960 for(index=0; index<car.module_activation_record_count; index++){ 961 memcpy( &cur_desc[index], 962 &list_record[num_file]->data[index_data], 963 sizeof (struct fru_picmgext_activation_record) ); 964 965 index_data += sizeof (struct fru_picmgext_activation_record); 966 } 967 /*Display the current*/ 968 ipmi_ek_display_current_descriptor( car, 969 cur_desc, filename[num_file] ); 970 free(cur_desc); 971 cur_desc = NULL; 972 } 973 /*Ref: AMC.0 specification, Table 3-10: Module Current Requirement*/ 974 else if ( list_record[num_file]->data[PICMG_ID_OFFSET] 975 == FRU_AMC_CURRENT 976 ){ 977 float power_in_watt = 0; 978 float current_in_amp = 0; 979 980 printf(" %s power required (Current Draw): ", 981 val2str ( file_type[num_file], ipmi_ekanalyzer_module_type) ); 982 current_in_amp = 983 list_record[num_file]->data[START_DATA_OFFSET]*0.1; 984 power_in_watt = current_in_amp * AMC_VOLTAGE; 985 printf("%.2f Watts (%.2f Amps)\n",power_in_watt, current_in_amp); 986 } 987 } 988 return_value = OK_STATUS; 989 /*Destroy the list of record*/ 990 for ( index = 0; index < argc; index++ ){ 991 while ( list_head[index] != NULL ){ 992 ipmi_ek_remove_record_from_list ( list_head[index], 993 &list_head[index],&list_last[index] ); 994 } 995 if ( verbose > 1 ) 996 printf("Record list has been removed successfully\n"); 997 } 998 } 999 } 1000 printf("%s\n", STAR_LINE_LIMITER); 1001 return return_value; 1002 } 1003 1004 /************************************************************************** 1005 * 1006 * Function name: ipmi_ek_display_current_descriptor 1007 * 1008 * Description: Display the current descriptor under format xx Watts (xx Amps) 1009 * 1010 * Restriction: None 1011 * 1012 * Input: struct fru_picmgext_carrier_activation_record car: contain binary data 1013 * of carrier activation record 1014 * struct fru_picmgext_activation_record * cur_desc: contain current 1015 * descriptor 1016 * char* filename: strings that contained filename of FRU data binary file 1017 * 1018 * Output: None 1019 * 1020 * Global: None 1021 * 1022 * Return: None 1023 * 1024 ***************************************************************************/ 1025 static void 1026 ipmi_ek_display_current_descriptor( 1027 struct fru_picmgext_carrier_activation_record car, 1028 struct fru_picmgext_activation_record *cur_desc, 1029 char *filename) 1030 { 1031 int index = 0; 1032 float power_in_watt = 0.0; 1033 float current_in_amp = 0.0; 1034 for (index = 0; index < car.module_activation_record_count; index++) { 1035 /* See AMC.0 specification, Table 3-12 for 1036 * detail about calculation 1037 */ 1038 current_in_amp = (float)cur_desc[index].max_module_curr * 0.1; 1039 power_in_watt = (float)current_in_amp * AMC_VOLTAGE; 1040 printf(" Carrier AMC power available on %s:\n", 1041 val2str( cur_desc[index].ibmb_addr, 1042 ipmi_ekanalyzer_IPMBL_addr)); 1043 printf("\t- Local IPMB Address \t: %02x\n", 1044 cur_desc[index].ibmb_addr); 1045 printf("\t- Maximum module Current\t: %.2f Watts (%.2f Amps)\n", 1046 power_in_watt, current_in_amp); 1047 } 1048 /* Display total power on Carrier */ 1049 current_in_amp = (float)car.max_internal_curr * 0.1; 1050 power_in_watt = (float)current_in_amp * AMC_VOLTAGE; 1051 printf(" Carrier AMC total power available for all bays from file '%s':", 1052 filename); 1053 printf(" %.2f Watts (%.2f Amps)\n", power_in_watt, current_in_amp); 1054 } 1055 1056 /************************************************************************** 1057 * 1058 * Function name: ipmi_ekanalyzer_ekeying_match 1059 * 1060 * Description: Check for possible Ekeying match between two FRU files 1061 * 1062 * Restriction: None 1063 * 1064 * Input: argc: number of the argument received 1065 * opt: string that contains display option received from user. 1066 * filename: strings that contained filename of FRU data binary file 1067 * file_type: a pointer that contain file type (on carrier file, 1068 * a1 file, b1 file...) 1069 * 1070 * Output: None 1071 * 1072 * Global: None 1073 * 1074 * Return: return TRUE on success and FALSE if the record doesn't exist. 1075 * 1076 ***************************************************************************/ 1077 static tboolean 1078 ipmi_ekanalyzer_ekeying_match( int argc, char * opt, 1079 char ** filename, int * file_type ) 1080 { 1081 tboolean return_value = FALSE; 1082 1083 if ( (strcmp(opt, "carrier") == 0 ) || (strcmp(opt, "power") == 0) ){ 1084 lprintf(LOG_ERR, " ekanalyzer summary [match/ unmatch/ all]"\ 1085 " <xx=frufile> <xx=frufile> [xx=frufile]"); 1086 return_value = ERROR_STATUS; 1087 } 1088 else{ 1089 int num_file=0; 1090 tboolean amc_file = FALSE; /*used to indicate the present of AMC file*/ 1091 tboolean oc_file = FALSE; /*used to indicate the present of Carrier file*/ 1092 1093 /*Check for possible ekeying match between files*/ 1094 for ( num_file=0; num_file < argc; num_file++ ){ 1095 if ( ( file_type[num_file] == ON_CARRIER_FRU_FILE ) 1096 || ( file_type[num_file] == CONFIG_FILE ) 1097 || ( file_type[num_file] == SHELF_MANAGER_FRU_FILE ) 1098 ){ 1099 amc_file = FALSE; 1100 } 1101 else { /*there is an amc file*/ 1102 amc_file = TRUE; 1103 break; 1104 } 1105 } 1106 if ( amc_file == FALSE ){ 1107 printf("\nNo AMC FRU file is provided --->" \ 1108 " No possible ekeying match!\n"); 1109 return_value = ERROR_STATUS; 1110 } 1111 else{ 1112 /*If no carrier file is provided, return error*/ 1113 for ( num_file=0; num_file < argc; num_file++ ){ 1114 if ( (file_type[num_file] == ON_CARRIER_FRU_FILE ) 1115 || ( file_type[num_file] == CONFIG_FILE ) 1116 || ( file_type[num_file] == SHELF_MANAGER_FRU_FILE ) 1117 ){ 1118 oc_file = TRUE; 1119 break; 1120 } 1121 } 1122 if ( !oc_file ){ 1123 printf("\nNo Carrier FRU file is provided" \ 1124 " ---> No possible ekeying match!\n"); 1125 return_value = ERROR_STATUS; 1126 } 1127 else{ 1128 /*list des multi record*/ 1129 struct ipmi_ek_multi_header * list_head[argc]; 1130 struct ipmi_ek_multi_header * list_record[argc]; 1131 struct ipmi_ek_multi_header * list_last[argc]; 1132 struct ipmi_ek_multi_header * pcarrier_p2p; 1133 int list = 0; 1134 int match_pair = 0; 1135 1136 /*Create an empty list*/ 1137 for ( list=0; list<argc; list++ ){ 1138 list_head[list] = NULL; 1139 list_record[list] = NULL; 1140 list_last[list] = NULL; 1141 } 1142 list=0; 1143 1144 for ( num_file=0; num_file < argc; num_file++ ){ 1145 if (file_type[num_file] != CONFIG_FILE){ 1146 return_value = ipmi_ekanalyzer_fru_file2structure( 1147 filename[num_file], &list_head[num_file], 1148 &list_record[num_file], &list_last[num_file]); 1149 } 1150 } 1151 /*Get Carrier p2p connectivity record for physical check*/ 1152 for (num_file=0; num_file < argc; num_file++){ 1153 if (file_type[num_file] == ON_CARRIER_FRU_FILE ){ 1154 for ( pcarrier_p2p=list_head[num_file]; 1155 pcarrier_p2p != NULL ; 1156 pcarrier_p2p = pcarrier_p2p->next 1157 ){ 1158 if ( pcarrier_p2p->data[PICMG_ID_OFFSET] 1159 == FRU_AMC_CARRIER_P2P 1160 ){ 1161 break; 1162 } 1163 } 1164 break; 1165 } 1166 } 1167 /*Determine the match making pair*/ 1168 while ( match_pair < argc ){ 1169 for ( num_file = (match_pair+1); num_file<argc; num_file++ ){ 1170 if ( ( file_type[match_pair] != CONFIG_FILE ) 1171 && ( file_type[num_file] != CONFIG_FILE ) 1172 ){ 1173 if ( ( file_type[match_pair] != ON_CARRIER_FRU_FILE ) 1174 || ( file_type[num_file] != ON_CARRIER_FRU_FILE ) 1175 ){ 1176 printf("%s vs %s\n", 1177 val2str(file_type[match_pair], 1178 ipmi_ekanalyzer_module_type), 1179 val2str(file_type[num_file], 1180 ipmi_ekanalyzer_module_type)); 1181 /*Ekeying match between 2 files*/ 1182 if (verbose>0){ 1183 printf("Start matching process\n"); 1184 } 1185 return_value = ipmi_ek_matching_process( file_type, 1186 match_pair, num_file, list_head, 1187 list_last, opt, pcarrier_p2p); 1188 } 1189 } 1190 } 1191 match_pair ++; 1192 } 1193 for( num_file=0; num_file < argc; num_file++ ){ 1194 if (list_head[num_file] != NULL ){ 1195 ipmi_ek_remove_record_from_list( list_head[num_file], 1196 &list_record[num_file], &list_last[num_file]); 1197 } 1198 if ( ( num_file == argc-1 ) && verbose ) 1199 printf("Record list has been removed successfully\n"); 1200 } 1201 return_value = OK_STATUS; 1202 } 1203 } 1204 } 1205 return return_value; 1206 } 1207 1208 /************************************************************************** 1209 * 1210 * Function name: ipmi_ek_matching_process 1211 * 1212 * Description: This function process the OEM check, Physical Connectivity check, 1213 * and Link Descriptor comparison to do Ekeying match 1214 * 1215 * Restriction: None 1216 * 1217 * Input: file_type: a pointer that contain file type (on carrier file, 1218 * a1 file, b1 file...) 1219 * index1: position of the first record in the list of the record 1220 * index2: position of the second record in the list of the record 1221 * ipmi_ek_multi_header ** list_head: pointer to the header of a 1222 * linked list that contain FRU multi record 1223 * ipmi_ek_multi_header ** list_last: pointer to the tale of a 1224 * linked list that contain FRU multi record 1225 * opt: string that contain display option such as "match", "unmatch", or 1226 * "all". 1227 * pphysical: a pointer that contain a carrier p2p connectivity record 1228 * to perform physical check 1229 * 1230 * Output: None 1231 * 1232 * Global: None 1233 * 1234 * Return: return OK_STATUS on success and ERROR_STATUS if the record doesn't 1235 * exist. 1236 * 1237 ***************************************************************************/ 1238 static int ipmi_ek_matching_process( int * file_type, int index1, int index2, 1239 struct ipmi_ek_multi_header ** list_head, 1240 struct ipmi_ek_multi_header ** list_last, char * opt, 1241 struct ipmi_ek_multi_header * pphysical ) 1242 { 1243 int result = ERROR_STATUS; 1244 struct ipmi_ek_multi_header * record; 1245 int num_amc_record1 = 0;/*Number of AMC records in the first module*/ 1246 int num_amc_record2 = 0;/*Number of AMC records in the second module*/ 1247 1248 /* Comparison between an On-Carrier and an AMC*/ 1249 if ( file_type[index2] == ON_CARRIER_FRU_FILE ){ 1250 int index_temp = 0; 1251 index_temp = index1; 1252 index1 = index2; /*index1 indicate on carrier*/ 1253 index2 = index_temp; /*index2 indcate an AMC*/ 1254 } 1255 /*Calculate record size for Carrier file*/ 1256 for ( record=list_head[index1]; record != NULL;record = record->next ){ 1257 if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ 1258 num_amc_record2++; 1259 } 1260 } 1261 /*Calculate record size for amc file*/ 1262 for ( record=list_head[index2]; record != NULL;record = record->next){ 1263 if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ 1264 num_amc_record1++; 1265 } 1266 } 1267 if ( (num_amc_record1 > 0) && (num_amc_record2 > 0) ){ 1268 int index_record1 = 0; 1269 int index_record2 = 0; 1270 /* Multi records of AMC module */ 1271 struct ipmi_ek_amc_p2p_connectivity_record * amc_record1 = NULL; 1272 /* Multi records of Carrier or an AMC module */ 1273 struct ipmi_ek_amc_p2p_connectivity_record * amc_record2 = NULL; 1274 1275 amc_record1 = malloc ( num_amc_record1 * \ 1276 sizeof(struct ipmi_ek_amc_p2p_connectivity_record)); 1277 amc_record2 = malloc ( num_amc_record2 * \ 1278 sizeof(struct ipmi_ek_amc_p2p_connectivity_record)); 1279 1280 for (record=list_head[index2]; record != NULL;record = record->next){ 1281 if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ 1282 result = ipmi_ek_create_amc_p2p_record( record, 1283 &amc_record1[index_record1] ); 1284 if (result != ERROR_STATUS){ 1285 struct ipmi_ek_multi_header * current_record = NULL; 1286 1287 for ( current_record=list_head[index1]; 1288 current_record != NULL ; 1289 current_record = current_record->next 1290 ){ 1291 if ( current_record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ 1292 result = ipmi_ek_create_amc_p2p_record( current_record, 1293 &amc_record2[index_record2] ); 1294 if ( result != ERROR_STATUS ){ 1295 if ( result == OK_STATUS ){ 1296 /*Compare Link descriptor*/ 1297 result = ipmi_ek_compare_link ( pphysical, 1298 amc_record1[index_record1], 1299 amc_record2[index_record2], 1300 opt, file_type[index1], file_type[index2]); 1301 } 1302 index_record2++; 1303 } 1304 } /*end of FRU_AMC_P2P */ 1305 } /* end of for loop */ 1306 index_record1++; 1307 } 1308 } 1309 } 1310 free(amc_record1) ; 1311 amc_record1 = NULL; 1312 free(amc_record2) ; 1313 amc_record2 = NULL; 1314 } 1315 else{ 1316 printf("No amc record is found!\n"); 1317 } 1318 1319 return result; 1320 } 1321 1322 /************************************************************************** 1323 * 1324 * Function name: ipmi_ek_check_physical_connectivity 1325 * 1326 * Description: This function check for point to point connectivity between 1327 * two modules by comparing each enable port in link descriptor 1328 * with local and remote ports of port descriptor in 1329 * carrier point-to-point connectivity record according to the 1330 * corresponding file type ( a1, b1, b2...). 1331 * 1332 * Restriction: In order to perform physical check connectivity, it needs to 1333 * compare between 2 AMC Modules, so the use of index ( 1 and 2 ) 1334 * can facilitate the comparison in this case. 1335 * 1336 * Input: record1: is an AMC p2p record for an AMC module 1337 * record2 is an AMC p2p record for an On-Carrier record or an AMC module 1338 * char* opt: option string that will tell if a matching result, unmatched 1339 * result or all the results will be displayed. 1340 * file_type1: indicates type of the first module 1341 * file_type2: indicates type of the second module 1342 * 1343 * Output: None 1344 * 1345 * Global: None 1346 * 1347 * Return: return OK_STATUS if both link are matched, otherwise 1348 * return ERROR_STATUS 1349 * 1350 ***************************************************************************/ 1351 static int 1352 ipmi_ek_check_physical_connectivity( 1353 struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, 1354 struct ipmi_ek_amc_p2p_connectivity_record record2, int index2, 1355 struct ipmi_ek_multi_header * record, 1356 int filetype1, int filetype2, char * option ) 1357 { 1358 int return_status = OK_STATUS; 1359 1360 if ( record == NULL ){ 1361 printf("NO Carrier p2p connectivity !\n"); 1362 return_status = ERROR_STATUS; 1363 } 1364 else{ 1365 #define INVALID_AMC_SITE_NUMBER -1 1366 int index = START_DATA_OFFSET; 1367 int amc_site = INVALID_AMC_SITE_NUMBER; 1368 struct fru_picmgext_carrier_p2p_record rsc_desc; 1369 struct fru_picmgext_carrier_p2p_descriptor * port_desc = NULL; 1370 1371 /* Get the physical connectivity record */ 1372 while ( index < record->header.len ) { 1373 rsc_desc.resource_id = record->data[index++]; 1374 rsc_desc.p2p_count = record->data[index++]; 1375 /* carrier p2p record starts with on-carrier device */ 1376 if ( (rsc_desc.resource_id == record1.rsc_id) 1377 || 1378 (rsc_desc.resource_id == record2.rsc_id) 1379 ){ 1380 if (rsc_desc.p2p_count <= 0){ 1381 printf("No p2p count\n"); 1382 return_status = ERROR_STATUS; 1383 } 1384 else{ 1385 port_desc = malloc ( rsc_desc.p2p_count * 1386 sizeof(struct fru_picmgext_carrier_p2p_descriptor) ); 1387 index = ipmi_ek_get_resource_descriptor( rsc_desc.p2p_count, 1388 index, port_desc, record ); 1389 amc_site = INVALID_AMC_SITE_NUMBER; 1390 break; 1391 } 1392 } 1393 else{ /* carrier p2p record starts with AMC module */ 1394 if (rsc_desc.resource_id == AMC_MODULE){ 1395 if (filetype1 != ON_CARRIER_FRU_FILE){ 1396 amc_site = filetype1; 1397 } 1398 else{ 1399 amc_site = filetype2; 1400 } 1401 } 1402 else{ 1403 amc_site = rsc_desc.resource_id & 0x0f; 1404 } 1405 if ( amc_site > 0 ){ 1406 if ( (amc_site == filetype1) || (amc_site == filetype2) ){ 1407 port_desc = malloc ( rsc_desc.p2p_count * 1408 sizeof(struct fru_picmgext_carrier_p2p_descriptor) ); 1409 index = ipmi_ek_get_resource_descriptor( rsc_desc.p2p_count, 1410 index, port_desc, record ); 1411 break; 1412 } 1413 } 1414 else{ 1415 return_status = ERROR_STATUS; 1416 } 1417 } 1418 /*If the record doesn't contain the same AMC site number in command 1419 * line, go to the next record 1420 */ 1421 index += ( sizeof(struct fru_picmgext_carrier_p2p_descriptor) * 1422 rsc_desc.p2p_count ); 1423 } 1424 1425 if ( (port_desc != NULL) && (return_status != ERROR_STATUS) ){ 1426 int j=0; 1427 1428 for ( j = 0; j < rsc_desc.p2p_count; j++ ){ 1429 /* Compare only enable channel descriptor */ 1430 if ( record1.ch_desc[index1].lane0port != DISABLE_PORT ){ 1431 /* matching result from channel descriptor comparison */ 1432 tboolean match_lane = FALSE; 1433 1434 match_lane = ipmi_ek_compare_channel_descriptor ( 1435 record1.ch_desc[index1], record2.ch_desc[index2], 1436 port_desc, j, rsc_desc.resource_id ); 1437 1438 if ( match_lane ){ 1439 if ( filetype1 != ON_CARRIER_FRU_FILE ){ 1440 if ( ( 1441 (filetype1 == (rsc_desc.resource_id & 0x0f)) 1442 && 1443 (filetype2 ==(port_desc[j].remote_resource_id &0x0f)) 1444 ) 1445 || 1446 ( 1447 (filetype2 == (rsc_desc.resource_id & 0x0f)) 1448 && 1449 (filetype1 ==(port_desc[j].remote_resource_id &0x0f)) 1450 ) 1451 ){ 1452 if ( ! (strcmp(option, "unmatch") == 0) ){ 1453 printf("%s port %d ==> %s port %d\n", 1454 val2str(filetype2, ipmi_ekanalyzer_module_type), 1455 record1.ch_desc[index1].lane0port, 1456 val2str(filetype1, ipmi_ekanalyzer_module_type), 1457 record2.ch_desc[index2].lane0port); 1458 } 1459 return_status = OK_STATUS; 1460 1461 break; 1462 } 1463 else{ 1464 if (verbose == LOG_DEBUG){ 1465 printf("No point 2 point connectivity\n"); 1466 } 1467 return_status = ERROR_STATUS; 1468 } 1469 } 1470 else{ 1471 if ( (record2.rsc_id == (rsc_desc.resource_id) ) 1472 && 1473 (filetype2 == (port_desc[j].remote_resource_id & 0x0f)) 1474 ){ 1475 if ( ! (strcmp(option, "unmatch") == 0) ){ 1476 printf("%s port %d ==> %s port %d\n", 1477 val2str(filetype2, ipmi_ekanalyzer_module_type), 1478 record1.ch_desc[index1].lane0port, 1479 val2str(filetype1, ipmi_ekanalyzer_module_type), 1480 record2.ch_desc[index2].lane0port); 1481 } 1482 return_status = OK_STATUS; 1483 break; 1484 } 1485 else if ( (filetype2 == (rsc_desc.resource_id & 0x0f) ) 1486 && 1487 (record2.rsc_id == (port_desc[j].remote_resource_id)) 1488 ){ 1489 if ( ! (strcmp(option, "unmatch") == 0) ){ 1490 printf("%s port %d ==> %s %x port %d\n", 1491 val2str(filetype2, ipmi_ekanalyzer_module_type), 1492 record1.ch_desc[index1].lane0port, 1493 val2str(filetype1, ipmi_ekanalyzer_module_type), 1494 record2.rsc_id,record2.ch_desc[index2].lane0port); 1495 } 1496 return_status = OK_STATUS; 1497 break; 1498 } 1499 else{ 1500 if (verbose == LOG_DEBUG){ 1501 printf("No point 2 point connectivity\n"); 1502 } 1503 return_status = ERROR_STATUS; 1504 } 1505 } 1506 } 1507 else{ 1508 if (verbose == LOG_DEBUG){ 1509 printf("No point 2 point connectivity\n"); 1510 } 1511 return_status = ERROR_STATUS; 1512 } 1513 } 1514 else{ /*If the link is disable, the result is always true*/ 1515 return_status = OK_STATUS; 1516 } 1517 } 1518 } 1519 else{ 1520 if (verbose == LOG_WARN){ 1521 printf("Invalid Carrier p2p connectivity record\n"); 1522 } 1523 return_status = ERROR_STATUS; 1524 } 1525 if (port_desc != NULL){ 1526 free(port_desc); 1527 port_desc = NULL; 1528 } 1529 } 1530 return return_status; 1531 } 1532 1533 /************************************************************************** 1534 * 1535 * Function name: ipmi_ek_compare_link 1536 * 1537 * Description: This function compares link grouping id of each 1538 * amc p2p connectiviy record 1539 * 1540 * Restriction: None 1541 * 1542 * Input: record1: is an AMC p2p record for an AMC module 1543 * record2 is an AMC p2p record for an On-Carrier record or an AMC module 1544 * char* opt: option string that will tell if a matching result, unmatched 1545 * result or all the results will be displayed. 1546 * file_type1: indicates type of the first module 1547 * file_type2: indicates type of the second module 1548 * 1549 * Output: None 1550 * 1551 * Global: None 1552 * 1553 * Return: return 0 if both link are matched, otherwise return -1 1554 * 1555 ***************************************************************************/ 1556 static int 1557 ipmi_ek_compare_link( struct ipmi_ek_multi_header * physic_record, 1558 struct ipmi_ek_amc_p2p_connectivity_record record1, 1559 struct ipmi_ek_amc_p2p_connectivity_record record2, char * opt, 1560 int file_type1, int file_type2 ) 1561 { 1562 int result = ERROR_STATUS; 1563 int index1 = 0; /*index for AMC module*/ 1564 int index2 = 0; /*index for On-carrier type*/ 1565 1566 record1.matching_result = malloc ( record1.link_desc_count * sizeof(int) ); 1567 record2.matching_result = malloc ( record2.link_desc_count * sizeof(int) ); 1568 /*Initialize all the matching_result to false*/ 1569 for( index2 = 0; index2 < record2.link_desc_count; index2++ ){ 1570 record2.matching_result[index2] = FALSE; 1571 } 1572 for( index1 = 0; index1 < record1.link_desc_count; index1++ ){ 1573 for( index2 = 0; index2 < record2.link_desc_count; index2++ ){ 1574 if( record1.link_desc[index1].group_id == 0 ){ 1575 if( record2.link_desc[index2].group_id == 0 ){ 1576 result = ipmi_ek_compare_link_descriptor( 1577 record1, index1, record2, index2 ); 1578 if ( result == OK_STATUS ){ 1579 /*Calculate the index for Channel descriptor in function of 1580 * link designator channel ID 1581 */ 1582 /*first channel_id in the AMC Link descriptor of record1*/ 1583 static int flag_first_link1; 1584 int index_ch_desc1; /*index of channel descriptor */ 1585 /*first channel_id in the AMC Link descriptor of record2*/ 1586 static int flag_first_link2; 1587 int index_ch_desc2; /*index of channel descriptor*/ 1588 1589 if (index1==0){ /*this indicate the first link is encounter*/ 1590 flag_first_link1 = record1.link_desc[index1].channel_id; 1591 } 1592 index_ch_desc1 = record1.link_desc[index1].channel_id - 1593 flag_first_link1; 1594 if (index2==0){ 1595 flag_first_link2 = record2.link_desc[index2].channel_id; 1596 } 1597 index_ch_desc2 = record2.link_desc[index2].channel_id - 1598 flag_first_link2; 1599 /*Check for physical connectivity for each link*/ 1600 result = ipmi_ek_check_physical_connectivity ( record1, 1601 index_ch_desc1, record2, index_ch_desc2, 1602 physic_record, file_type1, file_type2, opt ); 1603 if ( result == OK_STATUS ){ 1604 /*Display the result if option = match or all*/ 1605 if ( (strcmp( opt, "match" ) == 0) 1606 || (strcmp( opt, "all" ) == 0) 1607 || (strcmp( opt, "default" ) == 0) 1608 ){ 1609 tboolean isOEMtype = FALSE; 1610 printf(" Matching Result\n"); 1611 isOEMtype = ipmi_ek_display_link_descriptor( file_type1, 1612 record2.rsc_id, 1613 "From", record2.link_desc[index2]); 1614 if (isOEMtype){ 1615 ipmi_ek_display_oem_guid (record2); 1616 } 1617 isOEMtype = ipmi_ek_display_link_descriptor( file_type2, 1618 record1.rsc_id, 1619 "To", record1.link_desc[index1] ); 1620 if (isOEMtype){ 1621 ipmi_ek_display_oem_guid (record1); 1622 } 1623 printf(" %s\n", STAR_LINE_LIMITER); 1624 } 1625 record2.matching_result[index2] = TRUE; 1626 record1.matching_result[index1] = TRUE; 1627 /*quit the fist loop since the match is found*/ 1628 index2 = record2.link_desc_count; 1629 } 1630 } 1631 } 1632 } 1633 else { /*Link Grouping ID is non zero, Compare all link descriptor 1634 * that has non-zero link grouping id together 1635 */ 1636 if (record2.link_desc[index2].group_id != 0 ){ 1637 result = ipmi_ek_compare_link_descriptor( 1638 record1, index1, record2, index2 ); 1639 if ( result == OK_STATUS ){ 1640 /*Calculate the index for Channel descriptor in function of 1641 * link designator channel ID 1642 */ 1643 /*first channel_id in the AMC Link descriptor of record1*/ 1644 static int flag_first_link1; 1645 int index_ch_desc1; /*index of channel descriptor */ 1646 /*first channel_id in the AMC Link descriptor of record2*/ 1647 static int flag_first_link2; 1648 int index_ch_desc2; /*index of channel descriptor*/ 1649 1650 if (index1==0){ /*this indicate the first link is encounter*/ 1651 flag_first_link1 = record1.link_desc[index1].channel_id; 1652 } 1653 index_ch_desc1 = record1.link_desc[index1].channel_id - 1654 flag_first_link1; 1655 if (index2==0){ 1656 flag_first_link2 = record2.link_desc[index2].channel_id; 1657 } 1658 index_ch_desc2 = record2.link_desc[index2].channel_id - 1659 flag_first_link2; 1660 /*Check for physical connectivity for each link*/ 1661 result = ipmi_ek_check_physical_connectivity ( 1662 record1, index_ch_desc1, record2, index_ch_desc2, 1663 physic_record, file_type1, file_type2, opt ); 1664 if ( result == OK_STATUS ){ 1665 if ( (strcmp( opt, "match" ) == 0) 1666 || (strcmp( opt, "all" ) == 0) 1667 || (strcmp( opt, "default" ) == 0) 1668 ){ 1669 tboolean isOEMtype = FALSE; 1670 printf(" Matching Result\n"); 1671 isOEMtype = ipmi_ek_display_link_descriptor( file_type1, 1672 record2.rsc_id, 1673 "From", record2.link_desc[index2] ); 1674 if ( isOEMtype ){ 1675 ipmi_ek_display_oem_guid (record2); 1676 } 1677 isOEMtype = ipmi_ek_display_link_descriptor( file_type2, 1678 record1.rsc_id, 1679 "To", record1.link_desc[index1] ); 1680 if (isOEMtype){ 1681 ipmi_ek_display_oem_guid (record1); 1682 } 1683 printf(" %s\n", STAR_LINE_LIMITER); 1684 } 1685 record2.matching_result[index2] = TRUE; 1686 record1.matching_result[index1] = TRUE; 1687 /*leave the fist loop since the match is found*/ 1688 index2 = record2.link_desc_count; 1689 } 1690 } 1691 } 1692 } 1693 } 1694 } 1695 1696 if ( (strcmp(opt, "unmatch") == 0) || (strcmp(opt, "all") == 0) ){ 1697 int isOEMtype = FALSE; 1698 printf(" Unmatching result\n"); 1699 for (index1 = 0; index1 < record1.link_desc_count; index1++){ 1700 isOEMtype = ipmi_ek_display_link_descriptor( file_type2, 1701 record1.rsc_id, "", record1.link_desc[index1] ); 1702 if ( isOEMtype ){ 1703 ipmi_ek_display_oem_guid (record1); 1704 } 1705 printf(" %s\n", STAR_LINE_LIMITER); 1706 } 1707 for ( index2 = 0; index2 < record2.link_desc_count; index2++){ 1708 if ( !record2.matching_result[index2] ){ 1709 isOEMtype = ipmi_ek_display_link_descriptor( file_type1, 1710 record2.rsc_id, "", record2.link_desc[index2] ); 1711 if ( isOEMtype ){ 1712 ipmi_ek_display_oem_guid (record2); 1713 } 1714 printf(" %s\n", STAR_LINE_LIMITER); 1715 } 1716 } 1717 } 1718 1719 free(record1.matching_result); 1720 record1.matching_result = NULL; 1721 free(record2.matching_result); 1722 record2.matching_result = NULL; 1723 1724 return result; 1725 } 1726 1727 /************************************************************************** 1728 * 1729 * Function name: ipmi_ek_compare_channel_descriptor 1730 * 1731 * Description: This function compares 2 channel descriptors of 2 AMC 1732 * point-to-point connectivity records with port descriptor of 1733 * carrier point-to-point connectivity record. The comparison is 1734 * made between each enable port only. 1735 * 1736 * Restriction: Reference: AMC.0 specification: 1737 * - Table 3-14 for port descriptor 1738 * - Table 3-17 for channel descriptor 1739 * 1740 * Input: ch_desc1: first channel descriptor 1741 * ch_desc2: second channel descriptor 1742 * port_desc: a pointer that contain a list of port descriptor 1743 * index_port: index of the port descriptor 1744 * rsc_id: resource id that represents as local resource id in the 1745 * resource descriptor table. 1746 * 1747 * Output: None 1748 * 1749 * Global: None 1750 * 1751 * Return: return TRUE if both channel descriptor are matched, 1752 * or FALSE otherwise 1753 * 1754 ***************************************************************************/ 1755 static tboolean 1756 ipmi_ek_compare_channel_descriptor( 1757 struct fru_picmgext_amc_channel_desc_record ch_desc1, 1758 struct fru_picmgext_amc_channel_desc_record ch_desc2, 1759 struct fru_picmgext_carrier_p2p_descriptor * port_desc, 1760 int index_port, unsigned char rsc_id ) 1761 { 1762 tboolean match_lane = FALSE; 1763 1764 /* carrier p2p record start with AMC_MODULE as local port */ 1765 if ( (rsc_id & AMC_MODULE) == AMC_MODULE ){ 1766 if ( (ch_desc1.lane0port == port_desc[index_port].local_port) 1767 && 1768 (ch_desc2.lane0port == port_desc[index_port].remote_port) 1769 ){ 1770 /*check if the port is enable*/ 1771 if (ch_desc1.lane1port != DISABLE_PORT){ 1772 index_port ++; 1773 if ( (ch_desc1.lane1port == port_desc[index_port].local_port) 1774 && 1775 (ch_desc2.lane1port == port_desc[index_port].remote_port) 1776 ){ 1777 if (ch_desc1.lane2port != DISABLE_PORT){ 1778 index_port++; 1779 if ( (ch_desc1.lane2port == port_desc[index_port].local_port) 1780 && 1781 (ch_desc2.lane2port == port_desc[index_port].remote_port) 1782 ){ 1783 if (ch_desc1.lane3port != DISABLE_PORT){ 1784 index_port++; 1785 if ( (ch_desc1.lane3port == 1786 port_desc[index_port].local_port) 1787 && 1788 (ch_desc2.lane3port == 1789 port_desc[index_port].remote_port) 1790 ){ 1791 match_lane = TRUE; 1792 } 1793 } 1794 else{ 1795 match_lane = TRUE; 1796 } 1797 } /* end of if lane2port */ 1798 } 1799 else{ 1800 match_lane = TRUE; 1801 } 1802 } /* end of if lane1port */ 1803 } 1804 else{ /*if the port is disable, the compare result is always true*/ 1805 match_lane = TRUE; 1806 } 1807 }/* end of if lane0port */ 1808 } 1809 /* carrier p2p record start with Carrier as local port */ 1810 else{ 1811 if ( (ch_desc1.lane0port == port_desc[index_port].remote_port) 1812 && 1813 (ch_desc2.lane0port == port_desc[index_port].local_port) 1814 ){ 1815 if (ch_desc1.lane1port != DISABLE_PORT){ 1816 index_port ++; 1817 if ( (ch_desc1.lane1port == port_desc[index_port].remote_port) 1818 && 1819 (ch_desc2.lane1port == port_desc[index_port].local_port) 1820 ){ 1821 if (ch_desc1.lane2port != DISABLE_PORT){ 1822 index_port++; 1823 if ( (ch_desc1.lane2port == port_desc[index_port].remote_port) 1824 && 1825 (ch_desc2.lane2port == port_desc[index_port].local_port) 1826 ){ 1827 if (ch_desc1.lane3port != DISABLE_PORT){ 1828 index_port++; 1829 if ( (ch_desc1.lane3port == 1830 port_desc[index_port].remote_port) 1831 && 1832 (ch_desc2.lane3port == 1833 port_desc[index_port].local_port) 1834 ){ 1835 match_lane = TRUE; 1836 } 1837 } 1838 else{ 1839 match_lane = TRUE; 1840 } 1841 } /* end of if lane2port */ 1842 } 1843 else{ 1844 match_lane = TRUE; 1845 } 1846 } /* end of if lane1port */ 1847 } 1848 else{ 1849 match_lane = TRUE; 1850 } 1851 } /* end of if lane0port */ 1852 } 1853 1854 return match_lane; 1855 } 1856 1857 /************************************************************************** 1858 * 1859 * Function name: ipmi_ek_compare_link_descriptor 1860 * 1861 * Description: This function compares 2 link descriptors of 2 1862 * amc p2p connectiviy record 1863 * 1864 * Restriction: None 1865 * 1866 * Input: record1: AMC p2p connectivity record of the 1rst AMC or Carrier Module 1867 * index1: index of AMC link descriptor in 1rst record 1868 * record2: AMC p2p connectivity record of the 2nd AMC or Carrier Module 1869 * index1: index of AMC link descriptor in 2nd record 1870 * 1871 * Output: None 1872 * 1873 * Global: None 1874 * 1875 * Return: return OK_STATUS if both link are matched, 1876 * otherwise return ERROR_STATUS 1877 * 1878 ***************************************************************************/ 1879 static int 1880 ipmi_ek_compare_link_descriptor( 1881 struct ipmi_ek_amc_p2p_connectivity_record record1, 1882 int index1, 1883 struct ipmi_ek_amc_p2p_connectivity_record record2, 1884 int index2) 1885 { 1886 int result = ERROR_STATUS; 1887 if (record1.link_desc[index1].type != record2.link_desc[index2].type) { 1888 return ERROR_STATUS; 1889 } 1890 /* if it is an OEM type, we compare the OEM GUID */ 1891 if ((record1.link_desc[index1].type >= LOWER_OEM_TYPE) 1892 && (record1.link_desc[index1].type <= UPPER_OEM_TYPE)) { 1893 if ((record1.guid_count == 0) && (record2.guid_count == 0)) { 1894 /*there is no GUID for comparison, so the result is always OK*/ 1895 result = OK_STATUS; 1896 } else { 1897 int i = 0; 1898 int j = 0; 1899 for (i = 0; i < record1.guid_count; i++) { 1900 for (j = 0; j < record2.guid_count; j++) { 1901 if (memcmp(&record1.oem_guid[i], 1902 &record2.oem_guid[j], 1903 SIZE_OF_GUID) == 0) { 1904 result = OK_STATUS; 1905 break; 1906 } 1907 } 1908 } 1909 } 1910 } else { 1911 result = OK_STATUS; 1912 } 1913 if (result != OK_STATUS) { 1914 return result; 1915 } 1916 if (record1.link_desc[index1].type_ext == record2.link_desc[index2].type_ext) { 1917 unsigned char asym[COMPARE_CANDIDATE]; 1918 int offset = 0; 1919 asym[offset++] = record1.link_desc[index1].asym_match; 1920 asym[offset] = record2.link_desc[index2].asym_match; 1921 result = ipmi_ek_compare_asym (asym); 1922 if (result == OK_STATUS){ 1923 struct fru_picmgext_amc_link_desc_record link[COMPARE_CANDIDATE]; 1924 int index = 0; 1925 link[index++] = record1.link_desc[index1]; 1926 link[index] = record2.link_desc[index2]; 1927 result = ipmi_ek_compare_number_of_enable_port(link); 1928 } else { 1929 result = ERROR_STATUS; 1930 } 1931 } else { 1932 result = ERROR_STATUS; 1933 } 1934 return result; 1935 } 1936 1937 /************************************************************************** 1938 * 1939 * Function name: ipmi_ek_compare_asym 1940 * 1941 * Description: This function compares 2 asymetric match of 2 1942 * amc link descriptors 1943 * 1944 * Restriction: None 1945 * 1946 * Input: asym[COMPARE_CANDIDATE]: Contain 2 asymetric match for comparison 1947 * 1948 * Output: None 1949 * 1950 * Global: None 1951 * 1952 * Return: return 0 if both asym. match are matched, otherwise return -1 1953 * 1954 ***************************************************************************/ 1955 1956 static int 1957 ipmi_ek_compare_asym(unsigned char asym[COMPARE_CANDIDATE]) 1958 { 1959 int return_value = ERROR_STATUS; 1960 int first_index = 0; 1961 int second_index = 1; 1962 1963 if ((asym[first_index] == 0) && (asym[second_index] == 0)) { 1964 return_value = OK_STATUS; 1965 } else if ((asym[first_index] & asym[second_index]) == 0) { 1966 return_value = OK_STATUS; 1967 } else { 1968 return_value = ERROR_STATUS; 1969 } 1970 return return_value; 1971 } 1972 1973 /************************************************************************** 1974 * 1975 * Function name: ipmi_ek_compare_link_descriptor 1976 * 1977 * Description: This function compare number of enble port of Link designator 1978 * 1979 * Restriction: None 1980 * 1981 * Input: link_designator1: first link designator 1982 * link_designator2: second link designator 1983 * 1984 * Output: None 1985 * 1986 * Global: None 1987 * 1988 * Return: return 0 if both link are matched, otherwise return -1 1989 * 1990 ***************************************************************************/ 1991 static int 1992 ipmi_ek_compare_number_of_enable_port( 1993 struct fru_picmgext_amc_link_desc_record link_desc[COMPARE_CANDIDATE]) 1994 { 1995 int amc_port_count = 0; 1996 int carrier_port_count = 0; 1997 int return_value = ERROR_STATUS; 1998 int index = 0; 1999 2000 if (link_desc[index].port_flag_0) { 2001 /*bit 0 indicates port 0*/ 2002 amc_port_count++; 2003 } 2004 if (link_desc[index].port_flag_1) { 2005 /*bit 1 indicates port 1*/ 2006 amc_port_count++; 2007 } 2008 if (link_desc[index].port_flag_2) { 2009 /*bit 2 indicates port 2*/ 2010 amc_port_count++; 2011 } 2012 if (link_desc[index++].port_flag_3) { 2013 /*bit 3 indicates port 3*/ 2014 amc_port_count++; 2015 } 2016 2017 /* 2nd link designator */ 2018 if (link_desc[index].port_flag_0) { 2019 /*bit 0 indicates port 0*/ 2020 carrier_port_count++; 2021 } 2022 if (link_desc[index].port_flag_1) { 2023 /*bit 1 indicates port 1*/ 2024 carrier_port_count++; 2025 } 2026 if (link_desc[index].port_flag_2) { 2027 /*bit 2 indicates port 2*/ 2028 carrier_port_count++; 2029 } 2030 if (link_desc[index].port_flag_3) { 2031 /*bit 3 indicates port 3*/ 2032 carrier_port_count++; 2033 } 2034 2035 if (carrier_port_count == amc_port_count) { 2036 return_value = OK_STATUS; 2037 } else { 2038 return_value = ERROR_STATUS; 2039 } 2040 return return_value; 2041 } 2042 2043 /************************************************************************** 2044 * 2045 * Function name: ipmi_ek_display_link_descriptor 2046 * 2047 * Description: Display the link descriptor of an AMC p2p connectivity record 2048 * 2049 * Restriction: See AMC.0 or PICMG 3.0 specification for detail about bit masks 2050 * 2051 * Input: file_type: module type. 2052 * rsc_id: resource id 2053 * char* str: indicates if it is a source (its value= "From") or a 2054 * destination (its value = "To"). ( it is set to "" if it is not 2055 * a source nor destination 2056 * link_desc: AMC link descriptor 2057 * asym: asymetric match 2058 * 2059 * Output: None 2060 * 2061 * Global: None 2062 * 2063 * Return: None 2064 * 2065 ***************************************************************************/ 2066 static tboolean 2067 ipmi_ek_display_link_descriptor(int file_type, unsigned char rsc_id, 2068 char *str, 2069 struct fru_picmgext_amc_link_desc_record link_desc) 2070 { 2071 tboolean isOEMtype = FALSE; 2072 if (file_type == ON_CARRIER_FRU_FILE) { 2073 printf(" - %s On-Carrier Device ID %d\n", str, 2074 (rsc_id & 0x0f)); 2075 } else { 2076 printf(" - %s %s\n", str, val2str(file_type, 2077 ipmi_ekanalyzer_module_type)); 2078 } 2079 printf(" - Channel ID %d || ", link_desc.channel_id); 2080 printf("%s", link_desc.port_flag_0 ? "Lane 0: enable" : ""); 2081 printf("%s", link_desc.port_flag_1 ? ", Lane 1: enable" : ""); 2082 printf("%s", link_desc.port_flag_2 ? ", Lane 2: enable" : ""); 2083 printf("%s", link_desc.port_flag_3 ? ", Lane 3: enable" : ""); 2084 printf("\n"); 2085 printf(" - Link Type: %s \n", val2str(link_desc.type, 2086 ipmi_ekanalyzer_link_type)); 2087 switch (link_desc.type) { 2088 case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: 2089 case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: 2090 case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: 2091 printf(" - Link Type extension: %s\n", 2092 val2str(link_desc.type_ext, 2093 ipmi_ekanalyzer_extension_PCIE)); 2094 printf(" - Link Group ID: %d || ", link_desc.group_id); 2095 printf("Link Asym. Match: %d - %s\n", 2096 link_desc.asym_match, 2097 val2str(link_desc.asym_match, 2098 ipmi_ekanalyzer_asym_PCIE)); 2099 break; 2100 case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: 2101 printf(" - Link Type extension: %s\n", 2102 val2str(link_desc.type_ext, 2103 ipmi_ekanalyzer_extension_ETHERNET)); 2104 printf(" - Link Group ID: %d || ", link_desc.group_id); 2105 printf("Link Asym. Match: %d - %s\n", 2106 link_desc.asym_match, 2107 val2str(link_desc.asym_match, 2108 ipmi_ekanalyzer_asym_PCIE)); 2109 break; 2110 case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: 2111 printf(" - Link Type extension: %s\n", 2112 val2str(link_desc.type_ext, 2113 ipmi_ekanalyzer_extension_STORAGE)); 2114 printf(" - Link Group ID: %d || ", 2115 link_desc.group_id); 2116 printf("Link Asym. Match: %d - %s\n", 2117 link_desc.asym_match, 2118 val2str(link_desc.asym_match, 2119 ipmi_ekanalyzer_asym_STORAGE)); 2120 break; 2121 default: 2122 printf(" - Link Type extension: %i\n", 2123 link_desc.type_ext); 2124 printf(" - Link Group ID: %d || ", 2125 link_desc.group_id); 2126 printf("Link Asym. Match: %i\n", 2127 link_desc.asym_match); 2128 break; 2129 } 2130 /* return as OEM type if link type indicates OEM */ 2131 if ((link_desc.type >= LOWER_OEM_TYPE) 2132 && (link_desc.type <= UPPER_OEM_TYPE)) { 2133 isOEMtype = TRUE; 2134 } 2135 return isOEMtype; 2136 } 2137 2138 /************************************************************************** 2139 * 2140 * Function name: ipmi_ek_display_oem_guid 2141 * 2142 * Description: Display the oem guid of an AMC p2p connectivity record 2143 * 2144 * Restriction: None 2145 * 2146 * Input: amc_record: AMC p2p connectivity record 2147 * 2148 * Output: None 2149 * 2150 * Global: None 2151 * 2152 * Return: None 2153 * 2154 ***************************************************************************/ 2155 static void 2156 ipmi_ek_display_oem_guid(struct ipmi_ek_amc_p2p_connectivity_record amc_record) 2157 { 2158 int index_oem = 0; 2159 int index = 0; 2160 if (amc_record.guid_count == 0) { 2161 printf("\tThere is no OEM GUID for this module\n"); 2162 } 2163 for (index_oem = 0; index_oem < amc_record.guid_count; index_oem++) { 2164 printf(" - GUID: "); 2165 for (index = 0; index < SIZE_OF_GUID; index++) { 2166 printf("%02x", 2167 amc_record.oem_guid[index_oem].guid[index]); 2168 /* For a better look: putting a "-" after displaying 2169 * four bytes of GUID 2170 */ 2171 if (!(index % 4)){ 2172 printf("-"); 2173 } 2174 } 2175 printf("\n"); 2176 } 2177 } 2178 2179 /************************************************************************** 2180 * 2181 * Function name: ipmi_ek_create_amc_p2p_record 2182 * 2183 * Description: this function create an AMC point 2 point connectivity record 2184 * that contain link descriptor, channel descriptor, oem guid 2185 * 2186 * Restriction: Reference: AMC.0 Specification Table 3-16 2187 * 2188 * Input: record: a pointer to FRU multi record 2189 * 2190 * Output: amc_record: a pointer to the created AMC p2p record 2191 * 2192 * Global: None 2193 * 2194 * Return: Return OK_STATUS on success, or ERROR_STATUS if no record has been 2195 * created. 2196 * 2197 ***************************************************************************/ 2198 static int 2199 ipmi_ek_create_amc_p2p_record(struct ipmi_ek_multi_header *record, 2200 struct ipmi_ek_amc_p2p_connectivity_record *amc_record) 2201 { 2202 int index_data = START_DATA_OFFSET; 2203 int return_status = OK_STATUS; 2204 2205 amc_record->guid_count = record->data[index_data++]; 2206 if (amc_record->guid_count > 0) { 2207 int index_oem = 0; 2208 amc_record->oem_guid = malloc(amc_record->guid_count * \ 2209 sizeof(struct fru_picmgext_guid)); 2210 for (index_oem = 0; index_oem < amc_record->guid_count; 2211 index_oem++) { 2212 memcpy(&amc_record->oem_guid[index_oem].guid, 2213 &record->data[index_data], 2214 SIZE_OF_GUID); 2215 index_data += (int)SIZE_OF_GUID; 2216 } 2217 amc_record->rsc_id = record->data[index_data++]; 2218 amc_record->ch_count = record->data[index_data++]; 2219 /* Calculate link descriptor count */ 2220 amc_record->link_desc_count = ((record->header.len) - 8 - 2221 (SIZE_OF_GUID*amc_record->guid_count) - 2222 (FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE * 2223 amc_record->ch_count)) / 5 ; 2224 } else { 2225 amc_record->rsc_id = record->data[index_data++]; 2226 amc_record->ch_count = record->data[index_data++]; 2227 /* Calculate link descriptor count see spec AMC.0 for detail */ 2228 amc_record->link_desc_count = ((record->header.len) - 8 - 2229 (FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE * 2230 amc_record->ch_count)) / 5; 2231 } 2232 2233 if (amc_record->ch_count > 0) { 2234 int ch_index = 0; 2235 amc_record->ch_desc = malloc((amc_record->ch_count) * \ 2236 sizeof(struct fru_picmgext_amc_channel_desc_record)); 2237 for (ch_index = 0; ch_index < amc_record->ch_count; 2238 ch_index++) { 2239 unsigned int data; 2240 struct fru_picmgext_amc_channel_desc_record *src, *dst; 2241 data = record->data[index_data] | 2242 (record->data[index_data + 1] << 8) | 2243 (record->data[index_data + 2] << 16); 2244 2245 src = (struct fru_picmgext_amc_channel_desc_record *)&data; 2246 dst = (struct fru_picmgext_amc_channel_desc_record *) 2247 &amc_record->ch_desc[ch_index]; 2248 2249 dst->lane0port = src->lane0port; 2250 dst->lane1port = src->lane1port; 2251 dst->lane2port = src->lane2port; 2252 dst->lane3port = src->lane3port; 2253 index_data += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE; 2254 } 2255 } 2256 if (amc_record->link_desc_count > 0) { 2257 int i=0; 2258 amc_record->link_desc = malloc(amc_record->link_desc_count * \ 2259 sizeof(struct fru_picmgext_amc_link_desc_record)); 2260 for (i = 0; i< amc_record->link_desc_count; i++) { 2261 unsigned int data[2]; 2262 struct fru_picmgext_amc_link_desc_record *src, *dst; 2263 data[0] = record->data[index_data] | 2264 (record->data[index_data + 1] << 8) | 2265 (record->data[index_data + 2] << 16) | 2266 (record->data[index_data + 3] << 24); 2267 2268 data[1] = record->data[index_data + 4]; 2269 src = (struct fru_picmgext_amc_link_desc_record*)&data; 2270 dst = (struct fru_picmgext_amc_link_desc_record*) 2271 &amc_record->link_desc[i]; 2272 2273 dst->channel_id = src->channel_id; 2274 dst->port_flag_0 = src->port_flag_0; 2275 dst->port_flag_1 = src->port_flag_1; 2276 dst->port_flag_2 = src->port_flag_2; 2277 dst->port_flag_3 = src->port_flag_3; 2278 dst->type = src->type; 2279 dst->type_ext = src->type_ext; 2280 dst->group_id = src->group_id; 2281 dst->asym_match = src->asym_match; 2282 index_data += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE; 2283 } 2284 } else { 2285 return_status = ERROR_STATUS; 2286 } 2287 return return_status; 2288 } 2289 2290 /************************************************************************** 2291 * 2292 * Function name: ipmi_ek_get_resource_descriptor 2293 * 2294 * Description: this function create the resource descriptor of Carrier p2p 2295 * connectivity record. 2296 * 2297 * Restriction: None 2298 * 2299 * Input: port_count: number of port count 2300 * index: index to the position of data start offset 2301 * record: a pointer to FRU multi record 2302 * 2303 * Output: port_desc: a pointer to the created resource descriptor 2304 * 2305 * Global: None 2306 * 2307 * Return: Return index that indicates the current position of data in record. 2308 * 2309 ***************************************************************************/ 2310 static int 2311 ipmi_ek_get_resource_descriptor(int port_count, int index, 2312 struct fru_picmgext_carrier_p2p_descriptor *port_desc, 2313 struct ipmi_ek_multi_header *record) 2314 { 2315 int num_port = 0; 2316 while (num_port < port_count) { 2317 memcpy(&port_desc[num_port], &record->data[index], 2318 sizeof (struct fru_picmgext_carrier_p2p_descriptor)); 2319 index += sizeof (struct fru_picmgext_carrier_p2p_descriptor); 2320 num_port++; 2321 } 2322 return index; 2323 } 2324 2325 /************************************************************************** 2326 * 2327 * Function name: ipmi_ek_display_fru_header 2328 * 2329 * Description: this function display FRU header offset from a FRU binary file 2330 * 2331 * Restriction: Reference: IPMI Platform Management FRU Information Storage 2332 * Definition V1.0, Section 8 2333 * 2334 * Input: filename: name of FRU binary file 2335 * 2336 * Output: None 2337 * 2338 * Global: None 2339 * 2340 * Return: Return OK_STATUS on sucess, ERROR_STATUS on error 2341 * 2342 ***************************************************************************/ 2343 static int 2344 ipmi_ek_display_fru_header(char *filename) 2345 { 2346 FILE *input_file; 2347 struct fru_header header; 2348 int ret = 0; 2349 2350 input_file = fopen(filename, "r"); 2351 if (input_file == NULL) { 2352 lprintf(LOG_ERR, "File '%s' not found.", filename); 2353 return (ERROR_STATUS); 2354 } 2355 ret = fread(&header, sizeof (struct fru_header), 1, input_file); 2356 if ((ret != 1) || ferror(input_file)) { 2357 lprintf(LOG_ERR, "Failed to read FRU header!"); 2358 fclose(input_file); 2359 return (ERROR_STATUS); 2360 } 2361 printf("%s\n", EQUAL_LINE_LIMITER); 2362 printf("FRU Header Info\n"); 2363 printf("%s\n", EQUAL_LINE_LIMITER); 2364 printf("Format Version :0x%02x %s\n", 2365 (header.version & 0x0f), 2366 ((header.version & 0x0f) == 1) ? "" : "{unsupported}"); 2367 printf("Internal Use Offset :0x%02x\n", header.offset.internal); 2368 printf("Chassis Info Offset :0x%02x\n", header.offset.chassis); 2369 printf("Board Info Offset :0x%02x\n", header.offset.board); 2370 printf("Product Info Offset :0x%02x\n", header.offset.product); 2371 printf("MultiRecord Offset :0x%02x\n", header.offset.multi); 2372 printf("Common header Checksum :0x%02x\n", header.checksum); 2373 2374 fclose(input_file); 2375 return OK_STATUS; 2376 } 2377 2378 /************************************************************************** 2379 * 2380 * Function name: ipmi_ek_display_fru_header_detail 2381 * 2382 * Description: this function display detail FRU header information 2383 * from a FRU binary file. 2384 2385 * 2386 * Restriction: Reference: IPMI Platform Management FRU Information Storage 2387 * Definition V1.0, Section 8 2388 * 2389 * Input: filename: name of FRU binary file 2390 * 2391 * Output: None 2392 * 2393 * Global: None 2394 * 2395 * Return: None 2396 * 2397 ***************************************************************************/ 2398 static int 2399 ipmi_ek_display_fru_header_detail(char *filename) 2400 { 2401 # define FACTOR_OFFSET 8 2402 # define SIZE_MFG_DATE 3 2403 FILE *input_file; 2404 size_t file_offset = 0; 2405 struct fru_header header; 2406 time_t tval; 2407 int ret = 0; 2408 unsigned char data = 0; 2409 unsigned char lan_code = 0; 2410 unsigned char mfg_date[SIZE_MFG_DATE]; 2411 unsigned int board_length = 0; 2412 2413 input_file = fopen(filename, "r"); 2414 if (input_file == NULL) { 2415 lprintf(LOG_ERR, "File '%s' not found.", filename); 2416 return (-1); 2417 } 2418 /* The offset in each fru is in multiple of 8 bytes 2419 * See IPMI Platform Management FRU Information Storage Definition 2420 * for detail 2421 */ 2422 ret = fread(&header, sizeof(struct fru_header), 1, input_file); 2423 if ((ret != 1) || ferror(input_file)) { 2424 lprintf(LOG_ERR, "Failed to read FRU header!"); 2425 fclose(input_file); 2426 return (-1); 2427 } 2428 /*** Display FRU Internal Use Info ***/ 2429 if (!feof(input_file)) { 2430 unsigned char format_version; 2431 unsigned long len = 0; 2432 2433 printf("%s\n", EQUAL_LINE_LIMITER); 2434 printf("FRU Internal Use Info\n"); 2435 printf("%s\n", EQUAL_LINE_LIMITER); 2436 2437 ret = fread(&format_version, 1, 1, input_file); 2438 if ((ret != 1) || ferror(input_file)) { 2439 lprintf(LOG_ERR, "Invalid format version!"); 2440 fclose(input_file); 2441 return (-1); 2442 } 2443 printf("Format Version: %d\n", (format_version & 0x0f)); 2444 2445 if (header.offset.chassis > 0) { 2446 len = (header.offset.chassis * FACTOR_OFFSET) 2447 - (header.offset.internal * FACTOR_OFFSET); 2448 } else { 2449 len = (header.offset.board * FACTOR_OFFSET) 2450 - (header.offset.internal * FACTOR_OFFSET); 2451 } 2452 printf("Length: %ld\n", len); 2453 printf("Data dump:\n"); 2454 while ((len > 0) && (!feof(input_file))) { 2455 unsigned char data; 2456 ret = fread(&data, 1, 1, input_file); 2457 if ((ret != 1) || ferror(input_file)) { 2458 lprintf(LOG_ERR, "Invalid data!"); 2459 fclose(input_file); 2460 return (-1); 2461 } 2462 printf("0x%02x ", data); 2463 len--; 2464 } 2465 printf("\n"); 2466 } 2467 /*** Chassis Info Area ***/ 2468 if (header.offset.chassis != 0) { 2469 long offset = 0; 2470 offset = header.offset.chassis * FACTOR_OFFSET; 2471 ret = ipmi_ek_display_chassis_info_area(input_file, offset); 2472 } 2473 /*** Display FRU Board Info Area ***/ 2474 while (1) { 2475 if (header.offset.board == 0) { 2476 break; 2477 } 2478 ret = fseek(input_file, 2479 (header.offset.board * FACTOR_OFFSET), 2480 SEEK_SET); 2481 if (feof(input_file)) { 2482 break; 2483 } 2484 file_offset = ftell(input_file); 2485 printf("%s\n", EQUAL_LINE_LIMITER); 2486 printf("FRU Board Info Area\n"); 2487 printf("%s\n", EQUAL_LINE_LIMITER); 2488 2489 ret = fread(&data, 1, 1, input_file); /* Format version */ 2490 if ((ret != 1) || ferror(input_file)) { 2491 lprintf(LOG_ERR, "Invalid FRU Format Version!"); 2492 fclose(input_file); 2493 return (-1); 2494 } 2495 printf("Format Version: %d\n", (data & 0x0f)); 2496 if (feof(input_file)) { 2497 break; 2498 } 2499 ret = fread(&data, 1, 1, input_file); /* Board Area Length */ 2500 if ((ret != 1) || ferror(input_file)) { 2501 lprintf(LOG_ERR, "Invalid Board Area Length!"); 2502 fclose(input_file); 2503 return (-1); 2504 } 2505 board_length = (data * FACTOR_OFFSET); 2506 printf("Area Length: %d\n", board_length); 2507 /* Decrease the length of board area by 1 byte of format version 2508 * and 1 byte for area length itself. the rest of this length will 2509 * be used to check for additional custom mfg. byte 2510 */ 2511 board_length -= 2; 2512 if (feof(input_file)) { 2513 break; 2514 } 2515 ret = fread(&lan_code, 1, 1, input_file); /* Language Code */ 2516 if ((ret != 1) || ferror(input_file)) { 2517 lprintf(LOG_ERR, "Invalid Language Code in input"); 2518 fclose(input_file); 2519 return (-1); 2520 } 2521 printf("Language Code: %d\n", lan_code); 2522 board_length--; 2523 /* Board Mfg Date */ 2524 if (feof(input_file)) { 2525 break; 2526 } 2527 2528 ret = fread(mfg_date, SIZE_MFG_DATE, 1, input_file); 2529 if (ret != 1) { 2530 lprintf(LOG_ERR, "Invalid Board Data."); 2531 fclose(input_file); 2532 return (-1); 2533 } 2534 tval = ((mfg_date[2] << 16) + (mfg_date[1] << 8) 2535 + (mfg_date[0])); 2536 tval = tval * 60; 2537 tval = tval + secs_from_1970_1996; 2538 printf("Board Mfg Date: %ld, %s", tval, 2539 asctime(localtime(&tval))); 2540 board_length -= SIZE_MFG_DATE; 2541 /* Board Mfg */ 2542 file_offset = ipmi_ek_display_board_info_area( 2543 input_file, "Board Manufacture Data", &board_length); 2544 ret = fseek(input_file, file_offset, SEEK_SET); 2545 /* Board Product */ 2546 file_offset = ipmi_ek_display_board_info_area( 2547 input_file, "Board Product Name", &board_length); 2548 ret = fseek(input_file, file_offset, SEEK_SET); 2549 /* Board Serial */ 2550 file_offset = ipmi_ek_display_board_info_area( 2551 input_file, "Board Serial Number", &board_length); 2552 ret = fseek(input_file, file_offset, SEEK_SET); 2553 /* Board Part */ 2554 file_offset = ipmi_ek_display_board_info_area( 2555 input_file, "Board Part Number", &board_length); 2556 ret = fseek(input_file, file_offset, SEEK_SET); 2557 /* FRU file ID */ 2558 file_offset = ipmi_ek_display_board_info_area( 2559 input_file, "FRU File ID", &board_length); 2560 ret = fseek(input_file, file_offset, SEEK_SET); 2561 /* Additional Custom Mfg. */ 2562 file_offset = ipmi_ek_display_board_info_area( 2563 input_file, "Custom", &board_length); 2564 break; 2565 } 2566 /* Product Info Area */ 2567 if (header.offset.product && (!feof(input_file))) { 2568 long offset = 0; 2569 offset = header.offset.product * FACTOR_OFFSET; 2570 ret = ipmi_ek_display_product_info_area(input_file, 2571 offset); 2572 } 2573 fclose(input_file); 2574 return 0; 2575 } 2576 2577 /************************************************************************** 2578 * 2579 * Function name: ipmi_ek_display_chassis_info_area 2580 * 2581 * Description: this function displays detail format of product info area record 2582 * into humain readable text format 2583 * 2584 * Restriction: Reference: IPMI Platform Management FRU Information Storage 2585 * Definition V1.0, Section 10 2586 * 2587 * Input: input_file: pointer to file stream 2588 * offset: start offset of chassis info area 2589 * 2590 * Output: None 2591 * 2592 * Global: None 2593 * 2594 * Return: None 2595 * 2596 ***************************************************************************/ 2597 static int 2598 ipmi_ek_display_chassis_info_area(FILE *input_file, long offset) 2599 { 2600 size_t file_offset; 2601 int ret = 0; 2602 unsigned char data = 0; 2603 unsigned char ch_len = 0; 2604 unsigned char ch_type = 0; 2605 unsigned int len; 2606 2607 if (input_file == NULL) { 2608 lprintf(LOG_ERR, "No file stream to read."); 2609 return (-1); 2610 } 2611 printf("%s\n", EQUAL_LINE_LIMITER); 2612 printf("Chassis Info Area\n"); 2613 printf("%s\n", EQUAL_LINE_LIMITER); 2614 ret = fseek(input_file, offset, SEEK_SET); 2615 if (feof(input_file)) { 2616 lprintf(LOG_ERR, "Invalid Chassis Info Area!"); 2617 return (-1); 2618 } 2619 ret = fread(&data, 1, 1, input_file); 2620 if ((ret != 1) || ferror(input_file)) { 2621 lprintf(LOG_ERR, "Invalid Version Number!"); 2622 return (-1); 2623 } 2624 printf("Format Version Number: %d\n", (data & 0x0f)); 2625 ret = fread(&ch_len, 1, 1, input_file); 2626 if ((ret != 1) || ferror(input_file)) { 2627 lprintf(LOG_ERR, "Invalid length!"); 2628 return (-1); 2629 } 2630 /* len is in factor of 8 bytes */ 2631 len = ch_len * 8; 2632 printf("Area Length: %d\n", len); 2633 len -= 2; 2634 if (feof(input_file)) { 2635 return (-1); 2636 } 2637 /* Chassis Type*/ 2638 ret = fread(&ch_type, 1, 1, input_file); 2639 if ((ret != 1) || ferror(input_file)) { 2640 lprintf(LOG_ERR, "Invalid Chassis Type!"); 2641 return (-1); 2642 } 2643 printf("Chassis Type: %d\n", ch_type); 2644 len--; 2645 /* Chassis Part Number*/ 2646 file_offset = ipmi_ek_display_board_info_area(input_file, 2647 "Chassis Part Number", &len); 2648 ret = fseek(input_file, file_offset, SEEK_SET); 2649 /* Chassis Serial */ 2650 file_offset = ipmi_ek_display_board_info_area(input_file, 2651 "Chassis Serial Number", &len); 2652 ret = fseek(input_file, file_offset, SEEK_SET); 2653 /* Custom product info area */ 2654 file_offset = ipmi_ek_display_board_info_area(input_file, 2655 "Custom", &len); 2656 return 0; 2657 } 2658 2659 /************************************************************************** 2660 * 2661 * Function name: ipmi_ek_display_board_info_area 2662 * 2663 * Description: this function displays board info area depending on board type 2664 * that pass in argument. Board type can be: 2665 * Manufacturer, Serial, Product or Part... 2666 * 2667 * Restriction: IPMI Platform Management FRU Information Storage 2668 * Definition V1.0, Section 11 2669 * 2670 * Input: input_file: pointer to file stream 2671 * board_type: a string that contain board type 2672 * board_length: length of info area 2673 * 2674 * Output: None 2675 * 2676 * Global: None 2677 * 2678 * Return: the current position of input_file 2679 * 2680 ***************************************************************************/ 2681 static size_t 2682 ipmi_ek_display_board_info_area(FILE *input_file, char *board_type, 2683 unsigned int *board_length) 2684 { 2685 size_t file_offset; 2686 int ret = 0; 2687 unsigned char len = 0; 2688 unsigned int size_board = 0; 2689 if (input_file == NULL || board_type == NULL 2690 || board_length == NULL) { 2691 return (size_t)(-1); 2692 } 2693 file_offset = ftell(input_file); 2694 2695 /* Board length*/ 2696 ret = fread(&len, 1, 1, input_file); 2697 if ((ret != 1) || ferror(input_file)) { 2698 lprintf(LOG_ERR, "Invalid Length!"); 2699 goto out; 2700 } 2701 (*board_length)--; 2702 2703 /* Bit 5:0 of Board Mfg type represent legnth */ 2704 size_board = (len & 0x3f); 2705 if (size_board == 0) { 2706 printf("%s: None\n", board_type); 2707 goto out; 2708 } 2709 if (strncmp(board_type, "Custom", 6 ) != 0) { 2710 unsigned char *data; 2711 unsigned int i = 0; 2712 data = malloc(size_board); 2713 if (data == NULL) { 2714 lprintf(LOG_ERR, "ipmitool: malloc failure"); 2715 return (size_t)(-1); 2716 } 2717 ret = fread(data, size_board, 1, input_file); 2718 if ((ret != 1) || ferror(input_file)) { 2719 lprintf(LOG_ERR, "Invalid board type size!"); 2720 free(data); 2721 data = NULL; 2722 goto out; 2723 } 2724 printf("%s type: 0x%02x\n", board_type, len); 2725 printf("%s: ", board_type); 2726 for (i = 0; i < size_board; i++) { 2727 if ((len & TYPE_CODE) == TYPE_CODE) { 2728 printf("%c", data[i]); 2729 } else { 2730 /* other than language code (binary, BCD, 2731 * ASCII 6 bit...) is not supported 2732 */ 2733 printf("%02x", data[i]); 2734 } 2735 } 2736 printf("\n"); 2737 free(data); 2738 data = NULL; 2739 (*board_length) -= size_board; 2740 goto out; 2741 } 2742 while (!feof(input_file)) { 2743 if (len == NO_MORE_INFO_FIELD) { 2744 unsigned char padding; 2745 unsigned char checksum = 0; 2746 /* take the rest of data in the area minus 1 byte of 2747 * checksum 2748 */ 2749 printf("Additional Custom Mfg. length: 0x%02x\n", len); 2750 padding = (*board_length) - 1; 2751 if ((padding > 0) && (!feof(input_file))) { 2752 printf("Unused space: %d (bytes)\n", padding); 2753 fseek(input_file, padding, SEEK_CUR); 2754 } 2755 ret = fread(&checksum, 1, 1, input_file); 2756 if ((ret != 1) || ferror(input_file)) { 2757 lprintf(LOG_ERR, "Invalid Checksum!"); 2758 goto out; 2759 } 2760 printf("Checksum: 0x%02x\n", checksum); 2761 goto out; 2762 } 2763 printf("Additional Custom Mfg. length: 0x%02x\n", len); 2764 if ((size_board > 0) && (size_board < (*board_length))) { 2765 unsigned char * additional_data = NULL; 2766 unsigned int i = 0; 2767 additional_data = malloc(size_board); 2768 if (additional_data == NULL) { 2769 lprintf(LOG_ERR, "ipmitool: malloc failure"); 2770 return (size_t)(-1); 2771 } 2772 2773 ret = fread(additional_data, size_board, 1, input_file); 2774 if ((ret != 1) || ferror(input_file)) { 2775 lprintf(LOG_ERR, "Invalid Additional Data!"); 2776 goto out; 2777 } 2778 printf("Additional Custom Mfg. Data: %02x", 2779 additional_data[0]); 2780 for (i = 1; i < size_board; i++) { 2781 printf("-%02x", additional_data[i]); 2782 } 2783 printf("\n"); 2784 free(additional_data); 2785 additional_data = NULL; 2786 (*board_length) -= size_board; 2787 } 2788 else { 2789 printf("No Additional Custom Mfg. %d\n", *board_length); 2790 goto out; 2791 } 2792 } 2793 2794 out: 2795 file_offset = ftell(input_file); 2796 return file_offset; 2797 } 2798 2799 /************************************************************************** 2800 * 2801 * Function name: ipmi_ek_display_product_info_area 2802 * 2803 * Description: this function displays detail format of product info area record 2804 * into humain readable text format 2805 * 2806 * Restriction: Reference: IPMI Platform Management FRU Information Storage 2807 * Definition V1.0, Section 12 2808 * 2809 * Input: input_file: pointer to file stream 2810 * offset: start offset of product info area 2811 * 2812 * Output: None 2813 * 2814 * Global: None 2815 * 2816 * Return: None 2817 * 2818 ***************************************************************************/ 2819 static int 2820 ipmi_ek_display_product_info_area(FILE *input_file, long offset) 2821 { 2822 size_t file_offset; 2823 int ret = 0; 2824 unsigned char ch_len = 0; 2825 unsigned char data = 0; 2826 unsigned int len = 0; 2827 2828 if (input_file == NULL) { 2829 lprintf(LOG_ERR, "No file stream to read."); 2830 return (-1); 2831 } 2832 file_offset = ftell(input_file); 2833 printf("%s\n", EQUAL_LINE_LIMITER); 2834 printf("Product Info Area\n"); 2835 printf("%s\n", EQUAL_LINE_LIMITER); 2836 ret = fseek(input_file, offset, SEEK_SET); 2837 if (feof(input_file)) { 2838 lprintf(LOG_ERR, "Invalid Product Info Area!"); 2839 return (-1); 2840 } 2841 ret = fread(&data, 1, 1, input_file); 2842 if ((ret != 1) || ferror(input_file)) { 2843 lprintf(LOG_ERR, "Invalid Data!"); 2844 return (-1); 2845 } 2846 printf("Format Version Number: %d\n", (data & 0x0f)); 2847 if (feof(input_file)) { 2848 return (-1); 2849 } 2850 /* Have to read this into a char or else 2851 * it ends up byte swapped on big endian machines */ 2852 ret = fread(&ch_len, 1, 1, input_file); 2853 if ((ret != 1) || ferror(input_file)) { 2854 lprintf(LOG_ERR, "Invalid Length!"); 2855 return (-1); 2856 } 2857 /* length is in factor of 8 bytes */ 2858 len = ch_len * 8; 2859 printf("Area Length: %d\n", len); 2860 len -= 2; /* -1 byte of format version and -1 byte itself */ 2861 2862 ret = fread(&data, 1, 1, input_file); 2863 if ((ret != 1) || ferror(input_file)) { 2864 lprintf(LOG_ERR, "Invalid Length!"); 2865 return (-1); 2866 } 2867 2868 fread(&data, 1, 1, input_file); 2869 printf("Language Code: %d\n", data); 2870 len--; 2871 /* Product Mfg */ 2872 file_offset = ipmi_ek_display_board_info_area(input_file, 2873 "Product Manufacture Data", &len); 2874 ret = fseek(input_file, file_offset, SEEK_SET); 2875 /* Product Name */ 2876 file_offset = ipmi_ek_display_board_info_area(input_file, 2877 "Product Name", &len); 2878 ret = fseek(input_file, file_offset, SEEK_SET); 2879 /* Product Part */ 2880 file_offset = ipmi_ek_display_board_info_area(input_file, 2881 "Product Part/Model Number", &len); 2882 ret = fseek(input_file, file_offset, SEEK_SET); 2883 /* Product Version */ 2884 file_offset = ipmi_ek_display_board_info_area(input_file, 2885 "Product Version", &len); 2886 ret = fseek(input_file, file_offset, SEEK_SET); 2887 /* Product Serial */ 2888 file_offset = ipmi_ek_display_board_info_area(input_file, 2889 "Product Serial Number", &len); 2890 ret = fseek(input_file, file_offset, SEEK_SET); 2891 /* Product Asset Tag */ 2892 file_offset = ipmi_ek_display_board_info_area(input_file, 2893 "Asset Tag", &len); 2894 ret = fseek(input_file, file_offset, SEEK_SET); 2895 /* FRU file ID */ 2896 file_offset = ipmi_ek_display_board_info_area(input_file, 2897 "FRU File ID", &len); 2898 ret = fseek(input_file, file_offset, SEEK_SET); 2899 /* Custom product info area */ 2900 file_offset = ipmi_ek_display_board_info_area(input_file, 2901 "Custom", &len); 2902 return 0; 2903 } 2904 2905 /************************************************************************** 2906 * 2907 * Function name: ipmi_ek_display_record 2908 * 2909 * Description: this function displays FRU multi record information. 2910 * 2911 * Restriction: None 2912 * 2913 * Input: record: a pointer to current record 2914 * list_head: a pointer to header of the list 2915 * list_last: a pointer to tale of the list 2916 * 2917 * Output: None 2918 * 2919 * Global: None 2920 * 2921 * Return: None 2922 * 2923 ***************************************************************************/ 2924 static void 2925 ipmi_ek_display_record(struct ipmi_ek_multi_header *record, 2926 struct ipmi_ek_multi_header *list_head, 2927 struct ipmi_ek_multi_header *list_last) 2928 { 2929 if (list_head == NULL) { 2930 printf("***empty list***\n"); 2931 return; 2932 } 2933 printf("%s\n", EQUAL_LINE_LIMITER); 2934 printf("FRU Multi Info area\n"); 2935 printf("%s\n", EQUAL_LINE_LIMITER); 2936 for (record = list_head; record != NULL; record = record->next) { 2937 printf("Record Type ID: 0x%02x\n", record->header.type); 2938 printf("Record Format version: 0x%02x\n", 2939 record->header.format); 2940 if (record->header.len <= PICMG_ID_OFFSET) { 2941 continue; 2942 } 2943 /* In picmg3.0 specification, picmg record 2944 * id lower than 4 or greater than 0x2d 2945 * isn't supported 2946 */ 2947 #define PICMG_ID_LOWER_LIMIT 0x04 2948 #define PICMG_ID_UPPER_LIMIT 0x2d 2949 unsigned char picmg_id; 2950 2951 picmg_id = record->data[PICMG_ID_OFFSET]; 2952 printf("Manufacturer ID: %02x%02x%02x h\n", 2953 record->data[2], record->data[1], 2954 record->data[0]); 2955 if ((picmg_id < PICMG_ID_LOWER_LIMIT) 2956 || (picmg_id > PICMG_ID_UPPER_LIMIT)) { 2957 printf("Picmg record ID: Unsupported {0x%02x}\n", picmg_id); 2958 } else { 2959 printf("Picmg record ID: %s {0x%02x}\n", 2960 val2str(picmg_id, ipmi_ekanalyzer_picmg_record_id), 2961 picmg_id); 2962 } 2963 switch (picmg_id) { 2964 case FRU_PICMG_BACKPLANE_P2P: /*0x04*/ 2965 ipmi_ek_display_backplane_p2p_record (record); 2966 break; 2967 case FRU_PICMG_ADDRESS_TABLE: /*0x10*/ 2968 ipmi_ek_display_address_table_record (record); 2969 break; 2970 case FRU_PICMG_SHELF_POWER_DIST: /*0x11*/ 2971 ipmi_ek_display_shelf_power_distribution_record (record); 2972 break; 2973 case FRU_PICMG_SHELF_ACTIVATION: /*/0x12*/ 2974 ipmi_ek_display_shelf_activation_record (record); 2975 break; 2976 case FRU_PICMG_SHMC_IP_CONN: /*0x13*/ 2977 ipmi_ek_display_shelf_ip_connection_record (record); 2978 break; 2979 case FRU_PICMG_BOARD_P2P: /*0x14*/ 2980 ipmi_ek_display_board_p2p_record (record); 2981 break; 2982 case FRU_RADIAL_IPMB0_LINK_MAPPING: /*0x15*/ 2983 ipmi_ek_display_radial_ipmb0_record (record); 2984 break; 2985 case FRU_AMC_CURRENT: /*0x16*/ 2986 ipmi_ek_display_amc_current_record (record); 2987 break; 2988 case FRU_AMC_ACTIVATION: /*0x17*/ 2989 ipmi_ek_display_amc_activation_record (record); 2990 break; 2991 case FRU_AMC_CARRIER_P2P: /*0x18*/ 2992 ipmi_ek_display_carrier_connectivity (record); 2993 break; 2994 case FRU_AMC_P2P: /*0x19*/ 2995 ipmi_ek_display_amc_p2p_record (record); 2996 break; 2997 case FRU_AMC_CARRIER_INFO: /*0x1a*/ 2998 ipmi_ek_display_amc_carrier_info_record (record); 2999 break; 3000 case FRU_PICMG_CLK_CARRIER_P2P: /*0x2c*/ 3001 ipmi_ek_display_clock_carrier_p2p_record (record); 3002 break; 3003 case FRU_PICMG_CLK_CONFIG: /*0x2d*/ 3004 ipmi_ek_display_clock_config_record (record); 3005 break; 3006 default: 3007 if (verbose > 0) { 3008 int i; 3009 printf("%02x %02x %02x %02x %02x ", 3010 record->header.type, 3011 record->header.format, 3012 record->header.len, 3013 record->header.record_checksum, 3014 record->header.header_checksum); 3015 for (i = 0; i < record->header.len; i++) { 3016 printf("%02x ", record->data[i]); 3017 } 3018 printf("\n"); 3019 } 3020 break; 3021 } 3022 printf("%s\n", STAR_LINE_LIMITER); 3023 } 3024 } 3025 3026 /************************************************************************** 3027 * 3028 * Function name: ipmi_ek_display_backplane_p2p_record 3029 * 3030 * Description: this function displays backplane p2p record. 3031 * 3032 * Restriction: Reference: PICMG 3.0 Specification Table 3-40 3033 * 3034 * Input: record: a pointer to current record to be displayed 3035 * 3036 * Output: None 3037 * 3038 * Global: None 3039 * 3040 * Return: None 3041 * 3042 ***************************************************************************/ 3043 static void 3044 ipmi_ek_display_backplane_p2p_record(struct ipmi_ek_multi_header *record) 3045 { 3046 uint8_t index; 3047 int offset = START_DATA_OFFSET; 3048 struct fru_picmgext_slot_desc *slot_d = 3049 (struct fru_picmgext_slot_desc*)&record->data[offset]; 3050 3051 offset += sizeof(struct fru_picmgext_slot_desc); 3052 while (offset <= record->header.len) { 3053 printf(" Channel Type: "); 3054 switch (slot_d->chan_type) { 3055 case 0x00: 3056 case 0x07: 3057 printf("PICMG 2.9\n"); 3058 break; 3059 case 0x08: 3060 printf("Single Port Fabric IF\n"); 3061 break; 3062 case 0x09: 3063 printf("Double Port Fabric IF\n"); 3064 break; 3065 case 0x0a: 3066 printf("Full Channel Fabric IF\n"); 3067 break; 3068 case 0x0b: 3069 printf("Base IF\n"); 3070 break; 3071 case 0x0c: 3072 printf("Update Channel IF\n"); 3073 break; 3074 default: 3075 printf("Unknown IF\n"); 3076 break; 3077 } 3078 printf(" Slot Address: %02x\n", slot_d->slot_addr); 3079 printf(" Channel Count: %i\n", slot_d->chn_count); 3080 for (index = 0; index < (slot_d->chn_count); index++) { 3081 struct fru_picmgext_chn_desc *d = 3082 (struct fru_picmgext_chn_desc *)&record->data[offset]; 3083 if (verbose) { 3084 printf("\t" 3085 "Chn: %02x --> " 3086 "Chn: %02x in " 3087 "Slot: %02x\n", 3088 d->local_chn, 3089 d->remote_chn, 3090 d->remote_slot); 3091 } 3092 offset += sizeof(struct fru_picmgext_chn_desc); 3093 } 3094 slot_d = (struct fru_picmgext_slot_desc*)&record->data[offset]; 3095 offset += sizeof(struct fru_picmgext_slot_desc); 3096 } 3097 } 3098 3099 /************************************************************************** 3100 * 3101 * Function name: ipmi_ek_display_address_table_record 3102 * 3103 * Description: this function displays address table record. 3104 * 3105 * Restriction: Reference: PICMG 3.0 Specification Table 3-6 3106 * 3107 * Input: record: a pointer to current record to be displayed 3108 * 3109 * Output: None 3110 * 3111 * Global: None 3112 * 3113 * Return: None 3114 * 3115 ***************************************************************************/ 3116 static void 3117 ipmi_ek_display_address_table_record(struct ipmi_ek_multi_header *record) 3118 { 3119 #define SIZE_SHELF_ADDRESS_BYTE 20 3120 unsigned char entries = 0; 3121 unsigned char i; 3122 int offset = START_DATA_OFFSET; 3123 3124 printf(" Type/Len: 0x%02x\n", record->data[offset++]); 3125 printf(" Shelf Addr: "); 3126 for (i = 0; i < SIZE_SHELF_ADDRESS_BYTE; i++) { 3127 printf("0x%02x ", record->data[offset++]); 3128 } 3129 printf("\n"); 3130 entries = record->data[offset++]; 3131 printf(" Addr Table Entries count: 0x%02x\n", entries); 3132 for (i = 0; i < entries; i++) { 3133 printf("\tHWAddr: 0x%02x - SiteNum: 0x%02x - SiteType: 0x%02x \n", 3134 record->data[offset+0], 3135 record->data[offset+1], 3136 record->data[offset+2]); 3137 offset += 3; 3138 } 3139 } 3140 3141 /************************************************************************** 3142 * 3143 * Function name: ipmi_ek_display_shelf_power_distribution_record 3144 * 3145 * Description: this function displays shelf power distribution record. 3146 * 3147 * Restriction: Reference: PICMG 3.0 Specification Table 3-70 3148 * 3149 * Input: record: a pointer to current record to be displayed 3150 * 3151 * Output: None 3152 * 3153 * Global: None 3154 * 3155 * Return: None 3156 * 3157 ***************************************************************************/ 3158 static void 3159 ipmi_ek_display_shelf_power_distribution_record( 3160 struct ipmi_ek_multi_header *record) 3161 { 3162 int offset = START_DATA_OFFSET; 3163 unsigned char i; 3164 unsigned char j; 3165 unsigned char feeds = 0; 3166 3167 feeds = record->data[offset++]; 3168 printf(" Number of Power Feeds: 0x%02x\n", feeds); 3169 for (i = 0; i < feeds; i++) { 3170 unsigned char entries; 3171 unsigned long max_ext = 0; 3172 unsigned long max_int = 0; 3173 max_ext = record->data[offset+0] 3174 | (record->data[offset+1] << 8); 3175 printf(" Max External Available Current: %ld Amps\n", 3176 (max_ext * 10)); 3177 offset += 2; 3178 max_int = record->data[offset+0] 3179 | (record->data[offset+1] << 8); 3180 printf(" Max Internal Current:\t %ld Amps\n", 3181 (max_int * 10)); 3182 offset += 2; 3183 printf(" Min Expected Operating Voltage: %d Volts\n", 3184 (record->data[offset++] / 2)); 3185 entries = record->data[offset++]; 3186 printf(" Feed to FRU count: 0x%02x\n", entries); 3187 for (j = 0; j < entries; j++) { 3188 printf("\tHW: 0x%02x", record->data[offset++]); 3189 printf("\tFRU ID: 0x%02x\n", record->data[offset++]); 3190 } 3191 } 3192 } 3193 3194 /************************************************************************** 3195 * 3196 * Function name: ipmi_ek_display_shelf_activation_record 3197 * 3198 * Description: this function displays shelf activation record. 3199 * 3200 * Restriction: Reference: PICMG 3.0 Specification Table 3-73 3201 * 3202 * Input: record: a pointer to current record to be displayed 3203 * 3204 * Output: None 3205 * 3206 * Global: None 3207 * 3208 * Return: None 3209 * 3210 ***************************************************************************/ 3211 static void 3212 ipmi_ek_display_shelf_activation_record(struct ipmi_ek_multi_header *record) 3213 { 3214 unsigned char count = 0; 3215 int offset = START_DATA_OFFSET; 3216 3217 printf(" Allowance for FRU Act Readiness: 0x%02x\n", 3218 record->data[offset++]); 3219 count = record->data[offset++]; 3220 printf(" FRU activation and Power Desc Cnt: 0x%02x\n", count); 3221 while (count > 0) { 3222 printf(" FRU activation and Power descriptor:\n"); 3223 printf("\tHardware Address:\t\t0x%02x\n", 3224 record->data[offset++]); 3225 printf("\tFRU Device ID:\t\t\t0x%02x\n", 3226 record->data[offset++]); 3227 printf("\tMax FRU Power Capability:\t0x%04x Watts\n", 3228 (record->data[offset+0] 3229 | (record->data[offset+1]<<8))); 3230 offset += 2; 3231 printf("\tConfiguration parameter:\t0x%02x\n", 3232 record->data[offset++]); 3233 count --; 3234 } 3235 } 3236 3237 /************************************************************************** 3238 * 3239 * Function name: ipmi_ek_display_shelf_ip_connection_record 3240 * 3241 * Description: this function displays shelf ip connection record. 3242 * 3243 * Restriction: Fix me: Don't test yet 3244 * Reference: PICMG 3.0 Specification Table 3-31 3245 * 3246 * Input: record: a pointer to current record to be displayed 3247 * 3248 * Output: None 3249 * 3250 * Global: None 3251 * 3252 * Return: None 3253 * 3254 ***************************************************************************/ 3255 static void 3256 ipmi_ek_display_shelf_ip_connection_record(struct ipmi_ek_multi_header *record) 3257 { 3258 int ioffset = START_DATA_OFFSET; 3259 if (ioffset > record->header.len) { 3260 printf(" Shelf Manager IP Address: %d.%d.%d.%d\n", 3261 record->data[ioffset+0], 3262 record->data[ioffset+1], 3263 record->data[ioffset+2], 3264 record->data[ioffset+3]); 3265 ioffset += 4; 3266 } 3267 if (ioffset > record->header.len) { 3268 printf(" Default Gateway Address: %d.%d.%d.%d\n", 3269 record->data[ioffset+0], 3270 record->data[ioffset+1], 3271 record->data[ioffset+2], 3272 record->data[ioffset+3]); 3273 ioffset += 4; 3274 } 3275 if (ioffset > record->header.len) { 3276 printf(" Subnet Mask: %d.%d.%d.%d\n", 3277 record->data[ioffset+0], 3278 record->data[ioffset+1], 3279 record->data[ioffset+2], 3280 record->data[ioffset+3]); 3281 ioffset += 4; 3282 } 3283 } 3284 3285 /************************************************************************** 3286 * 3287 * Function name: ipmi_ek_display_shelf_fan_geography_record 3288 * 3289 * Description: this function displays shelf fan geography record. 3290 * 3291 * Restriction: Fix me: Don't test yet 3292 * Reference: PICMG 3.0 Specification Table 3-75 3293 * 3294 * Input: record: a pointer to current record to be displayed 3295 * 3296 * Output: None 3297 * 3298 * Global: None 3299 * 3300 * Return: None 3301 * 3302 ***************************************************************************/ 3303 static void 3304 ipmi_ek_display_shelf_fan_geography_record(struct ipmi_ek_multi_header *record) 3305 { 3306 int ioffset = START_DATA_OFFSET; 3307 unsigned char fan_count = 0; 3308 3309 fan_count = record->data[ioffset]; 3310 ioffset++; 3311 printf(" Fan-to-FRU Entry Count: 0x%02x\n", fan_count); 3312 while ((fan_count > 0) && (ioffset <= record->header.len)) { 3313 printf(" Fan-to-FRU Mapping Entry: {%2x%2x%2x%2x}\n", 3314 record->data[ioffset], 3315 record->data[ioffset+1], 3316 record->data[ioffset+2], 3317 record->data[ioffset+3]); 3318 printf(" Hardware Address: 0x%02x\n", 3319 record->data[ioffset++]); 3320 printf(" FRU device ID: 0x%02x\n", 3321 record->data[ioffset++]); 3322 printf(" Site Number: 0x%02x\n", 3323 record->data[ioffset++]); 3324 printf(" Site Type: 0x%02x\n", 3325 record->data[ioffset++]); 3326 fan_count --; 3327 } 3328 } 3329 3330 /************************************************************************** 3331 * 3332 * Function name: ipmi_ek_display_board_p2p_record 3333 * 3334 * Description: this function displays board pont-to-point record. 3335 * 3336 * Restriction: Reference: PICMG 3.0 Specification Table 3-44 3337 * 3338 * Input: record: a pointer to current record to be displayed 3339 * 3340 * Output: None 3341 * 3342 * Global: None 3343 * 3344 * Return: None 3345 * 3346 ***************************************************************************/ 3347 static void 3348 ipmi_ek_display_board_p2p_record(struct ipmi_ek_multi_header *record) 3349 { 3350 unsigned char guid_count; 3351 int offset = START_DATA_OFFSET; 3352 int i = 0; 3353 3354 guid_count = record->data[offset++]; 3355 printf(" GUID count: %2d\n", guid_count); 3356 for (i = 0 ; i < guid_count; i++) { 3357 int j; 3358 printf("\tGUID: "); 3359 for (j = 0; j < sizeof(struct fru_picmgext_guid); j++) { 3360 printf("%02x", record->data[offset+j]); 3361 } 3362 printf("\n"); 3363 offset += sizeof(struct fru_picmgext_guid); 3364 } 3365 for (offset; 3366 offset < record->header.len; 3367 offset += sizeof(struct fru_picmgext_link_desc)) { 3368 /* to solve little endian/big endian problem */ 3369 unsigned long data; 3370 struct fru_picmgext_link_desc * d; 3371 data = (record->data[offset+0]) 3372 | (record->data[offset+1] << 8)\ 3373 | (record->data[offset+2] << 16)\ 3374 | (record->data[offset+3] << 24); 3375 d = (struct fru_picmgext_link_desc *)&data; 3376 3377 printf(" Link Descriptor\n"); 3378 printf("\tLink Grouping ID:\t0x%02x\n", d->grouping); 3379 printf("\tLink Type Extension:\t0x%02x - ", d->ext); 3380 if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE) { 3381 switch (d->ext) { 3382 case 0: 3383 printf("10/100/1000BASE-T Link (four-pair)\n"); 3384 break; 3385 case 1: 3386 printf("ShMC Cross-connect (two-pair)\n"); 3387 break; 3388 default: 3389 printf("Unknwon\n"); 3390 break; 3391 } 3392 } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET) { 3393 switch (d->ext) { 3394 case 0: 3395 printf("Fixed 1000Base-BX\n"); 3396 break; 3397 case 1: 3398 printf("Fixed 10GBASE-BX4 [XAUI]\n"); 3399 break; 3400 case 2: 3401 printf("FC-PI\n"); 3402 break; 3403 default: 3404 printf("Unknwon\n"); 3405 break; 3406 } 3407 } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND) { 3408 printf("Unknwon\n"); 3409 } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR) { 3410 printf("Unknwon\n"); 3411 } else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE) { 3412 printf("Unknwon\n"); 3413 } else { 3414 printf("Unknwon\n"); 3415 } 3416 printf("\tLink Type:\t\t0x%02x - ", d->type); 3417 if (d->type == 0 || d->type == 0xff) { 3418 printf("Reserved\n"); 3419 } else if (d->type >= 0x06 && d->type <= 0xef) { 3420 printf("Reserved\n"); 3421 } else if (d->type >= LOWER_OEM_TYPE && d->type <= UPPER_OEM_TYPE) { 3422 printf("OEM GUID Definition\n"); 3423 } else { 3424 switch (d->type){ 3425 case FRU_PICMGEXT_LINK_TYPE_BASE: 3426 printf("PICMG 3.0 Base Interface 10/100/1000\n"); 3427 break; 3428 case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: 3429 printf("PICMG 3.1 Ethernet Fabric Interface\n"); 3430 break; 3431 case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: 3432 printf("PICMG 3.2 Infiniband Fabric Interface\n"); 3433 break; 3434 case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: 3435 printf("PICMG 3.3 Star Fabric Interface\n"); 3436 break; 3437 case FRU_PICMGEXT_LINK_TYPE_PCIE: 3438 printf("PICMG 3.4 PCI Express Fabric Interface\n"); 3439 break; 3440 default: 3441 printf("Invalid\n"); 3442 break; 3443 } 3444 } 3445 printf("\tLink Designator: \n"); 3446 printf("\t Port 0 Flag: %s\n", 3447 (d->desig_port & 0x01) ? "enable" : "disable"); 3448 printf("\t Port 1 Flag: %s\n", 3449 (d->desig_port & 0x02) ? "enable" : "disable"); 3450 printf("\t Port 2 Flag: %s\n", 3451 (d->desig_port & 0x04) ? "enable" : "disable"); 3452 printf("\t Port 3 Flag: %s\n", 3453 (d->desig_port & 0x08) ? "enable" : "disable"); 3454 printf("\t Interface: 0x%02x - ", d->desig_if); 3455 switch (d->desig_if) { 3456 case FRU_PICMGEXT_DESIGN_IF_BASE: 3457 printf("Base Interface\n"); 3458 break; 3459 case FRU_PICMGEXT_DESIGN_IF_FABRIC: 3460 printf("Fabric Interface\n"); 3461 break; 3462 case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: 3463 printf("Update Channel\n"); 3464 break; 3465 case FRU_PICMGEXT_DESIGN_IF_RESERVED: 3466 printf("Reserved\n"); 3467 break; 3468 default: 3469 printf("Invalid"); 3470 break; 3471 } 3472 printf("\t Channel Number: 0x%02x\n", 3473 d->desig_channel); 3474 } 3475 } 3476 3477 /************************************************************************** 3478 * 3479 * Function name: ipmi_ek_display_radial_ipmb0_record 3480 * 3481 * Description: this function displays radial IPMB-0 record. 3482 * 3483 * Restriction: Fix me: Don't test yet 3484 * 3485 * Input: record: a pointer to current record to be displayed 3486 * 3487 * Output: None 3488 * 3489 * Global: None 3490 * 3491 * Return: None 3492 * 3493 ***************************************************************************/ 3494 static void 3495 ipmi_ek_display_radial_ipmb0_record(struct ipmi_ek_multi_header *record) 3496 { 3497 #define SIZE_OF_CONNECTOR_DEFINER 3; /*bytes*/ 3498 int offset = START_DATA_OFFSET; 3499 /* Ref: PICMG 3.0 Specification Revision 2.0, Table 3-59 */ 3500 printf(" IPMB-0 Connector Definer: "); 3501 #ifndef WORDS_BIGENDIAN 3502 printf("%02x %02x %02x h\n", record->data[offset], 3503 record->data[offset+1], record->data[offset+2]); 3504 #else 3505 printf("%02x %02x %02x h\n", record->data[offset+2], 3506 record->data[offset+1], record->data[offset]); 3507 #endif 3508 /* 3 bytes of connector definer was used */ 3509 offset += SIZE_OF_CONNECTOR_DEFINER; 3510 printf(" IPMB-0 Connector version ID: "); 3511 #ifndef WORDS_BIGENDIAN 3512 printf("%02x %02x h\n", record->data[offset], 3513 record->data[offset+1]); 3514 #else 3515 printf("%02x %02x h\n", record->data[offset+1], 3516 record->data[offset]); 3517 #endif 3518 offset += 2; 3519 printf(" IPMB-0 Hub Descriptor Count: 0x%02x", 3520 record->data[offset++]); 3521 if (record->data[offset] < 1) { 3522 return; 3523 } 3524 for (offset; offset < record->header.len;) { 3525 unsigned char entry_count = 0; 3526 printf(" IPMB-0 Hub Descriptor\n"); 3527 printf("\tHardware Address: 0x%02x\n", 3528 record->data[offset++]); 3529 printf("\tHub Info {0x%02x}: ", record->data[offset]); 3530 /* Bit mask specified in Table 3-59 3531 * of PICMG 3.0 Specification 3532 */ 3533 if ((record->data[offset] & 0x01) == 0x01) { 3534 printf("IPMB-A only\n"); 3535 } else if ((record->data[offset] & 0x02) == 0x02) { 3536 printf("IPMB-B only\n"); 3537 } else if ((record->data[offset] & 0x03) == 0x03) { 3538 printf("IPMB-A and IPMB-B\n"); 3539 } else { 3540 printf("Reserved.\n"); 3541 } 3542 offset ++; 3543 entry_count = record->data[offset++]; 3544 printf("\tAddress Entry count: 0x%02x", entry_count); 3545 while (entry_count > 0) { 3546 printf("\t Hardware Address: 0x%02x\n", 3547 record->data[offset++]); 3548 printf("\t IPMB-0 Link Entry: 0x%02x\n", 3549 record->data[offset++]); 3550 entry_count --; 3551 } 3552 } 3553 } 3554 3555 /************************************************************************** 3556 * 3557 * Function name: ipmi_ek_display_amc_current_record 3558 * 3559 * Description: this function displays AMC current record. 3560 * 3561 * Restriction: None 3562 * 3563 * Input: record: a pointer to current record to be displayed 3564 * 3565 * Output: None 3566 * 3567 * Global: None 3568 * 3569 * Return: None 3570 * 3571 ***************************************************************************/ 3572 static void 3573 ipmi_ek_display_amc_current_record(struct ipmi_ek_multi_header *record) 3574 { 3575 unsigned char current; 3576 current = record->data[START_DATA_OFFSET]; 3577 printf(" Current draw: %.1f A @ 12V => %.2f Watt\n", 3578 (float)current / 10.0, 3579 ((float)current / 10.0) * 12.0); 3580 printf("\n"); 3581 } 3582 3583 /************************************************************************** 3584 * 3585 * Function name: ipmi_ek_display_amc_activation_record 3586 * 3587 * Description: this function displays carrier activation and current management 3588 * record. 3589 * 3590 * Restriction: Reference: AMC.0 Specification Table 3-11 and Table 3-12 3591 * 3592 * Input: record: a pointer to current record to be displayed 3593 * 3594 * Output: None 3595 * 3596 * Global: None 3597 * 3598 * Return: None 3599 * 3600 ***************************************************************************/ 3601 static void 3602 ipmi_ek_display_amc_activation_record(struct ipmi_ek_multi_header *record) 3603 { 3604 uint16_t max_current; 3605 int offset = START_DATA_OFFSET; 3606 3607 max_current = record->data[offset]; 3608 max_current |= record->data[++offset] << 8; 3609 printf(" Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n", 3610 (float) max_current / 10, 3611 (float) max_current / 10 * 12); 3612 printf(" Module Activation Readiness: %i sec.\n", 3613 record->data[++offset]); 3614 printf(" Descriptor Count: %i\n", record->data[++offset]); 3615 for (++offset; (offset < record->header.len); offset += 3) { 3616 struct fru_picmgext_activation_record *a = 3617 (struct fru_picmgext_activation_record *)&record->data[offset]; 3618 printf("\tIPMB-Address:\t\t0x%x\n", a->ibmb_addr); 3619 printf("\tMax. Module Current:\t%.2f A\n", 3620 (float)a->max_module_curr / 10); 3621 printf("\n"); 3622 } 3623 } 3624 3625 /************************************************************************** 3626 * 3627 * Function name: ipmi_ek_display_amc_p2p_record 3628 * 3629 * Description: this function display amc p2p connectivity record in humain 3630 * readable text format 3631 * 3632 * Restriction: Reference: AMC.0 Specification Table 3-16 3633 * 3634 * Input: record: a pointer to current record to be displayed 3635 * 3636 * Output: None 3637 * 3638 * Global: None 3639 * 3640 * Return: None 3641 * 3642 ***************************************************************************/ 3643 static void 3644 ipmi_ek_display_amc_p2p_record(struct ipmi_ek_multi_header *record) 3645 { 3646 int index_data = START_DATA_OFFSET; 3647 int oem_count = 0; 3648 int ch_count = 0; 3649 int index=0; 3650 3651 oem_count = record->data[index_data++]; 3652 printf("OEM GUID count: %02x\n", oem_count); 3653 if (oem_count > 0) { 3654 while (oem_count > 0) { 3655 printf("OEM GUID: "); 3656 for (index = 1; index <= SIZE_OF_GUID; index++) { 3657 printf("%02x", record->data[index_data++]); 3658 /* For a better look, display a "-" character 3659 * after each 5 bytes of OEM GUID 3660 */ 3661 if (!(index % 5)) { 3662 printf("-"); 3663 } 3664 } 3665 printf("\n"); 3666 oem_count--; 3667 } 3668 } 3669 if ((record->data[index_data] & AMC_MODULE) == AMC_MODULE) { 3670 printf("AMC module connection\n"); 3671 } else { 3672 printf("On-Carrier Device %02x h\n", 3673 (record->data[index_data] & 0x0f)); 3674 } 3675 index_data ++; 3676 ch_count = record->data[index_data++]; 3677 printf("AMC Channel Descriptor count: %02x h\n", ch_count); 3678 3679 if (ch_count > 0) { 3680 for (index = 0; index < ch_count; index++) { 3681 unsigned int data; 3682 struct fru_picmgext_amc_channel_desc_record *ch_desc; 3683 printf(" AMC Channel Descriptor {%02x%02x%02x}\n", 3684 record->data[index_data+2], 3685 record->data[index_data+1], 3686 record->data[index_data]); 3687 data = record->data[index_data] 3688 | (record->data[index_data + 1] << 8) 3689 | (record->data[index_data + 2] << 16); 3690 ch_desc = (struct fru_picmgext_amc_channel_desc_record *)&data; 3691 printf(" Lane 0 Port: %d\n", ch_desc->lane0port); 3692 printf(" Lane 1 Port: %d\n", ch_desc->lane1port); 3693 printf(" Lane 2 Port: %d\n", ch_desc->lane2port); 3694 printf(" Lane 3 Port: %d\n\n", ch_desc->lane3port); 3695 index_data += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE; 3696 } 3697 } 3698 while (index_data < record->header.len) { 3699 /* Warning: This code doesn't work with gcc version 3700 * between 4.0 and 4.3 3701 */ 3702 unsigned int data[2]; 3703 struct fru_picmgext_amc_link_desc_record *link_desc; 3704 data[0] = record->data[index_data] 3705 | (record->data[index_data + 1] << 8) 3706 | (record->data[index_data + 2] << 16) 3707 | (record->data[index_data + 3] << 24); 3708 data[1] = record->data[index_data + 4]; 3709 3710 link_desc = (struct fru_picmgext_amc_link_desc_record *)&data[0]; 3711 printf(" AMC Link Descriptor:\n"); 3712 printf("\t- Link Type: %s \n", 3713 val2str(link_desc->type, ipmi_ekanalyzer_link_type)); 3714 switch (link_desc->type) { 3715 case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: 3716 case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: 3717 case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: 3718 printf("\t- Link Type extension: %s\n", 3719 val2str(link_desc->type_ext, 3720 ipmi_ekanalyzer_extension_PCIE)); 3721 printf("\t- Link Group ID: %d\n ", 3722 link_desc->group_id); 3723 printf("\t- Link Asym. Match: %d - %s\n", 3724 link_desc->asym_match, 3725 val2str(link_desc->asym_match, 3726 ipmi_ekanalyzer_asym_PCIE)); 3727 break; 3728 case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: 3729 printf("\t- Link Type extension: %s\n", 3730 val2str (link_desc->type_ext, 3731 ipmi_ekanalyzer_extension_ETHERNET)); 3732 printf("\t- Link Group ID: %d \n", 3733 link_desc->group_id); 3734 printf("\t- Link Asym. Match: %d - %s\n", 3735 link_desc->asym_match, 3736 val2str(link_desc->asym_match, 3737 ipmi_ekanalyzer_asym_PCIE)); 3738 break; 3739 case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: 3740 printf("\t- Link Type extension: %s\n", 3741 val2str (link_desc->type_ext, 3742 ipmi_ekanalyzer_extension_STORAGE)); 3743 printf("\t- Link Group ID: %d \n", 3744 link_desc->group_id); 3745 printf("\t- Link Asym. Match: %d - %s\n", 3746 link_desc->asym_match, 3747 val2str(link_desc->asym_match, 3748 ipmi_ekanalyzer_asym_STORAGE)); 3749 break; 3750 default: 3751 printf("\t- Link Type extension: %i (Unknown)\n", 3752 link_desc->type_ext); 3753 printf("\t- Link Group ID: %d \n", 3754 link_desc->group_id); 3755 printf("\t- Link Asym. Match: %i\n", 3756 link_desc->asym_match); 3757 break; 3758 } 3759 printf("\t- AMC Link Designator:\n"); 3760 printf("\t Channel ID: %i\n", link_desc->channel_id); 3761 printf("\t\t Lane 0: %s\n", 3762 (link_desc->port_flag_0) ? "enable" : "disable"); 3763 printf("\t\t Lane 1: %s\n", 3764 (link_desc->port_flag_1) ? "enable" : "disable"); 3765 printf("\t\t Lane 2: %s\n", 3766 (link_desc->port_flag_2) ? "enable" : "disable"); 3767 printf("\t\t Lane 3: %s\n", 3768 (link_desc->port_flag_3) ? "enable" : "disable"); 3769 index_data += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE; 3770 } 3771 } 3772 3773 /************************************************************************** 3774 * 3775 * Function name: ipmi_ek_display_amc_carrier_info_record 3776 * 3777 * Description: this function displays Carrier information table. 3778 * 3779 * Restriction: Reference: AMC.0 Specification Table 3-3 3780 * 3781 * Input: record: a pointer to current record to be displayed 3782 * 3783 * Output: None 3784 * 3785 * Global: START_DATA_OFFSET 3786 * 3787 * Return: None 3788 * 3789 ***************************************************************************/ 3790 static void 3791 ipmi_ek_display_amc_carrier_info_record(struct ipmi_ek_multi_header *record) 3792 { 3793 unsigned char extVersion; 3794 unsigned char siteCount; 3795 int offset = START_DATA_OFFSET; 3796 3797 extVersion = record->data[offset++]; 3798 siteCount = record->data[offset++]; 3799 printf(" AMC.0 extension version: R%d.%d\n", 3800 (extVersion >> 0) & 0x0F, 3801 (extVersion >> 4) & 0x0F); 3802 printf(" Carrier Sie Number Count: %d\n", siteCount); 3803 while (siteCount > 0) { 3804 printf("\tSite ID (%d): %s \n", record->data[offset], 3805 val2str(record->data[offset], ipmi_ekanalyzer_module_type)); 3806 offset++; 3807 siteCount--; 3808 } 3809 printf("\n"); 3810 } 3811 3812 /************************************************************************** 3813 * 3814 * Function name: ipmi_ek_display_clock_carrier_p2p_record 3815 * 3816 * Description: this function displays Carrier clock point-to-pont 3817 * connectivity record. 3818 * 3819 * Restriction: the following code is copy from ipmi_fru.c with modification in 3820 * reference to AMC.0 Specification Table 3-29 3821 * 3822 * Input: record: a pointer to current record to be displayed 3823 * 3824 * Output: None 3825 * 3826 * Global: None 3827 * 3828 * Return: None 3829 * 3830 ***************************************************************************/ 3831 static void 3832 ipmi_ek_display_clock_carrier_p2p_record(struct ipmi_ek_multi_header *record) 3833 { 3834 unsigned char desc_count; 3835 int i; 3836 int j; 3837 int offset = START_DATA_OFFSET; 3838 3839 desc_count = record->data[offset++]; 3840 for(i = 0; i < desc_count; i++) { 3841 unsigned char resource_id; 3842 unsigned char channel_count; 3843 3844 resource_id = record->data[offset++]; 3845 channel_count = record->data[offset++]; 3846 3847 printf(" Clock Resource ID: 0x%02x\n", resource_id); 3848 printf(" Type: "); 3849 if ((resource_id & 0xC0) >> 6 == 0) { 3850 printf("On-Carrier-Device\n"); 3851 } else if ((resource_id & 0xC0) >> 6 == 1) { 3852 printf("AMC slot\n"); 3853 } else if ((resource_id & 0xC0) >> 6 == 2) { 3854 printf("Backplane\n"); 3855 } else{ 3856 printf("reserved\n"); 3857 } 3858 printf(" Channel Count: 0x%02x\n", channel_count); 3859 3860 for (j = 0; j < channel_count; j++) { 3861 unsigned char loc_channel; 3862 unsigned char rem_channel; 3863 unsigned char rem_resource; 3864 3865 loc_channel = record->data[offset++]; 3866 rem_channel = record->data[offset++]; 3867 rem_resource = record->data[offset++]; 3868 3869 printf("\tCLK-ID: 0x%02x ---> ", loc_channel); 3870 printf(" remote CLKID: 0x%02x ", rem_channel); 3871 if ((rem_resource & 0xC0) >> 6 == 0) { 3872 printf("[ Carrier-Dev"); 3873 } else if ((rem_resource & 0xC0) >> 6 == 1) { 3874 printf("[ AMC slot "); 3875 } else if ((rem_resource & 0xC0) >> 6 == 2) { 3876 printf("[ Backplane "); 3877 } else { 3878 printf("reserved "); 3879 } 3880 printf(" 0x%02x ]\n", rem_resource & 0xF); 3881 } 3882 } 3883 printf("\n"); 3884 } 3885 3886 /************************************************************************** 3887 * 3888 * Function name: ipmi_ek_display_clock_config_record 3889 * 3890 * Description: this function displays clock configuration record. 3891 * 3892 * Restriction: the following codes are copy from ipmi_fru.c with modification 3893 * in reference to AMC.0 Specification Table 3-35 and Table 3-36 3894 * 3895 * Input: record: a pointer to current record to be displayed 3896 * 3897 * Output: None 3898 * 3899 * Global: START_DATA_OFFSET 3900 * 3901 * Return: None 3902 * 3903 ***************************************************************************/ 3904 void 3905 ipmi_ek_display_clock_config_record(struct ipmi_ek_multi_header *record) 3906 { 3907 unsigned char resource_id; 3908 unsigned char descr_count; 3909 int i; 3910 int offset = START_DATA_OFFSET; 3911 3912 resource_id = record->data[offset++]; 3913 descr_count = record->data[offset++]; 3914 printf(" Clock Resource ID: 0x%02x\n", resource_id); 3915 printf(" Clock Configuration Descriptor Count: 0x%02x\n", descr_count); 3916 3917 for (i = 0; i < descr_count; i++) { 3918 int j = 0; 3919 unsigned char channel_id; 3920 unsigned char control; 3921 unsigned char indirect_cnt; 3922 unsigned char direct_cnt; 3923 3924 channel_id = record->data[offset++]; 3925 control = record->data[offset++]; 3926 printf("\tCLK-ID: 0x%02x - ", channel_id); 3927 printf("CTRL 0x%02x [ %12s ]\n", control, 3928 ((control & 0x1) == 0) ? "Carrier IPMC" : "Application"); 3929 3930 indirect_cnt = record->data[offset++]; 3931 direct_cnt = record->data[offset++]; 3932 printf("\t Count: Indirect 0x%02x / Direct 0x%02x\n", 3933 indirect_cnt, 3934 direct_cnt); 3935 3936 /* indirect desc */ 3937 for (j = 0; j < indirect_cnt; j++) { 3938 unsigned char feature; 3939 unsigned char dep_chn_id; 3940 3941 feature = record->data[offset++]; 3942 dep_chn_id = record->data[offset++]; 3943 printf("\t\tFeature: 0x%02x [%8s] - ", 3944 feature, 3945 (feature & 0x1) == 1 ? "Source" : "Receiver"); 3946 printf(" Dep. CLK-ID: 0x%02x\n", dep_chn_id); 3947 } 3948 /* direct desc */ 3949 for (j = 0; j < direct_cnt; j++) { 3950 unsigned char feature; 3951 unsigned char family; 3952 unsigned char accuracy; 3953 unsigned long freq; 3954 unsigned long min_freq; 3955 unsigned long max_freq; 3956 3957 feature = record->data[offset++]; 3958 family = record->data[offset++]; 3959 accuracy = record->data[offset++]; 3960 freq = (record->data[offset+0] << 0) 3961 | (record->data[offset+1] << 8) 3962 | (record->data[offset+2] << 16) 3963 | (record->data[offset+3] << 24); 3964 offset += 4; 3965 min_freq = (record->data[offset+0] << 0) 3966 | (record->data[offset+1] << 8) 3967 | (record->data[offset+2] << 16) 3968 | (record->data[offset+3] << 24); 3969 offset += 4; 3970 max_freq = (record->data[offset+0] << 0) 3971 | (record->data[offset+1] << 8) 3972 | (record->data[offset+2] << 16) 3973 | (record->data[offset+3] << 24); 3974 offset += 4; 3975 3976 printf("\t- Feature: 0x%02x - PLL: %x / Asym: %s\n", 3977 feature, 3978 (feature > 1) & 1, 3979 (feature & 1) ? "Source" : "Receiver"); 3980 printf("\tFamily: 0x%02x - AccLVL: 0x%02x\n", 3981 family, accuracy); 3982 printf("\tFRQ: %-9ld - min: %-9ld - max: %-9ld\n", 3983 freq, min_freq, max_freq); 3984 } 3985 printf("\n"); 3986 } 3987 } 3988 3989 /************************************************************************** 3990 * 3991 * Function name: ipmi_ekanalyzer_fru_file2structure 3992 * 3993 * Description: this function convert a FRU binary file into a linked list of 3994 * FRU multi record 3995 * 3996 * Restriction: None 3997 * 3998 * Input/Ouput: filename1: name of the file that contain FRU binary data 3999 * record: a pointer to current record 4000 * list_head: a pointer to header of the list 4001 * list_last: a pointer to tale of the list 4002 * 4003 * Global: None 4004 * 4005 * Return: return -1 as Error status, and 0 as Ok status 4006 * 4007 ***************************************************************************/ 4008 static int 4009 ipmi_ekanalyzer_fru_file2structure(char *filename, 4010 struct ipmi_ek_multi_header **list_head, 4011 struct ipmi_ek_multi_header **list_record, 4012 struct ipmi_ek_multi_header **list_last) 4013 { 4014 FILE *input_file; 4015 unsigned char data; 4016 unsigned char last_record = 0; 4017 unsigned int multi_offset = 0; 4018 int record_count = 0; 4019 int ret = 0; 4020 4021 input_file = fopen(filename, "r"); 4022 if (input_file == NULL) { 4023 lprintf(LOG_ERR, "File: '%s' is not found", filename); 4024 return ERROR_STATUS; 4025 } 4026 4027 fseek(input_file, START_DATA_OFFSET, SEEK_SET); 4028 data = 0; 4029 ret = fread(&data, 1, 1, input_file); 4030 if ((ret != 1) || ferror(input_file)) { 4031 lprintf(LOG_ERR, "Invalid Offset!"); 4032 fclose(input_file); 4033 return ERROR_STATUS; 4034 } 4035 if (data == 0) { 4036 lprintf(LOG_ERR, "There is no multi record in the file '%s'", 4037 filename); 4038 fclose(input_file); 4039 return ERROR_STATUS; 4040 } 4041 /* the offset value is in multiple of 8 bytes. */ 4042 multi_offset = data * 8; 4043 lprintf(LOG_DEBUG, "start multi offset = 0x%02x", 4044 multi_offset); 4045 4046 fseek(input_file, multi_offset, SEEK_SET); 4047 while (!feof(input_file)) { 4048 /* TODO - check malloc() */ 4049 *list_record = malloc(sizeof(struct ipmi_ek_multi_header)); 4050 ret = fread(&(*list_record)->header, START_DATA_OFFSET, 1, 4051 input_file); 4052 if ((ret != 1) || ferror(input_file)) { 4053 /* TODO - no free?! */ 4054 lprintf(LOG_ERR, "Invalid Header!"); 4055 fclose(input_file); 4056 return ERROR_STATUS; 4057 } 4058 if ((*list_record)->header.len == 0) { 4059 record_count++; 4060 continue; 4061 } 4062 (*list_record)->data = malloc((*list_record)->header.len); 4063 if ((*list_record)->data == NULL) { 4064 lprintf(LOG_ERR, "Failed to allocation memory size %d\n", 4065 (*list_record)->header.len); 4066 record_count++; 4067 continue; 4068 } 4069 4070 ret = fread((*list_record)->data, ((*list_record)->header.len), 4071 1, input_file); 4072 if ((ret != 1) || ferror(input_file)) { 4073 lprintf(LOG_ERR, "Invalid Record Data!"); 4074 fclose(input_file); 4075 return ERROR_STATUS; 4076 } 4077 if (verbose > 0) 4078 printf("Record %d has length = %02x\n", record_count, 4079 (*list_record)->header.len); 4080 if (verbose > 1) { 4081 int i; 4082 printf("Type: %02x", (*list_record)->header.type); 4083 for (i = 0; i < ((*list_record)->header.len); i++) { 4084 if (!(i % 8)) { 4085 printf("\n0x%02x: ", i); 4086 } 4087 printf("%02x ", 4088 (*list_record)->data[i]); 4089 } 4090 printf("\n\n"); 4091 } 4092 ipmi_ek_add_record2list(list_record, list_head, list_last); 4093 /* mask the 8th bits to see if it is the last record */ 4094 last_record = ((*list_record)->header.format) & 0x80; 4095 if (last_record) { 4096 break; 4097 } 4098 record_count++; 4099 } 4100 fclose(input_file); 4101 return OK_STATUS; 4102 } 4103 4104 /************************************************************************** 4105 * 4106 * Function name: ipmi_ek_add_record2list 4107 * 4108 * Description: this function adds a sigle FRU multi record to a linked list of 4109 * FRU multi record. 4110 * 4111 * Restriction: None 4112 * 4113 * Input/Output: record: a pointer to current record 4114 * list_head: a pointer to header of the list 4115 * list_last: a pointer to tale of the list 4116 * 4117 * Global: None 4118 * 4119 * Return: None 4120 * 4121 ***************************************************************************/ 4122 static void 4123 ipmi_ek_add_record2list(struct ipmi_ek_multi_header **record, 4124 struct ipmi_ek_multi_header **list_head, 4125 struct ipmi_ek_multi_header **list_last) 4126 { 4127 if (*list_head == NULL) { 4128 *list_head = *record; 4129 (*record)->prev = NULL; 4130 if (verbose > 2) { 4131 printf("Adding first record to list\n"); 4132 } 4133 } else { 4134 (*list_last)->next = *record; 4135 (*record)->prev = *list_last; 4136 if (verbose > 2) { 4137 printf("Add 1 record to list\n"); 4138 } 4139 } 4140 *list_last = *record; 4141 (*record)->next = NULL; 4142 } 4143 4144 /************************************************************************** 4145 * 4146 * Function name: ipmi_ek_remove_record_from_list 4147 * 4148 * Description: this function removes a sigle FRU multi record from a linked 4149 * list of FRU multi record. 4150 * 4151 * Restriction: None 4152 * 4153 * Input/Output: record: a pointer to record to be deleted 4154 * list_head: a pointer to header of the list 4155 * list_last: a pointer to tale of the list 4156 * 4157 * Global: None 4158 * 4159 * Return: None 4160 * 4161 ***************************************************************************/ 4162 static void 4163 ipmi_ek_remove_record_from_list(struct ipmi_ek_multi_header *record, 4164 struct ipmi_ek_multi_header **list_head, 4165 struct ipmi_ek_multi_header **list_last) 4166 { 4167 if (record->prev == NULL) { 4168 *list_head = record->next; 4169 } else { 4170 record->prev->next = record->next; 4171 } 4172 if (record->next == NULL) { 4173 (*list_last) = record->prev; 4174 } else { 4175 record->next->prev = record->prev; 4176 } 4177 free(record); 4178 record = NULL; 4179 } 4180