File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / tahoeif / if_ace.lp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:24:19 2019 UTC (6 years, 11 months ago) by root
Branches: bsd, MAIN
CVS tags: v12b, v121, HEAD
Power 6/32 Unix version 1.2b

/*								*/
/*	if_ace: ACC VERSAbus Ethernet controler (v/eiu)		*/
/*								*/

#include "ace.h"
#define	ACEBPTE	64
#if NACE > 0
#define	ACEDEBUG

#include "../machine/pte.h"

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/mbuf.h"
#include "../h/buf.h"
#include "../h/protosw.h"
#include "../h/socket.h"
#include "../h/vmmac.h"
#include "../h/ioctl.h"
#include "../h/errno.h"

#include "../net/if.h"
#define	LONET	127
#include "../net/netisr.h"
#include "../net/route.h"
#include "../netinet/in.h"
#include "../netinet/in_systm.h"
#include "../netinet/ip.h"
#include "../netinet/ip_var.h"
#include "../netinet/if_ether.h"
#include "../netpup/pup.h"

#include "../machine/mtpr.h"
#include "../tahoeif/if_ace.h"
#include "../tahoeif/if_acereg.h"
#define	LOHOST	2			/* no conflict with loop	*/
#include "../vba/vbavar.h"
#define	TRUE	1
#define	FALSE	0

				/* configuration table, for 2 units	*/
				/*  should be defined by config		*/
#define	ACEVECTOR	0x90
long	acestd[] = { 0x0ff0000, 0xff0100 };		/* controller	*/
extern	char	ace0utl[], ace1utl[];			/* dpm		*/
char	*acemap[]= { ace0utl, ace1utl };
extern	long	ACE0map[], ACE1map[];
long	*ACEmap[] = {ACE0map, ACE1map };
long	ACEmapa[] = {0xff780000,0xff790000};
char	ace_station[6*NACE] = {				/* addresses	*/
	~0x8,~0x0,~0x3,~0x0,~0x0,~0x1,
#if	(NACE > 1)
	~0x8,~0x0,~0x3,~0x0,~0x0,~0x2,
#if	(NACE > 2)
	~0x8,~0x0,~0x3,~0x0,~0x0,~0x3,
	~0x8,~0x0,~0x3,~0x0,~0x0,~0x4,
#endif	(NACE > 2)
#endif	(NACE > 1)
};

char ace_hash_code[8*NACE]={				/* hash tables	*/
	~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,/*u 0*/
#if	(NACE > 1)
        ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,/*u 1*/
#if	(NACE > 2)
        ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,/*u 2*/
        ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF /*u 3*/
#endif	(NACE > 2)
#endif	(NACE > 1)
}; 

short random_mask_tbl[16] = {				/* backoff table*/
	0x0040, 0x00C0, 0x01C0, 0x03C0, 
        0x07C0, 0x0FC0, 0x1FC0, 0x3FC0,
        0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0,
        0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0  };

int	aceprobe(), aceattach(), acerint(), acecint();
struct	vba_device *aceinfo[NACE];
struct	vba_driver acedriver =
	{ aceprobe, 0,aceattach,0,acestd,"ace",aceinfo,"v/eiu",0 };
	
#define	ACEUNIT(x)	minor(x)
int	aceinit(),aceoutput(),aceioctl(),acereset();
struct	mbuf *aceget();

/*
 * 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, ...
 */
struct	ace_softc {
	struct	arpcom is_ac;		/* Ethernet common part		*/
#define	is_if	is_ac.ac_if		/* network-visible interface	*/
#define	is_addr	is_ac.ac_enaddr		/* hardware Ethernet address	*/
	char	*is_dpm;
	short	is_flags;
#define	ACEF_OACTIVE	0x1		/* output is active		*/
#define	ACEF_RCVPENDING	0x2		/* start rcv in acecint		*/
	short	is_promiscuous;		/* true is enabled		*/
	short	is_segboundry;		/* first TX Seg in dpm		*/
	short	is_eictr;		/* Rx segment tracking ctr	*/
	short	is_eoctr;		/* Tx segment tracking ctr	*/
	short	is_txnext;		/* Next available Tx segment	*/
	short	is_currnd;		/* current random backoff	*/
	struct	ace_stats is_stats;	/* holds board statistics	*/
} ace_softc[NACE];

aceprobe(reg)
caddr_t reg;
{
register struct acedevice *addr = (struct acedevice *)reg;
register i;
#ifdef	ACEDEBUG
printf("aceprobe: veiu @%X\n",reg);
#endif	ACEDEBUG

#ifdef lint
	i = 0; acerint(i); acecint(i);
#endif

	if (badaddr(reg,2)) return(0);
	addr->csr = CSR_RESET;
	DELAY(10000);
	return (1);

}


/*
 * Interface exists: make available by filling in network interface
 * record.  System will initialize the interface when it is ready
 * to accept packets.
 */
aceattach(ui)
struct vba_device *ui;
{
register short	unit = ui->ui_unit;
register struct ace_softc *is = &ace_softc[unit];
register struct ifnet *ifp = &is->is_if;
register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
register short *pData0,i;
register char *pData1;
struct sockaddr_in *sin;
#ifdef	ACEDEBUG
printf("ace%dattach: ui %X\n",unit,ui);
#endif	ACEDEBUG

	ifp->if_unit = unit;
	ifp->if_name = "ace";
	ifp->if_mtu = ETHERMTU;

	/*
	 * Reset the board and map the statistics
	 * buffer onto the Unibus.
	 */
	addr->csr = CSR_RESET;
				/* set the station address	*/
	for (pData0 = (short *)addr->rar.station_addr,
	     pData1 = &ace_station[unit * 6], i = 6;
	     --i >= 0;)
	    *(pData0++) = *(pData1++);
				/* Copy to arp structure	*/
	for (pData0 = (short *)addr->rar.station_addr,
	     pData1 = (char *)(is->is_addr), i = 6;
	     --i >= 0;)
	    *(pData1++) = ~(*(pData0++));
#ifdef	ACEDEBUG
printf("ace%d: addr=%x:%x:%x:%x:%x:%x\n",
		unit,
		is->is_addr[0]&0xff, is->is_addr[1]&0xff,
		is->is_addr[2]&0xff, is->is_addr[3]&0xff,
		is->is_addr[4]&0xff, is->is_addr[5]&0xff);
#endif	ACEDEBUG

	is->is_promiscuous = (TRUE)? CSR_PROMISCUOUS: 0;
	for (pData0 = (short *)addr->rar.mcast_hash_code, 
	     pData1 = &ace_hash_code[unit * 8], i =  8;
	     --i >= 0;)
	    *(pData0++) = *(pData1++);

	addr->rar.broadcast_en[0] = ~0xffff;
	addr->rar.broadcast_en[1] = ~0xffff;

	is->is_dpm = acemap[unit];
	ioaccess(ACEmap[unit],ACEmapa[unit],ACEBPTE);
	for (pData0 = (short *)is->is_dpm, i = 16384; --i >= 0;)
	    *(pData0++) = 0;

	is->is_segboundry = 8;
	for (pData1 = (char*)((int)is->is_dpm + (is->is_segboundry << 11)),
	     i = (SEG_MAX + 1) - is->is_segboundry;
	     (--i >= 0);
	     pData1 += sizeof (struct tx_segment))
	 {
	  ((struct tx_segment*)pData1)->tx_csr = 15;
	 }

	is->is_eictr = 0;
	is->is_eoctr = is->is_txnext = is->is_segboundry;
	is->is_currnd = 49123;
	for (pData1 = (char *)&is->is_stats,i = sizeof (struct ace_stats); 
	     (--i != 0);)
	  *(pData1++) = 0;   

	sin = (struct sockaddr_in *)&ifp->if_addr;
	sin->sin_family = AF_INET;
	sin->sin_addr = arpmyaddr((struct arpcom *)0);
	ifp->if_init = aceinit;
	ifp->if_output = aceoutput;
	ifp->if_ioctl = aceioctl;
	ifp->if_reset = acereset;
	if_attach(ifp);
#ifdef	ACEDEBUG
printf("aceattach: ifattach complete\n");
#endif	ACEDEBUG
}

/*
 * Reset of interface after "system" reset.
 */
acereset(unit, vban)
int unit, vban;
{
register struct vba_device *ui;
#ifdef	ACEDEBUG
printf("ace%dreset:\n",unit,vban);
#endif	ACEDEBUG

	if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 ||
	    ui->ui_vbanum != vban)
		return;
	printf(" ace%d", unit);
	aceinit(unit);
}

/*
 * Initialization of interface; clear recorded pending operations
 */
aceinit(unit)
int unit;
{
register struct ace_softc *is = &ace_softc[unit];
register struct vba_device *ui = aceinfo[unit];
register struct acedevice *addr;
register struct ifnet *ifp = &is->is_if;
register struct sockaddr_in *sin;
register int i,s;
#ifdef	ACEDEBUG
printf("ace%dinit:\n",unit);
#endif	ACEDEBUG

	sin = (struct sockaddr_in *)&ifp->if_addr;
	if (sin->sin_addr.s_addr == 0)		/* address still unknown */
	  {
#ifdef	ACEDEBUG
printf("ace%dinit: no address assigned\n",unit);
#endif	ACEDEBUG
		return;
	  }

	if (!(ifp->if_flags & IFF_RUNNING))
	  {

	/*
	 * Reset the controller, initialize the recieve buffers,
	 * and turn the controller on again and set board online.
	 */
	    addr = (struct acedevice *)ui->ui_addr;
	    s = splimp();
	    addr->csr = CSR_GO;
	       
	    if (addr->csr & CSR_ACTIVE)
	      {
		addr->ivct = ACEVECTOR + (unit*8); 
		addr->csr |= CSR_ENINT | is->is_promiscuous;
		if (ifp->if_net == LONET)
		  addr->csr |= (CSR_LOOP3);
		is->is_flags = ACEF_OACTIVE;
		is->is_if.if_flags |= IFF_UP|IFF_RUNNING;
#ifdef	ACEDEBUG
		printf("aceinit: csr %x, segb %x, tseg %x, rseg %x\n",
			     (addr->csr & 0xffff),
			     ((addr->segb >> 11) & 0xf),
			     ((addr->tseg >> 11) & 0xf),
			     ((addr->rseg >> 11) & 0xf));
#endif	ACEDEBUG
		acecint(unit);
	      }
#ifdef	ACEDEBUG
	    else
	      {
		printf("ace%dinit: would not go active\n",unit);
	      }
#endif	ACEDEBUG
	    splx(s);
	  }
	if_rtinit(&is->is_if, RTF_UP);
	arpattach(&is->is_ac);
	arpwhohas(&is->is_ac, &sin->sin_addr);
}

/*
 * Start output on interface.
 * Get another datagram to send off of the interface queue,
 * and map it to the interface before starting the output.
 */
acestart(dev)
dev_t dev;
{
int unit = ACEUNIT(dev), len;
struct vba_device *ui = aceinfo[unit];
register struct ace_softc *is = &ace_softc[unit];
register struct tx_segment *txs;
struct mbuf *m;
short retries,idx;
#ifdef	ACEDEBUG
printf("ace%dstart: dev %X, tx seg %x\n",unit,dev,is->is_txnext);
#endif	ACEDEBUG

	txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
	if (txs->tx_csr & TCS_TBFULL) return;
	IF_DEQUEUE(&is->is_if.if_snd, m);
	if (m == 0)
	  {
	    if (TRUE) return;
	  }
	len = aceput(txs->tx_data, m);
#ifdef	ACEDEBUG
	printf("sending[");
	for (idx = 0;(idx < len);idx++)
	  {
	    printf("%x ",txs->tx_data[idx] & 0xff);
	  }
	printf("]\n");
#endif	ACEDEBUG
	retries = (txs->tx_csr & TCS_RTC);
	acebakoff(is,txs,retries);
	/*
	 * Ensure minimum packet length.
	 * This makes the safe assumtion that there are no virtual holes
	 * after the data.
	 * For security, it might be wise to zero out the added bytes,
	 * but we're mainly interested in speed at the moment.
	 */
	if (len - sizeof(struct ether_header) < ETHERMIN)
		len = ETHERMIN + sizeof(struct ether_header);
	if ((is->is_txnext += 1) > SEG_MAX)
	  is->is_txnext = is->is_segboundry;
	txs->tx_csr = (TCS_TBFULL|len);
	is->is_if.if_opackets++;
#ifdef	ACEDEBUG
	printf("sending %x bytes,retries fixed %x\n",
			(txs->tx_csr & 0xffff),retries);
#endif	ACEDEBUG
	is->is_flags |= ACEF_OACTIVE;
}

/*
 * Command done interrupt.
 */
acecint(unit)
int unit;
{
register struct ace_softc *is = &ace_softc[unit];
struct vba_device *ui = aceinfo[unit];
register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
register struct tx_segment *txseg;	/* ptr to V/EIU tx seg            */
short eostat;
#ifdef	ACEDEBUG
printf("ace%dcint: \n",unit);
#endif	ACEDEBUG

	if ((is->is_flags & ACEF_OACTIVE) == 0)
	  {
	    printf("ace%dcint: stray xmit interrupt\n", unit);
		return;
	  }

	is->is_flags &= ~ACEF_OACTIVE;
	txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm);
	if (((eostat = txseg->tx_csr) & TCS_TBFULL) == 0)
	  {
	    is->is_stats.tx_retries += (eostat & TCS_RTC);
	    if (eostat & TCS_RTFAIL)
	      {
		is->is_stats.tx_discarded++;
		is->is_if.if_oerrors++;
	      }
	    else
	      is->is_stats.tx_datagrams++;
	    if (++is->is_eoctr >= 16)
	      is->is_eoctr = is->is_segboundry; 
	  } 
#ifdef	ACEDEBUG
	else
	  {
printf("ace%dcint: tx segment %X busy\n",unit,is->is_eoctr);
	  }
#endif	ACEDEBUG
	acestart(unit);
}

/*
 * Ethernet interface receiver interrupt.
 * If input error just drop packet.
 * Otherwise purge input buffered data path and examine 
 * packet to determine type.  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.
 */
acerint(unit)
int unit;
{
register struct ace_softc *is = &ace_softc[unit];
struct acedevice *addr = (struct acedevice *)aceinfo[unit]->ui_addr;
register struct ifqueue *inq;
register struct ace_rheader *ace;
register struct rx_segment *rxseg;	/* ptr to V/EIU rx seg            */
short eistat;
struct mbuf *m;
int len, off, resid;
#ifdef	ACEDEBUG
printf("ace%xrint: rxseg %x\n",unit,is->is_eictr);
#endif	ACEDEBUG

	is->is_if.if_ipackets++;
	rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
	if (++is->is_eictr >= is->is_segboundry) 
	  is->is_eictr = 0;
#ifdef	ACEDEBUG
	printf("[(%x)",(rxseg->rx_csr & 0xffff));
	for (off = 0;(off < 64);off++)
	  {
	    printf("%x ",rxseg->rx_data[off] & 0xff);
	  }
	printf("]\n");
#endif	ACEDEBUG
	if ((eistat = rxseg->rx_csr) & RCS_RBFULL)
	  {
	    len = (eistat & RCS_RBC);
	    if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) ||
		(len < ET_MINLEN) || (len > (ET_MAXLEN+CRC_SIZE)))
	      {
		if (eistat & RCS_ROVRN) is->is_stats.rx_overruns++;
		if (eistat & RCS_RCRC) is->is_stats.rx_crc_errors++;
		if (eistat & RCS_RODD) is->is_stats.rx_align_errors++;
		if (len < ET_MINLEN) is->is_stats.rx_underruns++;
		if (len > (ET_MAXLEN+CRC_SIZE)) is->is_stats.rx_overruns++;
		is->is_if.if_ierrors++;
#ifdef	ACEDEBUG
		if (is->is_if.if_ierrors % 100 == 0)
			printf("ace%d: += 100 input errors\n", unit);
#endif
		rxseg->rx_csr = 0;
		return;
	      }
	    else
	      {
		is->is_stats.rx_datagrams++;
	      }
	  }
#ifdef	ACEDEBUG
	else
	  {
	    printf("ace%d: stray recv interrupt\n", unit);
	    return;
	  }
#endif	ACEDEBUG
	ace = (struct ace_rheader *)(rxseg->rx_data);
	len = ace->acer_length - sizeof(struct ace_rheader);

	/*
	 * 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.
	 */
	ace->acer_type = ntohs((u_short)ace->acer_type);
#define	acedataaddr(ace, off, type)	((type)(((caddr_t)((ace)+1)+(off))))
	if (ace->acer_type >= ETHERPUP_TRAIL &&
	    ace->acer_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
		off = (ace->acer_type - ETHERPUP_TRAIL) * 512;
		if (off >= ETHERMTU)
			goto setup;		/* sanity */
		ace->acer_type = ntohs(*acedataaddr(ace, off, u_short *));
		resid = ntohs(*(acedataaddr(ace, 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; aceget 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 = aceget(rxseg->rx_data, len, off);
	if (m == 0)
		goto setup;
	if (off) {
		m->m_off += 2 * sizeof (u_short);
		m->m_len -= 2 * sizeof (u_short);
	}
	switch (ace->acer_type) {

#ifdef INET
	case ETHERPUP_IPTYPE:
		schednetisr(NETISR_IP);
		inq = &ipintrq;
		break;

	case ETHERPUP_ARPTYPE:
		arpinput(&is->is_ac, m);
		goto setup;
#endif
	default:
		m_freem(m);
		goto setup;
	}

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

setup:
	rxseg->rx_csr = 0;
}

/*
 * 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.
 */
aceoutput(ifp, m0, dst)
struct ifnet *ifp;
struct mbuf *m0;
struct sockaddr *dst;
{
register short unit = ifp->if_unit;
register struct ace_softc *is = &ace_softc[unit];
register struct mbuf *m = m0;
register struct ether_header *ace;
register int off;
int type, s, error;
u_char edst[6];
struct in_addr idst;
#ifdef	ACEDEBUG
printf("ace%doutput: ifp %X, m0 %X, dst %X\n",unit,ifp,m0,dst);
#endif	ACEDEBUG

	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 */
		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
		/* need per host negotiation */
		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
		  if (off > 0 && (off & 0x1ff) == 0 &&
		      m->m_off >= MMINOFF + 2 * sizeof (u_short))
		    {
			type = ETHERPUP_TRAIL + (off>>9);
			m->m_off -= 2 * sizeof (u_short);
			m->m_len += 2 * sizeof (u_short);
			*mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
			goto gottrailertype;
		    }
		type = ETHERPUP_IPTYPE;
		off = 0;
		goto gottype;
#endif

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

	default:
		printf("ace%d: can't handle af%d\n", unit,dst->sa_family);
		error = EAFNOSUPPORT;
		goto bad;
	}

gottrailertype:
	/*
	 * 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);
	}
	ace = mtod(m, struct ether_header *);
	ace->ether_type = htons((u_short)type);
	bcopy((caddr_t)edst, (caddr_t)ace->ether_dhost, sizeof (edst));
	bcopy((caddr_t)is->is_addr, (caddr_t)ace->ether_shost, 6);

	/*
	 * 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);
	acestart(unit);
	splx(s);
	return (0);

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

/*
 * Routine to copy from mbuf chain to transmit buffer on the VERSAbus
 * If packet size is less than the minimum legal size,
 * the buffer is expanded.  We probably should zero out the extra
 * bytes for security, but that would slow things down.
 */
aceput(txbuf, m)
u_char *txbuf;
struct mbuf *m;
{
register struct mbuf *mp;
register int off,total;
u_char *bp;
#ifdef	ACEDEBUG
printf("aceput: txbuf %X, mbuf %X\n",txbuf,mp);
#endif	ACEDEBUG

	total = 0;
				/* Leave room for the destination	*/
	off = 0;
	bp = (u_char *)(txbuf + off);
	for (mp = m;(mp); mp = mp->m_next)
	  {
	  register unsigned len = mp->m_len;
	  u_char *mcp;

		if (len == 0)
			continue;
		total += len;
		mcp = mtod(mp, u_char *);
		if ((unsigned)bp & 01) {
			*bp++ = *mcp++;
			len--;
		}
		if (off = (len >> 1)) {
			register u_short *to, *from;

			to = (u_short *)bp;
			from = (u_short *)mcp;
			do
				*to++ = *from++;
			while (--off > 0);
			bp = (u_char *)to,
			mcp = (u_char *)from;
		}
		if (len & 01)
			*bp++ = *mcp++;
	  }
	m_freem(m);
	return(total);
}

/*
 * Routine to copy from VERSAbus memory into mbufs.
 *
 * Warning: This makes the fairly safe assumption that
 * mbufs have even lengths.
 */
struct mbuf *
aceget(rxbuf, totlen, off0)
u_char *rxbuf;
int totlen, off0;
{
register struct mbuf *m;
struct mbuf *top = 0, **mp = &top;
register int off = off0, len;
u_char *cp;
#ifdef	ACEDEBUG
printf("aceget: rxbuf %X\n",rxbuf);
#endif	ACEDEBUG

	cp = rxbuf + sizeof (struct ether_header);
	while (totlen > 0)
	  {
	  register int words;
	  u_char *mcp;

		MGET(m, M_DONTWAIT, MT_DATA);
		if (m == 0)
			goto bad;
		if (off) {
			len = totlen - off;
			cp = rxbuf +
				sizeof (struct ether_header) + off;
		} else
			len = totlen;
		if (len >= CLBYTES) {
			struct mbuf *p;

			MCLGET(p, 1);
			if (p != 0) {
				m->m_len = len = CLBYTES;
				m->m_off = (int)p - (int)m;
			} else {
				m->m_len = len = MIN(MLEN, len);
				m->m_off = MMINOFF;
			}
		} else {
			m->m_len = len = MIN(MLEN, len);
			m->m_off = MMINOFF;
		}
		mcp = mtod(m, u_char *);
		if (words = (len >> 1)) {
			register u_short *to, *from;

			to = (u_short *)mcp;
			from = (u_short *)cp;
			do
				*to++ = *from++;
			while (--words > 0);
			mcp = (u_char *)to;
			cp = (u_char *)from;
		}
		if (len & 01)
			*mcp++ = *cp++;
		*mp = m;
		mp = &m->m_next;
		if (off == 0) {
			totlen -= len;
			continue;
		}
		off += len;
		if (off == totlen) {
			cp = rxbuf + sizeof (struct ether_header);
			off = 0;
			totlen = off0;
		}
	  }
	return (top);
bad:
	m_freem(top);
	return (0);
}

/*+procedure							*/
/*								*/

acebakoff(is, txseg, retries)
struct ace_softc *is;		/* ptr to UCB for this device     */
struct tx_segment *txseg;	/* ptr to V/EIU tx seg            */
register int retries;		/* # of randoms to generate       */
{
short *pMask;			/* ptr to mask table.	     */
register short *pBakNum;	/* ptr to # entry in Tx seg table */
register short random_num;	/* random number value.	     */


	pMask   = &random_mask_tbl[0];
	pBakNum = &txseg->tx_backoff[0];

	for (; --retries >= 0;)
	  {
	    random_num   = (is->is_currnd = (is->is_currnd * 18741)-13849);
	    random_num  &= *(pMask++);
	    *(pBakNum++) = random_num ^ (short)(0xFF00 | 0x00FC);
	  }
}

/*
 * Process an ioctl request.
 */
aceioctl(ifp, cmd, data)
register struct ifnet *ifp;
int cmd;
caddr_t data;
{
register struct ifreq *ifr = (struct ifreq *)data;
int s = splimp(), error = 0;
#ifdef	ACEDEBUG
printf("aceioctl: ifp %X, cmd %X, data %X\n",ifp,cmd,data);
#endif	ACEDEBUG

	switch (cmd) {

	case SIOCSIFADDR:
		if (ifp->if_flags & IFF_RUNNING)
			if_rtinit(ifp, -1);	/* delete previous route */
		acesetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
		aceinit(ifp->if_unit);
		break;

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

acesetaddr(ifp, sin)
register struct ifnet *ifp;
register struct sockaddr_in *sin;
{
#ifdef	ACEDEBUG
printf("acesetaddr: ifp %X, sin %X\n",ifp,sin);
#endif	ACEDEBUG

	ifp->if_addr = *(struct sockaddr *)sin;
	ifp->if_net = in_netof(sin->sin_addr);
	ifp->if_host[0] = in_lnaof(sin->sin_addr);
	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
	sin->sin_family = AF_INET;
	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
	ifp->if_flags |= IFF_BROADCAST;
}
#endif	NACE > 0

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.