Subject: Re: port-mac68k/9679 -- Using scsi/libscsi lets mac68k sbc driver dump core
To: Dave Huang <khym@azeotrope.org>
From: Chuck Silvers <chuq@chuq.com>
List: netbsd-bugs
Date: 01/14/2006 12:02:51
--sdtB3X0nJg68CQEu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
On Wed, Jan 11, 2006 at 06:24:43PM -0600, Dave Huang wrote:
> I wonder if the sbc driver has problems if it's asked to read more
> data than is actually available. The scsi utility is attempting to
> read 255 bytes, even though chances are that the mode page isn't that
> long.
well, it's part of the problem. the sbc_pdma_in() is expecting to read
255 bytes, so is does the PDMA thing instead of PIO. since datalen is
more than 128, it tries to do the first 128 bytes using 4-byte reads.
however, there are only 35 bytes of data, so when it tries to read the
ninth 4-byte value it gets a bus error since there are only 3 bytes left.
so unless there's some way to know ahead of time how many bytes will
actually be read, it's not safe to use the 4-byte reads. all of the
other sbc PDMA data movers use the "nofault" hook to catch bus errors,
and sbc_pdma_in() should too. the attached patch will at least prevent
the panic, though it will miss transferring the last bytes if the number
of bytes transferred is not a multiple of 4.
we could try falling back to the byte-by-byte loop after a bus error on
the unrolled loop, does that seem likely to work?
-Chuck
--sdtB3X0nJg68CQEu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diff.sbc"
Index: arch/mac68k/dev/sbc.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mac68k/dev/sbc.c,v
retrieving revision 1.48
diff -u -p -r1.48 sbc.c
--- arch/mac68k/dev/sbc.c 24 Dec 2005 23:24:00 -0000 1.48
+++ arch/mac68k/dev/sbc.c 14 Jan 2006 19:42:40 -0000
@@ -246,6 +246,7 @@ sbc_pdma_in(struct ncr5380_softc *ncr_sc
struct sbc_softc *sc = (struct sbc_softc *)ncr_sc;
volatile u_int32_t *long_data = (u_int32_t *)sc->sc_drq_addr;
volatile u_int8_t *byte_data = (u_int8_t *)sc->sc_nodrq_addr;
+ label_t faultbuf;
int resid, s;
if (datalen < ncr_sc->sc_min_dma_len ||
@@ -261,9 +262,22 @@ sbc_pdma_in(struct ncr5380_softc *ncr_sc
*ncr_sc->sci_mode |= SCI_MODE_DMA;
*ncr_sc->sci_irecv = 0;
+ resid = datalen;
+
+ /*
+ * Setup for a possible bus error caused by SCSI controller
+ * switching out of DATA OUT before we're done with the
+ * current transfer. (See comment before sbc_drq_intr().)
+ */
+ nofault = &faultbuf;
+ if (setjmp(nofault)) {
+ printf("sbc_pdma_in: caught bus error\n");
+ goto interrupt;
+ }
+
#define R4 *((u_int32_t *)data)++ = *long_data
#define R1 *((u_int8_t *)data)++ = *byte_data
- for (resid = datalen; resid >= 128; resid -= 128) {
+ for (; resid >= 128; resid -= 128) {
if (sbc_ready(ncr_sc))
goto interrupt;
R4; R4; R4; R4; R4; R4; R4; R4;
@@ -281,6 +295,7 @@ sbc_pdma_in(struct ncr5380_softc *ncr_sc
#undef R1
interrupt:
+ nofault = NULL;
SCI_CLR_INTR(ncr_sc);
*ncr_sc->sci_mode &= ~SCI_MODE_DMA;
*ncr_sc->sci_icmd = 0;
--sdtB3X0nJg68CQEu--