123305Smckusick /* 236085Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 335328Sbostic * All rights reserved. 423305Smckusick * 535328Sbostic * Redistribution and use in source and binary forms are permitted 635328Sbostic * provided that the above copyright notice and this paragraph are 735328Sbostic * duplicated in all such forms and that any documentation, 835328Sbostic * advertising materials, and other materials related to such 935328Sbostic * distribution and use acknowledge that the software was developed 1035328Sbostic * by the University of California, Berkeley. The name of the 1135328Sbostic * University may not be used to endorse or promote products derived 1235328Sbostic * from this software without specific prior written permission. 1335328Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435328Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535328Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1635328Sbostic * 17*38986Skarels * @(#)if_vv.c 7.5 (Berkeley) 09/04/89 1823305Smckusick */ 197024Ssam 209799Ssam #include "vv.h" 2125275Sbloom #if NVV > 0 2211192Ssam 237024Ssam /* 2435805Skarels * 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 2735805Skarels * to "v2", but this won't work right in config. Thus the name is "vv". 2811192Ssam * 2935805Skarels * This driver is compatible with the Unibus ProNET 10 megabit 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 * 3435805Skarels * This driver is also compatible with the Q-bus ProNET 10 megabit and 3535805Skarels * 80 megabit token ring interfaces (models p1100 and p1180), but 3635805Skarels * only on a MicroVAX-II or MicroVAX-III. No attempt is made to 3735805Skarels * support the MicroVAX-I. 3835805Skarels * 3926950Sjas * TRAILERS: This driver has a new implementation of trailers that 4026950Sjas * is at least a tolerable neighbor on the ring. The offset is not 4126950Sjas * stored in the protocol type, but instead only in the vh_info 4226950Sjas * field. Also, the vh_info field, and the two shorts before the 4326950Sjas * trailing header, are in network byte order, not VAX byte order. 4420997Skarels * 4526950Sjas * Of course, nothing but BSD UNIX supports trailers on ProNET. 4635805Skarels * If you need interoperability with anything else (like the p4200), 4735805Skarels * turn off trailers using the -trailers option to /etc/ifconfig! 4826950Sjas * 4926903Sjas * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001) 5020997Skarels * have a serial number >= 040, which is about March, 1982. Older 5126903Sjas * HSBUs do not carry across 64kbyte boundaries. They can be supported 5226903Sjas * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization 5326903Sjas * in vvattach(). 5426903Sjas * 5526903Sjas * The old warning about use without Wire Centers applies only to CTL 5626903Sjas * (p1002) cards with serial <= 057, which have not received ECO 176-743, 5726903Sjas * which was implemented in March, 1982. Most such CTLs have received 5826903Sjas * this ECO. 597024Ssam */ 6017117Sbloom #include "param.h" 6117117Sbloom #include "systm.h" 6217117Sbloom #include "mbuf.h" 6317117Sbloom #include "buf.h" 64*38986Skarels #include "time.h" 65*38986Skarels #include "kernel.h" 6617117Sbloom #include "protosw.h" 6717117Sbloom #include "socket.h" 68*38986Skarels #include "syslog.h" 6917117Sbloom #include "vmmac.h" 7017117Sbloom #include "errno.h" 7117117Sbloom #include "ioctl.h" 728465Sroot 738465Sroot #include "../net/if.h" 7411209Ssam #include "../net/netisr.h" 758465Sroot #include "../net/route.h" 7624793Skarels 7724793Skarels #ifdef INET 788421Swnj #include "../netinet/in.h" 798421Swnj #include "../netinet/in_systm.h" 8021779Skarels #include "../netinet/in_var.h" 818421Swnj #include "../netinet/ip.h" 8224793Skarels #endif 838465Sroot 84*38986Skarels #include "../vax/pte.h" 8515794Sleres #include "../vax/cpu.h" 8611209Ssam #include "../vax/mtpr.h" 8717117Sbloom #include "if_vv.h" 8817117Sbloom #include "if_uba.h" 898465Sroot #include "../vaxuba/ubareg.h" 908465Sroot #include "../vaxuba/ubavar.h" 917024Ssam 927024Ssam /* 9320997Skarels * maximum transmission unit definition -- 9435805Skarels * you can set VVMTU at anything from 576 to 2036. 9520997Skarels * 1536 is a popular "large" value, because it is a multiple 9620997Skarels * of 512, which the trailer scheme likes. 9735805Skarels * The absolute maximum size is 2036, which is enforced. 9820997Skarels */ 9920997Skarels 10035805Skarels #define VVMTU (2036) 10120997Skarels 10235805Skarels #define VVMRU (VVMTU + (2 * sizeof(u_short))) 10320997Skarels #define VVBUFSIZE (VVMRU + sizeof(struct vv_header)) 10435805Skarels #if VVMTU>2036 10520997Skarels #undef VVMTU 10620997Skarels #undef VVMRU 10720997Skarels #undef VVBUFSIZE 10820997Skarels #define VVBUFSIZE (2046) 10920997Skarels #define VVMRU (VVBUFSIZE - sizeof (struct vv_header)) 11035805Skarels #define VVMTU (VVMRU - (2 * sizeof(u_short))) 1117024Ssam #endif 1127024Ssam 11320997Skarels /* 11420997Skarels * debugging and tracing stuff 11520997Skarels */ 11616581Skarels int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */ 1177640Ssam 11820997Skarels #define vvtracehdr if (vv_tracehdr) vvprt_hdr 119*38986Skarels #define vvlog if (vs->vs_if.if_flags & IFF_DEBUG) log 12011192Ssam 12120997Skarels /* 12220997Skarels * externals, types, etc. 12320997Skarels */ 12416581Skarels int vvprobe(), vvattach(), vvreset(), vvinit(); 12516581Skarels int vvidentify(), vvstart(), vvxint(), vvwatchdog(); 12626394Skarels int vvrint(), vvoutput(), vvioctl(); 1277024Ssam struct uba_device *vvinfo[NVV]; 1287024Ssam u_short vvstd[] = { 0 }; 1297024Ssam struct uba_driver vvdriver = 1307024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 1317024Ssam #define VVUNIT(x) minor(x) 1327024Ssam 13320997Skarels #define LOOPBACK /* use loopback for packets meant for us */ 13420997Skarels #ifdef LOOPBACK 13520997Skarels extern struct ifnet loif; 13620997Skarels #endif 13720997Skarels 138*38986Skarels extern wakeup(); 139*38986Skarels 1407024Ssam /* 1417024Ssam * Software status of each interface. 1427024Ssam * 1437024Ssam * Each interface is referenced by a network interface structure, 1447024Ssam * vs_if, which the routing code uses to locate the interface. 1457024Ssam * This structure contains the output queue for the interface, its address, ... 1467024Ssam * We also have, for each interface, a UBA interface structure, which 1477024Ssam * contains information about the UNIBUS resources held by the interface: 1487024Ssam * map registers, buffered data paths, etc. Information is cached in this 1497024Ssam * structure for use by the if_uba.c routines in running the interface 1507024Ssam * efficiently. 1517024Ssam */ 1527024Ssam struct vv_softc { 1537024Ssam struct ifnet vs_if; /* network-visible interface */ 1547024Ssam struct ifuba vs_ifuba; /* UNIBUS resources */ 15526298Skarels u_short vs_host; /* this interface address */ 15611192Ssam short vs_oactive; /* is output active */ 15726903Sjas short vs_is80; /* is 80 megabit version */ 1587024Ssam short vs_olen; /* length of last output */ 15915794Sleres u_short vs_lastx; /* address of last packet sent */ 16015794Sleres u_short vs_lastr; /* address of last packet received */ 16111192Ssam short vs_tries; /* transmit current retry count */ 1627024Ssam short vs_init; /* number of ring inits */ 16320997Skarels short vs_refused; /* number of packets refused */ 16415794Sleres short vs_timeouts; /* number of transmit timeouts */ 16520997Skarels short vs_otimeout; /* number of output timeouts */ 16620997Skarels short vs_ibadf; /* number of input bad formats */ 16720997Skarels short vs_parity; /* number of parity errors on 10 meg, */ 16820997Skarels /* link data errors on 80 meg */ 16936085Skarels short vs_ipl; /* interrupt priority on Q-bus */ 170*38986Skarels short vs_flags; /* board state: */ 171*38986Skarels #define VS_RUNNING 0x01 /* board has been initialized */ 172*38986Skarels #define VS_INIT 0x02 /* board being initialized */ 1737024Ssam } vv_softc[NVV]; 1747024Ssam 175*38986Skarels #define NOHOST 0xff /* illegal host number */ 17626311Skarels 17720997Skarels /* 17820997Skarels * probe the interface to see that the registers exist, and then 17920997Skarels * cause an interrupt to find its vector 18020997Skarels */ 18136085Skarels vvprobe(reg, ui) 1827024Ssam caddr_t reg; 18336085Skarels struct uba_device *ui; 1847024Ssam { 1857024Ssam register int br, cvec; 18616581Skarels register struct vvreg *addr; 1877024Ssam 1887024Ssam #ifdef lint 18915764Sleres br = 0; cvec = br; br = cvec; 1907024Ssam #endif 19116581Skarels addr = (struct vvreg *)reg; 19220997Skarels 1937024Ssam /* reset interface, enable, and wait till dust settles */ 19436085Skarels #ifdef QBA 19536085Skarels (void) spl6(); 19636085Skarels #endif 1977024Ssam addr->vvicsr = VV_RST; 1987024Ssam addr->vvocsr = VV_RST; 19915764Sleres DELAY(100000); 20020997Skarels 2017024Ssam /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 2027024Ssam addr->vvoba = 0; /* low 16 bits */ 2037024Ssam addr->vvoea = 0; /* extended bits */ 2047024Ssam addr->vvowc = -1; /* for 1 word */ 20520997Skarels addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */ 2067024Ssam DELAY(100000); 20736085Skarels #ifdef QBA 20836085Skarels vv_softc[ui->ui_unit].vs_ipl = br = qbgetpri(); 20936085Skarels #endif 21020997Skarels addr->vvocsr = VV_RST; /* clear out the CSR */ 2117024Ssam if (cvec && cvec != 0x200) 21215764Sleres cvec -= 4; /* backup so vector => receive */ 21336085Skarels return (sizeof(struct vvreg)); 2147024Ssam } 2157024Ssam 2167024Ssam /* 2177024Ssam * Interface exists: make available by filling in network interface 2187024Ssam * record. System will initialize the interface when it is ready 2197024Ssam * to accept packets. 2207024Ssam */ 2217024Ssam vvattach(ui) 2227024Ssam struct uba_device *ui; 2237024Ssam { 22415764Sleres register struct vv_softc *vs; 2257024Ssam 22615764Sleres vs = &vv_softc[ui->ui_unit]; 2277024Ssam vs->vs_if.if_unit = ui->ui_unit; 2287024Ssam vs->vs_if.if_name = "vv"; 2297024Ssam vs->vs_if.if_mtu = VVMTU; 23021779Skarels vs->vs_if.if_flags = IFF_BROADCAST; 2317024Ssam vs->vs_if.if_init = vvinit; 23213057Ssam vs->vs_if.if_ioctl = vvioctl; 2337024Ssam vs->vs_if.if_output = vvoutput; 23411209Ssam vs->vs_if.if_reset = vvreset; 23515794Sleres vs->vs_if.if_timer = 0; 23615794Sleres vs->vs_if.if_watchdog = vvwatchdog; 23726201Skarels vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP; 23826903Sjas 23926903Sjas /* use flag to determine if this is proNET-80 */ 24026903Sjas vs->vs_is80 = (short)(ui->ui_flags & 01); 241*38986Skarels vs->vs_host = NOHOST; 24226903Sjas 24312354Smo #if defined(VAX750) 24412354Smo /* don't chew up 750 bdp's */ 24512354Smo if (cpu == VAX_750 && ui->ui_unit > 0) 24612354Smo vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 24712354Smo #endif 2487024Ssam if_attach(&vs->vs_if); 2497024Ssam } 2507024Ssam 2517024Ssam /* 2527024Ssam * Reset of interface after UNIBUS reset. 2537024Ssam * If interface is on specified uba, reset its state. 2547024Ssam */ 2557024Ssam vvreset(unit, uban) 2567024Ssam int unit, uban; 2577024Ssam { 2587024Ssam register struct uba_device *ui; 2597024Ssam 2607024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 2617024Ssam ui->ui_ubanum != uban) 2627024Ssam return; 2637024Ssam printf(" vv%d", unit); 264*38986Skarels vv_softc[unit].vs_if.if_flags &= ~IFF_RUNNING; 265*38986Skarels vv_softc[unit].vs_flags &= ~VS_RUNNING; 266*38986Skarels vvinit(unit, 0); 2677024Ssam } 2687024Ssam 2697024Ssam /* 2707024Ssam * Initialization of interface; clear recorded pending 2717024Ssam * operations, and reinitialize UNIBUS usage. 2727024Ssam */ 273*38986Skarels vvinit(unit, cansleep) 274*38986Skarels int unit, cansleep; 2757024Ssam { 27615764Sleres register struct vv_softc *vs; 27715764Sleres register struct uba_device *ui; 2787024Ssam register struct vvreg *addr; 27935805Skarels register int ubaaddr, s; 2807024Ssam 28115764Sleres vs = &vv_softc[unit]; 28215764Sleres ui = vvinfo[unit]; 28320997Skarels 28421779Skarels if (vs->vs_if.if_addrlist == (struct ifaddr *)0) 28513057Ssam return; 28620997Skarels 287*38986Skarels /* 288*38986Skarels * Prevent multiple instances of vvinit 289*38986Skarels * from trying simultaneously. 290*38986Skarels */ 291*38986Skarels while (vs->vs_flags & VS_INIT) { 292*38986Skarels if (cansleep) 293*38986Skarels sleep((caddr_t)vs); 294*38986Skarels else 295*38986Skarels return; 296*38986Skarels } 297*38986Skarels if (vs->vs_flags & VS_RUNNING) 298*38986Skarels return; 299*38986Skarels vs->vs_flags = VS_INIT; 300*38986Skarels 3017640Ssam addr = (struct vvreg *)ui->ui_addr; 30236085Skarels if ((vs->vs_if.if_flags & IFF_RUNNING) == 0 && 30336085Skarels if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 30436085Skarels sizeof (struct vv_header), (int)btoc(VVMRU)) == 0) { 30515794Sleres printf("vv%d: can't initialize, if_ubainit() failed\n", unit); 3067640Ssam vs->vs_if.if_flags &= ~IFF_UP; 307*38986Skarels vs->vs_flags = 0; 3087024Ssam return; 3097024Ssam } 31036085Skarels vs->vs_if.if_flags |= IFF_RUNNING; 31120997Skarels 3127024Ssam /* 31315764Sleres * Now that the uba is set up, figure out our address and 31415764Sleres * update complete our host address. 3157640Ssam */ 316*38986Skarels if (cansleep) 317*38986Skarels vs->vs_host = vvidentify(unit); 318*38986Skarels if (vs->vs_host == NOHOST) { 31915794Sleres vs->vs_if.if_flags &= ~IFF_UP; 320*38986Skarels vs->vs_flags = 0; 32115794Sleres return; 32215794Sleres } 323*38986Skarels vvlog(LOG_DEBUG, "vv%d: host %u\n", unit, vs->vs_host); 32420997Skarels 3257640Ssam /* 32620997Skarels * Reset the interface, and stay in the ring 3277640Ssam */ 32820997Skarels addr->vvocsr = VV_RST; /* take over output */ 32920997Skarels addr->vvocsr = VV_CPB; /* clear packet buffer */ 33020997Skarels addr->vvicsr = VV_RST | VV_HEN; /* take over input, */ 33120997Skarels /* keep relay closed */ 332*38986Skarels if (cansleep) { 333*38986Skarels timeout(wakeup, (caddr_t)vs, hz/2); 334*38986Skarels sleep((caddr_t)vs, PZERO); /* let contacts settle */ 335*38986Skarels } else 336*38986Skarels DELAY(500000); /* let contacts settle */ 33720997Skarels 33820997Skarels vs->vs_init = 0; /* clear counters, etc. */ 33920997Skarels vs->vs_refused = 0; 34015794Sleres vs->vs_timeouts = 0; 34120997Skarels vs->vs_otimeout = 0; 34220997Skarels vs->vs_ibadf = 0; 34320997Skarels vs->vs_parity = 0; 34415794Sleres vs->vs_lastx = 256; /* an invalid address */ 34515794Sleres vs->vs_lastr = 256; /* an invalid address */ 34620997Skarels 3477640Ssam /* 3487640Ssam * Hang a receive and start any 3497640Ssam * pending writes by faking a transmit complete. 3507640Ssam */ 3517640Ssam s = splimp(); 35235805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 35335805Skarels addr->vviba = (u_short)ubaaddr; 35435805Skarels addr->vviea = (u_short)(ubaaddr >> 16); 35520997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 35620997Skarels addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB; 3577640Ssam vs->vs_oactive = 1; 35836085Skarels vs->vs_if.if_flags |= IFF_UP; 359*38986Skarels vs->vs_flags = VS_RUNNING; /* clear VS_INIT */ 360*38986Skarels wakeup((caddr_t)vs); 3617640Ssam vvxint(unit); 3627640Ssam splx(s); 3637640Ssam } 3647640Ssam 3657640Ssam /* 36620997Skarels * Do a moderately thorough self-test in all three modes. Mostly 36720997Skarels * to keeps defective nodes off the ring, rather than to be especially 36820997Skarels * thorough. The key issue is to detect any cable breaks before joining 36920997Skarels * the ring. Return our node address on success, return -1 on failure. 37020997Skarels * 3717640Ssam */ 37220997Skarels 37320997Skarels /* the three self-test modes */ 37420997Skarels static u_short vv_modes[] = { 37520997Skarels VV_STE|VV_LPB, /* digital loopback */ 37620997Skarels VV_STE, /* analog loopback */ 37720997Skarels VV_HEN /* network mode */ 37820997Skarels }; 37920997Skarels 38011209Ssam vvidentify(unit) 38113057Ssam int unit; 38211209Ssam { 38315764Sleres register struct vv_softc *vs; 38415764Sleres register struct uba_device *ui; 3857640Ssam register struct vvreg *addr; 38616581Skarels register struct mbuf *m; 38716581Skarels register struct vv_header *v; 38835805Skarels register int ubaaddr; 38920997Skarels register int i, successes, failures, waitcount; 39026311Skarels u_short shost = NOHOST; 3917640Ssam 39220997Skarels vs = &vv_softc[unit]; 39320997Skarels ui = vvinfo[unit]; 39420997Skarels addr = (struct vvreg *)ui->ui_addr; 39520997Skarels 3967640Ssam /* 3977024Ssam * Build a multicast message to identify our address 39820997Skarels * We need do this only once, since nobody else is about to use 39920997Skarels * the intermediate transmit buffer (ifu_w.ifrw_addr) that 40020997Skarels * if_ubainit() aquired for us. 4017024Ssam */ 40211209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 40315794Sleres if (m == NULL) { 40415794Sleres printf("vv%d: can't initialize, m_get() failed\n", unit); 405*38986Skarels return (NOHOST); 40615794Sleres } 40711192Ssam m->m_next = 0; 4087024Ssam m->m_off = MMINOFF; 4097024Ssam m->m_len = sizeof(struct vv_header); 4107024Ssam v = mtod(m, struct vv_header *); 41111192Ssam v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 4127024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 4137024Ssam v->vh_version = RING_VERSION; 41420997Skarels v->vh_type = RING_DIAGNOSTICS; 4157024Ssam v->vh_info = 0; 41620997Skarels /* map xmit message into uba, copying to intermediate buffer */ 41720997Skarels vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 41820997Skarels 4197024Ssam /* 42020997Skarels * For each of the modes (digital, analog, network), go through 42120997Skarels * a self-test that requires me to send VVIDENTSUCC good packets 42220997Skarels * in VVIDENTRETRY attempts. Use broadcast destination to find out 42320997Skarels * who I am, then use this as my address to check my address match 42420997Skarels * logic. Only data checked is the vh_type field. 4257024Ssam */ 4267640Ssam 42720997Skarels for (i = 0; i < 3; i++) { 42820997Skarels successes = 0; /* clear successes for this mode */ 42920997Skarels failures = 0; /* and clear failures, too */ 4307640Ssam 43120997Skarels /* take over device, and leave ring */ 43220997Skarels addr->vvicsr = VV_RST; 43320997Skarels addr->vvocsr = VV_RST; 43420997Skarels addr->vvicsr = vv_modes[i]; /* test mode */ 43520997Skarels 43620997Skarels /* 43720997Skarels * let the flag and token timers pop so that the init ring bit 43820997Skarels * will be allowed to work, by waiting about 1 second 43920997Skarels */ 440*38986Skarels timeout(wakeup, (caddr_t)vs, hz); 441*38986Skarels sleep((caddr_t)vs, PZERO); 44220997Skarels 44320997Skarels /* 44420997Skarels * retry loop 44520997Skarels */ 44620997Skarels while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY)) 44720997Skarels { 44820997Skarels /* start a receive */ 44935805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 45020997Skarels addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */ 45135805Skarels addr->vviba = (u_short) ubaaddr; 45235805Skarels addr->vviea = (u_short) (ubaaddr >> 16); 45320997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 45420997Skarels addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB; 45520997Skarels 456*38986Skarels #ifdef notdef 45720997Skarels /* purge stale data from BDP */ 45820997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 45920997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 46020997Skarels vs->vs_ifuba.ifu_w.ifrw_bdp); 461*38986Skarels #endif 46220997Skarels 46320997Skarels /* do a transmit */ 46435805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info); 46520997Skarels addr->vvocsr = VV_RST; /* abort last try */ 46635805Skarels addr->vvoba = (u_short) ubaaddr; 46735805Skarels addr->vvoea = (u_short) (ubaaddr >> 16); 46820997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); 46920997Skarels addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 47020997Skarels 47120997Skarels /* poll receive side for completion */ 47220997Skarels DELAY(10000); /* give it a chance */ 47320997Skarels for (waitcount = 0; waitcount < 10; waitcount++) { 47420997Skarels if (addr->vvicsr & VV_RDY) 47520997Skarels goto gotit; 47620997Skarels DELAY(1000); 47720997Skarels } 47820997Skarels failures++; /* no luck */ 47911209Ssam continue; 48020997Skarels 48120997Skarels gotit: /* we got something--is it any good? */ 48220997Skarels if ((addr->vvicsr & (VVRERR|VV_LDE)) || 48321779Skarels (addr->vvocsr & (VVXERR|VV_RFS))) { 48420997Skarels failures++; 48520997Skarels continue; 48620997Skarels } 48720997Skarels 48820997Skarels /* Purge BDP before looking at received packet */ 48920997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 49020997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 49120997Skarels vs->vs_ifuba.ifu_r.ifrw_bdp); 492*38986Skarels #ifdef notdef 49324793Skarels m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 49426394Skarels 0, &vs->vs_if); 49520997Skarels if (m != NULL) 49620997Skarels m_freem(m); 497*38986Skarels #endif 49820997Skarels 49920997Skarels v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 50020997Skarels 50120997Skarels /* check message type, catch our node address */ 50220997Skarels if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) { 50326311Skarels if (shost == NOHOST) { 50420997Skarels shost = v->vh_shost & 0xff; 50520997Skarels /* send to ourself now */ 50620997Skarels ((struct vv_header *) 50720997Skarels (vs->vs_ifuba.ifu_r.ifrw_addr)) 50820997Skarels ->vh_dhost = shost; 50920997Skarels } 51020997Skarels successes++; 51126903Sjas } else { 51226903Sjas failures++; 51320997Skarels } 51426903Sjas v->vh_type = 0; /* clear to check again */ 51511192Ssam } 51620997Skarels 51720997Skarels if (failures >= VVIDENTRETRY) 51820997Skarels { 51920997Skarels printf("vv%d: failed self-test after %d tries \ 52020997Skarels in %s mode\n", 52120997Skarels unit, VVIDENTRETRY, i == 0 ? "digital loopback" : 52220997Skarels (i == 1 ? "analog loopback" : "network")); 52320997Skarels printf("vv%d: icsr = %b, ocsr = %b\n", 52420997Skarels unit, 0xffff & addr->vvicsr, VV_IBITS, 52520997Skarels 0xffff & addr->vvocsr, VV_OBITS); 52620997Skarels addr->vvicsr = VV_RST; /* kill the sick board */ 52720997Skarels addr->vvocsr = VV_RST; 52826311Skarels shost = NOHOST; 52920997Skarels goto done; 53020997Skarels } 53111192Ssam } 53220997Skarels 53320997Skarels done: 53420997Skarels /* deallocate mbuf used for send packet (won't be one, anyways) */ 53515794Sleres if (vs->vs_ifuba.ifu_xtofree) { 5367024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 53715794Sleres vs->vs_ifuba.ifu_xtofree = 0; 53815794Sleres } 53920997Skarels 54020997Skarels return(shost); 5417024Ssam } 5427024Ssam 5437024Ssam /* 5447024Ssam * Start or restart output on interface. 54511192Ssam * If interface is active, this is a retransmit, so just 54611192Ssam * restuff registers and go. 5477024Ssam * If interface is not already active, get another datagram 5487024Ssam * to send off of the interface queue, and map it to the interface 5497024Ssam * before starting the output. 5507024Ssam */ 5517024Ssam vvstart(dev) 5527024Ssam dev_t dev; 5537024Ssam { 55416581Skarels register struct uba_device *ui; 55515764Sleres register struct vv_softc *vs; 5567024Ssam register struct vvreg *addr; 55716581Skarels register struct mbuf *m; 55835805Skarels register int unit, ubaaddr, dest, s; 5597024Ssam 56016581Skarels unit = VVUNIT(dev); 56115764Sleres ui = vvinfo[unit]; 56215764Sleres vs = &vv_softc[unit]; 5637024Ssam if (vs->vs_oactive) 5647024Ssam goto restart; 5657024Ssam /* 5667024Ssam * Not already active: dequeue another request 5677024Ssam * and map it to the UNIBUS. If no more requests, 5687024Ssam * just return. 5697024Ssam */ 57015794Sleres s = splimp(); 5717024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 57215794Sleres splx(s); 57311209Ssam if (m == NULL) { 5747024Ssam vs->vs_oactive = 0; 5757024Ssam return; 5767024Ssam } 5777024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 5787024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 5797024Ssam vs->vs_lastx = dest; 5807024Ssam restart: 5817024Ssam /* 5827024Ssam * Have request mapped to UNIBUS for transmission. 58315794Sleres * Purge any stale data from this BDP, and start the output. 58415794Sleres * 58515794Sleres * Make sure this packet will fit in the interface. 5867024Ssam */ 58720997Skarels if (vs->vs_olen > VVBUFSIZE) { 58820997Skarels printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen); 58911192Ssam panic("vvdriver vs_olen botch"); 59011192Ssam } 59120997Skarels 59220997Skarels vs->vs_if.if_timer = VVTIMEOUT; 59320997Skarels vs->vs_oactive = 1; 59420997Skarels 59520997Skarels /* ship it */ 59636085Skarels #ifdef notdef 5977024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 5987024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 59936085Skarels #endif 6007024Ssam addr = (struct vvreg *)ui->ui_addr; 60135805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info); 60235805Skarels addr->vvoba = (u_short) ubaaddr; 60335805Skarels addr->vvoea = (u_short) (ubaaddr >> 16); 6047024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 60520997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */ 60620997Skarels if (addr->vvocsr & VV_NOK) 60720997Skarels vs->vs_init++; /* count ring inits */ 6087024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 6097024Ssam } 6107024Ssam 6117024Ssam /* 61220997Skarels * proNET transmit interrupt 6137024Ssam * Start another output if more data to send. 6147024Ssam */ 6157024Ssam vvxint(unit) 6167024Ssam int unit; 6177024Ssam { 61815764Sleres register struct uba_device *ui; 61915764Sleres register struct vv_softc *vs; 6207024Ssam register struct vvreg *addr; 6217024Ssam register int oc; 6227024Ssam 623*38986Skarels ui = vvinfo[unit]; 624*38986Skarels vs = &vv_softc[unit]; 62536085Skarels #ifdef QBA 626*38986Skarels splx(vs->vs_ipl); 62736085Skarels #endif 62815794Sleres vs->vs_if.if_timer = 0; 6297024Ssam addr = (struct vvreg *)ui->ui_addr; 6307024Ssam oc = 0xffff & (addr->vvocsr); 6317024Ssam if (vs->vs_oactive == 0) { 632*38986Skarels vvlog(LOG_DEBUG, "vv%d: stray interrupt vvocsr = %b\n", unit, 63315764Sleres oc, VV_OBITS); 6347024Ssam return; 6357024Ssam } 63620997Skarels 63720997Skarels /* 63820997Skarels * we retransmit on soft error 63920997Skarels * TODO: sort retransmits to end of queue if possible! 64020997Skarels */ 64120997Skarels if (oc & (VV_OPT | VV_RFS)) { 64211192Ssam if (vs->vs_tries++ < VVRETRY) { 6437024Ssam if (oc & VV_OPT) 64420997Skarels vs->vs_otimeout++; 64520997Skarels if (oc & VV_RFS) { 64620997Skarels vs->vs_if.if_collisions++; 64720997Skarels vs->vs_refused++; 64820997Skarels } 64911192Ssam vvstart(unit); /* restart this message */ 6507024Ssam return; 6517024Ssam } 6527024Ssam } 6537024Ssam vs->vs_if.if_opackets++; 6547024Ssam vs->vs_oactive = 0; 6557024Ssam vs->vs_tries = 0; 65620997Skarels 6577024Ssam if (oc & VVXERR) { 6587024Ssam vs->vs_if.if_oerrors++; 659*38986Skarels vvlog(LOG_ERR, "vv%d: error vvocsr = %b\n", 660*38986Skarels unit, 0xffff & oc, VV_OBITS); 6617024Ssam } 6627024Ssam if (vs->vs_ifuba.ifu_xtofree) { 6637024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 6647024Ssam vs->vs_ifuba.ifu_xtofree = 0; 6657024Ssam } 6667024Ssam vvstart(unit); 6677024Ssam } 6687024Ssam 6697024Ssam /* 67015794Sleres * Transmit watchdog timer routine. 67115794Sleres * This routine gets called when we lose a transmit interrupt. 67215794Sleres * The best we can do is try to restart output. 67315794Sleres */ 67415794Sleres vvwatchdog(unit) 67515794Sleres int unit; 67615794Sleres { 67715794Sleres register struct vv_softc *vs; 67815794Sleres 67915794Sleres vs = &vv_softc[unit]; 680*38986Skarels log(LOG_ERR, "vv%d: lost transmit interrupt\n", unit); 68115794Sleres vs->vs_timeouts++; 68215794Sleres vvstart(unit); 68315794Sleres } 68415794Sleres 68515794Sleres /* 68620997Skarels * proNET interface receiver interrupt. 6877024Ssam * If input error just drop packet. 68815764Sleres * Otherwise purge input buffered data path and examine 6897024Ssam * packet to determine type. If can't determine length 69015764Sleres * from type, then have to drop packet. Otherwise decapsulate 6917024Ssam * packet based on type and pass to type specific higher-level 6927024Ssam * input routine. 6937024Ssam */ 6947024Ssam vvrint(unit) 6957024Ssam int unit; 6967024Ssam { 69715764Sleres register struct vv_softc *vs; 69816581Skarels register struct vvreg *addr; 6997024Ssam register struct vv_header *vv; 7007024Ssam register struct ifqueue *inq; 70116581Skarels register struct mbuf *m; 70235805Skarels int ubaaddr, len, off, s; 7037640Ssam short resid; 7047024Ssam 705*38986Skarels vs = &vv_softc[unit]; 70636085Skarels #ifdef QBA 707*38986Skarels splx(vs->vs_ipl); 70836085Skarels #endif 70916581Skarels vs->vs_if.if_ipackets++; 71015764Sleres addr = (struct vvreg *)vvinfo[unit]->ui_addr; 71120997Skarels 7127024Ssam /* 71326903Sjas * Purge BDP 7147024Ssam */ 7157024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 7167024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 71720997Skarels 71820997Skarels /* 71920997Skarels * receive errors? 72020997Skarels */ 7217024Ssam if (addr->vvicsr & VVRERR) { 722*38986Skarels vvlog(LOG_INFO, "vv%d: receive error, vvicsr = %b\n", unit, 72320997Skarels 0xffff&(addr->vvicsr), VV_IBITS); 72420997Skarels if (addr->vvicsr & VV_BDF) 72520997Skarels vs->vs_ibadf++; 7267640Ssam goto dropit; 7277024Ssam } 7287640Ssam 7297024Ssam /* 73020997Skarels * parity errors? 73120997Skarels */ 73220997Skarels if (addr->vvicsr & VV_LDE) { 73320997Skarels /* we don't have to clear it because the receive command */ 73420997Skarels /* writes 0 to parity bit */ 73520997Skarels vs->vs_parity++; 73626903Sjas 73720997Skarels /* 73820997Skarels * only on 10 megabit proNET is VV_LDE an end-to-end parity 73920997Skarels * bit. On 80 megabit, it returns to the intended use of 74020997Skarels * node-to-node parity. End-to-end parity errors on 80 megabit 74120997Skarels * give VV_BDF. 74220997Skarels */ 74326903Sjas if (vs->vs_is80 == 0) 74426903Sjas goto dropit; 74520997Skarels } 74620997Skarels 74720997Skarels /* 74820997Skarels * Get packet length from residual word count 7497640Ssam * 7507640Ssam * Compute header offset if trailer protocol 7517640Ssam * 7527640Ssam * Pull packet off interface. Off is nonzero if packet 7537640Ssam * has trailing header; if_rubaget will then force this header 7547640Ssam * information to be at the front. The vh_info field 7557640Ssam * carries the offset to the trailer data in trailer 7567640Ssam * format packets. 7577024Ssam */ 7587640Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 75911192Ssam vvtracehdr("vi", vv); 76020997Skarels resid = addr->vviwc & 01777; /* only low 10 bits valid */ 7617640Ssam if (resid) 76220997Skarels resid |= 0176000; /* high 6 bits are undefined */ 76320997Skarels len = ((VVBUFSIZE >> 1) + resid) << 1; 7647640Ssam len -= sizeof(struct vv_header); 76520997Skarels 76620997Skarels if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) { 767*38986Skarels vvlog(LOG_DEBUG, "vv%d: len too long or short, \ 76820997Skarels len = %d, vvicsr = %b\n", 76915794Sleres unit, len, 0xffff&(addr->vvicsr), VV_IBITS); 7707640Ssam goto dropit; 77115794Sleres } 77220997Skarels 77320997Skarels /* check the protocol header version */ 77420997Skarels if (vv->vh_version != RING_VERSION) { 775*38986Skarels vvlog(LOG_DEBUG, "vv%d: bad protocol header version %d\n", 77620997Skarels unit, vv->vh_version & 0xff); 77720997Skarels goto dropit; 77820997Skarels } 77920997Skarels 7807640Ssam #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 78126950Sjas if (vv->vh_type == RING_TRAILER ) { 78228954Skarels off = ntohs((u_short)vv->vh_info); 78315794Sleres if (off > VVMTU) { 784*38986Skarels vvlog(LOG_DEBUG, 785*38986Skarels "vv%d: off > VVMTU, off = %d, vvicsr = %b\n", 786*38986Skarels unit, off, 0xffff&(addr->vvicsr), VV_IBITS); 7877640Ssam goto dropit; 78815794Sleres } 78926903Sjas vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *)); 79026950Sjas resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *))); 79115794Sleres if (off + resid > len) { 792*38986Skarels vvlog(LOG_DEBUG, "vv%d: trailer packet too short\n", 793*38986Skarels unit); 794*38986Skarels vvlog(LOG_DEBUG, 795*38986Skarels "vv%d: off = %d, resid = %d, vvicsr = %b\n", 796*38986Skarels unit, off, resid, 0xffff&(addr->vvicsr), VV_IBITS); 7977640Ssam goto dropit; 79815794Sleres } 7997640Ssam len = off + resid; 80011209Ssam } else 8017640Ssam off = 0; 80220997Skarels 80315794Sleres if (len == 0) { 804*38986Skarels vvlog(LOG_DEBUG, "vv%d: len is zero, vvicsr = %b\n", unit, 80515794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 8067640Ssam goto dropit; 80715794Sleres } 80820997Skarels 80924793Skarels m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if); 81015794Sleres if (m == NULL) { 811*38986Skarels vvlog(LOG_DEBUG, "vv%d: if_rubaget() failed, vvicsr = %b\n", 812*38986Skarels unit, 0xffff&(addr->vvicsr), VV_IBITS); 8137640Ssam goto dropit; 81415794Sleres } 8157640Ssam if (off) { 81624793Skarels struct ifnet *ifp; 81724793Skarels 81824793Skarels ifp = *(mtod(m, struct ifnet **)); 81924793Skarels m->m_off += 2 * sizeof (u_short); 82024793Skarels m->m_len -= 2 * sizeof (u_short); 82124793Skarels *(mtod(m, struct ifnet **)) = ifp; 8227640Ssam } 82311192Ssam 82415794Sleres /* Keep track of source address of this packet */ 82515794Sleres vs->vs_lastr = vv->vh_shost; 82620997Skarels 82711192Ssam /* 82815764Sleres * Demultiplex on packet type 82911192Ssam */ 8307024Ssam switch (vv->vh_type) { 83111192Ssam 8327024Ssam #ifdef INET 8337024Ssam case RING_IP: 8347024Ssam schednetisr(NETISR_IP); 8357024Ssam inq = &ipintrq; 8367024Ssam break; 8377024Ssam #endif 8387024Ssam default: 839*38986Skarels vvlog(LOG_DEBUG, "vv%d: unknown pkt type 0x%x\n", 840*38986Skarels unit, vv->vh_type); 8417640Ssam m_freem(m); 8427024Ssam goto setup; 8437024Ssam } 84415794Sleres s = splimp(); 8457640Ssam if (IF_QFULL(inq)) { 8467640Ssam IF_DROP(inq); 8477640Ssam m_freem(m); 84811209Ssam } else 8497640Ssam IF_ENQUEUE(inq, m); 85015764Sleres 85115794Sleres splx(s); 8527024Ssam /* 85315764Sleres * Reset for the next packet. 8547024Ssam */ 85515764Sleres setup: 85635805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 85735805Skarels addr->vviba = (u_short) ubaaddr; 85835805Skarels addr->vviea = (u_short) (ubaaddr >> 16); 85920997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 86020997Skarels addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB; 86115764Sleres return; 86211192Ssam 86311192Ssam /* 86411209Ssam * Drop packet on floor -- count them!! 86511192Ssam */ 8667640Ssam dropit: 8677640Ssam vs->vs_if.if_ierrors++; 8687640Ssam goto setup; 8697024Ssam } 8707024Ssam 8717024Ssam /* 87220997Skarels * proNET output routine. 8737024Ssam * Encapsulate a packet of type family for the local net. 8747024Ssam * Use trailer local net encapsulation if enough data in first 8757024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 8767024Ssam */ 8777024Ssam vvoutput(ifp, m0, dst) 8787024Ssam struct ifnet *ifp; 8797024Ssam struct mbuf *m0; 8807024Ssam struct sockaddr *dst; 8817024Ssam { 88216581Skarels register struct mbuf *m; 8837024Ssam register struct vv_header *vv; 8847640Ssam register int off; 88516581Skarels register int unit; 88616581Skarels register struct vvreg *addr; 88716581Skarels register struct vv_softc *vs; 88816581Skarels register int s; 88916581Skarels int type, dest, error; 8907024Ssam 89116581Skarels m = m0; 89216581Skarels unit = ifp->if_unit; 893*38986Skarels if ((ifp->if_flags & IFF_UP) == 0) 894*38986Skarels return (ENETDOWN); 89516581Skarels addr = (struct vvreg *)vvinfo[unit]->ui_addr; 89616581Skarels vs = &vv_softc[unit]; 89720997Skarels 89816581Skarels /* 89920997Skarels * Check to see if the input side has wedged due the UBA 90020997Skarels * vectoring through 0. 90116581Skarels * 90216581Skarels * We are lower than device ipl when we enter this routine, 90316581Skarels * so if the interface is ready with an input packet then 90416581Skarels * an input interrupt must have slipped through the cracks. 90516581Skarels * 90616581Skarels * Avoid the race with an input interrupt by watching to see 90716581Skarels * if any packets come in. 90816581Skarels */ 90916581Skarels s = vs->vs_if.if_ipackets; 91016581Skarels if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) { 911*38986Skarels log(LOG_ERR, "vv%d: lost a receive interrupt, icsr = %b\n", 91216581Skarels unit, 0xffff&(addr->vvicsr), VV_IBITS); 91316581Skarels s = splimp(); 91416581Skarels vvrint(unit); 91516581Skarels splx(s); 91616581Skarels } 91716581Skarels 9187024Ssam switch (dst->sa_family) { 91911192Ssam 9207024Ssam #ifdef INET 92115764Sleres case AF_INET: 92221779Skarels if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) 92321779Skarels dest = VV_BROADCAST; 92421779Skarels else 92521779Skarels dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr); 92620997Skarels #ifdef LOOPBACK 92721779Skarels if (dest == vs->vs_host && (loif.if_flags & IFF_UP)) 92821779Skarels return (looutput(&loif, m0, dst)); 92920997Skarels #endif LOOPBACK 93021779Skarels if (dest >= 0x100) { 9317640Ssam error = EPERM; 9327640Ssam goto bad; 9337640Ssam } 9347640Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 93520997Skarels /* 93620997Skarels * Trailerize, if the configuration allows it. 93720997Skarels * TODO: Need per host negotiation. 93820997Skarels */ 93913090Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 94013090Ssam if (off > 0 && (off & 0x1ff) == 0 && 9417640Ssam m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 94226950Sjas type = RING_TRAILER; 9437640Ssam m->m_off -= 2 * sizeof (u_short); 9447640Ssam m->m_len += 2 * sizeof (u_short); 94528954Skarels *mtod(m, u_short *) = htons((short)RING_IP); 94628954Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 9477640Ssam goto gottrailertype; 9487640Ssam } 9497024Ssam type = RING_IP; 9507024Ssam off = 0; 9517024Ssam goto gottype; 9527024Ssam #endif 9537024Ssam default: 95416581Skarels printf("vv%d: can't handle af%d\n", unit, dst->sa_family); 9557640Ssam error = EAFNOSUPPORT; 9567640Ssam goto bad; 9577024Ssam } 9587024Ssam 9597024Ssam gottrailertype: 9607024Ssam /* 9617024Ssam * Packet to be sent as trailer: move first packet 9627024Ssam * (control information) to end of chain. 9637024Ssam */ 9647024Ssam while (m->m_next) 9657024Ssam m = m->m_next; 9667024Ssam m->m_next = m0; 9677024Ssam m = m0->m_next; 9687024Ssam m0->m_next = 0; 9697024Ssam m0 = m; 9707024Ssam gottype: 9717024Ssam /* 9727024Ssam * Add local net header. If no space in first mbuf, 9737024Ssam * allocate another. 9747024Ssam */ 9757024Ssam if (m->m_off > MMAXOFF || 9767024Ssam MMINOFF + sizeof (struct vv_header) > m->m_off) { 97711209Ssam m = m_get(M_DONTWAIT, MT_HEADER); 97811209Ssam if (m == NULL) { 9797640Ssam error = ENOBUFS; 9807640Ssam goto bad; 9817024Ssam } 9827024Ssam m->m_next = m0; 9837024Ssam m->m_off = MMINOFF; 9847024Ssam m->m_len = sizeof (struct vv_header); 9857024Ssam } else { 9867024Ssam m->m_off -= sizeof (struct vv_header); 9877024Ssam m->m_len += sizeof (struct vv_header); 9887024Ssam } 9897024Ssam vv = mtod(m, struct vv_header *); 99021779Skarels vv->vh_shost = vs->vs_host; 99121779Skarels vv->vh_dhost = dest; 9927024Ssam vv->vh_version = RING_VERSION; 9937024Ssam vv->vh_type = type; 99428954Skarels vv->vh_info = htons((u_short)off); 99511192Ssam vvtracehdr("vo", vv); 9967024Ssam 9977024Ssam /* 9987024Ssam * Queue message on interface, and start output if interface 9997024Ssam * not yet active. 10007024Ssam */ 10017024Ssam s = splimp(); 10027640Ssam if (IF_QFULL(&ifp->if_snd)) { 10037640Ssam IF_DROP(&ifp->if_snd); 10047640Ssam error = ENOBUFS; 10057640Ssam goto qfull; 10067640Ssam } 10077024Ssam IF_ENQUEUE(&ifp->if_snd, m); 100816581Skarels if (vs->vs_oactive == 0) 100916581Skarels vvstart(unit); 10107024Ssam splx(s); 10117640Ssam return (0); 10127640Ssam qfull: 10137640Ssam m0 = m; 10147640Ssam splx(s); 10157640Ssam bad: 10167640Ssam m_freem(m0); 10177640Ssam return(error); 10187024Ssam } 10197024Ssam 10207024Ssam /* 102113057Ssam * Process an ioctl request. 102213057Ssam */ 102313057Ssam vvioctl(ifp, cmd, data) 102413057Ssam register struct ifnet *ifp; 102513057Ssam int cmd; 102613057Ssam caddr_t data; 102713057Ssam { 1028*38986Skarels register struct vv_softc *vs = &vv_softc[ifp->if_unit]; 102921779Skarels struct ifaddr *ifa = (struct ifaddr *) data; 1030*38986Skarels struct vvreg *addr = (struct vvreg *)(vvinfo[ifp->if_unit]); 103121779Skarels int s = splimp(), error = 0; 103213057Ssam 103313057Ssam switch (cmd) { 103413057Ssam 103513057Ssam case SIOCSIFADDR: 1036*38986Skarels if ((vs->vs_flags & VS_RUNNING) == 0) 1037*38986Skarels vvinit(ifp->if_unit, 1); 103826903Sjas /* 103926903Sjas * Did self-test succeed? 104026903Sjas */ 104126903Sjas if ((ifp->if_flags & IFF_UP) == 0) 104226903Sjas error = ENETDOWN; 104336085Skarels else { 104436085Skarels /* 104536085Skarels * Attempt to check agreement of protocol address 104636085Skarels * and board address. 104736085Skarels */ 104836085Skarels switch (ifa->ifa_addr.sa_family) { 104936085Skarels case AF_INET: 105036085Skarels if ((in_lnaof(IA_SIN(ifa)->sin_addr) & 0xff) != 1051*38986Skarels vs->vs_host) 105236085Skarels error = EADDRNOTAVAIL; 105336085Skarels break; 105436085Skarels } 105521779Skarels } 105613057Ssam break; 105713057Ssam 1058*38986Skarels case SIOCSIFFLAGS: 1059*38986Skarels if ((ifp->if_flags & IFF_UP) == 0 && 1060*38986Skarels vs->vs_flags & VS_RUNNING) { 1061*38986Skarels addr->vvicsr = VV_RST; 1062*38986Skarels addr->vvocsr = VV_RST; 1063*38986Skarels vs->vs_flags &= ~VS_RUNNING; 1064*38986Skarels } else if (ifp->if_flags & IFF_UP && 1065*38986Skarels (vs->vs_flags & VS_RUNNING) == 0) 1066*38986Skarels vvinit(ifp->if_unit, 1); 1067*38986Skarels break; 1068*38986Skarels 106913057Ssam default: 107013057Ssam error = EINVAL; 1071*38986Skarels break; 107213057Ssam } 107313057Ssam splx(s); 107421779Skarels return (error); 107513057Ssam } 107625190Skarels 107725190Skarels /* 107825190Skarels * vvprt_hdr(s, v) print the local net header in "v" 107925190Skarels * with title is "s" 108025190Skarels */ 108125190Skarels vvprt_hdr(s, v) 108225190Skarels char *s; 108325190Skarels register struct vv_header *v; 108425190Skarels { 108525190Skarels printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 108625190Skarels s, 108725190Skarels 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 108825190Skarels 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 108925190Skarels 0xffff & (int)(v->vh_info)); 109025190Skarels } 109126903Sjas #endif NVV 1092