xref: /openbmc/ipmitool/lib/ipmi_mc.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/helper.h>
39 #include <ipmitool/log.h>
40 #include <ipmitool/bswap.h>
41 #include <ipmitool/ipmi.h>
42 #include <ipmitool/ipmi_intf.h>
43 #include <ipmitool/ipmi_mc.h>
44 #include <ipmitool/ipmi_strings.h>
45 
46 extern int verbose;
47 
48 static int ipmi_sysinfo_main(struct ipmi_intf *intf, int argc, char ** argv,
49 		int is_set);
50 static void printf_sysinfo_usage(int full_help);
51 
52 /* ipmi_mc_reset  -  attempt to reset an MC
53  *
54  * @intf:	ipmi interface
55  * @cmd:	reset command to send
56  *              BMC_WARM_RESET or
57  *              BMC_COLD_RESET
58  *
59  * returns 0 on success
60  * returns -1 on error
61  */
62 static int
63 ipmi_mc_reset(struct ipmi_intf * intf, int cmd)
64 {
65 	struct ipmi_rs * rsp;
66 	struct ipmi_rq req;
67 
68 	if( !intf->opened )
69 	intf->open(intf);
70 
71 	memset(&req, 0, sizeof(req));
72 	req.msg.netfn = IPMI_NETFN_APP;
73 	req.msg.cmd = cmd;
74 	req.msg.data_len = 0;
75 
76 	if (cmd == BMC_COLD_RESET)
77 		intf->noanswer = 1;
78 
79 	rsp = intf->sendrecv(intf, &req);
80 
81 	if (cmd == BMC_COLD_RESET)
82 		intf->abort = 1;
83 
84 	if (cmd == BMC_COLD_RESET && rsp == NULL) {
85 		/* This is expected. See 20.2 Cold Reset Command, p.243, IPMIv2.0 rev1.0 */
86 	} else if (rsp == NULL) {
87 		lprintf(LOG_ERR, "MC reset command failed.");
88 		return (-1);
89 	} else if (rsp->ccode > 0) {
90 		lprintf(LOG_ERR, "MC reset command failed: %s",
91 				val2str(rsp->ccode, completion_code_vals));
92 		return (-1);
93 	}
94 
95 	printf("Sent %s reset command to MC\n",
96 	       (cmd == BMC_WARM_RESET) ? "warm" : "cold");
97 
98 	return 0;
99 }
100 
101 #ifdef HAVE_PRAGMA_PACK
102 #pragma pack(1)
103 #endif
104 struct bmc_enables_data {
105 #if WORDS_BIGENDIAN
106 	uint8_t oem2		: 1;
107 	uint8_t oem1		: 1;
108 	uint8_t oem0		: 1;
109 	uint8_t __reserved	: 1;
110 	uint8_t system_event_log	: 1;
111 	uint8_t event_msgbuf	: 1;
112 	uint8_t event_msgbuf_intr	: 1;
113 	uint8_t receive_msg_intr	: 1;
114 #else
115 	uint8_t receive_msg_intr	: 1;
116 	uint8_t event_msgbuf_intr	: 1;
117 	uint8_t event_msgbuf	: 1;
118 	uint8_t system_event_log	: 1;
119 	uint8_t __reserved	: 1;
120 	uint8_t oem0		: 1;
121 	uint8_t oem1		: 1;
122 	uint8_t oem2		: 1;
123 #endif
124 } ATTRIBUTE_PACKING;
125 #ifdef HAVE_PRAGMA_PACK
126 #pragma pack(0)
127 #endif
128 
129 struct bitfield_data {
130 	const char * name;
131 	const char * desc;
132 	uint32_t mask;
133 };
134 
135 struct bitfield_data mc_enables_bf[] = {
136 	{
137 		name:	"recv_msg_intr",
138 		desc:	"Receive Message Queue Interrupt",
139 		mask:	1<<0,
140 	},
141 	{
142 		name:	"event_msg_intr",
143 		desc:	"Event Message Buffer Full Interrupt",
144 		mask:	1<<1,
145 	},
146 	{
147 		name:	"event_msg",
148 		desc:	"Event Message Buffer",
149 		mask:	1<<2,
150 	},
151 	{
152 		name:	"system_event_log",
153 		desc:	"System Event Logging",
154 		mask:	1<<3,
155 	},
156 	{
157 		name:	"oem0",
158 		desc:	"OEM 0",
159 		mask:	1<<5,
160 	},
161 	{
162 		name:	"oem1",
163 		desc:	"OEM 1",
164 		mask:	1<<6,
165 	},
166 	{
167 		name:	"oem2",
168 		desc:	"OEM 2",
169 		mask:	1<<7,
170 	},
171 	{ NULL },
172 };
173 
174 static void
175 printf_mc_reset_usage(void)
176 {
177 	lprintf(LOG_NOTICE, "usage: mc reset <warm|cold>");
178 } /* printf_mc_reset_usage(void) */
179 
180 static void
181 printf_mc_usage(void)
182 {
183 	struct bitfield_data * bf;
184 	lprintf(LOG_NOTICE, "MC Commands:");
185 	lprintf(LOG_NOTICE, "  reset <warm|cold>");
186 	lprintf(LOG_NOTICE, "  guid");
187 	lprintf(LOG_NOTICE, "  info");
188 	lprintf(LOG_NOTICE, "  watchdog <get|reset|off>");
189 	lprintf(LOG_NOTICE, "  selftest");
190 	lprintf(LOG_NOTICE, "  getenables");
191 	lprintf(LOG_NOTICE, "  setenables <option=on|off> ...");
192 	for (bf = mc_enables_bf; bf->name != NULL; bf++) {
193 		lprintf(LOG_NOTICE, "    %-20s  %s", bf->name, bf->desc);
194 	}
195 	printf_sysinfo_usage(0);
196 }
197 
198 static void
199 printf_sysinfo_usage(int full_help)
200 {
201 	if (full_help != 0)
202 		lprintf(LOG_NOTICE, "usage:");
203 
204 	lprintf(LOG_NOTICE, "  getsysinfo <argument>");
205 
206 	if (full_help != 0) {
207 		lprintf(LOG_NOTICE,
208 				"    Retrieves system info from BMC for given argument");
209 	}
210 
211 	lprintf(LOG_NOTICE, "  setsysinfo <argument> <string>");
212 
213 	if (full_help != 0) {
214 		lprintf(LOG_NOTICE,
215 				"    Stores system info string for given argument to BMC");
216 		lprintf(LOG_NOTICE, "");
217 		lprintf(LOG_NOTICE, "  Valid arguments are:");
218 	}
219 	lprintf(LOG_NOTICE,
220 			"    system_fw_version   System firmware (e.g. BIOS) version");
221 	lprintf(LOG_NOTICE,
222 			"    primary_os_name     Primary operating system name");
223 	lprintf(LOG_NOTICE, "    os_name             Operating system name");
224 	lprintf(LOG_NOTICE,
225 			"    system_name         System Name of server(vendor dependent)");
226 	lprintf(LOG_NOTICE,
227 			"    delloem_os_version  Running version of operating system");
228 	lprintf(LOG_NOTICE, "    delloem_url         URL of BMC webserver");
229 	lprintf(LOG_NOTICE, "");
230 }
231 
232 static void
233 print_watchdog_usage(void)
234 {
235 	lprintf(LOG_NOTICE, "usage: watchdog <command>:");
236 	lprintf(LOG_NOTICE, "   get    :  Get Current Watchdog settings");
237 	lprintf(LOG_NOTICE, "   reset  :  Restart Watchdog timer based on most recent settings");
238 	lprintf(LOG_NOTICE, "   off    :  Shut off a running Watchdog timer");
239 }
240 
241 /* ipmi_mc_get_enables  -  print out MC enables
242  *
243  * @intf:	ipmi inteface
244  *
245  * returns 0 on success
246  * returns -1 on error
247  */
248 static int
249 ipmi_mc_get_enables(struct ipmi_intf * intf)
250 {
251 	struct ipmi_rs * rsp;
252 	struct ipmi_rq req;
253 	struct bitfield_data * bf;
254 
255 	memset(&req, 0, sizeof(req));
256 	req.msg.netfn = IPMI_NETFN_APP;
257 	req.msg.cmd = BMC_GET_GLOBAL_ENABLES;
258 
259 	rsp = intf->sendrecv(intf, &req);
260 	if (rsp == NULL) {
261 		lprintf(LOG_ERR, "Get Global Enables command failed");
262 		return -1;
263 	}
264 	if (rsp->ccode > 0) {
265 		lprintf(LOG_ERR, "Get Global Enables command failed: %s",
266 		       val2str(rsp->ccode, completion_code_vals));
267 		return -1;
268 	}
269 
270 	for (bf = mc_enables_bf; bf->name != NULL; bf++) {
271 		printf("%-40s : %sabled\n", bf->desc,
272 		       rsp->data[0] & bf->mask ? "en" : "dis");
273 	}
274 
275 	return 0;
276 }
277 
278 /* ipmi_mc_set_enables  -  set MC enable flags
279  *
280  * @intf:	ipmi inteface
281  * @argc:	argument count
282  * @argv:	argument list
283  *
284  * returns 0 on success
285  * returns -1 on error
286  */
287 static int
288 ipmi_mc_set_enables(struct ipmi_intf * intf, int argc, char ** argv)
289 {
290 	struct ipmi_rs * rsp;
291 	struct ipmi_rq req;
292 	struct bitfield_data * bf;
293 	uint8_t en;
294 	int i;
295 
296 	if (argc < 1) {
297 		printf_mc_usage();
298 		return (-1);
299 	}
300 	else if (strncmp(argv[0], "help", 4) == 0) {
301 		printf_mc_usage();
302 		return 0;
303 	}
304 
305 	memset(&req, 0, sizeof(req));
306 	req.msg.netfn = IPMI_NETFN_APP;
307 	req.msg.cmd = BMC_GET_GLOBAL_ENABLES;
308 
309 	rsp = intf->sendrecv(intf, &req);
310 	if (rsp == NULL) {
311 		lprintf(LOG_ERR, "Get Global Enables command failed");
312 		return -1;
313 	}
314 	if (rsp->ccode > 0) {
315 		lprintf(LOG_ERR, "Get Global Enables command failed: %s",
316 		       val2str(rsp->ccode, completion_code_vals));
317 		return -1;
318 	}
319 
320 	en = rsp->data[0];
321 
322 	for (i = 0; i < argc; i++) {
323 		for (bf = mc_enables_bf; bf->name != NULL; bf++) {
324 			int nl = strlen(bf->name);
325 			if (strncmp(argv[i], bf->name, nl) != 0)
326 				continue;
327 			if (strncmp(argv[i]+nl+1, "off", 3) == 0) {
328 					printf("Disabling %s\n", bf->desc);
329 					en &= ~bf->mask;
330 			}
331 			else if (strncmp(argv[i]+nl+1, "on", 2) == 0) {
332 					printf("Enabling %s\n", bf->desc);
333 					en |= bf->mask;
334 			}
335 			else {
336 				lprintf(LOG_ERR, "Unrecognized option: %s", argv[i]);
337 			}
338 		}
339 	}
340 
341 	if (en == rsp->data[0]) {
342 		printf("\nNothing to change...\n");
343 		ipmi_mc_get_enables(intf);
344 		return 0;
345 	}
346 
347 	req.msg.cmd = BMC_SET_GLOBAL_ENABLES;
348 	req.msg.data = &en;
349 	req.msg.data_len = 1;
350 
351 	rsp = intf->sendrecv(intf, &req);
352 	if (rsp == NULL) {
353 		lprintf(LOG_ERR, "Set Global Enables command failed");
354 		return -1;
355 	}
356 	else if (rsp->ccode > 0) {
357 		lprintf(LOG_ERR, "Set Global Enables command failed: %s",
358 		       val2str(rsp->ccode, completion_code_vals));
359 		return -1;
360 	}
361 
362 	printf("\nVerifying...\n");
363 	ipmi_mc_get_enables(intf);
364 
365 	return 0;
366 }
367 
368 /* IPM Device, Get Device ID Command - Additional Device Support */
369 const char *ipm_dev_adtl_dev_support[8] = {
370 	"Sensor Device",         /* bit 0 */
371 	"SDR Repository Device", /* bit 1 */
372 	"SEL Device",            /* bit 2 */
373 	"FRU Inventory Device",  /*  ...  */
374 	"IPMB Event Receiver",
375 	"IPMB Event Generator",
376 	"Bridge",
377 	"Chassis Device"         /* bit 7 */
378 };
379 
380 /* ipmi_mc_get_deviceid  -  print information about this MC
381  *
382  * @intf:	ipmi interface
383  *
384  * returns 0 on success
385  * returns -1 on error
386  */
387 static int
388 ipmi_mc_get_deviceid(struct ipmi_intf * intf)
389 {
390 	struct ipmi_rs * rsp;
391 	struct ipmi_rq req;
392 	struct ipm_devid_rsp *devid;
393 	int i;
394 	const char *product=NULL;
395 
396 	memset(&req, 0, sizeof(req));
397 	req.msg.netfn = IPMI_NETFN_APP;
398 	req.msg.cmd = BMC_GET_DEVICE_ID;
399 	req.msg.data_len = 0;
400 
401 	rsp = intf->sendrecv(intf, &req);
402 	if (rsp == NULL) {
403 		lprintf(LOG_ERR, "Get Device ID command failed");
404 		return -1;
405 	}
406 	if (rsp->ccode > 0) {
407 		lprintf(LOG_ERR, "Get Device ID command failed: %s",
408 			val2str(rsp->ccode, completion_code_vals));
409 		return -1;
410 	}
411 
412 	devid = (struct ipm_devid_rsp *) rsp->data;
413 	printf("Device ID                 : %i\n",
414 		devid->device_id);
415 	printf("Device Revision           : %i\n",
416 		devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK);
417 	printf("Firmware Revision         : %u.%02x\n",
418 		devid->fw_rev1 & IPM_DEV_FWREV1_MAJOR_MASK,
419 		devid->fw_rev2);
420 	printf("IPMI Version              : %x.%x\n",
421 		IPM_DEV_IPMI_VERSION_MAJOR(devid->ipmi_version),
422 		IPM_DEV_IPMI_VERSION_MINOR(devid->ipmi_version));
423 	printf("Manufacturer ID           : %lu\n",
424 		(long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id));
425 	printf("Manufacturer Name         : %s\n",
426 			val2str( (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
427 				ipmi_oem_info) );
428 
429 	printf("Product ID                : %u (0x%02x%02x)\n",
430 		buf2short((uint8_t *)(devid->product_id)),
431 		devid->product_id[1], devid->product_id[0]);
432 
433 	product=oemval2str(IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
434 							 (devid->product_id[1]<<8)+devid->product_id[0],
435 							 ipmi_oem_product_info);
436 
437 	if (product!=NULL) {
438 		printf("Product Name              : %s\n", product);
439 	}
440 
441 	printf("Device Available          : %s\n",
442 		(devid->fw_rev1 & IPM_DEV_FWREV1_AVAIL_MASK) ?
443 		"no" : "yes");
444 	printf("Provides Device SDRs      : %s\n",
445 		(devid->device_revision & IPM_DEV_DEVICE_ID_SDR_MASK) ?
446 		"yes" : "no");
447 	printf("Additional Device Support :\n");
448 	for (i = 0; i < IPM_DEV_ADTL_SUPPORT_BITS; i++) {
449 		if (devid->adtl_device_support & (1 << i)) {
450 			printf("    %s\n", ipm_dev_adtl_dev_support[i]);
451 		}
452 	}
453 	if (rsp->data_len == sizeof(*devid)) {
454 		printf("Aux Firmware Rev Info     : \n");
455 		/* These values could be looked-up by vendor if documented,
456 		 * so we put them on individual lines for better treatment later
457 		 */
458 		printf("    0x%02x\n    0x%02x\n    0x%02x\n    0x%02x\n",
459 			devid->aux_fw_rev[0],
460 			devid->aux_fw_rev[1],
461 			devid->aux_fw_rev[2],
462 			devid->aux_fw_rev[3]);
463 	}
464 	return 0;
465 }
466 
467 /* Structure follow the IPMI V.2 Rev 1.0
468  * See Table 20-10 */
469 #ifdef HAVE_PRAGMA_PACK
470 #pragma pack(1)
471 #endif
472 
473 struct ipmi_guid {
474 	uint32_t  time_low;	/* timestamp low field */
475 	uint16_t  time_mid;	/* timestamp middle field */
476 	uint16_t  time_hi_and_version; /* timestamp high field and version number */
477 	uint8_t   clock_seq_hi_variant;/* clock sequence high field and variant */
478 	uint8_t   clock_seq_low; /* clock sequence low field */
479 	uint8_t   node[6];	/* node */
480 } ATTRIBUTE_PACKING;
481 #ifdef HAVE_PRAGMA_PACK
482 #pragma pack(0)
483 #endif
484 
485 /* ipmi_mc_get_guid  -  print this MC GUID
486  *
487  * @intf:	ipmi interface
488  *
489  * returns 0 on success
490  * returns -1 on error
491  */
492 static int
493 ipmi_mc_get_guid(struct ipmi_intf * intf)
494 {
495 	struct ipmi_rs * rsp;
496 	struct ipmi_rq req;
497 	struct ipmi_guid guid;
498 
499 	memset(&req, 0, sizeof(req));
500 	req.msg.netfn = IPMI_NETFN_APP;
501 	req.msg.cmd = BMC_GET_GUID;
502 
503 	rsp = intf->sendrecv(intf, &req);
504 	if (rsp == NULL) {
505 		lprintf(LOG_ERR, "Get GUID command failed");
506 		return -1;
507 	}
508 	if (rsp->ccode > 0) {
509 		lprintf(LOG_ERR, "Get GUID command failed: %s",
510 			val2str(rsp->ccode, completion_code_vals));
511 		return -1;
512 	}
513 
514 	if (rsp->data_len == sizeof(struct ipmi_guid)) {
515 		char tbuf[40];
516 		time_t s;
517 		memset(tbuf, 0, 40);
518 		memset(&guid, 0, sizeof(struct ipmi_guid));
519 		memcpy(&guid, rsp->data, rsp->data_len);
520 
521 		/* Kipp - changed order of last field (node) to follow specification */
522 		printf("System GUID  : %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n",
523 		       guid.time_low, guid.time_mid, guid.time_hi_and_version,
524 		       guid.clock_seq_hi_variant << 8 | guid.clock_seq_low,
525 		       guid.node[0], guid.node[1], guid.node[2],
526 		       guid.node[3], guid.node[4], guid.node[5]);
527 
528 		s = (time_t)guid.time_low; /* Kipp - removed the BSWAP_32, it was not needed here */
529 		strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", localtime(&s));
530 		printf("Timestamp    : %s\n", tbuf);
531 	}
532 	else {
533 		lprintf(LOG_ERR, "Invalid GUID length %d", rsp->data_len);
534 	}
535 
536 	return 0;
537 }
538 
539 /* ipmi_mc_get_selftest -  returns and print selftest results
540  *
541  * @intf:	ipmi interface
542  */
543 static int ipmi_mc_get_selftest(struct ipmi_intf * intf)
544 {
545    int rv = 0;
546 	struct ipmi_rs * rsp;
547 	struct ipmi_rq req;
548 	struct ipm_selftest_rsp *sft_res;
549 
550 	memset(&req, 0, sizeof(req));
551 	req.msg.netfn = IPMI_NETFN_APP;
552 	req.msg.cmd = BMC_GET_SELF_TEST;
553 	req.msg.data_len = 0;
554 
555 	rsp = intf->sendrecv(intf, &req);
556 	if (!rsp) {
557 		lprintf(LOG_ERR, "No response from devices\n");
558 		return -1;
559 	}
560 
561 	if (rsp->ccode) {
562 		lprintf(LOG_ERR, "Bad response: (%s)",
563 				val2str(rsp->ccode, completion_code_vals));
564 		return -1;
565 	}
566 
567 	sft_res = (struct ipm_selftest_rsp *) rsp->data;
568 
569 	if (sft_res->code == IPM_SFT_CODE_OK) {
570 		printf("Selftest: passed\n");
571 		rv = 0;
572 	}
573 
574 	else if (sft_res->code == IPM_SFT_CODE_NOT_IMPLEMENTED) {
575 		printf("Selftest: not implemented\n");
576 		rv = -1;
577 	}
578 
579 	else if (sft_res->code == IPM_SFT_CODE_DEV_CORRUPTED) {
580 		printf("Selftest: device corrupted\n");
581 		rv = -1;
582 
583 		if (sft_res->test & IPM_SELFTEST_SEL_ERROR) {
584 			printf(" -> SEL device not accessible\n");
585 		}
586 		if (sft_res->test & IPM_SELFTEST_SDR_ERROR) {
587 			printf(" -> SDR repository not accesible\n");
588 		}
589 		if (sft_res->test & IPM_SELFTEST_FRU_ERROR) {
590 			printf("FRU device not accessible\n");
591 		}
592 		if (sft_res->test & IPM_SELFTEST_IPMB_ERROR) {
593 			printf("IPMB signal lines do not respond\n");
594 		}
595 		if (sft_res->test & IPM_SELFTEST_SDRR_EMPTY) {
596 			printf("SDR repository empty\n");
597 		}
598 		if (sft_res->test & IPM_SELFTEST_INTERNAL_USE) {
599 			printf("Internal Use Area corrupted\n");
600 		}
601 		if (sft_res->test & IPM_SELFTEST_FW_BOOTBLOCK) {
602 			printf("Controller update boot block corrupted\n");
603 		}
604 		if (sft_res->test & IPM_SELFTEST_FW_CORRUPTED) {
605 			printf("controller operational firmware corrupted\n");
606 		}
607 	}
608 
609 	else if (sft_res->code == IPM_SFT_CODE_FATAL_ERROR) {
610 		printf("Selftest     : fatal error\n");
611 		printf("Failure code : %02x\n", sft_res->test);
612 		rv = -1;
613 	}
614 
615 	else if (sft_res->code == IPM_SFT_CODE_RESERVED) {
616 		printf("Selftest: N/A");
617 		rv = -1;
618 	}
619 
620 	else {
621 		printf("Selftest     : device specific (%02Xh)\n", sft_res->code);
622 		printf("Failure code : %02Xh\n", sft_res->test);
623 		rv = 0;
624 	}
625 
626 	return rv;
627 }
628 
629 /* ipmi_mc_get_watchdog
630  *
631  * @intf:	ipmi interface
632  *
633  * returns 0 on success
634  * returns -1 on error
635  */
636 
637 const char *wdt_use_string[8] = {
638 	"Reserved",
639 	"BIOS FRB2",
640 	"BIOS/POST",
641 	"OS Load",
642 	"SMS/OS",
643 	"OEM",
644 	"Reserved",
645 	"Reserved"
646 };
647 
648 const char *wdt_action_string[8] = {
649 	"No action",
650 	"Hard Reset",
651 	"Power Down",
652 	"Power Cycle",
653 	"Reserved",
654 	"Reserved",
655 	"Reserved",
656 	"Reserved"
657 };
658 
659 static int
660 ipmi_mc_get_watchdog(struct ipmi_intf * intf)
661 {
662 	struct ipmi_rs * rsp;
663 	struct ipmi_rq req;
664 	struct ipm_get_watchdog_rsp * wdt_res;
665 
666 	memset(&req, 0, sizeof(req));
667 	req.msg.netfn = IPMI_NETFN_APP;
668 	req.msg.cmd = BMC_GET_WATCHDOG_TIMER;
669 	req.msg.data_len = 0;
670 
671 	rsp = intf->sendrecv(intf, &req);
672 	if (rsp == NULL) {
673 		lprintf(LOG_ERR, "Get Watchdog Timer command failed");
674 		return -1;
675 	}
676 
677 	if (rsp->ccode) {
678 		lprintf(LOG_ERR, "Get Watchdog Timer command failed: %s",
679 			val2str(rsp->ccode, completion_code_vals));
680 		return -1;
681 	}
682 
683 	wdt_res = (struct ipm_get_watchdog_rsp *) rsp->data;
684 
685 	printf("Watchdog Timer Use:     %s (0x%02x)\n",
686 			wdt_use_string[(wdt_res->timer_use & 0x07 )], wdt_res->timer_use);
687 	printf("Watchdog Timer Is:      %s\n",
688 		wdt_res->timer_use & 0x40 ? "Started/Running" : "Stopped");
689 	printf("Watchdog Timer Actions: %s (0x%02x)\n",
690 		 wdt_action_string[(wdt_res->timer_actions&0x07)], wdt_res->timer_actions);
691 	printf("Pre-timeout interval:   %d seconds\n", wdt_res->pre_timeout);
692 	printf("Timer Expiration Flags: 0x%02x\n", wdt_res->timer_use_exp);
693 	printf("Initial Countdown:      %i sec\n",
694 			((wdt_res->initial_countdown_msb << 8) | wdt_res->initial_countdown_lsb)/10);
695 	printf("Present Countdown:      %i sec\n",
696 			(((wdt_res->present_countdown_msb << 8) | wdt_res->present_countdown_lsb)) / 10);
697 
698 	return 0;
699 }
700 
701 /* ipmi_mc_shutoff_watchdog
702  *
703  * @intf:	ipmi interface
704  *
705  * returns 0 on success
706  * returns -1 on error
707  */
708 static int
709 ipmi_mc_shutoff_watchdog(struct ipmi_intf * intf)
710 {
711 	struct ipmi_rs * rsp;
712 	struct ipmi_rq req;
713 	unsigned char msg_data[6];
714 
715 	memset(&req, 0, sizeof(req));
716 	req.msg.netfn = IPMI_NETFN_APP;
717 	req.msg.cmd   = BMC_SET_WATCHDOG_TIMER;
718 	req.msg.data  = msg_data;
719 	req.msg.data_len = 6;
720 
721 	/*
722 	 * The only set cmd we're allowing is to shut off the timer.
723 	 * Turning on the timer should be the job of the ipmi watchdog driver.
724 	 * See 'modinfo ipmi_watchdog' for more info. (NOTE: the reset
725 	 * command will restart the timer if it's already been initialized.)
726 	 *
727 	 * Out-of-band watchdog set commands can still be sent via the raw
728 	 * command interface but this is a very dangerous thing to do since
729 	 * a periodic "poke"/reset over a network is unreliable.  This is
730 	 * not a recommended way to use the IPMI watchdog commands.
731 	 */
732 
733 	msg_data[0] = IPM_WATCHDOG_SMS_OS;
734 	msg_data[1] = IPM_WATCHDOG_NO_ACTION;
735 	msg_data[2] = 0x00;  /* pretimeout interval */
736 	msg_data[3] = IPM_WATCHDOG_CLEAR_SMS_OS;
737 	msg_data[4] = 0xb8;  /* countdown lsb (100 ms/count) */
738 	msg_data[5] = 0x0b;  /* countdown msb - 5 mins */
739 
740 	rsp = intf->sendrecv(intf, &req);
741 	if (rsp == NULL) {
742 		lprintf(LOG_ERR, "Watchdog Timer Shutoff command failed!");
743 		return -1;
744 	}
745 
746 	if (rsp->ccode) {
747 		lprintf(LOG_ERR, "Watchdog Timer Shutoff command failed! %s",
748 			val2str(rsp->ccode, completion_code_vals));
749 		return -1;
750 	}
751 
752 	printf("Watchdog Timer Shutoff successful -- timer stopped\n");
753 	return 0;
754 }
755 
756 
757 /* ipmi_mc_rst_watchdog
758  *
759  * @intf:	ipmi interface
760  *
761  * returns 0 on success
762  * returns -1 on error
763  */
764 static int
765 ipmi_mc_rst_watchdog(struct ipmi_intf * intf)
766 {
767 	struct ipmi_rs * rsp;
768 	struct ipmi_rq req;
769 
770 	memset(&req, 0, sizeof(req));
771 	req.msg.netfn = IPMI_NETFN_APP;
772 	req.msg.cmd   = BMC_RESET_WATCHDOG_TIMER;
773 	req.msg.data_len = 0;
774 
775 	rsp = intf->sendrecv(intf, &req);
776 	if (rsp == NULL) {
777 		lprintf(LOG_ERR, "Reset Watchdog Timer command failed!");
778 		return -1;
779 	}
780 
781 	if (rsp->ccode) {
782 		lprintf(LOG_ERR, "Reset Watchdog Timer command failed: %s",
783 			(rsp->ccode == IPM_WATCHDOG_RESET_ERROR) ?
784 				"Attempt to reset unitialized watchdog" :
785 				val2str(rsp->ccode, completion_code_vals));
786 		return -1;
787 	}
788 
789 	printf("IPMI Watchdog Timer Reset -  countdown restarted!\n");
790 	return 0;
791 }
792 
793 /* ipmi_mc_main  -  top-level handler for MC functions
794  *
795  * @intf:	ipmi interface
796  * @argc:	number of arguments
797  * @argv:	argument list
798  *
799  * returns 0 on success
800  * returns -1 on error
801  */
802 int
803 ipmi_mc_main(struct ipmi_intf * intf, int argc, char ** argv)
804 {
805 	int rc = 0;
806 
807 	if (argc < 1) {
808 		lprintf(LOG_ERR, "Not enough parameters given.");
809 		printf_mc_usage();
810 		rc = (-1);
811 	}
812 	else if (strncmp(argv[0], "help", 4) == 0) {
813 		printf_mc_usage();
814 		rc = 0;
815 	}
816 	else if (strncmp(argv[0], "reset", 5) == 0) {
817 		if (argc < 2) {
818 			lprintf(LOG_ERR, "Not enough parameters given.");
819 			printf_mc_reset_usage();
820 			rc = (-1);
821 		}
822 		else if (strncmp(argv[1], "help", 4) == 0) {
823 			printf_mc_reset_usage();
824 			rc = 0;
825 		}
826 		else if (strncmp(argv[1], "cold", 4) == 0) {
827 			rc = ipmi_mc_reset(intf, BMC_COLD_RESET);
828 		}
829 		else if (strncmp(argv[1], "warm", 4) == 0) {
830 			rc = ipmi_mc_reset(intf, BMC_WARM_RESET);
831 		}
832 		else {
833 			lprintf(LOG_ERR, "Invalid mc/bmc %s command: %s", argv[0], argv[1]);
834 			printf_mc_reset_usage();
835 			rc = (-1);
836 		}
837 	}
838 	else if (strncmp(argv[0], "info", 4) == 0) {
839 		rc = ipmi_mc_get_deviceid(intf);
840 	}
841 	else if (strncmp(argv[0], "guid", 4) == 0) {
842 		rc = ipmi_mc_get_guid(intf);
843 	}
844 	else if (strncmp(argv[0], "getenables", 10) == 0) {
845 		rc = ipmi_mc_get_enables(intf);
846 	}
847 	else if (strncmp(argv[0], "setenables", 10) == 0) {
848 		rc = ipmi_mc_set_enables(intf, argc-1, &(argv[1]));
849 	}
850 	else if (!strncmp(argv[0], "selftest", 8)) {
851 		rc = ipmi_mc_get_selftest(intf);
852 	}
853 	else if (!strncmp(argv[0], "watchdog", 8)) {
854 		if (argc < 2) {
855 			lprintf(LOG_ERR, "Not enough parameters given.");
856 			print_watchdog_usage();
857 			rc = (-1);
858 		}
859 		else if (strncmp(argv[1], "help", 4) == 0) {
860 			print_watchdog_usage();
861 			rc = 0;
862 		}
863 		else if (strncmp(argv[1], "get", 3) == 0) {
864 			rc = ipmi_mc_get_watchdog(intf);
865 		}
866 		else if(strncmp(argv[1], "off", 3) == 0) {
867 			rc = ipmi_mc_shutoff_watchdog(intf);
868 		}
869 		else if(strncmp(argv[1], "reset", 5) == 0) {
870 			rc = ipmi_mc_rst_watchdog(intf);
871 		}
872 		else {
873 			lprintf(LOG_ERR, "Invalid mc/bmc %s command: %s", argv[0], argv[1]);
874 			print_watchdog_usage();
875 			rc = (-1);
876 		}
877 	}
878 	else if (strncmp(argv[0], "getsysinfo", 10) == 0) {
879 		rc = ipmi_sysinfo_main(intf, argc, argv, 0);
880 	}
881 	else if (strncmp(argv[0], "setsysinfo", 10) == 0) {
882 		rc = ipmi_sysinfo_main(intf, argc, argv, 1);
883 	}
884 	else {
885 		lprintf(LOG_ERR, "Invalid mc/bmc command: %s", argv[0]);
886 		printf_mc_usage();
887 		rc = (-1);
888 	}
889 	return rc;
890 }
891 
892 /*
893  * sysinfo_param() - function converts sysinfo param to int
894  *
895  * @str - user input string
896  * @maxset - ?
897  *
898  * returns (-1) on error
899  * returns > 0  on success
900  */
901 static int
902 sysinfo_param(const char *str, int *maxset)
903 {
904 	if (!str || !maxset)
905 		return (-1);
906 
907 	*maxset = 4;
908 	if (!strcmp(str, "system_name"))
909 		return IPMI_SYSINFO_HOSTNAME;
910 	else if (!strcmp(str, "primary_os_name"))
911 		return IPMI_SYSINFO_PRIMARY_OS_NAME;
912 	else if (!strcmp(str, "os_name"))
913 		return IPMI_SYSINFO_OS_NAME;
914 	else if (!strcmp(str, "delloem_os_version"))
915 		return IPMI_SYSINFO_DELL_OS_VERSION;
916 	else if (!strcmp(str, "delloem_url")) {
917 		*maxset = 2;
918 		return IPMI_SYSINFO_DELL_URL;
919 	} else if (!strcmp(str, "system_fw_version")) {
920 		return IPMI_SYSINFO_SYSTEM_FW_VERSION;
921 	}
922 
923 	return (-1);
924 }
925 
926 /*
927  * ipmi_mc_getsysinfo() - function processes the IPMI Get System Info command
928  *
929  * @intf - ipmi interface
930  * @param - parameter eg. 0xC0..0xFF = OEM
931  * @block - number of block parameters
932  * @set - number of set parameters
933  * @len - length of buffer
934  * @buffer - pointer to buffer
935  *
936  * returns (-1) on failure
937  * returns   0  on success
938  * returns > 0  IPMI code
939  */
940 int
941 ipmi_mc_getsysinfo(struct ipmi_intf * intf, int param, int block, int set,
942 		int len, void *buffer)
943 {
944 	uint8_t data[4];
945 	struct ipmi_rs *rsp = NULL;
946 	struct ipmi_rq req = {0};
947 
948 	memset(buffer, 0, len);
949 	memset(data, 0, 4);
950 	req.msg.netfn = IPMI_NETFN_APP;
951 	req.msg.lun = 0;
952 	req.msg.cmd = IPMI_GET_SYS_INFO;
953 	req.msg.data_len = 4;
954 	req.msg.data = data;
955 
956 	if (verbose > 1)
957 		printf("getsysinfo: %.2x/%.2x/%.2x\n", param, block, set);
958 
959 	data[0] = 0; /* get/set */
960 	data[1] = param;
961 	data[2] = block;
962 	data[3] = set;
963 
964 	/*
965 	 * Format of get output is:
966 	 *   u8 param_rev
967 	 *   u8 selector
968 	 *   u8 encoding  bit[0-3];
969 	 *   u8 length
970 	 *   u8 data0[14]
971 	 */
972 	rsp = intf->sendrecv(intf, &req);
973 	if (rsp == NULL)
974 		return (-1);
975 
976 	if (rsp->ccode == 0) {
977 		if (len > rsp->data_len)
978 			len = rsp->data_len;
979 		if (len && buffer)
980 			memcpy(buffer, rsp->data, len);
981 	}
982 	return rsp->ccode;
983 }
984 
985 /*
986  * ipmi_mc_setsysinfo() - function processes the IPMI Set System Info command
987  *
988  * @intf - ipmi interface
989  * @len - length of buffer
990  * @buffer - pointer to buffer
991  *
992  * returns (-1) on failure
993  * returns   0  on success
994  * returns > 0  IPMI code
995  */
996 int
997 ipmi_mc_setsysinfo(struct ipmi_intf * intf, int len, void *buffer)
998 {
999 	struct ipmi_rs *rsp = NULL;
1000 	struct ipmi_rq req = {0};
1001 
1002 	req.msg.netfn = IPMI_NETFN_APP;
1003 	req.msg.lun = 0;
1004 	req.msg.cmd = IPMI_SET_SYS_INFO;
1005 	req.msg.data_len = len;
1006 	req.msg.data = buffer;
1007 
1008 	/*
1009 	 * Format of set input:
1010 	 *   u8 param rev
1011 	 *   u8 selector
1012 	 *   u8 data1[16]
1013 	 */
1014 	rsp = intf->sendrecv(intf, &req);
1015 	if (rsp != NULL) {
1016 		return rsp->ccode;
1017 	}
1018 	return -1;
1019 }
1020 
1021 static int
1022 ipmi_sysinfo_main(struct ipmi_intf *intf, int argc, char ** argv, int is_set)
1023 {
1024 	char *str;
1025 	unsigned char  infostr[256];
1026 	unsigned char  paramdata[18];
1027 	int len, maxset, param, pos, rc, set;
1028 
1029 	if (argc == 2 && strcmp(argv[1], "help") == 0) {
1030 		printf_sysinfo_usage(1);
1031 		return 0;
1032 	}
1033 	else if (argc < 2 || (is_set == 1 && argc < 3)) {
1034 		lprintf(LOG_ERR, "Not enough parameters given.");
1035 		printf_sysinfo_usage(1);
1036 		return (-1);
1037 	}
1038 
1039 	/* Get Parameters */
1040 	if ((param = sysinfo_param(argv[1], &maxset)) < 0) {
1041 		lprintf(LOG_ERR, "Invalid mc/bmc %s command: %s", argv[0], argv[1]);
1042 		printf_sysinfo_usage(1);
1043 		return (-1);
1044 	}
1045 
1046 	rc = 0;
1047 	if (is_set != 0) {
1048 		str = argv[2];
1049 		set = pos = 0;
1050 		len = strlen(str);
1051 
1052 		/* first block holds 14 bytes, all others hold 16 */
1053 		if ((len + 2 + 15) / 16 >= maxset)
1054 			len = (maxset * 16) - 2;
1055 
1056 		do {
1057 			memset(paramdata, 0, sizeof(paramdata));
1058 			paramdata[0] = param;
1059 			paramdata[1] = set;
1060 			if (set == 0) {
1061 				/* First block is special case */
1062 				paramdata[2] = 0;   /* ascii encoding */
1063 				paramdata[3] = len; /* length */
1064 				strncpy(paramdata + 4, str + pos, IPMI_SYSINFO_SET0_SIZE);
1065 				pos += IPMI_SYSINFO_SET0_SIZE;
1066 			}
1067 			else {
1068 				strncpy(paramdata + 2, str + pos, IPMI_SYSINFO_SETN_SIZE);
1069 				pos += IPMI_SYSINFO_SETN_SIZE;
1070 			}
1071 			rc = ipmi_mc_setsysinfo(intf, 18, paramdata);
1072 
1073 			if (rc)
1074 				break;
1075 
1076 			set++;
1077 		} while (pos < len);
1078 	}
1079 	else {
1080 		memset(infostr, 0, sizeof(infostr));
1081 		/* Read blocks of data */
1082 		pos = 0;
1083 		for (set = 0; set < maxset; set++) {
1084 			rc = ipmi_mc_getsysinfo(intf, param, set, 0, 18, paramdata);
1085 
1086 			if (rc)
1087 				break;
1088 
1089 			if (set == 0) {
1090 				/* First block is special case */
1091 				if ((paramdata[2] & 0xF) == 0) {
1092 					/* Determine max number of blocks to read */
1093 					maxset = ((paramdata[3] + 2) + 15) / 16;
1094 				}
1095 				memcpy(infostr + pos, paramdata + 4, IPMI_SYSINFO_SET0_SIZE);
1096 				pos += IPMI_SYSINFO_SET0_SIZE;
1097 			}
1098 			else {
1099 				memcpy(infostr + pos, paramdata + 2, IPMI_SYSINFO_SETN_SIZE);
1100 				pos += IPMI_SYSINFO_SETN_SIZE;
1101 			}
1102 		}
1103 		printf("%s\n", infostr);
1104 	}
1105 	if (rc < 0) {
1106 		lprintf(LOG_ERR, "%s %s set %d command failed", argv[0], argv[1], set);
1107 	}
1108 	else if (rc == 0x80) {
1109 		lprintf(LOG_ERR, "%s %s parameter not supported", argv[0], argv[1]);
1110 	}
1111 	else if (rc > 0) {
1112 		lprintf(LOG_ERR, "%s command failed: %s", argv[0],
1113 				val2str(rc, completion_code_vals));
1114 	}
1115 	return rc;
1116 }
1117