[net.bugs.4bsd] 4.3 dmf driver that works with emulex boards

muller@sdcc7.ucsd.EDU (Keith Muller) (08/02/86)

Since a lot of people seem to have problems with emulex dmf's,
enclosed is diffs from the june 86 release of 4.3 for a dmf driver
that works with emulex cs11 and cs21's. NOTE: make sure you get prom
upgrades from emulex if you have an OLD board. The old microcode will
wedge your system while doing dma output (or all 8 ports on a dmf will
stop working).
If you have questions comments etc pleas contact me.
	Keith muller
	University of California, San Diego
	muller@sdcsvax.ucsd.edu
	muller@nprdc.arpa

*** vaxuba/dmf.c	Thu Jun  5 01:07:44 1986
--- local/dmf.c	Thu Jun 19 10:54:55 1986
***************
*** 68,75 ****
  struct	uba_driver dmfdriver =
  	{ dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo };
  
! int	dmf_timeout = 10;		/* silo timeout, in ms */
! int	dmf_mindma = 4;			/* don't dma below this point */
  
  /*
   * Local variables for the driver
--- 68,75 ----
  struct	uba_driver dmfdriver =
  	{ dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo };
  
! int	dmf_timeout = 4;		/* silo timeout, in ms */
! int	dmf_mindma = 3;			/* don't dma below this point */
  
  /*
   * Local variables for the driver
***************
*** 122,129 ****
  int	dmf_ubinfo[NUBA];		/* info about allocated unibus map */
  int	cbase[NUBA];			/* base address in unibus map */
  #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
- char	dmf_dma[NDMF*8];
  
  /*
   * Routine for configuration to set dmf interrupt.
   */
--- 122,137 ----
  int	dmf_ubinfo[NUBA];		/* info about allocated unibus map */
  int	cbase[NUBA];			/* base address in unibus map */
  #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
  
+ struct dmfa_softc {
+ 	int dmfa_state;
+ 	int dmfa_count;
+ } dmfa_softc[NDMF * 8];
+ 
+ #define ST_TXOFF	(0x01)		/* tx turned off */
+ #define ST_DMA		(0x02)		/* tx doing dma output */
+ #define ST_INBUSY	(0x04)		/* tx off while in TS_BUSY */
+ 
  /*
   * Routine for configuration to set dmf interrupt.
   */
***************
*** 275,280 ****
--- 283,289 ----
  #ifndef PORTSELECTOR
  		}
  #endif PORTSELECTOR
+ 		dmfa_softc[unit].dmfa_state = 0;
  		dmfparam(unit);
  	}
  	/*
***************
*** 566,572 ****
  	register struct dmfdevice *addr;
  	register struct uba_device *ui;
  	register int t;
! 	short cntr;
  
  	ui = dmfinfo[dmf];
  	addr = (struct dmfdevice *)ui->ui_addr;
--- 575,582 ----
  	register struct dmfdevice *addr;
  	register struct uba_device *ui;
  	register int t;
! 	struct dmfa_softc *sc0 = &dmfa_softc[unit0];
! 	register struct dmfa_softc *sc;
  
  	ui = dmfinfo[dmf];
  	addr = (struct dmfdevice *)ui->ui_addr;
***************
*** 573,594 ****
  	while ((t = addr->dmfcsr) & DMF_TI) {
  		if (t & DMF_NXM)
  			/* SHOULD RESTART OR SOMETHING... */
! 			printf("dmf%d: NXM line %d\n", dmf, t >> 8 & 7);
  		t = t >> 8 & 7;
  		tp = tp0 + t;
! 		tp->t_state &= ~TS_BUSY;
! 		if (tp->t_state&TS_FLUSH)
  			tp->t_state &= ~TS_FLUSH;
! 		else if (dmf_dma[unit0 + t]) {
! 			/*
! 			 * Do arithmetic in a short to make up
! 			 * for lost 16&17 bits.
! 			 */
! 			addr->dmfcsr = DMFIR_TBA | DMF_IE | t;
! 			cntr = addr->dmftba -
! 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
! 			ndflush(&tp->t_outq, (int)cntr);
! 		}
  		if (tp->t_line)
  			(*linesw[tp->t_line].l_start)(tp);
  		else
--- 583,600 ----
  	while ((t = addr->dmfcsr) & DMF_TI) {
  		if (t & DMF_NXM)
  			/* SHOULD RESTART OR SOMETHING... */
! 			log(LOG_WARNING, "dmf%d: NXM line %d\n", dmf, t >> 8 & 7);
  		t = t >> 8 & 7;
  		tp = tp0 + t;
! 		sc = sc0 + t;
! 		if (tp->t_state&TS_FLUSH) {
  			tp->t_state &= ~TS_FLUSH;
! 			addr->dmfcsr = DMF_IE | DMFIR_LCR | t;
! 			addr->dmflctms = addr->dmflctms | DMF_TE;
! 		} else if (sc->dmfa_state & ST_DMA)
! 			ndflush(&tp->t_outq, sc->dmfa_count);
! 		sc->dmfa_state = 0;
! 		tp->t_state &= ~TS_BUSY;
  		if (tp->t_line)
  			(*linesw[tp->t_line].l_start)(tp);
  		else
***************
*** 604,614 ****
--- 610,622 ----
  {
  	register struct dmfdevice *addr;
  	register int unit, nch;
+ 	register struct dmfa_softc *sc;
  	int s;
  	register int dmf;
  
  	unit = minor(tp->t_dev);
  	dmf = unit >> 3;
+ 	sc = &dmfa_softc[unit];
  	unit &= 07;
  	addr = (struct dmfdevice *)tp->t_addr;
  
***************
*** 623,637 ****
  	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
  		goto out;
  	/*
! 	 * If there are still characters in the silo,
! 	 * just reenable the transmitter.
  	 */
! 	addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
! 	if (addr->dmftsc) {
  		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
  		addr->dmflctms = addr->dmflctms | DMF_TE;
- 		tp->t_state |= TS_BUSY;
- 		goto out;
  	}
  	/*
  	 * If there are sleepers, and output has drained below low
--- 631,651 ----
  	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
  		goto out;
  	/*
! 	 * If tx off, turn on. If tx was turned off while TS_BUSY (before
! 	 * the interrupt), reset TS_BUSY and wait for interrupt. Otherwise
! 	 * turn on tx and start a new transmission.
  	 */
! 	if (sc->dmfa_state & ST_TXOFF) {
! 		sc->dmfa_state &= ~ST_TXOFF;
! 		if (sc->dmfa_state & ST_INBUSY) {
! 			sc->dmfa_state &= ~ST_INBUSY;
! 			tp->t_state |= TS_BUSY;
! 			addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
! 			addr->dmflctms = addr->dmflctms | DMF_TE;
! 			goto out;
! 		}
  		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
  		addr->dmflctms = addr->dmflctms | DMF_TE;
  	}
  	/*
  	 * If there are sleepers, and output has drained below low
***************
*** 673,699 ****
  	if (nch >= dmf_mindma) {
  		register car;
  
! 		dmf_dma[minor(tp->t_dev)] = 1;
  		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
  		addr->dmflctms = addr->dmflctms | DMF_TE;
  		car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum);
  		addr->dmfcsr = DMF_IE | DMFIR_TBA | unit;
  		addr->dmftba = car;
  		addr->dmftcc = ((car >> 2) & 0xc000) | nch;
- 		tp->t_state |= TS_BUSY;
  	} else if (nch) {
  		register char *cp = tp->t_outq.c_cf;
  		register int i;
  
! 		dmf_dma[minor(tp->t_dev)] = 0;
  		nch = MIN(nch, DMF_SILOCNT);
  		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
  		addr->dmflctms = addr->dmflctms | DMF_TE;
  		addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
  		for (i = 0; i < nch; i++)
  			addr->dmftbuf = *cp++;
  		ndflush(&tp->t_outq, nch);
- 		tp->t_state |= TS_BUSY;
  	}
  out:
  	splx(s);
--- 687,714 ----
  	if (nch >= dmf_mindma) {
  		register car;
  
! 		tp->t_state |= TS_BUSY;
  		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
  		addr->dmflctms = addr->dmflctms | DMF_TE;
  		car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum);
+ 		sc->dmfa_count = nch;
+ 		sc->dmfa_state |= ST_DMA;
  		addr->dmfcsr = DMF_IE | DMFIR_TBA | unit;
  		addr->dmftba = car;
  		addr->dmftcc = ((car >> 2) & 0xc000) | nch;
  	} else if (nch) {
  		register char *cp = tp->t_outq.c_cf;
  		register int i;
  
! 		tp->t_state |= TS_BUSY;
  		nch = MIN(nch, DMF_SILOCNT);
  		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
  		addr->dmflctms = addr->dmflctms | DMF_TE;
+ 		sc->dmfa_state &= ~ST_DMA;
  		addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
  		for (i = 0; i < nch; i++)
  			addr->dmftbuf = *cp++;
  		ndflush(&tp->t_outq, nch);
  	}
  out:
  	splx(s);
***************
*** 707,713 ****
  	register struct tty *tp;
  {
  	register struct dmfdevice *addr;
! 	register unit = minor(tp->t_dev) & 7;
  	int s;
  
  	addr = (struct dmfdevice *)tp->t_addr;
--- 722,729 ----
  	register struct tty *tp;
  {
  	register struct dmfdevice *addr;
! 	register unit = minor(tp->t_dev);
! 	register struct dmfa_softc *sc = &dmfa_softc[unit];
  	int s;
  
  	addr = (struct dmfdevice *)tp->t_addr;
***************
*** 715,745 ****
  	 * Block input/output interrupts while messing with state.
  	 */
  	s = spltty();
  	if (flag) {
! 		addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
! 		if (addr->dmftsc) {
! 			/*
! 			 * Flush regardless of whether we're transmitting
! 			 * (TS_BUSY), if the silo contains untransmitted
! 			 * characters.
! 			 */
! 			addr->dmfcsr = DMFIR_LCR | unit | DMF_IE;
! 			addr->dmflctms = addr->dmflctms | DMF_TE | DMF_FLUSH;
! 			/* this will interrupt so let dmfxint handle the rest */
! 			tp->t_state |= TS_FLUSH|TS_BUSY;
! 		}
! 	} else {
! 		if (tp->t_state & TS_BUSY) {
! 			/*
! 			 * Stop transmission by disabling
! 			 * the transmitter.  We'll pick up where we
! 			 * left off by reenabling in dmfstart.
! 			 */
! 			addr->dmfcsr = DMFIR_LCR | unit | DMF_IE;
! 			addr->dmflctms = addr->dmflctms &~ DMF_TE;
! 			/* no interrupt here */
! 			tp->t_state &= ~TS_BUSY;
! 		}
  	}
  	splx(s);
  }
--- 731,747 ----
  	 * Block input/output interrupts while messing with state.
  	 */
  	s = spltty();
+ 	addr->dmfcsr = DMFIR_LCR | (unit & 07) | DMF_IE;
+ 	addr->dmflctms = addr->dmflctms &~ DMF_TE;
+ 	sc->dmfa_state |= ST_TXOFF;
  	if (flag) {
! 		tp->t_state |= TS_FLUSH|TS_BUSY;
! 		addr->dmflctms = addr->dmflctms | DMF_FLUSH;
! 		/* this will interrupt so let dmfxint handle the rest */
! 	} else if (tp->t_state & TS_BUSY) {
! 		sc->dmfa_state |= ST_INBUSY;
! 		tp->t_state &= ~TS_BUSY;
! 		/* no interrupt here reenable in dmfstart */
  	}
  	splx(s);
  }
***************
*** 819,824 ****
--- 821,827 ----
  		addr->dmfrsp = dmf_timeout;
  		unit = dmf * 8;
  		for (i = 0; i < 8; i++) {
+ 			dmfa_softc[unit].dmfa_state = 0;
  			tp = &dmf_tty[unit];
  			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
  				dmfparam(unit);

mel@rocky2.UUCP (Melvin Ferentz) (08/08/86)

While waiting for the updated proms from Emulex, the following one line
hack will work.

dmf.c
72c72
< int	dmf_mindma = 4;			/* don't dma below this point */
---
> int	dmf_mindma = 20000; /* HACK FOR NO DMA    don't dma below this point */

The driver then works like the 4.2bsd driver, i.e. no dma.

				mel@rockefeller.arpa
				   @rockvax.bitnet
				   @rocky2.uucp