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 * 6 * @(#)if_vv.c 6.20 (Berkeley) 03/27/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(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(RING_IP); 871 *(mtod(m, u_short *) + 1) = htons(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(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 1002