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