diff options
author | gibbs <gibbs@FreeBSD.org> | 1997-02-11 17:10:37 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 1997-02-11 17:10:37 +0000 |
commit | 9df9fb6692f66cd7ecb90130e35ea7c7c07504dd (patch) | |
tree | adcd95da9a379cc933f356037c59a829dc44ee75 | |
parent | 9bbf9bfafb9002c185aca9438c31c7cd5d946019 (diff) | |
download | FreeBSD-src-9df9fb6692f66cd7ecb90130e35ea7c7c07504dd.zip FreeBSD-src-9df9fb6692f66cd7ecb90130e35ea7c7c07504dd.tar.gz |
Fix a bug in the reporting of residuals. The code was relying on the SG_COUNT
filed in the hardware SCB not changing during the course of a transaction.
Since the sequencer now DMAs the hardware SCB back up to the host when it
detects a residual, this is no longer the case. I added a field to the
"software" scb to mirror this information and it is now used for doing the
residual calculation.
-rw-r--r-- | sys/i386/scsi/aic7xxx.c | 26 | ||||
-rw-r--r-- | sys/i386/scsi/aic7xxx.h | 1 |
2 files changed, 22 insertions, 5 deletions
diff --git a/sys/i386/scsi/aic7xxx.c b/sys/i386/scsi/aic7xxx.c index 62c9de5..3b20b33 100644 --- a/sys/i386/scsi/aic7xxx.c +++ b/sys/i386/scsi/aic7xxx.c @@ -1208,7 +1208,7 @@ ahc_handle_seqint(ahc, intstat) hscb->datalen |= sg->len; hscb->cmdpointer = vtophys(sc); hscb->cmdlen = sizeof(*sc); - + scb->sg_count = hscb->SG_segment_count; scb->flags |= SCB_SENSE; ahc_outb(ahc, RETURN_1, SEND_SENSE); @@ -1344,15 +1344,29 @@ ahc_handle_seqint(ahc, intstat) * BITBUCKET mode. */ u_int8_t scbindex = ahc_inb(ahc, SCB_TAG); + u_int8_t lastphase = ahc_inb(ahc, LASTPHASE); u_int32_t overrun; + int i; scb = ahc->scb_data->scbarray[scbindex]; overrun = ahc_inb(ahc, STCNT0) | (ahc_inb(ahc, STCNT1) << 8) | (ahc_inb(ahc, STCNT2) << 16); overrun = 0x00ffffff - overrun; sc_print_addr(scb->xs->sc_link); - printf("data overrun of %d bytes detected." - " Forcing a retry.\n", overrun); + printf("data overrun of %d bytes detected in %s phase." + " Tag == 0x%x. Forcing a retry.\n", overrun, + lastphase == P_DATAIN ? "Data-In" : "Data-Out", + scb->hscb->tag); + sc_print_addr(scb->xs->sc_link); + printf("%s seen Data Phase. Length = %d. NumSGs = %d.\n", + ahc_inb(ahc, FLAGS) & DPHASE ? "Have" : "Haven't", + scb->xs->datalen, scb->sg_count); + for (i = 0; i < scb->sg_count; i++) { + printf("sg[%d] - Addr 0x%x : Length %d\n", + i, + scb->ahc_dma[i].addr, + scb->ahc_dma[i].len); + } /* * Set this and it will take affect when the * target does a command complete. @@ -2374,6 +2388,7 @@ ahc_scsi_cmd(xs) sg++; } hscb->SG_segment_count = seg; + scb->sg_count = hscb->SG_segment_count; /* Copy the first SG into the data pointer area */ hscb->data = scb->ahc_dma->addr; @@ -2395,6 +2410,7 @@ ahc_scsi_cmd(xs) * No data xfer, use non S/G values */ hscb->SG_segment_count = 0; + scb->sg_count = hscb->SG_segment_count; hscb->SG_list_pointer = 0; hscb->data = 0; hscb->datalen = (SCB_LIST_NULL << 24); @@ -3443,11 +3459,11 @@ ahc_calc_residual(scb) * SG segments that are after the SG where * the transfer stopped. */ - resid_sgs = hscb->residual_SG_segment_count - 1; + resid_sgs = scb->hscb->residual_SG_segment_count - 1; while (resid_sgs > 0) { int sg; - sg = hscb->SG_segment_count - resid_sgs; + sg = scb->sg_count - resid_sgs; xs->resid += scb->ahc_dma[sg].len; resid_sgs--; } diff --git a/sys/i386/scsi/aic7xxx.h b/sys/i386/scsi/aic7xxx.h index 1d857ca..c22431b 100644 --- a/sys/i386/scsi/aic7xxx.h +++ b/sys/i386/scsi/aic7xxx.h @@ -209,6 +209,7 @@ struct scb { scb_flag flags; struct ahc_dma_seg *ahc_dma;/* Pointer to SG segments */ struct scsi_sense sense_cmd; + u_int8_t sg_count;/* How full ahc_dma_seg is */ u_int8_t position;/* Position in card's scbarray */ }; |