xref: /openbmc/ipmitool/lib/ipmi_vita.c (revision 13a2a291)
1 /*
2  * Copyright (c) 2014 Pigeon Point Systems. 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 Pigeon Point Systems, 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  * PIGEON POINT SYSTEMS ("PPS") 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  * PPS 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 PPS 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_vita.h>
37 #include <ipmitool/ipmi_fru.h>
38 #include <ipmitool/ipmi_strings.h>
39 #include <ipmitool/log.h>
40 
41 /* Handled VITA 46.11 commands */
42 #define VITA_CMD_HELP		0
43 #define VITA_CMD_PROPERTIES	1
44 #define VITA_CMD_FRUCONTROL	2
45 #define VITA_CMD_ADDRINFO	3
46 #define VITA_CMD_ACTIVATE	4
47 #define VITA_CMD_DEACTIVATE	5
48 #define VITA_CMD_POLICY_GET	6
49 #define VITA_CMD_POLICY_SET	7
50 #define VITA_CMD_LED_PROP	8
51 #define VITA_CMD_LED_CAP	9
52 #define VITA_CMD_LED_GET	10
53 #define VITA_CMD_LED_SET	11
54 #define VITA_CMD_UNKNOWN	255
55 
56 /* VITA 46.11 Site Type strings */
57 static struct valstr vita_site_types[] = {
58 	{ VITA_FRONT_VPX_MODULE, "Front Loading VPX Plug-In Module" },
59 	{ VITA_POWER_ENTRY, "Power Entry Module" },
60 	{ VITA_CHASSIS_FRU, "Chassic FRU Information Module" },
61 	{ VITA_DEDICATED_CHMC, "Dedicated Chassis Manager" },
62 	{ VITA_FAN_TRAY, "Fan Tray" },
63 	{ VITA_FAN_TRAY_FILTER, "Fan Tray Filter" },
64 	{ VITA_ALARM_PANEL, "Alarm Panel" },
65 	{ VITA_XMC, "XMC" },
66 	{ VITA_VPX_RTM, "VPX Rear Transition Module" },
67 	{ VITA_FRONT_VME_MODULE, "Front Loading VME Plug-In Module" },
68 	{ VITA_FRONT_VXS_MODULE, "Front Loading VXS Plug-In Module" },
69 	{ VITA_POWER_SUPPLY, "Power Supply" },
70 	{ VITA_FRONT_VITA62_MODULE, "Front Loading VITA 62 Module\n" },
71 	{ VITA_71_MODULE, "VITA 71 Module\n" },
72 	{ VITA_FMC, "FMC\n" },
73 	{ 0, NULL }
74 };
75 
76 /* VITA 46.11 command help strings */
77 static struct valstr vita_help_strings[] = {
78 	{
79 		VITA_CMD_HELP,
80 		"VITA commands:\n"
81 		"    properties        - get VSO properties\n"
82 		"    frucontrol        - FRU control\n"
83 		"    addrinfo          - get address information\n"
84 		"    activate          - activate a FRU\n"
85 		"    deactivate        - deactivate a FRU\n"
86 		"    policy get        - get the FRU activation policy\n"
87 		"    policy set        - set the FRU activation policy\n"
88 		"    led prop          - get led properties\n"
89 		"    led cap           - get led color capabilities\n"
90 		"    led get           - get led state\n"
91 		"    led set           - set led state"
92 	},
93 	{
94 		VITA_CMD_FRUCONTROL,
95 		"usage: frucontrol <FRU-ID> <OPTION>\n"
96 		"    OPTION: 0 - Cold Reset\n"
97 		"            1 - Warm Reset\n"
98 		"            2 - Graceful Reboot\n"
99 		"            3 - Issue Diagnostic Interrupt"
100 	},
101 	{
102 		VITA_CMD_ADDRINFO,
103 		"usage: addrinfo [<FRU-ID>]"
104 	},
105 	{
106 		VITA_CMD_ACTIVATE,
107 		"usage: activate <FRU-ID>"
108 	},
109 	{
110 		VITA_CMD_DEACTIVATE,
111 		"usage: deactivate <FRU-ID>"
112 	},
113     	{
114 		VITA_CMD_POLICY_GET,
115 		"usage: policy get <FRU-ID>"
116 	},
117 	{
118 		VITA_CMD_POLICY_SET,
119 		"usage: policy set <FRU-ID> <MASK> <VALUE>\n"
120 		"    MASK:  [3] affect the Default-Activation-Locked Policy Bit\n"
121 		"           [2] affect the Commanded-Deactivation-Ignored Policy Bit\n"
122 		"           [1] affect the Deactivation-Locked Policy Bit\n"
123 		"           [0] affect the Activation-Locked Policy Bit\n"
124 		"    VALUE: [3] value for the Default-Activation-Locked Policy Bit\n"
125 		"           [2] value for the Commanded-Deactivation-Ignored Policy Bit\n"
126 		"           [1] value for the Deactivation-Locked Policy Bit\n"
127 		"           [0] value for the Activation-Locked Policy Bit"
128 	},
129 	{
130 		VITA_CMD_LED_PROP,
131 		"usage: led prop <FRU-ID>"
132 	},
133 	{
134 		VITA_CMD_LED_CAP,
135 		"usage: led cap <FRU-ID> <LED-ID"
136 	},
137 	{
138 		VITA_CMD_LED_GET,
139 		"usage: led get <FRU-ID> <LED-ID",
140 	},
141 	{
142 		VITA_CMD_LED_SET,
143 		"usage: led set <FRU-ID> <LED-ID> <FUNCTION> <DURATION> <COLOR>\n"
144 		"    <FRU-ID>\n"
145 		"    <LED-ID>   0-0xFE:    Specified LED\n"
146 		"               0xFF:      All LEDs under management control\n"
147 		"    <FUNCTION> 0:       LED OFF override\n"
148 		"               1 - 250: LED blinking override (off duration)\n"
149 		"               251:     LED Lamp Test\n"
150 		"               252:     LED restore to local control\n"
151 		"               255:     LED ON override\n"
152 		"    <DURATION> 1 - 127: LED Lamp Test / on duration\n"
153 		"    <COLOR>    1:   BLUE\n"
154 		"               2:   RED\n"
155 		"               3:   GREEN\n"
156 		"               4:   AMBER\n"
157 		"               5:   ORANGE\n"
158 		"               6:   WHITE\n"
159 		"               0xE: do not change\n"
160 		"               0xF: use default color"
161 	},
162 	{
163 		VITA_CMD_UNKNOWN,
164 		"Unknown command"
165 	},
166 	{ 0, NULL }
167 };
168 
169 /* check if VITA 46.11 is supported */
170 uint8_t
171 vita_discover(struct ipmi_intf *intf)
172 {
173 	struct ipmi_rq req;
174 	struct ipmi_rs *rsp;
175 	unsigned char msg_data;
176 	int vita_avail = 0;
177 
178 	memset(&req, 0, sizeof(req));
179 
180 	req.msg.netfn = IPMI_NETFN_PICMG;
181 	req.msg.cmd = VITA_GET_VSO_CAPABILITIES_CMD;
182 	req.msg.data = &msg_data;
183 	req.msg.data_len = 1;
184 
185 	msg_data = GROUP_EXT_VITA;
186 
187 	lprintf(LOG_INFO, "Running Get VSO Capabilities my_addr %#x, "
188 		"transit %#x, target %#x",
189 		intf->my_addr, intf->transit_addr, intf->target_addr);
190 
191 	rsp = intf->sendrecv(intf, &req);
192 
193 	if (rsp == NULL) {
194 		lprintf(LOG_ERR, "No valid response received");
195 	} else if (rsp->ccode == 0xC1) {
196 		lprintf(LOG_DEBUG, "Invalid completion code received: %s",
197 			val2str(rsp->ccode, completion_code_vals));
198 	} else if (rsp->ccode != 0) {
199 		lprintf(LOG_ERR, "Invalid completion code received: %s",
200 			val2str(rsp->ccode, completion_code_vals));
201 	} else if (rsp->data_len < 5) {
202 		lprintf(LOG_ERR, "Invalid response length %d",
203 			rsp->data_len);
204 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
205 		lprintf(LOG_ERR, "Invalid group extension %#x",
206 			rsp->data[0]);
207 	} else if ((rsp->data[3] & 0x03) != 0) {
208 		lprintf(LOG_ERR, "Unknown VSO Standard %d",
209 			(rsp->data[3] & 0x03));
210 	} else if ((rsp->data[4] & 0x0F) != 1) {
211 		lprintf(LOG_ERR, "Unknown VSO Specification Revision %d.%d",
212 			(rsp->data[4] & 0x0F), (rsp->data[4] >> 4));
213 	} else {
214 		vita_avail = 1;
215 		lprintf(LOG_INFO, "Discovered VITA 46.11 Revision %d.%d",
216 			(rsp->data[4] & 0x0F), (rsp->data[4] >> 4));
217 	}
218 
219 	return vita_avail;
220 }
221 
222 uint8_t
223 ipmi_vita_ipmb_address(struct ipmi_intf *intf)
224 {
225 	struct ipmi_rq req;
226 	struct ipmi_rs *rsp;
227 	unsigned char msg_data;
228 
229 	memset(&req, 0, sizeof(req));
230 
231 	req.msg.netfn = IPMI_NETFN_PICMG;
232 	req.msg.cmd = VITA_GET_FRU_ADDRESS_INFO_CMD;
233 	req.msg.data = &msg_data;
234 	req.msg.data_len = 1;
235 
236 	msg_data = GROUP_EXT_VITA;
237 
238 	rsp = intf->sendrecv(intf, &req);
239 
240 	if (rsp == NULL) {
241 		lprintf(LOG_ERR, "No valid response received");
242 	} else if (rsp->ccode != 0) {
243 		lprintf(LOG_ERR, "Invalid completion code received: %s",
244 			val2str(rsp->ccode, completion_code_vals));
245 	} else if (rsp->data_len < 7) {
246 		lprintf(LOG_ERR, "Invalid response length %d",
247 			rsp->data_len);
248 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
249 		lprintf(LOG_ERR, "Invalid group extension %#x",
250 			rsp->data[0]);
251 	} else {
252 		return rsp->data[2];
253 	}
254 
255 	return 0;
256 }
257 
258 static int
259 ipmi_vita_getaddr(struct ipmi_intf *intf, int argc, char **argv)
260 {
261 	struct ipmi_rs *rsp;
262 	struct ipmi_rq req;
263 	unsigned char msg_data[2];
264 
265 	memset(&req, 0, sizeof(req));
266 
267 	req.msg.netfn = IPMI_NETFN_PICMG;
268 	req.msg.cmd = VITA_GET_FRU_ADDRESS_INFO_CMD;
269 	req.msg.data = msg_data;
270 	req.msg.data_len = 2;
271 
272 	msg_data[0] = GROUP_EXT_VITA;		/* VITA identifier */
273 	msg_data[1] = 0;			/* default FRU ID */
274 
275 	if (argc > 0) {
276 		/* validate and get FRU Device ID */
277 		if (is_fru_id(argv[0], &msg_data[1]) != 0) {
278 			return -1;
279 		}
280 	}
281 
282 	rsp = intf->sendrecv(intf, &req);
283 
284 	if (rsp == NULL) {
285 		lprintf(LOG_ERR, "No valid response received");
286 		return -1;
287 	} else if (rsp->ccode != 0) {
288 		lprintf(LOG_ERR, "Invalid completion code received: %s",
289 			val2str(rsp->ccode, completion_code_vals));
290 		return -1;
291 	} else if (rsp->data_len < 7) {
292 		lprintf(LOG_ERR, "Invalid response length %d",
293 			rsp->data_len);
294 		return -1;
295 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
296 		lprintf(LOG_ERR, "Invalid group extension %#x",
297 			rsp->data[0]);
298 		return -1;
299 	}
300 
301 	printf("Hardware Address : 0x%02x\n", rsp->data[1]);
302 	printf("IPMB-0 Address   : 0x%02x\n", rsp->data[2]);
303 	printf("FRU ID           : 0x%02x\n", rsp->data[4]);
304 	printf("Site ID          : 0x%02x\n", rsp->data[5]);
305 	printf("Site Type        : %s\n", val2str(rsp->data[6],
306 		vita_site_types));
307 	if (rsp->data_len > 8) {
308 		printf("Channel 7 Address: 0x%02x\n", rsp->data[8]);
309 	}
310 
311 	return 0;
312 }
313 
314 static int
315 ipmi_vita_get_vso_capabilities(struct ipmi_intf *intf)
316 {
317 	struct ipmi_rs *rsp;
318 	struct ipmi_rq req;
319 	unsigned char msg_data, tmp;
320 
321 	memset(&req, 0, sizeof(req));
322 
323 	req.msg.netfn = IPMI_NETFN_PICMG;
324 	req.msg.cmd = VITA_GET_VSO_CAPABILITIES_CMD;
325 	req.msg.data = &msg_data;
326 	req.msg.data_len = 1;
327 
328 	msg_data = GROUP_EXT_VITA;		/* VITA identifier */
329 
330 	rsp = intf->sendrecv(intf, &req);
331 
332 	if (rsp == NULL) {
333 		lprintf(LOG_ERR, "No valid response received.");
334 		return -1;
335 	} else if (rsp->ccode != 0) {
336 		lprintf(LOG_ERR, "Invalid completion code received: %s",
337 			val2str(rsp->ccode, completion_code_vals));
338 		return -1;
339 	} else if (rsp->data_len < 5) {
340 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
341 		return -1;
342 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
343 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
344 		return -1;
345 	}
346 
347 	printf("VSO Identifier    : 0x%02x\n", rsp->data[0]);
348 	printf("IPMC Identifier   : 0x%02x\n", rsp->data[1]);
349 	printf("    Tier  %d\n", (rsp->data[1] & 0x03) + 1);
350 	printf("    Layer %d\n", ((rsp->data[1] & 0x30) >> 4) + 1);
351 
352 	printf("IPMB Capabilities : 0x%02x\n", rsp->data[2]);
353 
354 	tmp = (rsp->data[2] & 0x30) >> 4;
355 
356 	printf("    Frequency  %skHz\n",
357 		tmp == 0 ? "100" : tmp == 1 ? "400" : "RESERVED");
358 
359 	tmp = rsp->data[2] & 3;
360 
361 	if (tmp == 1) {
362 		printf("    2 IPMB interfaces supported\n");
363 	} else if (tmp == 0) {
364 		printf("    1 IPMB interface supported\n");
365 	}
366 
367 	printf("VSO Standard      : %s\n",
368 		(rsp->data[3] & 0x3) == 0 ? "VITA 46.11" : "RESERVED");
369 
370 	printf("VSO Spec Revision : %d.%d\n", rsp->data[4] & 0xf,
371 		rsp->data[4] >> 4);
372 
373 	printf("Max FRU Device ID : 0x%02x\n", rsp->data[5]);
374 	printf("FRU Device ID     : 0x%02x\n", rsp->data[6]);
375 
376 	return 0;
377 }
378 
379 static int
380 ipmi_vita_set_fru_activation(struct ipmi_intf *intf,
381 	char **argv, unsigned char command)
382 {
383 	struct ipmi_rs *rsp;
384 	struct ipmi_rq req;
385 	unsigned char msg_data[3];
386 
387 	memset(&req, 0, sizeof(req));
388 
389 	req.msg.netfn = IPMI_NETFN_PICMG;
390 	req.msg.cmd = VITA_SET_FRU_ACTIVATION_CMD;
391 	req.msg.data = msg_data;
392 	req.msg.data_len = 3;
393 
394 	msg_data[0]	= GROUP_EXT_VITA;		/* VITA identifier */
395 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
396 		return -1;
397 	}
398 	msg_data[2]	= command;			/* command */
399 
400 	rsp = intf->sendrecv(intf, &req);
401 
402 	if (rsp == NULL) {
403 		lprintf(LOG_ERR, "No valid response received.");
404 		return -1;
405 	} else if (rsp->ccode != 0) {
406 		lprintf(LOG_ERR, "Invalid completion code received: %s",
407 			val2str(rsp->ccode, completion_code_vals));
408 		return -1;
409 	} else if (rsp->data_len < 1) {
410 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
411 		return -1;
412 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
413 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
414 		return -1;
415 	}
416 
417 	printf("FRU has been successfully %s\n",
418 		command ? "activated" : "deactivated");
419 
420 	return 0;
421 }
422 
423 static int
424 ipmi_vita_get_fru_state_policy_bits(struct ipmi_intf *intf, char **argv)
425 {
426 	struct ipmi_rs *rsp;
427 	struct ipmi_rq req;
428 	unsigned char msg_data[2];
429 
430 	memset(&req, 0, sizeof(req));
431 
432 	req.msg.netfn = IPMI_NETFN_PICMG;
433 	req.msg.cmd = VITA_GET_FRU_STATE_POLICY_BITS_CMD;
434 	req.msg.data = msg_data;
435 	req.msg.data_len = 2;
436 
437 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
438 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
439 		return -1;
440 	}
441 
442 	rsp = intf->sendrecv(intf, &req);
443 
444 	if (rsp == NULL) {
445 		lprintf(LOG_ERR, "No valid response received.");
446 		return -1;
447 	} else if (rsp->ccode != 0) {
448 		lprintf(LOG_ERR, "Invalid completion code received: %s",
449 			val2str(rsp->ccode, completion_code_vals));
450 		return -1;
451 	} else if (rsp->data_len < 2) {
452 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
453 		return -1;
454 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
455 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
456 		return -1;
457 	}
458 
459 	printf("FRU State Policy Bits:	%xh\n", rsp->data[1]);
460 	printf("    Default-Activation-Locked Policy Bit is %d\n",
461 		rsp->data[1] & 0x08 ? 1 : 0);
462 	printf("    Commanded-Deactivation-Ignored Policy Bit is %d\n",
463 		rsp->data[1] & 0x04 ? 1 : 0);
464 	printf("    Deactivation-Locked Policy Bit is %d\n",
465 		rsp->data[1] & 0x02 ? 1 : 0);
466 	printf("    Activation-Locked Policy Bit is %d\n",
467 		rsp->data[1] & 0x01);
468 
469 	return 0;
470 }
471 
472 static int
473 ipmi_vita_set_fru_state_policy_bits(struct ipmi_intf *intf, char **argv)
474 {
475 	struct ipmi_rs *rsp;
476 	struct ipmi_rq req;
477 	unsigned char msg_data[4];
478 
479 	memset(&req, 0, sizeof(req));
480 
481 	req.msg.netfn = IPMI_NETFN_PICMG;
482 	req.msg.cmd = VITA_SET_FRU_STATE_POLICY_BITS_CMD;
483 	req.msg.data = msg_data;
484 	req.msg.data_len = 4;
485 
486 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
487 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
488 		return -1;
489 	}
490 	if (str2uchar(argv[1], &msg_data[2]) != 0) {	/* bits mask */
491 		return -1;
492 	}
493 	if (str2uchar(argv[2], &msg_data[3]) != 0) {	/* bits */
494 		return -1;
495 	}
496 
497 	rsp = intf->sendrecv(intf, &req);
498 
499 	if (rsp == NULL) {
500 		lprintf(LOG_ERR, "No valid response received.");
501 		return -1;
502 	} else if (rsp->ccode != 0) {
503 		lprintf(LOG_ERR, "Invalid completion code received: %s",
504 			val2str(rsp->ccode, completion_code_vals));
505 		return -1;
506 	} else if (rsp->data_len < 1) {
507 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
508 		return -1;
509 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
510 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
511 		return -1;
512 	}
513 
514 	printf("FRU state policy bits have been updated\n");
515 
516 	return 0;
517 }
518 
519 static int
520 ipmi_vita_get_led_properties(struct ipmi_intf *intf, char **argv)
521 {
522 	struct ipmi_rs *rsp;
523 	struct ipmi_rq req;
524 	unsigned char msg_data[2];
525 
526 	memset(&req, 0, sizeof(req));
527 
528 	req.msg.netfn = IPMI_NETFN_PICMG;
529 	req.msg.cmd = VITA_GET_FRU_LED_PROPERTIES_CMD;
530 	req.msg.data = msg_data;
531 	req.msg.data_len = 2;
532 
533 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
534 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
535 		return -1;
536 	}
537 
538 	rsp = intf->sendrecv(intf, &req);
539 
540 	if (rsp == NULL) {
541 		lprintf(LOG_ERR, "No valid response received.");
542 		return -1;
543 	} else if (rsp->ccode != 0) {
544 		lprintf(LOG_ERR, "Invalid completion code received: %s",
545 			val2str(rsp->ccode, completion_code_vals));
546 		return -1;
547 	} else if (rsp->data_len < 3) {
548 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
549 		return -1;
550 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
551 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
552 		return -1;
553 	}
554 
555 	printf("LED Count:	   %#x\n", rsp->data[2]);
556 
557 	return 0;
558 }
559 
560 static int
561 ipmi_vita_get_led_color_capabilities(struct ipmi_intf *intf, char **argv)
562 {
563 	struct ipmi_rs *rsp;
564 	struct ipmi_rq req;
565 	unsigned char msg_data[3];
566 	int i;
567 
568 	memset(&req, 0, sizeof(req));
569 
570 	req.msg.netfn = IPMI_NETFN_PICMG;
571 	req.msg.cmd = VITA_GET_LED_COLOR_CAPABILITIES_CMD;
572 	req.msg.data = msg_data;
573 	req.msg.data_len = 3;
574 
575 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
576 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
577 		return -1;
578 	}
579 	if (str2uchar(argv[1], &msg_data[2]) != 0) {	/* LED-ID */
580 		return -1;
581 	}
582 
583 	rsp = intf->sendrecv(intf, &req);
584 
585 	if (rsp == NULL) {
586 		lprintf(LOG_ERR, "No valid response received.");
587 		return -1;
588 	} else if (rsp->ccode != 0) {
589 		lprintf(LOG_ERR, "Invalid completion code received: %s",
590 			val2str(rsp->ccode, completion_code_vals));
591 		return -1;
592 	} else if (rsp->data_len < 5) {
593 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
594 		return -1;
595 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
596 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
597 		return -1;
598 	}
599 
600 	printf("LED Color Capabilities: ");
601 	for (i = 0; i < 8; i++) {
602 		if (rsp->data[1] & (0x01 << i)) {
603 			printf("%s, ", led_color_str[i]);
604 		}
605 	}
606 	putchar('\n');
607 
608 	printf("Default LED Color in\n");
609 	printf("      LOCAL control:  %s\n", led_color_str[rsp->data[2]]);
610 	printf("      OVERRIDE state: %s\n", led_color_str[rsp->data[3]]);
611 
612 	if (rsp->data_len == 5) {
613 		printf("LED flags:\n");
614 		if (rsp->data[4] & 2) {
615 			printf("      [HW RESTRICT]\n");
616 		}
617 		if (rsp->data[4] & 1) {
618 			printf("      [PAYLOAD PWR]\n");
619 		}
620 	}
621 
622 	return 0;
623 }
624 
625 static int
626 ipmi_vita_get_led_state(struct ipmi_intf *intf, char **argv)
627 {
628 	struct ipmi_rs *rsp;
629 	struct ipmi_rq req;
630 	unsigned char msg_data[3];
631 
632 	memset(&req, 0, sizeof(req));
633 
634 	req.msg.netfn = IPMI_NETFN_PICMG;
635 	req.msg.cmd = VITA_GET_FRU_LED_STATE_CMD;
636 	req.msg.data = msg_data;
637 	req.msg.data_len = 3;
638 
639 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
640 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
641 		return -1;
642 	}
643 	if (str2uchar(argv[1], &msg_data[2]) != 0) {	/* LED-ID */
644 		return -1;
645 	}
646 
647 	rsp = intf->sendrecv(intf, &req);
648 
649 	if (rsp == NULL) {
650 		lprintf(LOG_ERR, "No valid response received.");
651 		return -1;
652 	} else if (rsp->ccode != 0) {
653 		lprintf(LOG_ERR, "Invalid completion code received: %s",
654 			val2str(rsp->ccode, completion_code_vals));
655 		return -1;
656 	} else if (rsp->data_len < 5
657 		|| ((rsp->data[1] & 0x2) && rsp->data_len < 8)
658 		|| ((rsp->data[1] & 0x4) && rsp->data_len < 9)) {
659 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
660 		return -1;
661 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
662 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
663 		return -1;
664 	}
665 
666 	printf("LED states:                   %x\t", rsp->data[1]);
667 	if (rsp->data[1] & 0x1) {
668 		printf("[LOCAL CONTROL] ");
669 	}
670 	if (rsp->data[1] & 0x2) {
671 		printf("[OVERRIDE] ");
672 	}
673 	if (rsp->data[1] & 0x4) {
674 		printf("[LAMPTEST] ");
675 	}
676 	if (rsp->data[1] & 0x8) {
677 		printf("[HW RESTRICT] ");
678 	}
679 	putchar('\n');
680 
681 	if (rsp->data[1] & 1) {
682 		printf("  Local Control function:     %x\t", rsp->data[2]);
683 		if (rsp->data[2] == 0x0) {
684 			printf("[OFF]\n");
685 		} else if (rsp->data[2] == 0xff) {
686 			printf("[ON]\n");
687 		} else {
688 			printf("[BLINKING]\n");
689 		}
690 		printf("  Local Control On-Duration:  %x\n", rsp->data[3]);
691 		printf("  Local Control Color:        %x\t[%s]\n",
692 			rsp->data[4], led_color_str[rsp->data[4] & 7]);
693 	}
694 
695 	/* override state or lamp test */
696 	if (rsp->data[1] & 0x06) {
697 		printf("  Override function:     %x\t", rsp->data[5]);
698 		if (rsp->data[5] == 0x0) {
699 			printf("[OFF]\n");
700 		} else if (rsp->data[5] == 0xff) {
701 			printf("[ON]\n");
702 		} else {
703 			printf("[BLINKING]\n");
704 		}
705 		printf("  Override On-Duration:  %x\n", rsp->data[6]);
706 		printf("  Override Color:        %x\t[%s]\n",
707 			rsp->data[7], led_color_str[rsp->data[7] & 7]);
708 		if (rsp->data[1] == 0x04) {
709 			printf("  Lamp test duration:    %x\n", rsp->data[8]);
710 		}
711 	}
712 
713 	return 0;
714 }
715 
716 static int
717 ipmi_vita_set_led_state(struct ipmi_intf *intf, char **argv)
718 {
719 	struct ipmi_rs *rsp;
720 	struct ipmi_rq req;
721 	unsigned char msg_data[6];
722 
723 	memset(&req, 0, sizeof(req));
724 
725 	req.msg.netfn = IPMI_NETFN_PICMG;
726 	req.msg.cmd = VITA_SET_FRU_LED_STATE_CMD;
727 	req.msg.data = msg_data;
728 	req.msg.data_len = 6;
729 
730 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
731 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
732 		return -1;
733 	}
734 	if (str2uchar(argv[1], &msg_data[2]) != 0) {	/* LED-ID */
735 		return -1;
736 	}
737 	if (str2uchar(argv[2], &msg_data[3]) != 0) {	/* LED function */
738 		return -1;
739 	}
740 	if (str2uchar(argv[3], &msg_data[4]) != 0) {	/* LED on duration */
741 		return -1;
742 	}
743 	if (str2uchar(argv[4], &msg_data[5]) != 0) {	/* LED color */
744 		return -1;
745 	}
746 
747 	rsp = intf->sendrecv(intf, &req);
748 
749 	if (rsp == NULL) {
750 		lprintf(LOG_ERR, "No valid response received.");
751 		return -1;
752 	} else if (rsp->ccode != 0) {
753 		lprintf(LOG_ERR, "Invalid completion code received: %s",
754 			val2str(rsp->ccode, completion_code_vals));
755 		return -1;
756 	} else if (rsp->data_len < 1) {
757 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
758 		return -1;
759 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
760 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
761 		return -1;
762 	}
763 
764 	printf("LED state has been updated\n");
765 
766 	return 0;
767 }
768 
769 static int
770 ipmi_vita_fru_control(struct ipmi_intf *intf, char **argv)
771 {
772 	struct ipmi_rs *rsp;
773 	struct ipmi_rq req;
774 	unsigned char msg_data[3];
775 
776 	memset(&req, 0, sizeof(req));
777 
778 	req.msg.netfn = IPMI_NETFN_PICMG;
779 	req.msg.cmd = VITA_FRU_CONTROL_CMD;
780 	req.msg.data = msg_data;
781 	req.msg.data_len = 3;
782 
783 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
784 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
785 		return -1;
786 	}
787 	if (str2uchar(argv[1], &msg_data[2]) != 0) {	/* control option */
788 		return -1;
789 	}
790 
791 	printf("FRU Device Id: %d FRU Control Option: %s\n", msg_data[1],
792 		val2str(msg_data[2], picmg_frucontrol_vals));
793 
794 	rsp = intf->sendrecv(intf, &req);
795 
796 	if (rsp == NULL) {
797 		lprintf(LOG_ERR, "No valid response received.");
798 		return -1;
799 	} else if (rsp->ccode != 0) {
800 		lprintf(LOG_ERR, "Invalid completion code received: %s",
801 			val2str(rsp->ccode, completion_code_vals));
802 		return -1;
803 	} else if (rsp->data_len < 1) {
804 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
805 		return -1;
806 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
807 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
808 		return -1;
809 	}
810 
811 	printf("FRU Control: ok\n");
812 
813 	return 0;
814 }
815 
816 static int
817 ipmi_vita_get_cmd(int argc, char **argv)
818 {
819 	if (argc < 1 || !strncmp(argv[0], "help", 4)) {
820 		return VITA_CMD_HELP;
821 	}
822 
823 	/* Get VSO Properties */
824 	if (!strncmp(argv[0], "properties", 10)) {
825 		return VITA_CMD_PROPERTIES;
826 	}
827 
828 	/* FRU Control command */
829 	if (!strncmp(argv[0], "frucontrol", 10)) {
830 		return VITA_CMD_FRUCONTROL;
831 	}
832 
833 	/* Get FRU Address Info command */
834 	if (!strncmp(argv[0], "addrinfo", 8)) {
835 		return VITA_CMD_ADDRINFO;
836 	}
837 
838 	/* Set FRU Activation (activate) command */
839 	if (!strncmp(argv[0], "activate", 8)) {
840 		return VITA_CMD_ACTIVATE;
841 	}
842 
843 	/* Set FRU Activation (deactivate) command */
844 	if (!strncmp(argv[0], "deactivate", 10)) {
845 		return VITA_CMD_DEACTIVATE;
846 	}
847 
848 	/* FRU State Policy Bits commands */
849 	if (!strncmp(argv[0], "policy", 6)) {
850 		if (argc < 2) {
851 			return VITA_CMD_UNKNOWN;
852 		}
853 
854 		/* Get FRU State Policy Bits command */
855 		if (!strncmp(argv[1], "get", 3)) {
856 			return VITA_CMD_POLICY_GET;
857 		}
858 
859 		/* Set FRU State Policy Bits command */
860 		if (!strncmp(argv[1], "set", 3)) {
861 			return VITA_CMD_POLICY_SET;
862 		}
863 
864 		/* unknown command */
865 		return VITA_CMD_UNKNOWN;
866 	}
867 
868 	/* FRU LED commands */
869 	if (!strncmp(argv[0], "led", 3)) {
870 		if (argc < 2) {
871 			return VITA_CMD_UNKNOWN;
872 		}
873 
874 		/* FRU LED Get Properties */
875 		if (!strncmp(argv[1], "prop", 4)) {
876 			return VITA_CMD_LED_PROP;
877 		}
878 
879 		/* FRU LED Get Capabilities */
880 		if (!strncmp(argv[1], "cap", 3)) {
881 			return VITA_CMD_LED_CAP;
882 		}
883 
884 		/* FRU LED Get State */
885 		if (!strncmp(argv[1], "get", 3)) {
886 			return VITA_CMD_LED_GET;
887 		}
888 
889 		/* FRU LED Set State */
890 		if (!strncmp(argv[1], "set", 3)) {
891 			return VITA_CMD_LED_SET;
892 		}
893 
894 		/* unknown command */
895 		return VITA_CMD_UNKNOWN;
896 	}
897 
898 	/* unknown command */
899 	return VITA_CMD_UNKNOWN;
900 }
901 
902 int
903 ipmi_vita_main (struct ipmi_intf *intf, int argc, char **argv)
904 {
905 	int rc = -1, show_help = 0;
906 	int cmd = ipmi_vita_get_cmd(argc, argv);
907 
908 	switch (cmd) {
909 	case VITA_CMD_HELP:
910 		cmd = ipmi_vita_get_cmd(argc - 1, &argv[1]);
911 		show_help = 1;
912 		rc = 0;
913 		break;
914 
915 	case VITA_CMD_PROPERTIES:
916 		rc = ipmi_vita_get_vso_capabilities(intf);
917 		break;
918 
919 	case VITA_CMD_FRUCONTROL:
920 		if (argc > 2) {
921 			rc = ipmi_vita_fru_control(intf, &argv[1]);
922 		} else {
923 			show_help = 1;
924 		}
925 		break;
926 
927 	case VITA_CMD_ADDRINFO:
928 		rc = ipmi_vita_getaddr(intf, argc - 1, &argv[1]);
929 		break;
930 
931 	case VITA_CMD_ACTIVATE:
932 		if (argc > 1) {
933 			rc = ipmi_vita_set_fru_activation(intf, &argv[1], 1);
934 		} else {
935 			show_help = 1;
936 		}
937 		break;
938 
939 	case VITA_CMD_DEACTIVATE:
940 		if (argc > 1) {
941 			rc = ipmi_vita_set_fru_activation(intf, &argv[1], 0);
942 		} else {
943 			show_help = 1;
944 		}
945 		break;
946 
947 	case VITA_CMD_POLICY_GET:
948 		if (argc > 2) {
949 			rc = ipmi_vita_get_fru_state_policy_bits(intf,
950 				&argv[2]);
951 		} else {
952 			show_help = 1;
953 		}
954 		break;
955 
956 	case VITA_CMD_POLICY_SET:
957 		if (argc > 4) {
958 			rc = ipmi_vita_set_fru_state_policy_bits(intf,
959 				&argv[2]);
960 		} else {
961 			show_help = 1;
962 		}
963 		break;
964 
965 	case VITA_CMD_LED_PROP:
966 		if (argc > 2) {
967 			rc = ipmi_vita_get_led_properties(intf, &argv[2]);
968 		} else {
969 			show_help = 1;
970 		}
971 		break;
972 
973 	case VITA_CMD_LED_CAP:
974 		if (argc > 3) {
975 			rc = ipmi_vita_get_led_color_capabilities(intf,
976 				&argv[2]);
977 		} else {
978 			show_help = 1;
979 		}
980 		break;
981 
982 	case VITA_CMD_LED_GET:
983 		if (argc > 3) {
984 			rc = ipmi_vita_get_led_state(intf, &argv[2]);
985 		} else {
986 			show_help = 1;
987 		}
988 		break;
989 
990 	case VITA_CMD_LED_SET:
991 		if (argc > 6) {
992 			rc = ipmi_vita_set_led_state(intf, &argv[2]);
993 		} else {
994 			show_help = 1;
995 		}
996 		break;
997 	default:
998 		lprintf(LOG_NOTICE, "Unknown command");
999 		cmd = VITA_CMD_HELP;
1000 		show_help = 1;
1001 		break;
1002 	}
1003 
1004 	if (show_help) {
1005 		lprintf(LOG_NOTICE, "%s", val2str(cmd, vita_help_strings));
1006 	}
1007 
1008 	return rc;
1009 }
1010