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