📄 if_vv.c
字号:
#ifndef lintstatic char *sccsid = "@(#)if_vv.c 4.1 (ULTRIX) 7/2/90";#endif lint/************************************************************************ * * * Copyright (c) 1985 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * Modification History * * * 15-Jan-88 lp * Merge of final 43BSD changes. * * 13-Jun-86 -- jaw fix to uba reset and drivers. * * * 18-mar-86 -- jaw br/cvec changed to NOT use registers. * * Larry Cohen - 09/16/85 * * Add 43bsd alpha tape changes for subnet routing * * * ************************************************************************//* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * if_vv.c 7.1 (Berkeley) 6/5/86 */#include "vv.h"#if NVV > 0 || defined(BINARY)#include "../data/if_vv_data.c"/* * Proteon proNET-10 and proNET-80 token ring driver. * The name of this device driver derives from the old MIT * name of V2LNI for the proNET hardware, would would abbreviate * to "v2", but this won't work right. Thus the name is "vv". * * This driver is compatible with the proNET 10 meagbit and * 80 megabit token ring interfaces (models p1000 and p1080). * A unit may be marked as 80 megabit using "flags 1" in the * config file. * * TRAILERS: This driver has a new implementation of trailers that * is at least a tolerable neighbor on the ring. The offset is not * stored in the protocol type, but instead only in the vh_info * field. Also, the vh_info field, and the two shorts before the * trailing header, are in network byte order, not VAX byte order. * * Of course, nothing but BSD UNIX supports trailers on ProNET. * If you need interoperability with anything else, turn off * trailers using the -trailers option to /etc/ifconfig! * * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001) * have a serial number >= 040, which is about March, 1982. Older * HSBUs do not carry across 64kbyte boundaries. They can be supported * by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization * in vvattach(). * * The old warning about use without Wire Centers applies only to CTL * (p1002) cards with serial <= 057, which have not received ECO 176-743, * which was implemented in March, 1982. Most such CTLs have received * this ECO. *//* * maximum transmission unit definition -- * you can set VVMTU at anything from 576 to 2024. * 1536 is a popular "large" value, because it is a multiple * of 512, which the trailer scheme likes. * The absolute maximum size is 2024, which is enforced. */#define VVMTU (1536)#define VVMRU (VVMTU + 16)#define VVBUFSIZE (VVMRU + sizeof(struct vv_header))#if VVMTU>2024#undef VVMTU#undef VVMRU#undef VVBUFSIZE#define VVBUFSIZE (2046)#define VVMRU (VVBUFSIZE - sizeof (struct vv_header))#define VVMTU (VVMRU - 16)#endif/* * debugging and tracing stuff */int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */#define vvtracehdr if (vv_tracehdr) vvprt_hdr#define vvprintf if (vs->vs_if.if_flags & IFF_DEBUG) printf/* * externals, types, etc. */int vvprobe(), vvattach(), vvreset(), vvinit();int vvidentify(), vvstart(), vvxint(), vvwatchdog();int vvrint(), vvoutput(), vvioctl();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)#define LOOPBACK /* use loopback for packets meant for us */#ifdef LOOPBACKextern struct ifnet loif;#endif#define NOHOST 0xffff /* illegal host number *//* * probe the interface to see that the registers exist, and then * cause an interrupt to find its vector */vvprobe(reg) caddr_t reg;{ register struct vvreg *addr; addr = (struct vvreg *)reg; /* reset interface, enable, and wait till dust settles */ addr->vvicsr = VV_RST; addr->vvocsr = VV_RST; DELAY(100000); /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ addr->vvoba = 0; /* low 16 bits */ addr->vvoea = 0; /* extended bits */ addr->vvowc = -1; /* for 1 word */ addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */ DELAY(100000); addr->vvocsr = VV_RST; /* clear out the CSR */ if (cvec && cvec != 0x200) cvec -= 4; /* backup so vector => receive */ return(1);}/* * Interface exists: make available by filling in network interface * record. System will initialize the interface when it is ready * to accept packets. */vvattach(ui) struct uba_device *ui;{ register struct vv_softc *vs; vs = &vv_softc[ui->ui_unit]; vs->vs_if.if_unit = ui->ui_unit; vs->vs_if.if_name = "vv"; vs->vs_if.if_mtu = VVMTU; vs->vs_if.if_flags = IFF_BROADCAST; vs->vs_if.if_init = vvinit; 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; /* use flag to determine if this is proNET-80 */ vs->vs_is80 = (short)(ui->ui_flags & 01);#if defined(VAX750) /* don't chew up 750 bdp's */ if (cpu == VAX_750 && ui->ui_unit > 0) vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;#endif if_attach(&vs->vs_if);}/* * Reset of interface after UNIBUS reset. * If interface is on specified uba, reset its state. */vvreset(unit, uban) int unit, uban;{ register struct uba_device *ui; if (unit >= nNVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) return; printf(" vv%d", unit); vvinit(unit);}/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */vvinit(unit) int unit;{ register struct vv_softc *vs; register struct uba_device *ui; register struct vvreg *addr; register int ubainfo, s; vs = &vv_softc[unit]; ui = vvinfo[unit]; if (vs->vs_if.if_addrlist == (struct ifaddr *)0) return; 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, 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. */ if ((vs->vs_host = vvidentify(unit)) == NOHOST) { vs->vs_if.if_flags &= ~IFF_UP; return; } printf("vv%d: host %u\n", unit, vs->vs_host); /* * Reset the interface, and stay in the ring */ addr->vvocsr = VV_RST; /* take over output */ addr->vvocsr = VV_CPB; /* clear packet buffer */ addr->vvicsr = VV_RST | VV_HEN; /* take over input, */ /* keep relay closed */ DELAY(500000); /* let contacts settle */ vs->vs_init = 0; /* clear counters, etc. */ vs->vs_refused = 0; vs->vs_timeouts = 0; vs->vs_otimeout = 0; vs->vs_ibadf = 0; vs->vs_parity = 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. */ s = splimp(); ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; addr->vviba = (u_short)ubainfo; addr->vviea = (u_short)(ubainfo >> 16); addr->vviwc = -(VVBUFSIZE) >> 1; addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB; vs->vs_oactive = 1; vs->vs_if.if_flags |= IFF_RUNNING; vvxint(unit); splx(s);}/* * Do a moderately thorough self-test in all three modes. Mostly * to keeps defective nodes off the ring, rather than to be especially * thorough. The key issue is to detect any cable breaks before joining * the ring. Return our node address on success, return -1 on failure. * *//* the three self-test modes */static u_short vv_modes[] = { VV_STE|VV_LPB, /* digital loopback */ VV_STE, /* analog loopback */ VV_HEN /* network mode */};vvidentify(unit) int unit;{ register struct vv_softc *vs; register struct uba_device *ui; register struct vvreg *addr; register struct mbuf *m; register struct vv_header *v; register int ubainfo; register int i, successes, failures, waitcount; u_short shost = NOHOST; vs = &vv_softc[unit]; ui = vvinfo[unit]; addr = (struct vvreg *)ui->ui_addr; /* * Build a multicast message to identify our address * We need do this only once, since nobody else is about to use * the intermediate transmit buffer (ifu_w.ifrw_addr) that * if_ubainit() aquired for us. */ m = m_get(M_DONTWAIT, MT_DATA); 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); v = mtod(m, struct vv_header *); v->vh_dhost = VV_BROADCAST; /* multicast destination address */ v->vh_shost = 0; /* will be overwritten with ours */ v->vh_version = RING_VERSION; v->vh_type = RING_DIAGNOSTICS; v->vh_info = 0; /* map xmit message into uba, copying to intermediate buffer */ vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); /* * For each of the modes (digital, analog, network), go through * a self-test that requires me to send VVIDENTSUCC good packets * in VVIDENTRETRY attempts. Use broadcast destination to find out * who I am, then use this as my address to check my address match * logic. Only data checked is the vh_type field. */ for (i = 0; i < 3; i++) { successes = 0; /* clear successes for this mode */ failures = 0; /* and clear failures, too */ /* take over device, and leave ring */ addr->vvicsr = VV_RST; addr->vvocsr = VV_RST; addr->vvicsr = vv_modes[i]; /* test mode */ /* * let the flag and token timers pop so that the init ring bit * will be allowed to work, by waiting about 1 second */ DELAY(1000000L); /* * retry loop */ while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY)) { /* start a receive */ ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */ addr->vviba = (u_short) ubainfo; addr->vviea = (u_short) (ubainfo >> 16); addr->vviwc = -(VVBUFSIZE) >> 1; addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB; /* purge stale data from BDP */ if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp, vs->vs_ifuba.ifu_uban); /* do a transmit */ ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; addr->vvocsr = VV_RST; /* abort last try */ addr->vvoba = (u_short) ubainfo; addr->vvoea = (u_short) (ubainfo >> 16); addr->vvowc = -((vs->vs_olen + 1) >> 1); addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; /* poll receive side for completion */ DELAY(10000); /* give it a chance */ for (waitcount = 0; waitcount < 10; waitcount++) { if (addr->vvicsr & VV_RDY) goto gotit; DELAY(1000); } failures++; /* no luck */ continue;gotit: /* we got something--is it any good? */ if ((addr->vvicsr & (VVRERR|VV_LDE)) || (addr->vvocsr & (VVXERR|VV_RFS))) { failures++; continue; } /* Purge BDP before looking at received packet */ if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp, vs->vs_ifuba.ifu_uban); m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); if (m != NULL) m_freem(m); v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); /* check message type, catch our node address */ if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) { if (shost == NOHOST) { shost = v->vh_shost & 0xff; /* send to ourself now */ ((struct vv_header *) (vs->vs_ifuba.ifu_r.ifrw_addr)) ->vh_dhost = shost; } successes++; } else { failures++; } v->vh_type = 0; /* clear to check again */ } if (failures >= VVIDENTRETRY) { printf("vv%d: failed self-test after %d tries \in %s mode\n", unit, VVIDENTRETRY, i == 0 ? "digital loopback" : (i == 1 ? "analog loopback" : "network")); printf("vv%d: icsr = %b, ocsr = %b\n", unit, 0xffff & addr->vvicsr, VV_IBITS, 0xffff & addr->vvocsr, VV_OBITS); addr->vvicsr = VV_RST; /* kill the sick board */ addr->vvocsr = VV_RST; shost = NOHOST; goto done; } }done: /* deallocate mbuf used for send packet (won't be one, anyways) */ if (vs->vs_ifuba.ifu_xtofree) { m_freem(vs->vs_ifuba.ifu_xtofree); vs->vs_ifuba.ifu_xtofree = 0; } return(shost);}/* * Start or restart output on interface. * If interface is active, this is a retransmit, so just * restuff registers and go. * If interface is not already active, get another datagram * to send off of the interface queue, and map it to the interface * before starting the output. */vvstart(dev) dev_t dev;{ register struct uba_device *ui; register struct vv_softc *vs; register struct vvreg *addr; register struct mbuf *m; register int unit, ubainfo, dest, s; unit = VVUNIT(dev); ui = vvinfo[unit]; vs = &vv_softc[unit]; if (vs->vs_oactive) goto restart; /* * Not already active: dequeue another request * and map it to the UNIBUS. If no more requests, * just return. */ s = splimp(); IF_DEQUEUE(&vs->vs_if.if_snd, m); splx(s);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -