1 /* if_hy.c 4.3 83/02/21 */ 2 3 #include "hy.h" 4 #if NHY > 0 5 6 /* 7 * Network Systems Copropration Hyperchanel interface 8 * 9 * UNTESTED WITH 4.1C 10 */ 11 #include "../machine/pte.h" 12 13 #include "../h/param.h" 14 #include "../h/systm.h" 15 #include "../h/mbuf.h" 16 #include "../h/buf.h" 17 #include "../h/protosw.h" 18 #include "../h/socket.h" 19 #include "../h/vmmac.h" 20 #include "../h/errno.h" 21 #include "../h/time.h" 22 #include "../h/kernel.h" 23 #include "../h/ioctl.h" 24 25 #include "../net/if.h" 26 #include "../net/netisr.h" 27 #include "../net/route.h" 28 29 #include "../netinet/in.h" 30 #include "../netinet/in_systm.h" 31 #include "../netinet/ip.h" 32 #include "../netinet/ip_var.h" 33 34 #include "../vax/cpu.h" 35 #include "../vax/mtpr.h" 36 37 #include "../vaxuba/ubareg.h" 38 #include "../vaxuba/ubavar.h" 39 40 #include "../vaxif/if_hy.h" 41 #include "../vaxif/if_hyreg.h" 42 #include "../vaxif/if_uba.h" 43 44 #define HYROUTE 45 #define HYELOG 46 #define HYMTU 576 47 48 int hyprobe(), hyattach(), hyinit(), hyoutput(), hyreset(), hywatch(); 49 struct uba_device *hyinfo[NHY]; 50 u_short hystd[] = { 0772410, 0 }; 51 struct uba_driver hydriver = 52 { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo }; 53 54 /* 55 * Hyperchannel software status per interface. 56 * 57 * Each interface is referenced by a network interface structure, 58 * hy_if, which the routing code uses to locate the interface. 59 * This structure contains the output queue for the interface, its address, ... 60 * We also have, for each interface, a UBA interface structure, which 61 * contains information about the UNIBUS resources held by the interface: 62 * map registers, buffered data paths, etc. Information is cached in this 63 * structure for use by the if_uba.c routines in running the interface 64 * efficiently. 65 */ 66 struct hy_softc { 67 struct ifnet hy_if; /* network-visible interface */ 68 struct ifuba hy_ifuba; /* UNIBUS resources */ 69 short hy_flags; /* flags */ 70 short hy_state; /* driver state */ 71 int hy_ilen; /* mp length on input */ 72 int hy_olen; /* packet length on output */ 73 int hy_lastwcr; /* last command's word count */ 74 short hy_savedstate; /* saved for reissue after status */ 75 short hy_savedcmd; /* saved command for reissue */ 76 int hy_savedcount; /* saved byte count for reissue */ 77 int hy_savedaddr; /* saved unibus address for reissue */ 78 int hy_ntime; /* number of timeouts since last cmd */ 79 int hy_retry; /* retry counter */ 80 struct hy_stat hy_stat; /* statistics */ 81 struct hy_status hy_status; /* status */ 82 } hy_softc[NHY]; 83 84 #ifdef HYELOG 85 #define HYE_MAX 0x18 86 u_long hy_elog[(HYE_MAX+1)*4]; 87 #endif 88 89 #ifdef DEBUG 90 #define printL lprintf 91 #define printD if (hy_debug_flag) lprintf 92 int hy_debug_flag = 0; 93 /* 94 * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 95 * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 96 * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 97 * hy_nodebug bit 0x08 set hy_debug_flag on hyouput 98 * hy_nodebug bit 0x10 set hy_debug_flag on hyouput with associated data 99 */ 100 int hy_nodebug = 0x0; 101 #else 102 #define printD hyvoid 103 #endif 104 105 /* 106 * Requests for service (in order by descending priority). 107 */ 108 #define RQ_ENDOP 001 /* end the last adapter function */ 109 #define RQ_REISSUE 002 /* reissue previous cmd after status */ 110 #define RQ_STATUS 004 /* get the status of the adapter */ 111 #define RQ_STATISTICS 010 /* get the statistics of the adapter */ 112 #define RQ_MARKDOWN 020 /* mark this adapter port down */ 113 #define RQ_MARKUP 040 /* mark this interface up */ 114 115 #define RQ_XASSOC 0100 /* associated data to transmit */ 116 117 /* 118 * Driver states. 119 */ 120 #define STARTUP 0 /* initial state (before fully there) */ 121 #define IDLE 1 /* idle state */ 122 #define STATSENT 2 /* status cmd sent to adapter */ 123 #define ENDOPSENT 3 /* end operation cmd sent */ 124 #define RECVSENT 4 /* input message cmd sent */ 125 #define RECVDATASENT 5 /* input data cmd sent */ 126 #define XMITSENT 6 /* transmit message cmd sent */ 127 #define XMITDATASENT 7 /* transmit data cmd sent */ 128 #define WAITING 8 /* waiting for messages */ 129 #define CLEARSENT 9 /* clear wait for message cmd sent */ 130 #define MARKPORT 10 /* mark this host's adapter port down issued */ 131 #define RSTATSENT 11 /* read statistics cmd sent to adapter */ 132 133 #ifdef DEBUG 134 char *hy_state_names[] = { 135 "Startup", 136 "Idle", 137 "Status Sent", 138 "End op Sent", 139 "Recieve Message Proper Sent", 140 "Recieve Data Sent", 141 "Transmit Message Proper Sent", 142 "Transmit Data Sent", 143 "Wait for Message Sent", 144 "Clear Wait for Message Sent", 145 "Mark Port Down Sent", 146 "Read Statistics Sent" 147 }; 148 #endif 149 150 #define SCANINTERVAL 10 /* seconds */ 151 #define MAXINTERVAL 20 /* seconds (max action) */ 152 153 /* 154 * Cause a device interrupt. This code uses a buffer starting at 155 * location zero on the unibus (which is already mapped by the 156 * autoconfigure code in the kernel). 157 */ 158 hyprobe(reg) 159 caddr_t reg; 160 { 161 register int br, cvec; /* r11, r10 value-result */ 162 register struct hydevice *addr = (struct hydevice *) reg; 163 164 #ifdef lint 165 br = 0; cvec = br; br = cvec; 166 hyint(0); 167 #endif 168 /* 169 * request adapter status to a buffer starting at unibus location 0 170 */ 171 addr->hyd_bar = 0; 172 addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 173 addr->hyd_dbuf = HYF_STATUS; 174 #ifdef PI13 175 addr->hyd_csr |= S_GO | S_IE | S_IATTN; 176 #else 177 addr->hyd_csr |= S_GO | S_IE; 178 #endif 179 DELAY(10000); 180 #ifdef PI13 181 addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 182 #endif 183 addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 184 return(1); 185 } 186 187 /* 188 * Interface exists: make available by filling in network interface 189 * record. System will initialize the interface when it is ready 190 * to accept packets. 191 */ 192 hyattach(ui) 193 struct uba_device *ui; 194 { 195 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 196 register struct ifnet *ifp = &is->hy_if; 197 198 ifp->if_unit = ui->ui_unit; 199 ifp->if_name = "hy"; 200 ifp->if_mtu = HYMTU; 201 ifp->if_net = ui->ui_flags; 202 is->hy_state = STARTUP; /* don't allow state transitions yet */ 203 ifp->if_init = hyinit; 204 ifp->if_output = hyoutput; 205 ifp->if_reset = hyreset; 206 ifp->if_watchdog = hywatch; 207 ifp->if_timer = SCANINTERVAL; 208 is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 209 #ifdef notdef 210 is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 211 #endif 212 if_attach(ifp); 213 } 214 215 /* 216 * Reset of interface after UNIBUS reset. 217 * If interface is on specified uba, reset its state. 218 */ 219 hyreset(unit, uban) 220 int unit, uban; 221 { 222 register struct uba_device *ui = hyinfo[unit]; 223 register struct hy_softc *is; 224 225 if (unit >= NHY || ui == 0 || ui->ui_alive == 0 || 226 ui->ui_ubanum != uban) 227 return; 228 printf(" hy%d", unit); 229 hyinit(unit); 230 } 231 232 /* 233 * Initialization of interface; clear recorded pending 234 * operations, and reinitialize UNIBUS usage. 235 */ 236 hyinit(unit) 237 int unit; 238 { 239 register struct hy_softc *is = &hy_softc[unit]; 240 register struct uba_device *ui = hyinfo[unit]; 241 int s; 242 243 if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 244 sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) { 245 #ifdef DEBUG 246 if (hy_nodebug & 4) 247 hy_debug_flag = 1; 248 #endif 249 printf("hy%d: can't initialize\n", unit); 250 is->hy_if.if_flags &= ~IFF_UP; 251 return; 252 } 253 /* 254 * Issue wait for message and start the state machine 255 */ 256 s = splimp(); 257 is->hy_state = IDLE; 258 is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 259 is->hy_retry = 0; 260 hyact(ui); 261 splx(s); 262 } 263 264 /* 265 * Issue a command to the adapter 266 */ 267 hystart(ui, cmd, count, ubaddr) 268 struct uba_device *ui; 269 int cmd, count, ubaddr; 270 { 271 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 272 register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 273 274 #ifdef DEBUG 275 printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 276 ui->ui_unit, cmd, count, ubaddr); 277 printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 278 ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 279 addr->hyd_wcr); 280 #endif 281 if (((is->hy_flags & RQ_REISSUE) == 0) && 282 (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 283 is->hy_savedstate = is->hy_state; 284 is->hy_savedcmd = cmd; 285 is->hy_savedcount = count; 286 is->hy_savedaddr = ubaddr; 287 } 288 addr->hyd_bar = ubaddr & 0xffff; 289 addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 290 addr->hyd_dbuf = cmd; 291 #ifdef PI13 292 addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 293 #else 294 addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 295 #endif 296 #ifdef DEBUG 297 printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 298 ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 299 addr->hyd_wcr); 300 #endif 301 #ifdef HYLOG 302 { 303 struct { 304 u_char hcmd; 305 u_char hstate; 306 short hcount; 307 } hcl; 308 309 hcl.hcmd = cmd; 310 hcl.hstate = is->hy_state; 311 hcl.hcount = count; 312 hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 313 } 314 #endif 315 is->hy_ntime = 0; 316 } 317 318 int hyint_active = 0; /* set during hy interrupt */ 319 /* 320 * Hyperchannel interface interrupt. 321 * 322 * An interrupt can occur for many reasons. Examine the status of 323 * the hyperchannel status bits to determine what to do next. 324 * 325 * If input error just drop packet. 326 * Otherwise purge input buffered data path and examine 327 * packet to determine type. Othewise decapsulate 328 * packet based on type and pass to type specific higher-level 329 * input routine. 330 */ 331 hyint(unit) 332 int unit; 333 { 334 register struct hy_softc *is = &hy_softc[unit]; 335 register struct uba_device *ui = hyinfo[unit]; 336 register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 337 338 if (hyint_active) 339 panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 340 hyint_active++; 341 #ifdef DEBUG 342 printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 343 unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 344 #endif 345 #ifdef HYLOG 346 logit: 347 { 348 struct { 349 u_char hstate; 350 u_char hflags; 351 short hcsr; 352 short hwcr; 353 } hil; 354 hil.hstate = is->hy_state; 355 hil.hflags = is->hy_flags; 356 hil.hcsr = addr->hyd_csr; 357 hil.hwcr = addr->hyd_wcr; 358 hylog(HYL_INT, sizeof(hil), (char *)&hil); 359 } 360 #endif 361 if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 362 /* 363 * Error bit set, some sort of error in the interface. 364 * 365 * The adapter sets attn on command completion so that's not 366 * a real error even though the interface considers it one. 367 */ 368 #ifdef DEBUG 369 if (hy_nodebug & 4) 370 hy_debug_flag = 1; 371 #endif 372 printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 373 addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 374 addr->hyd_wcr); 375 if (addr->hyd_csr & S_NEX) { 376 printf("hy%d: NEX - Non Existant Memory\n", unit); 377 #ifdef PI13 378 addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 379 #else 380 addr->hyd_csr &= ~S_NEX; 381 #endif 382 hycancel(ui); 383 #ifdef PI13 384 } else if (addr->hyd_csr & S_POWEROFF) { 385 printf("hy%d: Power Off bit set, trying to reset\n", 386 unit); 387 addr->hyd_csr |= S_POWEROFF; 388 DELAY(100); 389 if (addr->hyd_csr & S_POWEROFF) { 390 if_down(&is->hy_if); 391 is->hy_state = STARTUP; 392 printf( 393 "hy%d: Power Off Error, network shutdown\n", 394 unit); 395 } 396 #endif 397 } else { 398 printf("hy%d: BAR overflow\n", unit); 399 hycancel(ui); 400 } 401 } else if (HYS_NORMAL(addr)) { 402 /* 403 * Normal interrupt, bump state machine unless in state 404 * waiting and no data present (assumed to be word count 405 * zero interrupt or other hardware botch). 406 */ 407 if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 408 hyact(ui); 409 } else if (HYS_ABNORMAL(addr)) { 410 /* 411 * Abnormal termination. 412 * bump error counts, retry the last function 413 * 'MAXRETRY' times before kicking the bucket. 414 * 415 * Don't reissue the cmd if in certain states, abnormal 416 * on a reissued cmd or max retry exceeded. 417 */ 418 #ifdef HYLOG 419 if (hy_log.hyl_enable != hy_log.hyl_onerr) { 420 hy_log.hyl_enable = hy_log.hyl_onerr; 421 goto logit; 422 } 423 #endif 424 #ifdef DEBUG 425 if (hy_nodebug & 4) 426 hy_debug_flag = 1; 427 printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 428 unit, hy_state_names[is->hy_state], is->hy_state); 429 printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 430 is->hy_flags, is->hy_ilen, is->hy_olen, 431 is->hy_lastwcr, is->hy_retry); 432 printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 433 is->hy_savedstate, is->hy_savedcount, 434 is->hy_savedaddr, is->hy_savedcmd); 435 #endif 436 #ifdef PI13 437 addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 438 #endif 439 if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 440 is->hy_if.if_oerrors++; 441 if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 442 is->hy_if.if_ierrors++; 443 if (is->hy_state == XMITDATASENT || 444 is->hy_state == RECVSENT || 445 is->hy_state == RECVDATASENT || 446 (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 447 hycancel(ui); 448 else { 449 #ifdef DEBUG 450 if (hy_nodebug & 2) 451 hy_debug_flag = 1; 452 #endif 453 is->hy_retry++; 454 is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 455 is->hy_state = IDLE; 456 hyact(ui); 457 } 458 } else { 459 /* 460 * Interrupt is neither normal, abnormal, or interface error. 461 * Ignore it. It's either stacked or a word count 0. 462 */ 463 #ifdef HYLOG 464 if (hy_log.hyl_enable != hy_log.hyl_onerr) { 465 hy_log.hyl_enable = hy_log.hyl_onerr; 466 goto logit; 467 } 468 #endif 469 #ifdef DEBUG 470 printD("hy%d: possible stacked interrupt ignored\n", unit); 471 #endif 472 } 473 #ifdef DEBUG 474 printD("hy%d: hyint exit\n\n", unit); 475 #endif 476 hyint_active = 0; 477 478 } 479 480 /* 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 hyoutput(ifp, m0, dst) 486 struct ifnet *ifp; 487 struct mbuf *m0; 488 struct sockaddr *dst; 489 { 490 register struct hym_hdr *hym; 491 register struct mbuf *m; 492 #ifdef HYROUTE 493 register struct hyroute *r = &hy_route[ifp->if_unit]; 494 #endif 495 short dtype; /* packet type */ 496 int dhost; /* destination adapter address */ 497 int dlen; 498 int mplen = 0; /* message proper length */ 499 short loopback = 0; /* hardware loopback requested */ 500 int error = 0; 501 int s; 502 503 #ifdef DEBUG 504 if (hy_nodebug & 8) 505 hy_debug_flag = 1; 506 #endif 507 dlen = 0; 508 for (m = m0; m; m = m->m_next) 509 dlen += m->m_len; 510 m = m0; 511 switch(dst->sa_family) { 512 513 #ifdef INET 514 case AF_INET: { 515 register struct ip *ip = mtod(m, struct ip *); 516 register struct sockaddr_in *sin = (struct sockaddr_in *)dst; 517 register long hostaddr = in_lnaof(sin->sin_addr); 518 519 dhost = hostaddr & 0xffff; 520 dtype = HYLINK_IP; 521 #ifdef DEBUG 522 printD("hy%d: output to host %x, dhost %x\n", 523 ifp->if_unit, sin->sin_addr.s_addr, dhost); 524 #endif 525 /* 526 * Debugging loopback support: 527 * upper byte of 24 bit host number interpreted as follows 528 * 0x00 --> no loopback 529 * 0x01 --> hardware loop through remote adapter 530 * other --> software loop through remote ip layer 531 */ 532 if (hostaddr & 0xff0000) { 533 struct in_addr temp; 534 535 temp = ip->ip_dst; 536 ip->ip_dst = ip->ip_src; 537 ip->ip_src = temp; 538 if ((hostaddr & 0xff0000) == 0x10000) 539 loopback = H_LOOPBK; 540 } 541 /* 542 * If entire packet won't fit in message proper, just 543 * send hyperchannel hardware header and ip header in 544 * message proper. If that won't fit either, just send 545 * the maximum message proper. 546 * 547 * This insures that the associated data is at least a 548 * TCP/UDP header in length and thus prevents potential 549 * problems with very short word counts. 550 */ 551 if (dlen > MPSIZE - sizeof (struct hy_hdr)) { 552 mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2); 553 if (mplen > MPSIZE) 554 mplen = MPSIZE; 555 } 556 break; 557 } 558 #endif 559 560 default: 561 printf("hy%d: can't handle af%d\n", ifp->if_unit, 562 dst->sa_family); 563 #ifdef DEBUG 564 if (hy_nodebug & 4) 565 hy_debug_flag = 1; 566 #endif 567 error = EAFNOSUPPORT; 568 goto drop; 569 } 570 571 /* 572 * Add the software and hardware hyperchannel headers. 573 * If there's not enough space in the first mbuf, allocate another. 574 * If that should fail, drop this sucker. 575 * No extra space for headers is allocated. 576 */ 577 if (m->m_off > MMAXOFF || 578 MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 579 m = m_get(M_DONTWAIT, MT_HEADER); 580 if (m == 0) { 581 m = m0; 582 error = ENOBUFS; 583 goto drop; 584 } 585 m->m_next = m0; 586 m->m_off = MMINOFF; 587 m->m_len = sizeof(struct hym_hdr); 588 } else { 589 m->m_off -= sizeof(struct hym_hdr); 590 m->m_len += sizeof(struct hym_hdr); 591 } 592 hym = mtod(m, struct hym_hdr *); 593 hym->hym_mplen = mplen; 594 hym->hym_hdr.hyh_type = dtype; 595 hym->hym_hdr.hyh_off = 0; 596 hym->hym_hdr.hyh_from = htons(ifp->if_host[0]); 597 hym->hym_hdr.hyh_param = loopback; 598 #ifdef HYROUTE 599 if (r->hyr_lasttime.tv_sec != 0) { 600 register struct hy_hash *rh; 601 register int i; 602 603 i = HYRHASH(dhost); 604 rh = &r->hyr_hash[i]; 605 i = 0; 606 while (rh->hyr_key != dhost) { 607 rh++; i++; 608 if (rh > &r->hyr_hash[HYRSIZE]) 609 rh = &r->hyr_hash[0]; 610 if (rh->hyr_flags == 0 || i > HYRSIZE) 611 goto notfound; 612 } 613 if (rh->hyr_flags & HYR_GATE) { 614 loopback = 0; /* no hardware loopback on gateways */ 615 i = rh->hyr_nextgate; 616 if (i >= rh->hyr_egate) 617 rh->hyr_nextgate = rh->hyr_pgate; 618 else 619 rh->hyr_nextgate++; 620 rh = &r->hyr_hash[r->hyr_gateway[i]]; 621 if ((rh->hyr_flags & HYR_DIR) == 0) 622 goto notfound; 623 } 624 hym->hym_hdr.hyh_ctl = rh->hyr_ctl; 625 hym->hym_hdr.hyh_access = rh->hyr_access; 626 hym->hym_hdr.hyh_to = rh->hyr_dst; 627 } else { 628 hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 629 hym->hym_hdr.hyh_access = 0; 630 hym->hym_hdr.hyh_to = htons(dhost); 631 } 632 #else 633 hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 634 hym->hym_hdr.hyh_access = 0; 635 hym->hym_hdr.hyh_to = htons(dhost); 636 #endif 637 638 headerexists: 639 if (hym->hym_mplen) { 640 hym->hym_hdr.hyh_ctl |= H_ASSOC; 641 #ifdef DEBUG 642 if (hy_nodebug & 16) 643 hy_debug_flag = 1; 644 #endif 645 } else 646 hym->hym_hdr.hyh_ctl &= ~H_ASSOC; 647 #ifdef DEBUG 648 printD("hy%d: output mplen=%x ctl=%x access=%x to=%x", 649 ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl, 650 hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to); 651 printD(" (adapter %x) from=%x param=%x type=%x off=%x\n", 652 hym->hym_hdr.hyh_to_adapter, 653 hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param, 654 hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off); 655 #endif 656 s = splimp(); 657 if (IF_QFULL(&ifp->if_snd)) { 658 IF_DROP(&ifp->if_snd); 659 error = ENOBUFS; 660 splx(s); 661 goto drop; 662 } 663 IF_ENQUEUE(&ifp->if_snd, m); 664 if (hy_softc[ifp->if_unit].hy_state == WAITING) 665 hyact(hyinfo[ifp->if_unit]); 666 splx(s); 667 return (0); 668 notfound: 669 error = ENETUNREACH; /* XXX */ 670 drop: 671 m_freem(m); 672 return (error); 673 } 674 675 hyact(ui) 676 register struct uba_device *ui; 677 { 678 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 679 register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 680 681 actloop: 682 #ifdef DEBUG 683 printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 684 hy_state_names[is->hy_state]); 685 #endif 686 switch (is->hy_state) { 687 688 case STARTUP: 689 goto endintr; 690 691 case IDLE: { 692 register rq = is->hy_flags; 693 694 if (rq & RQ_STATUS) { 695 is->hy_flags &= ~RQ_STATUS; 696 is->hy_state = STATSENT; 697 hystart(ui, HYF_STATUS, sizeof (is->hy_status), 698 is->hy_ifuba.ifu_r.ifrw_info); 699 } else if (rq & RQ_ENDOP) { 700 is->hy_flags &= ~RQ_ENDOP; 701 is->hy_state = ENDOPSENT; 702 hystart(ui, HYF_END_OP, 0, 0); 703 } else if (rq & RQ_STATISTICS) { 704 is->hy_flags &= ~RQ_STATISTICS; 705 is->hy_state = RSTATSENT; 706 hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 707 is->hy_ifuba.ifu_r.ifrw_info); 708 } else if (HYS_RECVDATA(addr)) { 709 is->hy_state = RECVSENT; 710 is->hy_retry = 0; 711 hystart(ui, HYF_INPUTMSG, MPSIZE, 712 is->hy_ifuba.ifu_r.ifrw_info); 713 } else if (rq & RQ_REISSUE) { 714 is->hy_flags &= ~RQ_REISSUE; 715 is->hy_state = is->hy_savedstate; 716 #ifdef DEBUG 717 printD("hy%d: reissue cmd=0x%x count=%d", 718 ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 719 printD(" ubaddr=0x%x retry=%d\n", 720 is->hy_savedaddr, is->hy_retry); 721 #endif 722 hystart(ui, is->hy_savedcmd, is->hy_savedcount, 723 is->hy_savedaddr); 724 } else { 725 register struct mbuf *m; 726 727 IF_DEQUEUE(&is->hy_if.if_snd, m); 728 if (m != NULL) { 729 register struct hym_hdr *hym; 730 register int mplen; 731 register int cmd; 732 733 is->hy_state = XMITSENT; 734 is->hy_retry = 0; 735 hym = mtod(m, struct hym_hdr *); 736 #ifdef HYLOG 737 hylog(HYL_XMIT, sizeof(struct hym_hdr), 738 (char *)hym); 739 #endif 740 mplen = hym->hym_mplen; 741 if (hym->hym_hdr.hyh_to_adapter == 742 hym->hym_hdr.hyh_from_adapter) 743 cmd = HYF_XMITLOCMSG; 744 else 745 cmd = HYF_XMITMSG; 746 #ifdef DEBUG 747 printD("hy%d: hym_hdr = ", ui->ui_unit); 748 if (hy_debug_flag) 749 hyprintdata((char *)hym, 750 sizeof (struct hym_hdr)); 751 #endif 752 /* 753 * Strip off the software part of 754 * the hyperchannel header 755 */ 756 m->m_off += sizeof(struct hym_data); 757 m->m_len -= sizeof(struct hym_data); 758 is->hy_olen = if_wubaput(&is->hy_ifuba, m); 759 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 760 UBAPURGE(is->hy_ifuba.ifu_uba, 761 is->hy_ifuba.ifu_w.ifrw_bdp); 762 #ifdef DEBUG 763 printD( 764 "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 765 ui->ui_unit, mplen, is->hy_olen); 766 if (hy_debug_flag) 767 hyprintdata( 768 is->hy_ifuba.ifu_w.ifrw_addr, 769 is->hy_olen); 770 #endif 771 hystart(ui, cmd, 772 (mplen == 0) ? is->hy_olen : mplen, 773 is->hy_ifuba.ifu_w.ifrw_info); 774 if (mplen != 0) 775 is->hy_flags |= RQ_XASSOC; 776 } else if (rq & RQ_MARKDOWN) { 777 is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 778 is->hy_state = MARKPORT; 779 is->hy_retry = 0; 780 /* 781 * Port number is taken from status data 782 */ 783 hystart(ui, 784 HYF_MARKP0 | (PORTNUM(&is->hy_status) << 2), 785 0, 0); 786 } else if (rq & RQ_MARKUP) { 787 register struct ifnet *ifp = &is->hy_if; 788 register struct sockaddr_in *sin = 789 (struct sockaddr_in *)&ifp->if_addr; 790 791 is->hy_flags &= ~RQ_MARKUP; 792 is->hy_retry = 0; 793 /* 794 * Fill in the Internet address 795 * from the status buffer 796 */ 797 printf( 798 "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 799 ui->ui_unit, 800 is->hy_stat.hyc_uaddr, 801 PORTNUM(&is->hy_status), 802 (is->hy_stat.hyc_atype[0]<<8) | 803 is->hy_stat.hyc_atype[1], 804 is->hy_stat.hyc_atype[2]); 805 806 ifp->if_host[0] = 807 (is->hy_stat.hyc_uaddr << 8) | 808 PORTNUM(&is->hy_status); 809 sin->sin_family = AF_INET; 810 sin->sin_addr = 811 if_makeaddr(ifp->if_net, ifp->if_host[0]); 812 ifp->if_flags |= IFF_UP; 813 if_rtinit(ifp, RTF_UP); 814 #ifdef HYLOG 815 hylog(HYL_UP, 0, (char *)0); 816 #endif 817 } else { 818 is->hy_state = WAITING; 819 is->hy_retry = 0; 820 hystart(ui, HYF_WAITFORMSG, 0, 0); 821 } 822 } 823 break; 824 } 825 826 case STATSENT: 827 bcopy(is->hy_ifuba.ifu_r.ifrw_addr, &is->hy_status, 828 sizeof (struct hy_status)); 829 #ifdef DEBUG 830 printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 831 ui->ui_unit, is->hy_status.hys_gen_status, 832 is->hy_status.hys_last_fcn, 833 is->hy_status.hys_resp_trunk, 834 is->hy_status.hys_status_trunk, 835 is->hy_status.hys_recd_resp, 836 is->hy_status.hys_error, 837 is->hy_status.hys_caddr, 838 is->hy_status.hys_pad); 839 #endif 840 is->hy_state = IDLE; 841 #ifdef HYLOG 842 hylog(HYL_STATUS, sizeof (struct hy_status), 843 (char *)&is->hy_status); 844 #endif 845 #ifdef HYELOG 846 { 847 register int i; 848 849 i = is->hy_status.hys_error; 850 if (i < HYE_MAX) 851 i = HYE_MAX; 852 switch (is->hy_status.hys_last_fcn) { 853 case HYF_XMITLOCMSG: 854 i += HYE_MAX+1; /* fall through */ 855 case HYF_XMITLSTDATA: 856 i += HYE_MAX+1; /* fall through */ 857 case HYF_XMITMSG: 858 i += HYE_MAX+1; 859 } 860 hy_elog[i]++; 861 } 862 #endif 863 break; 864 865 case RSTATSENT: { 866 register struct hy_stat *p = 867 (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 868 869 is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt); 870 is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt); 871 is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy); 872 is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret); 873 is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad); 874 is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret); 875 is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort); 876 is->hy_stat.hyc_atype[0] = p->hyc_atype[0]; 877 is->hy_stat.hyc_atype[1] = p->hyc_atype[1]; 878 is->hy_stat.hyc_atype[2] = p->hyc_atype[2]; 879 is->hy_stat.hyc_uaddr = p->hyc_uaddr; 880 #ifdef DEBUG 881 printD( 882 "hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n", 883 ui->ui_unit, 884 is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt, 885 is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret, 886 is->hy_stat.hyc_crcbad); 887 printD(" mcret %d tdabort %d atype %x %x %x uaddr %x\n", 888 is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort, 889 is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 890 is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 891 #endif 892 is->hy_state = IDLE; 893 #ifdef HYLOG 894 hylog(HYL_STATISTICS, sizeof (struct hy_stat), 895 (char *)&is->hy_stat); 896 #endif 897 break; 898 } 899 900 case CLEARSENT: 901 is->hy_state = IDLE; 902 break; 903 904 case ENDOPSENT: 905 is->hy_state = IDLE; 906 break; 907 908 case RECVSENT: { 909 register struct hy_hdr *hyh; 910 register unsigned len; 911 912 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 913 UBAPURGE(is->hy_ifuba.ifu_uba, 914 is->hy_ifuba.ifu_r.ifrw_bdp); 915 hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 916 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 917 if (len > MPSIZE) { 918 printf("hy%d: RECVD MP > MPSIZE (%d)\n", 919 ui->ui_unit, len); 920 #ifdef DEBUG 921 hy_debug_flag = 1; 922 printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 923 ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 924 addr->hyd_bar, addr->hyd_wcr); 925 #endif 926 } 927 #ifdef DEBUG 928 printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 929 if (hy_debug_flag) 930 hyprintdata((char *)hyh, len); 931 #endif 932 if (hyh->hyh_ctl & H_ASSOC) { 933 is->hy_state = RECVDATASENT; 934 is->hy_ilen = len; 935 is->hy_retry = 0; 936 hystart(ui, HYF_INPUTDATA, 937 HYMTU-len+sizeof (struct hy_hdr), 938 is->hy_ifuba.ifu_r.ifrw_info + len); 939 } else { 940 hyrecvdata(ui, hyh, len); 941 is->hy_state = IDLE; 942 } 943 break; 944 } 945 946 case RECVDATASENT: { 947 register struct hy_hdr *hyh; 948 register unsigned len; 949 950 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 951 UBAPURGE(is->hy_ifuba.ifu_uba, 952 is->hy_ifuba.ifu_r.ifrw_bdp); 953 hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 954 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 955 #ifdef DEBUG 956 printD("hy%d: recvd assoc data, len = %d, data = ", 957 ui->ui_unit, len); 958 if (hy_debug_flag) 959 hyprintdata((char *)hyh + is->hy_ilen, len); 960 #endif 961 hyrecvdata(ui, hyh, len + is->hy_ilen); 962 is->hy_state = IDLE; 963 break; 964 } 965 966 case XMITSENT: 967 if (is->hy_flags & RQ_XASSOC) { 968 register unsigned len; 969 970 is->hy_flags &= ~RQ_XASSOC; 971 is->hy_state = XMITDATASENT; 972 is->hy_retry = 0; 973 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 974 if (len > is->hy_olen) { 975 printf( 976 "hy%d: xmit error - len > hy_olen [%d > %d]\n", 977 ui->ui_unit, len, is->hy_olen); 978 #ifdef DEBUG 979 hy_debug_flag = 1; 980 #endif 981 } 982 hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 983 is->hy_ifuba.ifu_w.ifrw_info + len); 984 break; 985 } 986 /* fall through to ... */ 987 988 case XMITDATASENT: 989 hyxmitdata(ui); 990 is->hy_state = IDLE; 991 break; 992 993 case WAITING: /* wait for message complete or output requested */ 994 if (HYS_RECVDATA(addr)) 995 is->hy_state = IDLE; 996 else { 997 is->hy_state = CLEARSENT; 998 is->hy_retry = 0; 999 hystart(ui, HYF_CLRWFMSG, 0, 0); 1000 } 1001 break; 1002 1003 case MARKPORT: 1004 is->hy_state = STARTUP; 1005 is->hy_if.if_flags &= ~IFF_UP; 1006 goto endintr; 1007 1008 default: 1009 printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 1010 ui->ui_unit, is->hy_state); 1011 panic("HYPERCHANNEL IN INVALID STATE"); 1012 /*NOTREACHED*/ 1013 } 1014 if (is->hy_state == IDLE) 1015 goto actloop; 1016 endintr: 1017 #ifdef DEBUG 1018 printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 1019 hy_state_names[is->hy_state]); 1020 #endif 1021 return (0); 1022 } 1023 1024 /* 1025 * Called from device interrupt when recieving data. 1026 * Examine packet to determine type. Decapsulate packet 1027 * based on type and pass to type specific higher-level 1028 * input routine. 1029 */ 1030 hyrecvdata(ui, hyh0, len) 1031 struct uba_device *ui; 1032 struct hy_hdr *hyh0; 1033 int len; 1034 { 1035 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 1036 register struct hy_hdr *hyh = hyh0; 1037 struct mbuf *m; 1038 register struct ifqueue *inq; 1039 1040 is->hy_if.if_ipackets++; 1041 #ifdef DEBUG 1042 printD("hy%d: recieved packet, len = %d (actual %d)\n", 1043 ui->ui_unit, len, 1044 len - (hyh->hyh_off + sizeof (struct hy_hdr))); 1045 #endif 1046 #ifdef HYLOG 1047 { 1048 struct { 1049 short hlen; 1050 struct hy_hdr hhdr; 1051 } hh; 1052 hh.hlen = len; 1053 hh.hhdr = *hyh; 1054 hylog(HYL_RECV, sizeof(hh), (char *)&hh); 1055 } 1056 #endif 1057 if (len > HYMTU + MPSIZE || len == 0) 1058 return; /* sanity */ 1059 /* 1060 * Pull packet off interface. 1061 */ 1062 m = if_rubaget(&is->hy_ifuba, len, 0); 1063 if (m == NULL) 1064 return; 1065 switch (hyh->hyh_type) { 1066 1067 #ifdef INET 1068 case HYLINK_IP: 1069 /* 1070 * Strip the variable portion of the hyperchannel header 1071 * (fixed portion stripped in if_rubaget). 1072 */ 1073 m->m_len -= hyh->hyh_off; 1074 m->m_off += hyh->hyh_off; 1075 schednetisr(NETISR_IP); 1076 inq = &ipintrq; 1077 break; 1078 #endif 1079 default: 1080 m_freem(m); 1081 return; 1082 } 1083 if (IF_QFULL(inq)) { 1084 IF_DROP(inq); 1085 m_freem(m); 1086 } else 1087 IF_ENQUEUE(inq, m); 1088 } 1089 1090 /* 1091 * Transmit done, release resources, bump counters. 1092 */ 1093 hyxmitdata(ui) 1094 struct uba_device *ui; 1095 { 1096 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 1097 1098 is->hy_if.if_opackets++; 1099 if (is->hy_ifuba.ifu_xtofree) { 1100 m_freem(is->hy_ifuba.ifu_xtofree); 1101 is->hy_ifuba.ifu_xtofree = 0; 1102 } 1103 } 1104 1105 hycancel(ui) 1106 register struct uba_device *ui; 1107 { 1108 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 1109 1110 if (is->hy_ifuba.ifu_xtofree) { 1111 m_freem(is->hy_ifuba.ifu_xtofree); 1112 is->hy_ifuba.ifu_xtofree = 0; 1113 } 1114 #ifdef DEBUG 1115 if (hy_nodebug & 1) 1116 hy_debug_flag = 1; 1117 #endif 1118 #ifdef DEBUG 1119 printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 1120 ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 1121 is->hy_savedcount, is->hy_savedaddr); 1122 printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 1123 is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr, 1124 is->hy_retry); 1125 printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 1126 is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 1127 is->hy_savedcmd); 1128 #endif 1129 is->hy_state = IDLE; 1130 is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 1131 hyact(ui); 1132 } 1133 1134 #ifdef DEBUG 1135 hyprintdata(cp, len) 1136 register char *cp; 1137 register int len; 1138 { 1139 register int count = 16; 1140 register char *fmt; 1141 static char regfmt[] = "\n\t %x"; 1142 1143 fmt = ®fmt[2]; 1144 while (--len >= 0) { 1145 printL(fmt, *cp++ & 0xff); 1146 fmt = ®fmt[2]; 1147 if (--count <= 0) { 1148 fmt = ®fmt[0]; 1149 count = 16; 1150 } 1151 } 1152 printL("\n"); 1153 } 1154 #endif 1155 1156 hywatch(unit) 1157 int unit; 1158 { 1159 register struct hy_softc *is = &hy_softc[unit]; 1160 register struct uba_device *ui = hyinfo[unit]; 1161 register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 1162 int s; 1163 1164 s = splimp(); 1165 is->hy_if.if_timer = SCANINTERVAL; 1166 if (is->hy_ntime > 2 && is->hy_state != WAITING && 1167 is->hy_state != STARTUP && is->hy_state != IDLE) { 1168 printf("hy%d: watchdog timer expired\n", unit); 1169 hycancel(ui); 1170 } 1171 #ifdef PI13 1172 if ((addr->hyd_csr & S_POWEROFF) != 0) { 1173 addr->hyd_csr |= S_POWEROFF; 1174 DELAY(100); 1175 if ((addr->hyd_csr & S_POWEROFF) == 0) { 1176 printf("hy%d: adapter power restored\n", unit); 1177 is->hy_state = IDLE; 1178 is->hy_flags |= 1179 (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 1180 hyact(ui); 1181 } 1182 } 1183 #endif 1184 splx(s); 1185 } 1186 1187 #ifdef HYLOG 1188 hylog(code, len, ptr) 1189 int code; 1190 int len; 1191 char *ptr; 1192 { 1193 register unsigned char *p; 1194 int s; 1195 1196 s = splimp(); 1197 if (hy_log.hyl_self != &hy_log) { 1198 hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 1199 hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 1200 hy_log.hyl_self = &hy_log; 1201 hy_log.hyl_enable = HYL_DISABLED; 1202 hy_log.hyl_onerr = HYL_CATCH1; 1203 } 1204 if (hy_log.hyl_enable == HYL_DISABLED || 1205 hy_log.hyl_enable == HYL_CAUGHT1 || 1206 hy_log.hyl_enable == HYL_CAUGHTSTATUS || 1207 (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS)) 1208 goto out; 1209 p = hy_log.hyl_ptr; 1210 if (p + len + 2 >= hy_log.hyl_eptr) { 1211 bzero(p, hy_log.hyl_eptr - p); 1212 p = &hy_log.hyl_buf[0]; 1213 if (hy_log.hyl_enable == HYL_CATCH1) { 1214 hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1; 1215 goto out; 1216 } 1217 if (hy_log.hyl_enable == HYL_CATCHSTATUS) { 1218 hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS; 1219 goto out; 1220 } 1221 } 1222 *p++ = code; 1223 *p++ = len; 1224 bcopy(ptr, p, len); 1225 hy_log.hyl_ptr = p + len; 1226 out: 1227 splx(s); 1228 } 1229 #endif 1230 1231 hyioctl(dev, cmd, data, flag) 1232 dev_t dev; 1233 int cmd; 1234 caddr_t data; 1235 int flag; 1236 { 1237 int s = splimp(), error = 0; 1238 1239 if (minor(dev) >= NHY) { 1240 error = ENXIO; 1241 goto bad; 1242 } 1243 switch(cmd) { 1244 1245 case HYSETROUTE: 1246 if (!suser()) { 1247 error = EPERM; 1248 goto bad; 1249 } 1250 hy_route[minor(dev)] = *(struct hyroute *)data; 1251 hy_route[minor(dev)].hyr_lasttime = time; 1252 break; 1253 1254 case HYGETROUTE: 1255 *(struct hyroute *)data = hy_route[minor(dev)]; 1256 break; 1257 1258 default: 1259 error = ENXIO; 1260 break; 1261 } 1262 bad: 1263 splx(s); 1264 return (error); 1265 } 1266 #endif 1267