|
|
Power 6/32 Unix version 1.21
/* */
/* if_ace: ACC VERSAbus Ethernet controler (v/eiu) */
/* */
#include "ace.h"
#if NACE > 0
#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 "../h/vmparam.h"
#include "../net/if.h"
#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_acereg.h"
#include "../vba/vbavar.h"
#include "../tahoeif/if_debug.h"
#define LONET 124
#define LOHOST 1
#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[] = {0xfff80000,0xfff90000};
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();
struct ace_softc ace_softc[NACE];
extern struct ifnet loif;
int numace = NACE; /* for nstat unix command */
int printerror = 1;
int save_ace_inpkt = 0;
struct inp_err aceerr[NACE];
extern int saverrpkt();
#define INPTRACE(X) if (save_ace_inpkt) X
/*------ debugging tools ------------*/
#ifdef ACEPRINTFS
int aceprintfs;
#define INTTRACE 1
#define RTINTRACE 2
#define STARTTRACE 4
#define ACEOTRACE 8
#define RTINTRACE1 0x10
#define IOCTLTRACE 0x20
#define ATRACE 0x40
#define SETETTRACE 0x80
#define ALLTRACE (INTTRACE | RTINTRACE | STARTTRACE | ACEOTRACE\
| RTINTRACE1 | IOCTLTRACE | ATRACE | SETETTRACE)
#define ACETRACE(X,Y) {if (aceprintfs & X) Y}
#else ACEPRINTFS
#define ACETRACE(X,Y)
#endif ACEPRINTFS
/*------ performance study tools ---------------*/
#ifdef NET_PERF
#define ACESTUDY(X) {X}
#else NET_PERF
#define ACESTUDY(X)
#endif
aceprobe(reg)
caddr_t reg;
{
register struct acedevice *addr = (struct acedevice *)reg;
register i;
ACETRACE(ALLTRACE, printf("aceprobe: veiu @%X\n",reg);)
#ifdef lint
i = 0; acerint(i); acecint(i);
#endif
if (badaddr(reg,2)) return(0);
movew((short)CSR_RESET,&addr->csr);
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, data;
register char *pData1;
register short Csr;
struct sockaddr_in *sin;
ACETRACE( ALLTRACE, printf("ace%dattach: ui %X\n",unit,ui);)
ifp->if_unit = unit;
ifp->if_name = "ace";
ifp->if_mtu = ETHERMTU;
/*
* Set vector,station's addresses,cleanup dpm.
*/
/* set the station address, copy to arp structure */
acesetetaddr(unit,addr, &ace_station[unit * 6]);
/*
for (pData0 = (short *)addr->rar.station_addr,
pData1 = &ace_station[unit * 6], i = 6;
--i >= 0;) {
movew((short)(*pData1++),(pData0++));
}
for (pData0 = (short *)addr->rar.station_addr,
pData1 = (char *)(is->is_addr), i = 6;
--i >= 0;)
*(pData1++) = ~(*(pData0++));
ACETRACE(ALLTRACE,
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);)
*/
is->is_promiscuous = (FALSE)? CSR_PROMISCUOUS: 0;
for (pData0 = (short *)addr->rar.mcast_hash_code,
pData1 = &ace_hash_code[unit * 8], i = 8;
--i >= 0;){
movew((short)(*pData1++),(pData0++));
}
movew((short)~0xffff,&addr->rar.broadcast_en[0]);
movew((short)~0xffff,&addr->rar.broadcast_en[1]);
aceclean((int)unit);
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);
}
acesetetaddr(unit,addr,station_addr)
short unit;
struct acedevice *addr;
char *station_addr;
{
register short *pData0, i;
register char *pData1;
register struct ace_softc *is = &ace_softc[unit];
for (pData0 = (short *)addr->rar.station_addr,
pData1 = station_addr, i = 6; --i >= 0;) {
movew((short)(*pData1++),(pData0++));
}
for (pData0 = (short *)addr->rar.station_addr,
pData1 = (char *)(is->is_addr), i = 6; --i >= 0;)
*(pData1++) = ~(*(pData0++));
ACETRACE(SETETTRACE,
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);)
}
/*
* Reset of interface after "system" reset.
*/
acereset(unit, vban)
int unit, vban;
{
register struct vba_device *ui;
ACETRACE(ALLTRACE, printf("ace%dreset:\n",unit,vban);)
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 short Csr;
register int i,s;
ACETRACE(ALLTRACE, printf("ace%dinit:\n",unit);)
sin = (struct sockaddr_in *)&ifp->if_addr;
if (sin->sin_addr.s_addr == 0) /* address still unknown */
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();
movew((short)CSR_RESET,&addr->csr);
DELAY(10000);
/* clean up dpm since the controller might jumble dpm after
reset */
aceclean((int)unit);
movew((short)CSR_GO,&addr->csr); /* addr->csr = CSR_GO; */
Csr = addr->csr;
if (Csr & CSR_ACTIVE)
{
movew((short)(ACEVECTOR + (unit*8)),&addr->ivct);
Csr |= CSR_ENINT | is->is_promiscuous;
if (ifp->if_net == LONET)
Csr |= (CSR_LOOP3);
movew(Csr,&addr->csr);
is->is_flags = 0;
is->is_xcnt = 0;
is->is_if.if_flags |= IFF_UP|IFF_RUNNING;
}
else
{
ACETRACE(ALLTRACE,
printf("ace%dinit: would not go active\n",unit);)
}
splx(s);
}
if (is->is_if.if_flags & IFF_UP) {
if_rtinit(&is->is_if, RTF_UP);
aceStart((int)unit);
}
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;
{
register struct tx_segment *txs;
register long len,x;
int unit = ACEUNIT(dev);
struct vba_device *ui = aceinfo[unit];
register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
register struct ace_softc *is = &ace_softc[unit];
register long tripnum = 0;
struct mbuf *m;
short retries,idx;
ACETRACE(STARTTRACE,
printf("ace%dstart: dev %X, txnext seg %x\n",unit,dev,
(addr->tseg >> 11) & 0xf);)
ACESTUDY(is->is_stats.tx_startcnt++;)
again:
txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
if (txs->tx_csr & TCS_TBFULL) {
ACETRACE(ALLTRACE, printf("ace%dstart:segment %x is busy\n",
unit, is->is_txnext);)
is->is_stats.tx_busy++;
return;
}
x = splimp();
IF_DEQUEUE(&is->is_if.if_snd, m);
splx(x);
if (m == 0)
return;
len = aceput((int) unit, txs->tx_data, m);
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_ETHEADER < ETHERMIN)
len = ETHERMIN + SIZEOF_ETHEADER;
if (++is->is_txnext > SEG_MAX)
is->is_txnext = is->is_segboundry;
is->is_if.if_opackets++;
is->is_xcnt++;
len = (len & 0x7fff) | TCS_TBFULL;
ACETRACE(STARTTRACE,
printf("ace%dstart GO [csr %x][%x,%x,%x,%x,%x,%x] [%x,%x,%x,%x,%x,%x] [%x] [%x] \n",unit,
(len & 0xffff),
(txs->tx_data[0] & 0xff),(txs->tx_data[1] & 0xff),
(txs->tx_data[2] & 0xff),(txs->tx_data[3] & 0xff),
(txs->tx_data[4] & 0xff),(txs->tx_data[5] & 0xff),
(txs->tx_data[6] & 0xff),(txs->tx_data[7] & 0xff),
(txs->tx_data[8] & 0xff),(txs->tx_data[9] & 0xff),
(txs->tx_data[10] & 0xff),(txs->tx_data[11] & 0xff),
(txs->tx_data[12] & 0xff),(txs->tx_data[13] & 0xff));)
movew((short)len,txs);
goto again;
}
/*
* Transmit 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 txidx,eostat;
ACESTUDY(is->is_stats.tx_cintcnt++;)
if (is->is_xcnt <= 0) {
txidx = ((addr->tseg >> 11) & 0xf);
printf("ace%dcint: stray xmit interrupt,xcnt %d\n",
unit,is->is_xcnt);
printf("\t**eoctr %d, ctlr's tseg %d\n",is->is_eoctr,txidx);
is->is_xcnt = 0;
aceStart((int)unit);
return;
}
is->is_xcnt--;
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;
}
else {
ACESTUDY(is->is_stats.tx_cbusy++;)
}
aceStart((int)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];
register struct ifqueue *inq;
register struct ether_header *ace;
register struct rx_segment *rxseg; /* ptr to V/EIU rx seg */
register long tripnum = 0;
struct acedevice *addr = (struct acedevice *)aceinfo[unit]->ui_addr;
short eistat;
struct mbuf *m;
struct inp_err *acer = &aceerr[unit];
int len, s, off, resid, orglen;
ACESTUDY(is->is_stats.rx_rintcnt++;)
more:
rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
if ((eistat = rxseg->rx_csr) & RCS_RBFULL)
{
is->is_if.if_ipackets++;
if (++is->is_eictr >= is->is_segboundry)
is->is_eictr = 0;
ACETRACE(RTINTRACE, printf("ace%drint: is_eictr %x,[csr %x]\n",
unit,is->is_eictr,(eistat & 0xffff));)
ACESTUDY(if (tripnum) is->is_stats.rx_rwoint++;)
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++;
rxseg->rx_csr = 0;
ACETRACE( RTINTRACE,
if (is->is_if.if_ierrors % 100 == 0)
printf("ace%d: += 100 input errors\n", unit);)
return;
}
else is->is_stats.rx_datagrams++;
}
else
{
if (tripnum==0) {
ACESTUDY(is->is_stats.rx_busy++;)
}
return;
}
ace = (struct ether_header *)(rxseg->rx_data);
orglen = len;
len -= SIZEOF_ETHEADER;
/*
* 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->ether_type = ntohs((u_short)ace->ether_type);
#define acedataaddr(ace, off, type) ((type)(((caddr_t)(((char *)ace)+SIZEOF_ETHEADER)+(off))))
/*#define acedataaddr(ace, off, type) ((type)(((caddr_t)((ace)+1)+(off)))) */
if (ace->ether_type >= ETHERPUP_TRAIL &&
ace->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
off = (ace->ether_type - ETHERPUP_TRAIL) * 512;
if (off >= ETHERMTU) {
acer->bad_offset++;
INPTRACE(saverrpkt(rxseg->rx_data, B_OFFSET, orglen);)
goto setup; /* sanity */
}
ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *));
resid = ntohs(*(acedataaddr(ace, off+2, u_short *)));
if (off + resid > len) {
acer->bad_length++;
INPTRACE(saverrpkt(rxseg->rx_data, B_LENGTH, orglen);)
goto setup; /* sanity */
}
len = off + resid;
} else
off = 0;
if (len == 0) {
acer->bad_length++;
INPTRACE(saverrpkt(rxseg->rx_data, B_LENGTH, orglen);)
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((int)unit, rxseg->rx_data, len, off);
if (m == 0) {
acer->h_nobuffer++; /* host runs out of buf */
goto setup;
}
if (off) {
m->m_off += 2 * sizeof (u_short);
m->m_len -= 2 * sizeof (u_short);
}
switch (ace->ether_type) {
#ifdef INET
case ETHERPUP_IPTYPE:
if (tripnum == 0) {
/* rely on the fact that ip_input() will drain
the incoming queue after the first software
interrupt */
schednetisr(NETISR_IP);
}
inq = &ipintrq;
break;
case ETHERPUP_ARPTYPE:
arpinput(&is->is_ac, m);
goto setup;
#endif
default:
acer->bad_packetype++;
if (printerror) {
printf("\nace%d: Undefined packet type 0x%x ", unit,
ace->ether_type);
printf("from host: %x.%x.%x.%x.%x.%x\n",
ace->ether_shost[0], ace->ether_shost[1],
ace->ether_shost[2], ace->ether_shost[3],
ace->ether_shost[4], ace->ether_shost[5]);
}
INPTRACE(saverrpkt(rxseg->rx_data, B_PACKETYPE, orglen);)
m_freem(m);
goto setup;
}
if (IF_QFULL(inq)) {
acer->inq_full++;
IF_DROP(inq);
m_freem(m);
goto setup;
}
s = splimp();
IF_ENQUEUE(inq, m);
splx(s);
ACETRACE(RTINTRACE1,printf("ace%dacerint: enqlen %d: ",
unit, inq->ifq_len);)
ACETRACE(RTINTRACE1,aceprm(unit, m);)
setup:
rxseg->rx_csr = 0;
goto more;
}
/*
* 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;
register struct mbuf *mcopy;
int type, s, error;
u_char edst[6];
struct in_addr idst;
#ifndef INET
ACETRACE(ACEOTRACE,
printf("ace%doutput: ifp %lx, m0 %lx, dst ADDR %lx: ",
unit,ifp,m0, dst);)
ACETRACE(ACEOTRACE,aceprm(unit, m0);)
#endif
switch (dst->sa_family) {
#ifdef INET
case AF_INET:
idst = ((struct sockaddr_in *)dst)->sin_addr;
ACETRACE(ACEOTRACE,
printf("ace%doutput: ifp %lx, m0 %lx, dst %lx: ",
unit,ifp,m0, idst.S_un.S_addr);)
ACETRACE(ACEOTRACE,aceprm(unit, m0);)
/* translate internet to ethernet address */
switch(arpresolve(&is->is_ac, m, &idst, edst)) {
case ARPRESOLVE_WILLSEND:
return (0); /* if not yet resolved */
case ARPRESOLVE_BROADCAST:
mcopy = m_copy(m, 0, (int)M_COPYALL);
MBUFNULL(42, mcopy); /* for debugging */
if (mcopy)
looutput(&loif, mcopy, dst);
/* falls through ... */
case ARPRESOLVE_OK:
break;
}
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:
if (printerror)
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_ETHEADER > m->m_off) {
m = m_get(M_DONTWAIT, MT_HEADER);
MBUFNULL(30, m);
if (m == 0) {
error = ENOBUFS;
goto bad;
}
m->m_next = m0;
m->m_off = MMINOFF;
m->m_len = SIZEOF_ETHEADER;
} else {
m->m_off -= SIZEOF_ETHEADER;
m->m_len += SIZEOF_ETHEADER;
}
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);
splx(s);
ACETRACE (ACEOTRACE, printf("ace%doutput: enqu mbuf %lx: ",unit,m);)
ACETRACE (ACEOTRACE, aceprm(unit, m);)
ACESTUDY (is->is_stats.tx_outcnt++;)
aceStart((int)unit);
return (0);
bad:
ACETRACE(ACEOTRACE, printf("ace%doutput: BAD.\n");)
m_freem(m0);
return (error);
}
aceStart(unit)
int unit;
{
register struct ace_softc *is = &ace_softc[unit];
if (!(is->is_flags & ACEF_OACTIVE)) {
is->is_flags |= ACEF_OACTIVE;
acestart((dev_t)unit);
is->is_flags &= ~ACEF_OACTIVE;
}
}
/*
* 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(unit, txbuf, m)
int unit; /* for statistics collection */
u_char *txbuf;
struct mbuf *m;
{
register u_char *bp;
register u_char *mcp;
register short *s1;
register short *s2;
register unsigned len;
register struct mbuf *mp;
int total, idx;
ACETRACE(STARTTRACE, printf("ace%daceput: txbuf %X, mbuf %X, m->m_off %d\n",
unit, txbuf, m, m->m_off);)
ACETRACE(STARTTRACE,aceprm(unit, m);)
total = 0;
bp = (u_char *)txbuf;
for (mp = m;(mp); mp = mp->m_next)
{
len = mp->m_len;
if (len == 0)
continue;
total += len;
mcp = mtod(mp, u_char *);
/*bcopy((caddr_t)mcp,(caddr_t)bp,len);*/
/*bp += len;*/
if (((int)mcp & 01) && ((int)bp & 01)) {
/* source & destination at odd addresses */
/* *bp++ = *mcp++; */
asm("movob (r11),(r12)");
asm("addl2 $1,r12");
asm("addl2 $1,r11");
--len;
}
if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
register int l;
s1 = (short *)bp;
s2 = (short *)mcp;
l = (len >> 1); /* count # of shorts */
while (l-->0) { /* copy shorts */
/* *s1++ = *s2++; */
asm("movow (r9),(r10)");
asm("addl2 $2,r10");
asm("addl2 $2,r9");
}
len &= 1; /* # remaining bytes */
bp = (u_char *)s1;
mcp = (u_char *)s2;
}
while (len-- > 0) {
/* *bp++ = *mcp++; */
asm("movob (r11),(r12)");
asm("addl2 $1,r12");
asm("addl2 $1,r11");
}
}
m_freem(m);
return(total);
}
movew(data,to)
short data;
short *to;
{
asm("movow 6(fp),*8(fp)");
}
#ifdef ACEPRINTFS
aceprm(unit, mp)
int unit;
struct mbuf *mp;
{
register u_char *mcp;
register struct mbuf *mpp;
register long idx;
register long totlen,lx;
for(totlen=0,mpp=mp->m_next; mpp; mpp=mpp->m_next)
totlen += mpp->m_len;
mcp = mtod(mp, u_char *);
printf("ace%d mbuf[len %d,off %d],[next %lx,totlen %ld],[",
unit, mp->m_len,mp->m_off,mp->m_next,totlen);
for (idx=0 ; (idx < 20 ); idx++)
{
printf("%x ",mcp[idx] & 0xff);
}
printf("]\n");
}
#endif ACEPRINTFS
/*
* Routine to copy from VERSAbus memory into mbufs.
*
* Warning: This makes the fairly safe assumption that
* mbufs have even lengths.
*/
struct mbuf *
aceget(unit, rxbuf, totlen, off0)
int unit; /* for statistics collection */
u_char *rxbuf;
int totlen, off0;
{
register u_char *cp;
register u_char *mcp;
register int tlen;
int len;
register struct mbuf *m;
struct mbuf *top = 0, **mp = ⊤
int off = off0;
ACETRACE(RTINTRACE, printf("ace%daceget: rxbuf %lx, len %d, off %d\n",
unit, rxbuf,totlen,off0);)
cp = rxbuf + SIZEOF_ETHEADER;
while (totlen > 0)
{
register int words;
MGET(m, M_DONTWAIT, MT_DATA);
MBUFNULL(33, m);
if (m == 0)
goto bad;
if (off) {
len = totlen - off;
cp = rxbuf +
SIZEOF_ETHEADER + 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 *);
/*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/
/*cp += len; mcp += len;*/
tlen = len;
if (((int)mcp & 01) && ((int)cp & 01)) {
/* source & destination at odd addresses */
*mcp++ = *cp++;
--tlen;
}
if (tlen > 1 && (((int)mcp & 01)==0) && (((int)cp & 01)==0)) {
register short *s1;
register short *s2;
register int l;
s1 = (short *)mcp;
s2 = (short *)cp;
l = (tlen >> 1); /* count # of shorts */
while (l-->0) /* copy shorts */
*s1++ = *s2++;
tlen &= 1; /* # remaining bytes */
mcp = (u_char *)s1;
cp = (u_char *)s2;
}
while (tlen-- > 0)
*mcp++ = *cp++;
*mp = m;
mp = &m->m_next;
if (off == 0) {
totlen -= len;
continue;
}
off += len;
if (off == totlen) {
cp = rxbuf + SIZEOF_ETHEADER;
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 short unit = ifp->if_unit;
register struct vba_device *ui;
register struct acedevice *addr;
register struct sockaddr_in *et_addr;
register struct ace_softc *is = &ace_softc[ifp->if_unit];
register struct ifreq *ifr = (struct ifreq *)data;
int s , error = 0;
ACETRACE (IOCTLTRACE,
printf("ace%daceioctl: ifp %X, cmd %X, data %X\n", unit, ifp, cmd, data);)
switch (cmd) {
case SIOCSIFADDR:
s = splimp();
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);
splx(s);
break;
case SIOCSETETADDR: /* Set Ethernet station address */
s = splimp();
ifp->if_flags &= (~IFF_RUNNING | IFF_UP);
et_addr = (struct sockaddr_in *)&ifr->ifr_addr;
ui = aceinfo[ifp->if_unit];
addr = (struct acedevice *)ui->ui_addr;
movew((short)CSR_RESET,&addr->csr); /* Reset again */
DELAY(10000);
/* Set station address and copy addr to arp struct */
acesetetaddr(ifp->if_unit,addr,&et_addr->sin_zero[2]);
aceinit(ifp->if_unit); /* Re-initialize */
splx(s);
break;
case SIOCGETETADDR: /* Get Foreign Hosts' Ethernet address */
arpwhohas(&is->is_ac, (struct in_addr *)ifr->ifr_data);
break;
default:
error = EINVAL;
}
return (error);
}
acesetaddr(ifp, sin)
register struct ifnet *ifp;
register struct sockaddr_in *sin;
{
register short unit = ifp->if_unit;
ACETRACE (IOCTLTRACE, printf("ace%dacesetaddr: ifp %X, sin %X\n",unit,ifp,sin);)
arpremove(&ifp->if_addr);
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;
}
aceclean(unit)
int unit;
{
register struct ace_softc *is = &ace_softc[unit];
register struct ifnet *ifp = &is->is_if;
register struct vba_device *ui = aceinfo[unit];
register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
register short i, data;
register char *pData1;
is->is_dpm = acemap[unit]; /* init dpm */
ioaccess(ACEmap[unit],ACEmapa[unit],ACEBPTE);
bzero((char *)is->is_dpm, (16384*2));
is->is_currnd = 49123;
is->is_segboundry = (addr->segb >> 11) & 0xf;
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))
acebakoff(is,((struct tx_segment*)pData1),15);
is->is_eictr = 0;
is->is_eoctr = is->is_txnext = is->is_segboundry;
bzero((char *)&is->is_stats, sizeof(is->is_stats));
}
#endif NACE > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.