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