diff --git a/sys/dev/ic/esiop.c b/sys/dev/ic/esiop.c index c905d6befe2c..496103dd5fd4 100644 --- a/sys/dev/ic/esiop.c +++ b/sys/dev/ic/esiop.c @@ -1,4 +1,4 @@ -/* $NetBSD: esiop.c,v 1.27 2004/03/16 19:10:43 bouyer Exp $ */ +/* $NetBSD: esiop.c,v 1.28 2004/05/17 11:10:24 bouyer Exp $ */ /* * Copyright (c) 2002 Manuel Bouyer. @@ -33,7 +33,7 @@ /* SYM53c7/8xx PCI-SCSI I/O Processors driver */ #include -__KERNEL_RCSID(0, "$NetBSD: esiop.c,v 1.27 2004/03/16 19:10:43 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: esiop.c,v 1.28 2004/05/17 11:10:24 bouyer Exp $"); #include #include @@ -627,7 +627,13 @@ none: * and the command should terminate. */ INCSTAT(esiop_stat_intr_shortxfer); - if ((dstat & DSTAT_DFE) == 0) + /* + * sdp not needed here, but this + * will cause xs->resid to be adjusted + */ + if (scratchc0 & A_f_c_data) + siop_sdp(&esiop_cmd->cmd_c); + else if ((dstat & DSTAT_DFE) == 0) siop_clearfifo(&sc->sc_c); /* no table to flush here */ CALL_SCRIPT(Ent_status); @@ -709,7 +715,7 @@ none: esiop_cmd->cmd_c.status = CMDST_DONE; xs->error = XS_SELTIMEOUT; freetarget = 1; - goto end; + goto end_nodata; } else { printf("%s: selection timeout without " "command, target %d (sdid 0x%x), " @@ -728,7 +734,7 @@ none: if (esiop_cmd) { esiop_cmd->cmd_tables->status = htole32(SCSI_CHECK); - goto end; + goto end_nodata; } printf("%s: unexpected disconnect without " "command\n", sc->sc_c.sc_dev.dv_xname); @@ -766,7 +772,7 @@ none: if (esiop_cmd) { esiop_cmd->cmd_c.status = CMDST_DONE; xs->error = XS_SELTIMEOUT; - goto end; + goto end_nodata; } need_reset = 1; } @@ -811,7 +817,7 @@ scintr: sc->sc_c.sc_rh, SIOP_DSP) - sc->sc_c.sc_scriptaddr)); if (xs) { xs->error = XS_SELTIMEOUT; - goto end; + goto end_nodata; } else { goto reset; } @@ -1050,6 +1056,15 @@ scintr: * Don't call memmove in this case. */ if (offset < SIOP_NSG) { + int i; + /* + * adjust xs->resid for already-transfered + * data + */ + for (i = 0; i < offset; i++) + xs->resid -= le32toh( + esiop_cmd->cmd_tables->data[i].count + ); memmove(&esiop_cmd->cmd_tables->data[0], &esiop_cmd->cmd_tables->data[offset], (SIOP_NSG - offset) * sizeof(scr_table_t)); @@ -1083,7 +1098,7 @@ scintr: printf("unknown irqcode %x\n", irqcode); if (xs) { xs->error = XS_SELTIMEOUT; - goto end; + goto end_nodata; } goto reset; } @@ -1092,6 +1107,12 @@ scintr: /* We just should't get there */ panic("siop_intr: I shouldn't be there !"); +end_nodata: + /* + * no data was transfered, and the script didn't update tlp with the + * current offset (which is still 0) + */ + ((struct esiop_xfer *)esiop_cmd->cmd_tables)->tlq = 0; end: /* * restart the script now if command completed properly @@ -1119,6 +1140,21 @@ esiop_scsicmd_end(esiop_cmd) { struct scsipi_xfer *xs = esiop_cmd->cmd_c.xs; struct esiop_softc *sc = (struct esiop_softc *)esiop_cmd->cmd_c.siop_sc; + int offset, i; + + /* scratcha was saved in tlq by script. fetch offset from it */ + offset = + (le32toh(((struct esiop_xfer *)esiop_cmd->cmd_tables)->tlq) >> 8) + & 0xff; + /* + * update resid. If we completed a xfer with + * some data transfers, offset will be at last 1. + * If it's 0 then either no data was transfered at + * all, or resid was already adjusted by a save + * data pointer, or a phase mismatch. + */ + for (i = 0; i < offset; i++) + xs->resid -= le32toh(esiop_cmd->cmd_tables->data[i].count); switch(xs->status) { case SCSI_OK: @@ -1173,7 +1209,6 @@ esiop_scsicmd_end(esiop_cmd) callout_stop(&esiop_cmd->cmd_c.xs->xs_callout); esiop_cmd->cmd_c.status = CMDST_FREE; TAILQ_INSERT_TAIL(&sc->free_list, esiop_cmd, next); - xs->resid = 0; scsipi_done (xs); } diff --git a/sys/dev/ic/esiopvar.h b/sys/dev/ic/esiopvar.h index 948c8a278c3b..ddef75d84d90 100644 --- a/sys/dev/ic/esiopvar.h +++ b/sys/dev/ic/esiopvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: esiopvar.h,v 1.8 2003/11/02 11:07:45 wiz Exp $ */ +/* $NetBSD: esiopvar.h,v 1.9 2004/05/17 11:10:24 bouyer Exp $ */ /* * Copyright (c) 2002 Manuel Bouyer. @@ -53,6 +53,7 @@ struct esiop_slot { struct esiop_xfer { struct siop_common_xfer siop_tables; u_int32_t tlq; /* target/lun/tag loaded in scratchC by script */ + /* will also containt scratcha at end of command */ } __attribute__((__packed__)); /* diff --git a/sys/dev/ic/siop.c b/sys/dev/ic/siop.c index d1a12b63cb6b..5332aff165fb 100644 --- a/sys/dev/ic/siop.c +++ b/sys/dev/ic/siop.c @@ -1,4 +1,4 @@ -/* $NetBSD: siop.c,v 1.72 2004/03/16 19:10:43 bouyer Exp $ */ +/* $NetBSD: siop.c,v 1.73 2004/05/17 11:10:24 bouyer Exp $ */ /* * Copyright (c) 2000 Manuel Bouyer. @@ -33,7 +33,7 @@ /* SYM53c7/8xx PCI-SCSI I/O Processors driver */ #include -__KERNEL_RCSID(0, "$NetBSD: siop.c,v 1.72 2004/03/16 19:10:43 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: siop.c,v 1.73 2004/05/17 11:10:24 bouyer Exp $"); #include #include @@ -494,7 +494,13 @@ siop_intr(v) * and the command should terminate. */ INCSTAT(siop_stat_intr_shortxfer); - if ((dstat & DSTAT_DFE) == 0) + /* + * sdp not needed here, but this + * will cause xs->resid to be adjusted + */ + if (scratcha0 & A_flag_data) + siop_sdp(&siop_cmd->cmd_c); + else if ((dstat & DSTAT_DFE) == 0) siop_clearfifo(&sc->sc_c); /* no table to flush here */ CALL_SCRIPT(Ent_status); @@ -889,6 +895,15 @@ scintr: * Don't call memmove in this case. */ if (offset < SIOP_NSG) { + int i; + /* + * adjust xs->resid for already-transfered + * data + */ + for (i = 0; i < offset; i++) + xs->resid -= le32toh( + siop_cmd->cmd_tables->data[i].count + ); memmove(&siop_cmd->cmd_tables->data[0], &siop_cmd->cmd_tables->data[offset], (SIOP_NSG - offset) * sizeof(scr_table_t)); @@ -918,6 +933,22 @@ scintr: le32toh(siop_cmd->cmd_tables->status)); #endif INCSTAT(siop_stat_intr_done); + /* + * update resid. If we completed a xfer with + * some data transfers, offset will be at last 1. + * If it's 0 then either no data was transfered at + * all, or resid was already adjusted by a save + * data pointer, or a phase mismatch. + */ + offset = bus_space_read_1(sc->sc_c.sc_rt, + sc->sc_c.sc_rh, SIOP_SCRATCHA + 1); + { + int i; + for (i = 0; i < offset; i++) + xs->resid -= le32toh( + siop_cmd->cmd_tables->data[i].count + ); + } siop_cmd->cmd_c.status = CMDST_DONE; goto end; default: @@ -1017,7 +1048,6 @@ siop_scsicmd_end(siop_cmd) callout_stop(&siop_cmd->cmd_c.xs->xs_callout); siop_cmd->cmd_c.status = CMDST_FREE; TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next); - xs->resid = 0; scsipi_done (xs); } diff --git a/sys/dev/ic/siop_common.c b/sys/dev/ic/siop_common.c index b0690aed9c13..11d84e614930 100644 --- a/sys/dev/ic/siop_common.c +++ b/sys/dev/ic/siop_common.c @@ -1,4 +1,4 @@ -/* $NetBSD: siop_common.c,v 1.33 2004/03/10 22:02:53 bouyer Exp $ */ +/* $NetBSD: siop_common.c,v 1.34 2004/05/17 11:10:24 bouyer Exp $ */ /* * Copyright (c) 2000, 2002 Manuel Bouyer. @@ -33,7 +33,7 @@ /* SYM53c7/8xx PCI-SCSI I/O Processors driver */ #include -__KERNEL_RCSID(0, "$NetBSD: siop_common.c,v 1.33 2004/03/10 22:02:53 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: siop_common.c,v 1.34 2004/05/17 11:10:24 bouyer Exp $"); #include #include @@ -735,7 +735,10 @@ void siop_sdp(siop_cmd) struct siop_common_cmd *siop_cmd; { - /* save data pointer. Handle async only for now */ + /* + * Save data pointer when a phase mistmatch occurs. We need to compute + * how much of the current table was written. + */ int offset, dbc, sstat; struct siop_common_softc *sc = siop_cmd->siop_sc; scr_table_t *table; /* table to patch */ @@ -790,6 +793,9 @@ siop_sdp(siop_cmd) bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) | CTEST3_CLF); } + /* correct xs->resid for this partial transfer */ + siop_cmd->xs->resid -= le32toh(table->count) - dbc; + /* "cut" already transfered data from this table */ table->addr = htole32(le32toh(table->addr) + le32toh(table->count) - dbc); table->count = htole32(dbc); diff --git a/sys/dev/microcode/siop/esiop.ss b/sys/dev/microcode/siop/esiop.ss index 486b81a5abc2..81aaf085f0b6 100644 --- a/sys/dev/microcode/siop/esiop.ss +++ b/sys/dev/microcode/siop/esiop.ss @@ -1,4 +1,4 @@ -; $NetBSD: esiop.ss,v 1.16 2003/10/05 17:48:49 bouyer Exp $ +; $NetBSD: esiop.ss,v 1.17 2004/05/17 11:10:24 bouyer Exp $ ; ; Copyright (c) 2002 Manuel Bouyer. @@ -208,6 +208,7 @@ waitphase: handle_cmpl: CALL REL(disconnect); + STORE NOFLUSH SCRATCHA0, 4, from tlq_offset; save current offset MOVE SCRATCHE1 to SFBR; INT int_done, IF NOT 0x00; if status is not "done", let host handle it MOVE SCRATCHF0 to SFBR; load pointer in done ring