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