|
|
1.1 root 1:
2: /*
3: * Interlan Ethernet Communications Controller interface.
4: * Provides fairly raw access to a number of Interlan controllers.
5: * Minor device N talks to unit N / 8. Each written record should
6: * be an interlan output packet - 6 bytes addr, 2 bytes type, data.
7: * An ethernet packet type may be associated with a minor device with
8: * the ENIOTYPE ioctl; input packets of that type will be sent to
9: * the minor device in question. Input packets include 6 bytes src addr,
10: * 6 bytes dest, 2 bytes type, and data.
11: *
12: * The physical address of a controller may be fetched with the ENIOADDR
13: * ioctl on a minor device associated with that unit.
14: */
15: #include "il.h"
16: #if NIL > 0
17:
18: #include "../h/param.h"
19: #include "../h/systm.h"
20: #include "../h/stream.h"
21: #include "../h/map.h"
22: #include "../h/buf.h"
23: #include "../h/ubavar.h"
24: #include "../h/conf.h"
25: #include "../h/ioctl.h"
26: #include "../h/ttyld.h"
27: #include "../h/ill_reg.h"
28: #include "../h/ethernet.h"
29:
30: int ilprobe(), ilattach(), ilrint(), ilcint();
31: struct uba_device *ilinfo[NIL];
32: u_short ilstd[] = { 0 };
33: struct uba_driver ildriver =
34: { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
35:
36: #define ILOUTSTANDING 1 /* max # of rcv bufs in controller q */
37: #define BOGUS 1 /* CDONE doesn't work */
38:
39: struct il { /* per controller */
40: int attached;
41: int active;
42: int rcvpending;
43: int ipackets, opackets;
44: int ierrors, oerrors;
45: int collisions;
46: struct block *bp; /* waiting to be filled */
47: struct block *nbp; /* next block to be filled in this packet */
48: int len; /* amount left in this packet */
49: struct queue *tq; /* current transmit q */
50: struct block *freebp;
51: unsigned char addr[6];
52: } il[NIL];
53:
54: extern u_char blkdata[]; /* stream.c */
55: extern long blkubad;
56: int ilprintfs = 0;
57:
58: struct il_stats ilstats;
59:
60: #define CHANS_PER_UNIT 8
61: #define NILCHAN (CHANS_PER_UNIT * NIL)
62: struct ilchan{ /* per stream */
63: int unit;
64: int packets; /* # of packets on q to output */
65: struct queue *rq;
66: int type; /* ethernet protocol # */
67: int haveheader; /* ethernet header has gone by */
68: } ilchan[NILCHAN];
69:
70: ilprobe(reg)
71: caddr_t reg;
72: {
73: register int br, cvec; /* r11, r10 */
74: register struct ildevice *addr = (struct ildevice *) reg;
75: register i;
76:
77: #ifdef lint
78: br = 0; cvec = br; br = cvec; i = br; br = i;
79: #endif
80:
81: addr->il_csr = ILC_OFFLINE|IL_CIE;
82: DELAY(100000);
83: i = addr->il_csr; /* clear CDONE */
84: if(cvec > 0 && cvec != 0x200)
85: cvec -= 4;
86: return(1);
87: }
88:
89: ilattach(ui)
90: struct uba_device *ui;
91: {
92: register struct il *is = &il[ui->ui_unit];
93: register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
94: int ubaddr, s;
95:
96:
97: s = spl6();
98:
99: addr->il_csr = ILC_RESET;
100: while((addr->il_csr&IL_CDONE) == 0)
101: ;
102: if(addr->il_csr&IL_STATUS)
103: printf("il%d: reset failed, csr=%b\n", ui->ui_unit,
104: addr->il_csr, IL_BITS);
105:
106: ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&ilstats,
107: sizeof(ilstats), 0);
108: if(ubaddr == 0){
109: printf(" no uballoc\n");
110: goto nostats;
111: }
112: addr->il_bar = ubaddr&0xffff;
113: addr->il_bcr = sizeof(ilstats);
114: addr->il_csr = ((ubaddr >> 2) & IL_EUA) | ILC_STAT;
115: while((addr->il_csr&IL_CDONE) == 0)
116: ;
117:
118: ubarelse(ui->ui_ubanum, &ubaddr);
119: bcopy(ilstats.ils_addr, is->addr, sizeof(is->addr));
120:
121: nostats:
122: addr->il_csr = ILC_ONLINE;
123: while((addr->il_csr&IL_CDONE) == 0)
124: ;
125: /*
126: * ask ilcint to set up the first rcv buffer,
127: * since the block stuff doesn't seem to be
128: * initialized yet.
129: */
130: is->rcvpending = ETHERMTU;
131:
132: is->active = 0;
133: is->attached = 1;
134: splx(s);
135: }
136:
137: ilstart(unit)
138: {
139: int ubaddr, count;
140: struct uba_device *ui = ilinfo[unit];
141: register struct il *is = &il[unit];
142: register struct ildevice *addr;
143: struct ilchan *icp;
144: struct block *bp;
145: register struct queue *q;
146:
147: if(is->active){
148: printf(" start but active\n", unit);
149: is->active = 0;
150: }
151:
152: for(icp = ilchan; icp < &ilchan[NILCHAN]; icp++)
153: if(icp->rq && icp->unit == unit && icp->packets > 0)
154: break;
155: if(icp >= &ilchan[NILCHAN])
156: return;
157: q = WR(icp->rq);
158:
159: is->active = 1;
160: addr = (struct ildevice *)ui->ui_addr;
161: #ifdef BOGUS
162: is->tq = q;
163: bp = getq(q);
164: if(bp == 0){
165: printf("ilstart no bp\n");
166: is->active = 0;
167: return;
168: }
169: ildebug(bp, 1);
170: ubaddr = iladdr((caddr_t)(bp->rptr));
171: addr->il_bar = ubaddr&0xffff;
172: addr->il_bcr = bp->wptr - bp->rptr;
173: addr->il_csr = ((ubaddr>>2)&IL_EUA)|ILC_LDXMIT|IL_RIE|IL_CIE;
174: is->freebp = bp;
175: /*
176: * I would have given the entire packet to the controller,
177: * but it's brain-damaged. So I wait for the interrupt to
178: * put the next one on.
179: */
180: #else
181: while(bp = getq(q)){
182: if(bp->type != M_DATA){
183: /* don't free, it's re-used */
184: break;
185: }
186: ubaddr = iladdr((caddr_t)bp->rptr);
187: addr->il_bar = ubaddr&0xffff;
188: addr->il_bcr = bp->wptr - bp->rptr;
189: addr->il_csr = ((ubaddr>>2)&IL_EUA)|ILC_LDXMIT|IL_RIE;
190: ilcdone(addr, "LDX");
191: freeb(bp);
192: }
193: if(bp == 0){
194: printf("ilstart no delim?\n");
195: bp = allocb(1);
196: }
197: bp->wptr = bp->rptr;
198: --(icp->packets);
199: ubaddr = iladdr((caddr_t)bp->base);
200: addr->il_bar = ubaddr&0xffff;
201: addr->il_bcr = 0;
202: addr->il_csr = ((ubaddr>>2)&IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE;
203: /* go, baby */
204: is->opackets++;
205: freeb(bp);
206: #endif BOGUS
207: }
208:
209: /*
210: * transmit done
211: */
212: ilcint(unit)
213: {
214: int ubaddr;
215: register struct il *is = &il[unit];
216: struct uba_device *ui = ilinfo[unit];
217: register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
218: short csr;
219: register struct block *bp;
220:
221: if(is->active == 0){
222: printf("il%d: stray xmit interrupt, csr=%b\n", unit,
223: addr->il_csr, IL_BITS);
224: return;
225: }
226: #ifdef BOGUS
227: if(is->tq){
228: if(is->freebp)
229: freeb(is->freebp);
230: is->freebp = 0;
231: if((bp = getq(is->tq)) == 0){
232: printf("gak\n");
233: is->active = 0;
234: is->tq = 0;
235: return;
236: }
237: ubaddr = iladdr((caddr_t)(bp->rptr));
238: addr->il_bar = ubaddr&0xffff;
239: addr->il_bcr = bp->wptr - bp->rptr;
240: if(bp->type == M_DELIM){
241: addr->il_csr = ((ubaddr>>2)&IL_EUA)|ILC_XMIT|IL_RIE|IL_CIE;
242: ((struct ilchan *)(is->tq->ptr))->packets -= 1;
243: is->tq = 0;
244: freeb(bp);
245: } else {
246: addr->il_csr = ((ubaddr>>2)&IL_EUA)|ILC_LDXMIT|IL_RIE|IL_CIE;
247: is->freebp = bp;
248: }
249: return;
250: }
251: #endif BOGUS
252: csr = addr->il_csr;
253: is->active = 0;
254: if(is->rcvpending)
255: ilsetup(is, addr, is->rcvpending);
256:
257: /* check status of last xmit */
258: csr &= IL_STATUS;
259: if(csr > ILERR_RETRIES){
260: printf("il%d: tx error 0x%x\n", unit, csr);
261: is->oerrors++;
262: } else if(csr > ILERR_SUCCESS){
263: is->collisions++;
264: }
265: #ifdef BOGUS
266: else is->opackets++;
267: #endif
268: ilstart(unit);
269: }
270:
271: ilrint(unit)
272: {
273: register struct il *is = &il[unit];
274: register struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr;
275: register struct il_rheader *hp;
276: int len;
277: struct block *bp, *bp1;
278: register struct ilchan *icp;
279: register struct queue *q;
280:
281: if(is->bp == 0)
282: panic("ilrint no is->bp");
283: if(is->nbp == 0)
284: panic("ilrint no is->nbp");
285: bp = is->nbp;
286: if(bp == is->bp){
287: /* first buffer of a packet */
288: hp = (struct il_rheader *)bp->rptr;
289: is->len = hp->ilr_length;
290: is->len += 4;
291: }
292: is->len -= (bp->wptr - bp->rptr);
293: is->nbp = bp->next;
294: /* ilsetup will take care of huge packets by asking
295: * the controller to truncate.
296: */
297: if(is->len <= 0)
298: goto done;
299: if((bp->wptr - bp->rptr) % 8) /* not chaining */
300: goto done;
301: if(is->nbp == 0){
302: /* more, more */
303: if(is->active){
304: is->rcvpending = is->len;
305: } else {
306: ilsetup(is, addr, is->len);
307: }
308: }
309: return;
310:
311: done:
312: bp = is->bp;
313: hp = (struct il_rheader *)bp->rptr;
314: len = hp->ilr_length - sizeof(struct il_rheader);
315:
316: if(len < 46 || len > ETHERMTU || is->len > 0){
317: if(ilprintfs)
318: printf("il%d: ilr_length %d is-len %d\n",
319: unit, hp->ilr_length, is->len);
320: is->ierrors++;
321: goto setup;
322: }
323: if(hp->ilr_status&ILFSTAT_L)
324: is->ierrors++;
325: len += sizeof(struct il_rheader) - 4;
326:
327: for(icp = ilchan; icp < &ilchan[NILCHAN]; icp++)
328: if(icp->rq && icp->unit == unit && icp->type == hp->ilr_type)
329: break;
330: if(icp >= &ilchan[NILCHAN]){
331: if(ilprintfs)
332: printf("type %x?\n", hp->ilr_type);
333: goto setup;
334: }
335: q = icp->rq;
336: if(q->next->flag&QFULL){
337: if(ilprintfs)
338: printf(" q full\n");
339: is->ierrors++;
340: goto setup;
341: }
342: bp->rptr = &(hp->ilr_dhost[0]);
343: ildebug(bp, 0);
344: len = hp->ilr_length - 4;
345: while(bp && bp != is->nbp){
346: if (bp->wptr - bp->rptr > len)
347: bp->wptr = bp->rptr + len;
348: len -= bp->wptr - bp->rptr;
349: bp1 = bp->next;
350: if (bp->wptr > bp->rptr)
351: (*q->next->qinfo->putp)(q->next, bp);
352: else
353: freeb(bp);
354: bp = bp1;
355: }
356: is->bp = is->nbp;
357: bp = allocb(1);
358: if(bp){
359: bp->type = M_DELIM;
360: (*q->next->qinfo->putp)(q->next, bp);
361: is->ipackets++;
362: } else {
363: printf("ilrint no DELIM bp\n");
364: }
365: setup:
366: /* free up blocks in a rejected packet */
367: bp = is->bp;
368: while(bp && bp != is->nbp){
369: bp1 = bp->next;
370: freeb(bp);
371: bp = bp1;
372: }
373: is->bp = bp;
374: if(is->active){ /* don't interfere w/ output */
375: is->rcvpending = ETHERMTU;
376: return;
377: }
378: ilsetup(is, addr, ETHERMTU);
379: }
380:
381: iladdr(memaddr)
382: caddr_t memaddr;
383: {
384: register long a;
385:
386: if((unsigned)memaddr < (unsigned)blkdata){
387: printf("memaddr %x blkdata %x\n", memaddr, blkdata);
388: panic("iladdr");
389: }
390: a = (long)memaddr - (long)(caddr_t)blkdata + ((long)blkubad&0x03ffff);
391: /* sure */
392: return(a);
393: }
394:
395: int nodev(), ilopen(), ilclose(), ilput();
396: struct qinit ilrinit = { nodev, NULL, ilopen, ilclose, 0, 0 };
397: struct qinit ilwinit = { ilput, NULL, ilopen, ilclose, ETHERMTU-6, 64 };
398: struct streamtab ilsinfo = { &ilrinit, &ilwinit };
399:
400: ilopen(q, dev)
401: register struct queue *q;
402: register dev_t dev;
403: {
404: register struct ilchan *icp;
405: register struct il *is;
406: int unit, s;
407:
408: dev = minor(dev);
409: unit = dev / CHANS_PER_UNIT;
410: if(dev >= NILCHAN)
411: return(0);
412: if(unit >= NIL)
413: return(0);
414: is = &il[unit];
415: if(is->attached == 0)
416: return(0);
417: icp = &ilchan[dev];
418: if(icp->rq)
419: return(0);
420:
421: icp->rq = q;
422: q->ptr = (caddr_t)icp;
423: WR(q)->ptr = (caddr_t)icp;
424: WR(q)->flag |= QDELIM|QBIGB;
425: q->flag |= QDELIM;
426:
427: icp->unit = unit;
428: icp->type = 0;
429: icp->packets = 0;
430:
431: s = spl6();
432: if(is->rcvpending && is->active == 0){
433: /* first open, supply rcv buffer */
434: is->active = 1;
435: ilcint(unit);
436: }
437: splx(s);
438: return(1);
439: }
440:
441: ilclose(q)
442: register struct queue *q;
443: {
444: register struct ilchan *icp;
445:
446: icp = (struct ilchan *)q->ptr;
447: icp->rq = 0;
448: icp->packets = 0;
449: }
450:
451: /*
452: * Ilput expects the first block of each packet to contain a six byte
453: * ethernet address followed by a two byte packet type number in
454: * network byte order.
455: */
456: ilput(q, bp)
457: register struct queue *q;
458: struct block *bp;
459: {
460: register struct il *is;
461: int unit, s;
462: register struct ilchan *icp;
463:
464: icp = (struct ilchan *)q->ptr;
465: unit = icp->unit;
466:
467: if(bp->type == M_DATA){
468: if (!icp->haveheader) {
469: icp->haveheader = 1;
470: ilfixheader(bp);
471: }
472: putq(q, bp);
473: return;
474: } else if(bp->type == M_IOCTL){
475: ilioctl(q, bp);
476: return;
477: } else if(bp->type != M_DELIM){
478: freeb(bp);
479: return;
480: }
481: /* have end of packet */
482: icp->haveheader = 0;
483: putq(q, bp);
484: is = &il[unit];
485: s = spl6();
486: icp->packets++;
487: if(is->active == 0)
488: ilstart(unit);
489: splx(s);
490: }
491:
492: /*
493: * Interlan drivers accept a strange type of ethernet header.
494: * It is the normal ethernet header with the source field removed.
495: */
496: ilfixheader(bp)
497: register struct block *bp;
498: {
499: register struct ether_in *ep;
500:
501: if (bp->wptr - bp->rptr < sizeof(struct ether_out)) {
502: printf("ether_header too short\n");
503: return;
504: }
505: ep = (struct ether_in *)(bp->rptr);
506: bcopy(ep->dhost, ep->shost, 6);
507: bp->rptr += 6;
508: }
509:
510: #define ILLDEBSIZE 64
511: struct {
512: time_t time;
513: unsigned short code;
514: unsigned char addr[6];
515: } illdebarr[ILLDEBSIZE];
516:
517: int illindex = 0;
518:
519: ildebug(bp, code)
520: register struct block *bp;
521: {
522: illdebarr[illindex].time = time;
523: illdebarr[illindex].code = code;
524: bcopy(bp->rptr, illdebarr[illindex].addr, 6);
525: illindex = (illindex + 1) % ILLDEBSIZE;
526: }
527:
528: ilioctl(q, bp)
529: register struct queue *q;
530: register struct block *bp;
531: {
532: union stmsg *sp;
533: register struct ilchan *icp;
534: int unit;
535: struct uba_device *ui;
536: struct ildevice *addr;
537:
538: icp = (struct ilchan *)q->ptr;
539: sp = (union stmsg *)bp->rptr;
540: bp->type = M_IOCACK;
541: switch(sp->ioc0.com){
542: case ENIOTYPE:
543: icp->type = *((int *)(sp->iocx.xxx));
544: break;
545: case ENIOADDR:
546: bcopy(il[icp->unit].addr, sp->iocx.xxx, 6);
547: break;
548: case ENIOCMD: /* perform a non-dma interlan command */
549: unit = icp->unit;
550: ui = ilinfo[unit];
551: addr = (struct ildevice *)ui->ui_addr;
552: addr->il_csr = *((int *)(sp->iocx.xxx));
553: *((int *)(sp->iocx.xxx)) = ilcdone(addr, "CMD");
554: break;
555: default:
556: bp->type = M_IOCNAK;
557: break;
558: }
559: qreply(q, bp);
560: }
561:
562: ilsetup(is, addr, n)
563: register struct il *is;
564: register struct ildevice *addr;
565: {
566: register struct block *bp;
567: int ubaddr, count;
568:
569: if(is->active)
570: panic("ilsetup active");
571: /*
572: * is->bp is start of buffer chain, is->nbp is next buffer
573: * to be DMA'd into. if is->bp is zero, there is no chain
574: * yet, else if is->nbp is zero, add stuff to the end of
575: * the chain, else only add stuff if we need to.
576: */
577: if(is->nbp && is->bp == 0){
578: printf("il: nbp but no bp in ilsetup\n");
579: is->nbp = 0;
580: }
581: count = 0;
582: /* count bytes and buffers already loaded into controller */
583: for(bp = is->nbp; bp; bp = bp->next){
584: n -= bp->wptr - bp->rptr;
585: count++;
586: }
587: if(n <= 0)
588: return;
589: if(count > ILOUTSTANDING)
590: printf("ilsetup: already %d in bar/bcr q!\n", count);
591: if(is->bp == 0){
592: bp = is->nbp = 0;
593: } else {
594: for(bp = is->bp; bp->next; bp = bp->next)
595: ;
596: }
597: /* now bp is 0 or else the last block in the chain */
598: while(count < ILOUTSTANDING && n > 0){
599: if(bp == 0){
600: is->bp = is->nbp = bp = allocb(n);
601: } else {
602: bp->next = allocb(n);
603: bp = bp->next;
604: }
605: if(bp == 0){
606: is->rcvpending = n;
607: return;
608: }
609: bp->next = 0;
610: if(is->nbp == 0)
611: is->nbp = bp;
612: bp->rptr = bp->base;
613: bp->wptr = bp->lim;
614: if(n > ETHERMTU){ /* tell controller to truncate */
615: bp->wptr -= 2;
616: n = 0;
617: }
618: n -= bp->wptr - bp->rptr;
619: count++;
620: ubaddr = iladdr((caddr_t)(bp->rptr));
621: addr->il_bar = ubaddr & 0xffff;
622: addr->il_bcr = bp->wptr - bp->rptr;
623: addr->il_csr = ((ubaddr>>2)&IL_EUA)|ILC_RCV|IL_RIE;
624: ilcdone(addr, "RCV");
625: }
626: is->rcvpending = 0;
627: }
628:
629: ilcdone(addr, s)
630: struct ildevice *addr;
631: char *s;
632: {
633: int count;
634:
635: count = 0;
636: while((addr->il_csr & IL_CDONE) == 0){
637: count++;
638: if(count > 200000)
639: break;
640: }
641: if(count > 200000){
642: printf("%s: addr 0%o csr 0x%x\n", s, addr, addr->il_csr);
643: return(1);
644: }
645: return(addr->il_csr & 0xf);
646: }
647: #endif NIL
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.