134508Skarels /* 234508Skarels * Copyright (c) 1988 Regents of the University of California. 334508Skarels * All rights reserved. 434508Skarels * 535383Skarels * This code is derived from software contributed to Berkeley by 635383Skarels * Computer Consoles Inc. 735383Skarels * 8*44532Sbostic * %sccs.include.redist.c% 934508Skarels * 10*44532Sbostic * @(#)if_enp.c 7.7 (Berkeley) 06/28/90 1134508Skarels */ 1229649Ssam 1329649Ssam #include "enp.h" 1429649Ssam #if NENP > 0 1529649Ssam /* 1630986Ssam * CMC ENP-20 Ethernet Controller. 1729649Ssam */ 1829649Ssam #include "param.h" 1929649Ssam #include "systm.h" 2029649Ssam #include "mbuf.h" 2129649Ssam #include "buf.h" 2229649Ssam #include "protosw.h" 2329649Ssam #include "socket.h" 2429649Ssam #include "vmmac.h" 2530230Ssam #include "ioctl.h" 2629649Ssam #include "errno.h" 2730230Ssam #include "vmparam.h" 2830230Ssam #include "syslog.h" 2929649Ssam #include "uio.h" 3029649Ssam 3129649Ssam #include "../net/if.h" 3229649Ssam #include "../net/netisr.h" 3329649Ssam #include "../net/route.h" 3430230Ssam #ifdef INET 3529649Ssam #include "../netinet/in.h" 3629649Ssam #include "../netinet/in_systm.h" 3730230Ssam #include "../netinet/in_var.h" 3829649Ssam #include "../netinet/ip.h" 3929649Ssam #include "../netinet/ip_var.h" 4029649Ssam #include "../netinet/if_ether.h" 4130230Ssam #endif 4230230Ssam #ifdef NS 4330230Ssam #include "../netns/ns.h" 4430230Ssam #include "../netns/ns_if.h" 4530230Ssam #endif 4629649Ssam 4730230Ssam #include "../tahoe/cpu.h" 4830230Ssam #include "../tahoe/pte.h" 4930230Ssam #include "../tahoe/mtpr.h" 5030230Ssam 5129649Ssam #include "../tahoevba/vbavar.h" 5230230Ssam #include "../tahoeif/if_enpreg.h" 5329649Ssam 5430230Ssam #define ENPSTART 0xf02000 /* standard enp start addr */ 5530230Ssam #define ENPUNIT(dev) (minor(dev)) /* for enp ram devices */ 5630986Ssam /* macros for dealing with longs in i/o space */ 5730986Ssam #define ENPGETLONG(a) ((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1])) 5830986Ssam #define ENPSETLONG(a,v) \ 5930986Ssam { register u_short *wp = (u_short *)(a); \ 6030986Ssam wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];} 6129649Ssam 6229649Ssam int enpprobe(), enpattach(), enpintr(); 6330298Ssam long enpstd[] = { 0xfff41000, 0xfff61000, 0 }; 6430230Ssam struct vba_device *enpinfo[NENP]; 6529649Ssam struct vba_driver enpdriver = 6630230Ssam { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 }; 6729649Ssam 6835383Skarels int enpinit(), enpioctl(), enpreset(), enpoutput(), enpstart(); 6929649Ssam struct mbuf *enpget(); 7029649Ssam 7129649Ssam /* 7229649Ssam * Ethernet software status per interface. 7329649Ssam * 7429649Ssam * Each interface is referenced by a network interface structure, 7529649Ssam * es_if, which the routing code uses to locate the interface. 7629649Ssam * This structure contains the output queue for the interface, its address, ... 7729649Ssam */ 7830230Ssam struct enp_softc { 7930230Ssam struct arpcom es_ac; /* common ethernet structures */ 8030230Ssam #define es_if es_ac.ac_if 8130986Ssam #define es_addr es_ac.ac_enaddr 8230230Ssam short es_ivec; /* interrupt vector */ 8330230Ssam } enp_softc[NENP]; 8430230Ssam extern struct ifnet loif; 8529649Ssam 8630230Ssam enpprobe(reg, vi) 8730230Ssam caddr_t reg; 8830230Ssam struct vba_device *vi; 8929649Ssam { 9030230Ssam register br, cvec; /* must be r12, r11 */ 9130230Ssam register struct enpdevice *addr = (struct enpdevice *)reg; 9230230Ssam struct enp_softc *es = &enp_softc[vi->ui_unit]; 9329649Ssam 9430230Ssam #ifdef lint 9530295Ssam br = 0; cvec = br; br = cvec; 9630230Ssam enpintr(0); 9730230Ssam #endif 9830295Ssam if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2)) 9930230Ssam return (0); 10030230Ssam es->es_ivec = --vi->ui_hd->vh_lastiv; 10130230Ssam addr->enp_state = S_ENPRESET; /* reset by VERSAbus reset */ 10230230Ssam br = 0x14, cvec = es->es_ivec; /* XXX */ 10330230Ssam return (sizeof (struct enpdevice)); 10429649Ssam } 10529649Ssam 10629649Ssam /* 10729649Ssam * Interface exists: make available by filling in network interface 10829649Ssam * record. System will initialize the interface when it is ready 10929649Ssam * to accept packets. 11029649Ssam */ 11130230Ssam enpattach(ui) 11230230Ssam register struct vba_device *ui; 11329649Ssam { 11430230Ssam struct enp_softc *es = &enp_softc[ui->ui_unit]; 11530230Ssam register struct ifnet *ifp = &es->es_if; 11629649Ssam 11730230Ssam ifp->if_unit = ui->ui_unit; 11829649Ssam ifp->if_name = "enp"; 11929649Ssam ifp->if_mtu = ETHERMTU; 12029649Ssam ifp->if_init = enpinit; 12129649Ssam ifp->if_ioctl = enpioctl; 12237474Ssklower ifp->if_output = ether_output; 12335411Skarels ifp->if_start = enpstart; 12429649Ssam ifp->if_reset = enpreset; 12535411Skarels ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 12629649Ssam if_attach(ifp); 12729649Ssam } 12829649Ssam 12929649Ssam /* 13030230Ssam * Reset of interface after "system" reset. 13129649Ssam */ 13230230Ssam enpreset(unit, vban) 13330230Ssam int unit, vban; 13429649Ssam { 13530230Ssam register struct vba_device *ui; 13629649Ssam 13730230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 13830230Ssam ui->ui_vbanum != vban) 13930230Ssam return; 14030230Ssam printf(" enp%d", unit); 14129649Ssam enpinit(unit); 14229649Ssam } 14329649Ssam 14429649Ssam /* 14530230Ssam * Initialization of interface; clear recorded pending operations. 14629649Ssam */ 14730230Ssam enpinit(unit) 14830230Ssam int unit; 14929649Ssam { 15030230Ssam struct enp_softc *es = &enp_softc[unit]; 15130230Ssam register struct vba_device *ui = enpinfo[unit]; 15230230Ssam struct enpdevice *addr; 15330230Ssam register struct ifnet *ifp = &es->es_if; 15430230Ssam int s; 15529649Ssam 15630230Ssam if (ifp->if_addrlist == (struct ifaddr *)0) 15730230Ssam return; 15830230Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 15930230Ssam addr = (struct enpdevice *)ui->ui_addr; 16030230Ssam s = splimp(); 16130230Ssam RESET_ENP(addr); 16230230Ssam DELAY(200000); 16330230Ssam es->es_if.if_flags |= IFF_RUNNING; 16430230Ssam splx(s); 16529649Ssam } 16629649Ssam } 16729649Ssam 16829649Ssam /* 16929649Ssam * Ethernet interface interrupt. 17029649Ssam */ 17130230Ssam enpintr(unit) 17230230Ssam int unit; 17329649Ssam { 17430230Ssam register struct enpdevice *addr; 17530230Ssam register BCB *bcbp; 17629649Ssam 17730230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 17830295Ssam #if ENP == 30 17930230Ssam if (!IS_ENP_INTR(addr)) 18029649Ssam return; 18130230Ssam ACK_ENP_INTR(addr); 18230295Ssam #endif 18330295Ssam while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) { 18435383Skarels enpread(&enp_softc[unit], bcbp); 18530295Ssam (void) ringput((RING *)&addr->enp_enpfree, bcbp); 18629649Ssam } 18729649Ssam } 18829649Ssam 18929649Ssam /* 19029649Ssam * Read input packet, examine its packet type, and enqueue it. 19129649Ssam */ 19230295Ssam enpread(es, bcbp) 19330230Ssam struct enp_softc *es; 19430230Ssam register BCB *bcbp; 19529649Ssam { 19629649Ssam register struct ether_header *enp; 19729649Ssam struct mbuf *m; 19830295Ssam int s, len, off, resid; 19929649Ssam 20029649Ssam es->es_if.if_ipackets++; 20129649Ssam /* 20229649Ssam * Get input data length. 20329649Ssam * Get pointer to ethernet header (in input buffer). 20429649Ssam * Deal with trailer protocol: if type is PUP trailer 20529649Ssam * get true type from first 16-bit word past data. 20629649Ssam * Remember that type was trailer by setting off. 20729649Ssam */ 20830230Ssam len = bcbp->b_msglen - sizeof (struct ether_header); 20930986Ssam enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr); 21030230Ssam #define enpdataaddr(enp, off, type) \ 21130230Ssam ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off)))) 21230230Ssam enp->ether_type = ntohs((u_short)enp->ether_type); 21330230Ssam if (enp->ether_type >= ETHERTYPE_TRAIL && 21430230Ssam enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 21530230Ssam off = (enp->ether_type - ETHERTYPE_TRAIL) * 512; 21630230Ssam if (off >= ETHERMTU) 21735383Skarels return; 21830230Ssam enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *)); 21930230Ssam resid = ntohs(*(enpdataaddr(enp, off+2, u_short *))); 22030230Ssam if (off + resid > len) 22135383Skarels return; 22229649Ssam len = off + resid; 22330230Ssam } else 22429649Ssam off = 0; 22530230Ssam if (len == 0) 22635383Skarels return; 22729649Ssam 22829649Ssam /* 22929649Ssam * Pull packet off interface. Off is nonzero if packet 23029649Ssam * has trailing header; enpget will then force this header 23135383Skarels * information to be at the front. 23229649Ssam */ 23330986Ssam m = enpget((u_char *)enp, len, off, &es->es_if); 23430230Ssam if (m == 0) 23535383Skarels return; 23637474Ssklower ether_input(&es->es_if, enp, m); 23729649Ssam } 23829649Ssam 23935383Skarels enpstart(ifp) 24030230Ssam struct ifnet *ifp; 24129649Ssam { 24229649Ssam 24335383Skarels if (enpput(ifp)) 24435411Skarels return (ENOBUFS); 24535411Skarels else 24635411Skarels return (0); 24729649Ssam } 24829649Ssam 24929649Ssam /* 25030230Ssam * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus. 25129649Ssam */ 25235383Skarels enpput(ifp) 25335383Skarels struct ifnet *ifp; 25429649Ssam { 25529649Ssam register BCB *bcbp; 25630230Ssam register struct enpdevice *addr; 25729649Ssam register struct mbuf *mp; 25829649Ssam register u_char *bp; 25930230Ssam register u_int len; 26035411Skarels int unit = ifp->if_unit, ret = 1; 26135383Skarels struct mbuf *m; 26229649Ssam 26330230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 26435383Skarels again: 26535411Skarels if (ringempty((RING *)&addr->enp_hostfree)) { 26635411Skarels /* ifp->if_flags |= IFF_OACTIVE; */ 26735411Skarels return (ret); 26835411Skarels } 26935383Skarels IF_DEQUEUE(&ifp->if_snd, m); 27035411Skarels if (m == 0) { 27135411Skarels ifp->if_flags &= ~IFF_OACTIVE; 27235411Skarels return (0); 27335411Skarels } 27430295Ssam bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree); 27529649Ssam bcbp->b_len = 0; 27630986Ssam bp = (u_char *)ENPGETLONG(&bcbp->b_addr); 27730230Ssam for (mp = m; mp; mp = mp->m_next) { 27829649Ssam len = mp->m_len; 27930230Ssam if (len == 0) 28029649Ssam continue; 28135411Skarels enpcopy(mtod(mp, u_char *), bp, len); 28229649Ssam bp += len; 28329649Ssam bcbp->b_len += len; 28429649Ssam } 28535411Skarels bcbp->b_len = max(ETHERMIN+sizeof (struct ether_header), bcbp->b_len); 28629649Ssam bcbp->b_reserved = 0; 28730295Ssam if (ringput((RING *)&addr->enp_toenp, bcbp) == 1) 28830230Ssam INTR_ENP(addr); 28929649Ssam m_freem(m); 29035411Skarels ret = 0; 29135383Skarels goto again; 29229649Ssam } 29329649Ssam 29429649Ssam /* 29530230Ssam * Routine to copy from VERSAbus memory into mbufs. 29629649Ssam * 29729649Ssam * Warning: This makes the fairly safe assumption that 29829649Ssam * mbufs have even lengths. 29929649Ssam */ 30029649Ssam struct mbuf * 30135383Skarels enpget(rxbuf, totlen, off, ifp) 30230230Ssam u_char *rxbuf; 30335383Skarels int totlen, off; 30430230Ssam struct ifnet *ifp; 30529649Ssam { 30635411Skarels register u_char *cp; 30729649Ssam register struct mbuf *m; 30830230Ssam struct mbuf *top = 0, **mp = ⊤ 30935383Skarels int len; 31035383Skarels u_char *packet_end; 31129649Ssam 31235383Skarels rxbuf += sizeof (struct ether_header); 31335383Skarels cp = rxbuf; 31435383Skarels packet_end = cp + totlen; 31535383Skarels if (off) { 31635383Skarels off += 2 * sizeof(u_short); 31735383Skarels totlen -= 2 *sizeof(u_short); 31835383Skarels cp = rxbuf + off; 31935383Skarels } 32035383Skarels 32135383Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 32235383Skarels if (m == 0) 32335383Skarels return (0); 32435383Skarels m->m_pkthdr.rcvif = ifp; 32535383Skarels m->m_pkthdr.len = totlen; 32635383Skarels m->m_len = MHLEN; 32735383Skarels 32830230Ssam while (totlen > 0) { 32935383Skarels if (top) { 33035383Skarels MGET(m, M_DONTWAIT, MT_DATA); 33135383Skarels if (m == 0) { 33235383Skarels m_freem(top); 33335383Skarels return (0); 33435383Skarels } 33535383Skarels m->m_len = MLEN; 33635383Skarels } 33735383Skarels len = min(totlen, (packet_end - cp)); 33835383Skarels if (len >= MINCLSIZE) { 33935383Skarels MCLGET(m, M_DONTWAIT); 34035383Skarels if (m->m_flags & M_EXT) 34135383Skarels m->m_len = len = min(len, MCLBYTES); 34230230Ssam else 34335383Skarels len = m->m_len; 34430230Ssam } else { 34530230Ssam /* 34635383Skarels * Place initial small packet/header at end of mbuf. 34730230Ssam */ 34835383Skarels if (len < m->m_len) { 34935411Skarels if (top == 0 && len + max_linkhdr <= m->m_len) 35035383Skarels m->m_data += max_linkhdr; 35135383Skarels m->m_len = len; 35235383Skarels } else 35335383Skarels len = m->m_len; 35430230Ssam } 35535411Skarels enpcopy(cp, mtod(m, u_char *), (u_int)len); 35629649Ssam *mp = m; 35729649Ssam mp = &m->m_next; 35835383Skarels totlen -= len; 35935383Skarels cp += len; 36035383Skarels if (cp == packet_end) 36135383Skarels cp = rxbuf; 36229649Ssam } 36329649Ssam return (top); 36429649Ssam } 36529649Ssam 36630230Ssam enpcopy(from, to, cnt) 36730295Ssam register u_char *from, *to; 36830295Ssam register u_int cnt; 36930230Ssam { 37030230Ssam register c; 37130230Ssam register short *f, *t; 37230230Ssam 37330230Ssam if (((int)from&01) && ((int)to&01)) { 37430230Ssam /* source & dest at odd addresses */ 37530230Ssam *to++ = *from++; 37630230Ssam --cnt; 37730230Ssam } 37830230Ssam if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) { 37930230Ssam t = (short *)to; 38030230Ssam f = (short *)from; 38130230Ssam for (c = cnt>>1; c; --c) /* even address copy */ 38230230Ssam *t++ = *f++; 38330230Ssam cnt &= 1; 38430230Ssam if (cnt) { /* odd len */ 38530295Ssam from = (u_char *)f; 38630295Ssam to = (u_char *)t; 38730230Ssam *to = *from; 38830230Ssam } 38930230Ssam } 39030295Ssam while ((int)cnt-- > 0) /* one of the address(es) must be odd */ 39130230Ssam *to++ = *from++; 39230230Ssam } 39330230Ssam 39429649Ssam /* 39529649Ssam * Process an ioctl request. 39629649Ssam */ 39729649Ssam enpioctl(ifp, cmd, data) 39830230Ssam register struct ifnet *ifp; 39930230Ssam int cmd; 40030230Ssam caddr_t data; 40129649Ssam { 40230230Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 40330230Ssam struct enpdevice *addr; 40430230Ssam int s = splimp(), error = 0; 40529649Ssam 40629649Ssam switch (cmd) { 40729649Ssam 40829649Ssam case SIOCSIFADDR: 40930230Ssam ifp->if_flags |= IFF_UP; 41037474Ssklower switch (ifa->ifa_addr->sa_family) { 41130230Ssam #ifdef INET 41230230Ssam case AF_INET: 41330230Ssam enpinit(ifp->if_unit); 41430230Ssam ((struct arpcom *)ifp)->ac_ipaddr = 41530230Ssam IA_SIN(ifa)->sin_addr; 41630230Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 41729649Ssam break; 41830230Ssam #endif 41930230Ssam #ifdef NS 42030230Ssam case AF_NS: { 42130230Ssam struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 42230230Ssam struct enp_softc *es = &enp_softc[ifp->if_unit]; 42330230Ssam 42430230Ssam if (!ns_nullhost(*ina)) { 42530230Ssam ifp->if_flags &= ~IFF_RUNNING; 42630230Ssam addr = (struct enpdevice *) 42730230Ssam enpinfo[ifp->if_unit]->ui_addr; 42830230Ssam enpsetaddr(ifp->if_unit, addr, 42930230Ssam ina->x_host.c_host); 43030230Ssam } else 43130986Ssam ina->x_host = *(union ns_host *)es->es_addr; 43230230Ssam enpinit(ifp->if_unit); 43330230Ssam break; 43429649Ssam } 43530230Ssam #endif 43630230Ssam default: 43730230Ssam enpinit(ifp->if_unit); 43830230Ssam break; 43929649Ssam } 44029649Ssam break; 44129649Ssam 44230230Ssam case SIOCSIFFLAGS: 44330230Ssam if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 44430230Ssam enpinit(ifp->if_unit); /* reset board */ 44530230Ssam ifp->if_flags &= ~IFF_RUNNING; 44630230Ssam } else if (ifp->if_flags&IFF_UP && 44730230Ssam (ifp->if_flags&IFF_RUNNING) == 0) 44830230Ssam enpinit(ifp->if_unit); 44929649Ssam break; 45029649Ssam 45129649Ssam default: 45229649Ssam error = EINVAL; 45329649Ssam } 45430230Ssam splx(s); 45530230Ssam return (error); 45629649Ssam } 45729649Ssam 45830230Ssam enpsetaddr(unit, addr, enaddr) 45930230Ssam int unit; 46030230Ssam struct enpdevice *addr; 46130230Ssam u_char *enaddr; 46229649Ssam { 46329649Ssam 46430986Ssam enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr, 46530986Ssam sizeof (struct ether_addr)); 46630230Ssam enpinit(unit); 46730986Ssam enpgetaddr(unit, addr); 46829649Ssam } 46929649Ssam 47030986Ssam enpgetaddr(unit, addr) 47130986Ssam int unit; 47230986Ssam struct enpdevice *addr; 47330986Ssam { 47430986Ssam struct enp_softc *es = &enp_softc[unit]; 47530986Ssam 47630986Ssam enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr, 47730986Ssam sizeof (struct ether_addr)); 47830986Ssam printf("enp%d: hardware address %s\n", 47930986Ssam unit, ether_sprintf(es->es_addr)); 48030986Ssam } 48130986Ssam 48229649Ssam /* 48330230Ssam * Routines to synchronize enp and host. 48429649Ssam */ 48530295Ssam #ifdef notdef 48629649Ssam static 48730230Ssam ringinit(rp, size) 48830230Ssam register RING *rp; 48929649Ssam { 49029649Ssam 49129649Ssam rp->r_rdidx = rp->r_wrtidx = 0; 49229649Ssam rp->r_size = size; 49329649Ssam } 49429649Ssam 49529649Ssam static 49630295Ssam ringfull(rp) 49730230Ssam register RING *rp; 49829649Ssam { 49930295Ssam register short idx; 50030230Ssam 50130295Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 50230295Ssam return (idx == rp->r_rdidx); 50329649Ssam } 50429649Ssam 50529649Ssam static 50630295Ssam fir(rp) 50730230Ssam register RING *rp; 50829649Ssam { 50929649Ssam 51030295Ssam return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0); 51129649Ssam } 51230295Ssam #endif 51329649Ssam 51429649Ssam static 51530295Ssam ringempty(rp) 51630295Ssam register RING *rp; 51730295Ssam { 51830295Ssam 51930295Ssam return (rp->r_rdidx == rp->r_wrtidx); 52030295Ssam } 52130295Ssam 52230295Ssam static 52330230Ssam ringput(rp, v) 52430230Ssam register RING *rp; 52530295Ssam BCB *v; 52629649Ssam { 52729649Ssam register int idx; 52829649Ssam 52929649Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 53030230Ssam if (idx != rp->r_rdidx) { 53130986Ssam ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v); 53229649Ssam rp->r_wrtidx = idx; 53330230Ssam if ((idx -= rp->r_rdidx) < 0) 53429649Ssam idx += rp->r_size; 53530230Ssam return (idx); /* num ring entries */ 53629649Ssam } 53730230Ssam return (0); 53829649Ssam } 53929649Ssam 54029649Ssam static 54130230Ssam ringget(rp) 54230230Ssam register RING *rp; 54329649Ssam { 54429649Ssam register int i = 0; 54529649Ssam 54630230Ssam if (rp->r_rdidx != rp->r_wrtidx) { 54730986Ssam i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]); 54829649Ssam rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1); 54929649Ssam } 55030230Ssam return (i); 55129649Ssam } 55229649Ssam 55330230Ssam /* 55430230Ssam * ENP Ram device. 55530230Ssam */ 55630230Ssam enpr_open(dev) 55730230Ssam dev_t dev; 55829649Ssam { 55930230Ssam register int unit = ENPUNIT(dev); 56030230Ssam struct vba_device *ui; 56130230Ssam struct enpdevice *addr; 56229649Ssam 56330230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 56430230Ssam (addr = (struct enpdevice *)ui->ui_addr) == 0) 56530230Ssam return (ENODEV); 56630230Ssam if (addr->enp_state != S_ENPRESET) 56730230Ssam return (EACCES); /* enp is not in reset state, don't open */ 56830230Ssam return (0); 56929649Ssam } 57029649Ssam 57130295Ssam /*ARGSUSED*/ 57230230Ssam enpr_close(dev) 57330230Ssam dev_t dev; 57429649Ssam { 57529649Ssam 57630230Ssam return (0); 57729649Ssam } 57829649Ssam 57930230Ssam enpr_read(dev, uio) 58030230Ssam dev_t dev; 58130230Ssam register struct uio *uio; 58229649Ssam { 58330230Ssam register struct iovec *iov; 58430230Ssam struct enpdevice *addr; 58529649Ssam 58630230Ssam if (uio->uio_offset > RAM_SIZE) 58730230Ssam return (ENODEV); 58830295Ssam iov = uio->uio_iov; 58930230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 59030230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 59130230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 59230986Ssam if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0) 59330986Ssam return (EFAULT); 59430295Ssam enpcopy((u_char *)&addr->enp_ram[uio->uio_offset], 59530295Ssam (u_char *)iov->iov_base, (u_int)iov->iov_len); 59630230Ssam uio->uio_resid -= iov->iov_len; 59730230Ssam iov->iov_len = 0; 59830230Ssam return (0); 59929649Ssam } 60029649Ssam 60130230Ssam enpr_write(dev, uio) 60230230Ssam dev_t dev; 60330230Ssam register struct uio *uio; 60429649Ssam { 60530230Ssam register struct enpdevice *addr; 60630230Ssam register struct iovec *iov; 60729649Ssam 60830230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 60930230Ssam iov = uio->uio_iov; 61030230Ssam if (uio->uio_offset > RAM_SIZE) 61130230Ssam return (ENODEV); 61230230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 61330230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 61430986Ssam if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0) 61530986Ssam return (EFAULT); 61630295Ssam enpcopy((u_char *)iov->iov_base, 61730295Ssam (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len); 61830230Ssam uio->uio_resid -= iov->iov_len; 61940659Skarels uio->uio_offset += iov->iov_len; 62030230Ssam iov->iov_len = 0; 62130230Ssam return (0); 62229649Ssam } 62329649Ssam 62430295Ssam /*ARGSUSED*/ 62530230Ssam enpr_ioctl(dev, cmd, data) 62630230Ssam dev_t dev; 62730230Ssam caddr_t data; 62829649Ssam { 62930230Ssam register unit = ENPUNIT(dev); 63030986Ssam struct enpdevice *addr; 63129649Ssam 63230230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 63330230Ssam switch(cmd) { 63430230Ssam 63530230Ssam case ENPIOGO: 63630986Ssam ENPSETLONG(&addr->enp_base, addr); 63730230Ssam addr->enp_intrvec = enp_softc[unit].es_ivec; 63830230Ssam ENP_GO(addr, ENPSTART); 63930230Ssam DELAY(200000); 64030230Ssam enpinit(unit); 64130986Ssam /* 64230986Ssam * Fetch Ethernet address after link level 64330986Ssam * is booted (firmware copies manufacturer's 64430986Ssam * address from on-board ROM). 64530986Ssam */ 64630986Ssam enpgetaddr(unit, addr); 64730986Ssam addr->enp_state = S_ENPRUN; 64830230Ssam break; 64930230Ssam 65030230Ssam case ENPIORESET: 65130230Ssam RESET_ENP(addr); 65230986Ssam addr->enp_state = S_ENPRESET; 65330230Ssam DELAY(100000); 65430230Ssam break; 65530986Ssam default: 65630986Ssam return (EINVAL); 65729649Ssam } 65830230Ssam return (0); 65929649Ssam } 66029649Ssam #endif 661