xref: /csrg-svn/sys/vax/if/if_dmv.c (revision 31908)
1*31908Skarels /*
2*31908Skarels  * @(#)if_dmv.c	7.1 (Berkeley) 07/20/87
3*31908Skarels  * DMV-11 Driver
4*31908Skarels  *
5*31908Skarels  * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode
6*31908Skarels  *
7*31908Skarels  * Derived from 4.3 release if_dmv.c rev. 6.12 dated 4/23/86
8*31908Skarels  * (which wasn't the 4.3 release!)
9*31908Skarels  *
10*31908Skarels  * Bob Kridle
11*31908Skarels  * mt Xinu
12*31908Skarels  */
13*31908Skarels 
14*31908Skarels #include "dmv.h"
15*31908Skarels #if NDMV > 0
16*31908Skarels 
17*31908Skarels 
18*31908Skarels #include "../machine/pte.h"
19*31908Skarels 
20*31908Skarels #include "param.h"
21*31908Skarels #include "systm.h"
22*31908Skarels #include "mbuf.h"
23*31908Skarels #include "buf.h"
24*31908Skarels #include "ioctl.h"		/* must precede tty.h */
25*31908Skarels #include "tty.h"
26*31908Skarels #include "protosw.h"
27*31908Skarels #include "socket.h"
28*31908Skarels #include "syslog.h"
29*31908Skarels #include "vmmac.h"
30*31908Skarels #include "errno.h"
31*31908Skarels 
32*31908Skarels #include "../net/if.h"
33*31908Skarels #include "../net/netisr.h"
34*31908Skarels #include "../net/route.h"
35*31908Skarels 
36*31908Skarels #ifdef	INET
37*31908Skarels #include "../netinet/in.h"
38*31908Skarels #include "../netinet/in_systm.h"
39*31908Skarels #include "../netinet/in_var.h"
40*31908Skarels #include "../netinet/ip.h"
41*31908Skarels #endif
42*31908Skarels 
43*31908Skarels #include "../vax/cpu.h"
44*31908Skarels #include "../vax/mtpr.h"
45*31908Skarels #include "if_uba.h"
46*31908Skarels #include "if_dmv.h"
47*31908Skarels #include "../vaxuba/ubareg.h"
48*31908Skarels #include "../vaxuba/ubavar.h"
49*31908Skarels 
50*31908Skarels #include "../h/time.h"
51*31908Skarels #include "../h/kernel.h"
52*31908Skarels 
53*31908Skarels int	dmvtimer;			/* timer started? */
54*31908Skarels int	dmv_timeout = 8;		/* timeout value */
55*31908Skarels int	dmvwatch();
56*31908Skarels 
57*31908Skarels /*
58*31908Skarels  * Driver information for auto-configuration stuff.
59*31908Skarels  */
60*31908Skarels int	dmvprobe(), dmvattach(), dmvinit(), dmvioctl();
61*31908Skarels int	dmvoutput(), dmvreset();
62*31908Skarels struct	uba_device *dmvinfo[NDMV];
63*31908Skarels u_short	dmvstd[] = { 0 };
64*31908Skarels struct	uba_driver dmvdriver =
65*31908Skarels 	{ dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo };
66*31908Skarels 
67*31908Skarels /*
68*31908Skarels  * Don't really know how many buffers/commands can be queued to a DMV-11.
69*31908Skarels  * Manual doesn't say... Perhaps we can look at a DEC driver some day.
70*31908Skarels  * These numbers ame from DMV/DMR driver.
71*31908Skarels  */
72*31908Skarels #define NRCV 5
73*31908Skarels #define NXMT 3
74*31908Skarels #define NCMDS	(NRCV+NXMT+4)	/* size of command queue */
75*31908Skarels 
76*31908Skarels #define printd   if (sc->sc_if.if_flags & IFF_DEBUG) \
77*31908Skarels 	printf("DMVDEBUG: dmv%d: ", unit), printf
78*31908Skarels 
79*31908Skarels /* error reporting intervals */
80*31908Skarels 
81*31908Skarels #define	DMV_RPRTE	 1
82*31908Skarels #define	DMV_RPTTE        1
83*31908Skarels #define	DMV_RPSTE	 1
84*31908Skarels #define DMV_RPNXM        1
85*31908Skarels #define DMV_RPMODD       1
86*31908Skarels #define DMV_RPQOVF	 1
87*31908Skarels #define DMV_RPCXRL	 1
88*31908Skarels #define DMV_RPUNKNOWN	 1
89*31908Skarels 
90*31908Skarels struct  dmv_command {
91*31908Skarels 	u_char	qp_mask;	/* Which registers to set up */
92*31908Skarels #define	QP_TRIB		0x01
93*31908Skarels #define	QP_SEL4		0x02
94*31908Skarels #define	QP_SEL6		0x04
95*31908Skarels #define	QP_SEL10	0x08
96*31908Skarels 	u_char	qp_cmd;
97*31908Skarels 	u_char	qp_tributary;
98*31908Skarels 	u_short	qp_sel4;
99*31908Skarels 	u_short	qp_sel6;
100*31908Skarels 	u_short	qp_sel10;
101*31908Skarels 	struct	dmv_command *qp_next;	/* next command on queue */
102*31908Skarels };
103*31908Skarels 
104*31908Skarels #define	qp_lowbufaddr	qp_
105*31908Skarels 
106*31908Skarels struct dmvbufs {
107*31908Skarels 	int	ubinfo;		/* from uballoc */
108*31908Skarels 	short	cc;		/* buffer size */
109*31908Skarels 	short	flags;		/* access control */
110*31908Skarels };
111*31908Skarels 
112*31908Skarels #define	DBUF_OURS	0	/* buffer is available */
113*31908Skarels #define	DBUF_DMVS	1	/* buffer claimed by somebody */
114*31908Skarels #define	DBUF_XMIT	4	/* transmit buffer */
115*31908Skarels #define	DBUF_RCV	8	/* receive buffer */
116*31908Skarels 
117*31908Skarels 
118*31908Skarels /*
119*31908Skarels  * DMV software status per interface.
120*31908Skarels  *
121*31908Skarels  * Each interface is referenced by a network interface structure,
122*31908Skarels  * sc_if, which the routing code uses to locate the interface.
123*31908Skarels  * This structure contains the output queue for the interface, its address, ...
124*31908Skarels  * We also have, for each interface, a  set of 7 UBA interface structures
125*31908Skarels  * for each, which
126*31908Skarels  * contain information about the UNIBUS resources held by the interface:
127*31908Skarels  * map registers, buffered data paths, etc.  Information is cached in this
128*31908Skarels  * structure for use by the if_uba.c routines in running the interface
129*31908Skarels  * efficiently.
130*31908Skarels  */
131*31908Skarels struct dmv_softc {
132*31908Skarels 	struct	ifnet sc_if;		/* network-visible interface */
133*31908Skarels 	struct	dmvbufs sc_rbufs[NRCV];	/* receive buffer info */
134*31908Skarels 	struct	dmvbufs sc_xbufs[NXMT];	/* transmit buffer info */
135*31908Skarels 	struct	ifubinfo sc_ifuba;	/* UNIBUS resources */
136*31908Skarels 	struct	ifrw sc_ifr[NRCV];	/* UNIBUS receive buffer maps */
137*31908Skarels 	struct	ifxmt sc_ifw[NXMT];	/* UNIBUS receive buffer maps */
138*31908Skarels 	short	sc_oused;		/* output buffers currently in use */
139*31908Skarels 	short	sc_iused;		/* input buffers given to DMV */
140*31908Skarels 	short	sc_flag;		/* flags */
141*31908Skarels 	int	sc_nticks;		/* seconds since last interrupt */
142*31908Skarels 	int	sc_ubinfo;		/* UBA mapping info for base table */
143*31908Skarels 	int	sc_errors[8];		/* error counters */
144*31908Skarels #define	sc_rte	sc_errors[0]		/* receive threshhold error */
145*31908Skarels #define	sc_xte	sc_errors[1]		/* xmit threshhold error */
146*31908Skarels #define	sc_ste	sc_errors[2]		/* select threshhold error */
147*31908Skarels #define	sc_nxm	sc_errors[3]		/* non-existant memory */
148*31908Skarels #define	sc_modd	sc_errors[4]		/* modem disconnect */
149*31908Skarels #define	sc_qovf	sc_errors[5]		/* command/response queue overflow */
150*31908Skarels #define	sc_cxrl	sc_errors[6]		/* carrier loss */
151*31908Skarels #define sc_unknown sc_errors[7]		/* other errors - look in DMV manual */
152*31908Skarels 	/* command queue stuff */
153*31908Skarels 	struct	dmv_command sc_cmdbuf[NCMDS];
154*31908Skarels 	struct	dmv_command *sc_qhead;	/* head of command queue */
155*31908Skarels 	struct	dmv_command *sc_qtail;	/* tail of command queue */
156*31908Skarels 	struct	dmv_command *sc_qactive;	/* command in progress */
157*31908Skarels 	struct	dmv_command *sc_qfreeh;	/* head of list of free cmd buffers */
158*31908Skarels 	struct	dmv_command *sc_qfreet;	/* tail of list of free cmd buffers */
159*31908Skarels 	/* end command queue stuff */
160*31908Skarels } dmv_softc[NDMV];
161*31908Skarels 
162*31908Skarels /* flags */
163*31908Skarels #define DMV_ALLOC	0x01		/* unibus resources allocated */
164*31908Skarels #define DMV_RESTART	0x04		/* software restart in progress */
165*31908Skarels #define DMV_ACTIVE	0x08		/* device active */
166*31908Skarels #define DMV_RUNNING	0x20		/* device initialized */
167*31908Skarels 
168*31908Skarels 
169*31908Skarels /* queue manipulation macros */
170*31908Skarels #define	QUEUE_AT_HEAD(qp, head, tail) \
171*31908Skarels 	(qp)->qp_next = (head); \
172*31908Skarels 	(head) = (qp); \
173*31908Skarels 	if ((tail) == (struct dmv_command *) 0) \
174*31908Skarels 		(tail) = (head)
175*31908Skarels 
176*31908Skarels #define QUEUE_AT_TAIL(qp, head, tail) \
177*31908Skarels 	if ((tail)) \
178*31908Skarels 		(tail)->qp_next = (qp); \
179*31908Skarels 	else \
180*31908Skarels 		(head) = (qp); \
181*31908Skarels 	(qp)->qp_next = (struct dmv_command *) 0; \
182*31908Skarels 	(tail) = (qp)
183*31908Skarels 
184*31908Skarels #define DEQUEUE(head, tail) \
185*31908Skarels 	(head) = (head)->qp_next;\
186*31908Skarels 	if ((head) == (struct dmv_command *) 0)\
187*31908Skarels 		(tail) = (head)
188*31908Skarels 
189*31908Skarels dmvprobe(reg)
190*31908Skarels 	caddr_t reg;
191*31908Skarels {
192*31908Skarels 	register int br, cvec;
193*31908Skarels 	register struct dmvdevice *addr = (struct dmvdevice *)reg;
194*31908Skarels 	register int i;
195*31908Skarels 
196*31908Skarels #ifdef lint
197*31908Skarels 	br = 0; cvec = br; br = cvec;
198*31908Skarels 	dmvrint(0); dmvxint(0);
199*31908Skarels #endif
200*31908Skarels 	addr->bsel1 = DMV_MCLR;
201*31908Skarels 	for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--)
202*31908Skarels 		;
203*31908Skarels 	if ((addr->bsel1 & DMV_RUN) == 0) {
204*31908Skarels 		printf("dmvprobe: can't start device\n" );
205*31908Skarels 		return (0);
206*31908Skarels 	}
207*31908Skarels 	if ((addr->bsel4 != 033) || (addr->bsel6 != 0305))
208*31908Skarels 	{
209*31908Skarels 		printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n",
210*31908Skarels 			addr->bsel4, addr->bsel6);
211*31908Skarels 		return (0);
212*31908Skarels 	}
213*31908Skarels 	addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO;
214*31908Skarels 	DELAY(1000000);
215*31908Skarels 	addr->bsel1 = DMV_MCLR;
216*31908Skarels 	for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--)
217*31908Skarels 		;
218*31908Skarels 	return (1);
219*31908Skarels }
220*31908Skarels 
221*31908Skarels /*
222*31908Skarels  * Interface exists: make available by filling in network interface
223*31908Skarels  * record.  System will initialize the interface when it is ready
224*31908Skarels  * to accept packets.
225*31908Skarels  */
226*31908Skarels dmvattach(ui)
227*31908Skarels 	register struct uba_device *ui;
228*31908Skarels {
229*31908Skarels 	register struct dmv_softc *sc = &dmv_softc[ui->ui_unit];
230*31908Skarels 
231*31908Skarels 	sc->sc_if.if_unit = ui->ui_unit;
232*31908Skarels 	sc->sc_if.if_name = "dmv";
233*31908Skarels 	sc->sc_if.if_mtu = DMVMTU;
234*31908Skarels 	sc->sc_if.if_init = dmvinit;
235*31908Skarels 	sc->sc_if.if_output = dmvoutput;
236*31908Skarels 	sc->sc_if.if_ioctl = dmvioctl;
237*31908Skarels 	sc->sc_if.if_reset = dmvreset;
238*31908Skarels 	sc->sc_if.if_flags = IFF_POINTOPOINT;
239*31908Skarels 	sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
240*31908Skarels 
241*31908Skarels 	if (dmvtimer == 0) {
242*31908Skarels 		dmvtimer = 1;
243*31908Skarels 		timeout(dmvwatch, (caddr_t) 0, hz);
244*31908Skarels 	}
245*31908Skarels 	if_attach(&sc->sc_if);
246*31908Skarels }
247*31908Skarels 
248*31908Skarels /*
249*31908Skarels  * Reset of interface after UNIBUS reset.
250*31908Skarels  * If interface is on specified UBA, reset its state.
251*31908Skarels  */
252*31908Skarels dmvreset(unit, uban)
253*31908Skarels 	int unit, uban;
254*31908Skarels {
255*31908Skarels 	register struct uba_device *ui;
256*31908Skarels 	register struct dmv_softc *sc = &dmv_softc[unit];
257*31908Skarels 
258*31908Skarels 	if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 ||
259*31908Skarels 	    ui->ui_ubanum != uban)
260*31908Skarels 		return;
261*31908Skarels 	printf(" dmv%d", unit);
262*31908Skarels 	sc->sc_flag = 0;
263*31908Skarels 	sc->sc_if.if_flags &= ~IFF_RUNNING;
264*31908Skarels 	dmvinit(unit);
265*31908Skarels }
266*31908Skarels 
267*31908Skarels /*
268*31908Skarels  * Initialization of interface; reinitialize UNIBUS usage.
269*31908Skarels  */
270*31908Skarels dmvinit(unit)
271*31908Skarels 	int unit;
272*31908Skarels {
273*31908Skarels 	register struct dmv_softc *sc = &dmv_softc[unit];
274*31908Skarels 	register struct uba_device *ui = dmvinfo[unit];
275*31908Skarels 	register struct dmvdevice *addr;
276*31908Skarels 	register struct ifnet *ifp = &sc->sc_if;
277*31908Skarels 	register struct ifrw *ifrw;
278*31908Skarels 	register struct ifxmt *ifxp;
279*31908Skarels 	register struct dmvbufs *rp;
280*31908Skarels 	register struct dmv_command *qp;
281*31908Skarels 	struct ifaddr *ifa;
282*31908Skarels 	int base;
283*31908Skarels 	int s;
284*31908Skarels 
285*31908Skarels 	addr = (struct dmvdevice *)ui->ui_addr;
286*31908Skarels 
287*31908Skarels 	/*
288*31908Skarels 	 * Check to see that an address has been set
289*31908Skarels 	 * (both local and destination for an address family).
290*31908Skarels 	 */
291*31908Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
292*31908Skarels 		if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family)
293*31908Skarels 			break;
294*31908Skarels 	if (ifa == (struct ifaddr *) 0)
295*31908Skarels 		return;
296*31908Skarels 
297*31908Skarels 	if ((addr->bsel1&DMV_RUN) == 0) {
298*31908Skarels 		log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit);
299*31908Skarels 		ifp->if_flags &= ~IFF_UP;
300*31908Skarels 		return;
301*31908Skarels 	}
302*31908Skarels 	printd("dmvinit\n");
303*31908Skarels 	/* initialize UNIBUS resources */
304*31908Skarels 	sc->sc_iused = sc->sc_oused = 0;
305*31908Skarels 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
306*31908Skarels 		if (if_ubaminit(
307*31908Skarels 			&sc->sc_ifuba,
308*31908Skarels 			ui->ui_ubanum,
309*31908Skarels 		    	sizeof(struct dmv_header),
310*31908Skarels 			(int)btoc(DMVMTU),
311*31908Skarels 			sc->sc_ifr,
312*31908Skarels 			NRCV,
313*31908Skarels 			sc->sc_ifw,
314*31908Skarels 			NXMT
315*31908Skarels 	      	) == 0) {
316*31908Skarels 			log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit);
317*31908Skarels 			ifp->if_flags &= ~IFF_UP;
318*31908Skarels 			return;
319*31908Skarels 		}
320*31908Skarels 		ifp->if_flags |= IFF_RUNNING;
321*31908Skarels 	}
322*31908Skarels 
323*31908Skarels 	/* initialize buffer pool */
324*31908Skarels 	/* receives */
325*31908Skarels 	ifrw = &sc->sc_ifr[0];
326*31908Skarels 	for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
327*31908Skarels 		rp->ubinfo = ifrw->ifrw_info & 0x3ffff;
328*31908Skarels 		rp->cc = DMVMTU + sizeof (struct dmv_header);
329*31908Skarels 		rp->flags = DBUF_OURS|DBUF_RCV;
330*31908Skarels 		ifrw++;
331*31908Skarels 	}
332*31908Skarels 	/* transmits */
333*31908Skarels 	ifxp = &sc->sc_ifw[0];
334*31908Skarels 	for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
335*31908Skarels 		rp->ubinfo = ifxp->ifw_info & 0x3ffff;
336*31908Skarels 		rp->cc = 0;
337*31908Skarels 		rp->flags = DBUF_OURS|DBUF_XMIT;
338*31908Skarels 		ifxp++;
339*31908Skarels 	}
340*31908Skarels 
341*31908Skarels 	/* set up command queues */
342*31908Skarels 	sc->sc_qfreeh = sc->sc_qfreet
343*31908Skarels 		 = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive =
344*31908Skarels 		(struct dmv_command *)0;
345*31908Skarels 	/* set up free command buffer list */
346*31908Skarels 	for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) {
347*31908Skarels 		QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
348*31908Skarels 	}
349*31908Skarels 	if(sc->sc_flag & DMV_RUNNING)
350*31908Skarels 		dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0);
351*31908Skarels 	else
352*31908Skarels 		dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0);
353*31908Skarels 	dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0);
354*31908Skarels 	sc->sc_flag |= (DMV_RESTART|DMV_RUNNING);
355*31908Skarels 	sc->sc_flag &= ~DMV_ACTIVE;
356*31908Skarels 	addr->bsel0 |= DMV_IEO;
357*31908Skarels }
358*31908Skarels 
359*31908Skarels /*
360*31908Skarels  * Start output on interface.  Get another datagram
361*31908Skarels  * to send from the interface queue and map it to
362*31908Skarels  * the interface before starting output.
363*31908Skarels  *
364*31908Skarels  * Must be called at spl 5
365*31908Skarels  */
366*31908Skarels dmvstart(dev)
367*31908Skarels 	dev_t dev;
368*31908Skarels {
369*31908Skarels 	int unit = minor(dev);
370*31908Skarels 	register struct dmv_softc *sc = &dmv_softc[unit];
371*31908Skarels 	struct mbuf *m;
372*31908Skarels 	register struct dmvbufs *rp;
373*31908Skarels 	register int n;
374*31908Skarels 
375*31908Skarels 	/*
376*31908Skarels 	 * Dequeue up to NXMT requests and map them to the UNIBUS.
377*31908Skarels 	 * If no more requests, or no dmv buffers available, just return.
378*31908Skarels 	 */
379*31908Skarels 	printd("dmvstart\n");
380*31908Skarels 	n = 0;
381*31908Skarels 	for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) {
382*31908Skarels 		/* find an available buffer */
383*31908Skarels 		if ((rp->flags & DBUF_DMVS) == 0) {
384*31908Skarels 			IF_DEQUEUE(&sc->sc_if.if_snd, m);
385*31908Skarels 			if (m == 0)
386*31908Skarels 				return;
387*31908Skarels 			/* mark it dmvs */
388*31908Skarels 			rp->flags |= (DBUF_DMVS);
389*31908Skarels 			/*
390*31908Skarels 			 * Have request mapped to UNIBUS for transmission
391*31908Skarels 			 * and start the output.
392*31908Skarels 			 */
393*31908Skarels 			rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m);
394*31908Skarels 			sc->sc_oused++;
395*31908Skarels 			dmvload(
396*31908Skarels 				sc,
397*31908Skarels 				DMV_BACCX,
398*31908Skarels 				QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10,
399*31908Skarels 				1,
400*31908Skarels 				rp->ubinfo,
401*31908Skarels 				(rp->ubinfo>>16)&0x3f,
402*31908Skarels 				rp->cc
403*31908Skarels 			);
404*31908Skarels 		}
405*31908Skarels 		n++;
406*31908Skarels 	}
407*31908Skarels }
408*31908Skarels 
409*31908Skarels /*
410*31908Skarels  * Utility routine to load the DMV device registers.
411*31908Skarels  */
412*31908Skarels dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10)
413*31908Skarels 	register struct dmv_softc *sc;
414*31908Skarels 	u_char cmd, tributary, mask;
415*31908Skarels 	u_short sel4, sel6, sel10;
416*31908Skarels {
417*31908Skarels 	register struct dmvdevice *addr;
418*31908Skarels 	register int unit, sps;
419*31908Skarels 	register struct dmv_command *qp;
420*31908Skarels 
421*31908Skarels 	unit = sc - dmv_softc;
422*31908Skarels 	printd("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n",
423*31908Skarels 		(unsigned) cmd,
424*31908Skarels 		(unsigned) mask,
425*31908Skarels 		(unsigned) tributary,
426*31908Skarels 		(unsigned) sel4,
427*31908Skarels 		(unsigned) sel6,
428*31908Skarels 		(unsigned) sel10
429*31908Skarels 	);
430*31908Skarels 	addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr;
431*31908Skarels 	sps = spl5();
432*31908Skarels 
433*31908Skarels 	/* grab a command buffer from the free list */
434*31908Skarels 	if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0)
435*31908Skarels 		panic("dmv command queue overflow");
436*31908Skarels 	DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet);
437*31908Skarels 
438*31908Skarels 	/* fill in requested info */
439*31908Skarels 	qp->qp_cmd = cmd;
440*31908Skarels 	qp->qp_mask = mask;
441*31908Skarels 	qp->qp_tributary = tributary;
442*31908Skarels 	qp->qp_sel4 = sel4;
443*31908Skarels 	qp->qp_sel6 = sel6;
444*31908Skarels 	qp->qp_sel10 = sel10;
445*31908Skarels 
446*31908Skarels 	if (sc->sc_qactive) {	/* command in progress */
447*31908Skarels 		if (cmd == DMV_BACCR) {  /* supply read buffers first */
448*31908Skarels 			QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail);
449*31908Skarels 		} else {
450*31908Skarels 			QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail);
451*31908Skarels 		}
452*31908Skarels 	} else {	/* command port free */
453*31908Skarels 		sc->sc_qactive = qp;
454*31908Skarels 		addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO);
455*31908Skarels 	}
456*31908Skarels 	splx(sps);
457*31908Skarels }
458*31908Skarels /*
459*31908Skarels  * DMV interface input interrupt.
460*31908Skarels  * Ready to accept another command,
461*31908Skarels  * pull one off the command queue.
462*31908Skarels  */
463*31908Skarels dmvrint(unit)
464*31908Skarels 	int unit;
465*31908Skarels {
466*31908Skarels 	register struct dmv_softc *sc;
467*31908Skarels 	register struct dmvdevice *addr;
468*31908Skarels 	register struct dmv_command *qp;
469*31908Skarels 	register int n;
470*31908Skarels 
471*31908Skarels 	addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr;
472*31908Skarels 	sc = &dmv_softc[unit];
473*31908Skarels 	printd("dmvrint\n");
474*31908Skarels 	if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) {
475*31908Skarels 		log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit);
476*31908Skarels 		return;
477*31908Skarels 	}
478*31908Skarels 	while (addr->bsel2&DMV_RDI) {
479*31908Skarels 		if(qp->qp_mask&QP_SEL4)
480*31908Skarels 			addr->wsel4 = qp->qp_sel4;
481*31908Skarels 		if(qp->qp_mask&QP_SEL6)
482*31908Skarels 			addr->wsel6 = qp->qp_sel6;
483*31908Skarels 		if(qp->qp_mask&QP_SEL10) {
484*31908Skarels 			addr->wsel10 = qp->qp_sel10;
485*31908Skarels 			qp->qp_cmd |= DMV_22BIT;
486*31908Skarels 		}
487*31908Skarels 		if(qp->qp_mask&QP_TRIB)
488*31908Skarels 			addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8);
489*31908Skarels 		else
490*31908Skarels 			addr->bsel2 = qp->qp_cmd;
491*31908Skarels 		QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
492*31908Skarels 		if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0)
493*31908Skarels 			break;
494*31908Skarels 		qp = sc->sc_qactive;
495*31908Skarels 		DEQUEUE(sc->sc_qhead, sc->sc_qtail);
496*31908Skarels 		if (addr->bsel2&DMV_RDO)
497*31908Skarels 				break;
498*31908Skarels 	}
499*31908Skarels 	if (!sc->sc_qactive) {
500*31908Skarels 		if(addr->bsel2&DMV_RDI) {
501*31908Skarels 			/* clear RQI prior to last command per DMV manual */
502*31908Skarels 			addr->bsel0 &= ~DMV_RQI;
503*31908Skarels 			addr->wsel6 = DMV_NOP;
504*31908Skarels 			addr->bsel2 = DMV_CNTRLI;
505*31908Skarels 		}
506*31908Skarels 		addr->bsel0 = DMV_IEO;
507*31908Skarels 	}
508*31908Skarels 	else /* RDO set or DMV still holding CSR */
509*31908Skarels 		addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO);
510*31908Skarels 
511*31908Skarels }
512*31908Skarels 
513*31908Skarels /*
514*31908Skarels  * DMV interface output interrupt.
515*31908Skarels  * A transfer may have completed, check for errors.
516*31908Skarels  * If it was a read, notify appropriate protocol.
517*31908Skarels  * If it was a write, pull the next one off the queue.
518*31908Skarels  */
519*31908Skarels dmvxint(unit)
520*31908Skarels 	int unit;
521*31908Skarels {
522*31908Skarels 	register struct dmv_softc *sc;
523*31908Skarels 	register struct ifnet *ifp;
524*31908Skarels 	struct uba_device *ui = dmvinfo[unit];
525*31908Skarels 	struct dmvdevice *addr;
526*31908Skarels 	struct mbuf *m;
527*31908Skarels 	struct ifqueue *inq;
528*31908Skarels 	int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s;
529*31908Skarels 	register struct ifrw *ifrw;
530*31908Skarels 	register struct dmvbufs *rp;
531*31908Skarels 	register struct ifxmt *ifxp;
532*31908Skarels 	struct dmv_header *dh;
533*31908Skarels 	int off, resid, fatal;
534*31908Skarels 
535*31908Skarels 	addr = (struct dmvdevice *)ui->ui_addr;
536*31908Skarels 	sc = &dmv_softc[unit];
537*31908Skarels 	ifp = &sc->sc_if;
538*31908Skarels 
539*31908Skarels 	while (addr->bsel2 & DMV_RDO) {
540*31908Skarels 
541*31908Skarels 		sel2 = addr->bsel2;
542*31908Skarels 		sel3 = addr->bsel3;
543*31908Skarels 		sel4 = addr->wsel4;		/* release port */
544*31908Skarels 		sel6 = addr->wsel6;
545*31908Skarels 		if(sel2 & DMV_22BIT)
546*31908Skarels 			sel10 = addr->wsel10;
547*31908Skarels 		addr->bsel2 &= ~DMV_RDO;
548*31908Skarels 		pkaddr =  sel4 | ((sel6 & 0x3f) << 16);
549*31908Skarels 		printd("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n",
550*31908Skarels 			(unsigned) sel2,
551*31908Skarels 			(unsigned) sel4,
552*31908Skarels 			(unsigned) sel6,
553*31908Skarels 			(unsigned) sel10,
554*31908Skarels 			(unsigned) pkaddr
555*31908Skarels 		);
556*31908Skarels 		if((sc->sc_flag & DMV_RUNNING)==0) {
557*31908Skarels 				log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit);
558*31908Skarels 				return;
559*31908Skarels 		}
560*31908Skarels 		switch (sel2 & 07) {
561*31908Skarels 		case DMV_BDRUS:
562*31908Skarels 			/*
563*31908Skarels 			 * A read has completed.
564*31908Skarels 			 * Pass packet to type specific
565*31908Skarels 			 * higher-level input routine.
566*31908Skarels 			 */
567*31908Skarels 			ifp->if_ipackets++;
568*31908Skarels 			/* find location in dmvuba struct */
569*31908Skarels 			ifrw= &sc->sc_ifr[0];
570*31908Skarels 			for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
571*31908Skarels 				if(rp->ubinfo == pkaddr)
572*31908Skarels 					break;
573*31908Skarels 				ifrw++;
574*31908Skarels 			}
575*31908Skarels 			if (rp >= &sc->sc_rbufs[NRCV])
576*31908Skarels 				panic("dmv rcv");
577*31908Skarels 			if ((rp->flags & DBUF_DMVS) == 0)
578*31908Skarels 				log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit);
579*31908Skarels 
580*31908Skarels 			len = (sel10&0x3fff) - sizeof (struct dmv_header);
581*31908Skarels 			if (len < 0 || len > DMVMTU) {
582*31908Skarels 				ifp->if_ierrors++;
583*31908Skarels 				log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n",
584*31908Skarels 				    unit, pkaddr, len);
585*31908Skarels 				goto setup;
586*31908Skarels 			}
587*31908Skarels 			/*
588*31908Skarels 			 * Deal with trailer protocol: if type is trailer
589*31908Skarels 			 * get true type from first 16-bit word past data.
590*31908Skarels 			 * Remember that type was trailer by setting off.
591*31908Skarels 			 */
592*31908Skarels 			dh = (struct dmv_header *)ifrw->ifrw_addr;
593*31908Skarels 			dh->dmv_type = ntohs((u_short)dh->dmv_type);
594*31908Skarels #define dmvdataaddr(dh, off, type)	((type)(((caddr_t)((dh)+1)+(off))))
595*31908Skarels 			if (dh->dmv_type >= DMV_TRAILER &&
596*31908Skarels 			    dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) {
597*31908Skarels 				off = (dh->dmv_type - DMV_TRAILER) * 512;
598*31908Skarels 				if (off >= DMVMTU)
599*31908Skarels 					goto setup;		/* sanity */
600*31908Skarels 				dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *));
601*31908Skarels 				resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *)));
602*31908Skarels 				if (off + resid > len)
603*31908Skarels 					goto setup;		/* sanity */
604*31908Skarels 				len = off + resid;
605*31908Skarels 			} else
606*31908Skarels 				off = 0;
607*31908Skarels 			if (len == 0)
608*31908Skarels 				goto setup;
609*31908Skarels 
610*31908Skarels 			/*
611*31908Skarels 			 * Pull packet off interface.  Off is nonzero if
612*31908Skarels 			 * packet has trailing header; dmv_get will then
613*31908Skarels 			 * force this header information to be at the front,
614*31908Skarels 			 * but we still have to drop the type and length
615*31908Skarels 			 * which are at the front of any trailer data.
616*31908Skarels 			 */
617*31908Skarels 			m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);
618*31908Skarels 			if (m == 0)
619*31908Skarels 				goto setup;
620*31908Skarels 			if (off) {
621*31908Skarels 				ifp = *(mtod(m, struct ifnet **));
622*31908Skarels 				m->m_off += 2 * sizeof (u_short);
623*31908Skarels 				m->m_len -= 2 * sizeof (u_short);
624*31908Skarels 				*(mtod(m, struct ifnet **)) = ifp;
625*31908Skarels 			}
626*31908Skarels 			switch (dh->dmv_type) {
627*31908Skarels #ifdef INET
628*31908Skarels 			case DMV_IPTYPE:
629*31908Skarels 				schednetisr(NETISR_IP);
630*31908Skarels 				inq = &ipintrq;
631*31908Skarels 				break;
632*31908Skarels #endif
633*31908Skarels 			default:
634*31908Skarels 				m_freem(m);
635*31908Skarels 				goto setup;
636*31908Skarels 			}
637*31908Skarels 
638*31908Skarels 			s = splimp();
639*31908Skarels 			if (IF_QFULL(inq)) {
640*31908Skarels 				IF_DROP(inq);
641*31908Skarels 				m_freem(m);
642*31908Skarels 			} else
643*31908Skarels 				IF_ENQUEUE(inq, m);
644*31908Skarels 			splx(s);
645*31908Skarels 	setup:
646*31908Skarels 			/* is this needed? */
647*31908Skarels 			rp->ubinfo = ifrw->ifrw_info & 0x3ffff;
648*31908Skarels 			dmvload(
649*31908Skarels 				sc,
650*31908Skarels 				DMV_BACCR,
651*31908Skarels 				QP_SEL4|QP_SEL6|QP_SEL10,
652*31908Skarels 				0,
653*31908Skarels 				rp->ubinfo,
654*31908Skarels 				(rp->ubinfo>>16)&0x3f,
655*31908Skarels 				rp->cc
656*31908Skarels 			);
657*31908Skarels 			break;
658*31908Skarels 		case DMV_BDXSA:
659*31908Skarels 			/*
660*31908Skarels 			 * A write has completed, start another
661*31908Skarels 			 * transfer if there is more data to send.
662*31908Skarels 			 */
663*31908Skarels 			ifp->if_opackets++;
664*31908Skarels 			/* find associated dmvbuf structure */
665*31908Skarels 			ifxp = &sc->sc_ifw[0];
666*31908Skarels 			for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
667*31908Skarels 				if(rp->ubinfo == pkaddr)
668*31908Skarels 					break;
669*31908Skarels 				ifxp++;
670*31908Skarels 			}
671*31908Skarels 			if (rp >= &sc->sc_xbufs[NXMT]) {
672*31908Skarels 				log(LOG_ERR, "dmv%d: bad packet address 0x%x\n",
673*31908Skarels 				    unit, pkaddr);
674*31908Skarels 				break;
675*31908Skarels 			}
676*31908Skarels 			if ((rp->flags & DBUF_DMVS) == 0)
677*31908Skarels 				log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n",
678*31908Skarels 				    unit, pkaddr);
679*31908Skarels 			/* mark buffer free */
680*31908Skarels 			if (ifxp->ifw_xtofree) {
681*31908Skarels 				(void)m_freem(ifxp->ifw_xtofree);
682*31908Skarels 				ifxp->ifw_xtofree = 0;
683*31908Skarels 			}
684*31908Skarels 			rp->flags &= ~DBUF_DMVS;
685*31908Skarels 			sc->sc_oused--;
686*31908Skarels 			sc->sc_nticks = 0;
687*31908Skarels 			sc->sc_flag |= DMV_ACTIVE;
688*31908Skarels 			break;
689*31908Skarels 
690*31908Skarels 		case DMV_CNTRLO:
691*31908Skarels 			/* ACCUMULATE STATISTICS */
692*31908Skarels 			fatal=0;
693*31908Skarels 			switch(sel6&DMV_EEC) {
694*31908Skarels 			case DMV_ORUN:
695*31908Skarels 				if(sc->sc_flag & DMV_RESTART) {
696*31908Skarels 					load_rec_bufs(sc);
697*31908Skarels 					sc->sc_flag &= ~DMV_RESTART;
698*31908Skarels 					log(LOG_INFO,
699*31908Skarels 					    "dmvxint: dmv%d far end on-line\n",
700*31908Skarels 					    unit
701*31908Skarels 					);
702*31908Skarels 				} else {
703*31908Skarels 					log(LOG_WARNING,
704*31908Skarels 					    "dmvxint: dmv%d far end restart\n",
705*31908Skarels 					    unit
706*31908Skarels 					);
707*31908Skarels 					goto fatal;
708*31908Skarels 				}
709*31908Skarels 				break;
710*31908Skarels 			case DMV_RTE:
711*31908Skarels 				ifp->if_ierrors++;
712*31908Skarels 				log(LOG_WARNING,
713*31908Skarels 				    "dmvxint: dmv%d receive threshold error\n",
714*31908Skarels 				    unit
715*31908Skarels 				);
716*31908Skarels 				if ((sc->sc_rte++ % DMV_RPRTE) == 0)
717*31908Skarels 					goto fatal;
718*31908Skarels 				break;
719*31908Skarels 			case DMV_TTE:
720*31908Skarels 				ifp->if_oerrors++;
721*31908Skarels 				log(LOG_WARNING,
722*31908Skarels 				    "dmvxint: dmv%d transmit threshold error\n",
723*31908Skarels 				    unit
724*31908Skarels 				);
725*31908Skarels 				if ((sc->sc_xte++ % DMV_RPTTE) == 0)
726*31908Skarels 					goto fatal;
727*31908Skarels 				break;
728*31908Skarels 			case DMV_STE:
729*31908Skarels 				log(LOG_WARNING,
730*31908Skarels 				    "dmvxint: dmv%d select threshold error\n",
731*31908Skarels 				    unit
732*31908Skarels 				);
733*31908Skarels 				if ((sc->sc_ste++ % DMV_RPSTE) == 0)
734*31908Skarels 					goto fatal;
735*31908Skarels 				break;
736*31908Skarels 			case DMV_NXM:
737*31908Skarels 				log(LOG_WARNING,
738*31908Skarels 				    "dmvxint: dmv%d nonexistent memory error\n",
739*31908Skarels 				    unit
740*31908Skarels 				);
741*31908Skarels 				if ((sc->sc_nxm++ % DMV_RPNXM) == 0) {
742*31908Skarels 					goto fatal;
743*31908Skarels 				}
744*31908Skarels 				break;
745*31908Skarels 			case DMV_MODD:
746*31908Skarels 				log(LOG_WARNING,
747*31908Skarels 				    "dmvxint: dmv%d modem disconnected error\n",
748*31908Skarels 				    unit
749*31908Skarels 				);
750*31908Skarels 				if ((sc->sc_modd++ % DMV_RPMODD) == 0)
751*31908Skarels 					goto fatal;
752*31908Skarels 				break;
753*31908Skarels 			case DMV_CXRL:
754*31908Skarels 				log(LOG_WARNING,
755*31908Skarels 				    "dmvxint: dmv%d carrier loss error\n",
756*31908Skarels 				    unit
757*31908Skarels 				);
758*31908Skarels 				if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0)
759*31908Skarels 					goto fatal;
760*31908Skarels 				break;
761*31908Skarels 			case DMV_QOVF:
762*31908Skarels 				log(LOG_WARNING,
763*31908Skarels 				    "dmvxint: dmv%d response queue overflow\n",
764*31908Skarels 				    unit
765*31908Skarels 				);
766*31908Skarels 				sc->sc_qovf++;
767*31908Skarels 				goto fatal;
768*31908Skarels 
769*31908Skarels 			default:
770*31908Skarels 				log(LOG_WARNING,
771*31908Skarels 				    "dmvxint: dmv%d unknown error %o\n",
772*31908Skarels 				    unit,
773*31908Skarels 				    sel6&DMV_EEC
774*31908Skarels 				);
775*31908Skarels 				if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0)
776*31908Skarels 					goto fatal;
777*31908Skarels 				break;
778*31908Skarels 			}
779*31908Skarels 			break;
780*31908Skarels 
781*31908Skarels 		case DMV_BDRUNUS:
782*31908Skarels 		case DMV_BDXSN:
783*31908Skarels 		case DMV_BDXNS:
784*31908Skarels 			log(LOG_INFO,
785*31908Skarels 			   "dmvxint: dmv%d buffer disp for halted trib %o\n",
786*31908Skarels 			   unit, sel2&0x7
787*31908Skarels 		        );
788*31908Skarels 			break;
789*31908Skarels 
790*31908Skarels 		case DMV_MDEFO:
791*31908Skarels 			if((sel6&0x1f) == 020) {
792*31908Skarels 				log(LOG_INFO,
793*31908Skarels 			   		"dmvxint: dmv%d buffer return complete sel3=%x\n",
794*31908Skarels 			   		unit, sel3);
795*31908Skarels 			} else {
796*31908Skarels 				log(LOG_INFO,
797*31908Skarels 			   	"dmvxint: dmv%d info resp sel3=%x sel4=%x sel6=%x\n",
798*31908Skarels 			   	unit, sel3, sel4, sel6
799*31908Skarels 		        	);
800*31908Skarels 			}
801*31908Skarels 			break;
802*31908Skarels 
803*31908Skarels 		default:
804*31908Skarels 			log(LOG_WARNING,
805*31908Skarels 			   "dmvxint: dmv%d bad control %o\n",
806*31908Skarels 			   unit, sel2&0x7
807*31908Skarels 		        );
808*31908Skarels 			break;
809*31908Skarels 		}
810*31908Skarels 	}
811*31908Skarels 	dmvstart(unit);
812*31908Skarels 	return;
813*31908Skarels fatal:
814*31908Skarels 	log(
815*31908Skarels 	    LOG_ERR,
816*31908Skarels 	    "dmv%d: fatal error, output code ==%o\n",
817*31908Skarels 	    unit,
818*31908Skarels 	    sel6&DMV_EEC
819*31908Skarels 	);
820*31908Skarels 	dmvrestart(unit);
821*31908Skarels }
822*31908Skarels load_rec_bufs(sc)
823*31908Skarels register struct dmv_softc *sc;
824*31908Skarels {
825*31908Skarels 	register struct dmvbufs *rp;
826*31908Skarels 
827*31908Skarels 	/* queue first NRCV buffers for DMV to fill */
828*31908Skarels 	for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
829*31908Skarels 		rp->flags |= DBUF_DMVS;
830*31908Skarels 		dmvload(
831*31908Skarels 			sc,
832*31908Skarels 			DMV_BACCR,
833*31908Skarels 			QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10,
834*31908Skarels 			1,
835*31908Skarels 			rp->ubinfo,
836*31908Skarels 			(rp->ubinfo>>16)&0x3f,
837*31908Skarels 			rp->cc
838*31908Skarels 		);
839*31908Skarels 		sc->sc_iused++;
840*31908Skarels 	}
841*31908Skarels }
842*31908Skarels 
843*31908Skarels /*
844*31908Skarels  * DMV output routine.
845*31908Skarels  * Encapsulate a packet of type family for the dmv.
846*31908Skarels  * Use trailer local net encapsulation if enough data in first
847*31908Skarels  * packet leaves a multiple of 512 bytes of data in remainder.
848*31908Skarels  */
849*31908Skarels dmvoutput(ifp, m0, dst)
850*31908Skarels 	register struct ifnet *ifp;
851*31908Skarels 	register struct mbuf *m0;
852*31908Skarels 	struct sockaddr *dst;
853*31908Skarels {
854*31908Skarels 	int type, error, s;
855*31908Skarels 	register struct mbuf *m = m0;
856*31908Skarels 	register struct dmv_header *dh;
857*31908Skarels 	register int off;
858*31908Skarels 
859*31908Skarels 	switch (dst->sa_family) {
860*31908Skarels #ifdef	INET
861*31908Skarels 	case AF_INET:
862*31908Skarels 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
863*31908Skarels 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
864*31908Skarels 		if (off > 0 && (off & 0x1ff) == 0 &&
865*31908Skarels 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
866*31908Skarels 			type = DMV_TRAILER + (off>>9);
867*31908Skarels 			m->m_off -= 2 * sizeof (u_short);
868*31908Skarels 			m->m_len += 2 * sizeof (u_short);
869*31908Skarels 			*mtod(m, u_short *) = htons((u_short)DMV_IPTYPE);
870*31908Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
871*31908Skarels 			goto gottrailertype;
872*31908Skarels 		}
873*31908Skarels 		type = DMV_IPTYPE;
874*31908Skarels 		off = 0;
875*31908Skarels 		goto gottype;
876*31908Skarels #endif
877*31908Skarels 
878*31908Skarels 	case AF_UNSPEC:
879*31908Skarels 		dh = (struct dmv_header *)dst->sa_data;
880*31908Skarels 		type = dh->dmv_type;
881*31908Skarels 		goto gottype;
882*31908Skarels 
883*31908Skarels 	default:
884*31908Skarels 		log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n", ifp->if_unit,
885*31908Skarels 			dst->sa_family);
886*31908Skarels 		error = EAFNOSUPPORT;
887*31908Skarels 		goto bad;
888*31908Skarels 	}
889*31908Skarels 
890*31908Skarels gottrailertype:
891*31908Skarels 	/*
892*31908Skarels 	 * Packet to be sent as a trailer; move first packet
893*31908Skarels 	 * (control information) to end of chain.
894*31908Skarels 	 */
895*31908Skarels 	while (m->m_next)
896*31908Skarels 		m = m->m_next;
897*31908Skarels 	m->m_next = m0;
898*31908Skarels 	m = m0->m_next;
899*31908Skarels 	m0->m_next = 0;
900*31908Skarels 	m0 = m;
901*31908Skarels 
902*31908Skarels gottype:
903*31908Skarels 	/*
904*31908Skarels 	 * Add local network header
905*31908Skarels 	 * (there is space for a uba on a vax to step on)
906*31908Skarels 	 */
907*31908Skarels 	if (m->m_off > MMAXOFF ||
908*31908Skarels 	    MMINOFF + sizeof(struct dmv_header) > m->m_off) {
909*31908Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
910*31908Skarels 		if (m == 0) {
911*31908Skarels 			error = ENOBUFS;
912*31908Skarels 			goto bad;
913*31908Skarels 		}
914*31908Skarels 		m->m_next = m0;
915*31908Skarels 		m->m_off = MMINOFF;
916*31908Skarels 		m->m_len = sizeof (struct dmv_header);
917*31908Skarels 	} else {
918*31908Skarels 		m->m_off -= sizeof (struct dmv_header);
919*31908Skarels 		m->m_len += sizeof (struct dmv_header);
920*31908Skarels 	}
921*31908Skarels 	dh = mtod(m, struct dmv_header *);
922*31908Skarels 	dh->dmv_type = htons((u_short)type);
923*31908Skarels 
924*31908Skarels 	/*
925*31908Skarels 	 * Queue message on interface, and start output if interface
926*31908Skarels 	 * not yet active.
927*31908Skarels 	 */
928*31908Skarels 	s = splimp();
929*31908Skarels 	if (IF_QFULL(&ifp->if_snd)) {
930*31908Skarels 		IF_DROP(&ifp->if_snd);
931*31908Skarels 		m_freem(m);
932*31908Skarels 		splx(s);
933*31908Skarels 		return (ENOBUFS);
934*31908Skarels 	}
935*31908Skarels 	IF_ENQUEUE(&ifp->if_snd, m);
936*31908Skarels 	dmvstart(ifp->if_unit);
937*31908Skarels 	splx(s);
938*31908Skarels 	return (0);
939*31908Skarels 
940*31908Skarels bad:
941*31908Skarels 	m_freem(m0);
942*31908Skarels 	return (error);
943*31908Skarels }
944*31908Skarels 
945*31908Skarels 
946*31908Skarels /*
947*31908Skarels  * Process an ioctl request.
948*31908Skarels  */
949*31908Skarels /* ARGSUSED */
950*31908Skarels dmvioctl(ifp, cmd, data)
951*31908Skarels 	register struct ifnet *ifp;
952*31908Skarels 	int cmd;
953*31908Skarels 	caddr_t data;
954*31908Skarels {
955*31908Skarels 	int s = splimp(), error = 0;
956*31908Skarels 	struct mbuf *m;
957*31908Skarels 	register struct dmv_softc *sc = &dmv_softc[ifp->if_unit];
958*31908Skarels 
959*31908Skarels 	switch (cmd) {
960*31908Skarels 
961*31908Skarels 	case SIOCSIFADDR:
962*31908Skarels 		ifp->if_flags |= IFF_UP;
963*31908Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
964*31908Skarels 			dmvinit(ifp->if_unit);
965*31908Skarels 		break;
966*31908Skarels 
967*31908Skarels 	case SIOCSIFDSTADDR:
968*31908Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
969*31908Skarels 			dmvinit(ifp->if_unit);
970*31908Skarels 		break;
971*31908Skarels 
972*31908Skarels 	case SIOCSIFFLAGS:
973*31908Skarels 		if ((ifp->if_flags & IFF_UP) == 0 &&
974*31908Skarels 		    sc->sc_flag & DMV_RUNNING) {
975*31908Skarels 			((struct dmvdevice *)
976*31908Skarels 			   (dmvinfo[ifp->if_unit]->ui_addr))->bsel1 = DMV_MCLR;
977*31908Skarels 			for(;;) {
978*31908Skarels 				IF_DEQUEUE(&sc->sc_if.if_snd, m);
979*31908Skarels         			if (m != NULL)
980*31908Skarels             				m_freem(m);
981*31908Skarels         			else
982*31908Skarels             				break;
983*31908Skarels     			}
984*31908Skarels 			sc->sc_flag &= ~DMV_RUNNING;
985*31908Skarels 		} else if (ifp->if_flags & IFF_UP &&
986*31908Skarels 		    (sc->sc_flag & DMV_RUNNING) == 0)
987*31908Skarels 			dmvrestart(ifp->if_unit);
988*31908Skarels 		break;
989*31908Skarels 
990*31908Skarels 	default:
991*31908Skarels 		error = EINVAL;
992*31908Skarels 	}
993*31908Skarels 	splx(s);
994*31908Skarels 	return (error);
995*31908Skarels }
996*31908Skarels 
997*31908Skarels /*
998*31908Skarels  * Restart after a fatal error.
999*31908Skarels  * Clear device and reinitialize.
1000*31908Skarels  */
1001*31908Skarels dmvrestart(unit)
1002*31908Skarels 	int unit;
1003*31908Skarels {
1004*31908Skarels 	register struct dmv_softc *sc = &dmv_softc[unit];
1005*31908Skarels 	register struct uba_device *ui = dmvinfo[unit];
1006*31908Skarels 	register struct dmvdevice *addr;
1007*31908Skarels 	register struct ifxmt *ifxp;
1008*31908Skarels 	register int i;
1009*31908Skarels 
1010*31908Skarels #ifdef notdef
1011*31908Skarels 	addr = (struct dmvdevice *)ui->ui_addr;
1012*31908Skarels 	/*
1013*31908Skarels 	 * Let the DMR finish the MCLR.	 At 1 Mbit, it should do so
1014*31908Skarels 	 * in about a max of 6.4 milliseconds with diagnostics enabled.
1015*31908Skarels 	 */
1016*31908Skarels 	addr->bsel1 = DMV_MCLR;
1017*31908Skarels 	for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--)
1018*31908Skarels 		;
1019*31908Skarels 	if ((addr->bsel1 & DMV_RUN) == 0) {
1020*31908Skarels 		log(LOG_ERR, "dmvrestart: can't start device\n" );
1021*31908Skarels 		return (0);
1022*31908Skarels 	}
1023*31908Skarels 	if ((addr->bsel4 != 033) || (addr->bsel6 != 0305))
1024*31908Skarels 	{
1025*31908Skarels 		log(LOG_ERR, "dmvrestart: device init failed, bsel4=%o, bsel6=%o\n",
1026*31908Skarels 			addr->bsel4, addr->bsel6);
1027*31908Skarels 		return (0);
1028*31908Skarels 	}
1029*31908Skarels #endif
1030*31908Skarels 	for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
1031*31908Skarels 		if (ifxp->ifw_xtofree) {
1032*31908Skarels 			(void) m_freem(ifxp->ifw_xtofree);
1033*31908Skarels 			ifxp->ifw_xtofree = 0;
1034*31908Skarels 		}
1035*31908Skarels 	}
1036*31908Skarels 	/* restart DMV */
1037*31908Skarels 	dmvinit(unit);
1038*31908Skarels 	sc->sc_if.if_collisions++;	/* why not? */
1039*31908Skarels }
1040*31908Skarels 
1041*31908Skarels /*
1042*31908Skarels  * Check to see that transmitted packets don't
1043*31908Skarels  * lose interrupts.  The device has to be active.
1044*31908Skarels  */
1045*31908Skarels dmvwatch()
1046*31908Skarels {
1047*31908Skarels 	register struct uba_device *ui;
1048*31908Skarels 	register struct dmv_softc *sc;
1049*31908Skarels 	struct dmvdevice *addr;
1050*31908Skarels 	register int i;
1051*31908Skarels 
1052*31908Skarels 	for (i = 0; i < NDMV; i++) {
1053*31908Skarels 		sc = &dmv_softc[i];
1054*31908Skarels 		if ((sc->sc_flag & DMV_ACTIVE) == 0)
1055*31908Skarels 			continue;
1056*31908Skarels 		if ((ui = dmvinfo[i]) == 0 || ui->ui_alive == 0)
1057*31908Skarels 			continue;
1058*31908Skarels 		if (sc->sc_oused) {
1059*31908Skarels 			sc->sc_nticks++;
1060*31908Skarels 			if (sc->sc_nticks > dmv_timeout) {
1061*31908Skarels 				sc->sc_nticks = 0;
1062*31908Skarels 				addr = (struct dmvdevice *)ui->ui_addr;
1063*31908Skarels 				log(LOG_ERR, "dmv%d hung: bsel0=%b bsel2=%b\n",
1064*31908Skarels 				    i, addr->bsel0 & 0xff, DMV0BITS,
1065*31908Skarels 				    addr->bsel2 & 0xff, DMV2BITS);
1066*31908Skarels 				dmvrestart(i);
1067*31908Skarels 			}
1068*31908Skarels 		}
1069*31908Skarels 	}
1070*31908Skarels 	timeout(dmvwatch, (caddr_t) 0, hz);
1071*31908Skarels }
1072*31908Skarels #endif
1073