123286Smckusick /* 229360Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 335317Sbostic * All rights reserved. 423286Smckusick * 5*44558Sbostic * %sccs.include.redist.c% 635317Sbostic * 7*44558Sbostic * @(#)if_dmc.c 7.9 (Berkeley) 06/28/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 2537508Smckusick #include "machine/pte.h" 265725Sroot 2717111Sbloom #include "param.h" 2817111Sbloom #include "systm.h" 2917111Sbloom #include "mbuf.h" 3017111Sbloom #include "buf.h" 3117221Stef #include "ioctl.h" /* must precede tty.h */ 3217111Sbloom #include "tty.h" 3317111Sbloom #include "protosw.h" 3417111Sbloom #include "socket.h" 3526282Skarels #include "syslog.h" 3617111Sbloom #include "vmmac.h" 3717111Sbloom #include "errno.h" 3838989Skarels #include "time.h" 3938989Skarels #include "kernel.h" 408460Sroot 418460Sroot #include "../net/if.h" 429176Ssam #include "../net/netisr.h" 438460Sroot #include "../net/route.h" 4424796Skarels 4524796Skarels #ifdef INET 468416Swnj #include "../netinet/in.h" 478416Swnj #include "../netinet/in_systm.h" 4828950Skarels #include "../netinet/in_var.h" 4917565Skarels #include "../netinet/ip.h" 5024796Skarels #endif 518460Sroot 528460Sroot #include "../vax/cpu.h" 538460Sroot #include "../vax/mtpr.h" 5417111Sbloom #include "if_uba.h" 5517111Sbloom #include "if_dmc.h" 568460Sroot #include "../vaxuba/ubareg.h" 578460Sroot #include "../vaxuba/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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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