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