xref: /csrg-svn/sys/tahoe/if/if_enp.c (revision 29649)
1 /*	if_enp.c	1.1	86/07/20	*/
2 
3 #include "enp.h"
4 #define ENPBPTE 128
5 #if NENP > 0
6 
7 /*
8  * Modified 3 Com Ethernet Controller interface
9  * enp modifications added S. F. Holmgren
10  */
11 
12 #include "param.h"
13 #include "systm.h"
14 #include "mbuf.h"
15 #include "buf.h"
16 #include "protosw.h"
17 #include "socket.h"
18 #include "vmmac.h"
19 #include "errno.h"
20 #include "time.h"
21 #include "kernel.h"
22 #include "uio.h"
23 
24 #include "../net/if.h"
25 #include "../net/netisr.h"
26 #include "../net/route.h"
27 #include "../netinet/in.h"
28 #include "../h/ioctl.h"
29 
30 #include "../netinet/in_systm.h"
31 #include "../netinet/ip.h"
32 #include "../netinet/ip_var.h"
33 #include "../netinet/if_ether.h"
34 
35 #include "../tahoevba/vbavar.h"
36 #include "../tahoeif/if_enp.h"
37 #include "../machine/mtpr.h"
38 #include "../tahoeif/if_debug.h"
39 
40 #define ENP0_PHYSADDR	0xf40000	/* board # 0 physical base addr */
41 #define ENP1_PHYSADDR	0xf60000	/* board # 1 physical base addr */
42 #define ENPSTART	0xf02000	/* standard enp start addr 	*/
43 
44 int	enpprobe(), enpattach(), enpintr();
45 extern	nulldev();
46 caddr_t	vtoph();
47 struct  mbuf *m_tofree();
48 struct  vba_device *enpinfo[ NENP ];
49 
50 /*	Maximun 2 controllers per system supported			*/
51 
52 long  enpstd[] = { ENP0_PHYSADDR+0x1000,ENP1_PHYSADDR+0x1000, 0 };
53 extern	char	enp0utl[], enp1utl[];	/* enp accessible ram map	*/
54 char	*enpmap[]= { enp0utl, enp1utl };
55 extern	long	ENP0map[], ENP1map[];
56 long	*ENPmap[] = {ENP0map, ENP1map};
57 long	ENPmapa[] = {0xfff41000, 0xfff61000};
58 long	enpismapped[NENP];
59 
60 unsigned short intvec[4] =
61 	{ 0xc1, 0xc2, 0xc3, 0xc4 };	/* intrvec of upto 4 enps	*/
62 
63 struct  vba_driver enpdriver =
64 {
65 /* use of prom based version
66 	enpprobe, 0, enpattach, 0, 0,	enpintr,
67 */
68 	enpprobe, 0, nulldev, 0,
69 	enpstd,   "enp", enpinfo, "ENP 20", 0
70 };
71 
72 int     enpinit(),
73 	enpioctl(),
74 	enpoutput(),
75 	enpreset(),
76 	enpbroadcast(),
77 	enptimeout();
78 
79 int	enpcopy();
80 
81 struct  mbuf *enpget();
82 
83 extern  struct ifnet loif;
84 
85 /*
86  * Ethernet software status per interface.
87  *
88  * Each interface is referenced by a network interface structure,
89  * es_if, which the routing code uses to locate the interface.
90  * This structure contains the output queue for the interface, its address, ...
91  */
92 
93 struct 	enp_softc	enp_softc[NENP];
94 long	stat_addr[NENP];	/* enp statistic addr (for nstat use) */
95 long	ring_addr[NENP];	/* enp dev ring addresses (for nstat use) */
96 int 	numenp = NENP;
97 int	enp_intr = 0, 		/* no. of enp_to_host interrupts */
98 	host_intr = 0;		/* no. of host_to_enp interrupts */
99 short	enpram[NENP];		/* open/close flags for enp devices */
100 /*	Debugging tools, used to trace input packets */
101 extern 	int	printerror;	/* error print flag, from if_ace.c */
102 int	save_enp_inpkt = 0;
103 #define	ENPTRACE(X)	if (save_enp_inpkt) X;
104 
105 struct 	inp_err 	enperr[NENP];
106 
107 /*
108  * Probe for device.
109  */
110 
111 enpprobe(reg)
112 caddr_t reg;
113 {
114 	static	int 	unit=0;
115 	register ENPDEVICE	*addr = (ENPDEVICE *)reg;
116 
117 	if( (badaddr( addr, 2 ) ) || (badaddr( &addr->enp_ram[0], 2 ) ) )
118 		return( 0 );
119 	addr->enp_state = S_ENPRESET; /* controller is reset by vbus reset */
120 	/* save address of statistic area for nstat uses	*/
121 
122 	stat_addr[unit] = (long) &(addr->enp_stat);
123 	ring_addr[unit++] = (long) &(addr->enp_toenp);
124 
125 	return( ENPSIZE );
126 }
127 
128 /*
129  * Interface exists: make available by filling in network interface
130  * record.  System will initialize the interface when it is ready
131  * to accept packets.
132  */
133 
134 enpattach( md )
135 register struct vba_device *md;
136 {
137 	struct enp_softc 	*es = &enp_softc[md->ui_unit];
138 	register struct ifnet 	*ifp = &es->es_if;
139 	register ENPDEVICE 	*addr = (ENPDEVICE *)md->ui_addr;
140 	struct sockaddr_in 	*sin;
141 
142 	enpgetaddr( md->ui_unit );
143 
144 	ifp->if_unit = md->ui_unit;
145 	ifp->if_name = "enp";
146 	ifp->if_mtu = ETHERMTU;
147 
148 /*	bcopy(&es->es_boardaddr, es->es_enaddr, sizeof(es->es_enaddr)); */
149 
150 	sin = (struct sockaddr_in *)&es->es_if.if_addr;
151 	sin->sin_family = AF_INET;
152 
153 	ifp->if_init = enpinit;
154 	ifp->if_ioctl = enpioctl;
155 	ifp->if_output = enpoutput;
156 	ifp->if_reset = enpreset;
157 	if_attach(ifp);
158 }
159 
160 
161 /*
162  * Reset of interface after UNIBUS reset.
163  */
164 enpreset(unit)
165 int unit;
166 {
167 	register struct vba_device *md;
168 
169 	if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0)
170 		return(ENODEV);
171 
172 	enpinit(unit);
173 }
174 
175 /*
176  * Initialization of interface; clear recorded pending
177  * operations.
178  */
179 
180 enpinit( unit )
181 int unit;
182 {
183 	struct enp_softc 	*es = &enp_softc[unit];
184 	ENPDEVICE 		*addr;
185 	int i, s;
186 	u_char *cp, *ap;
187 	register struct ifnet 	*ifp = &es->es_if;
188 	register struct sockaddr_in *sin, *sinb;
189 
190 	sin = (struct sockaddr_in *)&ifp->if_addr;
191 
192 	if ( !enpismapped[unit] ) {
193 		ioaccess(ENPmap[unit],ENPmapa[unit],ENPBPTE);
194 		++enpismapped[unit];
195 	}
196 	if ((addr = (ENPDEVICE *)enpinfo[unit]->ui_addr) == (ENPDEVICE *)0)
197 		return(ENODEV);
198 	s = splimp();
199 	RESET_ENP( addr );
200 	DELAY( 200000 );
201 
202 #ifdef notdef
203 /* only needed if not downloading ( ie, ROM-resident ENP code) */
204 	addr->enp_intrvec = intvec[unit];
205 	ENP_GO( addr,ENPSTART );
206 	DELAY( 200000 );
207 /* end of ROM-resident */
208 #endif notdef
209 
210 	es->es_if.if_flags |= IFF_UP|IFF_RUNNING; /* open for business*/
211 	splx(s);
212 
213 	if_rtinit( &es->es_if,RTF_UP );
214 	arpwhohas(&es->es_ac, &sin->sin_addr);
215 }
216 
217 
218 /*
219  * Ethernet interface interrupt.
220  */
221 
222 enpintr( unit )
223 {
224 	register ENPDEVICE 		*addr;
225 	register BCB			*bcbp;
226 	register struct vba_device	 *md;
227 
228 	enp_intr++;
229 
230 	if (unit >= NENP || (md = enpinfo[unit]) == 0)
231 		return;
232 
233 	addr = (ENPDEVICE *)md->ui_addr;
234 
235 	if( IS_ENP_INTR(addr) == 0 )
236 		return;
237 
238 	ACK_ENP_INTR( addr );
239 
240 	while( (bcbp = (BCB *)ringget( &addr->enp_tohost )) != 0 )
241 	{
242 		enpread( &enp_softc[ unit ],bcbp, unit );
243 		ringput( &addr->enp_enpfree,bcbp );
244 	}
245 	return(0);
246 }
247 
248 #define	MAXBLEN	1500
249 char	errpkt[MAXBLEN];
250 int	bufptr = 0;
251 int	maxl_tosave = 200;		/* save only the first 200 bytes */
252 
253 saverrpkt(errbuf, errtype, len)
254 register u_char *errbuf;
255 int errtype, len;
256 {
257 	int remain, newptr;
258 
259 	remain = MAXBLEN - bufptr;
260 	if (remain < 50)		/* if too small			*/
261 		return;			/* no space avail		*/
262 	len = (len > maxl_tosave || len <= 0) ? maxl_tosave : len;
263 	len = len > remain ? (remain - 2*sizeof(len)): len;
264 	newptr = bufptr + len + 2*sizeof(len);
265 	if (newptr <= MAXBLEN) {
266 		enpcopy((char *)&len, &errpkt[bufptr], sizeof(len));
267 		enpcopy((char *)&errtype, &errpkt[bufptr+sizeof(len)],
268 			sizeof(errtype));
269 		enpcopy(errbuf, &errpkt[bufptr+(2*sizeof(len))], len);
270 	}
271 	bufptr = newptr;
272 }
273 
274 /*
275  * Read input packet, examine its packet type, and enqueue it.
276  */
277 
278 enpread( es, bcbp, unit )
279 struct	enp_softc *es;
280 register BCB *bcbp;
281 int	unit;
282 {
283 	register struct ether_header *enp;
284 	struct mbuf *m;
285 	long int  s, v;
286 	register short *vp = (short *)&v,
287 			*sp;
288 	int len, off, resid, enptype;
289 	register struct ifqueue *inq;
290 
291 	es->es_if.if_ipackets++;
292 
293 	/*
294 	 * Get input data length.
295 	 * Get pointer to ethernet header (in input buffer).
296 	 * Deal with trailer protocol: if type is PUP trailer
297 	 * get true type from first 16-bit word past data.
298 	 * Remember that type was trailer by setting off.
299 	 */
300 
301 	len = bcbp->b_msglen - SIZEOF_ETHEADER;
302 #ifdef TAHOE
303 	sp = (short *)&bcbp->b_addr;
304 	*vp = *sp; vp[1] = sp[1];
305 	enp = (struct ether_header *) v;
306 #else
307 	enp = (struct ether_header *)bcbp->b_addr;
308 #endif TAHOE
309 
310 #define enpdataaddr(enp, off, type) ((type)(((caddr_t)(((char *)enp)+SIZEOF_ETHEADER)+(off))))
311 
312 	enptype = enp->ether_type;
313 	if (enptype >= ETHERPUP_TRAIL && enptype < ETHERPUP_TRAIL+ETHERPUP_NTRAILER)
314 	{
315 		off = (enptype - ETHERPUP_TRAIL) * 512;
316 		if (off >= ETHERMTU) {
317 			enperr[unit].bad_offset++;
318 			ENPTRACE(saverrpkt((char *)enp, B_OFFSET, bcbp->b_msglen));
319 
320 			goto badinput;
321 		}
322 		enptype = *enpdataaddr(enp, off, u_short *);
323 		resid = *(enpdataaddr(enp, off+2, u_short *));
324 
325 		if (off + resid > len) {
326 			enperr[unit].bad_length++;
327 			ENPTRACE(saverrpkt((char *)enp, B_LENGTH, bcbp->b_msglen));
328 			goto badinput;
329 		}
330 		len = off + resid;
331 	}
332 	else
333 		off = 0;
334 
335 	if( len == 0 ) {
336 		enperr[unit].bad_length++;
337 		ENPTRACE(saverrpkt((char *)enp, B_LENGTH, bcbp->b_msglen));
338 		goto badinput;
339 	}
340 	/*
341 	 * Pull packet off interface.  Off is nonzero if packet
342 	 * has trailing header; enpget will then force this header
343 	 * information to be at the front, but we still have to drop
344 	 * the type and length which are at the front of any trailer data.
345 	 */
346 
347 	m = enpget(bcbp, len, off);
348 	if( m == 0 )  {
349 		enperr[unit].h_nobuffer++; /* host runs out of buf */
350 		goto badinput;
351 	}
352 	if( off )
353 	{
354 		m->m_off += 2 * sizeof (u_short);
355 		m->m_len -= 2 * sizeof (u_short);
356 	}
357 
358 	switch (enptype)
359 	{
360 #ifdef INET
361 	case ETHERPUP_IPTYPE:
362 #ifdef notdef
363 		arpipin(enp, m);
364 #endif notdef
365 		schednetisr(NETISR_IP);
366 		inq = &ipintrq;
367 		break;
368 
369 	case ETHERPUP_ARPTYPE:
370 		arpinput(&es->es_ac, m);
371 		return(0);
372 #endif
373 	default:	/* unrecognized ethernet header */
374 		enperr[unit].bad_packetype++;
375 		if (printerror) {
376 			printf("\nenp%d: Undefined packet type 0x%x ", unit,
377 				enp->ether_type);
378 			printf("from host: %x.%x.%x.%x.%x.%x\n",
379 				enp->ether_shost[0], enp->ether_shost[1],
380 				enp->ether_shost[2], enp->ether_shost[3],
381 				enp->ether_shost[4], enp->ether_shost[5]);
382 		}	/* end debugging aid	*/
383 		ENPTRACE(saverrpkt((char *)enp, B_PACKETYPE, bcbp->b_msglen));
384 		m_freem(m);
385 		goto badinput;
386 	}
387 
388 	if (IF_QFULL(inq))
389 	{
390 		enperr[unit].inq_full++;
391 		IF_DROP(inq);
392 		m_freem(m);
393 		return(0);
394 	}
395 	s = splimp();
396 	IF_ENQUEUE(inq, m);
397 	splx(s);
398 badinput:
399 	return(0);         /* sanity */
400 }
401 
402 /*
403  * Ethernet output routine. (called by user)
404  * Encapsulate a packet of type family for the local net.
405  * Use trailer local net encapsulation if enough data in first
406  * packet leaves a multiple of 512 bytes of data in remainder.
407  * If destination is this address or broadcast, send packet to
408  * loop device to kludge around the fact that 3com interfaces can't
409  * talk to themselves.
410  */
411 
412 enpoutput(ifp, m0, dst)
413 struct ifnet *ifp;
414 struct mbuf *m0;
415 struct sockaddr *dst;
416 {
417 	int type, s, error;
418 	struct ether_addr edst;
419 	struct in_addr idst;
420 
421 	register struct enp_softc *es = &enp_softc[ifp->if_unit];
422 	register struct mbuf *m = m0;
423 	register struct ether_header *enp;
424 	register int off, i;
425 
426 	struct mbuf *mcopy = (struct mbuf *) 0;         /* Null */
427 	int unit = ifp->if_unit;
428 
429 	switch( dst->sa_family )
430 	{
431 #ifdef INET
432 	case AF_INET:
433 		idst = ((struct sockaddr_in *)dst)->sin_addr;
434 
435 		/* translate internet to ethernet address */
436 
437 		switch(arpresolve(&es->es_ac, m, &idst, &edst)) {
438 
439 		   	case ARPRESOLVE_WILLSEND:
440 				return (0);	/* if not yet resolved */
441 		   	case ARPRESOLVE_BROADCAST:
442 				mcopy = m_copy(m, 0, (int)M_COPYALL);
443 				if (mcopy)
444 					looutput(&loif, mcopy, dst);
445 
446 				/* falls through ... */
447 		   	case ARPRESOLVE_OK:
448 				break;
449 		}
450 		off = ((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
451 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
452 			if (off > 0 && (off & 0x1ff) == 0 &&
453 			    m->m_off >= MMINOFF + 2 * sizeof (u_short))
454 			{
455 				type = ETHERPUP_TRAIL + (off>>9);
456 				m->m_off -= 2 * sizeof (u_short);
457 				m->m_len += 2 * sizeof (u_short);
458 				*mtod(m, u_short *) = ETHERPUP_IPTYPE;
459 				*(mtod(m, u_short *) + 1) = m->m_len;
460 				goto gottrailertype;
461 			}
462 
463 		type = ETHERPUP_IPTYPE;
464 		off = 0;
465 		goto gottype;
466 #endif
467 
468 #ifdef notdef
469 	case AF_RAW:
470 		enp = mtod(m, struct ether_header *);
471 		if (m->m_len < sizeof *enp)
472 		{
473 			error = EMSGSIZE;
474 			goto bad;
475 		}
476 		goto gotheader;
477 #endif
478 
479 	case AF_UNSPEC:
480 		enp = (struct ether_header *)dst->sa_data;
481 		bcopy( enp->ether_dhost, &edst, sizeof(edst));
482 		type = enp->ether_type;
483 		goto gottype;
484 
485 	default:
486 		if (printerror)
487 		    printf("enp%d: can't handle af%d\n", unit,dst->sa_family);
488 		error = EAFNOSUPPORT;
489 		goto bad;
490 	}
491 
492 gottrailertype:
493 	/*
494 	 * Packet to be sent as trailer: move first packet
495 	 * (control information) to end of chain.
496 	 */
497 	while (m->m_next)
498 		m = m->m_next;
499 	m->m_next = m0;
500 	m = m0->m_next;
501 	m0->m_next = 0;
502 	m0 = m;
503 
504 gottype:
505 	/*
506          * Add local net header.  If no space in first mbuf,
507          * allocate another.
508          */
509 	if (m->m_off > MMAXOFF ||
510 	    MMINOFF + SIZEOF_ETHEADER > m->m_off)
511 	{
512 		m = m_get(M_DONTWAIT, MT_HEADER);
513 		if (m == 0)
514 		{
515 			enperr[unit].h_nobuffer++; /* host runs out of buf */
516 			error = ENOBUFS;
517 			goto bad;
518 		}
519 		m->m_next = m0;
520 		m->m_off = MMINOFF;
521 		m->m_len = SIZEOF_ETHEADER;
522 	}
523 	else
524 	{
525 		m->m_off -= SIZEOF_ETHEADER;
526 		m->m_len += SIZEOF_ETHEADER;
527 	}
528 	enp = mtod(m, struct ether_header *);
529 	bcopy( &edst, enp->ether_dhost, sizeof(enp->ether_dhost) );
530 	enp->ether_type = type;
531 gotheader:
532 	bcopy( es->es_enaddr, enp->ether_shost, sizeof(enp->ether_shost));
533 
534 	/*
535 	 * Queue message on interface if possible
536 	 */
537 
538 	s = splimp();
539 	if( enpput( unit,m ) )
540 	{
541 		error = ENOBUFS;
542 		enperr[unit].c_nobuffer++; /* controller runs out of buf */
543 		goto qfull;
544 	}
545 	splx( s );
546 	es->es_if.if_opackets++;
547 	return(0);
548 qfull:
549 	splx( s );
550 	m0 = m;
551 bad:
552 	m_freem(m0);
553 	return(error);
554 }
555 
556 /*
557  * Routine to copy from mbuf chain to transmitter
558  * buffer in Multibus memory.
559  */
560 
561 enpput( unit,m )
562 int unit;
563 struct mbuf *m;
564 {
565 	register BCB *bcbp;
566 	register ENPDEVICE *addr;
567 	register struct mbuf *mp;
568 	register u_char *bp;
569 	int	 ctr = 0;
570 	long int	v;
571 	register short *vp = (short *)&v,
572 			*sp;
573 
574 	addr = (ENPDEVICE *)enpinfo[ unit ]->ui_addr;
575 
576 	if ( ringempty( &addr->enp_hostfree ) )
577 			return( 1 );
578 
579 	bcbp = (BCB *)ringget( &addr->enp_hostfree );
580 	bcbp->b_len = 0;
581 #ifdef TAHOE
582 	sp = (short *)&bcbp->b_addr;
583 	*vp = *sp; vp[1] = sp[1];
584 	bp = (u_char *)v;
585 #else
586 	bp = (u_char *)bcbp->b_addr;
587 #endif TAHOE
588 	for (mp = m; mp; mp = mp->m_next)
589 	{
590 		register unsigned len;
591 		u_char *mcp;
592 
593 		len = mp->m_len;
594 		if( len == 0 )
595 			continue;
596 		mcp = mtod( mp,u_char * );
597 		enpcopy( mcp,bp,len );
598 		bp += len;
599 		bcbp->b_len += len;
600 	}
601 	bcbp->b_len = max( MINPKTSIZE,bcbp->b_len );
602 	bcbp->b_reserved = 0;
603 	if ( ringput( &addr->enp_toenp,bcbp ) == 1 ) {
604 		host_intr++;
605 		INTR_ENP( addr );
606 	}
607 	m_freem(m);
608 	return( 0 );
609 }
610 
611 /*
612  * Routine to copy from Multibus memory into mbufs.
613  *
614  * Warning: This makes the fairly safe assumption that
615  * mbufs have even lengths.
616  */
617 struct mbuf *
618 enpget( bcbp, totlen, off0 )
619 register BCB *bcbp;
620 int totlen, off0;
621 {
622 	register struct mbuf *m;
623 	register int off = off0;
624 	register unsigned char *cp;
625 	long int	v;
626 	register short *vp = (short *)&v,
627 			*sp;
628 
629 	int len;
630 	struct mbuf *top = 0;
631 	struct mbuf **mp = &top;
632 
633 #ifdef TAHOE
634 	sp = (short *)&bcbp->b_addr;
635 	*vp = *sp; vp[1] = sp[1];
636 	cp = (unsigned char *)v + SIZEOF_ETHEADER;
637 #else
638 	cp = (unsigned char *)bcbp->b_addr + SIZEOF_ETHEADER;
639 #endif TAHOE
640 
641 	while( totlen > 0 )
642 	{
643 		u_char *mcp;
644 
645 		MGET(m, M_DONTWAIT, MT_DATA);
646 		if (m == 0)
647 			goto bad;
648 		if( off )
649 		{
650 			len = totlen - off;
651 #ifdef TAHOE
652 			sp = (short *)&bcbp->b_addr;
653 			*vp = *sp; vp[1] = sp[1];
654 			cp = (unsigned char *)v + SIZEOF_ETHEADER
655 				+ off;
656 #else
657 			cp = (unsigned char *)bcbp->b_addr +
658 				SIZEOF_ETHEADER + off;
659 #endif TAHOE
660 		}
661 		else
662 			len = totlen;
663 
664 
665 		if (len >= CLBYTES) {
666 			struct mbuf *p;
667 
668 			MCLGET(p, 1);
669 			if (p != 0) {
670 				m->m_len = len = CLBYTES;
671 				m->m_off = (int)p - (int)m;
672 			} else  {
673 				m->m_len = len = MIN(MLEN, len);
674 				m->m_off = MMINOFF;
675 				}
676 		} else  {
677 			m->m_len = len = MIN(MLEN, len);
678 			m->m_off = MMINOFF;
679 		}
680 
681 		mcp = mtod(m, u_char *);
682 		enpcopy(cp, mcp, len);
683 		cp += len;
684 		*mp = m;
685 		mp = &m->m_next;
686 		if (off == 0)
687 		{
688 			totlen -= len;
689 			continue;
690 		}
691 		off += len;
692 		if (off == totlen)
693 		{
694 #ifdef TAHOE
695 			sp = (short *)&bcbp->b_addr;
696 			*vp = *sp; vp[1] = sp[1];
697 			cp = (unsigned char *)v + SIZEOF_ETHEADER;
698 #else
699 			cp = (unsigned char *)bcbp->b_addr + SIZEOF_ETHEADER;
700 #endif TAHOE
701 			off = 0;
702 			totlen = off0;
703 		}
704 	}
705 	return (top);
706 bad:
707 	m_freem(top);
708 	return (0);
709 }
710 
711 /*
712  * Process an ioctl request.
713  *    this can be called via the "socket" route for SIOCSIFADDR or
714  *	by the cdev/inode route for SIOCSIFCCFWR/RD
715  *
716  */
717 
718 enpioctl(ifp, cmd, data)
719 register struct ifnet *ifp;
720 int cmd;
721 caddr_t data;
722 {
723 	register int	unit = ifp->if_unit;
724 	register struct vba_device *md;
725 	int s, error = 0;
726 	struct sockaddr_in	*sin;
727 	struct sockaddr		*sa;
728 	struct enp_softc	*es = &enp_softc[ifp->if_unit];
729 	ENPDEVICE		*addr;
730 	struct config_entry	*cf;
731 	struct ifreq *ifr	= (struct ifreq *)data;
732 	struct sockaddr_in	*et_addr;
733 	int code, i;
734 
735 
736 	if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0)
737 		return(ENODEV);
738 
739 	switch (cmd) {
740 
741 	case SIOCSIFADDR:
742 		s = splimp();
743 		sa = (struct sockaddr *)&ifr->ifr_addr;
744 		if (sa->sa_family == AF_UNSPEC ) {
745 			if (sa->sa_data[0] & 1){ /*broad or multi-cast*/
746 				splx( s );
747 				return( EINVAL );
748 			}
749 			bcopy(sa->sa_data,es->es_enaddr,sizeof(es->es_enaddr));
750 			enpinit( ifp->if_unit);
751 			break;
752 		}
753 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
754 		if (sin->sin_family != AF_INET){
755 			splx( s );
756 			return( EINVAL );
757 		}
758 		if (ifp->if_flags & IFF_RUNNING)
759 			if_rtinit(ifp, -1);     /* delete previous route */
760 		enpsetaddr(ifp, sin);
761 		enpinit(ifp->if_unit);
762 		enpgetaddr( ifp->if_unit );
763 		splx(s);
764 		break;
765 
766 
767 	case SIOCSETETADDR:	/* Set Ethernet station address */
768 		s = splimp();
769 		ifp->if_flags &= (~IFF_RUNNING | IFF_UP);
770 		et_addr = (struct sockaddr_in *)&ifr->ifr_addr;
771 		addr = (ENPDEVICE *)enpinfo[ifp->if_unit]->ui_addr;
772 
773 		/* Set station address and reset controller board */
774 		{
775 		u_char	*to = &addr->enp_addr.e_baseaddr.ea_addr[0];
776 		char	*from = &et_addr->sin_zero[2];
777 		int	i;
778 
779 		for (i = 0 ; i < ETHADDR_SIZE; i++)
780 			*to++ = (u_char) (~(*from++ & 0xff));
781 		}
782 		enpcopy(&addr->enp_addr.e_listsize, &code, sizeof(code));
783 		code |= E_ADDR_SUPP;
784 		enpcopy(&code, &addr->enp_addr.e_listsize, sizeof(code));
785 		enpreset(ifp->if_unit);		/* Re-initialize */
786 		enpgetaddr(ifp->if_unit);
787 		splx(s);
788 		break;
789 
790 	case SIOCGETETADDR:	/* Get Foreign Hosts' Ethernet addresses */
791 		arpwhohas(&es->es_ac, (struct in_addr *)ifr->ifr_data);
792 		break;
793 
794 	default:
795 		error = EINVAL;
796 	}
797 	return(error);
798 }
799 
800 enpsetaddr(ifp, sin)
801 register struct ifnet *ifp;
802 register struct sockaddr_in *sin;
803 {
804 
805 	ifp->if_addr = *(struct sockaddr *)sin;
806 	ifp->if_net = in_netof(sin->sin_addr);
807 	ifp->if_host[0] = in_lnaof(sin->sin_addr);
808 	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
809 	sin->sin_family = AF_INET;
810 	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
811 	ifp->if_flags |= IFF_BROADCAST;
812 }
813 
814 
815 /*
816  * Get the ethernet addr, store it and print it
817  * Read the ethernet address off the board, one byte at a time.
818  *	put it in enp_softc
819  */
820 
821 
822 enpgetaddr( unit )
823 int unit;
824 {
825 	register struct enp_softc	*es = &enp_softc[unit];
826 	register ENPDEVICE *addr =(ENPDEVICE *)enpinfo[unit]->ui_addr;
827 	int i;
828 
829 #ifdef TAHOE
830 	enpcopy(&addr->enp_addr.e_baseaddr, &es->es_boardaddr, sizeof(es->es_boardaddr));
831 #else
832 	es->es_boardaddr = addr->enp_addr.e_baseaddr;
833 #endif TAHOE
834 	bcopy(&es->es_boardaddr, es->es_enaddr, ETHADDR_SIZE);
835 	return( 1 );
836 }
837 
838 /*
839  * enpram device
840  *
841  */
842 
843 enpr_open( dev )
844 {
845 	register int	unit = minor(dev);
846 	register struct vba_device *md;
847 	register ENPDEVICE	*addr;
848 
849 	if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0 ||
850 	    (addr = (ENPDEVICE *)md->ui_addr) == (ENPDEVICE *)0)
851 		return(ENODEV);
852 	if (addr->enp_state != S_ENPRESET)
853 		return(EACCES);  /* enp is not in reset state, don't open  */
854 	if ( !enpismapped[unit] ) {
855 		ioaccess(ENPmap[unit],ENPmapa[unit],ENPBPTE);
856 		++enpismapped[unit];
857 	}
858 	enpram[unit] = ENP_OPEN;
859 	return( 0 );
860 }
861 
862 enpr_close(dev)
863 {
864 	enpram[minor(dev)] = ENP_CLOSE;
865 	return( 0 );
866 }
867 
868 enpr_read( dev,uio )
869 int dev;
870 register struct uio *uio;
871 {
872 	register ENPDEVICE *addr;
873 	register struct iovec *iov;
874 	register r=0;
875 
876 	if (enpram[minor(dev)] != ENP_OPEN)
877 		return(EACCES);
878 	if ( uio->uio_offset > RAM_SIZE )
879 		return( ENODEV );
880 	if ( uio->uio_offset + iov->iov_len > RAM_SIZE )
881 		iov->iov_len = RAM_SIZE - uio->uio_offset;
882 	addr = (ENPDEVICE *)enpinfo[ minor( dev ) ]->ui_addr;
883 	iov  = uio->uio_iov;
884 
885 	if( r = enpcopyout( &addr->enp_ram[ uio->uio_offset ], iov->iov_base,
886 			 iov->iov_len ) )
887 		 return( r );
888 
889 	uio->uio_resid -= iov->iov_len;
890 	iov->iov_len = 0;
891 
892 	return( 0 );
893 }
894 
895 enpr_write( dev,uio )
896 int dev;
897 register struct uio *uio;
898 {
899 	register ENPDEVICE *addr;
900 	register struct iovec *iov;
901 	register r=0;
902 
903 	if (enpram[minor(dev)] != ENP_OPEN)
904 		return(EACCES);
905 	addr = (ENPDEVICE *)enpinfo[ minor( dev ) ]->ui_addr;
906 	iov  = uio->uio_iov;
907 
908 	if ( uio->uio_offset > RAM_SIZE )
909 		return( ENODEV );
910 	if ( uio->uio_offset + iov->iov_len > RAM_SIZE )
911 		iov->iov_len = RAM_SIZE - uio->uio_offset;
912 	if( r = enpcopyin( iov->iov_base, &addr->enp_ram[ uio->uio_offset ],
913 			iov->iov_len ) )
914 		return( r );
915 
916 	uio->uio_resid -= iov->iov_len;
917 	iov->iov_len = 0;
918 
919 	return( 0 );
920 }
921 
922 enpr_ioctl( dev,cmd,arg,fflag )
923 dev_t dev;
924 caddr_t *arg;
925 {
926 	register ENPDEVICE *addr;
927 	long int	v;
928 	register short	*vp = (short *)&v, *sp;
929 	register unit = minor(dev);
930 	register struct vba_device *md;
931 
932 	if (unit >= NENP || (md = enpinfo[unit]) == 0 || md->ui_alive == 0 ||
933 	    (addr = (ENPDEVICE *)md->ui_addr) == (ENPDEVICE *)0)
934 		return(ENODEV);
935 	switch( cmd )
936 	{
937 		case ENPIOGO:
938 /* not needed if prom based version */
939 #ifdef TAHOE
940 			sp = (short *)&addr->enp_base;
941 			v = (int)addr;
942 			*sp = *vp; sp[1] = vp[1];
943 #else
944 			addr->enp_base = (int)addr;
945 #endif TAHOE
946 			addr->enp_intrvec = intvec[ unit ];
947 			ENP_GO( addr, ENPSTART );
948 			DELAY( 200000 );
949 			enpattach( enpinfo[ unit ] );
950 			enpinit( unit );
951 			addr->enp_state = S_ENPRUN;  /* it is running now */
952 /* end of not needed */
953 
954 			break;
955 
956 		case ENPIORESET:
957 			RESET_ENP( addr );
958 			addr->enp_state = S_ENPRESET;  /* it is reset now */
959 			DELAY( 100000 );
960 			break;
961 	}
962 	return( 0 );
963 }
964 
965 /*
966  * routines to synchronize enp and host
967  */
968 
969 static
970 ringinit( rp,size )
971 register RING *rp;
972 {
973 	register int	i;
974 	register short *sp;
975 
976 	rp->r_rdidx = rp->r_wrtidx = 0;
977 	rp->r_size = size;
978 }
979 
980 static
981 ringempty( rp )
982 register RING *rp;
983 {
984 	return( rp->r_rdidx == rp->r_wrtidx );
985 }
986 
987 static
988 ringfull( rp )
989 register RING *rp;
990 {
991 	register short idx;
992 
993 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
994 	return( idx == rp->r_rdidx );
995 }
996 
997 static
998 ringput( rp,v )
999 register RING *rp;
1000 {
1001 	register int idx;
1002 	register short *vp = (short *)&v,
1003 		       *sp;
1004 
1005 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
1006 	if( idx != rp->r_rdidx )
1007 	{
1008 #ifdef TAHOE
1009 		sp = (short *)&rp->r_slot[ rp->r_wrtidx ];
1010 		*sp = *vp; sp[1] = vp[1];
1011 #else
1012 		rp->r_slot[ rp->r_wrtidx ] = v;
1013 #endif TAHOE
1014 		rp->r_wrtidx = idx;
1015 		if( (idx -= rp->r_rdidx) < 0 )
1016 			idx += rp->r_size;
1017 		return( idx );			/* num ring entries */
1018 	}
1019 	return( 0 );
1020 }
1021 
1022 static
1023 ringget( rp )
1024 register RING *rp;
1025 {
1026 	register int i = 0;
1027 	long int v;
1028 	register short *vp = (short *)&v,
1029 		       *sp;
1030 
1031 	if( rp->r_rdidx != rp->r_wrtidx )
1032 	{
1033 #ifdef TAHOE
1034 		sp = (short *)&rp->r_slot[ rp->r_rdidx ];
1035 		*vp = *sp; vp[1] = sp[1];
1036 		i = v;
1037 #else
1038 		i = rp->r_slot[ rp->r_rdidx ];
1039 #endif TAHOE
1040 		rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
1041 	}
1042 	return( i );
1043 }
1044 
1045 #ifdef notdef
1046 struct mbuf *
1047 m_tofree( rp )
1048 register RING *rp;
1049 {
1050 	long int v = 0;
1051 	register short *vp = (short *)&v,
1052 		       *sp;
1053 
1054 	if( rp->r_rdidx != rp->r_wrtidx )
1055 	{
1056 #ifdef TAHOE
1057 		sp = (short *)&rp->r_slot[ rp->r_rdidx ];
1058 		*vp = *sp; vp[1] = sp[1];
1059 		/* *sp = 0xffff; sp[1] = 0xffff; */
1060 #else
1061 		v = rp->r_slot[ rp->r_rdidx ];
1062 #endif TAHOE
1063 	  	rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
1064 	}
1065 	return( (struct mbuf *)v );
1066 }
1067 #endif
1068 static
1069 fir( rp )
1070 register RING *rp;
1071 {
1072 	long int v;
1073 	register short *vp = (short *)&v,
1074 		       *sp;
1075 
1076 	if( rp->r_rdidx != rp->r_wrtidx )
1077 #ifdef TAHOE
1078 	{
1079 		sp = (short *)&rp->r_slot[ rp->r_rdidx ];
1080 		*vp = *sp; vp[1] = sp[1];
1081 		return( v );
1082 	}
1083 #else
1084 		return( rp->r_slot[ rp->r_rdidx ] );
1085 #endif TAHOE
1086 	else
1087 		return( 0 );
1088 }
1089 
1090 
1091 static
1092 prtbytes( addr )
1093 register char *addr;
1094 {
1095 	register int i;
1096 
1097 	for( i = 0; i < 12; i++ )
1098 	{
1099 		printf("%X ",*addr&0377);
1100 		addr++;
1101 	}
1102 	printf("\n");
1103 }
1104 
1105 static
1106 enpcopy(from, to, cnt)
1107 register char *from, *to;
1108 register cnt;
1109 {
1110 	register c;
1111 	register short *f, *t;
1112 
1113 	if (((int)from & 01) && ((int)to & 01)) {
1114 					/* source & dest at odd addresses */
1115 		*to++ = *from++;
1116 		--cnt;
1117 	}
1118 	if (cnt > 1 && (((int)to & 01)==0) && (((int)from & 01)==0)) {
1119 		t = (short *) to;
1120 		f = (short *) from;
1121 		for( c = cnt>>1; c; --c)	/* even address copy */
1122 			*t++ = *f++;
1123 		cnt &= 1;
1124 		if ( cnt ) {			/* odd len */
1125 			from = (char *) f;
1126 			to   = (char *) t;
1127 			*to = *from;
1128 		}
1129 	}
1130 	while (cnt-- > 0)	/* one of the address(es) must be odd */
1131 		*to++ = *from++;
1132 
1133 }
1134 
1135 static
1136 enpcopyin(userv, kernv, cnt)
1137 {
1138 
1139 	if (useracc(userv, cnt, 1)) {
1140 		enpcopy( userv, kernv, cnt );
1141 		return( 0 );
1142 	}
1143 	else	return( EFAULT );
1144 }
1145 
1146 
1147 static
1148 enpcopyout(kernv, userv, cnt)
1149 {
1150 
1151 	if (useracc(userv, cnt, 0)) {
1152 		enpcopy( kernv, userv, cnt );
1153 		return( 0 );
1154 	}
1155 	else	return( EFAULT );
1156 }
1157 #endif
1158