summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1997-02-11 17:10:37 +0000
committergibbs <gibbs@FreeBSD.org>1997-02-11 17:10:37 +0000
commit9df9fb6692f66cd7ecb90130e35ea7c7c07504dd (patch)
treeadcd95da9a379cc933f356037c59a829dc44ee75
parent9bbf9bfafb9002c185aca9438c31c7cd5d946019 (diff)
downloadFreeBSD-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.c26
-rw-r--r--sys/i386/scsi/aic7xxx.h1
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 */
};
OpenPOWER on IntegriCloud