1*21128Skarels /* @(#)if_hy.c 6.3 (Berkeley) 05/28/85 */ 211195Ssam 3*21128Skarels /* 4*21128Skarels * 4.2 BSD Unix Kernel - Vax Network Interface Support 5*21128Skarels * 6*21128Skarels * $Header: if_hy.c,v 10.1 84/07/22 21:02:56 steveg Exp $ 7*21128Skarels * $Locker: $ 8*21128Skarels * 9*21128Skarels * Modifications from Berkeley 4.2 BSD 10*21128Skarels * Copyright (c) 1983, Tektronix Inc. 11*21128Skarels * All Rights Reserved 12*21128Skarels * 13*21128Skarels * $Log: if_hy.c,v $ 14*21128Skarels * Revision 10.1 84/07/22 21:02:56 steveg 15*21128Skarels * define PI13 (moved from if_hyreg.h, somehow got dropped in the process) 16*21128Skarels * rework hywatch to check for power fails first 17*21128Skarels * 18*21128Skarels * Revision 10.0 84/06/30 19:54:27 steveg 19*21128Skarels * Big Build 20*21128Skarels * 21*21128Skarels * Revision 3.17 84/06/20 19:20:28 steveg 22*21128Skarels * increment hy_ntime in hywatch 23*21128Skarels * print out state name, csr, last command, and hy_flags when watchdog timer 24*21128Skarels * expires 25*21128Skarels * 26*21128Skarels * Revision 3.16 84/06/20 19:09:34 steveg 27*21128Skarels * turn on continuous logging by default 28*21128Skarels * 29*21128Skarels * Revision 3.15 84/05/30 22:19:09 steveg 30*21128Skarels * changes to reflect new layout ot statistics data 31*21128Skarels * 32*21128Skarels * Revision 3.14 84/05/30 19:25:15 steveg 33*21128Skarels * move driver states to if_hy.h so log printing programs can use them 34*21128Skarels * 35*21128Skarels * Revision 3.13 84/05/30 17:13:26 steveg 36*21128Skarels * make it compile 37*21128Skarels * 38*21128Skarels * Revision 3.12 84/05/30 13:46:16 steveg 39*21128Skarels * rework logging 40*21128Skarels * 41*21128Skarels * Revision 3.11 84/05/18 19:35:02 steveg 42*21128Skarels * clear IFF_RUNNING and IFF_UP on unibus reset to force resource allocation 43*21128Skarels * by the init routine 44*21128Skarels * 45*21128Skarels * Revision 3.10 84/05/04 12:14:44 steveg 46*21128Skarels * more rework to make it actually work under 4.2 47*21128Skarels * 48*21128Skarels * Revision 3.9 84/05/01 23:34:52 steveg 49*21128Skarels * fix typo so it compiles (unit -> ui->ui_unit) 50*21128Skarels * 51*21128Skarels * Revision 3.8 84/05/01 23:18:30 steveg 52*21128Skarels * changes after talking with rickk 53*21128Skarels * - check power off more closely 54*21128Skarels * - support remote loopback through A710 adapters 55*21128Skarels * - IMPLINK -> HYLINK 56*21128Skarels * - return EHOSTUNREACH on hyroute failure 57*21128Skarels * - bump if_collisions on abnormal interrupts that aren't input or output 58*21128Skarels * 59*21128Skarels * 60*21128Skarels */ 61*21128Skarels 62*21128Skarels 6311195Ssam #include "hy.h" 6411195Ssam #if NHY > 0 6511195Ssam 6611195Ssam /* 6711195Ssam * Network Systems Copropration Hyperchanel interface 6811195Ssam */ 69*21128Skarels #include "machine/pte.h" 7011195Ssam 71*21128Skarels #include "../h/param.h" 72*21128Skarels #include "../h/systm.h" 73*21128Skarels #include "../h/mbuf.h" 74*21128Skarels #include "../h/buf.h" 75*21128Skarels #include "../h/protosw.h" 76*21128Skarels #include "../h/socket.h" 77*21128Skarels #include "../h/vmmac.h" 78*21128Skarels #include "../h/errno.h" 79*21128Skarels #include "../h/time.h" 80*21128Skarels #include "../h/kernel.h" 81*21128Skarels #include "../h/ioctl.h" 8213088Ssam 8311195Ssam #include "../net/if.h" 8411207Ssam #include "../net/netisr.h" 8511195Ssam #include "../net/route.h" 8611195Ssam #include "../netinet/in.h" 8711195Ssam #include "../netinet/in_systm.h" 8811195Ssam #include "../netinet/ip.h" 8911195Ssam #include "../netinet/ip_var.h" 9011195Ssam 9111207Ssam #include "../vax/cpu.h" 9211207Ssam #include "../vax/mtpr.h" 9311207Ssam #include "../vaxuba/ubareg.h" 9411207Ssam #include "../vaxuba/ubavar.h" 9511195Ssam 96*21128Skarels /* 97*21128Skarels * configuration specific paramters 98*21128Skarels * - change as appropriate for particular installaions 99*21128Skarels */ 100*21128Skarels #define HYROUTE 101*21128Skarels #define HYELOG 102*21128Skarels #define HYLOG 103*21128Skarels #define HYMTU 1100 104*21128Skarels #define PI13 10511195Ssam 106*21128Skarels #ifdef DEBUG 107*21128Skarels #define HYLOG 108*21128Skarels #endif 109*21128Skarels 110*21128Skarels #include "../vaxif/if_hy.h" 111*21128Skarels #include "../vaxif/if_hyreg.h" 112*21128Skarels #include "../vaxif/if_uba.h" 113*21128Skarels 11413058Ssam int hyprobe(), hyattach(), hyinit(), hyioctl(); 11513058Ssam int hyoutput(), hyreset(), hywatch(); 11611195Ssam struct uba_device *hyinfo[NHY]; 11711195Ssam u_short hystd[] = { 0772410, 0 }; 11811195Ssam struct uba_driver hydriver = 11911195Ssam { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo }; 12011195Ssam 12111195Ssam /* 12211195Ssam * Hyperchannel software status per interface. 12311195Ssam * 12411195Ssam * Each interface is referenced by a network interface structure, 12511195Ssam * hy_if, which the routing code uses to locate the interface. 12611195Ssam * This structure contains the output queue for the interface, its address, ... 12711195Ssam * We also have, for each interface, a UBA interface structure, which 12811195Ssam * contains information about the UNIBUS resources held by the interface: 12911195Ssam * map registers, buffered data paths, etc. Information is cached in this 13011195Ssam * structure for use by the if_uba.c routines in running the interface 13111195Ssam * efficiently. 13211195Ssam */ 13311195Ssam struct hy_softc { 13411195Ssam struct ifnet hy_if; /* network-visible interface */ 13511195Ssam struct ifuba hy_ifuba; /* UNIBUS resources */ 13611207Ssam short hy_flags; /* flags */ 13711207Ssam short hy_state; /* driver state */ 13811195Ssam int hy_olen; /* packet length on output */ 13911195Ssam int hy_lastwcr; /* last command's word count */ 14011195Ssam short hy_savedstate; /* saved for reissue after status */ 14111195Ssam short hy_savedcmd; /* saved command for reissue */ 14211195Ssam int hy_savedcount; /* saved byte count for reissue */ 14311195Ssam int hy_savedaddr; /* saved unibus address for reissue */ 14411195Ssam int hy_ntime; /* number of timeouts since last cmd */ 14511195Ssam int hy_retry; /* retry counter */ 14611207Ssam struct hy_stat hy_stat; /* statistics */ 14711207Ssam struct hy_status hy_status; /* status */ 14811195Ssam } hy_softc[NHY]; 14911195Ssam 15011195Ssam #ifdef HYELOG 151*21128Skarels u_long hy_elog[HYE_SIZE]; 15211195Ssam #endif 15311195Ssam 154*21128Skarels #ifdef HYLOG 155*21128Skarels struct hy_log hy_log; 156*21128Skarels #endif 157*21128Skarels 158*21128Skarels #ifdef HYROUTE 159*21128Skarels struct hy_route hy_route[NHY]; 160*21128Skarels #endif 161*21128Skarels 16211195Ssam #ifdef DEBUG 163*21128Skarels #define printL printf 164*21128Skarels #define printD if (hy_debug_flag) printf 16511195Ssam int hy_debug_flag = 0; 16611195Ssam /* 16711195Ssam * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 16811195Ssam * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 16911195Ssam * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 17011195Ssam */ 17111195Ssam int hy_nodebug = 0x0; 17211195Ssam #endif 17311195Ssam 17411195Ssam #define SCANINTERVAL 10 /* seconds */ 17511195Ssam #define MAXINTERVAL 20 /* seconds (max action) */ 17611195Ssam 17711195Ssam /* 17811195Ssam * Cause a device interrupt. This code uses a buffer starting at 17911195Ssam * location zero on the unibus (which is already mapped by the 18011195Ssam * autoconfigure code in the kernel). 18111195Ssam */ 18211195Ssam hyprobe(reg) 18311195Ssam caddr_t reg; 18411195Ssam { 18511195Ssam register int br, cvec; /* r11, r10 value-result */ 18611195Ssam register struct hydevice *addr = (struct hydevice *) reg; 18711195Ssam 18811195Ssam #ifdef lint 18911195Ssam br = 0; cvec = br; br = cvec; 19011195Ssam hyint(0); 19111195Ssam #endif 19211195Ssam /* 19311195Ssam * request adapter status to a buffer starting at unibus location 0 19411195Ssam */ 19511195Ssam addr->hyd_bar = 0; 19611195Ssam addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 19711195Ssam addr->hyd_dbuf = HYF_STATUS; 19811195Ssam #ifdef PI13 19911195Ssam addr->hyd_csr |= S_GO | S_IE | S_IATTN; 20011195Ssam #else 20111195Ssam addr->hyd_csr |= S_GO | S_IE; 20211195Ssam #endif 20311195Ssam DELAY(10000); 20411195Ssam #ifdef PI13 20511195Ssam addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 20611195Ssam #endif 20711195Ssam addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 208*21128Skarels return(sizeof(struct hydevice)); 20911207Ssam } 21011195Ssam 21111195Ssam /* 21211195Ssam * Interface exists: make available by filling in network interface 21311195Ssam * record. System will initialize the interface when it is ready 21411195Ssam * to accept packets. 21511195Ssam */ 21611195Ssam hyattach(ui) 21711195Ssam struct uba_device *ui; 21811195Ssam { 21911195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 22011195Ssam register struct ifnet *ifp = &is->hy_if; 221*21128Skarels register struct sockaddr_in *sin; 22211195Ssam 22311195Ssam ifp->if_unit = ui->ui_unit; 22411195Ssam ifp->if_name = "hy"; 22511195Ssam ifp->if_mtu = HYMTU; 22611195Ssam is->hy_state = STARTUP; /* don't allow state transitions yet */ 227*21128Skarels sin = (struct sockaddr_in *)&ifp->if_addr; 228*21128Skarels sin->sin_family = AF_INET; 22911195Ssam ifp->if_init = hyinit; 23013058Ssam ifp->if_ioctl = hyioctl; 23111195Ssam ifp->if_output = hyoutput; 23211207Ssam ifp->if_reset = hyreset; 23311195Ssam ifp->if_watchdog = hywatch; 23411195Ssam ifp->if_timer = SCANINTERVAL; 23511195Ssam is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 23611207Ssam #ifdef notdef 23711195Ssam is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 23811195Ssam #endif 23911195Ssam if_attach(ifp); 24011207Ssam } 24111195Ssam 24211195Ssam /* 24311195Ssam * Reset of interface after UNIBUS reset. 24411195Ssam * If interface is on specified uba, reset its state. 24511195Ssam */ 24611195Ssam hyreset(unit, uban) 24711195Ssam int unit, uban; 24811195Ssam { 249*21128Skarels register struct uba_device *ui; 250*21128Skarels register struct hy_softc *is; 25111195Ssam 252*21128Skarels if (unit >= NHY || (ui = hyinfo[unit]) == 0 || ui->ui_alive == 0 || 25311207Ssam ui->ui_ubanum != uban) 25411195Ssam return; 25511195Ssam printf(" hy%d", unit); 256*21128Skarels is = &hy_softc[unit]; /* force unibus resource allocation */ 257*21128Skarels is->hy_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 25811195Ssam hyinit(unit); 25911207Ssam } 26011195Ssam 26111195Ssam /* 26211195Ssam * Initialization of interface; clear recorded pending 26311195Ssam * operations, and reinitialize UNIBUS usage. 26411195Ssam */ 26511195Ssam hyinit(unit) 26611195Ssam int unit; 26711195Ssam { 26811195Ssam register struct hy_softc *is = &hy_softc[unit]; 26911195Ssam register struct uba_device *ui = hyinfo[unit]; 270*21128Skarels register struct mbuf *m; 27113065Ssam struct sockaddr_in *sin; 27211195Ssam int s; 27311195Ssam 27413088Ssam sin = (struct sockaddr_in *)&is->hy_if.if_addr; 275*21128Skarels if (sin->sin_addr.s_addr == 0) /* address still unknown */ 27613065Ssam return; 277*21128Skarels if (is->hy_if.if_flags & IFF_RUNNING) /* just reset the device */ 278*21128Skarels goto justreset; 27911195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 280*21128Skarels sizeof (struct hym_hdr), (int)btoc(HYMTU)) == 0) { 28111195Ssam #ifdef DEBUG 28211207Ssam if (hy_nodebug & 4) 28311207Ssam hy_debug_flag = 1; 28411195Ssam #endif 28511195Ssam printf("hy%d: can't initialize\n", unit); 28611195Ssam is->hy_if.if_flags &= ~IFF_UP; 28711195Ssam return; 28811195Ssam } 28913088Ssam is->hy_if.if_flags |= IFF_RUNNING; 290*21128Skarels 291*21128Skarels justreset: 29211195Ssam /* 293*21128Skarels * remove any left over outgoing messages, reset the hardware and 294*21128Skarels * start the state machine 29511195Ssam */ 29611195Ssam s = splimp(); 297*21128Skarels #ifdef HYLOG 298*21128Skarels hylog(HYL_RESET, 0, (char *)0); 299*21128Skarels #endif 30011195Ssam is->hy_state = IDLE; 30111195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 30211195Ssam is->hy_retry = 0; 303*21128Skarels for(;;) { 304*21128Skarels IF_DEQUEUE(&is->hy_if.if_snd, m); 305*21128Skarels if (m != NULL) 306*21128Skarels m_freem(m); 307*21128Skarels else 308*21128Skarels break; 309*21128Skarels } 310*21128Skarels hycancel(ui); /* also bumps the state machine */ 31111195Ssam splx(s); 31211207Ssam } 31311195Ssam 31411195Ssam /* 31511207Ssam * Issue a command to the adapter 31611195Ssam */ 31711195Ssam hystart(ui, cmd, count, ubaddr) 31811195Ssam struct uba_device *ui; 31911207Ssam int cmd, count, ubaddr; 32011195Ssam { 32111195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 32211195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 32311195Ssam 32411195Ssam #ifdef DEBUG 32511207Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 32611207Ssam ui->ui_unit, cmd, count, ubaddr); 32711195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 32811207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 32911207Ssam addr->hyd_wcr); 33011195Ssam #endif 33111207Ssam if (((is->hy_flags & RQ_REISSUE) == 0) && 33211207Ssam (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 33311195Ssam is->hy_savedstate = is->hy_state; 33411195Ssam is->hy_savedcmd = cmd; 33511195Ssam is->hy_savedcount = count; 33611195Ssam is->hy_savedaddr = ubaddr; 33711195Ssam } 338*21128Skarels #ifdef PI13 339*21128Skarels if (addr->hyd_csr & S_POWEROFF) { 340*21128Skarels printf("hy%d: \"Soft\" Adapter Power Failure (hystart)\n", ui->ui_unit); 341*21128Skarels addr->hyd_csr |= S_POWEROFF; 342*21128Skarels DELAY(100); 343*21128Skarels if (addr->hyd_csr & S_POWEROFF) { 344*21128Skarels printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hystart)\n", ui->ui_unit); 345*21128Skarels if_down(&is->hy_if); 346*21128Skarels is->hy_if.if_flags &= ~IFF_UP; 347*21128Skarels is->hy_state = STARTUP; 348*21128Skarels } else { 349*21128Skarels printf("hy%d: Adapter Power Restored (hystart)\n", ui->ui_unit); 350*21128Skarels } 351*21128Skarels return; 352*21128Skarels } 353*21128Skarels #endif 35411195Ssam addr->hyd_bar = ubaddr & 0xffff; 35511207Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 35611195Ssam addr->hyd_dbuf = cmd; 35711195Ssam #ifdef PI13 35811195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 35911195Ssam #else 36011195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 36111195Ssam #endif 36211195Ssam #ifdef DEBUG 36311195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 36411207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 36511207Ssam addr->hyd_wcr); 36611195Ssam #endif 36711195Ssam #ifdef HYLOG 36811195Ssam { 36911195Ssam struct { 37011207Ssam u_char hcmd; 37111207Ssam u_char hstate; 37211207Ssam short hcount; 37311195Ssam } hcl; 37411195Ssam 37511195Ssam hcl.hcmd = cmd; 37611195Ssam hcl.hstate = is->hy_state; 37711195Ssam hcl.hcount = count; 37811195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 37911195Ssam } 38011195Ssam #endif 38111195Ssam is->hy_ntime = 0; 38211207Ssam } 38311195Ssam 38411195Ssam int hyint_active = 0; /* set during hy interrupt */ 38511195Ssam /* 38611207Ssam * Hyperchannel interface interrupt. 38711195Ssam * 38811195Ssam * An interrupt can occur for many reasons. Examine the status of 38911195Ssam * the hyperchannel status bits to determine what to do next. 39011195Ssam * 39111195Ssam * If input error just drop packet. 39211195Ssam * Otherwise purge input buffered data path and examine 39311195Ssam * packet to determine type. Othewise decapsulate 39411195Ssam * packet based on type and pass to type specific higher-level 39511195Ssam * input routine. 39611195Ssam */ 39711195Ssam hyint(unit) 39811195Ssam int unit; 39911195Ssam { 40011195Ssam register struct hy_softc *is = &hy_softc[unit]; 40111195Ssam register struct uba_device *ui = hyinfo[unit]; 40211207Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 40311195Ssam 40411207Ssam if (hyint_active) 40511195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 40611195Ssam hyint_active++; 40711195Ssam #ifdef DEBUG 40811195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 40911195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 41011195Ssam #endif 41111195Ssam #ifdef HYLOG 41211195Ssam logit: 41311195Ssam { 41411195Ssam struct { 41511207Ssam u_char hstate; 41611207Ssam u_char hflags; 41711207Ssam short hcsr; 41811207Ssam short hwcr; 41911195Ssam } hil; 42011195Ssam hil.hstate = is->hy_state; 42111195Ssam hil.hflags = is->hy_flags; 42211195Ssam hil.hcsr = addr->hyd_csr; 42311195Ssam hil.hwcr = addr->hyd_wcr; 42411195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil); 42511195Ssam } 42611195Ssam #endif 42711207Ssam if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 42811195Ssam /* 42911207Ssam * Error bit set, some sort of error in the interface. 43011195Ssam * 43111207Ssam * The adapter sets attn on command completion so that's not 43211207Ssam * a real error even though the interface considers it one. 43311195Ssam */ 43411195Ssam #ifdef DEBUG 43511207Ssam if (hy_nodebug & 4) 43611207Ssam hy_debug_flag = 1; 43711195Ssam #endif 43811207Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 43911207Ssam addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 44011207Ssam addr->hyd_wcr); 44111207Ssam if (addr->hyd_csr & S_NEX) { 44211195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit); 44311195Ssam #ifdef PI13 44411195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 44511195Ssam #else 44611195Ssam addr->hyd_csr &= ~S_NEX; 44711195Ssam #endif 44811195Ssam hycancel(ui); 44911195Ssam #ifdef PI13 45011207Ssam } else if (addr->hyd_csr & S_POWEROFF) { 451*21128Skarels printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit); 45211195Ssam addr->hyd_csr |= S_POWEROFF; 45311195Ssam DELAY(100); 45411207Ssam if (addr->hyd_csr & S_POWEROFF) { 455*21128Skarels printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit); 45611195Ssam if_down(&is->hy_if); 457*21128Skarels is->hy_if.if_flags &= ~IFF_UP; 45811195Ssam is->hy_state = STARTUP; 459*21128Skarels } else { 460*21128Skarels printf("hy%d: Adapter Power Restored (hyint)\n", unit); 46111195Ssam } 46211195Ssam #endif 46311195Ssam } else { 46411195Ssam printf("hy%d: BAR overflow\n", unit); 46511195Ssam hycancel(ui); 46611195Ssam } 46711207Ssam } else if (HYS_NORMAL(addr)) { 46811195Ssam /* 46911207Ssam * Normal interrupt, bump state machine unless in state 47011195Ssam * waiting and no data present (assumed to be word count 47111207Ssam * zero interrupt or other hardware botch). 47211195Ssam */ 47311207Ssam if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 47411195Ssam hyact(ui); 47511207Ssam } else if (HYS_ABNORMAL(addr)) { 47611195Ssam /* 47711207Ssam * Abnormal termination. 47811195Ssam * bump error counts, retry the last function 47911195Ssam * 'MAXRETRY' times before kicking the bucket. 48011195Ssam * 48111207Ssam * Don't reissue the cmd if in certain states, abnormal 48211207Ssam * on a reissued cmd or max retry exceeded. 48311195Ssam */ 48411195Ssam #ifdef HYLOG 48511195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 48611195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 48711195Ssam goto logit; 48811195Ssam } 48911195Ssam #endif 49011195Ssam #ifdef DEBUG 49111207Ssam if (hy_nodebug & 4) 49211207Ssam hy_debug_flag = 1; 49311195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 49411195Ssam unit, hy_state_names[is->hy_state], is->hy_state); 495*21128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 496*21128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 49711207Ssam printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 49811207Ssam is->hy_savedstate, is->hy_savedcount, 49911207Ssam is->hy_savedaddr, is->hy_savedcmd); 50011195Ssam #endif 50111195Ssam #ifdef PI13 50211195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 50311195Ssam #endif 50411207Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 50511195Ssam is->hy_if.if_oerrors++; 506*21128Skarels else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 50711195Ssam is->hy_if.if_ierrors++; 508*21128Skarels else 509*21128Skarels is->hy_if.if_collisions++; /* other errors */ 51011195Ssam if (is->hy_state == XMITDATASENT || 51111195Ssam is->hy_state == RECVSENT || 51211195Ssam is->hy_state == RECVDATASENT || 51311207Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 51411195Ssam hycancel(ui); 51511207Ssam else { 51611195Ssam #ifdef DEBUG 51711207Ssam if (hy_nodebug & 2) 51811207Ssam hy_debug_flag = 1; 51911195Ssam #endif 52011195Ssam is->hy_retry++; 52111195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 52211195Ssam is->hy_state = IDLE; 52311195Ssam hyact(ui); 52411195Ssam } 52511195Ssam } else { 52611195Ssam /* 52711195Ssam * Interrupt is neither normal, abnormal, or interface error. 52811195Ssam * Ignore it. It's either stacked or a word count 0. 52911195Ssam */ 53011195Ssam #ifdef HYLOG 53111195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 53211195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 53311195Ssam goto logit; 53411195Ssam } 53511195Ssam #endif 53611195Ssam #ifdef DEBUG 53711195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit); 53811195Ssam #endif 53911195Ssam } 54011195Ssam #ifdef DEBUG 54111195Ssam printD("hy%d: hyint exit\n\n", unit); 54211195Ssam #endif 54311195Ssam hyint_active = 0; 54411195Ssam 54511207Ssam } 54611195Ssam 547*21128Skarels int hyoutprint = 0; 548*21128Skarels 54911195Ssam /* 55011195Ssam * Encapsulate a packet of type family for the local net. 55111195Ssam */ 55211195Ssam hyoutput(ifp, m0, dst) 55311195Ssam struct ifnet *ifp; 55411195Ssam struct mbuf *m0; 55511195Ssam struct sockaddr *dst; 55611195Ssam { 55711195Ssam register struct hym_hdr *hym; 55811195Ssam register struct mbuf *m; 559*21128Skarels register char *mp; 56011195Ssam #ifdef HYROUTE 561*21128Skarels register struct hy_route *r = &hy_route[ifp->if_unit]; 56211195Ssam #endif 563*21128Skarels int dlen; /* packet size, incl hardware header, but not sw header */ 56411195Ssam int error = 0; 56511195Ssam int s; 56611195Ssam 567*21128Skarels /* 568*21128Skarels * Calculate packet length for later deciding whether it will fit 569*21128Skarels * in a message proper or we also need associated data. 570*21128Skarels */ 57111195Ssam dlen = 0; 57211195Ssam for (m = m0; m; m = m->m_next) 57311195Ssam dlen += m->m_len; 57411195Ssam m = m0; 575*21128Skarels if (dst->sa_family == AF_HYLINK) { /* don't add header */ 576*21128Skarels dlen -= HYM_SWLEN; 577*21128Skarels goto headerexists; 578*21128Skarels } 579*21128Skarels 580*21128Skarels /* 581*21128Skarels * Add the software and hardware hyperchannel headers. 582*21128Skarels * If there's not enough space in the first mbuf, allocate another. 583*21128Skarels * If that should fail, drop this sucker. 584*21128Skarels * No extra space for headers is allocated. 585*21128Skarels */ 586*21128Skarels mp = mtod(m, char *); /* save pointer to real message */ 587*21128Skarels if (m->m_off > MMAXOFF || 588*21128Skarels MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 589*21128Skarels m = m_get(M_DONTWAIT, MT_HEADER); 590*21128Skarels if (m == 0) { 591*21128Skarels m = m0; 592*21128Skarels error = ENOBUFS; 593*21128Skarels goto drop; 594*21128Skarels } 595*21128Skarels m->m_next = m0; 596*21128Skarels m->m_off = MMINOFF; 597*21128Skarels m->m_len = sizeof(struct hym_hdr); 598*21128Skarels } else { 599*21128Skarels m->m_off -= sizeof(struct hym_hdr); 600*21128Skarels m->m_len += sizeof(struct hym_hdr); 601*21128Skarels } 602*21128Skarels 603*21128Skarels dlen += sizeof(struct hym_hdr) - HYM_SWLEN; 604*21128Skarels 605*21128Skarels hym = mtod(m, struct hym_hdr *); 606*21128Skarels 607*21128Skarels bzero((caddr_t)hym, sizeof(struct hym_hdr)); 608*21128Skarels 60911195Ssam switch(dst->sa_family) { 61011195Ssam 61111195Ssam #ifdef INET 61211195Ssam case AF_INET: { 613*21128Skarels int i; 61411195Ssam 61511195Ssam /* 616*21128Skarels * if loopback address, swizzle ip header so when 617*21128Skarels * it comes back it looks like it was addressed to us 61811195Ssam */ 619*21128Skarels i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym); 620*21128Skarels if (i < 0) 621*21128Skarels goto notfound; 622*21128Skarels if (i > 0) { 62311195Ssam struct in_addr temp; 62411195Ssam 625*21128Skarels temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr; 626*21128Skarels ((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr; 627*21128Skarels ((struct ip *)mp)->ip_src.s_addr = temp.s_addr; 62811195Ssam } 62911195Ssam /* 63011195Ssam * If entire packet won't fit in message proper, just 63111195Ssam * send hyperchannel hardware header and ip header in 632*21128Skarels * message proper. 63311195Ssam * 63411195Ssam * This insures that the associated data is at least a 63511195Ssam * TCP/UDP header in length and thus prevents potential 63611195Ssam * problems with very short word counts. 63711195Ssam */ 638*21128Skarels if (dlen > MPSIZE) 639*21128Skarels hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2); 640*21128Skarels hym->hym_type = HYLINK_IP; 64111195Ssam break; 64211195Ssam } 64311195Ssam #endif 64411195Ssam 64511195Ssam default: 64611207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, 64711207Ssam dst->sa_family); 64811195Ssam error = EAFNOSUPPORT; 64911195Ssam goto drop; 65011195Ssam } 65111195Ssam 652*21128Skarels 653*21128Skarels headerexists: 654*21128Skarels 65511195Ssam /* 656*21128Skarels * insure message proper is below the maximum 65711195Ssam */ 658*21128Skarels if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0)) 659*21128Skarels hym->hym_mplen = MPSIZE; 66011195Ssam 661*21128Skarels hym->hym_from = htons((u_short)ifp->if_host[0]); 662*21128Skarels if (hym->hym_mplen) 663*21128Skarels hym->hym_ctl |= H_ASSOC; 664*21128Skarels else 665*21128Skarels hym->hym_ctl &= ~H_ASSOC; 666*21128Skarels if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 667*21128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 668*21128Skarels hym->hym_access, hym->hym_to, hym->hym_from, 669*21128Skarels hym->hym_param, hym->hym_type); 67011195Ssam #ifdef DEBUG 671*21128Skarels printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 672*21128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 673*21128Skarels hym->hym_access, hym->hym_to, hym->hym_from, 674*21128Skarels hym->hym_param, hym->hym_type); 67511195Ssam #endif 67611195Ssam s = splimp(); 67711195Ssam if (IF_QFULL(&ifp->if_snd)) { 67811195Ssam IF_DROP(&ifp->if_snd); 67911195Ssam error = ENOBUFS; 68011195Ssam splx(s); 68111195Ssam goto drop; 68211195Ssam } 68311195Ssam IF_ENQUEUE(&ifp->if_snd, m); 68411195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING) 68511195Ssam hyact(hyinfo[ifp->if_unit]); 68611195Ssam splx(s); 68711207Ssam return (0); 68811195Ssam notfound: 689*21128Skarels error = EHOSTUNREACH; 69011195Ssam drop: 69111195Ssam m_freem(m); 69211207Ssam return (error); 69311207Ssam } 69411195Ssam 695*21128Skarels int 696*21128Skarels hyroute(ifp, dest, hym) 697*21128Skarels register struct ifnet *ifp; 698*21128Skarels u_long dest; 699*21128Skarels register struct hym_hdr *hym; 700*21128Skarels { 701*21128Skarels #ifdef HYROUTE 702*21128Skarels register struct hy_route *rt = &hy_route[ifp->if_unit]; 703*21128Skarels register struct hyr_hash *rhash; 704*21128Skarels register int i; 705*21128Skarels #endif 706*21128Skarels 707*21128Skarels hym->hym_param = 0; 708*21128Skarels #ifdef HYROUTE 709*21128Skarels if (rt->hyr_lasttime != 0) { 710*21128Skarels i = HYRHASH(dest); 711*21128Skarels rhash = &rt->hyr_hash[i]; 712*21128Skarels i = 0; 713*21128Skarels while (rhash->hyr_key != dest) { 714*21128Skarels if (rhash->hyr_flags == 0 || i > HYRSIZE) 715*21128Skarels return(-1); 716*21128Skarels rhash++; i++; 717*21128Skarels if (rhash >= &rt->hyr_hash[HYRSIZE]) 718*21128Skarels rhash = &rt->hyr_hash[0]; 719*21128Skarels } 720*21128Skarels if (rhash->hyr_flags & HYR_GATE) { 721*21128Skarels i = rhash->hyr_nextgate; 722*21128Skarels if (i >= rhash->hyr_egate) 723*21128Skarels rhash->hyr_nextgate = rhash->hyr_pgate; 724*21128Skarels else 725*21128Skarels rhash->hyr_nextgate++; 726*21128Skarels rhash = &rt->hyr_hash[rt->hyr_gateway[i]]; 727*21128Skarels if ((rhash->hyr_flags & HYR_DIR) == 0) 728*21128Skarels return(-1); 729*21128Skarels } else if (rhash->hyr_flags & HYR_LOOP) { 730*21128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */ 731*21128Skarels } else if (rhash->hyr_flags & HYR_RLOOP) { 732*21128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 733*21128Skarels } 734*21128Skarels hym->hym_ctl = rhash->hyr_ctl; 735*21128Skarels hym->hym_access = rhash->hyr_access; 736*21128Skarels hym->hym_to = rhash->hyr_dst; 737*21128Skarels } else { 738*21128Skarels #endif 739*21128Skarels hym->hym_ctl = H_XTRUNKS | H_RTRUNKS; 740*21128Skarels hym->hym_access = 0; 741*21128Skarels hym->hym_to = htons((u_short)dest); 742*21128Skarels if (dest & 0x010000) 743*21128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */ 744*21128Skarels else if (dest & 0x020000) 745*21128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 746*21128Skarels #ifdef HYROUTE 747*21128Skarels } 748*21128Skarels #endif 749*21128Skarels 750*21128Skarels hym->hym_from = htons((u_short)ifp->if_host[0]); 751*21128Skarels if (hym->hym_param == 0) 752*21128Skarels return(0); 753*21128Skarels else 754*21128Skarels return(1); 755*21128Skarels } 756*21128Skarels 75711195Ssam hyact(ui) 75811195Ssam register struct uba_device *ui; 75911195Ssam { 76011195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 76111195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 76211195Ssam 76311195Ssam actloop: 76411195Ssam #ifdef DEBUG 76511207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 76611207Ssam hy_state_names[is->hy_state]); 76711195Ssam #endif 76811195Ssam switch (is->hy_state) { 76911195Ssam 77011195Ssam case STARTUP: 77111195Ssam goto endintr; 77211195Ssam 77311195Ssam case IDLE: { 77411195Ssam register rq = is->hy_flags; 77511195Ssam 77611195Ssam if (rq & RQ_STATUS) { 77711195Ssam is->hy_flags &= ~RQ_STATUS; 77811195Ssam is->hy_state = STATSENT; 77911207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status), 78013088Ssam is->hy_ifuba.ifu_r.ifrw_info); 78111195Ssam } else if (rq & RQ_ENDOP) { 78211195Ssam is->hy_flags &= ~RQ_ENDOP; 78311195Ssam is->hy_state = ENDOPSENT; 78411195Ssam hystart(ui, HYF_END_OP, 0, 0); 78511195Ssam } else if (rq & RQ_STATISTICS) { 78611195Ssam is->hy_flags &= ~RQ_STATISTICS; 78711195Ssam is->hy_state = RSTATSENT; 78811207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 78913088Ssam is->hy_ifuba.ifu_r.ifrw_info); 79011207Ssam } else if (HYS_RECVDATA(addr)) { 79111195Ssam is->hy_state = RECVSENT; 79211195Ssam is->hy_retry = 0; 793*21128Skarels hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN); 79411195Ssam } else if (rq & RQ_REISSUE) { 79511195Ssam is->hy_flags &= ~RQ_REISSUE; 79611195Ssam is->hy_state = is->hy_savedstate; 79711195Ssam #ifdef DEBUG 79811207Ssam printD("hy%d: reissue cmd=0x%x count=%d", 79911207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 80011207Ssam printD(" ubaddr=0x%x retry=%d\n", 80111207Ssam is->hy_savedaddr, is->hy_retry); 80211195Ssam #endif 80311207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, 80413088Ssam is->hy_savedaddr); 80511195Ssam } else { 80611195Ssam register struct mbuf *m; 80711195Ssam 80811195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 80911207Ssam if (m != NULL) { 81011195Ssam register struct hym_hdr *hym; 81111195Ssam register int mplen; 81211195Ssam register int cmd; 81311195Ssam 81411195Ssam is->hy_state = XMITSENT; 81511195Ssam is->hy_retry = 0; 81611195Ssam hym = mtod(m, struct hym_hdr *); 81711195Ssam #ifdef HYLOG 81811207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), 81913088Ssam (char *)hym); 82011195Ssam #endif 82111195Ssam mplen = hym->hym_mplen; 822*21128Skarels if (hym->hym_to_adapter == hym->hym_from_adapter) 82311207Ssam cmd = HYF_XMITLOCMSG; 82411207Ssam else 82511207Ssam cmd = HYF_XMITMSG; 82611195Ssam #ifdef DEBUG 82711195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 82811207Ssam if (hy_debug_flag) 82911207Ssam hyprintdata((char *)hym, 83013088Ssam sizeof (struct hym_hdr)); 83111195Ssam #endif 832*21128Skarels is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN; 83311195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 83411207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 83511207Ssam is->hy_ifuba.ifu_w.ifrw_bdp); 83611195Ssam #ifdef DEBUG 83711207Ssam printD( 83811207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 83911195Ssam ui->ui_unit, mplen, is->hy_olen); 84011207Ssam if (hy_debug_flag) 84111207Ssam hyprintdata( 84213088Ssam is->hy_ifuba.ifu_w.ifrw_addr, 843*21128Skarels is->hy_olen + HYM_SWLEN); 84411195Ssam #endif 845*21128Skarels if (mplen == 0) { 846*21128Skarels is->hy_flags &= ~RQ_XASSOC; 847*21128Skarels mplen = is->hy_olen; 848*21128Skarels } else { 84911195Ssam is->hy_flags |= RQ_XASSOC; 850*21128Skarels } 851*21128Skarels hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN); 85211195Ssam } else if (rq & RQ_MARKDOWN) { 85311195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 85411195Ssam is->hy_state = MARKPORT; 85511195Ssam is->hy_retry = 0; 85611195Ssam /* 85711207Ssam * Port number is taken from status data 85811195Ssam */ 85911207Ssam hystart(ui, 86012772Ssam (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 86112772Ssam 0, 0); 86211195Ssam } else if (rq & RQ_MARKUP) { 86311195Ssam register struct ifnet *ifp = &is->hy_if; 86411207Ssam register struct sockaddr_in *sin = 86511207Ssam (struct sockaddr_in *)&ifp->if_addr; 86611195Ssam 86711207Ssam is->hy_flags &= ~RQ_MARKUP; 86811195Ssam is->hy_retry = 0; 86911195Ssam /* 87013065Ssam * Fill in the host number 87111207Ssam * from the status buffer 87211195Ssam */ 87311207Ssam printf( 87411207Ssam "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 87511195Ssam ui->ui_unit, 87611195Ssam is->hy_stat.hyc_uaddr, 87711195Ssam PORTNUM(&is->hy_status), 87811207Ssam (is->hy_stat.hyc_atype[0]<<8) | 87911207Ssam is->hy_stat.hyc_atype[1], 88011195Ssam is->hy_stat.hyc_atype[2]); 88111195Ssam 88211207Ssam ifp->if_host[0] = 88311207Ssam (is->hy_stat.hyc_uaddr << 8) | 88411207Ssam PORTNUM(&is->hy_status); 88511195Ssam ifp->if_flags |= IFF_UP; 88611195Ssam if_rtinit(ifp, RTF_UP); 88711195Ssam #ifdef HYLOG 88811195Ssam hylog(HYL_UP, 0, (char *)0); 88911195Ssam #endif 89011195Ssam } else { 89111195Ssam is->hy_state = WAITING; 89211195Ssam is->hy_retry = 0; 89311195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0); 89411195Ssam } 89511195Ssam } 89611207Ssam break; 89711195Ssam } 89811195Ssam 89911195Ssam case STATSENT: 90012772Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status, 90111207Ssam sizeof (struct hy_status)); 90211195Ssam #ifdef DEBUG 90311207Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 90411207Ssam ui->ui_unit, is->hy_status.hys_gen_status, 90511207Ssam is->hy_status.hys_last_fcn, 90611207Ssam is->hy_status.hys_resp_trunk, 90711207Ssam is->hy_status.hys_status_trunk, 90811207Ssam is->hy_status.hys_recd_resp, 90911207Ssam is->hy_status.hys_error, 91011207Ssam is->hy_status.hys_caddr, 91111207Ssam is->hy_status.hys_pad); 91211195Ssam #endif 91311195Ssam is->hy_state = IDLE; 91411195Ssam #ifdef HYLOG 91511207Ssam hylog(HYL_STATUS, sizeof (struct hy_status), 91611207Ssam (char *)&is->hy_status); 91711195Ssam #endif 91811195Ssam #ifdef HYELOG 91911195Ssam { 92011195Ssam register int i; 92111195Ssam 92211195Ssam i = is->hy_status.hys_error; 923*21128Skarels if (i > HYE_MAX) 92411195Ssam i = HYE_MAX; 92511195Ssam switch (is->hy_status.hys_last_fcn) { 92611195Ssam case HYF_XMITLOCMSG: 92711195Ssam i += HYE_MAX+1; /* fall through */ 92811195Ssam case HYF_XMITLSTDATA: 92911195Ssam i += HYE_MAX+1; /* fall through */ 93011195Ssam case HYF_XMITMSG: 93111195Ssam i += HYE_MAX+1; 93211195Ssam } 93311195Ssam hy_elog[i]++; 93411195Ssam } 93511195Ssam #endif 93611195Ssam break; 93711195Ssam 93811195Ssam case RSTATSENT: { 93911207Ssam register struct hy_stat *p = 94011207Ssam (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 94111195Ssam 942*21128Skarels bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat)); 94311195Ssam #ifdef DEBUG 944*21128Skarels 945*21128Skarels printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n", 94611195Ssam ui->ui_unit, 947*21128Skarels (is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2], 948*21128Skarels (is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2], 949*21128Skarels (is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2], 950*21128Skarels (is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]); 951*21128Skarels printD(" ret0 %d ret1 %d ret2 %d ret3 %d\n", 952*21128Skarels (is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2], 953*21128Skarels (is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2], 954*21128Skarels (is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2], 955*21128Skarels (is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]); 956*21128Skarels printD(" cancel %d abort %d atype %x %x %x uaddr %x\n", 957*21128Skarels (is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1], 958*21128Skarels (is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1], 95911195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 96011195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 96111195Ssam #endif 96211195Ssam is->hy_state = IDLE; 96311195Ssam #ifdef HYLOG 96411207Ssam hylog(HYL_STATISTICS, sizeof (struct hy_stat), 96511207Ssam (char *)&is->hy_stat); 96611195Ssam #endif 96711195Ssam break; 96811195Ssam } 96911195Ssam 97011195Ssam case CLEARSENT: 97111195Ssam is->hy_state = IDLE; 97211195Ssam break; 97311195Ssam 97411195Ssam case ENDOPSENT: 97511195Ssam is->hy_state = IDLE; 97611195Ssam break; 97711195Ssam 97811195Ssam case RECVSENT: { 979*21128Skarels register struct hym_hdr *hym; 98011207Ssam register unsigned len; 98111195Ssam 98211207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 98311207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 98413088Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 985*21128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 98611207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 98711207Ssam if (len > MPSIZE) { 98811207Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n", 98913088Ssam ui->ui_unit, len); 990*21128Skarels is->hy_state = IDLE; 99111195Ssam #ifdef DEBUG 99211207Ssam hy_debug_flag = 1; 99311207Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 99411207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 99511207Ssam addr->hyd_bar, addr->hyd_wcr); 99611195Ssam #endif 99711207Ssam } 998*21128Skarels hym->hym_mplen = len; 99911195Ssam #ifdef DEBUG 100011207Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 100111207Ssam if (hy_debug_flag) 1002*21128Skarels hyprintdata((char *)hym, len + HYM_SWLEN); 100311195Ssam #endif 1004*21128Skarels if (hym->hym_ctl & H_ASSOC) { 100511207Ssam is->hy_state = RECVDATASENT; 100611207Ssam is->hy_retry = 0; 100711207Ssam hystart(ui, HYF_INPUTDATA, 1008*21128Skarels (int)(HYMTU + sizeof (struct hy_hdr) - len), 1009*21128Skarels (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len)); 101011207Ssam } else { 1011*21128Skarels hyrecvdata(ui, hym, (int)len + HYM_SWLEN); 101211207Ssam is->hy_state = IDLE; 101311195Ssam } 101411207Ssam break; 101511207Ssam } 101611195Ssam 101711195Ssam case RECVDATASENT: { 1018*21128Skarels register struct hym_hdr *hym; 101911207Ssam register unsigned len; 102011195Ssam 102111207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 102211207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 102313088Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 1024*21128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 102511207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 102611195Ssam #ifdef DEBUG 102711207Ssam printD("hy%d: recvd assoc data, len = %d, data = ", 102811207Ssam ui->ui_unit, len); 102911207Ssam if (hy_debug_flag) 1030*21128Skarels hyprintdata((char *)hym + hym->hym_mplen, len); 103111195Ssam #endif 1032*21128Skarels hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN)); 103311207Ssam is->hy_state = IDLE; 103411207Ssam break; 103511207Ssam } 103611195Ssam 103711195Ssam case XMITSENT: 103811207Ssam if (is->hy_flags & RQ_XASSOC) { 103913196Sroot register int len; 104011195Ssam 104111207Ssam is->hy_flags &= ~RQ_XASSOC; 104211207Ssam is->hy_state = XMITDATASENT; 104311207Ssam is->hy_retry = 0; 104411207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 104511207Ssam if (len > is->hy_olen) { 104611207Ssam printf( 104711207Ssam "hy%d: xmit error - len > hy_olen [%d > %d]\n", 104811207Ssam ui->ui_unit, len, is->hy_olen); 104911195Ssam #ifdef DEBUG 105011207Ssam hy_debug_flag = 1; 105111195Ssam #endif 105211195Ssam } 105311207Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 1054*21128Skarels is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len); 105511207Ssam break; 105611207Ssam } 105711207Ssam /* fall through to ... */ 105811195Ssam 105911195Ssam case XMITDATASENT: 106011207Ssam hyxmitdata(ui); 106111207Ssam is->hy_state = IDLE; 106211207Ssam break; 106311195Ssam 106411195Ssam case WAITING: /* wait for message complete or output requested */ 106511207Ssam if (HYS_RECVDATA(addr)) 106611195Ssam is->hy_state = IDLE; 106711195Ssam else { 106811195Ssam is->hy_state = CLEARSENT; 106911195Ssam is->hy_retry = 0; 107011195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0); 107111195Ssam } 107211195Ssam break; 107311195Ssam 107411195Ssam case MARKPORT: 107511195Ssam is->hy_state = STARTUP; 1076*21128Skarels if_down(&is->hy_if); 107711195Ssam is->hy_if.if_flags &= ~IFF_UP; 107811195Ssam goto endintr; 107911195Ssam 108011195Ssam default: 108111207Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 108211207Ssam ui->ui_unit, is->hy_state); 108311195Ssam panic("HYPERCHANNEL IN INVALID STATE"); 108411195Ssam /*NOTREACHED*/ 108511207Ssam } 108611195Ssam if (is->hy_state == IDLE) 108711195Ssam goto actloop; 108811195Ssam endintr: 108913088Ssam ; 109011195Ssam #ifdef DEBUG 109111207Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 109211207Ssam hy_state_names[is->hy_state]); 109311195Ssam #endif 109411207Ssam } 109511195Ssam 1096*21128Skarels struct sockproto hypproto = { PF_HYLINK }; 1097*21128Skarels struct sockaddr_in hypdst = { AF_HYLINK }; 1098*21128Skarels struct sockaddr_in hypsrc = { AF_HYLINK }; 1099*21128Skarels 110011195Ssam /* 110113088Ssam * Called from device interrupt when receiving data. 110211195Ssam * Examine packet to determine type. Decapsulate packet 110311195Ssam * based on type and pass to type specific higher-level 110411195Ssam * input routine. 110511195Ssam */ 1106*21128Skarels hyrecvdata(ui, hym, len) 110711195Ssam struct uba_device *ui; 1108*21128Skarels register struct hym_hdr *hym; 110911195Ssam int len; 111011195Ssam { 111111195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 111211195Ssam struct mbuf *m; 111311195Ssam register struct ifqueue *inq; 111411195Ssam 111511195Ssam is->hy_if.if_ipackets++; 111611195Ssam #ifdef DEBUG 1117*21128Skarels printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len); 111811195Ssam #endif 111911195Ssam #ifdef HYLOG 112011195Ssam { 112111195Ssam struct { 112211195Ssam short hlen; 1123*21128Skarels struct hym_hdr hhdr; 112411195Ssam } hh; 112511195Ssam hh.hlen = len; 1126*21128Skarels hh.hhdr = *hym; 112711195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh); 112811195Ssam } 112911195Ssam #endif 113011195Ssam if (len > HYMTU + MPSIZE || len == 0) 113111195Ssam return; /* sanity */ 113211195Ssam /* 113311195Ssam * Pull packet off interface. 113411195Ssam */ 113511195Ssam m = if_rubaget(&is->hy_ifuba, len, 0); 113611207Ssam if (m == NULL) 113711195Ssam return; 113811195Ssam 1139*21128Skarels /* 1140*21128Skarels * if normal or adapter loopback response packet believe hym_type, 1141*21128Skarels * otherwise, use the raw input queue cause it's a response from an 1142*21128Skarels * adapter command. 1143*21128Skarels */ 1144*21128Skarels if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff) 1145*21128Skarels goto rawlinkin; 1146*21128Skarels 1147*21128Skarels switch (hym->hym_type) { 1148*21128Skarels 114911195Ssam #ifdef INET 115011195Ssam case HYLINK_IP: 115111195Ssam schednetisr(NETISR_IP); 115211195Ssam inq = &ipintrq; 115311195Ssam break; 115411195Ssam #endif 115511195Ssam default: 1156*21128Skarels rawlinkin: 1157*21128Skarels { 1158*21128Skarels struct mbuf *m0; 1159*21128Skarels 1160*21128Skarels MGET(m0, M_DONTWAIT, MT_DATA); 1161*21128Skarels if (m == 0) { 1162*21128Skarels m_freem(m); 1163*21128Skarels return; 1164*21128Skarels } 1165*21128Skarels m0->m_off = MMINOFF; 1166*21128Skarels m0->m_len = sizeof(struct hym_hdr); 1167*21128Skarels m0->m_next = m; 1168*21128Skarels bcopy((caddr_t)hym, mtod(m0, caddr_t), sizeof(struct hym_hdr)); 1169*21128Skarels m = m0; 1170*21128Skarels hypproto.sp_protocol = 0; 1171*21128Skarels hypdst.sin_addr = ((struct sockaddr_in *)&is->hy_if.if_addr)->sin_addr; 1172*21128Skarels hypsrc.sin_addr = if_makeaddr(is->hy_if.if_net, is->hy_if.if_host[0]); 1173*21128Skarels raw_input(m, &hypproto, (struct sockaddr *)&hypsrc, 1174*21128Skarels (struct sockaddr *)&hypdst); 1175*21128Skarels return; 1176*21128Skarels } 117711195Ssam } 117811195Ssam if (IF_QFULL(inq)) { 117911195Ssam IF_DROP(inq); 118011195Ssam m_freem(m); 118111195Ssam } else 118211195Ssam IF_ENQUEUE(inq, m); 118311207Ssam } 118411195Ssam 118511195Ssam /* 118611207Ssam * Transmit done, release resources, bump counters. 118711195Ssam */ 118811195Ssam hyxmitdata(ui) 118911195Ssam struct uba_device *ui; 119011195Ssam { 119111195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 119211195Ssam 119311195Ssam is->hy_if.if_opackets++; 119411207Ssam if (is->hy_ifuba.ifu_xtofree) { 119511195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 119611195Ssam is->hy_ifuba.ifu_xtofree = 0; 119711195Ssam } 119811207Ssam } 119911195Ssam 120011195Ssam hycancel(ui) 120111195Ssam register struct uba_device *ui; 120211195Ssam { 120311195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 120411195Ssam 120511207Ssam if (is->hy_ifuba.ifu_xtofree) { 120611195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 120711195Ssam is->hy_ifuba.ifu_xtofree = 0; 120811195Ssam } 1209*21128Skarels #ifdef HYLOG 1210*21128Skarels hylog(HYL_CANCEL, 0, (char *)0); 1211*21128Skarels #endif 121211195Ssam #ifdef DEBUG 121311207Ssam if (hy_nodebug & 1) 121411207Ssam hy_debug_flag = 1; 121511195Ssam #endif 121611195Ssam #ifdef DEBUG 121711195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 121811195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 121911195Ssam is->hy_savedcount, is->hy_savedaddr); 1220*21128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 1221*21128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 122211207Ssam printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 122311207Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 122411207Ssam is->hy_savedcmd); 122511195Ssam #endif 122611195Ssam is->hy_state = IDLE; 122711195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 122811195Ssam hyact(ui); 122911207Ssam } 123011195Ssam 123111195Ssam #ifdef DEBUG 123211195Ssam hyprintdata(cp, len) 123311195Ssam register char *cp; 123411195Ssam register int len; 123511195Ssam { 123611195Ssam register int count = 16; 123711195Ssam register char *fmt; 123811195Ssam static char regfmt[] = "\n\t %x"; 123911195Ssam 124011195Ssam fmt = ®fmt[2]; 124111195Ssam while (--len >= 0) { 124211195Ssam printL(fmt, *cp++ & 0xff); 124311195Ssam fmt = ®fmt[2]; 124411195Ssam if (--count <= 0) { 124511195Ssam fmt = ®fmt[0]; 124611195Ssam count = 16; 124711195Ssam } 124811195Ssam } 124911195Ssam printL("\n"); 125011195Ssam } 125111195Ssam #endif 125211195Ssam 125311195Ssam hywatch(unit) 125413088Ssam int unit; 125511195Ssam { 125611195Ssam register struct hy_softc *is = &hy_softc[unit]; 125711195Ssam register struct uba_device *ui = hyinfo[unit]; 125811195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 125911195Ssam int s; 126011195Ssam 126111195Ssam s = splimp(); 126211195Ssam #ifdef PI13 126311195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 126411195Ssam addr->hyd_csr |= S_POWEROFF; 126511195Ssam DELAY(100); 126611195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) { 1267*21128Skarels printf("hy%d: Adapter Power Restored (hywatch)\n", unit); 126811195Ssam is->hy_state = IDLE; 126911207Ssam is->hy_flags |= 127011207Ssam (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 127111195Ssam hyact(ui); 127211195Ssam } 127311195Ssam } 127411195Ssam #endif 1275*21128Skarels if (++is->hy_ntime >= 2 && is->hy_state != WAITING && 1276*21128Skarels is->hy_state != STARTUP && is->hy_state != IDLE) { 1277*21128Skarels #ifdef HYLOG 1278*21128Skarels printf("hy%d: watchdog timer expired in state \"%s\"\n", unit, 1279*21128Skarels hy_state_names[is->hy_state]); 1280*21128Skarels #else 1281*21128Skarels printf("hy%d: watchdog timer expired in state %d\n", unit, 1282*21128Skarels is->hy_state); 1283*21128Skarels #endif 1284*21128Skarels printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit, 1285*21128Skarels is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS); 1286*21128Skarels hycancel(ui); 1287*21128Skarels } 128811195Ssam splx(s); 1289*21128Skarels is->hy_if.if_timer = SCANINTERVAL; 129011195Ssam } 129111195Ssam 129211195Ssam #ifdef HYLOG 129311195Ssam hylog(code, len, ptr) 129413088Ssam int code, len; 129511195Ssam char *ptr; 129611195Ssam { 129711195Ssam register unsigned char *p; 129811195Ssam int s; 129911195Ssam 130011195Ssam s = splimp(); 130111195Ssam if (hy_log.hyl_self != &hy_log) { 130211195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 130311195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 130411195Ssam hy_log.hyl_self = &hy_log; 1305*21128Skarels hy_log.hyl_enable = HYL_CONTINUOUS; 1306*21128Skarels hy_log.hyl_onerr = HYL_CONTINUOUS; 1307*21128Skarels hy_log.hyl_count = 0; 1308*21128Skarels hy_log.hyl_icount = 16; 1309*21128Skarels hy_log.hyl_filter = 0xffff; /* enable all */ 131011195Ssam } 1311*21128Skarels if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0) 131211207Ssam goto out; 131311195Ssam p = hy_log.hyl_ptr; 1314*21128Skarels if (p + len + 3 >= hy_log.hyl_eptr) { 131512772Ssam bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 131611195Ssam p = &hy_log.hyl_buf[0]; 1317*21128Skarels if (hy_log.hyl_enable != HYL_CONTINUOUS) { 1318*21128Skarels hy_log.hyl_enable = HYL_DISABLED; 131911195Ssam goto out; 132011195Ssam } 132111195Ssam } 132211195Ssam *p++ = code; 132311195Ssam *p++ = len; 132413088Ssam bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len); 1325*21128Skarels if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) { 1326*21128Skarels *p++ = '\0'; 1327*21128Skarels hy_log.hyl_enable = HYL_DISABLED; 1328*21128Skarels hy_log.hyl_count = hy_log.hyl_icount; 1329*21128Skarels } 1330*21128Skarels if (hy_log.hyl_wait != 0) { /* wakeup HYGETLOG if wanted */ 1331*21128Skarels hy_log.hyl_wait -= (p - hy_log.hyl_ptr) + len; 1332*21128Skarels if (hy_log.hyl_wait <= 0) { 1333*21128Skarels wakeup((caddr_t)&hy_log); 1334*21128Skarels hy_log.hyl_wait = 0; 1335*21128Skarels } 1336*21128Skarels } 133711195Ssam hy_log.hyl_ptr = p + len; 133811195Ssam out: 133911195Ssam splx(s); 134011195Ssam } 134111195Ssam #endif 134211195Ssam 134312772Ssam /*ARGSUSED*/ 134413058Ssam hyioctl(ifp, cmd, data) 134513058Ssam register struct ifnet *ifp; 134611207Ssam int cmd; 134711207Ssam caddr_t data; 134811195Ssam { 1349*21128Skarels struct sockaddr_in *sin = (struct sockaddr_in *)data; 1350*21128Skarels struct hyrsetget *sg = (struct hyrsetget *)data; 1351*21128Skarels #if defined(HYLOG) || defined(HYELOG) 1352*21128Skarels struct hylsetget *sgl = (struct hylsetget *)data; 1353*21128Skarels #endif 1354*21128Skarels struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit]; 135511207Ssam int s = splimp(), error = 0; 1356*21128Skarels #ifdef HYLOG 1357*21128Skarels struct hy_softc *is = &hy_softc[ifp->if_unit]; 1358*21128Skarels struct { 1359*21128Skarels u_char hstate; 1360*21128Skarels u_char hflags; 1361*21128Skarels u_short iflags; 1362*21128Skarels int hcmd; 1363*21128Skarels int herror; 1364*21128Skarels u_long haddr; 1365*21128Skarels u_long hmisc; 1366*21128Skarels } hil; 136711195Ssam 1368*21128Skarels hil.hmisc = -1; 1369*21128Skarels hil.hstate = is->hy_state; 1370*21128Skarels hil.hflags = is->hy_flags; 1371*21128Skarels hil.hcmd = cmd; 1372*21128Skarels #endif 1373*21128Skarels 137411195Ssam switch(cmd) { 137511195Ssam 137613065Ssam case SIOCSIFADDR: 1377*21128Skarels if (sin->sin_family != AF_INET) 1378*21128Skarels return(EINVAL); 137913065Ssam if (ifp->if_flags & IFF_RUNNING) 138013065Ssam if_rtinit(ifp, -1); 1381*21128Skarels #ifdef HYLOG 1382*21128Skarels hil.haddr = ((struct sockaddr_in *)&ifp->if_addr)->sin_addr.s_addr; 1383*21128Skarels #endif 1384*21128Skarels ifp->if_addr = *(struct sockaddr *)sin; 138513065Ssam ifp->if_net = in_netof(sin->sin_addr); 1386*21128Skarels hyinit(ifp->if_unit); 138713065Ssam break; 138813065Ssam 138911195Ssam case HYSETROUTE: 139011207Ssam if (!suser()) { 139111207Ssam error = EPERM; 1392*21128Skarels goto out; 139311195Ssam } 1394*21128Skarels 1395*21128Skarels if (sg->hyrsg_len != sizeof(struct hy_route)) { 1396*21128Skarels error = EINVAL; 1397*21128Skarels goto out; 1398*21128Skarels } 1399*21128Skarels if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) { 1400*21128Skarels r->hyr_lasttime = 0; /* disable further routing if trouble */ 1401*21128Skarels error = EFAULT; 1402*21128Skarels goto out; 1403*21128Skarels } 1404*21128Skarels r->hyr_lasttime = time.tv_sec; 1405*21128Skarels #ifdef HYLOG 1406*21128Skarels hil.hmisc = r->hyr_lasttime; 1407*21128Skarels #endif 140811195Ssam break; 140911195Ssam 141011195Ssam case HYGETROUTE: 1411*21128Skarels if (sg->hyrsg_len < sizeof(struct hy_route)) { 1412*21128Skarels error = EINVAL; 1413*21128Skarels goto out; 1414*21128Skarels } 1415*21128Skarels if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) { 1416*21128Skarels error = EFAULT; 1417*21128Skarels goto out; 1418*21128Skarels } 141911195Ssam break; 142011195Ssam 1421*21128Skarels #ifdef HYELOG 1422*21128Skarels case HYGETELOG: 1423*21128Skarels if (sgl->hylsg_len < sizeof(hy_elog)) { 1424*21128Skarels error = EINVAL; 1425*21128Skarels goto out; 1426*21128Skarels } 1427*21128Skarels if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) { 1428*21128Skarels error = EFAULT; 1429*21128Skarels goto out; 1430*21128Skarels } 1431*21128Skarels if (sgl->hylsg_cmd) { 1432*21128Skarels if (!suser()) { 1433*21128Skarels error = EPERM; 1434*21128Skarels goto out; 1435*21128Skarels } 1436*21128Skarels bzero((caddr_t)hy_elog, sizeof(hy_elog)); 1437*21128Skarels } 1438*21128Skarels break; 1439*21128Skarels #endif 1440*21128Skarels 1441*21128Skarels #ifdef HYLOG 1442*21128Skarels case HYSETLOG: 1443*21128Skarels if (!suser()) { 1444*21128Skarels error = EPERM; 1445*21128Skarels goto out; 1446*21128Skarels } 1447*21128Skarels hy_log.hyl_enable = HYL_DISABLED; 1448*21128Skarels hylog(HYL_NOP, 0, (char *)0); /* force log init */ 1449*21128Skarels hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f; 1450*21128Skarels hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f; 1451*21128Skarels hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff; 1452*21128Skarels hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len; 1453*21128Skarels wakeup((caddr_t)&hy_log); /* wakeup sleeping HYGETLOG */ 1454*21128Skarels break; 1455*21128Skarels 1456*21128Skarels case HYGETLOG: 1457*21128Skarels if (sgl->hylsg_len < sizeof(hy_log)) { 1458*21128Skarels error = EINVAL; 1459*21128Skarels goto out; 1460*21128Skarels } 1461*21128Skarels if (sgl->hylsg_cmd != 0) { 1462*21128Skarels if (hy_log.hyl_wait) { 1463*21128Skarels error = EBUSY; 1464*21128Skarels goto out; 1465*21128Skarels } 1466*21128Skarels hy_log.hyl_wait = sgl->hylsg_cmd; 1467*21128Skarels sleep((caddr_t)&hy_log); 1468*21128Skarels } 1469*21128Skarels 1470*21128Skarels if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) { 1471*21128Skarels error = EFAULT; 1472*21128Skarels goto out; 1473*21128Skarels } 1474*21128Skarels break; 1475*21128Skarels #endif 1476*21128Skarels 147711195Ssam default: 147813058Ssam error = EINVAL; 147911195Ssam break; 148011195Ssam } 1481*21128Skarels out: 1482*21128Skarels #ifdef HYLOG 1483*21128Skarels hil.herror = error; 1484*21128Skarels hil.iflags = ifp->if_flags; 1485*21128Skarels hil.haddr = ((struct sockaddr_in *)&ifp->if_addr)->sin_addr.s_addr; 1486*21128Skarels hylog(HYL_IOCTL, sizeof(hil), (char *)&hil); 1487*21128Skarels #endif 148811195Ssam splx(s); 148911207Ssam return (error); 149011195Ssam } 149111207Ssam #endif 1492