123305Smckusick /* 229372Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 3*35328Sbostic * All rights reserved. 423305Smckusick * 5*35328Sbostic * Redistribution and use in source and binary forms are permitted 6*35328Sbostic * provided that the above copyright notice and this paragraph are 7*35328Sbostic * duplicated in all such forms and that any documentation, 8*35328Sbostic * advertising materials, and other materials related to such 9*35328Sbostic * distribution and use acknowledge that the software was developed 10*35328Sbostic * by the University of California, Berkeley. The name of the 11*35328Sbostic * University may not be used to endorse or promote products derived 12*35328Sbostic * from this software without specific prior written permission. 13*35328Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35328Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35328Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*35328Sbostic * 17*35328Sbostic * @(#)if_vv.c 7.2 (Berkeley) 08/04/88 1823305Smckusick */ 197024Ssam 209799Ssam #include "vv.h" 2125275Sbloom #if NVV > 0 2211192Ssam 237024Ssam /* 2420997Skarels * Proteon proNET-10 and proNET-80 token ring driver. 2520997Skarels * The name of this device driver derives from the old MIT 2620997Skarels * name of V2LNI for the proNET hardware, would would abbreviate 2720997Skarels * to "v2", but this won't work right. Thus the name is "vv". 2811192Ssam * 2920997Skarels * This driver is compatible with the proNET 10 meagbit and 3020997Skarels * 80 megabit token ring interfaces (models p1000 and p1080). 3126903Sjas * A unit may be marked as 80 megabit using "flags 1" in the 3226903Sjas * config file. 3320997Skarels * 3426950Sjas * TRAILERS: This driver has a new implementation of trailers that 3526950Sjas * is at least a tolerable neighbor on the ring. The offset is not 3626950Sjas * stored in the protocol type, but instead only in the vh_info 3726950Sjas * field. Also, the vh_info field, and the two shorts before the 3826950Sjas * trailing header, are in network byte order, not VAX byte order. 3920997Skarels * 4026950Sjas * Of course, nothing but BSD UNIX supports trailers on ProNET. 4126950Sjas * If you need interoperability with anything else, turn off 4226950Sjas * trailers using the -trailers option to /etc/ifconfig! 4326950Sjas * 4426903Sjas * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001) 4520997Skarels * have a serial number >= 040, which is about March, 1982. Older 4626903Sjas * HSBUs do not carry across 64kbyte boundaries. They can be supported 4726903Sjas * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization 4826903Sjas * in vvattach(). 4926903Sjas * 5026903Sjas * The old warning about use without Wire Centers applies only to CTL 5126903Sjas * (p1002) cards with serial <= 057, which have not received ECO 176-743, 5226903Sjas * which was implemented in March, 1982. Most such CTLs have received 5326903Sjas * this ECO. 547024Ssam */ 5511209Ssam #include "../machine/pte.h" 569799Ssam 5717117Sbloom #include "param.h" 5817117Sbloom #include "systm.h" 5917117Sbloom #include "mbuf.h" 6017117Sbloom #include "buf.h" 6117117Sbloom #include "protosw.h" 6217117Sbloom #include "socket.h" 6317117Sbloom #include "vmmac.h" 6417117Sbloom #include "errno.h" 6517117Sbloom #include "ioctl.h" 668465Sroot 678465Sroot #include "../net/if.h" 6811209Ssam #include "../net/netisr.h" 698465Sroot #include "../net/route.h" 7024793Skarels 7124793Skarels #ifdef INET 728421Swnj #include "../netinet/in.h" 738421Swnj #include "../netinet/in_systm.h" 7421779Skarels #include "../netinet/in_var.h" 758421Swnj #include "../netinet/ip.h" 7624793Skarels #endif 778465Sroot 7815794Sleres #include "../vax/cpu.h" 7911209Ssam #include "../vax/mtpr.h" 8017117Sbloom #include "if_vv.h" 8117117Sbloom #include "if_uba.h" 828465Sroot #include "../vaxuba/ubareg.h" 838465Sroot #include "../vaxuba/ubavar.h" 847024Ssam 857024Ssam /* 8620997Skarels * maximum transmission unit definition -- 8720997Skarels * you can set VVMTU at anything from 576 to 2024. 8820997Skarels * 1536 is a popular "large" value, because it is a multiple 8920997Skarels * of 512, which the trailer scheme likes. 9020997Skarels * The absolute maximum size is 2024, which is enforced. 9120997Skarels */ 9220997Skarels 9324793Skarels #define VVMTU (1536) 9420997Skarels 9520997Skarels #define VVMRU (VVMTU + 16) 9620997Skarels #define VVBUFSIZE (VVMRU + sizeof(struct vv_header)) 9720997Skarels #if VVMTU>2024 9820997Skarels #undef VVMTU 9920997Skarels #undef VVMRU 10020997Skarels #undef VVBUFSIZE 10120997Skarels #define VVBUFSIZE (2046) 10220997Skarels #define VVMRU (VVBUFSIZE - sizeof (struct vv_header)) 10320997Skarels #define VVMTU (VVMRU - 16) 1047024Ssam #endif 1057024Ssam 10620997Skarels /* 10720997Skarels * debugging and tracing stuff 10820997Skarels */ 10916581Skarels int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */ 1107640Ssam 11120997Skarels #define vvtracehdr if (vv_tracehdr) vvprt_hdr 11221779Skarels #define vvprintf if (vs->vs_if.if_flags & IFF_DEBUG) printf 11311192Ssam 11420997Skarels /* 11520997Skarels * externals, types, etc. 11620997Skarels */ 11716581Skarels int vvprobe(), vvattach(), vvreset(), vvinit(); 11816581Skarels int vvidentify(), vvstart(), vvxint(), vvwatchdog(); 11926394Skarels int vvrint(), vvoutput(), vvioctl(); 1207024Ssam struct uba_device *vvinfo[NVV]; 1217024Ssam u_short vvstd[] = { 0 }; 1227024Ssam struct uba_driver vvdriver = 1237024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 1247024Ssam #define VVUNIT(x) minor(x) 1257024Ssam 12620997Skarels #define LOOPBACK /* use loopback for packets meant for us */ 12720997Skarels #ifdef LOOPBACK 12820997Skarels extern struct ifnet loif; 12920997Skarels #endif 13020997Skarels 1317024Ssam /* 1327024Ssam * Software status of each interface. 1337024Ssam * 1347024Ssam * Each interface is referenced by a network interface structure, 1357024Ssam * vs_if, which the routing code uses to locate the interface. 1367024Ssam * This structure contains the output queue for the interface, its address, ... 1377024Ssam * We also have, for each interface, a UBA interface structure, which 1387024Ssam * contains information about the UNIBUS resources held by the interface: 1397024Ssam * map registers, buffered data paths, etc. Information is cached in this 1407024Ssam * structure for use by the if_uba.c routines in running the interface 1417024Ssam * efficiently. 1427024Ssam */ 1437024Ssam struct vv_softc { 1447024Ssam struct ifnet vs_if; /* network-visible interface */ 1457024Ssam struct ifuba vs_ifuba; /* UNIBUS resources */ 14626298Skarels u_short vs_host; /* this interface address */ 14711192Ssam short vs_oactive; /* is output active */ 14826903Sjas short vs_is80; /* is 80 megabit version */ 1497024Ssam short vs_olen; /* length of last output */ 15015794Sleres u_short vs_lastx; /* address of last packet sent */ 15115794Sleres u_short vs_lastr; /* address of last packet received */ 15211192Ssam short vs_tries; /* transmit current retry count */ 1537024Ssam short vs_init; /* number of ring inits */ 15420997Skarels short vs_refused; /* number of packets refused */ 15515794Sleres short vs_timeouts; /* number of transmit timeouts */ 15620997Skarels short vs_otimeout; /* number of output timeouts */ 15720997Skarels short vs_ibadf; /* number of input bad formats */ 15820997Skarels short vs_parity; /* number of parity errors on 10 meg, */ 15920997Skarels /* link data errors on 80 meg */ 1607024Ssam } vv_softc[NVV]; 1617024Ssam 16226311Skarels #define NOHOST 0xffff /* illegal host number */ 16326311Skarels 16420997Skarels /* 16520997Skarels * probe the interface to see that the registers exist, and then 16620997Skarels * cause an interrupt to find its vector 16720997Skarels */ 1687024Ssam vvprobe(reg) 1697024Ssam caddr_t reg; 1707024Ssam { 1717024Ssam register int br, cvec; 17216581Skarels register struct vvreg *addr; 1737024Ssam 1747024Ssam #ifdef lint 17515764Sleres br = 0; cvec = br; br = cvec; 1767024Ssam #endif 17716581Skarels addr = (struct vvreg *)reg; 17820997Skarels 1797024Ssam /* reset interface, enable, and wait till dust settles */ 1807024Ssam addr->vvicsr = VV_RST; 1817024Ssam addr->vvocsr = VV_RST; 18215764Sleres DELAY(100000); 18320997Skarels 1847024Ssam /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 1857024Ssam addr->vvoba = 0; /* low 16 bits */ 1867024Ssam addr->vvoea = 0; /* extended bits */ 1877024Ssam addr->vvowc = -1; /* for 1 word */ 18820997Skarels addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */ 1897024Ssam DELAY(100000); 19020997Skarels addr->vvocsr = VV_RST; /* clear out the CSR */ 1917024Ssam if (cvec && cvec != 0x200) 19215764Sleres cvec -= 4; /* backup so vector => receive */ 1937024Ssam return(1); 1947024Ssam } 1957024Ssam 1967024Ssam /* 1977024Ssam * Interface exists: make available by filling in network interface 1987024Ssam * record. System will initialize the interface when it is ready 1997024Ssam * to accept packets. 2007024Ssam */ 2017024Ssam vvattach(ui) 2027024Ssam struct uba_device *ui; 2037024Ssam { 20415764Sleres register struct vv_softc *vs; 2057024Ssam 20615764Sleres vs = &vv_softc[ui->ui_unit]; 2077024Ssam vs->vs_if.if_unit = ui->ui_unit; 2087024Ssam vs->vs_if.if_name = "vv"; 2097024Ssam vs->vs_if.if_mtu = VVMTU; 21021779Skarels vs->vs_if.if_flags = IFF_BROADCAST; 2117024Ssam vs->vs_if.if_init = vvinit; 21213057Ssam vs->vs_if.if_ioctl = vvioctl; 2137024Ssam vs->vs_if.if_output = vvoutput; 21411209Ssam vs->vs_if.if_reset = vvreset; 21515794Sleres vs->vs_if.if_timer = 0; 21615794Sleres vs->vs_if.if_watchdog = vvwatchdog; 21726201Skarels vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP; 21826903Sjas 21926903Sjas /* use flag to determine if this is proNET-80 */ 22026903Sjas vs->vs_is80 = (short)(ui->ui_flags & 01); 22126903Sjas 22212354Smo #if defined(VAX750) 22312354Smo /* don't chew up 750 bdp's */ 22412354Smo if (cpu == VAX_750 && ui->ui_unit > 0) 22512354Smo vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 22612354Smo #endif 2277024Ssam if_attach(&vs->vs_if); 2287024Ssam } 2297024Ssam 2307024Ssam /* 2317024Ssam * Reset of interface after UNIBUS reset. 2327024Ssam * If interface is on specified uba, reset its state. 2337024Ssam */ 2347024Ssam vvreset(unit, uban) 2357024Ssam int unit, uban; 2367024Ssam { 2377024Ssam register struct uba_device *ui; 2387024Ssam 2397024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 2407024Ssam ui->ui_ubanum != uban) 2417024Ssam return; 2427024Ssam printf(" vv%d", unit); 2437024Ssam vvinit(unit); 2447024Ssam } 2457024Ssam 2467024Ssam /* 2477024Ssam * Initialization of interface; clear recorded pending 2487024Ssam * operations, and reinitialize UNIBUS usage. 2497024Ssam */ 2507024Ssam vvinit(unit) 2517024Ssam int unit; 2527024Ssam { 25315764Sleres register struct vv_softc *vs; 25415764Sleres register struct uba_device *ui; 2557024Ssam register struct vvreg *addr; 25616581Skarels register int ubainfo, s; 2577024Ssam 25815764Sleres vs = &vv_softc[unit]; 25915764Sleres ui = vvinfo[unit]; 26020997Skarels 26121779Skarels if (vs->vs_if.if_addrlist == (struct ifaddr *)0) 26213057Ssam return; 26320997Skarels 2647640Ssam addr = (struct vvreg *)ui->ui_addr; 2657024Ssam if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 26615764Sleres sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 26715794Sleres printf("vv%d: can't initialize, if_ubainit() failed\n", unit); 2687640Ssam vs->vs_if.if_flags &= ~IFF_UP; 2697024Ssam return; 2707024Ssam } 27120997Skarels 2727024Ssam /* 27315764Sleres * Now that the uba is set up, figure out our address and 27415764Sleres * update complete our host address. 2757640Ssam */ 27626311Skarels if ((vs->vs_host = vvidentify(unit)) == NOHOST) { 27715794Sleres vs->vs_if.if_flags &= ~IFF_UP; 27815794Sleres return; 27915794Sleres } 28026903Sjas printf("vv%d: host %u\n", unit, vs->vs_host); 28120997Skarels 2827640Ssam /* 28320997Skarels * Reset the interface, and stay in the ring 2847640Ssam */ 28520997Skarels addr->vvocsr = VV_RST; /* take over output */ 28620997Skarels addr->vvocsr = VV_CPB; /* clear packet buffer */ 28720997Skarels addr->vvicsr = VV_RST | VV_HEN; /* take over input, */ 28820997Skarels /* keep relay closed */ 28912351Smo DELAY(500000); /* let contacts settle */ 29020997Skarels 29120997Skarels vs->vs_init = 0; /* clear counters, etc. */ 29220997Skarels vs->vs_refused = 0; 29315794Sleres vs->vs_timeouts = 0; 29420997Skarels vs->vs_otimeout = 0; 29520997Skarels vs->vs_ibadf = 0; 29620997Skarels vs->vs_parity = 0; 29715794Sleres vs->vs_lastx = 256; /* an invalid address */ 29815794Sleres vs->vs_lastr = 256; /* an invalid address */ 29920997Skarels 3007640Ssam /* 3017640Ssam * Hang a receive and start any 3027640Ssam * pending writes by faking a transmit complete. 3037640Ssam */ 3047640Ssam s = splimp(); 3057640Ssam ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 30613057Ssam addr->vviba = (u_short)ubainfo; 30713057Ssam addr->vviea = (u_short)(ubainfo >> 16); 30820997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 30920997Skarels addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB; 3107640Ssam vs->vs_oactive = 1; 31121779Skarels vs->vs_if.if_flags |= IFF_RUNNING; 3127640Ssam vvxint(unit); 3137640Ssam splx(s); 3147640Ssam } 3157640Ssam 3167640Ssam /* 31720997Skarels * Do a moderately thorough self-test in all three modes. Mostly 31820997Skarels * to keeps defective nodes off the ring, rather than to be especially 31920997Skarels * thorough. The key issue is to detect any cable breaks before joining 32020997Skarels * the ring. Return our node address on success, return -1 on failure. 32120997Skarels * 3227640Ssam */ 32320997Skarels 32420997Skarels /* the three self-test modes */ 32520997Skarels static u_short vv_modes[] = { 32620997Skarels VV_STE|VV_LPB, /* digital loopback */ 32720997Skarels VV_STE, /* analog loopback */ 32820997Skarels VV_HEN /* network mode */ 32920997Skarels }; 33020997Skarels 33111209Ssam vvidentify(unit) 33213057Ssam int unit; 33311209Ssam { 33415764Sleres register struct vv_softc *vs; 33515764Sleres register struct uba_device *ui; 3367640Ssam register struct vvreg *addr; 33716581Skarels register struct mbuf *m; 33816581Skarels register struct vv_header *v; 33920997Skarels register int ubainfo; 34020997Skarels register int i, successes, failures, waitcount; 34126311Skarels u_short shost = NOHOST; 3427640Ssam 34320997Skarels vs = &vv_softc[unit]; 34420997Skarels ui = vvinfo[unit]; 34520997Skarels addr = (struct vvreg *)ui->ui_addr; 34620997Skarels 3477640Ssam /* 3487024Ssam * Build a multicast message to identify our address 34920997Skarels * We need do this only once, since nobody else is about to use 35020997Skarels * the intermediate transmit buffer (ifu_w.ifrw_addr) that 35120997Skarels * if_ubainit() aquired for us. 3527024Ssam */ 35311209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 35415794Sleres if (m == NULL) { 35515794Sleres printf("vv%d: can't initialize, m_get() failed\n", unit); 35613057Ssam return (0); 35715794Sleres } 35811192Ssam m->m_next = 0; 3597024Ssam m->m_off = MMINOFF; 3607024Ssam m->m_len = sizeof(struct vv_header); 3617024Ssam v = mtod(m, struct vv_header *); 36211192Ssam v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 3637024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 3647024Ssam v->vh_version = RING_VERSION; 36520997Skarels v->vh_type = RING_DIAGNOSTICS; 3667024Ssam v->vh_info = 0; 36720997Skarels /* map xmit message into uba, copying to intermediate buffer */ 36820997Skarels vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 36920997Skarels 3707024Ssam /* 37120997Skarels * For each of the modes (digital, analog, network), go through 37220997Skarels * a self-test that requires me to send VVIDENTSUCC good packets 37320997Skarels * in VVIDENTRETRY attempts. Use broadcast destination to find out 37420997Skarels * who I am, then use this as my address to check my address match 37520997Skarels * logic. Only data checked is the vh_type field. 3767024Ssam */ 3777640Ssam 37820997Skarels for (i = 0; i < 3; i++) { 37920997Skarels successes = 0; /* clear successes for this mode */ 38020997Skarels failures = 0; /* and clear failures, too */ 3817640Ssam 38220997Skarels /* take over device, and leave ring */ 38320997Skarels addr->vvicsr = VV_RST; 38420997Skarels addr->vvocsr = VV_RST; 38520997Skarels addr->vvicsr = vv_modes[i]; /* test mode */ 38620997Skarels 38720997Skarels /* 38820997Skarels * let the flag and token timers pop so that the init ring bit 38920997Skarels * will be allowed to work, by waiting about 1 second 39020997Skarels */ 39120997Skarels DELAY(1000000L); 39220997Skarels 39320997Skarels /* 39420997Skarels * retry loop 39520997Skarels */ 39620997Skarels while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY)) 39720997Skarels { 39820997Skarels /* start a receive */ 39920997Skarels ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 40020997Skarels addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */ 40120997Skarels addr->vviba = (u_short) ubainfo; 40220997Skarels addr->vviea = (u_short) (ubainfo >> 16); 40320997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 40420997Skarels addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB; 40520997Skarels 40620997Skarels /* purge stale data from BDP */ 40720997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 40820997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 40920997Skarels vs->vs_ifuba.ifu_w.ifrw_bdp); 41020997Skarels 41120997Skarels /* do a transmit */ 41220997Skarels ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 41320997Skarels addr->vvocsr = VV_RST; /* abort last try */ 41420997Skarels addr->vvoba = (u_short) ubainfo; 41520997Skarels addr->vvoea = (u_short) (ubainfo >> 16); 41620997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); 41720997Skarels addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 41820997Skarels 41920997Skarels /* poll receive side for completion */ 42020997Skarels DELAY(10000); /* give it a chance */ 42120997Skarels for (waitcount = 0; waitcount < 10; waitcount++) { 42220997Skarels if (addr->vvicsr & VV_RDY) 42320997Skarels goto gotit; 42420997Skarels DELAY(1000); 42520997Skarels } 42620997Skarels failures++; /* no luck */ 42711209Ssam continue; 42820997Skarels 42920997Skarels gotit: /* we got something--is it any good? */ 43020997Skarels if ((addr->vvicsr & (VVRERR|VV_LDE)) || 43121779Skarels (addr->vvocsr & (VVXERR|VV_RFS))) { 43220997Skarels failures++; 43320997Skarels continue; 43420997Skarels } 43520997Skarels 43620997Skarels /* Purge BDP before looking at received packet */ 43720997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 43820997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 43920997Skarels vs->vs_ifuba.ifu_r.ifrw_bdp); 44024793Skarels m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 44126394Skarels 0, &vs->vs_if); 44220997Skarels if (m != NULL) 44320997Skarels m_freem(m); 44420997Skarels 44520997Skarels v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 44620997Skarels 44720997Skarels /* check message type, catch our node address */ 44820997Skarels if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) { 44926311Skarels if (shost == NOHOST) { 45020997Skarels shost = v->vh_shost & 0xff; 45120997Skarels /* send to ourself now */ 45220997Skarels ((struct vv_header *) 45320997Skarels (vs->vs_ifuba.ifu_r.ifrw_addr)) 45420997Skarels ->vh_dhost = shost; 45520997Skarels } 45620997Skarels successes++; 45726903Sjas } else { 45826903Sjas failures++; 45920997Skarels } 46026903Sjas v->vh_type = 0; /* clear to check again */ 46111192Ssam } 46220997Skarels 46320997Skarels if (failures >= VVIDENTRETRY) 46420997Skarels { 46520997Skarels printf("vv%d: failed self-test after %d tries \ 46620997Skarels in %s mode\n", 46720997Skarels unit, VVIDENTRETRY, i == 0 ? "digital loopback" : 46820997Skarels (i == 1 ? "analog loopback" : "network")); 46920997Skarels printf("vv%d: icsr = %b, ocsr = %b\n", 47020997Skarels unit, 0xffff & addr->vvicsr, VV_IBITS, 47120997Skarels 0xffff & addr->vvocsr, VV_OBITS); 47220997Skarels addr->vvicsr = VV_RST; /* kill the sick board */ 47320997Skarels addr->vvocsr = VV_RST; 47426311Skarels shost = NOHOST; 47520997Skarels goto done; 47620997Skarels } 47711192Ssam } 47820997Skarels 47920997Skarels done: 48020997Skarels /* deallocate mbuf used for send packet (won't be one, anyways) */ 48115794Sleres if (vs->vs_ifuba.ifu_xtofree) { 4827024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 48315794Sleres vs->vs_ifuba.ifu_xtofree = 0; 48415794Sleres } 48520997Skarels 48620997Skarels return(shost); 4877024Ssam } 4887024Ssam 4897024Ssam /* 4907024Ssam * Start or restart output on interface. 49111192Ssam * If interface is active, this is a retransmit, so just 49211192Ssam * restuff registers and go. 4937024Ssam * If interface is not already active, get another datagram 4947024Ssam * to send off of the interface queue, and map it to the interface 4957024Ssam * before starting the output. 4967024Ssam */ 4977024Ssam vvstart(dev) 4987024Ssam dev_t dev; 4997024Ssam { 50016581Skarels register struct uba_device *ui; 50115764Sleres register struct vv_softc *vs; 5027024Ssam register struct vvreg *addr; 50316581Skarels register struct mbuf *m; 50416581Skarels register int unit, ubainfo, dest, s; 5057024Ssam 50616581Skarels unit = VVUNIT(dev); 50715764Sleres ui = vvinfo[unit]; 50815764Sleres vs = &vv_softc[unit]; 5097024Ssam if (vs->vs_oactive) 5107024Ssam goto restart; 5117024Ssam /* 5127024Ssam * Not already active: dequeue another request 5137024Ssam * and map it to the UNIBUS. If no more requests, 5147024Ssam * just return. 5157024Ssam */ 51615794Sleres s = splimp(); 5177024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 51815794Sleres splx(s); 51911209Ssam if (m == NULL) { 5207024Ssam vs->vs_oactive = 0; 5217024Ssam return; 5227024Ssam } 5237024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 5247024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 5257024Ssam vs->vs_lastx = dest; 5267024Ssam restart: 5277024Ssam /* 5287024Ssam * Have request mapped to UNIBUS for transmission. 52915794Sleres * Purge any stale data from this BDP, and start the output. 53015794Sleres * 53115794Sleres * Make sure this packet will fit in the interface. 5327024Ssam */ 53320997Skarels if (vs->vs_olen > VVBUFSIZE) { 53420997Skarels printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen); 53511192Ssam panic("vvdriver vs_olen botch"); 53611192Ssam } 53720997Skarels 53820997Skarels vs->vs_if.if_timer = VVTIMEOUT; 53920997Skarels vs->vs_oactive = 1; 54020997Skarels 54120997Skarels /* ship it */ 5427024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 5437024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 5447024Ssam addr = (struct vvreg *)ui->ui_addr; 5457024Ssam ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 5467024Ssam addr->vvoba = (u_short) ubainfo; 5477024Ssam addr->vvoea = (u_short) (ubainfo >> 16); 5487024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 54920997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */ 55020997Skarels if (addr->vvocsr & VV_NOK) 55120997Skarels vs->vs_init++; /* count ring inits */ 5527024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 5537024Ssam } 5547024Ssam 5557024Ssam /* 55620997Skarels * proNET transmit interrupt 5577024Ssam * Start another output if more data to send. 5587024Ssam */ 5597024Ssam vvxint(unit) 5607024Ssam int unit; 5617024Ssam { 56215764Sleres register struct uba_device *ui; 56315764Sleres register struct vv_softc *vs; 5647024Ssam register struct vvreg *addr; 5657024Ssam register int oc; 5667024Ssam 56715764Sleres ui = vvinfo[unit]; 56815764Sleres vs = &vv_softc[unit]; 56915794Sleres vs->vs_if.if_timer = 0; 5707024Ssam addr = (struct vvreg *)ui->ui_addr; 5717024Ssam oc = 0xffff & (addr->vvocsr); 5727024Ssam if (vs->vs_oactive == 0) { 57320997Skarels vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit, 57415764Sleres oc, VV_OBITS); 5757024Ssam return; 5767024Ssam } 57720997Skarels 57820997Skarels /* 57920997Skarels * we retransmit on soft error 58020997Skarels * TODO: sort retransmits to end of queue if possible! 58120997Skarels */ 58220997Skarels if (oc & (VV_OPT | VV_RFS)) { 58311192Ssam if (vs->vs_tries++ < VVRETRY) { 5847024Ssam if (oc & VV_OPT) 58520997Skarels vs->vs_otimeout++; 58620997Skarels if (oc & VV_RFS) { 58720997Skarels vs->vs_if.if_collisions++; 58820997Skarels vs->vs_refused++; 58920997Skarels } 59011192Ssam vvstart(unit); /* restart this message */ 5917024Ssam return; 5927024Ssam } 5937024Ssam } 5947024Ssam vs->vs_if.if_opackets++; 5957024Ssam vs->vs_oactive = 0; 5967024Ssam vs->vs_tries = 0; 59720997Skarels 5987024Ssam if (oc & VVXERR) { 5997024Ssam vs->vs_if.if_oerrors++; 60020997Skarels vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 60115764Sleres VV_OBITS); 6027024Ssam } 6037024Ssam if (vs->vs_ifuba.ifu_xtofree) { 6047024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 6057024Ssam vs->vs_ifuba.ifu_xtofree = 0; 6067024Ssam } 6077024Ssam vvstart(unit); 6087024Ssam } 6097024Ssam 6107024Ssam /* 61115794Sleres * Transmit watchdog timer routine. 61215794Sleres * This routine gets called when we lose a transmit interrupt. 61315794Sleres * The best we can do is try to restart output. 61415794Sleres */ 61515794Sleres vvwatchdog(unit) 61615794Sleres int unit; 61715794Sleres { 61815794Sleres register struct vv_softc *vs; 61915794Sleres register int s; 62015794Sleres 62115794Sleres vs = &vv_softc[unit]; 62220997Skarels vvprintf("vv%d: lost a transmit interrupt.\n", unit); 62315794Sleres vs->vs_timeouts++; 62415794Sleres s = splimp(); 62515794Sleres vvstart(unit); 62615794Sleres splx(s); 62715794Sleres } 62815794Sleres 62915794Sleres /* 63020997Skarels * proNET interface receiver interrupt. 6317024Ssam * If input error just drop packet. 63215764Sleres * Otherwise purge input buffered data path and examine 6337024Ssam * packet to determine type. If can't determine length 63415764Sleres * from type, then have to drop packet. Otherwise decapsulate 6357024Ssam * packet based on type and pass to type specific higher-level 6367024Ssam * input routine. 6377024Ssam */ 6387024Ssam vvrint(unit) 6397024Ssam int unit; 6407024Ssam { 64115764Sleres register struct vv_softc *vs; 64216581Skarels register struct vvreg *addr; 6437024Ssam register struct vv_header *vv; 6447024Ssam register struct ifqueue *inq; 64516581Skarels register struct mbuf *m; 64615794Sleres int ubainfo, len, off, s; 6477640Ssam short resid; 6487024Ssam 64915764Sleres vs = &vv_softc[unit]; 65016581Skarels vs->vs_if.if_ipackets++; 65115764Sleres addr = (struct vvreg *)vvinfo[unit]->ui_addr; 65220997Skarels 6537024Ssam /* 65426903Sjas * Purge BDP 6557024Ssam */ 6567024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 6577024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 65820997Skarels 65920997Skarels /* 66020997Skarels * receive errors? 66120997Skarels */ 6627024Ssam if (addr->vvicsr & VVRERR) { 66320997Skarels vvprintf("vv%d: receive error, vvicsr = %b\n", unit, 66420997Skarels 0xffff&(addr->vvicsr), VV_IBITS); 66520997Skarels if (addr->vvicsr & VV_BDF) 66620997Skarels vs->vs_ibadf++; 6677640Ssam goto dropit; 6687024Ssam } 6697640Ssam 6707024Ssam /* 67120997Skarels * parity errors? 67220997Skarels */ 67320997Skarels if (addr->vvicsr & VV_LDE) { 67420997Skarels /* we don't have to clear it because the receive command */ 67520997Skarels /* writes 0 to parity bit */ 67620997Skarels vs->vs_parity++; 67726903Sjas 67820997Skarels /* 67920997Skarels * only on 10 megabit proNET is VV_LDE an end-to-end parity 68020997Skarels * bit. On 80 megabit, it returns to the intended use of 68120997Skarels * node-to-node parity. End-to-end parity errors on 80 megabit 68220997Skarels * give VV_BDF. 68320997Skarels */ 68426903Sjas if (vs->vs_is80 == 0) 68526903Sjas goto dropit; 68620997Skarels } 68720997Skarels 68820997Skarels /* 68920997Skarels * Get packet length from residual word count 6907640Ssam * 6917640Ssam * Compute header offset if trailer protocol 6927640Ssam * 6937640Ssam * Pull packet off interface. Off is nonzero if packet 6947640Ssam * has trailing header; if_rubaget will then force this header 6957640Ssam * information to be at the front. The vh_info field 6967640Ssam * carries the offset to the trailer data in trailer 6977640Ssam * format packets. 6987024Ssam */ 6997640Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 70011192Ssam vvtracehdr("vi", vv); 70120997Skarels resid = addr->vviwc & 01777; /* only low 10 bits valid */ 7027640Ssam if (resid) 70320997Skarels resid |= 0176000; /* high 6 bits are undefined */ 70420997Skarels len = ((VVBUFSIZE >> 1) + resid) << 1; 7057640Ssam len -= sizeof(struct vv_header); 70620997Skarels 70720997Skarels if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) { 70820997Skarels vvprintf("vv%d: len too long or short, \ 70920997Skarels len = %d, vvicsr = %b\n", 71015794Sleres unit, len, 0xffff&(addr->vvicsr), VV_IBITS); 7117640Ssam goto dropit; 71215794Sleres } 71320997Skarels 71420997Skarels /* check the protocol header version */ 71520997Skarels if (vv->vh_version != RING_VERSION) { 71620997Skarels vvprintf("vv%d: bad protocol header version %d\n", 71720997Skarels unit, vv->vh_version & 0xff); 71820997Skarels goto dropit; 71920997Skarels } 72020997Skarels 7217640Ssam #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 72226950Sjas if (vv->vh_type == RING_TRAILER ) { 72328954Skarels off = ntohs((u_short)vv->vh_info); 72415794Sleres if (off > VVMTU) { 72520997Skarels vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n", 72615794Sleres unit, off, 0xffff&(addr->vvicsr), VV_IBITS); 7277640Ssam goto dropit; 72815794Sleres } 72926903Sjas vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *)); 73026950Sjas resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *))); 73115794Sleres if (off + resid > len) { 73220997Skarels vvprintf("vv%d: trailer packet too short\n", unit); 73320997Skarels vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n", 73415794Sleres unit, off, resid, 73515794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 7367640Ssam goto dropit; 73715794Sleres } 7387640Ssam len = off + resid; 73911209Ssam } else 7407640Ssam off = 0; 74120997Skarels 74215794Sleres if (len == 0) { 74320997Skarels vvprintf("vv%d: len is zero, vvicsr = %b\n", unit, 74415794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 7457640Ssam goto dropit; 74615794Sleres } 74720997Skarels 74824793Skarels m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if); 74915794Sleres if (m == NULL) { 75020997Skarels vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit, 75115794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 7527640Ssam goto dropit; 75315794Sleres } 7547640Ssam if (off) { 75524793Skarels struct ifnet *ifp; 75624793Skarels 75724793Skarels ifp = *(mtod(m, struct ifnet **)); 75824793Skarels m->m_off += 2 * sizeof (u_short); 75924793Skarels m->m_len -= 2 * sizeof (u_short); 76024793Skarels *(mtod(m, struct ifnet **)) = ifp; 7617640Ssam } 76211192Ssam 76315794Sleres /* Keep track of source address of this packet */ 76415794Sleres vs->vs_lastr = vv->vh_shost; 76520997Skarels 76611192Ssam /* 76715764Sleres * Demultiplex on packet type 76811192Ssam */ 7697024Ssam switch (vv->vh_type) { 77011192Ssam 7717024Ssam #ifdef INET 7727024Ssam case RING_IP: 7737024Ssam schednetisr(NETISR_IP); 7747024Ssam inq = &ipintrq; 7757024Ssam break; 7767024Ssam #endif 7777024Ssam default: 77820997Skarels vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 7797640Ssam m_freem(m); 7807024Ssam goto setup; 7817024Ssam } 78215794Sleres s = splimp(); 7837640Ssam if (IF_QFULL(inq)) { 7847640Ssam IF_DROP(inq); 7857640Ssam m_freem(m); 78611209Ssam } else 7877640Ssam IF_ENQUEUE(inq, m); 78815764Sleres 78915794Sleres splx(s); 7907024Ssam /* 79115764Sleres * Reset for the next packet. 7927024Ssam */ 79315764Sleres setup: 79415764Sleres ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 79515764Sleres addr->vviba = (u_short) ubainfo; 79615764Sleres addr->vviea = (u_short) (ubainfo >> 16); 79720997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 79820997Skarels addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB; 79915764Sleres return; 80011192Ssam 80111192Ssam /* 80211209Ssam * Drop packet on floor -- count them!! 80311192Ssam */ 8047640Ssam dropit: 8057640Ssam vs->vs_if.if_ierrors++; 8067640Ssam goto setup; 8077024Ssam } 8087024Ssam 8097024Ssam /* 81020997Skarels * proNET output routine. 8117024Ssam * Encapsulate a packet of type family for the local net. 8127024Ssam * Use trailer local net encapsulation if enough data in first 8137024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 8147024Ssam */ 8157024Ssam vvoutput(ifp, m0, dst) 8167024Ssam struct ifnet *ifp; 8177024Ssam struct mbuf *m0; 8187024Ssam struct sockaddr *dst; 8197024Ssam { 82016581Skarels register struct mbuf *m; 8217024Ssam register struct vv_header *vv; 8227640Ssam register int off; 82316581Skarels register int unit; 82416581Skarels register struct vvreg *addr; 82516581Skarels register struct vv_softc *vs; 82616581Skarels register int s; 82716581Skarels int type, dest, error; 8287024Ssam 82916581Skarels m = m0; 83016581Skarels unit = ifp->if_unit; 83116581Skarels addr = (struct vvreg *)vvinfo[unit]->ui_addr; 83216581Skarels vs = &vv_softc[unit]; 83320997Skarels 83416581Skarels /* 83520997Skarels * Check to see if the input side has wedged due the UBA 83620997Skarels * vectoring through 0. 83716581Skarels * 83816581Skarels * We are lower than device ipl when we enter this routine, 83916581Skarels * so if the interface is ready with an input packet then 84016581Skarels * an input interrupt must have slipped through the cracks. 84116581Skarels * 84216581Skarels * Avoid the race with an input interrupt by watching to see 84316581Skarels * if any packets come in. 84416581Skarels */ 84516581Skarels s = vs->vs_if.if_ipackets; 84616581Skarels if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) { 84720997Skarels vvprintf("vv%d: lost a receive interrupt, icsr = %b\n", 84816581Skarels unit, 0xffff&(addr->vvicsr), VV_IBITS); 84916581Skarels s = splimp(); 85016581Skarels vvrint(unit); 85116581Skarels splx(s); 85216581Skarels } 85316581Skarels 8547024Ssam switch (dst->sa_family) { 85511192Ssam 8567024Ssam #ifdef INET 85715764Sleres case AF_INET: 85821779Skarels if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) 85921779Skarels dest = VV_BROADCAST; 86021779Skarels else 86121779Skarels dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr); 86220997Skarels #ifdef LOOPBACK 86321779Skarels if (dest == vs->vs_host && (loif.if_flags & IFF_UP)) 86421779Skarels return (looutput(&loif, m0, dst)); 86520997Skarels #endif LOOPBACK 86621779Skarels if (dest >= 0x100) { 8677640Ssam error = EPERM; 8687640Ssam goto bad; 8697640Ssam } 8707640Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 87120997Skarels /* 87220997Skarels * Trailerize, if the configuration allows it. 87320997Skarels * TODO: Need per host negotiation. 87420997Skarels */ 87513090Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 87613090Ssam if (off > 0 && (off & 0x1ff) == 0 && 8777640Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 87826950Sjas type = RING_TRAILER; 8797640Ssam m->m_off -= 2 * sizeof (u_short); 8807640Ssam m->m_len += 2 * sizeof (u_short); 88128954Skarels *mtod(m, u_short *) = htons((short)RING_IP); 88228954Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 8837640Ssam goto gottrailertype; 8847640Ssam } 8857024Ssam type = RING_IP; 8867024Ssam off = 0; 8877024Ssam goto gottype; 8887024Ssam #endif 8897024Ssam default: 89016581Skarels printf("vv%d: can't handle af%d\n", unit, dst->sa_family); 8917640Ssam error = EAFNOSUPPORT; 8927640Ssam goto bad; 8937024Ssam } 8947024Ssam 8957024Ssam gottrailertype: 8967024Ssam /* 8977024Ssam * Packet to be sent as trailer: move first packet 8987024Ssam * (control information) to end of chain. 8997024Ssam */ 9007024Ssam while (m->m_next) 9017024Ssam m = m->m_next; 9027024Ssam m->m_next = m0; 9037024Ssam m = m0->m_next; 9047024Ssam m0->m_next = 0; 9057024Ssam m0 = m; 9067024Ssam gottype: 9077024Ssam /* 9087024Ssam * Add local net header. If no space in first mbuf, 9097024Ssam * allocate another. 9107024Ssam */ 9117024Ssam if (m->m_off > MMAXOFF || 9127024Ssam MMINOFF + sizeof (struct vv_header) > m->m_off) { 91311209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 91411209Ssam if (m == NULL) { 9157640Ssam error = ENOBUFS; 9167640Ssam goto bad; 9177024Ssam } 9187024Ssam m->m_next = m0; 9197024Ssam m->m_off = MMINOFF; 9207024Ssam m->m_len = sizeof (struct vv_header); 9217024Ssam } else { 9227024Ssam m->m_off -= sizeof (struct vv_header); 9237024Ssam m->m_len += sizeof (struct vv_header); 9247024Ssam } 9257024Ssam vv = mtod(m, struct vv_header *); 92621779Skarels vv->vh_shost = vs->vs_host; 92721779Skarels vv->vh_dhost = dest; 9287024Ssam vv->vh_version = RING_VERSION; 9297024Ssam vv->vh_type = type; 93028954Skarels vv->vh_info = htons((u_short)off); 93111192Ssam vvtracehdr("vo", vv); 9327024Ssam 9337024Ssam /* 9347024Ssam * Queue message on interface, and start output if interface 9357024Ssam * not yet active. 9367024Ssam */ 9377024Ssam s = splimp(); 9387640Ssam if (IF_QFULL(&ifp->if_snd)) { 9397640Ssam IF_DROP(&ifp->if_snd); 9407640Ssam error = ENOBUFS; 9417640Ssam goto qfull; 9427640Ssam } 9437024Ssam IF_ENQUEUE(&ifp->if_snd, m); 94416581Skarels if (vs->vs_oactive == 0) 94516581Skarels vvstart(unit); 9467024Ssam splx(s); 9477640Ssam return (0); 9487640Ssam qfull: 9497640Ssam m0 = m; 9507640Ssam splx(s); 9517640Ssam bad: 9527640Ssam m_freem(m0); 9537640Ssam return(error); 9547024Ssam } 9557024Ssam 9567024Ssam /* 95713057Ssam * Process an ioctl request. 95813057Ssam */ 95913057Ssam vvioctl(ifp, cmd, data) 96013057Ssam register struct ifnet *ifp; 96113057Ssam int cmd; 96213057Ssam caddr_t data; 96313057Ssam { 96421779Skarels struct ifaddr *ifa = (struct ifaddr *) data; 96521779Skarels int s = splimp(), error = 0; 96613057Ssam 96713057Ssam switch (cmd) { 96813057Ssam 96913057Ssam case SIOCSIFADDR: 97024793Skarels ifp->if_flags |= IFF_UP; 97121779Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 97213057Ssam vvinit(ifp->if_unit); 97326903Sjas /* 97426903Sjas * Did self-test succeed? 97526903Sjas */ 97626903Sjas if ((ifp->if_flags & IFF_UP) == 0) 97726903Sjas error = ENETDOWN; 97821779Skarels /* 97921779Skarels * Attempt to check agreement of protocol address 98021779Skarels * and board address. 98121779Skarels */ 98221779Skarels switch (ifa->ifa_addr.sa_family) { 98321779Skarels case AF_INET: 98421779Skarels if (in_lnaof(IA_SIN(ifa)->sin_addr) != 98521779Skarels vv_softc[ifp->if_unit].vs_host) 98625194Skarels error = EADDRNOTAVAIL; 98721779Skarels break; 98821779Skarels } 98913057Ssam break; 99013057Ssam 99113057Ssam default: 99213057Ssam error = EINVAL; 99313057Ssam } 99413057Ssam splx(s); 99521779Skarels return (error); 99613057Ssam } 99725190Skarels 99825190Skarels /* 99925190Skarels * vvprt_hdr(s, v) print the local net header in "v" 100025190Skarels * with title is "s" 100125190Skarels */ 100225190Skarels vvprt_hdr(s, v) 100325190Skarels char *s; 100425190Skarels register struct vv_header *v; 100525190Skarels { 100625190Skarels printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 100725190Skarels s, 100825190Skarels 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 100925190Skarels 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 101025190Skarels 0xffff & (int)(v->vh_info)); 101125190Skarels } 101226903Sjas #endif NVV 1013