BSD 4_3_Net_1 release
[unix-history] / sys / vaxif / if_dmv.c
CommitLineData
ecfa166d 1/*
2aba78b9
KM
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
616d42db
KB
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.
2aba78b9 16 *
e3419641 17 * @(#)if_dmv.c 7.7 (Berkeley) 10/22/88
616d42db
KB
18 */
19
20/*
ecfa166d
MK
21 * DMV-11 Driver
22 *
23 * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode
24 *
2aba78b9
KM
25 * Written by Bob Kridle of Mt Xinu
26 * starting from if_dmc.c version 6.12 dated 4/23/86
ecfa166d
MK
27 */
28
29#include "dmv.h"
30#if NDMV > 0
31
ecfa166d
MK
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"
bb08cf86
MK
43#include "time.h"
44#include "kernel.h"
ecfa166d
MK
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"
bb08cf86 59#include "../vax/pte.h"
ecfa166d
MK
60#include "../vaxuba/ubareg.h"
61#include "../vaxuba/ubavar.h"
bb08cf86
MK
62#include "if_uba.h"
63#include "if_dmv.h"
ecfa166d 64
ecfa166d 65int dmv_timeout = 8; /* timeout value */
ecfa166d
MK
66
67/*
68 * Driver information for auto-configuration stuff.
69 */
70int dmvprobe(), dmvattach(), dmvinit(), dmvioctl();
bb08cf86 71int dmvoutput(), dmvreset(), dmvtimeout();
ecfa166d
MK
72struct uba_device *dmvinfo[NDMV];
73u_short dmvstd[] = { 0 };
74struct 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.
bb08cf86 80 * These numbers ame from DMC/DMR driver.
ecfa166d
MK
81 */
82#define NRCV 5
83#define NXMT 3
84#define NCMDS (NRCV+NXMT+4) /* size of command queue */
85
bb08cf86
MK
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
ecfa166d
MK
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
d9bcdfcc
MK
102
103/* number of errors to accept before trying a reset */
104#define DMV_RPUNKNOWN 10
ecfa166d
MK
105
106struct 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
122struct 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 */
147struct dmv_softc {
148 struct ifnet sc_if; /* network-visible interface */
ecfa166d
MK
149 short sc_oused; /* output buffers currently in use */
150 short sc_iused; /* input buffers given to DMV */
151 short sc_flag; /* flags */
3ba98c3a 152 short sc_ipl; /* interrupt priority */
ecfa166d
MK
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 */
bb08cf86
MK
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 */
ecfa166d
MK
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 */
bb08cf86
MK
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 */
ecfa166d
MK
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
3ba98c3a 204dmvprobe(reg, ui)
ecfa166d 205 caddr_t reg;
3ba98c3a 206 struct uba_device *ui;
ecfa166d
MK
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 }
3ba98c3a 229 (void) spl6();
ecfa166d
MK
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 ;
3ba98c3a
MK
235 dmv_softc[ui->ui_unit].sc_ipl = br = qbgetpri();
236 return (sizeof(struct dmvdevice));
ecfa166d
MK
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 */
244dmvattach(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;
bb08cf86 256 sc->sc_if.if_watchdog = dmvtimeout;
ecfa166d
MK
257 sc->sc_if.if_flags = IFF_POINTOPOINT;
258 sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
259
ecfa166d
MK
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 */
267dmvreset(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 */
285dmvinit(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 }
bb08cf86 317 printd(("dmvinit\n"));
ecfa166d
MK
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 }
bb08cf86
MK
337 /*
338 * Limit packets enqueued until we see if we're on the air.
339 */
340 ifp->if_snd.ifq_maxlen = 3;
341
ecfa166d
MK
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++) {
3ba98c3a 347 rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
ecfa166d
MK
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++) {
3ba98c3a 355 rp->ubinfo = UBAI_ADDR(ifxp->ifw_info);
ecfa166d
MK
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);
bb08cf86 375 sc->sc_flag &= ~DMV_ONLINE;
ecfa166d
MK
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 */
386dmvstart(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 */
bb08cf86 399 printd(("dmvstart\n"));
ecfa166d
MK
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);
bb08cf86
MK
414 if (++sc->sc_oused == 1)
415 sc->sc_if.if_timer = dmv_timeout;
ecfa166d
MK
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 */
433dmvload(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;
bb08cf86 443 printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n",
ecfa166d
MK
444 (unsigned) cmd,
445 (unsigned) mask,
446 (unsigned) tributary,
447 (unsigned) sel4,
448 (unsigned) sel6,
449 (unsigned) sel10
bb08cf86 450 ));
ecfa166d
MK
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 */
484dmvrint(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];
3ba98c3a 494 splx(sc->sc_ipl);
bb08cf86 495 printd(("dmvrint\n"));
ecfa166d
MK
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 */
541dmvxint(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;
bb08cf86 555 int off, resid;
ecfa166d
MK
556
557 addr = (struct dmvdevice *)ui->ui_addr;
558 sc = &dmv_softc[unit];
3ba98c3a 559 splx(sc->sc_ipl);
ecfa166d
MK
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);
bb08cf86 572 printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n",
ecfa166d
MK
573 (unsigned) sel2,
574 (unsigned) sel4,
575 (unsigned) sel6,
576 (unsigned) sel10,
577 (unsigned) pkaddr
bb08cf86 578 ));
ecfa166d
MK
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;
3ba98c3a
MK
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 }
ecfa166d
MK
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? */
3ba98c3a 670 rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
ecfa166d
MK
671 dmvload(
672 sc,
673 DMV_BACCR,
674 QP_SEL4|QP_SEL6|QP_SEL10,
675 0,
3ba98c3a 676 (u_short) rp->ubinfo,
ecfa166d
MK
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;
bb08cf86
MK
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 }
ecfa166d
MK
722 break;
723
724 case DMV_CNTRLO:
725 /* ACCUMULATE STATISTICS */
ecfa166d
MK
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,
bb08cf86 732 "dmv%d: far end on-line\n", unit);
ecfa166d
MK
733 } else {
734 log(LOG_WARNING,
bb08cf86
MK
735 "dmv%d: far end restart\n", unit);
736 goto restart;
ecfa166d
MK
737 }
738 break;
739 case DMV_RTE:
740 ifp->if_ierrors++;
ecfa166d 741 if ((sc->sc_rte++ % DMV_RPRTE) == 0)
d9bcdfcc 742 log(LOG_WARNING,
bb08cf86 743 "dmv%d: receive threshold error\n",
d9bcdfcc 744 unit);
ecfa166d
MK
745 break;
746 case DMV_TTE:
747 ifp->if_oerrors++;
ecfa166d 748 if ((sc->sc_xte++ % DMV_RPTTE) == 0)
d9bcdfcc 749 log(LOG_WARNING,
bb08cf86 750 "dmv%d: transmit threshold error\n",
d9bcdfcc 751 unit);
ecfa166d
MK
752 break;
753 case DMV_STE:
ecfa166d 754 if ((sc->sc_ste++ % DMV_RPSTE) == 0)
d9bcdfcc 755 log(LOG_WARNING,
bb08cf86 756 "dmv%d: select threshold error\n",
d9bcdfcc 757 unit);
ecfa166d
MK
758 break;
759 case DMV_NXM:
d9bcdfcc
MK
760 if ((sc->sc_nxm++ % DMV_RPNXM) == 0)
761 log(LOG_WARNING,
bb08cf86 762 "dmv%d: nonexistent memory error\n",
d9bcdfcc 763 unit);
ecfa166d
MK
764 break;
765 case DMV_MODD:
bb08cf86 766 if ((sc->sc_modd++ % DMV_RPMODD) == 0) {
d9bcdfcc 767 log(LOG_WARNING,
bb08cf86 768 "dmv%d: modem disconnected error\n",
d9bcdfcc 769 unit);
bb08cf86
MK
770 goto restart;
771 }
ecfa166d
MK
772 break;
773 case DMV_CXRL:
ecfa166d 774 if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0)
d9bcdfcc 775 log(LOG_WARNING,
bb08cf86 776 "dmv%d: carrier loss error\n",
d9bcdfcc 777 unit);
ecfa166d
MK
778 break;
779 case DMV_QOVF:
780 log(LOG_WARNING,
bb08cf86
MK
781 "dmv%d: response queue overflow\n",
782 unit);
ecfa166d 783 sc->sc_qovf++;
bb08cf86 784 goto restart;
ecfa166d
MK
785
786 default:
787 log(LOG_WARNING,
bb08cf86
MK
788 "dmv%d: unknown error %o\n",
789 unit, sel6&DMV_EEC);
ecfa166d 790 if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0)
bb08cf86 791 goto restart;
ecfa166d
MK
792 break;
793 }
794 break;
795
796 case DMV_BDRUNUS:
797 case DMV_BDXSN:
798 case DMV_BDXNS:
799 log(LOG_INFO,
bb08cf86 800 "dmv%d: buffer disp for halted trib %o\n",
ecfa166d
MK
801 unit, sel2&0x7
802 );
803 break;
804
805 case DMV_MDEFO:
806 if((sel6&0x1f) == 020) {
807 log(LOG_INFO,
bb08cf86 808 "dmv%d: buffer return complete sel3=%x\n",
ecfa166d
MK
809 unit, sel3);
810 } else {
811 log(LOG_INFO,
bb08cf86 812 "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n",
ecfa166d
MK
813 unit, sel3, sel4, sel6
814 );
815 }
816 break;
817
818 default:
bb08cf86 819 log(LOG_WARNING, "dmv%d: bad control %o\n",
ecfa166d
MK
820 unit, sel2&0x7
821 );
822 break;
823 }
824 }
825 dmvstart(unit);
826 return;
bb08cf86 827restart:
ecfa166d
MK
828 dmvrestart(unit);
829}
bb08cf86 830
ecfa166d
MK
831load_rec_bufs(sc)
832register 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 */
858dmvoutput(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
bb08cf86
MK
868 if ((ifp->if_flags & IFF_UP) == 0) {
869 error = ENETDOWN;
870 goto bad;
871 }
872
ecfa166d
MK
873 switch (dst->sa_family) {
874#ifdef INET
875 case AF_INET:
3ba98c3a 876 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
ecfa166d
MK
877 if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
878 if (off > 0 && (off & 0x1ff) == 0 &&
3ba98c3a 879 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
ecfa166d 880 type = DMV_TRAILER + (off>>9);
3ba98c3a 881 m->m_off -= 2 * sizeof (u_short);
ecfa166d
MK
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:
bb08cf86
MK
898 log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n",
899 ifp->if_unit, dst->sa_family);
ecfa166d
MK
900 error = EAFNOSUPPORT;
901 goto bad;
902 }
903
904gottrailertype:
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
916gottype:
917 /*
918 * Add local network header
919 * (there is space for a uba on a vax to step on)
920 */
3ba98c3a
MK
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);
ecfa166d
MK
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
954bad:
955 m_freem(m0);
956 return (error);
957}
958
959
960/*
961 * Process an ioctl request.
962 */
963/* ARGSUSED */
964dmvioctl(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 &&
bb08cf86
MK
988 sc->sc_flag & DMV_RUNNING)
989 dmvdown(ifp->if_unit);
990 else if (ifp->if_flags & IFF_UP &&
ecfa166d
MK
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 */
1006dmvrestart(unit)
1007 int unit;
1008{
ecfa166d 1009 register struct dmvdevice *addr;
ecfa166d 1010 register int i;
bb08cf86
MK
1011
1012 dmvdown(unit);
1013
1014 addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr);
ecfa166d 1015 /*
bb08cf86 1016 * Let the DMV finish the MCLR.
ecfa166d 1017 */
ecfa166d
MK
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 {
bb08cf86
MK
1026 log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n",
1027 unit, addr->bsel4, addr->bsel6);
ecfa166d
MK
1028 return (0);
1029 }
bb08cf86
MK
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 */
1040dmvdown(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
ecfa166d
MK
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 }
bb08cf86
MK
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;
ecfa166d
MK
1062}
1063
1064/*
bb08cf86
MK
1065 * Watchdog timeout to see that transmitted packets don't
1066 * lose interrupts. The device has to be online.
ecfa166d 1067 */
bb08cf86
MK
1068dmvtimeout(unit)
1069 int unit;
ecfa166d 1070{
ecfa166d
MK
1071 register struct dmv_softc *sc;
1072 struct dmvdevice *addr;
ecfa166d 1073
bb08cf86
MK
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);
ecfa166d 1081 }
ecfa166d
MK
1082}
1083#endif