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