123286Smckusick /* 229360Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 335317Sbostic * All rights reserved. 423286Smckusick * 535317Sbostic * Redistribution and use in source and binary forms are permitted 635317Sbostic * provided that the above copyright notice and this paragraph are 735317Sbostic * duplicated in all such forms and that any documentation, 835317Sbostic * advertising materials, and other materials related to such 935317Sbostic * distribution and use acknowledge that the software was developed 1035317Sbostic * by the University of California, Berkeley. The name of the 1135317Sbostic * University may not be used to endorse or promote products derived 1235317Sbostic * from this software without specific prior written permission. 1335317Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435317Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535317Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1635317Sbostic * 17*36032Skarels * @(#)if_dmc.c 7.5 (Berkeley) 10/22/88 1823286Smckusick */ 195725Sroot 205725Sroot #include "dmc.h" 215725Sroot #if NDMC > 0 2217565Skarels 235725Sroot /* 245725Sroot * DMC11 device driver, internet version 255725Sroot * 2617565Skarels * Bill Nesheim 2717221Stef * Cornell University 2811191Ssam * 2917565Skarels * Lou Salkind 3017565Skarels * New York University 315725Sroot */ 3217565Skarels 3317565Skarels /* #define DEBUG /* for base table dump on fatal error */ 3417565Skarels 359794Ssam #include "../machine/pte.h" 365725Sroot 3717111Sbloom #include "param.h" 3817111Sbloom #include "systm.h" 3917111Sbloom #include "mbuf.h" 4017111Sbloom #include "buf.h" 4117221Stef #include "ioctl.h" /* must precede tty.h */ 4217111Sbloom #include "tty.h" 4317111Sbloom #include "protosw.h" 4417111Sbloom #include "socket.h" 4526282Skarels #include "syslog.h" 4617111Sbloom #include "vmmac.h" 4717111Sbloom #include "errno.h" 488460Sroot 498460Sroot #include "../net/if.h" 509176Ssam #include "../net/netisr.h" 518460Sroot #include "../net/route.h" 5224796Skarels 5324796Skarels #ifdef INET 548416Swnj #include "../netinet/in.h" 558416Swnj #include "../netinet/in_systm.h" 5628950Skarels #include "../netinet/in_var.h" 5717565Skarels #include "../netinet/ip.h" 5824796Skarels #endif 598460Sroot 608460Sroot #include "../vax/cpu.h" 618460Sroot #include "../vax/mtpr.h" 6217111Sbloom #include "if_uba.h" 6317111Sbloom #include "if_dmc.h" 648460Sroot #include "../vaxuba/ubareg.h" 658460Sroot #include "../vaxuba/ubavar.h" 665725Sroot 6717565Skarels #include "../h/time.h" 6817565Skarels #include "../h/kernel.h" 6917565Skarels 7034529Skarels /* 7134529Skarels * output timeout value, sec.; should depend on line speed. 7234529Skarels */ 7334529Skarels int dmc_timeout = 20; 7417565Skarels 755725Sroot /* 765725Sroot * Driver information for auto-configuration stuff. 775725Sroot */ 7813061Ssam int dmcprobe(), dmcattach(), dmcinit(), dmcioctl(); 7934529Skarels int dmcoutput(), dmcreset(), dmctimeout(); 805725Sroot struct uba_device *dmcinfo[NDMC]; 815725Sroot u_short dmcstd[] = { 0 }; 825725Sroot struct uba_driver dmcdriver = 835725Sroot { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo }; 845725Sroot 8517221Stef #define NRCV 7 8617565Skarels #define NXMT 3 8724796Skarels #define NCMDS (NRCV+NXMT+4) /* size of command queue */ 8817221Stef 8917565Skarels #define printd if(dmcdebug)printf 9017565Skarels int dmcdebug = 0; 9117565Skarels 9217221Stef /* error reporting intervals */ 9317221Stef #define DMC_RPNBFS 50 9417221Stef #define DMC_RPDSC 1 9517565Skarels #define DMC_RPTMO 10 9617565Skarels #define DMC_RPDCK 10 9717221Stef 9817221Stef struct dmc_command { 9917221Stef char qp_cmd; /* command */ 10017221Stef short qp_ubaddr; /* buffer address */ 10117221Stef short qp_cc; /* character count || XMEM */ 10217221Stef struct dmc_command *qp_next; /* next command on queue */ 10317221Stef }; 10417221Stef 10517221Stef struct dmcbufs { 10617221Stef int ubinfo; /* from uballoc */ 10717221Stef short cc; /* buffer size */ 10817221Stef short flags; /* access control */ 10917221Stef }; 11017221Stef #define DBUF_OURS 0 /* buffer is available */ 11117221Stef #define DBUF_DMCS 1 /* buffer claimed by somebody */ 11217221Stef #define DBUF_XMIT 4 /* transmit buffer */ 11317565Skarels #define DBUF_RCV 8 /* receive buffer */ 11417221Stef 11517221Stef 11617221Stef /* 1175725Sroot * DMC software status per interface. 1185725Sroot * 1195725Sroot * Each interface is referenced by a network interface structure, 1205725Sroot * sc_if, which the routing code uses to locate the interface. 1215725Sroot * This structure contains the output queue for the interface, its address, ... 12217221Stef * We also have, for each interface, a set of 7 UBA interface structures 12317221Stef * for each, which 12417221Stef * contain information about the UNIBUS resources held by the interface: 1255725Sroot * map registers, buffered data paths, etc. Information is cached in this 1265725Sroot * structure for use by the if_uba.c routines in running the interface 1275725Sroot * efficiently. 1285725Sroot */ 1295725Sroot struct dmc_softc { 1305725Sroot struct ifnet sc_if; /* network-visible interface */ 13126933Skarels short sc_oused; /* output buffers currently in use */ 13226933Skarels short sc_iused; /* input buffers given to DMC */ 13326933Skarels short sc_flag; /* flags */ 1345725Sroot int sc_ubinfo; /* UBA mapping info for base table */ 13517221Stef int sc_errors[4]; /* non-fatal error counters */ 13617221Stef #define sc_datck sc_errors[0] 13717221Stef #define sc_timeo sc_errors[1] 13817221Stef #define sc_nobuf sc_errors[2] 13917221Stef #define sc_disc sc_errors[3] 14034529Skarels struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */ 14134529Skarels struct dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */ 14234529Skarels struct ifubinfo sc_ifuba; /* UNIBUS resources */ 14334529Skarels struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ 14434529Skarels struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ 14517221Stef /* command queue stuff */ 14617565Skarels struct dmc_command sc_cmdbuf[NCMDS]; 14717221Stef struct dmc_command *sc_qhead; /* head of command queue */ 14817221Stef struct dmc_command *sc_qtail; /* tail of command queue */ 14917221Stef struct dmc_command *sc_qactive; /* command in progress */ 15017221Stef struct dmc_command *sc_qfreeh; /* head of list of free cmd buffers */ 15117221Stef struct dmc_command *sc_qfreet; /* tail of list of free cmd buffers */ 15217221Stef /* end command queue stuff */ 1535725Sroot } dmc_softc[NDMC]; 1545725Sroot 1555725Sroot /* flags */ 15634529Skarels #define DMC_RUNNING 0x01 /* device initialized */ 15727266Skarels #define DMC_BMAPPED 0x02 /* base table mapped */ 15827266Skarels #define DMC_RESTART 0x04 /* software restart in progress */ 15934529Skarels #define DMC_ONLINE 0x08 /* device running (had a RDYO) */ 1605725Sroot 16117565Skarels struct dmc_base { 16217565Skarels short d_base[128]; /* DMC base table */ 1635725Sroot } dmc_base[NDMC]; 1645725Sroot 16517221Stef /* queue manipulation macros */ 16617221Stef #define QUEUE_AT_HEAD(qp, head, tail) \ 16717221Stef (qp)->qp_next = (head); \ 16817221Stef (head) = (qp); \ 16917221Stef if ((tail) == (struct dmc_command *) 0) \ 17017221Stef (tail) = (head) 1715725Sroot 17217221Stef #define QUEUE_AT_TAIL(qp, head, tail) \ 17317221Stef if ((tail)) \ 17417221Stef (tail)->qp_next = (qp); \ 17517221Stef else \ 17617221Stef (head) = (qp); \ 17717221Stef (qp)->qp_next = (struct dmc_command *) 0; \ 17817221Stef (tail) = (qp) 17917221Stef 18017221Stef #define DEQUEUE(head, tail) \ 18117221Stef (head) = (head)->qp_next;\ 18217221Stef if ((head) == (struct dmc_command *) 0)\ 18317221Stef (tail) = (head) 18417221Stef 1855725Sroot dmcprobe(reg) 1865725Sroot caddr_t reg; 1875725Sroot { 1885725Sroot register int br, cvec; 1895725Sroot register struct dmcdevice *addr = (struct dmcdevice *)reg; 1905725Sroot register int i; 1915725Sroot 1925725Sroot #ifdef lint 1935725Sroot br = 0; cvec = br; br = cvec; 1945725Sroot dmcrint(0); dmcxint(0); 1955725Sroot #endif 1965725Sroot addr->bsel1 = DMC_MCLR; 1975725Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 1985725Sroot ; 19917565Skarels if ((addr->bsel1 & DMC_RUN) == 0) { 20017565Skarels printf("dmcprobe: can't start device\n" ); 2016334Ssam return (0); 20217565Skarels } 2035725Sroot addr->bsel0 = DMC_RQI|DMC_IEI; 20417565Skarels /* let's be paranoid */ 20517565Skarels addr->bsel0 |= DMC_RQI|DMC_IEI; 20617565Skarels DELAY(1000000); 2075725Sroot addr->bsel1 = DMC_MCLR; 2085725Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 2095725Sroot ; 2106334Ssam return (1); 2115725Sroot } 2125725Sroot 2135725Sroot /* 2145725Sroot * Interface exists: make available by filling in network interface 2155725Sroot * record. System will initialize the interface when it is ready 2165725Sroot * to accept packets. 2175725Sroot */ 2185725Sroot dmcattach(ui) 2195725Sroot register struct uba_device *ui; 2205725Sroot { 2215725Sroot register struct dmc_softc *sc = &dmc_softc[ui->ui_unit]; 2225725Sroot 2235725Sroot sc->sc_if.if_unit = ui->ui_unit; 2245725Sroot sc->sc_if.if_name = "dmc"; 2255725Sroot sc->sc_if.if_mtu = DMCMTU; 2265725Sroot sc->sc_if.if_init = dmcinit; 2275725Sroot sc->sc_if.if_output = dmcoutput; 22813061Ssam sc->sc_if.if_ioctl = dmcioctl; 2298976Sroot sc->sc_if.if_reset = dmcreset; 23034529Skarels sc->sc_if.if_watchdog = dmctimeout; 23117221Stef sc->sc_if.if_flags = IFF_POINTOPOINT; 23224796Skarels sc->sc_ifuba.iff_flags = UBA_CANTWAIT; 23317221Stef 23424796Skarels if_attach(&sc->sc_if); 2355725Sroot } 2365725Sroot 2375725Sroot /* 2385725Sroot * Reset of interface after UNIBUS reset. 23919862Skarels * If interface is on specified UBA, reset its state. 2405725Sroot */ 2415725Sroot dmcreset(unit, uban) 2425725Sroot int unit, uban; 2435725Sroot { 2445725Sroot register struct uba_device *ui; 24517221Stef register struct dmc_softc *sc = &dmc_softc[unit]; 2465725Sroot 2475725Sroot if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 || 2485725Sroot ui->ui_ubanum != uban) 2495725Sroot return; 2505725Sroot printf(" dmc%d", unit); 25117565Skarels sc->sc_flag = 0; 25219862Skarels sc->sc_if.if_flags &= ~IFF_RUNNING; 2535725Sroot dmcinit(unit); 2545725Sroot } 2555725Sroot 2565725Sroot /* 2575725Sroot * Initialization of interface; reinitialize UNIBUS usage. 2585725Sroot */ 2595725Sroot dmcinit(unit) 2605725Sroot int unit; 2615725Sroot { 2625725Sroot register struct dmc_softc *sc = &dmc_softc[unit]; 2635725Sroot register struct uba_device *ui = dmcinfo[unit]; 2645725Sroot register struct dmcdevice *addr; 26513061Ssam register struct ifnet *ifp = &sc->sc_if; 26617221Stef register struct ifrw *ifrw; 26717221Stef register struct ifxmt *ifxp; 26817221Stef register struct dmcbufs *rp; 26917565Skarels register struct dmc_command *qp; 27019862Skarels struct ifaddr *ifa; 27117221Stef int base; 27217565Skarels int s; 2735725Sroot 27417221Stef addr = (struct dmcdevice *)ui->ui_addr; 27517221Stef 27619862Skarels /* 27719862Skarels * Check to see that an address has been set 27819862Skarels * (both local and destination for an address family). 27919862Skarels */ 28019862Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 28119862Skarels if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) 28219862Skarels break; 28319862Skarels if (ifa == (struct ifaddr *) 0) 2845725Sroot return; 28517221Stef 28617221Stef if ((addr->bsel1&DMC_RUN) == 0) { 28717221Stef printf("dmcinit: DMC not running\n"); 28819862Skarels ifp->if_flags &= ~IFF_UP; 28917221Stef return; 29017221Stef } 29117221Stef /* map base table */ 29217565Skarels if ((sc->sc_flag & DMC_BMAPPED) == 0) { 29317221Stef sc->sc_ubinfo = uballoc(ui->ui_ubanum, 29417221Stef (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0); 29517221Stef sc->sc_flag |= DMC_BMAPPED; 29617221Stef } 29717221Stef /* initialize UNIBUS resources */ 29817221Stef sc->sc_iused = sc->sc_oused = 0; 29919862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 30024796Skarels if (if_ubaminit(&sc->sc_ifuba, ui->ui_ubanum, 30124796Skarels sizeof(struct dmc_header), (int)btoc(DMCMTU), 30224796Skarels sc->sc_ifr, NRCV, sc->sc_ifw, NXMT) == 0) { 30319862Skarels printf("dmc%d: can't allocate uba resources\n", unit); 30413061Ssam ifp->if_flags &= ~IFF_UP; 30513061Ssam return; 30613061Ssam } 30719862Skarels ifp->if_flags |= IFF_RUNNING; 3085725Sroot } 30934529Skarels sc->sc_flag &= ~DMC_ONLINE; 31027266Skarels sc->sc_flag |= DMC_RUNNING; 31134529Skarels /* 31234529Skarels * Limit packets enqueued until we see if we're on the air. 31334529Skarels */ 31434529Skarels ifp->if_snd.ifq_maxlen = 3; 31517221Stef 31617221Stef /* initialize buffer pool */ 31717565Skarels /* receives */ 31824796Skarels ifrw = &sc->sc_ifr[0]; 31917221Stef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 320*36032Skarels rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); 32117565Skarels rp->cc = DMCMTU + sizeof (struct dmc_header); 32217221Stef rp->flags = DBUF_OURS|DBUF_RCV; 32317221Stef ifrw++; 3246363Ssam } 32517221Stef /* transmits */ 32624796Skarels ifxp = &sc->sc_ifw[0]; 32717221Stef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 328*36032Skarels rp->ubinfo = UBAI_ADDR(ifxp->ifw_info); 32917221Stef rp->cc = 0; 33017221Stef rp->flags = DBUF_OURS|DBUF_XMIT; 33117221Stef ifxp++; 33217221Stef } 33317565Skarels 33417565Skarels /* set up command queues */ 33517565Skarels sc->sc_qfreeh = sc->sc_qfreet 33617565Skarels = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = 33717565Skarels (struct dmc_command *)0; 33817565Skarels /* set up free command buffer list */ 33917565Skarels for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { 34017565Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 34117565Skarels } 34217565Skarels 34317221Stef /* base in */ 344*36032Skarels base = UBAI_ADDR(sc->sc_ubinfo); 345*36032Skarels dmcload(sc, DMC_BASEI, (u_short)base, (base>>2) & DMC_XMEM); 34617221Stef /* specify half duplex operation, flags tell if primary */ 34717221Stef /* or secondary station */ 34817221Stef if (ui->ui_flags == 0) 34927266Skarels /* use DDCMP mode in full duplex */ 35017565Skarels dmcload(sc, DMC_CNTLI, 0, 0); 35117221Stef else if (ui->ui_flags == 1) 35217565Skarels /* use MAINTENENCE mode */ 35317565Skarels dmcload(sc, DMC_CNTLI, 0, DMC_MAINT ); 35417221Stef else if (ui->ui_flags == 2) 35517221Stef /* use DDCMP half duplex as primary station */ 35617221Stef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX); 35717221Stef else if (ui->ui_flags == 3) 35817221Stef /* use DDCMP half duplex as secondary station */ 35917221Stef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC); 36017565Skarels 36117565Skarels /* enable operation done interrupts */ 36217565Skarels while ((addr->bsel2 & DMC_IEO) == 0) 36317565Skarels addr->bsel2 |= DMC_IEO; 36417565Skarels s = spl5(); 36517221Stef /* queue first NRCV buffers for DMC to fill */ 36617221Stef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 36717221Stef rp->flags |= DBUF_DMCS; 36817221Stef dmcload(sc, DMC_READ, rp->ubinfo, 36917565Skarels (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc)); 37017221Stef sc->sc_iused++; 37117221Stef } 37217565Skarels splx(s); 3735725Sroot } 3745725Sroot 3755725Sroot /* 3765725Sroot * Start output on interface. Get another datagram 3775725Sroot * to send from the interface queue and map it to 3785725Sroot * the interface before starting output. 37917221Stef * 38017221Stef * Must be called at spl 5 3815725Sroot */ 38234529Skarels dmcstart(unit) 38334529Skarels int unit; 3845725Sroot { 3855725Sroot register struct dmc_softc *sc = &dmc_softc[unit]; 3865725Sroot struct mbuf *m; 38717221Stef register struct dmcbufs *rp; 38817221Stef register int n; 3895725Sroot 3905725Sroot /* 39117221Stef * Dequeue up to NXMT requests and map them to the UNIBUS. 39217221Stef * If no more requests, or no dmc buffers available, just return. 3935725Sroot */ 39417221Stef n = 0; 39517221Stef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { 39617221Stef /* find an available buffer */ 39717565Skarels if ((rp->flags & DBUF_DMCS) == 0) { 39817221Stef IF_DEQUEUE(&sc->sc_if.if_snd, m); 39917221Stef if (m == 0) 40017221Stef return; 40117221Stef /* mark it dmcs */ 40217221Stef rp->flags |= (DBUF_DMCS); 40317221Stef /* 40417221Stef * Have request mapped to UNIBUS for transmission 40517221Stef * and start the output. 40617221Stef */ 40724796Skarels rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); 40817565Skarels rp->cc &= DMC_CCOUNT; 40934529Skarels if (++sc->sc_oused == 1) 41034529Skarels sc->sc_if.if_timer = dmc_timeout; 41117221Stef dmcload(sc, DMC_WRITE, rp->ubinfo, 41217221Stef rp->cc | ((rp->ubinfo>>2)&DMC_XMEM)); 41317221Stef } 41417221Stef n++; 41517221Stef } 4165725Sroot } 4175725Sroot 4185725Sroot /* 4195725Sroot * Utility routine to load the DMC device registers. 4205725Sroot */ 4215725Sroot dmcload(sc, type, w0, w1) 4225725Sroot register struct dmc_softc *sc; 423*36032Skarels int type; 424*36032Skarels u_short w0, w1; 4255725Sroot { 4265725Sroot register struct dmcdevice *addr; 42717221Stef register int unit, sps; 42817221Stef register struct dmc_command *qp; 4295725Sroot 43017565Skarels unit = sc - dmc_softc; 4315725Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; 4325725Sroot sps = spl5(); 43317221Stef 43417221Stef /* grab a command buffer from the free list */ 43517221Stef if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0) 43617221Stef panic("dmc command queue overflow"); 43717221Stef DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); 43817221Stef 43917221Stef /* fill in requested info */ 44017221Stef qp->qp_cmd = (type | DMC_RQI); 44117221Stef qp->qp_ubaddr = w0; 44217221Stef qp->qp_cc = w1; 44317221Stef 44417221Stef if (sc->sc_qactive) { /* command in progress */ 44517221Stef if (type == DMC_READ) { 44617221Stef QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); 44717221Stef } else { 44817221Stef QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); 44917221Stef } 45017221Stef } else { /* command port free */ 45117221Stef sc->sc_qactive = qp; 45217221Stef addr->bsel0 = qp->qp_cmd; 4535725Sroot dmcrint(unit); 45417221Stef } 4555725Sroot splx(sps); 4565725Sroot } 4575725Sroot 4585725Sroot /* 4595725Sroot * DMC interface receiver interrupt. 4605725Sroot * Ready to accept another command, 4615725Sroot * pull one off the command queue. 4625725Sroot */ 4635725Sroot dmcrint(unit) 4645725Sroot int unit; 4655725Sroot { 4665725Sroot register struct dmc_softc *sc; 4675725Sroot register struct dmcdevice *addr; 46817221Stef register struct dmc_command *qp; 4695725Sroot register int n; 4705725Sroot 4715725Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; 4725725Sroot sc = &dmc_softc[unit]; 47317221Stef if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) { 47417565Skarels printf("dmc%d: dmcrint no command\n", unit); 47517221Stef return; 47617221Stef } 4775725Sroot while (addr->bsel0&DMC_RDYI) { 47817221Stef addr->sel4 = qp->qp_ubaddr; 47917221Stef addr->sel6 = qp->qp_cc; 4805725Sroot addr->bsel0 &= ~(DMC_IEI|DMC_RQI); 48117221Stef /* free command buffer */ 48217221Stef QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 48317221Stef while (addr->bsel0 & DMC_RDYI) { 48417221Stef /* 48517221Stef * Can't check for RDYO here 'cause 48617221Stef * this routine isn't reentrant! 48717221Stef */ 48817221Stef DELAY(5); 48917221Stef } 49017221Stef /* move on to next command */ 49117565Skarels if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0) 49217565Skarels break; /* all done */ 49317221Stef /* more commands to do, start the next one */ 49417221Stef qp = sc->sc_qactive; 49517221Stef DEQUEUE(sc->sc_qhead, sc->sc_qtail); 49617221Stef addr->bsel0 = qp->qp_cmd; 4975725Sroot n = RDYSCAN; 49817565Skarels while (n-- > 0) 49917565Skarels if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO)) 50017565Skarels break; 5015725Sroot } 50217221Stef if (sc->sc_qactive) { 50317221Stef addr->bsel0 |= DMC_IEI|DMC_RQI; 50417221Stef /* VMS does it twice !*$%@# */ 50517221Stef addr->bsel0 |= DMC_IEI|DMC_RQI; 50617221Stef } 50717565Skarels 5085725Sroot } 5095725Sroot 5105725Sroot /* 5115725Sroot * DMC interface transmitter interrupt. 51217221Stef * A transfer may have completed, check for errors. 5135725Sroot * If it was a read, notify appropriate protocol. 5145725Sroot * If it was a write, pull the next one off the queue. 5155725Sroot */ 5165725Sroot dmcxint(unit) 5175725Sroot int unit; 5185725Sroot { 5195725Sroot register struct dmc_softc *sc; 52013065Ssam register struct ifnet *ifp; 5215725Sroot struct uba_device *ui = dmcinfo[unit]; 5225725Sroot struct dmcdevice *addr; 5235725Sroot struct mbuf *m; 52417565Skarels struct ifqueue *inq; 52527266Skarels int arg, pkaddr, cmd, len, s; 52617221Stef register struct ifrw *ifrw; 52717221Stef register struct dmcbufs *rp; 52817565Skarels register struct ifxmt *ifxp; 52917565Skarels struct dmc_header *dh; 53017565Skarels int off, resid; 5315725Sroot 5325725Sroot addr = (struct dmcdevice *)ui->ui_addr; 53317221Stef sc = &dmc_softc[unit]; 53417221Stef ifp = &sc->sc_if; 53517221Stef 53617565Skarels while (addr->bsel2 & DMC_RDYO) { 5375725Sroot 53817565Skarels cmd = addr->bsel2 & 0xff; 53917565Skarels arg = addr->sel6 & 0xffff; 54017565Skarels /* reconstruct UNIBUS address of buffer returned to us */ 54117565Skarels pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff); 54217565Skarels /* release port */ 54317565Skarels addr->bsel2 &= ~DMC_RDYO; 54417565Skarels switch (cmd & 07) { 54517565Skarels 54617565Skarels case DMC_OUR: 54717565Skarels /* 54817565Skarels * A read has completed. 54917565Skarels * Pass packet to type specific 55017565Skarels * higher-level input routine. 55117565Skarels */ 55217565Skarels ifp->if_ipackets++; 55317565Skarels /* find location in dmcuba struct */ 55424796Skarels ifrw= &sc->sc_ifr[0]; 55517565Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 55617565Skarels if(rp->ubinfo == pkaddr) 55717565Skarels break; 55817565Skarels ifrw++; 55917565Skarels } 56017565Skarels if (rp >= &sc->sc_rbufs[NRCV]) 56117565Skarels panic("dmc rcv"); 56217565Skarels if ((rp->flags & DBUF_DMCS) == 0) 56317565Skarels printf("dmc%d: done unalloc rbuf\n", unit); 56417565Skarels 56517565Skarels len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header); 56617565Skarels if (len < 0 || len > DMCMTU) { 56717565Skarels ifp->if_ierrors++; 56817565Skarels printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n", 56917565Skarels unit, pkaddr, len); 57017565Skarels goto setup; 57117565Skarels } 57217565Skarels /* 57317565Skarels * Deal with trailer protocol: if type is trailer 57417565Skarels * get true type from first 16-bit word past data. 57517565Skarels * Remember that type was trailer by setting off. 57617565Skarels */ 57717565Skarels dh = (struct dmc_header *)ifrw->ifrw_addr; 57817565Skarels dh->dmc_type = ntohs((u_short)dh->dmc_type); 57917565Skarels #define dmcdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) 58017565Skarels if (dh->dmc_type >= DMC_TRAILER && 58117565Skarels dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) { 58217565Skarels off = (dh->dmc_type - DMC_TRAILER) * 512; 58317565Skarels if (off >= DMCMTU) 58417565Skarels goto setup; /* sanity */ 58517565Skarels dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *)); 58617565Skarels resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *))); 58717565Skarels if (off + resid > len) 58817565Skarels goto setup; /* sanity */ 58917565Skarels len = off + resid; 59017565Skarels } else 59117565Skarels off = 0; 59217565Skarels if (len == 0) 59317565Skarels goto setup; 59417565Skarels 59517565Skarels /* 59617565Skarels * Pull packet off interface. Off is nonzero if 59717565Skarels * packet has trailing header; dmc_get will then 59817565Skarels * force this header information to be at the front, 59917565Skarels * but we still have to drop the type and length 60017565Skarels * which are at the front of any trailer data. 60117565Skarels */ 60224796Skarels m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); 60317565Skarels if (m == 0) 60417565Skarels goto setup; 605*36032Skarels if (off) { 606*36032Skarels ifp = *(mtod(m, struct ifnet **)); 607*36032Skarels m->m_off += 2 * sizeof (u_short); 608*36032Skarels m->m_len -= 2 * sizeof (u_short); 609*36032Skarels *(mtod(m, struct ifnet **)) = ifp; 610*36032Skarels } 61117565Skarels switch (dh->dmc_type) { 61217565Skarels 6135725Sroot #ifdef INET 61417565Skarels case DMC_IPTYPE: 61517565Skarels schednetisr(NETISR_IP); 61617565Skarels inq = &ipintrq; 61717565Skarels break; 6185725Sroot #endif 61917565Skarels default: 62017565Skarels m_freem(m); 62117565Skarels goto setup; 62217565Skarels } 6235725Sroot 62427266Skarels s = splimp(); 62517565Skarels if (IF_QFULL(inq)) { 62617565Skarels IF_DROP(inq); 62717565Skarels m_freem(m); 62817565Skarels } else 62917565Skarels IF_ENQUEUE(inq, m); 63027266Skarels splx(s); 63117221Stef 63217565Skarels setup: 63317565Skarels /* is this needed? */ 634*36032Skarels rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info); 6355725Sroot 63617565Skarels dmcload(sc, DMC_READ, rp->ubinfo, 63717565Skarels ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc); 63817565Skarels break; 6395725Sroot 64017565Skarels case DMC_OUX: 64117565Skarels /* 64217565Skarels * A write has completed, start another 64317565Skarels * transfer if there is more data to send. 64417565Skarels */ 64517565Skarels ifp->if_opackets++; 64617565Skarels /* find associated dmcbuf structure */ 64724796Skarels ifxp = &sc->sc_ifw[0]; 64817565Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 64917565Skarels if(rp->ubinfo == pkaddr) 65017565Skarels break; 65117565Skarels ifxp++; 65217565Skarels } 65317565Skarels if (rp >= &sc->sc_xbufs[NXMT]) { 65417565Skarels printf("dmc%d: bad packet address 0x%x\n", 65517565Skarels unit, pkaddr); 65617565Skarels break; 65717565Skarels } 65817565Skarels if ((rp->flags & DBUF_DMCS) == 0) 65917565Skarels printf("dmc%d: unallocated packet 0x%x\n", 66017565Skarels unit, pkaddr); 66117565Skarels /* mark buffer free */ 66224796Skarels if (ifxp->ifw_xtofree) { 66324796Skarels (void)m_freem(ifxp->ifw_xtofree); 66424796Skarels ifxp->ifw_xtofree = 0; 66517565Skarels } 66617565Skarels rp->flags &= ~DBUF_DMCS; 66734529Skarels if (--sc->sc_oused == 0) 66834529Skarels sc->sc_if.if_timer = 0; 66934529Skarels else 67034529Skarels sc->sc_if.if_timer = dmc_timeout; 67134529Skarels if ((sc->sc_flag & DMC_ONLINE) == 0) { 67234529Skarels extern int ifqmaxlen; 67334529Skarels 67434529Skarels /* 67534529Skarels * We're on the air. 67634529Skarels * Open the queue to the usual value. 67734529Skarels */ 67834529Skarels sc->sc_flag |= DMC_ONLINE; 67934529Skarels ifp->if_snd.ifq_maxlen = ifqmaxlen; 68034529Skarels } 68117565Skarels break; 68217221Stef 68317565Skarels case DMC_CNTLO: 68417565Skarels arg &= DMC_CNTMASK; 68517565Skarels if (arg & DMC_FATAL) { 68634529Skarels if (arg != DMC_START) 68734529Skarels log(LOG_ERR, 68834529Skarels "dmc%d: fatal error, flags=%b\n", 68934529Skarels unit, arg, CNTLO_BITS); 69017565Skarels dmcrestart(unit); 69117565Skarels break; 69217565Skarels } 69317565Skarels /* ACCUMULATE STATISTICS */ 69417221Stef switch(arg) { 69517221Stef case DMC_NOBUFS: 69617565Skarels ifp->if_ierrors++; 69717565Skarels if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0) 69817565Skarels goto report; 69917565Skarels break; 70017221Stef case DMC_DISCONN: 70117565Skarels if ((sc->sc_disc++ % DMC_RPDSC) == 0) 70217565Skarels goto report; 70317565Skarels break; 70417221Stef case DMC_TIMEOUT: 70517565Skarels if ((sc->sc_timeo++ % DMC_RPTMO) == 0) 70617565Skarels goto report; 70717565Skarels break; 70817221Stef case DMC_DATACK: 70917565Skarels ifp->if_oerrors++; 71017565Skarels if ((sc->sc_datck++ % DMC_RPDCK) == 0) 71117565Skarels goto report; 71217565Skarels break; 71317221Stef default: 71417221Stef goto report; 71517221Stef } 71617221Stef break; 71717221Stef report: 71817565Skarels printd("dmc%d: soft error, flags=%b\n", unit, 71917565Skarels arg, CNTLO_BITS); 72017565Skarels if ((sc->sc_flag & DMC_RESTART) == 0) { 72117565Skarels /* 72217565Skarels * kill off the dmc to get things 72317565Skarels * going again by generating a 72417565Skarels * procedure error 72517565Skarels */ 72617565Skarels sc->sc_flag |= DMC_RESTART; 727*36032Skarels arg = UBAI_ADDR(sc->sc_ubinfo); 72817565Skarels dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM); 72917565Skarels } 73017565Skarels break; 73117565Skarels 73217565Skarels default: 73317565Skarels printf("dmc%d: bad control %o\n", unit, cmd); 73417565Skarels break; 7355725Sroot } 7365725Sroot } 73717565Skarels dmcstart(unit); 73817221Stef return; 7395725Sroot } 7405725Sroot 7415725Sroot /* 7425725Sroot * DMC output routine. 74317565Skarels * Encapsulate a packet of type family for the dmc. 74417565Skarels * Use trailer local net encapsulation if enough data in first 74517565Skarels * packet leaves a multiple of 512 bytes of data in remainder. 7465725Sroot */ 74717565Skarels dmcoutput(ifp, m0, dst) 7485725Sroot register struct ifnet *ifp; 74917565Skarels register struct mbuf *m0; 7506334Ssam struct sockaddr *dst; 7515725Sroot { 75217565Skarels int type, error, s; 75317565Skarels register struct mbuf *m = m0; 75417565Skarels register struct dmc_header *dh; 75517565Skarels register int off; 7565725Sroot 75734529Skarels if ((ifp->if_flags & IFF_UP) == 0) { 75834529Skarels error = ENETDOWN; 75934529Skarels goto bad; 76034529Skarels } 76134529Skarels 76217565Skarels switch (dst->sa_family) { 76317565Skarels #ifdef INET 76417565Skarels case AF_INET: 765*36032Skarels off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 76617565Skarels if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 76717565Skarels if (off > 0 && (off & 0x1ff) == 0 && 768*36032Skarels m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 76917565Skarels type = DMC_TRAILER + (off>>9); 770*36032Skarels m->m_off -= 2 * sizeof (u_short); 77117565Skarels m->m_len += 2 * sizeof (u_short); 77217565Skarels *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE); 77317565Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 77417565Skarels goto gottrailertype; 77517565Skarels } 77617565Skarels type = DMC_IPTYPE; 77717565Skarels off = 0; 77817565Skarels goto gottype; 77917565Skarels #endif 78017565Skarels 78117565Skarels case AF_UNSPEC: 78217565Skarels dh = (struct dmc_header *)dst->sa_data; 78317565Skarels type = dh->dmc_type; 78417565Skarels goto gottype; 78517565Skarels 78617565Skarels default: 78717565Skarels printf("dmc%d: can't handle af%d\n", ifp->if_unit, 78817565Skarels dst->sa_family); 78917565Skarels error = EAFNOSUPPORT; 79017565Skarels goto bad; 7915725Sroot } 79217565Skarels 79317565Skarels gottrailertype: 79417565Skarels /* 79517565Skarels * Packet to be sent as a trailer; move first packet 79617565Skarels * (control information) to end of chain. 79717565Skarels */ 79817565Skarels while (m->m_next) 79917565Skarels m = m->m_next; 80017565Skarels m->m_next = m0; 80117565Skarels m = m0->m_next; 80217565Skarels m0->m_next = 0; 80317565Skarels m0 = m; 80417565Skarels 80517565Skarels gottype: 80617565Skarels /* 80717565Skarels * Add local network header 80817565Skarels * (there is space for a uba on a vax to step on) 80917565Skarels */ 810*36032Skarels if (m->m_off > MMAXOFF || 811*36032Skarels MMINOFF + sizeof(struct dmc_header) > m->m_off) { 812*36032Skarels m = m_get(M_DONTWAIT, MT_HEADER); 813*36032Skarels if (m == 0) { 814*36032Skarels error = ENOBUFS; 815*36032Skarels goto bad; 816*36032Skarels } 817*36032Skarels m->m_next = m0; 818*36032Skarels m->m_off = MMINOFF; 819*36032Skarels m->m_len = sizeof (struct dmc_header); 820*36032Skarels } else { 821*36032Skarels m->m_off -= sizeof (struct dmc_header); 822*36032Skarels m->m_len += sizeof (struct dmc_header); 82317565Skarels } 82417565Skarels dh = mtod(m, struct dmc_header *); 82517565Skarels dh->dmc_type = htons((u_short)type); 82617565Skarels 82717565Skarels /* 82817565Skarels * Queue message on interface, and start output if interface 82917565Skarels * not yet active. 83017565Skarels */ 83117565Skarels s = splimp(); 8326207Swnj if (IF_QFULL(&ifp->if_snd)) { 8336207Swnj IF_DROP(&ifp->if_snd); 8346334Ssam m_freem(m); 8356207Swnj splx(s); 8366502Ssam return (ENOBUFS); 8376207Swnj } 8385725Sroot IF_ENQUEUE(&ifp->if_snd, m); 83917221Stef dmcstart(ifp->if_unit); 8405725Sroot splx(s); 8416502Ssam return (0); 84217565Skarels 84317565Skarels bad: 84417565Skarels m_freem(m0); 84517565Skarels return (error); 8465725Sroot } 84713061Ssam 84817565Skarels 84913061Ssam /* 85013061Ssam * Process an ioctl request. 85113061Ssam */ 85224796Skarels /* ARGSUSED */ 85313061Ssam dmcioctl(ifp, cmd, data) 85413061Ssam register struct ifnet *ifp; 85513061Ssam int cmd; 85613061Ssam caddr_t data; 85713061Ssam { 85813061Ssam int s = splimp(), error = 0; 85927266Skarels register struct dmc_softc *sc = &dmc_softc[ifp->if_unit]; 86013061Ssam 86113061Ssam switch (cmd) { 86213061Ssam 86313061Ssam case SIOCSIFADDR: 86417221Stef ifp->if_flags |= IFF_UP; 86519862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 86619862Skarels dmcinit(ifp->if_unit); 86713061Ssam break; 86813061Ssam 86913061Ssam case SIOCSIFDSTADDR: 87019862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 87119862Skarels dmcinit(ifp->if_unit); 87213061Ssam break; 87317221Stef 87427266Skarels case SIOCSIFFLAGS: 87527266Skarels if ((ifp->if_flags & IFF_UP) == 0 && 87634529Skarels sc->sc_flag & DMC_RUNNING) 87734529Skarels dmcdown(ifp->if_unit); 87834529Skarels else if (ifp->if_flags & IFF_UP && 87927266Skarels (sc->sc_flag & DMC_RUNNING) == 0) 88027266Skarels dmcrestart(ifp->if_unit); 88127266Skarels break; 88227266Skarels 88313061Ssam default: 88413061Ssam error = EINVAL; 88513061Ssam } 88613061Ssam splx(s); 88713061Ssam return (error); 88813061Ssam } 88917221Stef 89017221Stef /* 89117565Skarels * Restart after a fatal error. 89217565Skarels * Clear device and reinitialize. 89317565Skarels */ 89417565Skarels dmcrestart(unit) 89517565Skarels int unit; 89617565Skarels { 89717565Skarels register struct dmc_softc *sc = &dmc_softc[unit]; 89817565Skarels register struct dmcdevice *addr; 89917565Skarels register int i; 90034529Skarels int s; 90117565Skarels 90217565Skarels #ifdef DEBUG 90317565Skarels /* dump base table */ 90417565Skarels printf("dmc%d base table:\n", unit); 90517565Skarels for (i = 0; i < sizeof (struct dmc_base); i++) 90617565Skarels printf("%o\n" ,dmc_base[unit].d_base[i]); 90713085Ssam #endif 90834529Skarels 90934529Skarels dmcdown(unit); 91034529Skarels 91117565Skarels /* 91217565Skarels * Let the DMR finish the MCLR. At 1 Mbit, it should do so 91317565Skarels * in about a max of 6.4 milliseconds with diagnostics enabled. 91417565Skarels */ 91534529Skarels addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr); 91617565Skarels for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 91717565Skarels ; 91817565Skarels /* Did the timer expire or did the DMR finish? */ 91917565Skarels if ((addr->bsel1 & DMC_RUN) == 0) { 92026282Skarels log(LOG_ERR, "dmc%d: M820 Test Failed\n", unit); 92117565Skarels return; 92217565Skarels } 92317565Skarels 92434529Skarels /* restart DMC */ 92534529Skarels dmcinit(unit); 92634529Skarels sc->sc_flag &= ~DMC_RESTART; 92734529Skarels s = spl5(); 92834529Skarels dmcstart(unit); 92934529Skarels splx(s); 93034529Skarels sc->sc_if.if_collisions++; /* why not? */ 93134529Skarels } 93234529Skarels 93334529Skarels /* 93434529Skarels * Reset a device and mark down. 93534529Skarels * Flush output queue and drop queue limit. 93634529Skarels */ 93734529Skarels dmcdown(unit) 93834529Skarels int unit; 93934529Skarels { 94034529Skarels register struct dmc_softc *sc = &dmc_softc[unit]; 94134529Skarels register struct ifxmt *ifxp; 94234529Skarels 94334529Skarels ((struct dmcdevice *)(dmcinfo[unit]->ui_addr))->bsel1 = DMC_MCLR; 94434529Skarels sc->sc_flag &= ~(DMC_RUNNING | DMC_ONLINE); 94534529Skarels 94624796Skarels for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { 94724796Skarels if (ifxp->ifw_xtofree) { 94824796Skarels (void) m_freem(ifxp->ifw_xtofree); 94924796Skarels ifxp->ifw_xtofree = 0; 95017565Skarels } 95117565Skarels } 95234529Skarels if_qflush(&sc->sc_if.if_snd); 95317565Skarels } 95417565Skarels 95517565Skarels /* 95634529Skarels * Watchdog timeout to see that transmitted packets don't 95734529Skarels * lose interrupts. The device has to be online (the first 95834529Skarels * transmission may block until the other side comes up). 95917565Skarels */ 96034529Skarels dmctimeout(unit) 96134529Skarels int unit; 96217565Skarels { 96317565Skarels register struct dmc_softc *sc; 96417565Skarels struct dmcdevice *addr; 96517565Skarels 96634529Skarels sc = &dmc_softc[unit]; 96734529Skarels if (sc->sc_flag & DMC_ONLINE) { 96834529Skarels addr = (struct dmcdevice *)(dmcinfo[unit]->ui_addr); 96934529Skarels log(LOG_ERR, "dmc%d: output timeout, bsel0=%b bsel2=%b\n", 97034529Skarels unit, addr->bsel0 & 0xff, DMC0BITS, 97134529Skarels addr->bsel2 & 0xff, DMC2BITS); 97234529Skarels dmcrestart(unit); 97317565Skarels } 97417565Skarels } 97517565Skarels #endif 976