123294Smckusick /* 223294Smckusick * Copyright (c) 1982 Regents of the University of California. 323294Smckusick * All rights reserved. The Berkeley software License Agreement 423294Smckusick * specifies the terms and conditions for redistribution. 523294Smckusick * 6*26285Skarels * @(#)if_hy.c 6.8 (Berkeley) 02/20/86 723294Smckusick */ 811195Ssam 921128Skarels /* 1021128Skarels * 4.2 BSD Unix Kernel - Vax Network Interface Support 1121128Skarels * 1221128Skarels * $Header: if_hy.c,v 10.1 84/07/22 21:02:56 steveg Exp $ 1321128Skarels * $Locker: $ 1421128Skarels * 1521128Skarels * Modifications from Berkeley 4.2 BSD 1621128Skarels * Copyright (c) 1983, Tektronix Inc. 1721128Skarels * All Rights Reserved 1821128Skarels * 1921128Skarels * $Log: if_hy.c,v $ 2021128Skarels * Revision 10.1 84/07/22 21:02:56 steveg 2121128Skarels * define PI13 (moved from if_hyreg.h, somehow got dropped in the process) 2221128Skarels * rework hywatch to check for power fails first 2321128Skarels * 2421128Skarels * Revision 10.0 84/06/30 19:54:27 steveg 2521128Skarels * Big Build 2621128Skarels * 2721128Skarels * Revision 3.17 84/06/20 19:20:28 steveg 2821128Skarels * increment hy_ntime in hywatch 2921128Skarels * print out state name, csr, last command, and hy_flags when watchdog timer 3021128Skarels * expires 3121128Skarels * 3221128Skarels * Revision 3.16 84/06/20 19:09:34 steveg 3321128Skarels * turn on continuous logging by default 3421128Skarels * 3521128Skarels * Revision 3.15 84/05/30 22:19:09 steveg 3621128Skarels * changes to reflect new layout ot statistics data 3721128Skarels * 3821128Skarels * Revision 3.14 84/05/30 19:25:15 steveg 3921128Skarels * move driver states to if_hy.h so log printing programs can use them 4021128Skarels * 4121128Skarels * Revision 3.13 84/05/30 17:13:26 steveg 4221128Skarels * make it compile 4321128Skarels * 4421128Skarels * Revision 3.12 84/05/30 13:46:16 steveg 4521128Skarels * rework logging 4621128Skarels * 4721128Skarels * Revision 3.11 84/05/18 19:35:02 steveg 4821128Skarels * clear IFF_RUNNING and IFF_UP on unibus reset to force resource allocation 4921128Skarels * by the init routine 5021128Skarels * 5121128Skarels * Revision 3.10 84/05/04 12:14:44 steveg 5221128Skarels * more rework to make it actually work under 4.2 5321128Skarels * 5421128Skarels * Revision 3.9 84/05/01 23:34:52 steveg 5521128Skarels * fix typo so it compiles (unit -> ui->ui_unit) 5621128Skarels * 5721128Skarels * Revision 3.8 84/05/01 23:18:30 steveg 5821128Skarels * changes after talking with rickk 5921128Skarels * - check power off more closely 6021128Skarels * - support remote loopback through A710 adapters 6121128Skarels * - IMPLINK -> HYLINK 6221128Skarels * - return EHOSTUNREACH on hyroute failure 6321128Skarels * - bump if_collisions on abnormal interrupts that aren't input or output 6421128Skarels * 6521128Skarels * 6621128Skarels */ 6721128Skarels 6821128Skarels 6911195Ssam #include "hy.h" 7011195Ssam #if NHY > 0 7111195Ssam 7211195Ssam /* 7311195Ssam * Network Systems Copropration Hyperchanel interface 7411195Ssam */ 7521128Skarels #include "machine/pte.h" 7611195Ssam 7721775Skarels #include "param.h" 7821775Skarels #include "systm.h" 7921775Skarels #include "mbuf.h" 8021775Skarels #include "buf.h" 8121775Skarels #include "protosw.h" 8221775Skarels #include "socket.h" 8321775Skarels #include "vmmac.h" 8421775Skarels #include "errno.h" 8521775Skarels #include "time.h" 8621775Skarels #include "kernel.h" 8721775Skarels #include "ioctl.h" 8813088Ssam 8911195Ssam #include "../net/if.h" 9011207Ssam #include "../net/netisr.h" 9111195Ssam #include "../net/route.h" 9224797Skarels 9324797Skarels #ifdef INET 9411195Ssam #include "../netinet/in.h" 9511195Ssam #include "../netinet/in_systm.h" 9624797Skarels #include "../netinet/in_var.h" 9711195Ssam #include "../netinet/ip.h" 9824797Skarels #endif 9911195Ssam 10011207Ssam #include "../vax/cpu.h" 10111207Ssam #include "../vax/mtpr.h" 10211207Ssam #include "../vaxuba/ubareg.h" 10311207Ssam #include "../vaxuba/ubavar.h" 10411195Ssam 10521128Skarels /* 10621128Skarels * configuration specific paramters 10721128Skarels * - change as appropriate for particular installaions 10821128Skarels */ 10921128Skarels #define HYROUTE 11021128Skarels #define HYELOG 11121128Skarels #define HYLOG 11221128Skarels #define HYMTU 1100 11321128Skarels #define PI13 11411195Ssam 11521128Skarels #ifdef DEBUG 11621128Skarels #define HYLOG 11721128Skarels #endif 11821128Skarels 11921775Skarels #include "if_hy.h" 12021775Skarels #include "if_hyreg.h" 12121775Skarels #include "if_uba.h" 12221128Skarels 12313058Ssam int hyprobe(), hyattach(), hyinit(), hyioctl(); 12413058Ssam int hyoutput(), hyreset(), hywatch(); 12511195Ssam struct uba_device *hyinfo[NHY]; 12611195Ssam u_short hystd[] = { 0772410, 0 }; 12711195Ssam struct uba_driver hydriver = 12811195Ssam { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo }; 12911195Ssam 13011195Ssam /* 13111195Ssam * Hyperchannel software status per interface. 13211195Ssam * 13311195Ssam * Each interface is referenced by a network interface structure, 13411195Ssam * hy_if, which the routing code uses to locate the interface. 13511195Ssam * This structure contains the output queue for the interface, its address, ... 13611195Ssam * We also have, for each interface, a UBA interface structure, which 13711195Ssam * contains information about the UNIBUS resources held by the interface: 13811195Ssam * map registers, buffered data paths, etc. Information is cached in this 13911195Ssam * structure for use by the if_uba.c routines in running the interface 14011195Ssam * efficiently. 14111195Ssam */ 14211195Ssam struct hy_softc { 14311195Ssam struct ifnet hy_if; /* network-visible interface */ 14411195Ssam struct ifuba hy_ifuba; /* UNIBUS resources */ 14511207Ssam short hy_flags; /* flags */ 14611207Ssam short hy_state; /* driver state */ 14721775Skarels u_short hy_host; /* local host number */ 14821775Skarels struct in_addr hy_addr; /* internet address */ 14911195Ssam int hy_olen; /* packet length on output */ 15011195Ssam int hy_lastwcr; /* last command's word count */ 15111195Ssam short hy_savedstate; /* saved for reissue after status */ 15211195Ssam short hy_savedcmd; /* saved command for reissue */ 15311195Ssam int hy_savedcount; /* saved byte count for reissue */ 15411195Ssam int hy_savedaddr; /* saved unibus address for reissue */ 15511195Ssam int hy_ntime; /* number of timeouts since last cmd */ 15611195Ssam int hy_retry; /* retry counter */ 15711207Ssam struct hy_stat hy_stat; /* statistics */ 15811207Ssam struct hy_status hy_status; /* status */ 15911195Ssam } hy_softc[NHY]; 16011195Ssam 16111195Ssam #ifdef HYELOG 16221128Skarels u_long hy_elog[HYE_SIZE]; 16311195Ssam #endif 16411195Ssam 16521128Skarels #ifdef HYLOG 16621128Skarels struct hy_log hy_log; 16721128Skarels #endif 16821128Skarels 16921128Skarels #ifdef HYROUTE 17021128Skarels struct hy_route hy_route[NHY]; 17121128Skarels #endif 17221128Skarels 17311195Ssam #ifdef DEBUG 17421128Skarels #define printL printf 17521128Skarels #define printD if (hy_debug_flag) printf 17611195Ssam int hy_debug_flag = 0; 17711195Ssam /* 17811195Ssam * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 17911195Ssam * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 18011195Ssam * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 18111195Ssam */ 18211195Ssam int hy_nodebug = 0x0; 18311195Ssam #endif 18411195Ssam 18511195Ssam #define SCANINTERVAL 10 /* seconds */ 18611195Ssam #define MAXINTERVAL 20 /* seconds (max action) */ 18711195Ssam 18811195Ssam /* 18911195Ssam * Cause a device interrupt. This code uses a buffer starting at 19011195Ssam * location zero on the unibus (which is already mapped by the 19111195Ssam * autoconfigure code in the kernel). 19211195Ssam */ 19311195Ssam hyprobe(reg) 19411195Ssam caddr_t reg; 19511195Ssam { 19611195Ssam register int br, cvec; /* r11, r10 value-result */ 19711195Ssam register struct hydevice *addr = (struct hydevice *) reg; 19811195Ssam 19911195Ssam #ifdef lint 20011195Ssam br = 0; cvec = br; br = cvec; 20111195Ssam hyint(0); 20211195Ssam #endif 20311195Ssam /* 20411195Ssam * request adapter status to a buffer starting at unibus location 0 20511195Ssam */ 20611195Ssam addr->hyd_bar = 0; 20711195Ssam addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 20811195Ssam addr->hyd_dbuf = HYF_STATUS; 20911195Ssam #ifdef PI13 21011195Ssam addr->hyd_csr |= S_GO | S_IE | S_IATTN; 21111195Ssam #else 21211195Ssam addr->hyd_csr |= S_GO | S_IE; 21311195Ssam #endif 21411195Ssam DELAY(10000); 21511195Ssam #ifdef PI13 21611195Ssam addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 21711195Ssam #endif 21811195Ssam addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 21921128Skarels return(sizeof(struct hydevice)); 22011207Ssam } 22111195Ssam 22211195Ssam /* 22311195Ssam * Interface exists: make available by filling in network interface 22411195Ssam * record. System will initialize the interface when it is ready 22511195Ssam * to accept packets. 22611195Ssam */ 22711195Ssam hyattach(ui) 22811195Ssam struct uba_device *ui; 22911195Ssam { 23011195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 23111195Ssam register struct ifnet *ifp = &is->hy_if; 23211195Ssam 23311195Ssam ifp->if_unit = ui->ui_unit; 23411195Ssam ifp->if_name = "hy"; 23511195Ssam ifp->if_mtu = HYMTU; 23611195Ssam is->hy_state = STARTUP; /* don't allow state transitions yet */ 23711195Ssam ifp->if_init = hyinit; 23813058Ssam ifp->if_ioctl = hyioctl; 23911195Ssam ifp->if_output = hyoutput; 24011207Ssam ifp->if_reset = hyreset; 24111195Ssam ifp->if_watchdog = hywatch; 24211195Ssam ifp->if_timer = SCANINTERVAL; 24311195Ssam is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 24411207Ssam #ifdef notdef 24511195Ssam is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 24611195Ssam #endif 24711195Ssam if_attach(ifp); 24811207Ssam } 24911195Ssam 25011195Ssam /* 25111195Ssam * Reset of interface after UNIBUS reset. 25211195Ssam * If interface is on specified uba, reset its state. 25311195Ssam */ 25411195Ssam hyreset(unit, uban) 25511195Ssam int unit, uban; 25611195Ssam { 25721128Skarels register struct uba_device *ui; 25821128Skarels register struct hy_softc *is; 25911195Ssam 26021128Skarels if (unit >= NHY || (ui = hyinfo[unit]) == 0 || ui->ui_alive == 0 || 26111207Ssam ui->ui_ubanum != uban) 26211195Ssam return; 26311195Ssam printf(" hy%d", unit); 26421128Skarels is = &hy_softc[unit]; /* force unibus resource allocation */ 26521128Skarels is->hy_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 26611195Ssam hyinit(unit); 26711207Ssam } 26811195Ssam 26911195Ssam /* 27011195Ssam * Initialization of interface; clear recorded pending 27111195Ssam * operations, and reinitialize UNIBUS usage. 27211195Ssam */ 27311195Ssam hyinit(unit) 27411195Ssam int unit; 27511195Ssam { 27611195Ssam register struct hy_softc *is = &hy_softc[unit]; 27711195Ssam register struct uba_device *ui = hyinfo[unit]; 27821128Skarels register struct mbuf *m; 27911195Ssam int s; 28011195Ssam 28121775Skarels if (is->hy_if.if_addrlist == 0) /* address still unknown */ 28213065Ssam return; 28321128Skarels if (is->hy_if.if_flags & IFF_RUNNING) /* just reset the device */ 28421128Skarels goto justreset; 28511195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 28621128Skarels sizeof (struct hym_hdr), (int)btoc(HYMTU)) == 0) { 28711195Ssam #ifdef DEBUG 28811207Ssam if (hy_nodebug & 4) 28911207Ssam hy_debug_flag = 1; 29011195Ssam #endif 29111195Ssam printf("hy%d: can't initialize\n", unit); 29211195Ssam is->hy_if.if_flags &= ~IFF_UP; 29311195Ssam return; 29411195Ssam } 29513088Ssam is->hy_if.if_flags |= IFF_RUNNING; 29621128Skarels 29721128Skarels justreset: 29811195Ssam /* 29921128Skarels * remove any left over outgoing messages, reset the hardware and 30021128Skarels * start the state machine 30111195Ssam */ 30211195Ssam s = splimp(); 30321128Skarels #ifdef HYLOG 30421128Skarels hylog(HYL_RESET, 0, (char *)0); 30521128Skarels #endif 30611195Ssam is->hy_state = IDLE; 30711195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 30811195Ssam is->hy_retry = 0; 30921128Skarels for(;;) { 31021128Skarels IF_DEQUEUE(&is->hy_if.if_snd, m); 31121128Skarels if (m != NULL) 31221128Skarels m_freem(m); 31321128Skarels else 31421128Skarels break; 31521128Skarels } 31621128Skarels hycancel(ui); /* also bumps the state machine */ 31711195Ssam splx(s); 31811207Ssam } 31911195Ssam 32011195Ssam /* 32111207Ssam * Issue a command to the adapter 32211195Ssam */ 32311195Ssam hystart(ui, cmd, count, ubaddr) 32411195Ssam struct uba_device *ui; 32511207Ssam int cmd, count, ubaddr; 32611195Ssam { 32711195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 32811195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 32911195Ssam 33011195Ssam #ifdef DEBUG 33111207Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 33211207Ssam ui->ui_unit, cmd, count, ubaddr); 33311195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 33411207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 33511207Ssam addr->hyd_wcr); 33611195Ssam #endif 33711207Ssam if (((is->hy_flags & RQ_REISSUE) == 0) && 33811207Ssam (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 33911195Ssam is->hy_savedstate = is->hy_state; 34011195Ssam is->hy_savedcmd = cmd; 34111195Ssam is->hy_savedcount = count; 34211195Ssam is->hy_savedaddr = ubaddr; 34311195Ssam } 34421128Skarels #ifdef PI13 34521128Skarels if (addr->hyd_csr & S_POWEROFF) { 34621128Skarels printf("hy%d: \"Soft\" Adapter Power Failure (hystart)\n", ui->ui_unit); 34721128Skarels addr->hyd_csr |= S_POWEROFF; 34821128Skarels DELAY(100); 34921128Skarels if (addr->hyd_csr & S_POWEROFF) { 35021128Skarels printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hystart)\n", ui->ui_unit); 35121128Skarels if_down(&is->hy_if); 35221128Skarels is->hy_if.if_flags &= ~IFF_UP; 35321128Skarels is->hy_state = STARTUP; 35421128Skarels } else { 35521128Skarels printf("hy%d: Adapter Power Restored (hystart)\n", ui->ui_unit); 35621128Skarels } 35721128Skarels return; 35821128Skarels } 35921128Skarels #endif 36011195Ssam addr->hyd_bar = ubaddr & 0xffff; 36111207Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 36211195Ssam addr->hyd_dbuf = cmd; 36311195Ssam #ifdef PI13 36411195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 36511195Ssam #else 36611195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 36711195Ssam #endif 36811195Ssam #ifdef DEBUG 36911195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 37011207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 37111207Ssam addr->hyd_wcr); 37211195Ssam #endif 37311195Ssam #ifdef HYLOG 37411195Ssam { 37511195Ssam struct { 37611207Ssam u_char hcmd; 37711207Ssam u_char hstate; 37811207Ssam short hcount; 37911195Ssam } hcl; 38011195Ssam 38111195Ssam hcl.hcmd = cmd; 38211195Ssam hcl.hstate = is->hy_state; 38311195Ssam hcl.hcount = count; 38411195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 38511195Ssam } 38611195Ssam #endif 38711195Ssam is->hy_ntime = 0; 38811207Ssam } 38911195Ssam 39011195Ssam int hyint_active = 0; /* set during hy interrupt */ 39111195Ssam /* 39211207Ssam * Hyperchannel interface interrupt. 39311195Ssam * 39411195Ssam * An interrupt can occur for many reasons. Examine the status of 39511195Ssam * the hyperchannel status bits to determine what to do next. 39611195Ssam * 39711195Ssam * If input error just drop packet. 39811195Ssam * Otherwise purge input buffered data path and examine 39911195Ssam * packet to determine type. Othewise decapsulate 40011195Ssam * packet based on type and pass to type specific higher-level 40111195Ssam * input routine. 40211195Ssam */ 40311195Ssam hyint(unit) 40411195Ssam int unit; 40511195Ssam { 40611195Ssam register struct hy_softc *is = &hy_softc[unit]; 40711195Ssam register struct uba_device *ui = hyinfo[unit]; 40811207Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 40911195Ssam 41011207Ssam if (hyint_active) 41111195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 41211195Ssam hyint_active++; 41311195Ssam #ifdef DEBUG 41411195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 41511195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 41611195Ssam #endif 41711195Ssam #ifdef HYLOG 41811195Ssam logit: 41911195Ssam { 42011195Ssam struct { 42111207Ssam u_char hstate; 42211207Ssam u_char hflags; 42311207Ssam short hcsr; 42411207Ssam short hwcr; 42511195Ssam } hil; 42611195Ssam hil.hstate = is->hy_state; 42711195Ssam hil.hflags = is->hy_flags; 42811195Ssam hil.hcsr = addr->hyd_csr; 42911195Ssam hil.hwcr = addr->hyd_wcr; 43011195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil); 43111195Ssam } 43211195Ssam #endif 43311207Ssam if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 43411195Ssam /* 43511207Ssam * Error bit set, some sort of error in the interface. 43611195Ssam * 43711207Ssam * The adapter sets attn on command completion so that's not 43811207Ssam * a real error even though the interface considers it one. 43911195Ssam */ 44011195Ssam #ifdef DEBUG 44111207Ssam if (hy_nodebug & 4) 44211207Ssam hy_debug_flag = 1; 44311195Ssam #endif 44411207Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 44511207Ssam addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 44611207Ssam addr->hyd_wcr); 44711207Ssam if (addr->hyd_csr & S_NEX) { 44811195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit); 44911195Ssam #ifdef PI13 45011195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 45111195Ssam #else 45211195Ssam addr->hyd_csr &= ~S_NEX; 45311195Ssam #endif 45411195Ssam hycancel(ui); 45511195Ssam #ifdef PI13 45611207Ssam } else if (addr->hyd_csr & S_POWEROFF) { 45721128Skarels printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit); 45811195Ssam addr->hyd_csr |= S_POWEROFF; 45911195Ssam DELAY(100); 46011207Ssam if (addr->hyd_csr & S_POWEROFF) { 46121128Skarels printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit); 46211195Ssam if_down(&is->hy_if); 46321128Skarels is->hy_if.if_flags &= ~IFF_UP; 46411195Ssam is->hy_state = STARTUP; 46521128Skarels } else { 46621128Skarels printf("hy%d: Adapter Power Restored (hyint)\n", unit); 46711195Ssam } 46811195Ssam #endif 46911195Ssam } else { 47011195Ssam printf("hy%d: BAR overflow\n", unit); 47111195Ssam hycancel(ui); 47211195Ssam } 47311207Ssam } else if (HYS_NORMAL(addr)) { 47411195Ssam /* 47511207Ssam * Normal interrupt, bump state machine unless in state 47611195Ssam * waiting and no data present (assumed to be word count 47711207Ssam * zero interrupt or other hardware botch). 47811195Ssam */ 47911207Ssam if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 48011195Ssam hyact(ui); 48111207Ssam } else if (HYS_ABNORMAL(addr)) { 48211195Ssam /* 48311207Ssam * Abnormal termination. 48411195Ssam * bump error counts, retry the last function 48511195Ssam * 'MAXRETRY' times before kicking the bucket. 48611195Ssam * 48711207Ssam * Don't reissue the cmd if in certain states, abnormal 48811207Ssam * on a reissued cmd or max retry exceeded. 48911195Ssam */ 49011195Ssam #ifdef HYLOG 49111195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 49211195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 49311195Ssam goto logit; 49411195Ssam } 49511195Ssam #endif 49611195Ssam #ifdef DEBUG 49711207Ssam if (hy_nodebug & 4) 49811207Ssam hy_debug_flag = 1; 49911195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 50011195Ssam unit, hy_state_names[is->hy_state], is->hy_state); 50121128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 50221128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 50311207Ssam printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 50411207Ssam is->hy_savedstate, is->hy_savedcount, 50511207Ssam is->hy_savedaddr, is->hy_savedcmd); 50611195Ssam #endif 50711195Ssam #ifdef PI13 50811195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 50911195Ssam #endif 51011207Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 51111195Ssam is->hy_if.if_oerrors++; 51221128Skarels else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 51311195Ssam is->hy_if.if_ierrors++; 51421128Skarels else 51521128Skarels is->hy_if.if_collisions++; /* other errors */ 51611195Ssam if (is->hy_state == XMITDATASENT || 51711195Ssam is->hy_state == RECVSENT || 51811195Ssam is->hy_state == RECVDATASENT || 51911207Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 52011195Ssam hycancel(ui); 52111207Ssam else { 52211195Ssam #ifdef DEBUG 52311207Ssam if (hy_nodebug & 2) 52411207Ssam hy_debug_flag = 1; 52511195Ssam #endif 52611195Ssam is->hy_retry++; 52711195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 52811195Ssam is->hy_state = IDLE; 52911195Ssam hyact(ui); 53011195Ssam } 53111195Ssam } else { 53211195Ssam /* 53311195Ssam * Interrupt is neither normal, abnormal, or interface error. 53411195Ssam * Ignore it. It's either stacked or a word count 0. 53511195Ssam */ 53611195Ssam #ifdef HYLOG 53711195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 53811195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 53911195Ssam goto logit; 54011195Ssam } 54111195Ssam #endif 54211195Ssam #ifdef DEBUG 54311195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit); 54411195Ssam #endif 54511195Ssam } 54611195Ssam #ifdef DEBUG 54711195Ssam printD("hy%d: hyint exit\n\n", unit); 54811195Ssam #endif 54911195Ssam hyint_active = 0; 55011195Ssam 55111207Ssam } 55211195Ssam 55321128Skarels int hyoutprint = 0; 55421128Skarels 55511195Ssam /* 55611195Ssam * Encapsulate a packet of type family for the local net. 55711195Ssam */ 55811195Ssam hyoutput(ifp, m0, dst) 55911195Ssam struct ifnet *ifp; 56011195Ssam struct mbuf *m0; 56111195Ssam struct sockaddr *dst; 56211195Ssam { 56311195Ssam register struct hym_hdr *hym; 56411195Ssam register struct mbuf *m; 56521128Skarels register char *mp; 56621128Skarels int dlen; /* packet size, incl hardware header, but not sw header */ 56711195Ssam int error = 0; 56811195Ssam int s; 56911195Ssam 57021128Skarels /* 57121128Skarels * Calculate packet length for later deciding whether it will fit 57221128Skarels * in a message proper or we also need associated data. 57321128Skarels */ 57411195Ssam dlen = 0; 57511195Ssam for (m = m0; m; m = m->m_next) 57611195Ssam dlen += m->m_len; 57711195Ssam m = m0; 57821128Skarels if (dst->sa_family == AF_HYLINK) { /* don't add header */ 57921128Skarels dlen -= HYM_SWLEN; 58021128Skarels goto headerexists; 58121128Skarels } 58221128Skarels 58321128Skarels /* 58421128Skarels * Add the software and hardware hyperchannel headers. 58521128Skarels * If there's not enough space in the first mbuf, allocate another. 58621128Skarels * If that should fail, drop this sucker. 58721128Skarels * No extra space for headers is allocated. 58821128Skarels */ 58921128Skarels mp = mtod(m, char *); /* save pointer to real message */ 59021128Skarels if (m->m_off > MMAXOFF || 59121128Skarels MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 59221128Skarels m = m_get(M_DONTWAIT, MT_HEADER); 59321128Skarels if (m == 0) { 59421128Skarels m = m0; 59521128Skarels error = ENOBUFS; 59621128Skarels goto drop; 59721128Skarels } 59821128Skarels m->m_next = m0; 59921128Skarels m->m_off = MMINOFF; 60021128Skarels m->m_len = sizeof(struct hym_hdr); 60121128Skarels } else { 60221128Skarels m->m_off -= sizeof(struct hym_hdr); 60321128Skarels m->m_len += sizeof(struct hym_hdr); 60421128Skarels } 60521128Skarels 60621128Skarels dlen += sizeof(struct hym_hdr) - HYM_SWLEN; 60721128Skarels 60821128Skarels hym = mtod(m, struct hym_hdr *); 60921128Skarels 61021128Skarels bzero((caddr_t)hym, sizeof(struct hym_hdr)); 61121128Skarels 61211195Ssam switch(dst->sa_family) { 61311195Ssam 61411195Ssam #ifdef INET 61511195Ssam case AF_INET: { 61621128Skarels int i; 61711195Ssam 61811195Ssam /* 61921128Skarels * if loopback address, swizzle ip header so when 62021128Skarels * it comes back it looks like it was addressed to us 62111195Ssam */ 62221128Skarels i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym); 62321128Skarels if (i < 0) 62421128Skarels goto notfound; 62521128Skarels if (i > 0) { 62611195Ssam struct in_addr temp; 62711195Ssam 62821128Skarels temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr; 62921128Skarels ((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr; 63021128Skarels ((struct ip *)mp)->ip_src.s_addr = temp.s_addr; 63111195Ssam } 63211195Ssam /* 63311195Ssam * If entire packet won't fit in message proper, just 63411195Ssam * send hyperchannel hardware header and ip header in 63521128Skarels * message proper. 63611195Ssam * 63711195Ssam * This insures that the associated data is at least a 63811195Ssam * TCP/UDP header in length and thus prevents potential 63911195Ssam * problems with very short word counts. 64011195Ssam */ 64121128Skarels if (dlen > MPSIZE) 64221128Skarels hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2); 64321128Skarels hym->hym_type = HYLINK_IP; 64411195Ssam break; 64511195Ssam } 64611195Ssam #endif 64711195Ssam 64811195Ssam default: 64911207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, 65011207Ssam dst->sa_family); 65111195Ssam error = EAFNOSUPPORT; 65211195Ssam goto drop; 65311195Ssam } 65411195Ssam 65521128Skarels 65621128Skarels headerexists: 65721128Skarels 65811195Ssam /* 65921128Skarels * insure message proper is below the maximum 66011195Ssam */ 66121128Skarels if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0)) 66221128Skarels hym->hym_mplen = MPSIZE; 66311195Ssam 66421775Skarels hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host); 66521128Skarels if (hym->hym_mplen) 66621128Skarels hym->hym_ctl |= H_ASSOC; 66721128Skarels else 66821128Skarels hym->hym_ctl &= ~H_ASSOC; 66921128Skarels if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 67021128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 67121128Skarels hym->hym_access, hym->hym_to, hym->hym_from, 67221128Skarels hym->hym_param, hym->hym_type); 67311195Ssam #ifdef DEBUG 67421128Skarels printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 67521128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 67621128Skarels hym->hym_access, hym->hym_to, hym->hym_from, 67721128Skarels hym->hym_param, hym->hym_type); 67811195Ssam #endif 67911195Ssam s = splimp(); 68011195Ssam if (IF_QFULL(&ifp->if_snd)) { 68111195Ssam IF_DROP(&ifp->if_snd); 68211195Ssam error = ENOBUFS; 68311195Ssam splx(s); 68411195Ssam goto drop; 68511195Ssam } 68611195Ssam IF_ENQUEUE(&ifp->if_snd, m); 68711195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING) 68811195Ssam hyact(hyinfo[ifp->if_unit]); 68911195Ssam splx(s); 69011207Ssam return (0); 69111195Ssam notfound: 69221128Skarels error = EHOSTUNREACH; 69311195Ssam drop: 69411195Ssam m_freem(m); 69511207Ssam return (error); 69611207Ssam } 69711195Ssam 69821128Skarels int 69921128Skarels hyroute(ifp, dest, hym) 70021128Skarels register struct ifnet *ifp; 70121128Skarels u_long dest; 70221128Skarels register struct hym_hdr *hym; 70321128Skarels { 70421128Skarels #ifdef HYROUTE 70521128Skarels register struct hy_route *rt = &hy_route[ifp->if_unit]; 70621128Skarels register struct hyr_hash *rhash; 70721128Skarels register int i; 70821128Skarels #endif 70921128Skarels 71021128Skarels hym->hym_param = 0; 71121128Skarels #ifdef HYROUTE 71221128Skarels if (rt->hyr_lasttime != 0) { 71321128Skarels i = HYRHASH(dest); 71421128Skarels rhash = &rt->hyr_hash[i]; 71521128Skarels i = 0; 71621128Skarels while (rhash->hyr_key != dest) { 71721128Skarels if (rhash->hyr_flags == 0 || i > HYRSIZE) 71821128Skarels return(-1); 71921128Skarels rhash++; i++; 72021128Skarels if (rhash >= &rt->hyr_hash[HYRSIZE]) 72121128Skarels rhash = &rt->hyr_hash[0]; 72221128Skarels } 72321128Skarels if (rhash->hyr_flags & HYR_GATE) { 72421128Skarels i = rhash->hyr_nextgate; 72521128Skarels if (i >= rhash->hyr_egate) 72621128Skarels rhash->hyr_nextgate = rhash->hyr_pgate; 72721128Skarels else 72821128Skarels rhash->hyr_nextgate++; 72921128Skarels rhash = &rt->hyr_hash[rt->hyr_gateway[i]]; 73021128Skarels if ((rhash->hyr_flags & HYR_DIR) == 0) 73121128Skarels return(-1); 73221128Skarels } else if (rhash->hyr_flags & HYR_LOOP) { 73321128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */ 73421128Skarels } else if (rhash->hyr_flags & HYR_RLOOP) { 73521128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 73621128Skarels } 73721128Skarels hym->hym_ctl = rhash->hyr_ctl; 73821128Skarels hym->hym_access = rhash->hyr_access; 73921128Skarels hym->hym_to = rhash->hyr_dst; 74021128Skarels } else { 74121128Skarels #endif 74221128Skarels hym->hym_ctl = H_XTRUNKS | H_RTRUNKS; 74321128Skarels hym->hym_access = 0; 74421128Skarels hym->hym_to = htons((u_short)dest); 74521128Skarels if (dest & 0x010000) 74621128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */ 74721128Skarels else if (dest & 0x020000) 74821128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 74921128Skarels #ifdef HYROUTE 75021128Skarels } 75121128Skarels #endif 75221128Skarels 75321128Skarels if (hym->hym_param == 0) 75421128Skarels return(0); 75521128Skarels else 75621128Skarels return(1); 75721128Skarels } 75821128Skarels 75911195Ssam hyact(ui) 76011195Ssam register struct uba_device *ui; 76111195Ssam { 76211195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 76311195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 76411195Ssam 76511195Ssam actloop: 76611195Ssam #ifdef DEBUG 76711207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 76811207Ssam hy_state_names[is->hy_state]); 76911195Ssam #endif 77011195Ssam switch (is->hy_state) { 77111195Ssam 77211195Ssam case STARTUP: 77311195Ssam goto endintr; 77411195Ssam 77511195Ssam case IDLE: { 77611195Ssam register rq = is->hy_flags; 77711195Ssam 77811195Ssam if (rq & RQ_STATUS) { 77911195Ssam is->hy_flags &= ~RQ_STATUS; 78011195Ssam is->hy_state = STATSENT; 78111207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status), 78213088Ssam is->hy_ifuba.ifu_r.ifrw_info); 78311195Ssam } else if (rq & RQ_ENDOP) { 78411195Ssam is->hy_flags &= ~RQ_ENDOP; 78511195Ssam is->hy_state = ENDOPSENT; 78611195Ssam hystart(ui, HYF_END_OP, 0, 0); 78711195Ssam } else if (rq & RQ_STATISTICS) { 78811195Ssam is->hy_flags &= ~RQ_STATISTICS; 78911195Ssam is->hy_state = RSTATSENT; 79011207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 79113088Ssam is->hy_ifuba.ifu_r.ifrw_info); 79211207Ssam } else if (HYS_RECVDATA(addr)) { 79311195Ssam is->hy_state = RECVSENT; 79411195Ssam is->hy_retry = 0; 79521128Skarels hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN); 79611195Ssam } else if (rq & RQ_REISSUE) { 79711195Ssam is->hy_flags &= ~RQ_REISSUE; 79811195Ssam is->hy_state = is->hy_savedstate; 79911195Ssam #ifdef DEBUG 80011207Ssam printD("hy%d: reissue cmd=0x%x count=%d", 80111207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 80211207Ssam printD(" ubaddr=0x%x retry=%d\n", 80311207Ssam is->hy_savedaddr, is->hy_retry); 80411195Ssam #endif 80511207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, 80613088Ssam is->hy_savedaddr); 80711195Ssam } else { 80811195Ssam register struct mbuf *m; 80911195Ssam 81011195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 81111207Ssam if (m != NULL) { 81211195Ssam register struct hym_hdr *hym; 81311195Ssam register int mplen; 81411195Ssam register int cmd; 81511195Ssam 81611195Ssam is->hy_state = XMITSENT; 81711195Ssam is->hy_retry = 0; 81811195Ssam hym = mtod(m, struct hym_hdr *); 81911195Ssam #ifdef HYLOG 82011207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), 82113088Ssam (char *)hym); 82211195Ssam #endif 82311195Ssam mplen = hym->hym_mplen; 82421128Skarels if (hym->hym_to_adapter == hym->hym_from_adapter) 82511207Ssam cmd = HYF_XMITLOCMSG; 82611207Ssam else 82711207Ssam cmd = HYF_XMITMSG; 82811195Ssam #ifdef DEBUG 82911195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 83011207Ssam if (hy_debug_flag) 83111207Ssam hyprintdata((char *)hym, 83213088Ssam sizeof (struct hym_hdr)); 83311195Ssam #endif 83421128Skarels is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN; 83511195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 83611207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 83711207Ssam is->hy_ifuba.ifu_w.ifrw_bdp); 83811195Ssam #ifdef DEBUG 83911207Ssam printD( 84011207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 84111195Ssam ui->ui_unit, mplen, is->hy_olen); 84211207Ssam if (hy_debug_flag) 84311207Ssam hyprintdata( 84413088Ssam is->hy_ifuba.ifu_w.ifrw_addr, 84521128Skarels is->hy_olen + HYM_SWLEN); 84611195Ssam #endif 84721128Skarels if (mplen == 0) { 84821128Skarels is->hy_flags &= ~RQ_XASSOC; 84921128Skarels mplen = is->hy_olen; 85021128Skarels } else { 85111195Ssam is->hy_flags |= RQ_XASSOC; 85221128Skarels } 85321128Skarels hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN); 85411195Ssam } else if (rq & RQ_MARKDOWN) { 85511195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 85611195Ssam is->hy_state = MARKPORT; 85711195Ssam is->hy_retry = 0; 85811195Ssam /* 85911207Ssam * Port number is taken from status data 86011195Ssam */ 86111207Ssam hystart(ui, 86212772Ssam (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 86312772Ssam 0, 0); 86411195Ssam } else if (rq & RQ_MARKUP) { 86511195Ssam register struct ifnet *ifp = &is->hy_if; 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 88221775Skarels is->hy_host = 88311207Ssam (is->hy_stat.hyc_uaddr << 8) | 88411207Ssam PORTNUM(&is->hy_status); 88511195Ssam ifp->if_flags |= IFF_UP; 88611195Ssam #ifdef HYLOG 88711195Ssam hylog(HYL_UP, 0, (char *)0); 88811195Ssam #endif 88911195Ssam } else { 89011195Ssam is->hy_state = WAITING; 89111195Ssam is->hy_retry = 0; 89211195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0); 89311195Ssam } 89411195Ssam } 89511207Ssam break; 89611195Ssam } 89711195Ssam 89811195Ssam case STATSENT: 89912772Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status, 90011207Ssam sizeof (struct hy_status)); 90111195Ssam #ifdef DEBUG 90211207Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 90311207Ssam ui->ui_unit, is->hy_status.hys_gen_status, 90411207Ssam is->hy_status.hys_last_fcn, 90511207Ssam is->hy_status.hys_resp_trunk, 90611207Ssam is->hy_status.hys_status_trunk, 90711207Ssam is->hy_status.hys_recd_resp, 90811207Ssam is->hy_status.hys_error, 90911207Ssam is->hy_status.hys_caddr, 91011207Ssam is->hy_status.hys_pad); 91111195Ssam #endif 91211195Ssam is->hy_state = IDLE; 91311195Ssam #ifdef HYLOG 91411207Ssam hylog(HYL_STATUS, sizeof (struct hy_status), 91511207Ssam (char *)&is->hy_status); 91611195Ssam #endif 91711195Ssam #ifdef HYELOG 91811195Ssam { 91911195Ssam register int i; 92011195Ssam 92111195Ssam i = is->hy_status.hys_error; 92221128Skarels if (i > HYE_MAX) 92311195Ssam i = HYE_MAX; 92411195Ssam switch (is->hy_status.hys_last_fcn) { 92511195Ssam case HYF_XMITLOCMSG: 92611195Ssam i += HYE_MAX+1; /* fall through */ 92711195Ssam case HYF_XMITLSTDATA: 92811195Ssam i += HYE_MAX+1; /* fall through */ 92911195Ssam case HYF_XMITMSG: 93011195Ssam i += HYE_MAX+1; 93111195Ssam } 93211195Ssam hy_elog[i]++; 93311195Ssam } 93411195Ssam #endif 93511195Ssam break; 93611195Ssam 93711195Ssam case RSTATSENT: { 93811207Ssam register struct hy_stat *p = 93911207Ssam (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 94011195Ssam 94121128Skarels bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat)); 94211195Ssam #ifdef DEBUG 94321128Skarels 94421128Skarels printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n", 94511195Ssam ui->ui_unit, 94621128Skarels (is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2], 94721128Skarels (is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2], 94821128Skarels (is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2], 94921128Skarels (is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]); 95021128Skarels printD(" ret0 %d ret1 %d ret2 %d ret3 %d\n", 95121128Skarels (is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2], 95221128Skarels (is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2], 95321128Skarels (is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2], 95421128Skarels (is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]); 95521128Skarels printD(" cancel %d abort %d atype %x %x %x uaddr %x\n", 95621128Skarels (is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1], 95721128Skarels (is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1], 95811195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 95911195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 96011195Ssam #endif 96111195Ssam is->hy_state = IDLE; 96211195Ssam #ifdef HYLOG 96311207Ssam hylog(HYL_STATISTICS, sizeof (struct hy_stat), 96411207Ssam (char *)&is->hy_stat); 96511195Ssam #endif 96611195Ssam break; 96711195Ssam } 96811195Ssam 96911195Ssam case CLEARSENT: 97011195Ssam is->hy_state = IDLE; 97111195Ssam break; 97211195Ssam 97311195Ssam case ENDOPSENT: 97411195Ssam is->hy_state = IDLE; 97511195Ssam break; 97611195Ssam 97711195Ssam case RECVSENT: { 97821128Skarels register struct hym_hdr *hym; 97911207Ssam register unsigned len; 98011195Ssam 98111207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 98211207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 98313088Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 98421128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 98511207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 98611207Ssam if (len > MPSIZE) { 98711207Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n", 98813088Ssam ui->ui_unit, len); 98921128Skarels is->hy_state = IDLE; 99011195Ssam #ifdef DEBUG 99111207Ssam hy_debug_flag = 1; 99211207Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 99311207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 99411207Ssam addr->hyd_bar, addr->hyd_wcr); 99511195Ssam #endif 99611207Ssam } 99721128Skarels hym->hym_mplen = len; 99811195Ssam #ifdef DEBUG 99911207Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 100011207Ssam if (hy_debug_flag) 100121128Skarels hyprintdata((char *)hym, len + HYM_SWLEN); 100211195Ssam #endif 100321128Skarels if (hym->hym_ctl & H_ASSOC) { 100411207Ssam is->hy_state = RECVDATASENT; 100511207Ssam is->hy_retry = 0; 100611207Ssam hystart(ui, HYF_INPUTDATA, 100721128Skarels (int)(HYMTU + sizeof (struct hy_hdr) - len), 100821128Skarels (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len)); 100911207Ssam } else { 101021128Skarels hyrecvdata(ui, hym, (int)len + HYM_SWLEN); 101111207Ssam is->hy_state = IDLE; 101211195Ssam } 101311207Ssam break; 101411207Ssam } 101511195Ssam 101611195Ssam case RECVDATASENT: { 101721128Skarels register struct hym_hdr *hym; 101811207Ssam register unsigned len; 101911195Ssam 102011207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 102111207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 102213088Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 102321128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 102411207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 102511195Ssam #ifdef DEBUG 102611207Ssam printD("hy%d: recvd assoc data, len = %d, data = ", 102711207Ssam ui->ui_unit, len); 102811207Ssam if (hy_debug_flag) 102921128Skarels hyprintdata((char *)hym + hym->hym_mplen, len); 103011195Ssam #endif 103121128Skarels hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN)); 103211207Ssam is->hy_state = IDLE; 103311207Ssam break; 103411207Ssam } 103511195Ssam 103611195Ssam case XMITSENT: 103711207Ssam if (is->hy_flags & RQ_XASSOC) { 103813196Sroot register int len; 103911195Ssam 104011207Ssam is->hy_flags &= ~RQ_XASSOC; 104111207Ssam is->hy_state = XMITDATASENT; 104211207Ssam is->hy_retry = 0; 104311207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 104411207Ssam if (len > is->hy_olen) { 104511207Ssam printf( 104611207Ssam "hy%d: xmit error - len > hy_olen [%d > %d]\n", 104711207Ssam ui->ui_unit, len, is->hy_olen); 104811195Ssam #ifdef DEBUG 104911207Ssam hy_debug_flag = 1; 105011195Ssam #endif 105111195Ssam } 105211207Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 105321128Skarels is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len); 105411207Ssam break; 105511207Ssam } 105611207Ssam /* fall through to ... */ 105711195Ssam 105811195Ssam case XMITDATASENT: 105911207Ssam hyxmitdata(ui); 106011207Ssam is->hy_state = IDLE; 106111207Ssam break; 106211195Ssam 106311195Ssam case WAITING: /* wait for message complete or output requested */ 106411207Ssam if (HYS_RECVDATA(addr)) 106511195Ssam is->hy_state = IDLE; 106611195Ssam else { 106711195Ssam is->hy_state = CLEARSENT; 106811195Ssam is->hy_retry = 0; 106911195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0); 107011195Ssam } 107111195Ssam break; 107211195Ssam 107311195Ssam case MARKPORT: 107411195Ssam is->hy_state = STARTUP; 107521128Skarels if_down(&is->hy_if); 107611195Ssam is->hy_if.if_flags &= ~IFF_UP; 107711195Ssam goto endintr; 107811195Ssam 107911195Ssam default: 108011207Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 108111207Ssam ui->ui_unit, is->hy_state); 108211195Ssam panic("HYPERCHANNEL IN INVALID STATE"); 108311195Ssam /*NOTREACHED*/ 108411207Ssam } 108511195Ssam if (is->hy_state == IDLE) 108611195Ssam goto actloop; 108711195Ssam endintr: 108813088Ssam ; 108911195Ssam #ifdef DEBUG 109011207Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 109111207Ssam hy_state_names[is->hy_state]); 109211195Ssam #endif 109311207Ssam } 109411195Ssam 109521128Skarels struct sockproto hypproto = { PF_HYLINK }; 109621128Skarels struct sockaddr_in hypdst = { AF_HYLINK }; 109721128Skarels struct sockaddr_in hypsrc = { AF_HYLINK }; 109821128Skarels 109911195Ssam /* 110013088Ssam * Called from device interrupt when receiving data. 110111195Ssam * Examine packet to determine type. Decapsulate packet 110211195Ssam * based on type and pass to type specific higher-level 110311195Ssam * input routine. 110411195Ssam */ 110521128Skarels hyrecvdata(ui, hym, len) 110611195Ssam struct uba_device *ui; 110721128Skarels register struct hym_hdr *hym; 110811195Ssam int len; 110911195Ssam { 111011195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 111111195Ssam struct mbuf *m; 111211195Ssam register struct ifqueue *inq; 111311195Ssam 111411195Ssam is->hy_if.if_ipackets++; 111511195Ssam #ifdef DEBUG 111621128Skarels printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len); 111711195Ssam #endif 111811195Ssam #ifdef HYLOG 111911195Ssam { 112011195Ssam struct { 112111195Ssam short hlen; 112221128Skarels struct hym_hdr hhdr; 112311195Ssam } hh; 112411195Ssam hh.hlen = len; 112521128Skarels hh.hhdr = *hym; 112611195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh); 112711195Ssam } 112811195Ssam #endif 112911195Ssam if (len > HYMTU + MPSIZE || len == 0) 113011195Ssam return; /* sanity */ 113111195Ssam /* 113211195Ssam * Pull packet off interface. 113311195Ssam */ 113424797Skarels m = if_rubaget(&is->hy_ifuba, len, 0, &is->hy_if); 113511207Ssam if (m == NULL) 113611195Ssam return; 113711195Ssam 113821128Skarels /* 113921128Skarels * if normal or adapter loopback response packet believe hym_type, 114021128Skarels * otherwise, use the raw input queue cause it's a response from an 114121128Skarels * adapter command. 114221128Skarels */ 114321128Skarels if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff) 114421128Skarels goto rawlinkin; 114521128Skarels 114621128Skarels switch (hym->hym_type) { 114721128Skarels 114811195Ssam #ifdef INET 114911195Ssam case HYLINK_IP: 115011195Ssam schednetisr(NETISR_IP); 115111195Ssam inq = &ipintrq; 115211195Ssam break; 115311195Ssam #endif 115411195Ssam default: 115521128Skarels rawlinkin: 115621128Skarels { 115721128Skarels struct mbuf *m0; 115821128Skarels 115921128Skarels MGET(m0, M_DONTWAIT, MT_DATA); 116024797Skarels if (m0 == 0) { 116121128Skarels m_freem(m); 116221128Skarels return; 116321128Skarels } 116421128Skarels m0->m_off = MMINOFF; 116521128Skarels m0->m_len = sizeof(struct hym_hdr); 116621128Skarels m0->m_next = m; 116721128Skarels bcopy((caddr_t)hym, mtod(m0, caddr_t), sizeof(struct hym_hdr)); 116821128Skarels m = m0; 116921128Skarels hypproto.sp_protocol = 0; 117021775Skarels hypdst.sin_addr = is->hy_addr; 117121775Skarels hypsrc.sin_addr = is->hy_addr; 117221128Skarels raw_input(m, &hypproto, (struct sockaddr *)&hypsrc, 117321128Skarels (struct sockaddr *)&hypdst); 117421128Skarels return; 117521128Skarels } 117611195Ssam } 117711195Ssam if (IF_QFULL(inq)) { 117811195Ssam IF_DROP(inq); 117911195Ssam m_freem(m); 118011195Ssam } else 118111195Ssam IF_ENQUEUE(inq, m); 118211207Ssam } 118311195Ssam 118411195Ssam /* 118511207Ssam * Transmit done, release resources, bump counters. 118611195Ssam */ 118711195Ssam hyxmitdata(ui) 118811195Ssam struct uba_device *ui; 118911195Ssam { 119011195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 119111195Ssam 119211195Ssam is->hy_if.if_opackets++; 119311207Ssam if (is->hy_ifuba.ifu_xtofree) { 119411195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 119511195Ssam is->hy_ifuba.ifu_xtofree = 0; 119611195Ssam } 119711207Ssam } 119811195Ssam 119911195Ssam hycancel(ui) 120011195Ssam register struct uba_device *ui; 120111195Ssam { 120211195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 120311195Ssam 120411207Ssam if (is->hy_ifuba.ifu_xtofree) { 120511195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 120611195Ssam is->hy_ifuba.ifu_xtofree = 0; 120711195Ssam } 120821128Skarels #ifdef HYLOG 120921128Skarels hylog(HYL_CANCEL, 0, (char *)0); 121021128Skarels #endif 121111195Ssam #ifdef DEBUG 121211207Ssam if (hy_nodebug & 1) 121311207Ssam hy_debug_flag = 1; 121411195Ssam #endif 121511195Ssam #ifdef DEBUG 121611195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 121711195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 121811195Ssam is->hy_savedcount, is->hy_savedaddr); 121921128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 122021128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 122111207Ssam printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 122211207Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 122311207Ssam is->hy_savedcmd); 122411195Ssam #endif 122511195Ssam is->hy_state = IDLE; 122611195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 122711195Ssam hyact(ui); 122811207Ssam } 122911195Ssam 123011195Ssam #ifdef DEBUG 123111195Ssam hyprintdata(cp, len) 123211195Ssam register char *cp; 123311195Ssam register int len; 123411195Ssam { 123511195Ssam register int count = 16; 123611195Ssam register char *fmt; 123711195Ssam static char regfmt[] = "\n\t %x"; 123811195Ssam 123911195Ssam fmt = ®fmt[2]; 124011195Ssam while (--len >= 0) { 124111195Ssam printL(fmt, *cp++ & 0xff); 124211195Ssam fmt = ®fmt[2]; 124311195Ssam if (--count <= 0) { 124411195Ssam fmt = ®fmt[0]; 124511195Ssam count = 16; 124611195Ssam } 124711195Ssam } 124811195Ssam printL("\n"); 124911195Ssam } 125011195Ssam #endif 125111195Ssam 125211195Ssam hywatch(unit) 125313088Ssam int unit; 125411195Ssam { 125511195Ssam register struct hy_softc *is = &hy_softc[unit]; 125611195Ssam register struct uba_device *ui = hyinfo[unit]; 125711195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 125811195Ssam int s; 125911195Ssam 126011195Ssam s = splimp(); 126111195Ssam #ifdef PI13 126211195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 126311195Ssam addr->hyd_csr |= S_POWEROFF; 126411195Ssam DELAY(100); 126511195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) { 126621128Skarels printf("hy%d: Adapter Power Restored (hywatch)\n", unit); 126711195Ssam is->hy_state = IDLE; 126811207Ssam is->hy_flags |= 126911207Ssam (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 127011195Ssam hyact(ui); 127111195Ssam } 127211195Ssam } 127311195Ssam #endif 127421128Skarels if (++is->hy_ntime >= 2 && is->hy_state != WAITING && 127521128Skarels is->hy_state != STARTUP && is->hy_state != IDLE) { 127621128Skarels #ifdef HYLOG 127721128Skarels printf("hy%d: watchdog timer expired in state \"%s\"\n", unit, 127821128Skarels hy_state_names[is->hy_state]); 127921128Skarels #else 128021128Skarels printf("hy%d: watchdog timer expired in state %d\n", unit, 128121128Skarels is->hy_state); 128221128Skarels #endif 128321128Skarels printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit, 128421128Skarels is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS); 128521128Skarels hycancel(ui); 128621128Skarels } 128711195Ssam splx(s); 128821128Skarels is->hy_if.if_timer = SCANINTERVAL; 128911195Ssam } 129011195Ssam 129111195Ssam #ifdef HYLOG 129211195Ssam hylog(code, len, ptr) 129313088Ssam int code, len; 129411195Ssam char *ptr; 129511195Ssam { 129611195Ssam register unsigned char *p; 129711195Ssam int s; 129811195Ssam 129911195Ssam s = splimp(); 130011195Ssam if (hy_log.hyl_self != &hy_log) { 130111195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 130211195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 130311195Ssam hy_log.hyl_self = &hy_log; 130421128Skarels hy_log.hyl_enable = HYL_CONTINUOUS; 130521128Skarels hy_log.hyl_onerr = HYL_CONTINUOUS; 130621128Skarels hy_log.hyl_count = 0; 130721128Skarels hy_log.hyl_icount = 16; 130821128Skarels hy_log.hyl_filter = 0xffff; /* enable all */ 130911195Ssam } 131021128Skarels if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0) 131111207Ssam goto out; 131211195Ssam p = hy_log.hyl_ptr; 131321128Skarels if (p + len + 3 >= hy_log.hyl_eptr) { 131412772Ssam bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 131511195Ssam p = &hy_log.hyl_buf[0]; 131621128Skarels if (hy_log.hyl_enable != HYL_CONTINUOUS) { 131721128Skarels hy_log.hyl_enable = HYL_DISABLED; 131811195Ssam goto out; 131911195Ssam } 132011195Ssam } 132111195Ssam *p++ = code; 132211195Ssam *p++ = len; 132313088Ssam bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len); 132421128Skarels if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) { 132521128Skarels *p++ = '\0'; 132621128Skarels hy_log.hyl_enable = HYL_DISABLED; 132721128Skarels hy_log.hyl_count = hy_log.hyl_icount; 132821128Skarels } 1329*26285Skarels p += len; 133021128Skarels if (hy_log.hyl_wait != 0) { /* wakeup HYGETLOG if wanted */ 1331*26285Skarels if (hy_log.hyl_wait <= p - hy_log.hyl_ptr) { 133221128Skarels wakeup((caddr_t)&hy_log); 133321128Skarels hy_log.hyl_wait = 0; 1334*26285Skarels } else 1335*26285Skarels hy_log.hyl_wait -= p - hy_log.hyl_ptr; 133621128Skarels } 1337*26285Skarels hy_log.hyl_ptr = p; 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 { 134921775Skarels struct ifaddr *ifa = (struct ifaddr *) data; 135021128Skarels struct hyrsetget *sg = (struct hyrsetget *)data; 135121128Skarels #if defined(HYLOG) || defined(HYELOG) 135221128Skarels struct hylsetget *sgl = (struct hylsetget *)data; 135321128Skarels #endif 135421128Skarels struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit]; 135511207Ssam int s = splimp(), error = 0; 135621128Skarels #ifdef HYLOG 135721128Skarels struct hy_softc *is = &hy_softc[ifp->if_unit]; 135821128Skarels struct { 135921128Skarels u_char hstate; 136021128Skarels u_char hflags; 136121128Skarels u_short iflags; 136221128Skarels int hcmd; 136321128Skarels int herror; 136421128Skarels u_long haddr; 136521128Skarels u_long hmisc; 136621128Skarels } hil; 136711195Ssam 136821128Skarels hil.hmisc = -1; 136921128Skarels hil.hstate = is->hy_state; 137021128Skarels hil.hflags = is->hy_flags; 137121128Skarels hil.hcmd = cmd; 137221128Skarels #endif 137321128Skarels 137411195Ssam switch(cmd) { 137511195Ssam 137613065Ssam case SIOCSIFADDR: 137724797Skarels if (ifa->ifa_addr.sa_family != AF_INET) 137821128Skarels return(EINVAL); 137921775Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 138021775Skarels hyinit(ifp->if_unit); 138121775Skarels hy_softc[ifp->if_unit].hy_addr = IA_SIN(ifa)->sin_addr; 138221128Skarels #ifdef HYLOG 138321775Skarels hil.haddr = is->hy_addr.s_addr; 138421128Skarels #endif 138513065Ssam break; 138613065Ssam 138711195Ssam case HYSETROUTE: 138811207Ssam if (!suser()) { 138911207Ssam error = EPERM; 139021128Skarels goto out; 139111195Ssam } 139221128Skarels 139321128Skarels if (sg->hyrsg_len != sizeof(struct hy_route)) { 139421128Skarels error = EINVAL; 139521128Skarels goto out; 139621128Skarels } 139721128Skarels if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) { 139821128Skarels r->hyr_lasttime = 0; /* disable further routing if trouble */ 139921128Skarels error = EFAULT; 140021128Skarels goto out; 140121128Skarels } 140221128Skarels r->hyr_lasttime = time.tv_sec; 140321128Skarels #ifdef HYLOG 140421128Skarels hil.hmisc = r->hyr_lasttime; 140521128Skarels #endif 140611195Ssam break; 140711195Ssam 140811195Ssam case HYGETROUTE: 140921128Skarels if (sg->hyrsg_len < sizeof(struct hy_route)) { 141021128Skarels error = EINVAL; 141121128Skarels goto out; 141221128Skarels } 141321128Skarels if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) { 141421128Skarels error = EFAULT; 141521128Skarels goto out; 141621128Skarels } 141711195Ssam break; 141811195Ssam 141921128Skarels #ifdef HYELOG 142021128Skarels case HYGETELOG: 142121128Skarels if (sgl->hylsg_len < sizeof(hy_elog)) { 142221128Skarels error = EINVAL; 142321128Skarels goto out; 142421128Skarels } 142521128Skarels if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) { 142621128Skarels error = EFAULT; 142721128Skarels goto out; 142821128Skarels } 142921128Skarels if (sgl->hylsg_cmd) { 143021128Skarels if (!suser()) { 143121128Skarels error = EPERM; 143221128Skarels goto out; 143321128Skarels } 143421128Skarels bzero((caddr_t)hy_elog, sizeof(hy_elog)); 143521128Skarels } 143621128Skarels break; 143721128Skarels #endif 143821128Skarels 143921128Skarels #ifdef HYLOG 144021128Skarels case HYSETLOG: 144121128Skarels if (!suser()) { 144221128Skarels error = EPERM; 144321128Skarels goto out; 144421128Skarels } 144521128Skarels hy_log.hyl_enable = HYL_DISABLED; 144621128Skarels hylog(HYL_NOP, 0, (char *)0); /* force log init */ 144721128Skarels hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f; 144821128Skarels hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f; 144921128Skarels hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff; 145021128Skarels hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len; 145121128Skarels wakeup((caddr_t)&hy_log); /* wakeup sleeping HYGETLOG */ 145221128Skarels break; 145321128Skarels 145421128Skarels case HYGETLOG: 145521128Skarels if (sgl->hylsg_len < sizeof(hy_log)) { 145621128Skarels error = EINVAL; 145721128Skarels goto out; 145821128Skarels } 145921128Skarels if (sgl->hylsg_cmd != 0) { 146021128Skarels if (hy_log.hyl_wait) { 146121128Skarels error = EBUSY; 146221128Skarels goto out; 146321128Skarels } 146421128Skarels hy_log.hyl_wait = sgl->hylsg_cmd; 146521128Skarels sleep((caddr_t)&hy_log); 146621128Skarels } 146721128Skarels 146821128Skarels if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) { 146921128Skarels error = EFAULT; 147021128Skarels goto out; 147121128Skarels } 147221128Skarels break; 147321128Skarels #endif 147421128Skarels 147511195Ssam default: 147613058Ssam error = EINVAL; 147711195Ssam break; 147811195Ssam } 147921128Skarels out: 148021128Skarels #ifdef HYLOG 148121128Skarels hil.herror = error; 148221128Skarels hil.iflags = ifp->if_flags; 148321775Skarels hil.haddr = is->hy_addr.s_addr; 148421128Skarels hylog(HYL_IOCTL, sizeof(hil), (char *)&hil); 148521128Skarels #endif 148611195Ssam splx(s); 148711207Ssam return (error); 148811195Ssam } 148911207Ssam #endif 1490