xref: /csrg-svn/sys/tahoe/if/if_enp.c (revision 30230)
1*30230Ssam /*	if_enp.c	1.2	86/11/29	*/
229649Ssam 
329649Ssam #include "enp.h"
429649Ssam #if NENP > 0
529649Ssam /*
6*30230Ssam  * Modified 3Com Ethernet Controller interface
729649Ssam  * enp modifications added S. F. Holmgren
8*30230Ssam  *
9*30230Ssam  * UNTESTED WITH 4.3
1029649Ssam  */
1129649Ssam #include "param.h"
1229649Ssam #include "systm.h"
1329649Ssam #include "mbuf.h"
1429649Ssam #include "buf.h"
1529649Ssam #include "protosw.h"
1629649Ssam #include "socket.h"
1729649Ssam #include "vmmac.h"
18*30230Ssam #include "ioctl.h"
1929649Ssam #include "errno.h"
20*30230Ssam #include "vmparam.h"
21*30230Ssam #include "syslog.h"
2229649Ssam #include "uio.h"
2329649Ssam 
2429649Ssam #include "../net/if.h"
2529649Ssam #include "../net/netisr.h"
2629649Ssam #include "../net/route.h"
27*30230Ssam #ifdef INET
2829649Ssam #include "../netinet/in.h"
2929649Ssam #include "../netinet/in_systm.h"
30*30230Ssam #include "../netinet/in_var.h"
3129649Ssam #include "../netinet/ip.h"
3229649Ssam #include "../netinet/ip_var.h"
3329649Ssam #include "../netinet/if_ether.h"
34*30230Ssam #endif
35*30230Ssam #ifdef NS
36*30230Ssam #include "../netns/ns.h"
37*30230Ssam #include "../netns/ns_if.h"
38*30230Ssam #endif
3929649Ssam 
40*30230Ssam #include "../tahoe/cpu.h"
41*30230Ssam #include "../tahoe/pte.h"
42*30230Ssam #include "../tahoe/mtpr.h"
43*30230Ssam 
4429649Ssam #include "../tahoevba/vbavar.h"
45*30230Ssam #include "../tahoeif/if_enpreg.h"
4629649Ssam 
47*30230Ssam #define	ENPVEC	0xc1
48*30230Ssam #define ENPSTART	0xf02000	/* standard enp start addr */
49*30230Ssam #define	ENPUNIT(dev)	(minor(dev))	/* for enp ram devices */
5029649Ssam 
5129649Ssam int	enpprobe(), enpattach(), enpintr();
52*30230Ssam long	enpstd[] = { 0xf41000, 0xf61000, 0 };
53*30230Ssam struct  vba_device *enpinfo[NENP];
5429649Ssam struct  vba_driver enpdriver =
55*30230Ssam     { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 };
5629649Ssam 
57*30230Ssam int	enpinit(), enpioctl(), enpreset(), enpoutput();
5829649Ssam struct  mbuf *enpget();
5929649Ssam 
6029649Ssam /*
6129649Ssam  * Ethernet software status per interface.
6229649Ssam  *
6329649Ssam  * Each interface is referenced by a network interface structure,
6429649Ssam  * es_if, which the routing code uses to locate the interface.
6529649Ssam  * This structure contains the output queue for the interface, its address, ...
6629649Ssam  */
67*30230Ssam struct  enp_softc {
68*30230Ssam 	struct  arpcom es_ac;           /* common ethernet structures */
69*30230Ssam #define es_if		es_ac.ac_if
70*30230Ssam #define es_enaddr	es_ac.ac_enaddr
71*30230Ssam 	short	es_flags;		/* flags for devices */
72*30230Ssam 	short	es_ivec;		/* interrupt vector */
73*30230Ssam 	struct	pte *es_map;		/* map for dual ported memory */
74*30230Ssam 	caddr_t	es_ram;			/* virtual address of mapped memory */
75*30230Ssam } enp_softc[NENP];
76*30230Ssam extern	struct ifnet loif;
7729649Ssam 
78*30230Ssam enpprobe(reg, vi)
79*30230Ssam 	caddr_t reg;
80*30230Ssam 	struct vba_device *vi;
8129649Ssam {
82*30230Ssam 	register br, cvec;		/* must be r12, r11 */
83*30230Ssam 	register struct enpdevice *addr = (struct enpdevice *)reg;
84*30230Ssam 	struct enp_softc *es = &enp_softc[vi->ui_unit];
8529649Ssam 
86*30230Ssam #ifdef lint
87*30230Ssam 	enpintr(0);
88*30230Ssam #endif
89*30230Ssam 	if (badaddr(addr, 2) || badaddr(&addr->enp_ram[0], 2))
90*30230Ssam 		return (0);
91*30230Ssam 	es->es_ivec = --vi->ui_hd->vh_lastiv;
92*30230Ssam 	addr->enp_state = S_ENPRESET;		/* reset by VERSAbus reset */
93*30230Ssam 	br = 0x14, cvec = es->es_ivec;		/* XXX */
94*30230Ssam 	return (sizeof (struct enpdevice));
9529649Ssam }
9629649Ssam 
9729649Ssam /*
9829649Ssam  * Interface exists: make available by filling in network interface
9929649Ssam  * record.  System will initialize the interface when it is ready
10029649Ssam  * to accept packets.
10129649Ssam  */
102*30230Ssam enpattach(ui)
103*30230Ssam 	register struct vba_device *ui;
10429649Ssam {
105*30230Ssam 	struct enp_softc *es = &enp_softc[ui->ui_unit];
106*30230Ssam 	register struct ifnet *ifp = &es->es_if;
107*30230Ssam 	register struct enpdevice *addr = (struct enpdevice *)ui->ui_addr;
10829649Ssam 
109*30230Ssam 	ifp->if_unit = ui->ui_unit;
11029649Ssam 	ifp->if_name = "enp";
11129649Ssam 	ifp->if_mtu = ETHERMTU;
112*30230Ssam 	/*
113*30230Ssam 	 * Get station's addresses.
114*30230Ssam 	 */
115*30230Ssam 	enpcopy(&addr->enp_addr.e_baseaddr, es->es_enaddr,
116*30230Ssam 	    sizeof (es->es_enaddr));
117*30230Ssam 	printf("enp%d: hardware address %s\n", ui->ui_unit,
118*30230Ssam 	    ether_sprintf(es->es_enaddr));
119*30230Ssam 	/*
120*30230Ssam 	 * Allocate and map ram.
121*30230Ssam 	 */
122*30230Ssam 	vbmemalloc(128, ((caddr_t)addr)+0x1000, &es->es_map, &es->es_ram);
12329649Ssam 
12429649Ssam 	ifp->if_init = enpinit;
12529649Ssam 	ifp->if_ioctl = enpioctl;
12629649Ssam 	ifp->if_output = enpoutput;
12729649Ssam 	ifp->if_reset = enpreset;
128*30230Ssam 	ifp->if_flags = IFF_BROADCAST;
12929649Ssam 	if_attach(ifp);
13029649Ssam }
13129649Ssam 
13229649Ssam /*
133*30230Ssam  * Reset of interface after "system" reset.
13429649Ssam  */
135*30230Ssam enpreset(unit, vban)
136*30230Ssam 	int unit, vban;
13729649Ssam {
138*30230Ssam 	register struct vba_device *ui;
13929649Ssam 
140*30230Ssam 	if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
141*30230Ssam 	    ui->ui_vbanum != vban)
142*30230Ssam 		return;
143*30230Ssam 	printf(" enp%d", unit);
14429649Ssam 	enpinit(unit);
14529649Ssam }
14629649Ssam 
14729649Ssam /*
148*30230Ssam  * Initialization of interface; clear recorded pending operations.
14929649Ssam  */
150*30230Ssam enpinit(unit)
151*30230Ssam 	int unit;
15229649Ssam {
153*30230Ssam 	struct enp_softc *es = &enp_softc[unit];
154*30230Ssam 	register struct vba_device *ui = enpinfo[unit];
155*30230Ssam 	struct enpdevice *addr;
156*30230Ssam 	register struct ifnet *ifp = &es->es_if;
157*30230Ssam 	int s;
15829649Ssam 
159*30230Ssam 	if (ifp->if_addrlist == (struct ifaddr *)0)
160*30230Ssam 		return;
161*30230Ssam 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
162*30230Ssam 		addr = (struct enpdevice *)ui->ui_addr;
163*30230Ssam 		s = splimp();
164*30230Ssam 		RESET_ENP(addr);
165*30230Ssam 		DELAY(200000);
166*30230Ssam 		addr->enp_intrvec = es->es_ivec;
167*30230Ssam 		es->es_if.if_flags |= IFF_RUNNING;
168*30230Ssam 		splx(s);
16929649Ssam 	}
17029649Ssam }
17129649Ssam 
17229649Ssam /*
17329649Ssam  * Ethernet interface interrupt.
17429649Ssam  */
175*30230Ssam enpintr(unit)
176*30230Ssam 	int unit;
17729649Ssam {
178*30230Ssam 	register struct enpdevice *addr;
179*30230Ssam 	register BCB *bcbp;
18029649Ssam 
181*30230Ssam 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
182*30230Ssam 	if (!IS_ENP_INTR(addr))
18329649Ssam 		return;
184*30230Ssam 	ACK_ENP_INTR(addr);
185*30230Ssam 	while ((bcbp = (BCB *)ringget(&addr->enp_tohost )) != 0) {
186*30230Ssam 		(void) enpread(&enp_softc[unit], bcbp, unit);
187*30230Ssam 		ringput(&addr->enp_enpfree, bcbp);
18829649Ssam 	}
18929649Ssam }
19029649Ssam 
19129649Ssam /*
19229649Ssam  * Read input packet, examine its packet type, and enqueue it.
19329649Ssam  */
194*30230Ssam enpread(es, bcbp, unit)
195*30230Ssam 	struct enp_softc *es;
196*30230Ssam 	register BCB *bcbp;
197*30230Ssam 	int unit;
19829649Ssam {
19929649Ssam 	register struct ether_header *enp;
20029649Ssam 	struct mbuf *m;
201*30230Ssam 	long int s;
20229649Ssam 	int len, off, resid, enptype;
20329649Ssam 	register struct ifqueue *inq;
20429649Ssam 
20529649Ssam 	es->es_if.if_ipackets++;
20629649Ssam 	/*
20729649Ssam 	 * Get input data length.
20829649Ssam 	 * Get pointer to ethernet header (in input buffer).
20929649Ssam 	 * Deal with trailer protocol: if type is PUP trailer
21029649Ssam 	 * get true type from first 16-bit word past data.
21129649Ssam 	 * Remember that type was trailer by setting off.
21229649Ssam 	 */
213*30230Ssam 	len = bcbp->b_msglen - sizeof (struct ether_header);
21429649Ssam 	enp = (struct ether_header *)bcbp->b_addr;
215*30230Ssam #define enpdataaddr(enp, off, type) \
216*30230Ssam     ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off))))
217*30230Ssam 	enp->ether_type = ntohs((u_short)enp->ether_type);
218*30230Ssam 	if (enp->ether_type >= ETHERTYPE_TRAIL &&
219*30230Ssam 	    enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
220*30230Ssam 		off = (enp->ether_type - ETHERTYPE_TRAIL) * 512;
221*30230Ssam 		if (off >= ETHERMTU)
222*30230Ssam 			goto setup;
223*30230Ssam 		enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *));
224*30230Ssam 		resid = ntohs(*(enpdataaddr(enp, off+2, u_short *)));
225*30230Ssam 		if (off + resid > len)
226*30230Ssam 			goto setup;
22729649Ssam 		len = off + resid;
228*30230Ssam 	} else
22929649Ssam 		off = 0;
230*30230Ssam 	if (len == 0)
231*30230Ssam 		goto setup;
23229649Ssam 
23329649Ssam 	/*
23429649Ssam 	 * Pull packet off interface.  Off is nonzero if packet
23529649Ssam 	 * has trailing header; enpget will then force this header
23629649Ssam 	 * information to be at the front, but we still have to drop
23729649Ssam 	 * the type and length which are at the front of any trailer data.
23829649Ssam 	 */
239*30230Ssam 	m = enpget(bcbp->b_addr, len, off, &es->es_if);
240*30230Ssam 	if (m == 0)
241*30230Ssam 		goto setup;
242*30230Ssam 	if (off) {
243*30230Ssam 		struct ifnet *ifp;
24429649Ssam 
245*30230Ssam 		ifp = *(mtod(m, struct ifnet **));
24629649Ssam 		m->m_off += 2 * sizeof (u_short);
24729649Ssam 		m->m_len -= 2 * sizeof (u_short);
248*30230Ssam 		*(mtod(m, struct ifnet **)) = ifp;
24929649Ssam 	}
250*30230Ssam 	switch (enp->ether_type) {
25129649Ssam 
25229649Ssam #ifdef INET
253*30230Ssam 	case ETHERTYPE_IP:
25429649Ssam 		schednetisr(NETISR_IP);
25529649Ssam 		inq = &ipintrq;
25629649Ssam 		break;
257*30230Ssam #endif
258*30230Ssam 	case ETHERTYPE_ARP:
259*30230Ssam 		arpinput(&es->es_ac, m);
260*30230Ssam 		goto setup;
26129649Ssam 
262*30230Ssam #ifdef NS
263*30230Ssam 	case ETHERTYPE_NS:
264*30230Ssam 		schednetisr(NETISR_NS);
265*30230Ssam 		inq = &nsintrq;
266*30230Ssam 		break;
26729649Ssam #endif
268*30230Ssam 	default:
26929649Ssam 		m_freem(m);
270*30230Ssam 		goto setup;
27129649Ssam 	}
272*30230Ssam 	if (IF_QFULL(inq)) {
27329649Ssam 		IF_DROP(inq);
27429649Ssam 		m_freem(m);
275*30230Ssam 		goto setup;
27629649Ssam 	}
27729649Ssam 	s = splimp();
27829649Ssam 	IF_ENQUEUE(inq, m);
27929649Ssam 	splx(s);
280*30230Ssam setup:
281*30230Ssam 	return (0);
28229649Ssam }
28329649Ssam 
28429649Ssam /*
28529649Ssam  * Ethernet output routine. (called by user)
28629649Ssam  * Encapsulate a packet of type family for the local net.
28729649Ssam  * Use trailer local net encapsulation if enough data in first
28829649Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
28929649Ssam  * If destination is this address or broadcast, send packet to
29029649Ssam  * loop device to kludge around the fact that 3com interfaces can't
29129649Ssam  * talk to themselves.
29229649Ssam  */
29329649Ssam enpoutput(ifp, m0, dst)
294*30230Ssam 	struct ifnet *ifp;
295*30230Ssam 	struct mbuf *m0;
296*30230Ssam 	struct sockaddr *dst;
29729649Ssam {
29829649Ssam 	register struct enp_softc *es = &enp_softc[ifp->if_unit];
29929649Ssam 	register struct mbuf *m = m0;
30029649Ssam 	register struct ether_header *enp;
30129649Ssam 	register int off, i;
302*30230Ssam 	struct mbuf *mcopy = (struct mbuf *)0;
303*30230Ssam 	int type, s, error, usetrailers;
304*30230Ssam 	u_char edst[6];
305*30230Ssam 	struct in_addr idst;
30629649Ssam 
307*30230Ssam 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
308*30230Ssam 		error = ENETDOWN;
309*30230Ssam 		goto bad;
310*30230Ssam 	}
311*30230Ssam 	switch (dst->sa_family) {
31229649Ssam #ifdef INET
31329649Ssam 	case AF_INET:
31429649Ssam 		idst = ((struct sockaddr_in *)dst)->sin_addr;
315*30230Ssam 		if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers))
316*30230Ssam 			return (0);	/* if not yet resolved */
317*30230Ssam 		if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
318*30230Ssam 		    sizeof (edst)))
319*30230Ssam 			mcopy = m_copy(m, 0, (int)M_COPYALL);
320*30230Ssam 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
321*30230Ssam 		if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
322*30230Ssam 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
323*30230Ssam 			type = ETHERTYPE_TRAIL + (off>>9);
324*30230Ssam 			m->m_off -= 2 * sizeof (u_short);
325*30230Ssam 			m->m_len += 2 * sizeof (u_short);
326*30230Ssam 			*mtod(m, u_short *) = ETHERTYPE_IP;
327*30230Ssam 			*(mtod(m, u_short *) + 1) = m->m_len;
328*30230Ssam 			goto gottrailertype;
32929649Ssam 		}
330*30230Ssam 		type = ETHERTYPE_IP;
33129649Ssam 		off = 0;
33229649Ssam 		goto gottype;
33329649Ssam #endif
334*30230Ssam #ifdef NS
335*30230Ssam 	case AF_NS:
336*30230Ssam 		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
337*30230Ssam 		    (caddr_t)edst, sizeof (edst));
338*30230Ssam 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst)))
339*30230Ssam 			mcopy = m_copy(m, 0, (int)M_COPYALL);
340*30230Ssam 		else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
341*30230Ssam 		    sizeof (edst)))
342*30230Ssam 			return (looutput(&loif, m, dst));
343*30230Ssam 		type = ETHERTYPE_NS;
344*30230Ssam 		off = 0;
345*30230Ssam 		goto gottype;
34629649Ssam #endif
34729649Ssam 	case AF_UNSPEC:
34829649Ssam 		enp = (struct ether_header *)dst->sa_data;
349*30230Ssam 		bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst));
35029649Ssam 		type = enp->ether_type;
35129649Ssam 		goto gottype;
35229649Ssam 
35329649Ssam 	default:
354*30230Ssam 		log(LOG_ERR, "enp%d: can't handle af%d\n",
355*30230Ssam 		    ifp->if_unit, dst->sa_family);
35629649Ssam 		error = EAFNOSUPPORT;
35729649Ssam 		goto bad;
35829649Ssam 	}
35929649Ssam 
36029649Ssam gottrailertype:
36129649Ssam 	/*
36229649Ssam 	 * Packet to be sent as trailer: move first packet
36329649Ssam 	 * (control information) to end of chain.
36429649Ssam 	 */
36529649Ssam 	while (m->m_next)
36629649Ssam 		m = m->m_next;
36729649Ssam 	m->m_next = m0;
36829649Ssam 	m = m0->m_next;
36929649Ssam 	m0->m_next = 0;
37029649Ssam 	m0 = m;
37129649Ssam 
37229649Ssam gottype:
37329649Ssam 	/*
37429649Ssam          * Add local net header.  If no space in first mbuf,
37529649Ssam          * allocate another.
37629649Ssam          */
37729649Ssam 	if (m->m_off > MMAXOFF ||
378*30230Ssam 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
37929649Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
380*30230Ssam 		if (m == 0) {
38129649Ssam 			error = ENOBUFS;
38229649Ssam 			goto bad;
38329649Ssam 		}
38429649Ssam 		m->m_next = m0;
38529649Ssam 		m->m_off = MMINOFF;
386*30230Ssam 		m->m_len = sizeof (struct ether_header);
387*30230Ssam 	} else {
388*30230Ssam 		m->m_off -= sizeof (struct ether_header);
389*30230Ssam 		m->m_len += sizeof (struct ether_header);
39029649Ssam 	}
39129649Ssam 	enp = mtod(m, struct ether_header *);
392*30230Ssam 	bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst));
393*30230Ssam 	bcopy((caddr_t)es->es_enaddr, (caddr_t)enp->ether_shost,
394*30230Ssam 	    sizeof (es->es_enaddr));
395*30230Ssam 	enp->ether_type = htons((u_short)type);
39629649Ssam 
39729649Ssam 	/*
39829649Ssam 	 * Queue message on interface if possible
39929649Ssam 	 */
40029649Ssam 	s = splimp();
401*30230Ssam 	if (enpput(ifp->if_unit, m)) {
40229649Ssam 		error = ENOBUFS;
40329649Ssam 		goto qfull;
40429649Ssam 	}
405*30230Ssam 	splx(s);
40629649Ssam 	es->es_if.if_opackets++;
407*30230Ssam 	return (mcopy ? looutput(&loif, mcopy, dst) : 0);
40829649Ssam qfull:
409*30230Ssam 	splx(s);
41029649Ssam 	m0 = m;
41129649Ssam bad:
41229649Ssam 	m_freem(m0);
413*30230Ssam 	if (mcopy)
414*30230Ssam 		m_freem(mcopy);
415*30230Ssam 	return (error);
41629649Ssam }
41729649Ssam 
41829649Ssam /*
419*30230Ssam  * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
42029649Ssam  */
421*30230Ssam enpput(unit, m)
422*30230Ssam 	int unit;
423*30230Ssam 	struct mbuf *m;
42429649Ssam {
42529649Ssam 	register BCB *bcbp;
426*30230Ssam 	register struct enpdevice *addr;
42729649Ssam 	register struct mbuf *mp;
42829649Ssam 	register u_char *bp;
429*30230Ssam 	register u_int len;
430*30230Ssam 	u_char *mcp;
43129649Ssam 
432*30230Ssam 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
433*30230Ssam 	if (ringempty(&addr->enp_hostfree))
434*30230Ssam 		return (1);
435*30230Ssam 	bcbp = (BCB *)ringget(&addr->enp_hostfree);
43629649Ssam 	bcbp->b_len = 0;
43729649Ssam 	bp = (u_char *)bcbp->b_addr;
438*30230Ssam 	for (mp = m; mp; mp = mp->m_next) {
43929649Ssam 		len = mp->m_len;
440*30230Ssam 		if (len == 0)
44129649Ssam 			continue;
442*30230Ssam 		mcp = mtod(mp, u_char *);
443*30230Ssam 		enpcopy(mcp, bp, len);
44429649Ssam 		bp += len;
44529649Ssam 		bcbp->b_len += len;
44629649Ssam 	}
447*30230Ssam 	bcbp->b_len = max(ETHERMIN, bcbp->b_len);
44829649Ssam 	bcbp->b_reserved = 0;
449*30230Ssam 	if (ringput(&addr->enp_toenp, bcbp) == 1)
450*30230Ssam 		INTR_ENP(addr);
45129649Ssam 	m_freem(m);
452*30230Ssam 	return (0);
45329649Ssam }
45429649Ssam 
45529649Ssam /*
456*30230Ssam  * Routine to copy from VERSAbus memory into mbufs.
45729649Ssam  *
45829649Ssam  * Warning: This makes the fairly safe assumption that
45929649Ssam  * mbufs have even lengths.
46029649Ssam  */
46129649Ssam struct mbuf *
462*30230Ssam enpget(rxbuf, totlen, off0, ifp)
463*30230Ssam 	u_char *rxbuf;
464*30230Ssam 	int totlen, off0;
465*30230Ssam 	struct ifnet *ifp;
46629649Ssam {
467*30230Ssam 	register u_char *cp, *mcp;
46829649Ssam 	register struct mbuf *m;
469*30230Ssam 	struct mbuf *top = 0, **mp = &top;
470*30230Ssam 	int len, off = off0;
47129649Ssam 
472*30230Ssam 	cp = rxbuf + sizeof (struct ether_header);
473*30230Ssam 	while (totlen > 0) {
47429649Ssam 		MGET(m, M_DONTWAIT, MT_DATA);
47529649Ssam 		if (m == 0)
47629649Ssam 			goto bad;
477*30230Ssam 		if (off) {
47829649Ssam 			len = totlen - off;
479*30230Ssam 			cp = rxbuf + sizeof (struct ether_header) + off;
480*30230Ssam 		} else
48129649Ssam 			len = totlen;
482*30230Ssam 		if (len >= NBPG) {
48329649Ssam 			struct mbuf *p;
48429649Ssam 
485*30230Ssam 			MCLGET(m);
486*30230Ssam 			if (m->m_len == CLBYTES)
487*30230Ssam 				m->m_len = len = MIN(len, CLBYTES);
488*30230Ssam 			else
48929649Ssam 				m->m_len = len = MIN(MLEN, len);
490*30230Ssam 		} else {
49129649Ssam 			m->m_len = len = MIN(MLEN, len);
49229649Ssam 			m->m_off = MMINOFF;
49329649Ssam 		}
49429649Ssam 		mcp = mtod(m, u_char *);
495*30230Ssam 		if (ifp) {
496*30230Ssam 			/*
497*30230Ssam 			 * Prepend interface pointer to first mbuf.
498*30230Ssam 			 */
499*30230Ssam 			*(mtod(m, struct ifnet **)) = ifp;
500*30230Ssam 			mcp += sizeof (ifp);
501*30230Ssam 			len -= sizeof (ifp);
502*30230Ssam 			ifp = (struct ifnet *)0;
503*30230Ssam 		}
50429649Ssam 		enpcopy(cp, mcp, len);
50529649Ssam 		cp += len;
50629649Ssam 		*mp = m;
50729649Ssam 		mp = &m->m_next;
508*30230Ssam 		if (off == 0) {
50929649Ssam 			totlen -= len;
51029649Ssam 			continue;
51129649Ssam 		}
51229649Ssam 		off += len;
513*30230Ssam 		if (off == totlen) {
514*30230Ssam 			cp = rxbuf + sizeof (struct ether_header);
51529649Ssam 			off = 0;
51629649Ssam 			totlen = off0;
51729649Ssam 		}
51829649Ssam 	}
51929649Ssam 	return (top);
52029649Ssam bad:
52129649Ssam 	m_freem(top);
52229649Ssam 	return (0);
52329649Ssam }
52429649Ssam 
525*30230Ssam enpcopy(from, to, cnt)
526*30230Ssam 	register char *from, *to;
527*30230Ssam 	register cnt;
528*30230Ssam {
529*30230Ssam 	register c;
530*30230Ssam 	register short *f, *t;
531*30230Ssam 
532*30230Ssam 	if (((int)from&01) && ((int)to&01)) {
533*30230Ssam 		/* source & dest at odd addresses */
534*30230Ssam 		*to++ = *from++;
535*30230Ssam 		--cnt;
536*30230Ssam 	}
537*30230Ssam 	if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) {
538*30230Ssam 		t = (short *)to;
539*30230Ssam 		f = (short *)from;
540*30230Ssam 		for (c = cnt>>1; c; --c)	/* even address copy */
541*30230Ssam 			*t++ = *f++;
542*30230Ssam 		cnt &= 1;
543*30230Ssam 		if (cnt) {			/* odd len */
544*30230Ssam 			from = (char *)f;
545*30230Ssam 			to = (char *)t;
546*30230Ssam 			*to = *from;
547*30230Ssam 		}
548*30230Ssam 	}
549*30230Ssam 	while (cnt-- > 0)	/* one of the address(es) must be odd */
550*30230Ssam 		*to++ = *from++;
551*30230Ssam }
552*30230Ssam 
55329649Ssam /*
55429649Ssam  * Process an ioctl request.
55529649Ssam  */
55629649Ssam enpioctl(ifp, cmd, data)
557*30230Ssam 	register struct ifnet *ifp;
558*30230Ssam 	int cmd;
559*30230Ssam 	caddr_t data;
56029649Ssam {
561*30230Ssam 	register struct ifaddr *ifa = (struct ifaddr *)data;
562*30230Ssam 	struct enpdevice *addr;
563*30230Ssam 	int s = splimp(), error = 0;
56429649Ssam 
56529649Ssam 	switch (cmd) {
56629649Ssam 
56729649Ssam 	case SIOCSIFADDR:
568*30230Ssam 		ifp->if_flags |= IFF_UP;
569*30230Ssam 		switch (ifa->ifa_addr.sa_family) {
570*30230Ssam #ifdef INET
571*30230Ssam 		case AF_INET:
572*30230Ssam 			enpinit(ifp->if_unit);
573*30230Ssam 			((struct arpcom *)ifp)->ac_ipaddr =
574*30230Ssam 			    IA_SIN(ifa)->sin_addr;
575*30230Ssam 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
57629649Ssam 			break;
577*30230Ssam #endif
578*30230Ssam #ifdef NS
579*30230Ssam 		case AF_NS: {
580*30230Ssam 			struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
581*30230Ssam 			struct enp_softc *es = &enp_softc[ifp->if_unit];
582*30230Ssam 
583*30230Ssam 			if (!ns_nullhost(*ina)) {
584*30230Ssam 				ifp->if_flags &= ~IFF_RUNNING;
585*30230Ssam 				addr = (struct enpdevice *)
586*30230Ssam 				    enpinfo[ifp->if_unit]->ui_addr;
587*30230Ssam 				enpsetaddr(ifp->if_unit, addr,
588*30230Ssam 				    ina->x_host.c_host);
589*30230Ssam 			} else
590*30230Ssam 				ina->x_host = *(union ns_host *)es->es_enaddr;
591*30230Ssam 			enpinit(ifp->if_unit);
592*30230Ssam 			break;
59329649Ssam 		}
594*30230Ssam #endif
595*30230Ssam 		default:
596*30230Ssam 			enpinit(ifp->if_unit);
597*30230Ssam 			break;
59829649Ssam 		}
59929649Ssam 		break;
60029649Ssam 
601*30230Ssam 	case SIOCSIFFLAGS:
602*30230Ssam 		if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
603*30230Ssam 			enpinit(ifp->if_unit);		/* reset board */
604*30230Ssam 			ifp->if_flags &= ~IFF_RUNNING;
605*30230Ssam 		} else if (ifp->if_flags&IFF_UP &&
606*30230Ssam 		     (ifp->if_flags&IFF_RUNNING) == 0)
607*30230Ssam 			enpinit(ifp->if_unit);
60829649Ssam 		break;
60929649Ssam 
61029649Ssam 	default:
61129649Ssam 		error = EINVAL;
61229649Ssam 	}
613*30230Ssam 	splx(s);
614*30230Ssam 	return (error);
61529649Ssam }
61629649Ssam 
617*30230Ssam enpsetaddr(unit, addr, enaddr)
618*30230Ssam 	int unit;
619*30230Ssam 	struct enpdevice *addr;
620*30230Ssam 	u_char *enaddr;
62129649Ssam {
622*30230Ssam 	u_char *cp;
623*30230Ssam 	int i, code;
62429649Ssam 
625*30230Ssam 	cp = &addr->enp_addr.e_baseaddr.ea_addr[0];
626*30230Ssam 	for (i = 0; i < 6; i++)
627*30230Ssam 		*cp++ = ~*enaddr++;
628*30230Ssam 	enpcopy(&addr->enp_addr.e_listsize, &code, sizeof (code));
629*30230Ssam 	code |= E_ADDR_SUPP;
630*30230Ssam 	enpcopy(&code, &addr->enp_addr.e_listsize, sizeof (code));
631*30230Ssam 	enpinit(unit);
63229649Ssam }
63329649Ssam 
63429649Ssam /*
635*30230Ssam  * Routines to synchronize enp and host.
63629649Ssam  */
63729649Ssam static
638*30230Ssam ringinit(rp, size)
639*30230Ssam 	register RING *rp;
64029649Ssam {
641*30230Ssam 	register int i;
64229649Ssam 	register short *sp;
64329649Ssam 
64429649Ssam 	rp->r_rdidx = rp->r_wrtidx = 0;
64529649Ssam 	rp->r_size = size;
64629649Ssam }
64729649Ssam 
64829649Ssam static
649*30230Ssam ringempty(rp)
650*30230Ssam 	register RING *rp;
65129649Ssam {
652*30230Ssam 
653*30230Ssam 	return (rp->r_rdidx == rp->r_wrtidx);
65429649Ssam }
65529649Ssam 
65629649Ssam static
657*30230Ssam ringfull(rp)
658*30230Ssam 	register RING *rp;
65929649Ssam {
66029649Ssam 	register short idx;
66129649Ssam 
66229649Ssam 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
663*30230Ssam 	return (idx == rp->r_rdidx);
66429649Ssam }
66529649Ssam 
66629649Ssam static
667*30230Ssam ringput(rp, v)
668*30230Ssam 	register RING *rp;
66929649Ssam {
67029649Ssam 	register int idx;
67129649Ssam 
67229649Ssam 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
673*30230Ssam 	if (idx != rp->r_rdidx) {
674*30230Ssam 		rp->r_slot[rp->r_wrtidx] = v;
67529649Ssam 		rp->r_wrtidx = idx;
676*30230Ssam 		if ((idx -= rp->r_rdidx) < 0)
67729649Ssam 			idx += rp->r_size;
678*30230Ssam 		return (idx);			/* num ring entries */
67929649Ssam 	}
680*30230Ssam 	return (0);
68129649Ssam }
68229649Ssam 
68329649Ssam static
684*30230Ssam ringget(rp)
685*30230Ssam 	register RING *rp;
68629649Ssam {
68729649Ssam 	register int i = 0;
68829649Ssam 
689*30230Ssam 	if (rp->r_rdidx != rp->r_wrtidx) {
690*30230Ssam 		i = rp->r_slot[rp->r_rdidx];
69129649Ssam 		rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
69229649Ssam 	}
693*30230Ssam 	return (i);
69429649Ssam }
69529649Ssam 
696*30230Ssam static
697*30230Ssam fir(rp)
698*30230Ssam 	register RING *rp;
69929649Ssam {
70029649Ssam 
701*30230Ssam 	return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0);
70229649Ssam }
703*30230Ssam 
704*30230Ssam /*
705*30230Ssam  * ENP Ram device.
706*30230Ssam  */
707*30230Ssam enpr_open(dev)
708*30230Ssam 	dev_t dev;
70929649Ssam {
710*30230Ssam 	register int unit = ENPUNIT(dev);
711*30230Ssam 	struct vba_device *ui;
712*30230Ssam 	struct enpdevice *addr;
71329649Ssam 
714*30230Ssam 	if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
715*30230Ssam 	    (addr = (struct enpdevice *)ui->ui_addr) == 0)
716*30230Ssam 		return (ENODEV);
717*30230Ssam 	if (addr->enp_state != S_ENPRESET)
718*30230Ssam 		return (EACCES);  /* enp is not in reset state, don't open  */
719*30230Ssam 	return (0);
72029649Ssam }
72129649Ssam 
722*30230Ssam enpr_close(dev)
723*30230Ssam 	dev_t dev;
72429649Ssam {
72529649Ssam 
726*30230Ssam 	return (0);
72729649Ssam }
72829649Ssam 
729*30230Ssam enpr_read(dev, uio)
730*30230Ssam 	dev_t dev;
731*30230Ssam 	register struct uio *uio;
73229649Ssam {
733*30230Ssam 	register struct iovec *iov;
734*30230Ssam 	struct enpdevice *addr;
735*30230Ssam 	int error;
73629649Ssam 
737*30230Ssam 	if (uio->uio_offset > RAM_SIZE)
738*30230Ssam 		return (ENODEV);
739*30230Ssam 	if (uio->uio_offset + iov->iov_len > RAM_SIZE)
740*30230Ssam 		iov->iov_len = RAM_SIZE - uio->uio_offset;
741*30230Ssam 	addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
742*30230Ssam 	iov = uio->uio_iov;
743*30230Ssam 	error = useracc(iov->iov_base, iov->iov_len, 0);
744*30230Ssam 	if (error)
745*30230Ssam 		return (error);
746*30230Ssam 	enpcopy(&addr->enp_ram[uio->uio_offset], iov->iov_base, iov->iov_len);
747*30230Ssam 	uio->uio_resid -= iov->iov_len;
748*30230Ssam 	iov->iov_len = 0;
749*30230Ssam 	return (0);
75029649Ssam }
75129649Ssam 
752*30230Ssam enpr_write(dev, uio)
753*30230Ssam 	dev_t dev;
754*30230Ssam 	register struct uio *uio;
75529649Ssam {
756*30230Ssam 	register struct enpdevice *addr;
757*30230Ssam 	register struct iovec *iov;
758*30230Ssam 	register error;
75929649Ssam 
760*30230Ssam 	addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
761*30230Ssam 	iov = uio->uio_iov;
762*30230Ssam 	if (uio->uio_offset > RAM_SIZE)
763*30230Ssam 		return (ENODEV);
764*30230Ssam 	if (uio->uio_offset + iov->iov_len > RAM_SIZE)
765*30230Ssam 		iov->iov_len = RAM_SIZE - uio->uio_offset;
766*30230Ssam 	error =  useracc(iov->iov_base, iov->iov_len, 1);
767*30230Ssam 	if (error)
768*30230Ssam 		return (error);
769*30230Ssam 	enpcopy(iov->iov_base, &addr->enp_ram[uio->uio_offset], iov->iov_len);
770*30230Ssam 	uio->uio_resid -= iov->iov_len;
771*30230Ssam 	iov->iov_len = 0;
772*30230Ssam 	return (0);
77329649Ssam }
77429649Ssam 
775*30230Ssam enpr_ioctl(dev, cmd, data)
776*30230Ssam 	dev_t dev;
777*30230Ssam 	caddr_t data;
77829649Ssam {
779*30230Ssam 	register struct enpdevice *addr;
780*30230Ssam 	register unit = ENPUNIT(dev);
781*30230Ssam 	register struct vba_device *ui;
78229649Ssam 
783*30230Ssam 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
784*30230Ssam 	switch(cmd) {
785*30230Ssam 
786*30230Ssam 	case ENPIOGO:
787*30230Ssam /* not needed if prom based version */
788*30230Ssam 		addr->enp_base = (int)addr;
789*30230Ssam 		addr->enp_intrvec = enp_softc[unit].es_ivec;
790*30230Ssam 		ENP_GO(addr, ENPSTART);
791*30230Ssam 		DELAY(200000);
792*30230Ssam 		enpinit(unit);
793*30230Ssam 		addr->enp_state = S_ENPRUN;  /* it is running now */
794*30230Ssam /* end of not needed */
795*30230Ssam 		break;
796*30230Ssam 
797*30230Ssam 	case ENPIORESET:
798*30230Ssam 		RESET_ENP(addr);
799*30230Ssam 		addr->enp_state = S_ENPRESET;  /* it is reset now */
800*30230Ssam 		DELAY(100000);
801*30230Ssam 		break;
80229649Ssam 	}
803*30230Ssam 	return (0);
80429649Ssam }
80529649Ssam #endif
806