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