craig@loki.ARPA (12/18/84)
This is the cover letter for the sources of the ProNET driver for the SUN2. It also makes a good README file. The driver distribution contains 5 files: vv.4: the manual page (123 lines) vv.ms: the installation notes (261 lines) vv.h: one of the include files (1 line) if_vv.h: the other include file (146 lines) if_vv.c: the driver code itself. (1319 lines) The distribution itself is in a Bourne shell file, which if executed, extracts the files from itself. ("sh -x vv.shar"). Everything you ought to need to know is in vv.ms, so [nt]roffing a copy of it should be your first priority. Vv.4 is the manual page contains a complete set of driver error messages. If this still doesn't satisfy you, try reading if_vv.c -- it is pretty well documented. If you want information about the ring net itself, contact Proteon, Inc. (617) 655-3340. You can also reach them by mailing to acm@mit-borax. PLEASE READ THE DISCLAIMER AT THE END OF VV.MS! However, if you do have problems, please direct questions to me directly (not v2lni-people, and emphatically not any USENET mailing lists -- I'm not directly on USENET). Craig Partridge craig@bbn-loki {ARPA} craig%bbn-loki@csnet-relay {CSNET} {ihnp4,decvax,wjh12}!bbncca!craig {USENET}
craig@loki.ARPA (12/18/84)
This is the shell archive file (vv.shar) for the ProNET driver for the SUN2 Just run sh -x vv.shar and it will dump the various files in the current directory. Craig Partridge craig@bbn-loki [ARPANET] {ihnp4,decvax,wjh12}!bbncca!craig [USENET] craig%loki@csnet-relay [CSNET] SNIP-HERE-------------------------------------------------------------- echo 'sh - vv.h' sed 's/^X//' <<'_NO_MORE_TEXT_' > vv.h X#define NVV 1 _NO_MORE_TEXT_ echo 'sh if_vv.h' sed 's/^X//' <<'_NO_MORE_TEXT_' > if_vv.h X/* X * Part of the ProNET driver for the SUN (release 1.1) distributed by BBN Labs X * please see disclaimer statement in if_vv.c and accompanying documentation. X * X * $Log: if_vv.h,v $ X * Revision 1.2 84/12/12 10:33:19 craig X * add small distribution note X * X * Revision 1.1 84/10/17 12:08:07 craig X * Initial revision X * X */ X X/* X * Local network header for V2LNI Ring X * This is arbitrated by "V2LNI-PEOPLE@MIT-MC" X * (aka Joel N. Chiappa) X */ X X#define NEW_BROADCAST /* new plas for broadcast problem */ X X Xstruct vv_header { X /* the first two fields are required by the hardware */ X u_char vh_dhost; /* destination address */ X u_char vh_shost; /* source address */ X /* the next three fields are the local network header */ X u_char vh_version; /* header version */ X u_char vh_type; /* packet type => protocol number */ X u_short vh_info; /* protocol-specific information */ X}; X X/* reversed version of header used when you don't want to have to swab */ Xstruct vv_rheader { X u_char vh_shost; X u_char vh_dhost; X u_char vh_type; X u_char vh_version; X u_short vh_info; X}; X X#define RING_VERSION 2 /* current version of v2lni header */ X X/* X * Packet types (protocol numbers) in v2lni header X */ X#define RING_IP 1 X#define RING_IPTrailer 2 X#define RING_IPNTrailer 16 X#define RING_WHOAMI 0xa5 /* insure some bit transitions */ X X#ifdef NEW_BROADCAST X#define VV_BROADCAST 0xff /* hardware-defined broadcast address */ X#else X#define VV_BROADCAST 0x00 /* hardware-defined broadcast address */ X#endif X X/* X * Proteon V2LNI Hardware definitions X * register bit definitions - new style X */ X X#ifndef HARDSWAB X X#define VV_ENB 01 /* Enable Operation */ X#define VV_DEN 02 /* Enable DMA */ X#define VV_HEN 04 /* Host Relay Enable (Rcv) */ X#define VV_CPB 04 /* Clear Packet Buffer (Xmit) */ X#define VV_STE 010 /* Self Test Enable (Rcv) */ X#define VV_UT1 010 /* Unused (Xmit) */ X#define VV_LPB 020 /* Modem Disable (Rcv) */ X#define VV_INR 020 /* Initialize Ring (Xmit) */ X#define VV_RST 040 /* Reset */ X#define VV_IEN 0100 /* Interrupt Enable */ X#define VV_RDY 0200 /* Done */ X#define VV_DPR 0400 /* Data Present (Rcv) */ X#define VV_RFS 0400 /* Refused (Xmit) */ X#define VV_NXM 01000 /* Non Existent Memory */ X#define VV_OVR 02000 /* Overrun */ X#define VV_ODB 04000 /* Odd Byte (Achtung, mein Fuehrer) (Rcv) */ X#define VV_UT2 04000 /* Unused (Xmit) */ X#define VV_LDE 010000 /* Link Data Error (Rcv) */ X#define VV_OPT 010000 /* Output Timeout (Xmit) */ X#define VV_NOK 020000 /* Ring Not OK */ X#define VV_BDF 040000 /* Bad Format in Operation */ X#define VV_NIR 0100000 /* Not in Ring */ X X#define VV_IBITS \ X"\10\20NIR\17BDF\16NOK\15LDE\14ODB\13OVR\12NXM\11DPR\10RDY\7IEN\6RST\5LPB\4STE\3HEN\2DEN\1ENB" X X#define VV_OBITS \ X"\10\20NIR\17BDF\16NOK\15OPT\13OVR\12NXM\11RFS\10RDY\7IEN\6RST\5INR\3HEN\2DEN\1ENB" X X#else /* HARDSWABBING */ X X#define VV_ENB 0400 /* Enable Operation */ X#define VV_DEN 01000 /* Enable DMA */ X#define VV_HEN 02000 /* Host Relay Enable (Rcv) */ X#define VV_CPB 02000 /* Clear Packet Buffer (Xmit) */ X#define VV_STE 04000 /* Self Test Enable (Rcv) */ X#define VV_UT1 04000 /* Unused (Xmit) */ X#define VV_LPB 010000 /* Modem Disable (Rcv) */ X#define VV_INR 010000 /* Initialize Ring (Xmit) */ X#define VV_RST 020000 /* Reset */ X#define VV_IEN 040000 /* Interrupt Enable */ X#define VV_RDY 0100000 /* Done */ X#define VV_DPR 01 /* Data Present (Rcv) */ X#define VV_RFS 01 /* Refused (Xmit) */ X#define VV_NXM 02 /* Non Existent Memory */ X#define VV_OVR 04 /* Overrun */ X#define VV_ODB 010 /* Odd Byte (Achtung, mein Fuehrer) (Rcv) */ X#define VV_UT2 010 /* Unused (Xmit) */ X#define VV_LDE 020 /* Link Data Error (Rcv) */ X#define VV_OPT 020 /* Output Timeout (Xmit) */ X#define VV_NOK 040 /* Ring Not OK */ X#define VV_BDF 0100 /* Bad Format in Operation */ X#define VV_NIR 0200 /* Not in Ring */ X X#define VV_IBITS \ X"\10\20RDY\17IEN\16RST\15LPB\14STE\13HEN\12DEN\11ENB\10NIR\7BDF\6NOK\5LDE\4ODB\3OVR\2NXM\1DPR" X X#define VV_OBITS \ X"\10\10NIR\7BDF\6NOK\5OPT\3OVR\2NXM\1RFS\20RDY\17IEN\16RST\15INR\13HEN\12DEN\11ENB" X X#endif /* HARDSWABBING */ X X#define VVXERR (VV_NXM|VV_OVR|VV_OPT|VV_BDF) /* Xmit errs */ X#define VVRERR (VV_NXM|VV_OVR|VV_ODB|VV_BDF) /* Rcv errs */ X#define VVFE (VV_NXM|VV_OVR) /* Fatal errors */ X X X/* device registers */ Xstruct vvreg { X u_short vvila; /* input addr (low) */ X u_short vviha; /* input addr (hi) */ X short vvicsr; /* input csr */ X u_short vviwc; /* input word count */ X u_short vvola; /* output addr (low) */ X u_short vvoha; /* output addr (hi) */ X short vvocsr; /* output csr */ X u_short vvowc; /* output word count */ X}; X X#define VVRETRY 7 /* output retry limit */ X#define VVIDENTRETRY 10 /* identify loop retry limit */ X#define VVTIMEOUT 60 /* seconds before a transmit timeout */ _NO_MORE_TEXT_ echo 'sh - if_vv.c' sed 's/^X//' <<'_NO_MORE_TEXT_' > if_vv.c X/**************************************************************************/ X/* Proteon 10 Meg Ring Driver. for 4.2 SUN (release 1.1). */ X/* Derived from Craig Leres' 4.2 VAX driver by Craig Partridge, of Bolt, */ X/* Beranek and Newman, Cambridge, MA. Thanks also to Chuck O'Hare of */ X/* Wisconsin who provided copies of their 4.1c driver. */ X/* see disclaimer below.... */ X/* */ X/* This device is called "vv" because its "real name", V2LNI won't work */ X/* if shortened to the obvious "v2". Hence the subterfuge. */ X/* */ X/* SUN implementation notes: */ X/* */ X/* oct 84, initial port. Done on Rev C boards on a SUN2. Some */ X/* important observations/comments: */ X/* */ X/* (1) Swabbing is a bizarre problem. Here's what we found we had */ X/* to do.... If the hardware is not wired to swab, then you must */ X/* swab the data, but not the registers. However, if the hardware */ X/* is swabbing, you leave the data alone but swab the registers. */ X/* Apparently SUN's MMU is smart enough to figure out that the */ X/* registers are in mbio space, and quietly swabs their values */ X/* for you -- which screws when the ProNet board is swabbinb.... */ X/* */ X/* (2) There seemed no good reason to specify a register address */ X/* in the code, so vvstd[] is simply 0. This doesn't seem to make */ X/* any difference -- the kernel still finds the device, and it */ X/* saves me from worries that SUN will decide to put a new device */ X/* in where I decided to put the ring. */ X/* */ X/* (3) A caveat to people dealing with the boards. After */ X/* two days of tearing my hair I discovered an undocumented */ X/* feature of the ProNet boards -- some registers, in particular */ X/* the word count registers, have garbage bits which you have to */ X/* mask off. (vv_iwc and vv_owc are only good in the low 10 bits) */ X/* */ X/* (4) Speeding this driver is probably possible but likely to be */ X/* tricky. The basic structure of the driver is that of the */ X/* Leres driver, which seems to be quite good. The differences */ X/* are mostly a result of dealing with the SUN/Multibus. */ X/* If you are searching for speed increases, look at the new code. */ X/* The most productive place to look, I think, is in emptybuf(). */ X/* Here you can take advantage of the knowledge that all data is */ X/* short aligned, and write a tighter version of bcopy which moves */ X/* shorts in an unrolled loop. Such a routine should be about */ X/* 30% faster than bcopy -- but how much that affects overall */ X/* driver thruput wasn't clear, and I didn't feel like testing it */ X/* */ X/* (5) The data checking in the driver. QUICKTEST makes little or */ X/* no effect on thruput. SLOWTEST will, because it does a modifed */ X/* Internet checksum. (Modified in that we steal a bit to tell us */ X/* if the true packet length is odd or even). */ X/* */ X/* This software is in the public domain and is being provided free by */ X/* BBN Labs to all users of ARPANET and USENET. BBN disclaims all */ X/* express warranties with regard to any use of this software, including */ X/* all implied warranties of merchandability and fitness. In no event */ X/* shall BBN be liable for any direct, special, indirect or consequential*/ X/* damages or any damages whatsoever resulting from loss of use, data or */ X/* profits, or any other injury, whether in an action of contract, */ X/* negligence or other tortious action, arising out of or in connection */ X/* with the use or performance of this software. */ X/**************************************************************************/ X X/* X * Additions/Mods Log: X * X * $Log: if_vv.c,v $ X * Revision 1.6 84/12/12 10:29:43 craig X * add disclaimer X * X * Revision 1.5 84/12/07 10:28:04 craig X * remove 1.3 fixes. I have been unable to test them to my X * satisfaction, and no beta test site has reported them as bugs. X * if it ain't broke, don't fix it... X * X * Revision 1.4 84/12/03 16:02:20 craig X * make input error message consistent with VAX X * X * Revision 1.3 84/10/31 15:53:35 craig X * fixed two very minor bugs in error handling, related X * to VVMTU and VVBUFSIZE errors X * X * Revision 1.2 84/10/18 10:57:04 craig X * bug fixes in vvsetaddr and vvinit so addresses X * treated correctly X * X * Revision 1.1 84/10/17 12:07:02 craig X * Initial revision X * X */ X Xstatic char rcsid[] = "$Header: if_vv.c,v 1.6 84/12/12 10:29:43 craig Exp $"; X X X/**************************************************************************/ X/* all the following stuff is configuration control -- some definitions */ X/* affect values in include files. */ X/**************************************************************************/ X X/**************************************************************************/ X/* N.B. - if WIRECENTER is defined wrong, it can well break */ X/* the hardware!! */ X/**************************************************************************/ X X#define WIRECENTER X X/**************************************************************************/ X/* Is proNet board doing byteswabbing or do we have to? */ X/**************************************************************************/ X X#define HARDSWAB X X/**************************************************************************/ X/* cheap or EXPENSIVE tests to be done on packets?? */ X/* DEFINE NONE, ONE OR THE OTHER BUT NOT BOTH! */ X/**************************************************************************/ X X/* #define QUICKTEST */ X/* #define SLOWTEST */ X X X/**************************************************************************/ X/* not clear that all of these includes are necessary */ X/**************************************************************************/ X X#include "../machine/pte.h" X X#include "../h/param.h" X#include "../h/systm.h" X#include "../h/mbuf.h" X#include "../h/buf.h" X#include "../h/protosw.h" X#include "../h/socket.h" X#include "../h/vmmac.h" X#include "../h/errno.h" X#include "../h/ioctl.h" X X#include "../net/if.h" X#include "../net/netisr.h" X#include "../net/route.h" X X#include "../netinet/in.h" X#include "../netinet/in_systm.h" X#include "../netinet/ip.h" X#include "../netinet/ip_var.h" X X#include "../sun/mmu.h" X X#include "../sundev/mbvar.h" X X#include "../sunif/if_vv.h" X#include "vv.h" X X X#ifdef WIRECENTER X#define VV_CONF VV_HEN /* drive wire center relay */ X#else X#define VV_CONF VV_STE /* allow operation without wire center */ X#endif X X/**************************************************************************/ X/* maximum transmission unit defined -- 1536 size is historical */ X/**************************************************************************/ X X/* #define VVBUFSIZE (2036) */ X#define VVBUFSIZE (1536) X#define VVMTU (VVBUFSIZE-sizeof(struct vv_header)) X X/**************************************************************************/ X/* debugging and tracing stuff */ X/**************************************************************************/ X Xint vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */ Xint vv_logreaderrors = 1; /* 1 => log all read errors */ X X#define vvtracehdr if (vv_tracehdr) vvprt_hdr X X/**************************************************************************/ X/* list of driver routines and necessary data definitions for kernel */ X/**************************************************************************/ X Xint vvprobe(), vvattach(), vvreset(), vvinit(); Xint vvidentify(), vvstart(), vvxint(), vvwatchdog(); Xint vvrint(), vvoutput(), vvioctl(), vvsetaddr(); Xint vvintr(); X Xstruct mb_device *vvinfo[NVV]; X Xu_long vvstd[] = X{ X 0 X} ; X Xstruct mb_driver vvdriver = X{ X vvprobe, 0, vvattach, 0, /* probe, slave, setup, start transfer */ X 0, vvintr, vvstd, 0, /* done, interrupt, addrs, mem addrs */ X 0, "vv", vvinfo, 0, /* memsize, name, mbinit, controller */ X 0, MDR_OBIO, 0 /* mbcinit, flags, driver */ X} ; X X#define VVUNIT(x) minor(x) X X/**************************************************************************/ X/* Software status of each interface. */ X/* */ X/* Each interface is referenced by a network interface structure, */ X/* vs_if, which the routing code uses to locate the interface. */ X/* Structure contains the output queue for the interface, its address, ...*/ X/**************************************************************************/ X Xstruct vv_softc X{ X struct ifnet vs_if; /* network-visible interface */ X short vs_oactive; /* is output active */ X short vs_tries; /* transmit current retry count */ X short vs_init; /* number of ring inits */ X short vs_nottaken; /* number of packets refused */ X short vs_timeouts; /* number of transmit timeouts */ X short vs_olen; /* output length */ X int vs_imap; /* DVMA map for ibuf */ X int vs_omap; /* DVMA map for obuf */ X struct buf *vs_obuf; /* output mbuf */ X struct buf *vs_ibuf; /* input mbuf */ X} Xvv_softc[NVV]; X X X/**************************************************************************/ X/* */ X/* flip the bytes in a u_short. Has to be done if board is swabbing */ X/* */ X/**************************************************************************/ X X#ifndef HARDSWAB X X#define swabs(s) ((u_short)s) X X#else /* HARDSWABBING */ X Xu_short swabs(s) Xregister u_short s; X{ X register u_short tmp; X X tmp = (s >> 8); X s <<= 8; X X return((tmp|s) & 0xffff); X} X#endif /* HARDSWAB */ X X X/**************************************************************************/ X/* */ X/* flip the bytes in a buffer. Only has to be done if board not swabbing */ X/* the asm() is assuredly not worth keeping, I just don't have a non */ X/* swabbing board to test the change on. */ X/* */ X/**************************************************************************/ X X#ifndef HARDSWAB X Xflip(buf,buflen) Xchar *buf; Xint buflen; /* cannot be odd */ X{ X register u_short *p; X register u_short word, tmp; X register int len; X X p = (u_short *) buf; X len = (buflen+1) >> 1; X X while (len > 0) X { X word = *p; X asm(" rorw #8,d7"); /* d7 is word */ X *p = word; X p++; X len--; X } X} X#endif HARDSWAB X X X/**************************************************************************/ X/* */ X/* takes a chain of mbufs and copies the chain into a buffer. */ X/* returns the number of bytes put into the buffer. if board is */ X/* not swabbing it also swabs the bytes. */ X/* */ X/**************************************************************************/ X Xstatic Xint fillbuf(buf,mchain) Xstruct buf *buf; Xstruct mbuf *mchain; X{ X register struct mbuf *m = mchain; X register int i = 0; X register caddr_t mp,bp; X X bp = buf->b_un.b_addr; X X while (m) X { X mp = mtod(m,caddr_t); X bcopy(mp,bp,m->m_len); X X i += m->m_len; X X bp += m->m_len; X m = m->m_next; X } X X#ifndef HARDSWAB Xflip(buf->b_un.b_addr,i); X#endif X Xvvtracehdr("output",(struct vv_header *)buf->b_un.b_addr); X Xreturn(i); X} X X/**************************************************************************/ X/* */ X/* empties a buffer into a chain of mbufs. returns the start of the chain.*/ X/* */ X/* this routine is admitted to be hard to understand. It is doing three */ X/* things at once: copying the buffer, moving IP trailers to the front of */ X/* the packet and skipping the ring header. Hope this helps */ X/* */ X/**************************************************************************/ X Xstatic Xstruct mbuf *emptybuf(buf,totlen,off0,skip) Xstruct buf *buf; Xregister int totlen; /* bytes to copy */ Xint off0, skip; /* trailer offset, hdr len */ X{ X register struct mbuf *m; X register caddr_t bp; X register struct mbuf **mp; X register int len; X int off = off0; X struct mbuf *top; X X#ifndef HARDSWAB X flip(buf->b_un.b_addr,totlen+skip); X#endif X X vvtracehdr("input",(struct vv_header *)buf->b_un.b_addr); X X X top = (struct mbuf *) 0; X mp = ⊤ X bp = buf->b_un.b_addr + skip; X X while (totlen > 0) X { X MGET(m,M_DONTWAIT,MT_DATA); X if (m == (struct mbuf *)0) X goto bad; X X if (off) X { X len = totlen - off; X bp = buf->b_un.b_addr + off + skip; X } X else X len = totlen; X X m->m_len = MIN(MLEN,len); X m->m_off = MMINOFF; X m->m_next = (struct mbuf *)0; X X bcopy(bp,mtod(m,caddr_t),m->m_len); X bp += m->m_len; X X *mp = m; X mp = &m->m_next; X X if (off) X { X off += m->m_len; X if (off == totlen) X { X bp = buf->b_un.b_addr + skip; X off = 0; X totlen = off0; X } X } X else X totlen -= m->m_len; X } X return(top); X Xbad : X if (top != (struct mbuf *)0) X m_freem(top); X return((struct mbuf *)0); X} X X/**************************************************************************/ X/* */ X/* A weak probe routine........ */ X/* */ X/**************************************************************************/ X Xvvprobe(reg) Xcaddr_t reg; X{ X register struct vvreg *addr; X X addr = (struct vvreg *)reg; X X /* are the registers there? */ X if ((peek(&addr->vvicsr) == -1) || (peek(&addr->vvocsr) == -1)) X return(0); X X /* reset interface, enable, and wait till dust settles */ X X addr->vvicsr = VV_RST; X addr->vvocsr = VV_RST; X DELAY(100000); X X addr->vvocsr = 0; X return(sizeof(struct vvreg)); X} X X/**************************************************************************/ X/* */ X/* Interface exists: make available by filling in network interface */ X/* record. System will initialize the interface when it is ready */ X/* to accept packets. */ X/* */ X/**************************************************************************/ X Xvvattach(md) Xstruct mb_device *md; X{ X register struct vv_softc *vs; X X vs = &vv_softc[md->md_unit]; X X vs->vs_if.if_unit = md->md_unit; X vs->vs_if.if_name = "vv"; X vs->vs_if.if_mtu = VVMTU; X vs->vs_if.if_init = vvinit; X vs->vs_if.if_ioctl = vvioctl; X vs->vs_if.if_output = vvoutput; X vs->vs_if.if_reset = vvreset; X vs->vs_if.if_timer = 0; X vs->vs_if.if_watchdog = vvwatchdog; X X /* no bufs yet */ X vs->vs_obuf = vs->vs_ibuf = (struct buf *)0; X X if_attach(&vs->vs_if); X} X X/**************************************************************************/ X/* */ X/* reset of interface after MULTIBUS reset */ X/* */ X/**************************************************************************/ X Xvvreset(unit) Xint unit; X{ X register struct mb_device *md; X X if (unit >= NVV || (md = vvinfo[unit]) == 0 || md->md_alive == 0) X return; X X printf(" vv%d", unit); X vvinit(unit); X} X X X/**************************************************************************/ X/* */ X/* Initialization of interface; clear recorded pending */ X/* operations, and start any pending writes. */ X/* */ X/**************************************************************************/ X Xvvinit(unit) Xint unit; X{ X register struct vv_softc *vs; X register struct mb_device *md; X register struct vvreg *addr; X register struct sockaddr_in *sin; X register int s; X int mbaddr; X X vs = &vv_softc[unit]; X md = vvinfo[unit]; X sin = (struct sockaddr_in *)&vs->vs_if.if_addr; X X /* If the network number is still zero, then called too soon. */ X X if (in_netof(sin->sin_addr) == 0) X return; X X addr = (struct vvreg *)md->md_addr; X X /* allocate the buffers for the device */ X X if (vs->vs_obuf == (struct buf *)0) X { X vs->vs_obuf = geteblk(VVBUFSIZE); X vs->vs_omap = mbsetup(md->md_hd,vs->vs_obuf,MB_CANTWAIT); X } X X if (vs->vs_ibuf == (struct buf *)0) X { X vs->vs_ibuf = geteblk(VVBUFSIZE); X vs->vs_imap = mbsetup(md->md_hd,vs->vs_ibuf,MB_CANTWAIT); X } X X /* vvidentify sends out broadcast packet to find addr */ X X if ((vs->vs_if.if_host[0] = vvidentify(unit)) == 0) X { X vs->vs_if.if_flags &= ~IFF_UP; X X /* free buffers in case it's device problems */ X mbrelse(md->md_hd,vs->vs_ibuf,&(vs->vs_imap)); X brelse(vs->vs_ibuf); X mbrelse(md->md_hd,vs->vs_obuf,&(vs->vs_omap)); X brelse(vs->vs_obuf); X vs->vs_ibuf = vs->vs_obuf = (struct buf *)0; X X return; X } X X printf("vv%d: host %d\n",unit,vs->vs_if.if_host[0]); X X sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); X X /* reset and join ring */ X X addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ X addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */ X DELAY(500000); /* let contacts settle */ X X vs->vs_init = 0; X vs->vs_nottaken = 0; X vs->vs_timeouts = 0; X X /* Hang a receive and start any pending writes by X faking a transmit complete. */ X X s = splimp(); X X mbaddr = MBI_ADDR(vs->vs_imap); X X addr->vvila = swabs(mbaddr & 0xffff); X addr->vviha = swabs((mbaddr >> 16) & 0x0ff); X addr->vviwc = swabs(VVBUFSIZE >> 1); X addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; X vs->vs_oactive = 1; X vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING; X vvxint(unit); X X splx(s); X X if_rtinit(&vs->vs_if, RTF_UP); X} X X/**************************************************************************/ X/* */ X/* Return our host address. */ X/* */ X/**************************************************************************/ X Xvvidentify(unit) Xint unit; X{ X register struct vv_softc *vs; X register struct vvreg *addr; X#ifndef HARDSWAB X register struct vv_rheader *v; X#else X register struct vv_header *v; X#endif X register int attempts, waitcount; X u_long i_mbaddr, o_mbaddr; X u_short shost = 0; X X /* Build a message to identify our address */ X X vs = &vv_softc[unit]; X addr = (struct vvreg *)vvinfo[unit]->md_addr; X attempts = 0; /* total attempts, including bad msg type */ X X v = (struct vv_header *)(vs->vs_obuf->b_un).b_addr; X v->vh_dhost = VV_BROADCAST; /* multicast destination address */ X v->vh_shost = 0; /* will be overwritten with ours */ X v->vh_version = RING_VERSION; X v->vh_type = RING_WHOAMI; X v->vh_info = 0; X X vs->vs_olen = sizeof(struct vv_header) >> 1; X X i_mbaddr = MBI_ADDR(vs->vs_imap); X o_mbaddr = MBI_ADDR(vs->vs_omap); X X /* X * Reset interface, establish Digital Loopback Mode, and X * send the multicast (to myself) with Input Copy enabled. X */ X Xretry : X /* enable input */ X X addr->vvicsr = VV_RST; X addr->vvila = swabs(i_mbaddr & 0xffff); X addr->vviha = swabs((i_mbaddr >> 16) & 0x0ff); X addr->vviwc = swabs(VVBUFSIZE >> 1); X addr->vvicsr = VV_STE|VV_LPB|VV_DEN|VV_ENB; X X X /* let flag timers fire so ring will initialize */ X DELAY(2000000); /* about 2 SECONDS on a 780!! */ X X /* o.k. now send our output packet */ X addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ X addr->vvola = swabs(o_mbaddr & 0xffff); X addr->vvoha = swabs((o_mbaddr >> 16) & 0x0ff); X addr->vvowc = swabs(vs->vs_olen); X addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; X X /* POLL receive side to finish */ X X DELAY(10000); X X for (waitcount = 0; waitcount < 10; waitcount++) X { X if (addr->vvicsr & VV_RDY) X goto gotit; X DELAY(1000); X } X X if (attempts++ < VVIDENTRETRY) X goto retry; X X /* FAILED */ X X printf("vv%d: can't initialize after %d tries, icsr = %b\n", X unit, VVIDENTRETRY, 0xffff & addr->vvicsr, VV_IBITS); X return(0); X Xgotit: /* SUCCESS ?? */ X X v = (struct vv_header *)(vs->vs_ibuf->b_un).b_addr; X X /* proper message type */ X X if (v->vh_type == RING_WHOAMI) X shost = v->vh_shost; X else X goto retry; X X return(shost); X} X X/**************************************************************************/ X/* Start or restart output on interface. */ X/* */ X/* If interface active, then a retransmit, just restuff registers and go. */ X/* */ X/* If interface not already active, get another datagram off the interface*/ X/* queue, copy to buffer and send it. */ X/**************************************************************************/ X Xvvstart(dev) Xdev_t dev; X{ X register struct mb_device *md; X register struct vv_softc *vs; X register struct vvreg *addr; X register struct mbuf *m; X int unit, s; X u_long mbaddr; X X unit = VVUNIT(dev); X md = vvinfo[unit]; X vs = &vv_softc[unit]; X X /* active? */ X if (vs->vs_oactive) X goto restart; X X /* not active, try dequeueing a new message */ X X s = splimp(); X IF_DEQUEUE(&vs->vs_if.if_snd, m); X splx(s); X X /* any message? */ X if (m == NULL) X { X vs->vs_oactive = 0; X return; X } X X /* prepare to send */ X X vs->vs_olen = fillbuf(vs->vs_obuf, m); X m_freem(m); X X /* implement packet checking */ X#if defined(QUICKTEST) X { X struct vv_header *vv = (struct vv_header *)vs->vs_obuf->b_un.b_addr; X X vv->vh_info = (vs->vs_olen+1)>>1; /* just length */ X X# ifndef HARDSWAB X vv->vh_info = ((vv->vh_info>>8) & 0xff) | ((vv->vh_info<<8) & 0xff00); X# endif HARDSWAB X } X#endif defined(QUICKTEST) X Xrestart : X X /* Make sure this packet will fit in the interface. */ X X if (vs->vs_olen > VVBUFSIZE) X { X printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen); X panic("vvdriver vs_olen botch"); X } X X vs->vs_if.if_timer = VVTIMEOUT; X vs->vs_oactive = 1; X X /* ship it */ X addr = (struct vvreg *)md->md_addr; X mbaddr = MBI_ADDR(vs->vs_omap); X X addr->vvola = swabs(mbaddr & 0xffff); X addr->vvoha = swabs((mbaddr >> 16) & 0x0ff); X addr->vvowc = swabs(((vs->vs_olen + 1) >> 1)); X addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; X} X X/**************************************************************************/ X/* */ X/* called on interrupt -- figures out who did it and calls */ X/* appropriate interrupt routine. */ X/* */ X/**************************************************************************/ X Xvvintr() X{ X register struct mb_device *md; X register struct vvreg *addr; X register int found = 0; X X /* assumes one ring board -- if more will have to loop to poll regs */ X md = vvinfo[0]; X addr = (struct vvreg *)md->md_addr; X X /* is this output?? */ X if ((addr->vvocsr & VV_RDY) && (addr->vvocsr & VV_RST)) X { X vvxint(md->md_unit); X found = 1; X } X X /* try input */ X if ((addr->vvicsr & VV_RDY) && (addr->vvicsr & VV_RST)) X { X vvrint(md->md_unit); X found = 1; X } X X return(found); X} X X/**************************************************************************/ X/* */ X/* transmit interrupt -- start new output if more data available */ X/* */ X/**************************************************************************/ X Xvvxint(unit) Xint unit; X{ X register struct mb_device *md; X register struct vv_softc *vs; X register struct vvreg *addr; X register int oc; X X md = vvinfo[unit]; X vs = &vv_softc[unit]; X vs->vs_if.if_timer = 0; X addr = (struct vvreg *)md->md_addr; X X oc = 0xffff & (addr->vvocsr); X addr->vvocsr = VV_RST; X X if (vs->vs_oactive == 0) X { X printf("vv%d: stray interrupt vvocsr = %b\n", unit, X oc, VV_OBITS); X return; X } X X if (oc & (VV_OPT | VV_RFS)) X { X vs->vs_if.if_collisions++; X if (vs->vs_tries++ < VVRETRY) X { X if (oc & VV_OPT) X vs->vs_init++; X if (oc & VV_RFS) X vs->vs_nottaken++; X vvstart(unit); /* restart this message */ X return; X } X if (oc & VV_OPT) X printf("vv%d: output timeout\n", unit); X } X X vs->vs_if.if_opackets++; X vs->vs_oactive = 0; X vs->vs_tries = 0; X X if (oc & VVXERR) X { X vs->vs_if.if_oerrors++; X printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, X VV_OBITS); X } X X vvstart(unit); X} X X/**************************************************************************/ X/* */ X/* Transmit watchdog timer routine. This routine gets called when we lose */ X/* a transmit interrupt. The best we can do is try to restart output. */ X/* */ X/**************************************************************************/ X Xvvwatchdog(unit) Xint unit; X{ X register struct vv_softc *vs; X register int s; X X vs = &vv_softc[unit]; X if (vs->vs_if.if_flags & IFF_DEBUG) X printf("vv%d: lost a transmit interrupt.\n", unit); X vs->vs_timeouts++; X X s = splimp(); X vvstart(unit); X splx(s); X} X X/**************************************************************************/ X/* receive interrupt. If error drop packet, else peek at packet header */ X/* to determine type. If we want it then strip local header and pass */ X/* on to higher protocol. */ X/**************************************************************************/ X Xvvrint(unit) Xint unit; X{ X register struct vv_softc *vs; X register struct vvreg *addr; X#ifdef HARDSWAB X register struct vv_header *vv; X#else X register struct vv_rheader *vv; X#endif X register struct ifqueue *inq; X register struct mbuf *m; X register int len, s, off, type; X u_long mbaddr; X short resid; X X vs = &vv_softc[unit]; X vs->vs_if.if_ipackets++; X addr = (struct vvreg *)vvinfo[unit]->md_addr; X X if (addr->vvicsr & VVRERR) X { X if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) X printf("vv%d: error vvicsr = %b\n", unit, X 0xffff&(addr->vvicsr), VV_IBITS); X goto dropit; X } X X /* get length */ X X#ifdef HARDSWAB X vv = (struct vv_header *)(vs->vs_ibuf->b_un.b_addr); X#else X vv = (struct vv_rheader *)(vs->vs_ibuf->b_un.b_addr); X#endif X X /* real nuisance -- only low order 10 bits of iwc are valid */ X resid = swabs(addr->vviwc) & 0x3ff; X X len = VVBUFSIZE - (resid << 1); X len -= sizeof(struct vv_header); X X if (len > VVBUFSIZE || len <= 0) X { X if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) X printf("vv%d: len too big, len = %d, vvicsr = %b\n", X unit, len, 0xffff&(addr->vvicsr), VV_IBITS); X goto dropit; X } X X /* untested trailer handling -- taken straight from VAX code */ X X off = 0; X X#define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) X if (vv->vh_type >= RING_IPTrailer && X vv->vh_type < RING_IPTrailer+RING_IPNTrailer) X { X off = (vv->vh_type - RING_IPTrailer) * 512; X if (off > (VVBUFSIZE-12)) X { X if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) X printf("vv%d: VVMTU, off = %d, vvicsr = %b\n", X unit, off, 0xffff&(addr->vvicsr), VV_IBITS); X goto dropit; X } X vv->vh_type = *vvdataaddr(vv, off, u_short *); X resid = *(vvdataaddr(vv, off+2, u_short *)); X if (off + resid > len) X { X if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) X printf( X "vv%d: off = %d, resid = %d, vvicsr = %b\n", X unit, off, resid, X 0xffff&(addr->vvicsr), VV_IBITS); X goto dropit; X } X len = off + resid; X } X#ifdef QUICKTEST X /* can only test non-trailer packets */ X else if ((vv->vh_info != 0) && X (vv->vh_info != ((len+sizeof(struct vv_header)) >> 1))) X { X if (vv_logreaderrors) X printf("vv%d: incomplete packet\n",unit); X goto dropit; X } X X#endif QUICKTEST X X if (len == 0) X { X if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) X printf("vv%d: len is zero, vvicsr = %b\n", unit, X 0xffff&(addr->vvicsr), VV_IBITS); X goto dropit; X } X X X /* Keep track of source address of this packet */ X type = vv->vh_type; X X /* copy buffer into mbuf chain, without net header */ X /* could wait until type is o.k., but almost certainly is so why wait */ X X m = emptybuf(vs->vs_ibuf,len,off,sizeof(struct vv_header)); X X if (m == 0) X goto dropit; X X#ifdef SLOWTEST X if (vv->vh_info) X { X u_short sav_cksum, cksum; X short isodd; X X sav_cksum = vv->vh_info; X X isodd = (sav_cksum & 1); X sav_cksum &= 0xfffe; X X if (isodd) X cksum = in_cksum(m,len-1); X else X cksum = in_cksum(m,len); X X cksum &= 0xfffe; X X if (sav_cksum != cksum) X { X if (vv_logreaderrors) X printf("vv%d: garbled packet data\n",unit); X m_freem(m); X goto dropit; X } X } X#endif SLOWTEST X X /* handle according to type */ X X switch (type) X { X X#ifdef INET X case RING_IP: X inq = &ipintrq; X X s = splimp(); X if (IF_QFULL(inq)) X { X IF_DROP(inq); X m_freem(m); X } X else X IF_ENQUEUE(inq, m); X splx(s); X X schednetisr(NETISR_IP); X X break; X#endif X default: X printf("vv%d: unknown pkt type 0x%x\n", unit, type); X m_freem(m); X goto setup; X } X Xsetup : X /* Reset for the next packet. */ X X mbaddr = MBI_ADDR(vs->vs_imap); X X addr->vvila = swabs(mbaddr & 0xffff); X addr->vviha = swabs((mbaddr >> 16) & 0x0ff); X addr->vviwc = swabs(VVBUFSIZE >> 1); X addr->vvicsr = VV_RST | VV_CONF | VV_IEN | VV_DEN | VV_ENB; X X return; X Xdropit : X /* count dropped packets */ X X vs->vs_if.if_ierrors++; X goto setup; X} X X/**************************************************************************/ X/* v2nli output routine */ X/**************************************************************************/ X Xvvoutput(ifp, m0, dst) Xstruct ifnet *ifp; Xstruct mbuf *m0; Xstruct sockaddr *dst; X{ X register struct mbuf *m; X register struct vv_header *vv; X register int unit, s; X register struct vvreg *addr; X register struct vv_softc *vs; X int type, dest, error; X u_short info = 0; X X m = m0; X unit = ifp->if_unit; X addr = (struct vvreg *)vvinfo[unit]->md_addr; X vs = &vv_softc[unit]; X X /* X * Check to see if the input side has wedged. X * X * We are lower than device ipl when we enter this routine, X * so if the interface is ready with an input packet then X * an input interrupt must have slipped through the cracks. X * X * Avoid the race with an input interrupt by watching to see X * if any packets come in. X */ X X s = vs->vs_if.if_ipackets; X X if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) X { X if (vs->vs_if.if_flags & IFF_DEBUG) X printf("vv%d: lost a receive interrupt, icsr = %b\n", X unit, 0xffff&(addr->vvicsr), VV_IBITS); X s = splimp(); X vvrint(unit); X splx(s); X } X X switch (dst->sa_family) X { X X#ifdef INET X case AF_INET: X dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; X if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) X { X error = EPERM; X goto bad; X } X type = RING_IP; /* NO TRAILERS OUTBOUND */ X break; X X#endif X default: X printf("vv%d: can't handle af%d\n", unit, dst->sa_family); X error = EAFNOSUPPORT; X goto bad; X } X X /* if checksuming, do it now */ X#ifdef SLOWTEST X { X int len; X struct mbuf *m1; X X for (len=0, m1 = m; m1 != (struct mbuf *)0; m1 = m1->m_next) X len += m1->m_len; X X info = in_cksum(m,len) & 0xfffe; X X if (len & 1) X info |= 1; X X } X#endif SLOWTEST X X /* add local net header. If no space in first mbuf, allocate another. */ X X if (m->m_off > MMAXOFF || X MMINOFF + sizeof (struct vv_header) > m->m_off) X { X m = m_get(M_DONTWAIT, MT_HEADER); X if (m == (struct mbuf *)0) X { X error = ENOBUFS; X goto bad; X } X m->m_next = m0; X m->m_off = MMINOFF; X m->m_len = sizeof (struct vv_header); X } X else X { X m->m_off -= sizeof (struct vv_header); X m->m_len += sizeof (struct vv_header); X } X X vv = mtod(m, struct vv_header *); X vv->vh_shost = ifp->if_host[0]; X X /* Map the destination address if it's a broadcast */ X if ((vv->vh_dhost = dest) == INADDR_ANY) X vv->vh_dhost = VV_BROADCAST; X vv->vh_version = RING_VERSION; X vv->vh_type = type; X vv->vh_info = info; /* this gets changed if testing packets */ X X /* queue packet, and if interface not active, send */ X X s = splimp(); X if (IF_QFULL(&ifp->if_snd)) X { X IF_DROP(&ifp->if_snd); X error = ENOBUFS; X goto qfull; X } X IF_ENQUEUE(&ifp->if_snd, m); X if (vs->vs_oactive == 0) X vvstart(unit); X splx(s); X X return (0); X Xqfull : X m0 = m; X splx(s); X Xbad : X m_freem(m0); X return(error); X} X X/**************************************************************************/ X/* */ X/* process an ioctl request. the value of parameters different on SUN */ X/* from VAX. data now appears to be dependent on the cmd */ X/* */ X/**************************************************************************/ X Xvvioctl(ifp, cmd, data) Xregister struct ifnet *ifp; Xint cmd; Xcaddr_t data; X{ X register struct sockaddr *sin; X register int s; X int error; X X error = 0; X s = splimp(); X X switch (cmd) X { X X case SIOCSIFADDR: X X sin = (struct sockaddr *)data; X if (sin->sa_family != AF_INET) X { X error = EINVAL; X break; X } X X if (ifp->if_flags & IFF_RUNNING) X if_rtinit(ifp, -1); /* delete previous route */ X vvsetaddr(ifp, (struct sockaddr_in *)sin); X if (ifp->if_flags & IFF_RUNNING) X if_rtinit(ifp, RTF_UP); X else X vvinit(ifp->if_unit); X break; X X default: X error = EINVAL; X } X X splx(s); X return(error); X} X X/**************************************************************************/ X/* */ X/* set up the address for this interface. uses the network number */ X/* from the passed address and an invalid host number; vvidentify() */ X/* figures out and inserts real host addr later. */ X/* */ X/**************************************************************************/ X Xvvsetaddr(ifp, sin) Xregister struct ifnet *ifp; Xregister struct sockaddr_in *sin; X{ X X ifp->if_net = in_netof(sin->sin_addr); X ifp->if_host[0] = 0; /* an invalid host number */ X sin = (struct sockaddr_in *)&ifp->if_addr; X sin->sin_family = AF_INET; X sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); X X sin = (struct sockaddr_in *)&ifp->if_broadaddr; X sin->sin_family = AF_INET; X sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); X ifp->if_flags |= IFF_BROADCAST; X} X X/**************************************************************************/ X/* */ X/* vvprt_hdr(s, v) print the local net header in "v" with title "s" */ X/* */ X/**************************************************************************/ X Xvvprt_hdr(s, v) Xchar *s; X#ifdef HARDSWAB Xregister struct vv_header *v; X#else Xregister struct vv_rheader *v; X#endif X{ X printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", X s, X 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), X 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), X 0xffff & (int)(v->vh_info)); X} X X#ifdef VVDEBUG X X/**************************************************************************/ X/* */ X/* print "l" hex bytes starting at "s" -- not used in driver but may be */ X/* useful for future debugging. */ X/* */ X/**************************************************************************/ X Xvvprt_hex(s, l) Xchar *s; Xint l; X{ X register int i; X register int z; X X for (i=0 ; i < l; i++) X { X z = 0xff & (int)(*(s + i)); X printf("%c%c ", X "0123456789abcdef"[(z >> 4) & 0x0f], X "0123456789abcdef"[z & 0x0f] X ); X } X} X#endif VVDEBUG _NO_MORE_TEXT_ echo 'sh - vv.4' sed 's/^X//' <<'_NO_MORE_TEXT_' > vv.4 X.TH VV 4 "15 November 1984" X.ds ]W Bolt Beranek and Newman X.SH NAME Xvv \- Proteon proNET 10 Megabit ring X.SH SYNOPSIS X.B "device vv0 at mb0 csr 400 priority 3" X.SH DESCRIPTION XThe X.I vv Xinterface provides access to a 10 Mb/s Proteon proNET ring network. X.PP XThe network number to which the interface is attached must Xbe specified with an SIOCSIFADDR ioctl before data can be Xtransmitted or received. XThe host's address is discovered by putting the interface in Xdigital loopback mode (not joining the ring) Xand sending a broadcast packet from which the source Xaddress is extracted. X.PP XIf the installation is running CTL boards which use the old broadcast Xaddress of 0 instead of the new address of 0xff, the define OLD_BROADCAST Xshould be specified in the driver. X.PP XIf the installation has a Wirecenter, the define WIRECENTER should Xbe specified in the driver. X.BR N.B. : XIncorrect definition of WIRECENTER can cause hardware damage. X.PP XOn the SUN processors either the driver or the boards must swap bytes Xin each packet before it is sent (this is because of a disagreement Xbetween the SUN processor and the Multibus about byte ordering). XIf the boards will do byte swapping then the definition HARDSWAB should Xappear in the driver, otherwise the driver will swap bytes before Xsending them to the boards. X.PP XAlso, because of requests from users with early revision boards, it Xis possible to have the driver do various simple checks on each Xpacket as it is received from the board. These checks are Xdone by stuffing a value into the third word of the ring header X(which is normally supposed to be 0). To make these checks work, Xall drivers must use them, since the receiving driver simply checks Xdata put in the third word by the sending driver. If QUICKTEST is Xdefined in the driver then the word will contain the number of words Xthat were sent. If SLOWTEST is defined then the word contains an XIP checksum which makes things very slow, but makes sure that no Xgarbage packets get passed on, a check which is useful when running X\fBnd\fP (see \fInd(4)\fP). Note that because the third word in the Xring header is also used to implement trailer packets, packets with Xtrailers cannot be checked. Also note that the definitions have Xno effect if the third word is 0 (such packets are assumed to come Xfrom machines that are not doing any checking) and that the definitions Xmust be consistent among all machines or they will reject each other's Xpackets. Sites are encouraged to use \fIneither\fP definition Xunless their hardware proves to have problems. X.PP XIn the SUN implementation, the driver will not generate packets Xusing the trailer protocol, but will accept them. X.SH DIAGNOSTICS X.PP X\fBvv%d: host %d\fP. The software announces the host Xaddress discovered during autoconfiguration. X.PP X\fBvv%d: can't initialize after %d tries, icsr=%b\fP. XThe software was unable to discover the address of this interface, Xso it is deemed dead and will not be enabled. X.PP X\fBvv%d: error vvocsr=%b\fP. The hardware indicated an error on Xthe previous transmission. X.PP X\fBvv%d: output timeout\fP. The token timer has fired and the Xtoken will be recreated. X.PP X\fBvv%d: error vvicsr=%b\fP. The hardware indicated an error Xin reading a packet off the ring. X.PP X\fBvv%d: can't handle af%d\fP. The interface was handed Xa message with addresses formatted in an unsuitable address Xfamily; the packet was dropped. X.PP X\fBvv%d: vs_olen: %d > VVMTU\fP. The ring output routine has been Xhanded a message with a preposterous length. This results in Xan immediate X.IR "panic: vs_olen" . X.PP X\fBvv%d: stray interrupt vvocsr = %b\fP. An output Xinterrupt has been received but the driver was not in the process Xof sending any packets. X.PP X\fBvv%d: lost a transmit interrupt\fP. Self explanatory. X.PP X\fBvv%d: len too big, len = %d\fP. A packet larger than the MTU Xhas been received. X.PP X\fBvv%d: VVMTU, off %d, vvicsr = %b\fP. The offset into a trailer Xpacket is too large. X.PP X\fBvv%d: len is zero\fP. A zero length packet arrived. X.PP X\fBvv%d: unknown pkt type 0x%x\fP or \fBvv%d: can't handle af%d\fP. XA packet using an unsupported protocol has been seen. X.PP X\fBvv%d: incomplete packet\fP. An error only if QUICKTEST Xis on. A packet has arrived with an incorrect size. X.PP X\fBvv%d: garbled packet data\fP. An error only if SLOWTEST Xis on. A packet has failed its checksum. X.PP X\fBvv%d: off = %d, resid = %d, vvicsr = %b\fP. A bad trailer Xpacket has been received. X.SH SEE ALSO Xintro(4N), inet(4F), nd(4P) X.SH NOTICE X.PP XThis software is in the public domain and is being provided free by XBBN Labs to all users of ARPANET and USENET. BBN disclaims all Xexpress warranties with regard to any use of this software, including Xall implied warranties of merchandability and fitness. In no Xevent shall BBN be liable for any direct, special, indirect or Xconsequential damages or any damages whatsoever resulting from Xloss of use, data or profits, or any other injury, whether in Xan action of contract, negligence or other tortious action, Xarising out of or in connection with the use or performance of Xthis software. _NO_MORE_TEXT_ echo 'sh - vv.ms' sed 's/^X//' <<'_NO_MORE_TEXT_' > vv.ms X.ds LF "\fB\s-1BBN\s0 Laboratories\fP X.ds RF "December 8, 1984 X.DS C X.ft B X.ps +2 XNotes for Installing the Ring Driver on a SUN2 X.ps -2 X.ft R X.sp X\fICraig Partridge\fP X.DE X.PP XThis note is intended to be a simple guide to installing the 4.2 Xdriver for the ProNet ring (as modified at \s-1BBN\s0 for the \s-1SUN\s0) Xon a \s-1SUN\s02. XThe driver has now been in beta-test for about 5 weeks (many thanks Xto the people who agreed to be victims) and runs successfully on Xboth Rev. A and Rev. C boards.* X.FS X*Just for the record, the beta-test version was 1.2. This version is X1.6, but contains only cosmetic changes. The one substantive change Xwas undone because I could not satisfactorily induce the bug I thought XI was fixing. X.FE XWe therefore assume it will run on XRev. B boards. Please note that this is only a driver for the \s-1SUN\s02, Xwe make no promises that it will work on any other 68000-based Xmachine. X.SH XThe Boards X.PP XThe driver assumes that the boards are in the following configuration. XYou should check your operation manual to figure out how to set up Xyour boards. Section references here are given to the manual as Xof June 1983. X.RS X.IP \(bu XThe \s-1HSB\s0 should be an I/O device. (3.3.3.1). X.IP \(bu XThe \s-1HSB\s0 should use word \s-1DMA\s0. (3.3.3.2). X.IP \(bu XThe address bus width is 20 bits. (3.3.3.3) X.IP \(bu XUse parallel \s-1DMA\s0. (3.3.3.7) X.IP \(bu XEnable \s-1CBRQ\s0. (3.3.3.8). Note that this option may cause problems Xwith certain other boards, most notably the Interphase disk controller. XWhen in doubt check the settings on the other boards in your card Xcage. We, however, do know that it works with \s-1SCSI\s0 boards, Xethernet boards and \s-1SUN\s0 memory boards. The driver will work Xwhether or not \s-1CBRQ\s0 is enabled -- our experience on \s-1SUN\s0s Xsimply suggest it should be. X.IP \(bu XThe \s-1CTL\s0 board should be set to recognize both its address and Xthe broadcast address of 0x\s-1FF\s0. (3.2.2). (If this is not Xyour ring's broadcast address, change the \s-1NEWBROADCAST\s0 definition Xin \fIif_vv.h\fP). X.RE X.LP XIn addition, there are several configurational issues you must Xdeal with yourself, according to how you have already configured Xyour SUN. These are: X.RS X.IP \(bu XI/O page address. (3.3.3.4). You should choose an address that Xdoesn't conflict with that of any devices listed in your X\fIconfig\fP file. Remember that the board registers take Xup 16 bytes starting at the specified address. X(We presently use 0x400-0x40e). X.IP \(bu XThe interrupt priority selection. (3.3.3.5) XWe recommend you use the same priority as the Ethernet card (priority 3) Xbut any priority of 3 or below seems to work. X.IP \(bu XByte swapping. (3.3.3.11). The driver is set up so that it can do Xbyte swapping if your board doesn't (see notes on the driver below). XThe penalty appears to be a roughly 10% Xloss in throughput. If you haven't already got your board set up Xfor hard swabbing, we suggest you start with software swabbing to Xmake sure the board works, and then go through the wirewrapping Xnecessary to get the board to do the swabbing. X.IP \(bu XThe node number on the \s-1CTL\s0 board should be set appropriately (3.2.2). X.RE X.SH XThe Driver Itself X.PP XYou don't have to do much to the driver other than install it. However, Xthere are a few \fI#defines\fP near the start of X\fIif_vv.c\fP that you should check before Xyou compile a kernel. They are: X.IP \s-1WIRECENTER\s0 XThis should be defined if the ring has a wirecenter and left undefined Xif you are testing on a loopback device. Setting this wrong can damage Xyour board. X.IP \s-1HARDSWAB\s0 XThis should be defined if your board is doing swabbing, otherwise Xthe driver will swap all the bytes before or after each \s-1DMA\s0. XThe performance penalty for software swabbing is small, and it Xis recommended that you first test your boards without doing swabbing Xin hardware. X.IP \s-1QUICKTEST\s0 XThis should only be defined if you feel you may have a bad board. XSUNs which have \s-1QUICKTEST\s0 defined will check each other's packets Xto make sure they are the size the sender thought they were. Also Xuseful for making sure that a random failure doesn't cause you to Xtrash a fileserver's disk. X.IP \s-1SLOWTEST\s0 XA slower, but more thorough test of the data is done using an IP checksum Xof the entire packet. Almost assuredly not worth it. X.SH XInstalling the Driver X.PP XThere are three files that make up the driver: \fIvv.h\fP, \fIif_vv.h\fP Xand \fIif_vv.c\fP. X.PP X\fIvv.h\fP simply contains a definition for the Xnumber of ring devices the kernel should support. Be forewarned that Xthe driver, as presently written, can only support \s-1ONE\s0 ring device. X(This can be easily changed if it causes problems). XYou should put \fIvv.h\fP in the directory \fI/sys/\s-1OBJ\s0\fP. X.PP X\fIif_vv.c\fP and \fIif_vv.h\fP contain the code and definitions for Xthe driver. They should both be put in the directory \fI/sys/sunif\fP. XMake sure that \s-1HARDSWAB\s0 and \s-1WIRECENTER\s0 are defined correctly Xin \fIif_vv.c\fP. X.PP XYou should also add the following line to the file \fI/sys/conf/files.sun\fP: X.ne 4 X.br X.nf X.na X.sp Xsunif/if_vv.c optional vv inet device-driver X.sp X.fi X.ad X.LP XYou can then build a configuration file for a kernel with the \fIvv\fP Xdriver. Details on how to do this are described at the end of the Xarticle on device drivers in the \fISUN Systems Internals Manual\fP X(p. 38). You should refer to the line there for a description of the Xentry. To give you an example of how you should do it for the ring, Xhere is our \fIvv\fP entry in the \fIconfig\fP file for our kernels: X.ne 4 X.br X.sp X.nf X.na Xdevice vv0 at mb0 csr 0x400 priority 3 X.fi X.ad X.sp X.LP XYou can now generate your kernel X.PP XWhen bringing up your machine with the new kernel there are a few things to Xwatch for. First, you should see the kernel find the device -- the Xmessage X.br X.sp Xvv0 at mbio ... (\fIregister address\fP) X.br X.sp Xshould be in the list of devices found. Second, when \fI/etc/ifconfig\fP Xis called on device \fIvv0\fP, the message X.br X.sp Xvv0: host # X.sp Xwhere # is your host number, should appear. This tells you the host's Xnumber on the ring. Immediately after the message appears, the X\s-1LED\s0 on the wirecenter should light to indicate the connection Xhas been made. Finally, if your machine is the first host on the Xring, expect to see several error messages on the console the Xfirst time you try to use the ring. The ring is simply synchronizing Xand the messages will go away (typically we see 5 or 6 messages indicating Xeither \s-1NOK\s0 or \s-1BDF\s0 or a bad packet). We have also occasionally Xseen such messages on other hosts when a new host joins the ring. X.SH XProblems X.PP XHere are a couple of notes about potential problems you may see. X.IP \(bu XThe driver only works for one board. This could Xbe fixed easily (the comments in the code even say how). XIt just wasn't a problem that concerned us. X.IP \(bu XThe driver does not do \s-1ARP\s0. My view is that a Class C Xnet doesn't need this, but there have been some comments around the Xnet from people who apparently believe it does. X.IP \(bu XTo do the data checking (defining \s-1QUICKTEST\s0 or \s-1SLOWTEST\s0) Xin the driver it was necessary to use the third word in the ring Xnet header. Strictly speaking, this word should always be 0, Xso this is non-standard (it was included because most checking already Xexisted in the 4.1c \s-1SUN\s0 driver) but in general shouldn't Xcause problems. However, other drivers have also been known to plug Xspecial values into this word; \fIthese special values may cause this Xdriver to reject packets if \fR\s-1SLOWTEST\s0 \fIor\fP \s-1QUICKTEST\s0\fI Xis defined\fR\|! X.IP \(bu XIf you try to use your \s-1SUN\s0 as a gateway between two nets Xbe aware that it Xwon't quite work between a class B net and the ring. (It almost Xworks, but the return addresses get scrambled). We haven't found Xanything in the driver that should cause this and some of \s-1SUN\s0's Xtechnical personnel said they were pretty sure this was \s-1SUN\s0's Xproblem. They tell me that \s-1SUN\s0 never tested their class B Xnetworking code. X.IP \(bu XMachines with Rev. A boards may see a comparatively high incidence of bad Xpackets and error messages. The Rev. A board apparently sometimes Xasserts that an input packet has been \s-1DMA\s0'ed when only some of the Xpacket has been \s-1DMA\s0'ed. The board may still complete the Xentire \s-1DMA\s0 (people aren't quite sure) Xbut it is now too late because driver has already Xtried to accept a partial packet. This whole sequence tends to Xcause two or three error messages. This may or may not have a simple Xsolution (people are still looking at the problem). If a solution is found, Xan update will be posted. X.IP \(bu XOne last note. If the driver seems to be almost working, you probably Xhave a hardware problem -- this observation Xis based on some beta-test site experience. XSo my advice is, when in doubt, check your hardware first (both XSUN and ProNET).... X.LP XHowever, if you are having problems that you think are driver related, Xhere's how to reach me: X.DS C X XCraig Partridge Xc/o BBN Labs X10 Moulton St XCambridge, MA 02238 X X\s-1ARPANET\s0: craig@bbn-loki X\s-1USENET\s0: {wjh12,ihnp4,decvax}!bbncca!craig X\s-1CSNET\s0: craig%loki.arpa@csnet-relay X.DE X.LP XI'll also happily accept bugfixes. However, do please read the following Xnotice. X.SH XNotice X.nr PS 8 X.nr VS 10 X.PP XThis software is in the public domain and is being provided free by XBBN Labs to all users of ARPANET and USENET. BBN disclaims all Xexpress warranties with regard to any use of this software, including Xall implied warranties of merchandability and fitness. In no Xevent shall BBN be liable for any direct, special, indirect or Xconsequential damages or any damages whatsoever resulting from Xloss of use, data or profits, or any other injury, whether in Xan action of contract, negligence or other tortious action, Xarising out of or in connection with the use or performance of Xthis software. X.nr PS 10 X.nr VS 12 _NO_MORE_TEXT_