diff options
author | gibbs <gibbs@FreeBSD.org> | 1997-02-19 01:00:51 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 1997-02-19 01:00:51 +0000 |
commit | 87dca7091fa198d5f1e715636074dafb9e3ce7a9 (patch) | |
tree | 0179b9cffb295365e1454c63f7113b759a83f203 | |
parent | 78b845fbdb6056081bb326a468f74158b3ccdd1a (diff) | |
download | FreeBSD-src-87dca7091fa198d5f1e715636074dafb9e3ce7a9.zip FreeBSD-src-87dca7091fa198d5f1e715636074dafb9e3ce7a9.tar.gz |
Fix some more problems in the recovery code.
Cleanup of the disconnected list was broken in the SCB paging case
(confusion of NULLand SCB_LIST_NULL)
Implement a clean mechanism for determining that we have exited the timeout
state and test for this in ahc_done instead of all over the place.
Bring back the use of AAP (Auto Access Pause) I don't think it was the
true cause of the bus hangs people were reporting.
We want to reset the bus if we've been through an Abort action, not if
we are a recovery SCB (one implies the other, but not vice-versa).
-rw-r--r-- | sys/i386/scsi/aic7xxx.c | 57 |
1 files changed, 37 insertions, 20 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c index 9f0a91a..0788cc2 100644 --- a/sys/i386/scsi/aic7xxx.c +++ b/sys/i386/scsi/aic7xxx.c @@ -1545,13 +1545,6 @@ ahc_handle_scsiint(ahc, intstat) ahc_run_done_queue(ahc); scb = NULL; printerror = 0; - /* - * We only send these for - * error recovery, so if it - * worked, we're no longer in - * a timeout. - */ - ahc->in_timeout = 0; } } } @@ -1727,7 +1720,6 @@ ahc_handle_devreset(ahc, scb) XS_NOERROR); 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); } @@ -1754,7 +1746,8 @@ ahc_done(ahc, scb) xs->error = XS_TIMEOUT; } else if (scb->flags & SCB_SENSE) xs->error = XS_SENSE; - if (scb->flags & SCB_SENTORDEREDTAG) + + if (scb->flags & SCB_RECOVERY_SCB) ahc->in_timeout = FALSE; #if defined(__FreeBSD__) if ((xs->flags & SCSI_ERR_OK) && !(xs->error == XS_SENSE)) { @@ -2454,7 +2447,12 @@ ahc_run_waiting_queue(ahc) { struct scb *scb; - pause_sequencer(ahc); + /* + * 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); while ((scb = ahc->waiting_scbs.stqh_first) != NULL) { @@ -2475,7 +2473,8 @@ ahc_run_waiting_queue(ahc) */ ahc->curqincnt++; } - unpause_sequencer(ahc, /*Unpause always*/FALSE); + if ((ahc->type & AHC_AIC78X0) == 0) + unpause_sequencer(ahc, /*Unpause always*/FALSE); } /* @@ -2781,7 +2780,7 @@ ahc_timeout(arg) /* Decide our course of action */ channel = (scb->hscb->tcl & SELBUSB) ? 'B': 'A'; - if (scb->flags & SCB_RECOVERY_SCB) { + if (scb->flags & SCB_ABORT) { /* * Been down this road before. * Do a full bus reset. @@ -2790,7 +2789,6 @@ ahc_timeout(arg) /*Initiate Reset*/TRUE); printf("%s: Issued Channel %c Bus Reset. " "%d SCBs aborted\n", ahc_name(ahc), channel, found); - ahc->in_timeout = FALSE; } else if ((scb->hscb->control & TAG_ENB) != 0 && (scb->flags & SCB_SENTORDEREDTAG) == 0) { /* @@ -2898,7 +2896,7 @@ ahc_timeout(arg) STAILQ_INSERT_HEAD(&ahc->waiting_scbs, scb, links); timeout(ahc_timeout, (caddr_t)scb, - (100 * hz) / 1000); + (200 * hz) / 1000); ahc_run_waiting_queue(ahc); } ahc_outb(ahc, SCBPTR, saved_scbptr); @@ -2968,7 +2966,8 @@ ahc_search_qinfifo(ahc, target, channel, tag, flags, xs_error, requeue) if (requeue) { STAILQ_INSERT_TAIL(&removed_scbs, scbp, links); } else { - scbp->flags = flags; + scbp->flags |= flags; + scbp->flags &= ~SCB_ACTIVE; scbp->xs->error = xs_error; untimeout(ahc_timeout, (caddr_t)scbp); } @@ -3028,8 +3027,16 @@ ahc_reset_device(ahc, target, channel, tag, xs_error) prev = SCB_LIST_NULL; while (next != SCB_LIST_NULL) { + u_int8_t scb_index; + ahc_outb(ahc, SCBPTR, next); - scbp = ahc->scb_data->scbarray[ahc_inb(ahc, SCB_TAG)]; + scb_index = ahc_inb(ahc, SCB_TAG); + if (scb_index >= ahc->scb_data->numscbs) { + panic("Waiting List inconsistency. " + "SCB index == 0x%d, yet numscbs = 0x%d", + scb_index, ahc->scb_data->numscbs); + } + scbp = ahc->scb_data->scbarray[scb_index]; if (ahc_match_scb(scbp, target, channel, tag)) { next = ahc_abort_wscb(ahc, scbp, next, prev, xs_error); @@ -3054,7 +3061,8 @@ ahc_reset_device(ahc, target, channel, tag, xs_error) ahc_unbusy_target(ahc, target, (scbp->hscb->tcl & SELBUSB) ? 'B' : 'A'); - scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE; + scbp->flags |= SCB_ABORTED|SCB_QUEUED_FOR_DONE; + scbp->flags &= ~SCB_ACTIVE; scbp->xs->error = xs_error; untimeout(ahc_timeout, (caddr_t)scbp); found++; @@ -3072,7 +3080,15 @@ ahc_reset_device(ahc, target, channel, tag, xs_error) prev = SCB_LIST_NULL; while (next != SCB_LIST_NULL) { + u_int8_t scb_index; + ahc_outb(ahc, SCBPTR, next); + scb_index = ahc_inb(ahc, SCB_TAG); + if (scb_index >= ahc->scb_data->numscbs) { + panic("Disconnected List inconsistency. " + "SCB index == 0x%d, yet numscbs = 0x%d", + scb_index, ahc->scb_data->numscbs); + } scbp = ahc->scb_data->scbarray[ahc_inb(ahc, SCB_TAG)]; if (ahc_match_scb(scbp, target, channel, tag)) { u_int8_t curpos; @@ -3086,13 +3102,13 @@ ahc_reset_device(ahc, target, channel, tag, xs_error) ahc_inb(ahc, FREE_SCBH)); ahc_outb(ahc, FREE_SCBH, curpos); - if (prev != NULL) { + if (prev != SCB_LIST_NULL) { ahc_outb(ahc, SCBPTR, prev); ahc_outb(ahc, SCB_NEXT, next); } else ahc_outb(ahc, DISCONNECTED_SCBH, next); - if (next != NULL) { + if (next != SCB_LIST_NULL) { ahc_outb(ahc, SCBPTR, next); ahc_outb(ahc, SCB_NEXT, prev); } @@ -3157,7 +3173,8 @@ ahc_abort_wscb (ahc, scbp, scbpos, prev, xs_error) * has been aborted. */ ahc_outb(ahc, SCBPTR, curscb); - scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE; + scbp->flags |= SCB_ABORTED|SCB_QUEUED_FOR_DONE; + scbp->flags &= ~SCB_ACTIVE; scbp->xs->error = xs_error; untimeout(ahc_timeout, (caddr_t)scbp); return next; |