123286Smckusick /*
229360Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
335317Sbostic * All rights reserved.
423286Smckusick *
544558Sbostic * %sccs.include.redist.c%
635317Sbostic *
7*45801Sbostic * @(#)if_dmc.c 7.10 (Berkeley) 12/16/90
823286Smckusick */
95725Sroot
105725Sroot #include "dmc.h"
115725Sroot #if NDMC > 0
1217565Skarels
135725Sroot /*
145725Sroot * DMC11 device driver, internet version
155725Sroot *
1617565Skarels * Bill Nesheim
1717221Stef * Cornell University
1811191Ssam *
1917565Skarels * Lou Salkind
2017565Skarels * New York University
215725Sroot */
2217565Skarels
2317565Skarels /* #define DEBUG /* for base table dump on fatal error */
2417565Skarels
25*45801Sbostic #include "../include/pte.h"
265725Sroot
27*45801Sbostic #include "sys/param.h"
28*45801Sbostic #include "sys/systm.h"
29*45801Sbostic #include "sys/mbuf.h"
30*45801Sbostic #include "sys/buf.h"
31*45801Sbostic #include "sys/ioctl.h" /* must precede tty.h */
32*45801Sbostic #include "sys/tty.h"
33*45801Sbostic #include "sys/protosw.h"
34*45801Sbostic #include "sys/socket.h"
35*45801Sbostic #include "sys/syslog.h"
36*45801Sbostic #include "sys/vmmac.h"
37*45801Sbostic #include "sys/errno.h"
38*45801Sbostic #include "sys/time.h"
39*45801Sbostic #include "sys/kernel.h"
408460Sroot
41*45801Sbostic #include "net/if.h"
42*45801Sbostic #include "net/netisr.h"
43*45801Sbostic #include "net/route.h"
4424796Skarels
4524796Skarels #ifdef INET
46*45801Sbostic #include "netinet/in.h"
47*45801Sbostic #include "netinet/in_systm.h"
48*45801Sbostic #include "netinet/in_var.h"
49*45801Sbostic #include "netinet/ip.h"
5024796Skarels #endif
518460Sroot
52*45801Sbostic #include "../include/cpu.h"
53*45801Sbostic #include "../include/mtpr.h"
5417111Sbloom #include "if_uba.h"
5517111Sbloom #include "if_dmc.h"
56*45801Sbostic #include "../uba/ubareg.h"
57*45801Sbostic #include "../uba/ubavar.h"
585725Sroot
5917565Skarels
6034529Skarels /*
6134529Skarels * output timeout value, sec.; should depend on line speed.
6234529Skarels */
6334529Skarels int dmc_timeout = 20;
6417565Skarels
655725Sroot /*
665725Sroot * Driver information for auto-configuration stuff.
675725Sroot */
6813061Ssam int dmcprobe(), dmcattach(), dmcinit(), dmcioctl();
6934529Skarels int dmcoutput(), dmcreset(), dmctimeout();
705725Sroot struct uba_device *dmcinfo[NDMC];
715725Sroot u_short dmcstd[] = { 0 };
725725Sroot struct uba_driver dmcdriver =
735725Sroot { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo };
745725Sroot
7517221Stef #define NRCV 7
7617565Skarels #define NXMT 3
7724796Skarels #define NCMDS (NRCV+NXMT+4) /* size of command queue */
7817221Stef
7917565Skarels #define printd if(dmcdebug)printf
8017565Skarels int dmcdebug = 0;
8117565Skarels
8217221Stef /* error reporting intervals */
8317221Stef #define DMC_RPNBFS 50
8417221Stef #define DMC_RPDSC 1
8517565Skarels #define DMC_RPTMO 10
8617565Skarels #define DMC_RPDCK 10
8717221Stef
8817221Stef struct dmc_command {
8917221Stef char qp_cmd; /* command */
9017221Stef short qp_ubaddr; /* buffer address */
9117221Stef short qp_cc; /* character count || XMEM */
9217221Stef struct dmc_command *qp_next; /* next command on queue */
9317221Stef };
9417221Stef
9517221Stef struct dmcbufs {
9617221Stef int ubinfo; /* from uballoc */
9717221Stef short cc; /* buffer size */
9817221Stef short flags; /* access control */
9917221Stef };
10017221Stef #define DBUF_OURS 0 /* buffer is available */
10117221Stef #define DBUF_DMCS 1 /* buffer claimed by somebody */
10217221Stef #define DBUF_XMIT 4 /* transmit buffer */
10317565Skarels #define DBUF_RCV 8 /* receive buffer */
10417221Stef
10517221Stef
10617221Stef /*
1075725Sroot * DMC software status per interface.
1085725Sroot *
1095725Sroot * Each interface is referenced by a network interface structure,
1105725Sroot * sc_if, which the routing code uses to locate the interface.
1115725Sroot * This structure contains the output queue for the interface, its address, ...
11217221Stef * We also have, for each interface, a set of 7 UBA interface structures
11317221Stef * for each, which
11417221Stef * contain 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 */
12126933Skarels short sc_oused; /* output buffers currently in use */
12226933Skarels short sc_iused; /* input buffers given to DMC */
12326933Skarels short sc_flag; /* flags */
1245725Sroot int sc_ubinfo; /* UBA mapping info for base table */
12517221Stef int sc_errors[4]; /* non-fatal error counters */
12617221Stef #define sc_datck sc_errors[0]
12717221Stef #define sc_timeo sc_errors[1]
12817221Stef #define sc_nobuf sc_errors[2]
12917221Stef #define sc_disc sc_errors[3]
13034529Skarels struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */
13134529Skarels struct dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */
13234529Skarels struct ifubinfo sc_ifuba; /* UNIBUS resources */
13334529Skarels struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */
13434529Skarels struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */
13517221Stef /* command queue stuff */
13617565Skarels struct dmc_command sc_cmdbuf[NCMDS];
13717221Stef struct dmc_command *sc_qhead; /* head of command queue */
13817221Stef struct dmc_command *sc_qtail; /* tail of command queue */
13917221Stef struct dmc_command *sc_qactive; /* command in progress */
14017221Stef struct dmc_command *sc_qfreeh; /* head of list of free cmd buffers */
14117221Stef struct dmc_command *sc_qfreet; /* tail of list of free cmd buffers */
14217221Stef /* end command queue stuff */
1435725Sroot } dmc_softc[NDMC];
1445725Sroot
1455725Sroot /* flags */
14634529Skarels #define DMC_RUNNING 0x01 /* device initialized */
14727266Skarels #define DMC_BMAPPED 0x02 /* base table mapped */
14827266Skarels #define DMC_RESTART 0x04 /* software restart in progress */
14934529Skarels #define DMC_ONLINE 0x08 /* device running (had a RDYO) */
1505725Sroot
15117565Skarels struct dmc_base {
15217565Skarels short d_base[128]; /* DMC base table */
1535725Sroot } dmc_base[NDMC];
1545725Sroot
15517221Stef /* queue manipulation macros */
15617221Stef #define QUEUE_AT_HEAD(qp, head, tail) \
15717221Stef (qp)->qp_next = (head); \
15817221Stef (head) = (qp); \
15917221Stef if ((tail) == (struct dmc_command *) 0) \
16017221Stef (tail) = (head)
1615725Sroot
16217221Stef #define QUEUE_AT_TAIL(qp, head, tail) \
16317221Stef if ((tail)) \
16417221Stef (tail)->qp_next = (qp); \
16517221Stef else \
16617221Stef (head) = (qp); \
16717221Stef (qp)->qp_next = (struct dmc_command *) 0; \
16817221Stef (tail) = (qp)
16917221Stef
17017221Stef #define DEQUEUE(head, tail) \
17117221Stef (head) = (head)->qp_next;\
17217221Stef if ((head) == (struct dmc_command *) 0)\
17317221Stef (tail) = (head)
17417221Stef
dmcprobe(reg)1755725Sroot dmcprobe(reg)
1765725Sroot caddr_t reg;
1775725Sroot {
1785725Sroot register int br, cvec;
1795725Sroot register struct dmcdevice *addr = (struct dmcdevice *)reg;
1805725Sroot register int i;
1815725Sroot
1825725Sroot #ifdef lint
1835725Sroot br = 0; cvec = br; br = cvec;
1845725Sroot dmcrint(0); dmcxint(0);
1855725Sroot #endif
1865725Sroot addr->bsel1 = DMC_MCLR;
1875725Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
1885725Sroot ;
18917565Skarels if ((addr->bsel1 & DMC_RUN) == 0) {
19017565Skarels printf("dmcprobe: can't start device\n" );
1916334Ssam return (0);
19217565Skarels }
1935725Sroot addr->bsel0 = DMC_RQI|DMC_IEI;
19417565Skarels /* let's be paranoid */
19517565Skarels addr->bsel0 |= DMC_RQI|DMC_IEI;
19617565Skarels DELAY(1000000);
1975725Sroot addr->bsel1 = DMC_MCLR;
1985725Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
1995725Sroot ;
2006334Ssam return (1);
2015725Sroot }
2025725Sroot
2035725Sroot /*
2045725Sroot * Interface exists: make available by filling in network interface
2055725Sroot * record. System will initialize the interface when it is ready
2065725Sroot * to accept packets.
2075725Sroot */
dmcattach(ui)2085725Sroot dmcattach(ui)
2095725Sroot register struct uba_device *ui;
2105725Sroot {
2115725Sroot register struct dmc_softc *sc = &dmc_softc[ui->ui_unit];
2125725Sroot
2135725Sroot sc->sc_if.if_unit = ui->ui_unit;
2145725Sroot sc->sc_if.if_name = "dmc";
2155725Sroot sc->sc_if.if_mtu = DMCMTU;
2165725Sroot sc->sc_if.if_init = dmcinit;
2175725Sroot sc->sc_if.if_output = dmcoutput;
21813061Ssam sc->sc_if.if_ioctl = dmcioctl;
2198976Sroot sc->sc_if.if_reset = dmcreset;
22034529Skarels sc->sc_if.if_watchdog = dmctimeout;
22117221Stef sc->sc_if.if_flags = IFF_POINTOPOINT;
22224796Skarels sc->sc_ifuba.iff_flags = UBA_CANTWAIT;
22317221Stef
22424796Skarels if_attach(&sc->sc_if);
2255725Sroot }
2265725Sroot
2275725Sroot /*
2285725Sroot * Reset of interface after UNIBUS reset.
22919862Skarels * If interface is on specified UBA, reset its state.
2305725Sroot */
dmcreset(unit,uban)2315725Sroot dmcreset(unit, uban)
2325725Sroot int unit, uban;
2335725Sroot {
2345725Sroot register struct uba_device *ui;
23517221Stef register struct dmc_softc *sc = &dmc_softc[unit];
2365725Sroot
2375725Sroot if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 ||
2385725Sroot ui->ui_ubanum != uban)
2395725Sroot return;
2405725Sroot printf(" dmc%d", unit);
24117565Skarels sc->sc_flag = 0;
24219862Skarels sc->sc_if.if_flags &= ~IFF_RUNNING;
2435725Sroot dmcinit(unit);
2445725Sroot }
2455725Sroot
2465725Sroot /*
2475725Sroot * Initialization of interface; reinitialize UNIBUS usage.
2485725Sroot */
dmcinit(unit)2495725Sroot dmcinit(unit)
2505725Sroot int unit;
2515725Sroot {
2525725Sroot register struct dmc_softc *sc = &dmc_softc[unit];
2535725Sroot register struct uba_device *ui = dmcinfo[unit];
2545725Sroot register struct dmcdevice *addr;
25513061Ssam register struct ifnet *ifp = &sc->sc_if;
25617221Stef register struct ifrw *ifrw;
25717221Stef register struct ifxmt *ifxp;
25817221Stef register struct dmcbufs *rp;
25917565Skarels register struct dmc_command *qp;
26019862Skarels struct ifaddr *ifa;
26117221Stef int base;
26217565Skarels int s;
2635725Sroot
26417221Stef addr = (struct dmcdevice *)ui->ui_addr;
26517221Stef
26619862Skarels /*
26719862Skarels * Check to see that an address has been set
26819862Skarels * (both local and destination for an address family).
26919862Skarels */
27019862Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
27138983Skarels if (ifa->ifa_addr->sa_family && ifa->ifa_dstaddr->sa_family)
27219862Skarels break;
27319862Skarels if (ifa == (struct ifaddr *) 0)
2745725Sroot return;
27517221Stef
27617221Stef if ((addr->bsel1&DMC_RUN) == 0) {
27717221Stef printf("dmcinit: DMC not running\n");
27819862Skarels ifp->if_flags &= ~IFF_UP;
27917221Stef return;
28017221Stef }
28117221Stef /* map base table */
28217565Skarels if ((sc->sc_flag & DMC_BMAPPED) == 0) {
28317221Stef sc->sc_ubinfo = uballoc(ui->ui_ubanum,
28417221Stef (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0);
28517221Stef sc->sc_flag |= DMC_BMAPPED;
28617221Stef }
28717221Stef /* initialize UNIBUS resources */
28817221Stef sc->sc_iused = sc->sc_oused = 0;
28919862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) {
29024796Skarels if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum,
29124796Skarels sizeof(struct dmc_header), (int)btoc(DMCMTU),
29224796Skarels sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) {
29319862Skarels printf("dmc%d: can't allocate uba resources\n", unit);
29413061Ssam ifp->if_flags &= ~IFF_UP;
29513061Ssam return;
29613061Ssam }
29719862Skarels ifp->if_flags |= IFF_RUNNING;
2985725Sroot }
29934529Skarels sc->sc_flag &= ~DMC_ONLINE;
30027266Skarels sc->sc_flag |= DMC_RUNNING;
30134529Skarels /*
30234529Skarels * Limit packets enqueued until we see if we're on the air.
30334529Skarels */
30434529Skarels ifp->if_snd.ifq_maxlen = 3;
30517221Stef
30617221Stef /* initialize buffer pool */
30717565Skarels /* receives */
30824796Skarels ifrw = &sc->sc_ifr[0];
30917221Stef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
31036032Skarels rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
31117565Skarels rp->cc = DMCMTU + sizeof (struct dmc_header);
31217221Stef rp->flags = DBUF_OURS|DBUF_RCV;
31317221Stef ifrw++;
3146363Ssam }
31517221Stef /* transmits */
31624796Skarels ifxp = &sc->sc_ifw[0];
31717221Stef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
31836032Skarels rp->ubinfo = UBAI_ADDR(ifxp->ifw_info);
31917221Stef rp->cc = 0;
32017221Stef rp->flags = DBUF_OURS|DBUF_XMIT;
32117221Stef ifxp++;
32217221Stef }
32317565Skarels
32417565Skarels /* set up command queues */
32517565Skarels sc->sc_qfreeh = sc->sc_qfreet
32617565Skarels = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive =
32717565Skarels (struct dmc_command *)0;
32817565Skarels /* set up free command buffer list */
32917565Skarels for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) {
33017565Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
33117565Skarels }
33217565Skarels
33317221Stef /* base in */
33436032Skarels base = UBAI_ADDR(sc->sc_ubinfo);
33536032Skarels dmcload(sc, DMC_BASEI, (u_short)base, (base>>2) & DMC_XMEM);
33617221Stef /* specify half duplex operation, flags tell if primary */
33717221Stef /* or secondary station */
33817221Stef if (ui->ui_flags == 0)
33927266Skarels /* use DDCMP mode in full duplex */
34017565Skarels dmcload(sc, DMC_CNTLI, 0, 0);
34117221Stef else if (ui->ui_flags == 1)
34217565Skarels /* use MAINTENENCE mode */
34317565Skarels dmcload(sc, DMC_CNTLI, 0, DMC_MAINT );
34417221Stef else if (ui->ui_flags == 2)
34517221Stef /* use DDCMP half duplex as primary station */
34617221Stef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX);
34717221Stef else if (ui->ui_flags == 3)
34817221Stef /* use DDCMP half duplex as secondary station */
34917221Stef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC);
35017565Skarels
35117565Skarels /* enable operation done interrupts */
35217565Skarels while ((addr->bsel2 & DMC_IEO) == 0)
35317565Skarels addr->bsel2 |= DMC_IEO;
35417565Skarels s = spl5();
35517221Stef /* queue first NRCV buffers for DMC to fill */
35617221Stef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
35717221Stef rp->flags |= DBUF_DMCS;
35817221Stef dmcload(sc, DMC_READ, rp->ubinfo,
35917565Skarels (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc));
36017221Stef sc->sc_iused++;
36117221Stef }
36217565Skarels splx(s);
3635725Sroot }
3645725Sroot
3655725Sroot /*
3665725Sroot * Start output on interface. Get another datagram
3675725Sroot * to send from the interface queue and map it to
3685725Sroot * the interface before starting output.
36917221Stef *
37017221Stef * Must be called at spl 5
3715725Sroot */
dmcstart(unit)37234529Skarels dmcstart(unit)
37334529Skarels int unit;
3745725Sroot {
3755725Sroot register struct dmc_softc *sc = &dmc_softc[unit];
3765725Sroot struct mbuf *m;
37717221Stef register struct dmcbufs *rp;
37817221Stef register int n;
3795725Sroot
3805725Sroot /*
38117221Stef * Dequeue up to NXMT requests and map them to the UNIBUS.
38217221Stef * If no more requests, or no dmc buffers available, just return.
3835725Sroot */
38417221Stef n = 0;
38517221Stef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) {
38617221Stef /* find an available buffer */
38717565Skarels if ((rp->flags & DBUF_DMCS) == 0) {
38817221Stef IF_DEQUEUE(&sc->sc_if.if_snd, m);
38917221Stef if (m == 0)
39017221Stef return;
39117221Stef /* mark it dmcs */
39217221Stef rp->flags |= (DBUF_DMCS);
39317221Stef /*
39417221Stef * Have request mapped to UNIBUS for transmission
39517221Stef * and start the output.
39617221Stef */
39724796Skarels rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m);
39817565Skarels rp->cc &= DMC_CCOUNT;
39934529Skarels if (++sc->sc_oused == 1)
40034529Skarels sc->sc_if.if_timer = dmc_timeout;
40117221Stef dmcload(sc, DMC_WRITE, rp->ubinfo,
40217221Stef rp->cc | ((rp->ubinfo>>2)&DMC_XMEM));
40317221Stef }
40417221Stef n++;
40517221Stef }
4065725Sroot }
4075725Sroot
4085725Sroot /*
4095725Sroot * Utility routine to load the DMC device registers.
4105725Sroot */
dmcload(sc,type,w0,w1)4115725Sroot dmcload(sc, type, w0, w1)
4125725Sroot register struct dmc_softc *sc;
41336032Skarels int type;
41436032Skarels u_short w0, w1;
4155725Sroot {
4165725Sroot register struct dmcdevice *addr;
41717221Stef register int unit, sps;
41817221Stef register struct dmc_command *qp;
4195725Sroot
42017565Skarels unit = sc - dmc_softc;
4215725Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
4225725Sroot sps = spl5();
42317221Stef
42417221Stef /* grab a command buffer from the free list */
42517221Stef if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0)
42617221Stef panic("dmc command queue overflow");
42717221Stef DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet);
42817221Stef
42917221Stef /* fill in requested info */
43017221Stef qp->qp_cmd = (type | DMC_RQI);
43117221Stef qp->qp_ubaddr = w0;
43217221Stef qp->qp_cc = w1;
43317221Stef
43417221Stef if (sc->sc_qactive) { /* command in progress */
43517221Stef if (type == DMC_READ) {
43617221Stef QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail);
43717221Stef } else {
43817221Stef QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail);
43917221Stef }
44017221Stef } else { /* command port free */
44117221Stef sc->sc_qactive = qp;
44217221Stef addr->bsel0 = qp->qp_cmd;
4435725Sroot dmcrint(unit);
44417221Stef }
4455725Sroot splx(sps);
4465725Sroot }
4475725Sroot
4485725Sroot /*
4495725Sroot * DMC interface receiver interrupt.
4505725Sroot * Ready to accept another command,
4515725Sroot * pull one off the command queue.
4525725Sroot */
dmcrint(unit)4535725Sroot dmcrint(unit)
4545725Sroot int unit;
4555725Sroot {
4565725Sroot register struct dmc_softc *sc;
4575725Sroot register struct dmcdevice *addr;
45817221Stef register struct dmc_command *qp;
4595725Sroot register int n;
4605725Sroot
4615725Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr;
4625725Sroot sc = &dmc_softc[unit];
46317221Stef if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) {
46417565Skarels printf("dmc%d: dmcrint no command\n", unit);
46517221Stef return;
46617221Stef }
4675725Sroot while (addr->bsel0&DMC_RDYI) {
46817221Stef addr->sel4 = qp->qp_ubaddr;
46917221Stef addr->sel6 = qp->qp_cc;
4705725Sroot addr->bsel0 &= ~(DMC_IEI|DMC_RQI);
47117221Stef /* free command buffer */
47217221Stef QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet);
47317221Stef while (addr->bsel0 & DMC_RDYI) {
47417221Stef /*
47517221Stef * Can't check for RDYO here 'cause
47617221Stef * this routine isn't reentrant!
47717221Stef */
47817221Stef DELAY(5);
47917221Stef }
48017221Stef /* move on to next command */
48117565Skarels if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0)
48217565Skarels break; /* all done */
48317221Stef /* more commands to do, start the next one */
48417221Stef qp = sc->sc_qactive;
48517221Stef DEQUEUE(sc->sc_qhead, sc->sc_qtail);
48617221Stef addr->bsel0 = qp->qp_cmd;
4875725Sroot n = RDYSCAN;
48817565Skarels while (n-- > 0)
48917565Skarels if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO))
49017565Skarels break;
4915725Sroot }
49217221Stef if (sc->sc_qactive) {
49317221Stef addr->bsel0 |= DMC_IEI|DMC_RQI;
49417221Stef /* VMS does it twice !*$%@# */
49517221Stef addr->bsel0 |= DMC_IEI|DMC_RQI;
49617221Stef }
49717565Skarels
4985725Sroot }
4995725Sroot
5005725Sroot /*
5015725Sroot * DMC interface transmitter interrupt.
50217221Stef * A transfer may have completed, check for errors.
5035725Sroot * If it was a read, notify appropriate protocol.
5045725Sroot * If it was a write, pull the next one off the queue.
5055725Sroot */
dmcxint(unit)5065725Sroot dmcxint(unit)
5075725Sroot int unit;
5085725Sroot {
5095725Sroot register struct dmc_softc *sc;
51013065Ssam register struct ifnet *ifp;
5115725Sroot struct uba_device *ui = dmcinfo[unit];
5125725Sroot struct dmcdevice *addr;
5135725Sroot struct mbuf *m;
51417565Skarels struct ifqueue *inq;
51527266Skarels int arg, pkaddr, cmd, len, s;
51617221Stef register struct ifrw *ifrw;
51717221Stef register struct dmcbufs *rp;
51817565Skarels register struct ifxmt *ifxp;
51917565Skarels struct dmc_header *dh;
52017565Skarels int off, resid;
5215725Sroot
5225725Sroot addr = (struct dmcdevice *)ui->ui_addr;
52317221Stef sc = &dmc_softc[unit];
52417221Stef ifp = &sc->sc_if;
52517221Stef
52617565Skarels while (addr->bsel2 & DMC_RDYO) {
5275725Sroot
52817565Skarels cmd = addr->bsel2 & 0xff;
52917565Skarels arg = addr->sel6 & 0xffff;
53017565Skarels /* reconstruct UNIBUS address of buffer returned to us */
53117565Skarels pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff);
53217565Skarels /* release port */
53317565Skarels addr->bsel2 &= ~DMC_RDYO;
53417565Skarels switch (cmd & 07) {
53517565Skarels
53617565Skarels case DMC_OUR:
53717565Skarels /*
53817565Skarels * A read has completed.
53917565Skarels * Pass packet to type specific
54017565Skarels * higher-level input routine.
54117565Skarels */
54217565Skarels ifp->if_ipackets++;
54317565Skarels /* find location in dmcuba struct */
54424796Skarels ifrw= &sc->sc_ifr[0];
54517565Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {
54617565Skarels if(rp->ubinfo == pkaddr)
54717565Skarels break;
54817565Skarels ifrw++;
54917565Skarels }
55017565Skarels if (rp >= &sc->sc_rbufs[NRCV])
55117565Skarels panic("dmc rcv");
55217565Skarels if ((rp->flags & DBUF_DMCS) == 0)
55317565Skarels printf("dmc%d: done unalloc rbuf\n", unit);
55417565Skarels
55517565Skarels len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header);
55617565Skarels if (len < 0 || len > DMCMTU) {
55717565Skarels ifp->if_ierrors++;
55817565Skarels printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n",
55917565Skarels unit, pkaddr, len);
56017565Skarels goto setup;
56117565Skarels }
56217565Skarels /*
56317565Skarels * Deal with trailer protocol: if type is trailer
56417565Skarels * get true type from first 16-bit word past data.
56517565Skarels * Remember that type was trailer by setting off.
56617565Skarels */
56717565Skarels dh = (struct dmc_header *)ifrw->ifrw_addr;
56817565Skarels dh->dmc_type = ntohs((u_short)dh->dmc_type);
56917565Skarels #define dmcdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off))))
57017565Skarels if (dh->dmc_type >= DMC_TRAILER &&
57117565Skarels dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) {
57217565Skarels off = (dh->dmc_type - DMC_TRAILER) * 512;
57317565Skarels if (off >= DMCMTU)
57417565Skarels goto setup; /* sanity */
57517565Skarels dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *));
57617565Skarels resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *)));
57717565Skarels if (off + resid > len)
57817565Skarels goto setup; /* sanity */
57917565Skarels len = off + resid;
58017565Skarels } else
58117565Skarels off = 0;
58217565Skarels if (len == 0)
58317565Skarels goto setup;
58417565Skarels
58517565Skarels /*
58617565Skarels * Pull packet off interface. Off is nonzero if
58717565Skarels * packet has trailing header; dmc_get will then
58817565Skarels * force this header information to be at the front,
58917565Skarels * but we still have to drop the type and length
59017565Skarels * which are at the front of any trailer data.
59117565Skarels */
59224796Skarels m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);
59317565Skarels if (m == 0)
59417565Skarels goto setup;
59517565Skarels switch (dh->dmc_type) {
59617565Skarels
5975725Sroot #ifdef INET
59817565Skarels case DMC_IPTYPE:
59917565Skarels schednetisr(NETISR_IP);
60017565Skarels inq = &ipintrq;
60117565Skarels break;
6025725Sroot #endif
60317565Skarels default:
60417565Skarels m_freem(m);
60517565Skarels goto setup;
60617565Skarels }
6075725Sroot
60827266Skarels s = splimp();
60917565Skarels if (IF_QFULL(inq)) {
61017565Skarels IF_DROP(inq);
61117565Skarels m_freem(m);
61217565Skarels } else
61317565Skarels IF_ENQUEUE(inq, m);
61427266Skarels splx(s);
61517221Stef
61617565Skarels setup:
61717565Skarels /* is this needed? */
61836032Skarels rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);
6195725Sroot
62017565Skarels dmcload(sc, DMC_READ, rp->ubinfo,
62117565Skarels ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc);
62217565Skarels break;
6235725Sroot
62417565Skarels case DMC_OUX:
62517565Skarels /*
62617565Skarels * A write has completed, start another
62717565Skarels * transfer if there is more data to send.
62817565Skarels */
62917565Skarels ifp->if_opackets++;
63017565Skarels /* find associated dmcbuf structure */
63124796Skarels ifxp = &sc->sc_ifw[0];
63217565Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {
63317565Skarels if(rp->ubinfo == pkaddr)
63417565Skarels break;
63517565Skarels ifxp++;
63617565Skarels }
63717565Skarels if (rp >= &sc->sc_xbufs[NXMT]) {
63817565Skarels printf("dmc%d: bad packet address 0x%x\n",
63917565Skarels unit, pkaddr);
64017565Skarels break;
64117565Skarels }
64217565Skarels if ((rp->flags & DBUF_DMCS) == 0)
64317565Skarels printf("dmc%d: unallocated packet 0x%x\n",
64417565Skarels unit, pkaddr);
64517565Skarels /* mark buffer free */
64624796Skarels if (ifxp->ifw_xtofree) {
64724796Skarels (void)m_freem(ifxp->ifw_xtofree);
64824796Skarels ifxp->ifw_xtofree = 0;
64917565Skarels }
65017565Skarels rp->flags &= ~DBUF_DMCS;
65134529Skarels if (--sc->sc_oused == 0)
65234529Skarels sc->sc_if.if_timer = 0;
65334529Skarels else
65434529Skarels sc->sc_if.if_timer = dmc_timeout;
65534529Skarels if ((sc->sc_flag & DMC_ONLINE) == 0) {
65634529Skarels extern int ifqmaxlen;
65734529Skarels
65834529Skarels /*
65934529Skarels * We're on the air.
66034529Skarels * Open the queue to the usual value.
66134529Skarels */
66234529Skarels sc->sc_flag |= DMC_ONLINE;
66334529Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen;
66434529Skarels }
66517565Skarels break;
66617221Stef
66717565Skarels case DMC_CNTLO:
66817565Skarels arg &= DMC_CNTMASK;
66917565Skarels if (arg & DMC_FATAL) {
67034529Skarels if (arg != DMC_START)
67134529Skarels log(LOG_ERR,
67234529Skarels "dmc%d: fatal error, flags=%b\n",
67334529Skarels unit, arg, CNTLO_BITS);
67417565Skarels dmcrestart(unit);
67517565Skarels break;
67617565Skarels }
67717565Skarels /* ACCUMULATE STATISTICS */
67817221Stef switch(arg) {
67917221Stef case DMC_NOBUFS:
68017565Skarels ifp->if_ierrors++;
68117565Skarels if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0)
68217565Skarels goto report;
68317565Skarels break;
68417221Stef case DMC_DISCONN:
68517565Skarels if ((sc->sc_disc++ % DMC_RPDSC) == 0)
68617565Skarels goto report;
68717565Skarels break;
68817221Stef case DMC_TIMEOUT:
68917565Skarels if ((sc->sc_timeo++ % DMC_RPTMO) == 0)
69017565Skarels goto report;
69117565Skarels break;
69217221Stef case DMC_DATACK:
69317565Skarels ifp->if_oerrors++;
69417565Skarels if ((sc->sc_datck++ % DMC_RPDCK) == 0)
69517565Skarels goto report;
69617565Skarels break;
69717221Stef default:
69817221Stef goto report;
69917221Stef }
70017221Stef break;
70117221Stef report:
70217565Skarels printd("dmc%d: soft error, flags=%b\n", unit,
70317565Skarels arg, CNTLO_BITS);
70417565Skarels if ((sc->sc_flag & DMC_RESTART) == 0) {
70517565Skarels /*
70617565Skarels * kill off the dmc to get things
70717565Skarels * going again by generating a
70817565Skarels * procedure error
70917565Skarels */
71017565Skarels sc->sc_flag |= DMC_RESTART;
71136032Skarels arg = UBAI_ADDR(sc->sc_ubinfo);
71217565Skarels dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM);
71317565Skarels }
71417565Skarels break;
71517565Skarels
71617565Skarels default:
71717565Skarels printf("dmc%d: bad control %o\n", unit, cmd);
71817565Skarels break;
7195725Sroot }
7205725Sroot }
72117565Skarels dmcstart(unit);
72217221Stef return;
7235725Sroot }
7245725Sroot
7255725Sroot /*
7265725Sroot * DMC output routine.
72717565Skarels * Encapsulate a packet of type family for the dmc.
72817565Skarels * Use trailer local net encapsulation if enough data in first
72917565Skarels * packet leaves a multiple of 512 bytes of data in remainder.
7305725Sroot */
dmcoutput(ifp,m0,dst)73117565Skarels dmcoutput(ifp, m0, dst)
7325725Sroot register struct ifnet *ifp;
73317565Skarels register struct mbuf *m0;
7346334Ssam struct sockaddr *dst;
7355725Sroot {
73617565Skarels int type, error, s;
73717565Skarels register struct mbuf *m = m0;
73817565Skarels register struct dmc_header *dh;
73917565Skarels register int off;
7405725Sroot
74134529Skarels if ((ifp->if_flags & IFF_UP) == 0) {
74234529Skarels error = ENETDOWN;
74334529Skarels goto bad;
74434529Skarels }
74534529Skarels
74617565Skarels switch (dst->sa_family) {
74717565Skarels #ifdef INET
74817565Skarels case AF_INET:
74938983Skarels off = m->m_pkthdr.len - m->m_len;
75017565Skarels if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
75117565Skarels if (off > 0 && (off & 0x1ff) == 0 &&
75238983Skarels (m->m_flags & M_EXT) == 0 &&
75338983Skarels m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
75417565Skarels type = DMC_TRAILER + (off>>9);
75538983Skarels m->m_data -= 2 * sizeof (u_short);
75617565Skarels m->m_len += 2 * sizeof (u_short);
75717565Skarels *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE);
75817565Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
75917565Skarels goto gottrailertype;
76017565Skarels }
76117565Skarels type = DMC_IPTYPE;
76217565Skarels off = 0;
76317565Skarels goto gottype;
76417565Skarels #endif
76517565Skarels
76617565Skarels case AF_UNSPEC:
76717565Skarels dh = (struct dmc_header *)dst->sa_data;
76817565Skarels type = dh->dmc_type;
76917565Skarels goto gottype;
77017565Skarels
77117565Skarels default:
77217565Skarels printf("dmc%d: can't handle af%d\n", ifp->if_unit,
77317565Skarels dst->sa_family);
77417565Skarels error = EAFNOSUPPORT;
77517565Skarels goto bad;
7765725Sroot }
77717565Skarels
77817565Skarels gottrailertype:
77917565Skarels /*
78017565Skarels * Packet to be sent as a trailer; move first packet
78117565Skarels * (control information) to end of chain.
78217565Skarels */
78317565Skarels while (m->m_next)
78417565Skarels m = m->m_next;
78517565Skarels m->m_next = m0;
78617565Skarels m = m0->m_next;
78717565Skarels m0->m_next = 0;
78817565Skarels m0 = m;
78917565Skarels
79017565Skarels gottype:
79117565Skarels /*
79217565Skarels * Add local network header
79317565Skarels * (there is space for a uba on a vax to step on)
79417565Skarels */
79538983Skarels M_PREPEND(m, sizeof(struct dmc_header), M_DONTWAIT);
79638983Skarels if (m == 0) {
79738983Skarels error = ENOBUFS;
79838983Skarels goto bad;
79917565Skarels }
80017565Skarels dh = mtod(m, struct dmc_header *);
80117565Skarels dh->dmc_type = htons((u_short)type);
80217565Skarels
80317565Skarels /*
80417565Skarels * Queue message on interface, and start output if interface
80517565Skarels * not yet active.
80617565Skarels */
80717565Skarels s = splimp();
8086207Swnj if (IF_QFULL(&ifp->if_snd)) {
8096207Swnj IF_DROP(&ifp->if_snd);
8106334Ssam m_freem(m);
8116207Swnj splx(s);
8126502Ssam return (ENOBUFS);
8136207Swnj }
8145725Sroot IF_ENQUEUE(&ifp->if_snd, m);
81517221Stef dmcstart(ifp->if_unit);
8165725Sroot splx(s);
8176502Ssam return (0);
81817565Skarels
81917565Skarels bad:
82017565Skarels m_freem(m0);
82117565Skarels return (error);
8225725Sroot }
82313061Ssam
82417565Skarels
82513061Ssam /*
82613061Ssam * Process an ioctl request.
82713061Ssam */
82824796Skarels /* ARGSUSED */
dmcioctl(ifp,cmd,data)82913061Ssam dmcioctl(ifp, cmd, data)
83013061Ssam register struct ifnet *ifp;
83113061Ssam int cmd;
83213061Ssam caddr_t data;
83313061Ssam {
83413061Ssam int s = splimp(), error = 0;
83527266Skarels register struct dmc_softc *sc = &dmc_softc[ifp->if_unit];
83613061Ssam
83713061Ssam switch (cmd) {
83813061Ssam
83913061Ssam case SIOCSIFADDR:
84017221Stef ifp->if_flags |= IFF_UP;
84119862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0)
84219862Skarels dmcinit(ifp->if_unit);
84313061Ssam break;
84413061Ssam
84513061Ssam case SIOCSIFDSTADDR:
84619862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0)
84719862Skarels dmcinit(ifp->if_unit);
84813061Ssam break;
84917221Stef
85027266Skarels case SIOCSIFFLAGS:
85127266Skarels if ((ifp->if_flags & IFF_UP) == 0 &&
85234529Skarels sc->sc_flag & DMC_RUNNING)
85334529Skarels dmcdown(ifp->if_unit);
85434529Skarels else if (ifp->if_flags & IFF_UP &&
85527266Skarels (sc->sc_flag & DMC_RUNNING) == 0)
85627266Skarels dmcrestart(ifp->if_unit);
85727266Skarels break;
85827266Skarels
85913061Ssam default:
86013061Ssam error = EINVAL;
86113061Ssam }
86213061Ssam splx(s);
86313061Ssam return (error);
86413061Ssam }
86517221Stef
86617221Stef /*
86717565Skarels * Restart after a fatal error.
86817565Skarels * Clear device and reinitialize.
86917565Skarels */
dmcrestart(unit)87017565Skarels dmcrestart(unit)
87117565Skarels int unit;
87217565Skarels {
87317565Skarels register struct dmc_softc *sc = &dmc_softc[unit];
87417565Skarels register struct dmcdevice *addr;
87517565Skarels register int i;
87634529Skarels int s;
87717565Skarels
87817565Skarels #ifdef DEBUG
87917565Skarels /* dump base table */
88017565Skarels printf("dmc%d base table:\n", unit);
88117565Skarels for (i = 0; i < sizeof (struct dmc_base); i++)
88217565Skarels printf("%o\n" ,dmc_base[unit].d_base[i]);
88313085Ssam #endif
88434529Skarels
88534529Skarels dmcdown(unit);
88634529Skarels
88717565Skarels /*
88817565Skarels * Let the DMR finish the MCLR. At 1 Mbit, it should do so
88917565Skarels * in about a max of 6.4 milliseconds with diagnostics enabled.
89017565Skarels */
89134529Skarels addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
89217565Skarels for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--)
89317565Skarels ;
89417565Skarels /* Did the timer expire or did the DMR finish? */
89517565Skarels if ((addr->bsel1 & DMC_RUN) == 0) {
89626282Skarels log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit);
89717565Skarels return;
89817565Skarels }
89917565Skarels
90034529Skarels /* restart DMC */
90134529Skarels dmcinit(unit);
90234529Skarels sc->sc_flag &= ~DMC_RESTART;
90334529Skarels s = spl5();
90434529Skarels dmcstart(unit);
90534529Skarels splx(s);
90634529Skarels sc->sc_if.if_collisions++; /* why not? */
90734529Skarels }
90834529Skarels
90934529Skarels /*
91034529Skarels * Reset a device and mark down.
91134529Skarels * Flush output queue and drop queue limit.
91234529Skarels */
dmcdown(unit)91334529Skarels dmcdown(unit)
91434529Skarels int unit;
91534529Skarels {
91634529Skarels register struct dmc_softc *sc = &dmc_softc[unit];
91734529Skarels register struct ifxmt *ifxp;
91834529Skarels
91934529Skarels ((struct dmcdevice *)(dmcinfo[unit]->ui_addr))->bsel1 = DMC_MCLR;
92034529Skarels sc->sc_flag &= ~(DMC_RUNNING | DMC_ONLINE);
92134529Skarels
92224796Skarels for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {
92324796Skarels if (ifxp->ifw_xtofree) {
92424796Skarels (void) m_freem(ifxp->ifw_xtofree);
92524796Skarels ifxp->ifw_xtofree = 0;
92617565Skarels }
92717565Skarels }
92834529Skarels if_qflush(&sc->sc_if.if_snd);
92917565Skarels }
93017565Skarels
93117565Skarels /*
93234529Skarels * Watchdog timeout to see that transmitted packets don't
93334529Skarels * lose interrupts. The device has to be online (the first
93434529Skarels * transmission may block until the other side comes up).
93517565Skarels */
dmctimeout(unit)93634529Skarels dmctimeout(unit)
93734529Skarels int unit;
93817565Skarels {
93917565Skarels register struct dmc_softc *sc;
94017565Skarels struct dmcdevice *addr;
94117565Skarels
94234529Skarels sc = &dmc_softc[unit];
94334529Skarels if (sc->sc_flag & DMC_ONLINE) {
94434529Skarels addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr);
94534529Skarels log(LOG_ERR, "dmc%d: output timeout, bsel0=%b bsel2=%b\n",
94634529Skarels unit, addr->bsel0 & 0xff, DMC0BITS,
94734529Skarels addr->bsel2 & 0xff, DMC2BITS);
94834529Skarels dmcrestart(unit);
94917565Skarels }
95017565Skarels }
95117565Skarels #endif
952