xref: /csrg-svn/sys/vax/if/if_dmc.c (revision 35317)
123286Smckusick /*
229360Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
3*35317Sbostic  * All rights reserved.
423286Smckusick  *
5*35317Sbostic  * Redistribution and use in source and binary forms are permitted
6*35317Sbostic  * provided that the above copyright notice and this paragraph are
7*35317Sbostic  * duplicated in all such forms and that any documentation,
8*35317Sbostic  * advertising materials, and other materials related to such
9*35317Sbostic  * distribution and use acknowledge that the software was developed
10*35317Sbostic  * by the University of California, Berkeley.  The name of the
11*35317Sbostic  * University may not be used to endorse or promote products derived
12*35317Sbostic  * from this software without specific prior written permission.
13*35317Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*35317Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*35317Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*35317Sbostic  *
17*35317Sbostic  *	@(#)if_dmc.c	7.3 (Berkeley) 08/04/88
1823286Smckusick  */
195725Sroot 
205725Sroot #include "dmc.h"
215725Sroot #if NDMC > 0
2217565Skarels 
235725Sroot /*
245725Sroot  * DMC11 device driver, internet version
255725Sroot  *
2617565Skarels  *	Bill Nesheim
2717221Stef  *	Cornell University
2811191Ssam  *
2917565Skarels  *	Lou Salkind
3017565Skarels  *	New York University
315725Sroot  */
3217565Skarels 
3317565Skarels /* #define DEBUG	/* for base table dump on fatal error */
3417565Skarels 
359794Ssam #include "../machine/pte.h"
365725Sroot 
3717111Sbloom #include "param.h"
3817111Sbloom #include "systm.h"
3917111Sbloom #include "mbuf.h"
4017111Sbloom #include "buf.h"
4117221Stef #include "ioctl.h"		/* must precede tty.h */
4217111Sbloom #include "tty.h"
4317111Sbloom #include "protosw.h"
4417111Sbloom #include "socket.h"
4526282Skarels #include "syslog.h"
4617111Sbloom #include "vmmac.h"
4717111Sbloom #include "errno.h"
488460Sroot 
498460Sroot #include "../net/if.h"
509176Ssam #include "../net/netisr.h"
518460Sroot #include "../net/route.h"
5224796Skarels 
5324796Skarels #ifdef	INET
548416Swnj #include "../netinet/in.h"
558416Swnj #include "../netinet/in_systm.h"
5628950Skarels #include "../netinet/in_var.h"
5717565Skarels #include "../netinet/ip.h"
5824796Skarels #endif
598460Sroot 
608460Sroot #include "../vax/cpu.h"
618460Sroot #include "../vax/mtpr.h"
6217111Sbloom #include "if_uba.h"
6317111Sbloom #include "if_dmc.h"
648460Sroot #include "../vaxuba/ubareg.h"
658460Sroot #include "../vaxuba/ubavar.h"
665725Sroot 
6717565Skarels #include "../h/time.h"
6817565Skarels #include "../h/kernel.h"
6917565Skarels 
7034529Skarels /*
7134529Skarels  * output timeout value, sec.; should depend on line speed.
7234529Skarels  */
7334529Skarels int	dmc_timeout = 20;
7417565Skarels 
755725Sroot /*
765725Sroot  * Driver information for auto-configuration stuff.
775725Sroot  */
7813061Ssam int	dmcprobe(), dmcattach(), dmcinit(), dmcioctl();
7934529Skarels int	dmcoutput(), dmcreset(), dmctimeout();
805725Sroot struct	uba_device *dmcinfo[NDMC];
815725Sroot u_short	dmcstd[] = { 0 };
825725Sroot struct	uba_driver dmcdriver =
835725Sroot 	{ dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
845725Sroot 
8517221Stef #define NRCV 7
8617565Skarels #define NXMT 3
8724796Skarels #define NCMDS	(NRCV+NXMT+4)	/* size of command queue */
8817221Stef 
8917565Skarels #define printd if(dmcdebug)printf
9017565Skarels int dmcdebug = 0;
9117565Skarels 
9217221Stef /* error reporting intervals */
9317221Stef #define DMC_RPNBFS	50
9417221Stef #define DMC_RPDSC	1
9517565Skarels #define DMC_RPTMO	10
9617565Skarels #define DMC_RPDCK	10
9717221Stef 
9817221Stef struct  dmc_command {
9917221Stef 	char	qp_cmd;		/* command */
10017221Stef 	short	qp_ubaddr;	/* buffer address */
10117221Stef 	short	qp_cc;		/* character count || XMEM */
10217221Stef 	struct	dmc_command *qp_next;	/* next command on queue */
10317221Stef };
10417221Stef 
10517221Stef struct dmcbufs {
10617221Stef 	int	ubinfo;		/* from uballoc */
10717221Stef 	short	cc;		/* buffer size */
10817221Stef 	short	flags;		/* access control */
10917221Stef };
11017221Stef #define	DBUF_OURS	0	/* buffer is available */
11117221Stef #define	DBUF_DMCS	1	/* buffer claimed by somebody */
11217221Stef #define	DBUF_XMIT	4	/* transmit buffer */
11317565Skarels #define	DBUF_RCV	8	/* receive buffer */
11417221Stef 
11517221Stef 
11617221Stef /*
1175725Sroot  * DMC software status per interface.
1185725Sroot  *
1195725Sroot  * Each interface is referenced by a network interface structure,
1205725Sroot  * sc_if, which the routing code uses to locate the interface.
1215725Sroot  * This structure contains the output queue for the interface, its address, ...
12217221Stef  * We also have, for each interface, a  set of 7 UBA interface structures
12317221Stef  * for each, which
12417221Stef  * contain information about the UNIBUS resources held by the interface:
1255725Sroot  * map registers, buffered data paths, etc.  Information is cached in this
1265725Sroot  * structure for use by the if_uba.c routines in running the interface
1275725Sroot  * efficiently.
1285725Sroot  */
1295725Sroot struct dmc_softc {
1305725Sroot 	struct	ifnet sc_if;		/* network-visible interface */
13126933Skarels 	short	sc_oused;		/* output buffers currently in use */
13226933Skarels 	short	sc_iused;		/* input buffers given to DMC */
13326933Skarels 	short	sc_flag;		/* flags */
1345725Sroot 	int	sc_ubinfo;		/* UBA mapping info for base table */
13517221Stef 	int	sc_errors[4];		/* non-fatal error counters */
13617221Stef #define sc_datck sc_errors[0]
13717221Stef #define sc_timeo sc_errors[1]
13817221Stef #define sc_nobuf sc_errors[2]
13917221Stef #define sc_disc  sc_errors[3]
14034529Skarels 	struct	dmcbufs sc_rbufs[NRCV];	/* receive buffer info */
14134529Skarels 	struct	dmcbufs sc_xbufs[NXMT];	/* transmit buffer info */
14234529Skarels 	struct	ifubinfo sc_ifuba;	/* UNIBUS resources */
14334529Skarels 	struct	ifrw sc_ifr[NRCV];	/* UNIBUS receive buffer maps */
14434529Skarels 	struct	ifxmt sc_ifw[NXMT];	/* UNIBUS receive buffer maps */
14517221Stef 	/* command queue stuff */
14617565Skarels 	struct	dmc_command sc_cmdbuf[NCMDS];
14717221Stef 	struct	dmc_command *sc_qhead;	/* head of command queue */
14817221Stef 	struct	dmc_command *sc_qtail;	/* tail of command queue */
14917221Stef 	struct	dmc_command *sc_qactive;	/* command in progress */
15017221Stef 	struct	dmc_command *sc_qfreeh;	/* head of list of free cmd buffers */
15117221Stef 	struct	dmc_command *sc_qfreet;	/* tail of list of free cmd buffers */
15217221Stef 	/* end command queue stuff */
1535725Sroot } dmc_softc[NDMC];
1545725Sroot 
1555725Sroot /* flags */
15634529Skarels #define DMC_RUNNING	0x01		/* device initialized */
15727266Skarels #define DMC_BMAPPED	0x02		/* base table mapped */
15827266Skarels #define DMC_RESTART	0x04		/* software restart in progress */
15934529Skarels #define DMC_ONLINE	0x08		/* device running (had a RDYO) */
1605725Sroot 
16117565Skarels struct dmc_base {
16217565Skarels 	short	d_base[128];		/* DMC base table */
1635725Sroot } dmc_base[NDMC];
1645725Sroot 
16517221Stef /* queue manipulation macros */
16617221Stef #define	QUEUE_AT_HEAD(qp, head, tail) \
16717221Stef 	(qp)->qp_next = (head); \
16817221Stef 	(head) = (qp); \
16917221Stef 	if ((tail) == (struct dmc_command *) 0) \
17017221Stef 		(tail) = (head)
1715725Sroot 
17217221Stef #define QUEUE_AT_TAIL(qp, head, tail) \
17317221Stef 	if ((tail)) \
17417221Stef 		(tail)->qp_next = (qp); \
17517221Stef 	else \
17617221Stef 		(head) = (qp); \
17717221Stef 	(qp)->qp_next = (struct dmc_command *) 0; \
17817221Stef 	(tail) = (qp)
17917221Stef 
18017221Stef #define DEQUEUE(head, tail) \
18117221Stef 	(head) = (head)->qp_next;\
18217221Stef 	if ((head) == (struct dmc_command *) 0)\
18317221Stef 		(tail) = (head)
18417221Stef 
1855725Sroot dmcprobe(reg)
1865725Sroot 	caddr_t reg;
1875725Sroot {
1885725Sroot 	register int br, cvec;
1895725Sroot 	register struct dmcdevice *addr = (struct dmcdevice *)reg;
1905725Sroot 	register int i;
1915725Sroot 
1925725Sroot #ifdef lint
1935725Sroot 	br = 0; cvec = br; br = cvec;
1945725Sroot 	dmcrint(0); dmcxint(0);
1955725Sroot #endif
1965725Sroot 	addr->bsel1 = DMC_MCLR;
1975725Sroot 	for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
1985725Sroot 		;
19917565Skarels 	if ((addr->bsel1 & DMC_RUN) == 0) {
20017565Skarels 		printf("dmcprobe: can't start device\n" );
2016334Ssam 		return (0);
20217565Skarels 	}
2035725Sroot 	addr->bsel0 = DMC_RQI|DMC_IEI;
20417565Skarels 	/* let's be paranoid */
20517565Skarels 	addr->bsel0 |= DMC_RQI|DMC_IEI;
20617565Skarels 	DELAY(1000000);
2075725Sroot 	addr->bsel1 = DMC_MCLR;
2085725Sroot 	for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
2095725Sroot 		;
2106334Ssam 	return (1);
2115725Sroot }
2125725Sroot 
2135725Sroot /*
2145725Sroot  * Interface exists: make available by filling in network interface
2155725Sroot  * record.  System will initialize the interface when it is ready
2165725Sroot  * to accept packets.
2175725Sroot  */
2185725Sroot dmcattach(ui)
2195725Sroot 	register struct uba_device *ui;
2205725Sroot {
2215725Sroot 	register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
2225725Sroot 
2235725Sroot 	sc->sc_if.if_unit = ui->ui_unit;
2245725Sroot 	sc->sc_if.if_name = "dmc";
2255725Sroot 	sc->sc_if.if_mtu = DMCMTU;
2265725Sroot 	sc->sc_if.if_init = dmcinit;
2275725Sroot 	sc->sc_if.if_output = dmcoutput;
22813061Ssam 	sc->sc_if.if_ioctl = dmcioctl;
2298976Sroot 	sc->sc_if.if_reset = dmcreset;
23034529Skarels 	sc->sc_if.if_watchdog = dmctimeout;
23117221Stef 	sc->sc_if.if_flags = IFF_POINTOPOINT;
23224796Skarels 	sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
23317221Stef 
23424796Skarels 	if_attach(&sc->sc_if);
2355725Sroot }
2365725Sroot 
2375725Sroot /*
2385725Sroot  * Reset of interface after UNIBUS reset.
23919862Skarels  * If interface is on specified UBA, reset its state.
2405725Sroot  */
2415725Sroot dmcreset(unit, uban)
2425725Sroot 	int unit, uban;
2435725Sroot {
2445725Sroot 	register struct uba_device *ui;
24517221Stef 	register struct dmc_softc *sc = &dmc_softc[unit];
2465725Sroot 
2475725Sroot 	if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
2485725Sroot 	    ui->ui_ubanum != uban)
2495725Sroot 		return;
2505725Sroot 	printf(" dmc%d", unit);
25117565Skarels 	sc->sc_flag = 0;
25219862Skarels 	sc->sc_if.if_flags &= ~IFF_RUNNING;
2535725Sroot 	dmcinit(unit);
2545725Sroot }
2555725Sroot 
2565725Sroot /*
2575725Sroot  * Initialization of interface; reinitialize UNIBUS usage.
2585725Sroot  */
2595725Sroot dmcinit(unit)
2605725Sroot 	int unit;
2615725Sroot {
2625725Sroot 	register struct dmc_softc *sc = &dmc_softc[unit];
2635725Sroot 	register struct uba_device *ui = dmcinfo[unit];
2645725Sroot 	register struct dmcdevice *addr;
26513061Ssam 	register struct ifnet *ifp = &sc->sc_if;
26617221Stef 	register struct ifrw *ifrw;
26717221Stef 	register struct ifxmt *ifxp;
26817221Stef 	register struct dmcbufs *rp;
26917565Skarels 	register struct dmc_command *qp;
27019862Skarels 	struct ifaddr *ifa;
27117221Stef 	int base;
27217565Skarels 	int s;
2735725Sroot 
27417221Stef 	addr = (struct dmcdevice *)ui->ui_addr;
27517221Stef 
27619862Skarels 	/*
27719862Skarels 	 * Check to see that an address has been set
27819862Skarels 	 * (both local and destination for an address family).
27919862Skarels 	 */
28019862Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
28119862Skarels 		if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family)
28219862Skarels 			break;
28319862Skarels 	if (ifa == (struct ifaddr *) 0)
2845725Sroot 		return;
28517221Stef 
28617221Stef 	if ((addr->bsel1&DMC_RUN) == 0) {
28717221Stef 		printf("dmcinit: DMC not running\n");
28819862Skarels 		ifp->if_flags &= ~IFF_UP;
28917221Stef 		return;
29017221Stef 	}
29117221Stef 	/* map base table */
29217565Skarels 	if ((sc->sc_flag & DMC_BMAPPED) == 0) {
29317221Stef 		sc->sc_ubinfo = uballoc(ui->ui_ubanum,
29417221Stef 			(caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0);
29517221Stef 		sc->sc_flag |= DMC_BMAPPED;
29617221Stef 	}
29717221Stef 	/* initialize UNIBUS resources */
29817221Stef 	sc->sc_iused = sc->sc_oused = 0;
29919862Skarels 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
30024796Skarels 		if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum,
30124796Skarels 		    sizeof(struct dmc_header), (int)btoc(DMCMTU),
30224796Skarels 		    sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) {
30319862Skarels 			printf("dmc%d: can't allocate uba resources\n", unit);
30413061Ssam 			ifp->if_flags &= ~IFF_UP;
30513061Ssam 			return;
30613061Ssam 		}
30719862Skarels 		ifp->if_flags |= IFF_RUNNING;
3085725Sroot 	}
30934529Skarels 	sc->sc_flag &= ~DMC_ONLINE;
31027266Skarels 	sc->sc_flag |= DMC_RUNNING;
31134529Skarels 	/*
31234529Skarels 	 * Limit packets enqueued until we see if we're on the air.
31334529Skarels 	 */
31434529Skarels 	ifp->if_snd.ifq_maxlen = 3;
31517221Stef 
31617221Stef 	/* initialize buffer pool */
31717565Skarels 	/* receives */
31824796Skarels 	ifrw = &sc->sc_ifr[0];
31917221Stef 	for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
32017221Stef 		rp->ubinfo = ifrw->ifrw_info & 0x3ffff;
32117565Skarels 		rp->cc = DMCMTU + sizeof (struct dmc_header);
32217221Stef 		rp->flags = DBUF_OURS|DBUF_RCV;
32317221Stef 		ifrw++;
3246363Ssam 	}
32517221Stef 	/* transmits */
32624796Skarels 	ifxp = &sc->sc_ifw[0];
32717221Stef 	for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
32824796Skarels 		rp->ubinfo = ifxp->ifw_info & 0x3ffff;
32917221Stef 		rp->cc = 0;
33017221Stef 		rp->flags = DBUF_OURS|DBUF_XMIT;
33117221Stef 		ifxp++;
33217221Stef 	}
33317565Skarels 
33417565Skarels 	/* set up command queues */
33517565Skarels 	sc->sc_qfreeh = sc->sc_qfreet
33617565Skarels 		 = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive =
33717565Skarels 		(struct dmc_command *)0;
33817565Skarels 	/* set up free command buffer list */
33917565Skarels 	for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) {
34017565Skarels 		QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
34117565Skarels 	}
34217565Skarels 
34317221Stef 	/* base in */
34417221Stef 	base = sc->sc_ubinfo & 0x3ffff;
34517565Skarels 	dmcload(sc, DMC_BASEI, base, (base>>2) & DMC_XMEM);
34617221Stef 	/* specify half duplex operation, flags tell if primary */
34717221Stef 	/* or secondary station */
34817221Stef 	if (ui->ui_flags == 0)
34927266Skarels 		/* use DDCMP mode in full duplex */
35017565Skarels 		dmcload(sc, DMC_CNTLI, 0, 0);
35117221Stef 	else if (ui->ui_flags == 1)
35217565Skarels 		/* use MAINTENENCE mode */
35317565Skarels 		dmcload(sc, DMC_CNTLI, 0, DMC_MAINT );
35417221Stef 	else if (ui->ui_flags == 2)
35517221Stef 		/* use DDCMP half duplex as primary station */
35617221Stef 		dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX);
35717221Stef 	else if (ui->ui_flags == 3)
35817221Stef 		/* use DDCMP half duplex as secondary station */
35917221Stef 		dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC);
36017565Skarels 
36117565Skarels 	/* enable operation done interrupts */
36217565Skarels 	while ((addr->bsel2 & DMC_IEO) == 0)
36317565Skarels 		addr->bsel2 |= DMC_IEO;
36417565Skarels 	s = spl5();
36517221Stef 	/* queue first NRCV buffers for DMC to fill */
36617221Stef 	for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
36717221Stef 		rp->flags |= DBUF_DMCS;
36817221Stef 		dmcload(sc, DMC_READ, rp->ubinfo,
36917565Skarels 			(((rp->ubinfo>>2)&DMC_XMEM) | rp->cc));
37017221Stef 		sc->sc_iused++;
37117221Stef 	}
37217565Skarels 	splx(s);
3735725Sroot }
3745725Sroot 
3755725Sroot /*
3765725Sroot  * Start output on interface.  Get another datagram
3775725Sroot  * to send from the interface queue and map it to
3785725Sroot  * the interface before starting output.
37917221Stef  *
38017221Stef  * Must be called at spl 5
3815725Sroot  */
38234529Skarels dmcstart(unit)
38334529Skarels 	int unit;
3845725Sroot {
3855725Sroot 	register struct dmc_softc *sc = &dmc_softc[unit];
3865725Sroot 	struct mbuf *m;
38717221Stef 	register struct dmcbufs *rp;
38817221Stef 	register int n;
3895725Sroot 
3905725Sroot 	/*
39117221Stef 	 * Dequeue up to NXMT requests and map them to the UNIBUS.
39217221Stef 	 * If no more requests, or no dmc buffers available, just return.
3935725Sroot 	 */
39417221Stef 	n = 0;
39517221Stef 	for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) {
39617221Stef 		/* find an available buffer */
39717565Skarels 		if ((rp->flags & DBUF_DMCS) == 0) {
39817221Stef 			IF_DEQUEUE(&sc->sc_if.if_snd, m);
39917221Stef 			if (m == 0)
40017221Stef 				return;
40117221Stef 			/* mark it dmcs */
40217221Stef 			rp->flags |= (DBUF_DMCS);
40317221Stef 			/*
40417221Stef 			 * Have request mapped to UNIBUS for transmission
40517221Stef 			 * and start the output.
40617221Stef 			 */
40724796Skarels 			rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m);
40817565Skarels 			rp->cc &= DMC_CCOUNT;
40934529Skarels 			if (++sc->sc_oused == 1)
41034529Skarels 				sc->sc_if.if_timer = dmc_timeout;
41117221Stef 			dmcload(sc, DMC_WRITE, rp->ubinfo,
41217221Stef 				rp->cc | ((rp->ubinfo>>2)&DMC_XMEM));
41317221Stef 		}
41417221Stef 		n++;
41517221Stef 	}
4165725Sroot }
4175725Sroot 
4185725Sroot /*
4195725Sroot  * Utility routine to load the DMC device registers.
4205725Sroot  */
4215725Sroot dmcload(sc, type, w0, w1)
4225725Sroot 	register struct dmc_softc *sc;
4235725Sroot 	int type, w0, w1;
4245725Sroot {
4255725Sroot 	register struct dmcdevice *addr;
42617221Stef 	register int unit, sps;
42717221Stef 	register struct dmc_command *qp;
4285725Sroot 
42917565Skarels 	unit = sc - dmc_softc;
4305725Sroot 	addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
4315725Sroot 	sps = spl5();
43217221Stef 
43317221Stef 	/* grab a command buffer from the free list */
43417221Stef 	if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0)
43517221Stef 		panic("dmc command queue overflow");
43617221Stef 	DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet);
43717221Stef 
43817221Stef 	/* fill in requested info */
43917221Stef 	qp->qp_cmd = (type | DMC_RQI);
44017221Stef 	qp->qp_ubaddr = w0;
44117221Stef 	qp->qp_cc = w1;
44217221Stef 
44317221Stef 	if (sc->sc_qactive) {	/* command in progress */
44417221Stef 		if (type == DMC_READ) {
44517221Stef 			QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail);
44617221Stef 		} else {
44717221Stef 			QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail);
44817221Stef 		}
44917221Stef 	} else {	/* command port free */
45017221Stef 		sc->sc_qactive = qp;
45117221Stef 		addr->bsel0 = qp->qp_cmd;
4525725Sroot 		dmcrint(unit);
45317221Stef 	}
4545725Sroot 	splx(sps);
4555725Sroot }
4565725Sroot 
4575725Sroot /*
4585725Sroot  * DMC interface receiver interrupt.
4595725Sroot  * Ready to accept another command,
4605725Sroot  * pull one off the command queue.
4615725Sroot  */
4625725Sroot dmcrint(unit)
4635725Sroot 	int unit;
4645725Sroot {
4655725Sroot 	register struct dmc_softc *sc;
4665725Sroot 	register struct dmcdevice *addr;
46717221Stef 	register struct dmc_command *qp;
4685725Sroot 	register int n;
4695725Sroot 
4705725Sroot 	addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
4715725Sroot 	sc = &dmc_softc[unit];
47217221Stef 	if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) {
47317565Skarels 		printf("dmc%d: dmcrint no command\n", unit);
47417221Stef 		return;
47517221Stef 	}
4765725Sroot 	while (addr->bsel0&DMC_RDYI) {
47717221Stef 		addr->sel4 = qp->qp_ubaddr;
47817221Stef 		addr->sel6 = qp->qp_cc;
4795725Sroot 		addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
48017221Stef 		/* free command buffer */
48117221Stef 		QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
48217221Stef 		while (addr->bsel0 & DMC_RDYI) {
48317221Stef 			/*
48417221Stef 			 * Can't check for RDYO here 'cause
48517221Stef 			 * this routine isn't reentrant!
48617221Stef 			 */
48717221Stef 			DELAY(5);
48817221Stef 		}
48917221Stef 		/* move on to next command */
49017565Skarels 		if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0)
49117565Skarels 			break;		/* all done */
49217221Stef 		/* more commands to do, start the next one */
49317221Stef 		qp = sc->sc_qactive;
49417221Stef 		DEQUEUE(sc->sc_qhead, sc->sc_qtail);
49517221Stef 		addr->bsel0 = qp->qp_cmd;
4965725Sroot 		n = RDYSCAN;
49717565Skarels 		while (n-- > 0)
49817565Skarels 			if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO))
49917565Skarels 				break;
5005725Sroot 	}
50117221Stef 	if (sc->sc_qactive) {
50217221Stef 		addr->bsel0 |= DMC_IEI|DMC_RQI;
50317221Stef 		/* VMS does it twice !*$%@# */
50417221Stef 		addr->bsel0 |= DMC_IEI|DMC_RQI;
50517221Stef 	}
50617565Skarels 
5075725Sroot }
5085725Sroot 
5095725Sroot /*
5105725Sroot  * DMC interface transmitter interrupt.
51117221Stef  * A transfer may have completed, check for errors.
5125725Sroot  * If it was a read, notify appropriate protocol.
5135725Sroot  * If it was a write, pull the next one off the queue.
5145725Sroot  */
5155725Sroot dmcxint(unit)
5165725Sroot 	int unit;
5175725Sroot {
5185725Sroot 	register struct dmc_softc *sc;
51913065Ssam 	register struct ifnet *ifp;
5205725Sroot 	struct uba_device *ui = dmcinfo[unit];
5215725Sroot 	struct dmcdevice *addr;
5225725Sroot 	struct mbuf *m;
52317565Skarels 	struct ifqueue *inq;
52427266Skarels 	int arg, pkaddr, cmd, len, s;
52517221Stef 	register struct ifrw *ifrw;
52617221Stef 	register struct dmcbufs *rp;
52717565Skarels 	register struct ifxmt *ifxp;
52817565Skarels 	struct dmc_header *dh;
52917565Skarels 	int off, resid;
5305725Sroot 
5315725Sroot 	addr = (struct dmcdevice *)ui->ui_addr;
53217221Stef 	sc = &dmc_softc[unit];
53317221Stef 	ifp = &sc->sc_if;
53417221Stef 
53517565Skarels 	while (addr->bsel2 & DMC_RDYO) {
5365725Sroot 
53717565Skarels 		cmd = addr->bsel2 & 0xff;
53817565Skarels 		arg = addr->sel6 & 0xffff;
53917565Skarels 		/* reconstruct UNIBUS address of buffer returned to us */
54017565Skarels 		pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff);
54117565Skarels 		/* release port */
54217565Skarels 		addr->bsel2 &= ~DMC_RDYO;
54317565Skarels 		switch (cmd & 07) {
54417565Skarels 
54517565Skarels 		case DMC_OUR:
54617565Skarels 			/*
54717565Skarels 			 * A read has completed.
54817565Skarels 			 * Pass packet to type specific
54917565Skarels 			 * higher-level input routine.
55017565Skarels 			 */
55117565Skarels 			ifp->if_ipackets++;
55217565Skarels 			/* find location in dmcuba struct */
55324796Skarels 			ifrw= &sc->sc_ifr[0];
55417565Skarels 			for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
55517565Skarels 				if(rp->ubinfo == pkaddr)
55617565Skarels 					break;
55717565Skarels 				ifrw++;
55817565Skarels 			}
55917565Skarels 			if (rp >= &sc->sc_rbufs[NRCV])
56017565Skarels 				panic("dmc rcv");
56117565Skarels 			if ((rp->flags & DBUF_DMCS) == 0)
56217565Skarels 				printf("dmc%d: done unalloc rbuf\n", unit);
56317565Skarels 
56417565Skarels 			len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header);
56517565Skarels 			if (len < 0 || len > DMCMTU) {
56617565Skarels 				ifp->if_ierrors++;
56717565Skarels 				printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n",
56817565Skarels 				    unit, pkaddr, len);
56917565Skarels 				goto setup;
57017565Skarels 			}
57117565Skarels 			/*
57217565Skarels 			 * Deal with trailer protocol: if type is trailer
57317565Skarels 			 * get true type from first 16-bit word past data.
57417565Skarels 			 * Remember that type was trailer by setting off.
57517565Skarels 			 */
57617565Skarels 			dh = (struct dmc_header *)ifrw->ifrw_addr;
57717565Skarels 			dh->dmc_type = ntohs((u_short)dh->dmc_type);
57817565Skarels #define dmcdataaddr(dh, off, type)	((type)(((caddr_t)((dh)+1)+(off))))
57917565Skarels 			if (dh->dmc_type >= DMC_TRAILER &&
58017565Skarels 			    dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) {
58117565Skarels 				off = (dh->dmc_type - DMC_TRAILER) * 512;
58217565Skarels 				if (off >= DMCMTU)
58317565Skarels 					goto setup;		/* sanity */
58417565Skarels 				dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *));
58517565Skarels 				resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *)));
58617565Skarels 				if (off + resid > len)
58717565Skarels 					goto setup;		/* sanity */
58817565Skarels 				len = off + resid;
58917565Skarels 			} else
59017565Skarels 				off = 0;
59117565Skarels 			if (len == 0)
59217565Skarels 				goto setup;
59317565Skarels 
59417565Skarels 			/*
59517565Skarels 			 * Pull packet off interface.  Off is nonzero if
59617565Skarels 			 * packet has trailing header; dmc_get will then
59717565Skarels 			 * force this header information to be at the front,
59817565Skarels 			 * but we still have to drop the type and length
59917565Skarels 			 * which are at the front of any trailer data.
60017565Skarels 			 */
60124796Skarels 			m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);
60217565Skarels 			if (m == 0)
60317565Skarels 				goto setup;
60417565Skarels 			if (off) {
60524796Skarels 				ifp = *(mtod(m, struct ifnet **));
60617565Skarels 				m->m_off += 2 * sizeof (u_short);
60717565Skarels 				m->m_len -= 2 * sizeof (u_short);
60824796Skarels 				*(mtod(m, struct ifnet **)) = ifp;
60917565Skarels 			}
61017565Skarels 			switch (dh->dmc_type) {
61117565Skarels 
6125725Sroot #ifdef INET
61317565Skarels 			case DMC_IPTYPE:
61417565Skarels 				schednetisr(NETISR_IP);
61517565Skarels 				inq = &ipintrq;
61617565Skarels 				break;
6175725Sroot #endif
61817565Skarels 			default:
61917565Skarels 				m_freem(m);
62017565Skarels 				goto setup;
62117565Skarels 			}
6225725Sroot 
62327266Skarels 			s = splimp();
62417565Skarels 			if (IF_QFULL(inq)) {
62517565Skarels 				IF_DROP(inq);
62617565Skarels 				m_freem(m);
62717565Skarels 			} else
62817565Skarels 				IF_ENQUEUE(inq, m);
62927266Skarels 			splx(s);
63017221Stef 
63117565Skarels 	setup:
63217565Skarels 			/* is this needed? */
63317565Skarels 			rp->ubinfo = ifrw->ifrw_info & 0x3ffff;
6345725Sroot 
63517565Skarels 			dmcload(sc, DMC_READ, rp->ubinfo,
63617565Skarels 			    ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc);
63717565Skarels 			break;
6385725Sroot 
63917565Skarels 		case DMC_OUX:
64017565Skarels 			/*
64117565Skarels 			 * A write has completed, start another
64217565Skarels 			 * transfer if there is more data to send.
64317565Skarels 			 */
64417565Skarels 			ifp->if_opackets++;
64517565Skarels 			/* find associated dmcbuf structure */
64624796Skarels 			ifxp = &sc->sc_ifw[0];
64717565Skarels 			for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
64817565Skarels 				if(rp->ubinfo == pkaddr)
64917565Skarels 					break;
65017565Skarels 				ifxp++;
65117565Skarels 			}
65217565Skarels 			if (rp >= &sc->sc_xbufs[NXMT]) {
65317565Skarels 				printf("dmc%d: bad packet address 0x%x\n",
65417565Skarels 				    unit, pkaddr);
65517565Skarels 				break;
65617565Skarels 			}
65717565Skarels 			if ((rp->flags & DBUF_DMCS) == 0)
65817565Skarels 				printf("dmc%d: unallocated packet 0x%x\n",
65917565Skarels 				    unit, pkaddr);
66017565Skarels 			/* mark buffer free */
66124796Skarels 			if (ifxp->ifw_xtofree) {
66224796Skarels 				(void)m_freem(ifxp->ifw_xtofree);
66324796Skarels 				ifxp->ifw_xtofree = 0;
66417565Skarels 			}
66517565Skarels 			rp->flags &= ~DBUF_DMCS;
66634529Skarels 			if (--sc->sc_oused == 0)
66734529Skarels 				sc->sc_if.if_timer = 0;
66834529Skarels 			else
66934529Skarels 				sc->sc_if.if_timer = dmc_timeout;
67034529Skarels 			if ((sc->sc_flag & DMC_ONLINE) == 0) {
67134529Skarels 				extern int ifqmaxlen;
67234529Skarels 
67334529Skarels 				/*
67434529Skarels 				 * We're on the air.
67534529Skarels 				 * Open the queue to the usual value.
67634529Skarels 				 */
67734529Skarels 				sc->sc_flag |= DMC_ONLINE;
67834529Skarels 				ifp->if_snd.ifq_maxlen = ifqmaxlen;
67934529Skarels 			}
68017565Skarels 			break;
68117221Stef 
68217565Skarels 		case DMC_CNTLO:
68317565Skarels 			arg &= DMC_CNTMASK;
68417565Skarels 			if (arg & DMC_FATAL) {
68534529Skarels 				if (arg != DMC_START)
68634529Skarels 					log(LOG_ERR,
68734529Skarels 					    "dmc%d: fatal error, flags=%b\n",
68834529Skarels 					    unit, arg, CNTLO_BITS);
68917565Skarels 				dmcrestart(unit);
69017565Skarels 				break;
69117565Skarels 			}
69217565Skarels 			/* ACCUMULATE STATISTICS */
69317221Stef 			switch(arg) {
69417221Stef 			case DMC_NOBUFS:
69517565Skarels 				ifp->if_ierrors++;
69617565Skarels 				if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0)
69717565Skarels 					goto report;
69817565Skarels 				break;
69917221Stef 			case DMC_DISCONN:
70017565Skarels 				if ((sc->sc_disc++ % DMC_RPDSC) == 0)
70117565Skarels 					goto report;
70217565Skarels 				break;
70317221Stef 			case DMC_TIMEOUT:
70417565Skarels 				if ((sc->sc_timeo++ % DMC_RPTMO) == 0)
70517565Skarels 					goto report;
70617565Skarels 				break;
70717221Stef 			case DMC_DATACK:
70817565Skarels 				ifp->if_oerrors++;
70917565Skarels 				if ((sc->sc_datck++ % DMC_RPDCK) == 0)
71017565Skarels 					goto report;
71117565Skarels 				break;
71217221Stef 			default:
71317221Stef 				goto report;
71417221Stef 			}
71517221Stef 			break;
71617221Stef 		report:
71717565Skarels 			printd("dmc%d: soft error, flags=%b\n", unit,
71817565Skarels 			    arg, CNTLO_BITS);
71917565Skarels 			if ((sc->sc_flag & DMC_RESTART) == 0) {
72017565Skarels 				/*
72117565Skarels 				 * kill off the dmc to get things
72217565Skarels 				 * going again by generating a
72317565Skarels 				 * procedure error
72417565Skarels 				 */
72517565Skarels 				sc->sc_flag |= DMC_RESTART;
72617565Skarels 				arg = sc->sc_ubinfo & 0x3ffff;
72717565Skarels 				dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM);
72817565Skarels 			}
72917565Skarels 			break;
73017565Skarels 
73117565Skarels 		default:
73217565Skarels 			printf("dmc%d: bad control %o\n", unit, cmd);
73317565Skarels 			break;
7345725Sroot 		}
7355725Sroot 	}
73617565Skarels 	dmcstart(unit);
73717221Stef 	return;
7385725Sroot }
7395725Sroot 
7405725Sroot /*
7415725Sroot  * DMC output routine.
74217565Skarels  * Encapsulate a packet of type family for the dmc.
74317565Skarels  * Use trailer local net encapsulation if enough data in first
74417565Skarels  * packet leaves a multiple of 512 bytes of data in remainder.
7455725Sroot  */
74617565Skarels dmcoutput(ifp, m0, dst)
7475725Sroot 	register struct ifnet *ifp;
74817565Skarels 	register struct mbuf *m0;
7496334Ssam 	struct sockaddr *dst;
7505725Sroot {
75117565Skarels 	int type, error, s;
75217565Skarels 	register struct mbuf *m = m0;
75317565Skarels 	register struct dmc_header *dh;
75417565Skarels 	register int off;
7555725Sroot 
75634529Skarels 	if ((ifp->if_flags & IFF_UP) == 0) {
75734529Skarels 		error = ENETDOWN;
75834529Skarels 		goto bad;
75934529Skarels 	}
76034529Skarels 
76117565Skarels 	switch (dst->sa_family) {
76217565Skarels #ifdef	INET
76317565Skarels 	case AF_INET:
76417565Skarels 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
76517565Skarels 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
76617565Skarels 		if (off > 0 && (off & 0x1ff) == 0 &&
76717565Skarels 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
76817565Skarels 			type = DMC_TRAILER + (off>>9);
76917565Skarels 			m->m_off -= 2 * sizeof (u_short);
77017565Skarels 			m->m_len += 2 * sizeof (u_short);
77117565Skarels 			*mtod(m, u_short *) = htons((u_short)DMC_IPTYPE);
77217565Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
77317565Skarels 			goto gottrailertype;
77417565Skarels 		}
77517565Skarels 		type = DMC_IPTYPE;
77617565Skarels 		off = 0;
77717565Skarels 		goto gottype;
77817565Skarels #endif
77917565Skarels 
78017565Skarels 	case AF_UNSPEC:
78117565Skarels 		dh = (struct dmc_header *)dst->sa_data;
78217565Skarels 		type = dh->dmc_type;
78317565Skarels 		goto gottype;
78417565Skarels 
78517565Skarels 	default:
78617565Skarels 		printf("dmc%d: can't handle af%d\n", ifp->if_unit,
78717565Skarels 			dst->sa_family);
78817565Skarels 		error = EAFNOSUPPORT;
78917565Skarels 		goto bad;
7905725Sroot 	}
79117565Skarels 
79217565Skarels gottrailertype:
79317565Skarels 	/*
79417565Skarels 	 * Packet to be sent as a trailer; move first packet
79517565Skarels 	 * (control information) to end of chain.
79617565Skarels 	 */
79717565Skarels 	while (m->m_next)
79817565Skarels 		m = m->m_next;
79917565Skarels 	m->m_next = m0;
80017565Skarels 	m = m0->m_next;
80117565Skarels 	m0->m_next = 0;
80217565Skarels 	m0 = m;
80317565Skarels 
80417565Skarels gottype:
80517565Skarels 	/*
80617565Skarels 	 * Add local network header
80717565Skarels 	 * (there is space for a uba on a vax to step on)
80817565Skarels 	 */
80917565Skarels 	if (m->m_off > MMAXOFF ||
81017565Skarels 	    MMINOFF + sizeof(struct dmc_header) > m->m_off) {
81117565Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
81217565Skarels 		if (m == 0) {
81317565Skarels 			error = ENOBUFS;
81417565Skarels 			goto bad;
81517565Skarels 		}
81617565Skarels 		m->m_next = m0;
81717565Skarels 		m->m_off = MMINOFF;
81817565Skarels 		m->m_len = sizeof (struct dmc_header);
81917565Skarels 	} else {
82017565Skarels 		m->m_off -= sizeof (struct dmc_header);
82117565Skarels 		m->m_len += sizeof (struct dmc_header);
82217565Skarels 	}
82317565Skarels 	dh = mtod(m, struct dmc_header *);
82417565Skarels 	dh->dmc_type = htons((u_short)type);
82517565Skarels 
82617565Skarels 	/*
82717565Skarels 	 * Queue message on interface, and start output if interface
82817565Skarels 	 * not yet active.
82917565Skarels 	 */
83017565Skarels 	s = splimp();
8316207Swnj 	if (IF_QFULL(&ifp->if_snd)) {
8326207Swnj 		IF_DROP(&ifp->if_snd);
8336334Ssam 		m_freem(m);
8346207Swnj 		splx(s);
8356502Ssam 		return (ENOBUFS);
8366207Swnj 	}
8375725Sroot 	IF_ENQUEUE(&ifp->if_snd, m);
83817221Stef 	dmcstart(ifp->if_unit);
8395725Sroot 	splx(s);
8406502Ssam 	return (0);
84117565Skarels 
84217565Skarels bad:
84317565Skarels 	m_freem(m0);
84417565Skarels 	return (error);
8455725Sroot }
84613061Ssam 
84717565Skarels 
84813061Ssam /*
84913061Ssam  * Process an ioctl request.
85013061Ssam  */
85124796Skarels /* ARGSUSED */
85213061Ssam dmcioctl(ifp, cmd, data)
85313061Ssam 	register struct ifnet *ifp;
85413061Ssam 	int cmd;
85513061Ssam 	caddr_t data;
85613061Ssam {
85713061Ssam 	int s = splimp(), error = 0;
85827266Skarels 	register struct dmc_softc *sc = &dmc_softc[ifp->if_unit];
85913061Ssam 
86013061Ssam 	switch (cmd) {
86113061Ssam 
86213061Ssam 	case SIOCSIFADDR:
86317221Stef 		ifp->if_flags |= IFF_UP;
86419862Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
86519862Skarels 			dmcinit(ifp->if_unit);
86613061Ssam 		break;
86713061Ssam 
86813061Ssam 	case SIOCSIFDSTADDR:
86919862Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
87019862Skarels 			dmcinit(ifp->if_unit);
87113061Ssam 		break;
87217221Stef 
87327266Skarels 	case SIOCSIFFLAGS:
87427266Skarels 		if ((ifp->if_flags & IFF_UP) == 0 &&
87534529Skarels 		    sc->sc_flag & DMC_RUNNING)
87634529Skarels 			dmcdown(ifp->if_unit);
87734529Skarels 		else if (ifp->if_flags & IFF_UP &&
87827266Skarels 		    (sc->sc_flag & DMC_RUNNING) == 0)
87927266Skarels 			dmcrestart(ifp->if_unit);
88027266Skarels 		break;
88127266Skarels 
88213061Ssam 	default:
88313061Ssam 		error = EINVAL;
88413061Ssam 	}
88513061Ssam 	splx(s);
88613061Ssam 	return (error);
88713061Ssam }
88817221Stef 
88917221Stef /*
89017565Skarels  * Restart after a fatal error.
89117565Skarels  * Clear device and reinitialize.
89217565Skarels  */
89317565Skarels dmcrestart(unit)
89417565Skarels 	int unit;
89517565Skarels {
89617565Skarels 	register struct dmc_softc *sc = &dmc_softc[unit];
89717565Skarels 	register struct dmcdevice *addr;
89817565Skarels 	register int i;
89934529Skarels 	int s;
90017565Skarels 
90117565Skarels #ifdef DEBUG
90217565Skarels 	/* dump base table */
90317565Skarels 	printf("dmc%d base table:\n", unit);
90417565Skarels 	for (i = 0; i < sizeof (struct dmc_base); i++)
90517565Skarels 		printf("%o\n" ,dmc_base[unit].d_base[i]);
90613085Ssam #endif
90734529Skarels 
90834529Skarels 	dmcdown(unit);
90934529Skarels 
91017565Skarels 	/*
91117565Skarels 	 * Let the DMR finish the MCLR.	 At 1 Mbit, it should do so
91217565Skarels 	 * in about a max of 6.4 milliseconds with diagnostics enabled.
91317565Skarels 	 */
91434529Skarels 	addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
91517565Skarels 	for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
91617565Skarels 		;
91717565Skarels 	/* Did the timer expire or did the DMR finish? */
91817565Skarels 	if ((addr->bsel1 & DMC_RUN) == 0) {
91926282Skarels 		log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit);
92017565Skarels 		return;
92117565Skarels 	}
92217565Skarels 
92334529Skarels 	/* restart DMC */
92434529Skarels 	dmcinit(unit);
92534529Skarels 	sc->sc_flag &= ~DMC_RESTART;
92634529Skarels 	s = spl5();
92734529Skarels 	dmcstart(unit);
92834529Skarels 	splx(s);
92934529Skarels 	sc->sc_if.if_collisions++;	/* why not? */
93034529Skarels }
93134529Skarels 
93234529Skarels /*
93334529Skarels  * Reset a device and mark down.
93434529Skarels  * Flush output queue and drop queue limit.
93534529Skarels  */
93634529Skarels dmcdown(unit)
93734529Skarels 	int unit;
93834529Skarels {
93934529Skarels 	register struct dmc_softc *sc = &dmc_softc[unit];
94034529Skarels 	register struct ifxmt *ifxp;
94134529Skarels 
94234529Skarels 	((struct dmcdevice *)(dmcinfo[unit]->ui_addr))->bsel1 = DMC_MCLR;
94334529Skarels 	sc->sc_flag &= ~(DMC_RUNNING | DMC_ONLINE);
94434529Skarels 
94524796Skarels 	for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
94624796Skarels 		if (ifxp->ifw_xtofree) {
94724796Skarels 			(void) m_freem(ifxp->ifw_xtofree);
94824796Skarels 			ifxp->ifw_xtofree = 0;
94917565Skarels 		}
95017565Skarels 	}
95134529Skarels 	if_qflush(&sc->sc_if.if_snd);
95217565Skarels }
95317565Skarels 
95417565Skarels /*
95534529Skarels  * Watchdog timeout to see that transmitted packets don't
95634529Skarels  * lose interrupts.  The device has to be online (the first
95734529Skarels  * transmission may block until the other side comes up).
95817565Skarels  */
95934529Skarels dmctimeout(unit)
96034529Skarels 	int unit;
96117565Skarels {
96217565Skarels 	register struct dmc_softc *sc;
96317565Skarels 	struct dmcdevice *addr;
96417565Skarels 
96534529Skarels 	sc = &dmc_softc[unit];
96634529Skarels 	if (sc->sc_flag & DMC_ONLINE) {
96734529Skarels 		addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
96834529Skarels 		log(LOG_ERR, "dmc%d: output timeout, bsel0=%b bsel2=%b\n",
96934529Skarels 		    unit, addr->bsel0 & 0xff, DMC0BITS,
97034529Skarels 		    addr->bsel2 & 0xff, DMC2BITS);
97134529Skarels 		dmcrestart(unit);
97217565Skarels 	}
97317565Skarels }
97417565Skarels #endif
975