|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1989 The 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.5 (Berkeley) 12/16/90 ! 37: */ ! 38: ! 39: #include "ex.h" ! 40: ! 41: #if NEX > 0 ! 42: ! 43: /* ! 44: * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers ! 45: */ ! 46: #include "sys/param.h" ! 47: #include "sys/systm.h" ! 48: #include "sys/mbuf.h" ! 49: #include "sys/buf.h" ! 50: #include "sys/protosw.h" ! 51: #include "sys/socket.h" ! 52: #include "sys/vmmac.h" ! 53: #include "sys/ioctl.h" ! 54: #include "sys/errno.h" ! 55: #include "sys/vmparam.h" ! 56: #include "sys/syslog.h" ! 57: #include "sys/uio.h" ! 58: ! 59: #include "net/if.h" ! 60: #include "net/netisr.h" ! 61: #include "net/route.h" ! 62: ! 63: #ifdef INET ! 64: #include "netinet/in.h" ! 65: #include "netinet/in_systm.h" ! 66: #include "netinet/in_var.h" ! 67: #include "netinet/ip.h" ! 68: #include "netinet/if_ether.h" ! 69: #endif ! 70: ! 71: #ifdef NS ! 72: #include "netns/ns.h" ! 73: #include "netns/ns_if.h" ! 74: #endif ! 75: ! 76: #ifdef ISO ! 77: #include "netiso/iso.h" ! 78: #include "netiso/iso_var.h" ! 79: extern char all_es_snpa[], all_is_snpa[]; ! 80: #endif ! 81: ! 82: #include "../include/cpu.h" ! 83: #include "../include/pte.h" ! 84: #include "../include/mtpr.h" ! 85: ! 86: #include "../vba/vbavar.h" ! 87: #include "if_exreg.h" ! 88: #include "if_vba.h" ! 89: ! 90: ! 91: #define NH2X 32 /* Host to eXcelan request buffers */ ! 92: ! 93: #define NX2H 16 /* eXcelan to Host reply buffers */ ! 94: #define NREC 16 /* Number of RECeive buffers */ ! 95: #define NTRB 4 /* Number of TRansmit Buffers */ ! 96: #define NVBI (NREC + NTRB) ! 97: ! 98: #define EXWATCHINTVL 10 /* call exwatch every x secs */ ! 99: ! 100: int exprobe(), exslave(), exattach(), exintr(), exstart(); ! 101: struct vba_device *exinfo[NEX]; ! 102: ! 103: long exstd[] = { 0 }; ! 104: ! 105: ! 106: struct vba_driver exdriver = ! 107: { exprobe, 0, exattach, exstart, exstd, "ex", exinfo }; ! 108: int exinit(),ether_output(),exioctl(),exreset(),exwatch(); ! 109: struct ex_msg *exgetcbuf(); ! 110: int ex_ncall = 0; /* counts calls to exprobe */ ! 111: u_long busoff; ! 112: ! 113: /* ! 114: * Ethernet software status per interface. ! 115: * ! 116: * Each interface is referenced by a network interface structure, xs_if, which ! 117: * the routing code uses to locate the interface. This structure contains the ! 118: * output queue for the interface, its address, ... NOTE: To configure multiple ! 119: * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr). ! 120: */ ! 121: struct ex_softc { ! 122: struct arpcom xs_ac; /* Ethernet common part */ ! 123: #define xs_if xs_ac.ac_if /* network-visible interface */ ! 124: #define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */ ! 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: int xs_cvec; /* probe stores cvec here */ ! 131: short xs_enetunit; /* unit number for enet filtering */ ! 132: short xs_enetinit; /* enet inetrface is initialized */ ! 133: struct ex_msg *xs_h2xnext; /* host pointer to request queue */ ! 134: struct ex_msg *xs_x2hnext; /* host pointer to reply queue */ ! 135: u_long xs_qbaddr; /* map info for structs below */ ! 136: struct ex_shm { ! 137: /* the following structures are always mapped in */ ! 138: u_short sm_h2xhdr; /* EXOS's request queue header */ ! 139: u_short sm_x2hhdr; /* EXOS's reply queue header */ ! 140: struct ex_msg sm_h2xent[NH2X];/* request msg buffers */ ! 141: struct ex_msg sm_x2hent[NX2H];/* reply msg buffers */ ! 142: struct ex_conf sm_cm; /* configuration message */ ! 143: struct ex_stat sm_xsa; /* EXOS writes stats here */ ! 144: /* end mapped area */ ! 145: } *xs_shm; /* host pointer to shared area */ ! 146: #define xs_h2xhdr xs_shm->sm_h2xhdr ! 147: #define xs_x2hhdr xs_shm->sm_x2hhdr ! 148: #define xs_h2xent xs_shm->sm_h2xent ! 149: #define xs_x2hent xs_shm->sm_x2hent ! 150: #define xs_cm xs_shm->sm_cm ! 151: #define xs_xsa xs_shm->sm_xsa ! 152: #define BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFFF)) ! 153: #define P_BUSADDR(x) (0x3D000000 | (((u_long)kvtophys(x))&0xFFFFF0)) ! 154: #define INCORE_BASE(p) (((u_long)(p)->xs_shm) & 0xFFFFFFF0) ! 155: /* we will arrange that the shared memory begins on a 16 byte boundary */ ! 156: #define RVAL_OFF(n) (((char *)&(((struct ex_shm *)0)->n))-(char *)0) ! 157: #define LVAL_OFF(n) (((char *)(((struct ex_shm *)0)->n))-(char *)0) ! 158: #define H2XHDR_OFFSET RVAL_OFF(sm_h2xhdr) ! 159: #define X2HHDR_OFFSET RVAL_OFF(sm_x2hhdr) ! 160: #define H2XENT_OFFSET LVAL_OFF(sm_h2xent) ! 161: #define X2HENT_OFFSET LVAL_OFF(sm_x2hent) ! 162: #define CM_OFFSET RVAL_OFF(sm_cm) ! 163: #define SA_OFFSET RVAL_OFF(sm_xsa) ! 164: struct ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */ ! 165: struct ifvba *xs_pkblist; /* free list of above */ ! 166: #define GetPkBuf(b, v) ((v = (b)->mb_pkb = xs->xs_pkblist),\ ! 167: (xs->xs_pkblist = (struct ifvba *)(v)->iff_mbuf)) ! 168: #define FreePkBuf(v) (((v)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\ ! 169: (xs->xs_pkblist = v)) ! 170: char xs_nrec; /* number of pending receive buffers */ ! 171: char xs_ntrb; /* number of pending transmit buffers */ ! 172: } ex_softc[NEX]; ! 173: ! 174: int ex_padcheck = sizeof (struct ex_softc); ! 175: ! 176: exprobe(reg, vi) ! 177: caddr_t reg; ! 178: struct vba_device *vi; ! 179: { ! 180: register br, cvec; /* r12, r11 value-result */ ! 181: register struct exdevice *exaddr = (struct exdevice *)reg; ! 182: int i; ! 183: ! 184: if (badaddr((caddr_t)exaddr, 2)) ! 185: return 0; ! 186: /* ! 187: * Reset EXOS and run self-test (should complete within 2 seconds). ! 188: */ ! 189: movow(&exaddr->ex_porta, EX_RESET); ! 190: for (i = 1000000; i; i--) { ! 191: uncache(&(exaddr->ex_portb)); ! 192: if (exaddr->ex_portb & EX_TESTOK) ! 193: break; ! 194: } ! 195: if ((exaddr->ex_portb & EX_TESTOK) == 0) ! 196: return 0; ! 197: br = 0x15; ! 198: cvec = --vi->ui_hd->vh_lastiv; ! 199: ex_softc[vi->ui_unit].xs_cvec = cvec; ! 200: ex_ncall++; ! 201: return (sizeof(struct exdevice)); ! 202: } ! 203: ! 204: /* ! 205: * Interface exists: make available by filling in network interface record. ! 206: * System will initialize the interface when it is ready to accept packets. ! 207: * A NET_ADDRS command is done to get the ethernet address. ! 208: */ ! 209: exattach(ui) ! 210: register struct vba_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 *exaddr = (struct exdevice *)ui->ui_addr; ! 215: register struct ex_msg *bp; ! 216: ! 217: ifp->if_unit = ui->ui_unit; ! 218: ifp->if_name = "ex"; ! 219: ifp->if_mtu = ETHERMTU; ! 220: ifp->if_init = exinit; ! 221: ifp->if_ioctl = exioctl; ! 222: ifp->if_output = ether_output; ! 223: ifp->if_reset = exreset; ! 224: ifp->if_start = exstart; ! 225: ifp->if_flags = IFF_BROADCAST; ! 226: ! 227: /* ! 228: * Note: extra memory gets returned by if_vbareserve() ! 229: * first, so, being page alligned, it is also 16-byte alligned. ! 230: */ ! 231: if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF, ! 232: (caddr_t *)&xs->xs_shm, sizeof(*xs->xs_shm)) == 0) ! 233: return; ! 234: /* ! 235: * Temporarily map queues in order to configure EXOS ! 236: */ ! 237: xs->xs_qbaddr = INCORE_BASE(xs); ! 238: exconfig(ui, 0); /* without interrupts */ ! 239: if (xs->xs_cm.cm_cc) ! 240: return; /* bad conf */ ! 241: /* ! 242: * Get Ethernet address. ! 243: */ ! 244: if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0) ! 245: panic("exattach"); ! 246: bp->mb_na.na_mask = READ_OBJ; ! 247: bp->mb_na.na_slot = PHYSSLOT; ! 248: bp->mb_status |= MH_EXOS; ! 249: movow(&exaddr->ex_portb, EX_NTRUPT); ! 250: bp = xs->xs_x2hnext; ! 251: while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ ! 252: printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n", ! 253: ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3], ! 254: xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1], ! 255: ether_sprintf(bp->mb_na.na_addrs)); ! 256: bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr, ! 257: sizeof(xs->xs_addr)); ! 258: if_attach(ifp); ! 259: } ! 260: ! 261: /* ! 262: * Reset of interface after BUS reset. ! 263: * If interface is on specified vba, reset its state. ! 264: */ ! 265: exreset(unit) ! 266: int unit; ! 267: { ! 268: register struct vba_device *ui; ! 269: ! 270: if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0) ! 271: return; ! 272: printf(" ex%d", unit); ! 273: ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING; ! 274: ex_softc[unit].xs_flags &= ~EX_RUNNING; ! 275: ! 276: exinit(unit); ! 277: } ! 278: ! 279: /* ! 280: * Initialization of interface; clear recorded pending operations, and ! 281: * reinitialize BUS usage. Called at boot time, and at ifconfig time via ! 282: * exioctl, with interrupts disabled. ! 283: */ ! 284: exinit(unit) ! 285: int unit; ! 286: { ! 287: register struct ex_softc *xs = &ex_softc[unit]; ! 288: register struct vba_device *ui = exinfo[unit]; ! 289: register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; ! 290: register struct ifnet *ifp = &xs->xs_if; ! 291: register struct sockaddr_in *sin; ! 292: register struct ex_msg *bp; ! 293: int s; ! 294: ! 295: /* not yet, if address still unknown */ ! 296: if (ifp->if_addrlist == (struct ifaddr *)0) ! 297: return; ! 298: if (xs->xs_flags & EX_RUNNING) ! 299: return; ! 300: ! 301: xs->xs_qbaddr = INCORE_BASE(xs); ! 302: exconfig(ui, 4); /* with vectored interrupts*/ ! 303: ! 304: /* ! 305: * Put EXOS on the Ethernet, using NET_MODE command ! 306: */ ! 307: if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0) ! 308: panic("exinit"); ! 309: bp->mb_nm.nm_mask = WRITE_OBJ; ! 310: bp->mb_nm.nm_optn = 0; ! 311: bp->mb_nm.nm_mode = MODE_PERF; ! 312: bp->mb_status |= MH_EXOS; ! 313: movow(&exaddr->ex_portb, EX_NTRUPT); ! 314: bp = xs->xs_x2hnext; ! 315: while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */ ! 316: ; ! 317: bp->mb_length = MBDATALEN; ! 318: bp->mb_status |= MH_EXOS; /* free up buffer */ ! 319: movow(&exaddr->ex_portb, EX_NTRUPT); ! 320: xs->xs_x2hnext = xs->xs_x2hnext->mb_next; ! 321: ! 322: ifp->if_watchdog = exwatch; ! 323: ifp->if_timer = EXWATCHINTVL; ! 324: s = splimp(); /* are interrupts disabled here, anyway? */ ! 325: exhangrcv(unit); ! 326: xs->xs_if.if_flags |= IFF_RUNNING; ! 327: xs->xs_flags |= EX_RUNNING; ! 328: if (xs->xs_flags & EX_SETADDR) ! 329: ex_setaddr((u_char *)0, unit); ! 330: #ifdef ISO ! 331: ex_setmulti(all_es_snpa, unit, 1); ! 332: ex_setmulti(all_is_snpa, unit, 2); ! 333: #endif ! 334: exstart(&ex_softc[unit].xs_if); /* start transmits */ ! 335: splx(s); /* are interrupts disabled here, anyway? */ ! 336: } ! 337: ! 338: /* ! 339: * Reset, test, and configure EXOS. It is called by exinit, and exattach. ! 340: * Returns 0 if successful, 1 if self-test failed. ! 341: */ ! 342: exconfig(ui, itype) ! 343: struct vba_device *ui; ! 344: int itype; ! 345: { ! 346: register int unit = ui->ui_unit; ! 347: register struct ex_softc *xs = &ex_softc[unit]; ! 348: register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr; ! 349: register struct ex_conf *cm = &xs->xs_cm; ! 350: register struct ex_msg *bp; ! 351: register struct ifvba *pkb; ! 352: int i; ! 353: u_long shiftreg; ! 354: static u_char cmaddr[8] = {0xFF, 0xFF, 0, 0}; ! 355: ! 356: xs->xs_flags = 0; ! 357: /* ! 358: * Reset EXOS, wait for self-test to complete ! 359: */ ! 360: movow(&exaddr->ex_porta, EX_RESET); ! 361: do { ! 362: uncache(&exaddr->ex_portb); ! 363: } while ((exaddr->ex_portb & EX_TESTOK) == 0) ; ! 364: /* ! 365: * Set up configuration message. ! 366: */ ! 367: cm->cm_1rsrv = 1; ! 368: cm->cm_cc = 0xFF; ! 369: cm->cm_opmode = 0; /* link-level controller mode */ ! 370: cm->cm_dfo = 0x0101; /* enable host data order conversion */ ! 371: cm->cm_dcn1 = 1; ! 372: cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0; ! 373: cm->cm_ham = 3; /* absolute address mode */ ! 374: cm->cm_3rsrv = 0; ! 375: cm->cm_mapsiz = 0; ! 376: cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */ ! 377: cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */ ! 378: cm->cm_byteptrn[2] = 0x07; ! 379: cm->cm_byteptrn[3] = 0x0F; ! 380: cm->cm_wordptrn[0] = 0x0103; ! 381: cm->cm_wordptrn[1] = 0x070F; ! 382: cm->cm_lwordptrn = 0x0103070F; ! 383: for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0; ! 384: cm->cm_mba = 0xFFFFFFFF; ! 385: cm->cm_nproc = 0xFF; ! 386: cm->cm_nmbox = 0xFF; ! 387: cm->cm_nmcast = 0xFF; ! 388: cm->cm_nhost = 1; ! 389: cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr); ! 390: cm->cm_h2xhdr = H2XHDR_OFFSET; ! 391: cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */ ! 392: cm->cm_x2hba = cm->cm_h2xba; ! 393: cm->cm_x2hhdr = X2HHDR_OFFSET; ! 394: cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */ ! 395: cm->cm_x2haddr = xs->xs_cvec; /* ivec allocated in exprobe */ ! 396: /* ! 397: * Set up message queues and headers. ! 398: * First the request queue ! 399: */ ! 400: for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) { ! 401: bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); ! 402: bp->mb_rsrv = 0; ! 403: bp->mb_length = MBDATALEN; ! 404: bp->mb_status = MH_HOST; ! 405: bp->mb_next = bp+1; ! 406: } ! 407: xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET; ! 408: xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent; ! 409: ! 410: /* Now the reply queue. */ ! 411: for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) { ! 412: bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs)); ! 413: bp->mb_rsrv = 0; ! 414: bp->mb_length = MBDATALEN; ! 415: bp->mb_status = MH_EXOS; ! 416: bp->mb_next = bp+1; ! 417: } ! 418: xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET; ! 419: xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent; ! 420: xs->xs_nrec = 0; ! 421: xs->xs_ntrb = 0; ! 422: xs->xs_pkblist = xs->xs_vbinfo + NVBI - 1; ! 423: for (pkb = xs->xs_pkblist; pkb > xs->xs_vbinfo; pkb--) ! 424: pkb->iff_mbuf = (struct mbuf *)(pkb - 1); ! 425: xs->xs_vbinfo[0].iff_mbuf = 0; ! 426: ! 427: /* ! 428: * Write config msg address to EXOS and wait for configuration to ! 429: * complete (guaranteed response within 2 seconds). ! 430: */ ! 431: shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET; ! 432: for (i = 4; i < 8; i++) { ! 433: cmaddr[i] = (u_char)(shiftreg & 0xFF); ! 434: shiftreg >>= 8; ! 435: } ! 436: for (i = 0; i < 8; i++) { ! 437: do { ! 438: uncache(&exaddr->ex_portb); ! 439: } while (exaddr->ex_portb & EX_UNREADY) ; ! 440: DELAY(500); ! 441: movow(&exaddr->ex_portb, cmaddr[i]); ! 442: } ! 443: for (i = 500000; i; --i) { ! 444: DELAY(10); ! 445: uncache(&cm->cm_cc); ! 446: if (cm->cm_cc != 0xFF) ! 447: break; ! 448: } ! 449: if (cm->cm_cc) ! 450: printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc); ! 451: } ! 452: ! 453: /* ! 454: * Start or re-start output on interface. Get another datagram to send off of ! 455: * the interface queue, and map it to the interface before starting the output. ! 456: * This routine is called by exinit(), exoutput(), and excdint(). In all cases, ! 457: * interrupts by EXOS are disabled. ! 458: */ ! 459: exstart(ifp) ! 460: struct ifnet *ifp; ! 461: { ! 462: int unit = ifp->if_unit; ! 463: struct vba_device *ui = exinfo[unit]; ! 464: register struct ex_softc *xs = &ex_softc[unit]; ! 465: struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; ! 466: register struct ex_msg *bp; ! 467: register struct mbuf *m; ! 468: int len; ! 469: register struct ifvba *pkb; ! 470: struct mbuf *m0 = 0; ! 471: register int nb = 0, tlen = 0; ! 472: union l_util { ! 473: u_long l; ! 474: struct i86_long i; ! 475: } l_util; ! 476: ! 477: if (xs->xs_ntrb >= NTRB) ! 478: return; ! 479: if (xs->xs_pkblist == 0) { ! 480: printf("ex%d: vbinfo exhausted, would panic", unit); ! 481: return; ! 482: } ! 483: IF_DEQUEUE(&xs->xs_if.if_snd, m); ! 484: if (m == 0) ! 485: return; ! 486: /* ! 487: * Get a transmit request. ! 488: */ ! 489: if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) { ! 490: m_freem(m); ! 491: printf("exstart: no command buffers\n"); ! 492: return; ! 493: } ! 494: xs->xs_ntrb++; ! 495: GetPkBuf(bp, pkb); ! 496: pkb->iff_mbuf = m; /* save mbuf pointer to free when done */ ! 497: /* ! 498: * point directly to the first group of mbufs to be transmitted. The ! 499: * hardware can only support NFRAGMENTS descriptors. ! 500: */ ! 501: while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) { ! 502: l_util.l = BUSADDR(mtod(m, caddr_t)); ! 503: bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len; ! 504: bp->mb_et.et_blks[nb].bb_addr = l_util.i; ! 505: if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { ! 506: /* Here, the phys memory for the mbuf is out ! 507: of range for the vmebus to talk to it */ ! 508: if (m == pkb->iff_mbuf) ! 509: pkb->iff_mbuf = 0; ! 510: break; ! 511: } ! 512: tlen += m->m_len; ! 513: m0 = m; ! 514: m = m->m_next; ! 515: nb++; ! 516: } ! 517: ! 518: /* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */ ! 519: if (m0) ! 520: m0->m_next = 0; ! 521: ! 522: /* ! 523: * if not all of the descriptors would fit then merge remaining data ! 524: * into the transmit buffer, and point to it. Note: the mbufs are freed ! 525: * during the merge, they do not have to be freed when we get the ! 526: * transmit interrupt. ! 527: */ ! 528: if (m) { ! 529: if (m == pkb->iff_mbuf) { ! 530: printf("ex%d: exstart insanity\n", unit); ! 531: pkb->iff_mbuf = 0; ! 532: } ! 533: len = if_vbaput(pkb->iff_buffer, m, 0); ! 534: l_util.l = BUSADDR(pkb->iff_buffer); ! 535: bp->mb_et.et_blks[nb].bb_len = (u_short)len; ! 536: bp->mb_et.et_blks[nb].bb_addr = l_util.i; ! 537: tlen += len; ! 538: nb++; ! 539: } ! 540: ! 541: /* ! 542: * If the total length of the packet is too small, ! 543: * pad the last fragment. (May run into very obscure problems) ! 544: */ ! 545: if (tlen < sizeof(struct ether_header) + ETHERMIN) { ! 546: len = (ETHERMIN + sizeof(struct ether_header)) - tlen; ! 547: bp->mb_et.et_blks[nb-1].bb_len += (u_short)len; ! 548: tlen += len; ! 549: #ifdef notdef ! 550: if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { ! 551: must copy last frag into private buffer ! 552: } ! 553: #endif ! 554: } ! 555: ! 556: /* set number of fragments in descriptor */ ! 557: bp->mb_et.et_nblock = nb; ! 558: bp->mb_status |= MH_EXOS; ! 559: movow(&exaddr->ex_portb, EX_NTRUPT); ! 560: } ! 561: ! 562: /* ! 563: * interrupt service routine. ! 564: */ ! 565: exintr(unit) ! 566: int unit; ! 567: { ! 568: register struct ex_softc *xs = &ex_softc[unit]; ! 569: register struct ex_msg *bp = xs->xs_x2hnext; ! 570: struct vba_device *ui = exinfo[unit]; ! 571: struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; ! 572: struct ex_msg *next_bp; ! 573: ! 574: while ((bp->mb_status & MH_OWNER) == MH_HOST) { ! 575: switch (bp->mb_rqst) { ! 576: case LLRECEIVE: ! 577: if (--xs->xs_nrec < 0) { ! 578: printf("ex%d: internal receive check\n", unit); ! 579: xs->xs_nrec = 0; ! 580: } ! 581: exrecv(unit, bp); ! 582: FreePkBuf(bp->mb_pkb); ! 583: bp->mb_pkb = (struct ifvba *)0; ! 584: exhangrcv(unit); ! 585: break; ! 586: ! 587: case LLTRANSMIT: ! 588: case LLRTRANSMIT: ! 589: if (--xs->xs_ntrb < 0) { ! 590: printf("ex%d: internal transmit check\n", unit); ! 591: xs->xs_ntrb = 0; ! 592: } ! 593: xs->xs_if.if_opackets++; ! 594: if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) ! 595: ; ! 596: else if (bp->mb_rply & LLXM_1RTRY) ! 597: xs->xs_if.if_collisions++; ! 598: else if (bp->mb_rply & LLXM_RTRYS) ! 599: xs->xs_if.if_collisions += 2; /* guess */ ! 600: else if (bp->mb_rply & LLXM_ERROR) ! 601: if (xs->xs_if.if_oerrors++ % 100 == 0) ! 602: printf("ex%d: 100 transmit errors=%b\n", ! 603: unit, bp->mb_rply, XMIT_BITS); ! 604: if (bp->mb_pkb->iff_mbuf) { ! 605: m_freem(bp->mb_pkb->iff_mbuf); ! 606: bp->mb_pkb->iff_mbuf = (struct mbuf *)0; ! 607: } ! 608: FreePkBuf(bp->mb_pkb); ! 609: bp->mb_pkb = (struct ifvba *)0; ! 610: exstart(&xs->xs_if); ! 611: exhangrcv(unit); ! 612: break; ! 613: ! 614: case LLNET_STSTCS: ! 615: xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc; ! 616: xs->xs_flags &= ~EX_STATPENDING; ! 617: case LLNET_ADDRS: ! 618: case LLNET_RECV: ! 619: if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) ! 620: ; ! 621: else ! 622: printf("ex%d: %s, request 0x%x, reply 0x%x\n", ! 623: unit, "unsucessful stat or address change", ! 624: bp->mb_rqst, bp->mb_rply); ! 625: break; ! 626: ! 627: default: ! 628: printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst); ! 629: } ! 630: bp->mb_length = MBDATALEN; ! 631: next_bp = bp->mb_next; ! 632: bp->mb_status |= MH_EXOS; /* free up buffer */ ! 633: bp = next_bp; /* paranoia about race */ ! 634: movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */ ! 635: } ! 636: xs->xs_x2hnext = bp; ! 637: } ! 638: ! 639: /* ! 640: * Get a request buffer, fill in standard values, advance pointer. ! 641: */ ! 642: struct ex_msg * ! 643: exgetcbuf(xs, req) ! 644: struct ex_softc *xs; ! 645: int req; ! 646: { ! 647: register struct ex_msg *bp; ! 648: struct ifvba *pkb; ! 649: int s = splimp(); ! 650: ! 651: bp = xs->xs_h2xnext; ! 652: if ((bp->mb_status & MH_OWNER) == MH_EXOS) { ! 653: splx(s); ! 654: return (struct ex_msg *)0; ! 655: } ! 656: xs->xs_h2xnext = bp->mb_next; ! 657: bp->mb_1rsrv = 0; ! 658: bp->mb_rqst = req; ! 659: bp->mb_length = MBDATALEN; ! 660: bp->mb_pkb = (struct ifvba *)0; ! 661: splx(s); ! 662: return bp; ! 663: } ! 664: ! 665: /* ! 666: * Process Ethernet receive completion: If input error just drop packet, ! 667: * otherwise examine packet to determine type. If can't determine length from ! 668: * type, then have to drop packet, otherwise decapsulate packet based on type ! 669: * and pass to type-specific higher-level input routine. ! 670: */ ! 671: exrecv(unit, bp) ! 672: int unit; ! 673: register struct ex_msg *bp; ! 674: { ! 675: register struct ex_softc *xs = &ex_softc[unit]; ! 676: register struct ether_header *eh; ! 677: register struct mbuf *m; ! 678: int len, off, resid; ! 679: register struct ifqueue *inq; ! 680: int s; ! 681: ! 682: xs->xs_if.if_ipackets++; ! 683: /* total length - header - crc */ ! 684: len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4; ! 685: if (bp->mb_rply != LL_OK) { ! 686: if (xs->xs_if.if_ierrors++ % 100 == 0) ! 687: printf("ex%d: 100 receive errors=%b\n", ! 688: unit, bp->mb_rply, RECV_BITS); ! 689: return; ! 690: } ! 691: eh = (struct ether_header *)(bp->mb_pkb->iff_buffer); ! 692: ! 693: /* ! 694: * Deal with trailer protocol: if type is PUP trailer get true type from ! 695: * first 16-bit word past data. Remember that type was trailer by ! 696: * setting off. ! 697: */ ! 698: eh->ether_type = ntohs((u_short)eh->ether_type); ! 699: #define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) ! 700: if (eh->ether_type >= ETHERTYPE_TRAIL && ! 701: eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { ! 702: off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; ! 703: if (off >= ETHERMTU) ! 704: return; /* sanity */ ! 705: eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *)); ! 706: resid = ntohs(*(exdataaddr(eh, off+2, u_short *))); ! 707: if (off + resid > len) ! 708: return; /* sanity */ ! 709: len = off + resid; ! 710: } else ! 711: off = 0; ! 712: if (len == 0) ! 713: return; ! 714: /* ! 715: * Pull packet off interface. Off is nonzero if packet ! 716: * has trailing header; if_vbaget will then force this header ! 717: * information to be at the front, but we still have to drop ! 718: * the type and length which are at the front of any trailer data. ! 719: */ ! 720: m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0); ! 721: if (m == 0) ! 722: return; ! 723: ether_input(&xs->xs_if, eh, m); ! 724: return; ! 725: } ! 726: ! 727: /* ! 728: * Hang a receive request. This routine is called by exinit and excdint, ! 729: * with interrupts disabled in both cases. ! 730: */ ! 731: exhangrcv(unit) ! 732: int unit; ! 733: { ! 734: register struct ex_softc *xs = &ex_softc[unit]; ! 735: register struct ex_msg *bp; ! 736: register struct ifvba *pkb; ! 737: short mustint = 0; ! 738: union l_util { ! 739: u_long l; ! 740: struct i86_long i; ! 741: } l_util; ! 742: ! 743: while (xs->xs_nrec < NREC) { ! 744: if (xs->xs_pkblist == (struct ifvba *)0) ! 745: break; ! 746: if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) { ! 747: break; ! 748: } ! 749: GetPkBuf(bp, pkb); ! 750: pkb->iff_mbuf = 0; ! 751: xs->xs_nrec += 1; ! 752: bp->mb_er.er_nblock = 1; ! 753: bp->mb_er.er_blks[0].bb_len = EXMAXRBUF; ! 754: l_util.l = BUSADDR(pkb->iff_buffer); ! 755: bp->mb_er.er_blks[0].bb_addr = l_util.i; ! 756: bp->mb_status |= MH_EXOS; ! 757: mustint = 1; ! 758: } ! 759: if (mustint == 0) ! 760: return; ! 761: movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT); ! 762: } ! 763: ! 764: /* ! 765: * Ethernet output routine is ether_output(). ! 766: */ ! 767: ! 768: /* ! 769: * Watchdog routine (currently not used). Might use this to get stats from EXOS. ! 770: */ ! 771: exwatch(unit) ! 772: int unit; ! 773: { ! 774: struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr; ! 775: register struct ex_softc *xs = &ex_softc[unit]; ! 776: register struct ex_msg *bp; ! 777: int s = splimp(); ! 778: ! 779: if (xs->xs_flags & EX_STATPENDING) ! 780: goto exspnd; ! 781: if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) { ! 782: splx(s); ! 783: return; ! 784: } ! 785: xs->xs_flags |= EX_STATPENDING; ! 786: bp->mb_ns.ns_mask = READ_OBJ; ! 787: bp->mb_ns.ns_rsrv = 0; ! 788: bp->mb_ns.ns_nobj = 8; ! 789: bp->mb_ns.ns_xobj = 0; ! 790: bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET; ! 791: bp->mb_status |= MH_EXOS; ! 792: movow(&exaddr->ex_portb, EX_NTRUPT); ! 793: exspnd: splx(s); ! 794: xs->xs_if.if_timer = EXWATCHINTVL; ! 795: } ! 796: ! 797: /* ! 798: * Process an ioctl request. ! 799: */ ! 800: exioctl(ifp, cmd, data) ! 801: register struct ifnet *ifp; ! 802: int cmd; ! 803: caddr_t data; ! 804: { ! 805: register struct ifaddr *ifa = (struct ifaddr *)data; ! 806: register struct ex_softc *xs = &ex_softc[ifp->if_unit]; ! 807: int s = splimp(), error = 0; ! 808: ! 809: switch (cmd) { ! 810: ! 811: case SIOCSIFADDR: ! 812: ifp->if_flags |= IFF_UP; ! 813: exinit(ifp->if_unit); ! 814: ! 815: switch (ifa->ifa_addr->sa_family) { ! 816: #ifdef INET ! 817: case AF_INET: ! 818: ((struct arpcom *)ifp)->ac_ipaddr = ! 819: IA_SIN(ifa)->sin_addr; ! 820: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); ! 821: break; ! 822: #endif ! 823: #ifdef NS ! 824: case AF_NS: ! 825: { ! 826: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); ! 827: ! 828: if (ns_nullhost(*ina)) ! 829: ina->x_host = *(union ns_host *)(xs->xs_addr); ! 830: else ! 831: ex_setaddr(ina->x_host.c_host,ifp->if_unit); ! 832: break; ! 833: } ! 834: #endif ! 835: } ! 836: break; ! 837: ! 838: case SIOCSIFFLAGS: ! 839: if ((ifp->if_flags & IFF_UP) == 0 && ! 840: xs->xs_flags & EX_RUNNING) { ! 841: movow(&((struct exdevice *) ! 842: (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET); ! 843: xs->xs_flags &= ~EX_RUNNING; ! 844: } else if (ifp->if_flags & IFF_UP && ! 845: (xs->xs_flags & EX_RUNNING) == 0) ! 846: exinit(ifp->if_unit); ! 847: break; ! 848: ! 849: default: ! 850: error = EINVAL; ! 851: } ! 852: splx(s); ! 853: return (error); ! 854: } ! 855: ! 856: /* ! 857: * set ethernet address for unit ! 858: */ ! 859: ex_setaddr(physaddr, unit) ! 860: u_char *physaddr; ! 861: int unit; ! 862: { ! 863: register struct ex_softc *xs = &ex_softc[unit]; ! 864: ! 865: if (physaddr) { ! 866: xs->xs_flags |= EX_SETADDR; ! 867: bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6); ! 868: } ! 869: ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT); ! 870: } ! 871: ! 872: /* ! 873: * Enable multicast reception for unit. ! 874: */ ! 875: ex_setmulti(linkaddr, unit, slot) ! 876: u_char *linkaddr; ! 877: int unit, slot; ! 878: { ! 879: register struct ex_softc *xs = &ex_softc[unit]; ! 880: struct vba_device *ui = exinfo[unit]; ! 881: register struct exdevice *addr= (struct exdevice *)ui->ui_addr; ! 882: register struct ex_msg *bp; ! 883: ! 884: if (!(xs->xs_flags & EX_RUNNING)) ! 885: return; ! 886: bp = exgetcbuf(xs, LLNET_ADDRS); ! 887: bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ; ! 888: bp->mb_na.na_slot = slot; ! 889: bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6); ! 890: bp->mb_status |= MH_EXOS; ! 891: movow(&addr->ex_portb, EX_NTRUPT); ! 892: bp = xs->xs_x2hnext; ! 893: while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ ! 894: #ifdef DEBUG ! 895: log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit, ! 896: (slot == PHYSSLOT ? "reset addr" : "add multicast" ! 897: ether_sprintf(bp->mb_na.na_addrs), slot); ! 898: #endif ! 899: /* ! 900: * Now, re-enable reception on slot. ! 901: */ ! 902: bp = exgetcbuf(xs, LLNET_RECV); ! 903: bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ; ! 904: bp->mb_nr.nr_slot = slot; ! 905: bp->mb_status |= MH_EXOS; ! 906: movow(&addr->ex_portb, EX_NTRUPT); ! 907: bp = xs->xs_x2hnext; ! 908: while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ ! 909: ; ! 910: } ! 911: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.