xref: /csrg-svn/sys/tahoe/if/if_enp.c (revision 30986)
1*30986Ssam /*	if_enp.c	1.5	87/04/29	*/
229649Ssam 
329649Ssam #include "enp.h"
429649Ssam #if NENP > 0
529649Ssam /*
6*30986Ssam  * CMC ENP-20 Ethernet Controller.
729649Ssam  */
829649Ssam #include "param.h"
929649Ssam #include "systm.h"
1029649Ssam #include "mbuf.h"
1129649Ssam #include "buf.h"
1229649Ssam #include "protosw.h"
1329649Ssam #include "socket.h"
1429649Ssam #include "vmmac.h"
1530230Ssam #include "ioctl.h"
1629649Ssam #include "errno.h"
1730230Ssam #include "vmparam.h"
1830230Ssam #include "syslog.h"
1929649Ssam #include "uio.h"
2029649Ssam 
2129649Ssam #include "../net/if.h"
2229649Ssam #include "../net/netisr.h"
2329649Ssam #include "../net/route.h"
2430230Ssam #ifdef INET
2529649Ssam #include "../netinet/in.h"
2629649Ssam #include "../netinet/in_systm.h"
2730230Ssam #include "../netinet/in_var.h"
2829649Ssam #include "../netinet/ip.h"
2929649Ssam #include "../netinet/ip_var.h"
3029649Ssam #include "../netinet/if_ether.h"
3130230Ssam #endif
3230230Ssam #ifdef NS
3330230Ssam #include "../netns/ns.h"
3430230Ssam #include "../netns/ns_if.h"
3530230Ssam #endif
3629649Ssam 
3730230Ssam #include "../tahoe/cpu.h"
3830230Ssam #include "../tahoe/pte.h"
3930230Ssam #include "../tahoe/mtpr.h"
4030230Ssam 
4129649Ssam #include "../tahoevba/vbavar.h"
4230230Ssam #include "../tahoeif/if_enpreg.h"
4329649Ssam 
4430230Ssam #define ENPSTART	0xf02000	/* standard enp start addr */
4530230Ssam #define	ENPUNIT(dev)	(minor(dev))	/* for enp ram devices */
46*30986Ssam /* macros for dealing with longs in i/o space */
47*30986Ssam #define	ENPGETLONG(a)	((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1]))
48*30986Ssam #define	ENPSETLONG(a,v) \
49*30986Ssam    { register u_short *wp = (u_short *)(a); \
50*30986Ssam      wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];}
5129649Ssam 
5229649Ssam int	enpprobe(), enpattach(), enpintr();
5330298Ssam long	enpstd[] = { 0xfff41000, 0xfff61000, 0 };
5430230Ssam struct  vba_device *enpinfo[NENP];
5529649Ssam struct  vba_driver enpdriver =
5630230Ssam     { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 };
5729649Ssam 
5830230Ssam int	enpinit(), enpioctl(), enpreset(), enpoutput();
5929649Ssam struct  mbuf *enpget();
6029649Ssam 
6129649Ssam /*
6229649Ssam  * Ethernet software status per interface.
6329649Ssam  *
6429649Ssam  * Each interface is referenced by a network interface structure,
6529649Ssam  * es_if, which the routing code uses to locate the interface.
6629649Ssam  * This structure contains the output queue for the interface, its address, ...
6729649Ssam  */
6830230Ssam struct  enp_softc {
6930230Ssam 	struct  arpcom es_ac;           /* common ethernet structures */
7030230Ssam #define es_if		es_ac.ac_if
71*30986Ssam #define es_addr	es_ac.ac_enaddr
7230230Ssam 	short	es_ivec;		/* interrupt vector */
7330230Ssam } enp_softc[NENP];
7430230Ssam extern	struct ifnet loif;
7529649Ssam 
7630230Ssam enpprobe(reg, vi)
7730230Ssam 	caddr_t reg;
7830230Ssam 	struct vba_device *vi;
7929649Ssam {
8030230Ssam 	register br, cvec;		/* must be r12, r11 */
8130230Ssam 	register struct enpdevice *addr = (struct enpdevice *)reg;
8230230Ssam 	struct enp_softc *es = &enp_softc[vi->ui_unit];
8329649Ssam 
8430230Ssam #ifdef lint
8530295Ssam 	br = 0; cvec = br; br = cvec;
8630230Ssam 	enpintr(0);
8730230Ssam #endif
8830295Ssam 	if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2))
8930230Ssam 		return (0);
9030230Ssam 	es->es_ivec = --vi->ui_hd->vh_lastiv;
9130230Ssam 	addr->enp_state = S_ENPRESET;		/* reset by VERSAbus reset */
9230230Ssam 	br = 0x14, cvec = es->es_ivec;		/* XXX */
9330230Ssam 	return (sizeof (struct enpdevice));
9429649Ssam }
9529649Ssam 
9629649Ssam /*
9729649Ssam  * Interface exists: make available by filling in network interface
9829649Ssam  * record.  System will initialize the interface when it is ready
9929649Ssam  * to accept packets.
10029649Ssam  */
10130230Ssam enpattach(ui)
10230230Ssam 	register struct vba_device *ui;
10329649Ssam {
10430230Ssam 	struct enp_softc *es = &enp_softc[ui->ui_unit];
10530230Ssam 	register struct ifnet *ifp = &es->es_if;
10629649Ssam 
10730230Ssam 	ifp->if_unit = ui->ui_unit;
10829649Ssam 	ifp->if_name = "enp";
10929649Ssam 	ifp->if_mtu = ETHERMTU;
11029649Ssam 	ifp->if_init = enpinit;
11129649Ssam 	ifp->if_ioctl = enpioctl;
11229649Ssam 	ifp->if_output = enpoutput;
11329649Ssam 	ifp->if_reset = enpreset;
11430230Ssam 	ifp->if_flags = IFF_BROADCAST;
11529649Ssam 	if_attach(ifp);
11629649Ssam }
11729649Ssam 
11829649Ssam /*
11930230Ssam  * Reset of interface after "system" reset.
12029649Ssam  */
12130230Ssam enpreset(unit, vban)
12230230Ssam 	int unit, vban;
12329649Ssam {
12430230Ssam 	register struct vba_device *ui;
12529649Ssam 
12630230Ssam 	if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
12730230Ssam 	    ui->ui_vbanum != vban)
12830230Ssam 		return;
12930230Ssam 	printf(" enp%d", unit);
13029649Ssam 	enpinit(unit);
13129649Ssam }
13229649Ssam 
13329649Ssam /*
13430230Ssam  * Initialization of interface; clear recorded pending operations.
13529649Ssam  */
13630230Ssam enpinit(unit)
13730230Ssam 	int unit;
13829649Ssam {
13930230Ssam 	struct enp_softc *es = &enp_softc[unit];
14030230Ssam 	register struct vba_device *ui = enpinfo[unit];
14130230Ssam 	struct enpdevice *addr;
14230230Ssam 	register struct ifnet *ifp = &es->es_if;
14330230Ssam 	int s;
14429649Ssam 
14530230Ssam 	if (ifp->if_addrlist == (struct ifaddr *)0)
14630230Ssam 		return;
14730230Ssam 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
14830230Ssam 		addr = (struct enpdevice *)ui->ui_addr;
14930230Ssam 		s = splimp();
15030230Ssam 		RESET_ENP(addr);
15130230Ssam 		DELAY(200000);
15230230Ssam 		es->es_if.if_flags |= IFF_RUNNING;
15330230Ssam 		splx(s);
15429649Ssam 	}
15529649Ssam }
15629649Ssam 
15729649Ssam /*
15829649Ssam  * Ethernet interface interrupt.
15929649Ssam  */
16030230Ssam enpintr(unit)
16130230Ssam 	int unit;
16229649Ssam {
16330230Ssam 	register struct enpdevice *addr;
16430230Ssam 	register BCB *bcbp;
16529649Ssam 
16630230Ssam 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
16730295Ssam #if ENP == 30
16830230Ssam 	if (!IS_ENP_INTR(addr))
16929649Ssam 		return;
17030230Ssam 	ACK_ENP_INTR(addr);
17130295Ssam #endif
17230295Ssam 	while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) {
17330295Ssam 		(void) enpread(&enp_softc[unit], bcbp);
17430295Ssam 		(void) ringput((RING *)&addr->enp_enpfree, bcbp);
17529649Ssam 	}
17629649Ssam }
17729649Ssam 
17829649Ssam /*
17929649Ssam  * Read input packet, examine its packet type, and enqueue it.
18029649Ssam  */
18130295Ssam enpread(es, bcbp)
18230230Ssam 	struct enp_softc *es;
18330230Ssam 	register BCB *bcbp;
18429649Ssam {
18529649Ssam 	register struct ether_header *enp;
18629649Ssam 	struct mbuf *m;
18730295Ssam 	int s, len, off, resid;
18829649Ssam 	register struct ifqueue *inq;
18929649Ssam 
19029649Ssam 	es->es_if.if_ipackets++;
19129649Ssam 	/*
19229649Ssam 	 * Get input data length.
19329649Ssam 	 * Get pointer to ethernet header (in input buffer).
19429649Ssam 	 * Deal with trailer protocol: if type is PUP trailer
19529649Ssam 	 * get true type from first 16-bit word past data.
19629649Ssam 	 * Remember that type was trailer by setting off.
19729649Ssam 	 */
19830230Ssam 	len = bcbp->b_msglen - sizeof (struct ether_header);
199*30986Ssam 	enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr);
20030230Ssam #define enpdataaddr(enp, off, type) \
20130230Ssam     ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off))))
20230230Ssam 	enp->ether_type = ntohs((u_short)enp->ether_type);
20330230Ssam 	if (enp->ether_type >= ETHERTYPE_TRAIL &&
20430230Ssam 	    enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
20530230Ssam 		off = (enp->ether_type - ETHERTYPE_TRAIL) * 512;
20630230Ssam 		if (off >= ETHERMTU)
20730230Ssam 			goto setup;
20830230Ssam 		enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *));
20930230Ssam 		resid = ntohs(*(enpdataaddr(enp, off+2, u_short *)));
21030230Ssam 		if (off + resid > len)
21130230Ssam 			goto setup;
21229649Ssam 		len = off + resid;
21330230Ssam 	} else
21429649Ssam 		off = 0;
21530230Ssam 	if (len == 0)
21630230Ssam 		goto setup;
21729649Ssam 
21829649Ssam 	/*
21929649Ssam 	 * Pull packet off interface.  Off is nonzero if packet
22029649Ssam 	 * has trailing header; enpget will then force this header
22129649Ssam 	 * information to be at the front, but we still have to drop
22229649Ssam 	 * the type and length which are at the front of any trailer data.
22329649Ssam 	 */
224*30986Ssam 	m = enpget((u_char *)enp, len, off, &es->es_if);
22530230Ssam 	if (m == 0)
22630230Ssam 		goto setup;
22730230Ssam 	if (off) {
22830230Ssam 		struct ifnet *ifp;
22929649Ssam 
23030230Ssam 		ifp = *(mtod(m, struct ifnet **));
23129649Ssam 		m->m_off += 2 * sizeof (u_short);
23229649Ssam 		m->m_len -= 2 * sizeof (u_short);
23330230Ssam 		*(mtod(m, struct ifnet **)) = ifp;
23429649Ssam 	}
23530230Ssam 	switch (enp->ether_type) {
23629649Ssam 
23729649Ssam #ifdef INET
23830230Ssam 	case ETHERTYPE_IP:
23929649Ssam 		schednetisr(NETISR_IP);
24029649Ssam 		inq = &ipintrq;
24129649Ssam 		break;
24230230Ssam #endif
24330230Ssam 	case ETHERTYPE_ARP:
24430230Ssam 		arpinput(&es->es_ac, m);
24530230Ssam 		goto setup;
24629649Ssam 
24730230Ssam #ifdef NS
24830230Ssam 	case ETHERTYPE_NS:
24930230Ssam 		schednetisr(NETISR_NS);
25030230Ssam 		inq = &nsintrq;
25130230Ssam 		break;
25229649Ssam #endif
25330230Ssam 	default:
25429649Ssam 		m_freem(m);
25530230Ssam 		goto setup;
25629649Ssam 	}
25730230Ssam 	if (IF_QFULL(inq)) {
25829649Ssam 		IF_DROP(inq);
25929649Ssam 		m_freem(m);
26030230Ssam 		goto setup;
26129649Ssam 	}
26229649Ssam 	s = splimp();
26329649Ssam 	IF_ENQUEUE(inq, m);
26429649Ssam 	splx(s);
26530230Ssam setup:
26630230Ssam 	return (0);
26729649Ssam }
26829649Ssam 
26929649Ssam /*
27029649Ssam  * Ethernet output routine. (called by user)
27129649Ssam  * Encapsulate a packet of type family for the local net.
27229649Ssam  * Use trailer local net encapsulation if enough data in first
27329649Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
27429649Ssam  * If destination is this address or broadcast, send packet to
27529649Ssam  * loop device to kludge around the fact that 3com interfaces can't
27629649Ssam  * talk to themselves.
27729649Ssam  */
27829649Ssam enpoutput(ifp, m0, dst)
27930230Ssam 	struct ifnet *ifp;
28030230Ssam 	struct mbuf *m0;
28130230Ssam 	struct sockaddr *dst;
28229649Ssam {
28329649Ssam 	register struct enp_softc *es = &enp_softc[ifp->if_unit];
28429649Ssam 	register struct mbuf *m = m0;
28529649Ssam 	register struct ether_header *enp;
28630295Ssam 	register int off;
28730230Ssam 	struct mbuf *mcopy = (struct mbuf *)0;
28830230Ssam 	int type, s, error, usetrailers;
28930230Ssam 	u_char edst[6];
29030230Ssam 	struct in_addr idst;
29129649Ssam 
29230230Ssam 	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
29330230Ssam 		error = ENETDOWN;
29430230Ssam 		goto bad;
29530230Ssam 	}
29630230Ssam 	switch (dst->sa_family) {
29729649Ssam #ifdef INET
29829649Ssam 	case AF_INET:
29929649Ssam 		idst = ((struct sockaddr_in *)dst)->sin_addr;
30030230Ssam 		if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers))
30130230Ssam 			return (0);	/* if not yet resolved */
30230230Ssam 		if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
30330230Ssam 		    sizeof (edst)))
30430230Ssam 			mcopy = m_copy(m, 0, (int)M_COPYALL);
30530230Ssam 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
30630230Ssam 		if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
30730230Ssam 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
30830230Ssam 			type = ETHERTYPE_TRAIL + (off>>9);
30930230Ssam 			m->m_off -= 2 * sizeof (u_short);
31030230Ssam 			m->m_len += 2 * sizeof (u_short);
311*30986Ssam 			*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
312*30986Ssam 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
31330230Ssam 			goto gottrailertype;
31429649Ssam 		}
31530230Ssam 		type = ETHERTYPE_IP;
31629649Ssam 		off = 0;
31729649Ssam 		goto gottype;
31829649Ssam #endif
31930230Ssam #ifdef NS
32030230Ssam 	case AF_NS:
32130230Ssam 		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
32230230Ssam 		    (caddr_t)edst, sizeof (edst));
32330230Ssam 		if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst)))
32430230Ssam 			mcopy = m_copy(m, 0, (int)M_COPYALL);
32530230Ssam 		else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
32630230Ssam 		    sizeof (edst)))
32730230Ssam 			return (looutput(&loif, m, dst));
32830230Ssam 		type = ETHERTYPE_NS;
32930230Ssam 		off = 0;
33030230Ssam 		goto gottype;
33129649Ssam #endif
33229649Ssam 	case AF_UNSPEC:
33329649Ssam 		enp = (struct ether_header *)dst->sa_data;
33430230Ssam 		bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst));
33529649Ssam 		type = enp->ether_type;
33629649Ssam 		goto gottype;
33729649Ssam 
33829649Ssam 	default:
33930230Ssam 		log(LOG_ERR, "enp%d: can't handle af%d\n",
34030230Ssam 		    ifp->if_unit, dst->sa_family);
34129649Ssam 		error = EAFNOSUPPORT;
34229649Ssam 		goto bad;
34329649Ssam 	}
34429649Ssam 
34529649Ssam gottrailertype:
34629649Ssam 	/*
34729649Ssam 	 * Packet to be sent as trailer: move first packet
34829649Ssam 	 * (control information) to end of chain.
34929649Ssam 	 */
35029649Ssam 	while (m->m_next)
35129649Ssam 		m = m->m_next;
35229649Ssam 	m->m_next = m0;
35329649Ssam 	m = m0->m_next;
35429649Ssam 	m0->m_next = 0;
35529649Ssam 	m0 = m;
35629649Ssam 
35729649Ssam gottype:
35829649Ssam 	/*
35929649Ssam          * Add local net header.  If no space in first mbuf,
36029649Ssam          * allocate another.
36129649Ssam          */
36229649Ssam 	if (m->m_off > MMAXOFF ||
36330230Ssam 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
36429649Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
36530230Ssam 		if (m == 0) {
36629649Ssam 			error = ENOBUFS;
36729649Ssam 			goto bad;
36829649Ssam 		}
36929649Ssam 		m->m_next = m0;
37029649Ssam 		m->m_off = MMINOFF;
37130230Ssam 		m->m_len = sizeof (struct ether_header);
37230230Ssam 	} else {
37330230Ssam 		m->m_off -= sizeof (struct ether_header);
37430230Ssam 		m->m_len += sizeof (struct ether_header);
37529649Ssam 	}
37629649Ssam 	enp = mtod(m, struct ether_header *);
37730230Ssam 	bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst));
378*30986Ssam 	bcopy((caddr_t)es->es_addr, (caddr_t)enp->ether_shost,
379*30986Ssam 	    sizeof (es->es_addr));
38030230Ssam 	enp->ether_type = htons((u_short)type);
38129649Ssam 
38229649Ssam 	/*
38329649Ssam 	 * Queue message on interface if possible
38429649Ssam 	 */
38529649Ssam 	s = splimp();
38630230Ssam 	if (enpput(ifp->if_unit, m)) {
38729649Ssam 		error = ENOBUFS;
38829649Ssam 		goto qfull;
38929649Ssam 	}
39030230Ssam 	splx(s);
39129649Ssam 	es->es_if.if_opackets++;
39230230Ssam 	return (mcopy ? looutput(&loif, mcopy, dst) : 0);
39329649Ssam qfull:
39430230Ssam 	splx(s);
39529649Ssam 	m0 = m;
39629649Ssam bad:
39729649Ssam 	m_freem(m0);
39830230Ssam 	if (mcopy)
39930230Ssam 		m_freem(mcopy);
40030230Ssam 	return (error);
40129649Ssam }
40229649Ssam 
40329649Ssam /*
40430230Ssam  * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
40529649Ssam  */
40630230Ssam enpput(unit, m)
40730230Ssam 	int unit;
40830230Ssam 	struct mbuf *m;
40929649Ssam {
41029649Ssam 	register BCB *bcbp;
41130230Ssam 	register struct enpdevice *addr;
41229649Ssam 	register struct mbuf *mp;
41329649Ssam 	register u_char *bp;
41430230Ssam 	register u_int len;
41530230Ssam 	u_char *mcp;
41629649Ssam 
41730230Ssam 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
41830295Ssam 	if (ringempty((RING *)&addr->enp_hostfree))
41930230Ssam 		return (1);
42030295Ssam 	bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree);
42129649Ssam 	bcbp->b_len = 0;
422*30986Ssam 	bp = (u_char *)ENPGETLONG(&bcbp->b_addr);
42330230Ssam 	for (mp = m; mp; mp = mp->m_next) {
42429649Ssam 		len = mp->m_len;
42530230Ssam 		if (len == 0)
42629649Ssam 			continue;
42730230Ssam 		mcp = mtod(mp, u_char *);
42830230Ssam 		enpcopy(mcp, bp, len);
42929649Ssam 		bp += len;
43029649Ssam 		bcbp->b_len += len;
43129649Ssam 	}
432*30986Ssam 	bcbp->b_len = MAX(ETHERMIN+sizeof (struct ether_header), bcbp->b_len);
43329649Ssam 	bcbp->b_reserved = 0;
43430295Ssam 	if (ringput((RING *)&addr->enp_toenp, bcbp) == 1)
43530230Ssam 		INTR_ENP(addr);
43629649Ssam 	m_freem(m);
43730230Ssam 	return (0);
43829649Ssam }
43929649Ssam 
44029649Ssam /*
44130230Ssam  * Routine to copy from VERSAbus memory into mbufs.
44229649Ssam  *
44329649Ssam  * Warning: This makes the fairly safe assumption that
44429649Ssam  * mbufs have even lengths.
44529649Ssam  */
44629649Ssam struct mbuf *
44730230Ssam enpget(rxbuf, totlen, off0, ifp)
44830230Ssam 	u_char *rxbuf;
44930230Ssam 	int totlen, off0;
45030230Ssam 	struct ifnet *ifp;
45129649Ssam {
45230230Ssam 	register u_char *cp, *mcp;
45329649Ssam 	register struct mbuf *m;
45430230Ssam 	struct mbuf *top = 0, **mp = &top;
45530230Ssam 	int len, off = off0;
45629649Ssam 
45730230Ssam 	cp = rxbuf + sizeof (struct ether_header);
45830230Ssam 	while (totlen > 0) {
45929649Ssam 		MGET(m, M_DONTWAIT, MT_DATA);
46029649Ssam 		if (m == 0)
46129649Ssam 			goto bad;
46230230Ssam 		if (off) {
46329649Ssam 			len = totlen - off;
46430230Ssam 			cp = rxbuf + sizeof (struct ether_header) + off;
46530230Ssam 		} else
46629649Ssam 			len = totlen;
46730230Ssam 		if (len >= NBPG) {
46830230Ssam 			MCLGET(m);
46930230Ssam 			if (m->m_len == CLBYTES)
47030230Ssam 				m->m_len = len = MIN(len, CLBYTES);
47130230Ssam 			else
47229649Ssam 				m->m_len = len = MIN(MLEN, len);
47330230Ssam 		} else {
47429649Ssam 			m->m_len = len = MIN(MLEN, len);
47529649Ssam 			m->m_off = MMINOFF;
47629649Ssam 		}
47729649Ssam 		mcp = mtod(m, u_char *);
47830230Ssam 		if (ifp) {
47930230Ssam 			/*
48030230Ssam 			 * Prepend interface pointer to first mbuf.
48130230Ssam 			 */
48230230Ssam 			*(mtod(m, struct ifnet **)) = ifp;
48330230Ssam 			mcp += sizeof (ifp);
48430230Ssam 			len -= sizeof (ifp);
48530230Ssam 			ifp = (struct ifnet *)0;
48630230Ssam 		}
48730295Ssam 		enpcopy(cp, mcp, (u_int)len);
48829649Ssam 		cp += len;
48929649Ssam 		*mp = m;
49029649Ssam 		mp = &m->m_next;
49130230Ssam 		if (off == 0) {
49229649Ssam 			totlen -= len;
49329649Ssam 			continue;
49429649Ssam 		}
49529649Ssam 		off += len;
49630230Ssam 		if (off == totlen) {
49730230Ssam 			cp = rxbuf + sizeof (struct ether_header);
49829649Ssam 			off = 0;
49929649Ssam 			totlen = off0;
50029649Ssam 		}
50129649Ssam 	}
50229649Ssam 	return (top);
50329649Ssam bad:
50429649Ssam 	m_freem(top);
50529649Ssam 	return (0);
50629649Ssam }
50729649Ssam 
50830230Ssam enpcopy(from, to, cnt)
50930295Ssam 	register u_char *from, *to;
51030295Ssam 	register u_int cnt;
51130230Ssam {
51230230Ssam 	register c;
51330230Ssam 	register short *f, *t;
51430230Ssam 
51530230Ssam 	if (((int)from&01) && ((int)to&01)) {
51630230Ssam 		/* source & dest at odd addresses */
51730230Ssam 		*to++ = *from++;
51830230Ssam 		--cnt;
51930230Ssam 	}
52030230Ssam 	if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) {
52130230Ssam 		t = (short *)to;
52230230Ssam 		f = (short *)from;
52330230Ssam 		for (c = cnt>>1; c; --c)	/* even address copy */
52430230Ssam 			*t++ = *f++;
52530230Ssam 		cnt &= 1;
52630230Ssam 		if (cnt) {			/* odd len */
52730295Ssam 			from = (u_char *)f;
52830295Ssam 			to = (u_char *)t;
52930230Ssam 			*to = *from;
53030230Ssam 		}
53130230Ssam 	}
53230295Ssam 	while ((int)cnt-- > 0)	/* one of the address(es) must be odd */
53330230Ssam 		*to++ = *from++;
53430230Ssam }
53530230Ssam 
53629649Ssam /*
53729649Ssam  * Process an ioctl request.
53829649Ssam  */
53929649Ssam enpioctl(ifp, cmd, data)
54030230Ssam 	register struct ifnet *ifp;
54130230Ssam 	int cmd;
54230230Ssam 	caddr_t data;
54329649Ssam {
54430230Ssam 	register struct ifaddr *ifa = (struct ifaddr *)data;
54530230Ssam 	struct enpdevice *addr;
54630230Ssam 	int s = splimp(), error = 0;
54729649Ssam 
54829649Ssam 	switch (cmd) {
54929649Ssam 
55029649Ssam 	case SIOCSIFADDR:
55130230Ssam 		ifp->if_flags |= IFF_UP;
55230230Ssam 		switch (ifa->ifa_addr.sa_family) {
55330230Ssam #ifdef INET
55430230Ssam 		case AF_INET:
55530230Ssam 			enpinit(ifp->if_unit);
55630230Ssam 			((struct arpcom *)ifp)->ac_ipaddr =
55730230Ssam 			    IA_SIN(ifa)->sin_addr;
55830230Ssam 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
55929649Ssam 			break;
56030230Ssam #endif
56130230Ssam #ifdef NS
56230230Ssam 		case AF_NS: {
56330230Ssam 			struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
56430230Ssam 			struct enp_softc *es = &enp_softc[ifp->if_unit];
56530230Ssam 
56630230Ssam 			if (!ns_nullhost(*ina)) {
56730230Ssam 				ifp->if_flags &= ~IFF_RUNNING;
56830230Ssam 				addr = (struct enpdevice *)
56930230Ssam 				    enpinfo[ifp->if_unit]->ui_addr;
57030230Ssam 				enpsetaddr(ifp->if_unit, addr,
57130230Ssam 				    ina->x_host.c_host);
57230230Ssam 			} else
573*30986Ssam 				ina->x_host = *(union ns_host *)es->es_addr;
57430230Ssam 			enpinit(ifp->if_unit);
57530230Ssam 			break;
57629649Ssam 		}
57730230Ssam #endif
57830230Ssam 		default:
57930230Ssam 			enpinit(ifp->if_unit);
58030230Ssam 			break;
58129649Ssam 		}
58229649Ssam 		break;
58329649Ssam 
58430230Ssam 	case SIOCSIFFLAGS:
58530230Ssam 		if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
58630230Ssam 			enpinit(ifp->if_unit);		/* reset board */
58730230Ssam 			ifp->if_flags &= ~IFF_RUNNING;
58830230Ssam 		} else if (ifp->if_flags&IFF_UP &&
58930230Ssam 		     (ifp->if_flags&IFF_RUNNING) == 0)
59030230Ssam 			enpinit(ifp->if_unit);
59129649Ssam 		break;
59229649Ssam 
59329649Ssam 	default:
59429649Ssam 		error = EINVAL;
59529649Ssam 	}
59630230Ssam 	splx(s);
59730230Ssam 	return (error);
59829649Ssam }
59929649Ssam 
60030230Ssam enpsetaddr(unit, addr, enaddr)
60130230Ssam 	int unit;
60230230Ssam 	struct enpdevice *addr;
60330230Ssam 	u_char *enaddr;
60429649Ssam {
60529649Ssam 
606*30986Ssam 	enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr,
607*30986Ssam 	    sizeof (struct ether_addr));
60830230Ssam 	enpinit(unit);
609*30986Ssam 	enpgetaddr(unit, addr);
61029649Ssam }
61129649Ssam 
612*30986Ssam enpgetaddr(unit, addr)
613*30986Ssam 	int unit;
614*30986Ssam 	struct enpdevice *addr;
615*30986Ssam {
616*30986Ssam 	struct enp_softc *es = &enp_softc[unit];
617*30986Ssam 
618*30986Ssam 	enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr,
619*30986Ssam 	    sizeof (struct ether_addr));
620*30986Ssam 	printf("enp%d: hardware address %s\n",
621*30986Ssam 	    unit, ether_sprintf(es->es_addr));
622*30986Ssam }
623*30986Ssam 
62429649Ssam /*
62530230Ssam  * Routines to synchronize enp and host.
62629649Ssam  */
62730295Ssam #ifdef notdef
62829649Ssam static
62930230Ssam ringinit(rp, size)
63030230Ssam 	register RING *rp;
63129649Ssam {
63229649Ssam 
63329649Ssam 	rp->r_rdidx = rp->r_wrtidx = 0;
63429649Ssam 	rp->r_size = size;
63529649Ssam }
63629649Ssam 
63729649Ssam static
63830295Ssam ringfull(rp)
63930230Ssam 	register RING *rp;
64029649Ssam {
64130295Ssam 	register short idx;
64230230Ssam 
64330295Ssam 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
64430295Ssam 	return (idx == rp->r_rdidx);
64529649Ssam }
64629649Ssam 
64729649Ssam static
64830295Ssam fir(rp)
64930230Ssam 	register RING *rp;
65029649Ssam {
65129649Ssam 
65230295Ssam 	return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0);
65329649Ssam }
65430295Ssam #endif
65529649Ssam 
65629649Ssam static
65730295Ssam ringempty(rp)
65830295Ssam 	register RING *rp;
65930295Ssam {
66030295Ssam 
66130295Ssam 	return (rp->r_rdidx == rp->r_wrtidx);
66230295Ssam }
66330295Ssam 
66430295Ssam static
66530230Ssam ringput(rp, v)
66630230Ssam 	register RING *rp;
66730295Ssam 	BCB *v;
66829649Ssam {
66929649Ssam 	register int idx;
67029649Ssam 
67129649Ssam 	idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
67230230Ssam 	if (idx != rp->r_rdidx) {
673*30986Ssam 		ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v);
67429649Ssam 		rp->r_wrtidx = idx;
67530230Ssam 		if ((idx -= rp->r_rdidx) < 0)
67629649Ssam 			idx += rp->r_size;
67730230Ssam 		return (idx);			/* num ring entries */
67829649Ssam 	}
67930230Ssam 	return (0);
68029649Ssam }
68129649Ssam 
68229649Ssam static
68330230Ssam ringget(rp)
68430230Ssam 	register RING *rp;
68529649Ssam {
68629649Ssam 	register int i = 0;
68729649Ssam 
68830230Ssam 	if (rp->r_rdidx != rp->r_wrtidx) {
689*30986Ssam 		i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]);
69029649Ssam 		rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
69129649Ssam 	}
69230230Ssam 	return (i);
69329649Ssam }
69429649Ssam 
69530230Ssam /*
69630230Ssam  * ENP Ram device.
69730230Ssam  */
69830230Ssam enpr_open(dev)
69930230Ssam 	dev_t dev;
70029649Ssam {
70130230Ssam 	register int unit = ENPUNIT(dev);
70230230Ssam 	struct vba_device *ui;
70330230Ssam 	struct enpdevice *addr;
70429649Ssam 
70530230Ssam 	if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
70630230Ssam 	    (addr = (struct enpdevice *)ui->ui_addr) == 0)
70730230Ssam 		return (ENODEV);
70830230Ssam 	if (addr->enp_state != S_ENPRESET)
70930230Ssam 		return (EACCES);  /* enp is not in reset state, don't open  */
71030230Ssam 	return (0);
71129649Ssam }
71229649Ssam 
71330295Ssam /*ARGSUSED*/
71430230Ssam enpr_close(dev)
71530230Ssam 	dev_t dev;
71629649Ssam {
71729649Ssam 
71830230Ssam 	return (0);
71929649Ssam }
72029649Ssam 
72130230Ssam enpr_read(dev, uio)
72230230Ssam 	dev_t dev;
72330230Ssam 	register struct uio *uio;
72429649Ssam {
72530230Ssam 	register struct iovec *iov;
72630230Ssam 	struct enpdevice *addr;
72729649Ssam 
72830230Ssam 	if (uio->uio_offset > RAM_SIZE)
72930230Ssam 		return (ENODEV);
73030295Ssam 	iov = uio->uio_iov;
73130230Ssam 	if (uio->uio_offset + iov->iov_len > RAM_SIZE)
73230230Ssam 		iov->iov_len = RAM_SIZE - uio->uio_offset;
73330230Ssam 	addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
734*30986Ssam 	if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0)
735*30986Ssam 		return (EFAULT);
73630295Ssam 	enpcopy((u_char *)&addr->enp_ram[uio->uio_offset],
73730295Ssam 	    (u_char *)iov->iov_base, (u_int)iov->iov_len);
73830230Ssam 	uio->uio_resid -= iov->iov_len;
73930230Ssam 	iov->iov_len = 0;
74030230Ssam 	return (0);
74129649Ssam }
74229649Ssam 
74330230Ssam enpr_write(dev, uio)
74430230Ssam 	dev_t dev;
74530230Ssam 	register struct uio *uio;
74629649Ssam {
74730230Ssam 	register struct enpdevice *addr;
74830230Ssam 	register struct iovec *iov;
74929649Ssam 
75030230Ssam 	addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
75130230Ssam 	iov = uio->uio_iov;
75230230Ssam 	if (uio->uio_offset > RAM_SIZE)
75330230Ssam 		return (ENODEV);
75430230Ssam 	if (uio->uio_offset + iov->iov_len > RAM_SIZE)
75530230Ssam 		iov->iov_len = RAM_SIZE - uio->uio_offset;
756*30986Ssam 	if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0)
757*30986Ssam 		return (EFAULT);
75830295Ssam 	enpcopy((u_char *)iov->iov_base,
75930295Ssam 	    (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len);
76030230Ssam 	uio->uio_resid -= iov->iov_len;
76130230Ssam 	iov->iov_len = 0;
76230230Ssam 	return (0);
76329649Ssam }
76429649Ssam 
76530295Ssam /*ARGSUSED*/
76630230Ssam enpr_ioctl(dev, cmd, data)
76730230Ssam 	dev_t dev;
76830230Ssam 	caddr_t data;
76929649Ssam {
77030230Ssam 	register unit = ENPUNIT(dev);
771*30986Ssam 	struct enpdevice *addr;
77229649Ssam 
77330230Ssam 	addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
77430230Ssam 	switch(cmd) {
77530230Ssam 
77630230Ssam 	case ENPIOGO:
777*30986Ssam 		ENPSETLONG(&addr->enp_base, addr);
77830230Ssam 		addr->enp_intrvec = enp_softc[unit].es_ivec;
77930230Ssam 		ENP_GO(addr, ENPSTART);
78030230Ssam 		DELAY(200000);
78130230Ssam 		enpinit(unit);
782*30986Ssam 		/*
783*30986Ssam 		 * Fetch Ethernet address after link level
784*30986Ssam 		 * is booted (firmware copies manufacturer's
785*30986Ssam 		 * address from on-board ROM).
786*30986Ssam 		 */
787*30986Ssam 		enpgetaddr(unit, addr);
788*30986Ssam 		addr->enp_state = S_ENPRUN;
78930230Ssam 		break;
79030230Ssam 
79130230Ssam 	case ENPIORESET:
79230230Ssam 		RESET_ENP(addr);
793*30986Ssam 		addr->enp_state = S_ENPRESET;
79430230Ssam 		DELAY(100000);
79530230Ssam 		break;
796*30986Ssam 	default:
797*30986Ssam 		return (EINVAL);
79829649Ssam 	}
79930230Ssam 	return (0);
80029649Ssam }
80129649Ssam #endif
802