xref: /openbmc/ipmitool/lib/ipmi_chassis.c (revision 6ca88cb6)
1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights 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 Sun Microsystems, Inc. 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  * SUN MICROSYSTEMS, INC. ("SUN") 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  * SUN 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 SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  */
32 
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <time.h>
37 
38 #include <ipmitool/bswap.h>
39 #include <ipmitool/helper.h>
40 #include <ipmitool/ipmi.h>
41 #include <ipmitool/log.h>
42 #include <ipmitool/ipmi_intf.h>
43 #include <ipmitool/ipmi_strings.h>
44 #include <ipmitool/ipmi_chassis.h>
45 
46 extern int verbose;
47 
48 int
49 ipmi_chassis_power_status(struct ipmi_intf * intf)
50 {
51 	struct ipmi_rs * rsp;
52 	struct ipmi_rq req;
53 
54 	memset(&req, 0, sizeof(req));
55 	req.msg.netfn = IPMI_NETFN_CHASSIS;
56 	req.msg.cmd = 0x1;
57 	req.msg.data_len = 0;
58 
59 	rsp = intf->sendrecv(intf, &req);
60 	if (rsp == NULL) {
61 		lprintf(LOG_ERR, "Unable to get Chassis Power Status");
62 		return -1;
63 	}
64 	if (rsp->ccode > 0) {
65 		lprintf(LOG_ERR, "Get Chassis Power Status failed: %s",
66 				val2str(rsp->ccode, completion_code_vals));
67 		return -1;
68 	}
69 
70 	return rsp->data[0] & 1;
71 }
72 
73 static int
74 ipmi_chassis_print_power_status(struct ipmi_intf * intf)
75 {
76 	int ps = ipmi_chassis_power_status(intf);
77 
78 	if (ps < 0)
79 		return -1;
80 
81 	printf("Chassis Power is %s\n", ps ? "on" : "off");
82 
83 	return 0;
84 }
85 
86 int
87 ipmi_chassis_power_control(struct ipmi_intf * intf, uint8_t ctl)
88 {
89 	struct ipmi_rs * rsp;
90 	struct ipmi_rq req;
91 
92 	memset(&req, 0, sizeof(req));
93 	req.msg.netfn = IPMI_NETFN_CHASSIS;
94 	req.msg.cmd = 0x2;
95 	req.msg.data = &ctl;
96 	req.msg.data_len = 1;
97 
98 	rsp = intf->sendrecv(intf, &req);
99 	if (rsp == NULL) {
100 		lprintf(LOG_ERR, "Unable to set Chassis Power Control to %s",
101 				val2str(ctl, ipmi_chassis_power_control_vals));
102 		return -1;
103 	}
104 	if (rsp->ccode > 0) {
105 		lprintf(LOG_ERR, "Set Chassis Power Control to %s failed: %s",
106 				val2str(ctl, ipmi_chassis_power_control_vals),
107 				val2str(rsp->ccode, completion_code_vals));
108 		return -1;
109 	}
110 
111 	printf("Chassis Power Control: %s\n",
112 			val2str(ctl, ipmi_chassis_power_control_vals));
113 
114 #if 0	/* this can cause sessions to hang around after power commands */
115 	/* sessions often get lost when changing chassis power */
116 	intf->abort = 1;
117 #endif
118 
119 	return 0;
120 }
121 
122 static int
123 ipmi_chassis_identify(struct ipmi_intf * intf, char * arg)
124 {
125 	struct ipmi_rq req;
126 	struct ipmi_rs * rsp;
127 	int rc = (-3);
128 
129 	struct {
130 		uint8_t interval;
131 		uint8_t force_on;
132 	} identify_data = { .interval = 0, .force_on = 0 };
133 
134 	memset(&req, 0, sizeof(req));
135 	req.msg.netfn = IPMI_NETFN_CHASSIS;
136 	req.msg.cmd = 0x4;
137 
138 	if (arg != NULL) {
139 		if (strncmp(arg, "force", 5) == 0) {
140 			identify_data.force_on = 1;
141 		} else {
142 			if ( (rc = str2uchar(arg, &identify_data.interval)) != 0) {
143 				if (rc == (-2)) {
144 					lprintf(LOG_ERR, "Invalid interval given.");
145 				} else {
146 					lprintf(LOG_ERR, "Given interval is too big.");
147 				}
148 				return (-1);
149 			}
150 		}
151 		req.msg.data = (uint8_t *)&identify_data;
152 		/* The Force Identify On byte is optional and not
153 		 * supported by all devices-- if force is not specified,
154 		 * we pass only one data byte; if specified, we pass two
155 		 * data bytes and check for an error completion code
156 		 */
157 		req.msg.data_len = (identify_data.force_on) ? 2 : 1;
158 	}
159 
160 	rsp = intf->sendrecv(intf, &req);
161 	if (rsp == NULL) {
162 		lprintf(LOG_ERR, "Unable to set Chassis Identify");
163 		return -1;
164 	}
165 	if (rsp->ccode > 0) {
166 		lprintf(LOG_ERR, "Set Chassis Identify failed: %s",
167 				val2str(rsp->ccode, completion_code_vals));
168 		if (identify_data.force_on != 0) {
169 			/* Intel SE7501WV2 F/W 1.2 returns CC 0xC7, but
170 			 * the IPMI v1.5 spec does not standardize a CC
171 			 * if unsupported, so we warn
172 			 */
173 			lprintf(LOG_WARNING, "Chassis may not support Force Identify On\n");
174 		}
175 		return -1;
176 	}
177 
178 	printf("Chassis identify interval: ");
179 	if (arg == NULL) {
180 		printf("default (15 seconds)\n");
181 	} else {
182 		if (identify_data.force_on != 0) {
183 			printf("indefinite\n");
184 		} else {
185 			if (identify_data.interval == 0)
186 				printf("off\n");
187 			else
188 				printf("%i seconds\n", identify_data.interval);
189 		}
190 	}
191 	return 0;
192 }
193 
194 static int
195 ipmi_chassis_poh(struct ipmi_intf * intf)
196 {
197 	struct ipmi_rs * rsp;
198 	struct ipmi_rq req;
199 	uint8_t mins_per_count;
200 	uint32_t count;
201 	float minutes;
202 	uint32_t days, hours;
203 
204 	memset(&req, 0, sizeof(req));
205 	req.msg.netfn = IPMI_NETFN_CHASSIS;
206 	req.msg.cmd = 0xf;
207 
208 	rsp = intf->sendrecv(intf, &req);
209 	if (rsp == NULL) {
210 		lprintf(LOG_ERR, "Unable to get Chassis Power-On-Hours");
211 		return -1;
212 	}
213 	if (rsp->ccode > 0) {
214 		lprintf(LOG_ERR, "Get Chassis Power-On-Hours failed: %s",
215 				val2str(rsp->ccode, completion_code_vals));
216 		return -1;
217 	}
218 
219 	mins_per_count = rsp->data[0];
220 	memcpy(&count, rsp->data+1, 4);
221 #if WORDS_BIGENDIAN
222 	count = BSWAP_32(count);
223 #endif
224 
225 	minutes = (float)count * mins_per_count;
226 	days = minutes / 1440;
227 	minutes -= (float)days * 1440;
228 	hours = minutes / 60;
229 	minutes -= hours * 60;
230 
231 	if (mins_per_count < 60) {
232 		printf("POH Counter  : %i days, %i hours, %li minutes\n",
233 				days, hours, (long)minutes);
234 	} else {
235 		printf("POH Counter  : %i days, %i hours\n", days, hours);
236 	}
237 
238 	return 0;
239 }
240 
241 static int
242 ipmi_chassis_restart_cause(struct ipmi_intf * intf)
243 {
244 	struct ipmi_rs * rsp;
245 	struct ipmi_rq req;
246 
247 	memset(&req, 0, sizeof(req));
248 	req.msg.netfn = IPMI_NETFN_CHASSIS;
249 	req.msg.cmd = 0x7;
250 
251 	rsp = intf->sendrecv(intf, &req);
252 	if (rsp == NULL) {
253 		lprintf(LOG_ERR, "Unable to get Chassis Restart Cause");
254 		return -1;
255 	}
256 	if (rsp->ccode > 0) {
257 		lprintf(LOG_ERR, "Get Chassis Restart Cause failed: %s",
258 				val2str(rsp->ccode, completion_code_vals));
259 		return -1;
260 	}
261 
262 	printf("System restart cause: ");
263 
264 	switch (rsp->data[0] & 0xf) {
265 	case 0:
266 		printf("unknown\n");
267 		break;
268 	case 1:
269 		printf("chassis power control command\n");
270 		break;
271 	case 2:
272 		printf("reset via pushbutton\n");
273 		break;
274 	case 3:
275 		printf("power-up via pushbutton\n");
276 		break;
277 	case 4:
278 		printf("watchdog expired\n");
279 		break;
280 	case 5:
281 		printf("OEM\n");
282 		break;
283 	case 6:
284 		printf("power-up due to always-restore power policy\n");
285 		break;
286 	case 7:
287 		printf("power-up due to restore-previous power policy\n");
288 		break;
289 	case 8:
290 		printf("reset via PEF\n");
291 		break;
292 	case 9:
293 		printf("power-cycle via PEF\n");
294 		break;
295 	default:
296 		printf("invalid\n");
297 	}
298 
299 	return 0;
300 }
301 
302 int
303 ipmi_chassis_status(struct ipmi_intf * intf)
304 {
305 	struct ipmi_rs * rsp;
306 	struct ipmi_rq req;
307 
308 	memset(&req, 0, sizeof(req));
309 	req.msg.netfn = IPMI_NETFN_CHASSIS;
310 	req.msg.cmd = 0x1;
311 
312 	rsp = intf->sendrecv(intf, &req);
313 	if (rsp == NULL) {
314 		lprintf(LOG_ERR, "Error sending Chassis Status command");
315 		return -1;
316 	}
317 	if (rsp->ccode > 0) {
318 		lprintf(LOG_ERR, "Error sending Chassis Status command: %s",
319 				val2str(rsp->ccode, completion_code_vals));
320 		return -1;
321 	}
322 
323 	/* byte 1 */
324 	printf("System Power         : %s\n", (rsp->data[0] & 0x1) ? "on" : "off");
325 	printf("Power Overload       : %s\n", (rsp->data[0] & 0x2) ? "true" : "false");
326 	printf("Power Interlock      : %s\n", (rsp->data[0] & 0x4) ? "active" : "inactive");
327 	printf("Main Power Fault     : %s\n", (rsp->data[0] & 0x8) ? "true" : "false");
328 	printf("Power Control Fault  : %s\n", (rsp->data[0] & 0x10) ? "true" : "false");
329 	printf("Power Restore Policy : ");
330 	switch ((rsp->data[0] & 0x60) >> 5) {
331 	case 0x0:
332 		printf("always-off\n");
333 		break;
334 	case 0x1:
335 		printf("previous\n");
336 		break;
337 	case 0x2:
338 		printf("always-on\n");
339 		break;
340 	case 0x3:
341 	default:
342 		printf("unknown\n");
343 	}
344 
345 	/* byte 2 */
346 	printf("Last Power Event     : ");
347 	if (rsp->data[1] & 0x1)
348 		printf("ac-failed ");
349 	if (rsp->data[1] & 0x2)
350 		printf("overload ");
351 	if (rsp->data[1] & 0x4)
352 		printf("interlock ");
353 	if (rsp->data[1] & 0x8)
354 		printf("fault ");
355 	if (rsp->data[1] & 0x10)
356 		printf("command");
357 	printf("\n");
358 
359 	/* byte 3 */
360 	printf("Chassis Intrusion    : %s\n", (rsp->data[2] & 0x1) ? "active" : "inactive");
361 	printf("Front-Panel Lockout  : %s\n", (rsp->data[2] & 0x2) ? "active" : "inactive");
362 	printf("Drive Fault          : %s\n", (rsp->data[2] & 0x4) ? "true" : "false");
363 	printf("Cooling/Fan Fault    : %s\n", (rsp->data[2] & 0x8) ? "true" : "false");
364 
365 	if (rsp->data_len > 3) {
366 		/* optional byte 4 */
367 		if (rsp->data[3] == 0) {
368 			printf("Front Panel Control  : none\n");
369 		} else {
370 			printf("Sleep Button Disable : %s\n", (rsp->data[3] & 0x80) ? "allowed" : "not allowed");
371 			printf("Diag Button Disable  : %s\n", (rsp->data[3] & 0x40) ? "allowed" : "not allowed");
372 			printf("Reset Button Disable : %s\n", (rsp->data[3] & 0x20) ? "allowed" : "not allowed");
373 			printf("Power Button Disable : %s\n", (rsp->data[3] & 0x10) ? "allowed" : "not allowed");
374 			printf("Sleep Button Disabled: %s\n", (rsp->data[3] & 0x08) ? "true" : "false");
375 			printf("Diag Button Disabled : %s\n", (rsp->data[3] & 0x04) ? "true" : "false");
376 			printf("Reset Button Disabled: %s\n", (rsp->data[3] & 0x02) ? "true" : "false");
377 			printf("Power Button Disabled: %s\n", (rsp->data[3] & 0x01) ? "true" : "false");
378 		}
379 	}
380 
381 	return 0;
382 }
383 
384 
385 static int
386 ipmi_chassis_selftest(struct ipmi_intf * intf)
387 {
388 	struct ipmi_rs * rsp;
389 	struct ipmi_rq req;
390 
391 	memset(&req, 0, sizeof(req));
392 	req.msg.netfn = IPMI_NETFN_APP;
393 	req.msg.cmd = 0x4;
394 
395 	rsp = intf->sendrecv(intf, &req);
396 	if (rsp == NULL) {
397 		lprintf(LOG_ERR, "Error sending Get Self Test command");
398 		return -1;
399 	}
400 	if (rsp->ccode > 0) {
401 		lprintf(LOG_ERR, "Error sending Get Self Test command: %s",
402 				val2str(rsp->ccode, completion_code_vals));
403 		return -1;
404 	}
405 
406 	printf("Self Test Results    : ");
407 	switch (rsp->data[0]) {
408 	case 0x55:
409 		printf("passed\n");
410 		break;
411 
412 	case 0x56:
413 		printf("not implemented\n");
414 		break;
415 
416 	case 0x57:
417 	{
418 		int i;
419 		const struct valstr broken_dev_vals[] = {
420 			{ 0, "firmware corrupted" },
421 			{ 1, "boot block corrupted" },
422 			{ 2, "FRU Internal Use Area corrupted" },
423 			{ 3, "SDR Repository empty" },
424 			{ 4, "IPMB not responding" },
425 			{ 5, "cannot access BMC FRU" },
426 			{ 6, "cannot access SDR Repository" },
427 			{ 7, "cannot access SEL Device" },
428 			{ 0xff, NULL },
429 		};
430 		printf("device error\n");
431 		for (i=0; i<8; i++) {
432 			if (rsp->data[1] & (1<<i)) {
433 				printf("                       [%s]\n",
434 						val2str(i, broken_dev_vals));
435 			}
436 		}
437 	}
438 	break;
439 
440 	case 0x58:
441 		printf("Fatal hardware error: %02xh\n", rsp->data[1]);
442 		break;
443 
444 	default:
445 		printf("Device-specific failure %02xh:%02xh\n",
446 				rsp->data[0], rsp->data[1]);
447 		break;
448 	}
449 
450 	return 0;
451 }
452 
453 static int
454 ipmi_chassis_set_bootparam(struct ipmi_intf * intf, uint8_t param, uint8_t * data, int len)
455 {
456 	struct ipmi_rs * rsp;
457 	struct ipmi_rq req;
458 	uint8_t msg_data[16];
459 
460 	memset(msg_data, 0, 16);
461 	msg_data[0] = param & 0x7f;
462 	memcpy(msg_data+1, data, len);
463 
464 	memset(&req, 0, sizeof(req));
465 	req.msg.netfn = IPMI_NETFN_CHASSIS;
466 	req.msg.cmd = 0x8;
467 	req.msg.data = msg_data;
468 	req.msg.data_len = len + 1;
469 
470 	rsp = intf->sendrecv(intf, &req);
471 	if (rsp == NULL) {
472 		lprintf(LOG_ERR, "Error setting Chassis Boot Parameter %d", param);
473 		return -1;
474 	}
475 	if (rsp->ccode > 0) {
476 		if (param != 0) {
477 			lprintf(LOG_ERR, "Set Chassis Boot Parameter %d failed: %s",
478 					param, val2str(rsp->ccode, completion_code_vals));
479 		}
480 		return -1;
481 	}
482 
483 	lprintf(LOG_DEBUG, "Chassis Set Boot Parameter %d to %s", param, buf2str(data, len));
484 	return 0;
485 }
486 
487 static int
488 ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
489 {
490 	struct ipmi_rs * rsp;
491 	struct ipmi_rq req;
492 	uint8_t msg_data[3];
493 	uint8_t param_id = 0;
494 
495 	if (arg == NULL)
496 		return -1;
497 
498 	if (str2uchar(arg, &param_id) != 0) {
499 		lprintf(LOG_ERR, "Invalid parameter '%s' given instead of bootparam.",
500 				arg);
501 		return (-1);
502 	}
503 
504 	memset(msg_data, 0, 3);
505 
506 	msg_data[0] = param_id & 0x7f;
507 	msg_data[1] = 0;
508 	msg_data[2] = 0;
509 
510 	memset(&req, 0, sizeof(req));
511 	req.msg.netfn = IPMI_NETFN_CHASSIS;
512 	req.msg.cmd = 0x9;
513 	req.msg.data = msg_data;
514 	req.msg.data_len = 3;
515 
516 	rsp = intf->sendrecv(intf, &req);
517 	if (rsp == NULL) {
518 		lprintf(LOG_ERR, "Error Getting Chassis Boot Parameter %s", arg);
519 		return -1;
520 	}
521 	if (rsp->ccode > 0) {
522 		lprintf(LOG_ERR, "Get Chassis Boot Parameter %s failed: %s",
523 				arg, val2str(rsp->ccode, completion_code_vals));
524 		return -1;
525 	}
526 
527 	if (verbose > 2)
528 		printbuf(rsp->data, rsp->data_len, "Boot Option");
529 
530 	param_id = 0;
531 	param_id = (rsp->data[1] & 0x7f);
532 
533 	printf("Boot parameter version: %d\n", rsp->data[0]);
534 	printf("Boot parameter %d is %s\n", rsp->data[1] & 0x7f,
535 			(rsp->data[1] & 0x80) ? "invalid/locked" : "valid/unlocked");
536 	printf("Boot parameter data: %s\n", buf2str(rsp->data+2, rsp->data_len - 2));
537 
538 	switch(param_id)
539 	{
540 		case 0:
541 		{
542 			printf(" Set In Progress : ");
543 			switch((rsp->data[2]) &0x03)
544 			{
545 				case 0: printf("set complete\n"); break;
546 				case 1: printf("set in progress\n"); break;
547 				case 2: printf("commit write\n"); break;
548 				default: printf("error, reserved bit\n"); break;
549 			}
550 		}
551 		break;
552 		case 1:
553 		{
554 			printf(" Service Partition Selector : ");
555 			if((rsp->data[2]) == 0)
556 			{
557 				printf("unspecified\n");
558 			}
559 			else
560 			{
561 				printf("%d\n",(rsp->data[2]));
562 			}
563 		}
564 		break;
565 		case 2:
566 		{
567 			printf(   " Service Partition Scan :\n");
568 			if((rsp->data[2]&0x03) != 0)
569 			{
570 				if((rsp->data[2]&0x01) == 0x01)
571 					printf("     - Request BIOS to scan\n");
572 				if((rsp->data[2]&0x02) == 0x02)
573 					printf("     - Service Partition Discovered\n");
574 			}
575 			else
576 			{
577 				printf("     No flag set\n");
578 			}
579 		}
580 		break;
581 		case 3:
582 		{
583 			printf(   " BMC boot flag valid bit clearing :\n");
584 			if((rsp->data[2]&0x1f) != 0)
585 			{
586 				if((rsp->data[2]&0x10) == 0x10)
587 					printf("     - Don't clear valid bit on reset/power cycle cause by PEF\n");
588 				if((rsp->data[2]&0x08) == 0x08)
589 					printf("     - Don't automatically clear boot flag valid bit on timeout\n");
590 				if((rsp->data[2]&0x04) == 0x04)
591 					printf("     - Don't clear valid bit on reset/power cycle cause by watchdog\n");
592 				if((rsp->data[2]&0x02) == 0x02)
593 					printf("     - Don't clear valid bit on push button reset // soft reset\n");
594 				if((rsp->data[2]&0x01) == 0x01)
595 					printf("     - Don't clear valid bit on power up via power push button or wake event\n");
596 			}
597 			else
598 			{
599 				printf("     No flag set\n");
600 			}
601 		}
602 		break;
603 		case 4:
604 		{
605 			printf(   " Boot Info Acknowledge :\n");
606 			if((rsp->data[3]&0x1f) != 0)
607 			{
608 				if((rsp->data[3]&0x10) == 0x10)
609 					printf("    - OEM has handled boot info\n");
610 				if((rsp->data[3]&0x08) == 0x08)
611 					printf("    - SMS has handled boot info\n");
612 				if((rsp->data[3]&0x04) == 0x04)
613 					printf("    - OS // service partition has handled boot info\n");
614 				if((rsp->data[3]&0x02) == 0x02)
615 					printf("    - OS Loader has handled boot info\n");
616 				if((rsp->data[3]&0x01) == 0x01)
617 					printf("    - BIOS/POST has handled boot info\n");
618 			}
619 			else
620 			{
621 				printf("     No flag set\n");
622 			}
623 		}
624 		break;
625 		case 5:
626 		{
627 			printf(   " Boot Flags :\n");
628 
629 			if((rsp->data[2]&0x80) == 0x80)
630 				printf("   - Boot Flag Valid\n");
631 			else
632 				printf("   - Boot Flag Invalid\n");
633 
634 			if((rsp->data[2]&0x40) == 0x40)
635 				printf("   - Options apply to all future boots\n");
636 			else
637 				printf("   - Options apply to only next boot\n");
638 
639 			if((rsp->data[2]&0x20) == 0x20)
640 				printf("   - BIOS EFI boot \n");
641 			else
642 				printf("   - BIOS PC Compatible (legacy) boot \n");
643 
644 			if((rsp->data[3]&0x80) == 0x80)
645 				printf("   - CMOS Clear\n");
646 			if((rsp->data[3]&0x40) == 0x40)
647 				printf("   - Lock Keyboard\n");
648 			printf("   - Boot Device Selector : ");
649 			switch( ((rsp->data[3]>>2)&0x0f))
650 			{
651 				case 0: printf("No override\n"); break;
652 				case 1: printf("Force PXE\n"); break;
653 				case 2: printf("Force Boot from default Hard-Drive\n"); break;
654 				case 3: printf("Force Boot from default Hard-Drive, request Safe-Mode\n"); break;
655 				case 4: printf("Force Boot from Diagnostic Partition\n"); break;
656 				case 5: printf("Force Boot from CD/DVD\n"); break;
657 				case 6: printf("Force Boot into BIOS Setup\n"); break;
658 				case 15: printf("Force Boot from Floppy/primary removable media\n"); break;
659 				default: printf("Flag error\n"); break;
660 			}
661 			if((rsp->data[3]&0x02) == 0x02)
662 				printf("   - Screen blank\n");
663 			if((rsp->data[3]&0x01) == 0x01)
664 				printf("   - Lock out Reset buttons\n");
665 
666 			if((rsp->data[4]&0x80) == 0x80)
667 				printf("   - Lock out (power off/sleep request) vi Power Button\n");
668 			printf("   - Console Redirection control : ");
669 			switch( ((rsp->data[4]>>5)&0x03))
670 			{
671 				case 0: printf("System Default\n"); break;
672 				case 1: printf("Request Quiet Display\n"); break;
673 				case 2: printf("Request Verbose Display\n"); break;
674 				default: printf("Flag error\n"); break;
675 			}
676 			if((rsp->data[4]&0x10) == 0x10)
677 				printf("   - Force progress event traps\n");
678 			if((rsp->data[4]&0x08) == 0x08)
679 				printf("   - User password bypass\n");
680 			if((rsp->data[4]&0x04) == 0x04)
681 				printf("   - Lock Out Sleep Button\n");
682 			if((rsp->data[4]&0x02) == 0x02)
683 				printf("   - Lock Out Sleep Button\n");
684 			printf("   - BIOS verbosity : ");
685 			switch( ((rsp->data[4]>>0)&0x03))
686 			{
687 				case 0: printf("Console redirection occurs per BIOS configuration setting (default)\n"); break;
688 				case 1: printf("Suppress (skip) console redirection if enabled\n"); break;
689 				case 2: printf("Request console redirection be enabled\n"); break;
690 				default: printf("Flag error\n"); break;
691 			}
692 
693 			if((rsp->data[5]&0x08) == 0x08)
694 				printf("   - BIOS Shared Mode Override\n");
695 			printf("   - BIOS Mux Control Override : ");
696 			switch( ((rsp->data[5]>>0)&0x07))
697 			{
698 				case 0: printf("BIOS uses recommended setting of the mux at the end of POST\n"); break;
699 				case 1: printf("Requests BIOS to force mux to BMC at conclusion of POST/start of OS boot\n"); break;
700 				case 2: printf("Requests BIOS to force mux to system at conclusion of POST/start of OS boot\n"); break;
701 				default: printf("Flag error\n"); break;
702 			}
703 		}
704 		break;
705 		case 6:
706 		{
707 			unsigned long session_id;
708 			unsigned long timestamp;
709 			char time_buf[40];
710 			time_t out_time;
711 
712 			session_id  = ((unsigned long) rsp->data[3]);
713 			session_id |= (((unsigned long) rsp->data[4])<<8);
714 			session_id |= (((unsigned long) rsp->data[5])<<16);
715 			session_id |= (((unsigned long) rsp->data[6])<<24);
716 
717 			timestamp  = ((unsigned long) rsp->data[7]);
718 			timestamp |= (((unsigned long) rsp->data[8])<<8);
719 			timestamp |= (((unsigned long) rsp->data[9])<<16);
720 			timestamp |= (((unsigned long) rsp->data[10])<<24);
721 
722 			memset(time_buf, 0, 40);
723 			strftime(
724 					time_buf,
725 					sizeof(time_buf),
726 					"%m/%d/%Y %H:%M:%S", localtime(&out_time)
727 			);
728 
729 			printf(" Boot Initiator Info :\n");
730 			printf("    Channel Number : %d\n", (rsp->data[2] & 0x0f));
731 			printf("    Session Id     : %08lXh\n",session_id);
732 			if(timestamp != 0)
733 			{
734 				printf("    Timestamp      : %08lXh, %s\n",timestamp,time_buf);
735 			}
736 			else
737 			{
738 				printf("    Timestamp      : %08lXh, undefined\n",timestamp);
739 			}
740 
741 		}
742 		break;
743 		case 7:
744 		{
745 			printf(" Selector   : %d\n", rsp->data[2] );
746 			printf(" Block Data : %s\n", buf2str(rsp->data+3, rsp->data_len - 2));
747 		}
748 		break;
749 		default:
750 			printf(" Undefined byte\n");
751 			break;
752 	}
753 
754 	return 0;
755 }
756 
757 static int
758 get_bootparam_options(char *optstring,
759 		unsigned char *set_flag, unsigned char *clr_flag)
760 {
761 	char *token;
762 	char *saveptr = NULL;
763 	int optionError = 0;
764 	*set_flag = 0;
765 	*clr_flag = 0;
766 	static struct {
767 		char *name;
768 		unsigned char value;
769 		char *desc;
770 	} options[] = {
771 	{"PEF",          0x10,
772 	    "Clear valid bit on reset/power cycle cause by PEF"},
773 	{"timeout",      0x08,
774 	    "Automatically clear boot flag valid bit on timeout"},
775 	{"watchdog",     0x04,
776 	    "Clear valid bit on reset/power cycle cause by watchdog"},
777 	{"reset",        0x02,
778 	    "Clear valid bit on push button reset/soft reset"},
779 	{"power", 0x01,
780 	    "Clear valid bit on power up via power push button or wake event"},
781 
782 	{NULL}	/* End marker */
783 	}, *op;
784 
785 	if (strncmp(optstring, "options=", 8) != 0) {
786 		lprintf(LOG_ERR, "No options= keyword found \"%s\"", optstring);
787 		return -1;
788 	}
789 	token = strtok_r(optstring + 8, ",", &saveptr);
790 	while (token != NULL) {
791 		int setbit = 0;
792 		if (strcmp(token, "help") == 0) {
793 			optionError = 1;
794 			break;
795 		}
796 		if (strncmp(token, "no-", 3) == 0) {
797 			setbit = 1;
798 			token += 3;
799 		}
800 		for (op = options; op->name != NULL; ++op) {
801 			if (strncmp(token, op->name, strlen(op->name)) == 0) {
802 				if (setbit) {
803 				    *set_flag |= op->value;
804 				} else {
805 				    *clr_flag |= op->value;
806 				}
807 				break;
808 			}
809 		}
810 		if (op->name == NULL) {
811 			/* Option not found */
812 			optionError = 1;
813 			if (setbit) {
814 				token -=3;
815 			}
816 			lprintf(LOG_ERR, "Invalid option: %s", token);
817 		}
818 		token = strtok_r(NULL, ",", &saveptr);
819 	}
820 	if (optionError) {
821 		lprintf(LOG_NOTICE, " Legal options are:");
822 		lprintf(LOG_NOTICE, "  %-8s: print this message", "help");
823 		for (op = options; op->name != NULL; ++op) {
824 			lprintf(LOG_NOTICE, "  %-8s: %s", op->name, op->desc);
825 		}
826 		lprintf(LOG_NOTICE, " Any Option may be prepended with no-"
827 				    " to invert sense of operation\n");
828 		return (-1);
829 	}
830 	return (0);
831 }
832 
833 static int
834 ipmi_chassis_get_bootvalid(struct ipmi_intf * intf)
835 {
836 	struct ipmi_rs * rsp;
837 	struct ipmi_rq req;
838 	uint8_t msg_data[3];
839 	uint8_t param_id = IPMI_CHASSIS_BOOTPARAM_FLAG_VALID;
840 	memset(msg_data, 0, 3);
841 
842 	msg_data[0] = param_id & 0x7f;
843 	msg_data[1] = 0;
844 	msg_data[2] = 0;
845 
846 	memset(&req, 0, sizeof(req));
847 	req.msg.netfn = IPMI_NETFN_CHASSIS;
848 	req.msg.cmd = 0x9;
849 	req.msg.data = msg_data;
850 	req.msg.data_len = 3;
851 
852 	rsp = intf->sendrecv(intf, &req);
853 	if (rsp == NULL) {
854 		lprintf(LOG_ERR,
855 			"Error Getting Chassis Boot Parameter %d", param_id);
856 		return -1;
857 	}
858 	if (rsp->ccode > 0) {
859 		lprintf(LOG_ERR, "Get Chassis Boot Parameter %d failed: %s",
860 			param_id, val2str(rsp->ccode, completion_code_vals));
861 		return -1;
862 	}
863 
864 	if (verbose > 2)
865 		printbuf(rsp->data, rsp->data_len, "Boot Option");
866 
867 	return(rsp->data[2]);
868 }
869 
870 static int
871 ipmi_chassis_set_bootvalid(struct ipmi_intf *intf, uint8_t set_flag, uint8_t clr_flag)
872 {
873 	int bootvalid;
874 	uint8_t flags[5];
875 	int rc = 0;
876 	int use_progress = 1;
877 	uint8_t param_id = IPMI_CHASSIS_BOOTPARAM_FLAG_VALID;
878 
879 	if (use_progress) {
880 		/* set set-in-progress flag */
881 		memset(flags, 0, 5);
882 		flags[0] = 0x01;
883 		rc = ipmi_chassis_set_bootparam(intf,
884 				IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, flags, 1);
885 		if (rc < 0)
886 			use_progress = 0;
887 	}
888 
889 	memset(flags, 0, 5);
890 	flags[0] = 0x01;
891 	flags[1] = 0x01;
892 	rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_INFO_ACK,
893 			flags, 2);
894 
895 	if (rc < 0) {
896 		if (use_progress) {
897 			/* set-in-progress = set-complete */
898 			memset(flags, 0, 5);
899 			ipmi_chassis_set_bootparam(intf,
900 					IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
901 					flags, 1);
902 		}
903 		return -1;
904 	}
905 
906 	bootvalid = ipmi_chassis_get_bootvalid(intf);
907 
908 	if (bootvalid < 0) {
909 		if (use_progress) {
910 			/* set-in-progress = set-complete */
911 			memset(flags, 0, 5);
912 			ipmi_chassis_set_bootparam(intf,
913 					IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
914 					flags, 1);
915 		}
916 		return -1;
917 	}
918 	flags[0] = (bootvalid & ~clr_flag) | set_flag;
919 
920 	rc = ipmi_chassis_set_bootparam(intf, param_id, flags, 1);
921 
922 	if (rc == 0) {
923 		if (use_progress) {
924 			/* set-in-progress = commit-write */
925 			memset(flags, 0, 5);
926 			flags[0] = 0x02;
927 			ipmi_chassis_set_bootparam(intf,
928 					IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
929 					flags, 1);
930 		}
931 	}
932 
933 	if (use_progress) {
934 		/* set-in-progress = set-complete */
935 		memset(flags, 0, 5);
936 		ipmi_chassis_set_bootparam(intf,
937 				IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
938 				flags, 1);
939 	}
940 
941 	return rc;
942 }
943 
944 static int
945 ipmi_chassis_set_bootdev(struct ipmi_intf * intf, char * arg, uint8_t *iflags)
946 {
947 	uint8_t flags[5];
948 	int rc = 0;
949 	int use_progress = 1;
950 
951 	if (use_progress) {
952 		/* set set-in-progress flag */
953 		memset(flags, 0, 5);
954 		flags[0] = 0x01;
955 		rc = ipmi_chassis_set_bootparam(intf,
956 				IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, flags, 1);
957 		if (rc < 0)
958 			use_progress = 0;
959 	}
960 
961 	memset(flags, 0, 5);
962 	flags[0] = 0x01;
963 	flags[1] = 0x01;
964 	rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_INFO_ACK,
965 			flags, 2);
966 
967 	if (rc < 0) {
968 		if (use_progress) {
969 			/* set-in-progress = set-complete */
970 			memset(flags, 0, 5);
971 			ipmi_chassis_set_bootparam(intf,
972 					IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
973 					flags, 1);
974 		}
975 		return -1;
976 	}
977 
978 	if (iflags == NULL)
979 		memset(flags, 0, 5);
980 	else
981 		memcpy(flags, iflags, sizeof (flags));
982 
983 	if (arg == NULL)
984 		flags[1] |= 0x00;
985 	else if (strncmp(arg, "none", 4) == 0)
986 		flags[1] |= 0x00;
987 	else if (strncmp(arg, "pxe", 3) == 0 ||
988 		strncmp(arg, "force_pxe", 9) == 0)
989 		flags[1] |= 0x04;
990 	else if (strncmp(arg, "disk", 4) == 0 ||
991 		strncmp(arg, "force_disk", 10) == 0)
992 		flags[1] |= 0x08;
993 	else if (strncmp(arg, "safe", 4) == 0 ||
994 		strncmp(arg, "force_safe", 10) == 0)
995 		flags[1] |= 0x0c;
996 	else if (strncmp(arg, "diag", 4) == 0 ||
997 		strncmp(arg, "force_diag", 10) == 0)
998 		flags[1] |= 0x10;
999 	else if (strncmp(arg, "cdrom", 5) == 0 ||
1000 		strncmp(arg, "force_cdrom", 11) == 0)
1001 		flags[1] |= 0x14;
1002 	else if (strncmp(arg, "floppy", 6) == 0 ||
1003 		strncmp(arg, "force_floppy", 12) == 0)
1004 		flags[1] |= 0x3c;
1005 	else if (strncmp(arg, "bios", 4) == 0 ||
1006 		strncmp(arg, "force_bios", 10) == 0)
1007 		flags[1] |= 0x18;
1008 	else {
1009 		lprintf(LOG_ERR, "Invalid argument: %s", arg);
1010 		if (use_progress) {
1011 			/* set-in-progress = set-complete */
1012 			memset(flags, 0, 5);
1013 			ipmi_chassis_set_bootparam(intf,
1014 					IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
1015 					flags, 1);
1016 		}
1017 		return -1;
1018 	}
1019 
1020 	/* set flag valid bit */
1021 	flags[0] |= 0x80;
1022 
1023 	rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_BOOT_FLAGS,
1024 			flags, 5);
1025 	if (rc == 0) {
1026 		if (use_progress) {
1027 			/* set-in-progress = commit-write */
1028 			memset(flags, 0, 5);
1029 			flags[0] = 0x02;
1030 			ipmi_chassis_set_bootparam(intf,
1031 					IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
1032 					flags, 1);
1033 		}
1034 
1035 		printf("Set Boot Device to %s\n", arg);
1036 	}
1037 
1038 	if (use_progress) {
1039 		/* set-in-progress = set-complete */
1040 		memset(flags, 0, 5);
1041 		ipmi_chassis_set_bootparam(intf,
1042 				IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
1043 				flags, 1);
1044 	}
1045 
1046 	return rc;
1047 }
1048 
1049 static int
1050 ipmi_chassis_power_policy(struct ipmi_intf * intf, uint8_t policy)
1051 {
1052 	struct ipmi_rs * rsp;
1053 	struct ipmi_rq req;
1054 
1055 	memset(&req, 0, sizeof(req));
1056 	req.msg.netfn = IPMI_NETFN_CHASSIS;
1057 	req.msg.cmd = 0x6;
1058 	req.msg.data = &policy;
1059 	req.msg.data_len = 1;
1060 
1061 	rsp = intf->sendrecv(intf, &req);
1062 	if (rsp == NULL) {
1063 		lprintf(LOG_ERR, "Error in Power Restore Policy command");
1064 		return -1;
1065 	}
1066 	if (rsp->ccode > 0) {
1067 		lprintf(LOG_ERR, "Power Restore Policy command failed: %s",
1068 				val2str(rsp->ccode, completion_code_vals));
1069 		return -1;
1070 	}
1071 
1072 	if (policy == IPMI_CHASSIS_POLICY_NO_CHANGE) {
1073 		printf("Supported chassis power policy:  ");
1074 		if (rsp->data[0] & (1<<IPMI_CHASSIS_POLICY_ALWAYS_OFF))
1075 			printf("always-off ");
1076 		if (rsp->data[0] & (1<<IPMI_CHASSIS_POLICY_ALWAYS_ON))
1077 			printf("always-on ");
1078 		if (rsp->data[0] & (1<<IPMI_CHASSIS_POLICY_PREVIOUS))
1079 			printf("previous");
1080 		printf("\n");
1081 	}
1082 	else {
1083 		printf("Set chassis power restore policy to ");
1084 		switch (policy) {
1085 		case IPMI_CHASSIS_POLICY_ALWAYS_ON:
1086 			printf("always-on\n");
1087 			break;
1088 		case IPMI_CHASSIS_POLICY_ALWAYS_OFF:
1089 			printf("always-off\n");
1090 			break;
1091 		case IPMI_CHASSIS_POLICY_PREVIOUS:
1092 			printf("previous\n");
1093 			break;
1094 		default:
1095 			printf("unknown\n");
1096 		}
1097 	}
1098 	return 0;
1099 }
1100 
1101 int
1102 ipmi_power_main(struct ipmi_intf * intf, int argc, char ** argv)
1103 {
1104 	int rc = 0;
1105 	uint8_t ctl = 0;
1106 
1107 	if ((argc < 1) || (strncmp(argv[0], "help", 4) == 0)) {
1108 		lprintf(LOG_NOTICE, "chassis power Commands: status, on, off, cycle, reset, diag, soft");
1109 		return 0;
1110 	}
1111 	if (strncmp(argv[0], "status", 6) == 0) {
1112 		rc = ipmi_chassis_print_power_status(intf);
1113 		return rc;
1114 	}
1115 	if ((strncmp(argv[0], "up", 2) == 0) || (strncmp(argv[0], "on", 2) == 0))
1116 		ctl = IPMI_CHASSIS_CTL_POWER_UP;
1117 	else if ((strncmp(argv[0], "down", 4) == 0) || (strncmp(argv[0], "off", 3) == 0))
1118 		ctl = IPMI_CHASSIS_CTL_POWER_DOWN;
1119 	else if (strncmp(argv[0], "cycle", 5) == 0)
1120 		ctl = IPMI_CHASSIS_CTL_POWER_CYCLE;
1121 	else if (strncmp(argv[0], "reset", 5) == 0)
1122 		ctl = IPMI_CHASSIS_CTL_HARD_RESET;
1123 	else if (strncmp(argv[0], "diag", 4) == 0)
1124 		ctl = IPMI_CHASSIS_CTL_PULSE_DIAG;
1125 	else if ((strncmp(argv[0], "acpi", 4) == 0) || (strncmp(argv[0], "soft", 4) == 0))
1126 		ctl = IPMI_CHASSIS_CTL_ACPI_SOFT;
1127 	else {
1128 		lprintf(LOG_ERR, "Invalid chassis power command: %s", argv[0]);
1129 		return -1;
1130 	}
1131 
1132 	rc = ipmi_chassis_power_control(intf, ctl);
1133 	return rc;
1134 }
1135 
1136 void
1137 ipmi_chassis_set_bootflag_help()
1138 {
1139 	unsigned char set_flag;
1140 	unsigned char clr_flag;
1141 	lprintf(LOG_NOTICE, "bootparam set bootflag <device> [options=...]");
1142 	lprintf(LOG_NOTICE, " Legal devices are:");
1143 	lprintf(LOG_NOTICE, "  none        : No override");
1144 	lprintf(LOG_NOTICE, "  force_pxe   : Force PXE boot");
1145 	lprintf(LOG_NOTICE, "  force_disk  : Force boot from default Hard-drive");
1146 	lprintf(LOG_NOTICE, "  force_safe  : Force boot from default Hard-drive, request Safe Mode");
1147 	lprintf(LOG_NOTICE, "  force_diag  : Force boot from Diagnostic Partition");
1148 	lprintf(LOG_NOTICE, "  force_cdrom : Force boot from CD/DVD");
1149 	lprintf(LOG_NOTICE, "  force_bios  : Force boot into BIOS Setup");
1150 	get_bootparam_options("options=help", &set_flag, &clr_flag);
1151 }
1152 
1153 int
1154 ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
1155 {
1156 	int rc = 0;
1157 
1158 	if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
1159 		lprintf(LOG_NOTICE, "Chassis Commands:  status, power, identify, policy, restart_cause, poh, bootdev, bootparam, selftest");
1160 	}
1161 	else if (strncmp(argv[0], "status", 6) == 0) {
1162 		rc = ipmi_chassis_status(intf);
1163 	}
1164 	else if (strncmp(argv[0], "selftest", 8) == 0) {
1165 		rc = ipmi_chassis_selftest(intf);
1166 	}
1167 	else if (strncmp(argv[0], "power", 5) == 0) {
1168 		uint8_t ctl = 0;
1169 
1170 		if ((argc < 2) || (strncmp(argv[1], "help", 4) == 0)) {
1171 			lprintf(LOG_NOTICE, "chassis power Commands: status, on, off, cycle, reset, diag, soft");
1172 			return 0;
1173 		}
1174 		if (strncmp(argv[1], "status", 6) == 0) {
1175 			rc = ipmi_chassis_print_power_status(intf);
1176 			return rc;
1177 		}
1178 		if ((strncmp(argv[1], "up", 2) == 0) || (strncmp(argv[1], "on", 2) == 0))
1179 			ctl = IPMI_CHASSIS_CTL_POWER_UP;
1180 		else if ((strncmp(argv[1], "down", 4) == 0) || (strncmp(argv[1], "off", 3) == 0))
1181 			ctl = IPMI_CHASSIS_CTL_POWER_DOWN;
1182 		else if (strncmp(argv[1], "cycle", 5) == 0)
1183 			ctl = IPMI_CHASSIS_CTL_POWER_CYCLE;
1184 		else if (strncmp(argv[1], "reset", 5) == 0)
1185 			ctl = IPMI_CHASSIS_CTL_HARD_RESET;
1186 		else if (strncmp(argv[1], "diag", 4) == 0)
1187 			ctl = IPMI_CHASSIS_CTL_PULSE_DIAG;
1188 		else if ((strncmp(argv[1], "acpi", 4) == 0) || (strncmp(argv[1], "soft", 4) == 0))
1189 			ctl = IPMI_CHASSIS_CTL_ACPI_SOFT;
1190 		else {
1191 			lprintf(LOG_ERR, "Invalid chassis power command: %s", argv[1]);
1192 			return -1;
1193 		}
1194 
1195 		rc = ipmi_chassis_power_control(intf, ctl);
1196 	}
1197 	else if (strncmp(argv[0], "identify", 8) == 0) {
1198 		if (argc < 2) {
1199 			rc = ipmi_chassis_identify(intf, NULL);
1200 		}
1201 		else if (strncmp(argv[1], "help", 4) == 0) {
1202 			lprintf(LOG_NOTICE, "chassis identify <interval>");
1203 			lprintf(LOG_NOTICE, "                 default is 15 seconds");
1204 			lprintf(LOG_NOTICE, "                 0 to turn off");
1205 			lprintf(LOG_NOTICE, "                 force to turn on indefinitely");
1206 		} else {
1207 			rc = ipmi_chassis_identify(intf, argv[1]);
1208 		}
1209 	}
1210 	else if (strncmp(argv[0], "poh", 3) == 0) {
1211 		rc = ipmi_chassis_poh(intf);
1212 	}
1213 	else if (strncmp(argv[0], "restart_cause", 13) == 0) {
1214 		rc = ipmi_chassis_restart_cause(intf);
1215 	}
1216 	else if (strncmp(argv[0], "policy", 4) == 0) {
1217 		if ((argc < 2) || (strncmp(argv[1], "help", 4) == 0)) {
1218 			lprintf(LOG_NOTICE, "chassis policy <state>");
1219 			lprintf(LOG_NOTICE, "   list        : return supported policies");
1220 			lprintf(LOG_NOTICE, "   always-on   : turn on when power is restored");
1221 			lprintf(LOG_NOTICE, "   previous    : return to previous state when power is restored");
1222 			lprintf(LOG_NOTICE, "   always-off  : stay off after power is restored");
1223 		} else {
1224 			uint8_t ctl;
1225 			if (strncmp(argv[1], "list", 4) == 0)
1226 				ctl = IPMI_CHASSIS_POLICY_NO_CHANGE;
1227 			else if (strncmp(argv[1], "always-on", 9) == 0)
1228 				ctl = IPMI_CHASSIS_POLICY_ALWAYS_ON;
1229 			else if (strncmp(argv[1], "previous", 8) == 0)
1230 				ctl = IPMI_CHASSIS_POLICY_PREVIOUS;
1231 			else if (strncmp(argv[1], "always-off", 10) == 0)
1232 				ctl = IPMI_CHASSIS_POLICY_ALWAYS_OFF;
1233 			else {
1234 				lprintf(LOG_ERR, "Invalid chassis policy: %s", argv[1]);
1235 				return -1;
1236 			}
1237 			rc = ipmi_chassis_power_policy(intf, ctl);
1238 		}
1239 	}
1240 	else if (strncmp(argv[0], "bootparam", 9) == 0) {
1241 		if ((argc < 3) || (strncmp(argv[1], "help", 4) == 0)) {
1242 			lprintf(LOG_NOTICE, "bootparam get <param #>");
1243 		    ipmi_chassis_set_bootflag_help();
1244 		}
1245 		else {
1246 			if (strncmp(argv[1], "get", 3) == 0) {
1247 				rc = ipmi_chassis_get_bootparam(intf, argv[2]);
1248 			}
1249 			else if (strncmp(argv[1], "set", 3) == 0) {
1250 			    unsigned char set_flag=0;
1251 			    unsigned char clr_flag=0;
1252 				if (strncmp(argv[2], "help", 4) == 0  ||
1253 						argc < 4 || (argc >= 4 &&
1254 							 strncmp(argv[2], "bootflag", 8) != 0)) {
1255 					ipmi_chassis_set_bootflag_help();
1256 				} else {
1257 					if (argc == 5) {
1258 						get_bootparam_options(argv[4], &set_flag, &clr_flag);
1259 					}
1260 					rc = ipmi_chassis_set_bootdev(intf, argv[3], NULL);
1261 					if (argc == 5 && (set_flag != 0 || clr_flag != 0)) {
1262 						rc = ipmi_chassis_set_bootvalid(intf, set_flag, clr_flag);
1263 					}
1264 				}
1265 			}
1266 			else
1267 				lprintf(LOG_NOTICE, "bootparam get|set <option> [value ...]");
1268 		}
1269 	}
1270 	else if (strncmp(argv[0], "bootdev", 7) == 0) {
1271 		if ((argc < 2) || (strncmp(argv[1], "help", 4) == 0)) {
1272 			lprintf(LOG_NOTICE, "bootdev <device> [clear-cmos=yes|no]");
1273 			lprintf(LOG_NOTICE, "bootdev <device> [options=help,...]");
1274 			lprintf(LOG_NOTICE, "  none  : Do not change boot device order");
1275 			lprintf(LOG_NOTICE, "  pxe   : Force PXE boot");
1276 			lprintf(LOG_NOTICE, "  disk  : Force boot from default Hard-drive");
1277 			lprintf(LOG_NOTICE, "  safe  : Force boot from default Hard-drive, request Safe Mode");
1278 			lprintf(LOG_NOTICE, "  diag  : Force boot from Diagnostic Partition");
1279 			lprintf(LOG_NOTICE, "  cdrom : Force boot from CD/DVD");
1280 			lprintf(LOG_NOTICE, "  bios  : Force boot into BIOS Setup");
1281 			lprintf(LOG_NOTICE, "  floppy: Force boot from Floppy/primary removable media");
1282 		} else {
1283 			if (argc < 3)
1284 				rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
1285 			else if (strncmp(argv[2], "clear-cmos=", 11) == 0) {
1286 				if (strncmp(argv[2]+11, "yes", 3) == 0) {
1287 					uint8_t flags[5] = {0, (1<<7), 0, 0, 0};
1288 					rc = ipmi_chassis_set_bootdev(intf, argv[1], flags);
1289 				} else
1290 					rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
1291 			}
1292 			else if (strncmp(argv[2], "options=", 8) == 0) {
1293 				char *token;
1294 				char *saveptr = NULL;
1295 				int optionError = 0;
1296 				unsigned char flags[5];
1297 				static struct {
1298 					char *name;
1299 					int i;
1300 					unsigned char mask;
1301 					unsigned char value;
1302 					char *desc;
1303 				} options[] = {
1304 					/* data 1 */
1305 					{"valid", 0, (1<<7), (1<<7),
1306 						"Boot flags valid"},
1307 					{"persistent", 0, (1<<6), (1<<6),
1308 						"Changes are persistent for all future boots"},
1309 					{"efiboot", 0, (1<<5), (1<<5),
1310 						"Extensible Firmware Interface Boot (EFI)"},
1311 					/* data 2 */
1312 					{"clear-cmos", 1, (1<<7), (1<<7),
1313 						"CMOS clear"},
1314 					{"lockkbd", 1, (1<<6), (1<<6),
1315 						"Lock Keyboard"},
1316 					/* data2[5:2] is parsed elsewhere */
1317 					{"screenblank", 1, (1<<1), (1<<1),
1318 						"Screen Blank"},
1319 					{"lockoutreset", 1, (1<<0), (1<<0),
1320 						"Lock out Resetbuttons"},
1321 					/* data 3 */
1322 					{"lockout_power", 2, (1<<7), (1<<7),
1323 						"Lock out (power off/sleep request) via Power Button"},
1324 					{"verbose=default", 2, (3<<5), (0<<5),
1325 						"Request quiet BIOS display"},
1326 					{"verbose=no", 2, (3<<5), (1<<5),
1327 						"Request quiet BIOS display"},
1328 					{"verbose=yes", 2, (3<<5), (2<<5),
1329 						"Request verbose BIOS display"},
1330 					{"force_pet", 2, (1<<4), (1<<4),
1331 						"Force progress event traps"},
1332 					{"upw_bypass", 2, (1<<3), (1<<3),
1333 						"User password bypass"},
1334 					{"lockout_sleep", 2, (1<<2), (1<<2),
1335 						"Log Out Sleep Button"},
1336 					{"cons_redirect=default", 2, (3<<0), (0<<0),
1337 						"Console redirection occurs per BIOS configuration setting"},
1338 					{"cons_redirect=skip", 2, (3<<0), (1<<0),
1339 						"Suppress (skip) console redirection if enabled"},
1340 					{"cons_redirect=enable", 2, (3<<0), (2<<0),
1341 						"Suppress (skip) console redirection if enabled"},
1342 					/* data 4 */
1343 					/* data4[7:4] reserved */
1344 					/* data4[3] BIOS Shared Mode Override, not implemented here */
1345 					/* data4[2:0] BIOS Mux Control Override, not implemented here */
1346 
1347 					/* data5 reserved */
1348 
1349 					{NULL}	/* End marker */
1350 			}, *op;
1351 
1352 			memset(&flags[0], 0, sizeof(flags));
1353 			token = strtok_r(argv[2] + 8, ",", &saveptr);
1354 			while (token != NULL) {
1355 				if (strcmp(token, "help") == 0) {
1356 					optionError = 1;
1357 					break;
1358 				}
1359 				for (op = options; op->name != NULL; ++op) {
1360 					if (strcmp(token, op->name) == 0) {
1361 						flags[op->i] &= op->mask;
1362 						flags[op->i] |= op->value;
1363 						break;
1364 					}
1365 				}
1366 				if (op->name == NULL) {
1367 					/* Option not found */
1368 					optionError = 1;
1369 					lprintf(LOG_ERR, "Invalid option: %s", token);
1370 				}
1371 				token = strtok_r(NULL, ",", &saveptr);
1372 			}
1373 			if (optionError) {
1374 				lprintf(LOG_NOTICE, "Legal options settings are:");
1375 				lprintf(LOG_NOTICE, "\thelp:\tprint this message");
1376 				for (op = options; op->name != NULL; ++op) {
1377 					lprintf(LOG_NOTICE, "\t%s:\t%s", op->name, op->desc);
1378 				}
1379 				return (-1);
1380 			}
1381 			rc = ipmi_chassis_set_bootdev(intf, argv[1], flags);
1382 		}
1383 		else
1384 			rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
1385 		}
1386 	}
1387 	else {
1388 		lprintf(LOG_ERR, "Invalid Chassis command: %s", argv[0]);
1389 		return -1;
1390 	}
1391 
1392 	return rc;
1393 }
1394