From c646d245b26a8882583044cb5862f5976a449b04 Mon Sep 17 00:00:00 2001 From: "Justin T. Gibbs" Date: Mon, 3 Feb 1997 16:29:07 +0000 Subject: [PATCH] Fix an oversight in the handling of non-tagged abort requests. We need to search the QINFIFO to remove any possible command that is waiting otherwise our abort request may not be held up still waiting for the first command to complete. --- sys/i386/scsi/aic7xxx.c | 106 +++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 34 deletions(-) diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c index da5d1078d8ee..a3e72e011bdd 100644 --- a/sys/i386/scsi/aic7xxx.c +++ b/sys/i386/scsi/aic7xxx.c @@ -277,7 +277,11 @@ static int ahc_poll __P((struct ahc_softc *ahc, int wait)); #ifdef AHC_DEBUG static void ahc_print_scb __P((struct scb *scb)); #endif -static u_int8_t find_scb __P((struct ahc_softc *ahc, struct scb *scb)); +static u_int8_t ahc_find_scb __P((struct ahc_softc *ahc, struct scb *scb)); +static int ahc_search_qinfo __P((struct ahc_softc *ahc, int target, + char channel, u_int8_t tag, + u_int32_t flags, u_int32_t xs_error, + int requeue)); static int ahc_reset_channel __P((struct ahc_softc *ahc, char channel, u_int32_t xs_error, int initiate_reset)); static int ahc_reset_device __P((struct ahc_softc *ahc, int target, @@ -2840,11 +2844,11 @@ ahc_timeout(arg) u_int8_t hscb_index; int disconnected; + hscb_index = ahc_find_scb(ahc, scb); disconnected = FALSE; - hscb_index = find_scb(ahc, scb); - if (hscb_index == SCB_LIST_NULL) + if (hscb_index == SCB_LIST_NULL) { disconnected = TRUE; - else { + } else { ahc_outb(ahc, SCBPTR, hscb_index); if (ahc_inb(ahc, SCB_CONTROL) & DISCONNECTED) disconnected = TRUE; @@ -2870,15 +2874,19 @@ ahc_timeout(arg) * tagged, unbusy it first so that we don't * get held back from sending the command. */ - STAILQ_INSERT_HEAD(&ahc->waiting_scbs, scb, - links); - if ((scb->hscb->control & TAG_ENB) != 0) { + if ((scb->hscb->control & TAG_ENB) == 0) { u_int8_t target; target = scb->xs->sc_link->target; ahc_unbusy_target(ahc, target, channel); + ahc_search_qinfo(ahc, target, + channel, + SCB_LIST_NULL, + 0, 0, + /*requeue*/TRUE); } - + STAILQ_INSERT_HEAD(&ahc->waiting_scbs, scb, + links); timeout(ahc_timeout, (caddr_t)scb, (100 * hz) / 1000); ahc_run_waiting_queue(ahc); @@ -2900,7 +2908,7 @@ ahc_timeout(arg) * card is already paused. */ static u_int8_t -find_scb(ahc, scb) +ahc_find_scb(ahc, scb) struct ahc_softc *ahc; struct scb *scb; { @@ -2921,6 +2929,56 @@ find_scb(ahc, scb) return curindex; } +static int +ahc_search_qinfo(ahc, target, channel, tag, flags, xs_error, requeue) + struct ahc_softc *ahc; + int target; + char channel; + u_int8_t tag; + u_int32_t flags; + u_int32_t xs_error; + int requeue; +{ + u_int8_t saved_queue[AHC_SCB_MAX]; + u_int8_t queued = ahc_inb(ahc, QINCNT) & ahc->qcntmask; + int i; + int found; + struct scb *scbp; + STAILQ_HEAD(, scb) removed_scbs; + + for (i = 0; i < (queued - found); i++) { + saved_queue[i] = ahc_inb(ahc, QINFIFO); + scbp = ahc->scb_data->scbarray[saved_queue[i]]; + if (ahc_match_scb(scbp, target, channel, tag)) { + /* + * We found an scb that needs to be removed. + */ + if (requeue) { + STAILQ_INSERT_TAIL(&removed_scbs, scbp, links); + } else { + scbp->flags = flags; + scbp->xs->error = xs_error; + untimeout(ahc_timeout, (caddr_t)scbp); + } + i--; + found++; + } + } + /* Now put the saved scbs back. */ + for (queued = 0; queued < i; queued++) + ahc_outb(ahc, QINFIFO, saved_queue[queued]); + + if (requeue) { + while ((scbp = removed_scbs.stqh_first) != NULL) { + STAILQ_REMOVE_HEAD(&removed_scbs, links); + STAILQ_INSERT_HEAD(&ahc->waiting_scbs, scbp, links); + } + } + + return found; +} + + /* * The device at the given target/channel has been reset. Abort * all active and queued scbs for that target/channel. @@ -2936,37 +2994,17 @@ ahc_reset_device(ahc, target, channel, tag, xs_error) struct scb *scbp; u_char active_scb; int i = 0; - int found = 0; + int found; /* restore this when we're done */ active_scb = ahc_inb(ahc, SCBPTR); /* - * Search the QINFIFO. + * Remove any entries from the Queue-In FIFO. */ - { - u_int8_t saved_queue[AHC_SCB_MAX]; - u_int8_t queued = ahc_inb(ahc, QINCNT) & ahc->qcntmask; - - for (i = 0; i < (queued - found); i++) { - saved_queue[i] = ahc_inb(ahc, QINFIFO); - scbp = ahc->scb_data->scbarray[saved_queue[i]]; - if (ahc_match_scb(scbp, target, channel, tag)) { - /* - * We found an scb that needs to be aborted. - */ - scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE; - scbp->xs->error = xs_error; - untimeout(ahc_timeout, (caddr_t)scbp); - i--; - found++; - } - } - /* Now put the saved scbs back. */ - for (queued = 0; queued < i; queued++) { - ahc_outb(ahc, QINFIFO, saved_queue[queued]); - } - } + found = ahc_search_qinfo(ahc, target, channel, tag, + SCB_ABORTED|SCB_QUEUED_FOR_DONE, xs_error, + /*requeue*/FALSE); /* * Search waiting for selection list.