123286Smckusick /* 223286Smckusick * Copyright (c) 1982 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*26933Skarels * @(#)if_dmc.c 6.11 (Berkeley) 03/24/86 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" 4517565Skarels #include "../netinet/ip.h" 4624796Skarels #endif 478460Sroot 488460Sroot #include "../vax/cpu.h" 498460Sroot #include "../vax/mtpr.h" 5017111Sbloom #include "if_uba.h" 5117111Sbloom #include "if_dmc.h" 528460Sroot #include "../vaxuba/ubareg.h" 538460Sroot #include "../vaxuba/ubavar.h" 545725Sroot 5517565Skarels #include "../h/time.h" 5617565Skarels #include "../h/kernel.h" 5717565Skarels 5817565Skarels int dmctimer; /* timer started? */ 5917565Skarels int dmc_timeout = 8; /* timeout value */ 6017565Skarels int dmcwatch(); 6117565Skarels 625725Sroot /* 635725Sroot * Driver information for auto-configuration stuff. 645725Sroot */ 6513061Ssam int dmcprobe(), dmcattach(), dmcinit(), dmcioctl(); 6613061Ssam int dmcoutput(), dmcreset(); 675725Sroot struct uba_device *dmcinfo[NDMC]; 685725Sroot u_short dmcstd[] = { 0 }; 695725Sroot struct uba_driver dmcdriver = 705725Sroot { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo }; 715725Sroot 7217221Stef #define NRCV 7 7317565Skarels #define NXMT 3 7424796Skarels #define NCMDS (NRCV+NXMT+4) /* size of command queue */ 7517221Stef 7617565Skarels #define printd if(dmcdebug)printf 7717565Skarels int dmcdebug = 0; 7817565Skarels 7917221Stef /* error reporting intervals */ 8017221Stef #define DMC_RPNBFS 50 8117221Stef #define DMC_RPDSC 1 8217565Skarels #define DMC_RPTMO 10 8317565Skarels #define DMC_RPDCK 10 8417221Stef 8517221Stef struct dmc_command { 8617221Stef char qp_cmd; /* command */ 8717221Stef short qp_ubaddr; /* buffer address */ 8817221Stef short qp_cc; /* character count || XMEM */ 8917221Stef struct dmc_command *qp_next; /* next command on queue */ 9017221Stef }; 9117221Stef 9217221Stef struct dmcbufs { 9317221Stef int ubinfo; /* from uballoc */ 9417221Stef short cc; /* buffer size */ 9517221Stef short flags; /* access control */ 9617221Stef }; 9717221Stef #define DBUF_OURS 0 /* buffer is available */ 9817221Stef #define DBUF_DMCS 1 /* buffer claimed by somebody */ 9917221Stef #define DBUF_XMIT 4 /* transmit buffer */ 10017565Skarels #define DBUF_RCV 8 /* receive buffer */ 10117221Stef 10217221Stef 10317221Stef /* 1045725Sroot * DMC software status per interface. 1055725Sroot * 1065725Sroot * Each interface is referenced by a network interface structure, 1075725Sroot * sc_if, which the routing code uses to locate the interface. 1085725Sroot * This structure contains the output queue for the interface, its address, ... 10917221Stef * We also have, for each interface, a set of 7 UBA interface structures 11017221Stef * for each, which 11117221Stef * contain information about the UNIBUS resources held by the interface: 1125725Sroot * map registers, buffered data paths, etc. Information is cached in this 1135725Sroot * structure for use by the if_uba.c routines in running the interface 1145725Sroot * efficiently. 1155725Sroot */ 1165725Sroot struct dmc_softc { 1175725Sroot struct ifnet sc_if; /* network-visible interface */ 11817565Skarels struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */ 11917221Stef struct dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */ 12024796Skarels struct ifubinfo sc_ifuba; /* UNIBUS resources */ 12124796Skarels struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ 12224796Skarels struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ 123*26933Skarels short sc_oused; /* output buffers currently in use */ 124*26933Skarels short sc_iused; /* input buffers given to DMC */ 125*26933Skarels short sc_flag; /* flags */ 126*26933Skarels int sc_nticks; /* seconds since last interrupt */ 1275725Sroot int sc_ubinfo; /* UBA mapping info for base table */ 12817221Stef int sc_errors[4]; /* non-fatal error counters */ 12917221Stef #define sc_datck sc_errors[0] 13017221Stef #define sc_timeo sc_errors[1] 13117221Stef #define sc_nobuf sc_errors[2] 13217221Stef #define sc_disc sc_errors[3] 13317221Stef /* command queue stuff */ 13417565Skarels struct dmc_command sc_cmdbuf[NCMDS]; 13517221Stef struct dmc_command *sc_qhead; /* head of command queue */ 13617221Stef struct dmc_command *sc_qtail; /* tail of command queue */ 13717221Stef struct dmc_command *sc_qactive; /* command in progress */ 13817221Stef struct dmc_command *sc_qfreeh; /* head of list of free cmd buffers */ 13917221Stef struct dmc_command *sc_qfreet; /* tail of list of free cmd buffers */ 14017221Stef /* end command queue stuff */ 1415725Sroot } dmc_softc[NDMC]; 1425725Sroot 1435725Sroot /* flags */ 14417565Skarels #define DMC_ALLOC 01 /* unibus resources allocated */ 14517565Skarels #define DMC_BMAPPED 02 /* base table mapped */ 14617565Skarels #define DMC_RESTART 04 /* software restart in progress */ 14717565Skarels #define DMC_ACTIVE 08 /* device active */ 1485725Sroot 14917565Skarels struct dmc_base { 15017565Skarels short d_base[128]; /* DMC base table */ 1515725Sroot } dmc_base[NDMC]; 1525725Sroot 15317221Stef /* queue manipulation macros */ 15417221Stef #define QUEUE_AT_HEAD(qp, head, tail) \ 15517221Stef (qp)->qp_next = (head); \ 15617221Stef (head) = (qp); \ 15717221Stef if ((tail) == (struct dmc_command *) 0) \ 15817221Stef (tail) = (head) 1595725Sroot 16017221Stef #define QUEUE_AT_TAIL(qp, head, tail) \ 16117221Stef if ((tail)) \ 16217221Stef (tail)->qp_next = (qp); \ 16317221Stef else \ 16417221Stef (head) = (qp); \ 16517221Stef (qp)->qp_next = (struct dmc_command *) 0; \ 16617221Stef (tail) = (qp) 16717221Stef 16817221Stef #define DEQUEUE(head, tail) \ 16917221Stef (head) = (head)->qp_next;\ 17017221Stef if ((head) == (struct dmc_command *) 0)\ 17117221Stef (tail) = (head) 17217221Stef 1735725Sroot dmcprobe(reg) 1745725Sroot caddr_t reg; 1755725Sroot { 1765725Sroot register int br, cvec; 1775725Sroot register struct dmcdevice *addr = (struct dmcdevice *)reg; 1785725Sroot register int i; 1795725Sroot 1805725Sroot #ifdef lint 1815725Sroot br = 0; cvec = br; br = cvec; 1825725Sroot dmcrint(0); dmcxint(0); 1835725Sroot #endif 1845725Sroot addr->bsel1 = DMC_MCLR; 1855725Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 1865725Sroot ; 18717565Skarels if ((addr->bsel1 & DMC_RUN) == 0) { 18817565Skarels printf("dmcprobe: can't start device\n" ); 1896334Ssam return (0); 19017565Skarels } 1915725Sroot addr->bsel0 = DMC_RQI|DMC_IEI; 19217565Skarels /* let's be paranoid */ 19317565Skarels addr->bsel0 |= DMC_RQI|DMC_IEI; 19417565Skarels DELAY(1000000); 1955725Sroot addr->bsel1 = DMC_MCLR; 1965725Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 1975725Sroot ; 1986334Ssam return (1); 1995725Sroot } 2005725Sroot 2015725Sroot /* 2025725Sroot * Interface exists: make available by filling in network interface 2035725Sroot * record. System will initialize the interface when it is ready 2045725Sroot * to accept packets. 2055725Sroot */ 2065725Sroot dmcattach(ui) 2075725Sroot register struct uba_device *ui; 2085725Sroot { 2095725Sroot register struct dmc_softc *sc = &dmc_softc[ui->ui_unit]; 2105725Sroot 2115725Sroot sc->sc_if.if_unit = ui->ui_unit; 2125725Sroot sc->sc_if.if_name = "dmc"; 2135725Sroot sc->sc_if.if_mtu = DMCMTU; 2145725Sroot sc->sc_if.if_init = dmcinit; 2155725Sroot sc->sc_if.if_output = dmcoutput; 21613061Ssam sc->sc_if.if_ioctl = dmcioctl; 2178976Sroot sc->sc_if.if_reset = dmcreset; 21817221Stef sc->sc_if.if_flags = IFF_POINTOPOINT; 21924796Skarels sc->sc_ifuba.iff_flags = UBA_CANTWAIT; 22017221Stef 22117565Skarels if (dmctimer == 0) { 22217565Skarels dmctimer = 1; 22317565Skarels timeout(dmcwatch, (caddr_t) 0, hz); 22417221Stef } 22524796Skarels if_attach(&sc->sc_if); 2265725Sroot } 2275725Sroot 2285725Sroot /* 2295725Sroot * Reset of interface after UNIBUS reset. 23019862Skarels * If interface is on specified UBA, reset its state. 2315725Sroot */ 2325725Sroot dmcreset(unit, uban) 2335725Sroot int unit, uban; 2345725Sroot { 2355725Sroot register struct uba_device *ui; 23617221Stef register struct dmc_softc *sc = &dmc_softc[unit]; 2375725Sroot 2385725Sroot if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 || 2395725Sroot ui->ui_ubanum != uban) 2405725Sroot return; 2415725Sroot printf(" dmc%d", unit); 24217565Skarels sc->sc_flag = 0; 24319862Skarels sc->sc_if.if_flags &= ~IFF_RUNNING; 2445725Sroot dmcinit(unit); 2455725Sroot } 2465725Sroot 2475725Sroot /* 2485725Sroot * Initialization of interface; reinitialize UNIBUS usage. 2495725Sroot */ 2505725Sroot dmcinit(unit) 2515725Sroot int unit; 2525725Sroot { 2535725Sroot register struct dmc_softc *sc = &dmc_softc[unit]; 2545725Sroot register struct uba_device *ui = dmcinfo[unit]; 2555725Sroot register struct dmcdevice *addr; 25613061Ssam register struct ifnet *ifp = &sc->sc_if; 25717221Stef register struct ifrw *ifrw; 25817221Stef register struct ifxmt *ifxp; 25917221Stef register struct dmcbufs *rp; 26017565Skarels register struct dmc_command *qp; 26119862Skarels struct ifaddr *ifa; 26217221Stef int base; 26317565Skarels int s; 2645725Sroot 26517221Stef addr = (struct dmcdevice *)ui->ui_addr; 26617221Stef 26719862Skarels /* 26819862Skarels * Check to see that an address has been set 26919862Skarels * (both local and destination for an address family). 27019862Skarels */ 27119862Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 27219862Skarels if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) 27319862Skarels break; 27419862Skarels if (ifa == (struct ifaddr *) 0) 2755725Sroot return; 27617221Stef 27717221Stef if ((addr->bsel1&DMC_RUN) == 0) { 27817221Stef printf("dmcinit: DMC not running\n"); 27919862Skarels ifp->if_flags &= ~IFF_UP; 28017221Stef return; 28117221Stef } 28217221Stef /* map base table */ 28317565Skarels if ((sc->sc_flag & DMC_BMAPPED) == 0) { 28417221Stef sc->sc_ubinfo = uballoc(ui->ui_ubanum, 28517221Stef (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0); 28617221Stef sc->sc_flag |= DMC_BMAPPED; 28717221Stef } 28817221Stef /* initialize UNIBUS resources */ 28917221Stef sc->sc_iused = sc->sc_oused = 0; 29019862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 29124796Skarels if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum, 29224796Skarels sizeof(struct dmc_header), (int)btoc(DMCMTU), 29324796Skarels sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) { 29419862Skarels printf("dmc%d: can't allocate uba resources\n", unit); 29513061Ssam ifp->if_flags &= ~IFF_UP; 29613061Ssam return; 29713061Ssam } 29819862Skarels ifp->if_flags |= IFF_RUNNING; 2995725Sroot } 30017221Stef 30117221Stef /* initialize buffer pool */ 30217565Skarels /* receives */ 30324796Skarels ifrw = &sc->sc_ifr[0]; 30417221Stef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 30517221Stef rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 30617565Skarels rp->cc = DMCMTU + sizeof (struct dmc_header); 30717221Stef rp->flags = DBUF_OURS|DBUF_RCV; 30817221Stef ifrw++; 3096363Ssam } 31017221Stef /* transmits */ 31124796Skarels ifxp = &sc->sc_ifw[0]; 31217221Stef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 31324796Skarels rp->ubinfo = ifxp->ifw_info & 0x3ffff; 31417221Stef rp->cc = 0; 31517221Stef rp->flags = DBUF_OURS|DBUF_XMIT; 31617221Stef ifxp++; 31717221Stef } 31817565Skarels 31917565Skarels /* set up command queues */ 32017565Skarels sc->sc_qfreeh = sc->sc_qfreet 32117565Skarels = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = 32217565Skarels (struct dmc_command *)0; 32317565Skarels /* set up free command buffer list */ 32417565Skarels for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { 32517565Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 32617565Skarels } 32717565Skarels 32817221Stef /* base in */ 32917221Stef base = sc->sc_ubinfo & 0x3ffff; 33017565Skarels dmcload(sc, DMC_BASEI, base, (base>>2) & DMC_XMEM); 33117221Stef /* specify half duplex operation, flags tell if primary */ 33217221Stef /* or secondary station */ 33317221Stef if (ui->ui_flags == 0) 33417565Skarels /* use DDMCP mode in full duplex */ 33517565Skarels dmcload(sc, DMC_CNTLI, 0, 0); 33617221Stef else if (ui->ui_flags == 1) 33717565Skarels /* use MAINTENENCE mode */ 33817565Skarels dmcload(sc, DMC_CNTLI, 0, DMC_MAINT ); 33917221Stef else if (ui->ui_flags == 2) 34017221Stef /* use DDCMP half duplex as primary station */ 34117221Stef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX); 34217221Stef else if (ui->ui_flags == 3) 34317221Stef /* use DDCMP half duplex as secondary station */ 34417221Stef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC); 34517565Skarels 34617565Skarels /* enable operation done interrupts */ 34717565Skarels sc->sc_flag &= ~DMC_ACTIVE; 34817565Skarels while ((addr->bsel2 & DMC_IEO) == 0) 34917565Skarels addr->bsel2 |= DMC_IEO; 35017565Skarels s = spl5(); 35117221Stef /* queue first NRCV buffers for DMC to fill */ 35217221Stef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 35317221Stef rp->flags |= DBUF_DMCS; 35417221Stef dmcload(sc, DMC_READ, rp->ubinfo, 35517565Skarels (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc)); 35617221Stef sc->sc_iused++; 35717221Stef } 35817565Skarels splx(s); 3595725Sroot } 3605725Sroot 3615725Sroot /* 3625725Sroot * Start output on interface. Get another datagram 3635725Sroot * to send from the interface queue and map it to 3645725Sroot * the interface before starting output. 36517221Stef * 36617221Stef * Must be called at spl 5 3675725Sroot */ 3685725Sroot dmcstart(dev) 3695725Sroot dev_t dev; 3705725Sroot { 3715725Sroot int unit = minor(dev); 3725725Sroot register struct dmc_softc *sc = &dmc_softc[unit]; 3735725Sroot struct mbuf *m; 37417221Stef register struct dmcbufs *rp; 37517221Stef register int n; 3765725Sroot 3775725Sroot /* 37817221Stef * Dequeue up to NXMT requests and map them to the UNIBUS. 37917221Stef * If no more requests, or no dmc buffers available, just return. 3805725Sroot */ 38117221Stef n = 0; 38217221Stef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { 38317221Stef /* find an available buffer */ 38417565Skarels if ((rp->flags & DBUF_DMCS) == 0) { 38517221Stef IF_DEQUEUE(&sc->sc_if.if_snd, m); 38617221Stef if (m == 0) 38717221Stef return; 38817221Stef /* mark it dmcs */ 38917221Stef rp->flags |= (DBUF_DMCS); 39017221Stef /* 39117221Stef * Have request mapped to UNIBUS for transmission 39217221Stef * and start the output. 39317221Stef */ 39424796Skarels rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); 39517565Skarels rp->cc &= DMC_CCOUNT; 39617221Stef sc->sc_oused++; 39717221Stef dmcload(sc, DMC_WRITE, rp->ubinfo, 39817221Stef rp->cc | ((rp->ubinfo>>2)&DMC_XMEM)); 39917221Stef } 40017221Stef n++; 40117221Stef } 4025725Sroot } 4035725Sroot 4045725Sroot /* 4055725Sroot * Utility routine to load the DMC device registers. 4065725Sroot */ 4075725Sroot dmcload(sc, type, w0, w1) 4085725Sroot register struct dmc_softc *sc; 4095725Sroot int type, w0, w1; 4105725Sroot { 4115725Sroot register struct dmcdevice *addr; 41217221Stef register int unit, sps; 41317221Stef register struct dmc_command *qp; 4145725Sroot 41517565Skarels unit = sc - dmc_softc; 4165725Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; 4175725Sroot sps = spl5(); 41817221Stef 41917221Stef /* grab a command buffer from the free list */ 42017221Stef if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0) 42117221Stef panic("dmc command queue overflow"); 42217221Stef DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); 42317221Stef 42417221Stef /* fill in requested info */ 42517221Stef qp->qp_cmd = (type | DMC_RQI); 42617221Stef qp->qp_ubaddr = w0; 42717221Stef qp->qp_cc = w1; 42817221Stef 42917221Stef if (sc->sc_qactive) { /* command in progress */ 43017221Stef if (type == DMC_READ) { 43117221Stef QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); 43217221Stef } else { 43317221Stef QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); 43417221Stef } 43517221Stef } else { /* command port free */ 43617221Stef sc->sc_qactive = qp; 43717221Stef addr->bsel0 = qp->qp_cmd; 4385725Sroot dmcrint(unit); 43917221Stef } 4405725Sroot splx(sps); 4415725Sroot } 4425725Sroot 4435725Sroot /* 4445725Sroot * DMC interface receiver interrupt. 4455725Sroot * Ready to accept another command, 4465725Sroot * pull one off the command queue. 4475725Sroot */ 4485725Sroot dmcrint(unit) 4495725Sroot int unit; 4505725Sroot { 4515725Sroot register struct dmc_softc *sc; 4525725Sroot register struct dmcdevice *addr; 45317221Stef register struct dmc_command *qp; 4545725Sroot register int n; 4555725Sroot 4565725Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; 4575725Sroot sc = &dmc_softc[unit]; 45817221Stef if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) { 45917565Skarels printf("dmc%d: dmcrint no command\n", unit); 46017221Stef return; 46117221Stef } 4625725Sroot while (addr->bsel0&DMC_RDYI) { 46317221Stef addr->sel4 = qp->qp_ubaddr; 46417221Stef addr->sel6 = qp->qp_cc; 4655725Sroot addr->bsel0 &= ~(DMC_IEI|DMC_RQI); 46617221Stef /* free command buffer */ 46717221Stef QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 46817221Stef while (addr->bsel0 & DMC_RDYI) { 46917221Stef /* 47017221Stef * Can't check for RDYO here 'cause 47117221Stef * this routine isn't reentrant! 47217221Stef */ 47317221Stef DELAY(5); 47417221Stef } 47517221Stef /* move on to next command */ 47617565Skarels if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0) 47717565Skarels break; /* all done */ 47817221Stef /* more commands to do, start the next one */ 47917221Stef qp = sc->sc_qactive; 48017221Stef DEQUEUE(sc->sc_qhead, sc->sc_qtail); 48117221Stef addr->bsel0 = qp->qp_cmd; 4825725Sroot n = RDYSCAN; 48317565Skarels while (n-- > 0) 48417565Skarels if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO)) 48517565Skarels break; 4865725Sroot } 48717221Stef if (sc->sc_qactive) { 48817221Stef addr->bsel0 |= DMC_IEI|DMC_RQI; 48917221Stef /* VMS does it twice !*$%@# */ 49017221Stef addr->bsel0 |= DMC_IEI|DMC_RQI; 49117221Stef } 49217565Skarels 4935725Sroot } 4945725Sroot 4955725Sroot /* 4965725Sroot * DMC interface transmitter interrupt. 49717221Stef * A transfer may have completed, check for errors. 4985725Sroot * If it was a read, notify appropriate protocol. 4995725Sroot * If it was a write, pull the next one off the queue. 5005725Sroot */ 5015725Sroot dmcxint(unit) 5025725Sroot int unit; 5035725Sroot { 5045725Sroot register struct dmc_softc *sc; 50513065Ssam register struct ifnet *ifp; 5065725Sroot struct uba_device *ui = dmcinfo[unit]; 5075725Sroot struct dmcdevice *addr; 5085725Sroot struct mbuf *m; 50917565Skarels struct ifqueue *inq; 51017221Stef int arg, pkaddr, cmd, len; 51117221Stef register struct ifrw *ifrw; 51217221Stef register struct dmcbufs *rp; 51317565Skarels register struct ifxmt *ifxp; 51417565Skarels struct dmc_header *dh; 51517565Skarels int off, resid; 5165725Sroot 5175725Sroot addr = (struct dmcdevice *)ui->ui_addr; 51817221Stef sc = &dmc_softc[unit]; 51917221Stef ifp = &sc->sc_if; 52017221Stef 52117565Skarels while (addr->bsel2 & DMC_RDYO) { 5225725Sroot 52317565Skarels cmd = addr->bsel2 & 0xff; 52417565Skarels arg = addr->sel6 & 0xffff; 52517565Skarels /* reconstruct UNIBUS address of buffer returned to us */ 52617565Skarels pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff); 52717565Skarels /* release port */ 52817565Skarels addr->bsel2 &= ~DMC_RDYO; 52917565Skarels switch (cmd & 07) { 53017565Skarels 53117565Skarels case DMC_OUR: 53217565Skarels /* 53317565Skarels * A read has completed. 53417565Skarels * Pass packet to type specific 53517565Skarels * higher-level input routine. 53617565Skarels */ 53717565Skarels ifp->if_ipackets++; 53817565Skarels /* find location in dmcuba struct */ 53924796Skarels ifrw= &sc->sc_ifr[0]; 54017565Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 54117565Skarels if(rp->ubinfo == pkaddr) 54217565Skarels break; 54317565Skarels ifrw++; 54417565Skarels } 54517565Skarels if (rp >= &sc->sc_rbufs[NRCV]) 54617565Skarels panic("dmc rcv"); 54717565Skarels if ((rp->flags & DBUF_DMCS) == 0) 54817565Skarels printf("dmc%d: done unalloc rbuf\n", unit); 54917565Skarels 55017565Skarels len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header); 55117565Skarels if (len < 0 || len > DMCMTU) { 55217565Skarels ifp->if_ierrors++; 55317565Skarels printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n", 55417565Skarels unit, pkaddr, len); 55517565Skarels goto setup; 55617565Skarels } 55717565Skarels /* 55817565Skarels * Deal with trailer protocol: if type is trailer 55917565Skarels * get true type from first 16-bit word past data. 56017565Skarels * Remember that type was trailer by setting off. 56117565Skarels */ 56217565Skarels dh = (struct dmc_header *)ifrw->ifrw_addr; 56317565Skarels dh->dmc_type = ntohs((u_short)dh->dmc_type); 56417565Skarels #define dmcdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) 56517565Skarels if (dh->dmc_type >= DMC_TRAILER && 56617565Skarels dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) { 56717565Skarels off = (dh->dmc_type - DMC_TRAILER) * 512; 56817565Skarels if (off >= DMCMTU) 56917565Skarels goto setup; /* sanity */ 57017565Skarels dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *)); 57117565Skarels resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *))); 57217565Skarels if (off + resid > len) 57317565Skarels goto setup; /* sanity */ 57417565Skarels len = off + resid; 57517565Skarels } else 57617565Skarels off = 0; 57717565Skarels if (len == 0) 57817565Skarels goto setup; 57917565Skarels 58017565Skarels /* 58117565Skarels * Pull packet off interface. Off is nonzero if 58217565Skarels * packet has trailing header; dmc_get will then 58317565Skarels * force this header information to be at the front, 58417565Skarels * but we still have to drop the type and length 58517565Skarels * which are at the front of any trailer data. 58617565Skarels */ 58724796Skarels m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); 58817565Skarels if (m == 0) 58917565Skarels goto setup; 59017565Skarels if (off) { 59124796Skarels ifp = *(mtod(m, struct ifnet **)); 59217565Skarels m->m_off += 2 * sizeof (u_short); 59317565Skarels m->m_len -= 2 * sizeof (u_short); 59424796Skarels *(mtod(m, struct ifnet **)) = ifp; 59517565Skarels } 59617565Skarels switch (dh->dmc_type) { 59717565Skarels 5985725Sroot #ifdef INET 59917565Skarels case DMC_IPTYPE: 60017565Skarels schednetisr(NETISR_IP); 60117565Skarels inq = &ipintrq; 60217565Skarels break; 6035725Sroot #endif 60417565Skarels default: 60517565Skarels m_freem(m); 60617565Skarels goto setup; 60717565Skarels } 6085725Sroot 60917565Skarels if (IF_QFULL(inq)) { 61017565Skarels IF_DROP(inq); 61117565Skarels m_freem(m); 61217565Skarels } else 61317565Skarels IF_ENQUEUE(inq, m); 61417221Stef 61517565Skarels setup: 61617565Skarels /* is this needed? */ 61717565Skarels rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 6185725Sroot 61917565Skarels dmcload(sc, DMC_READ, rp->ubinfo, 62017565Skarels ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc); 62117565Skarels break; 6225725Sroot 62317565Skarels case DMC_OUX: 62417565Skarels /* 62517565Skarels * A write has completed, start another 62617565Skarels * transfer if there is more data to send. 62717565Skarels */ 62817565Skarels ifp->if_opackets++; 62917565Skarels /* find associated dmcbuf structure */ 63024796Skarels ifxp = &sc->sc_ifw[0]; 63117565Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 63217565Skarels if(rp->ubinfo == pkaddr) 63317565Skarels break; 63417565Skarels ifxp++; 63517565Skarels } 63617565Skarels if (rp >= &sc->sc_xbufs[NXMT]) { 63717565Skarels printf("dmc%d: bad packet address 0x%x\n", 63817565Skarels unit, pkaddr); 63917565Skarels break; 64017565Skarels } 64117565Skarels if ((rp->flags & DBUF_DMCS) == 0) 64217565Skarels printf("dmc%d: unallocated packet 0x%x\n", 64317565Skarels unit, pkaddr); 64417565Skarels /* mark buffer free */ 64524796Skarels if (ifxp->ifw_xtofree) { 64624796Skarels (void)m_freem(ifxp->ifw_xtofree); 64724796Skarels ifxp->ifw_xtofree = 0; 64817565Skarels } 64917565Skarels rp->flags &= ~DBUF_DMCS; 65017565Skarels sc->sc_oused--; 65117565Skarels sc->sc_nticks = 0; 65217565Skarels sc->sc_flag |= DMC_ACTIVE; 65317565Skarels break; 65417221Stef 65517565Skarels case DMC_CNTLO: 65617565Skarels arg &= DMC_CNTMASK; 65717565Skarels if (arg & DMC_FATAL) { 65826282Skarels log(LOG_ERR, "dmc%d: fatal error, flags=%b\n", 65917565Skarels unit, arg, CNTLO_BITS); 66017565Skarels dmcrestart(unit); 66117565Skarels break; 66217565Skarels } 66317565Skarels /* ACCUMULATE STATISTICS */ 66417221Stef switch(arg) { 66517221Stef case DMC_NOBUFS: 66617565Skarels ifp->if_ierrors++; 66717565Skarels if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0) 66817565Skarels goto report; 66917565Skarels break; 67017221Stef case DMC_DISCONN: 67117565Skarels if ((sc->sc_disc++ % DMC_RPDSC) == 0) 67217565Skarels goto report; 67317565Skarels break; 67417221Stef case DMC_TIMEOUT: 67517565Skarels if ((sc->sc_timeo++ % DMC_RPTMO) == 0) 67617565Skarels goto report; 67717565Skarels break; 67817221Stef case DMC_DATACK: 67917565Skarels ifp->if_oerrors++; 68017565Skarels if ((sc->sc_datck++ % DMC_RPDCK) == 0) 68117565Skarels goto report; 68217565Skarels break; 68317221Stef default: 68417221Stef goto report; 68517221Stef } 68617221Stef break; 68717221Stef report: 68817565Skarels printd("dmc%d: soft error, flags=%b\n", unit, 68917565Skarels arg, CNTLO_BITS); 69017565Skarels if ((sc->sc_flag & DMC_RESTART) == 0) { 69117565Skarels /* 69217565Skarels * kill off the dmc to get things 69317565Skarels * going again by generating a 69417565Skarels * procedure error 69517565Skarels */ 69617565Skarels sc->sc_flag |= DMC_RESTART; 69717565Skarels arg = sc->sc_ubinfo & 0x3ffff; 69817565Skarels dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM); 69917565Skarels } 70017565Skarels break; 70117565Skarels 70217565Skarels default: 70317565Skarels printf("dmc%d: bad control %o\n", unit, cmd); 70417565Skarels break; 7055725Sroot } 7065725Sroot } 70717565Skarels dmcstart(unit); 70817221Stef return; 7095725Sroot } 7105725Sroot 7115725Sroot /* 7125725Sroot * DMC output routine. 71317565Skarels * Encapsulate a packet of type family for the dmc. 71417565Skarels * Use trailer local net encapsulation if enough data in first 71517565Skarels * packet leaves a multiple of 512 bytes of data in remainder. 7165725Sroot */ 71717565Skarels dmcoutput(ifp, m0, dst) 7185725Sroot register struct ifnet *ifp; 71917565Skarels register struct mbuf *m0; 7206334Ssam struct sockaddr *dst; 7215725Sroot { 72217565Skarels int type, error, s; 72317565Skarels register struct mbuf *m = m0; 72417565Skarels register struct dmc_header *dh; 72517565Skarels register int off; 7265725Sroot 72717565Skarels switch (dst->sa_family) { 72817565Skarels #ifdef INET 72917565Skarels case AF_INET: 73017565Skarels off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 73117565Skarels if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 73217565Skarels if (off > 0 && (off & 0x1ff) == 0 && 73317565Skarels m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 73417565Skarels type = DMC_TRAILER + (off>>9); 73517565Skarels m->m_off -= 2 * sizeof (u_short); 73617565Skarels m->m_len += 2 * sizeof (u_short); 73717565Skarels *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE); 73817565Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 73917565Skarels goto gottrailertype; 74017565Skarels } 74117565Skarels type = DMC_IPTYPE; 74217565Skarels off = 0; 74317565Skarels goto gottype; 74417565Skarels #endif 74517565Skarels 74617565Skarels case AF_UNSPEC: 74717565Skarels dh = (struct dmc_header *)dst->sa_data; 74817565Skarels type = dh->dmc_type; 74917565Skarels goto gottype; 75017565Skarels 75117565Skarels default: 75217565Skarels printf("dmc%d: can't handle af%d\n", ifp->if_unit, 75317565Skarels dst->sa_family); 75417565Skarels error = EAFNOSUPPORT; 75517565Skarels goto bad; 7565725Sroot } 75717565Skarels 75817565Skarels gottrailertype: 75917565Skarels /* 76017565Skarels * Packet to be sent as a trailer; move first packet 76117565Skarels * (control information) to end of chain. 76217565Skarels */ 76317565Skarels while (m->m_next) 76417565Skarels m = m->m_next; 76517565Skarels m->m_next = m0; 76617565Skarels m = m0->m_next; 76717565Skarels m0->m_next = 0; 76817565Skarels m0 = m; 76917565Skarels 77017565Skarels gottype: 77117565Skarels /* 77217565Skarels * Add local network header 77317565Skarels * (there is space for a uba on a vax to step on) 77417565Skarels */ 77517565Skarels if (m->m_off > MMAXOFF || 77617565Skarels MMINOFF + sizeof(struct dmc_header) > m->m_off) { 77717565Skarels m = m_get(M_DONTWAIT, MT_HEADER); 77817565Skarels if (m == 0) { 77917565Skarels error = ENOBUFS; 78017565Skarels goto bad; 78117565Skarels } 78217565Skarels m->m_next = m0; 78317565Skarels m->m_off = MMINOFF; 78417565Skarels m->m_len = sizeof (struct dmc_header); 78517565Skarels } else { 78617565Skarels m->m_off -= sizeof (struct dmc_header); 78717565Skarels m->m_len += sizeof (struct dmc_header); 78817565Skarels } 78917565Skarels dh = mtod(m, struct dmc_header *); 79017565Skarels dh->dmc_type = htons((u_short)type); 79117565Skarels 79217565Skarels /* 79317565Skarels * Queue message on interface, and start output if interface 79417565Skarels * not yet active. 79517565Skarels */ 79617565Skarels s = splimp(); 7976207Swnj if (IF_QFULL(&ifp->if_snd)) { 7986207Swnj IF_DROP(&ifp->if_snd); 7996334Ssam m_freem(m); 8006207Swnj splx(s); 8016502Ssam return (ENOBUFS); 8026207Swnj } 8035725Sroot IF_ENQUEUE(&ifp->if_snd, m); 80417221Stef dmcstart(ifp->if_unit); 8055725Sroot splx(s); 8066502Ssam return (0); 80717565Skarels 80817565Skarels bad: 80917565Skarels m_freem(m0); 81017565Skarels return (error); 8115725Sroot } 81213061Ssam 81317565Skarels 81413061Ssam /* 81513061Ssam * Process an ioctl request. 81613061Ssam */ 81724796Skarels /* ARGSUSED */ 81813061Ssam dmcioctl(ifp, cmd, data) 81913061Ssam register struct ifnet *ifp; 82013061Ssam int cmd; 82113061Ssam caddr_t data; 82213061Ssam { 82313061Ssam int s = splimp(), error = 0; 82413061Ssam 82513061Ssam switch (cmd) { 82613061Ssam 82713061Ssam case SIOCSIFADDR: 82817221Stef ifp->if_flags |= IFF_UP; 82919862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 83019862Skarels dmcinit(ifp->if_unit); 83113061Ssam break; 83213061Ssam 83313061Ssam case SIOCSIFDSTADDR: 83419862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 83519862Skarels dmcinit(ifp->if_unit); 83613061Ssam break; 83717221Stef 83813061Ssam default: 83913061Ssam error = EINVAL; 84013061Ssam } 84113061Ssam splx(s); 84213061Ssam return (error); 84313061Ssam } 84417221Stef 84517221Stef /* 84617565Skarels * Restart after a fatal error. 84717565Skarels * Clear device and reinitialize. 84817565Skarels */ 84917565Skarels dmcrestart(unit) 85017565Skarels int unit; 85117565Skarels { 85217565Skarels register struct dmc_softc *sc = &dmc_softc[unit]; 85317565Skarels register struct uba_device *ui = dmcinfo[unit]; 85417565Skarels register struct dmcdevice *addr; 85517565Skarels register struct ifxmt *ifxp; 85617565Skarels register int i; 85717565Skarels 85817565Skarels addr = (struct dmcdevice *)ui->ui_addr; 85917565Skarels #ifdef DEBUG 86017565Skarels /* dump base table */ 86117565Skarels printf("dmc%d base table:\n", unit); 86217565Skarels for (i = 0; i < sizeof (struct dmc_base); i++) 86317565Skarels printf("%o\n" ,dmc_base[unit].d_base[i]); 86413085Ssam #endif 86517565Skarels /* 86617565Skarels * Let the DMR finish the MCLR. At 1 Mbit, it should do so 86717565Skarels * in about a max of 6.4 milliseconds with diagnostics enabled. 86817565Skarels */ 86917565Skarels addr->bsel1 = DMC_MCLR; 87017565Skarels for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 87117565Skarels ; 87217565Skarels /* Did the timer expire or did the DMR finish? */ 87317565Skarels if ((addr->bsel1 & DMC_RUN) == 0) { 87426282Skarels log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit); 87517565Skarels return; 87617565Skarels } 87717565Skarels 87824796Skarels for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { 87924796Skarels if (ifxp->ifw_xtofree) { 88024796Skarels (void) m_freem(ifxp->ifw_xtofree); 88124796Skarels ifxp->ifw_xtofree = 0; 88217565Skarels } 88317565Skarels } 88417565Skarels 88517565Skarels /* restart DMC */ 88617565Skarels dmcinit(unit); 88717565Skarels sc->sc_flag &= ~DMC_RESTART; 88817565Skarels sc->sc_if.if_collisions++; /* why not? */ 88917565Skarels } 89017565Skarels 89117565Skarels /* 89217565Skarels * Check to see that transmitted packets don't 89317565Skarels * lose interrupts. The device has to be active. 89417565Skarels */ 89517565Skarels dmcwatch() 89617565Skarels { 89717565Skarels register struct uba_device *ui; 89817565Skarels register struct dmc_softc *sc; 89917565Skarels struct dmcdevice *addr; 90017565Skarels register int i; 90117565Skarels 90217565Skarels for (i = 0; i < NDMC; i++) { 90317565Skarels sc = &dmc_softc[i]; 90417565Skarels if ((sc->sc_flag & DMC_ACTIVE) == 0) 90517565Skarels continue; 90617565Skarels if ((ui = dmcinfo[i]) == 0 || ui->ui_alive == 0) 90717565Skarels continue; 90817565Skarels if (sc->sc_oused) { 90917565Skarels sc->sc_nticks++; 91017565Skarels if (sc->sc_nticks > dmc_timeout) { 91117565Skarels sc->sc_nticks = 0; 91217565Skarels addr = (struct dmcdevice *)ui->ui_addr; 91326282Skarels log(LOG_ERR, "dmc%d hung: bsel0=%b bsel2=%b\n", 91426282Skarels i, addr->bsel0 & 0xff, DMC0BITS, 91517565Skarels addr->bsel2 & 0xff, DMC2BITS); 91617565Skarels dmcrestart(i); 91717565Skarels } 91817565Skarels } 91917565Skarels } 92017565Skarels timeout(dmcwatch, (caddr_t) 0, hz); 92117565Skarels } 92217565Skarels #endif 923