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