xref: /csrg-svn/sys/vax/if/if_de.c (revision 16208)
1*16208Skarels /*	if_de.c	6.3	84/03/20	*/
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 
4715916Skarels int	dedebug = 0;
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 /*
60*16208Skarels  * The deuba structures generalizes the ifuba structure
61*16208Skarels  * to an arbitrary number of receive and transmit buffers.
6215357Skarels  */
63*16208Skarels struct	ifxmt {
64*16208Skarels 	struct	ifrw x_ifrw;			/* mapping information */
65*16208Skarels 	struct	pte x_map[IF_MAXNUBAMR];	/* output base pages */
66*16208Skarels 	short	x_xswapd;			/* mask of clusters swapped */
67*16208Skarels 	struct	mbuf *x_xtofree;		/* pages being dma'ed out */
68*16208Skarels };
69*16208Skarels 
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 */
75*16208Skarels 	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);
20115357Skarels 	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 	sin->sin_addr = arpmyaddr((struct arpcom *)0);
20615357Skarels 	ifp->if_init = deinit;
20715357Skarels 	ifp->if_output = deoutput;
20815357Skarels 	ifp->if_ioctl = deioctl;
20915357Skarels 	ifp->if_reset = dereset;
21015357Skarels 	ds->ds_deuba.ifu_flags = UBA_CANTWAIT;
21115357Skarels #ifdef notdef
21215357Skarels 	/* CAN WE USE BDP's ??? */
21315357Skarels 	ds->ds_deuba.ifu_flags |= UBA_NEEDBDP;
21415357Skarels #endif
21515357Skarels 	if_attach(ifp);
21615357Skarels }
21715357Skarels 
21815357Skarels /*
21915357Skarels  * Reset of interface after UNIBUS reset.
22015357Skarels  * If interface is on specified uba, reset its state.
22115357Skarels  */
22215357Skarels dereset(unit, uban)
22315357Skarels 	int unit, uban;
22415357Skarels {
22515357Skarels 	register struct uba_device *ui;
22615357Skarels 
22715357Skarels 	if (unit >= NDE || (ui = deinfo[unit]) == 0 || ui->ui_alive == 0 ||
22815357Skarels 	    ui->ui_ubanum != uban)
22915357Skarels 		return;
23015357Skarels 	printf(" de%d", unit);
23115357Skarels 	deinit(unit);
23215357Skarels }
23315357Skarels 
23415357Skarels /*
23515357Skarels  * Initialization of interface; clear recorded pending
23615357Skarels  * operations, and reinitialize UNIBUS usage.
23715357Skarels  */
23815357Skarels deinit(unit)
23915357Skarels 	int unit;
24015357Skarels {
24115357Skarels 	register struct de_softc *ds = &de_softc[unit];
24215357Skarels 	register struct uba_device *ui = deinfo[unit];
24315357Skarels 	register struct dedevice *addr;
24415357Skarels 	register struct ifrw *ifrw;
245*16208Skarels 	register struct ifxmt *ifxp;
246*16208Skarels 	struct ifnet *ifp = &ds->ds_if;
247*16208Skarels 	struct sockaddr_in *sin;
24815357Skarels 	int s;
24915357Skarels 	struct de_ring *rp;
25015357Skarels 	int incaddr;
25115357Skarels 	int csr0;
25215357Skarels 
25315357Skarels 	sin = (struct sockaddr_in *)&ifp->if_addr;
25415357Skarels 	if (sin->sin_addr.s_addr == 0)	/* if address still unknown */
25515357Skarels 		return;
25615357Skarels 
25715357Skarels 	if (ifp->if_flags & IFF_RUNNING)
25815357Skarels 		goto justarp;
25915357Skarels 	if (de_ubainit(&ds->ds_deuba, ui->ui_ubanum,
26015357Skarels 	    sizeof (struct ether_header), (int)btoc(ETHERMTU)) == 0) {
26115357Skarels 		printf("de%d: can't initialize\n", unit);
26215357Skarels 		ds->ds_if.if_flags &= ~IFF_UP;
26315357Skarels 		return;
26415357Skarels 	}
26515357Skarels 	ds->ds_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(ds), INCORE_SIZE,0);
26615357Skarels 	addr = (struct dedevice *)ui->ui_addr;
26715357Skarels 
26815357Skarels 	/* set the pcbb block address */
26915357Skarels 	incaddr = ds->ds_ubaddr + PCBB_OFFSET;
27015357Skarels 	addr->pcsr2 = incaddr & 0xffff;
27115357Skarels 	addr->pcsr3 = (incaddr >> 16) & 0x3;
27215357Skarels 	addr->pclow = CMD_GETPCBB;
27315357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
27415357Skarels 		;
27515357Skarels 	csr0 = addr->pcsr0;
27615357Skarels 	addr->pchigh = csr0 >> 8;
27715357Skarels 	if (csr0 & PCSR0_PCEI)
27815357Skarels 		printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit,
27915357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
28015357Skarels 
28115357Skarels 	/* set the transmit and receive ring header addresses */
28215357Skarels 	incaddr = ds->ds_ubaddr + UDBBUF_OFFSET;
28315357Skarels 	ds->ds_pcbb.pcbb0 = FC_WTRING;
28415357Skarels 	ds->ds_pcbb.pcbb2 = incaddr & 0xffff;
28515357Skarels 	ds->ds_pcbb.pcbb4 = (incaddr >> 16) & 0x3;
28615357Skarels 
28715357Skarels 	incaddr = ds->ds_ubaddr + XRENT_OFFSET;
28815357Skarels 	ds->ds_udbbuf.b_tdrbl = incaddr & 0xffff;
28915357Skarels 	ds->ds_udbbuf.b_tdrbh = (incaddr >> 16) & 0x3;
29015357Skarels 	ds->ds_udbbuf.b_telen = sizeof (struct de_ring) / sizeof (short);
29115357Skarels 	ds->ds_udbbuf.b_trlen = NXMT;
29215357Skarels 	incaddr = ds->ds_ubaddr + RRENT_OFFSET;
29315357Skarels 	ds->ds_udbbuf.b_rdrbl = incaddr & 0xffff;
29415357Skarels 	ds->ds_udbbuf.b_rdrbh = (incaddr >> 16) & 0x3;
29515357Skarels 	ds->ds_udbbuf.b_relen = sizeof (struct de_ring) / sizeof (short);
29615357Skarels 	ds->ds_udbbuf.b_rrlen = NRCV;
29715357Skarels 
29815357Skarels 	addr->pclow = CMD_GETCMD;
29915357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
30015357Skarels 		;
30115357Skarels 	csr0 = addr->pcsr0;
30215357Skarels 	addr->pchigh = csr0 >> 8;
30315357Skarels 	if (csr0 & PCSR0_PCEI)
30415357Skarels 		printf("de%d: wtring failed, csr0=%b csr1=%b\n", ui->ui_unit,
30515357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
30615357Skarels 
30715357Skarels 	/* initialize the mode - enable hardware padding */
30815357Skarels 	ds->ds_pcbb.pcbb0 = FC_WTMODE;
30915357Skarels 	/* let hardware do padding - set MTCH bit on broadcast */
31015357Skarels 	ds->ds_pcbb.pcbb2 = MOD_TPAD|MOD_HDX;
31115357Skarels 	addr->pclow = CMD_GETCMD;
31215357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
31315357Skarels 		;
31415357Skarels 	csr0 = addr->pcsr0;
31515357Skarels 	addr->pchigh = csr0 >> 8;
31615357Skarels 	if (csr0 & PCSR0_PCEI)
31715357Skarels 		printf("de%d: wtmode failed, csr0=%b csr1=%b\n", ui->ui_unit,
31815357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
31915357Skarels 
32015357Skarels 	/* set up the receive and transmit ring entries */
321*16208Skarels 	ifxp = &ds->ds_deuba.ifu_w[0];
32215357Skarels 	for (rp = &ds->ds_xrent[0]; rp < &ds->ds_xrent[NXMT]; rp++) {
323*16208Skarels 		rp->r_segbl = ifxp->x_ifrw.ifrw_info & 0xffff;
324*16208Skarels 		rp->r_segbh = (ifxp->x_ifrw.ifrw_info >> 16) & 0x3;
32515357Skarels 		rp->r_flags = 0;
326*16208Skarels 		ifxp++;
32715357Skarels 	}
32815357Skarels 	ifrw = &ds->ds_deuba.ifu_r[0];
32915357Skarels 	for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) {
33015357Skarels 		rp->r_slen = sizeof (struct de_buf);
33115357Skarels 		rp->r_segbl = ifrw->ifrw_info & 0xffff;
33215357Skarels 		rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3;
33315357Skarels 		rp->r_flags = RFLG_OWN;		/* hang receive */
33415357Skarels 		ifrw++;
33515357Skarels 	}
33615357Skarels 
33715357Skarels 	/* start up the board (rah rah) */
33815357Skarels 	s = splimp();
33915357Skarels 	ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = 0;
34015916Skarels 	ds->ds_if.if_flags |= IFF_UP|IFF_RUNNING;
34115916Skarels 	destart(unit);				/* queue output packets */
34215357Skarels 	addr->pclow = PCSR0_INTE;		/* avoid interlock */
34315357Skarels 	addr->pclow = CMD_START | PCSR0_INTE;
34415916Skarels 	ds->ds_flags |= DSF_RUNNING;
34515357Skarels 	splx(s);
34615357Skarels justarp:
34715357Skarels 	if_rtinit(&ds->ds_if, RTF_UP);
34815357Skarels 	arpattach(&ds->ds_ac);
34915357Skarels 	arpwhohas(&ds->ds_ac, &sin->sin_addr);
35015357Skarels }
35115357Skarels 
35215357Skarels /*
35315357Skarels  * Setup output on interface.
35415357Skarels  * Get another datagram to send off of the interface queue,
35515357Skarels  * and map it to the interface before starting the output.
35615357Skarels  */
35715357Skarels destart(unit)
35815357Skarels 	int unit;
35915357Skarels {
36015357Skarels         int len;
36115357Skarels 	struct uba_device *ui = deinfo[unit];
36215357Skarels 	struct dedevice *addr = (struct dedevice *)ui->ui_addr;
36315357Skarels 	register struct de_softc *ds = &de_softc[unit];
36415357Skarels 	register struct de_ring *rp;
36515357Skarels 	struct mbuf *m;
36615357Skarels 	register int nxmit;
36715357Skarels 
36815357Skarels 	/*
36915357Skarels 	 * the following test is necessary, since
37015357Skarels 	 * the code is not reentrant and we have
37115357Skarels 	 * multiple transmission buffers.
37215357Skarels 	 */
37315357Skarels 	if (ds->ds_flags & DSF_LOCK)
37415357Skarels 		return;
37515357Skarels 	for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) {
37615357Skarels 		IF_DEQUEUE(&ds->ds_if.if_snd, m);
37715357Skarels 		if (m == 0)
37815357Skarels 			break;
37915357Skarels 		rp = &ds->ds_xrent[ds->ds_xfree];
38015357Skarels 		if (rp->r_flags & XFLG_OWN)
38115357Skarels 			panic("deuna xmit in progress");
382*16208Skarels 		len = deput(&ds->ds_deuba, ds->ds_xfree, m);
38315357Skarels 		if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP)
38415357Skarels 			UBAPURGE(ds->ds_deuba.ifu_uba,
385*16208Skarels 			ds->ds_deuba.ifu_w[ds->ds_xfree].x_ifrw.ifrw_bdp);
38615357Skarels 		rp->r_slen = len;
38715357Skarels 		rp->r_tdrerr = 0;
38815357Skarels 		rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN;
38915357Skarels 
39015357Skarels 		ds->ds_xfree++;
39115357Skarels 		if (ds->ds_xfree == NXMT)
39215357Skarels 			ds->ds_xfree = 0;
39315357Skarels 	}
39415357Skarels 	if (ds->ds_nxmit != nxmit) {
39515357Skarels 		ds->ds_nxmit = nxmit;
39615916Skarels 		if (ds->ds_flags & DSF_RUNNING)
39715357Skarels 			addr->pclow = PCSR0_INTE|CMD_PDMD;
39815357Skarels 	}
39915357Skarels }
40015357Skarels 
40115357Skarels /*
40215357Skarels  * Command done interrupt.
40315357Skarels  */
40415357Skarels deintr(unit)
40515357Skarels 	int unit;
40615357Skarels {
40715357Skarels 	struct uba_device *ui = deinfo[unit];
40815357Skarels 	register struct dedevice *addr = (struct dedevice *)ui->ui_addr;
40915357Skarels 	register struct de_softc *ds = &de_softc[unit];
41015357Skarels 	register struct de_ring *rp;
411*16208Skarels 	register struct ifxmt *ifxp;
41215357Skarels 	short csr0;
41315357Skarels 
41415357Skarels 	/* save flags right away - clear out interrupt bits */
41515357Skarels 	csr0 = addr->pcsr0;
41615357Skarels 	addr->pchigh = csr0 >> 8;
41715357Skarels 
41815357Skarels 
41915357Skarels 	ds->ds_flags |= DSF_LOCK;	/* prevent entering destart */
42015357Skarels 	/*
42115357Skarels 	 * if receive, put receive buffer on mbuf
42215357Skarels 	 * and hang the request again
42315357Skarels 	 */
42415357Skarels 	derecv(unit);
42515357Skarels 
42615357Skarels 	/*
42715357Skarels 	 * Poll transmit ring and check status.
42815357Skarels 	 * Be careful about loopback requests.
42915357Skarels 	 * Then free buffer space and check for
43015357Skarels 	 * more transmit requests.
43115357Skarels 	 */
43215357Skarels 	for ( ; ds->ds_nxmit > 0; ds->ds_nxmit--) {
43315357Skarels 		rp = &ds->ds_xrent[ds->ds_xindex];
43415357Skarels 		if (rp->r_flags & XFLG_OWN)
43515357Skarels 			break;
43615357Skarels 		ds->ds_if.if_opackets++;
437*16208Skarels 		ifxp = &ds->ds_deuba.ifu_w[ds->ds_xindex];
43815357Skarels 		/* check for unusual conditions */
43915357Skarels 		if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) {
44015357Skarels 			if (rp->r_flags & XFLG_ERRS) {
44115357Skarels 				/* output error */
44215357Skarels 				ds->ds_if.if_oerrors++;
44315916Skarels 				if (dedebug)
44415357Skarels 			printf("de%d: oerror, flags=%b tdrerr=%b (len=%d)\n",
44515357Skarels 				    unit, rp->r_flags, XFLG_BITS,
44615357Skarels 				    rp->r_tdrerr, XERR_BITS, rp->r_slen);
44715357Skarels 			} else if (rp->r_flags & XFLG_ONE) {
44815357Skarels 				/* one collision */
44915357Skarels 				ds->ds_if.if_collisions++;
45015357Skarels 			} else if (rp->r_flags & XFLG_MORE) {
45115357Skarels 				/* more than one collision */
45215357Skarels 				ds->ds_if.if_collisions += 2;	/* guess */
45315357Skarels 			} else if (rp->r_flags & XFLG_MTCH) {
45415357Skarels 				/* received our own packet */
45515357Skarels 				ds->ds_if.if_ipackets++;
456*16208Skarels 				deread(ds, &ifxp->x_ifrw,
45715357Skarels 				    rp->r_slen - sizeof (struct ether_header));
45815357Skarels 			}
45915357Skarels 		}
460*16208Skarels 		if (ifxp->x_xtofree) {
461*16208Skarels 			m_freem(ifxp->x_xtofree);
462*16208Skarels 			ifxp->x_xtofree = 0;
463*16208Skarels 		}
46415357Skarels 		/* check if next transmit buffer also finished */
46515357Skarels 		ds->ds_xindex++;
46615357Skarels 		if (ds->ds_xindex == NXMT)
46715357Skarels 			ds->ds_xindex = 0;
46815357Skarels 	}
46915357Skarels 	ds->ds_flags &= ~DSF_LOCK;
47015357Skarels 	destart(unit);
47115357Skarels 
47215357Skarels 	if (csr0 & PCSR0_RCBI) {
47315357Skarels 		printf("de%d: buffer unavailable\n", unit);
47415357Skarels 		addr->pclow = PCSR0_INTE|CMD_PDMD;
47515357Skarels 	}
47615357Skarels }
47715357Skarels 
47815357Skarels /*
47915357Skarels  * Ethernet interface receiver interface.
48015357Skarels  * If input error just drop packet.
48115357Skarels  * Otherwise purge input buffered data path and examine
48215357Skarels  * packet to determine type.  If can't determine length
48315357Skarels  * from type, then have to drop packet.  Othewise decapsulate
48415357Skarels  * packet based on type and pass to type specific higher-level
48515357Skarels  * input routine.
48615357Skarels  */
48715357Skarels derecv(unit)
48815357Skarels 	int unit;
48915357Skarels {
49015357Skarels 	register struct de_softc *ds = &de_softc[unit];
49115357Skarels 	register struct de_ring *rp;
49215357Skarels 	int len;
49315357Skarels 
49415357Skarels 	rp = &ds->ds_rrent[ds->ds_rindex];
49515357Skarels 	while ((rp->r_flags & RFLG_OWN) == 0) {
49615357Skarels 		ds->ds_if.if_ipackets++;
49715357Skarels 		if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP)
49815357Skarels 			UBAPURGE(ds->ds_deuba.ifu_uba,
49915357Skarels 			ds->ds_deuba.ifu_r[ds->ds_rindex].ifrw_bdp);
50015357Skarels 		len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header)
50115357Skarels 			- 4;	/* don't forget checksum! */
50215357Skarels 		/* check for errors */
50315357Skarels 		if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) ||
50415357Skarels 		    (rp->r_flags&(RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP) ||
50515357Skarels 		    (rp->r_lenerr & (RERR_BUFL|RERR_UBTO|RERR_NCHN)) ||
50615357Skarels 		    len < ETHERMIN || len > ETHERMTU) {
50715357Skarels 			ds->ds_if.if_ierrors++;
50815916Skarels 			if (dedebug)
50915357Skarels 			printf("de%d: ierror, flags=%b lenerr=%b (len=%d)\n",
51015357Skarels 				unit, rp->r_flags, RFLG_BITS, rp->r_lenerr,
51115357Skarels 				RERR_BITS, len);
51215357Skarels 		} else
51315357Skarels 			deread(ds, &ds->ds_deuba.ifu_r[ds->ds_rindex], len);
51415357Skarels 
51515357Skarels 		/* hang the receive buffer again */
51615357Skarels 		rp->r_lenerr = 0;
51715357Skarels 		rp->r_flags = RFLG_OWN;
51815357Skarels 
51915357Skarels 		/* check next receive buffer */
52015357Skarels 		ds->ds_rindex++;
52115357Skarels 		if (ds->ds_rindex == NRCV)
52215357Skarels 			ds->ds_rindex = 0;
52315357Skarels 		rp = &ds->ds_rrent[ds->ds_rindex];
52415357Skarels 	}
52515357Skarels }
52615357Skarels 
52715357Skarels /*
52815357Skarels  * Pass a packet to the higher levels.
52915357Skarels  * We deal with the trailer protocol here.
53015357Skarels  */
53115357Skarels deread(ds, ifrw, len)
53215357Skarels 	register struct de_softc *ds;
53315357Skarels 	struct ifrw *ifrw;
53415357Skarels 	int len;
53515357Skarels {
53615357Skarels 	struct ether_header *eh;
53715357Skarels     	struct mbuf *m;
53815357Skarels 	int off, resid;
53915357Skarels 	register struct ifqueue *inq;
54015357Skarels 
54115357Skarels 	/*
54215357Skarels 	 * Deal with trailer protocol: if type is PUP trailer
54315357Skarels 	 * get true type from first 16-bit word past data.
54415357Skarels 	 * Remember that type was trailer by setting off.
54515357Skarels 	 */
54615357Skarels 	eh = (struct ether_header *)ifrw->ifrw_addr;
54715357Skarels 	eh->ether_type = ntohs((u_short)eh->ether_type);
54815357Skarels #define	dedataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
54915357Skarels 	if (eh->ether_type >= ETHERPUP_TRAIL &&
55015357Skarels 	    eh->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
55115357Skarels 		off = (eh->ether_type - ETHERPUP_TRAIL) * 512;
55215357Skarels 		if (off >= ETHERMTU)
55315357Skarels 			return;		/* sanity */
55415357Skarels 		eh->ether_type = ntohs(*dedataaddr(eh, off, u_short *));
55515357Skarels 		resid = ntohs(*(dedataaddr(eh, off+2, u_short *)));
55615357Skarels 		if (off + resid > len)
55715357Skarels 			return;		/* sanity */
55815357Skarels 		len = off + resid;
55915357Skarels 	} else
56015357Skarels 		off = 0;
56115357Skarels 	if (len == 0)
56215357Skarels 		return;
56315357Skarels 
56415357Skarels 	/*
56515357Skarels 	 * Pull packet off interface.  Off is nonzero if packet
56615357Skarels 	 * has trailing header; deget will then force this header
56715357Skarels 	 * information to be at the front, but we still have to drop
56815357Skarels 	 * the type and length which are at the front of any trailer data.
56915357Skarels 	 */
57015357Skarels 	m = deget(&ds->ds_deuba, ifrw, len, off);
57115357Skarels 	if (m == 0)
57215357Skarels 		return;
57315357Skarels 	if (off) {
57415357Skarels 		m->m_off += 2 * sizeof (u_short);
57515357Skarels 		m->m_len -= 2 * sizeof (u_short);
57615357Skarels 	}
57715357Skarels 	switch (eh->ether_type) {
57815357Skarels 
57915357Skarels #ifdef INET
58015357Skarels 	case ETHERPUP_IPTYPE:
58115357Skarels 		schednetisr(NETISR_IP);
58215357Skarels 		inq = &ipintrq;
58315357Skarels 		break;
58415357Skarels 
58515357Skarels 	case ETHERPUP_ARPTYPE:
58615357Skarels 		arpinput(&ds->ds_ac, m);
58715357Skarels 		return;
58815357Skarels #endif
58915357Skarels 	default:
59015357Skarels 		m_freem(m);
59115357Skarels 		return;
59215357Skarels 	}
59315357Skarels 
59415357Skarels 	if (IF_QFULL(inq)) {
59515357Skarels 		IF_DROP(inq);
59615357Skarels 		m_freem(m);
59715357Skarels 		return;
59815357Skarels 	}
59915357Skarels 	IF_ENQUEUE(inq, m);
60015357Skarels }
60115357Skarels 
60215357Skarels /*
60315357Skarels  * Ethernet output routine.
60415357Skarels  * Encapsulate a packet of type family for the local net.
60515357Skarels  * Use trailer local net encapsulation if enough data in first
60615357Skarels  * packet leaves a multiple of 512 bytes of data in remainder.
60715357Skarels  */
60815357Skarels deoutput(ifp, m0, dst)
60915357Skarels 	struct ifnet *ifp;
61015357Skarels 	struct mbuf *m0;
61115357Skarels 	struct sockaddr *dst;
61215357Skarels {
61315357Skarels 	int type, s, error;
61415357Skarels 	u_char edst[6];
61515357Skarels 	struct in_addr idst;
61615357Skarels 	register struct de_softc *ds = &de_softc[ifp->if_unit];
61715357Skarels 	register struct mbuf *m = m0;
61815357Skarels 	register struct ether_header *eh;
61915357Skarels 	register int off;
62015357Skarels 
62115357Skarels 	switch (dst->sa_family) {
62215357Skarels 
62315357Skarels #ifdef INET
62415357Skarels 	case AF_INET:
62515357Skarels 		idst = ((struct sockaddr_in *)dst)->sin_addr;
62615357Skarels 		if (!arpresolve(&ds->ds_ac, m, &idst, edst))
62715357Skarels 			return (0);	/* if not yet resolved */
62815357Skarels 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
62915357Skarels 		/* need per host negotiation */
63015357Skarels 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
63115357Skarels 		if (off > 0 && (off & 0x1ff) == 0 &&
63215357Skarels 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
63315357Skarels 			type = ETHERPUP_TRAIL + (off>>9);
63415357Skarels 			m->m_off -= 2 * sizeof (u_short);
63515357Skarels 			m->m_len += 2 * sizeof (u_short);
63615357Skarels 			*mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
63715357Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
63815357Skarels 			goto gottrailertype;
63915357Skarels 		}
64015357Skarels 		type = ETHERPUP_IPTYPE;
64115357Skarels 		off = 0;
64215357Skarels 		goto gottype;
64315357Skarels #endif
64415357Skarels 
64515357Skarels 	case AF_UNSPEC:
64615357Skarels 		eh = (struct ether_header *)dst->sa_data;
64715357Skarels 		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
64815357Skarels 		type = eh->ether_type;
64915357Skarels 		goto gottype;
65015357Skarels 
65115357Skarels 	default:
65215357Skarels 		printf("de%d: can't handle af%d\n", ifp->if_unit,
65315357Skarels 			dst->sa_family);
65415357Skarels 		error = EAFNOSUPPORT;
65515357Skarels 		goto bad;
65615357Skarels 	}
65715357Skarels 
65815357Skarels gottrailertype:
65915357Skarels 	/*
66015357Skarels 	 * Packet to be sent as trailer: move first packet
66115357Skarels 	 * (control information) to end of chain.
66215357Skarels 	 */
66315357Skarels 	while (m->m_next)
66415357Skarels 		m = m->m_next;
66515357Skarels 	m->m_next = m0;
66615357Skarels 	m = m0->m_next;
66715357Skarels 	m0->m_next = 0;
66815357Skarels 	m0 = m;
66915357Skarels 
67015357Skarels gottype:
67115357Skarels 	/*
67215357Skarels 	 * Add local net header.  If no space in first mbuf,
67315357Skarels 	 * allocate another.
67415357Skarels 	 */
67515357Skarels 	if (m->m_off > MMAXOFF ||
67615357Skarels 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
67715357Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
67815357Skarels 		if (m == 0) {
67915357Skarels 			error = ENOBUFS;
68015357Skarels 			goto bad;
68115357Skarels 		}
68215357Skarels 		m->m_next = m0;
68315357Skarels 		m->m_off = MMINOFF;
68415357Skarels 		m->m_len = sizeof (struct ether_header);
68515357Skarels 	} else {
68615357Skarels 		m->m_off -= sizeof (struct ether_header);
68715357Skarels 		m->m_len += sizeof (struct ether_header);
68815357Skarels 	}
68915357Skarels 	eh = mtod(m, struct ether_header *);
69015357Skarels 	eh->ether_type = htons((u_short)type);
69115357Skarels 	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
69215357Skarels 	/* DEUNA fills in source address */
69315357Skarels 
69415357Skarels 	/*
69515357Skarels 	 * Queue message on interface, and start output if interface
69615357Skarels 	 * not yet active.
69715357Skarels 	 */
69815357Skarels 	s = splimp();
69915357Skarels 	if (IF_QFULL(&ifp->if_snd)) {
70015357Skarels 		IF_DROP(&ifp->if_snd);
70115357Skarels 		splx(s);
70215357Skarels 		m_freem(m);
70315357Skarels 		return (ENOBUFS);
70415357Skarels 	}
70515357Skarels 	IF_ENQUEUE(&ifp->if_snd, m);
70615357Skarels 	destart(ifp->if_unit);
70715357Skarels 	splx(s);
70815357Skarels 	return (0);
70915357Skarels 
71015357Skarels bad:
71115357Skarels 	m_freem(m0);
71215357Skarels 	return (error);
71315357Skarels }
71415357Skarels 
71515357Skarels /*
71615357Skarels  * Routines supporting UNIBUS network interfaces.
71715357Skarels  */
71815357Skarels 
71915357Skarels /*
72015357Skarels  * Init UNIBUS for interface on uban whose headers of size hlen are to
72115357Skarels  * end on a page boundary.  We allocate a UNIBUS map register for the page
72215357Skarels  * with the header, and nmr more UNIBUS map registers for i/o on the adapter,
72315357Skarels  * doing this for each receive and transmit buffer.  We also
72415357Skarels  * allocate page frames in the mbuffer pool for these pages.
72515357Skarels  */
72615357Skarels de_ubainit(ifu, uban, hlen, nmr)
72715357Skarels 	register struct deuba *ifu;
72815357Skarels 	int uban, hlen, nmr;
72915357Skarels {
73015357Skarels 	register caddr_t cp, dp;
73115357Skarels 	register struct ifrw *ifrw;
732*16208Skarels 	register struct ifxmt *ifxp;
733*16208Skarels 	int i, ncl;
73415357Skarels 
73515357Skarels 	ncl = clrnd(nmr + CLSIZE) / CLSIZE;
73615357Skarels 	if (ifu->ifu_r[0].ifrw_addr)
73715357Skarels 		/*
73815357Skarels 		 * If the first read buffer has a non-zero
73915357Skarels 		 * address, it means we have already allocated core
74015357Skarels 		 */
74115357Skarels 		cp = ifu->ifu_r[0].ifrw_addr - (CLBYTES - hlen);
74215357Skarels 	else {
74315357Skarels 		cp = m_clalloc(NTOT * ncl, MPG_SPACE);
74415357Skarels 		if (cp == 0)
74515357Skarels 			return (0);
74615357Skarels 		ifu->ifu_hlen = hlen;
74715357Skarels 		ifu->ifu_uban = uban;
74815357Skarels 		ifu->ifu_uba = uba_hd[uban].uh_uba;
74915357Skarels 		dp = cp + CLBYTES - hlen;
75015357Skarels 		for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) {
75115357Skarels 			ifrw->ifrw_addr = dp;
75215357Skarels 			dp += ncl * CLBYTES;
75315357Skarels 		}
754*16208Skarels 		for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) {
755*16208Skarels 			ifxp->x_ifrw.ifrw_addr = dp;
75615357Skarels 			dp += ncl * CLBYTES;
75715357Skarels 		}
75815357Skarels 	}
75915357Skarels 	/* allocate for receive ring */
76015357Skarels 	for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) {
76115357Skarels 		if (de_ubaalloc(ifu, ifrw, nmr) == 0) {
762*16208Skarels 			struct ifrw *rw;
76315357Skarels 
764*16208Skarels 			for (rw = ifu->ifu_r; rw < ifrw; rw++)
765*16208Skarels 				ubarelse(ifu->ifu_uban, &rw->ifrw_info);
76615357Skarels 			goto bad;
76715357Skarels 		}
76815357Skarels 	}
76915357Skarels 	/* and now transmit ring */
770*16208Skarels 	for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) {
771*16208Skarels 		ifrw = &ifxp->x_ifrw;
77215357Skarels 		if (de_ubaalloc(ifu, ifrw, nmr) == 0) {
773*16208Skarels 			struct ifxmt *xp;
77415357Skarels 
775*16208Skarels 			for (xp = ifu->ifu_w; xp < ifxp; xp++)
776*16208Skarels 				ubarelse(ifu->ifu_uban, &xp->x_ifrw.ifrw_info);
777*16208Skarels 			for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++)
778*16208Skarels 				ubarelse(ifu->ifu_uban, &ifrw->ifrw_info);
77915357Skarels 			goto bad;
78015357Skarels 		}
781*16208Skarels 		for (i = 0; i < nmr; i++)
782*16208Skarels 			ifxp->x_map[i] = ifrw->ifrw_mr[i];
783*16208Skarels 		ifxp->x_xswapd = 0;
78415357Skarels 	}
78515357Skarels 	return (1);
78615357Skarels bad:
78715357Skarels 	m_pgfree(cp, NTOT * ncl);
78815357Skarels 	ifu->ifu_r[0].ifrw_addr = 0;
78915357Skarels 	return(0);
79015357Skarels }
79115357Skarels 
79215357Skarels /*
79315357Skarels  * Setup either a ifrw structure by allocating UNIBUS map registers,
79415357Skarels  * possibly a buffered data path, and initializing the fields of
79515357Skarels  * the ifrw structure to minimize run-time overhead.
79615357Skarels  */
79715357Skarels static
79815357Skarels de_ubaalloc(ifu, ifrw, nmr)
79915357Skarels 	struct deuba *ifu;
80015357Skarels 	register struct ifrw *ifrw;
80115357Skarels 	int nmr;
80215357Skarels {
80315357Skarels 	register int info;
80415357Skarels 
80515357Skarels 	info =
80615357Skarels 	    uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen,
80715357Skarels 	        ifu->ifu_flags);
80815357Skarels 	if (info == 0)
80915357Skarels 		return (0);
81015357Skarels 	ifrw->ifrw_info = info;
81115357Skarels 	ifrw->ifrw_bdp = UBAI_BDP(info);
81215357Skarels 	ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT);
81315357Skarels 	ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1];
81415357Skarels 	return (1);
81515357Skarels }
81615357Skarels 
81715357Skarels /*
81815357Skarels  * Pull read data off a interface.
81915357Skarels  * Len is length of data, with local net header stripped.
82015357Skarels  * Off is non-zero if a trailer protocol was used, and
82115357Skarels  * gives the offset of the trailer information.
82215357Skarels  * We copy the trailer information and then all the normal
82315357Skarels  * data into mbufs.  When full cluster sized units are present
82415357Skarels  * on the interface on cluster boundaries we can get them more
82515357Skarels  * easily by remapping, and take advantage of this here.
82615357Skarels  */
82715357Skarels struct mbuf *
82815357Skarels deget(ifu, ifrw, totlen, off0)
82915357Skarels 	register struct deuba *ifu;
83015357Skarels 	register struct ifrw *ifrw;
83115357Skarels 	int totlen, off0;
83215357Skarels {
83315357Skarels 	struct mbuf *top, **mp, *m;
83415357Skarels 	int off = off0, len;
83515357Skarels 	register caddr_t cp = ifrw->ifrw_addr + ifu->ifu_hlen;
83615357Skarels 
83715357Skarels 	top = 0;
83815357Skarels 	mp = &top;
83915357Skarels 	while (totlen > 0) {
84015357Skarels 		MGET(m, M_DONTWAIT, MT_DATA);
84115357Skarels 		if (m == 0)
84215357Skarels 			goto bad;
84315357Skarels 		if (off) {
84415357Skarels 			len = totlen - off;
84515357Skarels 			cp = ifrw->ifrw_addr + ifu->ifu_hlen + off;
84615357Skarels 		} else
84715357Skarels 			len = totlen;
84815357Skarels 		if (len >= CLBYTES) {
84915357Skarels 			struct mbuf *p;
85015357Skarels 			struct pte *cpte, *ppte;
85115357Skarels 			int x, *ip, i;
85215357Skarels 
85315357Skarels 			MCLGET(p, 1);
85415357Skarels 			if (p == 0)
85515357Skarels 				goto nopage;
85615357Skarels 			len = m->m_len = CLBYTES;
85715357Skarels 			m->m_off = (int)p - (int)m;
85815357Skarels 			if (!claligned(cp))
85915357Skarels 				goto copy;
86015357Skarels 
86115357Skarels 			/*
86215357Skarels 			 * Switch pages mapped to UNIBUS with new page p,
86315357Skarels 			 * as quick form of copy.  Remap UNIBUS and invalidate.
86415357Skarels 			 */
86515357Skarels 			cpte = &Mbmap[mtocl(cp)*CLSIZE];
86615357Skarels 			ppte = &Mbmap[mtocl(p)*CLSIZE];
86715357Skarels 			x = btop(cp - ifrw->ifrw_addr);
86815357Skarels 			ip = (int *)&ifrw->ifrw_mr[x];
86915357Skarels 			for (i = 0; i < CLSIZE; i++) {
87015357Skarels 				struct pte t;
87115357Skarels 				t = *ppte; *ppte++ = *cpte; *cpte = t;
87215357Skarels 				*ip++ =
87315357Skarels 				    cpte++->pg_pfnum|ifrw->ifrw_proto;
87415357Skarels 				mtpr(TBIS, cp);
87515357Skarels 				cp += NBPG;
87615357Skarels 				mtpr(TBIS, (caddr_t)p);
87715357Skarels 				p += NBPG / sizeof (*p);
87815357Skarels 			}
87915357Skarels 			goto nocopy;
88015357Skarels 		}
88115357Skarels nopage:
88215357Skarels 		m->m_len = MIN(MLEN, len);
88315357Skarels 		m->m_off = MMINOFF;
88415357Skarels copy:
88515357Skarels 		bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len);
88615357Skarels 		cp += m->m_len;
88715357Skarels nocopy:
88815357Skarels 		*mp = m;
88915357Skarels 		mp = &m->m_next;
89015357Skarels 		if (off) {
89115357Skarels 			/* sort of an ALGOL-W style for statement... */
89215357Skarels 			off += m->m_len;
89315357Skarels 			if (off == totlen) {
89415357Skarels 				cp = ifrw->ifrw_addr + ifu->ifu_hlen;
89515357Skarels 				off = 0;
89615357Skarels 				totlen = off0;
89715357Skarels 			}
89815357Skarels 		} else
89915357Skarels 			totlen -= m->m_len;
90015357Skarels 	}
90115357Skarels 	return (top);
90215357Skarels bad:
90315357Skarels 	m_freem(top);
90415357Skarels 	return (0);
90515357Skarels }
90615357Skarels 
90715357Skarels /*
90815357Skarels  * Map a chain of mbufs onto a network interface
90915357Skarels  * in preparation for an i/o operation.
91015357Skarels  * The argument chain of mbufs includes the local network
91115357Skarels  * header which is copied to be in the mapped, aligned
91215357Skarels  * i/o space.
91315357Skarels  */
914*16208Skarels deput(ifu, n, m)
915*16208Skarels 	struct deuba *ifu;
916*16208Skarels 	int n;
91715357Skarels 	register struct mbuf *m;
91815357Skarels {
91915357Skarels 	register struct mbuf *mp;
92015357Skarels 	register caddr_t cp;
921*16208Skarels 	register struct ifxmt *ifxp;
922*16208Skarels 	register struct ifrw *ifrw;
92315357Skarels 	register int i;
924*16208Skarels 	int xswapd = 0;
925*16208Skarels 	int x, cc, t;
926*16208Skarels 	caddr_t dp;
92715357Skarels 
928*16208Skarels 	ifxp = &ifu->ifu_w[n];
929*16208Skarels 	ifrw = &ifxp->x_ifrw;
93015357Skarels 	cp = ifrw->ifrw_addr;
93115357Skarels 	while (m) {
93215357Skarels 		dp = mtod(m, char *);
93315357Skarels 		if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) {
934*16208Skarels 			struct pte *pte; int *ip;
935*16208Skarels 			pte = &Mbmap[mtocl(dp)*CLSIZE];
93615357Skarels 			x = btop(cp - ifrw->ifrw_addr);
93715357Skarels 			ip = (int *)&ifrw->ifrw_mr[x];
938*16208Skarels 			for (i = 0; i < CLSIZE; i++)
93915357Skarels 				*ip++ =
940*16208Skarels 				    ifrw->ifrw_proto | pte++->pg_pfnum;
941*16208Skarels 			xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT));
942*16208Skarels 			mp = m->m_next;
943*16208Skarels 			m->m_next = ifxp->x_xtofree;
944*16208Skarels 			ifxp->x_xtofree = m;
945*16208Skarels 			cp += m->m_len;
94615357Skarels 		} else {
94715357Skarels 			bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
94815357Skarels 			cp += m->m_len;
949*16208Skarels 			MFREE(m, mp);
95015357Skarels 		}
95115357Skarels 		m = mp;
95215357Skarels 	}
95315357Skarels 
954*16208Skarels 	/*
955*16208Skarels 	 * Xswapd is the set of clusters we just mapped out.  Ifxp->x_xswapd
956*16208Skarels 	 * is the set of clusters mapped out from before.  We compute
957*16208Skarels 	 * the number of clusters involved in this operation in x.
958*16208Skarels 	 * Clusters mapped out before and involved in this operation
959*16208Skarels 	 * should be unmapped so original pages will be accessed by the device.
960*16208Skarels 	 */
96115357Skarels 	cc = cp - ifrw->ifrw_addr;
962*16208Skarels 	x = ((cc - ifu->ifu_hlen) + CLBYTES - 1) >> CLSHIFT;
963*16208Skarels 	ifxp->x_xswapd &= ~xswapd;
964*16208Skarels 	while (i = ffs(ifxp->x_xswapd)) {
965*16208Skarels 		i--;
966*16208Skarels 		if (i >= x)
967*16208Skarels 			break;
968*16208Skarels 		ifxp->x_xswapd &= ~(1<<i);
969*16208Skarels 		i *= CLSIZE;
970*16208Skarels 		for (t = 0; t < CLSIZE; t++) {
971*16208Skarels 			ifrw->ifrw_mr[i] = ifxp->x_map[i];
972*16208Skarels 			i++;
973*16208Skarels 		}
974*16208Skarels 	}
975*16208Skarels 	ifxp->x_xswapd |= xswapd;
97615357Skarels 	return (cc);
97715357Skarels }
97815357Skarels 
97915357Skarels /*
98015357Skarels  * Process an ioctl request.
98115357Skarels  */
98215357Skarels deioctl(ifp, cmd, data)
98315357Skarels 	register struct ifnet *ifp;
98415357Skarels 	int cmd;
98515357Skarels 	caddr_t data;
98615357Skarels {
98715357Skarels 	register struct ifreq *ifr = (struct ifreq *)data;
98815357Skarels 	int s = splimp(), error = 0;
98915357Skarels 
99015357Skarels 	switch (cmd) {
99115357Skarels 
99215357Skarels 	case SIOCSIFADDR:
99315357Skarels 		if (ifp->if_flags & IFF_RUNNING)
99415357Skarels 			if_rtinit(ifp, -1);	/* delete previous route */
99515357Skarels 		desetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
99615357Skarels 		deinit(ifp->if_unit);
99715357Skarels 		break;
99815357Skarels 
99915357Skarels 	default:
100015357Skarels 		error = EINVAL;
100115357Skarels 	}
100215357Skarels 	splx(s);
100315357Skarels 	return (error);
100415357Skarels }
100515357Skarels 
100615357Skarels desetaddr(ifp, sin)
100715357Skarels 	register struct ifnet *ifp;
100815357Skarels 	register struct sockaddr_in *sin;
100915357Skarels {
101015357Skarels 
101115357Skarels 	ifp->if_addr = *(struct sockaddr *)sin;
101215357Skarels 	ifp->if_net = in_netof(sin->sin_addr);
101315357Skarels 	ifp->if_host[0] = in_lnaof(sin->sin_addr);
101415357Skarels 	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
101515357Skarels 	sin->sin_family = AF_INET;
101615357Skarels 	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
101715357Skarels 	ifp->if_flags |= IFF_BROADCAST;
101815357Skarels }
1019*16208Skarels #endif
1020