1 /* if_il.c 4.19 83/05/18 */ 2 3 #include "il.h" 4 5 /* 6 * Interlan Ethernet Communications Controller interface 7 */ 8 #include "../machine/pte.h" 9 10 #include "../h/param.h" 11 #include "../h/systm.h" 12 #include "../h/mbuf.h" 13 #include "../h/buf.h" 14 #include "../h/protosw.h" 15 #include "../h/socket.h" 16 #include "../h/vmmac.h" 17 #include <errno.h> 18 19 #include "../net/if.h" 20 #include "../net/netisr.h" 21 #include "../net/route.h" 22 #include "../netinet/in.h" 23 #include "../netinet/in_systm.h" 24 #include "../netinet/ip.h" 25 #include "../netinet/ip_var.h" 26 #include "../netinet/if_ether.h" 27 #include "../netpup/pup.h" 28 29 #include "../vax/cpu.h" 30 #include "../vax/mtpr.h" 31 #include "../vaxif/if_il.h" 32 #include "../vaxif/if_ilreg.h" 33 #include "../vaxif/if_uba.h" 34 #include "../vaxuba/ubareg.h" 35 #include "../vaxuba/ubavar.h" 36 37 int ilprobe(), ilattach(), ilrint(), ilcint(); 38 struct uba_device *ilinfo[NIL]; 39 u_short ilstd[] = { 0 }; 40 struct uba_driver ildriver = 41 { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo }; 42 #define ILUNIT(x) minor(x) 43 int ilinit(),iloutput(),ilreset(),ilwatch(); 44 45 /* 46 * Ethernet software status per interface. 47 * 48 * Each interface is referenced by a network interface structure, 49 * is_if, which the routing code uses to locate the interface. 50 * This structure contains the output queue for the interface, its address, ... 51 * We also have, for each interface, a UBA interface structure, which 52 * contains information about the UNIBUS resources held by the interface: 53 * map registers, buffered data paths, etc. Information is cached in this 54 * structure for use by the if_uba.c routines in running the interface 55 * efficiently. 56 */ 57 struct il_softc { 58 struct arpcom is_ac; /* Ethernet common part */ 59 #define is_if is_ac.ac_if /* network-visible interface */ 60 #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ 61 struct ifuba is_ifuba; /* UNIBUS resources */ 62 int is_flags; 63 #define ILF_OACTIVE 0x1 /* output is active */ 64 #define ILF_RCVPENDING 0x2 /* start rcv in ilcint */ 65 #define ILF_STATPENDING 0x4 /* stat cmd pending */ 66 short is_lastcmd; /* can't read csr, so must save it */ 67 short is_scaninterval; /* interval of stat collection */ 68 #define ILWATCHINTERVAL 60 /* once every 60 seconds */ 69 struct il_stats is_stats; /* holds on-board statistics */ 70 struct il_stats is_sum; /* summation over time */ 71 int is_ubaddr; /* mapping registers of is_stats */ 72 } il_softc[NIL]; 73 74 ilprobe(reg) 75 caddr_t reg; 76 { 77 register int br, cvec; /* r11, r10 value-result */ 78 register struct ildevice *addr = (struct ildevice *)reg; 79 register i; 80 81 #ifdef lint 82 br = 0; cvec = br; br = cvec; 83 i = 0; ilrint(i); ilcint(i); ilwatch(i); 84 #endif 85 86 addr->il_csr = ILC_OFFLINE|IL_CIE; 87 DELAY(100000); 88 i = addr->il_csr; /* clear CDONE */ 89 if (cvec > 0 && cvec != 0x200) 90 cvec -= 4; 91 return (1); 92 } 93 94 /* 95 * Interface exists: make available by filling in network interface 96 * record. System will initialize the interface when it is ready 97 * to accept packets. A STATUS command is done to get the ethernet 98 * address and other interesting data. 99 */ 100 ilattach(ui) 101 struct uba_device *ui; 102 { 103 register struct il_softc *is = &il_softc[ui->ui_unit]; 104 register struct ifnet *ifp = &is->is_if; 105 register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 106 struct sockaddr_in *sin; 107 108 ifp->if_unit = ui->ui_unit; 109 ifp->if_name = "il"; 110 ifp->if_mtu = ETHERMTU; 111 112 /* 113 * Reset the board and map the statistics 114 * buffer onto the Unibus. 115 */ 116 addr->il_csr = ILC_RESET; 117 while ((addr->il_csr&IL_CDONE) == 0) 118 ; 119 if (addr->il_csr&IL_STATUS) 120 printf("il%d: reset failed, csr=%b\n", ui->ui_unit, 121 addr->il_csr, IL_BITS); 122 123 is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats, 124 sizeof (struct il_stats), 0); 125 addr->il_bar = is->is_ubaddr & 0xffff; 126 addr->il_bcr = sizeof (struct il_stats); 127 addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT; 128 while ((addr->il_csr&IL_CDONE) == 0) 129 ; 130 if (addr->il_csr&IL_STATUS) 131 printf("il%d: status failed, csr=%b\n", ui->ui_unit, 132 addr->il_csr, IL_BITS); 133 ubarelse(ui->ui_ubanum, &is->is_ubaddr); 134 #ifdef notdef 135 printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n", 136 ui->ui_unit, 137 is->is_stats.ils_addr[0]&0xff, is->is_stats.ils_addr[1]&0xff, 138 is->is_stats.ils_addr[2]&0xff, is->is_stats.ils_addr[3]&0xff, 139 is->is_stats.ils_addr[4]&0xff, is->is_stats.ils_addr[5]&0xff, 140 is->is_stats.ils_module, is->is_stats.ils_firmware); 141 #endif 142 bcopy(is->is_stats.ils_addr, is->is_addr, sizeof (is->is_addr)); 143 sin = (struct sockaddr_in *)&ifp->if_addr; 144 sin->sin_family = AF_INET; 145 if (ui->ui_flags) { 146 int i = ((is->is_addr[3]&0xff)<<16) | 147 ((is->is_addr[4]&0xff)<<8) | 148 (is->is_addr[5]&0xff); 149 sin->sin_addr = if_makeaddr(ui->ui_flags, i); 150 } else 151 sin->sin_addr = arpmyaddr(); 152 153 ifp->if_init = ilinit; 154 ifp->if_output = iloutput; 155 ifp->if_reset = ilreset; 156 ifp->if_watchdog = ilwatch; 157 is->is_scaninterval = ILWATCHINTERVAL; 158 ifp->if_timer = is->is_scaninterval; 159 is->is_ifuba.ifu_flags = UBA_CANTWAIT; 160 #ifdef notdef 161 is->is_ifuba.ifu_flags |= UBA_NEEDBDP; 162 #endif 163 if_attach(ifp); 164 } 165 166 /* 167 * Reset of interface after UNIBUS reset. 168 * If interface is on specified uba, reset its state. 169 */ 170 ilreset(unit, uban) 171 int unit, uban; 172 { 173 register struct uba_device *ui; 174 175 if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 || 176 ui->ui_ubanum != uban) 177 return; 178 printf(" il%d", unit); 179 ilinit(unit); 180 } 181 182 /* 183 * Initialization of interface; clear recorded pending 184 * operations, and reinitialize UNIBUS usage. 185 */ 186 ilinit(unit) 187 int unit; 188 { 189 register struct il_softc *is = &il_softc[unit]; 190 register struct uba_device *ui = ilinfo[unit]; 191 register struct ildevice *addr; 192 int s; 193 register struct ifnet *ifp = &is->is_if; 194 register struct sockaddr_in *sin, *sinb; 195 196 sin = (struct sockaddr_in *)&ifp->if_addr; 197 if (sin->sin_addr.s_addr == 0) /* if address still unknown */ 198 return; 199 ifp->if_net = in_netof(sin->sin_addr); 200 ifp->if_host[0] = in_lnaof(sin->sin_addr); 201 sinb = (struct sockaddr_in *)&ifp->if_broadaddr; 202 sinb->sin_family = AF_INET; 203 sinb->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 204 ifp->if_flags = IFF_BROADCAST; 205 206 if (if_ubainit(&is->is_ifuba, ui->ui_ubanum, 207 sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) { 208 printf("il%d: can't initialize\n", unit); 209 is->is_if.if_flags &= ~IFF_UP; 210 return; 211 } 212 is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats, 213 sizeof (struct il_stats), 0); 214 addr = (struct ildevice *)ui->ui_addr; 215 216 /* 217 * Turn off source address insertion (it's faster this way), 218 * and set board online. Former doesn't work if board is 219 * already online (happens on ubareset), so we put it offline 220 * first. 221 */ 222 s = splimp(); 223 addr->il_csr = ILC_OFFLINE; 224 while ((addr->il_csr & IL_CDONE) == 0) 225 ; 226 addr->il_csr = ILC_CISA; 227 while ((addr->il_csr & IL_CDONE) == 0) 228 ; 229 /* 230 * Set board online. 231 * Hang receive buffer and start any pending 232 * writes by faking a transmit complete. 233 * Receive bcr is not a muliple of 4 so buffer 234 * chaining can't happen. 235 */ 236 addr->il_csr = ILC_ONLINE; 237 while ((addr->il_csr & IL_CDONE) == 0) 238 ; 239 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 240 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 241 addr->il_csr = 242 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 243 while ((addr->il_csr & IL_CDONE) == 0) 244 ; 245 is->is_flags = ILF_OACTIVE; 246 is->is_if.if_flags |= IFF_UP; 247 is->is_lastcmd = 0; 248 ilcint(unit); 249 splx(s); 250 if_rtinit(&is->is_if, RTF_UP); 251 arpattach(&is->is_ac); 252 arpwhohas(&is->is_ac, &sin->sin_addr); 253 } 254 255 /* 256 * Start output on interface. 257 * Get another datagram to send off of the interface queue, 258 * and map it to the interface before starting the output. 259 */ 260 ilstart(dev) 261 dev_t dev; 262 { 263 int unit = ILUNIT(dev), len; 264 struct uba_device *ui = ilinfo[unit]; 265 register struct il_softc *is = &il_softc[unit]; 266 register struct ildevice *addr; 267 struct mbuf *m; 268 short csr; 269 270 IF_DEQUEUE(&is->is_if.if_snd, m); 271 addr = (struct ildevice *)ui->ui_addr; 272 if (m == 0) { 273 if ((is->is_flags & ILF_STATPENDING) == 0) 274 return; 275 addr->il_bar = is->is_ubaddr & 0xffff; 276 addr->il_bcr = sizeof (struct il_stats); 277 csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE; 278 is->is_flags &= ~ILF_STATPENDING; 279 goto startcmd; 280 } 281 len = if_wubaput(&is->is_ifuba, m); 282 /* 283 * Ensure minimum packet length. 284 * This makes the safe assumtion that there are no virtual holes 285 * after the data. 286 * For security, it might be wise to zero out the added bytes, 287 * but we're mainly interested in speed at the moment. 288 */ 289 if (len - sizeof(struct ether_header) < ETHERMIN) 290 len = ETHERMIN + sizeof(struct ether_header); 291 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 292 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp); 293 addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff; 294 addr->il_bcr = len; 295 csr = 296 ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE; 297 298 startcmd: 299 is->is_lastcmd = csr & IL_CMD; 300 addr->il_csr = csr; 301 is->is_flags |= ILF_OACTIVE; 302 } 303 304 /* 305 * Command done interrupt. 306 */ 307 ilcint(unit) 308 int unit; 309 { 310 register struct il_softc *is = &il_softc[unit]; 311 struct uba_device *ui = ilinfo[unit]; 312 register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 313 short csr; 314 315 if ((is->is_flags & ILF_OACTIVE) == 0) { 316 printf("il%d: stray xmit interrupt, csr=%b\n", unit, 317 addr->il_csr, IL_BITS); 318 return; 319 } 320 321 csr = addr->il_csr; 322 /* 323 * Hang receive buffer if it couldn't 324 * be done earlier (in ilrint). 325 */ 326 if (is->is_flags & ILF_RCVPENDING) { 327 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 328 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 329 addr->il_csr = 330 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 331 while ((addr->il_csr & IL_CDONE) == 0) 332 ; 333 is->is_flags &= ~ILF_RCVPENDING; 334 } 335 is->is_flags &= ~ILF_OACTIVE; 336 csr &= IL_STATUS; 337 switch (is->is_lastcmd) { 338 339 case ILC_XMIT: 340 is->is_if.if_opackets++; 341 if (csr > ILERR_RETRIES) 342 is->is_if.if_oerrors++; 343 break; 344 345 case ILC_STAT: 346 if (csr == ILERR_SUCCESS) 347 iltotal(is); 348 break; 349 } 350 if (is->is_ifuba.ifu_xtofree) { 351 m_freem(is->is_ifuba.ifu_xtofree); 352 is->is_ifuba.ifu_xtofree = 0; 353 } 354 ilstart(unit); 355 } 356 357 /* 358 * Ethernet interface receiver interrupt. 359 * If input error just drop packet. 360 * Otherwise purge input buffered data path and examine 361 * packet to determine type. If can't determine length 362 * from type, then have to drop packet. Othewise decapsulate 363 * packet based on type and pass to type specific higher-level 364 * input routine. 365 */ 366 ilrint(unit) 367 int unit; 368 { 369 register struct il_softc *is = &il_softc[unit]; 370 struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr; 371 register struct il_rheader *il; 372 struct mbuf *m; 373 int len, off, resid; 374 register struct ifqueue *inq; 375 376 is->is_if.if_ipackets++; 377 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 378 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp); 379 il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr); 380 len = il->ilr_length - sizeof(struct il_rheader); 381 if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 || 382 len > ETHERMTU) { 383 is->is_if.if_ierrors++; 384 #ifdef notdef 385 if (is->is_if.if_ierrors % 100 == 0) 386 printf("il%d: += 100 input errors\n", unit); 387 #endif 388 goto setup; 389 } 390 391 /* 392 * Deal with trailer protocol: if type is PUP trailer 393 * get true type from first 16-bit word past data. 394 * Remember that type was trailer by setting off. 395 */ 396 il->ilr_type = ntohs((u_short)il->ilr_type); 397 #define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) 398 if (il->ilr_type >= ETHERPUP_TRAIL && 399 il->ilr_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) { 400 off = (il->ilr_type - ETHERPUP_TRAIL) * 512; 401 if (off >= ETHERMTU) 402 goto setup; /* sanity */ 403 il->ilr_type = ntohs(*ildataaddr(il, off, u_short *)); 404 resid = ntohs(*(ildataaddr(il, off+2, u_short *))); 405 if (off + resid > len) 406 goto setup; /* sanity */ 407 len = off + resid; 408 } else 409 off = 0; 410 if (len == 0) 411 goto setup; 412 413 /* 414 * Pull packet off interface. Off is nonzero if packet 415 * has trailing header; ilget will then force this header 416 * information to be at the front, but we still have to drop 417 * the type and length which are at the front of any trailer data. 418 */ 419 m = if_rubaget(&is->is_ifuba, len, off); 420 if (m == 0) 421 goto setup; 422 if (off) { 423 m->m_off += 2 * sizeof (u_short); 424 m->m_len -= 2 * sizeof (u_short); 425 } 426 switch (il->ilr_type) { 427 428 #ifdef INET 429 case ETHERPUP_IPTYPE: 430 schednetisr(NETISR_IP); 431 inq = &ipintrq; 432 break; 433 434 case ETHERPUP_ARPTYPE: 435 arpinput(&is->is_ac, m); 436 return; 437 #endif 438 default: 439 m_freem(m); 440 goto setup; 441 } 442 443 if (IF_QFULL(inq)) { 444 IF_DROP(inq); 445 m_freem(m); 446 goto setup; 447 } 448 IF_ENQUEUE(inq, m); 449 450 setup: 451 /* 452 * Reset for next packet if possible. 453 * If waiting for transmit command completion, set flag 454 * and wait until command completes. 455 */ 456 if (is->is_flags & ILF_OACTIVE) { 457 is->is_flags |= ILF_RCVPENDING; 458 return; 459 } 460 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 461 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 462 addr->il_csr = 463 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 464 while ((addr->il_csr & IL_CDONE) == 0) 465 ; 466 } 467 468 /* 469 * Ethernet output routine. 470 * Encapsulate a packet of type family for the local net. 471 * Use trailer local net encapsulation if enough data in first 472 * packet leaves a multiple of 512 bytes of data in remainder. 473 */ 474 iloutput(ifp, m0, dst) 475 struct ifnet *ifp; 476 struct mbuf *m0; 477 struct sockaddr *dst; 478 { 479 int type, s, error; 480 u_char edst[6]; 481 struct in_addr idst; 482 register struct il_softc *is = &il_softc[ifp->if_unit]; 483 register struct mbuf *m = m0; 484 register struct ether_header *il; 485 register int off; 486 487 switch (dst->sa_family) { 488 489 #ifdef INET 490 case AF_INET: 491 idst = ((struct sockaddr_in *)dst)->sin_addr; 492 if (!arpresolve(&is->is_ac, m, &idst, edst)) 493 return (0); /* if not yet resolved */ 494 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 495 if (off > 0 && (off & 0x1ff) == 0 && 496 m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 497 type = ETHERPUP_TRAIL + (off>>9); 498 m->m_off -= 2 * sizeof (u_short); 499 m->m_len += 2 * sizeof (u_short); 500 *mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE); 501 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 502 goto gottrailertype; 503 } 504 type = ETHERPUP_IPTYPE; 505 off = 0; 506 goto gottype; 507 #endif 508 509 case AF_UNSPEC: 510 il = (struct ether_header *)dst->sa_data; 511 bcopy(il->ether_dhost, edst, sizeof (edst)); 512 type = il->ether_type; 513 goto gottype; 514 515 default: 516 printf("il%d: can't handle af%d\n", ifp->if_unit, 517 dst->sa_family); 518 error = EAFNOSUPPORT; 519 goto bad; 520 } 521 522 gottrailertype: 523 /* 524 * Packet to be sent as trailer: move first packet 525 * (control information) to end of chain. 526 */ 527 while (m->m_next) 528 m = m->m_next; 529 m->m_next = m0; 530 m = m0->m_next; 531 m0->m_next = 0; 532 m0 = m; 533 534 gottype: 535 /* 536 * Add local net header. If no space in first mbuf, 537 * allocate another. 538 */ 539 if (m->m_off > MMAXOFF || 540 MMINOFF + sizeof (struct ether_header) > m->m_off) { 541 m = m_get(M_DONTWAIT, MT_HEADER); 542 if (m == 0) { 543 error = ENOBUFS; 544 goto bad; 545 } 546 m->m_next = m0; 547 m->m_off = MMINOFF; 548 m->m_len = sizeof (struct ether_header); 549 } else { 550 m->m_off -= sizeof (struct ether_header); 551 m->m_len += sizeof (struct ether_header); 552 } 553 il = mtod(m, struct ether_header *); 554 il->ether_type = htons((u_short)type); 555 bcopy(edst, il->ether_dhost, sizeof (edst)); 556 bcopy((caddr_t)is->is_addr, (caddr_t)il->ether_shost, 6); 557 558 /* 559 * Queue message on interface, and start output if interface 560 * not yet active. 561 */ 562 s = splimp(); 563 if (IF_QFULL(&ifp->if_snd)) { 564 IF_DROP(&ifp->if_snd); 565 splx(s); 566 m_freem(m); 567 return (ENOBUFS); 568 } 569 IF_ENQUEUE(&ifp->if_snd, m); 570 if ((is->is_flags & ILF_OACTIVE) == 0) 571 ilstart(ifp->if_unit); 572 splx(s); 573 return (0); 574 575 bad: 576 m_freem(m0); 577 return (error); 578 } 579 580 /* 581 * Watchdog routine, request statistics from board. 582 */ 583 ilwatch(unit) 584 int unit; 585 { 586 register struct il_softc *is = &il_softc[unit]; 587 register struct ifnet *ifp = &is->is_if; 588 int s; 589 590 if (is->is_flags & ILF_STATPENDING) { 591 ifp->if_timer = is->is_scaninterval; 592 return; 593 } 594 s = splimp(); 595 is->is_flags |= ILF_STATPENDING; 596 if ((is->is_flags & ILF_OACTIVE) == 0) 597 ilstart(ifp->if_unit); 598 splx(s); 599 ifp->if_timer = is->is_scaninterval; 600 } 601 602 /* 603 * Total up the on-board statistics. 604 */ 605 iltotal(is) 606 register struct il_softc *is; 607 { 608 register u_short *interval, *sum, *end; 609 610 interval = &is->is_stats.ils_frames; 611 sum = &is->is_sum.ils_frames; 612 end = is->is_sum.ils_fill2; 613 while (sum < end) 614 *sum++ += *interval++; 615 is->is_if.if_collisions = is->is_sum.ils_collis; 616 } 617