123305Smckusick /* 223305Smckusick * Copyright (c) 1982 Regents of the University of California. 323305Smckusick * All rights reserved. The Berkeley software License Agreement 423305Smckusick * specifies the terms and conditions for redistribution. 523305Smckusick * 6*26903Sjas * @(#)if_vv.c 6.19 (Berkeley) 03/18/86 723305Smckusick */ 87024Ssam 99799Ssam #include "vv.h" 1025275Sbloom #if NVV > 0 1111192Ssam 127024Ssam /* 1320997Skarels * Proteon proNET-10 and proNET-80 token ring driver. 1420997Skarels * The name of this device driver derives from the old MIT 1520997Skarels * name of V2LNI for the proNET hardware, would would abbreviate 1620997Skarels * to "v2", but this won't work right. Thus the name is "vv". 1711192Ssam * 1820997Skarels * This driver is compatible with the proNET 10 meagbit and 1920997Skarels * 80 megabit token ring interfaces (models p1000 and p1080). 20*26903Sjas * A unit may be marked as 80 megabit using "flags 1" in the 21*26903Sjas * config file. 2220997Skarels * 2320997Skarels * TRAILERS: You must turn off trailers via ifconfig if you want to share 2420997Skarels * a ring with software using the following protocol types: 2520997Skarels * 3: Address Resolution Protocol 2620997Skarels * 4: HDLC (old Proteon drivers) 2720997Skarels * 5: VAX Debugging Protocol (never used) 2820997Skarels * This is because the protocol type values chosen for trailers 2920997Skarels * conflict with these protocols. It's too late to change either now. 3020997Skarels * 31*26903Sjas * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001) 3220997Skarels * have a serial number >= 040, which is about March, 1982. Older 33*26903Sjas * HSBUs do not carry across 64kbyte boundaries. They can be supported 34*26903Sjas * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization 35*26903Sjas * in vvattach(). 36*26903Sjas * 37*26903Sjas * The old warning about use without Wire Centers applies only to CTL 38*26903Sjas * (p1002) cards with serial <= 057, which have not received ECO 176-743, 39*26903Sjas * which was implemented in March, 1982. Most such CTLs have received 40*26903Sjas * this ECO. 417024Ssam */ 4211209Ssam #include "../machine/pte.h" 439799Ssam 4417117Sbloom #include "param.h" 4517117Sbloom #include "systm.h" 4617117Sbloom #include "mbuf.h" 4717117Sbloom #include "buf.h" 4817117Sbloom #include "protosw.h" 4917117Sbloom #include "socket.h" 5017117Sbloom #include "vmmac.h" 5117117Sbloom #include "errno.h" 5217117Sbloom #include "ioctl.h" 538465Sroot 548465Sroot #include "../net/if.h" 5511209Ssam #include "../net/netisr.h" 568465Sroot #include "../net/route.h" 5724793Skarels 5824793Skarels #ifdef INET 598421Swnj #include "../netinet/in.h" 608421Swnj #include "../netinet/in_systm.h" 6121779Skarels #include "../netinet/in_var.h" 628421Swnj #include "../netinet/ip.h" 6324793Skarels #endif 648465Sroot 6515794Sleres #include "../vax/cpu.h" 6611209Ssam #include "../vax/mtpr.h" 6717117Sbloom #include "if_vv.h" 6817117Sbloom #include "if_uba.h" 698465Sroot #include "../vaxuba/ubareg.h" 708465Sroot #include "../vaxuba/ubavar.h" 717024Ssam 727024Ssam /* 7320997Skarels * maximum transmission unit definition -- 7420997Skarels * you can set VVMTU at anything from 576 to 2024. 7520997Skarels * 1536 is a popular "large" value, because it is a multiple 7620997Skarels * of 512, which the trailer scheme likes. 7720997Skarels * The absolute maximum size is 2024, which is enforced. 7820997Skarels */ 7920997Skarels 8024793Skarels #define VVMTU (1536) 8120997Skarels 8220997Skarels #define VVMRU (VVMTU + 16) 8320997Skarels #define VVBUFSIZE (VVMRU + sizeof(struct vv_header)) 8420997Skarels #if VVMTU>2024 8520997Skarels #undef VVMTU 8620997Skarels #undef VVMRU 8720997Skarels #undef VVBUFSIZE 8820997Skarels #define VVBUFSIZE (2046) 8920997Skarels #define VVMRU (VVBUFSIZE - sizeof (struct vv_header)) 9020997Skarels #define VVMTU (VVMRU - 16) 917024Ssam #endif 927024Ssam 9320997Skarels /* 9420997Skarels * debugging and tracing stuff 9520997Skarels */ 9616581Skarels int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */ 977640Ssam 9820997Skarels #define vvtracehdr if (vv_tracehdr) vvprt_hdr 9921779Skarels #define vvprintf if (vs->vs_if.if_flags & IFF_DEBUG) printf 10011192Ssam 10120997Skarels /* 10220997Skarels * externals, types, etc. 10320997Skarels */ 10416581Skarels int vvprobe(), vvattach(), vvreset(), vvinit(); 10516581Skarels int vvidentify(), vvstart(), vvxint(), vvwatchdog(); 10626394Skarels int vvrint(), vvoutput(), vvioctl(); 1077024Ssam struct uba_device *vvinfo[NVV]; 1087024Ssam u_short vvstd[] = { 0 }; 1097024Ssam struct uba_driver vvdriver = 1107024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 1117024Ssam #define VVUNIT(x) minor(x) 1127024Ssam 11320997Skarels #define LOOPBACK /* use loopback for packets meant for us */ 11420997Skarels #ifdef LOOPBACK 11520997Skarels extern struct ifnet loif; 11620997Skarels #endif 11720997Skarels 1187024Ssam /* 1197024Ssam * Software status of each interface. 1207024Ssam * 1217024Ssam * Each interface is referenced by a network interface structure, 1227024Ssam * vs_if, which the routing code uses to locate the interface. 1237024Ssam * This structure contains the output queue for the interface, its address, ... 1247024Ssam * We also have, for each interface, a UBA interface structure, which 1257024Ssam * contains information about the UNIBUS resources held by the interface: 1267024Ssam * map registers, buffered data paths, etc. Information is cached in this 1277024Ssam * structure for use by the if_uba.c routines in running the interface 1287024Ssam * efficiently. 1297024Ssam */ 1307024Ssam struct vv_softc { 1317024Ssam struct ifnet vs_if; /* network-visible interface */ 1327024Ssam struct ifuba vs_ifuba; /* UNIBUS resources */ 13326298Skarels u_short vs_host; /* this interface address */ 13411192Ssam short vs_oactive; /* is output active */ 135*26903Sjas short vs_is80; /* is 80 megabit version */ 1367024Ssam short vs_olen; /* length of last output */ 13715794Sleres u_short vs_lastx; /* address of last packet sent */ 13815794Sleres u_short vs_lastr; /* address of last packet received */ 13911192Ssam short vs_tries; /* transmit current retry count */ 1407024Ssam short vs_init; /* number of ring inits */ 14120997Skarels short vs_refused; /* number of packets refused */ 14215794Sleres short vs_timeouts; /* number of transmit timeouts */ 14320997Skarels short vs_otimeout; /* number of output timeouts */ 14420997Skarels short vs_ibadf; /* number of input bad formats */ 14520997Skarels short vs_parity; /* number of parity errors on 10 meg, */ 14620997Skarels /* link data errors on 80 meg */ 1477024Ssam } vv_softc[NVV]; 1487024Ssam 14926311Skarels #define NOHOST 0xffff /* illegal host number */ 15026311Skarels 15120997Skarels /* 15220997Skarels * probe the interface to see that the registers exist, and then 15320997Skarels * cause an interrupt to find its vector 15420997Skarels */ 1557024Ssam vvprobe(reg) 1567024Ssam caddr_t reg; 1577024Ssam { 1587024Ssam register int br, cvec; 15916581Skarels register struct vvreg *addr; 1607024Ssam 1617024Ssam #ifdef lint 16215764Sleres br = 0; cvec = br; br = cvec; 1637024Ssam #endif 16416581Skarels addr = (struct vvreg *)reg; 16520997Skarels 1667024Ssam /* reset interface, enable, and wait till dust settles */ 1677024Ssam addr->vvicsr = VV_RST; 1687024Ssam addr->vvocsr = VV_RST; 16915764Sleres DELAY(100000); 17020997Skarels 1717024Ssam /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 1727024Ssam addr->vvoba = 0; /* low 16 bits */ 1737024Ssam addr->vvoea = 0; /* extended bits */ 1747024Ssam addr->vvowc = -1; /* for 1 word */ 17520997Skarels addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */ 1767024Ssam DELAY(100000); 17720997Skarels addr->vvocsr = VV_RST; /* clear out the CSR */ 1787024Ssam if (cvec && cvec != 0x200) 17915764Sleres cvec -= 4; /* backup so vector => receive */ 1807024Ssam return(1); 1817024Ssam } 1827024Ssam 1837024Ssam /* 1847024Ssam * Interface exists: make available by filling in network interface 1857024Ssam * record. System will initialize the interface when it is ready 1867024Ssam * to accept packets. 1877024Ssam */ 1887024Ssam vvattach(ui) 1897024Ssam struct uba_device *ui; 1907024Ssam { 19115764Sleres register struct vv_softc *vs; 1927024Ssam 19315764Sleres vs = &vv_softc[ui->ui_unit]; 1947024Ssam vs->vs_if.if_unit = ui->ui_unit; 1957024Ssam vs->vs_if.if_name = "vv"; 1967024Ssam vs->vs_if.if_mtu = VVMTU; 19721779Skarels vs->vs_if.if_flags = IFF_BROADCAST; 1987024Ssam vs->vs_if.if_init = vvinit; 19913057Ssam vs->vs_if.if_ioctl = vvioctl; 2007024Ssam vs->vs_if.if_output = vvoutput; 20111209Ssam vs->vs_if.if_reset = vvreset; 20215794Sleres vs->vs_if.if_timer = 0; 20315794Sleres vs->vs_if.if_watchdog = vvwatchdog; 20426201Skarels vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP; 205*26903Sjas 206*26903Sjas /* use flag to determine if this is proNET-80 */ 207*26903Sjas vs->vs_is80 = (short)(ui->ui_flags & 01); 208*26903Sjas 20912354Smo #if defined(VAX750) 21012354Smo /* don't chew up 750 bdp's */ 21112354Smo if (cpu == VAX_750 && ui->ui_unit > 0) 21212354Smo vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 21312354Smo #endif 2147024Ssam if_attach(&vs->vs_if); 2157024Ssam } 2167024Ssam 2177024Ssam /* 2187024Ssam * Reset of interface after UNIBUS reset. 2197024Ssam * If interface is on specified uba, reset its state. 2207024Ssam */ 2217024Ssam vvreset(unit, uban) 2227024Ssam int unit, uban; 2237024Ssam { 2247024Ssam register struct uba_device *ui; 2257024Ssam 2267024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 2277024Ssam ui->ui_ubanum != uban) 2287024Ssam return; 2297024Ssam printf(" vv%d", unit); 2307024Ssam vvinit(unit); 2317024Ssam } 2327024Ssam 2337024Ssam /* 2347024Ssam * Initialization of interface; clear recorded pending 2357024Ssam * operations, and reinitialize UNIBUS usage. 2367024Ssam */ 2377024Ssam vvinit(unit) 2387024Ssam int unit; 2397024Ssam { 24015764Sleres register struct vv_softc *vs; 24115764Sleres register struct uba_device *ui; 2427024Ssam register struct vvreg *addr; 24316581Skarels register int ubainfo, s; 2447024Ssam 24515764Sleres vs = &vv_softc[unit]; 24615764Sleres ui = vvinfo[unit]; 24720997Skarels 24821779Skarels if (vs->vs_if.if_addrlist == (struct ifaddr *)0) 24913057Ssam return; 25020997Skarels 2517640Ssam addr = (struct vvreg *)ui->ui_addr; 2527024Ssam if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 25315764Sleres sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 25415794Sleres printf("vv%d: can't initialize, if_ubainit() failed\n", unit); 2557640Ssam vs->vs_if.if_flags &= ~IFF_UP; 2567024Ssam return; 2577024Ssam } 25820997Skarels 2597024Ssam /* 26015764Sleres * Now that the uba is set up, figure out our address and 26115764Sleres * update complete our host address. 2627640Ssam */ 26326311Skarels if ((vs->vs_host = vvidentify(unit)) == NOHOST) { 26415794Sleres vs->vs_if.if_flags &= ~IFF_UP; 26515794Sleres return; 26615794Sleres } 267*26903Sjas printf("vv%d: host %u\n", unit, vs->vs_host); 26820997Skarels 2697640Ssam /* 27020997Skarels * Reset the interface, and stay in the ring 2717640Ssam */ 27220997Skarels addr->vvocsr = VV_RST; /* take over output */ 27320997Skarels addr->vvocsr = VV_CPB; /* clear packet buffer */ 27420997Skarels addr->vvicsr = VV_RST | VV_HEN; /* take over input, */ 27520997Skarels /* keep relay closed */ 27612351Smo DELAY(500000); /* let contacts settle */ 27720997Skarels 27820997Skarels vs->vs_init = 0; /* clear counters, etc. */ 27920997Skarels vs->vs_refused = 0; 28015794Sleres vs->vs_timeouts = 0; 28120997Skarels vs->vs_otimeout = 0; 28220997Skarels vs->vs_ibadf = 0; 28320997Skarels vs->vs_parity = 0; 28415794Sleres vs->vs_lastx = 256; /* an invalid address */ 28515794Sleres vs->vs_lastr = 256; /* an invalid address */ 28620997Skarels 2877640Ssam /* 2887640Ssam * Hang a receive and start any 2897640Ssam * pending writes by faking a transmit complete. 2907640Ssam */ 2917640Ssam s = splimp(); 2927640Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 29313057Ssam addr->vviba = (u_short)ubainfo; 29413057Ssam addr->vviea = (u_short)(ubainfo >> 16); 29520997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 29620997Skarels addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB; 2977640Ssam vs->vs_oactive = 1; 29821779Skarels vs->vs_if.if_flags |= IFF_RUNNING; 2997640Ssam vvxint(unit); 3007640Ssam splx(s); 3017640Ssam } 3027640Ssam 3037640Ssam /* 30420997Skarels * Do a moderately thorough self-test in all three modes. Mostly 30520997Skarels * to keeps defective nodes off the ring, rather than to be especially 30620997Skarels * thorough. The key issue is to detect any cable breaks before joining 30720997Skarels * the ring. Return our node address on success, return -1 on failure. 30820997Skarels * 3097640Ssam */ 31020997Skarels 31120997Skarels /* the three self-test modes */ 31220997Skarels static u_short vv_modes[] = { 31320997Skarels VV_STE|VV_LPB, /* digital loopback */ 31420997Skarels VV_STE, /* analog loopback */ 31520997Skarels VV_HEN /* network mode */ 31620997Skarels }; 31720997Skarels 31811209Ssam vvidentify(unit) 31913057Ssam int unit; 32011209Ssam { 32115764Sleres register struct vv_softc *vs; 32215764Sleres register struct uba_device *ui; 3237640Ssam register struct vvreg *addr; 32416581Skarels register struct mbuf *m; 32516581Skarels register struct vv_header *v; 32620997Skarels register int ubainfo; 32720997Skarels register int i, successes, failures, waitcount; 32826311Skarels u_short shost = NOHOST; 3297640Ssam 33020997Skarels vs = &vv_softc[unit]; 33120997Skarels ui = vvinfo[unit]; 33220997Skarels addr = (struct vvreg *)ui->ui_addr; 33320997Skarels 3347640Ssam /* 3357024Ssam * Build a multicast message to identify our address 33620997Skarels * We need do this only once, since nobody else is about to use 33720997Skarels * the intermediate transmit buffer (ifu_w.ifrw_addr) that 33820997Skarels * if_ubainit() aquired for us. 3397024Ssam */ 34011209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 34115794Sleres if (m == NULL) { 34215794Sleres printf("vv%d: can't initialize, m_get() failed\n", unit); 34313057Ssam return (0); 34415794Sleres } 34511192Ssam m->m_next = 0; 3467024Ssam m->m_off = MMINOFF; 3477024Ssam m->m_len = sizeof(struct vv_header); 3487024Ssam v = mtod(m, struct vv_header *); 34911192Ssam v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 3507024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 3517024Ssam v->vh_version = RING_VERSION; 35220997Skarels v->vh_type = RING_DIAGNOSTICS; 3537024Ssam v->vh_info = 0; 35420997Skarels /* map xmit message into uba, copying to intermediate buffer */ 35520997Skarels vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 35620997Skarels 3577024Ssam /* 35820997Skarels * For each of the modes (digital, analog, network), go through 35920997Skarels * a self-test that requires me to send VVIDENTSUCC good packets 36020997Skarels * in VVIDENTRETRY attempts. Use broadcast destination to find out 36120997Skarels * who I am, then use this as my address to check my address match 36220997Skarels * logic. Only data checked is the vh_type field. 3637024Ssam */ 3647640Ssam 36520997Skarels for (i = 0; i < 3; i++) { 36620997Skarels successes = 0; /* clear successes for this mode */ 36720997Skarels failures = 0; /* and clear failures, too */ 3687640Ssam 36920997Skarels /* take over device, and leave ring */ 37020997Skarels addr->vvicsr = VV_RST; 37120997Skarels addr->vvocsr = VV_RST; 37220997Skarels addr->vvicsr = vv_modes[i]; /* test mode */ 37320997Skarels 37420997Skarels /* 37520997Skarels * let the flag and token timers pop so that the init ring bit 37620997Skarels * will be allowed to work, by waiting about 1 second 37720997Skarels */ 37820997Skarels DELAY(1000000L); 37920997Skarels 38020997Skarels /* 38120997Skarels * retry loop 38220997Skarels */ 38320997Skarels while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY)) 38420997Skarels { 38520997Skarels /* start a receive */ 38620997Skarels ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 38720997Skarels addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */ 38820997Skarels addr->vviba = (u_short) ubainfo; 38920997Skarels addr->vviea = (u_short) (ubainfo >> 16); 39020997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 39120997Skarels addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB; 39220997Skarels 39320997Skarels /* purge stale data from BDP */ 39420997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 39520997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 39620997Skarels vs->vs_ifuba.ifu_w.ifrw_bdp); 39720997Skarels 39820997Skarels /* do a transmit */ 39920997Skarels ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 40020997Skarels addr->vvocsr = VV_RST; /* abort last try */ 40120997Skarels addr->vvoba = (u_short) ubainfo; 40220997Skarels addr->vvoea = (u_short) (ubainfo >> 16); 40320997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); 40420997Skarels addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 40520997Skarels 40620997Skarels /* poll receive side for completion */ 40720997Skarels DELAY(10000); /* give it a chance */ 40820997Skarels for (waitcount = 0; waitcount < 10; waitcount++) { 40920997Skarels if (addr->vvicsr & VV_RDY) 41020997Skarels goto gotit; 41120997Skarels DELAY(1000); 41220997Skarels } 41320997Skarels failures++; /* no luck */ 41411209Ssam continue; 41520997Skarels 41620997Skarels gotit: /* we got something--is it any good? */ 41720997Skarels if ((addr->vvicsr & (VVRERR|VV_LDE)) || 41821779Skarels (addr->vvocsr & (VVXERR|VV_RFS))) { 41920997Skarels failures++; 42020997Skarels continue; 42120997Skarels } 42220997Skarels 42320997Skarels /* Purge BDP before looking at received packet */ 42420997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 42520997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 42620997Skarels vs->vs_ifuba.ifu_r.ifrw_bdp); 42724793Skarels m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 42826394Skarels 0, &vs->vs_if); 42920997Skarels if (m != NULL) 43020997Skarels m_freem(m); 43120997Skarels 43220997Skarels v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 43320997Skarels 43420997Skarels /* check message type, catch our node address */ 43520997Skarels if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) { 43626311Skarels if (shost == NOHOST) { 43720997Skarels shost = v->vh_shost & 0xff; 43820997Skarels /* send to ourself now */ 43920997Skarels ((struct vv_header *) 44020997Skarels (vs->vs_ifuba.ifu_r.ifrw_addr)) 44120997Skarels ->vh_dhost = shost; 44220997Skarels } 44320997Skarels successes++; 444*26903Sjas } else { 445*26903Sjas failures++; 44620997Skarels } 447*26903Sjas v->vh_type = 0; /* clear to check again */ 44811192Ssam } 44920997Skarels 45020997Skarels if (failures >= VVIDENTRETRY) 45120997Skarels { 45220997Skarels printf("vv%d: failed self-test after %d tries \ 45320997Skarels in %s mode\n", 45420997Skarels unit, VVIDENTRETRY, i == 0 ? "digital loopback" : 45520997Skarels (i == 1 ? "analog loopback" : "network")); 45620997Skarels printf("vv%d: icsr = %b, ocsr = %b\n", 45720997Skarels unit, 0xffff & addr->vvicsr, VV_IBITS, 45820997Skarels 0xffff & addr->vvocsr, VV_OBITS); 45920997Skarels addr->vvicsr = VV_RST; /* kill the sick board */ 46020997Skarels addr->vvocsr = VV_RST; 46126311Skarels shost = NOHOST; 46220997Skarels goto done; 46320997Skarels } 46411192Ssam } 46520997Skarels 46620997Skarels done: 46720997Skarels /* deallocate mbuf used for send packet (won't be one, anyways) */ 46815794Sleres if (vs->vs_ifuba.ifu_xtofree) { 4697024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 47015794Sleres vs->vs_ifuba.ifu_xtofree = 0; 47115794Sleres } 47220997Skarels 47320997Skarels return(shost); 4747024Ssam } 4757024Ssam 4767024Ssam /* 4777024Ssam * Start or restart output on interface. 47811192Ssam * If interface is active, this is a retransmit, so just 47911192Ssam * restuff registers and go. 4807024Ssam * If interface is not already active, get another datagram 4817024Ssam * to send off of the interface queue, and map it to the interface 4827024Ssam * before starting the output. 4837024Ssam */ 4847024Ssam vvstart(dev) 4857024Ssam dev_t dev; 4867024Ssam { 48716581Skarels register struct uba_device *ui; 48815764Sleres register struct vv_softc *vs; 4897024Ssam register struct vvreg *addr; 49016581Skarels register struct mbuf *m; 49116581Skarels register int unit, ubainfo, dest, s; 4927024Ssam 49316581Skarels unit = VVUNIT(dev); 49415764Sleres ui = vvinfo[unit]; 49515764Sleres vs = &vv_softc[unit]; 4967024Ssam if (vs->vs_oactive) 4977024Ssam goto restart; 4987024Ssam /* 4997024Ssam * Not already active: dequeue another request 5007024Ssam * and map it to the UNIBUS. If no more requests, 5017024Ssam * just return. 5027024Ssam */ 50315794Sleres s = splimp(); 5047024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 50515794Sleres splx(s); 50611209Ssam if (m == NULL) { 5077024Ssam vs->vs_oactive = 0; 5087024Ssam return; 5097024Ssam } 5107024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 5117024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 5127024Ssam vs->vs_lastx = dest; 5137024Ssam restart: 5147024Ssam /* 5157024Ssam * Have request mapped to UNIBUS for transmission. 51615794Sleres * Purge any stale data from this BDP, and start the output. 51715794Sleres * 51815794Sleres * Make sure this packet will fit in the interface. 5197024Ssam */ 52020997Skarels if (vs->vs_olen > VVBUFSIZE) { 52120997Skarels printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen); 52211192Ssam panic("vvdriver vs_olen botch"); 52311192Ssam } 52420997Skarels 52520997Skarels vs->vs_if.if_timer = VVTIMEOUT; 52620997Skarels vs->vs_oactive = 1; 52720997Skarels 52820997Skarels /* ship it */ 5297024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 5307024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 5317024Ssam addr = (struct vvreg *)ui->ui_addr; 5327024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 5337024Ssam addr->vvoba = (u_short) ubainfo; 5347024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 5357024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 53620997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */ 53720997Skarels if (addr->vvocsr & VV_NOK) 53820997Skarels vs->vs_init++; /* count ring inits */ 5397024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 5407024Ssam } 5417024Ssam 5427024Ssam /* 54320997Skarels * proNET transmit interrupt 5447024Ssam * Start another output if more data to send. 5457024Ssam */ 5467024Ssam vvxint(unit) 5477024Ssam int unit; 5487024Ssam { 54915764Sleres register struct uba_device *ui; 55015764Sleres register struct vv_softc *vs; 5517024Ssam register struct vvreg *addr; 5527024Ssam register int oc; 5537024Ssam 55415764Sleres ui = vvinfo[unit]; 55515764Sleres vs = &vv_softc[unit]; 55615794Sleres vs->vs_if.if_timer = 0; 5577024Ssam addr = (struct vvreg *)ui->ui_addr; 5587024Ssam oc = 0xffff & (addr->vvocsr); 5597024Ssam if (vs->vs_oactive == 0) { 56020997Skarels vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit, 56115764Sleres oc, VV_OBITS); 5627024Ssam return; 5637024Ssam } 56420997Skarels 56520997Skarels /* 56620997Skarels * we retransmit on soft error 56720997Skarels * TODO: sort retransmits to end of queue if possible! 56820997Skarels */ 56920997Skarels if (oc & (VV_OPT | VV_RFS)) { 57011192Ssam if (vs->vs_tries++ < VVRETRY) { 5717024Ssam if (oc & VV_OPT) 57220997Skarels vs->vs_otimeout++; 57320997Skarels if (oc & VV_RFS) { 57420997Skarels vs->vs_if.if_collisions++; 57520997Skarels vs->vs_refused++; 57620997Skarels } 57711192Ssam vvstart(unit); /* restart this message */ 5787024Ssam return; 5797024Ssam } 5807024Ssam } 5817024Ssam vs->vs_if.if_opackets++; 5827024Ssam vs->vs_oactive = 0; 5837024Ssam vs->vs_tries = 0; 58420997Skarels 5857024Ssam if (oc & VVXERR) { 5867024Ssam vs->vs_if.if_oerrors++; 58720997Skarels vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 58815764Sleres VV_OBITS); 5897024Ssam } 5907024Ssam if (vs->vs_ifuba.ifu_xtofree) { 5917024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 5927024Ssam vs->vs_ifuba.ifu_xtofree = 0; 5937024Ssam } 5947024Ssam vvstart(unit); 5957024Ssam } 5967024Ssam 5977024Ssam /* 59815794Sleres * Transmit watchdog timer routine. 59915794Sleres * This routine gets called when we lose a transmit interrupt. 60015794Sleres * The best we can do is try to restart output. 60115794Sleres */ 60215794Sleres vvwatchdog(unit) 60315794Sleres int unit; 60415794Sleres { 60515794Sleres register struct vv_softc *vs; 60615794Sleres register int s; 60715794Sleres 60815794Sleres vs = &vv_softc[unit]; 60920997Skarels vvprintf("vv%d: lost a transmit interrupt.\n", unit); 61015794Sleres vs->vs_timeouts++; 61115794Sleres s = splimp(); 61215794Sleres vvstart(unit); 61315794Sleres splx(s); 61415794Sleres } 61515794Sleres 61615794Sleres /* 61720997Skarels * proNET interface receiver interrupt. 6187024Ssam * If input error just drop packet. 61915764Sleres * Otherwise purge input buffered data path and examine 6207024Ssam * packet to determine type. If can't determine length 62115764Sleres * from type, then have to drop packet. Otherwise decapsulate 6227024Ssam * packet based on type and pass to type specific higher-level 6237024Ssam * input routine. 6247024Ssam */ 6257024Ssam vvrint(unit) 6267024Ssam int unit; 6277024Ssam { 62815764Sleres register struct vv_softc *vs; 62916581Skarels register struct vvreg *addr; 6307024Ssam register struct vv_header *vv; 6317024Ssam register struct ifqueue *inq; 63216581Skarels register struct mbuf *m; 63315794Sleres int ubainfo, len, off, s; 6347640Ssam short resid; 6357024Ssam 63615764Sleres vs = &vv_softc[unit]; 63716581Skarels vs->vs_if.if_ipackets++; 63815764Sleres addr = (struct vvreg *)vvinfo[unit]->ui_addr; 63920997Skarels 6407024Ssam /* 641*26903Sjas * Purge BDP 6427024Ssam */ 6437024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 6447024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 64520997Skarels 64620997Skarels /* 64720997Skarels * receive errors? 64820997Skarels */ 6497024Ssam if (addr->vvicsr & VVRERR) { 65020997Skarels vvprintf("vv%d: receive error, vvicsr = %b\n", unit, 65120997Skarels 0xffff&(addr->vvicsr), VV_IBITS); 65220997Skarels if (addr->vvicsr & VV_BDF) 65320997Skarels vs->vs_ibadf++; 6547640Ssam goto dropit; 6557024Ssam } 6567640Ssam 6577024Ssam /* 65820997Skarels * parity errors? 65920997Skarels */ 66020997Skarels if (addr->vvicsr & VV_LDE) { 66120997Skarels /* we don't have to clear it because the receive command */ 66220997Skarels /* writes 0 to parity bit */ 66320997Skarels vs->vs_parity++; 664*26903Sjas 66520997Skarels /* 66620997Skarels * only on 10 megabit proNET is VV_LDE an end-to-end parity 66720997Skarels * bit. On 80 megabit, it returns to the intended use of 66820997Skarels * node-to-node parity. End-to-end parity errors on 80 megabit 66920997Skarels * give VV_BDF. 67020997Skarels */ 671*26903Sjas if (vs->vs_is80 == 0) 672*26903Sjas goto dropit; 67320997Skarels } 67420997Skarels 67520997Skarels /* 67620997Skarels * Get packet length from residual word count 6777640Ssam * 6787640Ssam * Compute header offset if trailer protocol 6797640Ssam * 6807640Ssam * Pull packet off interface. Off is nonzero if packet 6817640Ssam * has trailing header; if_rubaget will then force this header 6827640Ssam * information to be at the front. The vh_info field 6837640Ssam * carries the offset to the trailer data in trailer 6847640Ssam * format packets. 6857024Ssam */ 6867640Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 68711192Ssam vvtracehdr("vi", vv); 68820997Skarels resid = addr->vviwc & 01777; /* only low 10 bits valid */ 6897640Ssam if (resid) 69020997Skarels resid |= 0176000; /* high 6 bits are undefined */ 69120997Skarels len = ((VVBUFSIZE >> 1) + resid) << 1; 6927640Ssam len -= sizeof(struct vv_header); 69320997Skarels 69420997Skarels if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) { 69520997Skarels vvprintf("vv%d: len too long or short, \ 69620997Skarels len = %d, vvicsr = %b\n", 69715794Sleres unit, len, 0xffff&(addr->vvicsr), VV_IBITS); 6987640Ssam goto dropit; 69915794Sleres } 70020997Skarels 70120997Skarels /* check the protocol header version */ 70220997Skarels if (vv->vh_version != RING_VERSION) { 70320997Skarels vvprintf("vv%d: bad protocol header version %d\n", 70420997Skarels unit, vv->vh_version & 0xff); 70520997Skarels goto dropit; 70620997Skarels } 70720997Skarels 7087640Ssam #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 70913057Ssam if (vv->vh_type >= RING_IPTrailer && 71013057Ssam vv->vh_type < RING_IPTrailer+RING_IPNTrailer) { 7117640Ssam off = (vv->vh_type - RING_IPTrailer) * 512; 71215794Sleres if (off > VVMTU) { 71320997Skarels vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n", 71415794Sleres unit, off, 0xffff&(addr->vvicsr), VV_IBITS); 7157640Ssam goto dropit; 71615794Sleres } 717*26903Sjas vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *)); 718*26903Sjas resid = ntohs(*(vvdataaddr(vv, off+2, u_short *))); 71915794Sleres if (off + resid > len) { 72020997Skarels vvprintf("vv%d: trailer packet too short\n", unit); 72120997Skarels vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n", 72215794Sleres unit, off, resid, 72315794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 7247640Ssam goto dropit; 72515794Sleres } 7267640Ssam len = off + resid; 72711209Ssam } else 7287640Ssam off = 0; 72920997Skarels 73015794Sleres if (len == 0) { 73120997Skarels vvprintf("vv%d: len is zero, vvicsr = %b\n", unit, 73215794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 7337640Ssam goto dropit; 73415794Sleres } 73520997Skarels 73624793Skarels m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if); 73715794Sleres if (m == NULL) { 73820997Skarels vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit, 73915794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 7407640Ssam goto dropit; 74115794Sleres } 7427640Ssam if (off) { 74324793Skarels struct ifnet *ifp; 74424793Skarels 74524793Skarels ifp = *(mtod(m, struct ifnet **)); 74624793Skarels m->m_off += 2 * sizeof (u_short); 74724793Skarels m->m_len -= 2 * sizeof (u_short); 74824793Skarels *(mtod(m, struct ifnet **)) = ifp; 7497640Ssam } 75011192Ssam 75115794Sleres /* Keep track of source address of this packet */ 75215794Sleres vs->vs_lastr = vv->vh_shost; 75320997Skarels 75411192Ssam /* 75515764Sleres * Demultiplex on packet type 75611192Ssam */ 7577024Ssam switch (vv->vh_type) { 75811192Ssam 7597024Ssam #ifdef INET 7607024Ssam case RING_IP: 7617024Ssam schednetisr(NETISR_IP); 7627024Ssam inq = &ipintrq; 7637024Ssam break; 7647024Ssam #endif 7657024Ssam default: 76620997Skarels vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 7677640Ssam m_freem(m); 7687024Ssam goto setup; 7697024Ssam } 77015794Sleres s = splimp(); 7717640Ssam if (IF_QFULL(inq)) { 7727640Ssam IF_DROP(inq); 7737640Ssam m_freem(m); 77411209Ssam } else 7757640Ssam IF_ENQUEUE(inq, m); 77615764Sleres 77715794Sleres splx(s); 7787024Ssam /* 77915764Sleres * Reset for the next packet. 7807024Ssam */ 78115764Sleres setup: 78215764Sleres ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 78315764Sleres addr->vviba = (u_short) ubainfo; 78415764Sleres addr->vviea = (u_short) (ubainfo >> 16); 78520997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 78620997Skarels addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB; 78715764Sleres return; 78811192Ssam 78911192Ssam /* 79011209Ssam * Drop packet on floor -- count them!! 79111192Ssam */ 7927640Ssam dropit: 7937640Ssam vs->vs_if.if_ierrors++; 7947640Ssam goto setup; 7957024Ssam } 7967024Ssam 7977024Ssam /* 79820997Skarels * proNET output routine. 7997024Ssam * Encapsulate a packet of type family for the local net. 8007024Ssam * Use trailer local net encapsulation if enough data in first 8017024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 8027024Ssam */ 8037024Ssam vvoutput(ifp, m0, dst) 8047024Ssam struct ifnet *ifp; 8057024Ssam struct mbuf *m0; 8067024Ssam struct sockaddr *dst; 8077024Ssam { 80816581Skarels register struct mbuf *m; 8097024Ssam register struct vv_header *vv; 8107640Ssam register int off; 81116581Skarels register int unit; 81216581Skarels register struct vvreg *addr; 81316581Skarels register struct vv_softc *vs; 81416581Skarels register int s; 81516581Skarels int type, dest, error; 8167024Ssam 81716581Skarels m = m0; 81816581Skarels unit = ifp->if_unit; 81916581Skarels addr = (struct vvreg *)vvinfo[unit]->ui_addr; 82016581Skarels vs = &vv_softc[unit]; 82120997Skarels 82216581Skarels /* 82320997Skarels * Check to see if the input side has wedged due the UBA 82420997Skarels * vectoring through 0. 82516581Skarels * 82616581Skarels * We are lower than device ipl when we enter this routine, 82716581Skarels * so if the interface is ready with an input packet then 82816581Skarels * an input interrupt must have slipped through the cracks. 82916581Skarels * 83016581Skarels * Avoid the race with an input interrupt by watching to see 83116581Skarels * if any packets come in. 83216581Skarels */ 83316581Skarels s = vs->vs_if.if_ipackets; 83416581Skarels if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) { 83520997Skarels vvprintf("vv%d: lost a receive interrupt, icsr = %b\n", 83616581Skarels unit, 0xffff&(addr->vvicsr), VV_IBITS); 83716581Skarels s = splimp(); 83816581Skarels vvrint(unit); 83916581Skarels splx(s); 84016581Skarels } 84116581Skarels 8427024Ssam switch (dst->sa_family) { 84311192Ssam 8447024Ssam #ifdef INET 84515764Sleres case AF_INET: 84621779Skarels if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) 84721779Skarels dest = VV_BROADCAST; 84821779Skarels else 84921779Skarels dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr); 85020997Skarels #ifdef LOOPBACK 85121779Skarels if (dest == vs->vs_host && (loif.if_flags & IFF_UP)) 85221779Skarels return (looutput(&loif, m0, dst)); 85320997Skarels #endif LOOPBACK 85421779Skarels if (dest >= 0x100) { 8557640Ssam error = EPERM; 8567640Ssam goto bad; 8577640Ssam } 8587640Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 85920997Skarels /* 86020997Skarels * Trailerize, if the configuration allows it. 86120997Skarels * TODO: Need per host negotiation. 86220997Skarels */ 86313090Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 86413090Ssam if (off > 0 && (off & 0x1ff) == 0 && 8657640Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 8667640Ssam type = RING_IPTrailer + (off>>9); 8677640Ssam m->m_off -= 2 * sizeof (u_short); 8687640Ssam m->m_len += 2 * sizeof (u_short); 869*26903Sjas *mtod(m, u_short *) = htons(RING_IP); 870*26903Sjas *(mtod(m, u_short *) + 1) = htons(m->m_len); 8717640Ssam goto gottrailertype; 8727640Ssam } 8737024Ssam type = RING_IP; 8747024Ssam off = 0; 8757024Ssam goto gottype; 8767024Ssam #endif 8777024Ssam default: 87816581Skarels printf("vv%d: can't handle af%d\n", unit, dst->sa_family); 8797640Ssam error = EAFNOSUPPORT; 8807640Ssam goto bad; 8817024Ssam } 8827024Ssam 8837024Ssam gottrailertype: 8847024Ssam /* 8857024Ssam * Packet to be sent as trailer: move first packet 8867024Ssam * (control information) to end of chain. 8877024Ssam */ 8887024Ssam while (m->m_next) 8897024Ssam m = m->m_next; 8907024Ssam m->m_next = m0; 8917024Ssam m = m0->m_next; 8927024Ssam m0->m_next = 0; 8937024Ssam m0 = m; 8947024Ssam gottype: 8957024Ssam /* 8967024Ssam * Add local net header. If no space in first mbuf, 8977024Ssam * allocate another. 8987024Ssam */ 8997024Ssam if (m->m_off > MMAXOFF || 9007024Ssam MMINOFF + sizeof (struct vv_header) > m->m_off) { 90111209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 90211209Ssam if (m == NULL) { 9037640Ssam error = ENOBUFS; 9047640Ssam goto bad; 9057024Ssam } 9067024Ssam m->m_next = m0; 9077024Ssam m->m_off = MMINOFF; 9087024Ssam m->m_len = sizeof (struct vv_header); 9097024Ssam } else { 9107024Ssam m->m_off -= sizeof (struct vv_header); 9117024Ssam m->m_len += sizeof (struct vv_header); 9127024Ssam } 9137024Ssam vv = mtod(m, struct vv_header *); 91421779Skarels vv->vh_shost = vs->vs_host; 91521779Skarels vv->vh_dhost = dest; 9167024Ssam vv->vh_version = RING_VERSION; 9177024Ssam vv->vh_type = type; 918*26903Sjas vv->vh_info = htons(off); 91911192Ssam vvtracehdr("vo", vv); 9207024Ssam 9217024Ssam /* 9227024Ssam * Queue message on interface, and start output if interface 9237024Ssam * not yet active. 9247024Ssam */ 9257024Ssam s = splimp(); 9267640Ssam if (IF_QFULL(&ifp->if_snd)) { 9277640Ssam IF_DROP(&ifp->if_snd); 9287640Ssam error = ENOBUFS; 9297640Ssam goto qfull; 9307640Ssam } 9317024Ssam IF_ENQUEUE(&ifp->if_snd, m); 93216581Skarels if (vs->vs_oactive == 0) 93316581Skarels vvstart(unit); 9347024Ssam splx(s); 9357640Ssam return (0); 9367640Ssam qfull: 9377640Ssam m0 = m; 9387640Ssam splx(s); 9397640Ssam bad: 9407640Ssam m_freem(m0); 9417640Ssam return(error); 9427024Ssam } 9437024Ssam 9447024Ssam /* 94513057Ssam * Process an ioctl request. 94613057Ssam */ 94713057Ssam vvioctl(ifp, cmd, data) 94813057Ssam register struct ifnet *ifp; 94913057Ssam int cmd; 95013057Ssam caddr_t data; 95113057Ssam { 95221779Skarels struct ifaddr *ifa = (struct ifaddr *) data; 95321779Skarels int s = splimp(), error = 0; 95413057Ssam 95513057Ssam switch (cmd) { 95613057Ssam 95713057Ssam case SIOCSIFADDR: 95824793Skarels ifp->if_flags |= IFF_UP; 95921779Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 96013057Ssam vvinit(ifp->if_unit); 961*26903Sjas /* 962*26903Sjas * Did self-test succeed? 963*26903Sjas */ 964*26903Sjas if ((ifp->if_flags & IFF_UP) == 0) 965*26903Sjas error = ENETDOWN; 96621779Skarels /* 96721779Skarels * Attempt to check agreement of protocol address 96821779Skarels * and board address. 96921779Skarels */ 97021779Skarels switch (ifa->ifa_addr.sa_family) { 97121779Skarels case AF_INET: 97221779Skarels if (in_lnaof(IA_SIN(ifa)->sin_addr) != 97321779Skarels vv_softc[ifp->if_unit].vs_host) 97425194Skarels error = EADDRNOTAVAIL; 97521779Skarels break; 97621779Skarels } 97713057Ssam break; 97813057Ssam 97913057Ssam default: 98013057Ssam error = EINVAL; 98113057Ssam } 98213057Ssam splx(s); 98321779Skarels return (error); 98413057Ssam } 98525190Skarels 98625190Skarels /* 98725190Skarels * vvprt_hdr(s, v) print the local net header in "v" 98825190Skarels * with title is "s" 98925190Skarels */ 99025190Skarels vvprt_hdr(s, v) 99125190Skarels char *s; 99225190Skarels register struct vv_header *v; 99325190Skarels { 99425190Skarels printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 99525190Skarels s, 99625190Skarels 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 99725190Skarels 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 99825190Skarels 0xffff & (int)(v->vh_info)); 99925190Skarels } 1000*26903Sjas #endif NVV 1001