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