mirror of
https://github.com/PDP-10/its.git
synced 2026-03-22 17:08:15 +00:00
Interlan NI1010 driver for 4.3BSD-Tahoe.
This commit is contained in:
663
doc/if_il.c
Normal file
663
doc/if_il.c
Normal file
@@ -0,0 +1,663 @@
|
||||
/*
|
||||
* Copyright (c) 1982, 1986 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* %sccs.include.redist.c%
|
||||
*
|
||||
* @(#)if_il.c 7.8 (Berkeley) 12/16/90
|
||||
*/
|
||||
|
||||
#include "il.h"
|
||||
#if NIL > 0
|
||||
|
||||
/*
|
||||
* Interlan Ethernet Communications Controller interface
|
||||
*/
|
||||
#include "../include/pte.h"
|
||||
|
||||
#include "sys/param.h"
|
||||
#include "sys/systm.h"
|
||||
#include "sys/mbuf.h"
|
||||
#include "sys/buf.h"
|
||||
#include "sys/protosw.h"
|
||||
#include "sys/socket.h"
|
||||
#include "sys/vmmac.h"
|
||||
#include "sys/ioctl.h"
|
||||
#include "sys/errno.h"
|
||||
#include "sys/syslog.h"
|
||||
|
||||
#include "net/if.h"
|
||||
#include "net/netisr.h"
|
||||
#include "net/route.h"
|
||||
|
||||
#ifdef INET
|
||||
#include "netinet/in.h"
|
||||
#include "netinet/in_systm.h"
|
||||
#include "netinet/in_var.h"
|
||||
#include "netinet/ip.h"
|
||||
#include "netinet/if_ether.h"
|
||||
#endif
|
||||
|
||||
#ifdef NS
|
||||
#include "netns/ns.h"
|
||||
#include "netns/ns_if.h"
|
||||
#endif
|
||||
|
||||
#include "../include/cpu.h"
|
||||
#include "../include/mtpr.h"
|
||||
#include "if_il.h"
|
||||
#include "if_ilreg.h"
|
||||
#include "if_uba.h"
|
||||
#include "../uba/ubareg.h"
|
||||
#include "../uba/ubavar.h"
|
||||
|
||||
int ilprobe(), ilattach(), ilrint(), ilcint();
|
||||
struct uba_device *ilinfo[NIL];
|
||||
u_short ilstd[] = { 0 };
|
||||
struct uba_driver ildriver =
|
||||
{ ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
|
||||
#define ILUNIT(x) minor(x)
|
||||
int ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch(),ilstart();
|
||||
int ildebug = 0;
|
||||
|
||||
/*
|
||||
* 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 also have, for each interface, a UBA interface structure, which
|
||||
* contains information about the UNIBUS resources held by the interface:
|
||||
* map registers, buffered data paths, etc. Information is cached in this
|
||||
* structure for use by the if_uba.c routines in running the interface
|
||||
* efficiently.
|
||||
*/
|
||||
|
||||
struct ether_addr {
|
||||
u_char addr[6];
|
||||
};
|
||||
struct il_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 */
|
||||
struct ifuba is_ifuba; /* UNIBUS resources */
|
||||
int is_flags;
|
||||
#define ILF_RCVPENDING 0x2 /* start rcv in ilcint */
|
||||
#define ILF_STATPENDING 0x4 /* stat cmd pending */
|
||||
#define ILF_RUNNING 0x8 /* board is running */
|
||||
#define ILF_SETADDR 0x10 /* physical address is changed */
|
||||
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 */
|
||||
union {
|
||||
struct il_stats isu_stats; /* holds on-board statistics */
|
||||
struct ether_addr isu_maddrs[63]; /* multicast addrs */
|
||||
} is_isu;
|
||||
#define is_stats is_isu.isu_stats
|
||||
#define is_maddrs is_isu.isu_maddrs
|
||||
struct il_stats is_sum; /* summation over time */
|
||||
int is_ubaddr; /* mapping registers of is_stats */
|
||||
} il_softc[NIL];
|
||||
|
||||
ilprobe(reg)
|
||||
caddr_t reg;
|
||||
{
|
||||
register int br, cvec; /* r11, r10 value-result */
|
||||
register struct ildevice *addr = (struct ildevice *)reg;
|
||||
register i;
|
||||
|
||||
#ifdef lint
|
||||
br = 0; cvec = br; br = cvec;
|
||||
i = 0; ilrint(i); ilcint(i); ilwatch(i);
|
||||
#endif
|
||||
|
||||
addr->il_csr = ILC_OFFLINE|IL_CIE;
|
||||
DELAY(100000);
|
||||
i = addr->il_csr; /* clear CDONE */
|
||||
if (cvec > 0 && cvec != 0x200)
|
||||
cvec -= 4;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface exists: make available by filling in network interface
|
||||
* record. System will initialize the interface when it is ready
|
||||
* to accept packets. A STATUS command is done to get the ethernet
|
||||
* address and other interesting data.
|
||||
*/
|
||||
ilattach(ui)
|
||||
struct uba_device *ui;
|
||||
{
|
||||
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;
|
||||
|
||||
ifp->if_unit = ui->ui_unit;
|
||||
ifp->if_name = "il";
|
||||
ifp->if_mtu = ETHERMTU;
|
||||
ifp->if_flags = IFF_BROADCAST;
|
||||
|
||||
/*
|
||||
* Reset the board and map the statistics
|
||||
* buffer onto the Unibus.
|
||||
*/
|
||||
addr->il_csr = ILC_RESET;
|
||||
(void)ilwait(ui, "reset");
|
||||
|
||||
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;
|
||||
(void)ilwait(ui, "status");
|
||||
ubarelse(ui->ui_ubanum, &is->is_ubaddr);
|
||||
if (ildebug)
|
||||
printf("il%d: module=%s firmware=%s\n", ui->ui_unit,
|
||||
is->is_stats.ils_module, is->is_stats.ils_firmware);
|
||||
bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
|
||||
sizeof (is->is_addr));
|
||||
printf("il%d: hardware address %s\n", ui->ui_unit,
|
||||
ether_sprintf(is->is_addr));
|
||||
ifp->if_init = ilinit;
|
||||
ifp->if_output = ether_output;
|
||||
ifp->if_ioctl = ilioctl;
|
||||
ifp->if_reset = ilreset;
|
||||
ifp->if_start = ilstart;
|
||||
is->is_ifuba.ifu_flags = UBA_CANTWAIT;
|
||||
if_attach(ifp);
|
||||
}
|
||||
|
||||
ilwait(ui, op)
|
||||
struct uba_device *ui;
|
||||
char *op;
|
||||
{
|
||||
register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
|
||||
|
||||
while ((addr->il_csr&IL_CDONE) == 0)
|
||||
;
|
||||
if (addr->il_csr&IL_STATUS) {
|
||||
printf("il%d: %s failed, csr=%b\n", ui->ui_unit, op,
|
||||
addr->il_csr, IL_BITS);
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset of interface after UNIBUS reset.
|
||||
* If interface is on specified uba, reset its state.
|
||||
*/
|
||||
ilreset(unit, uban)
|
||||
int unit, uban;
|
||||
{
|
||||
register struct uba_device *ui;
|
||||
|
||||
if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 ||
|
||||
ui->ui_ubanum != uban)
|
||||
return;
|
||||
printf(" il%d", unit);
|
||||
il_softc[unit].is_if.if_flags &= ~IFF_RUNNING;
|
||||
il_softc[unit].is_flags &= ~ILF_RUNNING;
|
||||
ilinit(unit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialization of interface; clear recorded pending
|
||||
* operations, and reinitialize UNIBUS usage.
|
||||
*/
|
||||
ilinit(unit)
|
||||
int unit;
|
||||
{
|
||||
register struct il_softc *is = &il_softc[unit];
|
||||
register struct uba_device *ui = ilinfo[unit];
|
||||
register struct ildevice *addr;
|
||||
register struct ifnet *ifp = &is->is_if;
|
||||
int s;
|
||||
|
||||
/* not yet, if address still unknown */
|
||||
if (ifp->if_addrlist == (struct ifaddr *)0)
|
||||
return;
|
||||
if (is->is_flags & ILF_RUNNING)
|
||||
return;
|
||||
|
||||
if ((ifp->if_flags & IFF_RUNNING) == 0) {
|
||||
if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
|
||||
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_isu,
|
||||
sizeof (is->is_isu), 0);
|
||||
}
|
||||
ifp->if_watchdog = ilwatch;
|
||||
is->is_scaninterval = ILWATCHINTERVAL;
|
||||
ifp->if_timer = is->is_scaninterval;
|
||||
addr = (struct ildevice *)ui->ui_addr;
|
||||
|
||||
/*
|
||||
* Turn off source address insertion (it's faster this way),
|
||||
* and set board online. Former doesn't work if board is
|
||||
* already online (happens on ubareset), so we put it offline
|
||||
* first.
|
||||
*/
|
||||
s = splimp();
|
||||
addr->il_csr = ILC_RESET;
|
||||
if (ilwait(ui, "hardware diag")) {
|
||||
is->is_if.if_flags &= ~IFF_UP;
|
||||
splx(s);
|
||||
return;
|
||||
}
|
||||
addr->il_csr = ILC_CISA;
|
||||
while ((addr->il_csr & IL_CDONE) == 0)
|
||||
;
|
||||
/*
|
||||
* If we must reprogram this board's physical ethernet
|
||||
* address (as for secondary XNS interfaces), we do so
|
||||
* before putting it on line, and starting receive requests.
|
||||
* If you try this on an older 1010 board, it will total
|
||||
* wedge the board.
|
||||
*/
|
||||
if (is->is_flags & ILF_SETADDR) {
|
||||
bcopy((caddr_t)is->is_addr, (caddr_t)&is->is_isu,
|
||||
sizeof is->is_addr);
|
||||
addr->il_bar = is->is_ubaddr & 0xffff;
|
||||
addr->il_bcr = sizeof is->is_addr;
|
||||
addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_LDPA;
|
||||
if (ilwait(ui, "setaddr"))
|
||||
return;
|
||||
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;
|
||||
if (ilwait(ui, "verifying setaddr"))
|
||||
return;
|
||||
if (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
|
||||
sizeof (is->is_addr)) != 0) {
|
||||
printf("il%d: setaddr didn't work\n", ui->ui_unit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef MULTICAST
|
||||
if (is->is_if.if_flags & IFF_PROMISC) {
|
||||
addr->il_csr = ILC_PRMSC;
|
||||
if (ilwait(ui, "all multi"))
|
||||
return;
|
||||
} else if (is->is_if.if_flags & IFF_ALLMULTI) {
|
||||
too_many_multis:
|
||||
addr->il_csr = ILC_ALLMC;
|
||||
if (ilwait(ui, "all multi"))
|
||||
return;
|
||||
else {
|
||||
int i;
|
||||
register struct ether_addr *ep = is->is_maddrs;
|
||||
struct ether_multi *enm;
|
||||
struct ether_multistep step;
|
||||
/*
|
||||
* Step through our list of multicast addresses. If we have
|
||||
* too many multicast addresses, or if we have to listen to
|
||||
* a range of multicast addresses, turn on reception of all
|
||||
* multicasts.
|
||||
*/
|
||||
i = 0;
|
||||
ETHER_FIRST_MULTI(step, &is->is_ac, enm);
|
||||
while (enm != NULL) {
|
||||
if (++i > 63 && k != 0) {
|
||||
break;
|
||||
}
|
||||
*ep++ = *(struct ether_addr *)enm->enm_addrlo;
|
||||
ETHER_NEXT_MULTI(step, enm);
|
||||
}
|
||||
if (i = 0) {
|
||||
/* no multicasts! */
|
||||
} else if (i <= 63) {
|
||||
addr->il_bar = is->is_ubaddr & 0xffff;
|
||||
addr->il_bcr = i * sizeof (struct ether_addr);
|
||||
addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|
|
||||
LC_LDGRPS;
|
||||
if (ilwait(ui, "load multi"))
|
||||
return;
|
||||
} else {
|
||||
is->is_if.if_flags |= IFF_ALLMULTI;
|
||||
goto too_many_multis;
|
||||
}
|
||||
}
|
||||
#endif MULTI
|
||||
/*
|
||||
* Set board online.
|
||||
* Hang receive buffer and start any pending
|
||||
* writes by faking a transmit complete.
|
||||
* Receive bcr is not a multiple of 8 so buffer
|
||||
* chaining can't happen.
|
||||
*/
|
||||
addr->il_csr = ILC_ONLINE;
|
||||
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) + 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_if.if_flags |= IFF_RUNNING | IFF_OACTIVE;
|
||||
is->is_flags |= ILF_RUNNING;
|
||||
is->is_lastcmd = 0;
|
||||
ilcint(unit);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start output on interface.
|
||||
* Get another datagram to send off of the interface queue,
|
||||
* and map it to the interface before starting the output.
|
||||
*/
|
||||
ilstart(ifp)
|
||||
register struct ifnet *ifp;
|
||||
{
|
||||
int unit = ifp->if_unit, len;
|
||||
struct uba_device *ui = ilinfo[unit];
|
||||
register struct il_softc *is = &il_softc[unit];
|
||||
register struct ildevice *addr;
|
||||
struct mbuf *m;
|
||||
short csr;
|
||||
|
||||
IF_DEQUEUE(&is->is_if.if_snd, m);
|
||||
addr = (struct ildevice *)ui->ui_addr;
|
||||
if (m == 0) {
|
||||
if ((is->is_flags & ILF_STATPENDING) == 0)
|
||||
return (0);
|
||||
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->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff;
|
||||
addr->il_bcr = len;
|
||||
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_if.if_flags |= IFF_OACTIVE;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Command done interrupt.
|
||||
*/
|
||||
ilcint(unit)
|
||||
int unit;
|
||||
{
|
||||
register struct il_softc *is = &il_softc[unit];
|
||||
struct uba_device *ui = ilinfo[unit];
|
||||
register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
|
||||
short csr;
|
||||
|
||||
if ((is->is_if.if_flags & IFF_OACTIVE) == 0) {
|
||||
printf("il%d: stray xmit interrupt, csr=%b\n", unit,
|
||||
addr->il_csr, IL_BITS);
|
||||
return;
|
||||
}
|
||||
|
||||
csr = addr->il_csr;
|
||||
/*
|
||||
* Hang receive buffer if it couldn't
|
||||
* be done earlier (in ilrint).
|
||||
*/
|
||||
if (is->is_flags & ILF_RCVPENDING) {
|
||||
int s;
|
||||
|
||||
addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
|
||||
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;
|
||||
s = splhigh();
|
||||
while ((addr->il_csr & IL_CDONE) == 0)
|
||||
;
|
||||
splx(s);
|
||||
is->is_flags &= ~ILF_RCVPENDING;
|
||||
}
|
||||
is->is_if.if_flags &= ~IFF_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;
|
||||
}
|
||||
(void) ilstart(&is->is_if);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
ilrint(unit)
|
||||
int unit;
|
||||
{
|
||||
register struct il_softc *is = &il_softc[unit];
|
||||
struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr;
|
||||
register struct il_rheader *il;
|
||||
struct mbuf *m;
|
||||
int len, off, resid, s;
|
||||
register struct ifqueue *inq;
|
||||
|
||||
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&(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
|
||||
goto setup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deal with trailer protocol: if type is trailer type
|
||||
* 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 >= ETHERTYPE_TRAIL &&
|
||||
il->ilr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
|
||||
off = (il->ilr_type - ETHERTYPE_TRAIL) * 512;
|
||||
if (off >= ETHERMTU)
|
||||
goto setup; /* sanity */
|
||||
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;
|
||||
} else
|
||||
off = 0;
|
||||
if (len == 0)
|
||||
goto setup;
|
||||
|
||||
/*
|
||||
* Pull packet off interface. Off is nonzero if packet
|
||||
* has trailing header; ilget will then force this header
|
||||
* information to be at the front, but we still have to drop
|
||||
* the type and length which are at the front of any trailer data.
|
||||
*/
|
||||
m = if_rubaget(&is->is_ifuba, len, off, &is->is_if);
|
||||
if (m)
|
||||
ether_input(&is->is_if, (struct ether_header *)il->ilr_dhost, m);
|
||||
setup:
|
||||
/*
|
||||
* Reset for next packet if possible.
|
||||
* If waiting for transmit command completion, set flag
|
||||
* and wait until command completes.
|
||||
*/
|
||||
if (is->is_if.if_flags & IFF_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) + ETHERMTU + 6;
|
||||
addr->il_csr =
|
||||
((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
|
||||
s = splhigh();
|
||||
while ((addr->il_csr & IL_CDONE) == 0)
|
||||
;
|
||||
splx(s);
|
||||
}
|
||||
/*
|
||||
* 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_if.if_flags & IFF_OACTIVE) == 0)
|
||||
(void) ilstart(ifp);
|
||||
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;
|
||||
if ((is->is_flags & ILF_SETADDR) &&
|
||||
(bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr,
|
||||
sizeof (is->is_addr)) != 0)) {
|
||||
log(LOG_ERR, "il%d: physaddr reverted\n", is->is_if.if_unit);
|
||||
is->is_flags &= ~ILF_RUNNING;
|
||||
ilinit(is->is_if.if_unit);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an ioctl request.
|
||||
*/
|
||||
ilioctl(ifp, cmd, data)
|
||||
register struct ifnet *ifp;
|
||||
int cmd;
|
||||
caddr_t data;
|
||||
{
|
||||
register struct ifaddr *ifa = (struct ifaddr *)data;
|
||||
register struct il_softc *is = &il_softc[ifp->if_unit];
|
||||
int s = splimp(), error = 0;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case SIOCSIFADDR:
|
||||
ifp->if_flags |= IFF_UP;
|
||||
ilinit(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 *)
|
||||
(il_softc[ifp->if_unit].is_addr);
|
||||
} else {
|
||||
il_setaddr(ina->x_host.c_host, ifp->if_unit);
|
||||
return (0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case SIOCSIFFLAGS:
|
||||
if ((ifp->if_flags & IFF_UP) == 0 &&
|
||||
is->is_flags & ILF_RUNNING) {
|
||||
((struct ildevice *)
|
||||
(ilinfo[ifp->if_unit]->ui_addr))->il_csr = ILC_RESET;
|
||||
is->is_flags &= ~ILF_RUNNING;
|
||||
} else if (ifp->if_flags & IFF_UP &&
|
||||
(is->is_flags & ILF_RUNNING) == 0)
|
||||
ilinit(ifp->if_unit);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
}
|
||||
splx(s);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* set ethernet address for unit
|
||||
*/
|
||||
il_setaddr(physaddr, unit)
|
||||
u_char *physaddr;
|
||||
int unit;
|
||||
{
|
||||
register struct il_softc *is = &il_softc[unit];
|
||||
|
||||
if (! (is->is_flags & ILF_RUNNING))
|
||||
return;
|
||||
|
||||
bcopy((caddr_t)physaddr, (caddr_t)is->is_addr, sizeof is->is_addr);
|
||||
is->is_flags &= ~ILF_RUNNING;
|
||||
is->is_flags |= ILF_SETADDR;
|
||||
ilinit(unit);
|
||||
}
|
||||
#endif
|
||||
53
doc/if_il.h
Normal file
53
doc/if_il.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 1982, 1986 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* %sccs.include.redist.c%
|
||||
*
|
||||
* @(#)if_il.h 7.3 (Berkeley) 06/28/90
|
||||
*/
|
||||
|
||||
/*
|
||||
* Structure of an Ethernet header -- receive format
|
||||
*/
|
||||
struct il_rheader {
|
||||
u_char ilr_status; /* Frame Status */
|
||||
u_char ilr_fill1;
|
||||
u_short ilr_length; /* Frame Length */
|
||||
u_char ilr_dhost[6]; /* Destination Host */
|
||||
u_char ilr_shost[6]; /* Source Host */
|
||||
u_short ilr_type; /* Type of packet */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of statistics record
|
||||
*/
|
||||
struct il_stats {
|
||||
u_short ils_fill1;
|
||||
u_short ils_length; /* Length (should be 62) */
|
||||
u_char ils_addr[6]; /* Ethernet Address */
|
||||
u_short ils_frames; /* Number of Frames Received */
|
||||
u_short ils_rfifo; /* Number of Frames in Receive FIFO */
|
||||
u_short ils_xmit; /* Number of Frames Transmitted */
|
||||
u_short ils_xcollis; /* Number of Excess Collisions */
|
||||
u_short ils_frag; /* Number of Fragments Received */
|
||||
u_short ils_lost; /* Number of Times Frames Lost */
|
||||
u_short ils_multi; /* Number of Multicasts Accepted */
|
||||
u_short ils_rmulti; /* Number of Multicasts Rejected */
|
||||
u_short ils_crc; /* Number of CRC Errors */
|
||||
u_short ils_align; /* Number of Alignment Errors */
|
||||
u_short ils_collis; /* Number of Collisions */
|
||||
u_short ils_owcollis; /* Number of Out-of-window Collisions */
|
||||
u_short ils_fill2[8];
|
||||
char ils_module[8]; /* Module ID */
|
||||
char ils_firmware[8]; /* Firmware ID */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of Collision Delay Time Record
|
||||
*/
|
||||
struct il_collis {
|
||||
u_short ilc_fill1;
|
||||
u_short ilc_length; /* Length (should be 0-32) */
|
||||
u_short ilc_delay[16]; /* Delay Times */
|
||||
};
|
||||
123
doc/if_ilreg.h
Normal file
123
doc/if_ilreg.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 1982, 1986 Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* %sccs.include.redist.c%
|
||||
*
|
||||
* @(#)if_ilreg.h 7.3 (Berkeley) 06/28/90
|
||||
*/
|
||||
|
||||
/*
|
||||
* Interlan Ethernet Communications Controller interface
|
||||
*/
|
||||
struct ildevice {
|
||||
short il_csr; /* Command and Status Register */
|
||||
short il_bar; /* Buffer Address Register */
|
||||
short il_bcr; /* Byte Count Register */
|
||||
};
|
||||
|
||||
/*
|
||||
* Command and status bits
|
||||
*/
|
||||
#define IL_EUA 0xc000 /* Extended Unibus Address */
|
||||
#define IL_CMD 0x3f00 /* Command Function Code */
|
||||
#define IL_CDONE 0x0080 /* Command Done */
|
||||
#define IL_CIE 0x0040 /* Command Interrupt Enable */
|
||||
#define IL_RDONE 0x0020 /* Receive DMA Done */
|
||||
#define IL_RIE 0x0010 /* Receive Interrupt Enable */
|
||||
#define IL_STATUS 0x000f /* Command Status Code */
|
||||
|
||||
#define IL_BITS "\20\10CDONE\7CIE\6RDONE\5RIE"
|
||||
|
||||
/* command definitions */
|
||||
#define ILC_MLPBAK 0x0100 /* Set Module Interface Loopback Mode */
|
||||
#define ILC_ILPBAK 0x0200 /* Set Internal Loopback Mode */
|
||||
#define ILC_CLPBAK 0x0300 /* Clear Loopback Mode */
|
||||
#define ILC_PRMSC 0x0400 /* Set Promiscuous Receive Mode */
|
||||
#define ILC_CLPRMSC 0x0500 /* Clear Promiscuous Receive Mode */
|
||||
#define ILC_RCVERR 0x0600 /* Set Receive-On-Error Bit */
|
||||
#define ILC_CRCVERR 0x0700 /* Clear Receive-On-Error Bit */
|
||||
#define ILC_OFFLINE 0x0800 /* Go Offline */
|
||||
#define ILC_ONLINE 0x0900 /* Go Online */
|
||||
#define ILC_DIAG 0x0a00 /* Run On-board Diagnostics */
|
||||
#define ILC_ISA 0x0d00 /* Set Insert Source Address Mode */
|
||||
#define ILC_CISA 0x0e00 /* Clear Insert Source Address Mode */
|
||||
#define ILC_DEFPA 0x0f00 /* Set Physical Address to Default */
|
||||
#define ILC_ALLMC 0x1000 /* Set Receive All Multicast Packets */
|
||||
#define ILC_CALLMC 0x1100 /* Clear Receive All Multicast */
|
||||
#define ILC_STAT 0x1800 /* Report and Reset Statistics */
|
||||
#define ILC_DELAYS 0x1900 /* Report Collision Delay Times */
|
||||
#define ILC_RCV 0x2000 /* Supply Receive Buffer */
|
||||
#define ILC_LDXMIT 0x2800 /* Load Transmit Data */
|
||||
#define ILC_XMIT 0x2900 /* Load Transmit Data and Send */
|
||||
#define ILC_LDGRPS 0x2a00 /* Load Group Addresses */
|
||||
#define ILC_RMGRPS 0x2b00 /* Delete Group Addresses */
|
||||
#define ILC_LDPA 0x2c00 /* Load Physical Address */
|
||||
#define ILC_FLUSH 0x3000 /* Flush Receive BAR/BCR Queue */
|
||||
#define ILC_RESET 0x3f00 /* Reset */
|
||||
|
||||
/*
|
||||
* Error codes found in the status bits of the csr.
|
||||
*/
|
||||
#define ILERR_SUCCESS 0 /* command successful */
|
||||
#define ILERR_RETRIES 1 /* " " with retries */
|
||||
#define ILERR_BADCMD 2 /* illegal command */
|
||||
#define ILERR_INVCMD 3 /* invalid command */
|
||||
#define ILERR_RECVERR 4 /* receiver error */
|
||||
#define ILERR_BUFSIZ 5 /* buffer size too big */
|
||||
#define ILERR_FRAMESIZ 6 /* frame size too small */
|
||||
#define ILERR_COLLISIONS 8 /* excessive collisions */
|
||||
#define ILERR_BUFALIGNMENT 10 /* buffer not word aligned */
|
||||
#define ILERR_NXM 15 /* non-existent memory */
|
||||
|
||||
#define NILERRS 16
|
||||
#ifdef ILERRS
|
||||
char *ilerrs[NILERRS] = {
|
||||
"success", /* 0 */
|
||||
"success with retries", /* 1 */
|
||||
"illegal command", /* 2 */
|
||||
"inappropriate command", /* 3 */
|
||||
"failure", /* 4 */
|
||||
"buffer size exceeded", /* 5 */
|
||||
"frame too small", /* 6 */
|
||||
0, /* 7 */
|
||||
"excessive collisions", /* 8 */
|
||||
0, /* 9 */
|
||||
"buffer alignment error", /* 10 */
|
||||
0, /* 11 */
|
||||
0, /* 12 */
|
||||
0, /* 13 */
|
||||
0, /* 14 */
|
||||
"non-existent memory" /* 15 */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Diagnostics codes.
|
||||
*/
|
||||
#define ILDIAG_SUCCESS 0 /* no problems */
|
||||
#define ILDIAG_CHKSUMERR 1 /* ROM/RAM checksum error */
|
||||
#define ILDIAG_DMAERR 2 /* DMA not working */
|
||||
#define ILDIAG_XMITERR 3 /* xmit circuitry failure */
|
||||
#define ILDIAG_RECVERR 4 /* rcvr circuitry failure */
|
||||
#define ILDIAG_LOOPBACK 5 /* loopback test failed */
|
||||
|
||||
#define NILDIAGS 6
|
||||
#ifdef ILDIAGS
|
||||
char *ildiag[NILDIAGS] = {
|
||||
"success", /* 0 */
|
||||
"checksum error", /* 1 */
|
||||
"NM10 dma error", /* 2 */
|
||||
"transmitter error", /* 3 */
|
||||
"receiver error", /* 4 */
|
||||
"loopback failure", /* 5 */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Frame status bits, returned in frame status byte
|
||||
* at the top of each received packet.
|
||||
*/
|
||||
#define ILFSTAT_C 0x1 /* CRC error */
|
||||
#define ILFSTAT_A 0x2 /* alignment error */
|
||||
#define ILFSTAT_L 0x4 /* 1+ frames lost just before */
|
||||
Reference in New Issue
Block a user