1*31908Skarels /* 2*31908Skarels * @(#)if_dmv.c 7.1 (Berkeley) 07/20/87 3*31908Skarels * DMV-11 Driver 4*31908Skarels * 5*31908Skarels * Qbus Sync DDCMP interface - DMV operated in full duplex, point to point mode 6*31908Skarels * 7*31908Skarels * Derived from 4.3 release if_dmv.c rev. 6.12 dated 4/23/86 8*31908Skarels * (which wasn't the 4.3 release!) 9*31908Skarels * 10*31908Skarels * Bob Kridle 11*31908Skarels * mt Xinu 12*31908Skarels */ 13*31908Skarels 14*31908Skarels #include "dmv.h" 15*31908Skarels #if NDMV > 0 16*31908Skarels 17*31908Skarels 18*31908Skarels #include "../machine/pte.h" 19*31908Skarels 20*31908Skarels #include "param.h" 21*31908Skarels #include "systm.h" 22*31908Skarels #include "mbuf.h" 23*31908Skarels #include "buf.h" 24*31908Skarels #include "ioctl.h" /* must precede tty.h */ 25*31908Skarels #include "tty.h" 26*31908Skarels #include "protosw.h" 27*31908Skarels #include "socket.h" 28*31908Skarels #include "syslog.h" 29*31908Skarels #include "vmmac.h" 30*31908Skarels #include "errno.h" 31*31908Skarels 32*31908Skarels #include "../net/if.h" 33*31908Skarels #include "../net/netisr.h" 34*31908Skarels #include "../net/route.h" 35*31908Skarels 36*31908Skarels #ifdef INET 37*31908Skarels #include "../netinet/in.h" 38*31908Skarels #include "../netinet/in_systm.h" 39*31908Skarels #include "../netinet/in_var.h" 40*31908Skarels #include "../netinet/ip.h" 41*31908Skarels #endif 42*31908Skarels 43*31908Skarels #include "../vax/cpu.h" 44*31908Skarels #include "../vax/mtpr.h" 45*31908Skarels #include "if_uba.h" 46*31908Skarels #include "if_dmv.h" 47*31908Skarels #include "../vaxuba/ubareg.h" 48*31908Skarels #include "../vaxuba/ubavar.h" 49*31908Skarels 50*31908Skarels #include "../h/time.h" 51*31908Skarels #include "../h/kernel.h" 52*31908Skarels 53*31908Skarels int dmvtimer; /* timer started? */ 54*31908Skarels int dmv_timeout = 8; /* timeout value */ 55*31908Skarels int dmvwatch(); 56*31908Skarels 57*31908Skarels /* 58*31908Skarels * Driver information for auto-configuration stuff. 59*31908Skarels */ 60*31908Skarels int dmvprobe(), dmvattach(), dmvinit(), dmvioctl(); 61*31908Skarels int dmvoutput(), dmvreset(); 62*31908Skarels struct uba_device *dmvinfo[NDMV]; 63*31908Skarels u_short dmvstd[] = { 0 }; 64*31908Skarels struct uba_driver dmvdriver = 65*31908Skarels { dmvprobe, 0, dmvattach, 0, dmvstd, "dmv", dmvinfo }; 66*31908Skarels 67*31908Skarels /* 68*31908Skarels * Don't really know how many buffers/commands can be queued to a DMV-11. 69*31908Skarels * Manual doesn't say... Perhaps we can look at a DEC driver some day. 70*31908Skarels * These numbers ame from DMV/DMR driver. 71*31908Skarels */ 72*31908Skarels #define NRCV 5 73*31908Skarels #define NXMT 3 74*31908Skarels #define NCMDS (NRCV+NXMT+4) /* size of command queue */ 75*31908Skarels 76*31908Skarels #define printd if (sc->sc_if.if_flags & IFF_DEBUG) \ 77*31908Skarels printf("DMVDEBUG: dmv%d: ", unit), printf 78*31908Skarels 79*31908Skarels /* error reporting intervals */ 80*31908Skarels 81*31908Skarels #define DMV_RPRTE 1 82*31908Skarels #define DMV_RPTTE 1 83*31908Skarels #define DMV_RPSTE 1 84*31908Skarels #define DMV_RPNXM 1 85*31908Skarels #define DMV_RPMODD 1 86*31908Skarels #define DMV_RPQOVF 1 87*31908Skarels #define DMV_RPCXRL 1 88*31908Skarels #define DMV_RPUNKNOWN 1 89*31908Skarels 90*31908Skarels struct dmv_command { 91*31908Skarels u_char qp_mask; /* Which registers to set up */ 92*31908Skarels #define QP_TRIB 0x01 93*31908Skarels #define QP_SEL4 0x02 94*31908Skarels #define QP_SEL6 0x04 95*31908Skarels #define QP_SEL10 0x08 96*31908Skarels u_char qp_cmd; 97*31908Skarels u_char qp_tributary; 98*31908Skarels u_short qp_sel4; 99*31908Skarels u_short qp_sel6; 100*31908Skarels u_short qp_sel10; 101*31908Skarels struct dmv_command *qp_next; /* next command on queue */ 102*31908Skarels }; 103*31908Skarels 104*31908Skarels #define qp_lowbufaddr qp_ 105*31908Skarels 106*31908Skarels struct dmvbufs { 107*31908Skarels int ubinfo; /* from uballoc */ 108*31908Skarels short cc; /* buffer size */ 109*31908Skarels short flags; /* access control */ 110*31908Skarels }; 111*31908Skarels 112*31908Skarels #define DBUF_OURS 0 /* buffer is available */ 113*31908Skarels #define DBUF_DMVS 1 /* buffer claimed by somebody */ 114*31908Skarels #define DBUF_XMIT 4 /* transmit buffer */ 115*31908Skarels #define DBUF_RCV 8 /* receive buffer */ 116*31908Skarels 117*31908Skarels 118*31908Skarels /* 119*31908Skarels * DMV software status per interface. 120*31908Skarels * 121*31908Skarels * Each interface is referenced by a network interface structure, 122*31908Skarels * sc_if, which the routing code uses to locate the interface. 123*31908Skarels * This structure contains the output queue for the interface, its address, ... 124*31908Skarels * We also have, for each interface, a set of 7 UBA interface structures 125*31908Skarels * for each, which 126*31908Skarels * contain information about the UNIBUS resources held by the interface: 127*31908Skarels * map registers, buffered data paths, etc. Information is cached in this 128*31908Skarels * structure for use by the if_uba.c routines in running the interface 129*31908Skarels * efficiently. 130*31908Skarels */ 131*31908Skarels struct dmv_softc { 132*31908Skarels struct ifnet sc_if; /* network-visible interface */ 133*31908Skarels struct dmvbufs sc_rbufs[NRCV]; /* receive buffer info */ 134*31908Skarels struct dmvbufs sc_xbufs[NXMT]; /* transmit buffer info */ 135*31908Skarels struct ifubinfo sc_ifuba; /* UNIBUS resources */ 136*31908Skarels struct ifrw sc_ifr[NRCV]; /* UNIBUS receive buffer maps */ 137*31908Skarels struct ifxmt sc_ifw[NXMT]; /* UNIBUS receive buffer maps */ 138*31908Skarels short sc_oused; /* output buffers currently in use */ 139*31908Skarels short sc_iused; /* input buffers given to DMV */ 140*31908Skarels short sc_flag; /* flags */ 141*31908Skarels int sc_nticks; /* seconds since last interrupt */ 142*31908Skarels int sc_ubinfo; /* UBA mapping info for base table */ 143*31908Skarels int sc_errors[8]; /* error counters */ 144*31908Skarels #define sc_rte sc_errors[0] /* receive threshhold error */ 145*31908Skarels #define sc_xte sc_errors[1] /* xmit threshhold error */ 146*31908Skarels #define sc_ste sc_errors[2] /* select threshhold error */ 147*31908Skarels #define sc_nxm sc_errors[3] /* non-existant memory */ 148*31908Skarels #define sc_modd sc_errors[4] /* modem disconnect */ 149*31908Skarels #define sc_qovf sc_errors[5] /* command/response queue overflow */ 150*31908Skarels #define sc_cxrl sc_errors[6] /* carrier loss */ 151*31908Skarels #define sc_unknown sc_errors[7] /* other errors - look in DMV manual */ 152*31908Skarels /* command queue stuff */ 153*31908Skarels struct dmv_command sc_cmdbuf[NCMDS]; 154*31908Skarels struct dmv_command *sc_qhead; /* head of command queue */ 155*31908Skarels struct dmv_command *sc_qtail; /* tail of command queue */ 156*31908Skarels struct dmv_command *sc_qactive; /* command in progress */ 157*31908Skarels struct dmv_command *sc_qfreeh; /* head of list of free cmd buffers */ 158*31908Skarels struct dmv_command *sc_qfreet; /* tail of list of free cmd buffers */ 159*31908Skarels /* end command queue stuff */ 160*31908Skarels } dmv_softc[NDMV]; 161*31908Skarels 162*31908Skarels /* flags */ 163*31908Skarels #define DMV_ALLOC 0x01 /* unibus resources allocated */ 164*31908Skarels #define DMV_RESTART 0x04 /* software restart in progress */ 165*31908Skarels #define DMV_ACTIVE 0x08 /* device active */ 166*31908Skarels #define DMV_RUNNING 0x20 /* device initialized */ 167*31908Skarels 168*31908Skarels 169*31908Skarels /* queue manipulation macros */ 170*31908Skarels #define QUEUE_AT_HEAD(qp, head, tail) \ 171*31908Skarels (qp)->qp_next = (head); \ 172*31908Skarels (head) = (qp); \ 173*31908Skarels if ((tail) == (struct dmv_command *) 0) \ 174*31908Skarels (tail) = (head) 175*31908Skarels 176*31908Skarels #define QUEUE_AT_TAIL(qp, head, tail) \ 177*31908Skarels if ((tail)) \ 178*31908Skarels (tail)->qp_next = (qp); \ 179*31908Skarels else \ 180*31908Skarels (head) = (qp); \ 181*31908Skarels (qp)->qp_next = (struct dmv_command *) 0; \ 182*31908Skarels (tail) = (qp) 183*31908Skarels 184*31908Skarels #define DEQUEUE(head, tail) \ 185*31908Skarels (head) = (head)->qp_next;\ 186*31908Skarels if ((head) == (struct dmv_command *) 0)\ 187*31908Skarels (tail) = (head) 188*31908Skarels 189*31908Skarels dmvprobe(reg) 190*31908Skarels caddr_t reg; 191*31908Skarels { 192*31908Skarels register int br, cvec; 193*31908Skarels register struct dmvdevice *addr = (struct dmvdevice *)reg; 194*31908Skarels register int i; 195*31908Skarels 196*31908Skarels #ifdef lint 197*31908Skarels br = 0; cvec = br; br = cvec; 198*31908Skarels dmvrint(0); dmvxint(0); 199*31908Skarels #endif 200*31908Skarels addr->bsel1 = DMV_MCLR; 201*31908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 202*31908Skarels ; 203*31908Skarels if ((addr->bsel1 & DMV_RUN) == 0) { 204*31908Skarels printf("dmvprobe: can't start device\n" ); 205*31908Skarels return (0); 206*31908Skarels } 207*31908Skarels if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) 208*31908Skarels { 209*31908Skarels printf("dmvprobe: device init failed, bsel4=%o, bsel6=%o\n", 210*31908Skarels addr->bsel4, addr->bsel6); 211*31908Skarels return (0); 212*31908Skarels } 213*31908Skarels addr->bsel0 = DMV_RQI|DMV_IEI|DMV_IEO; 214*31908Skarels DELAY(1000000); 215*31908Skarels addr->bsel1 = DMV_MCLR; 216*31908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 217*31908Skarels ; 218*31908Skarels return (1); 219*31908Skarels } 220*31908Skarels 221*31908Skarels /* 222*31908Skarels * Interface exists: make available by filling in network interface 223*31908Skarels * record. System will initialize the interface when it is ready 224*31908Skarels * to accept packets. 225*31908Skarels */ 226*31908Skarels dmvattach(ui) 227*31908Skarels register struct uba_device *ui; 228*31908Skarels { 229*31908Skarels register struct dmv_softc *sc = &dmv_softc[ui->ui_unit]; 230*31908Skarels 231*31908Skarels sc->sc_if.if_unit = ui->ui_unit; 232*31908Skarels sc->sc_if.if_name = "dmv"; 233*31908Skarels sc->sc_if.if_mtu = DMVMTU; 234*31908Skarels sc->sc_if.if_init = dmvinit; 235*31908Skarels sc->sc_if.if_output = dmvoutput; 236*31908Skarels sc->sc_if.if_ioctl = dmvioctl; 237*31908Skarels sc->sc_if.if_reset = dmvreset; 238*31908Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 239*31908Skarels sc->sc_ifuba.iff_flags = UBA_CANTWAIT; 240*31908Skarels 241*31908Skarels if (dmvtimer == 0) { 242*31908Skarels dmvtimer = 1; 243*31908Skarels timeout(dmvwatch, (caddr_t) 0, hz); 244*31908Skarels } 245*31908Skarels if_attach(&sc->sc_if); 246*31908Skarels } 247*31908Skarels 248*31908Skarels /* 249*31908Skarels * Reset of interface after UNIBUS reset. 250*31908Skarels * If interface is on specified UBA, reset its state. 251*31908Skarels */ 252*31908Skarels dmvreset(unit, uban) 253*31908Skarels int unit, uban; 254*31908Skarels { 255*31908Skarels register struct uba_device *ui; 256*31908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 257*31908Skarels 258*31908Skarels if (unit >= NDMV || (ui = dmvinfo[unit]) == 0 || ui->ui_alive == 0 || 259*31908Skarels ui->ui_ubanum != uban) 260*31908Skarels return; 261*31908Skarels printf(" dmv%d", unit); 262*31908Skarels sc->sc_flag = 0; 263*31908Skarels sc->sc_if.if_flags &= ~IFF_RUNNING; 264*31908Skarels dmvinit(unit); 265*31908Skarels } 266*31908Skarels 267*31908Skarels /* 268*31908Skarels * Initialization of interface; reinitialize UNIBUS usage. 269*31908Skarels */ 270*31908Skarels dmvinit(unit) 271*31908Skarels int unit; 272*31908Skarels { 273*31908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 274*31908Skarels register struct uba_device *ui = dmvinfo[unit]; 275*31908Skarels register struct dmvdevice *addr; 276*31908Skarels register struct ifnet *ifp = &sc->sc_if; 277*31908Skarels register struct ifrw *ifrw; 278*31908Skarels register struct ifxmt *ifxp; 279*31908Skarels register struct dmvbufs *rp; 280*31908Skarels register struct dmv_command *qp; 281*31908Skarels struct ifaddr *ifa; 282*31908Skarels int base; 283*31908Skarels int s; 284*31908Skarels 285*31908Skarels addr = (struct dmvdevice *)ui->ui_addr; 286*31908Skarels 287*31908Skarels /* 288*31908Skarels * Check to see that an address has been set 289*31908Skarels * (both local and destination for an address family). 290*31908Skarels */ 291*31908Skarels for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 292*31908Skarels if (ifa->ifa_addr.sa_family && ifa->ifa_dstaddr.sa_family) 293*31908Skarels break; 294*31908Skarels if (ifa == (struct ifaddr *) 0) 295*31908Skarels return; 296*31908Skarels 297*31908Skarels if ((addr->bsel1&DMV_RUN) == 0) { 298*31908Skarels log(LOG_CRIT, "dmvinit: dmv%d not running\n", unit); 299*31908Skarels ifp->if_flags &= ~IFF_UP; 300*31908Skarels return; 301*31908Skarels } 302*31908Skarels printd("dmvinit\n"); 303*31908Skarels /* initialize UNIBUS resources */ 304*31908Skarels sc->sc_iused = sc->sc_oused = 0; 305*31908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) { 306*31908Skarels if (if_ubaminit( 307*31908Skarels &sc->sc_ifuba, 308*31908Skarels ui->ui_ubanum, 309*31908Skarels sizeof(struct dmv_header), 310*31908Skarels (int)btoc(DMVMTU), 311*31908Skarels sc->sc_ifr, 312*31908Skarels NRCV, 313*31908Skarels sc->sc_ifw, 314*31908Skarels NXMT 315*31908Skarels ) == 0) { 316*31908Skarels log(LOG_CRIT, "dmvinit: dmv%d can't allocate uba resources\n", unit); 317*31908Skarels ifp->if_flags &= ~IFF_UP; 318*31908Skarels return; 319*31908Skarels } 320*31908Skarels ifp->if_flags |= IFF_RUNNING; 321*31908Skarels } 322*31908Skarels 323*31908Skarels /* initialize buffer pool */ 324*31908Skarels /* receives */ 325*31908Skarels ifrw = &sc->sc_ifr[0]; 326*31908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 327*31908Skarels rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 328*31908Skarels rp->cc = DMVMTU + sizeof (struct dmv_header); 329*31908Skarels rp->flags = DBUF_OURS|DBUF_RCV; 330*31908Skarels ifrw++; 331*31908Skarels } 332*31908Skarels /* transmits */ 333*31908Skarels ifxp = &sc->sc_ifw[0]; 334*31908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 335*31908Skarels rp->ubinfo = ifxp->ifw_info & 0x3ffff; 336*31908Skarels rp->cc = 0; 337*31908Skarels rp->flags = DBUF_OURS|DBUF_XMIT; 338*31908Skarels ifxp++; 339*31908Skarels } 340*31908Skarels 341*31908Skarels /* set up command queues */ 342*31908Skarels sc->sc_qfreeh = sc->sc_qfreet 343*31908Skarels = sc->sc_qhead = sc->sc_qtail = sc->sc_qactive = 344*31908Skarels (struct dmv_command *)0; 345*31908Skarels /* set up free command buffer list */ 346*31908Skarels for (qp = &sc->sc_cmdbuf[0]; qp < &sc->sc_cmdbuf[NCMDS]; qp++) { 347*31908Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 348*31908Skarels } 349*31908Skarels if(sc->sc_flag & DMV_RUNNING) 350*31908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQHS,0); 351*31908Skarels else 352*31908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_ESTTRIB,0); 353*31908Skarels dmvload( sc, DMV_CNTRLI, (QP_TRIB|QP_SEL6), 1, 0, DMV_REQSUS,0); 354*31908Skarels sc->sc_flag |= (DMV_RESTART|DMV_RUNNING); 355*31908Skarels sc->sc_flag &= ~DMV_ACTIVE; 356*31908Skarels addr->bsel0 |= DMV_IEO; 357*31908Skarels } 358*31908Skarels 359*31908Skarels /* 360*31908Skarels * Start output on interface. Get another datagram 361*31908Skarels * to send from the interface queue and map it to 362*31908Skarels * the interface before starting output. 363*31908Skarels * 364*31908Skarels * Must be called at spl 5 365*31908Skarels */ 366*31908Skarels dmvstart(dev) 367*31908Skarels dev_t dev; 368*31908Skarels { 369*31908Skarels int unit = minor(dev); 370*31908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 371*31908Skarels struct mbuf *m; 372*31908Skarels register struct dmvbufs *rp; 373*31908Skarels register int n; 374*31908Skarels 375*31908Skarels /* 376*31908Skarels * Dequeue up to NXMT requests and map them to the UNIBUS. 377*31908Skarels * If no more requests, or no dmv buffers available, just return. 378*31908Skarels */ 379*31908Skarels printd("dmvstart\n"); 380*31908Skarels n = 0; 381*31908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++ ) { 382*31908Skarels /* find an available buffer */ 383*31908Skarels if ((rp->flags & DBUF_DMVS) == 0) { 384*31908Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 385*31908Skarels if (m == 0) 386*31908Skarels return; 387*31908Skarels /* mark it dmvs */ 388*31908Skarels rp->flags |= (DBUF_DMVS); 389*31908Skarels /* 390*31908Skarels * Have request mapped to UNIBUS for transmission 391*31908Skarels * and start the output. 392*31908Skarels */ 393*31908Skarels rp->cc = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[n], m); 394*31908Skarels sc->sc_oused++; 395*31908Skarels dmvload( 396*31908Skarels sc, 397*31908Skarels DMV_BACCX, 398*31908Skarels QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 399*31908Skarels 1, 400*31908Skarels rp->ubinfo, 401*31908Skarels (rp->ubinfo>>16)&0x3f, 402*31908Skarels rp->cc 403*31908Skarels ); 404*31908Skarels } 405*31908Skarels n++; 406*31908Skarels } 407*31908Skarels } 408*31908Skarels 409*31908Skarels /* 410*31908Skarels * Utility routine to load the DMV device registers. 411*31908Skarels */ 412*31908Skarels dmvload(sc, cmd, mask, tributary, sel4, sel6, sel10) 413*31908Skarels register struct dmv_softc *sc; 414*31908Skarels u_char cmd, tributary, mask; 415*31908Skarels u_short sel4, sel6, sel10; 416*31908Skarels { 417*31908Skarels register struct dmvdevice *addr; 418*31908Skarels register int unit, sps; 419*31908Skarels register struct dmv_command *qp; 420*31908Skarels 421*31908Skarels unit = sc - dmv_softc; 422*31908Skarels printd("dmvload: cmd=%x mask=%x trib=%x sel4=%x sel6=%x sel10=%x\n", 423*31908Skarels (unsigned) cmd, 424*31908Skarels (unsigned) mask, 425*31908Skarels (unsigned) tributary, 426*31908Skarels (unsigned) sel4, 427*31908Skarels (unsigned) sel6, 428*31908Skarels (unsigned) sel10 429*31908Skarels ); 430*31908Skarels addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; 431*31908Skarels sps = spl5(); 432*31908Skarels 433*31908Skarels /* grab a command buffer from the free list */ 434*31908Skarels if ((qp = sc->sc_qfreeh) == (struct dmv_command *)0) 435*31908Skarels panic("dmv command queue overflow"); 436*31908Skarels DEQUEUE(sc->sc_qfreeh, sc->sc_qfreet); 437*31908Skarels 438*31908Skarels /* fill in requested info */ 439*31908Skarels qp->qp_cmd = cmd; 440*31908Skarels qp->qp_mask = mask; 441*31908Skarels qp->qp_tributary = tributary; 442*31908Skarels qp->qp_sel4 = sel4; 443*31908Skarels qp->qp_sel6 = sel6; 444*31908Skarels qp->qp_sel10 = sel10; 445*31908Skarels 446*31908Skarels if (sc->sc_qactive) { /* command in progress */ 447*31908Skarels if (cmd == DMV_BACCR) { /* supply read buffers first */ 448*31908Skarels QUEUE_AT_HEAD(qp, sc->sc_qhead, sc->sc_qtail); 449*31908Skarels } else { 450*31908Skarels QUEUE_AT_TAIL(qp, sc->sc_qhead, sc->sc_qtail); 451*31908Skarels } 452*31908Skarels } else { /* command port free */ 453*31908Skarels sc->sc_qactive = qp; 454*31908Skarels addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); 455*31908Skarels } 456*31908Skarels splx(sps); 457*31908Skarels } 458*31908Skarels /* 459*31908Skarels * DMV interface input interrupt. 460*31908Skarels * Ready to accept another command, 461*31908Skarels * pull one off the command queue. 462*31908Skarels */ 463*31908Skarels dmvrint(unit) 464*31908Skarels int unit; 465*31908Skarels { 466*31908Skarels register struct dmv_softc *sc; 467*31908Skarels register struct dmvdevice *addr; 468*31908Skarels register struct dmv_command *qp; 469*31908Skarels register int n; 470*31908Skarels 471*31908Skarels addr = (struct dmvdevice *)dmvinfo[unit]->ui_addr; 472*31908Skarels sc = &dmv_softc[unit]; 473*31908Skarels printd("dmvrint\n"); 474*31908Skarels if ((qp = sc->sc_qactive) == (struct dmv_command *) 0) { 475*31908Skarels log(LOG_WARNING, "dmvrint: dmv%d no command\n", unit); 476*31908Skarels return; 477*31908Skarels } 478*31908Skarels while (addr->bsel2&DMV_RDI) { 479*31908Skarels if(qp->qp_mask&QP_SEL4) 480*31908Skarels addr->wsel4 = qp->qp_sel4; 481*31908Skarels if(qp->qp_mask&QP_SEL6) 482*31908Skarels addr->wsel6 = qp->qp_sel6; 483*31908Skarels if(qp->qp_mask&QP_SEL10) { 484*31908Skarels addr->wsel10 = qp->qp_sel10; 485*31908Skarels qp->qp_cmd |= DMV_22BIT; 486*31908Skarels } 487*31908Skarels if(qp->qp_mask&QP_TRIB) 488*31908Skarels addr->wsel2 = qp->qp_cmd|(qp->qp_tributary << 8); 489*31908Skarels else 490*31908Skarels addr->bsel2 = qp->qp_cmd; 491*31908Skarels QUEUE_AT_HEAD(qp, sc->sc_qfreeh, sc->sc_qfreet); 492*31908Skarels if ((sc->sc_qactive = sc->sc_qhead) == (struct dmv_command *)0) 493*31908Skarels break; 494*31908Skarels qp = sc->sc_qactive; 495*31908Skarels DEQUEUE(sc->sc_qhead, sc->sc_qtail); 496*31908Skarels if (addr->bsel2&DMV_RDO) 497*31908Skarels break; 498*31908Skarels } 499*31908Skarels if (!sc->sc_qactive) { 500*31908Skarels if(addr->bsel2&DMV_RDI) { 501*31908Skarels /* clear RQI prior to last command per DMV manual */ 502*31908Skarels addr->bsel0 &= ~DMV_RQI; 503*31908Skarels addr->wsel6 = DMV_NOP; 504*31908Skarels addr->bsel2 = DMV_CNTRLI; 505*31908Skarels } 506*31908Skarels addr->bsel0 = DMV_IEO; 507*31908Skarels } 508*31908Skarels else /* RDO set or DMV still holding CSR */ 509*31908Skarels addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO); 510*31908Skarels 511*31908Skarels } 512*31908Skarels 513*31908Skarels /* 514*31908Skarels * DMV interface output interrupt. 515*31908Skarels * A transfer may have completed, check for errors. 516*31908Skarels * If it was a read, notify appropriate protocol. 517*31908Skarels * If it was a write, pull the next one off the queue. 518*31908Skarels */ 519*31908Skarels dmvxint(unit) 520*31908Skarels int unit; 521*31908Skarels { 522*31908Skarels register struct dmv_softc *sc; 523*31908Skarels register struct ifnet *ifp; 524*31908Skarels struct uba_device *ui = dmvinfo[unit]; 525*31908Skarels struct dmvdevice *addr; 526*31908Skarels struct mbuf *m; 527*31908Skarels struct ifqueue *inq; 528*31908Skarels int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s; 529*31908Skarels register struct ifrw *ifrw; 530*31908Skarels register struct dmvbufs *rp; 531*31908Skarels register struct ifxmt *ifxp; 532*31908Skarels struct dmv_header *dh; 533*31908Skarels int off, resid, fatal; 534*31908Skarels 535*31908Skarels addr = (struct dmvdevice *)ui->ui_addr; 536*31908Skarels sc = &dmv_softc[unit]; 537*31908Skarels ifp = &sc->sc_if; 538*31908Skarels 539*31908Skarels while (addr->bsel2 & DMV_RDO) { 540*31908Skarels 541*31908Skarels sel2 = addr->bsel2; 542*31908Skarels sel3 = addr->bsel3; 543*31908Skarels sel4 = addr->wsel4; /* release port */ 544*31908Skarels sel6 = addr->wsel6; 545*31908Skarels if(sel2 & DMV_22BIT) 546*31908Skarels sel10 = addr->wsel10; 547*31908Skarels addr->bsel2 &= ~DMV_RDO; 548*31908Skarels pkaddr = sel4 | ((sel6 & 0x3f) << 16); 549*31908Skarels printd("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n", 550*31908Skarels (unsigned) sel2, 551*31908Skarels (unsigned) sel4, 552*31908Skarels (unsigned) sel6, 553*31908Skarels (unsigned) sel10, 554*31908Skarels (unsigned) pkaddr 555*31908Skarels ); 556*31908Skarels if((sc->sc_flag & DMV_RUNNING)==0) { 557*31908Skarels log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit); 558*31908Skarels return; 559*31908Skarels } 560*31908Skarels switch (sel2 & 07) { 561*31908Skarels case DMV_BDRUS: 562*31908Skarels /* 563*31908Skarels * A read has completed. 564*31908Skarels * Pass packet to type specific 565*31908Skarels * higher-level input routine. 566*31908Skarels */ 567*31908Skarels ifp->if_ipackets++; 568*31908Skarels /* find location in dmvuba struct */ 569*31908Skarels ifrw= &sc->sc_ifr[0]; 570*31908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 571*31908Skarels if(rp->ubinfo == pkaddr) 572*31908Skarels break; 573*31908Skarels ifrw++; 574*31908Skarels } 575*31908Skarels if (rp >= &sc->sc_rbufs[NRCV]) 576*31908Skarels panic("dmv rcv"); 577*31908Skarels if ((rp->flags & DBUF_DMVS) == 0) 578*31908Skarels log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit); 579*31908Skarels 580*31908Skarels len = (sel10&0x3fff) - sizeof (struct dmv_header); 581*31908Skarels if (len < 0 || len > DMVMTU) { 582*31908Skarels ifp->if_ierrors++; 583*31908Skarels log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n", 584*31908Skarels unit, pkaddr, len); 585*31908Skarels goto setup; 586*31908Skarels } 587*31908Skarels /* 588*31908Skarels * Deal with trailer protocol: if type is trailer 589*31908Skarels * get true type from first 16-bit word past data. 590*31908Skarels * Remember that type was trailer by setting off. 591*31908Skarels */ 592*31908Skarels dh = (struct dmv_header *)ifrw->ifrw_addr; 593*31908Skarels dh->dmv_type = ntohs((u_short)dh->dmv_type); 594*31908Skarels #define dmvdataaddr(dh, off, type) ((type)(((caddr_t)((dh)+1)+(off)))) 595*31908Skarels if (dh->dmv_type >= DMV_TRAILER && 596*31908Skarels dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) { 597*31908Skarels off = (dh->dmv_type - DMV_TRAILER) * 512; 598*31908Skarels if (off >= DMVMTU) 599*31908Skarels goto setup; /* sanity */ 600*31908Skarels dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *)); 601*31908Skarels resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *))); 602*31908Skarels if (off + resid > len) 603*31908Skarels goto setup; /* sanity */ 604*31908Skarels len = off + resid; 605*31908Skarels } else 606*31908Skarels off = 0; 607*31908Skarels if (len == 0) 608*31908Skarels goto setup; 609*31908Skarels 610*31908Skarels /* 611*31908Skarels * Pull packet off interface. Off is nonzero if 612*31908Skarels * packet has trailing header; dmv_get will then 613*31908Skarels * force this header information to be at the front, 614*31908Skarels * but we still have to drop the type and length 615*31908Skarels * which are at the front of any trailer data. 616*31908Skarels */ 617*31908Skarels m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp); 618*31908Skarels if (m == 0) 619*31908Skarels goto setup; 620*31908Skarels if (off) { 621*31908Skarels ifp = *(mtod(m, struct ifnet **)); 622*31908Skarels m->m_off += 2 * sizeof (u_short); 623*31908Skarels m->m_len -= 2 * sizeof (u_short); 624*31908Skarels *(mtod(m, struct ifnet **)) = ifp; 625*31908Skarels } 626*31908Skarels switch (dh->dmv_type) { 627*31908Skarels #ifdef INET 628*31908Skarels case DMV_IPTYPE: 629*31908Skarels schednetisr(NETISR_IP); 630*31908Skarels inq = &ipintrq; 631*31908Skarels break; 632*31908Skarels #endif 633*31908Skarels default: 634*31908Skarels m_freem(m); 635*31908Skarels goto setup; 636*31908Skarels } 637*31908Skarels 638*31908Skarels s = splimp(); 639*31908Skarels if (IF_QFULL(inq)) { 640*31908Skarels IF_DROP(inq); 641*31908Skarels m_freem(m); 642*31908Skarels } else 643*31908Skarels IF_ENQUEUE(inq, m); 644*31908Skarels splx(s); 645*31908Skarels setup: 646*31908Skarels /* is this needed? */ 647*31908Skarels rp->ubinfo = ifrw->ifrw_info & 0x3ffff; 648*31908Skarels dmvload( 649*31908Skarels sc, 650*31908Skarels DMV_BACCR, 651*31908Skarels QP_SEL4|QP_SEL6|QP_SEL10, 652*31908Skarels 0, 653*31908Skarels rp->ubinfo, 654*31908Skarels (rp->ubinfo>>16)&0x3f, 655*31908Skarels rp->cc 656*31908Skarels ); 657*31908Skarels break; 658*31908Skarels case DMV_BDXSA: 659*31908Skarels /* 660*31908Skarels * A write has completed, start another 661*31908Skarels * transfer if there is more data to send. 662*31908Skarels */ 663*31908Skarels ifp->if_opackets++; 664*31908Skarels /* find associated dmvbuf structure */ 665*31908Skarels ifxp = &sc->sc_ifw[0]; 666*31908Skarels for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) { 667*31908Skarels if(rp->ubinfo == pkaddr) 668*31908Skarels break; 669*31908Skarels ifxp++; 670*31908Skarels } 671*31908Skarels if (rp >= &sc->sc_xbufs[NXMT]) { 672*31908Skarels log(LOG_ERR, "dmv%d: bad packet address 0x%x\n", 673*31908Skarels unit, pkaddr); 674*31908Skarels break; 675*31908Skarels } 676*31908Skarels if ((rp->flags & DBUF_DMVS) == 0) 677*31908Skarels log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n", 678*31908Skarels unit, pkaddr); 679*31908Skarels /* mark buffer free */ 680*31908Skarels if (ifxp->ifw_xtofree) { 681*31908Skarels (void)m_freem(ifxp->ifw_xtofree); 682*31908Skarels ifxp->ifw_xtofree = 0; 683*31908Skarels } 684*31908Skarels rp->flags &= ~DBUF_DMVS; 685*31908Skarels sc->sc_oused--; 686*31908Skarels sc->sc_nticks = 0; 687*31908Skarels sc->sc_flag |= DMV_ACTIVE; 688*31908Skarels break; 689*31908Skarels 690*31908Skarels case DMV_CNTRLO: 691*31908Skarels /* ACCUMULATE STATISTICS */ 692*31908Skarels fatal=0; 693*31908Skarels switch(sel6&DMV_EEC) { 694*31908Skarels case DMV_ORUN: 695*31908Skarels if(sc->sc_flag & DMV_RESTART) { 696*31908Skarels load_rec_bufs(sc); 697*31908Skarels sc->sc_flag &= ~DMV_RESTART; 698*31908Skarels log(LOG_INFO, 699*31908Skarels "dmvxint: dmv%d far end on-line\n", 700*31908Skarels unit 701*31908Skarels ); 702*31908Skarels } else { 703*31908Skarels log(LOG_WARNING, 704*31908Skarels "dmvxint: dmv%d far end restart\n", 705*31908Skarels unit 706*31908Skarels ); 707*31908Skarels goto fatal; 708*31908Skarels } 709*31908Skarels break; 710*31908Skarels case DMV_RTE: 711*31908Skarels ifp->if_ierrors++; 712*31908Skarels log(LOG_WARNING, 713*31908Skarels "dmvxint: dmv%d receive threshold error\n", 714*31908Skarels unit 715*31908Skarels ); 716*31908Skarels if ((sc->sc_rte++ % DMV_RPRTE) == 0) 717*31908Skarels goto fatal; 718*31908Skarels break; 719*31908Skarels case DMV_TTE: 720*31908Skarels ifp->if_oerrors++; 721*31908Skarels log(LOG_WARNING, 722*31908Skarels "dmvxint: dmv%d transmit threshold error\n", 723*31908Skarels unit 724*31908Skarels ); 725*31908Skarels if ((sc->sc_xte++ % DMV_RPTTE) == 0) 726*31908Skarels goto fatal; 727*31908Skarels break; 728*31908Skarels case DMV_STE: 729*31908Skarels log(LOG_WARNING, 730*31908Skarels "dmvxint: dmv%d select threshold error\n", 731*31908Skarels unit 732*31908Skarels ); 733*31908Skarels if ((sc->sc_ste++ % DMV_RPSTE) == 0) 734*31908Skarels goto fatal; 735*31908Skarels break; 736*31908Skarels case DMV_NXM: 737*31908Skarels log(LOG_WARNING, 738*31908Skarels "dmvxint: dmv%d nonexistent memory error\n", 739*31908Skarels unit 740*31908Skarels ); 741*31908Skarels if ((sc->sc_nxm++ % DMV_RPNXM) == 0) { 742*31908Skarels goto fatal; 743*31908Skarels } 744*31908Skarels break; 745*31908Skarels case DMV_MODD: 746*31908Skarels log(LOG_WARNING, 747*31908Skarels "dmvxint: dmv%d modem disconnected error\n", 748*31908Skarels unit 749*31908Skarels ); 750*31908Skarels if ((sc->sc_modd++ % DMV_RPMODD) == 0) 751*31908Skarels goto fatal; 752*31908Skarels break; 753*31908Skarels case DMV_CXRL: 754*31908Skarels log(LOG_WARNING, 755*31908Skarels "dmvxint: dmv%d carrier loss error\n", 756*31908Skarels unit 757*31908Skarels ); 758*31908Skarels if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0) 759*31908Skarels goto fatal; 760*31908Skarels break; 761*31908Skarels case DMV_QOVF: 762*31908Skarels log(LOG_WARNING, 763*31908Skarels "dmvxint: dmv%d response queue overflow\n", 764*31908Skarels unit 765*31908Skarels ); 766*31908Skarels sc->sc_qovf++; 767*31908Skarels goto fatal; 768*31908Skarels 769*31908Skarels default: 770*31908Skarels log(LOG_WARNING, 771*31908Skarels "dmvxint: dmv%d unknown error %o\n", 772*31908Skarels unit, 773*31908Skarels sel6&DMV_EEC 774*31908Skarels ); 775*31908Skarels if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0) 776*31908Skarels goto fatal; 777*31908Skarels break; 778*31908Skarels } 779*31908Skarels break; 780*31908Skarels 781*31908Skarels case DMV_BDRUNUS: 782*31908Skarels case DMV_BDXSN: 783*31908Skarels case DMV_BDXNS: 784*31908Skarels log(LOG_INFO, 785*31908Skarels "dmvxint: dmv%d buffer disp for halted trib %o\n", 786*31908Skarels unit, sel2&0x7 787*31908Skarels ); 788*31908Skarels break; 789*31908Skarels 790*31908Skarels case DMV_MDEFO: 791*31908Skarels if((sel6&0x1f) == 020) { 792*31908Skarels log(LOG_INFO, 793*31908Skarels "dmvxint: dmv%d buffer return complete sel3=%x\n", 794*31908Skarels unit, sel3); 795*31908Skarels } else { 796*31908Skarels log(LOG_INFO, 797*31908Skarels "dmvxint: dmv%d info resp sel3=%x sel4=%x sel6=%x\n", 798*31908Skarels unit, sel3, sel4, sel6 799*31908Skarels ); 800*31908Skarels } 801*31908Skarels break; 802*31908Skarels 803*31908Skarels default: 804*31908Skarels log(LOG_WARNING, 805*31908Skarels "dmvxint: dmv%d bad control %o\n", 806*31908Skarels unit, sel2&0x7 807*31908Skarels ); 808*31908Skarels break; 809*31908Skarels } 810*31908Skarels } 811*31908Skarels dmvstart(unit); 812*31908Skarels return; 813*31908Skarels fatal: 814*31908Skarels log( 815*31908Skarels LOG_ERR, 816*31908Skarels "dmv%d: fatal error, output code ==%o\n", 817*31908Skarels unit, 818*31908Skarels sel6&DMV_EEC 819*31908Skarels ); 820*31908Skarels dmvrestart(unit); 821*31908Skarels } 822*31908Skarels load_rec_bufs(sc) 823*31908Skarels register struct dmv_softc *sc; 824*31908Skarels { 825*31908Skarels register struct dmvbufs *rp; 826*31908Skarels 827*31908Skarels /* queue first NRCV buffers for DMV to fill */ 828*31908Skarels for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) { 829*31908Skarels rp->flags |= DBUF_DMVS; 830*31908Skarels dmvload( 831*31908Skarels sc, 832*31908Skarels DMV_BACCR, 833*31908Skarels QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10, 834*31908Skarels 1, 835*31908Skarels rp->ubinfo, 836*31908Skarels (rp->ubinfo>>16)&0x3f, 837*31908Skarels rp->cc 838*31908Skarels ); 839*31908Skarels sc->sc_iused++; 840*31908Skarels } 841*31908Skarels } 842*31908Skarels 843*31908Skarels /* 844*31908Skarels * DMV output routine. 845*31908Skarels * Encapsulate a packet of type family for the dmv. 846*31908Skarels * Use trailer local net encapsulation if enough data in first 847*31908Skarels * packet leaves a multiple of 512 bytes of data in remainder. 848*31908Skarels */ 849*31908Skarels dmvoutput(ifp, m0, dst) 850*31908Skarels register struct ifnet *ifp; 851*31908Skarels register struct mbuf *m0; 852*31908Skarels struct sockaddr *dst; 853*31908Skarels { 854*31908Skarels int type, error, s; 855*31908Skarels register struct mbuf *m = m0; 856*31908Skarels register struct dmv_header *dh; 857*31908Skarels register int off; 858*31908Skarels 859*31908Skarels switch (dst->sa_family) { 860*31908Skarels #ifdef INET 861*31908Skarels case AF_INET: 862*31908Skarels off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 863*31908Skarels if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 864*31908Skarels if (off > 0 && (off & 0x1ff) == 0 && 865*31908Skarels m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 866*31908Skarels type = DMV_TRAILER + (off>>9); 867*31908Skarels m->m_off -= 2 * sizeof (u_short); 868*31908Skarels m->m_len += 2 * sizeof (u_short); 869*31908Skarels *mtod(m, u_short *) = htons((u_short)DMV_IPTYPE); 870*31908Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 871*31908Skarels goto gottrailertype; 872*31908Skarels } 873*31908Skarels type = DMV_IPTYPE; 874*31908Skarels off = 0; 875*31908Skarels goto gottype; 876*31908Skarels #endif 877*31908Skarels 878*31908Skarels case AF_UNSPEC: 879*31908Skarels dh = (struct dmv_header *)dst->sa_data; 880*31908Skarels type = dh->dmv_type; 881*31908Skarels goto gottype; 882*31908Skarels 883*31908Skarels default: 884*31908Skarels log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n", ifp->if_unit, 885*31908Skarels dst->sa_family); 886*31908Skarels error = EAFNOSUPPORT; 887*31908Skarels goto bad; 888*31908Skarels } 889*31908Skarels 890*31908Skarels gottrailertype: 891*31908Skarels /* 892*31908Skarels * Packet to be sent as a trailer; move first packet 893*31908Skarels * (control information) to end of chain. 894*31908Skarels */ 895*31908Skarels while (m->m_next) 896*31908Skarels m = m->m_next; 897*31908Skarels m->m_next = m0; 898*31908Skarels m = m0->m_next; 899*31908Skarels m0->m_next = 0; 900*31908Skarels m0 = m; 901*31908Skarels 902*31908Skarels gottype: 903*31908Skarels /* 904*31908Skarels * Add local network header 905*31908Skarels * (there is space for a uba on a vax to step on) 906*31908Skarels */ 907*31908Skarels if (m->m_off > MMAXOFF || 908*31908Skarels MMINOFF + sizeof(struct dmv_header) > m->m_off) { 909*31908Skarels m = m_get(M_DONTWAIT, MT_HEADER); 910*31908Skarels if (m == 0) { 911*31908Skarels error = ENOBUFS; 912*31908Skarels goto bad; 913*31908Skarels } 914*31908Skarels m->m_next = m0; 915*31908Skarels m->m_off = MMINOFF; 916*31908Skarels m->m_len = sizeof (struct dmv_header); 917*31908Skarels } else { 918*31908Skarels m->m_off -= sizeof (struct dmv_header); 919*31908Skarels m->m_len += sizeof (struct dmv_header); 920*31908Skarels } 921*31908Skarels dh = mtod(m, struct dmv_header *); 922*31908Skarels dh->dmv_type = htons((u_short)type); 923*31908Skarels 924*31908Skarels /* 925*31908Skarels * Queue message on interface, and start output if interface 926*31908Skarels * not yet active. 927*31908Skarels */ 928*31908Skarels s = splimp(); 929*31908Skarels if (IF_QFULL(&ifp->if_snd)) { 930*31908Skarels IF_DROP(&ifp->if_snd); 931*31908Skarels m_freem(m); 932*31908Skarels splx(s); 933*31908Skarels return (ENOBUFS); 934*31908Skarels } 935*31908Skarels IF_ENQUEUE(&ifp->if_snd, m); 936*31908Skarels dmvstart(ifp->if_unit); 937*31908Skarels splx(s); 938*31908Skarels return (0); 939*31908Skarels 940*31908Skarels bad: 941*31908Skarels m_freem(m0); 942*31908Skarels return (error); 943*31908Skarels } 944*31908Skarels 945*31908Skarels 946*31908Skarels /* 947*31908Skarels * Process an ioctl request. 948*31908Skarels */ 949*31908Skarels /* ARGSUSED */ 950*31908Skarels dmvioctl(ifp, cmd, data) 951*31908Skarels register struct ifnet *ifp; 952*31908Skarels int cmd; 953*31908Skarels caddr_t data; 954*31908Skarels { 955*31908Skarels int s = splimp(), error = 0; 956*31908Skarels struct mbuf *m; 957*31908Skarels register struct dmv_softc *sc = &dmv_softc[ifp->if_unit]; 958*31908Skarels 959*31908Skarels switch (cmd) { 960*31908Skarels 961*31908Skarels case SIOCSIFADDR: 962*31908Skarels ifp->if_flags |= IFF_UP; 963*31908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 964*31908Skarels dmvinit(ifp->if_unit); 965*31908Skarels break; 966*31908Skarels 967*31908Skarels case SIOCSIFDSTADDR: 968*31908Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 969*31908Skarels dmvinit(ifp->if_unit); 970*31908Skarels break; 971*31908Skarels 972*31908Skarels case SIOCSIFFLAGS: 973*31908Skarels if ((ifp->if_flags & IFF_UP) == 0 && 974*31908Skarels sc->sc_flag & DMV_RUNNING) { 975*31908Skarels ((struct dmvdevice *) 976*31908Skarels (dmvinfo[ifp->if_unit]->ui_addr))->bsel1 = DMV_MCLR; 977*31908Skarels for(;;) { 978*31908Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 979*31908Skarels if (m != NULL) 980*31908Skarels m_freem(m); 981*31908Skarels else 982*31908Skarels break; 983*31908Skarels } 984*31908Skarels sc->sc_flag &= ~DMV_RUNNING; 985*31908Skarels } else if (ifp->if_flags & IFF_UP && 986*31908Skarels (sc->sc_flag & DMV_RUNNING) == 0) 987*31908Skarels dmvrestart(ifp->if_unit); 988*31908Skarels break; 989*31908Skarels 990*31908Skarels default: 991*31908Skarels error = EINVAL; 992*31908Skarels } 993*31908Skarels splx(s); 994*31908Skarels return (error); 995*31908Skarels } 996*31908Skarels 997*31908Skarels /* 998*31908Skarels * Restart after a fatal error. 999*31908Skarels * Clear device and reinitialize. 1000*31908Skarels */ 1001*31908Skarels dmvrestart(unit) 1002*31908Skarels int unit; 1003*31908Skarels { 1004*31908Skarels register struct dmv_softc *sc = &dmv_softc[unit]; 1005*31908Skarels register struct uba_device *ui = dmvinfo[unit]; 1006*31908Skarels register struct dmvdevice *addr; 1007*31908Skarels register struct ifxmt *ifxp; 1008*31908Skarels register int i; 1009*31908Skarels 1010*31908Skarels #ifdef notdef 1011*31908Skarels addr = (struct dmvdevice *)ui->ui_addr; 1012*31908Skarels /* 1013*31908Skarels * Let the DMR finish the MCLR. At 1 Mbit, it should do so 1014*31908Skarels * in about a max of 6.4 milliseconds with diagnostics enabled. 1015*31908Skarels */ 1016*31908Skarels addr->bsel1 = DMV_MCLR; 1017*31908Skarels for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--) 1018*31908Skarels ; 1019*31908Skarels if ((addr->bsel1 & DMV_RUN) == 0) { 1020*31908Skarels log(LOG_ERR, "dmvrestart: can't start device\n" ); 1021*31908Skarels return (0); 1022*31908Skarels } 1023*31908Skarels if ((addr->bsel4 != 033) || (addr->bsel6 != 0305)) 1024*31908Skarels { 1025*31908Skarels log(LOG_ERR, "dmvrestart: device init failed, bsel4=%o, bsel6=%o\n", 1026*31908Skarels addr->bsel4, addr->bsel6); 1027*31908Skarels return (0); 1028*31908Skarels } 1029*31908Skarels #endif 1030*31908Skarels for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) { 1031*31908Skarels if (ifxp->ifw_xtofree) { 1032*31908Skarels (void) m_freem(ifxp->ifw_xtofree); 1033*31908Skarels ifxp->ifw_xtofree = 0; 1034*31908Skarels } 1035*31908Skarels } 1036*31908Skarels /* restart DMV */ 1037*31908Skarels dmvinit(unit); 1038*31908Skarels sc->sc_if.if_collisions++; /* why not? */ 1039*31908Skarels } 1040*31908Skarels 1041*31908Skarels /* 1042*31908Skarels * Check to see that transmitted packets don't 1043*31908Skarels * lose interrupts. The device has to be active. 1044*31908Skarels */ 1045*31908Skarels dmvwatch() 1046*31908Skarels { 1047*31908Skarels register struct uba_device *ui; 1048*31908Skarels register struct dmv_softc *sc; 1049*31908Skarels struct dmvdevice *addr; 1050*31908Skarels register int i; 1051*31908Skarels 1052*31908Skarels for (i = 0; i < NDMV; i++) { 1053*31908Skarels sc = &dmv_softc[i]; 1054*31908Skarels if ((sc->sc_flag & DMV_ACTIVE) == 0) 1055*31908Skarels continue; 1056*31908Skarels if ((ui = dmvinfo[i]) == 0 || ui->ui_alive == 0) 1057*31908Skarels continue; 1058*31908Skarels if (sc->sc_oused) { 1059*31908Skarels sc->sc_nticks++; 1060*31908Skarels if (sc->sc_nticks > dmv_timeout) { 1061*31908Skarels sc->sc_nticks = 0; 1062*31908Skarels addr = (struct dmvdevice *)ui->ui_addr; 1063*31908Skarels log(LOG_ERR, "dmv%d hung: bsel0=%b bsel2=%b\n", 1064*31908Skarels i, addr->bsel0 & 0xff, DMV0BITS, 1065*31908Skarels addr->bsel2 & 0xff, DMV2BITS); 1066*31908Skarels dmvrestart(i); 1067*31908Skarels } 1068*31908Skarels } 1069*31908Skarels } 1070*31908Skarels timeout(dmvwatch, (caddr_t) 0, hz); 1071*31908Skarels } 1072*31908Skarels #endif 1073