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