1*30298Ssam /* if_enp.c 1.4 86/12/15 */ 229649Ssam 329649Ssam #include "enp.h" 429649Ssam #if NENP > 0 529649Ssam /* 630230Ssam * Modified 3Com Ethernet Controller interface 729649Ssam * enp modifications added S. F. Holmgren 830230Ssam * 930230Ssam * 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" 1830230Ssam #include "ioctl.h" 1929649Ssam #include "errno.h" 2030230Ssam #include "vmparam.h" 2130230Ssam #include "syslog.h" 2229649Ssam #include "uio.h" 2329649Ssam 2429649Ssam #include "../net/if.h" 2529649Ssam #include "../net/netisr.h" 2629649Ssam #include "../net/route.h" 2730230Ssam #ifdef INET 2829649Ssam #include "../netinet/in.h" 2929649Ssam #include "../netinet/in_systm.h" 3030230Ssam #include "../netinet/in_var.h" 3129649Ssam #include "../netinet/ip.h" 3229649Ssam #include "../netinet/ip_var.h" 3329649Ssam #include "../netinet/if_ether.h" 3430230Ssam #endif 3530230Ssam #ifdef NS 3630230Ssam #include "../netns/ns.h" 3730230Ssam #include "../netns/ns_if.h" 3830230Ssam #endif 3929649Ssam 4030230Ssam #include "../tahoe/cpu.h" 4130230Ssam #include "../tahoe/pte.h" 4230230Ssam #include "../tahoe/mtpr.h" 4330230Ssam 4429649Ssam #include "../tahoevba/vbavar.h" 4530230Ssam #include "../tahoeif/if_enpreg.h" 4629649Ssam 4730230Ssam #define ENPVEC 0xc1 4830230Ssam #define ENPSTART 0xf02000 /* standard enp start addr */ 4930230Ssam #define ENPUNIT(dev) (minor(dev)) /* for enp ram devices */ 5029649Ssam 5129649Ssam int enpprobe(), enpattach(), enpintr(); 52*30298Ssam long enpstd[] = { 0xfff41000, 0xfff61000, 0 }; 5330230Ssam struct vba_device *enpinfo[NENP]; 5429649Ssam struct vba_driver enpdriver = 5530230Ssam { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 }; 5629649Ssam 5730230Ssam 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 */ 6730230Ssam struct enp_softc { 6830230Ssam struct arpcom es_ac; /* common ethernet structures */ 6930230Ssam #define es_if es_ac.ac_if 7030230Ssam #define es_enaddr es_ac.ac_enaddr 7130230Ssam short es_flags; /* flags for devices */ 7230230Ssam short es_ivec; /* interrupt vector */ 7330230Ssam struct pte *es_map; /* map for dual ported memory */ 7430230Ssam caddr_t es_ram; /* virtual address of mapped memory */ 7530230Ssam } enp_softc[NENP]; 7630230Ssam extern struct ifnet loif; 7729649Ssam 7830230Ssam enpprobe(reg, vi) 7930230Ssam caddr_t reg; 8030230Ssam struct vba_device *vi; 8129649Ssam { 8230230Ssam register br, cvec; /* must be r12, r11 */ 8330230Ssam register struct enpdevice *addr = (struct enpdevice *)reg; 8430230Ssam struct enp_softc *es = &enp_softc[vi->ui_unit]; 8529649Ssam 8630230Ssam #ifdef lint 8730295Ssam br = 0; cvec = br; br = cvec; 8830230Ssam enpintr(0); 8930230Ssam #endif 9030295Ssam if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2)) 9130230Ssam return (0); 9230230Ssam es->es_ivec = --vi->ui_hd->vh_lastiv; 9330230Ssam addr->enp_state = S_ENPRESET; /* reset by VERSAbus reset */ 9430230Ssam br = 0x14, cvec = es->es_ivec; /* XXX */ 9530230Ssam return (sizeof (struct enpdevice)); 9629649Ssam } 9729649Ssam 9829649Ssam /* 9929649Ssam * Interface exists: make available by filling in network interface 10029649Ssam * record. System will initialize the interface when it is ready 10129649Ssam * to accept packets. 10229649Ssam */ 10330230Ssam enpattach(ui) 10430230Ssam register struct vba_device *ui; 10529649Ssam { 10630230Ssam struct enp_softc *es = &enp_softc[ui->ui_unit]; 10730230Ssam register struct ifnet *ifp = &es->es_if; 10830230Ssam register struct enpdevice *addr = (struct enpdevice *)ui->ui_addr; 10929649Ssam 11030230Ssam ifp->if_unit = ui->ui_unit; 11129649Ssam ifp->if_name = "enp"; 11229649Ssam ifp->if_mtu = ETHERMTU; 11330230Ssam /* 11430230Ssam * Get station's addresses. 11530230Ssam */ 11630295Ssam enpcopy((u_char *)&addr->enp_addr.e_baseaddr, es->es_enaddr, 11730230Ssam sizeof (es->es_enaddr)); 11830230Ssam printf("enp%d: hardware address %s\n", ui->ui_unit, 11930230Ssam ether_sprintf(es->es_enaddr)); 12030230Ssam /* 12130230Ssam * Allocate and map ram. 12230230Ssam */ 12330230Ssam vbmemalloc(128, ((caddr_t)addr)+0x1000, &es->es_map, &es->es_ram); 12429649Ssam 12529649Ssam ifp->if_init = enpinit; 12629649Ssam ifp->if_ioctl = enpioctl; 12729649Ssam ifp->if_output = enpoutput; 12829649Ssam ifp->if_reset = enpreset; 12930230Ssam ifp->if_flags = IFF_BROADCAST; 13029649Ssam if_attach(ifp); 13129649Ssam } 13229649Ssam 13329649Ssam /* 13430230Ssam * Reset of interface after "system" reset. 13529649Ssam */ 13630230Ssam enpreset(unit, vban) 13730230Ssam int unit, vban; 13829649Ssam { 13930230Ssam register struct vba_device *ui; 14029649Ssam 14130230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 14230230Ssam ui->ui_vbanum != vban) 14330230Ssam return; 14430230Ssam printf(" enp%d", unit); 14529649Ssam enpinit(unit); 14629649Ssam } 14729649Ssam 14829649Ssam /* 14930230Ssam * Initialization of interface; clear recorded pending operations. 15029649Ssam */ 15130230Ssam enpinit(unit) 15230230Ssam int unit; 15329649Ssam { 15430230Ssam struct enp_softc *es = &enp_softc[unit]; 15530230Ssam register struct vba_device *ui = enpinfo[unit]; 15630230Ssam struct enpdevice *addr; 15730230Ssam register struct ifnet *ifp = &es->es_if; 15830230Ssam int s; 15929649Ssam 16030230Ssam if (ifp->if_addrlist == (struct ifaddr *)0) 16130230Ssam return; 16230230Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 16330230Ssam addr = (struct enpdevice *)ui->ui_addr; 16430230Ssam s = splimp(); 16530230Ssam RESET_ENP(addr); 16630230Ssam DELAY(200000); 16730230Ssam addr->enp_intrvec = es->es_ivec; 16830230Ssam es->es_if.if_flags |= IFF_RUNNING; 16930230Ssam splx(s); 17029649Ssam } 17129649Ssam } 17229649Ssam 17329649Ssam /* 17429649Ssam * Ethernet interface interrupt. 17529649Ssam */ 17630230Ssam enpintr(unit) 17730230Ssam int unit; 17829649Ssam { 17930230Ssam register struct enpdevice *addr; 18030230Ssam register BCB *bcbp; 18129649Ssam 18230230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 18330295Ssam #if ENP == 30 18430230Ssam if (!IS_ENP_INTR(addr)) 18529649Ssam return; 18630230Ssam ACK_ENP_INTR(addr); 18730295Ssam #endif 18830295Ssam while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) { 18930295Ssam (void) enpread(&enp_softc[unit], bcbp); 19030295Ssam (void) ringput((RING *)&addr->enp_enpfree, bcbp); 19129649Ssam } 19229649Ssam } 19329649Ssam 19429649Ssam /* 19529649Ssam * Read input packet, examine its packet type, and enqueue it. 19629649Ssam */ 19730295Ssam enpread(es, bcbp) 19830230Ssam struct enp_softc *es; 19930230Ssam register BCB *bcbp; 20029649Ssam { 20129649Ssam register struct ether_header *enp; 20229649Ssam struct mbuf *m; 20330295Ssam int s, len, off, resid; 20429649Ssam register struct ifqueue *inq; 20529649Ssam 20629649Ssam es->es_if.if_ipackets++; 20729649Ssam /* 20829649Ssam * Get input data length. 20929649Ssam * Get pointer to ethernet header (in input buffer). 21029649Ssam * Deal with trailer protocol: if type is PUP trailer 21129649Ssam * get true type from first 16-bit word past data. 21229649Ssam * Remember that type was trailer by setting off. 21329649Ssam */ 21430230Ssam len = bcbp->b_msglen - sizeof (struct ether_header); 21529649Ssam enp = (struct ether_header *)bcbp->b_addr; 21630230Ssam #define enpdataaddr(enp, off, type) \ 21730230Ssam ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off)))) 21830230Ssam enp->ether_type = ntohs((u_short)enp->ether_type); 21930230Ssam if (enp->ether_type >= ETHERTYPE_TRAIL && 22030230Ssam enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 22130230Ssam off = (enp->ether_type - ETHERTYPE_TRAIL) * 512; 22230230Ssam if (off >= ETHERMTU) 22330230Ssam goto setup; 22430230Ssam enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *)); 22530230Ssam resid = ntohs(*(enpdataaddr(enp, off+2, u_short *))); 22630230Ssam if (off + resid > len) 22730230Ssam goto setup; 22829649Ssam len = off + resid; 22930230Ssam } else 23029649Ssam off = 0; 23130230Ssam if (len == 0) 23230230Ssam goto setup; 23329649Ssam 23429649Ssam /* 23529649Ssam * Pull packet off interface. Off is nonzero if packet 23629649Ssam * has trailing header; enpget will then force this header 23729649Ssam * information to be at the front, but we still have to drop 23829649Ssam * the type and length which are at the front of any trailer data. 23929649Ssam */ 24030230Ssam m = enpget(bcbp->b_addr, len, off, &es->es_if); 24130230Ssam if (m == 0) 24230230Ssam goto setup; 24330230Ssam if (off) { 24430230Ssam struct ifnet *ifp; 24529649Ssam 24630230Ssam ifp = *(mtod(m, struct ifnet **)); 24729649Ssam m->m_off += 2 * sizeof (u_short); 24829649Ssam m->m_len -= 2 * sizeof (u_short); 24930230Ssam *(mtod(m, struct ifnet **)) = ifp; 25029649Ssam } 25130230Ssam switch (enp->ether_type) { 25229649Ssam 25329649Ssam #ifdef INET 25430230Ssam case ETHERTYPE_IP: 25529649Ssam schednetisr(NETISR_IP); 25629649Ssam inq = &ipintrq; 25729649Ssam break; 25830230Ssam #endif 25930230Ssam case ETHERTYPE_ARP: 26030230Ssam arpinput(&es->es_ac, m); 26130230Ssam goto setup; 26229649Ssam 26330230Ssam #ifdef NS 26430230Ssam case ETHERTYPE_NS: 26530230Ssam schednetisr(NETISR_NS); 26630230Ssam inq = &nsintrq; 26730230Ssam break; 26829649Ssam #endif 26930230Ssam default: 27029649Ssam m_freem(m); 27130230Ssam goto setup; 27229649Ssam } 27330230Ssam if (IF_QFULL(inq)) { 27429649Ssam IF_DROP(inq); 27529649Ssam m_freem(m); 27630230Ssam goto setup; 27729649Ssam } 27829649Ssam s = splimp(); 27929649Ssam IF_ENQUEUE(inq, m); 28029649Ssam splx(s); 28130230Ssam setup: 28230230Ssam return (0); 28329649Ssam } 28429649Ssam 28529649Ssam /* 28629649Ssam * Ethernet output routine. (called by user) 28729649Ssam * Encapsulate a packet of type family for the local net. 28829649Ssam * Use trailer local net encapsulation if enough data in first 28929649Ssam * packet leaves a multiple of 512 bytes of data in remainder. 29029649Ssam * If destination is this address or broadcast, send packet to 29129649Ssam * loop device to kludge around the fact that 3com interfaces can't 29229649Ssam * talk to themselves. 29329649Ssam */ 29429649Ssam enpoutput(ifp, m0, dst) 29530230Ssam struct ifnet *ifp; 29630230Ssam struct mbuf *m0; 29730230Ssam struct sockaddr *dst; 29829649Ssam { 29929649Ssam register struct enp_softc *es = &enp_softc[ifp->if_unit]; 30029649Ssam register struct mbuf *m = m0; 30129649Ssam register struct ether_header *enp; 30230295Ssam register int off; 30330230Ssam struct mbuf *mcopy = (struct mbuf *)0; 30430230Ssam int type, s, error, usetrailers; 30530230Ssam u_char edst[6]; 30630230Ssam struct in_addr idst; 30729649Ssam 30830230Ssam if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 30930230Ssam error = ENETDOWN; 31030230Ssam goto bad; 31130230Ssam } 31230230Ssam switch (dst->sa_family) { 31329649Ssam #ifdef INET 31429649Ssam case AF_INET: 31529649Ssam idst = ((struct sockaddr_in *)dst)->sin_addr; 31630230Ssam if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers)) 31730230Ssam return (0); /* if not yet resolved */ 31830230Ssam if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr, 31930230Ssam sizeof (edst))) 32030230Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 32130230Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 32230230Ssam if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 32330230Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 32430230Ssam type = ETHERTYPE_TRAIL + (off>>9); 32530230Ssam m->m_off -= 2 * sizeof (u_short); 32630230Ssam m->m_len += 2 * sizeof (u_short); 32730230Ssam *mtod(m, u_short *) = ETHERTYPE_IP; 32830230Ssam *(mtod(m, u_short *) + 1) = m->m_len; 32930230Ssam goto gottrailertype; 33029649Ssam } 33130230Ssam type = ETHERTYPE_IP; 33229649Ssam off = 0; 33329649Ssam goto gottype; 33429649Ssam #endif 33530230Ssam #ifdef NS 33630230Ssam case AF_NS: 33730230Ssam bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 33830230Ssam (caddr_t)edst, sizeof (edst)); 33930230Ssam if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst))) 34030230Ssam mcopy = m_copy(m, 0, (int)M_COPYALL); 34130230Ssam else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, 34230230Ssam sizeof (edst))) 34330230Ssam return (looutput(&loif, m, dst)); 34430230Ssam type = ETHERTYPE_NS; 34530230Ssam off = 0; 34630230Ssam goto gottype; 34729649Ssam #endif 34829649Ssam case AF_UNSPEC: 34929649Ssam enp = (struct ether_header *)dst->sa_data; 35030230Ssam bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst)); 35129649Ssam type = enp->ether_type; 35229649Ssam goto gottype; 35329649Ssam 35429649Ssam default: 35530230Ssam log(LOG_ERR, "enp%d: can't handle af%d\n", 35630230Ssam ifp->if_unit, dst->sa_family); 35729649Ssam error = EAFNOSUPPORT; 35829649Ssam goto bad; 35929649Ssam } 36029649Ssam 36129649Ssam gottrailertype: 36229649Ssam /* 36329649Ssam * Packet to be sent as trailer: move first packet 36429649Ssam * (control information) to end of chain. 36529649Ssam */ 36629649Ssam while (m->m_next) 36729649Ssam m = m->m_next; 36829649Ssam m->m_next = m0; 36929649Ssam m = m0->m_next; 37029649Ssam m0->m_next = 0; 37129649Ssam m0 = m; 37229649Ssam 37329649Ssam gottype: 37429649Ssam /* 37529649Ssam * Add local net header. If no space in first mbuf, 37629649Ssam * allocate another. 37729649Ssam */ 37829649Ssam if (m->m_off > MMAXOFF || 37930230Ssam MMINOFF + sizeof (struct ether_header) > m->m_off) { 38029649Ssam m = m_get(M_DONTWAIT, MT_HEADER); 38130230Ssam if (m == 0) { 38229649Ssam error = ENOBUFS; 38329649Ssam goto bad; 38429649Ssam } 38529649Ssam m->m_next = m0; 38629649Ssam m->m_off = MMINOFF; 38730230Ssam m->m_len = sizeof (struct ether_header); 38830230Ssam } else { 38930230Ssam m->m_off -= sizeof (struct ether_header); 39030230Ssam m->m_len += sizeof (struct ether_header); 39129649Ssam } 39229649Ssam enp = mtod(m, struct ether_header *); 39330230Ssam bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst)); 39430230Ssam bcopy((caddr_t)es->es_enaddr, (caddr_t)enp->ether_shost, 39530230Ssam sizeof (es->es_enaddr)); 39630230Ssam enp->ether_type = htons((u_short)type); 39729649Ssam 39829649Ssam /* 39929649Ssam * Queue message on interface if possible 40029649Ssam */ 40129649Ssam s = splimp(); 40230230Ssam if (enpput(ifp->if_unit, m)) { 40329649Ssam error = ENOBUFS; 40429649Ssam goto qfull; 40529649Ssam } 40630230Ssam splx(s); 40729649Ssam es->es_if.if_opackets++; 40830230Ssam return (mcopy ? looutput(&loif, mcopy, dst) : 0); 40929649Ssam qfull: 41030230Ssam splx(s); 41129649Ssam m0 = m; 41229649Ssam bad: 41329649Ssam m_freem(m0); 41430230Ssam if (mcopy) 41530230Ssam m_freem(mcopy); 41630230Ssam return (error); 41729649Ssam } 41829649Ssam 41929649Ssam /* 42030230Ssam * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus. 42129649Ssam */ 42230230Ssam enpput(unit, m) 42330230Ssam int unit; 42430230Ssam struct mbuf *m; 42529649Ssam { 42629649Ssam register BCB *bcbp; 42730230Ssam register struct enpdevice *addr; 42829649Ssam register struct mbuf *mp; 42929649Ssam register u_char *bp; 43030230Ssam register u_int len; 43130230Ssam u_char *mcp; 43229649Ssam 43330230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 43430295Ssam if (ringempty((RING *)&addr->enp_hostfree)) 43530230Ssam return (1); 43630295Ssam bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree); 43729649Ssam bcbp->b_len = 0; 43829649Ssam bp = (u_char *)bcbp->b_addr; 43930230Ssam for (mp = m; mp; mp = mp->m_next) { 44029649Ssam len = mp->m_len; 44130230Ssam if (len == 0) 44229649Ssam continue; 44330230Ssam mcp = mtod(mp, u_char *); 44430230Ssam enpcopy(mcp, bp, len); 44529649Ssam bp += len; 44629649Ssam bcbp->b_len += len; 44729649Ssam } 44830295Ssam bcbp->b_len = MAX(ETHERMIN, bcbp->b_len); 44929649Ssam bcbp->b_reserved = 0; 45030295Ssam if (ringput((RING *)&addr->enp_toenp, bcbp) == 1) 45130230Ssam INTR_ENP(addr); 45229649Ssam m_freem(m); 45330230Ssam return (0); 45429649Ssam } 45529649Ssam 45629649Ssam /* 45730230Ssam * Routine to copy from VERSAbus memory into mbufs. 45829649Ssam * 45929649Ssam * Warning: This makes the fairly safe assumption that 46029649Ssam * mbufs have even lengths. 46129649Ssam */ 46229649Ssam struct mbuf * 46330230Ssam enpget(rxbuf, totlen, off0, ifp) 46430230Ssam u_char *rxbuf; 46530230Ssam int totlen, off0; 46630230Ssam struct ifnet *ifp; 46729649Ssam { 46830230Ssam register u_char *cp, *mcp; 46929649Ssam register struct mbuf *m; 47030230Ssam struct mbuf *top = 0, **mp = ⊤ 47130230Ssam int len, off = off0; 47229649Ssam 47330230Ssam cp = rxbuf + sizeof (struct ether_header); 47430230Ssam while (totlen > 0) { 47529649Ssam MGET(m, M_DONTWAIT, MT_DATA); 47629649Ssam if (m == 0) 47729649Ssam goto bad; 47830230Ssam if (off) { 47929649Ssam len = totlen - off; 48030230Ssam cp = rxbuf + sizeof (struct ether_header) + off; 48130230Ssam } else 48229649Ssam len = totlen; 48330230Ssam if (len >= NBPG) { 48430230Ssam MCLGET(m); 48530230Ssam if (m->m_len == CLBYTES) 48630230Ssam m->m_len = len = MIN(len, CLBYTES); 48730230Ssam else 48829649Ssam m->m_len = len = MIN(MLEN, len); 48930230Ssam } else { 49029649Ssam m->m_len = len = MIN(MLEN, len); 49129649Ssam m->m_off = MMINOFF; 49229649Ssam } 49329649Ssam mcp = mtod(m, u_char *); 49430230Ssam if (ifp) { 49530230Ssam /* 49630230Ssam * Prepend interface pointer to first mbuf. 49730230Ssam */ 49830230Ssam *(mtod(m, struct ifnet **)) = ifp; 49930230Ssam mcp += sizeof (ifp); 50030230Ssam len -= sizeof (ifp); 50130230Ssam ifp = (struct ifnet *)0; 50230230Ssam } 50330295Ssam enpcopy(cp, mcp, (u_int)len); 50429649Ssam cp += len; 50529649Ssam *mp = m; 50629649Ssam mp = &m->m_next; 50730230Ssam if (off == 0) { 50829649Ssam totlen -= len; 50929649Ssam continue; 51029649Ssam } 51129649Ssam off += len; 51230230Ssam if (off == totlen) { 51330230Ssam cp = rxbuf + sizeof (struct ether_header); 51429649Ssam off = 0; 51529649Ssam totlen = off0; 51629649Ssam } 51729649Ssam } 51829649Ssam return (top); 51929649Ssam bad: 52029649Ssam m_freem(top); 52129649Ssam return (0); 52229649Ssam } 52329649Ssam 52430230Ssam enpcopy(from, to, cnt) 52530295Ssam register u_char *from, *to; 52630295Ssam register u_int cnt; 52730230Ssam { 52830230Ssam register c; 52930230Ssam register short *f, *t; 53030230Ssam 53130230Ssam if (((int)from&01) && ((int)to&01)) { 53230230Ssam /* source & dest at odd addresses */ 53330230Ssam *to++ = *from++; 53430230Ssam --cnt; 53530230Ssam } 53630230Ssam if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) { 53730230Ssam t = (short *)to; 53830230Ssam f = (short *)from; 53930230Ssam for (c = cnt>>1; c; --c) /* even address copy */ 54030230Ssam *t++ = *f++; 54130230Ssam cnt &= 1; 54230230Ssam if (cnt) { /* odd len */ 54330295Ssam from = (u_char *)f; 54430295Ssam to = (u_char *)t; 54530230Ssam *to = *from; 54630230Ssam } 54730230Ssam } 54830295Ssam while ((int)cnt-- > 0) /* one of the address(es) must be odd */ 54930230Ssam *to++ = *from++; 55030230Ssam } 55130230Ssam 55229649Ssam /* 55329649Ssam * Process an ioctl request. 55429649Ssam */ 55529649Ssam enpioctl(ifp, cmd, data) 55630230Ssam register struct ifnet *ifp; 55730230Ssam int cmd; 55830230Ssam caddr_t data; 55929649Ssam { 56030230Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 56130230Ssam struct enpdevice *addr; 56230230Ssam int s = splimp(), error = 0; 56329649Ssam 56429649Ssam switch (cmd) { 56529649Ssam 56629649Ssam case SIOCSIFADDR: 56730230Ssam ifp->if_flags |= IFF_UP; 56830230Ssam switch (ifa->ifa_addr.sa_family) { 56930230Ssam #ifdef INET 57030230Ssam case AF_INET: 57130230Ssam enpinit(ifp->if_unit); 57230230Ssam ((struct arpcom *)ifp)->ac_ipaddr = 57330230Ssam IA_SIN(ifa)->sin_addr; 57430230Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 57529649Ssam break; 57630230Ssam #endif 57730230Ssam #ifdef NS 57830230Ssam case AF_NS: { 57930230Ssam struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 58030230Ssam struct enp_softc *es = &enp_softc[ifp->if_unit]; 58130230Ssam 58230230Ssam if (!ns_nullhost(*ina)) { 58330230Ssam ifp->if_flags &= ~IFF_RUNNING; 58430230Ssam addr = (struct enpdevice *) 58530230Ssam enpinfo[ifp->if_unit]->ui_addr; 58630230Ssam enpsetaddr(ifp->if_unit, addr, 58730230Ssam ina->x_host.c_host); 58830230Ssam } else 58930230Ssam ina->x_host = *(union ns_host *)es->es_enaddr; 59030230Ssam enpinit(ifp->if_unit); 59130230Ssam break; 59229649Ssam } 59330230Ssam #endif 59430230Ssam default: 59530230Ssam enpinit(ifp->if_unit); 59630230Ssam break; 59729649Ssam } 59829649Ssam break; 59929649Ssam 60030230Ssam case SIOCSIFFLAGS: 60130230Ssam if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 60230230Ssam enpinit(ifp->if_unit); /* reset board */ 60330230Ssam ifp->if_flags &= ~IFF_RUNNING; 60430230Ssam } else if (ifp->if_flags&IFF_UP && 60530230Ssam (ifp->if_flags&IFF_RUNNING) == 0) 60630230Ssam enpinit(ifp->if_unit); 60729649Ssam break; 60829649Ssam 60929649Ssam default: 61029649Ssam error = EINVAL; 61129649Ssam } 61230230Ssam splx(s); 61330230Ssam return (error); 61429649Ssam } 61529649Ssam 61630230Ssam enpsetaddr(unit, addr, enaddr) 61730230Ssam int unit; 61830230Ssam struct enpdevice *addr; 61930230Ssam u_char *enaddr; 62029649Ssam { 62130230Ssam u_char *cp; 62230230Ssam int i, code; 62329649Ssam 62430230Ssam cp = &addr->enp_addr.e_baseaddr.ea_addr[0]; 62530230Ssam for (i = 0; i < 6; i++) 62630230Ssam *cp++ = ~*enaddr++; 62730295Ssam enpcopy((u_char *)&addr->enp_addr.e_listsize, (u_char *)&code, 62830295Ssam sizeof (code)); 62930230Ssam code |= E_ADDR_SUPP; 63030295Ssam enpcopy((u_char *)&code, (u_char *)&addr->enp_addr.e_listsize, 63130295Ssam sizeof (code)); 63230230Ssam enpinit(unit); 63329649Ssam } 63429649Ssam 63529649Ssam /* 63630230Ssam * Routines to synchronize enp and host. 63729649Ssam */ 63830295Ssam #ifdef notdef 63929649Ssam static 64030230Ssam ringinit(rp, size) 64130230Ssam register RING *rp; 64229649Ssam { 64329649Ssam 64429649Ssam rp->r_rdidx = rp->r_wrtidx = 0; 64529649Ssam rp->r_size = size; 64629649Ssam } 64729649Ssam 64829649Ssam static 64930295Ssam ringfull(rp) 65030230Ssam register RING *rp; 65129649Ssam { 65230295Ssam register short idx; 65330230Ssam 65430295Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 65530295Ssam return (idx == rp->r_rdidx); 65629649Ssam } 65729649Ssam 65829649Ssam static 65930295Ssam fir(rp) 66030230Ssam register RING *rp; 66129649Ssam { 66229649Ssam 66330295Ssam return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0); 66429649Ssam } 66530295Ssam #endif 66629649Ssam 66729649Ssam static 66830295Ssam ringempty(rp) 66930295Ssam register RING *rp; 67030295Ssam { 67130295Ssam 67230295Ssam return (rp->r_rdidx == rp->r_wrtidx); 67330295Ssam } 67430295Ssam 67530295Ssam static 67630230Ssam ringput(rp, v) 67730230Ssam register RING *rp; 67830295Ssam BCB *v; 67929649Ssam { 68029649Ssam register int idx; 68129649Ssam 68229649Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 68330230Ssam if (idx != rp->r_rdidx) { 68430295Ssam rp->r_slot[rp->r_wrtidx] = (int)v; 68529649Ssam rp->r_wrtidx = idx; 68630230Ssam if ((idx -= rp->r_rdidx) < 0) 68729649Ssam idx += rp->r_size; 68830230Ssam return (idx); /* num ring entries */ 68929649Ssam } 69030230Ssam return (0); 69129649Ssam } 69229649Ssam 69329649Ssam static 69430230Ssam ringget(rp) 69530230Ssam register RING *rp; 69629649Ssam { 69729649Ssam register int i = 0; 69829649Ssam 69930230Ssam if (rp->r_rdidx != rp->r_wrtidx) { 70030230Ssam i = rp->r_slot[rp->r_rdidx]; 70129649Ssam rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1); 70229649Ssam } 70330230Ssam return (i); 70429649Ssam } 70529649Ssam 70630230Ssam /* 70730230Ssam * ENP Ram device. 70830230Ssam */ 70930230Ssam enpr_open(dev) 71030230Ssam dev_t dev; 71129649Ssam { 71230230Ssam register int unit = ENPUNIT(dev); 71330230Ssam struct vba_device *ui; 71430230Ssam struct enpdevice *addr; 71529649Ssam 71630230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 71730230Ssam (addr = (struct enpdevice *)ui->ui_addr) == 0) 71830230Ssam return (ENODEV); 71930230Ssam if (addr->enp_state != S_ENPRESET) 72030230Ssam return (EACCES); /* enp is not in reset state, don't open */ 72130230Ssam return (0); 72229649Ssam } 72329649Ssam 72430295Ssam /*ARGSUSED*/ 72530230Ssam enpr_close(dev) 72630230Ssam dev_t dev; 72729649Ssam { 72829649Ssam 72930230Ssam return (0); 73029649Ssam } 73129649Ssam 73230230Ssam enpr_read(dev, uio) 73330230Ssam dev_t dev; 73430230Ssam register struct uio *uio; 73529649Ssam { 73630230Ssam register struct iovec *iov; 73730230Ssam struct enpdevice *addr; 73830230Ssam int error; 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; 74630295Ssam error = useracc(iov->iov_base, (unsigned)iov->iov_len, 0); 74730230Ssam if (error) 74830230Ssam return (error); 74930295Ssam enpcopy((u_char *)&addr->enp_ram[uio->uio_offset], 75030295Ssam (u_char *)iov->iov_base, (u_int)iov->iov_len); 75130230Ssam uio->uio_resid -= iov->iov_len; 75230230Ssam iov->iov_len = 0; 75330230Ssam return (0); 75429649Ssam } 75529649Ssam 75630230Ssam enpr_write(dev, uio) 75730230Ssam dev_t dev; 75830230Ssam register struct uio *uio; 75929649Ssam { 76030230Ssam register struct enpdevice *addr; 76130230Ssam register struct iovec *iov; 76230230Ssam register error; 76329649Ssam 76430230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 76530230Ssam iov = uio->uio_iov; 76630230Ssam if (uio->uio_offset > RAM_SIZE) 76730230Ssam return (ENODEV); 76830230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 76930230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 77030295Ssam error = useracc(iov->iov_base, (unsigned)iov->iov_len, 1); 77130230Ssam if (error) 77230230Ssam return (error); 77330295Ssam enpcopy((u_char *)iov->iov_base, 77430295Ssam (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len); 77530230Ssam uio->uio_resid -= iov->iov_len; 77630230Ssam iov->iov_len = 0; 77730230Ssam return (0); 77829649Ssam } 77929649Ssam 78030295Ssam /*ARGSUSED*/ 78130230Ssam enpr_ioctl(dev, cmd, data) 78230230Ssam dev_t dev; 78330230Ssam caddr_t data; 78429649Ssam { 78530230Ssam register struct enpdevice *addr; 78630230Ssam register unit = ENPUNIT(dev); 78729649Ssam 78830230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 78930230Ssam switch(cmd) { 79030230Ssam 79130230Ssam case ENPIOGO: 79230230Ssam /* not needed if prom based version */ 79330230Ssam addr->enp_base = (int)addr; 79430230Ssam addr->enp_intrvec = enp_softc[unit].es_ivec; 79530230Ssam ENP_GO(addr, ENPSTART); 79630230Ssam DELAY(200000); 79730230Ssam enpinit(unit); 79830230Ssam addr->enp_state = S_ENPRUN; /* it is running now */ 79930230Ssam /* end of not needed */ 80030230Ssam break; 80130230Ssam 80230230Ssam case ENPIORESET: 80330230Ssam RESET_ENP(addr); 80430230Ssam addr->enp_state = S_ENPRESET; /* it is reset now */ 80530230Ssam DELAY(100000); 80630230Ssam break; 80729649Ssam } 80830230Ssam return (0); 80929649Ssam } 81029649Ssam #endif 811