summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1997-04-18 16:34:36 +0000
committergibbs <gibbs@FreeBSD.org>1997-04-18 16:34:36 +0000
commitdfe412521254a2c8c4f00d20c8020c9b6a75d103 (patch)
treefcdbdb5858927acecbf601e0f130c2eed936eab4
parent5cc94ca0386ef159015acc3680ed8b596e2952d7 (diff)
downloadFreeBSD-src-dfe412521254a2c8c4f00d20c8020c9b6a75d103.zip
FreeBSD-src-dfe412521254a2c8c4f00d20c8020c9b6a75d103.tar.gz
No longer use AAP for queueing SCBs to the QINFIFO.
Clean up the unexpected busfree handler. We now look directly at the message that might have caused the bus free to occur instead of looking at an SCB flag. This makes the handling more robust and also allows for recovery actions that might cause an "unexpected busfree" to be performed even if an SCB is not availible to "tag". Most notably, this happens when we don't find an SCB for a reconnecting target.
-rw-r--r--sys/i386/scsi/aic7xxx.c142
1 files changed, 63 insertions, 79 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index 52ca36f..77a9981 100644
--- a/sys/i386/scsi/aic7xxx.c
+++ b/sys/i386/scsi/aic7xxx.c
@@ -32,7 +32,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: aic7xxx.c,v 1.115 1997/04/10 19:14:58 gibbs Exp $
+ * $Id: aic7xxx.c,v 1.116 1997/04/14 02:27:50 gibbs Exp $
*/
/*
* TODO:
@@ -279,7 +279,7 @@ static void ahc_handle_seqint __P((struct ahc_softc *ahc, u_int8_t intstat));
static void ahc_handle_scsiint __P((struct ahc_softc *ahc,
u_int8_t intstat));
static void ahc_handle_devreset __P((struct ahc_softc *ahc,
- struct scb *scb));
+ int target, char channel));
static void ahc_loadseq __P((struct ahc_softc *ahc));
static struct patch *
ahc_next_patch __P((struct patch *cur_patch, int options,
@@ -896,14 +896,17 @@ ahc_handle_seqint(ahc, intstat)
*/
u_int8_t scb_index;
u_int8_t busy_scbid;
+ u_int8_t arg1;
busy_scbid = ahc_index_busy_target(ahc, target, channel,
/*unbusy*/FALSE);
- scb_index = ahc_inb(ahc, ARG_1);
+ arg1 = ahc_inb(ahc, ARG_1);
- if (scb_index == SCB_LIST_NULL)
+ if (arg1 == SCB_LIST_NULL)
/* Untagged Request */
scb_index = busy_scbid;
+ else
+ scb_index = arg1;
if (scb_index < ahc->scb_data->numscbs) {
scb = ahc->scb_data->scbarray[scb_index];
@@ -925,26 +928,16 @@ ahc_handle_seqint(ahc, intstat)
}
}
- /*
- * We expect a busfree to occur, so don't bother to interrupt
- * when it happens - we've already handled the error.
- */
- ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
-
- /*
- * XXX Don't know why this happened or which transaction
- * caused it, so we have to be pretty heavy handed. We should
- * probably modify the sequencer so we can issue a bus device
- * reset instead of an abort in this case.
- */
- ahc_reset_device(ahc, target, channel, ALL_LUNS, SCB_LIST_NULL,
- XS_TIMEOUT);
-
printf("%s:%c:%d: no active SCB for reconnecting "
- "target - issuing ABORT\n",
+ "target - issuing BUS DEVICE RESET\n",
ahc_name(ahc), channel, target);
- printf("SAVED_TCL == 0x%x\n",
- ahc_inb(ahc, SAVED_TCL));
+ printf("SAVED_TCL == 0x%x ARG_1 == 0x%x SEQADDR == 0x%x\n",
+ ahc_inb(ahc, SAVED_TCL), arg1,
+ (ahc_inb(ahc, SEQADDR1) << 8)
+ | ahc_inb(ahc, SEQADDR0));
+
+ ahc_handle_devreset(ahc, target, channel);
+
break;
}
case NO_MATCH_BUSY:
@@ -1586,51 +1579,49 @@ ahc_handle_scsiint(ahc, intstat)
* our abort requests.
*/
u_int8_t lastphase = ahc_inb(ahc, LASTPHASE);
- u_int8_t target = (ahc_inb(ahc, SCSIID) >> 4) & 0x0f;
- u_int8_t scbptr = ahc_inb(ahc, SCBPTR);
- u_int8_t scb_control = ahc_inb(ahc, SCB_CONTROL);
+ u_int8_t target = (ahc_inb(ahc, SAVED_TCL) >> 4) & 0x0f;
char channel = ahc_inb(ahc, SBLKCTL) & SELBUSB ? 'B': 'A';
int printerror = 1;
ahc_outb(ahc, SCSISEQ, 0);
- if (lastphase != P_BUSFREE) {
- u_int8_t flags = ahc_inb(ahc, SEQ_FLAGS)
- & (IDENTIFY_SEEN|RESELECTED);
+ if (lastphase == P_MESGOUT) {
+ u_int8_t sindex;
+ u_int8_t message;
- if (flags == 0 || flags == (IDENTIFY_SEEN|RESELECTED)) {
- /*
- * We have an SCB we have to clean up.
- */
- /* Did we ask for this?? */
- if ((lastphase == P_MESGOUT
- || lastphase == P_MESGIN) && scb != NULL) {
- if (scb->flags & SCB_DEVICE_RESET) {
- ahc_handle_devreset(ahc, scb);
- scb = NULL;
- printerror = 0;
- } else if (scb->flags & SCB_ABORT) {
- struct hardware_scb *hscb;
- u_int8_t tag;
-
- hscb = scb->hscb;
- tag = SCB_LIST_NULL;
- sc_print_addr(scb->xs->sc_link);
- printf("SCB %d - Abort "
- "Completed.\n",
- scbptr);
- if (hscb->control & TAG_ENB)
- tag = scb->hscb->tag;
- ahc_reset_device(ahc,
- target,
- channel,
- SCB_LUN(scb),
- tag,
- XS_TIMEOUT);
- ahc_run_done_queue(ahc);
- scb = NULL;
- printerror = 0;
- }
- }
+ sindex = ahc_inb(ahc, SINDEX);
+ message = ahc_inb(ahc, sindex - 1);
+
+ if (message == MSG_ABORT) {
+
+ sc_print_addr(scb->xs->sc_link);
+ printf("SCB %d - Abort Completed.\n",
+ scb->hscb->tag);
+ ahc_reset_device(ahc, target, channel,
+ SCB_LUN(scb),
+ SCB_LIST_NULL,
+ XS_TIMEOUT);
+ ahc_run_done_queue(ahc);
+ scb = NULL;
+ printerror = 0;
+ } else if (message == MSG_ABORT_TAG) {
+
+ sc_print_addr(scb->xs->sc_link);
+ printf("SCB %d - Abort Tag Completed.\n",
+ scb->hscb->tag);
+ ahc_reset_device(ahc,
+ target,
+ channel,
+ SCB_LUN(scb),
+ scb->hscb->tag,
+ XS_TIMEOUT);
+ ahc_run_done_queue(ahc);
+ scb = NULL;
+ printerror = 0;
+ } else if (message == MSG_BUS_DEV_RESET) {
+ ahc_handle_devreset(ahc, target,
+ channel);
+ scb = NULL;
+ printerror = 0;
}
}
if (printerror != 0) {
@@ -1812,16 +1803,14 @@ ahc_handle_scsiint(ahc, intstat)
}
static void
-ahc_handle_devreset(ahc, scb)
+ahc_handle_devreset(ahc, target, channel)
struct ahc_softc *ahc;
- struct scb *scb;
+ int target;
+ char channel;
{
u_int16_t targ_mask;
u_int8_t targ_scratch;
- int target = scb->xs->sc_link->target;
- int lun = scb->xs->sc_link->lun;
int scratch_offset = target;
- char channel = (scb->hscb->tcl & SELBUSB) ? 'B': 'A';
int found;
if (channel == 'B')
@@ -1838,10 +1827,10 @@ ahc_handle_devreset(ahc, scb)
targ_scratch = ahc_inb(ahc, TARG_SCRATCH + scratch_offset);
targ_scratch &= SXFR;
ahc_outb(ahc, TARG_SCRATCH + scratch_offset, targ_scratch);
- sc_print_addr(scb->xs->sc_link);
- found = ahc_reset_device(ahc, target, channel, lun,
+ found = ahc_reset_device(ahc, target, channel, ALL_LUNS,
SCB_LIST_NULL, XS_NOERROR);
- printf("Bus Device Reset delivered. %d SCBs aborted\n", found);
+ printf("%s: Bus Device Reset delivered. %d SCBs aborted\n",
+ ahc_name(ahc), found);
ahc_run_done_queue(ahc);
}
@@ -2580,12 +2569,7 @@ ahc_run_waiting_queue(ahc)
{
struct scb *scb;
- /*
- * On aic78X0 chips, we rely on Auto Access Pause (AAP)
- * instead of doing an explicit pause/unpause.
- */
- if ((ahc->type & AHC_AIC78X0) == 0)
- pause_sequencer(ahc);
+ pause_sequencer(ahc);
while ((scb = ahc->waiting_scbs.stqh_first) != NULL) {
@@ -2597,6 +2581,7 @@ ahc_run_waiting_queue(ahc)
}
STAILQ_REMOVE_HEAD(&ahc->waiting_scbs, links);
scb->flags &= ~SCB_WAITINGQ;
+
ahc_outb(ahc, QINFIFO, scb->hscb->tag);
if ((ahc->flags & AHC_PAGESCBS) != 0)
@@ -2607,8 +2592,7 @@ ahc_run_waiting_queue(ahc)
*/
ahc->curqincnt++;
}
- if ((ahc->type & AHC_AIC78X0) == 0)
- unpause_sequencer(ahc, /*Unpause always*/FALSE);
+ unpause_sequencer(ahc, /*Unpause always*/FALSE);
}
/*
@@ -3118,7 +3102,7 @@ bus_reset:
if (hscb_index == SCB_LIST_NULL) {
disconnected = TRUE;
linked_next = (scb->hscb->datalen >> 24)
- & 0xFF000000;
+ & 0xFF;
} else {
ahc_outb(ahc, SCBPTR, hscb_index);
if (ahc_inb(ahc, SCB_CONTROL) & DISCONNECTED)
OpenPOWER on IntegriCloud