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*53056Ssklower * @(#)if_vv.c 7.11 (Berkeley) 03/25/92
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 */
5045801Sbostic #include "sys/param.h"
5145801Sbostic #include "sys/systm.h"
5245801Sbostic #include "sys/mbuf.h"
5345801Sbostic #include "sys/buf.h"
5445801Sbostic #include "sys/time.h"
5545801Sbostic #include "sys/kernel.h"
5645801Sbostic #include "sys/protosw.h"
5745801Sbostic #include "sys/socket.h"
5845801Sbostic #include "sys/syslog.h"
5945801Sbostic #include "sys/vmmac.h"
6045801Sbostic #include "sys/errno.h"
6145801Sbostic #include "sys/ioctl.h"
628465Sroot
6345801Sbostic #include "net/if.h"
6445801Sbostic #include "net/if_types.h"
6545801Sbostic #include "net/netisr.h"
6645801Sbostic #include "net/route.h"
6724793Skarels
6824793Skarels #ifdef INET
6945801Sbostic #include "netinet/in.h"
7045801Sbostic #include "netinet/in_systm.h"
7145801Sbostic #include "netinet/in_var.h"
7245801Sbostic #include "netinet/ip.h"
7324793Skarels #endif
748465Sroot
7545801Sbostic #include "../include/pte.h"
7645801Sbostic #include "../include/cpu.h"
7745801Sbostic #include "../include/mtpr.h"
7817117Sbloom #include "if_vv.h"
7917117Sbloom #include "if_uba.h"
8045801Sbostic #include "../uba/ubareg.h"
8145801Sbostic #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 */
vvprobe(reg,ui)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 */
vvreset(unit,uban)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 */
vvinit(unit,cansleep)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
vvidentify(unit)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 */
vvstart(dev)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 */
vvxint(unit)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 */
vvwatchdog(unit)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 */
vvrint(unit)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);
973*53056Ssklower if (m == 0)
974*53056Ssklower return (ENOBUFS);
9757024Ssam vv = mtod(m, struct vv_header *);
97621779Skarels vv->vh_shost = vs->vs_host;
97721779Skarels vv->vh_dhost = dest;
9787024Ssam vv->vh_version = RING_VERSION;
9797024Ssam vv->vh_type = type;
98028954Skarels vv->vh_info = htons((u_short)off);
98111192Ssam vvtracehdr("vo", vv);
9827024Ssam
9837024Ssam /*
9847024Ssam * Queue message on interface, and start output if interface
9857024Ssam * not yet active.
9867024Ssam */
9877024Ssam s = splimp();
9887640Ssam if (IF_QFULL(&ifp->if_snd)) {
9897640Ssam IF_DROP(&ifp->if_snd);
9907640Ssam error = ENOBUFS;
9917640Ssam goto qfull;
9927640Ssam }
9937024Ssam IF_ENQUEUE(&ifp->if_snd, m);
99416581Skarels if (vs->vs_oactive == 0)
99516581Skarels vvstart(unit);
9967024Ssam splx(s);
9977640Ssam return (0);
9987640Ssam qfull:
9997640Ssam m0 = m;
10007640Ssam splx(s);
10017640Ssam bad:
10027640Ssam m_freem(m0);
10037640Ssam return(error);
10047024Ssam }
10057024Ssam
10067024Ssam /*
100713057Ssam * Process an ioctl request.
100813057Ssam */
vvioctl(ifp,cmd,data)100913057Ssam vvioctl(ifp, cmd, data)
101013057Ssam register struct ifnet *ifp;
101113057Ssam int cmd;
101213057Ssam caddr_t data;
101313057Ssam {
101438986Skarels register struct vv_softc *vs = &vv_softc[ifp->if_unit];
101521779Skarels struct ifaddr *ifa = (struct ifaddr *) data;
101638986Skarels struct vvreg *addr = (struct vvreg *)(vvinfo[ifp->if_unit]);
101721779Skarels int s = splimp(), error = 0;
101813057Ssam
101913057Ssam switch (cmd) {
102013057Ssam
102113057Ssam case SIOCSIFADDR:
102238986Skarels if ((vs->vs_flags & VS_RUNNING) == 0)
102338986Skarels vvinit(ifp->if_unit, 1);
102426903Sjas /*
102526903Sjas * Did self-test succeed?
102626903Sjas */
102726903Sjas if ((ifp->if_flags & IFF_UP) == 0)
102826903Sjas error = ENETDOWN;
102936085Skarels else {
103036085Skarels /*
103136085Skarels * Attempt to check agreement of protocol address
103236085Skarels * and board address.
103336085Skarels */
103439201Ssklower switch (ifa->ifa_addr->sa_family) {
103536085Skarels case AF_INET:
103636085Skarels if ((in_lnaof(IA_SIN(ifa)->sin_addr) & 0xff) !=
103738986Skarels vs->vs_host)
103836085Skarels error = EADDRNOTAVAIL;
103936085Skarels break;
104036085Skarels }
104121779Skarels }
104213057Ssam break;
104313057Ssam
104438986Skarels case SIOCSIFFLAGS:
104538986Skarels if ((ifp->if_flags & IFF_UP) == 0 &&
104638986Skarels vs->vs_flags & VS_RUNNING) {
104738986Skarels addr->vvicsr = VV_RST;
104838986Skarels addr->vvocsr = VV_RST;
104938986Skarels vs->vs_flags &= ~VS_RUNNING;
105038986Skarels } else if (ifp->if_flags & IFF_UP &&
105138986Skarels (vs->vs_flags & VS_RUNNING) == 0)
105238986Skarels vvinit(ifp->if_unit, 1);
105338986Skarels break;
105438986Skarels
105513057Ssam default:
105613057Ssam error = EINVAL;
105738986Skarels break;
105813057Ssam }
105913057Ssam splx(s);
106021779Skarels return (error);
106113057Ssam }
106225190Skarels
106325190Skarels /*
106425190Skarels * vvprt_hdr(s, v) print the local net header in "v"
106525190Skarels * with title is "s"
106625190Skarels */
vvprt_hdr(s,v)106725190Skarels vvprt_hdr(s, v)
106825190Skarels char *s;
106925190Skarels register struct vv_header *v;
107025190Skarels {
107125190Skarels printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
107225190Skarels s,
107325190Skarels 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
107425190Skarels 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
107525190Skarels 0xffff & (int)(v->vh_info));
107625190Skarels }
107726903Sjas #endif NVV
1078