|
|
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.