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