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.2 (Berkeley) 08/04/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 if (m->m_off > MMAXOFF || 605 MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 606 m = m_get(M_DONTWAIT, MT_HEADER); 607 if (m == 0) { 608 m = m0; 609 error = ENOBUFS; 610 goto drop; 611 } 612 m->m_next = m0; 613 m->m_off = MMINOFF; 614 m->m_len = sizeof(struct hym_hdr); 615 } else { 616 m->m_off -= sizeof(struct hym_hdr); 617 m->m_len += sizeof(struct hym_hdr); 618 } 619 620 dlen += sizeof(struct hym_hdr) - HYM_SWLEN; 621 622 hym = mtod(m, struct hym_hdr *); 623 624 bzero((caddr_t)hym, sizeof(struct hym_hdr)); 625 626 switch(dst->sa_family) { 627 628 #ifdef INET 629 case AF_INET: { 630 int i; 631 632 /* 633 * if loopback address, swizzle ip header so when 634 * it comes back it looks like it was addressed to us 635 */ 636 i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym); 637 if (i < 0) 638 goto notfound; 639 if (i > 0) { 640 struct in_addr temp; 641 642 temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr; 643 ((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr; 644 ((struct ip *)mp)->ip_src.s_addr = temp.s_addr; 645 } 646 /* 647 * If entire packet won't fit in message proper, just 648 * send hyperchannel hardware header and ip header in 649 * message proper. 650 * 651 * This insures that the associated data is at least a 652 * TCP/UDP header in length and thus prevents potential 653 * problems with very short word counts. 654 */ 655 if (dlen > MPSIZE) 656 hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2); 657 hym->hym_type = HYLINK_IP; 658 break; 659 } 660 #endif 661 662 default: 663 printf("hy%d: can't handle af%d\n", ifp->if_unit, 664 dst->sa_family); 665 error = EAFNOSUPPORT; 666 goto drop; 667 } 668 669 670 headerexists: 671 672 /* 673 * insure message proper is below the maximum 674 */ 675 if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0)) 676 hym->hym_mplen = MPSIZE; 677 678 hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host); 679 if (hym->hym_mplen) 680 hym->hym_ctl |= H_ASSOC; 681 else 682 hym->hym_ctl &= ~H_ASSOC; 683 if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 684 ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 685 hym->hym_access, hym->hym_to, hym->hym_from, 686 hym->hym_param, hym->hym_type); 687 #ifdef DEBUG 688 printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 689 ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 690 hym->hym_access, hym->hym_to, hym->hym_from, 691 hym->hym_param, hym->hym_type); 692 #endif 693 s = splimp(); 694 if (IF_QFULL(&ifp->if_snd)) { 695 IF_DROP(&ifp->if_snd); 696 error = ENOBUFS; 697 splx(s); 698 goto drop; 699 } 700 IF_ENQUEUE(&ifp->if_snd, m); 701 if (hy_softc[ifp->if_unit].hy_state == WAITING) 702 hyact(hyinfo[ifp->if_unit]); 703 splx(s); 704 return (0); 705 notfound: 706 error = EHOSTUNREACH; 707 drop: 708 m_freem(m); 709 return (error); 710 } 711 712 int 713 hyroute(ifp, dest, hym) 714 register struct ifnet *ifp; 715 u_long dest; 716 register struct hym_hdr *hym; 717 { 718 #ifdef HYROUTE 719 register struct hy_route *rt = &hy_route[ifp->if_unit]; 720 register struct hyr_hash *rhash; 721 register int i; 722 #endif 723 724 hym->hym_param = 0; 725 #ifdef HYROUTE 726 if (rt->hyr_lasttime != 0) { 727 i = HYRHASH(dest); 728 rhash = &rt->hyr_hash[i]; 729 i = 0; 730 while (rhash->hyr_key != dest) { 731 if (rhash->hyr_flags == 0 || i > HYRSIZE) 732 return(-1); 733 rhash++; i++; 734 if (rhash >= &rt->hyr_hash[HYRSIZE]) 735 rhash = &rt->hyr_hash[0]; 736 } 737 if (rhash->hyr_flags & HYR_GATE) { 738 i = rhash->hyr_nextgate; 739 if (i >= rhash->hyr_egate) 740 rhash->hyr_nextgate = rhash->hyr_pgate; 741 else 742 rhash->hyr_nextgate++; 743 rhash = &rt->hyr_hash[rt->hyr_gateway[i]]; 744 if ((rhash->hyr_flags & HYR_DIR) == 0) 745 return(-1); 746 } else if (rhash->hyr_flags & HYR_LOOP) { 747 hym->hym_param = H_LOOPBK; /* adapter loopback */ 748 } else if (rhash->hyr_flags & HYR_RLOOP) { 749 hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 750 } 751 hym->hym_ctl = rhash->hyr_ctl; 752 hym->hym_access = rhash->hyr_access; 753 hym->hym_to = rhash->hyr_dst; 754 } else { 755 #endif 756 hym->hym_ctl = H_XTRUNKS | H_RTRUNKS; 757 hym->hym_access = 0; 758 hym->hym_to = htons((u_short)dest); 759 if (dest & 0x010000) 760 hym->hym_param = H_LOOPBK; /* adapter loopback */ 761 else if (dest & 0x020000) 762 hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 763 #ifdef HYROUTE 764 } 765 #endif 766 767 if (hym->hym_param == 0) 768 return(0); 769 else 770 return(1); 771 } 772 773 hyact(ui) 774 register struct uba_device *ui; 775 { 776 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 777 register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 778 779 actloop: 780 #ifdef DEBUG 781 printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 782 hy_state_names[is->hy_state]); 783 #endif 784 switch (is->hy_state) { 785 786 case STARTUP: 787 goto endintr; 788 789 case IDLE: { 790 register rq = is->hy_flags; 791 792 if (rq & RQ_STATUS) { 793 is->hy_flags &= ~RQ_STATUS; 794 is->hy_state = STATSENT; 795 hystart(ui, HYF_STATUS, sizeof (is->hy_status), 796 is->hy_ifuba.ifu_r.ifrw_info); 797 } else if (rq & RQ_ENDOP) { 798 is->hy_flags &= ~RQ_ENDOP; 799 is->hy_state = ENDOPSENT; 800 hystart(ui, HYF_END_OP, 0, 0); 801 } else if (rq & RQ_STATISTICS) { 802 is->hy_flags &= ~RQ_STATISTICS; 803 is->hy_state = RSTATSENT; 804 hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 805 is->hy_ifuba.ifu_r.ifrw_info); 806 } else if (HYS_RECVDATA(addr)) { 807 is->hy_state = RECVSENT; 808 is->hy_retry = 0; 809 hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN); 810 } else if (rq & RQ_REISSUE) { 811 is->hy_flags &= ~RQ_REISSUE; 812 is->hy_state = is->hy_savedstate; 813 #ifdef DEBUG 814 printD("hy%d: reissue cmd=0x%x count=%d", 815 ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 816 printD(" ubaddr=0x%x retry=%d\n", 817 is->hy_savedaddr, is->hy_retry); 818 #endif 819 hystart(ui, is->hy_savedcmd, is->hy_savedcount, 820 is->hy_savedaddr); 821 } else { 822 register struct mbuf *m; 823 824 IF_DEQUEUE(&is->hy_if.if_snd, m); 825 if (m != NULL) { 826 register struct hym_hdr *hym; 827 register int mplen; 828 register int cmd; 829 830 is->hy_state = XMITSENT; 831 is->hy_retry = 0; 832 hym = mtod(m, struct hym_hdr *); 833 #ifdef HYLOG 834 hylog(HYL_XMIT, sizeof(struct hym_hdr), 835 (char *)hym); 836 #endif 837 mplen = hym->hym_mplen; 838 if (hym->hym_to_adapter == hym->hym_from_adapter) 839 cmd = HYF_XMITLOCMSG; 840 else 841 cmd = HYF_XMITMSG; 842 #ifdef DEBUG 843 printD("hy%d: hym_hdr = ", ui->ui_unit); 844 if (hy_debug_flag) 845 hyprintdata((char *)hym, 846 sizeof (struct hym_hdr)); 847 #endif 848 is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN; 849 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 850 UBAPURGE(is->hy_ifuba.ifu_uba, 851 is->hy_ifuba.ifu_w.ifrw_bdp); 852 #ifdef DEBUG 853 printD( 854 "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 855 ui->ui_unit, mplen, is->hy_olen); 856 if (hy_debug_flag) 857 hyprintdata( 858 is->hy_ifuba.ifu_w.ifrw_addr, 859 is->hy_olen + HYM_SWLEN); 860 #endif 861 if (mplen == 0) { 862 is->hy_flags &= ~RQ_XASSOC; 863 mplen = is->hy_olen; 864 } else { 865 is->hy_flags |= RQ_XASSOC; 866 } 867 hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN); 868 } else if (rq & RQ_MARKDOWN) { 869 is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 870 is->hy_state = MARKPORT; 871 is->hy_retry = 0; 872 /* 873 * Port number is taken from status data 874 */ 875 hystart(ui, 876 (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 877 0, 0); 878 } else if (rq & RQ_MARKUP) { 879 register struct ifnet *ifp = &is->hy_if; 880 881 is->hy_flags &= ~RQ_MARKUP; 882 is->hy_retry = 0; 883 /* 884 * Fill in the host number 885 * from the status buffer 886 */ 887 printf( 888 "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 889 ui->ui_unit, 890 is->hy_stat.hyc_uaddr, 891 PORTNUM(&is->hy_status), 892 (is->hy_stat.hyc_atype[0]<<8) | 893 is->hy_stat.hyc_atype[1], 894 is->hy_stat.hyc_atype[2]); 895 896 is->hy_host = 897 (is->hy_stat.hyc_uaddr << 8) | 898 PORTNUM(&is->hy_status); 899 ifp->if_flags |= IFF_UP; 900 #ifdef HYLOG 901 hylog(HYL_UP, 0, (char *)0); 902 #endif 903 } else { 904 is->hy_state = WAITING; 905 is->hy_retry = 0; 906 hystart(ui, HYF_WAITFORMSG, 0, 0); 907 } 908 } 909 break; 910 } 911 912 case STATSENT: 913 bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status, 914 sizeof (struct hy_status)); 915 #ifdef DEBUG 916 printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 917 ui->ui_unit, is->hy_status.hys_gen_status, 918 is->hy_status.hys_last_fcn, 919 is->hy_status.hys_resp_trunk, 920 is->hy_status.hys_status_trunk, 921 is->hy_status.hys_recd_resp, 922 is->hy_status.hys_error, 923 is->hy_status.hys_caddr, 924 is->hy_status.hys_pad); 925 #endif 926 is->hy_state = IDLE; 927 #ifdef HYLOG 928 hylog(HYL_STATUS, sizeof (struct hy_status), 929 (char *)&is->hy_status); 930 #endif 931 #ifdef HYELOG 932 { 933 register int i; 934 935 i = is->hy_status.hys_error; 936 if (i > HYE_MAX) 937 i = HYE_MAX; 938 switch (is->hy_status.hys_last_fcn) { 939 case HYF_XMITLOCMSG: 940 i += HYE_MAX+1; /* fall through */ 941 case HYF_XMITLSTDATA: 942 i += HYE_MAX+1; /* fall through */ 943 case HYF_XMITMSG: 944 i += HYE_MAX+1; 945 } 946 hy_elog[i]++; 947 } 948 #endif 949 break; 950 951 case RSTATSENT: { 952 register struct hy_stat *p = 953 (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 954 955 bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat)); 956 #ifdef DEBUG 957 958 printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n", 959 ui->ui_unit, 960 (is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2], 961 (is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2], 962 (is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2], 963 (is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]); 964 printD(" ret0 %d ret1 %d ret2 %d ret3 %d\n", 965 (is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2], 966 (is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2], 967 (is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2], 968 (is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]); 969 printD(" cancel %d abort %d atype %x %x %x uaddr %x\n", 970 (is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1], 971 (is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1], 972 is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 973 is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 974 #endif 975 is->hy_state = IDLE; 976 #ifdef HYLOG 977 hylog(HYL_STATISTICS, sizeof (struct hy_stat), 978 (char *)&is->hy_stat); 979 #endif 980 break; 981 } 982 983 case CLEARSENT: 984 is->hy_state = IDLE; 985 break; 986 987 case ENDOPSENT: 988 is->hy_state = IDLE; 989 break; 990 991 case RECVSENT: { 992 register struct hym_hdr *hym; 993 register unsigned len; 994 995 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 996 UBAPURGE(is->hy_ifuba.ifu_uba, 997 is->hy_ifuba.ifu_r.ifrw_bdp); 998 hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 999 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 1000 if (len > MPSIZE) { 1001 printf("hy%d: RECVD MP > MPSIZE (%d)\n", 1002 ui->ui_unit, len); 1003 is->hy_state = IDLE; 1004 #ifdef DEBUG 1005 hy_debug_flag = 1; 1006 printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 1007 ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 1008 addr->hyd_bar, addr->hyd_wcr); 1009 #endif 1010 } 1011 hym->hym_mplen = len; 1012 #ifdef DEBUG 1013 printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 1014 if (hy_debug_flag) 1015 hyprintdata((char *)hym, len + HYM_SWLEN); 1016 #endif 1017 if (hym->hym_ctl & H_ASSOC) { 1018 is->hy_state = RECVDATASENT; 1019 is->hy_retry = 0; 1020 hystart(ui, HYF_INPUTDATA, 1021 (int)(HYMTU + sizeof (struct hy_hdr) - len), 1022 (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len)); 1023 } else { 1024 hyrecvdata(ui, hym, (int)len + HYM_SWLEN); 1025 is->hy_state = IDLE; 1026 } 1027 break; 1028 } 1029 1030 case RECVDATASENT: { 1031 register struct hym_hdr *hym; 1032 register unsigned len; 1033 1034 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 1035 UBAPURGE(is->hy_ifuba.ifu_uba, 1036 is->hy_ifuba.ifu_r.ifrw_bdp); 1037 hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 1038 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 1039 #ifdef DEBUG 1040 printD("hy%d: recvd assoc data, len = %d, data = ", 1041 ui->ui_unit, len); 1042 if (hy_debug_flag) 1043 hyprintdata((char *)hym + hym->hym_mplen, len); 1044 #endif 1045 hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN)); 1046 is->hy_state = IDLE; 1047 break; 1048 } 1049 1050 case XMITSENT: 1051 if (is->hy_flags & RQ_XASSOC) { 1052 register int len; 1053 1054 is->hy_flags &= ~RQ_XASSOC; 1055 is->hy_state = XMITDATASENT; 1056 is->hy_retry = 0; 1057 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 1058 if (len > is->hy_olen) { 1059 printf( 1060 "hy%d: xmit error - len > hy_olen [%d > %d]\n", 1061 ui->ui_unit, len, is->hy_olen); 1062 #ifdef DEBUG 1063 hy_debug_flag = 1; 1064 #endif 1065 } 1066 hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 1067 is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len); 1068 break; 1069 } 1070 /* fall through to ... */ 1071 1072 case XMITDATASENT: 1073 hyxmitdata(ui); 1074 is->hy_state = IDLE; 1075 break; 1076 1077 case WAITING: /* wait for message complete or output requested */ 1078 if (HYS_RECVDATA(addr)) 1079 is->hy_state = IDLE; 1080 else { 1081 is->hy_state = CLEARSENT; 1082 is->hy_retry = 0; 1083 hystart(ui, HYF_CLRWFMSG, 0, 0); 1084 } 1085 break; 1086 1087 case MARKPORT: 1088 is->hy_state = STARTUP; 1089 if_down(&is->hy_if); 1090 is->hy_if.if_flags &= ~IFF_UP; 1091 goto endintr; 1092 1093 default: 1094 printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 1095 ui->ui_unit, is->hy_state); 1096 panic("HYPERCHANNEL IN INVALID STATE"); 1097 /*NOTREACHED*/ 1098 } 1099 if (is->hy_state == IDLE) 1100 goto actloop; 1101 endintr: 1102 ; 1103 #ifdef DEBUG 1104 printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 1105 hy_state_names[is->hy_state]); 1106 #endif 1107 } 1108 1109 struct sockproto hypproto = { PF_HYLINK }; 1110 struct sockaddr_in hypdst = { AF_HYLINK }; 1111 struct sockaddr_in hypsrc = { AF_HYLINK }; 1112 1113 /* 1114 * Called from device interrupt when receiving data. 1115 * Examine packet to determine type. Decapsulate packet 1116 * based on type and pass to type specific higher-level 1117 * input routine. 1118 */ 1119 hyrecvdata(ui, hym, len) 1120 struct uba_device *ui; 1121 register struct hym_hdr *hym; 1122 int len; 1123 { 1124 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 1125 struct mbuf *m; 1126 register struct ifqueue *inq; 1127 1128 is->hy_if.if_ipackets++; 1129 #ifdef DEBUG 1130 printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len); 1131 #endif 1132 #ifdef HYLOG 1133 { 1134 struct { 1135 short hlen; 1136 struct hym_hdr hhdr; 1137 } hh; 1138 hh.hlen = len; 1139 hh.hhdr = *hym; 1140 hylog(HYL_RECV, sizeof(hh), (char *)&hh); 1141 } 1142 #endif 1143 if (len > HYMTU + MPSIZE || len == 0) 1144 return; /* sanity */ 1145 /* 1146 * Pull packet off interface. 1147 */ 1148 m = if_rubaget(&is->hy_ifuba, len, 0, &is->hy_if); 1149 if (m == NULL) 1150 return; 1151 1152 /* 1153 * if normal or adapter loopback response packet believe hym_type, 1154 * otherwise, use the raw input queue cause it's a response from an 1155 * adapter command. 1156 */ 1157 if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff) 1158 goto rawlinkin; 1159 1160 switch (hym->hym_type) { 1161 1162 #ifdef INET 1163 case HYLINK_IP: 1164 schednetisr(NETISR_IP); 1165 inq = &ipintrq; 1166 break; 1167 #endif 1168 default: 1169 rawlinkin: 1170 { 1171 struct mbuf *m0; 1172 1173 MGET(m0, M_DONTWAIT, MT_DATA); 1174 if (m0 == 0) { 1175 m_freem(m); 1176 return; 1177 } 1178 m0->m_off = MMINOFF; 1179 m0->m_len = sizeof(struct hym_hdr); 1180 m0->m_next = m; 1181 bcopy((caddr_t)hym, mtod(m0, caddr_t), sizeof(struct hym_hdr)); 1182 m = m0; 1183 hypproto.sp_protocol = 0; 1184 hypdst.sin_addr = is->hy_addr; 1185 hypsrc.sin_addr = is->hy_addr; 1186 raw_input(m, &hypproto, (struct sockaddr *)&hypsrc, 1187 (struct sockaddr *)&hypdst); 1188 return; 1189 } 1190 } 1191 if (IF_QFULL(inq)) { 1192 IF_DROP(inq); 1193 m_freem(m); 1194 } else 1195 IF_ENQUEUE(inq, m); 1196 } 1197 1198 /* 1199 * Transmit done, release resources, bump counters. 1200 */ 1201 hyxmitdata(ui) 1202 struct uba_device *ui; 1203 { 1204 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 1205 1206 is->hy_if.if_opackets++; 1207 if (is->hy_ifuba.ifu_xtofree) { 1208 m_freem(is->hy_ifuba.ifu_xtofree); 1209 is->hy_ifuba.ifu_xtofree = 0; 1210 } 1211 } 1212 1213 hycancel(ui) 1214 register struct uba_device *ui; 1215 { 1216 register struct hy_softc *is = &hy_softc[ui->ui_unit]; 1217 1218 if (is->hy_ifuba.ifu_xtofree) { 1219 m_freem(is->hy_ifuba.ifu_xtofree); 1220 is->hy_ifuba.ifu_xtofree = 0; 1221 } 1222 #ifdef HYLOG 1223 hylog(HYL_CANCEL, 0, (char *)0); 1224 #endif 1225 #ifdef DEBUG 1226 if (hy_nodebug & 1) 1227 hy_debug_flag = 1; 1228 #endif 1229 #ifdef DEBUG 1230 printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 1231 ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 1232 is->hy_savedcount, is->hy_savedaddr); 1233 printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 1234 is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 1235 printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 1236 is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 1237 is->hy_savedcmd); 1238 #endif 1239 is->hy_state = IDLE; 1240 is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 1241 hyact(ui); 1242 } 1243 1244 #ifdef DEBUG 1245 hyprintdata(cp, len) 1246 register char *cp; 1247 register int len; 1248 { 1249 register int count = 16; 1250 register char *fmt; 1251 static char regfmt[] = "\n\t %x"; 1252 1253 fmt = ®fmt[2]; 1254 while (--len >= 0) { 1255 printL(fmt, *cp++ & 0xff); 1256 fmt = ®fmt[2]; 1257 if (--count <= 0) { 1258 fmt = ®fmt[0]; 1259 count = 16; 1260 } 1261 } 1262 printL("\n"); 1263 } 1264 #endif 1265 1266 hywatch(unit) 1267 int unit; 1268 { 1269 register struct hy_softc *is = &hy_softc[unit]; 1270 register struct uba_device *ui = hyinfo[unit]; 1271 register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 1272 int s; 1273 1274 s = splimp(); 1275 #ifdef PI13 1276 if ((addr->hyd_csr & S_POWEROFF) != 0) { 1277 addr->hyd_csr |= S_POWEROFF; 1278 DELAY(100); 1279 if ((addr->hyd_csr & S_POWEROFF) == 0) { 1280 printf("hy%d: Adapter Power Restored (hywatch)\n", unit); 1281 is->hy_state = IDLE; 1282 is->hy_flags |= 1283 (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 1284 hyact(ui); 1285 } 1286 } 1287 #endif 1288 if (++is->hy_ntime >= 2 && is->hy_state != WAITING && 1289 is->hy_state != STARTUP && is->hy_state != IDLE) { 1290 #ifdef HYLOG 1291 printf("hy%d: watchdog timer expired in state \"%s\"\n", unit, 1292 hy_state_names[is->hy_state]); 1293 #else 1294 printf("hy%d: watchdog timer expired in state %d\n", unit, 1295 is->hy_state); 1296 #endif 1297 printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit, 1298 is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS); 1299 hycancel(ui); 1300 } 1301 splx(s); 1302 is->hy_if.if_timer = SCANINTERVAL; 1303 } 1304 1305 #ifdef HYLOG 1306 hylog(code, len, ptr) 1307 int code, len; 1308 char *ptr; 1309 { 1310 register unsigned char *p; 1311 int s; 1312 1313 s = splimp(); 1314 if (hy_log.hyl_self != &hy_log) { 1315 hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 1316 hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 1317 hy_log.hyl_self = &hy_log; 1318 hy_log.hyl_enable = HYL_CONTINUOUS; 1319 hy_log.hyl_onerr = HYL_CONTINUOUS; 1320 hy_log.hyl_count = 0; 1321 hy_log.hyl_icount = 16; 1322 hy_log.hyl_filter = 0xffff; /* enable all */ 1323 } 1324 if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0) 1325 goto out; 1326 p = hy_log.hyl_ptr; 1327 if (p + len + 3 >= hy_log.hyl_eptr) { 1328 bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 1329 p = &hy_log.hyl_buf[0]; 1330 if (hy_log.hyl_enable != HYL_CONTINUOUS) { 1331 hy_log.hyl_enable = HYL_DISABLED; 1332 goto out; 1333 } 1334 } 1335 *p++ = code; 1336 *p++ = len; 1337 bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len); 1338 if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) { 1339 *p++ = '\0'; 1340 hy_log.hyl_enable = HYL_DISABLED; 1341 hy_log.hyl_count = hy_log.hyl_icount; 1342 } 1343 p += len; 1344 if (hy_log.hyl_wait != 0) { /* wakeup HYGETLOG if wanted */ 1345 if (hy_log.hyl_wait <= p - hy_log.hyl_ptr) { 1346 wakeup((caddr_t)&hy_log); 1347 hy_log.hyl_wait = 0; 1348 } else 1349 hy_log.hyl_wait -= p - hy_log.hyl_ptr; 1350 } 1351 hy_log.hyl_ptr = p; 1352 out: 1353 splx(s); 1354 } 1355 #endif 1356 1357 /*ARGSUSED*/ 1358 hyioctl(ifp, cmd, data) 1359 register struct ifnet *ifp; 1360 int cmd; 1361 caddr_t data; 1362 { 1363 struct ifaddr *ifa = (struct ifaddr *) data; 1364 struct hyrsetget *sg = (struct hyrsetget *)data; 1365 #if defined(HYLOG) || defined(HYELOG) 1366 struct hylsetget *sgl = (struct hylsetget *)data; 1367 #endif 1368 struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit]; 1369 int s = splimp(), error = 0; 1370 #ifdef HYLOG 1371 struct hy_softc *is = &hy_softc[ifp->if_unit]; 1372 struct { 1373 u_char hstate; 1374 u_char hflags; 1375 u_short iflags; 1376 int hcmd; 1377 int herror; 1378 u_long haddr; 1379 u_long hmisc; 1380 } hil; 1381 1382 hil.hmisc = -1; 1383 hil.hstate = is->hy_state; 1384 hil.hflags = is->hy_flags; 1385 hil.hcmd = cmd; 1386 #endif 1387 1388 switch(cmd) { 1389 1390 case SIOCSIFADDR: 1391 if (ifa->ifa_addr.sa_family != AF_INET) 1392 return(EINVAL); 1393 if ((ifp->if_flags & IFF_RUNNING) == 0) 1394 hyinit(ifp->if_unit); 1395 hy_softc[ifp->if_unit].hy_addr = IA_SIN(ifa)->sin_addr; 1396 #ifdef HYLOG 1397 hil.haddr = is->hy_addr.s_addr; 1398 #endif 1399 break; 1400 1401 case HYSETROUTE: 1402 if (!suser()) { 1403 error = EPERM; 1404 goto out; 1405 } 1406 1407 if (sg->hyrsg_len != sizeof(struct hy_route)) { 1408 error = EINVAL; 1409 goto out; 1410 } 1411 if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) { 1412 r->hyr_lasttime = 0; /* disable further routing if trouble */ 1413 error = EFAULT; 1414 goto out; 1415 } 1416 r->hyr_lasttime = time.tv_sec; 1417 #ifdef HYLOG 1418 hil.hmisc = r->hyr_lasttime; 1419 #endif 1420 break; 1421 1422 case HYGETROUTE: 1423 if (sg->hyrsg_len < sizeof(struct hy_route)) { 1424 error = EINVAL; 1425 goto out; 1426 } 1427 if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) { 1428 error = EFAULT; 1429 goto out; 1430 } 1431 break; 1432 1433 #ifdef HYELOG 1434 case HYGETELOG: 1435 if (sgl->hylsg_len < sizeof(hy_elog)) { 1436 error = EINVAL; 1437 goto out; 1438 } 1439 if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) { 1440 error = EFAULT; 1441 goto out; 1442 } 1443 if (sgl->hylsg_cmd) { 1444 if (!suser()) { 1445 error = EPERM; 1446 goto out; 1447 } 1448 bzero((caddr_t)hy_elog, sizeof(hy_elog)); 1449 } 1450 break; 1451 #endif 1452 1453 #ifdef HYLOG 1454 case HYSETLOG: 1455 if (!suser()) { 1456 error = EPERM; 1457 goto out; 1458 } 1459 hy_log.hyl_enable = HYL_DISABLED; 1460 hylog(HYL_NOP, 0, (char *)0); /* force log init */ 1461 hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f; 1462 hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f; 1463 hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff; 1464 hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len; 1465 wakeup((caddr_t)&hy_log); /* wakeup sleeping HYGETLOG */ 1466 break; 1467 1468 case HYGETLOG: 1469 if (sgl->hylsg_len < sizeof(hy_log)) { 1470 error = EINVAL; 1471 goto out; 1472 } 1473 if (sgl->hylsg_cmd != 0) { 1474 if (hy_log.hyl_wait) { 1475 error = EBUSY; 1476 goto out; 1477 } 1478 hy_log.hyl_wait = sgl->hylsg_cmd; 1479 sleep((caddr_t)&hy_log, PZERO - 1); 1480 } 1481 1482 if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) { 1483 error = EFAULT; 1484 goto out; 1485 } 1486 break; 1487 #endif 1488 1489 default: 1490 error = EINVAL; 1491 break; 1492 } 1493 out: 1494 #ifdef HYLOG 1495 hil.herror = error; 1496 hil.iflags = ifp->if_flags; 1497 hil.haddr = is->hy_addr.s_addr; 1498 hylog(HYL_IOCTL, sizeof(hil), (char *)&hil); 1499 #endif 1500 splx(s); 1501 return (error); 1502 } 1503 #endif 1504