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