xref: /csrg-svn/sys/vax/if/if_dmc.c (revision 27266)
123286Smckusick /*
223286Smckusick  * Copyright (c) 1982 Regents of the University of California.
323286Smckusick  * All rights reserved.  The Berkeley software License Agreement
423286Smckusick  * specifies the terms and conditions for redistribution.
523286Smckusick  *
6*27266Skarels  *	@(#)if_dmc.c	6.12 (Berkeley) 04/23/86
723286Smckusick  */
85725Sroot 
95725Sroot #include "dmc.h"
105725Sroot #if NDMC > 0
1117565Skarels 
125725Sroot /*
135725Sroot  * DMC11 device driver, internet version
145725Sroot  *
1517565Skarels  *	Bill Nesheim
1617221Stef  *	Cornell University
1711191Ssam  *
1817565Skarels  *	Lou Salkind
1917565Skarels  *	New York University
205725Sroot  */
2117565Skarels 
2217565Skarels /* #define DEBUG	/* for base table dump on fatal error */
2317565Skarels 
249794Ssam #include "../machine/pte.h"
255725Sroot 
2617111Sbloom #include "param.h"
2717111Sbloom #include "systm.h"
2817111Sbloom #include "mbuf.h"
2917111Sbloom #include "buf.h"
3017221Stef #include "ioctl.h"		/* must precede tty.h */
3117111Sbloom #include "tty.h"
3217111Sbloom #include "protosw.h"
3317111Sbloom #include "socket.h"
3426282Skarels #include "syslog.h"
3517111Sbloom #include "vmmac.h"
3617111Sbloom #include "errno.h"
378460Sroot 
388460Sroot #include "../net/if.h"
399176Ssam #include "../net/netisr.h"
408460Sroot #include "../net/route.h"
4124796Skarels 
4224796Skarels #ifdef	INET
438416Swnj #include "../netinet/in.h"
448416Swnj #include "../netinet/in_systm.h"
4517565Skarels #include "../netinet/ip.h"
4624796Skarels #endif
478460Sroot 
488460Sroot #include "../vax/cpu.h"
498460Sroot #include "../vax/mtpr.h"
5017111Sbloom #include "if_uba.h"
5117111Sbloom #include "if_dmc.h"
528460Sroot #include "../vaxuba/ubareg.h"
538460Sroot #include "../vaxuba/ubavar.h"
545725Sroot 
5517565Skarels #include "../h/time.h"
5617565Skarels #include "../h/kernel.h"
5717565Skarels 
5817565Skarels int	dmctimer;			/* timer started? */
5917565Skarels int	dmc_timeout = 8;		/* timeout value */
6017565Skarels int	dmcwatch();
6117565Skarels 
625725Sroot /*
635725Sroot  * Driver information for auto-configuration stuff.
645725Sroot  */
6513061Ssam int	dmcprobe(), dmcattach(), dmcinit(), dmcioctl();
6613061Ssam int	dmcoutput(), dmcreset();
675725Sroot struct	uba_device *dmcinfo[NDMC];
685725Sroot u_short	dmcstd[] = { 0 };
695725Sroot struct	uba_driver dmcdriver =
705725Sroot 	{ dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
715725Sroot 
7217221Stef #define NRCV 7
7317565Skarels #define NXMT 3
7424796Skarels #define NCMDS	(NRCV+NXMT+4)	/* size of command queue */
7517221Stef 
7617565Skarels #define printd if(dmcdebug)printf
7717565Skarels int dmcdebug = 0;
7817565Skarels 
7917221Stef /* error reporting intervals */
8017221Stef #define DMC_RPNBFS	50
8117221Stef #define DMC_RPDSC	1
8217565Skarels #define DMC_RPTMO	10
8317565Skarels #define DMC_RPDCK	10
8417221Stef 
8517221Stef struct  dmc_command {
8617221Stef 	char	qp_cmd;		/* command */
8717221Stef 	short	qp_ubaddr;	/* buffer address */
8817221Stef 	short	qp_cc;		/* character count || XMEM */
8917221Stef 	struct	dmc_command *qp_next;	/* next command on queue */
9017221Stef };
9117221Stef 
9217221Stef struct dmcbufs {
9317221Stef 	int	ubinfo;		/* from uballoc */
9417221Stef 	short	cc;		/* buffer size */
9517221Stef 	short	flags;		/* access control */
9617221Stef };
9717221Stef #define	DBUF_OURS	0	/* buffer is available */
9817221Stef #define	DBUF_DMCS	1	/* buffer claimed by somebody */
9917221Stef #define	DBUF_XMIT	4	/* transmit buffer */
10017565Skarels #define	DBUF_RCV	8	/* receive buffer */
10117221Stef 
10217221Stef 
10317221Stef /*
1045725Sroot  * DMC software status per interface.
1055725Sroot  *
1065725Sroot  * Each interface is referenced by a network interface structure,
1075725Sroot  * sc_if, which the routing code uses to locate the interface.
1085725Sroot  * This structure contains the output queue for the interface, its address, ...
10917221Stef  * We also have, for each interface, a  set of 7 UBA interface structures
11017221Stef  * for each, which
11117221Stef  * contain information about the UNIBUS resources held by the interface:
1125725Sroot  * map registers, buffered data paths, etc.  Information is cached in this
1135725Sroot  * structure for use by the if_uba.c routines in running the interface
1145725Sroot  * efficiently.
1155725Sroot  */
1165725Sroot struct dmc_softc {
1175725Sroot 	struct	ifnet sc_if;		/* network-visible interface */
11817565Skarels 	struct	dmcbufs sc_rbufs[NRCV];	/* receive buffer info */
11917221Stef 	struct	dmcbufs sc_xbufs[NXMT];	/* transmit buffer info */
12024796Skarels 	struct	ifubinfo sc_ifuba;	/* UNIBUS resources */
12124796Skarels 	struct	ifrw sc_ifr[NRCV];	/* UNIBUS receive buffer maps */
12224796Skarels 	struct	ifxmt sc_ifw[NXMT];	/* UNIBUS receive buffer maps */
12326933Skarels 	short	sc_oused;		/* output buffers currently in use */
12426933Skarels 	short	sc_iused;		/* input buffers given to DMC */
12526933Skarels 	short	sc_flag;		/* flags */
12626933Skarels 	int	sc_nticks;		/* seconds since last interrupt */
1275725Sroot 	int	sc_ubinfo;		/* UBA mapping info for base table */
12817221Stef 	int	sc_errors[4];		/* non-fatal error counters */
12917221Stef #define sc_datck sc_errors[0]
13017221Stef #define sc_timeo sc_errors[1]
13117221Stef #define sc_nobuf sc_errors[2]
13217221Stef #define sc_disc  sc_errors[3]
13317221Stef 	/* command queue stuff */
13417565Skarels 	struct	dmc_command sc_cmdbuf[NCMDS];
13517221Stef 	struct	dmc_command *sc_qhead;	/* head of command queue */
13617221Stef 	struct	dmc_command *sc_qtail;	/* tail of command queue */
13717221Stef 	struct	dmc_command *sc_qactive;	/* command in progress */
13817221Stef 	struct	dmc_command *sc_qfreeh;	/* head of list of free cmd buffers */
13917221Stef 	struct	dmc_command *sc_qfreet;	/* tail of list of free cmd buffers */
14017221Stef 	/* end command queue stuff */
1415725Sroot } dmc_softc[NDMC];
1425725Sroot 
1435725Sroot /* flags */
144*27266Skarels #define DMC_ALLOC	0x01		/* unibus resources allocated */
145*27266Skarels #define DMC_BMAPPED	0x02		/* base table mapped */
146*27266Skarels #define DMC_RESTART	0x04		/* software restart in progress */
147*27266Skarels #define DMC_ACTIVE	0x08		/* device active */
148*27266Skarels #define DMC_RUNNING	0x20		/* device initialized */
1495725Sroot 
15017565Skarels struct dmc_base {
15117565Skarels 	short	d_base[128];		/* DMC base table */
1525725Sroot } dmc_base[NDMC];
1535725Sroot 
15417221Stef /* queue manipulation macros */
15517221Stef #define	QUEUE_AT_HEAD(qp, head, tail) \
15617221Stef 	(qp)->qp_next = (head); \
15717221Stef 	(head) = (qp); \
15817221Stef 	if ((tail) == (struct dmc_command *) 0) \
15917221Stef 		(tail) = (head)
1605725Sroot 
16117221Stef #define QUEUE_AT_TAIL(qp, head, tail) \
16217221Stef 	if ((tail)) \
16317221Stef 		(tail)->qp_next = (qp); \
16417221Stef 	else \
16517221Stef 		(head) = (qp); \
16617221Stef 	(qp)->qp_next = (struct dmc_command *) 0; \
16717221Stef 	(tail) = (qp)
16817221Stef 
16917221Stef #define DEQUEUE(head, tail) \
17017221Stef 	(head) = (head)->qp_next;\
17117221Stef 	if ((head) == (struct dmc_command *) 0)\
17217221Stef 		(tail) = (head)
17317221Stef 
1745725Sroot dmcprobe(reg)
1755725Sroot 	caddr_t reg;
1765725Sroot {
1775725Sroot 	register int br, cvec;
1785725Sroot 	register struct dmcdevice *addr = (struct dmcdevice *)reg;
1795725Sroot 	register int i;
1805725Sroot 
1815725Sroot #ifdef lint
1825725Sroot 	br = 0; cvec = br; br = cvec;
1835725Sroot 	dmcrint(0); dmcxint(0);
1845725Sroot #endif
1855725Sroot 	addr->bsel1 = DMC_MCLR;
1865725Sroot 	for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
1875725Sroot 		;
18817565Skarels 	if ((addr->bsel1 & DMC_RUN) == 0) {
18917565Skarels 		printf("dmcprobe: can't start device\n" );
1906334Ssam 		return (0);
19117565Skarels 	}
1925725Sroot 	addr->bsel0 = DMC_RQI|DMC_IEI;
19317565Skarels 	/* let's be paranoid */
19417565Skarels 	addr->bsel0 |= DMC_RQI|DMC_IEI;
19517565Skarels 	DELAY(1000000);
1965725Sroot 	addr->bsel1 = DMC_MCLR;
1975725Sroot 	for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
1985725Sroot 		;
1996334Ssam 	return (1);
2005725Sroot }
2015725Sroot 
2025725Sroot /*
2035725Sroot  * Interface exists: make available by filling in network interface
2045725Sroot  * record.  System will initialize the interface when it is ready
2055725Sroot  * to accept packets.
2065725Sroot  */
2075725Sroot dmcattach(ui)
2085725Sroot 	register struct uba_device *ui;
2095725Sroot {
2105725Sroot 	register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
2115725Sroot 
2125725Sroot 	sc->sc_if.if_unit = ui->ui_unit;
2135725Sroot 	sc->sc_if.if_name = "dmc";
2145725Sroot 	sc->sc_if.if_mtu = DMCMTU;
2155725Sroot 	sc->sc_if.if_init = dmcinit;
2165725Sroot 	sc->sc_if.if_output = dmcoutput;
21713061Ssam 	sc->sc_if.if_ioctl = dmcioctl;
2188976Sroot 	sc->sc_if.if_reset = dmcreset;
21917221Stef 	sc->sc_if.if_flags = IFF_POINTOPOINT;
22024796Skarels 	sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
22117221Stef 
22217565Skarels 	if (dmctimer == 0) {
22317565Skarels 		dmctimer = 1;
22417565Skarels 		timeout(dmcwatch, (caddr_t) 0, hz);
22517221Stef 	}
22624796Skarels 	if_attach(&sc->sc_if);
2275725Sroot }
2285725Sroot 
2295725Sroot /*
2305725Sroot  * Reset of interface after UNIBUS reset.
23119862Skarels  * If interface is on specified UBA, reset its state.
2325725Sroot  */
2335725Sroot dmcreset(unit, uban)
2345725Sroot 	int unit, uban;
2355725Sroot {
2365725Sroot 	register struct uba_device *ui;
23717221Stef 	register struct dmc_softc *sc = &dmc_softc[unit];
2385725Sroot 
2395725Sroot 	if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
2405725Sroot 	    ui->ui_ubanum != uban)
2415725Sroot 		return;
2425725Sroot 	printf(" dmc%d", unit);
24317565Skarels 	sc->sc_flag = 0;
24419862Skarels 	sc->sc_if.if_flags &= ~IFF_RUNNING;
2455725Sroot 	dmcinit(unit);
2465725Sroot }
2475725Sroot 
2485725Sroot /*
2495725Sroot  * Initialization of interface; reinitialize UNIBUS usage.
2505725Sroot  */
2515725Sroot dmcinit(unit)
2525725Sroot 	int unit;
2535725Sroot {
2545725Sroot 	register struct dmc_softc *sc = &dmc_softc[unit];
2555725Sroot 	register struct uba_device *ui = dmcinfo[unit];
2565725Sroot 	register struct dmcdevice *addr;
25713061Ssam 	register struct ifnet *ifp = &sc->sc_if;
25817221Stef 	register struct ifrw *ifrw;
25917221Stef 	register struct ifxmt *ifxp;
26017221Stef 	register struct dmcbufs *rp;
26117565Skarels 	register struct dmc_command *qp;
26219862Skarels 	struct ifaddr *ifa;
26317221Stef 	int base;
26417565Skarels 	int s;
2655725Sroot 
26617221Stef 	addr = (struct dmcdevice *)ui->ui_addr;
26717221Stef 
26819862Skarels 	/*
26919862Skarels 	 * Check to see that an address has been set
27019862Skarels 	 * (both local and destination for an address family).
27119862Skarels 	 */
27219862Skarels 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
27319862Skarels 		if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family)
27419862Skarels 			break;
27519862Skarels 	if (ifa == (struct ifaddr *) 0)
2765725Sroot 		return;
27717221Stef 
27817221Stef 	if ((addr->bsel1&DMC_RUN) == 0) {
27917221Stef 		printf("dmcinit: DMC not running\n");
28019862Skarels 		ifp->if_flags &= ~IFF_UP;
28117221Stef 		return;
28217221Stef 	}
28317221Stef 	/* map base table */
28417565Skarels 	if ((sc->sc_flag & DMC_BMAPPED) == 0) {
28517221Stef 		sc->sc_ubinfo = uballoc(ui->ui_ubanum,
28617221Stef 			(caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0);
28717221Stef 		sc->sc_flag |= DMC_BMAPPED;
28817221Stef 	}
28917221Stef 	/* initialize UNIBUS resources */
29017221Stef 	sc->sc_iused = sc->sc_oused = 0;
29119862Skarels 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
29224796Skarels 		if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum,
29324796Skarels 		    sizeof(struct dmc_header), (int)btoc(DMCMTU),
29424796Skarels 		    sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) {
29519862Skarels 			printf("dmc%d: can't allocate uba resources\n", unit);
29613061Ssam 			ifp->if_flags &= ~IFF_UP;
29713061Ssam 			return;
29813061Ssam 		}
29919862Skarels 		ifp->if_flags |= IFF_RUNNING;
3005725Sroot 	}
301*27266Skarels 	sc->sc_flag |= DMC_RUNNING;
30217221Stef 
30317221Stef 	/* initialize buffer pool */
30417565Skarels 	/* receives */
30524796Skarels 	ifrw = &sc->sc_ifr[0];
30617221Stef 	for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
30717221Stef 		rp->ubinfo = ifrw->ifrw_info & 0x3ffff;
30817565Skarels 		rp->cc = DMCMTU + sizeof (struct dmc_header);
30917221Stef 		rp->flags = DBUF_OURS|DBUF_RCV;
31017221Stef 		ifrw++;
3116363Ssam 	}
31217221Stef 	/* transmits */
31324796Skarels 	ifxp = &sc->sc_ifw[0];
31417221Stef 	for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
31524796Skarels 		rp->ubinfo = ifxp->ifw_info & 0x3ffff;
31617221Stef 		rp->cc = 0;
31717221Stef 		rp->flags = DBUF_OURS|DBUF_XMIT;
31817221Stef 		ifxp++;
31917221Stef 	}
32017565Skarels 
32117565Skarels 	/* set up command queues */
32217565Skarels 	sc->sc_qfreeh = sc->sc_qfreet
32317565Skarels 		 = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive =
32417565Skarels 		(struct dmc_command *)0;
32517565Skarels 	/* set up free command buffer list */
32617565Skarels 	for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) {
32717565Skarels 		QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
32817565Skarels 	}
32917565Skarels 
33017221Stef 	/* base in */
33117221Stef 	base = sc->sc_ubinfo & 0x3ffff;
33217565Skarels 	dmcload(sc, DMC_BASEI, base, (base>>2) & DMC_XMEM);
33317221Stef 	/* specify half duplex operation, flags tell if primary */
33417221Stef 	/* or secondary station */
33517221Stef 	if (ui->ui_flags == 0)
336*27266Skarels 		/* use DDCMP mode in full duplex */
33717565Skarels 		dmcload(sc, DMC_CNTLI, 0, 0);
33817221Stef 	else if (ui->ui_flags == 1)
33917565Skarels 		/* use MAINTENENCE mode */
34017565Skarels 		dmcload(sc, DMC_CNTLI, 0, DMC_MAINT );
34117221Stef 	else if (ui->ui_flags == 2)
34217221Stef 		/* use DDCMP half duplex as primary station */
34317221Stef 		dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX);
34417221Stef 	else if (ui->ui_flags == 3)
34517221Stef 		/* use DDCMP half duplex as secondary station */
34617221Stef 		dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC);
34717565Skarels 
34817565Skarels 	/* enable operation done interrupts */
34917565Skarels 	sc->sc_flag &= ~DMC_ACTIVE;
35017565Skarels 	while ((addr->bsel2 & DMC_IEO) == 0)
35117565Skarels 		addr->bsel2 |= DMC_IEO;
35217565Skarels 	s = spl5();
35317221Stef 	/* queue first NRCV buffers for DMC to fill */
35417221Stef 	for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
35517221Stef 		rp->flags |= DBUF_DMCS;
35617221Stef 		dmcload(sc, DMC_READ, rp->ubinfo,
35717565Skarels 			(((rp->ubinfo>>2)&DMC_XMEM) | rp->cc));
35817221Stef 		sc->sc_iused++;
35917221Stef 	}
36017565Skarels 	splx(s);
3615725Sroot }
3625725Sroot 
3635725Sroot /*
3645725Sroot  * Start output on interface.  Get another datagram
3655725Sroot  * to send from the interface queue and map it to
3665725Sroot  * the interface before starting output.
36717221Stef  *
36817221Stef  * Must be called at spl 5
3695725Sroot  */
3705725Sroot dmcstart(dev)
3715725Sroot 	dev_t dev;
3725725Sroot {
3735725Sroot 	int unit = minor(dev);
3745725Sroot 	register struct dmc_softc *sc = &dmc_softc[unit];
3755725Sroot 	struct mbuf *m;
37617221Stef 	register struct dmcbufs *rp;
37717221Stef 	register int n;
3785725Sroot 
3795725Sroot 	/*
38017221Stef 	 * Dequeue up to NXMT requests and map them to the UNIBUS.
38117221Stef 	 * If no more requests, or no dmc buffers available, just return.
3825725Sroot 	 */
38317221Stef 	n = 0;
38417221Stef 	for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) {
38517221Stef 		/* find an available buffer */
38617565Skarels 		if ((rp->flags & DBUF_DMCS) == 0) {
38717221Stef 			IF_DEQUEUE(&sc->sc_if.if_snd, m);
38817221Stef 			if (m == 0)
38917221Stef 				return;
39017221Stef 			/* mark it dmcs */
39117221Stef 			rp->flags |= (DBUF_DMCS);
39217221Stef 			/*
39317221Stef 			 * Have request mapped to UNIBUS for transmission
39417221Stef 			 * and start the output.
39517221Stef 			 */
39624796Skarels 			rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m);
39717565Skarels 			rp->cc &= DMC_CCOUNT;
39817221Stef 			sc->sc_oused++;
39917221Stef 			dmcload(sc, DMC_WRITE, rp->ubinfo,
40017221Stef 				rp->cc | ((rp->ubinfo>>2)&DMC_XMEM));
40117221Stef 		}
40217221Stef 		n++;
40317221Stef 	}
4045725Sroot }
4055725Sroot 
4065725Sroot /*
4075725Sroot  * Utility routine to load the DMC device registers.
4085725Sroot  */
4095725Sroot dmcload(sc, type, w0, w1)
4105725Sroot 	register struct dmc_softc *sc;
4115725Sroot 	int type, w0, w1;
4125725Sroot {
4135725Sroot 	register struct dmcdevice *addr;
41417221Stef 	register int unit, sps;
41517221Stef 	register struct dmc_command *qp;
4165725Sroot 
41717565Skarels 	unit = sc - dmc_softc;
4185725Sroot 	addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
4195725Sroot 	sps = spl5();
42017221Stef 
42117221Stef 	/* grab a command buffer from the free list */
42217221Stef 	if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0)
42317221Stef 		panic("dmc command queue overflow");
42417221Stef 	DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet);
42517221Stef 
42617221Stef 	/* fill in requested info */
42717221Stef 	qp->qp_cmd = (type | DMC_RQI);
42817221Stef 	qp->qp_ubaddr = w0;
42917221Stef 	qp->qp_cc = w1;
43017221Stef 
43117221Stef 	if (sc->sc_qactive) {	/* command in progress */
43217221Stef 		if (type == DMC_READ) {
43317221Stef 			QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail);
43417221Stef 		} else {
43517221Stef 			QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail);
43617221Stef 		}
43717221Stef 	} else {	/* command port free */
43817221Stef 		sc->sc_qactive = qp;
43917221Stef 		addr->bsel0 = qp->qp_cmd;
4405725Sroot 		dmcrint(unit);
44117221Stef 	}
4425725Sroot 	splx(sps);
4435725Sroot }
4445725Sroot 
4455725Sroot /*
4465725Sroot  * DMC interface receiver interrupt.
4475725Sroot  * Ready to accept another command,
4485725Sroot  * pull one off the command queue.
4495725Sroot  */
4505725Sroot dmcrint(unit)
4515725Sroot 	int unit;
4525725Sroot {
4535725Sroot 	register struct dmc_softc *sc;
4545725Sroot 	register struct dmcdevice *addr;
45517221Stef 	register struct dmc_command *qp;
4565725Sroot 	register int n;
4575725Sroot 
4585725Sroot 	addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
4595725Sroot 	sc = &dmc_softc[unit];
46017221Stef 	if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) {
46117565Skarels 		printf("dmc%d: dmcrint no command\n", unit);
46217221Stef 		return;
46317221Stef 	}
4645725Sroot 	while (addr->bsel0&DMC_RDYI) {
46517221Stef 		addr->sel4 = qp->qp_ubaddr;
46617221Stef 		addr->sel6 = qp->qp_cc;
4675725Sroot 		addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
46817221Stef 		/* free command buffer */
46917221Stef 		QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
47017221Stef 		while (addr->bsel0 & DMC_RDYI) {
47117221Stef 			/*
47217221Stef 			 * Can't check for RDYO here 'cause
47317221Stef 			 * this routine isn't reentrant!
47417221Stef 			 */
47517221Stef 			DELAY(5);
47617221Stef 		}
47717221Stef 		/* move on to next command */
47817565Skarels 		if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0)
47917565Skarels 			break;		/* all done */
48017221Stef 		/* more commands to do, start the next one */
48117221Stef 		qp = sc->sc_qactive;
48217221Stef 		DEQUEUE(sc->sc_qhead, sc->sc_qtail);
48317221Stef 		addr->bsel0 = qp->qp_cmd;
4845725Sroot 		n = RDYSCAN;
48517565Skarels 		while (n-- > 0)
48617565Skarels 			if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO))
48717565Skarels 				break;
4885725Sroot 	}
48917221Stef 	if (sc->sc_qactive) {
49017221Stef 		addr->bsel0 |= DMC_IEI|DMC_RQI;
49117221Stef 		/* VMS does it twice !*$%@# */
49217221Stef 		addr->bsel0 |= DMC_IEI|DMC_RQI;
49317221Stef 	}
49417565Skarels 
4955725Sroot }
4965725Sroot 
4975725Sroot /*
4985725Sroot  * DMC interface transmitter interrupt.
49917221Stef  * A transfer may have completed, check for errors.
5005725Sroot  * If it was a read, notify appropriate protocol.
5015725Sroot  * If it was a write, pull the next one off the queue.
5025725Sroot  */
5035725Sroot dmcxint(unit)
5045725Sroot 	int unit;
5055725Sroot {
5065725Sroot 	register struct dmc_softc *sc;
50713065Ssam 	register struct ifnet *ifp;
5085725Sroot 	struct uba_device *ui = dmcinfo[unit];
5095725Sroot 	struct dmcdevice *addr;
5105725Sroot 	struct mbuf *m;
51117565Skarels 	struct ifqueue *inq;
512*27266Skarels 	int arg, pkaddr, cmd, len, s;
51317221Stef 	register struct ifrw *ifrw;
51417221Stef 	register struct dmcbufs *rp;
51517565Skarels 	register struct ifxmt *ifxp;
51617565Skarels 	struct dmc_header *dh;
51717565Skarels 	int off, resid;
5185725Sroot 
5195725Sroot 	addr = (struct dmcdevice *)ui->ui_addr;
52017221Stef 	sc = &dmc_softc[unit];
52117221Stef 	ifp = &sc->sc_if;
52217221Stef 
52317565Skarels 	while (addr->bsel2 & DMC_RDYO) {
5245725Sroot 
52517565Skarels 		cmd = addr->bsel2 & 0xff;
52617565Skarels 		arg = addr->sel6 & 0xffff;
52717565Skarels 		/* reconstruct UNIBUS address of buffer returned to us */
52817565Skarels 		pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff);
52917565Skarels 		/* release port */
53017565Skarels 		addr->bsel2 &= ~DMC_RDYO;
53117565Skarels 		switch (cmd & 07) {
53217565Skarels 
53317565Skarels 		case DMC_OUR:
53417565Skarels 			/*
53517565Skarels 			 * A read has completed.
53617565Skarels 			 * Pass packet to type specific
53717565Skarels 			 * higher-level input routine.
53817565Skarels 			 */
53917565Skarels 			ifp->if_ipackets++;
54017565Skarels 			/* find location in dmcuba struct */
54124796Skarels 			ifrw= &sc->sc_ifr[0];
54217565Skarels 			for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
54317565Skarels 				if(rp->ubinfo == pkaddr)
54417565Skarels 					break;
54517565Skarels 				ifrw++;
54617565Skarels 			}
54717565Skarels 			if (rp >= &sc->sc_rbufs[NRCV])
54817565Skarels 				panic("dmc rcv");
54917565Skarels 			if ((rp->flags & DBUF_DMCS) == 0)
55017565Skarels 				printf("dmc%d: done unalloc rbuf\n", unit);
55117565Skarels 
55217565Skarels 			len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header);
55317565Skarels 			if (len < 0 || len > DMCMTU) {
55417565Skarels 				ifp->if_ierrors++;
55517565Skarels 				printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n",
55617565Skarels 				    unit, pkaddr, len);
55717565Skarels 				goto setup;
55817565Skarels 			}
55917565Skarels 			/*
56017565Skarels 			 * Deal with trailer protocol: if type is trailer
56117565Skarels 			 * get true type from first 16-bit word past data.
56217565Skarels 			 * Remember that type was trailer by setting off.
56317565Skarels 			 */
56417565Skarels 			dh = (struct dmc_header *)ifrw->ifrw_addr;
56517565Skarels 			dh->dmc_type = ntohs((u_short)dh->dmc_type);
56617565Skarels #define dmcdataaddr(dh, off, type)	((type)(((caddr_t)((dh)+1)+(off))))
56717565Skarels 			if (dh->dmc_type >= DMC_TRAILER &&
56817565Skarels 			    dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) {
56917565Skarels 				off = (dh->dmc_type - DMC_TRAILER) * 512;
57017565Skarels 				if (off >= DMCMTU)
57117565Skarels 					goto setup;		/* sanity */
57217565Skarels 				dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *));
57317565Skarels 				resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *)));
57417565Skarels 				if (off + resid > len)
57517565Skarels 					goto setup;		/* sanity */
57617565Skarels 				len = off + resid;
57717565Skarels 			} else
57817565Skarels 				off = 0;
57917565Skarels 			if (len == 0)
58017565Skarels 				goto setup;
58117565Skarels 
58217565Skarels 			/*
58317565Skarels 			 * Pull packet off interface.  Off is nonzero if
58417565Skarels 			 * packet has trailing header; dmc_get will then
58517565Skarels 			 * force this header information to be at the front,
58617565Skarels 			 * but we still have to drop the type and length
58717565Skarels 			 * which are at the front of any trailer data.
58817565Skarels 			 */
58924796Skarels 			m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);
59017565Skarels 			if (m == 0)
59117565Skarels 				goto setup;
59217565Skarels 			if (off) {
59324796Skarels 				ifp = *(mtod(m, struct ifnet **));
59417565Skarels 				m->m_off += 2 * sizeof (u_short);
59517565Skarels 				m->m_len -= 2 * sizeof (u_short);
59624796Skarels 				*(mtod(m, struct ifnet **)) = ifp;
59717565Skarels 			}
59817565Skarels 			switch (dh->dmc_type) {
59917565Skarels 
6005725Sroot #ifdef INET
60117565Skarels 			case DMC_IPTYPE:
60217565Skarels 				schednetisr(NETISR_IP);
60317565Skarels 				inq = &ipintrq;
60417565Skarels 				break;
6055725Sroot #endif
60617565Skarels 			default:
60717565Skarels 				m_freem(m);
60817565Skarels 				goto setup;
60917565Skarels 			}
6105725Sroot 
611*27266Skarels 			s = splimp();
61217565Skarels 			if (IF_QFULL(inq)) {
61317565Skarels 				IF_DROP(inq);
61417565Skarels 				m_freem(m);
61517565Skarels 			} else
61617565Skarels 				IF_ENQUEUE(inq, m);
617*27266Skarels 			splx(s);
61817221Stef 
61917565Skarels 	setup:
62017565Skarels 			/* is this needed? */
62117565Skarels 			rp->ubinfo = ifrw->ifrw_info & 0x3ffff;
6225725Sroot 
62317565Skarels 			dmcload(sc, DMC_READ, rp->ubinfo,
62417565Skarels 			    ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc);
62517565Skarels 			break;
6265725Sroot 
62717565Skarels 		case DMC_OUX:
62817565Skarels 			/*
62917565Skarels 			 * A write has completed, start another
63017565Skarels 			 * transfer if there is more data to send.
63117565Skarels 			 */
63217565Skarels 			ifp->if_opackets++;
63317565Skarels 			/* find associated dmcbuf structure */
63424796Skarels 			ifxp = &sc->sc_ifw[0];
63517565Skarels 			for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
63617565Skarels 				if(rp->ubinfo == pkaddr)
63717565Skarels 					break;
63817565Skarels 				ifxp++;
63917565Skarels 			}
64017565Skarels 			if (rp >= &sc->sc_xbufs[NXMT]) {
64117565Skarels 				printf("dmc%d: bad packet address 0x%x\n",
64217565Skarels 				    unit, pkaddr);
64317565Skarels 				break;
64417565Skarels 			}
64517565Skarels 			if ((rp->flags & DBUF_DMCS) == 0)
64617565Skarels 				printf("dmc%d: unallocated packet 0x%x\n",
64717565Skarels 				    unit, pkaddr);
64817565Skarels 			/* mark buffer free */
64924796Skarels 			if (ifxp->ifw_xtofree) {
65024796Skarels 				(void)m_freem(ifxp->ifw_xtofree);
65124796Skarels 				ifxp->ifw_xtofree = 0;
65217565Skarels 			}
65317565Skarels 			rp->flags &= ~DBUF_DMCS;
65417565Skarels 			sc->sc_oused--;
65517565Skarels 			sc->sc_nticks = 0;
65617565Skarels 			sc->sc_flag |= DMC_ACTIVE;
65717565Skarels 			break;
65817221Stef 
65917565Skarels 		case DMC_CNTLO:
66017565Skarels 			arg &= DMC_CNTMASK;
66117565Skarels 			if (arg & DMC_FATAL) {
66226282Skarels 				log(LOG_ERR, "dmc%d: fatal error, flags=%b\n",
66317565Skarels 				    unit, arg, CNTLO_BITS);
66417565Skarels 				dmcrestart(unit);
66517565Skarels 				break;
66617565Skarels 			}
66717565Skarels 			/* ACCUMULATE STATISTICS */
66817221Stef 			switch(arg) {
66917221Stef 			case DMC_NOBUFS:
67017565Skarels 				ifp->if_ierrors++;
67117565Skarels 				if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0)
67217565Skarels 					goto report;
67317565Skarels 				break;
67417221Stef 			case DMC_DISCONN:
67517565Skarels 				if ((sc->sc_disc++ % DMC_RPDSC) == 0)
67617565Skarels 					goto report;
67717565Skarels 				break;
67817221Stef 			case DMC_TIMEOUT:
67917565Skarels 				if ((sc->sc_timeo++ % DMC_RPTMO) == 0)
68017565Skarels 					goto report;
68117565Skarels 				break;
68217221Stef 			case DMC_DATACK:
68317565Skarels 				ifp->if_oerrors++;
68417565Skarels 				if ((sc->sc_datck++ % DMC_RPDCK) == 0)
68517565Skarels 					goto report;
68617565Skarels 				break;
68717221Stef 			default:
68817221Stef 				goto report;
68917221Stef 			}
69017221Stef 			break;
69117221Stef 		report:
69217565Skarels 			printd("dmc%d: soft error, flags=%b\n", unit,
69317565Skarels 			    arg, CNTLO_BITS);
69417565Skarels 			if ((sc->sc_flag & DMC_RESTART) == 0) {
69517565Skarels 				/*
69617565Skarels 				 * kill off the dmc to get things
69717565Skarels 				 * going again by generating a
69817565Skarels 				 * procedure error
69917565Skarels 				 */
70017565Skarels 				sc->sc_flag |= DMC_RESTART;
70117565Skarels 				arg = sc->sc_ubinfo & 0x3ffff;
70217565Skarels 				dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM);
70317565Skarels 			}
70417565Skarels 			break;
70517565Skarels 
70617565Skarels 		default:
70717565Skarels 			printf("dmc%d: bad control %o\n", unit, cmd);
70817565Skarels 			break;
7095725Sroot 		}
7105725Sroot 	}
71117565Skarels 	dmcstart(unit);
71217221Stef 	return;
7135725Sroot }
7145725Sroot 
7155725Sroot /*
7165725Sroot  * DMC output routine.
71717565Skarels  * Encapsulate a packet of type family for the dmc.
71817565Skarels  * Use trailer local net encapsulation if enough data in first
71917565Skarels  * packet leaves a multiple of 512 bytes of data in remainder.
7205725Sroot  */
72117565Skarels dmcoutput(ifp, m0, dst)
7225725Sroot 	register struct ifnet *ifp;
72317565Skarels 	register struct mbuf *m0;
7246334Ssam 	struct sockaddr *dst;
7255725Sroot {
72617565Skarels 	int type, error, s;
72717565Skarels 	register struct mbuf *m = m0;
72817565Skarels 	register struct dmc_header *dh;
72917565Skarels 	register int off;
7305725Sroot 
73117565Skarels 	switch (dst->sa_family) {
73217565Skarels #ifdef	INET
73317565Skarels 	case AF_INET:
73417565Skarels 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
73517565Skarels 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
73617565Skarels 		if (off > 0 && (off & 0x1ff) == 0 &&
73717565Skarels 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
73817565Skarels 			type = DMC_TRAILER + (off>>9);
73917565Skarels 			m->m_off -= 2 * sizeof (u_short);
74017565Skarels 			m->m_len += 2 * sizeof (u_short);
74117565Skarels 			*mtod(m, u_short *) = htons((u_short)DMC_IPTYPE);
74217565Skarels 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
74317565Skarels 			goto gottrailertype;
74417565Skarels 		}
74517565Skarels 		type = DMC_IPTYPE;
74617565Skarels 		off = 0;
74717565Skarels 		goto gottype;
74817565Skarels #endif
74917565Skarels 
75017565Skarels 	case AF_UNSPEC:
75117565Skarels 		dh = (struct dmc_header *)dst->sa_data;
75217565Skarels 		type = dh->dmc_type;
75317565Skarels 		goto gottype;
75417565Skarels 
75517565Skarels 	default:
75617565Skarels 		printf("dmc%d: can't handle af%d\n", ifp->if_unit,
75717565Skarels 			dst->sa_family);
75817565Skarels 		error = EAFNOSUPPORT;
75917565Skarels 		goto bad;
7605725Sroot 	}
76117565Skarels 
76217565Skarels gottrailertype:
76317565Skarels 	/*
76417565Skarels 	 * Packet to be sent as a trailer; move first packet
76517565Skarels 	 * (control information) to end of chain.
76617565Skarels 	 */
76717565Skarels 	while (m->m_next)
76817565Skarels 		m = m->m_next;
76917565Skarels 	m->m_next = m0;
77017565Skarels 	m = m0->m_next;
77117565Skarels 	m0->m_next = 0;
77217565Skarels 	m0 = m;
77317565Skarels 
77417565Skarels gottype:
77517565Skarels 	/*
77617565Skarels 	 * Add local network header
77717565Skarels 	 * (there is space for a uba on a vax to step on)
77817565Skarels 	 */
77917565Skarels 	if (m->m_off > MMAXOFF ||
78017565Skarels 	    MMINOFF + sizeof(struct dmc_header) > m->m_off) {
78117565Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
78217565Skarels 		if (m == 0) {
78317565Skarels 			error = ENOBUFS;
78417565Skarels 			goto bad;
78517565Skarels 		}
78617565Skarels 		m->m_next = m0;
78717565Skarels 		m->m_off = MMINOFF;
78817565Skarels 		m->m_len = sizeof (struct dmc_header);
78917565Skarels 	} else {
79017565Skarels 		m->m_off -= sizeof (struct dmc_header);
79117565Skarels 		m->m_len += sizeof (struct dmc_header);
79217565Skarels 	}
79317565Skarels 	dh = mtod(m, struct dmc_header *);
79417565Skarels 	dh->dmc_type = htons((u_short)type);
79517565Skarels 
79617565Skarels 	/*
79717565Skarels 	 * Queue message on interface, and start output if interface
79817565Skarels 	 * not yet active.
79917565Skarels 	 */
80017565Skarels 	s = splimp();
8016207Swnj 	if (IF_QFULL(&ifp->if_snd)) {
8026207Swnj 		IF_DROP(&ifp->if_snd);
8036334Ssam 		m_freem(m);
8046207Swnj 		splx(s);
8056502Ssam 		return (ENOBUFS);
8066207Swnj 	}
8075725Sroot 	IF_ENQUEUE(&ifp->if_snd, m);
80817221Stef 	dmcstart(ifp->if_unit);
8095725Sroot 	splx(s);
8106502Ssam 	return (0);
81117565Skarels 
81217565Skarels bad:
81317565Skarels 	m_freem(m0);
81417565Skarels 	return (error);
8155725Sroot }
81613061Ssam 
81717565Skarels 
81813061Ssam /*
81913061Ssam  * Process an ioctl request.
82013061Ssam  */
82124796Skarels /* ARGSUSED */
82213061Ssam dmcioctl(ifp, cmd, data)
82313061Ssam 	register struct ifnet *ifp;
82413061Ssam 	int cmd;
82513061Ssam 	caddr_t data;
82613061Ssam {
82713061Ssam 	int s = splimp(), error = 0;
828*27266Skarels 	register struct dmc_softc *sc = &dmc_softc[ifp->if_unit];
82913061Ssam 
83013061Ssam 	switch (cmd) {
83113061Ssam 
83213061Ssam 	case SIOCSIFADDR:
83317221Stef 		ifp->if_flags |= IFF_UP;
83419862Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
83519862Skarels 			dmcinit(ifp->if_unit);
83613061Ssam 		break;
83713061Ssam 
83813061Ssam 	case SIOCSIFDSTADDR:
83919862Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
84019862Skarels 			dmcinit(ifp->if_unit);
84113061Ssam 		break;
84217221Stef 
843*27266Skarels 	case SIOCSIFFLAGS:
844*27266Skarels 		if ((ifp->if_flags & IFF_UP) == 0 &&
845*27266Skarels 		    sc->sc_flag & DMC_RUNNING) {
846*27266Skarels 			((struct dmcdevice *)
847*27266Skarels 			   (dmcinfo[ifp->if_unit]->ui_addr))->bsel1 = DMC_MCLR;
848*27266Skarels 			sc->sc_flag &= ~DMC_RUNNING;
849*27266Skarels 		} else if (ifp->if_flags & IFF_UP &&
850*27266Skarels 		    (sc->sc_flag & DMC_RUNNING) == 0)
851*27266Skarels 			dmcrestart(ifp->if_unit);
852*27266Skarels 		break;
853*27266Skarels 
85413061Ssam 	default:
85513061Ssam 		error = EINVAL;
85613061Ssam 	}
85713061Ssam 	splx(s);
85813061Ssam 	return (error);
85913061Ssam }
86017221Stef 
86117221Stef /*
86217565Skarels  * Restart after a fatal error.
86317565Skarels  * Clear device and reinitialize.
86417565Skarels  */
86517565Skarels dmcrestart(unit)
86617565Skarels 	int unit;
86717565Skarels {
86817565Skarels 	register struct dmc_softc *sc = &dmc_softc[unit];
86917565Skarels 	register struct uba_device *ui = dmcinfo[unit];
87017565Skarels 	register struct dmcdevice *addr;
87117565Skarels 	register struct ifxmt *ifxp;
87217565Skarels 	register int i;
87317565Skarels 
87417565Skarels 	addr = (struct dmcdevice *)ui->ui_addr;
87517565Skarels #ifdef DEBUG
87617565Skarels 	/* dump base table */
87717565Skarels 	printf("dmc%d base table:\n", unit);
87817565Skarels 	for (i = 0; i < sizeof (struct dmc_base); i++)
87917565Skarels 		printf("%o\n" ,dmc_base[unit].d_base[i]);
88013085Ssam #endif
88117565Skarels 	/*
88217565Skarels 	 * Let the DMR finish the MCLR.	 At 1 Mbit, it should do so
88317565Skarels 	 * in about a max of 6.4 milliseconds with diagnostics enabled.
88417565Skarels 	 */
88517565Skarels 	addr->bsel1 = DMC_MCLR;
88617565Skarels 	for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
88717565Skarels 		;
88817565Skarels 	/* Did the timer expire or did the DMR finish? */
88917565Skarels 	if ((addr->bsel1 & DMC_RUN) == 0) {
89026282Skarels 		log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit);
89117565Skarels 		return;
89217565Skarels 	}
89317565Skarels 
89424796Skarels 	for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
89524796Skarels 		if (ifxp->ifw_xtofree) {
89624796Skarels 			(void) m_freem(ifxp->ifw_xtofree);
89724796Skarels 			ifxp->ifw_xtofree = 0;
89817565Skarels 		}
89917565Skarels 	}
90017565Skarels 
90117565Skarels 	/* restart DMC */
90217565Skarels 	dmcinit(unit);
90317565Skarels 	sc->sc_flag &= ~DMC_RESTART;
90417565Skarels 	sc->sc_if.if_collisions++;	/* why not? */
90517565Skarels }
90617565Skarels 
90717565Skarels /*
90817565Skarels  * Check to see that transmitted packets don't
90917565Skarels  * lose interrupts.  The device has to be active.
91017565Skarels  */
91117565Skarels dmcwatch()
91217565Skarels {
91317565Skarels 	register struct uba_device *ui;
91417565Skarels 	register struct dmc_softc *sc;
91517565Skarels 	struct dmcdevice *addr;
91617565Skarels 	register int i;
91717565Skarels 
91817565Skarels 	for (i = 0; i < NDMC; i++) {
91917565Skarels 		sc = &dmc_softc[i];
92017565Skarels 		if ((sc->sc_flag & DMC_ACTIVE) == 0)
92117565Skarels 			continue;
92217565Skarels 		if ((ui = dmcinfo[i]) == 0 || ui->ui_alive == 0)
92317565Skarels 			continue;
92417565Skarels 		if (sc->sc_oused) {
92517565Skarels 			sc->sc_nticks++;
92617565Skarels 			if (sc->sc_nticks > dmc_timeout) {
92717565Skarels 				sc->sc_nticks = 0;
92817565Skarels 				addr = (struct dmcdevice *)ui->ui_addr;
92926282Skarels 				log(LOG_ERR, "dmc%d hung: bsel0=%b bsel2=%b\n",
93026282Skarels 				    i, addr->bsel0 & 0xff, DMC0BITS,
93117565Skarels 				    addr->bsel2 & 0xff, DMC2BITS);
93217565Skarels 				dmcrestart(i);
93317565Skarels 			}
93417565Skarels 		}
93517565Skarels 	}
93617565Skarels 	timeout(dmcwatch, (caddr_t) 0, hz);
93717565Skarels }
93817565Skarels #endif
939