⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_vv.c

📁 open bsd vax module -if function
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1982, 1986, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)if_vv.c	7.11 (Berkeley) 3/25/92 */#include "vv.h"#if NVV > 0/* * Proteon ProNET-10 and ProNET-80 token ring driver. * The name of this device driver derives from the old MIT * name of V2LNI for the proNET hardware, would would abbreviate * to "v2", but this won't work right in config. Thus the name is "vv". * * This driver is compatible with the Unibus ProNET 10 megabit and * 80 megabit token ring interfaces (models p1000 and p1080). * A unit may be marked as 80 megabit using "flags 1" in the * config file. * * This driver is also compatible with the Q-bus ProNET 10 megabit and * 80 megabit token ring interfaces (models p1100 and p1180), but * only on a MicroVAX-II or MicroVAX-III.  No attempt is made to * support the MicroVAX-I. * * TRAILERS: This driver has a new implementation of trailers that * is at least a tolerable neighbor on the ring. The offset is not * stored in the protocol type, but instead only in the vh_info * field. Also, the vh_info field, and the two shorts before the * trailing header, are in network byte order, not VAX byte order. * * Of course, nothing but BSD UNIX supports trailers on ProNET. * If you need interoperability with anything else (like the p4200), * turn off trailers using the -trailers option to /etc/ifconfig! * * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001) * have a serial number >= 040, which is about March, 1982. Older * HSBUs do not carry across 64kbyte boundaries. They can be supported * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization * in vvattach(). * * The old warning about use without Wire Centers applies only to CTL * (p1002) cards with serial <= 057, which have not received ECO 176-743, * which was implemented in March, 1982. Most such CTLs have received * this ECO. */#include "sys/param.h"#include "sys/systm.h"#include "sys/mbuf.h"#include "sys/buf.h"#include "sys/time.h"#include "sys/kernel.h"#include "sys/protosw.h"#include "sys/socket.h"#include "sys/syslog.h"#include "sys/vmmac.h"#include "sys/errno.h"#include "sys/ioctl.h"#include "net/if.h"#include "net/if_types.h"#include "net/netisr.h"#include "net/route.h"#ifdef	INET#include "netinet/in.h"#include "netinet/in_systm.h"#include "netinet/in_var.h"#include "netinet/ip.h"#endif#include "../include/pte.h"#include "../include/cpu.h"#include "../include/mtpr.h"#include "if_vv.h"#include "if_uba.h"#include "../uba/ubareg.h"#include "../uba/ubavar.h"/* *    maximum transmission unit definition -- *        you can set VVMTU at anything from 576 to 2036. *        1536 is a popular "large" value, because it is a multiple *	  of 512, which the trailer scheme likes. *        The absolute maximum size is 2036, which is enforced. */#define VVMTU (2036)#define VVMRU (VVMTU + (2 * sizeof(u_short)))#define VVBUFSIZE (VVMRU + sizeof(struct vv_header))#if VVMTU>2036#undef VVMTU#undef VVMRU#undef VVBUFSIZE#define VVBUFSIZE (2046)#define VVMRU (VVBUFSIZE - sizeof (struct vv_header))#define VVMTU (VVMRU - (2 * sizeof(u_short)))#endif/* *   debugging and tracing stuff */int	vv_tracehdr = 0;	/* 1 => trace headers (slowly!!) */#define vvtracehdr  if (vv_tracehdr) vvprt_hdr#define vvlog    if (vs->vs_if.if_flags & IFF_DEBUG) log/* * externals, types, etc. */int	vvprobe(), vvattach(), vvreset(), vvinit();int	vvidentify(), vvstart(), vvxint(), vvwatchdog();int	vvrint(), vvoutput(), vvioctl();struct	uba_device *vvinfo[NVV];u_short vvstd[] = { 0 };struct	uba_driver vvdriver =	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };#define	VVUNIT(x)	minor(x)#define LOOPBACK		/* use loopback for packets meant for us */#ifdef	LOOPBACKextern struct ifnet loif;#endifextern wakeup();/* * Software status of each interface. * * Each interface is referenced by a network interface structure, * vs_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... * We also have, for each interface, a UBA interface structure, which * contains information about the UNIBUS resources held by the interface: * map registers, buffered data paths, etc.  Information is cached in this * structure for use by the if_uba.c routines in running the interface * efficiently. */struct	vv_softc {	struct	ifnet vs_if;		/* network-visible interface */	struct	ifuba vs_ifuba;		/* UNIBUS resources */	u_short	vs_host;		/* this interface address */	short	vs_oactive;		/* is output active */	short	vs_is80;		/* is 80 megabit version */	short	vs_olen;		/* length of last output */	u_short	vs_lastx;		/* address of last packet sent */	u_short	vs_lastr;		/* address of last packet received */	short	vs_tries;		/* transmit current retry count */	short	vs_init;		/* number of ring inits */	short	vs_refused;		/* number of packets refused */	short	vs_timeouts;		/* number of transmit timeouts */	short	vs_otimeout;		/* number of output timeouts */	short	vs_ibadf;		/* number of input bad formats */	short	vs_parity;		/* number of parity errors on 10 meg, */					/* link data errors on 80 meg */	short	vs_ipl;			/* interrupt priority on Q-bus */	short	vs_flags;		/* board state: */#define	VS_RUNNING	0x01		/* board has been initialized */#define	VS_INIT		0x02		/* board being initialized */} vv_softc[NVV];#define	NOHOST	0xff			/* illegal host number *//* * probe the interface to see that the registers exist, and then * cause an interrupt to find its vector */vvprobe(reg, ui)	caddr_t reg;	struct uba_device *ui;{	register int br, cvec;	register struct vvreg *addr;#ifdef lint	br = 0; cvec = br; br = cvec;#endif	addr = (struct vvreg *)reg;	/* reset interface, enable, and wait till dust settles */#ifdef QBA	(void) spl6();#endif	addr->vvicsr = VV_RST;	addr->vvocsr = VV_RST;	DELAY(100000);	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */	addr->vvoba = 0;		/* low 16 bits */	addr->vvoea = 0;		/* extended bits */	addr->vvowc = -1;		/* for 1 word */	addr->vvocsr = VV_IEN | VV_DEN;	/* start the DMA, with interrupt */	DELAY(100000);#ifdef QBA	vv_softc[ui->ui_unit].vs_ipl = br = qbgetpri();#endif	addr->vvocsr = VV_RST;		/* clear out the CSR */	if (cvec && cvec != 0x200)		cvec -= 4;		/* backup so vector => receive */	return (sizeof(struct vvreg));}/* * Interface exists: make available by filling in network interface * record.  System will initialize the interface when it is ready * to accept packets. */vvattach(ui)	struct uba_device *ui;{	register struct vv_softc *vs;	vs = &vv_softc[ui->ui_unit];	vs->vs_if.if_unit = ui->ui_unit;	vs->vs_if.if_name = "vv";	vs->vs_if.if_mtu = VVMTU;	vs->vs_if.if_flags = IFF_BROADCAST;	vs->vs_if.if_init = vvinit;	vs->vs_if.if_ioctl = vvioctl;	vs->vs_if.if_output = vvoutput;	vs->vs_if.if_reset = vvreset;	vs->vs_if.if_timer = 0;	vs->vs_if.if_watchdog = vvwatchdog;	vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP;	/* use flag to determine if this is proNET-80 */	if (vs->vs_is80 = (short)(ui->ui_flags & 01)) {		vs->vs_if.if_type = IFT_P80;		vs->vs_if.if_baudrate = 80 * 1024 * 1024;	} else {		vs->vs_if.if_type = IFT_P10;		vs->vs_if.if_baudrate = 10 * 1024 * 1024;	}	vs->vs_host = NOHOST;#if defined(VAX750)	/* don't chew up 750 bdp's */	if (cpu == VAX_750 && ui->ui_unit > 0)		vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;#endif	if_attach(&vs->vs_if);}/* * Reset of interface after UNIBUS reset. * If interface is on specified uba, reset its state. */vvreset(unit, uban)	int unit, uban;{	register struct uba_device *ui;	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||	    ui->ui_ubanum != uban)		return;	printf(" vv%d", unit);	vv_softc[unit].vs_if.if_flags &= ~IFF_RUNNING;	vv_softc[unit].vs_flags &= ~VS_RUNNING;	vvinit(unit, 0);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */vvinit(unit, cansleep)	int unit, cansleep;{	register struct vv_softc *vs;	register struct uba_device *ui;	register struct vvreg *addr;	register int ubaaddr, s;	vs = &vv_softc[unit];	ui = vvinfo[unit];	if (vs->vs_if.if_addrlist == (struct ifaddr *)0)		return;	/*	 * Prevent multiple instances of vvinit	 * from trying simultaneously.	 */	while (vs->vs_flags & VS_INIT) {		if (cansleep)			sleep((caddr_t)vs, PZERO);		else			return;	}	if (vs->vs_flags & VS_RUNNING)		return;	vs->vs_flags = VS_INIT;	addr = (struct vvreg *)ui->ui_addr;	if ((vs->vs_if.if_flags & IFF_RUNNING) == 0 &&	    if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,	      sizeof (struct vv_header), (int)btoc(VVMRU)) == 0) {		printf("vv%d: can't initialize, if_ubainit() failed\n", unit);		vs->vs_if.if_flags &= ~IFF_UP;		vs->vs_flags = 0;		return;	}	vs->vs_if.if_flags |= IFF_RUNNING;	/*	 * Now that the uba is set up, figure out our address and	 * update complete our host address.	 */	if (cansleep)		vs->vs_host = vvidentify(unit);	if (vs->vs_host == NOHOST) {		vs->vs_if.if_flags &= ~IFF_UP;		vs->vs_flags = 0;		return;	}	vvlog(LOG_DEBUG, "vv%d: host %u\n", unit, vs->vs_host);	/*	 * Reset the interface, and stay in the ring	 */	addr->vvocsr = VV_RST;			/* take over output */	addr->vvocsr = VV_CPB;			/* clear packet buffer */	addr->vvicsr = VV_RST | VV_HEN;		/* take over input, */						/* keep relay closed */	if (cansleep) {		timeout(wakeup, (caddr_t)vs, hz/2);		sleep((caddr_t)vs, PZERO);	/* let contacts settle */	} else		DELAY(500000);			/* let contacts settle */	vs->vs_init = 0;			/* clear counters, etc. */	vs->vs_refused = 0;	vs->vs_timeouts = 0;	vs->vs_otimeout = 0;	vs->vs_ibadf = 0;	vs->vs_parity = 0;	vs->vs_lastx = 256;			/* an invalid address */	vs->vs_lastr = 256;			/* an invalid address */	/*	 * Hang a receive and start any	 * pending writes by faking a transmit complete.	 */	s = splimp();	ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);	addr->vviba = (u_short)ubaaddr;	addr->vviea = (u_short)(ubaaddr >> 16);	addr->vviwc = -(VVBUFSIZE) >> 1;	addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB;	vs->vs_oactive = 1;	vs->vs_if.if_flags |= IFF_UP;	vs->vs_flags = VS_RUNNING;		/* clear VS_INIT */	wakeup((caddr_t)vs);	vvxint(unit);	splx(s);}/* * Do a moderately thorough self-test in all three modes. Mostly * to keeps defective nodes off the ring, rather than to be especially * thorough. The key issue is to detect any cable breaks before joining * the ring. Return our node address on success, return -1 on failure. * *//* the three self-test modes */static u_short vv_modes[] = {	VV_STE|VV_LPB,			/* digital loopback */	VV_STE,				/* analog loopback */	VV_HEN				/* network mode */};vvidentify(unit)	int unit;{	register struct vv_softc *vs;	register struct uba_device *ui;	register struct vvreg *addr;	register struct mbuf *m;	register struct vv_header *v;	register int ubaaddr;	register int i, successes, failures, waitcount;	u_short shost = NOHOST;	vs = &vv_softc[unit];	ui = vvinfo[unit];	addr = (struct vvreg *)ui->ui_addr;	/*	 * Build a multicast message to identify our address	 * We need do this only once, since nobody else is about to use	 * the intermediate transmit buffer (ifu_w.ifrw_addr) that	 * if_ubainit() aquired for us.	 */	MGETHDR(m, M_DONTWAIT, MT_HEADER);	if (m == NULL) {		printf("vv%d: can't initialize, m_get() failed\n", unit);		return (NOHOST);	}	m->m_pkthdr.len = m->m_len = sizeof(struct vv_header);	v = mtod(m, struct vv_header *);	v->vh_dhost = VV_BROADCAST;	/* multicast destination address */	v->vh_shost = 0;		/* will be overwritten with ours */	v->vh_version = RING_VERSION;	v->vh_type = RING_DIAGNOSTICS;	v->vh_info = 0;	/* map xmit message into uba, copying to intermediate buffer */	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);	/*	 * For each of the modes (digital, analog, network), go through	 * a self-test that requires me to send VVIDENTSUCC good packets	 * in VVIDENTRETRY attempts. Use broadcast destination to find out	 * who I am, then use this as my address to check my address match	 * logic. Only data checked is the vh_type field.	 */	for (i = 0; i < 3; i++) {		successes = 0;	/* clear successes for this mode */		failures = 0;	/* and clear failures, too */		/* take over device, and leave ring */		addr->vvicsr = VV_RST;		addr->vvocsr = VV_RST;		addr->vvicsr = vv_modes[i];	/* test mode */		/*		 * let the flag and token timers pop so that the init ring bit		 * will be allowed to work, by waiting about 1 second		 */		timeout(wakeup, (caddr_t)vs, hz);		sleep((caddr_t)vs, PZERO);		/*		 * retry loop 		 */		while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY))		{			/* start a receive */			ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_r.ifrw_info);			addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */			addr->vviba = (u_short) ubaaddr;			addr->vviea = (u_short) (ubaaddr >> 16);			addr->vviwc = -(VVBUFSIZE) >> 1;			addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB;#ifdef notdef			/* purge stale data from BDP */			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)				UBAPURGE(vs->vs_ifuba.ifu_uba,				    vs->vs_ifuba.ifu_w.ifrw_bdp);#endif			/* do a transmit */			ubaaddr = UBAI_ADDR(vs->vs_ifuba.ifu_w.ifrw_info);			addr->vvocsr = VV_RST;	/* abort last try */			addr->vvoba = (u_short) ubaaddr;			addr->vvoea = (u_short) (ubaaddr >> 16);			addr->vvowc = -((vs->vs_olen + 1) >> 1);			addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;			/* poll receive side for completion */			DELAY(10000);		/* give it a chance */			for (waitcount = 0; waitcount < 10; waitcount++) {				if (addr->vvicsr & VV_RDY)					goto gotit;				DELAY(1000);			}			failures++;		/* no luck */			continue;gotit:			/* we got something--is it any good? */			if ((addr->vvicsr & (VVRERR|VV_LDE)) ||			    (addr->vvocsr & (VVXERR|VV_RFS))) {				failures++;				continue;			}			/* Purge BDP before looking at received packet */			if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)				UBAPURGE(vs->vs_ifuba.ifu_uba,				    vs->vs_ifuba.ifu_r.ifrw_bdp);#ifdef notdef			m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header),				0, &vs->vs_if);			if (m != NULL)				m_freem(m);#endif						v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);			/* check message type, catch our node address */			if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) {				if (shost == NOHOST) {					shost = v->vh_shost & 0xff;					/* send to ourself now */					((struct vv_header *)					    (vs->vs_ifuba.ifu_r.ifrw_addr))					    ->vh_dhost = shost;				}				successes++;			} else {				failures++;			}			v->vh_type = 0;  /* clear to check again */		}		if (failures >= VVIDENTRETRY)		{			printf("vv%d: failed self-test after %d tries \in %s mode\n",			    unit, VVIDENTRETRY, i == 0 ? "digital loopback" :			    (i == 1 ? "analog loopback" : "network"));			printf("vv%d: icsr = %b, ocsr = %b\n",			    unit, 0xffff & addr->vvicsr, VV_IBITS,			    0xffff & addr->vvocsr, VV_OBITS);			addr->vvicsr = VV_RST;	/* kill the sick board */			addr->vvocsr = VV_RST;			shost = NOHOST;			goto done;		}	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -