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 * $FreeBSD: head/sys/dev/ipmi/ipmi.c 257421 2013-10-31 05:13:53Z glebius $
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/bus.h>
32 #include <sys/condvar.h>
33 #include <sys/conf.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/module.h>
37 #include <sys/rman.h>
38 #include <sys/sysctl.h>
39 #include <sys/wdog.h>
40 #include <sys/device.h>
41 #include <sys/devfs.h>
42
43 #ifdef LOCAL_MODULE
44 #include <ipmi.h>
45 #include <ipmivars.h>
46 #else
47 #include <sys/ipmi.h>
48 #include <dev/misc/ipmi/ipmivars.h>
49 #endif
50
51 #ifdef IPMB
52 static int ipmi_ipmb_checksum(u_char, int);
53 static int ipmi_ipmb_send_message(device_t, u_char, u_char, u_char,
54 u_char, u_char, int)
55 #endif
56
57 static d_ioctl_t ipmi_ioctl;
58 static d_kqfilter_t ipmi_kqfilter;
59 static d_open_t ipmi_open;
60 static d_priv_dtor_t ipmi_dtor;
61
62 static void ipmi_filter_detach(struct knote *);
63 static int ipmi_filter_read(struct knote *, long);
64
65 int ipmi_attached = 0;
66
67 static int on = 1;
68 static SYSCTL_NODE(_hw, OID_AUTO, ipmi, CTLFLAG_RD, 0,
69 "IPMI driver parameters");
70 SYSCTL_INT(_hw_ipmi, OID_AUTO, on, CTLFLAG_RW,
71 &on, 0, "");
72
73 static struct dev_ops ipmi_ops = {
74 { "ipmi", 0, D_MPSAFE },
75 .d_open = ipmi_open,
76 .d_ioctl = ipmi_ioctl,
77 .d_kqfilter = ipmi_kqfilter,
78 };
79
80 static int ipmi_watchdog_sysctl_enable(SYSCTL_HANDLER_ARGS);
81 static int ipmi_watchdog_sysctl_period(SYSCTL_HANDLER_ARGS);
82
83 static MALLOC_DEFINE(M_IPMI, "ipmi", "ipmi");
84
85 static int
ipmi_open(struct dev_open_args * ap)86 ipmi_open(struct dev_open_args *ap)
87 {
88 struct file *fp = ap->a_fpp ? *ap->a_fpp : NULL;
89 cdev_t cdev = ap->a_head.a_dev;
90 struct ipmi_device *dev;
91 struct ipmi_softc *sc;
92 int error;
93
94 if (!on)
95 return (ENOENT);
96
97 /* Initialize the per file descriptor data. */
98 dev = kmalloc(sizeof(struct ipmi_device), M_IPMI, M_WAITOK | M_ZERO);
99 error = devfs_set_cdevpriv(fp, dev, ipmi_dtor);
100 if (error) {
101 kfree(dev, M_IPMI);
102 return (error);
103 }
104
105 sc = cdev->si_drv1;
106 TAILQ_INIT(&dev->ipmi_completed_requests);
107 dev->ipmi_address = IPMI_BMC_SLAVE_ADDR;
108 dev->ipmi_lun = IPMI_BMC_SMS_LUN;
109 dev->ipmi_softc = sc;
110 IPMI_LOCK(sc);
111 sc->ipmi_opened++;
112 IPMI_UNLOCK(sc);
113
114 return (0);
115 }
116
117 static struct filterops ipmi_filterops = {
118 FILTEROP_ISFD | FILTEROP_MPSAFE,
119 NULL,
120 ipmi_filter_detach,
121 ipmi_filter_read
122 };
123
124 static int
ipmi_kqfilter(struct dev_kqfilter_args * ap)125 ipmi_kqfilter(struct dev_kqfilter_args *ap)
126 {
127 cdev_t cdev = ap->a_head.a_dev;
128 struct file *fp = ap->a_fp;
129 struct knote *kn = ap->a_kn;
130 struct ipmi_softc *sc = cdev->si_drv1;
131 struct ipmi_device *dev;
132 struct klist *klist;
133
134 ap->a_result = 0;
135
136 switch(kn->kn_filter) {
137 case EVFILT_READ:
138 if (devfs_get_cdevpriv(fp, (void **)&dev))
139 return EOPNOTSUPP;
140 kn->kn_fop = &ipmi_filterops;
141 kn->kn_hook = (caddr_t)dev;
142 break;
143 default:
144 ap->a_result = EOPNOTSUPP;
145 return (0);
146 }
147
148 klist = &sc->ipmi_kq.ki_note;
149 knote_insert(klist, kn);
150
151 return (0);
152 }
153
154 static void
ipmi_filter_detach(struct knote * kn)155 ipmi_filter_detach(struct knote *kn)
156 {
157 struct ipmi_device *dev = (struct ipmi_device *)kn->kn_hook;
158 struct ipmi_softc *sc = dev->ipmi_softc;
159 struct klist *klist;
160
161 klist = &sc->ipmi_kq.ki_note;
162 knote_remove(klist, kn);
163 }
164
165 static int
ipmi_filter_read(struct knote * kn,long hint)166 ipmi_filter_read(struct knote *kn, long hint)
167 {
168 struct ipmi_device *dev = (struct ipmi_device *)kn->kn_hook;
169 struct ipmi_softc *sc = dev->ipmi_softc;
170 int ret = 0;
171
172 IPMI_LOCK(sc);
173 if (!TAILQ_EMPTY(&dev->ipmi_completed_requests))
174 ret = 1;
175 if (dev->ipmi_requests == 0)
176 kn->kn_flags |= EV_ERROR;
177 IPMI_UNLOCK(sc);
178
179 return (ret);
180 }
181
182 static void
ipmi_purge_completed_requests(struct ipmi_device * dev)183 ipmi_purge_completed_requests(struct ipmi_device *dev)
184 {
185 struct ipmi_request *req;
186
187 while (!TAILQ_EMPTY(&dev->ipmi_completed_requests)) {
188 req = TAILQ_FIRST(&dev->ipmi_completed_requests);
189 TAILQ_REMOVE(&dev->ipmi_completed_requests, req, ir_link);
190 dev->ipmi_requests--;
191 ipmi_free_request(req);
192 }
193 }
194
195 static void
ipmi_dtor(void * arg)196 ipmi_dtor(void *arg)
197 {
198 struct ipmi_request *req, *nreq;
199 struct ipmi_device *dev;
200 struct ipmi_softc *sc;
201
202 dev = arg;
203 sc = dev->ipmi_softc;
204
205 IPMI_LOCK(sc);
206 if (dev->ipmi_requests) {
207 /* Throw away any pending requests for this device. */
208 TAILQ_FOREACH_MUTABLE(req, &sc->ipmi_pending_requests, ir_link,
209 nreq) {
210 if (req->ir_owner == dev) {
211 TAILQ_REMOVE(&sc->ipmi_pending_requests, req,
212 ir_link);
213 dev->ipmi_requests--;
214 ipmi_free_request(req);
215 }
216 }
217
218 /* Throw away any pending completed requests for this device. */
219 ipmi_purge_completed_requests(dev);
220
221 /*
222 * If we still have outstanding requests, they must be stuck
223 * in an interface driver, so wait for those to drain.
224 */
225 dev->ipmi_closing = 1;
226 while (dev->ipmi_requests > 0) {
227 lksleep(&dev->ipmi_requests, &sc->ipmi_lock, 0,
228 "ipmidrain", 0);
229 ipmi_purge_completed_requests(dev);
230 }
231 }
232 sc->ipmi_opened--;
233 IPMI_UNLOCK(sc);
234
235 /* Cleanup. */
236 kfree(dev, M_IPMI);
237 }
238
239 #ifdef IPMB
240 static int
ipmi_ipmb_checksum(u_char * data,int len)241 ipmi_ipmb_checksum(u_char *data, int len)
242 {
243 u_char sum = 0;
244
245 for (; len; len--) {
246 sum += *data++;
247 }
248 return (-sum);
249 }
250
251 /* XXX: Needs work */
252 static int
ipmi_ipmb_send_message(device_t dev,u_char channel,u_char netfn,u_char command,u_char seq,u_char * data,int data_len)253 ipmi_ipmb_send_message(device_t dev, u_char channel, u_char netfn,
254 u_char command, u_char seq, u_char *data, int data_len)
255 {
256 struct ipmi_softc *sc = device_get_softc(dev);
257 struct ipmi_request *req;
258 u_char slave_addr = 0x52;
259 int error;
260
261 req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
262 IPMI_SEND_MSG, data_len + 8, 0);
263 req->ir_request[0] = channel;
264 req->ir_request[1] = slave_addr;
265 req->ir_request[2] = IPMI_ADDR(netfn, 0);
266 req->ir_request[3] = ipmi_ipmb_checksum(&req->ir_request[1], 2);
267 req->ir_request[4] = sc->ipmi_address;
268 req->ir_request[5] = IPMI_ADDR(seq, sc->ipmi_lun);
269 req->ir_request[6] = command;
270
271 bcopy(data, &req->ir_request[7], data_len);
272 temp[data_len + 7] = ipmi_ipmb_checksum(&req->ir_request[4],
273 data_len + 3);
274
275 ipmi_submit_driver_request(sc, req);
276 error = req->ir_error;
277 ipmi_free_request(req);
278
279 return (error);
280 }
281
282 static int
ipmi_handle_attn(struct ipmi_softc * sc)283 ipmi_handle_attn(struct ipmi_softc *sc)
284 {
285 struct ipmi_request *req;
286 int error;
287
288 device_printf(sc->ipmi_dev, "BMC has a message\n");
289 req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
290 IPMI_GET_MSG_FLAGS, 0, 1);
291
292 ipmi_submit_driver_request(sc, req);
293
294 if (req->ir_error == 0 && req->ir_compcode == 0) {
295 if (req->ir_reply[0] & IPMI_MSG_BUFFER_FULL) {
296 device_printf(sc->ipmi_dev, "message buffer full");
297 }
298 if (req->ir_reply[0] & IPMI_WDT_PRE_TIMEOUT) {
299 device_printf(sc->ipmi_dev,
300 "watchdog about to go off");
301 }
302 if (req->ir_reply[0] & IPMI_MSG_AVAILABLE) {
303 ipmi_free_request(req);
304
305 req = ipmi_alloc_driver_request(
306 IPMI_ADDR(IPMI_APP_REQUEST, 0), IPMI_GET_MSG, 0,
307 16);
308
309 device_printf(sc->ipmi_dev, "throw out message ");
310 dump_buf(temp, 16);
311 }
312 }
313 error = req->ir_error;
314 ipmi_free_request(req);
315
316 return (error);
317 }
318 #endif
319
320 #ifdef IPMICTL_SEND_COMMAND_32
321 #define PTRIN(p) ((void *)(uintptr_t)(p))
322 #define PTROUT(p) ((uintptr_t)(p))
323 #endif
324
325 static int
ipmi_ioctl(struct dev_ioctl_args * ap)326 ipmi_ioctl(struct dev_ioctl_args *ap)
327 {
328 struct file *fp = ap->a_fp;
329 cdev_t cdev = ap->a_head.a_dev;
330 u_long cmd = ap->a_cmd;
331 caddr_t data = ap->a_data;
332 struct ipmi_softc *sc;
333 struct ipmi_device *dev;
334 struct ipmi_request *kreq;
335 struct ipmi_req *req = (struct ipmi_req *)data;
336 struct ipmi_recv *recv = (struct ipmi_recv *)data;
337 struct ipmi_addr addr;
338 #ifdef IPMICTL_SEND_COMMAND_32
339 struct ipmi_req32 *req32 = (struct ipmi_req32 *)data;
340 struct ipmi_recv32 *recv32 = (struct ipmi_recv32 *)data;
341 union {
342 struct ipmi_req req;
343 struct ipmi_recv recv;
344 } thunk32;
345 #endif
346 int error, len;
347
348 error = devfs_get_cdevpriv(fp, (void **)&dev);
349 if (error)
350 return (error);
351
352 sc = cdev->si_drv1;
353
354 #ifdef IPMICTL_SEND_COMMAND_32
355 /* Convert 32-bit structures to native. */
356 switch (cmd) {
357 case IPMICTL_SEND_COMMAND_32:
358 req = &thunk32.req;
359 req->addr = PTRIN(req32->addr);
360 req->addr_len = req32->addr_len;
361 req->msgid = req32->msgid;
362 req->msg.netfn = req32->msg.netfn;
363 req->msg.cmd = req32->msg.cmd;
364 req->msg.data_len = req32->msg.data_len;
365 req->msg.data = PTRIN(req32->msg.data);
366 break;
367 case IPMICTL_RECEIVE_MSG_TRUNC_32:
368 case IPMICTL_RECEIVE_MSG_32:
369 recv = &thunk32.recv;
370 recv->addr = PTRIN(recv32->addr);
371 recv->addr_len = recv32->addr_len;
372 recv->msg.data_len = recv32->msg.data_len;
373 recv->msg.data = PTRIN(recv32->msg.data);
374 break;
375 }
376 #endif
377
378 switch (cmd) {
379 #ifdef IPMICTL_SEND_COMMAND_32
380 case IPMICTL_SEND_COMMAND_32:
381 #endif
382 case IPMICTL_SEND_COMMAND:
383 /*
384 * XXX: Need to add proper handling of this.
385 */
386 error = copyin(req->addr, &addr, sizeof(addr));
387 if (error)
388 return (error);
389
390 IPMI_LOCK(sc);
391 /* clear out old stuff in queue of stuff done */
392 /* XXX: This seems odd. */
393 while ((kreq = TAILQ_FIRST(&dev->ipmi_completed_requests))) {
394 TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq,
395 ir_link);
396 dev->ipmi_requests--;
397 ipmi_free_request(kreq);
398 }
399 IPMI_UNLOCK(sc);
400
401 kreq = ipmi_alloc_request(dev, req->msgid,
402 IPMI_ADDR(req->msg.netfn, 0), req->msg.cmd,
403 req->msg.data_len, IPMI_MAX_RX);
404 error = copyin(req->msg.data, kreq->ir_request,
405 req->msg.data_len);
406 if (error) {
407 ipmi_free_request(kreq);
408 return (error);
409 }
410 IPMI_LOCK(sc);
411 dev->ipmi_requests++;
412 error = sc->ipmi_enqueue_request(sc, kreq);
413 IPMI_UNLOCK(sc);
414 if (error)
415 return (error);
416 break;
417 #ifdef IPMICTL_SEND_COMMAND_32
418 case IPMICTL_RECEIVE_MSG_TRUNC_32:
419 case IPMICTL_RECEIVE_MSG_32:
420 #endif
421 case IPMICTL_RECEIVE_MSG_TRUNC:
422 case IPMICTL_RECEIVE_MSG:
423 error = copyin(recv->addr, &addr, sizeof(addr));
424 if (error)
425 return (error);
426
427 IPMI_LOCK(sc);
428 kreq = TAILQ_FIRST(&dev->ipmi_completed_requests);
429 if (kreq == NULL) {
430 IPMI_UNLOCK(sc);
431 return (EAGAIN);
432 }
433 addr.channel = IPMI_BMC_CHANNEL;
434 /* XXX */
435 recv->recv_type = IPMI_RESPONSE_RECV_TYPE;
436 recv->msgid = kreq->ir_msgid;
437 recv->msg.netfn = IPMI_REPLY_ADDR(kreq->ir_addr) >> 2;
438 recv->msg.cmd = kreq->ir_command;
439 error = kreq->ir_error;
440 if (error) {
441 TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq,
442 ir_link);
443 dev->ipmi_requests--;
444 IPMI_UNLOCK(sc);
445 ipmi_free_request(kreq);
446 return (error);
447 }
448 len = kreq->ir_replylen + 1;
449 if (recv->msg.data_len < len &&
450 (cmd == IPMICTL_RECEIVE_MSG
451 #ifdef IPMICTL_RECEIVE_MSG_32
452 || cmd == IPMICTL_RECEIVE_MSG_32
453 #endif
454 )) {
455 IPMI_UNLOCK(sc);
456 return (EMSGSIZE);
457 }
458 TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link);
459 dev->ipmi_requests--;
460 IPMI_UNLOCK(sc);
461 len = min(recv->msg.data_len, len);
462 recv->msg.data_len = len;
463 error = copyout(&addr, recv->addr,sizeof(addr));
464 if (error == 0)
465 error = copyout(&kreq->ir_compcode, recv->msg.data, 1);
466 if (error == 0)
467 error = copyout(kreq->ir_reply, recv->msg.data + 1,
468 len - 1);
469 ipmi_free_request(kreq);
470 if (error)
471 return (error);
472 break;
473 case IPMICTL_SET_MY_ADDRESS_CMD:
474 IPMI_LOCK(sc);
475 dev->ipmi_address = *(int*)data;
476 IPMI_UNLOCK(sc);
477 break;
478 case IPMICTL_GET_MY_ADDRESS_CMD:
479 IPMI_LOCK(sc);
480 *(int*)data = dev->ipmi_address;
481 IPMI_UNLOCK(sc);
482 break;
483 case IPMICTL_SET_MY_LUN_CMD:
484 IPMI_LOCK(sc);
485 dev->ipmi_lun = *(int*)data & 0x3;
486 IPMI_UNLOCK(sc);
487 break;
488 case IPMICTL_GET_MY_LUN_CMD:
489 IPMI_LOCK(sc);
490 *(int*)data = dev->ipmi_lun;
491 IPMI_UNLOCK(sc);
492 break;
493 case IPMICTL_SET_GETS_EVENTS_CMD:
494 /*
495 device_printf(sc->ipmi_dev,
496 "IPMICTL_SET_GETS_EVENTS_CMD NA\n");
497 */
498 break;
499 case IPMICTL_REGISTER_FOR_CMD:
500 case IPMICTL_UNREGISTER_FOR_CMD:
501 return (EOPNOTSUPP);
502 default:
503 device_printf(sc->ipmi_dev, "Unknown IOCTL %lX\n", cmd);
504 return (ENOIOCTL);
505 }
506
507 #ifdef IPMICTL_SEND_COMMAND_32
508 /* Update changed fields in 32-bit structures. */
509 switch (cmd) {
510 case IPMICTL_RECEIVE_MSG_TRUNC_32:
511 case IPMICTL_RECEIVE_MSG_32:
512 recv32->recv_type = recv->recv_type;
513 recv32->msgid = recv->msgid;
514 recv32->msg.netfn = recv->msg.netfn;
515 recv32->msg.cmd = recv->msg.cmd;
516 recv32->msg.data_len = recv->msg.data_len;
517 break;
518 }
519 #endif
520 return (0);
521 }
522
523 /*
524 * Request management.
525 */
526
527 /* Allocate a new request with request and reply buffers. */
528 struct ipmi_request *
ipmi_alloc_request(struct ipmi_device * dev,long msgid,uint8_t addr,uint8_t command,size_t requestlen,size_t replylen)529 ipmi_alloc_request(struct ipmi_device *dev, long msgid, uint8_t addr,
530 uint8_t command, size_t requestlen, size_t replylen)
531 {
532 struct ipmi_request *req;
533
534 req = kmalloc(sizeof(struct ipmi_request) + requestlen + replylen,
535 M_IPMI, M_WAITOK | M_ZERO);
536 req->ir_owner = dev;
537 req->ir_msgid = msgid;
538 req->ir_addr = addr;
539 req->ir_command = command;
540 if (requestlen) {
541 req->ir_request = (char *)&req[1];
542 req->ir_requestlen = requestlen;
543 }
544 if (replylen) {
545 req->ir_reply = (char *)&req[1] + requestlen;
546 req->ir_replybuflen = replylen;
547 }
548 return (req);
549 }
550
551 /* Free a request no longer in use. */
552 void
ipmi_free_request(struct ipmi_request * req)553 ipmi_free_request(struct ipmi_request *req)
554 {
555
556 kfree(req, M_IPMI);
557 }
558
559 /* Store a processed request on the appropriate completion queue. */
560 void
ipmi_complete_request(struct ipmi_softc * sc,struct ipmi_request * req)561 ipmi_complete_request(struct ipmi_softc *sc, struct ipmi_request *req)
562 {
563 struct ipmi_device *dev;
564
565 IPMI_LOCK_ASSERT(sc);
566
567 /*
568 * Anonymous requests (from inside the driver) always have a
569 * waiter that we awaken.
570 */
571 if (req->ir_owner == NULL)
572 wakeup(req);
573 else {
574 dev = req->ir_owner;
575 TAILQ_INSERT_TAIL(&dev->ipmi_completed_requests, req, ir_link);
576 KNOTE(&sc->ipmi_kq.ki_note, 0);
577 if (dev->ipmi_closing)
578 wakeup(&dev->ipmi_requests);
579 }
580 }
581
582 /* Enqueue an internal driver request and wait until it is completed. */
583 int
ipmi_submit_driver_request(struct ipmi_softc * sc,struct ipmi_request * req,int timo)584 ipmi_submit_driver_request(struct ipmi_softc *sc, struct ipmi_request *req,
585 int timo)
586 {
587 int error;
588
589 IPMI_LOCK(sc);
590 error = sc->ipmi_enqueue_request(sc, req);
591 if (error == 0)
592 error = lksleep(req, &sc->ipmi_lock, 0, "ipmireq", timo);
593 if (error == 0)
594 error = req->ir_error;
595 IPMI_UNLOCK(sc);
596 return (error);
597 }
598
599 /*
600 * Helper routine for polled system interfaces that use
601 * ipmi_polled_enqueue_request() to queue requests. This request
602 * waits until there is a pending request and then returns the first
603 * request. If the driver is shutting down, it returns NULL.
604 */
605 struct ipmi_request *
ipmi_dequeue_request(struct ipmi_softc * sc)606 ipmi_dequeue_request(struct ipmi_softc *sc)
607 {
608 struct ipmi_request *req;
609
610 IPMI_LOCK_ASSERT(sc);
611
612 while (!sc->ipmi_detaching && TAILQ_EMPTY(&sc->ipmi_pending_requests))
613 cv_wait(&sc->ipmi_request_added, &sc->ipmi_lock);
614 if (sc->ipmi_detaching)
615 return (NULL);
616
617 req = TAILQ_FIRST(&sc->ipmi_pending_requests);
618 TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link);
619 return (req);
620 }
621
622 /* Default implementation of ipmi_enqueue_request() for polled interfaces. */
623 int
ipmi_polled_enqueue_request(struct ipmi_softc * sc,struct ipmi_request * req)624 ipmi_polled_enqueue_request(struct ipmi_softc *sc, struct ipmi_request *req)
625 {
626 IPMI_LOCK_ASSERT(sc);
627
628 TAILQ_INSERT_TAIL(&sc->ipmi_pending_requests, req, ir_link);
629
630 cv_signal(&sc->ipmi_request_added);
631 return (0);
632 }
633
634 /*
635 * Watchdog event handler.
636 */
637 static int
ipmi_set_watchdog(struct ipmi_softc * sc,unsigned int sec)638 ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
639 {
640 struct ipmi_request *req;
641 int error;
642
643 if (sec > 0xffff / 10)
644 return (EINVAL);
645
646 req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
647 IPMI_SET_WDOG, 6, 0);
648
649 if (sec) {
650 req->ir_request[0] = IPMI_SET_WD_TIMER_DONT_STOP
651 | IPMI_SET_WD_TIMER_SMS_OS;
652 req->ir_request[1] = IPMI_SET_WD_ACTION_RESET;
653 req->ir_request[2] = 0;
654 req->ir_request[3] = 0; /* Timer use */
655 req->ir_request[4] = (sec * 10) & 0xff;
656 req->ir_request[5] = (sec * 10) >> 8;
657 } else {
658 req->ir_request[0] = IPMI_SET_WD_TIMER_SMS_OS;
659 req->ir_request[1] = 0;
660 req->ir_request[2] = 0;
661 req->ir_request[3] = 0; /* Timer use */
662 req->ir_request[4] = 0;
663 req->ir_request[5] = 0;
664 }
665 error = ipmi_submit_driver_request(sc, req, 0);
666 if (error)
667 device_printf(sc->ipmi_dev, "Failed to set watchdog\n");
668 else if (sec) {
669 ipmi_free_request(req);
670
671 req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
672 IPMI_RESET_WDOG, 0, 0);
673
674 error = ipmi_submit_driver_request(sc, req, 0);
675 if (error)
676 device_printf(sc->ipmi_dev,
677 "Failed to reset watchdog\n");
678 }
679
680 ipmi_free_request(req);
681 return (error);
682 /*
683 dump_watchdog(sc);
684 */
685 }
686
687 static void
ipmi_watchdog(void * arg)688 ipmi_watchdog(void *arg)
689 {
690 struct ipmi_softc *sc = (struct ipmi_softc *)arg;
691 int e;
692
693 if(sc->ipmi_wdog_period) {
694 e = ipmi_set_watchdog(sc, sc->ipmi_wdog_period + 1);
695
696 if (e == 0)
697 sc->ipmi_watchdog_active = 1;
698 else
699 ipmi_set_watchdog(sc, 0);
700
701 callout_reset(&sc->ipmi_watchdog,
702 sc->ipmi_wdog_period * hz,
703 &ipmi_watchdog, (void *)sc);
704 }
705 }
706
707 static void
ipmi_startup(void * arg)708 ipmi_startup(void *arg)
709 {
710 struct ipmi_softc *sc = arg;
711 struct ipmi_request *req;
712 device_t dev;
713 int error, i;
714
715 config_intrhook_disestablish(&sc->ipmi_ich);
716 dev = sc->ipmi_dev;
717
718 /* Initialize interface-independent state. */
719 lockinit(&sc->ipmi_lock, device_get_nameunit(dev), 0, LK_CANRECURSE);
720 cv_init(&sc->ipmi_request_added, "ipmireq");
721 TAILQ_INIT(&sc->ipmi_pending_requests);
722
723 /* Initialize interface-dependent state. */
724 error = sc->ipmi_startup(sc);
725 if (error) {
726 device_printf(dev, "Failed to initialize interface: %d\n",
727 error);
728 return;
729 }
730
731 /* Send a GET_DEVICE_ID request. */
732 req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
733 IPMI_GET_DEVICE_ID, 0, 15);
734
735 error = ipmi_submit_driver_request(sc, req, MAX_TIMEOUT);
736 if (error == EWOULDBLOCK) {
737 device_printf(dev, "Timed out waiting for GET_DEVICE_ID\n");
738 ipmi_free_request(req);
739 return;
740 } else if (error) {
741 device_printf(dev, "Failed GET_DEVICE_ID: %d\n", error);
742 ipmi_free_request(req);
743 return;
744 } else if (req->ir_compcode != 0) {
745 device_printf(dev,
746 "Bad completion code for GET_DEVICE_ID: %d\n",
747 req->ir_compcode);
748 ipmi_free_request(req);
749 return;
750 } else if (req->ir_replylen < 5) {
751 device_printf(dev, "Short reply for GET_DEVICE_ID: %d\n",
752 req->ir_replylen);
753 ipmi_free_request(req);
754 return;
755 }
756
757 device_printf(dev, "IPMI device rev. %d, firmware rev. %d.%d%d, "
758 "version %d.%d\n",
759 req->ir_reply[1] & 0x0f,
760 req->ir_reply[2] & 0x7f, req->ir_reply[3] >> 4, req->ir_reply[3] & 0x0f,
761 req->ir_reply[4] & 0x0f, req->ir_reply[4] >> 4);
762
763 ipmi_free_request(req);
764
765 req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
766 IPMI_CLEAR_FLAGS, 1, 0);
767
768 ipmi_submit_driver_request(sc, req, 0);
769
770 /* XXX: Magic numbers */
771 if (req->ir_compcode == 0xc0) {
772 device_printf(dev, "Clear flags is busy\n");
773 }
774 if (req->ir_compcode == 0xc1) {
775 device_printf(dev, "Clear flags illegal\n");
776 }
777 ipmi_free_request(req);
778
779 for (i = 0; i < 8; i++) {
780 req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
781 IPMI_GET_CHANNEL_INFO, 1, 0);
782 req->ir_request[0] = i;
783
784 ipmi_submit_driver_request(sc, req, 0);
785
786 if (req->ir_compcode != 0) {
787 ipmi_free_request(req);
788 break;
789 }
790 ipmi_free_request(req);
791 }
792 device_printf(dev, "Number of channels %d\n", i);
793
794 /* probe for watchdog */
795 req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
796 IPMI_GET_WDOG, 0, 0);
797
798 ipmi_submit_driver_request(sc, req, 0);
799
800 if (req->ir_compcode == 0x00) {
801 struct sysctl_ctx_list *ctx;
802 struct sysctl_oid *tree;
803 struct sysctl_oid_list *child;
804
805 device_printf(dev, "Attached watchdog\n");
806 /* register the watchdog event handler */
807 /* XXX profmakx: our wdog driver holds a spinlock while
808 running the watchdog function, but since the ipmi watchdog
809 function sleeps, this doesn't work. Hack something with
810 a callout */
811 callout_init(&sc->ipmi_watchdog);
812 sc->ipmi_wdog_enable = 0;
813 sc->ipmi_wdog_period = 30;
814
815 ctx = device_get_sysctl_ctx(dev);
816 tree = device_get_sysctl_tree(dev);
817 child = SYSCTL_CHILDREN(tree);
818
819 SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "watchdog_enable",
820 CTLTYPE_INT | CTLFLAG_RW, sc, 0,
821 ipmi_watchdog_sysctl_enable, "I",
822 "ipmi watchdog enable");
823 SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "watchdog_period",
824 CTLTYPE_INT | CTLFLAG_RW, sc, 0,
825 ipmi_watchdog_sysctl_period, "I",
826 "ipmi watchdog period");
827
828 }
829 ipmi_free_request(req);
830
831 sc->ipmi_cdev = make_dev(&ipmi_ops, device_get_unit(dev),
832 UID_ROOT, GID_OPERATOR, 0660, "ipmi%d", device_get_unit(dev));
833 if (sc->ipmi_cdev == NULL) {
834 device_printf(dev, "Failed to create cdev\n");
835 return;
836 }
837 sc->ipmi_cdev->si_drv1 = sc;
838 }
839
840 int
ipmi_attach(device_t dev)841 ipmi_attach(device_t dev)
842 {
843 struct ipmi_softc *sc = device_get_softc(dev);
844 int error;
845
846 if (sc->ipmi_irq_res != NULL && sc->ipmi_intr != NULL) {
847 error = bus_setup_intr(dev, sc->ipmi_irq_res, 0,
848 sc->ipmi_intr, sc, &sc->ipmi_irq, NULL);
849 if (error) {
850 device_printf(dev, "can't set up interrupt\n");
851 return (error);
852 }
853 }
854
855 bzero(&sc->ipmi_ich, sizeof(struct intr_config_hook));
856 sc->ipmi_ich.ich_func = ipmi_startup;
857 sc->ipmi_ich.ich_arg = sc;
858 sc->ipmi_ich.ich_desc = "ipmi";
859 if (config_intrhook_establish(&sc->ipmi_ich) != 0) {
860 device_printf(dev, "can't establish configuration hook\n");
861 return (ENOMEM);
862 }
863
864 ipmi_attached = 1;
865 return (0);
866 }
867
868 int
ipmi_detach(device_t dev)869 ipmi_detach(device_t dev)
870 {
871 struct ipmi_softc *sc;
872
873 sc = device_get_softc(dev);
874
875 /* Fail if there are any open handles. */
876 IPMI_LOCK(sc);
877 if (sc->ipmi_opened) {
878 IPMI_UNLOCK(sc);
879 return (EBUSY);
880 }
881 IPMI_UNLOCK(sc);
882 if (sc->ipmi_cdev)
883 destroy_dev(sc->ipmi_cdev);
884
885 /* Detach from watchdog handling and turn off watchdog. */
886 callout_cancel(&sc->ipmi_watchdog);
887 ipmi_set_watchdog(sc, 0);
888
889 /* XXX: should use shutdown callout I think. */
890 /* If the backend uses a kthread, shut it down. */
891 IPMI_LOCK(sc);
892 sc->ipmi_detaching = 1;
893 if (sc->ipmi_kthread) {
894 cv_broadcast(&sc->ipmi_request_added);
895 lksleep(sc->ipmi_kthread, &sc->ipmi_lock, 0, "ipmi_wait", 0);
896 }
897 IPMI_UNLOCK(sc);
898 if (sc->ipmi_irq)
899 bus_teardown_intr(dev, sc->ipmi_irq_res, sc->ipmi_irq);
900
901 ipmi_release_resources(dev);
902 lockuninit(&sc->ipmi_lock);
903 return (0);
904 }
905
906 void
ipmi_release_resources(device_t dev)907 ipmi_release_resources(device_t dev)
908 {
909 struct ipmi_softc *sc;
910 int i;
911
912 sc = device_get_softc(dev);
913 if (sc->ipmi_irq)
914 bus_teardown_intr(dev, sc->ipmi_irq_res, sc->ipmi_irq);
915 if (sc->ipmi_irq_res)
916 bus_release_resource(dev, SYS_RES_IRQ, sc->ipmi_irq_rid,
917 sc->ipmi_irq_res);
918 for (i = 0; i < MAX_RES; i++)
919 if (sc->ipmi_io_res[i])
920 bus_release_resource(dev, sc->ipmi_io_type,
921 sc->ipmi_io_rid + i, sc->ipmi_io_res[i]);
922 }
923
924 devclass_t ipmi_devclass;
925
926 /* XXX: Why? */
927 static void
ipmi_unload(void * arg)928 ipmi_unload(void *arg)
929 {
930 device_t * devs;
931 int count;
932 int i;
933
934 if (devclass_get_devices(ipmi_devclass, &devs, &count) != 0)
935 return;
936 for (i = 0; i < count; i++)
937 device_delete_child(device_get_parent(devs[i]), devs[i]);
938 kfree(devs, M_TEMP);
939 }
940 SYSUNINIT(ipmi_unload, SI_SUB_DRIVERS, SI_ORDER_FIRST, ipmi_unload, NULL);
941
942 static int
ipmi_watchdog_sysctl_enable(SYSCTL_HANDLER_ARGS)943 ipmi_watchdog_sysctl_enable(SYSCTL_HANDLER_ARGS)
944 {
945 struct ipmi_softc *sc;
946 int enable;
947 int error;
948
949 sc = oidp->oid_arg1;
950
951 IPMI_LOCK(sc);
952 enable = sc->ipmi_wdog_enable;
953 IPMI_UNLOCK(sc);
954
955 error = sysctl_handle_int(oidp, &enable, 0, req);
956 if(error || req->newptr == NULL)
957 return error;
958
959 IPMI_LOCK(sc);
960 sc->ipmi_wdog_enable = enable;
961 IPMI_UNLOCK(sc);
962
963 if (sc->ipmi_wdog_enable==0) {
964 callout_stop(&sc->ipmi_watchdog);
965 ipmi_set_watchdog(sc, 0);
966 } else {
967 callout_reset(&sc->ipmi_watchdog,
968 sc->ipmi_wdog_period * hz,
969 &ipmi_watchdog, (void *)sc);
970 ipmi_set_watchdog(sc, sc->ipmi_wdog_period + 1);
971 }
972 return 0;
973 }
974
975 static int
ipmi_watchdog_sysctl_period(SYSCTL_HANDLER_ARGS)976 ipmi_watchdog_sysctl_period(SYSCTL_HANDLER_ARGS)
977 {
978 struct ipmi_softc *sc;
979 int error;
980 int period;
981
982 sc = oidp->oid_arg1;
983
984 IPMI_LOCK(sc);
985 period = sc->ipmi_wdog_period;
986 IPMI_UNLOCK(sc);
987
988 error = sysctl_handle_int(oidp, &period, 30, req);
989
990 if (error || req->newptr == NULL)
991 return error;
992
993 IPMI_LOCK(sc);
994 sc->ipmi_wdog_period = period;
995 IPMI_UNLOCK(sc);
996
997 return 0;
998 }
999
1000 #ifdef IMPI_DEBUG
1001 static void
dump_buf(u_char * data,int len)1002 dump_buf(u_char *data, int len)
1003 {
1004 char buf[20];
1005 char line[1024];
1006 char temp[30];
1007 int count = 0;
1008 int i=0;
1009
1010 printf("Address %p len %d\n", data, len);
1011 if (len > 256)
1012 len = 256;
1013 line[0] = '\000';
1014 for (; len > 0; len--, data++) {
1015 sprintf(temp, "%02x ", *data);
1016 strcat(line, temp);
1017 if (*data >= ' ' && *data <= '~')
1018 buf[count] = *data;
1019 else if (*data >= 'A' && *data <= 'Z')
1020 buf[count] = *data;
1021 else
1022 buf[count] = '.';
1023 if (++count == 16) {
1024 buf[count] = '\000';
1025 count = 0;
1026 printf(" %3x %s %s\n", i, line, buf);
1027 i+=16;
1028 line[0] = '\000';
1029 }
1030 }
1031 buf[count] = '\000';
1032
1033 for (; count != 16; count++) {
1034 strcat(line, " ");
1035 }
1036 printf(" %3x %s %s\n", i, line, buf);
1037 }
1038 #endif
1039