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