add "#if N?? > 0"
[unix-history] / usr / src / sys / vax / if / if_vv.c
CommitLineData
da7c5cc6
KM
1/*
2 * Copyright (c) 1982 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
9a0b0c74 6 * @(#)if_vv.c 6.13 (Berkeley) %G%
da7c5cc6 7 */
547e5718 8
961945a8 9#include "vv.h"
9a0b0c74 10#if NVV > 0
4cdd59b5 11
547e5718 12/*
0f9c1d6e
MK
13 * Proteon proNET-10 and proNET-80 token ring driver.
14 * The name of this device driver derives from the old MIT
15 * name of V2LNI for the proNET hardware, would would abbreviate
16 * to "v2", but this won't work right. Thus the name is "vv".
4cdd59b5 17 *
0f9c1d6e
MK
18 * This driver is compatible with the proNET 10 meagbit and
19 * 80 megabit token ring interfaces (models p1000 and p1080).
20 *
21 * TRAILERS: You must turn off trailers via ifconfig if you want to share
22 * a ring with software using the following protocol types:
23 * 3: Address Resolution Protocol
24 * 4: HDLC (old Proteon drivers)
25 * 5: VAX Debugging Protocol (never used)
26 * This is because the protocol type values chosen for trailers
27 * conflict with these protocols. It's too late to change either now.
28 *
29 * HARDWARE COMPATABILITY: This driver requires that the HSBU (p1001)
30 * have a serial number >= 040, which is about March, 1982. Older
31 * HSBUs do not carry across 64kbyte boundaries. The old warning
32 * about use without Wire Centers applies only to CTL (p1002) cards with
33 * serial <= 057, which have not received ECO 176-743, which was
34 * implemented in March, 1982. Most such CTLs have received this ECO,
35 * but they are only compatible with the old HSBUs (<=039) anyways.
547e5718 36 */
38061563 37#include "../machine/pte.h"
961945a8 38
a6e960e7
JB
39#include "param.h"
40#include "systm.h"
41#include "mbuf.h"
42#include "buf.h"
43#include "protosw.h"
44#include "socket.h"
45#include "vmmac.h"
46#include "errno.h"
47#include "ioctl.h"
eaa60542
BJ
48
49#include "../net/if.h"
38061563 50#include "../net/netisr.h"
eaa60542 51#include "../net/route.h"
67eb6277
MK
52
53#ifdef BBNNET
54#define INET
55#endif
56#ifdef INET
d2cc167c
BJ
57#include "../netinet/in.h"
58#include "../netinet/in_systm.h"
1a568327 59#include "../netinet/in_var.h"
d2cc167c 60#include "../netinet/ip.h"
67eb6277 61#endif
eaa60542 62
38061563 63#include "../vax/cpu.h"
2888e947 64#include "../vax/mtpr.h"
a6e960e7
JB
65#include "if_vv.h"
66#include "if_uba.h"
2888e947
CL
67#include "../vaxuba/ubareg.h"
68#include "../vaxuba/ubavar.h"
38061563 69
547e5718 70/*
0f9c1d6e
MK
71 * 80 megabit configuration
72 * Uncomment the next line if you are using the 80 megabit system. The
73 * only change is the disposition of packets with parity/link_data_error
74 * indication.
547e5718 75 */
0f9c1d6e 76/* #define PRONET80 */
547e5718 77
0f9c1d6e
MK
78/*
79 * maximum transmission unit definition --
80 * you can set VVMTU at anything from 576 to 2024.
81 * 1536 is a popular "large" value, because it is a multiple
82 * of 512, which the trailer scheme likes.
83 * The absolute maximum size is 2024, which is enforced.
84 */
547e5718 85
67eb6277 86#define VVMTU (1536)
0f9c1d6e
MK
87
88#define VVMRU (VVMTU + 16)
89#define VVBUFSIZE (VVMRU + sizeof(struct vv_header))
90#if VVMTU>2024
91#undef VVMTU
92#undef VVMRU
93#undef VVBUFSIZE
94#define VVBUFSIZE (2046)
95#define VVMRU (VVBUFSIZE - sizeof (struct vv_header))
96#define VVMTU (VVMRU - 16)
97#endif
5f3ad58b 98
0f9c1d6e
MK
99/*
100 * debugging and tracing stuff
101 */
aa531fcf 102int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */
4cdd59b5 103
0f9c1d6e 104#define vvtracehdr if (vv_tracehdr) vvprt_hdr
1a568327 105#define vvprintf if (vs->vs_if.if_flags & IFF_DEBUG) printf
547e5718 106
0f9c1d6e
MK
107/*
108 * externals, types, etc.
109 */
aa531fcf
MK
110int vvprobe(), vvattach(), vvreset(), vvinit();
111int vvidentify(), vvstart(), vvxint(), vvwatchdog();
112int vvrint(), vvoutput(), vvioctl(), vvsetaddr();
547e5718
SL
113struct uba_device *vvinfo[NVV];
114u_short vvstd[] = { 0 };
115struct uba_driver vvdriver =
116 { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
117#define VVUNIT(x) minor(x)
547e5718 118
0f9c1d6e
MK
119#define LOOPBACK /* use loopback for packets meant for us */
120#ifdef LOOPBACK
121extern struct ifnet loif;
122#endif
123
547e5718
SL
124/*
125 * Software status of each interface.
126 *
127 * Each interface is referenced by a network interface structure,
128 * vs_if, which the routing code uses to locate the interface.
129 * This structure contains the output queue for the interface, its address, ...
130 * We also have, for each interface, a UBA interface structure, which
131 * contains information about the UNIBUS resources held by the interface:
132 * map registers, buffered data paths, etc. Information is cached in this
133 * structure for use by the if_uba.c routines in running the interface
134 * efficiently.
135 */
136struct vv_softc {
137 struct ifnet vs_if; /* network-visible interface */
138 struct ifuba vs_ifuba; /* UNIBUS resources */
1a568327 139 int vs_host;
4cdd59b5 140 short vs_oactive; /* is output active */
547e5718 141 short vs_olen; /* length of last output */
2888e947
CL
142 u_short vs_lastx; /* address of last packet sent */
143 u_short vs_lastr; /* address of last packet received */
4cdd59b5 144 short vs_tries; /* transmit current retry count */
547e5718 145 short vs_init; /* number of ring inits */
0f9c1d6e 146 short vs_refused; /* number of packets refused */
2888e947 147 short vs_timeouts; /* number of transmit timeouts */
0f9c1d6e
MK
148 short vs_otimeout; /* number of output timeouts */
149 short vs_ibadf; /* number of input bad formats */
150 short vs_parity; /* number of parity errors on 10 meg, */
151 /* link data errors on 80 meg */
547e5718
SL
152} vv_softc[NVV];
153
0f9c1d6e
MK
154/*
155 * probe the interface to see that the registers exist, and then
156 * cause an interrupt to find its vector
157 */
547e5718
SL
158vvprobe(reg)
159 caddr_t reg;
160{
161 register int br, cvec;
aa531fcf 162 register struct vvreg *addr;
547e5718
SL
163
164#ifdef lint
a23ec69a 165 br = 0; cvec = br; br = cvec;
547e5718 166#endif
aa531fcf 167 addr = (struct vvreg *)reg;
0f9c1d6e 168
547e5718
SL
169 /* reset interface, enable, and wait till dust settles */
170 addr->vvicsr = VV_RST;
171 addr->vvocsr = VV_RST;
a23ec69a 172 DELAY(100000);
0f9c1d6e 173
547e5718 174 /* generate interrupt by doing 1 word DMA from 0 in uba space!! */
547e5718
SL
175 addr->vvoba = 0; /* low 16 bits */
176 addr->vvoea = 0; /* extended bits */
177 addr->vvowc = -1; /* for 1 word */
0f9c1d6e 178 addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */
547e5718 179 DELAY(100000);
0f9c1d6e 180 addr->vvocsr = VV_RST; /* clear out the CSR */
547e5718 181 if (cvec && cvec != 0x200)
a23ec69a 182 cvec -= 4; /* backup so vector => receive */
547e5718
SL
183 return(1);
184}
185
186/*
187 * Interface exists: make available by filling in network interface
188 * record. System will initialize the interface when it is ready
189 * to accept packets.
190 */
191vvattach(ui)
192 struct uba_device *ui;
193{
a23ec69a 194 register struct vv_softc *vs;
547e5718 195
a23ec69a 196 vs = &vv_softc[ui->ui_unit];
547e5718
SL
197 vs->vs_if.if_unit = ui->ui_unit;
198 vs->vs_if.if_name = "vv";
199 vs->vs_if.if_mtu = VVMTU;
1a568327 200 vs->vs_if.if_flags = IFF_BROADCAST;
547e5718 201 vs->vs_if.if_init = vvinit;
1cd789fb 202 vs->vs_if.if_ioctl = vvioctl;
547e5718 203 vs->vs_if.if_output = vvoutput;
38061563 204 vs->vs_if.if_reset = vvreset;
2888e947
CL
205 vs->vs_if.if_timer = 0;
206 vs->vs_if.if_watchdog = vvwatchdog;
5f3ad58b 207 vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
41fb002a
MD
208#if defined(VAX750)
209 /* don't chew up 750 bdp's */
210 if (cpu == VAX_750 && ui->ui_unit > 0)
211 vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
212#endif
547e5718 213 if_attach(&vs->vs_if);
547e5718
SL
214}
215
216/*
217 * Reset of interface after UNIBUS reset.
218 * If interface is on specified uba, reset its state.
219 */
220vvreset(unit, uban)
221 int unit, uban;
222{
223 register struct uba_device *ui;
547e5718
SL
224
225 if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
226 ui->ui_ubanum != uban)
227 return;
228 printf(" vv%d", unit);
229 vvinit(unit);
230}
231
232/*
233 * Initialization of interface; clear recorded pending
234 * operations, and reinitialize UNIBUS usage.
235 */
236vvinit(unit)
237 int unit;
238{
a23ec69a
CL
239 register struct vv_softc *vs;
240 register struct uba_device *ui;
547e5718 241 register struct vvreg *addr;
aa531fcf 242 register int ubainfo, s;
547e5718 243
a23ec69a
CL
244 vs = &vv_softc[unit];
245 ui = vvinfo[unit];
0f9c1d6e 246
1a568327 247 if (vs->vs_if.if_addrlist == (struct ifaddr *)0)
1cd789fb 248 return;
0f9c1d6e 249
5f3ad58b 250 addr = (struct vvreg *)ui->ui_addr;
547e5718 251 if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
a23ec69a 252 sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
2888e947 253 printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
5f3ad58b 254 vs->vs_if.if_flags &= ~IFF_UP;
547e5718
SL
255 return;
256 }
0f9c1d6e 257
5f3ad58b 258 /*
a23ec69a
CL
259 * Now that the uba is set up, figure out our address and
260 * update complete our host address.
5f3ad58b 261 */
1a568327 262 if ((vs->vs_host = vvidentify(unit)) == -1) {
2888e947
CL
263 vs->vs_if.if_flags &= ~IFF_UP;
264 return;
265 }
1a568327 266 printf("vv%d: host %d\n", unit, vs->vs_host);
0f9c1d6e 267
5f3ad58b 268 /*
0f9c1d6e 269 * Reset the interface, and stay in the ring
5f3ad58b 270 */
0f9c1d6e
MK
271 addr->vvocsr = VV_RST; /* take over output */
272 addr->vvocsr = VV_CPB; /* clear packet buffer */
273 addr->vvicsr = VV_RST | VV_HEN; /* take over input, */
274 /* keep relay closed */
5b319f7c 275 DELAY(500000); /* let contacts settle */
0f9c1d6e
MK
276
277 vs->vs_init = 0; /* clear counters, etc. */
278 vs->vs_refused = 0;
2888e947 279 vs->vs_timeouts = 0;
0f9c1d6e
MK
280 vs->vs_otimeout = 0;
281 vs->vs_ibadf = 0;
282 vs->vs_parity = 0;
2888e947
CL
283 vs->vs_lastx = 256; /* an invalid address */
284 vs->vs_lastr = 256; /* an invalid address */
0f9c1d6e 285
5f3ad58b
SL
286 /*
287 * Hang a receive and start any
288 * pending writes by faking a transmit complete.
289 */
290 s = splimp();
291 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
1cd789fb
SL
292 addr->vviba = (u_short)ubainfo;
293 addr->vviea = (u_short)(ubainfo >> 16);
0f9c1d6e
MK
294 addr->vviwc = -(VVBUFSIZE) >> 1;
295 addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB;
5f3ad58b 296 vs->vs_oactive = 1;
1a568327 297 vs->vs_if.if_flags |= IFF_RUNNING;
5f3ad58b
SL
298 vvxint(unit);
299 splx(s);
5f3ad58b
SL
300}
301
302/*
0f9c1d6e
MK
303 * Do a moderately thorough self-test in all three modes. Mostly
304 * to keeps defective nodes off the ring, rather than to be especially
305 * thorough. The key issue is to detect any cable breaks before joining
306 * the ring. Return our node address on success, return -1 on failure.
307 *
5f3ad58b 308 */
0f9c1d6e
MK
309
310/* the three self-test modes */
311static u_short vv_modes[] = {
312 VV_STE|VV_LPB, /* digital loopback */
313 VV_STE, /* analog loopback */
314 VV_HEN /* network mode */
315};
316
38061563 317vvidentify(unit)
1cd789fb 318 int unit;
38061563 319{
a23ec69a
CL
320 register struct vv_softc *vs;
321 register struct uba_device *ui;
5f3ad58b 322 register struct vvreg *addr;
aa531fcf
MK
323 register struct mbuf *m;
324 register struct vv_header *v;
0f9c1d6e
MK
325 register int ubainfo;
326 register int i, successes, failures, waitcount;
327 u_short shost = -1;
5f3ad58b 328
a23ec69a
CL
329 vs = &vv_softc[unit];
330 ui = vvinfo[unit];
5f3ad58b 331 addr = (struct vvreg *)ui->ui_addr;
0f9c1d6e
MK
332
333 /*
334 * Build a multicast message to identify our address
335 * We need do this only once, since nobody else is about to use
336 * the intermediate transmit buffer (ifu_w.ifrw_addr) that
337 * if_ubainit() aquired for us.
338 */
38061563 339 m = m_get(M_DONTWAIT, MT_HEADER);
2888e947
CL
340 if (m == NULL) {
341 printf("vv%d: can't initialize, m_get() failed\n", unit);
1cd789fb 342 return (0);
2888e947 343 }
4cdd59b5 344 m->m_next = 0;
547e5718
SL
345 m->m_off = MMINOFF;
346 m->m_len = sizeof(struct vv_header);
547e5718 347 v = mtod(m, struct vv_header *);
4cdd59b5 348 v->vh_dhost = VV_BROADCAST; /* multicast destination address */
547e5718
SL
349 v->vh_shost = 0; /* will be overwritten with ours */
350 v->vh_version = RING_VERSION;
0f9c1d6e 351 v->vh_type = RING_DIAGNOSTICS;
547e5718 352 v->vh_info = 0;
0f9c1d6e
MK
353 /* map xmit message into uba, copying to intermediate buffer */
354 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
5f3ad58b 355
547e5718 356 /*
0f9c1d6e
MK
357 * For each of the modes (digital, analog, network), go through
358 * a self-test that requires me to send VVIDENTSUCC good packets
359 * in VVIDENTRETRY attempts. Use broadcast destination to find out
360 * who I am, then use this as my address to check my address match
361 * logic. Only data checked is the vh_type field.
547e5718 362 */
0f9c1d6e
MK
363
364 for (i = 0; i < 3; i++) {
365 successes = 0; /* clear successes for this mode */
366 failures = 0; /* and clear failures, too */
367
368 /* take over device, and leave ring */
369 addr->vvicsr = VV_RST;
370 addr->vvocsr = VV_RST;
371 addr->vvicsr = vv_modes[i]; /* test mode */
372
373 /*
374 * let the flag and token timers pop so that the init ring bit
375 * will be allowed to work, by waiting about 1 second
376 */
377 DELAY(1000000L);
378
379 /*
380 * retry loop
381 */
382 while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY))
383 {
384 /* start a receive */
385 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
386 addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */
387 addr->vviba = (u_short) ubainfo;
388 addr->vviea = (u_short) (ubainfo >> 16);
389 addr->vviwc = -(VVBUFSIZE) >> 1;
390 addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB;
391
392 /* purge stale data from BDP */
393 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
394 UBAPURGE(vs->vs_ifuba.ifu_uba,
395 vs->vs_ifuba.ifu_w.ifrw_bdp);
396
397 /* do a transmit */
398 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
399 addr->vvocsr = VV_RST; /* abort last try */
400 addr->vvoba = (u_short) ubainfo;
401 addr->vvoea = (u_short) (ubainfo >> 16);
402 addr->vvowc = -((vs->vs_olen + 1) >> 1);
403 addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
404
405 /* poll receive side for completion */
406 DELAY(10000); /* give it a chance */
407 for (waitcount = 0; waitcount < 10; waitcount++) {
408 if (addr->vvicsr & VV_RDY)
409 goto gotit;
410 DELAY(1000);
411 }
412 failures++; /* no luck */
38061563 413 continue;
0f9c1d6e
MK
414
415gotit: /* we got something--is it any good? */
416 if ((addr->vvicsr & (VVRERR|VV_LDE)) ||
1a568327 417 (addr->vvocsr & (VVXERR|VV_RFS))) {
0f9c1d6e
MK
418 failures++;
419 continue;
420 }
421
422 /* Purge BDP before looking at received packet */
423 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
424 UBAPURGE(vs->vs_ifuba.ifu_uba,
425 vs->vs_ifuba.ifu_r.ifrw_bdp);
67eb6277
MK
426 m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header),
427 0, 0);
0f9c1d6e
MK
428 if (m != NULL)
429 m_freem(m);
430
431 v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
432
433 /* check message type, catch our node address */
434 if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) {
435 if (shost == -1) {
436 shost = v->vh_shost & 0xff;
437 /* send to ourself now */
438 ((struct vv_header *)
439 (vs->vs_ifuba.ifu_r.ifrw_addr))
440 ->vh_dhost = shost;
441 }
442 successes++;
443 v->vh_type = 0; /* clear to check again */
444 }
445 }
446
447 if (failures >= VVIDENTRETRY)
448 {
449 printf("vv%d: failed self-test after %d tries \
450in %s mode\n",
451 unit, VVIDENTRETRY, i == 0 ? "digital loopback" :
452 (i == 1 ? "analog loopback" : "network"));
453 printf("vv%d: icsr = %b, ocsr = %b\n",
454 unit, 0xffff & addr->vvicsr, VV_IBITS,
455 0xffff & addr->vvocsr, VV_OBITS);
456 addr->vvicsr = VV_RST; /* kill the sick board */
457 addr->vvocsr = VV_RST;
458 shost = -1;
459 goto done;
4cdd59b5 460 }
4cdd59b5 461 }
0f9c1d6e
MK
462
463done:
464 /* deallocate mbuf used for send packet (won't be one, anyways) */
2888e947 465 if (vs->vs_ifuba.ifu_xtofree) {
547e5718 466 m_freem(vs->vs_ifuba.ifu_xtofree);
2888e947
CL
467 vs->vs_ifuba.ifu_xtofree = 0;
468 }
0f9c1d6e
MK
469
470 return(shost);
4cdd59b5
SL
471}
472
547e5718
SL
473/*
474 * Start or restart output on interface.
4cdd59b5
SL
475 * If interface is active, this is a retransmit, so just
476 * restuff registers and go.
547e5718
SL
477 * If interface is not already active, get another datagram
478 * to send off of the interface queue, and map it to the interface
479 * before starting the output.
480 */
481vvstart(dev)
482 dev_t dev;
483{
aa531fcf 484 register struct uba_device *ui;
a23ec69a 485 register struct vv_softc *vs;
547e5718 486 register struct vvreg *addr;
aa531fcf
MK
487 register struct mbuf *m;
488 register int unit, ubainfo, dest, s;
547e5718 489
aa531fcf 490 unit = VVUNIT(dev);
a23ec69a
CL
491 ui = vvinfo[unit];
492 vs = &vv_softc[unit];
547e5718
SL
493 if (vs->vs_oactive)
494 goto restart;
547e5718
SL
495 /*
496 * Not already active: dequeue another request
497 * and map it to the UNIBUS. If no more requests,
498 * just return.
499 */
2888e947 500 s = splimp();
547e5718 501 IF_DEQUEUE(&vs->vs_if.if_snd, m);
2888e947 502 splx(s);
38061563 503 if (m == NULL) {
547e5718
SL
504 vs->vs_oactive = 0;
505 return;
506 }
507 dest = mtod(m, struct vv_header *)->vh_dhost;
508 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
509 vs->vs_lastx = dest;
547e5718
SL
510restart:
511 /*
512 * Have request mapped to UNIBUS for transmission.
2888e947
CL
513 * Purge any stale data from this BDP, and start the output.
514 *
515 * Make sure this packet will fit in the interface.
a23ec69a 516 */
0f9c1d6e
MK
517 if (vs->vs_olen > VVBUFSIZE) {
518 printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen);
4cdd59b5
SL
519 panic("vvdriver vs_olen botch");
520 }
0f9c1d6e
MK
521
522 vs->vs_if.if_timer = VVTIMEOUT;
523 vs->vs_oactive = 1;
524
525 /* ship it */
547e5718
SL
526 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
527 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
528 addr = (struct vvreg *)ui->ui_addr;
529 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
530 addr->vvoba = (u_short) ubainfo;
531 addr->vvoea = (u_short) (ubainfo >> 16);
532 addr->vvowc = -((vs->vs_olen + 1) >> 1);
0f9c1d6e
MK
533 addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */
534 if (addr->vvocsr & VV_NOK)
535 vs->vs_init++; /* count ring inits */
547e5718 536 addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
2888e947 537 vs->vs_if.if_timer = VVTIMEOUT;
547e5718
SL
538 vs->vs_oactive = 1;
539}
540
541/*
0f9c1d6e 542 * proNET transmit interrupt
547e5718
SL
543 * Start another output if more data to send.
544 */
545vvxint(unit)
546 int unit;
547{
a23ec69a
CL
548 register struct uba_device *ui;
549 register struct vv_softc *vs;
547e5718
SL
550 register struct vvreg *addr;
551 register int oc;
547e5718 552
a23ec69a
CL
553 ui = vvinfo[unit];
554 vs = &vv_softc[unit];
2888e947 555 vs->vs_if.if_timer = 0;
547e5718
SL
556 addr = (struct vvreg *)ui->ui_addr;
557 oc = 0xffff & (addr->vvocsr);
558 if (vs->vs_oactive == 0) {
0f9c1d6e 559 vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit,
a23ec69a 560 oc, VV_OBITS);
547e5718
SL
561 return;
562 }
0f9c1d6e
MK
563
564 /*
565 * we retransmit on soft error
566 * TODO: sort retransmits to end of queue if possible!
567 */
568 if (oc & (VV_OPT | VV_RFS)) {
4cdd59b5 569 if (vs->vs_tries++ < VVRETRY) {
547e5718 570 if (oc & VV_OPT)
0f9c1d6e
MK
571 vs->vs_otimeout++;
572 if (oc & VV_RFS) {
573 vs->vs_if.if_collisions++;
574 vs->vs_refused++;
575 }
4cdd59b5 576 vvstart(unit); /* restart this message */
547e5718
SL
577 return;
578 }
547e5718
SL
579 }
580 vs->vs_if.if_opackets++;
581 vs->vs_oactive = 0;
582 vs->vs_tries = 0;
0f9c1d6e 583
547e5718
SL
584 if (oc & VVXERR) {
585 vs->vs_if.if_oerrors++;
0f9c1d6e 586 vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
a23ec69a 587 VV_OBITS);
547e5718
SL
588 }
589 if (vs->vs_ifuba.ifu_xtofree) {
590 m_freem(vs->vs_ifuba.ifu_xtofree);
591 vs->vs_ifuba.ifu_xtofree = 0;
592 }
547e5718
SL
593 vvstart(unit);
594}
595
2888e947
CL
596/*
597 * Transmit watchdog timer routine.
598 * This routine gets called when we lose a transmit interrupt.
599 * The best we can do is try to restart output.
600 */
601vvwatchdog(unit)
602 int unit;
603{
604 register struct vv_softc *vs;
605 register int s;
606
607 vs = &vv_softc[unit];
0f9c1d6e 608 vvprintf("vv%d: lost a transmit interrupt.\n", unit);
2888e947
CL
609 vs->vs_timeouts++;
610 s = splimp();
611 vvstart(unit);
612 splx(s);
613}
614
547e5718 615/*
0f9c1d6e 616 * proNET interface receiver interrupt.
547e5718 617 * If input error just drop packet.
a23ec69a 618 * Otherwise purge input buffered data path and examine
547e5718 619 * packet to determine type. If can't determine length
a23ec69a 620 * from type, then have to drop packet. Otherwise decapsulate
547e5718
SL
621 * packet based on type and pass to type specific higher-level
622 * input routine.
623 */
624vvrint(unit)
625 int unit;
626{
a23ec69a 627 register struct vv_softc *vs;
aa531fcf 628 register struct vvreg *addr;
547e5718
SL
629 register struct vv_header *vv;
630 register struct ifqueue *inq;
aa531fcf 631 register struct mbuf *m;
2888e947 632 int ubainfo, len, off, s;
5f3ad58b 633 short resid;
547e5718 634
a23ec69a 635 vs = &vv_softc[unit];
547e5718 636 vs->vs_if.if_ipackets++;
aa531fcf 637 addr = (struct vvreg *)vvinfo[unit]->ui_addr;
0f9c1d6e 638
547e5718
SL
639 /*
640 * Purge BDP; drop if input error indicated.
641 */
642 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
643 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
0f9c1d6e
MK
644
645 /*
646 * receive errors?
647 */
547e5718 648 if (addr->vvicsr & VVRERR) {
0f9c1d6e
MK
649 vvprintf("vv%d: receive error, vvicsr = %b\n", unit,
650 0xffff&(addr->vvicsr), VV_IBITS);
651 if (addr->vvicsr & VV_BDF)
652 vs->vs_ibadf++;
5f3ad58b 653 goto dropit;
547e5718 654 }
5f3ad58b 655
547e5718 656 /*
0f9c1d6e
MK
657 * parity errors?
658 */
659 if (addr->vvicsr & VV_LDE) {
660 /* we don't have to clear it because the receive command */
661 /* writes 0 to parity bit */
662 vs->vs_parity++;
663#ifndef PRONET80
664 /*
665 * only on 10 megabit proNET is VV_LDE an end-to-end parity
666 * bit. On 80 megabit, it returns to the intended use of
667 * node-to-node parity. End-to-end parity errors on 80 megabit
668 * give VV_BDF.
669 */
670 goto dropit;
671#endif
672 }
673
674 /*
675 * Get packet length from residual word count
5f3ad58b
SL
676 *
677 * Compute header offset if trailer protocol
678 *
679 * Pull packet off interface. Off is nonzero if packet
680 * has trailing header; if_rubaget will then force this header
681 * information to be at the front. The vh_info field
682 * carries the offset to the trailer data in trailer
683 * format packets.
547e5718 684 */
5f3ad58b 685 vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
4cdd59b5 686 vvtracehdr("vi", vv);
0f9c1d6e 687 resid = addr->vviwc & 01777; /* only low 10 bits valid */
5f3ad58b 688 if (resid)
0f9c1d6e
MK
689 resid |= 0176000; /* high 6 bits are undefined */
690 len = ((VVBUFSIZE >> 1) + resid) << 1;
5f3ad58b 691 len -= sizeof(struct vv_header);
0f9c1d6e
MK
692
693 if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) {
694 vvprintf("vv%d: len too long or short, \
695len = %d, vvicsr = %b\n",
2888e947 696 unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
5f3ad58b 697 goto dropit;
2888e947 698 }
0f9c1d6e
MK
699
700 /* check the protocol header version */
701 if (vv->vh_version != RING_VERSION) {
702 vvprintf("vv%d: bad protocol header version %d\n",
703 unit, vv->vh_version & 0xff);
704 goto dropit;
705 }
706
5f3ad58b 707#define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off))))
1cd789fb
SL
708 if (vv->vh_type >= RING_IPTrailer &&
709 vv->vh_type < RING_IPTrailer+RING_IPNTrailer) {
5f3ad58b 710 off = (vv->vh_type - RING_IPTrailer) * 512;
2888e947 711 if (off > VVMTU) {
0f9c1d6e 712 vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n",
2888e947 713 unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
5f3ad58b 714 goto dropit;
2888e947 715 }
5f3ad58b
SL
716 vv->vh_type = *vvdataaddr(vv, off, u_short *);
717 resid = *(vvdataaddr(vv, off+2, u_short *));
2888e947 718 if (off + resid > len) {
0f9c1d6e
MK
719 vvprintf("vv%d: trailer packet too short\n", unit);
720 vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n",
2888e947
CL
721 unit, off, resid,
722 0xffff&(addr->vvicsr), VV_IBITS);
5f3ad58b 723 goto dropit;
2888e947 724 }
5f3ad58b 725 len = off + resid;
38061563 726 } else
5f3ad58b 727 off = 0;
0f9c1d6e 728
2888e947 729 if (len == 0) {
0f9c1d6e 730 vvprintf("vv%d: len is zero, vvicsr = %b\n", unit,
2888e947 731 0xffff&(addr->vvicsr), VV_IBITS);
5f3ad58b 732 goto dropit;
2888e947 733 }
0f9c1d6e 734
67eb6277 735 m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if);
2888e947 736 if (m == NULL) {
0f9c1d6e 737 vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit,
2888e947 738 0xffff&(addr->vvicsr), VV_IBITS);
5f3ad58b 739 goto dropit;
2888e947 740 }
5f3ad58b 741 if (off) {
67eb6277
MK
742 struct ifnet *ifp;
743
744 ifp = *(mtod(m, struct ifnet **));
745 m->m_off += 2 * sizeof (u_short);
746 m->m_len -= 2 * sizeof (u_short);
747 *(mtod(m, struct ifnet **)) = ifp;
5f3ad58b 748 }
4cdd59b5 749
2888e947
CL
750 /* Keep track of source address of this packet */
751 vs->vs_lastr = vv->vh_shost;
0f9c1d6e 752
4cdd59b5 753 /*
a23ec69a 754 * Demultiplex on packet type
4cdd59b5 755 */
547e5718 756 switch (vv->vh_type) {
4cdd59b5 757
547e5718
SL
758#ifdef INET
759 case RING_IP:
547e5718
SL
760 schednetisr(NETISR_IP);
761 inq = &ipintrq;
762 break;
763#endif
764 default:
0f9c1d6e 765 vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
5f3ad58b 766 m_freem(m);
547e5718
SL
767 goto setup;
768 }
2888e947 769 s = splimp();
5f3ad58b
SL
770 if (IF_QFULL(inq)) {
771 IF_DROP(inq);
772 m_freem(m);
38061563 773 } else
5f3ad58b 774 IF_ENQUEUE(inq, m);
a23ec69a 775
2888e947 776 splx(s);
547e5718 777 /*
a23ec69a 778 * Reset for the next packet.
4cdd59b5 779 */
a23ec69a
CL
780setup:
781 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
782 addr->vviba = (u_short) ubainfo;
783 addr->vviea = (u_short) (ubainfo >> 16);
0f9c1d6e
MK
784 addr->vviwc = -(VVBUFSIZE) >> 1;
785 addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB;
a23ec69a 786 return;
4cdd59b5 787
4cdd59b5 788 /*
38061563 789 * Drop packet on floor -- count them!!
547e5718 790 */
5f3ad58b
SL
791dropit:
792 vs->vs_if.if_ierrors++;
5f3ad58b 793 goto setup;
547e5718
SL
794}
795
796/*
0f9c1d6e 797 * proNET output routine.
547e5718
SL
798 * Encapsulate a packet of type family for the local net.
799 * Use trailer local net encapsulation if enough data in first
800 * packet leaves a multiple of 512 bytes of data in remainder.
801 */
802vvoutput(ifp, m0, dst)
803 struct ifnet *ifp;
804 struct mbuf *m0;
805 struct sockaddr *dst;
806{
aa531fcf 807 register struct mbuf *m;
547e5718 808 register struct vv_header *vv;
5f3ad58b 809 register int off;
aa531fcf
MK
810 register int unit;
811 register struct vvreg *addr;
812 register struct vv_softc *vs;
813 register int s;
814 int type, dest, error;
815
816 m = m0;
817 unit = ifp->if_unit;
818 addr = (struct vvreg *)vvinfo[unit]->ui_addr;
819 vs = &vv_softc[unit];
0f9c1d6e 820
aa531fcf 821 /*
0f9c1d6e
MK
822 * Check to see if the input side has wedged due the UBA
823 * vectoring through 0.
aa531fcf
MK
824 *
825 * We are lower than device ipl when we enter this routine,
826 * so if the interface is ready with an input packet then
827 * an input interrupt must have slipped through the cracks.
828 *
829 * Avoid the race with an input interrupt by watching to see
830 * if any packets come in.
831 */
832 s = vs->vs_if.if_ipackets;
833 if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
0f9c1d6e 834 vvprintf("vv%d: lost a receive interrupt, icsr = %b\n",
aa531fcf
MK
835 unit, 0xffff&(addr->vvicsr), VV_IBITS);
836 s = splimp();
837 vvrint(unit);
838 splx(s);
839 }
547e5718
SL
840
841 switch (dst->sa_family) {
4cdd59b5 842
547e5718 843#ifdef INET
a23ec69a 844 case AF_INET:
1a568327
MK
845 if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr))
846 dest = VV_BROADCAST;
847 else
848 dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr);
0f9c1d6e 849#ifdef LOOPBACK
1a568327
MK
850 if (dest == vs->vs_host && (loif.if_flags & IFF_UP))
851 return (looutput(&loif, m0, dst));
0f9c1d6e 852#endif LOOPBACK
1a568327 853 if (dest >= 0x100) {
5f3ad58b
SL
854 error = EPERM;
855 goto bad;
856 }
5f3ad58b 857 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
0f9c1d6e
MK
858 /*
859 * Trailerize, if the configuration allows it.
860 * TODO: Need per host negotiation.
861 */
44eb2da3
SL
862 if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
863 if (off > 0 && (off & 0x1ff) == 0 &&
5f3ad58b
SL
864 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
865 type = RING_IPTrailer + (off>>9);
866 m->m_off -= 2 * sizeof (u_short);
867 m->m_len += 2 * sizeof (u_short);
868 *mtod(m, u_short *) = RING_IP;
869 *(mtod(m, u_short *) + 1) = m->m_len;
870 goto gottrailertype;
871 }
547e5718
SL
872 type = RING_IP;
873 off = 0;
874 goto gottype;
547e5718
SL
875#endif
876 default:
aa531fcf 877 printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
5f3ad58b
SL
878 error = EAFNOSUPPORT;
879 goto bad;
547e5718
SL
880 }
881
882gottrailertype:
883 /*
884 * Packet to be sent as trailer: move first packet
885 * (control information) to end of chain.
886 */
887 while (m->m_next)
888 m = m->m_next;
889 m->m_next = m0;
890 m = m0->m_next;
891 m0->m_next = 0;
892 m0 = m;
547e5718
SL
893gottype:
894 /*
895 * Add local net header. If no space in first mbuf,
896 * allocate another.
897 */
898 if (m->m_off > MMAXOFF ||
899 MMINOFF + sizeof (struct vv_header) > m->m_off) {
38061563
SL
900 m = m_get(M_DONTWAIT, MT_HEADER);
901 if (m == NULL) {
5f3ad58b
SL
902 error = ENOBUFS;
903 goto bad;
547e5718
SL
904 }
905 m->m_next = m0;
906 m->m_off = MMINOFF;
907 m->m_len = sizeof (struct vv_header);
908 } else {
909 m->m_off -= sizeof (struct vv_header);
910 m->m_len += sizeof (struct vv_header);
911 }
912 vv = mtod(m, struct vv_header *);
1a568327
MK
913 vv->vh_shost = vs->vs_host;
914 vv->vh_dhost = dest;
547e5718
SL
915 vv->vh_version = RING_VERSION;
916 vv->vh_type = type;
5f3ad58b 917 vv->vh_info = off;
4cdd59b5 918 vvtracehdr("vo", vv);
547e5718
SL
919
920 /*
921 * Queue message on interface, and start output if interface
922 * not yet active.
923 */
924 s = splimp();
5f3ad58b
SL
925 if (IF_QFULL(&ifp->if_snd)) {
926 IF_DROP(&ifp->if_snd);
927 error = ENOBUFS;
928 goto qfull;
929 }
547e5718 930 IF_ENQUEUE(&ifp->if_snd, m);
aa531fcf
MK
931 if (vs->vs_oactive == 0)
932 vvstart(unit);
547e5718 933 splx(s);
5f3ad58b 934 return (0);
5f3ad58b
SL
935qfull:
936 m0 = m;
937 splx(s);
938bad:
939 m_freem(m0);
940 return(error);
547e5718
SL
941}
942
1cd789fb
SL
943/*
944 * Process an ioctl request.
945 */
946vvioctl(ifp, cmd, data)
947 register struct ifnet *ifp;
948 int cmd;
949 caddr_t data;
950{
1a568327
MK
951 struct ifaddr *ifa = (struct ifaddr *) data;
952 int s = splimp(), error = 0;
1cd789fb
SL
953
954 switch (cmd) {
955
956 case SIOCSIFADDR:
67eb6277 957 ifp->if_flags |= IFF_UP;
1a568327 958 if ((ifp->if_flags & IFF_RUNNING) == 0)
1cd789fb 959 vvinit(ifp->if_unit);
1a568327
MK
960 /*
961 * Attempt to check agreement of protocol address
962 * and board address.
963 */
964 switch (ifa->ifa_addr.sa_family) {
965 case AF_INET:
966 if (in_lnaof(IA_SIN(ifa)->sin_addr) !=
967 vv_softc[ifp->if_unit].vs_host)
e37ca38f 968 error = EADDRNOTAVAIL;
1a568327
MK
969 break;
970 }
1cd789fb
SL
971 break;
972
973 default:
974 error = EINVAL;
975 }
976 splx(s);
1a568327 977 return (error);
547e5718 978}
5417a52b
MK
979
980/*
981 * vvprt_hdr(s, v) print the local net header in "v"
982 * with title is "s"
983 */
984vvprt_hdr(s, v)
985 char *s;
986 register struct vv_header *v;
987{
988 printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
989 s,
990 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
991 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
992 0xffff & (int)(v->vh_info));
993}
9a0b0c74 994#endif