summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/i386/scsi/aic7xxx.c469
-rw-r--r--sys/i386/scsi/aic7xxx.h5
-rw-r--r--sys/i386/scsi/bt.c12
3 files changed, 247 insertions, 239 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index 9cc35bd..e3a0440 100644
--- a/sys/i386/scsi/aic7xxx.c
+++ b/sys/i386/scsi/aic7xxx.c
@@ -24,7 +24,7 @@
*
* commenced: Sun Sep 27 18:14:01 PDT 1992
*
- * $Id: aic7xxx.c,v 1.54 1996/01/23 21:47:50 se Exp $
+ * $Id: aic7xxx.c,v 1.55 1996/01/29 03:17:37 gibbs Exp $
*/
/*
* TODO:
@@ -70,14 +70,9 @@ static int ahc_debug = AHC_SHOWABORTS|AHC_SHOWMISC;
#define HSCSIID 0x07 /* our SCSI ID */
#define HWSCSIID 0x0f /* our SCSI ID if Wide Bus */
-typedef enum {
- list_head,
- list_second,
-}insert_t;
-
-static u_int32 ahc_adapter_info __P((int unit));
-static void ahcminphys __P((struct buf *bp));
-static int32 ahc_scsi_cmd __P((struct scsi_xfer *xs));
+static u_int32_t ahc_adapter_info __P((int unit));
+static void ahcminphys __P((struct buf *bp));
+static int32_t ahc_scsi_cmd __P((struct scsi_xfer *xs));
static struct scsi_adapter ahc_switch =
{
@@ -129,13 +124,12 @@ static struct scsi_device ahc_dev =
static u_char ahc_abort_wscb __P((struct ahc_data *ahc, struct scb *scbp,
u_char prev, u_long iobase,
- u_char timedout_scb, u_int32 xs_error));
-static void ahc_add_waiting_scb __P((u_long iobase, struct scb *scb,
- insert_t where));
+ u_char timedout_scb, u_int32_t xs_error));
+static void ahc_add_waiting_scb __P((u_long iobase, struct scb *scb));
static void ahc_done __P((struct ahc_data *ahc, struct scb *scbp));
static void ahc_free_scb __P((struct ahc_data *ahc, struct scb *scb,
int flags));
-static inline void ahc_getscb __P((struct ahc_data *ahc, struct scb *scb,
+static inline void ahc_fetch_scb __P((struct ahc_data *ahc, struct scb *scb,
int iosize));
static struct scb *
ahc_get_scb __P((struct ahc_data *ahc, int flags));
@@ -147,16 +141,16 @@ static void ahc_print_active_scb __P((struct ahc_data *ahc));
static void ahc_print_scb __P((struct scb *scb));
#endif
static int ahc_reset_channel __P((struct ahc_data *ahc, char channel,
- u_char timedout_scb, u_int32 xs_error));
+ u_char timedout_scb, u_int32_t xs_error,
+ u_char initiate_reset));
static int ahc_reset_device __P((struct ahc_data *ahc, int target,
char channel, u_char timedout_scb,
- u_int32 xs_error));
+ u_int32_t xs_error));
static void ahc_reset_current_bus __P((u_long iobase));
-static void ahc_scb_timeout __P((struct ahc_data *ahc, struct scb *scb));
+static void ahc_run_done_queue __P((struct ahc_data *ahc));
static void ahc_scsirate __P((struct ahc_data* ahc, u_char *scsirate,
int period, int offset, int target));
-static inline void ahc_send_scb __P((struct ahc_data *ahc, struct scb *scb,
- int iosize));
+static inline void ahc_send_scb __P((struct ahc_data *ahc, struct scb *scb));
static timeout_t
ahc_timeout;
static void ahc_busy_target __P((int target, char channel,
@@ -439,10 +433,9 @@ ahc_attach(ahc)
/* Send an SCB down to the card via PIO maintaining the SCB pointer */
static inline void
-ahc_send_scb(ahc, scb, iosize)
+ahc_send_scb(ahc, scb)
struct ahc_data *ahc;
struct scb *scb;
- int iosize; /* In bytes */
{
u_long iobase = ahc->baseport;
u_char cur_scb;
@@ -452,15 +445,16 @@ ahc_send_scb(ahc, scb, iosize)
outb(SCBCNT + iobase, SCBAUTO);
if( ahc->type == AHC_284 )
/* Can only do 8bit PIO */
- outsb(SCBARRAY+iobase, scb, iosize);
+ outsb(SCBARRAY+iobase, scb, SCB_PIO_TRANSFER_SIZE);
else
- outsl(SCBARRAY+iobase, scb, (iosize + 3) / 4);
+ outsl(SCBARRAY+iobase, scb,
+ (SCB_PIO_TRANSFER_SIZE + 3) / 4);
outb(SCBCNT + iobase, 0);
outb(SCBPTR + iobase, cur_scb);
}
static inline void
-ahc_getscb(ahc, scb, iosize)
+ahc_fetch_scb(ahc, scb, iosize)
struct ahc_data *ahc;
struct scb *scb;
int iosize;
@@ -476,43 +470,28 @@ ahc_getscb(ahc, scb, iosize)
}
/*
- * Add this SCB to the "waiting for selection" list.
+ * Add this SCB to the head of the "waiting for selection" list.
*/
static
-void ahc_add_waiting_scb (iobase, scb, where)
+void ahc_add_waiting_scb (iobase, scb)
u_long iobase;
struct scb *scb;
- insert_t where;
{
- u_char head, tail;
+ u_char next;
u_char curscb;
curscb = inb(SCBPTR + iobase);
- head = inb(WAITING_SCBH + iobase);
- if(head == SCB_LIST_NULL) {
- /* List was empty */
- head = scb->position;
- tail = SCB_LIST_NULL;
- }
- else if (where == list_head) {
- outb(SCBPTR+iobase, scb->position);
- outb(SCB_NEXT_WAITING+iobase, head);
- head = scb->position;
- }
- else /*where == list_second*/ {
- u_char third_scb;
- outb(SCBPTR+iobase, head);
- third_scb = inb(SCB_NEXT_WAITING+iobase);
- outb(SCB_NEXT_WAITING+iobase,scb->position);
- outb(SCBPTR+iobase, scb->position);
- outb(SCB_NEXT_WAITING+iobase,third_scb);
- }
- outb(WAITING_SCBH + iobase, head);
+ next = inb(WAITING_SCBH + iobase);
+
+ outb(SCBPTR+iobase, scb->position);
+ outb(SCB_NEXT_WAITING+iobase, next);
+ outb(WAITING_SCBH + iobase, scb->position);
+
outb(SCBPTR + iobase, curscb);
}
/*
- * Catch an interrupt from the adaptor
+ * Catch an interrupt from the adapter
*/
void
ahc_intr(arg)
@@ -837,7 +816,7 @@ ahc_intr(arg)
xs = scb->xs;
- ahc_getscb(ahc, scb, SCB_PIO_TRANSFER_SIZE);
+ ahc_fetch_scb(ahc, scb, SCB_PIO_TRANSFER_SIZE);
#ifdef AHC_DEBUG
if((ahc_debug & AHC_SHOWSCBS)
@@ -893,8 +872,7 @@ ahc_intr(arg)
scb->data = sg->addr;
scb->datalen = sg->len;
- ahc_send_scb(ahc, scb,
- SCB_PIO_TRANSFER_SIZE);
+ ahc_send_scb(ahc, scb);
outb(SCB_NEXT_WAITING+iobase,
SCB_LIST_NULL);
/*
@@ -908,8 +886,7 @@ ahc_intr(arg)
/*
* Make us the next command to run
*/
- ahc_add_waiting_scb(iobase, scb,
- list_head);
+ ahc_add_waiting_scb(iobase, scb);
outb(RETURN_1 + iobase, SEND_SENSE);
break;
}
@@ -1061,13 +1038,11 @@ ahc_intr(arg)
found = ahc_reset_device(ahc, target,
channel, SCB_LIST_NULL,
XS_NOERROR);
-#ifdef AHC_DEBUG
- if(ahc_debug & AHC_SHOWABORTS) {
- sc_print_addr(scb->xs->sc_link);
- printf("Bus Device Reset delivered. "
- "%d SCBs aborted\n", found);
- }
-#endif
+ sc_print_addr(scb->xs->sc_link);
+ printf("Bus Device Reset delivered. "
+ "%d SCBs aborted\n", found);
+ ahc->in_timeout = FALSE;
+ ahc_run_done_queue(ahc);
}
else
panic("ahc_intr: Immediate complete for "
@@ -1183,10 +1158,26 @@ clear:
}
xs = scb->xs;
+ if (status & SCSIRSTI) {
+ u_char channel;
+ PAUSE_SEQUENCER(ahc);
+ channel = inb(SBLKCTL + iobase);
+ if( !(inb(SCSISEQ + iobase ) & SCSIRSTO)
+ && (ahc->flags & AHC_TWIN) )
+ {
+ /* Its on the other bus */
+ channel ^= SELBUSB;
+ }
+ ahc_reset_channel(ahc,
+ channel & SELBUSB ? 'B' : 'A',
+ SCB_LIST_NULL,
+ XS_BUSY,
+ /* Initiate Reset */FALSE);
+ ahc_run_done_queue(ahc);
+ }
if (status & SELTO) {
u_char waiting;
u_char flags;
- outb(SCSISEQ + iobase, ENRSELI);
xs->error = XS_TIMEOUT;
/*
* Clear any pending messages for the timed out
@@ -1377,7 +1368,7 @@ ahc_init(ahc)
outb(SCSIID + iobase, ahc->our_id_b);
scsi_conf = inb(SCSICONF + 1 + iobase) & (ENSPCHK|STIMESEL);
outb(SXFRCTL1 + iobase, scsi_conf|ENSTIMER|ACTNEGEN|STPWEN);
- outb(SIMODE1 + iobase, ENSELTIMO);
+ outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIRST);
if(ahc->type & AHC_ULTRA)
outb(SXFRCTL0 + iobase, DFON|SPIOEN|ULTRAEN);
else
@@ -1394,7 +1385,7 @@ ahc_init(ahc)
outb(SCSIID + iobase, ahc->our_id);
scsi_conf = inb(SCSICONF + iobase) & (ENSPCHK|STIMESEL);
outb(SXFRCTL1 + iobase, scsi_conf|ENSTIMER|ACTNEGEN|STPWEN);
- outb(SIMODE1 + iobase, ENSELTIMO);
+ outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIRST);
if(ahc->type & AHC_ULTRA)
outb(SXFRCTL0 + iobase, DFON|SPIOEN|ULTRAEN);
else
@@ -1555,7 +1546,7 @@ ahcminphys(bp)
* the data address, target, and lun all of which
* are stored in the scsi_xfer struct
*/
-static int32
+static int32_t
ahc_scsi_cmd(xs)
struct scsi_xfer *xs;
{
@@ -1689,7 +1680,7 @@ ahc_scsi_cmd(xs)
ahc->unit, AHC_NSEG);
xs->error = XS_DRIVER_STUFFUP;
ahc_free_scb(ahc, scb, flags);
- return (HAD_ERROR);
+ return (COMPLETE);
}
}
else {
@@ -1709,7 +1700,7 @@ ahc_scsi_cmd(xs)
if (!(flags & SCSI_NOMASK)) {
s = splbio();
PAUSE_SEQUENCER(ahc);
- ahc_send_scb(ahc, scb, SCB_PIO_TRANSFER_SIZE);
+ ahc_send_scb(ahc, scb);
outb(QINFIFO + ahc->baseport, scb->position);
UNPAUSE_SEQUENCER(ahc);
timeout(ahc_timeout, (caddr_t)scb, (xs->timeout * hz) / 1000);
@@ -1722,7 +1713,7 @@ ahc_scsi_cmd(xs)
*/
s = splbio();
PAUSE_SEQUENCER(ahc);
- ahc_send_scb(ahc, scb, SCB_PIO_TRANSFER_SIZE);
+ ahc_send_scb(ahc, scb);
outb(QINFIFO + ahc->baseport, scb->position);
UNPAUSE_SEQUENCER(ahc);
SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_wait\n"));
@@ -1730,15 +1721,10 @@ ahc_scsi_cmd(xs)
if (ahc_poll(ahc, xs->timeout)) {
if (!(xs->flags & SCSI_SILENT))
printf("cmd fail\n");
- ahc_scb_timeout(ahc, scb);
- splx(s);
- return (HAD_ERROR);
+ ahc_timeout(scb);
+ break;
}
} while (!(xs->flags & ITSDONE)); /* a non command complete intr */
- if (xs->error) {
- splx(s);
- return (HAD_ERROR);
- }
splx(s);
return (COMPLETE);
}
@@ -1748,7 +1734,7 @@ ahc_scsi_cmd(xs)
* Return some information to the caller about
* the adapter and it's capabilities.
*/
-static u_int32
+static u_int32_t
ahc_adapter_info(unit)
int unit;
{
@@ -1808,8 +1794,6 @@ ahc_get_scb(ahc, flags)
scbp = (struct scb *) malloc(sizeof(struct scb),
M_TEMP, M_NOWAIT);
if (scbp) {
- u_long iobase = ahc->baseport;
- u_char curscb;
bzero(scbp, sizeof(struct scb));
scbp->position = ahc->numscbs;
ahc->numscbs++;
@@ -1898,66 +1882,149 @@ ahc_poll(ahc, wait)
}
static void
-ahc_scb_timeout(ahc, scb)
- struct ahc_data *ahc;
- struct scb *scb;
+ahc_timeout(arg)
+ void *arg;
{
- u_long iobase = ahc->baseport;
- int found = 0;
- char channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
+ struct scb *scb = (struct scb *)arg;
+ struct ahc_data *ahc;
+ int s, h, found;
+ u_char bus_state;
+ u_long iobase;
- /*
+ s = splbio();
+
+ h = splhigh();
+
+ if (!(scb->flags & SCB_ACTIVE)) {
+ /* Previous timeout took care of me already */
+ splx(h);
+ splx(s);
+ return;
+ }
+
+ ahc = (struct ahc_data *)scb->xs->sc_link->adapter_softc;
+
+ if (ahc->in_timeout) {
+ /*
+ * Some other SCB has started a recovery operation
+ * and is still working on cleaning things up.
+ */
+ if (scb->flags & SCB_TIMEDOUT) {
+ /*
+ * This SCB has been here before and is not the
+ * recovery SCB. Cut our losses and panic. Its
+ * better to do this than trash a filesystem.
+ */
+ panic("ahc%d: Timed-out command times out "
+ "again\n", ahc->unit);
+ }
+ else if (!(scb->flags & SCB_ABORTED))
+ {
+ /*
+ * This is not the SCB that started this timeout
+ * processing. Give this scb another lifetime so
+ * that it can continue once we deal with the
+ * timeout.
+ */
+ scb->flags |= SCB_TIMEDOUT;
+ timeout(ahc_timeout, (caddr_t)scb,
+ (scb->xs->timeout * hz) / 1000);
+ splx(h);
+ splx(s);
+ return;
+ }
+ }
+ ahc->in_timeout = TRUE;
+ splx(h);
+
+ /*
* Ensure that the card doesn't do anything
* behind our back.
*/
PAUSE_SEQUENCER(ahc);
+ sc_print_addr(scb->xs->sc_link);
+ printf("timed out ");
/*
- * First, determine if we want to do a bus
- * reset or simply a bus device reset.
- * If this is the first time that a transaction
- * has timed out, just schedule a bus device
- * reset. Otherwise, we reset the bus and
- * abort all pending I/Os on that bus.
+ * Take a snapshot of the bus state and print out
+ * some information so we can track down driver bugs.
*/
+ iobase = ahc->baseport;
+ bus_state = inb(iobase + LASTPHASE);
+
+ switch(bus_state & PHASE_MASK)
+ {
+ case P_DATAOUT:
+ printf("in dataout phase");
+ break;
+ case P_DATAIN:
+ printf("in datain phase");
+ break;
+ case P_COMMAND:
+ printf("in command phase");
+ break;
+ case P_MESGOUT:
+ printf("in message out phase");
+ break;
+ case P_STATUS:
+ printf("in status phase");
+ break;
+ case P_MESGIN:
+ printf("in message in phase");
+ break;
+ default:
+ printf("while idle, LASTPHASE == 0x%x",
+ bus_state);
+ /*
+ * We aren't in a valid phase, so assume we're
+ * idle.
+ */
+ bus_state = 0;
+ break;
+ }
+
+ printf(", SCSISIGI == 0x%x\n", inb(iobase + SCSISIGI));
+
+ /* Decide our course of action */
+
if(scb->flags & SCB_ABORTED)
{
/*
* Been down this road before.
* Do a full bus reset.
*/
+ char channel = (scb->target_channel_lun & SELBUSB)
+ ? 'B': 'A';
found = ahc_reset_channel(ahc, channel, scb->position,
- XS_TIMEOUT);
-#ifdef AHC_DEBUG
- if(ahc_debug & AHC_SHOWABORTS)
- printf("ahc%d: Issued Channel %c Bus Reset #1. "
- "%d SCBs aborted\n", ahc->unit, channel, found);
-#endif
+ XS_TIMEOUT, /*Initiate Reset*/TRUE);
+ printf("ahc%d: Issued Channel %c Bus Reset #1. "
+ "%d SCBs aborted\n", ahc->unit, channel, found);
+ ahc->in_timeout = FALSE;
}
else {
/*
* Send a Bus Device Reset Message:
- * The target we select to send the message to may
- * be entirely different than the target pointed to
- * by the scb that timed out. If the command is
- * in the QINFIFO or the waiting for selection list,
- * its not tying up the bus and isn't responsible
- * for the delay so we pick off the active command
- * which should be the SCB selected by SCBPTR. If
- * its disconnected or active, we device reset the
- * target scbp points to. Although it may be that
- * this target is not responsible for the delay, it
- * may also be that we're timing out on a command that
- * just takes too much time, so we try the bus device
- * reset there first.
+ * The target that is holding up the bus may not
+ * be the same as the one that triggered this timeout
+ * (different commands have different timeout lengths).
+ * It is also impossible to get a message to a target
+ * if we are in a "frozen" data transfer phase. Our
+ * strategy here is to queue a bus device reset message
+ * to the timed out target if it is disconnected.
+ * Otherwise, if we have an active target we stuff the
+ * message buffer with a bus device reset message and
+ * assert ATN in the hopes that the target will let go
+ * of the bus and finally disconnect. If this fails,
+ * we'll get another timeout 2 seconds later which will
+ * cause a bus reset.
*/
u_char active_scb, control;
struct scb *active_scbp;
active_scb = inb(SCBPTR + iobase);
active_scbp = ahc->scbarray[active_scb];
- control = inb(SCBARRAY + iobase);
+ control = inb(SCB_CONTROL + iobase);
- /* Test to see if scbp is disconnected */
+ /* Test to see if scb is disconnected */
outb(SCBPTR + iobase, scb->position);
if(inb(SCB_CONTROL + iobase) & DISCONNECTED) {
scb->flags |= SCB_DEVICE_RESET|SCB_ABORTED;
@@ -1965,123 +2032,44 @@ ahc_scb_timeout(ahc, scb)
scb->SG_list_pointer = 0;
scb->data = 0;
scb->datalen = 0;
- outb(SCBCNT + iobase, 0x80);
- outsb(SCBARRAY+iobase,scb,SCB_PIO_TRANSFER_SIZE);
- outb(SCBCNT + iobase, 0);
- ahc_add_waiting_scb(iobase, scb, list_second);
+ ahc_send_scb(ahc, scb);
+ ahc_add_waiting_scb(iobase, scb);
timeout(ahc_timeout, (caddr_t)scb, (2 * hz));
-#ifdef AHC_DEBUG
- if(ahc_debug & AHC_SHOWABORTS) {
- sc_print_addr(scb->xs->sc_link);
- printf("BUS DEVICE RESET message queued.\n");
- }
-#endif
+ sc_print_addr(scb->xs->sc_link);
+ printf("BUS DEVICE RESET message queued.\n");
+ outb(SCBPTR + iobase, active_scb);
UNPAUSE_SEQUENCER(ahc);
}
/* Is the active SCB really active? */
- else if(active_scbp->flags & SCB_ACTIVE) {
- /* XXX && (control & NEEDDMA) == NEEDDMA) { */
- u_char msg_len = inb(MSG_LEN + iobase);
- if(msg_len) {
- /*
- * If we're in a message phase, tacking on
- * another message may confuse the target totally.
- * The bus is probably wedged, so reset the
- * channel.
- */
- channel = (active_scbp->target_channel_lun & SELBUSB)
- ? 'B': 'A';
- ahc_reset_channel(ahc, channel, scb->position,
- XS_TIMEOUT);
-#ifdef AHC_DEBUG
- if(ahc_debug & AHC_SHOWABORTS)
- printf("ahc%d: Issued Channel %c Bus Reset #2. "
- "%d SCBs aborted\n", ahc->unit, channel,
- found);
-#endif
- }
- else {
- /*
- * Load the message buffer and assert attention.
- */
- active_scbp->flags |= SCB_DEVICE_RESET|SCB_ABORTED;
- if(active_scbp != scb)
- untimeout(ahc_timeout, (caddr_t)active_scbp);
- timeout(ahc_timeout, (caddr_t)active_scbp, (2 * hz));
+ else if((active_scbp->flags & SCB_ACTIVE) && bus_state) {
outb(MSG_LEN + iobase, 1);
outb(MSG0 + iobase, MSG_BUS_DEVICE_RESET);
- if(active_scbp->target_channel_lun
- != scb->target_channel_lun) {
+ outb(SCSISIGO + iobase, bus_state|ATNO);
+ sc_print_addr(active_scbp->xs->sc_link);
+ printf("asserted ATN - device reset in message buffer\n");
+ active_scbp->flags |= SCB_DEVICE_RESET|SCB_ABORTED;
+ if(active_scbp != scb) {
+ untimeout(ahc_timeout, (caddr_t)active_scbp);
/* Give scb a new lease on life */
timeout(ahc_timeout, (caddr_t)scb,
(scb->xs->timeout * hz) / 1000);
}
-#ifdef AHC_DEBUG
- if(ahc_debug & AHC_SHOWABORTS) {
- sc_print_addr(active_scbp->xs->sc_link);
- printf("BUS DEVICE RESET message queued.\n");
- }
-#endif
+ timeout(ahc_timeout, (caddr_t)active_scbp, (2 * hz));
+ outb(SCBPTR + iobase, active_scb);
UNPAUSE_SEQUENCER(ahc);
- }
}
else {
- /*
- * No active command to single out, so reset
- * the bus for the timed out target.
- */
- ahc_reset_channel(ahc, channel, scb->position,
- XS_TIMEOUT);
-#ifdef AHC_DEBUG
- if(ahc_debug & AHC_SHOWABORTS)
- printf("ahc%d: Issued Channel %c Bus Reset #3. "
- "%d SCBs aborted\n", ahc->unit, channel,
- found);
-#endif
+ /* No active target? Try reseting the bus */
+ char channel = (scb->target_channel_lun & SELBUSB)
+ ? 'B': 'A';
+ found = ahc_reset_channel(ahc, channel, scb->position,
+ XS_TIMEOUT, /*Initiate Reset*/TRUE);
+ printf("ahc%d: Issued Channel %c Bus Reset #2. "
+ "%d SCBs aborted\n", ahc->unit, channel,
+ found);
+ ahc->in_timeout = FALSE;
}
}
-}
-
-static void
-ahc_timeout(void *arg1)
-{
- struct scb *scb = (struct scb *)arg1;
- struct ahc_data *ahc;
- int s;
-
- s = splhigh();
-
- if (!(scb->flags & SCB_ACTIVE)) {
- /* Previous timeout took care of me already */
- splx(s);
- return;
- }
-
- ahc = (struct ahc_data *)scb->xs->sc_link->adapter_softc;
- printf("ahc%d: target %d, lun %d (%s%d) timed out\n", ahc->unit
- ,scb->xs->sc_link->target
- ,scb->xs->sc_link->lun
- ,scb->xs->sc_link->device->name
- ,scb->xs->sc_link->dev_unit);
-#ifdef SCSIDEBUG
- show_scsi_cmd(scb->xs);
-#endif
-#ifdef AHC_DEBUG
- if (ahc_debug & AHC_SHOWSCBS)
- ahc_print_active_scb(ahc);
-#endif /*AHC_DEBUG */
-
- /*
- * If it's immediate, don't try to abort it
- */
- if (scb->flags & SCB_IMMED) {
- scb->xs->retries = 0; /* I MEAN IT ! */
- ahc_done(ahc, scb);
- }
- else {
- /* abort the operation that has timed out */
- ahc_scb_timeout(ahc, scb);
- }
splx(s);
}
@@ -2096,7 +2084,7 @@ ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
int target;
char channel;
u_char timedout_scb;
- u_int32 xs_error;
+ u_int32_t xs_error;
{
u_long iobase = ahc->baseport;
struct scb *scbp;
@@ -2121,11 +2109,10 @@ ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
/*
* We found an scb that needs to be aborted.
*/
- scbp->flags |= SCB_ABORTED;
+ scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE;
scbp->xs->error |= xs_error;
if(scbp->position != timedout_scb)
untimeout(ahc_timeout, (caddr_t)scbp);
- ahc_done (ahc, scbp);
outb(SCBPTR + iobase, scbp->position);
outb(SCBARRAY + iobase, 0);
i--;
@@ -2178,11 +2165,10 @@ ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
ahc_unbusy_target(target, channel, iobase);
outb(SCBPTR + iobase, scbp->position);
outb(SCBARRAY + iobase, 0);
- scbp->flags |= SCB_ABORTED;
+ scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE;
scbp->xs->error |= xs_error;
if(scbp->position != timedout_scb)
untimeout(ahc_timeout, (caddr_t)scbp);
- ahc_done (ahc, scbp);
found++;
}
}
@@ -2201,7 +2187,7 @@ ahc_abort_wscb (ahc, scbp, prev, iobase, timedout_scb, xs_error)
u_char prev;
u_long iobase;
u_char timedout_scb;
- u_int32 xs_error;
+ u_int32_t xs_error;
{
u_char curscbp, next;
int target = ((scbp->target_channel_lun >> 4) & 0x0f);
@@ -2215,7 +2201,7 @@ ahc_abort_wscb (ahc, scbp, prev, iobase, timedout_scb, xs_error)
next = inb(SCB_NEXT_WAITING + iobase);
/* Clear the necessary fields */
- outb(SCBARRAY + iobase, 0);
+ outb(SCB_CONTROL + iobase, 0);
outb(SCB_NEXT_WAITING + iobase, SCB_LIST_NULL);
ahc_unbusy_target(target, channel, iobase);
@@ -2231,21 +2217,16 @@ ahc_abort_wscb (ahc, scbp, prev, iobase, timedout_scb, xs_error)
outb(SCBPTR + iobase, prev);
outb(SCB_NEXT_WAITING + iobase, next);
}
- /* Update the tale pointer */
- if(inb(WAITING_SCBT + iobase) == scbp->position)
- outb(WAITING_SCBT + iobase, prev);
-
/*
* Point us back at the original scb position
* and inform the SCSI system that the command
* has been aborted.
*/
outb(SCBPTR + iobase, curscbp);
- scbp->flags |= SCB_ABORTED;
+ scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE;
scbp->xs->error |= xs_error;
if(scbp->position != timedout_scb)
untimeout(ahc_timeout, (caddr_t)scbp);
- ahc_done (ahc, scbp);
return next;
}
@@ -2301,11 +2282,12 @@ ahc_reset_current_bus(iobase)
}
static int
-ahc_reset_channel(ahc, channel, timedout_scb, xs_error)
+ahc_reset_channel(ahc, channel, timedout_scb, xs_error, initiate_reset)
struct ahc_data *ahc;
char channel;
u_char timedout_scb;
- u_int32 xs_error;
+ u_int32_t xs_error;
+ u_char initiate_reset;
{
u_long iobase = ahc->baseport;
u_char sblkctl;
@@ -2355,9 +2337,9 @@ ahc_reset_channel(ahc, channel, timedout_scb, xs_error)
}
/*
- * Reset the bus and unpause/restart the controller
+ * Reset the bus if we are initiating this reset and
+ * restart/unpause the sequencer
*/
-
/* Case 1: Command for another bus is active */
sblkctl = inb(SBLKCTL + iobase);
cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
@@ -2368,18 +2350,41 @@ ahc_reset_channel(ahc, channel, timedout_scb, xs_error)
* without upsetting the current bus
*/
outb(SBLKCTL + iobase, sblkctl ^ SELBUSB);
- ahc_reset_current_bus(iobase);
+ if( initiate_reset )
+ {
+ ahc_reset_current_bus(iobase);
+ }
+ outb(CLRSINT1 + iobase, CLRSCSIRSTI);
outb(SBLKCTL + iobase, sblkctl);
UNPAUSE_SEQUENCER(ahc);
}
/* Case 2: A command from this bus is active or we're idle */
else {
- ahc_reset_current_bus(iobase);
+ if( initiate_reset )
+ {
+ ahc_reset_current_bus(iobase);
+ }
+ outb(CLRSINT1 + iobase, CLRSCSIRSTI);
RESTART_SEQUENCER(ahc);
}
+ ahc_run_done_queue(ahc);
return found;
}
+void
+ahc_run_done_queue(ahc)
+ struct ahc_data *ahc;
+{
+ int i;
+ struct scb *scbp;
+
+ for(i = 0; i < ahc->numscbs; i++) {
+ scbp = ahc->scbarray[i];
+ if(scbp->flags & SCB_QUEUED_FOR_DONE)
+ ahc_done(ahc, scbp);
+ }
+}
+
static int
ahc_match_scb (scb, target, channel)
struct scb *scb;
diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h
index f92e003..a5c0b4a 100644
--- a/sys/i386/scsi/aic7xxx.h
+++ b/sys/i386/scsi/aic7xxx.h
@@ -20,7 +20,7 @@
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
- * $Id: aic7xxx.h,v 1.20 1996/01/29 03:17:39 gibbs Exp $
+ * $Id: aic7xxx.h,v 1.21 1996/01/30 22:56:41 mpp Exp $
*/
#ifndef _AIC7XXX_H_
@@ -124,6 +124,8 @@ struct scb {
#define SCB_DEVICE_RESET 0x04
#define SCB_IMMED 0x08
#define SCB_SENSE 0x10
+#define SCB_TIMEDOUT 0x20
+#define SCB_QUEUED_FOR_DONE 0x40
int position; /* Position in scbarray */
struct ahc_dma_seg ahc_dma[AHC_NSEG] __attribute__ ((packed));
struct scsi_sense sense_cmd; /* SCSI command block */
@@ -155,6 +157,7 @@ struct ahc_data {
u_char maxscbs;
u_char unpause;
u_char pause;
+ u_char in_timeout;
};
/* Different debugging levels used when AHC_DEBUG is defined */
diff --git a/sys/i386/scsi/bt.c b/sys/i386/scsi/bt.c
index de69feb..3d7b6fa 100644
--- a/sys/i386/scsi/bt.c
+++ b/sys/i386/scsi/bt.c
@@ -12,7 +12,7 @@
* on the understanding that TFS is not responsible for the correct
* functioning of this software in any circumstances.
*
- * $Id: bt.c,v 1.6 1996/02/16 17:23:56 gibbs Exp $
+ * $Id: bt.c,v 1.7 1996/02/18 07:45:36 gibbs Exp $
*/
/*
@@ -183,7 +183,7 @@ struct bt_ext_info {
u_char bios_addr; /* Bios Address-Not used */
u_short max_seg; /* Max segment List */
u_char num_mbx; /* Number of mailbox */
- int32 mbx_base; /* mailbox base address */
+ int32_t mbx_base; /* mailbox base address */
struct {
u_char resv1:1; /* ??? */
u_char force:1; /* ON: force sync */
@@ -219,7 +219,7 @@ struct bt_sync_value {
static int bt_debug = 0;
SYSCTL_INT(_debug, OID_AUTO, bt_debug, CTLFLAG_RW, &bt_debug, 0, "");
-static u_int32 bt_adapter_info __P((int unit));
+static u_int32_t bt_adapter_info __P((int unit));
static struct bt_ccb *
bt_ccb_phys_kv __P((struct bt_data *bt, physaddr ccb_phys));
#ifdef notyet
@@ -242,7 +242,7 @@ static int bt_poll __P((struct bt_data *bt, struct scsi_xfer *xs,
static void bt_print_active_ccbs __P((int unit));
static void bt_print_ccb __P((struct bt_ccb *ccb));
#endif
-static int32 bt_scsi_cmd __P((struct scsi_xfer *xs));
+static int32_t bt_scsi_cmd __P((struct scsi_xfer *xs));
static BT_MBO * bt_send_mbo __P((struct bt_data *bt, int flags, int cmd,
struct bt_ccb *ccb));
static timeout_t
@@ -526,7 +526,7 @@ bt_attach(bt)
* Return some information to the caller about the adapter and its
* capabilities.
*/
-static u_int32
+static u_int32_t
bt_adapter_info(unit)
int unit;
{
@@ -1237,7 +1237,7 @@ btminphys(bp)
* start a scsi operation given the command and the data address. Also needs
* the unit, target and lu.
*/
-static int32
+static int32_t
bt_scsi_cmd(xs)
struct scsi_xfer *xs;
{
OpenPOWER on IntegriCloud