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