xref: /freebsd/sys/dev/ipmi/ipmi.c (revision 9a14aa017b21c292740c00ee098195cd46642730)
1 /*-
2  * Copyright (c) 2006 IronPort Systems Inc. <ambrisko@ironport.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/condvar.h>
34 #include <sys/conf.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/poll.h>
39 #include <sys/rman.h>
40 #include <sys/selinfo.h>
41 #include <sys/sysctl.h>
42 #include <sys/watchdog.h>
43 
44 #ifdef LOCAL_MODULE
45 #include <ipmi.h>
46 #include <ipmivars.h>
47 #else
48 #include <sys/ipmi.h>
49 #include <dev/ipmi/ipmivars.h>
50 #endif
51 
52 #ifdef IPMB
53 static int ipmi_ipmb_checksum(u_char, int);
54 static int ipmi_ipmb_send_message(device_t, u_char, u_char, u_char,
55      u_char, u_char, int)
56 #endif
57 
58 static d_ioctl_t ipmi_ioctl;
59 static d_poll_t ipmi_poll;
60 static d_open_t ipmi_open;
61 static void ipmi_dtor(void *arg);
62 
63 int ipmi_attached = 0;
64 
65 static int on = 1;
66 static SYSCTL_NODE(_hw, OID_AUTO, ipmi, CTLFLAG_RD, 0,
67     "IPMI driver parameters");
68 SYSCTL_INT(_hw_ipmi, OID_AUTO, on, CTLFLAG_RW,
69 	&on, 0, "");
70 
71 static struct cdevsw ipmi_cdevsw = {
72 	.d_version =    D_VERSION,
73 	.d_open =	ipmi_open,
74 	.d_ioctl =	ipmi_ioctl,
75 	.d_poll =	ipmi_poll,
76 	.d_name =	"ipmi",
77 };
78 
79 static MALLOC_DEFINE(M_IPMI, "ipmi", "ipmi");
80 
81 static int
82 ipmi_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
83 {
84 	struct ipmi_device *dev;
85 	struct ipmi_softc *sc;
86 	int error;
87 
88 	if (!on)
89 		return (ENOENT);
90 
91 	/* Initialize the per file descriptor data. */
92 	dev = malloc(sizeof(struct ipmi_device), M_IPMI, M_WAITOK | M_ZERO);
93 	error = devfs_set_cdevpriv(dev, ipmi_dtor);
94 	if (error) {
95 		free(dev, M_IPMI);
96 		return (error);
97 	}
98 
99 	sc = cdev->si_drv1;
100 	TAILQ_INIT(&dev->ipmi_completed_requests);
101 	dev->ipmi_address = IPMI_BMC_SLAVE_ADDR;
102 	dev->ipmi_lun = IPMI_BMC_SMS_LUN;
103 	dev->ipmi_softc = sc;
104 	IPMI_LOCK(sc);
105 	sc->ipmi_opened++;
106 	IPMI_UNLOCK(sc);
107 
108 	return (0);
109 }
110 
111 static int
112 ipmi_poll(struct cdev *cdev, int poll_events, struct thread *td)
113 {
114 	struct ipmi_device *dev;
115 	struct ipmi_softc *sc;
116 	int revents = 0;
117 
118 	if (devfs_get_cdevpriv((void **)&dev))
119 		return (0);
120 
121 	sc = cdev->si_drv1;
122 	IPMI_LOCK(sc);
123 	if (poll_events & (POLLIN | POLLRDNORM)) {
124 		if (!TAILQ_EMPTY(&dev->ipmi_completed_requests))
125 		    revents |= poll_events & (POLLIN | POLLRDNORM);
126 		if (dev->ipmi_requests == 0)
127 		    revents |= POLLERR;
128 	}
129 
130 	if (revents == 0) {
131 		if (poll_events & (POLLIN | POLLRDNORM))
132 			selrecord(td, &dev->ipmi_select);
133 	}
134 	IPMI_UNLOCK(sc);
135 
136 	return (revents);
137 }
138 
139 static void
140 ipmi_purge_completed_requests(struct ipmi_device *dev)
141 {
142 	struct ipmi_request *req;
143 
144 	while (!TAILQ_EMPTY(&dev->ipmi_completed_requests)) {
145 		req = TAILQ_FIRST(&dev->ipmi_completed_requests);
146 		TAILQ_REMOVE(&dev->ipmi_completed_requests, req, ir_link);
147 		dev->ipmi_requests--;
148 		ipmi_free_request(req);
149 	}
150 }
151 
152 static void
153 ipmi_dtor(void *arg)
154 {
155 	struct ipmi_request *req, *nreq;
156 	struct ipmi_device *dev;
157 	struct ipmi_softc *sc;
158 
159 	dev = arg;
160 	sc = dev->ipmi_softc;
161 
162 	IPMI_LOCK(sc);
163 	if (dev->ipmi_requests) {
164 		/* Throw away any pending requests for this device. */
165 		TAILQ_FOREACH_SAFE(req, &sc->ipmi_pending_requests, ir_link,
166 		    nreq) {
167 			if (req->ir_owner == dev) {
168 				TAILQ_REMOVE(&sc->ipmi_pending_requests, req,
169 				    ir_link);
170 				dev->ipmi_requests--;
171 				ipmi_free_request(req);
172 			}
173 		}
174 
175 		/* Throw away any pending completed requests for this device. */
176 		ipmi_purge_completed_requests(dev);
177 
178 		/*
179 		 * If we still have outstanding requests, they must be stuck
180 		 * in an interface driver, so wait for those to drain.
181 		 */
182 		dev->ipmi_closing = 1;
183 		while (dev->ipmi_requests > 0) {
184 			msleep(&dev->ipmi_requests, &sc->ipmi_lock, PWAIT,
185 			    "ipmidrain", 0);
186 			ipmi_purge_completed_requests(dev);
187 		}
188 	}
189 	sc->ipmi_opened--;
190 	IPMI_UNLOCK(sc);
191 
192 	/* Cleanup. */
193 	free(dev, M_IPMI);
194 }
195 
196 #ifdef IPMB
197 static int
198 ipmi_ipmb_checksum(u_char *data, int len)
199 {
200 	u_char sum = 0;
201 
202 	for (; len; len--) {
203 		sum += *data++;
204 	}
205 	return (-sum);
206 }
207 
208 /* XXX: Needs work */
209 static int
210 ipmi_ipmb_send_message(device_t dev, u_char channel, u_char netfn,
211     u_char command, u_char seq, u_char *data, int data_len)
212 {
213 	struct ipmi_softc *sc = device_get_softc(dev);
214 	struct ipmi_request *req;
215 	u_char slave_addr = 0x52;
216 	int error;
217 
218 	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
219 	    IPMI_SEND_MSG, data_len + 8, 0);
220 	req->ir_request[0] = channel;
221 	req->ir_request[1] = slave_addr;
222 	req->ir_request[2] = IPMI_ADDR(netfn, 0);
223 	req->ir_request[3] = ipmi_ipmb_checksum(&req->ir_request[1], 2);
224 	req->ir_request[4] = sc->ipmi_address;
225 	req->ir_request[5] = IPMI_ADDR(seq, sc->ipmi_lun);
226 	req->ir_request[6] = command;
227 
228 	bcopy(data, &req->ir_request[7], data_len);
229 	temp[data_len + 7] = ipmi_ipmb_checksum(&req->ir_request[4],
230 	    data_len + 3);
231 
232 	ipmi_submit_driver_request(sc, req);
233 	error = req->ir_error;
234 	ipmi_free_request(req);
235 
236 	return (error);
237 }
238 
239 static int
240 ipmi_handle_attn(struct ipmi_softc *sc)
241 {
242 	struct ipmi_request *req;
243 	int error;
244 
245 	device_printf(sc->ipmi_dev, "BMC has a message\n");
246 	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
247 	    IPMI_GET_MSG_FLAGS, 0, 1);
248 
249 	ipmi_submit_driver_request(sc, req);
250 
251 	if (req->ir_error == 0 && req->ir_compcode == 0) {
252 		if (req->ir_reply[0] & IPMI_MSG_BUFFER_FULL) {
253 			device_printf(sc->ipmi_dev, "message buffer full");
254 		}
255 		if (req->ir_reply[0] & IPMI_WDT_PRE_TIMEOUT) {
256 			device_printf(sc->ipmi_dev,
257 			    "watchdog about to go off");
258 		}
259 		if (req->ir_reply[0] & IPMI_MSG_AVAILABLE) {
260 			ipmi_free_request(req);
261 
262 			req = ipmi_alloc_driver_request(
263 			    IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_GET_MSG, 0,
264 			    16);
265 
266 			device_printf(sc->ipmi_dev, "throw out message ");
267 			dump_buf(temp, 16);
268 		}
269 	}
270 	error = req->ir_error;
271 	ipmi_free_request(req);
272 
273 	return (error);
274 }
275 #endif
276 
277 #ifdef IPMICTL_SEND_COMMAND_32
278 #define	PTRIN(p)	((void *)(uintptr_t)(p))
279 #define	PTROUT(p)	((uintptr_t)(p))
280 #endif
281 
282 static int
283 ipmi_ioctl(struct cdev *cdev, u_long cmd, caddr_t data,
284     int flags, struct thread *td)
285 {
286 	struct ipmi_softc *sc;
287 	struct ipmi_device *dev;
288 	struct ipmi_request *kreq;
289 	struct ipmi_req *req = (struct ipmi_req *)data;
290 	struct ipmi_recv *recv = (struct ipmi_recv *)data;
291 	struct ipmi_addr addr;
292 #ifdef IPMICTL_SEND_COMMAND_32
293 	struct ipmi_req32 *req32 = (struct ipmi_req32 *)data;
294 	struct ipmi_recv32 *recv32 = (struct ipmi_recv32 *)data;
295 	union {
296 		struct ipmi_req req;
297 		struct ipmi_recv recv;
298 	} thunk32;
299 #endif
300 	int error, len;
301 
302 	error = devfs_get_cdevpriv((void **)&dev);
303 	if (error)
304 		return (error);
305 
306 	sc = cdev->si_drv1;
307 
308 #ifdef IPMICTL_SEND_COMMAND_32
309 	/* Convert 32-bit structures to native. */
310 	switch (cmd) {
311 	case IPMICTL_SEND_COMMAND_32:
312 		req = &thunk32.req;
313 		req->addr = PTRIN(req32->addr);
314 		req->addr_len = req32->addr_len;
315 		req->msgid = req32->msgid;
316 		req->msg.netfn = req32->msg.netfn;
317 		req->msg.cmd = req32->msg.cmd;
318 		req->msg.data_len = req32->msg.data_len;
319 		req->msg.data = PTRIN(req32->msg.data);
320 		break;
321 	case IPMICTL_RECEIVE_MSG_TRUNC_32:
322 	case IPMICTL_RECEIVE_MSG_32:
323 		recv = &thunk32.recv;
324 		recv->addr = PTRIN(recv32->addr);
325 		recv->addr_len = recv32->addr_len;
326 		recv->msg.data_len = recv32->msg.data_len;
327 		recv->msg.data = PTRIN(recv32->msg.data);
328 		break;
329 	}
330 #endif
331 
332 	switch (cmd) {
333 #ifdef IPMICTL_SEND_COMMAND_32
334 	case IPMICTL_SEND_COMMAND_32:
335 #endif
336 	case IPMICTL_SEND_COMMAND:
337 		/*
338 		 * XXX: Need to add proper handling of this.
339 		 */
340 		error = copyin(req->addr, &addr, sizeof(addr));
341 		if (error)
342 			return (error);
343 
344 		IPMI_LOCK(sc);
345 		/* clear out old stuff in queue of stuff done */
346 		/* XXX: This seems odd. */
347 		while ((kreq = TAILQ_FIRST(&dev->ipmi_completed_requests))) {
348 			TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq,
349 			    ir_link);
350 			dev->ipmi_requests--;
351 			ipmi_free_request(kreq);
352 		}
353 		IPMI_UNLOCK(sc);
354 
355 		kreq = ipmi_alloc_request(dev, req->msgid,
356 		    IPMI_ADDR(req->msg.netfn, 0), req->msg.cmd,
357 		    req->msg.data_len, IPMI_MAX_RX);
358 		error = copyin(req->msg.data, kreq->ir_request,
359 		    req->msg.data_len);
360 		if (error) {
361 			ipmi_free_request(kreq);
362 			return (error);
363 		}
364 		IPMI_LOCK(sc);
365 		dev->ipmi_requests++;
366 		error = sc->ipmi_enqueue_request(sc, kreq);
367 		IPMI_UNLOCK(sc);
368 		if (error)
369 			return (error);
370 		break;
371 #ifdef IPMICTL_SEND_COMMAND_32
372 	case IPMICTL_RECEIVE_MSG_TRUNC_32:
373 	case IPMICTL_RECEIVE_MSG_32:
374 #endif
375 	case IPMICTL_RECEIVE_MSG_TRUNC:
376 	case IPMICTL_RECEIVE_MSG:
377 		error = copyin(recv->addr, &addr, sizeof(addr));
378 		if (error)
379 			return (error);
380 
381 		IPMI_LOCK(sc);
382 		kreq = TAILQ_FIRST(&dev->ipmi_completed_requests);
383 		if (kreq == NULL) {
384 			IPMI_UNLOCK(sc);
385 			return (EAGAIN);
386 		}
387 		addr.channel = IPMI_BMC_CHANNEL;
388 		/* XXX */
389 		recv->recv_type = IPMI_RESPONSE_RECV_TYPE;
390 		recv->msgid = kreq->ir_msgid;
391 		recv->msg.netfn = IPMI_REPLY_ADDR(kreq->ir_addr) >> 2;
392 		recv->msg.cmd = kreq->ir_command;
393 		error = kreq->ir_error;
394 		if (error) {
395 			TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq,
396 			    ir_link);
397 			dev->ipmi_requests--;
398 			IPMI_UNLOCK(sc);
399 			ipmi_free_request(kreq);
400 			return (error);
401 		}
402 		len = kreq->ir_replylen + 1;
403 		if (recv->msg.data_len < len &&
404 		    (cmd == IPMICTL_RECEIVE_MSG
405 #ifdef IPMICTL_RECEIVE_MSG_32
406 		     || cmd == IPMICTL_RECEIVE_MSG_32
407 #endif
408 		    )) {
409 			IPMI_UNLOCK(sc);
410 			return (EMSGSIZE);
411 		}
412 		TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link);
413 		dev->ipmi_requests--;
414 		IPMI_UNLOCK(sc);
415 		len = min(recv->msg.data_len, len);
416 		recv->msg.data_len = len;
417 		error = copyout(&addr, recv->addr,sizeof(addr));
418 		if (error == 0)
419 			error = copyout(&kreq->ir_compcode, recv->msg.data, 1);
420 		if (error == 0)
421 			error = copyout(kreq->ir_reply, recv->msg.data + 1,
422 			    len - 1);
423 		ipmi_free_request(kreq);
424 		if (error)
425 			return (error);
426 		break;
427 	case IPMICTL_SET_MY_ADDRESS_CMD:
428 		IPMI_LOCK(sc);
429 		dev->ipmi_address = *(int*)data;
430 		IPMI_UNLOCK(sc);
431 		break;
432 	case IPMICTL_GET_MY_ADDRESS_CMD:
433 		IPMI_LOCK(sc);
434 		*(int*)data = dev->ipmi_address;
435 		IPMI_UNLOCK(sc);
436 		break;
437 	case IPMICTL_SET_MY_LUN_CMD:
438 		IPMI_LOCK(sc);
439 		dev->ipmi_lun = *(int*)data & 0x3;
440 		IPMI_UNLOCK(sc);
441 		break;
442 	case IPMICTL_GET_MY_LUN_CMD:
443 		IPMI_LOCK(sc);
444 		*(int*)data = dev->ipmi_lun;
445 		IPMI_UNLOCK(sc);
446 		break;
447 	case IPMICTL_SET_GETS_EVENTS_CMD:
448 		/*
449 		device_printf(sc->ipmi_dev,
450 		    "IPMICTL_SET_GETS_EVENTS_CMD NA\n");
451 		*/
452 		break;
453 	case IPMICTL_REGISTER_FOR_CMD:
454 	case IPMICTL_UNREGISTER_FOR_CMD:
455 		return (EOPNOTSUPP);
456 	default:
457 		device_printf(sc->ipmi_dev, "Unknown IOCTL %lX\n", cmd);
458 		return (ENOIOCTL);
459 	}
460 
461 #ifdef IPMICTL_SEND_COMMAND_32
462 	/* Update changed fields in 32-bit structures. */
463 	switch (cmd) {
464 	case IPMICTL_RECEIVE_MSG_TRUNC_32:
465 	case IPMICTL_RECEIVE_MSG_32:
466 		recv32->recv_type = recv->recv_type;
467 		recv32->msgid = recv->msgid;
468 		recv32->msg.netfn = recv->msg.netfn;
469 		recv32->msg.cmd = recv->msg.cmd;
470 		recv32->msg.data_len = recv->msg.data_len;
471 		break;
472 	}
473 #endif
474 	return (0);
475 }
476 
477 /*
478  * Request management.
479  */
480 
481 /* Allocate a new request with request and reply buffers. */
482 struct ipmi_request *
483 ipmi_alloc_request(struct ipmi_device *dev, long msgid, uint8_t addr,
484     uint8_t command, size_t requestlen, size_t replylen)
485 {
486 	struct ipmi_request *req;
487 
488 	req = malloc(sizeof(struct ipmi_request) + requestlen + replylen,
489 	    M_IPMI, M_WAITOK | M_ZERO);
490 	req->ir_owner = dev;
491 	req->ir_msgid = msgid;
492 	req->ir_addr = addr;
493 	req->ir_command = command;
494 	if (requestlen) {
495 		req->ir_request = (char *)&req[1];
496 		req->ir_requestlen = requestlen;
497 	}
498 	if (replylen) {
499 		req->ir_reply = (char *)&req[1] + requestlen;
500 		req->ir_replybuflen = replylen;
501 	}
502 	return (req);
503 }
504 
505 /* Free a request no longer in use. */
506 void
507 ipmi_free_request(struct ipmi_request *req)
508 {
509 
510 	free(req, M_IPMI);
511 }
512 
513 /* Store a processed request on the appropriate completion queue. */
514 void
515 ipmi_complete_request(struct ipmi_softc *sc, struct ipmi_request *req)
516 {
517 	struct ipmi_device *dev;
518 
519 	IPMI_LOCK_ASSERT(sc);
520 
521 	/*
522 	 * Anonymous requests (from inside the driver) always have a
523 	 * waiter that we awaken.
524 	 */
525 	if (req->ir_owner == NULL)
526 		wakeup(req);
527 	else {
528 		dev = req->ir_owner;
529 		TAILQ_INSERT_TAIL(&dev->ipmi_completed_requests, req, ir_link);
530 		selwakeup(&dev->ipmi_select);
531 		if (dev->ipmi_closing)
532 			wakeup(&dev->ipmi_requests);
533 	}
534 }
535 
536 /* Enqueue an internal driver request and wait until it is completed. */
537 int
538 ipmi_submit_driver_request(struct ipmi_softc *sc, struct ipmi_request *req,
539     int timo)
540 {
541 	int error;
542 
543 	IPMI_LOCK(sc);
544 	error = sc->ipmi_enqueue_request(sc, req);
545 	if (error == 0)
546 		error = msleep(req, &sc->ipmi_lock, 0, "ipmireq", timo);
547 	if (error == 0)
548 		error = req->ir_error;
549 	IPMI_UNLOCK(sc);
550 	return (error);
551 }
552 
553 /*
554  * Helper routine for polled system interfaces that use
555  * ipmi_polled_enqueue_request() to queue requests.  This request
556  * waits until there is a pending request and then returns the first
557  * request.  If the driver is shutting down, it returns NULL.
558  */
559 struct ipmi_request *
560 ipmi_dequeue_request(struct ipmi_softc *sc)
561 {
562 	struct ipmi_request *req;
563 
564 	IPMI_LOCK_ASSERT(sc);
565 
566 	while (!sc->ipmi_detaching && TAILQ_EMPTY(&sc->ipmi_pending_requests))
567 		cv_wait(&sc->ipmi_request_added, &sc->ipmi_lock);
568 	if (sc->ipmi_detaching)
569 		return (NULL);
570 
571 	req = TAILQ_FIRST(&sc->ipmi_pending_requests);
572 	TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link);
573 	return (req);
574 }
575 
576 /* Default implementation of ipmi_enqueue_request() for polled interfaces. */
577 int
578 ipmi_polled_enqueue_request(struct ipmi_softc *sc, struct ipmi_request *req)
579 {
580 
581 	IPMI_LOCK_ASSERT(sc);
582 
583 	TAILQ_INSERT_TAIL(&sc->ipmi_pending_requests, req, ir_link);
584 	cv_signal(&sc->ipmi_request_added);
585 	return (0);
586 }
587 
588 /*
589  * Watchdog event handler.
590  */
591 
592 static int
593 ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
594 {
595 	struct ipmi_request *req;
596 	int error;
597 
598 	if (sec > 0xffff / 10)
599 		return (EINVAL);
600 
601 	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
602 	    IPMI_SET_WDOG, 6, 0);
603 
604 	if (sec) {
605 		req->ir_request[0] = IPMI_SET_WD_TIMER_DONT_STOP
606 		    | IPMI_SET_WD_TIMER_SMS_OS;
607 		req->ir_request[1] = IPMI_SET_WD_ACTION_RESET;
608 		req->ir_request[2] = 0;
609 		req->ir_request[3] = 0;	/* Timer use */
610 		req->ir_request[4] = (sec * 10) & 0xff;
611 		req->ir_request[5] = (sec * 10) >> 8;
612 	} else {
613 		req->ir_request[0] = IPMI_SET_WD_TIMER_SMS_OS;
614 		req->ir_request[1] = 0;
615 		req->ir_request[2] = 0;
616 		req->ir_request[3] = 0;	/* Timer use */
617 		req->ir_request[4] = 0;
618 		req->ir_request[5] = 0;
619 	}
620 
621 	error = ipmi_submit_driver_request(sc, req, 0);
622 	if (error)
623 		device_printf(sc->ipmi_dev, "Failed to set watchdog\n");
624 	else if (sec) {
625 		ipmi_free_request(req);
626 
627 		req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
628 		    IPMI_RESET_WDOG, 0, 0);
629 
630 		error = ipmi_submit_driver_request(sc, req, 0);
631 		if (error)
632 			device_printf(sc->ipmi_dev,
633 			    "Failed to reset watchdog\n");
634 	}
635 
636 	ipmi_free_request(req);
637 	return (error);
638 	/*
639 	dump_watchdog(sc);
640 	*/
641 }
642 
643 static void
644 ipmi_wd_event(void *arg, unsigned int cmd, int *error)
645 {
646 	struct ipmi_softc *sc = arg;
647 	unsigned int timeout;
648 	int e;
649 
650 	cmd &= WD_INTERVAL;
651 	if (cmd > 0 && cmd <= 63) {
652 		timeout = ((uint64_t)1 << cmd) / 1000000000;
653 		if (timeout == 0)
654 			timeout = 1;
655 		e = ipmi_set_watchdog(sc, timeout);
656 		if (e == 0)
657 			*error = 0;
658 		else
659 			(void)ipmi_set_watchdog(sc, 0);
660 	} else {
661 		e = ipmi_set_watchdog(sc, 0);
662 		if (e != 0 && cmd == 0)
663 			*error = EOPNOTSUPP;
664 	}
665 }
666 
667 static void
668 ipmi_startup(void *arg)
669 {
670 	struct ipmi_softc *sc = arg;
671 	struct ipmi_request *req;
672 	device_t dev;
673 	int error, i;
674 
675 	config_intrhook_disestablish(&sc->ipmi_ich);
676 	dev = sc->ipmi_dev;
677 
678 	/* Initialize interface-independent state. */
679 	mtx_init(&sc->ipmi_lock, device_get_nameunit(dev), "ipmi", MTX_DEF);
680 	cv_init(&sc->ipmi_request_added, "ipmireq");
681 	TAILQ_INIT(&sc->ipmi_pending_requests);
682 
683 	/* Initialize interface-dependent state. */
684 	error = sc->ipmi_startup(sc);
685 	if (error) {
686 		device_printf(dev, "Failed to initialize interface: %d\n",
687 		    error);
688 		return;
689 	}
690 
691 	/* Send a GET_DEVICE_ID request. */
692 	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
693 	    IPMI_GET_DEVICE_ID, 0, 15);
694 
695 	error = ipmi_submit_driver_request(sc, req, MAX_TIMEOUT);
696 	if (error == EWOULDBLOCK) {
697 		device_printf(dev, "Timed out waiting for GET_DEVICE_ID\n");
698 		ipmi_free_request(req);
699 		return;
700 	} else if (error) {
701 		device_printf(dev, "Failed GET_DEVICE_ID: %d\n", error);
702 		ipmi_free_request(req);
703 		return;
704 	} else if (req->ir_compcode != 0) {
705 		device_printf(dev,
706 		    "Bad completion code for GET_DEVICE_ID: %d\n",
707 		    req->ir_compcode);
708 		ipmi_free_request(req);
709 		return;
710 	} else if (req->ir_replylen < 5) {
711 		device_printf(dev, "Short reply for GET_DEVICE_ID: %d\n",
712 		    req->ir_replylen);
713 		ipmi_free_request(req);
714 		return;
715 	}
716 
717 	device_printf(dev, "IPMI device rev. %d, firmware rev. %d.%d%d, "
718 	    "version %d.%d\n",
719 	     req->ir_reply[1] & 0x0f,
720 	     req->ir_reply[2] & 0x7f, req->ir_reply[3] >> 4, req->ir_reply[3] & 0x0f,
721 	     req->ir_reply[4] & 0x0f, req->ir_reply[4] >> 4);
722 
723 	ipmi_free_request(req);
724 
725 	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
726 	    IPMI_CLEAR_FLAGS, 1, 0);
727 
728 	ipmi_submit_driver_request(sc, req, 0);
729 
730 	/* XXX: Magic numbers */
731 	if (req->ir_compcode == 0xc0) {
732 		device_printf(dev, "Clear flags is busy\n");
733 	}
734 	if (req->ir_compcode == 0xc1) {
735 		device_printf(dev, "Clear flags illegal\n");
736 	}
737 	ipmi_free_request(req);
738 
739 	for (i = 0; i < 8; i++) {
740 		req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
741 		    IPMI_GET_CHANNEL_INFO, 1, 0);
742 		req->ir_request[0] = i;
743 
744 		ipmi_submit_driver_request(sc, req, 0);
745 
746 		if (req->ir_compcode != 0) {
747 			ipmi_free_request(req);
748 			break;
749 		}
750 		ipmi_free_request(req);
751 	}
752 	device_printf(dev, "Number of channels %d\n", i);
753 
754 	/* probe for watchdog */
755 	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
756 	    IPMI_GET_WDOG, 0, 0);
757 
758 	ipmi_submit_driver_request(sc, req, 0);
759 
760 	if (req->ir_compcode == 0x00) {
761 		device_printf(dev, "Attached watchdog\n");
762 		/* register the watchdog event handler */
763 		sc->ipmi_watchdog_tag = EVENTHANDLER_REGISTER(watchdog_list,
764 		    ipmi_wd_event, sc, 0);
765 	}
766 	ipmi_free_request(req);
767 
768 	sc->ipmi_cdev = make_dev(&ipmi_cdevsw, device_get_unit(dev),
769 	    UID_ROOT, GID_OPERATOR, 0660, "ipmi%d", device_get_unit(dev));
770 	if (sc->ipmi_cdev == NULL) {
771 		device_printf(dev, "Failed to create cdev\n");
772 		return;
773 	}
774 	sc->ipmi_cdev->si_drv1 = sc;
775 }
776 
777 int
778 ipmi_attach(device_t dev)
779 {
780 	struct ipmi_softc *sc = device_get_softc(dev);
781 	int error;
782 
783 	if (sc->ipmi_irq_res != NULL && sc->ipmi_intr != NULL) {
784 		error = bus_setup_intr(dev, sc->ipmi_irq_res, INTR_TYPE_MISC,
785 		    NULL, sc->ipmi_intr, sc, &sc->ipmi_irq);
786 		if (error) {
787 			device_printf(dev, "can't set up interrupt\n");
788 			return (error);
789 		}
790 	}
791 
792 	bzero(&sc->ipmi_ich, sizeof(struct intr_config_hook));
793 	sc->ipmi_ich.ich_func = ipmi_startup;
794 	sc->ipmi_ich.ich_arg = sc;
795 	if (config_intrhook_establish(&sc->ipmi_ich) != 0) {
796 		device_printf(dev, "can't establish configuration hook\n");
797 		return (ENOMEM);
798 	}
799 
800 	ipmi_attached = 1;
801 	return (0);
802 }
803 
804 int
805 ipmi_detach(device_t dev)
806 {
807 	struct ipmi_softc *sc;
808 
809 	sc = device_get_softc(dev);
810 
811 	/* Fail if there are any open handles. */
812 	IPMI_LOCK(sc);
813 	if (sc->ipmi_opened) {
814 		IPMI_UNLOCK(sc);
815 		return (EBUSY);
816 	}
817 	IPMI_UNLOCK(sc);
818 	if (sc->ipmi_cdev)
819 		destroy_dev(sc->ipmi_cdev);
820 
821 	/* Detach from watchdog handling and turn off watchdog. */
822 	if (sc->ipmi_watchdog_tag) {
823 		EVENTHANDLER_DEREGISTER(watchdog_list, sc->ipmi_watchdog_tag);
824 		ipmi_set_watchdog(sc, 0);
825 	}
826 
827 	/* XXX: should use shutdown callout I think. */
828 	/* If the backend uses a kthread, shut it down. */
829 	IPMI_LOCK(sc);
830 	sc->ipmi_detaching = 1;
831 	if (sc->ipmi_kthread) {
832 		cv_broadcast(&sc->ipmi_request_added);
833 		msleep(sc->ipmi_kthread, &sc->ipmi_lock, 0, "ipmi_wait", 0);
834 	}
835 	IPMI_UNLOCK(sc);
836 	if (sc->ipmi_irq)
837 		bus_teardown_intr(dev, sc->ipmi_irq_res, sc->ipmi_irq);
838 
839 	ipmi_release_resources(dev);
840 	mtx_destroy(&sc->ipmi_lock);
841 	return (0);
842 }
843 
844 void
845 ipmi_release_resources(device_t dev)
846 {
847 	struct ipmi_softc *sc;
848 	int i;
849 
850 	sc = device_get_softc(dev);
851 	if (sc->ipmi_irq)
852 		bus_teardown_intr(dev, sc->ipmi_irq_res, sc->ipmi_irq);
853 	if (sc->ipmi_irq_res)
854 		bus_release_resource(dev, SYS_RES_IRQ, sc->ipmi_irq_rid,
855 		    sc->ipmi_irq_res);
856 	for (i = 0; i < MAX_RES; i++)
857 		if (sc->ipmi_io_res[i])
858 			bus_release_resource(dev, sc->ipmi_io_type,
859 			    sc->ipmi_io_rid + i, sc->ipmi_io_res[i]);
860 }
861 
862 devclass_t ipmi_devclass;
863 
864 /* XXX: Why? */
865 static void
866 ipmi_unload(void *arg)
867 {
868 	device_t *	devs;
869 	int		count;
870 	int		i;
871 
872 	if (devclass_get_devices(ipmi_devclass, &devs, &count) != 0)
873 		return;
874 	for (i = 0; i < count; i++)
875 		device_delete_child(device_get_parent(devs[i]), devs[i]);
876 	free(devs, M_TEMP);
877 }
878 SYSUNINIT(ipmi_unload, SI_SUB_DRIVERS, SI_ORDER_FIRST, ipmi_unload, NULL);
879 
880 #ifdef IMPI_DEBUG
881 static void
882 dump_buf(u_char *data, int len)
883 {
884 	char buf[20];
885 	char line[1024];
886 	char temp[30];
887 	int count = 0;
888 	int i=0;
889 
890 	printf("Address %p len %d\n", data, len);
891 	if (len > 256)
892 		len = 256;
893 	line[0] = '\000';
894 	for (; len > 0; len--, data++) {
895 		sprintf(temp, "%02x ", *data);
896 		strcat(line, temp);
897 		if (*data >= ' ' && *data <= '~')
898 			buf[count] = *data;
899 		else if (*data >= 'A' && *data <= 'Z')
900 			buf[count] = *data;
901 		else
902 			buf[count] = '.';
903 		if (++count == 16) {
904 			buf[count] = '\000';
905 			count = 0;
906 			printf("  %3x  %s %s\n", i, line, buf);
907 			i+=16;
908 			line[0] = '\000';
909 		}
910 	}
911 	buf[count] = '\000';
912 
913 	for (; count != 16; count++) {
914 		strcat(line, "   ");
915 	}
916 	printf("  %3x  %s %s\n", i, line, buf);
917 }
918 #endif
919