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