1 /* if_vv.c 4.5 82/06/20 */ 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 116 vs->vs_if.if_unit = ui->ui_unit; 117 vs->vs_if.if_name = "vv"; 118 vs->vs_if.if_mtu = VVMTU; 119 vs->vs_if.if_net = ui->ui_flags; 120 vs->vs_if.if_host[0] = 0; /* this will be reset in vvinit() */ 121 122 sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 123 sin->sin_family = AF_INET; 124 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 125 126 sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr; 127 sin->sin_family = AF_INET; 128 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST); 129 vs->vs_if.if_flags = IFF_BROADCAST; 130 131 vs->vs_if.if_init = vvinit; 132 vs->vs_if.if_output = vvoutput; 133 vs->vs_if.if_ubareset = vvreset; 134 vs->vs_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16; 135 if_attach(&vs->vs_if); 136 } 137 138 /* 139 * Reset of interface after UNIBUS reset. 140 * If interface is on specified uba, reset its state. 141 */ 142 vvreset(unit, uban) 143 int unit, uban; 144 { 145 register struct uba_device *ui; 146 147 if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 148 ui->ui_ubanum != uban) 149 return; 150 printf(" vv%d", unit); 151 vvinit(unit); 152 } 153 154 /* 155 * Initialization of interface; clear recorded pending 156 * operations, and reinitialize UNIBUS usage. 157 */ 158 vvinit(unit) 159 int unit; 160 { 161 register struct vv_softc *vs = &vv_softc[unit]; 162 register struct uba_device *ui = vvinfo[unit]; 163 register struct vvreg *addr; 164 struct sockaddr_in *sin; 165 struct mbuf *m; 166 struct vv_header *v; 167 int ubainfo, retrying, attempts, waitcount, s; 168 169 if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 170 sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 171 printf("vv%d: can't initialize\n", unit); 172 vs->vs_ifuba.if_flags &= ~IFF_UP; 173 return; 174 } 175 addr = (struct vvreg *)ui->ui_addr; 176 177 #ifdef AUTOIDENTIFY 178 /* 179 * Build a multicast message to identify our address 180 */ 181 attempts = 0; /* total attempts, including bad msg type */ 182 top: 183 retrying = 0; /* first time through */ 184 m = m_get(M_DONTWAIT); 185 if (m == 0) 186 panic("vvinit: can't get mbuf"); 187 m->m_next = 0; 188 m->m_off = MMINOFF; 189 m->m_len = sizeof(struct vv_header); 190 191 v = mtod(m, struct vv_header *); 192 v->vh_dhost = 0; /* multicast destination address */ 193 v->vh_shost = 0; /* will be overwritten with ours */ 194 v->vh_version = RING_VERSION; 195 v->vh_type = RING_WHOAMI; 196 v->vh_info = 0; 197 198 /* 199 * Reset interface, establish Digital Loopback Mode, and 200 * send the multicast (to myself) with Input Copy enabled. 201 */ 202 retry: 203 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 204 addr->vvicsr = VV_RST; 205 addr->vviba = (u_short) ubainfo; 206 addr->vviea = (u_short) (ubainfo >> 16); 207 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 208 addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; 209 /* map xmit message into uba if not already there */ 210 if (!retrying) 211 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 212 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 213 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 214 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 215 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 216 addr->vvoba = (u_short) ubainfo; 217 addr->vvoea = (u_short) (ubainfo >> 16); 218 addr->vvowc = -((vs->vs_olen + 1) >> 1); 219 addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 220 221 /* 222 * Wait for receive side to finish. 223 * Extract source address (which will our own), 224 * and post to interface structure. 225 */ 226 DELAY(1000); 227 for (waitcount = 0; ((addr->vvicsr) & VV_RDY) == 0; waitcount++) { 228 if (waitcount < 10) 229 DELAY(1000); 230 else { 231 if (attempts++ < 10)s 232 goto retry; 233 else { 234 printf("vv%d: can't initialize\n", unit); 235 printf("vvinit loopwait: icsr = %b\n", 236 0xffff&(addr->vvicsr),VV_IBITS); 237 vs->vs_ifuba.if_flags &= ~IFF_UP; 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 vs->vs_ifuba.if_flags |= IFF_UP; 292 vvxint(unit); 293 splx(s); 294 if_rtinit(&vs->vs_if, RTF_UP); 295 } 296 297 /* 298 * Start or restart output on interface. 299 * If interface is not already active, get another datagram 300 * to send off of the interface queue, and map it to the interface 301 * before starting the output. 302 */ 303 vvstart(dev) 304 dev_t dev; 305 { 306 int unit = VVUNIT(dev); 307 struct uba_device *ui = vvinfo[unit]; 308 register struct vv_softc *vs = &vv_softc[unit]; 309 register struct vvreg *addr; 310 struct mbuf *m; 311 int ubainfo; 312 int dest; 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 359 addr = (struct vvreg *)ui->ui_addr; 360 oc = 0xffff & (addr->vvocsr); 361 if (vs->vs_oactive == 0) { 362 printf("vv%d: stray interrupt vvocsr = %b\n", unit, 363 oc, VV_OBITS); 364 return; 365 } 366 if (oc & (VV_OPT | VV_RFS)) { 367 if (++(vs->vs_tries) < VVRETRY) { 368 if (oc & VV_OPT) 369 vs->vs_init++; 370 if (oc & VV_RFS) 371 vs->vs_nottaken++; 372 addr->vvocsr = VV_IEN | VV_ENB | VV_INR; 373 return; 374 } 375 if (oc & VV_OPT) 376 printf("vv%d: output timeout\n"); 377 } 378 vs->vs_if.if_opackets++; 379 vs->vs_oactive = 0; 380 vs->vs_tries = 0; 381 if (oc & VVXERR) { 382 vs->vs_if.if_oerrors++; 383 printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 384 VV_OBITS); 385 } 386 if (vs->vs_ifuba.ifu_xtofree) { 387 m_freem(vs->vs_ifuba.ifu_xtofree); 388 vs->vs_ifuba.ifu_xtofree = 0; 389 } 390 if (vs->vs_if.if_snd.ifq_head == 0) { 391 vs->vs_lastx = 0; 392 return; 393 } 394 vvstart(unit); 395 } 396 397 /* 398 * V2lni interface receiver interrupt. 399 * If input error just drop packet. 400 * Otherwise purge input buffered data path and examine 401 * packet to determine type. If can't determine length 402 * from type, then have to drop packet. Othewise decapsulate 403 * packet based on type and pass to type specific higher-level 404 * input routine. 405 */ 406 vvrint(unit) 407 int unit; 408 { 409 register struct vv_softc *vs = &vv_softc[unit]; 410 struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr; 411 register struct vv_header *vv; 412 register struct ifqueue *inq; 413 struct mbuf *m; 414 int ubainfo, len, off; 415 416 vs->vs_if.if_ipackets++; 417 /* 418 * Purge BDP; drop if input error indicated. 419 */ 420 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 421 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 422 if (addr->vvicsr & VVRERR) { 423 vs->vs_if.if_ierrors++; 424 printf("vv%d: error vvicsr = %b\n", unit, 425 0xffff&(addr->vvicsr), VV_IBITS); 426 goto setup; 427 } 428 off = 0; 429 len = 0; 430 vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 431 /* 432 * Demultiplex on packet type and deal with oddities of 433 * trailer protocol format 434 */ 435 switch (vv->vh_type) { 436 437 #ifdef INET 438 case RING_IP: 439 len = htons((u_short)((struct ip *) vv)->ip_len); 440 schednetisr(NETISR_IP); 441 inq = &ipintrq; 442 break; 443 #endif 444 default: 445 printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 446 goto setup; 447 } 448 if (len == 0) 449 goto setup; 450 /* 451 * Pull packet off interface. Off is nonzero if packet 452 * has trailing header; if_rubaget will then force this header 453 * information to be at the front, but we still have to drop 454 * the two-byte type which is at the front of any trailer data. 455 */ 456 m = if_rubaget(&vs->vs_ifuba, len, off); 457 if (m == 0) 458 goto setup; 459 IF_ENQUEUE(inq, m); 460 461 setup: 462 /* 463 * Reset for next packet. 464 */ 465 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 466 addr->vviba = (u_short) ubainfo; 467 addr->vviea = (u_short) (ubainfo >> 16); 468 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 469 addr->vvicsr = VV_RST | VV_CONF; 470 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 471 472 } 473 474 /* 475 * V2lni output routine. 476 * Encapsulate a packet of type family for the local net. 477 * Use trailer local net encapsulation if enough data in first 478 * packet leaves a multiple of 512 bytes of data in remainder. 479 */ 480 vvoutput(ifp, m0, dst) 481 struct ifnet *ifp; 482 struct mbuf *m0; 483 struct sockaddr *dst; 484 { 485 register struct mbuf *m = m0; 486 register struct vv_header *vv; 487 int type, dest, s; 488 489 switch (dst->sa_family) { 490 491 #ifdef INET 492 case AF_INET: { 493 register struct ip *ip = mtod(m0, struct ip *); 494 int off; 495 496 dest = ip->ip_dst.s_addr >> 24; 497 type = RING_IP; 498 off = 0; 499 goto gottype; 500 } 501 #endif 502 default: 503 printf("vv%d: can't handle af%d\n", ifp->if_unit, 504 dst->sa_family); 505 m_freem(m0); 506 return (0); 507 } 508 509 gottrailertype: 510 /* 511 * Packet to be sent as trailer: move first packet 512 * (control information) to end of chain. 513 */ 514 while (m->m_next) 515 m = m->m_next; 516 m->m_next = m0; 517 m = m0->m_next; 518 m0->m_next = 0; 519 m0 = m; 520 521 gottype: 522 /* 523 * Add local net header. If no space in first mbuf, 524 * allocate another. 525 */ 526 if (m->m_off > MMAXOFF || 527 MMINOFF + sizeof (struct vv_header) > m->m_off) { 528 m = m_get(M_DONTWAIT); 529 if (m == 0) { 530 m_freem(m0); 531 return (0); 532 } 533 m->m_next = m0; 534 m->m_off = MMINOFF; 535 m->m_len = sizeof (struct vv_header); 536 } else { 537 m->m_off -= sizeof (struct vv_header); 538 m->m_len += sizeof (struct vv_header); 539 } 540 vv = mtod(m, struct vv_header *); 541 vv->vh_shost = ifp->if_host[0]; 542 vv->vh_dhost = dest; 543 vv->vh_version = RING_VERSION; 544 vv->vh_type = type; 545 vv->vh_info = m->m_len; 546 547 /* 548 * Queue message on interface, and start output if interface 549 * not yet active. 550 */ 551 s = splimp(); 552 IF_ENQUEUE(&ifp->if_snd, m); 553 if (vv_softc[ifp->if_unit].vs_oactive == 0) 554 vvstart(ifp->if_unit); 555 splx(s); 556 return (1); 557 } 558 559 #ifdef notdef 560 /* 561 * vvprt_hdr(s, v) print the local net header in "v" 562 * with title is "s" 563 */ 564 vvprt_hdr(s, v) 565 char *s; 566 register struct vv_header *v; 567 { 568 printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 569 s, 570 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 571 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 572 0xffff & (int)(v->vh_info)); 573 } 574 575 /* 576 * print "l" hex bytes starting at "s" 577 */ 578 vvprt_hex(s, l) 579 char *s; 580 int l; 581 { 582 register int i; 583 register int z; 584 585 for (i=0 ; i < l; i++) { 586 z = 0xff & (int)(*(s + i)); 587 printf("%c%c ", 588 "0123456789abcdef"[(z >> 4) & 0x0f], 589 "0123456789abcdef"[z & 0x0f] 590 ); 591 } 592 } 593 #endif 594