|
|
1.1 root 1: /* if_dmc.c 6.1 83/07/29 */
2:
3: #include "dmc.h"
4: #if NDMC > 0
5: #define printd if(dmcdebug)printf
6: int dmcdebug = 0;
7: /*
8: * DMC11 device driver, internet version
9: *
10: * TODO
11: * allow more than one outstanding read or write.
12: *
13: * UNTESTED WITH 4.2
14: */
15: #include "../machine/pte.h"
16:
17: #include "../h/param.h"
18: #include "../h/systm.h"
19: #include "../h/mbuf.h"
20: #include "../h/buf.h"
21: #include "../h/ioctl.h" /* must precede tty.h */
22: #include "../h/tty.h"
23: #include "../h/protosw.h"
24: #include "../h/socket.h"
25: #include "../h/vmmac.h"
26: #include "../h/errno.h"
27:
28: #include "../net/if.h"
29: #include "../net/netisr.h"
30: #include "../net/route.h"
31: #include "../netinet/in.h"
32: #include "../netinet/in_systm.h"
33:
34: #include "../vax/cpu.h"
35: #include "../vax/mtpr.h"
36: #include "../vaxif/if_uba.h"
37: #include "../vaxif/if_dmc.h"
38: #include "../vaxuba/ubareg.h"
39: #include "../vaxuba/ubavar.h"
40:
41: #ifndef DMC_USEMAINT
42: #define DMC_USEMAINT 1 /* use maintenance mode */
43: #endif
44:
45: /*
46: * Driver information for auto-configuration stuff.
47: */
48: int dmcprobe(), dmcattach(), dmcinit(), dmcioctl();
49: int dmcoutput(), dmcreset();
50: struct uba_device *dmcinfo[NDMC];
51: u_short dmcstd[] = { 0 };
52: struct uba_driver dmcdriver =
53: { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
54:
55: /*
56: * DMC software status per interface.
57: *
58: * Each interface is referenced by a network interface structure,
59: * sc_if, which the routing code uses to locate the interface.
60: * This structure contains the output queue for the interface, its address, ...
61: * We also have, for each interface, a UBA interface structure, which
62: * contains information about the UNIBUS resources held by the interface:
63: * map registers, buffered data paths, etc. Information is cached in this
64: * structure for use by the if_uba.c routines in running the interface
65: * efficiently.
66: */
67: struct dmc_softc {
68: struct ifnet sc_if; /* network-visible interface */
69: struct ifuba sc_ifuba; /* UNIBUS resources */
70: short sc_flag; /* flags */
71: short sc_oactive; /* output active */
72: int sc_ubinfo; /* UBA mapping info for base table */
73: struct clist sc_que; /* command queue */
74: } dmc_softc[NDMC];
75:
76: /* flags */
77: #define DMCRUN 01
78: #define DMCBMAPPED 02 /* base table mapped */
79:
80: struct dmc_base {
81: short d_base[128]; /* DMC base table */
82: } dmc_base[NDMC];
83:
84: #define loword(x) ((short *)&x)[0]
85: #define hiword(x) ((short *)&x)[1]
86:
87: dmcprobe(reg)
88: caddr_t reg;
89: {
90: register int br, cvec;
91: register struct dmcdevice *addr = (struct dmcdevice *)reg;
92: register int i;
93:
94: #ifdef lint
95: br = 0; cvec = br; br = cvec;
96: dmcrint(0); dmcxint(0);
97: #endif
98: addr->bsel1 = DMC_MCLR;
99: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
100: ;
101: if ((addr->bsel1 & DMC_RUN) == 0)
102: return (0);
103: addr->bsel1 &= ~DMC_MCLR;
104: addr->bsel0 = DMC_RQI|DMC_IEI;
105: DELAY(100000);
106: addr->bsel1 = DMC_MCLR;
107: for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
108: ;
109: return (1);
110: }
111:
112: /*
113: * Interface exists: make available by filling in network interface
114: * record. System will initialize the interface when it is ready
115: * to accept packets.
116: */
117: dmcattach(ui)
118: register struct uba_device *ui;
119: {
120: register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
121:
122: sc->sc_if.if_unit = ui->ui_unit;
123: sc->sc_if.if_name = "dmc";
124: sc->sc_if.if_mtu = DMCMTU;
125: sc->sc_if.if_init = dmcinit;
126: sc->sc_if.if_output = dmcoutput;
127: sc->sc_if.if_ioctl = dmcioctl;
128: sc->sc_if.if_reset = dmcreset;
129: /* DON'T KNOW IF THIS WILL WORK WITH A BDP AT HIGH SPEEDS */
130: sc->sc_ifuba.ifu_flags = UBA_NEEDBDP | UBA_CANTWAIT;
131: if_attach(&sc->sc_if);
132: }
133:
134: /*
135: * Reset of interface after UNIBUS reset.
136: * If interface is on specified UBA, reset it's state.
137: */
138: dmcreset(unit, uban)
139: int unit, uban;
140: {
141: register struct uba_device *ui;
142:
143: if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
144: ui->ui_ubanum != uban)
145: return;
146: printf(" dmc%d", unit);
147: dmcinit(unit);
148: }
149:
150: /*
151: * Initialization of interface; reinitialize UNIBUS usage.
152: */
153: dmcinit(unit)
154: int unit;
155: {
156: register struct dmc_softc *sc = &dmc_softc[unit];
157: register struct uba_device *ui = dmcinfo[unit];
158: register struct dmcdevice *addr;
159: register struct ifnet *ifp = &sc->sc_if;
160: struct sockaddr_in *sin;
161: int base;
162:
163: printd("dmcinit\n");
164: sin = (struct sockaddr_in *)&ifp->if_addr;
165: if (sin->sin_addr.s_addr == 0)
166: return;
167: if ((ifp->if_flags & IFF_RUNNING) == 0) {
168: if ((sc->sc_flag&DMCBMAPPED) == 0) {
169: sc->sc_ubinfo = uballoc(ui->ui_ubanum,
170: (caddr_t)&dmc_base[unit],
171: sizeof (struct dmc_base), 0);
172: sc->sc_flag |= DMCBMAPPED;
173: }
174: if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0,
175: (int)btoc(DMCMTU)) == 0) {
176: printf("dmc%d: can't initialize\n", unit);
177: ifp->if_flags &= ~IFF_UP;
178: return;
179: }
180: addr = (struct dmcdevice *)ui->ui_addr;
181: addr->bsel2 |= DMC_IEO;
182: base = sc->sc_ubinfo & 0x3ffff;
183: printd(" base 0x%x\n", base);
184: dmcload(sc, DMC_BASEI, base, (base>>2)&DMC_XMEM);
185: dmcload(sc, DMC_CNTLI, 0, DMC_USEMAINT ? DMC_MAINT : 0);
186: base = sc->sc_ifuba.ifu_r.ifrw_info & 0x3ffff;
187: dmcload(sc, DMC_READ, base, ((base>>2)&DMC_XMEM)|DMCMTU);
188: printd(" first read queued, addr 0x%x\n", base);
189: ifp->if_flags |= IFF_UP|IFF_RUNNING;
190: }
191: /* set up routing table entry */
192: if ((ifp->if_flags & IFF_ROUTE) == 0) {
193: rtinit((struct sockaddr *)sin, (struct sockaddr *)sin,
194: RTF_HOST|RTF_UP);
195: ifp->if_flags |= IFF_ROUTE;
196: }
197: }
198:
199: /*
200: * Start output on interface. Get another datagram
201: * to send from the interface queue and map it to
202: * the interface before starting output.
203: */
204: dmcstart(dev)
205: dev_t dev;
206: {
207: int unit = minor(dev);
208: register struct dmc_softc *sc = &dmc_softc[unit];
209: int addr, len;
210: struct mbuf *m;
211:
212: printd("dmcstart\n");
213: /*
214: * Dequeue a request and map it to the UNIBUS.
215: * If no more requests, just return.
216: */
217: IF_DEQUEUE(&sc->sc_if.if_snd, m);
218: if (m == 0)
219: return;
220: len = if_wubaput(&sc->sc_ifuba, m);
221:
222: /*
223: * Have request mapped to UNIBUS for transmission.
224: * Purge any stale data from this BDP and start the output.
225: */
226: if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
227: UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp);
228: addr = sc->sc_ifuba.ifu_w.ifrw_info & 0x3ffff;
229: printd(" len %d, addr 0x%x, ", len, addr);
230: printd("mr 0x%x\n", sc->sc_ifuba.ifu_w.ifrw_mr[0]);
231: dmcload(sc, DMC_WRITE, addr, (len&DMC_CCOUNT)|((addr>>2)&DMC_XMEM));
232: sc->sc_oactive = 1;
233: }
234:
235: /*
236: * Utility routine to load the DMC device registers.
237: */
238: dmcload(sc, type, w0, w1)
239: register struct dmc_softc *sc;
240: int type, w0, w1;
241: {
242: register struct dmcdevice *addr;
243: register int unit, sps, n;
244:
245: printd("dmcload: 0x%x 0x%x 0x%x\n", type, w0, w1);
246: unit = sc - dmc_softc;
247: addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
248: sps = spl5();
249: if ((n = sc->sc_que.c_cc) == 0)
250: addr->bsel0 = type | DMC_RQI;
251: else
252: (void) putc(type | DMC_RQI, &sc->sc_que);
253: (void) putw(w0, &sc->sc_que);
254: (void) putw(w1, &sc->sc_que);
255: if (n == 0)
256: dmcrint(unit);
257: splx(sps);
258: }
259:
260: /*
261: * DMC interface receiver interrupt.
262: * Ready to accept another command,
263: * pull one off the command queue.
264: */
265: dmcrint(unit)
266: int unit;
267: {
268: register struct dmc_softc *sc;
269: register struct dmcdevice *addr;
270: register int n;
271:
272: addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
273: sc = &dmc_softc[unit];
274: while (addr->bsel0&DMC_RDYI) {
275: addr->sel4 = getw(&sc->sc_que);
276: addr->sel6 = getw(&sc->sc_que);
277: addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
278: while (addr->bsel0&DMC_RDYI)
279: ;
280: if (sc->sc_que.c_cc == 0)
281: goto out;
282: addr->bsel0 = getc(&sc->sc_que);
283: n = RDYSCAN;
284: while (n-- && (addr->bsel0&DMC_RDYI) == 0)
285: ;
286: }
287: if (sc->sc_que.c_cc)
288: addr->bsel0 |= DMC_IEI;
289: out:
290: dmcxint(unit);
291: }
292:
293: /*
294: * DMC interface transmitter interrupt.
295: * A transfer has completed, check for errors.
296: * If it was a read, notify appropriate protocol.
297: * If it was a write, pull the next one off the queue.
298: */
299: dmcxint(unit)
300: int unit;
301: {
302: register struct dmc_softc *sc;
303: register struct ifnet *ifp;
304: struct uba_device *ui = dmcinfo[unit];
305: struct dmcdevice *addr;
306: struct mbuf *m;
307: register struct ifqueue *inq;
308: int arg, cmd, len;
309:
310: addr = (struct dmcdevice *)ui->ui_addr;
311: cmd = addr->bsel2 & 0xff;
312: if ((cmd & DMC_RDYO) == 0)
313: return;
314: #ifdef notdef
315: arg2 = addr->sel4;
316: #endif
317: arg = addr->sel6;
318: addr->bsel2 &= ~DMC_RDYO;
319: sc = &dmc_softc[unit];
320: ifp = &sc->sc_if;
321: printd("dmcxint\n");
322: switch (cmd & 07) {
323:
324: case DMC_OUR:
325: /*
326: * A read has completed. Purge input buffered
327: * data path. Pass packet to type specific
328: * higher-level input routine.
329: */
330: ifp->if_ipackets++;
331: if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
332: UBAPURGE(sc->sc_ifuba.ifu_uba,
333: sc->sc_ifuba.ifu_r.ifrw_bdp);
334: len = arg & DMC_CCOUNT;
335: printd(" read done, len %d\n", len);
336: switch (ifp->if_addr.sa_family) {
337: #ifdef INET
338: case AF_INET:
339: schednetisr(NETISR_IP);
340: inq = &ipintrq;
341: break;
342: #endif
343:
344: default:
345: printf("dmc%d: unknown address type %d\n", unit,
346: ifp->if_addr.sa_family);
347: goto setup;
348: }
349: m = if_rubaget(&sc->sc_ifuba, len, 0);
350: if (m == 0)
351: goto setup;
352: if (IF_QFULL(inq)) {
353: IF_DROP(inq);
354: m_freem(m);
355: } else
356: IF_ENQUEUE(inq, m);
357:
358: setup:
359: arg = sc->sc_ifuba.ifu_r.ifrw_info & 0x3ffff;
360: dmcload(sc, DMC_READ, arg, ((arg >> 2) & DMC_XMEM) | DMCMTU);
361: return;
362:
363: case DMC_OUX:
364: /*
365: * A write has completed, start another
366: * transfer if there is more data to send.
367: */
368: if (sc->sc_oactive == 0)
369: return; /* SHOULD IT BE A FATAL ERROR? */
370: printd(" write done\n");
371: ifp->if_opackets++;
372: sc->sc_oactive = 0;
373: if (sc->sc_ifuba.ifu_xtofree) {
374: m_freem(sc->sc_ifuba.ifu_xtofree);
375: sc->sc_ifuba.ifu_xtofree = 0;
376: }
377: if (ifp->if_snd.ifq_head == 0)
378: return;
379: dmcstart(unit);
380: return;
381:
382: case DMC_CNTLO:
383: arg &= DMC_CNTMASK;
384: if (arg&DMC_FATAL) {
385: addr->bsel1 = DMC_MCLR;
386: sc->sc_flag &= ~DMCRUN;
387: /*** DO SOMETHING TO RESTART DEVICE ***/
388: printf("DMC FATAL ERROR 0%o\n", arg);
389: } else {
390: /* ACCUMULATE STATISTICS */
391: printf("DMC SOFT ERROR 0%o\n", arg);
392: }
393: return;
394:
395: default:
396: printf("dmc%d: bad control %o\n", unit, cmd);
397: }
398: }
399:
400: /*
401: * DMC output routine.
402: * Just send the data, header was supplied by
403: * upper level protocol routines.
404: */
405: dmcoutput(ifp, m, dst)
406: register struct ifnet *ifp;
407: register struct mbuf *m;
408: struct sockaddr *dst;
409: {
410: int s;
411:
412: printd("dmcoutput\n");
413: if (dst->sa_family != ifp->if_addr.sa_family) {
414: printf("dmc%d: af%d not supported\n", ifp->if_unit,
415: dst->sa_family);
416: m_freem(m);
417: return (EAFNOSUPPORT);
418: }
419: s = splimp();
420: if (IF_QFULL(&ifp->if_snd)) {
421: IF_DROP(&ifp->if_snd);
422: m_freem(m);
423: splx(s);
424: return (ENOBUFS);
425: }
426: IF_ENQUEUE(&ifp->if_snd, m);
427: if (dmc_softc[ifp->if_unit].sc_oactive == 0)
428: dmcstart(ifp->if_unit);
429: splx(s);
430: return (0);
431: }
432:
433: /*
434: * Process an ioctl request.
435: */
436: dmcioctl(ifp, cmd, data)
437: register struct ifnet *ifp;
438: int cmd;
439: caddr_t data;
440: {
441: struct ifreq *ifr = (struct ifreq *)data;
442: struct sockaddr_in *sin;
443: int s = splimp(), error = 0;
444:
445: switch (cmd) {
446:
447: case SIOCSIFADDR:
448: if (ifp->if_flags & IFF_RUNNING)
449: if_rtinit(ifp, -1); /* delete previous route */
450: sin = (struct sockaddr_in *)&ifr->ifr_addr;
451: ifp->if_addr = *(struct sockaddr *)sin;
452: ifp->if_net = in_netof(sin->sin_addr);
453: ifp->if_host[0] = in_lnaof(sin->sin_addr);
454: dmcinit(ifp->if_unit);
455: break;
456:
457: case SIOCSIFDSTADDR:
458: ifp->if_dstaddr = ifr->ifr_dstaddr;
459: break;
460:
461: default:
462: error = EINVAL;
463: }
464: splx(s);
465: return (error);
466: }
467: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.