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

📄 if_dmv.c

📁 open bsd vax module -if function
💻 C
📖 第 1 页 / 共 2 页
字号:
		}		addr->bsel0 = DMV_IEO;	}	else /* RDO set or DMV still holding CSR */		addr->bsel0 = (DMV_RQI|DMV_IEI|DMV_IEO);}/* * DMV interface output interrupt. * A transfer may have completed, check for errors. * If it was a read, notify appropriate protocol. * If it was a write, pull the next one off the queue. */dmvxint(unit)	int unit;{	register struct dmv_softc *sc;	register struct ifnet *ifp;	struct uba_device *ui = dmvinfo[unit];	struct dmvdevice *addr;	struct mbuf *m;	struct ifqueue *inq;	int sel2, sel3, sel4, sel6, sel10, pkaddr, len, s;	register struct ifrw *ifrw;	register struct dmvbufs *rp;	register struct ifxmt *ifxp;	struct dmv_header *dh;	int off, resid;	addr = (struct dmvdevice *)ui->ui_addr;	sc = &dmv_softc[unit];	splx(sc->sc_ipl);	ifp = &sc->sc_if;	while (addr->bsel2 & DMV_RDO) {		sel2 = addr->bsel2;		sel3 = addr->bsel3;		sel4 = addr->wsel4;		/* release port */		sel6 = addr->wsel6;		if(sel2 & DMV_22BIT)			sel10 = addr->wsel10;		addr->bsel2 &= ~DMV_RDO;		pkaddr =  sel4 | ((sel6 & 0x3f) << 16);		printd(("dmvxint: sel2=%x sel4=%x sel6=%x sel10=%x pkaddr=%x\n",			(unsigned) sel2,			(unsigned) sel4,			(unsigned) sel6,			(unsigned) sel10,			(unsigned) pkaddr		));		if((sc->sc_flag & DMV_RUNNING)==0) {				log(LOG_WARNING, "dmvxint: dmv%d xint while down\n", unit);				return;		}		switch (sel2 & 07) {		case DMV_BDRUS:			/*			 * A read has completed.  			 * Pass packet to type specific			 * higher-level input routine.			 */			ifp->if_ipackets++;			/* find location in dmvuba struct */			ifrw= &sc->sc_ifr[0];			for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {				if(rp->ubinfo == pkaddr)					break;				ifrw++;			}			if (rp >= &sc->sc_rbufs[NRCV])				panic("dmv rcv");			if ((rp->flags & DBUF_DMVS) == 0)				log(LOG_WARNING, "dmvxint: dmv%d done unalloc rbuf\n", unit);			len = (sel10&0x3fff) - sizeof (struct dmv_header);			if (len < 0 || len > DMVMTU) {				ifp->if_ierrors++;				log(LOG_ERR, "dmvxint: dmv%d bad rcv pkt addr 0x%x len 0x%x\n",				    unit, pkaddr, len);				goto setup;			}			/*			 * Deal with trailer protocol: if type is trailer			 * get true type from first 16-bit word past data.			 * Remember that type was trailer by setting off.			 */			dh = (struct dmv_header *)ifrw->ifrw_addr;			dh->dmv_type = ntohs((u_short)dh->dmv_type);#define dmvdataaddr(dh, off, type)	((type)(((caddr_t)((dh)+1)+(off))))			if (dh->dmv_type >= DMV_TRAILER &&			    dh->dmv_type < DMV_TRAILER+DMV_NTRAILER) {				off = (dh->dmv_type - DMV_TRAILER) * 512;				if (off >= DMVMTU)					goto setup;		/* sanity */				dh->dmv_type = ntohs(*dmvdataaddr(dh, off, u_short *));				resid = ntohs(*(dmvdataaddr(dh, off+2, u_short *)));				if (off + resid > len)					goto setup;		/* sanity */				len = off + resid;			} else				off = 0;			if (len == 0)				goto setup;			/*			 * Pull packet off interface.  Off is nonzero if			 * packet has trailing header; dmv_get will then			 * force this header information to be at the front,			 * but we still have to drop the type and length			 * which are at the front of any trailer data.			 */			m = if_ubaget(&sc->sc_ifuba, ifrw, len, off, ifp);			if (m == 0)				goto setup;			switch (dh->dmv_type) {#ifdef INET			case DMV_IPTYPE:				schednetisr(NETISR_IP);				inq = &ipintrq;				break;#endif			default:				m_freem(m);				goto setup;			}			s = splimp();			if (IF_QFULL(inq)) {				IF_DROP(inq);				m_freem(m);			} else				IF_ENQUEUE(inq, m);			splx(s);	setup:			/* is this needed? */			rp->ubinfo = UBAI_ADDR(ifrw->ifrw_info);			dmvload(				sc,				DMV_BACCR,				QP_SEL4|QP_SEL6|QP_SEL10,				0,				(u_short) rp->ubinfo,				(rp->ubinfo>>16)&0x3f,				rp->cc			);			break;		case DMV_BDXSA:			/*			 * A write has completed, start another			 * transfer if there is more data to send.			 */			ifp->if_opackets++;			/* find associated dmvbuf structure */			ifxp = &sc->sc_ifw[0];			for (rp = &sc->sc_xbufs[0]; rp < &sc->sc_xbufs[NXMT]; rp++) {				if(rp->ubinfo == pkaddr)					break;				ifxp++;			}			if (rp >= &sc->sc_xbufs[NXMT]) {				log(LOG_ERR, "dmv%d: bad packet address 0x%x\n",				    unit, pkaddr);				break;			}			if ((rp->flags & DBUF_DMVS) == 0)				log(LOG_ERR, "dmvxint: dmv%d unallocated packet 0x%x\n",				    unit, pkaddr);			/* mark buffer free */			if (ifxp->ifw_xtofree) {				(void)m_freem(ifxp->ifw_xtofree);				ifxp->ifw_xtofree = 0;			}			rp->flags &= ~DBUF_DMVS;			if (--sc->sc_oused == 0)				sc->sc_if.if_timer = 0;			else				sc->sc_if.if_timer = dmv_timeout;			if ((sc->sc_flag & DMV_ONLINE) == 0) {				extern int ifqmaxlen;				/*				 * We're on the air.				 * Open the queue to the usual value.				 */				sc->sc_flag |= DMV_ONLINE;				ifp->if_snd.ifq_maxlen = ifqmaxlen;			}			break;		case DMV_CNTRLO:			/* ACCUMULATE STATISTICS */			switch(sel6&DMV_EEC) {			case DMV_ORUN:				if(sc->sc_flag & DMV_RESTART) {					load_rec_bufs(sc);					sc->sc_flag &= ~DMV_RESTART;					log(LOG_INFO,					    "dmv%d: far end on-line\n", unit);				} else {					log(LOG_WARNING,					    "dmv%d: far end restart\n", unit);					goto restart;				}				break;			case DMV_RTE:				ifp->if_ierrors++;				if ((sc->sc_rte++ % DMV_RPRTE) == 0)					log(LOG_WARNING,				    "dmv%d: receive threshold error\n",					    unit);				break;			case DMV_TTE:				ifp->if_oerrors++;				if ((sc->sc_xte++ % DMV_RPTTE) == 0)					log(LOG_WARNING,				    "dmv%d: transmit threshold error\n",					    unit);				break;			case DMV_STE:				if ((sc->sc_ste++ % DMV_RPSTE) == 0)					log(LOG_WARNING,				    "dmv%d: select threshold error\n",					    unit);				break;			case DMV_NXM:				if ((sc->sc_nxm++ % DMV_RPNXM) == 0)					log(LOG_WARNING,				    "dmv%d: nonexistent memory error\n",					    unit);				break;			case DMV_MODD:				if ((sc->sc_modd++ % DMV_RPMODD) == 0) {					log(LOG_WARNING,				    "dmv%d: modem disconnected error\n",					    unit);					goto restart;				}				break;			case DMV_CXRL:				if ((sc->sc_cxrl++ % DMV_RPCXRL) == 0)					log(LOG_WARNING,				    "dmv%d: carrier loss error\n",					    unit);				break;			case DMV_QOVF:				log(LOG_WARNING,				    "dmv%d: response queue overflow\n",				    unit);				sc->sc_qovf++;				goto restart;			default:				log(LOG_WARNING,				    "dmv%d: unknown error %o\n",				    unit, sel6&DMV_EEC);				if ((sc->sc_unknown++ % DMV_RPUNKNOWN) == 0)					goto restart;				break;			}			break;		case DMV_BDRUNUS:		case DMV_BDXSN:		case DMV_BDXNS:			log(LOG_INFO,			   "dmv%d: buffer disp for halted trib %o\n",			   unit, sel2&0x7		        );			break;		case DMV_MDEFO:			if((sel6&0x1f) == 020) {				log(LOG_INFO,			   		"dmv%d: buffer return complete sel3=%x\n",			   		unit, sel3);			} else {				log(LOG_INFO,			   	"dmv%d: info resp sel3=%x sel4=%x sel6=%x\n",			   	unit, sel3, sel4, sel6		        	);			}			break;					default:			log(LOG_WARNING, "dmv%d: bad control %o\n",			   unit, sel2&0x7		        );			break;		}	}	dmvstart(unit);	return;restart:	dmvrestart(unit);}load_rec_bufs(sc)register struct dmv_softc *sc;{	register struct dmvbufs *rp;	/* queue first NRCV buffers for DMV to fill */	for (rp = &sc->sc_rbufs[0]; rp < &sc->sc_rbufs[NRCV]; rp++) {		rp->flags |= DBUF_DMVS;		dmvload(			sc,			DMV_BACCR,			QP_TRIB|QP_SEL4|QP_SEL6|QP_SEL10,			1,			rp->ubinfo,			(rp->ubinfo>>16)&0x3f,			rp->cc		);		sc->sc_iused++;	}}/* * DMV output routine. * Encapsulate a packet of type family for the dmv. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. */dmvoutput(ifp, m0, dst)	register struct ifnet *ifp;	register struct mbuf *m0;	struct sockaddr *dst;{	int type, error, s;	register struct mbuf *m = m0;	register struct dmv_header *dh;	register int off;	if ((ifp->if_flags & IFF_UP) == 0) {		error = ENETDOWN;		goto bad;	}	switch (dst->sa_family) {#ifdef	INET	case AF_INET:		off = m->m_pkthdr.len - m->m_len;		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)		if (off > 0 && (off & 0x1ff) == 0 &&		    (m->m_flags & M_EXT) == 0 &&		    m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {			type = DMV_TRAILER + (off>>9);			m->m_data -= 2 * sizeof (u_short);			m->m_len += 2 * sizeof (u_short);			*mtod(m, u_short *) = htons((u_short)DMV_IPTYPE);			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);			goto gottrailertype;		}		type = DMV_IPTYPE;		off = 0;		goto gottype;#endif	case AF_UNSPEC:		dh = (struct dmv_header *)dst->sa_data;		type = dh->dmv_type;		goto gottype;	default:		log(LOG_ERR, "dmvoutput, dmv%d can't handle af%d\n",		    ifp->if_unit, dst->sa_family);		error = EAFNOSUPPORT;		goto bad;	}gottrailertype:	/*	 * Packet to be sent as a trailer; move first packet	 * (control information) to end of chain.	 */	while (m->m_next)		m = m->m_next;	m->m_next = m0;	m = m0->m_next;	m0->m_next = 0;	m0 = m;gottype:	/*	 * Add local network header	 * (there is space for a uba on a vax to step on)	 */	M_PREPEND(m, sizeof(struct dmv_header), M_DONTWAIT);	if (m == 0) {		error = ENOBUFS;		goto bad;	}	dh = mtod(m, struct dmv_header *);	dh->dmv_type = htons((u_short)type);	/*	 * 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);		m_freem(m);		splx(s);		return (ENOBUFS);	}	IF_ENQUEUE(&ifp->if_snd, m);	dmvstart(ifp->if_unit);	splx(s);	return (0);bad:	m_freem(m0);	return (error);}/* * Process an ioctl request. *//* ARGSUSED */dmvioctl(ifp, cmd, data)	register struct ifnet *ifp;	int cmd;	caddr_t data;{	int s = splimp(), error = 0;	struct mbuf *m;	register struct dmv_softc *sc = &dmv_softc[ifp->if_unit];	switch (cmd) {	case SIOCSIFADDR:		ifp->if_flags |= IFF_UP;		if ((ifp->if_flags & IFF_RUNNING) == 0)			dmvinit(ifp->if_unit); 		break;	case SIOCSIFDSTADDR:		if ((ifp->if_flags & IFF_RUNNING) == 0)			dmvinit(ifp->if_unit); 		break;			case SIOCSIFFLAGS:		if ((ifp->if_flags & IFF_UP) == 0 &&		    sc->sc_flag & DMV_RUNNING)			dmvdown(ifp->if_unit);		else if (ifp->if_flags & IFF_UP &&		    (sc->sc_flag & DMV_RUNNING) == 0)			dmvrestart(ifp->if_unit);		break;	default:		error = EINVAL;	}	splx(s);	return (error);}/* * Restart after a fatal error. * Clear device and reinitialize. */dmvrestart(unit)	int unit;{	register struct dmvdevice *addr;	register int i;	dmvdown(unit);	addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr);	/*	 * Let the DMV finish the MCLR.	 */	for (i = 100000; i && (addr->bsel1 & DMV_RUN) == 0; i--)		;	if ((addr->bsel1 & DMV_RUN) == 0) {		log(LOG_ERR, "dmvrestart: can't start device\n" );		return (0);	}	if ((addr->bsel4 != 033) || (addr->bsel6 != 0305))	{		log(LOG_ERR, "dmv%d: device init failed, bsel4=%o, bsel6=%o\n",			unit, addr->bsel4, addr->bsel6);		return (0);	}	/* restart DMV */	dmvinit(unit);	dmv_softc[unit].sc_if.if_collisions++;	/* why not? */}	/* * Reset a device and mark down. * Flush output queue and drop queue limit. */dmvdown(unit)	int unit;{	struct dmv_softc *sc = &dmv_softc[unit];	register struct ifxmt *ifxp;	((struct dmvdevice *)(dmvinfo[unit]->ui_addr))->bsel1 = DMV_MCLR;	sc->sc_flag &= ~(DMV_RUNNING | DMV_ONLINE);	for (ifxp = sc->sc_ifw; ifxp < &sc->sc_ifw[NXMT]; ifxp++) {		if (ifxp->ifw_xtofree) {			(void) m_freem(ifxp->ifw_xtofree);			ifxp->ifw_xtofree = 0;		}	}	sc->sc_oused = 0;	if_qflush(&sc->sc_if.if_snd);	/*	 * Limit packets enqueued until we're back on the air.	 */	sc->sc_if.if_snd.ifq_maxlen = 3;}/* * Watchdog timeout to see that transmitted packets don't * lose interrupts.  The device has to be online. */dmvtimeout(unit)	int unit;{	register struct dmv_softc *sc;	struct dmvdevice *addr;	sc = &dmv_softc[unit];	if (sc->sc_flag & DMV_ONLINE) {		addr = (struct dmvdevice *)(dmvinfo[unit]->ui_addr);		log(LOG_ERR, "dmv%d: output timeout, bsel0=%b bsel2=%b\n",		    unit, addr->bsel0 & 0xff, DMV0BITS,		    addr->bsel2 & 0xff, DMV2BITS);		dmvrestart(unit);	}}#endif

⌨️ 快捷键说明

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