summaryrefslogtreecommitdiff
path: root/sys/arch/i386/isa
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1996-10-04 02:51:26 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1996-10-04 02:51:26 +0000
commit3caed03f1967bf8dce8538bde32da448348f47ba (patch)
treed97990d7d1adee8969b376530c57005dd59d69e6 /sys/arch/i386/isa
parenta65bbb3b55639ef8c3322b01be268ce9f1a7e7b2 (diff)
ahc on eisa, netbsd
Diffstat (limited to 'sys/arch/i386/isa')
-rw-r--r--sys/arch/i386/isa/ahc_isa.c462
1 files changed, 462 insertions, 0 deletions
diff --git a/sys/arch/i386/isa/ahc_isa.c b/sys/arch/i386/isa/ahc_isa.c
new file mode 100644
index 00000000000..3efe4ec3827
--- /dev/null
+++ b/sys/arch/i386/isa/ahc_isa.c
@@ -0,0 +1,462 @@
+/* $OpenBSD: ahc_isa.c,v 1.1 1996/10/04 02:51:20 deraadt Exp $ */
+/* $NetBSD: ahc_isa.c,v 1.1 1996/08/05 21:14:29 soda Exp $ */
+
+/*
+ * Product specific probe and attach routines for:
+ * 284X VLbus SCSI controllers
+ *
+ * Copyright (c) 1996 Jason R. Thorpe.
+ * All rights reserved.
+ *
+ * Copyright (c) 1995, 1996 Christopher G. Demetriou.
+ * All rights reserved.
+ *
+ * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
+ * 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 immediately at the beginning of the file, without modification,
+ * 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 Christopher G. Demetriou
+ * for the NetBSD Project.
+ * 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 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.
+ */
+
+/*
+ * This front-end driver is really sort of a hack. The AHA-284X likes
+ * to masquerade as an EISA device. However, on VLbus machines with
+ * no EISA signature in the BIOS, the EISA bus will never be scanned.
+ * This is intended to catch the 284X controllers on those systems
+ * by looking in "EISA i/o space" for 284X controllers.
+ *
+ * This relies heavily on i/o port accounting. We also just use the
+ * EISA macros for everything ... it's a real waste to redefine them.
+ *
+ * Note: there isn't any #ifdef for FreeBSD in this file, since the
+ * FreeBSD EISA driver handles all cases of the 284X.
+ *
+ * -- Jason R. Thorpe <thorpej@NetBSD.ORG>
+ * July 12, 1996
+ *
+ * TODO: some code could be shared with ahc_eisa.c, but it would probably
+ * be a logistical mightmare to even try.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#include <dev/isa/isavar.h>
+
+#include <dev/eisa/eisareg.h>
+#include <dev/eisa/eisavar.h>
+#include <dev/eisa/eisadevs.h>
+
+#include <dev/ic/aic7xxxreg.h>
+#include <dev/ic/aic7xxxvar.h>
+
+/* IO port address setting range as EISA slot number */
+#define AHC_ISA_MIN_SLOT 0x1 /* from iobase = 0x1c00 */
+#define AHC_ISA_MAX_SLOT 0xe /* to iobase = 0xec00 */
+
+#define AHC_ISA_SLOT_OFFSET 0xc00 /* offset from EISA IO space */
+#define AHC_ISA_IOSIZE 0x100
+
+/*
+ * I/O port offsets
+ */
+#define INTDEF 0x5cul /* Interrupt Definition Register */
+#define AHC_ISA_VID (EISA_SLOTOFF_VID - AHC_ISA_SLOT_OFFSET)
+#define AHC_ISA_PID (EISA_SLOTOFF_PID - AHC_ISA_SLOT_OFFSET)
+#define AHC_ISA_PRIMING AHC_ISA_VID /* enable vendor/product ID */
+
+/*
+ * AHC_ISA_PRIMING register values (write)
+ */
+#define AHC_ISA_PRIMING_VID(index) (AHC_ISA_VID + (index))
+#define AHC_ISA_PRIMING_PID(index) (AHC_ISA_PID + (index))
+
+int ahc_isa_irq __P((bus_chipset_tag_t, bus_io_handle_t));
+int ahc_isa_idstring __P((bus_chipset_tag_t, bus_io_handle_t, char *));
+int ahc_isa_match __P((struct isa_attach_args *, bus_io_addr_t));
+
+int ahc_isa_probe __P((struct device *, void *, void *));
+void ahc_isa_attach __P((struct device *, struct device *, void *));
+
+struct cfattach ahc_isa_ca = {
+ sizeof(struct ahc_data), ahc_isa_probe, ahc_isa_attach
+};
+
+/*
+ * This keeps track of which slots are to be checked next if the
+ * iobase locator is a wildcard. A simple static variable isn't enough,
+ * since it's conceivable that a system might have more than one ISA
+ * bus.
+ *
+ * The "bus" member is the unit number of the parent ISA bus, e.g. "0"
+ * for "isa0".
+ */
+struct ahc_isa_slot {
+ LIST_ENTRY(ahc_isa_slot) link;
+ int bus;
+ int slot;
+};
+static LIST_HEAD(, ahc_isa_slot) ahc_isa_all_slots;
+static int ahc_isa_slot_initialized;
+
+/*
+ * Return irq setting of the board, otherwise -1.
+ */
+int
+ahc_isa_irq(bc, ioh)
+ bus_chipset_tag_t bc;
+ bus_io_handle_t ioh;
+{
+ int irq;
+ u_char intdef;
+
+ ahc_reset("ahc_isa", bc, ioh);
+ intdef = bus_io_read_1(bc, ioh, INTDEF);
+ switch (irq = (intdef & 0xf)) {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ break;
+ default:
+ printf("ahc_isa_irq: illegal irq setting %d\n", intdef);
+ return -1;
+ }
+
+ /* Note that we are going and return (to probe) */
+ return irq;
+}
+
+int
+ahc_isa_idstring(bc, ioh, idstring)
+ bus_chipset_tag_t bc;
+ bus_io_handle_t ioh;
+ char *idstring;
+{
+ u_int8_t vid[EISA_NVIDREGS], pid[EISA_NPIDREGS];
+ int i;
+
+ /* Get the vendor ID bytes */
+ for (i = 0; i < EISA_NVIDREGS; i++) {
+ bus_io_write_1(bc, ioh, AHC_ISA_PRIMING,
+ AHC_ISA_PRIMING_VID(i));
+ vid[i] = bus_io_read_1(bc, ioh, AHC_ISA_VID + i);
+ }
+
+ /* Check for device existence */
+ if (EISA_VENDID_NODEV(vid)) {
+#if 0
+ printf("ahc_isa_idstring: no device at 0x%lx\n",
+ ioh); /* XXX knows about ioh guts */
+ printf("\t(0x%x, 0x%x)\n", vid[0], vid[1]);
+#endif
+ return (0);
+ }
+
+ /* And check that the firmware didn't biff something badly */
+ if (EISA_VENDID_IDDELAY(vid)) {
+ printf("ahc_isa_idstring: BIOS biffed it at 0x%lx\n",
+ ioh); /* XXX knows about ioh guts */
+ return (0);
+ }
+
+ /* Get the product ID bytes */
+ for (i = 0; i < EISA_NPIDREGS; i++) {
+ bus_io_write_1(bc, ioh, AHC_ISA_PRIMING,
+ AHC_ISA_PRIMING_PID(i));
+ pid[i] = bus_io_read_1(bc, ioh, AHC_ISA_PID + i);
+ }
+
+ /* Create the ID string from the vendor and product IDs */
+ idstring[0] = EISA_VENDID_0(vid);
+ idstring[1] = EISA_VENDID_1(vid);
+ idstring[2] = EISA_VENDID_2(vid);
+ idstring[3] = EISA_PRODID_0(pid);
+ idstring[4] = EISA_PRODID_1(pid);
+ idstring[5] = EISA_PRODID_2(pid);
+ idstring[6] = EISA_PRODID_3(pid);
+ idstring[7] = '\0'; /* sanity */
+
+ return (1);
+}
+
+int
+ahc_isa_match(ia, iobase)
+ struct isa_attach_args *ia;
+ bus_io_addr_t iobase;
+{
+ bus_chipset_tag_t bc = ia->ia_bc;
+ bus_io_handle_t ioh;
+ int irq;
+ char idstring[EISA_IDSTRINGLEN];
+
+ /*
+ * Get a mapping for the while slot-specific address
+ * space. If we can't, assume nothing's there, but
+ * warn about it.
+ */
+ if (bus_io_map(bc, iobase, AHC_ISA_IOSIZE, &ioh)) {
+#if 0
+ /*
+ * Don't print anything out here, since this could
+ * be common on machines configured to look for
+ * ahc_eisa and ahc_isa.
+ */
+ printf("ahc_isa_match: can't map I/O space for 0x%x\n",
+ iobase);
+#endif
+ return (0);
+ }
+
+ if (!ahc_isa_idstring(bc, ioh, idstring))
+ irq = -1; /* cannot get the ID string */
+ else if (strcmp(idstring, "ADP7756") &&
+ strcmp(idstring, "ADP7757"))
+ irq = -1; /* unknown ID strings */
+ else
+ irq = ahc_isa_irq(bc, ioh);
+
+ bus_io_unmap(bc, ioh, AHC_ISA_IOSIZE);
+
+ if (irq < 0)
+ return (0);
+
+ if (ia->ia_irq != IRQUNK &&
+ ia->ia_irq != irq) {
+ printf("ahc_isa_match: irq mismatch (kernel %d, card %d)\n",
+ ia->ia_irq, irq);
+ return (0);
+ }
+
+ /* We have a match */
+ ia->ia_iobase = iobase;
+ ia->ia_irq = irq;
+ ia->ia_iosize = AHC_ISA_IOSIZE;
+ ia->ia_msize = 0;
+ return (1);
+}
+
+/*
+ * Check the slots looking for a board we recognise
+ * If we find one, note it's address (slot) and call
+ * the actual probe routine to check it out.
+ */
+int
+ahc_isa_probe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct isa_attach_args *ia = aux;
+ struct ahc_isa_slot *as;
+
+ if (ahc_isa_slot_initialized == 0) {
+ LIST_INIT(&ahc_isa_all_slots);
+ ahc_isa_slot_initialized = 1;
+ }
+
+ if (ia->ia_iobase != IOBASEUNK)
+ return (ahc_isa_match(ia, ia->ia_iobase));
+
+ /*
+ * Find this bus's state. If we don't yet have a slot
+ * marker, allocate and initialize one.
+ */
+ for (as = ahc_isa_all_slots.lh_first; as != NULL;
+ as = as->link.le_next)
+ if (as->bus == parent->dv_unit)
+ goto found_slot_marker;
+
+ /*
+ * Don't have one, so make one.
+ */
+ as = (struct ahc_isa_slot *)
+ malloc(sizeof(struct ahc_isa_slot), M_DEVBUF, M_NOWAIT);
+ if (as == NULL)
+ panic("ahc_isa_probe: can't allocate slot marker");
+
+ as->bus = parent->dv_unit;
+ as->slot = AHC_ISA_MIN_SLOT;
+ LIST_INSERT_HEAD(&ahc_isa_all_slots, as, link);
+
+ found_slot_marker:
+
+ for (; as->slot <= AHC_ISA_MAX_SLOT; as->slot++) {
+ if (ahc_isa_match(ia, EISA_SLOT_ADDR(as->slot) +
+ AHC_ISA_SLOT_OFFSET)) {
+ as->slot++; /* next slot to search */
+ return (1);
+ }
+ }
+
+ /* No matching cards were found. */
+ return (0);
+}
+
+void
+ahc_isa_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ ahc_type type;
+ struct ahc_data *ahc = (void *)self;
+ struct isa_attach_args *ia = aux;
+ bus_chipset_tag_t bc = ia->ia_bc;
+ bus_io_handle_t ioh;
+ int irq;
+ char idstring[EISA_IDSTRINGLEN];
+ const char *model;
+
+ if (bus_io_map(bc, ia->ia_iobase, ia->ia_iosize, &ioh))
+ panic("ahc_isa_attach: could not map slot I/O addresses");
+ if (!ahc_isa_idstring(bc, ioh, idstring))
+ panic("ahc_isa_attach: could not read ID string");
+ if ((irq = ahc_isa_irq(bc, ioh)) < 0)
+ panic("ahc_isa_attach: ahc_isa_irq failed!");
+
+ if (strcmp(idstring, "ADP7756") == 0) {
+ model = EISA_PRODUCT_ADP7756;
+ type = AHC_284;
+ } else if (strcmp(idstring, "ADP7757") == 0) {
+ model = EISA_PRODUCT_ADP7757;
+ type = AHC_284;
+ } else {
+ panic("ahc_isa_attach: Unknown device type %s\n", idstring);
+ }
+ printf(": %s\n", model);
+
+ ahc_construct(ahc, bc, ioh, type, AHC_FNONE);
+
+ /*
+ * Tell the user what type of interrupts we're using.
+ * usefull for debugging irq problems
+ */
+ printf( "%s: Using %s Interrupts\n", ahc_name(ahc),
+ ahc->pause & IRQMS ? "Level Sensitive" : "Edge Triggered");
+
+ /*
+ * Now that we know we own the resources we need, do the
+ * card initialization.
+ *
+ * First, the aic7770 card specific setup.
+ */
+
+ /* XXX
+ * On AHA-284x,
+ * all values are automagically intialized at
+ * POST for these cards, so we can always rely
+ * on the Scratch Ram values. However, we should
+ * read the SEEPROM here (Dan has the code to do
+ * it) so we can say what kind of translation the
+ * BIOS is using. Printing out the geometry could
+ * save a lot of users the grief of failed installs.
+ */
+
+ /*
+ * See if we have a Rev E or higher aic7770. Anything below a
+ * Rev E will have a R/O autoflush disable configuration bit.
+ * It's still not clear exactly what is differenent about the Rev E.
+ * We think it allows 8 bit entries in the QOUTFIFO to support
+ * "paging" SCBs so you can have more than 4 commands active at
+ * once.
+ */
+ {
+ char *id_string;
+ u_char sblkctl;
+ u_char sblkctl_orig;
+
+ sblkctl_orig = AHC_INB(ahc, SBLKCTL);
+ sblkctl = sblkctl_orig ^ AUTOFLUSHDIS;
+ AHC_OUTB(ahc, SBLKCTL, sblkctl);
+ sblkctl = AHC_INB(ahc, SBLKCTL);
+ if(sblkctl != sblkctl_orig)
+ {
+ id_string = "aic7770 >= Rev E, ";
+ /*
+ * Ensure autoflush is enabled
+ */
+ sblkctl &= ~AUTOFLUSHDIS;
+ AHC_OUTB(ahc, SBLKCTL, sblkctl);
+
+ /* Allow paging on this adapter */
+ ahc->flags |= AHC_PAGESCBS;
+ }
+ else
+ id_string = "aic7770 <= Rev C, ";
+
+ printf("%s: %s", ahc_name(ahc), id_string);
+ }
+
+ /* Setup the FIFO threshold and the bus off time */
+ {
+ u_char hostconf = AHC_INB(ahc, HOSTCONF);
+ AHC_OUTB(ahc, BUSSPD, hostconf & DFTHRSH);
+ AHC_OUTB(ahc, BUSTIME, (hostconf << 2) & BOFF);
+ }
+
+ /*
+ * Generic aic7xxx initialization.
+ */
+ if(ahc_init(ahc)){
+ ahc_free(ahc);
+ return;
+ }
+
+ /*
+ * Enable the board's BUS drivers
+ */
+ AHC_OUTB(ahc, BCTL, ENABLE);
+
+ /*
+ * The IRQMS bit enables level sensitive interrupts only allow
+ * IRQ sharing if its set.
+ */
+ ahc->sc_ih = isa_intr_establish(ia->ia_ic, irq,
+ ahc->pause & IRQMS ? IST_LEVEL : IST_EDGE, IPL_BIO, ahc_intr,
+ ahc, ahc->sc_dev.dv_xname);
+ if (ahc->sc_ih == NULL) {
+ printf("%s: couldn't establish interrupt\n",
+ ahc->sc_dev.dv_xname);
+ ahc_free(ahc);
+ return;
+ }
+
+ /* Attach sub-devices - always succeeds */
+ ahc_attach(ahc);
+}