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