xref: /csrg-svn/sys/tahoe/if/if_enp.c (revision 30230)
1 /*	if_enp.c	1.2	86/11/29	*/
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 	enpintr(0);
88 #endif
89 	if (badaddr(addr, 2) || badaddr(&addr->enp_ram[0], 2))
90 		return (0);
91 	es->es_ivec = --vi->ui_hd->vh_lastiv;
92 	addr->enp_state = S_ENPRESET;		/* reset by VERSAbus reset */
93 	br = 0x14, cvec = es->es_ivec;		/* XXX */
94 	return (sizeof (struct enpdevice));
95 }
96 
97 /*
98  * Interface exists: make available by filling in network interface
99  * record.  System will initialize the interface when it is ready
100  * to accept packets.
101  */
102 enpattach(ui)
103 	register struct vba_device *ui;
104 {
105 	struct enp_softc *es = &enp_softc[ui->ui_unit];
106 	register struct ifnet *ifp = &es->es_if;
107 	register struct enpdevice *addr = (struct enpdevice *)ui->ui_addr;
108 
109 	ifp->if_unit = ui->ui_unit;
110 	ifp->if_name = "enp";
111 	ifp->if_mtu = ETHERMTU;
112 	/*
113 	 * Get station's addresses.
114 	 */
115 	enpcopy(&addr->enp_addr.e_baseaddr, es->es_enaddr,
116 	    sizeof (es->es_enaddr));
117 	printf("enp%d: hardware address %s\n", ui->ui_unit,
118 	    ether_sprintf(es->es_enaddr));
119 	/*
120 	 * Allocate and map ram.
121 	 */
122 	vbmemalloc(128, ((caddr_t)addr)+0x1000, &es->es_map, &es->es_ram);
123 
124 	ifp->if_init = enpinit;
125 	ifp->if_ioctl = enpioctl;
126 	ifp->if_output = enpoutput;
127 	ifp->if_reset = enpreset;
128 	ifp->if_flags = IFF_BROADCAST;
129 	if_attach(ifp);
130 }
131 
132 /*
133  * Reset of interface after "system" reset.
134  */
135 enpreset(unit, vban)
136 	int unit, vban;
137 {
138 	register struct vba_device *ui;
139 
140 	if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
141 	    ui->ui_vbanum != vban)
142 		return;
143 	printf(" enp%d", unit);
144 	enpinit(unit);
145 }
146 
147 /*
148  * Initialization of interface; clear recorded pending operations.
149  */
150 enpinit(unit)
151 	int unit;
152 {
153 	struct enp_softc *es = &enp_softc[unit];
154 	register struct vba_device *ui = enpinfo[unit];
155 	struct enpdevice *addr;
156 	register struct ifnet *ifp = &es->es_if;
157 	int s;
158 
159 	if (ifp->if_addrlist == (struct ifaddr *)0)
160 		return;
161 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
162 		addr = (struct enpdevice *)ui->ui_addr;
163 		s = splimp();
164 		RESET_ENP(addr);
165 		DELAY(200000);
166 		addr->enp_intrvec = es->es_ivec;
167 		es->es_if.if_flags |= IFF_RUNNING;
168 		splx(s);
169 	}
170 }
171 
172 /*
173  * Ethernet interface interrupt.
174  */
175 enpintr(unit)
176 	int unit;
177 {
178 	register struct enpdevice *addr;
179 	register BCB *bcbp;
180 
181 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
182 	if (!IS_ENP_INTR(addr))
183 		return;
184 	ACK_ENP_INTR(addr);
185 	while ((bcbp = (BCB *)ringget(&addr->enp_tohost )) != 0) {
186 		(void) enpread(&enp_softc[unit], bcbp, unit);
187 		ringput(&addr->enp_enpfree, bcbp);
188 	}
189 }
190 
191 /*
192  * Read input packet, examine its packet type, and enqueue it.
193  */
194 enpread(es, bcbp, unit)
195 	struct enp_softc *es;
196 	register BCB *bcbp;
197 	int unit;
198 {
199 	register struct ether_header *enp;
200 	struct mbuf *m;
201 	long int s;
202 	int len, off, resid, enptype;
203 	register struct ifqueue *inq;
204 
205 	es->es_if.if_ipackets++;
206 	/*
207 	 * Get input data length.
208 	 * Get pointer to ethernet header (in input buffer).
209 	 * Deal with trailer protocol: if type is PUP trailer
210 	 * get true type from first 16-bit word past data.
211 	 * Remember that type was trailer by setting off.
212 	 */
213 	len = bcbp->b_msglen - sizeof (struct ether_header);
214 	enp = (struct ether_header *)bcbp->b_addr;
215 #define enpdataaddr(enp, off, type) \
216     ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off))))
217 	enp->ether_type = ntohs((u_short)enp->ether_type);
218 	if (enp->ether_type >= ETHERTYPE_TRAIL &&
219 	    enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
220 		off = (enp->ether_type - ETHERTYPE_TRAIL) * 512;
221 		if (off >= ETHERMTU)
222 			goto setup;
223 		enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *));
224 		resid = ntohs(*(enpdataaddr(enp, off+2, u_short *)));
225 		if (off + resid > len)
226 			goto setup;
227 		len = off + resid;
228 	} else
229 		off = 0;
230 	if (len == 0)
231 		goto setup;
232 
233 	/*
234 	 * Pull packet off interface.  Off is nonzero if packet
235 	 * has trailing header; enpget will then force this header
236 	 * information to be at the front, but we still have to drop
237 	 * the type and length which are at the front of any trailer data.
238 	 */
239 	m = enpget(bcbp->b_addr, len, off, &es->es_if);
240 	if (m == 0)
241 		goto setup;
242 	if (off) {
243 		struct ifnet *ifp;
244 
245 		ifp = *(mtod(m, struct ifnet **));
246 		m->m_off += 2 * sizeof (u_short);
247 		m->m_len -= 2 * sizeof (u_short);
248 		*(mtod(m, struct ifnet **)) = ifp;
249 	}
250 	switch (enp->ether_type) {
251 
252 #ifdef INET
253 	case ETHERTYPE_IP:
254 		schednetisr(NETISR_IP);
255 		inq = &ipintrq;
256 		break;
257 #endif
258 	case ETHERTYPE_ARP:
259 		arpinput(&es->es_ac, m);
260 		goto setup;
261 
262 #ifdef NS
263 	case ETHERTYPE_NS:
264 		schednetisr(NETISR_NS);
265 		inq = &nsintrq;
266 		break;
267 #endif
268 	default:
269 		m_freem(m);
270 		goto setup;
271 	}
272 	if (IF_QFULL(inq)) {
273 		IF_DROP(inq);
274 		m_freem(m);
275 		goto setup;
276 	}
277 	s = splimp();
278 	IF_ENQUEUE(inq, m);
279 	splx(s);
280 setup:
281 	return (0);
282 }
283 
284 /*
285  * Ethernet output routine. (called by user)
286  * Encapsulate a packet of type family for the local net.
287  * Use trailer local net encapsulation if enough data in first
288  * packet leaves a multiple of 512 bytes of data in remainder.
289  * If destination is this address or broadcast, send packet to
290  * loop device to kludge around the fact that 3com interfaces can't
291  * talk to themselves.
292  */
293 enpoutput(ifp, m0, dst)
294 	struct ifnet *ifp;
295 	struct mbuf *m0;
296 	struct sockaddr *dst;
297 {
298 	register struct enp_softc *es = &enp_softc[ifp->if_unit];
299 	register struct mbuf *m = m0;
300 	register struct ether_header *enp;
301 	register int off, i;
302 	struct mbuf *mcopy = (struct mbuf *)0;
303 	int type, s, error, usetrailers;
304 	u_char edst[6];
305 	struct in_addr idst;
306 
307 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
308 		error = ENETDOWN;
309 		goto bad;
310 	}
311 	switch (dst->sa_family) {
312 #ifdef INET
313 	case AF_INET:
314 		idst = ((struct sockaddr_in *)dst)->sin_addr;
315 		if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers))
316 			return (0);	/* if not yet resolved */
317 		if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
318 		    sizeof (edst)))
319 			mcopy = m_copy(m, 0, (int)M_COPYALL);
320 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
321 		if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
322 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
323 			type = ETHERTYPE_TRAIL + (off>>9);
324 			m->m_off -= 2 * sizeof (u_short);
325 			m->m_len += 2 * sizeof (u_short);
326 			*mtod(m, u_short *) = ETHERTYPE_IP;
327 			*(mtod(m, u_short *) + 1) = m->m_len;
328 			goto gottrailertype;
329 		}
330 		type = ETHERTYPE_IP;
331 		off = 0;
332 		goto gottype;
333 #endif
334 #ifdef NS
335 	case AF_NS:
336 		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
337 		    (caddr_t)edst, sizeof (edst));
338 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst)))
339 			mcopy = m_copy(m, 0, (int)M_COPYALL);
340 		else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
341 		    sizeof (edst)))
342 			return (looutput(&loif, m, dst));
343 		type = ETHERTYPE_NS;
344 		off = 0;
345 		goto gottype;
346 #endif
347 	case AF_UNSPEC:
348 		enp = (struct ether_header *)dst->sa_data;
349 		bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst));
350 		type = enp->ether_type;
351 		goto gottype;
352 
353 	default:
354 		log(LOG_ERR, "enp%d: can't handle af%d\n",
355 		    ifp->if_unit, dst->sa_family);
356 		error = EAFNOSUPPORT;
357 		goto bad;
358 	}
359 
360 gottrailertype:
361 	/*
362 	 * Packet to be sent as trailer: move first packet
363 	 * (control information) to end of chain.
364 	 */
365 	while (m->m_next)
366 		m = m->m_next;
367 	m->m_next = m0;
368 	m = m0->m_next;
369 	m0->m_next = 0;
370 	m0 = m;
371 
372 gottype:
373 	/*
374          * Add local net header.  If no space in first mbuf,
375          * allocate another.
376          */
377 	if (m->m_off > MMAXOFF ||
378 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
379 		m = m_get(M_DONTWAIT, MT_HEADER);
380 		if (m == 0) {
381 			error = ENOBUFS;
382 			goto bad;
383 		}
384 		m->m_next = m0;
385 		m->m_off = MMINOFF;
386 		m->m_len = sizeof (struct ether_header);
387 	} else {
388 		m->m_off -= sizeof (struct ether_header);
389 		m->m_len += sizeof (struct ether_header);
390 	}
391 	enp = mtod(m, struct ether_header *);
392 	bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst));
393 	bcopy((caddr_t)es->es_enaddr, (caddr_t)enp->ether_shost,
394 	    sizeof (es->es_enaddr));
395 	enp->ether_type = htons((u_short)type);
396 
397 	/*
398 	 * Queue message on interface if possible
399 	 */
400 	s = splimp();
401 	if (enpput(ifp->if_unit, m)) {
402 		error = ENOBUFS;
403 		goto qfull;
404 	}
405 	splx(s);
406 	es->es_if.if_opackets++;
407 	return (mcopy ? looutput(&loif, mcopy, dst) : 0);
408 qfull:
409 	splx(s);
410 	m0 = m;
411 bad:
412 	m_freem(m0);
413 	if (mcopy)
414 		m_freem(mcopy);
415 	return (error);
416 }
417 
418 /*
419  * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
420  */
421 enpput(unit, m)
422 	int unit;
423 	struct mbuf *m;
424 {
425 	register BCB *bcbp;
426 	register struct enpdevice *addr;
427 	register struct mbuf *mp;
428 	register u_char *bp;
429 	register u_int len;
430 	u_char *mcp;
431 
432 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
433 	if (ringempty(&addr->enp_hostfree))
434 		return (1);
435 	bcbp = (BCB *)ringget(&addr->enp_hostfree);
436 	bcbp->b_len = 0;
437 	bp = (u_char *)bcbp->b_addr;
438 	for (mp = m; mp; mp = mp->m_next) {
439 		len = mp->m_len;
440 		if (len == 0)
441 			continue;
442 		mcp = mtod(mp, u_char *);
443 		enpcopy(mcp, bp, len);
444 		bp += len;
445 		bcbp->b_len += len;
446 	}
447 	bcbp->b_len = max(ETHERMIN, bcbp->b_len);
448 	bcbp->b_reserved = 0;
449 	if (ringput(&addr->enp_toenp, bcbp) == 1)
450 		INTR_ENP(addr);
451 	m_freem(m);
452 	return (0);
453 }
454 
455 /*
456  * Routine to copy from VERSAbus memory into mbufs.
457  *
458  * Warning: This makes the fairly safe assumption that
459  * mbufs have even lengths.
460  */
461 struct mbuf *
462 enpget(rxbuf, totlen, off0, ifp)
463 	u_char *rxbuf;
464 	int totlen, off0;
465 	struct ifnet *ifp;
466 {
467 	register u_char *cp, *mcp;
468 	register struct mbuf *m;
469 	struct mbuf *top = 0, **mp = &top;
470 	int len, off = off0;
471 
472 	cp = rxbuf + sizeof (struct ether_header);
473 	while (totlen > 0) {
474 		MGET(m, M_DONTWAIT, MT_DATA);
475 		if (m == 0)
476 			goto bad;
477 		if (off) {
478 			len = totlen - off;
479 			cp = rxbuf + sizeof (struct ether_header) + off;
480 		} else
481 			len = totlen;
482 		if (len >= NBPG) {
483 			struct mbuf *p;
484 
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, 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 char *from, *to;
527 	register 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 = (char *)f;
545 			to = (char *)t;
546 			*to = *from;
547 		}
548 	}
549 	while (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_enaddr;
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 	u_char *cp;
623 	int i, code;
624 
625 	cp = &addr->enp_addr.e_baseaddr.ea_addr[0];
626 	for (i = 0; i < 6; i++)
627 		*cp++ = ~*enaddr++;
628 	enpcopy(&addr->enp_addr.e_listsize, &code, sizeof (code));
629 	code |= E_ADDR_SUPP;
630 	enpcopy(&code, &addr->enp_addr.e_listsize, sizeof (code));
631 	enpinit(unit);
632 }
633 
634 /*
635  * Routines to synchronize enp and host.
636  */
637 static
638 ringinit(rp, size)
639 	register RING *rp;
640 {
641 	register int i;
642 	register short *sp;
643 
644 	rp->r_rdidx = rp->r_wrtidx = 0;
645 	rp->r_size = size;
646 }
647 
648 static
649 ringempty(rp)
650 	register RING *rp;
651 {
652 
653 	return (rp->r_rdidx == rp->r_wrtidx);
654 }
655 
656 static
657 ringfull(rp)
658 	register RING *rp;
659 {
660 	register short idx;
661 
662 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
663 	return (idx == rp->r_rdidx);
664 }
665 
666 static
667 ringput(rp, v)
668 	register RING *rp;
669 {
670 	register int idx;
671 
672 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
673 	if (idx != rp->r_rdidx) {
674 		rp->r_slot[rp->r_wrtidx] = v;
675 		rp->r_wrtidx = idx;
676 		if ((idx -= rp->r_rdidx) < 0)
677 			idx += rp->r_size;
678 		return (idx);			/* num ring entries */
679 	}
680 	return (0);
681 }
682 
683 static
684 ringget(rp)
685 	register RING *rp;
686 {
687 	register int i = 0;
688 
689 	if (rp->r_rdidx != rp->r_wrtidx) {
690 		i = rp->r_slot[rp->r_rdidx];
691 		rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
692 	}
693 	return (i);
694 }
695 
696 static
697 fir(rp)
698 	register RING *rp;
699 {
700 
701 	return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0);
702 }
703 
704 /*
705  * ENP Ram device.
706  */
707 enpr_open(dev)
708 	dev_t dev;
709 {
710 	register int unit = ENPUNIT(dev);
711 	struct vba_device *ui;
712 	struct enpdevice *addr;
713 
714 	if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
715 	    (addr = (struct enpdevice *)ui->ui_addr) == 0)
716 		return (ENODEV);
717 	if (addr->enp_state != S_ENPRESET)
718 		return (EACCES);  /* enp is not in reset state, don't open  */
719 	return (0);
720 }
721 
722 enpr_close(dev)
723 	dev_t dev;
724 {
725 
726 	return (0);
727 }
728 
729 enpr_read(dev, uio)
730 	dev_t dev;
731 	register struct uio *uio;
732 {
733 	register struct iovec *iov;
734 	struct enpdevice *addr;
735 	int error;
736 
737 	if (uio->uio_offset > RAM_SIZE)
738 		return (ENODEV);
739 	if (uio->uio_offset + iov->iov_len > RAM_SIZE)
740 		iov->iov_len = RAM_SIZE - uio->uio_offset;
741 	addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
742 	iov = uio->uio_iov;
743 	error = useracc(iov->iov_base, iov->iov_len, 0);
744 	if (error)
745 		return (error);
746 	enpcopy(&addr->enp_ram[uio->uio_offset], iov->iov_base, iov->iov_len);
747 	uio->uio_resid -= iov->iov_len;
748 	iov->iov_len = 0;
749 	return (0);
750 }
751 
752 enpr_write(dev, uio)
753 	dev_t dev;
754 	register struct uio *uio;
755 {
756 	register struct enpdevice *addr;
757 	register struct iovec *iov;
758 	register error;
759 
760 	addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
761 	iov = uio->uio_iov;
762 	if (uio->uio_offset > RAM_SIZE)
763 		return (ENODEV);
764 	if (uio->uio_offset + iov->iov_len > RAM_SIZE)
765 		iov->iov_len = RAM_SIZE - uio->uio_offset;
766 	error =  useracc(iov->iov_base, iov->iov_len, 1);
767 	if (error)
768 		return (error);
769 	enpcopy(iov->iov_base, &addr->enp_ram[uio->uio_offset], iov->iov_len);
770 	uio->uio_resid -= iov->iov_len;
771 	iov->iov_len = 0;
772 	return (0);
773 }
774 
775 enpr_ioctl(dev, cmd, data)
776 	dev_t dev;
777 	caddr_t data;
778 {
779 	register struct enpdevice *addr;
780 	register unit = ENPUNIT(dev);
781 	register struct vba_device *ui;
782 
783 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
784 	switch(cmd) {
785 
786 	case ENPIOGO:
787 /* not needed if prom based version */
788 		addr->enp_base = (int)addr;
789 		addr->enp_intrvec = enp_softc[unit].es_ivec;
790 		ENP_GO(addr, ENPSTART);
791 		DELAY(200000);
792 		enpinit(unit);
793 		addr->enp_state = S_ENPRUN;  /* it is running now */
794 /* end of not needed */
795 		break;
796 
797 	case ENPIORESET:
798 		RESET_ENP(addr);
799 		addr->enp_state = S_ENPRESET;  /* it is reset now */
800 		DELAY(100000);
801 		break;
802 	}
803 	return (0);
804 }
805 #endif
806