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