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