-/* if_il.c 4.7 82/06/18 */
+/* if_il.c 4.17 82/12/17 */
#include "il.h"
/*
* Interlan Ethernet Communications Controller interface
*/
+#include "../machine/pte.h"
+
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/mbuf.h"
-#include "../h/pte.h"
#include "../h/buf.h"
#include "../h/protosw.h"
#include "../h/socket.h"
-#include "../h/ubareg.h"
-#include "../h/ubavar.h"
-#include "../h/ilreg.h"
-#include "../h/cpu.h"
-#include "../h/mtpr.h"
#include "../h/vmmac.h"
-#include "../net/in.h"
-#include "../net/in_systm.h"
-#include "../net/if.h"
-#include "../net/if_il.h"
-#include "../net/if_uba.h"
-#include "../net/ip.h"
-#include "../net/ip_var.h"
-#include "../net/pup.h"
-#include "../net/route.h"
#include <errno.h>
-#define ILMTU 1500
+#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 "../netpup/pup.h"
+
+#include "../vax/cpu.h"
+#include "../vax/mtpr.h"
+#include "../vaxif/if_ether.h"
+#include "../vaxif/if_il.h"
+#include "../vaxif/if_ilreg.h"
+#include "../vaxif/if_uba.h"
+#include "../vaxuba/ubareg.h"
+#include "../vaxuba/ubavar.h"
int ilprobe(), ilattach(), ilrint(), ilcint();
struct uba_device *ilinfo[NIL];
struct uba_driver ildriver =
{ ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
#define ILUNIT(x) minor(x)
-int ilinit(),iloutput(),ilreset();
+int ilinit(),iloutput(),ilreset(),ilwatch();
u_char il_ectop[3] = { 0x02, 0x60, 0x8c };
u_char ilbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
struct il_softc {
struct ifnet is_if; /* network-visible interface */
struct ifuba is_ifuba; /* UNIBUS resources */
- short is_oactive; /* is output active? */
- short is_startrcv; /* hang receive next chance */
- u_char is_enaddr[6]; /* board's ethernet address */
+ int is_flags;
+#define ILF_OACTIVE 0x1 /* output is active */
+#define ILF_RCVPENDING 0x2 /* start rcv in ilcint */
+#define ILF_STATPENDING 0x4 /* stat cmd pending */
+ short is_lastcmd; /* can't read csr, so must save it */
+ short is_scaninterval; /* interval of stat collection */
+#define ILWATCHINTERVAL 60 /* once every 60 seconds */
+ struct il_stats is_stats; /* holds on-board statistics */
+ struct il_stats is_sum; /* summation over time */
+ int is_ubaddr; /* mapping registers of is_stats */
} il_softc[NIL];
-/*
- * Do an OFFLINE command. This will cause an interrupt for the
- * autoconfigure stuff.
- */
ilprobe(reg)
caddr_t reg;
{
register struct ildevice *addr = (struct ildevice *)reg;
register i;
-COUNT(ILPROBE);
#ifdef lint
br = 0; cvec = br; br = cvec;
- ilrint(0); ilcint(0);
+ i = 0; ilrint(i); ilcint(i); ilwatch(i);
#endif
addr->il_csr = ILC_OFFLINE|IL_CIE;
DELAY(100000);
- i = addr->il_csr; /* Clear CDONE */
+ i = addr->il_csr; /* clear CDONE */
if (cvec > 0 && cvec != 0x200)
cvec -= 4;
return (1);
}
-struct il_stat ilbuf;
/*
* Interface exists: make available by filling in network interface
* record. System will initialize the interface when it is ready
register struct il_softc *is = &il_softc[ui->ui_unit];
register struct ifnet *ifp = &is->is_if;
register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
- register short csr;
struct sockaddr_in *sin;
- int i, s, ubaddr;
-COUNT(ILATTACH);
ifp->if_unit = ui->ui_unit;
ifp->if_name = "il";
- ifp->if_mtu = ILMTU;
+ ifp->if_mtu = ETHERMTU;
ifp->if_net = ui->ui_flags;
/*
- * Reset the board
+ * Reset the board and map the statistics
+ * buffer onto the Unibus.
*/
- s = splimp();
- csr = ((ubaddr>>2)&0xc000)|ILC_RESET;
- addr->il_csr = csr;
- do
- csr = addr->il_csr;
- while ((csr&IL_CDONE) == 0);
- if (csr &= IL_STATUS)
- printf("il%d: %s\n", ui->ui_unit, ildiag[csr]);
- splx(s);
+ addr->il_csr = ILC_RESET;
+ while ((addr->il_csr&IL_CDONE) == 0)
+ ;
+ if (addr->il_csr&IL_STATUS)
+ printf("il%d: reset failed, csr=%b\n", ui->ui_unit,
+ addr->il_csr, IL_BITS);
- /*
- * Map the status buffer to the Unibus, do the status command,
- * and unmap the buffer.
- */
- ubaddr = uballoc(ui->ui_ubanum, &ilbuf, sizeof(ilbuf), 0);
- s = splimp();
- addr->il_bar = ubaddr & 0xffff;
- addr->il_bcr = sizeof(ilbuf);
- csr = ((ubaddr>>2)&0xc000)|ILC_STAT;
- addr->il_csr = csr;
- do
- csr = addr->il_csr;
- while ((csr&IL_CDONE) == 0);
- if (csr &= IL_STATUS)
- printf("il%d: %s\n", ui->ui_unit, ilerrs[csr]);
- splx(s);
- ubarelse(ui->ui_ubanum, &ubaddr);
- /*
- * Fill in the Ethernet address from the status buffer
- */
- bcopy(ilbuf.ils_addr, is->is_enaddr, 6);
+ is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
+ sizeof (struct il_stats), 0);
+ addr->il_bar = is->is_ubaddr & 0xffff;
+ addr->il_bcr = sizeof (struct il_stats);
+ addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT;
+ while ((addr->il_csr&IL_CDONE) == 0)
+ ;
+ if (addr->il_csr&IL_STATUS)
+ printf("il%d: status failed, csr=%b\n", ui->ui_unit,
+ addr->il_csr, IL_BITS);
+ ubarelse(ui->ui_ubanum, &is->is_ubaddr);
printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n",
ui->ui_unit,
- is->is_enaddr[0]&0xff, is->is_enaddr[1]&0xff,
- is->is_enaddr[2]&0xff, is->is_enaddr[3]&0xff,
- is->is_enaddr[4]&0xff, is->is_enaddr[5]&0xff,
- ilbuf.ils_module, ilbuf.ils_firmware);
- ifp->if_host[0] = ((is->is_enaddr[3]&0xff)<<16) | 0x800000 |
- ((is->is_enaddr[4]&0xff)<<8) | (is->is_enaddr[5]&0xff);
+ is->is_stats.ils_addr[0]&0xff, is->is_stats.ils_addr[1]&0xff,
+ is->is_stats.ils_addr[2]&0xff, is->is_stats.ils_addr[3]&0xff,
+ is->is_stats.ils_addr[4]&0xff, is->is_stats.ils_addr[5]&0xff,
+ is->is_stats.ils_module, is->is_stats.ils_firmware);
+ ifp->if_host[0] =
+ ((is->is_stats.ils_addr[3]&0xff)<<16) | 0x800000 |
+ ((is->is_stats.ils_addr[4]&0xff)<<8) |
+ (is->is_stats.ils_addr[5]&0xff);
sin = (struct sockaddr_in *)&ifp->if_addr;
sin->sin_family = AF_INET;
sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
ifp->if_init = ilinit;
ifp->if_output = iloutput;
- ifp->if_ubareset = ilreset;
+ ifp->if_reset = ilreset;
+ ifp->if_watchdog = ilwatch;
+ is->is_scaninterval = ILWATCHINTERVAL;
+ ifp->if_timer = is->is_scaninterval;
is->is_ifuba.ifu_flags = UBA_CANTWAIT;
#ifdef notdef
is->is_ifuba.ifu_flags |= UBA_NEEDBDP;
int unit, uban;
{
register struct uba_device *ui;
-COUNT(ILRESET);
if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 ||
ui->ui_ubanum != uban)
register struct il_softc *is = &il_softc[unit];
register struct uba_device *ui = ilinfo[unit];
register struct ildevice *addr;
- int i, s;
- short csr;
+ int s;
if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
- sizeof (struct il_rheader), (int)btoc(ILMTU)) == 0) {
+ sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) {
printf("il%d: can't initialize\n", unit);
is->is_if.if_flags &= ~IFF_UP;
return;
}
+ is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats,
+ sizeof (struct il_stats), 0);
addr = (struct ildevice *)ui->ui_addr;
+ /*
+ * Turn off source address insertion (it's faster this way),
+ * and set board online.
+ */
+ s = splimp();
+ addr->il_csr = ILC_CISA;
+ while ((addr->il_csr & IL_CDONE) == 0)
+ ;
+ addr->il_csr = ILC_ONLINE;
+ while ((addr->il_csr & IL_CDONE) == 0)
+ ;
/*
* Set board online.
* Hang receive buffer and start any pending
while ((addr->il_csr & IL_CDONE) == 0)
;
addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
- addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
- csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)|ILC_RCV|IL_RIE;
- addr->il_csr = csr;
+ addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
+ addr->il_csr =
+ ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
while ((addr->il_csr & IL_CDONE) == 0)
;
- is->is_startrcv = 0;
- is->is_oactive = 1;
+ is->is_flags = ILF_OACTIVE;
is->is_if.if_flags |= IFF_UP;
+ is->is_lastcmd = 0;
ilcint(unit);
splx(s);
if_rtinit(&is->is_if, RTF_UP);
ilstart(dev)
dev_t dev;
{
- int unit = ILUNIT(dev), dest, len;
+ int unit = ILUNIT(dev), len;
struct uba_device *ui = ilinfo[unit];
register struct il_softc *is = &il_softc[unit];
register struct ildevice *addr;
struct mbuf *m;
short csr;
-COUNT(ILSTART);
IF_DEQUEUE(&is->is_if.if_snd, m);
- if (m == 0)
- return;
+ addr = (struct ildevice *)ui->ui_addr;
+ if (m == 0) {
+ if ((is->is_flags & ILF_STATPENDING) == 0)
+ return;
+ addr->il_bar = is->is_ubaddr & 0xffff;
+ addr->il_bcr = sizeof (struct il_stats);
+ csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE;
+ is->is_flags &= ~ILF_STATPENDING;
+ goto startcmd;
+ }
len = if_wubaput(&is->is_ifuba, m);
+ /*
+ * 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_ifuba.ifu_flags & UBA_NEEDBDP)
UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp);
- addr = (struct ildevice *)ui->ui_addr;
addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff;
addr->il_bcr = len;
- csr = ((is->is_ifuba.ifu_w.ifrw_info>>2)&0xc000)|ILC_XMIT|IL_CIE|IL_RIE;
+ csr =
+ ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE;
+
+startcmd:
+ is->is_lastcmd = csr & IL_CMD;
addr->il_csr = csr;
- is->is_oactive = 1;
+ is->is_flags |= ILF_OACTIVE;
}
/*
* Command done interrupt.
- * This should only happen after a transmit command,
- * so it is equivalent to a transmit interrupt.
- * Start another output if more data to send.
*/
ilcint(unit)
int unit;
struct uba_device *ui = ilinfo[unit];
register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
short csr;
-COUNT(ILCINT);
- csr = addr->il_csr;
- if (is->is_oactive == 0) {
+ if ((is->is_flags & ILF_OACTIVE) == 0) {
printf("il%d: stray xmit interrupt, csr=%b\n", unit,
- csr, IL_BITS);
+ addr->il_csr, IL_BITS);
return;
}
- is->is_if.if_opackets++;
- is->is_oactive = 0;
- if (csr &= IL_STATUS) {
- is->is_if.if_oerrors++;
- printf("il%d: output error %d\n", unit, csr);
- }
+ csr = addr->il_csr;
/*
- * Hang receive buffer if it couldn't be done earlier (in ilrint).
+ * Hang receive buffer if it couldn't
+ * be done earlier (in ilrint).
*/
- if (is->is_startrcv) {
+ if (is->is_flags & ILF_RCVPENDING) {
addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
- addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
- csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)|ILC_RCV|IL_RIE;
- addr->il_csr = csr;
+ addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
+ addr->il_csr =
+ ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
while ((addr->il_csr & IL_CDONE) == 0)
;
- is->is_startrcv = 0;
+ is->is_flags &= ~ILF_RCVPENDING;
+ }
+ is->is_flags &= ~ILF_OACTIVE;
+ csr &= IL_STATUS;
+ switch (is->is_lastcmd) {
+
+ case ILC_XMIT:
+ is->is_if.if_opackets++;
+ if (csr > ILERR_RETRIES)
+ is->is_if.if_oerrors++;
+ break;
+
+ case ILC_STAT:
+ if (csr == ILERR_SUCCESS)
+ iltotal(is);
+ break;
}
if (is->is_ifuba.ifu_xtofree) {
m_freem(is->is_ifuba.ifu_xtofree);
is->is_ifuba.ifu_xtofree = 0;
}
- if (is->is_if.if_snd.ifq_head)
- ilstart(unit);
+ ilstart(unit);
}
/*
struct mbuf *m;
int len, off, resid;
register struct ifqueue *inq;
- short csr;
-COUNT(ILRINT);
is->is_if.if_ipackets++;
if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp);
il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr);
len = il->ilr_length - sizeof(struct il_rheader);
- if ((il->ilr_status&0x3) || len < 46 || len > ILMTU) {
+ if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 ||
+ len > ETHERMTU) {
is->is_if.if_ierrors++;
#ifdef notdef
if (is->is_if.if_ierrors % 100 == 0)
printf("il%d: += 100 input errors\n", unit);
#endif
- printf("il%d: input error (status=%x, len=%d)\n", unit,
- il->ilr_status, len);
goto setup;
}
* get true type from first 16-bit word past data.
* Remember that type was trailer by setting off.
*/
+ il->ilr_type = ntohs((u_short)il->ilr_type);
#define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off))))
- if (il->ilr_type >= ILPUP_TRAIL &&
- il->ilr_type < ILPUP_TRAIL+ILPUP_NTRAILER) {
- off = (il->ilr_type - ILPUP_TRAIL) * 512;
- if (off >= ILMTU)
+ if (il->ilr_type >= ETHERPUP_TRAIL &&
+ il->ilr_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
+ off = (il->ilr_type - ETHERPUP_TRAIL) * 512;
+ if (off >= ETHERMTU)
goto setup; /* sanity */
- il->ilr_type = *ildataaddr(il, off, u_short *);
- resid = *(ildataaddr(il, off+2, u_short *));
+ il->ilr_type = ntohs(*ildataaddr(il, off, u_short *));
+ resid = ntohs(*(ildataaddr(il, off+2, u_short *)));
if (off + resid > len)
goto setup; /* sanity */
len = off + resid;
switch (il->ilr_type) {
#ifdef INET
- case ILPUP_IPTYPE:
+ case ETHERPUP_IPTYPE:
schednetisr(NETISR_IP);
inq = &ipintrq;
break;
* If waiting for transmit command completion, set flag
* and wait until command completes.
*/
- if (is->is_oactive) {
- is->is_startrcv = 1;
+ if (is->is_flags & ILF_OACTIVE) {
+ is->is_flags |= ILF_RCVPENDING;
return;
}
addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
- addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
- csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)|ILC_RCV|IL_RIE;
- addr->il_csr = csr;
+ addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6;
+ addr->il_csr =
+ ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
while ((addr->il_csr & IL_CDONE) == 0)
;
}
int type, dest, s, error;
register struct il_softc *is = &il_softc[ifp->if_unit];
register struct mbuf *m = m0;
- register struct il_xheader *il;
- register int off, i;
+ register struct ether_header *il;
+ register int off;
-COUNT(ILOUTPUT);
switch (dst->sa_family) {
#ifdef INET
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)) {
- type = ILPUP_TRAIL + (off>>9);
+ type = ETHERPUP_TRAIL + (off>>9);
m->m_off -= 2 * sizeof (u_short);
m->m_len += 2 * sizeof (u_short);
- *mtod(m, u_short *) = ILPUP_IPTYPE;
- *(mtod(m, u_short *) + 1) = m->m_len;
+ *mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
+ *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
goto gottrailertype;
}
- type = ILPUP_IPTYPE;
+ type = ETHERPUP_IPTYPE;
off = 0;
goto gottype;
#endif
* allocate another.
*/
if (m->m_off > MMAXOFF ||
- MMINOFF + sizeof (struct il_xheader) > m->m_off) {
- m = m_get(M_DONTWAIT);
+ 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 il_xheader);
+ m->m_len = sizeof (struct ether_header);
} else {
- m->m_off -= sizeof (struct il_xheader);
- m->m_len += sizeof (struct il_xheader);
+ m->m_off -= sizeof (struct ether_header);
+ m->m_len += sizeof (struct ether_header);
}
- il = mtod(m, struct il_xheader *);
+ il = mtod(m, struct ether_header *);
if ((dest &~ 0xff) == 0)
- bcopy(ilbroadcastaddr, il->ilx_dhost, 6);
+ bcopy((caddr_t)ilbroadcastaddr, (caddr_t)il->ether_dhost, 6);
else {
- u_char *to = dest & 0x8000 ? is->is_enaddr : il_ectop;
+ u_char *to = dest & 0x8000 ? is->is_stats.ils_addr : il_ectop;
- bcopy(to, il->ilx_dhost, 3);
- il->ilx_dhost[3] = (dest>>8) & 0x7f;
- il->ilx_dhost[4] = (dest>>16) & 0xff;
- il->ilx_dhost[5] = (dest>>24) & 0xff;
+ bcopy((caddr_t)to, (caddr_t)il->ether_dhost, 3);
+ il->ether_dhost[3] = (dest>>8) & 0x7f;
+ il->ether_dhost[4] = (dest>>16) & 0xff;
+ il->ether_dhost[5] = (dest>>24) & 0xff;
}
- il->ilx_type = type;
+ bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)il->ether_shost, 6);
+ il->ether_type = htons((u_short)type);
/*
* Queue message on interface, and start output if interface
return (ENOBUFS);
}
IF_ENQUEUE(&ifp->if_snd, m);
- if (is->is_oactive == 0)
+ if ((is->is_flags & ILF_OACTIVE) == 0)
ilstart(ifp->if_unit);
splx(s);
return (0);
m_freem(m0);
return (error);
}
+
+/*
+ * Watchdog routine, request statistics from board.
+ */
+ilwatch(unit)
+ int unit;
+{
+ register struct il_softc *is = &il_softc[unit];
+ register struct ifnet *ifp = &is->is_if;
+ int s;
+
+ if (is->is_flags & ILF_STATPENDING) {
+ ifp->if_timer = is->is_scaninterval;
+ return;
+ }
+ s = splimp();
+ is->is_flags |= ILF_STATPENDING;
+ if ((is->is_flags & ILF_OACTIVE) == 0)
+ ilstart(ifp->if_unit);
+ splx(s);
+ ifp->if_timer = is->is_scaninterval;
+}
+
+/*
+ * Total up the on-board statistics.
+ */
+iltotal(is)
+ register struct il_softc *is;
+{
+ register u_short *interval, *sum, *end;
+
+ interval = &is->is_stats.ils_frames;
+ sum = &is->is_sum.ils_frames;
+ end = is->is_sum.ils_fill2;
+ while (sum < end)
+ *sum++ += *interval++;
+ is->is_if.if_collisions = is->is_sum.ils_collis;
+}