summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1996-01-29 03:17:39 +0000
committergibbs <gibbs@FreeBSD.org>1996-01-29 03:17:39 +0000
commit2e4a124f9ae278260bdb4283512b7fc2213ab4f5 (patch)
tree9a3c9cdc296b54c0c021259df16fcc83f921e510
parentc2da320533415128fde60a143860b30ced3f1ac6 (diff)
downloadFreeBSD-src-2e4a124f9ae278260bdb4283512b7fc2213ab4f5.zip
FreeBSD-src-2e4a124f9ae278260bdb4283512b7fc2213ab4f5.tar.gz
Changes to support Performance enhancements in the sequencer.
Bring back the polling code (for dumps mostly), but protect it with splbio() to make it safe for reprobes.
-rw-r--r--sys/i386/scsi/aic7xxx.c293
-rw-r--r--sys/i386/scsi/aic7xxx.h17
2 files changed, 175 insertions, 135 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index 2832197..9cc35bd 100644
--- a/sys/i386/scsi/aic7xxx.c
+++ b/sys/i386/scsi/aic7xxx.c
@@ -1,6 +1,6 @@
/*
* Generic driver for the aic7xxx based adaptec SCSI controllers
- * Copyright (c) 1994, 1995 Justin T. Gibbs.
+ * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
* All rights reserved.
*
* Product specific probe and attach routines can be found in:
@@ -24,7 +24,7 @@
*
* commenced: Sun Sep 27 18:14:01 PDT 1992
*
- * $Id: aic7xxx.c,v 1.53 1996/01/07 19:24:31 gibbs Exp $
+ * $Id: aic7xxx.c,v 1.54 1996/01/23 21:47:50 se Exp $
*/
/*
* TODO:
@@ -135,11 +135,13 @@ 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 void ahc_getscb __P((u_long iobase, struct scb *scb));
+static inline void ahc_getscb __P((struct ahc_data *ahc, struct scb *scb,
+ int iosize));
static struct scb *
ahc_get_scb __P((struct ahc_data *ahc, int flags));
static void ahc_loadseq __P((u_long iobase));
static int ahc_match_scb __P((struct scb *scb, int target, char channel));
+static int ahc_poll __P((struct ahc_data *ahc, int wait));
#ifdef AHC_DEBUG
static void ahc_print_active_scb __P((struct ahc_data *ahc));
static void ahc_print_scb __P((struct scb *scb));
@@ -153,7 +155,8 @@ 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_scsirate __P((struct ahc_data* ahc, u_char *scsirate,
int period, int offset, int target));
-static void ahc_send_scb __P((struct ahc_data *ahc, struct scb *scb));
+static inline void ahc_send_scb __P((struct ahc_data *ahc, struct scb *scb,
+ int iosize));
static timeout_t
ahc_timeout;
static void ahc_busy_target __P((int target, char channel,
@@ -434,26 +437,40 @@ ahc_attach(ahc)
return 1;
}
-static void
-ahc_send_scb( ahc, scb )
- struct ahc_data *ahc;
- struct scb *scb;
+/* Send an SCB down to the card via PIO maintaining the SCB pointer */
+static inline void
+ahc_send_scb(ahc, scb, iosize)
+ struct ahc_data *ahc;
+ struct scb *scb;
+ int iosize; /* In bytes */
{
u_long iobase = ahc->baseport;
+ u_char cur_scb;
- PAUSE_SEQUENCER(ahc);
- outb(QINFIFO + iobase, scb->position);
- UNPAUSE_SEQUENCER(ahc);
+ cur_scb = inb(SCBPTR + iobase);
+ outb(SCBPTR + iobase, scb->position);
+ outb(SCBCNT + iobase, SCBAUTO);
+ if( ahc->type == AHC_284 )
+ /* Can only do 8bit PIO */
+ outsb(SCBARRAY+iobase, scb, iosize);
+ else
+ outsl(SCBARRAY+iobase, scb, (iosize + 3) / 4);
+ outb(SCBCNT + iobase, 0);
+ outb(SCBPTR + iobase, cur_scb);
}
-static
-void ahc_getscb(iobase, scb)
- u_long iobase;
- struct scb *scb;
+static inline void
+ahc_getscb(ahc, scb, iosize)
+ struct ahc_data *ahc;
+ struct scb *scb;
+ int iosize;
{
+ u_long iobase = ahc->baseport;
+
outb(SCBCNT + iobase, 0x80); /* SCBAUTO */
- insb(SCBARRAY + iobase, scb, SCB_PIO_TRANSFER_SIZE);
+ /* Can only do 8bit PIO for reads */
+ insb(SCBARRAY+iobase, scb, iosize);
outb(SCBCNT + iobase, 0);
}
@@ -582,7 +599,7 @@ ahc_intr(arg)
printf("SAVED_TCL == 0x%x\n",
inb(SAVED_TCL + iobase));
ahc_unbusy_target(target, channel, iobase);
- outb(SCBARRAY + iobase, NEEDDMA);
+ outb(SCBARRAY + iobase, 0);
outb(CLRSINT1 + iobase, CLRSELTIMEO);
RESTART_SEQUENCER(ahc);
break;
@@ -820,7 +837,7 @@ ahc_intr(arg)
xs = scb->xs;
- ahc_getscb(iobase, scb);
+ ahc_getscb(ahc, scb, SCB_PIO_TRANSFER_SIZE);
#ifdef AHC_DEBUG
if((ahc_debug & AHC_SHOWSCBS)
@@ -875,10 +892,11 @@ ahc_intr(arg)
scb->data = sg->addr;
scb->datalen = sg->len;
- outb(SCBCNT + iobase, 0x80);
- outsb(SCBARRAY+iobase,scb,SCB_PIO_TRANSFER_SIZE);
- outb(SCBCNT + iobase, 0);
- outb(SCB_NEXT_WAITING+iobase,SCB_LIST_NULL);
+
+ ahc_send_scb(ahc, scb,
+ SCB_PIO_TRANSFER_SIZE);
+ outb(SCB_NEXT_WAITING+iobase,
+ SCB_LIST_NULL);
/*
* Ensure that the target is "BUSY"
* so we don't get overlapping
@@ -1012,7 +1030,7 @@ ahc_intr(arg)
outb(MSG_LEN + iobase, 1);
}
else
- panic("ahc_intr: AWAITING_MSG for an SCB that"
+ panic("ahc_intr: AWAITING_MSG for an SCB that "
"does not have a waiting message");
break;
}
@@ -1063,6 +1081,68 @@ ahc_intr(arg)
case MSGIN_PHASEMIS:
break;
#endif
+ case PARITY_ERROR:
+ {
+ /*
+ * Determine the bus phase and
+ * queue an appropriate message
+ */
+ char *phase;
+ u_char mesg_out = MSG_NOP;
+ u_char lastphase = inb(LASTPHASE + iobase);
+ int scb_index = inb(SCBPTR + iobase);
+
+ scb = ahc->scbarray[scb_index];
+
+ sc_print_addr(scb->xs->sc_link);
+
+ switch(lastphase) {
+ case P_DATAOUT:
+ phase = "Data-Out";
+ break;
+ case P_DATAIN:
+ phase = "Data-In";
+ mesg_out = MSG_INITIATOR_DET_ERROR;
+ break;
+ case P_COMMAND:
+ phase = "Command";
+ break;
+ case P_MESGOUT:
+ phase = "Message-Out";
+ break;
+ case P_STATUS:
+ phase = "Status";
+ mesg_out = MSG_INITIATOR_DET_ERROR;
+ break;
+ case P_MESGIN:
+ phase = "Message-In";
+ mesg_out = MSG_MSG_PARITY_ERROR;
+ break;
+ default:
+ phase = "unknown";
+ break;
+ }
+ printf("parity error during %s phase.\n", phase);
+
+ /*
+ * We've set the hardware to assert ATN if we
+ * get a parity error on "in" phases, so all we
+ * need to do is stuff the message buffer with
+ * the appropriate message. In phases have set
+ * mesg_out to something other than MSG_NOP.
+ */
+ if(mesg_out != MSG_NOP) {
+ outb(MSG0 + iobase, mesg_out);
+ outb(MSG_LEN + iobase, 1);
+ }
+ else
+ /*
+ * Should we allow the target to make
+ * this decision for us?
+ */
+ scb->xs->error = XS_DRIVER_STUFFUP;
+ break;
+ }
default:
printf("ahc: seqint, "
"intstat == 0x%x, scsisigi = 0x%x\n",
@@ -1119,7 +1199,7 @@ clear:
? 'B' : 'A',
iobase);
- outb(SCBARRAY + iobase, NEEDDMA);
+ outb(SCBARRAY + iobase, 0);
outb(CLRSINT1 + iobase, CLRSELTIMEO);
@@ -1134,69 +1214,6 @@ clear:
RESTART_SEQUENCER(ahc);
}
- else if (status & SCSIPERR) {
- /*
- * Determine the bus phase and
- * queue an appropriate message
- */
- char *phase;
- u_char mesg_out = MSG_NOP;
- u_char sigstate = inb(SIGSTATE + iobase);
-
- sc_print_addr(xs->sc_link);
-
- switch(sigstate) {
- case P_DATAOUT:
- phase = "Data-Out";
- break;
- case P_DATAIN:
- phase = "Data-In";
- mesg_out = MSG_INITIATOR_DET_ERROR;
- break;
- case P_COMMAND:
- phase = "Command";
- break;
- case P_MESGOUT:
- phase = "Message-Out";
- break;
- case P_STATUS:
- phase = "Status";
- mesg_out = MSG_INITIATOR_DET_ERROR;
- break;
- case P_MESGIN:
- phase = "Message-In";
- mesg_out = MSG_MSG_PARITY_ERROR;
- break;
- default:
- phase = "unknown";
- break;
- }
- printf("parity error during %s phase.\n", phase);
-
- /*
- * We've set the hardware to assert ATN if we
- * get a parity error on "in" phases, so all we
- * need to do is stuff the message buffer with
- * the appropriate message. In phases have set
- * mesg_out to something other than MSG_NOP.
- */
- if(mesg_out != MSG_NOP) {
- outb(MSG0 + iobase, mesg_out);
- outb(MSG_LEN + iobase, 1);
- }
- else
- /*
- * Should we allow the target to make
- * this decision for us?
- */
- scb->xs->error = XS_DRIVER_STUFFUP;
-
- outb(CLRSINT1 + iobase, CLRSCSIPERR);
- UNPAUSE_SEQUENCER(ahc);
-
- outb(CLRINT + iobase, CLRSCSIINT);
- scb = NULL; /* Don't ahc_done the scb */
- }
else if (!(status & BUSFREE)) {
sc_print_addr(xs->sc_link);
printf("Unknown SCSIINT. Status = 0x%x\n", status);
@@ -1360,7 +1377,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|ENSCSIPERR);
+ outb(SIMODE1 + iobase, ENSELTIMO);
if(ahc->type & AHC_ULTRA)
outb(SXFRCTL0 + iobase, DFON|SPIOEN|ULTRAEN);
else
@@ -1377,7 +1394,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|ENSCSIPERR);
+ outb(SIMODE1 + iobase, ENSELTIMO);
if(ahc->type & AHC_ULTRA)
outb(SXFRCTL0 + iobase, DFON|SPIOEN|ULTRAEN);
else
@@ -1689,12 +1706,41 @@ ahc_scsi_cmd(xs)
if((ahc_debug & AHC_SHOWSCBS) && (xs->sc_link->target == DEBUGTARG))
ahc_print_scb(scb);
#endif
- s = splbio();
- ahc_send_scb(ahc, scb);
- timeout(ahc_timeout, (caddr_t)scb, (xs->timeout * hz) / 1000);
- splx(s);
- SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n"));
- return (SUCCESSFULLY_QUEUED);
+ if (!(flags & SCSI_NOMASK)) {
+ s = splbio();
+ PAUSE_SEQUENCER(ahc);
+ ahc_send_scb(ahc, scb, SCB_PIO_TRANSFER_SIZE);
+ outb(QINFIFO + ahc->baseport, scb->position);
+ UNPAUSE_SEQUENCER(ahc);
+ timeout(ahc_timeout, (caddr_t)scb, (xs->timeout * hz) / 1000);
+ splx(s);
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n"));
+ return (SUCCESSFULLY_QUEUED);
+ }
+ /*
+ * If we can't use interrupts, poll for completion
+ */
+ s = splbio();
+ PAUSE_SEQUENCER(ahc);
+ ahc_send_scb(ahc, scb, SCB_PIO_TRANSFER_SIZE);
+ outb(QINFIFO + ahc->baseport, scb->position);
+ UNPAUSE_SEQUENCER(ahc);
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_wait\n"));
+ do {
+ 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);
+ }
+ } while (!(xs->flags & ITSDONE)); /* a non command complete intr */
+ if (xs->error) {
+ splx(s);
+ return (HAD_ERROR);
+ }
+ splx(s);
+ return (COMPLETE);
}
@@ -1762,7 +1808,6 @@ ahc_get_scb(ahc, flags)
scbp = (struct scb *) malloc(sizeof(struct scb),
M_TEMP, M_NOWAIT);
if (scbp) {
- physaddr scbaddr = KVTOPHYS(scbp);
u_long iobase = ahc->baseport;
u_char curscb;
bzero(scbp, sizeof(struct scb));
@@ -1777,28 +1822,6 @@ ahc_get_scb(ahc, flags)
* load it into.
*/
ahc->scbarray[scbp->position] = scbp;
-
- /*
- * Initialize the host memory location
- * of this SCB down on the board and
- * flag that it should be DMA's before
- * reference. Also set its psuedo
- * next pointer (for use in the psuedo
- * list of SCBs waiting for selection)
- * to SCB_LIST_NULL.
- */
- scbp->control = NEEDDMA;
- scbp->host_scb = scbaddr;
- scbp->next_waiting = SCB_LIST_NULL;
- PAUSE_SEQUENCER(ahc);
- curscb = inb(SCBPTR + iobase);
- outb(SCBPTR + iobase, scbp->position);
- outb(SCBCNT + iobase, 0x80);
- outsb(SCBARRAY+iobase,scbp,SCB_HARDWARE_SIZE);
- outb(SCBCNT + iobase, 0);
- outb(SCBPTR + iobase, curscb);
- UNPAUSE_SEQUENCER(ahc);
- scbp->control = 0;
} else {
printf("ahc%d: Can't malloc SCB\n", ahc->unit);
}
@@ -1850,6 +1873,30 @@ static void ahc_loadseq(iobase)
inb(SEQADDR1 + iobase != 0));
}
+/*
+ * Function to poll for command completion when
+ * interrupts are disabled (crash dumps)
+ */
+static int
+ahc_poll(ahc, wait)
+ struct ahc_data *ahc;
+ int wait; /* in msec */
+{
+ u_long iobase = ahc->baseport;
+ u_long stport = INTSTAT + iobase;
+
+ while (--wait) {
+ DELAY(1000);
+ if (inb(stport) & INT_PEND)
+ break;
+ } if (wait == 0) {
+ printf("ahc%d: board not responding\n", ahc->unit);
+ return (EIO);
+ }
+ ahc_intr((void *)ahc);
+ return (0);
+}
+
static void
ahc_scb_timeout(ahc, scb)
struct ahc_data *ahc;
@@ -1932,8 +1979,8 @@ ahc_scb_timeout(ahc, scb)
UNPAUSE_SEQUENCER(ahc);
}
/* Is the active SCB really active? */
- else if((active_scbp->flags & SCB_ACTIVE)
- && (control & NEEDDMA) == NEEDDMA) {
+ else if(active_scbp->flags & SCB_ACTIVE) {
+ /* XXX && (control & NEEDDMA) == NEEDDMA) { */
u_char msg_len = inb(MSG_LEN + iobase);
if(msg_len) {
/*
@@ -2080,7 +2127,7 @@ ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
untimeout(ahc_timeout, (caddr_t)scbp);
ahc_done (ahc, scbp);
outb(SCBPTR + iobase, scbp->position);
- outb(SCBARRAY + iobase, NEEDDMA);
+ outb(SCBARRAY + iobase, 0);
i--;
found++;
}
@@ -2130,7 +2177,7 @@ ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
/* Ensure the target is "free" */
ahc_unbusy_target(target, channel, iobase);
outb(SCBPTR + iobase, scbp->position);
- outb(SCBARRAY + iobase, NEEDDMA);
+ outb(SCBARRAY + iobase, 0);
scbp->flags |= SCB_ABORTED;
scbp->xs->error |= xs_error;
if(scbp->position != timedout_scb)
@@ -2168,7 +2215,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, NEEDDMA);
+ outb(SCBARRAY + iobase, 0);
outb(SCB_NEXT_WAITING + iobase, SCB_LIST_NULL);
ahc_unbusy_target(target, channel, iobase);
diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h
index 9b3dc2e..8bfb807 100644
--- a/sys/i386/scsi/aic7xxx.h
+++ b/sys/i386/scsi/aic7xxx.h
@@ -3,7 +3,7 @@
* SCSI controllers. This is used to implement product specific
* probe and attach routines.
*
- * Copyright (c) 1994, 1995 Justin T. Gibbs.
+ * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -20,7 +20,7 @@
* 4. Modifications may be freely made to this file if the above conditions
* are met.
*
- * $Id: aic7xxx.h,v 1.18 1996/01/07 19:24:33 gibbs Exp $
+ * $Id: aic7xxx.h,v 1.19 1996/01/23 21:47:53 se Exp $
*/
#ifndef _AIC7XXX_H_
@@ -108,19 +108,12 @@ struct scb {
*/
/*20*/ physaddr cmdpointer;
/*24*/ u_char cmdlen;
-/*25*/ u_char RESERVED[2]; /* must be zero */
-#define SCB_PIO_TRANSFER_SIZE 26 /*
- * amount we need to upload/download
- * via rep in/outsb to perform
- * a request sense. The second
- * RESERVED byte is initialized to
- * 0 in get_scb().
+#define SCB_PIO_TRANSFER_SIZE 25 /* amount we need to upload/download
+ * via PIO to initialize a transaction.
*/
-/*27*/ u_char next_waiting; /* Used to thread SCBs awaiting
+/*25*/ u_char next_waiting; /* Used to thread SCBs awaiting
* selection
*/
-/*28*/ physaddr host_scb;
-#define SCB_HARDWARE_SIZE 32
/*-----------------end of hardware supported fields----------------*/
struct scb *next; /* in free list */
struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
OpenPOWER on IntegriCloud