Subject: Re: port-mac68k/9679 -- Using scsi/libscsi lets mac68k sbc driver dump core
To: None <port-mac68k-maintainer@netbsd.org, gnats-admin@netbsd.org,>
From: Chuck Silvers <chuq@chuq.com>
List: netbsd-bugs
Date: 01/14/2006 20:05:02
The following reply was made to PR port-mac68k/9679; it has been noted by GNATS.

From: Chuck Silvers <chuq@chuq.com>
To: Dave Huang <khym@azeotrope.org>
Cc: gnats-bugs@netbsd.org, netbsd-bugs@netbsd.org,
	hauke@Espresso.Rhein-Neckar.DE
Subject: Re: port-mac68k/9679 -- Using scsi/libscsi lets mac68k sbc driver dump core
Date: Sat, 14 Jan 2006 12:02:51 -0800

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