1*26197Ssklower /* 2*26197Ssklower * Copyright (c) 1986 Regents of the University of California. 3*26197Ssklower * All rights reserved. The Berkeley software License Agreement 4*26197Ssklower * specifies the terms and conditions for redistribution. 5*26197Ssklower * 6*26197Ssklower * @(#)if_ix.c 6.1 (Berkeley) 02/17/86 7*26197Ssklower */ 8*26197Ssklower 9*26197Ssklower #include "np.h" 10*26197Ssklower #if NNP > 0 11*26197Ssklower 12*26197Ssklower /* 13*26197Ssklower * Interlan NP100 Ethernet Communications Controller interface 14*26197Ssklower */ 15*26197Ssklower #include "../machine/pte.h" 16*26197Ssklower 17*26197Ssklower #include "param.h" 18*26197Ssklower #include "systm.h" 19*26197Ssklower #include "mbuf.h" 20*26197Ssklower #include "buf.h" 21*26197Ssklower #include "protosw.h" 22*26197Ssklower #include "socket.h" 23*26197Ssklower #include "vmmac.h" 24*26197Ssklower #include "ioctl.h" 25*26197Ssklower #include "errno.h" 26*26197Ssklower 27*26197Ssklower #include "../net/if.h" 28*26197Ssklower #include "../net/netisr.h" 29*26197Ssklower #include "../net/route.h" 30*26197Ssklower 31*26197Ssklower #ifdef INET 32*26197Ssklower #include "../netinet/in.h" 33*26197Ssklower #include "../netinet/in_systm.h" 34*26197Ssklower #include "../netinet/in_var.h" 35*26197Ssklower #include "../netinet/ip.h" 36*26197Ssklower #include "../netinet/if_ether.h" 37*26197Ssklower #endif 38*26197Ssklower 39*26197Ssklower #ifdef NS 40*26197Ssklower #include "../netns/ns.h" 41*26197Ssklower #include "../netns/ns_if.h" 42*26197Ssklower #endif 43*26197Ssklower 44*26197Ssklower #include "../vax/cpu.h" 45*26197Ssklower #include "../vax/mtpr.h" 46*26197Ssklower #include "../vaxif/if_uba.h" 47*26197Ssklower #include "../vaxuba/ubareg.h" 48*26197Ssklower #include "../vaxuba/ubavar.h" 49*26197Ssklower #include "../vaxuba/npreg.h" 50*26197Ssklower #include "../vaxif/if_ix.h" 51*26197Ssklower 52*26197Ssklower int ixattach(), ixrint(), ixcint(); 53*26197Ssklower #define ILUNIT(x) minor(x) 54*26197Ssklower int ixinit(), ixoutput(), ixioctl(), ixreset(), ixwatch(); 55*26197Ssklower int (*IxAttach)() = ixattach; 56*26197Ssklower int (*IxReset)() = ixreset; 57*26197Ssklower 58*26197Ssklower /* 59*26197Ssklower * Ethernet software status per interface. 60*26197Ssklower * 61*26197Ssklower * Each interface is referenced by a network interface structure, 62*26197Ssklower * ix_if, which the routing code uses to locate the interface. 63*26197Ssklower * This structure contains the output queue for the interface, its address, ... 64*26197Ssklower * We also have, for each interface, a UBA interface structure, which 65*26197Ssklower * contains information about the UNIBUS resources held by the interface: 66*26197Ssklower * map registers, buffered data paths, etc. Information is cached in this 67*26197Ssklower * structure for use by the if_uba.c routines in running the interface 68*26197Ssklower * efficiently. 69*26197Ssklower */ 70*26197Ssklower struct ix_softc { 71*26197Ssklower struct arpcom ix_ac; /* Ethernet common part */ 72*26197Ssklower #define ix_if ix_ac.ac_if /* network-visible interface */ 73*26197Ssklower #define ix_addr ix_ac.ac_enaddr /* hardware Ethernet address */ 74*26197Ssklower int ix_flags; 75*26197Ssklower #define IXF_OACTIVE 0x1 /* output is active */ 76*26197Ssklower #define IXF_RCVPENDING 0x2 /* start rcv in ilcint */ 77*26197Ssklower #define IXF_GOTUBA 0x4 /* unibus resources mapped */ 78*26197Ssklower #define IXF_RUNNING 0x8 /* board is running */ 79*26197Ssklower #define IXF_SETADDR 0x10 /* physical address is changed */ 80*26197Ssklower #define IXF_STATPENDING 0x20 /* stat cmd pending */ 81*26197Ssklower #define IXF_GOTCQE 0x40 /* np resources available */ 82*26197Ssklower struct ifuba ix_ifuba; /* unibus resources */ 83*26197Ssklower u_short ix_aid; /* Access Id returned by open DDL */ 84*26197Ssklower u_short ix_badcqe; 85*26197Ssklower struct npmaster *ix_mp; /* Board physio request header */ 86*26197Ssklower struct npreq *ix_rrp; /* Cached npreq for recv */ 87*26197Ssklower struct npreq *ix_wrp; /* Cached npreq for xmit */ 88*26197Ssklower short ix_scaninterval; /* interval of stat collection */ 89*26197Ssklower #define IXWATCHINTERVAL 60 /* once every 60 seconds */ 90*26197Ssklower union ix_stats ix_stats; /* holds on-board statistics */ 91*26197Ssklower int ix_ubaddr; /* mapping registers of ix_stats */ 92*26197Ssklower } ix_softc[NNP]; 93*26197Ssklower extern struct uba_device *npdinfo[]; 94*26197Ssklower 95*26197Ssklower /* 96*26197Ssklower * Interface exists: make available by filling in network interface 97*26197Ssklower * record. System will initialize the interface when it is ready 98*26197Ssklower * to accept packets. We can't even get the ethernet address 99*26197Ssklower * or other interesting data until the board has been downloaded. 100*26197Ssklower * running ifconfig will attempt to start unit. 101*26197Ssklower */ 102*26197Ssklower ixattach(ui) 103*26197Ssklower struct uba_device *ui; 104*26197Ssklower { 105*26197Ssklower register struct ix_softc *ix = &ix_softc[ui->ui_unit]; 106*26197Ssklower register struct ifnet *ifp = &ix->ix_if; 107*26197Ssklower extern struct npmaster npmasters[]; 108*26197Ssklower 109*26197Ssklower ifp->if_unit = ui->ui_unit; 110*26197Ssklower ifp->if_name = "ix"; 111*26197Ssklower ifp->if_mtu = ETHERMTU; 112*26197Ssklower ifp->if_flags = IFF_BROADCAST; 113*26197Ssklower 114*26197Ssklower ifp->if_init = ixinit; 115*26197Ssklower ifp->if_output = ixoutput; 116*26197Ssklower ifp->if_ioctl = ixioctl; 117*26197Ssklower ifp->if_reset = ixreset; 118*26197Ssklower 119*26197Ssklower ix->ix_mp = npmasters + ui->ui_unit; 120*26197Ssklower ix->ix_ifuba.ifu_flags = UBA_CANTWAIT; 121*26197Ssklower 122*26197Ssklower if_attach(ifp); 123*26197Ssklower } 124*26197Ssklower 125*26197Ssklower struct npreq * 126*26197Ssklower ix_GetReq(mp, addr, len) 127*26197Ssklower struct npmaster *mp; 128*26197Ssklower caddr_t addr; 129*26197Ssklower { 130*26197Ssklower int unit = mp->unit; 131*26197Ssklower register struct npreq *rp; 132*26197Ssklower register struct CQE *ep; 133*26197Ssklower struct ix_softc *ix = ix_softc + unit; 134*26197Ssklower extern struct npreq *NpGetReq(); 135*26197Ssklower 136*26197Ssklower while ((rp = NpGetReq(mp->reqtab)) == NULL) { 137*26197Ssklower mp->reqtab->flags |= WANTREQ; 138*26197Ssklower sleep((caddr_t)(mp->reqtab), PZERO - 1); 139*26197Ssklower } 140*26197Ssklower rp->flags = KERNREQ; /* Clear flags */ 141*26197Ssklower 142*26197Ssklower ep = rp->element; /* Associated CQE */ 143*26197Ssklower ep->cqe_famid = (unsign32)ix; /* Process ID */ 144*26197Ssklower ep->cqe_wind = 0; /* Amount of buffer mapped */ 145*26197Ssklower ep->cqe_nbuf = 1; /* Must be 1, no buffer chain */ 146*26197Ssklower ep->cqe_char = 1; /* Driver owns this CQE */ 147*26197Ssklower ep->cqe_prot = NPDLA; /* Data Link Access protocol */ 148*26197Ssklower ep->cqe_bcnt = len; /* Byte count */ 149*26197Ssklower rp->bufaddr = (caddr_t) (UBADDRMASK & (int) addr);/* mapped buffer */ 150*26197Ssklower ep->cqe_dma[0] = (unsign16)LOWORD(rp->bufaddr); 151*26197Ssklower ep->cqe_dma[1] = (unsign16)HIWORD(rp->bufaddr); 152*26197Ssklower return (rp); 153*26197Ssklower } 154*26197Ssklower 155*26197Ssklower ix_DoReq(mp, rp, cmd, addr, len, rpb, routine) 156*26197Ssklower struct npmaster *mp; 157*26197Ssklower register struct npreq *rp; 158*26197Ssklower u_short cmd; 159*26197Ssklower caddr_t addr; 160*26197Ssklower int len; 161*26197Ssklower register u_short *rpb; 162*26197Ssklower int (*routine)(); 163*26197Ssklower { 164*26197Ssklower register struct CQE *ep = rp->element; 165*26197Ssklower register u_short *p = &ep->rpb1; 166*26197Ssklower u_short cnt = *rpb++; 167*26197Ssklower extern long NpDebug; 168*26197Ssklower int pri; 169*26197Ssklower 170*26197Ssklower ep->cqe_ust0 = ep->cqe_ust1 = NPCLEAR; /* Clear status */ 171*26197Ssklower ep->cqe_bcnt = len; /* Byte count */ 172*26197Ssklower rp->flags = KERNREQ; /* Clear flags */ 173*26197Ssklower rp->bufaddr = (caddr_t) (UBADDRMASK & (int) addr);/* mapped buffer */ 174*26197Ssklower rp->intr = routine; 175*26197Ssklower rp->user = (caddr_t) (ep->cqe_func = cmd);/* In case pissed on in CQE */ 176*26197Ssklower ep->cqe_dma[0] = (unsign16)LOWORD(rp->bufaddr); 177*26197Ssklower ep->cqe_dma[1] = (unsign16)HIWORD(rp->bufaddr); 178*26197Ssklower ep->cqe_lenrpb = cnt + cnt; 179*26197Ssklower for (; cnt > 0; cnt--) *p++ = *rpb++; 180*26197Ssklower 181*26197Ssklower if (NpDebug & DEBCQE) 182*26197Ssklower printf("Function is %x ep %x reqid %x\n", ep->cqe_func, ep, ep->cqe_reqid); 183*26197Ssklower if (NpDebug & DEBCQE) 184*26197Ssklower printf("irp len = %x rp = %x\n", ep->cqe_lenrpb, rp); 185*26197Ssklower if (routine == 0) { 186*26197Ssklower NpAddReq(mp->reqtab, rp); /* Queue onto active list */ 187*26197Ssklower while (!(rp->flags & REQDONE)) { 188*26197Ssklower pri = spl4(); 189*26197Ssklower NpAddCQE(ep, &mp->shmemp->devcq, mp); 190*26197Ssklower sleep((caddr_t)rp, PZERO - 1); 191*26197Ssklower splx(pri); 192*26197Ssklower } 193*26197Ssklower if (rp->flags & IOABORT || ep->cqe_sts != NPDONE 194*26197Ssklower || ep->cqe_ust0 != NPDONE 195*26197Ssklower || ep->cqe_ust1 != NPOK) { 196*26197Ssklower struct ix_softc *ix = (struct ix_softc *)ep->cqe_famid; 197*26197Ssklower printf("ix%d: Req failed, cmd %x, stat %x, ", 198*26197Ssklower ix->ix_if.if_unit, rp->user, ep->cqe_sts); 199*26197Ssklower printf("ust error %x,%x\n", ep->cqe_ust0, ep->cqe_ust1); 200*26197Ssklower } 201*26197Ssklower NpRemReq(rp); /* Clear request */ 202*26197Ssklower } else { 203*26197Ssklower pri = spl4(); 204*26197Ssklower NpAddCQE(ep, &mp->shmemp->devcq, mp); 205*26197Ssklower splx(pri); 206*26197Ssklower } 207*26197Ssklower } 208*26197Ssklower 209*26197Ssklower /* 210*26197Ssklower * Ethernet output routine. 211*26197Ssklower * Encapsulate a packet of type family for the local net. 212*26197Ssklower * Use trailer local net encapsulation if enough data in first 213*26197Ssklower * packet leaves a multiple of 512 bytes of data in remainder. 214*26197Ssklower */ 215*26197Ssklower ixoutput(ifp, m0, dst) 216*26197Ssklower struct ifnet *ifp; 217*26197Ssklower struct mbuf *m0; 218*26197Ssklower struct sockaddr *dst; 219*26197Ssklower { 220*26197Ssklower int type, s, error; 221*26197Ssklower u_char edst[6]; 222*26197Ssklower struct in_addr idst; 223*26197Ssklower register struct ix_softc *ix = &ix_softc[ifp->if_unit]; 224*26197Ssklower register struct mbuf *m = m0; 225*26197Ssklower register struct ether_header *il; 226*26197Ssklower register int off; 227*26197Ssklower int usetrailers; 228*26197Ssklower 229*26197Ssklower if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 230*26197Ssklower error = ENETDOWN; 231*26197Ssklower goto bad; 232*26197Ssklower } 233*26197Ssklower switch (dst->sa_family) { 234*26197Ssklower 235*26197Ssklower #ifdef INET 236*26197Ssklower case AF_INET: 237*26197Ssklower idst = ((struct sockaddr_in *)dst)->sin_addr; 238*26197Ssklower if (!arpresolve(&ix->ix_ac, m, &idst, edst, &usetrailers)) 239*26197Ssklower return (0); /* if not yet resolved */ 240*26197Ssklower off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 241*26197Ssklower if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 242*26197Ssklower m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 243*26197Ssklower type = ETHERTYPE_TRAIL + (off>>9); 244*26197Ssklower m->m_off -= 2 * sizeof (u_short); 245*26197Ssklower m->m_len += 2 * sizeof (u_short); 246*26197Ssklower *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 247*26197Ssklower *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 248*26197Ssklower goto gottrailertype; 249*26197Ssklower } 250*26197Ssklower type = ETHERTYPE_IP; 251*26197Ssklower off = 0; 252*26197Ssklower goto gottype; 253*26197Ssklower #endif 254*26197Ssklower #ifdef NS 255*26197Ssklower case AF_NS: 256*26197Ssklower type = ETHERTYPE_NS; 257*26197Ssklower bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 258*26197Ssklower (caddr_t)edst, sizeof (edst)); 259*26197Ssklower off = 0; 260*26197Ssklower goto gottype; 261*26197Ssklower #endif 262*26197Ssklower 263*26197Ssklower case AF_UNSPEC: 264*26197Ssklower il = (struct ether_header *)dst->sa_data; 265*26197Ssklower bcopy((caddr_t)il->ether_dhost, (caddr_t)edst, sizeof (edst)); 266*26197Ssklower type = il->ether_type; 267*26197Ssklower goto gottype; 268*26197Ssklower 269*26197Ssklower default: 270*26197Ssklower printf("ix%d: can't handle af%d\n", ifp->if_unit, 271*26197Ssklower dst->sa_family); 272*26197Ssklower error = EAFNOSUPPORT; 273*26197Ssklower goto bad; 274*26197Ssklower } 275*26197Ssklower 276*26197Ssklower gottrailertype: 277*26197Ssklower /* 278*26197Ssklower * Packet to be sent as trailer: move first packet 279*26197Ssklower * (control information) to end of chain. 280*26197Ssklower */ 281*26197Ssklower while (m->m_next) 282*26197Ssklower m = m->m_next; 283*26197Ssklower m->m_next = m0; 284*26197Ssklower m = m0->m_next; 285*26197Ssklower m0->m_next = 0; 286*26197Ssklower m0 = m; 287*26197Ssklower 288*26197Ssklower gottype: 289*26197Ssklower /* 290*26197Ssklower * Add local net header. If no space in first mbuf, 291*26197Ssklower * allocate another. 292*26197Ssklower */ 293*26197Ssklower if (m->m_off > MMAXOFF || 294*26197Ssklower MMINOFF + sizeof (struct ether_header) > m->m_off) { 295*26197Ssklower m = m_get(M_DONTWAIT, MT_HEADER); 296*26197Ssklower if (m == 0) { 297*26197Ssklower error = ENOBUFS; 298*26197Ssklower goto bad; 299*26197Ssklower } 300*26197Ssklower m->m_next = m0; 301*26197Ssklower m->m_off = MMINOFF; 302*26197Ssklower m->m_len = sizeof (struct ether_header); 303*26197Ssklower } else { 304*26197Ssklower m->m_off -= sizeof (struct ether_header); 305*26197Ssklower m->m_len += sizeof (struct ether_header); 306*26197Ssklower } 307*26197Ssklower il = mtod(m, struct ether_header *); 308*26197Ssklower il->ether_type = htons((u_short)type); 309*26197Ssklower bcopy((caddr_t)edst, (caddr_t)il->ether_dhost, sizeof (edst)); 310*26197Ssklower bcopy((caddr_t)ix->ix_addr, (caddr_t)il->ether_shost, 311*26197Ssklower sizeof(il->ether_shost)); 312*26197Ssklower 313*26197Ssklower /* 314*26197Ssklower * Queue message on interface, and start output if interface 315*26197Ssklower * not yet active. 316*26197Ssklower */ 317*26197Ssklower s = splimp(); 318*26197Ssklower if (IF_QFULL(&ifp->if_snd)) { 319*26197Ssklower IF_DROP(&ifp->if_snd); 320*26197Ssklower splx(s); 321*26197Ssklower m_freem(m); 322*26197Ssklower return (ENOBUFS); 323*26197Ssklower } 324*26197Ssklower IF_ENQUEUE(&ifp->if_snd, m); 325*26197Ssklower if ((ix->ix_flags & IXF_OACTIVE) == 0) 326*26197Ssklower ixstart(ifp->if_unit); 327*26197Ssklower splx(s); 328*26197Ssklower return (0); 329*26197Ssklower 330*26197Ssklower bad: 331*26197Ssklower m_freem(m0); 332*26197Ssklower return (error); 333*26197Ssklower } 334*26197Ssklower /* 335*26197Ssklower * Reset of interface after UNIBUS reset. 336*26197Ssklower * If interface is on specified uba, reset its state. 337*26197Ssklower */ 338*26197Ssklower ixreset(unit, uban, softp) 339*26197Ssklower int unit, uban; 340*26197Ssklower caddr_t softp; 341*26197Ssklower { 342*26197Ssklower register struct uba_device *ui; 343*26197Ssklower int mask = IXF_SETADDR; /* Only remember new physaddr */ 344*26197Ssklower 345*26197Ssklower if (unit >= NNP || (ui = npdinfo[unit]) == 0 || ui->ui_alive == 0 || 346*26197Ssklower ui->ui_ubanum != uban) 347*26197Ssklower return; 348*26197Ssklower printf(" ix%d reset", unit); 349*26197Ssklower if (softp) 350*26197Ssklower mask |= IXF_GOTUBA; /* UBA mapping regs still valid; */ 351*26197Ssklower ix_softc[unit].ix_if.if_flags &= ~IFF_RUNNING; 352*26197Ssklower ix_softc[unit].ix_flags &= mask; 353*26197Ssklower } 354*26197Ssklower 355*26197Ssklower 356*26197Ssklower /* 357*26197Ssklower * Initialization of interface; clear recorded pending 358*26197Ssklower * operations, and reinitialize UNIBUS usage. 359*26197Ssklower */ 360*26197Ssklower ixinit(unit) 361*26197Ssklower int unit; 362*26197Ssklower { 363*26197Ssklower register struct ix_softc *ix = &ix_softc[unit]; 364*26197Ssklower struct uba_device *ui = npdinfo[unit]; 365*26197Ssklower register struct ifnet *ifp = &ix->ix_if; 366*26197Ssklower register struct CQE *ep; 367*26197Ssklower struct npreq *rp; 368*26197Ssklower struct npmaster *mp = ix->ix_mp; 369*26197Ssklower register u_short *dpmp = & mp->shmemp->statblock.sb_dpm; 370*26197Ssklower u_short rpb[7]; 371*26197Ssklower int s; 372*26197Ssklower 373*26197Ssklower /* not yet, if address still unknown */ 374*26197Ssklower if (ifp->if_addrlist == (struct ifaddr *)0) 375*26197Ssklower return; 376*26197Ssklower if (ix->ix_flags & IXF_RUNNING) 377*26197Ssklower return; 378*26197Ssklower if ((mp->flags & AVAILABLE) == 0 || (*dpmp & PROTOMASK(NPDLA)) == 0) { 379*26197Ssklower ifp->if_flags &= ~IFF_UP; 380*26197Ssklower return; 381*26197Ssklower } 382*26197Ssklower if ((ix->ix_flags & IXF_GOTUBA) == 0) { 383*26197Ssklower ix->ix_ifuba.ifu_flags = UBA_CANTWAIT; 384*26197Ssklower if (if_ubainit(&ix->ix_ifuba, ui->ui_ubanum, 385*26197Ssklower sizeof (struct ether_header), (int)btoc(ETHERMTU)) == 0) { 386*26197Ssklower printf("ix%d: can't initialize\n", unit); 387*26197Ssklower ix->ix_if.if_flags &= ~IFF_UP; 388*26197Ssklower return; 389*26197Ssklower } 390*26197Ssklower ix->ix_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&ix->ix_stats, 391*26197Ssklower sizeof (union ix_stats), 0); 392*26197Ssklower ix->ix_flags |= IXF_GOTUBA; 393*26197Ssklower } 394*26197Ssklower if ((ix->ix_flags & IXF_GOTCQE) == 0) { 395*26197Ssklower ix->ix_rrp = ix_GetReq(mp, ix->ix_ifuba.ifu_r.ifrw_info, 396*26197Ssklower ETHERMTU); 397*26197Ssklower ix->ix_wrp = ix_GetReq(mp, 0, 0); 398*26197Ssklower ix->ix_flags |= IXF_GOTCQE; 399*26197Ssklower } 400*26197Ssklower 401*26197Ssklower rp = ix->ix_wrp; 402*26197Ssklower ep = rp->element; 403*26197Ssklower 404*26197Ssklower /* Changing the ethernet address resets the dla module, 405*26197Ssklower so must do it before opening the channel */ 406*26197Ssklower if (ix->ix_flags & IXF_SETADDR) { 407*26197Ssklower register char *cp = (char *) &ix->ix_stats; 408*26197Ssklower int spincount; 409*26197Ssklower int x; 410*26197Ssklower *cp++ = 1; 411*26197Ssklower bcopy(ix->ix_addr, (caddr_t)cp, 6); 412*26197Ssklower rpb[0] = 1; /* RPB length */ 413*26197Ssklower ix_DoReq(mp, rp, IXC_LDPA, ix->ix_ubaddr, 7, rpb, 0); 414*26197Ssklower #ifndef TheyFinallyFixedTheBoard 415*26197Ssklower /* Board requires some time to reinitialize its protocols */ 416*26197Ssklower x = spl1(); 417*26197Ssklower spincount = 2000000; 418*26197Ssklower while (((*dpmp & PROTOMASK(NPDLA))==0) && spincount > 0) 419*26197Ssklower spincount--; 420*26197Ssklower if (spincount==0) { 421*26197Ssklower printf("ix%d: failed to reinitialize DLA module\n", 422*26197Ssklower unit); 423*26197Ssklower splx(x); 424*26197Ssklower } 425*26197Ssklower splx(x); 426*26197Ssklower #endif 427*26197Ssklower } 428*26197Ssklower rpb[0] = 6; /* RPB length */ 429*26197Ssklower rpb[2] = 0x10; /* Share with any smart users */ 430*26197Ssklower rpb[3] = 0; /* Take (a copy of) all frames */ 431*26197Ssklower rpb[5] = 8; /* On board rcv queue length */ 432*26197Ssklower rpb[6] = 0; /* XMT packets as is */ 433*26197Ssklower ix_DoReq(mp, rp, IXC_OPEN, 0, 0, rpb, 0); 434*26197Ssklower 435*26197Ssklower ix->ix_aid = ep->rpb1; 436*26197Ssklower 437*26197Ssklower /* Here we request our ethernet address, if we didn't reset it*/ 438*26197Ssklower if ((ix->ix_flags & IXF_SETADDR)==0) { 439*26197Ssklower rpb[0] = 2; 440*26197Ssklower rpb[1] = ix->ix_aid; 441*26197Ssklower rpb[2] = 0; /* get all stats */ 442*26197Ssklower ix_DoReq(mp, rp, IXC_GSTAT, /* Get Stats */ 443*26197Ssklower (caddr_t) ix->ix_ubaddr, sizeof(ix->ix_stats) - 8, 444*26197Ssklower rpb, 0); 445*26197Ssklower bcopy((caddr_t) &ix->ix_stats, (caddr_t) ix->ix_addr, 6); 446*26197Ssklower } 447*26197Ssklower ix->ix_if.if_flags |= IFF_RUNNING; 448*26197Ssklower ix->ix_flags |= IXF_RUNNING; 449*26197Ssklower ifp->if_watchdog = ixwatch; 450*26197Ssklower ifp->if_timer = ix->ix_scaninterval = IXWATCHINTERVAL; 451*26197Ssklower ixrint(mp, 0); 452*26197Ssklower } 453*26197Ssklower 454*26197Ssklower /* 455*26197Ssklower * Start output on interface. 456*26197Ssklower * Get another datagram to send off of the interface queue, 457*26197Ssklower * and map it to the interface before starting the output. 458*26197Ssklower */ 459*26197Ssklower ixstart(dev) 460*26197Ssklower dev_t dev; 461*26197Ssklower { 462*26197Ssklower int len = 0; 463*26197Ssklower int unit = minor(dev); 464*26197Ssklower register struct ix_softc *ix = &ix_softc[unit]; 465*26197Ssklower register struct mbuf *n; 466*26197Ssklower struct mbuf *m; 467*26197Ssklower int s, error = 0; 468*26197Ssklower struct npmaster *mp = ix->ix_mp; 469*26197Ssklower struct npreq *rp = ix->ix_wrp; 470*26197Ssklower struct CQE *ep; 471*26197Ssklower u_short rpb[8]; 472*26197Ssklower 473*26197Ssklower IF_DEQUEUE(&ix->ix_if.if_snd, m); 474*26197Ssklower if (m == 0) { 475*26197Ssklower if (ix->ix_flags & IXF_STATPENDING) { 476*26197Ssklower ix->ix_flags |= IXF_OACTIVE; 477*26197Ssklower rpb[0] = 2; 478*26197Ssklower rpb[1] = ix->ix_aid; 479*26197Ssklower rpb[2] = 0; /* get all stats */ 480*26197Ssklower ix_DoReq(mp, rp, IXC_GSTAT, /* general Stats */ 481*26197Ssklower (caddr_t) ix->ix_ubaddr, sizeof(ix->ix_stats) - 8, 482*26197Ssklower rpb, ixcint); 483*26197Ssklower } 484*26197Ssklower return; 485*26197Ssklower } 486*26197Ssklower /* 487*26197Ssklower * Ensure minimum packet length. 488*26197Ssklower * This makes the safe assumtion that there are no virtual holes 489*26197Ssklower * after the data. 490*26197Ssklower * For security, it might be wise to zero out the added bytes, 491*26197Ssklower * but we're mainly interested in speed at the moment. 492*26197Ssklower */ 493*26197Ssklower len = if_wubaput(&ix->ix_ifuba, m); 494*26197Ssklower if (len - sizeof(struct ether_header) < ETHERMIN) 495*26197Ssklower len = ETHERMIN + sizeof(struct ether_header); 496*26197Ssklower 497*26197Ssklower ix->ix_flags |= IXF_OACTIVE; 498*26197Ssklower 499*26197Ssklower /* Now setup to call np driver */ 500*26197Ssklower rpb[0] = 8; 501*26197Ssklower rpb[1] = ix->ix_aid; 502*26197Ssklower ix_DoReq(mp, rp, IXC_XMIT, /* send frame */ 503*26197Ssklower ix->ix_ifuba.ifu_w.ifrw_info, len, rpb, ixcint); 504*26197Ssklower } 505*26197Ssklower 506*26197Ssklower /* 507*26197Ssklower * Command done interrupt. (almost) 508*26197Ssklower */ 509*26197Ssklower ixcint(mp, rp) 510*26197Ssklower struct npmaster *mp; 511*26197Ssklower struct npreq *rp; 512*26197Ssklower { 513*26197Ssklower struct CQE *ep; 514*26197Ssklower register struct ix_softc *ix; 515*26197Ssklower int s = splimp(); 516*26197Ssklower 517*26197Ssklower ep = rp->element; 518*26197Ssklower ix = (struct ix_softc *)ep->cqe_famid; 519*26197Ssklower if ((ix->ix_flags & IXF_OACTIVE) == 0) { 520*26197Ssklower printf("ix%d: stray xmit interrupt, npreq=%x\n", 521*26197Ssklower ix->ix_if.if_unit, rp); 522*26197Ssklower } 523*26197Ssklower ix->ix_flags &= ~IXF_OACTIVE; 524*26197Ssklower 525*26197Ssklower switch (ep->cqe_func) { 526*26197Ssklower 527*26197Ssklower case IXC_XMIT: 528*26197Ssklower if (ep->cqe_sts == 1) 529*26197Ssklower ix->ix_if.if_opackets++; 530*26197Ssklower else 531*26197Ssklower ix->ix_if.if_oerrors++; 532*26197Ssklower break; 533*26197Ssklower 534*26197Ssklower case IXC_GSTAT: 535*26197Ssklower if (ep->cqe_sts == 1) 536*26197Ssklower ix->ix_if.if_collisions = ix->ix_stats.ixg.macg_xrty; 537*26197Ssklower break; 538*26197Ssklower } 539*26197Ssklower if (ix->ix_ifuba.ifu_xtofree) { 540*26197Ssklower m_freem(ix->ix_ifuba.ifu_xtofree); 541*26197Ssklower ix->ix_ifuba.ifu_xtofree = 0; 542*26197Ssklower } 543*26197Ssklower done: 544*26197Ssklower ixstart(ix->ix_if.if_unit); 545*26197Ssklower splx(s); 546*26197Ssklower } 547*26197Ssklower 548*26197Ssklower /* 549*26197Ssklower * Ethernet interface receiver interrupt. 550*26197Ssklower * If input error just drop packet. 551*26197Ssklower * Otherwise purge input buffered data path and examine 552*26197Ssklower * packet to determine type. If can't determine length 553*26197Ssklower * from type, then have to drop packet. Othewise decapsulate 554*26197Ssklower * packet based on type and pass to type specific higher-level 555*26197Ssklower * input routine. 556*26197Ssklower */ 557*26197Ssklower ixrint(mp, rp) 558*26197Ssklower struct npmaster *mp; 559*26197Ssklower struct npreq *rp; 560*26197Ssklower { 561*26197Ssklower struct CQE *ep; 562*26197Ssklower register struct ix_softc *ix = ix_softc + mp->unit; 563*26197Ssklower register struct ether_header *il; 564*26197Ssklower struct mbuf *m; 565*26197Ssklower int len, off, resid, s; 566*26197Ssklower register struct ifqueue *inq; 567*26197Ssklower 568*26197Ssklower if ((ix->ix_flags & IXF_RUNNING) == 0) 569*26197Ssklower return; 570*26197Ssklower if (rp == 0) 571*26197Ssklower goto setup; 572*26197Ssklower ix->ix_flags &= ~IXF_RCVPENDING; 573*26197Ssklower ep = rp->element; 574*26197Ssklower ix->ix_if.if_ipackets++; 575*26197Ssklower if (ix->ix_ifuba.ifu_flags & UBA_NEEDBDP) 576*26197Ssklower UBAPURGE(ix->ix_ifuba.ifu_uba, ix->ix_ifuba.ifu_r.ifrw_bdp); 577*26197Ssklower il = (struct ether_header *)(ix->ix_ifuba.ifu_r.ifrw_addr); 578*26197Ssklower len = ep->cqe_bcnt - sizeof (struct ether_header); 579*26197Ssklower if (ep->cqe_sts != NPDONE 580*26197Ssklower || ep->cqe_ust0 != NPDONE 581*26197Ssklower || ep->cqe_ust1 != NPOK) { 582*26197Ssklower printf("ixrint: cqe error %x, %x, %x\n", 583*26197Ssklower ep->cqe_sts, ep->cqe_ust0, ep->cqe_ust1); 584*26197Ssklower if (++ix->ix_badcqe > 100) { 585*26197Ssklower ix->ix_badcqe = 0; 586*26197Ssklower printf("ixrint: shutting down unix dla\n"); 587*26197Ssklower ix->ix_if.if_flags &= ~IFF_UP; 588*26197Ssklower return; 589*26197Ssklower } 590*26197Ssklower goto setup; 591*26197Ssklower } 592*26197Ssklower 593*26197Ssklower if ( len < 46 || len > ETHERMTU) { 594*26197Ssklower ix->ix_if.if_ierrors++; 595*26197Ssklower #ifdef notdef 596*26197Ssklower if (ix->ix_if.if_ierrors % 100 == 0) 597*26197Ssklower printf("ix%d: += 100 input errors\n", unit); 598*26197Ssklower #endif 599*26197Ssklower goto setup; 600*26197Ssklower } 601*26197Ssklower 602*26197Ssklower /* 603*26197Ssklower * Deal with trailer protocol: if type is trailer type 604*26197Ssklower * get true type from first 16-bit word past data. 605*26197Ssklower * Remember that type was trailer by setting off. 606*26197Ssklower */ 607*26197Ssklower il->ether_type = ntohs((u_short)il->ether_type); 608*26197Ssklower #define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) 609*26197Ssklower if (il->ether_type >= ETHERTYPE_TRAIL && 610*26197Ssklower il->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 611*26197Ssklower off = (il->ether_type - ETHERTYPE_TRAIL) * 512; 612*26197Ssklower if (off >= ETHERMTU) 613*26197Ssklower goto setup; /* sanity */ 614*26197Ssklower il->ether_type = ntohs(*ildataaddr(il, off, u_short *)); 615*26197Ssklower resid = ntohs(*(ildataaddr(il, off+2, u_short *))); 616*26197Ssklower if (off + resid > len) 617*26197Ssklower goto setup; /* sanity */ 618*26197Ssklower len = off + resid; 619*26197Ssklower } else 620*26197Ssklower off = 0; 621*26197Ssklower if (len == 0) 622*26197Ssklower goto setup; 623*26197Ssklower 624*26197Ssklower /* 625*26197Ssklower * Pull packet off interface. Off is nonzero if packet 626*26197Ssklower * has trailing header; ilget will then force this header 627*26197Ssklower * information to be at the front, but we still have to drop 628*26197Ssklower * the type and length which are at the front of any trailer data. 629*26197Ssklower */ 630*26197Ssklower m = if_rubaget(&ix->ix_ifuba, len, off, &ix->ix_if); 631*26197Ssklower if (m == 0) 632*26197Ssklower goto setup; 633*26197Ssklower if (off) { 634*26197Ssklower struct ifnet *ifp; 635*26197Ssklower 636*26197Ssklower ifp = *(mtod(m, struct ifnet **)); 637*26197Ssklower m->m_off += 2 * sizeof (u_short); 638*26197Ssklower m->m_len -= 2 * sizeof (u_short); 639*26197Ssklower *(mtod(m, struct ifnet **)) = ifp; 640*26197Ssklower } 641*26197Ssklower switch (il->ether_type) { 642*26197Ssklower 643*26197Ssklower #ifdef INET 644*26197Ssklower case ETHERTYPE_IP: 645*26197Ssklower schednetisr(NETISR_IP); 646*26197Ssklower inq = &ipintrq; 647*26197Ssklower break; 648*26197Ssklower 649*26197Ssklower case ETHERTYPE_ARP: 650*26197Ssklower arpinput(&ix->ix_ac, m); 651*26197Ssklower goto setup; 652*26197Ssklower #endif 653*26197Ssklower #ifdef NS 654*26197Ssklower case ETHERTYPE_NS: 655*26197Ssklower schednetisr(NETISR_NS); 656*26197Ssklower inq = &nsintrq; 657*26197Ssklower break; 658*26197Ssklower 659*26197Ssklower #endif 660*26197Ssklower default: 661*26197Ssklower m_freem(m); 662*26197Ssklower goto setup; 663*26197Ssklower } 664*26197Ssklower 665*26197Ssklower s = splimp(); 666*26197Ssklower if (IF_QFULL(inq)) { 667*26197Ssklower IF_DROP(inq); 668*26197Ssklower m_freem(m); 669*26197Ssklower } else 670*26197Ssklower IF_ENQUEUE(inq, m); 671*26197Ssklower splx(s); 672*26197Ssklower 673*26197Ssklower setup: 674*26197Ssklower /* 675*26197Ssklower * Reset for next packet if possible. 676*26197Ssklower * If waiting for transmit command completion, set flag 677*26197Ssklower * and wait until command completes. 678*26197Ssklower */ 679*26197Ssklower if (rp == 0) { 680*26197Ssklower rp = ix->ix_rrp; 681*26197Ssklower rp->intr = ixrint; 682*26197Ssklower ep = rp->element; 683*26197Ssklower } 684*26197Ssklower len = ETHERMTU + sizeof(struct ether_header); 685*26197Ssklower 686*26197Ssklower /* Now setup to call np driver */ 687*26197Ssklower /* Initializations of request structure */ 688*26197Ssklower 689*26197Ssklower ep->cqe_func = IXC_RECV; /* get frame */ 690*26197Ssklower ep->cqe_ust0 = ep->cqe_ust1 = NPCLEAR; /* Clear status */ 691*26197Ssklower ep->cqe_bcnt = len; /* Byte count */ 692*26197Ssklower ep->cqe_lenrpb = 10; /* RPB length */ 693*26197Ssklower ep->rpb1 = ix->ix_aid; /* which channel */ 694*26197Ssklower ep->rpb2 = 65535; /* Timeout */ 695*26197Ssklower 696*26197Ssklower ix->ix_flags |= IXF_RCVPENDING; 697*26197Ssklower 698*26197Ssklower s = spl4(); 699*26197Ssklower NpAddCQE(ep, &mp->shmemp->devcq, mp); /* Add CQE to device's queue */ 700*26197Ssklower splx(s); 701*26197Ssklower } 702*26197Ssklower 703*26197Ssklower 704*26197Ssklower /* 705*26197Ssklower * Watchdog routine, request statistics from board. 706*26197Ssklower */ 707*26197Ssklower ixwatch(unit) 708*26197Ssklower int unit; 709*26197Ssklower { 710*26197Ssklower register struct ix_softc *ix = &ix_softc[unit]; 711*26197Ssklower register struct ifnet *ifp = &ix->ix_if; 712*26197Ssklower int s; 713*26197Ssklower 714*26197Ssklower if (ix->ix_flags & IXF_STATPENDING) { 715*26197Ssklower ifp->if_timer = ix->ix_scaninterval; 716*26197Ssklower return; 717*26197Ssklower } 718*26197Ssklower s = splimp(); 719*26197Ssklower ix->ix_flags |= IXF_STATPENDING; 720*26197Ssklower if ((ix->ix_flags & IXF_OACTIVE) == 0) 721*26197Ssklower ixstart(ifp->if_unit); 722*26197Ssklower splx(s); 723*26197Ssklower ifp->if_timer = ix->ix_scaninterval; 724*26197Ssklower } 725*26197Ssklower /* 726*26197Ssklower * Process an ioctl request. 727*26197Ssklower */ 728*26197Ssklower ixioctl(ifp, cmd, data) 729*26197Ssklower register struct ifnet *ifp; 730*26197Ssklower int cmd; 731*26197Ssklower caddr_t data; 732*26197Ssklower { 733*26197Ssklower register struct ifaddr *ifa = (struct ifaddr *)data; 734*26197Ssklower register struct ix_softc *ix = &ix_softc[ifp->if_unit]; 735*26197Ssklower int s = splimp(), error = 0; 736*26197Ssklower 737*26197Ssklower switch (cmd) { 738*26197Ssklower 739*26197Ssklower case SIOCSIFADDR: 740*26197Ssklower ifp->if_flags |= IFF_UP; 741*26197Ssklower ixinit(ifp->if_unit); 742*26197Ssklower if ((ifp->if_flags & IFF_UP) == 0) 743*26197Ssklower return (EBUSY); 744*26197Ssklower 745*26197Ssklower switch (ifa->ifa_addr.sa_family) { 746*26197Ssklower #ifdef INET 747*26197Ssklower case AF_INET: 748*26197Ssklower ((struct arpcom *)ifp)->ac_ipaddr = 749*26197Ssklower IA_SIN(ifa)->sin_addr; 750*26197Ssklower arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 751*26197Ssklower break; 752*26197Ssklower #endif 753*26197Ssklower #ifdef NS 754*26197Ssklower case AF_NS: 755*26197Ssklower { 756*26197Ssklower register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 757*26197Ssklower 758*26197Ssklower if (ns_nullhost(*ina)) { 759*26197Ssklower ina->x_host = * (union ns_host *) 760*26197Ssklower (ix_softc[ifp->if_unit].ix_addr); 761*26197Ssklower } else { 762*26197Ssklower return 763*26197Ssklower ix_setaddr(ina->x_host.c_host, ifp->if_unit); 764*26197Ssklower } 765*26197Ssklower break; 766*26197Ssklower } 767*26197Ssklower #endif 768*26197Ssklower } 769*26197Ssklower break; 770*26197Ssklower 771*26197Ssklower case SIOCSIFFLAGS: 772*26197Ssklower if ((ifp->if_flags & IFF_UP) == 0 && 773*26197Ssklower ix->ix_flags & IXF_RUNNING) { 774*26197Ssklower ix->ix_flags &= ~IXF_RUNNING; 775*26197Ssklower NpReset(ix->ix_mp, 0); 776*26197Ssklower } else if (ifp->if_flags & IFF_UP && 777*26197Ssklower (ix->ix_flags & IXF_RUNNING) == 0) 778*26197Ssklower ixinit(ifp->if_unit); 779*26197Ssklower break; 780*26197Ssklower 781*26197Ssklower default: 782*26197Ssklower error = EINVAL; 783*26197Ssklower } 784*26197Ssklower splx(s); 785*26197Ssklower return (error); 786*26197Ssklower } 787*26197Ssklower 788*26197Ssklower /* 789*26197Ssklower * set ethernet address for unit 790*26197Ssklower */ 791*26197Ssklower ix_setaddr(physaddr, unit) 792*26197Ssklower u_char *physaddr; 793*26197Ssklower int unit; 794*26197Ssklower { 795*26197Ssklower register struct ix_softc *ix = &ix_softc[unit]; 796*26197Ssklower 797*26197Ssklower if (! (ix->ix_flags & IXF_RUNNING)) 798*26197Ssklower return (EBUSY); 799*26197Ssklower 800*26197Ssklower /* The following is a big cop out due to the fact that 801*26197Ssklower Changing the ethernet address resets the dla module, 802*26197Ssklower so must re-open the channel, anyway. */ 803*26197Ssklower 804*26197Ssklower 805*26197Ssklower bcopy((caddr_t)physaddr, (caddr_t)ix->ix_addr, sizeof ix->ix_addr); 806*26197Ssklower ix->ix_flags &= ~IXF_RUNNING; 807*26197Ssklower ix->ix_flags |= IXF_SETADDR; 808*26197Ssklower ixinit(unit); 809*26197Ssklower NpKill(ix->ix_mp, ix->ix_rrp); 810*26197Ssklower } 811*26197Ssklower #endif 812