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*40840Ssklower * @(#)if_vv.c 7.7 (Berkeley) 04/07/90 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" 6438986Skarels #include "time.h" 6538986Skarels #include "kernel.h" 6617117Sbloom #include "protosw.h" 6717117Sbloom #include "socket.h" 6838986Skarels #include "syslog.h" 6917117Sbloom #include "vmmac.h" 7017117Sbloom #include "errno.h" 7117117Sbloom #include "ioctl.h" 728465Sroot 738465Sroot #include "../net/if.h" 7439201Ssklower #include "../net/if_types.h" 7511209Ssam #include "../net/netisr.h" 768465Sroot #include "../net/route.h" 7724793Skarels 7824793Skarels #ifdef INET 798421Swnj #include "../netinet/in.h" 808421Swnj #include "../netinet/in_systm.h" 8121779Skarels #include "../netinet/in_var.h" 828421Swnj #include "../netinet/ip.h" 8324793Skarels #endif 848465Sroot 8538986Skarels #include "../vax/pte.h" 8615794Sleres #include "../vax/cpu.h" 8711209Ssam #include "../vax/mtpr.h" 8817117Sbloom #include "if_vv.h" 8917117Sbloom #include "if_uba.h" 908465Sroot #include "../vaxuba/ubareg.h" 918465Sroot #include "../vaxuba/ubavar.h" 927024Ssam 937024Ssam /* 9420997Skarels * maximum transmission unit definition -- 9535805Skarels * you can set VVMTU at anything from 576 to 2036. 9620997Skarels * 1536 is a popular "large" value, because it is a multiple 9720997Skarels * of 512, which the trailer scheme likes. 9835805Skarels * The absolute maximum size is 2036, which is enforced. 9920997Skarels */ 10020997Skarels 10135805Skarels #define VVMTU (2036) 10220997Skarels 10335805Skarels #define VVMRU (VVMTU + (2 * sizeof(u_short))) 10420997Skarels #define VVBUFSIZE (VVMRU + sizeof(struct vv_header)) 10535805Skarels #if VVMTU>2036 10620997Skarels #undef VVMTU 10720997Skarels #undef VVMRU 10820997Skarels #undef VVBUFSIZE 10920997Skarels #define VVBUFSIZE (2046) 11020997Skarels #define VVMRU (VVBUFSIZE - sizeof (struct vv_header)) 11135805Skarels #define VVMTU (VVMRU - (2 * sizeof(u_short))) 1127024Ssam #endif 1137024Ssam 11420997Skarels /* 11520997Skarels * debugging and tracing stuff 11620997Skarels */ 11716581Skarels int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */ 1187640Ssam 11920997Skarels #define vvtracehdr if (vv_tracehdr) vvprt_hdr 12038986Skarels #define vvlog if (vs->vs_if.if_flags & IFF_DEBUG) log 12111192Ssam 12220997Skarels /* 12320997Skarels * externals, types, etc. 12420997Skarels */ 12516581Skarels int vvprobe(), vvattach(), vvreset(), vvinit(); 12616581Skarels int vvidentify(), vvstart(), vvxint(), vvwatchdog(); 12726394Skarels int vvrint(), vvoutput(), vvioctl(); 1287024Ssam struct uba_device *vvinfo[NVV]; 1297024Ssam u_short vvstd[] = { 0 }; 1307024Ssam struct uba_driver vvdriver = 1317024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 1327024Ssam #define VVUNIT(x) minor(x) 1337024Ssam 13420997Skarels #define LOOPBACK /* use loopback for packets meant for us */ 13520997Skarels #ifdef LOOPBACK 13620997Skarels extern struct ifnet loif; 13720997Skarels #endif 13820997Skarels 13938986Skarels extern wakeup(); 14038986Skarels 1417024Ssam /* 1427024Ssam * Software status of each interface. 1437024Ssam * 1447024Ssam * Each interface is referenced by a network interface structure, 1457024Ssam * vs_if, which the routing code uses to locate the interface. 1467024Ssam * This structure contains the output queue for the interface, its address, ... 1477024Ssam * We also have, for each interface, a UBA interface structure, which 1487024Ssam * contains information about the UNIBUS resources held by the interface: 1497024Ssam * map registers, buffered data paths, etc. Information is cached in this 1507024Ssam * structure for use by the if_uba.c routines in running the interface 1517024Ssam * efficiently. 1527024Ssam */ 1537024Ssam struct vv_softc { 1547024Ssam struct ifnet vs_if; /* network-visible interface */ 1557024Ssam struct ifuba vs_ifuba; /* UNIBUS resources */ 15626298Skarels u_short vs_host; /* this interface address */ 15711192Ssam short vs_oactive; /* is output active */ 15826903Sjas short vs_is80; /* is 80 megabit version */ 1597024Ssam short vs_olen; /* length of last output */ 16015794Sleres u_short vs_lastx; /* address of last packet sent */ 16115794Sleres u_short vs_lastr; /* address of last packet received */ 16211192Ssam short vs_tries; /* transmit current retry count */ 1637024Ssam short vs_init; /* number of ring inits */ 16420997Skarels short vs_refused; /* number of packets refused */ 16515794Sleres short vs_timeouts; /* number of transmit timeouts */ 16620997Skarels short vs_otimeout; /* number of output timeouts */ 16720997Skarels short vs_ibadf; /* number of input bad formats */ 16820997Skarels short vs_parity; /* number of parity errors on 10 meg, */ 16920997Skarels /* link data errors on 80 meg */ 17036085Skarels short vs_ipl; /* interrupt priority on Q-bus */ 17138986Skarels short vs_flags; /* board state: */ 17238986Skarels #define VS_RUNNING 0x01 /* board has been initialized */ 17338986Skarels #define VS_INIT 0x02 /* board being initialized */ 1747024Ssam } vv_softc[NVV]; 1757024Ssam 17638986Skarels #define NOHOST 0xff /* illegal host number */ 17726311Skarels 17820997Skarels /* 17920997Skarels * probe the interface to see that the registers exist, and then 18020997Skarels * cause an interrupt to find its vector 18120997Skarels */ 18236085Skarels vvprobe(reg, ui) 1837024Ssam caddr_t reg; 18436085Skarels struct uba_device *ui; 1857024Ssam { 1867024Ssam register int br, cvec; 18716581Skarels register struct vvreg *addr; 1887024Ssam 1897024Ssam #ifdef lint 19015764Sleres br = 0; cvec = br; br = cvec; 1917024Ssam #endif 19216581Skarels addr = (struct vvreg *)reg; 19320997Skarels 1947024Ssam /* reset interface, enable, and wait till dust settles */ 19536085Skarels #ifdef QBA 19636085Skarels (void) spl6(); 19736085Skarels #endif 1987024Ssam addr->vvicsr = VV_RST; 1997024Ssam addr->vvocsr = VV_RST; 20015764Sleres DELAY(100000); 20120997Skarels 2027024Ssam /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 2037024Ssam addr->vvoba = 0; /* low 16 bits */ 2047024Ssam addr->vvoea = 0; /* extended bits */ 2057024Ssam addr->vvowc = -1; /* for 1 word */ 20620997Skarels addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */ 2077024Ssam DELAY(100000); 20836085Skarels #ifdef QBA 20936085Skarels vv_softc[ui->ui_unit].vs_ipl = br = qbgetpri(); 21036085Skarels #endif 21120997Skarels addr->vvocsr = VV_RST; /* clear out the CSR */ 2127024Ssam if (cvec && cvec != 0x200) 21315764Sleres cvec -= 4; /* backup so vector => receive */ 21436085Skarels return (sizeof(struct vvreg)); 2157024Ssam } 2167024Ssam 2177024Ssam /* 2187024Ssam * Interface exists: make available by filling in network interface 2197024Ssam * record. System will initialize the interface when it is ready 2207024Ssam * to accept packets. 2217024Ssam */ 2227024Ssam vvattach(ui) 2237024Ssam struct uba_device *ui; 2247024Ssam { 22515764Sleres register struct vv_softc *vs; 2267024Ssam 22715764Sleres vs = &vv_softc[ui->ui_unit]; 2287024Ssam vs->vs_if.if_unit = ui->ui_unit; 2297024Ssam vs->vs_if.if_name = "vv"; 2307024Ssam vs->vs_if.if_mtu = VVMTU; 23121779Skarels vs->vs_if.if_flags = IFF_BROADCAST; 2327024Ssam vs->vs_if.if_init = vvinit; 23313057Ssam vs->vs_if.if_ioctl = vvioctl; 2347024Ssam vs->vs_if.if_output = vvoutput; 23511209Ssam vs->vs_if.if_reset = vvreset; 23615794Sleres vs->vs_if.if_timer = 0; 23715794Sleres vs->vs_if.if_watchdog = vvwatchdog; 23826201Skarels vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP; 23926903Sjas 24026903Sjas /* use flag to determine if this is proNET-80 */ 24139201Ssklower if (vs->vs_is80 = (short)(ui->ui_flags & 01)) { 24239201Ssklower vs->vs_if.if_type = IFT_P80; 24339201Ssklower vs->vs_if.if_baudrate = 80 * 1024 * 1024; 24439201Ssklower } else { 24539201Ssklower vs->vs_if.if_type = IFT_P10; 24639201Ssklower vs->vs_if.if_baudrate = 10 * 1024 * 1024; 24739201Ssklower } 24838986Skarels vs->vs_host = NOHOST; 24926903Sjas 25012354Smo #if defined(VAX750) 25112354Smo /* don't chew up 750 bdp's */ 25212354Smo if (cpu == VAX_750 && ui->ui_unit > 0) 25312354Smo vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 25412354Smo #endif 2557024Ssam if_attach(&vs->vs_if); 2567024Ssam } 2577024Ssam 2587024Ssam /* 2597024Ssam * Reset of interface after UNIBUS reset. 2607024Ssam * If interface is on specified uba, reset its state. 2617024Ssam */ 2627024Ssam vvreset(unit, uban) 2637024Ssam int unit, uban; 2647024Ssam { 2657024Ssam register struct uba_device *ui; 2667024Ssam 2677024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 2687024Ssam ui->ui_ubanum != uban) 2697024Ssam return; 2707024Ssam printf(" vv%d", unit); 27138986Skarels vv_softc[unit].vs_if.if_flags &= ~IFF_RUNNING; 27238986Skarels vv_softc[unit].vs_flags &= ~VS_RUNNING; 27338986Skarels vvinit(unit, 0); 2747024Ssam } 2757024Ssam 2767024Ssam /* 2777024Ssam * Initialization of interface; clear recorded pending 2787024Ssam * operations, and reinitialize UNIBUS usage. 2797024Ssam */ 28038986Skarels vvinit(unit, cansleep) 28138986Skarels int unit, cansleep; 2827024Ssam { 28315764Sleres register struct vv_softc *vs; 28415764Sleres register struct uba_device *ui; 2857024Ssam register struct vvreg *addr; 28635805Skarels register int ubaaddr, s; 2877024Ssam 28815764Sleres vs = &vv_softc[unit]; 28915764Sleres ui = vvinfo[unit]; 29020997Skarels 29121779Skarels if (vs->vs_if.if_addrlist == (struct ifaddr *)0) 29213057Ssam return; 29320997Skarels 29438986Skarels /* 29538986Skarels * Prevent multiple instances of vvinit 29638986Skarels * from trying simultaneously. 29738986Skarels */ 29838986Skarels while (vs->vs_flags & VS_INIT) { 29938986Skarels if (cansleep) 300*40840Ssklower sleep((caddr_t)vs, PZERO); 30138986Skarels else 30238986Skarels return; 30338986Skarels } 30438986Skarels if (vs->vs_flags & VS_RUNNING) 30538986Skarels return; 30638986Skarels vs->vs_flags = VS_INIT; 30738986Skarels 3087640Ssam addr = (struct vvreg *)ui->ui_addr; 30936085Skarels if ((vs->vs_if.if_flags & IFF_RUNNING) == 0 && 31036085Skarels if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 31136085Skarels sizeof (struct vv_header), (int)btoc(VVMRU)) == 0) { 31215794Sleres printf("vv%d: can't initialize, if_ubainit() failed\n", unit); 3137640Ssam vs->vs_if.if_flags &= ~IFF_UP; 31438986Skarels vs->vs_flags = 0; 3157024Ssam return; 3167024Ssam } 31736085Skarels vs->vs_if.if_flags |= IFF_RUNNING; 31820997Skarels 3197024Ssam /* 32015764Sleres * Now that the uba is set up, figure out our address and 32115764Sleres * update complete our host address. 3227640Ssam */ 32338986Skarels if (cansleep) 32438986Skarels vs->vs_host = vvidentify(unit); 32538986Skarels if (vs->vs_host == NOHOST) { 32615794Sleres vs->vs_if.if_flags &= ~IFF_UP; 32738986Skarels vs->vs_flags = 0; 32815794Sleres return; 32915794Sleres } 33038986Skarels vvlog(LOG_DEBUG, "vv%d: host %u\n", unit, vs->vs_host); 33120997Skarels 3327640Ssam /* 33320997Skarels * Reset the interface, and stay in the ring 3347640Ssam */ 33520997Skarels addr->vvocsr = VV_RST; /* take over output */ 33620997Skarels addr->vvocsr = VV_CPB; /* clear packet buffer */ 33720997Skarels addr->vvicsr = VV_RST | VV_HEN; /* take over input, */ 33820997Skarels /* keep relay closed */ 33938986Skarels if (cansleep) { 34038986Skarels timeout(wakeup, (caddr_t)vs, hz/2); 34138986Skarels sleep((caddr_t)vs, PZERO); /* let contacts settle */ 34238986Skarels } else 34338986Skarels DELAY(500000); /* let contacts settle */ 34420997Skarels 34520997Skarels vs->vs_init = 0; /* clear counters, etc. */ 34620997Skarels vs->vs_refused = 0; 34715794Sleres vs->vs_timeouts = 0; 34820997Skarels vs->vs_otimeout = 0; 34920997Skarels vs->vs_ibadf = 0; 35020997Skarels vs->vs_parity = 0; 35115794Sleres vs->vs_lastx = 256; /* an invalid address */ 35215794Sleres vs->vs_lastr = 256; /* an invalid address */ 35320997Skarels 3547640Ssam /* 3557640Ssam * Hang a receive and start any 3567640Ssam * pending writes by faking a transmit complete. 3577640Ssam */ 3587640Ssam s = splimp(); 35935805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 36035805Skarels addr->vviba = (u_short)ubaaddr; 36135805Skarels addr->vviea = (u_short)(ubaaddr >> 16); 36220997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 36320997Skarels addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB; 3647640Ssam vs->vs_oactive = 1; 36536085Skarels vs->vs_if.if_flags |= IFF_UP; 36638986Skarels vs->vs_flags = VS_RUNNING; /* clear VS_INIT */ 36738986Skarels wakeup((caddr_t)vs); 3687640Ssam vvxint(unit); 3697640Ssam splx(s); 3707640Ssam } 3717640Ssam 3727640Ssam /* 37320997Skarels * Do a moderately thorough self-test in all three modes. Mostly 37420997Skarels * to keeps defective nodes off the ring, rather than to be especially 37520997Skarels * thorough. The key issue is to detect any cable breaks before joining 37620997Skarels * the ring. Return our node address on success, return -1 on failure. 37720997Skarels * 3787640Ssam */ 37920997Skarels 38020997Skarels /* the three self-test modes */ 38120997Skarels static u_short vv_modes[] = { 38220997Skarels VV_STE|VV_LPB, /* digital loopback */ 38320997Skarels VV_STE, /* analog loopback */ 38420997Skarels VV_HEN /* network mode */ 38520997Skarels }; 38620997Skarels 38711209Ssam vvidentify(unit) 38813057Ssam int unit; 38911209Ssam { 39015764Sleres register struct vv_softc *vs; 39115764Sleres register struct uba_device *ui; 3927640Ssam register struct vvreg *addr; 39316581Skarels register struct mbuf *m; 39416581Skarels register struct vv_header *v; 39535805Skarels register int ubaaddr; 39620997Skarels register int i, successes, failures, waitcount; 39726311Skarels u_short shost = NOHOST; 3987640Ssam 39920997Skarels vs = &vv_softc[unit]; 40020997Skarels ui = vvinfo[unit]; 40120997Skarels addr = (struct vvreg *)ui->ui_addr; 40220997Skarels 4037640Ssam /* 4047024Ssam * Build a multicast message to identify our address 40520997Skarels * We need do this only once, since nobody else is about to use 40620997Skarels * the intermediate transmit buffer (ifu_w.ifrw_addr) that 40720997Skarels * if_ubainit() aquired for us. 4087024Ssam */ 40939201Ssklower MGETHDR(m, M_DONTWAIT, MT_HEADER); 41015794Sleres if (m == NULL) { 41115794Sleres printf("vv%d: can't initialize, m_get() failed\n", unit); 41238986Skarels return (NOHOST); 41315794Sleres } 41439201Ssklower m->m_pkthdr.len = m->m_len = sizeof(struct vv_header); 4157024Ssam v = mtod(m, struct vv_header *); 41611192Ssam v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 4177024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 4187024Ssam v->vh_version = RING_VERSION; 41920997Skarels v->vh_type = RING_DIAGNOSTICS; 4207024Ssam v->vh_info = 0; 42120997Skarels /* map xmit message into uba, copying to intermediate buffer */ 42220997Skarels vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 42320997Skarels 4247024Ssam /* 42520997Skarels * For each of the modes (digital, analog, network), go through 42620997Skarels * a self-test that requires me to send VVIDENTSUCC good packets 42720997Skarels * in VVIDENTRETRY attempts. Use broadcast destination to find out 42820997Skarels * who I am, then use this as my address to check my address match 42920997Skarels * logic. Only data checked is the vh_type field. 4307024Ssam */ 4317640Ssam 43220997Skarels for (i = 0; i < 3; i++) { 43320997Skarels successes = 0; /* clear successes for this mode */ 43420997Skarels failures = 0; /* and clear failures, too */ 4357640Ssam 43620997Skarels /* take over device, and leave ring */ 43720997Skarels addr->vvicsr = VV_RST; 43820997Skarels addr->vvocsr = VV_RST; 43920997Skarels addr->vvicsr = vv_modes[i]; /* test mode */ 44020997Skarels 44120997Skarels /* 44220997Skarels * let the flag and token timers pop so that the init ring bit 44320997Skarels * will be allowed to work, by waiting about 1 second 44420997Skarels */ 44538986Skarels timeout(wakeup, (caddr_t)vs, hz); 44638986Skarels sleep((caddr_t)vs, PZERO); 44720997Skarels 44820997Skarels /* 44920997Skarels * retry loop 45020997Skarels */ 45120997Skarels while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY)) 45220997Skarels { 45320997Skarels /* start a receive */ 45435805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 45520997Skarels addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */ 45635805Skarels addr->vviba = (u_short) ubaaddr; 45735805Skarels addr->vviea = (u_short) (ubaaddr >> 16); 45820997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 45920997Skarels addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB; 46020997Skarels 46138986Skarels #ifdef notdef 46220997Skarels /* purge stale data from BDP */ 46320997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 46420997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 46520997Skarels vs->vs_ifuba.ifu_w.ifrw_bdp); 46638986Skarels #endif 46720997Skarels 46820997Skarels /* do a transmit */ 46935805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info); 47020997Skarels addr->vvocsr = VV_RST; /* abort last try */ 47135805Skarels addr->vvoba = (u_short) ubaaddr; 47235805Skarels addr->vvoea = (u_short) (ubaaddr >> 16); 47320997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); 47420997Skarels addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 47520997Skarels 47620997Skarels /* poll receive side for completion */ 47720997Skarels DELAY(10000); /* give it a chance */ 47820997Skarels for (waitcount = 0; waitcount < 10; waitcount++) { 47920997Skarels if (addr->vvicsr & VV_RDY) 48020997Skarels goto gotit; 48120997Skarels DELAY(1000); 48220997Skarels } 48320997Skarels failures++; /* no luck */ 48411209Ssam continue; 48520997Skarels 48620997Skarels gotit: /* we got something--is it any good? */ 48720997Skarels if ((addr->vvicsr & (VVRERR|VV_LDE)) || 48821779Skarels (addr->vvocsr & (VVXERR|VV_RFS))) { 48920997Skarels failures++; 49020997Skarels continue; 49120997Skarels } 49220997Skarels 49320997Skarels /* Purge BDP before looking at received packet */ 49420997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 49520997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 49620997Skarels vs->vs_ifuba.ifu_r.ifrw_bdp); 49738986Skarels #ifdef notdef 49824793Skarels m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 49926394Skarels 0, &vs->vs_if); 50020997Skarels if (m != NULL) 50120997Skarels m_freem(m); 50238986Skarels #endif 50320997Skarels 50420997Skarels v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 50520997Skarels 50620997Skarels /* check message type, catch our node address */ 50720997Skarels if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) { 50826311Skarels if (shost == NOHOST) { 50920997Skarels shost = v->vh_shost & 0xff; 51020997Skarels /* send to ourself now */ 51120997Skarels ((struct vv_header *) 51220997Skarels (vs->vs_ifuba.ifu_r.ifrw_addr)) 51320997Skarels ->vh_dhost = shost; 51420997Skarels } 51520997Skarels successes++; 51626903Sjas } else { 51726903Sjas failures++; 51820997Skarels } 51926903Sjas v->vh_type = 0; /* clear to check again */ 52011192Ssam } 52120997Skarels 52220997Skarels if (failures >= VVIDENTRETRY) 52320997Skarels { 52420997Skarels printf("vv%d: failed self-test after %d tries \ 52520997Skarels in %s mode\n", 52620997Skarels unit, VVIDENTRETRY, i == 0 ? "digital loopback" : 52720997Skarels (i == 1 ? "analog loopback" : "network")); 52820997Skarels printf("vv%d: icsr = %b, ocsr = %b\n", 52920997Skarels unit, 0xffff & addr->vvicsr, VV_IBITS, 53020997Skarels 0xffff & addr->vvocsr, VV_OBITS); 53120997Skarels addr->vvicsr = VV_RST; /* kill the sick board */ 53220997Skarels addr->vvocsr = VV_RST; 53326311Skarels shost = NOHOST; 53420997Skarels goto done; 53520997Skarels } 53611192Ssam } 53720997Skarels 53820997Skarels done: 53920997Skarels /* deallocate mbuf used for send packet (won't be one, anyways) */ 54015794Sleres if (vs->vs_ifuba.ifu_xtofree) { 5417024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 54215794Sleres vs->vs_ifuba.ifu_xtofree = 0; 54315794Sleres } 54420997Skarels 54520997Skarels return(shost); 5467024Ssam } 5477024Ssam 5487024Ssam /* 5497024Ssam * Start or restart output on interface. 55011192Ssam * If interface is active, this is a retransmit, so just 55111192Ssam * restuff registers and go. 5527024Ssam * If interface is not already active, get another datagram 5537024Ssam * to send off of the interface queue, and map it to the interface 5547024Ssam * before starting the output. 5557024Ssam */ 5567024Ssam vvstart(dev) 5577024Ssam dev_t dev; 5587024Ssam { 55916581Skarels register struct uba_device *ui; 56015764Sleres register struct vv_softc *vs; 5617024Ssam register struct vvreg *addr; 56216581Skarels register struct mbuf *m; 56335805Skarels register int unit, ubaaddr, dest, s; 5647024Ssam 56516581Skarels unit = VVUNIT(dev); 56615764Sleres ui = vvinfo[unit]; 56715764Sleres vs = &vv_softc[unit]; 5687024Ssam if (vs->vs_oactive) 5697024Ssam goto restart; 5707024Ssam /* 5717024Ssam * Not already active: dequeue another request 5727024Ssam * and map it to the UNIBUS. If no more requests, 5737024Ssam * just return. 5747024Ssam */ 57515794Sleres s = splimp(); 5767024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 57715794Sleres splx(s); 57811209Ssam if (m == NULL) { 5797024Ssam vs->vs_oactive = 0; 5807024Ssam return; 5817024Ssam } 5827024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 5837024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 5847024Ssam vs->vs_lastx = dest; 58539201Ssklower vs->vs_if.if_obytes += vs->vs_olen; 58639201Ssklower vs->vs_if.if_lastchange = time; 5877024Ssam restart: 5887024Ssam /* 5897024Ssam * Have request mapped to UNIBUS for transmission. 59015794Sleres * Purge any stale data from this BDP, and start the output. 59115794Sleres * 59215794Sleres * Make sure this packet will fit in the interface. 5937024Ssam */ 59420997Skarels if (vs->vs_olen > VVBUFSIZE) { 59520997Skarels printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen); 59611192Ssam panic("vvdriver vs_olen botch"); 59711192Ssam } 59820997Skarels 59920997Skarels vs->vs_if.if_timer = VVTIMEOUT; 60020997Skarels vs->vs_oactive = 1; 60120997Skarels 60220997Skarels /* ship it */ 60336085Skarels #ifdef notdef 6047024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 6057024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 60636085Skarels #endif 6077024Ssam addr = (struct vvreg *)ui->ui_addr; 60835805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info); 60935805Skarels addr->vvoba = (u_short) ubaaddr; 61035805Skarels addr->vvoea = (u_short) (ubaaddr >> 16); 6117024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 61220997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */ 61320997Skarels if (addr->vvocsr & VV_NOK) 61420997Skarels vs->vs_init++; /* count ring inits */ 6157024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 6167024Ssam } 6177024Ssam 6187024Ssam /* 61920997Skarels * proNET transmit interrupt 6207024Ssam * Start another output if more data to send. 6217024Ssam */ 6227024Ssam vvxint(unit) 6237024Ssam int unit; 6247024Ssam { 62515764Sleres register struct uba_device *ui; 62615764Sleres register struct vv_softc *vs; 6277024Ssam register struct vvreg *addr; 6287024Ssam register int oc; 6297024Ssam 63038986Skarels ui = vvinfo[unit]; 63138986Skarels vs = &vv_softc[unit]; 63236085Skarels #ifdef QBA 63338986Skarels splx(vs->vs_ipl); 63436085Skarels #endif 63515794Sleres vs->vs_if.if_timer = 0; 6367024Ssam addr = (struct vvreg *)ui->ui_addr; 6377024Ssam oc = 0xffff & (addr->vvocsr); 6387024Ssam if (vs->vs_oactive == 0) { 63938986Skarels vvlog(LOG_DEBUG, "vv%d: stray interrupt vvocsr = %b\n", unit, 64015764Sleres oc, VV_OBITS); 6417024Ssam return; 6427024Ssam } 64320997Skarels 64420997Skarels /* 64520997Skarels * we retransmit on soft error 64620997Skarels * TODO: sort retransmits to end of queue if possible! 64720997Skarels */ 64820997Skarels if (oc & (VV_OPT | VV_RFS)) { 64911192Ssam if (vs->vs_tries++ < VVRETRY) { 6507024Ssam if (oc & VV_OPT) 65120997Skarels vs->vs_otimeout++; 65220997Skarels if (oc & VV_RFS) { 65320997Skarels vs->vs_if.if_collisions++; 65420997Skarels vs->vs_refused++; 65520997Skarels } 65611192Ssam vvstart(unit); /* restart this message */ 6577024Ssam return; 6587024Ssam } 6597024Ssam } 6607024Ssam vs->vs_if.if_opackets++; 6617024Ssam vs->vs_oactive = 0; 6627024Ssam vs->vs_tries = 0; 66320997Skarels 6647024Ssam if (oc & VVXERR) { 66539201Ssklower vs->vs_if.if_obytes -= vs->vs_olen; 6667024Ssam vs->vs_if.if_oerrors++; 66738986Skarels vvlog(LOG_ERR, "vv%d: error vvocsr = %b\n", 66838986Skarels unit, 0xffff & oc, VV_OBITS); 6697024Ssam } 6707024Ssam if (vs->vs_ifuba.ifu_xtofree) { 6717024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 6727024Ssam vs->vs_ifuba.ifu_xtofree = 0; 6737024Ssam } 6747024Ssam vvstart(unit); 6757024Ssam } 6767024Ssam 6777024Ssam /* 67815794Sleres * Transmit watchdog timer routine. 67915794Sleres * This routine gets called when we lose a transmit interrupt. 68015794Sleres * The best we can do is try to restart output. 68115794Sleres */ 68215794Sleres vvwatchdog(unit) 68315794Sleres int unit; 68415794Sleres { 68515794Sleres register struct vv_softc *vs; 68615794Sleres 68715794Sleres vs = &vv_softc[unit]; 68838986Skarels log(LOG_ERR, "vv%d: lost transmit interrupt\n", unit); 68915794Sleres vs->vs_timeouts++; 69015794Sleres vvstart(unit); 69115794Sleres } 69215794Sleres 69315794Sleres /* 69420997Skarels * proNET interface receiver interrupt. 6957024Ssam * If input error just drop packet. 69615764Sleres * Otherwise purge input buffered data path and examine 6977024Ssam * packet to determine type. If can't determine length 69815764Sleres * from type, then have to drop packet. Otherwise decapsulate 6997024Ssam * packet based on type and pass to type specific higher-level 7007024Ssam * input routine. 7017024Ssam */ 7027024Ssam vvrint(unit) 7037024Ssam int unit; 7047024Ssam { 70515764Sleres register struct vv_softc *vs; 70616581Skarels register struct vvreg *addr; 7077024Ssam register struct vv_header *vv; 7087024Ssam register struct ifqueue *inq; 70916581Skarels register struct mbuf *m; 71035805Skarels int ubaaddr, len, off, s; 7117640Ssam short resid; 7127024Ssam 71338986Skarels vs = &vv_softc[unit]; 71436085Skarels #ifdef QBA 71538986Skarels splx(vs->vs_ipl); 71636085Skarels #endif 71716581Skarels vs->vs_if.if_ipackets++; 71839201Ssklower vs->vs_if.if_lastchange = time; 71915764Sleres addr = (struct vvreg *)vvinfo[unit]->ui_addr; 72020997Skarels 7217024Ssam /* 72226903Sjas * Purge BDP 7237024Ssam */ 7247024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 7257024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 72620997Skarels 72720997Skarels /* 72820997Skarels * receive errors? 72920997Skarels */ 7307024Ssam if (addr->vvicsr & VVRERR) { 73138986Skarels vvlog(LOG_INFO, "vv%d: receive error, vvicsr = %b\n", unit, 73220997Skarels 0xffff&(addr->vvicsr), VV_IBITS); 73320997Skarels if (addr->vvicsr & VV_BDF) 73420997Skarels vs->vs_ibadf++; 7357640Ssam goto dropit; 7367024Ssam } 7377640Ssam 7387024Ssam /* 73920997Skarels * parity errors? 74020997Skarels */ 74120997Skarels if (addr->vvicsr & VV_LDE) { 74220997Skarels /* we don't have to clear it because the receive command */ 74320997Skarels /* writes 0 to parity bit */ 74420997Skarels vs->vs_parity++; 74526903Sjas 74620997Skarels /* 74720997Skarels * only on 10 megabit proNET is VV_LDE an end-to-end parity 74820997Skarels * bit. On 80 megabit, it returns to the intended use of 74920997Skarels * node-to-node parity. End-to-end parity errors on 80 megabit 75020997Skarels * give VV_BDF. 75120997Skarels */ 75226903Sjas if (vs->vs_is80 == 0) 75326903Sjas goto dropit; 75420997Skarels } 75520997Skarels 75620997Skarels /* 75720997Skarels * Get packet length from residual word count 7587640Ssam * 7597640Ssam * Compute header offset if trailer protocol 7607640Ssam * 7617640Ssam * Pull packet off interface. Off is nonzero if packet 7627640Ssam * has trailing header; if_rubaget will then force this header 7637640Ssam * information to be at the front. The vh_info field 7647640Ssam * carries the offset to the trailer data in trailer 7657640Ssam * format packets. 7667024Ssam */ 7677640Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 76811192Ssam vvtracehdr("vi", vv); 76920997Skarels resid = addr->vviwc & 01777; /* only low 10 bits valid */ 7707640Ssam if (resid) 77120997Skarels resid |= 0176000; /* high 6 bits are undefined */ 77220997Skarels len = ((VVBUFSIZE >> 1) + resid) << 1; 7737640Ssam len -= sizeof(struct vv_header); 77420997Skarels 77520997Skarels if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) { 77638986Skarels vvlog(LOG_DEBUG, "vv%d: len too long or short, \ 77720997Skarels len = %d, vvicsr = %b\n", 77815794Sleres unit, len, 0xffff&(addr->vvicsr), VV_IBITS); 7797640Ssam goto dropit; 78015794Sleres } 78120997Skarels 78220997Skarels /* check the protocol header version */ 78320997Skarels if (vv->vh_version != RING_VERSION) { 78438986Skarels vvlog(LOG_DEBUG, "vv%d: bad protocol header version %d\n", 78520997Skarels unit, vv->vh_version & 0xff); 78620997Skarels goto dropit; 78720997Skarels } 78820997Skarels 7897640Ssam #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 79026950Sjas if (vv->vh_type == RING_TRAILER ) { 79128954Skarels off = ntohs((u_short)vv->vh_info); 79215794Sleres if (off > VVMTU) { 79338986Skarels vvlog(LOG_DEBUG, 79438986Skarels "vv%d: off > VVMTU, off = %d, vvicsr = %b\n", 79538986Skarels unit, off, 0xffff&(addr->vvicsr), VV_IBITS); 7967640Ssam goto dropit; 79715794Sleres } 79826903Sjas vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *)); 79926950Sjas resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *))); 80015794Sleres if (off + resid > len) { 80138986Skarels vvlog(LOG_DEBUG, "vv%d: trailer packet too short\n", 80238986Skarels unit); 80338986Skarels vvlog(LOG_DEBUG, 80438986Skarels "vv%d: off = %d, resid = %d, vvicsr = %b\n", 80538986Skarels unit, off, resid, 0xffff&(addr->vvicsr), VV_IBITS); 8067640Ssam goto dropit; 80715794Sleres } 8087640Ssam len = off + resid; 80911209Ssam } else 8107640Ssam off = 0; 81120997Skarels 81215794Sleres if (len == 0) { 81338986Skarels vvlog(LOG_DEBUG, "vv%d: len is zero, vvicsr = %b\n", unit, 81415794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 8157640Ssam goto dropit; 81615794Sleres } 81720997Skarels 81824793Skarels m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if); 81915794Sleres if (m == NULL) { 82038986Skarels vvlog(LOG_DEBUG, "vv%d: if_rubaget() failed, vvicsr = %b\n", 82138986Skarels unit, 0xffff&(addr->vvicsr), VV_IBITS); 8227640Ssam goto dropit; 82315794Sleres } 82439201Ssklower vs->vs_if.if_ibytes += m->m_pkthdr.len; 82539201Ssklower if (vv->vh_dhost == VV_BROADCAST) { 82639201Ssklower m->m_flags |= M_BCAST; 82739201Ssklower vs->vs_if.if_imcasts++; 8287640Ssam } 82915794Sleres /* Keep track of source address of this packet */ 83015794Sleres vs->vs_lastr = vv->vh_shost; 83120997Skarels 83211192Ssam /* 83315764Sleres * Demultiplex on packet type 83411192Ssam */ 8357024Ssam switch (vv->vh_type) { 83611192Ssam 8377024Ssam #ifdef INET 8387024Ssam case RING_IP: 8397024Ssam schednetisr(NETISR_IP); 8407024Ssam inq = &ipintrq; 8417024Ssam break; 8427024Ssam #endif 8437024Ssam default: 84438986Skarels vvlog(LOG_DEBUG, "vv%d: unknown pkt type 0x%x\n", 84538986Skarels unit, vv->vh_type); 8467640Ssam m_freem(m); 84739201Ssklower vs->vs_if.if_noproto++; 8487024Ssam goto setup; 8497024Ssam } 85015794Sleres s = splimp(); 8517640Ssam if (IF_QFULL(inq)) { 8527640Ssam IF_DROP(inq); 8537640Ssam m_freem(m); 85439201Ssklower vs->vs_if.if_iqdrops++; 85511209Ssam } else 8567640Ssam IF_ENQUEUE(inq, m); 85715794Sleres splx(s); 8587024Ssam /* 85915764Sleres * Reset for the next packet. 8607024Ssam */ 86115764Sleres setup: 86235805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 86335805Skarels addr->vviba = (u_short) ubaaddr; 86435805Skarels addr->vviea = (u_short) (ubaaddr >> 16); 86520997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 86620997Skarels addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB; 86715764Sleres return; 86811192Ssam 86911192Ssam /* 87011209Ssam * Drop packet on floor -- count them!! 87111192Ssam */ 8727640Ssam dropit: 8737640Ssam vs->vs_if.if_ierrors++; 8747640Ssam goto setup; 8757024Ssam } 8767024Ssam 8777024Ssam /* 87820997Skarels * proNET output routine. 8797024Ssam * Encapsulate a packet of type family for the local net. 8807024Ssam * Use trailer local net encapsulation if enough data in first 8817024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 8827024Ssam */ 8837024Ssam vvoutput(ifp, m0, dst) 8847024Ssam struct ifnet *ifp; 8857024Ssam struct mbuf *m0; 8867024Ssam struct sockaddr *dst; 8877024Ssam { 88816581Skarels register struct mbuf *m; 8897024Ssam register struct vv_header *vv; 8907640Ssam register int off; 89116581Skarels register int unit; 89216581Skarels register struct vvreg *addr; 89316581Skarels register struct vv_softc *vs; 89416581Skarels register int s; 89516581Skarels int type, dest, error; 8967024Ssam 89716581Skarels m = m0; 89816581Skarels unit = ifp->if_unit; 89938986Skarels if ((ifp->if_flags & IFF_UP) == 0) 90038986Skarels return (ENETDOWN); 90116581Skarels addr = (struct vvreg *)vvinfo[unit]->ui_addr; 90216581Skarels vs = &vv_softc[unit]; 90320997Skarels 90416581Skarels /* 90520997Skarels * Check to see if the input side has wedged due the UBA 90620997Skarels * vectoring through 0. 90716581Skarels * 90816581Skarels * We are lower than device ipl when we enter this routine, 90916581Skarels * so if the interface is ready with an input packet then 91016581Skarels * an input interrupt must have slipped through the cracks. 91116581Skarels * 91216581Skarels * Avoid the race with an input interrupt by watching to see 91316581Skarels * if any packets come in. 91416581Skarels */ 91516581Skarels s = vs->vs_if.if_ipackets; 91616581Skarels if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) { 91738986Skarels log(LOG_ERR, "vv%d: lost a receive interrupt, icsr = %b\n", 91816581Skarels unit, 0xffff&(addr->vvicsr), VV_IBITS); 91916581Skarels s = splimp(); 92016581Skarels vvrint(unit); 92116581Skarels splx(s); 92216581Skarels } 92316581Skarels 9247024Ssam switch (dst->sa_family) { 92511192Ssam 9267024Ssam #ifdef INET 92715764Sleres case AF_INET: 92821779Skarels if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) 92921779Skarels dest = VV_BROADCAST; 93021779Skarels else 93121779Skarels dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr); 93220997Skarels #ifdef LOOPBACK 93321779Skarels if (dest == vs->vs_host && (loif.if_flags & IFF_UP)) 93421779Skarels return (looutput(&loif, m0, dst)); 93520997Skarels #endif LOOPBACK 93621779Skarels if (dest >= 0x100) { 9377640Ssam error = EPERM; 9387640Ssam goto bad; 9397640Ssam } 9407640Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 94120997Skarels /* 94220997Skarels * Trailerize, if the configuration allows it. 94320997Skarels * TODO: Need per host negotiation. 94420997Skarels */ 94513090Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 94613090Ssam if (off > 0 && (off & 0x1ff) == 0 && 94739201Ssklower m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { 94826950Sjas type = RING_TRAILER; 94939201Ssklower m->m_data -= 2 * sizeof (u_short); 9507640Ssam m->m_len += 2 * sizeof (u_short); 95128954Skarels *mtod(m, u_short *) = htons((short)RING_IP); 95228954Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 9537640Ssam goto gottrailertype; 9547640Ssam } 9557024Ssam type = RING_IP; 9567024Ssam off = 0; 9577024Ssam goto gottype; 9587024Ssam #endif 9597024Ssam default: 96016581Skarels printf("vv%d: can't handle af%d\n", unit, dst->sa_family); 9617640Ssam error = EAFNOSUPPORT; 9627640Ssam goto bad; 9637024Ssam } 9647024Ssam 9657024Ssam gottrailertype: 9667024Ssam /* 9677024Ssam * Packet to be sent as trailer: move first packet 9687024Ssam * (control information) to end of chain. 9697024Ssam */ 9707024Ssam while (m->m_next) 9717024Ssam m = m->m_next; 9727024Ssam m->m_next = m0; 9737024Ssam m = m0->m_next; 9747024Ssam m0->m_next = 0; 9757024Ssam m0 = m; 9767024Ssam gottype: 9777024Ssam /* 9787024Ssam * Add local net header. If no space in first mbuf, 9797024Ssam * allocate another. 9807024Ssam */ 98139201Ssklower M_PREPEND(m, sizeof (struct vv_header), M_DONTWAIT); 98239201Ssklower if (m == 0) { 98339201Ssklower error = ENOBUFS; 98439201Ssklower goto bad; 9857024Ssam } 9867024Ssam vv = mtod(m, struct vv_header *); 98721779Skarels vv->vh_shost = vs->vs_host; 98821779Skarels vv->vh_dhost = dest; 9897024Ssam vv->vh_version = RING_VERSION; 9907024Ssam vv->vh_type = type; 99128954Skarels vv->vh_info = htons((u_short)off); 99211192Ssam vvtracehdr("vo", vv); 9937024Ssam 9947024Ssam /* 9957024Ssam * Queue message on interface, and start output if interface 9967024Ssam * not yet active. 9977024Ssam */ 9987024Ssam s = splimp(); 9997640Ssam if (IF_QFULL(&ifp->if_snd)) { 10007640Ssam IF_DROP(&ifp->if_snd); 10017640Ssam error = ENOBUFS; 10027640Ssam goto qfull; 10037640Ssam } 10047024Ssam IF_ENQUEUE(&ifp->if_snd, m); 100516581Skarels if (vs->vs_oactive == 0) 100616581Skarels vvstart(unit); 10077024Ssam splx(s); 10087640Ssam return (0); 10097640Ssam qfull: 10107640Ssam m0 = m; 10117640Ssam splx(s); 10127640Ssam bad: 10137640Ssam m_freem(m0); 10147640Ssam return(error); 10157024Ssam } 10167024Ssam 10177024Ssam /* 101813057Ssam * Process an ioctl request. 101913057Ssam */ 102013057Ssam vvioctl(ifp, cmd, data) 102113057Ssam register struct ifnet *ifp; 102213057Ssam int cmd; 102313057Ssam caddr_t data; 102413057Ssam { 102538986Skarels register struct vv_softc *vs = &vv_softc[ifp->if_unit]; 102621779Skarels struct ifaddr *ifa = (struct ifaddr *) data; 102738986Skarels struct vvreg *addr = (struct vvreg *)(vvinfo[ifp->if_unit]); 102821779Skarels int s = splimp(), error = 0; 102913057Ssam 103013057Ssam switch (cmd) { 103113057Ssam 103213057Ssam case SIOCSIFADDR: 103338986Skarels if ((vs->vs_flags & VS_RUNNING) == 0) 103438986Skarels vvinit(ifp->if_unit, 1); 103526903Sjas /* 103626903Sjas * Did self-test succeed? 103726903Sjas */ 103826903Sjas if ((ifp->if_flags & IFF_UP) == 0) 103926903Sjas error = ENETDOWN; 104036085Skarels else { 104136085Skarels /* 104236085Skarels * Attempt to check agreement of protocol address 104336085Skarels * and board address. 104436085Skarels */ 104539201Ssklower switch (ifa->ifa_addr->sa_family) { 104636085Skarels case AF_INET: 104736085Skarels if ((in_lnaof(IA_SIN(ifa)->sin_addr) & 0xff) != 104838986Skarels vs->vs_host) 104936085Skarels error = EADDRNOTAVAIL; 105036085Skarels break; 105136085Skarels } 105221779Skarels } 105313057Ssam break; 105413057Ssam 105538986Skarels case SIOCSIFFLAGS: 105638986Skarels if ((ifp->if_flags & IFF_UP) == 0 && 105738986Skarels vs->vs_flags & VS_RUNNING) { 105838986Skarels addr->vvicsr = VV_RST; 105938986Skarels addr->vvocsr = VV_RST; 106038986Skarels vs->vs_flags &= ~VS_RUNNING; 106138986Skarels } else if (ifp->if_flags & IFF_UP && 106238986Skarels (vs->vs_flags & VS_RUNNING) == 0) 106338986Skarels vvinit(ifp->if_unit, 1); 106438986Skarels break; 106538986Skarels 106613057Ssam default: 106713057Ssam error = EINVAL; 106838986Skarels break; 106913057Ssam } 107013057Ssam splx(s); 107121779Skarels return (error); 107213057Ssam } 107325190Skarels 107425190Skarels /* 107525190Skarels * vvprt_hdr(s, v) print the local net header in "v" 107625190Skarels * with title is "s" 107725190Skarels */ 107825190Skarels vvprt_hdr(s, v) 107925190Skarels char *s; 108025190Skarels register struct vv_header *v; 108125190Skarels { 108225190Skarels printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 108325190Skarels s, 108425190Skarels 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 108525190Skarels 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 108625190Skarels 0xffff & (int)(v->vh_info)); 108725190Skarels } 108826903Sjas #endif NVV 1089