1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2019 Joyent, Inc.
24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * The ipmi driver is an openipmi compatible IPMI driver based on the FreeBSD
29 * driver.
30 *
31 * The current implementation has several limitations:
32 * 1) It only does discovery through the SMBIOS. The FreeBSD driver has
33 * several additional ways to discover the IPMI device (acpi, bus checking,
34 * etc.). This support could be ported if necessary.
35 * 2) The driver currently only supports the IPMI KCS_MODE mode (reported
36 * through the SMBIOS as SMBIOS SMB_IPMI_T_KCS). Support for the other modes
37 * (BT_MODE, SMIC_MODE, SSIF_MODE) could be ported if necessary.
38 * 3) The driver does not currently set up an IPMI watchdog. This also could
39 * be ported if necessary.
40 */
41
42 #include <sys/devops.h>
43 #include <sys/conf.h>
44 #include <sys/modctl.h>
45 #include <sys/types.h>
46 #include <sys/file.h>
47 #include <sys/errno.h>
48 #include <sys/open.h>
49 #include <sys/cred.h>
50 #include <sys/uio.h>
51 #include <sys/stat.h>
52 #include <sys/cmn_err.h>
53 #include <sys/ddi.h>
54 #include <sys/sunddi.h>
55 #include <sys/smbios.h>
56 #include <sys/smbios_impl.h>
57 #include <sys/policy.h>
58 #include <sys/ipmi.h>
59 #include "ipmivars.h"
60
61 static dev_info_t *ipmi_dip;
62 static boolean_t ipmi_attached = B_FALSE;
63 static boolean_t ipmi_found = B_FALSE;
64 static struct ipmi_softc softc;
65 static struct ipmi_softc *sc = &softc;
66 static list_t dev_list;
67 static id_space_t *minor_ids;
68 static kmutex_t dev_list_lock;
69
70 #define PTRIN(p) ((void *)(uintptr_t)(p))
71 #define PTROUT(p) ((uintptr_t)(p))
72
73 /*
74 * Use the SMBIOS info to determine if the system has an IPMI.
75 */
76 static int
get_smbios_ipmi_info(void)77 get_smbios_ipmi_info(void)
78 {
79 smbios_ipmi_t ipmi;
80
81 if (ksmbios == NULL || smbios_info_ipmi(ksmbios, &ipmi) == SMB_ERR)
82 return (DDI_FAILURE);
83
84 cmn_err(CE_CONT, "!SMBIOS type 0x%x, addr 0x%llx", ipmi.smbip_type,
85 (long long unsigned int)(ipmi.smbip_addr));
86
87 /*
88 * Some systems have a bios that will report an IPMI device even when
89 * it is not installed. In this case we see 0x0 as the base address.
90 * If we see this address, assume the device is not really present.
91 */
92 if (ipmi.smbip_addr == NULL) {
93 cmn_err(CE_WARN, "!SMBIOS: Invalid base address");
94 return (DDI_FAILURE);
95 }
96
97 sc->ipmi_io_type = ipmi.smbip_type;
98 switch (ipmi.smbip_type) {
99 case SMB_IPMI_T_KCS:
100 case SMB_IPMI_T_SMIC:
101 sc->ipmi_io_address = ipmi.smbip_addr;
102 sc->ipmi_io_mode = (ipmi.smbip_flags & SMB_IPMI_F_IOADDR) ?
103 1 : 0;
104 sc->ipmi_io_spacing = ipmi.smbip_regspacing;
105 break;
106 case SMB_IPMI_T_SSIF:
107 if ((ipmi.smbip_addr & 0xffffffffffffff00) != 0) {
108 cmn_err(CE_WARN, "!SMBIOS: Invalid SSIF SMBus address, "
109 "using BMC I2C slave address instead");
110 sc->ipmi_io_address = ipmi.smbip_i2c;
111 } else {
112 sc->ipmi_io_address = ipmi.smbip_addr;
113 }
114 break;
115 default:
116 return (DDI_FAILURE);
117 }
118
119 if (ipmi.smbip_intr > 15) {
120 cmn_err(CE_WARN, "!SMBIOS: Non-ISA IRQ %d for IPMI",
121 ipmi.smbip_intr);
122 return (DDI_FAILURE);
123 }
124
125 sc->ipmi_io_irq = ipmi.smbip_intr;
126 return (DDI_SUCCESS);
127 }
128
129 static ipmi_device_t *
lookup_ipmidev_by_dev(dev_t dev)130 lookup_ipmidev_by_dev(dev_t dev)
131 {
132 ipmi_device_t *p;
133
134 mutex_enter(&dev_list_lock);
135 for (p = list_head(&dev_list); p; p = list_next(&dev_list, p)) {
136 if (dev == p->ipmi_dev) {
137 mutex_exit(&dev_list_lock);
138 return (p);
139 }
140 }
141 mutex_exit(&dev_list_lock);
142 return (NULL);
143 }
144
145 /*
146 * Each open returns a new pseudo device.
147 */
148 /*ARGSUSED*/
149 static int
ipmi_open(dev_t * devp,int flag,int otyp,cred_t * cred)150 ipmi_open(dev_t *devp, int flag, int otyp, cred_t *cred)
151 {
152 minor_t minor;
153 ipmi_device_t *dev;
154 id_t mid;
155
156 if (ipmi_attached == B_FALSE)
157 return (ENXIO);
158
159 if (ipmi_found == B_FALSE)
160 return (ENODEV);
161
162 /* exclusive opens are not supported */
163 if (flag & FEXCL)
164 return (ENOTSUP);
165
166 if ((mid = id_alloc_nosleep(minor_ids)) == -1)
167 return (ENODEV);
168 minor = (minor_t)mid;
169
170 /* Initialize the per file descriptor data. */
171 dev = kmem_zalloc(sizeof (ipmi_device_t), KM_SLEEP);
172
173 dev->ipmi_pollhead = kmem_zalloc(sizeof (pollhead_t), KM_SLEEP);
174
175 TAILQ_INIT(&dev->ipmi_completed_requests);
176 dev->ipmi_address = IPMI_BMC_SLAVE_ADDR;
177 dev->ipmi_lun = IPMI_BMC_SMS_LUN;
178 *devp = makedevice(getmajor(*devp), minor);
179 dev->ipmi_dev = *devp;
180 cv_init(&dev->ipmi_cv, NULL, CV_DEFAULT, NULL);
181
182 mutex_enter(&dev_list_lock);
183 list_insert_head(&dev_list, dev);
184 mutex_exit(&dev_list_lock);
185
186 return (0);
187 }
188
189 /*ARGSUSED*/
190 static int
ipmi_close(dev_t dev,int flag,int otyp,cred_t * cred)191 ipmi_close(dev_t dev, int flag, int otyp, cred_t *cred)
192 {
193 ipmi_device_t *dp;
194 struct ipmi_request *req, *next;
195
196 if ((dp = lookup_ipmidev_by_dev(dev)) == NULL)
197 return (ENODEV);
198
199 IPMI_LOCK(sc);
200 /* remove any pending requests */
201 req = TAILQ_FIRST(&sc->ipmi_pending_requests);
202 while (req != NULL) {
203 next = TAILQ_NEXT(req, ir_link);
204
205 if (req->ir_owner == dp) {
206 TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link);
207 ipmi_free_request(req);
208 }
209 req = next;
210 }
211
212 dp->ipmi_status |= IPMI_CLOSING;
213 while (dp->ipmi_status & IPMI_BUSY)
214 cv_wait(&dp->ipmi_cv, &sc->ipmi_lock);
215 IPMI_UNLOCK(sc);
216
217 /* remove any requests in queue of stuff completed */
218 while ((req = TAILQ_FIRST(&dp->ipmi_completed_requests)) != NULL) {
219 TAILQ_REMOVE(&dp->ipmi_completed_requests, req, ir_link);
220 ipmi_free_request(req);
221 }
222
223 mutex_enter(&dev_list_lock);
224 list_remove(&dev_list, dp);
225 mutex_exit(&dev_list_lock);
226 id_free(minor_ids, getminor(dev));
227 cv_destroy(&dp->ipmi_cv);
228 kmem_free(dp->ipmi_pollhead, sizeof (pollhead_t));
229 kmem_free(dp, sizeof (ipmi_device_t));
230
231 return (0);
232 }
233
234 /*ARGSUSED*/
235 static int
ipmi_ioctl(dev_t dv,int cmd,intptr_t data,int flags,cred_t * cr,int * rvalp)236 ipmi_ioctl(dev_t dv, int cmd, intptr_t data, int flags, cred_t *cr, int *rvalp)
237 {
238 struct ipmi_device *dev;
239 struct ipmi_request *kreq;
240 struct ipmi_req req;
241 struct ipmi_recv recv;
242 struct ipmi_recv32 recv32;
243 struct ipmi_addr addr;
244 int error, len;
245 model_t model;
246 int orig_cmd = 0;
247 uchar_t t_lun;
248
249 if (secpolicy_sys_config(cr, B_FALSE) != 0)
250 return (EPERM);
251
252 if ((dev = lookup_ipmidev_by_dev(dv)) == NULL)
253 return (ENODEV);
254
255 model = get_udatamodel();
256 if (model == DATAMODEL_NATIVE) {
257 switch (cmd) {
258 case IPMICTL_SEND_COMMAND:
259 if (copyin((void *)data, &req, sizeof (req)))
260 return (EFAULT);
261 break;
262 case IPMICTL_RECEIVE_MSG_TRUNC:
263 case IPMICTL_RECEIVE_MSG:
264 if (copyin((void *)data, &recv, sizeof (recv)))
265 return (EFAULT);
266 break;
267 }
268 } else {
269 /* Convert 32-bit structures to native. */
270 struct ipmi_req32 req32;
271
272 switch (cmd) {
273 case IPMICTL_SEND_COMMAND_32:
274 if (copyin((void *)data, &req32, sizeof (req32)))
275 return (EFAULT);
276
277 req.addr = PTRIN(req32.addr);
278 req.addr_len = req32.addr_len;
279 req.msgid = req32.msgid;
280 req.msg.netfn = req32.msg.netfn;
281 req.msg.cmd = req32.msg.cmd;
282 req.msg.data_len = req32.msg.data_len;
283 req.msg.data = PTRIN(req32.msg.data);
284
285 cmd = IPMICTL_SEND_COMMAND;
286 break;
287
288 case IPMICTL_RECEIVE_MSG_TRUNC_32:
289 case IPMICTL_RECEIVE_MSG_32:
290 if (copyin((void *)data, &recv32, sizeof (recv32)))
291 return (EFAULT);
292
293 recv.addr = PTRIN(recv32.addr);
294 recv.addr_len = recv32.addr_len;
295 recv.msg.data_len = recv32.msg.data_len;
296 recv.msg.data = PTRIN(recv32.msg.data);
297
298 orig_cmd = cmd;
299 cmd = (cmd == IPMICTL_RECEIVE_MSG_TRUNC_32) ?
300 IPMICTL_RECEIVE_MSG_TRUNC : IPMICTL_RECEIVE_MSG;
301 break;
302 }
303 }
304
305 switch (cmd) {
306 case IPMICTL_SEND_COMMAND:
307 /* Check that we didn't get a ridiculous length */
308 if (req.msg.data_len > IPMI_MAX_RX)
309 return (EINVAL);
310
311 kreq = ipmi_alloc_request(dev, req.msgid,
312 IPMI_ADDR(req.msg.netfn, 0), req.msg.cmd,
313 req.msg.data_len, IPMI_MAX_RX);
314 /* This struct is the same for 32/64 */
315 if (req.msg.data_len > 0 &&
316 copyin(req.msg.data, kreq->ir_request, req.msg.data_len)) {
317 ipmi_free_request(kreq);
318 return (EFAULT);
319 }
320 IPMI_LOCK(sc);
321 dev->ipmi_requests++;
322 error = sc->ipmi_enqueue_request(sc, kreq);
323 IPMI_UNLOCK(sc);
324 if (error)
325 return (error);
326 break;
327
328 case IPMICTL_RECEIVE_MSG_TRUNC:
329 case IPMICTL_RECEIVE_MSG:
330 /* This struct is the same for 32/64 */
331 if (copyin(recv.addr, &addr, sizeof (addr)))
332 return (EFAULT);
333
334 IPMI_LOCK(sc);
335 kreq = TAILQ_FIRST(&dev->ipmi_completed_requests);
336 if (kreq == NULL) {
337 IPMI_UNLOCK(sc);
338 return (EAGAIN);
339 }
340 addr.channel = IPMI_BMC_CHANNEL;
341 recv.recv_type = IPMI_RESPONSE_RECV_TYPE;
342 recv.msgid = kreq->ir_msgid;
343 recv.msg.netfn = IPMI_REPLY_ADDR(kreq->ir_addr) >> 2;
344 recv.msg.cmd = kreq->ir_command;
345 error = kreq->ir_error;
346 if (error) {
347 TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq,
348 ir_link);
349 dev->ipmi_requests--;
350 IPMI_UNLOCK(sc);
351 ipmi_free_request(kreq);
352 return (error);
353 }
354 len = kreq->ir_replylen + 1;
355 if (recv.msg.data_len < len && cmd == IPMICTL_RECEIVE_MSG) {
356 IPMI_UNLOCK(sc);
357 return (EMSGSIZE);
358 }
359 TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link);
360 dev->ipmi_requests--;
361 IPMI_UNLOCK(sc);
362 len = min(recv.msg.data_len, len);
363 recv.msg.data_len = (unsigned short)len;
364
365 if (orig_cmd == IPMICTL_RECEIVE_MSG_TRUNC_32 ||
366 orig_cmd == IPMICTL_RECEIVE_MSG_32) {
367 /* Update changed fields in 32-bit structure. */
368 recv32.recv_type = recv.recv_type;
369 recv32.msgid = (int32_t)recv.msgid;
370 recv32.msg.netfn = recv.msg.netfn;
371 recv32.msg.cmd = recv.msg.cmd;
372 recv32.msg.data_len = recv.msg.data_len;
373
374 error = copyout(&recv32, (void *)data, sizeof (recv32));
375 } else {
376 error = copyout(&recv, (void *)data, sizeof (recv));
377 }
378
379 /* This struct is the same for 32/64 */
380 if (error == 0)
381 error = copyout(&addr, recv.addr, sizeof (addr));
382 if (error == 0)
383 error = copyout(&kreq->ir_compcode, recv.msg.data, 1);
384 if (error == 0)
385 error = copyout(kreq->ir_reply, recv.msg.data + 1,
386 len - 1);
387 ipmi_free_request(kreq);
388
389 if (error)
390 return (EFAULT);
391
392 break;
393
394 case IPMICTL_SET_MY_ADDRESS_CMD:
395 IPMI_LOCK(sc);
396 if (copyin((void *)data, &dev->ipmi_address,
397 sizeof (dev->ipmi_address))) {
398 IPMI_UNLOCK(sc);
399 return (EFAULT);
400 }
401 IPMI_UNLOCK(sc);
402 break;
403
404 case IPMICTL_GET_MY_ADDRESS_CMD:
405 IPMI_LOCK(sc);
406 if (copyout(&dev->ipmi_address, (void *)data,
407 sizeof (dev->ipmi_address))) {
408 IPMI_UNLOCK(sc);
409 return (EFAULT);
410 }
411 IPMI_UNLOCK(sc);
412 break;
413
414 case IPMICTL_SET_MY_LUN_CMD:
415 IPMI_LOCK(sc);
416 if (copyin((void *)data, &t_lun, sizeof (t_lun))) {
417 IPMI_UNLOCK(sc);
418 return (EFAULT);
419 }
420 dev->ipmi_lun = t_lun & 0x3;
421 IPMI_UNLOCK(sc);
422 break;
423
424 case IPMICTL_GET_MY_LUN_CMD:
425 IPMI_LOCK(sc);
426 if (copyout(&dev->ipmi_lun, (void *)data,
427 sizeof (dev->ipmi_lun))) {
428 IPMI_UNLOCK(sc);
429 return (EFAULT);
430 }
431 IPMI_UNLOCK(sc);
432 break;
433
434 case IPMICTL_SET_GETS_EVENTS_CMD:
435 break;
436
437 case IPMICTL_REGISTER_FOR_CMD:
438 case IPMICTL_UNREGISTER_FOR_CMD:
439 return (EINVAL);
440
441 default:
442 return (EINVAL);
443 }
444
445 return (0);
446 }
447
448 static int
ipmi_poll(dev_t dv,short events,int anyyet,short * reventsp,pollhead_t ** phpp)449 ipmi_poll(dev_t dv, short events, int anyyet, short *reventsp,
450 pollhead_t **phpp)
451 {
452 struct ipmi_device *dev;
453 short revent = 0;
454
455 if ((dev = lookup_ipmidev_by_dev(dv)) == NULL)
456 return (ENODEV);
457
458 if (events & (POLLIN | POLLRDNORM)) {
459 if (!TAILQ_EMPTY(&dev->ipmi_completed_requests))
460 revent |= events & (POLLIN | POLLRDNORM);
461 if (dev->ipmi_requests == 0)
462 revent |= POLLERR;
463 }
464
465 if (revent == 0) {
466 /* nothing has occurred */
467 if (!anyyet)
468 *phpp = dev->ipmi_pollhead;
469 }
470
471 *reventsp = revent;
472 return (0);
473 }
474
475 /*ARGSUSED*/
476 static int
ipmi_info(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)477 ipmi_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
478 {
479 switch (cmd) {
480 case DDI_INFO_DEVT2DEVINFO:
481 *resultp = ipmi_dip;
482 return (DDI_SUCCESS);
483 case DDI_INFO_DEVT2INSTANCE:
484 *resultp = NULL;
485 return (DDI_SUCCESS);
486 }
487 return (DDI_FAILURE);
488 }
489
490 static void
ipmi_cleanup(dev_info_t * dip)491 ipmi_cleanup(dev_info_t *dip)
492 {
493 /* poke the taskq so that it can terminate */
494 IPMI_LOCK(sc);
495 sc->ipmi_detaching = 1;
496 cv_signal(&sc->ipmi_request_added);
497 IPMI_UNLOCK(sc);
498
499 ipmi_shutdown(sc);
500 ddi_remove_minor_node(dip, NULL);
501 ipmi_dip = NULL;
502
503 mutex_destroy(&dev_list_lock);
504 list_destroy(&dev_list);
505 id_space_destroy(minor_ids);
506
507 sc->ipmi_detaching = 0;
508 }
509
510 static int
ipmi_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)511 ipmi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
512 {
513 if (cmd != DDI_ATTACH)
514 return (DDI_FAILURE);
515
516 /* this driver only supports one device instance */
517 if (ddi_get_instance(dip) != 0) {
518 cmn_err(CE_WARN,
519 "!not attaching to non-zero device instance %d",
520 ddi_get_instance(dip));
521 return (DDI_FAILURE);
522 }
523
524 if (get_smbios_ipmi_info() == DDI_FAILURE)
525 return (DDI_FAILURE);
526
527 /*
528 * Support for the other types (SMIC, SSIF) should be added here.
529 */
530 switch (sc->ipmi_io_type) {
531 case SMB_IPMI_T_KCS:
532 if (ipmi_kcs_attach(sc) != 0)
533 return (DDI_FAILURE);
534 break;
535 default:
536 return (DDI_FAILURE);
537 }
538 ipmi_found = B_TRUE;
539
540 if (ddi_create_minor_node(dip, "ipmi", S_IFCHR, 0, DDI_PSEUDO,
541 0) == DDI_FAILURE) {
542 cmn_err(CE_WARN, "!attach could not create minor node");
543 ddi_remove_minor_node(dip, NULL);
544 return (DDI_FAILURE);
545 }
546
547 ipmi_dip = dip;
548
549 list_create(&dev_list, sizeof (ipmi_device_t),
550 offsetof(ipmi_device_t, ipmi_node));
551 mutex_init(&dev_list_lock, NULL, MUTEX_DRIVER, NULL);
552
553 /* Create ID space for open devs. ID 0 is reserved. */
554 minor_ids = id_space_create("ipmi_id_space", 1, 128);
555
556 if (ipmi_startup(sc) != B_TRUE) {
557 ipmi_cleanup(dip);
558 return (DDI_FAILURE);
559 }
560
561 ipmi_attached = B_TRUE;
562
563 return (DDI_SUCCESS);
564 }
565
566 static int
ipmi_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)567 ipmi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
568 {
569 if (cmd != DDI_DETACH)
570 return (DDI_FAILURE);
571
572 if (ipmi_found == B_FALSE)
573 return (DDI_SUCCESS);
574
575 mutex_enter(&dev_list_lock);
576 if (!list_is_empty(&dev_list)) {
577 mutex_exit(&dev_list_lock);
578 return (DDI_FAILURE);
579 }
580 mutex_exit(&dev_list_lock);
581
582 ipmi_cleanup(dip);
583
584 ipmi_attached = B_FALSE;
585 return (DDI_SUCCESS);
586 }
587
588 static struct cb_ops ipmi_cb_ops = {
589 ipmi_open,
590 ipmi_close,
591 nodev, /* strategy */
592 nodev, /* print */
593 nodev, /* dump */
594 nodev, /* read */
595 nodev, /* write */
596 ipmi_ioctl,
597 nodev, /* devmap */
598 nodev, /* mmap */
599 nodev, /* segmap */
600 ipmi_poll,
601 ddi_prop_op,
602 NULL, /* streamtab */
603 D_NEW | D_MP, /* flags */
604 CB_REV,
605 nodev, /* awread */
606 nodev /* awrite */
607 };
608
609 static struct dev_ops ipmi_ops = {
610 DEVO_REV,
611 0, /* reference count */
612 ipmi_info,
613 nulldev, /* identify */
614 nulldev, /* probe */
615 ipmi_attach,
616 ipmi_detach,
617 nodev, /* reset */
618 &ipmi_cb_ops,
619 NULL, /* bus ops */
620 NULL, /* power */
621 ddi_quiesce_not_needed,
622 };
623
624 static struct modldrv md = {
625 &mod_driverops, "ipmi driver", &ipmi_ops
626 };
627
628 static struct modlinkage ml = {
629 MODREV_1, &md, NULL
630 };
631
632 int
_init(void)633 _init(void)
634 {
635 return (mod_install(&ml));
636 }
637
638 int
_fini(void)639 _fini(void)
640 {
641 return (mod_remove(&ml));
642 }
643
644 int
_info(struct modinfo * mip)645 _info(struct modinfo *mip)
646 {
647 return (mod_info(&ml, mip));
648 }
649