1 /* if_vv.c 4.1 82/06/04 */ 2 3 /* 4 * Proteon 10 Meg Ring Driver. 5 * This device is called "vv" because its "real name", 6 * V2LNI won't work if shortened to the obvious "v2". 7 * Hence the subterfuge. 8 */ 9 #include "../h/param.h" 10 #include "../h/systm.h" 11 #include "../h/mbuf.h" 12 #include "../h/pte.h" 13 #include "../h/buf.h" 14 #include "../h/protosw.h" 15 #include "../h/socket.h" 16 #include "../h/ubareg.h" 17 #include "../h/ubavar.h" 18 #include "../h/cpu.h" 19 #include "../h/mtpr.h" 20 #include "../h/vmmac.h" 21 #include "../net/in.h" 22 #include "../net/in_systm.h" 23 #include "../net/if.h" 24 #include "../net/if_vv.h" 25 #include "../net/if_uba.h" 26 #include "../net/ip.h" 27 #include "../net/ip_var.h" 28 #include "../net/route.h" 29 30 #include "vv.h" 31 #include "imp.h" 32 33 /* 34 * N.B. - if WIRECENTER is defined wrong, it can well break 35 * the hardware!! 36 */ 37 #undef AUTOIDENTIFY 38 #define WIRECENTER 39 40 #ifdef WIRECENTER 41 #define VV_CONF VV_HEN /* drive wire center relay */ 42 #else 43 #define VV_CONF VV_STE /* allow operation without wire center */ 44 #endif 45 46 #define VVMTU (1024+512) 47 48 int vvprobe(), vvattach(), vvrint(), vvxint(); 49 struct uba_device *vvinfo[NVV]; 50 u_short vvstd[] = { 0 }; 51 struct uba_driver vvdriver = 52 { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 53 #define VVUNIT(x) minor(x) 54 int vvinit(),vvoutput(),vvreset(); 55 56 /* 57 * Software status of each interface. 58 * 59 * Each interface is referenced by a network interface structure, 60 * vs_if, which the routing code uses to locate the interface. 61 * This structure contains the output queue for the interface, its address, ... 62 * We also have, for each interface, a UBA interface structure, which 63 * contains information about the UNIBUS resources held by the interface: 64 * map registers, buffered data paths, etc. Information is cached in this 65 * structure for use by the if_uba.c routines in running the interface 66 * efficiently. 67 */ 68 struct vv_softc { 69 struct ifnet vs_if; /* network-visible interface */ 70 struct ifuba vs_ifuba; /* UNIBUS resources */ 71 short vs_oactive; /* is output active? */ 72 short vs_olen; /* length of last output */ 73 u_short vs_lastx; /* last destination address */ 74 short vs_tries; /* current retry count */ 75 short vs_init; /* number of ring inits */ 76 short vs_flush; /* number of flushed packets */ 77 short vs_nottaken; /* number of packets refused */ 78 } vv_softc[NVV]; 79 80 vvprobe(reg) 81 caddr_t reg; 82 { 83 register int br, cvec; 84 register struct vvreg *addr = (struct vvreg *)reg; 85 86 #ifdef lint 87 br = 0; cvec = br; br = cvec; 88 #endif 89 /* reset interface, enable, and wait till dust settles */ 90 addr->vvicsr = VV_RST; 91 addr->vvocsr = VV_RST; 92 DELAY(100000); 93 /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 94 addr->vvocsr = VV_IEN; /* enable interrupt */ 95 addr->vvoba = 0; /* low 16 bits */ 96 addr->vvoea = 0; /* extended bits */ 97 addr->vvowc = -1; /* for 1 word */ 98 addr->vvocsr |= VV_DEN; /* start the DMA */ 99 DELAY(100000); 100 addr->vvocsr = 0; 101 if (cvec && cvec != 0x200) 102 cvec -= 4; /* backup so vector => recieve */ 103 return(1); 104 } 105 106 /* 107 * Interface exists: make available by filling in network interface 108 * record. System will initialize the interface when it is ready 109 * to accept packets. 110 */ 111 vvattach(ui) 112 struct uba_device *ui; 113 { 114 register struct vv_softc *vs = &vv_softc[ui->ui_unit]; 115 register struct sockaddr_in *sin; 116 COUNT(VVATTACH); 117 118 vs->vs_if.if_unit = ui->ui_unit; 119 vs->vs_if.if_name = "vv"; 120 vs->vs_if.if_mtu = VVMTU; 121 vs->vs_if.if_net = ui->ui_flags; 122 vs->vs_if.if_host[0] = 0; /* this will be reset in vvinit() */ 123 124 sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 125 sin->sin_family = AF_INET; 126 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 127 128 sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr; 129 sin->sin_family = AF_INET; 130 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST); 131 vs->vs_if.if_flags = IFF_BROADCAST; 132 133 vs->vs_if.if_init = vvinit; 134 vs->vs_if.if_output = vvoutput; 135 vs->vs_if.if_ubareset = vvreset; 136 vs->vs_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16; 137 if_attach(&vs->vs_if); 138 #if NIMP == 0 139 if (ui->ui_flags & ~0xff) 140 vvlhinit((ui->ui_flags &~ 0xff) | 0x0a); 141 #endif 142 } 143 144 /* 145 * Reset of interface after UNIBUS reset. 146 * If interface is on specified uba, reset its state. 147 */ 148 vvreset(unit, uban) 149 int unit, uban; 150 { 151 register struct uba_device *ui; 152 COUNT(VVRESET); 153 154 if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 155 ui->ui_ubanum != uban) 156 return; 157 printf(" vv%d", unit); 158 vvinit(unit); 159 } 160 161 /* 162 * Initialization of interface; clear recorded pending 163 * operations, and reinitialize UNIBUS usage. 164 */ 165 vvinit(unit) 166 int unit; 167 { 168 register struct vv_softc *vs = &vv_softc[unit]; 169 register struct uba_device *ui = vvinfo[unit]; 170 register struct vvreg *addr; 171 struct sockaddr_in *sin; 172 struct mbuf *m; 173 struct vv_header *v; 174 int ubainfo, retrying, attempts, waitcount, s; 175 176 if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 177 sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 178 printf("vv%d: can't initialize\n", unit); 179 return; 180 } 181 addr = (struct vvreg *)ui->ui_addr; 182 183 #ifdef AUTOIDENTIFY 184 /* 185 * Build a multicast message to identify our address 186 */ 187 attempts = 0; /* total attempts, including bad msg type */ 188 top: 189 retrying = 0; /* first time through */ 190 m = m_get(M_DONTWAIT); 191 if (m == 0) 192 panic("vvinit: can't get mbuf"); 193 m->m_next = 0; 194 m->m_off = MMINOFF; 195 m->m_len = sizeof(struct vv_header); 196 197 v = mtod(m, struct vv_header *); 198 v->vh_dhost = 0; /* multicast destination address */ 199 v->vh_shost = 0; /* will be overwritten with ours */ 200 v->vh_version = RING_VERSION; 201 v->vh_type = RING_WHOAMI; 202 v->vh_info = 0; 203 204 /* 205 * Reset interface, establish Digital Loopback Mode, and 206 * send the multicast (to myself) with Input Copy enabled. 207 */ 208 retry: 209 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 210 addr->vvicsr = VV_RST; 211 addr->vviba = (u_short) ubainfo; 212 addr->vviea = (u_short) (ubainfo >> 16); 213 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 214 addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; 215 /* map xmit message into uba if not already there */ 216 if (!retrying) 217 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 218 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 219 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 220 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 221 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 222 addr->vvoba = (u_short) ubainfo; 223 addr->vvoea = (u_short) (ubainfo >> 16); 224 addr->vvowc = -((vs->vs_olen + 1) >> 1); 225 addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 226 227 /* 228 * Wait for receive side to finish. 229 * Extract source address (which will our own), 230 * and post to interface structure. 231 */ 232 DELAY(1000); 233 for (waitcount = 0; ((addr->vvicsr) & VV_RDY) == 0; waitcount++) { 234 if (waitcount < 10) 235 DELAY(1000); 236 else { 237 if (attempts++ < 10)s 238 goto retry; 239 else { 240 printf("vv%d: can't initialize\n", unit); 241 printf("vvinit loopwait: icsr = %b\n", 242 0xffff&(addr->vvicsr),VV_IBITS); 243 return; 244 } 245 } 246 } 247 248 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 249 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 250 if (vs->vs_ifuba.ifu_xtofree) 251 m_freem(vs->vs_ifuba.ifu_xtofree); 252 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 253 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 254 m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); 255 if (m) 256 m_freem(m); 257 /* 258 * check message type before we believe the source host address 259 */ 260 v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 261 if (v->vh_type == RING_WHOAMI) 262 vs->vs_if.if_host[0] = v->vh_shost; 263 else 264 goto top; 265 #else 266 vs->vs_if.if_host[0] = 24; 267 #endif 268 269 printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]); 270 sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 271 sin->sin_family = AF_INET; 272 sin->sin_addr = 273 if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 274 275 /* 276 * Reset the interface, and join the ring 277 */ 278 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 279 addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */ 280 sleep((caddr_t)&lbolt, PZERO); /* let contacts settle */ 281 vs->vs_init = 0; 282 vs->vs_flush = 0; 283 vs->vs_nottaken = 0; 284 285 /* 286 * Hang a receive and start any 287 * pending writes by faking a transmit complete. 288 */ 289 s = splimp(); 290 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 291 addr->vviba = (u_short) ubainfo; 292 addr->vviea = (u_short) (ubainfo >> 16); 293 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 294 addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; 295 vs->vs_oactive = 1; 296 vvxint(unit); 297 splx(s); 298 if_rtinit(&vs->vs_if, RTF_DIRECT|RTF_UP); 299 } 300 301 /* 302 * Start or restart output on interface. 303 * If interface is not already active, get another datagram 304 * to send off of the interface queue, and map it to the interface 305 * before starting the output. 306 */ 307 vvstart(dev) 308 dev_t dev; 309 { 310 int unit = VVUNIT(dev); 311 struct uba_device *ui = vvinfo[unit]; 312 register struct vv_softc *vs = &vv_softc[unit]; 313 register struct vvreg *addr; 314 struct mbuf *m; 315 int ubainfo; 316 int dest; 317 COUNT(VVSTART); 318 319 if (vs->vs_oactive) 320 goto restart; 321 322 /* 323 * Not already active: dequeue another request 324 * and map it to the UNIBUS. If no more requests, 325 * just return. 326 */ 327 IF_DEQUEUE(&vs->vs_if.if_snd, m); 328 if (m == 0) { 329 vs->vs_oactive = 0; 330 return; 331 } 332 dest = mtod(m, struct vv_header *)->vh_dhost; 333 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 334 vs->vs_lastx = dest; 335 336 restart: 337 /* 338 * Have request mapped to UNIBUS for transmission. 339 * Purge any stale data from this BDP, and start the otput. 340 */ 341 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 342 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 343 addr = (struct vvreg *)ui->ui_addr; 344 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 345 addr->vvoba = (u_short) ubainfo; 346 addr->vvoea = (u_short) (ubainfo >> 16); 347 addr->vvowc = -((vs->vs_olen + 1) >> 1); 348 addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 349 vs->vs_oactive = 1; 350 } 351 352 /* 353 * VVLNI transmit interrupt 354 * Start another output if more data to send. 355 */ 356 vvxint(unit) 357 int unit; 358 { 359 register struct uba_device *ui = vvinfo[unit]; 360 register struct vv_softc *vs = &vv_softc[unit]; 361 register struct vvreg *addr; 362 register int oc; 363 COUNT(ENXINT); 364 365 addr = (struct vvreg *)ui->ui_addr; 366 oc = 0xffff & (addr->vvocsr); 367 if (vs->vs_oactive == 0) { 368 printf("vv%d: stray interrupt vvocsr = %b\n", unit, 369 oc, VV_OBITS); 370 return; 371 } 372 if (oc & (VV_OPT | VV_RFS)) { 373 if (++(vs->vs_tries) < VVRETRY) { 374 if (oc & VV_OPT) 375 vs->vs_init++; 376 if (oc & VV_RFS) 377 vs->vs_nottaken++; 378 addr->vvocsr = VV_IEN | VV_ENB | VV_INR; 379 return; 380 } 381 if (oc & VV_OPT) 382 printf("vv%d: output timeout\n"); 383 } 384 vs->vs_if.if_opackets++; 385 vs->vs_oactive = 0; 386 vs->vs_tries = 0; 387 if (oc & VVXERR) { 388 vs->vs_if.if_oerrors++; 389 printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 390 VV_OBITS); 391 } 392 if (vs->vs_ifuba.ifu_xtofree) { 393 m_freem(vs->vs_ifuba.ifu_xtofree); 394 vs->vs_ifuba.ifu_xtofree = 0; 395 } 396 if (vs->vs_if.if_snd.ifq_head == 0) { 397 vs->vs_lastx = 0; 398 return; 399 } 400 vvstart(unit); 401 } 402 403 /* 404 * V2lni interface receiver interrupt. 405 * If input error just drop packet. 406 * Otherwise purge input buffered data path and examine 407 * packet to determine type. If can't determine length 408 * from type, then have to drop packet. Othewise decapsulate 409 * packet based on type and pass to type specific higher-level 410 * input routine. 411 */ 412 vvrint(unit) 413 int unit; 414 { 415 register struct vv_softc *vs = &vv_softc[unit]; 416 struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr; 417 register struct vv_header *vv; 418 register struct ifqueue *inq; 419 struct mbuf *m; 420 int ubainfo, len, off; 421 COUNT(VVRINT); 422 423 vs->vs_if.if_ipackets++; 424 /* 425 * Purge BDP; drop if input error indicated. 426 */ 427 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 428 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 429 if (addr->vvicsr & VVRERR) { 430 vs->vs_if.if_ierrors++; 431 printf("vv%d: error vvicsr = %b\n", unit, 432 0xffff&(addr->vvicsr), VV_IBITS); 433 goto setup; 434 } 435 off = 0; 436 len = 0; 437 vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 438 /* 439 * Demultiplex on packet type and deal with oddities of 440 * trailer protocol format 441 */ 442 switch (vv->vh_type) { 443 444 #ifdef INET 445 case RING_IP: 446 len = htons((u_short)((struct ip *) vv)->ip_len); 447 schednetisr(NETISR_IP); 448 inq = &ipintrq; 449 break; 450 #endif 451 default: 452 printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 453 goto setup; 454 } 455 if (len == 0) 456 goto setup; 457 /* 458 * Pull packet off interface. Off is nonzero if packet 459 * has trailing header; if_rubaget will then force this header 460 * information to be at the front, but we still have to drop 461 * the two-byte type which is at the front of any trailer data. 462 */ 463 m = if_rubaget(&vs->vs_ifuba, len, off); 464 if (m == 0) 465 goto setup; 466 IF_ENQUEUE(inq, m); 467 468 setup: 469 /* 470 * Reset for next packet. 471 */ 472 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 473 addr->vviba = (u_short) ubainfo; 474 addr->vviea = (u_short) (ubainfo >> 16); 475 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 476 addr->vvicsr = VV_RST | VV_CONF; 477 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 478 479 } 480 481 /* 482 * V2lni output routine. 483 * Encapsulate a packet of type family for the local net. 484 * Use trailer local net encapsulation if enough data in first 485 * packet leaves a multiple of 512 bytes of data in remainder. 486 */ 487 vvoutput(ifp, m0, dst) 488 struct ifnet *ifp; 489 struct mbuf *m0; 490 struct sockaddr *dst; 491 { 492 register struct mbuf *m = m0; 493 register struct vv_header *vv; 494 int type, dest, s; 495 496 switch (dst->sa_family) { 497 498 #ifdef INET 499 case AF_INET: { 500 register struct ip *ip = mtod(m0, struct ip *); 501 int off; 502 503 dest = ip->ip_dst.s_addr >> 24; 504 type = RING_IP; 505 off = 0; 506 goto gottype; 507 } 508 #endif 509 default: 510 printf("vv%d: can't handle af%d\n", ifp->if_unit, 511 dst->sa_family); 512 m_freem(m0); 513 return (0); 514 } 515 516 gottrailertype: 517 /* 518 * Packet to be sent as trailer: move first packet 519 * (control information) to end of chain. 520 */ 521 while (m->m_next) 522 m = m->m_next; 523 m->m_next = m0; 524 m = m0->m_next; 525 m0->m_next = 0; 526 m0 = m; 527 528 gottype: 529 /* 530 * Add local net header. If no space in first mbuf, 531 * allocate another. 532 */ 533 if (m->m_off > MMAXOFF || 534 MMINOFF + sizeof (struct vv_header) > m->m_off) { 535 m = m_get(M_DONTWAIT); 536 if (m == 0) { 537 m_freem(m0); 538 return (0); 539 } 540 m->m_next = m0; 541 m->m_off = MMINOFF; 542 m->m_len = sizeof (struct vv_header); 543 } else { 544 m->m_off -= sizeof (struct vv_header); 545 m->m_len += sizeof (struct vv_header); 546 } 547 vv = mtod(m, struct vv_header *); 548 vv->vh_shost = ifp->if_host[0]; 549 vv->vh_dhost = dest; 550 vv->vh_version = RING_VERSION; 551 vv->vh_type = type; 552 vv->vh_info = m->m_len; 553 554 /* 555 * Queue message on interface, and start output if interface 556 * not yet active. 557 */ 558 s = splimp(); 559 IF_ENQUEUE(&ifp->if_snd, m); 560 if (vv_softc[ifp->if_unit].vs_oactive == 0) 561 vvstart(ifp->if_unit); 562 splx(s); 563 return (1); 564 } 565 566 #ifdef notdef 567 /* 568 * vvprt_hdr(s, v) print the local net header in "v" 569 * with title is "s" 570 */ 571 vvprt_hdr(s, v) 572 char *s; 573 register struct vv_header *v; 574 { 575 printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 576 s, 577 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 578 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 579 0xffff & (int)(v->vh_info)); 580 } 581 582 /* 583 * print "l" hex bytes starting at "s" 584 */ 585 vvprt_hex(s, l) 586 char *s; 587 int l; 588 { 589 register int i; 590 register int z; 591 592 for (i=0 ; i < l; i++) { 593 z = 0xff & (int)(*(s + i)); 594 printf("%c%c ", 595 "0123456789abcdef"[(z >> 4) & 0x0f], 596 "0123456789abcdef"[z & 0x0f] 597 ); 598 } 599 } 600 #endif 601 602 #if NIMP == 0 && NVV > 0 603 /* 604 * Logical host interface driver. 605 * Allows host to appear as an ARPAnet 606 * logical host. Must also have routing 607 * table entry set up to forward packets 608 * to appropriate geteway on localnet. 609 */ 610 struct ifnet vvlhif; 611 int looutput(); 612 613 /* 614 * Called by localnet interface to allow logical 615 * host interface to "attach". 616 */ 617 vvlhinit(vvifp, addr) 618 struct ifnet *vvifp; 619 int addr; 620 { 621 register struct ifnet *ifp = &vvlhif; 622 register struct sockaddr_in *sin; 623 624 COUNT(VVLHINIT); 625 ifp->if_name = "lh"; 626 ifp->if_mtu = VVMTU; 627 sin = (struct sockaddr_in *)&ifp->if_addr; 628 sin->sin_family = AF_INET; 629 sin->sin_addr.s_addr = addr; 630 ifp->if_net = netpart(sin->sin_addr); 631 ifp->if_flags = IFF_UP; 632 ifp->if_output = looutput; 633 if_attach(ifp); 634 rtinit(&ifp->if_addr, &ifp->if_addr, RTF_DIRECT|RTF_UP|RTF_HOST); 635 } 636 #endif 637