ioctls
[unix-history] / usr / src / sys / vax / if / if_vv.c
CommitLineData
1cd789fb 1/* if_vv.c 4.21 83/06/12 */
547e5718 2
961945a8 3#include "vv.h"
4cdd59b5 4
547e5718
SL
5/*
6 * Proteon 10 Meg Ring Driver.
7 * This device is called "vv" because its "real name",
8 * V2LNI won't work if shortened to the obvious "v2".
9 * Hence the subterfuge.
4cdd59b5 10 *
547e5718 11 */
38061563 12#include "../machine/pte.h"
961945a8 13
547e5718
SL
14#include "../h/param.h"
15#include "../h/systm.h"
16#include "../h/mbuf.h"
547e5718
SL
17#include "../h/buf.h"
18#include "../h/protosw.h"
19#include "../h/socket.h"
547e5718 20#include "../h/vmmac.h"
4cdd59b5 21#include "../h/errno.h"
38061563
SL
22#include "../h/time.h"
23#include "../h/kernel.h"
1cd789fb 24#include "../h/ioctl.h"
eaa60542
BJ
25
26#include "../net/if.h"
38061563 27#include "../net/netisr.h"
eaa60542 28#include "../net/route.h"
4cdd59b5 29
d2cc167c
BJ
30#include "../netinet/in.h"
31#include "../netinet/in_systm.h"
32#include "../netinet/ip.h"
33#include "../netinet/ip_var.h"
eaa60542 34
38061563
SL
35#include "../vax/mtpr.h"
36#include "../vax/cpu.h"
4cdd59b5 37
eaa60542
BJ
38#include "../vaxuba/ubareg.h"
39#include "../vaxuba/ubavar.h"
547e5718 40
38061563
SL
41#include "../vaxif/if_vv.h"
42#include "../vaxif/if_uba.h"
43
547e5718
SL
44/*
45 * N.B. - if WIRECENTER is defined wrong, it can well break
46 * the hardware!!
47 */
547e5718
SL
48#define WIRECENTER
49
50#ifdef WIRECENTER
51#define VV_CONF VV_HEN /* drive wire center relay */
52#else
53#define VV_CONF VV_STE /* allow operation without wire center */
54#endif
55
56#define VVMTU (1024+512)
5f3ad58b
SL
57#define VVMRU (1024+512+16) /* space for trailer */
58
1cd789fb 59int vv_tracehdr = 0, /* 1 => trace headers (slowly!!) */
4cdd59b5
SL
60 vv_tracetimeout = 1; /* 1 => trace input error-rate limiting */
61 vv_logreaderrors = 0; /* 1 => log all read errors */
62
63#define vvtracehdr if (vv_tracehdr) vvprt_hdr
64#define vvtrprintf if (vv_tracetimeout) printf
65
66int vv_ticking = 0; /* error flywheel is running */
67
38061563
SL
68/*
69 * Interval in HZ - 50 msec.
70 * N.B. all times below are in units of flywheel ticks
71 */
72#define VV_FLYWHEEL 3
4cdd59b5
SL
73#define VV_ERRORTHRESHOLD 100 /* errors/flywheel-interval */
74#define VV_MODE1ATTEMPTS 10 /* number mode 1 retries */
75#define VV_MODE1DELAY 2 /* period interface is PAUSEd - 100ms */
76#define VV_MODE2DELAY 4 /* base interval host relay is off - 200ms */
77#define VV_MAXDELAY 6400 /* max interval host relay is off - 2 minutes */
547e5718
SL
78
79int vvprobe(), vvattach(), vvrint(), vvxint();
80struct uba_device *vvinfo[NVV];
81u_short vvstd[] = { 0 };
82struct uba_driver vvdriver =
83 { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
84#define VVUNIT(x) minor(x)
1cd789fb 85int vvinit(),vvioctl(),vvoutput(),vvreset();
547e5718
SL
86
87/*
88 * Software status of each interface.
89 *
90 * Each interface is referenced by a network interface structure,
91 * vs_if, which the routing code uses to locate the interface.
92 * This structure contains the output queue for the interface, its address, ...
93 * We also have, for each interface, a UBA interface structure, which
94 * contains information about the UNIBUS resources held by the interface:
95 * map registers, buffered data paths, etc. Information is cached in this
96 * structure for use by the if_uba.c routines in running the interface
97 * efficiently.
98 */
99struct vv_softc {
100 struct ifnet vs_if; /* network-visible interface */
101 struct ifuba vs_ifuba; /* UNIBUS resources */
4cdd59b5
SL
102 short vs_oactive; /* is output active */
103 short vs_iactive; /* is input active */
547e5718
SL
104 short vs_olen; /* length of last output */
105 u_short vs_lastx; /* last destination address */
4cdd59b5 106 short vs_tries; /* transmit current retry count */
547e5718 107 short vs_init; /* number of ring inits */
547e5718 108 short vs_nottaken; /* number of packets refused */
4cdd59b5
SL
109 /* input error rate limiting state */
110 short vs_major; /* recovery major state */
111 short vs_minor; /* recovery minor state */
112 short vs_retry; /* recovery retry count */
113 short vs_delayclock; /* recovery delay clock */
114 short vs_delayrange; /* increasing delay interval */
115 short vs_dropped; /* number of packes tossed in last dt */
547e5718
SL
116} vv_softc[NVV];
117
4cdd59b5 118/*
38061563 119 * States of vs_iactive.
4cdd59b5 120 */
4cdd59b5
SL
121#define ACTIVE 1 /* interface should post new receives */
122#define PAUSE 0 /* interface should NOT post new receives */
123#define OPEN -1 /* PAUSE and open host relay */
124
125/*
38061563 126 * Recovery major states.
4cdd59b5 127 */
4cdd59b5
SL
128#define MODE0 0 /* everything is wonderful */
129#define MODE1 1 /* hopefully whatever will go away */
38061563 130#define MODE2 2 /* drastic measures - open host relay for increasing intervals */
4cdd59b5 131
547e5718
SL
132vvprobe(reg)
133 caddr_t reg;
134{
135 register int br, cvec;
136 register struct vvreg *addr = (struct vvreg *)reg;
137
138#ifdef lint
66923854 139 br = 0; cvec = br; br = cvec; vvrint(0);
547e5718
SL
140#endif
141 /* reset interface, enable, and wait till dust settles */
142 addr->vvicsr = VV_RST;
143 addr->vvocsr = VV_RST;
5b319f7c 144 DELAY(10000);
547e5718
SL
145 /* generate interrupt by doing 1 word DMA from 0 in uba space!! */
146 addr->vvocsr = VV_IEN; /* enable interrupt */
147 addr->vvoba = 0; /* low 16 bits */
148 addr->vvoea = 0; /* extended bits */
149 addr->vvowc = -1; /* for 1 word */
150 addr->vvocsr |= VV_DEN; /* start the DMA */
151 DELAY(100000);
152 addr->vvocsr = 0;
153 if (cvec && cvec != 0x200)
154 cvec -= 4; /* backup so vector => recieve */
155 return(1);
156}
157
158/*
159 * Interface exists: make available by filling in network interface
160 * record. System will initialize the interface when it is ready
161 * to accept packets.
162 */
163vvattach(ui)
164 struct uba_device *ui;
165{
166 register struct vv_softc *vs = &vv_softc[ui->ui_unit];
547e5718
SL
167
168 vs->vs_if.if_unit = ui->ui_unit;
169 vs->vs_if.if_name = "vv";
170 vs->vs_if.if_mtu = VVMTU;
547e5718 171 vs->vs_if.if_init = vvinit;
1cd789fb 172 vs->vs_if.if_ioctl = vvioctl;
547e5718 173 vs->vs_if.if_output = vvoutput;
38061563 174 vs->vs_if.if_reset = vvreset;
5f3ad58b 175 vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
41fb002a
MD
176#if defined(VAX750)
177 /* don't chew up 750 bdp's */
178 if (cpu == VAX_750 && ui->ui_unit > 0)
179 vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
180#endif
547e5718 181 if_attach(&vs->vs_if);
547e5718
SL
182}
183
184/*
185 * Reset of interface after UNIBUS reset.
186 * If interface is on specified uba, reset its state.
187 */
188vvreset(unit, uban)
189 int unit, uban;
190{
191 register struct uba_device *ui;
547e5718
SL
192
193 if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
194 ui->ui_ubanum != uban)
195 return;
196 printf(" vv%d", unit);
197 vvinit(unit);
198}
199
200/*
201 * Initialization of interface; clear recorded pending
202 * operations, and reinitialize UNIBUS usage.
203 */
204vvinit(unit)
205 int unit;
206{
207 register struct vv_softc *vs = &vv_softc[unit];
208 register struct uba_device *ui = vvinfo[unit];
209 register struct vvreg *addr;
210 struct sockaddr_in *sin;
5f3ad58b 211 int ubainfo, s;
4cdd59b5 212 int vvtimeout();
547e5718 213
1cd789fb
SL
214 if (vs->vs_if.if_net == 0)
215 return;
5f3ad58b 216 addr = (struct vvreg *)ui->ui_addr;
547e5718
SL
217 if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
218 sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
219 printf("vv%d: can't initialize\n", unit);
5f3ad58b 220 vs->vs_if.if_flags &= ~IFF_UP;
547e5718
SL
221 return;
222 }
38061563
SL
223 if (vv_ticking++ == 0)
224 timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
5f3ad58b 225 /*
38061563 226 * Discover our host address and post it
5f3ad58b 227 */
5f3ad58b 228 vs->vs_if.if_host[0] = vvidentify(unit);
5f3ad58b
SL
229 printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
230 sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
231 sin->sin_family = AF_INET;
38061563 232 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
1cd789fb
SL
233 sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr;
234 sin->sin_family = AF_INET;
235 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST);
5f3ad58b
SL
236
237 /*
238 * Reset the interface, and join the ring
239 */
240 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */
241 addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */
5b319f7c 242 DELAY(500000); /* let contacts settle */
5f3ad58b 243 vs->vs_init = 0;
4cdd59b5 244 vs->vs_dropped = 0;
5f3ad58b
SL
245 vs->vs_nottaken = 0;
246
247 /*
248 * Hang a receive and start any
249 * pending writes by faking a transmit complete.
250 */
251 s = splimp();
252 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
1cd789fb
SL
253 addr->vviba = (u_short)ubainfo;
254 addr->vviea = (u_short)(ubainfo >> 16);
5f3ad58b
SL
255 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
256 addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
4cdd59b5 257 vs->vs_iactive = ACTIVE;
5f3ad58b 258 vs->vs_oactive = 1;
1cd789fb 259 vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING;
5f3ad58b
SL
260 vvxint(unit);
261 splx(s);
262 if_rtinit(&vs->vs_if, RTF_UP);
263}
264
265/*
266 * vvidentify() - return our host address
267 */
38061563 268vvidentify(unit)
1cd789fb 269 int unit;
38061563 270{
5f3ad58b
SL
271 register struct vv_softc *vs = &vv_softc[unit];
272 register struct uba_device *ui = vvinfo[unit];
273 register struct vvreg *addr;
274 struct mbuf *m;
275 struct vv_header *v;
66923854 276 int ubainfo, attempts, waitcount;
5f3ad58b 277
547e5718
SL
278 /*
279 * Build a multicast message to identify our address
280 */
5f3ad58b 281 addr = (struct vvreg *)ui->ui_addr;
547e5718 282 attempts = 0; /* total attempts, including bad msg type */
38061563 283 m = m_get(M_DONTWAIT, MT_HEADER);
66923854 284 if (m == NULL)
1cd789fb 285 return (0);
4cdd59b5 286 m->m_next = 0;
547e5718
SL
287 m->m_off = MMINOFF;
288 m->m_len = sizeof(struct vv_header);
547e5718 289 v = mtod(m, struct vv_header *);
4cdd59b5 290 v->vh_dhost = VV_BROADCAST; /* multicast destination address */
547e5718
SL
291 v->vh_shost = 0; /* will be overwritten with ours */
292 v->vh_version = RING_VERSION;
293 v->vh_type = RING_WHOAMI;
294 v->vh_info = 0;
4cdd59b5 295 /* map xmit message into uba */
5f3ad58b
SL
296 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
297 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
298 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
547e5718
SL
299 /*
300 * Reset interface, establish Digital Loopback Mode, and
301 * send the multicast (to myself) with Input Copy enabled.
302 */
303retry:
304 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
305 addr->vvicsr = VV_RST;
306 addr->vviba = (u_short) ubainfo;
307 addr->vviea = (u_short) (ubainfo >> 16);
308 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
309 addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
5f3ad58b
SL
310
311 /* let flag timers fire so ring will initialize */
d3758410 312 DELAY(2000000);
5f3ad58b 313
547e5718
SL
314 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */
315 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
316 addr->vvoba = (u_short) ubainfo;
317 addr->vvoea = (u_short) (ubainfo >> 16);
318 addr->vvowc = -((vs->vs_olen + 1) >> 1);
319 addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
547e5718
SL
320 /*
321 * Wait for receive side to finish.
4cdd59b5 322 * Extract source address (which will our own),
547e5718
SL
323 * and post to interface structure.
324 */
325 DELAY(1000);
4cdd59b5 326 for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) {
0d6eea7c 327 if (waitcount < 10) {
547e5718 328 DELAY(1000);
38061563 329 continue;
4cdd59b5 330 }
38061563
SL
331 if (attempts++ >= 10) {
332 printf("vv%d: can't initialize\n", unit);
333 printf("vvinit loopwait: icsr = %b\n",
334 0xffff&(addr->vvicsr), VV_IBITS);
335 vs->vs_if.if_flags &= ~IFF_UP;
66923854 336 return (0);
547e5718 337 }
38061563 338 goto retry;
4cdd59b5 339 }
547e5718
SL
340 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
341 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
342 if (vs->vs_ifuba.ifu_xtofree)
343 m_freem(vs->vs_ifuba.ifu_xtofree);
344 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
345 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
346 m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
38061563 347 if (m != NULL)
547e5718
SL
348 m_freem(m);
349 /*
38061563 350 * Check message type before we believe the source host address
547e5718
SL
351 */
352 v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
38061563 353 if (v->vh_type != RING_WHOAMI)
5f3ad58b 354 goto retry;
38061563 355 return(v->vh_shost);
4cdd59b5
SL
356}
357
358/*
359 * vvtimeout() - called by timer flywheel to monitor input packet
360 * discard rate. Interfaces getting too many errors are shut
361 * down for a while. If the condition persists, the interface
362 * is marked down.
363 */
66923854 364/*ARGSUSED*/
4cdd59b5 365vvtimeout(junk)
38061563 366 int junk;
4cdd59b5
SL
367{
368 register struct vv_softc *vs;
369 register int i;
370 register struct vvreg *addr;
371 int ubainfo;
372
373 timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
38061563 374 for (i = 0; i < NVV; i++) {
4cdd59b5
SL
375 vs = &vv_softc[i];
376 addr = (struct vvreg *)vvinfo[i]->ui_addr;
66923854
SL
377 if ((vs->vs_if.if_flags & IFF_UP) == 0)
378 continue;
4cdd59b5
SL
379 switch (vs->vs_major) {
380
381 /*
382 * MODE0: generally OK, just check error rate
383 */
4cdd59b5
SL
384 case MODE0:
385 if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
386 vs->vs_dropped = 0;
387 continue;
388 }
38061563
SL
389 /* suspend reads for a while */
390 vvtrprintf("vv%d going MODE1 in vvtimeout\n",i);
391 vs->vs_major = MODE1;
392 vs->vs_iactive = PAUSE; /* no new reads */
393 vs->vs_retry = VV_MODE1ATTEMPTS;
394 vs->vs_delayclock = VV_MODE1DELAY;
395 vs->vs_minor = 0;
396 continue;
4cdd59b5
SL
397
398 /*
399 * MODE1: excessive error rate observed
400 * Scheme: try simply suspending reads for a
401 * short while a small number of times
402 */
4cdd59b5
SL
403 case MODE1:
404 if (vs->vs_delayclock > 0) {
405 vs->vs_delayclock--;
406 continue;
407 }
408 switch (vs->vs_minor) {
38061563 409
4cdd59b5
SL
410 case 0: /* reenable reads */
411 vvtrprintf("vv%d M1m0\n",i);
412 vs->vs_dropped = 0;
413 vs->vs_iactive = ACTIVE;
414 vs->vs_minor = 1; /* next state */
415 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
416 addr->vviba = (u_short) ubainfo;
417 addr->vviea = (u_short) (ubainfo >> 16);
38061563
SL
418 addr->vviwc =
419 -(sizeof (struct vv_header) + VVMTU) >> 1;
4cdd59b5
SL
420 addr->vvicsr = VV_RST | VV_CONF;
421 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
422 continue;
38061563 423
4cdd59b5
SL
424 case 1: /* see if it worked */
425 vvtrprintf("vv%d M1m1\n",i);
426 if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
427 vs->vs_dropped = 0;
428 vs->vs_major = MODE0; /* yeah!! */
429 continue;
430 }
38061563
SL
431 if (vs->vs_retry -- > 0) {
432 vs->vs_dropped = 0;
433 vs->vs_iactive = PAUSE;
434 vs->vs_delayclock = VV_MODE1DELAY;
435 vs->vs_minor = 0; /* recheck */
436 continue;
4cdd59b5 437 }
38061563
SL
438 vs->vs_major = MODE2;
439 vs->vs_minor = 0;
440 vs->vs_dropped = 0;
441 vs->vs_iactive = OPEN;
442 vs->vs_delayrange = VV_MODE2DELAY;
443 vs->vs_delayclock = VV_MODE2DELAY;
444 /* fall thru ... */
4cdd59b5
SL
445 }
446
447 /*
448 * MODE2: simply ignoring traffic didn't relieve condition
449 * Scheme: open host relay for intervals linearly
450 * increasing up to some maximum of a several minutes.
451 * This allows broken networks to return to operation
452 * without rebooting.
453 */
4cdd59b5
SL
454 case MODE2:
455 if (vs->vs_delayclock > 0) {
456 vs->vs_delayclock--;
457 continue;
458 }
459 switch (vs->vs_minor) {
38061563 460
4cdd59b5
SL
461 case 0: /* close relay and reenable reads */
462 vvtrprintf("vv%d M2m0\n",i);
463 vs->vs_dropped = 0;
464 vs->vs_iactive = ACTIVE;
465 vs->vs_minor = 1; /* next state */
466 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
467 addr->vviba = (u_short) ubainfo;
468 addr->vviea = (u_short) (ubainfo >> 16);
38061563
SL
469 addr->vviwc =
470 -(sizeof (struct vv_header) + VVMTU) >> 1;
4cdd59b5
SL
471 addr->vvicsr = VV_RST | VV_CONF;
472 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
473 continue;
38061563 474
4cdd59b5
SL
475 case 1: /* see if it worked */
476 vvtrprintf("vv%d M2m1\n",i);
477 if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
478 vs->vs_dropped = 0;
479 vs->vs_major = MODE0; /* yeah!! */
480 continue;
481 }
38061563
SL
482 vvtrprintf("vv%d M2m1 ++ delay\n",i);
483 vs->vs_dropped = 0;
484 vs->vs_iactive = OPEN;
485 vs->vs_minor = 0;
486 if (vs->vs_delayrange < VV_MAXDELAY)
487 vs->vs_delayrange +=
488 (vs->vs_delayrange/2);
489 vs->vs_delayclock = vs->vs_delayrange;
490 continue;
4cdd59b5
SL
491 }
492
4cdd59b5
SL
493 default:
494 printf("vv%d: major state screwed\n", i);
495 vs->vs_if.if_flags &= ~IFF_UP;
496 }
497 }
547e5718
SL
498}
499
500/*
501 * Start or restart output on interface.
4cdd59b5
SL
502 * If interface is active, this is a retransmit, so just
503 * restuff registers and go.
547e5718
SL
504 * If interface is not already active, get another datagram
505 * to send off of the interface queue, and map it to the interface
506 * before starting the output.
507 */
508vvstart(dev)
509 dev_t dev;
510{
511 int unit = VVUNIT(dev);
512 struct uba_device *ui = vvinfo[unit];
513 register struct vv_softc *vs = &vv_softc[unit];
514 register struct vvreg *addr;
515 struct mbuf *m;
4cdd59b5
SL
516 int ubainfo;
517 int dest;
547e5718
SL
518
519 if (vs->vs_oactive)
520 goto restart;
547e5718
SL
521 /*
522 * Not already active: dequeue another request
523 * and map it to the UNIBUS. If no more requests,
524 * just return.
525 */
526 IF_DEQUEUE(&vs->vs_if.if_snd, m);
38061563 527 if (m == NULL) {
547e5718
SL
528 vs->vs_oactive = 0;
529 return;
530 }
531 dest = mtod(m, struct vv_header *)->vh_dhost;
532 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
533 vs->vs_lastx = dest;
547e5718
SL
534restart:
535 /*
536 * Have request mapped to UNIBUS for transmission.
537 * Purge any stale data from this BDP, and start the otput.
538 */
c8c82d1f 539 if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) {
4cdd59b5
SL
540 printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen);
541 panic("vvdriver vs_olen botch");
542 }
547e5718
SL
543 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
544 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
545 addr = (struct vvreg *)ui->ui_addr;
546 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
547 addr->vvoba = (u_short) ubainfo;
548 addr->vvoea = (u_short) (ubainfo >> 16);
549 addr->vvowc = -((vs->vs_olen + 1) >> 1);
550 addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
551 vs->vs_oactive = 1;
552}
553
554/*
555 * VVLNI transmit interrupt
556 * Start another output if more data to send.
557 */
558vvxint(unit)
559 int unit;
560{
561 register struct uba_device *ui = vvinfo[unit];
562 register struct vv_softc *vs = &vv_softc[unit];
563 register struct vvreg *addr;
564 register int oc;
547e5718
SL
565
566 addr = (struct vvreg *)ui->ui_addr;
567 oc = 0xffff & (addr->vvocsr);
568 if (vs->vs_oactive == 0) {
4cdd59b5 569 printf("vv%d: stray interrupt vvocsr = %b\n", unit,
547e5718
SL
570 oc, VV_OBITS);
571 return;
572 }
573 if (oc & (VV_OPT | VV_RFS)) {
5f3ad58b 574 vs->vs_if.if_collisions++;
4cdd59b5 575 if (vs->vs_tries++ < VVRETRY) {
547e5718
SL
576 if (oc & VV_OPT)
577 vs->vs_init++;
578 if (oc & VV_RFS)
579 vs->vs_nottaken++;
4cdd59b5 580 vvstart(unit); /* restart this message */
547e5718
SL
581 return;
582 }
583 if (oc & VV_OPT)
584 printf("vv%d: output timeout\n");
585 }
586 vs->vs_if.if_opackets++;
587 vs->vs_oactive = 0;
588 vs->vs_tries = 0;
589 if (oc & VVXERR) {
590 vs->vs_if.if_oerrors++;
4cdd59b5 591 printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
547e5718
SL
592 VV_OBITS);
593 }
594 if (vs->vs_ifuba.ifu_xtofree) {
595 m_freem(vs->vs_ifuba.ifu_xtofree);
596 vs->vs_ifuba.ifu_xtofree = 0;
597 }
598 if (vs->vs_if.if_snd.ifq_head == 0) {
4cdd59b5 599 vs->vs_lastx = 256; /* an invalid address */
547e5718
SL
600 return;
601 }
602 vvstart(unit);
603}
604
605/*
606 * V2lni interface receiver interrupt.
607 * If input error just drop packet.
608 * Otherwise purge input buffered data path and examine
609 * packet to determine type. If can't determine length
610 * from type, then have to drop packet. Othewise decapsulate
611 * packet based on type and pass to type specific higher-level
612 * input routine.
613 */
614vvrint(unit)
615 int unit;
616{
617 register struct vv_softc *vs = &vv_softc[unit];
618 struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr;
619 register struct vv_header *vv;
620 register struct ifqueue *inq;
621 struct mbuf *m;
622 int ubainfo, len, off;
5f3ad58b 623 short resid;
547e5718
SL
624
625 vs->vs_if.if_ipackets++;
626 /*
627 * Purge BDP; drop if input error indicated.
628 */
629 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
630 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
631 if (addr->vvicsr & VVRERR) {
4cdd59b5
SL
632 if (vv_logreaderrors)
633 printf("vv%d: error vvicsr = %b\n", unit,
634 0xffff&(addr->vvicsr), VV_IBITS);
5f3ad58b 635 goto dropit;
547e5718 636 }
5f3ad58b 637
547e5718 638 /*
5f3ad58b
SL
639 * Get packet length from word count residue
640 *
641 * Compute header offset if trailer protocol
642 *
643 * Pull packet off interface. Off is nonzero if packet
644 * has trailing header; if_rubaget will then force this header
645 * information to be at the front. The vh_info field
646 * carries the offset to the trailer data in trailer
647 * format packets.
547e5718 648 */
5f3ad58b 649 vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
4cdd59b5 650 vvtracehdr("vi", vv);
5f3ad58b
SL
651 resid = addr->vviwc;
652 if (resid)
653 resid |= 0176000; /* ugly!!!! */
654 len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
655 len -= sizeof(struct vv_header);
4cdd59b5 656 if (len > VVMRU || len <= 0)
5f3ad58b
SL
657 goto dropit;
658#define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off))))
1cd789fb
SL
659 if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
660 if (vv->vh_type >= RING_IPTrailer &&
661 vv->vh_type < RING_IPTrailer+RING_IPNTrailer) {
5f3ad58b
SL
662 off = (vv->vh_type - RING_IPTrailer) * 512;
663 if (off > VVMTU)
664 goto dropit;
665 vv->vh_type = *vvdataaddr(vv, off, u_short *);
666 resid = *(vvdataaddr(vv, off+2, u_short *));
667 if (off + resid > len)
668 goto dropit;
669 len = off + resid;
38061563 670 } else
5f3ad58b
SL
671 off = 0;
672 if (len == 0)
673 goto dropit;
674 m = if_rubaget(&vs->vs_ifuba, len, off);
38061563 675 if (m == NULL)
5f3ad58b
SL
676 goto dropit;
677 if (off) {
678 m->m_off += 2 * sizeof(u_short);
679 m->m_len -= 2 * sizeof(u_short);
680 }
4cdd59b5
SL
681
682 /*
683 * Demultiplex on packet type
684 */
547e5718 685 switch (vv->vh_type) {
4cdd59b5 686
547e5718
SL
687#ifdef INET
688 case RING_IP:
547e5718
SL
689 schednetisr(NETISR_IP);
690 inq = &ipintrq;
691 break;
692#endif
693 default:
694 printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
5f3ad58b 695 m_freem(m);
547e5718
SL
696 goto setup;
697 }
5f3ad58b
SL
698 if (IF_QFULL(inq)) {
699 IF_DROP(inq);
700 m_freem(m);
38061563 701 } else
5f3ad58b 702 IF_ENQUEUE(inq, m);
547e5718
SL
703setup:
704 /*
4cdd59b5
SL
705 * Check the error rate and start recovery if needed
706 * this has to go here since the timer flywheel runs at
707 * a lower ipl and never gets a chance to change the mode
708 */
709 if (vs->vs_major == MODE0 && vs->vs_dropped > VV_ERRORTHRESHOLD) {
4cdd59b5
SL
710 vvtrprintf("vv%d going MODE1 in vvrint\n",unit);
711 vs->vs_major = MODE1;
712 vs->vs_iactive = PAUSE; /* no new reads */
713 vs->vs_retry = VV_MODE1ATTEMPTS;
714 vs->vs_delayclock = VV_MODE1DELAY;
715 vs->vs_minor = 0;
716 vs->vs_dropped = 0;
717 }
4cdd59b5
SL
718 switch (vs->vs_iactive) {
719
38061563 720 case ACTIVE: /* Restart the read for next packet */
4cdd59b5
SL
721 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
722 addr->vviba = (u_short) ubainfo;
723 addr->vviea = (u_short) (ubainfo >> 16);
724 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
725 addr->vvicsr = VV_RST | VV_CONF;
726 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
727 return;
728
38061563 729 case PAUSE: /* requested to not start any new reads */
4cdd59b5
SL
730 vs->vs_dropped = 0;
731 return;
732
38061563 733 case OPEN: /* request to open host relay */
4cdd59b5
SL
734 vs->vs_dropped = 0;
735 addr->vvicsr = 0;
736 return;
737
738 default:
739 printf("vv%d: vs_iactive = %d\n", unit, vs->vs_iactive);
740 return;
741 }
4cdd59b5 742 /*
38061563 743 * Drop packet on floor -- count them!!
547e5718 744 */
5f3ad58b
SL
745dropit:
746 vs->vs_if.if_ierrors++;
4cdd59b5 747 vs->vs_dropped++;
5f3ad58b
SL
748 /*
749 printf("vv%d: error vvicsr = %b\n", unit,
750 0xffff&(addr->vvicsr), VV_IBITS);
751 */
752 goto setup;
547e5718
SL
753}
754
755/*
756 * V2lni output routine.
757 * Encapsulate a packet of type family for the local net.
758 * Use trailer local net encapsulation if enough data in first
759 * packet leaves a multiple of 512 bytes of data in remainder.
760 */
761vvoutput(ifp, m0, dst)
762 struct ifnet *ifp;
763 struct mbuf *m0;
764 struct sockaddr *dst;
765{
766 register struct mbuf *m = m0;
767 register struct vv_header *vv;
5f3ad58b
SL
768 register int off;
769 int type, dest, s, error;
547e5718
SL
770
771 switch (dst->sa_family) {
4cdd59b5 772
547e5718
SL
773#ifdef INET
774 case AF_INET: {
5f3ad58b 775 dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
4cdd59b5 776 if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) {
5f3ad58b
SL
777 error = EPERM;
778 goto bad;
779 }
5f3ad58b
SL
780 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
781 if (vv_dotrailer && off > 0 && (off & 0x1ff) == 0 &&
782 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
783 type = RING_IPTrailer + (off>>9);
784 m->m_off -= 2 * sizeof (u_short);
785 m->m_len += 2 * sizeof (u_short);
786 *mtod(m, u_short *) = RING_IP;
787 *(mtod(m, u_short *) + 1) = m->m_len;
788 goto gottrailertype;
789 }
547e5718
SL
790 type = RING_IP;
791 off = 0;
792 goto gottype;
793 }
794#endif
795 default:
796 printf("vv%d: can't handle af%d\n", ifp->if_unit,
797 dst->sa_family);
5f3ad58b
SL
798 error = EAFNOSUPPORT;
799 goto bad;
547e5718
SL
800 }
801
802gottrailertype:
803 /*
804 * Packet to be sent as trailer: move first packet
805 * (control information) to end of chain.
806 */
807 while (m->m_next)
808 m = m->m_next;
809 m->m_next = m0;
810 m = m0->m_next;
811 m0->m_next = 0;
812 m0 = m;
547e5718
SL
813gottype:
814 /*
815 * Add local net header. If no space in first mbuf,
816 * allocate another.
817 */
818 if (m->m_off > MMAXOFF ||
819 MMINOFF + sizeof (struct vv_header) > m->m_off) {
38061563
SL
820 m = m_get(M_DONTWAIT, MT_HEADER);
821 if (m == NULL) {
5f3ad58b
SL
822 error = ENOBUFS;
823 goto bad;
547e5718
SL
824 }
825 m->m_next = m0;
826 m->m_off = MMINOFF;
827 m->m_len = sizeof (struct vv_header);
828 } else {
829 m->m_off -= sizeof (struct vv_header);
830 m->m_len += sizeof (struct vv_header);
831 }
832 vv = mtod(m, struct vv_header *);
833 vv->vh_shost = ifp->if_host[0];
834 vv->vh_dhost = dest;
835 vv->vh_version = RING_VERSION;
836 vv->vh_type = type;
5f3ad58b 837 vv->vh_info = off;
4cdd59b5 838 vvtracehdr("vo", vv);
547e5718
SL
839
840 /*
841 * Queue message on interface, and start output if interface
842 * not yet active.
843 */
844 s = splimp();
5f3ad58b
SL
845 if (IF_QFULL(&ifp->if_snd)) {
846 IF_DROP(&ifp->if_snd);
847 error = ENOBUFS;
848 goto qfull;
849 }
547e5718
SL
850 IF_ENQUEUE(&ifp->if_snd, m);
851 if (vv_softc[ifp->if_unit].vs_oactive == 0)
852 vvstart(ifp->if_unit);
853 splx(s);
5f3ad58b 854 return (0);
5f3ad58b
SL
855qfull:
856 m0 = m;
857 splx(s);
858bad:
859 m_freem(m0);
860 return(error);
547e5718
SL
861}
862
1cd789fb
SL
863/*
864 * Process an ioctl request.
865 */
866vvioctl(ifp, cmd, data)
867 register struct ifnet *ifp;
868 int cmd;
869 caddr_t data;
870{
871 struct ifreq *ifr = (struct ifreq *)data;
872 int s = splimp(), error = 0;
873
874 switch (cmd) {
875
876 case SIOCSIFADDR:
877 /* too difficult to change addr while running */
878 if ((ifp->if_flags & IFF_RUNNING) == 0) {
879 ifp->if_net = in_netof(ifr->ifr_addr.sin_addr);
880 vvinit(ifp->if_unit);
881 } else
882 error = EINVAL;
883 break;
884
885 default:
886 error = EINVAL;
887 }
888 splx(s);
889 return (error);
890}
891
547e5718
SL
892/*
893 * vvprt_hdr(s, v) print the local net header in "v"
894 * with title is "s"
895 */
896vvprt_hdr(s, v)
897 char *s;
898 register struct vv_header *v;
899{
900 printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
901 s,
902 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
903 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
904 0xffff & (int)(v->vh_info));
905}
906
66923854 907#ifdef notdef
547e5718
SL
908/*
909 * print "l" hex bytes starting at "s"
910 */
911vvprt_hex(s, l)
912 char *s;
913 int l;
914{
915 register int i;
916 register int z;
917
918 for (i=0 ; i < l; i++) {
919 z = 0xff & (int)(*(s + i));
920 printf("%c%c ",
921 "0123456789abcdef"[(z >> 4) & 0x0f],
922 "0123456789abcdef"[z & 0x0f]
923 );
924 }
925}
66923854 926#endif