Fix data-corruption bug on async targets:
* When we are transferring in DATA (in asc_dma_in) and the target is an async device, there is sometimes an extra byte in the FIFO. If so, we need to drain that byte out of the fifo, but if and only if the target is async. See also the comments in asc_dma_in() in the related Mach mk84 asc driver (scsi_53C94_hdw.c), which has an identical fix but applied in more restrictive conditions than we need, with async *disk* targets, as well as async tapes. * Add a watchdog and timeout active SCSI requests, to eliminate any potential for deadlock due to applying the fix above on newer silicon versions of the 53c94 which may not have the above problem. Should use the MI scsi per-target timeout instead, when available.
This commit is contained in:
parent
c347bc09f1
commit
9b84ee7f35
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: asc.c,v 1.28 1996/09/25 21:07:46 jonathan Exp $ */
|
||||
/* $NetBSD: asc.c,v 1.29 1996/09/29 03:02:19 jonathan Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
|
@ -128,6 +128,7 @@
|
|||
#include <sys/buf.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/reboot.h>
|
||||
|
||||
|
@ -408,6 +409,7 @@ script_t asc_scripts[] = {
|
|||
*/
|
||||
static void asc_reset __P((asc_softc_t asc, asc_regmap_t *regs));
|
||||
static void asc_startcmd __P((asc_softc_t asc, int target));
|
||||
static void asc_timeout __P((void *arg));
|
||||
|
||||
extern struct cfdriver asc_cd;
|
||||
struct cfdriver asc_cd = {
|
||||
|
@ -598,6 +600,12 @@ asc_start(scsicmd)
|
|||
splx(s);
|
||||
}
|
||||
asc->cmd[sdp->sd_drive] = scsicmd;
|
||||
/*
|
||||
* Kludge: use a 60 second timeout if data is being transfered,
|
||||
* otherwise use a 30 minute timeout.
|
||||
*/
|
||||
timeout(asc_timeout, scsicmd, hz * (scsicmd->buflen == 0 ?
|
||||
1800 : 60));
|
||||
asc_startcmd(asc, sdp->sd_drive);
|
||||
splx(s);
|
||||
}
|
||||
|
@ -1315,6 +1323,7 @@ asc_end(asc, status, ss, ir)
|
|||
scsicmd = asc->cmd[target];
|
||||
asc->cmd[target] = (ScsiCmd *)0;
|
||||
state = &asc->st[target];
|
||||
untimeout(asc_timeout, scsicmd);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (asc_debug > 1) {
|
||||
|
@ -1408,13 +1417,36 @@ asc_dma_in(asc, status, ss, ir)
|
|||
state->buflen -= len;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!(state->flags & DMA_IN_PROGRESS) &&
|
||||
(regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 0) {
|
||||
printf("asc_dma_in: FIFO count %x flags %x\n",
|
||||
regs->asc_flags, state->flags);
|
||||
volatile int async_fifo_junk = 0;
|
||||
|
||||
/*
|
||||
* If the target is asynchronous, the FIFO contains
|
||||
* a byte of garbage. (see the Mach mk84 53c94 driver,
|
||||
* where this occurs on tk-50s and exabytes.)
|
||||
* It also occurs on asynch disks like SCSI-1 disks.
|
||||
* Recover by reading the byte of junk from the fifo if,
|
||||
* and only if, the target is async. If the target is
|
||||
* synch, there is no junk, and reading the fifo
|
||||
* deadlocks our SCSI state machine.
|
||||
*/
|
||||
if (state->sync_offset == 0)
|
||||
async_fifo_junk = regs->asc_fifo;
|
||||
#ifdef DEBUG
|
||||
printf("%s: asc_dma_in: FIFO count %x flags %x sync_offset %d",
|
||||
asc->sc_dev.dv_xname, regs->asc_flags,
|
||||
state->flags, state->sync_offset);
|
||||
if (state->sync_offset != 0)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" unexpected fifo data %x\n", async_fifo_junk);
|
||||
#ifdef DIAGNOSTIC
|
||||
asc_DumpLog("asc_dma_in");
|
||||
#endif /* DIAGNOSTIC */
|
||||
#endif /* DEBUG */
|
||||
|
||||
}
|
||||
#endif
|
||||
/* setup to start reading the next chunk */
|
||||
len = state->buflen;
|
||||
#ifdef DEBUG
|
||||
|
@ -2011,6 +2043,25 @@ asc_disconnect(asc, status, ss, ir)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
asc_timeout(arg)
|
||||
void *arg;
|
||||
{
|
||||
int s = splbio();
|
||||
ScsiCmd *scsicmd = (ScsiCmd *) arg;
|
||||
|
||||
printf("asc_timeout: cmd %p drive %d\n", scsicmd, scsicmd->sd->sd_drive);
|
||||
#ifdef DEBUG
|
||||
asc_DumpLog("asc_timeout");
|
||||
#endif
|
||||
#if 0
|
||||
panic("asc_timeout");
|
||||
#else
|
||||
boot(4, NULL); /* XXX */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
asc_DumpLog(str)
|
||||
|
|
Loading…
Reference in New Issue