diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2000-12-17 21:35:07 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2000-12-17 21:35:07 +0000 |
commit | 4a84265eb1253bc6abfb8acb6293c52e6b80b16d (patch) | |
tree | 89fa3c7b36c364292ff859a11cfd0dcdfb9d8f77 | |
parent | 21735d7d8a0901a2129a1e8d27c76cbbc178054f (diff) |
Compaq SMART Array RAID controllers.
based on netbsd driver.
testing helps from brad@
eisa untested, but should work (;
-rw-r--r-- | sys/arch/i386/conf/GENERIC | 5 | ||||
-rw-r--r-- | sys/arch/i386/conf/RAMDISKB | 5 | ||||
-rw-r--r-- | sys/arch/i386/conf/RAMDISK_CD | 5 | ||||
-rw-r--r-- | sys/conf/files | 6 | ||||
-rw-r--r-- | sys/dev/eisa/cac_eisa.c | 306 | ||||
-rw-r--r-- | sys/dev/eisa/files.eisa | 6 | ||||
-rw-r--r-- | sys/dev/ic/cac.c | 826 | ||||
-rw-r--r-- | sys/dev/ic/cacreg.h | 200 | ||||
-rw-r--r-- | sys/dev/ic/cacvar.h | 124 | ||||
-rw-r--r-- | sys/dev/pci/cac_pci.c | 270 | ||||
-rw-r--r-- | sys/dev/pci/files.pci | 6 |
11 files changed, 1753 insertions, 6 deletions
diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index 59c33cced91..3a49feb27d7 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.215 2000/11/17 15:13:20 aaron Exp $ +# $OpenBSD: GENERIC,v 1.216 2000/12/17 21:35:04 mickey Exp $ # $NetBSD: GENERIC,v 1.48 1996/05/20 18:17:23 mrg Exp $ # # GENERIC -- everything that's currently supported @@ -193,6 +193,9 @@ twe* at pci? dev ? function ? # 3ware Escalade RAID controllers scsibus* at twe? aac* at pci? dev ? function ? # Adaptec FSA RAID controllers scsibus* at aac? +cac* at pci? dev ? function ? # Compaq Smart ARRAY RAID controllers +cac* at eisa? slot ? +scsibus* at cac? isp* at pci? dev ? function ? # Qlogic ISP [12]0x0 SCSI/FibreChannel scsibus* at isp? aic0 at isa? port 0x340 irq 11 # Adaptec 152[02] SCSI controllers diff --git a/sys/arch/i386/conf/RAMDISKB b/sys/arch/i386/conf/RAMDISKB index 59179ad5594..f2bdd3093bf 100644 --- a/sys/arch/i386/conf/RAMDISKB +++ b/sys/arch/i386/conf/RAMDISKB @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISKB,v 1.25 2000/11/18 02:58:47 deraadt Exp $ +# $OpenBSD: RAMDISKB,v 1.26 2000/12/17 21:35:04 mickey Exp $ # from: OpenBSD: INST,v 1.19 1996/11/05 03:49:13 tholo Exp # # Install kernels no longer support X. @@ -128,6 +128,9 @@ gdt* at pci? dev ? function ? # ICP Vortex GDT RAID controllers scsibus* at gdt? aac* at pci? dev ? function ? # Adaptec FSA RAID controllers scsibus* at aac? +cac* at pci? dev ? function ? # Compaq Smart ARRAY RAID controllers +cac* at eisa? slot ? +scsibus* at cac? twe* at pci? dev ? function ? # 3ware Escalade RAID controllers scsibus* at twe? isp* at pci? dev ? function ? # Qlogic ISP [12]0x0 SCSI/FibreChannel diff --git a/sys/arch/i386/conf/RAMDISK_CD b/sys/arch/i386/conf/RAMDISK_CD index 647917ba25e..fc4743d635e 100644 --- a/sys/arch/i386/conf/RAMDISK_CD +++ b/sys/arch/i386/conf/RAMDISK_CD @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK_CD,v 1.26 2000/11/18 02:58:47 deraadt Exp $ +# $OpenBSD: RAMDISK_CD,v 1.27 2000/12/17 21:35:05 mickey Exp $ # from: OpenBSD: INST,v 1.19 1996/11/05 03:49:13 tholo Exp # # Install kernels no longer support X. @@ -134,6 +134,9 @@ gdt* at pci? dev ? function ? # ICP Vortex GDT RAID controllers scsibus* at gdt? aac* at pci? dev ? function ? # Adaptec FSA RAID controllers scsibus* at aac? +cac* at pci? dev ? function ? # Compaq Smart ARRAY RAID controllers +cac* at eisa? slot ? +scsibus* at cac? twe* at pci? dev ? function ? # 3ware Escalade RAID controllers scsibus* at twe? isp* at pci? dev ? function ? # Qlogic ISP [12]0x0 SCSI/FibreChannel diff --git a/sys/conf/files b/sys/conf/files index 58cae074312..5ed4f83c67e 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.181 2000/12/12 03:41:22 jason Exp $ +# $OpenBSD: files,v 1.182 2000/12/17 21:34:57 mickey Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -104,6 +104,10 @@ file dev/ic/gdt_common.c gdt device twe: scsi file dev/ic/twe.c twe +# Compaq Smart ARRAY controllers +device cac: scsi +file dev/ic/cac.c cac + # Qlogic ISP 10x0 SCSI Controllers device isp: scsi file dev/ic/isp.c isp diff --git a/sys/dev/eisa/cac_eisa.c b/sys/dev/eisa/cac_eisa.c new file mode 100644 index 00000000000..7c90dea630c --- /dev/null +++ b/sys/dev/eisa/cac_eisa.c @@ -0,0 +1,306 @@ +/* $OpenBSD: cac_eisa.c,v 1.1 2000/12/17 21:35:03 mickey Exp $ */ +/* $NetBSD: cac_eisa.c,v 1.1 2000/09/01 12:15:20 ad Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Andrew Doran. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2000 Jonathan Lemon + * Copyright (c) 1999 by Matthew N. Dodd <winter@jurai.net> + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * EISA front-end for cac(4) driver. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +#include <dev/eisa/eisavar.h> +#include <dev/eisa/eisadevs.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_disk.h> +#include <scsi/scsiconf.h> + +#include <dev/ic/cacreg.h> +#include <dev/ic/cacvar.h> + +#define CAC_EISA_SLOT_OFFSET 0x0c88 +#define CAC_EISA_IOSIZE 0x0017 +#define CAC_EISA_IOCONF 0x38 + +int cac_eisa_match(struct device *, void *, void *); +void cac_eisa_attach(struct device *, struct device *, void *); + +struct cac_ccb *cac_eisa_l0_completed(struct cac_softc *); +int cac_eisa_l0_fifo_full(struct cac_softc *); +void cac_eisa_l0_intr_enable(struct cac_softc *, int); +int cac_eisa_l0_intr_pending(struct cac_softc *); +void cac_eisa_l0_submit(struct cac_softc *, struct cac_ccb *); + +struct cfattach cac_eisa_ca = { + sizeof(struct cac_softc), cac_eisa_match, cac_eisa_attach +}; + +static const +struct cac_linkage cac_eisa_l0 = { + cac_eisa_l0_completed, + cac_eisa_l0_fifo_full, + cac_eisa_l0_intr_enable, + cac_eisa_l0_intr_pending, + cac_eisa_l0_submit +}; + +static const +struct cac_eisa_type { + const char *ct_prodstr; + const char *ct_typestr; + const struct cac_linkage *ct_linkage; +} cac_eisa_type[] = { + { "CPQ4001", "IDA", &cac_eisa_l0 }, + { "CPQ4002", "IDA-2", &cac_eisa_l0 }, + { "CPQ4010", "IEAS", &cac_eisa_l0 }, + { "CPQ4020", "SMART", &cac_eisa_l0 }, + { "CPQ4030", "SMART-2/E", &cac_l0 }, +}; + +int +cac_eisa_match(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct eisa_attach_args *ea; + int i; + + ea = aux; + + for (i = 0; i < sizeof(cac_eisa_type) / sizeof(cac_eisa_type[0]); i++) + if (strcmp(ea->ea_idstring, cac_eisa_type[i].ct_prodstr) == 0) + return (1); + + return (0); +} + +void +cac_eisa_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct eisa_attach_args *ea; + bus_space_handle_t ioh; + eisa_chipset_tag_t ec; + eisa_intr_handle_t ih; + struct cac_softc *sc; + bus_space_tag_t iot; + const char *intrstr; + int irq, i; + + ea = aux; + sc = (struct cac_softc *)self; + iot = ea->ea_iot; + ec = ea->ea_ec; + + if (bus_space_map(iot, EISA_SLOT_ADDR(ea->ea_slot) + + CAC_EISA_SLOT_OFFSET, CAC_EISA_IOSIZE, 0, &ioh)) { + printf(": can't map i/o space\n"); + return; + } + + sc->sc_iot = iot; + sc->sc_ioh = ioh; + sc->sc_dmat = ea->ea_dmat; + + /* + * Map and establish the interrupt. + */ + switch (bus_space_read_1(iot, ioh, CAC_EISA_IOCONF) & 0xf0) { + case 0x20: + irq = 10; + break; + case 0x10: + irq = 11; + break; + case 0x40: + irq = 14; + break; + case 0x80: + irq = 15; + break; + default: + printf(": controller on invalid IRQ\n"); + return; + } + + if (eisa_intr_map(ec, irq, &ih)) { + printf(": can't map interrupt (%d)\n", irq); + return; + } + + intrstr = eisa_intr_string(ec, ih); + if ((sc->sc_ih = eisa_intr_establish(ec, ih, IST_LEVEL, IPL_BIO, + cac_intr, sc, sc->sc_dv.dv_xname)) == NULL) { + printf(": can't establish interrupt"); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + return; + } + + /* + * Print board type and attach to the bus-independent code. + */ + for (i = 0; i < sizeof(cac_eisa_type) / sizeof(cac_eisa_type[0]); i++) + if (strcmp(ea->ea_idstring, cac_eisa_type[i].ct_prodstr) == 0) + break; + + printf(" %s: Compaq %s\n", intrstr, cac_eisa_type[i].ct_typestr); + sc->sc_cl = cac_eisa_type[i].ct_linkage; + cac_init(sc, 0); +} + +/* + * Linkage specific to EISA boards. + */ + +int +cac_eisa_l0_fifo_full(struct cac_softc *sc) +{ + + return ((cac_inb(sc, CAC_EISAREG_SYSTEM_DOORBELL) & + CAC_EISA_CHANNEL_CLEAR) == 0); +} + +void +cac_eisa_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb) +{ + u_int16_t size; + + /* + * On these boards, `ccb_hdr.size' is actually for control flags. + * Set it to zero and pass the value by means of an I/O port. + */ + size = letoh16(ccb->ccb_hdr.size) << 2; + ccb->ccb_hdr.size = 0; + + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + + cac_outb(sc, CAC_EISAREG_SYSTEM_DOORBELL, CAC_EISA_CHANNEL_CLEAR); + cac_outl(sc, CAC_EISAREG_LIST_ADDR, ccb->ccb_paddr); + cac_outw(sc, CAC_EISAREG_LIST_LEN, size); + cac_outb(sc, CAC_EISAREG_LOCAL_DOORBELL, CAC_EISA_CHANNEL_BUSY); +} + +struct cac_ccb * +cac_eisa_l0_completed(struct cac_softc *sc) +{ + struct cac_ccb *ccb; + u_int32_t off; + u_int8_t status; + + if ((cac_inb(sc, CAC_EISAREG_SYSTEM_DOORBELL) & + CAC_EISA_CHANNEL_BUSY) == 0) + return (NULL); + + cac_outb(sc, CAC_EISAREG_SYSTEM_DOORBELL, CAC_EISA_CHANNEL_BUSY); + off = cac_inl(sc, CAC_EISAREG_COMPLETE_ADDR); + status = cac_inb(sc, CAC_EISAREG_LIST_STATUS); + cac_outb(sc, CAC_EISAREG_LOCAL_DOORBELL, CAC_EISA_CHANNEL_CLEAR); + + if (off == 0) + return (NULL); + + off = (off & ~3) - sc->sc_ccbs_paddr; + ccb = (struct cac_ccb *)(sc->sc_ccbs + off); + + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); + + ccb->ccb_req.error = status; + return (ccb); +} + +int +cac_eisa_l0_intr_pending(struct cac_softc *sc) +{ + + return (cac_inb(sc, CAC_EISAREG_SYSTEM_DOORBELL) & + CAC_EISA_CHANNEL_BUSY); +} + +void +cac_eisa_l0_intr_enable(struct cac_softc *sc, int state) +{ + + if (state) { + cac_outb(sc, CAC_EISAREG_SYSTEM_DOORBELL, + ~CAC_EISA_CHANNEL_CLEAR); + cac_outb(sc, CAC_EISAREG_LOCAL_DOORBELL, + CAC_EISA_CHANNEL_BUSY); + cac_outb(sc, CAC_EISAREG_INTR_MASK, CAC_INTR_ENABLE); + cac_outb(sc, CAC_EISAREG_SYSTEM_MASK, CAC_INTR_ENABLE); + } else + cac_outb(sc, CAC_EISAREG_SYSTEM_MASK, CAC_INTR_DISABLE); +} diff --git a/sys/dev/eisa/files.eisa b/sys/dev/eisa/files.eisa index 22ff6417699..ba9447b47c6 100644 --- a/sys/dev/eisa/files.eisa +++ b/sys/dev/eisa/files.eisa @@ -1,4 +1,4 @@ -# $OpenBSD: files.eisa,v 1.9 1999/11/30 07:55:55 cmetz Exp $ +# $OpenBSD: files.eisa,v 1.10 2000/12/17 21:35:03 mickey Exp $ # $NetBSD: files.eisa,v 1.12 1996/09/01 00:10:55 mycroft Exp $ # # Config.new file and device description for machine-independent EISA code. @@ -34,6 +34,10 @@ file dev/eisa/dpt_eisa.c dpt_eisa attach uha at eisa with uha_eisa file dev/eisa/uha_eisa.c uha_eisa +# Compaq Array Controllers +attach cac at eisa with cac_eisa +file dev/eisa/cac_eisa.c cac_eisa + # 3Com 3c579 and 3c509 masquerading as EISA Ethernet Controllers # device declaration in sys/conf/files attach ep at eisa with ep_eisa diff --git a/sys/dev/ic/cac.c b/sys/dev/ic/cac.c new file mode 100644 index 00000000000..4c8dc18d396 --- /dev/null +++ b/sys/dev/ic/cac.c @@ -0,0 +1,826 @@ +/* $OpenBSD: cac.c,v 1.1 2000/12/17 21:35:06 mickey Exp $ */ +/* $NetBSD: cac.c,v 1.14 2000/11/08 19:20:35 ad Exp $ */ + +/* + * Copyright (c) 2000 Michael Shalayeff + * All rights reserved. + * + * The SCSI emulation layer is derived from gdt(4) driver, + * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Michael Shalayeff. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Andrew Doran. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Driver for Compaq array controllers. + */ +#undef CAC_DEBUG + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/queue.h> +#include <sys/proc.h> +#include <sys/buf.h> +#include <sys/endian.h> +#include <sys/malloc.h> +#include <sys/pool.h> + +#include <vm/vm.h> +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_disk.h> +#include <scsi/scsiconf.h> + +#include <dev/ic/cacreg.h> +#include <dev/ic/cacvar.h> + +struct cfdriver cac_cd = { + NULL, "cac", DV_DULL +}; + +int cac_scsi_cmd __P((struct scsi_xfer *)); +void cacminphys __P((struct buf *bp)); + +struct scsi_adapter cac_switch = { + cac_scsi_cmd, cacminphys, 0, 0, +}; + +struct scsi_device cac_dev = { + NULL, NULL, NULL, NULL +}; + +struct cac_ccb *cac_ccb_alloc(struct cac_softc *, int); +void cac_ccb_done(struct cac_softc *, struct cac_ccb *); +void cac_ccb_free(struct cac_softc *, struct cac_ccb *); +int cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int); +int cac_ccb_start(struct cac_softc *, struct cac_ccb *); +int cac_cmd(struct cac_softc *sc, int command, void *data, int datasize, + int drive, int blkno, int flags, struct scsi_xfer *xs); +int cac_get_dinfo __P((struct cac_softc *sc, int target)); +void cac_shutdown __P((void *)); +void cac_copy_internal_data __P((struct scsi_xfer *xs, void *v, size_t size)); + +struct cac_ccb *cac_l0_completed(struct cac_softc *); +int cac_l0_fifo_full(struct cac_softc *); +void cac_l0_intr_enable(struct cac_softc *, int); +int cac_l0_intr_pending(struct cac_softc *); +void cac_l0_submit(struct cac_softc *, struct cac_ccb *); + +void *cac_sdh; /* shutdown hook */ + +const +struct cac_linkage cac_l0 = { + cac_l0_completed, + cac_l0_fifo_full, + cac_l0_intr_enable, + cac_l0_intr_pending, + cac_l0_submit +}; + +/* + * Initialise our interface to the controller. + */ +int +cac_init(struct cac_softc *sc, int startfw) +{ + struct cac_controller_info cinfo; + int error, rseg, size, i; + bus_dma_segment_t seg; + struct cac_ccb *ccb; + + SIMPLEQ_INIT(&sc->sc_ccb_free); + SIMPLEQ_INIT(&sc->sc_ccb_queue); + + size = sizeof(struct cac_ccb) * CAC_MAX_CCBS; + + if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1, + &rseg, BUS_DMA_NOWAIT)) != 0) { + printf("%s: unable to allocate CCBs, error = %d\n", + sc->sc_dv.dv_xname, error); + return (-1); + } + + if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, + (caddr_t *)&sc->sc_ccbs, + BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { + printf("%s: unable to map CCBs, error = %d\n", + sc->sc_dv.dv_xname, error); + return (-1); + } + + if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, + BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { + printf("%s: unable to create CCB DMA map, error = %d\n", + sc->sc_dv.dv_xname, error); + return (-1); + } + + if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs, + size, NULL, BUS_DMA_NOWAIT)) != 0) { + printf("%s: unable to load CCB DMA map, error = %d\n", + sc->sc_dv.dv_xname, error); + return (-1); + } + + sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr; + memset(sc->sc_ccbs, 0, size); + ccb = (struct cac_ccb *)sc->sc_ccbs; + + for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) { + /* Create the DMA map for this CCB's data */ + error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER, + CAC_SG_SIZE, CAC_MAX_XFER, 0, + BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, + &ccb->ccb_dmamap_xfer); + + if (error) { + printf("%s: can't create ccb dmamap (%d)\n", + sc->sc_dv.dv_xname, error); + break; + } + + ccb->ccb_flags = 0; + ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb); + SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain); + } + + /* Start firmware background tasks, if needed. */ + if (startfw) { + if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo), + 0, 0, CAC_CCB_DATA_IN, NULL)) { + printf("%s: CAC_CMD_START_FIRMWARE failed\n", + sc->sc_dv.dv_xname); + return (-1); + } + } + + if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0, + CAC_CCB_DATA_IN, NULL)) { + printf("%s: CAC_CMD_GET_CTRL_INFO failed\n", + sc->sc_dv.dv_xname); + return (-1); + } + + sc->sc_nunits = cinfo.num_drvs; + sc->sc_dinfos = malloc(cinfo.num_drvs * sizeof(struct cac_drive_info), + M_DEVBUF, M_NOWAIT); + if (sc->sc_dinfos == NULL) { + printf("%s: cannot allocate memory for drive_info\n", + sc->sc_dv.dv_xname); + return (-1); + } + bzero(sc->sc_dinfos, cinfo.num_drvs * sizeof(struct cac_drive_info)); + + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter = &cac_switch; + sc->sc_link.adapter_target = cinfo.num_drvs; + sc->sc_link.adapter_buswidth = cinfo.num_drvs; + sc->sc_link.device = &cac_dev; + sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits; + if (sc->sc_link.openings < 4 ) + sc->sc_link.openings = 4; + + config_found(&sc->sc_dv, &sc->sc_link, scsiprint); + + /* Set our `shutdownhook' before we start any device activity. */ + if (cac_sdh == NULL) + cac_sdh = shutdownhook_establish(cac_shutdown, NULL); + + (*sc->sc_cl->cl_intr_enable)(sc, 1); + return (0); +} + +/* + * Shut down all `cac' controllers. + */ +void +cac_shutdown(void *cookie) +{ + extern struct cfdriver cac_cd; + struct cac_softc *sc; + u_int8_t buf[512]; + int i; + + for (i = 0; i < cac_cd.cd_ndevs; i++) { + if ((sc = (struct cac_softc *)device_lookup(&cac_cd, i)) == NULL) + continue; + memset(buf, 0, sizeof(buf)); + buf[0] = 1; + cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0, + CAC_CCB_DATA_OUT, NULL); + } +} + +/* + * Handle an interrupt from the controller: process finished CCBs and + * dequeue any waiting CCBs. + */ +int +cac_intr(v) + void *v; +{ + struct cac_softc *sc = v; + struct cac_ccb *ccb; + int ret = 0; + + if (!(sc->sc_cl->cl_intr_pending)(sc)) + return 0; + + while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) { + ret++; + cac_ccb_done(sc, ccb); + cac_ccb_start(sc, NULL); + } + + return (ret); +} + +/* + * Execute a [polled] command. + */ +int +cac_cmd(struct cac_softc *sc, int command, void *data, int datasize, + int drive, int blkno, int flags, struct scsi_xfer *xs) +{ + struct cac_ccb *ccb; + struct cac_sgb *sgb; + int i, rv, size, nsegs; + +#ifdef CAC_DEBUG + printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ", + command, drive, blkno, data, datasize, flags, xs); +#endif + + if ((ccb = cac_ccb_alloc(sc, 0)) == NULL) { + printf("%s: unable to alloc CCB", sc->sc_dv.dv_xname); + return (ENOMEM); + } + + if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { + bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, + (void *)data, datasize, NULL, BUS_DMA_NOWAIT); + + bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, + (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD : + BUS_DMASYNC_PREWRITE); + + sgb = ccb->ccb_seg; + nsegs = min(ccb->ccb_dmamap_xfer->dm_nsegs, CAC_SG_SIZE); + + size = 0; + for (i = 0; i < nsegs; i++, sgb++) { + size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len; + sgb->length = + htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len); + sgb->addr = + htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr); + } + } else { + size = datasize; + nsegs = 0; + } + + ccb->ccb_hdr.drive = drive; + ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) + + sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2); + + ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE)); + ccb->ccb_req.command = command; + ccb->ccb_req.sgcount = nsegs; + ccb->ccb_req.blkno = htole32(blkno); + + ccb->ccb_flags = flags; + ccb->ccb_datasize = size; + ccb->ccb_xs = xs; + + if (!xs || xs->flags & SCSI_POLL) { + int s; + + s = splbio(); + + /* Synchronous commands musn't wait. */ + if ((*sc->sc_cl->cl_fifo_full)(sc)) { + cac_ccb_free(sc, ccb); + rv = -1; + } else { + ccb->ccb_flags |= CAC_CCB_ACTIVE; + (*sc->sc_cl->cl_submit)(sc, ccb); + rv = cac_ccb_poll(sc, ccb, 2000); + } + splx(s); + } else + rv = cac_ccb_start(sc, ccb); + + return (rv); +} + +/* + * Wait for the specified CCB to complete. Must be called at splbio. + */ +int +cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo) +{ + struct cac_ccb *ccb; + + timo *= 10; + + do { + for (; timo > 0; timo--) { + if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) + break; + DELAY(100); + } + + if (timo <= 0) { + printf("%s: timeout\n", sc->sc_dv.dv_xname); + return (EBUSY); + } + cac_ccb_done(sc, ccb); + } while (ccb != wantccb); + + return (0); +} + +/* + * Enqueue the specifed command (if any) and attempt to start all enqueued + * commands. Must be called at splbio. + */ +int +cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb) +{ + + if (ccb != NULL) + SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain); + + while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) { + if ((*sc->sc_cl->cl_fifo_full)(sc)) + return (EBUSY); + SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb, ccb_chain); + ccb->ccb_flags |= CAC_CCB_ACTIVE; + (*sc->sc_cl->cl_submit)(sc, ccb); + } + + return (0); +} + +/* + * Process a finished CCB. + */ +void +cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb) +{ + struct scsi_xfer *xs = ccb->ccb_xs; + int error = 0; + + if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) { +#ifdef CAC_DEBUG + printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs); +#endif + if (xs) { + xs->error = XS_DRIVER_STUFFUP; + scsi_done(xs); + } + return; + } + ccb->ccb_flags &= ~CAC_CCB_ACTIVE; + + if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) { + bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, + ccb->ccb_flags & CAC_CCB_DATA_IN ? + BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer); + } + + if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0) + printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname); + if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) { + error = 1; + printf("%s: hard error\n", sc->sc_dv.dv_xname); + } + if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) { + error = 1; + printf("%s: invalid request\n", sc->sc_dv.dv_xname); + } + + if (xs) { + if (error) + xs->error = XS_DRIVER_STUFFUP; + else { + xs->resid = 0; + xs->flags |= ITSDONE; + } + + scsi_done(xs); + } + cac_ccb_free(sc, ccb); +} + +/* + * Allocate a CCB. + */ +struct cac_ccb * +cac_ccb_alloc(struct cac_softc *sc, int nosleep) +{ + struct cac_ccb *ccb; + int s; + + s = splbio(); + + for (;;) { + if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) { + SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); + break; + } + if (nosleep) { + ccb = NULL; + break; + } + tsleep(&sc->sc_ccb_free, PRIBIO, "cacccb", 0); + } + + splx(s); + return (ccb); +} + +/* + * Put a CCB onto the freelist. + */ +void +cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb) +{ + int s; + + ccb->ccb_flags = 0; + s = splbio(); + SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain); + if (SIMPLEQ_NEXT(ccb, ccb_chain) == NULL) + wakeup(&sc->sc_ccb_free); + splx(s); +} + +int +cac_get_dinfo(sc, target) + struct cac_softc *sc; + int target; +{ + if (sc->sc_dinfos[target].ncylinders) + return (0); + + if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target], + sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) { + printf("%s: CMD_GET_LOG_DRV_INFO failed\n", + sc->sc_dv.dv_xname); + return (-1); + } + + return (0); +} + +void +cacminphys(bp) + struct buf *bp; +{ + if (bp->b_bcount > CAC_MAX_XFER) + bp->b_bcount = CAC_MAX_XFER; + minphys(bp); +} + +void +cac_copy_internal_data(xs, v, size) + struct scsi_xfer *xs; + void *v; + size_t size; +{ + size_t copy_cnt; + + if (!xs->datalen) + printf("uio move is not yet supported\n"); + else { + copy_cnt = MIN(size, xs->datalen); + bcopy(v, xs->data, copy_cnt); + } +} + +int +cac_scsi_cmd(xs) + struct scsi_xfer *xs; +{ + struct scsi_link *link = xs->sc_link; + struct cac_softc *sc = link->adapter_softc; + struct cac_drive_info *dinfo; + struct scsi_inquiry_data inq; + struct scsi_sense_data sd; + struct { + struct scsi_mode_header hd; + struct scsi_blk_desc bd; + union scsi_disk_pages dp; + } mpd; + struct scsi_read_cap_data rcd; + u_int8_t target = link->target; + u_int32_t blockno, blockcnt, size; + struct scsi_rw *rw; + struct scsi_rw_big *rwb; + int op, flags, s; + const char *p; + + if (target >= sc->sc_nunits || link->lun != 0) { + xs->error = XS_DRIVER_STUFFUP; + return (COMPLETE); + } + + xs->error = XS_NOERROR; + + switch (xs->cmd->opcode) { + case TEST_UNIT_READY: + case START_STOP: +#if 0 + case VERIFY: +#endif + break; + + case REQUEST_SENSE: + bzero(&sd, sizeof sd); + sd.error_code = 0x70; + sd.segment = 0; + sd.flags = SKEY_NO_SENSE; + *(u_int32_t*)sd.info = htole32(0); + sd.extra_len = 0; + cac_copy_internal_data(xs, &sd, sizeof sd); + break; + + case INQUIRY: + if (cac_get_dinfo(sc, target)) { + xs->error = XS_DRIVER_STUFFUP; + scsi_done(xs); + return (COMPLETE); + } + dinfo = &sc->sc_dinfos[target]; + bzero(&inq, sizeof inq); + inq.device = T_DIRECT; + inq.dev_qual2 = 0; + inq.version = 2; + inq.response_format = 2; + inq.additional_length = 32; + strcpy(inq.vendor, "Compaq "); + switch (CAC_GET1(dinfo->mirror)) { + case 0: p = "RAID0"; break; + case 1: p = "RAID4"; break; + case 2: p = "RAID1"; break; + case 3: p = "RAID5"; break; + default:p = "<UNK>"; break; + } + sprintf(inq.product, "%s volume #%02d", p, target); + strcpy(inq.revision, " "); + cac_copy_internal_data(xs, &inq, sizeof inq); + break; + + case MODE_SENSE: + if (cac_get_dinfo(sc, target)) { + xs->error = XS_DRIVER_STUFFUP; + scsi_done(xs); + return (COMPLETE); + } + dinfo = &sc->sc_dinfos[target]; + bzero(&mpd, sizeof mpd); + switch (((struct scsi_mode_sense *)xs->cmd)->page) { + case 4: + /* scsi_disk.h says this should be 0x16 */ + mpd.dp.rigid_geometry.pg_length = 0x16; + mpd.hd.data_length = sizeof mpd.hd + sizeof mpd.bd + + mpd.dp.rigid_geometry.pg_length; + mpd.hd.blk_desc_len = sizeof mpd.bd; + + /* XXX */ + mpd.hd.dev_spec = 0; + _lto3b(CAC_SECTOR_SIZE, mpd.bd.blklen); + mpd.dp.rigid_geometry.pg_code = 4; + _lto3b(CAC_GET2(dinfo->ncylinders), + mpd.dp.rigid_geometry.ncyl); + mpd.dp.rigid_geometry.nheads = + CAC_GET1(dinfo->nheads); + cac_copy_internal_data(xs, (u_int8_t *)&mpd, + sizeof mpd); + break; + + default: + printf("%s: mode sense page %d not simulated\n", + sc->sc_dv.dv_xname, + ((struct scsi_mode_sense *)xs->cmd)->page); + xs->error = XS_DRIVER_STUFFUP; + return (TRY_AGAIN_LATER); + } + break; + + case READ_CAPACITY: + if (cac_get_dinfo(sc, target)) { + xs->error = XS_DRIVER_STUFFUP; + scsi_done(xs); + return (COMPLETE); + } + dinfo = &sc->sc_dinfos[target]; + bzero(&rcd, sizeof rcd); + _lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) * + CAC_GET1(dinfo->nsectors), rcd.addr); + _lto4b(CAC_SECTOR_SIZE, rcd.length); + cac_copy_internal_data(xs, &rcd, sizeof rcd); + break; + + case PREVENT_ALLOW: + return (COMPLETE); + + case READ_COMMAND: + case READ_BIG: + case WRITE_COMMAND: + case WRITE_BIG: + case SYNCHRONIZE_CACHE: + s = splbio(); + + flags = 0; + if (xs->cmd->opcode != SYNCHRONIZE_CACHE) { + /* A read or write operation. */ + if (xs->cmdlen == 6) { + rw = (struct scsi_rw *)xs->cmd; + blockno = _3btol(rw->addr) & + (SRW_TOPADDR << 16 | 0xffff); + blockcnt = rw->length ? rw->length : 0x100; + } else { + rwb = (struct scsi_rw_big *)xs->cmd; + blockno = _4btol(rwb->addr); + blockcnt = _2btol(rwb->length); + } + size = CAC_GET2(dinfo->ncylinders) * + CAC_GET1(dinfo->nheads) * + CAC_GET1(dinfo->nsectors); + if (blockno >= size || blockno + blockcnt > size) { + splx(s); + printf("%s: out of bounds %u-%u >= %u\n", + sc->sc_dv.dv_xname, blockno, blockcnt, + size); + xs->error = XS_DRIVER_STUFFUP; + scsi_done(xs); + return (COMPLETE); + } + } + + switch (xs->cmd->opcode) { + case READ_COMMAND: + case READ_BIG: + op = CAC_CMD_READ; + flags = CAC_CCB_DATA_IN; + break; + case WRITE_COMMAND: + case WRITE_BIG: + op = CAC_CMD_WRITE; + flags = CAC_CCB_DATA_OUT; + break; + } + + if (cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE, target, + blockno, flags, xs)) { + + splx(s); + if (xs->flags & SCSI_POLL) { + xs->error = XS_TIMEOUT; + return (TRY_AGAIN_LATER); + } else { + xs->error = XS_DRIVER_STUFFUP; + scsi_done(xs); + return (COMPLETE); + } + } + + splx(s); + + if (xs->flags & SCSI_POLL) + return (COMPLETE); + else + return (SUCCESSFULLY_QUEUED); + + default: + xs->error = XS_DRIVER_STUFFUP; + } + + return (COMPLETE); +} + +/* + * Board specific linkage shared between multiple bus types. + */ + +int +cac_l0_fifo_full(struct cac_softc *sc) +{ + + return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0); +} + +void +cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb) +{ +#ifdef CAC_DEBUG + printf("submit-%x ", ccb->ccb_paddr); +#endif + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr); +} + +struct cac_ccb * +cac_l0_completed(sc) + struct cac_softc *sc; +{ + struct cac_ccb *ccb; + paddr_t off; + + if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO))) + return NULL; +#ifdef CAC_DEBUG + printf("compl-%x ", off); +#endif + ccb = (struct cac_ccb *)(sc->sc_ccbs + + ((off & ~3) - sc->sc_ccbs_paddr)); + + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); + + return (ccb); +} + +int +cac_l0_intr_pending(struct cac_softc *sc) +{ + + return (cac_inl(sc, CAC_REG_INTR_PENDING)); +} + +void +cac_l0_intr_enable(struct cac_softc *sc, int state) +{ + + cac_outl(sc, CAC_REG_INTR_MASK, + state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE); +} diff --git a/sys/dev/ic/cacreg.h b/sys/dev/ic/cacreg.h new file mode 100644 index 00000000000..ce3c02d935f --- /dev/null +++ b/sys/dev/ic/cacreg.h @@ -0,0 +1,200 @@ +/* $OpenBSD: cacreg.h,v 1.1 2000/12/17 21:35:06 mickey Exp $ */ +/* $NetBSD: cacreg.h,v 1.3 2000/06/13 13:36:47 ad Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Andrew Doran. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1999 Jonathan Lemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _IC_CACREG_H_ +#define _IC_CACREG_H_ + +/* Board register offsets */ +#define CAC_REG_CMD_FIFO 0x04 +#define CAC_REG_DONE_FIFO 0x08 +#define CAC_REG_INTR_MASK 0x0C +#define CAC_REG_STATUS 0x10 +#define CAC_REG_INTR_PENDING 0x14 + +#define CAC_42REG_CMD_FIFO 0x40 +#define CAC_42REG_DONE_FIFO 0x44 +#define CAC_42REG_INTR_MASK 0x34 +#define CAC_42REG_STATUS 0x30 +#define CAC_42REG_INTR_PENDING 0x08 + +#define CAC_EISAREG_INTR_MASK 0x01 +#define CAC_EISAREG_LOCAL_MASK 0x04 +#define CAC_EISAREG_LOCAL_DOORBELL 0x05 +#define CAC_EISAREG_SYSTEM_MASK 0x06 +#define CAC_EISAREG_SYSTEM_DOORBELL 0x07 +#define CAC_EISAREG_LIST_ADDR 0x08 +#define CAC_EISAREG_LIST_LEN 0x0c +#define CAC_EISAREG_TAG 0x0f +#define CAC_EISAREG_COMPLETE_ADDR 0x10 +#define CAC_EISAREG_LIST_STATUS 0x16 + +/* EISA channel control */ +#define CAC_EISA_CHANNEL_BUSY 0x01 +#define CAC_EISA_CHANNEL_CLEAR 0x02 + +/* Interrupt mask values */ +#define CAC_INTR_DISABLE 0x00 +#define CAC_INTR_ENABLE 0x01 + +/* Command types */ +#define CAC_CMD_GET_LOG_DRV_INFO 0x10 +#define CAC_CMD_GET_CTRL_INFO 0x11 +#define CAC_CMD_SENSE_DRV_STATUS 0x12 +#define CAC_CMD_START_RECOVERY 0x13 +#define CAC_CMD_GET_PHYS_DRV_INFO 0x15 +#define CAC_CMD_BLINK_DRV_LEDS 0x16 +#define CAC_CMD_SENSE_DRV_LEDS 0x17 +#define CAC_CMD_GET_LOG_DRV_EXT 0x18 +#define CAC_CMD_GET_CTRL_INFO 0x11 +#define CAC_CMD_READ 0x20 +#define CAC_CMD_WRITE 0x30 +#define CAC_CMD_WRITE_MEDIA 0x31 +#define CAC_CMD_GET_CONFIG 0x50 +#define CAC_CMD_SET_CONFIG 0x51 +#define CAC_CMD_START_FIRMWARE 0x99 +#define CAC_CMD_FLUSH_CACHE 0xc2 + +/* Return status codes */ +#define CAC_RET_SOFT_ERROR 0x02 +#define CAC_RET_HARD_ERROR 0x04 +#define CAC_RET_CMD_REJECTED 0x14 + +struct cac_drive_info { + u_int16_t secsize; + u_int32_t secperunit; + u_int16_t ncylinders; + u_int8_t nheads; + u_int8_t signature; + u_int8_t psectors; + u_int16_t wprecomp; + u_int8_t max_acc; + u_int8_t control; + u_int16_t pcylinders; + u_int8_t ptracks; + u_int16_t landing_zone; + u_int8_t nsectors; + u_int8_t checksum; + u_int8_t mirror; +} __attribute__((__packed__)); + +struct cac_controller_info { + u_int8_t num_drvs; + u_int32_t signature; + u_int8_t firm_rev[4]; + u_int8_t rom_rev[4]; + u_int8_t hw_rev; + u_int32_t bb_rev; + u_int32_t drv_present_map; + u_int32_t ext_drv_map; + u_int32_t board_id; + u_int8_t cfg_error; + u_int32_t non_disk_bits; + u_int8_t bad_ram_addr; + u_int8_t cpu_rev; + u_int8_t pdpi_rev; + u_int8_t epic_rev; + u_int8_t wcxc_rev; + u_int8_t marketing_rev; + u_int8_t ctlr_flags; + u_int8_t host_flags; + u_int8_t expand_dis; + u_int8_t scsi_chips; + u_int32_t max_req_blocks; + u_int32_t ctlr_clock; + u_int8_t drvs_per_bus; + u_int16_t big_drv_present_map[8]; + u_int16_t big_ext_drv_map[8]; + u_int16_t big_non_disk_map[8]; + u_int16_t task_flags; + u_int8_t icl_bus; + u_int8_t red_modes; + u_int8_t cur_red_mode; + u_int8_t red_ctlr_stat; + u_int8_t red_fail_reason; + u_int8_t reserved[403]; +} __attribute__((__packed__)); + +struct cac_hdr { + u_int8_t drive; /* logical drive */ + u_int8_t priority; /* block priority */ + u_int16_t size; /* size of request, in words */ +} __attribute__((__packed__)); + +struct cac_req { + u_int16_t next; /* offset of next request */ + u_int8_t command; /* command */ + u_int8_t error; /* return error code */ + u_int32_t blkno; /* block number */ + u_int16_t bcount; /* block count */ + u_int8_t sgcount; /* number of scatter/gather entries */ + u_int8_t reserved; /* reserved */ +} __attribute__((__packed__)); + +struct cac_sgb { + u_int32_t length; /* length of S/G segment */ + u_int32_t addr; /* physical address of block */ +} __attribute__((__packed__)); + +#endif /* !_IC_CACREG_H_ */ diff --git a/sys/dev/ic/cacvar.h b/sys/dev/ic/cacvar.h new file mode 100644 index 00000000000..9c5a2732136 --- /dev/null +++ b/sys/dev/ic/cacvar.h @@ -0,0 +1,124 @@ +/* $OpenBSD: cacvar.h,v 1.1 2000/12/17 21:35:06 mickey Exp $ */ +/* $NetBSD: cacvar.h,v 1.7 2000/10/19 14:28:47 ad Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Andrew Doran. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _IC_CACVAR_H_ +#define _IC_CACVAR_H_ + +#define CAC_MAX_CCBS 20 +#define CAC_MAX_XFER (0xffff * 512) +#define CAC_SG_SIZE 32 +#define CAC_SECTOR_SIZE 512 + +#define cac_inb(sc, port) \ + bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, port) +#define cac_inw(sc, port) \ + bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, port) +#define cac_inl(sc, port) \ + bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, port) +#define cac_outb(sc, port, val) \ + bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, port, val) +#define cac_outw(sc, port, val) \ + bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, port, val) +#define cac_outl(sc, port, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, port, val) + +/* + * Stupid macros to deal with alignment/endianness issues. + */ + +#define CAC_GET1(x) \ + (((u_char *)&(x))[0]) +#define CAC_GET2(x) \ + (((u_char *)&(x))[0] | (((u_char *)&(x))[1] << 8)) +#define CAC_GET4(x) \ + ((((u_char *)&(x))[0] | (((u_char *)&(x))[1] << 8)) | \ + (((u_char *)&(x))[0] << 16 | (((u_char *)&(x))[1] << 24))) + +struct cac_ccb { + /* Data the controller will touch - 276 bytes */ + struct cac_hdr ccb_hdr; + struct cac_req ccb_req; + struct cac_sgb ccb_seg[CAC_SG_SIZE]; + + /* Data the controller won't touch */ + int ccb_flags; + int ccb_datasize; + paddr_t ccb_paddr; + bus_dmamap_t ccb_dmamap_xfer; + SIMPLEQ_ENTRY(cac_ccb) ccb_chain; + struct scsi_xfer *ccb_xs; +}; + +#define CAC_CCB_DATA_IN 0x0001 /* Map describes inbound xfer */ +#define CAC_CCB_DATA_OUT 0x0002 /* Map describes outbound xfer */ +#define CAC_CCB_ACTIVE 0x0004 /* Command submitted to controller */ + +struct cac_softc; + +struct cac_linkage { + struct cac_ccb *(*cl_completed)(struct cac_softc *); + int (*cl_fifo_full)(struct cac_softc *); + void (*cl_intr_enable)(struct cac_softc *, int); + int (*cl_intr_pending)(struct cac_softc *); + void (*cl_submit)(struct cac_softc *, struct cac_ccb *); +}; + +struct cac_softc { + struct device sc_dv; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + bus_dma_tag_t sc_dmat; + bus_dmamap_t sc_dmamap; + int sc_nunits; + void *sc_ih; + struct scsi_link sc_link; + const struct cac_linkage *sc_cl; + caddr_t sc_ccbs; + paddr_t sc_ccbs_paddr; + SIMPLEQ_HEAD(, cac_ccb) sc_ccb_free; + SIMPLEQ_HEAD(, cac_ccb) sc_ccb_queue; + struct cac_drive_info *sc_dinfos; +}; + +int cac_init __P((struct cac_softc *, int)); +int cac_intr __P((void *)); + +extern const struct cac_linkage cac_l0; + +#endif /* !_IC_CACVAR_H_ */ diff --git a/sys/dev/pci/cac_pci.c b/sys/dev/pci/cac_pci.c new file mode 100644 index 00000000000..29b7375f8f0 --- /dev/null +++ b/sys/dev/pci/cac_pci.c @@ -0,0 +1,270 @@ +/* $OpenBSD: cac_pci.c,v 1.1 2000/12/17 21:35:02 mickey Exp $ */ +/* $NetBSD: cac_pci.c,v 1.7 2000/10/19 15:31:20 ad Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Andrew Doran. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * PCI front-end for cac(4) driver. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/queue.h> + +#include <machine/endian.h> +#include <machine/bus.h> + +#include <dev/pci/pcidevs.h> +#include <dev/pci/pcivar.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_disk.h> +#include <scsi/scsiconf.h> + +#include <dev/ic/cacreg.h> +#include <dev/ic/cacvar.h> + +#define PCI_CBIO 0x10 /* Configuration base I/O address */ +#define PCI_CBMA 0x14 /* Configuration base memory address */ + +void cac_pci_attach(struct device *, struct device *, void *); +const struct cac_pci_type *cac_pci_findtype(struct pci_attach_args *); +int cac_pci_match(struct device *, void *, void *); + +struct cac_ccb *cac_pci_l0_completed(struct cac_softc *); +int cac_pci_l0_fifo_full(struct cac_softc *); +void cac_pci_l0_intr_enable(struct cac_softc *, int); +int cac_pci_l0_intr_pending(struct cac_softc *); +void cac_pci_l0_submit(struct cac_softc *, struct cac_ccb *); + +struct cfattach cac_pci_ca = { + sizeof(struct cac_softc), cac_pci_match, cac_pci_attach +}; + +static const struct cac_linkage cac_pci_l0 = { + cac_pci_l0_completed, + cac_pci_l0_fifo_full, + cac_pci_l0_intr_enable, + cac_pci_l0_intr_pending, + cac_pci_l0_submit +}; + +#define CT_STARTFW 0x01 /* Need to start controller firmware */ + +static const +struct cac_pci_type { + int ct_subsysid; + int ct_flags; + const struct cac_linkage *ct_linkage; + char *ct_typestr; +} cac_pci_type[] = { + { 0x40300e11, 0, &cac_l0, "SMART-2/P" }, + { 0x40310e11, 0, &cac_l0, "SMART-2SL" }, + { 0x40320e11, 0, &cac_l0, "Smart Array 3200" }, + { 0x40330e11, 0, &cac_l0, "Smart Array 3100ES" }, + { 0x40340e11, 0, &cac_l0, "Smart Array 221" }, + { 0x40400e11, CT_STARTFW, &cac_pci_l0, "Integrated Array" }, + { 0x40480e11, CT_STARTFW, &cac_pci_l0, "RAID LC2" }, + { 0x40500e11, 0, &cac_pci_l0, "Smart Array 4200" }, + { 0x40510e11, 0, &cac_pci_l0, "Smart Array 4200ES" }, + { 0x40580e11, 0, &cac_pci_l0, "Smart Array 431" }, +}; + +static const +struct cac_pci_product { + u_short cp_vendor; + u_short cp_product; +} cac_pci_product[] = { + { PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_SMART2P }, + { PCI_VENDOR_DEC, PCI_PRODUCT_DEC_CPQ42XX }, + { PCI_VENDOR_SYMBIOS, PCI_PRODUCT_SYMBIOS_1510 }, +}; + +const struct cac_pci_type * +cac_pci_findtype(pa) + struct pci_attach_args *pa; +{ + const struct cac_pci_type *ct; + const struct cac_pci_product *cp; + pcireg_t subsysid; + int i; + + cp = cac_pci_product; + i = 0; + while (i < sizeof(cac_pci_product) / sizeof(cac_pci_product[0])) { + if (PCI_VENDOR(pa->pa_id) == cp->cp_vendor && + PCI_PRODUCT(pa->pa_id) == cp->cp_product) + break; + cp++; + i++; + } + if (i == sizeof(cac_pci_product) / sizeof(cac_pci_product[0])) + return (NULL); + + subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); + ct = cac_pci_type; + i = 0; + while (i < sizeof(cac_pci_type) / sizeof(cac_pci_type[0])) { + if (subsysid == ct->ct_subsysid) + break; + ct++; + i++; + } + if (i == sizeof(cac_pci_type) / sizeof(cac_pci_type[0])) + return (NULL); + + return (ct); +} + +int +cac_pci_match(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + + return (cac_pci_findtype(aux) != NULL); +} + +void +cac_pci_attach(parent, self, aux) + struct device *parent; + struct device *self; + void *aux; +{ + struct pci_attach_args *pa; + const struct cac_pci_type *ct; + struct cac_softc *sc; + pci_chipset_tag_t pc; + pci_intr_handle_t ih; + const char *intrstr; + pcireg_t csr; + + sc = (struct cac_softc *)self; + pa = (struct pci_attach_args *)aux; + pc = pa->pa_pc; + ct = cac_pci_findtype(pa); + + if (pci_mapreg_map(pa, PCI_CBMA, PCI_MAPREG_TYPE_MEM, 0, + &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) + if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, + &sc->sc_iot, &sc->sc_ioh, NULL, NULL)) { + printf(": can't map memory or i/o space\n"); + return; + } + + sc->sc_dmat = pa->pa_dmat; + + /* Enable the device. */ + csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); + pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, + csr | PCI_COMMAND_MASTER_ENABLE); + + /* Map and establish the interrupt. */ + if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin, + pa->pa_intrline, &ih)) { + printf(": can't map interrupt\n"); + return; + } + intrstr = pci_intr_string(pc, ih); + sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, cac_intr, + sc, sc->sc_dv.dv_xname); + if (sc->sc_ih == NULL) { + printf(": can't establish interrupt"); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + return; + } + + printf(" %s: Compaq %s\n", intrstr, ct->ct_typestr); + + /* Now attach to the bus-independent code. */ + sc->sc_cl = ct->ct_linkage; + cac_init(sc, (ct->ct_flags & CT_STARTFW) != 0); +} + +void +cac_pci_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb) +{ + + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + cac_outl(sc, CAC_42REG_CMD_FIFO, ccb->ccb_paddr); +} + +struct cac_ccb * +cac_pci_l0_completed(struct cac_softc *sc) +{ + struct cac_ccb *ccb; + u_int32_t off; + + if ((off = cac_inl(sc, CAC_42REG_DONE_FIFO)) == 0xffffffffU) + return (NULL); + + cac_outl(sc, CAC_42REG_DONE_FIFO, 0); + off = (off & ~3) - sc->sc_ccbs_paddr; + ccb = (struct cac_ccb *)(sc->sc_ccbs + off); + + bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + + return (ccb); +} + +int +cac_pci_l0_intr_pending(struct cac_softc *sc) +{ + + return (cac_inl(sc, CAC_42REG_INTR_PENDING) & + cac_inl(sc, CAC_42REG_STATUS)); +} + +void +cac_pci_l0_intr_enable(struct cac_softc *sc, int state) +{ + + cac_outl(sc, CAC_42REG_INTR_MASK, (state ? 0 : 8)); /* XXX */ +} + +int +cac_pci_l0_fifo_full(struct cac_softc *sc) +{ + + return (~cac_inl(sc, CAC_42REG_CMD_FIFO)); +} diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index fbe8aa61feb..0f66c73e2e2 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $OpenBSD: files.pci,v 1.86 2000/11/10 09:39:36 niklas Exp $ +# $OpenBSD: files.pci,v 1.87 2000/12/17 21:35:02 mickey Exp $ # $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $ # # Config file and device description for machine-independent PCI code. @@ -111,6 +111,10 @@ attach aac at pci with aac_pci file dev/pci/aac_pci.c aac_pci file dev/ic/aac.c aac +# Compaq Array Controllers +attach cac at pci with cac_pci +file dev/pci/cac_pci.c cac_pci + # Qlogic ISP 10x0 (PCI) family # device declaration in sys/conf/files attach isp at pci with isp_pci |