ipmitool/lib/ipmi_ekanalyzer.c
Zdenek Styblik 24ebe2fed9 ID:355 - Remove declared, but not used variables
Commit removes bunch of declared, but not used, variables.
2016-03-14 20:19:35 +01:00

4181 lines
136 KiB
C

/*
* 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 filetype = ERROR_STATUS;
if (strlen(argument) <= MIN_ARGUMENT) {
return filetype;
}
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];
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) {
lprintf(LOG_ERR, "Not enough parameters given.");
ipmi_ekanalyzer_usage();
return (-1);
} else if ((argc - 1) > MAX_FILE_NUMBER) {
lprintf(LOG_ERR, "Too too many parameters given.");
return (-1);
}
if (strcmp(argv[argument_offset], "help") == 0) {
ipmi_ekanalyzer_usage();
return 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
|| file_type[type_offset] == CONFIG_FILE) {
lprintf(LOG_ERR, "Invalid file type!");
lprintf(LOG_ERR, " ekanalyzer frushow <xx=frufile> ...");
return (-1);
}
/* 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) {
lprintf(LOG_ERR, "malloc failure");
return (-1);
}
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 */
rc = 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 if ((strcmp(argv[argument_offset], "print") == 0)
|| (strcmp(argv[argument_offset], "summary") == 0)) {
/* Display help text for corresponding command
* if not enough parameters were given.
*/
char * option;
/* index=1 indicates start position of first file
* name in command line
*/
int index = 1;
int filename_size=0;
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]");
}
return ERROR_STATUS;
}
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--;
} else if ( strncmp(&argv[argument_offset][2], "=", 1) == 0) {
/* since the command line must receive xx=filename,
* so the position of "=" sign is 2
*/
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) {
/* TODO - check malloc() retval */
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 */
} 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;
}
/* reset list count */
list = 0;
for (index = 0; index < argc; index++) {
if (file_type[index] != ON_CARRIER_FRU_FILE) {
continue;
}
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 offset = START_DATA_OFFSET;
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 ERROR_STATUS;
}
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 OK_STATUS;
}
/**************************************************************************
*
* 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) {
return ERROR_STATUS;
}
/* 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) {
return result;
}
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;
}
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 (header.offset.internal != 0) {
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!");
if (additional_data != NULL) {
free(additional_data);
additional_data = NULL;
}
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);
}
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");
return;
}
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) {
continue;
}
/* In picmg3.0 specification, picmg record
* id lower than 4 or greater than 0x2d
* isn't 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)
{
#define SIZE_SHELF_ADDRESS_BYTE 20
unsigned char entries = 0;
unsigned char i;
int offset = START_DATA_OFFSET;
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;
unsigned char 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)
{
#define SIZE_OF_CONNECTOR_DEFINER 3; /*bytes*/
int offset = START_DATA_OFFSET;
/* 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] < 1) {
return;
}
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: This code doesn't work with gcc version
* between 4.0 and 4.3
*/
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;
int 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;
unsigned char rem_channel;
unsigned char 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;
unsigned char 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++) {
int j = 0;
unsigned char channel_id;
unsigned char control;
unsigned char indirect_cnt;
unsigned char direct_cnt;
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;
unsigned char family;
unsigned char accuracy;
unsigned long freq;
unsigned long min_freq;
unsigned long 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)) {
/* TODO - check malloc() */
*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)) {
/* TODO - no free?! */
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;
}