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