1 /* if_il.c 4.2 82/05/24 */ 2 3 #include "il.h" 4 #include "imp.h" 5 #include "loop.h" 6 7 /* 8 * Interlan Ethernet Communications Controller interface 9 */ 10 11 #include "../h/param.h" 12 #include "../h/systm.h" 13 #include "../h/mbuf.h" 14 #include "../h/pte.h" 15 #include "../h/buf.h" 16 #include "../h/protosw.h" 17 #include "../h/socket.h" 18 #include "../h/ubareg.h" 19 #include "../h/ubavar.h" 20 #include "../h/ilreg.h" 21 #include "../h/cpu.h" 22 #include "../h/mtpr.h" 23 #include "../h/vmmac.h" 24 #include "../net/in.h" 25 #include "../net/in_systm.h" 26 #include "../net/if.h" 27 #include "../net/if_il.h" 28 #include "../net/if_uba.h" 29 #include "../net/ip.h" 30 #include "../net/ip_var.h" 31 #include "../net/pup.h" 32 #include "../net/route.h" 33 #include <errno.h> 34 35 #define ILMTU 1500 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 u_char il_ectop[3] = { 0x02, 0x60, 0x8c }; 43 #define ILUNIT(x) minor(x) 44 45 int ilinit(),iloutput(),ilreset(); 46 47 /* 48 * Ethernet software status per interface. 49 * 50 * Each interface is referenced by a network interface structure, 51 * is_if, which the routing code uses to locate the interface. 52 * This structure contains the output queue for the interface, its address, ... 53 * We also have, for each interface, a UBA interface structure, which 54 * contains information about the UNIBUS resources held by the interface: 55 * map registers, buffered data paths, etc. Information is cached in this 56 * structure for use by the if_uba.c routines in running the interface 57 * efficiently. 58 */ 59 struct il_softc { 60 struct ifnet is_if; /* network-visible interface */ 61 struct ifuba is_ifuba; /* UNIBUS resources */ 62 short is_oactive; /* is output active? */ 63 short is_startrcv; /* hang receive next chance */ 64 u_char is_enaddr[6]; /* board's ethernet address */ 65 } il_softc[NIL]; 66 67 /* 68 * Do an OFFLINE command. This will cause an interrupt for the 69 * autoconfigure stuff. 70 */ 71 ilprobe(reg) 72 caddr_t reg; 73 { 74 register int br, cvec; /* r11, r10 value-result */ 75 register struct ildevice *addr = (struct ildevice *)reg; 76 register i; 77 78 COUNT(ILPROBE); 79 #ifdef lint 80 br = 0; cvec = br; br = cvec; 81 ilrint(0); ilcint(0); 82 #endif 83 84 addr->il_csr = ILC_OFFLINE|IL_CIE; 85 DELAY(100000); 86 i = addr->il_csr; /* Clear CDONE */ 87 if (cvec > 0 && cvec != 0x200) 88 cvec -= 4; 89 return (1); 90 } 91 92 struct il_stat ilbuf; 93 /* 94 * Interface exists: make available by filling in network interface 95 * record. System will initialize the interface when it is ready 96 * to accept packets. A STATUS command is done to get the ethernet 97 * address and other interesting data. 98 */ 99 ilattach(ui) 100 struct uba_device *ui; 101 { 102 register struct il_softc *is = &il_softc[ui->ui_unit]; 103 register struct sockaddr_in *sin; 104 register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 105 register int i; 106 int s; 107 int ubaddr; 108 COUNT(ILATTACH); 109 110 is->is_if.if_unit = ui->ui_unit; 111 is->is_if.if_name = "il"; 112 is->is_if.if_mtu = ILMTU; 113 is->is_if.if_net = ui->ui_flags & 0xff; 114 115 /* 116 * Reset the board 117 */ 118 s = splimp(); 119 addr->il_csr = ((ubaddr>>2)&0xc000)|ILC_RESET; 120 while (!(addr->il_csr & IL_CDONE)) 121 /* Busy wait */; 122 if (addr->il_csr & IL_STATUS) 123 printf("il%d: %s\n", ui->ui_unit, 124 ildiag[addr->il_csr & IL_STATUS]); 125 splx(s); 126 127 /* 128 * Map the status buffer to the Unibus, do the status command, 129 * and unmap the buffer. 130 */ 131 ubaddr = uballoc(ui->ui_ubanum, &ilbuf, sizeof(ilbuf), 0); 132 s = splimp(); 133 addr->il_bar = ubaddr & 0xffff; 134 addr->il_bcr = sizeof(ilbuf); 135 addr->il_csr = ((ubaddr>>2)&0xc000)|ILC_STAT; 136 while (!(addr->il_csr & IL_CDONE)) 137 /* Busy wait */; 138 if (addr->il_csr & IL_STATUS) 139 printf("il%d: %s\n", ui->ui_unit, 140 ilerrs[addr->il_csr & IL_STATUS]); 141 splx(s); 142 ubarelse(ui->ui_ubanum, &ubaddr); 143 /* 144 * Fill in the Ethernet address from the status buffer 145 */ 146 for (i=0; i<6; i++) 147 is->is_enaddr[i] = ilbuf.ils_addr[i]; 148 printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n", 149 ui->ui_unit, 150 is->is_enaddr[0]&0xff, is->is_enaddr[1]&0xff, 151 is->is_enaddr[2]&0xff, is->is_enaddr[3]&0xff, 152 is->is_enaddr[4]&0xff, is->is_enaddr[5]&0xff, 153 ilbuf.ils_module, ilbuf.ils_firmware); 154 is->is_if.if_host[0] = ((is->is_enaddr[3]&0xff)<<16) | 0x800000 | 155 ((is->is_enaddr[4]&0xff)<<8) | (is->is_enaddr[5]&0xff); 156 sin = (struct sockaddr_in *)&is->is_if.if_addr; 157 sin->sin_family = AF_INET; 158 sin->sin_addr = if_makeaddr(is->is_if.if_net, is->is_if.if_host[0]); 159 160 sin = (struct sockaddr_in *)&is->is_if.if_broadaddr; 161 sin->sin_family = AF_INET; 162 sin->sin_addr = if_makeaddr(is->is_if.if_net, 0); 163 is->is_if.if_flags = IFF_BROADCAST; 164 165 is->is_if.if_init = ilinit; 166 is->is_if.if_output = iloutput; 167 is->is_if.if_ubareset = ilreset; 168 is->is_ifuba.ifu_flags = UBA_CANTWAIT; 169 if_attach(&is->is_if); 170 #if NIMP == 0 171 if (ui->ui_flags &~ 0xff) 172 illhinit(&is->is_if, (ui->ui_flags &~ 0xff) | 0x0a); 173 #endif 174 } 175 176 /* 177 * Reset of interface after UNIBUS reset. 178 * If interface is on specified uba, reset its state. 179 */ 180 ilreset(unit, uban) 181 int unit, uban; 182 { 183 register struct uba_device *ui; 184 COUNT(ILRESET); 185 186 if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 || 187 ui->ui_ubanum != uban) 188 return; 189 printf(" il%d", unit); 190 ilinit(unit); 191 } 192 193 /* 194 * Initialization of interface; clear recorded pending 195 * operations, and reinitialize UNIBUS usage. 196 */ 197 ilinit(unit) 198 int unit; 199 { 200 register struct il_softc *is = &il_softc[unit]; 201 register struct uba_device *ui = ilinfo[unit]; 202 register struct ildevice *addr; 203 register i; 204 int s; 205 206 if (if_ubainit(&is->is_ifuba, ui->ui_ubanum, 207 sizeof (struct il_rheader), (int)btoc(ILMTU)) == 0) { 208 printf("il%d: can't initialize\n", unit); 209 is->is_if.if_flags &= ~IFF_UP; 210 return; 211 } 212 addr = (struct ildevice *)ui->ui_addr; 213 214 /* 215 * Set board online. 216 * Hang receive buffer and start any pending 217 * writes by faking a transmit complete. 218 * Receive bcr is not a muliple of 4 so buffer 219 * chaining can't happen. 220 */ 221 s = splimp(); 222 addr->il_csr = ILC_ONLINE; 223 while (!(addr->il_csr & IL_CDONE)) 224 /* Busy wait */; 225 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 226 addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6; 227 addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)| 228 ILC_RCV|IL_RIE; 229 while (!(addr->il_csr & IL_CDONE)) 230 /* Busy wait */; 231 is->is_startrcv = 0; 232 is->is_oactive = 1; 233 is->is_if.if_flags |= IFF_UP; 234 ilcint(unit); 235 splx(s); 236 if_rtinit(&is->is_if, RTF_DIRECT|RTF_UP); 237 } 238 239 /* 240 * Start output on interface. 241 * Get another datagram to send off of the interface queue, 242 * and map it to the interface before starting the output. 243 */ 244 ilstart(dev) 245 dev_t dev; 246 { 247 int unit = ILUNIT(dev); 248 struct uba_device *ui = ilinfo[unit]; 249 register struct il_softc *is = &il_softc[unit]; 250 register struct ildevice *addr; 251 register len; 252 struct mbuf *m; 253 int dest; 254 COUNT(ILSTART); 255 256 /* 257 * Dequeue another request and copy it into the buffer. 258 * If no more requests, just return. 259 */ 260 IF_DEQUEUE(&is->is_if.if_snd, m); 261 if (m == 0) 262 return; 263 len = if_wubaput(&is->is_ifuba, m); 264 265 /* 266 * Flush BDP, then start the output. 267 */ 268 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 269 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp); 270 addr = (struct ildevice *)ui->ui_addr; 271 addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff; 272 addr->il_bcr = len; 273 addr->il_csr = ((is->is_ifuba.ifu_w.ifrw_info>>2)&0xc000)| 274 ILC_XMIT|IL_CIE|IL_RIE; 275 is->is_oactive = 1; 276 } 277 278 /* 279 * Command done interrupt. 280 * This should only happen after a transmit command, 281 * so it is equivalent to a transmit interrupt. 282 * Start another output if more data to send. 283 */ 284 ilcint(unit) 285 int unit; 286 { 287 register struct uba_device *ui = ilinfo[unit]; 288 register struct il_softc *is = &il_softc[unit]; 289 register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 290 register int err; 291 COUNT(ILCINT); 292 293 if (is->is_oactive == 0) { 294 printf("il%d: strange xmit interrupt!\n", unit); 295 return; 296 } 297 is->is_if.if_opackets++; 298 is->is_oactive = 0; 299 if (err = (addr->il_csr & IL_STATUS)){ 300 is->is_if.if_oerrors++; 301 printf("il%d: output error %d\n", unit, err); 302 } 303 /* 304 * Hang receive buffer if it couldn't be done earlier (in ilrint). 305 */ 306 if (is->is_startrcv) { 307 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 308 addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6; 309 addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)| 310 ILC_RCV|IL_RIE; 311 while (!(addr->il_csr & IL_CDONE)) 312 /* Busy wait */; 313 is->is_startrcv = 0; 314 } 315 if (is->is_ifuba.ifu_xtofree) { 316 m_freem(is->is_ifuba.ifu_xtofree); 317 is->is_ifuba.ifu_xtofree = 0; 318 } 319 if (is->is_if.if_snd.ifq_head == 0) { 320 return; 321 } 322 ilstart(unit); 323 } 324 325 /* 326 * Ethernet interface receiver interrupt. 327 * If input error just drop packet. 328 * Otherwise purge input buffered data path and examine 329 * packet to determine type. If can't determine length 330 * from type, then have to drop packet. Othewise decapsulate 331 * packet based on type and pass to type specific higher-level 332 * input routine. 333 */ 334 ilrint(unit) 335 int unit; 336 { 337 register struct il_softc *is = &il_softc[unit]; 338 struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr; 339 register struct il_rheader *il; 340 struct mbuf *m; 341 int len, off, resid; 342 register struct ifqueue *inq; 343 344 COUNT(ILRINT); 345 is->is_if.if_ipackets++; 346 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 347 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp); 348 il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr); 349 len = il->ilr_length - sizeof(struct il_rheader); 350 if (il->ilr_status&0x3 || len < 46 || len > ILMTU) { 351 is->is_if.if_ierrors++; 352 #ifdef notdef 353 if (is->is_if.if_ierrors % 100 == 0) 354 printf("il%d: += 100 input errors\n", unit); 355 #endif 356 printf("il%d: input error (status=%x, len=%d)\n", unit, 357 il->ilr_status, len); 358 goto setup; 359 } 360 361 /* 362 * Deal with trailer protocol: if type is PUP trailer 363 * get true type from first 16-bit word past data. 364 * Remember that type was trailer by setting off. 365 */ 366 #define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) 367 if (il->ilr_type >= ILPUP_TRAIL && 368 il->ilr_type < ILPUP_TRAIL+ILPUP_NTRAILER) { 369 off = (il->ilr_type - ILPUP_TRAIL) * 512; 370 if (off >= ILMTU) 371 goto setup; /* sanity */ 372 il->ilr_type = *ildataaddr(il, off, u_short *); 373 resid = *(ildataaddr(il, off+2, u_short *)); 374 if (off + resid > len) 375 goto setup; /* sanity */ 376 len = off + resid; 377 } else 378 off = 0; 379 if (len == 0) 380 goto setup; 381 382 /* 383 * Pull packet off interface. Off is nonzero if packet 384 * has trailing header; ilget will then force this header 385 * information to be at the front, but we still have to drop 386 * the type and length which are at the front of any trailer data. 387 */ 388 m = if_rubaget(&is->is_ifuba, len, off); 389 if (m == 0) 390 goto setup; 391 if (off) { 392 m->m_off += 2 * sizeof (u_short); 393 m->m_len -= 2 * sizeof (u_short); 394 } 395 switch (il->ilr_type) { 396 397 #ifdef INET 398 case ILPUP_IPTYPE: 399 schednetisr(NETISR_IP); 400 inq = &ipintrq; 401 break; 402 #endif 403 default: 404 m_freem(m); 405 goto setup; 406 } 407 408 if (IF_QFULL(inq)) { 409 IF_DROP(inq); 410 m_freem(m); 411 } else 412 IF_ENQUEUE(inq, m); 413 414 setup: 415 /* 416 * Reset for next packet if possible. 417 * If waiting for transmit command completion, set flag 418 * and wait until command completes. 419 */ 420 if (!is->is_oactive) { 421 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 422 addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6; 423 addr->il_csr = ((is->is_ifuba.ifu_r.ifrw_info>>2)&0xc000)| 424 ILC_RCV|IL_RIE; 425 while (!(addr->il_csr & IL_CDONE)) 426 /* Busy wait */; 427 } else 428 is->is_startrcv = 1; 429 } 430 431 /* 432 * Ethernet output routine. 433 * Encapsulate a packet of type family for the local net. 434 * Use trailer local net encapsulation if enough data in first 435 * packet leaves a multiple of 512 bytes of data in remainder. 436 */ 437 iloutput(ifp, m0, dst) 438 struct ifnet *ifp; 439 struct mbuf *m0; 440 struct sockaddr *dst; 441 { 442 int type, dest, s, error; 443 register struct il_softc *is = &il_softc[ifp->if_unit]; 444 register struct mbuf *m = m0; 445 register struct il_xheader *il; 446 register int off; 447 register int i; 448 449 COUNT(ILOUTPUT); 450 switch (dst->sa_family) { 451 452 #ifdef INET 453 case AF_INET: 454 dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 455 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 456 if (off > 0 && (off & 0x1ff) == 0 && 457 m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 458 type = ILPUP_TRAIL + (off>>9); 459 m->m_off -= 2 * sizeof (u_short); 460 m->m_len += 2 * sizeof (u_short); 461 *mtod(m, u_short *) = ILPUP_IPTYPE; 462 *(mtod(m, u_short *) + 1) = m->m_len; 463 goto gottrailertype; 464 } 465 type = ILPUP_IPTYPE; 466 off = 0; 467 goto gottype; 468 #endif 469 470 default: 471 printf("il%d: can't handle af%d\n", ifp->if_unit, 472 dst->sa_family); 473 error = EAFNOSUPPORT; 474 goto bad; 475 } 476 477 gottrailertype: 478 /* 479 * Packet to be sent as trailer: move first packet 480 * (control information) to end of chain. 481 */ 482 while (m->m_next) 483 m = m->m_next; 484 m->m_next = m0; 485 m = m0->m_next; 486 m0->m_next = 0; 487 m0 = m; 488 489 gottype: 490 /* 491 * Add local net header. If no space in first mbuf, 492 * allocate another. 493 */ 494 if (m->m_off > MMAXOFF || 495 MMINOFF + sizeof (struct il_xheader) > m->m_off) { 496 m = m_get(M_DONTWAIT); 497 if (m == 0) { 498 error = ENOBUFS; 499 goto bad; 500 } 501 m->m_next = m0; 502 m->m_off = MMINOFF; 503 m->m_len = sizeof (struct il_xheader); 504 } else { 505 m->m_off -= sizeof (struct il_xheader); 506 m->m_len += sizeof (struct il_xheader); 507 } 508 il = mtod(m, struct il_xheader *); 509 if ((dest &~ 0xff) == 0) 510 for (i=0; i<6; i++) 511 il->ilx_dhost[i] = 0xff; 512 else { 513 if (dest & 0x8000) { 514 il->ilx_dhost[0] = is->is_enaddr[0]; 515 il->ilx_dhost[1] = is->is_enaddr[1]; 516 il->ilx_dhost[2] = is->is_enaddr[2]; 517 } else { 518 il->ilx_dhost[0] = il_ectop[0]; 519 il->ilx_dhost[1] = il_ectop[1]; 520 il->ilx_dhost[2] = il_ectop[2]; 521 } 522 il->ilx_dhost[3] = (dest>>8) & 0x7f; 523 il->ilx_dhost[4] = (dest>>16) & 0xff; 524 il->ilx_dhost[5] = (dest>>24) & 0xff; 525 } 526 il->ilx_type = type; 527 528 /* 529 * Queue message on interface, and start output if interface 530 * not yet active. 531 */ 532 s = splimp(); 533 if (IF_QFULL(&ifp->if_snd)) { 534 IF_DROP(&ifp->if_snd); 535 error = ENOBUFS; 536 goto qfull; 537 } 538 IF_ENQUEUE(&ifp->if_snd, m); 539 if (is->is_oactive == 0) 540 ilstart(ifp->if_unit); 541 splx(s); 542 return (0); 543 qfull: 544 m0 = m; 545 splx(s); 546 bad: 547 m_freem(m0); 548 return(error); 549 } 550 551 #if NIMP == 0 && NIL > 0 552 /* 553 * Logical host interface driver. 554 * Allows host to appear as an ARPAnet 555 * logical host. Must also have routing 556 * table entry set up to forward packets 557 * to appropriate gateway on localnet. 558 */ 559 560 struct ifnet illhif; 561 int looutput(); 562 563 /* 564 * Called by localnet interface to allow logical 565 * host interface to "attach". Nothing should ever 566 * be sent locally to this interface, it's purpose 567 * is simply to establish the host's arpanet address. 568 */ 569 illhinit(ilifp, addr) 570 struct ifnet *ilifp; 571 int addr; 572 { 573 register struct ifnet *ifp = &illhif; 574 register struct sockaddr_in *sin; 575 576 COUNT(ILLHINIT); 577 ifp->if_name = "lh"; 578 ifp->if_mtu = ILMTU; 579 sin = (struct sockaddr_in *)&ifp->if_addr; 580 sin->sin_family = AF_INET; 581 sin->sin_addr.s_addr = addr; 582 ifp->if_net = sin->sin_addr.s_net; 583 ifp->if_dstaddr = ilifp->if_addr; 584 ifp->if_flags = IFF_UP|IFF_POINTOPOINT; 585 ifp->if_output = looutput; 586 if_attach(ifp); 587 rtinit(&ifp->if_addr, &ifp->if_addr, RTF_UP|RTF_DIRECT); 588 } 589 #endif 590