xref: /csrg-svn/sys/vax/if/if_dmc.c (revision 5768)
1*5768Sroot /*	if_dmc.c	4.2	82/02/12	*/
25725Sroot 
35725Sroot #include "dmc.h"
45725Sroot #if NDMC > 0
55725Sroot #define printd if(dmcdebug)printf
65725Sroot int dmcdebug = 1;
75725Sroot /*
85725Sroot  * DMC11 device driver, internet version
95725Sroot  *
105725Sroot  * TODO
115725Sroot  *	allow more than one outstanding read or write.
125725Sroot  */
135725Sroot 
145725Sroot #include "../h/param.h"
155725Sroot #include "../h/systm.h"
165725Sroot #include "../h/mbuf.h"
175725Sroot #include "../h/pte.h"
185725Sroot #include "../h/buf.h"
195725Sroot #include "../h/tty.h"
205725Sroot #include "../h/protosw.h"
215725Sroot #include "../h/socket.h"
225725Sroot #include "../h/ubareg.h"
235725Sroot #include "../h/ubavar.h"
245725Sroot #include "../h/cpu.h"
255725Sroot #include "../h/mtpr.h"
265725Sroot #include "../h/vmmac.h"
275725Sroot #include "../net/in.h"
285725Sroot #include "../net/in_systm.h"
295725Sroot #include "../net/if.h"
305725Sroot #include "../net/if_uba.h"
315725Sroot #include "../net/ip.h"
325725Sroot #include "../net/ip_var.h"
335725Sroot 
345725Sroot /*
355725Sroot  * Driver information for auto-configuration stuff.
365725Sroot  */
375725Sroot int	dmcprobe(), dmcattach(), dmcinit(), dmcoutput(), dmcreset();
385725Sroot struct	uba_device *dmcinfo[NDMC];
395725Sroot u_short	dmcstd[] = { 0 };
405725Sroot struct	uba_driver dmcdriver =
415725Sroot 	{ dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
425725Sroot 
435725Sroot struct dmcdevice {
445725Sroot 	union {
455725Sroot 		char	b[8];
465725Sroot 		short	w[4];
475725Sroot 	} un;
485725Sroot };
495725Sroot 
505725Sroot #define	bsel0	un.b[0]
515725Sroot #define	bsel1	un.b[1]
525725Sroot #define	bsel2	un.b[2]
535725Sroot #define	bsel3	un.b[3]
545725Sroot #define	bsel4	un.b[4]
555725Sroot #define	bsel5	un.b[5]
565725Sroot #define	bsel6	un.b[6]
575725Sroot #define	bsel7	un.b[7]
585725Sroot #define	sel0	un.w[0]
595725Sroot #define	sel2	un.w[1]
605725Sroot #define	sel4	un.w[2]
615725Sroot #define	sel6	un.w[3]
625725Sroot 
635725Sroot #define	DMCMTU	(2048)
645725Sroot 
655725Sroot #define RDYSCAN	16	/* loop delay for RDYI after RQI */
665725Sroot 
675725Sroot /* defines for bsel0 */
685725Sroot #define	DMC_BACCI	0
695725Sroot #define	DMC_CNTLI	1
705725Sroot #define	DMC_PERR	2
715725Sroot #define	DMC_BASEI	3
725725Sroot #define	DMC_WRITE	0		/* transmit block */
735725Sroot #define	DMC_READ	4		/* read block */
745725Sroot #define	DMC_RQI		0040		/* port request bit */
755725Sroot #define	DMC_IEI		0100		/* enable input interrupts */
765725Sroot #define	DMC_RDYI	0200		/* port ready */
775725Sroot 
785725Sroot /* defines for bsel1 */
795725Sroot #define	DMC_MCLR	0100		/* DMC11 Master Clear */
805725Sroot #define	DMC_RUN		0200		/* clock running */
815725Sroot 
825725Sroot /* defines for bsel2 */
835725Sroot #define	DMC_BACCO	0
845725Sroot #define	DMC_CNTLO	1
855725Sroot #define	DMC_OUX		0		/* transmit block */
865725Sroot #define	DMC_OUR		4		/* read block */
875725Sroot #define	DMC_IEO		0100		/* enable output interrupts */
885725Sroot #define	DMC_RDYO	0200		/* port available */
895725Sroot 
905725Sroot /* defines for CNTLI mode */
915725Sroot #define	DMC_HDPLX	02000		/* half duplex DDCMP operation */
925725Sroot #define	DMC_SEC		04000		/* half duplex secondary station */
935725Sroot #define	DMC_MAINT	00400		/* enter maintenance mode */
945725Sroot 
955725Sroot /* defines for BACCI/O and BASEI mode */
965725Sroot #define	DMC_XMEM	0140000		/* xmem bit position */
975725Sroot #define	DMC_CCOUNT	0037777		/* character count mask */
985725Sroot #define	DMC_RESUME	0002000		/* resume (BASEI only) */
995725Sroot 
1005725Sroot /* defines for CNTLO */
1015725Sroot #define	DMC_CNTMASK	01777
1025725Sroot #define DMC_FATAL	01620
1035725Sroot 
1045725Sroot #define	DMC_PF	0xff		/* 8 bits of protocol type in ui_flags */
1055725Sroot #define	DMC_NET	0xff00		/* 8 bits of net number in ui_flags */
1065725Sroot 
1075725Sroot /*
1085725Sroot  * DMC software status per interface.
1095725Sroot  *
1105725Sroot  * Each interface is referenced by a network interface structure,
1115725Sroot  * sc_if, which the routing code uses to locate the interface.
1125725Sroot  * This structure contains the output queue for the interface, its address, ...
1135725Sroot  * We also have, for each interface, a UBA interface structure, which
1145725Sroot  * contains information about the UNIBUS resources held by the interface:
1155725Sroot  * map registers, buffered data paths, etc.  Information is cached in this
1165725Sroot  * structure for use by the if_uba.c routines in running the interface
1175725Sroot  * efficiently.
1185725Sroot  */
1195725Sroot struct dmc_softc {
1205725Sroot 	struct	ifnet sc_if;		/* network-visible interface */
1215725Sroot 	struct	ifuba sc_ifuba;		/* UNIBUS resources */
1225725Sroot 	short	sc_flag;		/* flags */
1235725Sroot 	short	sc_oactive;		/* output active */
1245725Sroot 	int	sc_ubinfo;		/* UBA mapping info for base table */
1255725Sroot 	struct clist sc_que;		/* command queue */
1265725Sroot } dmc_softc[NDMC];
1275725Sroot 
1285725Sroot /* flags */
1295725Sroot #define	DMCRUN		01
1305725Sroot #define	DMCBMAPPED	02		/* base table mapped */
1315725Sroot 
1325725Sroot struct dmc_base {
1335725Sroot 	short	d_base[128];		/* DMC base table */
1345725Sroot } dmc_base[NDMC];
1355725Sroot 
1365725Sroot #define	loword(x)	((short *)&x)[0]
1375725Sroot #define	hiword(x)	((short *)&x)[1]
1385725Sroot 
1395725Sroot dmcprobe(reg)
1405725Sroot 	caddr_t reg;
1415725Sroot {
1425725Sroot 	register int br, cvec;
1435725Sroot 	register struct dmcdevice *addr = (struct dmcdevice *)reg;
1445725Sroot 	register int i;
1455725Sroot 
1465725Sroot #ifdef lint
1475725Sroot 	br = 0; cvec = br; br = cvec;
1485725Sroot 	dmcrint(0); dmcxint(0);
1495725Sroot #endif
1505725Sroot 	addr->bsel1 = DMC_MCLR;
1515725Sroot 	for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
1525725Sroot 		;
1535725Sroot 	if ((addr->bsel1 & DMC_RUN) == 0)
1545725Sroot 		return(0);
1555725Sroot 	addr->bsel1 &= ~DMC_MCLR;
1565725Sroot 	addr->bsel0 = DMC_RQI|DMC_IEI;
1575725Sroot 	DELAY(100000);
1585725Sroot 	addr->bsel1 = DMC_MCLR;
1595725Sroot 	for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
1605725Sroot 		;
1615725Sroot 	return(1);
1625725Sroot }
1635725Sroot 
1645725Sroot /*
1655725Sroot  * Interface exists: make available by filling in network interface
1665725Sroot  * record.  System will initialize the interface when it is ready
1675725Sroot  * to accept packets.
1685725Sroot  */
1695725Sroot dmcattach(ui)
1705725Sroot 	register struct uba_device *ui;
1715725Sroot {
1725725Sroot 	register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
1735725Sroot 
1745725Sroot 	sc->sc_if.if_unit = ui->ui_unit;
1755725Sroot 	sc->sc_if.if_name = "dmc";
1765725Sroot 	sc->sc_if.if_mtu = DMCMTU;
1775725Sroot 	sc->sc_if.if_net = (ui->ui_flags & DMC_NET) >> 8;
1785725Sroot 	sc->sc_if.if_host[0] = 17;	/* random number */
1795725Sroot 	sc->sc_if.if_addr =
1805725Sroot 	    if_makeaddr(sc->sc_if.if_net, sc->sc_if.if_host[0]);
1815725Sroot 	sc->sc_if.if_init = dmcinit;
1825725Sroot 	sc->sc_if.if_output = dmcoutput;
1835725Sroot 	sc->sc_if.if_ubareset = dmcreset;
1845725Sroot 	if_attach(&sc->sc_if);
1855725Sroot }
1865725Sroot 
1875725Sroot /*
1885725Sroot  * Reset of interface after UNIBUS reset.
1895725Sroot  * If interface is on specified UBA, reset it's state.
1905725Sroot  */
1915725Sroot dmcreset(unit, uban)
1925725Sroot 	int unit, uban;
1935725Sroot {
1945725Sroot 	register struct uba_device *ui;
1955725Sroot 
1965725Sroot 	if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
1975725Sroot 	    ui->ui_ubanum != uban)
1985725Sroot 		return;
1995725Sroot 	printf(" dmc%d", unit);
2005725Sroot 	dmcinit(unit);
2015725Sroot }
2025725Sroot 
2035725Sroot /*
2045725Sroot  * Initialization of interface; reinitialize UNIBUS usage.
2055725Sroot  */
2065725Sroot dmcinit(unit)
2075725Sroot 	int unit;
2085725Sroot {
2095725Sroot 	register struct dmc_softc *sc = &dmc_softc[unit];
2105725Sroot 	register struct uba_device *ui = dmcinfo[unit];
2115725Sroot 	register struct dmcdevice *addr;
2125725Sroot 	int base;
2135725Sroot 
2145725Sroot 	printd("dmcinit\n");
2155725Sroot 	if ((sc->sc_flag&DMCBMAPPED) == 0) {
2165725Sroot 		sc->sc_ubinfo = uballoc(ui->ui_ubanum,
2175725Sroot 		    (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0);
2185725Sroot 		sc->sc_flag |= DMCBMAPPED;
2195725Sroot 	}
2205725Sroot 	if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0,
221*5768Sroot 	    (int)btoc(DMCMTU)) == 0) {
2225725Sroot 		printf("dmc%d: can't initialize\n", unit);
2235725Sroot 		return;
2245725Sroot 	}
2255725Sroot 	addr = (struct dmcdevice *)ui->ui_addr;
2265725Sroot 	addr->bsel2 |= DMC_IEO;
2275725Sroot 	base = sc->sc_ubinfo & 0x3ffff;
2285725Sroot 	printd("  base 0x%x\n", base);
2295725Sroot 	dmcload(sc, DMC_BASEI, base, (base>>2)&DMC_XMEM);
2305725Sroot 	dmcload(sc, DMC_CNTLI, 0, 0);
2315725Sroot 	base = sc->sc_ifuba.ifu_r.ifrw_info & 0x3ffff;
2325725Sroot 	dmcload(sc, DMC_READ, base, ((base>>2)&DMC_XMEM)|DMCMTU);
2335725Sroot 	printd("  first read queued, addr 0x%x\n", base);
2345725Sroot }
2355725Sroot 
2365725Sroot /*
2375725Sroot  * Start output on interface.  Get another datagram
2385725Sroot  * to send from the interface queue and map it to
2395725Sroot  * the interface before starting output.
2405725Sroot  */
2415725Sroot dmcstart(dev)
2425725Sroot 	dev_t dev;
2435725Sroot {
2445725Sroot 	int unit = minor(dev);
2455725Sroot 	struct uba_device *ui = dmcinfo[unit];
2465725Sroot 	register struct dmc_softc *sc = &dmc_softc[unit];
2475725Sroot 	int addr, len;
2485725Sroot 	struct mbuf *m;
2495725Sroot 
2505725Sroot 	printd("dmcstart\n");
2515725Sroot 	/*
2525725Sroot 	 * Dequeue a request and map it to the UNIBUS.
2535725Sroot 	 * If no more requests, just return.
2545725Sroot 	 */
2555725Sroot 	IF_DEQUEUE(&sc->sc_if.if_snd, m);
2565725Sroot 	if (m == 0)
2575725Sroot 		return;
2585725Sroot 	len = if_wubaput(&sc->sc_ifuba, m);
2595725Sroot 
2605725Sroot 	/*
2615725Sroot 	 * Have request mapped to UNIBUS for transmission.
2625725Sroot 	 * Purge any stale data from this BDP and start the output.
2635725Sroot 	 */
2645725Sroot 	UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp);
2655725Sroot 	addr = sc->sc_ifuba.ifu_w.ifrw_info & 0x3ffff;
2665725Sroot 	printd("  len %d, addr 0x%x, ", len, addr);
2675725Sroot 	printd("mr 0x%x\n", sc->sc_ifuba.ifu_w.ifrw_mr[0]);
2685725Sroot 	dmcload(sc, DMC_WRITE, addr, (len&DMC_CCOUNT)|((addr>>2)&DMC_XMEM));
2695725Sroot 	sc->sc_oactive = 1;
2705725Sroot }
2715725Sroot 
2725725Sroot /*
2735725Sroot  * Utility routine to load the DMC device registers.
2745725Sroot  */
2755725Sroot dmcload(sc, type, w0, w1)
2765725Sroot 	register struct dmc_softc *sc;
2775725Sroot 	int type, w0, w1;
2785725Sroot {
2795725Sroot 	register struct dmcdevice *addr;
2805725Sroot 	register int unit, sps, n;
2815725Sroot 
2825725Sroot 	printd("dmcload: 0x%x 0x%x 0x%x\n", type, w0, w1);
2835725Sroot 	unit = sc - dmc_softc;
2845725Sroot 	addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
2855725Sroot 	sps = spl5();
2865725Sroot 	if ((n = sc->sc_que.c_cc) == 0)
2875725Sroot 		addr->bsel0 = type | DMC_RQI;
2885725Sroot 	else
2895725Sroot 		putc(type | DMC_RQI, &sc->sc_que);
2905725Sroot 	putw(w0, &sc->sc_que);
2915725Sroot 	putw(w1, &sc->sc_que);
2925725Sroot 	if (n == 0)
2935725Sroot 		dmcrint(unit);
2945725Sroot 	splx(sps);
2955725Sroot }
2965725Sroot 
2975725Sroot /*
2985725Sroot  * DMC interface receiver interrupt.
2995725Sroot  * Ready to accept another command,
3005725Sroot  * pull one off the command queue.
3015725Sroot  */
3025725Sroot dmcrint(unit)
3035725Sroot 	int unit;
3045725Sroot {
3055725Sroot 	register struct dmc_softc *sc;
3065725Sroot 	register struct dmcdevice *addr;
3075725Sroot 	register int n;
3085725Sroot 	int w0, w1; /* DEBUG */
3095725Sroot 
3105725Sroot 	addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
3115725Sroot 	sc = &dmc_softc[unit];
3125725Sroot 	while (addr->bsel0&DMC_RDYI) {
3135725Sroot 		w0 = getw(&sc->sc_que); /* DEBUG */
3145725Sroot 		addr->sel4 = w0; /* DEBUG */
3155725Sroot 		w1 = getw(&sc->sc_que); /* DEBUG */
3165725Sroot 		addr->sel6 = w1; /* DEBUG */
3175725Sroot 		/* DEBUG
3185725Sroot 		addr->sel4 = getw(&sc->sc_que);
3195725Sroot 		addr->sel6 = getw(&sc->sc_que);
3205725Sroot 		DEBUG */
3215725Sroot 		addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
3225725Sroot 		printd("  w0 0x%x, w1 0x%x\n", w0, w1);
3235725Sroot 		while (addr->bsel0&DMC_RDYI)
3245725Sroot 			;
3255725Sroot 		if (sc->sc_que.c_cc == 0)
3265725Sroot 			return;
3275725Sroot 		addr->bsel0 = getc(&sc->sc_que);
3285725Sroot 		n = RDYSCAN;
3295725Sroot 		while (n-- && (addr->bsel0&DMC_RDYI) == 0)
3305725Sroot 			;
3315725Sroot 	}
3325725Sroot 	if (sc->sc_que.c_cc)
3335725Sroot 		addr->bsel0 |= DMC_IEI;
3345725Sroot }
3355725Sroot 
3365725Sroot /*
3375725Sroot  * DMC interface transmitter interrupt.
3385725Sroot  * A transfer has completed, check for errors.
3395725Sroot  * If it was a read, notify appropriate protocol.
3405725Sroot  * If it was a write, pull the next one off the queue.
3415725Sroot  */
3425725Sroot dmcxint(unit)
3435725Sroot 	int unit;
3445725Sroot {
3455725Sroot 	register struct dmc_softc *sc;
3465725Sroot 	struct uba_device *ui = dmcinfo[unit];
3475725Sroot 	struct dmcdevice *addr;
3485725Sroot 	struct mbuf *m;
3495725Sroot 	register struct ifqueue *inq;
3505725Sroot 	int arg, cmd, len;
3515725Sroot 
3525725Sroot 	addr = (struct dmcdevice *)ui->ui_addr;
3535725Sroot 	arg = addr->sel6;
3545725Sroot 	cmd = addr->bsel2&7;
3555725Sroot 	addr->bsel2 &= ~DMC_RDYO;
3565725Sroot 	sc = &dmc_softc[unit];
3575725Sroot 	printd("dmcxint\n");
3585725Sroot 	switch (cmd) {
3595725Sroot 
3605725Sroot 	case DMC_OUR:
3615725Sroot 		/*
3625725Sroot 		 * A read has completed.  Purge input buffered
3635725Sroot 		 * data path.  Pass packet to type specific
3645725Sroot 		 * higher-level input routine.
3655725Sroot 		 */
3665725Sroot 		sc->sc_if.if_ipackets++;
3675725Sroot 		UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_r.ifrw_bdp);
3685725Sroot 		len = arg & DMC_CCOUNT;
3695725Sroot 		printd("  read done, len %d\n", len);
3705725Sroot 		switch (ui->ui_flags & DMC_PF) {
3715725Sroot #ifdef INET
3725725Sroot 		case PF_INET:
3735725Sroot 			setipintr();
3745725Sroot 			inq = &ipintrq;
3755725Sroot 			break;
3765725Sroot #endif
3775725Sroot 
3785725Sroot 		default:
3795725Sroot 			printf("dmc%d: unknown packet type %d\n", unit,
3805725Sroot 			    ui->ui_flags & DMC_NET);
3815725Sroot 			goto setup;
3825725Sroot 		}
3835725Sroot 		m = if_rubaget(&sc->sc_ifuba, len, 0);
3845725Sroot 		if (m == 0)
3855725Sroot 			goto setup;
3865725Sroot 		IF_ENQUEUE(inq, m);
3875725Sroot 
3885725Sroot setup:
3895725Sroot 		arg = sc->sc_ifuba.ifu_r.ifrw_info & 0x3ffff;
3905725Sroot 		dmcload(sc, DMC_READ, arg, ((arg >> 2) & DMC_XMEM) | DMCMTU);
3915725Sroot 		return;
3925725Sroot 
3935725Sroot 	case DMC_OUX:
3945725Sroot 		/*
3955725Sroot 		 * A write has completed, start another
3965725Sroot 		 * transfer if there is more data to send.
3975725Sroot 		 */
3985725Sroot 		if (sc->sc_oactive == 0)
3995725Sroot 			return;		/* SHOULD IT BE A FATAL ERROR? */
4005725Sroot 		printd("  write done\n");
4015725Sroot 		sc->sc_if.if_opackets++;
4025725Sroot 		sc->sc_oactive = 0;
4035725Sroot 		if (sc->sc_ifuba.ifu_xtofree) {
4045725Sroot 			m_freem(sc->sc_ifuba.ifu_xtofree);
4055725Sroot 			sc->sc_ifuba.ifu_xtofree = 0;
4065725Sroot 		}
4075725Sroot 		if (sc->sc_if.if_snd.ifq_head == 0)
4085725Sroot 			return;
4095725Sroot 		dmcstart(unit);
4105725Sroot 		return;
4115725Sroot 
4125725Sroot 	case DMC_CNTLO:
4135725Sroot 		arg &= DMC_CNTMASK;
4145725Sroot 		if (arg&DMC_FATAL) {
4155725Sroot 			addr->bsel1 = DMC_MCLR;
4165725Sroot 			sc->sc_flag &= ~DMCRUN;
4175725Sroot 			/*** DO SOMETHING TO RESTART DEVICE ***/
4185725Sroot 			printf("DMC FATAL ERROR 0%o\n", arg);
4195725Sroot 		} else {
4205725Sroot 			/* ACCUMULATE STATISTICS */
4215725Sroot 			printf("DMC SOFT ERROR 0%o\n", arg);
4225725Sroot 		}
4235725Sroot 		return;
4245725Sroot 
4255725Sroot 	default:
4265725Sroot 		printf("dmc%d: bad control %o\n", unit, cmd);
4275725Sroot 	}
4285725Sroot }
4295725Sroot 
4305725Sroot /*
4315725Sroot  * DMC output routine.
4325725Sroot  * Just send the data, header was supplied by
4335725Sroot  * upper level protocol routines.
4345725Sroot  */
4355725Sroot dmcoutput(ifp, m, pf)
4365725Sroot 	register struct ifnet *ifp;
4375725Sroot 	register struct mbuf *m;
4385725Sroot 	int pf;
4395725Sroot {
4405725Sroot 	struct uba_device *ui = dmcinfo[ifp->if_unit];
4415725Sroot 	int s;
4425725Sroot 
4435725Sroot 	printd("dmcoutput\n");
4445725Sroot 	if (pf != (ui->ui_flags & DMC_PF)) {
4455725Sroot 		printf("dmc%d: protocol %d not supported\n", ifp->if_unit, pf);
4465725Sroot 		m_freem(m);
4475725Sroot 		return (0);
4485725Sroot 	}
4495725Sroot 	s = splimp();
4505725Sroot 	IF_ENQUEUE(&ifp->if_snd, m);
4515725Sroot 	if (dmc_softc[ifp->if_unit].sc_oactive == 0)
4525725Sroot 		dmcstart(ifp->if_unit);
4535725Sroot 	splx(s);
4545725Sroot 	return (1);
4555725Sroot }
456