Properly compute xs->resid, instead of assuming it'll always be 0 when

a command is done.
This commit is contained in:
bouyer 2004-05-17 11:10:24 +00:00
parent e88c851d08
commit 76fa396c1d
5 changed files with 91 additions and 18 deletions

View File

@ -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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/systm.h>
@ -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);
}

View File

@ -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__));
/*

View File

@ -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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/systm.h>
@ -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);
}

View File

@ -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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/systm.h>
@ -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);

View File

@ -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