123294Smckusick /* 235322Sbostic * Copyright (c) 1988 Regents of the University of California. 335322Sbostic * All rights reserved. 435322Sbostic * 535322Sbostic * This code is derived from software contributed to Berkeley by 635322Sbostic * Tektronix Inc. 735322Sbostic * 835322Sbostic * Redistribution and use in source and binary forms are permitted 935322Sbostic * provided that the above copyright notice and this paragraph are 1035322Sbostic * duplicated in all such forms and that any documentation, 1135322Sbostic * advertising materials, and other materials related to such 1235322Sbostic * distribution and use acknowledge that the software was developed 1335322Sbostic * by the University of California, Berkeley. The name of the 1435322Sbostic * University may not be used to endorse or promote products derived 1535322Sbostic * from this software without specific prior written permission. 1635322Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1735322Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1835322Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1935322Sbostic * 20*37476Ssklower * @(#)if_hy.c 7.4 (Berkeley) 04/22/89 2123294Smckusick */ 2211195Ssam 2321128Skarels /* 2421128Skarels * 4.2 BSD Unix Kernel - Vax Network Interface Support 2521128Skarels * 2621128Skarels * $Header: if_hy.c,v 10.1 84/07/22 21:02:56 steveg Exp $ 2721128Skarels * $Locker: $ 2821128Skarels * 2921128Skarels * Modifications from Berkeley 4.2 BSD 3021128Skarels * Copyright (c) 1983, Tektronix Inc. 3121128Skarels * All Rights Reserved 3221128Skarels * 3321128Skarels * $Log: if_hy.c,v $ 3421128Skarels * Revision 10.1 84/07/22 21:02:56 steveg 3521128Skarels * define PI13 (moved from if_hyreg.h, somehow got dropped in the process) 3621128Skarels * rework hywatch to check for power fails first 3721128Skarels * 3821128Skarels * Revision 10.0 84/06/30 19:54:27 steveg 3921128Skarels * Big Build 4021128Skarels * 4121128Skarels * Revision 3.17 84/06/20 19:20:28 steveg 4221128Skarels * increment hy_ntime in hywatch 4321128Skarels * print out state name, csr, last command, and hy_flags when watchdog timer 4421128Skarels * expires 4521128Skarels * 4621128Skarels * Revision 3.16 84/06/20 19:09:34 steveg 4721128Skarels * turn on continuous logging by default 4821128Skarels * 4921128Skarels * Revision 3.15 84/05/30 22:19:09 steveg 5021128Skarels * changes to reflect new layout ot statistics data 5121128Skarels * 5221128Skarels * Revision 3.14 84/05/30 19:25:15 steveg 5321128Skarels * move driver states to if_hy.h so log printing programs can use them 5421128Skarels * 5521128Skarels * Revision 3.13 84/05/30 17:13:26 steveg 5621128Skarels * make it compile 5721128Skarels * 5821128Skarels * Revision 3.12 84/05/30 13:46:16 steveg 5921128Skarels * rework logging 6021128Skarels * 6121128Skarels * Revision 3.11 84/05/18 19:35:02 steveg 6221128Skarels * clear IFF_RUNNING and IFF_UP on unibus reset to force resource allocation 6321128Skarels * by the init routine 6421128Skarels * 6521128Skarels * Revision 3.10 84/05/04 12:14:44 steveg 6621128Skarels * more rework to make it actually work under 4.2 6721128Skarels * 6821128Skarels * Revision 3.9 84/05/01 23:34:52 steveg 6921128Skarels * fix typo so it compiles (unit -> ui->ui_unit) 7021128Skarels * 7121128Skarels * Revision 3.8 84/05/01 23:18:30 steveg 7221128Skarels * changes after talking with rickk 7321128Skarels * - check power off more closely 7421128Skarels * - support remote loopback through A710 adapters 7521128Skarels * - IMPLINK -> HYLINK 7621128Skarels * - return EHOSTUNREACH on hyroute failure 7721128Skarels * - bump if_collisions on abnormal interrupts that aren't input or output 7821128Skarels * 7921128Skarels * 8021128Skarels */ 8121128Skarels 8221128Skarels 8311195Ssam #include "hy.h" 8411195Ssam #if NHY > 0 8511195Ssam 8611195Ssam /* 8711195Ssam * Network Systems Copropration Hyperchanel interface 8811195Ssam */ 8921128Skarels #include "machine/pte.h" 9011195Ssam 9121775Skarels #include "param.h" 9221775Skarels #include "systm.h" 9321775Skarels #include "mbuf.h" 9421775Skarels #include "buf.h" 9521775Skarels #include "protosw.h" 9621775Skarels #include "socket.h" 9721775Skarels #include "vmmac.h" 9821775Skarels #include "errno.h" 9921775Skarels #include "time.h" 10021775Skarels #include "kernel.h" 10121775Skarels #include "ioctl.h" 10213088Ssam 10311195Ssam #include "../net/if.h" 10411207Ssam #include "../net/netisr.h" 10511195Ssam #include "../net/route.h" 10624797Skarels 10724797Skarels #ifdef INET 10811195Ssam #include "../netinet/in.h" 10911195Ssam #include "../netinet/in_systm.h" 11024797Skarels #include "../netinet/in_var.h" 11111195Ssam #include "../netinet/ip.h" 11224797Skarels #endif 11311195Ssam 11411207Ssam #include "../vax/cpu.h" 11511207Ssam #include "../vax/mtpr.h" 11611207Ssam #include "../vaxuba/ubareg.h" 11711207Ssam #include "../vaxuba/ubavar.h" 11811195Ssam 11921128Skarels /* 12021128Skarels * configuration specific paramters 12121128Skarels * - change as appropriate for particular installaions 12221128Skarels */ 12321128Skarels #define HYROUTE 12421128Skarels #define HYELOG 12521128Skarels #define HYLOG 12621128Skarels #define HYMTU 1100 12721128Skarels #define PI13 12811195Ssam 12921128Skarels #ifdef DEBUG 13021128Skarels #define HYLOG 13121128Skarels #endif 13221128Skarels 13321775Skarels #include "if_hy.h" 13421775Skarels #include "if_hyreg.h" 13521775Skarels #include "if_uba.h" 13621128Skarels 13713058Ssam int hyprobe(), hyattach(), hyinit(), hyioctl(); 13813058Ssam int hyoutput(), hyreset(), hywatch(); 13911195Ssam struct uba_device *hyinfo[NHY]; 14011195Ssam u_short hystd[] = { 0772410, 0 }; 14111195Ssam struct uba_driver hydriver = 14211195Ssam { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo }; 14311195Ssam 14411195Ssam /* 14511195Ssam * Hyperchannel software status per interface. 14611195Ssam * 14711195Ssam * Each interface is referenced by a network interface structure, 14811195Ssam * hy_if, which the routing code uses to locate the interface. 14911195Ssam * This structure contains the output queue for the interface, its address, ... 15011195Ssam * We also have, for each interface, a UBA interface structure, which 15111195Ssam * contains information about the UNIBUS resources held by the interface: 15211195Ssam * map registers, buffered data paths, etc. Information is cached in this 15311195Ssam * structure for use by the if_uba.c routines in running the interface 15411195Ssam * efficiently. 15511195Ssam */ 15611195Ssam struct hy_softc { 15711195Ssam struct ifnet hy_if; /* network-visible interface */ 15811195Ssam struct ifuba hy_ifuba; /* UNIBUS resources */ 15911207Ssam short hy_flags; /* flags */ 16011207Ssam short hy_state; /* driver state */ 16121775Skarels u_short hy_host; /* local host number */ 16221775Skarels struct in_addr hy_addr; /* internet address */ 16311195Ssam int hy_olen; /* packet length on output */ 16411195Ssam int hy_lastwcr; /* last command's word count */ 16511195Ssam short hy_savedstate; /* saved for reissue after status */ 16611195Ssam short hy_savedcmd; /* saved command for reissue */ 16711195Ssam int hy_savedcount; /* saved byte count for reissue */ 16811195Ssam int hy_savedaddr; /* saved unibus address for reissue */ 16911195Ssam int hy_ntime; /* number of timeouts since last cmd */ 17011195Ssam int hy_retry; /* retry counter */ 17111207Ssam struct hy_stat hy_stat; /* statistics */ 17211207Ssam struct hy_status hy_status; /* status */ 17311195Ssam } hy_softc[NHY]; 17411195Ssam 17511195Ssam #ifdef HYELOG 17621128Skarels u_long hy_elog[HYE_SIZE]; 17711195Ssam #endif 17811195Ssam 17921128Skarels #ifdef HYLOG 18021128Skarels struct hy_log hy_log; 18121128Skarels #endif 18221128Skarels 18321128Skarels #ifdef HYROUTE 18421128Skarels struct hy_route hy_route[NHY]; 18521128Skarels #endif 18621128Skarels 18711195Ssam #ifdef DEBUG 18821128Skarels #define printL printf 18921128Skarels #define printD if (hy_debug_flag) printf 19011195Ssam int hy_debug_flag = 0; 19111195Ssam /* 19211195Ssam * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 19311195Ssam * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 19411195Ssam * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 19511195Ssam */ 19611195Ssam int hy_nodebug = 0x0; 19711195Ssam #endif 19811195Ssam 19911195Ssam #define SCANINTERVAL 10 /* seconds */ 20011195Ssam #define MAXINTERVAL 20 /* seconds (max action) */ 20111195Ssam 20211195Ssam /* 20311195Ssam * Cause a device interrupt. This code uses a buffer starting at 20411195Ssam * location zero on the unibus (which is already mapped by the 20511195Ssam * autoconfigure code in the kernel). 20611195Ssam */ 20711195Ssam hyprobe(reg) 20811195Ssam caddr_t reg; 20911195Ssam { 21011195Ssam register int br, cvec; /* r11, r10 value-result */ 21111195Ssam register struct hydevice *addr = (struct hydevice *) reg; 21211195Ssam 21311195Ssam #ifdef lint 21411195Ssam br = 0; cvec = br; br = cvec; 21511195Ssam hyint(0); 21611195Ssam #endif 21711195Ssam /* 21811195Ssam * request adapter status to a buffer starting at unibus location 0 21911195Ssam */ 22011195Ssam addr->hyd_bar = 0; 22111195Ssam addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 22211195Ssam addr->hyd_dbuf = HYF_STATUS; 22311195Ssam #ifdef PI13 22411195Ssam addr->hyd_csr |= S_GO | S_IE | S_IATTN; 22511195Ssam #else 22611195Ssam addr->hyd_csr |= S_GO | S_IE; 22711195Ssam #endif 22811195Ssam DELAY(10000); 22911195Ssam #ifdef PI13 23011195Ssam addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 23111195Ssam #endif 23211195Ssam addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 23321128Skarels return(sizeof(struct hydevice)); 23411207Ssam } 23511195Ssam 23611195Ssam /* 23711195Ssam * Interface exists: make available by filling in network interface 23811195Ssam * record. System will initialize the interface when it is ready 23911195Ssam * to accept packets. 24011195Ssam */ 24111195Ssam hyattach(ui) 24211195Ssam struct uba_device *ui; 24311195Ssam { 24411195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 24511195Ssam register struct ifnet *ifp = &is->hy_if; 24611195Ssam 24711195Ssam ifp->if_unit = ui->ui_unit; 24811195Ssam ifp->if_name = "hy"; 24911195Ssam ifp->if_mtu = HYMTU; 25011195Ssam is->hy_state = STARTUP; /* don't allow state transitions yet */ 25111195Ssam ifp->if_init = hyinit; 25213058Ssam ifp->if_ioctl = hyioctl; 25311195Ssam ifp->if_output = hyoutput; 25411207Ssam ifp->if_reset = hyreset; 25511195Ssam ifp->if_watchdog = hywatch; 25611195Ssam ifp->if_timer = SCANINTERVAL; 25711195Ssam is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 25811207Ssam #ifdef notdef 25911195Ssam is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 26011195Ssam #endif 26111195Ssam if_attach(ifp); 26211207Ssam } 26311195Ssam 26411195Ssam /* 26511195Ssam * Reset of interface after UNIBUS reset. 26611195Ssam * If interface is on specified uba, reset its state. 26711195Ssam */ 26811195Ssam hyreset(unit, uban) 26911195Ssam int unit, uban; 27011195Ssam { 27121128Skarels register struct uba_device *ui; 27221128Skarels register struct hy_softc *is; 27311195Ssam 27421128Skarels if (unit >= NHY || (ui = hyinfo[unit]) == 0 || ui->ui_alive == 0 || 27511207Ssam ui->ui_ubanum != uban) 27611195Ssam return; 27711195Ssam printf(" hy%d", unit); 27821128Skarels is = &hy_softc[unit]; /* force unibus resource allocation */ 27921128Skarels is->hy_if.if_flags &= ~(IFF_UP|IFF_RUNNING); 28011195Ssam hyinit(unit); 28111207Ssam } 28211195Ssam 28311195Ssam /* 28411195Ssam * Initialization of interface; clear recorded pending 28511195Ssam * operations, and reinitialize UNIBUS usage. 28611195Ssam */ 28711195Ssam hyinit(unit) 28811195Ssam int unit; 28911195Ssam { 29011195Ssam register struct hy_softc *is = &hy_softc[unit]; 29111195Ssam register struct uba_device *ui = hyinfo[unit]; 29221128Skarels register struct mbuf *m; 29311195Ssam int s; 29411195Ssam 29521775Skarels if (is->hy_if.if_addrlist == 0) /* address still unknown */ 29613065Ssam return; 29721128Skarels if (is->hy_if.if_flags & IFF_RUNNING) /* just reset the device */ 29821128Skarels goto justreset; 29911195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 30021128Skarels sizeof (struct hym_hdr), (int)btoc(HYMTU)) == 0) { 30111195Ssam #ifdef DEBUG 30211207Ssam if (hy_nodebug & 4) 30311207Ssam hy_debug_flag = 1; 30411195Ssam #endif 30511195Ssam printf("hy%d: can't initialize\n", unit); 30611195Ssam is->hy_if.if_flags &= ~IFF_UP; 30711195Ssam return; 30811195Ssam } 30913088Ssam is->hy_if.if_flags |= IFF_RUNNING; 31021128Skarels 31121128Skarels justreset: 31211195Ssam /* 31321128Skarels * remove any left over outgoing messages, reset the hardware and 31421128Skarels * start the state machine 31511195Ssam */ 31611195Ssam s = splimp(); 31721128Skarels #ifdef HYLOG 31821128Skarels hylog(HYL_RESET, 0, (char *)0); 31921128Skarels #endif 32011195Ssam is->hy_state = IDLE; 32111195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 32211195Ssam is->hy_retry = 0; 32321128Skarels for(;;) { 32421128Skarels IF_DEQUEUE(&is->hy_if.if_snd, m); 32521128Skarels if (m != NULL) 32621128Skarels m_freem(m); 32721128Skarels else 32821128Skarels break; 32921128Skarels } 33021128Skarels hycancel(ui); /* also bumps the state machine */ 33111195Ssam splx(s); 33211207Ssam } 33311195Ssam 33411195Ssam /* 33511207Ssam * Issue a command to the adapter 33611195Ssam */ 33711195Ssam hystart(ui, cmd, count, ubaddr) 33811195Ssam struct uba_device *ui; 33911207Ssam int cmd, count, ubaddr; 34011195Ssam { 34111195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 34211195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 34311195Ssam 34411195Ssam #ifdef DEBUG 34511207Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 34611207Ssam ui->ui_unit, cmd, count, ubaddr); 34711195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 34811207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 34911207Ssam addr->hyd_wcr); 35011195Ssam #endif 35111207Ssam if (((is->hy_flags & RQ_REISSUE) == 0) && 35211207Ssam (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 35311195Ssam is->hy_savedstate = is->hy_state; 35411195Ssam is->hy_savedcmd = cmd; 35511195Ssam is->hy_savedcount = count; 35611195Ssam is->hy_savedaddr = ubaddr; 35711195Ssam } 35821128Skarels #ifdef PI13 35921128Skarels if (addr->hyd_csr & S_POWEROFF) { 36021128Skarels printf("hy%d: \"Soft\" Adapter Power Failure (hystart)\n", ui->ui_unit); 36121128Skarels addr->hyd_csr |= S_POWEROFF; 36221128Skarels DELAY(100); 36321128Skarels if (addr->hyd_csr & S_POWEROFF) { 36421128Skarels printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hystart)\n", ui->ui_unit); 36521128Skarels if_down(&is->hy_if); 36621128Skarels is->hy_if.if_flags &= ~IFF_UP; 36721128Skarels is->hy_state = STARTUP; 36821128Skarels } else { 36921128Skarels printf("hy%d: Adapter Power Restored (hystart)\n", ui->ui_unit); 37021128Skarels } 37121128Skarels return; 37221128Skarels } 37321128Skarels #endif 37411195Ssam addr->hyd_bar = ubaddr & 0xffff; 37511207Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 37611195Ssam addr->hyd_dbuf = cmd; 37711195Ssam #ifdef PI13 37811195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 37911195Ssam #else 38011195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 38111195Ssam #endif 38211195Ssam #ifdef DEBUG 38311195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 38411207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 38511207Ssam addr->hyd_wcr); 38611195Ssam #endif 38711195Ssam #ifdef HYLOG 38811195Ssam { 38911195Ssam struct { 39011207Ssam u_char hcmd; 39111207Ssam u_char hstate; 39211207Ssam short hcount; 39311195Ssam } hcl; 39411195Ssam 39511195Ssam hcl.hcmd = cmd; 39611195Ssam hcl.hstate = is->hy_state; 39711195Ssam hcl.hcount = count; 39811195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 39911195Ssam } 40011195Ssam #endif 40111195Ssam is->hy_ntime = 0; 40211207Ssam } 40311195Ssam 40411195Ssam int hyint_active = 0; /* set during hy interrupt */ 40511195Ssam /* 40611207Ssam * Hyperchannel interface interrupt. 40711195Ssam * 40811195Ssam * An interrupt can occur for many reasons. Examine the status of 40911195Ssam * the hyperchannel status bits to determine what to do next. 41011195Ssam * 41111195Ssam * If input error just drop packet. 41211195Ssam * Otherwise purge input buffered data path and examine 41311195Ssam * packet to determine type. Othewise decapsulate 41411195Ssam * packet based on type and pass to type specific higher-level 41511195Ssam * input routine. 41611195Ssam */ 41711195Ssam hyint(unit) 41811195Ssam int unit; 41911195Ssam { 42011195Ssam register struct hy_softc *is = &hy_softc[unit]; 42111195Ssam register struct uba_device *ui = hyinfo[unit]; 42211207Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 42311195Ssam 42411207Ssam if (hyint_active) 42511195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 42611195Ssam hyint_active++; 42711195Ssam #ifdef DEBUG 42811195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 42911195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 43011195Ssam #endif 43111195Ssam #ifdef HYLOG 43211195Ssam logit: 43311195Ssam { 43411195Ssam struct { 43511207Ssam u_char hstate; 43611207Ssam u_char hflags; 43711207Ssam short hcsr; 43811207Ssam short hwcr; 43911195Ssam } hil; 44011195Ssam hil.hstate = is->hy_state; 44111195Ssam hil.hflags = is->hy_flags; 44211195Ssam hil.hcsr = addr->hyd_csr; 44311195Ssam hil.hwcr = addr->hyd_wcr; 44411195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil); 44511195Ssam } 44611195Ssam #endif 44711207Ssam if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 44811195Ssam /* 44911207Ssam * Error bit set, some sort of error in the interface. 45011195Ssam * 45111207Ssam * The adapter sets attn on command completion so that's not 45211207Ssam * a real error even though the interface considers it one. 45311195Ssam */ 45411195Ssam #ifdef DEBUG 45511207Ssam if (hy_nodebug & 4) 45611207Ssam hy_debug_flag = 1; 45711195Ssam #endif 45811207Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 45911207Ssam addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 46011207Ssam addr->hyd_wcr); 46111207Ssam if (addr->hyd_csr & S_NEX) { 46211195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit); 46311195Ssam #ifdef PI13 46411195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 46511195Ssam #else 46611195Ssam addr->hyd_csr &= ~S_NEX; 46711195Ssam #endif 46811195Ssam hycancel(ui); 46911195Ssam #ifdef PI13 47011207Ssam } else if (addr->hyd_csr & S_POWEROFF) { 47121128Skarels printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit); 47211195Ssam addr->hyd_csr |= S_POWEROFF; 47311195Ssam DELAY(100); 47411207Ssam if (addr->hyd_csr & S_POWEROFF) { 47521128Skarels printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit); 47611195Ssam if_down(&is->hy_if); 47721128Skarels is->hy_if.if_flags &= ~IFF_UP; 47811195Ssam is->hy_state = STARTUP; 47921128Skarels } else { 48021128Skarels printf("hy%d: Adapter Power Restored (hyint)\n", unit); 48111195Ssam } 48211195Ssam #endif 48311195Ssam } else { 48411195Ssam printf("hy%d: BAR overflow\n", unit); 48511195Ssam hycancel(ui); 48611195Ssam } 48711207Ssam } else if (HYS_NORMAL(addr)) { 48811195Ssam /* 48911207Ssam * Normal interrupt, bump state machine unless in state 49011195Ssam * waiting and no data present (assumed to be word count 49111207Ssam * zero interrupt or other hardware botch). 49211195Ssam */ 49311207Ssam if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 49411195Ssam hyact(ui); 49511207Ssam } else if (HYS_ABNORMAL(addr)) { 49611195Ssam /* 49711207Ssam * Abnormal termination. 49811195Ssam * bump error counts, retry the last function 49911195Ssam * 'MAXRETRY' times before kicking the bucket. 50011195Ssam * 50111207Ssam * Don't reissue the cmd if in certain states, abnormal 50211207Ssam * on a reissued cmd or max retry exceeded. 50311195Ssam */ 50411195Ssam #ifdef HYLOG 50511195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 50611195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 50711195Ssam goto logit; 50811195Ssam } 50911195Ssam #endif 51011195Ssam #ifdef DEBUG 51111207Ssam if (hy_nodebug & 4) 51211207Ssam hy_debug_flag = 1; 51311195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 51411195Ssam unit, hy_state_names[is->hy_state], is->hy_state); 51521128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 51621128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 51711207Ssam printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 51811207Ssam is->hy_savedstate, is->hy_savedcount, 51911207Ssam is->hy_savedaddr, is->hy_savedcmd); 52011195Ssam #endif 52111195Ssam #ifdef PI13 52211195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 52311195Ssam #endif 52411207Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 52511195Ssam is->hy_if.if_oerrors++; 52621128Skarels else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 52711195Ssam is->hy_if.if_ierrors++; 52821128Skarels else 52921128Skarels is->hy_if.if_collisions++; /* other errors */ 53011195Ssam if (is->hy_state == XMITDATASENT || 53111195Ssam is->hy_state == RECVSENT || 53211195Ssam is->hy_state == RECVDATASENT || 53311207Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 53411195Ssam hycancel(ui); 53511207Ssam else { 53611195Ssam #ifdef DEBUG 53711207Ssam if (hy_nodebug & 2) 53811207Ssam hy_debug_flag = 1; 53911195Ssam #endif 54011195Ssam is->hy_retry++; 54111195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 54211195Ssam is->hy_state = IDLE; 54311195Ssam hyact(ui); 54411195Ssam } 54511195Ssam } else { 54611195Ssam /* 54711195Ssam * Interrupt is neither normal, abnormal, or interface error. 54811195Ssam * Ignore it. It's either stacked or a word count 0. 54911195Ssam */ 55011195Ssam #ifdef HYLOG 55111195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 55211195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 55311195Ssam goto logit; 55411195Ssam } 55511195Ssam #endif 55611195Ssam #ifdef DEBUG 55711195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit); 55811195Ssam #endif 55911195Ssam } 56011195Ssam #ifdef DEBUG 56111195Ssam printD("hy%d: hyint exit\n\n", unit); 56211195Ssam #endif 56311195Ssam hyint_active = 0; 56411195Ssam 56511207Ssam } 56611195Ssam 56721128Skarels int hyoutprint = 0; 56821128Skarels 56911195Ssam /* 57011195Ssam * Encapsulate a packet of type family for the local net. 57111195Ssam */ 57211195Ssam hyoutput(ifp, m0, dst) 57311195Ssam struct ifnet *ifp; 57411195Ssam struct mbuf *m0; 57511195Ssam struct sockaddr *dst; 57611195Ssam { 57711195Ssam register struct hym_hdr *hym; 57811195Ssam register struct mbuf *m; 57921128Skarels register char *mp; 58021128Skarels int dlen; /* packet size, incl hardware header, but not sw header */ 58111195Ssam int error = 0; 58211195Ssam int s; 58311195Ssam 58421128Skarels /* 58521128Skarels * Calculate packet length for later deciding whether it will fit 58621128Skarels * in a message proper or we also need associated data. 58721128Skarels */ 58811195Ssam dlen = 0; 58911195Ssam for (m = m0; m; m = m->m_next) 59011195Ssam dlen += m->m_len; 59111195Ssam m = m0; 59221128Skarels if (dst->sa_family == AF_HYLINK) { /* don't add header */ 59321128Skarels dlen -= HYM_SWLEN; 59421128Skarels goto headerexists; 59521128Skarels } 59621128Skarels 59721128Skarels /* 59821128Skarels * Add the software and hardware hyperchannel headers. 59921128Skarels * If there's not enough space in the first mbuf, allocate another. 60021128Skarels * If that should fail, drop this sucker. 60121128Skarels * No extra space for headers is allocated. 60221128Skarels */ 60321128Skarels mp = mtod(m, char *); /* save pointer to real message */ 60435800Ssklower M_PREPEND(m, sizeof(struct hym_hdr), M_DONTWAIT); 60535800Ssklower if (m == 0) { 60635800Ssklower error = ENOBUFS; 60735800Ssklower goto bad; 60821128Skarels } 60921128Skarels dlen += sizeof(struct hym_hdr) - HYM_SWLEN; 61021128Skarels 61121128Skarels hym = mtod(m, struct hym_hdr *); 61221128Skarels 61321128Skarels bzero((caddr_t)hym, sizeof(struct hym_hdr)); 61421128Skarels 61511195Ssam switch(dst->sa_family) { 61611195Ssam 61711195Ssam #ifdef INET 61811195Ssam case AF_INET: { 61921128Skarels int i; 62011195Ssam 62111195Ssam /* 62221128Skarels * if loopback address, swizzle ip header so when 62321128Skarels * it comes back it looks like it was addressed to us 62411195Ssam */ 62521128Skarels i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym); 62621128Skarels if (i < 0) 62721128Skarels goto notfound; 62821128Skarels if (i > 0) { 62911195Ssam struct in_addr temp; 63011195Ssam 63121128Skarels temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr; 63221128Skarels ((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr; 63321128Skarels ((struct ip *)mp)->ip_src.s_addr = temp.s_addr; 63411195Ssam } 63511195Ssam /* 63611195Ssam * If entire packet won't fit in message proper, just 63711195Ssam * send hyperchannel hardware header and ip header in 63821128Skarels * message proper. 63911195Ssam * 64011195Ssam * This insures that the associated data is at least a 64111195Ssam * TCP/UDP header in length and thus prevents potential 64211195Ssam * problems with very short word counts. 64311195Ssam */ 64421128Skarels if (dlen > MPSIZE) 64521128Skarels hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2); 64621128Skarels hym->hym_type = HYLINK_IP; 64711195Ssam break; 64811195Ssam } 64911195Ssam #endif 65011195Ssam 65111195Ssam default: 65211207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, 65311207Ssam dst->sa_family); 65411195Ssam error = EAFNOSUPPORT; 65511195Ssam goto drop; 65611195Ssam } 65711195Ssam 65821128Skarels 65921128Skarels headerexists: 66021128Skarels 66111195Ssam /* 66221128Skarels * insure message proper is below the maximum 66311195Ssam */ 66421128Skarels if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0)) 66521128Skarels hym->hym_mplen = MPSIZE; 66611195Ssam 66721775Skarels hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host); 66821128Skarels if (hym->hym_mplen) 66921128Skarels hym->hym_ctl |= H_ASSOC; 67021128Skarels else 67121128Skarels hym->hym_ctl &= ~H_ASSOC; 67221128Skarels if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 67321128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 67421128Skarels hym->hym_access, hym->hym_to, hym->hym_from, 67521128Skarels hym->hym_param, hym->hym_type); 67611195Ssam #ifdef DEBUG 67721128Skarels printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 67821128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 67921128Skarels hym->hym_access, hym->hym_to, hym->hym_from, 68021128Skarels hym->hym_param, hym->hym_type); 68111195Ssam #endif 68211195Ssam s = splimp(); 68311195Ssam if (IF_QFULL(&ifp->if_snd)) { 68411195Ssam IF_DROP(&ifp->if_snd); 68511195Ssam error = ENOBUFS; 68611195Ssam splx(s); 68711195Ssam goto drop; 68811195Ssam } 68911195Ssam IF_ENQUEUE(&ifp->if_snd, m); 69011195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING) 69111195Ssam hyact(hyinfo[ifp->if_unit]); 69211195Ssam splx(s); 69311207Ssam return (0); 69411195Ssam notfound: 69521128Skarels error = EHOSTUNREACH; 69611195Ssam drop: 69711195Ssam m_freem(m); 69811207Ssam return (error); 69911207Ssam } 70011195Ssam 70121128Skarels int 70221128Skarels hyroute(ifp, dest, hym) 70321128Skarels register struct ifnet *ifp; 70421128Skarels u_long dest; 70521128Skarels register struct hym_hdr *hym; 70621128Skarels { 70721128Skarels #ifdef HYROUTE 70821128Skarels register struct hy_route *rt = &hy_route[ifp->if_unit]; 70921128Skarels register struct hyr_hash *rhash; 71021128Skarels register int i; 71121128Skarels #endif 71221128Skarels 71321128Skarels hym->hym_param = 0; 71421128Skarels #ifdef HYROUTE 71521128Skarels if (rt->hyr_lasttime != 0) { 71621128Skarels i = HYRHASH(dest); 71721128Skarels rhash = &rt->hyr_hash[i]; 71821128Skarels i = 0; 71921128Skarels while (rhash->hyr_key != dest) { 72021128Skarels if (rhash->hyr_flags == 0 || i > HYRSIZE) 72121128Skarels return(-1); 72221128Skarels rhash++; i++; 72321128Skarels if (rhash >= &rt->hyr_hash[HYRSIZE]) 72421128Skarels rhash = &rt->hyr_hash[0]; 72521128Skarels } 72621128Skarels if (rhash->hyr_flags & HYR_GATE) { 72721128Skarels i = rhash->hyr_nextgate; 72821128Skarels if (i >= rhash->hyr_egate) 72921128Skarels rhash->hyr_nextgate = rhash->hyr_pgate; 73021128Skarels else 73121128Skarels rhash->hyr_nextgate++; 73221128Skarels rhash = &rt->hyr_hash[rt->hyr_gateway[i]]; 73321128Skarels if ((rhash->hyr_flags & HYR_DIR) == 0) 73421128Skarels return(-1); 73521128Skarels } else if (rhash->hyr_flags & HYR_LOOP) { 73621128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */ 73721128Skarels } else if (rhash->hyr_flags & HYR_RLOOP) { 73821128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 73921128Skarels } 74021128Skarels hym->hym_ctl = rhash->hyr_ctl; 74121128Skarels hym->hym_access = rhash->hyr_access; 74221128Skarels hym->hym_to = rhash->hyr_dst; 74321128Skarels } else { 74421128Skarels #endif 74521128Skarels hym->hym_ctl = H_XTRUNKS | H_RTRUNKS; 74621128Skarels hym->hym_access = 0; 74721128Skarels hym->hym_to = htons((u_short)dest); 74821128Skarels if (dest & 0x010000) 74921128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */ 75021128Skarels else if (dest & 0x020000) 75121128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 75221128Skarels #ifdef HYROUTE 75321128Skarels } 75421128Skarels #endif 75521128Skarels 75621128Skarels if (hym->hym_param == 0) 75721128Skarels return(0); 75821128Skarels else 75921128Skarels return(1); 76021128Skarels } 76121128Skarels 76211195Ssam hyact(ui) 76311195Ssam register struct uba_device *ui; 76411195Ssam { 76511195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 76611195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 76711195Ssam 76811195Ssam actloop: 76911195Ssam #ifdef DEBUG 77011207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 77111207Ssam hy_state_names[is->hy_state]); 77211195Ssam #endif 77311195Ssam switch (is->hy_state) { 77411195Ssam 77511195Ssam case STARTUP: 77611195Ssam goto endintr; 77711195Ssam 77811195Ssam case IDLE: { 77911195Ssam register rq = is->hy_flags; 78011195Ssam 78111195Ssam if (rq & RQ_STATUS) { 78211195Ssam is->hy_flags &= ~RQ_STATUS; 78311195Ssam is->hy_state = STATSENT; 78411207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status), 78513088Ssam is->hy_ifuba.ifu_r.ifrw_info); 78611195Ssam } else if (rq & RQ_ENDOP) { 78711195Ssam is->hy_flags &= ~RQ_ENDOP; 78811195Ssam is->hy_state = ENDOPSENT; 78911195Ssam hystart(ui, HYF_END_OP, 0, 0); 79011195Ssam } else if (rq & RQ_STATISTICS) { 79111195Ssam is->hy_flags &= ~RQ_STATISTICS; 79211195Ssam is->hy_state = RSTATSENT; 79311207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 79413088Ssam is->hy_ifuba.ifu_r.ifrw_info); 79511207Ssam } else if (HYS_RECVDATA(addr)) { 79611195Ssam is->hy_state = RECVSENT; 79711195Ssam is->hy_retry = 0; 79821128Skarels hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN); 79911195Ssam } else if (rq & RQ_REISSUE) { 80011195Ssam is->hy_flags &= ~RQ_REISSUE; 80111195Ssam is->hy_state = is->hy_savedstate; 80211195Ssam #ifdef DEBUG 80311207Ssam printD("hy%d: reissue cmd=0x%x count=%d", 80411207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 80511207Ssam printD(" ubaddr=0x%x retry=%d\n", 80611207Ssam is->hy_savedaddr, is->hy_retry); 80711195Ssam #endif 80811207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, 80913088Ssam is->hy_savedaddr); 81011195Ssam } else { 81111195Ssam register struct mbuf *m; 81211195Ssam 81311195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 81411207Ssam if (m != NULL) { 81511195Ssam register struct hym_hdr *hym; 81611195Ssam register int mplen; 81711195Ssam register int cmd; 81811195Ssam 81911195Ssam is->hy_state = XMITSENT; 82011195Ssam is->hy_retry = 0; 82111195Ssam hym = mtod(m, struct hym_hdr *); 82211195Ssam #ifdef HYLOG 82311207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), 82413088Ssam (char *)hym); 82511195Ssam #endif 82611195Ssam mplen = hym->hym_mplen; 82721128Skarels if (hym->hym_to_adapter == hym->hym_from_adapter) 82811207Ssam cmd = HYF_XMITLOCMSG; 82911207Ssam else 83011207Ssam cmd = HYF_XMITMSG; 83111195Ssam #ifdef DEBUG 83211195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 83311207Ssam if (hy_debug_flag) 83411207Ssam hyprintdata((char *)hym, 83513088Ssam sizeof (struct hym_hdr)); 83611195Ssam #endif 83721128Skarels is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN; 83811195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 83911207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 84011207Ssam is->hy_ifuba.ifu_w.ifrw_bdp); 84111195Ssam #ifdef DEBUG 84211207Ssam printD( 84311207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 84411195Ssam ui->ui_unit, mplen, is->hy_olen); 84511207Ssam if (hy_debug_flag) 84611207Ssam hyprintdata( 84713088Ssam is->hy_ifuba.ifu_w.ifrw_addr, 84821128Skarels is->hy_olen + HYM_SWLEN); 84911195Ssam #endif 85021128Skarels if (mplen == 0) { 85121128Skarels is->hy_flags &= ~RQ_XASSOC; 85221128Skarels mplen = is->hy_olen; 85321128Skarels } else { 85411195Ssam is->hy_flags |= RQ_XASSOC; 85521128Skarels } 85621128Skarels hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN); 85711195Ssam } else if (rq & RQ_MARKDOWN) { 85811195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 85911195Ssam is->hy_state = MARKPORT; 86011195Ssam is->hy_retry = 0; 86111195Ssam /* 86211207Ssam * Port number is taken from status data 86311195Ssam */ 86411207Ssam hystart(ui, 86512772Ssam (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 86612772Ssam 0, 0); 86711195Ssam } else if (rq & RQ_MARKUP) { 86811195Ssam register struct ifnet *ifp = &is->hy_if; 86911195Ssam 87011207Ssam is->hy_flags &= ~RQ_MARKUP; 87111195Ssam is->hy_retry = 0; 87211195Ssam /* 87313065Ssam * Fill in the host number 87411207Ssam * from the status buffer 87511195Ssam */ 87611207Ssam printf( 87711207Ssam "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 87811195Ssam ui->ui_unit, 87911195Ssam is->hy_stat.hyc_uaddr, 88011195Ssam PORTNUM(&is->hy_status), 88111207Ssam (is->hy_stat.hyc_atype[0]<<8) | 88211207Ssam is->hy_stat.hyc_atype[1], 88311195Ssam is->hy_stat.hyc_atype[2]); 88411195Ssam 88521775Skarels is->hy_host = 88611207Ssam (is->hy_stat.hyc_uaddr << 8) | 88711207Ssam PORTNUM(&is->hy_status); 88811195Ssam ifp->if_flags |= IFF_UP; 88911195Ssam #ifdef HYLOG 89011195Ssam hylog(HYL_UP, 0, (char *)0); 89111195Ssam #endif 89211195Ssam } else { 89311195Ssam is->hy_state = WAITING; 89411195Ssam is->hy_retry = 0; 89511195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0); 89611195Ssam } 89711195Ssam } 89811207Ssam break; 89911195Ssam } 90011195Ssam 90111195Ssam case STATSENT: 90212772Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status, 90311207Ssam sizeof (struct hy_status)); 90411195Ssam #ifdef DEBUG 90511207Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 90611207Ssam ui->ui_unit, is->hy_status.hys_gen_status, 90711207Ssam is->hy_status.hys_last_fcn, 90811207Ssam is->hy_status.hys_resp_trunk, 90911207Ssam is->hy_status.hys_status_trunk, 91011207Ssam is->hy_status.hys_recd_resp, 91111207Ssam is->hy_status.hys_error, 91211207Ssam is->hy_status.hys_caddr, 91311207Ssam is->hy_status.hys_pad); 91411195Ssam #endif 91511195Ssam is->hy_state = IDLE; 91611195Ssam #ifdef HYLOG 91711207Ssam hylog(HYL_STATUS, sizeof (struct hy_status), 91811207Ssam (char *)&is->hy_status); 91911195Ssam #endif 92011195Ssam #ifdef HYELOG 92111195Ssam { 92211195Ssam register int i; 92311195Ssam 92411195Ssam i = is->hy_status.hys_error; 92521128Skarels if (i > HYE_MAX) 92611195Ssam i = HYE_MAX; 92711195Ssam switch (is->hy_status.hys_last_fcn) { 92811195Ssam case HYF_XMITLOCMSG: 92911195Ssam i += HYE_MAX+1; /* fall through */ 93011195Ssam case HYF_XMITLSTDATA: 93111195Ssam i += HYE_MAX+1; /* fall through */ 93211195Ssam case HYF_XMITMSG: 93311195Ssam i += HYE_MAX+1; 93411195Ssam } 93511195Ssam hy_elog[i]++; 93611195Ssam } 93711195Ssam #endif 93811195Ssam break; 93911195Ssam 94011195Ssam case RSTATSENT: { 94111207Ssam register struct hy_stat *p = 94211207Ssam (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 94311195Ssam 94421128Skarels bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat)); 94511195Ssam #ifdef DEBUG 94621128Skarels 94721128Skarels printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n", 94811195Ssam ui->ui_unit, 94921128Skarels (is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2], 95021128Skarels (is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2], 95121128Skarels (is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2], 95221128Skarels (is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]); 95321128Skarels printD(" ret0 %d ret1 %d ret2 %d ret3 %d\n", 95421128Skarels (is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2], 95521128Skarels (is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2], 95621128Skarels (is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2], 95721128Skarels (is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]); 95821128Skarels printD(" cancel %d abort %d atype %x %x %x uaddr %x\n", 95921128Skarels (is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1], 96021128Skarels (is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1], 96111195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 96211195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 96311195Ssam #endif 96411195Ssam is->hy_state = IDLE; 96511195Ssam #ifdef HYLOG 96611207Ssam hylog(HYL_STATISTICS, sizeof (struct hy_stat), 96711207Ssam (char *)&is->hy_stat); 96811195Ssam #endif 96911195Ssam break; 97011195Ssam } 97111195Ssam 97211195Ssam case CLEARSENT: 97311195Ssam is->hy_state = IDLE; 97411195Ssam break; 97511195Ssam 97611195Ssam case ENDOPSENT: 97711195Ssam is->hy_state = IDLE; 97811195Ssam break; 97911195Ssam 98011195Ssam case RECVSENT: { 98121128Skarels register struct hym_hdr *hym; 98211207Ssam register unsigned len; 98311195Ssam 98411207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 98511207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 98613088Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 98721128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 98811207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 98911207Ssam if (len > MPSIZE) { 99011207Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n", 99113088Ssam ui->ui_unit, len); 99221128Skarels is->hy_state = IDLE; 99311195Ssam #ifdef DEBUG 99411207Ssam hy_debug_flag = 1; 99511207Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 99611207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 99711207Ssam addr->hyd_bar, addr->hyd_wcr); 99811195Ssam #endif 99911207Ssam } 100021128Skarels hym->hym_mplen = len; 100111195Ssam #ifdef DEBUG 100211207Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 100311207Ssam if (hy_debug_flag) 100421128Skarels hyprintdata((char *)hym, len + HYM_SWLEN); 100511195Ssam #endif 100621128Skarels if (hym->hym_ctl & H_ASSOC) { 100711207Ssam is->hy_state = RECVDATASENT; 100811207Ssam is->hy_retry = 0; 100911207Ssam hystart(ui, HYF_INPUTDATA, 101021128Skarels (int)(HYMTU + sizeof (struct hy_hdr) - len), 101121128Skarels (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len)); 101211207Ssam } else { 101321128Skarels hyrecvdata(ui, hym, (int)len + HYM_SWLEN); 101411207Ssam is->hy_state = IDLE; 101511195Ssam } 101611207Ssam break; 101711207Ssam } 101811195Ssam 101911195Ssam case RECVDATASENT: { 102021128Skarels register struct hym_hdr *hym; 102111207Ssam register unsigned len; 102211195Ssam 102311207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 102411207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 102513088Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 102621128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 102711207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 102811195Ssam #ifdef DEBUG 102911207Ssam printD("hy%d: recvd assoc data, len = %d, data = ", 103011207Ssam ui->ui_unit, len); 103111207Ssam if (hy_debug_flag) 103221128Skarels hyprintdata((char *)hym + hym->hym_mplen, len); 103311195Ssam #endif 103421128Skarels hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN)); 103511207Ssam is->hy_state = IDLE; 103611207Ssam break; 103711207Ssam } 103811195Ssam 103911195Ssam case XMITSENT: 104011207Ssam if (is->hy_flags & RQ_XASSOC) { 104113196Sroot register int len; 104211195Ssam 104311207Ssam is->hy_flags &= ~RQ_XASSOC; 104411207Ssam is->hy_state = XMITDATASENT; 104511207Ssam is->hy_retry = 0; 104611207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 104711207Ssam if (len > is->hy_olen) { 104811207Ssam printf( 104911207Ssam "hy%d: xmit error - len > hy_olen [%d > %d]\n", 105011207Ssam ui->ui_unit, len, is->hy_olen); 105111195Ssam #ifdef DEBUG 105211207Ssam hy_debug_flag = 1; 105311195Ssam #endif 105411195Ssam } 105511207Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 105621128Skarels is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len); 105711207Ssam break; 105811207Ssam } 105911207Ssam /* fall through to ... */ 106011195Ssam 106111195Ssam case XMITDATASENT: 106211207Ssam hyxmitdata(ui); 106311207Ssam is->hy_state = IDLE; 106411207Ssam break; 106511195Ssam 106611195Ssam case WAITING: /* wait for message complete or output requested */ 106711207Ssam if (HYS_RECVDATA(addr)) 106811195Ssam is->hy_state = IDLE; 106911195Ssam else { 107011195Ssam is->hy_state = CLEARSENT; 107111195Ssam is->hy_retry = 0; 107211195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0); 107311195Ssam } 107411195Ssam break; 107511195Ssam 107611195Ssam case MARKPORT: 107711195Ssam is->hy_state = STARTUP; 107821128Skarels if_down(&is->hy_if); 107911195Ssam is->hy_if.if_flags &= ~IFF_UP; 108011195Ssam goto endintr; 108111195Ssam 108211195Ssam default: 108311207Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 108411207Ssam ui->ui_unit, is->hy_state); 108511195Ssam panic("HYPERCHANNEL IN INVALID STATE"); 108611195Ssam /*NOTREACHED*/ 108711207Ssam } 108811195Ssam if (is->hy_state == IDLE) 108911195Ssam goto actloop; 109011195Ssam endintr: 109113088Ssam ; 109211195Ssam #ifdef DEBUG 109311207Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 109411207Ssam hy_state_names[is->hy_state]); 109511195Ssam #endif 109611207Ssam } 109711195Ssam 109821128Skarels struct sockproto hypproto = { PF_HYLINK }; 1099*37476Ssklower struct sockaddr_in hypdst = { sizeof(hypdst), AF_HYLINK }; 1100*37476Ssklower struct sockaddr_in hypsrc = { sizeof(hypsrc), AF_HYLINK }; 110121128Skarels 110211195Ssam /* 110313088Ssam * Called from device interrupt when receiving data. 110411195Ssam * Examine packet to determine type. Decapsulate packet 110511195Ssam * based on type and pass to type specific higher-level 110611195Ssam * input routine. 110711195Ssam */ 110821128Skarels hyrecvdata(ui, hym, len) 110911195Ssam struct uba_device *ui; 111021128Skarels register struct hym_hdr *hym; 111111195Ssam int len; 111211195Ssam { 111311195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 111411195Ssam struct mbuf *m; 111511195Ssam register struct ifqueue *inq; 111611195Ssam 111711195Ssam is->hy_if.if_ipackets++; 111811195Ssam #ifdef DEBUG 111921128Skarels printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len); 112011195Ssam #endif 112111195Ssam #ifdef HYLOG 112211195Ssam { 112311195Ssam struct { 112411195Ssam short hlen; 112521128Skarels struct hym_hdr hhdr; 112611195Ssam } hh; 112711195Ssam hh.hlen = len; 112821128Skarels hh.hhdr = *hym; 112911195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh); 113011195Ssam } 113111195Ssam #endif 113211195Ssam if (len > HYMTU + MPSIZE || len == 0) 113311195Ssam return; /* sanity */ 113411195Ssam /* 113511195Ssam * Pull packet off interface. 113611195Ssam */ 113724797Skarels m = if_rubaget(&is->hy_ifuba, len, 0, &is->hy_if); 113811207Ssam if (m == NULL) 113911195Ssam return; 114011195Ssam 114121128Skarels /* 114221128Skarels * if normal or adapter loopback response packet believe hym_type, 114321128Skarels * otherwise, use the raw input queue cause it's a response from an 114421128Skarels * adapter command. 114521128Skarels */ 114621128Skarels if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff) 114721128Skarels goto rawlinkin; 114821128Skarels 114921128Skarels switch (hym->hym_type) { 115021128Skarels 115111195Ssam #ifdef INET 115211195Ssam case HYLINK_IP: 115311195Ssam schednetisr(NETISR_IP); 115411195Ssam inq = &ipintrq; 115511195Ssam break; 115611195Ssam #endif 115711195Ssam default: 115821128Skarels rawlinkin: 115921128Skarels { 116035800Ssklower M_PREPEND(m, sizeof(struct hym_hdr), M_DONTWAIT); 116135800Ssklower if (m == 0) { 116221128Skarels m_freem(m); 116321128Skarels return; 116421128Skarels } 116535800Ssklower bcopy((caddr_t)hym, mtod(m, caddr_t), sizeof(struct hym_hdr)); 116621128Skarels hypproto.sp_protocol = 0; 116721775Skarels hypdst.sin_addr = is->hy_addr; 116821775Skarels hypsrc.sin_addr = is->hy_addr; 116921128Skarels raw_input(m, &hypproto, (struct sockaddr *)&hypsrc, 117021128Skarels (struct sockaddr *)&hypdst); 117121128Skarels return; 117221128Skarels } 117311195Ssam } 117411195Ssam if (IF_QFULL(inq)) { 117511195Ssam IF_DROP(inq); 117611195Ssam m_freem(m); 117711195Ssam } else 117811195Ssam IF_ENQUEUE(inq, m); 117911207Ssam } 118011195Ssam 118111195Ssam /* 118211207Ssam * Transmit done, release resources, bump counters. 118311195Ssam */ 118411195Ssam hyxmitdata(ui) 118511195Ssam struct uba_device *ui; 118611195Ssam { 118711195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 118811195Ssam 118911195Ssam is->hy_if.if_opackets++; 119011207Ssam if (is->hy_ifuba.ifu_xtofree) { 119111195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 119211195Ssam is->hy_ifuba.ifu_xtofree = 0; 119311195Ssam } 119411207Ssam } 119511195Ssam 119611195Ssam hycancel(ui) 119711195Ssam register struct uba_device *ui; 119811195Ssam { 119911195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 120011195Ssam 120111207Ssam if (is->hy_ifuba.ifu_xtofree) { 120211195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 120311195Ssam is->hy_ifuba.ifu_xtofree = 0; 120411195Ssam } 120521128Skarels #ifdef HYLOG 120621128Skarels hylog(HYL_CANCEL, 0, (char *)0); 120721128Skarels #endif 120811195Ssam #ifdef DEBUG 120911207Ssam if (hy_nodebug & 1) 121011207Ssam hy_debug_flag = 1; 121111195Ssam #endif 121211195Ssam #ifdef DEBUG 121311195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 121411195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 121511195Ssam is->hy_savedcount, is->hy_savedaddr); 121621128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 121721128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 121811207Ssam printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 121911207Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 122011207Ssam is->hy_savedcmd); 122111195Ssam #endif 122211195Ssam is->hy_state = IDLE; 122311195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 122411195Ssam hyact(ui); 122511207Ssam } 122611195Ssam 122711195Ssam #ifdef DEBUG 122811195Ssam hyprintdata(cp, len) 122911195Ssam register char *cp; 123011195Ssam register int len; 123111195Ssam { 123211195Ssam register int count = 16; 123311195Ssam register char *fmt; 123411195Ssam static char regfmt[] = "\n\t %x"; 123511195Ssam 123611195Ssam fmt = ®fmt[2]; 123711195Ssam while (--len >= 0) { 123811195Ssam printL(fmt, *cp++ & 0xff); 123911195Ssam fmt = ®fmt[2]; 124011195Ssam if (--count <= 0) { 124111195Ssam fmt = ®fmt[0]; 124211195Ssam count = 16; 124311195Ssam } 124411195Ssam } 124511195Ssam printL("\n"); 124611195Ssam } 124711195Ssam #endif 124811195Ssam 124911195Ssam hywatch(unit) 125013088Ssam int unit; 125111195Ssam { 125211195Ssam register struct hy_softc *is = &hy_softc[unit]; 125311195Ssam register struct uba_device *ui = hyinfo[unit]; 125411195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 125511195Ssam int s; 125611195Ssam 125711195Ssam s = splimp(); 125811195Ssam #ifdef PI13 125911195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 126011195Ssam addr->hyd_csr |= S_POWEROFF; 126111195Ssam DELAY(100); 126211195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) { 126321128Skarels printf("hy%d: Adapter Power Restored (hywatch)\n", unit); 126411195Ssam is->hy_state = IDLE; 126511207Ssam is->hy_flags |= 126611207Ssam (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 126711195Ssam hyact(ui); 126811195Ssam } 126911195Ssam } 127011195Ssam #endif 127121128Skarels if (++is->hy_ntime >= 2 && is->hy_state != WAITING && 127221128Skarels is->hy_state != STARTUP && is->hy_state != IDLE) { 127321128Skarels #ifdef HYLOG 127421128Skarels printf("hy%d: watchdog timer expired in state \"%s\"\n", unit, 127521128Skarels hy_state_names[is->hy_state]); 127621128Skarels #else 127721128Skarels printf("hy%d: watchdog timer expired in state %d\n", unit, 127821128Skarels is->hy_state); 127921128Skarels #endif 128021128Skarels printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit, 128121128Skarels is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS); 128221128Skarels hycancel(ui); 128321128Skarels } 128411195Ssam splx(s); 128521128Skarels is->hy_if.if_timer = SCANINTERVAL; 128611195Ssam } 128711195Ssam 128811195Ssam #ifdef HYLOG 128911195Ssam hylog(code, len, ptr) 129013088Ssam int code, len; 129111195Ssam char *ptr; 129211195Ssam { 129311195Ssam register unsigned char *p; 129411195Ssam int s; 129511195Ssam 129611195Ssam s = splimp(); 129711195Ssam if (hy_log.hyl_self != &hy_log) { 129811195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 129911195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 130011195Ssam hy_log.hyl_self = &hy_log; 130121128Skarels hy_log.hyl_enable = HYL_CONTINUOUS; 130221128Skarels hy_log.hyl_onerr = HYL_CONTINUOUS; 130321128Skarels hy_log.hyl_count = 0; 130421128Skarels hy_log.hyl_icount = 16; 130521128Skarels hy_log.hyl_filter = 0xffff; /* enable all */ 130611195Ssam } 130721128Skarels if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0) 130811207Ssam goto out; 130911195Ssam p = hy_log.hyl_ptr; 131021128Skarels if (p + len + 3 >= hy_log.hyl_eptr) { 131112772Ssam bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 131211195Ssam p = &hy_log.hyl_buf[0]; 131321128Skarels if (hy_log.hyl_enable != HYL_CONTINUOUS) { 131421128Skarels hy_log.hyl_enable = HYL_DISABLED; 131511195Ssam goto out; 131611195Ssam } 131711195Ssam } 131811195Ssam *p++ = code; 131911195Ssam *p++ = len; 132013088Ssam bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len); 132121128Skarels if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) { 132221128Skarels *p++ = '\0'; 132321128Skarels hy_log.hyl_enable = HYL_DISABLED; 132421128Skarels hy_log.hyl_count = hy_log.hyl_icount; 132521128Skarels } 132626285Skarels p += len; 132721128Skarels if (hy_log.hyl_wait != 0) { /* wakeup HYGETLOG if wanted */ 132826285Skarels if (hy_log.hyl_wait <= p - hy_log.hyl_ptr) { 132921128Skarels wakeup((caddr_t)&hy_log); 133021128Skarels hy_log.hyl_wait = 0; 133126285Skarels } else 133226285Skarels hy_log.hyl_wait -= p - hy_log.hyl_ptr; 133321128Skarels } 133426285Skarels hy_log.hyl_ptr = p; 133511195Ssam out: 133611195Ssam splx(s); 133711195Ssam } 133811195Ssam #endif 133911195Ssam 134012772Ssam /*ARGSUSED*/ 134113058Ssam hyioctl(ifp, cmd, data) 134213058Ssam register struct ifnet *ifp; 134311207Ssam int cmd; 134411207Ssam caddr_t data; 134511195Ssam { 134621775Skarels struct ifaddr *ifa = (struct ifaddr *) data; 134721128Skarels struct hyrsetget *sg = (struct hyrsetget *)data; 134821128Skarels #if defined(HYLOG) || defined(HYELOG) 134921128Skarels struct hylsetget *sgl = (struct hylsetget *)data; 135021128Skarels #endif 135121128Skarels struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit]; 135211207Ssam int s = splimp(), error = 0; 135321128Skarels #ifdef HYLOG 135421128Skarels struct hy_softc *is = &hy_softc[ifp->if_unit]; 135521128Skarels struct { 135621128Skarels u_char hstate; 135721128Skarels u_char hflags; 135821128Skarels u_short iflags; 135921128Skarels int hcmd; 136021128Skarels int herror; 136121128Skarels u_long haddr; 136221128Skarels u_long hmisc; 136321128Skarels } hil; 136411195Ssam 136521128Skarels hil.hmisc = -1; 136621128Skarels hil.hstate = is->hy_state; 136721128Skarels hil.hflags = is->hy_flags; 136821128Skarels hil.hcmd = cmd; 136921128Skarels #endif 137021128Skarels 137111195Ssam switch(cmd) { 137211195Ssam 137313065Ssam case SIOCSIFADDR: 1374*37476Ssklower if (ifa->ifa_addr->sa_family != AF_INET) 137521128Skarels return(EINVAL); 137621775Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 137721775Skarels hyinit(ifp->if_unit); 137821775Skarels hy_softc[ifp->if_unit].hy_addr = IA_SIN(ifa)->sin_addr; 137921128Skarels #ifdef HYLOG 138021775Skarels hil.haddr = is->hy_addr.s_addr; 138121128Skarels #endif 138213065Ssam break; 138313065Ssam 138411195Ssam case HYSETROUTE: 138511207Ssam if (!suser()) { 138611207Ssam error = EPERM; 138721128Skarels goto out; 138811195Ssam } 138921128Skarels 139021128Skarels if (sg->hyrsg_len != sizeof(struct hy_route)) { 139121128Skarels error = EINVAL; 139221128Skarels goto out; 139321128Skarels } 139421128Skarels if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) { 139521128Skarels r->hyr_lasttime = 0; /* disable further routing if trouble */ 139621128Skarels error = EFAULT; 139721128Skarels goto out; 139821128Skarels } 139921128Skarels r->hyr_lasttime = time.tv_sec; 140021128Skarels #ifdef HYLOG 140121128Skarels hil.hmisc = r->hyr_lasttime; 140221128Skarels #endif 140311195Ssam break; 140411195Ssam 140511195Ssam case HYGETROUTE: 140621128Skarels if (sg->hyrsg_len < sizeof(struct hy_route)) { 140721128Skarels error = EINVAL; 140821128Skarels goto out; 140921128Skarels } 141021128Skarels if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) { 141121128Skarels error = EFAULT; 141221128Skarels goto out; 141321128Skarels } 141411195Ssam break; 141511195Ssam 141621128Skarels #ifdef HYELOG 141721128Skarels case HYGETELOG: 141821128Skarels if (sgl->hylsg_len < sizeof(hy_elog)) { 141921128Skarels error = EINVAL; 142021128Skarels goto out; 142121128Skarels } 142221128Skarels if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) { 142321128Skarels error = EFAULT; 142421128Skarels goto out; 142521128Skarels } 142621128Skarels if (sgl->hylsg_cmd) { 142721128Skarels if (!suser()) { 142821128Skarels error = EPERM; 142921128Skarels goto out; 143021128Skarels } 143121128Skarels bzero((caddr_t)hy_elog, sizeof(hy_elog)); 143221128Skarels } 143321128Skarels break; 143421128Skarels #endif 143521128Skarels 143621128Skarels #ifdef HYLOG 143721128Skarels case HYSETLOG: 143821128Skarels if (!suser()) { 143921128Skarels error = EPERM; 144021128Skarels goto out; 144121128Skarels } 144221128Skarels hy_log.hyl_enable = HYL_DISABLED; 144321128Skarels hylog(HYL_NOP, 0, (char *)0); /* force log init */ 144421128Skarels hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f; 144521128Skarels hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f; 144621128Skarels hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff; 144721128Skarels hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len; 144821128Skarels wakeup((caddr_t)&hy_log); /* wakeup sleeping HYGETLOG */ 144921128Skarels break; 145021128Skarels 145121128Skarels case HYGETLOG: 145221128Skarels if (sgl->hylsg_len < sizeof(hy_log)) { 145321128Skarels error = EINVAL; 145421128Skarels goto out; 145521128Skarels } 145621128Skarels if (sgl->hylsg_cmd != 0) { 145721128Skarels if (hy_log.hyl_wait) { 145821128Skarels error = EBUSY; 145921128Skarels goto out; 146021128Skarels } 146121128Skarels hy_log.hyl_wait = sgl->hylsg_cmd; 146226392Skarels sleep((caddr_t)&hy_log, PZERO - 1); 146321128Skarels } 146421128Skarels 146521128Skarels if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) { 146621128Skarels error = EFAULT; 146721128Skarels goto out; 146821128Skarels } 146921128Skarels break; 147021128Skarels #endif 147121128Skarels 147211195Ssam default: 147313058Ssam error = EINVAL; 147411195Ssam break; 147511195Ssam } 147621128Skarels out: 147721128Skarels #ifdef HYLOG 147821128Skarels hil.herror = error; 147921128Skarels hil.iflags = ifp->if_flags; 148021775Skarels hil.haddr = is->hy_addr.s_addr; 148121128Skarels hylog(HYL_IOCTL, sizeof(hil), (char *)&hil); 148221128Skarels #endif 148311195Ssam splx(s); 148411207Ssam return (error); 148511195Ssam } 148611207Ssam #endif 1487