Subject: Re: Crash! Boom! (was Re: README: Calling all beta testers!)
To: Mason Loring Bliss <mason@acheron.middleboro.ma.us>
From: Scott Reynolds <scottr@og.org>
List: port-mac68k
Date: 12/06/1997 14:27:47
On Sat, 6 Dec 1997, Mason Loring Bliss wrote:

> The patch worked - I'm booting without errors now. I tried to figure out
> what was going on by looking at the patch, but it's still sort of beyond
> me... What was the problem?

The patch I gave you put sbc.c back up to the post-1.3 tree, and backed
out the change to sbc_obio.c that enabled the SCSI IRQ interrupt.  What
this tells me is that there was a problem with servicing this interrupt
when the hardware generated one during autoconfig.

Here's the fix I've come up with.  It should be in the NetBSD 1.3 source
soon.

> Oh... FWIW, the kernel I just compiled is able to reboot without freezing,
> as was the 1.3_ALPHA kernel I had previously been running.

It's definitely related to the size of the kernel, which gives me a good
idea of _where_ the problem is, even though I don't know _what_ it is.
I'm planning to look at this in greater detail after the 1.3 release
happens.

--scott

Index: sbc.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mac68k/dev/sbc.c,v
retrieving revision 1.32.2.2
retrieving revision 1.33
diff -c -r1.32.2.2 -r1.33
*** sbc.c	1997/11/19 21:42:45	1.32.2.2
--- sbc.c	1997/12/06 18:53:30	1.33
***************
*** 185,191 ****
--- 185,193 ----
  	void *p;
  {
  	struct ncr5380_softc *ncr_sc = p;
+ 	struct sbc_softc *sc = (struct sbc_softc *)ncr_sc;
  	int claimed = 0;
+ 	extern int cold;
  
  	/* How we ever arrive here without IRQ set is a mystery... */
  	if (*ncr_sc->sci_csr & SCI_CSR_INT) {
***************
*** 193,203 ****
  		if (sbc_debug & SBC_DB_INTR)
  			decode_5380_intr(ncr_sc);
  #endif
! 		claimed = ncr5380_intr(ncr_sc);
  		if (!claimed) {
  			if (((*ncr_sc->sci_csr & ~SCI_CSR_PHASE_MATCH) == SCI_CSR_INT)
! 			    && ((*ncr_sc->sci_bus_csr & ~SCI_BUS_RST) == 0))
  				SCI_CLR_INTR(ncr_sc);	/* RST interrupt */
  #ifdef SBC_DEBUG
  			else {
  				printf("%s: spurious intr\n",
--- 195,209 ----
  		if (sbc_debug & SBC_DB_INTR)
  			decode_5380_intr(ncr_sc);
  #endif
! 		if (!cold)
! 			claimed = ncr5380_intr(ncr_sc);
  		if (!claimed) {
  			if (((*ncr_sc->sci_csr & ~SCI_CSR_PHASE_MATCH) == SCI_CSR_INT)
! 			    && ((*ncr_sc->sci_bus_csr & ~SCI_BUS_RST) == 0)) {
  				SCI_CLR_INTR(ncr_sc);	/* RST interrupt */
+ 				if (sc->sc_clrintr)
+ 					(*sc->sc_clrintr)(ncr_sc);
+ 			}
  #ifdef SBC_DEBUG
  			else {
  				printf("%s: spurious intr\n",
***************
*** 214,221 ****
  decode_5380_intr(ncr_sc)
  	struct ncr5380_softc *ncr_sc;
  {
! 	u_char csr = *ncr_sc->sci_csr;
! 	u_char bus_csr = *ncr_sc->sci_bus_csr;
  
  	if (((csr & ~(SCI_CSR_PHASE_MATCH | SCI_CSR_ATN)) == SCI_CSR_INT) &&
  	    ((bus_csr & ~(SCI_BUS_MSG | SCI_BUS_CD | SCI_BUS_IO | SCI_BUS_DBP)) == SCI_BUS_SEL)) {
--- 220,227 ----
  decode_5380_intr(ncr_sc)
  	struct ncr5380_softc *ncr_sc;
  {
! 	u_int8_t csr = *ncr_sc->sci_csr;
! 	u_int8_t bus_csr = *ncr_sc->sci_bus_csr;
  
  	if (((csr & ~(SCI_CSR_PHASE_MATCH | SCI_CSR_ATN)) == SCI_CSR_INT) &&
  	    ((bus_csr & ~(SCI_BUS_MSG | SCI_BUS_CD | SCI_BUS_IO | SCI_BUS_DBP)) == SCI_BUS_SEL)) {
***************
*** 250,399 ****
   ***/
  
  int
! sbc_pdma_out(ncr_sc, phase, count, data)
  	struct ncr5380_softc *ncr_sc;
  	int phase;
! 	int count;
  	u_char *data;
  {
  	struct sbc_softc *sc = (struct sbc_softc *)ncr_sc;
! 	volatile long *long_data = (long *)sc->sc_drq_addr;
! 	volatile u_char *byte_data = (u_char *)sc->sc_nodrq_addr;
! 	int s, len;
  
! 	if (count < ncr_sc->sc_min_dma_len || (sc->sc_options & SBC_PDMA) == 0)
! 		return ncr5380_pio_out(ncr_sc, phase, count, data);
  
  	s = splbio();
! 	len = count = min(count, MAX_DMA_LEN);
! 	if (sbc_wait_busy(ncr_sc) == 0) {
! 		*ncr_sc->sci_mode |= SCI_MODE_DMA;
! 		*ncr_sc->sci_icmd |= SCI_ICMD_DATA;
! 		*ncr_sc->sci_dma_send = 0;
! 
! #define W1	*byte_data = *data++
! #define W4	*long_data = *((long*)data)++
! 		while (len >= 64) {
! 			if (sbc_ready(ncr_sc))
! 				goto interrupt;
! 			W1;
! 			if (sbc_ready(ncr_sc))
! 				goto interrupt;
! 			W1;
! 			if (sbc_ready(ncr_sc))
! 				goto interrupt;
! 			W1;
! 			if (sbc_ready(ncr_sc))
! 				goto interrupt;
! 			W1;
! 			if (sbc_ready(ncr_sc))
! 				goto interrupt;
! 			W4; W4; W4; W4;
! 			W4; W4; W4; W4;
! 			W4; W4; W4; W4;
! 			W4; W4; W4;
! 			len -= 64;
! 		}
! 		while (len) {
! 			if (sbc_ready(ncr_sc))
! 				goto interrupt;
! 			W1;
! 			len--;
! 		}
! #undef  W1
! #undef  W4
! 		if (sbc_wait_dreq(ncr_sc))
! 			printf("%s: timeout waiting for DREQ.\n",
! 			    ncr_sc->sc_dev.dv_xname);
! 
! 		*byte_data = 0;
! 
! 		SCI_CLR_INTR(ncr_sc);
! 		*ncr_sc->sci_mode &= ~SCI_MODE_DMA;
! 		*ncr_sc->sci_icmd = 0;
  	}
- 	goto done;
  
! interrupt:
! #ifdef SBC_DEBUG
! 	if (sbc_debug & SBC_DB_INTR)
! 		printf("%s: pdma_out: timeout len=%d count=%d (disconnect?)\n",
! 		    ncr_sc->sc_dev.dv_xname, len, count);
! #endif
! 	if ((*ncr_sc->sci_csr & SCI_CSR_PHASE_MATCH) == 0) {
! 		*ncr_sc->sci_icmd &= ~SCI_ICMD_DATA;
! 		--len;
  	}
  
  	SCI_CLR_INTR(ncr_sc);
  	*ncr_sc->sci_mode &= ~SCI_MODE_DMA;
  	*ncr_sc->sci_icmd = 0;
- 
- done:
  	splx(s);
! 	return count - len;
  }
  
  int
! sbc_pdma_in(ncr_sc, phase, count, data)
  	struct ncr5380_softc *ncr_sc;
  	int phase;
! 	int count;
  	u_char *data;
  {
  	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;
! 	int len, s;
  
! 	if (count < ncr_sc->sc_min_dma_len || (sc->sc_options & SBC_PDMA) == 0)
! 		return ncr5380_pio_in(ncr_sc, phase, count, data);
  
  	s = splbio();
! 	len = count = min(count, MAX_DMA_LEN);
! 	if (sbc_wait_busy(ncr_sc) == 0) {
! 		*ncr_sc->sci_mode |= SCI_MODE_DMA;
! 		*ncr_sc->sci_icmd |= SCI_ICMD_DATA;
! 		*ncr_sc->sci_irecv = 0;
! 
! #define R4	*((long *)data)++ = *long_data
! #define R1	*data++ = *byte_data
! 		while (len >= 128) {
! 			if (sbc_ready(ncr_sc))
! 				goto interrupt;
! 			R4; R4; R4; R4; R4; R4; R4; R4;
! 			R4; R4; R4; R4; R4; R4; R4; R4;
! 			R4; R4; R4; R4; R4; R4; R4; R4;
! 			R4; R4; R4; R4; R4; R4; R4; R4;		/* 128 */
! 			len -= 128;
! 		}
! 		while (len) {
! 			if (sbc_ready(ncr_sc))
! 				goto interrupt;
! 			R1;
! 			len--;
! 		}
! #undef R4
! #undef R1
! 		SCI_CLR_INTR(ncr_sc);
! 		*ncr_sc->sci_mode &= ~SCI_MODE_DMA;
! 		*ncr_sc->sci_icmd = 0;
  	}
  	goto done;
  
  interrupt:
! #ifdef SBC_DEBUG
! 	if (sbc_debug & SBC_DB_INTR)
! 		printf("%s: pdma_in: timeout len=%d count=%d (disconnect?)\n",
! 		    ncr_sc->sc_dev.dv_xname, len, count);
! #endif
! 	SCI_CLR_INTR(ncr_sc);
! 	*ncr_sc->sci_mode &= ~SCI_MODE_DMA;
! 	*ncr_sc->sci_icmd = 0;
  
  done:
  	splx(s);
! 	return count - len;
  }
  
  
--- 256,408 ----
   ***/
  
  int
! sbc_pdma_in(ncr_sc, phase, datalen, data)
  	struct ncr5380_softc *ncr_sc;
  	int phase;
! 	int datalen;
  	u_char *data;
  {
  	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;
! 	int resid, s;
  
! 	if (datalen < ncr_sc->sc_min_dma_len ||
! 	    (sc->sc_options & SBC_PDMA) == 0)
! 		return ncr5380_pio_in(ncr_sc, phase, datalen, data);
  
  	s = splbio();
! 	if (sbc_wait_busy(ncr_sc)) {
! 		splx(s);
! 		return 0;
  	}
  
! 	*ncr_sc->sci_mode |= SCI_MODE_DMA;
! 	*ncr_sc->sci_irecv = 0;
! 
! #define R4	*((u_int32_t *)data)++ = *long_data
! #define R1	*((u_int8_t *)data)++ = *byte_data
! 	for (resid = datalen; resid >= 128; resid -= 128) {
! 		if (sbc_ready(ncr_sc))
! 			goto interrupt;
! 		R4; R4; R4; R4; R4; R4; R4; R4;
! 		R4; R4; R4; R4; R4; R4; R4; R4;
! 		R4; R4; R4; R4; R4; R4; R4; R4;
! 		R4; R4; R4; R4; R4; R4; R4; R4;		/* 128 */
  	}
+ 	while (resid) {
+ 		if (sbc_ready(ncr_sc))
+ 			goto interrupt;
+ 		R1;
+ 		resid--;
+ 	}
+ #undef R4
+ #undef R1
  
+ interrupt:
  	SCI_CLR_INTR(ncr_sc);
  	*ncr_sc->sci_mode &= ~SCI_MODE_DMA;
  	*ncr_sc->sci_icmd = 0;
  	splx(s);
! 	return (datalen - resid);
  }
  
  int
! sbc_pdma_out(ncr_sc, phase, datalen, data)
  	struct ncr5380_softc *ncr_sc;
  	int phase;
! 	int datalen;
  	u_char *data;
  {
  	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;
! 	u_int8_t icmd;
! 
! #if 1
! 	/* Work around lame gcc initialization bug */
! 	(void)&data;
! #endif
  
! 	if (datalen < ncr_sc->sc_min_dma_len ||
! 	    (sc->sc_options & SBC_PDMA) == 0)
! 		return ncr5380_pio_out(ncr_sc, phase, datalen, data);
  
  	s = splbio();
! 	if (sbc_wait_busy(ncr_sc)) {
! 		splx(s);
! 		return 0;
! 	}
! 
! 	icmd = *(ncr_sc->sci_icmd) & SCI_ICMD_RMASK;
! 	*ncr_sc->sci_icmd = icmd | SCI_ICMD_DATA;
! 	*ncr_sc->sci_mode |= SCI_MODE_DMA;
! 	*ncr_sc->sci_dma_send = 0;
! 
! 	/*
! 	 * 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("buf = 0x%lx, fault = 0x%lx\n",
! 		    (u_long)sc->sc_drq_addr, (u_long)m68k_fault_addr);
! 		panic("Unexpected bus error in sbc_pdma_out()");
  	}
+ 
+ #define W1	*byte_data = *((u_int8_t *)data)++
+ #define W4	*long_data = *((u_int32_t *)data)++
+ 	for (resid = datalen; resid >= 64; resid -= 64) {
+ 		if (sbc_ready(ncr_sc))
+ 			goto interrupt;
+ 		W1;
+ 		if (sbc_ready(ncr_sc))
+ 			goto interrupt;
+ 		W1;
+ 		if (sbc_ready(ncr_sc))
+ 			goto interrupt;
+ 		W1;
+ 		if (sbc_ready(ncr_sc))
+ 			goto interrupt;
+ 		W1;
+ 		if (sbc_ready(ncr_sc))
+ 			goto interrupt;
+ 		W4; W4; W4; W4;
+ 		W4; W4; W4; W4;
+ 		W4; W4; W4; W4;
+ 		W4; W4; W4;
+ 	}
+ 	while (resid) {
+ 		if (sbc_ready(ncr_sc))
+ 			goto interrupt;
+ 		W1;
+ 		resid--;
+ 	}
+ #undef  W1
+ #undef  W4
+ 	if (sbc_wait_dreq(ncr_sc))
+ 		printf("%s: timeout waiting for DREQ.\n",
+ 		    ncr_sc->sc_dev.dv_xname);
+ 
+ 	*byte_data = 0;
  	goto done;
  
  interrupt:
! 	if ((*ncr_sc->sci_csr & SCI_CSR_PHASE_MATCH) == 0) {
! 		*ncr_sc->sci_icmd = icmd & ~SCI_ICMD_DATA;
! 		--resid;
! 	}
  
  done:
+ 	SCI_CLR_INTR(ncr_sc);
+ 	*ncr_sc->sci_mode &= ~SCI_MODE_DMA;
+ 	*ncr_sc->sci_icmd = icmd;
  	splx(s);
! 	return (datalen - resid);
  }