1*30230Ssam /* if_enp.c 1.2 86/11/29 */ 229649Ssam 329649Ssam #include "enp.h" 429649Ssam #if NENP > 0 529649Ssam /* 6*30230Ssam * Modified 3Com Ethernet Controller interface 729649Ssam * enp modifications added S. F. Holmgren 8*30230Ssam * 9*30230Ssam * UNTESTED WITH 4.3 1029649Ssam */ 1129649Ssam #include "param.h" 1229649Ssam #include "systm.h" 1329649Ssam #include "mbuf.h" 1429649Ssam #include "buf.h" 1529649Ssam #include "protosw.h" 1629649Ssam #include "socket.h" 1729649Ssam #include "vmmac.h" 18*30230Ssam #include "ioctl.h" 1929649Ssam #include "errno.h" 20*30230Ssam #include "vmparam.h" 21*30230Ssam #include "syslog.h" 2229649Ssam #include "uio.h" 2329649Ssam 2429649Ssam #include "../net/if.h" 2529649Ssam #include "../net/netisr.h" 2629649Ssam #include "../net/route.h" 27*30230Ssam #ifdef INET 2829649Ssam #include "../netinet/in.h" 2929649Ssam #include "../netinet/in_systm.h" 30*30230Ssam #include "../netinet/in_var.h" 3129649Ssam #include "../netinet/ip.h" 3229649Ssam #include "../netinet/ip_var.h" 3329649Ssam #include "../netinet/if_ether.h" 34*30230Ssam #endif 35*30230Ssam #ifdef NS 36*30230Ssam #include "../netns/ns.h" 37*30230Ssam #include "../netns/ns_if.h" 38*30230Ssam #endif 3929649Ssam 40*30230Ssam #include "../tahoe/cpu.h" 41*30230Ssam #include "../tahoe/pte.h" 42*30230Ssam #include "../tahoe/mtpr.h" 43*30230Ssam 4429649Ssam #include "../tahoevba/vbavar.h" 45*30230Ssam #include "../tahoeif/if_enpreg.h" 4629649Ssam 47*30230Ssam #define ENPVEC 0xc1 48*30230Ssam #define ENPSTART 0xf02000 /* standard enp start addr */ 49*30230Ssam #define ENPUNIT(dev) (minor(dev)) /* for enp ram devices */ 5029649Ssam 5129649Ssam int enpprobe(), enpattach(), enpintr(); 52*30230Ssam long enpstd[] = { 0xf41000, 0xf61000, 0 }; 53*30230Ssam struct vba_device *enpinfo[NENP]; 5429649Ssam struct vba_driver enpdriver = 55*30230Ssam { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 }; 5629649Ssam 57*30230Ssam int enpinit(), enpioctl(), enpreset(), enpoutput(); 5829649Ssam struct mbuf *enpget(); 5929649Ssam 6029649Ssam /* 6129649Ssam * Ethernet software status per interface. 6229649Ssam * 6329649Ssam * Each interface is referenced by a network interface structure, 6429649Ssam * es_if, which the routing code uses to locate the interface. 6529649Ssam * This structure contains the output queue for the interface, its address, ... 6629649Ssam */ 67*30230Ssam struct enp_softc { 68*30230Ssam struct arpcom es_ac; /* common ethernet structures */ 69*30230Ssam #define es_if es_ac.ac_if 70*30230Ssam #define es_enaddr es_ac.ac_enaddr 71*30230Ssam short es_flags; /* flags for devices */ 72*30230Ssam short es_ivec; /* interrupt vector */ 73*30230Ssam struct pte *es_map; /* map for dual ported memory */ 74*30230Ssam caddr_t es_ram; /* virtual address of mapped memory */ 75*30230Ssam } enp_softc[NENP]; 76*30230Ssam extern struct ifnet loif; 7729649Ssam 78*30230Ssam enpprobe(reg, vi) 79*30230Ssam caddr_t reg; 80*30230Ssam struct vba_device *vi; 8129649Ssam { 82*30230Ssam register br, cvec; /* must be r12, r11 */ 83*30230Ssam register struct enpdevice *addr = (struct enpdevice *)reg; 84*30230Ssam struct enp_softc *es = &enp_softc[vi->ui_unit]; 8529649Ssam 86*30230Ssam #ifdef lint 87*30230Ssam enpintr(0); 88*30230Ssam #endif 89*30230Ssam if (badaddr(addr, 2) || badaddr(&addr->enp_ram[0], 2)) 90*30230Ssam return (0); 91*30230Ssam es->es_ivec = --vi->ui_hd->vh_lastiv; 92*30230Ssam addr->enp_state = S_ENPRESET; /* reset by VERSAbus reset */ 93*30230Ssam br = 0x14, cvec = es->es_ivec; /* XXX */ 94*30230Ssam return (sizeof (struct enpdevice)); 9529649Ssam } 9629649Ssam 9729649Ssam /* 9829649Ssam * Interface exists: make available by filling in network interface 9929649Ssam * record. System will initialize the interface when it is ready 10029649Ssam * to accept packets. 10129649Ssam */ 102*30230Ssam enpattach(ui) 103*30230Ssam register struct vba_device *ui; 10429649Ssam { 105*30230Ssam struct enp_softc *es = &enp_softc[ui->ui_unit]; 106*30230Ssam register struct ifnet *ifp = &es->es_if; 107*30230Ssam register struct enpdevice *addr = (struct enpdevice *)ui->ui_addr; 10829649Ssam 109*30230Ssam ifp->if_unit = ui->ui_unit; 11029649Ssam ifp->if_name = "enp"; 11129649Ssam ifp->if_mtu = ETHERMTU; 112*30230Ssam /* 113*30230Ssam * Get station's addresses. 114*30230Ssam */ 115*30230Ssam enpcopy(&addr->enp_addr.e_baseaddr, es->es_enaddr, 116*30230Ssam sizeof (es->es_enaddr)); 117*30230Ssam printf("enp%d: hardware address %s\n", ui->ui_unit, 118*30230Ssam ether_sprintf(es->es_enaddr)); 119*30230Ssam /* 120*30230Ssam * Allocate and map ram. 121*30230Ssam */ 122*30230Ssam vbmemalloc(128, ((caddr_t)addr)+0x1000, &es->es_map, &es->es_ram); 12329649Ssam 12429649Ssam ifp->if_init = enpinit; 12529649Ssam ifp->if_ioctl = enpioctl; 12629649Ssam ifp->if_output = enpoutput; 12729649Ssam ifp->if_reset = enpreset; 128*30230Ssam ifp->if_flags = IFF_BROADCAST; 12929649Ssam if_attach(ifp); 13029649Ssam } 13129649Ssam 13229649Ssam /* 133*30230Ssam * Reset of interface after "system" reset. 13429649Ssam */ 135*30230Ssam enpreset(unit, vban) 136*30230Ssam int unit, vban; 13729649Ssam { 138*30230Ssam register struct vba_device *ui; 13929649Ssam 140*30230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 141*30230Ssam ui->ui_vbanum != vban) 142*30230Ssam return; 143*30230Ssam printf(" enp%d", unit); 14429649Ssam enpinit(unit); 14529649Ssam } 14629649Ssam 14729649Ssam /* 148*30230Ssam * Initialization of interface; clear recorded pending operations. 14929649Ssam */ 150*30230Ssam enpinit(unit) 151*30230Ssam int unit; 15229649Ssam { 153*30230Ssam struct enp_softc *es = &enp_softc[unit]; 154*30230Ssam register struct vba_device *ui = enpinfo[unit]; 155*30230Ssam struct enpdevice *addr; 156*30230Ssam register struct ifnet *ifp = &es->es_if; 157*30230Ssam int s; 15829649Ssam 159*30230Ssam if (ifp->if_addrlist == (struct ifaddr *)0) 160*30230Ssam return; 161*30230Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 162*30230Ssam addr = (struct enpdevice *)ui->ui_addr; 163*30230Ssam s = splimp(); 164*30230Ssam RESET_ENP(addr); 165*30230Ssam DELAY(200000); 166*30230Ssam addr->enp_intrvec = es->es_ivec; 167*30230Ssam es->es_if.if_flags |= IFF_RUNNING; 168*30230Ssam splx(s); 16929649Ssam } 17029649Ssam } 17129649Ssam 17229649Ssam /* 17329649Ssam * Ethernet interface interrupt. 17429649Ssam */ 175*30230Ssam enpintr(unit) 176*30230Ssam int unit; 17729649Ssam { 178*30230Ssam register struct enpdevice *addr; 179*30230Ssam register BCB *bcbp; 18029649Ssam 181*30230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 182*30230Ssam if (!IS_ENP_INTR(addr)) 18329649Ssam return; 184*30230Ssam ACK_ENP_INTR(addr); 185*30230Ssam while ((bcbp = (BCB *)ringget(&addr->enp_tohost )) != 0) { 186*30230Ssam (void) enpread(&enp_softc[unit], bcbp, unit); 187*30230Ssam ringput(&addr->enp_enpfree, bcbp); 18829649Ssam } 18929649Ssam } 19029649Ssam 19129649Ssam /* 19229649Ssam * Read input packet, examine its packet type, and enqueue it. 19329649Ssam */ 194*30230Ssam enpread(es, bcbp, unit) 195*30230Ssam struct enp_softc *es; 196*30230Ssam register BCB *bcbp; 197*30230Ssam int unit; 19829649Ssam { 19929649Ssam register struct ether_header *enp; 20029649Ssam struct mbuf *m; 201*30230Ssam long int s; 20229649Ssam int len, off, resid, enptype; 20329649Ssam register struct ifqueue *inq; 20429649Ssam 20529649Ssam es->es_if.if_ipackets++; 20629649Ssam /* 20729649Ssam * Get input data length. 20829649Ssam * Get pointer to ethernet header (in input buffer). 20929649Ssam * Deal with trailer protocol: if type is PUP trailer 21029649Ssam * get true type from first 16-bit word past data. 21129649Ssam * Remember that type was trailer by setting off. 21229649Ssam */ 213*30230Ssam len = bcbp->b_msglen - sizeof (struct ether_header); 21429649Ssam enp = (struct ether_header *)bcbp->b_addr; 215*30230Ssam #define enpdataaddr(enp, off, type) \ 216*30230Ssam ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off)))) 217*30230Ssam enp->ether_type = ntohs((u_short)enp->ether_type); 218*30230Ssam if (enp->ether_type >= ETHERTYPE_TRAIL && 219*30230Ssam enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 220*30230Ssam off = (enp->ether_type - ETHERTYPE_TRAIL) * 512; 221*30230Ssam if (off >= ETHERMTU) 222*30230Ssam goto setup; 223*30230Ssam enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *)); 224*30230Ssam resid = ntohs(*(enpdataaddr(enp, off+2, u_short *))); 225*30230Ssam if (off + resid > len) 226*30230Ssam goto setup; 22729649Ssam len = off + resid; 228*30230Ssam } else 22929649Ssam off = 0; 230*30230Ssam if (len == 0) 231*30230Ssam goto setup; 23229649Ssam 23329649Ssam /* 23429649Ssam * Pull packet off interface. Off is nonzero if packet 23529649Ssam * has trailing header; enpget will then force this header 23629649Ssam * information to be at the front, but we still have to drop 23729649Ssam * the type and length which are at the front of any trailer data. 23829649Ssam */ 239*30230Ssam m = enpget(bcbp->b_addr, len, off, &es->es_if); 240*30230Ssam if (m == 0) 241*30230Ssam goto setup; 242*30230Ssam if (off) { 243*30230Ssam struct ifnet *ifp; 24429649Ssam 245*30230Ssam ifp = *(mtod(m, struct ifnet **)); 24629649Ssam m->m_off += 2 * sizeof (u_short); 24729649Ssam m->m_len -= 2 * sizeof (u_short); 248*30230Ssam *(mtod(m, struct ifnet **)) = ifp; 24929649Ssam } 250*30230Ssam switch (enp->ether_type) { 25129649Ssam 25229649Ssam #ifdef INET 253*30230Ssam case ETHERTYPE_IP: 25429649Ssam schednetisr(NETISR_IP); 25529649Ssam inq = &ipintrq; 25629649Ssam break; 257*30230Ssam #endif 258*30230Ssam case ETHERTYPE_ARP: 259*30230Ssam arpinput(&es->es_ac, m); 260*30230Ssam goto setup; 26129649Ssam 262*30230Ssam #ifdef NS 263*30230Ssam case ETHERTYPE_NS: 264*30230Ssam schednetisr(NETISR_NS); 265*30230Ssam inq = &nsintrq; 266*30230Ssam break; 26729649Ssam #endif 268*30230Ssam default: 26929649Ssam m_freem(m); 270*30230Ssam goto setup; 27129649Ssam } 272*30230Ssam if (IF_QFULL(inq)) { 27329649Ssam IF_DROP(inq); 27429649Ssam m_freem(m); 275*30230Ssam goto setup; 27629649Ssam } 27729649Ssam s = splimp(); 27829649Ssam IF_ENQUEUE(inq, m); 27929649Ssam splx(s); 280*30230Ssam setup: 281*30230Ssam return (0); 28229649Ssam } 28329649Ssam 28429649Ssam /* 28529649Ssam * Ethernet output routine. (called by user) 28629649Ssam * Encapsulate a packet of type family for the local net. 28729649Ssam * Use trailer local net encapsulation if enough data in first 28829649Ssam * packet leaves a multiple of 512 bytes of data in remainder. 28929649Ssam * If destination is this address or broadcast, send packet to 29029649Ssam * loop device to kludge around the fact that 3com interfaces can't 29129649Ssam * talk to themselves. 29229649Ssam */ 29329649Ssam enpoutput(ifp, m0, dst) 294*30230Ssam struct ifnet *ifp; 295*30230Ssam struct mbuf *m0; 296*30230Ssam struct sockaddr *dst; 29729649Ssam { 29829649Ssam register struct enp_softc *es = &enp_softc[ifp->if_unit]; 29929649Ssam register struct mbuf *m = m0; 30029649Ssam register struct ether_header *enp; 30129649Ssam register int off, i; 302*30230Ssam struct mbuf *mcopy = (struct mbuf *)0; 303*30230Ssam int type, s, error, usetrailers; 304*30230Ssam u_char edst[6]; 305*30230Ssam struct in_addr idst; 30629649Ssam 307*30230Ssam if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 308*30230Ssam error = ENETDOWN; 309*30230Ssam goto bad; 310*30230Ssam } 311*30230Ssam switch (dst->sa_family) { 31229649Ssam #ifdef INET 31329649Ssam case AF_INET: 31429649Ssam idst = ((struct sockaddr_in *)dst)->sin_addr; 315*30230Ssam if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers)) 316*30230Ssam return (0); /* if not yet resolved */ 317*30230Ssam if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, 318*30230Ssam sizeof (edst))) 319*30230Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 320*30230Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 321*30230Ssam if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 322*30230Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 323*30230Ssam type = ETHERTYPE_TRAIL + (off>>9); 324*30230Ssam m->m_off -= 2 * sizeof (u_short); 325*30230Ssam m->m_len += 2 * sizeof (u_short); 326*30230Ssam *mtod(m, u_short *) = ETHERTYPE_IP; 327*30230Ssam *(mtod(m, u_short *) + 1) = m->m_len; 328*30230Ssam goto gottrailertype; 32929649Ssam } 330*30230Ssam type = ETHERTYPE_IP; 33129649Ssam off = 0; 33229649Ssam goto gottype; 33329649Ssam #endif 334*30230Ssam #ifdef NS 335*30230Ssam case AF_NS: 336*30230Ssam bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 337*30230Ssam (caddr_t)edst, sizeof (edst)); 338*30230Ssam if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst))) 339*30230Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 340*30230Ssam else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, 341*30230Ssam sizeof (edst))) 342*30230Ssam return (looutput(&loif, m, dst)); 343*30230Ssam type = ETHERTYPE_NS; 344*30230Ssam off = 0; 345*30230Ssam goto gottype; 34629649Ssam #endif 34729649Ssam case AF_UNSPEC: 34829649Ssam enp = (struct ether_header *)dst->sa_data; 349*30230Ssam bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst)); 35029649Ssam type = enp->ether_type; 35129649Ssam goto gottype; 35229649Ssam 35329649Ssam default: 354*30230Ssam log(LOG_ERR, "enp%d: can't handle af%d\n", 355*30230Ssam ifp->if_unit, dst->sa_family); 35629649Ssam error = EAFNOSUPPORT; 35729649Ssam goto bad; 35829649Ssam } 35929649Ssam 36029649Ssam gottrailertype: 36129649Ssam /* 36229649Ssam * Packet to be sent as trailer: move first packet 36329649Ssam * (control information) to end of chain. 36429649Ssam */ 36529649Ssam while (m->m_next) 36629649Ssam m = m->m_next; 36729649Ssam m->m_next = m0; 36829649Ssam m = m0->m_next; 36929649Ssam m0->m_next = 0; 37029649Ssam m0 = m; 37129649Ssam 37229649Ssam gottype: 37329649Ssam /* 37429649Ssam * Add local net header. If no space in first mbuf, 37529649Ssam * allocate another. 37629649Ssam */ 37729649Ssam if (m->m_off > MMAXOFF || 378*30230Ssam MMINOFF + sizeof (struct ether_header) > m->m_off) { 37929649Ssam m = m_get(M_DONTWAIT, MT_HEADER); 380*30230Ssam if (m == 0) { 38129649Ssam error = ENOBUFS; 38229649Ssam goto bad; 38329649Ssam } 38429649Ssam m->m_next = m0; 38529649Ssam m->m_off = MMINOFF; 386*30230Ssam m->m_len = sizeof (struct ether_header); 387*30230Ssam } else { 388*30230Ssam m->m_off -= sizeof (struct ether_header); 389*30230Ssam m->m_len += sizeof (struct ether_header); 39029649Ssam } 39129649Ssam enp = mtod(m, struct ether_header *); 392*30230Ssam bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst)); 393*30230Ssam bcopy((caddr_t)es->es_enaddr, (caddr_t)enp->ether_shost, 394*30230Ssam sizeof (es->es_enaddr)); 395*30230Ssam enp->ether_type = htons((u_short)type); 39629649Ssam 39729649Ssam /* 39829649Ssam * Queue message on interface if possible 39929649Ssam */ 40029649Ssam s = splimp(); 401*30230Ssam if (enpput(ifp->if_unit, m)) { 40229649Ssam error = ENOBUFS; 40329649Ssam goto qfull; 40429649Ssam } 405*30230Ssam splx(s); 40629649Ssam es->es_if.if_opackets++; 407*30230Ssam return (mcopy ? looutput(&loif, mcopy, dst) : 0); 40829649Ssam qfull: 409*30230Ssam splx(s); 41029649Ssam m0 = m; 41129649Ssam bad: 41229649Ssam m_freem(m0); 413*30230Ssam if (mcopy) 414*30230Ssam m_freem(mcopy); 415*30230Ssam return (error); 41629649Ssam } 41729649Ssam 41829649Ssam /* 419*30230Ssam * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus. 42029649Ssam */ 421*30230Ssam enpput(unit, m) 422*30230Ssam int unit; 423*30230Ssam struct mbuf *m; 42429649Ssam { 42529649Ssam register BCB *bcbp; 426*30230Ssam register struct enpdevice *addr; 42729649Ssam register struct mbuf *mp; 42829649Ssam register u_char *bp; 429*30230Ssam register u_int len; 430*30230Ssam u_char *mcp; 43129649Ssam 432*30230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 433*30230Ssam if (ringempty(&addr->enp_hostfree)) 434*30230Ssam return (1); 435*30230Ssam bcbp = (BCB *)ringget(&addr->enp_hostfree); 43629649Ssam bcbp->b_len = 0; 43729649Ssam bp = (u_char *)bcbp->b_addr; 438*30230Ssam for (mp = m; mp; mp = mp->m_next) { 43929649Ssam len = mp->m_len; 440*30230Ssam if (len == 0) 44129649Ssam continue; 442*30230Ssam mcp = mtod(mp, u_char *); 443*30230Ssam enpcopy(mcp, bp, len); 44429649Ssam bp += len; 44529649Ssam bcbp->b_len += len; 44629649Ssam } 447*30230Ssam bcbp->b_len = max(ETHERMIN, bcbp->b_len); 44829649Ssam bcbp->b_reserved = 0; 449*30230Ssam if (ringput(&addr->enp_toenp, bcbp) == 1) 450*30230Ssam INTR_ENP(addr); 45129649Ssam m_freem(m); 452*30230Ssam return (0); 45329649Ssam } 45429649Ssam 45529649Ssam /* 456*30230Ssam * Routine to copy from VERSAbus memory into mbufs. 45729649Ssam * 45829649Ssam * Warning: This makes the fairly safe assumption that 45929649Ssam * mbufs have even lengths. 46029649Ssam */ 46129649Ssam struct mbuf * 462*30230Ssam enpget(rxbuf, totlen, off0, ifp) 463*30230Ssam u_char *rxbuf; 464*30230Ssam int totlen, off0; 465*30230Ssam struct ifnet *ifp; 46629649Ssam { 467*30230Ssam register u_char *cp, *mcp; 46829649Ssam register struct mbuf *m; 469*30230Ssam struct mbuf *top = 0, **mp = ⊤ 470*30230Ssam int len, off = off0; 47129649Ssam 472*30230Ssam cp = rxbuf + sizeof (struct ether_header); 473*30230Ssam while (totlen > 0) { 47429649Ssam MGET(m, M_DONTWAIT, MT_DATA); 47529649Ssam if (m == 0) 47629649Ssam goto bad; 477*30230Ssam if (off) { 47829649Ssam len = totlen - off; 479*30230Ssam cp = rxbuf + sizeof (struct ether_header) + off; 480*30230Ssam } else 48129649Ssam len = totlen; 482*30230Ssam if (len >= NBPG) { 48329649Ssam struct mbuf *p; 48429649Ssam 485*30230Ssam MCLGET(m); 486*30230Ssam if (m->m_len == CLBYTES) 487*30230Ssam m->m_len = len = MIN(len, CLBYTES); 488*30230Ssam else 48929649Ssam m->m_len = len = MIN(MLEN, len); 490*30230Ssam } else { 49129649Ssam m->m_len = len = MIN(MLEN, len); 49229649Ssam m->m_off = MMINOFF; 49329649Ssam } 49429649Ssam mcp = mtod(m, u_char *); 495*30230Ssam if (ifp) { 496*30230Ssam /* 497*30230Ssam * Prepend interface pointer to first mbuf. 498*30230Ssam */ 499*30230Ssam *(mtod(m, struct ifnet **)) = ifp; 500*30230Ssam mcp += sizeof (ifp); 501*30230Ssam len -= sizeof (ifp); 502*30230Ssam ifp = (struct ifnet *)0; 503*30230Ssam } 50429649Ssam enpcopy(cp, mcp, len); 50529649Ssam cp += len; 50629649Ssam *mp = m; 50729649Ssam mp = &m->m_next; 508*30230Ssam if (off == 0) { 50929649Ssam totlen -= len; 51029649Ssam continue; 51129649Ssam } 51229649Ssam off += len; 513*30230Ssam if (off == totlen) { 514*30230Ssam cp = rxbuf + sizeof (struct ether_header); 51529649Ssam off = 0; 51629649Ssam totlen = off0; 51729649Ssam } 51829649Ssam } 51929649Ssam return (top); 52029649Ssam bad: 52129649Ssam m_freem(top); 52229649Ssam return (0); 52329649Ssam } 52429649Ssam 525*30230Ssam enpcopy(from, to, cnt) 526*30230Ssam register char *from, *to; 527*30230Ssam register cnt; 528*30230Ssam { 529*30230Ssam register c; 530*30230Ssam register short *f, *t; 531*30230Ssam 532*30230Ssam if (((int)from&01) && ((int)to&01)) { 533*30230Ssam /* source & dest at odd addresses */ 534*30230Ssam *to++ = *from++; 535*30230Ssam --cnt; 536*30230Ssam } 537*30230Ssam if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) { 538*30230Ssam t = (short *)to; 539*30230Ssam f = (short *)from; 540*30230Ssam for (c = cnt>>1; c; --c) /* even address copy */ 541*30230Ssam *t++ = *f++; 542*30230Ssam cnt &= 1; 543*30230Ssam if (cnt) { /* odd len */ 544*30230Ssam from = (char *)f; 545*30230Ssam to = (char *)t; 546*30230Ssam *to = *from; 547*30230Ssam } 548*30230Ssam } 549*30230Ssam while (cnt-- > 0) /* one of the address(es) must be odd */ 550*30230Ssam *to++ = *from++; 551*30230Ssam } 552*30230Ssam 55329649Ssam /* 55429649Ssam * Process an ioctl request. 55529649Ssam */ 55629649Ssam enpioctl(ifp, cmd, data) 557*30230Ssam register struct ifnet *ifp; 558*30230Ssam int cmd; 559*30230Ssam caddr_t data; 56029649Ssam { 561*30230Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 562*30230Ssam struct enpdevice *addr; 563*30230Ssam int s = splimp(), error = 0; 56429649Ssam 56529649Ssam switch (cmd) { 56629649Ssam 56729649Ssam case SIOCSIFADDR: 568*30230Ssam ifp->if_flags |= IFF_UP; 569*30230Ssam switch (ifa->ifa_addr.sa_family) { 570*30230Ssam #ifdef INET 571*30230Ssam case AF_INET: 572*30230Ssam enpinit(ifp->if_unit); 573*30230Ssam ((struct arpcom *)ifp)->ac_ipaddr = 574*30230Ssam IA_SIN(ifa)->sin_addr; 575*30230Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 57629649Ssam break; 577*30230Ssam #endif 578*30230Ssam #ifdef NS 579*30230Ssam case AF_NS: { 580*30230Ssam struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 581*30230Ssam struct enp_softc *es = &enp_softc[ifp->if_unit]; 582*30230Ssam 583*30230Ssam if (!ns_nullhost(*ina)) { 584*30230Ssam ifp->if_flags &= ~IFF_RUNNING; 585*30230Ssam addr = (struct enpdevice *) 586*30230Ssam enpinfo[ifp->if_unit]->ui_addr; 587*30230Ssam enpsetaddr(ifp->if_unit, addr, 588*30230Ssam ina->x_host.c_host); 589*30230Ssam } else 590*30230Ssam ina->x_host = *(union ns_host *)es->es_enaddr; 591*30230Ssam enpinit(ifp->if_unit); 592*30230Ssam break; 59329649Ssam } 594*30230Ssam #endif 595*30230Ssam default: 596*30230Ssam enpinit(ifp->if_unit); 597*30230Ssam break; 59829649Ssam } 59929649Ssam break; 60029649Ssam 601*30230Ssam case SIOCSIFFLAGS: 602*30230Ssam if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 603*30230Ssam enpinit(ifp->if_unit); /* reset board */ 604*30230Ssam ifp->if_flags &= ~IFF_RUNNING; 605*30230Ssam } else if (ifp->if_flags&IFF_UP && 606*30230Ssam (ifp->if_flags&IFF_RUNNING) == 0) 607*30230Ssam enpinit(ifp->if_unit); 60829649Ssam break; 60929649Ssam 61029649Ssam default: 61129649Ssam error = EINVAL; 61229649Ssam } 613*30230Ssam splx(s); 614*30230Ssam return (error); 61529649Ssam } 61629649Ssam 617*30230Ssam enpsetaddr(unit, addr, enaddr) 618*30230Ssam int unit; 619*30230Ssam struct enpdevice *addr; 620*30230Ssam u_char *enaddr; 62129649Ssam { 622*30230Ssam u_char *cp; 623*30230Ssam int i, code; 62429649Ssam 625*30230Ssam cp = &addr->enp_addr.e_baseaddr.ea_addr[0]; 626*30230Ssam for (i = 0; i < 6; i++) 627*30230Ssam *cp++ = ~*enaddr++; 628*30230Ssam enpcopy(&addr->enp_addr.e_listsize, &code, sizeof (code)); 629*30230Ssam code |= E_ADDR_SUPP; 630*30230Ssam enpcopy(&code, &addr->enp_addr.e_listsize, sizeof (code)); 631*30230Ssam enpinit(unit); 63229649Ssam } 63329649Ssam 63429649Ssam /* 635*30230Ssam * Routines to synchronize enp and host. 63629649Ssam */ 63729649Ssam static 638*30230Ssam ringinit(rp, size) 639*30230Ssam register RING *rp; 64029649Ssam { 641*30230Ssam register int i; 64229649Ssam register short *sp; 64329649Ssam 64429649Ssam rp->r_rdidx = rp->r_wrtidx = 0; 64529649Ssam rp->r_size = size; 64629649Ssam } 64729649Ssam 64829649Ssam static 649*30230Ssam ringempty(rp) 650*30230Ssam register RING *rp; 65129649Ssam { 652*30230Ssam 653*30230Ssam return (rp->r_rdidx == rp->r_wrtidx); 65429649Ssam } 65529649Ssam 65629649Ssam static 657*30230Ssam ringfull(rp) 658*30230Ssam register RING *rp; 65929649Ssam { 66029649Ssam register short idx; 66129649Ssam 66229649Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 663*30230Ssam return (idx == rp->r_rdidx); 66429649Ssam } 66529649Ssam 66629649Ssam static 667*30230Ssam ringput(rp, v) 668*30230Ssam register RING *rp; 66929649Ssam { 67029649Ssam register int idx; 67129649Ssam 67229649Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 673*30230Ssam if (idx != rp->r_rdidx) { 674*30230Ssam rp->r_slot[rp->r_wrtidx] = v; 67529649Ssam rp->r_wrtidx = idx; 676*30230Ssam if ((idx -= rp->r_rdidx) < 0) 67729649Ssam idx += rp->r_size; 678*30230Ssam return (idx); /* num ring entries */ 67929649Ssam } 680*30230Ssam return (0); 68129649Ssam } 68229649Ssam 68329649Ssam static 684*30230Ssam ringget(rp) 685*30230Ssam register RING *rp; 68629649Ssam { 68729649Ssam register int i = 0; 68829649Ssam 689*30230Ssam if (rp->r_rdidx != rp->r_wrtidx) { 690*30230Ssam i = rp->r_slot[rp->r_rdidx]; 69129649Ssam rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1); 69229649Ssam } 693*30230Ssam return (i); 69429649Ssam } 69529649Ssam 696*30230Ssam static 697*30230Ssam fir(rp) 698*30230Ssam register RING *rp; 69929649Ssam { 70029649Ssam 701*30230Ssam return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0); 70229649Ssam } 703*30230Ssam 704*30230Ssam /* 705*30230Ssam * ENP Ram device. 706*30230Ssam */ 707*30230Ssam enpr_open(dev) 708*30230Ssam dev_t dev; 70929649Ssam { 710*30230Ssam register int unit = ENPUNIT(dev); 711*30230Ssam struct vba_device *ui; 712*30230Ssam struct enpdevice *addr; 71329649Ssam 714*30230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 715*30230Ssam (addr = (struct enpdevice *)ui->ui_addr) == 0) 716*30230Ssam return (ENODEV); 717*30230Ssam if (addr->enp_state != S_ENPRESET) 718*30230Ssam return (EACCES); /* enp is not in reset state, don't open */ 719*30230Ssam return (0); 72029649Ssam } 72129649Ssam 722*30230Ssam enpr_close(dev) 723*30230Ssam dev_t dev; 72429649Ssam { 72529649Ssam 726*30230Ssam return (0); 72729649Ssam } 72829649Ssam 729*30230Ssam enpr_read(dev, uio) 730*30230Ssam dev_t dev; 731*30230Ssam register struct uio *uio; 73229649Ssam { 733*30230Ssam register struct iovec *iov; 734*30230Ssam struct enpdevice *addr; 735*30230Ssam int error; 73629649Ssam 737*30230Ssam if (uio->uio_offset > RAM_SIZE) 738*30230Ssam return (ENODEV); 739*30230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 740*30230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 741*30230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 742*30230Ssam iov = uio->uio_iov; 743*30230Ssam error = useracc(iov->iov_base, iov->iov_len, 0); 744*30230Ssam if (error) 745*30230Ssam return (error); 746*30230Ssam enpcopy(&addr->enp_ram[uio->uio_offset], iov->iov_base, iov->iov_len); 747*30230Ssam uio->uio_resid -= iov->iov_len; 748*30230Ssam iov->iov_len = 0; 749*30230Ssam return (0); 75029649Ssam } 75129649Ssam 752*30230Ssam enpr_write(dev, uio) 753*30230Ssam dev_t dev; 754*30230Ssam register struct uio *uio; 75529649Ssam { 756*30230Ssam register struct enpdevice *addr; 757*30230Ssam register struct iovec *iov; 758*30230Ssam register error; 75929649Ssam 760*30230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 761*30230Ssam iov = uio->uio_iov; 762*30230Ssam if (uio->uio_offset > RAM_SIZE) 763*30230Ssam return (ENODEV); 764*30230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 765*30230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 766*30230Ssam error = useracc(iov->iov_base, iov->iov_len, 1); 767*30230Ssam if (error) 768*30230Ssam return (error); 769*30230Ssam enpcopy(iov->iov_base, &addr->enp_ram[uio->uio_offset], iov->iov_len); 770*30230Ssam uio->uio_resid -= iov->iov_len; 771*30230Ssam iov->iov_len = 0; 772*30230Ssam return (0); 77329649Ssam } 77429649Ssam 775*30230Ssam enpr_ioctl(dev, cmd, data) 776*30230Ssam dev_t dev; 777*30230Ssam caddr_t data; 77829649Ssam { 779*30230Ssam register struct enpdevice *addr; 780*30230Ssam register unit = ENPUNIT(dev); 781*30230Ssam register struct vba_device *ui; 78229649Ssam 783*30230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 784*30230Ssam switch(cmd) { 785*30230Ssam 786*30230Ssam case ENPIOGO: 787*30230Ssam /* not needed if prom based version */ 788*30230Ssam addr->enp_base = (int)addr; 789*30230Ssam addr->enp_intrvec = enp_softc[unit].es_ivec; 790*30230Ssam ENP_GO(addr, ENPSTART); 791*30230Ssam DELAY(200000); 792*30230Ssam enpinit(unit); 793*30230Ssam addr->enp_state = S_ENPRUN; /* it is running now */ 794*30230Ssam /* end of not needed */ 795*30230Ssam break; 796*30230Ssam 797*30230Ssam case ENPIORESET: 798*30230Ssam RESET_ENP(addr); 799*30230Ssam addr->enp_state = S_ENPRESET; /* it is reset now */ 800*30230Ssam DELAY(100000); 801*30230Ssam break; 80229649Ssam } 803*30230Ssam return (0); 80429649Ssam } 80529649Ssam #endif 806