Ultrix-3.1/sys/net/if_qe.c

Compare this file to the similar file:
Show the results in this format:

/*
 * if_qe.c
 *
 * SCCSID: @(#)if_qe.c	3.1	12/31/87
 *	based on "@(#)if_qe.c	1.1	(decvax!rjl)";
 */

/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/include/COPYRIGHT" for applicable restrictions.  *
 **********************************************************************/
/* ---------------------------------------------------------------------
 * Modification History 
 *
 *  04 Oct. 84 -- jf
 *	Added support for new ioctls to add and delete multicast addresses
 *	and set the physical address.
 *	Add support for general protocols.
 *
 *  14 Aug. 84 -- rjl
 *	Integrated Shannon changes. (allow arp above 1024 and ? )
 *
 *  13 Feb. 84 -- rjl
 *
 *	Initial version of driver. derived from IL driver.
 * 
 * ---------------------------------------------------------------------
 */

/*
 * Digital Q-BUS to NI Adapter
 */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/buf.h>
#include <sys/protosw.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <net/if_qe.h>


/*
 * Ethernet software status per interface.
 *
 * Each interface is referenced by a network interface structure,
 * is_if, which the routing code uses to locate the interface.
 * This structure contains the output queue for the interface, its address, ...
 */
/*
 * We allocate enough descriptors to do scatter/gather plus 1 to
 * construct a ring.
 *
 * The MicroVAX-I doesn't have an I/O map, therefore all addresses presented
 * to devices must be physical address. To keep track of mbufs in use the
 * softc for this device has to record the mbufs because  the data addresses
 * in the ring descriptors are physical addresses instead of virtual. With
 * an I/O map this will no longer be necessary and we'll be able to use
 * the mbuf macro's for allocation and deallocation.
 *
 * There must be enough descriptors in the receive ring to map at least 2
 * of the largest size datagrams so that a race condition doesn't occur in
 * the receiver. (~1600/252 bytes)
 *
 */
/*
 * This constant should really be 60 because the qna adds 4 bytes of crc.
 * However when set to 60 our packets are ignored by deuna's , 3coms are
 * okay ??????????????????????????????????????????
 */
#define MINDATA 64



struct qe_softc qe_softc[];

#define	QEADDR	0174440			/* alternate value is 0174460 */
#define	QEVECT	0400			/* arbitrary, for now... */
extern  int	nNQE;			/* initialised in dds.c */


extern struct protosw *iftype_to_proto(), *iffamily_to_proto();
extern long time;
int	qeattach();
struct mbuf *qeget();
#define	QEUNIT(x)	minor(x)
int	qewrun = 0;
int	qeinit(),qeoutput(),qeioctl(), qewatch();
int	qedebug = 0;
extern	hz;
/*
 * Watchdog timeout value, in clicks.  Three times this value
 * is the maximum time for us to decide that the deqna transmit
 * queue is wedged (could be as short as two times this value).
 */
#define	QETIMO	30
 
/*
 * Interface exists: make available by filling in network interface
 * record.  System will initialize the interface when it is ready
 * to accept packets.
 */
static char QEname[] = { 'q', 'e', '\0' };
qeattach(unit, addr, vector)
int unit;
register struct qedevice *addr;
int vector;
{
	register struct qe_softc *sc;
	register struct ifnet *ifp;
	register int i;

	if (badaddr(addr)) {
		printf("qe%d: non-existant address %o\n", unit, addr);
		return;
	}
	sc = &qe_softc[unit];
	ifp = &sc->is_if;

	ifp->if_unit = unit;
	ifp->if_name = QEname;
	ifp->if_mtu = ETHERMTU;
	ifp->if_flags |= IFF_BROADCAST | IFF_DYNPROTO;

	/*
	 * Read the address from the prom and save it.
	 */
	for( i=0 ; i<6 ; i++ ) 
		sc->is_addr[i] = addr->qe_sta_addr[i] & 0xff;  

	/*
	 * Save the vector for initialization at reset time.
	 */
	sc->qe_intvec = vector;
	sc->addr = addr;

	ifp->if_init = qeinit;
	ifp->if_output = qeoutput;
	ifp->if_ioctl = qeioctl;
	ifp->if_reset = 0;
	if_attach(ifp);
}

/*
 * Initialization of interface and allocation of mbufs for receive ring
 * buffers.
 */
qeinit(unit)
	int unit;
{
	register struct qe_softc *sc = &qe_softc[unit];
	register struct qedevice *addr = sc->addr;
	register struct ifnet *ifp = &sc->is_if;
/*	char (*setup_pkt)[8]; */
	char setup_pkt[16][8];
	int i, s;

	/* address not known */
	/* DECnet must set this somewhere to make device happy */
	if (ifp->if_addrlist == (struct ifaddr *)0)
		return;

	/*
	 * Initialize the transmit and receive rings.
	 */
	initring(sc->rring, sc->rmbuf, NRECV, QEALLOC);
	initring(sc->tring, sc->tmbuf, NXMIT, QENOALLOC);

	sc->nxmit = 0;
	sc->timeout = 0;
	sc->otindex = 0;
	sc->tindex = 0;
	sc->rindex = 0;

	/*
	 * Take the interface out of reset, program the vector, 
	 * enable interrupts, and tell the world we are up.
	 */
	s = splimp();
	addr->qe_vector = sc->qe_intvec;
	if (ifp->if_flags & IFF_LOOPBACK)
		addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ELOOP;
	else
		addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP;
	addr->qe_rcvlist_lo = &sc->rring[sc->rindex];
	addr->qe_rcvlist_hi = 0;
	ifp->if_flags |= IFF_UP | IFF_RUNNING;
	/*
	 * Get the addr off of the interface and place it into the setup
	 * packet. This code looks strange due to the fact that the address
	 * is placed in the setup packet in col. major order. 
	 */
/*
	setup_pkt = (char (*)[8])m_sget(16*8, 0);
	if (setup_pkt == NULL)
		panic("qe_setup");
 */
	for( i = 0 ; i < 6 ; i++ )
		setup_pkt[i][1] = addr->qe_sta_addr[i];
	qesetup(sc, setup_pkt);
	qeissuesetup(sc, "qeinit", setup_pkt);
/*
	MSFREE(setup_pkt);
*/
	qestart( unit );
	sc->ztime = time;
	splx( s );

}

/*
 * Initialize a bdl ring, possibly allocating mbufs
 * on the way.
 */
static
initring(rp, mbp, cnt, option)
register struct qe_ring *rp;
register struct mbuf **mbp;
register int cnt, option;
{
	struct qe_ring *orp = rp;

	do {
		qeinitdesc(rp++, mbp++, option, NULL);
	} while (--cnt > 0);
	qeinitdesc(rp, mbp, QENOALLOC, NULL);
	rp->qe_addr_lo = orp;
	rp->qe_addr_hi = 0;
	rp->qe_chain = 1;
	rp->qe_valid = 1;
}
 
/*
 * Start output on interface.
 *
 */
static
qestart(dev)
	dev_t dev;
{
        int unit = QEUNIT(dev);
	register struct qe_softc *sc = &qe_softc[unit];
	register struct qedevice *addr;
	register struct qe_ring *rp;
	struct mbuf *m;
	int desc_needed, i, buf_addr, len, j, tlen, s, diff;

	/*
	 * Check for enough transmit descriptors to map
	 * this datagram onto the interface. If there will never be enough
	 * throw the packet away and complain. If there will be enough but
	 * there aren't right now just return and if there are enough now,
	 * setup one or more descriptors to map the packet onto the interface 
	 * and start it.
	 *
	 * The deqna doesn't look at anything but the valid bit to determine
	 * if it should transmit this packet.  If you fill the ring, the
	 * device will loop indefinately and flood the network with packets
	 * until the ring is broken.  So, we always make sure there is at
	 * least one empty descriptor.
	 */
	s = splimp();
	if( (m = sc->is_if.if_snd.ifq_head) == 0 ){
		splx( s );
		return;				/* Nothing on the queue	*/
	}

	for( desc_needed = 0 ; m ; m = m->m_next )
		desc_needed++;

	if( desc_needed > NXMIT-1 )
		panic("qe: xmit packet too big");

	/*
	 * See if the required descriptors are available.
	 */
	addr = sc->addr;
	i = 0;
	j = sc->tindex;
	while( sc->tring[j].qe_valid == 0 && i <= desc_needed ) {
		i++;
		j = ++j % NXMIT;
	}

	/*
	 * Fred Canter -- 2/20/86
	 * Following allowed qestart() to overrun the xmit ring.
	 * This caused the orphaned mbuf problem.
	 */
/*	if( desc_needed > i+1 ) {	BOGUS!  */
	if((desc_needed+1) > i) {
		splx( s );
		return;
	}

	/*
	 * Record the chain head, attach each mbuf data area to a 
	 * descriptor and start the QNA if the transmit list is invalid.
	 */
	IF_DEQUEUE(&sc->is_if.if_snd, m);
	/*
	 * Save the chain head so that we can deallocate it after the
	 * i/o is done. This will not be necessary when we have an i/o map
	 * because we can use virtual addresses ?
	 */
	for(i=sc->tindex, sc->tmbuf[i]=m, tlen=0 ; m ; m=m->m_next, i = ++i % NXMIT){
		rp = &sc->tring[i];
		len = m->m_len;

		/*
		 *  Does buffer end on odd byte ? 
		 */
		if( len & 1 ) {
			len++;
			rp->qe_odd_end = 1;
		}
		tlen += len;
		rp->qe_buf_len = -(len/2);
		rp->qe_addr_lo = (ctob(m->m_click)&~077) + m->m_off;
		rp->qe_addr_hi = (m->m_click >> 10) & 077;
		if( m->m_next == NULL ) {
			/*
			 * Make sure we don't send a runt.
			 */
			if( tlen < MINDATA ) {
				diff = MINDATA - tlen;
				if( (len + diff + m->m_off) <= MMAXOFF ) {
					rp->qe_buf_len = -(len + diff)/2;
					tlen += diff;
				} else {
					/*
					 * This packet is too short.  Grab
					 * another descriptor, and point it
					 * to arbitrary data, just so that
					 * we can fill up to the minimum
					 * length.  This should probabaly be
					 * an empty buffer, not low core, but
					 * no one should look at it anyway...
					 */
					i = ++i % NXMIT;
					rp = &sc->tring[i];
					if( diff & 1 )
						diff++;
					rp->qe_buf_len = -(diff/2);
					rp->qe_addr_lo = 0;
					rp->qe_addr_hi = 0;
				}
			}
			rp->qe_eomsg = 1;
			rp->qe_valid = 1;
			/*
			 * Last descriptor !! If the QNA is running it could
			 * beat us down the list if we set the valid address 
			 * bits in the forward order, so we do it backwards.
			 */
			for( j = i ; j != sc->tindex ; ) {
				j = --j >= 0 ? j : NXMIT;
				sc->tring[j].qe_valid = 1;
			}
			sc->nxmit++;
			/* a few statistics */
			if ((sc->ctrblk.est_bytesent += len) < len)
				sc->ctrblk.est_bytesent -= len;
			if (++sc->ctrblk.est_bloksent == 0)
				--sc->ctrblk.est_bloksent;
		}
	}
	/*
	 * If the watchdog time isn't running kick it.
	 */
	sc->timeout = 1;
	if (!qewrun++)
		timeout(qewatch, 0, QETIMO);
	/*
	 * See if the xmit list is invalid.
	 */
	if( addr->qe_csr & QE_XL_INVALID ) {
		addr->qe_xmtlist_lo = &sc->tring[sc->tindex];
		addr->qe_xmtlist_hi = 0;
	}
	sc->tindex = i;
	splx( s );
}
 
/*
 * Ethernet interface interrupt processor
 */

qeint(unit)
int unit;
{
	register struct qe_softc *sc;
	struct qedevice *addr;
	int s, csr;
	mapinfo map;
/*@*/	extern char *panicstr;

/*@*/	if (panicstr)
/*@*/		return;
	unit = minor(unit);
	sc = &qe_softc[unit];
	addr = sc->addr;
	csr = addr->qe_csr;
	if (sc->is_if.if_flags & IFF_LOOPBACK)
		addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ELOOP;
	else
		addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP;
	savemap(map);
	if (csr & QE_RCV_INT)
		qerint(unit);
	if (csr & QE_NEX_MEM_INT)
		printf("qe%d: NXM intr\n", unit);
	else if (csr & QE_XMIT_INT)
		qetint(unit);
	
	if (addr->qe_csr & QE_RL_INVALID && sc->rring[sc->rindex].qe_status1 == QE_NOTYET) {

		addr->qe_rcvlist_lo = (int)&sc->rring[sc->rindex];
		addr->qe_rcvlist_hi = 0;
	}
	restormap(map);
}
 
/*
 * Ethernet interface transmit interrupt.
 */
static
qetint(unit)
	int unit;
{
	register struct qe_softc *sc = &qe_softc[unit];
	register struct mbuf *mp;
	register first, index;
	int i, len, status1;
/*	int	status2;	removed, was not used */

	while (sc->otindex != sc->tindex &&
	       sc->tring[sc->otindex].qe_status1 != QE_NOTYET) {
		/*
		 * Find the index of the last descriptor in this 
		 * packet. ( LASTNOT will be clear ) If we can't find one
		 * then the QNA is still working on it. This is necessary
		 * for subsequent passes because we can't be sure that the
		 * QNA is through with a descriptor until we find the last
		 * in the chain.
		 */
		first = index = sc->otindex;
		while (sc->tring[index].qe_valid && !sc->tring[index].qe_eomsg)
			index = ++index % NXMIT;
		/*
		 * Is the QNA done with this packet ?
		 */
		if (sc->tring[index].qe_status1 == QE_NOTYET)
			break;
		/*
		 * Save the status words from the descriptor so that it can
		 * be released.
		 */
		status1 = sc->tring[index].qe_status1;
/*		status2 = sc->tring[index].qe_status2;	not used */
		mp = sc->tmbuf[first];

		qeinitdesc(&sc->tring[first], &sc->tmbuf[first], QENOALLOC, NULL);
		if (--sc->nxmit == 0)
			sc->timeout = 0;
		if (first == NXMIT-1)
			sc->tring[NXMIT].qe_flag = QE_NOTYET;
		while (first != index) {
			first = ++first % NXMIT;
			qeinitdesc(&sc->tring[first], &sc->tmbuf[first], QENOALLOC, NULL);
			if (first == NXMIT-1)
				sc->tring[NXMIT].qe_flag = QE_NOTYET;
		}
		sc->otindex = ++index % NXMIT;

		/*
		 * Do some statistics.
		 */
		sc->is_if.if_opackets++;
		if (status1 & QE_CCNT) {
			i = (status1 & QE_CCNT) >> 4;
			sc->is_if.if_collisions += i;
			if (i == 1) {
				if (++sc->ctrblk.est_single == 0)
					--sc->ctrblk.est_single;
			} else {
				if (++sc->ctrblk.est_multiple == 0)
					--sc->ctrblk.est_multiple;
			}
		}
		if (status1 & QE_FAIL)
			if (++sc->ctrblk.est_collis == 0)
				--sc->ctrblk.est_collis;
		if (status1 & QE_ERROR) { 
			sc->is_if.if_oerrors++;
			if (++sc->ctrblk.est_sendfail == 0)
				--sc->ctrblk.est_sendfail;
			else {
				if (status1 & QE_ABORT)
					sc->ctrblk.est_sendfail_bm |= 1;
				if (status1 & QE_NOCAR)
					sc->ctrblk.est_sendfail_bm |= 2;
			}
			m_freem(mp);
		} else if (mp) {
			/*
			 * The QNA doesn't hear it's own packets. Unfortunately
			 * the code above us expects to hear all broadcast 
			 * traffic including our own. Therefore if this is a
			 * broadcast packet we have to loop it back,
			 * otherwise we simply free the packets.
			 */
			{
				register short *p;
				segm	map5;

				saveseg5(map5);
				p = (int *)(mtod(mp, struct ether_header *)
					->ether_dhost);
				i = *p++ == -1 && *p++ == -1 && *p == -1;
				restorseg5(map5);
			}
			if (i) {
				register struct mbuf *mp0;
				for (mp0 = mp, len=0; mp0; mp0 = mp0->m_next)
					len += mp0->m_len;
				qerecv(sc, mp, len);
			} else	
				m_freem(mp);
		}
	}
	qestart(unit);
}
 
struct foob {
	unsigned char lo;
	unsigned char hi;
};
#define	lobyte(x)	(((struct foob *)&(x))->lo)
#define	hibyte(x)	(((struct foob *)&(x))->hi)
/*
 * Ethernet interface receiver interrupt.
 * If can't determine length from type, then have to drop packet.  
 * Othewise decapsulate packet based on type and pass to type specific 
 * higher-level input routine.
 *	Fred Canter -- 2/20/86
 *	Serach the entire receive ring for a completed message
 *	instead of depending on the DEQNA to always put the next
 *	message in the descriptor pointed to by sc->rindex.
 *	Looks like this fixed the "winking out" problem.
 */
int	qe_search = 1;
static
qerint(unit)
	int unit;
{
	register struct qe_softc *sc = &qe_softc[unit];
    	struct mbuf *m, *n;
	int len, index, first, status1, status2, resid, drop;
	struct mbuf tmb;
	int	orindex, i;

	/*
	 * If qe_search set, find where the DEANA really put
	 * the next message (sometimes not where we expect).
	 */
	orindex = sc->rindex;
	i = sc->rindex;
	while(1) {
		if(qe_search == 0)
			break;
		if(sc->rring[i].qe_status1 != QE_NOTYET) {
			sc->rindex = i;
			break;
		}
		i = ++i % NRECV;
		if(i == orindex)
			return;
	}
	/*
	 * Traverse the receive ring looking for packets to pass back.
	 * The search is complete when we find a descriptor not in use.
	 */
	while ( sc->rring[sc->rindex].qe_status1 != QE_NOTYET ) {
		/*
		 * Find the index of the last descriptor in this 
		 * packet. ( LASTNOT will be clear ) If we can't find one
		 * then the QNA is still working on it.
		 */
		first = index = sc->rindex;

		while( (sc->rring[index].qe_status1 & QE_MASK) == QE_MASK )
			index = ++index % NRECV;
		/*
		 * If we found an unused descriptor we've beat the QNA 
		 */
		if( sc->rring[index].qe_status1 == QE_NOTYET )
			break;
		/*
		 * Save the status words from the descriptor so that it can
		 * be released. This thing isn't valid unless the low and
		 * high bytes are the same.
		 */
		status2 = sc->rring[index].qe_status2;
		if (lobyte(status2) != hibyte(status2))
			break;
		status1 = sc->rring[index].qe_status1;
		sc->is_if.if_ipackets++;
		/*
		 * Link the mbufs together, reinitialize the descriptors and
		 * pass the mbuf chain off to qerecv if status is okay.
		 */
		n = &tmb;
		drop = 0;
		for (;;) {
			m = sc->rmbuf[first];
			if (qeinitdesc(&sc->rring[first], &sc->rmbuf[first],
							QEALLOC, m)) {
				n->m_next = m;
				n = m;
			} else
				drop++;
/* see qeinitdesc()	sc->rring[first].qe_status2 = 1;	*/
			if (first == NRECV - 1)
				sc->rring[NRECV].qe_flag = QE_NOTYET;
			if (first == index)
				break;
			first = ++first % NRECV;
		}
		if ((sc->rindex = ++first % NRECV) == NRECV - 1)
			sc->rring[NRECV].qe_flag = QE_NOTYET;
		n->m_next = 0;
		m = tmb.m_next;
		/*
		 * If this was a setup packet, discard it.
		 */
		if (status1 & QE_ESETUP) {
			if (qedebug)
				printf("qe%d: setup pkt\n", unit);
			m_freem( m );
			continue;
		}
		if (drop) {
			sc->is_if.if_ierrors++;
			m_freem( m );
			if (qedebug)
				printf("qe%d: pkt drop\n", unit);
			continue;
		}
		/*
		 * If there was an error discard it.
		 */
		if (status1 & QE_ERROR) {
			sc->is_if.if_ierrors++;
			m_freem( m );
			if (status1&QE_DISCARD) {
				sc->ctrblk.est_recvfail++;
				if (status1&QE_CRCERR) {
					sc->ctrblk.est_recvfail_bm |= 1;
					if (status1&QE_FRAME)
						sc->ctrblk.est_recvfail_bm |= 2;
				}
				if (status1&QE_OVF)
					sc->ctrblk.est_recvfail_bm |= 4;
				if (qedebug) {
				    if (status1&QE_SHORT)
					printf("qe%d: short pkt\n", unit);
				    if (status1&QE_RUNT)
					printf("qe%d: runt pkt\n", unit);
				}
			} else if (qedebug) {
				if (status1&QE_RUNT)
					printf("qe%d: runt pkt\n", unit);
				else
					printf("qe%d: long pkt\n", unit);
			}
			continue;
		}
		/*
		 * Get the actual length and compute the size of data in the
		 * last mbuf. The hardware doesn't have time to count the first
		 * 60 bytes because it is doing address filtering so we add 60.
		 */
		len = ((status1 & QE_RBL_HI) | (status2 & QE_RBL_LO)) + 60;
		sc->ctrblk.est_bytercvd += len;
		sc->ctrblk.est_blokrcvd++;

		/*
		 * The last mbuf may not be full so we have to set the correct 
		 * length in it.
		 */
		if( resid = len % MLEN )
			n->m_len = resid;
		qerecv( sc, m, len );
	}
}
 
/*
 * Process a packet.
 */
static
qerecv( sc, m, len )
	struct qe_softc *sc;
	struct mbuf *m;
	int len;
{
    	register struct mbuf *mp;
	int off, resid, index;
	struct ifqueue *inq;
	register int type;
	struct protosw *pr;
	segm	map5;

	/*
	 * Deal with trailer protocol: If type is PUP trailer
	 * get true type from first 16-bit word past data.
	 * Remember that type was trailer by setting off.
	 */
	saveseg5(map5);
	type = ntohs(mtod(m, struct ether_header *)->ether_type);
	restorseg5(map5);
	if (type >= ETHERTYPE_TRAIL &&
	    type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
		off = ((type - ETHERTYPE_TRAIL) * 512) + sizeof(struct ether_header);;
		if (off >= ETHERMTU) 
			goto bad;		/* sanity */

		for (index=0, mp=m; mp && (index + mp->m_len) <= off; ) {
			index += mp->m_len;
			mp = mp->m_next;
		}
		if (mp) {
			register u_short *p;
			p = mtod(mp, caddr_t) + (off-index);
			type = ntohs(*p++);
			resid = ntohs(*p);
			restorseg5(map5);
		} else 
			goto bad;
		 
		if (off + resid > len) 
			goto bad;		/* sanity */

		len = off + resid;
	} else
		off = 0;
	if (len == 0)
		goto bad;

	/*
	 * Pull packet off interface.  Off is nonzero if packet
	 * has trailing header; qeget will then force this header
	 * information to be at the front, but we still have to drop
	 * the type and length words which are at the front of any trailer data.
	 */
	if (off) {
		if ((m = qeget(m, mp, off-index)) == 0) 
			return;
		 
		m->m_off += 2 * sizeof(u_short);
		m->m_len -= 2 * sizeof(u_short);
	} else {
		m->m_off += sizeof(struct ether_header);
		m->m_len -= sizeof(struct ether_header);
	}
	switch (type) {
#ifdef INET
	case ETHERTYPE_IP:
		schednetisr(NETISR_IP);
		inq = &ipintrq;
		break;

	case ETHERTYPE_ARP:
		arpinput(&sc->is_ac, m);
		return;
#endif
	default:
		/*
		 * See if other protocol families are defined and
		 * call protocol specific routines. If no other
		 * protocol families are defined then dump the message.
		 */
		if (pr = iftype_to_proto(type))
			(*pr->pr_ifinput)( m, &sc->is_if, &inq);
		else {
			if (++sc->ctrblk.est_unrecog == 0)
				--sc->ctrblk.est_unrecog;
			m_freem(m);
			return;
		}
	}

	if (IF_QFULL(inq)) {
		IF_DROP(inq);
		m_freem(m);
		return;
	}
	IF_ENQUEUE(inq, m);
	return;

	/*
	 * If the packet format looks like a trailer but is currupt we exit here
	 * after releasing the mbuf.
	 */
bad:
	m_freem(m);
	return;
}
 

/*
 * Ethernet output routine.
 * Encapsulate a packet of type family for the local net.
 * Use trailer local net encapsulation if enough data in first
 * packet leaves a multiple of 512 bytes of data in remainder.
 */
qeoutput(ifp, m0, dst)
	struct ifnet *ifp;
	struct mbuf *m0;
	struct sockaddr *dst;
{
	int type, s, error;
	u_char edst[6];
	struct in_addr idst;
	struct protosw *pr;
	register struct qe_softc *is = &qe_softc[ifp->if_unit];
	register struct mbuf *m = m0;
	register struct ether_header *eh;
	register int off;
	segm	map5;

	saveseg5(map5);
	switch (dst->sa_family) {

#ifdef INET
	case AF_INET:
		idst = ((struct sockaddr_in *)dst)->sin_addr;
		if (!arpresolve(&is->is_ac, m, &idst, edst))
			return (0);	/* if not yet resolved */
		/* need per host negotiation */
		if ((ifp->if_flags & IFF_NOTRAILERS) == 0) {
		    off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
		    if (off > 0 && (off & 0x1ff) == 0 &&
			    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
			u_short *p;

			type = ETHERTYPE_TRAIL + (off>>9);
			m->m_off -= 2 * sizeof (u_short);
			m->m_len += 2 * sizeof (u_short);
			p = mtod(m, u_short *);
			*p++ = HTONS(ETHERTYPE_IP);
			*p = htons(m->m_len);
			goto gottraqeertype;
		    }
		}
		type = ETHERTYPE_IP;
		off = 0;
		goto gottype;
#endif

	case AF_UNSPEC:
		eh = (struct ether_header *)dst->sa_data;
		bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
		type = eh->ether_type;
		goto gottype;

	default:
		/*
		 * Try to find other address families and call protocol
		 * specific output routine.
		 */
		if (pr = iffamily_to_proto(dst->sa_family)) {
			(*pr->pr_ifoutput)(ifp, m0, dst, &type, (char *)edst);
			goto gottype;
		} else {
			printf("qe%d: can't handle af%d\n", ifp->if_unit,
				dst->sa_family);
			error = EAFNOSUPPORT;
			goto bad;
		}
	}

gottraqeertype:
	/*
	 * Packet to be sent as 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 net header.  If no space in first mbuf,
	 * allocate another.
	 */
	if (m->m_off > MMAXOFF || MMINOFF + sizeof (struct ether_header) > m->m_off) {
		m = m_get(M_DONTWAIT, MT_HEADER);
		if (m == 0) {
			error = ENOBUFS;
			goto bad;
		}
		m->m_next = m0;
		m->m_off = MMINOFF;
		m->m_len = sizeof (struct ether_header);
	} else {
		m->m_off -= sizeof (struct ether_header);
		m->m_len += sizeof (struct ether_header);
	}
	eh = mtod(m, struct ether_header *);
	eh->ether_type = htons((u_short)type);
	bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
	bcopy((caddr_t)is->is_addr, (caddr_t)eh->ether_shost, sizeof (is->is_addr));
	restorseg5(map5);

	/*
	 * 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);
		splx(s);
		m_freem(m);
		return (ENOBUFS);
	}
	IF_ENQUEUE(&ifp->if_snd, m);
	qestart(ifp->if_unit);
	splx(s);
	return (0);

bad:
	restorseg5(map5);
	m_freem(m0);
	return (error);
}
 

/*
 * Process an ioctl request.
 */
qeioctl(ifp, cmd, data)
	register struct ifnet *ifp;
	int cmd;
	caddr_t data;
{
	struct qe_softc *sc = &qe_softc[ifp->if_unit];
	struct sockaddr *sa;
	struct sockaddr_in *sin;
	struct ifreq *ifr = (struct ifreq *)data;
	struct protosw *pr;
	int i,s = splimp(), error = 0;
	struct ifaddr *ifa = (struct ifaddr *)data;

	switch (cmd) {

	case SIOCSPHYSADDR:
	    {
/*
		char (*setup_pkt)[8];
*/
		char setup_pkt[16][8];

		/*
		 * Before we do anything, make sure we can get the
		 * data space if we need it.
		 */
/*
		if (ifp->if_flags & IFF_RUNNING) {
			setup_pkt = (char (*)[8])m_sget(16*8, 0);
			if (setup_pkt == NULL) {
				splx(s);
				return(ENOBUFS);
			}
		}
*/
		bcopy(ifr->ifr_addr.sa_data, &sc->is_addr, sizeof(sc->is_addr));
		if (ifp->if_flags & IFF_RUNNING) {
			for (i = 0; i < 6; i++)
			    setup_pkt[i][1] = sc->is_addr[i];
			qesetup(sc, setup_pkt);
			qeissuesetup(sc, "SIOCPHYSADDR", setup_pkt);
#ifdef	notdef
			if_rtinit(ifp, -1);
#endif
/*
			MSFREE(setup_pkt);
*/
		}
		qeinit(ifp->if_unit);
		break;
	    }

	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;
		qeinit(ifp->if_unit);
		switch(ifa->ifa_addr.sa_family) {
#ifdef	INET
		case AF_INET:
			((struct arpcom *)ifp)->ac_ipaddr =
				IA_SIN(ifa)->sin_addr;
			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
			break;
#endif
#ifdef	NS
		case AF_NS:
		    {
			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);

			if (ns_nullhost(*ina)) {
				ina->x_host = * (union ns_host *)
					(qe_softc[ifp->if_unit].qe_addr);
			} else {
				qe_setaddr(ina->x_host.c_host, ifp->if_unit);
			}
			break;
		    }
#endif
		default:
			if (pr=iffamily_to_proto(ifa->ifa_addr.sa_family)) {
				error = (*pr->pr_ifioctl)(ifp, cmd, data);
			}
			break;
		}
		break;

	default:
		error = EINVAL;
	}
done:	splx(s);
	return (error);
}

/*
 * Initialize a ring descriptor with mbuf allocation side effects
 * If we are allocating, and mp2 is non-null, then use it if we
 * can't allocate a new mbuf.  The return value indicates whether
 * or not we used mp2.
 */
static
qeinitdesc(rp, mp, option, mp2)
register struct qe_ring *rp;
register struct mbuf **mp;
int option;
struct mbuf *mp2;
{
	/*
	 * clear the entire descriptor
	 */
	bzero(rp, sizeof(*rp));

	rp->qe_flag = rp->qe_status1 = QE_NOTYET;
	rp->qe_status2 = 0xff00;

	/*
	 * Perform the necessary allocation/deallocation
	 */
	if (option == QENOALLOC)
		*mp = NULL;
	else {
		register struct mbuf *m;

		if ((option == QEALLOC) || ((m = *mp) == NULL))
			MGET(m, M_DONTWAIT, MT_DATA);
		if (m == 0) {
		    if ((m = mp2) == 0)
			panic("qe: no mbufs for desc ring");
		}
		*mp = m;
		rp->qe_buf_len = -(MLEN/2);
		m->m_len = MLEN; 
		m->m_off = MMINOFF;
		rp->qe_addr_lo = (ctob(m->m_click)&~077) + m->m_off;
		rp->qe_addr_hi = (m->m_click >> 10) & 077;
		/*
		 * Must be last. QNA could be listening.
		 */
		rp->qe_valid = 1;
		return(m != mp2);
	}
	return(1);
}
 

/*
 * Pull the trailer info up to the front of the chain.
 */
static struct mbuf *
qeget(m, mtp, off)
register struct mbuf 	*m;	/* Pointer to first mbuf in the chain 	*/
register struct mbuf	*mtp;	/* Pointer to first mbuf in trailer	*/
int			off;	/* Offset to trailer in trailer mbuf	*/
{
	register struct mbuf	*mp;
	struct mbuf		*mp0;

	/*
	 * The trailer consists of 2 words followed by an IP header.
	 * The rest of the code assumes that the trailer is enclosed in
	 * a single mbuf. In our case the trailer spans two mbufs so it
	 * has to be packed back into a single packet so that other routines
	 * can access it as a structure.
	 */
	MGET(mp, M_DONTWAIT, MT_DATA);
	if (mp == NULL) {
		m_freem(m);
		return(0);
	}
	mp->m_off = MMINOFF;
	/*
	 * Copy the portion of the trailer in this mbuf to the new
	 * mbuf and adjust the length. This mbuf now becomes the last
	 * in the packet.
	 */
	MBCOPY(mtp, off, mp, 0, mtp->m_len - off);
	mp->m_len = mtp->m_len - off;
	mtp->m_len = off;
	mp0 = mtp;			/* Save so we can break the chain */
	/*
	 * The remainder of the trailer is in the next mbuf.
	 */
	mtp = mtp->m_next;
	if (mtp) {
		if (mtp->m_len + mp->m_len > MLEN || mtp->m_next) {
			/*
			 * Can't fit trailer in an mbuf. Must be insane.
			 */
			m_freem(m);
			m_freem(mp);
			return(0);
		}
		/*
		 * Pull the data up, break the chain and release the old
		 * trailer.
		 */
		MBCOPY(mtp, 0, mp, mp->m_len, mtp->m_len);
		mp->m_len += mtp->m_len;
		mp0->m_next = NULL;	/* Break the chain		*/
		m_freem(mtp);
	}

	/*
	 * Move the new trailer to the head of the packet and remove the 
	 * ethernet header.
	 */
	mp->m_next = m;
	m->m_off += sizeof (struct ether_header);
	m->m_len -= sizeof (struct ether_header);
	return(mp);
}

/*
 * Build a setup packet - the physical address will already be present
 * in first column.
 */
static
qesetup(sc, setup_pkt)
struct qe_softc *sc;
char setup_pkt[16][8];
{
    register int i,j;

    /*
     * Copy the target address to the rest of the entries in this row.
     */
     for (j = 0; j < 6; j++)
	    for (i = 2; i < 8; i++)
		    setup_pkt[j][i] = setup_pkt[j][1];
    /*
     * Duplicate the first half.
     */
    bcopy(setup_pkt, setup_pkt[8], 64);
    /*
     * Fill in the broadcast address.
     */
    for (i = 0; i < 6; i++)
	    setup_pkt[i][2] = 0xff;
}

/*
 * Issue a setup packet to the QNA and wait for it's completion. Report an
 * error if we can't immediately get the transmit ring entry to send the
 * setup packet or if the transmission fails.
 */
static
qeissuesetup(sc, cmdname, setup_pkt)
struct qe_softc *sc;
char *cmdname;
char setup_pkt[16][8];
{
    register struct qe_ring *rp = (struct qe_ring *)&sc->tring[sc->tindex];
    struct qedevice *addr = sc->addr;

    if (rp->qe_valid == 0) {
	    sc->tmbuf[sc->tindex] = 0;
	    if (setup_pkt >= 0140000) {
		    /* packet is on stack, get 22 bit address */
		    long paddr;
		    paddr = ctob((long)*KDSA6) + (long)setup_pkt - 0140000L;
		    rp->qe_addr_lo = (int)(paddr&0177777);
		    rp->qe_addr_hi = (int)((paddr>>16)&077);
	    } else {
		    rp->qe_addr_lo = setup_pkt;
		    rp->qe_addr_hi = 0;
	    }
	    rp->qe_buf_len = -64;
	    rp->qe_setup = 1;
	    rp->qe_eomsg = 1;
	    rp->qe_valid = 1;

	    if (addr->qe_csr & QE_XL_INVALID) {
		    addr->qe_xmtlist_lo = rp;
		    addr->qe_xmtlist_hi = 0;
	    }
	    sc->nxmit++;
	    sc->tindex = ++sc->tindex % NXMIT;
	    while (rp->qe_status1 == QE_NOTYET)
		    ;
	    /*
	     * Avoid an obscure race condition with the hardware continueing
	     * around the transmit ring and finding this setup packet again.
	     */
	    rp->qe_setup = 0;
    } else {
	    printf("qe%d: %s failed: no ring entry\n", sc->is_if.if_unit, cmdname);
    }
}

qewatch()
{
	register struct	qe_softc *sc;
	register int i, inprogress = 0;

	for (sc = &qe_softc[0], i = nNQE; i ; --i) {
		if (sc->timeout) {
			if (++sc->timeout > 3)
				qerestart(sc);
			else
				inprogress++;
		}
		sc++;
	}
	if (inprogress) {
		timeout(qewatch, 0, QETIMO);
		qewrun++;
	} else
		qewrun = 0;
}

/*
 * Fred Canter -- 2/20/86
 * On a qerestart, if qe_xfree is set free all mbufs
 * on the transmit ring, otherwise re-transmit them.
 * Freeing is the recommended approach.
 */
int	qe_xfree = 1;
int	qe_restarts;	/* number of qerestarts since boot */

static
qerestart(sc)
register struct qe_softc *sc;
{
	register struct ifnet *ifp = &sc->is_if;
	register struct qedevice *addr = sc->addr;
	char setup_pkt[16][8];
	register i;

	/*
	 * 1. Reset the device.
	 * 2. Clean out the transmit ring, and put all the pending
	 *    transmits back on the send queue.  We do this in
	 *    reverse order, and stick them at the front of the queue.
	 * 3. Clean out and re-allocate the receive ring, making
	 *    sure that we free up any mbufs that don't get re-used!
	 * 4. Turn on interrupts, validate the receive ring, and
	 *    issue a setup packet.
	 * 5. Restart the device.
	 */
	addr->qe_csr = QE_RESET;
	/*
	 * Clear of CSR added at the request of hardware
	 * engineering, so the DELQA can be bug for bug
	 * compatible with the DEQNA.
	 * 1/28/86 -- Fred Canter
	 */
	addr->qe_csr = 0;
	sc->timeout = 0;
	qe_restarts++;

	if(qe_xfree == 1) {
	    for(i=0; i<NXMIT; i++) {
		register struct mbuf *m;
		if (m = sc->tmbuf[i])
			m_freem(m);
	    }
	}
	if(qe_xfree == 0) {
	    i = sc->tindex;
	    do {
		register struct mbuf *m;
		if ( --i < 0)
			i = NXMIT - 1;
		if (m = sc->tmbuf[i])
			IF_PREPEND(&ifp->if_snd, m);
	    } while(i != sc->otindex);
	}
	initring(sc->tring, sc->tmbuf, NXMIT, QENOALLOC);
	initring(sc->rring, sc->rmbuf, NRECV, QEREALLOC);

	sc->nxmit = sc->otindex = sc->tindex = sc->rindex = 0;

	if (ifp->if_flags & IFF_LOOPBACK)
		addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT |
							QE_RCV_INT | QE_ELOOP;
	else
		addr->qe_csr = QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT |
							QE_RCV_INT | QE_ILOOP;
	addr->qe_rcvlist_lo = &sc->rring[0];
	addr->qe_rcvlist_hi = 0;

	for( i = 0 ; i < 6 ; i++ )
		setup_pkt[i][1] = sc->is_addr[i];
	qesetup(sc, setup_pkt);
	qeissuesetup(sc, "qerestart", setup_pkt);
	qestart(ifp->if_unit);
	if (qedebug)
		printf("qerestart: restarted qe%d\n", ifp->if_unit);
}