summaryrefslogtreecommitdiff
path: root/sys/dev/isa/aha.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1996-04-21 22:33:19 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1996-04-21 22:33:19 +0000
commit67d88b0a9910a68bb666b448d2dac29cb4d3d8c2 (patch)
tree967b89f6e07398a22bd8c76d30179b648776542d /sys/dev/isa/aha.c
parentba95d3c1d69cdb251d15a12ebf70f50b0ea2019b (diff)
partial sync with netbsd 960418, more to come
Diffstat (limited to 'sys/dev/isa/aha.c')
-rw-r--r--sys/dev/isa/aha.c1662
1 files changed, 715 insertions, 947 deletions
diff --git a/sys/dev/isa/aha.c b/sys/dev/isa/aha.c
index 4a0bb77f998..d8a95ec3f85 100644
--- a/sys/dev/isa/aha.c
+++ b/sys/dev/isa/aha.c
@@ -1,8 +1,10 @@
-/* $OpenBSD: aha.c,v 1.13 1996/03/20 01:00:35 mickey Exp $ */
-/* $NetBSD: aha1542.c,v 1.55 1995/12/24 02:31:06 mycroft Exp $ */
+/* $NetBSD: aha.c,v 1.7 1996/04/11 22:27:59 cgd Exp $ */
+
+#define AHADIAG
+#define integrate
/*
- * Copyright (c) 1994 Charles Hannum. All rights reserved.
+ * Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -14,7 +16,7 @@
* 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 Charles Hannum.
+ * This product includes software developed by Charles M. Hannum.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
@@ -45,13 +47,8 @@
* functioning of this software in any circumstances.
*/
-/*
- * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
- */
-
#include <sys/types.h>
#include <sys/param.h>
-#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/errno.h>
@@ -64,99 +61,25 @@
#include <machine/pio.h>
-#include <dev/isa/isavar.h>
-#include <dev/isa/isadmavar.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
+#include <dev/isa/isavar.h>
+#include <dev/isa/isadmavar.h>
+#include <dev/isa/ahareg.h>
+
#ifndef DDB
#define Debugger() panic("should call debugger here (aha1542.c)")
#endif /* ! DDB */
-/* XXX fixme:
- * on i386 at least, xfers to/from user memory
- * cannot be serviced at interrupt time.
- */
-#ifdef i386
-#define VOLATILE_XS(xs) \
- ((xs)->datalen > 0 && (xs)->bp == NULL && \
- ((xs)->flags & SCSI_POLL) == 0)
-#else
-#define VOLATILE_XS(xs) 0
-#endif
-
-#undef TUNE_1542 /* if bus speed check breaks the machine, undefine it */
-
-/************************** board definitions *******************************/
-
-/*
- * I/O Port Interface
- */
-#define AHA_BASE aha->sc_iobase
-#define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */
-#define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */
-#define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */
-
-/*
- * AHA_CTRL_STAT bits (write)
- */
-#define AHA_HRST 0x80 /* Hardware reset */
-#define AHA_SRST 0x40 /* Software reset */
-#define AHA_IRST 0x20 /* Interrupt reset */
-#define AHA_SCRST 0x10 /* SCSI bus reset */
-
-/*
- * AHA_CTRL_STAT bits (read)
- */
-#define AHA_STST 0x80 /* Self test in Progress */
-#define AHA_DIAGF 0x40 /* Diagnostic Failure */
-#define AHA_INIT 0x20 /* Mbx Init required */
-#define AHA_IDLE 0x10 /* Host Adapter Idle */
-#define AHA_CDF 0x08 /* cmd/data out port full */
-#define AHA_DF 0x04 /* Data in port full */
-#define AHA_INVDCMD 0x01 /* Invalid command */
-
/*
- * AHA_CMD_DATA bits (write)
- */
-#define AHA_NOP 0x00 /* No operation */
-#define AHA_MBX_INIT 0x01 /* Mbx initialization */
-#define AHA_START_SCSI 0x02 /* start scsi command */
-#define AHA_START_BIOS 0x03 /* start bios command */
-#define AHA_INQUIRE 0x04 /* Adapter Inquiry */
-#define AHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
-#define AHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
-#define AHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */
-#define AHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
-#define AHA_SPEED_SET 0x09 /* set transfer speed */
-#define AHA_DEV_GET 0x0a /* return installed devices */
-#define AHA_CONF_GET 0x0b /* return configuration data */
-#define AHA_TARGET_EN 0x0c /* enable target mode */
-#define AHA_SETUP_GET 0x0d /* return setup data */
-#define AHA_WRITE_CH2 0x1a /* write channel 2 buffer */
-#define AHA_READ_CH2 0x1b /* read channel 2 buffer */
-#define AHA_WRITE_FIFO 0x1c /* write fifo buffer */
-#define AHA_READ_FIFO 0x1d /* read fifo buffer */
-#define AHA_ECHO 0x1e /* Echo command data */
-#define AHA_EXT_BIOS 0x28 /* return extended bios info */
-#define AHA_MBX_ENABLE 0x29 /* enable mail box interface */
-
-/*
- * AHA_INTR_PORT bits (read)
- */
-#define AHA_ANY_INTR 0x80 /* Any interrupt */
-#define AHA_SCRD 0x08 /* SCSI reset detected */
-#define AHA_HACC 0x04 /* Command complete */
-#define AHA_MBOA 0x02 /* MBX out empty */
-#define AHA_MBIF 0x01 /* MBX in full */
-
-/*
- * Mail box defs
+ * Mail box defs etc.
+ * these could be bigger but we need the aha_softc to fit on a single page..
*/
#define AHA_MBX_SIZE 16 /* mail box size */
-#define AHA_CCB_MAX 32 /* store up to 32 CCBs at one time */
-#define CCB_HASH_SIZE 32 /* hash table size for phystokv */
+#define AHA_CCB_MAX 16 /* store up to 32 CCBs at one time */
+#define CCB_HASH_SIZE 16 /* hash table size for phystokv */
#define CCB_HASH_SHIFT 9
#define CCB_HASH(x) ((((long)(x))>>CCB_HASH_SHIFT) & (CCB_HASH_SIZE - 1))
@@ -166,165 +89,15 @@
else \
(wmb)++;
-struct aha_mbx_out {
- u_char cmd;
- u_char ccb_addr[3];
-};
-
-struct aha_mbx_in {
- u_char stat;
- u_char ccb_addr[3];
-};
-
struct aha_mbx {
struct aha_mbx_out mbo[AHA_MBX_SIZE];
struct aha_mbx_in mbi[AHA_MBX_SIZE];
+ struct aha_mbx_out *cmbo; /* Collection Mail Box out */
struct aha_mbx_out *tmbo; /* Target Mail Box out */
struct aha_mbx_in *tmbi; /* Target Mail Box in */
};
-/*
- * mbo.cmd values
- */
-#define AHA_MBO_FREE 0x0 /* MBO entry is free */
-#define AHA_MBO_START 0x1 /* MBO activate entry */
-#define AHA_MBO_ABORT 0x2 /* MBO abort entry */
-
-/*
- * mbi.stat values
- */
-#define AHA_MBI_FREE 0x0 /* MBI entry is free */
-#define AHA_MBI_OK 0x1 /* completed without error */
-#define AHA_MBI_ABORT 0x2 /* aborted ccb */
-#define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
-#define AHA_MBI_ERROR 0x4 /* Completed with error */
-
-/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */
-#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */
- /* allow 60 K i/o (min) */
-
-struct aha_ccb {
- u_char opcode;
- u_char lun:3;
- u_char data_in:1; /* must be 0 */
- u_char data_out:1; /* must be 0 */
- u_char target:3;
- u_char scsi_cmd_length;
- u_char req_sense_length;
- u_char data_length[3];
- u_char data_addr[3];
- u_char link_addr[3];
- u_char link_id;
- u_char host_stat;
- u_char target_stat;
- u_char reserved[2];
- struct scsi_generic scsi_cmd;
- struct scsi_sense_data scsi_sense;
- struct aha_scat_gath {
- u_char seg_len[3];
- u_char seg_addr[3];
- } scat_gath[AHA_NSEG];
- /*----------------------------------------------------------------*/
-#define CCB_PHYS_SIZE ((int)&((struct aha_ccb *)0)->chain)
- TAILQ_ENTRY(aha_ccb) chain;
- struct aha_ccb *nexthash;
- struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
- int flags;
-#define CCB_FREE 0
-#define CCB_ACTIVE 1
-#define CCB_ABORTED 2
- struct aha_mbx_out *mbx; /* pointer to mail box */
- struct isadma_seg ccb_phys[1]; /* phys segment of this ccb */
- struct isadma_seg data_phys[AHA_NSEG]; /* phys segments of data */
- int data_nseg; /* number of phys segments of data */
-};
-
-/*
- * opcode fields
- */
-#define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
-#define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */
-#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scatter gather */
-#define AHA_RESET_CCB 0x81 /* SCSI Bus reset */
-
-/*
- * aha_ccb.host_stat values
- */
-#define AHA_OK 0x00 /* cmd ok */
-#define AHA_LINK_OK 0x0a /* Link cmd ok */
-#define AHA_LINK_IT 0x0b /* Link cmd ok + int */
-#define AHA_SEL_TIMEOUT 0x11 /* Selection time out */
-#define AHA_OVER_UNDER 0x12 /* Data over/under run */
-#define AHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */
-#define AHA_INV_BUS 0x14 /* Invalid bus phase/sequence */
-#define AHA_BAD_MBO 0x15 /* Incorrect MBO cmd */
-#define AHA_BAD_CCB 0x16 /* Incorrect ccb opcode */
-#define AHA_BAD_LINK 0x17 /* Not same values of LUN for links */
-#define AHA_INV_TARGET 0x18 /* Invalid target direction */
-#define AHA_CCB_DUP 0x19 /* Duplicate CCB received */
-#define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */
-#define AHA_ABORTED 42
-
-struct aha_setup {
- u_char sync_neg:1;
- u_char parity:1;
- u_char:6;
- u_char speed;
- u_char bus_on;
- u_char bus_off;
- u_char num_mbx;
- u_char mbx[3];
- struct {
- u_char offset:4;
- u_char period:3;
- u_char valid:1;
- } sync[8];
- u_char disc_sts;
-};
-
-struct aha_config {
- u_char chan;
- u_char intr;
- u_char scsi_dev:3;
- u_char:5;
-};
-
-struct aha_inquire {
- u_char boardid; /* type of board */
- /* 0x31 = AHA-1540 */
- /* 0x41 = AHA-1540A/1542A/1542B */
- /* 0x42 = AHA-1640 */
- /* 0x43 = AHA-1542C */
- /* 0x44 = AHA-1542CF */
- /* 0x45 = AHA-1542CF, BIOS v2.01 */
- u_char spec_opts; /* special options ID */
- /* 0x41 = Board is standard model */
- u_char revision_1; /* firmware revision [0-9A-Z] */
- u_char revision_2; /* firmware revision [0-9A-Z] */
-};
-
-struct aha_extbios {
- u_char flags; /* Bit 3 == 1 extended bios enabled */
- u_char mailboxlock; /* mail box lock code to unlock it */
-};
-
-#define INT9 0x01
-#define INT10 0x02
-#define INT11 0x04
-#define INT12 0x08
-#define INT14 0x20
-#define INT15 0x40
-
-#define CHAN0 0x01
-#define CHAN5 0x20
-#define CHAN6 0x40
-#define CHAN7 0x80
-
-/*********************************** end of board definitions***************/
-
-#ifdef AHADEBUG
-int aha_debug = 1;
-#endif /*AHADEBUG */
+#define KVTOPHYS(x) vtophys(x)
struct aha_softc {
struct device sc_dev;
@@ -334,28 +107,40 @@ struct aha_softc {
int sc_iobase;
int sc_irq, sc_drq;
- struct aha_mbx aha_mbx; /* all the mailboxes */
- struct aha_ccb *ccbhash[CCB_HASH_SIZE];
- TAILQ_HEAD(, aha_ccb) free_ccb;
- int numccbs;
- int aha_scsi_dev; /* our scsi id */
+ char sc_model[18],
+ sc_firmware[4];
+
+ struct aha_mbx sc_mbx; /* all the mailboxes */
+#define wmbx (&sc->sc_mbx)
+ struct aha_ccb *sc_ccbhash[CCB_HASH_SIZE];
+ TAILQ_HEAD(, aha_ccb) sc_free_ccb, sc_waiting_ccb;
+ int sc_numccbs, sc_mbofull;
+ int sc_scsi_dev; /* our scsi id */
struct scsi_link sc_link;
};
-int aha_cmd(); /* XXX must be varargs to prototype */
+#ifdef AHADEBUG
+int aha_debug = 1;
+#endif /* AHADEBUG */
+
+int aha_cmd __P((int, struct aha_softc *, int, u_char *, int, u_char *));
+integrate void aha_finish_ccbs __P((struct aha_softc *));
int ahaintr __P((void *));
-void aha_free_ccb __P((struct aha_softc *, struct aha_ccb *, int));
+integrate void aha_reset_ccb __P((struct aha_softc *, struct aha_ccb *));
+void aha_free_ccb __P((struct aha_softc *, struct aha_ccb *));
+integrate void aha_init_ccb __P((struct aha_softc *, struct aha_ccb *));
struct aha_ccb *aha_get_ccb __P((struct aha_softc *, int));
struct aha_ccb *aha_ccb_phys_kv __P((struct aha_softc *, u_long));
-struct aha_mbx_out *aha_send_mbo __P((struct aha_softc *, int, struct aha_ccb *));
+void aha_queue_ccb __P((struct aha_softc *, struct aha_ccb *));
+void aha_collect_mbo __P((struct aha_softc *));
+void aha_start_ccbs __P((struct aha_softc *));
void aha_done __P((struct aha_softc *, struct aha_ccb *));
-int aha_find __P((struct aha_softc *));
+int aha_find __P((struct isa_attach_args *, struct aha_softc *));
void aha_init __P((struct aha_softc *));
+void aha_inquire_setup_information __P((struct aha_softc *));
void ahaminphys __P((struct buf *));
int aha_scsi_cmd __P((struct scsi_xfer *));
int aha_poll __P((struct aha_softc *, struct scsi_xfer *, int));
-int aha_set_bus_speed __P((struct aha_softc *));
-int aha_bus_speed_check __P((struct aha_softc *, int));
void aha_timeout __P((void *arg));
struct scsi_adapter aha_switch = {
@@ -377,64 +162,75 @@ int ahaprobe __P((struct device *, void *, void *));
void ahaattach __P((struct device *, struct device *, void *));
int ahaprint __P((void *, char *));
-struct cfdriver ahacd = {
- NULL, "aha", ahaprobe, ahaattach, DV_DULL, sizeof(struct aha_softc)
+struct cfattach aha_ca = {
+ sizeof(struct aha_softc), ahaprobe, ahaattach
+};
+
+struct cfdriver aha_cd = {
+ NULL, "aha", DV_DULL
};
#define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
+#define AHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
/*
- * aha_cmd(aha,icnt, ocnt,wait, retval, opcode, args)
+ * aha_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)
+ *
* Activate Adapter command
- * icnt: number of args (outbound bytes written after opcode)
+ * icnt: number of args (outbound bytes including opcode)
+ * ibuf: argument buffer
* ocnt: number of expected returned bytes
+ * obuf: result buffer
* wait: number of seconds to wait for response
- * retval: buffer where to place returned bytes
- * opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ...
- * args: parameters
*
- * Performs an adapter command through the ports. Not to be confused
- * with a scsi command, which is read in via the dma. One of the adapter
- * commands tells it to read in a scsi command but that one is done
- * separately. This is only called during set-up.
+ * Performs an adapter command through the ports. Not to be confused with a
+ * scsi command, which is read in via the dma; one of the adapter commands
+ * tells it to read in a scsi command.
*/
int
-aha_cmd(aha, icnt, ocnt, wait, retval, opcode, args)
- struct aha_softc *aha;
- int icnt, ocnt, wait;
- u_char *retval;
- unsigned opcode;
- u_char args;
+aha_cmd(iobase, sc, icnt, ibuf, ocnt, obuf)
+ int iobase;
+ struct aha_softc *sc;
+ int icnt, ocnt;
+ u_char *ibuf, *obuf;
{
- unsigned *ic = &opcode;
- u_char oc;
- register i;
- int sts;
+ const char *name;
+ register int i;
+ int wait;
+ u_char sts;
+ u_char opcode = ibuf[0];
+
+ if (sc == NULL)
+ name = sc->sc_dev.dv_xname;
+ else
+ name = "(probe)";
/*
- * multiply the wait argument by a big constant
- * zero defaults to 1 sec..
- * all wait loops are in 50uSec cycles
+ * Calculate a reasonable timeout for the command.
*/
- if (wait)
- wait *= 20000;
- else
- wait = 20000;
+ switch (opcode) {
+ case AHA_INQUIRE_DEVICES:
+ wait = 15 * 20000;
+ break;
+ default:
+ wait = 1 * 20000;
+ break;
+ }
+
/*
* Wait for the adapter to go idle, unless it's one of
* the commands which don't need this
*/
- if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) {
- i = 20000; /*do this for upto about a second */
- while (--i) {
- sts = inb(AHA_CTRL_STAT_PORT);
- if (sts & AHA_IDLE)
+ if (opcode != AHA_MBO_INTR_EN) {
+ for (i = 20000; i; i--) { /* 1 sec? */
+ sts = inb(iobase + AHA_STAT_PORT);
+ if (sts & AHA_STAT_IDLE)
break;
delay(50);
}
if (!i) {
printf("%s: aha_cmd, host not idle(0x%x)\n",
- aha->sc_dev.dv_xname, sts);
+ name, sts);
return ENXIO;
}
}
@@ -443,71 +239,68 @@ aha_cmd(aha, icnt, ocnt, wait, retval, opcode, args)
* queue feeding to us.
*/
if (ocnt) {
- while ((inb(AHA_CTRL_STAT_PORT)) & AHA_DF)
- inb(AHA_CMD_DATA_PORT);
+ while ((inb(iobase + AHA_STAT_PORT)) & AHA_STAT_DF)
+ inb(iobase + AHA_DATA_PORT);
}
/*
* Output the command and the number of arguments given
* for each byte, first check the port is empty.
*/
- icnt++;
- /* include the command */
while (icnt--) {
- sts = inb(AHA_CTRL_STAT_PORT);
for (i = wait; i; i--) {
- sts = inb(AHA_CTRL_STAT_PORT);
- if (!(sts & AHA_CDF))
+ sts = inb(iobase + AHA_STAT_PORT);
+ if (!(sts & AHA_STAT_CDF))
break;
delay(50);
}
if (!i) {
- if (opcode != AHA_INQUIRE)
- printf("%s: aha_cmd, cmd/data port full\n",
- aha->sc_dev.dv_xname);
- outb(AHA_CTRL_STAT_PORT, AHA_SRST);
+ if (opcode != AHA_INQUIRE_REVISION)
+ printf("%s: aha_cmd, cmd/data port full\n", name);
+ outb(iobase + AHA_CTRL_PORT, AHA_CTRL_SRST);
return ENXIO;
}
- outb(AHA_CMD_DATA_PORT, (u_char) (*ic++));
+ outb(iobase + AHA_CMD_PORT, *ibuf++);
}
/*
* If we expect input, loop that many times, each time,
* looking for the data register to have valid data
*/
while (ocnt--) {
- sts = inb(AHA_CTRL_STAT_PORT);
for (i = wait; i; i--) {
- sts = inb(AHA_CTRL_STAT_PORT);
- if (sts & AHA_DF)
+ sts = inb(iobase + AHA_STAT_PORT);
+ if (sts & AHA_STAT_DF)
break;
delay(50);
}
if (!i) {
- if (opcode != AHA_INQUIRE)
+ if (opcode != AHA_INQUIRE_REVISION)
printf("%s: aha_cmd, cmd/data port empty %d\n",
- aha->sc_dev.dv_xname, ocnt);
- outb(AHA_CTRL_STAT_PORT, AHA_SRST);
+ name, ocnt);
+ outb(iobase + AHA_CTRL_PORT, AHA_CTRL_SRST);
return ENXIO;
}
- oc = inb(AHA_CMD_DATA_PORT);
- if (retval)
- *retval++ = oc;
+ *obuf++ = inb(iobase + AHA_DATA_PORT);
}
/*
- * Wait for the board to report a finised instruction
+ * Wait for the board to report a finished instruction.
+ * We may get an extra interrupt for the HACC signal, but this is
+ * unimportant.
*/
- i = 20000;
- while (--i) {
- sts = inb(AHA_INTR_PORT);
- if (sts & AHA_HACC)
- break;
- delay(50);
- }
- if (!i) {
- printf("%s: aha_cmd, host not finished(0x%x)\n",
- aha->sc_dev.dv_xname, sts);
- return ENXIO;
+ if (opcode != AHA_MBO_INTR_EN) {
+ for (i = 20000; i; i--) { /* 1 sec? */
+ sts = inb(iobase + AHA_INTR_PORT);
+ /* XXX Need to save this in the interrupt handler? */
+ if (sts & AHA_INTR_HACC)
+ break;
+ delay(50);
+ }
+ if (!i) {
+ printf("%s: aha_cmd, host not finished(0x%x)\n",
+ name, sts);
+ return ENXIO;
+ }
}
- outb(AHA_CTRL_STAT_PORT, AHA_IRST);
+ outb(iobase + AHA_CTRL_PORT, AHA_CTRL_IRST);
return 0;
}
@@ -522,43 +315,20 @@ ahaprobe(parent, match, aux)
struct device *parent;
void *match, *aux;
{
- struct aha_softc *aha = match;
- struct isa_attach_args *ia = aux;
+ register struct isa_attach_args *ia = aux;
#ifdef NEWCONFIG
if (ia->ia_iobase == IOBASEUNK)
return 0;
#endif
- aha->sc_iobase = ia->ia_iobase;
-
- /*
- * Try initialise a unit at this location
- * sets up dma and bus speed, loads aha->sc_irq
- */
- if (aha_find(aha) != 0)
+ /* See if there is a unit at this location. */
+ if (aha_find(ia, NULL) != 0)
return 0;
- if (ia->ia_irq != IRQUNK) {
- if (ia->ia_irq != aha->sc_irq) {
- printf("%s: irq mismatch; kernel configured %d != board configured %d\n",
- aha->sc_dev.dv_xname, ia->ia_irq, aha->sc_irq);
- return 0;
- }
- } else
- ia->ia_irq = aha->sc_irq;
-
- if (ia->ia_drq != DRQUNK) {
- if (ia->ia_drq != aha->sc_drq) {
- printf("%s: drq mismatch; kernel configured %d != board configured %d\n",
- aha->sc_dev.dv_xname, ia->ia_drq, aha->sc_drq);
- return 0;
- }
- } else
- ia->ia_drq = aha->sc_drq;
-
ia->ia_msize = 0;
ia->ia_iosize = 4;
+ /* IRQ and DRQ set by aha_find(). */
return 1;
}
@@ -567,6 +337,7 @@ ahaprint(aux, name)
void *aux;
char *name;
{
+
if (name != NULL)
printf("%s: scsibus ", name);
return UNCONF;
@@ -581,274 +352,272 @@ ahaattach(parent, self, aux)
void *aux;
{
struct isa_attach_args *ia = aux;
- struct aha_softc *aha = (void *)self;
+ struct aha_softc *sc = (void *)self;
- if (ia->ia_drq != DRQUNK)
- isadma_cascade(ia->ia_drq);
+ if (aha_find(ia, sc) != 0)
+ panic("ahaattach: aha_find of %s failed", self->dv_xname);
+ sc->sc_iobase = ia->ia_iobase;
- aha_init(aha);
- TAILQ_INIT(&aha->free_ccb);
+ if (sc->sc_drq != DRQUNK)
+ isa_dmacascade(sc->sc_drq);
+
+ aha_inquire_setup_information(sc);
+ aha_init(sc);
+ TAILQ_INIT(&sc->sc_free_ccb);
+ TAILQ_INIT(&sc->sc_waiting_ccb);
/*
* fill in the prototype scsi_link.
*/
- aha->sc_link.adapter_softc = aha;
- aha->sc_link.adapter_target = aha->aha_scsi_dev;
- aha->sc_link.adapter = &aha_switch;
- aha->sc_link.device = &aha_dev;
- aha->sc_link.openings = 2;
-
- printf("\n");
+ sc->sc_link.adapter_softc = sc;
+ sc->sc_link.adapter_target = sc->sc_scsi_dev;
+ sc->sc_link.adapter = &aha_switch;
+ sc->sc_link.device = &aha_dev;
+ sc->sc_link.openings = 2;
#ifdef NEWCONFIG
- isa_establish(&aha->sc_id, &aha->sc_dev);
+ isa_establish(&sc->sc_id, &sc->sc_dev);
#endif
- aha->sc_ih = isa_intr_establish(ia->ia_irq, IST_EDGE, IPL_BIO, ahaintr,
- aha, aha->sc_dev.dv_xname);
+ sc->sc_ih = isa_intr_establish(ia->ia_ic, sc->sc_irq, IST_EDGE,
+ IPL_BIO, ahaintr, sc);
/*
* ask the adapter what subunits are present
*/
- config_found(self, &aha->sc_link, ahaprint);
+ config_found(self, &sc->sc_link, ahaprint);
}
-/*
- * Catch an interrupt from the adaptor
- */
-int
-ahaintr(arg)
- void *arg;
+integrate void
+aha_finish_ccbs(sc)
+ struct aha_softc *sc;
{
- struct aha_softc *aha = arg;
struct aha_mbx_in *wmbi;
- struct aha_mbx *wmbx;
struct aha_ccb *ccb;
- u_char stat;
int i;
- int found = 0;
-#ifdef AHADEBUG
- printf("%s: ahaintr ", aha->sc_dev.dv_xname);
-#endif /*AHADEBUG */
-
- /*
- * First acknowlege the interrupt, Then if it's not telling about
- * a completed operation just return.
- */
- stat = inb(AHA_INTR_PORT);
- if ((stat & (AHA_MBOA | AHA_MBIF)) == 0) {
- outb(AHA_CTRL_STAT_PORT, AHA_IRST);
- return -1; /* XXX */
- }
+ wmbi = wmbx->tmbi;
- /* Mail box out empty? */
- if (stat & AHA_MBOA) {
- /* Disable MBO available interrupt. */
- outb(AHA_CMD_DATA_PORT, AHA_MBO_INTR_EN);
- for (i = 100000; i; i--) {
- if (!(inb(AHA_CTRL_STAT_PORT) & AHA_CDF))
- break;
- delay(10);
- }
- if (!i) {
- printf("%s: ahaintr, cmd/data port full\n",
- aha->sc_dev.dv_xname);
- outb(AHA_CTRL_STAT_PORT, AHA_SRST);
- return 1;
+ if (wmbi->stat == AHA_MBI_FREE) {
+ for (i = 0; i < AHA_MBX_SIZE; i++) {
+ if (wmbi->stat != AHA_MBI_FREE) {
+ printf("%s: mbi not in round-robin order\n",
+ sc->sc_dev.dv_xname);
+ goto AGAIN;
+ }
+ aha_nextmbx(wmbi, wmbx, mbi);
}
- outb(AHA_CMD_DATA_PORT, 0x00); /* Disable */
- wakeup(&aha->aha_mbx);
+#ifdef AHADIAGnot
+ printf("%s: mbi interrupt with no full mailboxes\n",
+ sc->sc_dev.dv_xname);
+#endif
+ return;
}
- /* Mail box in full? */
- if ((stat & AHA_MBIF) == 0)
- return 1;
- wmbx = &aha->aha_mbx;
- wmbi = wmbx->tmbi;
AGAIN:
- while (wmbi->stat != AHA_MBI_FREE) {
- ccb = aha_ccb_phys_kv(aha, _3btol(wmbi->ccb_addr));
+ do {
+ ccb = aha_ccb_phys_kv(sc, phystol(wmbi->ccb_addr));
if (!ccb) {
- wmbi->stat = AHA_MBI_FREE;
- printf("%s: BAD CCB ADDR!\n", aha->sc_dev.dv_xname);
- continue;
+ printf("%s: bad mbi ccb pointer; skipping\n",
+ sc->sc_dev.dv_xname);
+ goto next;
}
- found++;
+
+#ifdef AHADEBUG
+ if (aha_debug) {
+ u_char *cp = &ccb->scsi_cmd;
+ printf("op=%x %x %x %x %x %x\n",
+ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+ printf("stat %x for mbi addr = 0x%08x, ",
+ wmbi->stat, wmbi);
+ printf("ccb addr = 0x%x\n", ccb);
+ }
+#endif /* AHADEBUG */
+
switch (wmbi->stat) {
case AHA_MBI_OK:
case AHA_MBI_ERROR:
+ if ((ccb->flags & CCB_ABORT) != 0) {
+ /*
+ * If we already started an abort, wait for it
+ * to complete before clearing the CCB. We
+ * could instead just clear CCB_SENDING, but
+ * what if the mailbox was already received?
+ * The worst that happens here is that we clear
+ * the CCB a bit later than we need to. BFD.
+ */
+ goto next;
+ }
break;
case AHA_MBI_ABORT:
- ccb->host_stat = AHA_ABORTED;
- break;
-
case AHA_MBI_UNKNOWN:
- ccb = 0;
+ /*
+ * Even if the CCB wasn't found, we clear it anyway.
+ * See preceeding comment.
+ */
break;
default:
- panic("Impossible mbxi status");
- }
-#ifdef AHADEBUG
- if (aha_debug && ccb) {
- u_char *cp = &ccb->scsi_cmd;
- printf("op=%x %x %x %x %x %x\n",
- cp[0], cp[1], cp[2],
- cp[3], cp[4], cp[5]);
- printf("stat %x for mbi addr = 0x%08x, ",
- wmbi->stat, wmbi);
- printf("ccb addr = 0x%x\n", ccb);
+ printf("%s: bad mbi status %02x; skipping\n",
+ sc->sc_dev.dv_xname, wmbi->stat);
+ goto next;
}
-#endif /* AHADEBUG */
+
+ untimeout(aha_timeout, ccb);
+ aha_done(sc, ccb);
+
+ next:
wmbi->stat = AHA_MBI_FREE;
- if (ccb) {
- untimeout(aha_timeout, ccb);
- aha_done(aha, ccb);
- }
aha_nextmbx(wmbi, wmbx, mbi);
- }
- if (!found) {
- for (i = 0; i < AHA_MBX_SIZE; i++) {
- if (wmbi->stat != AHA_MBI_FREE) {
- found++;
- break;
- }
- aha_nextmbx(wmbi, wmbx, mbi);
- }
- if (!found) {
-#if 0
- printf("%s: mbi interrupt with no full mailboxes\n",
- aha->sc_dev.dv_xname);
+ } while (wmbi->stat != AHA_MBI_FREE);
+
+ wmbx->tmbi = wmbi;
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+int
+ahaintr(arg)
+ void *arg;
+{
+ struct aha_softc *sc = arg;
+ int iobase = sc->sc_iobase;
+ u_char sts;
+
+#ifdef AHADEBUG
+ printf("%s: ahaintr ", sc->sc_dev.dv_xname);
+#endif /*AHADEBUG */
+
+ /*
+ * First acknowlege the interrupt, Then if it's not telling about
+ * a completed operation just return.
+ */
+ sts = inb(iobase + AHA_INTR_PORT);
+ if ((sts & AHA_INTR_ANYINTR) == 0)
+ return 0;
+ outb(iobase + AHA_CTRL_PORT, AHA_CTRL_IRST);
+
+#ifdef AHADIAG
+ /* Make sure we clear CCB_SENDING before finishing a CCB. */
+ aha_collect_mbo(sc);
#endif
- } else {
- found = 0;
- goto AGAIN;
- }
+
+ /* Mail box out empty? */
+ if (sts & AHA_INTR_MBOA) {
+ struct aha_toggle toggle;
+
+ toggle.cmd.opcode = AHA_MBO_INTR_EN;
+ toggle.cmd.enable = 0;
+ aha_cmd(iobase, sc, sizeof(toggle.cmd), (u_char *)&toggle.cmd, 0,
+ (u_char *)0);
+ aha_start_ccbs(sc);
}
- wmbx->tmbi = wmbi;
- outb(AHA_CTRL_STAT_PORT, AHA_IRST);
+
+ /* Mail box in full? */
+ if (sts & AHA_INTR_MBIF)
+ aha_finish_ccbs(sc);
+
return 1;
}
+integrate void
+aha_reset_ccb(sc, ccb)
+ struct aha_softc *sc;
+ struct aha_ccb *ccb;
+{
+
+ ccb->flags = 0;
+}
+
/*
- * A ccb (and hence a mbx-out is put onto the
- * free list.
+ * A ccb is put onto the free list.
*/
void
-aha_free_ccb(aha, ccb, flags)
- struct aha_softc *aha;
+aha_free_ccb(sc, ccb)
+ struct aha_softc *sc;
struct aha_ccb *ccb;
- int flags;
{
- int s, hashnum;
- struct aha_ccb **hashccb;
+ int s;
s = splbio();
- if (ccb->ccb_phys[0].addr)
- isadma_unmap((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);
-
- /* remove from hash table */
-
- hashnum = CCB_HASH(ccb->ccb_phys[0].addr);
- hashccb = &aha->ccbhash[hashnum];
-
- while (*hashccb) {
- if ((*hashccb)->ccb_phys[0].addr == ccb->ccb_phys[0].addr) {
- *hashccb = (*hashccb)->nexthash;
- break;
- }
- hashccb = &(*hashccb)->nexthash;
- }
-
- ccb->flags = CCB_FREE;
- TAILQ_INSERT_HEAD(&aha->free_ccb, ccb, chain);
+ aha_reset_ccb(sc, ccb);
+ TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);
/*
* If there were none, wake anybody waiting for one to come free,
* starting with queued entries.
*/
if (ccb->chain.tqe_next == 0)
- wakeup(&aha->free_ccb);
+ wakeup(&sc->sc_free_ccb);
splx(s);
}
-static inline void
-aha_init_ccb(aha, ccb)
- struct aha_softc *aha;
- struct aha_ccb *ccb;
-{
- bzero(ccb, sizeof(struct aha_ccb));
-}
-
-static inline void
-aha_reset_ccb(aha, ccb)
- struct aha_softc *aha;
+integrate void
+aha_init_ccb(sc, ccb)
+ struct aha_softc *sc;
struct aha_ccb *ccb;
{
+ int hashnum;
+ bzero(ccb, sizeof(struct aha_ccb));
+ /*
+ * put in the phystokv hash table
+ * Never gets taken out.
+ */
+ ccb->hashkey = KVTOPHYS(ccb);
+ hashnum = CCB_HASH(ccb->hashkey);
+ ccb->nexthash = sc->sc_ccbhash[hashnum];
+ sc->sc_ccbhash[hashnum] = ccb;
+ aha_reset_ccb(sc, ccb);
}
/*
* Get a free ccb
+ *
+ * If there are none, see if we can allocate a new one. If so, put it in
+ * the hash table too otherwise either return an error or sleep.
*/
struct aha_ccb *
-aha_get_ccb(aha, flags)
- struct aha_softc *aha;
+aha_get_ccb(sc, flags)
+ struct aha_softc *sc;
int flags;
{
struct aha_ccb *ccb;
- int hashnum, mflags, s;
+ int s;
s = splbio();
- if (flags & SCSI_NOSLEEP)
- mflags = ISADMA_MAP_BOUNCE;
- else
- mflags = ISADMA_MAP_BOUNCE | ISADMA_MAP_WAITOK;
-
/*
- * If we can and have to, sleep waiting for one
- * to come free
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we can't allocate a new one.
*/
for (;;) {
- ccb = aha->free_ccb.tqh_first;
+ ccb = sc->sc_free_ccb.tqh_first;
if (ccb) {
- TAILQ_REMOVE(&aha->free_ccb, ccb, chain);
+ TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);
break;
}
- if (aha->numccbs < AHA_CCB_MAX) {
- if (ccb = (struct aha_ccb *) malloc(sizeof(struct aha_ccb),
- M_TEMP, M_NOWAIT)) {
- aha_init_ccb(aha, ccb);
- aha->numccbs++;
- } else {
+ if (sc->sc_numccbs < AHA_CCB_MAX) {
+ ccb = (struct aha_ccb *) malloc(sizeof(struct aha_ccb),
+ M_TEMP, M_NOWAIT);
+ if (!ccb) {
printf("%s: can't malloc ccb\n",
- aha->sc_dev.dv_xname);
+ sc->sc_dev.dv_xname);
goto out;
}
+ aha_init_ccb(sc, ccb);
+ sc->sc_numccbs++;
break;
}
if ((flags & SCSI_NOSLEEP) != 0)
goto out;
- tsleep(&aha->free_ccb, PRIBIO, "ahaccb", 0);
+ tsleep(&sc->sc_free_ccb, PRIBIO, "ahaccb", 0);
}
- aha_reset_ccb(aha, ccb);
- ccb->flags = CCB_ACTIVE;
-
- if (isadma_map((caddr_t)ccb, CCB_PHYS_SIZE, ccb->ccb_phys,
- mflags | ISADMA_MAP_CONTIG) == 1) {
- hashnum = CCB_HASH(ccb->ccb_phys[0].addr);
- ccb->nexthash = aha->ccbhash[hashnum];
- aha->ccbhash[hashnum] = ccb;
- } else {
- ccb->ccb_phys[0].addr = 0;
- aha_free_ccb(aha, ccb, flags);
- ccb = 0;
- }
+ ccb->flags |= CCB_ALLOC;
out:
splx(s);
@@ -856,74 +625,116 @@ out:
}
/*
- * given a physical address, find the ccb that it corresponds to.
+ * Given a physical address, find the ccb that it corresponds to.
*/
struct aha_ccb *
-aha_ccb_phys_kv(aha, ccb_phys)
- struct aha_softc *aha;
+aha_ccb_phys_kv(sc, ccb_phys)
+ struct aha_softc *sc;
u_long ccb_phys;
{
int hashnum = CCB_HASH(ccb_phys);
- struct aha_ccb *res = aha->ccbhash[hashnum];
+ struct aha_ccb *ccb = sc->sc_ccbhash[hashnum];
- while (res) {
- if (res->ccb_phys[0].addr == ccb_phys)
+ while (ccb) {
+ if (ccb->hashkey == ccb_phys)
break;
- res = res->nexthash;
+ ccb = ccb->nexthash;
}
+ return ccb;
+}
- return res;
+/*
+ * Queue a CCB to be sent to the controller, and send it if possible.
+ */
+void
+aha_queue_ccb(sc, ccb)
+ struct aha_softc *sc;
+ struct aha_ccb *ccb;
+{
+
+ TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
+ aha_start_ccbs(sc);
}
/*
- * Get a mbo and send the ccb.
+ * Garbage collect mailboxes that are no longer in use.
*/
-struct aha_mbx_out *
-aha_send_mbo(aha, cmd, ccb)
- struct aha_softc *aha;
- int cmd;
+void
+aha_collect_mbo(sc)
+ struct aha_softc *sc;
+{
+ struct aha_mbx_out *wmbo; /* Mail Box Out pointer */
struct aha_ccb *ccb;
+
+ wmbo = wmbx->cmbo;
+
+ while (sc->sc_mbofull > 0) {
+ if (wmbo->cmd != AHA_MBO_FREE)
+ break;
+
+#ifdef AHADIAG
+ ccb = aha_ccb_phys_kv(sc, phystol(wmbo->ccb_addr));
+ ccb->flags &= ~CCB_SENDING;
+#endif
+
+ --sc->sc_mbofull;
+ aha_nextmbx(wmbo, wmbx, mbo);
+ }
+
+ wmbx->cmbo = wmbo;
+}
+
+/*
+ * Send as many CCBs as we have empty mailboxes for.
+ */
+void
+aha_start_ccbs(sc)
+ struct aha_softc *sc;
{
+ int iobase = sc->sc_iobase;
struct aha_mbx_out *wmbo; /* Mail Box Out pointer */
- struct aha_mbx *wmbx; /* Mail Box pointer specified unit */
+ struct aha_ccb *ccb;
int i;
- /* Get the target out mail box pointer and increment. */
- wmbx = &aha->aha_mbx;
wmbo = wmbx->tmbo;
- aha_nextmbx(wmbx->tmbo, wmbx, mbo);
- /*
- * Check the outmail box is free or not.
- * Note: Under the normal operation, it shuld NOT happen to wait.
- */
- while (wmbo->cmd != AHA_MBO_FREE) {
- /* Enable mbo available interrupt. */
- outb(AHA_CMD_DATA_PORT, AHA_MBO_INTR_EN);
- for (i = 100000; i; i--) {
- if (!(inb(AHA_CTRL_STAT_PORT) & AHA_CDF))
+ while (ccb = sc->sc_waiting_ccb.tqh_first) {
+ if (sc->sc_mbofull >= AHA_MBX_SIZE) {
+ aha_collect_mbo(sc);
+ if (sc->sc_mbofull >= AHA_MBX_SIZE) {
+ struct aha_toggle toggle;
+
+ toggle.cmd.opcode = AHA_MBO_INTR_EN;
+ toggle.cmd.enable = 1;
+ aha_cmd(iobase, sc, sizeof(toggle.cmd),
+ (u_char *)&toggle.cmd, 0, (u_char *)0);
break;
- delay(10);
- }
- if (!i) {
- printf("%s: aha_send_mbo, cmd/data port full\n",
- aha->sc_dev.dv_xname);
- outb(AHA_CTRL_STAT_PORT, AHA_SRST);
- return NULL;
+ }
}
- outb(AHA_CMD_DATA_PORT, 0x01); /* Enable */
- tsleep(wmbx, PRIBIO, "ahasnd", 0);/*XXX can't do this */
- }
- /* Link ccb to mbo. */
- lto3b(ccb->ccb_phys[0].addr, wmbo->ccb_addr);
- ccb->mbx = wmbo;
- wmbo->cmd = cmd;
+ TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
+#ifdef AHADIAG
+ ccb->flags |= CCB_SENDING;
+#endif
+
+ /* Link ccb to mbo. */
+ ltophys(KVTOPHYS(ccb), wmbo->ccb_addr);
+ if (ccb->flags & CCB_ABORT)
+ wmbo->cmd = AHA_MBO_ABORT;
+ else
+ wmbo->cmd = AHA_MBO_START;
- /* Sent it! */
- outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
+ /* Tell the card to poll immediately. */
+ outb(iobase + AHA_CMD_PORT, AHA_START_SCSI);
- return wmbo;
+ if ((ccb->xs->flags & SCSI_POLL) == 0)
+ timeout(aha_timeout, ccb, (ccb->timeout * hz) / 1000);
+
+ ++sc->sc_mbofull;
+ aha_nextmbx(wmbo, wmbx, mbo);
+ }
+
+ wmbx->tmbo = wmbo;
}
/*
@@ -932,8 +743,8 @@ aha_send_mbo(aha, cmd, ccb)
* went. Wake up the owner if waiting
*/
void
-aha_done(aha, ccb)
- struct aha_softc *aha;
+aha_done(sc, ccb)
+ struct aha_softc *sc;
struct aha_ccb *ccb;
{
struct scsi_sense_data *s1, *s2;
@@ -944,23 +755,29 @@ aha_done(aha, ccb)
* Otherwise, put the results of the operation
* into the xfer and call whoever started it
*/
- if ((xs->flags & INUSE) == 0) {
- printf("%s: exiting but not in use!\n", aha->sc_dev.dv_xname);
+#ifdef AHADIAG
+ if (ccb->flags & CCB_SENDING) {
+ printf("%s: exiting ccb still in transit!\n", sc->sc_dev.dv_xname);
+ Debugger();
+ return;
+ }
+#endif
+ if ((ccb->flags & CCB_ALLOC) == 0) {
+ printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
Debugger();
+ return;
}
if (xs->error == XS_NOERROR) {
if (ccb->host_stat != AHA_OK) {
switch (ccb->host_stat) {
- case AHA_ABORTED:
- xs->error = XS_DRIVER_STUFFUP;
- break;
case AHA_SEL_TIMEOUT: /* No response */
xs->error = XS_SELTIMEOUT;
break;
default: /* Other scsi protocol messes */
printf("%s: host_stat %x\n",
- aha->sc_dev.dv_xname, ccb->host_stat);
+ sc->sc_dev.dv_xname, ccb->host_stat);
xs->error = XS_DRIVER_STUFFUP;
+ break;
}
} else if (ccb->target_stat != SCSI_OK) {
switch (ccb->target_stat) {
@@ -976,27 +793,15 @@ aha_done(aha, ccb)
break;
default:
printf("%s: target_stat %x\n",
- aha->sc_dev.dv_xname, ccb->target_stat);
+ sc->sc_dev.dv_xname, ccb->target_stat);
xs->error = XS_DRIVER_STUFFUP;
+ break;
}
} else
xs->resid = 0;
}
+ aha_free_ccb(sc, ccb);
xs->flags |= ITSDONE;
-
- if (VOLATILE_XS(xs)) {
- wakeup(ccb);
- return;
- }
-
- if (ccb->data_nseg) {
- if (xs->flags & SCSI_DATA_IN)
- isadma_copyfrombuf(xs->data, xs->datalen,
- ccb->data_nseg, ccb->data_phys);
- isadma_unmap(xs->data, xs->datalen,
- ccb->data_nseg, ccb->data_phys);
- }
- aha_free_ccb(aha, ccb, xs->flags);
scsi_done(xs);
}
@@ -1004,147 +809,108 @@ aha_done(aha, ccb)
* Find the board and find its irq/drq
*/
int
-aha_find(aha)
- struct aha_softc *aha;
+aha_find(ia, sc)
+ struct isa_attach_args *ia;
+ struct aha_softc *sc;
{
- volatile int i, sts;
- struct aha_config conf;
- struct aha_inquire inquire;
- struct aha_extbios extbios;
+ int iobase = ia->ia_iobase;
+ int i;
+ u_char sts;
+ struct aha_config config;
+ int irq, drq;
/*
* reset board, If it doesn't respond, assume
* that it's not there.. good for the probe
*/
- outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST);
+ outb(iobase + AHA_CTRL_PORT, AHA_CTRL_HRST | AHA_CTRL_SRST);
+ delay(100);
for (i = AHA_RESET_TIMEOUT; i; i--) {
- sts = inb(AHA_CTRL_STAT_PORT);
- if (sts == (AHA_IDLE | AHA_INIT))
+ sts = inb(iobase + AHA_STAT_PORT);
+ if (sts == (AHA_STAT_IDLE | AHA_STAT_INIT))
break;
delay(1000); /* calibrated in msec */
}
if (!i) {
-#ifdef AHADEBUG
+#ifdef AHADEBUG
if (aha_debug)
printf("aha_find: No answer from adaptec board\n");
-#endif /*AHADEBUG */
- return ENXIO;
- }
-
- /*
- * Assume we have a board at this stage, do an adapter inquire
- * to find out what type of controller it is. If the command
- * fails, we assume it's either a crusty board or an old 1542
- * clone, and skip the board-specific stuff.
- */
- if (aha_cmd(aha, 0, sizeof(inquire), 1, &inquire, AHA_INQUIRE)) {
- /*
- * aha_cmd() already started the reset. It's not clear we
- * even need to bother here.
- */
- for (i = AHA_RESET_TIMEOUT; i; i--) {
- sts = inb(AHA_CTRL_STAT_PORT);
- if (sts == (AHA_IDLE | AHA_INIT))
- break;
- delay(1000);
- }
- if (!i) {
-#ifdef AHADEBUG
- printf("aha_init: soft reset failed\n");
-#endif /* AHADEBUG */
- return ENXIO;
- }
-#ifdef AHADEBUG
- printf("aha_init: inquire command failed\n");
#endif /* AHADEBUG */
- goto noinquire;
- }
-#ifdef AHADEBUG
- printf("%s: inquire %x, %x, %x, %x\n",
- aha->sc_dev.dv_xname,
- inquire.boardid, inquire.spec_opts,
- inquire.revision_1, inquire.revision_2);
-#endif /* AHADEBUG */
- /*
- * If we are a 1542C or 1542CF disable the extended bios so that the
- * mailbox interface is unlocked.
- * No need to check the extended bios flags as some of the
- * extensions that cause us problems are not flagged in that byte.
- */
- if (inquire.boardid == 0x43 || inquire.boardid == 0x44 ||
- inquire.boardid == 0x45) {
- aha_cmd(aha, 0, sizeof(extbios), 0, &extbios, AHA_EXT_BIOS);
-#ifdef AHADEBUG
- printf("%s: extended bios flags %x\n", aha->sc_dev.dv_xname,
- extbios.flags);
-#endif /* AHADEBUG */
- printf("%s: 1542C/CF detected, unlocking mailbox\n",
- aha->sc_dev.dv_xname);
- aha_cmd(aha, 2, 0, 0, 0, AHA_MBX_ENABLE,
- 0, extbios.mailboxlock);
+ return 1;
}
-noinquire:
/*
* setup dma channel from jumpers and save int
* level
*/
delay(1000); /* for Bustek 545 */
- aha_cmd(aha, 0, sizeof(conf), 0, &conf, AHA_CONF_GET);
- switch (conf.chan) {
+ config.cmd.opcode = AHA_INQUIRE_CONFIG;
+ aha_cmd(iobase, sc, sizeof(config.cmd), (u_char *)&config.cmd,
+ sizeof(config.reply), (u_char *)&config.reply);
+ switch (config.reply.chan) {
+ case EISADMA:
+ drq = DRQUNK; /* for EISA/VLB/PCI clones */
+ break;
case CHAN0:
- aha->sc_drq = 0;
+ drq = 0;
break;
case CHAN5:
- aha->sc_drq = 5;
+ drq = 5;
break;
case CHAN6:
- aha->sc_drq = 6;
+ drq = 6;
break;
case CHAN7:
- aha->sc_drq = 7;
+ drq = 7;
break;
default:
- printf("%s: illegal drq setting %x\n", aha->sc_dev.dv_xname,
- conf.chan);
- return EIO;
+ printf("aha_find: illegal drq setting %x\n", config.reply.chan);
+ return 1;
}
- switch (conf.intr) {
+ switch (config.reply.intr) {
case INT9:
- aha->sc_irq = 9;
+ irq = 9;
break;
case INT10:
- aha->sc_irq = 10;
+ irq = 10;
break;
case INT11:
- aha->sc_irq = 11;
+ irq = 11;
break;
case INT12:
- aha->sc_irq = 12;
+ irq = 12;
break;
case INT14:
- aha->sc_irq = 14;
+ irq = 14;
break;
case INT15:
- aha->sc_irq = 15;
+ irq = 15;
break;
default:
- printf("%s: illegal irq setting %x\n", aha->sc_dev.dv_xname,
- conf.intr);
+ printf("aha_find: illegal irq setting %x\n", config.reply.intr);
return EIO;
}
- /* who are we on the scsi bus? */
- aha->aha_scsi_dev = conf.scsi_dev;
+ if (sc != NULL) {
+ /* who are we on the scsi bus? */
+ sc->sc_scsi_dev = config.reply.scsi_dev;
- /*
- * Change the bus on/off times to not clash with other dma users.
- */
- aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7);
- aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4);
+ sc->sc_iobase = iobase;
+ sc->sc_irq = irq;
+ sc->sc_drq = drq;
+ } else {
+ if (ia->ia_irq == IRQUNK)
+ ia->ia_irq = irq;
+ else if (ia->ia_irq != irq)
+ return 1;
+ if (ia->ia_drq == DRQUNK)
+ ia->ia_drq = drq;
+ else if (ia->ia_drq != drq)
+ return 1;
+ }
return 0;
}
@@ -1153,43 +919,176 @@ noinquire:
* Start the board, ready for normal operation
*/
void
-aha_init(aha)
- struct aha_softc *aha;
+aha_init(sc)
+ struct aha_softc *sc;
{
- u_char ad[3];
- struct isadma_seg mbx_phys[1];
+ int iobase = sc->sc_iobase;
+ struct aha_devices devices;
+ struct aha_setup setup;
+ struct aha_mailbox mailbox;
int i;
-#ifdef TUNE_1542
/*
- * Initialize memory transfer speed
- * Not compiled in by default because it breaks some machines
+ * XXX
+ * If we are a 1542C or later, disable the extended BIOS so that the
+ * mailbox interface is unlocked.
+ * No need to check the extended BIOS flags as some of the
+ * extensions that cause us problems are not flagged in that byte.
*/
- if (!aha_set_bus_speed(aha))
- panic("aha_init: cannot set bus speed");
-#endif /* TUNE_1542 */
+ if (!strncmp(sc->sc_model, "1542C", 5)) {
+ struct aha_extbios extbios;
+ struct aha_unlock unlock;
+
+ printf("%s: unlocking mailbox interface\n", sc->sc_dev.dv_xname);
+ extbios.cmd.opcode = AHA_EXT_BIOS;
+ aha_cmd(iobase, sc, sizeof(extbios.cmd), (u_char *)&extbios.cmd,
+ sizeof(extbios.reply), (u_char *)&extbios.reply);
+
+#ifdef AHADEBUG
+ printf("%s: flags=%02x, mailboxlock=%02x\n",
+ sc->sc_dev.dv_xname,
+ extbios.reply.flags, extbios.reply.mailboxlock);
+#endif /* AHADEBUG */
+ unlock.cmd.opcode = AHA_MBX_ENABLE;
+ unlock.cmd.junk = 0;
+ unlock.cmd.magic = extbios.reply.mailboxlock;
+ aha_cmd(iobase, sc, sizeof(unlock.cmd), (u_char *)&unlock.cmd,
+ 0, (u_char *)0);
+ }
+
+#if 0
/*
- * Initialize mail box. This mapping will never be undone.
+ * Change the bus on/off times to not clash with other dma users.
*/
- if (isadma_map((caddr_t)(&aha->aha_mbx), sizeof(struct aha_mbx),
- mbx_phys, ISADMA_MAP_CONTIG) != 1)
- panic("aha_init: cannot map mail box");
- lto3b(mbx_phys[0].addr, ad);
+ aha_cmd(sc, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7);
+ aha_cmd(sc, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4);
+#endif
- aha_cmd(aha, 4, 0, 0, 0, AHA_MBX_INIT, AHA_MBX_SIZE,
- ad[0], ad[1], ad[2]);
+ /* Inquire Installed Devices (to force synchronous negotiation). */
+ devices.cmd.opcode = AHA_INQUIRE_DEVICES;
+ aha_cmd(iobase, sc, sizeof(devices.cmd), (u_char *)&devices.cmd,
+ sizeof(devices.reply), (u_char *)&devices.reply);
+
+ /* Obtain setup information from. */
+ setup.cmd.opcode = AHA_INQUIRE_SETUP;
+ setup.cmd.len = sizeof(setup.reply);
+ aha_cmd(iobase, sc, sizeof(setup.cmd), (u_char *)&setup.cmd,
+ sizeof(setup.reply), (u_char *)&setup.reply);
+
+ printf("%s: %s, %s\n",
+ sc->sc_dev.dv_xname,
+ setup.reply.sync_neg ? "sync" : "async",
+ setup.reply.parity ? "parity" : "no parity");
+
+ for (i = 0; i < 8; i++) {
+ if (!setup.reply.sync[i].valid ||
+ (!setup.reply.sync[i].offset && !setup.reply.sync[i].period))
+ continue;
+ printf("%s targ %d: sync, offset %d, period %dnsec\n",
+ sc->sc_dev.dv_xname, i,
+ setup.reply.sync[i].offset, setup.reply.sync[i].period * 50 + 200);
+ }
+ /*
+ * Set up initial mail box for round-robin operation.
+ */
for (i = 0; i < AHA_MBX_SIZE; i++) {
- aha->aha_mbx.mbo[i].cmd = AHA_MBO_FREE;
- aha->aha_mbx.mbi[i].stat = AHA_MBO_FREE;
+ wmbx->mbo[i].cmd = AHA_MBO_FREE;
+ wmbx->mbi[i].stat = AHA_MBO_FREE;
}
+ wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0];
+ wmbx->tmbi = &wmbx->mbi[0];
+ sc->sc_mbofull = 0;
+
+ /* Initialize mail box. */
+ mailbox.cmd.opcode = AHA_MBX_INIT;
+ mailbox.cmd.nmbx = AHA_MBX_SIZE;
+ ltophys(KVTOPHYS(wmbx), mailbox.cmd.addr);
+ aha_cmd(iobase, sc, sizeof(mailbox.cmd), (u_char *)&mailbox.cmd,
+ 0, (u_char *)0);
+}
+
+void
+aha_inquire_setup_information(sc)
+ struct aha_softc *sc;
+{
+ int iobase = sc->sc_iobase;
+ struct aha_revision revision;
+ u_char sts;
+ int i;
+ char *p;
+
+ strcpy(sc->sc_model, "unknown");
/*
- * Set up initial mail box for round-robin operation.
+ * Assume we have a board at this stage, do an adapter inquire
+ * to find out what type of controller it is. If the command
+ * fails, we assume it's either a crusty board or an old 1542
+ * clone, and skip the board-specific stuff.
*/
- aha->aha_mbx.tmbo = &aha->aha_mbx.mbo[0];
- aha->aha_mbx.tmbi = &aha->aha_mbx.mbi[0];
+ revision.cmd.opcode = AHA_INQUIRE_REVISION;
+ if (aha_cmd(iobase, sc, sizeof(revision.cmd), (u_char *)&revision.cmd,
+ sizeof(revision.reply), (u_char *)&revision.reply)) {
+ /*
+ * aha_cmd() already started the reset. It's not clear we
+ * even need to bother here.
+ */
+ for (i = AHA_RESET_TIMEOUT; i; i--) {
+ sts = inb(iobase + AHA_STAT_PORT);
+ if (sts == (AHA_STAT_IDLE | AHA_STAT_INIT))
+ break;
+ delay(1000);
+ }
+ if (!i) {
+#ifdef AHADEBUG
+ printf("aha_init: soft reset failed\n");
+#endif /* AHADEBUG */
+ return;
+ }
+#ifdef AHADEBUG
+ printf("aha_init: inquire command failed\n");
+#endif /* AHADEBUG */
+ goto noinquire;
+ }
+
+#ifdef AHADEBUG
+ printf("%s: inquire %x, %x, %x, %x\n",
+ sc->sc_dev.dv_xname,
+ revision.reply.boardid, revision.reply.spec_opts,
+ revision.reply.revision_1, revision.reply.revision_2);
+#endif /* AHADEBUG */
+
+ switch (revision.reply.boardid) {
+ case 0x31:
+ strcpy(sc->sc_model, "1540");
+ break;
+ case 0x41:
+ strcpy(sc->sc_model, "1540A/1542A/1542B");
+ break;
+ case 0x42:
+ strcpy(sc->sc_model, "1640");
+ break;
+ case 0x43:
+ strcpy(sc->sc_model, "1542C");
+ break;
+ case 0x44:
+ case 0x45:
+ strcpy(sc->sc_model, "1542CF");
+ break;
+ case 0x46:
+ strcpy(sc->sc_model, "1542CP");
+ break;
+ }
+
+ p = sc->sc_firmware;
+ *p++ = revision.reply.revision_1;
+ *p++ = '.';
+ *p++ = revision.reply.revision_2;
+ *p = '\0';
+
+noinquire:
+ printf(": model AHA-%s, firmware %s\n", sc->sc_model, sc->sc_firmware);
}
void
@@ -1211,12 +1110,13 @@ aha_scsi_cmd(xs)
struct scsi_xfer *xs;
{
struct scsi_link *sc_link = xs->sc_link;
- struct aha_softc *aha = sc_link->adapter_softc;
+ struct aha_softc *sc = sc_link->adapter_softc;
struct aha_ccb *ccb;
struct aha_scat_gath *sg;
- int seg, datalen, flags, mflags;
+ int seg; /* scatter gather seg being worked on */
+ u_long thiskv, thisphys, nextphys;
+ int bytes_this_seg, bytes_this_page, datalen, flags;
struct iovec *iovp;
- struct aha_mbx_out *mbo;
int s;
SC_DEBUG(sc_link, SDEV_DB2, ("aha_scsi_cmd\n"));
@@ -1226,44 +1126,28 @@ aha_scsi_cmd(xs)
* then we can't allow it to sleep
*/
flags = xs->flags;
- if (flags & SCSI_NOSLEEP)
- mflags = ISADMA_MAP_BOUNCE;
- else
- mflags = ISADMA_MAP_BOUNCE | ISADMA_MAP_WAITOK;
- if ((flags & (ITSDONE|INUSE)) != INUSE) {
- printf("%s: done or not in use?\n", aha->sc_dev.dv_xname);
- xs->flags &= ~ITSDONE;
- xs->flags |= INUSE;
- }
- if ((ccb = aha_get_ccb(aha, flags)) == NULL) {
+ if ((ccb = aha_get_ccb(sc, flags)) == NULL) {
xs->error = XS_DRIVER_STUFFUP;
return TRY_AGAIN_LATER;
}
ccb->xs = xs;
+ ccb->timeout = xs->timeout;
/*
* Put all the arguments for the xfer in the ccb
*/
if (flags & SCSI_RESET) {
ccb->opcode = AHA_RESET_CCB;
+ ccb->scsi_cmd_length = 0;
} else {
/* can't use S/G if zero length */
ccb->opcode = (xs->datalen ? AHA_INIT_SCAT_GATH_CCB
: AHA_INITIATOR_CCB);
+ bcopy(xs->cmd, &ccb->scsi_cmd,
+ ccb->scsi_cmd_length = xs->cmdlen);
}
- ccb->data_out = 0;
- ccb->data_in = 0;
- ccb->target = sc_link->target;
- ccb->lun = sc_link->lun;
- ccb->scsi_cmd_length = xs->cmdlen;
- ccb->req_sense_length = sizeof(ccb->scsi_sense);
- ccb->host_stat = 0x00;
- ccb->target_stat = 0x00;
- ccb->data_nseg = 0;
- if (xs->datalen && (flags & SCSI_RESET) == 0) {
- sg = ((struct aha_ccb *)(ccb->ccb_phys[0].addr))->scat_gath;
- lto3b((vm_offset_t)sg, ccb->data_addr);
+ if (xs->datalen) {
sg = ccb->scat_gath;
seg = 0;
#ifdef TFS
@@ -1272,8 +1156,8 @@ aha_scsi_cmd(xs)
datalen = ((struct uio *)xs->data)->uio_iovcnt;
xs->datalen = 0;
while (datalen && seg < AHA_NSEG) {
- lto3b(iovp->iov_base, sg->seg_addr);
- lto3b(iovp->iov_len, sg->seg_len);
+ ltophys(iovp->iov_base, sg->seg_addr);
+ ltophys(iovp->iov_len, sg->seg_len);
xs->datalen += iovp->iov_len;
SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)",
iovp->iov_len, iovp->iov_base));
@@ -1283,109 +1167,129 @@ aha_scsi_cmd(xs)
datalen--;
}
} else
-#endif /*TFS_ONLY */
+#endif /* TFS */
{
/*
- * Set up the scatter gather block
+ * Set up the scatter-gather block.
*/
+ SC_DEBUG(sc_link, SDEV_DB4,
+ ("%d @0x%x:- ", xs->datalen, xs->data));
+
+ datalen = xs->datalen;
+ thiskv = (int)xs->data;
+ thisphys = KVTOPHYS(thiskv);
- ccb->data_nseg = isadma_map(xs->data, xs->datalen,
- ccb->data_phys, mflags);
- for (seg = 0; seg < ccb->data_nseg; seg++) {
- lto3b(ccb->data_phys[seg].addr,
- sg[seg].seg_addr);
- lto3b(ccb->data_phys[seg].length,
- sg[seg].seg_len);
+ while (datalen && seg < AHA_NSEG) {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ ltophys(thisphys, sg->seg_addr);
+
+ SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys));
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while (datalen && thisphys == nextphys) {
+ /*
+ * This page is contiguous (physically)
+ * with the the last, just extend the
+ * length
+ */
+ /* check it fits on the ISA bus */
+ if (thisphys > 0xFFFFFF) {
+ printf("%s: DMA beyond"
+ " end of ISA\n",
+ sc->sc_dev.dv_xname);
+ goto bad;
+ }
+ /* how far to the end of the page */
+ nextphys = (thisphys & ~PGOFSET) + NBPG;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page,
+ datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /* get more ready for the next page */
+ thiskv = (thiskv & ~PGOFSET) + NBPG;
+ if (datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /*
+ * next page isn't contiguous, finish the seg
+ */
+ SC_DEBUGN(sc_link, SDEV_DB4,
+ ("(0x%x)", bytes_this_seg));
+ ltophys(bytes_this_seg, sg->seg_len);
+ sg++;
+ seg++;
}
}
- lto3b(ccb->data_nseg * sizeof(struct aha_scat_gath), ccb->data_length);
- if (ccb->data_nseg == 0) {
- printf("%s: aha_scsi_cmd, cannot map\n",
- aha->sc_dev.dv_xname);
- xs->error = XS_DRIVER_STUFFUP;
- aha_free_ccb(aha, ccb, flags);
- return COMPLETE;
- } else if (flags & SCSI_DATA_OUT)
- isadma_copytobuf(xs->data, xs->datalen,
- ccb->data_nseg, ccb->data_phys);
+ /* end of iov/kv decision */
+ SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
+ if (datalen) {
+ /*
+ * there's still data, must have run out of segs!
+ */
+ printf("%s: aha_scsi_cmd, more than %d dma segs\n",
+ sc->sc_dev.dv_xname, AHA_NSEG);
+ goto bad;
+ }
+ ltophys(KVTOPHYS(ccb->scat_gath), ccb->data_addr);
+ ltophys(seg * sizeof(struct aha_scat_gath), ccb->data_length);
} else { /* No data xfer, use non S/G values */
- lto3b(0, ccb->data_addr);
- lto3b(0, ccb->data_length);
+ ltophys(0, ccb->data_addr);
+ ltophys(0, ccb->data_length);
}
- ccb->link_id = 0;
- lto3b(0, ccb->link_addr);
- /*
- * Put the scsi command in the ccb and start it
- */
- if ((flags & SCSI_RESET) == 0)
- bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length);
+ ccb->data_out = 0;
+ ccb->data_in = 0;
+ ccb->target = sc_link->target;
+ ccb->lun = sc_link->lun;
+ ccb->req_sense_length = sizeof(ccb->scsi_sense);
+ ccb->host_stat = 0x00;
+ ccb->target_stat = 0x00;
+ ccb->link_id = 0;
+ ltophys(0, ccb->link_addr);
s = splbio();
-
- isadma_copytobuf((caddr_t)ccb, CCB_PHYS_SIZE, 1, ccb->ccb_phys);
-
- if (aha_send_mbo(aha, AHA_MBO_START, ccb) == NULL) {
- splx(s);
- xs->error = XS_DRIVER_STUFFUP;
- if (ccb->data_nseg)
- isadma_unmap(xs->data, xs->datalen,
- ccb->data_nseg, ccb->data_phys);
- aha_free_ccb(aha, ccb, flags);
- return TRY_AGAIN_LATER;
- }
+ aha_queue_ccb(sc, ccb);
+ splx(s);
/*
* Usually return SUCCESSFULLY QUEUED
*/
SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n"));
-
- if (VOLATILE_XS(xs)) {
- timeout(aha_timeout, ccb, (xs->timeout * hz) / 1000);
- while ((ccb->xs->flags & ITSDONE) == 0) {
- tsleep(ccb, PRIBIO, "ahawait", 0);
- }
- splx(s);
- if (ccb->data_nseg) {
- if (flags & SCSI_DATA_IN)
- isadma_copyfrombuf(xs->data, xs->datalen,
- ccb->data_nseg, ccb->data_phys);
- isadma_unmap(xs->data, xs->datalen,
- ccb->data_nseg, ccb->data_phys);
- }
- aha_free_ccb(aha, ccb, xs->flags);
- scsi_done(xs);
- return COMPLETE;
- }
-
- if ((flags & SCSI_POLL) == 0) {
- timeout(aha_timeout, ccb, (xs->timeout * hz) / 1000);
- splx(s);
+ if ((flags & SCSI_POLL) == 0)
return SUCCESSFULLY_QUEUED;
- }
-
- splx(s);
/*
* If we can't use interrupts, poll on completion
*/
- if (aha_poll(aha, xs, xs->timeout)) {
+ if (aha_poll(sc, xs, ccb->timeout)) {
aha_timeout(ccb);
- if (aha_poll(aha, xs, 2000))
+ if (aha_poll(sc, xs, ccb->timeout))
aha_timeout(ccb);
}
return COMPLETE;
+
+bad:
+ xs->error = XS_DRIVER_STUFFUP;
+ aha_free_ccb(sc, ccb);
+ return COMPLETE;
}
/*
* Poll a particular unit, looking for a particular xs
*/
int
-aha_poll(aha, xs, count)
- struct aha_softc *aha;
+aha_poll(sc, xs, count)
+ struct aha_softc *sc;
struct scsi_xfer *xs;
int count;
{
+ int iobase = sc->sc_iobase;
/* timeouts are in msec, so we loop in 1000 usec cycles */
while (count) {
@@ -1393,8 +1297,8 @@ aha_poll(aha, xs, count)
* If we had interrupts enabled, would we
* have got an interrupt?
*/
- if (inb(AHA_INTR_PORT) & AHA_ANY_INTR)
- ahaintr(aha);
+ if (inb(iobase + AHA_INTR_PORT) & AHA_INTR_ANYINTR)
+ ahaintr(sc);
if (xs->flags & ITSDONE)
return 0;
delay(1000); /* only happens in boot so ok */
@@ -1403,141 +1307,6 @@ aha_poll(aha, xs, count)
return 1;
}
-#ifdef TUNE_1542
-/*
- * Try all the speeds from slowest to fastest.. if it finds a
- * speed that fails, back off one notch from the last working
- * speed (unless there is no other notch).
- * Returns the nSEC value of the time used
- * or 0 if it could get a working speed (or the NEXT speed
- * failed)
- */
-static struct bus_speed {
- u_char arg;
- int nsecs;
-} aha_bus_speeds[] = {
- {0x88, 100},
- {0x99, 150},
- {0xaa, 200},
- {0xbb, 250},
- {0xcc, 300},
- {0xdd, 350},
- {0xee, 400},
- {0xff, 450}
-};
-
-int
-aha_set_bus_speed(aha)
- struct aha_softc *aha;
-{
- int speed;
- int lastworking;
-
- lastworking = -1;
- for (speed = 7; speed >= 0; speed--) {
- if (!aha_bus_speed_check(aha, speed))
- break;
- lastworking = speed;
- }
- if (lastworking == -1) {
- printf(" no working bus speed");
- return 0;
- }
- printf(", %d nsec ", aha_bus_speeds[lastworking].nsecs);
- if (lastworking == 7) /* is slowest already */
- printf("marginal");
- else {
- lastworking++;
- printf("ok, using %d nsec", aha_bus_speeds[lastworking].nsecs);
- }
- if (!aha_bus_speed_check(aha, lastworking)) {
- printf("test retry failed.. aborting.");
- return 0;
- }
- return 1;
-}
-
-/*
- * Set the DMA speed to the Nth speed and try an xfer. If it
- * fails return 0, if it succeeds return the nSec value selected
- * If there is no such speed return COMPLETE.
- */
-char aha_scratch_buf[256];
-char aha_test_string[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@";
-
-int
-aha_bus_speed_check(aha, speed)
- struct aha_softc *aha;
- int speed;
-{
- int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed);
- int result, loopcount;
- struct isadma_seg test_phys[1], scratch_phys[1];
- u_char ad[3];
-
- result = 1;
-
- if (isadma_map(aha_scratch_buf, sizeof(aha_scratch_buf),
- scratch_phys, ISADMA_MAP_CONTIG) != 1)
- return 0;
- if (isadma_map(aha_test_string, sizeof(aha_test_string),
- test_phys, ISADMA_MAP_CONTIG) != 1) {
- isadma_unmap(aha_scratch_buf, sizeof(aha_scratch_buf),
- 1, scratch_phys);
- return 0;
- }
- isadma_copytobuf(aha_test_string, sizeof(aha_test_string),
- 1, test_phys);
-
- /*
- * Set the dma-speed
- */
- aha_cmd(aha, 1, 0, 0, 0, AHA_SPEED_SET, aha_bus_speeds[speed].arg);
-
- /*
- * put the test data into the buffer and calculate
- * it's address. Read it onto the board
- */
- for (loopcount = 100; loopcount; loopcount--) {
- lto3b(test_phys[0].addr, ad);
- aha_cmd(aha, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]);
-
- /*
- * Clear the buffer then copy the contents back from the
- * board.
- */
- bzero(aha_scratch_buf, 54);
- isadma_copytobuf(aha_scratch_buf, sizeof(aha_scratch_buf),
- 1, scratch_phys);
-
- lto3b(scratch_phys[0].addr, ad);
- aha_cmd(aha, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]);
- isadma_copyfrombuf(aha_scratch_buf, sizeof(aha_scratch_buf),
- 1, scratch_phys);
-
- /*
- * Compare the original data and the final data and return the
- * correct value depending upon the result. We only check the
- * first 54 bytes, because that's all the board copies during
- * WRITE_FIFO and READ_FIFO.
- */
- if (bcmp(aha_test_string, aha_scratch_buf, 54)) {
- result = 0; /* failed test */
- break;
- }
- }
-
- isadma_unmap(aha_scratch_buf, sizeof(aha_scratch_buf),
- 1, scratch_phys);
- isadma_unmap(aha_test_string, sizeof(aha_test_string),
- 1, test_phys);
-
- /* copy succeeded; assume speed ok */
- return result;
-}
-#endif /* TUNE_1542 */
-
void
aha_timeout(arg)
void *arg;
@@ -1545,7 +1314,7 @@ aha_timeout(arg)
struct aha_ccb *ccb = arg;
struct scsi_xfer *xs = ccb->xs;
struct scsi_link *sc_link = xs->sc_link;
- struct aha_softc *aha = sc_link->adapter_softc;
+ struct aha_softc *sc = sc_link->adapter_softc;
int s;
sc_print_addr(sc_link);
@@ -1553,34 +1322,33 @@ aha_timeout(arg)
s = splbio();
+#ifdef AHADIAG
/*
* If The ccb's mbx is not free, then the board has gone south?
*/
- if (aha_ccb_phys_kv(aha, _3btol(ccb->mbx->ccb_addr)) == ccb &&
- ccb->mbx->cmd != AHA_MBO_FREE) {
- printf("%s: not taking commands!\n", aha->sc_dev.dv_xname);
+ aha_collect_mbo(sc);
+ if (ccb->flags & CCB_SENDING) {
+ printf("%s: not taking commands!\n", sc->sc_dev.dv_xname);
Debugger();
}
+#endif
/*
* If it has been through before, then
* a previous abort has failed, don't
* try abort again
*/
- if (ccb->flags == CCB_ABORTED) {
+ if (ccb->flags & CCB_ABORT) {
/* abort timed out */
printf(" AGAIN\n");
- ccb->xs->retries = 0;
- aha_done(aha, ccb);
+ /* XXX Must reset! */
} else {
/* abort the operation that has timed out */
printf("\n");
ccb->xs->error = XS_TIMEOUT;
- ccb->flags = CCB_ABORTED;
- aha_send_mbo(aha, AHA_MBO_ABORT, ccb);
- /* 2 secs for the abort */
- if ((xs->flags & SCSI_POLL) == 0)
- timeout(aha_timeout, ccb, 2 * hz);
+ ccb->timeout = AHA_ABORT_TIMEOUT;
+ ccb->flags |= CCB_ABORT;
+ aha_queue_ccb(sc, ccb);
}
splx(s);