summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Shalayeff <mickey@cvs.openbsd.org>2000-12-17 21:35:07 +0000
committerMichael Shalayeff <mickey@cvs.openbsd.org>2000-12-17 21:35:07 +0000
commit4a84265eb1253bc6abfb8acb6293c52e6b80b16d (patch)
tree89fa3c7b36c364292ff859a11cfd0dcdfb9d8f77
parent21735d7d8a0901a2129a1e8d27c76cbbc178054f (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/GENERIC5
-rw-r--r--sys/arch/i386/conf/RAMDISKB5
-rw-r--r--sys/arch/i386/conf/RAMDISK_CD5
-rw-r--r--sys/conf/files6
-rw-r--r--sys/dev/eisa/cac_eisa.c306
-rw-r--r--sys/dev/eisa/files.eisa6
-rw-r--r--sys/dev/ic/cac.c826
-rw-r--r--sys/dev/ic/cacreg.h200
-rw-r--r--sys/dev/ic/cacvar.h124
-rw-r--r--sys/dev/pci/cac_pci.c270
-rw-r--r--sys/dev/pci/files.pci6
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