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