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