diff options
Diffstat (limited to 'sys/dev/pci/qli_pci.c')
| -rw-r--r-- | sys/dev/pci/qli_pci.c | 1168 |
1 files changed, 0 insertions, 1168 deletions
diff --git a/sys/dev/pci/qli_pci.c b/sys/dev/pci/qli_pci.c deleted file mode 100644 index 159838b50e1..00000000000 --- a/sys/dev/pci/qli_pci.c +++ /dev/null @@ -1,1168 +0,0 @@ -/* $OpenBSD: qli_pci.c,v 1.21 2014/02/21 18:47:35 deraadt 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) - -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; - - /* mailbox members */ - struct rwlock sc_mbox_lock; - u_int32_t sc_mbox[QLI_MBOX_SIZE]; - int sc_mbox_flags; -#define QLI_MBOX_F_INVALID (0x00) -#define QLI_MBOX_F_PENDING (0x01) -#define QLI_MBOX_F_WAKEUP (0x02) -#define QLI_MBOX_F_POLL (0x04) - - /* firmware control block */ - struct qli_mem *sc_fw_cb; - - /* queues */ - unsigned int sc_queues_len; - struct qli_mem *sc_queues; - bus_addr_t sc_request_dva; - struct qli_queue_entry *sc_request_ring; -}; - -/* #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 -#define QLI_D_MBOX 0x0200 - -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 - | QLI_D_MBOX - ; - -void qli_dump_mbox(struct qli_softc *, u_int32_t *); -#else -#define DPRINTF(x...) -#define DNPRINTF(n,x...) -#define qli_dump_mbox(x, y) -#endif /* QLI_DEBUG */ - -struct qli_mem { - bus_dmamap_t am_map; - bus_dma_segment_t am_seg; - size_t am_size; - caddr_t am_kva; -}; - -#define QLIMEM_MAP(_am) ((_am)->am_map) -#define QLIMEM_DVA(_am) ((_am)->am_map->dm_segs[0].ds_addr) -#define QLIMEM_KVA(_am) ((void *)(_am)->am_kva) -#define QLIMEM_ALIGN (MAX(QLI_REQUESTQ_DEPTH, QLI_RESPONSEQ_DEPTH) *\ - sizeof(struct qli_queue_entry)) - -struct qli_mem *qli_allocmem(struct qli_softc *, size_t); -void qli_freemem(struct qli_softc *, struct qli_mem *); -void 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, struct scsi_link *sl); -void qli_disable_interrupts(struct qli_softc *); -void qli_enable_interrupts(struct qli_softc *); -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); -void qli_eeprom_out(struct qli_softc *, u_int32_t); -u_int16_t qli_read_nvram(struct qli_softc *, u_int32_t); -int qli_validate_nvram(struct qli_softc *); -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_mgmt(struct qli_softc *, int, u_int32_t *); -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 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); -} - -struct qli_mem * -qli_allocmem(struct qli_softc *sc, size_t size) -{ - struct qli_mem *mm; - int nsegs; - - DNPRINTF(QLI_D_MEM, "%s: qli_allocmem: %d\n", DEVNAME(sc), - size); - - mm = malloc(sizeof(*mm), M_DEVBUF, M_NOWAIT | M_ZERO); - if (mm == NULL) - return (NULL); - - mm->am_size = size; - - if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, - BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mm->am_map) != 0) - goto amfree; - - if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &mm->am_seg, 1, - &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0) - goto destroy; - - if (bus_dmamem_map(sc->sc_dmat, &mm->am_seg, nsegs, size, &mm->am_kva, - BUS_DMA_NOWAIT) != 0) - goto free; - - if (bus_dmamap_load(sc->sc_dmat, mm->am_map, mm->am_kva, size, NULL, - BUS_DMA_NOWAIT) != 0) - goto unmap; - - DNPRINTF(QLI_D_MEM, " kva: %p dva: %p map: %p\n", - mm->am_kva, mm->am_map->dm_segs[0].ds_addr, mm->am_map); - - return (mm); - -unmap: - bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, size); -free: - bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1); -destroy: - bus_dmamap_destroy(sc->sc_dmat, mm->am_map); -amfree: - free(mm, M_DEVBUF); - - return (NULL); -} - -void -qli_freemem(struct qli_softc *sc, struct qli_mem *mm) -{ - DNPRINTF(QLI_D_MEM, "%s: qli_freemem: %p\n", DEVNAME(sc), mm); - - bus_dmamap_unload(sc->sc_dmat, mm->am_map); - bus_dmamem_unmap(sc->sc_dmat, mm->am_kva, mm->am_size); - bus_dmamem_free(sc->sc_dmat, &mm->am_seg, 1); - bus_dmamap_destroy(sc->sc_dmat, mm->am_map); - free(mm, M_DEVBUF); -} - -void -qliminphys(struct buf *bp, struct scsi_link *sl) -{ - DNPRINTF(QLI_D_MISC, "qliminphys: %d\n", bp->b_bcount); - - if (bp->b_bcount > QLI_MAXFER) - bp->b_bcount = QLI_MAXFER; - minphys(bp); -} - -void -qli_disable_interrupts(struct qli_softc *sc) -{ - DNPRINTF(QLI_D_INTR, "%s: qli_disable_interrupts\n", DEVNAME(sc)); - - if (sc->sc_ql4010) - qli_write(sc, &sc->sc_reg->qlr_ctrl_status, - QLI_CLR_MASK(QLI_REG_CTRLSTAT_SCSI_INTR_ENABLE)); - else - qli_write(sc, &sc->sc_reg->u1.isp4022.q22_intr_mask, - QLI_CLR_MASK(QLI_REG_CTRLSTAT_SCSI_INTR_ENABLE_4022)); -} - -void -qli_enable_interrupts(struct qli_softc *sc) -{ - DNPRINTF(QLI_D_INTR, "%s: qli_enable_interrupts\n", DEVNAME(sc)); - - if (sc->sc_ql4010) - qli_write(sc, &sc->sc_reg->qlr_ctrl_status, - QLI_SET_MASK(QLI_REG_CTRLSTAT_SCSI_INTR_ENABLE)); - else - qli_write(sc, &sc->sc_reg->u1.isp4022.q22_intr_mask, - QLI_SET_MASK(QLI_REG_CTRLSTAT_SCSI_INTR_ENABLE_4022)); -} - -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) -{ - int rv = 1; - - DNPRINTF(QLI_D_MISC, "%s: qli_get_fw_state\n", DEVNAME(sc)); - - mbox[0] = QLI_MBOX_OPC_GET_FW_STATE; - if (qli_mgmt(sc, 1, mbox)) - goto done; - - DNPRINTF(QLI_D_MISC, "%s: qli_get_fw_state: state: 0x%08x\n", - DEVNAME(sc), mbox[1]); - rv = 0; -done: - return (rv); -} - -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); -} - -void -qli_eeprom_out(struct qli_softc *sc, u_int32_t data) -{ - qli_write(sc, QLI_NVRAM(sc), data); - delay(1); -} - -u_int16_t -qli_read_nvram(struct qli_softc *sc, u_int32_t offset) -{ - int i; - u_int32_t s, mask, data; - u_int16_t val = 0; -#ifdef QLI_DEBUG - u_int32_t qli_debug_save = qli_debug; - - qli_debug = 0; -#endif /* QLI_DEBUG */ - - /* select chip */ - s = QLI_NVRAM_MASK | QLI_NVRAM_SELECT; - qli_eeprom_out(sc, s); - - /* start bit */ - qli_eeprom_out(sc, s | QLI_NVRAM_DATA_OUT); - qli_eeprom_out(sc, s | QLI_NVRAM_DATA_OUT | QLI_NVRAM_CLOCK); - qli_eeprom_out(sc, s | QLI_NVRAM_DATA_OUT); /* clock low */ - - /* send read command */ - mask = 1 << (QLI_NVRAM_NUM_CMD_BITS - 1); - for (i = 0; i < QLI_NVRAM_NUM_CMD_BITS; i++) { - data = ((QLI_NVRAM_CMD_READ << i) & mask) ? - QLI_NVRAM_DATA_OUT : 0; - - qli_eeprom_out(sc, s | data); - qli_eeprom_out(sc, s | data | QLI_NVRAM_CLOCK); - qli_eeprom_out(sc, s | data); - } - - /* send read address */ - mask = 1 << (QLI_NVRAM_NUM_ADDR_BITS(sc) - 1); - for (i = 0; i < QLI_NVRAM_NUM_ADDR_BITS(sc); i++) { - data = ((offset << i) & mask) ? QLI_NVRAM_DATA_OUT : 0; - qli_eeprom_out(sc, s | data); - qli_eeprom_out(sc, s | data | QLI_NVRAM_CLOCK); - qli_eeprom_out(sc, s | data); - } - - /* read data */ - for (i = 0; i < QLI_NVRAM_NUM_DATA_BITS; i++) { - qli_eeprom_out(sc, s | QLI_NVRAM_CLOCK); - qli_eeprom_out(sc, s); - data = (qli_read(sc, QLI_NVRAM(sc)) & QLI_NVRAM_DATA_IN) ? - 1 : 0; - val = (val << 1) | data; - } - - /* deselect chip */ - s = QLI_NVRAM_MASK; - qli_write(sc, QLI_NVRAM(sc), s); - -#ifdef QLI_DEBUG - qli_debug = qli_debug_save; -#endif /* QLI_DEBUG */ - - DNPRINTF(QLI_D_RW, "%s: qli_read_nvram 0x%x 0x%04x\n", DEVNAME(sc), - offset, letoh16(val)); - - return (letoh16(val)); -} - -int -qli_validate_nvram(struct qli_softc *sc) -{ - int i, rv = 1; - u_int16_t nvram_checksum = 0; - - DNPRINTF(QLI_D_MISC, "%s: qli_validate_nvram\n", DEVNAME(sc)); - - for (i = 0; i < QLI_NVRAM_SIZE(sc); i++) - nvram_checksum += qli_read_nvram(sc, i); - - DNPRINTF(QLI_D_MISC, "%s: nvram checksum 0x%04x\n", DEVNAME(sc), - nvram_checksum); - - if (nvram_checksum == 0) - rv = 0; - - 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 (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 - r = (u_int32_t)qli_read_nvram(sc, - QLI_NVRAM_EXT_HW_CFG(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 1234 */ - 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_mgmt(struct qli_softc *sc, int len, u_int32_t *mbox) -{ - int rv = 1, s, i; - u_int32_t x; - - DNPRINTF(QLI_D_MBOX, "%s: qli_mgmt: cold: %d\n", DEVNAME(sc), cold); - - if (!mbox) - goto done; - - s = splbio(); - rw_enter_write(&sc->sc_mbox_lock); - - if (qli_read(sc, &sc->sc_reg->qlr_ctrl_status) & - QLI_REG_CTRLSTAT_SCSI_PROC_INTR) { - /* this should not happen */ - printf("%s: qli_mgmt called while interrupt is pending\n", - DEVNAME(sc)); - qli_intr(sc); - } - - qli_dump_mbox(sc, mbox); - - /* mbox[0] needs to be written last so write backwards */ - for (i = QLI_MBOX_SIZE - 1; i >= 0; i--) - qli_write(sc, &sc->sc_reg->qlr_mbox[i], i < len ? mbox[i] : 0); - - /* notify chip it has to deal with mailbox */ - qli_write(sc, &sc->sc_reg->qlr_ctrl_status, - QLI_SET_MASK(QLI_REG_CTRLSTAT_EP_INTR)); - - /* wait for completion */ - if (cold) { - sc->sc_mbox_flags = QLI_MBOX_F_POLL; - for (i = 0; i < 6000000 /* up to a minute */; i++) { - delay(10); - if ((qli_read(sc, &sc->sc_reg->qlr_ctrl_status) & - (QLI_REG_CTRLSTAT_SCSI_RESET_INTR | - QLI_REG_CTRLSTAT_SCSI_COMPL_INTR | - QLI_REG_CTRLSTAT_SCSI_PROC_INTR))) { - qli_intr(sc); - break; - } - } - } else { - sc->sc_mbox_flags = QLI_MBOX_F_PENDING; - while ((sc->sc_mbox_flags & QLI_MBOX_F_WAKEUP) == 0) - tsleep(sc->sc_mbox, PRIBIO, "qli_mgmt", 0); - } - - x = sc->sc_mbox[0]; - switch (x) { - case QLI_MBOX_STATUS_COMMAND_COMPLETE: - for (i = 0; i < QLI_MBOX_SIZE; i++) - mbox[i] = sc->sc_mbox[i]; - sc->sc_mbox_flags = QLI_MBOX_F_INVALID; - rv = 0; - - qli_dump_mbox(sc, mbox); - break; - default: - printf("%s: qli_mgmt: mailbox failed opcode 0x%08x failed " - "with error code 0x%08x\n", DEVNAME(sc), mbox[0], x); - } - - rw_exit_write(&sc->sc_mbox_lock); - splx(s); -done: - return (rv); -} - -int -qli_attach(struct qli_softc *sc) -{ - /* struct scsibus_attach_args saa; */ - int rv = 1; - u_int32_t f, mbox[QLI_MBOX_SIZE]; - unsigned int align; - - DNPRINTF(QLI_D_MISC, "%s: qli_attach\n", DEVNAME(sc)); - - rw_init(&sc->sc_lock, "qli_lock"); - rw_init(&sc->sc_mbox_lock, "qli_mbox_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); - - if (qli_start_firmware(sc)) { - printf("%s: could not start firmware\n", DEVNAME(sc)); - goto done; - } - - bzero(mbox, sizeof(mbox)); - mbox[0] = QLI_MBOX_OPC_ABOUT_FIRMWARE; - if (qli_mgmt(sc, 4, mbox)) { - printf("%s: about firmware command failed\n", DEVNAME(sc)); - goto done; - } - printf("%s: version %d.%d.%d.%d\n", DEVNAME(sc), mbox[1], mbox[2], - mbox[3], mbox[4]); - - /* get state */ - bzero(mbox, sizeof(mbox)); - if (qli_get_fw_state(sc, mbox)) { - printf("%s: get firmware state command failed\n", DEVNAME(sc)); - goto done; - } - - /* initialize firmware */ - sc->sc_fw_cb = qli_allocmem(sc, QLI_FW_CTRL_BLK_SIZE); - if (sc->sc_fw_cb == NULL) { - printf("%s: unable to allocate firmware control block memory\n", - DEVNAME(sc)); - goto done; - } - bzero(mbox, sizeof(mbox)); - mbox[0] = QLI_MBOX_OPC_GET_INITIAL_FW_CB; - mbox[2] = (u_int32_t)QLIMEM_DVA(sc->sc_fw_cb); - mbox[3] = (u_int32_t)((u_int64_t)QLIMEM_DVA(sc->sc_fw_cb) >> 32); - if (qli_mgmt(sc, 4, mbox)) { - printf("%s: get initial firmware control block failed\n", - DEVNAME(sc)); - goto nofwcb; - } - - /* setup queues & shadow registers */ - sc->sc_queues_len = (QLI_REQUESTQ_DEPTH * QLI_QUEUE_SIZE) + - (QLI_RESPONSEQ_DEPTH * QLI_QUEUE_SIZE) + - sizeof(struct qli_shadow_regs) + - QLIMEM_ALIGN + PAGE_SIZE - 1; - sc->sc_queues_len &= ~(PAGE_SIZE - 1); - - sc->sc_queues = qli_allocmem(sc, sc->sc_queues_len); - if (sc->sc_queues == NULL) { - printf("%s: unable to allocate firmware control block memory\n", - DEVNAME(sc)); - goto nofwcb; - } - - if (QLIMEM_DVA(sc->sc_queues) & (QLIMEM_ALIGN - 1)) - align = QLIMEM_ALIGN - - (QLIMEM_DVA(sc->sc_queues) & (QLIMEM_ALIGN - 1)); - else - align = 0; - - sc->sc_request_dva = QLIMEM_DVA(sc->sc_queues) + align; - sc->sc_request_ring = QLIMEM_KVA(sc->sc_queues) + align; - -#if 0 - /* enable interrupts */ - qli_enable_interrupts(sc); -#endif - -#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 */ - -done: - return (rv); -/* noqueues: */ - qli_freemem(sc, sc->sc_queues); -nofwcb: - qli_freemem(sc, sc->sc_fw_cb); - return (rv); -} - -void -qli_scsi_cmd(struct scsi_xfer *xs) -{ - int s; -#ifdef QLI_DEBUG - 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); -#endif - - goto stuffup; - return; - -stuffup: - xs->error = XS_DRIVER_STUFFUP; - scsi_done(xs); -} - -int -qli_intr(void *arg) -{ - struct qli_softc *sc = arg; - int claimed = 0, i; - u_int32_t intr, mbox_status; - - intr = qli_read(sc, &sc->sc_reg->qlr_ctrl_status); - if ((intr & (QLI_REG_CTRLSTAT_SCSI_RESET_INTR | - QLI_REG_CTRLSTAT_SCSI_COMPL_INTR | - QLI_REG_CTRLSTAT_SCSI_PROC_INTR | - QLI_REG_CTRLSTAT_FATAL_ERROR)) == 0) - goto done; - - DNPRINTF(QLI_D_INTR, "%s: qli_intr %#x cs: 0x%08x\n", DEVNAME(sc), sc, - intr); - - if (intr & QLI_REG_CTRLSTAT_SCSI_RESET_INTR) { - /* chip requests soft reset */ - /* XXX */ - panic("%s: qli_intr chip reset not implemented", DEVNAME(sc)); - } - - if (intr & QLI_REG_CTRLSTAT_FATAL_ERROR) { - /* reset firmware */ - /* XXX */ - panic("%s: qli_intr chip hang recovery not implemented", - DEVNAME(sc)); - } - - if (intr & QLI_REG_CTRLSTAT_SCSI_COMPL_INTR) { - /* io completion */ - /* XXX */ - panic("%s: qli_intr io completion not implemented", - DEVNAME(sc)); - } - - if (intr & QLI_REG_CTRLSTAT_SCSI_PROC_INTR) { - /* mailbox completion */ - mbox_status = qli_read(sc, &sc->sc_reg->qlr_mbox[0]); - switch (mbox_status >> QLI_MBOX_TYPE_SHIFT) { - case QLI_MBOX_COMPLETION_STATUS: - for (i = 0; i < QLI_MBOX_SIZE; i++) - sc->sc_mbox[i] = qli_read(sc, - &sc->sc_reg->qlr_mbox[i]); - qli_write(sc, &sc->sc_reg->qlr_ctrl_status, - QLI_SET_MASK(QLI_REG_CTRLSTAT_SCSI_PROC_INTR)); - if (sc->sc_mbox_flags & QLI_MBOX_F_PENDING) { - sc->sc_mbox_flags |= QLI_MBOX_F_WAKEUP; - wakeup(sc->sc_mbox); - } - claimed = 1; - break; - case QLI_MBOX_ASYNC_EVENT_STATUS: - printf("%s: unhandled async event 0x%08x\n", - DEVNAME(sc), - qli_read(sc, &sc->sc_reg->qlr_mbox[0])); - break; - default: - printf("%s: invalid mailbox return 0x%08x\n", - DEVNAME(sc), - qli_read(sc, &sc->sc_reg->qlr_mbox[0])); - break; - } - } - -done: - return (claimed); -} - -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 */ - -#ifdef QLI_DEBUG -void -qli_dump_mbox(struct qli_softc *sc, u_int32_t *mbox) -{ - int i; - - if ((qli_debug & QLI_D_MBOX) == 0) - return; - - printf("%s: qli_dump_mbox: ", DEVNAME(sc)); - for (i = 0; i < QLI_MBOX_SIZE; i++) - printf("mbox[%d] = 0x%08x ", i, mbox[i]); - printf("\n"); -} -#endif /* QLI_DEBUG */ |
