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