989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek/*
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * CDDL HEADER START
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek *
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 *
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * or http://www.opensolaris.org/os/licensing.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * See the License for the specific language governing permissions
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * and limitations under the License.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek *
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 *
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * CDDL HEADER END
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek/*
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi * Copyright (c) 2013, Joyent, Inc. All rights reserved.
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek/*
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * The ipmi driver is an openipmi compatible IPMI driver based on the FreeBSD
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * driver.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek *
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 */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/devops.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/conf.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/modctl.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/types.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/file.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/errno.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/open.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/cred.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/uio.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/stat.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/cmn_err.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/ddi.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/sunddi.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/smbios.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/smbios_impl.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/policy.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include <sys/ipmi.h>
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#include "ipmivars.h"
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic dev_info_t *ipmi_dip;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic boolean_t ipmi_attached = B_FALSE;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic boolean_t ipmi_found = B_FALSE;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic struct ipmi_softc softc;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic struct ipmi_softc *sc = &softc;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic list_t dev_list;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic id_space_t *minor_ids;
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchistatic kmutex_t dev_list_lock;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#define PTRIN(p) ((void *)(uintptr_t)(p))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek#define PTROUT(p) ((uintptr_t)(p))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek/*
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * Use the SMBIOS info to determine if the system has an IPMI.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic int
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekget_smbios_ipmi_info(void)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek smbios_ipmi_t ipmi;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (ksmbios == NULL || smbios_info_ipmi(ksmbios, &ipmi) == SMB_ERR)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmn_err(CE_CONT, "!SMBIOS type 0x%x, addr 0x%llx", ipmi.smbip_type,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek (long long unsigned int)(ipmi.smbip_addr));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /*
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 */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (ipmi.smbip_addr == NULL) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmn_err(CE_WARN, "!SMBIOS: Invalid base address");
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek sc->ipmi_io_type = ipmi.smbip_type;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek switch (ipmi.smbip_type) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case SMB_IPMI_T_KCS:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case SMB_IPMI_T_SMIC:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek sc->ipmi_io_address = ipmi.smbip_addr;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek sc->ipmi_io_mode = (ipmi.smbip_flags & SMB_IPMI_F_IOADDR) ?
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek 1 : 0;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek sc->ipmi_io_spacing = ipmi.smbip_regspacing;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case SMB_IPMI_T_SSIF:
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 sc->ipmi_io_address = ipmi.smbip_i2c;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek } else {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek sc->ipmi_io_address = ipmi.smbip_addr;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek default:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (ipmi.smbip_intr > 15) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmn_err(CE_WARN, "!SMBIOS: Non-ISA IRQ %d for IPMI",
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi.smbip_intr);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek sc->ipmi_io_irq = ipmi.smbip_intr;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_SUCCESS);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic ipmi_device_t *
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelineklookup_ipmidev_by_dev(dev_t dev)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_device_t *p;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_enter(&dev_list_lock);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek for (p = list_head(&dev_list); p; p = list_next(&dev_list, p)) {
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi if (dev == p->ipmi_dev) {
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_exit(&dev_list_lock);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (p);
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_exit(&dev_list_lock);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (NULL);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek/*
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * Each open returns a new pseudo device.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek/*ARGSUSED*/
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic int
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_open(dev_t *devp, int flag, int otyp, cred_t *cred)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek minor_t minor;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_device_t *dev;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (ipmi_attached == B_FALSE)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (ENXIO);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (ipmi_found == B_FALSE)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (ENODEV);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* exclusive opens are not supported */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (flag & FEXCL)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (ENOTSUP);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if ((minor = (minor_t)id_alloc_nosleep(minor_ids)) == 0)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (ENODEV);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* Initialize the per file descriptor data. */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev = kmem_zalloc(sizeof (ipmi_device_t), KM_SLEEP);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev->ipmi_pollhead = kmem_zalloc(sizeof (pollhead_t), KM_SLEEP);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek TAILQ_INIT(&dev->ipmi_completed_requests);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev->ipmi_address = IPMI_BMC_SLAVE_ADDR;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev->ipmi_lun = IPMI_BMC_SMS_LUN;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek *devp = makedevice(getmajor(*devp), minor);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev->ipmi_dev = *devp;
cc944374608a39fb5622959cc9a210fb116539cbMarcel Telka cv_init(&dev->ipmi_cv, NULL, CV_DEFAULT, NULL);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_enter(&dev_list_lock);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek list_insert_head(&dev_list, dev);
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_exit(&dev_list_lock);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (0);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek/*ARGSUSED*/
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic int
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_close(dev_t dev, int flag, int otyp, cred_t *cred)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_device_t *dp;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek struct ipmi_request *req, *next;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if ((dp = lookup_ipmidev_by_dev(dev)) == NULL)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (ENODEV);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_LOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* remove any pending requests */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req = TAILQ_FIRST(&sc->ipmi_pending_requests);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek while (req != NULL) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek next = TAILQ_NEXT(req, ir_link);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (req->ir_owner == dp) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek TAILQ_REMOVE(&sc->ipmi_pending_requests, req, ir_link);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_free_request(req);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req = next;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
cc944374608a39fb5622959cc9a210fb116539cbMarcel Telka
cc944374608a39fb5622959cc9a210fb116539cbMarcel Telka dp->ipmi_status |= IPMI_CLOSING;
cc944374608a39fb5622959cc9a210fb116539cbMarcel Telka while (dp->ipmi_status & IPMI_BUSY)
cc944374608a39fb5622959cc9a210fb116539cbMarcel Telka cv_wait(&dp->ipmi_cv, &sc->ipmi_lock);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
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 ipmi_free_request(req);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_enter(&dev_list_lock);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek list_remove(&dev_list, dp);
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_exit(&dev_list_lock);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek id_free(minor_ids, getminor(dev));
cc944374608a39fb5622959cc9a210fb116539cbMarcel Telka cv_destroy(&dp->ipmi_cv);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek kmem_free(dp->ipmi_pollhead, sizeof (pollhead_t));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek kmem_free(dp, sizeof (ipmi_device_t));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (0);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek/*ARGSUSED*/
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic int
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_ioctl(dev_t dv, int cmd, intptr_t data, int flags, cred_t *cr, int *rvalp)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek struct ipmi_device *dev;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek struct ipmi_request *kreq;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek struct ipmi_req req;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek struct ipmi_recv recv;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek struct ipmi_recv32 recv32;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek struct ipmi_addr addr;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek int error, len;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek model_t model;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek int orig_cmd = 0;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek uchar_t t_lun;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (secpolicy_sys_config(cr, B_FALSE) != 0)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EPERM);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if ((dev = lookup_ipmidev_by_dev(dv)) == NULL)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (ENODEV);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek model = get_udatamodel();
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (model == DATAMODEL_NATIVE) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek switch (cmd) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_SEND_COMMAND:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin((void *)data, &req, sizeof (req)))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_RECEIVE_MSG_TRUNC:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_RECEIVE_MSG:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin((void *)data, &recv, sizeof (recv)))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek } else {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* Convert 32-bit structures to native. */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek struct ipmi_req32 req32;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek switch (cmd) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_SEND_COMMAND_32:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin((void *)data, &req32, sizeof (req32)))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req.addr = PTRIN(req32.addr);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req.addr_len = req32.addr_len;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req.msgid = req32.msgid;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req.msg.netfn = req32.msg.netfn;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req.msg.cmd = req32.msg.cmd;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req.msg.data_len = req32.msg.data_len;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req.msg.data = PTRIN(req32.msg.data);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmd = IPMICTL_SEND_COMMAND;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_RECEIVE_MSG_TRUNC_32:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_RECEIVE_MSG_32:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin((void *)data, &recv32, sizeof (recv32)))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv.addr = PTRIN(recv32.addr);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv.addr_len = recv32.addr_len;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv.msg.data_len = recv32.msg.data_len;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv.msg.data = PTRIN(recv32.msg.data);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek orig_cmd = cmd;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmd = (cmd == IPMICTL_RECEIVE_MSG_TRUNC_32) ?
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMICTL_RECEIVE_MSG_TRUNC : IPMICTL_RECEIVE_MSG;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek switch (cmd) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_SEND_COMMAND:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* Check that we didn't get a ridiculous length */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (req.msg.data_len > IPMI_MAX_RX)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EINVAL);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek kreq = ipmi_alloc_request(dev, req.msgid,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_ADDR(req.msg.netfn, 0), req.msg.cmd,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek req.msg.data_len, IPMI_MAX_RX);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* This struct is the same for 32/64 */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (req.msg.data_len > 0 &&
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek copyin(req.msg.data, kreq->ir_request, req.msg.data_len)) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_free_request(kreq);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_LOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev->ipmi_requests++;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = sc->ipmi_enqueue_request(sc, kreq);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (error)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (error);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_RECEIVE_MSG_TRUNC:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_RECEIVE_MSG:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* This struct is the same for 32/64 */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin(recv.addr, &addr, sizeof (addr)))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_LOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek kreq = TAILQ_FIRST(&dev->ipmi_completed_requests);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (kreq == NULL) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EAGAIN);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek addr.channel = IPMI_BMC_CHANNEL;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv.recv_type = IPMI_RESPONSE_RECV_TYPE;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv.msgid = kreq->ir_msgid;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv.msg.netfn = IPMI_REPLY_ADDR(kreq->ir_addr) >> 2;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv.msg.cmd = kreq->ir_command;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = kreq->ir_error;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (error) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ir_link);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev->ipmi_requests--;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_free_request(kreq);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (error);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek len = kreq->ir_replylen + 1;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (recv.msg.data_len < len && cmd == IPMICTL_RECEIVE_MSG) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EMSGSIZE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek TAILQ_REMOVE(&dev->ipmi_completed_requests, kreq, ir_link);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev->ipmi_requests--;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek len = min(recv.msg.data_len, len);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv.msg.data_len = (unsigned short)len;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (orig_cmd == IPMICTL_RECEIVE_MSG_TRUNC_32 ||
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek orig_cmd == IPMICTL_RECEIVE_MSG_32) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* Update changed fields in 32-bit structure. */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv32.recv_type = recv.recv_type;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv32.msgid = (int32_t)recv.msgid;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv32.msg.netfn = recv.msg.netfn;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv32.msg.cmd = recv.msg.cmd;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek recv32.msg.data_len = recv.msg.data_len;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = copyout(&recv32, (void *)data, sizeof (recv32));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek } else {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = copyout(&recv, (void *)data, sizeof (recv));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* This struct is the same for 32/64 */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (error == 0)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = copyout(&addr, recv.addr, sizeof (addr));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (error == 0)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = copyout(&kreq->ir_compcode, recv.msg.data, 1);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (error == 0)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek error = copyout(kreq->ir_reply, recv.msg.data + 1,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek len - 1);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_free_request(kreq);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (error)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_SET_MY_ADDRESS_CMD:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_LOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin((void *)data, &dev->ipmi_address,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek sizeof (dev->ipmi_address))) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_GET_MY_ADDRESS_CMD:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_LOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyout(&dev->ipmi_address, (void *)data,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek sizeof (dev->ipmi_address))) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_SET_MY_LUN_CMD:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_LOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyin((void *)data, &t_lun, sizeof (t_lun))) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek dev->ipmi_lun = t_lun & 0x3;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_GET_MY_LUN_CMD:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_LOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (copyout(&dev->ipmi_lun, (void *)data,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek sizeof (dev->ipmi_lun))) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EFAULT);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek IPMI_UNLOCK(sc);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_SET_GETS_EVENTS_CMD:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_REGISTER_FOR_CMD:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case IPMICTL_UNREGISTER_FOR_CMD:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EINVAL);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek default:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (EINVAL);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (0);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic int
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_poll(dev_t dv, short events, int anyyet, short *reventsp,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek pollhead_t **phpp)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek struct ipmi_device *dev;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek short revent = 0;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if ((dev = lookup_ipmidev_by_dev(dv)) == NULL)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (ENODEV);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (events & (POLLIN | POLLRDNORM)) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (!TAILQ_EMPTY(&dev->ipmi_completed_requests))
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek revent |= events & (POLLIN | POLLRDNORM);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (dev->ipmi_requests == 0)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek revent |= POLLERR;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (revent == 0) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /* nothing has occurred */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (!anyyet)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek *phpp = dev->ipmi_pollhead;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek *reventsp = revent;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (0);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek/*ARGSUSED*/
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic int
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek switch (cmd) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case DDI_INFO_DEVT2DEVINFO:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek *resultp = ipmi_dip;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_SUCCESS);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case DDI_INFO_DEVT2INSTANCE:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek *resultp = NULL;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_SUCCESS);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telkastatic void
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telkaipmi_cleanup(dev_info_t *dip)
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka{
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka /* poke the taskq so that it can terminate */
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka IPMI_LOCK(sc);
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka sc->ipmi_detaching = 1;
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka cv_signal(&sc->ipmi_request_added);
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka IPMI_UNLOCK(sc);
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka ipmi_shutdown(sc);
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka ddi_remove_minor_node(dip, NULL);
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka ipmi_dip = NULL;
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_destroy(&dev_list_lock);
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka list_destroy(&dev_list);
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka id_space_destroy(minor_ids);
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka sc->ipmi_detaching = 0;
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka}
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic int
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (cmd != DDI_ATTACH)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk /* this driver only supports one device instance */
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk if (ddi_get_instance(dip) != 0) {
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk cmn_err(CE_WARN,
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk "!not attaching to non-zero device instance %d",
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk ddi_get_instance(dip));
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk return (DDI_FAILURE);
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk }
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (get_smbios_ipmi_info() == DDI_FAILURE)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek /*
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek * Support for the other types (SMIC, SSIF) should be added here.
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek switch (sc->ipmi_io_type) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek case SMB_IPMI_T_KCS:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (ipmi_kcs_attach(sc) != 0)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek break;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek default:
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_found = B_TRUE;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (ddi_create_minor_node(dip, "ipmi", S_IFCHR, 0, DDI_PSEUDO,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek 0) == DDI_FAILURE) {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek cmn_err(CE_WARN, "!attach could not create minor node");
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ddi_remove_minor_node(dip, NULL);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek }
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_dip = dip;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek list_create(&dev_list, sizeof (ipmi_device_t),
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek offsetof(ipmi_device_t, ipmi_node));
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_init(&dev_list_lock, NULL, MUTEX_DRIVER, NULL);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
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 Jelinek
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk if (ipmi_startup(sc) != B_TRUE) {
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka ipmi_cleanup(dip);
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk return (DDI_FAILURE);
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk }
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_attached = B_TRUE;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_SUCCESS);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic int
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekipmi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (cmd != DDI_DETACH)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek if (ipmi_found == B_FALSE)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_SUCCESS);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_enter(&dev_list_lock);
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi if (!list_is_empty(&dev_list)) {
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_exit(&dev_list_lock);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_FAILURE);
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi }
164b0ee5065e049b55a69e2bc0d31757ffafae07Robert Mustacchi mutex_exit(&dev_list_lock);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
1e3934778d15dd08e911e1d050dd7a4949348d93Marcel Telka ipmi_cleanup(dip);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_attached = B_FALSE;
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (DDI_SUCCESS);
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic struct cb_ops ipmi_cb_ops = {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_open,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_close,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nodev, /* strategy */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nodev, /* print */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nodev, /* dump */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nodev, /* read */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nodev, /* write */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_ioctl,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nodev, /* devmap */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nodev, /* mmap */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nodev, /* segmap */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_poll,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ddi_prop_op,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek NULL, /* streamtab */
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk D_NEW | D_MP, /* flags */
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk CB_REV,
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk nodev, /* awread */
e1c99a74dc27ba07cba2cd8181f462ea9a5b0dbaAlek Pinchuk nodev /* awrite */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek};
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic struct dev_ops ipmi_ops = {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek DEVO_REV,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek 0, /* reference count */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_info,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nulldev, /* identify */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nulldev, /* probe */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_attach,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ipmi_detach,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek nodev, /* reset */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek &ipmi_cb_ops,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek NULL, /* bus ops */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek NULL, /* power */
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek ddi_quiesce_not_needed,
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek};
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic struct modldrv md = {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek &mod_driverops, "ipmi driver", &ipmi_ops
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek};
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekstatic struct modlinkage ml = {
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek MODREV_1, &md, NULL
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek};
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekint
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek_init(void)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (mod_install(&ml));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekint
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek_fini(void)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (mod_remove(&ml));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinekint
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek_info(struct modinfo *mip)
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek{
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek return (mod_info(&ml, mip));
989f28072d20c73ae0955d6a1e3e2fc74831cb39Jerry Jelinek}