xref: /csrg-svn/sys/vax/if/if_de.c (revision 16247)
1*16247Skarels /*	if_de.c	6.4	84/03/27	*/
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*16247Skarels int	dedebug = 1;
4815916Skarels 
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 /*
6016208Skarels  * The deuba structures generalizes the ifuba structure
6116208Skarels  * to an arbitrary number of receive and transmit buffers.
6215357Skarels  */
6316208Skarels struct	ifxmt {
6416208Skarels 	struct	ifrw x_ifrw;			/* mapping information */
6516208Skarels 	struct	pte x_map[IF_MAXNUBAMR];	/* output base pages */
6616208Skarels 	short	x_xswapd;			/* mask of clusters swapped */
6716208Skarels 	struct	mbuf *x_xtofree;		/* pages being dma'ed out */
6816208Skarels };
6916208Skarels 
7015357Skarels struct	deuba {
7115357Skarels 	short	ifu_uban;		/* uba number */
7215357Skarels 	short	ifu_hlen;		/* local net header length */
7315357Skarels 	struct	uba_regs *ifu_uba;	/* uba regs, in vm */
7415357Skarels 	struct	ifrw ifu_r[NRCV];	/* receive information */
7516208Skarels 	struct	ifxmt ifu_w[NXMT];	/* transmit information */
7615357Skarels 	short	ifu_flags;		/* used during uballoc's */
7715357Skarels };
7815357Skarels 
7915357Skarels /*
8015357Skarels  * Ethernet software status per interface.
8115357Skarels  *
8215357Skarels  * Each interface is referenced by a network interface structure,
8315357Skarels  * ds_if, which the routing code uses to locate the interface.
8415357Skarels  * This structure contains the output queue for the interface, its address, ...
8515357Skarels  * We also have, for each interface, a UBA interface structure, which
8615357Skarels  * contains information about the UNIBUS resources held by the interface:
8715357Skarels  * map registers, buffered data paths, etc.  Information is cached in this
8815357Skarels  * structure for use by the if_uba.c routines in running the interface
8915357Skarels  * efficiently.
9015357Skarels  */
9115357Skarels struct	de_softc {
9215357Skarels 	struct	arpcom ds_ac;		/* Ethernet common part */
9315357Skarels #define	ds_if	ds_ac.ac_if		/* network-visible interface */
9415357Skarels #define	ds_addr	ds_ac.ac_enaddr		/* hardware Ethernet address */
9515357Skarels 	int	ds_flags;
9615357Skarels #define	DSF_LOCK	1		/* lock out destart */
9715916Skarels #define	DSF_RUNNING	2
9815357Skarels 	int	ds_ubaddr;		/* map info for incore structs */
9915357Skarels 	struct	deuba ds_deuba;		/* unibus resource structure */
10015357Skarels 	/* the following structures are always mapped in */
10115357Skarels 	struct	de_pcbb ds_pcbb;	/* port control block */
10215357Skarels 	struct	de_ring ds_xrent[NXMT];	/* transmit ring entrys */
10315357Skarels 	struct	de_ring ds_rrent[NRCV];	/* receive ring entrys */
10415357Skarels 	struct	de_udbbuf ds_udbbuf;	/* UNIBUS data buffer */
10515357Skarels 	/* end mapped area */
10615357Skarels #define	INCORE_BASE(p)	((char *)&(p)->ds_pcbb)
10715357Skarels #define	RVAL_OFF(n)	((char *)&de_softc[0].n - INCORE_BASE(&de_softc[0]))
10815357Skarels #define	LVAL_OFF(n)	((char *)de_softc[0].n - INCORE_BASE(&de_softc[0]))
10915357Skarels #define	PCBB_OFFSET	RVAL_OFF(ds_pcbb)
11015357Skarels #define	XRENT_OFFSET	LVAL_OFF(ds_xrent)
11115357Skarels #define	RRENT_OFFSET	LVAL_OFF(ds_rrent)
11215357Skarels #define	UDBBUF_OFFSET	RVAL_OFF(ds_udbbuf)
11315357Skarels #define	INCORE_SIZE	RVAL_OFF(ds_xindex)
11415357Skarels 	int	ds_xindex;		/* UNA index into transmit chain */
11515357Skarels 	int	ds_rindex;		/* UNA index into receive chain */
11615357Skarels 	int	ds_xfree;		/* index for next transmit buffer */
11715357Skarels 	int	ds_nxmit;		/* # of transmits in progress */
11815357Skarels } de_softc[NDE];
11915357Skarels 
12015357Skarels deprobe(reg)
12115357Skarels 	caddr_t reg;
12215357Skarels {
12315357Skarels 	register int br, cvec;		/* r11, r10 value-result */
12415357Skarels 	register struct dedevice *addr = (struct dedevice *)reg;
12515357Skarels 	register i;
12615357Skarels 
12715357Skarels #ifdef lint
12815357Skarels 	br = 0; cvec = br; br = cvec;
12915357Skarels 	i = 0; derint(i); deintr(i);
13015357Skarels #endif
13115357Skarels 
13215357Skarels 	addr->pcsr0 = PCSR0_RSET;
13315357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
13415357Skarels 		;
13515357Skarels 	/* make board interrupt by executing a GETPCBB command */
13615357Skarels 	addr->pcsr0 = PCSR0_INTE;
13715357Skarels 	addr->pcsr2 = 0;
13815357Skarels 	addr->pcsr3 = 0;
13915357Skarels 	addr->pcsr0 = PCSR0_INTE|CMD_GETPCBB;
14015357Skarels 	DELAY(100000);
14115357Skarels 	return(1);
14215357Skarels }
14315357Skarels 
14415357Skarels /*
14515357Skarels  * Interface exists: make available by filling in network interface
14615357Skarels  * record.  System will initialize the interface when it is ready
14715357Skarels  * to accept packets.  We get the ethernet address here.
14815357Skarels  */
14915357Skarels deattach(ui)
15015357Skarels 	struct uba_device *ui;
15115357Skarels {
15215357Skarels 	register struct de_softc *ds = &de_softc[ui->ui_unit];
15315357Skarels 	register struct ifnet *ifp = &ds->ds_if;
15415357Skarels 	register struct dedevice *addr = (struct dedevice *)ui->ui_addr;
15515357Skarels 	struct sockaddr_in *sin;
15615357Skarels 	int csr0;
15715357Skarels 
15815357Skarels 	ifp->if_unit = ui->ui_unit;
15915357Skarels 	ifp->if_name = "de";
16015357Skarels 	ifp->if_mtu = ETHERMTU;
16115357Skarels 
16215357Skarels 	/*
16315357Skarels 	 * Reset the board and temporarily map
16415357Skarels 	 * the pcbb buffer onto the Unibus.
16515357Skarels 	 */
16615357Skarels 	addr->pcsr0 = PCSR0_RSET;
16715357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
16815357Skarels 		;
16915357Skarels 	csr0 = addr->pcsr0;
17015357Skarels 	addr->pchigh = csr0 >> 8;
17115357Skarels 	if (csr0 & PCSR0_PCEI)
17215357Skarels 		printf("de%d: reset failed, csr0=%b csr1=%b\n", ui->ui_unit,
17315357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
17415357Skarels 	ds->ds_ubaddr = uballoc(ui->ui_ubanum, (char *)&ds->ds_pcbb,
17515357Skarels 		sizeof (struct de_pcbb), 0);
17615357Skarels 	addr->pcsr2 = ds->ds_ubaddr & 0xffff;
17715357Skarels 	addr->pcsr3 = (ds->ds_ubaddr >> 16) & 0x3;
17815357Skarels 	addr->pclow = CMD_GETPCBB;
17915357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
18015357Skarels 		;
18115357Skarels 	csr0 = addr->pcsr0;
18215357Skarels 	addr->pchigh = csr0 >> 8;
18315357Skarels 	if (csr0 & PCSR0_PCEI)
18415357Skarels 		printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit,
18515357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
18615357Skarels 	ds->ds_pcbb.pcbb0 = FC_RDPHYAD;
18715357Skarels 	addr->pclow = CMD_GETCMD;
18815357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
18915357Skarels 		;
19015357Skarels 	csr0 = addr->pcsr0;
19115357Skarels 	addr->pchigh = csr0 >> 8;
19215357Skarels 	if (csr0 & PCSR0_PCEI)
19315357Skarels 		printf("de%d: rdphyad failed, csr0=%b csr1=%b\n", ui->ui_unit,
19415357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
19515357Skarels 	ubarelse(ui->ui_ubanum, &ds->ds_ubaddr);
19615916Skarels 	if (dedebug)
19715916Skarels 		printf("de%d: addr=%d:%d:%d:%d:%d:%d\n", ui->ui_unit,
19815916Skarels 		    ds->ds_pcbb.pcbb2&0xff, (ds->ds_pcbb.pcbb2>>8)&0xff,
19915916Skarels 		    ds->ds_pcbb.pcbb4&0xff, (ds->ds_pcbb.pcbb4>>8)&0xff,
20015916Skarels 		    ds->ds_pcbb.pcbb6&0xff, (ds->ds_pcbb.pcbb6>>8)&0xff);
201*16247Skarels 	bcopy((caddr_t)&ds->ds_pcbb.pcbb2, (caddr_t)&ds->ds_addr,
20215357Skarels 	    sizeof (ds->ds_addr));
20315357Skarels 	sin = (struct sockaddr_in *)&ifp->if_addr;
20415357Skarels 	sin->sin_family = AF_INET;
20515357Skarels 	ifp->if_init = deinit;
20615357Skarels 	ifp->if_output = deoutput;
20715357Skarels 	ifp->if_ioctl = deioctl;
20815357Skarels 	ifp->if_reset = dereset;
20915357Skarels 	ds->ds_deuba.ifu_flags = UBA_CANTWAIT;
21015357Skarels #ifdef notdef
21115357Skarels 	/* CAN WE USE BDP's ??? */
21215357Skarels 	ds->ds_deuba.ifu_flags |= UBA_NEEDBDP;
21315357Skarels #endif
21415357Skarels 	if_attach(ifp);
21515357Skarels }
21615357Skarels 
21715357Skarels /*
21815357Skarels  * Reset of interface after UNIBUS reset.
21915357Skarels  * If interface is on specified uba, reset its state.
22015357Skarels  */
22115357Skarels dereset(unit, uban)
22215357Skarels 	int unit, uban;
22315357Skarels {
22415357Skarels 	register struct uba_device *ui;
22515357Skarels 
22615357Skarels 	if (unit >= NDE || (ui = deinfo[unit]) == 0 || ui->ui_alive == 0 ||
22715357Skarels 	    ui->ui_ubanum != uban)
22815357Skarels 		return;
22915357Skarels 	printf(" de%d", unit);
23015357Skarels 	deinit(unit);
23115357Skarels }
23215357Skarels 
23315357Skarels /*
23415357Skarels  * Initialization of interface; clear recorded pending
23515357Skarels  * operations, and reinitialize UNIBUS usage.
23615357Skarels  */
23715357Skarels deinit(unit)
23815357Skarels 	int unit;
23915357Skarels {
24015357Skarels 	register struct de_softc *ds = &de_softc[unit];
24115357Skarels 	register struct uba_device *ui = deinfo[unit];
24215357Skarels 	register struct dedevice *addr;
24315357Skarels 	register struct ifrw *ifrw;
24416208Skarels 	register struct ifxmt *ifxp;
24516208Skarels 	struct ifnet *ifp = &ds->ds_if;
24616208Skarels 	struct sockaddr_in *sin;
24715357Skarels 	int s;
24815357Skarels 	struct de_ring *rp;
24915357Skarels 	int incaddr;
25015357Skarels 	int csr0;
25115357Skarels 
25215357Skarels 	sin = (struct sockaddr_in *)&ifp->if_addr;
25315357Skarels 	if (sin->sin_addr.s_addr == 0)	/* if address still unknown */
25415357Skarels 		return;
25515357Skarels 
25615357Skarels 	if (ifp->if_flags & IFF_RUNNING)
25715357Skarels 		goto justarp;
25815357Skarels 	if (de_ubainit(&ds->ds_deuba, ui->ui_ubanum,
25915357Skarels 	    sizeof (struct ether_header), (int)btoc(ETHERMTU)) == 0) {
26015357Skarels 		printf("de%d: can't initialize\n", unit);
26115357Skarels 		ds->ds_if.if_flags &= ~IFF_UP;
26215357Skarels 		return;
26315357Skarels 	}
26415357Skarels 	ds->ds_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(ds), INCORE_SIZE,0);
26515357Skarels 	addr = (struct dedevice *)ui->ui_addr;
26615357Skarels 
26715357Skarels 	/* set the pcbb block address */
26815357Skarels 	incaddr = ds->ds_ubaddr + PCBB_OFFSET;
26915357Skarels 	addr->pcsr2 = incaddr & 0xffff;
27015357Skarels 	addr->pcsr3 = (incaddr >> 16) & 0x3;
27115357Skarels 	addr->pclow = CMD_GETPCBB;
27215357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
27315357Skarels 		;
27415357Skarels 	csr0 = addr->pcsr0;
27515357Skarels 	addr->pchigh = csr0 >> 8;
27615357Skarels 	if (csr0 & PCSR0_PCEI)
27715357Skarels 		printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit,
27815357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
27915357Skarels 
28015357Skarels 	/* set the transmit and receive ring header addresses */
28115357Skarels 	incaddr = ds->ds_ubaddr + UDBBUF_OFFSET;
28215357Skarels 	ds->ds_pcbb.pcbb0 = FC_WTRING;
28315357Skarels 	ds->ds_pcbb.pcbb2 = incaddr & 0xffff;
28415357Skarels 	ds->ds_pcbb.pcbb4 = (incaddr >> 16) & 0x3;
28515357Skarels 
28615357Skarels 	incaddr = ds->ds_ubaddr + XRENT_OFFSET;
28715357Skarels 	ds->ds_udbbuf.b_tdrbl = incaddr & 0xffff;
28815357Skarels 	ds->ds_udbbuf.b_tdrbh = (incaddr >> 16) & 0x3;
28915357Skarels 	ds->ds_udbbuf.b_telen = sizeof (struct de_ring) / sizeof (short);
29015357Skarels 	ds->ds_udbbuf.b_trlen = NXMT;
29115357Skarels 	incaddr = ds->ds_ubaddr + RRENT_OFFSET;
29215357Skarels 	ds->ds_udbbuf.b_rdrbl = incaddr & 0xffff;
29315357Skarels 	ds->ds_udbbuf.b_rdrbh = (incaddr >> 16) & 0x3;
29415357Skarels 	ds->ds_udbbuf.b_relen = sizeof (struct de_ring) / sizeof (short);
29515357Skarels 	ds->ds_udbbuf.b_rrlen = NRCV;
29615357Skarels 
29715357Skarels 	addr->pclow = CMD_GETCMD;
29815357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
29915357Skarels 		;
30015357Skarels 	csr0 = addr->pcsr0;
30115357Skarels 	addr->pchigh = csr0 >> 8;
30215357Skarels 	if (csr0 & PCSR0_PCEI)
30315357Skarels 		printf("de%d: wtring failed, csr0=%b csr1=%b\n", ui->ui_unit,
30415357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
30515357Skarels 
30615357Skarels 	/* initialize the mode - enable hardware padding */
30715357Skarels 	ds->ds_pcbb.pcbb0 = FC_WTMODE;
30815357Skarels 	/* let hardware do padding - set MTCH bit on broadcast */
30915357Skarels 	ds->ds_pcbb.pcbb2 = MOD_TPAD|MOD_HDX;
31015357Skarels 	addr->pclow = CMD_GETCMD;
31115357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
31215357Skarels 		;
31315357Skarels 	csr0 = addr->pcsr0;
31415357Skarels 	addr->pchigh = csr0 >> 8;
31515357Skarels 	if (csr0 & PCSR0_PCEI)
31615357Skarels 		printf("de%d: wtmode failed, csr0=%b csr1=%b\n", ui->ui_unit,
31715357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
31815357Skarels 
31915357Skarels 	/* set up the receive and transmit ring entries */
32016208Skarels 	ifxp = &ds->ds_deuba.ifu_w[0];
32115357Skarels 	for (rp = &ds->ds_xrent[0]; rp < &ds->ds_xrent[NXMT]; rp++) {
32216208Skarels 		rp->r_segbl = ifxp->x_ifrw.ifrw_info & 0xffff;
32316208Skarels 		rp->r_segbh = (ifxp->x_ifrw.ifrw_info >> 16) & 0x3;
32415357Skarels 		rp->r_flags = 0;
32516208Skarels 		ifxp++;
32615357Skarels 	}
32715357Skarels 	ifrw = &ds->ds_deuba.ifu_r[0];
32815357Skarels 	for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) {
32915357Skarels 		rp->r_slen = sizeof (struct de_buf);
33015357Skarels 		rp->r_segbl = ifrw->ifrw_info & 0xffff;
33115357Skarels 		rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3;
33215357Skarels 		rp->r_flags = RFLG_OWN;		/* hang receive */
33315357Skarels 		ifrw++;
33415357Skarels 	}
33515357Skarels 
33615357Skarels 	/* start up the board (rah rah) */
33715357Skarels 	s = splimp();
33815357Skarels 	ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = 0;
33915916Skarels 	ds->ds_if.if_flags |= IFF_UP|IFF_RUNNING;
34015916Skarels 	destart(unit);				/* queue output packets */
34115357Skarels 	addr->pclow = PCSR0_INTE;		/* avoid interlock */
34215357Skarels 	addr->pclow = CMD_START | PCSR0_INTE;
34315916Skarels 	ds->ds_flags |= DSF_RUNNING;
34415357Skarels 	splx(s);
34515357Skarels justarp:
34615357Skarels 	if_rtinit(&ds->ds_if, RTF_UP);
34715357Skarels 	arpwhohas(&ds->ds_ac, &sin->sin_addr);
34815357Skarels }
34915357Skarels 
35015357Skarels /*
35115357Skarels  * Setup output on interface.
35215357Skarels  * Get another datagram to send off of the interface queue,
35315357Skarels  * and map it to the interface before starting the output.
35415357Skarels  */
35515357Skarels destart(unit)
35615357Skarels 	int unit;
35715357Skarels {
35815357Skarels         int len;
35915357Skarels 	struct uba_device *ui = deinfo[unit];
36015357Skarels 	struct dedevice *addr = (struct dedevice *)ui->ui_addr;
36115357Skarels 	register struct de_softc *ds = &de_softc[unit];
36215357Skarels 	register struct de_ring *rp;
36315357Skarels 	struct mbuf *m;
36415357Skarels 	register int nxmit;
36515357Skarels 
36615357Skarels 	/*
36715357Skarels 	 * the following test is necessary, since
36815357Skarels 	 * the code is not reentrant and we have
36915357Skarels 	 * multiple transmission buffers.
37015357Skarels 	 */
37115357Skarels 	if (ds->ds_flags & DSF_LOCK)
37215357Skarels 		return;
37315357Skarels 	for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) {
37415357Skarels 		IF_DEQUEUE(&ds->ds_if.if_snd, m);
37515357Skarels 		if (m == 0)
37615357Skarels 			break;
37715357Skarels 		rp = &ds->ds_xrent[ds->ds_xfree];
37815357Skarels 		if (rp->r_flags & XFLG_OWN)
37915357Skarels 			panic("deuna xmit in progress");
38016208Skarels 		len = deput(&ds->ds_deuba, ds->ds_xfree, m);
38115357Skarels 		if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP)
38215357Skarels 			UBAPURGE(ds->ds_deuba.ifu_uba,
38316208Skarels 			ds->ds_deuba.ifu_w[ds->ds_xfree].x_ifrw.ifrw_bdp);
38415357Skarels 		rp->r_slen = len;
38515357Skarels 		rp->r_tdrerr = 0;
38615357Skarels 		rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN;
38715357Skarels 
38815357Skarels 		ds->ds_xfree++;
38915357Skarels 		if (ds->ds_xfree == NXMT)
39015357Skarels 			ds->ds_xfree = 0;
39115357Skarels 	}
39215357Skarels 	if (ds->ds_nxmit != nxmit) {
39315357Skarels 		ds->ds_nxmit = nxmit;
39415916Skarels 		if (ds->ds_flags & DSF_RUNNING)
39515357Skarels 			addr->pclow = PCSR0_INTE|CMD_PDMD;
39615357Skarels 	}
39715357Skarels }
39815357Skarels 
39915357Skarels /*
40015357Skarels  * Command done interrupt.
40115357Skarels  */
40215357Skarels deintr(unit)
40315357Skarels 	int unit;
40415357Skarels {
40515357Skarels 	struct uba_device *ui = deinfo[unit];
40615357Skarels 	register struct dedevice *addr = (struct dedevice *)ui->ui_addr;
40715357Skarels 	register struct de_softc *ds = &de_softc[unit];
40815357Skarels 	register struct de_ring *rp;
40916208Skarels 	register struct ifxmt *ifxp;
41015357Skarels 	short csr0;
41115357Skarels 
41215357Skarels 	/* save flags right away - clear out interrupt bits */
41315357Skarels 	csr0 = addr->pcsr0;
41415357Skarels 	addr->pchigh = csr0 >> 8;
41515357Skarels 
41615357Skarels 
41715357Skarels 	ds->ds_flags |= DSF_LOCK;	/* prevent entering destart */
41815357Skarels 	/*
41915357Skarels 	 * if receive, put receive buffer on mbuf
42015357Skarels 	 * and hang the request again
42115357Skarels 	 */
42215357Skarels 	derecv(unit);
42315357Skarels 
42415357Skarels 	/*
42515357Skarels 	 * Poll transmit ring and check status.
42615357Skarels 	 * Be careful about loopback requests.
42715357Skarels 	 * Then free buffer space and check for
42815357Skarels 	 * more transmit requests.
42915357Skarels 	 */
43015357Skarels 	for ( ; ds->ds_nxmit > 0; ds->ds_nxmit--) {
43115357Skarels 		rp = &ds->ds_xrent[ds->ds_xindex];
43215357Skarels 		if (rp->r_flags & XFLG_OWN)
43315357Skarels 			break;
43415357Skarels 		ds->ds_if.if_opackets++;
43516208Skarels 		ifxp = &ds->ds_deuba.ifu_w[ds->ds_xindex];
43615357Skarels 		/* check for unusual conditions */
43715357Skarels 		if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) {
43815357Skarels 			if (rp->r_flags & XFLG_ERRS) {
43915357Skarels 				/* output error */
44015357Skarels 				ds->ds_if.if_oerrors++;
44115916Skarels 				if (dedebug)
44215357Skarels 			printf("de%d: oerror, flags=%b tdrerr=%b (len=%d)\n",
44315357Skarels 				    unit, rp->r_flags, XFLG_BITS,
44415357Skarels 				    rp->r_tdrerr, XERR_BITS, rp->r_slen);
44515357Skarels 			} else if (rp->r_flags & XFLG_ONE) {
44615357Skarels 				/* one collision */
44715357Skarels 				ds->ds_if.if_collisions++;
44815357Skarels 			} else if (rp->r_flags & XFLG_MORE) {
44915357Skarels 				/* more than one collision */
45015357Skarels 				ds->ds_if.if_collisions += 2;	/* guess */
45115357Skarels 			} else if (rp->r_flags & XFLG_MTCH) {
45215357Skarels 				/* received our own packet */
45315357Skarels 				ds->ds_if.if_ipackets++;
45416208Skarels 				deread(ds, &ifxp->x_ifrw,
45515357Skarels 				    rp->r_slen - sizeof (struct ether_header));
45615357Skarels 			}
45715357Skarels 		}
45816208Skarels 		if (ifxp->x_xtofree) {
45916208Skarels 			m_freem(ifxp->x_xtofree);
46016208Skarels 			ifxp->x_xtofree = 0;
46116208Skarels 		}
46215357Skarels 		/* check if next transmit buffer also finished */
46315357Skarels 		ds->ds_xindex++;
46415357Skarels 		if (ds->ds_xindex == NXMT)
46515357Skarels 			ds->ds_xindex = 0;
46615357Skarels 	}
46715357Skarels 	ds->ds_flags &= ~DSF_LOCK;
46815357Skarels 	destart(unit);
46915357Skarels 
47015357Skarels 	if (csr0 & PCSR0_RCBI) {
47115357Skarels 		printf("de%d: buffer unavailable\n", unit);
47215357Skarels 		addr->pclow = PCSR0_INTE|CMD_PDMD;
47315357Skarels 	}
47415357Skarels }
47515357Skarels 
47615357Skarels /*
47715357Skarels  * Ethernet interface receiver interface.
47815357Skarels  * If input error just drop packet.
47915357Skarels  * Otherwise purge input buffered data path and examine
48015357Skarels  * packet to determine type.  If can't determine length
48115357Skarels  * from type, then have to drop packet.  Othewise decapsulate
48215357Skarels  * packet based on type and pass to type specific higher-level
48315357Skarels  * input routine.
48415357Skarels  */
48515357Skarels derecv(unit)
48615357Skarels 	int unit;
48715357Skarels {
48815357Skarels 	register struct de_softc *ds = &de_softc[unit];
48915357Skarels 	register struct de_ring *rp;
49015357Skarels 	int len;
49115357Skarels 
49215357Skarels 	rp = &ds->ds_rrent[ds->ds_rindex];
49315357Skarels 	while ((rp->r_flags & RFLG_OWN) == 0) {
49415357Skarels 		ds->ds_if.if_ipackets++;
49515357Skarels 		if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP)
49615357Skarels 			UBAPURGE(ds->ds_deuba.ifu_uba,
49715357Skarels 			ds->ds_deuba.ifu_r[ds->ds_rindex].ifrw_bdp);
49815357Skarels 		len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header)
49915357Skarels 			- 4;	/* don't forget checksum! */
50015357Skarels 		/* check for errors */
50115357Skarels 		if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) ||
50215357Skarels 		    (rp->r_flags&(RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP) ||
50315357Skarels 		    (rp->r_lenerr & (RERR_BUFL|RERR_UBTO|RERR_NCHN)) ||
50415357Skarels 		    len < ETHERMIN || len > ETHERMTU) {
50515357Skarels 			ds->ds_if.if_ierrors++;
50615916Skarels 			if (dedebug)
50715357Skarels 			printf("de%d: ierror, flags=%b lenerr=%b (len=%d)\n",
50815357Skarels 				unit, rp->r_flags, RFLG_BITS, rp->r_lenerr,
50915357Skarels 				RERR_BITS, len);
51015357Skarels 		} else
51115357Skarels 			deread(ds, &ds->ds_deuba.ifu_r[ds->ds_rindex], len);
51215357Skarels 
51315357Skarels 		/* hang the receive buffer again */
51415357Skarels 		rp->r_lenerr = 0;
51515357Skarels 		rp->r_flags = RFLG_OWN;
51615357Skarels 
51715357Skarels 		/* check next receive buffer */
51815357Skarels 		ds->ds_rindex++;
51915357Skarels 		if (ds->ds_rindex == NRCV)
52015357Skarels 			ds->ds_rindex = 0;
52115357Skarels 		rp = &ds->ds_rrent[ds->ds_rindex];
52215357Skarels 	}
52315357Skarels }
52415357Skarels 
52515357Skarels /*
52615357Skarels  * Pass a packet to the higher levels.
52715357Skarels  * We deal with the trailer protocol here.
52815357Skarels  */
52915357Skarels deread(ds, ifrw, len)
53015357Skarels 	register struct de_softc *ds;
53115357Skarels 	struct ifrw *ifrw;
53215357Skarels 	int len;
53315357Skarels {
53415357Skarels 	struct ether_header *eh;
53515357Skarels     	struct mbuf *m;
53615357Skarels 	int off, resid;
53715357Skarels 	register struct ifqueue *inq;
53815357Skarels 
53915357Skarels 	/*
54015357Skarels 	 * Deal with trailer protocol: if type is PUP trailer
54115357Skarels 	 * get true type from first 16-bit word past data.
54215357Skarels 	 * Remember that type was trailer by setting off.
54315357Skarels 	 */
54415357Skarels 	eh = (struct ether_header *)ifrw->ifrw_addr;
54515357Skarels 	eh->ether_type = ntohs((u_short)eh->ether_type);
54615357Skarels #define	dedataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
54715357Skarels 	if (eh->ether_type >= ETHERPUP_TRAIL &&
54815357Skarels 	    eh->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
54915357Skarels 		off = (eh->ether_type - ETHERPUP_TRAIL) * 512;
55015357Skarels 		if (off >= ETHERMTU)
55115357Skarels 			return;		/* sanity */
55215357Skarels 		eh->ether_type = ntohs(*dedataaddr(eh, off, u_short *));
55315357Skarels 		resid = ntohs(*(dedataaddr(eh, off+2, u_short *)));
55415357Skarels 		if (off + resid > len)
55515357Skarels 			return;		/* sanity */
55615357Skarels 		len = off + resid;
55715357Skarels 	} else
55815357Skarels 		off = 0;
55915357Skarels 	if (len == 0)
56015357Skarels 		return;
56115357Skarels 
56215357Skarels 	/*
56315357Skarels 	 * Pull packet off interface.  Off is nonzero if packet
56415357Skarels 	 * has trailing header; deget will then force this header
56515357Skarels 	 * information to be at the front, but we still have to drop
56615357Skarels 	 * the type and length which are at the front of any trailer data.
56715357Skarels 	 */
56815357Skarels 	m = deget(&ds->ds_deuba, ifrw, len, off);
56915357Skarels 	if (m == 0)
57015357Skarels 		return;
57115357Skarels 	if (off) {
57215357Skarels 		m->m_off += 2 * sizeof (u_short);
57315357Skarels 		m->m_len -= 2 * sizeof (u_short);
57415357Skarels 	}
57515357Skarels 	switch (eh->ether_type) {
57615357Skarels 
57715357Skarels #ifdef INET
57815357Skarels 	case ETHERPUP_IPTYPE:
57915357Skarels 		schednetisr(NETISR_IP);
58015357Skarels 		inq = &ipintrq;
58115357Skarels 		break;
58215357Skarels 
58315357Skarels 	case ETHERPUP_ARPTYPE:
58415357Skarels 		arpinput(&ds->ds_ac, m);
58515357Skarels 		return;
58615357Skarels #endif
58715357Skarels 	default:
58815357Skarels 		m_freem(m);
58915357Skarels 		return;
59015357Skarels 	}
59115357Skarels 
59215357Skarels 	if (IF_QFULL(inq)) {
59315357Skarels 		IF_DROP(inq);
59415357Skarels 		m_freem(m);
59515357Skarels 		return;
59615357Skarels 	}
59715357Skarels 	IF_ENQUEUE(inq, m);
59815357Skarels }
59915357Skarels 
60015357Skarels /*
60115357Skarels  * Ethernet output routine.
60215357Skarels  * Encapsulate a packet of type family for the local net.
60315357Skarels  * Use trailer local net encapsulation if enough data in first
60415357Skarels  * packet leaves a multiple of 512 bytes of data in remainder.
60515357Skarels  */
60615357Skarels deoutput(ifp, m0, dst)
60715357Skarels 	struct ifnet *ifp;
60815357Skarels 	struct mbuf *m0;
60915357Skarels 	struct sockaddr *dst;
61015357Skarels {
61115357Skarels 	int type, s, error;
612*16247Skarels 	struct ether_addr edst;
61315357Skarels 	struct in_addr idst;
61415357Skarels 	register struct de_softc *ds = &de_softc[ifp->if_unit];
61515357Skarels 	register struct mbuf *m = m0;
61615357Skarels 	register struct ether_header *eh;
61715357Skarels 	register int off;
61815357Skarels 
61915357Skarels 	switch (dst->sa_family) {
62015357Skarels 
62115357Skarels #ifdef INET
62215357Skarels 	case AF_INET:
62315357Skarels 		idst = ((struct sockaddr_in *)dst)->sin_addr;
624*16247Skarels 		if (!arpresolve(&ds->ds_ac, m, &idst, &edst))
62515357Skarels 			return (0);	/* if not yet resolved */
62615357Skarels 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
62715357Skarels 		/* need per host negotiation */
62815357Skarels 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
62915357Skarels 		if (off > 0 && (off & 0x1ff) == 0 &&
63015357Skarels 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
63115357Skarels 			type = ETHERPUP_TRAIL + (off>>9);
63215357Skarels 			m->m_off -= 2 * sizeof (u_short);
63315357Skarels 			m->m_len += 2 * sizeof (u_short);
63415357Skarels 			*mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
63515357Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
63615357Skarels 			goto gottrailertype;
63715357Skarels 		}
63815357Skarels 		type = ETHERPUP_IPTYPE;
63915357Skarels 		off = 0;
64015357Skarels 		goto gottype;
64115357Skarels #endif
64215357Skarels 
64315357Skarels 	case AF_UNSPEC:
64415357Skarels 		eh = (struct ether_header *)dst->sa_data;
645*16247Skarels 		edst = eh->ether_dhost;
64615357Skarels 		type = eh->ether_type;
64715357Skarels 		goto gottype;
64815357Skarels 
64915357Skarels 	default:
65015357Skarels 		printf("de%d: can't handle af%d\n", ifp->if_unit,
65115357Skarels 			dst->sa_family);
65215357Skarels 		error = EAFNOSUPPORT;
65315357Skarels 		goto bad;
65415357Skarels 	}
65515357Skarels 
65615357Skarels gottrailertype:
65715357Skarels 	/*
65815357Skarels 	 * Packet to be sent as trailer: move first packet
65915357Skarels 	 * (control information) to end of chain.
66015357Skarels 	 */
66115357Skarels 	while (m->m_next)
66215357Skarels 		m = m->m_next;
66315357Skarels 	m->m_next = m0;
66415357Skarels 	m = m0->m_next;
66515357Skarels 	m0->m_next = 0;
66615357Skarels 	m0 = m;
66715357Skarels 
66815357Skarels gottype:
66915357Skarels 	/*
67015357Skarels 	 * Add local net header.  If no space in first mbuf,
67115357Skarels 	 * allocate another.
67215357Skarels 	 */
67315357Skarels 	if (m->m_off > MMAXOFF ||
67415357Skarels 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
67515357Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
67615357Skarels 		if (m == 0) {
67715357Skarels 			error = ENOBUFS;
67815357Skarels 			goto bad;
67915357Skarels 		}
68015357Skarels 		m->m_next = m0;
68115357Skarels 		m->m_off = MMINOFF;
68215357Skarels 		m->m_len = sizeof (struct ether_header);
68315357Skarels 	} else {
68415357Skarels 		m->m_off -= sizeof (struct ether_header);
68515357Skarels 		m->m_len += sizeof (struct ether_header);
68615357Skarels 	}
68715357Skarels 	eh = mtod(m, struct ether_header *);
68815357Skarels 	eh->ether_type = htons((u_short)type);
689*16247Skarels 	eh->ether_dhost = edst;
69015357Skarels 	/* DEUNA fills in source address */
69115357Skarels 
69215357Skarels 	/*
69315357Skarels 	 * Queue message on interface, and start output if interface
69415357Skarels 	 * not yet active.
69515357Skarels 	 */
69615357Skarels 	s = splimp();
69715357Skarels 	if (IF_QFULL(&ifp->if_snd)) {
69815357Skarels 		IF_DROP(&ifp->if_snd);
69915357Skarels 		splx(s);
70015357Skarels 		m_freem(m);
70115357Skarels 		return (ENOBUFS);
70215357Skarels 	}
70315357Skarels 	IF_ENQUEUE(&ifp->if_snd, m);
70415357Skarels 	destart(ifp->if_unit);
70515357Skarels 	splx(s);
70615357Skarels 	return (0);
70715357Skarels 
70815357Skarels bad:
70915357Skarels 	m_freem(m0);
71015357Skarels 	return (error);
71115357Skarels }
71215357Skarels 
71315357Skarels /*
71415357Skarels  * Routines supporting UNIBUS network interfaces.
71515357Skarels  */
71615357Skarels 
71715357Skarels /*
71815357Skarels  * Init UNIBUS for interface on uban whose headers of size hlen are to
71915357Skarels  * end on a page boundary.  We allocate a UNIBUS map register for the page
72015357Skarels  * with the header, and nmr more UNIBUS map registers for i/o on the adapter,
72115357Skarels  * doing this for each receive and transmit buffer.  We also
72215357Skarels  * allocate page frames in the mbuffer pool for these pages.
72315357Skarels  */
72415357Skarels de_ubainit(ifu, uban, hlen, nmr)
72515357Skarels 	register struct deuba *ifu;
72615357Skarels 	int uban, hlen, nmr;
72715357Skarels {
72815357Skarels 	register caddr_t cp, dp;
72915357Skarels 	register struct ifrw *ifrw;
73016208Skarels 	register struct ifxmt *ifxp;
73116208Skarels 	int i, ncl;
73215357Skarels 
73315357Skarels 	ncl = clrnd(nmr + CLSIZE) / CLSIZE;
73415357Skarels 	if (ifu->ifu_r[0].ifrw_addr)
73515357Skarels 		/*
73615357Skarels 		 * If the first read buffer has a non-zero
73715357Skarels 		 * address, it means we have already allocated core
73815357Skarels 		 */
73915357Skarels 		cp = ifu->ifu_r[0].ifrw_addr - (CLBYTES - hlen);
74015357Skarels 	else {
74115357Skarels 		cp = m_clalloc(NTOT * ncl, MPG_SPACE);
74215357Skarels 		if (cp == 0)
74315357Skarels 			return (0);
74415357Skarels 		ifu->ifu_hlen = hlen;
74515357Skarels 		ifu->ifu_uban = uban;
74615357Skarels 		ifu->ifu_uba = uba_hd[uban].uh_uba;
74715357Skarels 		dp = cp + CLBYTES - hlen;
74815357Skarels 		for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) {
74915357Skarels 			ifrw->ifrw_addr = dp;
75015357Skarels 			dp += ncl * CLBYTES;
75115357Skarels 		}
75216208Skarels 		for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) {
75316208Skarels 			ifxp->x_ifrw.ifrw_addr = dp;
75415357Skarels 			dp += ncl * CLBYTES;
75515357Skarels 		}
75615357Skarels 	}
75715357Skarels 	/* allocate for receive ring */
75815357Skarels 	for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) {
75915357Skarels 		if (de_ubaalloc(ifu, ifrw, nmr) == 0) {
76016208Skarels 			struct ifrw *rw;
76115357Skarels 
76216208Skarels 			for (rw = ifu->ifu_r; rw < ifrw; rw++)
76316208Skarels 				ubarelse(ifu->ifu_uban, &rw->ifrw_info);
76415357Skarels 			goto bad;
76515357Skarels 		}
76615357Skarels 	}
76715357Skarels 	/* and now transmit ring */
76816208Skarels 	for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) {
76916208Skarels 		ifrw = &ifxp->x_ifrw;
77015357Skarels 		if (de_ubaalloc(ifu, ifrw, nmr) == 0) {
77116208Skarels 			struct ifxmt *xp;
77215357Skarels 
77316208Skarels 			for (xp = ifu->ifu_w; xp < ifxp; xp++)
77416208Skarels 				ubarelse(ifu->ifu_uban, &xp->x_ifrw.ifrw_info);
77516208Skarels 			for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++)
77616208Skarels 				ubarelse(ifu->ifu_uban, &ifrw->ifrw_info);
77715357Skarels 			goto bad;
77815357Skarels 		}
77916208Skarels 		for (i = 0; i < nmr; i++)
78016208Skarels 			ifxp->x_map[i] = ifrw->ifrw_mr[i];
78116208Skarels 		ifxp->x_xswapd = 0;
78215357Skarels 	}
78315357Skarels 	return (1);
78415357Skarels bad:
78515357Skarels 	m_pgfree(cp, NTOT * ncl);
78615357Skarels 	ifu->ifu_r[0].ifrw_addr = 0;
78715357Skarels 	return(0);
78815357Skarels }
78915357Skarels 
79015357Skarels /*
79115357Skarels  * Setup either a ifrw structure by allocating UNIBUS map registers,
79215357Skarels  * possibly a buffered data path, and initializing the fields of
79315357Skarels  * the ifrw structure to minimize run-time overhead.
79415357Skarels  */
79515357Skarels static
79615357Skarels de_ubaalloc(ifu, ifrw, nmr)
79715357Skarels 	struct deuba *ifu;
79815357Skarels 	register struct ifrw *ifrw;
79915357Skarels 	int nmr;
80015357Skarels {
80115357Skarels 	register int info;
80215357Skarels 
80315357Skarels 	info =
80415357Skarels 	    uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen,
80515357Skarels 	        ifu->ifu_flags);
80615357Skarels 	if (info == 0)
80715357Skarels 		return (0);
80815357Skarels 	ifrw->ifrw_info = info;
80915357Skarels 	ifrw->ifrw_bdp = UBAI_BDP(info);
81015357Skarels 	ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT);
81115357Skarels 	ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1];
81215357Skarels 	return (1);
81315357Skarels }
81415357Skarels 
81515357Skarels /*
81615357Skarels  * Pull read data off a interface.
81715357Skarels  * Len is length of data, with local net header stripped.
81815357Skarels  * Off is non-zero if a trailer protocol was used, and
81915357Skarels  * gives the offset of the trailer information.
82015357Skarels  * We copy the trailer information and then all the normal
82115357Skarels  * data into mbufs.  When full cluster sized units are present
82215357Skarels  * on the interface on cluster boundaries we can get them more
82315357Skarels  * easily by remapping, and take advantage of this here.
82415357Skarels  */
82515357Skarels struct mbuf *
82615357Skarels deget(ifu, ifrw, totlen, off0)
82715357Skarels 	register struct deuba *ifu;
82815357Skarels 	register struct ifrw *ifrw;
82915357Skarels 	int totlen, off0;
83015357Skarels {
83115357Skarels 	struct mbuf *top, **mp, *m;
83215357Skarels 	int off = off0, len;
83315357Skarels 	register caddr_t cp = ifrw->ifrw_addr + ifu->ifu_hlen;
83415357Skarels 
83515357Skarels 	top = 0;
83615357Skarels 	mp = &top;
83715357Skarels 	while (totlen > 0) {
83815357Skarels 		MGET(m, M_DONTWAIT, MT_DATA);
83915357Skarels 		if (m == 0)
84015357Skarels 			goto bad;
84115357Skarels 		if (off) {
84215357Skarels 			len = totlen - off;
84315357Skarels 			cp = ifrw->ifrw_addr + ifu->ifu_hlen + off;
84415357Skarels 		} else
84515357Skarels 			len = totlen;
84615357Skarels 		if (len >= CLBYTES) {
84715357Skarels 			struct mbuf *p;
84815357Skarels 			struct pte *cpte, *ppte;
84915357Skarels 			int x, *ip, i;
85015357Skarels 
85115357Skarels 			MCLGET(p, 1);
85215357Skarels 			if (p == 0)
85315357Skarels 				goto nopage;
85415357Skarels 			len = m->m_len = CLBYTES;
85515357Skarels 			m->m_off = (int)p - (int)m;
85615357Skarels 			if (!claligned(cp))
85715357Skarels 				goto copy;
85815357Skarels 
85915357Skarels 			/*
86015357Skarels 			 * Switch pages mapped to UNIBUS with new page p,
86115357Skarels 			 * as quick form of copy.  Remap UNIBUS and invalidate.
86215357Skarels 			 */
86315357Skarels 			cpte = &Mbmap[mtocl(cp)*CLSIZE];
86415357Skarels 			ppte = &Mbmap[mtocl(p)*CLSIZE];
86515357Skarels 			x = btop(cp - ifrw->ifrw_addr);
86615357Skarels 			ip = (int *)&ifrw->ifrw_mr[x];
86715357Skarels 			for (i = 0; i < CLSIZE; i++) {
86815357Skarels 				struct pte t;
86915357Skarels 				t = *ppte; *ppte++ = *cpte; *cpte = t;
87015357Skarels 				*ip++ =
87115357Skarels 				    cpte++->pg_pfnum|ifrw->ifrw_proto;
87215357Skarels 				mtpr(TBIS, cp);
87315357Skarels 				cp += NBPG;
87415357Skarels 				mtpr(TBIS, (caddr_t)p);
87515357Skarels 				p += NBPG / sizeof (*p);
87615357Skarels 			}
87715357Skarels 			goto nocopy;
87815357Skarels 		}
87915357Skarels nopage:
88015357Skarels 		m->m_len = MIN(MLEN, len);
88115357Skarels 		m->m_off = MMINOFF;
88215357Skarels copy:
88315357Skarels 		bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len);
88415357Skarels 		cp += m->m_len;
88515357Skarels nocopy:
88615357Skarels 		*mp = m;
88715357Skarels 		mp = &m->m_next;
88815357Skarels 		if (off) {
88915357Skarels 			/* sort of an ALGOL-W style for statement... */
89015357Skarels 			off += m->m_len;
89115357Skarels 			if (off == totlen) {
89215357Skarels 				cp = ifrw->ifrw_addr + ifu->ifu_hlen;
89315357Skarels 				off = 0;
89415357Skarels 				totlen = off0;
89515357Skarels 			}
89615357Skarels 		} else
89715357Skarels 			totlen -= m->m_len;
89815357Skarels 	}
89915357Skarels 	return (top);
90015357Skarels bad:
90115357Skarels 	m_freem(top);
90215357Skarels 	return (0);
90315357Skarels }
90415357Skarels 
90515357Skarels /*
90615357Skarels  * Map a chain of mbufs onto a network interface
90715357Skarels  * in preparation for an i/o operation.
90815357Skarels  * The argument chain of mbufs includes the local network
90915357Skarels  * header which is copied to be in the mapped, aligned
91015357Skarels  * i/o space.
91115357Skarels  */
91216208Skarels deput(ifu, n, m)
91316208Skarels 	struct deuba *ifu;
91416208Skarels 	int n;
91515357Skarels 	register struct mbuf *m;
91615357Skarels {
91715357Skarels 	register struct mbuf *mp;
91815357Skarels 	register caddr_t cp;
91916208Skarels 	register struct ifxmt *ifxp;
92016208Skarels 	register struct ifrw *ifrw;
92115357Skarels 	register int i;
92216208Skarels 	int xswapd = 0;
92316208Skarels 	int x, cc, t;
92416208Skarels 	caddr_t dp;
92515357Skarels 
92616208Skarels 	ifxp = &ifu->ifu_w[n];
92716208Skarels 	ifrw = &ifxp->x_ifrw;
92815357Skarels 	cp = ifrw->ifrw_addr;
92915357Skarels 	while (m) {
93015357Skarels 		dp = mtod(m, char *);
93115357Skarels 		if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) {
93216208Skarels 			struct pte *pte; int *ip;
93316208Skarels 			pte = &Mbmap[mtocl(dp)*CLSIZE];
93415357Skarels 			x = btop(cp - ifrw->ifrw_addr);
93515357Skarels 			ip = (int *)&ifrw->ifrw_mr[x];
93616208Skarels 			for (i = 0; i < CLSIZE; i++)
93715357Skarels 				*ip++ =
93816208Skarels 				    ifrw->ifrw_proto | pte++->pg_pfnum;
93916208Skarels 			xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT));
94016208Skarels 			mp = m->m_next;
94116208Skarels 			m->m_next = ifxp->x_xtofree;
94216208Skarels 			ifxp->x_xtofree = m;
94316208Skarels 			cp += m->m_len;
94415357Skarels 		} else {
94515357Skarels 			bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
94615357Skarels 			cp += m->m_len;
94716208Skarels 			MFREE(m, mp);
94815357Skarels 		}
94915357Skarels 		m = mp;
95015357Skarels 	}
95115357Skarels 
95216208Skarels 	/*
95316208Skarels 	 * Xswapd is the set of clusters we just mapped out.  Ifxp->x_xswapd
95416208Skarels 	 * is the set of clusters mapped out from before.  We compute
95516208Skarels 	 * the number of clusters involved in this operation in x.
95616208Skarels 	 * Clusters mapped out before and involved in this operation
95716208Skarels 	 * should be unmapped so original pages will be accessed by the device.
95816208Skarels 	 */
95915357Skarels 	cc = cp - ifrw->ifrw_addr;
96016208Skarels 	x = ((cc - ifu->ifu_hlen) + CLBYTES - 1) >> CLSHIFT;
96116208Skarels 	ifxp->x_xswapd &= ~xswapd;
96216208Skarels 	while (i = ffs(ifxp->x_xswapd)) {
96316208Skarels 		i--;
96416208Skarels 		if (i >= x)
96516208Skarels 			break;
96616208Skarels 		ifxp->x_xswapd &= ~(1<<i);
96716208Skarels 		i *= CLSIZE;
96816208Skarels 		for (t = 0; t < CLSIZE; t++) {
96916208Skarels 			ifrw->ifrw_mr[i] = ifxp->x_map[i];
97016208Skarels 			i++;
97116208Skarels 		}
97216208Skarels 	}
97316208Skarels 	ifxp->x_xswapd |= xswapd;
97415357Skarels 	return (cc);
97515357Skarels }
97615357Skarels 
97715357Skarels /*
97815357Skarels  * Process an ioctl request.
97915357Skarels  */
98015357Skarels deioctl(ifp, cmd, data)
98115357Skarels 	register struct ifnet *ifp;
98215357Skarels 	int cmd;
98315357Skarels 	caddr_t data;
98415357Skarels {
98515357Skarels 	register struct ifreq *ifr = (struct ifreq *)data;
98615357Skarels 	int s = splimp(), error = 0;
98715357Skarels 
98815357Skarels 	switch (cmd) {
98915357Skarels 
99015357Skarels 	case SIOCSIFADDR:
99115357Skarels 		if (ifp->if_flags & IFF_RUNNING)
99215357Skarels 			if_rtinit(ifp, -1);	/* delete previous route */
99315357Skarels 		desetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
99415357Skarels 		deinit(ifp->if_unit);
99515357Skarels 		break;
99615357Skarels 
99715357Skarels 	default:
99815357Skarels 		error = EINVAL;
99915357Skarels 	}
100015357Skarels 	splx(s);
100115357Skarels 	return (error);
100215357Skarels }
100315357Skarels 
100415357Skarels desetaddr(ifp, sin)
100515357Skarels 	register struct ifnet *ifp;
100615357Skarels 	register struct sockaddr_in *sin;
100715357Skarels {
100815357Skarels 
100915357Skarels 	ifp->if_addr = *(struct sockaddr *)sin;
101015357Skarels 	ifp->if_net = in_netof(sin->sin_addr);
101115357Skarels 	ifp->if_host[0] = in_lnaof(sin->sin_addr);
101215357Skarels 	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
101315357Skarels 	sin->sin_family = AF_INET;
101415357Skarels 	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
101515357Skarels 	ifp->if_flags |= IFF_BROADCAST;
101615357Skarels }
101716208Skarels #endif
1018