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 if (additional_data != NULL) { 2777 free(additional_data); 2778 additional_data = NULL; 2779 } 2780 goto out; 2781 } 2782 printf("Additional Custom Mfg. Data: %02x", 2783 additional_data[0]); 2784 for (i = 1; i < size_board; i++) { 2785 printf("-%02x", additional_data[i]); 2786 } 2787 printf("\n"); 2788 free(additional_data); 2789 additional_data = NULL; 2790 (*board_length) -= size_board; 2791 } 2792 else { 2793 printf("No Additional Custom Mfg. %d\n", *board_length); 2794 goto out; 2795 } 2796 } 2797 2798 out: 2799 file_offset = ftell(input_file); 2800 return file_offset; 2801 } 2802 2803 /************************************************************************** 2804 * 2805 * Function name: ipmi_ek_display_product_info_area 2806 * 2807 * Description: this function displays detail format of product info area record 2808 * into humain readable text format 2809 * 2810 * Restriction: Reference: IPMI Platform Management FRU Information Storage 2811 * Definition V1.0, Section 12 2812 * 2813 * Input: input_file: pointer to file stream 2814 * offset: start offset of product info area 2815 * 2816 * Output: None 2817 * 2818 * Global: None 2819 * 2820 * Return: None 2821 * 2822 ***************************************************************************/ 2823 static int 2824 ipmi_ek_display_product_info_area(FILE *input_file, long offset) 2825 { 2826 size_t file_offset; 2827 int ret = 0; 2828 unsigned char ch_len = 0; 2829 unsigned char data = 0; 2830 unsigned int len = 0; 2831 2832 if (input_file == NULL) { 2833 lprintf(LOG_ERR, "No file stream to read."); 2834 return (-1); 2835 } 2836 file_offset = ftell(input_file); 2837 printf("%s\n", EQUAL_LINE_LIMITER); 2838 printf("Product Info Area\n"); 2839 printf("%s\n", EQUAL_LINE_LIMITER); 2840 ret = fseek(input_file, offset, SEEK_SET); 2841 if (feof(input_file)) { 2842 lprintf(LOG_ERR, "Invalid Product Info Area!"); 2843 return (-1); 2844 } 2845 ret = fread(&data, 1, 1, input_file); 2846 if ((ret != 1) || ferror(input_file)) { 2847 lprintf(LOG_ERR, "Invalid Data!"); 2848 return (-1); 2849 } 2850 printf("Format Version Number: %d\n", (data & 0x0f)); 2851 if (feof(input_file)) { 2852 return (-1); 2853 } 2854 /* Have to read this into a char or else 2855 * it ends up byte swapped on big endian machines */ 2856 ret = fread(&ch_len, 1, 1, input_file); 2857 if ((ret != 1) || ferror(input_file)) { 2858 lprintf(LOG_ERR, "Invalid Length!"); 2859 return (-1); 2860 } 2861 /* length is in factor of 8 bytes */ 2862 len = ch_len * 8; 2863 printf("Area Length: %d\n", len); 2864 len -= 2; /* -1 byte of format version and -1 byte itself */ 2865 2866 ret = fread(&data, 1, 1, input_file); 2867 if ((ret != 1) || ferror(input_file)) { 2868 lprintf(LOG_ERR, "Invalid Length!"); 2869 return (-1); 2870 } 2871 2872 fread(&data, 1, 1, input_file); 2873 printf("Language Code: %d\n", data); 2874 len--; 2875 /* Product Mfg */ 2876 file_offset = ipmi_ek_display_board_info_area(input_file, 2877 "Product Manufacture Data", &len); 2878 ret = fseek(input_file, file_offset, SEEK_SET); 2879 /* Product Name */ 2880 file_offset = ipmi_ek_display_board_info_area(input_file, 2881 "Product Name", &len); 2882 ret = fseek(input_file, file_offset, SEEK_SET); 2883 /* Product Part */ 2884 file_offset = ipmi_ek_display_board_info_area(input_file, 2885 "Product Part/Model Number", &len); 2886 ret = fseek(input_file, file_offset, SEEK_SET); 2887 /* Product Version */ 2888 file_offset = ipmi_ek_display_board_info_area(input_file, 2889 "Product Version", &len); 2890 ret = fseek(input_file, file_offset, SEEK_SET); 2891 /* Product Serial */ 2892 file_offset = ipmi_ek_display_board_info_area(input_file, 2893 "Product Serial Number", &len); 2894 ret = fseek(input_file, file_offset, SEEK_SET); 2895 /* Product Asset Tag */ 2896 file_offset = ipmi_ek_display_board_info_area(input_file, 2897 "Asset Tag", &len); 2898 ret = fseek(input_file, file_offset, SEEK_SET); 2899 /* FRU file ID */ 2900 file_offset = ipmi_ek_display_board_info_area(input_file, 2901 "FRU File ID", &len); 2902 ret = fseek(input_file, file_offset, SEEK_SET); 2903 /* Custom product info area */ 2904 file_offset = ipmi_ek_display_board_info_area(input_file, 2905 "Custom", &len); 2906 return 0; 2907 } 2908 2909 /************************************************************************** 2910 * 2911 * Function name: ipmi_ek_display_record 2912 * 2913 * Description: this function displays FRU multi record information. 2914 * 2915 * Restriction: None 2916 * 2917 * Input: record: a pointer to current record 2918 * list_head: a pointer to header of the list 2919 * list_last: a pointer to tale of the list 2920 * 2921 * Output: None 2922 * 2923 * Global: None 2924 * 2925 * Return: None 2926 * 2927 ***************************************************************************/ 2928 static void 2929 ipmi_ek_display_record(struct ipmi_ek_multi_header *record, 2930 struct ipmi_ek_multi_header *list_head, 2931 struct ipmi_ek_multi_header *list_last) 2932 { 2933 if (list_head == NULL) { 2934 printf("***empty list***\n"); 2935 return; 2936 } 2937 printf("%s\n", EQUAL_LINE_LIMITER); 2938 printf("FRU Multi Info area\n"); 2939 printf("%s\n", EQUAL_LINE_LIMITER); 2940 for (record = list_head; record != NULL; record = record->next) { 2941 printf("Record Type ID: 0x%02x\n", record->header.type); 2942 printf("Record Format version: 0x%02x\n", 2943 record->header.format); 2944 if (record->header.len <= PICMG_ID_OFFSET) { 2945 continue; 2946 } 2947 /* In picmg3.0 specification, picmg record 2948 * id lower than 4 or greater than 0x2d 2949 * isn't supported 2950 */ 2951 #define PICMG_ID_LOWER_LIMIT 0x04 2952 #define PICMG_ID_UPPER_LIMIT 0x2d 2953 unsigned char picmg_id; 2954 2955 picmg_id = record->data[PICMG_ID_OFFSET]; 2956 printf("Manufacturer ID: %02x%02x%02x h\n", 2957 record->data[2], record->data[1], 2958 record->data[0]); 2959 if ((picmg_id < PICMG_ID_LOWER_LIMIT) 2960 || (picmg_id > PICMG_ID_UPPER_LIMIT)) { 2961 printf("Picmg record ID: Unsupported {0x%02x}\n", picmg_id); 2962 } else { 2963 printf("Picmg record ID: %s {0x%02x}\n", 2964 val2str(picmg_id, ipmi_ekanalyzer_picmg_record_id), 2965 picmg_id); 2966 } 2967 switch (picmg_id) { 2968 case FRU_PICMG_BACKPLANE_P2P: /*0x04*/ 2969 ipmi_ek_display_backplane_p2p_record (record); 2970 break; 2971 case FRU_PICMG_ADDRESS_TABLE: /*0x10*/ 2972 ipmi_ek_display_address_table_record (record); 2973 break; 2974 case FRU_PICMG_SHELF_POWER_DIST: /*0x11*/ 2975 ipmi_ek_display_shelf_power_distribution_record (record); 2976 break; 2977 case FRU_PICMG_SHELF_ACTIVATION: /*/0x12*/ 2978 ipmi_ek_display_shelf_activation_record (record); 2979 break; 2980 case FRU_PICMG_SHMC_IP_CONN: /*0x13*/ 2981 ipmi_ek_display_shelf_ip_connection_record (record); 2982 break; 2983 case FRU_PICMG_BOARD_P2P: /*0x14*/ 2984 ipmi_ek_display_board_p2p_record (record); 2985 break; 2986 case FRU_RADIAL_IPMB0_LINK_MAPPING: /*0x15*/ 2987 ipmi_ek_display_radial_ipmb0_record (record); 2988 break; 2989 case FRU_AMC_CURRENT: /*0x16*/ 2990 ipmi_ek_display_amc_current_record (record); 2991 break; 2992 case FRU_AMC_ACTIVATION: /*0x17*/ 2993 ipmi_ek_display_amc_activation_record (record); 2994 break; 2995 case FRU_AMC_CARRIER_P2P: /*0x18*/ 2996 ipmi_ek_display_carrier_connectivity (record); 2997 break; 2998 case FRU_AMC_P2P: /*0x19*/ 2999 ipmi_ek_display_amc_p2p_record (record); 3000 break; 3001 case FRU_AMC_CARRIER_INFO: /*0x1a*/ 3002 ipmi_ek_display_amc_carrier_info_record (record); 3003 break; 3004 case FRU_PICMG_CLK_CARRIER_P2P: /*0x2c*/ 3005 ipmi_ek_display_clock_carrier_p2p_record (record); 3006 break; 3007 case FRU_PICMG_CLK_CONFIG: /*0x2d*/ 3008 ipmi_ek_display_clock_config_record (record); 3009 break; 3010 default: 3011 if (verbose > 0) { 3012 int i; 3013 printf("%02x %02x %02x %02x %02x ", 3014 record->header.type, 3015 record->header.format, 3016 record->header.len, 3017 record->header.record_checksum, 3018 record->header.header_checksum); 3019 for (i = 0; i < record->header.len; i++) { 3020 printf("%02x ", record->data[i]); 3021 } 3022 printf("\n"); 3023 } 3024 break; 3025 } 3026 printf("%s\n", STAR_LINE_LIMITER); 3027 } 3028 } 3029 3030 /************************************************************************** 3031 * 3032 * Function name: ipmi_ek_display_backplane_p2p_record 3033 * 3034 * Description: this function displays backplane p2p record. 3035 * 3036 * Restriction: Reference: PICMG 3.0 Specification Table 3-40 3037 * 3038 * Input: record: a pointer to current record to be displayed 3039 * 3040 * Output: None 3041 * 3042 * Global: None 3043 * 3044 * Return: None 3045 * 3046 ***************************************************************************/ 3047 static void 3048 ipmi_ek_display_backplane_p2p_record(struct ipmi_ek_multi_header *record) 3049 { 3050 uint8_t index; 3051 int offset = START_DATA_OFFSET; 3052 struct fru_picmgext_slot_desc *slot_d = 3053 (struct fru_picmgext_slot_desc*)&record->data[offset]; 3054 3055 offset += sizeof(struct fru_picmgext_slot_desc); 3056 while (offset <= record->header.len) { 3057 printf(" Channel Type: "); 3058 switch (slot_d->chan_type) { 3059 case 0x00: 3060 case 0x07: 3061 printf("PICMG 2.9\n"); 3062 break; 3063 case 0x08: 3064 printf("Single Port Fabric IF\n"); 3065 break; 3066 case 0x09: 3067 printf("Double Port Fabric IF\n"); 3068 break; 3069 case 0x0a: 3070 printf("Full Channel Fabric IF\n"); 3071 break; 3072 case 0x0b: 3073 printf("Base IF\n"); 3074 break; 3075 case 0x0c: 3076 printf("Update Channel IF\n"); 3077 break; 3078 default: 3079 printf("Unknown IF\n"); 3080 break; 3081 } 3082 printf(" Slot Address: %02x\n", slot_d->slot_addr); 3083 printf(" Channel Count: %i\n", slot_d->chn_count); 3084 for (index = 0; index < (slot_d->chn_count); index++) { 3085 struct fru_picmgext_chn_desc *d = 3086 (struct fru_picmgext_chn_desc *)&record->data[offset]; 3087 if (verbose) { 3088 printf("\t" 3089 "Chn: %02x --> " 3090 "Chn: %02x in " 3091 "Slot: %02x\n", 3092 d->local_chn, 3093 d->remote_chn, 3094 d->remote_slot); 3095 } 3096 offset += sizeof(struct fru_picmgext_chn_desc); 3097 } 3098 slot_d = (struct fru_picmgext_slot_desc*)&record->data[offset]; 3099 offset += sizeof(struct fru_picmgext_slot_desc); 3100 } 3101 } 3102 3103 /************************************************************************** 3104 * 3105 * Function name: ipmi_ek_display_address_table_record 3106 * 3107 * Description: this function displays address table record. 3108 * 3109 * Restriction: Reference: PICMG 3.0 Specification Table 3-6 3110 * 3111 * Input: record: a pointer to current record to be displayed 3112 * 3113 * Output: None 3114 * 3115 * Global: None 3116 * 3117 * Return: None 3118 * 3119 ***************************************************************************/ 3120 static void 3121 ipmi_ek_display_address_table_record(struct ipmi_ek_multi_header *record) 3122 { 3123 #define SIZE_SHELF_ADDRESS_BYTE 20 3124 unsigned char entries = 0; 3125 unsigned char i; 3126 int offset = START_DATA_OFFSET; 3127 3128 printf(" Type/Len: 0x%02x\n", record->data[offset++]); 3129 printf(" Shelf Addr: "); 3130 for (i = 0; i < SIZE_SHELF_ADDRESS_BYTE; i++) { 3131 printf("0x%02x ", record->data[offset++]); 3132 } 3133 printf("\n"); 3134 entries = record->data[offset++]; 3135 printf(" Addr Table Entries count: 0x%02x\n", entries); 3136 for (i = 0; i < entries; i++) { 3137 printf("\tHWAddr: 0x%02x - SiteNum: 0x%02x - SiteType: 0x%02x \n", 3138 record->data[offset+0], 3139 record->data[offset+1], 3140 record->data[offset+2]); 3141 offset += 3; 3142 } 3143 } 3144 3145 /************************************************************************** 3146 * 3147 * Function name: ipmi_ek_display_shelf_power_distribution_record 3148 * 3149 * Description: this function displays shelf power distribution record. 3150 * 3151 * Restriction: Reference: PICMG 3.0 Specification Table 3-70 3152 * 3153 * Input: record: a pointer to current record to be displayed 3154 * 3155 * Output: None 3156 * 3157 * Global: None 3158 * 3159 * Return: None 3160 * 3161 ***************************************************************************/ 3162 static void 3163 ipmi_ek_display_shelf_power_distribution_record( 3164 struct ipmi_ek_multi_header *record) 3165 { 3166 int offset = START_DATA_OFFSET; 3167 unsigned char i; 3168 unsigned char j; 3169 unsigned char feeds = 0; 3170 3171 feeds = record->data[offset++]; 3172 printf(" Number of Power Feeds: 0x%02x\n", feeds); 3173 for (i = 0; i < feeds; i++) { 3174 unsigned char entries; 3175 unsigned long max_ext = 0; 3176 unsigned long max_int = 0; 3177 max_ext = record->data[offset+0] 3178 | (record->data[offset+1] << 8); 3179 printf(" Max External Available Current: %ld Amps\n", 3180 (max_ext * 10)); 3181 offset += 2; 3182 max_int = record->data[offset+0] 3183 | (record->data[offset+1] << 8); 3184 printf(" Max Internal Current:\t %ld Amps\n", 3185 (max_int * 10)); 3186 offset += 2; 3187 printf(" Min Expected Operating Voltage: %d Volts\n", 3188 (record->data[offset++] / 2)); 3189 entries = record->data[offset++]; 3190 printf(" Feed to FRU count: 0x%02x\n", entries); 3191 for (j = 0; j < entries; j++) { 3192 printf("\tHW: 0x%02x", record->data[offset++]); 3193 printf("\tFRU ID: 0x%02x\n", record->data[offset++]); 3194 } 3195 } 3196 } 3197 3198 /************************************************************************** 3199 * 3200 * Function name: ipmi_ek_display_shelf_activation_record 3201 * 3202 * Description: this function displays shelf activation record. 3203 * 3204 * Restriction: Reference: PICMG 3.0 Specification Table 3-73 3205 * 3206 * Input: record: a pointer to current record to be displayed 3207 * 3208 * Output: None 3209 * 3210 * Global: None 3211 * 3212 * Return: None 3213 * 3214 ***************************************************************************/ 3215 static void 3216 ipmi_ek_display_shelf_activation_record(struct ipmi_ek_multi_header *record) 3217 { 3218 unsigned char count = 0; 3219 int offset = START_DATA_OFFSET; 3220 3221 printf(" Allowance for FRU Act Readiness: 0x%02x\n", 3222 record->data[offset++]); 3223 count = record->data[offset++]; 3224 printf(" FRU activation and Power Desc Cnt: 0x%02x\n", count); 3225 while (count > 0) { 3226 printf(" FRU activation and Power descriptor:\n"); 3227 printf("\tHardware Address:\t\t0x%02x\n", 3228 record->data[offset++]); 3229 printf("\tFRU Device ID:\t\t\t0x%02x\n", 3230 record->data[offset++]); 3231 printf("\tMax FRU Power Capability:\t0x%04x Watts\n", 3232 (record->data[offset+0] 3233 | (record->data[offset+1]<<8))); 3234 offset += 2; 3235 printf("\tConfiguration parameter:\t0x%02x\n", 3236 record->data[offset++]); 3237 count --; 3238 } 3239 } 3240 3241 /************************************************************************** 3242 * 3243 * Function name: ipmi_ek_display_shelf_ip_connection_record 3244 * 3245 * Description: this function displays shelf ip connection record. 3246 * 3247 * Restriction: Fix me: Don't test yet 3248 * Reference: PICMG 3.0 Specification Table 3-31 3249 * 3250 * Input: record: a pointer to current record to be displayed 3251 * 3252 * Output: None 3253 * 3254 * Global: None 3255 * 3256 * Return: None 3257 * 3258 ***************************************************************************/ 3259 static void 3260 ipmi_ek_display_shelf_ip_connection_record(struct ipmi_ek_multi_header *record) 3261 { 3262 int ioffset = START_DATA_OFFSET; 3263 if (ioffset > record->header.len) { 3264 printf(" Shelf Manager IP Address: %d.%d.%d.%d\n", 3265 record->data[ioffset+0], 3266 record->data[ioffset+1], 3267 record->data[ioffset+2], 3268 record->data[ioffset+3]); 3269 ioffset += 4; 3270 } 3271 if (ioffset > record->header.len) { 3272 printf(" Default Gateway Address: %d.%d.%d.%d\n", 3273 record->data[ioffset+0], 3274 record->data[ioffset+1], 3275 record->data[ioffset+2], 3276 record->data[ioffset+3]); 3277 ioffset += 4; 3278 } 3279 if (ioffset > record->header.len) { 3280 printf(" Subnet Mask: %d.%d.%d.%d\n", 3281 record->data[ioffset+0], 3282 record->data[ioffset+1], 3283 record->data[ioffset+2], 3284 record->data[ioffset+3]); 3285 ioffset += 4; 3286 } 3287 } 3288 3289 /************************************************************************** 3290 * 3291 * Function name: ipmi_ek_display_shelf_fan_geography_record 3292 * 3293 * Description: this function displays shelf fan geography record. 3294 * 3295 * Restriction: Fix me: Don't test yet 3296 * Reference: PICMG 3.0 Specification Table 3-75 3297 * 3298 * Input: record: a pointer to current record to be displayed 3299 * 3300 * Output: None 3301 * 3302 * Global: None 3303 * 3304 * Return: None 3305 * 3306 ***************************************************************************/ 3307 static void 3308 ipmi_ek_display_shelf_fan_geography_record(struct ipmi_ek_multi_header *record) 3309 { 3310 int ioffset = START_DATA_OFFSET; 3311 unsigned char fan_count = 0; 3312 3313 fan_count = record->data[ioffset]; 3314 ioffset++; 3315 printf(" Fan-to-FRU Entry Count: 0x%02x\n", fan_count); 3316 while ((fan_count > 0) && (ioffset <= record->header.len)) { 3317 printf(" Fan-to-FRU Mapping Entry: {%2x%2x%2x%2x}\n", 3318 record->data[ioffset], 3319 record->data[ioffset+1], 3320 record->data[ioffset+2], 3321 record->data[ioffset+3]); 3322 printf(" Hardware Address: 0x%02x\n", 3323 record->data[ioffset++]); 3324 printf(" FRU device ID: 0x%02x\n", 3325 record->data[ioffset++]); 3326 printf(" Site Number: 0x%02x\n", 3327 record->data[ioffset++]); 3328 printf(" Site Type: 0x%02x\n", 3329 record->data[ioffset++]); 3330 fan_count --; 3331 } 3332 } 3333 3334 /************************************************************************** 3335 * 3336 * Function name: ipmi_ek_display_board_p2p_record 3337 * 3338 * Description: this function displays board pont-to-point record. 3339 * 3340 * Restriction: Reference: PICMG 3.0 Specification Table 3-44 3341 * 3342 * Input: record: a pointer to current record to be displayed 3343 * 3344 * Output: None 3345 * 3346 * Global: None 3347 * 3348 * Return: None 3349 * 3350 ***************************************************************************/ 3351 static void 3352 ipmi_ek_display_board_p2p_record(struct ipmi_ek_multi_header *record) 3353 { 3354 unsigned char guid_count; 3355 int offset = START_DATA_OFFSET; 3356 int i = 0; 3357 3358 guid_count = record->data[offset++]; 3359 printf(" GUID count: %2d\n", guid_count); 3360 for (i = 0 ; i < guid_count; i++) { 3361 int j; 3362 printf("\tGUID: "); 3363 for (j = 0; j < sizeof(struct fru_picmgext_guid); j++) { 3364 printf("%02x", record->data[offset+j]); 3365 } 3366 printf("\n"); 3367 offset += sizeof(struct fru_picmgext_guid); 3368 } 3369 for (offset; 3370 offset < record->header.len; 3371 offset += sizeof(struct fru_picmgext_link_desc)) { 3372 /* to solve little endian/big endian problem */ 3373 unsigned long data; 3374 struct fru_picmgext_link_desc * d; 3375 data = (record->data[offset+0]) 3376 | (record->data[offset+1] << 8)\ 3377 | (record->data[offset+2] << 16)\ 3378 | (record->data[offset+3] << 24); 3379 d = (struct fru_picmgext_link_desc *)&data; 3380 3381 printf(" Link Descriptor\n"); 3382 printf("\tLink Grouping ID:\t0x%02x\n", d->grouping); 3383 printf("\tLink Type Extension:\t0x%02x - ", d->ext); 3384 if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE) { 3385 switch (d->ext) { 3386 case 0: 3387 printf("10/100/1000BASE-T Link (four-pair)\n"); 3388 break; 3389 case 1: 3390 printf("ShMC Cross-connect (two-pair)\n"); 3391 break; 3392 default: 3393 printf("Unknwon\n"); 3394 break; 3395 } 3396 } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET) { 3397 switch (d->ext) { 3398 case 0: 3399 printf("Fixed 1000Base-BX\n"); 3400 break; 3401 case 1: 3402 printf("Fixed 10GBASE-BX4 [XAUI]\n"); 3403 break; 3404 case 2: 3405 printf("FC-PI\n"); 3406 break; 3407 default: 3408 printf("Unknwon\n"); 3409 break; 3410 } 3411 } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND) { 3412 printf("Unknwon\n"); 3413 } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR) { 3414 printf("Unknwon\n"); 3415 } else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE) { 3416 printf("Unknwon\n"); 3417 } else { 3418 printf("Unknwon\n"); 3419 } 3420 printf("\tLink Type:\t\t0x%02x - ", d->type); 3421 if (d->type == 0 || d->type == 0xff) { 3422 printf("Reserved\n"); 3423 } else if (d->type >= 0x06 && d->type <= 0xef) { 3424 printf("Reserved\n"); 3425 } else if (d->type >= LOWER_OEM_TYPE && d->type <= UPPER_OEM_TYPE) { 3426 printf("OEM GUID Definition\n"); 3427 } else { 3428 switch (d->type){ 3429 case FRU_PICMGEXT_LINK_TYPE_BASE: 3430 printf("PICMG 3.0 Base Interface 10/100/1000\n"); 3431 break; 3432 case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: 3433 printf("PICMG 3.1 Ethernet Fabric Interface\n"); 3434 break; 3435 case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: 3436 printf("PICMG 3.2 Infiniband Fabric Interface\n"); 3437 break; 3438 case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: 3439 printf("PICMG 3.3 Star Fabric Interface\n"); 3440 break; 3441 case FRU_PICMGEXT_LINK_TYPE_PCIE: 3442 printf("PICMG 3.4 PCI Express Fabric Interface\n"); 3443 break; 3444 default: 3445 printf("Invalid\n"); 3446 break; 3447 } 3448 } 3449 printf("\tLink Designator: \n"); 3450 printf("\t Port 0 Flag: %s\n", 3451 (d->desig_port & 0x01) ? "enable" : "disable"); 3452 printf("\t Port 1 Flag: %s\n", 3453 (d->desig_port & 0x02) ? "enable" : "disable"); 3454 printf("\t Port 2 Flag: %s\n", 3455 (d->desig_port & 0x04) ? "enable" : "disable"); 3456 printf("\t Port 3 Flag: %s\n", 3457 (d->desig_port & 0x08) ? "enable" : "disable"); 3458 printf("\t Interface: 0x%02x - ", d->desig_if); 3459 switch (d->desig_if) { 3460 case FRU_PICMGEXT_DESIGN_IF_BASE: 3461 printf("Base Interface\n"); 3462 break; 3463 case FRU_PICMGEXT_DESIGN_IF_FABRIC: 3464 printf("Fabric Interface\n"); 3465 break; 3466 case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: 3467 printf("Update Channel\n"); 3468 break; 3469 case FRU_PICMGEXT_DESIGN_IF_RESERVED: 3470 printf("Reserved\n"); 3471 break; 3472 default: 3473 printf("Invalid"); 3474 break; 3475 } 3476 printf("\t Channel Number: 0x%02x\n", 3477 d->desig_channel); 3478 } 3479 } 3480 3481 /************************************************************************** 3482 * 3483 * Function name: ipmi_ek_display_radial_ipmb0_record 3484 * 3485 * Description: this function displays radial IPMB-0 record. 3486 * 3487 * Restriction: Fix me: Don't test yet 3488 * 3489 * Input: record: a pointer to current record to be displayed 3490 * 3491 * Output: None 3492 * 3493 * Global: None 3494 * 3495 * Return: None 3496 * 3497 ***************************************************************************/ 3498 static void 3499 ipmi_ek_display_radial_ipmb0_record(struct ipmi_ek_multi_header *record) 3500 { 3501 #define SIZE_OF_CONNECTOR_DEFINER 3; /*bytes*/ 3502 int offset = START_DATA_OFFSET; 3503 /* Ref: PICMG 3.0 Specification Revision 2.0, Table 3-59 */ 3504 printf(" IPMB-0 Connector Definer: "); 3505 #ifndef WORDS_BIGENDIAN 3506 printf("%02x %02x %02x h\n", record->data[offset], 3507 record->data[offset+1], record->data[offset+2]); 3508 #else 3509 printf("%02x %02x %02x h\n", record->data[offset+2], 3510 record->data[offset+1], record->data[offset]); 3511 #endif 3512 /* 3 bytes of connector definer was used */ 3513 offset += SIZE_OF_CONNECTOR_DEFINER; 3514 printf(" IPMB-0 Connector version ID: "); 3515 #ifndef WORDS_BIGENDIAN 3516 printf("%02x %02x h\n", record->data[offset], 3517 record->data[offset+1]); 3518 #else 3519 printf("%02x %02x h\n", record->data[offset+1], 3520 record->data[offset]); 3521 #endif 3522 offset += 2; 3523 printf(" IPMB-0 Hub Descriptor Count: 0x%02x", 3524 record->data[offset++]); 3525 if (record->data[offset] < 1) { 3526 return; 3527 } 3528 for (offset; offset < record->header.len;) { 3529 unsigned char entry_count = 0; 3530 printf(" IPMB-0 Hub Descriptor\n"); 3531 printf("\tHardware Address: 0x%02x\n", 3532 record->data[offset++]); 3533 printf("\tHub Info {0x%02x}: ", record->data[offset]); 3534 /* Bit mask specified in Table 3-59 3535 * of PICMG 3.0 Specification 3536 */ 3537 if ((record->data[offset] & 0x01) == 0x01) { 3538 printf("IPMB-A only\n"); 3539 } else if ((record->data[offset] & 0x02) == 0x02) { 3540 printf("IPMB-B only\n"); 3541 } else if ((record->data[offset] & 0x03) == 0x03) { 3542 printf("IPMB-A and IPMB-B\n"); 3543 } else { 3544 printf("Reserved.\n"); 3545 } 3546 offset ++; 3547 entry_count = record->data[offset++]; 3548 printf("\tAddress Entry count: 0x%02x", entry_count); 3549 while (entry_count > 0) { 3550 printf("\t Hardware Address: 0x%02x\n", 3551 record->data[offset++]); 3552 printf("\t IPMB-0 Link Entry: 0x%02x\n", 3553 record->data[offset++]); 3554 entry_count --; 3555 } 3556 } 3557 } 3558 3559 /************************************************************************** 3560 * 3561 * Function name: ipmi_ek_display_amc_current_record 3562 * 3563 * Description: this function displays AMC current record. 3564 * 3565 * Restriction: None 3566 * 3567 * Input: record: a pointer to current record to be displayed 3568 * 3569 * Output: None 3570 * 3571 * Global: None 3572 * 3573 * Return: None 3574 * 3575 ***************************************************************************/ 3576 static void 3577 ipmi_ek_display_amc_current_record(struct ipmi_ek_multi_header *record) 3578 { 3579 unsigned char current; 3580 current = record->data[START_DATA_OFFSET]; 3581 printf(" Current draw: %.1f A @ 12V => %.2f Watt\n", 3582 (float)current / 10.0, 3583 ((float)current / 10.0) * 12.0); 3584 printf("\n"); 3585 } 3586 3587 /************************************************************************** 3588 * 3589 * Function name: ipmi_ek_display_amc_activation_record 3590 * 3591 * Description: this function displays carrier activation and current management 3592 * record. 3593 * 3594 * Restriction: Reference: AMC.0 Specification Table 3-11 and Table 3-12 3595 * 3596 * Input: record: a pointer to current record to be displayed 3597 * 3598 * Output: None 3599 * 3600 * Global: None 3601 * 3602 * Return: None 3603 * 3604 ***************************************************************************/ 3605 static void 3606 ipmi_ek_display_amc_activation_record(struct ipmi_ek_multi_header *record) 3607 { 3608 uint16_t max_current; 3609 int offset = START_DATA_OFFSET; 3610 3611 max_current = record->data[offset]; 3612 max_current |= record->data[++offset] << 8; 3613 printf(" Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n", 3614 (float) max_current / 10, 3615 (float) max_current / 10 * 12); 3616 printf(" Module Activation Readiness: %i sec.\n", 3617 record->data[++offset]); 3618 printf(" Descriptor Count: %i\n", record->data[++offset]); 3619 for (++offset; (offset < record->header.len); offset += 3) { 3620 struct fru_picmgext_activation_record *a = 3621 (struct fru_picmgext_activation_record *)&record->data[offset]; 3622 printf("\tIPMB-Address:\t\t0x%x\n", a->ibmb_addr); 3623 printf("\tMax. Module Current:\t%.2f A\n", 3624 (float)a->max_module_curr / 10); 3625 printf("\n"); 3626 } 3627 } 3628 3629 /************************************************************************** 3630 * 3631 * Function name: ipmi_ek_display_amc_p2p_record 3632 * 3633 * Description: this function display amc p2p connectivity record in humain 3634 * readable text format 3635 * 3636 * Restriction: Reference: AMC.0 Specification Table 3-16 3637 * 3638 * Input: record: a pointer to current record to be displayed 3639 * 3640 * Output: None 3641 * 3642 * Global: None 3643 * 3644 * Return: None 3645 * 3646 ***************************************************************************/ 3647 static void 3648 ipmi_ek_display_amc_p2p_record(struct ipmi_ek_multi_header *record) 3649 { 3650 int index_data = START_DATA_OFFSET; 3651 int oem_count = 0; 3652 int ch_count = 0; 3653 int index=0; 3654 3655 oem_count = record->data[index_data++]; 3656 printf("OEM GUID count: %02x\n", oem_count); 3657 if (oem_count > 0) { 3658 while (oem_count > 0) { 3659 printf("OEM GUID: "); 3660 for (index = 1; index <= SIZE_OF_GUID; index++) { 3661 printf("%02x", record->data[index_data++]); 3662 /* For a better look, display a "-" character 3663 * after each 5 bytes of OEM GUID 3664 */ 3665 if (!(index % 5)) { 3666 printf("-"); 3667 } 3668 } 3669 printf("\n"); 3670 oem_count--; 3671 } 3672 } 3673 if ((record->data[index_data] & AMC_MODULE) == AMC_MODULE) { 3674 printf("AMC module connection\n"); 3675 } else { 3676 printf("On-Carrier Device %02x h\n", 3677 (record->data[index_data] & 0x0f)); 3678 } 3679 index_data ++; 3680 ch_count = record->data[index_data++]; 3681 printf("AMC Channel Descriptor count: %02x h\n", ch_count); 3682 3683 if (ch_count > 0) { 3684 for (index = 0; index < ch_count; index++) { 3685 unsigned int data; 3686 struct fru_picmgext_amc_channel_desc_record *ch_desc; 3687 printf(" AMC Channel Descriptor {%02x%02x%02x}\n", 3688 record->data[index_data+2], 3689 record->data[index_data+1], 3690 record->data[index_data]); 3691 data = record->data[index_data] 3692 | (record->data[index_data + 1] << 8) 3693 | (record->data[index_data + 2] << 16); 3694 ch_desc = (struct fru_picmgext_amc_channel_desc_record *)&data; 3695 printf(" Lane 0 Port: %d\n", ch_desc->lane0port); 3696 printf(" Lane 1 Port: %d\n", ch_desc->lane1port); 3697 printf(" Lane 2 Port: %d\n", ch_desc->lane2port); 3698 printf(" Lane 3 Port: %d\n\n", ch_desc->lane3port); 3699 index_data += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE; 3700 } 3701 } 3702 while (index_data < record->header.len) { 3703 /* Warning: This code doesn't work with gcc version 3704 * between 4.0 and 4.3 3705 */ 3706 unsigned int data[2]; 3707 struct fru_picmgext_amc_link_desc_record *link_desc; 3708 data[0] = record->data[index_data] 3709 | (record->data[index_data + 1] << 8) 3710 | (record->data[index_data + 2] << 16) 3711 | (record->data[index_data + 3] << 24); 3712 data[1] = record->data[index_data + 4]; 3713 3714 link_desc = (struct fru_picmgext_amc_link_desc_record *)&data[0]; 3715 printf(" AMC Link Descriptor:\n"); 3716 printf("\t- Link Type: %s \n", 3717 val2str(link_desc->type, ipmi_ekanalyzer_link_type)); 3718 switch (link_desc->type) { 3719 case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: 3720 case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: 3721 case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: 3722 printf("\t- Link Type extension: %s\n", 3723 val2str(link_desc->type_ext, 3724 ipmi_ekanalyzer_extension_PCIE)); 3725 printf("\t- Link Group ID: %d\n ", 3726 link_desc->group_id); 3727 printf("\t- Link Asym. Match: %d - %s\n", 3728 link_desc->asym_match, 3729 val2str(link_desc->asym_match, 3730 ipmi_ekanalyzer_asym_PCIE)); 3731 break; 3732 case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: 3733 printf("\t- Link Type extension: %s\n", 3734 val2str (link_desc->type_ext, 3735 ipmi_ekanalyzer_extension_ETHERNET)); 3736 printf("\t- Link Group ID: %d \n", 3737 link_desc->group_id); 3738 printf("\t- Link Asym. Match: %d - %s\n", 3739 link_desc->asym_match, 3740 val2str(link_desc->asym_match, 3741 ipmi_ekanalyzer_asym_PCIE)); 3742 break; 3743 case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: 3744 printf("\t- Link Type extension: %s\n", 3745 val2str (link_desc->type_ext, 3746 ipmi_ekanalyzer_extension_STORAGE)); 3747 printf("\t- Link Group ID: %d \n", 3748 link_desc->group_id); 3749 printf("\t- Link Asym. Match: %d - %s\n", 3750 link_desc->asym_match, 3751 val2str(link_desc->asym_match, 3752 ipmi_ekanalyzer_asym_STORAGE)); 3753 break; 3754 default: 3755 printf("\t- Link Type extension: %i (Unknown)\n", 3756 link_desc->type_ext); 3757 printf("\t- Link Group ID: %d \n", 3758 link_desc->group_id); 3759 printf("\t- Link Asym. Match: %i\n", 3760 link_desc->asym_match); 3761 break; 3762 } 3763 printf("\t- AMC Link Designator:\n"); 3764 printf("\t Channel ID: %i\n", link_desc->channel_id); 3765 printf("\t\t Lane 0: %s\n", 3766 (link_desc->port_flag_0) ? "enable" : "disable"); 3767 printf("\t\t Lane 1: %s\n", 3768 (link_desc->port_flag_1) ? "enable" : "disable"); 3769 printf("\t\t Lane 2: %s\n", 3770 (link_desc->port_flag_2) ? "enable" : "disable"); 3771 printf("\t\t Lane 3: %s\n", 3772 (link_desc->port_flag_3) ? "enable" : "disable"); 3773 index_data += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE; 3774 } 3775 } 3776 3777 /************************************************************************** 3778 * 3779 * Function name: ipmi_ek_display_amc_carrier_info_record 3780 * 3781 * Description: this function displays Carrier information table. 3782 * 3783 * Restriction: Reference: AMC.0 Specification Table 3-3 3784 * 3785 * Input: record: a pointer to current record to be displayed 3786 * 3787 * Output: None 3788 * 3789 * Global: START_DATA_OFFSET 3790 * 3791 * Return: None 3792 * 3793 ***************************************************************************/ 3794 static void 3795 ipmi_ek_display_amc_carrier_info_record(struct ipmi_ek_multi_header *record) 3796 { 3797 unsigned char extVersion; 3798 unsigned char siteCount; 3799 int offset = START_DATA_OFFSET; 3800 3801 extVersion = record->data[offset++]; 3802 siteCount = record->data[offset++]; 3803 printf(" AMC.0 extension version: R%d.%d\n", 3804 (extVersion >> 0) & 0x0F, 3805 (extVersion >> 4) & 0x0F); 3806 printf(" Carrier Sie Number Count: %d\n", siteCount); 3807 while (siteCount > 0) { 3808 printf("\tSite ID (%d): %s \n", record->data[offset], 3809 val2str(record->data[offset], ipmi_ekanalyzer_module_type)); 3810 offset++; 3811 siteCount--; 3812 } 3813 printf("\n"); 3814 } 3815 3816 /************************************************************************** 3817 * 3818 * Function name: ipmi_ek_display_clock_carrier_p2p_record 3819 * 3820 * Description: this function displays Carrier clock point-to-pont 3821 * connectivity record. 3822 * 3823 * Restriction: the following code is copy from ipmi_fru.c with modification in 3824 * reference to AMC.0 Specification Table 3-29 3825 * 3826 * Input: record: a pointer to current record to be displayed 3827 * 3828 * Output: None 3829 * 3830 * Global: None 3831 * 3832 * Return: None 3833 * 3834 ***************************************************************************/ 3835 static void 3836 ipmi_ek_display_clock_carrier_p2p_record(struct ipmi_ek_multi_header *record) 3837 { 3838 unsigned char desc_count; 3839 int i; 3840 int j; 3841 int offset = START_DATA_OFFSET; 3842 3843 desc_count = record->data[offset++]; 3844 for(i = 0; i < desc_count; i++) { 3845 unsigned char resource_id; 3846 unsigned char channel_count; 3847 3848 resource_id = record->data[offset++]; 3849 channel_count = record->data[offset++]; 3850 3851 printf(" Clock Resource ID: 0x%02x\n", resource_id); 3852 printf(" Type: "); 3853 if ((resource_id & 0xC0) >> 6 == 0) { 3854 printf("On-Carrier-Device\n"); 3855 } else if ((resource_id & 0xC0) >> 6 == 1) { 3856 printf("AMC slot\n"); 3857 } else if ((resource_id & 0xC0) >> 6 == 2) { 3858 printf("Backplane\n"); 3859 } else{ 3860 printf("reserved\n"); 3861 } 3862 printf(" Channel Count: 0x%02x\n", channel_count); 3863 3864 for (j = 0; j < channel_count; j++) { 3865 unsigned char loc_channel; 3866 unsigned char rem_channel; 3867 unsigned char rem_resource; 3868 3869 loc_channel = record->data[offset++]; 3870 rem_channel = record->data[offset++]; 3871 rem_resource = record->data[offset++]; 3872 3873 printf("\tCLK-ID: 0x%02x ---> ", loc_channel); 3874 printf(" remote CLKID: 0x%02x ", rem_channel); 3875 if ((rem_resource & 0xC0) >> 6 == 0) { 3876 printf("[ Carrier-Dev"); 3877 } else if ((rem_resource & 0xC0) >> 6 == 1) { 3878 printf("[ AMC slot "); 3879 } else if ((rem_resource & 0xC0) >> 6 == 2) { 3880 printf("[ Backplane "); 3881 } else { 3882 printf("reserved "); 3883 } 3884 printf(" 0x%02x ]\n", rem_resource & 0xF); 3885 } 3886 } 3887 printf("\n"); 3888 } 3889 3890 /************************************************************************** 3891 * 3892 * Function name: ipmi_ek_display_clock_config_record 3893 * 3894 * Description: this function displays clock configuration record. 3895 * 3896 * Restriction: the following codes are copy from ipmi_fru.c with modification 3897 * in reference to AMC.0 Specification Table 3-35 and Table 3-36 3898 * 3899 * Input: record: a pointer to current record to be displayed 3900 * 3901 * Output: None 3902 * 3903 * Global: START_DATA_OFFSET 3904 * 3905 * Return: None 3906 * 3907 ***************************************************************************/ 3908 void 3909 ipmi_ek_display_clock_config_record(struct ipmi_ek_multi_header *record) 3910 { 3911 unsigned char resource_id; 3912 unsigned char descr_count; 3913 int i; 3914 int offset = START_DATA_OFFSET; 3915 3916 resource_id = record->data[offset++]; 3917 descr_count = record->data[offset++]; 3918 printf(" Clock Resource ID: 0x%02x\n", resource_id); 3919 printf(" Clock Configuration Descriptor Count: 0x%02x\n", descr_count); 3920 3921 for (i = 0; i < descr_count; i++) { 3922 int j = 0; 3923 unsigned char channel_id; 3924 unsigned char control; 3925 unsigned char indirect_cnt; 3926 unsigned char direct_cnt; 3927 3928 channel_id = record->data[offset++]; 3929 control = record->data[offset++]; 3930 printf("\tCLK-ID: 0x%02x - ", channel_id); 3931 printf("CTRL 0x%02x [ %12s ]\n", control, 3932 ((control & 0x1) == 0) ? "Carrier IPMC" : "Application"); 3933 3934 indirect_cnt = record->data[offset++]; 3935 direct_cnt = record->data[offset++]; 3936 printf("\t Count: Indirect 0x%02x / Direct 0x%02x\n", 3937 indirect_cnt, 3938 direct_cnt); 3939 3940 /* indirect desc */ 3941 for (j = 0; j < indirect_cnt; j++) { 3942 unsigned char feature; 3943 unsigned char dep_chn_id; 3944 3945 feature = record->data[offset++]; 3946 dep_chn_id = record->data[offset++]; 3947 printf("\t\tFeature: 0x%02x [%8s] - ", 3948 feature, 3949 (feature & 0x1) == 1 ? "Source" : "Receiver"); 3950 printf(" Dep. CLK-ID: 0x%02x\n", dep_chn_id); 3951 } 3952 /* direct desc */ 3953 for (j = 0; j < direct_cnt; j++) { 3954 unsigned char feature; 3955 unsigned char family; 3956 unsigned char accuracy; 3957 unsigned long freq; 3958 unsigned long min_freq; 3959 unsigned long max_freq; 3960 3961 feature = record->data[offset++]; 3962 family = record->data[offset++]; 3963 accuracy = record->data[offset++]; 3964 freq = (record->data[offset+0] << 0) 3965 | (record->data[offset+1] << 8) 3966 | (record->data[offset+2] << 16) 3967 | (record->data[offset+3] << 24); 3968 offset += 4; 3969 min_freq = (record->data[offset+0] << 0) 3970 | (record->data[offset+1] << 8) 3971 | (record->data[offset+2] << 16) 3972 | (record->data[offset+3] << 24); 3973 offset += 4; 3974 max_freq = (record->data[offset+0] << 0) 3975 | (record->data[offset+1] << 8) 3976 | (record->data[offset+2] << 16) 3977 | (record->data[offset+3] << 24); 3978 offset += 4; 3979 3980 printf("\t- Feature: 0x%02x - PLL: %x / Asym: %s\n", 3981 feature, 3982 (feature > 1) & 1, 3983 (feature & 1) ? "Source" : "Receiver"); 3984 printf("\tFamily: 0x%02x - AccLVL: 0x%02x\n", 3985 family, accuracy); 3986 printf("\tFRQ: %-9ld - min: %-9ld - max: %-9ld\n", 3987 freq, min_freq, max_freq); 3988 } 3989 printf("\n"); 3990 } 3991 } 3992 3993 /************************************************************************** 3994 * 3995 * Function name: ipmi_ekanalyzer_fru_file2structure 3996 * 3997 * Description: this function convert a FRU binary file into a linked list of 3998 * FRU multi record 3999 * 4000 * Restriction: None 4001 * 4002 * Input/Ouput: filename1: name of the file that contain FRU binary data 4003 * record: a pointer to current record 4004 * list_head: a pointer to header of the list 4005 * list_last: a pointer to tale of the list 4006 * 4007 * Global: None 4008 * 4009 * Return: return -1 as Error status, and 0 as Ok status 4010 * 4011 ***************************************************************************/ 4012 static int 4013 ipmi_ekanalyzer_fru_file2structure(char *filename, 4014 struct ipmi_ek_multi_header **list_head, 4015 struct ipmi_ek_multi_header **list_record, 4016 struct ipmi_ek_multi_header **list_last) 4017 { 4018 FILE *input_file; 4019 unsigned char data; 4020 unsigned char last_record = 0; 4021 unsigned int multi_offset = 0; 4022 int record_count = 0; 4023 int ret = 0; 4024 4025 input_file = fopen(filename, "r"); 4026 if (input_file == NULL) { 4027 lprintf(LOG_ERR, "File: '%s' is not found", filename); 4028 return ERROR_STATUS; 4029 } 4030 4031 fseek(input_file, START_DATA_OFFSET, SEEK_SET); 4032 data = 0; 4033 ret = fread(&data, 1, 1, input_file); 4034 if ((ret != 1) || ferror(input_file)) { 4035 lprintf(LOG_ERR, "Invalid Offset!"); 4036 fclose(input_file); 4037 return ERROR_STATUS; 4038 } 4039 if (data == 0) { 4040 lprintf(LOG_ERR, "There is no multi record in the file '%s'", 4041 filename); 4042 fclose(input_file); 4043 return ERROR_STATUS; 4044 } 4045 /* the offset value is in multiple of 8 bytes. */ 4046 multi_offset = data * 8; 4047 lprintf(LOG_DEBUG, "start multi offset = 0x%02x", 4048 multi_offset); 4049 4050 fseek(input_file, multi_offset, SEEK_SET); 4051 while (!feof(input_file)) { 4052 /* TODO - check malloc() */ 4053 *list_record = malloc(sizeof(struct ipmi_ek_multi_header)); 4054 ret = fread(&(*list_record)->header, START_DATA_OFFSET, 1, 4055 input_file); 4056 if ((ret != 1) || ferror(input_file)) { 4057 /* TODO - no free?! */ 4058 lprintf(LOG_ERR, "Invalid Header!"); 4059 fclose(input_file); 4060 return ERROR_STATUS; 4061 } 4062 if ((*list_record)->header.len == 0) { 4063 record_count++; 4064 continue; 4065 } 4066 (*list_record)->data = malloc((*list_record)->header.len); 4067 if ((*list_record)->data == NULL) { 4068 lprintf(LOG_ERR, "Failed to allocation memory size %d\n", 4069 (*list_record)->header.len); 4070 record_count++; 4071 continue; 4072 } 4073 4074 ret = fread((*list_record)->data, ((*list_record)->header.len), 4075 1, input_file); 4076 if ((ret != 1) || ferror(input_file)) { 4077 lprintf(LOG_ERR, "Invalid Record Data!"); 4078 fclose(input_file); 4079 return ERROR_STATUS; 4080 } 4081 if (verbose > 0) 4082 printf("Record %d has length = %02x\n", record_count, 4083 (*list_record)->header.len); 4084 if (verbose > 1) { 4085 int i; 4086 printf("Type: %02x", (*list_record)->header.type); 4087 for (i = 0; i < ((*list_record)->header.len); i++) { 4088 if (!(i % 8)) { 4089 printf("\n0x%02x: ", i); 4090 } 4091 printf("%02x ", 4092 (*list_record)->data[i]); 4093 } 4094 printf("\n\n"); 4095 } 4096 ipmi_ek_add_record2list(list_record, list_head, list_last); 4097 /* mask the 8th bits to see if it is the last record */ 4098 last_record = ((*list_record)->header.format) & 0x80; 4099 if (last_record) { 4100 break; 4101 } 4102 record_count++; 4103 } 4104 fclose(input_file); 4105 return OK_STATUS; 4106 } 4107 4108 /************************************************************************** 4109 * 4110 * Function name: ipmi_ek_add_record2list 4111 * 4112 * Description: this function adds a sigle FRU multi record to a linked list of 4113 * FRU multi record. 4114 * 4115 * Restriction: None 4116 * 4117 * Input/Output: record: a pointer to current record 4118 * list_head: a pointer to header of the list 4119 * list_last: a pointer to tale of the list 4120 * 4121 * Global: None 4122 * 4123 * Return: None 4124 * 4125 ***************************************************************************/ 4126 static void 4127 ipmi_ek_add_record2list(struct ipmi_ek_multi_header **record, 4128 struct ipmi_ek_multi_header **list_head, 4129 struct ipmi_ek_multi_header **list_last) 4130 { 4131 if (*list_head == NULL) { 4132 *list_head = *record; 4133 (*record)->prev = NULL; 4134 if (verbose > 2) { 4135 printf("Adding first record to list\n"); 4136 } 4137 } else { 4138 (*list_last)->next = *record; 4139 (*record)->prev = *list_last; 4140 if (verbose > 2) { 4141 printf("Add 1 record to list\n"); 4142 } 4143 } 4144 *list_last = *record; 4145 (*record)->next = NULL; 4146 } 4147 4148 /************************************************************************** 4149 * 4150 * Function name: ipmi_ek_remove_record_from_list 4151 * 4152 * Description: this function removes a sigle FRU multi record from a linked 4153 * list of FRU multi record. 4154 * 4155 * Restriction: None 4156 * 4157 * Input/Output: record: a pointer to record to be deleted 4158 * list_head: a pointer to header of the list 4159 * list_last: a pointer to tale of the list 4160 * 4161 * Global: None 4162 * 4163 * Return: None 4164 * 4165 ***************************************************************************/ 4166 static void 4167 ipmi_ek_remove_record_from_list(struct ipmi_ek_multi_header *record, 4168 struct ipmi_ek_multi_header **list_head, 4169 struct ipmi_ek_multi_header **list_last) 4170 { 4171 if (record->prev == NULL) { 4172 *list_head = record->next; 4173 } else { 4174 record->prev->next = record->next; 4175 } 4176 if (record->next == NULL) { 4177 (*list_last) = record->prev; 4178 } else { 4179 record->next->prev = record->prev; 4180 } 4181 free(record); 4182 record = NULL; 4183 } 4184