123294Smckusick /* 2*35322Sbostic * Copyright (c) 1988 Regents of the University of California. 3*35322Sbostic * All rights reserved. 4*35322Sbostic * 5*35322Sbostic * This code is derived from software contributed to Berkeley by 6*35322Sbostic * Tektronix Inc. 7*35322Sbostic * 8*35322Sbostic * Redistribution and use in source and binary forms are permitted 9*35322Sbostic * provided that the above copyright notice and this paragraph are 10*35322Sbostic * duplicated in all such forms and that any documentation, 11*35322Sbostic * advertising materials, and other materials related to such 12*35322Sbostic * distribution and use acknowledge that the software was developed 13*35322Sbostic * by the University of California, Berkeley. The name of the 14*35322Sbostic * University may not be used to endorse or promote products derived 15*35322Sbostic * from this software without specific prior written permission. 16*35322Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17*35322Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18*35322Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19*35322Sbostic * 20*35322Sbostic * @(#)if_hy.c 7.2 (Berkeley) 08/04/88 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 */ 60421128Skarels if (m->m_off > MMAXOFF || 60521128Skarels MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 60621128Skarels m = m_get(M_DONTWAIT, MT_HEADER); 60721128Skarels if (m == 0) { 60821128Skarels m = m0; 60921128Skarels error = ENOBUFS; 61021128Skarels goto drop; 61121128Skarels } 61221128Skarels m->m_next = m0; 61321128Skarels m->m_off = MMINOFF; 61421128Skarels m->m_len = sizeof(struct hym_hdr); 61521128Skarels } else { 61621128Skarels m->m_off -= sizeof(struct hym_hdr); 61721128Skarels m->m_len += sizeof(struct hym_hdr); 61821128Skarels } 61921128Skarels 62021128Skarels dlen += sizeof(struct hym_hdr) - HYM_SWLEN; 62121128Skarels 62221128Skarels hym = mtod(m, struct hym_hdr *); 62321128Skarels 62421128Skarels bzero((caddr_t)hym, sizeof(struct hym_hdr)); 62521128Skarels 62611195Ssam switch(dst->sa_family) { 62711195Ssam 62811195Ssam #ifdef INET 62911195Ssam case AF_INET: { 63021128Skarels int i; 63111195Ssam 63211195Ssam /* 63321128Skarels * if loopback address, swizzle ip header so when 63421128Skarels * it comes back it looks like it was addressed to us 63511195Ssam */ 63621128Skarels i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym); 63721128Skarels if (i < 0) 63821128Skarels goto notfound; 63921128Skarels if (i > 0) { 64011195Ssam struct in_addr temp; 64111195Ssam 64221128Skarels temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr; 64321128Skarels ((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr; 64421128Skarels ((struct ip *)mp)->ip_src.s_addr = temp.s_addr; 64511195Ssam } 64611195Ssam /* 64711195Ssam * If entire packet won't fit in message proper, just 64811195Ssam * send hyperchannel hardware header and ip header in 64921128Skarels * message proper. 65011195Ssam * 65111195Ssam * This insures that the associated data is at least a 65211195Ssam * TCP/UDP header in length and thus prevents potential 65311195Ssam * problems with very short word counts. 65411195Ssam */ 65521128Skarels if (dlen > MPSIZE) 65621128Skarels hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2); 65721128Skarels hym->hym_type = HYLINK_IP; 65811195Ssam break; 65911195Ssam } 66011195Ssam #endif 66111195Ssam 66211195Ssam default: 66311207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, 66411207Ssam dst->sa_family); 66511195Ssam error = EAFNOSUPPORT; 66611195Ssam goto drop; 66711195Ssam } 66811195Ssam 66921128Skarels 67021128Skarels headerexists: 67121128Skarels 67211195Ssam /* 67321128Skarels * insure message proper is below the maximum 67411195Ssam */ 67521128Skarels if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0)) 67621128Skarels hym->hym_mplen = MPSIZE; 67711195Ssam 67821775Skarels hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host); 67921128Skarels if (hym->hym_mplen) 68021128Skarels hym->hym_ctl |= H_ASSOC; 68121128Skarels else 68221128Skarels hym->hym_ctl &= ~H_ASSOC; 68321128Skarels if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 68421128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 68521128Skarels hym->hym_access, hym->hym_to, hym->hym_from, 68621128Skarels hym->hym_param, hym->hym_type); 68711195Ssam #ifdef DEBUG 68821128Skarels printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n", 68921128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl, 69021128Skarels hym->hym_access, hym->hym_to, hym->hym_from, 69121128Skarels hym->hym_param, hym->hym_type); 69211195Ssam #endif 69311195Ssam s = splimp(); 69411195Ssam if (IF_QFULL(&ifp->if_snd)) { 69511195Ssam IF_DROP(&ifp->if_snd); 69611195Ssam error = ENOBUFS; 69711195Ssam splx(s); 69811195Ssam goto drop; 69911195Ssam } 70011195Ssam IF_ENQUEUE(&ifp->if_snd, m); 70111195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING) 70211195Ssam hyact(hyinfo[ifp->if_unit]); 70311195Ssam splx(s); 70411207Ssam return (0); 70511195Ssam notfound: 70621128Skarels error = EHOSTUNREACH; 70711195Ssam drop: 70811195Ssam m_freem(m); 70911207Ssam return (error); 71011207Ssam } 71111195Ssam 71221128Skarels int 71321128Skarels hyroute(ifp, dest, hym) 71421128Skarels register struct ifnet *ifp; 71521128Skarels u_long dest; 71621128Skarels register struct hym_hdr *hym; 71721128Skarels { 71821128Skarels #ifdef HYROUTE 71921128Skarels register struct hy_route *rt = &hy_route[ifp->if_unit]; 72021128Skarels register struct hyr_hash *rhash; 72121128Skarels register int i; 72221128Skarels #endif 72321128Skarels 72421128Skarels hym->hym_param = 0; 72521128Skarels #ifdef HYROUTE 72621128Skarels if (rt->hyr_lasttime != 0) { 72721128Skarels i = HYRHASH(dest); 72821128Skarels rhash = &rt->hyr_hash[i]; 72921128Skarels i = 0; 73021128Skarels while (rhash->hyr_key != dest) { 73121128Skarels if (rhash->hyr_flags == 0 || i > HYRSIZE) 73221128Skarels return(-1); 73321128Skarels rhash++; i++; 73421128Skarels if (rhash >= &rt->hyr_hash[HYRSIZE]) 73521128Skarels rhash = &rt->hyr_hash[0]; 73621128Skarels } 73721128Skarels if (rhash->hyr_flags & HYR_GATE) { 73821128Skarels i = rhash->hyr_nextgate; 73921128Skarels if (i >= rhash->hyr_egate) 74021128Skarels rhash->hyr_nextgate = rhash->hyr_pgate; 74121128Skarels else 74221128Skarels rhash->hyr_nextgate++; 74321128Skarels rhash = &rt->hyr_hash[rt->hyr_gateway[i]]; 74421128Skarels if ((rhash->hyr_flags & HYR_DIR) == 0) 74521128Skarels return(-1); 74621128Skarels } else if (rhash->hyr_flags & HYR_LOOP) { 74721128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */ 74821128Skarels } else if (rhash->hyr_flags & HYR_RLOOP) { 74921128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 75021128Skarels } 75121128Skarels hym->hym_ctl = rhash->hyr_ctl; 75221128Skarels hym->hym_access = rhash->hyr_access; 75321128Skarels hym->hym_to = rhash->hyr_dst; 75421128Skarels } else { 75521128Skarels #endif 75621128Skarels hym->hym_ctl = H_XTRUNKS | H_RTRUNKS; 75721128Skarels hym->hym_access = 0; 75821128Skarels hym->hym_to = htons((u_short)dest); 75921128Skarels if (dest & 0x010000) 76021128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */ 76121128Skarels else if (dest & 0x020000) 76221128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */ 76321128Skarels #ifdef HYROUTE 76421128Skarels } 76521128Skarels #endif 76621128Skarels 76721128Skarels if (hym->hym_param == 0) 76821128Skarels return(0); 76921128Skarels else 77021128Skarels return(1); 77121128Skarels } 77221128Skarels 77311195Ssam hyact(ui) 77411195Ssam register struct uba_device *ui; 77511195Ssam { 77611195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 77711195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 77811195Ssam 77911195Ssam actloop: 78011195Ssam #ifdef DEBUG 78111207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 78211207Ssam hy_state_names[is->hy_state]); 78311195Ssam #endif 78411195Ssam switch (is->hy_state) { 78511195Ssam 78611195Ssam case STARTUP: 78711195Ssam goto endintr; 78811195Ssam 78911195Ssam case IDLE: { 79011195Ssam register rq = is->hy_flags; 79111195Ssam 79211195Ssam if (rq & RQ_STATUS) { 79311195Ssam is->hy_flags &= ~RQ_STATUS; 79411195Ssam is->hy_state = STATSENT; 79511207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status), 79613088Ssam is->hy_ifuba.ifu_r.ifrw_info); 79711195Ssam } else if (rq & RQ_ENDOP) { 79811195Ssam is->hy_flags &= ~RQ_ENDOP; 79911195Ssam is->hy_state = ENDOPSENT; 80011195Ssam hystart(ui, HYF_END_OP, 0, 0); 80111195Ssam } else if (rq & RQ_STATISTICS) { 80211195Ssam is->hy_flags &= ~RQ_STATISTICS; 80311195Ssam is->hy_state = RSTATSENT; 80411207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 80513088Ssam is->hy_ifuba.ifu_r.ifrw_info); 80611207Ssam } else if (HYS_RECVDATA(addr)) { 80711195Ssam is->hy_state = RECVSENT; 80811195Ssam is->hy_retry = 0; 80921128Skarels hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN); 81011195Ssam } else if (rq & RQ_REISSUE) { 81111195Ssam is->hy_flags &= ~RQ_REISSUE; 81211195Ssam is->hy_state = is->hy_savedstate; 81311195Ssam #ifdef DEBUG 81411207Ssam printD("hy%d: reissue cmd=0x%x count=%d", 81511207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 81611207Ssam printD(" ubaddr=0x%x retry=%d\n", 81711207Ssam is->hy_savedaddr, is->hy_retry); 81811195Ssam #endif 81911207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, 82013088Ssam is->hy_savedaddr); 82111195Ssam } else { 82211195Ssam register struct mbuf *m; 82311195Ssam 82411195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 82511207Ssam if (m != NULL) { 82611195Ssam register struct hym_hdr *hym; 82711195Ssam register int mplen; 82811195Ssam register int cmd; 82911195Ssam 83011195Ssam is->hy_state = XMITSENT; 83111195Ssam is->hy_retry = 0; 83211195Ssam hym = mtod(m, struct hym_hdr *); 83311195Ssam #ifdef HYLOG 83411207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), 83513088Ssam (char *)hym); 83611195Ssam #endif 83711195Ssam mplen = hym->hym_mplen; 83821128Skarels if (hym->hym_to_adapter == hym->hym_from_adapter) 83911207Ssam cmd = HYF_XMITLOCMSG; 84011207Ssam else 84111207Ssam cmd = HYF_XMITMSG; 84211195Ssam #ifdef DEBUG 84311195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 84411207Ssam if (hy_debug_flag) 84511207Ssam hyprintdata((char *)hym, 84613088Ssam sizeof (struct hym_hdr)); 84711195Ssam #endif 84821128Skarels is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN; 84911195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 85011207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 85111207Ssam is->hy_ifuba.ifu_w.ifrw_bdp); 85211195Ssam #ifdef DEBUG 85311207Ssam printD( 85411207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 85511195Ssam ui->ui_unit, mplen, is->hy_olen); 85611207Ssam if (hy_debug_flag) 85711207Ssam hyprintdata( 85813088Ssam is->hy_ifuba.ifu_w.ifrw_addr, 85921128Skarels is->hy_olen + HYM_SWLEN); 86011195Ssam #endif 86121128Skarels if (mplen == 0) { 86221128Skarels is->hy_flags &= ~RQ_XASSOC; 86321128Skarels mplen = is->hy_olen; 86421128Skarels } else { 86511195Ssam is->hy_flags |= RQ_XASSOC; 86621128Skarels } 86721128Skarels hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN); 86811195Ssam } else if (rq & RQ_MARKDOWN) { 86911195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 87011195Ssam is->hy_state = MARKPORT; 87111195Ssam is->hy_retry = 0; 87211195Ssam /* 87311207Ssam * Port number is taken from status data 87411195Ssam */ 87511207Ssam hystart(ui, 87612772Ssam (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 87712772Ssam 0, 0); 87811195Ssam } else if (rq & RQ_MARKUP) { 87911195Ssam register struct ifnet *ifp = &is->hy_if; 88011195Ssam 88111207Ssam is->hy_flags &= ~RQ_MARKUP; 88211195Ssam is->hy_retry = 0; 88311195Ssam /* 88413065Ssam * Fill in the host number 88511207Ssam * from the status buffer 88611195Ssam */ 88711207Ssam printf( 88811207Ssam "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 88911195Ssam ui->ui_unit, 89011195Ssam is->hy_stat.hyc_uaddr, 89111195Ssam PORTNUM(&is->hy_status), 89211207Ssam (is->hy_stat.hyc_atype[0]<<8) | 89311207Ssam is->hy_stat.hyc_atype[1], 89411195Ssam is->hy_stat.hyc_atype[2]); 89511195Ssam 89621775Skarels is->hy_host = 89711207Ssam (is->hy_stat.hyc_uaddr << 8) | 89811207Ssam PORTNUM(&is->hy_status); 89911195Ssam ifp->if_flags |= IFF_UP; 90011195Ssam #ifdef HYLOG 90111195Ssam hylog(HYL_UP, 0, (char *)0); 90211195Ssam #endif 90311195Ssam } else { 90411195Ssam is->hy_state = WAITING; 90511195Ssam is->hy_retry = 0; 90611195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0); 90711195Ssam } 90811195Ssam } 90911207Ssam break; 91011195Ssam } 91111195Ssam 91211195Ssam case STATSENT: 91312772Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status, 91411207Ssam sizeof (struct hy_status)); 91511195Ssam #ifdef DEBUG 91611207Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 91711207Ssam ui->ui_unit, is->hy_status.hys_gen_status, 91811207Ssam is->hy_status.hys_last_fcn, 91911207Ssam is->hy_status.hys_resp_trunk, 92011207Ssam is->hy_status.hys_status_trunk, 92111207Ssam is->hy_status.hys_recd_resp, 92211207Ssam is->hy_status.hys_error, 92311207Ssam is->hy_status.hys_caddr, 92411207Ssam is->hy_status.hys_pad); 92511195Ssam #endif 92611195Ssam is->hy_state = IDLE; 92711195Ssam #ifdef HYLOG 92811207Ssam hylog(HYL_STATUS, sizeof (struct hy_status), 92911207Ssam (char *)&is->hy_status); 93011195Ssam #endif 93111195Ssam #ifdef HYELOG 93211195Ssam { 93311195Ssam register int i; 93411195Ssam 93511195Ssam i = is->hy_status.hys_error; 93621128Skarels if (i > HYE_MAX) 93711195Ssam i = HYE_MAX; 93811195Ssam switch (is->hy_status.hys_last_fcn) { 93911195Ssam case HYF_XMITLOCMSG: 94011195Ssam i += HYE_MAX+1; /* fall through */ 94111195Ssam case HYF_XMITLSTDATA: 94211195Ssam i += HYE_MAX+1; /* fall through */ 94311195Ssam case HYF_XMITMSG: 94411195Ssam i += HYE_MAX+1; 94511195Ssam } 94611195Ssam hy_elog[i]++; 94711195Ssam } 94811195Ssam #endif 94911195Ssam break; 95011195Ssam 95111195Ssam case RSTATSENT: { 95211207Ssam register struct hy_stat *p = 95311207Ssam (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 95411195Ssam 95521128Skarels bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat)); 95611195Ssam #ifdef DEBUG 95721128Skarels 95821128Skarels printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n", 95911195Ssam ui->ui_unit, 96021128Skarels (is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2], 96121128Skarels (is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2], 96221128Skarels (is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2], 96321128Skarels (is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]); 96421128Skarels printD(" ret0 %d ret1 %d ret2 %d ret3 %d\n", 96521128Skarels (is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2], 96621128Skarels (is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2], 96721128Skarels (is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2], 96821128Skarels (is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]); 96921128Skarels printD(" cancel %d abort %d atype %x %x %x uaddr %x\n", 97021128Skarels (is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1], 97121128Skarels (is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1], 97211195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 97311195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 97411195Ssam #endif 97511195Ssam is->hy_state = IDLE; 97611195Ssam #ifdef HYLOG 97711207Ssam hylog(HYL_STATISTICS, sizeof (struct hy_stat), 97811207Ssam (char *)&is->hy_stat); 97911195Ssam #endif 98011195Ssam break; 98111195Ssam } 98211195Ssam 98311195Ssam case CLEARSENT: 98411195Ssam is->hy_state = IDLE; 98511195Ssam break; 98611195Ssam 98711195Ssam case ENDOPSENT: 98811195Ssam is->hy_state = IDLE; 98911195Ssam break; 99011195Ssam 99111195Ssam case RECVSENT: { 99221128Skarels register struct hym_hdr *hym; 99311207Ssam register unsigned len; 99411195Ssam 99511207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 99611207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 99713088Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 99821128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 99911207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 100011207Ssam if (len > MPSIZE) { 100111207Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n", 100213088Ssam ui->ui_unit, len); 100321128Skarels is->hy_state = IDLE; 100411195Ssam #ifdef DEBUG 100511207Ssam hy_debug_flag = 1; 100611207Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 100711207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 100811207Ssam addr->hyd_bar, addr->hyd_wcr); 100911195Ssam #endif 101011207Ssam } 101121128Skarels hym->hym_mplen = len; 101211195Ssam #ifdef DEBUG 101311207Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 101411207Ssam if (hy_debug_flag) 101521128Skarels hyprintdata((char *)hym, len + HYM_SWLEN); 101611195Ssam #endif 101721128Skarels if (hym->hym_ctl & H_ASSOC) { 101811207Ssam is->hy_state = RECVDATASENT; 101911207Ssam is->hy_retry = 0; 102011207Ssam hystart(ui, HYF_INPUTDATA, 102121128Skarels (int)(HYMTU + sizeof (struct hy_hdr) - len), 102221128Skarels (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len)); 102311207Ssam } else { 102421128Skarels hyrecvdata(ui, hym, (int)len + HYM_SWLEN); 102511207Ssam is->hy_state = IDLE; 102611195Ssam } 102711207Ssam break; 102811207Ssam } 102911195Ssam 103011195Ssam case RECVDATASENT: { 103121128Skarels register struct hym_hdr *hym; 103211207Ssam register unsigned len; 103311195Ssam 103411207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 103511207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 103613088Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 103721128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 103811207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 103911195Ssam #ifdef DEBUG 104011207Ssam printD("hy%d: recvd assoc data, len = %d, data = ", 104111207Ssam ui->ui_unit, len); 104211207Ssam if (hy_debug_flag) 104321128Skarels hyprintdata((char *)hym + hym->hym_mplen, len); 104411195Ssam #endif 104521128Skarels hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN)); 104611207Ssam is->hy_state = IDLE; 104711207Ssam break; 104811207Ssam } 104911195Ssam 105011195Ssam case XMITSENT: 105111207Ssam if (is->hy_flags & RQ_XASSOC) { 105213196Sroot register int len; 105311195Ssam 105411207Ssam is->hy_flags &= ~RQ_XASSOC; 105511207Ssam is->hy_state = XMITDATASENT; 105611207Ssam is->hy_retry = 0; 105711207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 105811207Ssam if (len > is->hy_olen) { 105911207Ssam printf( 106011207Ssam "hy%d: xmit error - len > hy_olen [%d > %d]\n", 106111207Ssam ui->ui_unit, len, is->hy_olen); 106211195Ssam #ifdef DEBUG 106311207Ssam hy_debug_flag = 1; 106411195Ssam #endif 106511195Ssam } 106611207Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 106721128Skarels is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len); 106811207Ssam break; 106911207Ssam } 107011207Ssam /* fall through to ... */ 107111195Ssam 107211195Ssam case XMITDATASENT: 107311207Ssam hyxmitdata(ui); 107411207Ssam is->hy_state = IDLE; 107511207Ssam break; 107611195Ssam 107711195Ssam case WAITING: /* wait for message complete or output requested */ 107811207Ssam if (HYS_RECVDATA(addr)) 107911195Ssam is->hy_state = IDLE; 108011195Ssam else { 108111195Ssam is->hy_state = CLEARSENT; 108211195Ssam is->hy_retry = 0; 108311195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0); 108411195Ssam } 108511195Ssam break; 108611195Ssam 108711195Ssam case MARKPORT: 108811195Ssam is->hy_state = STARTUP; 108921128Skarels if_down(&is->hy_if); 109011195Ssam is->hy_if.if_flags &= ~IFF_UP; 109111195Ssam goto endintr; 109211195Ssam 109311195Ssam default: 109411207Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 109511207Ssam ui->ui_unit, is->hy_state); 109611195Ssam panic("HYPERCHANNEL IN INVALID STATE"); 109711195Ssam /*NOTREACHED*/ 109811207Ssam } 109911195Ssam if (is->hy_state == IDLE) 110011195Ssam goto actloop; 110111195Ssam endintr: 110213088Ssam ; 110311195Ssam #ifdef DEBUG 110411207Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 110511207Ssam hy_state_names[is->hy_state]); 110611195Ssam #endif 110711207Ssam } 110811195Ssam 110921128Skarels struct sockproto hypproto = { PF_HYLINK }; 111021128Skarels struct sockaddr_in hypdst = { AF_HYLINK }; 111121128Skarels struct sockaddr_in hypsrc = { AF_HYLINK }; 111221128Skarels 111311195Ssam /* 111413088Ssam * Called from device interrupt when receiving data. 111511195Ssam * Examine packet to determine type. Decapsulate packet 111611195Ssam * based on type and pass to type specific higher-level 111711195Ssam * input routine. 111811195Ssam */ 111921128Skarels hyrecvdata(ui, hym, len) 112011195Ssam struct uba_device *ui; 112121128Skarels register struct hym_hdr *hym; 112211195Ssam int len; 112311195Ssam { 112411195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 112511195Ssam struct mbuf *m; 112611195Ssam register struct ifqueue *inq; 112711195Ssam 112811195Ssam is->hy_if.if_ipackets++; 112911195Ssam #ifdef DEBUG 113021128Skarels printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len); 113111195Ssam #endif 113211195Ssam #ifdef HYLOG 113311195Ssam { 113411195Ssam struct { 113511195Ssam short hlen; 113621128Skarels struct hym_hdr hhdr; 113711195Ssam } hh; 113811195Ssam hh.hlen = len; 113921128Skarels hh.hhdr = *hym; 114011195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh); 114111195Ssam } 114211195Ssam #endif 114311195Ssam if (len > HYMTU + MPSIZE || len == 0) 114411195Ssam return; /* sanity */ 114511195Ssam /* 114611195Ssam * Pull packet off interface. 114711195Ssam */ 114824797Skarels m = if_rubaget(&is->hy_ifuba, len, 0, &is->hy_if); 114911207Ssam if (m == NULL) 115011195Ssam return; 115111195Ssam 115221128Skarels /* 115321128Skarels * if normal or adapter loopback response packet believe hym_type, 115421128Skarels * otherwise, use the raw input queue cause it's a response from an 115521128Skarels * adapter command. 115621128Skarels */ 115721128Skarels if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff) 115821128Skarels goto rawlinkin; 115921128Skarels 116021128Skarels switch (hym->hym_type) { 116121128Skarels 116211195Ssam #ifdef INET 116311195Ssam case HYLINK_IP: 116411195Ssam schednetisr(NETISR_IP); 116511195Ssam inq = &ipintrq; 116611195Ssam break; 116711195Ssam #endif 116811195Ssam default: 116921128Skarels rawlinkin: 117021128Skarels { 117121128Skarels struct mbuf *m0; 117221128Skarels 117321128Skarels MGET(m0, M_DONTWAIT, MT_DATA); 117424797Skarels if (m0 == 0) { 117521128Skarels m_freem(m); 117621128Skarels return; 117721128Skarels } 117821128Skarels m0->m_off = MMINOFF; 117921128Skarels m0->m_len = sizeof(struct hym_hdr); 118021128Skarels m0->m_next = m; 118121128Skarels bcopy((caddr_t)hym, mtod(m0, caddr_t), sizeof(struct hym_hdr)); 118221128Skarels m = m0; 118321128Skarels hypproto.sp_protocol = 0; 118421775Skarels hypdst.sin_addr = is->hy_addr; 118521775Skarels hypsrc.sin_addr = is->hy_addr; 118621128Skarels raw_input(m, &hypproto, (struct sockaddr *)&hypsrc, 118721128Skarels (struct sockaddr *)&hypdst); 118821128Skarels return; 118921128Skarels } 119011195Ssam } 119111195Ssam if (IF_QFULL(inq)) { 119211195Ssam IF_DROP(inq); 119311195Ssam m_freem(m); 119411195Ssam } else 119511195Ssam IF_ENQUEUE(inq, m); 119611207Ssam } 119711195Ssam 119811195Ssam /* 119911207Ssam * Transmit done, release resources, bump counters. 120011195Ssam */ 120111195Ssam hyxmitdata(ui) 120211195Ssam struct uba_device *ui; 120311195Ssam { 120411195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 120511195Ssam 120611195Ssam is->hy_if.if_opackets++; 120711207Ssam if (is->hy_ifuba.ifu_xtofree) { 120811195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 120911195Ssam is->hy_ifuba.ifu_xtofree = 0; 121011195Ssam } 121111207Ssam } 121211195Ssam 121311195Ssam hycancel(ui) 121411195Ssam register struct uba_device *ui; 121511195Ssam { 121611195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 121711195Ssam 121811207Ssam if (is->hy_ifuba.ifu_xtofree) { 121911195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 122011195Ssam is->hy_ifuba.ifu_xtofree = 0; 122111195Ssam } 122221128Skarels #ifdef HYLOG 122321128Skarels hylog(HYL_CANCEL, 0, (char *)0); 122421128Skarels #endif 122511195Ssam #ifdef DEBUG 122611207Ssam if (hy_nodebug & 1) 122711207Ssam hy_debug_flag = 1; 122811195Ssam #endif 122911195Ssam #ifdef DEBUG 123011195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 123111195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 123211195Ssam is->hy_savedcount, is->hy_savedaddr); 123321128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n", 123421128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry); 123511207Ssam printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 123611207Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 123711207Ssam is->hy_savedcmd); 123811195Ssam #endif 123911195Ssam is->hy_state = IDLE; 124011195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 124111195Ssam hyact(ui); 124211207Ssam } 124311195Ssam 124411195Ssam #ifdef DEBUG 124511195Ssam hyprintdata(cp, len) 124611195Ssam register char *cp; 124711195Ssam register int len; 124811195Ssam { 124911195Ssam register int count = 16; 125011195Ssam register char *fmt; 125111195Ssam static char regfmt[] = "\n\t %x"; 125211195Ssam 125311195Ssam fmt = ®fmt[2]; 125411195Ssam while (--len >= 0) { 125511195Ssam printL(fmt, *cp++ & 0xff); 125611195Ssam fmt = ®fmt[2]; 125711195Ssam if (--count <= 0) { 125811195Ssam fmt = ®fmt[0]; 125911195Ssam count = 16; 126011195Ssam } 126111195Ssam } 126211195Ssam printL("\n"); 126311195Ssam } 126411195Ssam #endif 126511195Ssam 126611195Ssam hywatch(unit) 126713088Ssam int unit; 126811195Ssam { 126911195Ssam register struct hy_softc *is = &hy_softc[unit]; 127011195Ssam register struct uba_device *ui = hyinfo[unit]; 127111195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 127211195Ssam int s; 127311195Ssam 127411195Ssam s = splimp(); 127511195Ssam #ifdef PI13 127611195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 127711195Ssam addr->hyd_csr |= S_POWEROFF; 127811195Ssam DELAY(100); 127911195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) { 128021128Skarels printf("hy%d: Adapter Power Restored (hywatch)\n", unit); 128111195Ssam is->hy_state = IDLE; 128211207Ssam is->hy_flags |= 128311207Ssam (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 128411195Ssam hyact(ui); 128511195Ssam } 128611195Ssam } 128711195Ssam #endif 128821128Skarels if (++is->hy_ntime >= 2 && is->hy_state != WAITING && 128921128Skarels is->hy_state != STARTUP && is->hy_state != IDLE) { 129021128Skarels #ifdef HYLOG 129121128Skarels printf("hy%d: watchdog timer expired in state \"%s\"\n", unit, 129221128Skarels hy_state_names[is->hy_state]); 129321128Skarels #else 129421128Skarels printf("hy%d: watchdog timer expired in state %d\n", unit, 129521128Skarels is->hy_state); 129621128Skarels #endif 129721128Skarels printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit, 129821128Skarels is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS); 129921128Skarels hycancel(ui); 130021128Skarels } 130111195Ssam splx(s); 130221128Skarels is->hy_if.if_timer = SCANINTERVAL; 130311195Ssam } 130411195Ssam 130511195Ssam #ifdef HYLOG 130611195Ssam hylog(code, len, ptr) 130713088Ssam int code, len; 130811195Ssam char *ptr; 130911195Ssam { 131011195Ssam register unsigned char *p; 131111195Ssam int s; 131211195Ssam 131311195Ssam s = splimp(); 131411195Ssam if (hy_log.hyl_self != &hy_log) { 131511195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 131611195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 131711195Ssam hy_log.hyl_self = &hy_log; 131821128Skarels hy_log.hyl_enable = HYL_CONTINUOUS; 131921128Skarels hy_log.hyl_onerr = HYL_CONTINUOUS; 132021128Skarels hy_log.hyl_count = 0; 132121128Skarels hy_log.hyl_icount = 16; 132221128Skarels hy_log.hyl_filter = 0xffff; /* enable all */ 132311195Ssam } 132421128Skarels if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0) 132511207Ssam goto out; 132611195Ssam p = hy_log.hyl_ptr; 132721128Skarels if (p + len + 3 >= hy_log.hyl_eptr) { 132812772Ssam bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 132911195Ssam p = &hy_log.hyl_buf[0]; 133021128Skarels if (hy_log.hyl_enable != HYL_CONTINUOUS) { 133121128Skarels hy_log.hyl_enable = HYL_DISABLED; 133211195Ssam goto out; 133311195Ssam } 133411195Ssam } 133511195Ssam *p++ = code; 133611195Ssam *p++ = len; 133713088Ssam bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len); 133821128Skarels if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) { 133921128Skarels *p++ = '\0'; 134021128Skarels hy_log.hyl_enable = HYL_DISABLED; 134121128Skarels hy_log.hyl_count = hy_log.hyl_icount; 134221128Skarels } 134326285Skarels p += len; 134421128Skarels if (hy_log.hyl_wait != 0) { /* wakeup HYGETLOG if wanted */ 134526285Skarels if (hy_log.hyl_wait <= p - hy_log.hyl_ptr) { 134621128Skarels wakeup((caddr_t)&hy_log); 134721128Skarels hy_log.hyl_wait = 0; 134826285Skarels } else 134926285Skarels hy_log.hyl_wait -= p - hy_log.hyl_ptr; 135021128Skarels } 135126285Skarels hy_log.hyl_ptr = p; 135211195Ssam out: 135311195Ssam splx(s); 135411195Ssam } 135511195Ssam #endif 135611195Ssam 135712772Ssam /*ARGSUSED*/ 135813058Ssam hyioctl(ifp, cmd, data) 135913058Ssam register struct ifnet *ifp; 136011207Ssam int cmd; 136111207Ssam caddr_t data; 136211195Ssam { 136321775Skarels struct ifaddr *ifa = (struct ifaddr *) data; 136421128Skarels struct hyrsetget *sg = (struct hyrsetget *)data; 136521128Skarels #if defined(HYLOG) || defined(HYELOG) 136621128Skarels struct hylsetget *sgl = (struct hylsetget *)data; 136721128Skarels #endif 136821128Skarels struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit]; 136911207Ssam int s = splimp(), error = 0; 137021128Skarels #ifdef HYLOG 137121128Skarels struct hy_softc *is = &hy_softc[ifp->if_unit]; 137221128Skarels struct { 137321128Skarels u_char hstate; 137421128Skarels u_char hflags; 137521128Skarels u_short iflags; 137621128Skarels int hcmd; 137721128Skarels int herror; 137821128Skarels u_long haddr; 137921128Skarels u_long hmisc; 138021128Skarels } hil; 138111195Ssam 138221128Skarels hil.hmisc = -1; 138321128Skarels hil.hstate = is->hy_state; 138421128Skarels hil.hflags = is->hy_flags; 138521128Skarels hil.hcmd = cmd; 138621128Skarels #endif 138721128Skarels 138811195Ssam switch(cmd) { 138911195Ssam 139013065Ssam case SIOCSIFADDR: 139124797Skarels if (ifa->ifa_addr.sa_family != AF_INET) 139221128Skarels return(EINVAL); 139321775Skarels if ((ifp->if_flags & IFF_RUNNING) == 0) 139421775Skarels hyinit(ifp->if_unit); 139521775Skarels hy_softc[ifp->if_unit].hy_addr = IA_SIN(ifa)->sin_addr; 139621128Skarels #ifdef HYLOG 139721775Skarels hil.haddr = is->hy_addr.s_addr; 139821128Skarels #endif 139913065Ssam break; 140013065Ssam 140111195Ssam case HYSETROUTE: 140211207Ssam if (!suser()) { 140311207Ssam error = EPERM; 140421128Skarels goto out; 140511195Ssam } 140621128Skarels 140721128Skarels if (sg->hyrsg_len != sizeof(struct hy_route)) { 140821128Skarels error = EINVAL; 140921128Skarels goto out; 141021128Skarels } 141121128Skarels if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) { 141221128Skarels r->hyr_lasttime = 0; /* disable further routing if trouble */ 141321128Skarels error = EFAULT; 141421128Skarels goto out; 141521128Skarels } 141621128Skarels r->hyr_lasttime = time.tv_sec; 141721128Skarels #ifdef HYLOG 141821128Skarels hil.hmisc = r->hyr_lasttime; 141921128Skarels #endif 142011195Ssam break; 142111195Ssam 142211195Ssam case HYGETROUTE: 142321128Skarels if (sg->hyrsg_len < sizeof(struct hy_route)) { 142421128Skarels error = EINVAL; 142521128Skarels goto out; 142621128Skarels } 142721128Skarels if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) { 142821128Skarels error = EFAULT; 142921128Skarels goto out; 143021128Skarels } 143111195Ssam break; 143211195Ssam 143321128Skarels #ifdef HYELOG 143421128Skarels case HYGETELOG: 143521128Skarels if (sgl->hylsg_len < sizeof(hy_elog)) { 143621128Skarels error = EINVAL; 143721128Skarels goto out; 143821128Skarels } 143921128Skarels if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) { 144021128Skarels error = EFAULT; 144121128Skarels goto out; 144221128Skarels } 144321128Skarels if (sgl->hylsg_cmd) { 144421128Skarels if (!suser()) { 144521128Skarels error = EPERM; 144621128Skarels goto out; 144721128Skarels } 144821128Skarels bzero((caddr_t)hy_elog, sizeof(hy_elog)); 144921128Skarels } 145021128Skarels break; 145121128Skarels #endif 145221128Skarels 145321128Skarels #ifdef HYLOG 145421128Skarels case HYSETLOG: 145521128Skarels if (!suser()) { 145621128Skarels error = EPERM; 145721128Skarels goto out; 145821128Skarels } 145921128Skarels hy_log.hyl_enable = HYL_DISABLED; 146021128Skarels hylog(HYL_NOP, 0, (char *)0); /* force log init */ 146121128Skarels hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f; 146221128Skarels hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f; 146321128Skarels hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff; 146421128Skarels hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len; 146521128Skarels wakeup((caddr_t)&hy_log); /* wakeup sleeping HYGETLOG */ 146621128Skarels break; 146721128Skarels 146821128Skarels case HYGETLOG: 146921128Skarels if (sgl->hylsg_len < sizeof(hy_log)) { 147021128Skarels error = EINVAL; 147121128Skarels goto out; 147221128Skarels } 147321128Skarels if (sgl->hylsg_cmd != 0) { 147421128Skarels if (hy_log.hyl_wait) { 147521128Skarels error = EBUSY; 147621128Skarels goto out; 147721128Skarels } 147821128Skarels hy_log.hyl_wait = sgl->hylsg_cmd; 147926392Skarels sleep((caddr_t)&hy_log, PZERO - 1); 148021128Skarels } 148121128Skarels 148221128Skarels if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) { 148321128Skarels error = EFAULT; 148421128Skarels goto out; 148521128Skarels } 148621128Skarels break; 148721128Skarels #endif 148821128Skarels 148911195Ssam default: 149013058Ssam error = EINVAL; 149111195Ssam break; 149211195Ssam } 149321128Skarels out: 149421128Skarels #ifdef HYLOG 149521128Skarels hil.herror = error; 149621128Skarels hil.iflags = ifp->if_flags; 149721775Skarels hil.haddr = is->hy_addr.s_addr; 149821128Skarels hylog(HYL_IOCTL, sizeof(hil), (char *)&hil); 149921128Skarels #endif 150011195Ssam splx(s); 150111207Ssam return (error); 150211195Ssam } 150311207Ssam #endif 1504