xref: /csrg-svn/sys/vax/if/if_de.c (revision 15916)
1*15916Skarels /*	if_de.c	6.2	84/02/02	*/
215357Skarels #include "de.h"
315357Skarels #if NDE > 0
415357Skarels 
515357Skarels /*
615357Skarels  * DEC DEUNA interface
715357Skarels  *
815357Skarels  *	Lou Salkind
915357Skarels  *	New York University
1015357Skarels  *
1115357Skarels  * TODO:
1215357Skarels  *	timeout routine (get statistics)
1315357Skarels  */
1415357Skarels #include "../machine/pte.h"
1515357Skarels 
1615357Skarels #include "../h/param.h"
1715357Skarels #include "../h/systm.h"
1815357Skarels #include "../h/mbuf.h"
1915357Skarels #include "../h/buf.h"
2015357Skarels #include "../h/protosw.h"
2115357Skarels #include "../h/socket.h"
2215357Skarels #include "../h/vmmac.h"
2315357Skarels #include "../h/ioctl.h"
2415357Skarels #include "../h/errno.h"
2515357Skarels 
2615357Skarels #include "../net/if.h"
2715357Skarels #include "../net/netisr.h"
2815357Skarels #include "../net/route.h"
2915357Skarels #include "../netinet/in.h"
3015357Skarels #include "../netinet/in_systm.h"
3115357Skarels #include "../netinet/ip.h"
3215357Skarels #include "../netinet/ip_var.h"
3315357Skarels #include "../netinet/if_ether.h"
3415357Skarels #include "../netpup/pup.h"
3515357Skarels 
3615357Skarels #include "../vax/cpu.h"
3715357Skarels #include "../vax/mtpr.h"
3815357Skarels #include "../vaxif/if_dereg.h"
3915357Skarels #include "../vaxif/if_uba.h"
4015357Skarels #include "../vaxuba/ubareg.h"
4115357Skarels #include "../vaxuba/ubavar.h"
4215357Skarels 
4315357Skarels #define	NXMT	2	/* number of transmit buffers */
4415357Skarels #define	NRCV	4	/* number of receive buffers (must be > 1) */
4515357Skarels #define	NTOT	(NXMT + NRCV)
4615357Skarels 
47*15916Skarels int	dedebug = 0;
48*15916Skarels 
4915357Skarels int	deprobe(), deattach(), deintr();
5015357Skarels struct	uba_device *deinfo[NDE];
5115357Skarels u_short destd[] = { 0 };
5215357Skarels struct	uba_driver dedriver =
5315357Skarels 	{ deprobe, 0, deattach, 0, destd, "de", deinfo };
5415357Skarels #define	DEUNIT(x)	minor(x)
5515357Skarels int	deinit(),deoutput(),deioctl(),dereset();
5615357Skarels struct	mbuf *deget();
5715357Skarels 
5815357Skarels 
5915357Skarels /*
6015357Skarels  * The following generalizes the ifuba structure
6115357Skarels  * to an arbitrary number of receive and transmit
6215357Skarels  * buffers.
6315357Skarels  */
6415357Skarels struct	deuba {
6515357Skarels 	short	ifu_uban;		/* uba number */
6615357Skarels 	short	ifu_hlen;		/* local net header length */
6715357Skarels 	struct	uba_regs *ifu_uba;	/* uba regs, in vm */
6815357Skarels 	struct	ifrw ifu_r[NRCV];	/* receive information */
6915357Skarels 	struct	ifrw ifu_w[NXMT];	/* transmit information */
7015357Skarels 				/* these should only be pointers */
7115357Skarels 	short	ifu_flags;		/* used during uballoc's */
7215357Skarels };
7315357Skarels 
7415357Skarels /*
7515357Skarels  * Ethernet software status per interface.
7615357Skarels  *
7715357Skarels  * Each interface is referenced by a network interface structure,
7815357Skarels  * ds_if, which the routing code uses to locate the interface.
7915357Skarels  * This structure contains the output queue for the interface, its address, ...
8015357Skarels  * We also have, for each interface, a UBA interface structure, which
8115357Skarels  * contains information about the UNIBUS resources held by the interface:
8215357Skarels  * map registers, buffered data paths, etc.  Information is cached in this
8315357Skarels  * structure for use by the if_uba.c routines in running the interface
8415357Skarels  * efficiently.
8515357Skarels  */
8615357Skarels struct	de_softc {
8715357Skarels 	struct	arpcom ds_ac;		/* Ethernet common part */
8815357Skarels #define	ds_if	ds_ac.ac_if		/* network-visible interface */
8915357Skarels #define	ds_addr	ds_ac.ac_enaddr		/* hardware Ethernet address */
9015357Skarels 	int	ds_flags;
9115357Skarels #define	DSF_LOCK	1		/* lock out destart */
92*15916Skarels #define	DSF_RUNNING	2
9315357Skarels 	int	ds_ubaddr;		/* map info for incore structs */
9415357Skarels 	struct	deuba ds_deuba;		/* unibus resource structure */
9515357Skarels 	/* the following structures are always mapped in */
9615357Skarels 	struct	de_pcbb ds_pcbb;	/* port control block */
9715357Skarels 	struct	de_ring ds_xrent[NXMT];	/* transmit ring entrys */
9815357Skarels 	struct	de_ring ds_rrent[NRCV];	/* receive ring entrys */
9915357Skarels 	struct	de_udbbuf ds_udbbuf;	/* UNIBUS data buffer */
10015357Skarels 	/* end mapped area */
10115357Skarels #define	INCORE_BASE(p)	((char *)&(p)->ds_pcbb)
10215357Skarels #define	RVAL_OFF(n)	((char *)&de_softc[0].n - INCORE_BASE(&de_softc[0]))
10315357Skarels #define	LVAL_OFF(n)	((char *)de_softc[0].n - INCORE_BASE(&de_softc[0]))
10415357Skarels #define	PCBB_OFFSET	RVAL_OFF(ds_pcbb)
10515357Skarels #define	XRENT_OFFSET	LVAL_OFF(ds_xrent)
10615357Skarels #define	RRENT_OFFSET	LVAL_OFF(ds_rrent)
10715357Skarels #define	UDBBUF_OFFSET	RVAL_OFF(ds_udbbuf)
10815357Skarels #define	INCORE_SIZE	RVAL_OFF(ds_xindex)
10915357Skarels 	int	ds_xindex;		/* UNA index into transmit chain */
11015357Skarels 	int	ds_rindex;		/* UNA index into receive chain */
11115357Skarels 	int	ds_xfree;		/* index for next transmit buffer */
11215357Skarels 	int	ds_nxmit;		/* # of transmits in progress */
11315357Skarels } de_softc[NDE];
11415357Skarels 
11515357Skarels deprobe(reg)
11615357Skarels 	caddr_t reg;
11715357Skarels {
11815357Skarels 	register int br, cvec;		/* r11, r10 value-result */
11915357Skarels 	register struct dedevice *addr = (struct dedevice *)reg;
12015357Skarels 	register i;
12115357Skarels 
12215357Skarels #ifdef lint
12315357Skarels 	br = 0; cvec = br; br = cvec;
12415357Skarels 	i = 0; derint(i); deintr(i);
12515357Skarels #endif
12615357Skarels 
12715357Skarels 	addr->pcsr0 = PCSR0_RSET;
12815357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
12915357Skarels 		;
13015357Skarels 	/* make board interrupt by executing a GETPCBB command */
13115357Skarels 	addr->pcsr0 = PCSR0_INTE;
13215357Skarels 	addr->pcsr2 = 0;
13315357Skarels 	addr->pcsr3 = 0;
13415357Skarels 	addr->pcsr0 = PCSR0_INTE|CMD_GETPCBB;
13515357Skarels 	DELAY(100000);
13615357Skarels 	return(1);
13715357Skarels }
13815357Skarels 
13915357Skarels /*
14015357Skarels  * Interface exists: make available by filling in network interface
14115357Skarels  * record.  System will initialize the interface when it is ready
14215357Skarels  * to accept packets.  We get the ethernet address here.
14315357Skarels  */
14415357Skarels deattach(ui)
14515357Skarels 	struct uba_device *ui;
14615357Skarels {
14715357Skarels 	register struct de_softc *ds = &de_softc[ui->ui_unit];
14815357Skarels 	register struct ifnet *ifp = &ds->ds_if;
14915357Skarels 	register struct dedevice *addr = (struct dedevice *)ui->ui_addr;
15015357Skarels 	struct sockaddr_in *sin;
15115357Skarels 	int csr0;
15215357Skarels 
15315357Skarels 	ifp->if_unit = ui->ui_unit;
15415357Skarels 	ifp->if_name = "de";
15515357Skarels 	ifp->if_mtu = ETHERMTU;
15615357Skarels 
15715357Skarels 	/*
15815357Skarels 	 * Reset the board and temporarily map
15915357Skarels 	 * the pcbb buffer onto the Unibus.
16015357Skarels 	 */
16115357Skarels 	addr->pcsr0 = PCSR0_RSET;
16215357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
16315357Skarels 		;
16415357Skarels 	csr0 = addr->pcsr0;
16515357Skarels 	addr->pchigh = csr0 >> 8;
16615357Skarels 	if (csr0 & PCSR0_PCEI)
16715357Skarels 		printf("de%d: reset failed, csr0=%b csr1=%b\n", ui->ui_unit,
16815357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
16915357Skarels 	ds->ds_ubaddr = uballoc(ui->ui_ubanum, (char *)&ds->ds_pcbb,
17015357Skarels 		sizeof (struct de_pcbb), 0);
17115357Skarels 	addr->pcsr2 = ds->ds_ubaddr & 0xffff;
17215357Skarels 	addr->pcsr3 = (ds->ds_ubaddr >> 16) & 0x3;
17315357Skarels 	addr->pclow = CMD_GETPCBB;
17415357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
17515357Skarels 		;
17615357Skarels 	csr0 = addr->pcsr0;
17715357Skarels 	addr->pchigh = csr0 >> 8;
17815357Skarels 	if (csr0 & PCSR0_PCEI)
17915357Skarels 		printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit,
18015357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
18115357Skarels 	ds->ds_pcbb.pcbb0 = FC_RDPHYAD;
18215357Skarels 	addr->pclow = CMD_GETCMD;
18315357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
18415357Skarels 		;
18515357Skarels 	csr0 = addr->pcsr0;
18615357Skarels 	addr->pchigh = csr0 >> 8;
18715357Skarels 	if (csr0 & PCSR0_PCEI)
18815357Skarels 		printf("de%d: rdphyad failed, csr0=%b csr1=%b\n", ui->ui_unit,
18915357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
19015357Skarels 	ubarelse(ui->ui_ubanum, &ds->ds_ubaddr);
191*15916Skarels 	if (dedebug)
192*15916Skarels 		printf("de%d: addr=%d:%d:%d:%d:%d:%d\n", ui->ui_unit,
193*15916Skarels 		    ds->ds_pcbb.pcbb2&0xff, (ds->ds_pcbb.pcbb2>>8)&0xff,
194*15916Skarels 		    ds->ds_pcbb.pcbb4&0xff, (ds->ds_pcbb.pcbb4>>8)&0xff,
195*15916Skarels 		    ds->ds_pcbb.pcbb6&0xff, (ds->ds_pcbb.pcbb6>>8)&0xff);
19615357Skarels 	bcopy((caddr_t)&ds->ds_pcbb.pcbb2, (caddr_t)ds->ds_addr,
19715357Skarels 	    sizeof (ds->ds_addr));
19815357Skarels 	sin = (struct sockaddr_in *)&ifp->if_addr;
19915357Skarels 	sin->sin_family = AF_INET;
20015357Skarels 	sin->sin_addr = arpmyaddr((struct arpcom *)0);
20115357Skarels 	ifp->if_init = deinit;
20215357Skarels 	ifp->if_output = deoutput;
20315357Skarels 	ifp->if_ioctl = deioctl;
20415357Skarels 	ifp->if_reset = dereset;
20515357Skarels 	ds->ds_deuba.ifu_flags = UBA_CANTWAIT;
20615357Skarels #ifdef notdef
20715357Skarels 	/* CAN WE USE BDP's ??? */
20815357Skarels 	ds->ds_deuba.ifu_flags |= UBA_NEEDBDP;
20915357Skarels #endif
21015357Skarels 	if_attach(ifp);
21115357Skarels }
21215357Skarels 
21315357Skarels /*
21415357Skarels  * Reset of interface after UNIBUS reset.
21515357Skarels  * If interface is on specified uba, reset its state.
21615357Skarels  */
21715357Skarels dereset(unit, uban)
21815357Skarels 	int unit, uban;
21915357Skarels {
22015357Skarels 	register struct uba_device *ui;
22115357Skarels 
22215357Skarels 	if (unit >= NDE || (ui = deinfo[unit]) == 0 || ui->ui_alive == 0 ||
22315357Skarels 	    ui->ui_ubanum != uban)
22415357Skarels 		return;
22515357Skarels 	printf(" de%d", unit);
226*15916Skarels 	/* NEED TO RESET IFF_RUNNING AND DSF_RUNNING? */
22715357Skarels 	deinit(unit);
22815357Skarels }
22915357Skarels 
23015357Skarels /*
23115357Skarels  * Initialization of interface; clear recorded pending
23215357Skarels  * operations, and reinitialize UNIBUS usage.
23315357Skarels  */
23415357Skarels deinit(unit)
23515357Skarels 	int unit;
23615357Skarels {
23715357Skarels 	register struct de_softc *ds = &de_softc[unit];
23815357Skarels 	register struct uba_device *ui = deinfo[unit];
23915357Skarels 	register struct dedevice *addr;
24015357Skarels 	register struct ifrw *ifrw;
24115357Skarels 	int s;
24215357Skarels 	register struct ifnet *ifp = &ds->ds_if;
24315357Skarels 	register struct sockaddr_in *sin;
24415357Skarels 	struct de_ring *rp;
24515357Skarels 	int incaddr;
24615357Skarels 	int csr0;
24715357Skarels 
24815357Skarels 	sin = (struct sockaddr_in *)&ifp->if_addr;
24915357Skarels 	if (sin->sin_addr.s_addr == 0)	/* if address still unknown */
25015357Skarels 		return;
25115357Skarels 
25215357Skarels 	if (ifp->if_flags & IFF_RUNNING)
25315357Skarels 		goto justarp;
25415357Skarels 	if (de_ubainit(&ds->ds_deuba, ui->ui_ubanum,
25515357Skarels 	    sizeof (struct ether_header), (int)btoc(ETHERMTU)) == 0) {
25615357Skarels 		printf("de%d: can't initialize\n", unit);
25715357Skarels 		ds->ds_if.if_flags &= ~IFF_UP;
25815357Skarels 		return;
25915357Skarels 	}
26015357Skarels 	ds->ds_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(ds), INCORE_SIZE,0);
26115357Skarels 	addr = (struct dedevice *)ui->ui_addr;
26215357Skarels 
26315357Skarels 	/* set the pcbb block address */
26415357Skarels 	incaddr = ds->ds_ubaddr + PCBB_OFFSET;
26515357Skarels 	addr->pcsr2 = incaddr & 0xffff;
26615357Skarels 	addr->pcsr3 = (incaddr >> 16) & 0x3;
26715357Skarels 	addr->pclow = CMD_GETPCBB;
26815357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
26915357Skarels 		;
27015357Skarels 	csr0 = addr->pcsr0;
27115357Skarels 	addr->pchigh = csr0 >> 8;
27215357Skarels 	if (csr0 & PCSR0_PCEI)
27315357Skarels 		printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit,
27415357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
27515357Skarels 
27615357Skarels 	/* set the transmit and receive ring header addresses */
27715357Skarels 	incaddr = ds->ds_ubaddr + UDBBUF_OFFSET;
27815357Skarels 	ds->ds_pcbb.pcbb0 = FC_WTRING;
27915357Skarels 	ds->ds_pcbb.pcbb2 = incaddr & 0xffff;
28015357Skarels 	ds->ds_pcbb.pcbb4 = (incaddr >> 16) & 0x3;
28115357Skarels 
28215357Skarels 	incaddr = ds->ds_ubaddr + XRENT_OFFSET;
28315357Skarels 	ds->ds_udbbuf.b_tdrbl = incaddr & 0xffff;
28415357Skarels 	ds->ds_udbbuf.b_tdrbh = (incaddr >> 16) & 0x3;
28515357Skarels 	ds->ds_udbbuf.b_telen = sizeof (struct de_ring) / sizeof (short);
28615357Skarels 	ds->ds_udbbuf.b_trlen = NXMT;
28715357Skarels 	incaddr = ds->ds_ubaddr + RRENT_OFFSET;
28815357Skarels 	ds->ds_udbbuf.b_rdrbl = incaddr & 0xffff;
28915357Skarels 	ds->ds_udbbuf.b_rdrbh = (incaddr >> 16) & 0x3;
29015357Skarels 	ds->ds_udbbuf.b_relen = sizeof (struct de_ring) / sizeof (short);
29115357Skarels 	ds->ds_udbbuf.b_rrlen = NRCV;
29215357Skarels 
29315357Skarels 	addr->pclow = CMD_GETCMD;
29415357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
29515357Skarels 		;
29615357Skarels 	csr0 = addr->pcsr0;
29715357Skarels 	addr->pchigh = csr0 >> 8;
29815357Skarels 	if (csr0 & PCSR0_PCEI)
29915357Skarels 		printf("de%d: wtring failed, csr0=%b csr1=%b\n", ui->ui_unit,
30015357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
30115357Skarels 
30215357Skarels 	/* initialize the mode - enable hardware padding */
30315357Skarels 	ds->ds_pcbb.pcbb0 = FC_WTMODE;
30415357Skarels 	/* let hardware do padding - set MTCH bit on broadcast */
30515357Skarels 	ds->ds_pcbb.pcbb2 = MOD_TPAD|MOD_HDX;
30615357Skarels 	addr->pclow = CMD_GETCMD;
30715357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
30815357Skarels 		;
30915357Skarels 	csr0 = addr->pcsr0;
31015357Skarels 	addr->pchigh = csr0 >> 8;
31115357Skarels 	if (csr0 & PCSR0_PCEI)
31215357Skarels 		printf("de%d: wtmode failed, csr0=%b csr1=%b\n", ui->ui_unit,
31315357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
31415357Skarels 
31515357Skarels 	/* set up the receive and transmit ring entries */
31615357Skarels 	ifrw = &ds->ds_deuba.ifu_w[0];
31715357Skarels 	for (rp = &ds->ds_xrent[0]; rp < &ds->ds_xrent[NXMT]; rp++) {
31815357Skarels 		rp->r_segbl = ifrw->ifrw_info & 0xffff;
31915357Skarels 		rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3;
32015357Skarels 		rp->r_flags = 0;
32115357Skarels 		ifrw++;
32215357Skarels 	}
32315357Skarels 	ifrw = &ds->ds_deuba.ifu_r[0];
32415357Skarels 	for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) {
32515357Skarels 		rp->r_slen = sizeof (struct de_buf);
32615357Skarels 		rp->r_segbl = ifrw->ifrw_info & 0xffff;
32715357Skarels 		rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3;
32815357Skarels 		rp->r_flags = RFLG_OWN;		/* hang receive */
32915357Skarels 		ifrw++;
33015357Skarels 	}
33115357Skarels 
33215357Skarels 	/* start up the board (rah rah) */
33315357Skarels 	s = splimp();
33415357Skarels 	ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = 0;
335*15916Skarels 	ds->ds_if.if_flags |= IFF_UP|IFF_RUNNING;
336*15916Skarels 	destart(unit);				/* queue output packets */
33715357Skarels 	addr->pclow = PCSR0_INTE;		/* avoid interlock */
33815357Skarels 	addr->pclow = CMD_START | PCSR0_INTE;
339*15916Skarels 	ds->ds_flags |= DSF_RUNNING;
34015357Skarels 	splx(s);
34115357Skarels justarp:
34215357Skarels 	if_rtinit(&ds->ds_if, RTF_UP);
34315357Skarels 	arpattach(&ds->ds_ac);
34415357Skarels 	arpwhohas(&ds->ds_ac, &sin->sin_addr);
34515357Skarels }
34615357Skarels 
34715357Skarels /*
34815357Skarels  * Setup output on interface.
34915357Skarels  * Get another datagram to send off of the interface queue,
35015357Skarels  * and map it to the interface before starting the output.
35115357Skarels  */
35215357Skarels destart(unit)
35315357Skarels 	int unit;
35415357Skarels {
35515357Skarels         int len;
35615357Skarels 	struct uba_device *ui = deinfo[unit];
35715357Skarels 	struct dedevice *addr = (struct dedevice *)ui->ui_addr;
35815357Skarels 	register struct de_softc *ds = &de_softc[unit];
35915357Skarels 	register struct de_ring *rp;
36015357Skarels 	struct mbuf *m;
36115357Skarels 	register int nxmit;
36215357Skarels 
36315357Skarels 	/*
36415357Skarels 	 * the following test is necessary, since
36515357Skarels 	 * the code is not reentrant and we have
36615357Skarels 	 * multiple transmission buffers.
36715357Skarels 	 */
36815357Skarels 	if (ds->ds_flags & DSF_LOCK)
36915357Skarels 		return;
37015357Skarels 	for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) {
37115357Skarels 		IF_DEQUEUE(&ds->ds_if.if_snd, m);
37215357Skarels 		if (m == 0)
37315357Skarels 			break;
37415357Skarels 		rp = &ds->ds_xrent[ds->ds_xfree];
37515357Skarels 		if (rp->r_flags & XFLG_OWN)
37615357Skarels 			panic("deuna xmit in progress");
37715357Skarels 		len = deput(&ds->ds_deuba.ifu_w[ds->ds_xfree], m);
37815357Skarels 		if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP)
37915357Skarels 			UBAPURGE(ds->ds_deuba.ifu_uba,
38015357Skarels 			ds->ds_deuba.ifu_w[ds->ds_xfree].ifrw_bdp);
38115357Skarels 		rp->r_slen = len;
38215357Skarels 		rp->r_tdrerr = 0;
38315357Skarels 		rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN;
38415357Skarels 
38515357Skarels 		ds->ds_xfree++;
38615357Skarels 		if (ds->ds_xfree == NXMT)
38715357Skarels 			ds->ds_xfree = 0;
38815357Skarels 	}
38915357Skarels 	if (ds->ds_nxmit != nxmit) {
39015357Skarels 		ds->ds_nxmit = nxmit;
391*15916Skarels 		if (ds->ds_flags & DSF_RUNNING)
39215357Skarels 			addr->pclow = PCSR0_INTE|CMD_PDMD;
39315357Skarels 	}
39415357Skarels }
39515357Skarels 
39615357Skarels /*
39715357Skarels  * Command done interrupt.
39815357Skarels  */
39915357Skarels deintr(unit)
40015357Skarels 	int unit;
40115357Skarels {
40215357Skarels 	struct uba_device *ui = deinfo[unit];
40315357Skarels 	register struct dedevice *addr = (struct dedevice *)ui->ui_addr;
40415357Skarels 	register struct de_softc *ds = &de_softc[unit];
40515357Skarels 	register struct de_ring *rp;
40615357Skarels 	short csr0;
40715357Skarels 
40815357Skarels 	/* save flags right away - clear out interrupt bits */
40915357Skarels 	csr0 = addr->pcsr0;
41015357Skarels 	addr->pchigh = csr0 >> 8;
41115357Skarels 
41215357Skarels 
41315357Skarels 	ds->ds_flags |= DSF_LOCK;	/* prevent entering destart */
41415357Skarels 	/*
41515357Skarels 	 * if receive, put receive buffer on mbuf
41615357Skarels 	 * and hang the request again
41715357Skarels 	 */
41815357Skarels 	derecv(unit);
41915357Skarels 
42015357Skarels 	/*
42115357Skarels 	 * Poll transmit ring and check status.
42215357Skarels 	 * Be careful about loopback requests.
42315357Skarels 	 * Then free buffer space and check for
42415357Skarels 	 * more transmit requests.
42515357Skarels 	 */
42615357Skarels 	for ( ; ds->ds_nxmit > 0; ds->ds_nxmit--) {
42715357Skarels 		rp = &ds->ds_xrent[ds->ds_xindex];
42815357Skarels 		if (rp->r_flags & XFLG_OWN)
42915357Skarels 			break;
43015357Skarels 		ds->ds_if.if_opackets++;
43115357Skarels 		/* check for unusual conditions */
43215357Skarels 		if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) {
43315357Skarels 			if (rp->r_flags & XFLG_ERRS) {
43415357Skarels 				/* output error */
43515357Skarels 				ds->ds_if.if_oerrors++;
436*15916Skarels 				if (dedebug)
43715357Skarels 			printf("de%d: oerror, flags=%b tdrerr=%b (len=%d)\n",
43815357Skarels 				    unit, rp->r_flags, XFLG_BITS,
43915357Skarels 				    rp->r_tdrerr, XERR_BITS, rp->r_slen);
44015357Skarels 			} else if (rp->r_flags & XFLG_ONE) {
44115357Skarels 				/* one collision */
44215357Skarels 				ds->ds_if.if_collisions++;
44315357Skarels 			} else if (rp->r_flags & XFLG_MORE) {
44415357Skarels 				/* more than one collision */
44515357Skarels 				ds->ds_if.if_collisions += 2;	/* guess */
44615357Skarels 			} else if (rp->r_flags & XFLG_MTCH) {
44715357Skarels 				/* received our own packet */
44815357Skarels 				ds->ds_if.if_ipackets++;
44915357Skarels 				deread(ds, &ds->ds_deuba.ifu_w[ds->ds_xindex],
45015357Skarels 				    rp->r_slen - sizeof (struct ether_header));
45115357Skarels 			}
45215357Skarels 		}
45315357Skarels 		/* check if next transmit buffer also finished */
45415357Skarels 		ds->ds_xindex++;
45515357Skarels 		if (ds->ds_xindex == NXMT)
45615357Skarels 			ds->ds_xindex = 0;
45715357Skarels 	}
45815357Skarels 	ds->ds_flags &= ~DSF_LOCK;
45915357Skarels 	destart(unit);
46015357Skarels 
46115357Skarels 	if (csr0 & PCSR0_RCBI) {
46215357Skarels 		printf("de%d: buffer unavailable\n", unit);
46315357Skarels 		addr->pclow = PCSR0_INTE|CMD_PDMD;
46415357Skarels 	}
46515357Skarels }
46615357Skarels 
46715357Skarels /*
46815357Skarels  * Ethernet interface receiver interface.
46915357Skarels  * If input error just drop packet.
47015357Skarels  * Otherwise purge input buffered data path and examine
47115357Skarels  * packet to determine type.  If can't determine length
47215357Skarels  * from type, then have to drop packet.  Othewise decapsulate
47315357Skarels  * packet based on type and pass to type specific higher-level
47415357Skarels  * input routine.
47515357Skarels  */
47615357Skarels derecv(unit)
47715357Skarels 	int unit;
47815357Skarels {
47915357Skarels 	register struct de_softc *ds = &de_softc[unit];
48015357Skarels 	register struct de_ring *rp;
48115357Skarels 	int len;
48215357Skarels 
48315357Skarels 	rp = &ds->ds_rrent[ds->ds_rindex];
48415357Skarels 	while ((rp->r_flags & RFLG_OWN) == 0) {
48515357Skarels 		ds->ds_if.if_ipackets++;
48615357Skarels 		if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP)
48715357Skarels 			UBAPURGE(ds->ds_deuba.ifu_uba,
48815357Skarels 			ds->ds_deuba.ifu_r[ds->ds_rindex].ifrw_bdp);
48915357Skarels 		len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header)
49015357Skarels 			- 4;	/* don't forget checksum! */
49115357Skarels 		/* check for errors */
49215357Skarels 		if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) ||
49315357Skarels 		    (rp->r_flags&(RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP) ||
49415357Skarels 		    (rp->r_lenerr & (RERR_BUFL|RERR_UBTO|RERR_NCHN)) ||
49515357Skarels 		    len < ETHERMIN || len > ETHERMTU) {
49615357Skarels 			ds->ds_if.if_ierrors++;
497*15916Skarels 			if (dedebug)
49815357Skarels 			printf("de%d: ierror, flags=%b lenerr=%b (len=%d)\n",
49915357Skarels 				unit, rp->r_flags, RFLG_BITS, rp->r_lenerr,
50015357Skarels 				RERR_BITS, len);
50115357Skarels 		} else
50215357Skarels 			deread(ds, &ds->ds_deuba.ifu_r[ds->ds_rindex], len);
50315357Skarels 
50415357Skarels 		/* hang the receive buffer again */
50515357Skarels 		rp->r_lenerr = 0;
50615357Skarels 		rp->r_flags = RFLG_OWN;
50715357Skarels 
50815357Skarels 		/* check next receive buffer */
50915357Skarels 		ds->ds_rindex++;
51015357Skarels 		if (ds->ds_rindex == NRCV)
51115357Skarels 			ds->ds_rindex = 0;
51215357Skarels 		rp = &ds->ds_rrent[ds->ds_rindex];
51315357Skarels 	}
51415357Skarels }
51515357Skarels 
51615357Skarels /*
51715357Skarels  * Pass a packet to the higher levels.
51815357Skarels  * We deal with the trailer protocol here.
51915357Skarels  */
52015357Skarels deread(ds, ifrw, len)
52115357Skarels 	register struct de_softc *ds;
52215357Skarels 	struct ifrw *ifrw;
52315357Skarels 	int len;
52415357Skarels {
52515357Skarels 	struct ether_header *eh;
52615357Skarels     	struct mbuf *m;
52715357Skarels 	int off, resid;
52815357Skarels 	register struct ifqueue *inq;
52915357Skarels 
53015357Skarels 	/*
53115357Skarels 	 * Deal with trailer protocol: if type is PUP trailer
53215357Skarels 	 * get true type from first 16-bit word past data.
53315357Skarels 	 * Remember that type was trailer by setting off.
53415357Skarels 	 */
53515357Skarels 	eh = (struct ether_header *)ifrw->ifrw_addr;
53615357Skarels 	eh->ether_type = ntohs((u_short)eh->ether_type);
53715357Skarels #define	dedataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
53815357Skarels 	if (eh->ether_type >= ETHERPUP_TRAIL &&
53915357Skarels 	    eh->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
54015357Skarels 		off = (eh->ether_type - ETHERPUP_TRAIL) * 512;
54115357Skarels 		if (off >= ETHERMTU)
54215357Skarels 			return;		/* sanity */
54315357Skarels 		eh->ether_type = ntohs(*dedataaddr(eh, off, u_short *));
54415357Skarels 		resid = ntohs(*(dedataaddr(eh, off+2, u_short *)));
54515357Skarels 		if (off + resid > len)
54615357Skarels 			return;		/* sanity */
54715357Skarels 		len = off + resid;
54815357Skarels 	} else
54915357Skarels 		off = 0;
55015357Skarels 	if (len == 0)
55115357Skarels 		return;
55215357Skarels 
55315357Skarels 	/*
55415357Skarels 	 * Pull packet off interface.  Off is nonzero if packet
55515357Skarels 	 * has trailing header; deget will then force this header
55615357Skarels 	 * information to be at the front, but we still have to drop
55715357Skarels 	 * the type and length which are at the front of any trailer data.
55815357Skarels 	 */
55915357Skarels 	m = deget(&ds->ds_deuba, ifrw, len, off);
56015357Skarels 	if (m == 0)
56115357Skarels 		return;
56215357Skarels 	if (off) {
56315357Skarels 		m->m_off += 2 * sizeof (u_short);
56415357Skarels 		m->m_len -= 2 * sizeof (u_short);
56515357Skarels 	}
56615357Skarels 	switch (eh->ether_type) {
56715357Skarels 
56815357Skarels #ifdef INET
56915357Skarels 	case ETHERPUP_IPTYPE:
57015357Skarels 		schednetisr(NETISR_IP);
57115357Skarels 		inq = &ipintrq;
57215357Skarels 		break;
57315357Skarels 
57415357Skarels 	case ETHERPUP_ARPTYPE:
57515357Skarels 		arpinput(&ds->ds_ac, m);
57615357Skarels 		return;
57715357Skarels #endif
57815357Skarels 	default:
57915357Skarels 		m_freem(m);
58015357Skarels 		return;
58115357Skarels 	}
58215357Skarels 
58315357Skarels 	if (IF_QFULL(inq)) {
58415357Skarels 		IF_DROP(inq);
58515357Skarels 		m_freem(m);
58615357Skarels 		return;
58715357Skarels 	}
58815357Skarels 	IF_ENQUEUE(inq, m);
58915357Skarels }
59015357Skarels 
59115357Skarels /*
59215357Skarels  * Ethernet output routine.
59315357Skarels  * Encapsulate a packet of type family for the local net.
59415357Skarels  * Use trailer local net encapsulation if enough data in first
59515357Skarels  * packet leaves a multiple of 512 bytes of data in remainder.
59615357Skarels  */
59715357Skarels deoutput(ifp, m0, dst)
59815357Skarels 	struct ifnet *ifp;
59915357Skarels 	struct mbuf *m0;
60015357Skarels 	struct sockaddr *dst;
60115357Skarels {
60215357Skarels 	int type, s, error;
60315357Skarels 	u_char edst[6];
60415357Skarels 	struct in_addr idst;
60515357Skarels 	register struct de_softc *ds = &de_softc[ifp->if_unit];
60615357Skarels 	register struct mbuf *m = m0;
60715357Skarels 	register struct ether_header *eh;
60815357Skarels 	register int off;
60915357Skarels 
61015357Skarels 	switch (dst->sa_family) {
61115357Skarels 
61215357Skarels #ifdef INET
61315357Skarels 	case AF_INET:
61415357Skarels 		idst = ((struct sockaddr_in *)dst)->sin_addr;
61515357Skarels 		if (!arpresolve(&ds->ds_ac, m, &idst, edst))
61615357Skarels 			return (0);	/* if not yet resolved */
61715357Skarels 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
61815357Skarels 		/* need per host negotiation */
61915357Skarels 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
62015357Skarels 		if (off > 0 && (off & 0x1ff) == 0 &&
62115357Skarels 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
62215357Skarels 			type = ETHERPUP_TRAIL + (off>>9);
62315357Skarels 			m->m_off -= 2 * sizeof (u_short);
62415357Skarels 			m->m_len += 2 * sizeof (u_short);
62515357Skarels 			*mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
62615357Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
62715357Skarels 			goto gottrailertype;
62815357Skarels 		}
62915357Skarels 		type = ETHERPUP_IPTYPE;
63015357Skarels 		off = 0;
63115357Skarels 		goto gottype;
63215357Skarels #endif
63315357Skarels 
63415357Skarels 	case AF_UNSPEC:
63515357Skarels 		eh = (struct ether_header *)dst->sa_data;
63615357Skarels 		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
63715357Skarels 		type = eh->ether_type;
63815357Skarels 		goto gottype;
63915357Skarels 
64015357Skarels 	default:
64115357Skarels 		printf("de%d: can't handle af%d\n", ifp->if_unit,
64215357Skarels 			dst->sa_family);
64315357Skarels 		error = EAFNOSUPPORT;
64415357Skarels 		goto bad;
64515357Skarels 	}
64615357Skarels 
64715357Skarels gottrailertype:
64815357Skarels 	/*
64915357Skarels 	 * Packet to be sent as trailer: move first packet
65015357Skarels 	 * (control information) to end of chain.
65115357Skarels 	 */
65215357Skarels 	while (m->m_next)
65315357Skarels 		m = m->m_next;
65415357Skarels 	m->m_next = m0;
65515357Skarels 	m = m0->m_next;
65615357Skarels 	m0->m_next = 0;
65715357Skarels 	m0 = m;
65815357Skarels 
65915357Skarels gottype:
66015357Skarels 	/*
66115357Skarels 	 * Add local net header.  If no space in first mbuf,
66215357Skarels 	 * allocate another.
66315357Skarels 	 */
66415357Skarels 	if (m->m_off > MMAXOFF ||
66515357Skarels 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
66615357Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
66715357Skarels 		if (m == 0) {
66815357Skarels 			error = ENOBUFS;
66915357Skarels 			goto bad;
67015357Skarels 		}
67115357Skarels 		m->m_next = m0;
67215357Skarels 		m->m_off = MMINOFF;
67315357Skarels 		m->m_len = sizeof (struct ether_header);
67415357Skarels 	} else {
67515357Skarels 		m->m_off -= sizeof (struct ether_header);
67615357Skarels 		m->m_len += sizeof (struct ether_header);
67715357Skarels 	}
67815357Skarels 	eh = mtod(m, struct ether_header *);
67915357Skarels 	eh->ether_type = htons((u_short)type);
68015357Skarels 	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
68115357Skarels 	/* DEUNA fills in source address */
68215357Skarels 
68315357Skarels 	/*
68415357Skarels 	 * Queue message on interface, and start output if interface
68515357Skarels 	 * not yet active.
68615357Skarels 	 */
68715357Skarels 	s = splimp();
68815357Skarels 	if (IF_QFULL(&ifp->if_snd)) {
68915357Skarels 		IF_DROP(&ifp->if_snd);
69015357Skarels 		splx(s);
69115357Skarels 		m_freem(m);
69215357Skarels 		return (ENOBUFS);
69315357Skarels 	}
69415357Skarels 	IF_ENQUEUE(&ifp->if_snd, m);
69515357Skarels 	destart(ifp->if_unit);
69615357Skarels 	splx(s);
69715357Skarels 	return (0);
69815357Skarels 
69915357Skarels bad:
70015357Skarels 	m_freem(m0);
70115357Skarels 	return (error);
70215357Skarels }
70315357Skarels 
70415357Skarels /*
70515357Skarels  * Routines supporting UNIBUS network interfaces.
70615357Skarels  */
70715357Skarels 
70815357Skarels /*
70915357Skarels  * Init UNIBUS for interface on uban whose headers of size hlen are to
71015357Skarels  * end on a page boundary.  We allocate a UNIBUS map register for the page
71115357Skarels  * with the header, and nmr more UNIBUS map registers for i/o on the adapter,
71215357Skarels  * doing this for each receive and transmit buffer.  We also
71315357Skarels  * allocate page frames in the mbuffer pool for these pages.
71415357Skarels  */
71515357Skarels de_ubainit(ifu, uban, hlen, nmr)
71615357Skarels 	register struct deuba *ifu;
71715357Skarels 	int uban, hlen, nmr;
71815357Skarels {
71915357Skarels 	register caddr_t cp, dp;
72015357Skarels 	register struct ifrw *ifrw;
72115357Skarels 	int ncl;
72215357Skarels 
72315357Skarels 	ncl = clrnd(nmr + CLSIZE) / CLSIZE;
72415357Skarels 	if (ifu->ifu_r[0].ifrw_addr)
72515357Skarels 		/*
72615357Skarels 		 * If the first read buffer has a non-zero
72715357Skarels 		 * address, it means we have already allocated core
72815357Skarels 		 */
72915357Skarels 		cp = ifu->ifu_r[0].ifrw_addr - (CLBYTES - hlen);
73015357Skarels 	else {
73115357Skarels 		cp = m_clalloc(NTOT * ncl, MPG_SPACE);
73215357Skarels 		if (cp == 0)
73315357Skarels 			return (0);
73415357Skarels 		ifu->ifu_hlen = hlen;
73515357Skarels 		ifu->ifu_uban = uban;
73615357Skarels 		ifu->ifu_uba = uba_hd[uban].uh_uba;
73715357Skarels 		dp = cp + CLBYTES - hlen;
73815357Skarels 		for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) {
73915357Skarels 			ifrw->ifrw_addr = dp;
74015357Skarels 			dp += ncl * CLBYTES;
74115357Skarels 		}
74215357Skarels 		for (ifrw = ifu->ifu_w; ifrw < &ifu->ifu_w[NXMT]; ifrw++) {
74315357Skarels 			ifrw->ifrw_addr = dp;
74415357Skarels 			dp += ncl * CLBYTES;
74515357Skarels 		}
74615357Skarels 	}
74715357Skarels 	/* allocate for receive ring */
74815357Skarels 	for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) {
74915357Skarels 		if (de_ubaalloc(ifu, ifrw, nmr) == 0) {
75015357Skarels 			struct ifrw *if2;
75115357Skarels 
75215357Skarels 			for (if2 = ifu->ifu_r; if2 < ifrw; if2++)
75315357Skarels 				ubarelse(ifu->ifu_uban, &if2->ifrw_info);
75415357Skarels 			goto bad;
75515357Skarels 		}
75615357Skarels 	}
75715357Skarels 	/* and now transmit ring */
75815357Skarels 	for (ifrw = ifu->ifu_w; ifrw < &ifu->ifu_w[NXMT]; ifrw++) {
75915357Skarels 		if (de_ubaalloc(ifu, ifrw, nmr) == 0) {
76015357Skarels 			struct ifrw *if2;
76115357Skarels 
76215357Skarels 			for (if2 = ifu->ifu_w; if2 < ifrw; if2++)
76315357Skarels 				ubarelse(ifu->ifu_uban, &if2->ifrw_info);
76415357Skarels 			for (if2 = ifu->ifu_r; if2 < &ifu->ifu_r[NRCV]; if2++)
76515357Skarels 				ubarelse(ifu->ifu_uban, &if2->ifrw_info);
76615357Skarels 			goto bad;
76715357Skarels 		}
76815357Skarels 	}
76915357Skarels 	return (1);
77015357Skarels bad:
77115357Skarels 	m_pgfree(cp, NTOT * ncl);
77215357Skarels 	ifu->ifu_r[0].ifrw_addr = 0;
77315357Skarels 	return(0);
77415357Skarels }
77515357Skarels 
77615357Skarels /*
77715357Skarels  * Setup either a ifrw structure by allocating UNIBUS map registers,
77815357Skarels  * possibly a buffered data path, and initializing the fields of
77915357Skarels  * the ifrw structure to minimize run-time overhead.
78015357Skarels  */
78115357Skarels static
78215357Skarels de_ubaalloc(ifu, ifrw, nmr)
78315357Skarels 	struct deuba *ifu;
78415357Skarels 	register struct ifrw *ifrw;
78515357Skarels 	int nmr;
78615357Skarels {
78715357Skarels 	register int info;
78815357Skarels 
78915357Skarels 	info =
79015357Skarels 	    uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen,
79115357Skarels 	        ifu->ifu_flags);
79215357Skarels 	if (info == 0)
79315357Skarels 		return (0);
79415357Skarels 	ifrw->ifrw_info = info;
79515357Skarels 	ifrw->ifrw_bdp = UBAI_BDP(info);
79615357Skarels 	ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT);
79715357Skarels 	ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1];
79815357Skarels 	return (1);
79915357Skarels }
80015357Skarels 
80115357Skarels /*
80215357Skarels  * Pull read data off a interface.
80315357Skarels  * Len is length of data, with local net header stripped.
80415357Skarels  * Off is non-zero if a trailer protocol was used, and
80515357Skarels  * gives the offset of the trailer information.
80615357Skarels  * We copy the trailer information and then all the normal
80715357Skarels  * data into mbufs.  When full cluster sized units are present
80815357Skarels  * on the interface on cluster boundaries we can get them more
80915357Skarels  * easily by remapping, and take advantage of this here.
81015357Skarels  */
81115357Skarels struct mbuf *
81215357Skarels deget(ifu, ifrw, totlen, off0)
81315357Skarels 	register struct deuba *ifu;
81415357Skarels 	register struct ifrw *ifrw;
81515357Skarels 	int totlen, off0;
81615357Skarels {
81715357Skarels 	struct mbuf *top, **mp, *m;
81815357Skarels 	int off = off0, len;
81915357Skarels 	register caddr_t cp = ifrw->ifrw_addr + ifu->ifu_hlen;
82015357Skarels 
82115357Skarels 	top = 0;
82215357Skarels 	mp = &top;
82315357Skarels 	while (totlen > 0) {
82415357Skarels 		MGET(m, M_DONTWAIT, MT_DATA);
82515357Skarels 		if (m == 0)
82615357Skarels 			goto bad;
82715357Skarels 		if (off) {
82815357Skarels 			len = totlen - off;
82915357Skarels 			cp = ifrw->ifrw_addr + ifu->ifu_hlen + off;
83015357Skarels 		} else
83115357Skarels 			len = totlen;
83215357Skarels 		if (len >= CLBYTES) {
83315357Skarels 			struct mbuf *p;
83415357Skarels 			struct pte *cpte, *ppte;
83515357Skarels 			int x, *ip, i;
83615357Skarels 
83715357Skarels 			MCLGET(p, 1);
83815357Skarels 			if (p == 0)
83915357Skarels 				goto nopage;
84015357Skarels 			len = m->m_len = CLBYTES;
84115357Skarels 			m->m_off = (int)p - (int)m;
84215357Skarels 			if (!claligned(cp))
84315357Skarels 				goto copy;
84415357Skarels 
84515357Skarels 			/*
84615357Skarels 			 * Switch pages mapped to UNIBUS with new page p,
84715357Skarels 			 * as quick form of copy.  Remap UNIBUS and invalidate.
84815357Skarels 			 */
84915357Skarels 			cpte = &Mbmap[mtocl(cp)*CLSIZE];
85015357Skarels 			ppte = &Mbmap[mtocl(p)*CLSIZE];
85115357Skarels 			x = btop(cp - ifrw->ifrw_addr);
85215357Skarels 			ip = (int *)&ifrw->ifrw_mr[x];
85315357Skarels 			for (i = 0; i < CLSIZE; i++) {
85415357Skarels 				struct pte t;
85515357Skarels 				t = *ppte; *ppte++ = *cpte; *cpte = t;
85615357Skarels 				*ip++ =
85715357Skarels 				    cpte++->pg_pfnum|ifrw->ifrw_proto;
85815357Skarels 				mtpr(TBIS, cp);
85915357Skarels 				cp += NBPG;
86015357Skarels 				mtpr(TBIS, (caddr_t)p);
86115357Skarels 				p += NBPG / sizeof (*p);
86215357Skarels 			}
86315357Skarels 			goto nocopy;
86415357Skarels 		}
86515357Skarels nopage:
86615357Skarels 		m->m_len = MIN(MLEN, len);
86715357Skarels 		m->m_off = MMINOFF;
86815357Skarels copy:
86915357Skarels 		bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len);
87015357Skarels 		cp += m->m_len;
87115357Skarels nocopy:
87215357Skarels 		*mp = m;
87315357Skarels 		mp = &m->m_next;
87415357Skarels 		if (off) {
87515357Skarels 			/* sort of an ALGOL-W style for statement... */
87615357Skarels 			off += m->m_len;
87715357Skarels 			if (off == totlen) {
87815357Skarels 				cp = ifrw->ifrw_addr + ifu->ifu_hlen;
87915357Skarels 				off = 0;
88015357Skarels 				totlen = off0;
88115357Skarels 			}
88215357Skarels 		} else
88315357Skarels 			totlen -= m->m_len;
88415357Skarels 	}
88515357Skarels 	return (top);
88615357Skarels bad:
88715357Skarels 	m_freem(top);
88815357Skarels 	return (0);
88915357Skarels }
89015357Skarels 
89115357Skarels /*
89215357Skarels  * Map a chain of mbufs onto a network interface
89315357Skarels  * in preparation for an i/o operation.
89415357Skarels  * The argument chain of mbufs includes the local network
89515357Skarels  * header which is copied to be in the mapped, aligned
89615357Skarels  * i/o space.
89715357Skarels  *
89815357Skarels  * This routine is unlike if_wubaput in that pages are
89915357Skarels  * actually switched, rather than the UNIBUS maps temporarily
90015357Skarels  * remapped.
90115357Skarels  */
90215357Skarels deput(ifrw, m)
90315357Skarels 	register struct ifrw *ifrw;
90415357Skarels 	register struct mbuf *m;
90515357Skarels {
90615357Skarels 	register struct mbuf *mp;
90715357Skarels 	register caddr_t cp;
90815357Skarels 	int cc;
90915357Skarels 	register caddr_t dp;
91015357Skarels 	register int i;
91115357Skarels 	int x;
91215357Skarels 
91315357Skarels 	cp = ifrw->ifrw_addr;
91415357Skarels 	while (m) {
91515357Skarels 		dp = mtod(m, char *);
91615357Skarels 		if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) {
91715357Skarels 			struct pte *cpte, *ppte;
91815357Skarels 			int *ip;
91915357Skarels 
92015357Skarels 			cpte = &Mbmap[mtocl(cp)*CLSIZE];
92115357Skarels 			ppte = &Mbmap[mtocl(dp)*CLSIZE];
92215357Skarels 			x = btop(cp - ifrw->ifrw_addr);
92315357Skarels 			ip = (int *)&ifrw->ifrw_mr[x];
92415357Skarels 			for (i = 0; i < CLSIZE; i++) {
92515357Skarels 				struct pte t;
92615357Skarels 				t = *ppte; *ppte++ = *cpte; *cpte = t;
92715357Skarels 				*ip++ =
92815357Skarels 				    cpte++->pg_pfnum|ifrw->ifrw_proto;
92915357Skarels 				mtpr(TBIS, cp);
93015357Skarels 				cp += NBPG;
93115357Skarels 				mtpr(TBIS, dp);
93215357Skarels 				dp += NBPG;
93315357Skarels 			}
93415357Skarels 		} else {
93515357Skarels 			bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
93615357Skarels 			cp += m->m_len;
93715357Skarels 		}
93815357Skarels 		MFREE(m, mp);
93915357Skarels 		m = mp;
94015357Skarels 	}
94115357Skarels 
94215357Skarels 	cc = cp - ifrw->ifrw_addr;
94315357Skarels 	return (cc);
94415357Skarels }
94515357Skarels #endif
94615357Skarels 
94715357Skarels /*
94815357Skarels  * Process an ioctl request.
94915357Skarels  */
95015357Skarels deioctl(ifp, cmd, data)
95115357Skarels 	register struct ifnet *ifp;
95215357Skarels 	int cmd;
95315357Skarels 	caddr_t data;
95415357Skarels {
95515357Skarels 	register struct ifreq *ifr = (struct ifreq *)data;
95615357Skarels 	int s = splimp(), error = 0;
95715357Skarels 
95815357Skarels 	switch (cmd) {
95915357Skarels 
96015357Skarels 	case SIOCSIFADDR:
96115357Skarels 		if (ifp->if_flags & IFF_RUNNING)
96215357Skarels 			if_rtinit(ifp, -1);	/* delete previous route */
96315357Skarels 		desetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
96415357Skarels 		deinit(ifp->if_unit);
96515357Skarels 		break;
96615357Skarels 
96715357Skarels 	default:
96815357Skarels 		error = EINVAL;
96915357Skarels 	}
97015357Skarels 	splx(s);
97115357Skarels 	return (error);
97215357Skarels }
97315357Skarels 
97415357Skarels desetaddr(ifp, sin)
97515357Skarels 	register struct ifnet *ifp;
97615357Skarels 	register struct sockaddr_in *sin;
97715357Skarels {
97815357Skarels 
97915357Skarels 	ifp->if_addr = *(struct sockaddr *)sin;
98015357Skarels 	ifp->if_net = in_netof(sin->sin_addr);
98115357Skarels 	ifp->if_host[0] = in_lnaof(sin->sin_addr);
98215357Skarels 	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
98315357Skarels 	sin->sin_family = AF_INET;
98415357Skarels 	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
98515357Skarels 	ifp->if_flags |= IFF_BROADCAST;
98615357Skarels }
987