1 /* if_vv.c 4.3 82/06/13 */ 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 return; 175 } 176 addr = (struct vvreg *)ui->ui_addr; 177 178 #ifdef AUTOIDENTIFY 179 /* 180 * Build a multicast message to identify our address 181 */ 182 attempts = 0; /* total attempts, including bad msg type */ 183 top: 184 retrying = 0; /* first time through */ 185 m = m_get(M_DONTWAIT); 186 if (m == 0) 187 panic("vvinit: can't get mbuf"); 188 m->m_next = 0; 189 m->m_off = MMINOFF; 190 m->m_len = sizeof(struct vv_header); 191 192 v = mtod(m, struct vv_header *); 193 v->vh_dhost = 0; /* multicast destination address */ 194 v->vh_shost = 0; /* will be overwritten with ours */ 195 v->vh_version = RING_VERSION; 196 v->vh_type = RING_WHOAMI; 197 v->vh_info = 0; 198 199 /* 200 * Reset interface, establish Digital Loopback Mode, and 201 * send the multicast (to myself) with Input Copy enabled. 202 */ 203 retry: 204 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 205 addr->vvicsr = VV_RST; 206 addr->vviba = (u_short) ubainfo; 207 addr->vviea = (u_short) (ubainfo >> 16); 208 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 209 addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; 210 /* map xmit message into uba if not already there */ 211 if (!retrying) 212 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 213 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 214 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 215 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 216 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 217 addr->vvoba = (u_short) ubainfo; 218 addr->vvoea = (u_short) (ubainfo >> 16); 219 addr->vvowc = -((vs->vs_olen + 1) >> 1); 220 addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 221 222 /* 223 * Wait for receive side to finish. 224 * Extract source address (which will our own), 225 * and post to interface structure. 226 */ 227 DELAY(1000); 228 for (waitcount = 0; ((addr->vvicsr) & VV_RDY) == 0; waitcount++) { 229 if (waitcount < 10) 230 DELAY(1000); 231 else { 232 if (attempts++ < 10)s 233 goto retry; 234 else { 235 printf("vv%d: can't initialize\n", unit); 236 printf("vvinit loopwait: icsr = %b\n", 237 0xffff&(addr->vvicsr),VV_IBITS); 238 return; 239 } 240 } 241 } 242 243 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 244 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 245 if (vs->vs_ifuba.ifu_xtofree) 246 m_freem(vs->vs_ifuba.ifu_xtofree); 247 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 248 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 249 m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); 250 if (m) 251 m_freem(m); 252 /* 253 * check message type before we believe the source host address 254 */ 255 v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 256 if (v->vh_type == RING_WHOAMI) 257 vs->vs_if.if_host[0] = v->vh_shost; 258 else 259 goto top; 260 #else 261 vs->vs_if.if_host[0] = 24; 262 #endif 263 264 printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]); 265 sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 266 sin->sin_family = AF_INET; 267 sin->sin_addr = 268 if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 269 270 /* 271 * Reset the interface, and join the ring 272 */ 273 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 274 addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */ 275 sleep((caddr_t)&lbolt, PZERO); /* let contacts settle */ 276 vs->vs_init = 0; 277 vs->vs_flush = 0; 278 vs->vs_nottaken = 0; 279 280 /* 281 * Hang a receive and start any 282 * pending writes by faking a transmit complete. 283 */ 284 s = splimp(); 285 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 286 addr->vviba = (u_short) ubainfo; 287 addr->vviea = (u_short) (ubainfo >> 16); 288 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 289 addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; 290 vs->vs_oactive = 1; 291 vvxint(unit); 292 splx(s); 293 if_rtinit(&vs->vs_if, RTF_UP); 294 } 295 296 /* 297 * Start or restart output on interface. 298 * If interface is not already active, get another datagram 299 * to send off of the interface queue, and map it to the interface 300 * before starting the output. 301 */ 302 vvstart(dev) 303 dev_t dev; 304 { 305 int unit = VVUNIT(dev); 306 struct uba_device *ui = vvinfo[unit]; 307 register struct vv_softc *vs = &vv_softc[unit]; 308 register struct vvreg *addr; 309 struct mbuf *m; 310 int ubainfo; 311 int dest; 312 COUNT(VVSTART); 313 314 if (vs->vs_oactive) 315 goto restart; 316 317 /* 318 * Not already active: dequeue another request 319 * and map it to the UNIBUS. If no more requests, 320 * just return. 321 */ 322 IF_DEQUEUE(&vs->vs_if.if_snd, m); 323 if (m == 0) { 324 vs->vs_oactive = 0; 325 return; 326 } 327 dest = mtod(m, struct vv_header *)->vh_dhost; 328 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 329 vs->vs_lastx = dest; 330 331 restart: 332 /* 333 * Have request mapped to UNIBUS for transmission. 334 * Purge any stale data from this BDP, and start the otput. 335 */ 336 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 337 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 338 addr = (struct vvreg *)ui->ui_addr; 339 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 340 addr->vvoba = (u_short) ubainfo; 341 addr->vvoea = (u_short) (ubainfo >> 16); 342 addr->vvowc = -((vs->vs_olen + 1) >> 1); 343 addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 344 vs->vs_oactive = 1; 345 } 346 347 /* 348 * VVLNI transmit interrupt 349 * Start another output if more data to send. 350 */ 351 vvxint(unit) 352 int unit; 353 { 354 register struct uba_device *ui = vvinfo[unit]; 355 register struct vv_softc *vs = &vv_softc[unit]; 356 register struct vvreg *addr; 357 register int oc; 358 COUNT(ENXINT); 359 360 addr = (struct vvreg *)ui->ui_addr; 361 oc = 0xffff & (addr->vvocsr); 362 if (vs->vs_oactive == 0) { 363 printf("vv%d: stray interrupt vvocsr = %b\n", unit, 364 oc, VV_OBITS); 365 return; 366 } 367 if (oc & (VV_OPT | VV_RFS)) { 368 if (++(vs->vs_tries) < VVRETRY) { 369 if (oc & VV_OPT) 370 vs->vs_init++; 371 if (oc & VV_RFS) 372 vs->vs_nottaken++; 373 addr->vvocsr = VV_IEN | VV_ENB | VV_INR; 374 return; 375 } 376 if (oc & VV_OPT) 377 printf("vv%d: output timeout\n"); 378 } 379 vs->vs_if.if_opackets++; 380 vs->vs_oactive = 0; 381 vs->vs_tries = 0; 382 if (oc & VVXERR) { 383 vs->vs_if.if_oerrors++; 384 printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 385 VV_OBITS); 386 } 387 if (vs->vs_ifuba.ifu_xtofree) { 388 m_freem(vs->vs_ifuba.ifu_xtofree); 389 vs->vs_ifuba.ifu_xtofree = 0; 390 } 391 if (vs->vs_if.if_snd.ifq_head == 0) { 392 vs->vs_lastx = 0; 393 return; 394 } 395 vvstart(unit); 396 } 397 398 /* 399 * V2lni interface receiver interrupt. 400 * If input error just drop packet. 401 * Otherwise purge input buffered data path and examine 402 * packet to determine type. If can't determine length 403 * from type, then have to drop packet. Othewise decapsulate 404 * packet based on type and pass to type specific higher-level 405 * input routine. 406 */ 407 vvrint(unit) 408 int unit; 409 { 410 register struct vv_softc *vs = &vv_softc[unit]; 411 struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr; 412 register struct vv_header *vv; 413 register struct ifqueue *inq; 414 struct mbuf *m; 415 int ubainfo, len, off; 416 COUNT(VVRINT); 417 418 vs->vs_if.if_ipackets++; 419 /* 420 * Purge BDP; drop if input error indicated. 421 */ 422 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 423 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 424 if (addr->vvicsr & VVRERR) { 425 vs->vs_if.if_ierrors++; 426 printf("vv%d: error vvicsr = %b\n", unit, 427 0xffff&(addr->vvicsr), VV_IBITS); 428 goto setup; 429 } 430 off = 0; 431 len = 0; 432 vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 433 /* 434 * Demultiplex on packet type and deal with oddities of 435 * trailer protocol format 436 */ 437 switch (vv->vh_type) { 438 439 #ifdef INET 440 case RING_IP: 441 len = htons((u_short)((struct ip *) vv)->ip_len); 442 schednetisr(NETISR_IP); 443 inq = &ipintrq; 444 break; 445 #endif 446 default: 447 printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 448 goto setup; 449 } 450 if (len == 0) 451 goto setup; 452 /* 453 * Pull packet off interface. Off is nonzero if packet 454 * has trailing header; if_rubaget will then force this header 455 * information to be at the front, but we still have to drop 456 * the two-byte type which is at the front of any trailer data. 457 */ 458 m = if_rubaget(&vs->vs_ifuba, len, off); 459 if (m == 0) 460 goto setup; 461 IF_ENQUEUE(inq, m); 462 463 setup: 464 /* 465 * Reset for next packet. 466 */ 467 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 468 addr->vviba = (u_short) ubainfo; 469 addr->vviea = (u_short) (ubainfo >> 16); 470 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 471 addr->vvicsr = VV_RST | VV_CONF; 472 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 473 474 } 475 476 /* 477 * V2lni output routine. 478 * Encapsulate a packet of type family for the local net. 479 * Use trailer local net encapsulation if enough data in first 480 * packet leaves a multiple of 512 bytes of data in remainder. 481 */ 482 vvoutput(ifp, m0, dst) 483 struct ifnet *ifp; 484 struct mbuf *m0; 485 struct sockaddr *dst; 486 { 487 register struct mbuf *m = m0; 488 register struct vv_header *vv; 489 int type, dest, s; 490 491 switch (dst->sa_family) { 492 493 #ifdef INET 494 case AF_INET: { 495 register struct ip *ip = mtod(m0, struct ip *); 496 int off; 497 498 dest = ip->ip_dst.s_addr >> 24; 499 type = RING_IP; 500 off = 0; 501 goto gottype; 502 } 503 #endif 504 default: 505 printf("vv%d: can't handle af%d\n", ifp->if_unit, 506 dst->sa_family); 507 m_freem(m0); 508 return (0); 509 } 510 511 gottrailertype: 512 /* 513 * Packet to be sent as trailer: move first packet 514 * (control information) to end of chain. 515 */ 516 while (m->m_next) 517 m = m->m_next; 518 m->m_next = m0; 519 m = m0->m_next; 520 m0->m_next = 0; 521 m0 = m; 522 523 gottype: 524 /* 525 * Add local net header. If no space in first mbuf, 526 * allocate another. 527 */ 528 if (m->m_off > MMAXOFF || 529 MMINOFF + sizeof (struct vv_header) > m->m_off) { 530 m = m_get(M_DONTWAIT); 531 if (m == 0) { 532 m_freem(m0); 533 return (0); 534 } 535 m->m_next = m0; 536 m->m_off = MMINOFF; 537 m->m_len = sizeof (struct vv_header); 538 } else { 539 m->m_off -= sizeof (struct vv_header); 540 m->m_len += sizeof (struct vv_header); 541 } 542 vv = mtod(m, struct vv_header *); 543 vv->vh_shost = ifp->if_host[0]; 544 vv->vh_dhost = dest; 545 vv->vh_version = RING_VERSION; 546 vv->vh_type = type; 547 vv->vh_info = m->m_len; 548 549 /* 550 * Queue message on interface, and start output if interface 551 * not yet active. 552 */ 553 s = splimp(); 554 IF_ENQUEUE(&ifp->if_snd, m); 555 if (vv_softc[ifp->if_unit].vs_oactive == 0) 556 vvstart(ifp->if_unit); 557 splx(s); 558 return (1); 559 } 560 561 #ifdef notdef 562 /* 563 * vvprt_hdr(s, v) print the local net header in "v" 564 * with title is "s" 565 */ 566 vvprt_hdr(s, v) 567 char *s; 568 register struct vv_header *v; 569 { 570 printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 571 s, 572 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 573 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 574 0xffff & (int)(v->vh_info)); 575 } 576 577 /* 578 * print "l" hex bytes starting at "s" 579 */ 580 vvprt_hex(s, l) 581 char *s; 582 int l; 583 { 584 register int i; 585 register int z; 586 587 for (i=0 ; i < l; i++) { 588 z = 0xff & (int)(*(s + i)); 589 printf("%c%c ", 590 "0123456789abcdef"[(z >> 4) & 0x0f], 591 "0123456789abcdef"[z & 0x0f] 592 ); 593 } 594 } 595 #endif 596