1*21775Skarels /* @(#)if_hy.c 6.4 (Berkeley) 06/03/85 */ 211195Ssam 321128Skarels /* 421128Skarels * 4.2 BSD Unix Kernel - Vax Network Interface Support 521128Skarels * 621128Skarels * $Header: if_hy.c,v 10.1 84/07/22 21:02:56 steveg Exp $ 721128Skarels * $Locker: $ 821128Skarels * 921128Skarels * Modifications from Berkeley 4.2 BSD 1021128Skarels * Copyright (c) 1983, Tektronix Inc. 1121128Skarels * All Rights Reserved 1221128Skarels * 1321128Skarels * $Log: if_hy.c,v $ 1421128Skarels * Revision 10.1 84/07/22 21:02:56 steveg 1521128Skarels * define PI13 (moved from if_hyreg.h, somehow got dropped in the process) 1621128Skarels * rework hywatch to check for power fails first 1721128Skarels * 1821128Skarels * Revision 10.0 84/06/30 19:54:27 steveg 1921128Skarels * Big Build 2021128Skarels * 2121128Skarels * Revision 3.17 84/06/20 19:20:28 steveg 2221128Skarels * increment hy_ntime in hywatch 2321128Skarels * print out state name, csr, last command, and hy_flags when watchdog timer 2421128Skarels * expires 2521128Skarels * 2621128Skarels * Revision 3.16 84/06/20 19:09:34 steveg 2721128Skarels * turn on continuous logging by default 2821128Skarels * 2921128Skarels * Revision 3.15 84/05/30 22:19:09 steveg 3021128Skarels * changes to reflect new layout ot statistics data 3121128Skarels * 3221128Skarels * Revision 3.14 84/05/30 19:25:15 steveg 3321128Skarels * move driver states to if_hy.h so log printing programs can use them 3421128Skarels * 3521128Skarels * Revision 3.13 84/05/30 17:13:26 steveg 3621128Skarels * make it compile 3721128Skarels * 3821128Skarels * Revision 3.12 84/05/30 13:46:16 steveg 3921128Skarels * rework logging 4021128Skarels * 4121128Skarels * Revision 3.11 84/05/18 19:35:02 steveg 4221128Skarels * clear IFF_RUNNING and IFF_UP on unibus reset to force resource allocation 4321128Skarels * by the init routine 4421128Skarels * 4521128Skarels * Revision 3.10 84/05/04 12:14:44 steveg 4621128Skarels * more rework to make it actually work under 4.2 4721128Skarels * 4821128Skarels * Revision 3.9 84/05/01 23:34:52 steveg 4921128Skarels * fix typo so it compiles (unit -> ui->ui_unit) 5021128Skarels * 5121128Skarels * Revision 3.8 84/05/01 23:18:30 steveg 5221128Skarels * changes after talking with rickk 5321128Skarels * - check power off more closely 5421128Skarels * - support remote loopback through A710 adapters 5521128Skarels * - IMPLINK -> HYLINK 5621128Skarels * - return EHOSTUNREACH on hyroute failure 5721128Skarels * - bump if_collisions on abnormal interrupts that aren't input or output 5821128Skarels * 5921128Skarels * 6021128Skarels */ 6121128Skarels 6221128Skarels 6311195Ssam #include "hy.h" 6411195Ssam #if NHY > 0 6511195Ssam 6611195Ssam /* 6711195Ssam * Network Systems Copropration Hyperchanel interface 6811195Ssam */ 6921128Skarels #include "machine/pte.h" 7011195Ssam 71*21775Skarels #include "param.h" 72*21775Skarels #include "systm.h" 73*21775Skarels #include "mbuf.h" 74*21775Skarels #include "buf.h" 75*21775Skarels #include "protosw.h" 76*21775Skarels #include "socket.h" 77*21775Skarels #include "vmmac.h" 78*21775Skarels #include "errno.h" 79*21775Skarels #include "time.h" 80*21775Skarels #include "kernel.h" 81*21775Skarels #include "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 9621128Skarels /* 9721128Skarels * configuration specific paramters 9821128Skarels * - change as appropriate for particular installaions 9921128Skarels */ 10021128Skarels #define HYROUTE 10121128Skarels #define HYELOG 10221128Skarels #define HYLOG 10321128Skarels #define HYMTU 1100 10421128Skarels #define PI13 10511195Ssam 10621128Skarels #ifdef DEBUG 10721128Skarels #define HYLOG 10821128Skarels #endif 10921128Skarels 110*21775Skarels #include "if_hy.h" 111*21775Skarels #include "if_hyreg.h" 112*21775Skarels #include "if_uba.h" 11321128Skarels 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 */ 138*21775Skarels u_short hy_host; /* local host number */ 139*21775Skarels struct in_addr hy_addr; /* internet address */ 14011195Ssam int hy_olen; /* packet length on output */ 14111195Ssam int hy_lastwcr; /* last command's word count */ 14211195Ssam short hy_savedstate; /* saved for reissue after status */ 14311195Ssam short hy_savedcmd; /* saved command for reissue */ 14411195Ssam int hy_savedcount; /* saved byte count for reissue */ 14511195Ssam int hy_savedaddr; /* saved unibus address for reissue */ 14611195Ssam int hy_ntime; /* number of timeouts since last cmd */ 14711195Ssam int hy_retry; /* retry counter */ 14811207Ssam struct hy_stat hy_stat; /* statistics */ 14911207Ssam struct hy_status hy_status; /* status */ 15011195Ssam } hy_softc[NHY]; 15111195Ssam 15211195Ssam #ifdef HYELOG 15321128Skarels u_long hy_elog[HYE_SIZE]; 15411195Ssam #endif 15511195Ssam 15621128Skarels #ifdef HYLOG 15721128Skarels struct hy_log hy_log; 15821128Skarels #endif 15921128Skarels 16021128Skarels #ifdef HYROUTE 16121128Skarels struct hy_route hy_route[NHY]; 16221128Skarels #endif 16321128Skarels 16411195Ssam #ifdef DEBUG 16521128Skarels #define printL printf 16621128Skarels #define printD if (hy_debug_flag) printf 16711195Ssam int hy_debug_flag = 0; 16811195Ssam /* 16911195Ssam * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 17011195Ssam * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 17111195Ssam * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 17211195Ssam */ 17311195Ssam int hy_nodebug = 0x0; 17411195Ssam #endif 17511195Ssam 17611195Ssam #define SCANINTERVAL 10 /* seconds */ 17711195Ssam #define MAXINTERVAL 20 /* seconds (max action) */ 17811195Ssam 17911195Ssam /* 18011195Ssam * Cause a device interrupt. This code uses a buffer starting at 18111195Ssam * location zero on the unibus (which is already mapped by the 18211195Ssam * autoconfigure code in the kernel). 18311195Ssam */ 18411195Ssam hyprobe(reg) 18511195Ssam caddr_t reg; 18611195Ssam { 18711195Ssam register int br, cvec; /* r11, r10 value-result */ 18811195Ssam register struct hydevice *addr = (struct hydevice *) reg; 18911195Ssam 19011195Ssam #ifdef lint 19111195Ssam br = 0; cvec = br; br = cvec; 19211195Ssam hyint(0); 19311195Ssam #endif 19411195Ssam /* 19511195Ssam * request adapter status to a buffer starting at unibus location 0 19611195Ssam */ 19711195Ssam addr->hyd_bar = 0; 19811195Ssam addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 19911195Ssam addr->hyd_dbuf = HYF_STATUS; 20011195Ssam #ifdef PI13 20111195Ssam addr->hyd_csr |= S_GO | S_IE | S_IATTN; 20211195Ssam #else 20311195Ssam addr->hyd_csr |= S_GO | S_IE; 20411195Ssam #endif 20511195Ssam DELAY(10000); 20611195Ssam #ifdef PI13 20711195Ssam addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 20811195Ssam #endif 20911195Ssam addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 21021128Skarels return(sizeof(struct hydevice)); 21111207Ssam } 21211195Ssam 21311195Ssam /* 21411195Ssam * Interface exists: make available by filling in network interface 21511195Ssam * record. System will initialize the interface when it is ready 21611195Ssam * to accept packets. 21711195Ssam */ 21811195Ssam hyattach(ui) 21911195Ssam struct uba_device *ui; 22011195Ssam { 22111195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 22211195Ssam register struct ifnet *ifp = &is->hy_if; 22311195Ssam 22411195Ssam ifp->if_unit = ui->ui_unit; 22511195Ssam ifp->if_name = "hy"; 22611195Ssam ifp->if_mtu = HYMTU; 22711195Ssam is->hy_state = STARTUP; /* don't allow state transitions yet */ 22811195Ssam ifp->if_init = hyinit; 22913058Ssam ifp->if_ioctl = hyioctl; 23011195Ssam ifp->if_output = hyoutput; 23111207Ssam ifp->if_reset = hyreset; 23211195Ssam ifp->if_watchdog = hywatch; 23311195Ssam ifp->if_timer = SCANINTERVAL; 23411195Ssam is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 23511207Ssam #ifdef notdef 23611195Ssam is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 23711195Ssam #endif 23811195Ssam if_attach(ifp); 23911207Ssam } 24011195Ssam 24111195Ssam /* 24211195Ssam * Reset of interface after UNIBUS reset. 24311195Ssam * If interface is on specified uba, reset its state. 24411195Ssam */ 24511195Ssam hyreset(unit, uban) 24611195Ssam int unit, uban; 24711195Ssam { 24821128Skarels register struct uba_device *ui; 24921128Skarels register struct hy_softc *is; 25011195Ssam 25121128Skarels if (unit >= NHY || (ui = hyinfo[unit]) == 0 || ui->ui_alive == 0 || 25211207Ssam ui->ui_ubanum != uban) 25311195Ssam return; 25411195Ssam printf(" hy%d", unit); 25521128Skarels is = &hy_softc[unit]; /* force unibus resource allocation */ 25621128Skarels is->hy_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 25711195Ssam hyinit(unit); 25811207Ssam } 25911195Ssam 26011195Ssam /* 26111195Ssam * Initialization of interface; clear recorded pending 26211195Ssam * operations, and reinitialize UNIBUS usage. 26311195Ssam */ 26411195Ssam hyinit(unit) 26511195Ssam int unit; 26611195Ssam { 26711195Ssam register struct hy_softc *is = &hy_softc[unit]; 26811195Ssam register struct uba_device *ui = hyinfo[unit]; 26921128Skarels register struct mbuf *m; 27011195Ssam int s; 27111195Ssam 272*21775Skarels if (is->hy_if.if_addrlist == 0) /* address still unknown */ 27313065Ssam return; 27421128Skarels if (is->hy_if.if_flags & IFF_RUNNING) /* just reset the device */ 27521128Skarels goto justreset; 27611195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 27721128Skarels sizeof (struct hym_hdr), (int)btoc(HYMTU)) == 0) { 27811195Ssam #ifdef DEBUG 27911207Ssam if (hy_nodebug & 4) 28011207Ssam hy_debug_flag = 1; 28111195Ssam #endif 28211195Ssam printf("hy%d: can't initialize\n", unit); 28311195Ssam is->hy_if.if_flags &= ~IFF_UP; 28411195Ssam return; 28511195Ssam } 28613088Ssam is->hy_if.if_flags |= IFF_RUNNING; 28721128Skarels 28821128Skarels justreset: 28911195Ssam /* 29021128Skarels * remove any left over outgoing messages, reset the hardware and 29121128Skarels * start the state machine 29211195Ssam */ 29311195Ssam s = splimp(); 29421128Skarels #ifdef HYLOG 29521128Skarels hylog(HYL_RESET, 0, (char *)0); 29621128Skarels #endif 29711195Ssam is->hy_state = IDLE; 29811195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 29911195Ssam is->hy_retry = 0; 30021128Skarels for(;;) { 30121128Skarels IF_DEQUEUE(&is->hy_if.if_snd, m); 30221128Skarels if (m != NULL) 30321128Skarels m_freem(m); 30421128Skarels else 30521128Skarels break; 30621128Skarels } 30721128Skarels hycancel(ui); /* also bumps the state machine */ 30811195Ssam splx(s); 30911207Ssam } 31011195Ssam 31111195Ssam /* 31211207Ssam * Issue a command to the adapter 31311195Ssam */ 31411195Ssam hystart(ui, cmd, count, ubaddr) 31511195Ssam struct uba_device *ui; 31611207Ssam int cmd, count, ubaddr; 31711195Ssam { 31811195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 31911195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 32011195Ssam 32111195Ssam #ifdef DEBUG 32211207Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 32311207Ssam ui->ui_unit, cmd, count, ubaddr); 32411195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 32511207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 32611207Ssam addr->hyd_wcr); 32711195Ssam #endif 32811207Ssam if (((is->hy_flags & RQ_REISSUE) == 0) && 32911207Ssam (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 33011195Ssam is->hy_savedstate = is->hy_state; 33111195Ssam is->hy_savedcmd = cmd; 33211195Ssam is->hy_savedcount = count; 33311195Ssam is->hy_savedaddr = ubaddr; 33411195Ssam } 33521128Skarels #ifdef PI13 33621128Skarels if (addr->hyd_csr & S_POWEROFF) { 33721128Skarels printf("hy%d: \"Soft\" Adapter Power Failure (hystart)\n", ui->ui_unit); 33821128Skarels addr->hyd_csr |= S_POWEROFF; 33921128Skarels DELAY(100); 34021128Skarels if (addr->hyd_csr & S_POWEROFF) { 34121128Skarels printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hystart)\n", ui->ui_unit); 34221128Skarels if_down(&is->hy_if); 34321128Skarels is->hy_if.if_flags &= ~IFF_UP; 34421128Skarels is->hy_state = STARTUP; 34521128Skarels } else { 34621128Skarels printf("hy%d: Adapter Power Restored (hystart)\n", ui->ui_unit); 34721128Skarels } 34821128Skarels return; 34921128Skarels } 35021128Skarels #endif 35111195Ssam addr->hyd_bar = ubaddr & 0xffff; 35211207Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 35311195Ssam addr->hyd_dbuf = cmd; 35411195Ssam #ifdef PI13 35511195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 35611195Ssam #else 35711195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 35811195Ssam #endif 35911195Ssam #ifdef DEBUG 36011195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 36111207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 36211207Ssam addr->hyd_wcr); 36311195Ssam #endif 36411195Ssam #ifdef HYLOG 36511195Ssam { 36611195Ssam struct { 36711207Ssam u_char hcmd; 36811207Ssam u_char hstate; 36911207Ssam short hcount; 37011195Ssam } hcl; 37111195Ssam 37211195Ssam hcl.hcmd = cmd; 37311195Ssam hcl.hstate = is->hy_state; 37411195Ssam hcl.hcount = count; 37511195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 37611195Ssam } 37711195Ssam #endif 37811195Ssam is->hy_ntime = 0; 37911207Ssam } 38011195Ssam 38111195Ssam int hyint_active = 0; /* set during hy interrupt */ 38211195Ssam /* 38311207Ssam * Hyperchannel interface interrupt. 38411195Ssam * 38511195Ssam * An interrupt can occur for many reasons. Examine the status of 38611195Ssam * the hyperchannel status bits to determine what to do next. 38711195Ssam * 38811195Ssam * If input error just drop packet. 38911195Ssam * Otherwise purge input buffered data path and examine 39011195Ssam * packet to determine type. Othewise decapsulate 39111195Ssam * packet based on type and pass to type specific higher-level 39211195Ssam * input routine. 39311195Ssam */ 39411195Ssam hyint(unit) 39511195Ssam int unit; 39611195Ssam { 39711195Ssam register struct hy_softc *is = &hy_softc[unit]; 39811195Ssam register struct uba_device *ui = hyinfo[unit]; 39911207Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 40011195Ssam 40111207Ssam if (hyint_active) 40211195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 40311195Ssam hyint_active++; 40411195Ssam #ifdef DEBUG 40511195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 40611195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 40711195Ssam #endif 40811195Ssam #ifdef HYLOG 40911195Ssam logit: 41011195Ssam { 41111195Ssam struct { 41211207Ssam u_char hstate; 41311207Ssam u_char hflags; 41411207Ssam short hcsr; 41511207Ssam short hwcr; 41611195Ssam } hil; 41711195Ssam hil.hstate = is->hy_state; 41811195Ssam hil.hflags = is->hy_flags; 41911195Ssam hil.hcsr = addr->hyd_csr; 42011195Ssam hil.hwcr = addr->hyd_wcr; 42111195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil); 42211195Ssam } 42311195Ssam #endif 42411207Ssam if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 42511195Ssam /* 42611207Ssam * Error bit set, some sort of error in the interface. 42711195Ssam * 42811207Ssam * The adapter sets attn on command completion so that's not 42911207Ssam * a real error even though the interface considers it one. 43011195Ssam */ 43111195Ssam #ifdef DEBUG 43211207Ssam if (hy_nodebug & 4) 43311207Ssam hy_debug_flag = 1; 43411195Ssam #endif 43511207Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 43611207Ssam addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 43711207Ssam addr->hyd_wcr); 43811207Ssam if (addr->hyd_csr & S_NEX) { 43911195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit); 44011195Ssam #ifdef PI13 44111195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 44211195Ssam #else 44311195Ssam addr->hyd_csr &= ~S_NEX; 44411195Ssam #endif 44511195Ssam hycancel(ui); 44611195Ssam #ifdef PI13 44711207Ssam } else if (addr->hyd_csr & S_POWEROFF) { 44821128Skarels printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit); 44911195Ssam addr->hyd_csr |= S_POWEROFF; 45011195Ssam DELAY(100); 45111207Ssam if (addr->hyd_csr & S_POWEROFF) { 45221128Skarels printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit); 45311195Ssam if_down(&is->hy_if); 45421128Skarels is->hy_if.if_flags &= ~IFF_UP; 45511195Ssam is->hy_state = STARTUP; 45621128Skarels } else { 45721128Skarels printf("hy%d: Adapter Power Restored (hyint)\n", unit); 45811195Ssam } 45911195Ssam #endif 46011195Ssam } else { 46111195Ssam printf("hy%d: BAR overflow\n", unit); 46211195Ssam hycancel(ui); 46311195Ssam } 46411207Ssam } else if (HYS_NORMAL(addr)) { 46511195Ssam /* 46611207Ssam * Normal interrupt, bump state machine unless in state 46711195Ssam * waiting and no data present (assumed to be word count 46811207Ssam * zero interrupt or other hardware botch). 46911195Ssam */ 47011207Ssam if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 47111195Ssam hyact(ui); 47211207Ssam } else if (HYS_ABNORMAL(addr)) { 47311195Ssam /* 47411207Ssam * Abnormal termination. 47511195Ssam * bump error counts, retry the last function 47611195Ssam * 'MAXRETRY' times before kicking the bucket. 47711195Ssam * 47811207Ssam * Don't reissue the cmd if in certain states, abnormal 47911207Ssam * on a reissued cmd or max retry exceeded. 48011195Ssam */ 48111195Ssam #ifdef HYLOG 48211195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 48311195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 48411195Ssam goto logit; 48511195Ssam } 48611195Ssam #endif 48711195Ssam #ifdef DEBUG 48811207Ssam if (hy_nodebug & 4) 48911207Ssam hy_debug_flag = 1; 49011195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 49111195Ssam unit, hy_state_names[is->hy_state], is->hy_state); 49221128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 49321128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 49411207Ssam printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 49511207Ssam is->hy_savedstate, is->hy_savedcount, 49611207Ssam is->hy_savedaddr, is->hy_savedcmd); 49711195Ssam #endif 49811195Ssam #ifdef PI13 49911195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 50011195Ssam #endif 50111207Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 50211195Ssam is->hy_if.if_oerrors++; 50321128Skarels else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 50411195Ssam is->hy_if.if_ierrors++; 50521128Skarels else 50621128Skarels is->hy_if.if_collisions++; /* other errors */ 50711195Ssam if (is->hy_state == XMITDATASENT || 50811195Ssam is->hy_state == RECVSENT || 50911195Ssam is->hy_state == RECVDATASENT || 51011207Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 51111195Ssam hycancel(ui); 51211207Ssam else { 51311195Ssam #ifdef DEBUG 51411207Ssam if (hy_nodebug & 2) 51511207Ssam hy_debug_flag = 1; 51611195Ssam #endif 51711195Ssam is->hy_retry++; 51811195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 51911195Ssam is->hy_state = IDLE; 52011195Ssam hyact(ui); 52111195Ssam } 52211195Ssam } else { 52311195Ssam /* 52411195Ssam * Interrupt is neither normal, abnormal, or interface error. 52511195Ssam * Ignore it. It's either stacked or a word count 0. 52611195Ssam */ 52711195Ssam #ifdef HYLOG 52811195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 52911195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 53011195Ssam goto logit; 53111195Ssam } 53211195Ssam #endif 53311195Ssam #ifdef DEBUG 53411195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit); 53511195Ssam #endif 53611195Ssam } 53711195Ssam #ifdef DEBUG 53811195Ssam printD("hy%d: hyint exit\n\n", unit); 53911195Ssam #endif 54011195Ssam hyint_active = 0; 54111195Ssam 54211207Ssam } 54311195Ssam 54421128Skarels int hyoutprint = 0; 54521128Skarels 54611195Ssam /* 54711195Ssam * Encapsulate a packet of type family for the local net. 54811195Ssam */ 54911195Ssam hyoutput(ifp, m0, dst) 55011195Ssam struct ifnet *ifp; 55111195Ssam struct mbuf *m0; 55211195Ssam struct sockaddr *dst; 55311195Ssam { 55411195Ssam register struct hym_hdr *hym; 55511195Ssam register struct mbuf *m; 55621128Skarels register char *mp; 55711195Ssam #ifdef HYROUTE 55821128Skarels register struct hy_route *r = &hy_route[ifp->if_unit]; 55911195Ssam #endif 56021128Skarels int dlen; /* packet size, incl hardware header, but not sw header */ 56111195Ssam int error = 0; 56211195Ssam int s; 56311195Ssam 56421128Skarels /* 56521128Skarels * Calculate packet length for later deciding whether it will fit 56621128Skarels * in a message proper or we also need associated data. 56721128Skarels */ 56811195Ssam dlen = 0; 56911195Ssam for (m = m0; m; m = m->m_next) 57011195Ssam dlen += m->m_len; 57111195Ssam m = m0; 57221128Skarels if (dst->sa_family == AF_HYLINK) { /* don't add header */ 57321128Skarels dlen -= HYM_SWLEN; 57421128Skarels goto headerexists; 57521128Skarels } 57621128Skarels 57721128Skarels /* 57821128Skarels * Add the software and hardware hyperchannel headers. 57921128Skarels * If there's not enough space in the first mbuf, allocate another. 58021128Skarels * If that should fail, drop this sucker. 58121128Skarels * No extra space for headers is allocated. 58221128Skarels */ 58321128Skarels mp = mtod(m, char *); /* save pointer to real message */ 58421128Skarels if (m->m_off > MMAXOFF || 58521128Skarels MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 58621128Skarels m = m_get(M_DONTWAIT, MT_HEADER); 58721128Skarels if (m == 0) { 58821128Skarels m = m0; 58921128Skarels error = ENOBUFS; 59021128Skarels goto drop; 59121128Skarels } 59221128Skarels m->m_next = m0; 59321128Skarels m->m_off = MMINOFF; 59421128Skarels m->m_len = sizeof(struct hym_hdr); 59521128Skarels } else { 59621128Skarels m->m_off -= sizeof(struct hym_hdr); 59721128Skarels m->m_len += sizeof(struct hym_hdr); 59821128Skarels } 59921128Skarels 60021128Skarels dlen += sizeof(struct hym_hdr) - HYM_SWLEN; 60121128Skarels 60221128Skarels hym = mtod(m, struct hym_hdr *); 60321128Skarels 60421128Skarels bzero((caddr_t)hym, sizeof(struct hym_hdr)); 60521128Skarels 60611195Ssam switch(dst->sa_family) { 60711195Ssam 60811195Ssam #ifdef INET 60911195Ssam case AF_INET: { 61021128Skarels int i; 61111195Ssam 61211195Ssam /* 61321128Skarels * if loopback address, swizzle ip header so when 61421128Skarels * it comes back it looks like it was addressed to us 61511195Ssam */ 61621128Skarels i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym); 61721128Skarels if (i < 0) 61821128Skarels goto notfound; 61921128Skarels if (i > 0) { 62011195Ssam struct in_addr temp; 62111195Ssam 62221128Skarels temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr; 62321128Skarels ((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr; 62421128Skarels ((struct ip *)mp)->ip_src.s_addr = temp.s_addr; 62511195Ssam } 62611195Ssam /* 62711195Ssam * If entire packet won't fit in message proper, just 62811195Ssam * send hyperchannel hardware header and ip header in 62921128Skarels * message proper. 63011195Ssam * 63111195Ssam * This insures that the associated data is at least a 63211195Ssam * TCP/UDP header in length and thus prevents potential 63311195Ssam * problems with very short word counts. 63411195Ssam */ 63521128Skarels if (dlen > MPSIZE) 63621128Skarels hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2); 63721128Skarels hym->hym_type = HYLINK_IP; 63811195Ssam break; 63911195Ssam } 64011195Ssam #endif 64111195Ssam 64211195Ssam default: 64311207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, 64411207Ssam dst->sa_family); 64511195Ssam error = EAFNOSUPPORT; 64611195Ssam goto drop; 64711195Ssam } 64811195Ssam 64921128Skarels 65021128Skarels headerexists: 65121128Skarels 65211195Ssam /* 65321128Skarels * insure message proper is below the maximum 65411195Ssam */ 65521128Skarels if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0)) 65621128Skarels hym->hym_mplen = MPSIZE; 65711195Ssam 658*21775Skarels hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host); 65921128Skarels if (hym->hym_mplen) 66021128Skarels hym->hym_ctl |= H_ASSOC; 66121128Skarels else 66221128Skarels hym->hym_ctl &= ~H_ASSOC; 66321128Skarels if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 66421128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 66521128Skarels hym->hym_access, hym->hym_to, hym->hym_from, 66621128Skarels hym->hym_param, hym->hym_type); 66711195Ssam #ifdef DEBUG 66821128Skarels printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 66921128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 67021128Skarels hym->hym_access, hym->hym_to, hym->hym_from, 67121128Skarels hym->hym_param, hym->hym_type); 67211195Ssam #endif 67311195Ssam s = splimp(); 67411195Ssam if (IF_QFULL(&ifp->if_snd)) { 67511195Ssam IF_DROP(&ifp->if_snd); 67611195Ssam error = ENOBUFS; 67711195Ssam splx(s); 67811195Ssam goto drop; 67911195Ssam } 68011195Ssam IF_ENQUEUE(&ifp->if_snd, m); 68111195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING) 68211195Ssam hyact(hyinfo[ifp->if_unit]); 68311195Ssam splx(s); 68411207Ssam return (0); 68511195Ssam notfound: 68621128Skarels error = EHOSTUNREACH; 68711195Ssam drop: 68811195Ssam m_freem(m); 68911207Ssam return (error); 69011207Ssam } 69111195Ssam 69221128Skarels int 69321128Skarels hyroute(ifp, dest, hym) 69421128Skarels register struct ifnet *ifp; 69521128Skarels u_long dest; 69621128Skarels register struct hym_hdr *hym; 69721128Skarels { 69821128Skarels #ifdef HYROUTE 69921128Skarels register struct hy_route *rt = &hy_route[ifp->if_unit]; 70021128Skarels register struct hyr_hash *rhash; 70121128Skarels register int i; 70221128Skarels #endif 70321128Skarels 70421128Skarels hym->hym_param = 0; 70521128Skarels #ifdef HYROUTE 70621128Skarels if (rt->hyr_lasttime != 0) { 70721128Skarels i = HYRHASH(dest); 70821128Skarels rhash = &rt->hyr_hash[i]; 70921128Skarels i = 0; 71021128Skarels while (rhash->hyr_key != dest) { 71121128Skarels if (rhash->hyr_flags == 0 || i > HYRSIZE) 71221128Skarels return(-1); 71321128Skarels rhash++; i++; 71421128Skarels if (rhash >= &rt->hyr_hash[HYRSIZE]) 71521128Skarels rhash = &rt->hyr_hash[0]; 71621128Skarels } 71721128Skarels if (rhash->hyr_flags & HYR_GATE) { 71821128Skarels i = rhash->hyr_nextgate; 71921128Skarels if (i >= rhash->hyr_egate) 72021128Skarels rhash->hyr_nextgate = rhash->hyr_pgate; 72121128Skarels else 72221128Skarels rhash->hyr_nextgate++; 72321128Skarels rhash = &rt->hyr_hash[rt->hyr_gateway[i]]; 72421128Skarels if ((rhash->hyr_flags & HYR_DIR) == 0) 72521128Skarels return(-1); 72621128Skarels } else if (rhash->hyr_flags & HYR_LOOP) { 72721128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */ 72821128Skarels } else if (rhash->hyr_flags & HYR_RLOOP) { 72921128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 73021128Skarels } 73121128Skarels hym->hym_ctl = rhash->hyr_ctl; 73221128Skarels hym->hym_access = rhash->hyr_access; 73321128Skarels hym->hym_to = rhash->hyr_dst; 73421128Skarels } else { 73521128Skarels #endif 73621128Skarels hym->hym_ctl = H_XTRUNKS | H_RTRUNKS; 73721128Skarels hym->hym_access = 0; 73821128Skarels hym->hym_to = htons((u_short)dest); 73921128Skarels if (dest & 0x010000) 74021128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */ 74121128Skarels else if (dest & 0x020000) 74221128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 74321128Skarels #ifdef HYROUTE 74421128Skarels } 74521128Skarels #endif 74621128Skarels 74721128Skarels if (hym->hym_param == 0) 74821128Skarels return(0); 74921128Skarels else 75021128Skarels return(1); 75121128Skarels } 75221128Skarels 75311195Ssam hyact(ui) 75411195Ssam register struct uba_device *ui; 75511195Ssam { 75611195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 75711195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 75811195Ssam 75911195Ssam actloop: 76011195Ssam #ifdef DEBUG 76111207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 76211207Ssam hy_state_names[is->hy_state]); 76311195Ssam #endif 76411195Ssam switch (is->hy_state) { 76511195Ssam 76611195Ssam case STARTUP: 76711195Ssam goto endintr; 76811195Ssam 76911195Ssam case IDLE: { 77011195Ssam register rq = is->hy_flags; 77111195Ssam 77211195Ssam if (rq & RQ_STATUS) { 77311195Ssam is->hy_flags &= ~RQ_STATUS; 77411195Ssam is->hy_state = STATSENT; 77511207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status), 77613088Ssam is->hy_ifuba.ifu_r.ifrw_info); 77711195Ssam } else if (rq & RQ_ENDOP) { 77811195Ssam is->hy_flags &= ~RQ_ENDOP; 77911195Ssam is->hy_state = ENDOPSENT; 78011195Ssam hystart(ui, HYF_END_OP, 0, 0); 78111195Ssam } else if (rq & RQ_STATISTICS) { 78211195Ssam is->hy_flags &= ~RQ_STATISTICS; 78311195Ssam is->hy_state = RSTATSENT; 78411207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 78513088Ssam is->hy_ifuba.ifu_r.ifrw_info); 78611207Ssam } else if (HYS_RECVDATA(addr)) { 78711195Ssam is->hy_state = RECVSENT; 78811195Ssam is->hy_retry = 0; 78921128Skarels hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN); 79011195Ssam } else if (rq & RQ_REISSUE) { 79111195Ssam is->hy_flags &= ~RQ_REISSUE; 79211195Ssam is->hy_state = is->hy_savedstate; 79311195Ssam #ifdef DEBUG 79411207Ssam printD("hy%d: reissue cmd=0x%x count=%d", 79511207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 79611207Ssam printD(" ubaddr=0x%x retry=%d\n", 79711207Ssam is->hy_savedaddr, is->hy_retry); 79811195Ssam #endif 79911207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, 80013088Ssam is->hy_savedaddr); 80111195Ssam } else { 80211195Ssam register struct mbuf *m; 80311195Ssam 80411195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 80511207Ssam if (m != NULL) { 80611195Ssam register struct hym_hdr *hym; 80711195Ssam register int mplen; 80811195Ssam register int cmd; 80911195Ssam 81011195Ssam is->hy_state = XMITSENT; 81111195Ssam is->hy_retry = 0; 81211195Ssam hym = mtod(m, struct hym_hdr *); 81311195Ssam #ifdef HYLOG 81411207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), 81513088Ssam (char *)hym); 81611195Ssam #endif 81711195Ssam mplen = hym->hym_mplen; 81821128Skarels if (hym->hym_to_adapter == hym->hym_from_adapter) 81911207Ssam cmd = HYF_XMITLOCMSG; 82011207Ssam else 82111207Ssam cmd = HYF_XMITMSG; 82211195Ssam #ifdef DEBUG 82311195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 82411207Ssam if (hy_debug_flag) 82511207Ssam hyprintdata((char *)hym, 82613088Ssam sizeof (struct hym_hdr)); 82711195Ssam #endif 82821128Skarels is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN; 82911195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 83011207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 83111207Ssam is->hy_ifuba.ifu_w.ifrw_bdp); 83211195Ssam #ifdef DEBUG 83311207Ssam printD( 83411207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 83511195Ssam ui->ui_unit, mplen, is->hy_olen); 83611207Ssam if (hy_debug_flag) 83711207Ssam hyprintdata( 83813088Ssam is->hy_ifuba.ifu_w.ifrw_addr, 83921128Skarels is->hy_olen + HYM_SWLEN); 84011195Ssam #endif 84121128Skarels if (mplen == 0) { 84221128Skarels is->hy_flags &= ~RQ_XASSOC; 84321128Skarels mplen = is->hy_olen; 84421128Skarels } else { 84511195Ssam is->hy_flags |= RQ_XASSOC; 84621128Skarels } 84721128Skarels hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN); 84811195Ssam } else if (rq & RQ_MARKDOWN) { 84911195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 85011195Ssam is->hy_state = MARKPORT; 85111195Ssam is->hy_retry = 0; 85211195Ssam /* 85311207Ssam * Port number is taken from status data 85411195Ssam */ 85511207Ssam hystart(ui, 85612772Ssam (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 85712772Ssam 0, 0); 85811195Ssam } else if (rq & RQ_MARKUP) { 85911195Ssam register struct ifnet *ifp = &is->hy_if; 86011195Ssam 86111207Ssam is->hy_flags &= ~RQ_MARKUP; 86211195Ssam is->hy_retry = 0; 86311195Ssam /* 86413065Ssam * Fill in the host number 86511207Ssam * from the status buffer 86611195Ssam */ 86711207Ssam printf( 86811207Ssam "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 86911195Ssam ui->ui_unit, 87011195Ssam is->hy_stat.hyc_uaddr, 87111195Ssam PORTNUM(&is->hy_status), 87211207Ssam (is->hy_stat.hyc_atype[0]<<8) | 87311207Ssam is->hy_stat.hyc_atype[1], 87411195Ssam is->hy_stat.hyc_atype[2]); 87511195Ssam 876*21775Skarels is->hy_host = 87711207Ssam (is->hy_stat.hyc_uaddr << 8) | 87811207Ssam PORTNUM(&is->hy_status); 87911195Ssam ifp->if_flags |= IFF_UP; 88011195Ssam #ifdef HYLOG 88111195Ssam hylog(HYL_UP, 0, (char *)0); 88211195Ssam #endif 88311195Ssam } else { 88411195Ssam is->hy_state = WAITING; 88511195Ssam is->hy_retry = 0; 88611195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0); 88711195Ssam } 88811195Ssam } 88911207Ssam break; 89011195Ssam } 89111195Ssam 89211195Ssam case STATSENT: 89312772Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status, 89411207Ssam sizeof (struct hy_status)); 89511195Ssam #ifdef DEBUG 89611207Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 89711207Ssam ui->ui_unit, is->hy_status.hys_gen_status, 89811207Ssam is->hy_status.hys_last_fcn, 89911207Ssam is->hy_status.hys_resp_trunk, 90011207Ssam is->hy_status.hys_status_trunk, 90111207Ssam is->hy_status.hys_recd_resp, 90211207Ssam is->hy_status.hys_error, 90311207Ssam is->hy_status.hys_caddr, 90411207Ssam is->hy_status.hys_pad); 90511195Ssam #endif 90611195Ssam is->hy_state = IDLE; 90711195Ssam #ifdef HYLOG 90811207Ssam hylog(HYL_STATUS, sizeof (struct hy_status), 90911207Ssam (char *)&is->hy_status); 91011195Ssam #endif 91111195Ssam #ifdef HYELOG 91211195Ssam { 91311195Ssam register int i; 91411195Ssam 91511195Ssam i = is->hy_status.hys_error; 91621128Skarels if (i > HYE_MAX) 91711195Ssam i = HYE_MAX; 91811195Ssam switch (is->hy_status.hys_last_fcn) { 91911195Ssam case HYF_XMITLOCMSG: 92011195Ssam i += HYE_MAX+1; /* fall through */ 92111195Ssam case HYF_XMITLSTDATA: 92211195Ssam i += HYE_MAX+1; /* fall through */ 92311195Ssam case HYF_XMITMSG: 92411195Ssam i += HYE_MAX+1; 92511195Ssam } 92611195Ssam hy_elog[i]++; 92711195Ssam } 92811195Ssam #endif 92911195Ssam break; 93011195Ssam 93111195Ssam case RSTATSENT: { 93211207Ssam register struct hy_stat *p = 93311207Ssam (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 93411195Ssam 93521128Skarels bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat)); 93611195Ssam #ifdef DEBUG 93721128Skarels 93821128Skarels printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n", 93911195Ssam ui->ui_unit, 94021128Skarels (is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2], 94121128Skarels (is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2], 94221128Skarels (is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2], 94321128Skarels (is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]); 94421128Skarels printD(" ret0 %d ret1 %d ret2 %d ret3 %d\n", 94521128Skarels (is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2], 94621128Skarels (is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2], 94721128Skarels (is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2], 94821128Skarels (is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]); 94921128Skarels printD(" cancel %d abort %d atype %x %x %x uaddr %x\n", 95021128Skarels (is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1], 95121128Skarels (is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1], 95211195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 95311195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 95411195Ssam #endif 95511195Ssam is->hy_state = IDLE; 95611195Ssam #ifdef HYLOG 95711207Ssam hylog(HYL_STATISTICS, sizeof (struct hy_stat), 95811207Ssam (char *)&is->hy_stat); 95911195Ssam #endif 96011195Ssam break; 96111195Ssam } 96211195Ssam 96311195Ssam case CLEARSENT: 96411195Ssam is->hy_state = IDLE; 96511195Ssam break; 96611195Ssam 96711195Ssam case ENDOPSENT: 96811195Ssam is->hy_state = IDLE; 96911195Ssam break; 97011195Ssam 97111195Ssam case RECVSENT: { 97221128Skarels register struct hym_hdr *hym; 97311207Ssam register unsigned len; 97411195Ssam 97511207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 97611207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 97713088Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 97821128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 97911207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 98011207Ssam if (len > MPSIZE) { 98111207Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n", 98213088Ssam ui->ui_unit, len); 98321128Skarels is->hy_state = IDLE; 98411195Ssam #ifdef DEBUG 98511207Ssam hy_debug_flag = 1; 98611207Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 98711207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 98811207Ssam addr->hyd_bar, addr->hyd_wcr); 98911195Ssam #endif 99011207Ssam } 99121128Skarels hym->hym_mplen = len; 99211195Ssam #ifdef DEBUG 99311207Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 99411207Ssam if (hy_debug_flag) 99521128Skarels hyprintdata((char *)hym, len + HYM_SWLEN); 99611195Ssam #endif 99721128Skarels if (hym->hym_ctl & H_ASSOC) { 99811207Ssam is->hy_state = RECVDATASENT; 99911207Ssam is->hy_retry = 0; 100011207Ssam hystart(ui, HYF_INPUTDATA, 100121128Skarels (int)(HYMTU + sizeof (struct hy_hdr) - len), 100221128Skarels (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len)); 100311207Ssam } else { 100421128Skarels hyrecvdata(ui, hym, (int)len + HYM_SWLEN); 100511207Ssam is->hy_state = IDLE; 100611195Ssam } 100711207Ssam break; 100811207Ssam } 100911195Ssam 101011195Ssam case RECVDATASENT: { 101121128Skarels register struct hym_hdr *hym; 101211207Ssam register unsigned len; 101311195Ssam 101411207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 101511207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 101613088Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 101721128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 101811207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 101911195Ssam #ifdef DEBUG 102011207Ssam printD("hy%d: recvd assoc data, len = %d, data = ", 102111207Ssam ui->ui_unit, len); 102211207Ssam if (hy_debug_flag) 102321128Skarels hyprintdata((char *)hym + hym->hym_mplen, len); 102411195Ssam #endif 102521128Skarels hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN)); 102611207Ssam is->hy_state = IDLE; 102711207Ssam break; 102811207Ssam } 102911195Ssam 103011195Ssam case XMITSENT: 103111207Ssam if (is->hy_flags & RQ_XASSOC) { 103213196Sroot register int len; 103311195Ssam 103411207Ssam is->hy_flags &= ~RQ_XASSOC; 103511207Ssam is->hy_state = XMITDATASENT; 103611207Ssam is->hy_retry = 0; 103711207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 103811207Ssam if (len > is->hy_olen) { 103911207Ssam printf( 104011207Ssam "hy%d: xmit error - len > hy_olen [%d > %d]\n", 104111207Ssam ui->ui_unit, len, is->hy_olen); 104211195Ssam #ifdef DEBUG 104311207Ssam hy_debug_flag = 1; 104411195Ssam #endif 104511195Ssam } 104611207Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 104721128Skarels is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len); 104811207Ssam break; 104911207Ssam } 105011207Ssam /* fall through to ... */ 105111195Ssam 105211195Ssam case XMITDATASENT: 105311207Ssam hyxmitdata(ui); 105411207Ssam is->hy_state = IDLE; 105511207Ssam break; 105611195Ssam 105711195Ssam case WAITING: /* wait for message complete or output requested */ 105811207Ssam if (HYS_RECVDATA(addr)) 105911195Ssam is->hy_state = IDLE; 106011195Ssam else { 106111195Ssam is->hy_state = CLEARSENT; 106211195Ssam is->hy_retry = 0; 106311195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0); 106411195Ssam } 106511195Ssam break; 106611195Ssam 106711195Ssam case MARKPORT: 106811195Ssam is->hy_state = STARTUP; 106921128Skarels if_down(&is->hy_if); 107011195Ssam is->hy_if.if_flags &= ~IFF_UP; 107111195Ssam goto endintr; 107211195Ssam 107311195Ssam default: 107411207Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 107511207Ssam ui->ui_unit, is->hy_state); 107611195Ssam panic("HYPERCHANNEL IN INVALID STATE"); 107711195Ssam /*NOTREACHED*/ 107811207Ssam } 107911195Ssam if (is->hy_state == IDLE) 108011195Ssam goto actloop; 108111195Ssam endintr: 108213088Ssam ; 108311195Ssam #ifdef DEBUG 108411207Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 108511207Ssam hy_state_names[is->hy_state]); 108611195Ssam #endif 108711207Ssam } 108811195Ssam 108921128Skarels struct sockproto hypproto = { PF_HYLINK }; 109021128Skarels struct sockaddr_in hypdst = { AF_HYLINK }; 109121128Skarels struct sockaddr_in hypsrc = { AF_HYLINK }; 109221128Skarels 109311195Ssam /* 109413088Ssam * Called from device interrupt when receiving data. 109511195Ssam * Examine packet to determine type. Decapsulate packet 109611195Ssam * based on type and pass to type specific higher-level 109711195Ssam * input routine. 109811195Ssam */ 109921128Skarels hyrecvdata(ui, hym, len) 110011195Ssam struct uba_device *ui; 110121128Skarels register struct hym_hdr *hym; 110211195Ssam int len; 110311195Ssam { 110411195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 110511195Ssam struct mbuf *m; 110611195Ssam register struct ifqueue *inq; 110711195Ssam 110811195Ssam is->hy_if.if_ipackets++; 110911195Ssam #ifdef DEBUG 111021128Skarels printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len); 111111195Ssam #endif 111211195Ssam #ifdef HYLOG 111311195Ssam { 111411195Ssam struct { 111511195Ssam short hlen; 111621128Skarels struct hym_hdr hhdr; 111711195Ssam } hh; 111811195Ssam hh.hlen = len; 111921128Skarels hh.hhdr = *hym; 112011195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh); 112111195Ssam } 112211195Ssam #endif 112311195Ssam if (len > HYMTU + MPSIZE || len == 0) 112411195Ssam return; /* sanity */ 112511195Ssam /* 112611195Ssam * Pull packet off interface. 112711195Ssam */ 112811195Ssam m = if_rubaget(&is->hy_ifuba, len, 0); 112911207Ssam if (m == NULL) 113011195Ssam return; 113111195Ssam 113221128Skarels /* 113321128Skarels * if normal or adapter loopback response packet believe hym_type, 113421128Skarels * otherwise, use the raw input queue cause it's a response from an 113521128Skarels * adapter command. 113621128Skarels */ 113721128Skarels if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff) 113821128Skarels goto rawlinkin; 113921128Skarels 114021128Skarels switch (hym->hym_type) { 114121128Skarels 114211195Ssam #ifdef INET 114311195Ssam case HYLINK_IP: 114411195Ssam schednetisr(NETISR_IP); 114511195Ssam inq = &ipintrq; 114611195Ssam break; 114711195Ssam #endif 114811195Ssam default: 114921128Skarels rawlinkin: 115021128Skarels { 115121128Skarels struct mbuf *m0; 115221128Skarels 115321128Skarels MGET(m0, M_DONTWAIT, MT_DATA); 115421128Skarels if (m == 0) { 115521128Skarels m_freem(m); 115621128Skarels return; 115721128Skarels } 115821128Skarels m0->m_off = MMINOFF; 115921128Skarels m0->m_len = sizeof(struct hym_hdr); 116021128Skarels m0->m_next = m; 116121128Skarels bcopy((caddr_t)hym, mtod(m0, caddr_t), sizeof(struct hym_hdr)); 116221128Skarels m = m0; 116321128Skarels hypproto.sp_protocol = 0; 1164*21775Skarels hypdst.sin_addr = is->hy_addr; 1165*21775Skarels hypsrc.sin_addr = is->hy_addr; 116621128Skarels raw_input(m, &hypproto, (struct sockaddr *)&hypsrc, 116721128Skarels (struct sockaddr *)&hypdst); 116821128Skarels return; 116921128Skarels } 117011195Ssam } 117111195Ssam if (IF_QFULL(inq)) { 117211195Ssam IF_DROP(inq); 117311195Ssam m_freem(m); 117411195Ssam } else 117511195Ssam IF_ENQUEUE(inq, m); 117611207Ssam } 117711195Ssam 117811195Ssam /* 117911207Ssam * Transmit done, release resources, bump counters. 118011195Ssam */ 118111195Ssam hyxmitdata(ui) 118211195Ssam struct uba_device *ui; 118311195Ssam { 118411195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 118511195Ssam 118611195Ssam is->hy_if.if_opackets++; 118711207Ssam if (is->hy_ifuba.ifu_xtofree) { 118811195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 118911195Ssam is->hy_ifuba.ifu_xtofree = 0; 119011195Ssam } 119111207Ssam } 119211195Ssam 119311195Ssam hycancel(ui) 119411195Ssam register struct uba_device *ui; 119511195Ssam { 119611195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 119711195Ssam 119811207Ssam if (is->hy_ifuba.ifu_xtofree) { 119911195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 120011195Ssam is->hy_ifuba.ifu_xtofree = 0; 120111195Ssam } 120221128Skarels #ifdef HYLOG 120321128Skarels hylog(HYL_CANCEL, 0, (char *)0); 120421128Skarels #endif 120511195Ssam #ifdef DEBUG 120611207Ssam if (hy_nodebug & 1) 120711207Ssam hy_debug_flag = 1; 120811195Ssam #endif 120911195Ssam #ifdef DEBUG 121011195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 121111195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 121211195Ssam is->hy_savedcount, is->hy_savedaddr); 121321128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 121421128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 121511207Ssam printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 121611207Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 121711207Ssam is->hy_savedcmd); 121811195Ssam #endif 121911195Ssam is->hy_state = IDLE; 122011195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 122111195Ssam hyact(ui); 122211207Ssam } 122311195Ssam 122411195Ssam #ifdef DEBUG 122511195Ssam hyprintdata(cp, len) 122611195Ssam register char *cp; 122711195Ssam register int len; 122811195Ssam { 122911195Ssam register int count = 16; 123011195Ssam register char *fmt; 123111195Ssam static char regfmt[] = "\n\t %x"; 123211195Ssam 123311195Ssam fmt = ®fmt[2]; 123411195Ssam while (--len >= 0) { 123511195Ssam printL(fmt, *cp++ & 0xff); 123611195Ssam fmt = ®fmt[2]; 123711195Ssam if (--count <= 0) { 123811195Ssam fmt = ®fmt[0]; 123911195Ssam count = 16; 124011195Ssam } 124111195Ssam } 124211195Ssam printL("\n"); 124311195Ssam } 124411195Ssam #endif 124511195Ssam 124611195Ssam hywatch(unit) 124713088Ssam int unit; 124811195Ssam { 124911195Ssam register struct hy_softc *is = &hy_softc[unit]; 125011195Ssam register struct uba_device *ui = hyinfo[unit]; 125111195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 125211195Ssam int s; 125311195Ssam 125411195Ssam s = splimp(); 125511195Ssam #ifdef PI13 125611195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 125711195Ssam addr->hyd_csr |= S_POWEROFF; 125811195Ssam DELAY(100); 125911195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) { 126021128Skarels printf("hy%d: Adapter Power Restored (hywatch)\n", unit); 126111195Ssam is->hy_state = IDLE; 126211207Ssam is->hy_flags |= 126311207Ssam (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 126411195Ssam hyact(ui); 126511195Ssam } 126611195Ssam } 126711195Ssam #endif 126821128Skarels if (++is->hy_ntime >= 2 && is->hy_state != WAITING && 126921128Skarels is->hy_state != STARTUP && is->hy_state != IDLE) { 127021128Skarels #ifdef HYLOG 127121128Skarels printf("hy%d: watchdog timer expired in state \"%s\"\n", unit, 127221128Skarels hy_state_names[is->hy_state]); 127321128Skarels #else 127421128Skarels printf("hy%d: watchdog timer expired in state %d\n", unit, 127521128Skarels is->hy_state); 127621128Skarels #endif 127721128Skarels printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit, 127821128Skarels is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS); 127921128Skarels hycancel(ui); 128021128Skarels } 128111195Ssam splx(s); 128221128Skarels is->hy_if.if_timer = SCANINTERVAL; 128311195Ssam } 128411195Ssam 128511195Ssam #ifdef HYLOG 128611195Ssam hylog(code, len, ptr) 128713088Ssam int code, len; 128811195Ssam char *ptr; 128911195Ssam { 129011195Ssam register unsigned char *p; 129111195Ssam int s; 129211195Ssam 129311195Ssam s = splimp(); 129411195Ssam if (hy_log.hyl_self != &hy_log) { 129511195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 129611195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 129711195Ssam hy_log.hyl_self = &hy_log; 129821128Skarels hy_log.hyl_enable = HYL_CONTINUOUS; 129921128Skarels hy_log.hyl_onerr = HYL_CONTINUOUS; 130021128Skarels hy_log.hyl_count = 0; 130121128Skarels hy_log.hyl_icount = 16; 130221128Skarels hy_log.hyl_filter = 0xffff; /* enable all */ 130311195Ssam } 130421128Skarels if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0) 130511207Ssam goto out; 130611195Ssam p = hy_log.hyl_ptr; 130721128Skarels if (p + len + 3 >= hy_log.hyl_eptr) { 130812772Ssam bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 130911195Ssam p = &hy_log.hyl_buf[0]; 131021128Skarels if (hy_log.hyl_enable != HYL_CONTINUOUS) { 131121128Skarels hy_log.hyl_enable = HYL_DISABLED; 131211195Ssam goto out; 131311195Ssam } 131411195Ssam } 131511195Ssam *p++ = code; 131611195Ssam *p++ = len; 131713088Ssam bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len); 131821128Skarels if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) { 131921128Skarels *p++ = '\0'; 132021128Skarels hy_log.hyl_enable = HYL_DISABLED; 132121128Skarels hy_log.hyl_count = hy_log.hyl_icount; 132221128Skarels } 132321128Skarels if (hy_log.hyl_wait != 0) { /* wakeup HYGETLOG if wanted */ 132421128Skarels hy_log.hyl_wait -= (p - hy_log.hyl_ptr) + len; 132521128Skarels if (hy_log.hyl_wait <= 0) { 132621128Skarels wakeup((caddr_t)&hy_log); 132721128Skarels hy_log.hyl_wait = 0; 132821128Skarels } 132921128Skarels } 133011195Ssam hy_log.hyl_ptr = p + len; 133111195Ssam out: 133211195Ssam splx(s); 133311195Ssam } 133411195Ssam #endif 133511195Ssam 133612772Ssam /*ARGSUSED*/ 133713058Ssam hyioctl(ifp, cmd, data) 133813058Ssam register struct ifnet *ifp; 133911207Ssam int cmd; 134011207Ssam caddr_t data; 134111195Ssam { 1342*21775Skarels struct ifaddr *ifa = (struct ifaddr *) data; 134321128Skarels struct hyrsetget *sg = (struct hyrsetget *)data; 134421128Skarels #if defined(HYLOG) || defined(HYELOG) 134521128Skarels struct hylsetget *sgl = (struct hylsetget *)data; 134621128Skarels #endif 134721128Skarels struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit]; 134811207Ssam int s = splimp(), error = 0; 134921128Skarels #ifdef HYLOG 135021128Skarels struct hy_softc *is = &hy_softc[ifp->if_unit]; 135121128Skarels struct { 135221128Skarels u_char hstate; 135321128Skarels u_char hflags; 135421128Skarels u_short iflags; 135521128Skarels int hcmd; 135621128Skarels int herror; 135721128Skarels u_long haddr; 135821128Skarels u_long hmisc; 135921128Skarels } hil; 136011195Ssam 136121128Skarels hil.hmisc = -1; 136221128Skarels hil.hstate = is->hy_state; 136321128Skarels hil.hflags = is->hy_flags; 136421128Skarels hil.hcmd = cmd; 136521128Skarels #endif 136621128Skarels 136711195Ssam switch(cmd) { 136811195Ssam 136913065Ssam case SIOCSIFADDR: 137021128Skarels if (sin->sin_family != AF_INET) 137121128Skarels return(EINVAL); 1372*21775Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 1373*21775Skarels hyinit(ifp->if_unit); 1374*21775Skarels hy_softc[ifp->if_unit].hy_addr = IA_SIN(ifa)->sin_addr; 137521128Skarels #ifdef HYLOG 1376*21775Skarels hil.haddr = is->hy_addr.s_addr; 137721128Skarels #endif 137813065Ssam break; 137913065Ssam 138011195Ssam case HYSETROUTE: 138111207Ssam if (!suser()) { 138211207Ssam error = EPERM; 138321128Skarels goto out; 138411195Ssam } 138521128Skarels 138621128Skarels if (sg->hyrsg_len != sizeof(struct hy_route)) { 138721128Skarels error = EINVAL; 138821128Skarels goto out; 138921128Skarels } 139021128Skarels if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) { 139121128Skarels r->hyr_lasttime = 0; /* disable further routing if trouble */ 139221128Skarels error = EFAULT; 139321128Skarels goto out; 139421128Skarels } 139521128Skarels r->hyr_lasttime = time.tv_sec; 139621128Skarels #ifdef HYLOG 139721128Skarels hil.hmisc = r->hyr_lasttime; 139821128Skarels #endif 139911195Ssam break; 140011195Ssam 140111195Ssam case HYGETROUTE: 140221128Skarels if (sg->hyrsg_len < sizeof(struct hy_route)) { 140321128Skarels error = EINVAL; 140421128Skarels goto out; 140521128Skarels } 140621128Skarels if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) { 140721128Skarels error = EFAULT; 140821128Skarels goto out; 140921128Skarels } 141011195Ssam break; 141111195Ssam 141221128Skarels #ifdef HYELOG 141321128Skarels case HYGETELOG: 141421128Skarels if (sgl->hylsg_len < sizeof(hy_elog)) { 141521128Skarels error = EINVAL; 141621128Skarels goto out; 141721128Skarels } 141821128Skarels if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) { 141921128Skarels error = EFAULT; 142021128Skarels goto out; 142121128Skarels } 142221128Skarels if (sgl->hylsg_cmd) { 142321128Skarels if (!suser()) { 142421128Skarels error = EPERM; 142521128Skarels goto out; 142621128Skarels } 142721128Skarels bzero((caddr_t)hy_elog, sizeof(hy_elog)); 142821128Skarels } 142921128Skarels break; 143021128Skarels #endif 143121128Skarels 143221128Skarels #ifdef HYLOG 143321128Skarels case HYSETLOG: 143421128Skarels if (!suser()) { 143521128Skarels error = EPERM; 143621128Skarels goto out; 143721128Skarels } 143821128Skarels hy_log.hyl_enable = HYL_DISABLED; 143921128Skarels hylog(HYL_NOP, 0, (char *)0); /* force log init */ 144021128Skarels hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f; 144121128Skarels hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f; 144221128Skarels hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff; 144321128Skarels hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len; 144421128Skarels wakeup((caddr_t)&hy_log); /* wakeup sleeping HYGETLOG */ 144521128Skarels break; 144621128Skarels 144721128Skarels case HYGETLOG: 144821128Skarels if (sgl->hylsg_len < sizeof(hy_log)) { 144921128Skarels error = EINVAL; 145021128Skarels goto out; 145121128Skarels } 145221128Skarels if (sgl->hylsg_cmd != 0) { 145321128Skarels if (hy_log.hyl_wait) { 145421128Skarels error = EBUSY; 145521128Skarels goto out; 145621128Skarels } 145721128Skarels hy_log.hyl_wait = sgl->hylsg_cmd; 145821128Skarels sleep((caddr_t)&hy_log); 145921128Skarels } 146021128Skarels 146121128Skarels if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) { 146221128Skarels error = EFAULT; 146321128Skarels goto out; 146421128Skarels } 146521128Skarels break; 146621128Skarels #endif 146721128Skarels 146811195Ssam default: 146913058Ssam error = EINVAL; 147011195Ssam break; 147111195Ssam } 147221128Skarels out: 147321128Skarels #ifdef HYLOG 147421128Skarels hil.herror = error; 147521128Skarels hil.iflags = ifp->if_flags; 1476*21775Skarels hil.haddr = is->hy_addr.s_addr; 147721128Skarels hylog(HYL_IOCTL, sizeof(hil), (char *)&hil); 147821128Skarels #endif 147911195Ssam splx(s); 148011207Ssam return (error); 148111195Ssam } 148211207Ssam #endif 1483