989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * CDDL HEADER START
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * The contents of this file are subject to the terms of the
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * Common Development and Distribution License (the "License").
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * You may not use this file except in compliance with the License.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * See the License for the specific language governing permissions
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * and limitations under the License.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * When distributing Covered Code, include this CDDL HEADER in each
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * If applicable, add the following below this CDDL HEADER, with the
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * fields enclosed by brackets "[]" replaced with your own identifying
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * information: Portions Copyright [yyyy] [name of copyright owner]
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * CDDL HEADER END
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi * Copyright (c) 2013, Joyent, Inc. All rights reserved.
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * The ipmi driver is an openipmi compatible IPMI driver based on the FreeBSD
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * The current implementation has several limitations:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * 1) It only does discovery through the SMBIOS. The FreeBSD driver has
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * several additional ways to discover the IPMI device (acpi, bus checking,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * etc.). This support could be ported if necessary.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * 2) The driver currently only supports the IPMI KCS_MODE mode (reported
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * through the SMBIOS as SMBIOS SMB_IPMI_T_KCS). Support for the other modes
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * (BT_MODE, SMIC_MODE, SSIF_MODE) could be ported if necessary.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * 3) The driver does not currently set up an IPMI watchdog. This also could
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * be ported if necessary.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * Use the SMBIOS info to determine if the system has an IPMI.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (ksmbios == NULL || smbios_info_ipmi(ksmbios, &ipmi) == SMB_ERR)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmn_err(CE_CONT, "!SMBIOS type 0x%x, addr 0x%llx", ipmi.smbip_type,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * Some systems have a bios that will report an IPMI device even when
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * it is not installed. In this case we see 0x0 as the base address.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * If we see this address, assume the device is not really present.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmn_err(CE_WARN, "!SMBIOS: Invalid base address");
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek sc->ipmi_io_mode = (ipmi.smbip_flags & SMB_IPMI_F_IOADDR) ?
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if ((ipmi.smbip_addr & 0xffffffffffffff00) != 0) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmn_err(CE_WARN, "!SMBIOS: Invalid SSIF SMBus address, "
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek "using BMC I2C slave address instead");
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmn_err(CE_WARN, "!SMBIOS: Non-ISA IRQ %d for IPMI",
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek for (p = list_head(&dev_list); p; p = list_next(&dev_list, p)) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * Each open returns a new pseudo device.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_open(dev_t *devp, int flag, int otyp, cred_t *cred)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* exclusive opens are not supported */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if ((minor = (minor_t)id_alloc_nosleep(minor_ids)) == 0)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* Initialize the per file descriptor data. */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev = kmem_zalloc(sizeof (ipmi_device_t), KM_SLEEP);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev->ipmi_pollhead = kmem_zalloc(sizeof (pollhead_t), KM_SLEEP);
cc944374608a39fb5622959cc9a210fb116539cbMarcel Telka cv_init(&dev->ipmi_cv, NULL, CV_DEFAULT, NULL);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_close(dev_t dev, int flag, int otyp, cred_t *cred)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if ((dp = lookup_ipmidev_by_dev(dev)) == NULL)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* remove any pending requests */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req = TAILQ_FIRST(&sc->ipmi_pending_requests);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* remove any requests in queue of stuff completed */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek while ((req = TAILQ_FIRST(&dp->ipmi_completed_requests)) != NULL) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek TAILQ_REMOVE(&dp->ipmi_completed_requests, req, ir_link);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek kmem_free(dp->ipmi_pollhead, sizeof (pollhead_t));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_ioctl(dev_t dv, int cmd, intptr_t data, int flags, cred_t *cr, int *rvalp)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if ((dev = lookup_ipmidev_by_dev(dv)) == NULL)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin((void *)data, &recv, sizeof (recv)))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* Convert 32-bit structures to native. */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin((void *)data, &req32, sizeof (req32)))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin((void *)data, &recv32, sizeof (recv32)))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMICTL_RECEIVE_MSG_TRUNC : IPMICTL_RECEIVE_MSG;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* Check that we didn't get a ridiculous length */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* This struct is the same for 32/64 */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek copyin(req.msg.data, kreq->ir_request, req.msg.data_len)) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* This struct is the same for 32/64 */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek kreq = TAILQ_FIRST(&dev->ipmi_completed_requests);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv.msg.netfn = IPMI_REPLY_ADDR(kreq->ir_addr) >> 2;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (recv.msg.data_len < len && cmd == IPMICTL_RECEIVE_MSG) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (orig_cmd == IPMICTL_RECEIVE_MSG_TRUNC_32 ||
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* Update changed fields in 32-bit structure. */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = copyout(&recv32, (void *)data, sizeof (recv32));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = copyout(&recv, (void *)data, sizeof (recv));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* This struct is the same for 32/64 */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = copyout(&addr, recv.addr, sizeof (addr));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = copyout(&kreq->ir_compcode, recv.msg.data, 1);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = copyout(kreq->ir_reply, recv.msg.data + 1,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin((void *)data, &t_lun, sizeof (t_lun))) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_poll(dev_t dv, short events, int anyyet, short *reventsp,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if ((dev = lookup_ipmidev_by_dev(dv)) == NULL)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (!TAILQ_EMPTY(&dev->ipmi_completed_requests))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* nothing has occurred */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka /* poke the taskq so that it can terminate */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk /* this driver only supports one device instance */
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk "!not attaching to non-zero device instance %d",
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * Support for the other types (SMIC, SSIF) should be added here.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (ddi_create_minor_node(dip, "ipmi", S_IFCHR, 0, DDI_PSEUDO,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmn_err(CE_WARN, "!attach could not create minor node");
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek list_create(&dev_list, sizeof (ipmi_device_t),
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_init(&dev_list_lock, NULL, MUTEX_DRIVER, NULL);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* Create ID space for open devs. ID 0 is reserved. */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek minor_ids = id_space_create("ipmi_id_space", 1, 128);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek 0, /* reference count */