xref: /csrg-svn/sys/vax/if/if_acc.c (revision 45801)
123281Smckusick /*
234868Sbostic  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
333462Skarels  * All rights reserved.
423281Smckusick  *
544555Sbostic  * %sccs.include.redist.c%
633462Skarels  *
7*45801Sbostic  *	@(#)if_acc.c	7.8 (Berkeley) 12/16/90
823281Smckusick  */
95638Ssam 
105638Ssam #include "acc.h"
1123700Skarels #if NACC > 0
125638Ssam 
135638Ssam /*
145638Ssam  * ACC LH/DH ARPAnet IMP interface driver.
155638Ssam  */
1637508Smckusick #include "machine/pte.h"
175638Ssam 
18*45801Sbostic #include "sys/param.h"
19*45801Sbostic #include "sys/systm.h"
20*45801Sbostic #include "sys/mbuf.h"
21*45801Sbostic #include "sys/buf.h"
22*45801Sbostic #include "sys/protosw.h"
23*45801Sbostic #include "sys/socket.h"
24*45801Sbostic #include "sys/vmmac.h"
258458Sroot 
26*45801Sbostic #include "net/if.h"
27*45801Sbostic #include "netimp/if_imp.h"
288458Sroot 
29*45801Sbostic #include "../include/cpu.h"
30*45801Sbostic #include "../include/mtpr.h"
3117109Sbloom #include "if_accreg.h"
3217109Sbloom #include "if_uba.h"
33*45801Sbostic #include "../uba/ubareg.h"
34*45801Sbostic #include "../uba/ubavar.h"
355638Ssam 
365638Ssam int     accprobe(), accattach(), accrint(), accxint();
375638Ssam struct  uba_device *accinfo[NACC];
385638Ssam u_short accstd[] = { 0 };
395638Ssam struct  uba_driver accdriver =
405638Ssam 	{ accprobe, 0, accattach, 0, accstd, "acc", accinfo };
415638Ssam 
4233452Skarels int	accinit(), accoutput(), accdown(), accreset();
435638Ssam 
445638Ssam /*
455638Ssam  * "Lower half" of IMP interface driver.
465638Ssam  *
475638Ssam  * Each IMP interface is handled by a common module which handles
485638Ssam  * the IMP-host protocol and a hardware driver which manages the
495638Ssam  * hardware specific details of talking with the IMP.
505638Ssam  *
515638Ssam  * The hardware portion of the IMP driver handles DMA and related
525638Ssam  * management of UNIBUS resources.  The IMP protocol module interprets
535638Ssam  * contents of these messages and "controls" the actions of the
545638Ssam  * hardware module during IMP resets, but not, for instance, during
555638Ssam  * UNIBUS resets.
565638Ssam  *
575638Ssam  * The two modules are coupled at "attach time", and ever after,
585638Ssam  * through the imp interface structure.  Higher level protocols,
595638Ssam  * e.g. IP, interact with the IMP driver, rather than the ACC.
605638Ssam  */
615638Ssam struct	acc_softc {
6233452Skarels 	struct	imp_softc *acc_imp;	/* data structure shared with IMP */
635638Ssam 	struct	ifuba acc_ifuba;	/* UNIBUS resources */
645638Ssam 	struct	mbuf *acc_iq;		/* input reassembly queue */
655638Ssam 	short	acc_olen;		/* size of last message sent */
665638Ssam 	char	acc_flush;		/* flush remainder of message */
675638Ssam } acc_softc[NACC];
685638Ssam 
695638Ssam /*
705638Ssam  * Reset the IMP and cause a transmitter interrupt by
715638Ssam  * performing a null DMA.
725638Ssam  */
accprobe(reg)735638Ssam accprobe(reg)
745638Ssam 	caddr_t reg;
755638Ssam {
765638Ssam 	register int br, cvec;		/* r11, r10 value-result */
775638Ssam 	register struct accdevice *addr = (struct accdevice *)reg;
785638Ssam 
795638Ssam #ifdef lint
805638Ssam 	br = 0; cvec = br; br = cvec;
815638Ssam 	accrint(0); accxint(0);
825638Ssam #endif
835771Swnj 	addr->icsr = ACC_RESET; DELAY(5000);
845771Swnj 	addr->ocsr = ACC_RESET; DELAY(5000);
855771Swnj 	addr->ocsr = OUT_BBACK; DELAY(5000);
865771Swnj 	addr->owc = 0;
875771Swnj 	addr->ocsr = ACC_IE | ACC_GO; DELAY(5000);
887176Sroot 	addr->ocsr = 0;
895771Swnj 	if (cvec && cvec != 0x200)	/* transmit -> receive */
905638Ssam 		cvec -= 4;
915638Ssam 	return (1);
925638Ssam }
935638Ssam 
945638Ssam /*
955638Ssam  * Call the IMP module to allow it to set up its internal
965638Ssam  * state, then tie the two modules together by setting up
975638Ssam  * the back pointers to common data structures.
985638Ssam  */
accattach(ui)995638Ssam accattach(ui)
10034273Skarels 	register struct uba_device *ui;
1015638Ssam {
1025638Ssam 	register struct acc_softc *sc = &acc_softc[ui->ui_unit];
1035638Ssam 	register struct impcb *ip;
1045638Ssam 
10534273Skarels 	if ((sc->acc_imp = impattach(ui->ui_driver->ud_dname, ui->ui_unit,
10634273Skarels 	    accreset)) == 0)
10724799Skarels 		return;
10833452Skarels 	ip = &sc->acc_imp->imp_cb;
1095638Ssam 	ip->ic_init = accinit;
11033452Skarels 	ip->ic_output = accoutput;
11133452Skarels 	ip->ic_down = accdown;
1128837Sroot 	sc->acc_ifuba.ifu_flags = UBA_CANTWAIT;
1135771Swnj #ifdef notdef
1147169Ssam 	sc->acc_ifuba.ifu_flags |= UBA_NEEDBDP;
1155771Swnj #endif
1165638Ssam }
1175638Ssam 
1185638Ssam /*
1195638Ssam  * Reset interface after UNIBUS reset.
1205638Ssam  * If interface is on specified uba, reset its state.
1215638Ssam  */
accreset(unit,uban)1225638Ssam accreset(unit, uban)
1235638Ssam 	int unit, uban;
1245638Ssam {
1255638Ssam 	register struct uba_device *ui;
1265638Ssam 	struct acc_softc *sc;
1275638Ssam 
1285638Ssam 	if (unit >= NACC || (ui = accinfo[unit]) == 0 || ui->ui_alive == 0 ||
1295638Ssam 	    ui->ui_ubanum != uban)
1305638Ssam 		return;
1315638Ssam 	printf(" acc%d", unit);
1325638Ssam 	sc = &acc_softc[unit];
13333452Skarels 	sc->acc_imp->imp_if.if_flags &= ~IFF_RUNNING;
13434273Skarels 	accoflush(unit);
1355638Ssam 	/* must go through IMP to allow it to set state */
13633452Skarels 	(*sc->acc_imp->imp_if.if_init)(sc->acc_imp->imp_if.if_unit);
1375638Ssam }
1385638Ssam 
1395638Ssam /*
1405638Ssam  * Initialize interface: clear recorded pending operations,
1415771Swnj  * and retrieve, and initialize UNIBUS resources.  Note
1425771Swnj  * return value is used by IMP init routine to mark IMP
1435771Swnj  * unavailable for outgoing traffic.
1445638Ssam  */
accinit(unit)1455638Ssam accinit(unit)
1465638Ssam 	int unit;
1475638Ssam {
1485771Swnj 	register struct acc_softc *sc;
1495771Swnj 	register struct uba_device *ui;
1505638Ssam 	register struct accdevice *addr;
1518615Sroot 	int info;
1525638Ssam 
1535771Swnj 	if (unit >= NACC || (ui = accinfo[unit]) == 0 || ui->ui_alive == 0) {
1545771Swnj 		printf("acc%d: not alive\n", unit);
1555771Swnj 		return (0);
1565771Swnj 	}
1575771Swnj 	sc = &acc_softc[unit];
1585771Swnj 	/*
1595771Swnj 	 * Header length is 0 since we have to passs
1605771Swnj 	 * the IMP leader up to the protocol interpretation
1615771Swnj 	 * routines.  If we had the header length as
1625771Swnj 	 * sizeof(struct imp_leader), then the if_ routines
1635771Swnj 	 * would asssume we handle it on input and output.
1645771Swnj 	 */
16533452Skarels 	if ((sc->acc_imp->imp_if.if_flags & IFF_RUNNING) == 0 &&
16633452Skarels 	    if_ubainit(&sc->acc_ifuba, ui->ui_ubanum, 0,
16733452Skarels 	     (int)btoc(IMP_RCVBUF)) == 0) {
1685638Ssam 		printf("acc%d: can't initialize\n", unit);
16933452Skarels 		sc->acc_imp->imp_if.if_flags &= ~(IFF_UP | IFF_RUNNING);
1707169Ssam 		return (0);
1715638Ssam 	}
17233452Skarels 	sc->acc_imp->imp_if.if_flags |= IFF_RUNNING;
1735638Ssam 	addr = (struct accdevice *)ui->ui_addr;
1745638Ssam 
1755647Ssam 	/*
1765771Swnj 	 * Reset the imp interface;
1775771Swnj 	 * the delays are pure guesswork.
1785647Ssam 	 */
1795771Swnj         addr->ocsr = ACC_RESET; DELAY(5000);
1806258Sroot 	addr->ocsr = OUT_BBACK;	DELAY(5000);	/* reset host master ready */
1815771Swnj 	addr->ocsr = 0;
1827169Ssam 	if (accinputreset(addr, unit) == 0) {
1837169Ssam 		ui->ui_alive = 0;
1847169Ssam 		return (0);
1855638Ssam 	}
1865638Ssam 
1875638Ssam 	/*
1885638Ssam 	 * Put up a read.  We can't restart any outstanding writes
1895638Ssam 	 * until we're back in synch with the IMP (i.e. we've flushed
1905638Ssam 	 * the NOOPs it throws at us).
19133452Skarels 	 * Note: IMP_RCVBUF includes the leader.
1925638Ssam 	 */
1935638Ssam 	info = sc->acc_ifuba.ifu_r.ifrw_info;
1945771Swnj 	addr->iba = (u_short)info;
19533452Skarels 	addr->iwc = -((IMP_RCVBUF) >> 1);
1965771Swnj #ifdef LOOPBACK
1975771Swnj 	addr->ocsr |= OUT_BBACK;
1985771Swnj #endif
1995771Swnj 	addr->icsr =
2005638Ssam 		IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO;
2015771Swnj 	return (1);
2025638Ssam }
2035638Ssam 
accinputreset(addr,unit)2047169Ssam accinputreset(addr, unit)
2057169Ssam 	register struct accdevice *addr;
2067169Ssam 	register int unit;
2077169Ssam {
2087169Ssam 	register int i;
2097169Ssam 
2107169Ssam 	addr->icsr = ACC_RESET; DELAY(5000);
2117169Ssam 	addr->icsr = IN_MRDY | IN_WEN;		/* close the relay */
2127169Ssam 	DELAY(10000);
2137169Ssam 	/* YECH!!! */
2147169Ssam 	for (i = 0; i < 500; i++) {
2157169Ssam 		if ((addr->icsr & IN_HRDY) ||
2167169Ssam 		    (addr->icsr & (IN_RMR | IN_IMPBSY)) == 0)
2177169Ssam 			return (1);
2187169Ssam 		addr->icsr = IN_MRDY | IN_WEN; DELAY(10000);
2197169Ssam 		/* keep turning IN_RMR off */
2207169Ssam 	}
2217169Ssam 	printf("acc%d: imp doesn't respond, icsr=%b\n", unit,
2227169Ssam 		addr->icsr, ACC_INBITS);
2237169Ssam 	return (0);
2247169Ssam }
2257169Ssam 
2265638Ssam /*
22733452Skarels  * Drop the host ready line to mark host down.
22833452Skarels  */
accdown(unit)22933452Skarels accdown(unit)
23033452Skarels 	int unit;
23133452Skarels {
23233452Skarels 	register struct accdevice *addr;
23333452Skarels 
23433452Skarels 	addr = (struct accdevice *)(accinfo[unit]->ui_addr);
23533452Skarels         addr->ocsr = ACC_RESET;
23633452Skarels 	DELAY(5000);
23733452Skarels 	addr->ocsr = OUT_BBACK;		/* reset host master ready */
23834273Skarels 	accoflush(unit);
23933452Skarels 	return (1);
24033452Skarels }
24133452Skarels 
accoflush(unit)24234273Skarels accoflush(unit)
24334273Skarels 	int unit;
24434273Skarels {
24534273Skarels 	register struct acc_softc *sc = &acc_softc[unit];
24634273Skarels 
24734273Skarels 	sc->acc_imp->imp_cb.ic_oactive = 0;
24834273Skarels 	if (sc->acc_ifuba.ifu_xtofree) {
24934273Skarels 		m_freem(sc->acc_ifuba.ifu_xtofree);
25034273Skarels 		sc->acc_ifuba.ifu_xtofree = 0;
25134273Skarels 	}
25234273Skarels }
25334273Skarels 
25433452Skarels /*
2555638Ssam  * Start output on an interface.
2565638Ssam  */
accoutput(unit,m)25733452Skarels accoutput(unit, m)
25833452Skarels 	int unit;
25933452Skarels 	struct mbuf *m;
2605638Ssam {
26133452Skarels 	int info;
2625638Ssam 	register struct acc_softc *sc = &acc_softc[unit];
2635638Ssam 	register struct accdevice *addr;
2645638Ssam 	u_short cmd;
2655638Ssam 
2665638Ssam 	sc->acc_olen = if_wubaput(&sc->acc_ifuba, m);
2675638Ssam 	/*
2685771Swnj 	 * Have request mapped to UNIBUS for
2695771Swnj 	 * transmission; start the output.
2705638Ssam 	 */
2715771Swnj 	if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP)
2725771Swnj 		UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_w.ifrw_bdp);
2735923Ssam 	addr = (struct accdevice *)accinfo[unit]->ui_addr;
2745638Ssam 	info = sc->acc_ifuba.ifu_w.ifrw_info;
2755771Swnj 	addr->oba = (u_short)info;
2765771Swnj 	addr->owc = -((sc->acc_olen + 1) >> 1);
2775638Ssam 	cmd = ACC_IE | OUT_ENLB | ((info & 0x30000) >> 12) | ACC_GO;
2785771Swnj #ifdef LOOPBACK
2795771Swnj 	cmd |= OUT_BBACK;
2805771Swnj #endif
2815771Swnj 	addr->ocsr = cmd;
28233452Skarels 	sc->acc_imp->imp_cb.ic_oactive = 1;
2835638Ssam }
2845638Ssam 
2855638Ssam /*
2865638Ssam  * Output interrupt handler.
2875638Ssam  */
accxint(unit)2885638Ssam accxint(unit)
2898414Swnj 	int unit;
2905638Ssam {
2915638Ssam 	register struct acc_softc *sc = &acc_softc[unit];
2925638Ssam 	register struct accdevice *addr;
2935638Ssam 
2947169Ssam 	addr = (struct accdevice *)accinfo[unit]->ui_addr;
29533452Skarels 	if (sc->acc_imp->imp_cb.ic_oactive == 0) {
2967169Ssam 		printf("acc%d: stray xmit interrupt, csr=%b\n", unit,
2977169Ssam 			addr->ocsr, ACC_OUTBITS);
2985638Ssam 		return;
2995638Ssam 	}
30033452Skarels 	sc->acc_imp->imp_if.if_opackets++;
30133452Skarels 	sc->acc_imp->imp_cb.ic_oactive = 0;
3027176Sroot 	if (addr->ocsr & ACC_ERR) {
3037169Ssam 		printf("acc%d: output error, ocsr=%b, icsr=%b\n", unit,
3047169Ssam 			addr->ocsr, ACC_OUTBITS, addr->icsr, ACC_INBITS);
30533452Skarels 		sc->acc_imp->imp_if.if_oerrors++;
3065647Ssam 	}
3075771Swnj 	if (sc->acc_ifuba.ifu_xtofree) {
3085771Swnj 		m_freem(sc->acc_ifuba.ifu_xtofree);
3095771Swnj 		sc->acc_ifuba.ifu_xtofree = 0;
3105771Swnj 	}
31133452Skarels 	impstart(sc->acc_imp);
3125638Ssam }
3135638Ssam 
3145638Ssam /*
3155638Ssam  * Input interrupt handler
3165638Ssam  */
accrint(unit)3175638Ssam accrint(unit)
3188414Swnj 	int unit;
3195638Ssam {
3205638Ssam 	register struct acc_softc *sc = &acc_softc[unit];
3215638Ssam 	register struct accdevice *addr;
3225638Ssam     	struct mbuf *m;
3235638Ssam 	int len, info;
3245638Ssam 
3257169Ssam 	addr = (struct accdevice *)accinfo[unit]->ui_addr;
32633452Skarels 	sc->acc_imp->imp_if.if_ipackets++;
3275638Ssam 
3285638Ssam 	/*
3295638Ssam 	 * Purge BDP; flush message if error indicated.
3305638Ssam 	 */
3315771Swnj 	if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP)
3325771Swnj 		UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_r.ifrw_bdp);
3337176Sroot 	if (addr->icsr & ACC_ERR) {
3347198Ssam 		printf("acc%d: input error, csr=%b\n", unit,
3357198Ssam 		    addr->icsr, ACC_INBITS);
33633452Skarels 		sc->acc_imp->imp_if.if_ierrors++;
3375638Ssam 		sc->acc_flush = 1;
3385638Ssam 	}
3395638Ssam 
3405638Ssam 	if (sc->acc_flush) {
3415771Swnj 		if (addr->icsr & IN_EOM)
3425638Ssam 			sc->acc_flush = 0;
3435638Ssam 		goto setup;
3445638Ssam 	}
34533452Skarels 	len = IMP_RCVBUF + (addr->iwc << 1);
34633452Skarels 	if (len < 0 || len > IMP_RCVBUF) {
34725441Skarels 		printf("acc%d: bad length=%d\n", unit, len);
34833452Skarels 		sc->acc_imp->imp_if.if_ierrors++;
3495771Swnj 		goto setup;
3505771Swnj 	}
3515638Ssam 
3525638Ssam 	/*
35324799Skarels 	 * The offset parameter is always 0 since using
3545638Ssam 	 * trailers on the ARPAnet is insane.
3555638Ssam 	 */
35633452Skarels 	m = if_rubaget(&sc->acc_ifuba, len, 0, &sc->acc_imp->imp_if);
3575638Ssam 	if (m == 0)
3585638Ssam 		goto setup;
3595771Swnj 	if ((addr->icsr & IN_EOM) == 0) {
3605647Ssam 		if (sc->acc_iq)
3615638Ssam 			m_cat(sc->acc_iq, m);
3625647Ssam 		else
3635638Ssam 			sc->acc_iq = m;
3645638Ssam 		goto setup;
3655638Ssam 	}
3665647Ssam 	if (sc->acc_iq) {
3675638Ssam 		m_cat(sc->acc_iq, m);
3685638Ssam 		m = sc->acc_iq;
3695638Ssam 		sc->acc_iq = 0;
3705638Ssam 	}
3715638Ssam 	impinput(unit, m);
3725638Ssam 
3735638Ssam setup:
3745638Ssam 	/*
3755638Ssam 	 * Setup for next message.
3765638Ssam 	 */
3775638Ssam 	info = sc->acc_ifuba.ifu_r.ifrw_info;
3785771Swnj 	addr->iba = (u_short)info;
37933452Skarels 	addr->iwc = -((IMP_RCVBUF)>> 1);
3805771Swnj 	addr->icsr =
3815638Ssam 		IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO;
3825638Ssam }
3835638Ssam #endif
384