xref: /openbmc/ipmitool/lib/ipmi_vita.c (revision 89e9e634)
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 != 0) {
196 		lprintf(LOG_ERR, "Invalid completion code received: %s",
197 			val2str(rsp->ccode, completion_code_vals));
198 	} else if (rsp->data_len < 5) {
199 		lprintf(LOG_ERR, "Invalid response length %d",
200 			rsp->data_len);
201 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
202 		lprintf(LOG_ERR, "Invalid group extension %#x",
203 			rsp->data[0]);
204 	} else if ((rsp->data[3] & 0x03) != 0) {
205 		lprintf(LOG_ERR, "Unknown VSO Standard %d",
206 			(rsp->data[3] & 0x03));
207 	} else if ((rsp->data[4] & 0x0F) != 1) {
208 		lprintf(LOG_ERR, "Unknown VSO Specification Revision %d.%d",
209 			(rsp->data[4] & 0x0F), (rsp->data[4] >> 4));
210 	} else {
211 		vita_avail = 1;
212 		lprintf(LOG_INFO, "Discovered VITA 46.11 Revision %d.%d",
213 			(rsp->data[4] & 0x0F), (rsp->data[4] >> 4));
214 	}
215 
216 	return vita_avail;
217 }
218 
219 uint8_t
220 ipmi_vita_ipmb_address(struct ipmi_intf *intf)
221 {
222 	struct ipmi_rq req;
223 	struct ipmi_rs *rsp;
224 	unsigned char msg_data;
225 
226 	memset(&req, 0, sizeof(req));
227 
228 	req.msg.netfn = IPMI_NETFN_PICMG;
229 	req.msg.cmd = VITA_GET_FRU_ADDRESS_INFO_CMD;
230 	req.msg.data = &msg_data;
231 	req.msg.data_len = 1;
232 
233 	msg_data = GROUP_EXT_VITA;
234 
235 	rsp = intf->sendrecv(intf, &req);
236 
237 	if (rsp == NULL) {
238 		lprintf(LOG_ERR, "No valid response received");
239 	} else if (rsp->ccode != 0) {
240 		lprintf(LOG_ERR, "Invalid completion code received: %s",
241 			val2str(rsp->ccode, completion_code_vals));
242 	} else if (rsp->data_len < 7) {
243 		lprintf(LOG_ERR, "Invalid response length %d",
244 			rsp->data_len);
245 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
246 		lprintf(LOG_ERR, "Invalid group extension %#x",
247 			rsp->data[0]);
248 	} else {
249 		return rsp->data[2];
250 	}
251 
252 	return 0;
253 }
254 
255 static int
256 ipmi_vita_getaddr(struct ipmi_intf *intf, int argc, char **argv)
257 {
258 	struct ipmi_rs *rsp;
259 	struct ipmi_rq req;
260 	unsigned char msg_data[2];
261 
262 	memset(&req, 0, sizeof(req));
263 
264 	req.msg.netfn = IPMI_NETFN_PICMG;
265 	req.msg.cmd = VITA_GET_FRU_ADDRESS_INFO_CMD;
266 	req.msg.data = msg_data;
267 	req.msg.data_len = 2;
268 
269 	msg_data[0] = GROUP_EXT_VITA;		/* VITA identifier */
270 	msg_data[1] = 0;			/* default FRU ID */
271 
272 	if (argc > 0) {
273 		/* validate and get FRU Device ID */
274 		if (is_fru_id(argv[0], &msg_data[1]) != 0) {
275 			return -1;
276 		}
277 	}
278 
279 	rsp = intf->sendrecv(intf, &req);
280 
281 	if (rsp == NULL) {
282 		lprintf(LOG_ERR, "No valid response received");
283 		return -1;
284 	} else if (rsp->ccode != 0) {
285 		lprintf(LOG_ERR, "Invalid completion code received: %s",
286 			val2str(rsp->ccode, completion_code_vals));
287 		return -1;
288 	} else if (rsp->data_len < 7) {
289 		lprintf(LOG_ERR, "Invalid response length %d",
290 			rsp->data_len);
291 		return -1;
292 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
293 		lprintf(LOG_ERR, "Invalid group extension %#x",
294 			rsp->data[0]);
295 		return -1;
296 	}
297 
298 	printf("Hardware Address : 0x%02x\n", rsp->data[1]);
299 	printf("IPMB-0 Address   : 0x%02x\n", rsp->data[2]);
300 	printf("FRU ID           : 0x%02x\n", rsp->data[4]);
301 	printf("Site ID          : 0x%02x\n", rsp->data[5]);
302 	printf("Site Type        : %s\n", val2str(rsp->data[6],
303 		vita_site_types));
304 	if (rsp->data_len > 8) {
305 		printf("Channel 7 Address: 0x%02x\n", rsp->data[8]);
306 	}
307 
308 	return 0;
309 }
310 
311 static int
312 ipmi_vita_get_vso_capabilities(struct ipmi_intf *intf)
313 {
314 	struct ipmi_rs *rsp;
315 	struct ipmi_rq req;
316 	unsigned char msg_data, tmp;
317 
318 	memset(&req, 0, sizeof(req));
319 
320 	req.msg.netfn = IPMI_NETFN_PICMG;
321 	req.msg.cmd = VITA_GET_VSO_CAPABILITIES_CMD;
322 	req.msg.data = &msg_data;
323 	req.msg.data_len = 1;
324 
325 	msg_data = GROUP_EXT_VITA;		/* VITA identifier */
326 
327 	rsp = intf->sendrecv(intf, &req);
328 
329 	if (rsp == NULL) {
330 		lprintf(LOG_ERR, "No valid response received.");
331 		return -1;
332 	} else if (rsp->ccode != 0) {
333 		lprintf(LOG_ERR, "Invalid completion code received: %s",
334 			val2str(rsp->ccode, completion_code_vals));
335 		return -1;
336 	} else if (rsp->data_len < 5) {
337 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
338 		return -1;
339 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
340 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
341 		return -1;
342 	}
343 
344 	printf("VSO Identifier    : 0x%02x\n", rsp->data[0]);
345 	printf("IPMC Identifier   : 0x%02x\n", rsp->data[1]);
346 	printf("    Tier  %d\n", (rsp->data[1] & 0x03) + 1);
347 	printf("    Layer %d\n", ((rsp->data[1] & 0x30) >> 4) + 1);
348 
349 	printf("IPMB Capabilities : 0x%02x\n", rsp->data[2]);
350 
351 	tmp = (rsp->data[2] & 0x30) >> 4;
352 
353 	printf("    Frequency  %skHz\n",
354 		tmp == 0 ? "100" : tmp == 1 ? "400" : "RESERVED");
355 
356 	tmp = rsp->data[2] & 3;
357 
358 	if (tmp == 1) {
359 		printf("    2 IPMB interfaces supported\n");
360 	} else if (tmp == 0) {
361 		printf("    1 IPMB interface supported\n");
362 	}
363 
364 	printf("VSO Standard      : %s\n",
365 		(rsp->data[3] & 0x3) == 0 ? "VITA 46.11" : "RESERVED");
366 
367 	printf("VSO Spec Revision : %d.%d\n", rsp->data[4] & 0xf,
368 		rsp->data[4] >> 4);
369 
370 	printf("Max FRU Device ID : 0x%02x\n", rsp->data[5]);
371 	printf("FRU Device ID     : 0x%02x\n", rsp->data[6]);
372 
373 	return 0;
374 }
375 
376 static int
377 ipmi_vita_set_fru_activation(struct ipmi_intf *intf,
378 	char **argv, unsigned char command)
379 {
380 	struct ipmi_rs *rsp;
381 	struct ipmi_rq req;
382 	unsigned char msg_data[3];
383 
384 	memset(&req, 0, sizeof(req));
385 
386 	req.msg.netfn = IPMI_NETFN_PICMG;
387 	req.msg.cmd = VITA_SET_FRU_ACTIVATION_CMD;
388 	req.msg.data = msg_data;
389 	req.msg.data_len = 3;
390 
391 	msg_data[0]	= GROUP_EXT_VITA;		/* VITA identifier */
392 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
393 		return -1;
394 	}
395 	msg_data[2]	= command;			/* command */
396 
397 	rsp = intf->sendrecv(intf, &req);
398 
399 	if (rsp == NULL) {
400 		lprintf(LOG_ERR, "No valid response received.");
401 		return -1;
402 	} else if (rsp->ccode != 0) {
403 		lprintf(LOG_ERR, "Invalid completion code received: %s",
404 			val2str(rsp->ccode, completion_code_vals));
405 		return -1;
406 	} else if (rsp->data_len < 1) {
407 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
408 		return -1;
409 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
410 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
411 		return -1;
412 	}
413 
414 	printf("FRU has been successfully %s\n",
415 		command ? "activated" : "deactivated");
416 
417 	return 0;
418 }
419 
420 static int
421 ipmi_vita_get_fru_state_policy_bits(struct ipmi_intf *intf, char **argv)
422 {
423 	struct ipmi_rs *rsp;
424 	struct ipmi_rq req;
425 	unsigned char msg_data[2];
426 
427 	memset(&req, 0, sizeof(req));
428 
429 	req.msg.netfn = IPMI_NETFN_PICMG;
430 	req.msg.cmd = VITA_GET_FRU_STATE_POLICY_BITS_CMD;
431 	req.msg.data = msg_data;
432 	req.msg.data_len = 2;
433 
434 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
435 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
436 		return -1;
437 	}
438 
439 	rsp = intf->sendrecv(intf, &req);
440 
441 	if (rsp == NULL) {
442 		lprintf(LOG_ERR, "No valid response received.");
443 		return -1;
444 	} else if (rsp->ccode != 0) {
445 		lprintf(LOG_ERR, "Invalid completion code received: %s",
446 			val2str(rsp->ccode, completion_code_vals));
447 		return -1;
448 	} else if (rsp->data_len < 2) {
449 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
450 		return -1;
451 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
452 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
453 		return -1;
454 	}
455 
456 	printf("FRU State Policy Bits:	%xh\n", rsp->data[1]);
457 	printf("    Default-Activation-Locked Policy Bit is %d\n",
458 		rsp->data[1] & 0x08 ? 1 : 0);
459 	printf("    Commanded-Deactivation-Ignored Policy Bit is %d\n",
460 		rsp->data[1] & 0x04 ? 1 : 0);
461 	printf("    Deactivation-Locked Policy Bit is %d\n",
462 		rsp->data[1] & 0x02 ? 1 : 0);
463 	printf("    Activation-Locked Policy Bit is %d\n",
464 		rsp->data[1] & 0x01);
465 
466 	return 0;
467 }
468 
469 static int
470 ipmi_vita_set_fru_state_policy_bits(struct ipmi_intf *intf, char **argv)
471 {
472 	struct ipmi_rs *rsp;
473 	struct ipmi_rq req;
474 	unsigned char msg_data[4];
475 
476 	memset(&req, 0, sizeof(req));
477 
478 	req.msg.netfn = IPMI_NETFN_PICMG;
479 	req.msg.cmd = VITA_SET_FRU_STATE_POLICY_BITS_CMD;
480 	req.msg.data = msg_data;
481 	req.msg.data_len = 4;
482 
483 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
484 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
485 		return -1;
486 	}
487 	if (str2uchar(argv[1], &msg_data[2]) != 0) {	/* bits mask */
488 		return -1;
489 	}
490 	if (str2uchar(argv[2], &msg_data[3]) != 0) {	/* bits */
491 		return -1;
492 	}
493 
494 	rsp = intf->sendrecv(intf, &req);
495 
496 	if (rsp == NULL) {
497 		lprintf(LOG_ERR, "No valid response received.");
498 		return -1;
499 	} else if (rsp->ccode != 0) {
500 		lprintf(LOG_ERR, "Invalid completion code received: %s",
501 			val2str(rsp->ccode, completion_code_vals));
502 		return -1;
503 	} else if (rsp->data_len < 1) {
504 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
505 		return -1;
506 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
507 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
508 		return -1;
509 	}
510 
511 	printf("FRU state policy bits have been updated\n");
512 
513 	return 0;
514 }
515 
516 static int
517 ipmi_vita_get_led_properties(struct ipmi_intf *intf, char **argv)
518 {
519 	struct ipmi_rs *rsp;
520 	struct ipmi_rq req;
521 	unsigned char msg_data[2];
522 
523 	memset(&req, 0, sizeof(req));
524 
525 	req.msg.netfn = IPMI_NETFN_PICMG;
526 	req.msg.cmd = VITA_GET_FRU_LED_PROPERTIES_CMD;
527 	req.msg.data = msg_data;
528 	req.msg.data_len = 2;
529 
530 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
531 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
532 		return -1;
533 	}
534 
535 	rsp = intf->sendrecv(intf, &req);
536 
537 	if (rsp == NULL) {
538 		lprintf(LOG_ERR, "No valid response received.");
539 		return -1;
540 	} else if (rsp->ccode != 0) {
541 		lprintf(LOG_ERR, "Invalid completion code received: %s",
542 			val2str(rsp->ccode, completion_code_vals));
543 		return -1;
544 	} else if (rsp->data_len < 3) {
545 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
546 		return -1;
547 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
548 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
549 		return -1;
550 	}
551 
552 	printf("LED Count:	   %#x\n", rsp->data[2]);
553 
554 	return 0;
555 }
556 
557 static int
558 ipmi_vita_get_led_color_capabilities(struct ipmi_intf *intf, char **argv)
559 {
560 	struct ipmi_rs *rsp;
561 	struct ipmi_rq req;
562 	unsigned char msg_data[3];
563 	int i;
564 
565 	memset(&req, 0, sizeof(req));
566 
567 	req.msg.netfn = IPMI_NETFN_PICMG;
568 	req.msg.cmd = VITA_GET_LED_COLOR_CAPABILITIES_CMD;
569 	req.msg.data = msg_data;
570 	req.msg.data_len = 3;
571 
572 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
573 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
574 		return -1;
575 	}
576 	if (str2uchar(argv[1], &msg_data[2]) != 0) {	/* LED-ID */
577 		return -1;
578 	}
579 
580 	rsp = intf->sendrecv(intf, &req);
581 
582 	if (rsp == NULL) {
583 		lprintf(LOG_ERR, "No valid response received.");
584 		return -1;
585 	} else if (rsp->ccode != 0) {
586 		lprintf(LOG_ERR, "Invalid completion code received: %s",
587 			val2str(rsp->ccode, completion_code_vals));
588 		return -1;
589 	} else if (rsp->data_len < 5) {
590 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
591 		return -1;
592 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
593 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
594 		return -1;
595 	}
596 
597 	printf("LED Color Capabilities: ");
598 	for (i = 0; i < 8; i++) {
599 		if (rsp->data[1] & (0x01 << i)) {
600 			printf("%s, ", led_color_str[i]);
601 		}
602 	}
603 	putchar('\n');
604 
605 	printf("Default LED Color in\n");
606 	printf("      LOCAL control:  %s\n", led_color_str[rsp->data[2]]);
607 	printf("      OVERRIDE state: %s\n", led_color_str[rsp->data[3]]);
608 
609 	if (rsp->data_len == 5) {
610 		printf("LED flags:\n");
611 		if (rsp->data[4] & 2) {
612 			printf("      [HW RESTRICT]\n");
613 		}
614 		if (rsp->data[4] & 1) {
615 			printf("      [PAYLOAD PWR]\n");
616 		}
617 	}
618 
619 	return 0;
620 }
621 
622 static int
623 ipmi_vita_get_led_state(struct ipmi_intf *intf, char **argv)
624 {
625 	struct ipmi_rs *rsp;
626 	struct ipmi_rq req;
627 	unsigned char msg_data[3];
628 
629 	memset(&req, 0, sizeof(req));
630 
631 	req.msg.netfn = IPMI_NETFN_PICMG;
632 	req.msg.cmd = VITA_GET_FRU_LED_STATE_CMD;
633 	req.msg.data = msg_data;
634 	req.msg.data_len = 3;
635 
636 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
637 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
638 		return -1;
639 	}
640 	if (str2uchar(argv[1], &msg_data[2]) != 0) {	/* LED-ID */
641 		return -1;
642 	}
643 
644 	rsp = intf->sendrecv(intf, &req);
645 
646 	if (rsp == NULL) {
647 		lprintf(LOG_ERR, "No valid response received.");
648 		return -1;
649 	} else if (rsp->ccode != 0) {
650 		lprintf(LOG_ERR, "Invalid completion code received: %s",
651 			val2str(rsp->ccode, completion_code_vals));
652 		return -1;
653 	} else if (rsp->data_len < 5
654 		|| ((rsp->data[1] & 0x2) && rsp->data_len < 8)
655 		|| ((rsp->data[1] & 0x4) && rsp->data_len < 9)) {
656 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
657 		return -1;
658 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
659 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
660 		return -1;
661 	}
662 
663 	printf("LED states:                   %x\t", rsp->data[1]);
664 	if (rsp->data[1] & 0x1) {
665 		printf("[LOCAL CONTROL] ");
666 	}
667 	if (rsp->data[1] & 0x2) {
668 		printf("[OVERRIDE] ");
669 	}
670 	if (rsp->data[1] & 0x4) {
671 		printf("[LAMPTEST] ");
672 	}
673 	if (rsp->data[1] & 0x8) {
674 		printf("[HW RESTRICT] ");
675 	}
676 	putchar('\n');
677 
678 	if (rsp->data[1] & 1) {
679 		printf("  Local Control function:     %x\t", rsp->data[2]);
680 		if (rsp->data[2] == 0x0) {
681 			printf("[OFF]\n");
682 		} else if (rsp->data[2] == 0xff) {
683 			printf("[ON]\n");
684 		} else {
685 			printf("[BLINKING]\n");
686 		}
687 		printf("  Local Control On-Duration:  %x\n", rsp->data[3]);
688 		printf("  Local Control Color:        %x\t[%s]\n",
689 			rsp->data[4], led_color_str[rsp->data[4] & 7]);
690 	}
691 
692 	/* override state or lamp test */
693 	if (rsp->data[1] & 0x06) {
694 		printf("  Override function:     %x\t", rsp->data[5]);
695 		if (rsp->data[5] == 0x0) {
696 			printf("[OFF]\n");
697 		} else if (rsp->data[5] == 0xff) {
698 			printf("[ON]\n");
699 		} else {
700 			printf("[BLINKING]\n");
701 		}
702 		printf("  Override On-Duration:  %x\n", rsp->data[6]);
703 		printf("  Override Color:        %x\t[%s]\n",
704 			rsp->data[7], led_color_str[rsp->data[7] & 7]);
705 		if (rsp->data[1] == 0x04) {
706 			printf("  Lamp test duration:    %x\n", rsp->data[8]);
707 		}
708 	}
709 
710 	return 0;
711 }
712 
713 static int
714 ipmi_vita_set_led_state(struct ipmi_intf *intf, char **argv)
715 {
716 	struct ipmi_rs *rsp;
717 	struct ipmi_rq req;
718 	unsigned char msg_data[6];
719 
720 	memset(&req, 0, sizeof(req));
721 
722 	req.msg.netfn = IPMI_NETFN_PICMG;
723 	req.msg.cmd = VITA_SET_FRU_LED_STATE_CMD;
724 	req.msg.data = msg_data;
725 	req.msg.data_len = 6;
726 
727 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
728 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
729 		return -1;
730 	}
731 	if (str2uchar(argv[1], &msg_data[2]) != 0) {	/* LED-ID */
732 		return -1;
733 	}
734 	if (str2uchar(argv[2], &msg_data[3]) != 0) {	/* LED function */
735 		return -1;
736 	}
737 	if (str2uchar(argv[3], &msg_data[4]) != 0) {	/* LED on duration */
738 		return -1;
739 	}
740 	if (str2uchar(argv[4], &msg_data[5]) != 0) {	/* LED color */
741 		return -1;
742 	}
743 
744 	rsp = intf->sendrecv(intf, &req);
745 
746 	if (rsp == NULL) {
747 		lprintf(LOG_ERR, "No valid response received.");
748 		return -1;
749 	} else if (rsp->ccode != 0) {
750 		lprintf(LOG_ERR, "Invalid completion code received: %s",
751 			val2str(rsp->ccode, completion_code_vals));
752 		return -1;
753 	} else if (rsp->data_len < 1) {
754 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
755 		return -1;
756 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
757 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
758 		return -1;
759 	}
760 
761 	printf("LED state has been updated\n");
762 
763 	return 0;
764 }
765 
766 static int
767 ipmi_vita_fru_control(struct ipmi_intf *intf, char **argv)
768 {
769 	struct ipmi_rs *rsp;
770 	struct ipmi_rq req;
771 	unsigned char msg_data[3];
772 
773 	memset(&req, 0, sizeof(req));
774 
775 	req.msg.netfn = IPMI_NETFN_PICMG;
776 	req.msg.cmd = VITA_FRU_CONTROL_CMD;
777 	req.msg.data = msg_data;
778 	req.msg.data_len = 3;
779 
780 	msg_data[0] = GROUP_EXT_VITA;			/* VITA identifier */
781 	if (is_fru_id(argv[0], &msg_data[1]) != 0) {	/* FRU ID */
782 		return -1;
783 	}
784 	if (str2uchar(argv[1], &msg_data[2]) != 0) {	/* control option */
785 		return -1;
786 	}
787 
788 	printf("FRU Device Id: %d FRU Control Option: %s\n", msg_data[1],
789 		val2str(msg_data[2], picmg_frucontrol_vals));
790 
791 	rsp = intf->sendrecv(intf, &req);
792 
793 	if (rsp == NULL) {
794 		lprintf(LOG_ERR, "No valid response received.");
795 		return -1;
796 	} else if (rsp->ccode != 0) {
797 		lprintf(LOG_ERR, "Invalid completion code received: %s",
798 			val2str(rsp->ccode, completion_code_vals));
799 		return -1;
800 	} else if (rsp->data_len < 1) {
801 		lprintf(LOG_ERR, "Invalid response length %d", rsp->data_len);
802 		return -1;
803 	} else if (rsp->data[0] != GROUP_EXT_VITA) {
804 		lprintf(LOG_ERR, "Invalid group extension %#x", rsp->data[0]);
805 		return -1;
806 	}
807 
808 	printf("FRU Control: ok\n");
809 
810 	return 0;
811 }
812 
813 static int
814 ipmi_vita_get_cmd(int argc, char **argv)
815 {
816 	if (argc < 1 || !strncmp(argv[0], "help", 4)) {
817 		return VITA_CMD_HELP;
818 	}
819 
820 	/* Get VSO Properties */
821 	if (!strncmp(argv[0], "properties", 10)) {
822 		return VITA_CMD_PROPERTIES;
823 	}
824 
825 	/* FRU Control command */
826 	if (!strncmp(argv[0], "frucontrol", 10)) {
827 		return VITA_CMD_FRUCONTROL;
828 	}
829 
830 	/* Get FRU Address Info command */
831 	if (!strncmp(argv[0], "addrinfo", 8)) {
832 		return VITA_CMD_ADDRINFO;
833 	}
834 
835 	/* Set FRU Activation (activate) command */
836 	if (!strncmp(argv[0], "activate", 8)) {
837 		return VITA_CMD_ACTIVATE;
838 	}
839 
840 	/* Set FRU Activation (deactivate) command */
841 	if (!strncmp(argv[0], "deactivate", 10)) {
842 		return VITA_CMD_DEACTIVATE;
843 	}
844 
845 	/* FRU State Policy Bits commands */
846 	if (!strncmp(argv[0], "policy", 6)) {
847 		if (argc < 2) {
848 			return VITA_CMD_UNKNOWN;
849 		}
850 
851 		/* Get FRU State Policy Bits command */
852 		if (!strncmp(argv[1], "get", 3)) {
853 			return VITA_CMD_POLICY_GET;
854 		}
855 
856 		/* Set FRU State Policy Bits command */
857 		if (!strncmp(argv[1], "set", 3)) {
858 			return VITA_CMD_POLICY_SET;
859 		}
860 
861 		/* unknown command */
862 		return VITA_CMD_UNKNOWN;
863 	}
864 
865 	/* FRU LED commands */
866 	if (!strncmp(argv[0], "led", 3)) {
867 		if (argc < 2) {
868 			return VITA_CMD_UNKNOWN;
869 		}
870 
871 		/* FRU LED Get Properties */
872 		if (!strncmp(argv[1], "prop", 4)) {
873 			return VITA_CMD_LED_PROP;
874 		}
875 
876 		/* FRU LED Get Capabilities */
877 		if (!strncmp(argv[1], "cap", 3)) {
878 			return VITA_CMD_LED_CAP;
879 		}
880 
881 		/* FRU LED Get State */
882 		if (!strncmp(argv[1], "get", 3)) {
883 			return VITA_CMD_LED_GET;
884 		}
885 
886 		/* FRU LED Set State */
887 		if (!strncmp(argv[1], "set", 3)) {
888 			return VITA_CMD_LED_SET;
889 		}
890 
891 		/* unknown command */
892 		return VITA_CMD_UNKNOWN;
893 	}
894 
895 	/* unknown command */
896 	return VITA_CMD_UNKNOWN;
897 }
898 
899 int
900 ipmi_vita_main (struct ipmi_intf *intf, int argc, char **argv)
901 {
902 	int rc = -1, show_help = 0;
903 	int cmd = ipmi_vita_get_cmd(argc, argv);
904 
905 	switch (cmd) {
906 	case VITA_CMD_HELP:
907 		cmd = ipmi_vita_get_cmd(argc - 1, &argv[1]);
908 		show_help = 1;
909 		rc = 0;
910 		break;
911 
912 	case VITA_CMD_PROPERTIES:
913 		rc = ipmi_vita_get_vso_capabilities(intf);
914 		break;
915 
916 	case VITA_CMD_FRUCONTROL:
917 		if (argc > 2) {
918 			rc = ipmi_vita_fru_control(intf, &argv[1]);
919 		} else {
920 			show_help = 1;
921 		}
922 		break;
923 
924 	case VITA_CMD_ADDRINFO:
925 		rc = ipmi_vita_getaddr(intf, argc - 1, &argv[1]);
926 		break;
927 
928 	case VITA_CMD_ACTIVATE:
929 		if (argc > 1) {
930 			rc = ipmi_vita_set_fru_activation(intf, &argv[1], 1);
931 		} else {
932 			show_help = 1;
933 		}
934 		break;
935 
936 	case VITA_CMD_DEACTIVATE:
937 		if (argc > 1) {
938 			rc = ipmi_vita_set_fru_activation(intf, &argv[1], 0);
939 		} else {
940 			show_help = 1;
941 		}
942 		break;
943 
944 	case VITA_CMD_POLICY_GET:
945 		if (argc > 2) {
946 			rc = ipmi_vita_get_fru_state_policy_bits(intf,
947 				&argv[2]);
948 		} else {
949 			show_help = 1;
950 		}
951 		break;
952 
953 	case VITA_CMD_POLICY_SET:
954 		if (argc > 4) {
955 			rc = ipmi_vita_set_fru_state_policy_bits(intf,
956 				&argv[2]);
957 		} else {
958 			show_help = 1;
959 		}
960 		break;
961 
962 	case VITA_CMD_LED_PROP:
963 		if (argc > 2) {
964 			rc = ipmi_vita_get_led_properties(intf, &argv[2]);
965 		} else {
966 			show_help = 1;
967 		}
968 		break;
969 
970 	case VITA_CMD_LED_CAP:
971 		if (argc > 3) {
972 			rc = ipmi_vita_get_led_color_capabilities(intf,
973 				&argv[2]);
974 		} else {
975 			show_help = 1;
976 		}
977 		break;
978 
979 	case VITA_CMD_LED_GET:
980 		if (argc > 3) {
981 			rc = ipmi_vita_get_led_state(intf, &argv[2]);
982 		} else {
983 			show_help = 1;
984 		}
985 		break;
986 
987 	case VITA_CMD_LED_SET:
988 		if (argc > 6) {
989 			rc = ipmi_vita_set_led_state(intf, &argv[2]);
990 		} else {
991 			show_help = 1;
992 		}
993 		break;
994 	default:
995 		lprintf(LOG_NOTICE, "Unknown command");
996 		cmd = VITA_CMD_HELP;
997 		show_help = 1;
998 		break;
999 	}
1000 
1001 	if (show_help) {
1002 		lprintf(LOG_NOTICE, "%s", val2str(cmd, vita_help_strings));
1003 	}
1004 
1005 	return rc;
1006 }
1007