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