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