diff options
author | Marco Peereboom <marco@cvs.openbsd.org> | 2007-08-31 16:18:58 +0000 |
---|---|---|
committer | Marco Peereboom <marco@cvs.openbsd.org> | 2007-08-31 16:18:58 +0000 |
commit | 97a0540ea5762c2081b20b002d8294313854c0eb (patch) | |
tree | 93f50bb07410fc0d30c4163d8f9fa79d66a17491 /sys/dev/pci/qli_pci.c | |
parent | 9c07db17894969068b35a3da5deb3745c20f963c (diff) |
Add qli (qlogic iscsi) HBA driver for further development in tree. Help
from David Collins <dave at davec dot name>.
Name pitched by deraadt
help and ok dlg
Diffstat (limited to 'sys/dev/pci/qli_pci.c')
-rw-r--r-- | sys/dev/pci/qli_pci.c | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/sys/dev/pci/qli_pci.c b/sys/dev/pci/qli_pci.c new file mode 100644 index 00000000000..a6427b8edc7 --- /dev/null +++ b/sys/dev/pci/qli_pci.c @@ -0,0 +1,738 @@ +/* $OpenBSD: qli_pci.c,v 1.1 2007/08/31 16:18:57 marco Exp $ */ +/* + * Copyright (c) 2007 Marco Peereboom <marco@peereboom.us> + * Copyright (c) 2007 David Collins <dave@davec.name> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "bio.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/rwlock.h> + +#include <dev/pci/pcidevs.h> +#include <dev/pci/pcivar.h> + +#include <machine/bus.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_disk.h> +#include <scsi/scsiconf.h> + +#include <dev/pci/qlireg.h> + +#if NBIO > 0 +#include <dev/biovar.h> +#include <sys/sensors.h> +#endif /* NBIO > 0 */ + +#define DEVNAME(_s) ((_s)->sc_dev.dv_xname) + +#define QLI_DEBUG +#ifdef QLI_DEBUG +#define DPRINTF(x...) do { if (qli_debug) printf(x); } while(0) +#define DNPRINTF(n,x...) do { if (qli_debug & n) printf(x); } while(0) +#define QLI_D_CMD 0x0001 +#define QLI_D_INTR 0x0002 +#define QLI_D_MISC 0x0004 +#define QLI_D_DMA 0x0008 +#define QLI_D_IOCTL 0x0010 +#define QLI_D_RW 0x0020 +#define QLI_D_MEM 0x0040 +#define QLI_D_CCB 0x0080 +#define QLI_D_SEM 0x0100 +#else +#define DPRINTF(x...) +#define DNPRINTF(n,x...) +#endif + +#ifdef QLI_DEBUG +u_int32_t qli_debug = 0 + | QLI_D_CMD + | QLI_D_INTR + | QLI_D_MISC + | QLI_D_DMA + | QLI_D_IOCTL + | QLI_D_RW + | QLI_D_MEM + | QLI_D_CCB + | QLI_D_SEM + ; +#endif + +struct qli_softc { + struct device sc_dev; + + void *sc_ih; + bus_space_tag_t sc_memt; + bus_space_handle_t sc_memh; + bus_size_t sc_memsize; + bus_dma_tag_t sc_dmat; + + volatile struct qli_reg *sc_reg; /* pointer to registers */ + + /* scsi ioctl from sd device */ + int (*sc_ioctl)(struct device *, u_long, caddr_t); + + int sc_ql4010; /* if set we are a QL4010 HBA */ + u_int32_t sc_resource; /* nr for semaphores */ + + struct rwlock sc_lock; +}; + +int qli_scsi_cmd(struct scsi_xfer *); +int qli_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int, + struct proc *); +void qliminphys(struct buf *bp); +int qli_pci_find_device(void *); +int qli_pci_match(struct device *, void *, void *); +void qli_pci_attach(struct device *, struct device *, void *); +int qli_ioctl(struct device *, u_long, caddr_t); +int qli_lock_sem(struct qli_softc *, u_int32_t, u_int32_t); +void qli_unlock_sem(struct qli_softc *, u_int32_t); +int qli_lock_driver(struct qli_softc *); +void qli_write(struct qli_softc *, volatile u_int32_t *, u_int32_t); +u_int32_t qli_read(struct qli_softc *, volatile u_int32_t *); +void qli_hw_reset(struct qli_softc *); +int qli_soft_reset(struct qli_softc *); +int qli_get_fw_state(struct qli_softc *, u_int32_t *); +int qli_start_firmware(struct qli_softc *); +int qli_intr(void *); +int qli_attach(struct qli_softc *); +#ifndef SMALL_KERNEL +int qli_create_sensors(struct qli_softc *); +#endif /* SMALL_KERNEL */ + + +struct scsi_adapter qli_switch = { + qli_scsi_cmd, qliminphys, 0, 0, qli_scsi_ioctl +}; + +struct scsi_device qli_dev = { + NULL, NULL, NULL, NULL +}; + +struct cfdriver qli_cd = { + NULL, "qli", DV_DULL +}; + +struct cfattach qli_pci_ca = { + sizeof(struct qli_softc), qli_pci_match, qli_pci_attach +}; + +struct qli_pci_device { + pcireg_t qpd_vendor; + pcireg_t qpd_product; + pcireg_t qpd_subvendor; + pcireg_t qpd_subproduct; + char *qpd_model; + uint32_t qpd_flags; +} qli_pci_devices[] = { + { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP4022_HBA, + 0, 0, "", 0 }, + { PCI_VENDOR_QLOGIC, PCI_PRODUCT_QLOGIC_ISP4010_HBA, + 0, 0, "", 0 }, + { 0 } +}; + +int +qli_pci_find_device(void *aux) { + struct pci_attach_args *pa = aux; + int i; + + for (i = 0; qli_pci_devices[i].qpd_vendor; i++) { + if (qli_pci_devices[i].qpd_vendor == PCI_VENDOR(pa->pa_id) && + qli_pci_devices[i].qpd_product == PCI_PRODUCT(pa->pa_id)) { + DNPRINTF(QLI_D_MISC, "qli_pci_find_device: %i\n", i); + return (i); + } + } + + return (-1); +} + +int +qli_pci_match(struct device *parent, void *match, void *aux) +{ + int i; + + if ((i = qli_pci_find_device(aux)) != -1) { + DNPRINTF(QLI_D_MISC, + "qli_pci_match: vendor: %04x product: %04x\n", + qli_pci_devices[i].qpd_vendor, + qli_pci_devices[i].qpd_product); + + return (1); + } + return (0); +} + +void +qli_pci_attach(struct device *parent, struct device *self, void *aux) +{ + struct qli_softc *sc = (struct qli_softc *)self; + struct pci_attach_args *pa = aux; + const char *intrstr; + pci_intr_handle_t ih; + pcireg_t memtype; + int r; + + /* find the appropriate memory base */ + for (r = PCI_MAPREG_START; r < PCI_MAPREG_END; r += sizeof(memtype)) { + memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, r); + if ((memtype & PCI_MAPREG_TYPE_MASK) == PCI_MAPREG_TYPE_MEM) + break; + } + if (r >= PCI_MAPREG_END) { + printf(": unable to locate system interface registers\n"); + return; + } + if (pci_mapreg_map(pa, r, memtype, BUS_SPACE_MAP_LINEAR, &sc->sc_memt, + &sc->sc_memh, NULL, &sc->sc_memsize, 0)) { + printf(": can't map controller pci space\n"); + return; + } + sc->sc_dmat = pa->pa_dmat; + + /* establish interrupt */ + if (pci_intr_map(pa, &ih)) { + printf(": can't map interrupt\n"); + goto unmap; + } + intrstr = pci_intr_string(pa->pa_pc, ih); + sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, qli_intr, sc, + DEVNAME(sc)); + if (!sc->sc_ih) { + printf(": can't establish interrupt"); + if (intrstr) + printf(" at %s", intrstr); + printf("\n"); + goto unmap; + } + + /* retrieve kva for register access */ + sc->sc_reg = bus_space_vaddr(sc->sc_memt, sc->sc_memh); + if (sc->sc_reg == NULL) { + printf(": can't map registers into kernel\n"); + goto intrdis; + } + printf(": %s\n", intrstr); + + sc->sc_ql4010 = + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_QLOGIC_ISP4010_HBA; + + if (qli_attach(sc)) { + printf(": %s can't attach\n", DEVNAME(sc)); + goto intrdis; + } + + return; +intrdis: + pci_intr_disestablish(pa->pa_pc, sc->sc_ih); +unmap: + sc->sc_ih = NULL; + bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_memsize); +} + +void +qliminphys(struct buf *bp) +{ + DNPRINTF(QLI_D_MISC, "qliminphys: %d\n", bp->b_bcount); + + /* XXX currently using QLI_MAXFER = MAXPHYS */ + if (bp->b_bcount > QLI_MAXFER) + bp->b_bcount = QLI_MAXFER; + minphys(bp); +} + +void +qli_write(struct qli_softc *sc, volatile u_int32_t *p, u_int32_t v) +{ + DNPRINTF(QLI_D_RW, "%s: qw 0x%x 0x%08x\n", DEVNAME(sc), + (u_int8_t *)p - (u_int8_t *)sc->sc_reg, v); + + *p = letoh32(v); + bus_space_barrier(sc->sc_memt, sc->sc_memh, + (u_int8_t *)p - (u_int8_t *)sc->sc_reg, 4, BUS_SPACE_BARRIER_WRITE); +} + +u_int32_t +qli_read(struct qli_softc *sc, volatile u_int32_t *p) +{ + u_int32_t v; + + bus_space_barrier(sc->sc_memt, sc->sc_memh, + (u_int8_t *)p - (u_int8_t *)sc->sc_reg, 4, BUS_SPACE_BARRIER_READ); + v = letoh32(*p); + + DNPRINTF(QLI_D_RW, "%s: qr 0x%x 0x%08x\n", DEVNAME(sc), + (u_int8_t *)p - (u_int8_t *)sc->sc_reg, v); + return (v); +} + +void +qli_hw_reset(struct qli_softc *sc) +{ + u_int32_t s; + + DNPRINTF(QLI_D_MISC, "%s: qli_hw_reset\n", DEVNAME(sc)); + + /* clear scsi reset interrupt bit or soft reset won't work */ + s = qli_read(sc, &sc->sc_reg->qlr_ctrl_status); + if (s & QLI_REG_CTRLSTAT_SCSI_RESET_INTR) + qli_write(sc, &sc->sc_reg->qlr_ctrl_status, QLI_SET_MASK(s)); + + /* issue soft reset */ + qli_write(sc, &sc->sc_reg->qlr_ctrl_status, + QLI_SET_MASK(QLI_REG_CTRLSTAT_SOFT_RESET)); +} + +int +qli_soft_reset(struct qli_softc *sc) +{ + int rv = 1, i, failed; + u_int32_t s; + + DNPRINTF(QLI_D_MISC, "%s: qli_soft_reset\n", DEVNAME(sc)); + + qli_hw_reset(sc); + + /* wait until net reset bit is cleared */ + for (i = 0; i < QLI_SOFT_RESET_RETRIES; i++) { + s = qli_read(sc, &sc->sc_reg->qlr_ctrl_status); + if ((s & QLI_REG_CTRLSTAT_NET_RESET_INTR) == 0) + break; + delay(1000000); /* 1s */ + } + s = qli_read(sc, &sc->sc_reg->qlr_ctrl_status); + if (s & QLI_REG_CTRLSTAT_NET_RESET_INTR) { + printf("%s: qli_soft_reset: net reset intr bit not cleared\n", + DEVNAME(sc)); + /* XXX set the same bit per the linux driver */ + qli_write(sc, &sc->sc_reg->qlr_ctrl_status, + QLI_SET_MASK(QLI_REG_CTRLSTAT_NET_RESET_INTR)); + } + + /* wait for soft reset to complete */ + for (i = 0, failed = 1; i < QLI_SOFT_RESET_RETRIES; i++) { + s = qli_read(sc, &sc->sc_reg->qlr_ctrl_status); + if ((s & QLI_REG_CTRLSTAT_SOFT_RESET) == 0) { + failed = 0; + break; + } + delay(1000000); /* 1s */ + } + + /* check if scsi reset interrupt is cleared */ + s = qli_read(sc, &sc->sc_reg->qlr_ctrl_status); + if (s & QLI_REG_CTRLSTAT_SCSI_RESET_INTR) { + printf("%s: qli_soft_reset: scsi reset intr bit not cleared\n", + DEVNAME(sc)); + /* XXX set the same bit per the linux driver */ + qli_write(sc, &sc->sc_reg->qlr_ctrl_status, + QLI_SET_MASK(QLI_REG_CTRLSTAT_SCSI_RESET_INTR)); + } + + if (failed) { + /* force the soft reset */ + printf("%s: qli_soft_reset: soft reset failed\n", DEVNAME(sc)); + qli_write(sc, &sc->sc_reg->qlr_ctrl_status, + QLI_SET_MASK(QLI_REG_CTRLSTAT_FORCE_SOFT_RESET)); + for (i = 0; i < QLI_SOFT_RESET_RETRIES; i++) { + s = qli_read(sc, &sc->sc_reg->qlr_ctrl_status); + if ((s & QLI_REG_CTRLSTAT_FORCE_SOFT_RESET) == 0) { + rv = 0; + break; + } + delay(1000000); /* 1s */ + } + } else + rv = 0; + + return (rv); +} + +int +qli_get_fw_state(struct qli_softc *sc, u_int32_t *mbox) +{ + DNPRINTF(QLI_D_MISC, "%s: qli_get_fw_state\n", DEVNAME(sc)); + + DNPRINTF(QLI_D_MISC, "%s: qli_get_fw_state: not implemented yet\n", + DEVNAME(sc)); + + return (1); +} + +int +qli_lock_driver(struct qli_softc *sc) +{ + int i, rv = 1; + + DNPRINTF(QLI_D_SEM, "%s: qli_lock_driver\n", DEVNAME(sc)); + + for (i = 0; i < QLI_SEM_MAX_RETRIES; i++) { + if (qli_lock_sem(sc, QLI_SEM_DRIVER(sc), + QLI_SEM_DRIVER_MASK(sc))) { + DNPRINTF(QLI_D_SEM, "%s: qli_lock_driver: semaphore" + " not acquired, retry %d\n", DEVNAME(sc), i); + if (cold) + delay(1000000); /* 1s */ + else + while (tsleep(sc, PRIBIO + 1, "qlisem", hz) != + EWOULDBLOCK) + ; + } else { + DNPRINTF(QLI_D_SEM, "%s: qli_lock_driver: semaphore" + " acquired\n", DEVNAME(sc)); + rv = 0; + break; + } + } + return (rv); +} + +void +qli_unlock_sem(struct qli_softc *sc, u_int32_t mask) +{ + DNPRINTF(QLI_D_SEM, "%s: qli_unlock_sem: 0x%08x released\n", + DEVNAME(sc), mask); + + qli_write(sc, QLI_SEMAPHORE(sc), mask); +} + +int +qli_lock_sem(struct qli_softc *sc, u_int32_t shift, u_int32_t mask) +{ + int rv = 1; + u_int32_t v, s; + + s = sc->sc_resource << shift; + qli_write(sc, QLI_SEMAPHORE(sc), s | mask); + v = qli_read(sc, QLI_SEMAPHORE(sc)); + + if ((v & (mask >> 16)) == s) + rv = 0; + + DNPRINTF(QLI_D_SEM, "%s: qli_lock_sem: mask: 0x%08x shift: 0x%08x " + "s: 0x%08x v: 0x%08x did %sacquire semaphore \n", DEVNAME(sc), + mask, shift, s, v, rv ? "not " : ""); + + return (rv); +} + +int +qli_start_firmware(struct qli_softc *sc) +{ + int rv = 1, reset_required = 1, config_required = 0; + int boot_required = 0, i; + u_int32_t mbox[QLI_MBOX_SIZE], r; + + DNPRINTF(QLI_D_MISC, "%s: qli_start_firmware\n", DEVNAME(sc)); + + if (qli_lock_driver(sc)) { + printf("%s: could not acquire global driver semaphore, " + "aborting firmware bring-up\n", DEVNAME(sc)); + goto done; + } + + if (qli_read(sc, QLI_PORT_CTRL(sc)) & QLI_PORT_CTRL_INITIALIZED) { + /* Hardware has been initialized */ + DNPRINTF(QLI_D_MISC, "%s: qli_start_firmware: hardware has " + "been initialized\n", DEVNAME(sc)); + + if (qli_read(sc, &sc->sc_reg->qlr_mbox[0]) == 0) { + /* firmware is not running */ + DNPRINTF(QLI_D_MISC, "%s: qli_start_firmware: fw " + "not running\n", DEVNAME(sc)); + reset_required = 0; + config_required = 1; + } else { + qli_write(sc, &sc->sc_reg->qlr_ctrl_status, + QLI_SET_MASK(QLI_REG_CTRLSTAT_SCSI_RESET_INTR)); + + /* issue command to fw to find out if we are up */ + bzero(mbox, sizeof(mbox)); + if (qli_get_fw_state(sc, mbox)) { + /* command failed, reset chip */ + DNPRINTF(QLI_D_MISC, "%s: qli_start_firmware: " + "firmware in unknown state, reseting " + "chip\n", DEVNAME(sc)); + } else { + if (mbox[1] & QLI_MBOX_STATE_CONFIG_WAIT) { + config_required = 1; + reset_required = 0; + } + } + } + } + + if (reset_required) { + if (qli_soft_reset(sc)) { + printf("%s: soft reset failed, aborting firmware " + "bring-up\n", DEVNAME(sc)); + goto done; + } + config_required = 1; + + if (qli_lock_driver(sc)) { + printf("%s: could not acquire global driver semaphore " + "after reseting chip, aborting firmware bring-up\n", + DEVNAME(sc)); + goto done; + } + } + + if (config_required) { + DNPRINTF(QLI_D_MISC, "%s: qli_start_firmware: configuring " + "firmware\n", DEVNAME(sc)); + + if (qli_lock_sem(sc, QLI_SEM_FLASH(sc), + QLI_SEM_FLASH_MASK(sc))) { + printf("%s: could not lock flash during firmware " + "bring-up\n", DEVNAME(sc)); + goto unlock_driver; + } + + if (qli_lock_sem(sc, QLI_SEM_NVRAM(sc), + QLI_SEM_NVRAM_MASK(sc))) { + printf("%s: could not lock nvram during firmware " + "bring-up\n", DEVNAME(sc)); + qli_unlock_sem(sc, QLI_SEM_FLASH_MASK(sc)); + goto unlock_driver; + } + + if (0 /*qli_validate_nvram(sc)*/) { + printf("%s: invalid NVRAM checksum. Flash your " + "controller", DEVNAME(sc)); + + if (sc->sc_ql4010) + r = QLI_EXT_HW_CFG_DEFAULT_QL4010; + else + r = QLI_EXT_HW_CFG_DEFAULT_QL4022; + } else { + /* XXX success, get NVRAM settings instead of default */ + if (sc->sc_ql4010) + r = QLI_EXT_HW_CFG_DEFAULT_QL4010; + else + r = QLI_EXT_HW_CFG_DEFAULT_QL4022; + printf("%s: fixme, get NVRAM settings, using defaults" + " for now\n", DEVNAME(sc)); + + } + + /* upper 16 bits are write mask; enable everything */ + qli_write(sc, QLI_EXT_HW_CFG(sc), (0xffff << 16 ) | r); + + qli_unlock_sem(sc, QLI_SEM_NVRAM_MASK(sc)); + qli_unlock_sem(sc, QLI_SEM_FLASH_MASK(sc)); + + boot_required = 1; + } + + if (boot_required) { + /* boot firmware */ + DNPRINTF(QLI_D_MISC, "%s: qli_start_firmware: booting " + "firmware\n", DEVNAME(sc)); + + /* stuff random value in mbox[7] to randomize source ports */ + /* XXX use random ne instead of 123 */ + qli_write(sc, &sc->sc_reg->qlr_mbox[7], 1234); + + /* XXX linux driver sets ACB v2 into mbox[6] */ + + qli_write(sc, &sc->sc_reg->qlr_ctrl_status, + QLI_SET_MASK(QLI_REG_CTRLSTAT_BOOT_ENABLE)); + + /* wait for firmware to come up */ + for (i = 0; i < 60 * 4 /* up to 60 seconds */; i ++) { + if (qli_read(sc, &sc->sc_reg->qlr_ctrl_status) & + QLI_SET_MASK(QLI_REG_CTRLSTAT_SCSI_PROC_INTR)) + break; + if (qli_read(sc, &sc->sc_reg->qlr_mbox[0]) == + QLI_MBOX_STATUS_COMMAND_COMPLETE) + break; + DNPRINTF(QLI_D_MISC, "%s: qli_start_firmware: waiting " + "for firmware, retry = %d\n", DEVNAME(sc), i); + + delay(250000); /* 250ms */ + } + if (qli_read(sc, &sc->sc_reg->qlr_mbox[0]) == + QLI_MBOX_STATUS_COMMAND_COMPLETE) { + /* firmware is done booting */ + qli_write(sc, &sc->sc_reg->qlr_ctrl_status, + QLI_SET_MASK(QLI_REG_CTRLSTAT_SCSI_PROC_INTR)); + + DNPRINTF(QLI_D_MISC, "%s: qli_start_firmware: firmware " + "booting complete\n", DEVNAME(sc)); + + rv = 0; + } + else { + DNPRINTF(QLI_D_MISC, "%s: qli_start_firmware: firmware " + "booting failed\n", DEVNAME(sc)); + rv = 1; + } + } + +unlock_driver: + qli_unlock_sem(sc, QLI_SEM_DRIVER_MASK(sc)); +done: + return (rv); +} + +int +qli_attach(struct qli_softc *sc) +{ + /* struct scsibus_attach_args saa; */ + int rv = 1; + u_int32_t f; + + DNPRINTF(QLI_D_MISC, "%s: qli_attach\n", DEVNAME(sc)); + + rw_init(&sc->sc_lock, "qli_lock"); + + if (sc->sc_ql4010) + sc->sc_resource = QLI_SEM_4010_SCSI; + else { + f = qli_read(sc, &sc->sc_reg->qlr_ctrl_status) & + QLI_REG_CTRLSTAT_FUNC_MASK; + sc->sc_resource = f >> 8; + } + DNPRINTF(QLI_D_MISC, "%s: qli_attach resource: %d\n", DEVNAME(sc), + sc->sc_resource); + + qli_start_firmware(sc); + +#if NBIO > 0 + if (bio_register(&sc->sc_dev, qli_ioctl) != 0) + panic("%s: controller registration failed", DEVNAME(sc)); + else + sc->sc_ioctl = qli_ioctl; + +#ifndef SMALL_KERNEL + if (qli_create_sensors(sc) != 0) + printf("%s: unable to create sensors\n", DEVNAME(sc)); +#endif /* SMALL_KERNEL */ +#endif /* NBIO > 0 */ + + return (rv); +} + +int +qli_scsi_cmd(struct scsi_xfer *xs) +{ + struct scsi_link *link = xs->sc_link; + struct qli_softc *sc = link->adapter_softc; + + DNPRINTF(QLI_D_CMD, "%s: qli_scsi_cmd opcode: %#x\n", + DEVNAME(sc), xs->cmd->opcode); + + goto stuffup; + + return (SUCCESSFULLY_QUEUED); + +stuffup: + xs->error = XS_DRIVER_STUFFUP; + xs->flags |= ITSDONE; + scsi_done(xs); + return (COMPLETE); +} + +int +qli_intr(void *arg) +{ +#ifdef QLI_DEBUG + struct qli_softc *sc = arg; + + DNPRINTF(QLI_D_INTR, "%s: qli_intr %#x\n", DEVNAME(sc), sc); +#endif + + return (0); +} + +int +qli_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag, + struct proc *p) +{ + struct qli_softc *sc = (struct qli_softc *)link->adapter_softc; + + DNPRINTF(QLI_D_IOCTL, "%s: qli_scsi_ioctl\n", DEVNAME(sc)); + + if (sc->sc_ioctl) + return (sc->sc_ioctl(link->adapter_softc, cmd, addr)); + else + return (ENOTTY); +} + +#if NBIO > 0 +int +qli_ioctl(struct device *dev, u_long cmd, caddr_t addr) +{ + struct qli_softc *sc = (struct qli_softc *)dev; + int error = EINVAL; + + DNPRINTF(QLI_D_IOCTL, "%s: qli_ioctl ", DEVNAME(sc)); + + rw_enter_write(&sc->sc_lock); + + switch (cmd) { + case BIOCINQ: + DNPRINTF(QLI_D_IOCTL, "inq\n"); + break; + + case BIOCVOL: + DNPRINTF(QLI_D_IOCTL, "vol\n"); + break; + + case BIOCDISK: + DNPRINTF(QLI_D_IOCTL, "disk\n"); + break; + + case BIOCALARM: + DNPRINTF(QLI_D_IOCTL, "alarm\n"); + break; + + case BIOCBLINK: + DNPRINTF(QLI_D_IOCTL, "blink\n"); + break; + + case BIOCSETSTATE: + DNPRINTF(QLI_D_IOCTL, "setstate\n"); + break; + + default: + DNPRINTF(QLI_D_IOCTL, " invalid ioctl\n"); + error = EINVAL; + } + + rw_exit_write(&sc->sc_lock); + + return (error); +} +#endif /* NBIO > 0 */ + +#ifndef SMALL_KERNEL +int +qli_create_sensors(struct qli_softc *sc) +{ + return (1); +} +#endif /* SMALL_KERNEL */ |