summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorjonathan <jonathan@NetBSD.org>1996-09-29 03:02:19 +0000
committerjonathan <jonathan@NetBSD.org>1996-09-29 03:02:19 +0000
commit9b84ee7f356b60d2d86896f7b927248a3b1ee2ba (patch)
treee75b47a497382e69e5ab929059bd9ecda9694696 /sys/dev
parentc347bc09f1a796e415d16ff8d22782510cfffca1 (diff)
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.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/tc/asc.c61
1 files changed, 56 insertions, 5 deletions
diff --git a/sys/dev/tc/asc.c b/sys/dev/tc/asc.c
index b6d0de3642e..0aba303d8bd 100644
--- a/sys/dev/tc/asc.c
+++ b/sys/dev/tc/asc.c
@@ -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)