cleanup up-down code; limit snd queue to 3 packets until we get going;
[unix-history] / usr / src / sys / vax / if / if_dmv.c
CommitLineData
ecfa166d 1/*
bb08cf86 2 * @(#)if_dmv.c 7.3 (Berkeley) %G%
ecfa166d
MK
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
ecfa166d
MK
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"
bb08cf86
MK
28#include "time.h"
29#include "kernel.h"
ecfa166d
MK
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"
bb08cf86 44#include "../vax/pte.h"
ecfa166d
MK
45#include "../vaxuba/ubareg.h"
46#include "../vaxuba/ubavar.h"
bb08cf86
MK
47#include "if_uba.h"
48#include "if_dmv.h"
ecfa166d 49
ecfa166d 50int dmv_timeout = 8; /* timeout value */
ecfa166d
MK
51
52/*
53 * Driver information for auto-configuration stuff.
54 */
55int dmvprobe(), dmvattach(), dmvinit(), dmvioctl();
bb08cf86 56int dmvoutput(), dmvreset(), dmvtimeout();
ecfa166d
MK
57struct uba_device *dmvinfo[NDMV];
58u_short dmvstd[] = { 0 };
59struct 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.
bb08cf86 65 * These numbers ame from DMC/DMR driver.
ecfa166d
MK
66 */
67#define NRCV 5
68#define NXMT 3
69#define NCMDS (NRCV+NXMT+4) /* size of command queue */
70
bb08cf86
MK
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
ecfa166d
MK
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
d9bcdfcc
MK
87
88/* number of errors to accept before trying a reset */
89#define DMV_RPUNKNOWN 10
ecfa166d
MK
90
91struct 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
107struct 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 */
132struct dmv_softc {
133 struct ifnet sc_if; /* network-visible interface */
ecfa166d
MK
134 short sc_oused; /* output buffers currently in use */
135 short sc_iused; /* input buffers given to DMV */
136 short sc_flag; /* flags */
ecfa166d
MK
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 */
bb08cf86
MK
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 */
ecfa166d
MK
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 */
bb08cf86
MK
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 */
ecfa166d
MK
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
188dmvprobe(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 ;
bb08cf86 217 br = 0x15; /* screwy interrupt structure */
ecfa166d
MK
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 */
226dmvattach(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;
bb08cf86 238 sc->sc_if.if_watchdog = dmvtimeout;
ecfa166d
MK
239 sc->sc_if.if_flags = IFF_POINTOPOINT;
240 sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
241
ecfa166d
MK
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 */
249dmvreset(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 */
267dmvinit(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 }
bb08cf86 299 printd(("dmvinit\n"));
ecfa166d
MK
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 }
bb08cf86
MK
319 /*
320 * Limit packets enqueued until we see if we're on the air.
321 */
322 ifp->if_snd.ifq_maxlen = 3;
323
ecfa166d
MK
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);
bb08cf86 357 sc->sc_flag &= ~DMV_ONLINE;
ecfa166d
MK
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 */
368dmvstart(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 */
bb08cf86 381 printd(("dmvstart\n"));
ecfa166d
MK
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);
bb08cf86
MK
396 if (++sc->sc_oused == 1)
397 sc->sc_if.if_timer = dmv_timeout;
ecfa166d
MK
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 */
415dmvload(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;
bb08cf86 425 printd(("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n",
ecfa166d
MK
426 (unsigned) cmd,
427 (unsigned) mask,
428 (unsigned) tributary,
429 (unsigned) sel4,
430 (unsigned) sel6,
431 (unsigned) sel10
bb08cf86 432 ));
ecfa166d
MK
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 */
466dmvrint(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];
bb08cf86 476 printd(("dmvrint\n"));
ecfa166d
MK
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 */
522dmvxint(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;
bb08cf86 536 int off, resid;
ecfa166d
MK
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);
bb08cf86 552 printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n",
ecfa166d
MK
553 (unsigned) sel2,
554 (unsigned) sel4,
555 (unsigned) sel6,
556 (unsigned) sel10,
557 (unsigned) pkaddr
bb08cf86 558 ));
ecfa166d
MK
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;
bb08cf86
MK
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 }
ecfa166d
MK
702 break;
703
704 case DMV_CNTRLO:
705 /* ACCUMULATE STATISTICS */
ecfa166d
MK
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,
bb08cf86 712 "dmv%d: far end on-line\n", unit);
ecfa166d
MK
713 } else {
714 log(LOG_WARNING,
bb08cf86
MK
715 "dmv%d: far end restart\n", unit);
716 goto restart;
ecfa166d
MK
717 }
718 break;
719 case DMV_RTE:
720 ifp->if_ierrors++;
ecfa166d 721 if ((sc->sc_rte++ % DMV_RPRTE) == 0)
d9bcdfcc 722 log(LOG_WARNING,
bb08cf86 723 "dmv%d: receive threshold error\n",
d9bcdfcc 724 unit);
ecfa166d
MK
725 break;
726 case DMV_TTE:
727 ifp->if_oerrors++;
ecfa166d 728 if ((sc->sc_xte++ % DMV_RPTTE) == 0)
d9bcdfcc 729 log(LOG_WARNING,
bb08cf86 730 "dmv%d: transmit threshold error\n",
d9bcdfcc 731 unit);
ecfa166d
MK
732 break;
733 case DMV_STE:
ecfa166d 734 if ((sc->sc_ste++ % DMV_RPSTE) == 0)
d9bcdfcc 735 log(LOG_WARNING,
bb08cf86 736 "dmv%d: select threshold error\n",
d9bcdfcc 737 unit);
ecfa166d
MK
738 break;
739 case DMV_NXM:
d9bcdfcc
MK
740 if ((sc->sc_nxm++ % DMV_RPNXM) == 0)
741 log(LOG_WARNING,
bb08cf86 742 "dmv%d: nonexistent memory error\n",
d9bcdfcc 743 unit);
ecfa166d
MK
744 break;
745 case DMV_MODD:
bb08cf86 746 if ((sc->sc_modd++ % DMV_RPMODD) == 0) {
d9bcdfcc 747 log(LOG_WARNING,
bb08cf86 748 "dmv%d: modem disconnected error\n",
d9bcdfcc 749 unit);
bb08cf86
MK
750 goto restart;
751 }
ecfa166d
MK
752 break;
753 case DMV_CXRL:
ecfa166d 754 if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0)
d9bcdfcc 755 log(LOG_WARNING,
bb08cf86 756 "dmv%d: carrier loss error\n",
d9bcdfcc 757 unit);
ecfa166d
MK
758 break;
759 case DMV_QOVF:
760 log(LOG_WARNING,
bb08cf86
MK
761 "dmv%d: response queue overflow\n",
762 unit);
ecfa166d 763 sc->sc_qovf++;
bb08cf86 764 goto restart;
ecfa166d
MK
765
766 default:
767 log(LOG_WARNING,
bb08cf86
MK
768 "dmv%d: unknown error %o\n",
769 unit, sel6&DMV_EEC);
ecfa166d 770 if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0)
bb08cf86 771 goto restart;
ecfa166d
MK
772 break;
773 }
774 break;
775
776 case DMV_BDRUNUS:
777 case DMV_BDXSN:
778 case DMV_BDXNS:
779 log(LOG_INFO,
bb08cf86 780 "dmv%d: buffer disp for halted trib %o\n",
ecfa166d
MK
781 unit, sel2&0x7
782 );
783 break;
784
785 case DMV_MDEFO:
786 if((sel6&0x1f) == 020) {
787 log(LOG_INFO,
bb08cf86 788 "dmv%d: buffer return complete sel3=%x\n",
ecfa166d
MK
789 unit, sel3);
790 } else {
791 log(LOG_INFO,
bb08cf86 792 "dmv%d: info resp sel3=%x sel4=%x sel6=%x\n",
ecfa166d
MK
793 unit, sel3, sel4, sel6
794 );
795 }
796 break;
797
798 default:
bb08cf86 799 log(LOG_WARNING, "dmv%d: bad control %o\n",
ecfa166d
MK
800 unit, sel2&0x7
801 );
802 break;
803 }
804 }
805 dmvstart(unit);
806 return;
bb08cf86 807restart:
ecfa166d
MK
808 dmvrestart(unit);
809}
bb08cf86 810
ecfa166d
MK
811load_rec_bufs(sc)
812register 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 */
838dmvoutput(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
bb08cf86
MK
848 if ((ifp->if_flags & IFF_UP) == 0) {
849 error = ENETDOWN;
850 goto bad;
851 }
852
ecfa166d
MK
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:
bb08cf86
MK
878 log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n",
879 ifp->if_unit, dst->sa_family);
ecfa166d
MK
880 error = EAFNOSUPPORT;
881 goto bad;
882 }
883
884gottrailertype:
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
896gottype:
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
934bad:
935 m_freem(m0);
936 return (error);
937}
938
939
940/*
941 * Process an ioctl request.
942 */
943/* ARGSUSED */
944dmvioctl(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 &&
bb08cf86
MK
968 sc->sc_flag & DMV_RUNNING)
969 dmvdown(ifp->if_unit);
970 else if (ifp->if_flags & IFF_UP &&
ecfa166d
MK
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 */
986dmvrestart(unit)
987 int unit;
988{
ecfa166d 989 register struct dmvdevice *addr;
ecfa166d 990 register int i;
bb08cf86
MK
991
992 dmvdown(unit);
993
994 addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr);
ecfa166d 995 /*
bb08cf86 996 * Let the DMV finish the MCLR.
ecfa166d 997 */
ecfa166d
MK
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 {
bb08cf86
MK
1006 log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n",
1007 unit, addr->bsel4, addr->bsel6);
ecfa166d
MK
1008 return (0);
1009 }
bb08cf86
MK
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 */
1020dmvdown(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
ecfa166d
MK
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 }
bb08cf86
MK
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;
ecfa166d
MK
1042}
1043
1044/*
bb08cf86
MK
1045 * Watchdog timeout to see that transmitted packets don't
1046 * lose interrupts. The device has to be online.
ecfa166d 1047 */
bb08cf86
MK
1048dmvtimeout(unit)
1049 int unit;
ecfa166d 1050{
ecfa166d
MK
1051 register struct dmv_softc *sc;
1052 struct dmvdevice *addr;
ecfa166d 1053
bb08cf86
MK
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);
ecfa166d 1061 }
ecfa166d
MK
1062}
1063#endif