|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * @(#)if_dmc.c 7.1 (Berkeley) 6/5/86
7: */
8:
9: #include "dmc.h"
10: #if NDMC > 0
11:
12: /*
13: * DMC11 device driver, internet version
14: *
15: * Bill Nesheim
16: * Cornell University
17: *
18: * Lou Salkind
19: * New York University
20: */
21:
22: /* #define DEBUG /* for base table dump on fatal error */
23:
24: #include "../machine/pte.h"
25:
26: #include "param.h"
27: #include "systm.h"
28: #include "mbuf.h"
29: #include "buf.h"
30: #include "ioctl.h" /* must precede tty.h */
31: #include "tty.h"
32: #include "protosw.h"
33: #include "socket.h"
34: #include "syslog.h"
35: #include "vmmac.h"
36: #include "errno.h"
37:
38: #include "../net/if.h"
39: #include "../net/netisr.h"
40: #include "../net/route.h"
41:
42: #ifdef INET
43: #include "../netinet/in.h"
44: #include "../netinet/in_systm.h"
45: #include "../netinet/in_var.h"
46: #include "../netinet/ip.h"
47: #endif
48:
49: #include "../vax/cpu.h"
50: #include "../vax/mtpr.h"
51: #include "if_uba.h"
52: #include "if_dmc.h"
53: #include "../vaxuba/ubareg.h"
54: #include "../vaxuba/ubavar.h"
55:
56: #include "../h/time.h"
57: #include "../h/kernel.h"
58:
59: int dmctimer; /* timer started? */
60: int dmc_timeout = 8; /* timeout value */
61: int dmcwatch();
62:
63: /*
64: * Driver information for auto-configuration stuff.
65: */
66: int dmcprobe(), dmcattach(), dmcinit(), dmcioctl();
67: int dmcoutput(), dmcreset();
68: struct uba_device *dmcinfo[NDMC];
69: u_short dmcstd[] = { 0 };
70: struct uba_driver dmcdriver =
71: { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
72:
73: #define NRCV 7
74: #define NXMT 3
75: #define NCMDS (NRCV+NXMT+4) /* size of command queue */
76:
77: #define printd if(dmcdebug)printf
78: int dmcdebug = 0;
79:
80: /* error reporting intervals */
81: #define DMC_RPNBFS 50
82: #define DMC_RPDSC 1
83: #define DMC_RPTMO 10
84: #define DMC_RPDCK 10
85:
86: struct dmc_command {
87: char qp_cmd; /* command */
88: short qp_ubaddr; /* buffer address */
89: short qp_cc; /* character count || XMEM */
90: struct dmc_command *qp_next; /* next command on queue */
91: };
92:
93: struct dmcbufs {
94: int ubinfo; /* from uballoc */
95: short cc; /* buffer size */
96: short flags; /* access control */
97: };
98: #define DBUF_OURS 0 /* buffer is available */
99: #define DBUF_DMCS 1 /* buffer claimed by somebody */
100: #define DBUF_XMIT 4 /* transmit buffer */
101: #define DBUF_RCV 8 /* receive buffer */
102:
103:
104: /*
105: * DMC software status per interface.
106: *
107: * Each interface is referenced by a network interface structure,
108: * sc_if, which the routing code uses to locate the interface.
109: * This structure contains the output queue for the interface, its address, ...
110: * We also have, for each interface, a set of 7 UBA interface structures
111: * for each, which
112: * contain information about the UNIBUS resources held by the interface:
113: * map registers, buffered data paths, etc. Information is cached in this
114: * structure for use by the if_uba.c routines in running the interface
115: * efficiently.
116: */
117: struct dmc_softc {
118: struct ifnet sc_if; /* network-visible interface */
119: struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */
120: struct dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */
121: struct ifubinfo sc_ifuba; /* UNIBUS resources */
122: struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */
123: struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */
124: short sc_oused; /* output buffers currently in use */
125: short sc_iused; /* input buffers given to DMC */
126: short sc_flag; /* flags */
127: int sc_nticks; /* seconds since last interrupt */
128: int sc_ubinfo; /* UBA mapping info for base table */
129: int sc_errors[4]; /* non-fatal error counters */
130: #define sc_datck sc_errors[0]
131: #define sc_timeo sc_errors[1]
132: #define sc_nobuf sc_errors[2]
133: #define sc_disc sc_errors[3]
134: /* command queue stuff */
135: struct dmc_command sc_cmdbuf[NCMDS];
136: struct dmc_command *sc_qhead; /* head of command queue */
137: struct dmc_command *sc_qtail; /* tail of command queue */
138: struct dmc_command *sc_qactive; /* command in progress */
139: struct dmc_command *sc_qfreeh; /* head of list of free cmd buffers */
140: struct dmc_command *sc_qfreet; /* tail of list of free cmd buffers */
141: /* end command queue stuff */
142: } dmc_softc[NDMC];
143:
144: /* flags */
145: #define DMC_ALLOC 0x01 /* unibus resources allocated */
146: #define DMC_BMAPPED 0x02 /* base table mapped */
147: #define DMC_RESTART 0x04 /* software restart in progress */
148: #define DMC_ACTIVE 0x08 /* device active */
149: #define DMC_RUNNING 0x20 /* device initialized */
150:
151: struct dmc_base {
152: short d_base[128]; /* DMC base table */
153: } dmc_base[NDMC];
154:
155: /* queue manipulation macros */
156: #define QUEUE_AT_HEAD(qp, head, tail) \
157: (qp)->qp_next = (head); \
158: (head) = (qp); \
159: if ((tail) == (struct dmc_command *) 0) \
160: (tail) = (head)
161:
162: #define QUEUE_AT_TAIL(qp, head, tail) \
163: if ((tail)) \
164: (tail)->qp_next = (qp); \
165: else \
166: (head) = (qp); \
167: (qp)->qp_next = (struct dmc_command *) 0; \
168: (tail) = (qp)
169:
170: #define DEQUEUE(head, tail) \
171: (head) = (head)->qp_next;\
172: if ((head) == (struct dmc_command *) 0)\
173: (tail) = (head)
174:
175: dmcprobe(reg)
176: caddr_t reg;
177: {
178: register int br, cvec;
179: register struct dmcdevice *addr = (struct dmcdevice *)reg;
180: register int i;
181:
182: #ifdef lint
183: br = 0; cvec = br; br = cvec;
184: dmcrint(0); dmcxint(0);
185: #endif
186: addr->bsel1 = DMC_MCLR;
187: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
188: ;
189: if ((addr->bsel1 & DMC_RUN) == 0) {
190: printf("dmcprobe: can't start device\n" );
191: return (0);
192: }
193: addr->bsel0 = DMC_RQI|DMC_IEI;
194: /* let's be paranoid */
195: addr->bsel0 |= DMC_RQI|DMC_IEI;
196: DELAY(1000000);
197: addr->bsel1 = DMC_MCLR;
198: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
199: ;
200: return (1);
201: }
202:
203: /*
204: * Interface exists: make available by filling in network interface
205: * record. System will initialize the interface when it is ready
206: * to accept packets.
207: */
208: dmcattach(ui)
209: register struct uba_device *ui;
210: {
211: register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
212:
213: sc->sc_if.if_unit = ui->ui_unit;
214: sc->sc_if.if_name = "dmc";
215: sc->sc_if.if_mtu = DMCMTU;
216: sc->sc_if.if_init = dmcinit;
217: sc->sc_if.if_output = dmcoutput;
218: sc->sc_if.if_ioctl = dmcioctl;
219: sc->sc_if.if_reset = dmcreset;
220: sc->sc_if.if_flags = IFF_POINTOPOINT;
221: sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
222:
223: if (dmctimer == 0) {
224: dmctimer = 1;
225: timeout(dmcwatch, (caddr_t) 0, hz);
226: }
227: if_attach(&sc->sc_if);
228: }
229:
230: /*
231: * Reset of interface after UNIBUS reset.
232: * If interface is on specified UBA, reset its state.
233: */
234: dmcreset(unit, uban)
235: int unit, uban;
236: {
237: register struct uba_device *ui;
238: register struct dmc_softc *sc = &dmc_softc[unit];
239:
240: if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
241: ui->ui_ubanum != uban)
242: return;
243: printf(" dmc%d", unit);
244: sc->sc_flag = 0;
245: sc->sc_if.if_flags &= ~IFF_RUNNING;
246: dmcinit(unit);
247: }
248:
249: /*
250: * Initialization of interface; reinitialize UNIBUS usage.
251: */
252: dmcinit(unit)
253: int unit;
254: {
255: register struct dmc_softc *sc = &dmc_softc[unit];
256: register struct uba_device *ui = dmcinfo[unit];
257: register struct dmcdevice *addr;
258: register struct ifnet *ifp = &sc->sc_if;
259: register struct ifrw *ifrw;
260: register struct ifxmt *ifxp;
261: register struct dmcbufs *rp;
262: register struct dmc_command *qp;
263: struct ifaddr *ifa;
264: int base;
265: int s;
266:
267: addr = (struct dmcdevice *)ui->ui_addr;
268:
269: /*
270: * Check to see that an address has been set
271: * (both local and destination for an address family).
272: */
273: for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
274: if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family)
275: break;
276: if (ifa == (struct ifaddr *) 0)
277: return;
278:
279: if ((addr->bsel1&DMC_RUN) == 0) {
280: printf("dmcinit: DMC not running\n");
281: ifp->if_flags &= ~IFF_UP;
282: return;
283: }
284: /* map base table */
285: if ((sc->sc_flag & DMC_BMAPPED) == 0) {
286: sc->sc_ubinfo = uballoc(ui->ui_ubanum,
287: (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0);
288: sc->sc_flag |= DMC_BMAPPED;
289: }
290: /* initialize UNIBUS resources */
291: sc->sc_iused = sc->sc_oused = 0;
292: if ((ifp->if_flags & IFF_RUNNING) == 0) {
293: if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum,
294: sizeof(struct dmc_header), (int)btoc(DMCMTU),
295: sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) {
296: printf("dmc%d: can't allocate uba resources\n", unit);
297: ifp->if_flags &= ~IFF_UP;
298: return;
299: }
300: ifp->if_flags |= IFF_RUNNING;
301: }
302: sc->sc_flag |= DMC_RUNNING;
303:
304: /* initialize buffer pool */
305: /* receives */
306: ifrw = &sc->sc_ifr[0];
307: for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
308: rp->ubinfo = ifrw->ifrw_info & 0x3ffff;
309: rp->cc = DMCMTU + sizeof (struct dmc_header);
310: rp->flags = DBUF_OURS|DBUF_RCV;
311: ifrw++;
312: }
313: /* transmits */
314: ifxp = &sc->sc_ifw[0];
315: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
316: rp->ubinfo = ifxp->ifw_info & 0x3ffff;
317: rp->cc = 0;
318: rp->flags = DBUF_OURS|DBUF_XMIT;
319: ifxp++;
320: }
321:
322: /* set up command queues */
323: sc->sc_qfreeh = sc->sc_qfreet
324: = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive =
325: (struct dmc_command *)0;
326: /* set up free command buffer list */
327: for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) {
328: QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
329: }
330:
331: /* base in */
332: base = sc->sc_ubinfo & 0x3ffff;
333: dmcload(sc, DMC_BASEI, base, (base>>2) & DMC_XMEM);
334: /* specify half duplex operation, flags tell if primary */
335: /* or secondary station */
336: if (ui->ui_flags == 0)
337: /* use DDCMP mode in full duplex */
338: dmcload(sc, DMC_CNTLI, 0, 0);
339: else if (ui->ui_flags == 1)
340: /* use MAINTENENCE mode */
341: dmcload(sc, DMC_CNTLI, 0, DMC_MAINT );
342: else if (ui->ui_flags == 2)
343: /* use DDCMP half duplex as primary station */
344: dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX);
345: else if (ui->ui_flags == 3)
346: /* use DDCMP half duplex as secondary station */
347: dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC);
348:
349: /* enable operation done interrupts */
350: sc->sc_flag &= ~DMC_ACTIVE;
351: while ((addr->bsel2 & DMC_IEO) == 0)
352: addr->bsel2 |= DMC_IEO;
353: s = spl5();
354: /* queue first NRCV buffers for DMC to fill */
355: for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
356: rp->flags |= DBUF_DMCS;
357: dmcload(sc, DMC_READ, rp->ubinfo,
358: (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc));
359: sc->sc_iused++;
360: }
361: splx(s);
362: }
363:
364: /*
365: * Start output on interface. Get another datagram
366: * to send from the interface queue and map it to
367: * the interface before starting output.
368: *
369: * Must be called at spl 5
370: */
371: dmcstart(dev)
372: dev_t dev;
373: {
374: int unit = minor(dev);
375: register struct dmc_softc *sc = &dmc_softc[unit];
376: struct mbuf *m;
377: register struct dmcbufs *rp;
378: register int n;
379:
380: /*
381: * Dequeue up to NXMT requests and map them to the UNIBUS.
382: * If no more requests, or no dmc buffers available, just return.
383: */
384: n = 0;
385: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) {
386: /* find an available buffer */
387: if ((rp->flags & DBUF_DMCS) == 0) {
388: IF_DEQUEUE(&sc->sc_if.if_snd, m);
389: if (m == 0)
390: return;
391: /* mark it dmcs */
392: rp->flags |= (DBUF_DMCS);
393: /*
394: * Have request mapped to UNIBUS for transmission
395: * and start the output.
396: */
397: rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m);
398: rp->cc &= DMC_CCOUNT;
399: sc->sc_oused++;
400: dmcload(sc, DMC_WRITE, rp->ubinfo,
401: rp->cc | ((rp->ubinfo>>2)&DMC_XMEM));
402: }
403: n++;
404: }
405: }
406:
407: /*
408: * Utility routine to load the DMC device registers.
409: */
410: dmcload(sc, type, w0, w1)
411: register struct dmc_softc *sc;
412: int type, w0, w1;
413: {
414: register struct dmcdevice *addr;
415: register int unit, sps;
416: register struct dmc_command *qp;
417:
418: unit = sc - dmc_softc;
419: addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
420: sps = spl5();
421:
422: /* grab a command buffer from the free list */
423: if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0)
424: panic("dmc command queue overflow");
425: DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet);
426:
427: /* fill in requested info */
428: qp->qp_cmd = (type | DMC_RQI);
429: qp->qp_ubaddr = w0;
430: qp->qp_cc = w1;
431:
432: if (sc->sc_qactive) { /* command in progress */
433: if (type == DMC_READ) {
434: QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail);
435: } else {
436: QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail);
437: }
438: } else { /* command port free */
439: sc->sc_qactive = qp;
440: addr->bsel0 = qp->qp_cmd;
441: dmcrint(unit);
442: }
443: splx(sps);
444: }
445:
446: /*
447: * DMC interface receiver interrupt.
448: * Ready to accept another command,
449: * pull one off the command queue.
450: */
451: dmcrint(unit)
452: int unit;
453: {
454: register struct dmc_softc *sc;
455: register struct dmcdevice *addr;
456: register struct dmc_command *qp;
457: register int n;
458:
459: addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
460: sc = &dmc_softc[unit];
461: if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) {
462: printf("dmc%d: dmcrint no command\n", unit);
463: return;
464: }
465: while (addr->bsel0&DMC_RDYI) {
466: addr->sel4 = qp->qp_ubaddr;
467: addr->sel6 = qp->qp_cc;
468: addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
469: /* free command buffer */
470: QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
471: while (addr->bsel0 & DMC_RDYI) {
472: /*
473: * Can't check for RDYO here 'cause
474: * this routine isn't reentrant!
475: */
476: DELAY(5);
477: }
478: /* move on to next command */
479: if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0)
480: break; /* all done */
481: /* more commands to do, start the next one */
482: qp = sc->sc_qactive;
483: DEQUEUE(sc->sc_qhead, sc->sc_qtail);
484: addr->bsel0 = qp->qp_cmd;
485: n = RDYSCAN;
486: while (n-- > 0)
487: if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO))
488: break;
489: }
490: if (sc->sc_qactive) {
491: addr->bsel0 |= DMC_IEI|DMC_RQI;
492: /* VMS does it twice !*$%@# */
493: addr->bsel0 |= DMC_IEI|DMC_RQI;
494: }
495:
496: }
497:
498: /*
499: * DMC interface transmitter interrupt.
500: * A transfer may have completed, check for errors.
501: * If it was a read, notify appropriate protocol.
502: * If it was a write, pull the next one off the queue.
503: */
504: dmcxint(unit)
505: int unit;
506: {
507: register struct dmc_softc *sc;
508: register struct ifnet *ifp;
509: struct uba_device *ui = dmcinfo[unit];
510: struct dmcdevice *addr;
511: struct mbuf *m;
512: struct ifqueue *inq;
513: int arg, pkaddr, cmd, len, s;
514: register struct ifrw *ifrw;
515: register struct dmcbufs *rp;
516: register struct ifxmt *ifxp;
517: struct dmc_header *dh;
518: int off, resid;
519:
520: addr = (struct dmcdevice *)ui->ui_addr;
521: sc = &dmc_softc[unit];
522: ifp = &sc->sc_if;
523:
524: while (addr->bsel2 & DMC_RDYO) {
525:
526: cmd = addr->bsel2 & 0xff;
527: arg = addr->sel6 & 0xffff;
528: /* reconstruct UNIBUS address of buffer returned to us */
529: pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff);
530: /* release port */
531: addr->bsel2 &= ~DMC_RDYO;
532: switch (cmd & 07) {
533:
534: case DMC_OUR:
535: /*
536: * A read has completed.
537: * Pass packet to type specific
538: * higher-level input routine.
539: */
540: ifp->if_ipackets++;
541: /* find location in dmcuba struct */
542: ifrw= &sc->sc_ifr[0];
543: for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
544: if(rp->ubinfo == pkaddr)
545: break;
546: ifrw++;
547: }
548: if (rp >= &sc->sc_rbufs[NRCV])
549: panic("dmc rcv");
550: if ((rp->flags & DBUF_DMCS) == 0)
551: printf("dmc%d: done unalloc rbuf\n", unit);
552:
553: len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header);
554: if (len < 0 || len > DMCMTU) {
555: ifp->if_ierrors++;
556: printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n",
557: unit, pkaddr, len);
558: goto setup;
559: }
560: /*
561: * Deal with trailer protocol: if type is trailer
562: * get true type from first 16-bit word past data.
563: * Remember that type was trailer by setting off.
564: */
565: dh = (struct dmc_header *)ifrw->ifrw_addr;
566: dh->dmc_type = ntohs((u_short)dh->dmc_type);
567: #define dmcdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off))))
568: if (dh->dmc_type >= DMC_TRAILER &&
569: dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) {
570: off = (dh->dmc_type - DMC_TRAILER) * 512;
571: if (off >= DMCMTU)
572: goto setup; /* sanity */
573: dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *));
574: resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *)));
575: if (off + resid > len)
576: goto setup; /* sanity */
577: len = off + resid;
578: } else
579: off = 0;
580: if (len == 0)
581: goto setup;
582:
583: /*
584: * Pull packet off interface. Off is nonzero if
585: * packet has trailing header; dmc_get will then
586: * force this header information to be at the front,
587: * but we still have to drop the type and length
588: * which are at the front of any trailer data.
589: */
590: m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);
591: if (m == 0)
592: goto setup;
593: if (off) {
594: ifp = *(mtod(m, struct ifnet **));
595: m->m_off += 2 * sizeof (u_short);
596: m->m_len -= 2 * sizeof (u_short);
597: *(mtod(m, struct ifnet **)) = ifp;
598: }
599: switch (dh->dmc_type) {
600:
601: #ifdef INET
602: case DMC_IPTYPE:
603: schednetisr(NETISR_IP);
604: inq = &ipintrq;
605: break;
606: #endif
607: default:
608: m_freem(m);
609: goto setup;
610: }
611:
612: s = splimp();
613: if (IF_QFULL(inq)) {
614: IF_DROP(inq);
615: m_freem(m);
616: } else
617: IF_ENQUEUE(inq, m);
618: splx(s);
619:
620: setup:
621: /* is this needed? */
622: rp->ubinfo = ifrw->ifrw_info & 0x3ffff;
623:
624: dmcload(sc, DMC_READ, rp->ubinfo,
625: ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc);
626: break;
627:
628: case DMC_OUX:
629: /*
630: * A write has completed, start another
631: * transfer if there is more data to send.
632: */
633: ifp->if_opackets++;
634: /* find associated dmcbuf structure */
635: ifxp = &sc->sc_ifw[0];
636: for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
637: if(rp->ubinfo == pkaddr)
638: break;
639: ifxp++;
640: }
641: if (rp >= &sc->sc_xbufs[NXMT]) {
642: printf("dmc%d: bad packet address 0x%x\n",
643: unit, pkaddr);
644: break;
645: }
646: if ((rp->flags & DBUF_DMCS) == 0)
647: printf("dmc%d: unallocated packet 0x%x\n",
648: unit, pkaddr);
649: /* mark buffer free */
650: if (ifxp->ifw_xtofree) {
651: (void)m_freem(ifxp->ifw_xtofree);
652: ifxp->ifw_xtofree = 0;
653: }
654: rp->flags &= ~DBUF_DMCS;
655: sc->sc_oused--;
656: sc->sc_nticks = 0;
657: sc->sc_flag |= DMC_ACTIVE;
658: break;
659:
660: case DMC_CNTLO:
661: arg &= DMC_CNTMASK;
662: if (arg & DMC_FATAL) {
663: log(LOG_ERR, "dmc%d: fatal error, flags=%b\n",
664: unit, arg, CNTLO_BITS);
665: dmcrestart(unit);
666: break;
667: }
668: /* ACCUMULATE STATISTICS */
669: switch(arg) {
670: case DMC_NOBUFS:
671: ifp->if_ierrors++;
672: if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0)
673: goto report;
674: break;
675: case DMC_DISCONN:
676: if ((sc->sc_disc++ % DMC_RPDSC) == 0)
677: goto report;
678: break;
679: case DMC_TIMEOUT:
680: if ((sc->sc_timeo++ % DMC_RPTMO) == 0)
681: goto report;
682: break;
683: case DMC_DATACK:
684: ifp->if_oerrors++;
685: if ((sc->sc_datck++ % DMC_RPDCK) == 0)
686: goto report;
687: break;
688: default:
689: goto report;
690: }
691: break;
692: report:
693: printd("dmc%d: soft error, flags=%b\n", unit,
694: arg, CNTLO_BITS);
695: if ((sc->sc_flag & DMC_RESTART) == 0) {
696: /*
697: * kill off the dmc to get things
698: * going again by generating a
699: * procedure error
700: */
701: sc->sc_flag |= DMC_RESTART;
702: arg = sc->sc_ubinfo & 0x3ffff;
703: dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM);
704: }
705: break;
706:
707: default:
708: printf("dmc%d: bad control %o\n", unit, cmd);
709: break;
710: }
711: }
712: dmcstart(unit);
713: return;
714: }
715:
716: /*
717: * DMC output routine.
718: * Encapsulate a packet of type family for the dmc.
719: * Use trailer local net encapsulation if enough data in first
720: * packet leaves a multiple of 512 bytes of data in remainder.
721: */
722: dmcoutput(ifp, m0, dst)
723: register struct ifnet *ifp;
724: register struct mbuf *m0;
725: struct sockaddr *dst;
726: {
727: int type, error, s;
728: register struct mbuf *m = m0;
729: register struct dmc_header *dh;
730: register int off;
731:
732: switch (dst->sa_family) {
733: #ifdef INET
734: case AF_INET:
735: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
736: if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
737: if (off > 0 && (off & 0x1ff) == 0 &&
738: m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
739: type = DMC_TRAILER + (off>>9);
740: m->m_off -= 2 * sizeof (u_short);
741: m->m_len += 2 * sizeof (u_short);
742: *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE);
743: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
744: goto gottrailertype;
745: }
746: type = DMC_IPTYPE;
747: off = 0;
748: goto gottype;
749: #endif
750:
751: case AF_UNSPEC:
752: dh = (struct dmc_header *)dst->sa_data;
753: type = dh->dmc_type;
754: goto gottype;
755:
756: default:
757: printf("dmc%d: can't handle af%d\n", ifp->if_unit,
758: dst->sa_family);
759: error = EAFNOSUPPORT;
760: goto bad;
761: }
762:
763: gottrailertype:
764: /*
765: * Packet to be sent as a trailer; move first packet
766: * (control information) to end of chain.
767: */
768: while (m->m_next)
769: m = m->m_next;
770: m->m_next = m0;
771: m = m0->m_next;
772: m0->m_next = 0;
773: m0 = m;
774:
775: gottype:
776: /*
777: * Add local network header
778: * (there is space for a uba on a vax to step on)
779: */
780: if (m->m_off > MMAXOFF ||
781: MMINOFF + sizeof(struct dmc_header) > m->m_off) {
782: m = m_get(M_DONTWAIT, MT_HEADER);
783: if (m == 0) {
784: error = ENOBUFS;
785: goto bad;
786: }
787: m->m_next = m0;
788: m->m_off = MMINOFF;
789: m->m_len = sizeof (struct dmc_header);
790: } else {
791: m->m_off -= sizeof (struct dmc_header);
792: m->m_len += sizeof (struct dmc_header);
793: }
794: dh = mtod(m, struct dmc_header *);
795: dh->dmc_type = htons((u_short)type);
796:
797: /*
798: * Queue message on interface, and start output if interface
799: * not yet active.
800: */
801: s = splimp();
802: if (IF_QFULL(&ifp->if_snd)) {
803: IF_DROP(&ifp->if_snd);
804: m_freem(m);
805: splx(s);
806: return (ENOBUFS);
807: }
808: IF_ENQUEUE(&ifp->if_snd, m);
809: dmcstart(ifp->if_unit);
810: splx(s);
811: return (0);
812:
813: bad:
814: m_freem(m0);
815: return (error);
816: }
817:
818:
819: /*
820: * Process an ioctl request.
821: */
822: /* ARGSUSED */
823: dmcioctl(ifp, cmd, data)
824: register struct ifnet *ifp;
825: int cmd;
826: caddr_t data;
827: {
828: int s = splimp(), error = 0;
829: register struct dmc_softc *sc = &dmc_softc[ifp->if_unit];
830:
831: switch (cmd) {
832:
833: case SIOCSIFADDR:
834: ifp->if_flags |= IFF_UP;
835: if ((ifp->if_flags & IFF_RUNNING) == 0)
836: dmcinit(ifp->if_unit);
837: break;
838:
839: case SIOCSIFDSTADDR:
840: if ((ifp->if_flags & IFF_RUNNING) == 0)
841: dmcinit(ifp->if_unit);
842: break;
843:
844: case SIOCSIFFLAGS:
845: if ((ifp->if_flags & IFF_UP) == 0 &&
846: sc->sc_flag & DMC_RUNNING) {
847: ((struct dmcdevice *)
848: (dmcinfo[ifp->if_unit]->ui_addr))->bsel1 = DMC_MCLR;
849: sc->sc_flag &= ~DMC_RUNNING;
850: } else if (ifp->if_flags & IFF_UP &&
851: (sc->sc_flag & DMC_RUNNING) == 0)
852: dmcrestart(ifp->if_unit);
853: break;
854:
855: default:
856: error = EINVAL;
857: }
858: splx(s);
859: return (error);
860: }
861:
862: /*
863: * Restart after a fatal error.
864: * Clear device and reinitialize.
865: */
866: dmcrestart(unit)
867: int unit;
868: {
869: register struct dmc_softc *sc = &dmc_softc[unit];
870: register struct uba_device *ui = dmcinfo[unit];
871: register struct dmcdevice *addr;
872: register struct ifxmt *ifxp;
873: register int i;
874:
875: addr = (struct dmcdevice *)ui->ui_addr;
876: #ifdef DEBUG
877: /* dump base table */
878: printf("dmc%d base table:\n", unit);
879: for (i = 0; i < sizeof (struct dmc_base); i++)
880: printf("%o\n" ,dmc_base[unit].d_base[i]);
881: #endif
882: /*
883: * Let the DMR finish the MCLR. At 1 Mbit, it should do so
884: * in about a max of 6.4 milliseconds with diagnostics enabled.
885: */
886: addr->bsel1 = DMC_MCLR;
887: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
888: ;
889: /* Did the timer expire or did the DMR finish? */
890: if ((addr->bsel1 & DMC_RUN) == 0) {
891: log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit);
892: return;
893: }
894:
895: for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
896: if (ifxp->ifw_xtofree) {
897: (void) m_freem(ifxp->ifw_xtofree);
898: ifxp->ifw_xtofree = 0;
899: }
900: }
901:
902: /* restart DMC */
903: dmcinit(unit);
904: sc->sc_flag &= ~DMC_RESTART;
905: sc->sc_if.if_collisions++; /* why not? */
906: }
907:
908: /*
909: * Check to see that transmitted packets don't
910: * lose interrupts. The device has to be active.
911: */
912: dmcwatch()
913: {
914: register struct uba_device *ui;
915: register struct dmc_softc *sc;
916: struct dmcdevice *addr;
917: register int i;
918:
919: for (i = 0; i < NDMC; i++) {
920: sc = &dmc_softc[i];
921: if ((sc->sc_flag & DMC_ACTIVE) == 0)
922: continue;
923: if ((ui = dmcinfo[i]) == 0 || ui->ui_alive == 0)
924: continue;
925: if (sc->sc_oused) {
926: sc->sc_nticks++;
927: if (sc->sc_nticks > dmc_timeout) {
928: sc->sc_nticks = 0;
929: addr = (struct dmcdevice *)ui->ui_addr;
930: log(LOG_ERR, "dmc%d hung: bsel0=%b bsel2=%b\n",
931: i, addr->bsel0 & 0xff, DMC0BITS,
932: addr->bsel2 & 0xff, DMC2BITS);
933: dmcrestart(i);
934: }
935: }
936: }
937: timeout(dmcwatch, (caddr_t) 0, hz);
938: }
939: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.