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

📄 if_vv.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifndef lintstatic char *sccsid = "@(#)if_vv.c	4.1	(ULTRIX)	7/2/90";#endif lint/************************************************************************ *									* *			Copyright (c) 1985 by				* *		Digital Equipment Corporation, Maynard, MA		* *			All rights reserved.				* *									* *   This software is furnished under a license and may be used and	* *   copied  only  in accordance with the terms of such license and	* *   with the  inclusion  of  the  above  copyright  notice.   This	* *   software  or  any  other copies thereof may not be provided or	* *   otherwise made available to any other person.  No title to and	* *   ownership of the software is hereby transferred.			* *									* *   This software is  derived  from  software  received  from  the	* *   University    of   California,   Berkeley,   and   from   Bell	* *   Laboratories.  Use, duplication, or disclosure is  subject  to	* *   restrictions  under  license  agreements  with  University  of	* *   California and with AT&T.						* *									* *   The information in this software is subject to change  without	* *   notice  and should not be construed as a commitment by Digital	* *   Equipment Corporation.						* *									* *   Digital assumes no responsibility for the use  or  reliability	* *   of its software on equipment which is not supplied by Digital.	* *									* ************************************************************************//************************************************************************ *			Modification History				* * *	15-Jan-88	lp *		Merge of final 43BSD changes. * * 13-Jun-86   -- jaw 	fix to uba reset and drivers. *									* * 18-mar-86  -- jaw     br/cvec changed to NOT use registers. * *	Larry Cohen  -	09/16/85					* * 		Add 43bsd alpha tape changes for subnet routing		* *									* ************************************************************************//* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved.  The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * *	if_vv.c	7.1 (Berkeley) 6/5/86 */#include "vv.h"#if NVV > 0 || defined(BINARY)#include "../data/if_vv_data.c"/* * 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. Thus the name is "vv". * * This driver is compatible with the proNET 10 meagbit 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. * * 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, 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. *//* *    maximum transmission unit definition -- *        you can set VVMTU at anything from 576 to 2024. *        1536 is a popular "large" value, because it is a multiple *	  of 512, which the trailer scheme likes. *        The absolute maximum size is 2024, which is enforced. */#define VVMTU (1536)#define VVMRU (VVMTU + 16)#define VVBUFSIZE (VVMRU + sizeof(struct vv_header))#if VVMTU>2024#undef VVMTU#undef VVMRU#undef VVBUFSIZE#define VVBUFSIZE (2046)#define VVMRU (VVBUFSIZE - sizeof (struct vv_header))#define VVMTU (VVMRU - 16)#endif/* *   debugging and tracing stuff */int	vv_tracehdr = 0;	/* 1 => trace headers (slowly!!) */#define vvtracehdr  if (vv_tracehdr) vvprt_hdr#define vvprintf    if (vs->vs_if.if_flags & IFF_DEBUG) printf/* * 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;#endif#define	NOHOST	0xffff			/* illegal host number *//* * probe the interface to see that the registers exist, and then * cause an interrupt to find its vector */vvprobe(reg)	caddr_t reg;{	register struct vvreg *addr;	addr = (struct vvreg *)reg;	/* reset interface, enable, and wait till dust settles */	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);	addr->vvocsr = VV_RST;		/* clear out the CSR */	if (cvec && cvec != 0x200)		cvec -= 4;		/* backup so vector => receive */	return(1);}/* * 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 */	vs->vs_is80 = (short)(ui->ui_flags & 01);#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 >= nNVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||	    ui->ui_ubanum != uban)		return;	printf(" vv%d", unit);	vvinit(unit);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */vvinit(unit)	int unit;{	register struct vv_softc *vs;	register struct uba_device *ui;	register struct vvreg *addr;	register int ubainfo, s;	vs = &vv_softc[unit];	ui = vvinfo[unit];	if (vs->vs_if.if_addrlist == (struct ifaddr *)0)		return;	addr = (struct vvreg *)ui->ui_addr;	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,	    sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {		printf("vv%d: can't initialize, if_ubainit() failed\n", unit);		vs->vs_if.if_flags &= ~IFF_UP;		return;	}	/*	 * Now that the uba is set up, figure out our address and	 * update complete our host address.	 */	if ((vs->vs_host = vvidentify(unit)) == NOHOST) {		vs->vs_if.if_flags &= ~IFF_UP;		return;	}	printf("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 */	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();	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;	addr->vviba = (u_short)ubainfo;	addr->vviea = (u_short)(ubainfo >> 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_RUNNING;	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 ubainfo;	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.	 */	m = m_get(M_DONTWAIT, MT_DATA);	if (m == NULL) {		printf("vv%d: can't initialize, m_get() failed\n", unit);		return (0);	}	m->m_next = 0;	m->m_off = MMINOFF;	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		 */		DELAY(1000000L);		/*		 * retry loop 		 */		while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY))		{			/* start a receive */			ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;			addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */			addr->vviba = (u_short) ubainfo;			addr->vviea = (u_short) (ubainfo >> 16);			addr->vviwc = -(VVBUFSIZE) >> 1;			addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB;			/* 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,				vs->vs_ifuba.ifu_uban);			/* do a transmit */			ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;			addr->vvocsr = VV_RST;	/* abort last try */			addr->vvoba = (u_short) ubainfo;			addr->vvoea = (u_short) (ubainfo >> 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,				    vs->vs_ifuba.ifu_uban);			m = if_rubaget(&vs->vs_ifuba,			    sizeof(struct vv_header), 0);			if (m != NULL)				m_freem(m);						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;		}	}done:	/* deallocate mbuf used for send packet (won't be one, anyways) */	if (vs->vs_ifuba.ifu_xtofree) {		m_freem(vs->vs_ifuba.ifu_xtofree);		vs->vs_ifuba.ifu_xtofree = 0;	}	return(shost);}/* * Start or restart output on interface. * If interface is active, this is a retransmit, so just * restuff registers and go. * If interface is not already active, get another datagram * to send off of the interface queue, and map it to the interface * before starting the output. */vvstart(dev)	dev_t dev;{	register struct uba_device *ui;	register struct vv_softc *vs;	register struct vvreg *addr;	register struct mbuf *m;	register int unit, ubainfo, dest, s;	unit = VVUNIT(dev);	ui = vvinfo[unit];	vs = &vv_softc[unit];	if (vs->vs_oactive)		goto restart;	/*	 * Not already active: dequeue another request	 * and map it to the UNIBUS.  If no more requests,	 * just return.	 */	s = splimp();	IF_DEQUEUE(&vs->vs_if.if_snd, m);	splx(s);

⌨️ 快捷键说明

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