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 * 834508Skarels * Redistribution and use in source and binary forms are permitted 934864Sbostic * provided that the above copyright notice and this paragraph are 1034864Sbostic * duplicated in all such forms and that any documentation, 1134864Sbostic * advertising materials, and other materials related to such 1234864Sbostic * distribution and use acknowledge that the software was developed 1334864Sbostic * by the University of California, Berkeley. The name of the 1434864Sbostic * University may not be used to endorse or promote products derived 1534864Sbostic * from this software without specific prior written permission. 1634864Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1734864Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1834864Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1934508Skarels * 20*35411Skarels * @(#)if_enp.c 7.4 (Berkeley) 08/27/88 2134508Skarels */ 2229649Ssam 2329649Ssam #include "enp.h" 2429649Ssam #if NENP > 0 2529649Ssam /* 2630986Ssam * CMC ENP-20 Ethernet Controller. 2729649Ssam */ 2829649Ssam #include "param.h" 2929649Ssam #include "systm.h" 3029649Ssam #include "mbuf.h" 3129649Ssam #include "buf.h" 3229649Ssam #include "protosw.h" 3329649Ssam #include "socket.h" 3429649Ssam #include "vmmac.h" 3530230Ssam #include "ioctl.h" 3629649Ssam #include "errno.h" 3730230Ssam #include "vmparam.h" 3830230Ssam #include "syslog.h" 3929649Ssam #include "uio.h" 4029649Ssam 4129649Ssam #include "../net/if.h" 4229649Ssam #include "../net/netisr.h" 4329649Ssam #include "../net/route.h" 4430230Ssam #ifdef INET 4529649Ssam #include "../netinet/in.h" 4629649Ssam #include "../netinet/in_systm.h" 4730230Ssam #include "../netinet/in_var.h" 4829649Ssam #include "../netinet/ip.h" 4929649Ssam #include "../netinet/ip_var.h" 5029649Ssam #include "../netinet/if_ether.h" 5130230Ssam #endif 5230230Ssam #ifdef NS 5330230Ssam #include "../netns/ns.h" 5430230Ssam #include "../netns/ns_if.h" 5530230Ssam #endif 5629649Ssam 5730230Ssam #include "../tahoe/cpu.h" 5830230Ssam #include "../tahoe/pte.h" 5930230Ssam #include "../tahoe/mtpr.h" 6030230Ssam 6129649Ssam #include "../tahoevba/vbavar.h" 6230230Ssam #include "../tahoeif/if_enpreg.h" 6329649Ssam 6430230Ssam #define ENPSTART 0xf02000 /* standard enp start addr */ 6530230Ssam #define ENPUNIT(dev) (minor(dev)) /* for enp ram devices */ 6630986Ssam /* macros for dealing with longs in i/o space */ 6730986Ssam #define ENPGETLONG(a) ((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1])) 6830986Ssam #define ENPSETLONG(a,v) \ 6930986Ssam { register u_short *wp = (u_short *)(a); \ 7030986Ssam wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];} 7129649Ssam 7229649Ssam int enpprobe(), enpattach(), enpintr(); 7330298Ssam long enpstd[] = { 0xfff41000, 0xfff61000, 0 }; 7430230Ssam struct vba_device *enpinfo[NENP]; 7529649Ssam struct vba_driver enpdriver = 7630230Ssam { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 }; 7729649Ssam 7835383Skarels int enpinit(), enpioctl(), enpreset(), enpoutput(), enpstart(); 7929649Ssam struct mbuf *enpget(); 8029649Ssam 8129649Ssam /* 8229649Ssam * Ethernet software status per interface. 8329649Ssam * 8429649Ssam * Each interface is referenced by a network interface structure, 8529649Ssam * es_if, which the routing code uses to locate the interface. 8629649Ssam * This structure contains the output queue for the interface, its address, ... 8729649Ssam */ 8830230Ssam struct enp_softc { 8930230Ssam struct arpcom es_ac; /* common ethernet structures */ 9030230Ssam #define es_if es_ac.ac_if 9130986Ssam #define es_addr es_ac.ac_enaddr 9230230Ssam short es_ivec; /* interrupt vector */ 9330230Ssam } enp_softc[NENP]; 9430230Ssam extern struct ifnet loif; 9529649Ssam 9630230Ssam enpprobe(reg, vi) 9730230Ssam caddr_t reg; 9830230Ssam struct vba_device *vi; 9929649Ssam { 10030230Ssam register br, cvec; /* must be r12, r11 */ 10130230Ssam register struct enpdevice *addr = (struct enpdevice *)reg; 10230230Ssam struct enp_softc *es = &enp_softc[vi->ui_unit]; 10329649Ssam 10430230Ssam #ifdef lint 10530295Ssam br = 0; cvec = br; br = cvec; 10630230Ssam enpintr(0); 10730230Ssam #endif 10830295Ssam if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2)) 10930230Ssam return (0); 11030230Ssam es->es_ivec = --vi->ui_hd->vh_lastiv; 11130230Ssam addr->enp_state = S_ENPRESET; /* reset by VERSAbus reset */ 11230230Ssam br = 0x14, cvec = es->es_ivec; /* XXX */ 11330230Ssam return (sizeof (struct enpdevice)); 11429649Ssam } 11529649Ssam 11629649Ssam /* 11729649Ssam * Interface exists: make available by filling in network interface 11829649Ssam * record. System will initialize the interface when it is ready 11929649Ssam * to accept packets. 12029649Ssam */ 12130230Ssam enpattach(ui) 12230230Ssam register struct vba_device *ui; 12329649Ssam { 12430230Ssam struct enp_softc *es = &enp_softc[ui->ui_unit]; 12530230Ssam register struct ifnet *ifp = &es->es_if; 12629649Ssam 12730230Ssam ifp->if_unit = ui->ui_unit; 12829649Ssam ifp->if_name = "enp"; 12929649Ssam ifp->if_mtu = ETHERMTU; 13029649Ssam ifp->if_init = enpinit; 13129649Ssam ifp->if_ioctl = enpioctl; 13235383Skarels ifp->if_output = enoutput; 133*35411Skarels ifp->if_start = enpstart; 13429649Ssam ifp->if_reset = enpreset; 135*35411Skarels ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 13629649Ssam if_attach(ifp); 13729649Ssam } 13829649Ssam 13929649Ssam /* 14030230Ssam * Reset of interface after "system" reset. 14129649Ssam */ 14230230Ssam enpreset(unit, vban) 14330230Ssam int unit, vban; 14429649Ssam { 14530230Ssam register struct vba_device *ui; 14629649Ssam 14730230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 14830230Ssam ui->ui_vbanum != vban) 14930230Ssam return; 15030230Ssam printf(" enp%d", unit); 15129649Ssam enpinit(unit); 15229649Ssam } 15329649Ssam 15429649Ssam /* 15530230Ssam * Initialization of interface; clear recorded pending operations. 15629649Ssam */ 15730230Ssam enpinit(unit) 15830230Ssam int unit; 15929649Ssam { 16030230Ssam struct enp_softc *es = &enp_softc[unit]; 16130230Ssam register struct vba_device *ui = enpinfo[unit]; 16230230Ssam struct enpdevice *addr; 16330230Ssam register struct ifnet *ifp = &es->es_if; 16430230Ssam int s; 16529649Ssam 16630230Ssam if (ifp->if_addrlist == (struct ifaddr *)0) 16730230Ssam return; 16830230Ssam if ((ifp->if_flags & IFF_RUNNING) == 0) { 16930230Ssam addr = (struct enpdevice *)ui->ui_addr; 17030230Ssam s = splimp(); 17130230Ssam RESET_ENP(addr); 17230230Ssam DELAY(200000); 17330230Ssam es->es_if.if_flags |= IFF_RUNNING; 17430230Ssam splx(s); 17529649Ssam } 17629649Ssam } 17729649Ssam 17829649Ssam /* 17929649Ssam * Ethernet interface interrupt. 18029649Ssam */ 18130230Ssam enpintr(unit) 18230230Ssam int unit; 18329649Ssam { 18430230Ssam register struct enpdevice *addr; 18530230Ssam register BCB *bcbp; 18629649Ssam 18730230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 18830295Ssam #if ENP == 30 18930230Ssam if (!IS_ENP_INTR(addr)) 19029649Ssam return; 19130230Ssam ACK_ENP_INTR(addr); 19230295Ssam #endif 19330295Ssam while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) { 19435383Skarels enpread(&enp_softc[unit], bcbp); 19530295Ssam (void) ringput((RING *)&addr->enp_enpfree, bcbp); 19629649Ssam } 19729649Ssam } 19829649Ssam 19929649Ssam /* 20029649Ssam * Read input packet, examine its packet type, and enqueue it. 20129649Ssam */ 20230295Ssam enpread(es, bcbp) 20330230Ssam struct enp_softc *es; 20430230Ssam register BCB *bcbp; 20529649Ssam { 20629649Ssam register struct ether_header *enp; 20729649Ssam struct mbuf *m; 20830295Ssam int s, len, off, resid; 20929649Ssam 21029649Ssam es->es_if.if_ipackets++; 21129649Ssam /* 21229649Ssam * Get input data length. 21329649Ssam * Get pointer to ethernet header (in input buffer). 21429649Ssam * Deal with trailer protocol: if type is PUP trailer 21529649Ssam * get true type from first 16-bit word past data. 21629649Ssam * Remember that type was trailer by setting off. 21729649Ssam */ 21830230Ssam len = bcbp->b_msglen - sizeof (struct ether_header); 21930986Ssam enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr); 22030230Ssam #define enpdataaddr(enp, off, type) \ 22130230Ssam ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off)))) 22230230Ssam enp->ether_type = ntohs((u_short)enp->ether_type); 22330230Ssam if (enp->ether_type >= ETHERTYPE_TRAIL && 22430230Ssam enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 22530230Ssam off = (enp->ether_type - ETHERTYPE_TRAIL) * 512; 22630230Ssam if (off >= ETHERMTU) 22735383Skarels return; 22830230Ssam enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *)); 22930230Ssam resid = ntohs(*(enpdataaddr(enp, off+2, u_short *))); 23030230Ssam if (off + resid > len) 23135383Skarels return; 23229649Ssam len = off + resid; 23330230Ssam } else 23429649Ssam off = 0; 23530230Ssam if (len == 0) 23635383Skarels return; 23729649Ssam 23829649Ssam /* 23929649Ssam * Pull packet off interface. Off is nonzero if packet 24029649Ssam * has trailing header; enpget will then force this header 24135383Skarels * information to be at the front. 24229649Ssam */ 24330986Ssam m = enpget((u_char *)enp, len, off, &es->es_if); 24430230Ssam if (m == 0) 24535383Skarels return; 24635383Skarels en_doproto(&es->es_if, enp, m); 24729649Ssam } 24829649Ssam 24935383Skarels enpstart(ifp) 25030230Ssam struct ifnet *ifp; 25129649Ssam { 25229649Ssam 25335383Skarels if (enpput(ifp)) 254*35411Skarels return (ENOBUFS); 255*35411Skarels else 256*35411Skarels return (0); 25729649Ssam } 25829649Ssam 25929649Ssam /* 26030230Ssam * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus. 26129649Ssam */ 26235383Skarels enpput(ifp) 26335383Skarels struct ifnet *ifp; 26429649Ssam { 26529649Ssam register BCB *bcbp; 26630230Ssam register struct enpdevice *addr; 26729649Ssam register struct mbuf *mp; 26829649Ssam register u_char *bp; 26930230Ssam register u_int len; 270*35411Skarels int unit = ifp->if_unit, ret = 1; 27135383Skarels struct mbuf *m; 27229649Ssam 27330230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 27435383Skarels again: 275*35411Skarels if (ringempty((RING *)&addr->enp_hostfree)) { 276*35411Skarels /* ifp->if_flags |= IFF_OACTIVE; */ 277*35411Skarels return (ret); 278*35411Skarels } 27935383Skarels IF_DEQUEUE(&ifp->if_snd, m); 280*35411Skarels if (m == 0) { 281*35411Skarels ifp->if_flags &= ~IFF_OACTIVE; 282*35411Skarels return (0); 283*35411Skarels } 28430295Ssam bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree); 28529649Ssam bcbp->b_len = 0; 28630986Ssam bp = (u_char *)ENPGETLONG(&bcbp->b_addr); 28730230Ssam for (mp = m; mp; mp = mp->m_next) { 28829649Ssam len = mp->m_len; 28930230Ssam if (len == 0) 29029649Ssam continue; 291*35411Skarels enpcopy(mtod(mp, u_char *), bp, len); 29229649Ssam bp += len; 29329649Ssam bcbp->b_len += len; 29429649Ssam } 295*35411Skarels bcbp->b_len = max(ETHERMIN+sizeof (struct ether_header), bcbp->b_len); 29629649Ssam bcbp->b_reserved = 0; 29730295Ssam if (ringput((RING *)&addr->enp_toenp, bcbp) == 1) 29830230Ssam INTR_ENP(addr); 29929649Ssam m_freem(m); 300*35411Skarels ret = 0; 30135383Skarels goto again; 30229649Ssam } 30329649Ssam 30429649Ssam /* 30530230Ssam * Routine to copy from VERSAbus memory into mbufs. 30629649Ssam * 30729649Ssam * Warning: This makes the fairly safe assumption that 30829649Ssam * mbufs have even lengths. 30929649Ssam */ 31029649Ssam struct mbuf * 31135383Skarels enpget(rxbuf, totlen, off, ifp) 31230230Ssam u_char *rxbuf; 31335383Skarels int totlen, off; 31430230Ssam struct ifnet *ifp; 31529649Ssam { 316*35411Skarels register u_char *cp; 31729649Ssam register struct mbuf *m; 31830230Ssam struct mbuf *top = 0, **mp = ⊤ 31935383Skarels int len; 32035383Skarels u_char *packet_end; 32129649Ssam 32235383Skarels rxbuf += sizeof (struct ether_header); 32335383Skarels cp = rxbuf; 32435383Skarels packet_end = cp + totlen; 32535383Skarels if (off) { 32635383Skarels off += 2 * sizeof(u_short); 32735383Skarels totlen -= 2 *sizeof(u_short); 32835383Skarels cp = rxbuf + off; 32935383Skarels } 33035383Skarels 33135383Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 33235383Skarels if (m == 0) 33335383Skarels return (0); 33435383Skarels m->m_pkthdr.rcvif = ifp; 33535383Skarels m->m_pkthdr.len = totlen; 33635383Skarels m->m_len = MHLEN; 33735383Skarels 33830230Ssam while (totlen > 0) { 33935383Skarels if (top) { 34035383Skarels MGET(m, M_DONTWAIT, MT_DATA); 34135383Skarels if (m == 0) { 34235383Skarels m_freem(top); 34335383Skarels return (0); 34435383Skarels } 34535383Skarels m->m_len = MLEN; 34635383Skarels } 34735383Skarels len = min(totlen, (packet_end - cp)); 34835383Skarels if (len >= MINCLSIZE) { 34935383Skarels MCLGET(m, M_DONTWAIT); 35035383Skarels if (m->m_flags & M_EXT) 35135383Skarels m->m_len = len = min(len, MCLBYTES); 35230230Ssam else 35335383Skarels len = m->m_len; 35430230Ssam } else { 35530230Ssam /* 35635383Skarels * Place initial small packet/header at end of mbuf. 35730230Ssam */ 35835383Skarels if (len < m->m_len) { 359*35411Skarels if (top == 0 && len + max_linkhdr <= m->m_len) 36035383Skarels m->m_data += max_linkhdr; 36135383Skarels m->m_len = len; 36235383Skarels } else 36335383Skarels len = m->m_len; 36430230Ssam } 365*35411Skarels enpcopy(cp, mtod(m, u_char *), (u_int)len); 36629649Ssam *mp = m; 36729649Ssam mp = &m->m_next; 36835383Skarels totlen -= len; 36935383Skarels cp += len; 37035383Skarels if (cp == packet_end) 37135383Skarels cp = rxbuf; 37229649Ssam } 37329649Ssam return (top); 37429649Ssam } 37529649Ssam 37630230Ssam enpcopy(from, to, cnt) 37730295Ssam register u_char *from, *to; 37830295Ssam register u_int cnt; 37930230Ssam { 38030230Ssam register c; 38130230Ssam register short *f, *t; 38230230Ssam 38330230Ssam if (((int)from&01) && ((int)to&01)) { 38430230Ssam /* source & dest at odd addresses */ 38530230Ssam *to++ = *from++; 38630230Ssam --cnt; 38730230Ssam } 38830230Ssam if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) { 38930230Ssam t = (short *)to; 39030230Ssam f = (short *)from; 39130230Ssam for (c = cnt>>1; c; --c) /* even address copy */ 39230230Ssam *t++ = *f++; 39330230Ssam cnt &= 1; 39430230Ssam if (cnt) { /* odd len */ 39530295Ssam from = (u_char *)f; 39630295Ssam to = (u_char *)t; 39730230Ssam *to = *from; 39830230Ssam } 39930230Ssam } 40030295Ssam while ((int)cnt-- > 0) /* one of the address(es) must be odd */ 40130230Ssam *to++ = *from++; 40230230Ssam } 40330230Ssam 40429649Ssam /* 40529649Ssam * Process an ioctl request. 40629649Ssam */ 40729649Ssam enpioctl(ifp, cmd, data) 40830230Ssam register struct ifnet *ifp; 40930230Ssam int cmd; 41030230Ssam caddr_t data; 41129649Ssam { 41230230Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 41330230Ssam struct enpdevice *addr; 41430230Ssam int s = splimp(), error = 0; 41529649Ssam 41629649Ssam switch (cmd) { 41729649Ssam 41829649Ssam case SIOCSIFADDR: 41930230Ssam ifp->if_flags |= IFF_UP; 42030230Ssam switch (ifa->ifa_addr.sa_family) { 42130230Ssam #ifdef INET 42230230Ssam case AF_INET: 42330230Ssam enpinit(ifp->if_unit); 42430230Ssam ((struct arpcom *)ifp)->ac_ipaddr = 42530230Ssam IA_SIN(ifa)->sin_addr; 42630230Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 42729649Ssam break; 42830230Ssam #endif 42930230Ssam #ifdef NS 43030230Ssam case AF_NS: { 43130230Ssam struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 43230230Ssam struct enp_softc *es = &enp_softc[ifp->if_unit]; 43330230Ssam 43430230Ssam if (!ns_nullhost(*ina)) { 43530230Ssam ifp->if_flags &= ~IFF_RUNNING; 43630230Ssam addr = (struct enpdevice *) 43730230Ssam enpinfo[ifp->if_unit]->ui_addr; 43830230Ssam enpsetaddr(ifp->if_unit, addr, 43930230Ssam ina->x_host.c_host); 44030230Ssam } else 44130986Ssam ina->x_host = *(union ns_host *)es->es_addr; 44230230Ssam enpinit(ifp->if_unit); 44330230Ssam break; 44429649Ssam } 44530230Ssam #endif 44630230Ssam default: 44730230Ssam enpinit(ifp->if_unit); 44830230Ssam break; 44929649Ssam } 45029649Ssam break; 45129649Ssam 45230230Ssam case SIOCSIFFLAGS: 45330230Ssam if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 45430230Ssam enpinit(ifp->if_unit); /* reset board */ 45530230Ssam ifp->if_flags &= ~IFF_RUNNING; 45630230Ssam } else if (ifp->if_flags&IFF_UP && 45730230Ssam (ifp->if_flags&IFF_RUNNING) == 0) 45830230Ssam enpinit(ifp->if_unit); 45929649Ssam break; 46029649Ssam 46129649Ssam default: 46229649Ssam error = EINVAL; 46329649Ssam } 46430230Ssam splx(s); 46530230Ssam return (error); 46629649Ssam } 46729649Ssam 46830230Ssam enpsetaddr(unit, addr, enaddr) 46930230Ssam int unit; 47030230Ssam struct enpdevice *addr; 47130230Ssam u_char *enaddr; 47229649Ssam { 47329649Ssam 47430986Ssam enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr, 47530986Ssam sizeof (struct ether_addr)); 47630230Ssam enpinit(unit); 47730986Ssam enpgetaddr(unit, addr); 47829649Ssam } 47929649Ssam 48030986Ssam enpgetaddr(unit, addr) 48130986Ssam int unit; 48230986Ssam struct enpdevice *addr; 48330986Ssam { 48430986Ssam struct enp_softc *es = &enp_softc[unit]; 48530986Ssam 48630986Ssam enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr, 48730986Ssam sizeof (struct ether_addr)); 48830986Ssam printf("enp%d: hardware address %s\n", 48930986Ssam unit, ether_sprintf(es->es_addr)); 49030986Ssam } 49130986Ssam 49229649Ssam /* 49330230Ssam * Routines to synchronize enp and host. 49429649Ssam */ 49530295Ssam #ifdef notdef 49629649Ssam static 49730230Ssam ringinit(rp, size) 49830230Ssam register RING *rp; 49929649Ssam { 50029649Ssam 50129649Ssam rp->r_rdidx = rp->r_wrtidx = 0; 50229649Ssam rp->r_size = size; 50329649Ssam } 50429649Ssam 50529649Ssam static 50630295Ssam ringfull(rp) 50730230Ssam register RING *rp; 50829649Ssam { 50930295Ssam register short idx; 51030230Ssam 51130295Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 51230295Ssam return (idx == rp->r_rdidx); 51329649Ssam } 51429649Ssam 51529649Ssam static 51630295Ssam fir(rp) 51730230Ssam register RING *rp; 51829649Ssam { 51929649Ssam 52030295Ssam return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0); 52129649Ssam } 52230295Ssam #endif 52329649Ssam 52429649Ssam static 52530295Ssam ringempty(rp) 52630295Ssam register RING *rp; 52730295Ssam { 52830295Ssam 52930295Ssam return (rp->r_rdidx == rp->r_wrtidx); 53030295Ssam } 53130295Ssam 53230295Ssam static 53330230Ssam ringput(rp, v) 53430230Ssam register RING *rp; 53530295Ssam BCB *v; 53629649Ssam { 53729649Ssam register int idx; 53829649Ssam 53929649Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 54030230Ssam if (idx != rp->r_rdidx) { 54130986Ssam ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v); 54229649Ssam rp->r_wrtidx = idx; 54330230Ssam if ((idx -= rp->r_rdidx) < 0) 54429649Ssam idx += rp->r_size; 54530230Ssam return (idx); /* num ring entries */ 54629649Ssam } 54730230Ssam return (0); 54829649Ssam } 54929649Ssam 55029649Ssam static 55130230Ssam ringget(rp) 55230230Ssam register RING *rp; 55329649Ssam { 55429649Ssam register int i = 0; 55529649Ssam 55630230Ssam if (rp->r_rdidx != rp->r_wrtidx) { 55730986Ssam i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]); 55829649Ssam rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1); 55929649Ssam } 56030230Ssam return (i); 56129649Ssam } 56229649Ssam 56330230Ssam /* 56430230Ssam * ENP Ram device. 56530230Ssam */ 56630230Ssam enpr_open(dev) 56730230Ssam dev_t dev; 56829649Ssam { 56930230Ssam register int unit = ENPUNIT(dev); 57030230Ssam struct vba_device *ui; 57130230Ssam struct enpdevice *addr; 57229649Ssam 57330230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 57430230Ssam (addr = (struct enpdevice *)ui->ui_addr) == 0) 57530230Ssam return (ENODEV); 57630230Ssam if (addr->enp_state != S_ENPRESET) 57730230Ssam return (EACCES); /* enp is not in reset state, don't open */ 57830230Ssam return (0); 57929649Ssam } 58029649Ssam 58130295Ssam /*ARGSUSED*/ 58230230Ssam enpr_close(dev) 58330230Ssam dev_t dev; 58429649Ssam { 58529649Ssam 58630230Ssam return (0); 58729649Ssam } 58829649Ssam 58930230Ssam enpr_read(dev, uio) 59030230Ssam dev_t dev; 59130230Ssam register struct uio *uio; 59229649Ssam { 59330230Ssam register struct iovec *iov; 59430230Ssam struct enpdevice *addr; 59529649Ssam 59630230Ssam if (uio->uio_offset > RAM_SIZE) 59730230Ssam return (ENODEV); 59830295Ssam iov = uio->uio_iov; 59930230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 60030230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 60130230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 60230986Ssam if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0) 60330986Ssam return (EFAULT); 60430295Ssam enpcopy((u_char *)&addr->enp_ram[uio->uio_offset], 60530295Ssam (u_char *)iov->iov_base, (u_int)iov->iov_len); 60630230Ssam uio->uio_resid -= iov->iov_len; 60730230Ssam iov->iov_len = 0; 60830230Ssam return (0); 60929649Ssam } 61029649Ssam 61130230Ssam enpr_write(dev, uio) 61230230Ssam dev_t dev; 61330230Ssam register struct uio *uio; 61429649Ssam { 61530230Ssam register struct enpdevice *addr; 61630230Ssam register struct iovec *iov; 61729649Ssam 61830230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 61930230Ssam iov = uio->uio_iov; 62030230Ssam if (uio->uio_offset > RAM_SIZE) 62130230Ssam return (ENODEV); 62230230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 62330230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 62430986Ssam if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0) 62530986Ssam return (EFAULT); 62630295Ssam enpcopy((u_char *)iov->iov_base, 62730295Ssam (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len); 62830230Ssam uio->uio_resid -= iov->iov_len; 62930230Ssam iov->iov_len = 0; 63030230Ssam return (0); 63129649Ssam } 63229649Ssam 63330295Ssam /*ARGSUSED*/ 63430230Ssam enpr_ioctl(dev, cmd, data) 63530230Ssam dev_t dev; 63630230Ssam caddr_t data; 63729649Ssam { 63830230Ssam register unit = ENPUNIT(dev); 63930986Ssam struct enpdevice *addr; 64029649Ssam 64130230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 64230230Ssam switch(cmd) { 64330230Ssam 64430230Ssam case ENPIOGO: 64530986Ssam ENPSETLONG(&addr->enp_base, addr); 64630230Ssam addr->enp_intrvec = enp_softc[unit].es_ivec; 64730230Ssam ENP_GO(addr, ENPSTART); 64830230Ssam DELAY(200000); 64930230Ssam enpinit(unit); 65030986Ssam /* 65130986Ssam * Fetch Ethernet address after link level 65230986Ssam * is booted (firmware copies manufacturer's 65330986Ssam * address from on-board ROM). 65430986Ssam */ 65530986Ssam enpgetaddr(unit, addr); 65630986Ssam addr->enp_state = S_ENPRUN; 65730230Ssam break; 65830230Ssam 65930230Ssam case ENPIORESET: 66030230Ssam RESET_ENP(addr); 66130986Ssam addr->enp_state = S_ENPRESET; 66230230Ssam DELAY(100000); 66330230Ssam break; 66430986Ssam default: 66530986Ssam return (EINVAL); 66629649Ssam } 66730230Ssam return (0); 66829649Ssam } 66929649Ssam #endif 670