1*30986Ssam /* if_enp.c 1.5 87/04/29 */ 229649Ssam 329649Ssam #include "enp.h" 429649Ssam #if NENP > 0 529649Ssam /* 6*30986Ssam * CMC ENP-20 Ethernet Controller. 729649Ssam */ 829649Ssam #include "param.h" 929649Ssam #include "systm.h" 1029649Ssam #include "mbuf.h" 1129649Ssam #include "buf.h" 1229649Ssam #include "protosw.h" 1329649Ssam #include "socket.h" 1429649Ssam #include "vmmac.h" 1530230Ssam #include "ioctl.h" 1629649Ssam #include "errno.h" 1730230Ssam #include "vmparam.h" 1830230Ssam #include "syslog.h" 1929649Ssam #include "uio.h" 2029649Ssam 2129649Ssam #include "../net/if.h" 2229649Ssam #include "../net/netisr.h" 2329649Ssam #include "../net/route.h" 2430230Ssam #ifdef INET 2529649Ssam #include "../netinet/in.h" 2629649Ssam #include "../netinet/in_systm.h" 2730230Ssam #include "../netinet/in_var.h" 2829649Ssam #include "../netinet/ip.h" 2929649Ssam #include "../netinet/ip_var.h" 3029649Ssam #include "../netinet/if_ether.h" 3130230Ssam #endif 3230230Ssam #ifdef NS 3330230Ssam #include "../netns/ns.h" 3430230Ssam #include "../netns/ns_if.h" 3530230Ssam #endif 3629649Ssam 3730230Ssam #include "../tahoe/cpu.h" 3830230Ssam #include "../tahoe/pte.h" 3930230Ssam #include "../tahoe/mtpr.h" 4030230Ssam 4129649Ssam #include "../tahoevba/vbavar.h" 4230230Ssam #include "../tahoeif/if_enpreg.h" 4329649Ssam 4430230Ssam #define ENPSTART 0xf02000 /* standard enp start addr */ 4530230Ssam #define ENPUNIT(dev) (minor(dev)) /* for enp ram devices */ 46*30986Ssam /* macros for dealing with longs in i/o space */ 47*30986Ssam #define ENPGETLONG(a) ((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1])) 48*30986Ssam #define ENPSETLONG(a,v) \ 49*30986Ssam { register u_short *wp = (u_short *)(a); \ 50*30986Ssam wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];} 5129649Ssam 5229649Ssam int enpprobe(), enpattach(), enpintr(); 5330298Ssam long enpstd[] = { 0xfff41000, 0xfff61000, 0 }; 5430230Ssam struct vba_device *enpinfo[NENP]; 5529649Ssam struct vba_driver enpdriver = 5630230Ssam { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 }; 5729649Ssam 5830230Ssam int enpinit(), enpioctl(), enpreset(), enpoutput(); 5929649Ssam struct mbuf *enpget(); 6029649Ssam 6129649Ssam /* 6229649Ssam * Ethernet software status per interface. 6329649Ssam * 6429649Ssam * Each interface is referenced by a network interface structure, 6529649Ssam * es_if, which the routing code uses to locate the interface. 6629649Ssam * This structure contains the output queue for the interface, its address, ... 6729649Ssam */ 6830230Ssam struct enp_softc { 6930230Ssam struct arpcom es_ac; /* common ethernet structures */ 7030230Ssam #define es_if es_ac.ac_if 71*30986Ssam #define es_addr es_ac.ac_enaddr 7230230Ssam short es_ivec; /* interrupt vector */ 7330230Ssam } enp_softc[NENP]; 7430230Ssam extern struct ifnet loif; 7529649Ssam 7630230Ssam enpprobe(reg, vi) 7730230Ssam caddr_t reg; 7830230Ssam struct vba_device *vi; 7929649Ssam { 8030230Ssam register br, cvec; /* must be r12, r11 */ 8130230Ssam register struct enpdevice *addr = (struct enpdevice *)reg; 8230230Ssam struct enp_softc *es = &enp_softc[vi->ui_unit]; 8329649Ssam 8430230Ssam #ifdef lint 8530295Ssam br = 0; cvec = br; br = cvec; 8630230Ssam enpintr(0); 8730230Ssam #endif 8830295Ssam if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2)) 8930230Ssam return (0); 9030230Ssam es->es_ivec = --vi->ui_hd->vh_lastiv; 9130230Ssam addr->enp_state = S_ENPRESET; /* reset by VERSAbus reset */ 9230230Ssam br = 0x14, cvec = es->es_ivec; /* XXX */ 9330230Ssam return (sizeof (struct enpdevice)); 9429649Ssam } 9529649Ssam 9629649Ssam /* 9729649Ssam * Interface exists: make available by filling in network interface 9829649Ssam * record. System will initialize the interface when it is ready 9929649Ssam * to accept packets. 10029649Ssam */ 10130230Ssam enpattach(ui) 10230230Ssam register struct vba_device *ui; 10329649Ssam { 10430230Ssam struct enp_softc *es = &enp_softc[ui->ui_unit]; 10530230Ssam register struct ifnet *ifp = &es->es_if; 10629649Ssam 10730230Ssam ifp->if_unit = ui->ui_unit; 10829649Ssam ifp->if_name = "enp"; 10929649Ssam ifp->if_mtu = ETHERMTU; 11029649Ssam ifp->if_init = enpinit; 11129649Ssam ifp->if_ioctl = enpioctl; 11229649Ssam ifp->if_output = enpoutput; 11329649Ssam ifp->if_reset = enpreset; 11430230Ssam ifp->if_flags = IFF_BROADCAST; 11529649Ssam if_attach(ifp); 11629649Ssam } 11729649Ssam 11829649Ssam /* 11930230Ssam * Reset of interface after "system" reset. 12029649Ssam */ 12130230Ssam enpreset(unit, vban) 12230230Ssam int unit, vban; 12329649Ssam { 12430230Ssam register struct vba_device *ui; 12529649Ssam 12630230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 12730230Ssam ui->ui_vbanum != vban) 12830230Ssam return; 12930230Ssam printf(" enp%d", unit); 13029649Ssam enpinit(unit); 13129649Ssam } 13229649Ssam 13329649Ssam /* 13430230Ssam * Initialization of interface; clear recorded pending operations. 13529649Ssam */ 13630230Ssam enpinit(unit) 13730230Ssam int unit; 13829649Ssam { 13930230Ssam struct enp_softc *es = &enp_softc[unit]; 14030230Ssam register struct vba_device *ui = enpinfo[unit]; 14130230Ssam struct enpdevice *addr; 14230230Ssam register struct ifnet *ifp = &es->es_if; 14330230Ssam int s; 14429649Ssam 14530230Ssam if (ifp->if_addrlist == (struct ifaddr *)0) 14630230Ssam return; 14730230Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 14830230Ssam addr = (struct enpdevice *)ui->ui_addr; 14930230Ssam s = splimp(); 15030230Ssam RESET_ENP(addr); 15130230Ssam DELAY(200000); 15230230Ssam es->es_if.if_flags |= IFF_RUNNING; 15330230Ssam splx(s); 15429649Ssam } 15529649Ssam } 15629649Ssam 15729649Ssam /* 15829649Ssam * Ethernet interface interrupt. 15929649Ssam */ 16030230Ssam enpintr(unit) 16130230Ssam int unit; 16229649Ssam { 16330230Ssam register struct enpdevice *addr; 16430230Ssam register BCB *bcbp; 16529649Ssam 16630230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 16730295Ssam #if ENP == 30 16830230Ssam if (!IS_ENP_INTR(addr)) 16929649Ssam return; 17030230Ssam ACK_ENP_INTR(addr); 17130295Ssam #endif 17230295Ssam while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) { 17330295Ssam (void) enpread(&enp_softc[unit], bcbp); 17430295Ssam (void) ringput((RING *)&addr->enp_enpfree, bcbp); 17529649Ssam } 17629649Ssam } 17729649Ssam 17829649Ssam /* 17929649Ssam * Read input packet, examine its packet type, and enqueue it. 18029649Ssam */ 18130295Ssam enpread(es, bcbp) 18230230Ssam struct enp_softc *es; 18330230Ssam register BCB *bcbp; 18429649Ssam { 18529649Ssam register struct ether_header *enp; 18629649Ssam struct mbuf *m; 18730295Ssam int s, len, off, resid; 18829649Ssam register struct ifqueue *inq; 18929649Ssam 19029649Ssam es->es_if.if_ipackets++; 19129649Ssam /* 19229649Ssam * Get input data length. 19329649Ssam * Get pointer to ethernet header (in input buffer). 19429649Ssam * Deal with trailer protocol: if type is PUP trailer 19529649Ssam * get true type from first 16-bit word past data. 19629649Ssam * Remember that type was trailer by setting off. 19729649Ssam */ 19830230Ssam len = bcbp->b_msglen - sizeof (struct ether_header); 199*30986Ssam enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr); 20030230Ssam #define enpdataaddr(enp, off, type) \ 20130230Ssam ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off)))) 20230230Ssam enp->ether_type = ntohs((u_short)enp->ether_type); 20330230Ssam if (enp->ether_type >= ETHERTYPE_TRAIL && 20430230Ssam enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 20530230Ssam off = (enp->ether_type - ETHERTYPE_TRAIL) * 512; 20630230Ssam if (off >= ETHERMTU) 20730230Ssam goto setup; 20830230Ssam enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *)); 20930230Ssam resid = ntohs(*(enpdataaddr(enp, off+2, u_short *))); 21030230Ssam if (off + resid > len) 21130230Ssam goto setup; 21229649Ssam len = off + resid; 21330230Ssam } else 21429649Ssam off = 0; 21530230Ssam if (len == 0) 21630230Ssam goto setup; 21729649Ssam 21829649Ssam /* 21929649Ssam * Pull packet off interface. Off is nonzero if packet 22029649Ssam * has trailing header; enpget will then force this header 22129649Ssam * information to be at the front, but we still have to drop 22229649Ssam * the type and length which are at the front of any trailer data. 22329649Ssam */ 224*30986Ssam m = enpget((u_char *)enp, len, off, &es->es_if); 22530230Ssam if (m == 0) 22630230Ssam goto setup; 22730230Ssam if (off) { 22830230Ssam struct ifnet *ifp; 22929649Ssam 23030230Ssam ifp = *(mtod(m, struct ifnet **)); 23129649Ssam m->m_off += 2 * sizeof (u_short); 23229649Ssam m->m_len -= 2 * sizeof (u_short); 23330230Ssam *(mtod(m, struct ifnet **)) = ifp; 23429649Ssam } 23530230Ssam switch (enp->ether_type) { 23629649Ssam 23729649Ssam #ifdef INET 23830230Ssam case ETHERTYPE_IP: 23929649Ssam schednetisr(NETISR_IP); 24029649Ssam inq = &ipintrq; 24129649Ssam break; 24230230Ssam #endif 24330230Ssam case ETHERTYPE_ARP: 24430230Ssam arpinput(&es->es_ac, m); 24530230Ssam goto setup; 24629649Ssam 24730230Ssam #ifdef NS 24830230Ssam case ETHERTYPE_NS: 24930230Ssam schednetisr(NETISR_NS); 25030230Ssam inq = &nsintrq; 25130230Ssam break; 25229649Ssam #endif 25330230Ssam default: 25429649Ssam m_freem(m); 25530230Ssam goto setup; 25629649Ssam } 25730230Ssam if (IF_QFULL(inq)) { 25829649Ssam IF_DROP(inq); 25929649Ssam m_freem(m); 26030230Ssam goto setup; 26129649Ssam } 26229649Ssam s = splimp(); 26329649Ssam IF_ENQUEUE(inq, m); 26429649Ssam splx(s); 26530230Ssam setup: 26630230Ssam return (0); 26729649Ssam } 26829649Ssam 26929649Ssam /* 27029649Ssam * Ethernet output routine. (called by user) 27129649Ssam * Encapsulate a packet of type family for the local net. 27229649Ssam * Use trailer local net encapsulation if enough data in first 27329649Ssam * packet leaves a multiple of 512 bytes of data in remainder. 27429649Ssam * If destination is this address or broadcast, send packet to 27529649Ssam * loop device to kludge around the fact that 3com interfaces can't 27629649Ssam * talk to themselves. 27729649Ssam */ 27829649Ssam enpoutput(ifp, m0, dst) 27930230Ssam struct ifnet *ifp; 28030230Ssam struct mbuf *m0; 28130230Ssam struct sockaddr *dst; 28229649Ssam { 28329649Ssam register struct enp_softc *es = &enp_softc[ifp->if_unit]; 28429649Ssam register struct mbuf *m = m0; 28529649Ssam register struct ether_header *enp; 28630295Ssam register int off; 28730230Ssam struct mbuf *mcopy = (struct mbuf *)0; 28830230Ssam int type, s, error, usetrailers; 28930230Ssam u_char edst[6]; 29030230Ssam struct in_addr idst; 29129649Ssam 29230230Ssam if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 29330230Ssam error = ENETDOWN; 29430230Ssam goto bad; 29530230Ssam } 29630230Ssam switch (dst->sa_family) { 29729649Ssam #ifdef INET 29829649Ssam case AF_INET: 29929649Ssam idst = ((struct sockaddr_in *)dst)->sin_addr; 30030230Ssam if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers)) 30130230Ssam return (0); /* if not yet resolved */ 30230230Ssam if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, 30330230Ssam sizeof (edst))) 30430230Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 30530230Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 30630230Ssam if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 30730230Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 30830230Ssam type = ETHERTYPE_TRAIL + (off>>9); 30930230Ssam m->m_off -= 2 * sizeof (u_short); 31030230Ssam m->m_len += 2 * sizeof (u_short); 311*30986Ssam *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 312*30986Ssam *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 31330230Ssam goto gottrailertype; 31429649Ssam } 31530230Ssam type = ETHERTYPE_IP; 31629649Ssam off = 0; 31729649Ssam goto gottype; 31829649Ssam #endif 31930230Ssam #ifdef NS 32030230Ssam case AF_NS: 32130230Ssam bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 32230230Ssam (caddr_t)edst, sizeof (edst)); 32330230Ssam if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst))) 32430230Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 32530230Ssam else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, 32630230Ssam sizeof (edst))) 32730230Ssam return (looutput(&loif, m, dst)); 32830230Ssam type = ETHERTYPE_NS; 32930230Ssam off = 0; 33030230Ssam goto gottype; 33129649Ssam #endif 33229649Ssam case AF_UNSPEC: 33329649Ssam enp = (struct ether_header *)dst->sa_data; 33430230Ssam bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst)); 33529649Ssam type = enp->ether_type; 33629649Ssam goto gottype; 33729649Ssam 33829649Ssam default: 33930230Ssam log(LOG_ERR, "enp%d: can't handle af%d\n", 34030230Ssam ifp->if_unit, dst->sa_family); 34129649Ssam error = EAFNOSUPPORT; 34229649Ssam goto bad; 34329649Ssam } 34429649Ssam 34529649Ssam gottrailertype: 34629649Ssam /* 34729649Ssam * Packet to be sent as trailer: move first packet 34829649Ssam * (control information) to end of chain. 34929649Ssam */ 35029649Ssam while (m->m_next) 35129649Ssam m = m->m_next; 35229649Ssam m->m_next = m0; 35329649Ssam m = m0->m_next; 35429649Ssam m0->m_next = 0; 35529649Ssam m0 = m; 35629649Ssam 35729649Ssam gottype: 35829649Ssam /* 35929649Ssam * Add local net header. If no space in first mbuf, 36029649Ssam * allocate another. 36129649Ssam */ 36229649Ssam if (m->m_off > MMAXOFF || 36330230Ssam MMINOFF + sizeof (struct ether_header) > m->m_off) { 36429649Ssam m = m_get(M_DONTWAIT, MT_HEADER); 36530230Ssam if (m == 0) { 36629649Ssam error = ENOBUFS; 36729649Ssam goto bad; 36829649Ssam } 36929649Ssam m->m_next = m0; 37029649Ssam m->m_off = MMINOFF; 37130230Ssam m->m_len = sizeof (struct ether_header); 37230230Ssam } else { 37330230Ssam m->m_off -= sizeof (struct ether_header); 37430230Ssam m->m_len += sizeof (struct ether_header); 37529649Ssam } 37629649Ssam enp = mtod(m, struct ether_header *); 37730230Ssam bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst)); 378*30986Ssam bcopy((caddr_t)es->es_addr, (caddr_t)enp->ether_shost, 379*30986Ssam sizeof (es->es_addr)); 38030230Ssam enp->ether_type = htons((u_short)type); 38129649Ssam 38229649Ssam /* 38329649Ssam * Queue message on interface if possible 38429649Ssam */ 38529649Ssam s = splimp(); 38630230Ssam if (enpput(ifp->if_unit, m)) { 38729649Ssam error = ENOBUFS; 38829649Ssam goto qfull; 38929649Ssam } 39030230Ssam splx(s); 39129649Ssam es->es_if.if_opackets++; 39230230Ssam return (mcopy ? looutput(&loif, mcopy, dst) : 0); 39329649Ssam qfull: 39430230Ssam splx(s); 39529649Ssam m0 = m; 39629649Ssam bad: 39729649Ssam m_freem(m0); 39830230Ssam if (mcopy) 39930230Ssam m_freem(mcopy); 40030230Ssam return (error); 40129649Ssam } 40229649Ssam 40329649Ssam /* 40430230Ssam * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus. 40529649Ssam */ 40630230Ssam enpput(unit, m) 40730230Ssam int unit; 40830230Ssam struct mbuf *m; 40929649Ssam { 41029649Ssam register BCB *bcbp; 41130230Ssam register struct enpdevice *addr; 41229649Ssam register struct mbuf *mp; 41329649Ssam register u_char *bp; 41430230Ssam register u_int len; 41530230Ssam u_char *mcp; 41629649Ssam 41730230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 41830295Ssam if (ringempty((RING *)&addr->enp_hostfree)) 41930230Ssam return (1); 42030295Ssam bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree); 42129649Ssam bcbp->b_len = 0; 422*30986Ssam bp = (u_char *)ENPGETLONG(&bcbp->b_addr); 42330230Ssam for (mp = m; mp; mp = mp->m_next) { 42429649Ssam len = mp->m_len; 42530230Ssam if (len == 0) 42629649Ssam continue; 42730230Ssam mcp = mtod(mp, u_char *); 42830230Ssam enpcopy(mcp, bp, len); 42929649Ssam bp += len; 43029649Ssam bcbp->b_len += len; 43129649Ssam } 432*30986Ssam bcbp->b_len = MAX(ETHERMIN+sizeof (struct ether_header), bcbp->b_len); 43329649Ssam bcbp->b_reserved = 0; 43430295Ssam if (ringput((RING *)&addr->enp_toenp, bcbp) == 1) 43530230Ssam INTR_ENP(addr); 43629649Ssam m_freem(m); 43730230Ssam return (0); 43829649Ssam } 43929649Ssam 44029649Ssam /* 44130230Ssam * Routine to copy from VERSAbus memory into mbufs. 44229649Ssam * 44329649Ssam * Warning: This makes the fairly safe assumption that 44429649Ssam * mbufs have even lengths. 44529649Ssam */ 44629649Ssam struct mbuf * 44730230Ssam enpget(rxbuf, totlen, off0, ifp) 44830230Ssam u_char *rxbuf; 44930230Ssam int totlen, off0; 45030230Ssam struct ifnet *ifp; 45129649Ssam { 45230230Ssam register u_char *cp, *mcp; 45329649Ssam register struct mbuf *m; 45430230Ssam struct mbuf *top = 0, **mp = ⊤ 45530230Ssam int len, off = off0; 45629649Ssam 45730230Ssam cp = rxbuf + sizeof (struct ether_header); 45830230Ssam while (totlen > 0) { 45929649Ssam MGET(m, M_DONTWAIT, MT_DATA); 46029649Ssam if (m == 0) 46129649Ssam goto bad; 46230230Ssam if (off) { 46329649Ssam len = totlen - off; 46430230Ssam cp = rxbuf + sizeof (struct ether_header) + off; 46530230Ssam } else 46629649Ssam len = totlen; 46730230Ssam if (len >= NBPG) { 46830230Ssam MCLGET(m); 46930230Ssam if (m->m_len == CLBYTES) 47030230Ssam m->m_len = len = MIN(len, CLBYTES); 47130230Ssam else 47229649Ssam m->m_len = len = MIN(MLEN, len); 47330230Ssam } else { 47429649Ssam m->m_len = len = MIN(MLEN, len); 47529649Ssam m->m_off = MMINOFF; 47629649Ssam } 47729649Ssam mcp = mtod(m, u_char *); 47830230Ssam if (ifp) { 47930230Ssam /* 48030230Ssam * Prepend interface pointer to first mbuf. 48130230Ssam */ 48230230Ssam *(mtod(m, struct ifnet **)) = ifp; 48330230Ssam mcp += sizeof (ifp); 48430230Ssam len -= sizeof (ifp); 48530230Ssam ifp = (struct ifnet *)0; 48630230Ssam } 48730295Ssam enpcopy(cp, mcp, (u_int)len); 48829649Ssam cp += len; 48929649Ssam *mp = m; 49029649Ssam mp = &m->m_next; 49130230Ssam if (off == 0) { 49229649Ssam totlen -= len; 49329649Ssam continue; 49429649Ssam } 49529649Ssam off += len; 49630230Ssam if (off == totlen) { 49730230Ssam cp = rxbuf + sizeof (struct ether_header); 49829649Ssam off = 0; 49929649Ssam totlen = off0; 50029649Ssam } 50129649Ssam } 50229649Ssam return (top); 50329649Ssam bad: 50429649Ssam m_freem(top); 50529649Ssam return (0); 50629649Ssam } 50729649Ssam 50830230Ssam enpcopy(from, to, cnt) 50930295Ssam register u_char *from, *to; 51030295Ssam register u_int cnt; 51130230Ssam { 51230230Ssam register c; 51330230Ssam register short *f, *t; 51430230Ssam 51530230Ssam if (((int)from&01) && ((int)to&01)) { 51630230Ssam /* source & dest at odd addresses */ 51730230Ssam *to++ = *from++; 51830230Ssam --cnt; 51930230Ssam } 52030230Ssam if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) { 52130230Ssam t = (short *)to; 52230230Ssam f = (short *)from; 52330230Ssam for (c = cnt>>1; c; --c) /* even address copy */ 52430230Ssam *t++ = *f++; 52530230Ssam cnt &= 1; 52630230Ssam if (cnt) { /* odd len */ 52730295Ssam from = (u_char *)f; 52830295Ssam to = (u_char *)t; 52930230Ssam *to = *from; 53030230Ssam } 53130230Ssam } 53230295Ssam while ((int)cnt-- > 0) /* one of the address(es) must be odd */ 53330230Ssam *to++ = *from++; 53430230Ssam } 53530230Ssam 53629649Ssam /* 53729649Ssam * Process an ioctl request. 53829649Ssam */ 53929649Ssam enpioctl(ifp, cmd, data) 54030230Ssam register struct ifnet *ifp; 54130230Ssam int cmd; 54230230Ssam caddr_t data; 54329649Ssam { 54430230Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 54530230Ssam struct enpdevice *addr; 54630230Ssam int s = splimp(), error = 0; 54729649Ssam 54829649Ssam switch (cmd) { 54929649Ssam 55029649Ssam case SIOCSIFADDR: 55130230Ssam ifp->if_flags |= IFF_UP; 55230230Ssam switch (ifa->ifa_addr.sa_family) { 55330230Ssam #ifdef INET 55430230Ssam case AF_INET: 55530230Ssam enpinit(ifp->if_unit); 55630230Ssam ((struct arpcom *)ifp)->ac_ipaddr = 55730230Ssam IA_SIN(ifa)->sin_addr; 55830230Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 55929649Ssam break; 56030230Ssam #endif 56130230Ssam #ifdef NS 56230230Ssam case AF_NS: { 56330230Ssam struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 56430230Ssam struct enp_softc *es = &enp_softc[ifp->if_unit]; 56530230Ssam 56630230Ssam if (!ns_nullhost(*ina)) { 56730230Ssam ifp->if_flags &= ~IFF_RUNNING; 56830230Ssam addr = (struct enpdevice *) 56930230Ssam enpinfo[ifp->if_unit]->ui_addr; 57030230Ssam enpsetaddr(ifp->if_unit, addr, 57130230Ssam ina->x_host.c_host); 57230230Ssam } else 573*30986Ssam ina->x_host = *(union ns_host *)es->es_addr; 57430230Ssam enpinit(ifp->if_unit); 57530230Ssam break; 57629649Ssam } 57730230Ssam #endif 57830230Ssam default: 57930230Ssam enpinit(ifp->if_unit); 58030230Ssam break; 58129649Ssam } 58229649Ssam break; 58329649Ssam 58430230Ssam case SIOCSIFFLAGS: 58530230Ssam if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 58630230Ssam enpinit(ifp->if_unit); /* reset board */ 58730230Ssam ifp->if_flags &= ~IFF_RUNNING; 58830230Ssam } else if (ifp->if_flags&IFF_UP && 58930230Ssam (ifp->if_flags&IFF_RUNNING) == 0) 59030230Ssam enpinit(ifp->if_unit); 59129649Ssam break; 59229649Ssam 59329649Ssam default: 59429649Ssam error = EINVAL; 59529649Ssam } 59630230Ssam splx(s); 59730230Ssam return (error); 59829649Ssam } 59929649Ssam 60030230Ssam enpsetaddr(unit, addr, enaddr) 60130230Ssam int unit; 60230230Ssam struct enpdevice *addr; 60330230Ssam u_char *enaddr; 60429649Ssam { 60529649Ssam 606*30986Ssam enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr, 607*30986Ssam sizeof (struct ether_addr)); 60830230Ssam enpinit(unit); 609*30986Ssam enpgetaddr(unit, addr); 61029649Ssam } 61129649Ssam 612*30986Ssam enpgetaddr(unit, addr) 613*30986Ssam int unit; 614*30986Ssam struct enpdevice *addr; 615*30986Ssam { 616*30986Ssam struct enp_softc *es = &enp_softc[unit]; 617*30986Ssam 618*30986Ssam enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr, 619*30986Ssam sizeof (struct ether_addr)); 620*30986Ssam printf("enp%d: hardware address %s\n", 621*30986Ssam unit, ether_sprintf(es->es_addr)); 622*30986Ssam } 623*30986Ssam 62429649Ssam /* 62530230Ssam * Routines to synchronize enp and host. 62629649Ssam */ 62730295Ssam #ifdef notdef 62829649Ssam static 62930230Ssam ringinit(rp, size) 63030230Ssam register RING *rp; 63129649Ssam { 63229649Ssam 63329649Ssam rp->r_rdidx = rp->r_wrtidx = 0; 63429649Ssam rp->r_size = size; 63529649Ssam } 63629649Ssam 63729649Ssam static 63830295Ssam ringfull(rp) 63930230Ssam register RING *rp; 64029649Ssam { 64130295Ssam register short idx; 64230230Ssam 64330295Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 64430295Ssam return (idx == rp->r_rdidx); 64529649Ssam } 64629649Ssam 64729649Ssam static 64830295Ssam fir(rp) 64930230Ssam register RING *rp; 65029649Ssam { 65129649Ssam 65230295Ssam return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0); 65329649Ssam } 65430295Ssam #endif 65529649Ssam 65629649Ssam static 65730295Ssam ringempty(rp) 65830295Ssam register RING *rp; 65930295Ssam { 66030295Ssam 66130295Ssam return (rp->r_rdidx == rp->r_wrtidx); 66230295Ssam } 66330295Ssam 66430295Ssam static 66530230Ssam ringput(rp, v) 66630230Ssam register RING *rp; 66730295Ssam BCB *v; 66829649Ssam { 66929649Ssam register int idx; 67029649Ssam 67129649Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 67230230Ssam if (idx != rp->r_rdidx) { 673*30986Ssam ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v); 67429649Ssam rp->r_wrtidx = idx; 67530230Ssam if ((idx -= rp->r_rdidx) < 0) 67629649Ssam idx += rp->r_size; 67730230Ssam return (idx); /* num ring entries */ 67829649Ssam } 67930230Ssam return (0); 68029649Ssam } 68129649Ssam 68229649Ssam static 68330230Ssam ringget(rp) 68430230Ssam register RING *rp; 68529649Ssam { 68629649Ssam register int i = 0; 68729649Ssam 68830230Ssam if (rp->r_rdidx != rp->r_wrtidx) { 689*30986Ssam i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]); 69029649Ssam rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1); 69129649Ssam } 69230230Ssam return (i); 69329649Ssam } 69429649Ssam 69530230Ssam /* 69630230Ssam * ENP Ram device. 69730230Ssam */ 69830230Ssam enpr_open(dev) 69930230Ssam dev_t dev; 70029649Ssam { 70130230Ssam register int unit = ENPUNIT(dev); 70230230Ssam struct vba_device *ui; 70330230Ssam struct enpdevice *addr; 70429649Ssam 70530230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 70630230Ssam (addr = (struct enpdevice *)ui->ui_addr) == 0) 70730230Ssam return (ENODEV); 70830230Ssam if (addr->enp_state != S_ENPRESET) 70930230Ssam return (EACCES); /* enp is not in reset state, don't open */ 71030230Ssam return (0); 71129649Ssam } 71229649Ssam 71330295Ssam /*ARGSUSED*/ 71430230Ssam enpr_close(dev) 71530230Ssam dev_t dev; 71629649Ssam { 71729649Ssam 71830230Ssam return (0); 71929649Ssam } 72029649Ssam 72130230Ssam enpr_read(dev, uio) 72230230Ssam dev_t dev; 72330230Ssam register struct uio *uio; 72429649Ssam { 72530230Ssam register struct iovec *iov; 72630230Ssam struct enpdevice *addr; 72729649Ssam 72830230Ssam if (uio->uio_offset > RAM_SIZE) 72930230Ssam return (ENODEV); 73030295Ssam iov = uio->uio_iov; 73130230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 73230230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 73330230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 734*30986Ssam if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0) 735*30986Ssam return (EFAULT); 73630295Ssam enpcopy((u_char *)&addr->enp_ram[uio->uio_offset], 73730295Ssam (u_char *)iov->iov_base, (u_int)iov->iov_len); 73830230Ssam uio->uio_resid -= iov->iov_len; 73930230Ssam iov->iov_len = 0; 74030230Ssam return (0); 74129649Ssam } 74229649Ssam 74330230Ssam enpr_write(dev, uio) 74430230Ssam dev_t dev; 74530230Ssam register struct uio *uio; 74629649Ssam { 74730230Ssam register struct enpdevice *addr; 74830230Ssam register struct iovec *iov; 74929649Ssam 75030230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 75130230Ssam iov = uio->uio_iov; 75230230Ssam if (uio->uio_offset > RAM_SIZE) 75330230Ssam return (ENODEV); 75430230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 75530230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 756*30986Ssam if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0) 757*30986Ssam return (EFAULT); 75830295Ssam enpcopy((u_char *)iov->iov_base, 75930295Ssam (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len); 76030230Ssam uio->uio_resid -= iov->iov_len; 76130230Ssam iov->iov_len = 0; 76230230Ssam return (0); 76329649Ssam } 76429649Ssam 76530295Ssam /*ARGSUSED*/ 76630230Ssam enpr_ioctl(dev, cmd, data) 76730230Ssam dev_t dev; 76830230Ssam caddr_t data; 76929649Ssam { 77030230Ssam register unit = ENPUNIT(dev); 771*30986Ssam struct enpdevice *addr; 77229649Ssam 77330230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 77430230Ssam switch(cmd) { 77530230Ssam 77630230Ssam case ENPIOGO: 777*30986Ssam ENPSETLONG(&addr->enp_base, addr); 77830230Ssam addr->enp_intrvec = enp_softc[unit].es_ivec; 77930230Ssam ENP_GO(addr, ENPSTART); 78030230Ssam DELAY(200000); 78130230Ssam enpinit(unit); 782*30986Ssam /* 783*30986Ssam * Fetch Ethernet address after link level 784*30986Ssam * is booted (firmware copies manufacturer's 785*30986Ssam * address from on-board ROM). 786*30986Ssam */ 787*30986Ssam enpgetaddr(unit, addr); 788*30986Ssam addr->enp_state = S_ENPRUN; 78930230Ssam break; 79030230Ssam 79130230Ssam case ENPIORESET: 79230230Ssam RESET_ENP(addr); 793*30986Ssam addr->enp_state = S_ENPRESET; 79430230Ssam DELAY(100000); 79530230Ssam break; 796*30986Ssam default: 797*30986Ssam return (EINVAL); 79829649Ssam } 79930230Ssam return (0); 80029649Ssam } 80129649Ssam #endif 802