diff options
Diffstat (limited to 'lib/ipmi_ekanalyzer.c')
| -rw-r--r-- | lib/ipmi_ekanalyzer.c | 4195 | 
1 files changed, 4195 insertions, 0 deletions
| diff --git a/lib/ipmi_ekanalyzer.c b/lib/ipmi_ekanalyzer.c new file mode 100644 index 0000000..2ac1012 --- /dev/null +++ b/lib/ipmi_ekanalyzer.c @@ -0,0 +1,4195 @@ +/* + * Copyright (c) 2007 Kontron Canada, Inc.  All Rights Reserved. + * + * Base on code from + * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include <ipmitool/ipmi_ekanalyzer.h> +#include <ipmitool/log.h> +#include <ipmitool/helper.h> +#include <ipmitool/ipmi_strings.h> + +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#define NO_MORE_INFO_FIELD         0xc1 +#define TYPE_CODE 0xc0 /*Language code*/ + +/***************************************************************** +* CONSTANT +*****************************************************************/ +const int ERROR_STATUS  = -1; +const int OK_STATUS     = 0; + +const char * STAR_LINE_LIMITER = +            "*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"; +const char * EQUAL_LINE_LIMITER = +            "================================================================="; +const int SIZE_OF_FILE_TYPE          = 3; +const unsigned char AMC_MODULE       = 0x80; +const int PICMG_ID_OFFSET            = 3; +const unsigned int COMPARE_CANDIDATE = 2; +/*In AMC.0 or PICMG 3.0 specification offset start from 0 with 3 bytes of +* Mfg.ID, 1 byte of Picmg record Id, and +* 1 byte of format version, so the data offset start from 5 +*/ +const int START_DATA_OFFSET         = 5; +const int LOWER_OEM_TYPE            = 0xf0; +const int UPPER_OEM_TYPE            = 0xfe; +const unsigned char DISABLE_PORT    = 0x1f; + +const struct valstr ipmi_ekanalyzer_module_type[] = { +   { ON_CARRIER_FRU_FILE,     "On-Carrier Device" }, +   { A1_AMC_FRU_FILE,         "AMC slot A1" }, +   { A2_AMC_FRU_FILE,         "AMC slot A2" }, +   { A3_AMC_FRU_FILE,         "AMC slot A3" }, +   { A4_AMC_FRU_FILE,         "AMC slot A4" }, +   { B1_AMC_FRU_FILE,         "AMC slot B1" }, +   { B2_AMC_FRU_FILE,         "AMC slot B2" }, +   { B3_AMC_FRU_FILE,         "AMC slot B3" }, +   { B4_AMC_FRU_FILE,         "AMC slot B4" }, +   { RTM_FRU_FILE,            "RTM" }, /*This is OEM specific module*/ +   { CONFIG_FILE,             "Configuration file" }, +   { SHELF_MANAGER_FRU_FILE,  "Shelf Manager" }, +   { 0xffff ,                 NULL }, +}; + +const struct valstr ipmi_ekanalyzer_IPMBL_addr[] = { +   { 0x72,         "AMC slot A1" }, +   { 0x74,         "AMC slot A2" }, +   { 0x76,         "AMC slot A3" }, +   { 0x78,         "AMC slot A4" }, +   { 0x7a,         "AMC slot B1" }, +   { 0x7c,         "AMC slot B2" }, +   { 0x7e,         "AMC slot B3" }, +   { 0x80,         "AMC slot B4" }, +   { 0x90,         "RTM"}, /*This is OEM specific module*/ +   { 0xffff ,      NULL }, +}; + +const struct valstr ipmi_ekanalyzer_link_type[] = { +   { 0x00,         "Reserved" }, +   { 0x01,         "Reserved" }, +   { 0x02,         "AMC.1 PCI Express" }, +   { 0x03,         "AMC.1 PCI Express Advanced Switching" }, +   { 0x04,         "AMC.1 PCI Express Advanced Switching" }, +   { 0x05,         "AMC.2 Ethernet" }, +   { 0x06,         "AMC.4 Serial RapidIO" }, +   { 0x07,         "AMC.3 Storage" }, +   /*This is OEM specific module*/ +   { 0xf0,         "OEM Type 0"}, +   { 0xf1,         "OEM Type 1"}, +   { 0xf2,         "OEM Type 2"}, +   { 0xf3,         "OEM Type 3"}, +   { 0xf4,         "OEM Type 4"}, +   { 0xf5,         "OEM Type 5"}, +   { 0xf6,         "OEM Type 6"}, +   { 0xf7,         "OEM Type 7"}, +   { 0xf8,         "OEM Type 8"}, +   { 0xf9,         "OEM Type 9"}, +   { 0xfa,         "OEM Type 10"}, +   { 0xfb,         "OEM Type 11"}, +   { 0xfc,         "OEM Type 12"}, +   { 0xfd,         "OEM Type 13"}, +   { 0xfe,         "OEM Type 14"}, +   { 0xff ,        "Reserved" }, +}; + +/*Reference: AMC.1 specification*/ +const struct valstr ipmi_ekanalyzer_extension_PCIE[] = { +   { 0x00,         "Gen 1 capable - non SSC" }, +   { 0x01,         "Gen 1 capable - SSC" }, +   { 0x02,         "Gen 2 capable - non SSC" }, +   { 0x03,         "Gen 3 capable - SSC" }, +   { 0x0f,         "Reserved"}, +}; +/*Reference: AMC.2 specification*/ +const struct valstr ipmi_ekanalyzer_extension_ETHERNET[] = { +   { 0x00,         "1000BASE-BX (SerDES Gigabit) Ethernet link" }, +   { 0x01,         "10GBASE-BX4 10 Gigabit Ethernet link" }, +}; +/*Reference: AMC.3 specification*/ +const struct valstr ipmi_ekanalyzer_extension_STORAGE[] = { +   { 0x00,         "Fibre Channel  (FC)" }, +   { 0x01,         "Serial ATA (SATA)" }, +   { 0x02,         "Serial Attached SCSI (SAS/SATA)" }, +}; + +const struct valstr ipmi_ekanalyzer_asym_PCIE[] = { +   { 0x00,         "exact match"}, +   { 0x01,         "provides a Primary PCI Express Port" }, +   { 0x02,         "provides a Secondary PCI Express Port" }, +}; + +const struct valstr ipmi_ekanalyzer_asym_STORAGE[] = { +   { 0x00,         "FC or SAS interface {exact match}" }, +   { 0x01,         "SATA Server interface" }, +   { 0x02,         "SATA Client interface" }, +   { 0x03,         "Reserved" }, +}; + +const struct valstr ipmi_ekanalyzer_picmg_record_id[] = { +   { 0x04,         "Backplane Point to Point Connectivity Record" }, +   { 0x10,         "Address Table Record" }, +   { 0x11,         "Shelf Power Distribution Record" }, +   { 0x12,         "Shelf Activation and Power Management Record" }, +   { 0x13,         "Shelf Manager IP Connection Record" }, +   { 0x14,         "Board Point to Point Connectivity Record" }, +   { 0x15,         "Radial IPMB-0 Link Mapping Record" }, +   { 0x16,         "Module Current Requirements Record" }, +   { 0x17,         "Carrier Activation and Power Management Record" }, +   { 0x18,         "Carrier Point-to-Point Connectivity Record" }, +   { 0x19,         "AdvancedMC Point-to-Point Connectivity Record" }, +   { 0x1a,         "Carrier Information Table" }, +   { 0x1b,         "Shelf Fan Geography Record" }, +   { 0x2c,         "Carrier Clock Point-to-Point Connectivity Record" }, +   { 0x2d,         "Clock Configuration Record" }, +}; + +extern int verbose; + +struct ipmi_ek_multi_header { +   struct fru_multirec_header header; +   unsigned char * data; +   struct ipmi_ek_multi_header * prev; +   struct ipmi_ek_multi_header * next; +}; + +struct ipmi_ek_amc_p2p_connectivity_record{ +   unsigned char guid_count; +   struct fru_picmgext_guid * oem_guid; +   unsigned char rsc_id; +   unsigned char ch_count; +   struct fru_picmgext_amc_channel_desc_record * ch_desc; +   unsigned char link_desc_count; +   struct fru_picmgext_amc_link_desc_record * link_desc; +   int * matching_result; /*For link descriptor comparision*/ +}; + +/***************************************************************************** +* Function prototype +******************************************************************************/ +/**************************************************************************** +* command Functions +*****************************************************************************/ +static int ipmi_ekanalyzer_print( int argc, char * opt, +                        char ** filename, int * file_type ); + +static tboolean ipmi_ekanalyzer_ekeying_match( int argc, char * opt, +                        char ** filename, int * file_type ); + +/**************************************************************************** +* Linked list Functions +*****************************************************************************/ +static void ipmi_ek_add_record2list( struct ipmi_ek_multi_header ** record, +      struct ipmi_ek_multi_header ** list_head, +      struct ipmi_ek_multi_header ** list_last ); + +static void ipmi_ek_display_record( struct ipmi_ek_multi_header * record, +      struct ipmi_ek_multi_header * list_head, +      struct ipmi_ek_multi_header * list_last ); + +static void ipmi_ek_remove_record_from_list( +      struct ipmi_ek_multi_header * record, +      struct ipmi_ek_multi_header ** list_head, +      struct ipmi_ek_multi_header ** list_last ); + +static int ipmi_ekanalyzer_fru_file2structure( char * filename, +      struct ipmi_ek_multi_header ** list_head, +      struct ipmi_ek_multi_header ** list_record, +      struct ipmi_ek_multi_header ** list_last ); + +/**************************************************************************** +* Ekeying match Functions +*****************************************************************************/ +static int ipmi_ek_matching_process( int * file_type, int index1, int index2, +      struct ipmi_ek_multi_header ** list_head, +      struct ipmi_ek_multi_header ** list_last, char * opt, +      struct ipmi_ek_multi_header * pphysical ); + +static int ipmi_ek_get_resource_descriptor( int port_count, int index, +      struct fru_picmgext_carrier_p2p_descriptor * port_desc, +      struct ipmi_ek_multi_header * record ); + +static int ipmi_ek_create_amc_p2p_record( struct ipmi_ek_multi_header * record, +      struct ipmi_ek_amc_p2p_connectivity_record * amc_record ); + +static int ipmi_ek_compare_link( struct ipmi_ek_multi_header * physic_record, +      struct ipmi_ek_amc_p2p_connectivity_record record1, +      struct ipmi_ek_amc_p2p_connectivity_record record2, +      char * opt, int file_type1, int file_type2 ); + +static tboolean ipmi_ek_compare_channel_descriptor( +      struct fru_picmgext_amc_channel_desc_record ch_desc1, +      struct fru_picmgext_amc_channel_desc_record ch_desc2, +      struct fru_picmgext_carrier_p2p_descriptor * port_desc, +      int index_port, unsigned char rsc_id ); + +static int ipmi_ek_compare_link_descriptor( +      struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, +      struct ipmi_ek_amc_p2p_connectivity_record record2, int index2 ); + +static int ipmi_ek_compare_asym( unsigned char asym[COMPARE_CANDIDATE] ); + +static int ipmi_ek_compare_number_of_enable_port( +      struct fru_picmgext_amc_link_desc_record link_desc[COMPARE_CANDIDATE] ); + +static int ipmi_ek_check_physical_connectivity( +      struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, +      struct ipmi_ek_amc_p2p_connectivity_record record2, int index2, +      struct ipmi_ek_multi_header * record, +      int filetype1, int filetype2, char * option ); + +/**************************************************************************** +* Display Functions +*****************************************************************************/ +static int ipmi_ek_display_fru_header( char * filename ); + +static int ipmi_ek_display_fru_header_detail(char * filename); + +static int ipmi_ek_display_chassis_info_area(FILE * input_file, long offset); + +static size_t ipmi_ek_display_board_info_area( FILE * input_file, +      char * board_type, unsigned int * board_length ); + +static int ipmi_ek_display_product_info_area(FILE * input_file, long offset); + +static tboolean ipmi_ek_display_link_descriptor( int file_type, +      unsigned char rsc_id, char * str, +      struct fru_picmgext_amc_link_desc_record link_desc ); + +static void ipmi_ek_display_oem_guid( +      struct ipmi_ek_amc_p2p_connectivity_record amc_record1 ); + +static int ipmi_ek_display_carrier_connectivity( +      struct ipmi_ek_multi_header * record ); + +static int ipmi_ek_display_power( int argc, char * opt, +      char ** filename, int * file_type ); + +static void ipmi_ek_display_current_descriptor( +      struct fru_picmgext_carrier_activation_record car, +      struct fru_picmgext_activation_record * cur_desc, char * filename ); + +static void ipmi_ek_display_backplane_p2p_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_address_table_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_shelf_power_distribution_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_shelf_activation_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_shelf_ip_connection_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_shelf_fan_geography_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_board_p2p_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_radial_ipmb0_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_current_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_activation_record ( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_p2p_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_carrier_info_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_clock_carrier_p2p_record( +      struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_clock_config_record( +      struct ipmi_ek_multi_header * record ); + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_usage +* +* Description  : Print the usage (help menu) of ekeying analyzer tool +* +* Restriction  : None +* +* Input        : None +* +* Output       : None +* +* Global       : None +* +* Return       :   None +* +***************************************************************************/ +static void +ipmi_ekanalyzer_usage( void ) +{ +	lprintf(LOG_NOTICE, "Ekeying analyzer tool version 1.00"); +	lprintf(LOG_NOTICE, "ekanalyzer Commands:"); +	lprintf(LOG_NOTICE, +			"      print    [carrier | power | all] <oc=filename1> <b1=filename2>..."); +	lprintf(LOG_NOTICE, +			"      frushow  <b2=filename>"); +	lprintf(LOG_NOTICE, +			"      summary  [match | unmatch | all] <oc=filename1> <b1=filename2>..."); +} + +/************************************************************************** +* +* Function name: ipmi_ek_get_file_type +* +* Description: this function takes an argument, then xtract the file type and +*              convert into module type (on carrier, AMC,...) value. +* +* +* Restriction: None +* +* Input:       argument: strings contain the type and the name of the file +*                        together +* +* Output:      None +* +* Global:      None +* +* Return:      Return value of module type: On carrier FRU file, A1 FRUM file... +*           if the file type is invalid, it return -1. See structure +*           ipmi_ekanalyzer_module_type for a list of valid type. +***************************************************************************/ +static int +ipmi_ek_get_file_type( char * argument ) +{ +   int index_name=0; +   int filetype = ERROR_STATUS; + +   if( strlen (argument) > MIN_ARGUMENT ){ +      if( strncmp( argument, "oc=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype =  ON_CARRIER_FRU_FILE; +      } +      else if( strncmp( argument, "a1=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = A1_AMC_FRU_FILE; +      } +      else if( strncmp( argument, "a2=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = A2_AMC_FRU_FILE; +      } +      else if( strncmp( argument, "a3=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = A3_AMC_FRU_FILE; +      } +      else if( strncmp( argument, "a4=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = A4_AMC_FRU_FILE; +      } +      else if( strncmp( argument, "b1=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = B1_AMC_FRU_FILE; +      } +      else if( strncmp( argument, "b2=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = B2_AMC_FRU_FILE; +      } +      else if( strncmp( argument, "b3=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = B3_AMC_FRU_FILE; +      } +      else if( strncmp( argument, "b4=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = B4_AMC_FRU_FILE; +      } +      else if( strncmp( argument, "rt=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = RTM_FRU_FILE; +      } +      else if( strncmp( argument, "rc=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = CONFIG_FILE; +      } +      else if( strncmp( argument, "sm=", SIZE_OF_FILE_TYPE ) == 0 ) { +         filetype = SHELF_MANAGER_FRU_FILE; +      } +      else{ +         filetype = ERROR_STATUS; +      } +   } +   return filetype; +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_main +* +* Description: Main program of ekeying analyzer. It calls the appropriate +*           function according to the command received. +* +* Restriction: None +* +* Input: ipmi_intf * intf: ? +*        int argc : number of argument received +*        int ** argv: argument strings +* +* Output: None +* +* Global: None +* +* Return:   OK_STATUS as succes or ERROR_STATUS as error +* +***************************************************************************/ +int +ipmi_ekanalyzer_main( struct ipmi_intf * intf, int argc, char ** argv ) +{ +   int rc = ERROR_STATUS; +   int file_type[MAX_FILE_NUMBER]; +   int tmp_ret = 0; +   char * filename[MAX_FILE_NUMBER]; +   unsigned int argument_offset = 0; +   unsigned int type_offset = 0; +   /*list des multi record*/ +   struct ipmi_ek_multi_header * list_head = NULL; +   struct ipmi_ek_multi_header * list_record = NULL; +   struct ipmi_ek_multi_header * list_last = NULL; + +   if ( (argc == 0) || ( (argc - 1) > MAX_FILE_NUMBER ) ){ +      lprintf(LOG_ERR, "Too few or too many arguments!"); +      ipmi_ekanalyzer_usage(); +      rc = ERROR_STATUS; +   } +   else if ( strcmp(argv[argument_offset], "help") == 0) { +      ipmi_ekanalyzer_usage(); +      rc = 0; +   } +   else if ( (strcmp(argv[argument_offset], "frushow") == 0) +               && (argc > (MIN_ARGUMENT-1) ) +           ){ +      for ( type_offset = 0; type_offset < (argc-1); type_offset++ ){ +         argument_offset++; +         file_type[type_offset] = ipmi_ek_get_file_type (argv[argument_offset]); +         if ( file_type[type_offset] != ERROR_STATUS ){ +            if ( file_type[type_offset] != CONFIG_FILE ){ +               /* because of strlen doesn't count '\0', we need to add 1 byte for +               * this character to filename size +               */ +               filename[type_offset] = malloc( strlen(argv[argument_offset]) + 1 +                                                - SIZE_OF_FILE_TYPE +                                             ); +               if( filename[type_offset] != NULL ){ +                  strcpy(filename[type_offset], +                              &argv[argument_offset][SIZE_OF_FILE_TYPE]); +                  printf("Start converting file '%s'...\n", filename[type_offset]); +                  /* Display FRU header offset */ +                  rc = ipmi_ek_display_fru_header (filename[type_offset]); + +                  if ( rc != ERROR_STATUS ){ +                     /* Display FRU header info in detail record */ +                     tmp_ret = ipmi_ek_display_fru_header_detail(filename[type_offset]); +                     /* Convert from binary data into multi record structure */ +                     rc = ipmi_ekanalyzer_fru_file2structure ( filename[type_offset], +                             &list_head, &list_record, &list_last ); + +                     ipmi_ek_display_record ( list_record, list_head, list_last ); +                     /* Remove record of list */ +                     while ( list_head != NULL ){ +                        ipmi_ek_remove_record_from_list( list_head, +                                 &list_head,&list_last ); +                        if (verbose > 1) +                           printf("record has been removed!\n"); +                     } +                  } +                  free(filename[type_offset]); +                  filename[type_offset] = NULL; +               } +            } +         } +         else{ +            lprintf(LOG_ERR, "Invalid file type!"); +            lprintf(LOG_ERR, "   ekanalyzer frushow <xx=frufile> ..."); +         } +      } +   } +   else if ( (strcmp(argv[argument_offset], "print") == 0) +             || (strcmp(argv[argument_offset], "summary") == 0) +           ){ +      /*Display help of the correspond command if there is not enought argument +      * passing in command line +      */ +      if ( argc < MIN_ARGUMENT ){ +         lprintf(LOG_ERR, "Not enough parameters given."); +         if ( strcmp(argv[argument_offset], "print") == 0 ){ +            lprintf(LOG_ERR, "   ekanalyzer print [carrier/power/all]" +                             " <xx=frufile> <xx=frufile> [xx=frufile]" +                   ); +         } +         else{ +            lprintf(LOG_ERR, "   ekanalyzer summary [match/ unmatch/ all]" +                             " <xx=frufile> <xx=frufile> [xx=frufile]" +                   ); +         } +      } +      else{ +         char * option; +         /*index=1 indicates start position of first file name in command line*/ +         int index = 1; +         int filename_size=0; + +         argument_offset++; +         if ( (strcmp(argv[argument_offset], "carrier") == 0) +               || (strcmp(argv[argument_offset], "power") == 0) +               || (strcmp(argv[argument_offset], "all") == 0) +            ){ +            option = argv[argument_offset]; +            index ++; +            argc--; +         } +         else if ( ( strcmp(argv[argument_offset], "match") == 0 ) +                     || ( strcmp(argv[argument_offset], "unmatch") == 0 ) +                 ){ +                  option = argv[argument_offset]; +                  index ++; +                  argc--; +         } +         /*since the command line must receive xx=filename, so the position of +         * "=" sign is 2 +         */ +         else if ( strncmp(&argv[argument_offset][2], "=", 1) == 0 ){ +            option = "default"; +            /* Since there is no option from user, the first argument +            * becomes first file type */ +            index = 1; /* index of argument */ +         } +         else{ +            option = "invalid"; +            printf("Invalid option '%s'\n", argv[argument_offset]); +            argument_offset--; +            if (strcmp(argv[0], "print") == 0){ +               lprintf (LOG_ERR, "   ekanalyzer print [carrier/power/all]" +                                 " <xx=frufile> <xx=frufile> [xx=frufile]" +                       ); +            } +            else{ +               lprintf (LOG_ERR, "   ekanalyzer summary [match/ unmatch/ all]" +                                 " <xx=frufile> <xx=frufile> [xx=frufile]" +                       ); +            } +            rc = ERROR_STATUS; +         } +         if ( strcmp(option, "invalid") != 0 ){ +            int i=0; + +            for ( i = 0; i < (argc-1); i++){ +               file_type[i] = ipmi_ek_get_file_type (argv[index]); +               if ( file_type[i] == ERROR_STATUS ){ +                  /* display the first 2 charactors (file type) of argument */ +                  lprintf(LOG_ERR, "Invalid file type: %c%c\n", argv[index][0], +                         argv[index][1]); +                  ipmi_ekanalyzer_usage(); +                  rc = ERROR_STATUS; +                  break; +               } +               /*size is equal to string size minus 3 bytes of file type plus +               * 1 byte of '\0' since the strlen doesn't count the '\0' +               */ +               filename_size = strlen( argv[index] ) - SIZE_OF_FILE_TYPE + 1; +               if ( filename_size > 0 ){ +                  filename[i] = malloc( filename_size ); +                  if (filename[i] != NULL) +                     strcpy( filename[i], &argv[index][SIZE_OF_FILE_TYPE] ); +               } +               rc = OK_STATUS; +               index++; +            } +            if ( rc != ERROR_STATUS ){ +               if (verbose > 0){ +                  for (i = 0; i < (argc-1); i++){ +                     printf ("Type: %s,   ", +                         val2str(file_type[i], ipmi_ekanalyzer_module_type)); +                     printf("file name: %s\n", filename[i]); +                  } +               } +               if (strcmp(argv[0], "print") == 0){ +                  rc = ipmi_ekanalyzer_print( +                                    (argc-1), option, filename, file_type); +               } +               else{ +                  rc = ipmi_ekanalyzer_ekeying_match( +                                    (argc-1), option, filename, file_type); +               } +               for (i = 0; i < (argc-1); i++){ +                  if (filename[i] != NULL){ +                     free(filename[i]); +                     filename[i] = NULL; +                  } +               } +            } /* End of ERROR_STATUS */ +         } /* End of comparison of invalid option */ +      } /* End of else MIN_ARGUMENT */ +   } /* End of print or summary option */ +   else{ +      lprintf(LOG_ERR, "Invalid ekanalyzer command: %s", argv[0]); +      ipmi_ekanalyzer_usage(); +      rc = ERROR_STATUS; +   } + +   return rc; +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_print +* +* Description: this function will display the topology, power or both +*            information together according to the option that it received. +* +* Restriction: None +* +* Input: int argc: number of the argument received +*       char* opt: option string that will tell what to display +*       char** filename: strings that contained filename of FRU data binary file +*       int* file_type: a pointer that contain file type (on carrier file, +*                       a1 file, b1 file...). See structure +*                       ipmi_ekanalyzer_module_type for a list of valid type +* +* Output: None +* +* Global: None +* +* Return:   return 0 as success and -1 as error. +* +***************************************************************************/ +static int +ipmi_ekanalyzer_print( int argc, char * opt, char ** filename, int * file_type ) +{ +   int return_value = OK_STATUS; + +   /*Display carrier topology*/ +   if ( (strcmp(opt, "carrier") == 0) || (strcmp(opt, "default") == 0) ){ +      tboolean found_flag = FALSE; +      int index = 0; +      int index_name[argc]; +      int list = 0; +      /*list of multi record*/ +      struct ipmi_ek_multi_header * list_head[argc]; +      struct ipmi_ek_multi_header * list_record[argc]; +      struct ipmi_ek_multi_header * list_last[argc]; + +      for ( list=0; list < argc; list++ ){ +         list_head[list] = NULL; +         list_record[list] = NULL; +         list_last[list] = NULL; +      } + +      list=0;   /* reset list count */ +      for ( index = 0; index < argc; index++ ){ +         if ( file_type[index] == ON_CARRIER_FRU_FILE ){ +            index_name[list] = index; +            return_value = ipmi_ekanalyzer_fru_file2structure( filename[index], +                    &list_head[list], &list_record[list], &list_last[list] ); +            list++; +            found_flag = TRUE; +         } +      } +      if ( !found_flag ){ +         printf("No carrier file has been found\n"); +         return_value = ERROR_STATUS; +      } +      else{ +         int i = 0; +         for ( i = 0; i < argc; i++ ){ +            /*this is a flag to advoid displaying the same data multiple time*/ +            tboolean first_data = TRUE; +            for (    list_record[i] = list_head[i]; +                     list_record[i] != NULL; +                     list_record[i] = list_record[i]->next ){ +               if ( list_record[i]->data[PICMG_ID_OFFSET] +                     == +                    FRU_AMC_CARRIER_P2P ){ +                  if ( first_data ){ +                     printf("%s\n", STAR_LINE_LIMITER); +                     printf("From Carrier file: %s\n", filename[index_name[i]]); +                     first_data = FALSE; +                  } +                  return_value = ipmi_ek_display_carrier_connectivity( +                                                list_record[i] ); +               } +               else if ( list_record[i]->data[PICMG_ID_OFFSET] +                           == +                        FRU_AMC_CARRIER_INFO ){ +                  /*See AMC.0 specification Table3-3 for mor detail*/ +                  #define COUNT_OFFSET 6 +                  if ( first_data ){ +                     printf("From Carrier file: %s\n", filename[index_name[i]]); +                     first_data = FALSE; +                  } +                  printf("   Number of AMC bays supported by Carrier: %d\n", +                              list_record[i]->data[COUNT_OFFSET] ); +               } +            } +         } +         /*Destroy the list of record*/ +         for ( i = 0; i < argc; i++ ){ +            while ( list_head[i] != NULL ){ +               ipmi_ek_remove_record_from_list( list_head[i], +                        &list_head[i], &list_last[i] ); +            } +            /* display deleted result when we reach the last record */ +            if ( ( i == (list-1) ) && verbose ) +               printf("Record list has been removed successfully\n"); +         } +      } +   } +   else if ( (strcmp(opt, "power") == 0) ){ +      printf("Print power information\n"); +      return_value = ipmi_ek_display_power(argc, opt, filename, file_type); +   } +   else if ( strcmp(opt, "all") == 0 ){ +      printf("Print all information\n"); +      return_value = ipmi_ek_display_power(argc, opt, filename, file_type); +   } +   else{ +      lprintf(LOG_ERR, "Invalid option %s", opt); +      return_value = ERROR_STATUS; +   } +   return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_carrier_connectivity +* +* Description: Display the topology between a Carrier and all AMC modules by +*           using carrier p2p connectivity record +* +* Restriction: Ref: AMC.0 Specification: Table 3-13 and Table 3-14 +* +* Input: struct ipmi_ek_multi_header* record: a pointer to the carrier p2p +*                              connectivity record. +* +* Output: None +* +* Global: None +* +* Return:   return 0 on success and -1 if the record doesn't exist. +* +***************************************************************************/ +static int +ipmi_ek_display_carrier_connectivity( struct ipmi_ek_multi_header * record ) +{ +   int return_value = ERROR_STATUS; +   struct fru_picmgext_carrier_p2p_record rsc_desc; +   struct fru_picmgext_carrier_p2p_descriptor *port_desc; + +   if ( record == NULL ){ +      lprintf(LOG_ERR, "P2P connectivity record is invalid\n"); +      return_value = ERROR_STATUS; +   } +   else{ +      int offset = START_DATA_OFFSET; +      if ( verbose > 1 ){ +         int k = 0; +         printf("Binary data of Carrier p2p connectivity"\ +                  " record starting from mfg id\n"); +         for ( k = 0; k < ( record->header.len ); k++ ){ +            printf("%02x   ", record->data[k]); +         } +         printf("\n"); +      } +      while ( offset <= (record->header.len - START_DATA_OFFSET) ){ +         rsc_desc.resource_id = record->data[offset++]; +         rsc_desc.p2p_count = record->data[offset++]; +         if ( verbose > 0 ){ +            printf("resource id= %02x  port count= %d\n", +                        rsc_desc.resource_id,rsc_desc.p2p_count); +         } +         /*check if it is an AMC Module*/ +         if ( ( (rsc_desc.resource_id & AMC_MODULE) ) == AMC_MODULE ) { +            /*check if it is an RTM module*/ +            if ((rsc_desc.resource_id == AMC_MODULE)){ +               printf("   %s topology:\n", val2str( RTM_IPMB_L, +                                 ipmi_ekanalyzer_IPMBL_addr)); +            } +            else{ +               /*The last four bits of resource ID represent site number +               * (mask = 0x0f) +               */ +               printf("   %s topology:\n", +                        val2str( (rsc_desc.resource_id & 0x0f), +                        ipmi_ekanalyzer_module_type)); +            } +         } +         else{ +            printf("   On Carrier Device ID %d topology: \n", +                        (rsc_desc.resource_id & 0x0f)); +         } +         while ( rsc_desc.p2p_count > 0 ){ +		unsigned char data[3]; +#ifndef WORDS_BIGENDIAN +		data[0] = record->data[offset+0]; +		data[1] = record->data[offset+1]; +		data[2] = record->data[offset+2]; +#else +		data[0] = record->data[offset+2]; +		data[1] = record->data[offset+1]; +		data[2] = record->data[offset+0]; +#endif +		port_desc = (struct fru_picmgext_carrier_p2p_descriptor*)data; +		offset += sizeof (struct fru_picmgext_carrier_p2p_descriptor); +		if ((port_desc->remote_resource_id & AMC_MODULE) == AMC_MODULE) { +			printf("\tPort %d =====> %s, Port %d\n", +				port_desc->local_port, +				val2str( (port_desc->remote_resource_id & 0x0f), +					ipmi_ekanalyzer_module_type), +				port_desc->remote_port); +		} +		else { +			printf("\tPort %d =====> On Carrier Device ID %d, Port %d\n", +				port_desc->local_port, +				(port_desc->remote_resource_id & 0x0f), +				port_desc->remote_port); +		} +		rsc_desc.p2p_count--; +         } +      } +      return_value = OK_STATUS; +   } +   return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_power +* +* Description: Display the power management of the Carrier and AMC module by +*           using current management record. If the display option equal to all, +*           it will display power and carrier topology together. +* +* Restriction: Reference: AMC.0 Specification, Table 3-11 +* +* Input: int argc: number of the argument received +*       char* opt: option string that will tell what to display +*       char** filename: strings that contained filename of FRU data binary file +*       int* file_type: a pointer that contain file type (on carrier file, +*                       a1 file, b1 file...) +* +* Output: None +* +* Global: None +* +* Return:   return 0 on success and -1 if the record doesn't exist. +* +***************************************************************************/ +static int +ipmi_ek_display_power( int argc, char * opt, char ** filename, int * file_type ) +{ +   int num_file=0; +   int return_value = ERROR_STATUS; +   int index = 0; + +   /*list des multi record*/ +   struct ipmi_ek_multi_header * list_head[argc]; +   struct ipmi_ek_multi_header * list_record[argc]; +   struct ipmi_ek_multi_header * list_last[argc]; + +   for ( num_file = 0; num_file < argc; num_file++ ){ +      list_head[num_file] = NULL; +      list_record[num_file] = NULL; +      list_last[num_file] = NULL; +   } + +   for ( num_file = 0; num_file < argc; num_file++ ){ +      tboolean is_first_data = TRUE; +      if ( file_type[num_file] == CONFIG_FILE ){ +         num_file++; +      } + +      if ( is_first_data ){ +         printf("%s\n", STAR_LINE_LIMITER); +         printf("\nFrom %s file '%s'\n", +                  val2str( file_type[num_file], ipmi_ekanalyzer_module_type), +                  filename[num_file]); +         is_first_data = FALSE; +      } + +      return_value = ipmi_ekanalyzer_fru_file2structure( filename[num_file], +        &list_head[num_file], &list_record[num_file], &list_last[num_file]); + +      if ( list_head[num_file] != NULL ){ +         for (    list_record[num_file] = list_head[num_file]; +                  list_record[num_file] != NULL; +                  list_record[num_file] = list_record[num_file]->next +            ){ +            if ( ( strcmp(opt, "all") == 0 ) +                  && ( file_type[num_file] == ON_CARRIER_FRU_FILE ) +               ){ +                  if ( list_record[num_file]->data[PICMG_ID_OFFSET] +                           == +                        FRU_AMC_CARRIER_P2P +                     ){ +                        return_value = ipmi_ek_display_carrier_connectivity( +                                                list_record[num_file] ); +               } +               else if ( list_record[num_file]->data[PICMG_ID_OFFSET] +                           == +                         FRU_AMC_CARRIER_INFO +                       ){ +                  /*Ref: See AMC.0 Specification Table 3-3: Carrier Information +                  * Table about offset value +                  */ +                  printf( "   Number of AMC bays supported by Carrier: %d\n", +                          list_record[num_file]->data[START_DATA_OFFSET+1] ); +               } +            } +            /*Ref: AMC.0 Specification: Table 3-11 +            * Carrier Activation and Current Management Record +            */ +            if ( list_record[num_file]->data[PICMG_ID_OFFSET] +                  == +                 FRU_AMC_ACTIVATION +               ){ +               int index_data = START_DATA_OFFSET; +               struct fru_picmgext_carrier_activation_record car; +               struct fru_picmgext_activation_record * cur_desc; + +               memcpy ( &car, &list_record[num_file]->data[index_data], +                     sizeof (struct fru_picmgext_carrier_activation_record) ); +               index_data += +                     sizeof (struct fru_picmgext_carrier_activation_record); +               cur_desc = malloc (car.module_activation_record_count * \ +                     sizeof (struct fru_picmgext_activation_record) ); +               for(index=0; index<car.module_activation_record_count; index++){ +                  memcpy( &cur_desc[index], +                           &list_record[num_file]->data[index_data], +                           sizeof (struct fru_picmgext_activation_record) ); + +                  index_data += sizeof (struct fru_picmgext_activation_record); +               } +               /*Display the current*/ +               ipmi_ek_display_current_descriptor( car, +                                    cur_desc, filename[num_file] ); +               free(cur_desc); +               cur_desc = NULL; +            } +            /*Ref: AMC.0 specification, Table 3-10: Module Current Requirement*/ +            else if ( list_record[num_file]->data[PICMG_ID_OFFSET] +                       == FRU_AMC_CURRENT +                    ){ +               float power_in_watt = 0; +               float current_in_amp = 0; + +               printf("   %s power required (Current Draw): ", +                  val2str ( file_type[num_file], ipmi_ekanalyzer_module_type) ); +               current_in_amp = +                        list_record[num_file]->data[START_DATA_OFFSET]*0.1; +               power_in_watt = current_in_amp * AMC_VOLTAGE; +               printf("%.2f Watts (%.2f Amps)\n",power_in_watt, current_in_amp); +            } +         } +         return_value = OK_STATUS; +         /*Destroy the list of record*/ +         for ( index = 0; index < argc; index++ ){ +            while ( list_head[index] != NULL ){ +               ipmi_ek_remove_record_from_list ( list_head[index], +                        &list_head[index],&list_last[index] ); +            } +            if ( verbose > 1 ) +               printf("Record list has been removed successfully\n"); +         } +      } +   } +   printf("%s\n", STAR_LINE_LIMITER); +   return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_current_descriptor +* +* Description: Display the current descriptor under format xx Watts (xx Amps) +* +* Restriction: None +* +* Input: struct fru_picmgext_carrier_activation_record car: contain binary data +*                  of carrier activation record +*        struct fru_picmgext_activation_record * cur_desc: contain current +*                  descriptor +*        char* filename: strings that contained filename of FRU data binary file +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_current_descriptor( +      struct fru_picmgext_carrier_activation_record car, +      struct fru_picmgext_activation_record * cur_desc, char * filename ) +{ +   int index = 0; +   float power_in_watt = 0.0; +   float current_in_amp = 0.0; + +   for ( index = 0; index < car.module_activation_record_count; index++ ){ +      /*See AMC.0 specification, Table 3-12 for detail about calculation*/ +      current_in_amp = (float) cur_desc[index].max_module_curr * 0.1; +      power_in_watt = (float) current_in_amp * AMC_VOLTAGE; + +      printf("   Carrier AMC power available on %s:\n", +         val2str( cur_desc[index].ibmb_addr, ipmi_ekanalyzer_IPMBL_addr ) ); +      printf("\t- Local IPMB Address    \t: %02x\n", cur_desc[index].ibmb_addr); +      printf("\t- Maximum module Current\t: %.2f Watts (%.2f Amps)\n", +                      power_in_watt, current_in_amp ); +   } +   /*Display total power on Carrier*/ +   current_in_amp =  (float) car.max_internal_curr * 0.1; +   power_in_watt = (float) current_in_amp * AMC_VOLTAGE; +   printf("   Carrier AMC total power available for all bays from file '%s':", +            filename); +   printf(" %.2f Watts (%.2f Amps)\n", power_in_watt, current_in_amp ); +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_ekeying_match +* +* Description: Check for possible Ekeying match between two FRU files +* +* Restriction: None +* +* Input: argc: number of the argument received +*        opt: string that contains display option received from user. +*        filename: strings that contained filename of FRU data binary file +*        file_type: a pointer that contain file type (on carrier file, +*                       a1 file, b1 file...) +* +* Output: None +* +* Global: None +* +* Return:   return TRUE on success and FALSE if the record doesn't exist. +* +***************************************************************************/ +static tboolean +ipmi_ekanalyzer_ekeying_match( int argc, char * opt, +         char ** filename, int * file_type ) +{ +   tboolean return_value = FALSE; + +   if ( (strcmp(opt, "carrier") == 0 ) || (strcmp(opt, "power") == 0) ){ +      lprintf(LOG_ERR, "   ekanalyzer summary [match/ unmatch/ all]"\ +                   " <xx=frufile> <xx=frufile> [xx=frufile]"); +      return_value = ERROR_STATUS; +   } +   else{ +      int num_file=0; +      tboolean amc_file = FALSE; /*used to indicate the present of AMC file*/ +      tboolean oc_file = FALSE; /*used to indicate the present of Carrier file*/ + +      /*Check for possible ekeying match between files*/ +      for ( num_file=0; num_file < argc; num_file++ ){ +         if ( ( file_type[num_file] == ON_CARRIER_FRU_FILE ) +              || ( file_type[num_file] == CONFIG_FILE ) +              || ( file_type[num_file] == SHELF_MANAGER_FRU_FILE ) +            ){ +            amc_file = FALSE; +         } +         else {   /*there is an amc file*/ +            amc_file = TRUE; +            break; +         } +      } +      if ( amc_file == FALSE ){ +         printf("\nNo AMC FRU file is provided --->" \ +                       " No possible ekeying match!\n"); +         return_value = ERROR_STATUS; +      } +      else{ +         /*If no carrier file is provided, return error*/ +         for ( num_file=0; num_file < argc; num_file++ ){ +            if ( (file_type[num_file] == ON_CARRIER_FRU_FILE ) +                 || ( file_type[num_file] == CONFIG_FILE ) +                 || ( file_type[num_file] == SHELF_MANAGER_FRU_FILE ) +               ){ +               oc_file = TRUE; +               break; +            } +         } +         if ( !oc_file ){ +            printf("\nNo Carrier FRU file is provided" \ +                        " ---> No possible ekeying match!\n"); +            return_value = ERROR_STATUS; +         } +         else{ +            /*list des multi record*/ +            struct ipmi_ek_multi_header * list_head[argc]; +            struct ipmi_ek_multi_header * list_record[argc]; +            struct ipmi_ek_multi_header * list_last[argc]; +            struct ipmi_ek_multi_header * pcarrier_p2p; +            int list = 0; +            int match_pair = 0; + +            /*Create an empty list*/ +            for ( list=0; list<argc; list++ ){ +               list_head[list] = NULL; +               list_record[list] = NULL; +               list_last[list] = NULL; +            } +            list=0; + +            for ( num_file=0; num_file < argc; num_file++ ){ +               if (file_type[num_file] != CONFIG_FILE){ +                  return_value = ipmi_ekanalyzer_fru_file2structure( +                                filename[num_file], &list_head[num_file], +                                &list_record[num_file], &list_last[num_file]); +               } +            } +            /*Get Carrier p2p connectivity record for physical check*/ +            for (num_file=0; num_file < argc; num_file++){ +               if (file_type[num_file] == ON_CARRIER_FRU_FILE ){ +                  for ( pcarrier_p2p=list_head[num_file]; +                        pcarrier_p2p != NULL ; +                        pcarrier_p2p = pcarrier_p2p->next +                     ){ +                     if ( pcarrier_p2p->data[PICMG_ID_OFFSET] +                           == FRU_AMC_CARRIER_P2P +                        ){ +                        break; +                     } +                  } +                  break; +               } +            } +            /*Determine the match making pair*/ +            while ( match_pair < argc ){ +               for ( num_file = (match_pair+1); num_file<argc; num_file++ ){ +                  if ( ( file_type[match_pair] != CONFIG_FILE ) +                        && ( file_type[num_file] != CONFIG_FILE ) +                     ){ +                     if ( ( file_type[match_pair] != ON_CARRIER_FRU_FILE ) +                           || ( file_type[num_file] != ON_CARRIER_FRU_FILE ) +                        ){ +                        printf("%s vs %s\n", +                                 val2str(file_type[match_pair], +                                                ipmi_ekanalyzer_module_type), +                                 val2str(file_type[num_file], +                                                ipmi_ekanalyzer_module_type)); +                        /*Ekeying match between 2 files*/ +                        if (verbose>0){ +                           printf("Start matching process\n"); +                        } +                        return_value = ipmi_ek_matching_process( file_type, +                                             match_pair, num_file, list_head, +                                             list_last, opt, pcarrier_p2p); +                     } +                  } +               } +               match_pair ++; +            } +            for( num_file=0; num_file < argc; num_file++ ){ +               if (list_head[num_file] != NULL ){ +                  ipmi_ek_remove_record_from_list( list_head[num_file], +                           &list_record[num_file], &list_last[num_file]); +               } +               if ( ( num_file == argc-1 ) && verbose ) +                  printf("Record list has been removed successfully\n"); +            } +            return_value = OK_STATUS; +         } +      } +   } +   return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_matching_process +* +* Description: This function process the OEM check, Physical Connectivity check, +*              and Link Descriptor comparison to do Ekeying match +* +* Restriction: None +* +* Input: file_type: a pointer that contain file type (on carrier file, +*                       a1 file, b1 file...) +*        index1: position of the first record in the list of the record +*        index2: position of the second record in the list of the record +*        ipmi_ek_multi_header ** list_head: pointer to the header of a +*                 linked list that contain FRU multi record +*        ipmi_ek_multi_header ** list_last: pointer to the tale of a +*                 linked list that contain FRU multi record +*        opt: string that contain display option such as "match", "unmatch", or +*               "all". +*        pphysical: a pointer that contain a carrier p2p connectivity record +*                   to perform physical check +* +* Output: None +* +* Global: None +* +* Return:   return OK_STATUS on success and ERROR_STATUS if the record doesn't +*           exist. +* +***************************************************************************/ +static int ipmi_ek_matching_process( int * file_type, int index1, int index2, +      struct ipmi_ek_multi_header ** list_head, +      struct ipmi_ek_multi_header ** list_last, char * opt, +      struct ipmi_ek_multi_header * pphysical ) +{ +   int result = ERROR_STATUS; +   struct ipmi_ek_multi_header * record; +   int num_amc_record1 = 0;/*Number of AMC records in the first module*/ +   int num_amc_record2 = 0;/*Number of AMC records in the second module*/ + +   /* Comparison between an On-Carrier and an AMC*/ +   if ( file_type[index2] == ON_CARRIER_FRU_FILE ){ +      int index_temp = 0; +      index_temp = index1; +      index1 = index2; /*index1 indicate on carrier*/ +      index2 = index_temp; /*index2 indcate an AMC*/ +   } +   /*Calculate record size for Carrier file*/ +   for ( record=list_head[index1]; record != NULL;record = record->next ){ +      if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ +         num_amc_record2++; +      } +   } +   /*Calculate record size for amc file*/ +   for ( record=list_head[index2]; record != NULL;record = record->next){ +      if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ +         num_amc_record1++; +      } +   } +   if ( (num_amc_record1 > 0) && (num_amc_record2 > 0) ){ +      int index_record1 = 0; +      int index_record2 = 0; +      /* Multi records of AMC module */ +      struct ipmi_ek_amc_p2p_connectivity_record * amc_record1 = NULL; +      /* Multi records of Carrier or an AMC module */ +      struct ipmi_ek_amc_p2p_connectivity_record * amc_record2 = NULL; + +      amc_record1 = malloc ( num_amc_record1 * \ +                           sizeof(struct ipmi_ek_amc_p2p_connectivity_record)); +      amc_record2 = malloc ( num_amc_record2 * \ +                           sizeof(struct ipmi_ek_amc_p2p_connectivity_record)); + +      for (record=list_head[index2]; record != NULL;record = record->next){ +         if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ +            result = ipmi_ek_create_amc_p2p_record( record, +                                       &amc_record1[index_record1] ); +            if (result != ERROR_STATUS){ +               struct ipmi_ek_multi_header * current_record = NULL; + +               for ( current_record=list_head[index1]; +                     current_record != NULL ; +                     current_record = current_record->next +                  ){ +                  if ( current_record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ +                     result = ipmi_ek_create_amc_p2p_record( current_record, +                                       &amc_record2[index_record2] ); +                     if ( result != ERROR_STATUS ){ +                        if ( result == OK_STATUS ){ +                           /*Compare Link descriptor*/ +                           result = ipmi_ek_compare_link ( pphysical, +                                    amc_record1[index_record1], +                                    amc_record2[index_record2], +                                    opt, file_type[index1], file_type[index2]); +                        } +                        index_record2++; +                     } +                  } /*end of FRU_AMC_P2P */ +               } /* end of for loop */ +               index_record1++; +            } +         } +      } +      free(amc_record1) ; +      amc_record1 = NULL; +      free(amc_record2) ; +      amc_record2 = NULL; +   } +   else{ +      printf("No amc record is found!\n"); +   } + +   return result; +} + +/************************************************************************** +* +* Function name: ipmi_ek_check_physical_connectivity +* +* Description: This function check for point to point connectivity between +*               two modules by comparing each enable port in link descriptor +*               with local and remote ports of port descriptor in +*               carrier point-to-point connectivity record according to the +*               corresponding file type ( a1, b1, b2...). +* +* Restriction: In order to perform physical check connectivity, it needs to +*               compare between 2 AMC Modules, so the use of index ( 1 and 2 ) +*               can facilitate the comparison in this case. +* +* Input: record1: is an AMC p2p record for an AMC module +*        record2 is an AMC p2p record for an On-Carrier record or an AMC module +*        char* opt: option string that will tell if a matching result, unmatched +*                 result or all the results will be displayed. +*        file_type1: indicates type of the first module +*        file_type2: indicates type of the second module +* +* Output: None +* +* Global: None +* +* Return:   return OK_STATUS if both link are matched, otherwise +*            return ERROR_STATUS +* +***************************************************************************/ +static int +ipmi_ek_check_physical_connectivity( +      struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, +      struct ipmi_ek_amc_p2p_connectivity_record record2, int index2, +      struct ipmi_ek_multi_header * record, +      int filetype1, int filetype2, char * option ) +{ +   int return_status = OK_STATUS; + +   if ( record == NULL ){ +      printf("NO Carrier p2p connectivity !\n"); +      return_status = ERROR_STATUS; +   } +   else{ +      #define INVALID_AMC_SITE_NUMBER      -1 +      int index = START_DATA_OFFSET; +      int amc_site = INVALID_AMC_SITE_NUMBER; +      struct fru_picmgext_carrier_p2p_record rsc_desc; +      struct fru_picmgext_carrier_p2p_descriptor * port_desc = NULL; + +      /* Get the physical connectivity record */ +      while ( index < record->header.len ) { +         rsc_desc.resource_id = record->data[index++]; +         rsc_desc.p2p_count = record->data[index++]; +         /* carrier p2p record starts with on-carrier device */ +         if ( (rsc_desc.resource_id == record1.rsc_id) +               || +              (rsc_desc.resource_id == record2.rsc_id) +            ){ +            if (rsc_desc.p2p_count <= 0){ +               printf("No p2p count\n"); +               return_status = ERROR_STATUS; +            } +            else{ +               port_desc = malloc ( rsc_desc.p2p_count * +                           sizeof(struct fru_picmgext_carrier_p2p_descriptor) ); +               index = ipmi_ek_get_resource_descriptor( rsc_desc.p2p_count, +                           index, port_desc, record ); +               amc_site = INVALID_AMC_SITE_NUMBER; +               break; +            } +         } +         else{ /* carrier p2p record starts with AMC module */ +            if (rsc_desc.resource_id == AMC_MODULE){ +               if (filetype1 != ON_CARRIER_FRU_FILE){ +                  amc_site = filetype1; +               } +               else{ +                  amc_site = filetype2; +               } +            } +            else{ +               amc_site = rsc_desc.resource_id & 0x0f; +            } +            if ( amc_site > 0 ){ +               if ( (amc_site == filetype1) || (amc_site == filetype2) ){ +                  port_desc = malloc ( rsc_desc.p2p_count * +                           sizeof(struct fru_picmgext_carrier_p2p_descriptor) ); +                  index = ipmi_ek_get_resource_descriptor( rsc_desc.p2p_count, +                                    index, port_desc, record ); +                  break; +               } +            } +            else{ +               return_status = ERROR_STATUS; +            } +         } +         /*If the record doesn't contain the same AMC site number in command +         * line, go to the next record +         */ +         index += ( sizeof(struct fru_picmgext_carrier_p2p_descriptor) * +                     rsc_desc.p2p_count ); +      } + +      if ( (port_desc != NULL) && (return_status != ERROR_STATUS) ){ +         int j=0; + +         for ( j = 0; j < rsc_desc.p2p_count; j++ ){ +            /* Compare only enable channel descriptor */ +            if ( record1.ch_desc[index1].lane0port != DISABLE_PORT ){ +               /* matching result from channel descriptor comparison */ +               tboolean match_lane = FALSE; + +               match_lane = ipmi_ek_compare_channel_descriptor ( +                              record1.ch_desc[index1], record2.ch_desc[index2], +                              port_desc, j, rsc_desc.resource_id ); + +               if ( match_lane ){ +                  if ( filetype1 != ON_CARRIER_FRU_FILE ){ +                     if ( ( +                           (filetype1 == (rsc_desc.resource_id & 0x0f)) +                              && +                           (filetype2 ==(port_desc[j].remote_resource_id &0x0f)) +                          ) +                          || +                          ( +                           (filetype2 == (rsc_desc.resource_id & 0x0f)) +                              && +                           (filetype1 ==(port_desc[j].remote_resource_id &0x0f)) +                          ) +                        ){ +                        if ( ! (strcmp(option, "unmatch") == 0) ){ +                           printf("%s port %d ==> %s port %d\n", +                              val2str(filetype2, ipmi_ekanalyzer_module_type), +                              record1.ch_desc[index1].lane0port, +                              val2str(filetype1, ipmi_ekanalyzer_module_type), +                              record2.ch_desc[index2].lane0port); +                        } +                        return_status = OK_STATUS; + +                        break; +                     } +                     else{ +                        if (verbose == LOG_DEBUG){ +                           printf("No point 2 point connectivity\n"); +                        } +                        return_status = ERROR_STATUS; +                     } +                  } +                  else{ +                     if ( (record2.rsc_id == (rsc_desc.resource_id) ) +                           && +                         (filetype2 == (port_desc[j].remote_resource_id & 0x0f)) +                        ){ +                        if ( ! (strcmp(option, "unmatch") == 0) ){ +                           printf("%s port %d ==> %s port %d\n", +                              val2str(filetype2, ipmi_ekanalyzer_module_type), +                              record1.ch_desc[index1].lane0port, +                              val2str(filetype1, ipmi_ekanalyzer_module_type), +                              record2.ch_desc[index2].lane0port); +                        } +                        return_status = OK_STATUS; +                        break; +                     } +                     else if ( (filetype2 == (rsc_desc.resource_id & 0x0f) ) +                              && +                           (record2.rsc_id == (port_desc[j].remote_resource_id)) +                        ){ +                        if ( ! (strcmp(option, "unmatch") == 0) ){ +                           printf("%s port %d ==> %s %x port %d\n", +                              val2str(filetype2, ipmi_ekanalyzer_module_type), +                              record1.ch_desc[index1].lane0port, +                              val2str(filetype1, ipmi_ekanalyzer_module_type), +                              record2.rsc_id,record2.ch_desc[index2].lane0port); +                        } +                        return_status = OK_STATUS; +                        break; +                     } +                     else{ +                        if (verbose == LOG_DEBUG){ +                           printf("No point 2 point connectivity\n"); +                        } +                        return_status = ERROR_STATUS; +                     } +                  } +               } +               else{ +                  if (verbose == LOG_DEBUG){ +                           printf("No point 2 point connectivity\n"); +                  } +                  return_status = ERROR_STATUS; +               } +            } +            else{ /*If the link is disable, the result is always true*/ +               return_status = OK_STATUS; +            } +         } +      } +      else{ +         if (verbose == LOG_WARN){ +            printf("Invalid Carrier p2p connectivity record\n"); +         } +         return_status = ERROR_STATUS; +      } +      if (port_desc != NULL){ +         free(port_desc); +         port_desc = NULL; +      } +   } +   return return_status; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_link +* +* Description: This function compares link grouping id of each +*               amc p2p connectiviy record +* +* Restriction: None +* +* Input: record1: is an AMC p2p record for an AMC module +*        record2 is an AMC p2p record for an On-Carrier record or an AMC module +*        char* opt: option string that will tell if a matching result, unmatched +*                 result or all the results will be displayed. +*        file_type1: indicates type of the first module +*        file_type2: indicates type of the second module +* +* Output: None +* +* Global: None +* +* Return:   return 0 if both link are matched, otherwise return -1 +* +***************************************************************************/ +static int +ipmi_ek_compare_link( struct ipmi_ek_multi_header * physic_record, +   struct ipmi_ek_amc_p2p_connectivity_record record1, +   struct ipmi_ek_amc_p2p_connectivity_record record2, char * opt, +   int file_type1, int file_type2 ) +{ +   int result = ERROR_STATUS; +   int index1 = 0; /*index for AMC module*/ +   int index2 = 0; /*index for On-carrier type*/ + +   record1.matching_result = malloc ( record1.link_desc_count * sizeof(int) ); +   record2.matching_result = malloc ( record2.link_desc_count * sizeof(int) ); +   /*Initialize all the matching_result to false*/ +   for( index2 = 0; index2 < record2.link_desc_count; index2++ ){ +      record2.matching_result[index2] = FALSE; +   } +   for( index1 = 0; index1 < record1.link_desc_count; index1++ ){ +      for( index2 = 0; index2 < record2.link_desc_count; index2++ ){ +         if( record1.link_desc[index1].group_id == 0 ){ +            if( record2.link_desc[index2].group_id == 0 ){ +               result = ipmi_ek_compare_link_descriptor( +                              record1, index1, record2, index2 ); +               if ( result == OK_STATUS ){ +                  /*Calculate the index for Channel descriptor in function of +                  * link designator channel ID +                  */ +                  /*first channel_id in the AMC Link descriptor of record1*/ +                  static int flag_first_link1; +                  int index_ch_desc1; /*index of channel descriptor */ +                  /*first channel_id in the AMC Link descriptor of record2*/ +                  static int flag_first_link2; +                  int index_ch_desc2; /*index of channel descriptor*/ + +                  if (index1==0){ /*this indicate the first link is encounter*/ +                     flag_first_link1 = record1.link_desc[index1].channel_id; +                  } +                  index_ch_desc1 = record1.link_desc[index1].channel_id - +                              flag_first_link1; +                  if (index2==0){ +                     flag_first_link2 = record2.link_desc[index2].channel_id; +                  } +                  index_ch_desc2 = record2.link_desc[index2].channel_id - +                              flag_first_link2; +                  /*Check for physical connectivity for each link*/ +                  result = ipmi_ek_check_physical_connectivity ( record1, +                      index_ch_desc1, record2, index_ch_desc2, +                           physic_record, file_type1, file_type2, opt ); +                  if ( result == OK_STATUS ){ +                     /*Display the result if option = match or all*/ +                     if ( (strcmp( opt, "match" ) == 0) +                           || (strcmp( opt, "all" ) == 0) +                           || (strcmp( opt, "default" ) == 0) +                        ){ +                        tboolean isOEMtype = FALSE; +                        printf(" Matching Result\n"); +                        isOEMtype = ipmi_ek_display_link_descriptor( file_type1, +                                          record2.rsc_id, +                                          "From", record2.link_desc[index2]); +                        if (isOEMtype){ +                           ipmi_ek_display_oem_guid (record2); +                        } +                        isOEMtype = ipmi_ek_display_link_descriptor( file_type2, +                                          record1.rsc_id, +                                          "To", record1.link_desc[index1] ); +                        if (isOEMtype){ +                           ipmi_ek_display_oem_guid (record1); +                        } +                        printf("  %s\n", STAR_LINE_LIMITER); +                     } +                     record2.matching_result[index2] = TRUE; +                     record1.matching_result[index1] = TRUE; +                     /*quit the fist loop since the match is found*/ +                     index2 = record2.link_desc_count; +                  } +               } +            } +         } +         else { /*Link Grouping ID is non zero, Compare all link descriptor +                 * that has non-zero link grouping id together +                 */ +            if (record2.link_desc[index2].group_id != 0 ){ +               result = ipmi_ek_compare_link_descriptor( +                              record1, index1, record2, index2 ); +               if ( result == OK_STATUS ){ +                  /*Calculate the index for Channel descriptor in function of +                  * link designator channel ID +                  */ +                  /*first channel_id in the AMC Link descriptor of record1*/ +                  static int flag_first_link1; +                  int index_ch_desc1; /*index of channel descriptor */ +                  /*first channel_id in the AMC Link descriptor of record2*/ +                  static int flag_first_link2; +                  int index_ch_desc2; /*index of channel descriptor*/ + +                  if (index1==0){ /*this indicate the first link is encounter*/ +                     flag_first_link1 = record1.link_desc[index1].channel_id; +                  } +                  index_ch_desc1 = record1.link_desc[index1].channel_id - +                              flag_first_link1; +                  if (index2==0){ +                     flag_first_link2 = record2.link_desc[index2].channel_id; +                  } +                  index_ch_desc2 = record2.link_desc[index2].channel_id - +                              flag_first_link2; +                  /*Check for physical connectivity for each link*/ +                  result = ipmi_ek_check_physical_connectivity ( +                           record1, index_ch_desc1, record2, index_ch_desc2, +                           physic_record, file_type1, file_type2, opt ); +                  if ( result == OK_STATUS ){ +                     if ( (strcmp( opt, "match" ) == 0) +                           || (strcmp( opt, "all" ) == 0) +                           || (strcmp( opt, "default" ) == 0) +                        ){ +                        tboolean isOEMtype = FALSE; +                        printf("  Matching Result\n"); +                        isOEMtype = ipmi_ek_display_link_descriptor( file_type1, +                                       record2.rsc_id, +                                       "From", record2.link_desc[index2] ); +                        if ( isOEMtype ){ +                           ipmi_ek_display_oem_guid (record2); +                        } +                        isOEMtype = ipmi_ek_display_link_descriptor( file_type2, +                                       record1.rsc_id, +                                       "To", record1.link_desc[index1] ); +                        if (isOEMtype){ +                           ipmi_ek_display_oem_guid (record1); +                        } +                        printf("  %s\n", STAR_LINE_LIMITER); +                     } +                     record2.matching_result[index2] = TRUE; +                     record1.matching_result[index1] = TRUE; +                     /*leave the fist loop since the match is found*/ +                     index2 = record2.link_desc_count; +                  } +               } +            } +         } +      } +   } + +   if ( (strcmp(opt, "unmatch") == 0) || (strcmp(opt, "all") == 0) ){ +      int isOEMtype = FALSE; +      printf("  Unmatching result\n"); +      for (index1 = 0; index1 < record1.link_desc_count; index1++){ +         isOEMtype = ipmi_ek_display_link_descriptor( file_type2, +                           record1.rsc_id, "", record1.link_desc[index1] ); +         if ( isOEMtype ){ +            ipmi_ek_display_oem_guid (record1); +         } +         printf("   %s\n", STAR_LINE_LIMITER); +      } +      for ( index2 = 0; index2 < record2.link_desc_count; index2++){ +         if ( !record2.matching_result[index2] ){ +            isOEMtype = ipmi_ek_display_link_descriptor( file_type1, +                           record2.rsc_id, "", record2.link_desc[index2] ); +            if ( isOEMtype ){ +               ipmi_ek_display_oem_guid (record2); +            } +            printf("   %s\n", STAR_LINE_LIMITER); +         } +      } +   } + +   free(record1.matching_result); +   record1.matching_result = NULL; +   free(record2.matching_result); +   record2.matching_result = NULL; + +   return result; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_channel_descriptor +* +* Description: This function compares 2 channel descriptors of 2 AMC +*               point-to-point connectivity records with port descriptor of +*                carrier point-to-point connectivity record. The comparison is +*                made between each enable port only. +* +* Restriction: Reference: AMC.0 specification: +*                     - Table 3-14 for port descriptor +*                     - Table 3-17 for channel descriptor +* +* Input: ch_desc1: first channel descriptor +*        ch_desc2: second channel descriptor +*        port_desc: a pointer that contain a list of port descriptor +*        index_port: index of the port descriptor +*         rsc_id: resource id that represents as local resource id in the +*                  resource descriptor table. +* +* Output: None +* +* Global: None +* +* Return:   return TRUE if both channel descriptor are matched, +*         or FALSE otherwise +* +***************************************************************************/ +static tboolean +ipmi_ek_compare_channel_descriptor( +      struct fru_picmgext_amc_channel_desc_record ch_desc1, +      struct fru_picmgext_amc_channel_desc_record ch_desc2, +      struct fru_picmgext_carrier_p2p_descriptor * port_desc, +      int index_port, unsigned char rsc_id ) +{ +   tboolean match_lane = FALSE; + +   /* carrier p2p record start with AMC_MODULE as local port */ +   if ( (rsc_id & AMC_MODULE) == AMC_MODULE ){ +      if ( (ch_desc1.lane0port == port_desc[index_port].local_port) +               && +           (ch_desc2.lane0port == port_desc[index_port].remote_port) +         ){ +         /*check if the port is enable*/ +         if (ch_desc1.lane1port != DISABLE_PORT){ +            index_port ++; +            if ( (ch_desc1.lane1port == port_desc[index_port].local_port) +                     && +                 (ch_desc2.lane1port == port_desc[index_port].remote_port) +               ){ +               if (ch_desc1.lane2port != DISABLE_PORT){ +                  index_port++; +                  if ( (ch_desc1.lane2port == port_desc[index_port].local_port) +                           && +                       (ch_desc2.lane2port == port_desc[index_port].remote_port) +                     ){ +                     if (ch_desc1.lane3port != DISABLE_PORT){ +                        index_port++; +                        if ( (ch_desc1.lane3port == +                                             port_desc[index_port].local_port) +                                 && +                             (ch_desc2.lane3port == +                                             port_desc[index_port].remote_port) +                           ){ +                              match_lane = TRUE; +                        } +                     } +                     else{ +                        match_lane = TRUE; +                     } +                  } /* end of if lane2port */ +               } +               else{ +                  match_lane = TRUE; +               } +            } /* end of if lane1port */ +         } +         else{ /*if the port is disable, the compare result is always true*/ +              match_lane = TRUE; +         } +      }/* end of if lane0port */ +   } +   /* carrier p2p record start with Carrier as local port */ +   else{ +      if ( (ch_desc1.lane0port == port_desc[index_port].remote_port) +               && +           (ch_desc2.lane0port == port_desc[index_port].local_port) +         ){ +         if (ch_desc1.lane1port != DISABLE_PORT){ +            index_port ++; +            if ( (ch_desc1.lane1port == port_desc[index_port].remote_port) +                     && +                 (ch_desc2.lane1port == port_desc[index_port].local_port) +               ){ +               if (ch_desc1.lane2port != DISABLE_PORT){ +                  index_port++; +                  if ( (ch_desc1.lane2port == port_desc[index_port].remote_port) +                           && +                       (ch_desc2.lane2port == port_desc[index_port].local_port) +                     ){ +                     if (ch_desc1.lane3port != DISABLE_PORT){ +                        index_port++; +                        if ( (ch_desc1.lane3port == +                                             port_desc[index_port].remote_port) +                                 && +                             (ch_desc2.lane3port == +                                             port_desc[index_port].local_port) +                           ){ +                              match_lane = TRUE; +                        } +                     } +                     else{ +                        match_lane = TRUE; +                     } +                  } /* end of if lane2port */ +               } +               else{ +                  match_lane = TRUE; +               } +            } /* end of if lane1port */ +         } +         else{ +              match_lane = TRUE; +         } +      } /* end of if lane0port */ +   } + +   return match_lane; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_link_descriptor +* +* Description: This function compares 2 link descriptors of 2 +*               amc p2p connectiviy record +* +* Restriction: None +* +* Input: record1: AMC p2p connectivity record of the 1rst AMC or Carrier Module +*         index1: index of AMC link descriptor in 1rst record +*         record2: AMC p2p connectivity record of the 2nd AMC or Carrier Module +*         index1: index of AMC link descriptor in 2nd record +* +* Output: None +* +* Global: None +* +* Return:   return OK_STATUS if both link are matched, +*            otherwise return ERROR_STATUS +* +***************************************************************************/ +static int +ipmi_ek_compare_link_descriptor( +   struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, +   struct ipmi_ek_amc_p2p_connectivity_record record2, int index2 ) +{ +   int result = ERROR_STATUS; + +   if (record1.link_desc[index1].type == record2.link_desc[index2].type){ +      /*if it is an OEM type, we compare the OEM GUID*/ +      if ( (record1.link_desc[index1].type >= LOWER_OEM_TYPE) +            && (record1.link_desc[index1].type <= UPPER_OEM_TYPE) +         ){ +            if ( (record1.guid_count == 0) && (record2.guid_count == 0) ){ +               /*there is no GUID for comparison, so the result is always OK*/ +               result = OK_STATUS; +            } +            else{ +               int i=0; +               int j=0; + +               for( i=0; i<record1.guid_count; i++){ +                  for( j=0; j < record2.guid_count; j++){ +                     if( memcmp (&record1.oem_guid[i], &record2.oem_guid[j], +                                 SIZE_OF_GUID ) +                        == 0 +                       ){ +                        result = OK_STATUS; +                        break; +                     } +                  } +               } +            } +      } +      else{ +         result = OK_STATUS; +      } +      if (result == OK_STATUS){ +         if (record1.link_desc[index1].type_ext +               == record2.link_desc[index2].type_ext +            ){ +            unsigned char asym[COMPARE_CANDIDATE]; +            int offset = 0; + +            asym[offset++] = record1.link_desc[index1].asym_match; +            asym[offset] = record2.link_desc[index2].asym_match; +            result = ipmi_ek_compare_asym ( asym ); +            if (result == OK_STATUS){ +               struct fru_picmgext_amc_link_desc_record link[COMPARE_CANDIDATE]; +               int index = 0; + +               link[index++] = record1.link_desc[index1]; +               link[index] = record2.link_desc[index2]; +               result = ipmi_ek_compare_number_of_enable_port( link ); +            } +            else{ +               result = ERROR_STATUS; +            } +         } +         else{ +            result = ERROR_STATUS; +         } +      } +   } +   else{ +      result = ERROR_STATUS; +   } + +   return result; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_asym +* +* Description: This function compares 2 asymetric match of 2 +*               amc link descriptors +* +* Restriction: None +* +* Input:      asym[COMPARE_CANDIDATE]: Contain 2 asymetric match for comparison +* +* Output: None +* +* Global: None +* +* Return:   return 0 if both asym. match are matched, otherwise return -1 +* +***************************************************************************/ + +static int +ipmi_ek_compare_asym( unsigned char asym[COMPARE_CANDIDATE] ) +{ +   int return_value = ERROR_STATUS; +   int first_index = 0; +   int second_index = 1; + +   if ( (asym[first_index] == 0) && (asym[second_index] == 0) ){ +      return_value = OK_STATUS; +   } +   else if ( (asym[first_index] & asym[second_index]) == 0 ){ +      return_value = OK_STATUS; +   } +   else{ +      return_value = ERROR_STATUS; +   } +   return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_link_descriptor +* +* Description: This function compare number of enble port of Link designator +* +* Restriction: None +* +* Input: link_designator1: first link designator +*        link_designator2:  second link designator +* +* Output: None +* +* Global: None +* +* Return:   return 0 if both link are matched, otherwise return -1 +* +***************************************************************************/ +static int +ipmi_ek_compare_number_of_enable_port( +   struct fru_picmgext_amc_link_desc_record link_desc[COMPARE_CANDIDATE] ) +{ +   int amc_port_count = 0; +   int carrier_port_count = 0; +   int return_value = ERROR_STATUS; +   int index = 0; + +   if (link_desc[index].port_flag_0){ /*bit 0 indicates port 0*/ +      amc_port_count++; +   } +   if (link_desc[index].port_flag_1){ /*bit 1 indicates port 1*/ +      amc_port_count++; +   } +   if (link_desc[index].port_flag_2){ /*bit 2 indicates port 2*/ +      amc_port_count++; +   } +   if (link_desc[index++].port_flag_3){ /*bit 3 indicates port 3*/ +      amc_port_count++; +   } + +   /*2nd link designator*/ +   if (link_desc[index].port_flag_0){ /*bit 0 indicates port 0*/ +      carrier_port_count++; +   } +   if (link_desc[index].port_flag_1){ /*bit 1 indicates port 1*/ +      carrier_port_count++; +   } +   if (link_desc[index].port_flag_2){ /*bit 2 indicates port 2*/ +      carrier_port_count++; +   } +   if (link_desc[index].port_flag_3){ /*bit 3 indicates port 3*/ +      carrier_port_count++; +   } + +   if(carrier_port_count == amc_port_count){ + +      return_value = OK_STATUS; +   } +   else{ +      return_value = ERROR_STATUS; +   } + +   return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_link_descriptor +* +* Description: Display the link descriptor of an AMC p2p connectivity record +* +* Restriction: See AMC.0 or PICMG 3.0 specification for detail about bit masks +* +* Input: file_type: module type. +*        rsc_id: resource id +*        char* str: indicates if it is a source (its value= "From") or a +*                 destination (its value = "To"). ( it is set to "" if it is not +*                 a source nor destination +*        link_desc: AMC link descriptor +*        asym:  asymetric match +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static tboolean +ipmi_ek_display_link_descriptor( int file_type, unsigned char rsc_id, +   char * str, struct fru_picmgext_amc_link_desc_record link_desc ) +{ +   tboolean isOEMtype = FALSE; + +   if (file_type == ON_CARRIER_FRU_FILE){ +      printf("  - %s On-Carrier Device ID %d\n", str, (rsc_id & 0x0f) ); +   } +   else{ +      printf("  - %s %s\n", str, +                     val2str(file_type,ipmi_ekanalyzer_module_type)); +   } + +   printf("    - Channel ID %d || ",  link_desc.channel_id ); +   printf("%s", link_desc.port_flag_0 ? "Lane 0: enable" : ""); +   printf("%s", link_desc.port_flag_1 ? ", Lane 1: enable" : ""); +   printf("%s", link_desc.port_flag_2 ? ", Lane 2: enable" : ""); +   printf("%s", link_desc.port_flag_3 ? ", Lane 3: enable" : ""); + +   printf("\n"); +   printf("    - Link Type: %s \n", +               val2str (link_desc.type, ipmi_ekanalyzer_link_type) ); +   switch ( link_desc.type ){ +      case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: +      case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: +      case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: +         printf("    - Link Type extension: %s\n", +               val2str (link_desc.type_ext, ipmi_ekanalyzer_extension_PCIE) ); +         printf("    - Link Group ID: %d || ", link_desc.group_id ); +         printf("Link Asym. Match: %d - %s\n", +                  link_desc.asym_match,  +                  val2str (link_desc.asym_match, ipmi_ekanalyzer_asym_PCIE) ); +         break; +      case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: +         printf("    - Link Type extension: %s\n", +            val2str (link_desc.type_ext, ipmi_ekanalyzer_extension_ETHERNET) ); +         printf("    - Link Group ID: %d || ", link_desc.group_id ); +         printf("Link Asym. Match: %d - %s\n", +                  link_desc.asym_match,  +                  val2str (link_desc.asym_match, ipmi_ekanalyzer_asym_PCIE) ); +         break; +      case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: +         printf("    - Link Type extension: %s\n", +            val2str (link_desc.type_ext, ipmi_ekanalyzer_extension_STORAGE) ); +         printf("    - Link Group ID: %d || ", link_desc.group_id ); +         printf("Link Asym. Match: %d - %s\n", +                  link_desc.asym_match,  +                  val2str (link_desc.asym_match, ipmi_ekanalyzer_asym_STORAGE) ); +         break; +      default: +         printf("    - Link Type extension: %i\n", link_desc.type_ext ); +         printf("    - Link Group ID: %d || ", link_desc.group_id ); +         printf("Link Asym. Match: %i\n", link_desc.asym_match); +         break; +   } +   /*return as OEM type if link type indicates OEM*/ +   if ( (link_desc.type >= LOWER_OEM_TYPE) +            && +        (link_desc.type <= UPPER_OEM_TYPE) +      ){ +         isOEMtype = TRUE; +   } + +   return isOEMtype; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_oem_guid +* +* Description: Display the oem guid of an AMC p2p connectivity record +* +* Restriction: None +* +* Input: amc_record: AMC p2p connectivity record +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_oem_guid( +   struct ipmi_ek_amc_p2p_connectivity_record amc_record ) +{ +   int index_oem = 0; +   int index = 0; + +   if ( amc_record.guid_count == 0 ){ +      printf("\tThere is no OEM GUID for this module\n"); +   } +   for (index_oem = 0; index_oem < amc_record.guid_count; index_oem++){ +      printf("    - GUID: "); +      for(index = 0; index < SIZE_OF_GUID; index++){ +         printf("%02x", amc_record.oem_guid[index_oem].guid[index]); +         /*For a better look: putting a "-" after displaying four bytes of GUID*/ +         if (!(index % 4)){ +            printf("-"); +         } +      } +      printf("\n"); +   } +} + +/************************************************************************** +* +* Function name: ipmi_ek_create_amc_p2p_record +* +* Description: this function create an AMC point 2 point connectivity record +*            that contain link descriptor, channel descriptor, oem guid +* +* Restriction: Reference: AMC.0 Specification Table 3-16 +* +* Input: record: a pointer to FRU multi record +* +* Output: amc_record: a pointer to the created AMC p2p record +* +* Global: None +* +* Return: Return OK_STATUS on success, or ERROR_STATUS if no record has been +*          created. +* +***************************************************************************/ +static int +ipmi_ek_create_amc_p2p_record(struct ipmi_ek_multi_header * record, +		struct ipmi_ek_amc_p2p_connectivity_record * amc_record) +{ +	int index_data = START_DATA_OFFSET; +	int return_status = OK_STATUS; + +	amc_record->guid_count = record->data[index_data++]; +	if (amc_record->guid_count > 0) { +		int index_oem = 0; +		amc_record->oem_guid = malloc(amc_record->guid_count * \ +				sizeof(struct fru_picmgext_guid)); +		for (index_oem = 0; index_oem < amc_record->guid_count; +				index_oem++) { +			memcpy(&amc_record->oem_guid[index_oem].guid, +					&record->data[index_data], +					SIZE_OF_GUID); +			index_data += (int)SIZE_OF_GUID; +		} +		amc_record->rsc_id = record->data[index_data++]; +		amc_record->ch_count = record->data[index_data++]; +		/* Calculate link descriptor count */ +		amc_record->link_desc_count = ((record->header.len) - 8 - +				(SIZE_OF_GUID*amc_record->guid_count) - +				(FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE * +				amc_record->ch_count)) / 5 ; +	} else { +		amc_record->rsc_id = record->data[index_data++]; +		amc_record->ch_count = record->data[index_data++]; +		/* Calculate link descriptor count see spec AMC.0 for detail */ +		amc_record->link_desc_count = ((record->header.len) - 8 - +				(FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE * +				amc_record->ch_count)) / 5; +	} + +	if (amc_record->ch_count > 0) { +		int ch_index = 0; +		amc_record->ch_desc = malloc((amc_record->ch_count) * \ +				sizeof(struct fru_picmgext_amc_channel_desc_record)); +		for (ch_index = 0; ch_index < amc_record->ch_count; +				ch_index++) { +			unsigned int data; +			struct fru_picmgext_amc_channel_desc_record *src, *dst; +			data = record->data[index_data] |  +				(record->data[index_data + 1] << 8) | +				(record->data[index_data + 2] << 16); +			 +			src = (struct fru_picmgext_amc_channel_desc_record *)&data; +			dst = (struct fru_picmgext_amc_channel_desc_record *) +				&amc_record->ch_desc[ch_index]; + +			dst->lane0port = src->lane0port; +			dst->lane1port = src->lane1port; +			dst->lane2port = src->lane2port; +			dst->lane3port = src->lane3port; +			index_data += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE; +		} +	} +	if (amc_record->link_desc_count > 0) { +		int i=0; +		amc_record->link_desc = malloc(amc_record->link_desc_count * \ +				sizeof(struct fru_picmgext_amc_link_desc_record)); +		for (i = 0; i< amc_record->link_desc_count; i++) { +			unsigned int data[2]; +			struct fru_picmgext_amc_link_desc_record *src, *dst; +			data[0] = record->data[index_data] |  +				(record->data[index_data + 1] << 8) | +				(record->data[index_data + 2] << 16) | +				(record->data[index_data + 3] << 24); + +			data[1] = record->data[index_data + 4]; +			src = (struct fru_picmgext_amc_link_desc_record*)&data; +			dst = (struct fru_picmgext_amc_link_desc_record*)  +				&amc_record->link_desc[i]; + +			dst->channel_id = src->channel_id; +			dst->port_flag_0 = src->port_flag_0; +			dst->port_flag_1 = src->port_flag_1; +			dst->port_flag_2 = src->port_flag_2; +			dst->port_flag_3 = src->port_flag_3; +			dst->type = src->type; +			dst->type_ext = src->type_ext; +			dst->group_id = src->group_id; +			dst->asym_match = src->asym_match; +			index_data += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE; +		} +	} else { +		return_status = ERROR_STATUS; +	} +	return return_status; +} + +/************************************************************************** +* +* Function name: ipmi_ek_get_resource_descriptor +* +* Description: this function create the resource descriptor of Carrier p2p +*              connectivity record. +* +* Restriction: None +* +* Input: port_count: number of port count +*        index: index to the position of data start offset +*        record: a pointer to FRU multi record +* +* Output: port_desc: a pointer to the created resource descriptor +* +* Global: None +* +* Return: Return index that indicates the current position of data in record. +* +***************************************************************************/ +static int +ipmi_ek_get_resource_descriptor( int port_count, int index, +   struct fru_picmgext_carrier_p2p_descriptor * port_desc, +   struct ipmi_ek_multi_header * record ) +{ +   int num_port = 0; + +   while ( num_port < port_count ){ +      memcpy ( &port_desc[num_port], &record->data[index], +               sizeof (struct fru_picmgext_carrier_p2p_descriptor) ); +      index += sizeof (struct fru_picmgext_carrier_p2p_descriptor); +      num_port++; +   } + +   return index; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_fru_header +* +* Description: this function display FRU header offset from a FRU binary file +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +*                  Definition V1.0, Section 8 +* +* Input: filename: name of FRU binary file +* +* Output: None +* +* Global: None +* +* Return: Return OK_STATUS on sucess, ERROR_STATUS on error +* +***************************************************************************/ +static int +ipmi_ek_display_fru_header(char * filename) +{ +	FILE * input_file; +	struct fru_header header; +	int ret = 0; + +	input_file = fopen(filename, "r"); +	if (input_file == NULL) { +		lprintf(LOG_ERR, "File '%s' not found.", filename); +		return (ERROR_STATUS); +	} +	ret = fread(&header, sizeof (struct fru_header), 1, input_file); +	if ((ret != 1) || ferror(input_file)) { +		lprintf(LOG_ERR, "Failed to read FRU header!"); +		fclose(input_file); +		return (ERROR_STATUS); +	} +	printf("%s\n", EQUAL_LINE_LIMITER); +	printf("FRU Header Info\n"); +	printf("%s\n", EQUAL_LINE_LIMITER); +	printf("Format Version          :0x%02x %s\n", +		(header.version & 0x0f), +		((header.version & 0x0f) == 1) ? "" : "{unsupported}"); +	printf("Internal Use Offset     :0x%02x\n", header.offset.internal); +	printf("Chassis Info Offset     :0x%02x\n", header.offset.chassis); +	printf("Board Info Offset       :0x%02x\n", header.offset.board); +	printf("Product Info Offset     :0x%02x\n", header.offset.product); +	printf("MultiRecord Offset      :0x%02x\n", header.offset.multi); +	printf("Common header Checksum  :0x%02x\n", header.checksum); + +	fclose(input_file); +	return OK_STATUS; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_fru_header_detail +* +* Description: this function display detail FRU header information +*               from a FRU binary file. + +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +*                  Definition V1.0, Section 8 +* +* Input: filename: name of FRU binary file +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static int +ipmi_ek_display_fru_header_detail(char * filename) +{ +# define FACTOR_OFFSET 8 +# define SIZE_MFG_DATE 3 +	FILE * input_file; +	size_t file_offset = 0; +	struct fru_header header; +	time_t tval; +	int ret = 0; +	unsigned char data = 0; +	unsigned char lan_code = 0; +	unsigned char mfg_date[SIZE_MFG_DATE]; +	unsigned int board_length = 0; + +	input_file = fopen(filename, "r"); +	if (input_file == NULL) { +		lprintf(LOG_ERR, "File '%s' not found.", filename); +		return (-1); +	} +	/* The offset in each fru is in multiple of 8 bytes +	 * See IPMI Platform Management FRU Information Storage Definition +	 * for detail +	 */ +	ret = fread(&header, sizeof(struct fru_header), 1, input_file); +	if ((ret != 1) || ferror(input_file)) { +		lprintf(LOG_ERR, "Failed to read FRU header!"); +		fclose(input_file); +		return (-1); +	} +	/*** Display FRU Internal Use Info ***/ +	if (!feof(input_file)) { +		unsigned char format_version; +		unsigned long len = 0; + +		printf("%s\n", EQUAL_LINE_LIMITER); +		printf("FRU Internal Use Info\n"); +		printf("%s\n", EQUAL_LINE_LIMITER); + +		ret = fread(&format_version, 1, 1, input_file); +		if ((ret != 1) || ferror(input_file)) { +			lprintf(LOG_ERR, "Invalid format version!"); +			fclose(input_file); +			return (-1); +		} +		printf("Format Version: %d\n", (format_version & 0x0f)); + +		if (header.offset.chassis > 0) { +			len = (header.offset.chassis * FACTOR_OFFSET) +				- (header.offset.internal * FACTOR_OFFSET); +		} else { +			len = (header.offset.board * FACTOR_OFFSET) +				- (header.offset.internal * FACTOR_OFFSET); +		} +		printf("Length: %ld\n", len); +		printf("Data dump:\n"); +		while ((len > 0) && (!feof(input_file))) { +			unsigned char data; +			ret = fread(&data, 1, 1, input_file); +			if ((ret != 1) || ferror(input_file)) { +				lprintf(LOG_ERR, "Invalid data!"); +				fclose(input_file); +				return (-1); +			} +			printf("0x%02x ", data); +			len--; +		} +		printf("\n"); +	} +	/*** Chassis Info Area ***/ +	if (header.offset.chassis != 0) { +		long offset = 0; +		offset = header.offset.chassis * FACTOR_OFFSET; +		ret = ipmi_ek_display_chassis_info_area(input_file, offset); +	} +	/*** Display FRU Board Info Area ***/ +	while (1) { +		if (header.offset.board == 0) { +			break; +		} +		ret = fseek(input_file, +				(header.offset.board * FACTOR_OFFSET), +				SEEK_SET); +		if (feof(input_file)) { +			break; +		} +		file_offset = ftell(input_file); +		printf("%s\n", EQUAL_LINE_LIMITER); +		printf("FRU Board Info Area\n"); +		printf("%s\n", EQUAL_LINE_LIMITER); + +		ret = fread(&data, 1, 1, input_file); /* Format version */ +		if ((ret != 1) || ferror(input_file)) { +			lprintf(LOG_ERR, "Invalid FRU Format Version!"); +			fclose(input_file); +			return (-1); +		} +		printf("Format Version: %d\n", (data & 0x0f)); +		if (feof(input_file)) { +			break; +		} +		ret = fread(&data, 1, 1, input_file); /* Board Area Length */ +		if ((ret != 1) || ferror(input_file)) { +			lprintf(LOG_ERR, "Invalid Board Area Length!"); +			fclose(input_file); +			return (-1); +		} +		board_length = (data * FACTOR_OFFSET); +		printf("Area Length: %d\n", board_length); +		/* Decrease the length of board area by 1 byte of format version +		 * and 1 byte for area length itself. the rest of this length will +		 * be used to check for additional custom mfg. byte +		 */ +		board_length -= 2; +		if (feof(input_file)) { +			break; +		} +		ret = fread(&lan_code, 1, 1, input_file); /* Language Code */ +		if ((ret != 1) || ferror(input_file)) { +			lprintf(LOG_ERR, "Invalid Language Code in input"); +			fclose(input_file); +			return (-1); +		} +		printf("Language Code: %d\n", lan_code); +		board_length--; +		/* Board Mfg Date */ +		if (feof(input_file)) { +			break; +		} + +		ret = fread(mfg_date, SIZE_MFG_DATE, 1, input_file); +		if (ret != 1) { +			lprintf(LOG_ERR, "Invalid Board Data."); +			fclose(input_file); +			return (-1); +		} +		tval = ((mfg_date[2] << 16) + (mfg_date[1] << 8) +				+ (mfg_date[0])); +		tval = tval * 60; +		tval = tval + secs_from_1970_1996; +		printf("Board Mfg Date: %ld, %s", tval, +				asctime(localtime(&tval))); +		board_length -= SIZE_MFG_DATE; +		/* Board Mfg */ +		file_offset = ipmi_ek_display_board_info_area( +				input_file, "Board Manufacture Data", &board_length); +		ret = fseek(input_file, file_offset, SEEK_SET); +		/* Board Product */ +		file_offset = ipmi_ek_display_board_info_area( +				input_file, "Board Product Name", &board_length); +		ret = fseek(input_file, file_offset, SEEK_SET); +		/* Board Serial */ +		file_offset = ipmi_ek_display_board_info_area( +				input_file, "Board Serial Number", &board_length); +		ret = fseek(input_file, file_offset, SEEK_SET); +		/* Board Part */ +		file_offset = ipmi_ek_display_board_info_area( +				input_file, "Board Part Number", &board_length); +		ret = fseek(input_file, file_offset, SEEK_SET); +		/* FRU file ID */ +		file_offset = ipmi_ek_display_board_info_area( +				input_file, "FRU File ID", &board_length); +		ret = fseek(input_file, file_offset, SEEK_SET); +		/* Additional Custom Mfg. */ +		file_offset = ipmi_ek_display_board_info_area( +				input_file, "Custom", &board_length); +		break; +	} +	/* Product Info Area */ +	if (header.offset.product && (!feof(input_file))) { +		long offset = 0; +		offset = header.offset.product * FACTOR_OFFSET; +		ret = ipmi_ek_display_product_info_area(input_file, +				offset); +	} +	fclose(input_file); +	return 0; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_chassis_info_area +* +* Description: this function displays detail format of product info area record +*               into humain readable text format +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +*                  Definition V1.0, Section 10 +* +* Input: input_file: pointer to file stream +*         offset: start offset of chassis info area +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static int +ipmi_ek_display_chassis_info_area(FILE * input_file, long offset) +{ +	size_t file_offset; +	int ret = 0; +	unsigned char data = 0; +	unsigned char ch_len = 0; +	unsigned char ch_type = 0; +	unsigned int len; + +	if (input_file == NULL) { +		lprintf(LOG_ERR, "No file stream to read."); +		return (-1); +	} +	printf("%s\n", EQUAL_LINE_LIMITER); +	printf("Chassis Info Area\n"); +	printf("%s\n", EQUAL_LINE_LIMITER); +	ret = fseek(input_file, offset, SEEK_SET); +	if (feof(input_file)) { +		lprintf(LOG_ERR, "Invalid Chassis Info Area!"); +		return (-1); +	} +	ret = fread(&data, 1, 1, input_file); +	if ((ret != 1) || ferror(input_file)) { +		lprintf(LOG_ERR, "Invalid Version Number!"); +		return (-1); +	} +	printf("Format Version Number: %d\n", (data & 0x0f)); +	ret = fread(&ch_len, 1, 1, input_file); +	if ((ret != 1) || ferror(input_file)) { +		lprintf(LOG_ERR, "Invalid length!"); +		return (-1); +	} +	/* len is in factor of 8 bytes */ +	len = ch_len * 8; +	printf("Area Length: %d\n", len); +	len -= 2; +	if (feof(input_file)) { +		return (-1); +	} +	/* Chassis Type*/ +	ret = fread(&ch_type, 1, 1, input_file); +	if ((ret != 1) || ferror(input_file)) { +		lprintf(LOG_ERR, "Invalid Chassis Type!"); +		return (-1); +	} +	printf("Chassis Type: %d\n", ch_type); +	len--; +	/* Chassis Part Number*/ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"Chassis Part Number", &len); +	ret = fseek(input_file, file_offset, SEEK_SET); +	/* Chassis Serial */ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"Chassis Serial Number", &len); +	ret = fseek(input_file, file_offset, SEEK_SET); +	/* Custom product info area */ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"Custom", &len); +	return 0; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_board_info_area +* +* Description: this function displays board info area depending on board type +*               that pass in argument. Board type can be: +*               Manufacturer, Serial, Product or Part... +* +* Restriction: IPMI Platform Management FRU Information Storage +*                  Definition V1.0, Section 11 +* +* Input: input_file: pointer to file stream +*         board_type: a string that contain board type +*         board_length: length of info area +* +* Output: None +* +* Global: None +* +* Return: the current position of input_file +* +***************************************************************************/ +static size_t +ipmi_ek_display_board_info_area(FILE * input_file, char * board_type, +		unsigned int * board_length) +{ +	size_t file_offset; +	int ret = 0; +	unsigned char len = 0; +	unsigned int size_board = 0; +	if (input_file == NULL || board_type == NULL +			|| board_length == NULL) { +		return (size_t)(-1); +	} +	file_offset = ftell(input_file); + +	/* Board length*/ +	ret = fread(&len, 1, 1, input_file); +	if ((ret != 1) || ferror(input_file)) { +		lprintf(LOG_ERR, "Invalid Length!"); +		goto out; +	} +	(*board_length)--; + +	/* Bit 5:0 of Board Mfg type represent legnth */ +	size_board = (len & 0x3f); +	if (size_board == 0) { +		printf("%s: None\n", board_type); +		goto out; +	} +	if (strncmp(board_type, "Custom", 6 ) != 0) { +		unsigned char *data; +		unsigned int i = 0; +		data = malloc(size_board); +		if (data == NULL) { +			lprintf(LOG_ERR, "ipmitool: malloc failure"); +			return (size_t)(-1); +		} +		ret = fread(data, size_board, 1, input_file); +		if ((ret != 1) || ferror(input_file)) { +			lprintf(LOG_ERR, "Invalid board type size!"); +			free(data); +			data = NULL; +			goto out; +		} +		printf("%s type: 0x%02x\n", board_type, len); +		printf("%s: ", board_type); +		for (i = 0; i < size_board; i++) { +			if ((len & TYPE_CODE) == TYPE_CODE) { +				printf("%c", data[i]); +			} else { +				/* other than language code (binary, BCD, +				 * ASCII 6 bit...) is not supported +				 */ +				printf("%02x", data[i]); +			} +		} +		printf("\n"); +		free(data); +		data = NULL; +		(*board_length) -= size_board; +		goto out; +	} +	while (!feof(input_file)) { +		if (len == NO_MORE_INFO_FIELD) { +			unsigned char padding; +			unsigned char checksum = 0; +			/* take the rest of data in the area minus 1 byte of  +			 * checksum +			 */ +			printf("Additional Custom Mfg. length: 0x%02x\n", len); +			padding = (*board_length) - 1; +			if ((padding > 0) && (!feof(input_file))) { +				printf("Unused space: %d (bytes)\n", padding); +				fseek(input_file, padding, SEEK_CUR); +			} +			ret = fread(&checksum, 1, 1, input_file); +			if ((ret != 1) || ferror(input_file)) { +				lprintf(LOG_ERR, "Invalid Checksum!"); +				goto out; +			} +			printf("Checksum: 0x%02x\n", checksum); +			goto out; +		} +		printf("Additional Custom Mfg. length: 0x%02x\n", len); +		if ((size_board > 0) && (size_board < (*board_length))) { +			unsigned char * additional_data = NULL; +			unsigned int i = 0; +			additional_data = malloc(size_board); +			if (additional_data == NULL) { +				lprintf(LOG_ERR, "ipmitool: malloc failure"); +				return (size_t)(-1); +			} +				 +			ret = fread(additional_data, size_board, 1, input_file); +			if ((ret != 1) || ferror(input_file)) { +				lprintf(LOG_ERR, "Invalid Additional Data!"); +				goto out; +			} +			printf("Additional Custom Mfg. Data: %02x", +					additional_data[0]); +			for (i = 1; i < size_board; i++) { +				printf("-%02x", additional_data[i]); +			} +			printf("\n"); +			free(additional_data); +			additional_data = NULL; +			(*board_length) -= size_board; +		} +		else { +			printf("No Additional Custom Mfg. %d\n", *board_length); +			goto out; +		} +	} +  +out: +	file_offset = ftell(input_file); +	return file_offset; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_product_info_area +* +* Description: this function displays detail format of product info area record +*               into humain readable text format +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +*                  Definition V1.0, Section 12 +* +* Input: input_file: pointer to file stream +*         offset: start offset of product info area +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static int +ipmi_ek_display_product_info_area(FILE * input_file, long offset) +{ +	size_t file_offset; +	int ret = 0; +	unsigned char ch_len = 0; +	unsigned char data = 0; +	unsigned int len = 0; + +	if (input_file == NULL) { +		lprintf(LOG_ERR, "No file stream to read."); +		return (-1); +	} +	file_offset = ftell(input_file); +	printf("%s\n", EQUAL_LINE_LIMITER); +	printf("Product Info Area\n"); +	printf("%s\n", EQUAL_LINE_LIMITER); +	ret = fseek(input_file, offset, SEEK_SET); +	if (feof(input_file)) { +		lprintf(LOG_ERR, "Invalid Product Info Area!"); +		return (-1); +	} +	ret = fread(&data, 1, 1, input_file); +	if ((ret != 1) || ferror(input_file)) { +		lprintf(LOG_ERR, "Invalid Data!"); +		return (-1); +	} +	printf("Format Version Number: %d\n", (data & 0x0f)); +	if (feof(input_file)) { +		return (-1); +	} +	/* Have to read this into a char or else +	 * it ends up byte swapped on big endian machines */ +	ret = fread(&ch_len, 1, 1, input_file); +	if ((ret != 1) || ferror(input_file)) { +		lprintf(LOG_ERR, "Invalid Length!"); +		return (-1); +	} +	/* length is in factor of 8 bytes */ +	len = ch_len * 8; +	printf("Area Length: %d\n", len); +	len -= 2; /* -1 byte of format version and -1 byte itself */ + +	ret = fread(&data, 1, 1, input_file); +	if ((ret != 1) || ferror(input_file)) { +		lprintf(LOG_ERR, "Invalid Length!"); +		return (-1); +	} + +	fread(&data, 1, 1, input_file); +	printf("Language Code: %d\n", data); +	len--; +	/* Product Mfg */ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"Product Manufacture Data", &len); +	ret = fseek(input_file, file_offset, SEEK_SET); +	/* Product Name */ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"Product Name", &len); +	ret = fseek(input_file, file_offset, SEEK_SET); +	/* Product Part */ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"Product Part/Model Number", &len); +	ret = fseek(input_file, file_offset, SEEK_SET); +	/* Product Version */ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"Product Version", &len); +	ret = fseek(input_file, file_offset, SEEK_SET); +	/* Product Serial */ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"Product Serial Number", &len); +	ret = fseek(input_file, file_offset, SEEK_SET); +	/* Product Asset Tag */ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"Asset Tag", &len); +	ret = fseek(input_file, file_offset, SEEK_SET); +	/* FRU file ID */ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"FRU File ID", &len); +	ret = fseek(input_file, file_offset, SEEK_SET); +	/* Custom product info area */ +	file_offset = ipmi_ek_display_board_info_area(input_file, +			"Custom", &len); +	return 0; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_record +* +* Description: this function displays FRU multi record information. +* +* Restriction: None +* +* Input: record: a pointer to current record +*        list_head: a pointer to header of the list +*        list_last: a pointer to tale of the list +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_record( struct ipmi_ek_multi_header * record, +      struct ipmi_ek_multi_header * list_head, +      struct ipmi_ek_multi_header * list_last ) +{ +   if ( list_head == NULL ){ +      printf("***empty list***\n"); +   } +   else{ +      printf("%s\n", EQUAL_LINE_LIMITER); +      printf("FRU Multi Info area\n"); +      printf("%s\n", EQUAL_LINE_LIMITER); +      for ( record = list_head; record != NULL; record = record->next ){ +         printf("Record Type ID: 0x%02x\n", record->header.type); +         printf("Record Format version: 0x%02x\n", record->header.format); +         if (record->header.len > PICMG_ID_OFFSET){ +            /* In picmg3.0 specification, picmg record id lower than 4 or +            * greater than 0x2d is not supported +            */ +            #define PICMG_ID_LOWER_LIMIT  0x04 +            #define PICMG_ID_UPPER_LIMIT  0x2d +            unsigned char picmg_id; + +            picmg_id = record->data[PICMG_ID_OFFSET]; +            printf("Manufacturer ID: %02x%02x%02x h\n", record->data[2], +                     record->data[1], record->data[0] ); +            if( ( picmg_id < PICMG_ID_LOWER_LIMIT ) +                  || +                 ( picmg_id > PICMG_ID_UPPER_LIMIT ) ){ +               printf("Picmg record ID: Unsupported {0x%02x}\n", picmg_id ); +            } +            else{ +               printf("Picmg record ID: %s {0x%02x}\n", +                        val2str(picmg_id, ipmi_ekanalyzer_picmg_record_id), +                        picmg_id ); +            } +            switch (picmg_id){ +               case FRU_PICMG_BACKPLANE_P2P: /*0x04*/ +                  ipmi_ek_display_backplane_p2p_record (record); +                  break; +               case FRU_PICMG_ADDRESS_TABLE: /*0x10*/ +                  ipmi_ek_display_address_table_record (record); +                  break; +               case FRU_PICMG_SHELF_POWER_DIST: /*0x11*/ +                  ipmi_ek_display_shelf_power_distribution_record (record); +                  break; +               case FRU_PICMG_SHELF_ACTIVATION: /*/0x12*/ +                  ipmi_ek_display_shelf_activation_record (record); +                  break; +               case FRU_PICMG_SHMC_IP_CONN: /*0x13*/ +                  ipmi_ek_display_shelf_ip_connection_record (record); +                  break; +               case FRU_PICMG_BOARD_P2P: /*0x14*/ +                  ipmi_ek_display_board_p2p_record (record); +                  break; +               case FRU_RADIAL_IPMB0_LINK_MAPPING: /*0x15*/ +                  ipmi_ek_display_radial_ipmb0_record (record); +                  break; +               case FRU_AMC_CURRENT: /*0x16*/ +                  ipmi_ek_display_amc_current_record (record); +                  break; +               case FRU_AMC_ACTIVATION: /*0x17*/ +                  ipmi_ek_display_amc_activation_record (record); +                  break; +               case FRU_AMC_CARRIER_P2P: /*0x18*/ +                  ipmi_ek_display_carrier_connectivity (record); +                  break; +               case FRU_AMC_P2P: /*0x19*/ +                  ipmi_ek_display_amc_p2p_record (record); +                  break; +               case FRU_AMC_CARRIER_INFO: /*0x1a*/ +                  ipmi_ek_display_amc_carrier_info_record (record); +                  break; +               case FRU_PICMG_CLK_CARRIER_P2P: /*0x2c*/ +                  ipmi_ek_display_clock_carrier_p2p_record (record); +                  break; +               case FRU_PICMG_CLK_CONFIG: /*0x2d*/ +                  ipmi_ek_display_clock_config_record (record); +                  break; +               default: +                  if (verbose > 0){ +                     int i; +                     printf("%02x %02x %02x %02x %02x ", record->header.type, +                              record->header.format, record->header.len, +                              record->header.record_checksum, +                              record->header.header_checksum ); +                     for ( i = 0; i < record->header.len; i++ ){ +                        printf("%02x ", record->data[i]); +                     } +                     printf("\n"); +                  } +                  break; +            } +            printf("%s\n", STAR_LINE_LIMITER); +         } +      } +   } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_backplane_p2p_record +* +* Description: this function displays backplane p2p record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-40 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_backplane_p2p_record( struct ipmi_ek_multi_header * record ) +{ +   uint8_t index; +   int offset = START_DATA_OFFSET; +   struct fru_picmgext_slot_desc * slot_d +               = (struct fru_picmgext_slot_desc*) &record->data[offset]; + +   offset += sizeof(struct fru_picmgext_slot_desc); + +   while ( offset <= record->header.len ) { +      printf("   Channel Type: "); +      switch ( slot_d -> chan_type ) +      { +         case 0x00: +         case 0x07: +            printf("PICMG 2.9\n"); +            break; +         case 0x08: +            printf("Single Port Fabric IF\n"); +            break; +         case 0x09: +            printf("Double Port Fabric IF\n"); +            break; +         case 0x0a: +            printf("Full Channel Fabric IF\n"); +            break; +         case 0x0b: +            printf("Base IF\n"); +            break; +         case 0x0c: +            printf("Update Channel IF\n"); +            break; +         default: +            printf("Unknown IF\n"); +            break; +      } +      printf("   Slot Address:  %02x\n", slot_d -> slot_addr); +      printf("   Channel Count: %i\n", slot_d -> chn_count); + +      for ( index = 0; index < (slot_d -> chn_count); index++ ) { +         struct fru_picmgext_chn_desc * d +                  = (struct fru_picmgext_chn_desc *) &record->data[offset]; + +         if ( verbose ){ +            printf(   "\t" +                     "Chn: %02x   -->   " +                     "Chn: %02x in " +                     "Slot: %02x\n", +                     d->local_chn, d->remote_chn, d->remote_slot +                  ); +         } +         offset += sizeof(struct fru_picmgext_chn_desc); +      } +      slot_d = (struct fru_picmgext_slot_desc*) &record->data[offset]; +      offset += sizeof(struct fru_picmgext_slot_desc); +   } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_address_table_record +* +* Description: this function displays address table record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-6 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_address_table_record( struct ipmi_ek_multi_header * record ) +{ +   unsigned char entries = 0; +   unsigned char i; +   int offset = START_DATA_OFFSET; +   #define SIZE_SHELF_ADDRESS_BYTE   20 + +   printf("   Type/Len:    0x%02x\n", record->data[offset++]); +   printf("   Shelf Addr: "); +   for ( i = 0; i < SIZE_SHELF_ADDRESS_BYTE; i++ ){ +      printf("0x%02x ", record->data[offset++]); +   } +   printf("\n"); + +   entries = record->data[offset++]; +   printf("   Addr Table Entries count: 0x%02x\n", entries); + +   for ( i = 0; i < entries; i++ ){ +      printf("\tHWAddr: 0x%02x  - SiteNum: 0x%02x - SiteType: 0x%02x \n", +               record->data[offset+0], +               record->data[offset+1], +               record->data[offset+2]); +      offset += 3; +   } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_power_distribution_record +* +* Description: this function displays shelf power distribution record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-70 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_power_distribution_record( +      struct ipmi_ek_multi_header * record ) +{ +   int offset = START_DATA_OFFSET; +   unsigned char i,j; +   unsigned char feeds = 0; + +   feeds = record->data[offset++]; +   printf("   Number of Power Feeds: 0x%02x\n", feeds); + +   for (i=0; i<feeds; i++) { +      unsigned char entries; +      unsigned long max_ext = 0; +      unsigned long max_int = 0; +      max_ext = record->data[offset+0] | (record->data[offset+1]<<8); +      printf("   Max External Available Current: %ld Amps\n", (max_ext*10) ); + +      offset += 2; + +      max_int = record->data[offset+0] | (record->data[offset+1]<<8); +      printf("   Max Internal Current:\t   %ld Amps\n", (max_int*10)); +      offset += 2; +      printf("   Min Expected Operating Voltage: %d Volts\n", +                     (record->data[offset++]/2)); +      entries = record->data[offset++]; +      printf("   Feed to FRU count: 0x%02x\n", entries); +      for (j=0; j<entries; j++) { +         printf("\tHW: 0x%02x",   record->data[offset++]); +         printf("\tFRU ID: 0x%02x\n", record->data[offset++]); +      } +   } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_activation_record +* +* Description: this function displays shelf activation record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-73 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_activation_record( +      struct ipmi_ek_multi_header * record ) +{ +   unsigned char count = 0; +   int offset = START_DATA_OFFSET; + +   printf("   Allowance for FRU Act Readiness: 0x%02x\n", +                  record->data[offset++]); +   count = record->data[offset++]; +   printf("   FRU activation and Power Desc Cnt: 0x%02x\n", count); + +   while ( count > 0 ) { +      printf("   FRU activation and Power descriptor:\n"); +      printf("\tHardware Address:\t\t0x%02x\n", record->data[offset++]); +      printf("\tFRU Device ID:\t\t\t0x%02x\n", record->data[offset++]); +      printf("\tMax FRU Power Capability:\t0x%04x Watts\n", +                  ( record->data[offset+0] | (record->data[offset+1]<<8) )); +      offset += 2; +      printf("\tConfiguration parameter:\t0x%02x\n", record->data[offset++]); +      count --; +   } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_ip_connection_record +* +* Description: this function displays shelf ip connection record. +* +* Restriction: Fix me: Don't test yet +*               Reference: PICMG 3.0 Specification Table 3-31 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_ip_connection_record( +      struct ipmi_ek_multi_header * record ) +{ +   int ioffset = START_DATA_OFFSET; +   if (ioffset > record->header.len) { +      printf("   Shelf Manager IP Address: %d.%d.%d.%d\n", +            record->data[ioffset+0], record->data[ioffset+1], +            record->data[ioffset+2], record->data[ioffset+3]); +      ioffset += 4; +   } +   if (ioffset > record->header.len) { +      printf("   Default Gateway Address: %d.%d.%d.%d\n", +            record->data[ioffset+0], record->data[ioffset+1], +            record->data[ioffset+2], record->data[ioffset+3]); +      ioffset += 4; +   } +   if (ioffset > record->header.len) { +      printf("   Subnet Mask: %d.%d.%d.%d\n",  +            record->data[ioffset+0], record->data[ioffset+1], +            record->data[ioffset+2], record->data[ioffset+3]); +      ioffset += 4; +   } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_fan_geography_record +* +* Description: this function displays shelf fan geography record. +* +* Restriction: Fix me: Don't test yet +*               Reference: PICMG 3.0 Specification Table 3-75 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_fan_geography_record( +      struct ipmi_ek_multi_header * record ) +{ +   int ioffset = START_DATA_OFFSET; +   unsigned char fan_count = 0; + +   fan_count = record->data[ioffset]; +   ioffset++; +   printf("   Fan-to-FRU Entry Count: 0x%02x\n", fan_count); + +   while ( (fan_count > 0) && (ioffset <= record->header.len) ) { +      printf("   Fan-to-FRU Mapping Entry: {%2x%2x%2x%2x}\n", +                  record->data[ioffset], record->data[ioffset+1], +                  record->data[ioffset+2], record->data[ioffset+3] +             ); +      printf("      Hardware Address:   0x%02x\n", record->data[ioffset++]); +      printf("      FRU device ID:   0x%02x\n", record->data[ioffset++]); +      printf("      Site Number:   0x%02x\n", record->data[ioffset++]); +      printf("      Site Type:   0x%02x\n", record->data[ioffset++]); +      fan_count --; +   } + +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_board_p2p_record +* +* Description: this function displays board pont-to-point record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-44 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_board_p2p_record( struct ipmi_ek_multi_header * record ) +{ +   unsigned char guid_count; +   int offset = START_DATA_OFFSET; +   int i = 0; + +   guid_count = record->data[offset++]; +   printf("   GUID count: %2d\n", guid_count); + +   for (i = 0 ; i < guid_count; i++ ) { +      int j; +      printf("\tGUID: "); +      for (j=0; j < sizeof(struct fru_picmgext_guid); j++) { +         printf("%02x", record->data[offset+j]); +      } +      printf("\n"); +      offset += sizeof(struct fru_picmgext_guid); +   } + +   for ( offset; +         offset < record->header.len; +         offset += sizeof(struct fru_picmgext_link_desc) +       ) { +      /* to solve little endian /big endian problem */ +      unsigned long data; +      struct fru_picmgext_link_desc * d; + +      data = (record->data[offset+0]) |   (record->data[offset+1] << 8)\ +            | (record->data[offset+2] << 16)\ +            | (record->data[offset+3] << 24); + +      d = (struct fru_picmgext_link_desc *) &data; + +      printf("   Link Descriptor\n"); +      printf("\tLink Grouping ID:\t0x%02x\n", d->grouping); +      printf("\tLink Type Extension:\t0x%02x - ", d->ext); + +      if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE){ +         switch (d->ext){ +            case 0: +               printf("10/100/1000BASE-T Link (four-pair)\n"); +               break; +            case 1: +               printf("ShMC Cross-connect (two-pair)\n"); +               break; +            default: +               printf("Unknwon\n"); +               break; +         } +      } +      else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET){ +         switch (d->ext){ +            case 0: +               printf("Fixed 1000Base-BX\n"); +               break; +            case 1: +               printf("Fixed 10GBASE-BX4 [XAUI]\n"); +               break; +            case 2: +               printf("FC-PI\n"); +               break; +            default: +               printf("Unknwon\n"); +               break; +         } +      } +      else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND){ +         printf("Unknwon\n"); +      } +      else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR){ +         printf("Unknwon\n"); +      } +      else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE){ +         printf("Unknwon\n"); +      } +      else{ +         printf("Unknwon\n"); +      } + +      printf("\tLink Type:\t\t0x%02x - ",d->type); +      if (d->type == 0 || d->type == 0xff){ +         printf("Reserved\n"); +      } +      else if (d->type >= 0x06 && d->type <= 0xef) { +         printf("Reserved\n"); +      } +      else if (d->type >= LOWER_OEM_TYPE && d->type <= UPPER_OEM_TYPE) { +         printf("OEM GUID Definition\n"); +      } +      else { +         switch (d->type){ +            case FRU_PICMGEXT_LINK_TYPE_BASE: +               printf("PICMG 3.0 Base Interface 10/100/1000\n"); +               break; +            case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: +               printf("PICMG 3.1 Ethernet Fabric Interface\n"); +               break; +            case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: +               printf("PICMG 3.2 Infiniband Fabric Interface\n"); +               break; +            case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: +               printf("PICMG 3.3 Star Fabric Interface\n"); +               break; +            case   FRU_PICMGEXT_LINK_TYPE_PCIE: +               printf("PICMG 3.4 PCI Express Fabric Interface\n"); +               break; +            default: +               printf("Invalid\n"); +               break; +         } +      } +      printf("\tLink Designator: \n"); +      printf("\t   Port 0 Flag:   %s\n", +               (d->desig_port & 0x01) ? "enable" : "disable"); +      printf("\t   Port 1 Flag:   %s\n", +               (d->desig_port & 0x02) ? "enable" : "disable"); +      printf("\t   Port 2 Flag:   %s\n", +               (d->desig_port & 0x04) ? "enable" : "disable"); +      printf("\t   Port 3 Flag:   %s\n", +               (d->desig_port & 0x08) ? "enable" : "disable"); + +      printf("\t   Interface:    0x%02x - ", d->desig_if); +      switch (d->desig_if){ +         case FRU_PICMGEXT_DESIGN_IF_BASE: +            printf("Base Interface\n"); +            break; +         case FRU_PICMGEXT_DESIGN_IF_FABRIC: +            printf("Fabric Interface\n"); +            break; +         case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: +            printf("Update Channel\n"); +            break; +         case FRU_PICMGEXT_DESIGN_IF_RESERVED: +            printf("Reserved\n"); +            break; +         default: +            printf("Invalid"); +            break; +      } +      printf("\t   Channel Number:    0x%02x\n", d->desig_channel); +   } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_radial_ipmb0_record +* +* Description: this function displays radial IPMB-0 record. +* +* Restriction: Fix me: Don't test yet +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_radial_ipmb0_record( struct ipmi_ek_multi_header * record ) +{ +   int offset = START_DATA_OFFSET; +   #define SIZE_OF_CONNECTOR_DEFINER  3; /*bytes*/ + +   /*Ref: PICMG 3.0 Specification Revision 2.0, Table 3-59*/ +   printf("   IPMB-0 Connector Definer: "); +   #ifndef WORDS_BIGENDIAN +      printf("%02x %02x %02x h\n", record->data[offset], +               record->data[offset+1], record->data[offset+2]); +   #else +      printf("%02x %02x %02x h\n", record->data[offset+2], +               record->data[offset+1], record->data[offset]); +   #endif +   /*3 bytes of connector definer was used*/ +   offset += SIZE_OF_CONNECTOR_DEFINER; + +   printf ("   IPMB-0 Connector version ID: "); +   #ifndef WORDS_BIGENDIAN +      printf("%02x %02x h\n", record->data[offset], record->data[offset+1]); +   #else +      printf("%02x %02x h\n", record->data[offset+1], record->data[offset]); +   #endif +   offset += 2; + +   printf("   IPMB-0 Hub Descriptor Count: 0x%02x", record->data[offset++]); +   if (record->data[offset] > 0){ +      for (offset; offset < record->header.len;){ +         unsigned char entry_count = 0; +         printf("   IPMB-0 Hub Descriptor\n"); +         printf("\tHardware Address: 0x%02x\n", record->data[offset++]); +         printf("\tHub Info {0x%02x}: ", record->data[offset]); +         /* Bit mask specified in Table 3-59 of PICMG 3.0 Specification */ +         if ( (record->data[offset] & 0x01) == 0x01 ){ +            printf("IPMB-A only\n"); +         } +         else if ( (record->data[offset] & 0x02) == 0x02 ){ +            printf("IPMB-B only\n"); +         } +         else if ( (record->data[offset] & 0x03) == 0x03 ){ +            printf("IPMB-A and IPMB-B\n"); +         } +         else{ +            printf("Reserved.\n"); +         } +         offset ++; + +         entry_count = record->data[offset++]; +         printf("\tAddress Entry count: 0x%02x", entry_count); +         while (entry_count > 0){ +            printf("\t   Hardware Address: 0x%02x\n", record->data[offset++]); +            printf("\t   IPMB-0 Link Entry: 0x%02x\n",record->data[offset++]); +            entry_count --; +         } +      } +   } + +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_current_record +* +* Description: this function displays AMC current record. +* +* Restriction: None +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_current_record( struct ipmi_ek_multi_header * record ) +{ +   unsigned char current; +   current     = record->data[START_DATA_OFFSET]; +   printf("   Current draw: %.1f A @ 12V => %.2f Watt\n", +                  (float) current/10.0, ((float)current/10.0)*12.0 ); +   printf("\n"); +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_activation_record +* +* Description: this function displays carrier activation and current management +*             record. +* +* Restriction: Reference: AMC.0 Specification Table 3-11 and Table 3-12 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_activation_record( struct ipmi_ek_multi_header * record ) +{ +   uint16_t max_current; +   int offset = START_DATA_OFFSET; + +   max_current = record->data[offset]; +   max_current |= record->data[++offset] << 8; +   printf("   Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n", +                                       (float) max_current / 10, +                                       (float) max_current / 10 * 12); +   printf("   Module Activation Readiness:    %i sec.\n", +                     record->data[++offset]); + +   printf("   Descriptor Count: %i\n", record->data[++offset]); +   for(++offset; (offset < record->header.len); offset += 3 ) +   { +      struct fru_picmgext_activation_record * a = +      (struct fru_picmgext_activation_record *) &record->data[offset]; + +      printf("\tIPMB-Address:\t\t0x%x\n", a->ibmb_addr); +      printf("\tMax. Module Current:\t%.2f A\n", (float)a->max_module_curr/10); +      printf("\n"); +   } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_p2p_record +* +* Description: this function display amc p2p connectivity record in humain +*              readable text format +* +* Restriction: Reference: AMC.0 Specification Table 3-16 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_p2p_record( struct ipmi_ek_multi_header * record ) +{ +   int index_data = START_DATA_OFFSET; +   int oem_count = 0; +   int ch_count = 0; +   int index=0; + +   oem_count = record->data[index_data++]; +   printf("OEM GUID count: %02x\n", oem_count); + +   if ( oem_count > 0 ){ +      while ( oem_count > 0 ){ +         printf("OEM GUID: "); +         for ( index = 1; index <= SIZE_OF_GUID; index++ ){ +            printf("%02x", record->data[index_data++]); +            /* For a better look, display a "-" character after each 5 bytes +            * of OEM GUID */ +            if ( !(index % 5) ){ +               printf("-"); +            } +         } +         printf("\n"); +         oem_count--; +      } +   } +   if ( ( record->data[index_data] & AMC_MODULE ) == AMC_MODULE ){ +      printf("AMC module connection\n"); +   } +   else{ +      printf("On-Carrier Device %02x h\n", ( record->data[index_data] & 0x0f )); +   } +   index_data ++; +   ch_count = record->data[index_data++]; +   printf("AMC Channel Descriptor count: %02x h\n", ch_count); + +   if ( ch_count > 0 ){ +      for ( index = 0; index < ch_count; index++ ){ +         unsigned int data; +         struct fru_picmgext_amc_channel_desc_record * ch_desc; +         printf("   AMC Channel Descriptor {%02x%02x%02x}\n", +               record->data[index_data+2], record->data[index_data+1], +               record->data[index_data] +               ); +         data = record->data[index_data] |  +             (record->data[index_data + 1] << 8) | +             (record->data[index_data + 2] << 16); +         ch_desc = ( struct fru_picmgext_amc_channel_desc_record * ) &data; +         printf("      Lane 0 Port: %d\n", ch_desc->lane0port); +         printf("      Lane 1 Port: %d\n", ch_desc->lane1port); +         printf("      Lane 2 Port: %d\n", ch_desc->lane2port); +         printf("      Lane 3 Port: %d\n\n", ch_desc->lane3port); +         index_data += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE; +      } +   } +   while ( index_data < record->header.len ){ +      /*Warning: For gcc version between 4.0 and 4.3 this code doesnt work*/ +      unsigned int data[2]; +      struct fru_picmgext_amc_link_desc_record *link_desc; +      data[0] = record->data[index_data] |  +              (record->data[index_data + 1] << 8) | +              (record->data[index_data + 2] << 16) | +              (record->data[index_data + 3] << 24); +      data[1] = record->data[index_data + 4]; + +      link_desc = (struct fru_picmgext_amc_link_desc_record *) &data[0]; + +      printf("   AMC Link Descriptor:\n" ); + +      printf("\t- Link Type: %s \n", +               val2str (link_desc->type, ipmi_ekanalyzer_link_type)); +      switch ( link_desc->type ) { +         case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: +         case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: +         case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: +            printf("\t- Link Type extension: %s\n", +                 val2str (link_desc->type_ext, ipmi_ekanalyzer_extension_PCIE)); +            printf("\t- Link Group ID: %d\n ", link_desc->group_id ); +            printf("\t- Link Asym. Match: %d - %s\n", +                 link_desc->asym_match,  +                 val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_PCIE)); +            break; +         case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: +            printf("\t- Link Type extension: %s\n", +                 val2str (link_desc->type_ext, +                           ipmi_ekanalyzer_extension_ETHERNET)); +            printf("\t- Link Group ID: %d \n", link_desc->group_id ); +            printf("\t- Link Asym. Match: %d - %s\n", +                 link_desc->asym_match,  +                 val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_PCIE)); +            break; +         case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: +            printf("\t- Link Type extension: %s\n", +                 val2str (link_desc->type_ext, +                           ipmi_ekanalyzer_extension_STORAGE)); +            printf("\t- Link Group ID: %d \n", link_desc->group_id ); +            printf("\t- Link Asym. Match: %d - %s\n", +                 link_desc->asym_match,  +                 val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_STORAGE)); +            break; +         default: +            printf("\t- Link Type extension: %i (Unknown)\n", link_desc->type_ext ); +            printf("\t- Link Group ID: %d \n", link_desc->group_id ); +            printf("\t- Link Asym. Match: %i\n", link_desc->asym_match); +            break; +      } +      printf("\t- AMC Link Designator:\n"); +      printf("\t    Channel ID: %i\n", link_desc->channel_id); +      printf("\t\t Lane 0: %s\n", (link_desc->port_flag_0)?"enable":"disable"); +      printf("\t\t Lane 1: %s\n", (link_desc->port_flag_1)?"enable":"disable"); +      printf("\t\t Lane 2: %s\n", (link_desc->port_flag_2)?"enable":"disable"); +      printf("\t\t Lane 3: %s\n", (link_desc->port_flag_3)?"enable":"disable"); +      index_data += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE; +   } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_carrier_info_record +* +* Description: this function displays Carrier information table. +* +* Restriction: Reference: AMC.0 Specification Table 3-3 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: START_DATA_OFFSET +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_carrier_info_record( struct ipmi_ek_multi_header * record ) +{ +   unsigned char extVersion; +   unsigned char siteCount; +   int offset = START_DATA_OFFSET; + +   extVersion = record->data[offset++]; +   siteCount  = record->data[offset++]; + +   printf("   AMC.0 extension version: R%d.%d\n", (extVersion >> 0)& 0x0F, +               (extVersion >> 4)& 0x0F ); +   printf("   Carrier Sie Number Count: %d\n", siteCount); + +   while (siteCount > 0){ +      printf("\tSite ID (%d): %s \n", record->data[offset], +         val2str(record->data[offset], ipmi_ekanalyzer_module_type) ); +      offset++; +      siteCount--; +   } +   printf("\n"); +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_clock_carrier_p2p_record +* +* Description: this function displays Carrier clock point-to-pont +*              connectivity record. +* +* Restriction: the following code is copy from ipmi_fru.c with modification in +*               reference to AMC.0 Specification Table 3-29 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_clock_carrier_p2p_record( +      struct ipmi_ek_multi_header * record ) +{ +   unsigned char desc_count; +   int i,j; +   int offset = START_DATA_OFFSET; + +   desc_count = record->data[offset++]; + +   for(i=0; i<desc_count; i++){ +      unsigned char resource_id; +      unsigned char channel_count; + +      resource_id     = record->data[offset++]; +      channel_count = record->data[offset++]; + +      printf("   Clock Resource ID: 0x%02x\n", resource_id); +      printf("   Type: "); +      if((resource_id & 0xC0)>>6 == 0) { +         printf("On-Carrier-Device\n"); +      } +      else if((resource_id & 0xC0)>>6 == 1) { +         printf("AMC slot\n"); +      } +      else if((resource_id & 0xC0)>>6 == 2) { +         printf("Backplane\n"); +      } +      else{ +         printf("reserved\n"); +      } +      printf("   Channel Count: 0x%02x\n", channel_count); + +      for(j=0; j<channel_count; j++){ +         unsigned char loc_channel, rem_channel, rem_resource; + +         loc_channel    = record->data[offset++]; +         rem_channel    = record->data[offset++]; +         rem_resource = record->data[offset++]; + +         printf("\tCLK-ID: 0x%02x   --->  ", loc_channel); +         printf(" remote CLKID: 0x%02x   ", rem_channel); +         if((rem_resource & 0xC0)>>6 == 0) { +            printf("[ Carrier-Dev"); +         } +         else if((rem_resource & 0xC0)>>6 == 1) { +            printf("[ AMC slot    "); +         } +         else if((rem_resource & 0xC0)>>6 == 2) { +            printf("[ Backplane    "); +         } +         else{ +            printf("reserved          "); +         } +         printf(" 0x%02x ]\n", rem_resource&0xF); +      } +   } +   printf("\n"); +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_clock_config_record +* +* Description: this function displays clock configuration record. +* +* Restriction: the following codes are copy from ipmi_fru.c with modification +*               in reference to AMC.0 Specification Table 3-35 and Table 3-36 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: START_DATA_OFFSET +* +* Return: None +* +***************************************************************************/ +void +ipmi_ek_display_clock_config_record( struct ipmi_ek_multi_header * record ) +{ +   unsigned char resource_id, descr_count; +   int i; +   int offset = START_DATA_OFFSET; + +   resource_id = record->data[offset++]; +   descr_count = record->data[offset++]; +   printf("   Clock Resource ID: 0x%02x\n", resource_id); +   printf("   Clock Configuration Descriptor Count: 0x%02x\n", descr_count); + +   for(i=0; i<descr_count; i++){ +      unsigned char channel_id, control; +      unsigned char indirect_cnt, direct_cnt; +      int j=0; + +      channel_id = record->data[offset++]; +      control     = record->data[offset++]; +      printf("\tCLK-ID: 0x%02x  -  ", channel_id); +      printf("CTRL 0x%02x [ %12s ]\n", control, +                  ((control&0x1)==0)?"Carrier IPMC":"Application"); + +      indirect_cnt = record->data[offset++]; +      direct_cnt    = record->data[offset++]; +      printf("\t   Count: Indirect 0x%02x   / Direct 0x%02x\n", indirect_cnt, +                  direct_cnt   ); + +      /* indirect desc */ +      for(j=0; j<indirect_cnt; j++){ +         unsigned char feature; +         unsigned char dep_chn_id; + +         feature     = record->data[offset++]; +         dep_chn_id = record->data[offset++]; +         printf("\t\tFeature: 0x%02x [%8s] - ", feature, +                     (feature&0x1)==1?"Source":"Receiver"); +         printf(" Dep. CLK-ID: 0x%02x\n", dep_chn_id); +      } + +      /* direct desc */ +      for(j=0; j<direct_cnt; j++){ +         unsigned char feature, family, accuracy; +         unsigned long freq, min_freq, max_freq; + +         feature   = record->data[offset++]; +         family   = record->data[offset++]; +         accuracy = record->data[offset++]; +         freq = (record->data[offset+0] << 0 ) +                     | (record->data[offset+1] << 8 ) +                     | (record->data[offset+2] << 16) +                     | (record->data[offset+3] << 24); +         offset += 4; +         min_freq = (record->data[offset+0] << 0 ) +                     | (record->data[offset+1] << 8 ) +                     | (record->data[offset+2] << 16) +                     | (record->data[offset+3] << 24); +         offset += 4; +         max_freq = (record->data[offset+0] << 0 ) +                     | (record->data[offset+1] << 8 ) +                     | (record->data[offset+2] << 16) +                     | (record->data[offset+3] << 24); +         offset += 4; + +         printf("\t- Feature: 0x%02x    - PLL: %x / Asym: %s\n", +                      feature, +                      (feature > 1) & 1, +                      (feature&1)?"Source":"Receiver"); +         printf("\tFamily:  0x%02x    - AccLVL: 0x%02x\n", family, accuracy); +         printf("\tFRQ: %-9ld - min: %-9ld - max: %-9ld\n", +                     freq, min_freq, max_freq); +      } +      printf("\n"); +   } +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_fru_file2structure +* +* Description: this function convert a FRU binary file into a linked list of +*              FRU multi record +* +* Restriction: None +* +* Input/Ouput: filename1: name of the file that contain FRU binary data +*        record: a pointer to current record +*        list_head: a pointer to header of the list +*        list_last: a pointer to tale of the list +* +* Global: None +* +* Return: return -1 as Error status, and 0 as Ok status +* +***************************************************************************/ +static int +ipmi_ekanalyzer_fru_file2structure(char * filename, +		struct ipmi_ek_multi_header ** list_head, +		struct ipmi_ek_multi_header ** list_record, +		struct ipmi_ek_multi_header ** list_last) +{ +	FILE * input_file; +	unsigned char data; +	unsigned char last_record = 0; +	unsigned int multi_offset = 0; +	int record_count = 0; +	int ret = 0; + +	input_file = fopen(filename, "r"); +	if (input_file == NULL) { +		lprintf(LOG_ERR, "File: '%s' is not found", filename); +		return ERROR_STATUS; +	} + +	fseek(input_file, START_DATA_OFFSET, SEEK_SET); +	data = 0; +	ret = fread(&data, 1, 1, input_file); +	if ((ret != 1) || ferror(input_file)) { +		lprintf(LOG_ERR, "Invalid Offset!"); +		fclose(input_file); +		return ERROR_STATUS; +	} +	if (data == 0) { +		lprintf(LOG_ERR, "There is no multi record in the file '%s'", +			filename); +		fclose(input_file); +		return ERROR_STATUS; +	} +	/* the offset value is in multiple of 8 bytes. */ +	multi_offset = data * 8; +	lprintf(LOG_DEBUG, "start multi offset = 0x%02x",  +		multi_offset ); + +	fseek(input_file, multi_offset, SEEK_SET); +	while (!feof(input_file)) { +		*list_record = malloc(sizeof(struct ipmi_ek_multi_header)); +		ret = fread(&(*list_record)->header, START_DATA_OFFSET, 1,  +				input_file); +		if ((ret != 1) || ferror(input_file)) { +			lprintf(LOG_ERR, "Invalid Header!"); +			fclose(input_file); +			return ERROR_STATUS; +		} +		if ((*list_record)->header.len == 0) { +			record_count++; +			continue; +		} +		(*list_record)->data = malloc((*list_record)->header.len); +		if ((*list_record)->data == NULL) { +			lprintf(LOG_ERR, "Failed to allocation memory size %d\n", +					(*list_record)->header.len); +			record_count++; +			continue; +		} + +		ret = fread((*list_record)->data, ((*list_record)->header.len), +				1, input_file); +		if ((ret != 1) || ferror(input_file)) { +			lprintf(LOG_ERR, "Invalid Record Data!"); +			fclose(input_file); +			return ERROR_STATUS; +		} +		if (verbose > 0) +			printf("Record %d has length = %02x\n", record_count, +					(*list_record)->header.len); +		if (verbose > 1) { +			int i; +			printf("Type: %02x", (*list_record)->header.type); +			for (i = 0; i < ((*list_record)->header.len); i++) { +				if (!(i % 8)) { +					printf("\n0x%02x: ", i); +				} +				printf("%02x ", +					(*list_record)->data[i]); +			} +			printf("\n\n"); +		} +		ipmi_ek_add_record2list(list_record, list_head, list_last); +		/* mask the 8th bits to see if it is the last record */ +		last_record = ((*list_record)->header.format) & 0x80; +		if (last_record) { +			break; +		} +		record_count++; +	} +	fclose(input_file); +	return OK_STATUS; +} + + +/************************************************************************** +* +* Function name: ipmi_ek_add_record2list +* +* Description: this function adds a sigle FRU multi record to a linked list of +*              FRU multi record. +* +* Restriction: None +* +* Input/Output: record: a pointer to current record +*        list_head: a pointer to header of the list +*        list_last: a pointer to tale of the list +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_add_record2list( struct ipmi_ek_multi_header ** record, +      struct ipmi_ek_multi_header ** list_head, +      struct ipmi_ek_multi_header ** list_last ) +{ +   if (*list_head == NULL) { +      *list_head = *record; +      (*record)->prev = NULL; +      if (verbose > 2) +         printf("Adding first record to list\n"); +   } +   else { +      (*list_last)->next = *record; +      (*record)->prev = *list_last; +      if (verbose > 2) +         printf("Add 1 record to list\n"); +   } +   *list_last = *record; +   (*record)->next = NULL; +} + +/************************************************************************** +* +* Function name: ipmi_ek_remove_record_from_list +* +* Description: this function removes a sigle FRU multi record from a linked +*              list of FRU multi record. +* +* Restriction: None +* +* Input/Output: record: a pointer to record to be deleted +*        list_head: a pointer to header of the list +*        list_last: a pointer to tale of the list +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_remove_record_from_list( struct ipmi_ek_multi_header * record, +      struct ipmi_ek_multi_header ** list_head, +      struct ipmi_ek_multi_header ** list_last ) +{ +   if (record->prev == NULL) +      *list_head = record->next; +   else +      record->prev->next = record->next; +   if ( record->next == NULL ) +      (*list_last) = record->prev; +   else +      record->next->prev = record->prev; +   free(record); +   record = NULL; +} + + + + | 
