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

📄 if_pcl.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
字号:
#ifndef lintstatic char *sccsid = "@(#)if_pcl.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				* * * 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		* *									* ************************************************************************/#include "pcl.h"#if NPCL > 0 || defined(BINARY)/* * DEC CSS PCL-11B Parallel Communications Interface * * Written by Mike Muuss and Jeff Schwab. */#include "../data/if_pcl_data.c"/* The MTU has been carefully selected to prevent fragmentation <-> ArpaNet */#define	PCLMTU		(1006)	/* Max transmission unit (bytes) */#define	PCLMAXTDM	7	/* Max unit number on TDM bus */int	pclprobe(), pclattach(), pclrint(), pclxint();int	pclinit(), pclioctl(), pcloutput(), pclreset();u_short pclstd[] = { 0 };#define	PCLUNIT(x)	minor(x)struct	uba_driver pcldriver =	{ pclprobe, 0, pclattach, 0, pclstd, "pcl", pclinfo };/* * Structure of "local header", which only goes between * pcloutput and pclstart. */struct pcl_header {	short	pcl_dest;		/* Destination PCL station */};/* * Do non-DMA output of 1 word to determine presence of interface, * and to find the interupt vector.  1 word messages are a special * case in the receiver routine, and will be discarded. */pclprobe(reg)	caddr_t reg;{	register struct pcldevice *addr = (struct pcldevice *)reg;#ifdef lint	pclrint(0); pclxint(0);#endif	addr->pcl_rcr = PCL_RCINIT;	addr->pcl_tcr = PCL_TXINIT;	addr->pcl_tsba = 0xFFFE;	/* going for 01777776 */	addr->pcl_tsbc = -4;		/* really short */	addr->pcl_tcr =	 ((1 & 0xF) << 8) | PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE | 0x0030;	DELAY(100000);	addr->pcl_tcr = PCL_TXINIT;	return (sizeof (struct pcldevice));}/* * Interface exists: make available by filling in network interface * record.  System will initialize the interface when it is ready * to accept packets. */pclattach(ui)	struct uba_device *ui;{	register struct pcl_softc *sc = &pcl_softc[ui->ui_unit];	sc->sc_if.if_unit = ui->ui_unit;	sc->sc_if.if_name = "pcl";	sc->sc_if.if_mtu = PCLMTU;	sc->sc_if.if_init = pclinit;	sc->sc_if.if_output = pcloutput;	sc->sc_if.if_ioctl = pclioctl;	sc->sc_if.if_reset = pclreset;	sc->sc_ifuba.ifu_flags = UBA_NEEDBDP;	if_attach(&sc->sc_if);}/* * Reset of interface after UNIBUS reset. * If interface is on specified uba, reset its state. */pclreset(unit, uban)	int unit, uban;{	register struct uba_device *ui;	if (unit >= nNPCL || (ui = pclinfo[unit]) == 0 || ui->ui_alive == 0 ||	    ui->ui_ubanum != uban)		return;	printf(" pcl%d", unit);	pclinit(unit);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */pclinit(unit)	int unit;{	register struct pcl_softc *sc = &pcl_softc[unit];	register struct uba_device *ui = pclinfo[unit];	register struct pcldevice *addr;	int s;	if (sc->sc_if.if_addrlist == (struct ifaddr *)0)		return;	if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0,	    (int)btoc(PCLMTU)) == 0) { 		printf("pcl%d: can't init\n", unit);		sc->sc_if.if_flags &= ~IFF_UP;		return;	}	addr = (struct pcldevice *)ui->ui_addr;	addr->pcl_rcr = PCL_RCINIT;	addr->pcl_tcr = PCL_TXINIT;	/*	 * Hang a receive and start any	 * pending writes by faking a transmit complete.	 */	s = splimp();	addr->pcl_rdba = (short) sc->sc_ifuba.ifu_r.ifrw_info;	addr->pcl_rdbc = -PCLMTU;	addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_r.ifrw_info>>12))&0x0030) |		PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE;	sc->sc_oactive = 0;	sc->sc_if.if_flags |= IFF_UP|IFF_RUNNING;	pclstart(unit);	splx(s);	/* Set up routing table entry */#ifdef notdef	if_rtinit(&sc->sc_if, RTF_UP);#endif}/* * PCL output routine. */pcloutput(ifp, m, dst)	struct ifnet *ifp;	struct mbuf *m;	struct sockaddr *dst;{	int dest, s, error;	struct pcl_header *pclp;	struct mbuf *m2;	switch (dst->sa_family) {#ifdef INET	case AF_INET:		if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))			dest = 0;		else			dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);		if (dest > PCLMAXTDM) {			error = EHOSTUNREACH;			goto bad;		}		break;#endif	default:		printf("pcl%d: can't handle af%d\n", ifp->if_unit,			dst->sa_family);		error = EAFNOSUPPORT;		goto bad;	}	/*	 * Add pseudo local net header.	 * Actually, it does not get transmitted, but merely stripped	 * off and used by the START routine to route the packet.	 * If no space in first mbuf, allocate another.	 */	if (m->m_off > MMAXOFF ||	    MMINOFF + sizeof (struct pcl_header) > m->m_off) {		m2 = m_get(M_DONTWAIT, MT_DATA);		if (m2 == 0) {			error = ENOBUFS;			goto bad;		}		m2->m_next = m;		m2->m_off = MMINOFF;		m2->m_len = sizeof (struct pcl_header);		m = m2;	} else {		m->m_off -= sizeof (struct pcl_header);		m->m_len += sizeof (struct pcl_header);	}	pclp = mtod(m, struct pcl_header *);	pclp->pcl_dest = dest;	/*	 * Queue message on interface, and start output if interface	 * not yet active.	 */	s = splimp();	if (IF_QFULL(&ifp->if_snd)) {		IF_DROP(&ifp->if_snd);		error = ENOBUFS;		goto qfull;	}	IF_ENQUEUE(&ifp->if_snd, m);	if (pcl_softc[ifp->if_unit].sc_oactive == 0)		pclstart(ifp->if_unit);	splx(s);	return (0);qfull:	splx(s);bad:	m_freem(m);	return (error);}/* * Start or restart output on interface. * If interface is already active, then this is a retransmit. * 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. */pclstart(dev)	dev_t dev;{        int unit = PCLUNIT(dev);	struct uba_device *ui = pclinfo[unit];	register struct pcl_softc *sc = &pcl_softc[unit];	register struct pcldevice *addr;	struct mbuf *m;	if (sc->sc_oactive)		goto restart;	/*	 * Not already active: dequeue another request	 * and map it to the UNIBUS.  If no more requests,	 * just return.	 */	IF_DEQUEUE(&sc->sc_if.if_snd, m);	if (m == 0) {		sc->sc_oactive = 0;		return;	}	/*	 * Pull destination node out of pseudo-local net header.	 * remove it from outbound data.	 * Note that if_wubaput calls m_bcopy, which is prepared for	 * m_len to be 0 in the first mbuf in the chain.	 */	sc->sc_bdest = mtod(m, struct pcl_header *)->pcl_dest;	sc->sc_odest = sc->sc_bdest? sc->sc_bdest: 1;	m->m_off += sizeof (struct pcl_header);	m->m_len -= sizeof (struct pcl_header);	/* Map out to the DMA area */	sc->sc_olen = if_wubaput(&sc->sc_ifuba, m);restart:	/*	 * Have request mapped to UNIBUS for transmission.	 * Purge any stale data from this BDP, and start the output.	 */	addr = (struct pcldevice *)ui->ui_addr;	addr->pcl_tcr = PCL_TXINIT;	if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)		UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp,			sc->sc_ifuba.ifu_uban);	addr->pcl_tsba = (int)sc->sc_ifuba.ifu_w.ifrw_info;	addr->pcl_tsbc = -sc->sc_olen;	/*	 * RIB (retry if busy) is used on the second and subsequent packets	 * to a single host, because TCP often wants to transmit multiple	 * buffers in a row,	 * and if they are all going to the same place, the second and	 * subsequent ones may be lost due to receiver not ready again yet.	 * This can cause serious problems, because the TCP will resend the	 * whole window, which just repeats the problem.  The result is that	 * a perfectly good link appears not to work unless we take steps here.	 */	addr->pcl_tcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) |		((sc->sc_odest & 0xF)<<8) |		PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE |		(sc->sc_odest == sc->sc_lastdest ? PCL_RIB : 0);	sc->sc_lastdest = sc->sc_odest;	sc->sc_oactive = 1;}/* * PCL transmitter interrupt. * Start another output if more data to send. */pclxint(unit)	int unit;{	register struct uba_device *ui = pclinfo[unit];	register struct pcl_softc *sc = &pcl_softc[unit];	register struct pcldevice *addr = (struct pcldevice *)ui->ui_addr;	if (sc->sc_oactive == 0) {		printf ("pcl%d: stray interrupt\n", unit);		return;	}	if (addr->pcl_tsr & PCL_ERR) {		sc->sc_lastdest = 0;		/* don't bother with RIB */		if (addr->pcl_tsr & PCL_MSTDWN) {			addr->pcl_tmmr = PCL_MASTER|PCL_AUTOADDR;			pclstart(unit);	/* Retry */			printf("pcl%d: master\n", unit );			return;		}#ifndef PCL_TESTING		if ((addr->pcl_tsr & (PCL_ERR|PCL_RESPB)) == (PCL_ERR|0))  {			;	/* Receiver Offline -- not exactly an error */		}  else  {#else		{#endif			/* Log as an error */			printf("pcl%d: send error, tcr=%b tsr=%b\n",				unit, addr->pcl_tcr, PCL_TCSRBITS,				addr->pcl_tsr, PCL_TERRBITS);			sc->sc_if.if_oerrors++;		}	} else		sc->sc_if.if_opackets++;	if (sc->sc_bdest == 0 && sc->sc_odest < PCLMAXTDM) {		sc->sc_odest++;		/* do next host (broadcast) */	} else {		sc->sc_oactive = 0;		if (sc->sc_ifuba.ifu_xtofree) {			m_freem(sc->sc_ifuba.ifu_xtofree);			sc->sc_ifuba.ifu_xtofree = 0;		}	}	pclstart(unit);}/* * PCL interface receiver interrupt. * If input error just drop packet. */pclrint(unit)	int unit;{	register struct pcl_softc *sc = &pcl_softc[unit];	struct pcldevice *addr = (struct pcldevice *)pclinfo[unit]->ui_addr;    	struct mbuf *m;	int len;	register struct ifqueue *inq;	sc->sc_if.if_ipackets++;	/*	 * Purge BDP; drop if input error indicated.	 */	if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)		UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_r.ifrw_bdp,			sc->sc_ifuba.ifu_uban);	if (addr->pcl_rsr & PCL_ERR) {		printf("pcl%d: rcv error, rcr=%b rsr=%b\n",			unit, addr->pcl_rcr, PCL_RCSRBITS,			addr->pcl_rsr, PCL_RERRBITS);		sc->sc_if.if_ierrors++;		addr->pcl_rcr = PCL_RCINIT;		goto setup;	}	len = PCLMTU + addr->pcl_rdbc;	addr->pcl_rcr = PCL_RCINIT;	if (len <= 0 || len > PCLMTU) {		printf("pcl%d: bad len=%d.\n", unit, len);		sc->sc_if.if_ierrors++;		goto setup;	}	/* Really short packets will be part of the startup sequence */	if (len <= 4) {		/* Later, do comming-up processing here */		goto setup;	/* drop packet */	}	/*	 * Pull packet off interface.	 */	m = if_rubaget(&sc->sc_ifuba, len, 0);	if (m == 0)		goto setup;	schednetisr(NETISR_IP);	inq = &ipintrq;	if (IF_QFULL(inq)) {		IF_DROP(inq);		m_freem(m);	} else		IF_ENQUEUE(inq, m);setup:	/*	 * Reset for next packet.	 */	addr->pcl_rdba = (int)sc->sc_ifuba.ifu_r.ifrw_info;	addr->pcl_rdbc = -PCLMTU;	addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_r.ifrw_info>>12))&0x0030) |		PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE;}/* * Process an ioctl request. */pclioctl(ifp, cmd, data)	register struct ifnet *ifp;	int cmd;	caddr_t data;{	int s = splimp(), error = 0;	switch (cmd) {	case SIOCSIFADDR:		if ((ifp->if_flags & IFF_RUNNING) == 0)			pclinit(ifp->if_unit);		ifp->if_flags |= IFF_UP;		break;	default:		error = EINVAL;	}	splx(s);	return (error);}#endif

⌨️ 快捷键说明

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