summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin T. Gibbs <gibbs@FreeBSD.org>1996-11-22 08:28:45 +0000
committerJustin T. Gibbs <gibbs@FreeBSD.org>1996-11-22 08:28:45 +0000
commitccddabb0c768d9fb5aadb13a7f03cffce5cbce5f (patch)
tree624e6ab7e83a38272bd5fbeeee1a0f71a09ccd7d
parenta33b54a06139a979823db133626cf2161bf8fb08 (diff)
Notes
-rw-r--r--sys/i386/scsi/aic7xxx.c182
1 files changed, 130 insertions, 52 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c
index 058d4aa52afd..a098f13f087e 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.85 1996/11/11 05:24:44 gibbs Exp $
+ * $Id: aic7xxx.c,v 1.86 1996/11/16 01:19:14 gibbs Exp $
*/
/*
* TODO:
@@ -254,6 +254,8 @@ static void ahc_done __P((struct ahc_softc *ahc, struct scb *scbp));
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));
static void ahc_loadseq __P((struct ahc_softc *ahc));
static int ahc_match_scb __P((struct scb *scb, int target, char channel));
static int ahc_poll __P((struct ahc_softc *ahc, int wait));
@@ -951,6 +953,7 @@ ahc_handle_seqint(ahc, intstat)
* transfers.
*/
if ((ahc->sdtrpending & targ_mask) != 0) {
+ /* We started it */
if (saved_offset == offset) {
/*
* Don't send an SDTR back to
@@ -1233,6 +1236,10 @@ ahc_handle_seqint(ahc, intstat)
*/
STAILQ_INSERT_TAIL(&ahc->waiting_scbs, scb,
links);
+ /* Give the command a new lease on life */
+ untimeout(ahc_timeout, (caddr_t)scb);
+ timeout(ahc_timeout, (caddr_t)scb,
+ (scb->xs->timeout * hz) / 1000);
break;
}
/* Else treat as if it is a BUSY condition */
@@ -1322,44 +1329,6 @@ ahc_handle_seqint(ahc, intstat)
"does not have a waiting message");
break;
}
- case IMMEDDONE:
- {
- /*
- * Take care of device reset messages
- */
- u_int8_t scbindex = ahc_inb(ahc, SCB_TAG);
-
- scb = ahc->scb_data->scbarray[scbindex];
- if (scb->flags & SCB_DEVICE_RESET) {
- u_int8_t targ_scratch;
- int found;
- /*
- * Go back to async/narrow transfers and
- * renegotiate.
- */
- ahc_unbusy_target(ahc, target, channel);
- ahc->needsdtr |= ahc->needsdtr_orig & targ_mask;
- ahc->needwdtr |= ahc->needwdtr_orig & targ_mask;
- ahc->sdtrpending &= ~targ_mask;
- ahc->wdtrpending &= ~targ_mask;
- targ_scratch = ahc_inb(ahc, TARG_SCRATCH
- + scratch_offset);
- targ_scratch &= SXFR;
- ahc_outb(ahc, TARG_SCRATCH + scratch_offset,
- targ_scratch);
- found = ahc_reset_device(ahc, target,
- channel, NULL,
- 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);
- } else
- panic("ahc_intr: Immediate complete for "
- "unknown operation.");
- break;
- }
case DATA_OVERRUN:
{
/*
@@ -1465,9 +1434,15 @@ ahc_handle_scsiint(ahc, intstat)
scb_index = ahc_inb(ahc, SCB_TAG);
status = ahc_inb(ahc, SSTAT1);
- scb = ahc->scb_data->scbarray[scb_index];
- if (status & SCSIRSTI) {
+ if (scb_index < ahc->scb_data->numscbs) {
+ scb = ahc->scb_data->scbarray[scb_index];
+ if ((scb->flags & SCB_ACTIVE) == 0)
+ scb = NULL;
+ } else
+ scb = NULL;
+
+ if ((status & SCSIRSTI) != 0) {
char channel;
channel = (ahc_inb(ahc, SBLKCTL) & SELBUSB) ? 'B' : 'A';
printf("%s: Someone reset channel %c\n",
@@ -1478,7 +1453,80 @@ ahc_handle_scsiint(ahc, intstat)
XS_BUSY,
/* Initiate Reset */FALSE);
scb = NULL;
- } else if (!(scb && (scb->flags & SCB_ACTIVE))){
+ } else if ((status & BUSFREE) != 0 && (status & SELTO) == 0) {
+ /*
+ * First look at what phase we were last in.
+ * If its message out, chances are pretty good
+ * that the busfree was in response to one of
+ * our abort requests.
+ */
+ u_int8_t lastphase = ahc_inb(ahc, LASTPHASE);
+ u_int8_t target = (ahc_inb(ahc, SCSIID) >> 4) & 0x0f;
+ char channel = ahc_inb(ahc, SBLKCTL) & SELBUSB ? 'B': 'A';
+ int printerror = 1;
+
+ if (lastphase != P_BUSFREE) {
+ u_int8_t flags = ahc_inb(ahc, FLAGS)
+ & (IDENTIFY_SEEN|RESELECTED);
+
+ if (flags == 0 || flags == (IDENTIFY_SEEN|RESELECTED)) {
+ /*
+ * We have an SCB we have to clean up.
+ */
+ u_int8_t next;
+
+ next = ahc_unbusy_target(ahc, target, channel);
+
+ if (next != SCB_LIST_NULL) {
+ if (ahc->flags & AHC_PAGESCBS) {
+ /* Use the current SCB */
+ struct hardware_scb *hscb;
+
+ hscb = &ahc->scb_data->hscbs[next];
+ ahc_outb(ahc, SCBCNT, SCBAUTO);
+ ahc_outsb(ahc, SCBARRAY,
+ (u_int8_t *)hscb, 28);
+ ahc_outb(ahc, SCBCNT, 0);
+ } else
+ /* Just switch to the SCB */
+ ahc_outb(ahc, SCBPTR, next);
+
+ /* Add this SCB as the next to run */
+ ahc_outb(ahc, SCB_NEXT,
+ ahc_inb(ahc, WAITING_SCBH));
+ ahc_outb(ahc, WAITING_SCBH,
+ ahc_inb(ahc, SCBPTR));
+ } else {
+ /* Add us to the Free list */
+ ahc_outb(ahc, SCB_NEXT,
+ ahc_inb(ahc, FREE_SCBH));
+ ahc_outb(ahc, FREE_SCBH,
+ ahc_inb(ahc, SCBPTR));
+ }
+
+ /* Did we ask for this?? */
+ if (lastphase == P_MESGOUT && scb != NULL) {
+ if (scb->flags & SCB_DEVICE_RESET) {
+ ahc_handle_devreset(ahc, scb);
+ printerror = 0;
+ } else if (scb->flags & SCB_ABORTED) {
+ ahc_done(ahc, scb);
+ printerror = 0;
+ }
+ }
+ }
+ }
+ if (printerror != 0) {
+ if (scb != NULL) {
+ scb->xs->error = XS_DRIVER_STUFFUP;
+ sc_print_addr(scb->xs->sc_link);
+ ahc_done(ahc, scb);
+ } else
+ printf("%s: ", ahc_name(ahc));
+ printf("Unexpected busfree. LASTPHASE == 0x%x\n",
+ lastphase);
+ }
+ } else if (scb == NULL) {
printf("%s: ahc_intr - referenced scb not "
"valid during scsiint 0x%x scb(%d)\n",
ahc_name(ahc), status, scb_index);
@@ -1486,7 +1534,7 @@ ahc_handle_scsiint(ahc, intstat)
unpause_sequencer(ahc, /*unpause_always*/TRUE);
ahc_outb(ahc, CLRINT, CLRSCSIINT);
scb = NULL;
- } else if (status & SCSIPERR) {
+ } else if ((status & SCSIPERR) != 0) {
/*
* Determine the bus phase and
* queue an appropriate message
@@ -1543,7 +1591,7 @@ ahc_handle_scsiint(ahc, intstat)
* this decision for us?
*/
xs->error = XS_DRIVER_STUFFUP;
- } else if (status & SELTO) {
+ } else if ((status & SELTO) != 0) {
struct scsi_xfer *xs;
u_int8_t scbptr;
u_int8_t nextscb;
@@ -1579,7 +1627,7 @@ ahc_handle_scsiint(ahc, intstat)
ahc_outb(ahc, SCB_NEXT, nextscb);
ahc_outb(ahc, FREE_SCBH, scbptr);
restart_sequencer(ahc);
- } else if (!(status & BUSFREE)) {
+ } else {
sc_print_addr(scb->xs->sc_link);
printf("Unknown SCSIINT. Status = 0x%x\n", status);
ahc_outb(ahc, CLRSINT1, status);
@@ -1594,7 +1642,40 @@ ahc_handle_scsiint(ahc, intstat)
}
}
-
+static void
+ahc_handle_devreset(ahc, scb)
+ struct ahc_softc *ahc;
+ struct scb *scb;
+{
+ u_int16_t targ_mask;
+ u_int8_t targ_scratch;
+ u_int8_t target = scb->xs->sc_link->target;
+ int scratch_offset = target;
+ char channel = (scb->hscb->tcl & SELBUSB) ? 'B': 'A';
+ int found;
+
+ if (channel == 'B')
+ scratch_offset += 8;
+ targ_mask = (0x01 << scratch_offset);
+ /*
+ * Go back to async/narrow transfers and
+ * renegotiate.
+ */
+ ahc_unbusy_target(ahc, target, channel);
+ ahc->needsdtr |= ahc->needsdtr_orig & targ_mask;
+ ahc->needwdtr |= ahc->needwdtr_orig & targ_mask;
+ ahc->sdtrpending &= ~targ_mask;
+ ahc->wdtrpending &= ~targ_mask;
+ targ_scratch = ahc_inb(ahc, TARG_SCRATCH + scratch_offset);
+ targ_scratch &= SXFR;
+ ahc_outb(ahc, TARG_SCRATCH + scratch_offset, targ_scratch);
+ found = ahc_reset_device(ahc, target, channel, NULL, 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);
+}
+
/*
* We have a scb which has been processed by the
* adaptor, now we look to see how the operation
@@ -1612,14 +1693,11 @@ ahc_done(ahc, scb)
* Put the results of the operation
* into the xfer and call whoever started it
*/
-#if defined(__NetBSD__)
if (xs->error != XS_NOERROR) {
/* Don't override the error value. */
} else if (scb->flags & SCB_ABORTED) {
xs->error = XS_DRIVER_STUFFUP;
- } else
-#endif
- if (scb->flags & SCB_SENSE)
+ } else if (scb->flags & SCB_SENSE)
xs->error = XS_SENSE;
if (scb->flags & SCB_SENTORDEREDTAG)
ahc->in_timeout = FALSE;
@@ -3090,8 +3168,8 @@ ahc_calc_residual(scb)
}
/*
- * Clean out the residual information in this SCB for the
- * next consumer of this SCB.
+ * Clean out the residual information in this SCB for its
+ * next consumer.
*/
hscb->residual_data_count[2] = 0;
hscb->residual_data_count[1] = 0;