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 *
844559Sbostic * %sccs.include.redist.c%
935322Sbostic *
10*45801Sbostic * @(#)if_hy.c 7.7 (Berkeley) 12/16/90
1123294Smckusick */
1211195Ssam
1321128Skarels /*
1421128Skarels * 4.2 BSD Unix Kernel - Vax Network Interface Support
1521128Skarels *
1621128Skarels * $Header: if_hy.c,v 10.1 84/07/22 21:02:56 steveg Exp $
1721128Skarels * $Locker: $
1821128Skarels *
1921128Skarels * Modifications from Berkeley 4.2 BSD
2021128Skarels * Copyright (c) 1983, Tektronix Inc.
2121128Skarels * All Rights Reserved
2221128Skarels *
2321128Skarels * $Log: if_hy.c,v $
2421128Skarels * Revision 10.1 84/07/22 21:02:56 steveg
2521128Skarels * define PI13 (moved from if_hyreg.h, somehow got dropped in the process)
2621128Skarels * rework hywatch to check for power fails first
2721128Skarels *
2821128Skarels * Revision 10.0 84/06/30 19:54:27 steveg
2921128Skarels * Big Build
3021128Skarels *
3121128Skarels * Revision 3.17 84/06/20 19:20:28 steveg
3221128Skarels * increment hy_ntime in hywatch
3321128Skarels * print out state name, csr, last command, and hy_flags when watchdog timer
3421128Skarels * expires
3521128Skarels *
3621128Skarels * Revision 3.16 84/06/20 19:09:34 steveg
3721128Skarels * turn on continuous logging by default
3821128Skarels *
3921128Skarels * Revision 3.15 84/05/30 22:19:09 steveg
4021128Skarels * changes to reflect new layout ot statistics data
4121128Skarels *
4221128Skarels * Revision 3.14 84/05/30 19:25:15 steveg
4321128Skarels * move driver states to if_hy.h so log printing programs can use them
4421128Skarels *
4521128Skarels * Revision 3.13 84/05/30 17:13:26 steveg
4621128Skarels * make it compile
4721128Skarels *
4821128Skarels * Revision 3.12 84/05/30 13:46:16 steveg
4921128Skarels * rework logging
5021128Skarels *
5121128Skarels * Revision 3.11 84/05/18 19:35:02 steveg
5221128Skarels * clear IFF_RUNNING and IFF_UP on unibus reset to force resource allocation
5321128Skarels * by the init routine
5421128Skarels *
5521128Skarels * Revision 3.10 84/05/04 12:14:44 steveg
5621128Skarels * more rework to make it actually work under 4.2
5721128Skarels *
5821128Skarels * Revision 3.9 84/05/01 23:34:52 steveg
5921128Skarels * fix typo so it compiles (unit -> ui->ui_unit)
6021128Skarels *
6121128Skarels * Revision 3.8 84/05/01 23:18:30 steveg
6221128Skarels * changes after talking with rickk
6321128Skarels * - check power off more closely
6421128Skarels * - support remote loopback through A710 adapters
6521128Skarels * - IMPLINK -> HYLINK
6621128Skarels * - return EHOSTUNREACH on hyroute failure
6721128Skarels * - bump if_collisions on abnormal interrupts that aren't input or output
6821128Skarels *
6921128Skarels *
7021128Skarels */
7121128Skarels
7221128Skarels
7311195Ssam #include "hy.h"
7411195Ssam #if NHY > 0
7511195Ssam
7611195Ssam /*
7711195Ssam * Network Systems Copropration Hyperchanel interface
7811195Ssam */
79*45801Sbostic #include "../include/pte.h"
8011195Ssam
81*45801Sbostic #include "sys/param.h"
82*45801Sbostic #include "sys/systm.h"
83*45801Sbostic #include "sys/mbuf.h"
84*45801Sbostic #include "sys/buf.h"
85*45801Sbostic #include "sys/protosw.h"
86*45801Sbostic #include "sys/socket.h"
87*45801Sbostic #include "sys/vmmac.h"
88*45801Sbostic #include "sys/errno.h"
89*45801Sbostic #include "sys/time.h"
90*45801Sbostic #include "sys/kernel.h"
91*45801Sbostic #include "sys/ioctl.h"
9213088Ssam
93*45801Sbostic #include "net/if.h"
94*45801Sbostic #include "net/netisr.h"
95*45801Sbostic #include "net/route.h"
9624797Skarels
9724797Skarels #ifdef INET
98*45801Sbostic #include "netinet/in.h"
99*45801Sbostic #include "netinet/in_systm.h"
100*45801Sbostic #include "netinet/in_var.h"
101*45801Sbostic #include "netinet/ip.h"
10224797Skarels #endif
10311195Ssam
104*45801Sbostic #include "../include/cpu.h"
105*45801Sbostic #include "../include/mtpr.h"
106*45801Sbostic #include "../uba/ubareg.h"
107*45801Sbostic #include "../uba/ubavar.h"
10811195Ssam
10921128Skarels /*
11021128Skarels * configuration specific paramters
11121128Skarels * - change as appropriate for particular installaions
11221128Skarels */
11321128Skarels #define HYROUTE
11421128Skarels #define HYELOG
11521128Skarels #define HYLOG
11621128Skarels #define HYMTU 1100
11721128Skarels #define PI13
11811195Ssam
11921128Skarels #ifdef DEBUG
12021128Skarels #define HYLOG
12121128Skarels #endif
12221128Skarels
12321775Skarels #include "if_hy.h"
12421775Skarels #include "if_hyreg.h"
12521775Skarels #include "if_uba.h"
12621128Skarels
12713058Ssam int hyprobe(), hyattach(), hyinit(), hyioctl();
12813058Ssam int hyoutput(), hyreset(), hywatch();
12911195Ssam struct uba_device *hyinfo[NHY];
13011195Ssam u_short hystd[] = { 0772410, 0 };
13111195Ssam struct uba_driver hydriver =
13211195Ssam { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo };
13311195Ssam
13411195Ssam /*
13511195Ssam * Hyperchannel software status per interface.
13611195Ssam *
13711195Ssam * Each interface is referenced by a network interface structure,
13811195Ssam * hy_if, which the routing code uses to locate the interface.
13911195Ssam * This structure contains the output queue for the interface, its address, ...
14011195Ssam * We also have, for each interface, a UBA interface structure, which
14111195Ssam * contains information about the UNIBUS resources held by the interface:
14211195Ssam * map registers, buffered data paths, etc. Information is cached in this
14311195Ssam * structure for use by the if_uba.c routines in running the interface
14411195Ssam * efficiently.
14511195Ssam */
14611195Ssam struct hy_softc {
14711195Ssam struct ifnet hy_if; /* network-visible interface */
14811195Ssam struct ifuba hy_ifuba; /* UNIBUS resources */
14911207Ssam short hy_flags; /* flags */
15011207Ssam short hy_state; /* driver state */
15121775Skarels u_short hy_host; /* local host number */
15221775Skarels struct in_addr hy_addr; /* internet address */
15311195Ssam int hy_olen; /* packet length on output */
15411195Ssam int hy_lastwcr; /* last command's word count */
15511195Ssam short hy_savedstate; /* saved for reissue after status */
15611195Ssam short hy_savedcmd; /* saved command for reissue */
15711195Ssam int hy_savedcount; /* saved byte count for reissue */
15811195Ssam int hy_savedaddr; /* saved unibus address for reissue */
15911195Ssam int hy_ntime; /* number of timeouts since last cmd */
16011195Ssam int hy_retry; /* retry counter */
16111207Ssam struct hy_stat hy_stat; /* statistics */
16211207Ssam struct hy_status hy_status; /* status */
16311195Ssam } hy_softc[NHY];
16411195Ssam
16511195Ssam #ifdef HYELOG
16621128Skarels u_long hy_elog[HYE_SIZE];
16711195Ssam #endif
16811195Ssam
16921128Skarels #ifdef HYLOG
17021128Skarels struct hy_log hy_log;
17121128Skarels #endif
17221128Skarels
17321128Skarels #ifdef HYROUTE
17421128Skarels struct hy_route hy_route[NHY];
17521128Skarels #endif
17621128Skarels
17711195Ssam #ifdef DEBUG
17821128Skarels #define printL printf
17921128Skarels #define printD if (hy_debug_flag) printf
18011195Ssam int hy_debug_flag = 0;
18111195Ssam /*
18211195Ssam * hy_nodebug bit 0x01 set hy_debug_flag on hycancel
18311195Ssam * hy_nodebug bit 0x02 set hy_debug_flag on command reissue
18411195Ssam * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt
18511195Ssam */
18611195Ssam int hy_nodebug = 0x0;
18711195Ssam #endif
18811195Ssam
18911195Ssam #define SCANINTERVAL 10 /* seconds */
19011195Ssam #define MAXINTERVAL 20 /* seconds (max action) */
19111195Ssam
19211195Ssam /*
19311195Ssam * Cause a device interrupt. This code uses a buffer starting at
19411195Ssam * location zero on the unibus (which is already mapped by the
19511195Ssam * autoconfigure code in the kernel).
19611195Ssam */
hyprobe(reg)19711195Ssam hyprobe(reg)
19811195Ssam caddr_t reg;
19911195Ssam {
20011195Ssam register int br, cvec; /* r11, r10 value-result */
20111195Ssam register struct hydevice *addr = (struct hydevice *) reg;
20211195Ssam
20311195Ssam #ifdef lint
20411195Ssam br = 0; cvec = br; br = cvec;
20511195Ssam hyint(0);
20611195Ssam #endif
20711195Ssam /*
20811195Ssam * request adapter status to a buffer starting at unibus location 0
20911195Ssam */
21011195Ssam addr->hyd_bar = 0;
21111195Ssam addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1);
21211195Ssam addr->hyd_dbuf = HYF_STATUS;
21311195Ssam #ifdef PI13
21411195Ssam addr->hyd_csr |= S_GO | S_IE | S_IATTN;
21511195Ssam #else
21611195Ssam addr->hyd_csr |= S_GO | S_IE;
21711195Ssam #endif
21811195Ssam DELAY(10000);
21911195Ssam #ifdef PI13
22011195Ssam addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */
22111195Ssam #endif
22211195Ssam addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */
22321128Skarels return(sizeof(struct hydevice));
22411207Ssam }
22511195Ssam
22611195Ssam /*
22711195Ssam * Interface exists: make available by filling in network interface
22811195Ssam * record. System will initialize the interface when it is ready
22911195Ssam * to accept packets.
23011195Ssam */
23111195Ssam hyattach(ui)
23211195Ssam struct uba_device *ui;
23311195Ssam {
23411195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit];
23511195Ssam register struct ifnet *ifp = &is->hy_if;
23611195Ssam
23711195Ssam ifp->if_unit = ui->ui_unit;
23811195Ssam ifp->if_name = "hy";
23911195Ssam ifp->if_mtu = HYMTU;
24011195Ssam is->hy_state = STARTUP; /* don't allow state transitions yet */
24111195Ssam ifp->if_init = hyinit;
24213058Ssam ifp->if_ioctl = hyioctl;
24311195Ssam ifp->if_output = hyoutput;
24411207Ssam ifp->if_reset = hyreset;
24511195Ssam ifp->if_watchdog = hywatch;
24611195Ssam ifp->if_timer = SCANINTERVAL;
24711195Ssam is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
24811207Ssam #ifdef notdef
24911195Ssam is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
25011195Ssam #endif
25111195Ssam if_attach(ifp);
25211207Ssam }
25311195Ssam
25411195Ssam /*
25511195Ssam * Reset of interface after UNIBUS reset.
25611195Ssam * If interface is on specified uba, reset its state.
25711195Ssam */
hyreset(unit,uban)25811195Ssam hyreset(unit, uban)
25911195Ssam int unit, uban;
26011195Ssam {
26121128Skarels register struct uba_device *ui;
26221128Skarels register struct hy_softc *is;
26311195Ssam
26421128Skarels if (unit >= NHY || (ui = hyinfo[unit]) == 0 || ui->ui_alive == 0 ||
26511207Ssam ui->ui_ubanum != uban)
26611195Ssam return;
26711195Ssam printf(" hy%d", unit);
26821128Skarels is = &hy_softc[unit]; /* force unibus resource allocation */
26921128Skarels is->hy_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
27011195Ssam hyinit(unit);
27111207Ssam }
27211195Ssam
27311195Ssam /*
27411195Ssam * Initialization of interface; clear recorded pending
27511195Ssam * operations, and reinitialize UNIBUS usage.
27611195Ssam */
hyinit(unit)27711195Ssam hyinit(unit)
27811195Ssam int unit;
27911195Ssam {
28011195Ssam register struct hy_softc *is = &hy_softc[unit];
28111195Ssam register struct uba_device *ui = hyinfo[unit];
28221128Skarels register struct mbuf *m;
28311195Ssam int s;
28411195Ssam
28521775Skarels if (is->hy_if.if_addrlist == 0) /* address still unknown */
28613065Ssam return;
28721128Skarels if (is->hy_if.if_flags & IFF_RUNNING) /* just reset the device */
28821128Skarels goto justreset;
28911195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
29021128Skarels sizeof (struct hym_hdr), (int)btoc(HYMTU)) == 0) {
29111195Ssam #ifdef DEBUG
29211207Ssam if (hy_nodebug & 4)
29311207Ssam hy_debug_flag = 1;
29411195Ssam #endif
29511195Ssam printf("hy%d: can't initialize\n", unit);
29611195Ssam is->hy_if.if_flags &= ~IFF_UP;
29711195Ssam return;
29811195Ssam }
29913088Ssam is->hy_if.if_flags |= IFF_RUNNING;
30021128Skarels
30121128Skarels justreset:
30211195Ssam /*
30321128Skarels * remove any left over outgoing messages, reset the hardware and
30421128Skarels * start the state machine
30511195Ssam */
30611195Ssam s = splimp();
30721128Skarels #ifdef HYLOG
30821128Skarels hylog(HYL_RESET, 0, (char *)0);
30921128Skarels #endif
31011195Ssam is->hy_state = IDLE;
31111195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
31211195Ssam is->hy_retry = 0;
31321128Skarels for(;;) {
31421128Skarels IF_DEQUEUE(&is->hy_if.if_snd, m);
31521128Skarels if (m != NULL)
31621128Skarels m_freem(m);
31721128Skarels else
31821128Skarels break;
31921128Skarels }
32021128Skarels hycancel(ui); /* also bumps the state machine */
32111195Ssam splx(s);
32211207Ssam }
32311195Ssam
32411195Ssam /*
32511207Ssam * Issue a command to the adapter
32611195Ssam */
32711195Ssam hystart(ui, cmd, count, ubaddr)
32811195Ssam struct uba_device *ui;
32911207Ssam int cmd, count, ubaddr;
33011195Ssam {
33111195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit];
33211195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
33311195Ssam
33411195Ssam #ifdef DEBUG
33511207Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
33611207Ssam ui->ui_unit, cmd, count, ubaddr);
33711195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
33811207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
33911207Ssam addr->hyd_wcr);
34011195Ssam #endif
34111207Ssam if (((is->hy_flags & RQ_REISSUE) == 0) &&
34211207Ssam (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
34311195Ssam is->hy_savedstate = is->hy_state;
34411195Ssam is->hy_savedcmd = cmd;
34511195Ssam is->hy_savedcount = count;
34611195Ssam is->hy_savedaddr = ubaddr;
34711195Ssam }
34821128Skarels #ifdef PI13
34921128Skarels if (addr->hyd_csr & S_POWEROFF) {
35021128Skarels printf("hy%d: \"Soft\" Adapter Power Failure (hystart)\n", ui->ui_unit);
35121128Skarels addr->hyd_csr |= S_POWEROFF;
35221128Skarels DELAY(100);
35321128Skarels if (addr->hyd_csr & S_POWEROFF) {
35421128Skarels printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hystart)\n", ui->ui_unit);
35521128Skarels if_down(&is->hy_if);
35621128Skarels is->hy_if.if_flags &= ~IFF_UP;
35721128Skarels is->hy_state = STARTUP;
35821128Skarels } else {
35921128Skarels printf("hy%d: Adapter Power Restored (hystart)\n", ui->ui_unit);
36021128Skarels }
36121128Skarels return;
36221128Skarels }
36321128Skarels #endif
36411195Ssam addr->hyd_bar = ubaddr & 0xffff;
36511207Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);
36611195Ssam addr->hyd_dbuf = cmd;
36711195Ssam #ifdef PI13
36811195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN;
36911195Ssam #else
37011195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE;
37111195Ssam #endif
37211195Ssam #ifdef DEBUG
37311195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
37411207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
37511207Ssam addr->hyd_wcr);
37611195Ssam #endif
37711195Ssam #ifdef HYLOG
37811195Ssam {
37911195Ssam struct {
38011207Ssam u_char hcmd;
38111207Ssam u_char hstate;
38211207Ssam short hcount;
38311195Ssam } hcl;
38411195Ssam
38511195Ssam hcl.hcmd = cmd;
38611195Ssam hcl.hstate = is->hy_state;
38711195Ssam hcl.hcount = count;
38811195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl);
38911195Ssam }
39011195Ssam #endif
39111195Ssam is->hy_ntime = 0;
39211207Ssam }
39311195Ssam
39411195Ssam int hyint_active = 0; /* set during hy interrupt */
39511195Ssam /*
39611207Ssam * Hyperchannel interface interrupt.
39711195Ssam *
39811195Ssam * An interrupt can occur for many reasons. Examine the status of
39911195Ssam * the hyperchannel status bits to determine what to do next.
40011195Ssam *
40111195Ssam * If input error just drop packet.
40211195Ssam * Otherwise purge input buffered data path and examine
40311195Ssam * packet to determine type. Othewise decapsulate
40411195Ssam * packet based on type and pass to type specific higher-level
40511195Ssam * input routine.
40611195Ssam */
hyint(unit)40711195Ssam hyint(unit)
40811195Ssam int unit;
40911195Ssam {
41011195Ssam register struct hy_softc *is = &hy_softc[unit];
41111195Ssam register struct uba_device *ui = hyinfo[unit];
41211207Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
41311195Ssam
41411207Ssam if (hyint_active)
41511195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT");
41611195Ssam hyint_active++;
41711195Ssam #ifdef DEBUG
41811195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
41911195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
42011195Ssam #endif
42111195Ssam #ifdef HYLOG
42211195Ssam logit:
42311195Ssam {
42411195Ssam struct {
42511207Ssam u_char hstate;
42611207Ssam u_char hflags;
42711207Ssam short hcsr;
42811207Ssam short hwcr;
42911195Ssam } hil;
43011195Ssam hil.hstate = is->hy_state;
43111195Ssam hil.hflags = is->hy_flags;
43211195Ssam hil.hcsr = addr->hyd_csr;
43311195Ssam hil.hwcr = addr->hyd_wcr;
43411195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil);
43511195Ssam }
43611195Ssam #endif
43711207Ssam if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
43811195Ssam /*
43911207Ssam * Error bit set, some sort of error in the interface.
44011195Ssam *
44111207Ssam * The adapter sets attn on command completion so that's not
44211207Ssam * a real error even though the interface considers it one.
44311195Ssam */
44411195Ssam #ifdef DEBUG
44511207Ssam if (hy_nodebug & 4)
44611207Ssam hy_debug_flag = 1;
44711195Ssam #endif
44811207Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n",
44911207Ssam addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
45011207Ssam addr->hyd_wcr);
45111207Ssam if (addr->hyd_csr & S_NEX) {
45211195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit);
45311195Ssam #ifdef PI13
45411195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */
45511195Ssam #else
45611195Ssam addr->hyd_csr &= ~S_NEX;
45711195Ssam #endif
45811195Ssam hycancel(ui);
45911195Ssam #ifdef PI13
46011207Ssam } else if (addr->hyd_csr & S_POWEROFF) {
46121128Skarels printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit);
46211195Ssam addr->hyd_csr |= S_POWEROFF;
46311195Ssam DELAY(100);
46411207Ssam if (addr->hyd_csr & S_POWEROFF) {
46521128Skarels printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit);
46611195Ssam if_down(&is->hy_if);
46721128Skarels is->hy_if.if_flags &= ~IFF_UP;
46811195Ssam is->hy_state = STARTUP;
46921128Skarels } else {
47021128Skarels printf("hy%d: Adapter Power Restored (hyint)\n", unit);
47111195Ssam }
47211195Ssam #endif
47311195Ssam } else {
47411195Ssam printf("hy%d: BAR overflow\n", unit);
47511195Ssam hycancel(ui);
47611195Ssam }
47711207Ssam } else if (HYS_NORMAL(addr)) {
47811195Ssam /*
47911207Ssam * Normal interrupt, bump state machine unless in state
48011195Ssam * waiting and no data present (assumed to be word count
48111207Ssam * zero interrupt or other hardware botch).
48211195Ssam */
48311207Ssam if (is->hy_state != WAITING || HYS_RECVDATA(addr))
48411195Ssam hyact(ui);
48511207Ssam } else if (HYS_ABNORMAL(addr)) {
48611195Ssam /*
48711207Ssam * Abnormal termination.
48811195Ssam * bump error counts, retry the last function
48911195Ssam * 'MAXRETRY' times before kicking the bucket.
49011195Ssam *
49111207Ssam * Don't reissue the cmd if in certain states, abnormal
49211207Ssam * on a reissued cmd or max retry exceeded.
49311195Ssam */
49411195Ssam #ifdef HYLOG
49511195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) {
49611195Ssam hy_log.hyl_enable = hy_log.hyl_onerr;
49711195Ssam goto logit;
49811195Ssam }
49911195Ssam #endif
50011195Ssam #ifdef DEBUG
50111207Ssam if (hy_nodebug & 4)
50211207Ssam hy_debug_flag = 1;
50311195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
50411195Ssam unit, hy_state_names[is->hy_state], is->hy_state);
50521128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
50621128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry);
50711207Ssam printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
50811207Ssam is->hy_savedstate, is->hy_savedcount,
50911207Ssam is->hy_savedaddr, is->hy_savedcmd);
51011195Ssam #endif
51111195Ssam #ifdef PI13
51211195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */
51311195Ssam #endif
51411207Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT)
51511195Ssam is->hy_if.if_oerrors++;
51621128Skarels else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT)
51711195Ssam is->hy_if.if_ierrors++;
51821128Skarels else
51921128Skarels is->hy_if.if_collisions++; /* other errors */
52011195Ssam if (is->hy_state == XMITDATASENT ||
52111195Ssam is->hy_state == RECVSENT ||
52211195Ssam is->hy_state == RECVDATASENT ||
52311207Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY)
52411195Ssam hycancel(ui);
52511207Ssam else {
52611195Ssam #ifdef DEBUG
52711207Ssam if (hy_nodebug & 2)
52811207Ssam hy_debug_flag = 1;
52911195Ssam #endif
53011195Ssam is->hy_retry++;
53111195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE;
53211195Ssam is->hy_state = IDLE;
53311195Ssam hyact(ui);
53411195Ssam }
53511195Ssam } else {
53611195Ssam /*
53711195Ssam * Interrupt is neither normal, abnormal, or interface error.
53811195Ssam * Ignore it. It's either stacked or a word count 0.
53911195Ssam */
54011195Ssam #ifdef HYLOG
54111195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) {
54211195Ssam hy_log.hyl_enable = hy_log.hyl_onerr;
54311195Ssam goto logit;
54411195Ssam }
54511195Ssam #endif
54611195Ssam #ifdef DEBUG
54711195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit);
54811195Ssam #endif
54911195Ssam }
55011195Ssam #ifdef DEBUG
55111195Ssam printD("hy%d: hyint exit\n\n", unit);
55211195Ssam #endif
55311195Ssam hyint_active = 0;
55411195Ssam
55511207Ssam }
55611195Ssam
55721128Skarels int hyoutprint = 0;
55821128Skarels
55911195Ssam /*
56011195Ssam * Encapsulate a packet of type family for the local net.
56111195Ssam */
56211195Ssam hyoutput(ifp, m0, dst)
56311195Ssam struct ifnet *ifp;
56411195Ssam struct mbuf *m0;
56511195Ssam struct sockaddr *dst;
56611195Ssam {
56711195Ssam register struct hym_hdr *hym;
56811195Ssam register struct mbuf *m;
56921128Skarels register char *mp;
57021128Skarels int dlen; /* packet size, incl hardware header, but not sw header */
57111195Ssam int error = 0;
57211195Ssam int s;
57311195Ssam
57421128Skarels /*
57521128Skarels * Calculate packet length for later deciding whether it will fit
57621128Skarels * in a message proper or we also need associated data.
57721128Skarels */
57811195Ssam dlen = 0;
57911195Ssam for (m = m0; m; m = m->m_next)
58011195Ssam dlen += m->m_len;
58111195Ssam m = m0;
58221128Skarels if (dst->sa_family == AF_HYLINK) { /* don't add header */
58321128Skarels dlen -= HYM_SWLEN;
58421128Skarels goto headerexists;
58521128Skarels }
58621128Skarels
58721128Skarels /*
58821128Skarels * Add the software and hardware hyperchannel headers.
58921128Skarels * If there's not enough space in the first mbuf, allocate another.
59021128Skarels * If that should fail, drop this sucker.
59121128Skarels * No extra space for headers is allocated.
59221128Skarels */
59321128Skarels mp = mtod(m, char *); /* save pointer to real message */
59435800Ssklower M_PREPEND(m, sizeof(struct hym_hdr), M_DONTWAIT);
59535800Ssklower if (m == 0) {
59635800Ssklower error = ENOBUFS;
59735800Ssklower goto bad;
59821128Skarels }
59921128Skarels dlen += sizeof(struct hym_hdr) - HYM_SWLEN;
60021128Skarels
60121128Skarels hym = mtod(m, struct hym_hdr *);
60221128Skarels
60321128Skarels bzero((caddr_t)hym, sizeof(struct hym_hdr));
60421128Skarels
60511195Ssam switch(dst->sa_family) {
60611195Ssam
60711195Ssam #ifdef INET
60811195Ssam case AF_INET: {
60921128Skarels int i;
61011195Ssam
61111195Ssam /*
61221128Skarels * if loopback address, swizzle ip header so when
61321128Skarels * it comes back it looks like it was addressed to us
61411195Ssam */
61521128Skarels i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym);
61621128Skarels if (i < 0)
61721128Skarels goto notfound;
61821128Skarels if (i > 0) {
61911195Ssam struct in_addr temp;
62011195Ssam
62121128Skarels temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr;
62221128Skarels ((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr;
62321128Skarels ((struct ip *)mp)->ip_src.s_addr = temp.s_addr;
62411195Ssam }
62511195Ssam /*
62611195Ssam * If entire packet won't fit in message proper, just
62711195Ssam * send hyperchannel hardware header and ip header in
62821128Skarels * message proper.
62911195Ssam *
63011195Ssam * This insures that the associated data is at least a
63111195Ssam * TCP/UDP header in length and thus prevents potential
63211195Ssam * problems with very short word counts.
63311195Ssam */
63421128Skarels if (dlen > MPSIZE)
63521128Skarels hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2);
63621128Skarels hym->hym_type = HYLINK_IP;
63711195Ssam break;
63811195Ssam }
63911195Ssam #endif
64011195Ssam
64111195Ssam default:
64211207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit,
64311207Ssam dst->sa_family);
64411195Ssam error = EAFNOSUPPORT;
64511195Ssam goto drop;
64611195Ssam }
64711195Ssam
64821128Skarels
64921128Skarels headerexists:
65021128Skarels
65111195Ssam /*
65221128Skarels * insure message proper is below the maximum
65311195Ssam */
65421128Skarels if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0))
65521128Skarels hym->hym_mplen = MPSIZE;
65611195Ssam
65721775Skarels hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host);
65821128Skarels if (hym->hym_mplen)
65921128Skarels hym->hym_ctl |= H_ASSOC;
66021128Skarels else
66121128Skarels hym->hym_ctl &= ~H_ASSOC;
66221128Skarels if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
66321128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl,
66421128Skarels hym->hym_access, hym->hym_to, hym->hym_from,
66521128Skarels hym->hym_param, hym->hym_type);
66611195Ssam #ifdef DEBUG
66721128Skarels printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
66821128Skarels ifp->if_unit, hym->hym_mplen, hym->hym_ctl,
66921128Skarels hym->hym_access, hym->hym_to, hym->hym_from,
67021128Skarels hym->hym_param, hym->hym_type);
67111195Ssam #endif
67211195Ssam s = splimp();
67311195Ssam if (IF_QFULL(&ifp->if_snd)) {
67411195Ssam IF_DROP(&ifp->if_snd);
67511195Ssam error = ENOBUFS;
67611195Ssam splx(s);
67711195Ssam goto drop;
67811195Ssam }
67911195Ssam IF_ENQUEUE(&ifp->if_snd, m);
68011195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING)
68111195Ssam hyact(hyinfo[ifp->if_unit]);
68211195Ssam splx(s);
68311207Ssam return (0);
68411195Ssam notfound:
68521128Skarels error = EHOSTUNREACH;
68611195Ssam drop:
68711195Ssam m_freem(m);
68811207Ssam return (error);
68911207Ssam }
69011195Ssam
69121128Skarels int
hyroute(ifp,dest,hym)69221128Skarels hyroute(ifp, dest, hym)
69321128Skarels register struct ifnet *ifp;
69421128Skarels u_long dest;
69521128Skarels register struct hym_hdr *hym;
69621128Skarels {
69721128Skarels #ifdef HYROUTE
69821128Skarels register struct hy_route *rt = &hy_route[ifp->if_unit];
69921128Skarels register struct hyr_hash *rhash;
70021128Skarels register int i;
70121128Skarels #endif
70221128Skarels
70321128Skarels hym->hym_param = 0;
70421128Skarels #ifdef HYROUTE
70521128Skarels if (rt->hyr_lasttime != 0) {
70621128Skarels i = HYRHASH(dest);
70721128Skarels rhash = &rt->hyr_hash[i];
70821128Skarels i = 0;
70921128Skarels while (rhash->hyr_key != dest) {
71021128Skarels if (rhash->hyr_flags == 0 || i > HYRSIZE)
71121128Skarels return(-1);
71221128Skarels rhash++; i++;
71321128Skarels if (rhash >= &rt->hyr_hash[HYRSIZE])
71421128Skarels rhash = &rt->hyr_hash[0];
71521128Skarels }
71621128Skarels if (rhash->hyr_flags & HYR_GATE) {
71721128Skarels i = rhash->hyr_nextgate;
71821128Skarels if (i >= rhash->hyr_egate)
71921128Skarels rhash->hyr_nextgate = rhash->hyr_pgate;
72021128Skarels else
72121128Skarels rhash->hyr_nextgate++;
72221128Skarels rhash = &rt->hyr_hash[rt->hyr_gateway[i]];
72321128Skarels if ((rhash->hyr_flags & HYR_DIR) == 0)
72421128Skarels return(-1);
72521128Skarels } else if (rhash->hyr_flags & HYR_LOOP) {
72621128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */
72721128Skarels } else if (rhash->hyr_flags & HYR_RLOOP) {
72821128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */
72921128Skarels }
73021128Skarels hym->hym_ctl = rhash->hyr_ctl;
73121128Skarels hym->hym_access = rhash->hyr_access;
73221128Skarels hym->hym_to = rhash->hyr_dst;
73321128Skarels } else {
73421128Skarels #endif
73521128Skarels hym->hym_ctl = H_XTRUNKS | H_RTRUNKS;
73621128Skarels hym->hym_access = 0;
73721128Skarels hym->hym_to = htons((u_short)dest);
73821128Skarels if (dest & 0x010000)
73921128Skarels hym->hym_param = H_LOOPBK; /* adapter loopback */
74021128Skarels else if (dest & 0x020000)
74121128Skarels hym->hym_param = H_RLOOPBK; /* A710 remote loopback */
74221128Skarels #ifdef HYROUTE
74321128Skarels }
74421128Skarels #endif
74521128Skarels
74621128Skarels if (hym->hym_param == 0)
74721128Skarels return(0);
74821128Skarels else
74921128Skarels return(1);
75021128Skarels }
75121128Skarels
hyact(ui)75211195Ssam hyact(ui)
75311195Ssam register struct uba_device *ui;
75411195Ssam {
75511195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit];
75611195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
75711195Ssam
75811195Ssam actloop:
75911195Ssam #ifdef DEBUG
76011207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
76111207Ssam hy_state_names[is->hy_state]);
76211195Ssam #endif
76311195Ssam switch (is->hy_state) {
76411195Ssam
76511195Ssam case STARTUP:
76611195Ssam goto endintr;
76711195Ssam
76811195Ssam case IDLE: {
76911195Ssam register rq = is->hy_flags;
77011195Ssam
77111195Ssam if (rq & RQ_STATUS) {
77211195Ssam is->hy_flags &= ~RQ_STATUS;
77311195Ssam is->hy_state = STATSENT;
77411207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status),
77513088Ssam is->hy_ifuba.ifu_r.ifrw_info);
77611195Ssam } else if (rq & RQ_ENDOP) {
77711195Ssam is->hy_flags &= ~RQ_ENDOP;
77811195Ssam is->hy_state = ENDOPSENT;
77911195Ssam hystart(ui, HYF_END_OP, 0, 0);
78011195Ssam } else if (rq & RQ_STATISTICS) {
78111195Ssam is->hy_flags &= ~RQ_STATISTICS;
78211195Ssam is->hy_state = RSTATSENT;
78311207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
78413088Ssam is->hy_ifuba.ifu_r.ifrw_info);
78511207Ssam } else if (HYS_RECVDATA(addr)) {
78611195Ssam is->hy_state = RECVSENT;
78711195Ssam is->hy_retry = 0;
78821128Skarels hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN);
78911195Ssam } else if (rq & RQ_REISSUE) {
79011195Ssam is->hy_flags &= ~RQ_REISSUE;
79111195Ssam is->hy_state = is->hy_savedstate;
79211195Ssam #ifdef DEBUG
79311207Ssam printD("hy%d: reissue cmd=0x%x count=%d",
79411207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount);
79511207Ssam printD(" ubaddr=0x%x retry=%d\n",
79611207Ssam is->hy_savedaddr, is->hy_retry);
79711195Ssam #endif
79811207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount,
79913088Ssam is->hy_savedaddr);
80011195Ssam } else {
80111195Ssam register struct mbuf *m;
80211195Ssam
80311195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m);
80411207Ssam if (m != NULL) {
80511195Ssam register struct hym_hdr *hym;
80611195Ssam register int mplen;
80711195Ssam register int cmd;
80811195Ssam
80911195Ssam is->hy_state = XMITSENT;
81011195Ssam is->hy_retry = 0;
81111195Ssam hym = mtod(m, struct hym_hdr *);
81211195Ssam #ifdef HYLOG
81311207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr),
81413088Ssam (char *)hym);
81511195Ssam #endif
81611195Ssam mplen = hym->hym_mplen;
81721128Skarels if (hym->hym_to_adapter == hym->hym_from_adapter)
81811207Ssam cmd = HYF_XMITLOCMSG;
81911207Ssam else
82011207Ssam cmd = HYF_XMITMSG;
82111195Ssam #ifdef DEBUG
82211195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit);
82311207Ssam if (hy_debug_flag)
82411207Ssam hyprintdata((char *)hym,
82513088Ssam sizeof (struct hym_hdr));
82611195Ssam #endif
82721128Skarels is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN;
82811195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
82911207Ssam UBAPURGE(is->hy_ifuba.ifu_uba,
83011207Ssam is->hy_ifuba.ifu_w.ifrw_bdp);
83111195Ssam #ifdef DEBUG
83211207Ssam printD(
83311207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
83411195Ssam ui->ui_unit, mplen, is->hy_olen);
83511207Ssam if (hy_debug_flag)
83611207Ssam hyprintdata(
83713088Ssam is->hy_ifuba.ifu_w.ifrw_addr,
83821128Skarels is->hy_olen + HYM_SWLEN);
83911195Ssam #endif
84021128Skarels if (mplen == 0) {
84121128Skarels is->hy_flags &= ~RQ_XASSOC;
84221128Skarels mplen = is->hy_olen;
84321128Skarels } else {
84411195Ssam is->hy_flags |= RQ_XASSOC;
84521128Skarels }
84621128Skarels hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN);
84711195Ssam } else if (rq & RQ_MARKDOWN) {
84811195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
84911195Ssam is->hy_state = MARKPORT;
85011195Ssam is->hy_retry = 0;
85111195Ssam /*
85211207Ssam * Port number is taken from status data
85311195Ssam */
85411207Ssam hystart(ui,
85512772Ssam (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)),
85612772Ssam 0, 0);
85711195Ssam } else if (rq & RQ_MARKUP) {
85811195Ssam register struct ifnet *ifp = &is->hy_if;
85911195Ssam
86011207Ssam is->hy_flags &= ~RQ_MARKUP;
86111195Ssam is->hy_retry = 0;
86211195Ssam /*
86313065Ssam * Fill in the host number
86411207Ssam * from the status buffer
86511195Ssam */
86611207Ssam printf(
86711207Ssam "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
86811195Ssam ui->ui_unit,
86911195Ssam is->hy_stat.hyc_uaddr,
87011195Ssam PORTNUM(&is->hy_status),
87111207Ssam (is->hy_stat.hyc_atype[0]<<8) |
87211207Ssam is->hy_stat.hyc_atype[1],
87311195Ssam is->hy_stat.hyc_atype[2]);
87411195Ssam
87521775Skarels is->hy_host =
87611207Ssam (is->hy_stat.hyc_uaddr << 8) |
87711207Ssam PORTNUM(&is->hy_status);
87811195Ssam ifp->if_flags |= IFF_UP;
87911195Ssam #ifdef HYLOG
88011195Ssam hylog(HYL_UP, 0, (char *)0);
88111195Ssam #endif
88211195Ssam } else {
88311195Ssam is->hy_state = WAITING;
88411195Ssam is->hy_retry = 0;
88511195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0);
88611195Ssam }
88711195Ssam }
88811207Ssam break;
88911195Ssam }
89011195Ssam
89111195Ssam case STATSENT:
89212772Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status,
89311207Ssam sizeof (struct hy_status));
89411195Ssam #ifdef DEBUG
89511207Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
89611207Ssam ui->ui_unit, is->hy_status.hys_gen_status,
89711207Ssam is->hy_status.hys_last_fcn,
89811207Ssam is->hy_status.hys_resp_trunk,
89911207Ssam is->hy_status.hys_status_trunk,
90011207Ssam is->hy_status.hys_recd_resp,
90111207Ssam is->hy_status.hys_error,
90211207Ssam is->hy_status.hys_caddr,
90311207Ssam is->hy_status.hys_pad);
90411195Ssam #endif
90511195Ssam is->hy_state = IDLE;
90611195Ssam #ifdef HYLOG
90711207Ssam hylog(HYL_STATUS, sizeof (struct hy_status),
90811207Ssam (char *)&is->hy_status);
90911195Ssam #endif
91011195Ssam #ifdef HYELOG
91111195Ssam {
91211195Ssam register int i;
91311195Ssam
91411195Ssam i = is->hy_status.hys_error;
91521128Skarels if (i > HYE_MAX)
91611195Ssam i = HYE_MAX;
91711195Ssam switch (is->hy_status.hys_last_fcn) {
91811195Ssam case HYF_XMITLOCMSG:
91911195Ssam i += HYE_MAX+1; /* fall through */
92011195Ssam case HYF_XMITLSTDATA:
92111195Ssam i += HYE_MAX+1; /* fall through */
92211195Ssam case HYF_XMITMSG:
92311195Ssam i += HYE_MAX+1;
92411195Ssam }
92511195Ssam hy_elog[i]++;
92611195Ssam }
92711195Ssam #endif
92811195Ssam break;
92911195Ssam
93011195Ssam case RSTATSENT: {
93111207Ssam register struct hy_stat *p =
93211207Ssam (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
93311195Ssam
93421128Skarels bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat));
93511195Ssam #ifdef DEBUG
93621128Skarels
93721128Skarels printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n",
93811195Ssam ui->ui_unit,
93921128Skarels (is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2],
94021128Skarels (is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2],
94121128Skarels (is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2],
94221128Skarels (is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]);
94321128Skarels printD(" ret0 %d ret1 %d ret2 %d ret3 %d\n",
94421128Skarels (is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2],
94521128Skarels (is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2],
94621128Skarels (is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2],
94721128Skarels (is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]);
94821128Skarels printD(" cancel %d abort %d atype %x %x %x uaddr %x\n",
94921128Skarels (is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1],
95021128Skarels (is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1],
95111195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
95211195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
95311195Ssam #endif
95411195Ssam is->hy_state = IDLE;
95511195Ssam #ifdef HYLOG
95611207Ssam hylog(HYL_STATISTICS, sizeof (struct hy_stat),
95711207Ssam (char *)&is->hy_stat);
95811195Ssam #endif
95911195Ssam break;
96011195Ssam }
96111195Ssam
96211195Ssam case CLEARSENT:
96311195Ssam is->hy_state = IDLE;
96411195Ssam break;
96511195Ssam
96611195Ssam case ENDOPSENT:
96711195Ssam is->hy_state = IDLE;
96811195Ssam break;
96911195Ssam
97011195Ssam case RECVSENT: {
97121128Skarels register struct hym_hdr *hym;
97211207Ssam register unsigned len;
97311195Ssam
97411207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
97511207Ssam UBAPURGE(is->hy_ifuba.ifu_uba,
97613088Ssam is->hy_ifuba.ifu_r.ifrw_bdp);
97721128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
97811207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
97911207Ssam if (len > MPSIZE) {
98011207Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n",
98113088Ssam ui->ui_unit, len);
98221128Skarels is->hy_state = IDLE;
98311195Ssam #ifdef DEBUG
98411207Ssam hy_debug_flag = 1;
98511207Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
98611207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS,
98711207Ssam addr->hyd_bar, addr->hyd_wcr);
98811195Ssam #endif
98911207Ssam }
99021128Skarels hym->hym_mplen = len;
99111195Ssam #ifdef DEBUG
99211207Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
99311207Ssam if (hy_debug_flag)
99421128Skarels hyprintdata((char *)hym, len + HYM_SWLEN);
99511195Ssam #endif
99621128Skarels if (hym->hym_ctl & H_ASSOC) {
99711207Ssam is->hy_state = RECVDATASENT;
99811207Ssam is->hy_retry = 0;
99911207Ssam hystart(ui, HYF_INPUTDATA,
100021128Skarels (int)(HYMTU + sizeof (struct hy_hdr) - len),
100121128Skarels (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len));
100211207Ssam } else {
100321128Skarels hyrecvdata(ui, hym, (int)len + HYM_SWLEN);
100411207Ssam is->hy_state = IDLE;
100511195Ssam }
100611207Ssam break;
100711207Ssam }
100811195Ssam
100911195Ssam case RECVDATASENT: {
101021128Skarels register struct hym_hdr *hym;
101111207Ssam register unsigned len;
101211195Ssam
101311207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
101411207Ssam UBAPURGE(is->hy_ifuba.ifu_uba,
101513088Ssam is->hy_ifuba.ifu_r.ifrw_bdp);
101621128Skarels hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
101711207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
101811195Ssam #ifdef DEBUG
101911207Ssam printD("hy%d: recvd assoc data, len = %d, data = ",
102011207Ssam ui->ui_unit, len);
102111207Ssam if (hy_debug_flag)
102221128Skarels hyprintdata((char *)hym + hym->hym_mplen, len);
102311195Ssam #endif
102421128Skarels hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN));
102511207Ssam is->hy_state = IDLE;
102611207Ssam break;
102711207Ssam }
102811195Ssam
102911195Ssam case XMITSENT:
103011207Ssam if (is->hy_flags & RQ_XASSOC) {
103113196Sroot register int len;
103211195Ssam
103311207Ssam is->hy_flags &= ~RQ_XASSOC;
103411207Ssam is->hy_state = XMITDATASENT;
103511207Ssam is->hy_retry = 0;
103611207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
103711207Ssam if (len > is->hy_olen) {
103811207Ssam printf(
103911207Ssam "hy%d: xmit error - len > hy_olen [%d > %d]\n",
104011207Ssam ui->ui_unit, len, is->hy_olen);
104111195Ssam #ifdef DEBUG
104211207Ssam hy_debug_flag = 1;
104311195Ssam #endif
104411195Ssam }
104511207Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
104621128Skarels is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len);
104711207Ssam break;
104811207Ssam }
104911207Ssam /* fall through to ... */
105011195Ssam
105111195Ssam case XMITDATASENT:
105211207Ssam hyxmitdata(ui);
105311207Ssam is->hy_state = IDLE;
105411207Ssam break;
105511195Ssam
105611195Ssam case WAITING: /* wait for message complete or output requested */
105711207Ssam if (HYS_RECVDATA(addr))
105811195Ssam is->hy_state = IDLE;
105911195Ssam else {
106011195Ssam is->hy_state = CLEARSENT;
106111195Ssam is->hy_retry = 0;
106211195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0);
106311195Ssam }
106411195Ssam break;
106511195Ssam
106611195Ssam case MARKPORT:
106711195Ssam is->hy_state = STARTUP;
106821128Skarels if_down(&is->hy_if);
106911195Ssam is->hy_if.if_flags &= ~IFF_UP;
107011195Ssam goto endintr;
107111195Ssam
107211195Ssam default:
107311207Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
107411207Ssam ui->ui_unit, is->hy_state);
107511195Ssam panic("HYPERCHANNEL IN INVALID STATE");
107611195Ssam /*NOTREACHED*/
107711207Ssam }
107811195Ssam if (is->hy_state == IDLE)
107911195Ssam goto actloop;
108011195Ssam endintr:
108113088Ssam ;
108211195Ssam #ifdef DEBUG
108311207Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit,
108411207Ssam hy_state_names[is->hy_state]);
108511195Ssam #endif
108611207Ssam }
108711195Ssam
108821128Skarels struct sockproto hypproto = { PF_HYLINK };
108937476Ssklower struct sockaddr_in hypdst = { sizeof(hypdst), AF_HYLINK };
109037476Ssklower struct sockaddr_in hypsrc = { sizeof(hypsrc), AF_HYLINK };
109121128Skarels
109211195Ssam /*
109313088Ssam * Called from device interrupt when receiving data.
109411195Ssam * Examine packet to determine type. Decapsulate packet
109511195Ssam * based on type and pass to type specific higher-level
109611195Ssam * input routine.
109711195Ssam */
109821128Skarels hyrecvdata(ui, hym, len)
109911195Ssam struct uba_device *ui;
110021128Skarels register struct hym_hdr *hym;
110111195Ssam int len;
110211195Ssam {
110311195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit];
110411195Ssam struct mbuf *m;
110511195Ssam register struct ifqueue *inq;
110611195Ssam
110711195Ssam is->hy_if.if_ipackets++;
110811195Ssam #ifdef DEBUG
110921128Skarels printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len);
111011195Ssam #endif
111111195Ssam #ifdef HYLOG
111211195Ssam {
111311195Ssam struct {
111411195Ssam short hlen;
111521128Skarels struct hym_hdr hhdr;
111611195Ssam } hh;
111711195Ssam hh.hlen = len;
111821128Skarels hh.hhdr = *hym;
111911195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh);
112011195Ssam }
112111195Ssam #endif
112211195Ssam if (len > HYMTU + MPSIZE || len == 0)
112311195Ssam return; /* sanity */
112411195Ssam /*
112511195Ssam * Pull packet off interface.
112611195Ssam */
112724797Skarels m = if_rubaget(&is->hy_ifuba, len, 0, &is->hy_if);
112811207Ssam if (m == NULL)
112911195Ssam return;
113011195Ssam
113121128Skarels /*
113221128Skarels * if normal or adapter loopback response packet believe hym_type,
113321128Skarels * otherwise, use the raw input queue cause it's a response from an
113421128Skarels * adapter command.
113521128Skarels */
113621128Skarels if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff)
113721128Skarels goto rawlinkin;
113821128Skarels
113921128Skarels switch (hym->hym_type) {
114021128Skarels
114111195Ssam #ifdef INET
114211195Ssam case HYLINK_IP:
114311195Ssam schednetisr(NETISR_IP);
114411195Ssam inq = &ipintrq;
114511195Ssam break;
114611195Ssam #endif
114711195Ssam default:
114821128Skarels rawlinkin:
114921128Skarels {
115035800Ssklower M_PREPEND(m, sizeof(struct hym_hdr), M_DONTWAIT);
115135800Ssklower if (m == 0) {
115221128Skarels m_freem(m);
115321128Skarels return;
115421128Skarels }
115535800Ssklower bcopy((caddr_t)hym, mtod(m, caddr_t), sizeof(struct hym_hdr));
115621128Skarels hypproto.sp_protocol = 0;
115721775Skarels hypdst.sin_addr = is->hy_addr;
115821775Skarels hypsrc.sin_addr = is->hy_addr;
115921128Skarels raw_input(m, &hypproto, (struct sockaddr *)&hypsrc,
116021128Skarels (struct sockaddr *)&hypdst);
116121128Skarels return;
116221128Skarels }
116311195Ssam }
116411195Ssam if (IF_QFULL(inq)) {
116511195Ssam IF_DROP(inq);
116611195Ssam m_freem(m);
116711195Ssam } else
116811195Ssam IF_ENQUEUE(inq, m);
116911207Ssam }
117011195Ssam
117111195Ssam /*
117211207Ssam * Transmit done, release resources, bump counters.
117311195Ssam */
117411195Ssam hyxmitdata(ui)
117511195Ssam struct uba_device *ui;
117611195Ssam {
117711195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit];
117811195Ssam
117911195Ssam is->hy_if.if_opackets++;
118011207Ssam if (is->hy_ifuba.ifu_xtofree) {
118111195Ssam m_freem(is->hy_ifuba.ifu_xtofree);
118211195Ssam is->hy_ifuba.ifu_xtofree = 0;
118311195Ssam }
118411207Ssam }
118511195Ssam
hycancel(ui)118611195Ssam hycancel(ui)
118711195Ssam register struct uba_device *ui;
118811195Ssam {
118911195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit];
119011195Ssam
119111207Ssam if (is->hy_ifuba.ifu_xtofree) {
119211195Ssam m_freem(is->hy_ifuba.ifu_xtofree);
119311195Ssam is->hy_ifuba.ifu_xtofree = 0;
119411195Ssam }
119521128Skarels #ifdef HYLOG
119621128Skarels hylog(HYL_CANCEL, 0, (char *)0);
119721128Skarels #endif
119811195Ssam #ifdef DEBUG
119911207Ssam if (hy_nodebug & 1)
120011207Ssam hy_debug_flag = 1;
120111195Ssam #endif
120211195Ssam #ifdef DEBUG
120311195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
120411195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
120511195Ssam is->hy_savedcount, is->hy_savedaddr);
120621128Skarels printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
120721128Skarels is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry);
120811207Ssam printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
120911207Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr,
121011207Ssam is->hy_savedcmd);
121111195Ssam #endif
121211195Ssam is->hy_state = IDLE;
121311195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
121411195Ssam hyact(ui);
121511207Ssam }
121611195Ssam
121711195Ssam #ifdef DEBUG
hyprintdata(cp,len)121811195Ssam hyprintdata(cp, len)
121911195Ssam register char *cp;
122011195Ssam register int len;
122111195Ssam {
122211195Ssam register int count = 16;
122311195Ssam register char *fmt;
122411195Ssam static char regfmt[] = "\n\t %x";
122511195Ssam
122611195Ssam fmt = ®fmt[2];
122711195Ssam while (--len >= 0) {
122811195Ssam printL(fmt, *cp++ & 0xff);
122911195Ssam fmt = ®fmt[2];
123011195Ssam if (--count <= 0) {
123111195Ssam fmt = ®fmt[0];
123211195Ssam count = 16;
123311195Ssam }
123411195Ssam }
123511195Ssam printL("\n");
123611195Ssam }
123711195Ssam #endif
123811195Ssam
hywatch(unit)123911195Ssam hywatch(unit)
124013088Ssam int unit;
124111195Ssam {
124211195Ssam register struct hy_softc *is = &hy_softc[unit];
124311195Ssam register struct uba_device *ui = hyinfo[unit];
124411195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
124511195Ssam int s;
124611195Ssam
124711195Ssam s = splimp();
124811195Ssam #ifdef PI13
124911195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) {
125011195Ssam addr->hyd_csr |= S_POWEROFF;
125111195Ssam DELAY(100);
125211195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) {
125321128Skarels printf("hy%d: Adapter Power Restored (hywatch)\n", unit);
125411195Ssam is->hy_state = IDLE;
125511207Ssam is->hy_flags |=
125611207Ssam (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
125711195Ssam hyact(ui);
125811195Ssam }
125911195Ssam }
126011195Ssam #endif
126121128Skarels if (++is->hy_ntime >= 2 && is->hy_state != WAITING &&
126221128Skarels is->hy_state != STARTUP && is->hy_state != IDLE) {
126321128Skarels #ifdef HYLOG
126421128Skarels printf("hy%d: watchdog timer expired in state \"%s\"\n", unit,
126521128Skarels hy_state_names[is->hy_state]);
126621128Skarels #else
126721128Skarels printf("hy%d: watchdog timer expired in state %d\n", unit,
126821128Skarels is->hy_state);
126921128Skarels #endif
127021128Skarels printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit,
127121128Skarels is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS);
127221128Skarels hycancel(ui);
127321128Skarels }
127411195Ssam splx(s);
127521128Skarels is->hy_if.if_timer = SCANINTERVAL;
127611195Ssam }
127711195Ssam
127811195Ssam #ifdef HYLOG
hylog(code,len,ptr)127911195Ssam hylog(code, len, ptr)
128013088Ssam int code, len;
128111195Ssam char *ptr;
128211195Ssam {
128311195Ssam register unsigned char *p;
128411195Ssam int s;
128511195Ssam
128611195Ssam s = splimp();
128711195Ssam if (hy_log.hyl_self != &hy_log) {
128811195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
128911195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0];
129011195Ssam hy_log.hyl_self = &hy_log;
129121128Skarels hy_log.hyl_enable = HYL_CONTINUOUS;
129221128Skarels hy_log.hyl_onerr = HYL_CONTINUOUS;
129321128Skarels hy_log.hyl_count = 0;
129421128Skarels hy_log.hyl_icount = 16;
129521128Skarels hy_log.hyl_filter = 0xffff; /* enable all */
129611195Ssam }
129721128Skarels if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0)
129811207Ssam goto out;
129911195Ssam p = hy_log.hyl_ptr;
130021128Skarels if (p + len + 3 >= hy_log.hyl_eptr) {
130112772Ssam bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p));
130211195Ssam p = &hy_log.hyl_buf[0];
130321128Skarels if (hy_log.hyl_enable != HYL_CONTINUOUS) {
130421128Skarels hy_log.hyl_enable = HYL_DISABLED;
130511195Ssam goto out;
130611195Ssam }
130711195Ssam }
130811195Ssam *p++ = code;
130911195Ssam *p++ = len;
131013088Ssam bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len);
131121128Skarels if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) {
131221128Skarels *p++ = '\0';
131321128Skarels hy_log.hyl_enable = HYL_DISABLED;
131421128Skarels hy_log.hyl_count = hy_log.hyl_icount;
131521128Skarels }
131626285Skarels p += len;
131721128Skarels if (hy_log.hyl_wait != 0) { /* wakeup HYGETLOG if wanted */
131826285Skarels if (hy_log.hyl_wait <= p - hy_log.hyl_ptr) {
131921128Skarels wakeup((caddr_t)&hy_log);
132021128Skarels hy_log.hyl_wait = 0;
132126285Skarels } else
132226285Skarels hy_log.hyl_wait -= p - hy_log.hyl_ptr;
132321128Skarels }
132426285Skarels hy_log.hyl_ptr = p;
132511195Ssam out:
132611195Ssam splx(s);
132711195Ssam }
132811195Ssam #endif
132911195Ssam
133012772Ssam /*ARGSUSED*/
hyioctl(ifp,cmd,data)133113058Ssam hyioctl(ifp, cmd, data)
133213058Ssam register struct ifnet *ifp;
133311207Ssam int cmd;
133411207Ssam caddr_t data;
133511195Ssam {
133621775Skarels struct ifaddr *ifa = (struct ifaddr *) data;
133721128Skarels struct hyrsetget *sg = (struct hyrsetget *)data;
133821128Skarels #if defined(HYLOG) || defined(HYELOG)
133921128Skarels struct hylsetget *sgl = (struct hylsetget *)data;
134021128Skarels #endif
134121128Skarels struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit];
134211207Ssam int s = splimp(), error = 0;
134321128Skarels #ifdef HYLOG
134421128Skarels struct hy_softc *is = &hy_softc[ifp->if_unit];
134521128Skarels struct {
134621128Skarels u_char hstate;
134721128Skarels u_char hflags;
134821128Skarels u_short iflags;
134921128Skarels int hcmd;
135021128Skarels int herror;
135121128Skarels u_long haddr;
135221128Skarels u_long hmisc;
135321128Skarels } hil;
135411195Ssam
135521128Skarels hil.hmisc = -1;
135621128Skarels hil.hstate = is->hy_state;
135721128Skarels hil.hflags = is->hy_flags;
135821128Skarels hil.hcmd = cmd;
135921128Skarels #endif
136021128Skarels
136111195Ssam switch(cmd) {
136211195Ssam
136313065Ssam case SIOCSIFADDR:
136437476Ssklower if (ifa->ifa_addr->sa_family != AF_INET)
136521128Skarels return(EINVAL);
136621775Skarels if ((ifp->if_flags & IFF_RUNNING) == 0)
136721775Skarels hyinit(ifp->if_unit);
136821775Skarels hy_softc[ifp->if_unit].hy_addr = IA_SIN(ifa)->sin_addr;
136921128Skarels #ifdef HYLOG
137021775Skarels hil.haddr = is->hy_addr.s_addr;
137121128Skarels #endif
137213065Ssam break;
137313065Ssam
137411195Ssam case HYSETROUTE:
137537543Smckusick if (error = suser(u.u_cred, &u.u_acflag))
137621128Skarels goto out;
137721128Skarels
137821128Skarels if (sg->hyrsg_len != sizeof(struct hy_route)) {
137921128Skarels error = EINVAL;
138021128Skarels goto out;
138121128Skarels }
138221128Skarels if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) {
138321128Skarels r->hyr_lasttime = 0; /* disable further routing if trouble */
138421128Skarels error = EFAULT;
138521128Skarels goto out;
138621128Skarels }
138721128Skarels r->hyr_lasttime = time.tv_sec;
138821128Skarels #ifdef HYLOG
138921128Skarels hil.hmisc = r->hyr_lasttime;
139021128Skarels #endif
139111195Ssam break;
139211195Ssam
139311195Ssam case HYGETROUTE:
139421128Skarels if (sg->hyrsg_len < sizeof(struct hy_route)) {
139521128Skarels error = EINVAL;
139621128Skarels goto out;
139721128Skarels }
139821128Skarels if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) {
139921128Skarels error = EFAULT;
140021128Skarels goto out;
140121128Skarels }
140211195Ssam break;
140311195Ssam
140421128Skarels #ifdef HYELOG
140521128Skarels case HYGETELOG:
140621128Skarels if (sgl->hylsg_len < sizeof(hy_elog)) {
140721128Skarels error = EINVAL;
140821128Skarels goto out;
140921128Skarels }
141021128Skarels if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) {
141121128Skarels error = EFAULT;
141221128Skarels goto out;
141321128Skarels }
141421128Skarels if (sgl->hylsg_cmd) {
141537543Smckusick if (error = suser(u.u_cred, &u.u_acflag))
141621128Skarels goto out;
141721128Skarels bzero((caddr_t)hy_elog, sizeof(hy_elog));
141821128Skarels }
141921128Skarels break;
142021128Skarels #endif
142121128Skarels
142221128Skarels #ifdef HYLOG
142321128Skarels case HYSETLOG:
142437543Smckusick if (error = suser(u.u_cred, &u.u_acflag))
142521128Skarels goto out;
142621128Skarels hy_log.hyl_enable = HYL_DISABLED;
142721128Skarels hylog(HYL_NOP, 0, (char *)0); /* force log init */
142821128Skarels hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f;
142921128Skarels hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f;
143021128Skarels hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff;
143121128Skarels hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len;
143221128Skarels wakeup((caddr_t)&hy_log); /* wakeup sleeping HYGETLOG */
143321128Skarels break;
143421128Skarels
143521128Skarels case HYGETLOG:
143621128Skarels if (sgl->hylsg_len < sizeof(hy_log)) {
143721128Skarels error = EINVAL;
143821128Skarels goto out;
143921128Skarels }
144021128Skarels if (sgl->hylsg_cmd != 0) {
144121128Skarels if (hy_log.hyl_wait) {
144221128Skarels error = EBUSY;
144321128Skarels goto out;
144421128Skarels }
144521128Skarels hy_log.hyl_wait = sgl->hylsg_cmd;
144626392Skarels sleep((caddr_t)&hy_log, PZERO - 1);
144721128Skarels }
144821128Skarels
144921128Skarels if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) {
145021128Skarels error = EFAULT;
145121128Skarels goto out;
145221128Skarels }
145321128Skarels break;
145421128Skarels #endif
145521128Skarels
145611195Ssam default:
145713058Ssam error = EINVAL;
145811195Ssam break;
145911195Ssam }
146021128Skarels out:
146121128Skarels #ifdef HYLOG
146221128Skarels hil.herror = error;
146321128Skarels hil.iflags = ifp->if_flags;
146421775Skarels hil.haddr = is->hy_addr.s_addr;
146521128Skarels hylog(HYL_IOCTL, sizeof(hil), (char *)&hil);
146621128Skarels #endif
146711195Ssam splx(s);
146811207Ssam return (error);
146911195Ssam }
147011207Ssam #endif
1471