123305Smckusick /* 236085Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 335328Sbostic * All rights reserved. 423305Smckusick * 544564Sbostic * %sccs.include.redist.c% 635328Sbostic * 7*45801Sbostic * @(#)if_vv.c 7.10 (Berkeley) 12/16/90 823305Smckusick */ 97024Ssam 109799Ssam #include "vv.h" 1125275Sbloom #if NVV > 0 1211192Ssam 137024Ssam /* 1435805Skarels * Proteon ProNET-10 and ProNET-80 token ring driver. 1520997Skarels * The name of this device driver derives from the old MIT 1620997Skarels * name of V2LNI for the proNET hardware, would would abbreviate 1735805Skarels * to "v2", but this won't work right in config. Thus the name is "vv". 1811192Ssam * 1935805Skarels * This driver is compatible with the Unibus ProNET 10 megabit and 2020997Skarels * 80 megabit token ring interfaces (models p1000 and p1080). 2126903Sjas * A unit may be marked as 80 megabit using "flags 1" in the 2226903Sjas * config file. 2320997Skarels * 2435805Skarels * This driver is also compatible with the Q-bus ProNET 10 megabit and 2535805Skarels * 80 megabit token ring interfaces (models p1100 and p1180), but 2635805Skarels * only on a MicroVAX-II or MicroVAX-III. No attempt is made to 2735805Skarels * support the MicroVAX-I. 2835805Skarels * 2926950Sjas * TRAILERS: This driver has a new implementation of trailers that 3026950Sjas * is at least a tolerable neighbor on the ring. The offset is not 3126950Sjas * stored in the protocol type, but instead only in the vh_info 3226950Sjas * field. Also, the vh_info field, and the two shorts before the 3326950Sjas * trailing header, are in network byte order, not VAX byte order. 3420997Skarels * 3526950Sjas * Of course, nothing but BSD UNIX supports trailers on ProNET. 3635805Skarels * If you need interoperability with anything else (like the p4200), 3735805Skarels * turn off trailers using the -trailers option to /etc/ifconfig! 3826950Sjas * 3926903Sjas * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001) 4020997Skarels * have a serial number >= 040, which is about March, 1982. Older 4126903Sjas * HSBUs do not carry across 64kbyte boundaries. They can be supported 4226903Sjas * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization 4326903Sjas * in vvattach(). 4426903Sjas * 4526903Sjas * The old warning about use without Wire Centers applies only to CTL 4626903Sjas * (p1002) cards with serial <= 057, which have not received ECO 176-743, 4726903Sjas * which was implemented in March, 1982. Most such CTLs have received 4826903Sjas * this ECO. 497024Ssam */ 50*45801Sbostic #include "sys/param.h" 51*45801Sbostic #include "sys/systm.h" 52*45801Sbostic #include "sys/mbuf.h" 53*45801Sbostic #include "sys/buf.h" 54*45801Sbostic #include "sys/time.h" 55*45801Sbostic #include "sys/kernel.h" 56*45801Sbostic #include "sys/protosw.h" 57*45801Sbostic #include "sys/socket.h" 58*45801Sbostic #include "sys/syslog.h" 59*45801Sbostic #include "sys/vmmac.h" 60*45801Sbostic #include "sys/errno.h" 61*45801Sbostic #include "sys/ioctl.h" 628465Sroot 63*45801Sbostic #include "net/if.h" 64*45801Sbostic #include "net/if_types.h" 65*45801Sbostic #include "net/netisr.h" 66*45801Sbostic #include "net/route.h" 6724793Skarels 6824793Skarels #ifdef INET 69*45801Sbostic #include "netinet/in.h" 70*45801Sbostic #include "netinet/in_systm.h" 71*45801Sbostic #include "netinet/in_var.h" 72*45801Sbostic #include "netinet/ip.h" 7324793Skarels #endif 748465Sroot 75*45801Sbostic #include "../include/pte.h" 76*45801Sbostic #include "../include/cpu.h" 77*45801Sbostic #include "../include/mtpr.h" 7817117Sbloom #include "if_vv.h" 7917117Sbloom #include "if_uba.h" 80*45801Sbostic #include "../uba/ubareg.h" 81*45801Sbostic #include "../uba/ubavar.h" 827024Ssam 837024Ssam /* 8420997Skarels * maximum transmission unit definition -- 8535805Skarels * you can set VVMTU at anything from 576 to 2036. 8620997Skarels * 1536 is a popular "large" value, because it is a multiple 8720997Skarels * of 512, which the trailer scheme likes. 8835805Skarels * The absolute maximum size is 2036, which is enforced. 8920997Skarels */ 9020997Skarels 9135805Skarels #define VVMTU (2036) 9220997Skarels 9335805Skarels #define VVMRU (VVMTU + (2 * sizeof(u_short))) 9420997Skarels #define VVBUFSIZE (VVMRU + sizeof(struct vv_header)) 9535805Skarels #if VVMTU>2036 9620997Skarels #undef VVMTU 9720997Skarels #undef VVMRU 9820997Skarels #undef VVBUFSIZE 9920997Skarels #define VVBUFSIZE (2046) 10020997Skarels #define VVMRU (VVBUFSIZE - sizeof (struct vv_header)) 10135805Skarels #define VVMTU (VVMRU - (2 * sizeof(u_short))) 1027024Ssam #endif 1037024Ssam 10420997Skarels /* 10520997Skarels * debugging and tracing stuff 10620997Skarels */ 10716581Skarels int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */ 1087640Ssam 10920997Skarels #define vvtracehdr if (vv_tracehdr) vvprt_hdr 11038986Skarels #define vvlog if (vs->vs_if.if_flags & IFF_DEBUG) log 11111192Ssam 11220997Skarels /* 11320997Skarels * externals, types, etc. 11420997Skarels */ 11516581Skarels int vvprobe(), vvattach(), vvreset(), vvinit(); 11616581Skarels int vvidentify(), vvstart(), vvxint(), vvwatchdog(); 11726394Skarels int vvrint(), vvoutput(), vvioctl(); 1187024Ssam struct uba_device *vvinfo[NVV]; 1197024Ssam u_short vvstd[] = { 0 }; 1207024Ssam struct uba_driver vvdriver = 1217024Ssam { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 1227024Ssam #define VVUNIT(x) minor(x) 1237024Ssam 12420997Skarels #define LOOPBACK /* use loopback for packets meant for us */ 12520997Skarels #ifdef LOOPBACK 12620997Skarels extern struct ifnet loif; 12720997Skarels #endif 12820997Skarels 12938986Skarels extern wakeup(); 13038986Skarels 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 */ 16036085Skarels short vs_ipl; /* interrupt priority on Q-bus */ 16138986Skarels short vs_flags; /* board state: */ 16238986Skarels #define VS_RUNNING 0x01 /* board has been initialized */ 16338986Skarels #define VS_INIT 0x02 /* board being initialized */ 1647024Ssam } vv_softc[NVV]; 1657024Ssam 16638986Skarels #define NOHOST 0xff /* illegal host number */ 16726311Skarels 16820997Skarels /* 16920997Skarels * probe the interface to see that the registers exist, and then 17020997Skarels * cause an interrupt to find its vector 17120997Skarels */ 17236085Skarels vvprobe(reg, ui) 1737024Ssam caddr_t reg; 17436085Skarels struct uba_device *ui; 1757024Ssam { 1767024Ssam register int br, cvec; 17716581Skarels register struct vvreg *addr; 1787024Ssam 1797024Ssam #ifdef lint 18015764Sleres br = 0; cvec = br; br = cvec; 1817024Ssam #endif 18216581Skarels addr = (struct vvreg *)reg; 18320997Skarels 1847024Ssam /* reset interface, enable, and wait till dust settles */ 18536085Skarels #ifdef QBA 18636085Skarels (void) spl6(); 18736085Skarels #endif 1887024Ssam addr->vvicsr = VV_RST; 1897024Ssam addr->vvocsr = VV_RST; 19015764Sleres DELAY(100000); 19120997Skarels 1927024Ssam /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 1937024Ssam addr->vvoba = 0; /* low 16 bits */ 1947024Ssam addr->vvoea = 0; /* extended bits */ 1957024Ssam addr->vvowc = -1; /* for 1 word */ 19620997Skarels addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */ 1977024Ssam DELAY(100000); 19836085Skarels #ifdef QBA 19936085Skarels vv_softc[ui->ui_unit].vs_ipl = br = qbgetpri(); 20036085Skarels #endif 20120997Skarels addr->vvocsr = VV_RST; /* clear out the CSR */ 2027024Ssam if (cvec && cvec != 0x200) 20315764Sleres cvec -= 4; /* backup so vector => receive */ 20436085Skarels return (sizeof(struct vvreg)); 2057024Ssam } 2067024Ssam 2077024Ssam /* 2087024Ssam * Interface exists: make available by filling in network interface 2097024Ssam * record. System will initialize the interface when it is ready 2107024Ssam * to accept packets. 2117024Ssam */ 2127024Ssam vvattach(ui) 2137024Ssam struct uba_device *ui; 2147024Ssam { 21515764Sleres register struct vv_softc *vs; 2167024Ssam 21715764Sleres vs = &vv_softc[ui->ui_unit]; 2187024Ssam vs->vs_if.if_unit = ui->ui_unit; 2197024Ssam vs->vs_if.if_name = "vv"; 2207024Ssam vs->vs_if.if_mtu = VVMTU; 22121779Skarels vs->vs_if.if_flags = IFF_BROADCAST; 2227024Ssam vs->vs_if.if_init = vvinit; 22313057Ssam vs->vs_if.if_ioctl = vvioctl; 2247024Ssam vs->vs_if.if_output = vvoutput; 22511209Ssam vs->vs_if.if_reset = vvreset; 22615794Sleres vs->vs_if.if_timer = 0; 22715794Sleres vs->vs_if.if_watchdog = vvwatchdog; 22826201Skarels vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP; 22926903Sjas 23026903Sjas /* use flag to determine if this is proNET-80 */ 23139201Ssklower if (vs->vs_is80 = (short)(ui->ui_flags & 01)) { 23239201Ssklower vs->vs_if.if_type = IFT_P80; 23339201Ssklower vs->vs_if.if_baudrate = 80 * 1024 * 1024; 23439201Ssklower } else { 23539201Ssklower vs->vs_if.if_type = IFT_P10; 23639201Ssklower vs->vs_if.if_baudrate = 10 * 1024 * 1024; 23739201Ssklower } 23838986Skarels vs->vs_host = NOHOST; 23926903Sjas 24012354Smo #if defined(VAX750) 24112354Smo /* don't chew up 750 bdp's */ 24212354Smo if (cpu == VAX_750 && ui->ui_unit > 0) 24312354Smo vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 24412354Smo #endif 2457024Ssam if_attach(&vs->vs_if); 2467024Ssam } 2477024Ssam 2487024Ssam /* 2497024Ssam * Reset of interface after UNIBUS reset. 2507024Ssam * If interface is on specified uba, reset its state. 2517024Ssam */ 2527024Ssam vvreset(unit, uban) 2537024Ssam int unit, uban; 2547024Ssam { 2557024Ssam register struct uba_device *ui; 2567024Ssam 2577024Ssam if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 2587024Ssam ui->ui_ubanum != uban) 2597024Ssam return; 2607024Ssam printf(" vv%d", unit); 26138986Skarels vv_softc[unit].vs_if.if_flags &= ~IFF_RUNNING; 26238986Skarels vv_softc[unit].vs_flags &= ~VS_RUNNING; 26338986Skarels vvinit(unit, 0); 2647024Ssam } 2657024Ssam 2667024Ssam /* 2677024Ssam * Initialization of interface; clear recorded pending 2687024Ssam * operations, and reinitialize UNIBUS usage. 2697024Ssam */ 27038986Skarels vvinit(unit, cansleep) 27138986Skarels int unit, cansleep; 2727024Ssam { 27315764Sleres register struct vv_softc *vs; 27415764Sleres register struct uba_device *ui; 2757024Ssam register struct vvreg *addr; 27635805Skarels register int ubaaddr, s; 2777024Ssam 27815764Sleres vs = &vv_softc[unit]; 27915764Sleres ui = vvinfo[unit]; 28020997Skarels 28121779Skarels if (vs->vs_if.if_addrlist == (struct ifaddr *)0) 28213057Ssam return; 28320997Skarels 28438986Skarels /* 28538986Skarels * Prevent multiple instances of vvinit 28638986Skarels * from trying simultaneously. 28738986Skarels */ 28838986Skarels while (vs->vs_flags & VS_INIT) { 28938986Skarels if (cansleep) 29040840Ssklower sleep((caddr_t)vs, PZERO); 29138986Skarels else 29238986Skarels return; 29338986Skarels } 29438986Skarels if (vs->vs_flags & VS_RUNNING) 29538986Skarels return; 29638986Skarels vs->vs_flags = VS_INIT; 29738986Skarels 2987640Ssam addr = (struct vvreg *)ui->ui_addr; 29936085Skarels if ((vs->vs_if.if_flags & IFF_RUNNING) == 0 && 30036085Skarels if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 30136085Skarels sizeof (struct vv_header), (int)btoc(VVMRU)) == 0) { 30215794Sleres printf("vv%d: can't initialize, if_ubainit() failed\n", unit); 3037640Ssam vs->vs_if.if_flags &= ~IFF_UP; 30438986Skarels vs->vs_flags = 0; 3057024Ssam return; 3067024Ssam } 30736085Skarels vs->vs_if.if_flags |= IFF_RUNNING; 30820997Skarels 3097024Ssam /* 31015764Sleres * Now that the uba is set up, figure out our address and 31115764Sleres * update complete our host address. 3127640Ssam */ 31338986Skarels if (cansleep) 31438986Skarels vs->vs_host = vvidentify(unit); 31538986Skarels if (vs->vs_host == NOHOST) { 31615794Sleres vs->vs_if.if_flags &= ~IFF_UP; 31738986Skarels vs->vs_flags = 0; 31815794Sleres return; 31915794Sleres } 32038986Skarels vvlog(LOG_DEBUG, "vv%d: host %u\n", unit, vs->vs_host); 32120997Skarels 3227640Ssam /* 32320997Skarels * Reset the interface, and stay in the ring 3247640Ssam */ 32520997Skarels addr->vvocsr = VV_RST; /* take over output */ 32620997Skarels addr->vvocsr = VV_CPB; /* clear packet buffer */ 32720997Skarels addr->vvicsr = VV_RST | VV_HEN; /* take over input, */ 32820997Skarels /* keep relay closed */ 32938986Skarels if (cansleep) { 33038986Skarels timeout(wakeup, (caddr_t)vs, hz/2); 33138986Skarels sleep((caddr_t)vs, PZERO); /* let contacts settle */ 33238986Skarels } else 33338986Skarels DELAY(500000); /* let contacts settle */ 33420997Skarels 33520997Skarels vs->vs_init = 0; /* clear counters, etc. */ 33620997Skarels vs->vs_refused = 0; 33715794Sleres vs->vs_timeouts = 0; 33820997Skarels vs->vs_otimeout = 0; 33920997Skarels vs->vs_ibadf = 0; 34020997Skarels vs->vs_parity = 0; 34115794Sleres vs->vs_lastx = 256; /* an invalid address */ 34215794Sleres vs->vs_lastr = 256; /* an invalid address */ 34320997Skarels 3447640Ssam /* 3457640Ssam * Hang a receive and start any 3467640Ssam * pending writes by faking a transmit complete. 3477640Ssam */ 3487640Ssam s = splimp(); 34935805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 35035805Skarels addr->vviba = (u_short)ubaaddr; 35135805Skarels addr->vviea = (u_short)(ubaaddr >> 16); 35220997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 35320997Skarels addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB; 3547640Ssam vs->vs_oactive = 1; 35536085Skarels vs->vs_if.if_flags |= IFF_UP; 35638986Skarels vs->vs_flags = VS_RUNNING; /* clear VS_INIT */ 35738986Skarels wakeup((caddr_t)vs); 3587640Ssam vvxint(unit); 3597640Ssam splx(s); 3607640Ssam } 3617640Ssam 3627640Ssam /* 36320997Skarels * Do a moderately thorough self-test in all three modes. Mostly 36420997Skarels * to keeps defective nodes off the ring, rather than to be especially 36520997Skarels * thorough. The key issue is to detect any cable breaks before joining 36620997Skarels * the ring. Return our node address on success, return -1 on failure. 36720997Skarels * 3687640Ssam */ 36920997Skarels 37020997Skarels /* the three self-test modes */ 37120997Skarels static u_short vv_modes[] = { 37220997Skarels VV_STE|VV_LPB, /* digital loopback */ 37320997Skarels VV_STE, /* analog loopback */ 37420997Skarels VV_HEN /* network mode */ 37520997Skarels }; 37620997Skarels 37711209Ssam vvidentify(unit) 37813057Ssam int unit; 37911209Ssam { 38015764Sleres register struct vv_softc *vs; 38115764Sleres register struct uba_device *ui; 3827640Ssam register struct vvreg *addr; 38316581Skarels register struct mbuf *m; 38416581Skarels register struct vv_header *v; 38535805Skarels register int ubaaddr; 38620997Skarels register int i, successes, failures, waitcount; 38726311Skarels u_short shost = NOHOST; 3887640Ssam 38920997Skarels vs = &vv_softc[unit]; 39020997Skarels ui = vvinfo[unit]; 39120997Skarels addr = (struct vvreg *)ui->ui_addr; 39220997Skarels 3937640Ssam /* 3947024Ssam * Build a multicast message to identify our address 39520997Skarels * We need do this only once, since nobody else is about to use 39620997Skarels * the intermediate transmit buffer (ifu_w.ifrw_addr) that 39720997Skarels * if_ubainit() aquired for us. 3987024Ssam */ 39939201Ssklower MGETHDR(m, M_DONTWAIT, MT_HEADER); 40015794Sleres if (m == NULL) { 40115794Sleres printf("vv%d: can't initialize, m_get() failed\n", unit); 40238986Skarels return (NOHOST); 40315794Sleres } 40439201Ssklower m->m_pkthdr.len = m->m_len = sizeof(struct vv_header); 4057024Ssam v = mtod(m, struct vv_header *); 40611192Ssam v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 4077024Ssam v->vh_shost = 0; /* will be overwritten with ours */ 4087024Ssam v->vh_version = RING_VERSION; 40920997Skarels v->vh_type = RING_DIAGNOSTICS; 4107024Ssam v->vh_info = 0; 41120997Skarels /* map xmit message into uba, copying to intermediate buffer */ 41220997Skarels vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 41320997Skarels 4147024Ssam /* 41520997Skarels * For each of the modes (digital, analog, network), go through 41620997Skarels * a self-test that requires me to send VVIDENTSUCC good packets 41720997Skarels * in VVIDENTRETRY attempts. Use broadcast destination to find out 41820997Skarels * who I am, then use this as my address to check my address match 41920997Skarels * logic. Only data checked is the vh_type field. 4207024Ssam */ 4217640Ssam 42220997Skarels for (i = 0; i < 3; i++) { 42320997Skarels successes = 0; /* clear successes for this mode */ 42420997Skarels failures = 0; /* and clear failures, too */ 4257640Ssam 42620997Skarels /* take over device, and leave ring */ 42720997Skarels addr->vvicsr = VV_RST; 42820997Skarels addr->vvocsr = VV_RST; 42920997Skarels addr->vvicsr = vv_modes[i]; /* test mode */ 43020997Skarels 43120997Skarels /* 43220997Skarels * let the flag and token timers pop so that the init ring bit 43320997Skarels * will be allowed to work, by waiting about 1 second 43420997Skarels */ 43538986Skarels timeout(wakeup, (caddr_t)vs, hz); 43638986Skarels sleep((caddr_t)vs, PZERO); 43720997Skarels 43820997Skarels /* 43920997Skarels * retry loop 44020997Skarels */ 44120997Skarels while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY)) 44220997Skarels { 44320997Skarels /* start a receive */ 44435805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 44520997Skarels addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */ 44635805Skarels addr->vviba = (u_short) ubaaddr; 44735805Skarels addr->vviea = (u_short) (ubaaddr >> 16); 44820997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 44920997Skarels addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB; 45020997Skarels 45138986Skarels #ifdef notdef 45220997Skarels /* purge stale data from BDP */ 45320997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 45420997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 45520997Skarels vs->vs_ifuba.ifu_w.ifrw_bdp); 45638986Skarels #endif 45720997Skarels 45820997Skarels /* do a transmit */ 45935805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info); 46020997Skarels addr->vvocsr = VV_RST; /* abort last try */ 46135805Skarels addr->vvoba = (u_short) ubaaddr; 46235805Skarels addr->vvoea = (u_short) (ubaaddr >> 16); 46320997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); 46420997Skarels addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 46520997Skarels 46620997Skarels /* poll receive side for completion */ 46720997Skarels DELAY(10000); /* give it a chance */ 46820997Skarels for (waitcount = 0; waitcount < 10; waitcount++) { 46920997Skarels if (addr->vvicsr & VV_RDY) 47020997Skarels goto gotit; 47120997Skarels DELAY(1000); 47220997Skarels } 47320997Skarels failures++; /* no luck */ 47411209Ssam continue; 47520997Skarels 47620997Skarels gotit: /* we got something--is it any good? */ 47720997Skarels if ((addr->vvicsr & (VVRERR|VV_LDE)) || 47821779Skarels (addr->vvocsr & (VVXERR|VV_RFS))) { 47920997Skarels failures++; 48020997Skarels continue; 48120997Skarels } 48220997Skarels 48320997Skarels /* Purge BDP before looking at received packet */ 48420997Skarels if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 48520997Skarels UBAPURGE(vs->vs_ifuba.ifu_uba, 48620997Skarels vs->vs_ifuba.ifu_r.ifrw_bdp); 48738986Skarels #ifdef notdef 48824793Skarels m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 48926394Skarels 0, &vs->vs_if); 49020997Skarels if (m != NULL) 49120997Skarels m_freem(m); 49238986Skarels #endif 49320997Skarels 49420997Skarels v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 49520997Skarels 49620997Skarels /* check message type, catch our node address */ 49720997Skarels if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) { 49826311Skarels if (shost == NOHOST) { 49920997Skarels shost = v->vh_shost & 0xff; 50020997Skarels /* send to ourself now */ 50120997Skarels ((struct vv_header *) 50220997Skarels (vs->vs_ifuba.ifu_r.ifrw_addr)) 50320997Skarels ->vh_dhost = shost; 50420997Skarels } 50520997Skarels successes++; 50626903Sjas } else { 50726903Sjas failures++; 50820997Skarels } 50926903Sjas v->vh_type = 0; /* clear to check again */ 51011192Ssam } 51120997Skarels 51220997Skarels if (failures >= VVIDENTRETRY) 51320997Skarels { 51420997Skarels printf("vv%d: failed self-test after %d tries \ 51520997Skarels in %s mode\n", 51620997Skarels unit, VVIDENTRETRY, i == 0 ? "digital loopback" : 51720997Skarels (i == 1 ? "analog loopback" : "network")); 51820997Skarels printf("vv%d: icsr = %b, ocsr = %b\n", 51920997Skarels unit, 0xffff & addr->vvicsr, VV_IBITS, 52020997Skarels 0xffff & addr->vvocsr, VV_OBITS); 52120997Skarels addr->vvicsr = VV_RST; /* kill the sick board */ 52220997Skarels addr->vvocsr = VV_RST; 52326311Skarels shost = NOHOST; 52420997Skarels goto done; 52520997Skarels } 52611192Ssam } 52720997Skarels 52820997Skarels done: 52920997Skarels /* deallocate mbuf used for send packet (won't be one, anyways) */ 53015794Sleres if (vs->vs_ifuba.ifu_xtofree) { 5317024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 53215794Sleres vs->vs_ifuba.ifu_xtofree = 0; 53315794Sleres } 53420997Skarels 53520997Skarels return(shost); 5367024Ssam } 5377024Ssam 5387024Ssam /* 5397024Ssam * Start or restart output on interface. 54011192Ssam * If interface is active, this is a retransmit, so just 54111192Ssam * restuff registers and go. 5427024Ssam * If interface is not already active, get another datagram 5437024Ssam * to send off of the interface queue, and map it to the interface 5447024Ssam * before starting the output. 5457024Ssam */ 5467024Ssam vvstart(dev) 5477024Ssam dev_t dev; 5487024Ssam { 54916581Skarels register struct uba_device *ui; 55015764Sleres register struct vv_softc *vs; 5517024Ssam register struct vvreg *addr; 55216581Skarels register struct mbuf *m; 55335805Skarels register int unit, ubaaddr, dest, s; 5547024Ssam 55516581Skarels unit = VVUNIT(dev); 55615764Sleres ui = vvinfo[unit]; 55715764Sleres vs = &vv_softc[unit]; 5587024Ssam if (vs->vs_oactive) 5597024Ssam goto restart; 5607024Ssam /* 5617024Ssam * Not already active: dequeue another request 5627024Ssam * and map it to the UNIBUS. If no more requests, 5637024Ssam * just return. 5647024Ssam */ 56515794Sleres s = splimp(); 5667024Ssam IF_DEQUEUE(&vs->vs_if.if_snd, m); 56715794Sleres splx(s); 56811209Ssam if (m == NULL) { 5697024Ssam vs->vs_oactive = 0; 5707024Ssam return; 5717024Ssam } 5727024Ssam dest = mtod(m, struct vv_header *)->vh_dhost; 5737024Ssam vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 5747024Ssam vs->vs_lastx = dest; 57539201Ssklower vs->vs_if.if_obytes += vs->vs_olen; 57639201Ssklower vs->vs_if.if_lastchange = time; 5777024Ssam restart: 5787024Ssam /* 5797024Ssam * Have request mapped to UNIBUS for transmission. 58015794Sleres * Purge any stale data from this BDP, and start the output. 58115794Sleres * 58215794Sleres * Make sure this packet will fit in the interface. 5837024Ssam */ 58420997Skarels if (vs->vs_olen > VVBUFSIZE) { 58520997Skarels printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen); 58611192Ssam panic("vvdriver vs_olen botch"); 58711192Ssam } 58820997Skarels 58920997Skarels vs->vs_if.if_timer = VVTIMEOUT; 59020997Skarels vs->vs_oactive = 1; 59120997Skarels 59220997Skarels /* ship it */ 59336085Skarels #ifdef notdef 5947024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 5957024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 59636085Skarels #endif 5977024Ssam addr = (struct vvreg *)ui->ui_addr; 59835805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info); 59935805Skarels addr->vvoba = (u_short) ubaaddr; 60035805Skarels addr->vvoea = (u_short) (ubaaddr >> 16); 6017024Ssam addr->vvowc = -((vs->vs_olen + 1) >> 1); 60220997Skarels addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */ 60320997Skarels if (addr->vvocsr & VV_NOK) 60420997Skarels vs->vs_init++; /* count ring inits */ 6057024Ssam addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 6067024Ssam } 6077024Ssam 6087024Ssam /* 60920997Skarels * proNET transmit interrupt 6107024Ssam * Start another output if more data to send. 6117024Ssam */ 6127024Ssam vvxint(unit) 6137024Ssam int unit; 6147024Ssam { 61515764Sleres register struct uba_device *ui; 61615764Sleres register struct vv_softc *vs; 6177024Ssam register struct vvreg *addr; 6187024Ssam register int oc; 6197024Ssam 62038986Skarels ui = vvinfo[unit]; 62138986Skarels vs = &vv_softc[unit]; 62236085Skarels #ifdef QBA 62338986Skarels splx(vs->vs_ipl); 62436085Skarels #endif 62515794Sleres vs->vs_if.if_timer = 0; 6267024Ssam addr = (struct vvreg *)ui->ui_addr; 6277024Ssam oc = 0xffff & (addr->vvocsr); 6287024Ssam if (vs->vs_oactive == 0) { 62938986Skarels vvlog(LOG_DEBUG, "vv%d: stray interrupt vvocsr = %b\n", unit, 63015764Sleres oc, VV_OBITS); 6317024Ssam return; 6327024Ssam } 63320997Skarels 63420997Skarels /* 63520997Skarels * we retransmit on soft error 63620997Skarels * TODO: sort retransmits to end of queue if possible! 63720997Skarels */ 63820997Skarels if (oc & (VV_OPT | VV_RFS)) { 63911192Ssam if (vs->vs_tries++ < VVRETRY) { 6407024Ssam if (oc & VV_OPT) 64120997Skarels vs->vs_otimeout++; 64220997Skarels if (oc & VV_RFS) { 64320997Skarels vs->vs_if.if_collisions++; 64420997Skarels vs->vs_refused++; 64520997Skarels } 64611192Ssam vvstart(unit); /* restart this message */ 6477024Ssam return; 6487024Ssam } 6497024Ssam } 6507024Ssam vs->vs_if.if_opackets++; 6517024Ssam vs->vs_oactive = 0; 6527024Ssam vs->vs_tries = 0; 65320997Skarels 6547024Ssam if (oc & VVXERR) { 65539201Ssklower vs->vs_if.if_obytes -= vs->vs_olen; 6567024Ssam vs->vs_if.if_oerrors++; 65738986Skarels vvlog(LOG_ERR, "vv%d: error vvocsr = %b\n", 65838986Skarels unit, 0xffff & oc, VV_OBITS); 6597024Ssam } 6607024Ssam if (vs->vs_ifuba.ifu_xtofree) { 6617024Ssam m_freem(vs->vs_ifuba.ifu_xtofree); 6627024Ssam vs->vs_ifuba.ifu_xtofree = 0; 6637024Ssam } 6647024Ssam vvstart(unit); 6657024Ssam } 6667024Ssam 6677024Ssam /* 66815794Sleres * Transmit watchdog timer routine. 66915794Sleres * This routine gets called when we lose a transmit interrupt. 67015794Sleres * The best we can do is try to restart output. 67115794Sleres */ 67215794Sleres vvwatchdog(unit) 67315794Sleres int unit; 67415794Sleres { 67515794Sleres register struct vv_softc *vs; 67615794Sleres 67715794Sleres vs = &vv_softc[unit]; 67838986Skarels log(LOG_ERR, "vv%d: lost transmit interrupt\n", unit); 67915794Sleres vs->vs_timeouts++; 68015794Sleres vvstart(unit); 68115794Sleres } 68215794Sleres 68315794Sleres /* 68420997Skarels * proNET interface receiver interrupt. 6857024Ssam * If input error just drop packet. 68615764Sleres * Otherwise purge input buffered data path and examine 6877024Ssam * packet to determine type. If can't determine length 68815764Sleres * from type, then have to drop packet. Otherwise decapsulate 6897024Ssam * packet based on type and pass to type specific higher-level 6907024Ssam * input routine. 6917024Ssam */ 6927024Ssam vvrint(unit) 6937024Ssam int unit; 6947024Ssam { 69515764Sleres register struct vv_softc *vs; 69616581Skarels register struct vvreg *addr; 6977024Ssam register struct vv_header *vv; 6987024Ssam register struct ifqueue *inq; 69916581Skarels register struct mbuf *m; 70035805Skarels int ubaaddr, len, off, s; 7017640Ssam short resid; 7027024Ssam 70338986Skarels vs = &vv_softc[unit]; 70436085Skarels #ifdef QBA 70538986Skarels splx(vs->vs_ipl); 70636085Skarels #endif 70716581Skarels vs->vs_if.if_ipackets++; 70839201Ssklower vs->vs_if.if_lastchange = time; 70915764Sleres addr = (struct vvreg *)vvinfo[unit]->ui_addr; 71020997Skarels 7117024Ssam /* 71226903Sjas * Purge BDP 7137024Ssam */ 7147024Ssam if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 7157024Ssam UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 71620997Skarels 71720997Skarels /* 71820997Skarels * receive errors? 71920997Skarels */ 7207024Ssam if (addr->vvicsr & VVRERR) { 72138986Skarels vvlog(LOG_INFO, "vv%d: receive error, vvicsr = %b\n", unit, 72220997Skarels 0xffff&(addr->vvicsr), VV_IBITS); 72320997Skarels if (addr->vvicsr & VV_BDF) 72420997Skarels vs->vs_ibadf++; 7257640Ssam goto dropit; 7267024Ssam } 7277640Ssam 7287024Ssam /* 72920997Skarels * parity errors? 73020997Skarels */ 73120997Skarels if (addr->vvicsr & VV_LDE) { 73220997Skarels /* we don't have to clear it because the receive command */ 73320997Skarels /* writes 0 to parity bit */ 73420997Skarels vs->vs_parity++; 73526903Sjas 73620997Skarels /* 73720997Skarels * only on 10 megabit proNET is VV_LDE an end-to-end parity 73820997Skarels * bit. On 80 megabit, it returns to the intended use of 73920997Skarels * node-to-node parity. End-to-end parity errors on 80 megabit 74020997Skarels * give VV_BDF. 74120997Skarels */ 74226903Sjas if (vs->vs_is80 == 0) 74326903Sjas goto dropit; 74420997Skarels } 74520997Skarels 74620997Skarels /* 74720997Skarels * Get packet length from residual word count 7487640Ssam * 7497640Ssam * Compute header offset if trailer protocol 7507640Ssam * 7517640Ssam * Pull packet off interface. Off is nonzero if packet 7527640Ssam * has trailing header; if_rubaget will then force this header 7537640Ssam * information to be at the front. The vh_info field 7547640Ssam * carries the offset to the trailer data in trailer 7557640Ssam * format packets. 7567024Ssam */ 7577640Ssam vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 75811192Ssam vvtracehdr("vi", vv); 75920997Skarels resid = addr->vviwc & 01777; /* only low 10 bits valid */ 7607640Ssam if (resid) 76120997Skarels resid |= 0176000; /* high 6 bits are undefined */ 76220997Skarels len = ((VVBUFSIZE >> 1) + resid) << 1; 7637640Ssam len -= sizeof(struct vv_header); 76420997Skarels 76520997Skarels if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) { 76638986Skarels vvlog(LOG_DEBUG, "vv%d: len too long or short, \ 76720997Skarels len = %d, vvicsr = %b\n", 76815794Sleres unit, len, 0xffff&(addr->vvicsr), VV_IBITS); 7697640Ssam goto dropit; 77015794Sleres } 77120997Skarels 77220997Skarels /* check the protocol header version */ 77320997Skarels if (vv->vh_version != RING_VERSION) { 77438986Skarels vvlog(LOG_DEBUG, "vv%d: bad protocol header version %d\n", 77520997Skarels unit, vv->vh_version & 0xff); 77620997Skarels goto dropit; 77720997Skarels } 77820997Skarels 7797640Ssam #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 78026950Sjas if (vv->vh_type == RING_TRAILER ) { 78128954Skarels off = ntohs((u_short)vv->vh_info); 78215794Sleres if (off > VVMTU) { 78338986Skarels vvlog(LOG_DEBUG, 78438986Skarels "vv%d: off > VVMTU, off = %d, vvicsr = %b\n", 78538986Skarels unit, off, 0xffff&(addr->vvicsr), VV_IBITS); 7867640Ssam goto dropit; 78715794Sleres } 78826903Sjas vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *)); 78926950Sjas resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *))); 79015794Sleres if (off + resid > len) { 79138986Skarels vvlog(LOG_DEBUG, "vv%d: trailer packet too short\n", 79238986Skarels unit); 79338986Skarels vvlog(LOG_DEBUG, 79438986Skarels "vv%d: off = %d, resid = %d, vvicsr = %b\n", 79538986Skarels unit, off, resid, 0xffff&(addr->vvicsr), VV_IBITS); 7967640Ssam goto dropit; 79715794Sleres } 7987640Ssam len = off + resid; 79911209Ssam } else 8007640Ssam off = 0; 80120997Skarels 80215794Sleres if (len == 0) { 80338986Skarels vvlog(LOG_DEBUG, "vv%d: len is zero, vvicsr = %b\n", unit, 80415794Sleres 0xffff&(addr->vvicsr), VV_IBITS); 8057640Ssam goto dropit; 80615794Sleres } 80720997Skarels 80824793Skarels m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if); 80915794Sleres if (m == NULL) { 81038986Skarels vvlog(LOG_DEBUG, "vv%d: if_rubaget() failed, vvicsr = %b\n", 81138986Skarels unit, 0xffff&(addr->vvicsr), VV_IBITS); 8127640Ssam goto dropit; 81315794Sleres } 81439201Ssklower vs->vs_if.if_ibytes += m->m_pkthdr.len; 81539201Ssklower if (vv->vh_dhost == VV_BROADCAST) { 81639201Ssklower m->m_flags |= M_BCAST; 81739201Ssklower vs->vs_if.if_imcasts++; 8187640Ssam } 81915794Sleres /* Keep track of source address of this packet */ 82015794Sleres vs->vs_lastr = vv->vh_shost; 82120997Skarels 82211192Ssam /* 82315764Sleres * Demultiplex on packet type 82411192Ssam */ 8257024Ssam switch (vv->vh_type) { 82611192Ssam 8277024Ssam #ifdef INET 8287024Ssam case RING_IP: 8297024Ssam schednetisr(NETISR_IP); 8307024Ssam inq = &ipintrq; 8317024Ssam break; 8327024Ssam #endif 8337024Ssam default: 83438986Skarels vvlog(LOG_DEBUG, "vv%d: unknown pkt type 0x%x\n", 83538986Skarels unit, vv->vh_type); 8367640Ssam m_freem(m); 83739201Ssklower vs->vs_if.if_noproto++; 8387024Ssam goto setup; 8397024Ssam } 84015794Sleres s = splimp(); 8417640Ssam if (IF_QFULL(inq)) { 8427640Ssam IF_DROP(inq); 8437640Ssam m_freem(m); 84439201Ssklower vs->vs_if.if_iqdrops++; 84511209Ssam } else 8467640Ssam IF_ENQUEUE(inq, m); 84715794Sleres splx(s); 8487024Ssam /* 84915764Sleres * Reset for the next packet. 8507024Ssam */ 85115764Sleres setup: 85235805Skarels ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info); 85335805Skarels addr->vviba = (u_short) ubaaddr; 85435805Skarels addr->vviea = (u_short) (ubaaddr >> 16); 85520997Skarels addr->vviwc = -(VVBUFSIZE) >> 1; 85620997Skarels addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB; 85715764Sleres return; 85811192Ssam 85911192Ssam /* 86011209Ssam * Drop packet on floor -- count them!! 86111192Ssam */ 8627640Ssam dropit: 8637640Ssam vs->vs_if.if_ierrors++; 8647640Ssam goto setup; 8657024Ssam } 8667024Ssam 8677024Ssam /* 86820997Skarels * proNET output routine. 8697024Ssam * Encapsulate a packet of type family for the local net. 8707024Ssam * Use trailer local net encapsulation if enough data in first 8717024Ssam * packet leaves a multiple of 512 bytes of data in remainder. 8727024Ssam */ 87345290Ssklower vvoutput(ifp, m0, dst, rt) 8747024Ssam struct ifnet *ifp; 8757024Ssam struct mbuf *m0; 8767024Ssam struct sockaddr *dst; 87745290Ssklower struct rtentry *rt; 8787024Ssam { 87916581Skarels register struct mbuf *m; 8807024Ssam register struct vv_header *vv; 8817640Ssam register int off; 88216581Skarels register int unit; 88316581Skarels register struct vvreg *addr; 88416581Skarels register struct vv_softc *vs; 88516581Skarels register int s; 88616581Skarels int type, dest, error; 8877024Ssam 88816581Skarels m = m0; 88916581Skarels unit = ifp->if_unit; 89038986Skarels if ((ifp->if_flags & IFF_UP) == 0) 89138986Skarels return (ENETDOWN); 89216581Skarels addr = (struct vvreg *)vvinfo[unit]->ui_addr; 89316581Skarels vs = &vv_softc[unit]; 89420997Skarels 89516581Skarels /* 89620997Skarels * Check to see if the input side has wedged due the UBA 89720997Skarels * vectoring through 0. 89816581Skarels * 89916581Skarels * We are lower than device ipl when we enter this routine, 90016581Skarels * so if the interface is ready with an input packet then 90116581Skarels * an input interrupt must have slipped through the cracks. 90216581Skarels * 90316581Skarels * Avoid the race with an input interrupt by watching to see 90416581Skarels * if any packets come in. 90516581Skarels */ 90616581Skarels s = vs->vs_if.if_ipackets; 90716581Skarels if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) { 90838986Skarels log(LOG_ERR, "vv%d: lost a receive interrupt, icsr = %b\n", 90916581Skarels unit, 0xffff&(addr->vvicsr), VV_IBITS); 91016581Skarels s = splimp(); 91116581Skarels vvrint(unit); 91216581Skarels splx(s); 91316581Skarels } 91416581Skarels 9157024Ssam switch (dst->sa_family) { 91611192Ssam 9177024Ssam #ifdef INET 91815764Sleres case AF_INET: 91921779Skarels if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) 92021779Skarels dest = VV_BROADCAST; 92121779Skarels else 92221779Skarels dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr); 92320997Skarels #ifdef LOOPBACK 92421779Skarels if (dest == vs->vs_host && (loif.if_flags & IFF_UP)) 92545290Ssklower return (looutput(&loif, m0, dst, rt)); 92620997Skarels #endif LOOPBACK 92721779Skarels if (dest >= 0x100) { 9287640Ssam error = EPERM; 9297640Ssam goto bad; 9307640Ssam } 9317640Ssam off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 93220997Skarels /* 93320997Skarels * Trailerize, if the configuration allows it. 93420997Skarels * TODO: Need per host negotiation. 93520997Skarels */ 93613090Ssam if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 93713090Ssam if (off > 0 && (off & 0x1ff) == 0 && 93839201Ssklower m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { 93926950Sjas type = RING_TRAILER; 94039201Ssklower m->m_data -= 2 * sizeof (u_short); 9417640Ssam m->m_len += 2 * sizeof (u_short); 94228954Skarels *mtod(m, u_short *) = htons((short)RING_IP); 94328954Skarels *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 9447640Ssam goto gottrailertype; 9457640Ssam } 9467024Ssam type = RING_IP; 9477024Ssam off = 0; 9487024Ssam goto gottype; 9497024Ssam #endif 9507024Ssam default: 95116581Skarels printf("vv%d: can't handle af%d\n", unit, dst->sa_family); 9527640Ssam error = EAFNOSUPPORT; 9537640Ssam goto bad; 9547024Ssam } 9557024Ssam 9567024Ssam gottrailertype: 9577024Ssam /* 9587024Ssam * Packet to be sent as trailer: move first packet 9597024Ssam * (control information) to end of chain. 9607024Ssam */ 9617024Ssam while (m->m_next) 9627024Ssam m = m->m_next; 9637024Ssam m->m_next = m0; 9647024Ssam m = m0->m_next; 9657024Ssam m0->m_next = 0; 9667024Ssam m0 = m; 9677024Ssam gottype: 9687024Ssam /* 9697024Ssam * Add local net header. If no space in first mbuf, 9707024Ssam * allocate another. 9717024Ssam */ 97239201Ssklower M_PREPEND(m, sizeof (struct vv_header), M_DONTWAIT); 97339201Ssklower if (m == 0) { 97439201Ssklower error = ENOBUFS; 97539201Ssklower goto bad; 9767024Ssam } 9777024Ssam vv = mtod(m, struct vv_header *); 97821779Skarels vv->vh_shost = vs->vs_host; 97921779Skarels vv->vh_dhost = dest; 9807024Ssam vv->vh_version = RING_VERSION; 9817024Ssam vv->vh_type = type; 98228954Skarels vv->vh_info = htons((u_short)off); 98311192Ssam vvtracehdr("vo", vv); 9847024Ssam 9857024Ssam /* 9867024Ssam * Queue message on interface, and start output if interface 9877024Ssam * not yet active. 9887024Ssam */ 9897024Ssam s = splimp(); 9907640Ssam if (IF_QFULL(&ifp->if_snd)) { 9917640Ssam IF_DROP(&ifp->if_snd); 9927640Ssam error = ENOBUFS; 9937640Ssam goto qfull; 9947640Ssam } 9957024Ssam IF_ENQUEUE(&ifp->if_snd, m); 99616581Skarels if (vs->vs_oactive == 0) 99716581Skarels vvstart(unit); 9987024Ssam splx(s); 9997640Ssam return (0); 10007640Ssam qfull: 10017640Ssam m0 = m; 10027640Ssam splx(s); 10037640Ssam bad: 10047640Ssam m_freem(m0); 10057640Ssam return(error); 10067024Ssam } 10077024Ssam 10087024Ssam /* 100913057Ssam * Process an ioctl request. 101013057Ssam */ 101113057Ssam vvioctl(ifp, cmd, data) 101213057Ssam register struct ifnet *ifp; 101313057Ssam int cmd; 101413057Ssam caddr_t data; 101513057Ssam { 101638986Skarels register struct vv_softc *vs = &vv_softc[ifp->if_unit]; 101721779Skarels struct ifaddr *ifa = (struct ifaddr *) data; 101838986Skarels struct vvreg *addr = (struct vvreg *)(vvinfo[ifp->if_unit]); 101921779Skarels int s = splimp(), error = 0; 102013057Ssam 102113057Ssam switch (cmd) { 102213057Ssam 102313057Ssam case SIOCSIFADDR: 102438986Skarels if ((vs->vs_flags & VS_RUNNING) == 0) 102538986Skarels vvinit(ifp->if_unit, 1); 102626903Sjas /* 102726903Sjas * Did self-test succeed? 102826903Sjas */ 102926903Sjas if ((ifp->if_flags & IFF_UP) == 0) 103026903Sjas error = ENETDOWN; 103136085Skarels else { 103236085Skarels /* 103336085Skarels * Attempt to check agreement of protocol address 103436085Skarels * and board address. 103536085Skarels */ 103639201Ssklower switch (ifa->ifa_addr->sa_family) { 103736085Skarels case AF_INET: 103836085Skarels if ((in_lnaof(IA_SIN(ifa)->sin_addr) & 0xff) != 103938986Skarels vs->vs_host) 104036085Skarels error = EADDRNOTAVAIL; 104136085Skarels break; 104236085Skarels } 104321779Skarels } 104413057Ssam break; 104513057Ssam 104638986Skarels case SIOCSIFFLAGS: 104738986Skarels if ((ifp->if_flags & IFF_UP) == 0 && 104838986Skarels vs->vs_flags & VS_RUNNING) { 104938986Skarels addr->vvicsr = VV_RST; 105038986Skarels addr->vvocsr = VV_RST; 105138986Skarels vs->vs_flags &= ~VS_RUNNING; 105238986Skarels } else if (ifp->if_flags & IFF_UP && 105338986Skarels (vs->vs_flags & VS_RUNNING) == 0) 105438986Skarels vvinit(ifp->if_unit, 1); 105538986Skarels break; 105638986Skarels 105713057Ssam default: 105813057Ssam error = EINVAL; 105938986Skarels break; 106013057Ssam } 106113057Ssam splx(s); 106221779Skarels return (error); 106313057Ssam } 106425190Skarels 106525190Skarels /* 106625190Skarels * vvprt_hdr(s, v) print the local net header in "v" 106725190Skarels * with title is "s" 106825190Skarels */ 106925190Skarels vvprt_hdr(s, v) 107025190Skarels char *s; 107125190Skarels register struct vv_header *v; 107225190Skarels { 107325190Skarels printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 107425190Skarels s, 107525190Skarels 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 107625190Skarels 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 107725190Skarels 0xffff & (int)(v->vh_info)); 107825190Skarels } 107926903Sjas #endif NVV 1080