1: /*
   2:  * Copyright (c) 1982, 1986 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  *
   6:  *	@(#)if_vv.c	7.1 (Berkeley) 6/5/86
   7:  */
   8: 
   9: #include "vv.h"
  10: #if NVV > 0
  11: 
  12: /*
  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".
  17:  *
  18:  * This driver is compatible with the proNET 10 meagbit and
  19:  * 80 megabit token ring interfaces (models p1000 and p1080).
  20:  * A unit may be marked as 80 megabit using "flags 1" in the
  21:  * config file.
  22:  *
  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!
  32:  *
  33:  * HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001)
  34:  * have a serial number >= 040, which is about March, 1982. Older
  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.
  43:  */
  44: #include "../machine/pte.h"
  45: 
  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"
  55: 
  56: #include "../net/if.h"
  57: #include "../net/netisr.h"
  58: #include "../net/route.h"
  59: 
  60: #ifdef  INET
  61: #include "../netinet/in.h"
  62: #include "../netinet/in_systm.h"
  63: #include "../netinet/in_var.h"
  64: #include "../netinet/ip.h"
  65: #endif
  66: 
  67: #include "../vax/cpu.h"
  68: #include "../vax/mtpr.h"
  69: #include "if_vv.h"
  70: #include "if_uba.h"
  71: #include "../vaxuba/ubareg.h"
  72: #include "../vaxuba/ubavar.h"
  73: 
  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:  */
  81: 
  82: #define VVMTU (1536)
  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
  94: 
  95: /*
  96:  *   debugging and tracing stuff
  97:  */
  98: int vv_tracehdr = 0;    /* 1 => trace headers (slowly!!) */
  99: 
 100: #define vvtracehdr  if (vv_tracehdr) vvprt_hdr
 101: #define vvprintf    if (vs->vs_if.if_flags & IFF_DEBUG) printf
 102: 
 103: /*
 104:  * externals, types, etc.
 105:  */
 106: int vvprobe(), vvattach(), vvreset(), vvinit();
 107: int vvidentify(), vvstart(), vvxint(), vvwatchdog();
 108: int vvrint(), vvoutput(), vvioctl();
 109: struct  uba_device *vvinfo[NVV];
 110: u_short vvstd[] = { 0 };
 111: struct  uba_driver vvdriver =
 112:     { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
 113: #define VVUNIT(x)   minor(x)
 114: 
 115: #define LOOPBACK        /* use loopback for packets meant for us */
 116: #ifdef  LOOPBACK
 117: extern struct ifnet loif;
 118: #endif
 119: 
 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:  */
 132: struct  vv_softc {
 133:     struct  ifnet vs_if;        /* network-visible interface */
 134:     struct  ifuba vs_ifuba;     /* UNIBUS resources */
 135:     u_short vs_host;        /* this interface address */
 136:     short   vs_oactive;     /* is output active */
 137:     short   vs_is80;        /* is 80 megabit version */
 138:     short   vs_olen;        /* length of last output */
 139:     u_short vs_lastx;       /* address of last packet sent */
 140:     u_short vs_lastr;       /* address of last packet received */
 141:     short   vs_tries;       /* transmit current retry count */
 142:     short   vs_init;        /* number of ring inits */
 143:     short   vs_refused;     /* number of packets refused */
 144:     short   vs_timeouts;        /* number of transmit timeouts */
 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 */
 149: } vv_softc[NVV];
 150: 
 151: #define NOHOST  0xffff          /* illegal host number */
 152: 
 153: /*
 154:  * probe the interface to see that the registers exist, and then
 155:  * cause an interrupt to find its vector
 156:  */
 157: vvprobe(reg)
 158:     caddr_t reg;
 159: {
 160:     register int br, cvec;
 161:     register struct vvreg *addr;
 162: 
 163: #ifdef lint
 164:     br = 0; cvec = br; br = cvec;
 165: #endif
 166:     addr = (struct vvreg *)reg;
 167: 
 168:     /* reset interface, enable, and wait till dust settles */
 169:     addr->vvicsr = VV_RST;
 170:     addr->vvocsr = VV_RST;
 171:     DELAY(100000);
 172: 
 173:     /* generate interrupt by doing 1 word DMA from 0 in uba space!! */
 174:     addr->vvoba = 0;        /* low 16 bits */
 175:     addr->vvoea = 0;        /* extended bits */
 176:     addr->vvowc = -1;       /* for 1 word */
 177:     addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */
 178:     DELAY(100000);
 179:     addr->vvocsr = VV_RST;      /* clear out the CSR */
 180:     if (cvec && cvec != 0x200)
 181:         cvec -= 4;      /* backup so vector => receive */
 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:  */
 190: vvattach(ui)
 191:     struct uba_device *ui;
 192: {
 193:     register struct vv_softc *vs;
 194: 
 195:     vs = &vv_softc[ui->ui_unit];
 196:     vs->vs_if.if_unit = ui->ui_unit;
 197:     vs->vs_if.if_name = "vv";
 198:     vs->vs_if.if_mtu = VVMTU;
 199:     vs->vs_if.if_flags = IFF_BROADCAST;
 200:     vs->vs_if.if_init = vvinit;
 201:     vs->vs_if.if_ioctl = vvioctl;
 202:     vs->vs_if.if_output = vvoutput;
 203:     vs->vs_if.if_reset = vvreset;
 204:     vs->vs_if.if_timer = 0;
 205:     vs->vs_if.if_watchdog = vvwatchdog;
 206:     vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP;
 207: 
 208:     /* use flag to determine if this is proNET-80 */
 209:     vs->vs_is80 = (short)(ui->ui_flags & 01);
 210: 
 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
 216:     if_attach(&vs->vs_if);
 217: }
 218: 
 219: /*
 220:  * Reset of interface after UNIBUS reset.
 221:  * If interface is on specified uba, reset its state.
 222:  */
 223: vvreset(unit, uban)
 224:     int unit, uban;
 225: {
 226:     register struct uba_device *ui;
 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:  */
 239: vvinit(unit)
 240:     int unit;
 241: {
 242:     register struct vv_softc *vs;
 243:     register struct uba_device *ui;
 244:     register struct vvreg *addr;
 245:     register int ubainfo, s;
 246: 
 247:     vs = &vv_softc[unit];
 248:     ui = vvinfo[unit];
 249: 
 250:     if (vs->vs_if.if_addrlist == (struct ifaddr *)0)
 251:         return;
 252: 
 253:     addr = (struct vvreg *)ui->ui_addr;
 254:     if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
 255:         sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
 256:         printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
 257:         vs->vs_if.if_flags &= ~IFF_UP;
 258:         return;
 259:     }
 260: 
 261:     /*
 262: 	 * Now that the uba is set up, figure out our address and
 263: 	 * update complete our host address.
 264: 	 */
 265:     if ((vs->vs_host = vvidentify(unit)) == NOHOST) {
 266:         vs->vs_if.if_flags &= ~IFF_UP;
 267:         return;
 268:     }
 269:     printf("vv%d: host %u\n", unit, vs->vs_host);
 270: 
 271:     /*
 272: 	 * Reset the interface, and stay in the ring
 273: 	 */
 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 */
 278:     DELAY(500000);              /* let contacts settle */
 279: 
 280:     vs->vs_init = 0;            /* clear counters, etc. */
 281:     vs->vs_refused = 0;
 282:     vs->vs_timeouts = 0;
 283:     vs->vs_otimeout = 0;
 284:     vs->vs_ibadf = 0;
 285:     vs->vs_parity = 0;
 286:     vs->vs_lastx = 256;         /* an invalid address */
 287:     vs->vs_lastr = 256;         /* an invalid address */
 288: 
 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;
 295:     addr->vviba = (u_short)ubainfo;
 296:     addr->vviea = (u_short)(ubainfo >> 16);
 297:     addr->vviwc = -(VVBUFSIZE) >> 1;
 298:     addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB;
 299:     vs->vs_oactive = 1;
 300:     vs->vs_if.if_flags |= IFF_RUNNING;
 301:     vvxint(unit);
 302:     splx(s);
 303: }
 304: 
 305: /*
 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:  *
 311:  */
 312: 
 313: /* the three self-test modes */
 314: static u_short vv_modes[] = {
 315:     VV_STE|VV_LPB,          /* digital loopback */
 316:     VV_STE,             /* analog loopback */
 317:     VV_HEN              /* network mode */
 318: };
 319: 
 320: vvidentify(unit)
 321:     int unit;
 322: {
 323:     register struct vv_softc *vs;
 324:     register struct uba_device *ui;
 325:     register struct vvreg *addr;
 326:     register struct mbuf *m;
 327:     register struct vv_header *v;
 328:     register int ubainfo;
 329:     register int i, successes, failures, waitcount;
 330:     u_short shost = NOHOST;
 331: 
 332:     vs = &vv_softc[unit];
 333:     ui = vvinfo[unit];
 334:     addr = (struct vvreg *)ui->ui_addr;
 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: 	 */
 342:     m = m_get(M_DONTWAIT, MT_HEADER);
 343:     if (m == NULL) {
 344:         printf("vv%d: can't initialize, m_get() failed\n", unit);
 345:         return (0);
 346:     }
 347:     m->m_next = 0;
 348:     m->m_off = MMINOFF;
 349:     m->m_len = sizeof(struct vv_header);
 350:     v = mtod(m, struct vv_header *);
 351:     v->vh_dhost = VV_BROADCAST; /* multicast destination address */
 352:     v->vh_shost = 0;        /* will be overwritten with ours */
 353:     v->vh_version = RING_VERSION;
 354:     v->vh_type = RING_DIAGNOSTICS;
 355:     v->vh_info = 0;
 356:     /* map xmit message into uba, copying to intermediate buffer */
 357:     vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
 358: 
 359:     /*
 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.
 365: 	 */
 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 */
 416:             continue;
 417: 
 418: gotit:          /* we got something--is it any good? */
 419:             if ((addr->vvicsr & (VVRERR|VV_LDE)) ||
 420:                 (addr->vvocsr & (VVXERR|VV_RFS))) {
 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);
 429:             m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header),
 430:                 0, &vs->vs_if);
 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) {
 438:                 if (shost == NOHOST) {
 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++;
 446:             } else {
 447:                 failures++;
 448:             }
 449:             v->vh_type = 0;  /* clear to check again */
 450:         }
 451: 
 452:         if (failures >= VVIDENTRETRY)
 453:         {
 454:             printf("vv%d: failed self-test after %d tries \
 455: in %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;
 463:             shost = NOHOST;
 464:             goto done;
 465:         }
 466:     }
 467: 
 468: done:
 469:     /* deallocate mbuf used for send packet (won't be one, anyways) */
 470:     if (vs->vs_ifuba.ifu_xtofree) {
 471:         m_freem(vs->vs_ifuba.ifu_xtofree);
 472:         vs->vs_ifuba.ifu_xtofree = 0;
 473:     }
 474: 
 475:     return(shost);
 476: }
 477: 
 478: /*
 479:  * Start or restart output on interface.
 480:  * If interface is active, this is a retransmit, so just
 481:  * restuff registers and go.
 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:  */
 486: vvstart(dev)
 487:     dev_t dev;
 488: {
 489:     register struct uba_device *ui;
 490:     register struct vv_softc *vs;
 491:     register struct vvreg *addr;
 492:     register struct mbuf *m;
 493:     register int unit, ubainfo, dest, s;
 494: 
 495:     unit = VVUNIT(dev);
 496:     ui = vvinfo[unit];
 497:     vs = &vv_softc[unit];
 498:     if (vs->vs_oactive)
 499:         goto restart;
 500:     /*
 501: 	 * Not already active: dequeue another request
 502: 	 * and map it to the UNIBUS.  If no more requests,
 503: 	 * just return.
 504: 	 */
 505:     s = splimp();
 506:     IF_DEQUEUE(&vs->vs_if.if_snd, m);
 507:     splx(s);
 508:     if (m == NULL) {
 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;
 515: restart:
 516:     /*
 517: 	 * Have request mapped to UNIBUS for transmission.
 518: 	 * Purge any stale data from this BDP, and start the output.
 519: 	 *
 520: 	 * Make sure this packet will fit in the interface.
 521: 	 */
 522:     if (vs->vs_olen > VVBUFSIZE) {
 523:         printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen);
 524:         panic("vvdriver vs_olen botch");
 525:     }
 526: 
 527:     vs->vs_if.if_timer = VVTIMEOUT;
 528:     vs->vs_oactive = 1;
 529: 
 530:     /* ship it */
 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);
 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 */
 541:     addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
 542: }
 543: 
 544: /*
 545:  * proNET transmit interrupt
 546:  * Start another output if more data to send.
 547:  */
 548: vvxint(unit)
 549:     int unit;
 550: {
 551:     register struct uba_device *ui;
 552:     register struct vv_softc *vs;
 553:     register struct vvreg *addr;
 554:     register int oc;
 555: 
 556:     ui = vvinfo[unit];
 557:     vs = &vv_softc[unit];
 558:     vs->vs_if.if_timer = 0;
 559:     addr = (struct vvreg *)ui->ui_addr;
 560:     oc = 0xffff & (addr->vvocsr);
 561:     if (vs->vs_oactive == 0) {
 562:         vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit,
 563:             oc, VV_OBITS);
 564:         return;
 565:     }
 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)) {
 572:         if (vs->vs_tries++ < VVRETRY) {
 573:             if (oc & VV_OPT)
 574:                 vs->vs_otimeout++;
 575:             if (oc & VV_RFS) {
 576:                 vs->vs_if.if_collisions++;
 577:                 vs->vs_refused++;
 578:             }
 579:             vvstart(unit);      /* restart this message */
 580:             return;
 581:         }
 582:     }
 583:     vs->vs_if.if_opackets++;
 584:     vs->vs_oactive = 0;
 585:     vs->vs_tries = 0;
 586: 
 587:     if (oc & VVXERR) {
 588:         vs->vs_if.if_oerrors++;
 589:         vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
 590:             VV_OBITS);
 591:     }
 592:     if (vs->vs_ifuba.ifu_xtofree) {
 593:         m_freem(vs->vs_ifuba.ifu_xtofree);
 594:         vs->vs_ifuba.ifu_xtofree = 0;
 595:     }
 596:     vvstart(unit);
 597: }
 598: 
 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:  */
 604: vvwatchdog(unit)
 605:     int unit;
 606: {
 607:     register struct vv_softc *vs;
 608:     register int s;
 609: 
 610:     vs = &vv_softc[unit];
 611:     vvprintf("vv%d: lost a transmit interrupt.\n", unit);
 612:     vs->vs_timeouts++;
 613:     s = splimp();
 614:     vvstart(unit);
 615:     splx(s);
 616: }
 617: 
 618: /*
 619:  * proNET interface receiver interrupt.
 620:  * If input error just drop packet.
 621:  * Otherwise purge input buffered data path and examine
 622:  * packet to determine type.  If can't determine length
 623:  * from type, then have to drop packet.  Otherwise decapsulate
 624:  * packet based on type and pass to type specific higher-level
 625:  * input routine.
 626:  */
 627: vvrint(unit)
 628:     int unit;
 629: {
 630:     register struct vv_softc *vs;
 631:     register struct vvreg *addr;
 632:     register struct vv_header *vv;
 633:     register struct ifqueue *inq;
 634:     register struct mbuf *m;
 635:     int ubainfo, len, off, s;
 636:     short resid;
 637: 
 638:     vs = &vv_softc[unit];
 639:     vs->vs_if.if_ipackets++;
 640:     addr = (struct vvreg *)vvinfo[unit]->ui_addr;
 641: 
 642:     /*
 643: 	 * Purge BDP
 644: 	 */
 645:     if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
 646:         UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
 647: 
 648:     /*
 649: 	 * receive errors?
 650: 	 */
 651:     if (addr->vvicsr & VVRERR) {
 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++;
 656:         goto dropit;
 657:     }
 658: 
 659:     /*
 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++;
 666: 
 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: 		 */
 673:         if (vs->vs_is80 == 0)
 674:             goto dropit;
 675:     }
 676: 
 677:     /*
 678: 	 * Get packet length from residual word count
 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.
 687: 	 */
 688:     vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
 689:     vvtracehdr("vi", vv);
 690:     resid = addr->vviwc & 01777;    /* only low 10 bits valid */
 691:     if (resid)
 692:         resid |= 0176000;   /* high 6 bits are undefined */
 693:     len = ((VVBUFSIZE >> 1) + resid) << 1;
 694:     len -= sizeof(struct vv_header);
 695: 
 696:     if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) {
 697:         vvprintf("vv%d: len too long or short, \
 698: len = %d, vvicsr = %b\n",
 699:                 unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
 700:         goto dropit;
 701:     }
 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: 
 710: #define vvdataaddr(vv, off, type)   ((type)(((caddr_t)((vv)+1)+(off))))
 711:     if (vv->vh_type == RING_TRAILER ) {
 712:         off = ntohs((u_short)vv->vh_info);
 713:         if (off > VVMTU) {
 714:             vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n",
 715:                     unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
 716:             goto dropit;
 717:         }
 718:         vv->vh_type = ntohs(*vvdataaddr(vv, off, u_short *));
 719:         resid = ntohs(*(vvdataaddr(vv, off+sizeof(u_short), u_short *)));
 720:         if (off + resid > len) {
 721:             vvprintf("vv%d: trailer packet too short\n", unit);
 722:             vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n",
 723:                     unit, off, resid,
 724:                     0xffff&(addr->vvicsr), VV_IBITS);
 725:             goto dropit;
 726:         }
 727:         len = off + resid;
 728:     } else
 729:         off = 0;
 730: 
 731:     if (len == 0) {
 732:         vvprintf("vv%d: len is zero, vvicsr = %b\n", unit,
 733:                 0xffff&(addr->vvicsr), VV_IBITS);
 734:         goto dropit;
 735:     }
 736: 
 737:     m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if);
 738:     if (m == NULL) {
 739:         vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit,
 740:                 0xffff&(addr->vvicsr), VV_IBITS);
 741:         goto dropit;
 742:     }
 743:     if (off) {
 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;
 750:     }
 751: 
 752:     /* Keep track of source address of this packet */
 753:     vs->vs_lastr = vv->vh_shost;
 754: 
 755:     /*
 756: 	 * Demultiplex on packet type
 757: 	 */
 758:     switch (vv->vh_type) {
 759: 
 760: #ifdef INET
 761:     case RING_IP:
 762:         schednetisr(NETISR_IP);
 763:         inq = &ipintrq;
 764:         break;
 765: #endif
 766:     default:
 767:         vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
 768:         m_freem(m);
 769:         goto setup;
 770:     }
 771:     s = splimp();
 772:     if (IF_QFULL(inq)) {
 773:         IF_DROP(inq);
 774:         m_freem(m);
 775:     } else
 776:         IF_ENQUEUE(inq, m);
 777: 
 778:     splx(s);
 779:     /*
 780: 	 * Reset for the next packet.
 781: 	 */
 782: setup:
 783:     ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
 784:     addr->vviba = (u_short) ubainfo;
 785:     addr->vviea = (u_short) (ubainfo >> 16);
 786:     addr->vviwc = -(VVBUFSIZE) >> 1;
 787:     addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB;
 788:     return;
 789: 
 790:     /*
 791: 	 * Drop packet on floor -- count them!!
 792: 	 */
 793: dropit:
 794:     vs->vs_if.if_ierrors++;
 795:     goto setup;
 796: }
 797: 
 798: /*
 799:  * proNET output routine.
 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:  */
 804: vvoutput(ifp, m0, dst)
 805:     struct ifnet *ifp;
 806:     struct mbuf *m0;
 807:     struct sockaddr *dst;
 808: {
 809:     register struct mbuf *m;
 810:     register struct vv_header *vv;
 811:     register int off;
 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];
 822: 
 823:     /*
 824: 	 * Check to see if the input side has wedged due the UBA
 825: 	 * vectoring through 0.
 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) {
 836:         vvprintf("vv%d: lost a receive interrupt, icsr = %b\n",
 837:                 unit, 0xffff&(addr->vvicsr), VV_IBITS);
 838:         s = splimp();
 839:         vvrint(unit);
 840:         splx(s);
 841:     }
 842: 
 843:     switch (dst->sa_family) {
 844: 
 845: #ifdef INET
 846:     case AF_INET:
 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);
 851: #ifdef LOOPBACK
 852:         if (dest == vs->vs_host && (loif.if_flags & IFF_UP))
 853:             return (looutput(&loif, m0, dst));
 854: #endif LOOPBACK
 855:         if (dest >= 0x100) {
 856:             error = EPERM;
 857:             goto bad;
 858:         }
 859:         off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
 860:         /*
 861: 		 * Trailerize, if the configuration allows it.
 862: 		 * TODO: Need per host negotiation.
 863: 		 */
 864:         if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
 865:         if (off > 0 && (off & 0x1ff) == 0 &&
 866:             m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
 867:             type = RING_TRAILER;
 868:             m->m_off -= 2 * sizeof (u_short);
 869:             m->m_len += 2 * sizeof (u_short);
 870:             *mtod(m, u_short *) = htons((short)RING_IP);
 871:             *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
 872:             goto gottrailertype;
 873:         }
 874:         type = RING_IP;
 875:         off = 0;
 876:         goto gottype;
 877: #endif
 878:     default:
 879:         printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
 880:         error = EAFNOSUPPORT;
 881:         goto bad;
 882:     }
 883: 
 884: gottrailertype:
 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;
 895: gottype:
 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) {
 902:         m = m_get(M_DONTWAIT, MT_HEADER);
 903:         if (m == NULL) {
 904:             error = ENOBUFS;
 905:             goto bad;
 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 *);
 915:     vv->vh_shost = vs->vs_host;
 916:     vv->vh_dhost = dest;
 917:     vv->vh_version = RING_VERSION;
 918:     vv->vh_type = type;
 919:     vv->vh_info = htons((u_short)off);
 920:     vvtracehdr("vo", vv);
 921: 
 922:     /*
 923: 	 * Queue message on interface, and start output if interface
 924: 	 * not yet active.
 925: 	 */
 926:     s = splimp();
 927:     if (IF_QFULL(&ifp->if_snd)) {
 928:         IF_DROP(&ifp->if_snd);
 929:         error = ENOBUFS;
 930:         goto qfull;
 931:     }
 932:     IF_ENQUEUE(&ifp->if_snd, m);
 933:     if (vs->vs_oactive == 0)
 934:         vvstart(unit);
 935:     splx(s);
 936:     return (0);
 937: qfull:
 938:     m0 = m;
 939:     splx(s);
 940: bad:
 941:     m_freem(m0);
 942:     return(error);
 943: }
 944: 
 945: /*
 946:  * Process an ioctl request.
 947:  */
 948: vvioctl(ifp, cmd, data)
 949:     register struct ifnet *ifp;
 950:     int cmd;
 951:     caddr_t data;
 952: {
 953:     struct ifaddr *ifa = (struct ifaddr *) data;
 954:     int s = splimp(), error = 0;
 955: 
 956:     switch (cmd) {
 957: 
 958:     case SIOCSIFADDR:
 959:         ifp->if_flags |= IFF_UP;
 960:         if ((ifp->if_flags & IFF_RUNNING) == 0)
 961:             vvinit(ifp->if_unit);
 962:         /*
 963: 		 * Did self-test succeed?
 964: 		 */
 965:         if ((ifp->if_flags & IFF_UP) == 0)
 966:             error = ENETDOWN;
 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)
 975:                 error = EADDRNOTAVAIL;
 976:             break;
 977:         }
 978:         break;
 979: 
 980:     default:
 981:         error = EINVAL;
 982:     }
 983:     splx(s);
 984:     return (error);
 985: }
 986: 
 987: /*
 988:  * vvprt_hdr(s, v) print the local net header in "v"
 989:  *	with title is "s"
 990:  */
 991: vvprt_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: }
1001: #endif NVV

Defined functions

vvattach defined in line 190; used 2 times
vvidentify defined in line 320; used 2 times
vvinit defined in line 239; used 4 times
vvioctl defined in line 948; used 2 times
vvoutput defined in line 804; used 2 times
vvprobe defined in line 157; used 2 times
vvprt_hdr defined in line 991; used 1 times
vvreset defined in line 223; used 2 times
vvrint defined in line 627; used 2 times
vvstart defined in line 486; used 5 times
vvwatchdog defined in line 604; used 2 times
vvxint defined in line 548; used 2 times

Defined variables

vv_modes defined in line 314; used 3 times
vv_softc defined in line 149; used 9 times
vv_tracehdr defined in line 98; used 1 times
vvdriver defined in line 111; never used
vvinfo defined in line 109; used 8 times
vvstd defined in line 110; used 1 times

Defined struct's

vv_softc defined in line 132; used 16 times

Defined macros

LOOPBACK defined in line 115; used 2 times
NOHOST defined in line 151; used 4 times
VVBUFSIZE defined in line 90; used 7 times
VVMRU defined in line 91; used 4 times
VVMTU defined in line 92; used 6 times
VVUNIT defined in line 113; used 1 times
vvdataaddr defined in line 710; used 2 times
vvprintf defined in line 101; used 13 times
vvtracehdr defined in line 100; used 2 times
Last modified: 1986-06-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2232
Valid CSS Valid XHTML 1.0 Strict