xref: /csrg-svn/sys/vax/if/if_de.c (revision 23672)
123503Ssklower /*
223503Ssklower  * Copyright (c) 1982 Regents of the University of California.
323503Ssklower  * All rights reserved.  The Berkeley software License Agreement
423503Ssklower  * specifies the terms and conditions for redistribution.
523503Ssklower  *
6*23672Ssklower  *	@(#)if_de.c	6.12 (Berkeley) 06/22/85
723503Ssklower  */
815357Skarels #include "de.h"
915357Skarels #if NDE > 0
1015357Skarels 
1115357Skarels /*
1215357Skarels  * DEC DEUNA interface
1315357Skarels  *
1415357Skarels  *	Lou Salkind
1515357Skarels  *	New York University
1615357Skarels  *
1715357Skarels  * TODO:
1815357Skarels  *	timeout routine (get statistics)
1915357Skarels  */
2015357Skarels #include "../machine/pte.h"
2115357Skarels 
2217110Sbloom #include "param.h"
2317110Sbloom #include "systm.h"
2417110Sbloom #include "mbuf.h"
2517110Sbloom #include "buf.h"
2617110Sbloom #include "protosw.h"
2717110Sbloom #include "socket.h"
2817110Sbloom #include "vmmac.h"
2917110Sbloom #include "ioctl.h"
3017110Sbloom #include "errno.h"
3115357Skarels 
3215357Skarels #include "../net/if.h"
3315357Skarels #include "../net/netisr.h"
3415357Skarels #include "../net/route.h"
3523503Ssklower 
3623503Ssklower #ifdef INET
3715357Skarels #include "../netinet/in.h"
3815357Skarels #include "../netinet/in_systm.h"
3919861Skarels #include "../netinet/in_var.h"
4015357Skarels #include "../netinet/ip.h"
4115357Skarels #include "../netinet/ip_var.h"
4215357Skarels #include "../netinet/if_ether.h"
4323503Ssklower #endif
4423503Ssklower 
4519952Sbloom #ifdef PUP
4615357Skarels #include "../netpup/pup.h"
4719952Sbloom #endif
4815357Skarels 
4923503Ssklower #ifdef NS
5023503Ssklower #include "../netns/ns.h"
5123503Ssklower #include "../netns/ns_if.h"
5223503Ssklower #endif
5323503Ssklower 
5415357Skarels #include "../vax/cpu.h"
5515357Skarels #include "../vax/mtpr.h"
5617110Sbloom #include "if_dereg.h"
5717110Sbloom #include "if_uba.h"
5815357Skarels #include "../vaxuba/ubareg.h"
5915357Skarels #include "../vaxuba/ubavar.h"
6015357Skarels 
6123559Ssklower #define	NXMT	3	/* number of transmit buffers */
6223559Ssklower #define	NRCV	7	/* number of receive buffers (must be > 1) */
6315357Skarels #define	NTOT	(NXMT + NRCV)
6415357Skarels 
6516279Skarels int	dedebug = 0;
6615916Skarels 
6715357Skarels int	deprobe(), deattach(), deintr();
6815357Skarels struct	uba_device *deinfo[NDE];
6915357Skarels u_short destd[] = { 0 };
7015357Skarels struct	uba_driver dedriver =
7115357Skarels 	{ deprobe, 0, deattach, 0, destd, "de", deinfo };
7215357Skarels int	deinit(),deoutput(),deioctl(),dereset();
7315357Skarels struct	mbuf *deget();
7415357Skarels 
7515357Skarels 
7615357Skarels /*
7716208Skarels  * The deuba structures generalizes the ifuba structure
7816208Skarels  * to an arbitrary number of receive and transmit buffers.
7915357Skarels  */
8016208Skarels struct	ifxmt {
8116208Skarels 	struct	ifrw x_ifrw;			/* mapping information */
8216208Skarels 	struct	pte x_map[IF_MAXNUBAMR];	/* output base pages */
8316208Skarels 	short	x_xswapd;			/* mask of clusters swapped */
8416208Skarels 	struct	mbuf *x_xtofree;		/* pages being dma'ed out */
8516208Skarels };
8616208Skarels 
8715357Skarels struct	deuba {
8815357Skarels 	short	ifu_uban;		/* uba number */
8915357Skarels 	short	ifu_hlen;		/* local net header length */
9015357Skarels 	struct	uba_regs *ifu_uba;	/* uba regs, in vm */
9115357Skarels 	struct	ifrw ifu_r[NRCV];	/* receive information */
9216208Skarels 	struct	ifxmt ifu_w[NXMT];	/* transmit information */
9315357Skarels 	short	ifu_flags;		/* used during uballoc's */
9415357Skarels };
9515357Skarels 
9615357Skarels /*
9715357Skarels  * Ethernet software status per interface.
9815357Skarels  *
9915357Skarels  * Each interface is referenced by a network interface structure,
10015357Skarels  * ds_if, which the routing code uses to locate the interface.
10115357Skarels  * This structure contains the output queue for the interface, its address, ...
10215357Skarels  * We also have, for each interface, a UBA interface structure, which
10315357Skarels  * contains information about the UNIBUS resources held by the interface:
10415357Skarels  * map registers, buffered data paths, etc.  Information is cached in this
10515357Skarels  * structure for use by the if_uba.c routines in running the interface
10615357Skarels  * efficiently.
10715357Skarels  */
10815357Skarels struct	de_softc {
10915357Skarels 	struct	arpcom ds_ac;		/* Ethernet common part */
11015357Skarels #define	ds_if	ds_ac.ac_if		/* network-visible interface */
11115357Skarels #define	ds_addr	ds_ac.ac_enaddr		/* hardware Ethernet address */
11215357Skarels 	int	ds_flags;
11315357Skarels #define	DSF_LOCK	1		/* lock out destart */
11415916Skarels #define	DSF_RUNNING	2
11515357Skarels 	int	ds_ubaddr;		/* map info for incore structs */
11615357Skarels 	struct	deuba ds_deuba;		/* unibus resource structure */
11715357Skarels 	/* the following structures are always mapped in */
11815357Skarels 	struct	de_pcbb ds_pcbb;	/* port control block */
11915357Skarels 	struct	de_ring ds_xrent[NXMT];	/* transmit ring entrys */
12015357Skarels 	struct	de_ring ds_rrent[NRCV];	/* receive ring entrys */
12115357Skarels 	struct	de_udbbuf ds_udbbuf;	/* UNIBUS data buffer */
12215357Skarels 	/* end mapped area */
12315357Skarels #define	INCORE_BASE(p)	((char *)&(p)->ds_pcbb)
12415357Skarels #define	RVAL_OFF(n)	((char *)&de_softc[0].n - INCORE_BASE(&de_softc[0]))
12515357Skarels #define	LVAL_OFF(n)	((char *)de_softc[0].n - INCORE_BASE(&de_softc[0]))
12615357Skarels #define	PCBB_OFFSET	RVAL_OFF(ds_pcbb)
12715357Skarels #define	XRENT_OFFSET	LVAL_OFF(ds_xrent)
12815357Skarels #define	RRENT_OFFSET	LVAL_OFF(ds_rrent)
12915357Skarels #define	UDBBUF_OFFSET	RVAL_OFF(ds_udbbuf)
13015357Skarels #define	INCORE_SIZE	RVAL_OFF(ds_xindex)
13115357Skarels 	int	ds_xindex;		/* UNA index into transmit chain */
13215357Skarels 	int	ds_rindex;		/* UNA index into receive chain */
13315357Skarels 	int	ds_xfree;		/* index for next transmit buffer */
13415357Skarels 	int	ds_nxmit;		/* # of transmits in progress */
13515357Skarels } de_softc[NDE];
13615357Skarels 
13715357Skarels deprobe(reg)
13815357Skarels 	caddr_t reg;
13915357Skarels {
14015357Skarels 	register int br, cvec;		/* r11, r10 value-result */
14115357Skarels 	register struct dedevice *addr = (struct dedevice *)reg;
14215357Skarels 	register i;
14315357Skarels 
14415357Skarels #ifdef lint
14515357Skarels 	br = 0; cvec = br; br = cvec;
14615357Skarels 	i = 0; derint(i); deintr(i);
14715357Skarels #endif
14815357Skarels 
14915357Skarels 	addr->pcsr0 = PCSR0_RSET;
15015357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
15115357Skarels 		;
15215357Skarels 	/* make board interrupt by executing a GETPCBB command */
15315357Skarels 	addr->pcsr0 = PCSR0_INTE;
15415357Skarels 	addr->pcsr2 = 0;
15515357Skarels 	addr->pcsr3 = 0;
15615357Skarels 	addr->pcsr0 = PCSR0_INTE|CMD_GETPCBB;
15715357Skarels 	DELAY(100000);
15815357Skarels 	return(1);
15915357Skarels }
16015357Skarels 
16115357Skarels /*
16215357Skarels  * Interface exists: make available by filling in network interface
16315357Skarels  * record.  System will initialize the interface when it is ready
16415357Skarels  * to accept packets.  We get the ethernet address here.
16515357Skarels  */
16615357Skarels deattach(ui)
16715357Skarels 	struct uba_device *ui;
16815357Skarels {
16915357Skarels 	register struct de_softc *ds = &de_softc[ui->ui_unit];
17015357Skarels 	register struct ifnet *ifp = &ds->ds_if;
17115357Skarels 	register struct dedevice *addr = (struct dedevice *)ui->ui_addr;
17215357Skarels 	int csr0;
17315357Skarels 
17415357Skarels 	ifp->if_unit = ui->ui_unit;
17515357Skarels 	ifp->if_name = "de";
17615357Skarels 	ifp->if_mtu = ETHERMTU;
17719861Skarels 	ifp->if_flags = IFF_BROADCAST;
17815357Skarels 
17915357Skarels 	/*
18015357Skarels 	 * Reset the board and temporarily map
18115357Skarels 	 * the pcbb buffer onto the Unibus.
18215357Skarels 	 */
18315357Skarels 	addr->pcsr0 = PCSR0_RSET;
18415357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
18515357Skarels 		;
18615357Skarels 	csr0 = addr->pcsr0;
18715357Skarels 	addr->pchigh = csr0 >> 8;
18815357Skarels 	if (csr0 & PCSR0_PCEI)
18915357Skarels 		printf("de%d: reset failed, csr0=%b csr1=%b\n", ui->ui_unit,
19015357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
19115357Skarels 	ds->ds_ubaddr = uballoc(ui->ui_ubanum, (char *)&ds->ds_pcbb,
19215357Skarels 		sizeof (struct de_pcbb), 0);
19315357Skarels 	addr->pcsr2 = ds->ds_ubaddr & 0xffff;
19415357Skarels 	addr->pcsr3 = (ds->ds_ubaddr >> 16) & 0x3;
19515357Skarels 	addr->pclow = CMD_GETPCBB;
19615357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
19715357Skarels 		;
19815357Skarels 	csr0 = addr->pcsr0;
19915357Skarels 	addr->pchigh = csr0 >> 8;
20015357Skarels 	if (csr0 & PCSR0_PCEI)
20115357Skarels 		printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit,
20215357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
20315357Skarels 	ds->ds_pcbb.pcbb0 = FC_RDPHYAD;
20415357Skarels 	addr->pclow = CMD_GETCMD;
20515357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
20615357Skarels 		;
20715357Skarels 	csr0 = addr->pcsr0;
20815357Skarels 	addr->pchigh = csr0 >> 8;
20915357Skarels 	if (csr0 & PCSR0_PCEI)
21015357Skarels 		printf("de%d: rdphyad failed, csr0=%b csr1=%b\n", ui->ui_unit,
21115357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
21215357Skarels 	ubarelse(ui->ui_ubanum, &ds->ds_ubaddr);
21315916Skarels 	if (dedebug)
21415916Skarels 		printf("de%d: addr=%d:%d:%d:%d:%d:%d\n", ui->ui_unit,
21515916Skarels 		    ds->ds_pcbb.pcbb2&0xff, (ds->ds_pcbb.pcbb2>>8)&0xff,
21615916Skarels 		    ds->ds_pcbb.pcbb4&0xff, (ds->ds_pcbb.pcbb4>>8)&0xff,
21715916Skarels 		    ds->ds_pcbb.pcbb6&0xff, (ds->ds_pcbb.pcbb6>>8)&0xff);
21819861Skarels  	bcopy((caddr_t)&ds->ds_pcbb.pcbb2, (caddr_t)ds->ds_addr,
21915357Skarels 	    sizeof (ds->ds_addr));
22015357Skarels 	ifp->if_init = deinit;
22115357Skarels 	ifp->if_output = deoutput;
22215357Skarels 	ifp->if_ioctl = deioctl;
22315357Skarels 	ifp->if_reset = dereset;
22415357Skarels 	ds->ds_deuba.ifu_flags = UBA_CANTWAIT;
22515357Skarels #ifdef notdef
22615357Skarels 	/* CAN WE USE BDP's ??? */
22715357Skarels 	ds->ds_deuba.ifu_flags |= UBA_NEEDBDP;
22815357Skarels #endif
22915357Skarels 	if_attach(ifp);
23015357Skarels }
23115357Skarels 
23215357Skarels /*
23315357Skarels  * Reset of interface after UNIBUS reset.
23415357Skarels  * If interface is on specified uba, reset its state.
23515357Skarels  */
23615357Skarels dereset(unit, uban)
23715357Skarels 	int unit, uban;
23815357Skarels {
23915357Skarels 	register struct uba_device *ui;
24015357Skarels 
24115357Skarels 	if (unit >= NDE || (ui = deinfo[unit]) == 0 || ui->ui_alive == 0 ||
24215357Skarels 	    ui->ui_ubanum != uban)
24315357Skarels 		return;
24415357Skarels 	printf(" de%d", unit);
24519861Skarels 	de_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
24615357Skarels 	deinit(unit);
24715357Skarels }
24815357Skarels 
24915357Skarels /*
25015357Skarels  * Initialization of interface; clear recorded pending
25115357Skarels  * operations, and reinitialize UNIBUS usage.
25215357Skarels  */
25315357Skarels deinit(unit)
25415357Skarels 	int unit;
25515357Skarels {
25615357Skarels 	register struct de_softc *ds = &de_softc[unit];
25715357Skarels 	register struct uba_device *ui = deinfo[unit];
25815357Skarels 	register struct dedevice *addr;
25915357Skarels 	register struct ifrw *ifrw;
26016208Skarels 	register struct ifxmt *ifxp;
26116208Skarels 	struct ifnet *ifp = &ds->ds_if;
26215357Skarels 	int s;
26315357Skarels 	struct de_ring *rp;
26415357Skarels 	int incaddr;
26515357Skarels 	int csr0;
26615357Skarels 
26719861Skarels 	/* not yet, if address still unknown */
26819861Skarels 	if (ifp->if_addrlist == (struct ifaddr *)0)
26915357Skarels 		return;
27015357Skarels 
27115357Skarels 	if (ifp->if_flags & IFF_RUNNING)
27219861Skarels 		return;
27315357Skarels 	if (de_ubainit(&ds->ds_deuba, ui->ui_ubanum,
27415357Skarels 	    sizeof (struct ether_header), (int)btoc(ETHERMTU)) == 0) {
27515357Skarels 		printf("de%d: can't initialize\n", unit);
27615357Skarels 		ds->ds_if.if_flags &= ~IFF_UP;
27715357Skarels 		return;
27815357Skarels 	}
27915357Skarels 	ds->ds_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(ds), INCORE_SIZE,0);
28015357Skarels 	addr = (struct dedevice *)ui->ui_addr;
28115357Skarels 
28215357Skarels 	/* set the pcbb block address */
28315357Skarels 	incaddr = ds->ds_ubaddr + PCBB_OFFSET;
28415357Skarels 	addr->pcsr2 = incaddr & 0xffff;
28515357Skarels 	addr->pcsr3 = (incaddr >> 16) & 0x3;
28615357Skarels 	addr->pclow = CMD_GETPCBB;
28715357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
28815357Skarels 		;
28915357Skarels 	csr0 = addr->pcsr0;
29015357Skarels 	addr->pchigh = csr0 >> 8;
29115357Skarels 	if (csr0 & PCSR0_PCEI)
29215357Skarels 		printf("de%d: pcbb failed, csr0=%b csr1=%b\n", ui->ui_unit,
29315357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
29415357Skarels 
29515357Skarels 	/* set the transmit and receive ring header addresses */
29615357Skarels 	incaddr = ds->ds_ubaddr + UDBBUF_OFFSET;
29715357Skarels 	ds->ds_pcbb.pcbb0 = FC_WTRING;
29815357Skarels 	ds->ds_pcbb.pcbb2 = incaddr & 0xffff;
29915357Skarels 	ds->ds_pcbb.pcbb4 = (incaddr >> 16) & 0x3;
30015357Skarels 
30115357Skarels 	incaddr = ds->ds_ubaddr + XRENT_OFFSET;
30215357Skarels 	ds->ds_udbbuf.b_tdrbl = incaddr & 0xffff;
30315357Skarels 	ds->ds_udbbuf.b_tdrbh = (incaddr >> 16) & 0x3;
30415357Skarels 	ds->ds_udbbuf.b_telen = sizeof (struct de_ring) / sizeof (short);
30515357Skarels 	ds->ds_udbbuf.b_trlen = NXMT;
30615357Skarels 	incaddr = ds->ds_ubaddr + RRENT_OFFSET;
30715357Skarels 	ds->ds_udbbuf.b_rdrbl = incaddr & 0xffff;
30815357Skarels 	ds->ds_udbbuf.b_rdrbh = (incaddr >> 16) & 0x3;
30915357Skarels 	ds->ds_udbbuf.b_relen = sizeof (struct de_ring) / sizeof (short);
31015357Skarels 	ds->ds_udbbuf.b_rrlen = NRCV;
31115357Skarels 
31215357Skarels 	addr->pclow = CMD_GETCMD;
31315357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
31415357Skarels 		;
31515357Skarels 	csr0 = addr->pcsr0;
31615357Skarels 	addr->pchigh = csr0 >> 8;
31715357Skarels 	if (csr0 & PCSR0_PCEI)
31815357Skarels 		printf("de%d: wtring failed, csr0=%b csr1=%b\n", ui->ui_unit,
31915357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
32015357Skarels 
32115357Skarels 	/* initialize the mode - enable hardware padding */
32215357Skarels 	ds->ds_pcbb.pcbb0 = FC_WTMODE;
32315357Skarels 	/* let hardware do padding - set MTCH bit on broadcast */
32415357Skarels 	ds->ds_pcbb.pcbb2 = MOD_TPAD|MOD_HDX;
32515357Skarels 	addr->pclow = CMD_GETCMD;
32615357Skarels 	while ((addr->pcsr0 & PCSR0_INTR) == 0)
32715357Skarels 		;
32815357Skarels 	csr0 = addr->pcsr0;
32915357Skarels 	addr->pchigh = csr0 >> 8;
33015357Skarels 	if (csr0 & PCSR0_PCEI)
33115357Skarels 		printf("de%d: wtmode failed, csr0=%b csr1=%b\n", ui->ui_unit,
33215357Skarels 		    csr0, PCSR0_BITS, addr->pcsr1, PCSR1_BITS);
33315357Skarels 
33415357Skarels 	/* set up the receive and transmit ring entries */
33516208Skarels 	ifxp = &ds->ds_deuba.ifu_w[0];
33615357Skarels 	for (rp = &ds->ds_xrent[0]; rp < &ds->ds_xrent[NXMT]; rp++) {
33716208Skarels 		rp->r_segbl = ifxp->x_ifrw.ifrw_info & 0xffff;
33816208Skarels 		rp->r_segbh = (ifxp->x_ifrw.ifrw_info >> 16) & 0x3;
33915357Skarels 		rp->r_flags = 0;
34016208Skarels 		ifxp++;
34115357Skarels 	}
34215357Skarels 	ifrw = &ds->ds_deuba.ifu_r[0];
34315357Skarels 	for (rp = &ds->ds_rrent[0]; rp < &ds->ds_rrent[NRCV]; rp++) {
34415357Skarels 		rp->r_slen = sizeof (struct de_buf);
34515357Skarels 		rp->r_segbl = ifrw->ifrw_info & 0xffff;
34615357Skarels 		rp->r_segbh = (ifrw->ifrw_info >> 16) & 0x3;
34715357Skarels 		rp->r_flags = RFLG_OWN;		/* hang receive */
34815357Skarels 		ifrw++;
34915357Skarels 	}
35015357Skarels 
35115357Skarels 	/* start up the board (rah rah) */
35215357Skarels 	s = splimp();
35315357Skarels 	ds->ds_rindex = ds->ds_xindex = ds->ds_xfree = 0;
35419861Skarels 	ds->ds_if.if_flags |= IFF_RUNNING;
35515916Skarels 	destart(unit);				/* queue output packets */
35615357Skarels 	addr->pclow = PCSR0_INTE;		/* avoid interlock */
35715357Skarels 	addr->pclow = CMD_START | PCSR0_INTE;
35815916Skarels 	ds->ds_flags |= DSF_RUNNING;
35915357Skarels 	splx(s);
36015357Skarels }
36115357Skarels 
36215357Skarels /*
36315357Skarels  * Setup output on interface.
36415357Skarels  * Get another datagram to send off of the interface queue,
36515357Skarels  * and map it to the interface before starting the output.
36615357Skarels  */
36715357Skarels destart(unit)
36815357Skarels 	int unit;
36915357Skarels {
37015357Skarels         int len;
37115357Skarels 	struct uba_device *ui = deinfo[unit];
37215357Skarels 	struct dedevice *addr = (struct dedevice *)ui->ui_addr;
37315357Skarels 	register struct de_softc *ds = &de_softc[unit];
37415357Skarels 	register struct de_ring *rp;
37515357Skarels 	struct mbuf *m;
37615357Skarels 	register int nxmit;
37715357Skarels 
37815357Skarels 	/*
37915357Skarels 	 * the following test is necessary, since
38015357Skarels 	 * the code is not reentrant and we have
38115357Skarels 	 * multiple transmission buffers.
38215357Skarels 	 */
38315357Skarels 	if (ds->ds_flags & DSF_LOCK)
38415357Skarels 		return;
38515357Skarels 	for (nxmit = ds->ds_nxmit; nxmit < NXMT; nxmit++) {
38615357Skarels 		IF_DEQUEUE(&ds->ds_if.if_snd, m);
38715357Skarels 		if (m == 0)
38815357Skarels 			break;
38915357Skarels 		rp = &ds->ds_xrent[ds->ds_xfree];
39015357Skarels 		if (rp->r_flags & XFLG_OWN)
39115357Skarels 			panic("deuna xmit in progress");
39216208Skarels 		len = deput(&ds->ds_deuba, ds->ds_xfree, m);
39315357Skarels 		if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP)
39415357Skarels 			UBAPURGE(ds->ds_deuba.ifu_uba,
39516208Skarels 			ds->ds_deuba.ifu_w[ds->ds_xfree].x_ifrw.ifrw_bdp);
39615357Skarels 		rp->r_slen = len;
39715357Skarels 		rp->r_tdrerr = 0;
39815357Skarels 		rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN;
39915357Skarels 
40015357Skarels 		ds->ds_xfree++;
40115357Skarels 		if (ds->ds_xfree == NXMT)
40215357Skarels 			ds->ds_xfree = 0;
40315357Skarels 	}
40415357Skarels 	if (ds->ds_nxmit != nxmit) {
40515357Skarels 		ds->ds_nxmit = nxmit;
40615916Skarels 		if (ds->ds_flags & DSF_RUNNING)
40715357Skarels 			addr->pclow = PCSR0_INTE|CMD_PDMD;
40815357Skarels 	}
40915357Skarels }
41015357Skarels 
41115357Skarels /*
41215357Skarels  * Command done interrupt.
41315357Skarels  */
41415357Skarels deintr(unit)
41515357Skarels 	int unit;
41615357Skarels {
41715357Skarels 	struct uba_device *ui = deinfo[unit];
41815357Skarels 	register struct dedevice *addr = (struct dedevice *)ui->ui_addr;
41915357Skarels 	register struct de_softc *ds = &de_softc[unit];
42015357Skarels 	register struct de_ring *rp;
42116208Skarels 	register struct ifxmt *ifxp;
42215357Skarels 	short csr0;
42315357Skarels 
42415357Skarels 	/* save flags right away - clear out interrupt bits */
42515357Skarels 	csr0 = addr->pcsr0;
42615357Skarels 	addr->pchigh = csr0 >> 8;
42715357Skarels 
42815357Skarels 
42915357Skarels 	ds->ds_flags |= DSF_LOCK;	/* prevent entering destart */
43015357Skarels 	/*
43115357Skarels 	 * if receive, put receive buffer on mbuf
43215357Skarels 	 * and hang the request again
43315357Skarels 	 */
43415357Skarels 	derecv(unit);
43515357Skarels 
43615357Skarels 	/*
43715357Skarels 	 * Poll transmit ring and check status.
43815357Skarels 	 * Be careful about loopback requests.
43915357Skarels 	 * Then free buffer space and check for
44015357Skarels 	 * more transmit requests.
44115357Skarels 	 */
44215357Skarels 	for ( ; ds->ds_nxmit > 0; ds->ds_nxmit--) {
44315357Skarels 		rp = &ds->ds_xrent[ds->ds_xindex];
44415357Skarels 		if (rp->r_flags & XFLG_OWN)
44515357Skarels 			break;
44615357Skarels 		ds->ds_if.if_opackets++;
44716208Skarels 		ifxp = &ds->ds_deuba.ifu_w[ds->ds_xindex];
44815357Skarels 		/* check for unusual conditions */
44915357Skarels 		if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) {
45015357Skarels 			if (rp->r_flags & XFLG_ERRS) {
45115357Skarels 				/* output error */
45215357Skarels 				ds->ds_if.if_oerrors++;
45315916Skarels 				if (dedebug)
45415357Skarels 			printf("de%d: oerror, flags=%b tdrerr=%b (len=%d)\n",
45515357Skarels 				    unit, rp->r_flags, XFLG_BITS,
45615357Skarels 				    rp->r_tdrerr, XERR_BITS, rp->r_slen);
45715357Skarels 			} else if (rp->r_flags & XFLG_ONE) {
45815357Skarels 				/* one collision */
45915357Skarels 				ds->ds_if.if_collisions++;
46015357Skarels 			} else if (rp->r_flags & XFLG_MORE) {
46115357Skarels 				/* more than one collision */
46215357Skarels 				ds->ds_if.if_collisions += 2;	/* guess */
46315357Skarels 			} else if (rp->r_flags & XFLG_MTCH) {
46415357Skarels 				/* received our own packet */
46515357Skarels 				ds->ds_if.if_ipackets++;
46616208Skarels 				deread(ds, &ifxp->x_ifrw,
46715357Skarels 				    rp->r_slen - sizeof (struct ether_header));
46815357Skarels 			}
46915357Skarels 		}
47016208Skarels 		if (ifxp->x_xtofree) {
47116208Skarels 			m_freem(ifxp->x_xtofree);
47216208Skarels 			ifxp->x_xtofree = 0;
47316208Skarels 		}
47415357Skarels 		/* check if next transmit buffer also finished */
47515357Skarels 		ds->ds_xindex++;
47615357Skarels 		if (ds->ds_xindex == NXMT)
47715357Skarels 			ds->ds_xindex = 0;
47815357Skarels 	}
47915357Skarels 	ds->ds_flags &= ~DSF_LOCK;
48015357Skarels 	destart(unit);
48115357Skarels 
48215357Skarels 	if (csr0 & PCSR0_RCBI) {
48315357Skarels 		printf("de%d: buffer unavailable\n", unit);
48415357Skarels 		addr->pclow = PCSR0_INTE|CMD_PDMD;
48515357Skarels 	}
48615357Skarels }
48715357Skarels 
48815357Skarels /*
48915357Skarels  * Ethernet interface receiver interface.
49015357Skarels  * If input error just drop packet.
49115357Skarels  * Otherwise purge input buffered data path and examine
49215357Skarels  * packet to determine type.  If can't determine length
49315357Skarels  * from type, then have to drop packet.  Othewise decapsulate
49415357Skarels  * packet based on type and pass to type specific higher-level
49515357Skarels  * input routine.
49615357Skarels  */
49715357Skarels derecv(unit)
49815357Skarels 	int unit;
49915357Skarels {
50015357Skarels 	register struct de_softc *ds = &de_softc[unit];
50115357Skarels 	register struct de_ring *rp;
50215357Skarels 	int len;
50315357Skarels 
50415357Skarels 	rp = &ds->ds_rrent[ds->ds_rindex];
50515357Skarels 	while ((rp->r_flags & RFLG_OWN) == 0) {
50615357Skarels 		ds->ds_if.if_ipackets++;
50715357Skarels 		if (ds->ds_deuba.ifu_flags & UBA_NEEDBDP)
50815357Skarels 			UBAPURGE(ds->ds_deuba.ifu_uba,
50915357Skarels 			ds->ds_deuba.ifu_r[ds->ds_rindex].ifrw_bdp);
51015357Skarels 		len = (rp->r_lenerr&RERR_MLEN) - sizeof (struct ether_header)
51115357Skarels 			- 4;	/* don't forget checksum! */
51215357Skarels 		/* check for errors */
51315357Skarels 		if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) ||
51415357Skarels 		    (rp->r_flags&(RFLG_STP|RFLG_ENP)) != (RFLG_STP|RFLG_ENP) ||
51515357Skarels 		    (rp->r_lenerr & (RERR_BUFL|RERR_UBTO|RERR_NCHN)) ||
51615357Skarels 		    len < ETHERMIN || len > ETHERMTU) {
51715357Skarels 			ds->ds_if.if_ierrors++;
51815916Skarels 			if (dedebug)
51915357Skarels 			printf("de%d: ierror, flags=%b lenerr=%b (len=%d)\n",
52015357Skarels 				unit, rp->r_flags, RFLG_BITS, rp->r_lenerr,
52115357Skarels 				RERR_BITS, len);
52215357Skarels 		} else
52315357Skarels 			deread(ds, &ds->ds_deuba.ifu_r[ds->ds_rindex], len);
52415357Skarels 
52515357Skarels 		/* hang the receive buffer again */
52615357Skarels 		rp->r_lenerr = 0;
52715357Skarels 		rp->r_flags = RFLG_OWN;
52815357Skarels 
52915357Skarels 		/* check next receive buffer */
53015357Skarels 		ds->ds_rindex++;
53115357Skarels 		if (ds->ds_rindex == NRCV)
53215357Skarels 			ds->ds_rindex = 0;
53315357Skarels 		rp = &ds->ds_rrent[ds->ds_rindex];
53415357Skarels 	}
53515357Skarels }
53615357Skarels 
53715357Skarels /*
53815357Skarels  * Pass a packet to the higher levels.
53915357Skarels  * We deal with the trailer protocol here.
54015357Skarels  */
54115357Skarels deread(ds, ifrw, len)
54215357Skarels 	register struct de_softc *ds;
54315357Skarels 	struct ifrw *ifrw;
54415357Skarels 	int len;
54515357Skarels {
54615357Skarels 	struct ether_header *eh;
54715357Skarels     	struct mbuf *m;
54815357Skarels 	int off, resid;
54916722Sbloom 	int s;
55015357Skarels 	register struct ifqueue *inq;
55115357Skarels 
55215357Skarels 	/*
55319861Skarels 	 * Deal with trailer protocol: if type is trailer type
55415357Skarels 	 * get true type from first 16-bit word past data.
55515357Skarels 	 * Remember that type was trailer by setting off.
55615357Skarels 	 */
55715357Skarels 	eh = (struct ether_header *)ifrw->ifrw_addr;
55815357Skarels 	eh->ether_type = ntohs((u_short)eh->ether_type);
55915357Skarels #define	dedataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
56019861Skarels 	if (eh->ether_type >= ETHERTYPE_TRAIL &&
56119861Skarels 	    eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
56219861Skarels 		off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
56315357Skarels 		if (off >= ETHERMTU)
56415357Skarels 			return;		/* sanity */
56515357Skarels 		eh->ether_type = ntohs(*dedataaddr(eh, off, u_short *));
56615357Skarels 		resid = ntohs(*(dedataaddr(eh, off+2, u_short *)));
56715357Skarels 		if (off + resid > len)
56815357Skarels 			return;		/* sanity */
56915357Skarels 		len = off + resid;
57015357Skarels 	} else
57115357Skarels 		off = 0;
57215357Skarels 	if (len == 0)
57315357Skarels 		return;
57415357Skarels 
57515357Skarels 	/*
57615357Skarels 	 * Pull packet off interface.  Off is nonzero if packet
57715357Skarels 	 * has trailing header; deget will then force this header
57815357Skarels 	 * information to be at the front, but we still have to drop
57915357Skarels 	 * the type and length which are at the front of any trailer data.
58015357Skarels 	 */
58115357Skarels 	m = deget(&ds->ds_deuba, ifrw, len, off);
58215357Skarels 	if (m == 0)
58315357Skarels 		return;
58415357Skarels 	if (off) {
58515357Skarels 		m->m_off += 2 * sizeof (u_short);
58615357Skarels 		m->m_len -= 2 * sizeof (u_short);
58715357Skarels 	}
58815357Skarels 	switch (eh->ether_type) {
58915357Skarels 
59015357Skarels #ifdef INET
59119861Skarels 	case ETHERTYPE_IP:
59215357Skarels 		schednetisr(NETISR_IP);
59315357Skarels 		inq = &ipintrq;
59415357Skarels 		break;
59515357Skarels 
59619861Skarels 	case ETHERTYPE_ARP:
59715357Skarels 		arpinput(&ds->ds_ac, m);
59815357Skarels 		return;
59915357Skarels #endif
60023503Ssklower #ifdef NS
60123503Ssklower 	case ETHERTYPE_NS:
60223503Ssklower 		schednetisr(NETISR_NS);
60323503Ssklower 		inq = &nsintrq;
60423503Ssklower 		break;
60523503Ssklower 
60623503Ssklower #endif
60715357Skarels 	default:
60815357Skarels 		m_freem(m);
60915357Skarels 		return;
61015357Skarels 	}
61115357Skarels 
61216722Sbloom 	s = splimp();
61315357Skarels 	if (IF_QFULL(inq)) {
61415357Skarels 		IF_DROP(inq);
61516722Sbloom 		splx(s);
61615357Skarels 		m_freem(m);
61715357Skarels 		return;
61815357Skarels 	}
61915357Skarels 	IF_ENQUEUE(inq, m);
62016722Sbloom 	splx(s);
62115357Skarels }
62215357Skarels 
62315357Skarels /*
62415357Skarels  * Ethernet output routine.
62515357Skarels  * Encapsulate a packet of type family for the local net.
62615357Skarels  * Use trailer local net encapsulation if enough data in first
62715357Skarels  * packet leaves a multiple of 512 bytes of data in remainder.
62815357Skarels  */
62915357Skarels deoutput(ifp, m0, dst)
63015357Skarels 	struct ifnet *ifp;
63115357Skarels 	struct mbuf *m0;
63215357Skarels 	struct sockaddr *dst;
63315357Skarels {
63415357Skarels 	int type, s, error;
63519861Skarels  	u_char edst[6];
63615357Skarels 	struct in_addr idst;
63715357Skarels 	register struct de_softc *ds = &de_softc[ifp->if_unit];
63815357Skarels 	register struct mbuf *m = m0;
63915357Skarels 	register struct ether_header *eh;
64015357Skarels 	register int off;
64115357Skarels 
64215357Skarels 	switch (dst->sa_family) {
64315357Skarels 
64415357Skarels #ifdef INET
64515357Skarels 	case AF_INET:
64615357Skarels 		idst = ((struct sockaddr_in *)dst)->sin_addr;
64719861Skarels  		if (!arpresolve(&ds->ds_ac, m, &idst, edst))
64815357Skarels 			return (0);	/* if not yet resolved */
64915357Skarels 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
65015357Skarels 		/* need per host negotiation */
65115357Skarels 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
65215357Skarels 		if (off > 0 && (off & 0x1ff) == 0 &&
65315357Skarels 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
65419861Skarels 			type = ETHERTYPE_TRAIL + (off>>9);
65515357Skarels 			m->m_off -= 2 * sizeof (u_short);
65615357Skarels 			m->m_len += 2 * sizeof (u_short);
65719861Skarels 			*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
65815357Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
65915357Skarels 			goto gottrailertype;
66015357Skarels 		}
66119861Skarels 		type = ETHERTYPE_IP;
66215357Skarels 		off = 0;
66315357Skarels 		goto gottype;
66415357Skarels #endif
66523503Ssklower #ifdef NS
66623503Ssklower 	case AF_NS:
66723503Ssklower 		type = ETHERTYPE_NS;
66823503Ssklower  		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
66923503Ssklower 		(caddr_t)edst, sizeof (edst));
67023503Ssklower 		off = 0;
67123503Ssklower 		goto gottype;
67223503Ssklower #endif
67315357Skarels 
67415357Skarels 	case AF_UNSPEC:
67515357Skarels 		eh = (struct ether_header *)dst->sa_data;
67619861Skarels  		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
67715357Skarels 		type = eh->ether_type;
67815357Skarels 		goto gottype;
67915357Skarels 
68015357Skarels 	default:
68115357Skarels 		printf("de%d: can't handle af%d\n", ifp->if_unit,
68215357Skarels 			dst->sa_family);
68315357Skarels 		error = EAFNOSUPPORT;
68415357Skarels 		goto bad;
68515357Skarels 	}
68615357Skarels 
68715357Skarels gottrailertype:
68815357Skarels 	/*
68915357Skarels 	 * Packet to be sent as trailer: move first packet
69015357Skarels 	 * (control information) to end of chain.
69115357Skarels 	 */
69215357Skarels 	while (m->m_next)
69315357Skarels 		m = m->m_next;
69415357Skarels 	m->m_next = m0;
69515357Skarels 	m = m0->m_next;
69615357Skarels 	m0->m_next = 0;
69715357Skarels 	m0 = m;
69815357Skarels 
69915357Skarels gottype:
70015357Skarels 	/*
70115357Skarels 	 * Add local net header.  If no space in first mbuf,
70215357Skarels 	 * allocate another.
70315357Skarels 	 */
70415357Skarels 	if (m->m_off > MMAXOFF ||
70515357Skarels 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
70615357Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
70715357Skarels 		if (m == 0) {
70815357Skarels 			error = ENOBUFS;
70915357Skarels 			goto bad;
71015357Skarels 		}
71115357Skarels 		m->m_next = m0;
71215357Skarels 		m->m_off = MMINOFF;
71315357Skarels 		m->m_len = sizeof (struct ether_header);
71415357Skarels 	} else {
71515357Skarels 		m->m_off -= sizeof (struct ether_header);
71615357Skarels 		m->m_len += sizeof (struct ether_header);
71715357Skarels 	}
71815357Skarels 	eh = mtod(m, struct ether_header *);
71915357Skarels 	eh->ether_type = htons((u_short)type);
72019861Skarels  	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
72115357Skarels 	/* DEUNA fills in source address */
72215357Skarels 
72315357Skarels 	/*
72415357Skarels 	 * Queue message on interface, and start output if interface
72515357Skarels 	 * not yet active.
72615357Skarels 	 */
72715357Skarels 	s = splimp();
72815357Skarels 	if (IF_QFULL(&ifp->if_snd)) {
72915357Skarels 		IF_DROP(&ifp->if_snd);
73015357Skarels 		splx(s);
73115357Skarels 		m_freem(m);
73215357Skarels 		return (ENOBUFS);
73315357Skarels 	}
73415357Skarels 	IF_ENQUEUE(&ifp->if_snd, m);
73515357Skarels 	destart(ifp->if_unit);
73615357Skarels 	splx(s);
73715357Skarels 	return (0);
73815357Skarels 
73915357Skarels bad:
74015357Skarels 	m_freem(m0);
74115357Skarels 	return (error);
74215357Skarels }
74315357Skarels 
74415357Skarels /*
74515357Skarels  * Routines supporting UNIBUS network interfaces.
74615357Skarels  */
74715357Skarels 
74815357Skarels /*
74915357Skarels  * Init UNIBUS for interface on uban whose headers of size hlen are to
75015357Skarels  * end on a page boundary.  We allocate a UNIBUS map register for the page
75115357Skarels  * with the header, and nmr more UNIBUS map registers for i/o on the adapter,
75215357Skarels  * doing this for each receive and transmit buffer.  We also
75315357Skarels  * allocate page frames in the mbuffer pool for these pages.
75415357Skarels  */
75515357Skarels de_ubainit(ifu, uban, hlen, nmr)
75615357Skarels 	register struct deuba *ifu;
75715357Skarels 	int uban, hlen, nmr;
75815357Skarels {
75915357Skarels 	register caddr_t cp, dp;
76015357Skarels 	register struct ifrw *ifrw;
76116208Skarels 	register struct ifxmt *ifxp;
76216208Skarels 	int i, ncl;
76315357Skarels 
76415357Skarels 	ncl = clrnd(nmr + CLSIZE) / CLSIZE;
76515357Skarels 	if (ifu->ifu_r[0].ifrw_addr)
76615357Skarels 		/*
76715357Skarels 		 * If the first read buffer has a non-zero
76815357Skarels 		 * address, it means we have already allocated core
76915357Skarels 		 */
77015357Skarels 		cp = ifu->ifu_r[0].ifrw_addr - (CLBYTES - hlen);
77115357Skarels 	else {
77215357Skarels 		cp = m_clalloc(NTOT * ncl, MPG_SPACE);
77315357Skarels 		if (cp == 0)
77415357Skarels 			return (0);
77515357Skarels 		ifu->ifu_hlen = hlen;
77615357Skarels 		ifu->ifu_uban = uban;
77715357Skarels 		ifu->ifu_uba = uba_hd[uban].uh_uba;
77815357Skarels 		dp = cp + CLBYTES - hlen;
77915357Skarels 		for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) {
78015357Skarels 			ifrw->ifrw_addr = dp;
78115357Skarels 			dp += ncl * CLBYTES;
78215357Skarels 		}
78316208Skarels 		for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) {
78416208Skarels 			ifxp->x_ifrw.ifrw_addr = dp;
78515357Skarels 			dp += ncl * CLBYTES;
78615357Skarels 		}
78715357Skarels 	}
78815357Skarels 	/* allocate for receive ring */
78915357Skarels 	for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) {
79015357Skarels 		if (de_ubaalloc(ifu, ifrw, nmr) == 0) {
79116208Skarels 			struct ifrw *rw;
79215357Skarels 
79316208Skarels 			for (rw = ifu->ifu_r; rw < ifrw; rw++)
79416208Skarels 				ubarelse(ifu->ifu_uban, &rw->ifrw_info);
79515357Skarels 			goto bad;
79615357Skarels 		}
79715357Skarels 	}
79815357Skarels 	/* and now transmit ring */
79916208Skarels 	for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) {
80016208Skarels 		ifrw = &ifxp->x_ifrw;
80115357Skarels 		if (de_ubaalloc(ifu, ifrw, nmr) == 0) {
80216208Skarels 			struct ifxmt *xp;
80315357Skarels 
80416208Skarels 			for (xp = ifu->ifu_w; xp < ifxp; xp++)
80516208Skarels 				ubarelse(ifu->ifu_uban, &xp->x_ifrw.ifrw_info);
80616208Skarels 			for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++)
80716208Skarels 				ubarelse(ifu->ifu_uban, &ifrw->ifrw_info);
80815357Skarels 			goto bad;
80915357Skarels 		}
81016208Skarels 		for (i = 0; i < nmr; i++)
81116208Skarels 			ifxp->x_map[i] = ifrw->ifrw_mr[i];
81216208Skarels 		ifxp->x_xswapd = 0;
81315357Skarels 	}
81415357Skarels 	return (1);
81515357Skarels bad:
81615357Skarels 	m_pgfree(cp, NTOT * ncl);
81715357Skarels 	ifu->ifu_r[0].ifrw_addr = 0;
81815357Skarels 	return(0);
81915357Skarels }
82015357Skarels 
82115357Skarels /*
82215357Skarels  * Setup either a ifrw structure by allocating UNIBUS map registers,
82315357Skarels  * possibly a buffered data path, and initializing the fields of
82415357Skarels  * the ifrw structure to minimize run-time overhead.
82515357Skarels  */
82615357Skarels static
82715357Skarels de_ubaalloc(ifu, ifrw, nmr)
82815357Skarels 	struct deuba *ifu;
82915357Skarels 	register struct ifrw *ifrw;
83015357Skarels 	int nmr;
83115357Skarels {
83215357Skarels 	register int info;
83315357Skarels 
83415357Skarels 	info =
83515357Skarels 	    uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen,
83615357Skarels 	        ifu->ifu_flags);
83715357Skarels 	if (info == 0)
83815357Skarels 		return (0);
83915357Skarels 	ifrw->ifrw_info = info;
84015357Skarels 	ifrw->ifrw_bdp = UBAI_BDP(info);
84115357Skarels 	ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT);
84215357Skarels 	ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1];
84315357Skarels 	return (1);
84415357Skarels }
84515357Skarels 
84615357Skarels /*
84715357Skarels  * Pull read data off a interface.
84815357Skarels  * Len is length of data, with local net header stripped.
84915357Skarels  * Off is non-zero if a trailer protocol was used, and
85015357Skarels  * gives the offset of the trailer information.
85115357Skarels  * We copy the trailer information and then all the normal
85215357Skarels  * data into mbufs.  When full cluster sized units are present
85315357Skarels  * on the interface on cluster boundaries we can get them more
85415357Skarels  * easily by remapping, and take advantage of this here.
85515357Skarels  */
85615357Skarels struct mbuf *
85715357Skarels deget(ifu, ifrw, totlen, off0)
85815357Skarels 	register struct deuba *ifu;
85915357Skarels 	register struct ifrw *ifrw;
86015357Skarels 	int totlen, off0;
86115357Skarels {
86215357Skarels 	struct mbuf *top, **mp, *m;
86315357Skarels 	int off = off0, len;
86415357Skarels 	register caddr_t cp = ifrw->ifrw_addr + ifu->ifu_hlen;
86515357Skarels 
86615357Skarels 	top = 0;
86715357Skarels 	mp = &top;
86815357Skarels 	while (totlen > 0) {
86915357Skarels 		MGET(m, M_DONTWAIT, MT_DATA);
87015357Skarels 		if (m == 0)
87115357Skarels 			goto bad;
87215357Skarels 		if (off) {
87315357Skarels 			len = totlen - off;
87415357Skarels 			cp = ifrw->ifrw_addr + ifu->ifu_hlen + off;
87515357Skarels 		} else
87615357Skarels 			len = totlen;
87715357Skarels 		if (len >= CLBYTES) {
87815357Skarels 			struct mbuf *p;
87915357Skarels 			struct pte *cpte, *ppte;
88015357Skarels 			int x, *ip, i;
88115357Skarels 
88215357Skarels 			MCLGET(p, 1);
88315357Skarels 			if (p == 0)
88415357Skarels 				goto nopage;
88515357Skarels 			len = m->m_len = CLBYTES;
88615357Skarels 			m->m_off = (int)p - (int)m;
88715357Skarels 			if (!claligned(cp))
88815357Skarels 				goto copy;
88915357Skarels 
89015357Skarels 			/*
89115357Skarels 			 * Switch pages mapped to UNIBUS with new page p,
89215357Skarels 			 * as quick form of copy.  Remap UNIBUS and invalidate.
89315357Skarels 			 */
89415357Skarels 			cpte = &Mbmap[mtocl(cp)*CLSIZE];
89515357Skarels 			ppte = &Mbmap[mtocl(p)*CLSIZE];
89615357Skarels 			x = btop(cp - ifrw->ifrw_addr);
89715357Skarels 			ip = (int *)&ifrw->ifrw_mr[x];
89815357Skarels 			for (i = 0; i < CLSIZE; i++) {
89915357Skarels 				struct pte t;
90015357Skarels 				t = *ppte; *ppte++ = *cpte; *cpte = t;
90115357Skarels 				*ip++ =
90215357Skarels 				    cpte++->pg_pfnum|ifrw->ifrw_proto;
90315357Skarels 				mtpr(TBIS, cp);
90415357Skarels 				cp += NBPG;
90515357Skarels 				mtpr(TBIS, (caddr_t)p);
90615357Skarels 				p += NBPG / sizeof (*p);
90715357Skarels 			}
90815357Skarels 			goto nocopy;
90915357Skarels 		}
91015357Skarels nopage:
91115357Skarels 		m->m_len = MIN(MLEN, len);
91215357Skarels 		m->m_off = MMINOFF;
91315357Skarels copy:
91415357Skarels 		bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len);
91515357Skarels 		cp += m->m_len;
91615357Skarels nocopy:
91715357Skarels 		*mp = m;
91815357Skarels 		mp = &m->m_next;
91915357Skarels 		if (off) {
92015357Skarels 			/* sort of an ALGOL-W style for statement... */
92115357Skarels 			off += m->m_len;
92215357Skarels 			if (off == totlen) {
92315357Skarels 				cp = ifrw->ifrw_addr + ifu->ifu_hlen;
92415357Skarels 				off = 0;
92515357Skarels 				totlen = off0;
92615357Skarels 			}
92715357Skarels 		} else
92815357Skarels 			totlen -= m->m_len;
92915357Skarels 	}
93015357Skarels 	return (top);
93115357Skarels bad:
93215357Skarels 	m_freem(top);
93315357Skarels 	return (0);
93415357Skarels }
93515357Skarels 
93615357Skarels /*
93715357Skarels  * Map a chain of mbufs onto a network interface
93815357Skarels  * in preparation for an i/o operation.
93915357Skarels  * The argument chain of mbufs includes the local network
94015357Skarels  * header which is copied to be in the mapped, aligned
94115357Skarels  * i/o space.
94215357Skarels  */
94316208Skarels deput(ifu, n, m)
94416208Skarels 	struct deuba *ifu;
94516208Skarels 	int n;
94615357Skarels 	register struct mbuf *m;
94715357Skarels {
94815357Skarels 	register struct mbuf *mp;
94915357Skarels 	register caddr_t cp;
95016208Skarels 	register struct ifxmt *ifxp;
95116208Skarels 	register struct ifrw *ifrw;
95215357Skarels 	register int i;
95316208Skarels 	int xswapd = 0;
95416208Skarels 	int x, cc, t;
95516208Skarels 	caddr_t dp;
95615357Skarels 
95716208Skarels 	ifxp = &ifu->ifu_w[n];
95816208Skarels 	ifrw = &ifxp->x_ifrw;
95915357Skarels 	cp = ifrw->ifrw_addr;
96015357Skarels 	while (m) {
96115357Skarels 		dp = mtod(m, char *);
96215357Skarels 		if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) {
96316208Skarels 			struct pte *pte; int *ip;
96416208Skarels 			pte = &Mbmap[mtocl(dp)*CLSIZE];
96515357Skarels 			x = btop(cp - ifrw->ifrw_addr);
96615357Skarels 			ip = (int *)&ifrw->ifrw_mr[x];
96716208Skarels 			for (i = 0; i < CLSIZE; i++)
96815357Skarels 				*ip++ =
96916208Skarels 				    ifrw->ifrw_proto | pte++->pg_pfnum;
97016208Skarels 			xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT));
97116208Skarels 			mp = m->m_next;
97216208Skarels 			m->m_next = ifxp->x_xtofree;
97316208Skarels 			ifxp->x_xtofree = m;
97416208Skarels 			cp += m->m_len;
97515357Skarels 		} else {
97615357Skarels 			bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
97715357Skarels 			cp += m->m_len;
97816208Skarels 			MFREE(m, mp);
97915357Skarels 		}
98015357Skarels 		m = mp;
98115357Skarels 	}
98215357Skarels 
98316208Skarels 	/*
98416208Skarels 	 * Xswapd is the set of clusters we just mapped out.  Ifxp->x_xswapd
98516208Skarels 	 * is the set of clusters mapped out from before.  We compute
98616208Skarels 	 * the number of clusters involved in this operation in x.
98716208Skarels 	 * Clusters mapped out before and involved in this operation
98816208Skarels 	 * should be unmapped so original pages will be accessed by the device.
98916208Skarels 	 */
99015357Skarels 	cc = cp - ifrw->ifrw_addr;
99116208Skarels 	x = ((cc - ifu->ifu_hlen) + CLBYTES - 1) >> CLSHIFT;
99216208Skarels 	ifxp->x_xswapd &= ~xswapd;
99316208Skarels 	while (i = ffs(ifxp->x_xswapd)) {
99416208Skarels 		i--;
99516208Skarels 		if (i >= x)
99616208Skarels 			break;
99716208Skarels 		ifxp->x_xswapd &= ~(1<<i);
99816208Skarels 		i *= CLSIZE;
99916208Skarels 		for (t = 0; t < CLSIZE; t++) {
100016208Skarels 			ifrw->ifrw_mr[i] = ifxp->x_map[i];
100116208Skarels 			i++;
100216208Skarels 		}
100316208Skarels 	}
100416208Skarels 	ifxp->x_xswapd |= xswapd;
100515357Skarels 	return (cc);
100615357Skarels }
100715357Skarels 
100815357Skarels /*
100915357Skarels  * Process an ioctl request.
101015357Skarels  */
101115357Skarels deioctl(ifp, cmd, data)
101215357Skarels 	register struct ifnet *ifp;
101315357Skarels 	int cmd;
101415357Skarels 	caddr_t data;
101515357Skarels {
101619861Skarels 	register struct ifaddr *ifa = (struct ifaddr *)data;
101715357Skarels 	int s = splimp(), error = 0;
101815357Skarels 
101915357Skarels 	switch (cmd) {
102015357Skarels 
102115357Skarels 	case SIOCSIFADDR:
102219861Skarels 		ifp->if_flags |= IFF_UP;
102315357Skarels 		deinit(ifp->if_unit);
102419861Skarels 
102519861Skarels 		switch (ifa->ifa_addr.sa_family) {
102623503Ssklower #ifdef INET
102719861Skarels 		case AF_INET:
102819861Skarels 			((struct arpcom *)ifp)->ac_ipaddr =
102919861Skarels 				IA_SIN(ifa)->sin_addr;
103019861Skarels 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
103119861Skarels 			break;
103223503Ssklower #endif
103323503Ssklower #ifdef NS
103423503Ssklower 		case AF_NS:
103523559Ssklower 		    {
103623559Ssklower 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
103723559Ssklower 
103823559Ssklower 			if (ns_nullhost(*ina)) {
103923559Ssklower 				ina->x_host = * (union ns_host *)
104023503Ssklower 				     (de_softc[ifp->if_unit].ds_addr);
104123559Ssklower 			} else {
104223559Ssklower 				de_setaddr(ina->x_host.c_host,ifp->if_unit);
104323559Ssklower 			}
104423503Ssklower 			break;
104523559Ssklower 		    }
104623503Ssklower #endif
104719861Skarels 		}
104815357Skarels 		break;
104915357Skarels 
105015357Skarels 	default:
105115357Skarels 		error = EINVAL;
105215357Skarels 	}
105315357Skarels 	splx(s);
105415357Skarels 	return (error);
105515357Skarels }
105623559Ssklower 
105723559Ssklower /*
105823559Ssklower  * set ethernet address for unit
105923559Ssklower  */
106023559Ssklower de_setaddr(physaddr, unit)
106123559Ssklower u_char *physaddr;
106223559Ssklower int unit;
106323559Ssklower {
106423559Ssklower 	register struct de_softc *ds = &de_softc[unit];
106523559Ssklower 	register struct uba_device *ui = deinfo[unit];
106623559Ssklower 	register struct dedevice *addr= (struct dedevice *)ui->ui_addr;
106723559Ssklower 	int csr0;
106823559Ssklower 
1069*23672Ssklower 	if (! (ds->ds_flags & DSF_RUNNING))
1070*23672Ssklower 		return;
1071*23672Ssklower 
107223559Ssklower 	bcopy(physaddr, &ds->ds_pcbb.pcbb2, 6);
107323559Ssklower 	ds->ds_pcbb.pcbb0 = FC_WTPHYAD;
1074*23672Ssklower 	addr->pclow = PCSR0_INTE|CMD_PDMD;
107523559Ssklower 	csr0 = addr->pcsr0;
107623559Ssklower 	addr->pchigh = csr0 >> 8;
107723559Ssklower 	if (csr0 & PCSR0_PCEI)
107823559Ssklower 		printf("de%d: wtphyad failed, csr0=%b csr1=%b\n",
107923559Ssklower 		    ui->ui_unit, csr0, PCSR0_BITS,
108023559Ssklower 		    addr->pcsr1, PCSR1_BITS);
108123559Ssklower }
108223559Ssklower 
108316208Skarels #endif
108423559Ssklower 
1085