1*23286Smckusick /* 2*23286Smckusick * Copyright (c) 1982 Regents of the University of California. 3*23286Smckusick * All rights reserved. The Berkeley software License Agreement 4*23286Smckusick * specifies the terms and conditions for redistribution. 5*23286Smckusick * 6*23286Smckusick * @(#)if_dmc.c 6.6 (Berkeley) 06/08/85 7*23286Smckusick */ 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" 3417111Sbloom #include "vmmac.h" 3517111Sbloom #include "errno.h" 368460Sroot 378460Sroot #include "../net/if.h" 389176Ssam #include "../net/netisr.h" 398460Sroot #include "../net/route.h" 408416Swnj #include "../netinet/in.h" 418416Swnj #include "../netinet/in_systm.h" 4217565Skarels #include "../netinet/ip.h" 4317565Skarels #include "../netinet/ip_var.h" 448460Sroot 458460Sroot #include "../vax/cpu.h" 468460Sroot #include "../vax/mtpr.h" 4717111Sbloom #include "if_uba.h" 4817111Sbloom #include "if_dmc.h" 498460Sroot #include "../vaxuba/ubareg.h" 508460Sroot #include "../vaxuba/ubavar.h" 515725Sroot 5217565Skarels #include "../h/time.h" 5317565Skarels #include "../h/kernel.h" 5417565Skarels 5517565Skarels int dmctimer; /* timer started? */ 5617565Skarels int dmc_timeout = 8; /* timeout value */ 5717565Skarels int dmcwatch(); 5817565Skarels 595725Sroot /* 605725Sroot * Driver information for auto-configuration stuff. 615725Sroot */ 6213061Ssam int dmcprobe(), dmcattach(), dmcinit(), dmcioctl(); 6313061Ssam int dmcoutput(), dmcreset(); 645725Sroot struct uba_device *dmcinfo[NDMC]; 655725Sroot u_short dmcstd[] = { 0 }; 665725Sroot struct uba_driver dmcdriver = 675725Sroot { dmcprobe, 0, dmcattach, 0, dmcstd, "dmc", dmcinfo }; 685725Sroot 6917221Stef #define NRCV 7 7017565Skarels #define NXMT 3 7117221Stef #define NTOT (NRCV + NXMT) 7217565Skarels #define NCMDS (NTOT+4) /* size of command queue */ 7317221Stef 7417565Skarels #define printd if(dmcdebug)printf 7517565Skarels int dmcdebug = 0; 7617565Skarels 7717221Stef /* error reporting intervals */ 7817221Stef #define DMC_RPNBFS 50 7917221Stef #define DMC_RPDSC 1 8017565Skarels #define DMC_RPTMO 10 8117565Skarels #define DMC_RPDCK 10 8217221Stef 8317221Stef struct dmc_command { 8417221Stef char qp_cmd; /* command */ 8517221Stef short qp_ubaddr; /* buffer address */ 8617221Stef short qp_cc; /* character count || XMEM */ 8717221Stef struct dmc_command *qp_next; /* next command on queue */ 8817221Stef }; 8917221Stef 905725Sroot /* 9117221Stef * The dmcuba structures generalize the ifuba structure 9217565Skarels * to an arbitrary number of receive and transmit buffers. 9317221Stef */ 9417221Stef struct ifxmt { 9517565Skarels struct ifrw x_ifrw; /* mapping info */ 9617221Stef struct pte x_map[IF_MAXNUBAMR]; /* output base pages */ 9717221Stef short x_xswapd; /* mask of clusters swapped */ 9817221Stef struct mbuf *x_xtofree; /* pages being dma'd out */ 9917221Stef }; 10017565Skarels 10117221Stef struct dmcuba { 10217221Stef short ifu_uban; /* uba number */ 10317221Stef short ifu_hlen; /* local net header length */ 10417221Stef struct uba_regs *ifu_uba; /* uba regs, in vm */ 10517221Stef struct ifrw ifu_r[NRCV]; /* receive information */ 10617221Stef struct ifxmt ifu_w[NXMT]; /* transmit information */ 10717221Stef /* these should only be pointers */ 10817221Stef short ifu_flags; /* used during uballoc's */ 10917221Stef }; 11017221Stef 11117221Stef struct dmcbufs { 11217221Stef int ubinfo; /* from uballoc */ 11317221Stef short cc; /* buffer size */ 11417221Stef short flags; /* access control */ 11517221Stef }; 11617221Stef #define DBUF_OURS 0 /* buffer is available */ 11717221Stef #define DBUF_DMCS 1 /* buffer claimed by somebody */ 11817221Stef #define DBUF_XMIT 4 /* transmit buffer */ 11917565Skarels #define DBUF_RCV 8 /* receive buffer */ 12017221Stef 12117221Stef struct mbuf *dmc_get(); 12217221Stef 12317221Stef /* 1245725Sroot * DMC software status per interface. 1255725Sroot * 1265725Sroot * Each interface is referenced by a network interface structure, 1275725Sroot * sc_if, which the routing code uses to locate the interface. 1285725Sroot * This structure contains the output queue for the interface, its address, ... 12917221Stef * We also have, for each interface, a set of 7 UBA interface structures 13017221Stef * for each, which 13117221Stef * contain information about the UNIBUS resources held by the interface: 1325725Sroot * map registers, buffered data paths, etc. Information is cached in this 1335725Sroot * structure for use by the if_uba.c routines in running the interface 1345725Sroot * efficiently. 1355725Sroot */ 1365725Sroot struct dmc_softc { 13717221Stef short sc_oused; /* output buffers currently in use */ 13817221Stef short sc_iused; /* input buffers given to DMC */ 13917221Stef short sc_flag; /* flags */ 14017565Skarels int sc_nticks; /* seconds since last interrupt */ 1415725Sroot struct ifnet sc_if; /* network-visible interface */ 14217565Skarels struct dmcbufs sc_rbufs[NRCV]; /* receive buffer info */ 14317221Stef struct dmcbufs sc_xbufs[NXMT]; /* transmit buffer info */ 14417221Stef struct dmcuba sc_ifuba; /* UNIBUS resources */ 1455725Sroot int sc_ubinfo; /* UBA mapping info for base table */ 14617221Stef int sc_errors[4]; /* non-fatal error counters */ 14717221Stef #define sc_datck sc_errors[0] 14817221Stef #define sc_timeo sc_errors[1] 14917221Stef #define sc_nobuf sc_errors[2] 15017221Stef #define sc_disc sc_errors[3] 15117221Stef /* command queue stuff */ 15217565Skarels struct dmc_command sc_cmdbuf[NCMDS]; 15317221Stef struct dmc_command *sc_qhead; /* head of command queue */ 15417221Stef struct dmc_command *sc_qtail; /* tail of command queue */ 15517221Stef struct dmc_command *sc_qactive; /* command in progress */ 15617221Stef struct dmc_command *sc_qfreeh; /* head of list of free cmd buffers */ 15717221Stef struct dmc_command *sc_qfreet; /* tail of list of free cmd buffers */ 15817221Stef /* end command queue stuff */ 1595725Sroot } dmc_softc[NDMC]; 1605725Sroot 1615725Sroot /* flags */ 16217565Skarels #define DMC_ALLOC 01 /* unibus resources allocated */ 16317565Skarels #define DMC_BMAPPED 02 /* base table mapped */ 16417565Skarels #define DMC_RESTART 04 /* software restart in progress */ 16517565Skarels #define DMC_ACTIVE 08 /* device active */ 1665725Sroot 16717565Skarels struct dmc_base { 16817565Skarels short d_base[128]; /* DMC base table */ 1695725Sroot } dmc_base[NDMC]; 1705725Sroot 17117221Stef /* queue manipulation macros */ 17217221Stef #define QUEUE_AT_HEAD(qp, head, tail) \ 17317221Stef (qp)->qp_next = (head); \ 17417221Stef (head) = (qp); \ 17517221Stef if ((tail) == (struct dmc_command *) 0) \ 17617221Stef (tail) = (head) 1775725Sroot 17817221Stef #define QUEUE_AT_TAIL(qp, head, tail) \ 17917221Stef if ((tail)) \ 18017221Stef (tail)->qp_next = (qp); \ 18117221Stef else \ 18217221Stef (head) = (qp); \ 18317221Stef (qp)->qp_next = (struct dmc_command *) 0; \ 18417221Stef (tail) = (qp) 18517221Stef 18617221Stef #define DEQUEUE(head, tail) \ 18717221Stef (head) = (head)->qp_next;\ 18817221Stef if ((head) == (struct dmc_command *) 0)\ 18917221Stef (tail) = (head) 19017221Stef 1915725Sroot dmcprobe(reg) 1925725Sroot caddr_t reg; 1935725Sroot { 1945725Sroot register int br, cvec; 1955725Sroot register struct dmcdevice *addr = (struct dmcdevice *)reg; 1965725Sroot register int i; 1975725Sroot 1985725Sroot #ifdef lint 1995725Sroot br = 0; cvec = br; br = cvec; 2005725Sroot dmcrint(0); dmcxint(0); 2015725Sroot #endif 2025725Sroot addr->bsel1 = DMC_MCLR; 2035725Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 2045725Sroot ; 20517565Skarels if ((addr->bsel1 & DMC_RUN) == 0) { 20617565Skarels printf("dmcprobe: can't start device\n" ); 2076334Ssam return (0); 20817565Skarels } 2095725Sroot addr->bsel0 = DMC_RQI|DMC_IEI; 21017565Skarels /* let's be paranoid */ 21117565Skarels addr->bsel0 |= DMC_RQI|DMC_IEI; 21217565Skarels DELAY(1000000); 2135725Sroot addr->bsel1 = DMC_MCLR; 2145725Sroot for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 2155725Sroot ; 2166334Ssam return (1); 2175725Sroot } 2185725Sroot 2195725Sroot /* 2205725Sroot * Interface exists: make available by filling in network interface 2215725Sroot * record. System will initialize the interface when it is ready 2225725Sroot * to accept packets. 2235725Sroot */ 2245725Sroot dmcattach(ui) 2255725Sroot register struct uba_device *ui; 2265725Sroot { 2275725Sroot register struct dmc_softc *sc = &dmc_softc[ui->ui_unit]; 2285725Sroot 2295725Sroot sc->sc_if.if_unit = ui->ui_unit; 2305725Sroot sc->sc_if.if_name = "dmc"; 2315725Sroot sc->sc_if.if_mtu = DMCMTU; 2325725Sroot sc->sc_if.if_init = dmcinit; 2335725Sroot sc->sc_if.if_output = dmcoutput; 23413061Ssam sc->sc_if.if_ioctl = dmcioctl; 2358976Sroot sc->sc_if.if_reset = dmcreset; 23617221Stef sc->sc_if.if_flags = IFF_POINTOPOINT; 23717221Stef sc->sc_ifuba.ifu_flags = UBA_CANTWAIT; 23817221Stef 23917565Skarels if_attach(&sc->sc_if); 24017565Skarels if (dmctimer == 0) { 24117565Skarels dmctimer = 1; 24217565Skarels timeout(dmcwatch, (caddr_t) 0, hz); 24317221Stef } 2445725Sroot } 2455725Sroot 2465725Sroot /* 2475725Sroot * Reset of interface after UNIBUS reset. 24819862Skarels * If interface is on specified UBA, reset its state. 2495725Sroot */ 2505725Sroot dmcreset(unit, uban) 2515725Sroot int unit, uban; 2525725Sroot { 2535725Sroot register struct uba_device *ui; 25417221Stef register struct dmc_softc *sc = &dmc_softc[unit]; 2555725Sroot 2565725Sroot if (unit >= NDMC || (ui = dmcinfo[unit]) == 0 || ui->ui_alive == 0 || 2575725Sroot ui->ui_ubanum != uban) 2585725Sroot return; 2595725Sroot printf(" dmc%d", unit); 26017565Skarels sc->sc_flag = 0; 26119862Skarels sc->sc_if.if_flags &= ~IFF_RUNNING; 2625725Sroot dmcinit(unit); 2635725Sroot } 2645725Sroot 2655725Sroot /* 2665725Sroot * Initialization of interface; reinitialize UNIBUS usage. 2675725Sroot */ 2685725Sroot dmcinit(unit) 2695725Sroot int unit; 2705725Sroot { 2715725Sroot register struct dmc_softc *sc = &dmc_softc[unit]; 2725725Sroot register struct uba_device *ui = dmcinfo[unit]; 2735725Sroot register struct dmcdevice *addr; 27413061Ssam register struct ifnet *ifp = &sc->sc_if; 27517221Stef register struct ifrw *ifrw; 27617221Stef register struct ifxmt *ifxp; 27717221Stef register struct dmcbufs *rp; 27817565Skarels register struct dmc_command *qp; 27919862Skarels struct ifaddr *ifa; 28017221Stef int base; 28117565Skarels int s; 2825725Sroot 28317221Stef addr = (struct dmcdevice *)ui->ui_addr; 28417221Stef 28519862Skarels /* 28619862Skarels * Check to see that an address has been set 28719862Skarels * (both local and destination for an address family). 28819862Skarels */ 28919862Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 29019862Skarels if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) 29119862Skarels break; 29219862Skarels if (ifa == (struct ifaddr *) 0) 2935725Sroot return; 29417221Stef 29517221Stef if ((addr->bsel1&DMC_RUN) == 0) { 29617221Stef printf("dmcinit: DMC not running\n"); 29719862Skarels ifp->if_flags &= ~IFF_UP; 29817221Stef return; 29917221Stef } 30017221Stef /* map base table */ 30117565Skarels if ((sc->sc_flag & DMC_BMAPPED) == 0) { 30217221Stef sc->sc_ubinfo = uballoc(ui->ui_ubanum, 30317221Stef (caddr_t)&dmc_base[unit], sizeof (struct dmc_base), 0); 30417221Stef sc->sc_flag |= DMC_BMAPPED; 30517221Stef } 30617221Stef /* initialize UNIBUS resources */ 30717221Stef sc->sc_iused = sc->sc_oused = 0; 30819862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 30917565Skarels if (dmc_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 31017565Skarels sizeof(struct dmc_header), (int)btoc(DMCMTU)) == 0) { 31119862Skarels printf("dmc%d: can't allocate uba resources\n", unit); 31213061Ssam ifp->if_flags &= ~IFF_UP; 31313061Ssam return; 31413061Ssam } 31519862Skarels ifp->if_flags |= IFF_RUNNING; 3165725Sroot } 31717221Stef 31817221Stef /* initialize buffer pool */ 31917565Skarels /* receives */ 32017221Stef ifrw = &sc->sc_ifuba.ifu_r[0]; 32117221Stef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 32217221Stef rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 32317565Skarels rp->cc = DMCMTU + sizeof (struct dmc_header); 32417221Stef rp->flags = DBUF_OURS|DBUF_RCV; 32517221Stef ifrw++; 3266363Ssam } 32717221Stef /* transmits */ 32817221Stef ifxp = &sc->sc_ifuba.ifu_w[0]; 32917221Stef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 33017221Stef rp->ubinfo = ifxp->x_ifrw.ifrw_info & 0x3ffff; 33117221Stef rp->cc = 0; 33217221Stef rp->flags = DBUF_OURS|DBUF_XMIT; 33317221Stef ifxp++; 33417221Stef } 33517565Skarels 33617565Skarels /* set up command queues */ 33717565Skarels sc->sc_qfreeh = sc->sc_qfreet 33817565Skarels = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = 33917565Skarels (struct dmc_command *)0; 34017565Skarels /* set up free command buffer list */ 34117565Skarels for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { 34217565Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 34317565Skarels } 34417565Skarels 34517221Stef /* base in */ 34617221Stef base = sc->sc_ubinfo & 0x3ffff; 34717565Skarels dmcload(sc, DMC_BASEI, base, (base>>2) & DMC_XMEM); 34817221Stef /* specify half duplex operation, flags tell if primary */ 34917221Stef /* or secondary station */ 35017221Stef if (ui->ui_flags == 0) 35117565Skarels /* use DDMCP mode in full duplex */ 35217565Skarels dmcload(sc, DMC_CNTLI, 0, 0); 35317221Stef else if (ui->ui_flags == 1) 35417565Skarels /* use MAINTENENCE mode */ 35517565Skarels dmcload(sc, DMC_CNTLI, 0, DMC_MAINT ); 35617221Stef else if (ui->ui_flags == 2) 35717221Stef /* use DDCMP half duplex as primary station */ 35817221Stef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX); 35917221Stef else if (ui->ui_flags == 3) 36017221Stef /* use DDCMP half duplex as secondary station */ 36117221Stef dmcload(sc, DMC_CNTLI, 0, DMC_HDPLX | DMC_SEC); 36217565Skarels 36317565Skarels /* enable operation done interrupts */ 36417565Skarels sc->sc_flag &= ~DMC_ACTIVE; 36517565Skarels while ((addr->bsel2 & DMC_IEO) == 0) 36617565Skarels addr->bsel2 |= DMC_IEO; 36717565Skarels s = spl5(); 36817221Stef /* queue first NRCV buffers for DMC to fill */ 36917221Stef for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 37017221Stef rp->flags |= DBUF_DMCS; 37117221Stef dmcload(sc, DMC_READ, rp->ubinfo, 37217565Skarels (((rp->ubinfo>>2)&DMC_XMEM) | rp->cc)); 37317221Stef sc->sc_iused++; 37417221Stef } 37517565Skarels splx(s); 3765725Sroot } 3775725Sroot 3785725Sroot /* 3795725Sroot * Start output on interface. Get another datagram 3805725Sroot * to send from the interface queue and map it to 3815725Sroot * the interface before starting output. 38217221Stef * 38317221Stef * Must be called at spl 5 3845725Sroot */ 3855725Sroot dmcstart(dev) 3865725Sroot dev_t dev; 3875725Sroot { 3885725Sroot int unit = minor(dev); 3895725Sroot register struct dmc_softc *sc = &dmc_softc[unit]; 3905725Sroot struct mbuf *m; 39117221Stef register struct dmcbufs *rp; 39217221Stef register int n; 3935725Sroot 3945725Sroot /* 39517221Stef * Dequeue up to NXMT requests and map them to the UNIBUS. 39617221Stef * If no more requests, or no dmc buffers available, just return. 3975725Sroot */ 39817221Stef n = 0; 39917221Stef for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { 40017221Stef /* find an available buffer */ 40117565Skarels if ((rp->flags & DBUF_DMCS) == 0) { 40217221Stef IF_DEQUEUE(&sc->sc_if.if_snd, m); 40317221Stef if (m == 0) 40417221Stef return; 40517221Stef /* mark it dmcs */ 40617221Stef rp->flags |= (DBUF_DMCS); 40717221Stef /* 40817221Stef * Have request mapped to UNIBUS for transmission 40917221Stef * and start the output. 41017221Stef */ 41117565Skarels rp->cc = dmcput(&sc->sc_ifuba, n, m); 41217565Skarels rp->cc &= DMC_CCOUNT; 41317221Stef sc->sc_oused++; 41417221Stef dmcload(sc, DMC_WRITE, rp->ubinfo, 41517221Stef rp->cc | ((rp->ubinfo>>2)&DMC_XMEM)); 41617221Stef } 41717221Stef n++; 41817221Stef } 4195725Sroot } 4205725Sroot 4215725Sroot /* 4225725Sroot * Utility routine to load the DMC device registers. 4235725Sroot */ 4245725Sroot dmcload(sc, type, w0, w1) 4255725Sroot register struct dmc_softc *sc; 4265725Sroot int type, w0, w1; 4275725Sroot { 4285725Sroot register struct dmcdevice *addr; 42917221Stef register int unit, sps; 43017221Stef register struct dmc_command *qp; 4315725Sroot 43217565Skarels unit = sc - dmc_softc; 4335725Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; 4345725Sroot sps = spl5(); 43517221Stef 43617221Stef /* grab a command buffer from the free list */ 43717221Stef if ((qp = sc->sc_qfreeh) == (struct dmc_command *)0) 43817221Stef panic("dmc command queue overflow"); 43917221Stef DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); 44017221Stef 44117221Stef /* fill in requested info */ 44217221Stef qp->qp_cmd = (type | DMC_RQI); 44317221Stef qp->qp_ubaddr = w0; 44417221Stef qp->qp_cc = w1; 44517221Stef 44617221Stef if (sc->sc_qactive) { /* command in progress */ 44717221Stef if (type == DMC_READ) { 44817221Stef QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); 44917221Stef } else { 45017221Stef QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); 45117221Stef } 45217221Stef } else { /* command port free */ 45317221Stef sc->sc_qactive = qp; 45417221Stef addr->bsel0 = qp->qp_cmd; 4555725Sroot dmcrint(unit); 45617221Stef } 4575725Sroot splx(sps); 4585725Sroot } 4595725Sroot 4605725Sroot /* 4615725Sroot * DMC interface receiver interrupt. 4625725Sroot * Ready to accept another command, 4635725Sroot * pull one off the command queue. 4645725Sroot */ 4655725Sroot dmcrint(unit) 4665725Sroot int unit; 4675725Sroot { 4685725Sroot register struct dmc_softc *sc; 4695725Sroot register struct dmcdevice *addr; 47017221Stef register struct dmc_command *qp; 4715725Sroot register int n; 4725725Sroot 4735725Sroot addr = (struct dmcdevice *)dmcinfo[unit]->ui_addr; 4745725Sroot sc = &dmc_softc[unit]; 47517221Stef if ((qp = sc->sc_qactive) == (struct dmc_command *) 0) { 47617565Skarels printf("dmc%d: dmcrint no command\n", unit); 47717221Stef return; 47817221Stef } 4795725Sroot while (addr->bsel0&DMC_RDYI) { 48017221Stef addr->sel4 = qp->qp_ubaddr; 48117221Stef addr->sel6 = qp->qp_cc; 4825725Sroot addr->bsel0 &= ~(DMC_IEI|DMC_RQI); 48317221Stef /* free command buffer */ 48417221Stef QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 48517221Stef while (addr->bsel0 & DMC_RDYI) { 48617221Stef /* 48717221Stef * Can't check for RDYO here 'cause 48817221Stef * this routine isn't reentrant! 48917221Stef */ 49017221Stef DELAY(5); 49117221Stef } 49217221Stef /* move on to next command */ 49317565Skarels if ((sc->sc_qactive = sc->sc_qhead) == (struct dmc_command *)0) 49417565Skarels break; /* all done */ 49517221Stef /* more commands to do, start the next one */ 49617221Stef qp = sc->sc_qactive; 49717221Stef DEQUEUE(sc->sc_qhead, sc->sc_qtail); 49817221Stef addr->bsel0 = qp->qp_cmd; 4995725Sroot n = RDYSCAN; 50017565Skarels while (n-- > 0) 50117565Skarels if ((addr->bsel0&DMC_RDYI) || (addr->bsel2&DMC_RDYO)) 50217565Skarels break; 5035725Sroot } 50417221Stef if (sc->sc_qactive) { 50517221Stef addr->bsel0 |= DMC_IEI|DMC_RQI; 50617221Stef /* VMS does it twice !*$%@# */ 50717221Stef addr->bsel0 |= DMC_IEI|DMC_RQI; 50817221Stef } 50917565Skarels 5105725Sroot } 5115725Sroot 5125725Sroot /* 5135725Sroot * DMC interface transmitter interrupt. 51417221Stef * A transfer may have completed, check for errors. 5155725Sroot * If it was a read, notify appropriate protocol. 5165725Sroot * If it was a write, pull the next one off the queue. 5175725Sroot */ 5185725Sroot dmcxint(unit) 5195725Sroot int unit; 5205725Sroot { 5215725Sroot register struct dmc_softc *sc; 52213065Ssam register struct ifnet *ifp; 5235725Sroot struct uba_device *ui = dmcinfo[unit]; 5245725Sroot struct dmcdevice *addr; 5255725Sroot struct mbuf *m; 52617565Skarels struct ifqueue *inq; 52717221Stef int arg, pkaddr, cmd, len; 52817221Stef register struct ifrw *ifrw; 52917221Stef register struct dmcbufs *rp; 53017565Skarels register struct ifxmt *ifxp; 53117565Skarels struct dmc_header *dh; 53217565Skarels int off, resid; 5335725Sroot 5345725Sroot addr = (struct dmcdevice *)ui->ui_addr; 53517221Stef sc = &dmc_softc[unit]; 53617221Stef ifp = &sc->sc_if; 53717221Stef 53817565Skarels while (addr->bsel2 & DMC_RDYO) { 5395725Sroot 54017565Skarels cmd = addr->bsel2 & 0xff; 54117565Skarels arg = addr->sel6 & 0xffff; 54217565Skarels /* reconstruct UNIBUS address of buffer returned to us */ 54317565Skarels pkaddr = ((arg&DMC_XMEM)<<2) | (addr->sel4 & 0xffff); 54417565Skarels /* release port */ 54517565Skarels addr->bsel2 &= ~DMC_RDYO; 54617565Skarels switch (cmd & 07) { 54717565Skarels 54817565Skarels case DMC_OUR: 54917565Skarels /* 55017565Skarels * A read has completed. 55117565Skarels * Pass packet to type specific 55217565Skarels * higher-level input routine. 55317565Skarels */ 55417565Skarels ifp->if_ipackets++; 55517565Skarels /* find location in dmcuba struct */ 55617565Skarels ifrw= &sc->sc_ifuba.ifu_r[0]; 55717565Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 55817565Skarels if(rp->ubinfo == pkaddr) 55917565Skarels break; 56017565Skarels ifrw++; 56117565Skarels } 56217565Skarels if (rp >= &sc->sc_rbufs[NRCV]) 56317565Skarels panic("dmc rcv"); 56417565Skarels if ((rp->flags & DBUF_DMCS) == 0) 56517565Skarels printf("dmc%d: done unalloc rbuf\n", unit); 56617565Skarels 56717565Skarels len = (arg & DMC_CCOUNT) - sizeof (struct dmc_header); 56817565Skarels if (len < 0 || len > DMCMTU) { 56917565Skarels ifp->if_ierrors++; 57017565Skarels printd("dmc%d: bad rcv pkt addr 0x%x len 0x%x\n", 57117565Skarels unit, pkaddr, len); 57217565Skarels goto setup; 57317565Skarels } 57417565Skarels /* 57517565Skarels * Deal with trailer protocol: if type is trailer 57617565Skarels * get true type from first 16-bit word past data. 57717565Skarels * Remember that type was trailer by setting off. 57817565Skarels */ 57917565Skarels dh = (struct dmc_header *)ifrw->ifrw_addr; 58017565Skarels dh->dmc_type = ntohs((u_short)dh->dmc_type); 58117565Skarels #define dmcdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) 58217565Skarels if (dh->dmc_type >= DMC_TRAILER && 58317565Skarels dh->dmc_type < DMC_TRAILER+DMC_NTRAILER) { 58417565Skarels off = (dh->dmc_type - DMC_TRAILER) * 512; 58517565Skarels if (off >= DMCMTU) 58617565Skarels goto setup; /* sanity */ 58717565Skarels dh->dmc_type = ntohs(*dmcdataaddr(dh, off, u_short *)); 58817565Skarels resid = ntohs(*(dmcdataaddr(dh, off+2, u_short *))); 58917565Skarels if (off + resid > len) 59017565Skarels goto setup; /* sanity */ 59117565Skarels len = off + resid; 59217565Skarels } else 59317565Skarels off = 0; 59417565Skarels if (len == 0) 59517565Skarels goto setup; 59617565Skarels 59717565Skarels /* 59817565Skarels * Pull packet off interface. Off is nonzero if 59917565Skarels * packet has trailing header; dmc_get will then 60017565Skarels * force this header information to be at the front, 60117565Skarels * but we still have to drop the type and length 60217565Skarels * which are at the front of any trailer data. 60317565Skarels */ 60417565Skarels m = dmc_get(&sc->sc_ifuba, ifrw, len, off); 60517565Skarels if (m == 0) 60617565Skarels goto setup; 60717565Skarels if (off) { 60817565Skarels m->m_off += 2 * sizeof (u_short); 60917565Skarels m->m_len -= 2 * sizeof (u_short); 61017565Skarels } 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 62417565Skarels if (IF_QFULL(inq)) { 62517565Skarels IF_DROP(inq); 62617565Skarels m_freem(m); 62717565Skarels } else 62817565Skarels IF_ENQUEUE(inq, m); 62917221Stef 63017565Skarels setup: 63117565Skarels /* is this needed? */ 63217565Skarels rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 6335725Sroot 63417565Skarels dmcload(sc, DMC_READ, rp->ubinfo, 63517565Skarels ((rp->ubinfo >> 2) & DMC_XMEM) | rp->cc); 63617565Skarels break; 6375725Sroot 63817565Skarels case DMC_OUX: 63917565Skarels /* 64017565Skarels * A write has completed, start another 64117565Skarels * transfer if there is more data to send. 64217565Skarels */ 64317565Skarels ifp->if_opackets++; 64417565Skarels /* find associated dmcbuf structure */ 64517565Skarels ifxp = &sc->sc_ifuba.ifu_w[0]; 64617565Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 64717565Skarels if(rp->ubinfo == pkaddr) 64817565Skarels break; 64917565Skarels ifxp++; 65017565Skarels } 65117565Skarels if (rp >= &sc->sc_xbufs[NXMT]) { 65217565Skarels printf("dmc%d: bad packet address 0x%x\n", 65317565Skarels unit, pkaddr); 65417565Skarels break; 65517565Skarels } 65617565Skarels if ((rp->flags & DBUF_DMCS) == 0) 65717565Skarels printf("dmc%d: unallocated packet 0x%x\n", 65817565Skarels unit, pkaddr); 65917565Skarels /* mark buffer free */ 66017565Skarels if (ifxp->x_xtofree) { 66117565Skarels (void)m_freem(ifxp->x_xtofree); 66217565Skarels ifxp->x_xtofree = 0; 66317565Skarels } 66417565Skarels rp->flags &= ~DBUF_DMCS; 66517565Skarels sc->sc_oused--; 66617565Skarels sc->sc_nticks = 0; 66717565Skarels sc->sc_flag |= DMC_ACTIVE; 66817565Skarels break; 66917221Stef 67017565Skarels case DMC_CNTLO: 67117565Skarels arg &= DMC_CNTMASK; 67217565Skarels if (arg & DMC_FATAL) { 67317565Skarels printd("dmc%d: fatal error, flags=%b\n", 67417565Skarels unit, arg, CNTLO_BITS); 67517565Skarels dmcrestart(unit); 67617565Skarels break; 67717565Skarels } 67817565Skarels /* ACCUMULATE STATISTICS */ 67917221Stef switch(arg) { 68017221Stef case DMC_NOBUFS: 68117565Skarels ifp->if_ierrors++; 68217565Skarels if ((sc->sc_nobuf++ % DMC_RPNBFS) == 0) 68317565Skarels goto report; 68417565Skarels break; 68517221Stef case DMC_DISCONN: 68617565Skarels if ((sc->sc_disc++ % DMC_RPDSC) == 0) 68717565Skarels goto report; 68817565Skarels break; 68917221Stef case DMC_TIMEOUT: 69017565Skarels if ((sc->sc_timeo++ % DMC_RPTMO) == 0) 69117565Skarels goto report; 69217565Skarels break; 69317221Stef case DMC_DATACK: 69417565Skarels ifp->if_oerrors++; 69517565Skarels if ((sc->sc_datck++ % DMC_RPDCK) == 0) 69617565Skarels goto report; 69717565Skarels break; 69817221Stef default: 69917221Stef goto report; 70017221Stef } 70117221Stef break; 70217221Stef report: 70317565Skarels printd("dmc%d: soft error, flags=%b\n", unit, 70417565Skarels arg, CNTLO_BITS); 70517565Skarels if ((sc->sc_flag & DMC_RESTART) == 0) { 70617565Skarels /* 70717565Skarels * kill off the dmc to get things 70817565Skarels * going again by generating a 70917565Skarels * procedure error 71017565Skarels */ 71117565Skarels sc->sc_flag |= DMC_RESTART; 71217565Skarels arg = sc->sc_ubinfo & 0x3ffff; 71317565Skarels dmcload(sc, DMC_BASEI, arg, (arg>>2)&DMC_XMEM); 71417565Skarels } 71517565Skarels break; 71617565Skarels 71717565Skarels default: 71817565Skarels printf("dmc%d: bad control %o\n", unit, cmd); 71917565Skarels break; 7205725Sroot } 7215725Sroot } 72217565Skarels dmcstart(unit); 72317221Stef return; 7245725Sroot } 7255725Sroot 7265725Sroot /* 7275725Sroot * DMC output routine. 72817565Skarels * Encapsulate a packet of type family for the dmc. 72917565Skarels * Use trailer local net encapsulation if enough data in first 73017565Skarels * packet leaves a multiple of 512 bytes of data in remainder. 7315725Sroot */ 73217565Skarels dmcoutput(ifp, m0, dst) 7335725Sroot register struct ifnet *ifp; 73417565Skarels register struct mbuf *m0; 7356334Ssam struct sockaddr *dst; 7365725Sroot { 73717565Skarels int type, error, s; 73817565Skarels register struct mbuf *m = m0; 73917565Skarels register struct dmc_header *dh; 74017565Skarels register int off; 7415725Sroot 74217565Skarels switch (dst->sa_family) { 74317565Skarels #ifdef INET 74417565Skarels case AF_INET: 74517565Skarels off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 74617565Skarels if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 74717565Skarels if (off > 0 && (off & 0x1ff) == 0 && 74817565Skarels m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 74917565Skarels type = DMC_TRAILER + (off>>9); 75017565Skarels m->m_off -= 2 * sizeof (u_short); 75117565Skarels m->m_len += 2 * sizeof (u_short); 75217565Skarels *mtod(m, u_short *) = htons((u_short)DMC_IPTYPE); 75317565Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 75417565Skarels goto gottrailertype; 75517565Skarels } 75617565Skarels type = DMC_IPTYPE; 75717565Skarels off = 0; 75817565Skarels goto gottype; 75917565Skarels #endif 76017565Skarels 76117565Skarels case AF_UNSPEC: 76217565Skarels dh = (struct dmc_header *)dst->sa_data; 76317565Skarels type = dh->dmc_type; 76417565Skarels goto gottype; 76517565Skarels 76617565Skarels default: 76717565Skarels printf("dmc%d: can't handle af%d\n", ifp->if_unit, 76817565Skarels dst->sa_family); 76917565Skarels error = EAFNOSUPPORT; 77017565Skarels goto bad; 7715725Sroot } 77217565Skarels 77317565Skarels gottrailertype: 77417565Skarels /* 77517565Skarels * Packet to be sent as a trailer; move first packet 77617565Skarels * (control information) to end of chain. 77717565Skarels */ 77817565Skarels while (m->m_next) 77917565Skarels m = m->m_next; 78017565Skarels m->m_next = m0; 78117565Skarels m = m0->m_next; 78217565Skarels m0->m_next = 0; 78317565Skarels m0 = m; 78417565Skarels 78517565Skarels gottype: 78617565Skarels /* 78717565Skarels * Add local network header 78817565Skarels * (there is space for a uba on a vax to step on) 78917565Skarels */ 79017565Skarels if (m->m_off > MMAXOFF || 79117565Skarels MMINOFF + sizeof(struct dmc_header) > m->m_off) { 79217565Skarels m = m_get(M_DONTWAIT, MT_HEADER); 79317565Skarels if (m == 0) { 79417565Skarels error = ENOBUFS; 79517565Skarels goto bad; 79617565Skarels } 79717565Skarels m->m_next = m0; 79817565Skarels m->m_off = MMINOFF; 79917565Skarels m->m_len = sizeof (struct dmc_header); 80017565Skarels } else { 80117565Skarels m->m_off -= sizeof (struct dmc_header); 80217565Skarels m->m_len += sizeof (struct dmc_header); 80317565Skarels } 80417565Skarels dh = mtod(m, struct dmc_header *); 80517565Skarels dh->dmc_type = htons((u_short)type); 80617565Skarels 80717565Skarels /* 80817565Skarels * Queue message on interface, and start output if interface 80917565Skarels * not yet active. 81017565Skarels */ 81117565Skarels s = splimp(); 8126207Swnj if (IF_QFULL(&ifp->if_snd)) { 8136207Swnj IF_DROP(&ifp->if_snd); 8146334Ssam m_freem(m); 8156207Swnj splx(s); 8166502Ssam return (ENOBUFS); 8176207Swnj } 8185725Sroot IF_ENQUEUE(&ifp->if_snd, m); 81917221Stef dmcstart(ifp->if_unit); 8205725Sroot splx(s); 8216502Ssam return (0); 82217565Skarels 82317565Skarels bad: 82417565Skarels m_freem(m0); 82517565Skarels return (error); 8265725Sroot } 82713061Ssam 82817565Skarels 82913061Ssam /* 83013061Ssam * Process an ioctl request. 83113061Ssam */ 83213061Ssam dmcioctl(ifp, cmd, data) 83313061Ssam register struct ifnet *ifp; 83413061Ssam int cmd; 83513061Ssam caddr_t data; 83613061Ssam { 83713061Ssam int s = splimp(), error = 0; 83813061Ssam 83913061Ssam switch (cmd) { 84013061Ssam 84113061Ssam case SIOCSIFADDR: 84217221Stef ifp->if_flags |= IFF_UP; 84319862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 84419862Skarels dmcinit(ifp->if_unit); 84513061Ssam break; 84613061Ssam 84713061Ssam case SIOCSIFDSTADDR: 84819862Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 84919862Skarels dmcinit(ifp->if_unit); 85013061Ssam break; 85117221Stef 85213061Ssam default: 85313061Ssam error = EINVAL; 85413061Ssam } 85513061Ssam splx(s); 85613061Ssam return (error); 85713061Ssam } 85817221Stef 85917565Skarels 86017221Stef /* 86117221Stef * Routines supporting UNIBUS network interfaces. 86217221Stef */ 86317221Stef 86417221Stef /* 86517221Stef * Init UNIBUS for interface on uban whose headers of size hlen are to 86617221Stef * end on a page boundary. We allocate a UNIBUS map register for the page 86717221Stef * with the header, and nmr more UNIBUS map registers for i/o on the adapter, 86817221Stef * doing this for each receive and transmit buffer. We also 86917221Stef * allocate page frames in the mbuffer pool for these pages. 87017221Stef */ 87117221Stef dmc_ubainit(ifu, uban, hlen, nmr) 87217221Stef register struct dmcuba *ifu; 87317221Stef int uban, hlen, nmr; 87417221Stef { 87517221Stef register caddr_t cp, dp; 87617221Stef register struct ifrw *ifrw; 87717221Stef register struct ifxmt *ifxp; 87817221Stef int i, ncl; 87917221Stef 88017221Stef ncl = clrnd(nmr + CLSIZE) / CLSIZE; 88117565Skarels if (ifu->ifu_r[0].ifrw_addr) 88217221Stef /* 88317221Stef * If the first read buffer has a non-zero 88417221Stef * address, it means we have already allocated core 88517221Stef */ 88617221Stef cp = ifu->ifu_r[0].ifrw_addr - (CLBYTES - hlen); 88717565Skarels else { 88817221Stef cp = m_clalloc(NTOT * ncl, MPG_SPACE); 88917221Stef if (cp == 0) 89017221Stef return (0); 89117221Stef ifu->ifu_hlen = hlen; 89217221Stef ifu->ifu_uban = uban; 89317221Stef ifu->ifu_uba = uba_hd[uban].uh_uba; 89417221Stef dp = cp + CLBYTES - hlen; 89517221Stef for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) { 89617221Stef ifrw->ifrw_addr = dp; 89717221Stef dp += ncl * CLBYTES; 89817221Stef } 89917221Stef for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) { 90017221Stef ifxp->x_ifrw.ifrw_addr = dp; 90117221Stef dp += ncl * CLBYTES; 90217221Stef } 90317221Stef } 90417221Stef /* allocate for receive ring */ 90517221Stef for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) { 90617221Stef if (dmc_ubaalloc(ifu, ifrw, nmr) == 0) { 90717221Stef struct ifrw *rw; 90817221Stef 90917221Stef for (rw = ifu->ifu_r; rw < ifrw; rw++) 91017221Stef ubarelse(ifu->ifu_uban, &rw->ifrw_info); 91117221Stef goto bad; 91217221Stef } 91317221Stef } 91417221Stef /* and now transmit ring */ 91517221Stef for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) { 91617221Stef ifrw = &ifxp->x_ifrw; 91717221Stef if (dmc_ubaalloc(ifu, ifrw, nmr) == 0) { 91817221Stef struct ifxmt *xp; 91917221Stef 92017221Stef for (xp = ifu->ifu_w; xp < ifxp; xp++) 92117221Stef ubarelse(ifu->ifu_uban, &xp->x_ifrw.ifrw_info); 92217221Stef for (ifrw = ifu->ifu_r; ifrw < &ifu->ifu_r[NRCV]; ifrw++) 92317221Stef ubarelse(ifu->ifu_uban, &ifrw->ifrw_info); 92417221Stef goto bad; 92517221Stef } 92617221Stef for (i = 0; i < nmr; i++) 92717221Stef ifxp->x_map[i] = ifrw->ifrw_mr[i]; 92817221Stef ifxp->x_xswapd = 0; 92917221Stef } 93017221Stef return (1); 93117221Stef bad: 93217221Stef m_pgfree(cp, NTOT * ncl); 93317221Stef ifu->ifu_r[0].ifrw_addr = 0; 93417221Stef return (0); 93517221Stef } 93617221Stef 93717221Stef /* 93817221Stef * Setup either a ifrw structure by allocating UNIBUS map registers, 93917221Stef * possibly a buffered data path, and initializing the fields of 94017221Stef * the ifrw structure to minimize run-time overhead. 94117221Stef */ 94217221Stef static 94317221Stef dmc_ubaalloc(ifu, ifrw, nmr) 94417221Stef struct dmcuba *ifu; 94517221Stef register struct ifrw *ifrw; 94617221Stef int nmr; 94717221Stef { 94817221Stef register int info; 94917221Stef 95017221Stef info = 95117221Stef uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen, 95217221Stef ifu->ifu_flags); 95317221Stef if (info == 0) 95417221Stef return (0); 95517221Stef ifrw->ifrw_info = info; 95617221Stef ifrw->ifrw_bdp = UBAI_BDP(info); 95717221Stef ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT); 95817221Stef ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1]; 95917221Stef return (1); 96017221Stef } 96117221Stef 96217221Stef /* 96317221Stef * Pull read data off a interface. 96417221Stef * Len is length of data, with local net header stripped. 96517221Stef * Off is non-zero if a trailer protocol was used, and 96617221Stef * gives the offset of the trailer information. 96717221Stef * We copy the trailer information and then all the normal 96817221Stef * data into mbufs. When full cluster sized units are present 96917221Stef * on the interface on cluster boundaries we can get them more 97017221Stef * easily by remapping, and take advantage of this here. 97117221Stef */ 97217221Stef struct mbuf * 97317221Stef dmc_get(ifu, ifrw, totlen, off0) 97417221Stef register struct dmcuba *ifu; 97517221Stef register struct ifrw *ifrw; 97617221Stef int totlen, off0; 97717221Stef { 97817221Stef struct mbuf *top, **mp, *m; 97917221Stef int off = off0, len; 98017221Stef register caddr_t cp = ifrw->ifrw_addr + ifu->ifu_hlen; 98117221Stef 98217221Stef top = 0; 98317221Stef mp = ⊤ 98417221Stef while (totlen > 0) { 98517221Stef MGET(m, M_DONTWAIT, MT_DATA); 98617221Stef if (m == 0) 98717221Stef goto bad; 98817221Stef if (off) { 98917221Stef len = totlen - off; 99017221Stef cp = ifrw->ifrw_addr + ifu->ifu_hlen + off; 99117221Stef } else 99217221Stef len = totlen; 99317221Stef if (len >= CLBYTES) { 99417221Stef struct mbuf *p; 99517221Stef struct pte *cpte, *ppte; 99617221Stef int x, *ip, i; 99717221Stef 99817221Stef MCLGET(p, 1); 99917221Stef if (p == 0) 100017221Stef goto nopage; 100117221Stef len = m->m_len = CLBYTES; 100217221Stef m->m_off = (int)p - (int)m; 100317221Stef if (!claligned(cp)) 100417221Stef goto copy; 100517221Stef 100617221Stef /* 100717221Stef * Switch pages mapped to UNIBUS with new page p, 100817221Stef * as quick form of copy. Remap UNIBUS and invalidate. 100917221Stef */ 101017221Stef cpte = &Mbmap[mtocl(cp)*CLSIZE]; 101117221Stef ppte = &Mbmap[mtocl(p)*CLSIZE]; 101217221Stef x = btop(cp - ifrw->ifrw_addr); 101317221Stef ip = (int *)&ifrw->ifrw_mr[x]; 101417221Stef for (i = 0; i < CLSIZE; i++) { 101517221Stef struct pte t; 101617221Stef t = *ppte; *ppte++ = *cpte; *cpte = t; 101717221Stef *ip++ = 101817221Stef cpte++->pg_pfnum|ifrw->ifrw_proto; 101917221Stef mtpr(TBIS, cp); 102017221Stef cp += NBPG; 102117221Stef mtpr(TBIS, (caddr_t)p); 102217221Stef p += NBPG / sizeof (*p); 102317221Stef } 102417221Stef goto nocopy; 102517221Stef } 102617221Stef nopage: 102717221Stef m->m_len = MIN(MLEN, len); 102817221Stef m->m_off = MMINOFF; 102917221Stef copy: 103017221Stef bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len); 103117221Stef cp += m->m_len; 103217221Stef nocopy: 103317221Stef *mp = m; 103417221Stef mp = &m->m_next; 103517221Stef if (off) { 103617221Stef /* sort of an ALGOL-W style for statement... */ 103717221Stef off += m->m_len; 103817221Stef if (off == totlen) { 103917221Stef cp = ifrw->ifrw_addr + ifu->ifu_hlen; 104017221Stef off = 0; 104117221Stef totlen = off0; 104217221Stef } 104317221Stef } else 104417221Stef totlen -= m->m_len; 104517221Stef } 104617221Stef return (top); 104717221Stef bad: 104817221Stef m_freem(top); 104917221Stef return (0); 105017221Stef } 105117221Stef 105217221Stef /* 105317221Stef * Map a chain of mbufs onto a network interface 105417221Stef * in preparation for an i/o operation. 105517221Stef * The argument chain of mbufs includes the local network 105617221Stef * header which is copied to be in the mapped, aligned 105717221Stef * i/o space. 105817221Stef */ 105917221Stef dmcput(ifu, n, m) 106017221Stef struct dmcuba *ifu; 106117221Stef int n; 106217221Stef register struct mbuf *m; 106317221Stef { 106417221Stef register struct mbuf *mp; 106517221Stef register caddr_t cp; 106617221Stef register struct ifxmt *ifxp; 106717221Stef register struct ifrw *ifrw; 106817221Stef register int i; 106917221Stef int xswapd = 0; 107017221Stef int x, cc, t; 107117221Stef caddr_t dp; 107217221Stef 107317221Stef ifxp = &ifu->ifu_w[n]; 107417221Stef ifrw = &ifxp->x_ifrw; 107517221Stef cp = ifrw->ifrw_addr; 107617221Stef while (m) { 107717221Stef dp = mtod(m, char *); 107817221Stef if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) { 107917221Stef struct pte *pte; int *ip; 108017221Stef pte = &Mbmap[mtocl(dp)*CLSIZE]; 108117221Stef x = btop(cp - ifrw->ifrw_addr); 108217221Stef ip = (int *)&ifrw->ifrw_mr[x]; 108317221Stef for (i = 0; i < CLSIZE; i++) 108417221Stef *ip++ = ifrw->ifrw_proto | pte++->pg_pfnum; 108517221Stef xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT)); 108617221Stef mp = m->m_next; 108717221Stef m->m_next = ifxp->x_xtofree; 108817221Stef ifxp->x_xtofree = m; 108917221Stef cp += m->m_len; 109017221Stef } else { 109117221Stef bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len); 109217221Stef cp += m->m_len; 109317221Stef MFREE(m, mp); 109417221Stef } 109517221Stef m = mp; 109617221Stef } 109717221Stef 109817221Stef /* 109917221Stef * Xswapd is the set of clusters we just mapped out. Ifxp->x_xswapd 110017221Stef * is the set of clusters mapped out from before. We compute 110117221Stef * the number of clusters involved in this operation in x. 110217221Stef * Clusters mapped out before and involved in this operation 110317221Stef * should be unmapped so original pages will be accessed by the device. 110417221Stef */ 110517221Stef cc = cp - ifrw->ifrw_addr; 110617221Stef x = ((cc - ifu->ifu_hlen) + CLBYTES - 1) >> CLSHIFT; 110717221Stef ifxp->x_xswapd &= ~xswapd; 110817221Stef while (i = ffs(ifxp->x_xswapd)) { 110917221Stef i--; 111017221Stef if (i >= x) 111117221Stef break; 111217221Stef ifxp->x_xswapd &= ~(1<<i); 111317221Stef i *= CLSIZE; 111417221Stef for (t = 0; t < CLSIZE; t++) { 111517221Stef ifrw->ifrw_mr[i] = ifxp->x_map[i]; 111617221Stef i++; 111717221Stef } 111817221Stef } 111917221Stef ifxp->x_xswapd |= xswapd; 112017221Stef return (cc); 112117221Stef } 112217565Skarels 112317565Skarels /* 112417565Skarels * Restart after a fatal error. 112517565Skarels * Clear device and reinitialize. 112617565Skarels */ 112717565Skarels dmcrestart(unit) 112817565Skarels int unit; 112917565Skarels { 113017565Skarels register struct dmc_softc *sc = &dmc_softc[unit]; 113117565Skarels register struct uba_device *ui = dmcinfo[unit]; 113217565Skarels register struct dmcdevice *addr; 113317565Skarels register struct ifxmt *ifxp; 113417565Skarels register int i; 113517565Skarels register struct mbuf *m; 113617565Skarels struct dmcuba *ifu; 113717565Skarels 113817565Skarels addr = (struct dmcdevice *)ui->ui_addr; 113917565Skarels ifu = &sc->sc_ifuba; 114017565Skarels #ifdef DEBUG 114117565Skarels /* dump base table */ 114217565Skarels printf("dmc%d base table:\n", unit); 114317565Skarels for (i = 0; i < sizeof (struct dmc_base); i++) 114417565Skarels printf("%o\n" ,dmc_base[unit].d_base[i]); 114513085Ssam #endif 114617565Skarels /* 114717565Skarels * Let the DMR finish the MCLR. At 1 Mbit, it should do so 114817565Skarels * in about a max of 6.4 milliseconds with diagnostics enabled. 114917565Skarels */ 115017565Skarels addr->bsel1 = DMC_MCLR; 115117565Skarels for (i = 100000; i && (addr->bsel1 & DMC_RUN) == 0; i--) 115217565Skarels ; 115317565Skarels /* Did the timer expire or did the DMR finish? */ 115417565Skarels if ((addr->bsel1 & DMC_RUN) == 0) { 115517565Skarels printf("dmc%d: M820 Test Failed\n", unit); 115617565Skarels return; 115717565Skarels } 115817565Skarels 115917565Skarels #ifdef notdef /* tef sez why throw these packets away??? */ 116017565Skarels /* purge send queue */ 116117565Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 116217565Skarels while (m) { 116317565Skarels m_freem(m); 116417565Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 116517565Skarels } 116617565Skarels #endif 116717565Skarels for (ifxp = ifu->ifu_w; ifxp < &ifu->ifu_w[NXMT]; ifxp++) { 116817565Skarels if (ifxp->x_xtofree) { 116917565Skarels (void) m_freem(ifxp->x_xtofree); 117017565Skarels ifxp->x_xtofree = 0; 117117565Skarels } 117217565Skarels } 117317565Skarels 117417565Skarels /* restart DMC */ 117517565Skarels dmcinit(unit); 117617565Skarels sc->sc_flag &= ~DMC_RESTART; 117717565Skarels sc->sc_if.if_collisions++; /* why not? */ 117817565Skarels } 117917565Skarels 118017565Skarels /* 118117565Skarels * Check to see that transmitted packets don't 118217565Skarels * lose interrupts. The device has to be active. 118317565Skarels */ 118417565Skarels dmcwatch() 118517565Skarels { 118617565Skarels register struct uba_device *ui; 118717565Skarels register struct dmc_softc *sc; 118817565Skarels struct dmcdevice *addr; 118917565Skarels register int i; 119017565Skarels 119117565Skarels for (i = 0; i < NDMC; i++) { 119217565Skarels sc = &dmc_softc[i]; 119317565Skarels if ((sc->sc_flag & DMC_ACTIVE) == 0) 119417565Skarels continue; 119517565Skarels if ((ui = dmcinfo[i]) == 0 || ui->ui_alive == 0) 119617565Skarels continue; 119717565Skarels if (sc->sc_oused) { 119817565Skarels sc->sc_nticks++; 119917565Skarels if (sc->sc_nticks > dmc_timeout) { 120017565Skarels sc->sc_nticks = 0; 120117565Skarels addr = (struct dmcdevice *)ui->ui_addr; 120217565Skarels printd("dmc%d hung: bsel0=%b bsel2=%b\n", i, 120317565Skarels addr->bsel0 & 0xff, DMC0BITS, 120417565Skarels addr->bsel2 & 0xff, DMC2BITS); 120517565Skarels dmcrestart(i); 120617565Skarels } 120717565Skarels } 120817565Skarels } 120917565Skarels timeout(dmcwatch, (caddr_t) 0, hz); 121017565Skarels } 121117565Skarels #endif 1212