X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/4023eed27a3d5dfd1145560a2a8cc42880469c82..961945a80c6f995f4567dbce8881af0bbdee211c:/usr/src/sys/vax/if/if_il.c diff --git a/usr/src/sys/vax/if/if_il.c b/usr/src/sys/vax/if/if_il.c index ab4d78f52e..677401c58f 100644 --- a/usr/src/sys/vax/if/if_il.c +++ b/usr/src/sys/vax/if/if_il.c @@ -1,35 +1,38 @@ -/* if_il.c 4.8 82/06/20 */ +/* 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 -#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]; @@ -37,7 +40,7 @@ u_short ilstd[] = { 0 }; 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 }; @@ -57,15 +60,18 @@ 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; { @@ -75,18 +81,17 @@ ilprobe(reg) #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 @@ -99,57 +104,45 @@ ilattach(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; - register short csr; struct sockaddr_in *sin; - int i, s, ubaddr; 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]); @@ -161,7 +154,10 @@ ilattach(ui) 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; @@ -195,17 +191,29 @@ ilinit(unit) 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 @@ -218,14 +226,14 @@ ilinit(unit) 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); @@ -239,7 +247,7 @@ ilinit(unit) 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; @@ -247,24 +255,41 @@ ilstart(dev) short csr; 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; @@ -274,37 +299,46 @@ ilcint(unit) register struct ildevice *addr = (struct ildevice *)ui->ui_addr; short csr; - 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); } /* @@ -325,21 +359,19 @@ ilrint(unit) struct mbuf *m; int len, off, resid; register struct ifqueue *inq; - short csr; 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; } @@ -348,14 +380,15 @@ ilrint(unit) * 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; @@ -380,7 +413,7 @@ ilrint(unit) switch (il->ilr_type) { #ifdef INET - case ILPUP_IPTYPE: + case ETHERPUP_IPTYPE: schednetisr(NETISR_IP); inq = &ipintrq; break; @@ -403,14 +436,14 @@ setup: * 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) ; } @@ -429,8 +462,8 @@ iloutput(ifp, m0, dst) 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; switch (dst->sa_family) { @@ -440,14 +473,14 @@ iloutput(ifp, m0, dst) 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 @@ -477,31 +510,32 @@ gottype: * 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 @@ -515,7 +549,7 @@ gottype: 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); @@ -524,3 +558,41 @@ bad: 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; +}