1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Tektronix Inc. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * @(#)if_hy.c 7.3 (Berkeley) 10/12/88 21 */ 22 23 /* 24 * 4.2 BSD Unix Kernel - Vax Network Interface Support 25 * 26 * $Header: if_hy.c,v 10.1 84/07/22 21:02:56 steveg Exp $ 27 * $Locker: $ 28 * 29 * Modifications from Berkeley 4.2 BSD 30 * Copyright (c) 1983, Tektronix Inc. 31 * All Rights Reserved 32 * 33 * $Log: if_hy.c,v $ 34 * Revision 10.1 84/07/22 21:02:56 steveg 35 * define PI13 (moved from if_hyreg.h, somehow got dropped in the process) 36 * rework hywatch to check for power fails first 37 * 38 * Revision 10.0 84/06/30 19:54:27 steveg 39 * Big Build 40 * 41 * Revision 3.17 84/06/20 19:20:28 steveg 42 * increment hy_ntime in hywatch 43 * print out state name, csr, last command, and hy_flags when watchdog timer 44 * expires 45 * 46 * Revision 3.16 84/06/20 19:09:34 steveg 47 * turn on continuous logging by default 48 * 49 * Revision 3.15 84/05/30 22:19:09 steveg 50 * changes to reflect new layout ot statistics data 51 * 52 * Revision 3.14 84/05/30 19:25:15 steveg 53 * move driver states to if_hy.h so log printing programs can use them 54 * 55 * Revision 3.13 84/05/30 17:13:26 steveg 56 * make it compile 57 * 58 * Revision 3.12 84/05/30 13:46:16 steveg 59 * rework logging 60 * 61 * Revision 3.11 84/05/18 19:35:02 steveg 62 * clear IFF_RUNNING and IFF_UP on unibus reset to force resource allocation 63 * by the init routine 64 * 65 * Revision 3.10 84/05/04 12:14:44 steveg 66 * more rework to make it actually work under 4.2 67 * 68 * Revision 3.9 84/05/01 23:34:52 steveg 69 * fix typo so it compiles (unit -> ui->ui_unit) 70 * 71 * Revision 3.8 84/05/01 23:18:30 steveg 72 * changes after talking with rickk 73 * - check power off more closely 74 * - support remote loopback through A710 adapters 75 * - IMPLINK -> HYLINK 76 * - return EHOSTUNREACH on hyroute failure 77 * - bump if_collisions on abnormal interrupts that aren't input or output 78 * 79 * 80 */ 81 82 83 #include "hy.h" 84 #if NHY > 0 85 86 /* 87 * Network Systems Copropration Hyperchanel interface 88 */ 89 #include "machine/pte.h" 90 91 #include "param.h" 92 #include "systm.h" 93 #include "mbuf.h" 94 #include "buf.h" 95 #include "protosw.h" 96 #include "socket.h" 97 #include "vmmac.h" 98 #include "errno.h" 99 #include "time.h" 100 #include "kernel.h" 101 #include "ioctl.h" 102 103 #include "../net/if.h" 104 #include "../net/netisr.h" 105 #include "../net/route.h" 106 107 #ifdef INET 108 #include "../netinet/in.h" 109 #include "../netinet/in_systm.h" 110 #include "../netinet/in_var.h" 111 #include "../netinet/ip.h" 112 #endif 113 114 #include "../vax/cpu.h" 115 #include "../vax/mtpr.h" 116 #include "../vaxuba/ubareg.h" 117 #include "../vaxuba/ubavar.h" 118 119 /* 120 * configuration specific paramters 121 * - change as appropriate for particular installaions 122 */ 123 #define HYROUTE 124 #define HYELOG 125 #define HYLOG 126 #define HYMTU 1100 127 #define PI13 128 129 #ifdef DEBUG 130 #define HYLOG 131 #endif 132 133 #include "if_hy.h" 134 #include "if_hyreg.h" 135 #include "if_uba.h" 136 137 int hyprobe(), hyattach(), hyinit(), hyioctl(); 138 int hyoutput(), hyreset(), hywatch(); 139 struct uba_device *hyinfo[NHY]; 140 u_short hystd[] = { 0772410, 0 }; 141 struct uba_driver hydriver = 142 { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo }; 143 144 /* 145 * Hyperchannel software status per interface. 146 * 147 * Each interface is referenced by a network interface structure, 148 * hy_if, which the routing code uses to locate the interface. 149 * This structure contains the output queue for the interface, its address, ... 150 * We also have, for each interface, a UBA interface structure, which 151 * contains information about the UNIBUS resources held by the interface: 152 * map registers, buffered data paths, etc. Information is cached in this 153 * structure for use by the if_uba.c routines in running the interface 154 * efficiently. 155 */ 156 struct hy_softc { 157 struct ifnet hy_if; /* network-visible interface */ 158 struct ifuba hy_ifuba; /* UNIBUS resources */ 159 short hy_flags; /* flags */ 160 short hy_state; /* driver state */ 161 u_short hy_host; /* local host number */ 162 struct in_addr hy_addr; /* internet address */ 163 int hy_olen; /* packet length on output */ 164 int hy_lastwcr; /* last command's word count */ 165 short hy_savedstate; /* saved for reissue after status */ 166 short hy_savedcmd; /* saved command for reissue */ 167 int hy_savedcount; /* saved byte count for reissue */ 168 int hy_savedaddr; /* saved unibus address for reissue */ 169 int hy_ntime; /* number of timeouts since last cmd */ 170 int hy_retry; /* retry counter */ 171 struct hy_stat hy_stat; /* statistics */ 172 struct hy_status hy_status; /* status */ 173 } hy_softc[NHY]; 174 175 #ifdef HYELOG 176 u_long hy_elog[HYE_SIZE]; 177 #endif 178 179 #ifdef HYLOG 180 struct hy_log hy_log; 181 #endif 182 183 #ifdef HYROUTE 184 struct hy_route hy_route[NHY]; 185 #endif 186 187 #ifdef DEBUG 188 #define printL printf 189 #define printD if (hy_debug_flag) printf 190 int hy_debug_flag = 0; 191 /* 192 * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 193 * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 194 * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 195 */ 196 int hy_nodebug = 0x0; 197 #endif 198 199 #define SCANINTERVAL 10 /* seconds */ 200 #define MAXINTERVAL 20 /* seconds (max action) */ 201 202 /* 203 * Cause a device interrupt. This code uses a buffer starting at 204 * location zero on the unibus (which is already mapped by the 205 * autoconfigure code in the kernel). 206 */ 207 hyprobe(reg) 208 caddr_t reg; 209 { 210 register int br, cvec; /* r11, r10 value-result */ 211 register struct hydevice *addr = (struct hydevice *) reg; 212 213 #ifdef lint 214 br = 0; cvec = br; br = cvec; 215 hyint(0); 216 #endif 217 /* 218 * request adapter status to a buffer starting at unibus location 0 219 */ 220 addr->hyd_bar = 0; 221 addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 222 addr->hyd_dbuf = HYF_STATUS; 223 #ifdef PI13 224 addr->hyd_csr |= S_GO | S_IE | S_IATTN; 225 #else 226 addr->hyd_csr |= S_GO | S_IE; 227 #endif 228 DELAY(10000); 229 #ifdef PI13 230 addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 231 #endif 232 addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 233 return(sizeof(struct hydevice)); 234 } 235 236 /* 237 * Interface exists: make available by filling in network interface 238 * record. System will initialize the interface when it is ready 239 * to accept packets. 240 */ 241 hyattach(ui) 242 struct uba_device *ui; 243 { 244 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 245 register struct ifnet *ifp = &is->hy_if; 246 247 ifp->if_unit = ui->ui_unit; 248 ifp->if_name = "hy"; 249 ifp->if_mtu = HYMTU; 250 is->hy_state = STARTUP; /* don't allow state transitions yet */ 251 ifp->if_init = hyinit; 252 ifp->if_ioctl = hyioctl; 253 ifp->if_output = hyoutput; 254 ifp->if_reset = hyreset; 255 ifp->if_watchdog = hywatch; 256 ifp->if_timer = SCANINTERVAL; 257 is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 258 #ifdef notdef 259 is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 260 #endif 261 if_attach(ifp); 262 } 263 264 /* 265 * Reset of interface after UNIBUS reset. 266 * If interface is on specified uba, reset its state. 267 */ 268 hyreset(unit, uban) 269 int unit, uban; 270 { 271 register struct uba_device *ui; 272 register struct hy_softc *is; 273 274 if (unit >= NHY || (ui = hyinfo[unit]) == 0 || ui->ui_alive == 0 || 275 ui->ui_ubanum != uban) 276 return; 277 printf(" hy%d", unit); 278 is = &hy_softc[unit]; /* force unibus resource allocation */ 279 is->hy_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 280 hyinit(unit); 281 } 282 283 /* 284 * Initialization of interface; clear recorded pending 285 * operations, and reinitialize UNIBUS usage. 286 */ 287 hyinit(unit) 288 int unit; 289 { 290 register struct hy_softc *is = &hy_softc[unit]; 291 register struct uba_device *ui = hyinfo[unit]; 292 register struct mbuf *m; 293 int s; 294 295 if (is->hy_if.if_addrlist == 0) /* address still unknown */ 296 return; 297 if (is->hy_if.if_flags & IFF_RUNNING) /* just reset the device */ 298 goto justreset; 299 if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 300 sizeof (struct hym_hdr), (int)btoc(HYMTU)) == 0) { 301 #ifdef DEBUG 302 if (hy_nodebug & 4) 303 hy_debug_flag = 1; 304 #endif 305 printf("hy%d: can't initialize\n", unit); 306 is->hy_if.if_flags &= ~IFF_UP; 307 return; 308 } 309 is->hy_if.if_flags |= IFF_RUNNING; 310 311 justreset: 312 /* 313 * remove any left over outgoing messages, reset the hardware and 314 * start the state machine 315 */ 316 s = splimp(); 317 #ifdef HYLOG 318 hylog(HYL_RESET, 0, (char *)0); 319 #endif 320 is->hy_state = IDLE; 321 is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 322 is->hy_retry = 0; 323 for(;;) { 324 IF_DEQUEUE(&is->hy_if.if_snd, m); 325 if (m != NULL) 326 m_freem(m); 327 else 328 break; 329 } 330 hycancel(ui); /* also bumps the state machine */ 331 splx(s); 332 } 333 334 /* 335 * Issue a command to the adapter 336 */ 337 hystart(ui, cmd, count, ubaddr) 338 struct uba_device *ui; 339 int cmd, count, ubaddr; 340 { 341 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 342 register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 343 344 #ifdef DEBUG 345 printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 346 ui->ui_unit, cmd, count, ubaddr); 347 printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 348 ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 349 addr->hyd_wcr); 350 #endif 351 if (((is->hy_flags & RQ_REISSUE) == 0) && 352 (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 353 is->hy_savedstate = is->hy_state; 354 is->hy_savedcmd = cmd; 355 is->hy_savedcount = count; 356 is->hy_savedaddr = ubaddr; 357 } 358 #ifdef PI13 359 if (addr->hyd_csr & S_POWEROFF) { 360 printf("hy%d: \"Soft\" Adapter Power Failure (hystart)\n", ui->ui_unit); 361 addr->hyd_csr |= S_POWEROFF; 362 DELAY(100); 363 if (addr->hyd_csr & S_POWEROFF) { 364 printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hystart)\n", ui->ui_unit); 365 if_down(&is->hy_if); 366 is->hy_if.if_flags &= ~IFF_UP; 367 is->hy_state = STARTUP; 368 } else { 369 printf("hy%d: Adapter Power Restored (hystart)\n", ui->ui_unit); 370 } 371 return; 372 } 373 #endif 374 addr->hyd_bar = ubaddr & 0xffff; 375 addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 376 addr->hyd_dbuf = cmd; 377 #ifdef PI13 378 addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 379 #else 380 addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 381 #endif 382 #ifdef DEBUG 383 printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 384 ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 385 addr->hyd_wcr); 386 #endif 387 #ifdef HYLOG 388 { 389 struct { 390 u_char hcmd; 391 u_char hstate; 392 short hcount; 393 } hcl; 394 395 hcl.hcmd = cmd; 396 hcl.hstate = is->hy_state; 397 hcl.hcount = count; 398 hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 399 } 400 #endif 401 is->hy_ntime = 0; 402 } 403 404 int hyint_active = 0; /* set during hy interrupt */ 405 /* 406 * Hyperchannel interface interrupt. 407 * 408 * An interrupt can occur for many reasons. Examine the status of 409 * the hyperchannel status bits to determine what to do next. 410 * 411 * If input error just drop packet. 412 * Otherwise purge input buffered data path and examine 413 * packet to determine type. Othewise decapsulate 414 * packet based on type and pass to type specific higher-level 415 * input routine. 416 */ 417 hyint(unit) 418 int unit; 419 { 420 register struct hy_softc *is = &hy_softc[unit]; 421 register struct uba_device *ui = hyinfo[unit]; 422 register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 423 424 if (hyint_active) 425 panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 426 hyint_active++; 427 #ifdef DEBUG 428 printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 429 unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 430 #endif 431 #ifdef HYLOG 432 logit: 433 { 434 struct { 435 u_char hstate; 436 u_char hflags; 437 short hcsr; 438 short hwcr; 439 } hil; 440 hil.hstate = is->hy_state; 441 hil.hflags = is->hy_flags; 442 hil.hcsr = addr->hyd_csr; 443 hil.hwcr = addr->hyd_wcr; 444 hylog(HYL_INT, sizeof(hil), (char *)&hil); 445 } 446 #endif 447 if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 448 /* 449 * Error bit set, some sort of error in the interface. 450 * 451 * The adapter sets attn on command completion so that's not 452 * a real error even though the interface considers it one. 453 */ 454 #ifdef DEBUG 455 if (hy_nodebug & 4) 456 hy_debug_flag = 1; 457 #endif 458 printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 459 addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 460 addr->hyd_wcr); 461 if (addr->hyd_csr & S_NEX) { 462 printf("hy%d: NEX - Non Existant Memory\n", unit); 463 #ifdef PI13 464 addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 465 #else 466 addr->hyd_csr &= ~S_NEX; 467 #endif 468 hycancel(ui); 469 #ifdef PI13 470 } else if (addr->hyd_csr & S_POWEROFF) { 471 printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit); 472 addr->hyd_csr |= S_POWEROFF; 473 DELAY(100); 474 if (addr->hyd_csr & S_POWEROFF) { 475 printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit); 476 if_down(&is->hy_if); 477 is->hy_if.if_flags &= ~IFF_UP; 478 is->hy_state = STARTUP; 479 } else { 480 printf("hy%d: Adapter Power Restored (hyint)\n", unit); 481 } 482 #endif 483 } else { 484 printf("hy%d: BAR overflow\n", unit); 485 hycancel(ui); 486 } 487 } else if (HYS_NORMAL(addr)) { 488 /* 489 * Normal interrupt, bump state machine unless in state 490 * waiting and no data present (assumed to be word count 491 * zero interrupt or other hardware botch). 492 */ 493 if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 494 hyact(ui); 495 } else if (HYS_ABNORMAL(addr)) { 496 /* 497 * Abnormal termination. 498 * bump error counts, retry the last function 499 * 'MAXRETRY' times before kicking the bucket. 500 * 501 * Don't reissue the cmd if in certain states, abnormal 502 * on a reissued cmd or max retry exceeded. 503 */ 504 #ifdef HYLOG 505 if (hy_log.hyl_enable != hy_log.hyl_onerr) { 506 hy_log.hyl_enable = hy_log.hyl_onerr; 507 goto logit; 508 } 509 #endif 510 #ifdef DEBUG 511 if (hy_nodebug & 4) 512 hy_debug_flag = 1; 513 printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 514 unit, hy_state_names[is->hy_state], is->hy_state); 515 printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 516 is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 517 printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 518 is->hy_savedstate, is->hy_savedcount, 519 is->hy_savedaddr, is->hy_savedcmd); 520 #endif 521 #ifdef PI13 522 addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 523 #endif 524 if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 525 is->hy_if.if_oerrors++; 526 else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 527 is->hy_if.if_ierrors++; 528 else 529 is->hy_if.if_collisions++; /* other errors */ 530 if (is->hy_state == XMITDATASENT || 531 is->hy_state == RECVSENT || 532 is->hy_state == RECVDATASENT || 533 (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 534 hycancel(ui); 535 else { 536 #ifdef DEBUG 537 if (hy_nodebug & 2) 538 hy_debug_flag = 1; 539 #endif 540 is->hy_retry++; 541 is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 542 is->hy_state = IDLE; 543 hyact(ui); 544 } 545 } else { 546 /* 547 * Interrupt is neither normal, abnormal, or interface error. 548 * Ignore it. It's either stacked or a word count 0. 549 */ 550 #ifdef HYLOG 551 if (hy_log.hyl_enable != hy_log.hyl_onerr) { 552 hy_log.hyl_enable = hy_log.hyl_onerr; 553 goto logit; 554 } 555 #endif 556 #ifdef DEBUG 557 printD("hy%d: possible stacked interrupt ignored\n", unit); 558 #endif 559 } 560 #ifdef DEBUG 561 printD("hy%d: hyint exit\n\n", unit); 562 #endif 563 hyint_active = 0; 564 565 } 566 567 int hyoutprint = 0; 568 569 /* 570 * Encapsulate a packet of type family for the local net. 571 */ 572 hyoutput(ifp, m0, dst) 573 struct ifnet *ifp; 574 struct mbuf *m0; 575 struct sockaddr *dst; 576 { 577 register struct hym_hdr *hym; 578 register struct mbuf *m; 579 register char *mp; 580 int dlen; /* packet size, incl hardware header, but not sw header */ 581 int error = 0; 582 int s; 583 584 /* 585 * Calculate packet length for later deciding whether it will fit 586 * in a message proper or we also need associated data. 587 */ 588 dlen = 0; 589 for (m = m0; m; m = m->m_next) 590 dlen += m->m_len; 591 m = m0; 592 if (dst->sa_family == AF_HYLINK) { /* don't add header */ 593 dlen -= HYM_SWLEN; 594 goto headerexists; 595 } 596 597 /* 598 * Add the software and hardware hyperchannel headers. 599 * If there's not enough space in the first mbuf, allocate another. 600 * If that should fail, drop this sucker. 601 * No extra space for headers is allocated. 602 */ 603 mp = mtod(m, char *); /* save pointer to real message */ 604 M_PREPEND(m, sizeof(struct hym_hdr), M_DONTWAIT); 605 if (m == 0) { 606 error = ENOBUFS; 607 goto bad; 608 } 609 dlen += sizeof(struct hym_hdr) - HYM_SWLEN; 610 611 hym = mtod(m, struct hym_hdr *); 612 613 bzero((caddr_t)hym, sizeof(struct hym_hdr)); 614 615 switch(dst->sa_family) { 616 617 #ifdef INET 618 case AF_INET: { 619 int i; 620 621 /* 622 * if loopback address, swizzle ip header so when 623 * it comes back it looks like it was addressed to us 624 */ 625 i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym); 626 if (i < 0) 627 goto notfound; 628 if (i > 0) { 629 struct in_addr temp; 630 631 temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr; 632 ((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr; 633 ((struct ip *)mp)->ip_src.s_addr = temp.s_addr; 634 } 635 /* 636 * If entire packet won't fit in message proper, just 637 * send hyperchannel hardware header and ip header in 638 * message proper. 639 * 640 * This insures that the associated data is at least a 641 * TCP/UDP header in length and thus prevents potential 642 * problems with very short word counts. 643 */ 644 if (dlen > MPSIZE) 645 hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2); 646 hym->hym_type = HYLINK_IP; 647 break; 648 } 649 #endif 650 651 default: 652 printf("hy%d: can't handle af%d\n", ifp->if_unit, 653 dst->sa_family); 654 error = EAFNOSUPPORT; 655 goto drop; 656 } 657 658 659 headerexists: 660 661 /* 662 * insure message proper is below the maximum 663 */ 664 if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0)) 665 hym->hym_mplen = MPSIZE; 666 667 hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host); 668 if (hym->hym_mplen) 669 hym->hym_ctl |= H_ASSOC; 670 else 671 hym->hym_ctl &= ~H_ASSOC; 672 if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 673 ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 674 hym->hym_access, hym->hym_to, hym->hym_from, 675 hym->hym_param, hym->hym_type); 676 #ifdef DEBUG 677 printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 678 ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 679 hym->hym_access, hym->hym_to, hym->hym_from, 680 hym->hym_param, hym->hym_type); 681 #endif 682 s = splimp(); 683 if (IF_QFULL(&ifp->if_snd)) { 684 IF_DROP(&ifp->if_snd); 685 error = ENOBUFS; 686 splx(s); 687 goto drop; 688 } 689 IF_ENQUEUE(&ifp->if_snd, m); 690 if (hy_softc[ifp->if_unit].hy_state == WAITING) 691 hyact(hyinfo[ifp->if_unit]); 692 splx(s); 693 return (0); 694 notfound: 695 error = EHOSTUNREACH; 696 drop: 697 m_freem(m); 698 return (error); 699 } 700 701 int 702 hyroute(ifp, dest, hym) 703 register struct ifnet *ifp; 704 u_long dest; 705 register struct hym_hdr *hym; 706 { 707 #ifdef HYROUTE 708 register struct hy_route *rt = &hy_route[ifp->if_unit]; 709 register struct hyr_hash *rhash; 710 register int i; 711 #endif 712 713 hym->hym_param = 0; 714 #ifdef HYROUTE 715 if (rt->hyr_lasttime != 0) { 716 i = HYRHASH(dest); 717 rhash = &rt->hyr_hash[i]; 718 i = 0; 719 while (rhash->hyr_key != dest) { 720 if (rhash->hyr_flags == 0 || i > HYRSIZE) 721 return(-1); 722 rhash++; i++; 723 if (rhash >= &rt->hyr_hash[HYRSIZE]) 724 rhash = &rt->hyr_hash[0]; 725 } 726 if (rhash->hyr_flags & HYR_GATE) { 727 i = rhash->hyr_nextgate; 728 if (i >= rhash->hyr_egate) 729 rhash->hyr_nextgate = rhash->hyr_pgate; 730 else 731 rhash->hyr_nextgate++; 732 rhash = &rt->hyr_hash[rt->hyr_gateway[i]]; 733 if ((rhash->hyr_flags & HYR_DIR) == 0) 734 return(-1); 735 } else if (rhash->hyr_flags & HYR_LOOP) { 736 hym->hym_param = H_LOOPBK; /* adapter loopback */ 737 } else if (rhash->hyr_flags & HYR_RLOOP) { 738 hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 739 } 740 hym->hym_ctl = rhash->hyr_ctl; 741 hym->hym_access = rhash->hyr_access; 742 hym->hym_to = rhash->hyr_dst; 743 } else { 744 #endif 745 hym->hym_ctl = H_XTRUNKS | H_RTRUNKS; 746 hym->hym_access = 0; 747 hym->hym_to = htons((u_short)dest); 748 if (dest & 0x010000) 749 hym->hym_param = H_LOOPBK; /* adapter loopback */ 750 else if (dest & 0x020000) 751 hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 752 #ifdef HYROUTE 753 } 754 #endif 755 756 if (hym->hym_param == 0) 757 return(0); 758 else 759 return(1); 760 } 761 762 hyact(ui) 763 register struct uba_device *ui; 764 { 765 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 766 register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 767 768 actloop: 769 #ifdef DEBUG 770 printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 771 hy_state_names[is->hy_state]); 772 #endif 773 switch (is->hy_state) { 774 775 case STARTUP: 776 goto endintr; 777 778 case IDLE: { 779 register rq = is->hy_flags; 780 781 if (rq & RQ_STATUS) { 782 is->hy_flags &= ~RQ_STATUS; 783 is->hy_state = STATSENT; 784 hystart(ui, HYF_STATUS, sizeof (is->hy_status), 785 is->hy_ifuba.ifu_r.ifrw_info); 786 } else if (rq & RQ_ENDOP) { 787 is->hy_flags &= ~RQ_ENDOP; 788 is->hy_state = ENDOPSENT; 789 hystart(ui, HYF_END_OP, 0, 0); 790 } else if (rq & RQ_STATISTICS) { 791 is->hy_flags &= ~RQ_STATISTICS; 792 is->hy_state = RSTATSENT; 793 hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 794 is->hy_ifuba.ifu_r.ifrw_info); 795 } else if (HYS_RECVDATA(addr)) { 796 is->hy_state = RECVSENT; 797 is->hy_retry = 0; 798 hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN); 799 } else if (rq & RQ_REISSUE) { 800 is->hy_flags &= ~RQ_REISSUE; 801 is->hy_state = is->hy_savedstate; 802 #ifdef DEBUG 803 printD("hy%d: reissue cmd=0x%x count=%d", 804 ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 805 printD(" ubaddr=0x%x retry=%d\n", 806 is->hy_savedaddr, is->hy_retry); 807 #endif 808 hystart(ui, is->hy_savedcmd, is->hy_savedcount, 809 is->hy_savedaddr); 810 } else { 811 register struct mbuf *m; 812 813 IF_DEQUEUE(&is->hy_if.if_snd, m); 814 if (m != NULL) { 815 register struct hym_hdr *hym; 816 register int mplen; 817 register int cmd; 818 819 is->hy_state = XMITSENT; 820 is->hy_retry = 0; 821 hym = mtod(m, struct hym_hdr *); 822 #ifdef HYLOG 823 hylog(HYL_XMIT, sizeof(struct hym_hdr), 824 (char *)hym); 825 #endif 826 mplen = hym->hym_mplen; 827 if (hym->hym_to_adapter == hym->hym_from_adapter) 828 cmd = HYF_XMITLOCMSG; 829 else 830 cmd = HYF_XMITMSG; 831 #ifdef DEBUG 832 printD("hy%d: hym_hdr = ", ui->ui_unit); 833 if (hy_debug_flag) 834 hyprintdata((char *)hym, 835 sizeof (struct hym_hdr)); 836 #endif 837 is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN; 838 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 839 UBAPURGE(is->hy_ifuba.ifu_uba, 840 is->hy_ifuba.ifu_w.ifrw_bdp); 841 #ifdef DEBUG 842 printD( 843 "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 844 ui->ui_unit, mplen, is->hy_olen); 845 if (hy_debug_flag) 846 hyprintdata( 847 is->hy_ifuba.ifu_w.ifrw_addr, 848 is->hy_olen + HYM_SWLEN); 849 #endif 850 if (mplen == 0) { 851 is->hy_flags &= ~RQ_XASSOC; 852 mplen = is->hy_olen; 853 } else { 854 is->hy_flags |= RQ_XASSOC; 855 } 856 hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN); 857 } else if (rq & RQ_MARKDOWN) { 858 is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 859 is->hy_state = MARKPORT; 860 is->hy_retry = 0; 861 /* 862 * Port number is taken from status data 863 */ 864 hystart(ui, 865 (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 866 0, 0); 867 } else if (rq & RQ_MARKUP) { 868 register struct ifnet *ifp = &is->hy_if; 869 870 is->hy_flags &= ~RQ_MARKUP; 871 is->hy_retry = 0; 872 /* 873 * Fill in the host number 874 * from the status buffer 875 */ 876 printf( 877 "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 878 ui->ui_unit, 879 is->hy_stat.hyc_uaddr, 880 PORTNUM(&is->hy_status), 881 (is->hy_stat.hyc_atype[0]<<8) | 882 is->hy_stat.hyc_atype[1], 883 is->hy_stat.hyc_atype[2]); 884 885 is->hy_host = 886 (is->hy_stat.hyc_uaddr << 8) | 887 PORTNUM(&is->hy_status); 888 ifp->if_flags |= IFF_UP; 889 #ifdef HYLOG 890 hylog(HYL_UP, 0, (char *)0); 891 #endif 892 } else { 893 is->hy_state = WAITING; 894 is->hy_retry = 0; 895 hystart(ui, HYF_WAITFORMSG, 0, 0); 896 } 897 } 898 break; 899 } 900 901 case STATSENT: 902 bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status, 903 sizeof (struct hy_status)); 904 #ifdef DEBUG 905 printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 906 ui->ui_unit, is->hy_status.hys_gen_status, 907 is->hy_status.hys_last_fcn, 908 is->hy_status.hys_resp_trunk, 909 is->hy_status.hys_status_trunk, 910 is->hy_status.hys_recd_resp, 911 is->hy_status.hys_error, 912 is->hy_status.hys_caddr, 913 is->hy_status.hys_pad); 914 #endif 915 is->hy_state = IDLE; 916 #ifdef HYLOG 917 hylog(HYL_STATUS, sizeof (struct hy_status), 918 (char *)&is->hy_status); 919 #endif 920 #ifdef HYELOG 921 { 922 register int i; 923 924 i = is->hy_status.hys_error; 925 if (i > HYE_MAX) 926 i = HYE_MAX; 927 switch (is->hy_status.hys_last_fcn) { 928 case HYF_XMITLOCMSG: 929 i += HYE_MAX+1; /* fall through */ 930 case HYF_XMITLSTDATA: 931 i += HYE_MAX+1; /* fall through */ 932 case HYF_XMITMSG: 933 i += HYE_MAX+1; 934 } 935 hy_elog[i]++; 936 } 937 #endif 938 break; 939 940 case RSTATSENT: { 941 register struct hy_stat *p = 942 (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 943 944 bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat)); 945 #ifdef DEBUG 946 947 printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n", 948 ui->ui_unit, 949 (is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2], 950 (is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2], 951 (is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2], 952 (is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]); 953 printD(" ret0 %d ret1 %d ret2 %d ret3 %d\n", 954 (is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2], 955 (is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2], 956 (is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2], 957 (is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]); 958 printD(" cancel %d abort %d atype %x %x %x uaddr %x\n", 959 (is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1], 960 (is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1], 961 is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 962 is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 963 #endif 964 is->hy_state = IDLE; 965 #ifdef HYLOG 966 hylog(HYL_STATISTICS, sizeof (struct hy_stat), 967 (char *)&is->hy_stat); 968 #endif 969 break; 970 } 971 972 case CLEARSENT: 973 is->hy_state = IDLE; 974 break; 975 976 case ENDOPSENT: 977 is->hy_state = IDLE; 978 break; 979 980 case RECVSENT: { 981 register struct hym_hdr *hym; 982 register unsigned len; 983 984 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 985 UBAPURGE(is->hy_ifuba.ifu_uba, 986 is->hy_ifuba.ifu_r.ifrw_bdp); 987 hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 988 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 989 if (len > MPSIZE) { 990 printf("hy%d: RECVD MP > MPSIZE (%d)\n", 991 ui->ui_unit, len); 992 is->hy_state = IDLE; 993 #ifdef DEBUG 994 hy_debug_flag = 1; 995 printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 996 ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 997 addr->hyd_bar, addr->hyd_wcr); 998 #endif 999 } 1000 hym->hym_mplen = len; 1001 #ifdef DEBUG 1002 printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 1003 if (hy_debug_flag) 1004 hyprintdata((char *)hym, len + HYM_SWLEN); 1005 #endif 1006 if (hym->hym_ctl & H_ASSOC) { 1007 is->hy_state = RECVDATASENT; 1008 is->hy_retry = 0; 1009 hystart(ui, HYF_INPUTDATA, 1010 (int)(HYMTU + sizeof (struct hy_hdr) - len), 1011 (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len)); 1012 } else { 1013 hyrecvdata(ui, hym, (int)len + HYM_SWLEN); 1014 is->hy_state = IDLE; 1015 } 1016 break; 1017 } 1018 1019 case RECVDATASENT: { 1020 register struct hym_hdr *hym; 1021 register unsigned len; 1022 1023 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 1024 UBAPURGE(is->hy_ifuba.ifu_uba, 1025 is->hy_ifuba.ifu_r.ifrw_bdp); 1026 hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 1027 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 1028 #ifdef DEBUG 1029 printD("hy%d: recvd assoc data, len = %d, data = ", 1030 ui->ui_unit, len); 1031 if (hy_debug_flag) 1032 hyprintdata((char *)hym + hym->hym_mplen, len); 1033 #endif 1034 hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN)); 1035 is->hy_state = IDLE; 1036 break; 1037 } 1038 1039 case XMITSENT: 1040 if (is->hy_flags & RQ_XASSOC) { 1041 register int len; 1042 1043 is->hy_flags &= ~RQ_XASSOC; 1044 is->hy_state = XMITDATASENT; 1045 is->hy_retry = 0; 1046 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 1047 if (len > is->hy_olen) { 1048 printf( 1049 "hy%d: xmit error - len > hy_olen [%d > %d]\n", 1050 ui->ui_unit, len, is->hy_olen); 1051 #ifdef DEBUG 1052 hy_debug_flag = 1; 1053 #endif 1054 } 1055 hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 1056 is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len); 1057 break; 1058 } 1059 /* fall through to ... */ 1060 1061 case XMITDATASENT: 1062 hyxmitdata(ui); 1063 is->hy_state = IDLE; 1064 break; 1065 1066 case WAITING: /* wait for message complete or output requested */ 1067 if (HYS_RECVDATA(addr)) 1068 is->hy_state = IDLE; 1069 else { 1070 is->hy_state = CLEARSENT; 1071 is->hy_retry = 0; 1072 hystart(ui, HYF_CLRWFMSG, 0, 0); 1073 } 1074 break; 1075 1076 case MARKPORT: 1077 is->hy_state = STARTUP; 1078 if_down(&is->hy_if); 1079 is->hy_if.if_flags &= ~IFF_UP; 1080 goto endintr; 1081 1082 default: 1083 printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 1084 ui->ui_unit, is->hy_state); 1085 panic("HYPERCHANNEL IN INVALID STATE"); 1086 /*NOTREACHED*/ 1087 } 1088 if (is->hy_state == IDLE) 1089 goto actloop; 1090 endintr: 1091 ; 1092 #ifdef DEBUG 1093 printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 1094 hy_state_names[is->hy_state]); 1095 #endif 1096 } 1097 1098 struct sockproto hypproto = { PF_HYLINK }; 1099 struct sockaddr_in hypdst = { AF_HYLINK }; 1100 struct sockaddr_in hypsrc = { AF_HYLINK }; 1101 1102 /* 1103 * Called from device interrupt when receiving data. 1104 * Examine packet to determine type. Decapsulate packet 1105 * based on type and pass to type specific higher-level 1106 * input routine. 1107 */ 1108 hyrecvdata(ui, hym, len) 1109 struct uba_device *ui; 1110 register struct hym_hdr *hym; 1111 int len; 1112 { 1113 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 1114 struct mbuf *m; 1115 register struct ifqueue *inq; 1116 1117 is->hy_if.if_ipackets++; 1118 #ifdef DEBUG 1119 printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len); 1120 #endif 1121 #ifdef HYLOG 1122 { 1123 struct { 1124 short hlen; 1125 struct hym_hdr hhdr; 1126 } hh; 1127 hh.hlen = len; 1128 hh.hhdr = *hym; 1129 hylog(HYL_RECV, sizeof(hh), (char *)&hh); 1130 } 1131 #endif 1132 if (len > HYMTU + MPSIZE || len == 0) 1133 return; /* sanity */ 1134 /* 1135 * Pull packet off interface. 1136 */ 1137 m = if_rubaget(&is->hy_ifuba, len, 0, &is->hy_if); 1138 if (m == NULL) 1139 return; 1140 1141 /* 1142 * if normal or adapter loopback response packet believe hym_type, 1143 * otherwise, use the raw input queue cause it's a response from an 1144 * adapter command. 1145 */ 1146 if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff) 1147 goto rawlinkin; 1148 1149 switch (hym->hym_type) { 1150 1151 #ifdef INET 1152 case HYLINK_IP: 1153 schednetisr(NETISR_IP); 1154 inq = &ipintrq; 1155 break; 1156 #endif 1157 default: 1158 rawlinkin: 1159 { 1160 M_PREPEND(m, sizeof(struct hym_hdr), M_DONTWAIT); 1161 if (m == 0) { 1162 m_freem(m); 1163 return; 1164 } 1165 bcopy((caddr_t)hym, mtod(m, caddr_t), sizeof(struct hym_hdr)); 1166 hypproto.sp_protocol = 0; 1167 hypdst.sin_addr = is->hy_addr; 1168 hypsrc.sin_addr = is->hy_addr; 1169 raw_input(m, &hypproto, (struct sockaddr *)&hypsrc, 1170 (struct sockaddr *)&hypdst); 1171 return; 1172 } 1173 } 1174 if (IF_QFULL(inq)) { 1175 IF_DROP(inq); 1176 m_freem(m); 1177 } else 1178 IF_ENQUEUE(inq, m); 1179 } 1180 1181 /* 1182 * Transmit done, release resources, bump counters. 1183 */ 1184 hyxmitdata(ui) 1185 struct uba_device *ui; 1186 { 1187 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 1188 1189 is->hy_if.if_opackets++; 1190 if (is->hy_ifuba.ifu_xtofree) { 1191 m_freem(is->hy_ifuba.ifu_xtofree); 1192 is->hy_ifuba.ifu_xtofree = 0; 1193 } 1194 } 1195 1196 hycancel(ui) 1197 register struct uba_device *ui; 1198 { 1199 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 1200 1201 if (is->hy_ifuba.ifu_xtofree) { 1202 m_freem(is->hy_ifuba.ifu_xtofree); 1203 is->hy_ifuba.ifu_xtofree = 0; 1204 } 1205 #ifdef HYLOG 1206 hylog(HYL_CANCEL, 0, (char *)0); 1207 #endif 1208 #ifdef DEBUG 1209 if (hy_nodebug & 1) 1210 hy_debug_flag = 1; 1211 #endif 1212 #ifdef DEBUG 1213 printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 1214 ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 1215 is->hy_savedcount, is->hy_savedaddr); 1216 printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 1217 is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 1218 printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 1219 is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 1220 is->hy_savedcmd); 1221 #endif 1222 is->hy_state = IDLE; 1223 is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 1224 hyact(ui); 1225 } 1226 1227 #ifdef DEBUG 1228 hyprintdata(cp, len) 1229 register char *cp; 1230 register int len; 1231 { 1232 register int count = 16; 1233 register char *fmt; 1234 static char regfmt[] = "\n\t %x"; 1235 1236 fmt = ®fmt[2]; 1237 while (--len >= 0) { 1238 printL(fmt, *cp++ & 0xff); 1239 fmt = ®fmt[2]; 1240 if (--count <= 0) { 1241 fmt = ®fmt[0]; 1242 count = 16; 1243 } 1244 } 1245 printL("\n"); 1246 } 1247 #endif 1248 1249 hywatch(unit) 1250 int unit; 1251 { 1252 register struct hy_softc *is = &hy_softc[unit]; 1253 register struct uba_device *ui = hyinfo[unit]; 1254 register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 1255 int s; 1256 1257 s = splimp(); 1258 #ifdef PI13 1259 if ((addr->hyd_csr & S_POWEROFF) != 0) { 1260 addr->hyd_csr |= S_POWEROFF; 1261 DELAY(100); 1262 if ((addr->hyd_csr & S_POWEROFF) == 0) { 1263 printf("hy%d: Adapter Power Restored (hywatch)\n", unit); 1264 is->hy_state = IDLE; 1265 is->hy_flags |= 1266 (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 1267 hyact(ui); 1268 } 1269 } 1270 #endif 1271 if (++is->hy_ntime >= 2 && is->hy_state != WAITING && 1272 is->hy_state != STARTUP && is->hy_state != IDLE) { 1273 #ifdef HYLOG 1274 printf("hy%d: watchdog timer expired in state \"%s\"\n", unit, 1275 hy_state_names[is->hy_state]); 1276 #else 1277 printf("hy%d: watchdog timer expired in state %d\n", unit, 1278 is->hy_state); 1279 #endif 1280 printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit, 1281 is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS); 1282 hycancel(ui); 1283 } 1284 splx(s); 1285 is->hy_if.if_timer = SCANINTERVAL; 1286 } 1287 1288 #ifdef HYLOG 1289 hylog(code, len, ptr) 1290 int code, len; 1291 char *ptr; 1292 { 1293 register unsigned char *p; 1294 int s; 1295 1296 s = splimp(); 1297 if (hy_log.hyl_self != &hy_log) { 1298 hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 1299 hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 1300 hy_log.hyl_self = &hy_log; 1301 hy_log.hyl_enable = HYL_CONTINUOUS; 1302 hy_log.hyl_onerr = HYL_CONTINUOUS; 1303 hy_log.hyl_count = 0; 1304 hy_log.hyl_icount = 16; 1305 hy_log.hyl_filter = 0xffff; /* enable all */ 1306 } 1307 if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0) 1308 goto out; 1309 p = hy_log.hyl_ptr; 1310 if (p + len + 3 >= hy_log.hyl_eptr) { 1311 bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 1312 p = &hy_log.hyl_buf[0]; 1313 if (hy_log.hyl_enable != HYL_CONTINUOUS) { 1314 hy_log.hyl_enable = HYL_DISABLED; 1315 goto out; 1316 } 1317 } 1318 *p++ = code; 1319 *p++ = len; 1320 bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len); 1321 if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) { 1322 *p++ = '\0'; 1323 hy_log.hyl_enable = HYL_DISABLED; 1324 hy_log.hyl_count = hy_log.hyl_icount; 1325 } 1326 p += len; 1327 if (hy_log.hyl_wait != 0) { /* wakeup HYGETLOG if wanted */ 1328 if (hy_log.hyl_wait <= p - hy_log.hyl_ptr) { 1329 wakeup((caddr_t)&hy_log); 1330 hy_log.hyl_wait = 0; 1331 } else 1332 hy_log.hyl_wait -= p - hy_log.hyl_ptr; 1333 } 1334 hy_log.hyl_ptr = p; 1335 out: 1336 splx(s); 1337 } 1338 #endif 1339 1340 /*ARGSUSED*/ 1341 hyioctl(ifp, cmd, data) 1342 register struct ifnet *ifp; 1343 int cmd; 1344 caddr_t data; 1345 { 1346 struct ifaddr *ifa = (struct ifaddr *) data; 1347 struct hyrsetget *sg = (struct hyrsetget *)data; 1348 #if defined(HYLOG) || defined(HYELOG) 1349 struct hylsetget *sgl = (struct hylsetget *)data; 1350 #endif 1351 struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit]; 1352 int s = splimp(), error = 0; 1353 #ifdef HYLOG 1354 struct hy_softc *is = &hy_softc[ifp->if_unit]; 1355 struct { 1356 u_char hstate; 1357 u_char hflags; 1358 u_short iflags; 1359 int hcmd; 1360 int herror; 1361 u_long haddr; 1362 u_long hmisc; 1363 } hil; 1364 1365 hil.hmisc = -1; 1366 hil.hstate = is->hy_state; 1367 hil.hflags = is->hy_flags; 1368 hil.hcmd = cmd; 1369 #endif 1370 1371 switch(cmd) { 1372 1373 case SIOCSIFADDR: 1374 if (ifa->ifa_addr.sa_family != AF_INET) 1375 return(EINVAL); 1376 if ((ifp->if_flags & IFF_RUNNING) == 0) 1377 hyinit(ifp->if_unit); 1378 hy_softc[ifp->if_unit].hy_addr = IA_SIN(ifa)->sin_addr; 1379 #ifdef HYLOG 1380 hil.haddr = is->hy_addr.s_addr; 1381 #endif 1382 break; 1383 1384 case HYSETROUTE: 1385 if (!suser()) { 1386 error = EPERM; 1387 goto out; 1388 } 1389 1390 if (sg->hyrsg_len != sizeof(struct hy_route)) { 1391 error = EINVAL; 1392 goto out; 1393 } 1394 if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) { 1395 r->hyr_lasttime = 0; /* disable further routing if trouble */ 1396 error = EFAULT; 1397 goto out; 1398 } 1399 r->hyr_lasttime = time.tv_sec; 1400 #ifdef HYLOG 1401 hil.hmisc = r->hyr_lasttime; 1402 #endif 1403 break; 1404 1405 case HYGETROUTE: 1406 if (sg->hyrsg_len < sizeof(struct hy_route)) { 1407 error = EINVAL; 1408 goto out; 1409 } 1410 if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) { 1411 error = EFAULT; 1412 goto out; 1413 } 1414 break; 1415 1416 #ifdef HYELOG 1417 case HYGETELOG: 1418 if (sgl->hylsg_len < sizeof(hy_elog)) { 1419 error = EINVAL; 1420 goto out; 1421 } 1422 if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) { 1423 error = EFAULT; 1424 goto out; 1425 } 1426 if (sgl->hylsg_cmd) { 1427 if (!suser()) { 1428 error = EPERM; 1429 goto out; 1430 } 1431 bzero((caddr_t)hy_elog, sizeof(hy_elog)); 1432 } 1433 break; 1434 #endif 1435 1436 #ifdef HYLOG 1437 case HYSETLOG: 1438 if (!suser()) { 1439 error = EPERM; 1440 goto out; 1441 } 1442 hy_log.hyl_enable = HYL_DISABLED; 1443 hylog(HYL_NOP, 0, (char *)0); /* force log init */ 1444 hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f; 1445 hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f; 1446 hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff; 1447 hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len; 1448 wakeup((caddr_t)&hy_log); /* wakeup sleeping HYGETLOG */ 1449 break; 1450 1451 case HYGETLOG: 1452 if (sgl->hylsg_len < sizeof(hy_log)) { 1453 error = EINVAL; 1454 goto out; 1455 } 1456 if (sgl->hylsg_cmd != 0) { 1457 if (hy_log.hyl_wait) { 1458 error = EBUSY; 1459 goto out; 1460 } 1461 hy_log.hyl_wait = sgl->hylsg_cmd; 1462 sleep((caddr_t)&hy_log, PZERO - 1); 1463 } 1464 1465 if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) { 1466 error = EFAULT; 1467 goto out; 1468 } 1469 break; 1470 #endif 1471 1472 default: 1473 error = EINVAL; 1474 break; 1475 } 1476 out: 1477 #ifdef HYLOG 1478 hil.herror = error; 1479 hil.iflags = ifp->if_flags; 1480 hil.haddr = is->hy_addr.s_addr; 1481 hylog(HYL_IOCTL, sizeof(hil), (char *)&hil); 1482 #endif 1483 splx(s); 1484 return (error); 1485 } 1486 #endif 1487