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