xref: /openbmc/ipmitool/lib/ipmi_picmg.c (revision 531569ec)
1 /*
2   Copyright (c) Kontron. All right reserved
3 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * Redistribution of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * Redistribution in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * Neither the name of Kontron, or the names of
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * This software is provided "AS IS," without a warranty of any kind.
20  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23  * DELL COMPUTERS ("DELL") AND ITS LICENSORS SHALL NOT BE LIABLE
24  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26  * DELL OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF DELL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  */
32 
33 
34 #include <ipmitool/ipmi_intf.h>
35 #include <ipmitool/ipmi_picmg.h>
36 #include <ipmitool/ipmi_fru.h>		/* for access to link descriptor defines */
37 #include <ipmitool/ipmi_strings.h>
38 #include <ipmitool/log.h>
39 
40 #define PICMG_EXTENSION_ATCA_MAJOR_VERSION  2
41 #define PICMG_EXTENSION_AMC0_MAJOR_VERSION  4
42 #define PICMG_EXTENSION_UTCA_MAJOR_VERSION  5
43 
44 
45 #define PICMG_EKEY_MODE_QUERY          0
46 #define PICMG_EKEY_MODE_PRINT_ALL      1
47 #define PICMG_EKEY_MODE_PRINT_ENABLED  2
48 #define PICMG_EKEY_MODE_PRINT_DISABLED 3
49 
50 #define PICMG_EKEY_MAX_CHANNEL          16
51 #define PICMG_EKEY_MAX_FABRIC_CHANNEL   15
52 #define PICMG_EKEY_MAX_INTERFACE 3
53 
54 #define PICMG_EKEY_AMC_MAX_CHANNEL  16
55 #define PICMG_EKEY_AMC_MAX_DEVICE   15 /* 4 bits */
56 
57 
58 typedef enum picmg_bused_resource_mode {
59 	PICMG_BUSED_RESOURCE_SUMMARY,
60 } t_picmg_bused_resource_mode ;
61 
62 
63 typedef enum picmg_card_type {
64 	PICMG_CARD_TYPE_CPCI,
65 	PICMG_CARD_TYPE_ATCA,
66 	PICMG_CARD_TYPE_AMC,
67 	PICMG_CARD_TYPE_RESERVED
68 } t_picmg_card_type ;
69 
70 /* This is the version of the PICMG Extenstion */
71 static t_picmg_card_type PicmgCardType = PICMG_CARD_TYPE_RESERVED;
72 
73 void
74 ipmi_picmg_help (void)
75 {
76 	lprintf(LOG_NOTICE, "PICMG commands:");
77 	lprintf(LOG_NOTICE, " properties           - get PICMG properties");
78 	lprintf(LOG_NOTICE, " frucontrol           - FRU control");
79 	lprintf(LOG_NOTICE, " addrinfo             - get address information");
80 	lprintf(LOG_NOTICE, " activate             - activate a FRU");
81 	lprintf(LOG_NOTICE, " deactivate           - deactivate a FRU");
82 	lprintf(LOG_NOTICE, " policy get           - get the FRU activation policy");
83 	lprintf(LOG_NOTICE, " policy set           - set the FRU activation policy");
84 	lprintf(LOG_NOTICE, " portstate get        - get port state");
85 	lprintf(LOG_NOTICE,
86 			" portstate getdenied  - get all denied[disabled] port description");
87 	lprintf(LOG_NOTICE,
88 			" portstate getgranted - get all granted[enabled] port description");
89 	lprintf(LOG_NOTICE,
90 			" portstate getall     - get all port state description");
91 	lprintf(LOG_NOTICE, " portstate set        - set port state");
92 	lprintf(LOG_NOTICE, " amcportstate get     - get port state");
93 	lprintf(LOG_NOTICE, " amcportstate set     - set port state");
94 	lprintf(LOG_NOTICE, " led prop             - get led properties");
95 	lprintf(LOG_NOTICE, " led cap              - get led color capabilities");
96 	lprintf(LOG_NOTICE, " led get              - get led state");
97 	lprintf(LOG_NOTICE, " led set              - set led state");
98 	lprintf(LOG_NOTICE, " power get            - get power level info");
99 	lprintf(LOG_NOTICE, " power set            - set power level");
100 	lprintf(LOG_NOTICE, " clk get              - get clk state");
101 	lprintf(LOG_NOTICE,
102 			" clk getdenied        - get all(up to 16) denied[disabled] clock descriptions");
103 	lprintf(LOG_NOTICE,
104 			" clk getgranted       - get all(up to 16) granted[enabled] clock descriptions");
105 	lprintf(LOG_NOTICE,
106 			" clk getall           - get all(up to 16) clock descriptions");
107 	lprintf(LOG_NOTICE, " clk set              - set clk state");
108 	lprintf(LOG_NOTICE,
109 			" busres summary       - display brief bused resource status info");
110 }
111 
112 
113 struct sAmcAddrMap {
114 	unsigned char ipmbLAddr;
115 	char*         amcBayId;
116 	unsigned char siteNum;
117 } amcAddrMap[] = {
118 	{0xFF, "reserved", 0},
119 	{0x72, "A1"      , 1},
120 	{0x74, "A2"      , 2},
121 	{0x76, "A3"      , 3},
122 	{0x78, "A4"      , 4},
123 	{0x7A, "B1"      , 5},
124 	{0x7C, "B2"      , 6},
125 	{0x7E, "B3"      , 7},
126 	{0x80, "B4"      , 8},
127 	{0x82, "reserved", 0},
128 	{0x84, "reserved", 0},
129 	{0x86, "reserved", 0},
130 	{0x88, "reserved", 0},
131 };
132 
133 /* is_amc_channel - wrapper to convert user input into integer
134  * AMC Channel range seems to be <0..255>, bits [7:0]
135  *
136  * @argv_ptr: source string to convert from; usually argv
137  * @amc_chan_ptr: pointer where to store result
138  * returns: zero on success, other values mean error
139  */
140 int
141 is_amc_channel(const char *argv_ptr, uint8_t *amc_chan_ptr)
142 {
143 	if (!argv_ptr || !amc_chan_ptr) {
144 		lprintf(LOG_ERR, "is_amc_channel(): invalid argument(s).");
145 		return (-1);
146 	}
147 	if (str2uchar(argv_ptr, amc_chan_ptr) == 0) {
148 		return 0;
149 	}
150 	lprintf(LOG_ERR, "Given AMC Channel '%s' is invalid.", argv_ptr);
151 	return (-1);
152 }
153 /* is_amc_dev - wrapper to convert user input into integer.
154  * AMC Dev ID limits are uknown.
155  *
156  * @argv_ptr: source string to convert from; usually argv
157  * @amc_dev_ptr: pointer where to store result
158  * returns: zero on success, other values mean error
159  */
160 int
161 is_amc_dev(const char *argv_ptr, int32_t *amc_dev_ptr)
162 {
163 	if (!argv_ptr || !amc_dev_ptr) {
164 		lprintf(LOG_ERR, "is_amc_dev(): invalid argument(s).");
165 		return (-1);
166 	}
167 	if (str2int(argv_ptr, amc_dev_ptr) == 0 && *amc_dev_ptr >= 0) {
168 		return 0;
169 	}
170 	lprintf(LOG_ERR, "Given PICMG Device '%s' is invalid.",
171 			argv_ptr);
172 	return (-1);
173 }
174 /* is_amc_intf - wrapper to convert user input into integer.
175  * AMC Interface (ID) limits are uknown.
176  *
177  * @argv_ptr: source string to convert from; usually argv
178  * @amc_intf_ptr: pointer where to store result
179  * returns: zero on success, other values mean error
180  */
181 int
182 is_amc_intf(const char *argv_ptr, int32_t *amc_intf_ptr)
183 {
184 	if (!argv_ptr || !amc_intf_ptr) {
185 		lprintf(LOG_ERR, "is_amc_intf(): invalid argument(s).");
186 		return (-1);
187 	}
188 	if (str2int(argv_ptr, amc_intf_ptr) == 0 && *amc_intf_ptr >= 0) {
189 		return 0;
190 	}
191 	lprintf(LOG_ERR, "Given PICMG Interface '%s' is invalid.",
192 			argv_ptr);
193 	return (-1);
194 }
195 /* is_amc_port - wrapper to convert user input into integer.
196  * AMC Port limits are uknown.
197  *
198  * @argv_ptr: source string to convert from; usually argv
199  * @amc_port_ptr: pointer where to store result
200  * returns: zero on success, other values mean error
201  */
202 int
203 is_amc_port(const char *argv_ptr, int32_t *amc_port_ptr)
204 {
205 	if (!argv_ptr || !amc_port_ptr) {
206 		lprintf(LOG_ERR, "is_amc_port(): invalid argument(s).");
207 		return (-1);
208 	}
209 	if (str2int(argv_ptr, amc_port_ptr) == 0 && *amc_port_ptr >= 0) {
210 		return 0;
211 	}
212 	lprintf(LOG_ERR, "Given PICMG Port '%s' is invalid.", argv_ptr);
213 	return (-1);
214 }
215 /* is_clk_acc - wrapper to convert user input into integer.
216  * Clock Accuracy limits are uknown[1byte by spec].
217  *
218  * @argv_ptr: source string to convert from; usually argv
219  * @clk_acc_ptr: pointer where to store result
220  * returns: zero on success, other values mean error
221  */
222 int
223 is_clk_acc(const char *argv_ptr, uint8_t *clk_acc_ptr)
224 {
225 	if (!argv_ptr || !clk_acc_ptr) {
226 		lprintf(LOG_ERR, "is_clk_acc(): invalid argument(s).");
227 		return (-1);
228 	}
229 	if (str2uchar(argv_ptr, clk_acc_ptr) == 0) {
230 		return 0;
231 	}
232 	lprintf(LOG_ERR, "Given Clock Accuracy '%s' is invalid.",
233 			argv_ptr);
234 	return (-1);
235 }
236 /* is_clk_family - wrapper to convert user input into integer.
237  * Clock Family limits are uknown[1byte by spec].
238  *
239  * @argv_ptr: source string to convert from; usually argv
240  * @clk_family_ptr: pointer where to store result
241  * returns: zero on success, other values mean error
242  */
243 int
244 is_clk_family(const char *argv_ptr, uint8_t *clk_family_ptr)
245 {
246 	if (!argv_ptr || !clk_family_ptr) {
247 		lprintf(LOG_ERR, "is_clk_family(): invalid argument(s).");
248 		return (-1);
249 	}
250 	if (str2uchar(argv_ptr, clk_family_ptr) == 0) {
251 		return 0;
252 	}
253 	lprintf(LOG_ERR, "Given Clock Family '%s' is invalid.",
254 			argv_ptr);
255 	return (-1);
256 }
257 /* is_clk_freq - wrapper to convert user input into integer.
258  * Clock Frequency limits are uknown, but specification says
259  * 3Bytes + 1B checksum
260  *
261  * @argv_ptr: source string to convert from; usually argv
262  * @clk_freq_ptr: pointer where to store result
263  * returns: zero on success, other values mean error
264  */
265 int
266 is_clk_freq(const char *argv_ptr, uint32_t *clk_freq_ptr)
267 {
268 	if (!argv_ptr || !clk_freq_ptr) {
269 		lprintf(LOG_ERR, "is_clk_freq(): invalid argument(s).");
270 		return (-1);
271 	}
272 	if (str2uint(argv_ptr, clk_freq_ptr) == 0) {
273 		return 0;
274 	}
275 	lprintf(LOG_ERR, "Given Clock Frequency '%s' is invalid.",
276 			argv_ptr);
277 	return (-1);
278 }
279 /* is_clk_id - wrapper to convert user input into integer.
280  * Clock ID limits are uknown, however it's 1B by specification and I've
281  * found two ranges: <1..5> or <0..15>
282  *
283  * @argv_ptr: source string to convert from; usually argv
284  * @clk_id_ptr: pointer where to store result
285  * returns: zero on success, other values mean error
286  */
287 int
288 is_clk_id(const char *argv_ptr, uint8_t *clk_id_ptr)
289 {
290 	if (!argv_ptr || !clk_id_ptr) {
291 		lprintf(LOG_ERR, "is_clk_id(): invalid argument(s).");
292 		return (-1);
293 	}
294 	if (str2uchar(argv_ptr, clk_id_ptr) == 0) {
295 		return 0;
296 	}
297 	lprintf(LOG_ERR, "Given Clock ID '%s' is invalid.", argv_ptr);
298 	return (-1);
299 }
300 /* is_clk_index - wrapper to convert user input into integer.
301  * Clock Index limits are uknown[1B by spec]
302  *
303  * @argv_ptr: source string to convert from; usually argv
304  * @clk_index_ptr: pointer where to store result
305  * returns: zero on success, other values mean error
306  */
307 int
308 is_clk_index(const char *argv_ptr, uint8_t *clk_index_ptr)
309 {
310 	if (!argv_ptr || !clk_index_ptr) {
311 		lprintf(LOG_ERR, "is_clk_index(): invalid argument(s).");
312 		return (-1);
313 	}
314 	if (str2uchar(argv_ptr, clk_index_ptr) == 0) {
315 		return 0;
316 	}
317 	lprintf(LOG_ERR, "Given Clock Index '%s' is invalid.", argv_ptr);
318 	return (-1);
319 }
320 /* is_clk_resid - wrapper to convert user input into integer.
321  * Clock Resource Index(?) limits are uknown, but maximum seems to be 15.
322  *
323  * @argv_ptr: source string to convert from; usually argv
324  * @clk_resid_ptr: pointer where to store result
325  * returns: zero on success, other values mean error
326  */
327 int
328 is_clk_resid(const char *argv_ptr, int8_t *clk_resid_ptr)
329 {
330 	if (!argv_ptr || !clk_resid_ptr) {
331 		lprintf(LOG_ERR, "is_clk_resid(): invalid argument(s).");
332 		return (-1);
333 	}
334 	if (str2char(argv_ptr, clk_resid_ptr) == 0
335 			&& *clk_resid_ptr > (-1)) {
336 		return 0;
337 	}
338 	lprintf(LOG_ERR, "Given Resource ID '%s' is invalid.",
339 			clk_resid_ptr);
340 	return (-1);
341 }
342 /* is_clk_setting - wrapper to convert user input into integer.
343  * Clock Setting is a 1B bitfield:
344  * x [7:4] - reserved
345  * x [3] - state - 0/1
346  * x [2] - direction - 0/1
347  * x [1:0] - PLL ctrl - 00/01/10/11[Reserved]
348  *
349  * @argv_ptr: source string to convert from; usually argv
350  * @clk_setting_ptr: pointer where to store result
351  * returns: zero on success, other values mean error
352  */
353 int
354 is_clk_setting(const char *argv_ptr, uint8_t *clk_setting_ptr)
355 {
356 	if (!argv_ptr || !clk_setting_ptr) {
357 		lprintf(LOG_ERR, "is_clk_setting(): invalid argument(s).");
358 		return (-1);
359 	}
360 	if (str2uchar(argv_ptr, clk_setting_ptr) == 0) {
361 		return 0;
362 	}
363 	/* FIXME - validate bits 4-7 are 0 ? */
364 	lprintf(LOG_ERR, "Given Clock Setting '%s' is invalid.", argv_ptr);
365 	return (-1);
366 }
367 /* is_enable - wrapper to convert user input into integer.
368  * Valid input range for Enable is <0..1>.
369  *
370  * @argv_ptr: source string to convert from; usually argv
371  * @enable_ptr: pointer where to store result
372  * returns: zero on success, other values mean error
373  */
374 int
375 is_enable(const char *argv_ptr, uint8_t *enable_ptr)
376 {
377 	if (!argv_ptr || !enable_ptr) {
378 		lprintf(LOG_ERR, "is_enable(): invalid argument(s).");
379 		return (-1);
380 	}
381 	if (str2uchar(argv_ptr, enable_ptr) == 0
382 			&& (*enable_ptr == 0 || *enable_ptr == 1)) {
383 		return 0;
384 	}
385 	lprintf(LOG_ERR, "Given Enable '%s' is invalid.", argv_ptr);
386 	return (-1);
387 }
388 /* is_enable - wrapper to convert user input into integer.
389  * LED colors:
390  * - valid <1..6>, <0xE..0xF>
391  * - reserved [0, 7]
392  * - undefined <8..D>
393  *
394  * @argv_ptr: source string to convert from; usually argv
395  * @enable_ptr: pointer where to store result
396  * returns: zero on success, other values mean error
397  */
398 int
399 is_led_color(const char *argv_ptr, uint8_t *led_color_ptr)
400 {
401 	if (!argv_ptr || !led_color_ptr) {
402 		lprintf(LOG_ERR, "is_led_color(): invalid argument(s).");
403 		return (-1);
404 	}
405 	if (str2uchar(argv_ptr, led_color_ptr) != 0) {
406 		lprintf(LOG_ERR, "Given LED Color '%s' is invalid.",
407 				argv_ptr);
408 		lprintf(LOG_ERR,
409 				"LED Color must be from ranges: <1..6>, <0xE..0xF>");
410 		return (-1);
411 	}
412 	if ((*led_color_ptr >= 1 && *led_color_ptr <= 6)
413 			|| (*led_color_ptr >= 0xE && *led_color_ptr <= 0xF)) {
414 		return 0;
415 	}
416 	lprintf(LOG_ERR, "Given LED Color '%s' is out of range.", argv_ptr);
417 	lprintf(LOG_ERR, "LED Color must be from ranges: <1..6>, <0xE..0xF>");
418 	return (-1);
419 }
420 /* is_led_duration - wrapper to convert user input into integer.
421  * LED duration range is <1..127>
422  *
423  * @argv_ptr: source string to convert from; usually argv
424  * @enable_ptr: pointer where to store result
425  * returns: zero on success, other values mean error
426  */
427 int
428 is_led_duration(const char *argv_ptr, uint8_t *led_duration_ptr)
429 {
430 	if (!argv_ptr || !led_duration_ptr) {
431 		lprintf(LOG_ERR, "is_led_duration(): invalid argument(s).");
432 		return (-1);
433 	}
434 	if (str2uchar(argv_ptr, led_duration_ptr) == 0
435 			&& *led_duration_ptr > 0 && *led_duration_ptr <= 127) {
436 		return 0;
437 	}
438 	lprintf(LOG_ERR, "Given LED Duration '%s' is invalid", argv_ptr);
439 	return (-1);
440 }
441 /* is_led_function - wrapper to convert user input into integer.
442  * LED functions, however, might differ by OEM:
443  * - 0x00 - off override
444  * - <0x01..0xFA> - blinking override
445  * - 0xFB - lamp test state
446  * - 0xFC - state restored to local ctrl state
447  * - <0xFD..0xFE> - reserved
448  * - 0xFF - on override
449  *
450  * @argv_ptr: source string to convert from; usually argv
451  * @led_fn_ptr: pointer where to store result
452  * returns: zero on success, other values mean error
453  */
454 int
455 is_led_function(const char *argv_ptr, uint8_t *led_fn_ptr)
456 {
457 	if (!argv_ptr || !led_fn_ptr) {
458 		lprintf(LOG_ERR, "is_led_function(): invalid argument(s).");
459 		return (-1);
460 	}
461 	if (str2uchar(argv_ptr, led_fn_ptr) == 0
462 			&& (*led_fn_ptr < 0xFD || *led_fn_ptr > 0xFE)) {
463 		return 0;
464 	}
465 	lprintf(LOG_ERR, "Given LED Function '%s' is invalid.", argv_ptr);
466 	return (-1);
467 }
468 /* is_led_id - wrapper to convert user input into integer.
469  * LED ID range seems to be <0..255>
470  *
471  * @argv_ptr: source string to convert from; usually argv
472  * @led_id_ptr: pointer where to store result
473  * returns: zero on success, other values mean error
474  */
475 int
476 is_led_id(const char *argv_ptr, uint8_t *led_id_ptr)
477 {
478 	if (!argv_ptr || !led_id_ptr) {
479 		lprintf(LOG_ERR, "is_led_id(): invalid argument(s).");
480 		return (-1);
481 	}
482 	if (str2uchar(argv_ptr, led_id_ptr) == 0) {
483 		return 0;
484 	}
485 	lprintf(LOG_ERR, "Given LED ID '%s' is invalid.", argv_ptr);
486 	return (-1);
487 }
488 /* is_link_group - wrapper to convert user input into integer.
489  * Link Grouping ID limis are unknown, bits [31:24] by spec.
490  *
491  * @argv_ptr: source string to convert from; usually argv
492  * @link_grp_ptr: pointer where to store result
493  * returns: zero on success, other values mean error
494  */
495 int
496 is_link_group(const char *argv_ptr, uint8_t *link_grp_ptr)
497 {
498 	if (!argv_ptr || !link_grp_ptr) {
499 		lprintf(LOG_ERR, "is_link_group(): invalid argument(s).");
500 		return (-1);
501 	}
502 	if (str2uchar(argv_ptr, link_grp_ptr) == 0) {
503 		return 0;
504 	}
505 	lprintf(LOG_ERR, "Given Link Group '%s' is invalid.", argv_ptr);
506 	return (-1);
507 }
508 /* is_link_type - wrapper to convert user input into integer.
509  * Link Type limits are unknown, bits [19:12]
510  *
511  * @argv_ptr: source string to convert from; usually argv
512  * @link_type_ptr: pointer where to store result
513  * returns: zero on success, other values mean error
514  */
515 int
516 is_link_type(const char *argv_ptr, uint8_t *link_type_ptr)
517 {
518 	if (!argv_ptr || !link_type_ptr) {
519 		lprintf(LOG_ERR, "is_link_type(): invalid argument(s).");
520 		return (-1);
521 	}
522 	if (str2uchar(argv_ptr, link_type_ptr) == 0) {
523 		return 0;
524 	}
525 	lprintf(LOG_ERR, "Given Link Type '%s' is invalid.", argv_ptr);
526 	return (-1);
527 }
528 /* is_link_type_ext - wrapper to convert user input into integer.
529  * Link Type Extension limits are unknown, bits [23:20] => <0..15> ?
530  *
531  * @argv_ptr: source string to convert from; usually argv
532  * @link_type_ext_ptr: pointer where to store result
533  * returns: zero on success, other values mean error
534  */
535 int
536 is_link_type_ext(const char *argv_ptr, uint8_t *link_type_ext_ptr)
537 {
538 	if (!argv_ptr || !link_type_ext_ptr) {
539 		lprintf(LOG_ERR, "is_link_type_ext(): invalid argument(s).");
540 		return (-1);
541 	}
542 	if (str2uchar(argv_ptr, link_type_ext_ptr) != 0
543 			|| *link_type_ext_ptr > 15) {
544 		lprintf(LOG_ERR,
545 				"Given Link Type Extension '%s' is invalid.",
546 				argv_ptr);
547 		return (-1);
548 	}
549 	return 0;
550 }
551 
552 int
553 ipmi_picmg_getaddr(struct ipmi_intf * intf, int argc, char ** argv)
554 {
555 	struct ipmi_rs * rsp;
556 	struct ipmi_rq req;
557 	unsigned char msg_data[5];
558 
559 	memset(&req, 0, sizeof(req));
560 	req.msg.netfn = IPMI_NETFN_PICMG;
561 	req.msg.cmd = PICMG_GET_ADDRESS_INFO_CMD;
562 	req.msg.data = msg_data;
563 	req.msg.data_len = 2;
564 	msg_data[0] = 0;   /* picmg identifier */
565 	msg_data[1] = 0;   /* default fru id */
566 
567 	if(argc > 0) {
568 		if (is_fru_id(argv[0], &msg_data[1]) != 0) {
569 			return (-1);
570 		}
571 	}
572 
573 	rsp = intf->sendrecv(intf, &req);
574 	if (!rsp) {
575 		lprintf(LOG_ERR, "Error. No valid response received.");
576 		return (-1);
577 	} else if (rsp->ccode) {
578 		lprintf(LOG_ERR, "Error getting address information CC: 0x%02x",
579 				rsp->ccode);
580 		return (-1);
581 	}
582 
583 	printf("Hardware Address : 0x%02x\n", rsp->data[1]);
584 	printf("IPMB-0 Address   : 0x%02x\n", rsp->data[2]);
585 	printf("FRU ID           : 0x%02x\n", rsp->data[4]);
586 	printf("Site ID          : 0x%02x\n", rsp->data[5]);
587 
588 	printf("Site Type        : ");
589 	switch (rsp->data[6]) {
590 	case PICMG_ATCA_BOARD:
591 		printf("ATCA board\n");
592 		break;
593 	case PICMG_POWER_ENTRY:
594 		printf("Power Entry Module\n");
595 		break;
596 	case PICMG_SHELF_FRU:
597 		printf("Shelf FRU\n");
598 		break;
599 	case PICMG_DEDICATED_SHMC:
600 		printf("Dedicated Shelf Manager\n");
601 		break;
602 	case PICMG_FAN_TRAY:
603 		printf("Fan Tray\n");
604 		break;
605 	case PICMG_FAN_FILTER_TRAY:
606 		printf("Fan Filter Tray\n");
607 		break;
608 	case PICMG_ALARM:
609 		printf("Alarm module\n");
610 		break;
611 	case PICMG_AMC:
612 		printf("AMC");
613 		printf("  -> IPMB-L Address: 0x%02x\n", amcAddrMap[rsp->data[5]].ipmbLAddr);
614 		break;
615 	case PICMG_PMC:
616 		printf("PMC\n");
617 		break;
618 	 case PICMG_RTM:
619 		printf("RTM\n");
620 		break;
621 	default:
622 		if (rsp->data[6] >= 0xc0 && rsp->data[6] <= 0xcf) {
623 			printf("OEM\n");
624 		} else {
625 			printf("unknown\n");
626 		}
627 	}
628 
629 	return 0;
630 }
631 
632 int
633 ipmi_picmg_properties(struct ipmi_intf * intf, int show )
634 {
635 	unsigned char PicmgExtMajorVersion;
636 	struct ipmi_rs * rsp;
637 	struct ipmi_rq req;
638 	unsigned char msg_data;
639 
640 	memset(&req, 0, sizeof(req));
641 	req.msg.netfn    = IPMI_NETFN_PICMG;
642 	req.msg.cmd      = PICMG_GET_PICMG_PROPERTIES_CMD;
643 	req.msg.data     = &msg_data;
644 	req.msg.data_len = 1;
645 	msg_data = 0;
646 
647 	rsp = intf->sendrecv(intf, &req);
648 	if (!rsp  || rsp->ccode) {
649 		lprintf(LOG_ERR, "Error getting address information.");
650 		return -1;
651 	}
652 
653 	if( show )
654 	{
655 		printf("PICMG identifier	: 0x%02x\n", rsp->data[0]);
656 		printf("PICMG Ext. Version : %i.%i\n",	 rsp->data[1]&0x0f,
657 															 (rsp->data[1]&0xf0) >> 4);
658 		printf("Max FRU Device ID	: 0x%02x\n", rsp->data[2]);
659 		printf("FRU Device ID		: 0x%02x\n", rsp->data[3]);
660 	}
661 
662    /* We cache the major extension version ...
663       to know how to format some commands */
664 	PicmgExtMajorVersion = rsp->data[1]&0x0f;
665 
666 	if( PicmgExtMajorVersion == PICMG_CPCI_MAJOR_VERSION  ) {
667 		PicmgCardType = PICMG_CARD_TYPE_CPCI;
668    }
669 	else if(  PicmgExtMajorVersion == PICMG_ATCA_MAJOR_VERSION) {
670 		PicmgCardType = PICMG_CARD_TYPE_ATCA;
671    }
672 	else if(  PicmgExtMajorVersion == PICMG_AMC_MAJOR_VERSION) {
673 		PicmgCardType = PICMG_CARD_TYPE_AMC;
674    }
675 
676 	return 0;
677 }
678 
679 
680 
681 #define PICMG_FRU_DEACTIVATE	(unsigned char) 0x00
682 #define PICMG_FRU_ACTIVATE	(unsigned char) 0x01
683 
684 int
685 ipmi_picmg_fru_activation(struct ipmi_intf * intf, int argc, char ** argv, unsigned char state)
686 {
687 	struct ipmi_rs * rsp;
688 	struct ipmi_rq req;
689 
690 	struct picmg_set_fru_activation_cmd cmd;
691 
692 	memset(&req, 0, sizeof(req));
693 	req.msg.netfn    = IPMI_NETFN_PICMG;
694 	req.msg.cmd      = PICMG_FRU_ACTIVATION_CMD;
695 	req.msg.data     = (unsigned char*) &cmd;
696 	req.msg.data_len = 3;
697 
698 	cmd.picmg_id  = 0;						/* PICMG identifier */
699 	if (is_fru_id(argv[0], &(cmd.fru_id)) != 0) {
700 		return (-1);
701 	}
702 	cmd.fru_state = state;
703 
704 	rsp = intf->sendrecv(intf, &req);
705 
706 	if (!rsp  || rsp->ccode) {
707 		lprintf(LOG_ERR, "Error activation/deactivation of FRU.");
708 		return -1;
709 	}
710 	if (rsp->data[0] != 0x00) {
711 		lprintf(LOG_ERR, "Error activation/deactivation of FRU.");
712 	}
713 
714 	return 0;
715 }
716 
717 
718 int
719 ipmi_picmg_fru_activation_policy_get(struct ipmi_intf * intf, int argc, char ** argv)
720 {
721 	struct ipmi_rs * rsp;
722 	struct ipmi_rq req;
723 
724 	unsigned char msg_data[4];
725 
726 	memset(&req, 0, sizeof(req));
727 	req.msg.netfn    = IPMI_NETFN_PICMG;
728 	req.msg.cmd      = PICMG_GET_FRU_POLICY_CMD;
729 	req.msg.data     = msg_data;
730 	req.msg.data_len = 2;
731 
732 	msg_data[0] = 0;								/* PICMG identifier */
733 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {
734 		return (-1);
735 	}
736 
737 	rsp = intf->sendrecv(intf, &req);
738 
739 	if (!rsp) {
740 		lprintf(LOG_ERR, "No valid response received.");
741 		return -1;
742 	}
743 	if (rsp->ccode) {
744 		lprintf(LOG_ERR, "FRU activation policy get failed with CC code 0x%02x",
745 				rsp->ccode);
746 		return -1;
747 	}
748 
749 	printf(" %s\n", ((rsp->data[1] & 0x01) == 0x01) ?
750 	                           "activation locked" : "activation not locked");
751 	printf(" %s\n", ((rsp->data[1] & 0x02) == 0x02) ?
752 	                            "deactivation locked" : "deactivation not locked");
753 
754 	return 0;
755 }
756 
757 int
758 ipmi_picmg_fru_activation_policy_set(struct ipmi_intf * intf, int argc, char ** argv)
759 {
760 	struct ipmi_rs * rsp;
761 	struct ipmi_rq req;
762 
763 	unsigned char msg_data[4];
764 
765 	memset(&req, 0, sizeof(req));
766 	req.msg.netfn    = IPMI_NETFN_PICMG;
767 	req.msg.cmd      = PICMG_SET_FRU_POLICY_CMD;
768 	req.msg.data     = msg_data;
769 	req.msg.data_len = 4;
770 
771 	msg_data[0] = 0;								            /* PICMG identifier */
772 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {
773 		return (-1);
774 	}
775 	if (str2uchar(argv[1], &msg_data[2]) != 0 || msg_data[2] > 1) {
776 		/* FRU Lock Mask */
777 		lprintf(LOG_ERR, "Given FRU Lock Mask '%s' is invalid.",
778 				argv[1]);
779 		return (-1);
780 	}
781 	if (str2uchar(argv[2], &msg_data[3]) != 0 || msg_data[3] > 1) {
782 		/* FRU Act Policy */
783 		lprintf(LOG_ERR,
784 				"Given FRU Activation Policy '%s' is invalid.",
785 				argv[2]);
786 		return (-1);
787 	}
788 	msg_data[2]&= 0x03;
789 	msg_data[3]&= 0x03;
790 
791 	rsp = intf->sendrecv(intf, &req);
792 
793 	if (!rsp) {
794 		lprintf(LOG_ERR, "No valid response received.");
795 		return -1;
796 	}
797 
798 	if (rsp->ccode) {
799 		lprintf(LOG_ERR, "FRU activation policy set failed with CC code 0x%02x",
800 				rsp->ccode);
801 		return -1;
802 	}
803 
804 	return 0;
805 }
806 
807 #define PICMG_MAX_LINK_PER_CHANNEL 4
808 
809 int
810 ipmi_picmg_portstate_get(struct ipmi_intf * intf, int32_t interface,
811 		uint8_t channel, int mode)
812 {
813 	struct ipmi_rs * rsp = NULL;
814 	struct ipmi_rq req;
815 
816 	unsigned char msg_data[4];
817 
818 	struct fru_picmgext_link_desc* d; /* descriptor pointer for rec. data */
819 
820 	memset(&req, 0, sizeof(req));
821 
822 	req.msg.netfn    = IPMI_NETFN_PICMG;
823 	req.msg.cmd      = PICMG_GET_PORT_STATE_CMD;
824 	req.msg.data     = msg_data;
825 	req.msg.data_len = 2;
826 
827 	msg_data[0] = 0x00;						/* PICMG identifier */
828 	msg_data[1] = (interface & 0x3)<<6;	/* interface      */
829 	msg_data[1] |= (channel & 0x3F);	/* channel number */
830 
831 	rsp = intf->sendrecv(intf, &req);
832 
833 	if (!rsp) {
834 		lprintf(LOG_ERR, "No valid response received.");
835 		return -1;
836 	}
837 
838 	if (rsp->ccode) {
839 		if( mode == PICMG_EKEY_MODE_QUERY ){
840 			lprintf(LOG_ERR, "FRU portstate get failed with CC code 0x%02x",
841 					rsp->ccode);
842 		}
843 		return -1;
844 	}
845 
846 	if (rsp->data_len >= 6) {
847 		int index;
848 		/* add support for more than one link per channel */
849 		for(index=0;index<PICMG_MAX_LINK_PER_CHANNEL;index++){
850 			if( rsp->data_len > (1+ (index*5))){
851 				d = (struct fru_picmgext_link_desc *) &(rsp->data[1 + (index*5)]);
852 
853 				if
854 				(
855 					mode == PICMG_EKEY_MODE_PRINT_ALL
856 					||
857 					mode == PICMG_EKEY_MODE_QUERY
858 					||
859 					(
860 						mode == PICMG_EKEY_MODE_PRINT_ENABLED
861 						&&
862 						rsp->data[5 + (index*5) ] == 0x01
863 					)
864 					||
865 					(
866 						mode == PICMG_EKEY_MODE_PRINT_DISABLED
867 						&&
868 						rsp->data[5 + (index*5) ] == 0x00
869 					)
870 				)
871 				{
872 					printf("      Link Grouping ID:     0x%02x\n", d->grouping);
873 					printf("      Link Type Extension:  0x%02x\n", d->ext);
874 					printf("      Link Type:            0x%02x  ", d->type);
875 					if (d->type == 0 || d->type == 0xff)
876 					{
877 						printf("Reserved %d\n",d->type);
878 					}
879 					else if (d->type >= 0x06 && d->type <= 0xef)
880 					{
881 						printf("Reserved\n");
882 					}
883 					else if (d->type >= 0xf0 && d->type <= 0xfe)
884 					{
885 						printf("OEM GUID Definition\n");
886 					}
887 					else
888 					{
889 						switch (d->type)
890 						{
891 							case FRU_PICMGEXT_LINK_TYPE_BASE:
892 								printf("PICMG 3.0 Base Interface 10/100/1000\n");
893 							break;
894 							case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET:
895 								printf("PICMG 3.1 Ethernet Fabric Interface\n");
896 							break;
897 							case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND:
898 								printf("PICMG 3.2 Infiniband Fabric Interface\n");
899 							break;
900 							case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR:
901 								printf("PICMG 3.3 Star Fabric Interface\n");
902 							break;
903 							case  FRU_PICMGEXT_LINK_TYPE_PCIE:
904 								printf("PCI Express Fabric Interface\n");
905 							break;
906 							default:
907 							printf("Invalid\n");
908 							break;
909 						}
910 					}
911 					printf("      Link Designator: \n");
912 					printf("        Port Flag:          0x%02x\n", d->desig_port);
913 					printf("        Interface:          0x%02x - ", d->desig_if);
914 					switch (d->desig_if)
915 					{
916 						case FRU_PICMGEXT_DESIGN_IF_BASE:
917 							printf("Base Interface\n");
918 						break;
919 						case FRU_PICMGEXT_DESIGN_IF_FABRIC:
920 							printf("Fabric Interface\n");
921 						break;
922 						case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL:
923 							printf("Update Channel\n");
924 						break;
925 						case FRU_PICMGEXT_DESIGN_IF_RESERVED:
926 							printf("Reserved\n");
927 						break;
928 						default:
929 							printf("Invalid");
930 						break;
931 					}
932 					printf("        Channel Number:     0x%02x\n", d->desig_channel);
933 					printf("      STATE:                %s\n",
934 							( rsp->data[5 +(index*5)] == 0x01) ?"enabled":"disabled");
935 					printf("\n");
936 				}
937 			}
938 		}
939 	}
940 	else
941 	{
942 		lprintf(LOG_ERR, "Unexpected answer, can't print result.");
943 	}
944 
945 	return 0;
946 }
947 
948 
949 int
950 ipmi_picmg_portstate_set(struct ipmi_intf * intf, int32_t interface,
951 		uint8_t channel, int32_t port, uint8_t type,
952 		uint8_t typeext, uint8_t group, uint8_t enable)
953 {
954 	struct ipmi_rs * rsp;
955 	struct ipmi_rq req;
956 
957 	unsigned char msg_data[6];
958 
959 	memset(&req, 0, sizeof(req));
960 
961 	req.msg.netfn    = IPMI_NETFN_PICMG;
962 	req.msg.cmd      = PICMG_SET_PORT_STATE_CMD;
963 	req.msg.data     = msg_data;
964 	req.msg.data_len = 6;
965 
966 	msg_data[0] = 0x00;												/* PICMG identifier */
967 	msg_data[1] = (channel & 0x3f) | ((interface & 3) << 6);
968 	msg_data[2] = (port & 0xf) | ((type & 0xf) << 4);
969 	msg_data[3] = ((type >> 4) & 0xf) | ((typeext & 0xf) << 4);
970 	msg_data[4] = group & 0xff;
971 	msg_data[5] = (enable & 0x01); /* enable/disable */
972 
973 	rsp = intf->sendrecv(intf, &req);
974 
975 	if (!rsp) {
976 		lprintf(LOG_ERR, "No valid response received.");
977 		return -1;
978 	}
979 
980 	if (rsp->ccode) {
981 		lprintf(LOG_ERR, "Picmg portstate set failed with CC code 0x%02x",
982 				rsp->ccode);
983 		return -1;
984 	}
985 
986 	return 0;
987 }
988 
989 
990 
991 /* AMC.0 commands */
992 
993 #define PICMG_AMC_MAX_LINK_PER_CHANNEL 4
994 
995 int
996 ipmi_picmg_amc_portstate_get(struct ipmi_intf * intf, int32_t device,
997 		uint8_t channel, int mode)
998 {
999 	struct ipmi_rs * rsp;
1000 	struct ipmi_rq req;
1001 
1002 	unsigned char msg_data[4];
1003 
1004 	struct fru_picmgext_amc_link_info* d; /* descriptor pointer for rec. data */
1005 
1006 	memset(&req, 0, sizeof(req));
1007 
1008 	req.msg.netfn	  = IPMI_NETFN_PICMG;
1009 	req.msg.cmd		  = PICMG_AMC_GET_PORT_STATE_CMD;
1010 	req.msg.data	  = msg_data;
1011 
1012 	/* FIXME : add check for AMC or carrier device */
1013 	if(device == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){
1014 		req.msg.data_len = 2;	/* for amc only channel */
1015 	}else{
1016 		req.msg.data_len = 3;	/* for carrier channel and device */
1017 	}
1018 
1019 	msg_data[0] = 0x00;						/* PICMG identifier */
1020 	msg_data[1] = channel ;
1021 	msg_data[2] = device ;
1022 
1023 
1024 	rsp = intf->sendrecv(intf, &req);
1025 
1026 	if (!rsp) {
1027 		lprintf(LOG_ERR, "No valid response received.");
1028 		return -1;
1029 	}
1030 
1031 	if (rsp->ccode) {
1032 		if( mode == PICMG_EKEY_MODE_QUERY ){
1033 			lprintf(LOG_ERR, "Amc portstate get failed with CC code 0x%02x",
1034 					rsp->ccode);
1035 		}
1036 		return -1;
1037 	}
1038 
1039 	if (rsp->data_len >= 5) {
1040 		int index;
1041 
1042 		/* add support for more than one link per channel */
1043 		for(index=0;index<PICMG_AMC_MAX_LINK_PER_CHANNEL;index++){
1044 
1045 			if( rsp->data_len > (1+ (index*4))){
1046 				unsigned char type;
1047 				unsigned char ext;
1048 				unsigned char grouping;
1049 				unsigned char port;
1050 				unsigned char enabled;
1051 				d = (struct fru_picmgext_amc_link_info *)&(rsp->data[1 + (index*4)]);
1052 
1053 
1054 				/* Removed endianness check here, probably not required
1055 					as we dont use bitfields  */
1056 				port = d->linkInfo[0] & 0x0F;
1057 				type = ((d->linkInfo[0] & 0xF0) >> 4 )|(d->linkInfo[1] & 0x0F );
1058 				ext  = ((d->linkInfo[1] & 0xF0) >> 4 );
1059 				grouping = d->linkInfo[2];
1060 
1061 
1062 				enabled =  rsp->data[4 + (index*4) ];
1063 
1064 				if
1065 				(
1066 					mode == PICMG_EKEY_MODE_PRINT_ALL
1067 					||
1068 					mode == PICMG_EKEY_MODE_QUERY
1069 					||
1070 					(
1071 						mode == PICMG_EKEY_MODE_PRINT_ENABLED
1072 						&&
1073 						enabled == 0x01
1074 					)
1075 					||
1076 					(
1077 						mode == PICMG_EKEY_MODE_PRINT_DISABLED
1078 						&&
1079 						enabled	== 0x00
1080 					)
1081 				)
1082 				{
1083 					if(device == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){
1084 						printf("   Link device :         AMC\n");
1085 					}else{
1086                   printf("   Link device :         0x%02x\n", device );
1087 					}
1088 
1089 					printf("   Link Grouping ID:     0x%02x\n", grouping);
1090 
1091 					if (type == 0 || type == 1 ||type == 0xff)
1092 					{
1093 						printf("   Link Type Extension:  0x%02x\n", ext);
1094 						printf("   Link Type:            Reserved\n");
1095 					}
1096 					else if (type >= 0xf0 && type <= 0xfe)
1097 					{
1098 						printf("   Link Type Extension:  0x%02x\n", ext);
1099 						printf("   Link Type:            OEM GUID Definition\n");
1100 					}
1101 					else
1102 					{
1103 						if (type <= FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE )
1104 						{
1105 							printf("   Link Type Extension:  %s\n",
1106                                       amc_link_type_ext_str[type][ext]);
1107 							printf("   Link Type:            %s\n",
1108                                       amc_link_type_str[type]);
1109 						}
1110 						else{
1111 							printf("   Link Type Extension:  0x%02x\n", ext);
1112 							printf("   Link Type:            undefined\n");
1113 						}
1114 					}
1115 					printf("   Link Designator: \n");
1116 					printf("      Channel Number:    0x%02x\n", channel);
1117 					printf("      Port Flag:         0x%02x\n", port );
1118 					printf("   STATE:                %s\n",
1119                               ( enabled == 0x01 )?"enabled":"disabled");
1120 					printf("\n");
1121 				}
1122 			}
1123 		}
1124 	}
1125 	else
1126 	{
1127 		lprintf(LOG_NOTICE,"ipmi_picmg_amc_portstate_get"\
1128 							"Unexpected answer, can't print result");
1129 	}
1130 
1131 	return 0;
1132 }
1133 
1134 
1135 int
1136 ipmi_picmg_amc_portstate_set(struct ipmi_intf * intf, uint8_t channel,
1137 		int32_t port, uint8_t type, uint8_t typeext,
1138 		uint8_t group, uint8_t enable, int32_t device)
1139 {
1140 	struct ipmi_rs	 * rsp;
1141 	struct ipmi_rq	 req;
1142 	unsigned char	 msg_data[7];
1143 
1144 	memset(&req, 0, sizeof(req));
1145 
1146 	req.msg.netfn	  = IPMI_NETFN_PICMG;
1147 	req.msg.cmd		  = PICMG_AMC_SET_PORT_STATE_CMD;
1148 	req.msg.data	  = msg_data;
1149 
1150 	msg_data[0]	 = 0x00;						 /* PICMG identifier*/
1151 	msg_data[1]	 = channel;					 /* channel id */
1152 	msg_data[2]	 = port & 0xF;				 /* port flags */
1153 	msg_data[2] |= (type & 0x0F)<<4;		 /* type	 */
1154 	msg_data[3]	 = (type & 0xF0)>>4;		 /* type */
1155 	msg_data[3] |= (typeext & 0x0F)<<4;	 /* extension */
1156 	msg_data[4]	 = (group & 0xFF);		 /* group */
1157 	msg_data[5]	 = (enable & 0x01);		 /* state */
1158 	req.msg.data_len = 6;
1159 
1160 	/* device id - only for carrier needed */
1161 	if (device >= 0) {
1162 		msg_data[6]	 = device;
1163 		req.msg.data_len = 7;
1164 	}
1165 
1166 	rsp = intf->sendrecv(intf, &req);
1167 
1168 	if (!rsp) {
1169 		lprintf(LOG_ERR, "No valid response received.");
1170 		return -1;
1171 	}
1172 
1173 	if (rsp->ccode) {
1174 		lprintf(LOG_ERR, "Amc portstate set failed with CC code 0x%02x",
1175 				rsp->ccode);
1176 		return -1;
1177 	}
1178 
1179 	return 0;
1180 }
1181 
1182 
1183 int
1184 ipmi_picmg_get_led_properties(struct ipmi_intf * intf, int argc, char ** argv)
1185 {
1186 	struct ipmi_rs * rsp;
1187 	struct ipmi_rq req;
1188 
1189 	unsigned char msg_data[6];
1190 
1191 	memset(&req, 0, sizeof(req));
1192 
1193 	req.msg.netfn = IPMI_NETFN_PICMG;
1194 	req.msg.cmd	  = PICMG_GET_FRU_LED_PROPERTIES_CMD;
1195 	req.msg.data  = msg_data;
1196 	req.msg.data_len = 2;
1197 
1198 	msg_data[0] = 0x00;									/* PICMG identifier */
1199 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {
1200 		return (-1);
1201 	}
1202 
1203 	rsp = intf->sendrecv(intf, &req);
1204 
1205 	if (!rsp) {
1206 		lprintf(LOG_ERR, "No valid response received.");
1207 		return -1;
1208 	}
1209 
1210 	if (rsp->ccode) {
1211 		lprintf(LOG_ERR, "LED get properties failed with CC code 0x%02x",
1212 				rsp->ccode);
1213 		return -1;
1214 	}
1215 
1216 	printf("General Status LED Properties:  0x%2x\n", rsp->data[1] );
1217 	printf("App. Specific  LED Count:       0x%2x\n", rsp->data[2] );
1218 
1219 	return 0;
1220 }
1221 
1222 int
1223 ipmi_picmg_get_led_capabilities(struct ipmi_intf * intf, int argc, char ** argv)
1224 {
1225 	int i;
1226 	struct ipmi_rs * rsp;
1227 	struct ipmi_rq req;
1228 
1229 	unsigned char msg_data[6];
1230 
1231 	memset(&req, 0, sizeof(req));
1232 
1233 	req.msg.netfn = IPMI_NETFN_PICMG;
1234 	req.msg.cmd	  = PICMG_GET_LED_COLOR_CAPABILITIES_CMD;
1235 	req.msg.data  = msg_data;
1236 	req.msg.data_len = 3;
1237 
1238 	msg_data[0] = 0x00;									/* PICMG identifier */
1239 	if (is_fru_id(argv[0], &msg_data[1]) != 0
1240 			|| is_led_id(argv[1], &msg_data[2]) != 0) {
1241 		return (-1);
1242 	}
1243 
1244 	rsp = intf->sendrecv(intf, &req);
1245 
1246 	if (!rsp) {
1247 		lprintf(LOG_ERR, "No valid response received.");
1248 		return -1;
1249 	}
1250 
1251 	if (rsp->ccode) {
1252 		lprintf(LOG_ERR, "LED get capabilities failed with CC code 0x%02x",
1253 				rsp->ccode);
1254 		return -1;
1255 	}
1256 
1257 	printf("LED Color Capabilities: ");
1258 	for ( i=0 ; i<8 ; i++ ) {
1259 		if ( rsp->data[1] & (0x01 << i) ) {
1260 			printf("%s, ", led_color_str[ i ]);
1261 		}
1262 	}
1263 	printf("\n");
1264 
1265 	printf("Default LED Color in\n");
1266 	printf("      LOCAL control:  %s\n", led_color_str[ rsp->data[2] ] );
1267 	printf("      OVERRIDE state: %s\n", led_color_str[ rsp->data[3] ] );
1268 
1269 	return 0;
1270 }
1271 
1272 int
1273 ipmi_picmg_get_led_state(struct ipmi_intf * intf, int argc, char ** argv)
1274 {
1275 	struct ipmi_rs * rsp;
1276 	struct ipmi_rq req;
1277 
1278 	unsigned char msg_data[6];
1279 
1280 	memset(&req, 0, sizeof(req));
1281 
1282 	req.msg.netfn = IPMI_NETFN_PICMG;
1283 	req.msg.cmd	  = PICMG_GET_FRU_LED_STATE_CMD;
1284 	req.msg.data  = msg_data;
1285 	req.msg.data_len = 3;
1286 
1287 	msg_data[0] = 0x00;									/* PICMG identifier */
1288 	if (is_fru_id(argv[0], &msg_data[1]) != 0
1289 			|| is_led_id(argv[1], &msg_data[2]) != 0) {
1290 		return (-1);
1291 	}
1292 
1293 	rsp = intf->sendrecv(intf, &req);
1294 
1295 	if (!rsp) {
1296 		lprintf(LOG_ERR, "No valid response received.");
1297 		return -1;
1298 	}
1299 
1300 	if (rsp->ccode) {
1301 		lprintf(LOG_ERR, "LED get state failed with CC code 0x%02x", rsp->ccode);
1302 		return -1;
1303 	}
1304 
1305 	printf("LED states:						  %x	", rsp->data[1] );
1306 	if (rsp->data[1] == 0x1)
1307 		printf("[LOCAL CONTROL]\n");
1308 	else if (rsp->data[1] == 0x2)
1309 		printf("[OVERRIDE]\n");
1310 	else if (rsp->data[1] == 0x4)
1311 		printf("[LAMPTEST]\n");
1312 	else
1313 		printf("\n");
1314 
1315 	printf("  Local Control function:     %x  ", rsp->data[2] );
1316 	if (rsp->data[2] == 0x0)
1317 		printf("[OFF]\n");
1318 	else if (rsp->data[2] == 0xff)
1319 		printf("[ON]\n");
1320 	else
1321 		printf("[BLINKING]\n");
1322 
1323 	printf("  Local Control On-Duration:  %x\n", rsp->data[3] );
1324 	printf("  Local Control Color:        %x  [%s]\n", rsp->data[4], led_color_str[ rsp->data[4] ]);
1325 
1326 	/* override state or lamp test */
1327 	if (rsp->data[1] == 0x02) {
1328 		printf("  Override function:     %x  ", rsp->data[5] );
1329 		if (rsp->data[2] == 0x0)
1330 			printf("[OFF]\n");
1331 		else if (rsp->data[2] == 0xff)
1332 			printf("[ON]\n");
1333 		else
1334 			printf("[BLINKING]\n");
1335 
1336 		printf("  Override On-Duration:  %x\n", rsp->data[6] );
1337 		printf("  Override Color:        %x  [%s]\n", rsp->data[7], led_color_str[ rsp->data[7] ]);
1338 
1339 	}else if (rsp->data[1] == 0x06) {
1340 		printf("  Override function:     %x  ", rsp->data[5] );
1341 		if (rsp->data[2] == 0x0)
1342 			printf("[OFF]\n");
1343 		else if (rsp->data[2] == 0xff)
1344 			printf("[ON]\n");
1345 		else
1346 			printf("[BLINKING]\n");
1347 		printf("  Override On-Duration:  %x\n", rsp->data[6] );
1348 		printf("  Override Color:        %x  [%s]\n", rsp->data[7], led_color_str[ rsp->data[7] ]);
1349 		printf("  Lamp test duration:    %x\n", rsp->data[8] );
1350 	}
1351 
1352 	return 0;
1353 }
1354 
1355 int
1356 ipmi_picmg_set_led_state(struct ipmi_intf * intf, int argc, char ** argv)
1357 {
1358 	struct ipmi_rs * rsp;
1359 	struct ipmi_rq req;
1360 
1361 	unsigned char msg_data[6];
1362 
1363 	memset(&req, 0, sizeof(req));
1364 
1365 	req.msg.netfn = IPMI_NETFN_PICMG;
1366 	req.msg.cmd	  = PICMG_SET_FRU_LED_STATE_CMD;
1367 	req.msg.data  = msg_data;
1368 	req.msg.data_len = 6;
1369 
1370 	msg_data[0] = 0x00;									/* PICMG identifier */
1371 	if (is_fru_id(argv[0], &msg_data[1]) != 0
1372 			|| is_led_id(argv[1], &msg_data[2]) != 0
1373 			|| is_led_function(argv[2], &msg_data[3]) != 0
1374 			|| is_led_duration(argv[3], &msg_data[4]) != 0
1375 			|| is_led_color(argv[4], &msg_data[5]) != 0) {
1376 		return (-1);
1377 	}
1378 
1379 	rsp = intf->sendrecv(intf, &req);
1380 
1381 	if (!rsp) {
1382 		lprintf(LOG_ERR, "No valid response received.");
1383 		return -1;
1384 	}
1385 
1386 	if (rsp->ccode) {
1387 		lprintf(LOG_ERR, "LED set state failed with CC code 0x%02x", rsp->ccode);
1388 		return -1;
1389 	}
1390 
1391 
1392 	return 0;
1393 }
1394 
1395 int
1396 ipmi_picmg_get_power_level(struct ipmi_intf * intf, int argc, char ** argv)
1397 {
1398 	int i;
1399 	struct ipmi_rs * rsp;
1400 	struct ipmi_rq req;
1401 
1402 	unsigned char msg_data[6];
1403 
1404 	memset(&req, 0, sizeof(req));
1405 
1406 	req.msg.netfn = IPMI_NETFN_PICMG;
1407 	req.msg.cmd	  = PICMG_GET_POWER_LEVEL_CMD;
1408 	req.msg.data  = msg_data;
1409 	req.msg.data_len = 3;
1410 
1411 	msg_data[0] = 0x00;									/* PICMG identifier */
1412 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {
1413 		return (-1);
1414 	}
1415 	/* PICMG Power Type - <0..3> */
1416 	if (str2uchar(argv[1], &msg_data[2]) != 0 || msg_data[2] > 3) {
1417 		lprintf(LOG_ERR, "Given Power Type '%s' is invalid",
1418 				argv[1]);
1419 		return (-1);
1420 	}
1421 
1422 	rsp = intf->sendrecv(intf, &req);
1423 
1424 	if (!rsp) {
1425 		lprintf(LOG_ERR, "No valid response received.");
1426 		return -1;
1427 	}
1428 
1429 	if (rsp->ccode) {
1430 		lprintf(LOG_ERR, "Power level get failed with CC code 0x%02x", rsp->ccode);
1431 		return -1;
1432 	}
1433 
1434 	printf("Dynamic Power Configuration: %s\n", (rsp->data[1]&0x80)==0x80?"enabled":"disabled" );
1435 	printf("Actual Power Level:          %i\n", (rsp->data[1] & 0xf));
1436 	printf("Delay to stable Power:       %i\n", rsp->data[2]);
1437 	printf("Power Multiplier:            %i\n", rsp->data[3]);
1438 
1439 
1440 	for ( i = 1; i+3 < rsp->data_len ; i++ ) {
1441 		printf("   Power Draw %i:            %i\n", i, (rsp->data[i+3]) * rsp->data[3] / 10);
1442 	}
1443 	return 0;
1444 }
1445 
1446 int
1447 ipmi_picmg_set_power_level(struct ipmi_intf * intf, int argc, char ** argv)
1448 {
1449 	struct ipmi_rs * rsp;
1450 	struct ipmi_rq req;
1451 
1452 	unsigned char msg_data[6];
1453 
1454 	memset(&req, 0, sizeof(req));
1455 
1456 	req.msg.netfn = IPMI_NETFN_PICMG;
1457 	req.msg.cmd	  = PICMG_SET_POWER_LEVEL_CMD;
1458 	req.msg.data  = msg_data;
1459 	req.msg.data_len = 4;
1460 
1461 	msg_data[0] = 0x00;					/* PICMG identifier	 */
1462 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {
1463 		return (-1);
1464 	}
1465 	/* PICMG Power Level - <0x00..0x14>, [0xFF] */
1466 	if (str2uchar(argv[1], &msg_data[2]) != 0
1467 			|| (msg_data[2] > 0x14 && msg_data[2] != 0xFF)) {
1468 		lprintf(LOG_ERR,
1469 				"Given PICMG Power Level '%s' is invalid.",
1470 				argv[1]);
1471 		return (-1);
1472 	}
1473 	/* PICMG Present-to-desired - <0..1> */
1474 	if (str2uchar(argv[2], &msg_data[3]) != 0 || msg_data[3] > 1) {
1475 		lprintf(LOG_ERR,
1476 				"Given PICMG Present-to-desired '%s' is invalid.",
1477 				argv[2]);
1478 		return (-1);
1479 	}
1480 
1481 	rsp = intf->sendrecv(intf, &req);
1482 
1483 	if (!rsp) {
1484 		lprintf(LOG_ERR, "No valid response received.");
1485 		return -1;
1486 	}
1487 
1488 	if (rsp->ccode) {
1489 		lprintf(LOG_ERR, "Power level set failed with CC code 0x%02x", rsp->ccode);
1490 		return -1;
1491 	}
1492 
1493 	return 0;
1494 }
1495 
1496 int
1497 ipmi_picmg_bused_resource(struct ipmi_intf * intf, t_picmg_bused_resource_mode mode)
1498 {
1499 	struct ipmi_rs * rsp;
1500 	struct ipmi_rq req;
1501 
1502 	unsigned char msg_data[6];
1503 	memset(&req, 0, sizeof(req));
1504 
1505    int status = 0;
1506    switch ( mode ) {
1507       case PICMG_BUSED_RESOURCE_SUMMARY:
1508       {
1509          t_picmg_busres_resource_id resource;
1510          t_picmg_busres_board_cmd_types cmd =PICMG_BUSRES_BOARD_CMD_QUERY;
1511 
1512          req.msg.netfn	  = IPMI_NETFN_PICMG;
1513          req.msg.cmd	     = PICMG_BUSED_RESOURCE_CMD;
1514          req.msg.data	  = msg_data;
1515          req.msg.data_len = 3;
1516 
1517          /* IF BOARD
1518             query for all resources
1519          */
1520          for( resource=PICMG_BUSRES_METAL_TEST_BUS_1;resource<=PICMG_BUSRES_SYNC_CLOCK_GROUP_3;resource+=(t_picmg_busres_resource_id)1 ) {
1521             msg_data[0] = 0x00;					/* PICMG identifier */
1522             msg_data[1] = (unsigned char) cmd;
1523             msg_data[2] = (unsigned char) resource;
1524             rsp = intf->sendrecv(intf, &req);
1525 
1526             if (!rsp) {
1527                printf("bused resource control: no response\n");
1528                return -1;
1529             }
1530 
1531             if (rsp->ccode) {
1532                printf("bused resource control: returned CC code 0x%02x\n", rsp->ccode);
1533                return -1;
1534             } else {
1535                printf("Resource 0x%02x '%-26s' : 0x%02x [%s] \n" ,
1536                        resource, val2str(resource,picmg_busres_id_vals),
1537                        rsp->data[1], oemval2str(cmd,rsp->data[1],
1538                       picmg_busres_board_status_vals));
1539             }
1540          }
1541       }
1542       break;
1543       default :
1544       break;
1545    }
1546 
1547    return status;
1548 }
1549 
1550 int
1551 ipmi_picmg_fru_control(struct ipmi_intf * intf, int argc, char ** argv)
1552 {
1553 	struct ipmi_rs * rsp;
1554 	struct ipmi_rq req;
1555 
1556 	unsigned char msg_data[6];
1557 
1558 	memset(&req, 0, sizeof(req));
1559 
1560 	req.msg.netfn	  = IPMI_NETFN_PICMG;
1561 	req.msg.cmd	  = PICMG_FRU_CONTROL_CMD;
1562 	req.msg.data	  = msg_data;
1563 	req.msg.data_len = 3;
1564 
1565 	msg_data[0] = 0x00;					/* PICMG identifier */
1566 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {
1567 		return (-1);
1568 	}
1569 	/* FRU Control Option, valid range: <0..4> */
1570 	if (str2uchar(argv[1], &msg_data[2]) != 0 || msg_data[2] > 4) {
1571 		lprintf(LOG_ERR,
1572 				"Given FRU Control Option '%s' is invalid.",
1573 				argv[1]);
1574 		return (-1);
1575 	}
1576 
1577 	printf("FRU Device Id: %d FRU Control Option: %s\n", msg_data[1],  \
1578 				val2str( msg_data[2], picmg_frucontrol_vals));
1579 
1580 	rsp = intf->sendrecv(intf, &req);
1581 
1582 	if (!rsp) {
1583 		lprintf(LOG_ERR, "No valid response received.");
1584 		return -1;
1585 	}
1586 
1587 	if (rsp->ccode) {
1588 		lprintf(LOG_ERR, "frucontrol failed with CC code 0x%02x", rsp->ccode);
1589 		return -1;
1590 	} else {
1591       printf("frucontrol: ok\n");
1592 	}
1593 
1594 
1595 
1596 	return 0;
1597 }
1598 
1599 
1600 int
1601 ipmi_picmg_clk_get(struct ipmi_intf * intf, uint8_t clk_id, int8_t clk_res,
1602 		int mode)
1603 {
1604 	struct ipmi_rs * rsp;
1605 	struct ipmi_rq req;
1606 
1607 	unsigned char enabled;
1608 	unsigned char direction;
1609 
1610 	unsigned char msg_data[6];
1611 
1612 	memset(&req, 0, sizeof(req));
1613 
1614 	req.msg.netfn = IPMI_NETFN_PICMG;
1615 	req.msg.cmd   = PICMG_AMC_GET_CLK_STATE_CMD;
1616 	req.msg.data  = msg_data;
1617 
1618 	msg_data[0] = 0x00;									/* PICMG identifier	 */
1619 	msg_data[1] = clk_id;
1620 
1621 	if(clk_res == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){
1622 		req.msg.data_len = 2;	/* for amc only channel */
1623 	}else{
1624 		req.msg.data_len = 3;	/* for carrier channel and device */
1625       msg_data[2] = clk_res;
1626 	}
1627 
1628 	rsp = intf->sendrecv(intf, &req);
1629 
1630 	if (!rsp) {
1631 		lprintf(LOG_ERR, "No valid response received.");
1632 		return -1;
1633 	}
1634 
1635 	if (rsp->ccode && (mode == PICMG_EKEY_MODE_QUERY) ) {
1636 		lprintf(LOG_ERR, "Clk get failed with CC code 0x%02x", rsp->ccode);
1637 		return -1;
1638 	}
1639 
1640 	if (rsp->ccode == 0 ) {
1641 		enabled	 = (rsp->data[1]&0x8)!=0;
1642 		direction = (rsp->data[1]&0x4)!=0;
1643 
1644 		if
1645 		(
1646 			mode == PICMG_EKEY_MODE_QUERY
1647  			||
1648  			mode == PICMG_EKEY_MODE_PRINT_ALL
1649  			||
1650  			(
1651  				mode == PICMG_EKEY_MODE_PRINT_DISABLED
1652  				&&
1653  				enabled == 0
1654  			)
1655  			||
1656  			(
1657  				mode == PICMG_EKEY_MODE_PRINT_ENABLED
1658  				&&
1659  				enabled == 1
1660          )
1661 		) {
1662 			if( PicmgCardType != PICMG_CARD_TYPE_AMC ) {
1663 				printf("CLK resource id   : %3d [ %s ]\n", clk_res ,
1664 					oemval2str( ((clk_res>>6)&0x03), (clk_res&0x0F),
1665 														picmg_clk_resource_vals));
1666 			} else {
1667 				printf("CLK resource id   : N/A [ AMC Module ]\n");
1668 				clk_res = 0x40; /* Set */
1669 			}
1670          printf("CLK id            : %3d [ %s ]\n", clk_id,
1671 					oemval2str( ((clk_res>>6)&0x03), clk_id ,
1672 														picmg_clk_id_vals));
1673 
1674 
1675 			printf("CLK setting       : 0x%02x\n", rsp->data[1]);
1676 			printf(" - state:     %s\n", (enabled)?"enabled":"disabled");
1677 			printf(" - direction: %s\n", (direction)?"Source":"Receiver");
1678 			printf(" - PLL ctrl:  0x%x\n", rsp->data[1]&0x3);
1679 
1680 		   if(enabled){
1681 		      unsigned long freq = 0;
1682 		      freq = (  rsp->data[5] <<  0
1683 		              | rsp->data[6] <<  8
1684 		              | rsp->data[7] << 16
1685 		              | rsp->data[8] << 24 );
1686 		      printf("  - Index:  %3d\n", rsp->data[2]);
1687 		      printf("  - Family: %3d [ %s ] \n", rsp->data[3],
1688 						val2str( rsp->data[3], picmg_clk_family_vals));
1689 		      printf("  - AccLVL: %3d [ %s ] \n", rsp->data[4],
1690 						oemval2str( rsp->data[3], rsp->data[4],
1691 											picmg_clk_accuracy_vals));
1692 
1693 		      printf("  - Freq:   %ld\n", freq);
1694 		   }
1695 		}
1696 	}
1697 	return 0;
1698 }
1699 
1700 
1701 int
1702 ipmi_picmg_clk_set(struct ipmi_intf * intf, int argc, char ** argv)
1703 {
1704 	struct ipmi_rs * rsp;
1705 	struct ipmi_rq req;
1706 
1707 	unsigned char msg_data[11] = {0};
1708 	uint32_t freq = 0;
1709 
1710 	memset(&req, 0, sizeof(req));
1711 
1712 	req.msg.netfn = IPMI_NETFN_PICMG;
1713 	req.msg.cmd	  = PICMG_AMC_SET_CLK_STATE_CMD;
1714 	req.msg.data  = msg_data;
1715 
1716 	msg_data[0] = 0x00;									/* PICMG identifier	 */
1717 	if (is_clk_id(argv[0], &msg_data[1]) != 0
1718 			|| is_clk_index(argv[1], &msg_data[2]) != 0
1719 			|| is_clk_setting(argv[2], &msg_data[3]) != 0
1720 			|| is_clk_family(argv[3], &msg_data[4]) != 0
1721 			|| is_clk_acc(argv[4], &msg_data[5]) != 0
1722 			|| is_clk_freq(argv[5], &freq) != 0) {
1723 		return (-1);
1724 	}
1725 
1726 	msg_data[6] = (freq >> 0)& 0xFF;		/* freq					 */
1727 	msg_data[7] = (freq >> 8)& 0xFF;		/* freq					 */
1728 	msg_data[8] = (freq >>16)& 0xFF;		/* freq					 */
1729 	msg_data[9] = (freq >>24)& 0xFF;		/* freq					 */
1730 
1731 	req.msg.data_len = 10;
1732    if( PicmgCardType == PICMG_CARD_TYPE_ATCA  )
1733    {
1734       if( argc > 7)
1735       {
1736          req.msg.data_len = 11;
1737 		 if (is_clk_resid(argv[6], &msg_data[10]) != 0) {
1738 			 return (-1);
1739 		 }
1740       }
1741       else
1742       {
1743          lprintf(LOG_ERR, "Missing resource id for atca board.");
1744          return -1;
1745       }
1746    }
1747 
1748 
1749 	rsp = intf->sendrecv(intf, &req);
1750 	if (!rsp) {
1751 		lprintf(LOG_ERR, "No valid response received.");
1752 		return -1;
1753 	}
1754 
1755 	if (rsp->ccode) {
1756 		lprintf(LOG_ERR, "Clk set failed with CC code 0x%02x", rsp->ccode);
1757 		return -1;
1758 	}
1759 
1760 	return 0;
1761 }
1762 
1763 
1764 
1765 int
1766 ipmi_picmg_main (struct ipmi_intf * intf, int argc, char ** argv)
1767 {
1768 	int rc = 0;
1769 	int showProperties = 0;
1770 
1771 	if (argc == 0 || (!strncmp(argv[0], "help", 4))) {
1772 		ipmi_picmg_help();
1773 		return 0;
1774 	}
1775 
1776 	/* Get PICMG properties is called to obtain version information */
1777 	if (argc !=0 && !strncmp(argv[0], "properties", 10)) {
1778 		showProperties =1;
1779 	}
1780 	rc = ipmi_picmg_properties(intf,showProperties);
1781 
1782 	/* address info command */
1783 	if (!strncmp(argv[0], "addrinfo", 8)) {
1784 		rc = ipmi_picmg_getaddr(intf, argc-1, &argv[1]);
1785 	}
1786 	else if (!strncmp(argv[0], "busres", 6)) {
1787 		if (argc > 1) {
1788 			if (!strncmp(argv[1], "summary", 7)) {
1789 				ipmi_picmg_bused_resource(intf, PICMG_BUSED_RESOURCE_SUMMARY );
1790 			}
1791 		} else {
1792 			lprintf(LOG_NOTICE, "usage: busres summary");
1793       }
1794 	}
1795 	/* fru control command */
1796 	else if (!strncmp(argv[0], "frucontrol", 10)) {
1797 		if (argc > 2) {
1798 			rc = ipmi_picmg_fru_control(intf, argc-1, &(argv[1]));
1799 		}
1800 		else {
1801 			lprintf(LOG_NOTICE, "usage: frucontrol <FRU-ID> <OPTION>");
1802 			lprintf(LOG_NOTICE, "   OPTION:");
1803 			lprintf(LOG_NOTICE, "      0      - Cold Reset");
1804 			lprintf(LOG_NOTICE, "      1      - Warm Reset");
1805 			lprintf(LOG_NOTICE, "      2      - Graceful Reboot");
1806 			lprintf(LOG_NOTICE, "      3      - Issue Diagnostic Interrupt");
1807 			lprintf(LOG_NOTICE, "      4      - Quiesce [AMC only]");
1808 			lprintf(LOG_NOTICE, "      5-255  - Reserved");
1809 
1810 			return -1;
1811 		}
1812 
1813 	}
1814 
1815 	/* fru activation command */
1816 	else if (!strncmp(argv[0], "activate", 8)) {
1817 		if (argc > 1) {
1818 			rc = ipmi_picmg_fru_activation(intf, argc-1, &(argv[1]), PICMG_FRU_ACTIVATE);
1819 		}
1820 		else {
1821 			lprintf(LOG_ERR, "Specify the FRU to activate.");
1822 			return -1;
1823 		}
1824 	}
1825 
1826 	/* fru deactivation command */
1827 	else if (!strncmp(argv[0], "deactivate", 10)) {
1828 		if (argc > 1) {
1829 			rc = ipmi_picmg_fru_activation(intf, argc-1, &(argv[1]), PICMG_FRU_DEACTIVATE);
1830 		}else {
1831 			lprintf(LOG_ERR, "Specify the FRU to deactivate.");
1832 			return -1;
1833 		}
1834 	}
1835 
1836 	/* activation policy command */
1837 	else if (!strncmp(argv[0], "policy", 6)) {
1838 		if (argc > 1) {
1839 			if (!strncmp(argv[1], "get", 3)) {
1840 				if (argc > 2) {
1841 					rc = ipmi_picmg_fru_activation_policy_get(intf, argc-1, &(argv[2]));
1842 				} else {
1843 					lprintf(LOG_NOTICE, "usage: get <fruid>");
1844 				}
1845 			} else if (!strncmp(argv[1], "set", 3)) {
1846 				if (argc > 4) {
1847 					rc = ipmi_picmg_fru_activation_policy_set(intf, argc-1, &(argv[2]));
1848 				} else {
1849 					lprintf(LOG_NOTICE, "usage: set <fruid> <lockmask> <lock>");
1850 					lprintf(LOG_NOTICE,
1851 							"    lockmask:  [1] affect the deactivation locked bit");
1852 					lprintf(LOG_NOTICE,
1853 							"               [0] affect the activation locked bit");
1854 					lprintf(LOG_NOTICE,
1855 							"    lock:      [1] set/clear deactivation locked");
1856 					lprintf(LOG_NOTICE, "               [0] set/clear locked");
1857 				}
1858 			}
1859 			else {
1860 				lprintf(LOG_ERR, "Specify FRU.");
1861 				return -1;
1862 			}
1863 		} else {
1864 			lprintf(LOG_ERR, "Wrong parameters.");
1865 			return -1;
1866 		}
1867 	}
1868 
1869 	/* portstate command */
1870 	else if (!strncmp(argv[0], "portstate", 9)) {
1871 
1872 		lprintf(LOG_DEBUG,"PICMG: portstate API");
1873 
1874 		if (argc > 1) {
1875 			if (!strncmp(argv[1], "get", 3)) {
1876 				int32_t iface;
1877 				uint8_t channel = 0;
1878 
1879 				lprintf(LOG_DEBUG,"PICMG: get");
1880 
1881 				if(!strncmp(argv[1], "getall", 6)) {
1882 					for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) {
1883 						for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) {
1884 							if(!(( iface == FRU_PICMGEXT_DESIGN_IF_FABRIC ) &&
1885 							      ( channel > PICMG_EKEY_MAX_FABRIC_CHANNEL ) ))
1886 							{
1887 								rc = ipmi_picmg_portstate_get(intf,iface,channel,
1888 								        PICMG_EKEY_MODE_PRINT_ALL);
1889 							}
1890 						}
1891 					}
1892 				}
1893 				else if(!strncmp(argv[1], "getgranted", 10)) {
1894 					for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) {
1895 						for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) {
1896 							rc = ipmi_picmg_portstate_get(intf,iface,channel,
1897 							            PICMG_EKEY_MODE_PRINT_ENABLED);
1898 						}
1899 					}
1900 				}
1901 				else if(!strncmp(argv[1], "getdenied", 9)){
1902 					for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) {
1903 						for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) {
1904 							rc = ipmi_picmg_portstate_get(intf,iface,channel,
1905 							           PICMG_EKEY_MODE_PRINT_DISABLED);
1906 						}
1907 					}
1908 				}
1909 				else if (argc > 3){
1910 					if (is_amc_intf(argv[2], &iface) != 0
1911 							|| is_amc_channel(argv[3], &channel) != 0) {
1912 						return (-1);
1913 					}
1914 					lprintf(LOG_DEBUG,"PICMG: requesting interface %d",iface);
1915 					lprintf(LOG_DEBUG,"PICMG: requesting channel %d",channel);
1916 
1917 					rc = ipmi_picmg_portstate_get(intf,iface,channel,
1918 					            PICMG_EKEY_MODE_QUERY );
1919 				}
1920 				else {
1921 					lprintf(LOG_NOTICE, "<intf> <chn>|getall|getgranted|getdenied");
1922 				}
1923 			}
1924 			else if (!strncmp(argv[1], "set", 3)) {
1925 					if (argc == 9) {
1926 						int32_t interface = 0;
1927 						int32_t port = 0;
1928 						uint8_t channel = 0;
1929 						uint8_t enable = 0;
1930 						uint8_t group = 0;
1931 						uint8_t type = 0;
1932 						uint8_t typeext = 0;
1933 						if (is_amc_intf(argv[2], &interface) != 0
1934 								|| is_amc_channel(argv[3], &channel) != 0
1935 								|| is_amc_port(argv[4], &port) != 0
1936 								|| is_link_type(argv[5], &type) != 0
1937 								|| is_link_type_ext(argv[6], &typeext) != 0
1938 								|| is_link_group(argv[7], &group) != 0
1939 								|| is_enable(argv[8], &enable) != 0) {
1940 							return (-1);
1941 						}
1942 
1943 						lprintf(LOG_DEBUG,"PICMG: interface %d",interface);
1944 						lprintf(LOG_DEBUG,"PICMG: channel %d",channel);
1945 						lprintf(LOG_DEBUG,"PICMG: port %d",port);
1946 						lprintf(LOG_DEBUG,"PICMG: type %d",type);
1947 						lprintf(LOG_DEBUG,"PICMG: typeext %d",typeext);
1948 						lprintf(LOG_DEBUG,"PICMG: group %d",group);
1949 						lprintf(LOG_DEBUG,"PICMG: enable %d",enable);
1950 
1951 						rc = ipmi_picmg_portstate_set(intf, interface,
1952 						    channel, port, type, typeext  ,group ,enable);
1953 					}
1954 					else {
1955 						lprintf(LOG_NOTICE,
1956 								"<intf> <chn> <port> <type> <ext> <group> <1|0>");
1957 						return -1;
1958 					}
1959 			}
1960 		}
1961 		else {
1962 			lprintf(LOG_NOTICE, "<set>|<getall>|<getgranted>|<getdenied>");
1963 			return -1;
1964 		}
1965 	}
1966 	/* amc portstate command */
1967 	else if (!strncmp(argv[0], "amcportstate", 12)) {
1968 
1969 		lprintf(LOG_DEBUG,"PICMG: amcportstate API");
1970 
1971 		if (argc > 1) {
1972 			if (!strncmp(argv[1], "get", 3)){
1973 				int32_t device;
1974 				uint8_t channel;
1975 
1976 				lprintf(LOG_DEBUG,"PICMG: get");
1977 
1978 				if(!strncmp(argv[1], "getall", 6)){
1979 					int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE;
1980 					if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){
1981 						maxDevice = 0;
1982 					}
1983 					for(device=0;device<=maxDevice;device++){
1984 						for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){
1985 							rc = ipmi_picmg_amc_portstate_get(intf,device,channel,
1986 																	PICMG_EKEY_MODE_PRINT_ALL);
1987 						}
1988 					}
1989 				}
1990 				else if(!strncmp(argv[1], "getgranted", 10)){
1991 					int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE;
1992 					if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){
1993 						maxDevice = 0;
1994 					}
1995 					for(device=0;device<=maxDevice;device++){
1996 						for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){
1997 							rc = ipmi_picmg_amc_portstate_get(intf,device,channel,
1998 																  PICMG_EKEY_MODE_PRINT_ENABLED);
1999 						}
2000 					}
2001 				}
2002 				else if(!strncmp(argv[1], "getdenied", 9)){
2003 					int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE;
2004 					if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){
2005 						maxDevice = 0;
2006 					}
2007 					for(device=0;device<=maxDevice;device++){
2008 						for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){
2009 							rc = ipmi_picmg_amc_portstate_get(intf,device,channel,
2010                                                  PICMG_EKEY_MODE_PRINT_DISABLED);
2011 						}
2012 					}
2013 				}
2014 				else if (argc > 2){
2015 					if (is_amc_channel(argv[2], &channel) != 0) {
2016 						return (-1);
2017 					}
2018 					if (argc > 3){
2019 						if (is_amc_dev(argv[3], &device) != 0) {
2020 							return (-1);
2021 						}
2022 					}else{
2023 					   device = -1;
2024 				    }
2025 					lprintf(LOG_DEBUG,"PICMG: requesting device %d",device);
2026 					lprintf(LOG_DEBUG,"PICMG: requesting channel %d",channel);
2027 
2028 					rc = ipmi_picmg_amc_portstate_get(intf,device,channel,
2029                                              PICMG_EKEY_MODE_QUERY );
2030 				}
2031 				else {
2032 					lprintf(LOG_NOTICE, "<chn> <device>|getall|getgranted|getdenied");
2033 				}
2034 			}
2035 			else if (!strncmp(argv[1], "set", 3)) {
2036 				if (argc > 7) {
2037 					int32_t device = -1;
2038 					int32_t port = 0;
2039 					uint8_t channel = 0;
2040 					uint8_t enable = 0;
2041 					uint8_t group = 0;
2042 					uint8_t type = 0;
2043 					uint8_t typeext = 0;
2044 					if (is_amc_channel(argv[2], &channel) != 0
2045 							|| is_amc_port(argv[3], &port) != 0
2046 							|| is_link_type(argv[4], &type) !=0
2047 							|| is_link_type_ext(argv[5], &typeext) != 0
2048 							|| is_link_group(argv[6], &group) != 0
2049 							|| is_enable(argv[7], &enable) != 0) {
2050 						return (-1);
2051 					}
2052 					if(argc > 8){
2053 						if (is_amc_dev(argv[8], &device) != 0) {
2054 							return (-1);
2055 						}
2056 					}
2057 
2058 					lprintf(LOG_DEBUG,"PICMG: channel %d",channel);
2059 					lprintf(LOG_DEBUG,"PICMG: portflags %d",port);
2060 					lprintf(LOG_DEBUG,"PICMG: type %d",type);
2061 					lprintf(LOG_DEBUG,"PICMG: typeext %d",typeext);
2062 					lprintf(LOG_DEBUG,"PICMG: group %d",group);
2063 					lprintf(LOG_DEBUG,"PICMG: enable %d",enable);
2064 					lprintf(LOG_DEBUG,"PICMG: device %d",device);
2065 
2066 					rc = ipmi_picmg_amc_portstate_set(intf, channel, port, type,
2067                                                typeext, group, enable, device);
2068 				}
2069 				else {
2070 					lprintf(LOG_NOTICE,
2071 							"<chn> <portflags> <type> <ext> <group> <1|0> [<device>]");
2072 					return -1;
2073 				}
2074 			}
2075 		}
2076 		else {
2077 			lprintf(LOG_NOTICE, "<set>|<get>|<getall>|<getgranted>|<getdenied>");
2078 			return -1;
2079 		}
2080 	}
2081 	/* ATCA led commands */
2082 	else if (!strncmp(argv[0], "led", 3)) {
2083 		if (argc > 1) {
2084 			if (!strncmp(argv[1], "prop", 4)) {
2085 				if (argc > 2) {
2086 					rc = ipmi_picmg_get_led_properties(intf, argc-1, &(argv[2]));
2087 				}
2088 				else {
2089 					lprintf(LOG_NOTICE, "led prop <FRU-ID>");
2090 				}
2091 			}
2092 			else if (!strncmp(argv[1], "cap", 3)) {
2093 				if (argc > 3) {
2094 					rc = ipmi_picmg_get_led_capabilities(intf, argc-1, &(argv[2]));
2095 				}
2096 				else {
2097 					lprintf(LOG_NOTICE, "led cap <FRU-ID> <LED-ID>");
2098 				}
2099 			}
2100 			else if (!strncmp(argv[1], "get", 3)) {
2101 				if (argc > 3) {
2102 					rc = ipmi_picmg_get_led_state(intf, argc-1, &(argv[2]));
2103 				}
2104 				else {
2105 					lprintf(LOG_NOTICE, "led get <FRU-ID> <LED-ID>");
2106 				}
2107 			}
2108 			else if (!strncmp(argv[1], "set", 3)) {
2109 				if (argc > 6) {
2110 					rc = ipmi_picmg_set_led_state(intf, argc-1, &(argv[2]));
2111 				}
2112 				else {
2113 					lprintf(LOG_NOTICE,
2114 							"led set <FRU-ID> <LED-ID> <function> <duration> <color>");
2115 					lprintf(LOG_NOTICE, "   <FRU-ID>");
2116 					lprintf(LOG_NOTICE, "   <LED-ID>    0:         Blue LED");
2117 					lprintf(LOG_NOTICE, "               1:         LED 1");
2118 					lprintf(LOG_NOTICE, "               2:         LED 2");
2119 					lprintf(LOG_NOTICE, "               3:         LED 3");
2120 					lprintf(LOG_NOTICE, "               0x04-0xFE: OEM defined");
2121 					lprintf(LOG_NOTICE,
2122 							"               0xFF:      All LEDs under management control");
2123 					lprintf(LOG_NOTICE, "   <function>  0:       LED OFF override");
2124 					lprintf(LOG_NOTICE,
2125 							"               1 - 250: LED blinking override (off duration)");
2126 					lprintf(LOG_NOTICE, "               251:     LED Lamp Test");
2127 					lprintf(LOG_NOTICE,
2128 							"               252:     LED restore to local control");
2129 					lprintf(LOG_NOTICE, "               255:     LED ON override");
2130 					lprintf(LOG_NOTICE,
2131 							"   <duration>  1 - 127: LED Lamp Test / on duration");
2132 					lprintf(LOG_NOTICE, "   <color>     0:   reserved");
2133 					lprintf(LOG_NOTICE, "               1:   BLUE");
2134 					lprintf(LOG_NOTICE, "               2:   RED");
2135 					lprintf(LOG_NOTICE, "               3:   GREEN");
2136 					lprintf(LOG_NOTICE, "               4:   AMBER");
2137 					lprintf(LOG_NOTICE, "               5:   ORANGE");
2138 					lprintf(LOG_NOTICE, "               6:   WHITE");
2139 					lprintf(LOG_NOTICE, "               7:   reserved");
2140 					lprintf(LOG_NOTICE, "               0xE: do not change");
2141 					lprintf(LOG_NOTICE, "               0xF: use default color");
2142 				}
2143 			}
2144 			else {
2145 				lprintf(LOG_NOTICE, "prop | cap | get | set");
2146 			}
2147 		}
2148 	}
2149 	/* power commands */
2150 	else if (!strncmp(argv[0], "power", 5)) {
2151 		if (argc > 1) {
2152 			if (!strncmp(argv[1], "get", 3)) {
2153 				if (argc > 3) {
2154 					rc = ipmi_picmg_get_power_level(intf, argc-1, &(argv[2]));
2155 				}
2156 				else {
2157 					lprintf(LOG_NOTICE, "power get <FRU-ID> <type>");
2158 					lprintf(LOG_NOTICE, "   <type>   0 : steady state power draw levels");
2159 					lprintf(LOG_NOTICE,
2160 							"            1 : desired steady state draw levels");
2161 					lprintf(LOG_NOTICE, "            2 : early power draw levels");
2162 					lprintf(LOG_NOTICE, "            3 : desired early levels");
2163 
2164 					return -1;
2165 				}
2166 			}
2167 			else if (!strncmp(argv[1], "set", 3)) {
2168 				if (argc > 4) {
2169 					rc = ipmi_picmg_set_power_level(intf, argc-1, &(argv[2]));
2170 				}
2171 				else {
2172 					lprintf(LOG_NOTICE, "power set <FRU-ID> <level> <present-desired>");
2173 					lprintf(LOG_NOTICE, "   <level>  0 :        Power Off");
2174 					lprintf(LOG_NOTICE, "            0x1-0x14 : Power level");
2175 					lprintf(LOG_NOTICE, "            0xFF :     do not change");
2176 					lprintf(LOG_NOTICE,
2177 							"\n   <present-desired> 0: do not change present levels");
2178 					lprintf(LOG_NOTICE,
2179 							"                     1: copy desired to present level");
2180 
2181 					return -1;
2182 				}
2183 			}
2184 			else {
2185 				lprintf(LOG_NOTICE, "<set>|<get>");
2186 				return -1;
2187 			}
2188 		}
2189 		else {
2190 			lprintf(LOG_NOTICE, "<set>|<get>");
2191 			return -1;
2192 		}
2193 	}/* clk commands*/
2194 	else if (!strncmp(argv[0], "clk", 3)) {
2195 		if (argc > 1) {
2196 			if (!strncmp(argv[1], "get", 3)) {
2197 				int8_t clk_res = -1;
2198 				uint8_t clk_id;
2199 				uint8_t max_res = 15;
2200 
2201 				if( PicmgCardType == PICMG_CARD_TYPE_AMC ) {
2202 					max_res = 0;
2203 				}
2204 
2205 				if(!strncmp(argv[1], "getall", 6)) {
2206 					if( verbose ) { printf("Getting all clock state\n") ;}
2207 					for(clk_res=0;clk_res<=max_res;clk_res++) {
2208 						for(clk_id=0;clk_id<=15;clk_id++) {
2209 								rc = ipmi_picmg_clk_get(intf,clk_id,clk_res,
2210 								        PICMG_EKEY_MODE_PRINT_ALL);
2211 						}
2212 					}
2213 				}
2214 				else if(!strncmp(argv[1], "getdenied", 6)) {
2215 					if( verbose ) { printf("Getting disabled clocks\n") ;}
2216 					for(clk_res=0;clk_res<=max_res;clk_res++) {
2217 						for(clk_id=0;clk_id<=15;clk_id++) {
2218 								rc = ipmi_picmg_clk_get(intf,clk_id,clk_res,
2219 								        PICMG_EKEY_MODE_PRINT_DISABLED);
2220 						}
2221 					}
2222 				}
2223 				else if(!strncmp(argv[1], "getgranted", 6)) {
2224 					if( verbose ) { printf("Getting enabled clocks\n") ;}
2225 					for(clk_res=0;clk_res<=max_res;clk_res++) {
2226 						for(clk_id=0;clk_id<=15;clk_id++) {
2227 								rc = ipmi_picmg_clk_get(intf,clk_id,clk_res,
2228 								        PICMG_EKEY_MODE_PRINT_ENABLED);
2229 						}
2230 					}
2231 				}
2232 				else if (argc > 2) {
2233 					if (is_clk_id(argv[2], &clk_id) != 0) {
2234 						return (-1);
2235 					}
2236 					if (argc > 3) {
2237 						if (is_clk_resid(argv[3], &clk_res) != 0) {
2238 							return (-1);
2239 						}
2240 					}
2241 
2242 					rc = ipmi_picmg_clk_get(intf, clk_id, clk_res,
2243 							PICMG_EKEY_MODE_QUERY );
2244 				}
2245 				else {
2246 					lprintf(LOG_NOTICE, "clk get");
2247 					lprintf(LOG_NOTICE,
2248 							"<CLK-ID> [<DEV-ID>] |getall|getgranted|getdenied");
2249 					return -1;
2250 				}
2251 			}
2252 			else if (!strncmp(argv[1], "set", 3)) {
2253 				if (argc > 7) {
2254 					rc = ipmi_picmg_clk_set(intf, argc-1, &(argv[2]));
2255 				}
2256 				else {
2257 					lprintf(LOG_NOTICE,
2258 							"clk set <CLK-ID> <index> <setting> <family> <acc-lvl> <freq> [<DEV-ID>]");
2259 
2260 					return -1;
2261 				}
2262 			}
2263 			else {
2264 				lprintf(LOG_NOTICE, "<set>|<get>|<getall>|<getgranted>|<getdenied>");
2265 				return -1;
2266 			}
2267 		}
2268 		else {
2269 			lprintf(LOG_NOTICE, "<set>|<get>|<getall>|<getgranted>|<getdenied>");
2270 			return -1;
2271 		}
2272 	}
2273 
2274 	else if(showProperties == 0 ){
2275 
2276 		ipmi_picmg_help();
2277 		return -1;
2278 	}
2279 
2280 	return rc;
2281 }
2282 
2283 uint8_t
2284 ipmi_picmg_ipmb_address(struct ipmi_intf *intf) {
2285 	struct ipmi_rq req;
2286 	struct ipmi_rs *rsp;
2287 	char msg_data;
2288 
2289 	if (!intf->picmg_avail) {
2290 		return 0;
2291 	}
2292 	memset(&req, 0, sizeof(req));
2293 	req.msg.netfn = IPMI_NETFN_PICMG;
2294 	req.msg.cmd = PICMG_GET_ADDRESS_INFO_CMD;
2295 	msg_data    = 0x00;
2296 	req.msg.data = &msg_data;
2297 	req.msg.data_len = 1;
2298 	msg_data = 0;
2299 
2300 	rsp = intf->sendrecv(intf, &req);
2301 	if (rsp && !rsp->ccode) {
2302 		return rsp->data[2];
2303 	}
2304 	if (rsp) {
2305 		lprintf(LOG_DEBUG, "Get Address Info failed: %#x %s",
2306 			rsp->ccode, val2str(rsp->ccode, completion_code_vals));
2307 	} else {
2308 		lprintf(LOG_DEBUG, "Get Address Info failed: No Response");
2309 	}
2310 	return 0;
2311 }
2312 
2313 uint8_t
2314 picmg_discover(struct ipmi_intf *intf) {
2315 	/* Check if PICMG extension is available to use the function
2316 	 * GetDeviceLocator to retreive i2c address PICMG hack to set
2317 	 * right IPMB address, If extension is not supported, should
2318 	 * not give any problems
2319 	 *  PICMG Extension Version 2.0 (PICMG 3.0 Revision 1.0 ATCA) to
2320 	 *  PICMG Extension Version 2.3 (PICMG 3.0 Revision 3.0 ATCA)
2321 	 *  PICMG Extension Version 4.1 (PICMG 3.0 Revision 3.0 AMC)
2322 	 */
2323 
2324 	/* First, check if PICMG extension is available and supported */
2325 	struct ipmi_rq req;
2326 	struct ipmi_rs *rsp;
2327 	char msg_data;
2328 	uint8_t picmg_avail = 0;
2329 
2330 	memset(&req, 0, sizeof(req));
2331 	req.msg.netfn = IPMI_NETFN_PICMG;
2332 	req.msg.cmd = PICMG_GET_PICMG_PROPERTIES_CMD;
2333 	msg_data    = 0x00;
2334 	req.msg.data = &msg_data;
2335 	req.msg.data_len = 1;
2336 	msg_data = 0;
2337 
2338 	lprintf(LOG_INFO, "Running Get PICMG Properties my_addr %#x, transit %#x, target %#x",
2339 		intf->my_addr, intf->transit_addr, intf->target_addr);
2340 	rsp = intf->sendrecv(intf, &req);
2341 	if (rsp == NULL) {
2342 	    lprintf(LOG_INFO,"No response from Get PICMG Properties");
2343 	} else if (rsp->ccode != 0) {
2344 	    lprintf(LOG_INFO,"Error response %#x from Get PICMG Properities",
2345 		    rsp->ccode);
2346 	} else if (rsp->data_len < 4) {
2347 	    lprintf(LOG_INFO,"Invalid Get PICMG Properties response length %d",
2348 		    rsp->data_len);
2349 	} else if (rsp->data[0] != 0) {
2350 	    lprintf(LOG_INFO,"Invalid Get PICMG Properties group extension %#x",
2351 		    rsp->data[0]);
2352 	} else if ((rsp->data[1] & 0x0F) != PICMG_ATCA_MAJOR_VERSION
2353 		&& (rsp->data[1] & 0x0F) != PICMG_AMC_MAJOR_VERSION) {
2354 	    lprintf(LOG_INFO,"Unknown PICMG Extension Version %d.%d",
2355 		    (rsp->data[1] & 0x0F), (rsp->data[1] >> 4));
2356 	} else {
2357 	    picmg_avail = 1;
2358 	    lprintf(LOG_INFO, "Discovered PICMG Extension Version %d.%d",
2359 		    (rsp->data[1] & 0x0f), (rsp->data[1] >> 4));
2360 	}
2361 
2362 	return picmg_avail;
2363 }
2364