1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)if_ex.c 7.1 (Berkeley) 6/5/86 7: */ 8: 9: 10: #include "ex.h" 11: #if NEX > 0 12: 13: /* 14: * Excelan EXOS 204 Interface 15: * 16: * George Powers 17: * Excelan Inc. 18: */ 19: 20: #include "../machine/pte.h" 21: 22: #include "param.h" 23: #include "systm.h" 24: #include "mbuf.h" 25: #include "buf.h" 26: #include "protosw.h" 27: #include "socket.h" 28: #include "vmmac.h" 29: #include "ioctl.h" 30: #include "errno.h" 31: 32: #include "../net/if.h" 33: #include "../net/netisr.h" 34: #include "../net/route.h" 35: 36: #ifdef INET 37: #include "../netinet/in.h" 38: #include "../netinet/in_systm.h" 39: #include "../netinet/in_var.h" 40: #include "../netinet/ip.h" 41: #include "../netinet/if_ether.h" 42: #endif 43: 44: #ifdef NS 45: #include "../netns/ns.h" 46: #include "../netns/ns_if.h" 47: #endif 48: 49: #include "../vax/cpu.h" 50: #include "../vax/mtpr.h" 51: #include "if_exreg.h" 52: #include "if_uba.h" 53: #include "../vaxuba/ubareg.h" 54: #include "../vaxuba/ubavar.h" 55: 56: #define DEBUG /* check for "impossible" events */ 57: 58: #define NH2X 4 /* a sufficient number is critical */ 59: #define NX2H 4 /* this is pretty arbitrary */ 60: #define EXWATCHINTVL 10 /* call exwatch() every 10 seconds */ 61: 62: int exprobe(), exattach(), excdint(); 63: struct uba_device *exinfo[NEX]; 64: u_short exstd[] = { 0 }; 65: struct uba_driver exdriver = 66: { exprobe, 0, exattach, 0, exstd, "ex", exinfo }; 67: int exinit(),exoutput(),exioctl(),exreset(),exwatch(); 68: struct ex_msg *exgetcbuf(); 69: 70: /* 71: * Ethernet software status per interface. 72: * 73: * Each interface is referenced by a network interface structure, 74: * xs_if, which the routing code uses to locate the interface. 75: * This structure contains the output queue for the interface, its address, ... 76: * We also have, for each interface, a UBA interface structure, which 77: * contains information about the UNIBUS resources held by the interface: 78: * map registers, buffered data paths, etc. Information is cached in this 79: * structure for use by the if_uba.c routines in running the interface 80: * efficiently. 81: */ 82: struct ex_softc { 83: struct arpcom xs_ac; /* Ethernet common part */ 84: #define xs_if xs_ac.ac_if /* network-visible interface */ 85: #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */ 86: #ifdef DEBUG 87: int xs_wait; 88: #endif 89: struct ifuba xs_ifuba; /* UNIBUS resources */ 90: int xs_flags; /* private flags */ 91: #define EX_XPENDING 1 /* xmit rqst pending on EXOS */ 92: #define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */ 93: #define EX_RUNNING (1<<2) /* board is running */ 94: #define EX_SETADDR (1<<3) /* physaddr has been changed */ 95: struct ex_msg *xs_h2xnext; /* host pointer to request queue */ 96: struct ex_msg *xs_x2hnext; /* host pointer to reply queue */ 97: int xs_ubaddr; /* map info for structs below */ 98: #define UNIADDR(x) ((u_long)(x)&0x3FFFF) 99: #define P_UNIADDR(x) ((u_long)(x)&0x3FFF0) 100: /* the following structures are always mapped in */ 101: u_short xs_h2xhdr; /* EXOS's request queue header */ 102: u_short xs_x2hhdr; /* EXOS's reply queue header */ 103: struct ex_msg xs_h2xent[NH2X]; /* request msg buffers */ 104: struct ex_msg xs_x2hent[NX2H]; /* reply msg buffers */ 105: struct confmsg xs_cm; /* configuration message */ 106: struct stat_array xs_xsa; /* EXOS writes stats here */ 107: /* end mapped area */ 108: #define INCORE_BASE(p) ((caddr_t)((u_long)(&(p)->xs_h2xhdr) & 0xFFFFFFF0)) 109: #define RVAL_OFF(unit, n) \ 110: ((caddr_t)(&(ex_softc[unit].n)) - INCORE_BASE(&ex_softc[unit])) 111: #define LVAL_OFF(unit, n) \ 112: ((caddr_t)(ex_softc[unit].n) - INCORE_BASE(&ex_softc[unit])) 113: #define H2XHDR_OFFSET(unit) RVAL_OFF(unit, xs_h2xhdr) 114: #define X2HHDR_OFFSET(unit) RVAL_OFF(unit, xs_x2hhdr) 115: #define H2XENT_OFFSET(unit) LVAL_OFF(unit, xs_h2xent) 116: #define X2HENT_OFFSET(unit) LVAL_OFF(unit, xs_x2hent) 117: #define CM_OFFSET(unit) RVAL_OFF(unit, xs_cm) 118: #define SA_OFFSET(unit) RVAL_OFF(unit, xs_xsa) 119: #define INCORE_SIZE(unit) RVAL_OFF(unit, xs_end) 120: int xs_end; /* place holder */ 121: } ex_softc[NEX]; 122: 123: /* 124: * The following structure is a kludge to store a cvec value 125: * between the time exprobe is called, and exconfig. 126: */ 127: struct ex_cvecs { 128: struct exdevice *xc_csraddr; 129: int xc_cvec; 130: }ex_cvecs[NEX]; 131: 132: int ex_ncall = 0; /* counts calls to exprobe */ 133: 134: exprobe(reg) 135: caddr_t reg; 136: { 137: register int br, cvec; /* r11, r10 value-result */ 138: register struct exdevice *addr = (struct exdevice *)reg; 139: register i; 140: 141: /* 142: * We program the EXOS interrupt vector, like dmf device. 143: */ 144: br = 0x15; 145: cvec = (uba_hd[numuba].uh_lastiv -= 4); 146: ex_cvecs[ex_ncall].xc_csraddr = addr; 147: ex_cvecs[ex_ncall].xc_cvec = cvec; 148: /* 149: * Reset EXOS and run self-test (guaranteed to 150: * complete within 2 seconds). 151: */ 152: addr->xd_porta = EX_RESET; 153: i = 2000; 154: while (((addr->xd_portb & EX_TESTOK) == 0) && --i) 155: DELAY(1000); 156: if ((addr->xd_portb & EX_TESTOK) == 0) { 157: printf("ex: self-test failed\n"); 158: return 0; 159: } 160: #ifdef lint 161: br = br; 162: excdint(0); 163: #endif 164: ex_ncall++; 165: return (sizeof(struct exdevice)); 166: } 167: 168: /* 169: * Interface exists: make available by filling in network interface 170: * record. System will initialize the interface when it is ready 171: * to accept packets. Board is temporarily configured and issues 172: * a NET_ADDRS command, only to get the Ethernet address. 173: */ 174: exattach(ui) 175: struct uba_device *ui; 176: { 177: register struct ex_softc *xs = &ex_softc[ui->ui_unit]; 178: register struct ifnet *ifp = &xs->xs_if; 179: register struct exdevice *addr = (struct exdevice *)ui->ui_addr; 180: register struct ex_msg *bp; 181: int unit = ui->ui_unit; 182: ifp->if_unit = ui->ui_unit; 183: ifp->if_name = "ex"; 184: ifp->if_mtu = ETHERMTU; 185: 186: /* 187: * Temporarily map queues in order to configure EXOS 188: */ 189: xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), 190: INCORE_SIZE(unit), 0); 191: exconfig(ui, 0); /* without interrupts */ 192: if (xs->xs_cm.cm_cc) goto badconf; 193: 194: bp = exgetcbuf(xs); 195: bp->mb_rqst = LLNET_ADDRS; 196: bp->mb_na.na_mask = READ_OBJ; 197: bp->mb_na.na_slot = PHYSSLOT; 198: bp->mb_status |= MH_EXOS; 199: addr->xd_portb = EX_NTRUPT; 200: bp = xs->xs_x2hnext; 201: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 202: ; 203: printf("ex%d: HW %c.%c, NX %c.%c, hardware address %s\n", 204: ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3], 205: xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1], 206: ether_sprintf(bp->mb_na.na_addrs)); 207: bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr, 208: sizeof (xs->xs_addr)); 209: 210: ifp->if_init = exinit; 211: ifp->if_output = exoutput; 212: ifp->if_ioctl = exioctl; 213: ifp->if_reset = exreset; 214: ifp->if_flags = IFF_BROADCAST; 215: xs->xs_ifuba.ifu_flags = UBA_CANTWAIT; 216: if_attach(ifp); 217: badconf: 218: ubarelse(ui->ui_ubanum, &xs->xs_ubaddr); 219: } 220: 221: /* 222: * Reset of interface after UNIBUS reset. 223: * If interface is on specified uba, reset its state. 224: */ 225: exreset(unit, uban) 226: int unit, uban; 227: { 228: register struct uba_device *ui; 229: 230: if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0 || 231: ui->ui_ubanum != uban) 232: return; 233: printf(" ex%d", unit); 234: ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING; 235: ex_softc[unit].xs_flags &= ~EX_RUNNING; 236: exinit(unit); 237: } 238: 239: /* 240: * Initialization of interface; clear recorded pending 241: * operations, and reinitialize UNIBUS usage. 242: * Called at boot time (with interrupts disabled?), 243: * and at ifconfig time via exioctl, with interrupts disabled. 244: */ 245: exinit(unit) 246: int unit; 247: { 248: register struct ex_softc *xs = &ex_softc[unit]; 249: register struct uba_device *ui = exinfo[unit]; 250: register struct exdevice *addr = (struct exdevice *)ui->ui_addr; 251: register struct ifnet *ifp = &xs->xs_if; 252: register struct ex_msg *bp; 253: int s; 254: 255: /* not yet, if address still unknown */ 256: if (ifp->if_addrlist == (struct ifaddr *)0) 257: return; 258: if (xs->xs_flags & EX_RUNNING) 259: return; 260: 261: if ((ifp->if_flags & IFF_RUNNING) == 0) { 262: if (if_ubainit(&xs->xs_ifuba, ui->ui_ubanum, 263: sizeof (struct ether_header), 264: (int)btoc(EXMAXRBUF-sizeof(struct ether_header))) == 0) { 265: printf("ex%d: can't initialize\n", unit); 266: xs->xs_if.if_flags &= ~IFF_UP; 267: return; 268: } 269: xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), 270: INCORE_SIZE(unit), 0); 271: } 272: exconfig(ui, 4); /* with vectored interrupts*/ 273: /* 274: * Put EXOS on the Ethernet, using NET_MODE command 275: */ 276: bp = exgetcbuf(xs); 277: bp->mb_rqst = LLNET_MODE; 278: bp->mb_nm.nm_mask = WRITE_OBJ; 279: bp->mb_nm.nm_optn = 0; 280: bp->mb_nm.nm_mode = MODE_PERF; 281: bp->mb_status |= MH_EXOS; 282: addr->xd_portb = EX_NTRUPT; 283: bp = xs->xs_x2hnext; 284: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 285: ; 286: bp->mb_length = MBDATALEN; 287: bp->mb_status |= MH_EXOS; /* free up buffer */ 288: addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */ 289: xs->xs_x2hnext = xs->xs_x2hnext->mb_next; 290: 291: ifp->if_watchdog = exwatch; 292: ifp->if_timer = EXWATCHINTVL; 293: s = splimp(); /* are interrupts always disabled here, anyway? */ 294: exhangrcv(unit); /* hang receive request */ 295: xs->xs_if.if_flags |= IFF_RUNNING; 296: xs->xs_flags |= EX_RUNNING; 297: if (xs->xs_flags & EX_SETADDR) 298: ex_setaddr((u_char *)0, unit); 299: exstart(unit); /* start transmits */ 300: splx(s); 301: } 302: 303: /* 304: * Reset, test, and configure EXOS. This routine assumes 305: * that message queues, etc. have already been mapped into 306: * the UBA. It is called by exinit, and should also be 307: * callable by exattach. 308: */ 309: exconfig(ui, itype) 310: struct uba_device *ui; 311: int itype; 312: { 313: register int unit = ui->ui_unit; 314: register struct ex_softc *xs = &ex_softc[unit]; 315: register struct exdevice *addr = (struct exdevice *) ui->ui_addr; 316: register struct confmsg *cm = &xs->xs_cm; 317: register struct ex_msg *bp; 318: int i; 319: u_long shiftreg; 320: 321: xs->xs_flags = 0; 322: /* 323: * Reset EXOS, wait for self-test to complete 324: */ 325: addr->xd_porta = EX_RESET; 326: while ((addr->xd_portb & EX_TESTOK) == 0) 327: ; 328: /* 329: * Set up configuration message. 330: */ 331: cm->cm_1rsrv = 1; 332: cm->cm_cc = 0xFF; 333: cm->cm_opmode = 0; /* link-level controller mode */ 334: cm->cm_dfo = 0x0101; /* enable host data order conversion */ 335: cm->cm_dcn1 = 1; 336: cm->cm_2rsrv[0] = 337: cm->cm_2rsrv[1] = 0; 338: cm->cm_ham = 3; /* absolute address mode */ 339: cm->cm_3rsrv = 0; 340: cm->cm_mapsiz = 0; 341: cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */ 342: cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */ 343: cm->cm_byteptrn[2] = 0x07; 344: cm->cm_byteptrn[3] = 0x0F; 345: cm->cm_wordptrn[0] = 0x0103; 346: cm->cm_wordptrn[1] = 0x070F; 347: cm->cm_lwordptrn = 0x0103070F; 348: for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0; 349: cm->cm_mba = 0xFFFFFFFF; 350: cm->cm_nproc = 0xFF; 351: cm->cm_nmbox = 0xFF; 352: cm->cm_nmcast = 0xFF; 353: cm->cm_nhost = 1; 354: cm->cm_h2xba = P_UNIADDR(xs->xs_ubaddr); 355: cm->cm_h2xhdr = H2XHDR_OFFSET(unit); 356: cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */ 357: cm->cm_x2hba = cm->cm_h2xba; 358: cm->cm_x2hhdr = X2HHDR_OFFSET(unit); 359: cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */ 360: for (i=0; (addr != ex_cvecs[i].xc_csraddr); i++) 361: #ifdef DEBUG 362: if (i >= NEX) 363: panic("ex: matching csr address not found"); 364: #endif 365: ; 366: cm->cm_x2haddr = ex_cvecs[i].xc_cvec; /* stashed here by exprobe */ 367: /* 368: * Set up message queues and headers. 369: * First the request queue. 370: */ 371: for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) { 372: bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 373: bp->mb_rsrv = 0; 374: bp->mb_length = MBDATALEN; 375: bp->mb_status = MH_HOST; 376: bp->mb_next = bp+1; 377: } 378: xs->xs_h2xhdr = 379: xs->xs_h2xent[NH2X-1].mb_link = 380: (u_short)H2XENT_OFFSET(unit); 381: xs->xs_h2xnext = 382: xs->xs_h2xent[NH2X-1].mb_next = 383: xs->xs_h2xent; 384: 385: /* Now the reply queue. */ 386: for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) { 387: bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); 388: bp->mb_rsrv = 0; 389: bp->mb_length = MBDATALEN; 390: bp->mb_status = MH_EXOS; 391: bp->mb_next = bp+1; 392: } 393: xs->xs_x2hhdr = 394: xs->xs_x2hent[NX2H-1].mb_link = 395: (u_short)X2HENT_OFFSET(unit); 396: xs->xs_x2hnext = 397: xs->xs_x2hent[NX2H-1].mb_next = 398: xs->xs_x2hent; 399: 400: /* 401: * Write config msg address to EXOS and wait for 402: * configuration to complete (guaranteed response 403: * within 2 seconds). 404: */ 405: shiftreg = (u_long)0x0000FFFF; 406: for (i = 0; i < 8; i++) { 407: if (i == 4) 408: shiftreg = P_UNIADDR(xs->xs_ubaddr) + CM_OFFSET(unit); 409: while (addr->xd_portb & EX_UNREADY) 410: ; 411: addr->xd_portb = (u_char)(shiftreg & 0xFF); 412: shiftreg >>= 8; 413: } 414: for (i = 1000000; (cm->cm_cc == 0xFF) && i; --i); 415: if (cm->cm_cc) 416: printf("ex%d: configuration failed; cc = %x\n", 417: unit, cm->cm_cc); 418: } 419: 420: /* 421: * Start or re-start output on interface. 422: * Get another datagram to send off of the interface queue, 423: * and map it to the interface before starting the output. 424: * This routine is called by exinit(), exoutput(), and excdint(). 425: * In all cases, interrupts by EXOS are disabled. 426: */ 427: exstart(unit) 428: int unit; 429: { 430: struct uba_device *ui = exinfo[unit]; 431: register struct ex_softc *xs = &ex_softc[unit]; 432: register struct exdevice *addr = (struct exdevice *)ui->ui_addr; 433: register struct ex_msg *bp; 434: struct mbuf *m; 435: int len; 436: 437: #ifdef DEBUG 438: if (xs->xs_flags & EX_XPENDING) 439: panic("exstart(): xmit still pending"); 440: #endif 441: IF_DEQUEUE(&xs->xs_if.if_snd, m); 442: if (m == 0) 443: return; 444: len = if_wubaput(&xs->xs_ifuba, m); 445: if (len - sizeof(struct ether_header) < ETHERMIN) 446: len = ETHERMIN + sizeof(struct ether_header); 447: /* 448: * Place a transmit request. 449: */ 450: bp = exgetcbuf(xs); 451: bp->mb_rqst = LLRTRANSMIT; 452: bp->mb_et.et_nblock = 1; 453: bp->mb_et.et_blks[0].bb_len = (u_short)len; 454: *(u_long *)bp->mb_et.et_blks[0].bb_addr = 455: UNIADDR(xs->xs_ifuba.ifu_w.ifrw_info); 456: xs->xs_flags |= EX_XPENDING; 457: bp->mb_status |= MH_EXOS; 458: addr->xd_portb = EX_NTRUPT; 459: } 460: 461: /* 462: * Command done interrupt. 463: */ 464: excdint(unit) 465: int unit; 466: { 467: register struct ex_softc *xs = &ex_softc[unit]; 468: register struct ex_msg *bp = xs->xs_x2hnext; 469: struct uba_device *ui = exinfo[unit]; 470: struct exdevice *addr = (struct exdevice *)ui->ui_addr; 471: 472: while ((bp->mb_status & MH_OWNER) == MH_HOST) { 473: switch (bp->mb_rqst) { 474: case LLRECEIVE: 475: exrecv(unit, bp); 476: exhangrcv(unit); 477: break; 478: case LLRTRANSMIT: 479: #ifdef DEBUG 480: if ((xs->xs_flags & EX_XPENDING) == 0) 481: panic("exxmit: no xmit pending"); 482: #endif 483: xs->xs_flags &= ~EX_XPENDING; 484: xs->xs_if.if_opackets++; 485: if (bp->mb_rply == LL_OK) { 486: ; 487: } else if (bp->mb_rply & LLXM_1RTRY) { 488: xs->xs_if.if_collisions++; 489: } else if (bp->mb_rply & LLXM_RTRYS) { 490: xs->xs_if.if_collisions += 2; /* guess */ 491: } else if (bp->mb_rply & LLXM_ERROR) { 492: xs->xs_if.if_oerrors++; 493: printf("ex%d: transmit error=%b\n", 494: unit, bp->mb_rply, XMIT_BITS); 495: } 496: if (xs->xs_ifuba.ifu_xtofree) { 497: m_freem(xs->xs_ifuba.ifu_xtofree); 498: xs->xs_ifuba.ifu_xtofree = 0; 499: } 500: exstart(unit); 501: break; 502: case LLNET_STSTCS: 503: xs->xs_if.if_ierrors = xs->xs_xsa.sa_crc; 504: xs->xs_flags &= ~EX_STATPENDING; 505: break; 506: case LLNET_ADDRS: 507: case LLNET_RECV: 508: break; 509: #ifdef DEBUG 510: default: 511: panic("ex%d: unknown reply"); 512: #endif 513: } /* end of switch */ 514: bp->mb_length = MBDATALEN; 515: bp->mb_status |= MH_EXOS; /* free up buffer */ 516: addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */ 517: bp = xs->xs_x2hnext = xs->xs_x2hnext->mb_next; 518: } 519: } 520: 521: /* 522: * Get a request buffer, fill in standard values, advance pointer. 523: */ 524: struct ex_msg * 525: exgetcbuf(xs) 526: struct ex_softc *xs; 527: { 528: register struct ex_msg *bp = xs->xs_h2xnext; 529: 530: #ifdef DEBUG 531: if ((bp->mb_status & MH_OWNER) == MH_EXOS) 532: panic("exgetcbuf(): EXOS owns message buffer"); 533: #endif 534: bp->mb_1rsrv = 0; 535: bp->mb_length = MBDATALEN; 536: xs->xs_h2xnext = xs->xs_h2xnext->mb_next; 537: return bp; 538: } 539: 540: /* 541: * Process Ethernet receive completion: 542: * If input error just drop packet. 543: * Otherwise purge input buffered data path and examine 544: * packet to determine type. If can't determine length 545: * from type, then have to drop packet. Otherwise decapsulate 546: * packet based on type and pass to type-specific higher-level 547: * input routine. 548: */ 549: exrecv(unit, bp) 550: int unit; 551: register struct ex_msg *bp; 552: { 553: register struct ex_softc *xs = &ex_softc[unit]; 554: register struct ether_header *eh; 555: struct mbuf *m; 556: register int len, off, resid; 557: register struct ifqueue *inq; 558: 559: xs->xs_if.if_ipackets++; 560: len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4; 561: if (bp->mb_rply != LL_OK) { 562: xs->xs_if.if_ierrors++; 563: printf("ex%d: receive error=%b\n", 564: unit, bp->mb_rply, RECV_BITS); 565: return; 566: } 567: eh = (struct ether_header *)(xs->xs_ifuba.ifu_r.ifrw_addr); 568: 569: /* 570: * Deal with trailer protocol: if type is trailer 571: * get true type from first 16-bit word past data. 572: * Remember that type was trailer by setting off. 573: */ 574: eh->ether_type = ntohs((u_short)eh->ether_type); 575: #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) 576: if (eh->ether_type >= ETHERTYPE_TRAIL && 577: eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 578: off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 579: if (off >= ETHERMTU) 580: return; /* sanity */ 581: eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *)); 582: resid = ntohs(*(exdataaddr(eh, off+2, u_short *))); 583: if (off + resid > len) 584: return; /* sanity */ 585: len = off + resid; 586: } else 587: off = 0; 588: if (len == 0) 589: return; 590: 591: /* 592: * Pull packet off interface. Off is nonzero if packet 593: * has trailing header; if_rubaget will then force this header 594: * information to be at the front, but we still have to drop 595: * the type and length which are at the front of any trailer data. 596: */ 597: m = if_rubaget(&xs->xs_ifuba, len, off, &xs->xs_if); 598: if (m == 0) 599: return; 600: if (off) { 601: struct ifnet *ifp; 602: 603: ifp = *(mtod(m, struct ifnet **)); 604: m->m_off += 2 * sizeof (u_short); 605: m->m_len -= 2 * sizeof (u_short); 606: *(mtod(m, struct ifnet **)) = ifp; 607: } 608: switch (eh->ether_type) { 609: 610: #ifdef INET 611: case ETHERTYPE_IP: 612: schednetisr(NETISR_IP); /* is this necessary */ 613: inq = &ipintrq; 614: break; 615: 616: case ETHERTYPE_ARP: 617: arpinput(&xs->xs_ac, m); 618: return; 619: #endif 620: #ifdef NS 621: case ETHERTYPE_NS: 622: schednetisr(NETISR_NS); 623: inq = &nsintrq; 624: break; 625: 626: #endif 627: default: 628: m_freem(m); 629: return; 630: } 631: 632: if (IF_QFULL(inq)) { 633: IF_DROP(inq); 634: m_freem(m); 635: return; 636: } 637: IF_ENQUEUE(inq, m); 638: } 639: 640: /* 641: * Send receive request to EXOS. 642: * This routine is called by exinit and excdint, 643: * with interrupts disabled in both cases. 644: */ 645: exhangrcv(unit) 646: int unit; 647: { 648: register struct ex_softc *xs = &ex_softc[unit]; 649: register struct ex_msg *bp = exgetcbuf(xs); 650: struct exdevice *addr = (struct exdevice *)exinfo[unit]->ui_addr; 651: 652: bp->mb_rqst = LLRECEIVE; 653: bp->mb_er.er_nblock = 1; 654: bp->mb_er.er_blks[0].bb_len = EXMAXRBUF; 655: *(u_long *)bp->mb_er.er_blks[0].bb_addr = 656: UNIADDR(xs->xs_ifuba.ifu_r.ifrw_info); 657: bp->mb_status |= MH_EXOS; 658: addr->xd_portb = EX_NTRUPT; 659: } 660: 661: /* 662: * Ethernet output routine. 663: * Encapsulate a packet of type family for the local net. 664: * Use trailer local net encapsulation if enough data in first 665: * packet leaves a multiple of 512 bytes of data in remainder. 666: */ 667: exoutput(ifp, m0, dst) 668: register struct ifnet *ifp; 669: register struct mbuf *m0; 670: struct sockaddr *dst; 671: { 672: int type, s, error; 673: u_char edst[6]; 674: struct in_addr idst; 675: register struct ex_softc *xs = &ex_softc[ifp->if_unit]; 676: register struct mbuf *m = m0; 677: register struct ether_header *eh; 678: register int off; 679: int usetrailers; 680: 681: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 682: error = ENETDOWN; 683: goto bad; 684: } 685: switch (dst->sa_family) { 686: 687: #ifdef INET 688: case AF_INET: 689: idst = ((struct sockaddr_in *)dst)->sin_addr; 690: if (!arpresolve(&xs->xs_ac, m, &idst, edst, &usetrailers)) 691: return (0); /* if not yet resolved */ 692: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 693: if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 694: m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 695: type = ETHERTYPE_TRAIL + (off>>9); 696: m->m_off -= 2 * sizeof (u_short); 697: m->m_len += 2 * sizeof (u_short); 698: *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 699: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 700: goto gottrailertype; 701: } 702: type = ETHERTYPE_IP; 703: off = 0; 704: goto gottype; 705: #endif 706: #ifdef NS 707: case AF_NS: 708: type = ETHERTYPE_NS; 709: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 710: (caddr_t)edst, sizeof (edst)); 711: off = 0; 712: goto gottype; 713: #endif 714: 715: case AF_UNSPEC: 716: eh = (struct ether_header *)dst->sa_data; 717: bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); 718: type = eh->ether_type; 719: goto gottype; 720: 721: default: 722: printf("ex%d: can't handle af%d\n", ifp->if_unit, 723: dst->sa_family); 724: error = EAFNOSUPPORT; 725: goto bad; 726: } 727: 728: gottrailertype: 729: /* 730: * Packet to be sent as trailer: move first packet 731: * (control information) to end of chain. 732: */ 733: while (m->m_next) 734: m = m->m_next; 735: m->m_next = m0; 736: m = m0->m_next; 737: m0->m_next = 0; 738: m0 = m; 739: 740: gottype: 741: /* 742: * Add local net header. If no space in first mbuf, 743: * allocate another. 744: */ 745: if (m->m_off > MMAXOFF || 746: MMINOFF + sizeof (struct ether_header) > m->m_off) { 747: m = m_get(M_DONTWAIT, MT_HEADER); 748: if (m == 0) { 749: error = ENOBUFS; 750: goto bad; 751: } 752: m->m_next = m0; 753: m->m_off = MMINOFF; 754: m->m_len = sizeof (struct ether_header); 755: } else { 756: m->m_off -= sizeof (struct ether_header); 757: m->m_len += sizeof (struct ether_header); 758: } 759: eh = mtod(m, struct ether_header *); 760: eh->ether_type = htons((u_short)type); 761: bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); 762: bcopy((caddr_t)xs->xs_addr, (caddr_t)eh->ether_shost, 6); 763: 764: /* 765: * Queue message on interface, and start output if interface 766: * not yet active. 767: */ 768: s = splimp(); 769: if (IF_QFULL(&ifp->if_snd)) { 770: IF_DROP(&ifp->if_snd); 771: splx(s); 772: m_freem(m); 773: return (ENOBUFS); 774: } 775: IF_ENQUEUE(&ifp->if_snd, m); 776: /* 777: * If transmit request not already pending, then 778: * kick the back end. 779: */ 780: if ((xs->xs_flags & EX_XPENDING) == 0) { 781: exstart(ifp->if_unit); 782: } 783: #ifdef DEBUG 784: else { 785: xs->xs_wait++; 786: } 787: #endif 788: splx(s); 789: return (0); 790: 791: bad: 792: m_freem(m0); 793: return (error); 794: } 795: 796: /* 797: * Watchdog routine - place stats request to EXOS 798: * (This could be dispensed with, if you don't care 799: * about the if_ierrors count, or are willing to receive 800: * bad packets in order to derive it.) 801: */ 802: exwatch(unit) 803: int unit; 804: { 805: struct uba_device *ui = exinfo[unit]; 806: struct exdevice *addr = (struct exdevice *)ui->ui_addr; 807: register struct ex_softc *xs = &ex_softc[unit]; 808: register struct ex_msg *bp; 809: int s = splimp(); 810: 811: if (xs->xs_flags & EX_STATPENDING) goto exspnd; 812: bp = exgetcbuf(xs); 813: xs->xs_flags |= EX_STATPENDING; 814: bp->mb_rqst = LLNET_STSTCS; 815: bp->mb_ns.ns_mask = READ_OBJ; 816: bp->mb_ns.ns_rsrv = 0; 817: bp->mb_ns.ns_nobj = 8; /* read all 8 stats objects */ 818: bp->mb_ns.ns_xobj = 0; /* starting with the 1st one */ 819: bp->mb_ns.ns_bufp = P_UNIADDR(xs->xs_ubaddr) + SA_OFFSET(unit); 820: bp->mb_status |= MH_EXOS; 821: addr->xd_portb = EX_NTRUPT; 822: exspnd: 823: splx(s); 824: xs->xs_if.if_timer = EXWATCHINTVL; 825: } 826: 827: /* 828: * Process an ioctl request. 829: */ 830: exioctl(ifp, cmd, data) 831: register struct ifnet *ifp; 832: int cmd; 833: caddr_t data; 834: { 835: register struct ifaddr *ifa = (struct ifaddr *)data; 836: register struct ex_softc *xs = &ex_softc[ifp->if_unit]; 837: int s = splimp(), error = 0; 838: 839: switch (cmd) { 840: 841: case SIOCSIFADDR: 842: ifp->if_flags |= IFF_UP; 843: exinit(ifp->if_unit); 844: 845: switch (ifa->ifa_addr.sa_family) { 846: #ifdef INET 847: case AF_INET: 848: ((struct arpcom *)ifp)->ac_ipaddr = 849: IA_SIN(ifa)->sin_addr; 850: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 851: break; 852: #endif 853: #ifdef NS 854: case AF_NS: 855: { 856: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 857: 858: if (ns_nullhost(*ina)) 859: ina->x_host = *(union ns_host *)(xs->xs_addr); 860: else 861: ex_setaddr(ina->x_host.c_host,ifp->if_unit); 862: break; 863: } 864: #endif 865: } 866: break; 867: 868: case SIOCSIFFLAGS: 869: if ((ifp->if_flags & IFF_UP) == 0 && 870: xs->xs_flags & EX_RUNNING) { 871: ((struct exdevice *) 872: (exinfo[ifp->if_unit]->ui_addr))->xd_porta = EX_RESET; 873: xs->xs_flags &= ~EX_RUNNING; 874: } else if (ifp->if_flags & IFF_UP && 875: (xs->xs_flags & EX_RUNNING) == 0) 876: exinit(ifp->if_unit); 877: break; 878: 879: default: 880: error = EINVAL; 881: } 882: splx(s); 883: return (error); 884: } 885: 886: /* 887: * set ethernet address for unit 888: */ 889: ex_setaddr(physaddr, unit) 890: u_char *physaddr; 891: int unit; 892: { 893: register struct ex_softc *xs = &ex_softc[unit]; 894: struct uba_device *ui = exinfo[unit]; 895: register struct exdevice *addr= (struct exdevice *)ui->ui_addr; 896: register struct ex_msg *bp; 897: 898: if (physaddr) { 899: xs->xs_flags |= EX_SETADDR; 900: bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6); 901: } 902: if (! (xs->xs_flags & EX_RUNNING)) 903: return; 904: bp = exgetcbuf(xs); 905: bp->mb_rqst = LLNET_ADDRS; 906: bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ; 907: bp->mb_na.na_slot = PHYSSLOT; 908: bcopy((caddr_t)xs->xs_addr, (caddr_t)bp->mb_na.na_addrs, 6); 909: bp->mb_status |= MH_EXOS; 910: addr->xd_portb = EX_NTRUPT; 911: bp = xs->xs_x2hnext; 912: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 913: ; 914: #ifdef DEBUG 915: printf("ex%d: reset addr %s\n", ui->ui_unit, 916: ether_sprintf(bp->mb_na.na_addrs)); 917: #endif 918: /* 919: * Now, re-enable reception on phys slot. 920: */ 921: bp = exgetcbuf(xs); 922: bp->mb_rqst = LLNET_RECV; 923: bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ; 924: bp->mb_nr.nr_slot = PHYSSLOT; 925: bp->mb_status |= MH_EXOS; 926: addr->xd_portb = EX_NTRUPT; 927: bp = xs->xs_x2hnext; 928: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ 929: ; 930: } 931: #endif