1*34508Skarels /* 2*34508Skarels * Copyright (c) 1988 Regents of the University of California. 3*34508Skarels * All rights reserved. 4*34508Skarels * 5*34508Skarels * Redistribution and use in source and binary forms are permitted 6*34508Skarels * provided that this notice is preserved and that due credit is given 7*34508Skarels * to the University of California at Berkeley. The name of the University 8*34508Skarels * may not be used to endorse or promote products derived from this 9*34508Skarels * software without specific prior written permission. This software 10*34508Skarels * is provided ``as is'' without express or implied warranty. 11*34508Skarels * 12*34508Skarels * @(#)if_enp.c 1.6 (Berkeley) 05/26/88 13*34508Skarels */ 1429649Ssam 1529649Ssam #include "enp.h" 1629649Ssam #if NENP > 0 1729649Ssam /* 1830986Ssam * CMC ENP-20 Ethernet Controller. 1929649Ssam */ 2029649Ssam #include "param.h" 2129649Ssam #include "systm.h" 2229649Ssam #include "mbuf.h" 2329649Ssam #include "buf.h" 2429649Ssam #include "protosw.h" 2529649Ssam #include "socket.h" 2629649Ssam #include "vmmac.h" 2730230Ssam #include "ioctl.h" 2829649Ssam #include "errno.h" 2930230Ssam #include "vmparam.h" 3030230Ssam #include "syslog.h" 3129649Ssam #include "uio.h" 3229649Ssam 3329649Ssam #include "../net/if.h" 3429649Ssam #include "../net/netisr.h" 3529649Ssam #include "../net/route.h" 3630230Ssam #ifdef INET 3729649Ssam #include "../netinet/in.h" 3829649Ssam #include "../netinet/in_systm.h" 3930230Ssam #include "../netinet/in_var.h" 4029649Ssam #include "../netinet/ip.h" 4129649Ssam #include "../netinet/ip_var.h" 4229649Ssam #include "../netinet/if_ether.h" 4330230Ssam #endif 4430230Ssam #ifdef NS 4530230Ssam #include "../netns/ns.h" 4630230Ssam #include "../netns/ns_if.h" 4730230Ssam #endif 4829649Ssam 4930230Ssam #include "../tahoe/cpu.h" 5030230Ssam #include "../tahoe/pte.h" 5130230Ssam #include "../tahoe/mtpr.h" 5230230Ssam 5329649Ssam #include "../tahoevba/vbavar.h" 5430230Ssam #include "../tahoeif/if_enpreg.h" 5529649Ssam 5630230Ssam #define ENPSTART 0xf02000 /* standard enp start addr */ 5730230Ssam #define ENPUNIT(dev) (minor(dev)) /* for enp ram devices */ 5830986Ssam /* macros for dealing with longs in i/o space */ 5930986Ssam #define ENPGETLONG(a) ((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1])) 6030986Ssam #define ENPSETLONG(a,v) \ 6130986Ssam { register u_short *wp = (u_short *)(a); \ 6230986Ssam wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];} 6329649Ssam 6429649Ssam int enpprobe(), enpattach(), enpintr(); 6530298Ssam long enpstd[] = { 0xfff41000, 0xfff61000, 0 }; 6630230Ssam struct vba_device *enpinfo[NENP]; 6729649Ssam struct vba_driver enpdriver = 6830230Ssam { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 }; 6929649Ssam 7030230Ssam int enpinit(), enpioctl(), enpreset(), enpoutput(); 7129649Ssam struct mbuf *enpget(); 7229649Ssam 7329649Ssam /* 7429649Ssam * Ethernet software status per interface. 7529649Ssam * 7629649Ssam * Each interface is referenced by a network interface structure, 7729649Ssam * es_if, which the routing code uses to locate the interface. 7829649Ssam * This structure contains the output queue for the interface, its address, ... 7929649Ssam */ 8030230Ssam struct enp_softc { 8130230Ssam struct arpcom es_ac; /* common ethernet structures */ 8230230Ssam #define es_if es_ac.ac_if 8330986Ssam #define es_addr es_ac.ac_enaddr 8430230Ssam short es_ivec; /* interrupt vector */ 8530230Ssam } enp_softc[NENP]; 8630230Ssam extern struct ifnet loif; 8729649Ssam 8830230Ssam enpprobe(reg, vi) 8930230Ssam caddr_t reg; 9030230Ssam struct vba_device *vi; 9129649Ssam { 9230230Ssam register br, cvec; /* must be r12, r11 */ 9330230Ssam register struct enpdevice *addr = (struct enpdevice *)reg; 9430230Ssam struct enp_softc *es = &enp_softc[vi->ui_unit]; 9529649Ssam 9630230Ssam #ifdef lint 9730295Ssam br = 0; cvec = br; br = cvec; 9830230Ssam enpintr(0); 9930230Ssam #endif 10030295Ssam if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2)) 10130230Ssam return (0); 10230230Ssam es->es_ivec = --vi->ui_hd->vh_lastiv; 10330230Ssam addr->enp_state = S_ENPRESET; /* reset by VERSAbus reset */ 10430230Ssam br = 0x14, cvec = es->es_ivec; /* XXX */ 10530230Ssam return (sizeof (struct enpdevice)); 10629649Ssam } 10729649Ssam 10829649Ssam /* 10929649Ssam * Interface exists: make available by filling in network interface 11029649Ssam * record. System will initialize the interface when it is ready 11129649Ssam * to accept packets. 11229649Ssam */ 11330230Ssam enpattach(ui) 11430230Ssam register struct vba_device *ui; 11529649Ssam { 11630230Ssam struct enp_softc *es = &enp_softc[ui->ui_unit]; 11730230Ssam register struct ifnet *ifp = &es->es_if; 11829649Ssam 11930230Ssam ifp->if_unit = ui->ui_unit; 12029649Ssam ifp->if_name = "enp"; 12129649Ssam ifp->if_mtu = ETHERMTU; 12229649Ssam ifp->if_init = enpinit; 12329649Ssam ifp->if_ioctl = enpioctl; 12429649Ssam ifp->if_output = enpoutput; 12529649Ssam ifp->if_reset = enpreset; 12630230Ssam ifp->if_flags = IFF_BROADCAST; 12729649Ssam if_attach(ifp); 12829649Ssam } 12929649Ssam 13029649Ssam /* 13130230Ssam * Reset of interface after "system" reset. 13229649Ssam */ 13330230Ssam enpreset(unit, vban) 13430230Ssam int unit, vban; 13529649Ssam { 13630230Ssam register struct vba_device *ui; 13729649Ssam 13830230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 13930230Ssam ui->ui_vbanum != vban) 14030230Ssam return; 14130230Ssam printf(" enp%d", unit); 14229649Ssam enpinit(unit); 14329649Ssam } 14429649Ssam 14529649Ssam /* 14630230Ssam * Initialization of interface; clear recorded pending operations. 14729649Ssam */ 14830230Ssam enpinit(unit) 14930230Ssam int unit; 15029649Ssam { 15130230Ssam struct enp_softc *es = &enp_softc[unit]; 15230230Ssam register struct vba_device *ui = enpinfo[unit]; 15330230Ssam struct enpdevice *addr; 15430230Ssam register struct ifnet *ifp = &es->es_if; 15530230Ssam int s; 15629649Ssam 15730230Ssam if (ifp->if_addrlist == (struct ifaddr *)0) 15830230Ssam return; 15930230Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 16030230Ssam addr = (struct enpdevice *)ui->ui_addr; 16130230Ssam s = splimp(); 16230230Ssam RESET_ENP(addr); 16330230Ssam DELAY(200000); 16430230Ssam es->es_if.if_flags |= IFF_RUNNING; 16530230Ssam splx(s); 16629649Ssam } 16729649Ssam } 16829649Ssam 16929649Ssam /* 17029649Ssam * Ethernet interface interrupt. 17129649Ssam */ 17230230Ssam enpintr(unit) 17330230Ssam int unit; 17429649Ssam { 17530230Ssam register struct enpdevice *addr; 17630230Ssam register BCB *bcbp; 17729649Ssam 17830230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 17930295Ssam #if ENP == 30 18030230Ssam if (!IS_ENP_INTR(addr)) 18129649Ssam return; 18230230Ssam ACK_ENP_INTR(addr); 18330295Ssam #endif 18430295Ssam while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) { 18530295Ssam (void) enpread(&enp_softc[unit], bcbp); 18630295Ssam (void) ringput((RING *)&addr->enp_enpfree, bcbp); 18729649Ssam } 18829649Ssam } 18929649Ssam 19029649Ssam /* 19129649Ssam * Read input packet, examine its packet type, and enqueue it. 19229649Ssam */ 19330295Ssam enpread(es, bcbp) 19430230Ssam struct enp_softc *es; 19530230Ssam register BCB *bcbp; 19629649Ssam { 19729649Ssam register struct ether_header *enp; 19829649Ssam struct mbuf *m; 19930295Ssam int s, len, off, resid; 20029649Ssam register struct ifqueue *inq; 20129649Ssam 20229649Ssam es->es_if.if_ipackets++; 20329649Ssam /* 20429649Ssam * Get input data length. 20529649Ssam * Get pointer to ethernet header (in input buffer). 20629649Ssam * Deal with trailer protocol: if type is PUP trailer 20729649Ssam * get true type from first 16-bit word past data. 20829649Ssam * Remember that type was trailer by setting off. 20929649Ssam */ 21030230Ssam len = bcbp->b_msglen - sizeof (struct ether_header); 21130986Ssam enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr); 21230230Ssam #define enpdataaddr(enp, off, type) \ 21330230Ssam ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off)))) 21430230Ssam enp->ether_type = ntohs((u_short)enp->ether_type); 21530230Ssam if (enp->ether_type >= ETHERTYPE_TRAIL && 21630230Ssam enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 21730230Ssam off = (enp->ether_type - ETHERTYPE_TRAIL) * 512; 21830230Ssam if (off >= ETHERMTU) 21930230Ssam goto setup; 22030230Ssam enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *)); 22130230Ssam resid = ntohs(*(enpdataaddr(enp, off+2, u_short *))); 22230230Ssam if (off + resid > len) 22330230Ssam goto setup; 22429649Ssam len = off + resid; 22530230Ssam } else 22629649Ssam off = 0; 22730230Ssam if (len == 0) 22830230Ssam goto setup; 22929649Ssam 23029649Ssam /* 23129649Ssam * Pull packet off interface. Off is nonzero if packet 23229649Ssam * has trailing header; enpget will then force this header 23329649Ssam * information to be at the front, but we still have to drop 23429649Ssam * the type and length which are at the front of any trailer data. 23529649Ssam */ 23630986Ssam m = enpget((u_char *)enp, len, off, &es->es_if); 23730230Ssam if (m == 0) 23830230Ssam goto setup; 23930230Ssam if (off) { 24030230Ssam struct ifnet *ifp; 24129649Ssam 24230230Ssam ifp = *(mtod(m, struct ifnet **)); 24329649Ssam m->m_off += 2 * sizeof (u_short); 24429649Ssam m->m_len -= 2 * sizeof (u_short); 24530230Ssam *(mtod(m, struct ifnet **)) = ifp; 24629649Ssam } 24730230Ssam switch (enp->ether_type) { 24829649Ssam 24929649Ssam #ifdef INET 25030230Ssam case ETHERTYPE_IP: 25129649Ssam schednetisr(NETISR_IP); 25229649Ssam inq = &ipintrq; 25329649Ssam break; 25430230Ssam #endif 25530230Ssam case ETHERTYPE_ARP: 25630230Ssam arpinput(&es->es_ac, m); 25730230Ssam goto setup; 25829649Ssam 25930230Ssam #ifdef NS 26030230Ssam case ETHERTYPE_NS: 26130230Ssam schednetisr(NETISR_NS); 26230230Ssam inq = &nsintrq; 26330230Ssam break; 26429649Ssam #endif 26530230Ssam default: 26629649Ssam m_freem(m); 26730230Ssam goto setup; 26829649Ssam } 26930230Ssam if (IF_QFULL(inq)) { 27029649Ssam IF_DROP(inq); 27129649Ssam m_freem(m); 27230230Ssam goto setup; 27329649Ssam } 27429649Ssam s = splimp(); 27529649Ssam IF_ENQUEUE(inq, m); 27629649Ssam splx(s); 27730230Ssam setup: 27830230Ssam return (0); 27929649Ssam } 28029649Ssam 28129649Ssam /* 28229649Ssam * Ethernet output routine. (called by user) 28329649Ssam * Encapsulate a packet of type family for the local net. 28429649Ssam * Use trailer local net encapsulation if enough data in first 28529649Ssam * packet leaves a multiple of 512 bytes of data in remainder. 28629649Ssam * If destination is this address or broadcast, send packet to 28729649Ssam * loop device to kludge around the fact that 3com interfaces can't 28829649Ssam * talk to themselves. 28929649Ssam */ 29029649Ssam enpoutput(ifp, m0, dst) 29130230Ssam struct ifnet *ifp; 29230230Ssam struct mbuf *m0; 29330230Ssam struct sockaddr *dst; 29429649Ssam { 29529649Ssam register struct enp_softc *es = &enp_softc[ifp->if_unit]; 29629649Ssam register struct mbuf *m = m0; 29729649Ssam register struct ether_header *enp; 29830295Ssam register int off; 29930230Ssam struct mbuf *mcopy = (struct mbuf *)0; 30030230Ssam int type, s, error, usetrailers; 30130230Ssam u_char edst[6]; 30230230Ssam struct in_addr idst; 30329649Ssam 30430230Ssam if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 30530230Ssam error = ENETDOWN; 30630230Ssam goto bad; 30730230Ssam } 30830230Ssam switch (dst->sa_family) { 30929649Ssam #ifdef INET 31029649Ssam case AF_INET: 31129649Ssam idst = ((struct sockaddr_in *)dst)->sin_addr; 31230230Ssam if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers)) 31330230Ssam return (0); /* if not yet resolved */ 31430230Ssam if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, 31530230Ssam sizeof (edst))) 31630230Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 31730230Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 31830230Ssam if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 31930230Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 32030230Ssam type = ETHERTYPE_TRAIL + (off>>9); 32130230Ssam m->m_off -= 2 * sizeof (u_short); 32230230Ssam m->m_len += 2 * sizeof (u_short); 32330986Ssam *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 32430986Ssam *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 32530230Ssam goto gottrailertype; 32629649Ssam } 32730230Ssam type = ETHERTYPE_IP; 32829649Ssam off = 0; 32929649Ssam goto gottype; 33029649Ssam #endif 33130230Ssam #ifdef NS 33230230Ssam case AF_NS: 33330230Ssam bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 33430230Ssam (caddr_t)edst, sizeof (edst)); 33530230Ssam if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst))) 33630230Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 33730230Ssam else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, 33830230Ssam sizeof (edst))) 33930230Ssam return (looutput(&loif, m, dst)); 34030230Ssam type = ETHERTYPE_NS; 34130230Ssam off = 0; 34230230Ssam goto gottype; 34329649Ssam #endif 34429649Ssam case AF_UNSPEC: 34529649Ssam enp = (struct ether_header *)dst->sa_data; 34630230Ssam bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst)); 34729649Ssam type = enp->ether_type; 34829649Ssam goto gottype; 34929649Ssam 35029649Ssam default: 35130230Ssam log(LOG_ERR, "enp%d: can't handle af%d\n", 35230230Ssam ifp->if_unit, dst->sa_family); 35329649Ssam error = EAFNOSUPPORT; 35429649Ssam goto bad; 35529649Ssam } 35629649Ssam 35729649Ssam gottrailertype: 35829649Ssam /* 35929649Ssam * Packet to be sent as trailer: move first packet 36029649Ssam * (control information) to end of chain. 36129649Ssam */ 36229649Ssam while (m->m_next) 36329649Ssam m = m->m_next; 36429649Ssam m->m_next = m0; 36529649Ssam m = m0->m_next; 36629649Ssam m0->m_next = 0; 36729649Ssam m0 = m; 36829649Ssam 36929649Ssam gottype: 37029649Ssam /* 37129649Ssam * Add local net header. If no space in first mbuf, 37229649Ssam * allocate another. 37329649Ssam */ 37429649Ssam if (m->m_off > MMAXOFF || 37530230Ssam MMINOFF + sizeof (struct ether_header) > m->m_off) { 37629649Ssam m = m_get(M_DONTWAIT, MT_HEADER); 37730230Ssam if (m == 0) { 37829649Ssam error = ENOBUFS; 37929649Ssam goto bad; 38029649Ssam } 38129649Ssam m->m_next = m0; 38229649Ssam m->m_off = MMINOFF; 38330230Ssam m->m_len = sizeof (struct ether_header); 38430230Ssam } else { 38530230Ssam m->m_off -= sizeof (struct ether_header); 38630230Ssam m->m_len += sizeof (struct ether_header); 38729649Ssam } 38829649Ssam enp = mtod(m, struct ether_header *); 38930230Ssam bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst)); 39030986Ssam bcopy((caddr_t)es->es_addr, (caddr_t)enp->ether_shost, 39130986Ssam sizeof (es->es_addr)); 39230230Ssam enp->ether_type = htons((u_short)type); 39329649Ssam 39429649Ssam /* 39529649Ssam * Queue message on interface if possible 39629649Ssam */ 39729649Ssam s = splimp(); 39830230Ssam if (enpput(ifp->if_unit, m)) { 39929649Ssam error = ENOBUFS; 40029649Ssam goto qfull; 40129649Ssam } 40230230Ssam splx(s); 40329649Ssam es->es_if.if_opackets++; 40430230Ssam return (mcopy ? looutput(&loif, mcopy, dst) : 0); 40529649Ssam qfull: 40630230Ssam splx(s); 40729649Ssam m0 = m; 40829649Ssam bad: 40929649Ssam m_freem(m0); 41030230Ssam if (mcopy) 41130230Ssam m_freem(mcopy); 41230230Ssam return (error); 41329649Ssam } 41429649Ssam 41529649Ssam /* 41630230Ssam * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus. 41729649Ssam */ 41830230Ssam enpput(unit, m) 41930230Ssam int unit; 42030230Ssam struct mbuf *m; 42129649Ssam { 42229649Ssam register BCB *bcbp; 42330230Ssam register struct enpdevice *addr; 42429649Ssam register struct mbuf *mp; 42529649Ssam register u_char *bp; 42630230Ssam register u_int len; 42730230Ssam u_char *mcp; 42829649Ssam 42930230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 43030295Ssam if (ringempty((RING *)&addr->enp_hostfree)) 43130230Ssam return (1); 43230295Ssam bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree); 43329649Ssam bcbp->b_len = 0; 43430986Ssam bp = (u_char *)ENPGETLONG(&bcbp->b_addr); 43530230Ssam for (mp = m; mp; mp = mp->m_next) { 43629649Ssam len = mp->m_len; 43730230Ssam if (len == 0) 43829649Ssam continue; 43930230Ssam mcp = mtod(mp, u_char *); 44030230Ssam enpcopy(mcp, bp, len); 44129649Ssam bp += len; 44229649Ssam bcbp->b_len += len; 44329649Ssam } 44430986Ssam bcbp->b_len = MAX(ETHERMIN+sizeof (struct ether_header), bcbp->b_len); 44529649Ssam bcbp->b_reserved = 0; 44630295Ssam if (ringput((RING *)&addr->enp_toenp, bcbp) == 1) 44730230Ssam INTR_ENP(addr); 44829649Ssam m_freem(m); 44930230Ssam return (0); 45029649Ssam } 45129649Ssam 45229649Ssam /* 45330230Ssam * Routine to copy from VERSAbus memory into mbufs. 45429649Ssam * 45529649Ssam * Warning: This makes the fairly safe assumption that 45629649Ssam * mbufs have even lengths. 45729649Ssam */ 45829649Ssam struct mbuf * 45930230Ssam enpget(rxbuf, totlen, off0, ifp) 46030230Ssam u_char *rxbuf; 46130230Ssam int totlen, off0; 46230230Ssam struct ifnet *ifp; 46329649Ssam { 46430230Ssam register u_char *cp, *mcp; 46529649Ssam register struct mbuf *m; 46630230Ssam struct mbuf *top = 0, **mp = ⊤ 46730230Ssam int len, off = off0; 46829649Ssam 46930230Ssam cp = rxbuf + sizeof (struct ether_header); 47030230Ssam while (totlen > 0) { 47129649Ssam MGET(m, M_DONTWAIT, MT_DATA); 47229649Ssam if (m == 0) 47329649Ssam goto bad; 47430230Ssam if (off) { 47529649Ssam len = totlen - off; 47630230Ssam cp = rxbuf + sizeof (struct ether_header) + off; 47730230Ssam } else 47829649Ssam len = totlen; 47930230Ssam if (len >= NBPG) { 48030230Ssam MCLGET(m); 48130230Ssam if (m->m_len == CLBYTES) 48230230Ssam m->m_len = len = MIN(len, CLBYTES); 48330230Ssam else 48429649Ssam m->m_len = len = MIN(MLEN, len); 48530230Ssam } else { 48629649Ssam m->m_len = len = MIN(MLEN, len); 48729649Ssam m->m_off = MMINOFF; 48829649Ssam } 48929649Ssam mcp = mtod(m, u_char *); 49030230Ssam if (ifp) { 49130230Ssam /* 49230230Ssam * Prepend interface pointer to first mbuf. 49330230Ssam */ 49430230Ssam *(mtod(m, struct ifnet **)) = ifp; 49530230Ssam mcp += sizeof (ifp); 49630230Ssam len -= sizeof (ifp); 49730230Ssam ifp = (struct ifnet *)0; 49830230Ssam } 49930295Ssam enpcopy(cp, mcp, (u_int)len); 50029649Ssam cp += len; 50129649Ssam *mp = m; 50229649Ssam mp = &m->m_next; 50330230Ssam if (off == 0) { 50429649Ssam totlen -= len; 50529649Ssam continue; 50629649Ssam } 50729649Ssam off += len; 50830230Ssam if (off == totlen) { 50930230Ssam cp = rxbuf + sizeof (struct ether_header); 51029649Ssam off = 0; 51129649Ssam totlen = off0; 51229649Ssam } 51329649Ssam } 51429649Ssam return (top); 51529649Ssam bad: 51629649Ssam m_freem(top); 51729649Ssam return (0); 51829649Ssam } 51929649Ssam 52030230Ssam enpcopy(from, to, cnt) 52130295Ssam register u_char *from, *to; 52230295Ssam register u_int cnt; 52330230Ssam { 52430230Ssam register c; 52530230Ssam register short *f, *t; 52630230Ssam 52730230Ssam if (((int)from&01) && ((int)to&01)) { 52830230Ssam /* source & dest at odd addresses */ 52930230Ssam *to++ = *from++; 53030230Ssam --cnt; 53130230Ssam } 53230230Ssam if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) { 53330230Ssam t = (short *)to; 53430230Ssam f = (short *)from; 53530230Ssam for (c = cnt>>1; c; --c) /* even address copy */ 53630230Ssam *t++ = *f++; 53730230Ssam cnt &= 1; 53830230Ssam if (cnt) { /* odd len */ 53930295Ssam from = (u_char *)f; 54030295Ssam to = (u_char *)t; 54130230Ssam *to = *from; 54230230Ssam } 54330230Ssam } 54430295Ssam while ((int)cnt-- > 0) /* one of the address(es) must be odd */ 54530230Ssam *to++ = *from++; 54630230Ssam } 54730230Ssam 54829649Ssam /* 54929649Ssam * Process an ioctl request. 55029649Ssam */ 55129649Ssam enpioctl(ifp, cmd, data) 55230230Ssam register struct ifnet *ifp; 55330230Ssam int cmd; 55430230Ssam caddr_t data; 55529649Ssam { 55630230Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 55730230Ssam struct enpdevice *addr; 55830230Ssam int s = splimp(), error = 0; 55929649Ssam 56029649Ssam switch (cmd) { 56129649Ssam 56229649Ssam case SIOCSIFADDR: 56330230Ssam ifp->if_flags |= IFF_UP; 56430230Ssam switch (ifa->ifa_addr.sa_family) { 56530230Ssam #ifdef INET 56630230Ssam case AF_INET: 56730230Ssam enpinit(ifp->if_unit); 56830230Ssam ((struct arpcom *)ifp)->ac_ipaddr = 56930230Ssam IA_SIN(ifa)->sin_addr; 57030230Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 57129649Ssam break; 57230230Ssam #endif 57330230Ssam #ifdef NS 57430230Ssam case AF_NS: { 57530230Ssam struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 57630230Ssam struct enp_softc *es = &enp_softc[ifp->if_unit]; 57730230Ssam 57830230Ssam if (!ns_nullhost(*ina)) { 57930230Ssam ifp->if_flags &= ~IFF_RUNNING; 58030230Ssam addr = (struct enpdevice *) 58130230Ssam enpinfo[ifp->if_unit]->ui_addr; 58230230Ssam enpsetaddr(ifp->if_unit, addr, 58330230Ssam ina->x_host.c_host); 58430230Ssam } else 58530986Ssam ina->x_host = *(union ns_host *)es->es_addr; 58630230Ssam enpinit(ifp->if_unit); 58730230Ssam break; 58829649Ssam } 58930230Ssam #endif 59030230Ssam default: 59130230Ssam enpinit(ifp->if_unit); 59230230Ssam break; 59329649Ssam } 59429649Ssam break; 59529649Ssam 59630230Ssam case SIOCSIFFLAGS: 59730230Ssam if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 59830230Ssam enpinit(ifp->if_unit); /* reset board */ 59930230Ssam ifp->if_flags &= ~IFF_RUNNING; 60030230Ssam } else if (ifp->if_flags&IFF_UP && 60130230Ssam (ifp->if_flags&IFF_RUNNING) == 0) 60230230Ssam enpinit(ifp->if_unit); 60329649Ssam break; 60429649Ssam 60529649Ssam default: 60629649Ssam error = EINVAL; 60729649Ssam } 60830230Ssam splx(s); 60930230Ssam return (error); 61029649Ssam } 61129649Ssam 61230230Ssam enpsetaddr(unit, addr, enaddr) 61330230Ssam int unit; 61430230Ssam struct enpdevice *addr; 61530230Ssam u_char *enaddr; 61629649Ssam { 61729649Ssam 61830986Ssam enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr, 61930986Ssam sizeof (struct ether_addr)); 62030230Ssam enpinit(unit); 62130986Ssam enpgetaddr(unit, addr); 62229649Ssam } 62329649Ssam 62430986Ssam enpgetaddr(unit, addr) 62530986Ssam int unit; 62630986Ssam struct enpdevice *addr; 62730986Ssam { 62830986Ssam struct enp_softc *es = &enp_softc[unit]; 62930986Ssam 63030986Ssam enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr, 63130986Ssam sizeof (struct ether_addr)); 63230986Ssam printf("enp%d: hardware address %s\n", 63330986Ssam unit, ether_sprintf(es->es_addr)); 63430986Ssam } 63530986Ssam 63629649Ssam /* 63730230Ssam * Routines to synchronize enp and host. 63829649Ssam */ 63930295Ssam #ifdef notdef 64029649Ssam static 64130230Ssam ringinit(rp, size) 64230230Ssam register RING *rp; 64329649Ssam { 64429649Ssam 64529649Ssam rp->r_rdidx = rp->r_wrtidx = 0; 64629649Ssam rp->r_size = size; 64729649Ssam } 64829649Ssam 64929649Ssam static 65030295Ssam ringfull(rp) 65130230Ssam register RING *rp; 65229649Ssam { 65330295Ssam register short idx; 65430230Ssam 65530295Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 65630295Ssam return (idx == rp->r_rdidx); 65729649Ssam } 65829649Ssam 65929649Ssam static 66030295Ssam fir(rp) 66130230Ssam register RING *rp; 66229649Ssam { 66329649Ssam 66430295Ssam return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0); 66529649Ssam } 66630295Ssam #endif 66729649Ssam 66829649Ssam static 66930295Ssam ringempty(rp) 67030295Ssam register RING *rp; 67130295Ssam { 67230295Ssam 67330295Ssam return (rp->r_rdidx == rp->r_wrtidx); 67430295Ssam } 67530295Ssam 67630295Ssam static 67730230Ssam ringput(rp, v) 67830230Ssam register RING *rp; 67930295Ssam BCB *v; 68029649Ssam { 68129649Ssam register int idx; 68229649Ssam 68329649Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 68430230Ssam if (idx != rp->r_rdidx) { 68530986Ssam ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v); 68629649Ssam rp->r_wrtidx = idx; 68730230Ssam if ((idx -= rp->r_rdidx) < 0) 68829649Ssam idx += rp->r_size; 68930230Ssam return (idx); /* num ring entries */ 69029649Ssam } 69130230Ssam return (0); 69229649Ssam } 69329649Ssam 69429649Ssam static 69530230Ssam ringget(rp) 69630230Ssam register RING *rp; 69729649Ssam { 69829649Ssam register int i = 0; 69929649Ssam 70030230Ssam if (rp->r_rdidx != rp->r_wrtidx) { 70130986Ssam i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]); 70229649Ssam rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1); 70329649Ssam } 70430230Ssam return (i); 70529649Ssam } 70629649Ssam 70730230Ssam /* 70830230Ssam * ENP Ram device. 70930230Ssam */ 71030230Ssam enpr_open(dev) 71130230Ssam dev_t dev; 71229649Ssam { 71330230Ssam register int unit = ENPUNIT(dev); 71430230Ssam struct vba_device *ui; 71530230Ssam struct enpdevice *addr; 71629649Ssam 71730230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 71830230Ssam (addr = (struct enpdevice *)ui->ui_addr) == 0) 71930230Ssam return (ENODEV); 72030230Ssam if (addr->enp_state != S_ENPRESET) 72130230Ssam return (EACCES); /* enp is not in reset state, don't open */ 72230230Ssam return (0); 72329649Ssam } 72429649Ssam 72530295Ssam /*ARGSUSED*/ 72630230Ssam enpr_close(dev) 72730230Ssam dev_t dev; 72829649Ssam { 72929649Ssam 73030230Ssam return (0); 73129649Ssam } 73229649Ssam 73330230Ssam enpr_read(dev, uio) 73430230Ssam dev_t dev; 73530230Ssam register struct uio *uio; 73629649Ssam { 73730230Ssam register struct iovec *iov; 73830230Ssam struct enpdevice *addr; 73929649Ssam 74030230Ssam if (uio->uio_offset > RAM_SIZE) 74130230Ssam return (ENODEV); 74230295Ssam iov = uio->uio_iov; 74330230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 74430230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 74530230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 74630986Ssam if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0) 74730986Ssam return (EFAULT); 74830295Ssam enpcopy((u_char *)&addr->enp_ram[uio->uio_offset], 74930295Ssam (u_char *)iov->iov_base, (u_int)iov->iov_len); 75030230Ssam uio->uio_resid -= iov->iov_len; 75130230Ssam iov->iov_len = 0; 75230230Ssam return (0); 75329649Ssam } 75429649Ssam 75530230Ssam enpr_write(dev, uio) 75630230Ssam dev_t dev; 75730230Ssam register struct uio *uio; 75829649Ssam { 75930230Ssam register struct enpdevice *addr; 76030230Ssam register struct iovec *iov; 76129649Ssam 76230230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 76330230Ssam iov = uio->uio_iov; 76430230Ssam if (uio->uio_offset > RAM_SIZE) 76530230Ssam return (ENODEV); 76630230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 76730230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 76830986Ssam if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0) 76930986Ssam return (EFAULT); 77030295Ssam enpcopy((u_char *)iov->iov_base, 77130295Ssam (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len); 77230230Ssam uio->uio_resid -= iov->iov_len; 77330230Ssam iov->iov_len = 0; 77430230Ssam return (0); 77529649Ssam } 77629649Ssam 77730295Ssam /*ARGSUSED*/ 77830230Ssam enpr_ioctl(dev, cmd, data) 77930230Ssam dev_t dev; 78030230Ssam caddr_t data; 78129649Ssam { 78230230Ssam register unit = ENPUNIT(dev); 78330986Ssam struct enpdevice *addr; 78429649Ssam 78530230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 78630230Ssam switch(cmd) { 78730230Ssam 78830230Ssam case ENPIOGO: 78930986Ssam ENPSETLONG(&addr->enp_base, addr); 79030230Ssam addr->enp_intrvec = enp_softc[unit].es_ivec; 79130230Ssam ENP_GO(addr, ENPSTART); 79230230Ssam DELAY(200000); 79330230Ssam enpinit(unit); 79430986Ssam /* 79530986Ssam * Fetch Ethernet address after link level 79630986Ssam * is booted (firmware copies manufacturer's 79730986Ssam * address from on-board ROM). 79830986Ssam */ 79930986Ssam enpgetaddr(unit, addr); 80030986Ssam addr->enp_state = S_ENPRUN; 80130230Ssam break; 80230230Ssam 80330230Ssam case ENPIORESET: 80430230Ssam RESET_ENP(addr); 80530986Ssam addr->enp_state = S_ENPRESET; 80630230Ssam DELAY(100000); 80730230Ssam break; 80830986Ssam default: 80930986Ssam return (EINVAL); 81029649Ssam } 81130230Ssam return (0); 81229649Ssam } 81329649Ssam #endif 814