134508Skarels /* 234508Skarels * Copyright (c) 1988 Regents of the University of California. 334508Skarels * All rights reserved. 434508Skarels * 5*35383Skarels * This code is derived from software contributed to Berkeley by 6*35383Skarels * Computer Consoles Inc. 7*35383Skarels * 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*35383Skarels * @(#)if_enp.c 7.3 (Berkeley) 08/19/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 78*35383Skarels 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; 132*35383Skarels ifp->if_output = enoutput; 13329649Ssam ifp->if_reset = enpreset; 134*35383Skarels ifp->if_start = enpstart; 13530230Ssam ifp->if_flags = IFF_BROADCAST; 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) { 194*35383Skarels 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) 227*35383Skarels 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) 231*35383Skarels return; 23229649Ssam len = off + resid; 23330230Ssam } else 23429649Ssam off = 0; 23530230Ssam if (len == 0) 236*35383Skarels return; 23729649Ssam 23829649Ssam /* 23929649Ssam * Pull packet off interface. Off is nonzero if packet 24029649Ssam * has trailing header; enpget will then force this header 241*35383Skarels * information to be at the front. 24229649Ssam */ 24330986Ssam m = enpget((u_char *)enp, len, off, &es->es_if); 24430230Ssam if (m == 0) 245*35383Skarels return; 246*35383Skarels en_doproto(&es->es_if, enp, m); 24729649Ssam } 24829649Ssam 249*35383Skarels enpstart(ifp) 25030230Ssam struct ifnet *ifp; 25129649Ssam { 252*35383Skarels int error = 0; 253*35383Skarels int s = splimp(); 25429649Ssam 255*35383Skarels if (enpput(ifp)) 25629649Ssam error = ENOBUFS; 25730230Ssam splx(s); 25830230Ssam return (error); 25929649Ssam } 26029649Ssam 26129649Ssam /* 26230230Ssam * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus. 26329649Ssam */ 264*35383Skarels enpput(ifp) 265*35383Skarels struct ifnet *ifp; 26629649Ssam { 26729649Ssam register BCB *bcbp; 26830230Ssam register struct enpdevice *addr; 26929649Ssam register struct mbuf *mp; 27029649Ssam register u_char *bp; 27130230Ssam register u_int len; 272*35383Skarels int unit = ifp->if_unit; 27330230Ssam u_char *mcp; 274*35383Skarels struct mbuf *m; 27529649Ssam 27630230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 277*35383Skarels again: 27830295Ssam if (ringempty((RING *)&addr->enp_hostfree)) 27930230Ssam return (1); 280*35383Skarels IF_DEQUEUE(&ifp->if_snd, m); 281*35383Skarels if (m == 0) return (0); 28230295Ssam bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree); 28329649Ssam bcbp->b_len = 0; 28430986Ssam bp = (u_char *)ENPGETLONG(&bcbp->b_addr); 28530230Ssam for (mp = m; mp; mp = mp->m_next) { 28629649Ssam len = mp->m_len; 28730230Ssam if (len == 0) 28829649Ssam continue; 28930230Ssam mcp = mtod(mp, u_char *); 29030230Ssam enpcopy(mcp, bp, len); 29129649Ssam bp += len; 29229649Ssam bcbp->b_len += len; 29329649Ssam } 29430986Ssam bcbp->b_len = MAX(ETHERMIN+sizeof (struct ether_header), bcbp->b_len); 29529649Ssam bcbp->b_reserved = 0; 29630295Ssam if (ringput((RING *)&addr->enp_toenp, bcbp) == 1) 29730230Ssam INTR_ENP(addr); 29829649Ssam m_freem(m); 299*35383Skarels goto again; 30029649Ssam } 30129649Ssam 30229649Ssam /* 30330230Ssam * Routine to copy from VERSAbus memory into mbufs. 30429649Ssam * 30529649Ssam * Warning: This makes the fairly safe assumption that 30629649Ssam * mbufs have even lengths. 30729649Ssam */ 30829649Ssam struct mbuf * 309*35383Skarels enpget(rxbuf, totlen, off, ifp) 31030230Ssam u_char *rxbuf; 311*35383Skarels int totlen, off; 31230230Ssam struct ifnet *ifp; 31329649Ssam { 31430230Ssam register u_char *cp, *mcp; 31529649Ssam register struct mbuf *m; 31630230Ssam struct mbuf *top = 0, **mp = ⊤ 317*35383Skarels int len; 318*35383Skarels u_char *packet_end; 31929649Ssam 320*35383Skarels rxbuf += sizeof (struct ether_header); 321*35383Skarels cp = rxbuf; 322*35383Skarels packet_end = cp + totlen; 323*35383Skarels if (off) { 324*35383Skarels off += 2 * sizeof(u_short); 325*35383Skarels totlen -= 2 *sizeof(u_short); 326*35383Skarels cp = rxbuf + off; 327*35383Skarels } 328*35383Skarels 329*35383Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 330*35383Skarels if (m == 0) 331*35383Skarels return (0); 332*35383Skarels m->m_pkthdr.rcvif = ifp; 333*35383Skarels m->m_pkthdr.len = totlen; 334*35383Skarels m->m_len = MHLEN; 335*35383Skarels 33630230Ssam while (totlen > 0) { 337*35383Skarels if (top) { 338*35383Skarels MGET(m, M_DONTWAIT, MT_DATA); 339*35383Skarels if (m == 0) { 340*35383Skarels m_freem(top); 341*35383Skarels return (0); 342*35383Skarels } 343*35383Skarels m->m_len = MLEN; 344*35383Skarels } 345*35383Skarels len = min(totlen, (packet_end - cp)); 346*35383Skarels if (len >= MINCLSIZE) { 347*35383Skarels MCLGET(m, M_DONTWAIT); 348*35383Skarels if (m->m_flags & M_EXT) 349*35383Skarels m->m_len = len = min(len, MCLBYTES); 35030230Ssam else 351*35383Skarels len = m->m_len; 35230230Ssam } else { 35330230Ssam /* 354*35383Skarels * Place initial small packet/header at end of mbuf. 35530230Ssam */ 356*35383Skarels if (len < m->m_len) { 357*35383Skarels if (top == 0 && len < max_linkhdr + m->m_len) 358*35383Skarels m->m_data += max_linkhdr; 359*35383Skarels m->m_len = len; 360*35383Skarels } else 361*35383Skarels len = m->m_len; 36230230Ssam } 363*35383Skarels mcp = mtod(m, u_char *); 36430295Ssam enpcopy(cp, mcp, (u_int)len); 36529649Ssam *mp = m; 36629649Ssam mp = &m->m_next; 367*35383Skarels totlen -= len; 368*35383Skarels cp += len; 369*35383Skarels if (cp == packet_end) 370*35383Skarels cp = rxbuf; 37129649Ssam } 37229649Ssam return (top); 37329649Ssam } 37429649Ssam 37530230Ssam enpcopy(from, to, cnt) 37630295Ssam register u_char *from, *to; 37730295Ssam register u_int cnt; 37830230Ssam { 37930230Ssam register c; 38030230Ssam register short *f, *t; 38130230Ssam 38230230Ssam if (((int)from&01) && ((int)to&01)) { 38330230Ssam /* source & dest at odd addresses */ 38430230Ssam *to++ = *from++; 38530230Ssam --cnt; 38630230Ssam } 38730230Ssam if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) { 38830230Ssam t = (short *)to; 38930230Ssam f = (short *)from; 39030230Ssam for (c = cnt>>1; c; --c) /* even address copy */ 39130230Ssam *t++ = *f++; 39230230Ssam cnt &= 1; 39330230Ssam if (cnt) { /* odd len */ 39430295Ssam from = (u_char *)f; 39530295Ssam to = (u_char *)t; 39630230Ssam *to = *from; 39730230Ssam } 39830230Ssam } 39930295Ssam while ((int)cnt-- > 0) /* one of the address(es) must be odd */ 40030230Ssam *to++ = *from++; 40130230Ssam } 40230230Ssam 40329649Ssam /* 40429649Ssam * Process an ioctl request. 40529649Ssam */ 40629649Ssam enpioctl(ifp, cmd, data) 40730230Ssam register struct ifnet *ifp; 40830230Ssam int cmd; 40930230Ssam caddr_t data; 41029649Ssam { 41130230Ssam register struct ifaddr *ifa = (struct ifaddr *)data; 41230230Ssam struct enpdevice *addr; 41330230Ssam int s = splimp(), error = 0; 41429649Ssam 41529649Ssam switch (cmd) { 41629649Ssam 41729649Ssam case SIOCSIFADDR: 41830230Ssam ifp->if_flags |= IFF_UP; 41930230Ssam switch (ifa->ifa_addr.sa_family) { 42030230Ssam #ifdef INET 42130230Ssam case AF_INET: 42230230Ssam enpinit(ifp->if_unit); 42330230Ssam ((struct arpcom *)ifp)->ac_ipaddr = 42430230Ssam IA_SIN(ifa)->sin_addr; 42530230Ssam arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 42629649Ssam break; 42730230Ssam #endif 42830230Ssam #ifdef NS 42930230Ssam case AF_NS: { 43030230Ssam struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 43130230Ssam struct enp_softc *es = &enp_softc[ifp->if_unit]; 43230230Ssam 43330230Ssam if (!ns_nullhost(*ina)) { 43430230Ssam ifp->if_flags &= ~IFF_RUNNING; 43530230Ssam addr = (struct enpdevice *) 43630230Ssam enpinfo[ifp->if_unit]->ui_addr; 43730230Ssam enpsetaddr(ifp->if_unit, addr, 43830230Ssam ina->x_host.c_host); 43930230Ssam } else 44030986Ssam ina->x_host = *(union ns_host *)es->es_addr; 44130230Ssam enpinit(ifp->if_unit); 44230230Ssam break; 44329649Ssam } 44430230Ssam #endif 44530230Ssam default: 44630230Ssam enpinit(ifp->if_unit); 44730230Ssam break; 44829649Ssam } 44929649Ssam break; 45029649Ssam 45130230Ssam case SIOCSIFFLAGS: 45230230Ssam if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 45330230Ssam enpinit(ifp->if_unit); /* reset board */ 45430230Ssam ifp->if_flags &= ~IFF_RUNNING; 45530230Ssam } else if (ifp->if_flags&IFF_UP && 45630230Ssam (ifp->if_flags&IFF_RUNNING) == 0) 45730230Ssam enpinit(ifp->if_unit); 45829649Ssam break; 45929649Ssam 46029649Ssam default: 46129649Ssam error = EINVAL; 46229649Ssam } 46330230Ssam splx(s); 46430230Ssam return (error); 46529649Ssam } 46629649Ssam 46730230Ssam enpsetaddr(unit, addr, enaddr) 46830230Ssam int unit; 46930230Ssam struct enpdevice *addr; 47030230Ssam u_char *enaddr; 47129649Ssam { 47229649Ssam 47330986Ssam enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr, 47430986Ssam sizeof (struct ether_addr)); 47530230Ssam enpinit(unit); 47630986Ssam enpgetaddr(unit, addr); 47729649Ssam } 47829649Ssam 47930986Ssam enpgetaddr(unit, addr) 48030986Ssam int unit; 48130986Ssam struct enpdevice *addr; 48230986Ssam { 48330986Ssam struct enp_softc *es = &enp_softc[unit]; 48430986Ssam 48530986Ssam enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr, 48630986Ssam sizeof (struct ether_addr)); 48730986Ssam printf("enp%d: hardware address %s\n", 48830986Ssam unit, ether_sprintf(es->es_addr)); 48930986Ssam } 49030986Ssam 49129649Ssam /* 49230230Ssam * Routines to synchronize enp and host. 49329649Ssam */ 49430295Ssam #ifdef notdef 49529649Ssam static 49630230Ssam ringinit(rp, size) 49730230Ssam register RING *rp; 49829649Ssam { 49929649Ssam 50029649Ssam rp->r_rdidx = rp->r_wrtidx = 0; 50129649Ssam rp->r_size = size; 50229649Ssam } 50329649Ssam 50429649Ssam static 50530295Ssam ringfull(rp) 50630230Ssam register RING *rp; 50729649Ssam { 50830295Ssam register short idx; 50930230Ssam 51030295Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 51130295Ssam return (idx == rp->r_rdidx); 51229649Ssam } 51329649Ssam 51429649Ssam static 51530295Ssam fir(rp) 51630230Ssam register RING *rp; 51729649Ssam { 51829649Ssam 51930295Ssam return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0); 52029649Ssam } 52130295Ssam #endif 52229649Ssam 52329649Ssam static 52430295Ssam ringempty(rp) 52530295Ssam register RING *rp; 52630295Ssam { 52730295Ssam 52830295Ssam return (rp->r_rdidx == rp->r_wrtidx); 52930295Ssam } 53030295Ssam 53130295Ssam static 53230230Ssam ringput(rp, v) 53330230Ssam register RING *rp; 53430295Ssam BCB *v; 53529649Ssam { 53629649Ssam register int idx; 53729649Ssam 53829649Ssam idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 53930230Ssam if (idx != rp->r_rdidx) { 54030986Ssam ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v); 54129649Ssam rp->r_wrtidx = idx; 54230230Ssam if ((idx -= rp->r_rdidx) < 0) 54329649Ssam idx += rp->r_size; 54430230Ssam return (idx); /* num ring entries */ 54529649Ssam } 54630230Ssam return (0); 54729649Ssam } 54829649Ssam 54929649Ssam static 55030230Ssam ringget(rp) 55130230Ssam register RING *rp; 55229649Ssam { 55329649Ssam register int i = 0; 55429649Ssam 55530230Ssam if (rp->r_rdidx != rp->r_wrtidx) { 55630986Ssam i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]); 55729649Ssam rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1); 55829649Ssam } 55930230Ssam return (i); 56029649Ssam } 56129649Ssam 56230230Ssam /* 56330230Ssam * ENP Ram device. 56430230Ssam */ 56530230Ssam enpr_open(dev) 56630230Ssam dev_t dev; 56729649Ssam { 56830230Ssam register int unit = ENPUNIT(dev); 56930230Ssam struct vba_device *ui; 57030230Ssam struct enpdevice *addr; 57129649Ssam 57230230Ssam if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 57330230Ssam (addr = (struct enpdevice *)ui->ui_addr) == 0) 57430230Ssam return (ENODEV); 57530230Ssam if (addr->enp_state != S_ENPRESET) 57630230Ssam return (EACCES); /* enp is not in reset state, don't open */ 57730230Ssam return (0); 57829649Ssam } 57929649Ssam 58030295Ssam /*ARGSUSED*/ 58130230Ssam enpr_close(dev) 58230230Ssam dev_t dev; 58329649Ssam { 58429649Ssam 58530230Ssam return (0); 58629649Ssam } 58729649Ssam 58830230Ssam enpr_read(dev, uio) 58930230Ssam dev_t dev; 59030230Ssam register struct uio *uio; 59129649Ssam { 59230230Ssam register struct iovec *iov; 59330230Ssam struct enpdevice *addr; 59429649Ssam 59530230Ssam if (uio->uio_offset > RAM_SIZE) 59630230Ssam return (ENODEV); 59730295Ssam iov = uio->uio_iov; 59830230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 59930230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 60030230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 60130986Ssam if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0) 60230986Ssam return (EFAULT); 60330295Ssam enpcopy((u_char *)&addr->enp_ram[uio->uio_offset], 60430295Ssam (u_char *)iov->iov_base, (u_int)iov->iov_len); 60530230Ssam uio->uio_resid -= iov->iov_len; 60630230Ssam iov->iov_len = 0; 60730230Ssam return (0); 60829649Ssam } 60929649Ssam 61030230Ssam enpr_write(dev, uio) 61130230Ssam dev_t dev; 61230230Ssam register struct uio *uio; 61329649Ssam { 61430230Ssam register struct enpdevice *addr; 61530230Ssam register struct iovec *iov; 61629649Ssam 61730230Ssam addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 61830230Ssam iov = uio->uio_iov; 61930230Ssam if (uio->uio_offset > RAM_SIZE) 62030230Ssam return (ENODEV); 62130230Ssam if (uio->uio_offset + iov->iov_len > RAM_SIZE) 62230230Ssam iov->iov_len = RAM_SIZE - uio->uio_offset; 62330986Ssam if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0) 62430986Ssam return (EFAULT); 62530295Ssam enpcopy((u_char *)iov->iov_base, 62630295Ssam (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len); 62730230Ssam uio->uio_resid -= iov->iov_len; 62830230Ssam iov->iov_len = 0; 62930230Ssam return (0); 63029649Ssam } 63129649Ssam 63230295Ssam /*ARGSUSED*/ 63330230Ssam enpr_ioctl(dev, cmd, data) 63430230Ssam dev_t dev; 63530230Ssam caddr_t data; 63629649Ssam { 63730230Ssam register unit = ENPUNIT(dev); 63830986Ssam struct enpdevice *addr; 63929649Ssam 64030230Ssam addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 64130230Ssam switch(cmd) { 64230230Ssam 64330230Ssam case ENPIOGO: 64430986Ssam ENPSETLONG(&addr->enp_base, addr); 64530230Ssam addr->enp_intrvec = enp_softc[unit].es_ivec; 64630230Ssam ENP_GO(addr, ENPSTART); 64730230Ssam DELAY(200000); 64830230Ssam enpinit(unit); 64930986Ssam /* 65030986Ssam * Fetch Ethernet address after link level 65130986Ssam * is booted (firmware copies manufacturer's 65230986Ssam * address from on-board ROM). 65330986Ssam */ 65430986Ssam enpgetaddr(unit, addr); 65530986Ssam addr->enp_state = S_ENPRUN; 65630230Ssam break; 65730230Ssam 65830230Ssam case ENPIORESET: 65930230Ssam RESET_ENP(addr); 66030986Ssam addr->enp_state = S_ENPRESET; 66130230Ssam DELAY(100000); 66230230Ssam break; 66330986Ssam default: 66430986Ssam return (EINVAL); 66529649Ssam } 66630230Ssam return (0); 66729649Ssam } 66829649Ssam #endif 669