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