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