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