|
|
1.1 root 1: /*
2: * Interlan NI1010A Ethernet interface.
3: * Each hardware device has eight minor devices starting at N*8;
4: * the different channels may be caused to receive different
5: * Ethernet protocols via ENIOTYPE.
6: * Packets read or written have the Ethernet header in front.
7: */
8: #include "sys/param.h"
9: #include "sys/stream.h"
10: #include "sys/conf.h"
11: #include "sys/ubaddr.h"
12: #include "sys/enio.h"
13: #include "sys/ethernet.h"
14: #include "sys/ni1010a.h"
15:
16: /*
17: * hardware registers
18: */
19: struct ildevice {
20: unsigned short il_csr;
21: short il_bar;
22: short il_bcr;
23: };
24:
25: /*
26: * il_csr
27: */
28: #define IL_EUA 0xc000 /* buffer address high bits */
29: #define IL_CDONE 0x0080 /* command done */
30: #define IL_CIE 0x0040 /* command intr enable */
31: #define IL_RDONE 0x0020 /* receive data arrived */
32: #define IL_RIE 0x0010 /* receive intr enable */
33: #define IL_STATUS 0x000f /* mask for command status */
34:
35: /*
36: * commands, already shifted into place
37: */
38: #define ILC_ONLINE 0x0900 /* speak to the network */
39: #define ILC_STAT 0x1800 /* return statistics and address */
40: #define ILC_RCV 0x2000 /* here's a receive buffer */
41: #define ILC_LDXMIT 0x2800 /* take this data */
42: #define ILC_XMIT 0x2900 /* take this data, start sending */
43: #define ILC_RESET 0x3f00 /* reset */
44:
45: /*
46: * status values (some)
47: */
48: #define ILERR_SUCCESS 0 /* ok */
49: #define ILERR_RETRIES 1 /* ok, but retried */
50: /* other values mean it didn't work */
51:
52: /*
53: * status after diagnostics
54: */
55: #define ILDIAG_SUCCESS 0 /* ok */
56:
57: /*
58: * frame status bits in received packet
59: */
60: #define FS_LOST 04 /* some earlier packet was lost */
61: #define FS_ALIGN 02 /* alignment error */
62: #define FS_CRC 01 /* CRC error */
63:
64: #define CRCSIZE 4 /* size of the pointless CRC on received pkt */
65: #define MAXRBUFS 16 /* max number of rcv buffers allowed */
66:
67: /*
68: * enormous statistics record
69: * we get it only for the ethernet address address
70: */
71: struct il_stats {
72: short ils_fill1;
73: short ils_length; /* Length (should be 62) */
74: char ils_addr[6]; /* Ethernet Address */
75: short ils_frames; /* Number of Frames Received */
76: short ils_rfifo; /* Number of Frames in Receive FIFO */
77: short ils_xmit; /* Number of Frames Transmitted */
78: short ils_xcollis; /* Number of Excess Collisions */
79: short ils_frag; /* Number of Fragments Received */
80: short ils_lost; /* Number of Times Frames Lost */
81: short ils_multi; /* Number of Multicasts Accepted */
82: short ils_rmulti; /* Number of Multicasts Rejected */
83: short ils_crc; /* Number of CRC Errors */
84: short ils_align; /* Number of Alignment Errors */
85: short ils_collis; /* Number of Collisions */
86: short ils_owcollis; /* Number of Out-of-window Collisions */
87: short ils_fill2[8];
88: char ils_module[8]; /* Module ID */
89: char ils_firmware[8]; /* Firmware ID */
90: };
91:
92: extern int ilcnt;
93: extern struct il il[];
94: extern struct ubaddr iladdr[];
95:
96: /*
97: * il.flags
98: */
99:
100: #define CMDACT 01 /* some command active -- can't issue another yet */
101: #define INITDONE 02 /* finished init */
102: #define INITING 04 /* halfway through init; just wakeup on intr */
103:
104: #define NEXTCH(i) (((i)+1)%NILCHAN)
105:
106: #define ETHERMAXTU 1500 /* max packet size */
107: #define ILRBYTES (ETHERMAXTU*2) /* desired receive buffer size */
108: #define ILRSIZE 1024 /* preferred receive block size */
109:
110: #define ISCHAIN(l) (((l)&07) == 0)
111: #define MKCHAIN(l) ((l)&~07) /* force length to allow rbuf chaining */
112: #define MKTRUNC(l) (MKCHAIN(l)-2) /* force to disallow */
113:
114: long ilopen();
115: int ilclose(), ilput();
116: static struct qinit ilrinit = { noput, NULL, ilopen, ilclose, 0, 0 };
117: static struct qinit ilwinit = { ilput, NULL, ilopen, ilclose, 4*ETHERMAXTU, 64 };
118: static struct streamtab ilsinfo = { &ilrinit, &ilwinit };
119: struct cdevsw ilcdev = cstrinit(&ilsinfo);
120:
121: long
122: ilopen(q, dev)
123: register struct queue *q;
124: register dev_t dev;
125: {
126: register struct ilchan *cp;
127: register struct il *is;
128: int unit;
129:
130: dev = minor(dev);
131: unit = dev / NILCHAN;
132: if (unit >= ilcnt || ilinit(unit) == 0)
133: return(0);
134: is = &il[unit];
135: cp = &is->chan[dev%NILCHAN];
136: if(cp->rq)
137: return(0);
138: cp->rq = q;
139: q->ptr = (caddr_t)cp;
140: WR(q)->ptr = (caddr_t)cp;
141: WR(q)->flag |= QDELIM|QBIGB;
142: q->flag |= QDELIM;
143: cp->unit = unit; /* needed? */
144: cp->type = 0;
145: return(1);
146: }
147:
148: /*
149: * init the hardware
150: */
151: static struct il_stats ilstats;
152: static char ilsbusy;
153:
154: ilinit(dev)
155: int dev;
156: {
157: register struct il *is;
158: register struct ildevice *addr;
159: ubm_t ubm;
160: uaddr_t uad;
161: register int sts;
162: int s;
163:
164: is = &il[dev];
165: s = spl6();
166: while (is->flags & INITING)
167: tsleep((caddr_t)is, PZERO+1, 5);
168: splx(s);
169: if (is->flags & INITDONE)
170: return (1);
171: is->flags |= INITING;
172: if ((addr = (struct ildevice *)ubaddr(&iladdr[dev])) == NULL
173: || badaddr(&addr->il_csr, sizeof(short))) {
174: printf("ni1010a %d absent\n", dev);
175: is->flags &=~ INITING;
176: return (0);
177: }
178: is->ubno = iladdr[dev].ubno;
179: is->addr = addr;
180: if ((sts = ilincmd(is, ILC_RESET)) == 0
181: || (sts & IL_STATUS) != ILDIAG_SUCCESS) {
182: printf("ni1010a %d: reset failed csr %x\n", dev, is->lastcsr);
183: is->flags &=~ INITING;
184: return (0);
185: }
186: s = spl6();
187: while (ilsbusy)
188: tsleep((caddr_t)&ilsbusy, PZERO, 5);
189: ilsbusy = 1;
190: splx(s);
191: ubm = ubmalloc(is->ubno, sizeof(ilstats), USLP);
192: uad = ubmaddr(is->ubno, (char *)&ilstats, sizeof(ilstats), ubm);
193: addr->il_bar = uad;
194: addr->il_bcr = sizeof(ilstats);
195: sts = ilincmd(is, (int)((uad >> 2) & IL_EUA) | ILC_STAT);
196: ubmfree(is->ubno, ubm);
197: if (sts == 0 || (sts & IL_STATUS) != ILERR_SUCCESS) {
198: ilsbusy = 0;
199: wakeup((caddr_t)&ilsbusy);
200: printf("ni1010a %d: stat failed csr %x\n", dev, is->lastcsr);
201: is->flags &=~ INITING;
202: return (0);
203: }
204: bcopy(ilstats.ils_addr, is->enaddr, sizeof(is->enaddr));
205: ilsbusy = 0;
206: wakeup((caddr_t)&ilsbusy);
207: if ((sts = ilincmd(is, ILC_ONLINE)) == 0
208: || (sts & IL_STATUS) != ILERR_SUCCESS) {
209: printf("ni1010a %d: online failed csr %x\n", dev, sts);
210: is->flags &=~ INITING;
211: return (0);
212: }
213: is->flags &=~ INITING;
214: is->flags |= INITDONE;
215: wakeup((caddr_t)is); /* in case someone is waiting */
216: s = spl6();
217: ilrcvbufs(is);
218: splx(s);
219: return (1);
220: }
221:
222: int
223: ilincmd(is, csr)
224: register struct il *is;
225: register short csr;
226: {
227: register int s;
228:
229: s = spl6();
230: is->flags |= CMDACT;
231: is->addr->il_csr = csr|IL_CIE;
232: while (is->flags & CMDACT)
233: if (tsleep((caddr_t)is, PZERO, 5) != TS_OK) {
234: is->flags &=~ CMDACT;
235: splx(s);
236: return (0);
237: }
238: csr = is->lastcsr; /* probably unnecessary */
239: splx(s);
240: return (csr);
241: }
242:
243: ilclose(q)
244: struct queue *q;
245: {
246: struct ilchan *cp;
247:
248: cp = (struct ilchan *)q->ptr;
249: cp->rq = 0;
250: }
251:
252: /*
253: * stash data
254: */
255: ilput(q, bp)
256: struct queue *q;
257: register struct block *bp;
258: {
259: register struct ilchan *cp;
260: register int s;
261:
262: cp = (struct ilchan *)q->ptr;
263: switch (bp->type) {
264: case M_DATA:
265: cp->xlast = bp;
266: putq(q, bp);
267: if (bp->class&S_DELIM)
268: break;
269: return;
270:
271: case M_IOCTL:
272: ilioctl(q, bp);
273: return;
274:
275: default:
276: freeb(bp);
277: return;
278: }
279: /*
280: * S_DELIM: end of packet
281: */
282: if (cp->xlast == NULL) /* empty record */
283: return;
284: cp->xlast = NULL;
285: cp->ndelims++;
286: s = spl6();
287: ilsendpkt(&il[cp->unit]);
288: splx(s);
289: }
290:
291: /*
292: * pick a channel with a packet to send, and start sending it
293: * first block goes to the device here;
294: * interrupt code will feed it more
295: * adjust ethernet header in first block --
296: * interlan expects no source address
297: */
298: ilsendpkt(is)
299: register struct il *is;
300: {
301: register struct ilchan *cp;
302: register struct block *bp;
303: register int i;
304: register struct etherpup *ep;
305:
306: if (is->flags & CMDACT)
307: return;
308: again:
309: for (i = NEXTCH(is->lastch); ; i = NEXTCH(i)) {
310: cp = &is->chan[i];
311: if (cp->ndelims)
312: break;
313: if (i == is->lastch)
314: return;
315: }
316: is->lastch = i;
317: if ((bp = getq(WR(cp->rq))) == NULL)
318: panic("ilsendpkt");
319: cp->ndelims--;
320: if (bp->wptr - bp->rptr < sizeof(struct etherpup)) {
321: /* should probably try to pull packets together here */
322: printf("ni1010a %d: short header\n", cp->unit);
323: for (; (bp && bp->class&S_DELIM)==0; bp = getq(WR(cp->rq)))
324: freeb(bp);
325: goto again;
326: }
327: ep = (struct etherpup *)(bp->rptr);
328: bcopy(ep->dhost, ep->shost, sizeof(ep->dhost));
329: bp->rptr += sizeof(ep->dhost);
330: cp->xcur = bp;
331: ildebug(bp, 1, 0); /* how can we generate length cheaply? */
332: ilsendblock(is, bp);
333: }
334:
335: /*
336: * command done interrupt
337: * if in init code, just wakeup
338: * if need receive buffers, make one
339: * else finish any pending transmit
340: */
341: il1int(unit)
342: {
343: register struct il *is;
344: register struct ilchan *cp;
345: register int type;
346:
347: is = &il[unit];
348: if (is->addr == NULL) {
349: printf("ni1010a %d: spurious interrupt\n", unit);
350: return;
351: }
352: is->lastcsr = is->addr->il_csr;
353: if ((is->flags & CMDACT) == 0) {
354: printf("ni1010a %d: stray cmd interrupt, csr %x\n", unit, is->lastcsr);
355: return;
356: }
357: is->flags &=~ CMDACT;
358: if (is->flags & INITING) {
359: wakeup((caddr_t)is);
360: return;
361: }
362: if (is->rbytes < ILRBYTES)
363: if (ilrcvbufs(is))
364: return;
365: cp = &is->chan[is->lastch];
366: if (cp->xcur) { /* sending something */
367: type = cp->xcur->class;
368: freeb(cp->xcur);
369: cp->xcur = NULL;
370: if ((type&S_DELIM)==0
371: && (cp->xcur = getq(WR(cp->rq))) != NULL) {
372: ilsendblock(is, cp->xcur);
373: return;
374: }
375: switch (is->lastcsr & IL_STATUS) {
376: case ILERR_RETRIES:
377: is->collisions++;
378: case ILERR_SUCCESS:
379: is->opackets++;
380: break;
381:
382: default:
383: is->oerrors++;
384: printf("ni1010a %d: xmt error 0x%x\n", unit, is->lastcsr&IL_STATUS);
385: break;
386: }
387: }
388: ilsendpkt(is);
389: }
390:
391: /*
392: * feed a block to the controller
393: */
394: ilsendblock(is, bp)
395: struct il *is;
396: register struct block *bp;
397: {
398: register struct ildevice *addr;
399: uaddr_t uad;
400: register int i;
401:
402: addr = is->addr;
403: uad = ubadrptr(is->ubno, bp, ubmblk(is->ubno, bp, 0));
404: addr->il_bar = uad;
405: addr->il_bcr = bp->wptr - bp->rptr;
406: is->flags |= CMDACT;
407: i = ((uad>>2)&IL_EUA)|IL_RIE|IL_CIE;
408: if ((bp->class&S_DELIM)==0) /* not last piece of packet */
409: addr->il_csr = i | ILC_LDXMIT;
410: else
411: addr->il_csr = i | ILC_XMIT;
412: }
413:
414: /*
415: * add receive buffer space if needed
416: * -- let it be an ordinary command, interrupt when complete, for now.
417: * this is probably too slow
418: * returns nonzero if a command was started
419: */
420: ilrcvbufs(is)
421: register struct il *is;
422: {
423: register struct block *bp;
424: register struct ildevice *addr;
425: register int len;
426: register uaddr_t uad;
427:
428: if (is->flags & CMDACT)
429: return (0);
430: if (is->rbytes >= ILRBYTES || is->rbufs >= MAXRBUFS)
431: return (0);
432: if ((bp = allocb(ILRSIZE)) == NULL)
433: return (0);
434: bp->next = NULL;
435: if (is->rfirst == NULL)
436: is->rfirst = bp;
437: else
438: is->rlast->next = bp;
439: is->rlast = bp;
440: len = bp->lim - bp->wptr;
441: /* assume at least eight bytes in bp */
442: len = MKCHAIN(len);
443: is->rbytes += len;
444: bp->wptr = bp->rptr + len;
445: is->rbufs++;
446: *(long *)bp->rptr = 0x80818283; /* debuggery */
447: uad = ubadrptr(is->ubno, bp, ubmblk(is->ubno, bp, 0));
448: is->flags |= CMDACT;
449: addr = is->addr;
450: addr->il_bar = uad;
451: addr->il_bcr = len;
452: addr->il_csr = ((uad>>2)&IL_EUA)|ILC_RCV|IL_RIE|IL_CIE;
453: return (1);
454: }
455:
456: /*
457: * receive done interrupt
458: * -- (is->rfirst, is->rlast) is the set of buffers involved in receiving
459: * is->rnext, if non-empty, points to the next one we expect data in
460: * hence (is->rfirst, is->rnext) is the current incomplete packet
461: * is->rcur is the number of bytes not yet received in the current packet
462: */
463: il0int(unit)
464: int unit;
465: {
466: register struct il *is;
467: register struct block *bp;
468: register struct block *lbp;
469: register struct ilchan *cp;
470: register struct queue *nq;
471: register int i;
472: int proto;
473:
474: is = &il[unit];
475: if (is->addr)
476: is->lastcsr = is->addr->il_csr;
477: if (is->addr == NULL || is->rfirst == NULL) {
478: printf("ni1010a %d: spurious rcv intr csr %x\n", unit, is->lastcsr);
479: return;
480: }
481: if ((lbp = is->rnext) == NULL) {
482: lbp = is->rfirst;
483: lbp->rptr += 2; /* frame status, junk */
484: is->rcur = *lbp->rptr++;
485: is->rcur += *lbp->rptr++ << 8;
486: /* assume header is all in first block */
487: ildebug(lbp, 0, is->rcur - CRCSIZE);
488: }
489: is->rbytes -= lbp->wptr - lbp->base; /* sic -- in case first block */
490: is->rbufs--;
491: ilrcvbufs(is);
492: i = lbp->wptr - lbp->rptr;
493: if (is->rcur < i)
494: i = is->rcur;
495: lbp->wptr = lbp->rptr + i;
496: is->rcur -= i;
497: if (is->rcur > 0) { /* more expected */
498: if ((is->rnext = lbp->next) == NULL)
499: panic("il0int"); /* too draconian */
500: return;
501: }
502: /*
503: * complete packet:
504: * first block is is->rfirst,
505: * last is is->rnext == lbp
506: */
507: lbp->wptr -= CRCSIZE; /* discard boring CRC */
508: lbp->class |= S_DELIM; /* make delimiter */
509: if (lbp->wptr < lbp->rptr) {
510: i = lbp->rptr - lbp->wptr;
511: lbp->rptr = lbp->wptr;
512: for (bp = is->rfirst; bp != lbp; bp = bp->next)
513: if (bp->next == lbp) {
514: bp->wptr -= i; /* and assume it stops here */
515: break;
516: }
517: }
518: bp = is->rfirst; /* first piece of this packet */
519: if (bp->rptr[-4] & (FS_ALIGN|FS_CRC)) { /* [-4] == frame status */
520: is->ierrors++;
521: cp = NULL;
522: } else {
523: is->ipackets++;
524: if (bp->rptr[-4] & FS_LOST)
525: is->ilost++;
526: /* assume the whole ethernet header is in the first block */
527: proto = ((struct etherpup *)(bp->rptr))->type;
528: for (i = 0; i < NILCHAN; i++) {
529: cp = &is->chan[i];
530: if (cp->rq && cp->type == proto)
531: break;
532: }
533: if (i >= NILCHAN)
534: cp = NULL;
535: }
536: lbp = lbp->next; /* one past the end */
537: if (cp == NULL || cp->rq->next->flag & QFULL) {
538: while (is->rfirst != lbp) {
539: bp = is->rfirst;
540: is->rfirst = bp->next;
541: freeb(bp);
542: }
543: } else {
544: nq = cp->rq->next;
545: while (is->rfirst != lbp) {
546: bp = is->rfirst;
547: is->rfirst = bp->next;
548: (*nq->qinfo->putp)(nq, bp);
549: }
550: }
551: is->rnext = NULL;
552: }
553:
554: ilioctl(q, bp)
555: register struct queue *q;
556: register struct block *bp;
557: {
558: register struct ilchan *cp;
559:
560: cp = (struct ilchan *)q->ptr;
561: bp->type = M_IOCACK;
562: switch(stiocom(bp)){
563: case ENIOTYPE:
564: cp->type = *((int *)stiodata(bp));
565: break;
566:
567: case ENIOADDR:
568: bcopy(il[cp->unit].enaddr, stiodata(bp), ETHERALEN);
569: bp->wptr = bp->rptr + ETHERALEN + STIOCHDR;
570: break;
571:
572: default:
573: bp->type = M_IOCNAK;
574: break;
575: }
576: qreply(q, bp);
577: }
578:
579: #define ILLDEBSIZE 64
580: struct ild {
581: time_t time;
582: unsigned short code;
583: struct etherpup pup;
584: short len;
585: } ild[ILLDEBSIZE];
586:
587: int ili = 0;
588:
589: #include "sys/systm.h" /* just for time */
590:
591: ildebug(bp, code, len)
592: struct block *bp;
593: int code, len;
594: {
595: register struct ild *ip;
596:
597: ip = &ild[ili];
598: ip->time = time;
599: ip->code = code;
600: ip->len = len;
601: bcopy(bp->rptr, &ip->pup, sizeof(struct etherpup));
602: if (++ili >= ILLDEBSIZE)
603: ili = 0;
604: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.