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