xref: /openbmc/ipmitool/lib/ipmi_ekanalyzer.c (revision 8227384c)
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 				if (additional_data != NULL) {
2777 					free(additional_data);
2778 					additional_data = NULL;
2779 				}
2780 				goto out;
2781 			}
2782 			printf("Additional Custom Mfg. Data: %02x",
2783 					additional_data[0]);
2784 			for (i = 1; i < size_board; i++) {
2785 				printf("-%02x", additional_data[i]);
2786 			}
2787 			printf("\n");
2788 			free(additional_data);
2789 			additional_data = NULL;
2790 			(*board_length) -= size_board;
2791 		}
2792 		else {
2793 			printf("No Additional Custom Mfg. %d\n", *board_length);
2794 			goto out;
2795 		}
2796 	}
2797 
2798 out:
2799 	file_offset = ftell(input_file);
2800 	return file_offset;
2801 }
2802 
2803 /**************************************************************************
2804 *
2805 * Function name: ipmi_ek_display_product_info_area
2806 *
2807 * Description: this function displays detail format of product info area record
2808 *               into humain readable text format
2809 *
2810 * Restriction: Reference: IPMI Platform Management FRU Information Storage
2811 *                  Definition V1.0, Section 12
2812 *
2813 * Input: input_file: pointer to file stream
2814 *         offset: start offset of product info area
2815 *
2816 * Output: None
2817 *
2818 * Global: None
2819 *
2820 * Return: None
2821 *
2822 ***************************************************************************/
2823 static int
2824 ipmi_ek_display_product_info_area(FILE *input_file, long offset)
2825 {
2826 	size_t file_offset;
2827 	int ret = 0;
2828 	unsigned char ch_len = 0;
2829 	unsigned char data = 0;
2830 	unsigned int len = 0;
2831 
2832 	if (input_file == NULL) {
2833 		lprintf(LOG_ERR, "No file stream to read.");
2834 		return (-1);
2835 	}
2836 	file_offset = ftell(input_file);
2837 	printf("%s\n", EQUAL_LINE_LIMITER);
2838 	printf("Product Info Area\n");
2839 	printf("%s\n", EQUAL_LINE_LIMITER);
2840 	ret = fseek(input_file, offset, SEEK_SET);
2841 	if (feof(input_file)) {
2842 		lprintf(LOG_ERR, "Invalid Product Info Area!");
2843 		return (-1);
2844 	}
2845 	ret = fread(&data, 1, 1, input_file);
2846 	if ((ret != 1) || ferror(input_file)) {
2847 		lprintf(LOG_ERR, "Invalid Data!");
2848 		return (-1);
2849 	}
2850 	printf("Format Version Number: %d\n", (data & 0x0f));
2851 	if (feof(input_file)) {
2852 		return (-1);
2853 	}
2854 	/* Have to read this into a char or else
2855 	 * it ends up byte swapped on big endian machines */
2856 	ret = fread(&ch_len, 1, 1, input_file);
2857 	if ((ret != 1) || ferror(input_file)) {
2858 		lprintf(LOG_ERR, "Invalid Length!");
2859 		return (-1);
2860 	}
2861 	/* length is in factor of 8 bytes */
2862 	len = ch_len * 8;
2863 	printf("Area Length: %d\n", len);
2864 	len -= 2; /* -1 byte of format version and -1 byte itself */
2865 
2866 	ret = fread(&data, 1, 1, input_file);
2867 	if ((ret != 1) || ferror(input_file)) {
2868 		lprintf(LOG_ERR, "Invalid Length!");
2869 		return (-1);
2870 	}
2871 
2872 	fread(&data, 1, 1, input_file);
2873 	printf("Language Code: %d\n", data);
2874 	len--;
2875 	/* Product Mfg */
2876 	file_offset = ipmi_ek_display_board_info_area(input_file,
2877 			"Product Manufacture Data", &len);
2878 	ret = fseek(input_file, file_offset, SEEK_SET);
2879 	/* Product Name */
2880 	file_offset = ipmi_ek_display_board_info_area(input_file,
2881 			"Product Name", &len);
2882 	ret = fseek(input_file, file_offset, SEEK_SET);
2883 	/* Product Part */
2884 	file_offset = ipmi_ek_display_board_info_area(input_file,
2885 			"Product Part/Model Number", &len);
2886 	ret = fseek(input_file, file_offset, SEEK_SET);
2887 	/* Product Version */
2888 	file_offset = ipmi_ek_display_board_info_area(input_file,
2889 			"Product Version", &len);
2890 	ret = fseek(input_file, file_offset, SEEK_SET);
2891 	/* Product Serial */
2892 	file_offset = ipmi_ek_display_board_info_area(input_file,
2893 			"Product Serial Number", &len);
2894 	ret = fseek(input_file, file_offset, SEEK_SET);
2895 	/* Product Asset Tag */
2896 	file_offset = ipmi_ek_display_board_info_area(input_file,
2897 			"Asset Tag", &len);
2898 	ret = fseek(input_file, file_offset, SEEK_SET);
2899 	/* FRU file ID */
2900 	file_offset = ipmi_ek_display_board_info_area(input_file,
2901 			"FRU File ID", &len);
2902 	ret = fseek(input_file, file_offset, SEEK_SET);
2903 	/* Custom product info area */
2904 	file_offset = ipmi_ek_display_board_info_area(input_file,
2905 			"Custom", &len);
2906 	return 0;
2907 }
2908 
2909 /**************************************************************************
2910 *
2911 * Function name: ipmi_ek_display_record
2912 *
2913 * Description: this function displays FRU multi record information.
2914 *
2915 * Restriction: None
2916 *
2917 * Input: record: a pointer to current record
2918 *        list_head: a pointer to header of the list
2919 *        list_last: a pointer to tale of the list
2920 *
2921 * Output: None
2922 *
2923 * Global: None
2924 *
2925 * Return: None
2926 *
2927 ***************************************************************************/
2928 static void
2929 ipmi_ek_display_record(struct ipmi_ek_multi_header *record,
2930 		struct ipmi_ek_multi_header *list_head,
2931 		struct ipmi_ek_multi_header *list_last)
2932 {
2933 	if (list_head == NULL) {
2934 		printf("***empty list***\n");
2935 		return;
2936 	}
2937 	printf("%s\n", EQUAL_LINE_LIMITER);
2938 	printf("FRU Multi Info area\n");
2939 	printf("%s\n", EQUAL_LINE_LIMITER);
2940 	for (record = list_head; record != NULL; record = record->next) {
2941 		printf("Record Type ID: 0x%02x\n", record->header.type);
2942 		printf("Record Format version: 0x%02x\n",
2943 				record->header.format);
2944 		if (record->header.len <= PICMG_ID_OFFSET) {
2945 			continue;
2946 		}
2947 		/* In picmg3.0 specification, picmg record
2948 		 * id lower than 4 or greater than 0x2d
2949 		 * isn't supported
2950 		 */
2951 		#define PICMG_ID_LOWER_LIMIT  0x04
2952 		#define PICMG_ID_UPPER_LIMIT  0x2d
2953 		unsigned char picmg_id;
2954 
2955 		picmg_id = record->data[PICMG_ID_OFFSET];
2956 		printf("Manufacturer ID: %02x%02x%02x h\n",
2957 				record->data[2], record->data[1],
2958 				record->data[0]);
2959 		if ((picmg_id < PICMG_ID_LOWER_LIMIT)
2960 				|| (picmg_id > PICMG_ID_UPPER_LIMIT)) {
2961 			printf("Picmg record ID: Unsupported {0x%02x}\n", picmg_id);
2962 		} else {
2963 			printf("Picmg record ID: %s {0x%02x}\n",
2964 					val2str(picmg_id, ipmi_ekanalyzer_picmg_record_id),
2965 					picmg_id);
2966 		}
2967 		switch (picmg_id) {
2968 		case FRU_PICMG_BACKPLANE_P2P: /*0x04*/
2969 			ipmi_ek_display_backplane_p2p_record (record);
2970 			break;
2971 		case FRU_PICMG_ADDRESS_TABLE: /*0x10*/
2972 			ipmi_ek_display_address_table_record (record);
2973 			break;
2974 		case FRU_PICMG_SHELF_POWER_DIST: /*0x11*/
2975 			ipmi_ek_display_shelf_power_distribution_record (record);
2976 			break;
2977 		case FRU_PICMG_SHELF_ACTIVATION: /*/0x12*/
2978 			ipmi_ek_display_shelf_activation_record (record);
2979 			break;
2980 		case FRU_PICMG_SHMC_IP_CONN: /*0x13*/
2981 			ipmi_ek_display_shelf_ip_connection_record (record);
2982 			break;
2983 		case FRU_PICMG_BOARD_P2P: /*0x14*/
2984 			ipmi_ek_display_board_p2p_record (record);
2985 			break;
2986 		case FRU_RADIAL_IPMB0_LINK_MAPPING: /*0x15*/
2987 			ipmi_ek_display_radial_ipmb0_record (record);
2988 			break;
2989 		case FRU_AMC_CURRENT: /*0x16*/
2990 			ipmi_ek_display_amc_current_record (record);
2991 			break;
2992 		case FRU_AMC_ACTIVATION: /*0x17*/
2993 			ipmi_ek_display_amc_activation_record (record);
2994 			break;
2995 		case FRU_AMC_CARRIER_P2P: /*0x18*/
2996 			ipmi_ek_display_carrier_connectivity (record);
2997 			break;
2998 		case FRU_AMC_P2P: /*0x19*/
2999 			ipmi_ek_display_amc_p2p_record (record);
3000 			break;
3001 		case FRU_AMC_CARRIER_INFO: /*0x1a*/
3002 			ipmi_ek_display_amc_carrier_info_record (record);
3003 			break;
3004 		case FRU_PICMG_CLK_CARRIER_P2P: /*0x2c*/
3005 			ipmi_ek_display_clock_carrier_p2p_record (record);
3006 			break;
3007 		case FRU_PICMG_CLK_CONFIG: /*0x2d*/
3008 			ipmi_ek_display_clock_config_record (record);
3009 			break;
3010 		default:
3011 			if (verbose > 0) {
3012 				int i;
3013 				printf("%02x %02x %02x %02x %02x ",
3014 						record->header.type,
3015 						record->header.format,
3016 						record->header.len,
3017 						record->header.record_checksum,
3018 						record->header.header_checksum);
3019 				for (i = 0; i < record->header.len; i++) {
3020 					printf("%02x ", record->data[i]);
3021 				}
3022 				printf("\n");
3023 			}
3024 			break;
3025 		}
3026 		printf("%s\n", STAR_LINE_LIMITER);
3027 	}
3028 }
3029 
3030 /**************************************************************************
3031 *
3032 * Function name: ipmi_ek_display_backplane_p2p_record
3033 *
3034 * Description: this function displays backplane p2p record.
3035 *
3036 * Restriction: Reference: PICMG 3.0 Specification Table 3-40
3037 *
3038 * Input: record: a pointer to current record to be displayed
3039 *
3040 * Output: None
3041 *
3042 * Global: None
3043 *
3044 * Return: None
3045 *
3046 ***************************************************************************/
3047 static void
3048 ipmi_ek_display_backplane_p2p_record(struct ipmi_ek_multi_header *record)
3049 {
3050 	uint8_t index;
3051 	int offset = START_DATA_OFFSET;
3052 	struct fru_picmgext_slot_desc *slot_d =
3053 		(struct fru_picmgext_slot_desc*)&record->data[offset];
3054 
3055 	offset += sizeof(struct fru_picmgext_slot_desc);
3056 	while (offset <= record->header.len) {
3057 		printf("   Channel Type: ");
3058 		switch (slot_d->chan_type) {
3059 		case 0x00:
3060 		case 0x07:
3061 			printf("PICMG 2.9\n");
3062 			break;
3063 		case 0x08:
3064 			printf("Single Port Fabric IF\n");
3065 			break;
3066 		case 0x09:
3067 			printf("Double Port Fabric IF\n");
3068 			break;
3069 		case 0x0a:
3070 			printf("Full Channel Fabric IF\n");
3071 			break;
3072 		case 0x0b:
3073 			printf("Base IF\n");
3074 			break;
3075 		case 0x0c:
3076 			printf("Update Channel IF\n");
3077 			break;
3078 		default:
3079 			printf("Unknown IF\n");
3080 			break;
3081 		}
3082 		printf("   Slot Address:  %02x\n", slot_d->slot_addr);
3083 		printf("   Channel Count: %i\n", slot_d->chn_count);
3084 		for (index = 0; index < (slot_d->chn_count); index++) {
3085 			struct fru_picmgext_chn_desc *d =
3086 				(struct fru_picmgext_chn_desc *)&record->data[offset];
3087 			if (verbose) {
3088 				printf("\t"
3089 						"Chn: %02x   -->   "
3090 						"Chn: %02x in "
3091 						"Slot: %02x\n",
3092 						d->local_chn,
3093 						d->remote_chn,
3094 						d->remote_slot);
3095 			}
3096 			offset += sizeof(struct fru_picmgext_chn_desc);
3097 		}
3098 		slot_d = (struct fru_picmgext_slot_desc*)&record->data[offset];
3099 		offset += sizeof(struct fru_picmgext_slot_desc);
3100 	}
3101 }
3102 
3103 /**************************************************************************
3104 *
3105 * Function name: ipmi_ek_display_address_table_record
3106 *
3107 * Description: this function displays address table record.
3108 *
3109 * Restriction: Reference: PICMG 3.0 Specification Table 3-6
3110 *
3111 * Input: record: a pointer to current record to be displayed
3112 *
3113 * Output: None
3114 *
3115 * Global: None
3116 *
3117 * Return: None
3118 *
3119 ***************************************************************************/
3120 static void
3121 ipmi_ek_display_address_table_record(struct ipmi_ek_multi_header *record)
3122 {
3123 #define SIZE_SHELF_ADDRESS_BYTE 20
3124 	unsigned char entries = 0;
3125 	unsigned char i;
3126 	int offset = START_DATA_OFFSET;
3127 
3128 	printf("   Type/Len:    0x%02x\n", record->data[offset++]);
3129 	printf("   Shelf Addr: ");
3130 	for (i = 0; i < SIZE_SHELF_ADDRESS_BYTE; i++) {
3131 		printf("0x%02x ", record->data[offset++]);
3132 	}
3133 	printf("\n");
3134 	entries = record->data[offset++];
3135 	printf("   Addr Table Entries count: 0x%02x\n", entries);
3136 	for (i = 0; i < entries; i++) {
3137 		printf("\tHWAddr: 0x%02x  - SiteNum: 0x%02x - SiteType: 0x%02x \n",
3138 				record->data[offset+0],
3139 				record->data[offset+1],
3140 				record->data[offset+2]);
3141 		offset += 3;
3142 	}
3143 }
3144 
3145 /**************************************************************************
3146 *
3147 * Function name: ipmi_ek_display_shelf_power_distribution_record
3148 *
3149 * Description: this function displays shelf power distribution record.
3150 *
3151 * Restriction: Reference: PICMG 3.0 Specification Table 3-70
3152 *
3153 * Input: record: a pointer to current record to be displayed
3154 *
3155 * Output: None
3156 *
3157 * Global: None
3158 *
3159 * Return: None
3160 *
3161 ***************************************************************************/
3162 static void
3163 ipmi_ek_display_shelf_power_distribution_record(
3164 		struct ipmi_ek_multi_header *record)
3165 {
3166 	int offset = START_DATA_OFFSET;
3167 	unsigned char i;
3168 	unsigned char j;
3169 	unsigned char feeds = 0;
3170 
3171 	feeds = record->data[offset++];
3172 	printf("   Number of Power Feeds: 0x%02x\n", feeds);
3173 	for (i = 0; i < feeds; i++) {
3174 		unsigned char entries;
3175 		unsigned long max_ext = 0;
3176 		unsigned long max_int = 0;
3177 		max_ext = record->data[offset+0]
3178 			| (record->data[offset+1] << 8);
3179 		printf("   Max External Available Current: %ld Amps\n",
3180 				(max_ext * 10));
3181 		offset += 2;
3182 		max_int = record->data[offset+0]
3183 			| (record->data[offset+1] << 8);
3184 		printf("   Max Internal Current:\t   %ld Amps\n",
3185 				(max_int * 10));
3186 		offset += 2;
3187 		printf("   Min Expected Operating Voltage: %d Volts\n",
3188 				(record->data[offset++] / 2));
3189 		entries = record->data[offset++];
3190 		printf("   Feed to FRU count: 0x%02x\n", entries);
3191 		for (j = 0; j < entries; j++) {
3192 			printf("\tHW: 0x%02x", record->data[offset++]);
3193 			printf("\tFRU ID: 0x%02x\n", record->data[offset++]);
3194 		}
3195 	}
3196 }
3197 
3198 /**************************************************************************
3199 *
3200 * Function name: ipmi_ek_display_shelf_activation_record
3201 *
3202 * Description: this function displays shelf activation record.
3203 *
3204 * Restriction: Reference: PICMG 3.0 Specification Table 3-73
3205 *
3206 * Input: record: a pointer to current record to be displayed
3207 *
3208 * Output: None
3209 *
3210 * Global: None
3211 *
3212 * Return: None
3213 *
3214 ***************************************************************************/
3215 static void
3216 ipmi_ek_display_shelf_activation_record(struct ipmi_ek_multi_header *record)
3217 {
3218 	unsigned char count = 0;
3219 	int offset = START_DATA_OFFSET;
3220 
3221 	printf("   Allowance for FRU Act Readiness: 0x%02x\n",
3222 			record->data[offset++]);
3223 	count = record->data[offset++];
3224 	printf("   FRU activation and Power Desc Cnt: 0x%02x\n", count);
3225 	while (count > 0) {
3226 		printf("   FRU activation and Power descriptor:\n");
3227 		printf("\tHardware Address:\t\t0x%02x\n",
3228 				record->data[offset++]);
3229 		printf("\tFRU Device ID:\t\t\t0x%02x\n",
3230 				record->data[offset++]);
3231 		printf("\tMax FRU Power Capability:\t0x%04x Watts\n",
3232 				(record->data[offset+0]
3233 				 | (record->data[offset+1]<<8)));
3234 		offset += 2;
3235 		printf("\tConfiguration parameter:\t0x%02x\n",
3236 				record->data[offset++]);
3237 		count --;
3238 	}
3239 }
3240 
3241 /**************************************************************************
3242 *
3243 * Function name: ipmi_ek_display_shelf_ip_connection_record
3244 *
3245 * Description: this function displays shelf ip connection record.
3246 *
3247 * Restriction: Fix me: Don't test yet
3248 *               Reference: PICMG 3.0 Specification Table 3-31
3249 *
3250 * Input: record: a pointer to current record to be displayed
3251 *
3252 * Output: None
3253 *
3254 * Global: None
3255 *
3256 * Return: None
3257 *
3258 ***************************************************************************/
3259 static void
3260 ipmi_ek_display_shelf_ip_connection_record(struct ipmi_ek_multi_header *record)
3261 {
3262 	int ioffset = START_DATA_OFFSET;
3263 	if (ioffset > record->header.len) {
3264 		printf("   Shelf Manager IP Address: %d.%d.%d.%d\n",
3265 				record->data[ioffset+0],
3266 				record->data[ioffset+1],
3267 				record->data[ioffset+2],
3268 				record->data[ioffset+3]);
3269 		ioffset += 4;
3270 	}
3271 	if (ioffset > record->header.len) {
3272 		printf("   Default Gateway Address: %d.%d.%d.%d\n",
3273 				record->data[ioffset+0],
3274 				record->data[ioffset+1],
3275 				record->data[ioffset+2],
3276 				record->data[ioffset+3]);
3277 		ioffset += 4;
3278 	}
3279 	if (ioffset > record->header.len) {
3280 		printf("   Subnet Mask: %d.%d.%d.%d\n",
3281 				record->data[ioffset+0],
3282 				record->data[ioffset+1],
3283 				record->data[ioffset+2],
3284 				record->data[ioffset+3]);
3285 		ioffset += 4;
3286 	}
3287 }
3288 
3289 /**************************************************************************
3290 *
3291 * Function name: ipmi_ek_display_shelf_fan_geography_record
3292 *
3293 * Description: this function displays shelf fan geography record.
3294 *
3295 * Restriction: Fix me: Don't test yet
3296 *               Reference: PICMG 3.0 Specification Table 3-75
3297 *
3298 * Input: record: a pointer to current record to be displayed
3299 *
3300 * Output: None
3301 *
3302 * Global: None
3303 *
3304 * Return: None
3305 *
3306 ***************************************************************************/
3307 static void
3308 ipmi_ek_display_shelf_fan_geography_record(struct ipmi_ek_multi_header *record)
3309 {
3310 	int ioffset = START_DATA_OFFSET;
3311 	unsigned char fan_count = 0;
3312 
3313 	fan_count = record->data[ioffset];
3314 	ioffset++;
3315 	printf("   Fan-to-FRU Entry Count: 0x%02x\n", fan_count);
3316 	while ((fan_count > 0) && (ioffset <= record->header.len)) {
3317 		printf("   Fan-to-FRU Mapping Entry: {%2x%2x%2x%2x}\n",
3318 				record->data[ioffset],
3319 				record->data[ioffset+1],
3320 				record->data[ioffset+2],
3321 				record->data[ioffset+3]);
3322 		printf("      Hardware Address:   0x%02x\n",
3323 				record->data[ioffset++]);
3324 		printf("      FRU device ID:   0x%02x\n",
3325 				record->data[ioffset++]);
3326 		printf("      Site Number:   0x%02x\n",
3327 				record->data[ioffset++]);
3328 		printf("      Site Type:   0x%02x\n",
3329 				record->data[ioffset++]);
3330 		fan_count --;
3331 	}
3332 }
3333 
3334 /**************************************************************************
3335 *
3336 * Function name: ipmi_ek_display_board_p2p_record
3337 *
3338 * Description: this function displays board pont-to-point record.
3339 *
3340 * Restriction: Reference: PICMG 3.0 Specification Table 3-44
3341 *
3342 * Input: record: a pointer to current record to be displayed
3343 *
3344 * Output: None
3345 *
3346 * Global: None
3347 *
3348 * Return: None
3349 *
3350 ***************************************************************************/
3351 static void
3352 ipmi_ek_display_board_p2p_record(struct ipmi_ek_multi_header *record)
3353 {
3354 	unsigned char guid_count;
3355 	int offset = START_DATA_OFFSET;
3356 	int i = 0;
3357 
3358 	guid_count = record->data[offset++];
3359 	printf("   GUID count: %2d\n", guid_count);
3360 	for (i = 0 ; i < guid_count; i++) {
3361 		int j;
3362 		printf("\tGUID: ");
3363 		for (j = 0; j < sizeof(struct fru_picmgext_guid); j++) {
3364 			printf("%02x", record->data[offset+j]);
3365 		}
3366 		printf("\n");
3367 		offset += sizeof(struct fru_picmgext_guid);
3368 	}
3369 	for (offset;
3370 			offset < record->header.len;
3371 			offset += sizeof(struct fru_picmgext_link_desc)) {
3372 		/* to solve little endian/big endian problem */
3373 		unsigned long data;
3374 		struct fru_picmgext_link_desc * d;
3375 		data = (record->data[offset+0])
3376 			| (record->data[offset+1] << 8)\
3377 			| (record->data[offset+2] << 16)\
3378 			| (record->data[offset+3] << 24);
3379 		d = (struct fru_picmgext_link_desc *)&data;
3380 
3381 		printf("   Link Descriptor\n");
3382 		printf("\tLink Grouping ID:\t0x%02x\n", d->grouping);
3383 		printf("\tLink Type Extension:\t0x%02x - ", d->ext);
3384 		if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE) {
3385 			switch (d->ext) {
3386 			case 0:
3387 				printf("10/100/1000BASE-T Link (four-pair)\n");
3388 				break;
3389 			case 1:
3390 				printf("ShMC Cross-connect (two-pair)\n");
3391 				break;
3392 			default:
3393 				printf("Unknwon\n");
3394 				break;
3395 			}
3396 		} else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET) {
3397 			switch (d->ext) {
3398 			case 0:
3399 				printf("Fixed 1000Base-BX\n");
3400 				break;
3401 			case 1:
3402 				printf("Fixed 10GBASE-BX4 [XAUI]\n");
3403 				break;
3404 			case 2:
3405 				printf("FC-PI\n");
3406 				break;
3407 			default:
3408 				printf("Unknwon\n");
3409 				break;
3410 			}
3411 		} else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND) {
3412 			printf("Unknwon\n");
3413 		} else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR) {
3414 			printf("Unknwon\n");
3415 		} else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE) {
3416 			printf("Unknwon\n");
3417 		} else {
3418 			printf("Unknwon\n");
3419 		}
3420 		printf("\tLink Type:\t\t0x%02x - ", d->type);
3421 		if (d->type == 0 || d->type == 0xff) {
3422 			printf("Reserved\n");
3423 		} else if (d->type >= 0x06 && d->type <= 0xef) {
3424 			printf("Reserved\n");
3425 		} else if (d->type >= LOWER_OEM_TYPE && d->type <= UPPER_OEM_TYPE) {
3426 			printf("OEM GUID Definition\n");
3427 		} else {
3428 			switch (d->type){
3429 			case FRU_PICMGEXT_LINK_TYPE_BASE:
3430 				printf("PICMG 3.0 Base Interface 10/100/1000\n");
3431 				break;
3432 			case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET:
3433 				printf("PICMG 3.1 Ethernet Fabric Interface\n");
3434 				break;
3435 			case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND:
3436 				printf("PICMG 3.2 Infiniband Fabric Interface\n");
3437 				break;
3438 			case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR:
3439 				printf("PICMG 3.3 Star Fabric Interface\n");
3440 				break;
3441 			case FRU_PICMGEXT_LINK_TYPE_PCIE:
3442 				printf("PICMG 3.4 PCI Express Fabric Interface\n");
3443 				break;
3444 			default:
3445 				printf("Invalid\n");
3446 				break;
3447 			}
3448 		}
3449 		printf("\tLink Designator: \n");
3450 		printf("\t   Port 0 Flag:   %s\n",
3451 				(d->desig_port & 0x01) ? "enable" : "disable");
3452 		printf("\t   Port 1 Flag:   %s\n",
3453 				(d->desig_port & 0x02) ? "enable" : "disable");
3454 		printf("\t   Port 2 Flag:   %s\n",
3455 				(d->desig_port & 0x04) ? "enable" : "disable");
3456 		printf("\t   Port 3 Flag:   %s\n",
3457 				(d->desig_port & 0x08) ? "enable" : "disable");
3458 		printf("\t   Interface:    0x%02x - ", d->desig_if);
3459 		switch (d->desig_if) {
3460 		case FRU_PICMGEXT_DESIGN_IF_BASE:
3461 			printf("Base Interface\n");
3462 			break;
3463 		case FRU_PICMGEXT_DESIGN_IF_FABRIC:
3464 			printf("Fabric Interface\n");
3465 			break;
3466 		case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL:
3467 			printf("Update Channel\n");
3468 			break;
3469 		case FRU_PICMGEXT_DESIGN_IF_RESERVED:
3470 			printf("Reserved\n");
3471 			break;
3472 		default:
3473 			printf("Invalid");
3474 			break;
3475 		}
3476 		printf("\t   Channel Number:    0x%02x\n",
3477 				d->desig_channel);
3478 	}
3479 }
3480 
3481 /**************************************************************************
3482 *
3483 * Function name: ipmi_ek_display_radial_ipmb0_record
3484 *
3485 * Description: this function displays radial IPMB-0 record.
3486 *
3487 * Restriction: Fix me: Don't test yet
3488 *
3489 * Input: record: a pointer to current record to be displayed
3490 *
3491 * Output: None
3492 *
3493 * Global: None
3494 *
3495 * Return: None
3496 *
3497 ***************************************************************************/
3498 static void
3499 ipmi_ek_display_radial_ipmb0_record(struct ipmi_ek_multi_header *record)
3500 {
3501 #define SIZE_OF_CONNECTOR_DEFINER  3; /*bytes*/
3502 	int offset = START_DATA_OFFSET;
3503 	/* Ref: PICMG 3.0 Specification Revision 2.0, Table 3-59 */
3504 	printf("   IPMB-0 Connector Definer: ");
3505 #ifndef WORDS_BIGENDIAN
3506 	printf("%02x %02x %02x h\n", record->data[offset],
3507 			record->data[offset+1], record->data[offset+2]);
3508 #else
3509 	printf("%02x %02x %02x h\n", record->data[offset+2],
3510 			record->data[offset+1], record->data[offset]);
3511 #endif
3512 	/* 3 bytes of connector definer was used */
3513 	offset += SIZE_OF_CONNECTOR_DEFINER;
3514 	printf("   IPMB-0 Connector version ID: ");
3515 #ifndef WORDS_BIGENDIAN
3516 	printf("%02x %02x h\n", record->data[offset],
3517 			record->data[offset+1]);
3518 #else
3519 	printf("%02x %02x h\n", record->data[offset+1],
3520 			record->data[offset]);
3521 #endif
3522 	offset += 2;
3523 	printf("   IPMB-0 Hub Descriptor Count: 0x%02x",
3524 			record->data[offset++]);
3525 	if (record->data[offset] < 1) {
3526 		return;
3527 	}
3528 	for (offset; offset < record->header.len;) {
3529 		unsigned char entry_count = 0;
3530 		printf("   IPMB-0 Hub Descriptor\n");
3531 		printf("\tHardware Address: 0x%02x\n",
3532 				record->data[offset++]);
3533 		printf("\tHub Info {0x%02x}: ", record->data[offset]);
3534 		/* Bit mask specified in Table 3-59
3535 		 * of PICMG 3.0 Specification
3536 		 */
3537 		if ((record->data[offset] & 0x01) == 0x01) {
3538 			printf("IPMB-A only\n");
3539 		} else if ((record->data[offset] & 0x02) == 0x02) {
3540 			printf("IPMB-B only\n");
3541 		} else if ((record->data[offset] & 0x03) == 0x03) {
3542 			printf("IPMB-A and IPMB-B\n");
3543 		} else {
3544 			printf("Reserved.\n");
3545 		}
3546 		offset ++;
3547 		entry_count = record->data[offset++];
3548 		printf("\tAddress Entry count: 0x%02x", entry_count);
3549 		while (entry_count > 0) {
3550 			printf("\t   Hardware Address: 0x%02x\n",
3551 					record->data[offset++]);
3552 			printf("\t   IPMB-0 Link Entry: 0x%02x\n",
3553 					record->data[offset++]);
3554 			entry_count --;
3555 		}
3556 	}
3557 }
3558 
3559 /**************************************************************************
3560 *
3561 * Function name: ipmi_ek_display_amc_current_record
3562 *
3563 * Description: this function displays AMC current record.
3564 *
3565 * Restriction: None
3566 *
3567 * Input: record: a pointer to current record to be displayed
3568 *
3569 * Output: None
3570 *
3571 * Global: None
3572 *
3573 * Return: None
3574 *
3575 ***************************************************************************/
3576 static void
3577 ipmi_ek_display_amc_current_record(struct ipmi_ek_multi_header *record)
3578 {
3579 	unsigned char current;
3580 	current = record->data[START_DATA_OFFSET];
3581 	printf("   Current draw: %.1f A @ 12V => %.2f Watt\n",
3582 			(float)current / 10.0,
3583 			((float)current / 10.0) * 12.0);
3584 	printf("\n");
3585 }
3586 
3587 /**************************************************************************
3588 *
3589 * Function name: ipmi_ek_display_amc_activation_record
3590 *
3591 * Description: this function displays carrier activation and current management
3592 *             record.
3593 *
3594 * Restriction: Reference: AMC.0 Specification Table 3-11 and Table 3-12
3595 *
3596 * Input: record: a pointer to current record to be displayed
3597 *
3598 * Output: None
3599 *
3600 * Global: None
3601 *
3602 * Return: None
3603 *
3604 ***************************************************************************/
3605 static void
3606 ipmi_ek_display_amc_activation_record(struct ipmi_ek_multi_header *record)
3607 {
3608 	uint16_t max_current;
3609 	int offset = START_DATA_OFFSET;
3610 
3611 	max_current = record->data[offset];
3612 	max_current |= record->data[++offset] << 8;
3613 	printf("   Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n",
3614 			(float) max_current / 10,
3615 			(float) max_current / 10 * 12);
3616 	printf("   Module Activation Readiness:    %i sec.\n",
3617 			record->data[++offset]);
3618 	printf("   Descriptor Count: %i\n", record->data[++offset]);
3619 	for (++offset; (offset < record->header.len); offset += 3) {
3620 		struct fru_picmgext_activation_record *a =
3621 			(struct fru_picmgext_activation_record *)&record->data[offset];
3622 		printf("\tIPMB-Address:\t\t0x%x\n", a->ibmb_addr);
3623 		printf("\tMax. Module Current:\t%.2f A\n",
3624 				(float)a->max_module_curr / 10);
3625 		printf("\n");
3626 	}
3627 }
3628 
3629 /**************************************************************************
3630 *
3631 * Function name: ipmi_ek_display_amc_p2p_record
3632 *
3633 * Description: this function display amc p2p connectivity record in humain
3634 *              readable text format
3635 *
3636 * Restriction: Reference: AMC.0 Specification Table 3-16
3637 *
3638 * Input: record: a pointer to current record to be displayed
3639 *
3640 * Output: None
3641 *
3642 * Global: None
3643 *
3644 * Return: None
3645 *
3646 ***************************************************************************/
3647 static void
3648 ipmi_ek_display_amc_p2p_record(struct ipmi_ek_multi_header *record)
3649 {
3650 	int index_data = START_DATA_OFFSET;
3651 	int oem_count = 0;
3652 	int ch_count = 0;
3653 	int index=0;
3654 
3655 	oem_count = record->data[index_data++];
3656 	printf("OEM GUID count: %02x\n", oem_count);
3657 	if (oem_count > 0) {
3658 		while (oem_count > 0) {
3659 			printf("OEM GUID: ");
3660 			for (index = 1; index <= SIZE_OF_GUID; index++) {
3661 				printf("%02x", record->data[index_data++]);
3662 				/* For a better look, display a "-" character
3663 				 * after each 5 bytes of OEM GUID
3664 				 */
3665 				if (!(index % 5)) {
3666 					printf("-");
3667 				}
3668 			}
3669 			printf("\n");
3670 			oem_count--;
3671 		}
3672 	}
3673 	if ((record->data[index_data] & AMC_MODULE) == AMC_MODULE) {
3674 		printf("AMC module connection\n");
3675 	} else {
3676 		printf("On-Carrier Device %02x h\n",
3677 				(record->data[index_data] & 0x0f));
3678 	}
3679 	index_data ++;
3680 	ch_count = record->data[index_data++];
3681 	printf("AMC Channel Descriptor count: %02x h\n", ch_count);
3682 
3683 	if (ch_count > 0) {
3684 		for (index = 0; index < ch_count; index++) {
3685 			unsigned int data;
3686 			struct fru_picmgext_amc_channel_desc_record *ch_desc;
3687 			printf("   AMC Channel Descriptor {%02x%02x%02x}\n",
3688 					record->data[index_data+2],
3689 					record->data[index_data+1],
3690 					record->data[index_data]);
3691 			data = record->data[index_data]
3692 				| (record->data[index_data + 1] << 8)
3693 				| (record->data[index_data + 2] << 16);
3694 			ch_desc = (struct fru_picmgext_amc_channel_desc_record *)&data;
3695 			printf("      Lane 0 Port: %d\n", ch_desc->lane0port);
3696 			printf("      Lane 1 Port: %d\n", ch_desc->lane1port);
3697 			printf("      Lane 2 Port: %d\n", ch_desc->lane2port);
3698 			printf("      Lane 3 Port: %d\n\n", ch_desc->lane3port);
3699 			index_data += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE;
3700 		}
3701 	}
3702 	while (index_data < record->header.len) {
3703 		/* Warning: This code doesn't work with gcc version
3704 		 * between 4.0 and 4.3
3705 		 */
3706 		unsigned int data[2];
3707 		struct fru_picmgext_amc_link_desc_record *link_desc;
3708 		data[0] = record->data[index_data]
3709 			| (record->data[index_data + 1] << 8)
3710 			| (record->data[index_data + 2] << 16)
3711 			| (record->data[index_data + 3] << 24);
3712 		data[1] = record->data[index_data + 4];
3713 
3714 		link_desc = (struct fru_picmgext_amc_link_desc_record *)&data[0];
3715 		printf("   AMC Link Descriptor:\n");
3716 		printf("\t- Link Type: %s \n",
3717 				val2str(link_desc->type, ipmi_ekanalyzer_link_type));
3718 		switch (link_desc->type) {
3719 		case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE:
3720 		case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1:
3721 		case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2:
3722 			printf("\t- Link Type extension: %s\n",
3723 					val2str(link_desc->type_ext,
3724 						ipmi_ekanalyzer_extension_PCIE));
3725 			printf("\t- Link Group ID: %d\n ",
3726 					link_desc->group_id);
3727 			printf("\t- Link Asym. Match: %d - %s\n",
3728 					link_desc->asym_match,
3729 					val2str(link_desc->asym_match,
3730 						ipmi_ekanalyzer_asym_PCIE));
3731 			break;
3732 		case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET:
3733 			printf("\t- Link Type extension: %s\n",
3734 					val2str (link_desc->type_ext,
3735 						ipmi_ekanalyzer_extension_ETHERNET));
3736 			printf("\t- Link Group ID: %d \n",
3737 					link_desc->group_id);
3738 			printf("\t- Link Asym. Match: %d - %s\n",
3739 					link_desc->asym_match,
3740 					val2str(link_desc->asym_match,
3741 						ipmi_ekanalyzer_asym_PCIE));
3742 			break;
3743 		case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE:
3744 			printf("\t- Link Type extension: %s\n",
3745 					val2str (link_desc->type_ext,
3746 						ipmi_ekanalyzer_extension_STORAGE));
3747 			printf("\t- Link Group ID: %d \n",
3748 					link_desc->group_id);
3749 			printf("\t- Link Asym. Match: %d - %s\n",
3750 					link_desc->asym_match,
3751 					val2str(link_desc->asym_match,
3752 						ipmi_ekanalyzer_asym_STORAGE));
3753 			break;
3754 		default:
3755 			printf("\t- Link Type extension: %i (Unknown)\n",
3756 					link_desc->type_ext);
3757 			printf("\t- Link Group ID: %d \n",
3758 					link_desc->group_id);
3759 			printf("\t- Link Asym. Match: %i\n",
3760 					link_desc->asym_match);
3761 			break;
3762 		}
3763 		printf("\t- AMC Link Designator:\n");
3764 		printf("\t    Channel ID: %i\n", link_desc->channel_id);
3765 		printf("\t\t Lane 0: %s\n",
3766 				(link_desc->port_flag_0) ? "enable" : "disable");
3767 		printf("\t\t Lane 1: %s\n",
3768 				(link_desc->port_flag_1) ? "enable" : "disable");
3769 		printf("\t\t Lane 2: %s\n",
3770 				(link_desc->port_flag_2) ? "enable" : "disable");
3771 		printf("\t\t Lane 3: %s\n",
3772 				(link_desc->port_flag_3) ? "enable" : "disable");
3773 		index_data += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE;
3774 	}
3775 }
3776 
3777 /**************************************************************************
3778 *
3779 * Function name: ipmi_ek_display_amc_carrier_info_record
3780 *
3781 * Description: this function displays Carrier information table.
3782 *
3783 * Restriction: Reference: AMC.0 Specification Table 3-3
3784 *
3785 * Input: record: a pointer to current record to be displayed
3786 *
3787 * Output: None
3788 *
3789 * Global: START_DATA_OFFSET
3790 *
3791 * Return: None
3792 *
3793 ***************************************************************************/
3794 static void
3795 ipmi_ek_display_amc_carrier_info_record(struct ipmi_ek_multi_header *record)
3796 {
3797 	unsigned char extVersion;
3798 	unsigned char siteCount;
3799 	int offset = START_DATA_OFFSET;
3800 
3801 	extVersion = record->data[offset++];
3802 	siteCount  = record->data[offset++];
3803 	printf("   AMC.0 extension version: R%d.%d\n",
3804 			(extVersion >> 0) & 0x0F,
3805 			(extVersion >> 4) & 0x0F);
3806 	printf("   Carrier Sie Number Count: %d\n", siteCount);
3807 	while (siteCount > 0) {
3808 		printf("\tSite ID (%d): %s \n", record->data[offset],
3809 				val2str(record->data[offset], ipmi_ekanalyzer_module_type));
3810 		offset++;
3811 		siteCount--;
3812 	}
3813 	printf("\n");
3814 }
3815 
3816 /**************************************************************************
3817 *
3818 * Function name: ipmi_ek_display_clock_carrier_p2p_record
3819 *
3820 * Description: this function displays Carrier clock point-to-pont
3821 *              connectivity record.
3822 *
3823 * Restriction: the following code is copy from ipmi_fru.c with modification in
3824 *               reference to AMC.0 Specification Table 3-29
3825 *
3826 * Input: record: a pointer to current record to be displayed
3827 *
3828 * Output: None
3829 *
3830 * Global: None
3831 *
3832 * Return: None
3833 *
3834 ***************************************************************************/
3835 static void
3836 ipmi_ek_display_clock_carrier_p2p_record(struct ipmi_ek_multi_header *record)
3837 {
3838 	unsigned char desc_count;
3839 	int i;
3840 	int j;
3841 	int offset = START_DATA_OFFSET;
3842 
3843 	desc_count = record->data[offset++];
3844 	for(i = 0; i < desc_count; i++) {
3845 		unsigned char resource_id;
3846 		unsigned char channel_count;
3847 
3848 		resource_id = record->data[offset++];
3849 		channel_count = record->data[offset++];
3850 
3851 		printf("   Clock Resource ID: 0x%02x\n", resource_id);
3852 		printf("   Type: ");
3853 		if ((resource_id & 0xC0) >> 6 == 0) {
3854 			printf("On-Carrier-Device\n");
3855 		} else if ((resource_id & 0xC0) >> 6 == 1) {
3856 			printf("AMC slot\n");
3857 		} else if ((resource_id & 0xC0) >> 6 == 2) {
3858 			printf("Backplane\n");
3859 		} else{
3860 			printf("reserved\n");
3861 		}
3862 		printf("   Channel Count: 0x%02x\n", channel_count);
3863 
3864 		for (j = 0; j < channel_count; j++) {
3865 			unsigned char loc_channel;
3866 			unsigned char rem_channel;
3867 			unsigned char rem_resource;
3868 
3869 			loc_channel = record->data[offset++];
3870 			rem_channel = record->data[offset++];
3871 			rem_resource = record->data[offset++];
3872 
3873 			printf("\tCLK-ID: 0x%02x   --->  ", loc_channel);
3874 			printf(" remote CLKID: 0x%02x   ", rem_channel);
3875 			if ((rem_resource & 0xC0) >> 6 == 0) {
3876 				printf("[ Carrier-Dev");
3877 			} else if ((rem_resource & 0xC0) >> 6 == 1) {
3878 				printf("[ AMC slot    ");
3879 			} else if ((rem_resource & 0xC0) >> 6 == 2) {
3880 				printf("[ Backplane    ");
3881 			} else {
3882 				printf("reserved          ");
3883 			}
3884 			printf(" 0x%02x ]\n", rem_resource & 0xF);
3885 		}
3886 	}
3887 	printf("\n");
3888 }
3889 
3890 /**************************************************************************
3891 *
3892 * Function name: ipmi_ek_display_clock_config_record
3893 *
3894 * Description: this function displays clock configuration record.
3895 *
3896 * Restriction: the following codes are copy from ipmi_fru.c with modification
3897 *               in reference to AMC.0 Specification Table 3-35 and Table 3-36
3898 *
3899 * Input: record: a pointer to current record to be displayed
3900 *
3901 * Output: None
3902 *
3903 * Global: START_DATA_OFFSET
3904 *
3905 * Return: None
3906 *
3907 ***************************************************************************/
3908 void
3909 ipmi_ek_display_clock_config_record(struct ipmi_ek_multi_header *record)
3910 {
3911 	unsigned char resource_id;
3912 	unsigned char descr_count;
3913 	int i;
3914 	int offset = START_DATA_OFFSET;
3915 
3916 	resource_id = record->data[offset++];
3917 	descr_count = record->data[offset++];
3918 	printf("   Clock Resource ID: 0x%02x\n", resource_id);
3919 	printf("   Clock Configuration Descriptor Count: 0x%02x\n", descr_count);
3920 
3921 	for (i = 0; i < descr_count; i++) {
3922 		int j = 0;
3923 		unsigned char channel_id;
3924 		unsigned char control;
3925 		unsigned char indirect_cnt;
3926 		unsigned char direct_cnt;
3927 
3928 		channel_id = record->data[offset++];
3929 		control = record->data[offset++];
3930 		printf("\tCLK-ID: 0x%02x  -  ", channel_id);
3931 		printf("CTRL 0x%02x [ %12s ]\n", control,
3932 				((control & 0x1) == 0) ? "Carrier IPMC" : "Application");
3933 
3934 		indirect_cnt = record->data[offset++];
3935 		direct_cnt = record->data[offset++];
3936 		printf("\t   Count: Indirect 0x%02x   / Direct 0x%02x\n",
3937 				indirect_cnt,
3938 				direct_cnt);
3939 
3940 		/* indirect desc */
3941 		for (j = 0; j < indirect_cnt; j++) {
3942 			unsigned char feature;
3943 			unsigned char dep_chn_id;
3944 
3945 			feature = record->data[offset++];
3946 			dep_chn_id = record->data[offset++];
3947 			printf("\t\tFeature: 0x%02x [%8s] - ",
3948 					feature,
3949 					(feature & 0x1) == 1 ? "Source" : "Receiver");
3950 			printf(" Dep. CLK-ID: 0x%02x\n", dep_chn_id);
3951 		}
3952 		/* direct desc */
3953 		for (j = 0; j < direct_cnt; j++) {
3954 			unsigned char feature;
3955 			unsigned char family;
3956 			unsigned char accuracy;
3957 			unsigned long freq;
3958 			unsigned long min_freq;
3959 			unsigned long max_freq;
3960 
3961 			feature = record->data[offset++];
3962 			family = record->data[offset++];
3963 			accuracy = record->data[offset++];
3964 			freq = (record->data[offset+0] << 0)
3965 				| (record->data[offset+1] << 8)
3966 				| (record->data[offset+2] << 16)
3967 				| (record->data[offset+3] << 24);
3968 			offset += 4;
3969 			min_freq = (record->data[offset+0] << 0)
3970 				| (record->data[offset+1] << 8)
3971 				| (record->data[offset+2] << 16)
3972 				| (record->data[offset+3] << 24);
3973 			offset += 4;
3974 			max_freq = (record->data[offset+0] << 0)
3975 				| (record->data[offset+1] << 8)
3976 				| (record->data[offset+2] << 16)
3977 				| (record->data[offset+3] << 24);
3978 			offset += 4;
3979 
3980 			printf("\t- Feature: 0x%02x    - PLL: %x / Asym: %s\n",
3981 					feature,
3982 					(feature > 1) & 1,
3983 					(feature & 1) ? "Source" : "Receiver");
3984 			printf("\tFamily:  0x%02x    - AccLVL: 0x%02x\n",
3985 					family, accuracy);
3986 			printf("\tFRQ: %-9ld - min: %-9ld - max: %-9ld\n",
3987 					freq, min_freq, max_freq);
3988 		}
3989 		printf("\n");
3990 	}
3991 }
3992 
3993 /**************************************************************************
3994 *
3995 * Function name: ipmi_ekanalyzer_fru_file2structure
3996 *
3997 * Description: this function convert a FRU binary file into a linked list of
3998 *              FRU multi record
3999 *
4000 * Restriction: None
4001 *
4002 * Input/Ouput: filename1: name of the file that contain FRU binary data
4003 *        record: a pointer to current record
4004 *        list_head: a pointer to header of the list
4005 *        list_last: a pointer to tale of the list
4006 *
4007 * Global: None
4008 *
4009 * Return: return -1 as Error status, and 0 as Ok status
4010 *
4011 ***************************************************************************/
4012 static int
4013 ipmi_ekanalyzer_fru_file2structure(char *filename,
4014 		struct ipmi_ek_multi_header **list_head,
4015 		struct ipmi_ek_multi_header **list_record,
4016 		struct ipmi_ek_multi_header **list_last)
4017 {
4018 	FILE *input_file;
4019 	unsigned char data;
4020 	unsigned char last_record = 0;
4021 	unsigned int multi_offset = 0;
4022 	int record_count = 0;
4023 	int ret = 0;
4024 
4025 	input_file = fopen(filename, "r");
4026 	if (input_file == NULL) {
4027 		lprintf(LOG_ERR, "File: '%s' is not found", filename);
4028 		return ERROR_STATUS;
4029 	}
4030 
4031 	fseek(input_file, START_DATA_OFFSET, SEEK_SET);
4032 	data = 0;
4033 	ret = fread(&data, 1, 1, input_file);
4034 	if ((ret != 1) || ferror(input_file)) {
4035 		lprintf(LOG_ERR, "Invalid Offset!");
4036 		fclose(input_file);
4037 		return ERROR_STATUS;
4038 	}
4039 	if (data == 0) {
4040 		lprintf(LOG_ERR, "There is no multi record in the file '%s'",
4041 				filename);
4042 		fclose(input_file);
4043 		return ERROR_STATUS;
4044 	}
4045 	/* the offset value is in multiple of 8 bytes. */
4046 	multi_offset = data * 8;
4047 	lprintf(LOG_DEBUG, "start multi offset = 0x%02x",
4048 			multi_offset);
4049 
4050 	fseek(input_file, multi_offset, SEEK_SET);
4051 	while (!feof(input_file)) {
4052 		/* TODO - check malloc() */
4053 		*list_record = malloc(sizeof(struct ipmi_ek_multi_header));
4054 		ret = fread(&(*list_record)->header, START_DATA_OFFSET, 1,
4055 				input_file);
4056 		if ((ret != 1) || ferror(input_file)) {
4057 			/* TODO - no free?! */
4058 			lprintf(LOG_ERR, "Invalid Header!");
4059 			fclose(input_file);
4060 			return ERROR_STATUS;
4061 		}
4062 		if ((*list_record)->header.len == 0) {
4063 			record_count++;
4064 			continue;
4065 		}
4066 		(*list_record)->data = malloc((*list_record)->header.len);
4067 		if ((*list_record)->data == NULL) {
4068 			lprintf(LOG_ERR, "Failed to allocation memory size %d\n",
4069 					(*list_record)->header.len);
4070 			record_count++;
4071 			continue;
4072 		}
4073 
4074 		ret = fread((*list_record)->data, ((*list_record)->header.len),
4075 				1, input_file);
4076 		if ((ret != 1) || ferror(input_file)) {
4077 			lprintf(LOG_ERR, "Invalid Record Data!");
4078 			fclose(input_file);
4079 			return ERROR_STATUS;
4080 		}
4081 		if (verbose > 0)
4082 			printf("Record %d has length = %02x\n", record_count,
4083 					(*list_record)->header.len);
4084 		if (verbose > 1) {
4085 			int i;
4086 			printf("Type: %02x", (*list_record)->header.type);
4087 			for (i = 0; i < ((*list_record)->header.len); i++) {
4088 				if (!(i % 8)) {
4089 					printf("\n0x%02x: ", i);
4090 				}
4091 				printf("%02x ",
4092 					(*list_record)->data[i]);
4093 			}
4094 			printf("\n\n");
4095 		}
4096 		ipmi_ek_add_record2list(list_record, list_head, list_last);
4097 		/* mask the 8th bits to see if it is the last record */
4098 		last_record = ((*list_record)->header.format) & 0x80;
4099 		if (last_record) {
4100 			break;
4101 		}
4102 		record_count++;
4103 	}
4104 	fclose(input_file);
4105 	return OK_STATUS;
4106 }
4107 
4108 /**************************************************************************
4109 *
4110 * Function name: ipmi_ek_add_record2list
4111 *
4112 * Description: this function adds a sigle FRU multi record to a linked list of
4113 *              FRU multi record.
4114 *
4115 * Restriction: None
4116 *
4117 * Input/Output: record: a pointer to current record
4118 *        list_head: a pointer to header of the list
4119 *        list_last: a pointer to tale of the list
4120 *
4121 * Global: None
4122 *
4123 * Return: None
4124 *
4125 ***************************************************************************/
4126 static void
4127 ipmi_ek_add_record2list(struct ipmi_ek_multi_header **record,
4128 		struct ipmi_ek_multi_header **list_head,
4129 		struct ipmi_ek_multi_header **list_last)
4130 {
4131 	if (*list_head == NULL) {
4132 		*list_head = *record;
4133 		(*record)->prev = NULL;
4134 		if (verbose > 2) {
4135 			printf("Adding first record to list\n");
4136 		}
4137 	} else {
4138 		(*list_last)->next = *record;
4139 		(*record)->prev = *list_last;
4140 		if (verbose > 2) {
4141 			printf("Add 1 record to list\n");
4142 		}
4143 	}
4144 	*list_last = *record;
4145 	(*record)->next = NULL;
4146 }
4147 
4148 /**************************************************************************
4149 *
4150 * Function name: ipmi_ek_remove_record_from_list
4151 *
4152 * Description: this function removes a sigle FRU multi record from a linked
4153 *              list of FRU multi record.
4154 *
4155 * Restriction: None
4156 *
4157 * Input/Output: record: a pointer to record to be deleted
4158 *        list_head: a pointer to header of the list
4159 *        list_last: a pointer to tale of the list
4160 *
4161 * Global: None
4162 *
4163 * Return: None
4164 *
4165 ***************************************************************************/
4166 static void
4167 ipmi_ek_remove_record_from_list(struct ipmi_ek_multi_header *record,
4168 		struct ipmi_ek_multi_header **list_head,
4169 		struct ipmi_ek_multi_header **list_last)
4170 {
4171 	if (record->prev == NULL) {
4172 		*list_head = record->next;
4173 	} else {
4174 		record->prev->next = record->next;
4175 	}
4176 	if (record->next == NULL) {
4177 		(*list_last) = record->prev;
4178 	} else {
4179 		record->next->prev = record->prev;
4180 	}
4181 	free(record);
4182 	record = NULL;
4183 }
4184