123286Smckusick /* 229360Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323286Smckusick * All rights reserved. The Berkeley software License Agreement 423286Smckusick * specifies the terms and conditions for redistribution. 523286Smckusick * 6*34529Skarels * @(#)if_dmc.c 7.2 (Berkeley) 05/27/88 723286Smckusick */ 85725Sroot 95725Sroot #include "dmc.h" 105725Sroot #if NDMC > 0 1117565Skarels 125725Sroot /* 135725Sroot * DMC11 device driver, internet version 145725Sroot * 1517565Skarels * Bill Nesheim 1617221Stef * Cornell University 1711191Ssam * 1817565Skarels * Lou Salkind 1917565Skarels * New York University 205725Sroot */ 2117565Skarels 2217565Skarels /* #define DEBUG /* for base table dump on fatal error */ 2317565Skarels 249794Ssam #include "../machine/pte.h" 255725Sroot 2617111Sbloom #include "param.h" 2717111Sbloom #include "systm.h" 2817111Sbloom #include "mbuf.h" 2917111Sbloom #include "buf.h" 3017221Stef #include "ioctl.h" /* must precede tty.h */ 3117111Sbloom #include "tty.h" 3217111Sbloom #include "protosw.h" 3317111Sbloom #include "socket.h" 3426282Skarels #include "syslog.h" 3517111Sbloom #include "vmmac.h" 3617111Sbloom #include "errno.h" 378460Sroot 388460Sroot #include "../net/if.h" 399176Ssam #include "../net/netisr.h" 408460Sroot #include "../net/route.h" 4124796Skarels 4224796Skarels #ifdef INET 438416Swnj #include "../netinet/in.h" 448416Swnj #include "../netinet/in_systm.h" 4528950Skarels #include "../netinet/in_var.h" 4617565Skarels #include "../netinet/ip.h" 4724796Skarels #endif 488460Sroot 498460Sroot #include "../vax/cpu.h" 508460Sroot #include "../vax/mtpr.h" 5117111Sbloom #include "if_uba.h" 5217111Sbloom #include "if_dmc.h" 538460Sroot #include "../vaxuba/ubareg.h" 548460Sroot #include "../vaxuba/ubavar.h" 555725Sroot 5617565Skarels #include "../h/time.h" 5717565Skarels #include "../h/kernel.h" 5817565Skarels 59*34529Skarels /* 60*34529Skarels * output timeout value, sec.; should depend on line speed. 61*34529Skarels */ 62*34529Skarels int dmc_timeout = 20; 6317565Skarels 645725Sroot /* 655725Sroot * Driver information for auto-configuration stuff. 665725Sroot */ 6713061Ssam int dmcprobe(), dmcattach(), dmcinit(), dmcioctl(); 68*34529Skarels int dmcoutput(), dmcreset(), dmctimeout(); 695725Sroot struct uba_device *dmcinfo[NDMC]; 705725Sroot u_short dmcstd[] = { 0 }; 715725Sroot struct uba_driver dmcdriver = 725725Sroot { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo }; 735725Sroot 7417221Stef #define NRCV 7 7517565Skarels #define NXMT 3 7624796Skarels #define NCMDS (NRCV+NXMT+4) /* size of command queue */ 7717221Stef 7817565Skarels #define printd if(dmcdebug)printf 7917565Skarels int dmcdebug = 0; 8017565Skarels 8117221Stef /* error reporting intervals */ 8217221Stef #define DMC_RPNBFS 50 8317221Stef #define DMC_RPDSC 1 8417565Skarels #define DMC_RPTMO 10 8517565Skarels #define DMC_RPDCK 10 8617221Stef 8717221Stef struct dmc_command { 8817221Stef char qp_cmd; /* command */ 8917221Stef short qp_ubaddr; /* buffer address */ 9017221Stef short qp_cc; /* character count || XMEM */ 9117221Stef struct dmc_command *qp_next; /* next command on queue */ 9217221Stef }; 9317221Stef 9417221Stef struct dmcbufs { 9517221Stef int ubinfo; /* from uballoc */ 9617221Stef short cc; /* buffer size */ 9717221Stef short flags; /* access control */ 9817221Stef }; 9917221Stef #define DBUF_OURS 0 /* buffer is available */ 10017221Stef #define DBUF_DMCS 1 /* buffer claimed by somebody */ 10117221Stef #define DBUF_XMIT 4 /* transmit buffer */ 10217565Skarels #define DBUF_RCV 8 /* receive buffer */ 10317221Stef 10417221Stef 10517221Stef /* 1065725Sroot * DMC software status per interface. 1075725Sroot * 1085725Sroot * Each interface is referenced by a network interface structure, 1095725Sroot * sc_if, which the routing code uses to locate the interface. 1105725Sroot * This structure contains the output queue for the interface, its address, ... 11117221Stef * We also have, for each interface, a set of 7 UBA interface structures 11217221Stef * for each, which 11317221Stef * contain information about the UNIBUS resources held by the interface: 1145725Sroot * map registers, buffered data paths, etc. Information is cached in this 1155725Sroot * structure for use by the if_uba.c routines in running the interface 1165725Sroot * efficiently. 1175725Sroot */ 1185725Sroot struct dmc_softc { 1195725Sroot struct ifnet sc_if; /* network-visible interface */ 12026933Skarels short sc_oused; /* output buffers currently in use */ 12126933Skarels short sc_iused; /* input buffers given to DMC */ 12226933Skarels short sc_flag; /* flags */ 1235725Sroot int sc_ubinfo; /* UBA mapping info for base table */ 12417221Stef int sc_errors[4]; /* non-fatal error counters */ 12517221Stef #define sc_datck sc_errors[0] 12617221Stef #define sc_timeo sc_errors[1] 12717221Stef #define sc_nobuf sc_errors[2] 12817221Stef #define sc_disc sc_errors[3] 129*34529Skarels struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */ 130*34529Skarels struct dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */ 131*34529Skarels struct ifubinfo sc_ifuba; /* UNIBUS resources */ 132*34529Skarels struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ 133*34529Skarels struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ 13417221Stef /* command queue stuff */ 13517565Skarels struct dmc_command sc_cmdbuf[NCMDS]; 13617221Stef struct dmc_command *sc_qhead; /* head of command queue */ 13717221Stef struct dmc_command *sc_qtail; /* tail of command queue */ 13817221Stef struct dmc_command *sc_qactive; /* command in progress */ 13917221Stef struct dmc_command *sc_qfreeh; /* head of list of free cmd buffers */ 14017221Stef struct dmc_command *sc_qfreet; /* tail of list of free cmd buffers */ 14117221Stef /* end command queue stuff */ 1425725Sroot } dmc_softc[NDMC]; 1435725Sroot 1445725Sroot /* flags */ 145*34529Skarels #define DMC_RUNNING 0x01 /* device initialized */ 14627266Skarels #define DMC_BMAPPED 0x02 /* base table mapped */ 14727266Skarels #define DMC_RESTART 0x04 /* software restart in progress */ 148*34529Skarels #define DMC_ONLINE 0x08 /* device running (had a RDYO) */ 1495725Sroot 15017565Skarels struct dmc_base { 15117565Skarels short d_base[128]; /* DMC base table */ 1525725Sroot } dmc_base[NDMC]; 1535725Sroot 15417221Stef /* queue manipulation macros */ 15517221Stef #define QUEUE_AT_HEAD(qp, head, tail) \ 15617221Stef (qp)->qp_next = (head); \ 15717221Stef (head) = (qp); \ 15817221Stef if ((tail) == (struct dmc_command *) 0) \ 15917221Stef (tail) = (head) 1605725Sroot 16117221Stef #define QUEUE_AT_TAIL(qp, head, tail) \ 16217221Stef if ((tail)) \ 16317221Stef (tail)->qp_next = (qp); \ 16417221Stef else \ 16517221Stef (head) = (qp); \ 16617221Stef (qp)->qp_next = (struct dmc_command *) 0; \ 16717221Stef (tail) = (qp) 16817221Stef 16917221Stef #define DEQUEUE(head, tail) \ 17017221Stef (head) = (head)->qp_next;\ 17117221Stef if ((head) == (struct dmc_command *) 0)\ 17217221Stef (tail) = (head) 17317221Stef 1745725Sroot dmcprobe(reg) 1755725Sroot caddr_t reg; 1765725Sroot { 1775725Sroot register int br, cvec; 1785725Sroot register struct dmcdevice *addr = (struct dmcdevice *)reg; 1795725Sroot register int i; 1805725Sroot 1815725Sroot #ifdef lint 1825725Sroot br = 0; cvec = br; br = cvec; 1835725Sroot dmcrint(0); dmcxint(0); 1845725Sroot #endif 1855725Sroot addr->bsel1 = DMC_MCLR; 1865725Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 1875725Sroot ; 18817565Skarels if ((addr->bsel1 & DMC_RUN) == 0) { 18917565Skarels printf("dmcprobe: can't start device\n" ); 1906334Ssam return (0); 19117565Skarels } 1925725Sroot addr->bsel0 = DMC_RQI|DMC_IEI; 19317565Skarels /* let's be paranoid */ 19417565Skarels addr->bsel0 |= DMC_RQI|DMC_IEI; 19517565Skarels DELAY(1000000); 1965725Sroot addr->bsel1 = DMC_MCLR; 1975725Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 1985725Sroot ; 1996334Ssam return (1); 2005725Sroot } 2015725Sroot 2025725Sroot /* 2035725Sroot * Interface exists: make available by filling in network interface 2045725Sroot * record. System will initialize the interface when it is ready 2055725Sroot * to accept packets. 2065725Sroot */ 2075725Sroot dmcattach(ui) 2085725Sroot register struct uba_device *ui; 2095725Sroot { 2105725Sroot register struct dmc_softc *sc = &dmc_softc[ui->ui_unit]; 2115725Sroot 2125725Sroot sc->sc_if.if_unit = ui->ui_unit; 2135725Sroot sc->sc_if.if_name = "dmc"; 2145725Sroot sc->sc_if.if_mtu = DMCMTU; 2155725Sroot sc->sc_if.if_init = dmcinit; 2165725Sroot sc->sc_if.if_output = dmcoutput; 21713061Ssam sc->sc_if.if_ioctl = dmcioctl; 2188976Sroot sc->sc_if.if_reset = dmcreset; 219*34529Skarels sc->sc_if.if_watchdog = dmctimeout; 22017221Stef sc->sc_if.if_flags = IFF_POINTOPOINT; 22124796Skarels sc->sc_ifuba.iff_flags = UBA_CANTWAIT; 22217221Stef 22324796Skarels if_attach(&sc->sc_if); 2245725Sroot } 2255725Sroot 2265725Sroot /* 2275725Sroot * Reset of interface after UNIBUS reset. 22819862Skarels * If interface is on specified UBA, reset its state. 2295725Sroot */ 2305725Sroot dmcreset(unit, uban) 2315725Sroot int unit, uban; 2325725Sroot { 2335725Sroot register struct uba_device *ui; 23417221Stef register struct dmc_softc *sc = &dmc_softc[unit]; 2355725Sroot 2365725Sroot if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 || 2375725Sroot ui->ui_ubanum != uban) 2385725Sroot return; 2395725Sroot printf(" dmc%d", unit); 24017565Skarels sc->sc_flag = 0; 24119862Skarels sc->sc_if.if_flags &= ~IFF_RUNNING; 2425725Sroot dmcinit(unit); 2435725Sroot } 2445725Sroot 2455725Sroot /* 2465725Sroot * Initialization of interface; reinitialize UNIBUS usage. 2475725Sroot */ 2485725Sroot dmcinit(unit) 2495725Sroot int unit; 2505725Sroot { 2515725Sroot register struct dmc_softc *sc = &dmc_softc[unit]; 2525725Sroot register struct uba_device *ui = dmcinfo[unit]; 2535725Sroot register struct dmcdevice *addr; 25413061Ssam register struct ifnet *ifp = &sc->sc_if; 25517221Stef register struct ifrw *ifrw; 25617221Stef register struct ifxmt *ifxp; 25717221Stef register struct dmcbufs *rp; 25817565Skarels register struct dmc_command *qp; 25919862Skarels struct ifaddr *ifa; 26017221Stef int base; 26117565Skarels int s; 2625725Sroot 26317221Stef addr = (struct dmcdevice *)ui->ui_addr; 26417221Stef 26519862Skarels /* 26619862Skarels * Check to see that an address has been set 26719862Skarels * (both local and destination for an address family). 26819862Skarels */ 26919862Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 27019862Skarels if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) 27119862Skarels break; 27219862Skarels if (ifa == (struct ifaddr *) 0) 2735725Sroot return; 27417221Stef 27517221Stef if ((addr->bsel1&DMC_RUN) == 0) { 27617221Stef printf("dmcinit: DMC not running\n"); 27719862Skarels ifp->if_flags &= ~IFF_UP; 27817221Stef return; 27917221Stef } 28017221Stef /* map base table */ 28117565Skarels if ((sc->sc_flag & DMC_BMAPPED) == 0) { 28217221Stef sc->sc_ubinfo = uballoc(ui->ui_ubanum, 28317221Stef (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0); 28417221Stef sc->sc_flag |= DMC_BMAPPED; 28517221Stef } 28617221Stef /* initialize UNIBUS resources */ 28717221Stef sc->sc_iused = sc->sc_oused = 0; 28819862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 28924796Skarels if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum, 29024796Skarels sizeof(struct dmc_header), (int)btoc(DMCMTU), 29124796Skarels sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) { 29219862Skarels printf("dmc%d: can't allocate uba resources\n", unit); 29313061Ssam ifp->if_flags &= ~IFF_UP; 29413061Ssam return; 29513061Ssam } 29619862Skarels ifp->if_flags |= IFF_RUNNING; 2975725Sroot } 298*34529Skarels sc->sc_flag &= ~DMC_ONLINE; 29927266Skarels sc->sc_flag |= DMC_RUNNING; 300*34529Skarels /* 301*34529Skarels * Limit packets enqueued until we see if we're on the air. 302*34529Skarels */ 303*34529Skarels ifp->if_snd.ifq_maxlen = 3; 30417221Stef 30517221Stef /* initialize buffer pool */ 30617565Skarels /* receives */ 30724796Skarels ifrw = &sc->sc_ifr[0]; 30817221Stef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 30917221Stef rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 31017565Skarels rp->cc = DMCMTU + sizeof (struct dmc_header); 31117221Stef rp->flags = DBUF_OURS|DBUF_RCV; 31217221Stef ifrw++; 3136363Ssam } 31417221Stef /* transmits */ 31524796Skarels ifxp = &sc->sc_ifw[0]; 31617221Stef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 31724796Skarels rp->ubinfo = ifxp->ifw_info & 0x3ffff; 31817221Stef rp->cc = 0; 31917221Stef rp->flags = DBUF_OURS|DBUF_XMIT; 32017221Stef ifxp++; 32117221Stef } 32217565Skarels 32317565Skarels /* set up command queues */ 32417565Skarels sc->sc_qfreeh = sc->sc_qfreet 32517565Skarels = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = 32617565Skarels (struct dmc_command *)0; 32717565Skarels /* set up free command buffer list */ 32817565Skarels for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { 32917565Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 33017565Skarels } 33117565Skarels 33217221Stef /* base in */ 33317221Stef base = sc->sc_ubinfo & 0x3ffff; 33417565Skarels dmcload(sc, DMC_BASEI, base, (base>>2) & DMC_XMEM); 33517221Stef /* specify half duplex operation, flags tell if primary */ 33617221Stef /* or secondary station */ 33717221Stef if (ui->ui_flags == 0) 33827266Skarels /* use DDCMP mode in full duplex */ 33917565Skarels dmcload(sc, DMC_CNTLI, 0, 0); 34017221Stef else if (ui->ui_flags == 1) 34117565Skarels /* use MAINTENENCE mode */ 34217565Skarels dmcload(sc, DMC_CNTLI, 0, DMC_MAINT ); 34317221Stef else if (ui->ui_flags == 2) 34417221Stef /* use DDCMP half duplex as primary station */ 34517221Stef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX); 34617221Stef else if (ui->ui_flags == 3) 34717221Stef /* use DDCMP half duplex as secondary station */ 34817221Stef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC); 34917565Skarels 35017565Skarels /* enable operation done interrupts */ 35117565Skarels while ((addr->bsel2 & DMC_IEO) == 0) 35217565Skarels addr->bsel2 |= DMC_IEO; 35317565Skarels s = spl5(); 35417221Stef /* queue first NRCV buffers for DMC to fill */ 35517221Stef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 35617221Stef rp->flags |= DBUF_DMCS; 35717221Stef dmcload(sc, DMC_READ, rp->ubinfo, 35817565Skarels (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc)); 35917221Stef sc->sc_iused++; 36017221Stef } 36117565Skarels splx(s); 3625725Sroot } 3635725Sroot 3645725Sroot /* 3655725Sroot * Start output on interface. Get another datagram 3665725Sroot * to send from the interface queue and map it to 3675725Sroot * the interface before starting output. 36817221Stef * 36917221Stef * Must be called at spl 5 3705725Sroot */ 371*34529Skarels dmcstart(unit) 372*34529Skarels int unit; 3735725Sroot { 3745725Sroot register struct dmc_softc *sc = &dmc_softc[unit]; 3755725Sroot struct mbuf *m; 37617221Stef register struct dmcbufs *rp; 37717221Stef register int n; 3785725Sroot 3795725Sroot /* 38017221Stef * Dequeue up to NXMT requests and map them to the UNIBUS. 38117221Stef * If no more requests, or no dmc buffers available, just return. 3825725Sroot */ 38317221Stef n = 0; 38417221Stef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { 38517221Stef /* find an available buffer */ 38617565Skarels if ((rp->flags & DBUF_DMCS) == 0) { 38717221Stef IF_DEQUEUE(&sc->sc_if.if_snd, m); 38817221Stef if (m == 0) 38917221Stef return; 39017221Stef /* mark it dmcs */ 39117221Stef rp->flags |= (DBUF_DMCS); 39217221Stef /* 39317221Stef * Have request mapped to UNIBUS for transmission 39417221Stef * and start the output. 39517221Stef */ 39624796Skarels rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); 39717565Skarels rp->cc &= DMC_CCOUNT; 398*34529Skarels if (++sc->sc_oused == 1) 399*34529Skarels sc->sc_if.if_timer = dmc_timeout; 40017221Stef dmcload(sc, DMC_WRITE, rp->ubinfo, 40117221Stef rp->cc | ((rp->ubinfo>>2)&DMC_XMEM)); 40217221Stef } 40317221Stef n++; 40417221Stef } 4055725Sroot } 4065725Sroot 4075725Sroot /* 4085725Sroot * Utility routine to load the DMC device registers. 4095725Sroot */ 4105725Sroot dmcload(sc, type, w0, w1) 4115725Sroot register struct dmc_softc *sc; 4125725Sroot int type, w0, w1; 4135725Sroot { 4145725Sroot register struct dmcdevice *addr; 41517221Stef register int unit, sps; 41617221Stef register struct dmc_command *qp; 4175725Sroot 41817565Skarels unit = sc - dmc_softc; 4195725Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; 4205725Sroot sps = spl5(); 42117221Stef 42217221Stef /* grab a command buffer from the free list */ 42317221Stef if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0) 42417221Stef panic("dmc command queue overflow"); 42517221Stef DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); 42617221Stef 42717221Stef /* fill in requested info */ 42817221Stef qp->qp_cmd = (type | DMC_RQI); 42917221Stef qp->qp_ubaddr = w0; 43017221Stef qp->qp_cc = w1; 43117221Stef 43217221Stef if (sc->sc_qactive) { /* command in progress */ 43317221Stef if (type == DMC_READ) { 43417221Stef QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); 43517221Stef } else { 43617221Stef QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); 43717221Stef } 43817221Stef } else { /* command port free */ 43917221Stef sc->sc_qactive = qp; 44017221Stef addr->bsel0 = qp->qp_cmd; 4415725Sroot dmcrint(unit); 44217221Stef } 4435725Sroot splx(sps); 4445725Sroot } 4455725Sroot 4465725Sroot /* 4475725Sroot * DMC interface receiver interrupt. 4485725Sroot * Ready to accept another command, 4495725Sroot * pull one off the command queue. 4505725Sroot */ 4515725Sroot dmcrint(unit) 4525725Sroot int unit; 4535725Sroot { 4545725Sroot register struct dmc_softc *sc; 4555725Sroot register struct dmcdevice *addr; 45617221Stef register struct dmc_command *qp; 4575725Sroot register int n; 4585725Sroot 4595725Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; 4605725Sroot sc = &dmc_softc[unit]; 46117221Stef if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) { 46217565Skarels printf("dmc%d: dmcrint no command\n", unit); 46317221Stef return; 46417221Stef } 4655725Sroot while (addr->bsel0&DMC_RDYI) { 46617221Stef addr->sel4 = qp->qp_ubaddr; 46717221Stef addr->sel6 = qp->qp_cc; 4685725Sroot addr->bsel0 &= ~(DMC_IEI|DMC_RQI); 46917221Stef /* free command buffer */ 47017221Stef QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 47117221Stef while (addr->bsel0 & DMC_RDYI) { 47217221Stef /* 47317221Stef * Can't check for RDYO here 'cause 47417221Stef * this routine isn't reentrant! 47517221Stef */ 47617221Stef DELAY(5); 47717221Stef } 47817221Stef /* move on to next command */ 47917565Skarels if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0) 48017565Skarels break; /* all done */ 48117221Stef /* more commands to do, start the next one */ 48217221Stef qp = sc->sc_qactive; 48317221Stef DEQUEUE(sc->sc_qhead, sc->sc_qtail); 48417221Stef addr->bsel0 = qp->qp_cmd; 4855725Sroot n = RDYSCAN; 48617565Skarels while (n-- > 0) 48717565Skarels if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO)) 48817565Skarels break; 4895725Sroot } 49017221Stef if (sc->sc_qactive) { 49117221Stef addr->bsel0 |= DMC_IEI|DMC_RQI; 49217221Stef /* VMS does it twice !*$%@# */ 49317221Stef addr->bsel0 |= DMC_IEI|DMC_RQI; 49417221Stef } 49517565Skarels 4965725Sroot } 4975725Sroot 4985725Sroot /* 4995725Sroot * DMC interface transmitter interrupt. 50017221Stef * A transfer may have completed, check for errors. 5015725Sroot * If it was a read, notify appropriate protocol. 5025725Sroot * If it was a write, pull the next one off the queue. 5035725Sroot */ 5045725Sroot dmcxint(unit) 5055725Sroot int unit; 5065725Sroot { 5075725Sroot register struct dmc_softc *sc; 50813065Ssam register struct ifnet *ifp; 5095725Sroot struct uba_device *ui = dmcinfo[unit]; 5105725Sroot struct dmcdevice *addr; 5115725Sroot struct mbuf *m; 51217565Skarels struct ifqueue *inq; 51327266Skarels int arg, pkaddr, cmd, len, s; 51417221Stef register struct ifrw *ifrw; 51517221Stef register struct dmcbufs *rp; 51617565Skarels register struct ifxmt *ifxp; 51717565Skarels struct dmc_header *dh; 51817565Skarels int off, resid; 5195725Sroot 5205725Sroot addr = (struct dmcdevice *)ui->ui_addr; 52117221Stef sc = &dmc_softc[unit]; 52217221Stef ifp = &sc->sc_if; 52317221Stef 52417565Skarels while (addr->bsel2 & DMC_RDYO) { 5255725Sroot 52617565Skarels cmd = addr->bsel2 & 0xff; 52717565Skarels arg = addr->sel6 & 0xffff; 52817565Skarels /* reconstruct UNIBUS address of buffer returned to us */ 52917565Skarels pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff); 53017565Skarels /* release port */ 53117565Skarels addr->bsel2 &= ~DMC_RDYO; 53217565Skarels switch (cmd & 07) { 53317565Skarels 53417565Skarels case DMC_OUR: 53517565Skarels /* 53617565Skarels * A read has completed. 53717565Skarels * Pass packet to type specific 53817565Skarels * higher-level input routine. 53917565Skarels */ 54017565Skarels ifp->if_ipackets++; 54117565Skarels /* find location in dmcuba struct */ 54224796Skarels ifrw= &sc->sc_ifr[0]; 54317565Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 54417565Skarels if(rp->ubinfo == pkaddr) 54517565Skarels break; 54617565Skarels ifrw++; 54717565Skarels } 54817565Skarels if (rp >= &sc->sc_rbufs[NRCV]) 54917565Skarels panic("dmc rcv"); 55017565Skarels if ((rp->flags & DBUF_DMCS) == 0) 55117565Skarels printf("dmc%d: done unalloc rbuf\n", unit); 55217565Skarels 55317565Skarels len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header); 55417565Skarels if (len < 0 || len > DMCMTU) { 55517565Skarels ifp->if_ierrors++; 55617565Skarels printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n", 55717565Skarels unit, pkaddr, len); 55817565Skarels goto setup; 55917565Skarels } 56017565Skarels /* 56117565Skarels * Deal with trailer protocol: if type is trailer 56217565Skarels * get true type from first 16-bit word past data. 56317565Skarels * Remember that type was trailer by setting off. 56417565Skarels */ 56517565Skarels dh = (struct dmc_header *)ifrw->ifrw_addr; 56617565Skarels dh->dmc_type = ntohs((u_short)dh->dmc_type); 56717565Skarels #define dmcdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) 56817565Skarels if (dh->dmc_type >= DMC_TRAILER && 56917565Skarels dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) { 57017565Skarels off = (dh->dmc_type - DMC_TRAILER) * 512; 57117565Skarels if (off >= DMCMTU) 57217565Skarels goto setup; /* sanity */ 57317565Skarels dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *)); 57417565Skarels resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *))); 57517565Skarels if (off + resid > len) 57617565Skarels goto setup; /* sanity */ 57717565Skarels len = off + resid; 57817565Skarels } else 57917565Skarels off = 0; 58017565Skarels if (len == 0) 58117565Skarels goto setup; 58217565Skarels 58317565Skarels /* 58417565Skarels * Pull packet off interface. Off is nonzero if 58517565Skarels * packet has trailing header; dmc_get will then 58617565Skarels * force this header information to be at the front, 58717565Skarels * but we still have to drop the type and length 58817565Skarels * which are at the front of any trailer data. 58917565Skarels */ 59024796Skarels m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); 59117565Skarels if (m == 0) 59217565Skarels goto setup; 59317565Skarels if (off) { 59424796Skarels ifp = *(mtod(m, struct ifnet **)); 59517565Skarels m->m_off += 2 * sizeof (u_short); 59617565Skarels m->m_len -= 2 * sizeof (u_short); 59724796Skarels *(mtod(m, struct ifnet **)) = ifp; 59817565Skarels } 59917565Skarels switch (dh->dmc_type) { 60017565Skarels 6015725Sroot #ifdef INET 60217565Skarels case DMC_IPTYPE: 60317565Skarels schednetisr(NETISR_IP); 60417565Skarels inq = &ipintrq; 60517565Skarels break; 6065725Sroot #endif 60717565Skarels default: 60817565Skarels m_freem(m); 60917565Skarels goto setup; 61017565Skarels } 6115725Sroot 61227266Skarels s = splimp(); 61317565Skarels if (IF_QFULL(inq)) { 61417565Skarels IF_DROP(inq); 61517565Skarels m_freem(m); 61617565Skarels } else 61717565Skarels IF_ENQUEUE(inq, m); 61827266Skarels splx(s); 61917221Stef 62017565Skarels setup: 62117565Skarels /* is this needed? */ 62217565Skarels rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 6235725Sroot 62417565Skarels dmcload(sc, DMC_READ, rp->ubinfo, 62517565Skarels ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc); 62617565Skarels break; 6275725Sroot 62817565Skarels case DMC_OUX: 62917565Skarels /* 63017565Skarels * A write has completed, start another 63117565Skarels * transfer if there is more data to send. 63217565Skarels */ 63317565Skarels ifp->if_opackets++; 63417565Skarels /* find associated dmcbuf structure */ 63524796Skarels ifxp = &sc->sc_ifw[0]; 63617565Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 63717565Skarels if(rp->ubinfo == pkaddr) 63817565Skarels break; 63917565Skarels ifxp++; 64017565Skarels } 64117565Skarels if (rp >= &sc->sc_xbufs[NXMT]) { 64217565Skarels printf("dmc%d: bad packet address 0x%x\n", 64317565Skarels unit, pkaddr); 64417565Skarels break; 64517565Skarels } 64617565Skarels if ((rp->flags & DBUF_DMCS) == 0) 64717565Skarels printf("dmc%d: unallocated packet 0x%x\n", 64817565Skarels unit, pkaddr); 64917565Skarels /* mark buffer free */ 65024796Skarels if (ifxp->ifw_xtofree) { 65124796Skarels (void)m_freem(ifxp->ifw_xtofree); 65224796Skarels ifxp->ifw_xtofree = 0; 65317565Skarels } 65417565Skarels rp->flags &= ~DBUF_DMCS; 655*34529Skarels if (--sc->sc_oused == 0) 656*34529Skarels sc->sc_if.if_timer = 0; 657*34529Skarels else 658*34529Skarels sc->sc_if.if_timer = dmc_timeout; 659*34529Skarels if ((sc->sc_flag & DMC_ONLINE) == 0) { 660*34529Skarels extern int ifqmaxlen; 661*34529Skarels 662*34529Skarels /* 663*34529Skarels * We're on the air. 664*34529Skarels * Open the queue to the usual value. 665*34529Skarels */ 666*34529Skarels sc->sc_flag |= DMC_ONLINE; 667*34529Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen; 668*34529Skarels } 66917565Skarels break; 67017221Stef 67117565Skarels case DMC_CNTLO: 67217565Skarels arg &= DMC_CNTMASK; 67317565Skarels if (arg & DMC_FATAL) { 674*34529Skarels if (arg != DMC_START) 675*34529Skarels log(LOG_ERR, 676*34529Skarels "dmc%d: fatal error, flags=%b\n", 677*34529Skarels unit, arg, CNTLO_BITS); 67817565Skarels dmcrestart(unit); 67917565Skarels break; 68017565Skarels } 68117565Skarels /* ACCUMULATE STATISTICS */ 68217221Stef switch(arg) { 68317221Stef case DMC_NOBUFS: 68417565Skarels ifp->if_ierrors++; 68517565Skarels if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0) 68617565Skarels goto report; 68717565Skarels break; 68817221Stef case DMC_DISCONN: 68917565Skarels if ((sc->sc_disc++ % DMC_RPDSC) == 0) 69017565Skarels goto report; 69117565Skarels break; 69217221Stef case DMC_TIMEOUT: 69317565Skarels if ((sc->sc_timeo++ % DMC_RPTMO) == 0) 69417565Skarels goto report; 69517565Skarels break; 69617221Stef case DMC_DATACK: 69717565Skarels ifp->if_oerrors++; 69817565Skarels if ((sc->sc_datck++ % DMC_RPDCK) == 0) 69917565Skarels goto report; 70017565Skarels break; 70117221Stef default: 70217221Stef goto report; 70317221Stef } 70417221Stef break; 70517221Stef report: 70617565Skarels printd("dmc%d: soft error, flags=%b\n", unit, 70717565Skarels arg, CNTLO_BITS); 70817565Skarels if ((sc->sc_flag & DMC_RESTART) == 0) { 70917565Skarels /* 71017565Skarels * kill off the dmc to get things 71117565Skarels * going again by generating a 71217565Skarels * procedure error 71317565Skarels */ 71417565Skarels sc->sc_flag |= DMC_RESTART; 71517565Skarels arg = sc->sc_ubinfo & 0x3ffff; 71617565Skarels dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM); 71717565Skarels } 71817565Skarels break; 71917565Skarels 72017565Skarels default: 72117565Skarels printf("dmc%d: bad control %o\n", unit, cmd); 72217565Skarels break; 7235725Sroot } 7245725Sroot } 72517565Skarels dmcstart(unit); 72617221Stef return; 7275725Sroot } 7285725Sroot 7295725Sroot /* 7305725Sroot * DMC output routine. 73117565Skarels * Encapsulate a packet of type family for the dmc. 73217565Skarels * Use trailer local net encapsulation if enough data in first 73317565Skarels * packet leaves a multiple of 512 bytes of data in remainder. 7345725Sroot */ 73517565Skarels dmcoutput(ifp, m0, dst) 7365725Sroot register struct ifnet *ifp; 73717565Skarels register struct mbuf *m0; 7386334Ssam struct sockaddr *dst; 7395725Sroot { 74017565Skarels int type, error, s; 74117565Skarels register struct mbuf *m = m0; 74217565Skarels register struct dmc_header *dh; 74317565Skarels register int off; 7445725Sroot 745*34529Skarels if ((ifp->if_flags & IFF_UP) == 0) { 746*34529Skarels error = ENETDOWN; 747*34529Skarels goto bad; 748*34529Skarels } 749*34529Skarels 75017565Skarels switch (dst->sa_family) { 75117565Skarels #ifdef INET 75217565Skarels case AF_INET: 75317565Skarels off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 75417565Skarels if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 75517565Skarels if (off > 0 && (off & 0x1ff) == 0 && 75617565Skarels m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 75717565Skarels type = DMC_TRAILER + (off>>9); 75817565Skarels m->m_off -= 2 * sizeof (u_short); 75917565Skarels m->m_len += 2 * sizeof (u_short); 76017565Skarels *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE); 76117565Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 76217565Skarels goto gottrailertype; 76317565Skarels } 76417565Skarels type = DMC_IPTYPE; 76517565Skarels off = 0; 76617565Skarels goto gottype; 76717565Skarels #endif 76817565Skarels 76917565Skarels case AF_UNSPEC: 77017565Skarels dh = (struct dmc_header *)dst->sa_data; 77117565Skarels type = dh->dmc_type; 77217565Skarels goto gottype; 77317565Skarels 77417565Skarels default: 77517565Skarels printf("dmc%d: can't handle af%d\n", ifp->if_unit, 77617565Skarels dst->sa_family); 77717565Skarels error = EAFNOSUPPORT; 77817565Skarels goto bad; 7795725Sroot } 78017565Skarels 78117565Skarels gottrailertype: 78217565Skarels /* 78317565Skarels * Packet to be sent as a trailer; move first packet 78417565Skarels * (control information) to end of chain. 78517565Skarels */ 78617565Skarels while (m->m_next) 78717565Skarels m = m->m_next; 78817565Skarels m->m_next = m0; 78917565Skarels m = m0->m_next; 79017565Skarels m0->m_next = 0; 79117565Skarels m0 = m; 79217565Skarels 79317565Skarels gottype: 79417565Skarels /* 79517565Skarels * Add local network header 79617565Skarels * (there is space for a uba on a vax to step on) 79717565Skarels */ 79817565Skarels if (m->m_off > MMAXOFF || 79917565Skarels MMINOFF + sizeof(struct dmc_header) > m->m_off) { 80017565Skarels m = m_get(M_DONTWAIT, MT_HEADER); 80117565Skarels if (m == 0) { 80217565Skarels error = ENOBUFS; 80317565Skarels goto bad; 80417565Skarels } 80517565Skarels m->m_next = m0; 80617565Skarels m->m_off = MMINOFF; 80717565Skarels m->m_len = sizeof (struct dmc_header); 80817565Skarels } else { 80917565Skarels m->m_off -= sizeof (struct dmc_header); 81017565Skarels m->m_len += sizeof (struct dmc_header); 81117565Skarels } 81217565Skarels dh = mtod(m, struct dmc_header *); 81317565Skarels dh->dmc_type = htons((u_short)type); 81417565Skarels 81517565Skarels /* 81617565Skarels * Queue message on interface, and start output if interface 81717565Skarels * not yet active. 81817565Skarels */ 81917565Skarels s = splimp(); 8206207Swnj if (IF_QFULL(&ifp->if_snd)) { 8216207Swnj IF_DROP(&ifp->if_snd); 8226334Ssam m_freem(m); 8236207Swnj splx(s); 8246502Ssam return (ENOBUFS); 8256207Swnj } 8265725Sroot IF_ENQUEUE(&ifp->if_snd, m); 82717221Stef dmcstart(ifp->if_unit); 8285725Sroot splx(s); 8296502Ssam return (0); 83017565Skarels 83117565Skarels bad: 83217565Skarels m_freem(m0); 83317565Skarels return (error); 8345725Sroot } 83513061Ssam 83617565Skarels 83713061Ssam /* 83813061Ssam * Process an ioctl request. 83913061Ssam */ 84024796Skarels /* ARGSUSED */ 84113061Ssam dmcioctl(ifp, cmd, data) 84213061Ssam register struct ifnet *ifp; 84313061Ssam int cmd; 84413061Ssam caddr_t data; 84513061Ssam { 84613061Ssam int s = splimp(), error = 0; 84727266Skarels register struct dmc_softc *sc = &dmc_softc[ifp->if_unit]; 84813061Ssam 84913061Ssam switch (cmd) { 85013061Ssam 85113061Ssam case SIOCSIFADDR: 85217221Stef ifp->if_flags |= IFF_UP; 85319862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 85419862Skarels dmcinit(ifp->if_unit); 85513061Ssam break; 85613061Ssam 85713061Ssam case SIOCSIFDSTADDR: 85819862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 85919862Skarels dmcinit(ifp->if_unit); 86013061Ssam break; 86117221Stef 86227266Skarels case SIOCSIFFLAGS: 86327266Skarels if ((ifp->if_flags & IFF_UP) == 0 && 864*34529Skarels sc->sc_flag & DMC_RUNNING) 865*34529Skarels dmcdown(ifp->if_unit); 866*34529Skarels else if (ifp->if_flags & IFF_UP && 86727266Skarels (sc->sc_flag & DMC_RUNNING) == 0) 86827266Skarels dmcrestart(ifp->if_unit); 86927266Skarels break; 87027266Skarels 87113061Ssam default: 87213061Ssam error = EINVAL; 87313061Ssam } 87413061Ssam splx(s); 87513061Ssam return (error); 87613061Ssam } 87717221Stef 87817221Stef /* 87917565Skarels * Restart after a fatal error. 88017565Skarels * Clear device and reinitialize. 88117565Skarels */ 88217565Skarels dmcrestart(unit) 88317565Skarels int unit; 88417565Skarels { 88517565Skarels register struct dmc_softc *sc = &dmc_softc[unit]; 88617565Skarels register struct dmcdevice *addr; 88717565Skarels register int i; 888*34529Skarels int s; 88917565Skarels 89017565Skarels #ifdef DEBUG 89117565Skarels /* dump base table */ 89217565Skarels printf("dmc%d base table:\n", unit); 89317565Skarels for (i = 0; i < sizeof (struct dmc_base); i++) 89417565Skarels printf("%o\n" ,dmc_base[unit].d_base[i]); 89513085Ssam #endif 896*34529Skarels 897*34529Skarels dmcdown(unit); 898*34529Skarels 89917565Skarels /* 90017565Skarels * Let the DMR finish the MCLR. At 1 Mbit, it should do so 90117565Skarels * in about a max of 6.4 milliseconds with diagnostics enabled. 90217565Skarels */ 903*34529Skarels addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr); 90417565Skarels for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 90517565Skarels ; 90617565Skarels /* Did the timer expire or did the DMR finish? */ 90717565Skarels if ((addr->bsel1 & DMC_RUN) == 0) { 90826282Skarels log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit); 90917565Skarels return; 91017565Skarels } 91117565Skarels 912*34529Skarels /* restart DMC */ 913*34529Skarels dmcinit(unit); 914*34529Skarels sc->sc_flag &= ~DMC_RESTART; 915*34529Skarels s = spl5(); 916*34529Skarels dmcstart(unit); 917*34529Skarels splx(s); 918*34529Skarels sc->sc_if.if_collisions++; /* why not? */ 919*34529Skarels } 920*34529Skarels 921*34529Skarels /* 922*34529Skarels * Reset a device and mark down. 923*34529Skarels * Flush output queue and drop queue limit. 924*34529Skarels */ 925*34529Skarels dmcdown(unit) 926*34529Skarels int unit; 927*34529Skarels { 928*34529Skarels register struct dmc_softc *sc = &dmc_softc[unit]; 929*34529Skarels register struct ifxmt *ifxp; 930*34529Skarels 931*34529Skarels ((struct dmcdevice *)(dmcinfo[unit]->ui_addr))->bsel1 = DMC_MCLR; 932*34529Skarels sc->sc_flag &= ~(DMC_RUNNING | DMC_ONLINE); 933*34529Skarels 93424796Skarels for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { 93524796Skarels if (ifxp->ifw_xtofree) { 93624796Skarels (void) m_freem(ifxp->ifw_xtofree); 93724796Skarels ifxp->ifw_xtofree = 0; 93817565Skarels } 93917565Skarels } 940*34529Skarels if_qflush(&sc->sc_if.if_snd); 94117565Skarels } 94217565Skarels 94317565Skarels /* 944*34529Skarels * Watchdog timeout to see that transmitted packets don't 945*34529Skarels * lose interrupts. The device has to be online (the first 946*34529Skarels * transmission may block until the other side comes up). 94717565Skarels */ 948*34529Skarels dmctimeout(unit) 949*34529Skarels int unit; 95017565Skarels { 95117565Skarels register struct dmc_softc *sc; 95217565Skarels struct dmcdevice *addr; 95317565Skarels 954*34529Skarels sc = &dmc_softc[unit]; 955*34529Skarels if (sc->sc_flag & DMC_ONLINE) { 956*34529Skarels addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr); 957*34529Skarels log(LOG_ERR, "dmc%d: output timeout, bsel0=%b bsel2=%b\n", 958*34529Skarels unit, addr->bsel0 & 0xff, DMC0BITS, 959*34529Skarels addr->bsel2 & 0xff, DMC2BITS); 960*34529Skarels dmcrestart(unit); 96117565Skarels } 96217565Skarels } 96317565Skarels #endif 964