xref: /csrg-svn/sys/tahoe/if/if_enp.c (revision 34864)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)if_enp.c	7.2 (Berkeley) 06/29/88
18  */
19 
20 #include "enp.h"
21 #if NENP > 0
22 /*
23  * CMC ENP-20 Ethernet Controller.
24  */
25 #include "param.h"
26 #include "systm.h"
27 #include "mbuf.h"
28 #include "buf.h"
29 #include "protosw.h"
30 #include "socket.h"
31 #include "vmmac.h"
32 #include "ioctl.h"
33 #include "errno.h"
34 #include "vmparam.h"
35 #include "syslog.h"
36 #include "uio.h"
37 
38 #include "../net/if.h"
39 #include "../net/netisr.h"
40 #include "../net/route.h"
41 #ifdef INET
42 #include "../netinet/in.h"
43 #include "../netinet/in_systm.h"
44 #include "../netinet/in_var.h"
45 #include "../netinet/ip.h"
46 #include "../netinet/ip_var.h"
47 #include "../netinet/if_ether.h"
48 #endif
49 #ifdef NS
50 #include "../netns/ns.h"
51 #include "../netns/ns_if.h"
52 #endif
53 
54 #include "../tahoe/cpu.h"
55 #include "../tahoe/pte.h"
56 #include "../tahoe/mtpr.h"
57 
58 #include "../tahoevba/vbavar.h"
59 #include "../tahoeif/if_enpreg.h"
60 
61 #define ENPSTART	0xf02000	/* standard enp start addr */
62 #define	ENPUNIT(dev)	(minor(dev))	/* for enp ram devices */
63 /* macros for dealing with longs in i/o space */
64 #define	ENPGETLONG(a)	((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1]))
65 #define	ENPSETLONG(a,v) \
66    { register u_short *wp = (u_short *)(a); \
67      wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];}
68 
69 int	enpprobe(), enpattach(), enpintr();
70 long	enpstd[] = { 0xfff41000, 0xfff61000, 0 };
71 struct  vba_device *enpinfo[NENP];
72 struct  vba_driver enpdriver =
73     { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 };
74 
75 int	enpinit(), enpioctl(), enpreset(), enpoutput();
76 struct  mbuf *enpget();
77 
78 /*
79  * Ethernet software status per interface.
80  *
81  * Each interface is referenced by a network interface structure,
82  * es_if, which the routing code uses to locate the interface.
83  * This structure contains the output queue for the interface, its address, ...
84  */
85 struct  enp_softc {
86 	struct  arpcom es_ac;           /* common ethernet structures */
87 #define es_if		es_ac.ac_if
88 #define es_addr	es_ac.ac_enaddr
89 	short	es_ivec;		/* interrupt vector */
90 } enp_softc[NENP];
91 extern	struct ifnet loif;
92 
93 enpprobe(reg, vi)
94 	caddr_t reg;
95 	struct vba_device *vi;
96 {
97 	register br, cvec;		/* must be r12, r11 */
98 	register struct enpdevice *addr = (struct enpdevice *)reg;
99 	struct enp_softc *es = &enp_softc[vi->ui_unit];
100 
101 #ifdef lint
102 	br = 0; cvec = br; br = cvec;
103 	enpintr(0);
104 #endif
105 	if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2))
106 		return (0);
107 	es->es_ivec = --vi->ui_hd->vh_lastiv;
108 	addr->enp_state = S_ENPRESET;		/* reset by VERSAbus reset */
109 	br = 0x14, cvec = es->es_ivec;		/* XXX */
110 	return (sizeof (struct enpdevice));
111 }
112 
113 /*
114  * Interface exists: make available by filling in network interface
115  * record.  System will initialize the interface when it is ready
116  * to accept packets.
117  */
118 enpattach(ui)
119 	register struct vba_device *ui;
120 {
121 	struct enp_softc *es = &enp_softc[ui->ui_unit];
122 	register struct ifnet *ifp = &es->es_if;
123 
124 	ifp->if_unit = ui->ui_unit;
125 	ifp->if_name = "enp";
126 	ifp->if_mtu = ETHERMTU;
127 	ifp->if_init = enpinit;
128 	ifp->if_ioctl = enpioctl;
129 	ifp->if_output = enpoutput;
130 	ifp->if_reset = enpreset;
131 	ifp->if_flags = IFF_BROADCAST;
132 	if_attach(ifp);
133 }
134 
135 /*
136  * Reset of interface after "system" reset.
137  */
138 enpreset(unit, vban)
139 	int unit, vban;
140 {
141 	register struct vba_device *ui;
142 
143 	if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
144 	    ui->ui_vbanum != vban)
145 		return;
146 	printf(" enp%d", unit);
147 	enpinit(unit);
148 }
149 
150 /*
151  * Initialization of interface; clear recorded pending operations.
152  */
153 enpinit(unit)
154 	int unit;
155 {
156 	struct enp_softc *es = &enp_softc[unit];
157 	register struct vba_device *ui = enpinfo[unit];
158 	struct enpdevice *addr;
159 	register struct ifnet *ifp = &es->es_if;
160 	int s;
161 
162 	if (ifp->if_addrlist == (struct ifaddr *)0)
163 		return;
164 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
165 		addr = (struct enpdevice *)ui->ui_addr;
166 		s = splimp();
167 		RESET_ENP(addr);
168 		DELAY(200000);
169 		es->es_if.if_flags |= IFF_RUNNING;
170 		splx(s);
171 	}
172 }
173 
174 /*
175  * Ethernet interface interrupt.
176  */
177 enpintr(unit)
178 	int unit;
179 {
180 	register struct enpdevice *addr;
181 	register BCB *bcbp;
182 
183 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
184 #if ENP == 30
185 	if (!IS_ENP_INTR(addr))
186 		return;
187 	ACK_ENP_INTR(addr);
188 #endif
189 	while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) {
190 		(void) enpread(&enp_softc[unit], bcbp);
191 		(void) ringput((RING *)&addr->enp_enpfree, bcbp);
192 	}
193 }
194 
195 /*
196  * Read input packet, examine its packet type, and enqueue it.
197  */
198 enpread(es, bcbp)
199 	struct enp_softc *es;
200 	register BCB *bcbp;
201 {
202 	register struct ether_header *enp;
203 	struct mbuf *m;
204 	int s, len, off, resid;
205 	register struct ifqueue *inq;
206 
207 	es->es_if.if_ipackets++;
208 	/*
209 	 * Get input data length.
210 	 * Get pointer to ethernet header (in input buffer).
211 	 * Deal with trailer protocol: if type is PUP trailer
212 	 * get true type from first 16-bit word past data.
213 	 * Remember that type was trailer by setting off.
214 	 */
215 	len = bcbp->b_msglen - sizeof (struct ether_header);
216 	enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr);
217 #define enpdataaddr(enp, off, type) \
218     ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off))))
219 	enp->ether_type = ntohs((u_short)enp->ether_type);
220 	if (enp->ether_type >= ETHERTYPE_TRAIL &&
221 	    enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
222 		off = (enp->ether_type - ETHERTYPE_TRAIL) * 512;
223 		if (off >= ETHERMTU)
224 			goto setup;
225 		enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *));
226 		resid = ntohs(*(enpdataaddr(enp, off+2, u_short *)));
227 		if (off + resid > len)
228 			goto setup;
229 		len = off + resid;
230 	} else
231 		off = 0;
232 	if (len == 0)
233 		goto setup;
234 
235 	/*
236 	 * Pull packet off interface.  Off is nonzero if packet
237 	 * has trailing header; enpget will then force this header
238 	 * information to be at the front, but we still have to drop
239 	 * the type and length which are at the front of any trailer data.
240 	 */
241 	m = enpget((u_char *)enp, len, off, &es->es_if);
242 	if (m == 0)
243 		goto setup;
244 	if (off) {
245 		struct ifnet *ifp;
246 
247 		ifp = *(mtod(m, struct ifnet **));
248 		m->m_off += 2 * sizeof (u_short);
249 		m->m_len -= 2 * sizeof (u_short);
250 		*(mtod(m, struct ifnet **)) = ifp;
251 	}
252 	switch (enp->ether_type) {
253 
254 #ifdef INET
255 	case ETHERTYPE_IP:
256 		schednetisr(NETISR_IP);
257 		inq = &ipintrq;
258 		break;
259 #endif
260 	case ETHERTYPE_ARP:
261 		arpinput(&es->es_ac, m);
262 		goto setup;
263 
264 #ifdef NS
265 	case ETHERTYPE_NS:
266 		schednetisr(NETISR_NS);
267 		inq = &nsintrq;
268 		break;
269 #endif
270 	default:
271 		m_freem(m);
272 		goto setup;
273 	}
274 	if (IF_QFULL(inq)) {
275 		IF_DROP(inq);
276 		m_freem(m);
277 		goto setup;
278 	}
279 	s = splimp();
280 	IF_ENQUEUE(inq, m);
281 	splx(s);
282 setup:
283 	return (0);
284 }
285 
286 /*
287  * Ethernet output routine. (called by user)
288  * Encapsulate a packet of type family for the local net.
289  * Use trailer local net encapsulation if enough data in first
290  * packet leaves a multiple of 512 bytes of data in remainder.
291  * If destination is this address or broadcast, send packet to
292  * loop device to kludge around the fact that 3com interfaces can't
293  * talk to themselves.
294  */
295 enpoutput(ifp, m0, dst)
296 	struct ifnet *ifp;
297 	struct mbuf *m0;
298 	struct sockaddr *dst;
299 {
300 	register struct enp_softc *es = &enp_softc[ifp->if_unit];
301 	register struct mbuf *m = m0;
302 	register struct ether_header *enp;
303 	register int off;
304 	struct mbuf *mcopy = (struct mbuf *)0;
305 	int type, s, error, usetrailers;
306 	u_char edst[6];
307 	struct in_addr idst;
308 
309 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
310 		error = ENETDOWN;
311 		goto bad;
312 	}
313 	switch (dst->sa_family) {
314 #ifdef INET
315 	case AF_INET:
316 		idst = ((struct sockaddr_in *)dst)->sin_addr;
317 		if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers))
318 			return (0);	/* if not yet resolved */
319 		if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
320 		    sizeof (edst)))
321 			mcopy = m_copy(m, 0, (int)M_COPYALL);
322 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
323 		if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
324 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
325 			type = ETHERTYPE_TRAIL + (off>>9);
326 			m->m_off -= 2 * sizeof (u_short);
327 			m->m_len += 2 * sizeof (u_short);
328 			*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
329 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
330 			goto gottrailertype;
331 		}
332 		type = ETHERTYPE_IP;
333 		off = 0;
334 		goto gottype;
335 #endif
336 #ifdef NS
337 	case AF_NS:
338 		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
339 		    (caddr_t)edst, sizeof (edst));
340 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst)))
341 			mcopy = m_copy(m, 0, (int)M_COPYALL);
342 		else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
343 		    sizeof (edst)))
344 			return (looutput(&loif, m, dst));
345 		type = ETHERTYPE_NS;
346 		off = 0;
347 		goto gottype;
348 #endif
349 	case AF_UNSPEC:
350 		enp = (struct ether_header *)dst->sa_data;
351 		bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst));
352 		type = enp->ether_type;
353 		goto gottype;
354 
355 	default:
356 		log(LOG_ERR, "enp%d: can't handle af%d\n",
357 		    ifp->if_unit, dst->sa_family);
358 		error = EAFNOSUPPORT;
359 		goto bad;
360 	}
361 
362 gottrailertype:
363 	/*
364 	 * Packet to be sent as trailer: move first packet
365 	 * (control information) to end of chain.
366 	 */
367 	while (m->m_next)
368 		m = m->m_next;
369 	m->m_next = m0;
370 	m = m0->m_next;
371 	m0->m_next = 0;
372 	m0 = m;
373 
374 gottype:
375 	/*
376          * Add local net header.  If no space in first mbuf,
377          * allocate another.
378          */
379 	if (m->m_off > MMAXOFF ||
380 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
381 		m = m_get(M_DONTWAIT, MT_HEADER);
382 		if (m == 0) {
383 			error = ENOBUFS;
384 			goto bad;
385 		}
386 		m->m_next = m0;
387 		m->m_off = MMINOFF;
388 		m->m_len = sizeof (struct ether_header);
389 	} else {
390 		m->m_off -= sizeof (struct ether_header);
391 		m->m_len += sizeof (struct ether_header);
392 	}
393 	enp = mtod(m, struct ether_header *);
394 	bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst));
395 	bcopy((caddr_t)es->es_addr, (caddr_t)enp->ether_shost,
396 	    sizeof (es->es_addr));
397 	enp->ether_type = htons((u_short)type);
398 
399 	/*
400 	 * Queue message on interface if possible
401 	 */
402 	s = splimp();
403 	if (enpput(ifp->if_unit, m)) {
404 		error = ENOBUFS;
405 		goto qfull;
406 	}
407 	splx(s);
408 	es->es_if.if_opackets++;
409 	return (mcopy ? looutput(&loif, mcopy, dst) : 0);
410 qfull:
411 	splx(s);
412 	m0 = m;
413 bad:
414 	m_freem(m0);
415 	if (mcopy)
416 		m_freem(mcopy);
417 	return (error);
418 }
419 
420 /*
421  * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
422  */
423 enpput(unit, m)
424 	int unit;
425 	struct mbuf *m;
426 {
427 	register BCB *bcbp;
428 	register struct enpdevice *addr;
429 	register struct mbuf *mp;
430 	register u_char *bp;
431 	register u_int len;
432 	u_char *mcp;
433 
434 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
435 	if (ringempty((RING *)&addr->enp_hostfree))
436 		return (1);
437 	bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree);
438 	bcbp->b_len = 0;
439 	bp = (u_char *)ENPGETLONG(&bcbp->b_addr);
440 	for (mp = m; mp; mp = mp->m_next) {
441 		len = mp->m_len;
442 		if (len == 0)
443 			continue;
444 		mcp = mtod(mp, u_char *);
445 		enpcopy(mcp, bp, len);
446 		bp += len;
447 		bcbp->b_len += len;
448 	}
449 	bcbp->b_len = MAX(ETHERMIN+sizeof (struct ether_header), bcbp->b_len);
450 	bcbp->b_reserved = 0;
451 	if (ringput((RING *)&addr->enp_toenp, bcbp) == 1)
452 		INTR_ENP(addr);
453 	m_freem(m);
454 	return (0);
455 }
456 
457 /*
458  * Routine to copy from VERSAbus memory into mbufs.
459  *
460  * Warning: This makes the fairly safe assumption that
461  * mbufs have even lengths.
462  */
463 struct mbuf *
464 enpget(rxbuf, totlen, off0, ifp)
465 	u_char *rxbuf;
466 	int totlen, off0;
467 	struct ifnet *ifp;
468 {
469 	register u_char *cp, *mcp;
470 	register struct mbuf *m;
471 	struct mbuf *top = 0, **mp = &top;
472 	int len, off = off0;
473 
474 	cp = rxbuf + sizeof (struct ether_header);
475 	while (totlen > 0) {
476 		MGET(m, M_DONTWAIT, MT_DATA);
477 		if (m == 0)
478 			goto bad;
479 		if (off) {
480 			len = totlen - off;
481 			cp = rxbuf + sizeof (struct ether_header) + off;
482 		} else
483 			len = totlen;
484 		if (len >= NBPG) {
485 			MCLGET(m);
486 			if (m->m_len == CLBYTES)
487 				m->m_len = len = MIN(len, CLBYTES);
488 			else
489 				m->m_len = len = MIN(MLEN, len);
490 		} else {
491 			m->m_len = len = MIN(MLEN, len);
492 			m->m_off = MMINOFF;
493 		}
494 		mcp = mtod(m, u_char *);
495 		if (ifp) {
496 			/*
497 			 * Prepend interface pointer to first mbuf.
498 			 */
499 			*(mtod(m, struct ifnet **)) = ifp;
500 			mcp += sizeof (ifp);
501 			len -= sizeof (ifp);
502 			ifp = (struct ifnet *)0;
503 		}
504 		enpcopy(cp, mcp, (u_int)len);
505 		cp += len;
506 		*mp = m;
507 		mp = &m->m_next;
508 		if (off == 0) {
509 			totlen -= len;
510 			continue;
511 		}
512 		off += len;
513 		if (off == totlen) {
514 			cp = rxbuf + sizeof (struct ether_header);
515 			off = 0;
516 			totlen = off0;
517 		}
518 	}
519 	return (top);
520 bad:
521 	m_freem(top);
522 	return (0);
523 }
524 
525 enpcopy(from, to, cnt)
526 	register u_char *from, *to;
527 	register u_int cnt;
528 {
529 	register c;
530 	register short *f, *t;
531 
532 	if (((int)from&01) && ((int)to&01)) {
533 		/* source & dest at odd addresses */
534 		*to++ = *from++;
535 		--cnt;
536 	}
537 	if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) {
538 		t = (short *)to;
539 		f = (short *)from;
540 		for (c = cnt>>1; c; --c)	/* even address copy */
541 			*t++ = *f++;
542 		cnt &= 1;
543 		if (cnt) {			/* odd len */
544 			from = (u_char *)f;
545 			to = (u_char *)t;
546 			*to = *from;
547 		}
548 	}
549 	while ((int)cnt-- > 0)	/* one of the address(es) must be odd */
550 		*to++ = *from++;
551 }
552 
553 /*
554  * Process an ioctl request.
555  */
556 enpioctl(ifp, cmd, data)
557 	register struct ifnet *ifp;
558 	int cmd;
559 	caddr_t data;
560 {
561 	register struct ifaddr *ifa = (struct ifaddr *)data;
562 	struct enpdevice *addr;
563 	int s = splimp(), error = 0;
564 
565 	switch (cmd) {
566 
567 	case SIOCSIFADDR:
568 		ifp->if_flags |= IFF_UP;
569 		switch (ifa->ifa_addr.sa_family) {
570 #ifdef INET
571 		case AF_INET:
572 			enpinit(ifp->if_unit);
573 			((struct arpcom *)ifp)->ac_ipaddr =
574 			    IA_SIN(ifa)->sin_addr;
575 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
576 			break;
577 #endif
578 #ifdef NS
579 		case AF_NS: {
580 			struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
581 			struct enp_softc *es = &enp_softc[ifp->if_unit];
582 
583 			if (!ns_nullhost(*ina)) {
584 				ifp->if_flags &= ~IFF_RUNNING;
585 				addr = (struct enpdevice *)
586 				    enpinfo[ifp->if_unit]->ui_addr;
587 				enpsetaddr(ifp->if_unit, addr,
588 				    ina->x_host.c_host);
589 			} else
590 				ina->x_host = *(union ns_host *)es->es_addr;
591 			enpinit(ifp->if_unit);
592 			break;
593 		}
594 #endif
595 		default:
596 			enpinit(ifp->if_unit);
597 			break;
598 		}
599 		break;
600 
601 	case SIOCSIFFLAGS:
602 		if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
603 			enpinit(ifp->if_unit);		/* reset board */
604 			ifp->if_flags &= ~IFF_RUNNING;
605 		} else if (ifp->if_flags&IFF_UP &&
606 		     (ifp->if_flags&IFF_RUNNING) == 0)
607 			enpinit(ifp->if_unit);
608 		break;
609 
610 	default:
611 		error = EINVAL;
612 	}
613 	splx(s);
614 	return (error);
615 }
616 
617 enpsetaddr(unit, addr, enaddr)
618 	int unit;
619 	struct enpdevice *addr;
620 	u_char *enaddr;
621 {
622 
623 	enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr,
624 	    sizeof (struct ether_addr));
625 	enpinit(unit);
626 	enpgetaddr(unit, addr);
627 }
628 
629 enpgetaddr(unit, addr)
630 	int unit;
631 	struct enpdevice *addr;
632 {
633 	struct enp_softc *es = &enp_softc[unit];
634 
635 	enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr,
636 	    sizeof (struct ether_addr));
637 	printf("enp%d: hardware address %s\n",
638 	    unit, ether_sprintf(es->es_addr));
639 }
640 
641 /*
642  * Routines to synchronize enp and host.
643  */
644 #ifdef notdef
645 static
646 ringinit(rp, size)
647 	register RING *rp;
648 {
649 
650 	rp->r_rdidx = rp->r_wrtidx = 0;
651 	rp->r_size = size;
652 }
653 
654 static
655 ringfull(rp)
656 	register RING *rp;
657 {
658 	register short idx;
659 
660 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
661 	return (idx == rp->r_rdidx);
662 }
663 
664 static
665 fir(rp)
666 	register RING *rp;
667 {
668 
669 	return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0);
670 }
671 #endif
672 
673 static
674 ringempty(rp)
675 	register RING *rp;
676 {
677 
678 	return (rp->r_rdidx == rp->r_wrtidx);
679 }
680 
681 static
682 ringput(rp, v)
683 	register RING *rp;
684 	BCB *v;
685 {
686 	register int idx;
687 
688 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
689 	if (idx != rp->r_rdidx) {
690 		ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v);
691 		rp->r_wrtidx = idx;
692 		if ((idx -= rp->r_rdidx) < 0)
693 			idx += rp->r_size;
694 		return (idx);			/* num ring entries */
695 	}
696 	return (0);
697 }
698 
699 static
700 ringget(rp)
701 	register RING *rp;
702 {
703 	register int i = 0;
704 
705 	if (rp->r_rdidx != rp->r_wrtidx) {
706 		i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]);
707 		rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
708 	}
709 	return (i);
710 }
711 
712 /*
713  * ENP Ram device.
714  */
715 enpr_open(dev)
716 	dev_t dev;
717 {
718 	register int unit = ENPUNIT(dev);
719 	struct vba_device *ui;
720 	struct enpdevice *addr;
721 
722 	if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
723 	    (addr = (struct enpdevice *)ui->ui_addr) == 0)
724 		return (ENODEV);
725 	if (addr->enp_state != S_ENPRESET)
726 		return (EACCES);  /* enp is not in reset state, don't open  */
727 	return (0);
728 }
729 
730 /*ARGSUSED*/
731 enpr_close(dev)
732 	dev_t dev;
733 {
734 
735 	return (0);
736 }
737 
738 enpr_read(dev, uio)
739 	dev_t dev;
740 	register struct uio *uio;
741 {
742 	register struct iovec *iov;
743 	struct enpdevice *addr;
744 
745 	if (uio->uio_offset > RAM_SIZE)
746 		return (ENODEV);
747 	iov = uio->uio_iov;
748 	if (uio->uio_offset + iov->iov_len > RAM_SIZE)
749 		iov->iov_len = RAM_SIZE - uio->uio_offset;
750 	addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
751 	if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0)
752 		return (EFAULT);
753 	enpcopy((u_char *)&addr->enp_ram[uio->uio_offset],
754 	    (u_char *)iov->iov_base, (u_int)iov->iov_len);
755 	uio->uio_resid -= iov->iov_len;
756 	iov->iov_len = 0;
757 	return (0);
758 }
759 
760 enpr_write(dev, uio)
761 	dev_t dev;
762 	register struct uio *uio;
763 {
764 	register struct enpdevice *addr;
765 	register struct iovec *iov;
766 
767 	addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
768 	iov = uio->uio_iov;
769 	if (uio->uio_offset > RAM_SIZE)
770 		return (ENODEV);
771 	if (uio->uio_offset + iov->iov_len > RAM_SIZE)
772 		iov->iov_len = RAM_SIZE - uio->uio_offset;
773 	if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0)
774 		return (EFAULT);
775 	enpcopy((u_char *)iov->iov_base,
776 	    (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len);
777 	uio->uio_resid -= iov->iov_len;
778 	iov->iov_len = 0;
779 	return (0);
780 }
781 
782 /*ARGSUSED*/
783 enpr_ioctl(dev, cmd, data)
784 	dev_t dev;
785 	caddr_t data;
786 {
787 	register unit = ENPUNIT(dev);
788 	struct enpdevice *addr;
789 
790 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
791 	switch(cmd) {
792 
793 	case ENPIOGO:
794 		ENPSETLONG(&addr->enp_base, addr);
795 		addr->enp_intrvec = enp_softc[unit].es_ivec;
796 		ENP_GO(addr, ENPSTART);
797 		DELAY(200000);
798 		enpinit(unit);
799 		/*
800 		 * Fetch Ethernet address after link level
801 		 * is booted (firmware copies manufacturer's
802 		 * address from on-board ROM).
803 		 */
804 		enpgetaddr(unit, addr);
805 		addr->enp_state = S_ENPRUN;
806 		break;
807 
808 	case ENPIORESET:
809 		RESET_ENP(addr);
810 		addr->enp_state = S_ENPRESET;
811 		DELAY(100000);
812 		break;
813 	default:
814 		return (EINVAL);
815 	}
816 	return (0);
817 }
818 #endif
819