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