-/* if_vv.c 6.3 83/12/22 */
+/* if_vv.c 6.6 84/08/29 */
#include "vv.h"
*/
#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/errno.h"
-#include "../h/time.h"
-#include "../h/kernel.h"
-#include "../h/ioctl.h"
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "buf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "vmmac.h"
+#include "errno.h"
+#include "ioctl.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 "../vax/mtpr.h"
#include "../vax/cpu.h"
-
+#include "../vax/mtpr.h"
+#include "if_vv.h"
+#include "if_uba.h"
#include "../vaxuba/ubareg.h"
#include "../vaxuba/ubavar.h"
-#include "../vaxif/if_vv.h"
-#include "../vaxif/if_uba.h"
-
/*
* N.B. - if WIRECENTER is defined wrong, it can well break
* the hardware!!
#define VVMTU (1024+512)
#define VVMRU (1024+512+16) /* space for trailer */
-int vv_tracehdr = 0, /* 1 => trace headers (slowly!!) */
- vv_logreaderrors = 1; /* 1 => log all read errors */
+int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */
+int vv_logreaderrors = 1; /* 1 => log all read errors */
#define vvtracehdr if (vv_tracehdr) vvprt_hdr
-int vvprobe(), vvattach(), vvrint(), vvxint();
+int vvprobe(), vvattach(), vvreset(), vvinit();
+int vvidentify(), vvstart(), vvxint(), vvwatchdog();
+int vvrint(), vvoutput(), vvioctl(), vvsetaddr();
struct uba_device *vvinfo[NVV];
u_short vvstd[] = { 0 };
struct uba_driver vvdriver =
{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
#define VVUNIT(x) minor(x)
-int vvinit(),vvioctl(),vvoutput(),vvreset(),vvsetaddr();
/*
* Software status of each interface.
struct ifuba vs_ifuba; /* UNIBUS resources */
short vs_oactive; /* is output active */
short vs_olen; /* length of last output */
- u_short vs_lastx; /* last destination address */
+ u_short vs_lastx; /* address of last packet sent */
+ u_short vs_lastr; /* address of last packet received */
short vs_tries; /* transmit current retry count */
short vs_init; /* number of ring inits */
short vs_nottaken; /* number of packets refused */
+ short vs_timeouts; /* number of transmit timeouts */
} vv_softc[NVV];
vvprobe(reg)
caddr_t reg;
{
register int br, cvec;
- register struct vvreg *addr = (struct vvreg *)reg;
+ register struct vvreg *addr;
#ifdef lint
br = 0; cvec = br; br = cvec;
#endif
+ addr = (struct vvreg *)reg;
/* reset interface, enable, and wait till dust settles */
addr->vvicsr = VV_RST;
addr->vvocsr = VV_RST;
vs->vs_if.if_ioctl = vvioctl;
vs->vs_if.if_output = vvoutput;
vs->vs_if.if_reset = vvreset;
+ vs->vs_if.if_timer = 0;
+ vs->vs_if.if_watchdog = vvwatchdog;
vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
#if defined(VAX750)
/* don't chew up 750 bdp's */
register struct vv_softc *vs;
register struct uba_device *ui;
register struct vvreg *addr;
- struct sockaddr_in *sin;
- int ubainfo, s;
+ register struct sockaddr_in *sin;
+ register int ubainfo, s;
vs = &vv_softc[unit];
ui = vvinfo[unit];
addr = (struct vvreg *)ui->ui_addr;
if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
- printf("vv%d: can't initialize\n", unit);
+ printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
vs->vs_if.if_flags &= ~IFF_UP;
return;
}
* Now that the uba is set up, figure out our address and
* update complete our host address.
*/
- vs->vs_if.if_host[0] = vvidentify(unit);
+ if ((vs->vs_if.if_host[0] = vvidentify(unit)) == 0) {
+ vs->vs_if.if_flags &= ~IFF_UP;
+ return;
+ }
printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
/*
DELAY(500000); /* let contacts settle */
vs->vs_init = 0;
vs->vs_nottaken = 0;
+ vs->vs_timeouts = 0;
+ vs->vs_lastx = 256; /* an invalid address */
+ vs->vs_lastr = 256; /* an invalid address */
/*
* Hang a receive and start any
* pending writes by faking a transmit complete.
register struct vv_softc *vs;
register struct uba_device *ui;
register struct vvreg *addr;
- struct mbuf *m;
- struct vv_header *v;
- int ubainfo, attempts, waitcount;
+ register struct mbuf *m;
+ register struct vv_header *v;
+ register int ubainfo, attempts, waitcount;
/*
* Build a multicast message to identify our address
addr = (struct vvreg *)ui->ui_addr;
attempts = 0; /* total attempts, including bad msg type */
m = m_get(M_DONTWAIT, MT_HEADER);
- if (m == NULL)
+ if (m == NULL) {
+ printf("vv%d: can't initialize, m_get() failed\n", unit);
return (0);
+ }
m->m_next = 0;
m->m_off = MMINOFF;
m->m_len = sizeof(struct vv_header);
addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
/*
* Wait for receive side to finish.
- * Extract source address (which will our own),
+ * Extract source address (which will be our own),
* and post to interface structure.
*/
DELAY(10000);
DELAY(1000);
continue;
}
- if (attempts++ >= 10) {
- printf("vv%d: can't initialize\n", unit);
- printf("vvinit loopwait: icsr = %b\n",
- 0xffff&(addr->vvicsr), VV_IBITS);
- vs->vs_if.if_flags &= ~IFF_UP;
- return (0);
- }
- goto retry;
+ if (attempts++ < VVIDENTRETRY)
+ goto retry;
}
- if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
- UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
- if (vs->vs_ifuba.ifu_xtofree)
+ /* deallocate mbuf used for send packet */
+ if (vs->vs_ifuba.ifu_xtofree) {
m_freem(vs->vs_ifuba.ifu_xtofree);
+ vs->vs_ifuba.ifu_xtofree = 0;
+ }
+ if (attempts >= VVIDENTRETRY) {
+ printf("vv%d: can't initialize after %d tries, icsr = %b\n",
+ unit, VVIDENTRETRY, 0xffff&(addr->vvicsr), VV_IBITS);
+ return (0);
+ }
+ /* Purge BDP before looking at packet we just received */
if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
vvstart(dev)
dev_t dev;
{
- int unit = VVUNIT(dev);
- struct uba_device *ui;
+ register struct uba_device *ui;
register struct vv_softc *vs;
register struct vvreg *addr;
- struct mbuf *m;
- int ubainfo;
- int dest;
+ register struct mbuf *m;
+ register int unit, ubainfo, dest, s;
+ unit = VVUNIT(dev);
ui = vvinfo[unit];
vs = &vv_softc[unit];
if (vs->vs_oactive)
* and map it to the UNIBUS. If no more requests,
* just return.
*/
+ s = splimp();
IF_DEQUEUE(&vs->vs_if.if_snd, m);
+ splx(s);
if (m == NULL) {
vs->vs_oactive = 0;
return;
restart:
/*
* Have request mapped to UNIBUS for transmission.
- * Purge any stale data from this BDP, and start the otput.
- */
- /*
- * The following test is questionable and isn't done in
- * the en driver...
+ * Purge any stale data from this BDP, and start the output.
+ *
+ * Make sure this packet will fit in the interface.
*/
if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) {
printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen);
addr->vvoea = (u_short) (ubainfo >> 16);
addr->vvowc = -((vs->vs_olen + 1) >> 1);
addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
+ vs->vs_if.if_timer = VVTIMEOUT;
vs->vs_oactive = 1;
}
ui = vvinfo[unit];
vs = &vv_softc[unit];
+ vs->vs_if.if_timer = 0;
addr = (struct vvreg *)ui->ui_addr;
oc = 0xffff & (addr->vvocsr);
if (vs->vs_oactive == 0) {
m_freem(vs->vs_ifuba.ifu_xtofree);
vs->vs_ifuba.ifu_xtofree = 0;
}
- if (vs->vs_if.if_snd.ifq_head == 0) {
- vs->vs_lastx = 256; /* an invalid address */
- return;
- }
vvstart(unit);
}
+/*
+ * Transmit watchdog timer routine.
+ * This routine gets called when we lose a transmit interrupt.
+ * The best we can do is try to restart output.
+ */
+vvwatchdog(unit)
+ int unit;
+{
+ register struct vv_softc *vs;
+ register int s;
+
+ vs = &vv_softc[unit];
+ if (vs->vs_if.if_flags & IFF_DEBUG)
+ printf("vv%d: lost a transmit interrupt.\n", unit);
+ vs->vs_timeouts++;
+ s = splimp();
+ vvstart(unit);
+ splx(s);
+}
+
/*
* V2lni interface receiver interrupt.
* If input error just drop packet.
int unit;
{
register struct vv_softc *vs;
- struct vvreg *addr;
+ register struct vvreg *addr;
register struct vv_header *vv;
register struct ifqueue *inq;
- struct mbuf *m;
- int ubainfo, len, off;
+ register struct mbuf *m;
+ int ubainfo, len, off, s;
short resid;
vs = &vv_softc[unit];
- addr = (struct vvreg *)vvinfo[unit]->ui_addr;
vs->vs_if.if_ipackets++;
+ addr = (struct vvreg *)vvinfo[unit]->ui_addr;
/*
* Purge BDP; drop if input error indicated.
*/
if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
if (addr->vvicsr & VVRERR) {
- if (vs->vs_if.if_flags & IFF_DEBUG && vv_logreaderrors)
- printf("vv%d: error vvicsr = %b\n", unit,
+ if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+ printf("vv%d: VVRERR, vvicsr = %b\n", unit,
0xffff&(addr->vvicsr), VV_IBITS);
goto dropit;
}
resid |= 0176000; /* ugly!!!! */
len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
len -= sizeof(struct vv_header);
- if (len > VVMRU || len <= 0)
+ if (len > VVMRU || len <= 0) {
+ if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+ printf("vv%d: len too big, len = %d, vvicsr = %b\n",
+ unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
goto dropit;
+ }
#define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off))))
if (vv->vh_type >= RING_IPTrailer &&
vv->vh_type < RING_IPTrailer+RING_IPNTrailer) {
off = (vv->vh_type - RING_IPTrailer) * 512;
- if (off > VVMTU)
+ if (off > VVMTU) {
+ if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+ printf("vv%d: VVMTU, off = %d, vvicsr = %b\n",
+ unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
goto dropit;
+ }
vv->vh_type = *vvdataaddr(vv, off, u_short *);
resid = *(vvdataaddr(vv, off+2, u_short *));
- if (off + resid > len)
+ if (off + resid > len) {
+ if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+ printf(
+ "vv%d: off = %d, resid = %d, vvicsr = %b\n",
+ unit, off, resid,
+ 0xffff&(addr->vvicsr), VV_IBITS);
goto dropit;
+ }
len = off + resid;
} else
off = 0;
- if (len == 0)
+ if (len == 0) {
+ if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+ printf("vv%d: len is zero, vvicsr = %b\n", unit,
+ 0xffff&(addr->vvicsr), VV_IBITS);
goto dropit;
+ }
m = if_rubaget(&vs->vs_ifuba, len, off);
- if (m == NULL)
+ if (m == NULL) {
+ if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
+ printf("vv%d: if_rubaget failed, vvicsr = %b\n", unit,
+ 0xffff&(addr->vvicsr), VV_IBITS);
goto dropit;
+ }
if (off) {
m->m_off += 2 * sizeof(u_short);
m->m_len -= 2 * sizeof(u_short);
}
+ /* Keep track of source address of this packet */
+ vs->vs_lastr = vv->vh_shost;
/*
* Demultiplex on packet type
*/
m_freem(m);
goto setup;
}
+ s = splimp();
if (IF_QFULL(inq)) {
IF_DROP(inq);
m_freem(m);
} else
IF_ENQUEUE(inq, m);
+ splx(s);
/*
* Reset for the next packet.
*/
*/
dropit:
vs->vs_if.if_ierrors++;
- if (vs->vs_if.if_flags & IFF_DEBUG && vv_logreaderrors)
- printf("vv%d: error vvicsr = %b\n", unit,
- 0xffff&(addr->vvicsr), VV_IBITS);
goto setup;
}
struct mbuf *m0;
struct sockaddr *dst;
{
- register struct mbuf *m = m0;
+ register struct mbuf *m;
register struct vv_header *vv;
register int off;
- int type, dest, s, error;
+ register int unit;
+ register struct vvreg *addr;
+ register struct vv_softc *vs;
+ register int s;
+ int type, dest, error;
+
+ m = m0;
+ unit = ifp->if_unit;
+ addr = (struct vvreg *)vvinfo[unit]->ui_addr;
+ vs = &vv_softc[unit];
+ /*
+ * Check to see if the input side has wedged.
+ *
+ * We are lower than device ipl when we enter this routine,
+ * so if the interface is ready with an input packet then
+ * an input interrupt must have slipped through the cracks.
+ *
+ * Avoid the race with an input interrupt by watching to see
+ * if any packets come in.
+ */
+ s = vs->vs_if.if_ipackets;
+ if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
+ if (vs->vs_if.if_flags & IFF_DEBUG)
+ printf("vv%d: lost a receive interrupt, icsr = %b\n",
+ unit, 0xffff&(addr->vvicsr), VV_IBITS);
+ s = splimp();
+ vvrint(unit);
+ splx(s);
+ }
switch (dst->sa_family) {
goto gottype;
#endif
default:
- printf("vv%d: can't handle af%d\n", ifp->if_unit,
- dst->sa_family);
+ printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
error = EAFNOSUPPORT;
goto bad;
}
goto qfull;
}
IF_ENQUEUE(&ifp->if_snd, m);
- if (vv_softc[ifp->if_unit].vs_oactive == 0)
- vvstart(ifp->if_unit);
+ if (vs->vs_oactive == 0)
+ vvstart(unit);
splx(s);
return (0);
qfull:
int cmd;
caddr_t data;
{
- struct ifreq *ifr;
- int s, error;
+ register struct ifreq *ifr;
+ register int s;
+ int error;
ifr = (struct ifreq *)data;
error = 0;
switch (cmd) {
case SIOCSIFADDR:
- /* too difficult to change addr while running */
- if ((ifp->if_flags & IFF_RUNNING) == 0) {
- vvsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
+ if (ifp->if_flags & IFF_RUNNING)
+ if_rtinit(ifp, -1); /* delete previous route */
+ vvsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
+ if (ifp->if_flags & IFF_RUNNING)
+ if_rtinit(ifp, RTF_UP);
+ else
vvinit(ifp->if_unit);
- } else
- error = EINVAL;
break;
default:
error = EINVAL;
}
splx(s);
- return (error);
+ return(error);
}
/*
* Set up the address for this interface. We use the network number
- * from the passed address and an invalid host number because vvinit()
- * is smart enough to figure out the host number out.
+ * from the passed address and an invalid host number; vvinit() will
+ * figure out the host number and insert it later.
*/
vvsetaddr(ifp, sin)
register struct ifnet *ifp;