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