xref: /csrg-svn/sys/vax/if/if_hy.c (revision 21128)
1*21128Skarels /*	@(#)if_hy.c	6.3 (Berkeley) 05/28/85 */
211195Ssam 
3*21128Skarels /*
4*21128Skarels  * 4.2 BSD Unix Kernel - Vax Network Interface Support
5*21128Skarels  *
6*21128Skarels  * $Header: if_hy.c,v 10.1 84/07/22 21:02:56 steveg Exp $
7*21128Skarels  * $Locker:  $
8*21128Skarels  *
9*21128Skarels  * Modifications from Berkeley 4.2 BSD
10*21128Skarels  * Copyright (c) 1983, Tektronix Inc.
11*21128Skarels  * All Rights Reserved
12*21128Skarels  *
13*21128Skarels  * $Log:	if_hy.c,v $
14*21128Skarels  *	Revision 10.1  84/07/22  21:02:56  steveg
15*21128Skarels  *	define PI13 (moved from if_hyreg.h, somehow got dropped in the process)
16*21128Skarels  *	rework hywatch to check for power fails first
17*21128Skarels  *
18*21128Skarels  *	Revision 10.0  84/06/30  19:54:27  steveg
19*21128Skarels  *	Big Build
20*21128Skarels  *
21*21128Skarels  *	Revision 3.17  84/06/20  19:20:28  steveg
22*21128Skarels  *	increment hy_ntime in hywatch
23*21128Skarels  *	print out state name, csr, last command, and hy_flags when watchdog timer
24*21128Skarels  *	expires
25*21128Skarels  *
26*21128Skarels  *	Revision 3.16  84/06/20  19:09:34  steveg
27*21128Skarels  *	turn on continuous logging by default
28*21128Skarels  *
29*21128Skarels  *	Revision 3.15  84/05/30  22:19:09  steveg
30*21128Skarels  *	changes to reflect new layout ot statistics data
31*21128Skarels  *
32*21128Skarels  *	Revision 3.14  84/05/30  19:25:15  steveg
33*21128Skarels  *	move driver states to if_hy.h so log printing programs can use them
34*21128Skarels  *
35*21128Skarels  *	Revision 3.13  84/05/30  17:13:26  steveg
36*21128Skarels  *	make it compile
37*21128Skarels  *
38*21128Skarels  *	Revision 3.12  84/05/30  13:46:16  steveg
39*21128Skarels  *	rework logging
40*21128Skarels  *
41*21128Skarels  *	Revision 3.11  84/05/18  19:35:02  steveg
42*21128Skarels  *	clear IFF_RUNNING and IFF_UP on unibus reset to force resource allocation
43*21128Skarels  *	by the init routine
44*21128Skarels  *
45*21128Skarels  *	Revision 3.10  84/05/04  12:14:44  steveg
46*21128Skarels  *	more rework to make it actually work under 4.2
47*21128Skarels  *
48*21128Skarels  *	Revision 3.9  84/05/01  23:34:52  steveg
49*21128Skarels  *	fix typo so it compiles (unit -> ui->ui_unit)
50*21128Skarels  *
51*21128Skarels  *	Revision 3.8  84/05/01  23:18:30  steveg
52*21128Skarels  *	changes after talking with rickk
53*21128Skarels  *	- check power off more closely
54*21128Skarels  *	- support remote loopback through A710 adapters
55*21128Skarels  *	- IMPLINK -> HYLINK
56*21128Skarels  *	- return EHOSTUNREACH on hyroute failure
57*21128Skarels  *	- bump if_collisions on abnormal interrupts that aren't input or output
58*21128Skarels  *
59*21128Skarels  *
60*21128Skarels  */
61*21128Skarels 
62*21128Skarels 
6311195Ssam #include "hy.h"
6411195Ssam #if NHY > 0
6511195Ssam 
6611195Ssam /*
6711195Ssam  * Network Systems Copropration Hyperchanel interface
6811195Ssam  */
69*21128Skarels #include "machine/pte.h"
7011195Ssam 
71*21128Skarels #include "../h/param.h"
72*21128Skarels #include "../h/systm.h"
73*21128Skarels #include "../h/mbuf.h"
74*21128Skarels #include "../h/buf.h"
75*21128Skarels #include "../h/protosw.h"
76*21128Skarels #include "../h/socket.h"
77*21128Skarels #include "../h/vmmac.h"
78*21128Skarels #include "../h/errno.h"
79*21128Skarels #include "../h/time.h"
80*21128Skarels #include "../h/kernel.h"
81*21128Skarels #include "../h/ioctl.h"
8213088Ssam 
8311195Ssam #include "../net/if.h"
8411207Ssam #include "../net/netisr.h"
8511195Ssam #include "../net/route.h"
8611195Ssam #include "../netinet/in.h"
8711195Ssam #include "../netinet/in_systm.h"
8811195Ssam #include "../netinet/ip.h"
8911195Ssam #include "../netinet/ip_var.h"
9011195Ssam 
9111207Ssam #include "../vax/cpu.h"
9211207Ssam #include "../vax/mtpr.h"
9311207Ssam #include "../vaxuba/ubareg.h"
9411207Ssam #include "../vaxuba/ubavar.h"
9511195Ssam 
96*21128Skarels /*
97*21128Skarels  * configuration specific paramters
98*21128Skarels  *	- change as appropriate for particular installaions
99*21128Skarels  */
100*21128Skarels #define	HYROUTE
101*21128Skarels #define	HYELOG
102*21128Skarels #define	HYLOG
103*21128Skarels #define	HYMTU	1100
104*21128Skarels #define PI13
10511195Ssam 
106*21128Skarels #ifdef	DEBUG
107*21128Skarels #define	HYLOG
108*21128Skarels #endif
109*21128Skarels 
110*21128Skarels #include "../vaxif/if_hy.h"
111*21128Skarels #include "../vaxif/if_hyreg.h"
112*21128Skarels #include "../vaxif/if_uba.h"
113*21128Skarels 
11413058Ssam int	hyprobe(), hyattach(), hyinit(), hyioctl();
11513058Ssam int	hyoutput(), hyreset(), hywatch();
11611195Ssam struct	uba_device *hyinfo[NHY];
11711195Ssam u_short hystd[] = { 0772410, 0 };
11811195Ssam struct	uba_driver hydriver =
11911195Ssam 	{ hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo };
12011195Ssam 
12111195Ssam /*
12211195Ssam  * Hyperchannel software status per interface.
12311195Ssam  *
12411195Ssam  * Each interface is referenced by a network interface structure,
12511195Ssam  * hy_if, which the routing code uses to locate the interface.
12611195Ssam  * This structure contains the output queue for the interface, its address, ...
12711195Ssam  * We also have, for each interface, a UBA interface structure, which
12811195Ssam  * contains information about the UNIBUS resources held by the interface:
12911195Ssam  * map registers, buffered data paths, etc.  Information is cached in this
13011195Ssam  * structure for use by the if_uba.c routines in running the interface
13111195Ssam  * efficiently.
13211195Ssam  */
13311195Ssam struct	hy_softc {
13411195Ssam 	struct	ifnet hy_if;		/* network-visible interface */
13511195Ssam 	struct	ifuba hy_ifuba;		/* UNIBUS resources */
13611207Ssam 	short	hy_flags;		/* flags */
13711207Ssam 	short	hy_state;		/* driver state */
13811195Ssam 	int	hy_olen;		/* packet length on output */
13911195Ssam 	int	hy_lastwcr;		/* last command's word count */
14011195Ssam 	short	hy_savedstate;		/* saved for reissue after status */
14111195Ssam 	short	hy_savedcmd;		/* saved command for reissue */
14211195Ssam 	int	hy_savedcount;		/* saved byte count for reissue */
14311195Ssam 	int	hy_savedaddr;		/* saved unibus address for reissue */
14411195Ssam 	int	hy_ntime;		/* number of timeouts since last cmd */
14511195Ssam 	int	hy_retry;		/* retry counter */
14611207Ssam 	struct	hy_stat hy_stat;	/* statistics */
14711207Ssam 	struct	hy_status hy_status;	/* status */
14811195Ssam } hy_softc[NHY];
14911195Ssam 
15011195Ssam #ifdef HYELOG
151*21128Skarels u_long	hy_elog[HYE_SIZE];
15211195Ssam #endif
15311195Ssam 
154*21128Skarels #ifdef HYLOG
155*21128Skarels struct hy_log hy_log;
156*21128Skarels #endif
157*21128Skarels 
158*21128Skarels #ifdef HYROUTE
159*21128Skarels struct hy_route hy_route[NHY];
160*21128Skarels #endif
161*21128Skarels 
16211195Ssam #ifdef DEBUG
163*21128Skarels #define printL	printf
164*21128Skarels #define printD	if (hy_debug_flag) printf
16511195Ssam int	hy_debug_flag = 0;
16611195Ssam /*
16711195Ssam  * hy_nodebug bit 0x01	set hy_debug_flag on hycancel
16811195Ssam  * hy_nodebug bit 0x02	set hy_debug_flag on command reissue
16911195Ssam  * hy_nodebug bit 0x04	set hy_debug_flag on abnormal interrupt
17011195Ssam  */
17111195Ssam int	hy_nodebug = 0x0;
17211195Ssam #endif
17311195Ssam 
17411195Ssam #define SCANINTERVAL	10	/* seconds */
17511195Ssam #define MAXINTERVAL	20	/* seconds (max action) */
17611195Ssam 
17711195Ssam /*
17811195Ssam  * Cause a device interrupt.  This code uses a buffer starting at
17911195Ssam  * location zero on the unibus (which is already mapped by the
18011195Ssam  * autoconfigure code in the kernel).
18111195Ssam  */
18211195Ssam hyprobe(reg)
18311195Ssam 	caddr_t reg;
18411195Ssam {
18511195Ssam 	register int br, cvec;		/* r11, r10 value-result */
18611195Ssam 	register struct hydevice *addr = (struct hydevice *) reg;
18711195Ssam 
18811195Ssam #ifdef lint
18911195Ssam 	br = 0; cvec = br; br = cvec;
19011195Ssam 	hyint(0);
19111195Ssam #endif
19211195Ssam 	/*
19311195Ssam 	 * request adapter status to a buffer starting at unibus location 0
19411195Ssam 	 */
19511195Ssam 	addr->hyd_bar = 0;
19611195Ssam 	addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1);
19711195Ssam 	addr->hyd_dbuf = HYF_STATUS;
19811195Ssam #ifdef PI13
19911195Ssam 	addr->hyd_csr |= S_GO | S_IE | S_IATTN;
20011195Ssam #else
20111195Ssam 	addr->hyd_csr |= S_GO | S_IE;
20211195Ssam #endif
20311195Ssam 	DELAY(10000);
20411195Ssam #ifdef PI13
20511195Ssam 	addr->hyd_csr |= S_CLRINT;	/* clear any stacked interrupts */
20611195Ssam #endif
20711195Ssam 	addr->hyd_csr &= ~(S_IE | S_CLRINT);	/* disable further interrupts */
208*21128Skarels 	return(sizeof(struct hydevice));
20911207Ssam }
21011195Ssam 
21111195Ssam /*
21211195Ssam  * Interface exists: make available by filling in network interface
21311195Ssam  * record.  System will initialize the interface when it is ready
21411195Ssam  * to accept packets.
21511195Ssam  */
21611195Ssam hyattach(ui)
21711195Ssam 	struct uba_device *ui;
21811195Ssam {
21911195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
22011195Ssam 	register struct ifnet *ifp = &is->hy_if;
221*21128Skarels 	register struct sockaddr_in *sin;
22211195Ssam 
22311195Ssam 	ifp->if_unit = ui->ui_unit;
22411195Ssam 	ifp->if_name = "hy";
22511195Ssam 	ifp->if_mtu = HYMTU;
22611195Ssam 	is->hy_state = STARTUP;		/* don't allow state transitions yet */
227*21128Skarels 	sin = (struct sockaddr_in *)&ifp->if_addr;
228*21128Skarels 	sin->sin_family = AF_INET;
22911195Ssam 	ifp->if_init = hyinit;
23013058Ssam 	ifp->if_ioctl = hyioctl;
23111195Ssam 	ifp->if_output = hyoutput;
23211207Ssam 	ifp->if_reset = hyreset;
23311195Ssam 	ifp->if_watchdog = hywatch;
23411195Ssam 	ifp->if_timer = SCANINTERVAL;
23511195Ssam 	is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
23611207Ssam #ifdef notdef
23711195Ssam 	is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
23811195Ssam #endif
23911195Ssam 	if_attach(ifp);
24011207Ssam }
24111195Ssam 
24211195Ssam /*
24311195Ssam  * Reset of interface after UNIBUS reset.
24411195Ssam  * If interface is on specified uba, reset its state.
24511195Ssam  */
24611195Ssam hyreset(unit, uban)
24711195Ssam 	int unit, uban;
24811195Ssam {
249*21128Skarels 	register struct uba_device *ui;
250*21128Skarels 	register struct hy_softc *is;
25111195Ssam 
252*21128Skarels 	if (unit >= NHY || (ui = hyinfo[unit]) == 0 || ui->ui_alive == 0 ||
25311207Ssam 	  ui->ui_ubanum != uban)
25411195Ssam 		return;
25511195Ssam 	printf(" hy%d", unit);
256*21128Skarels 	is = &hy_softc[unit];		/* force unibus resource allocation */
257*21128Skarels 	is->hy_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
25811195Ssam 	hyinit(unit);
25911207Ssam }
26011195Ssam 
26111195Ssam /*
26211195Ssam  * Initialization of interface; clear recorded pending
26311195Ssam  * operations, and reinitialize UNIBUS usage.
26411195Ssam  */
26511195Ssam hyinit(unit)
26611195Ssam 	int unit;
26711195Ssam {
26811195Ssam 	register struct hy_softc *is = &hy_softc[unit];
26911195Ssam 	register struct uba_device *ui = hyinfo[unit];
270*21128Skarels 	register struct mbuf *m;
27113065Ssam 	struct sockaddr_in *sin;
27211195Ssam 	int s;
27311195Ssam 
27413088Ssam 	sin = (struct sockaddr_in *)&is->hy_if.if_addr;
275*21128Skarels 	if (sin->sin_addr.s_addr == 0)		/* address still unknown */
27613065Ssam 		return;
277*21128Skarels 	if (is->hy_if.if_flags & IFF_RUNNING)	/* just reset the device */
278*21128Skarels 		goto justreset;
27911195Ssam 	if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
280*21128Skarels 	    sizeof (struct hym_hdr), (int)btoc(HYMTU)) == 0) {
28111195Ssam #ifdef DEBUG
28211207Ssam 		if (hy_nodebug & 4)
28311207Ssam 			hy_debug_flag = 1;
28411195Ssam #endif
28511195Ssam 		printf("hy%d: can't initialize\n", unit);
28611195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
28711195Ssam 		return;
28811195Ssam 	}
28913088Ssam 	is->hy_if.if_flags |= IFF_RUNNING;
290*21128Skarels 
291*21128Skarels justreset:
29211195Ssam 	/*
293*21128Skarels 	 * remove any left over outgoing messages, reset the hardware and
294*21128Skarels 	 * start the state machine
29511195Ssam 	 */
29611195Ssam 	s = splimp();
297*21128Skarels #ifdef HYLOG
298*21128Skarels 	hylog(HYL_RESET, 0, (char *)0);
299*21128Skarels #endif
30011195Ssam 	is->hy_state = IDLE;
30111195Ssam 	is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
30211195Ssam 	is->hy_retry = 0;
303*21128Skarels 	for(;;) {
304*21128Skarels 		IF_DEQUEUE(&is->hy_if.if_snd, m);
305*21128Skarels 		if (m != NULL)
306*21128Skarels 			m_freem(m);
307*21128Skarels 		else
308*21128Skarels 			break;
309*21128Skarels 	}
310*21128Skarels 	hycancel(ui);		/* also bumps the state machine */
31111195Ssam 	splx(s);
31211207Ssam }
31311195Ssam 
31411195Ssam /*
31511207Ssam  * Issue a command to the adapter
31611195Ssam  */
31711195Ssam hystart(ui, cmd, count, ubaddr)
31811195Ssam 	struct uba_device *ui;
31911207Ssam 	int cmd, count, ubaddr;
32011195Ssam {
32111195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
32211195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
32311195Ssam 
32411195Ssam #ifdef DEBUG
32511207Ssam 	printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
32611207Ssam 		ui->ui_unit, cmd, count, ubaddr);
32711195Ssam 	printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
32811207Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
32911207Ssam 		addr->hyd_wcr);
33011195Ssam #endif
33111207Ssam 	if (((is->hy_flags & RQ_REISSUE) == 0) &&
33211207Ssam 	  (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
33311195Ssam 		is->hy_savedstate = is->hy_state;
33411195Ssam 		is->hy_savedcmd = cmd;
33511195Ssam 		is->hy_savedcount = count;
33611195Ssam 		is->hy_savedaddr = ubaddr;
33711195Ssam 	}
338*21128Skarels #ifdef PI13
339*21128Skarels 	if (addr->hyd_csr & S_POWEROFF) {
340*21128Skarels 		printf("hy%d: \"Soft\" Adapter Power Failure (hystart)\n", ui->ui_unit);
341*21128Skarels 		addr->hyd_csr |= S_POWEROFF;
342*21128Skarels 		DELAY(100);
343*21128Skarels 		if (addr->hyd_csr & S_POWEROFF) {
344*21128Skarels 			printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hystart)\n", ui->ui_unit);
345*21128Skarels 			if_down(&is->hy_if);
346*21128Skarels 			is->hy_if.if_flags &= ~IFF_UP;
347*21128Skarels 			is->hy_state = STARTUP;
348*21128Skarels 		} else {
349*21128Skarels 			printf("hy%d: Adapter Power Restored (hystart)\n", ui->ui_unit);
350*21128Skarels 		}
351*21128Skarels 		return;
352*21128Skarels 	}
353*21128Skarels #endif
35411195Ssam 	addr->hyd_bar = ubaddr & 0xffff;
35511207Ssam 	addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);
35611195Ssam 	addr->hyd_dbuf = cmd;
35711195Ssam #ifdef PI13
35811195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN;
35911195Ssam #else
36011195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE;
36111195Ssam #endif
36211195Ssam #ifdef DEBUG
36311195Ssam 	printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
36411207Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
36511207Ssam 		addr->hyd_wcr);
36611195Ssam #endif
36711195Ssam #ifdef HYLOG
36811195Ssam 	{
36911195Ssam 		struct {
37011207Ssam 			u_char	hcmd;
37111207Ssam 			u_char	hstate;
37211207Ssam 			short	hcount;
37311195Ssam 		} hcl;
37411195Ssam 
37511195Ssam 		hcl.hcmd = cmd;
37611195Ssam 		hcl.hstate = is->hy_state;
37711195Ssam 		hcl.hcount = count;
37811195Ssam 		hylog(HYL_CMD, sizeof(hcl), (char *)&hcl);
37911195Ssam 	}
38011195Ssam #endif
38111195Ssam 	is->hy_ntime = 0;
38211207Ssam }
38311195Ssam 
38411195Ssam int hyint_active = 0;		/* set during hy interrupt */
38511195Ssam /*
38611207Ssam  * Hyperchannel interface interrupt.
38711195Ssam  *
38811195Ssam  * An interrupt can occur for many reasons.  Examine the status of
38911195Ssam  * the hyperchannel status bits to determine what to do next.
39011195Ssam  *
39111195Ssam  * If input error just drop packet.
39211195Ssam  * Otherwise purge input buffered data path and examine
39311195Ssam  * packet to determine type.  Othewise decapsulate
39411195Ssam  * packet based on type and pass to type specific higher-level
39511195Ssam  * input routine.
39611195Ssam  */
39711195Ssam hyint(unit)
39811195Ssam 	int unit;
39911195Ssam {
40011195Ssam 	register struct hy_softc *is = &hy_softc[unit];
40111195Ssam 	register struct uba_device *ui = hyinfo[unit];
40211207Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
40311195Ssam 
40411207Ssam 	if (hyint_active)
40511195Ssam 		panic("RECURSIVE HYPERCHANNEL INTERRUPT");
40611195Ssam 	hyint_active++;
40711195Ssam #ifdef DEBUG
40811195Ssam 	printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
40911195Ssam 		unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
41011195Ssam #endif
41111195Ssam #ifdef HYLOG
41211195Ssam logit:
41311195Ssam 	{
41411195Ssam 		struct {
41511207Ssam 			u_char	hstate;
41611207Ssam 			u_char	hflags;
41711207Ssam 			short	hcsr;
41811207Ssam 			short	hwcr;
41911195Ssam 		} hil;
42011195Ssam 		hil.hstate = is->hy_state;
42111195Ssam 		hil.hflags = is->hy_flags;
42211195Ssam 		hil.hcsr = addr->hyd_csr;
42311195Ssam 		hil.hwcr = addr->hyd_wcr;
42411195Ssam 		hylog(HYL_INT, sizeof(hil), (char *)&hil);
42511195Ssam 	}
42611195Ssam #endif
42711207Ssam 	if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
42811195Ssam 		/*
42911207Ssam 		 * Error bit set, some sort of error in the interface.
43011195Ssam 		 *
43111207Ssam 		 * The adapter sets attn on command completion so that's not
43211207Ssam 		 * a real error even though the interface considers it one.
43311195Ssam 		 */
43411195Ssam #ifdef DEBUG
43511207Ssam 		if (hy_nodebug & 4)
43611207Ssam 			hy_debug_flag = 1;
43711195Ssam #endif
43811207Ssam 		printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n",
43911207Ssam 			addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
44011207Ssam 			addr->hyd_wcr);
44111207Ssam 		if (addr->hyd_csr & S_NEX) {
44211195Ssam 			printf("hy%d: NEX - Non Existant Memory\n", unit);
44311195Ssam #ifdef PI13
44411195Ssam 			addr->hyd_csr |= S_NEX;  /* as per PI13 manual */
44511195Ssam #else
44611195Ssam 			addr->hyd_csr &= ~S_NEX;
44711195Ssam #endif
44811195Ssam 			hycancel(ui);
44911195Ssam #ifdef PI13
45011207Ssam 		} else if (addr->hyd_csr & S_POWEROFF) {
451*21128Skarels 			printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit);
45211195Ssam 			addr->hyd_csr |= S_POWEROFF;
45311195Ssam 			DELAY(100);
45411207Ssam 			if (addr->hyd_csr & S_POWEROFF) {
455*21128Skarels 				printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit);
45611195Ssam 				if_down(&is->hy_if);
457*21128Skarels 				is->hy_if.if_flags &= ~IFF_UP;
45811195Ssam 				is->hy_state = STARTUP;
459*21128Skarels 			} else {
460*21128Skarels 				printf("hy%d: Adapter Power Restored (hyint)\n", unit);
46111195Ssam 			}
46211195Ssam #endif
46311195Ssam 		} else {
46411195Ssam 			printf("hy%d:  BAR overflow\n", unit);
46511195Ssam 			hycancel(ui);
46611195Ssam 		}
46711207Ssam 	} else if (HYS_NORMAL(addr)) {
46811195Ssam 		/*
46911207Ssam 		 * Normal interrupt, bump state machine unless in state
47011195Ssam 		 * waiting and no data present (assumed to be word count
47111207Ssam 		 * zero interrupt or other hardware botch).
47211195Ssam 		 */
47311207Ssam 		if (is->hy_state != WAITING || HYS_RECVDATA(addr))
47411195Ssam 			hyact(ui);
47511207Ssam 	} else if (HYS_ABNORMAL(addr)) {
47611195Ssam 		/*
47711207Ssam 		 * Abnormal termination.
47811195Ssam 		 * bump error counts, retry the last function
47911195Ssam 		 * 'MAXRETRY' times before kicking the bucket.
48011195Ssam 		 *
48111207Ssam 		 * Don't reissue the cmd if in certain states, abnormal
48211207Ssam 		 * on a reissued cmd or max retry exceeded.
48311195Ssam 		 */
48411195Ssam #ifdef HYLOG
48511195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
48611195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
48711195Ssam 			goto logit;
48811195Ssam 		}
48911195Ssam #endif
49011195Ssam #ifdef DEBUG
49111207Ssam 		if (hy_nodebug & 4)
49211207Ssam 			hy_debug_flag = 1;
49311195Ssam 		printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
49411195Ssam 			unit, hy_state_names[is->hy_state], is->hy_state);
495*21128Skarels 		printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
496*21128Skarels 			is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry);
49711207Ssam 		printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
49811207Ssam 			is->hy_savedstate, is->hy_savedcount,
49911207Ssam 			is->hy_savedaddr, is->hy_savedcmd);
50011195Ssam #endif
50111195Ssam #ifdef PI13
50211195Ssam 		addr->hyd_csr &= ~S_C;  /* clear the damned PI-13 */
50311195Ssam #endif
50411207Ssam 		if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT)
50511195Ssam 			is->hy_if.if_oerrors++;
506*21128Skarels 		else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT)
50711195Ssam 			is->hy_if.if_ierrors++;
508*21128Skarels 		else
509*21128Skarels 			is->hy_if.if_collisions++;	/* other errors */
51011195Ssam 		if (is->hy_state == XMITDATASENT ||
51111195Ssam 		    is->hy_state == RECVSENT ||
51211195Ssam 		    is->hy_state == RECVDATASENT ||
51311207Ssam 		    (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY)
51411195Ssam 			hycancel(ui);
51511207Ssam 		else {
51611195Ssam #ifdef DEBUG
51711207Ssam 			if (hy_nodebug & 2)
51811207Ssam 				hy_debug_flag = 1;
51911195Ssam #endif
52011195Ssam 			is->hy_retry++;
52111195Ssam 			is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE;
52211195Ssam 			is->hy_state = IDLE;
52311195Ssam 			hyact(ui);
52411195Ssam 		}
52511195Ssam 	} else {
52611195Ssam 		/*
52711195Ssam 		 * Interrupt is neither normal, abnormal, or interface error.
52811195Ssam 		 * Ignore it. It's either stacked or a word count 0.
52911195Ssam 		 */
53011195Ssam #ifdef HYLOG
53111195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
53211195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
53311195Ssam 			goto logit;
53411195Ssam 		}
53511195Ssam #endif
53611195Ssam #ifdef DEBUG
53711195Ssam 		printD("hy%d: possible stacked interrupt ignored\n", unit);
53811195Ssam #endif
53911195Ssam 	}
54011195Ssam #ifdef DEBUG
54111195Ssam 	printD("hy%d: hyint exit\n\n", unit);
54211195Ssam #endif
54311195Ssam 	hyint_active = 0;
54411195Ssam 
54511207Ssam }
54611195Ssam 
547*21128Skarels int hyoutprint = 0;
548*21128Skarels 
54911195Ssam /*
55011195Ssam  * Encapsulate a packet of type family for the local net.
55111195Ssam  */
55211195Ssam hyoutput(ifp, m0, dst)
55311195Ssam 	struct ifnet *ifp;
55411195Ssam 	struct mbuf *m0;
55511195Ssam 	struct sockaddr *dst;
55611195Ssam {
55711195Ssam 	register struct hym_hdr *hym;
55811195Ssam 	register struct mbuf *m;
559*21128Skarels 	register char *mp;
56011195Ssam #ifdef HYROUTE
561*21128Skarels 	register struct hy_route *r = &hy_route[ifp->if_unit];
56211195Ssam #endif
563*21128Skarels 	int dlen;	/* packet size, incl hardware header, but not sw header */
56411195Ssam 	int error = 0;
56511195Ssam 	int s;
56611195Ssam 
567*21128Skarels 	/*
568*21128Skarels 	 * Calculate packet length for later deciding whether it will fit
569*21128Skarels 	 * in a message proper or we also need associated data.
570*21128Skarels 	 */
57111195Ssam 	dlen = 0;
57211195Ssam 	for (m = m0; m; m = m->m_next)
57311195Ssam 		dlen += m->m_len;
57411195Ssam 	m = m0;
575*21128Skarels 	if (dst->sa_family == AF_HYLINK) {	/* don't add header */
576*21128Skarels 		dlen -= HYM_SWLEN;
577*21128Skarels 		goto headerexists;
578*21128Skarels 	}
579*21128Skarels 
580*21128Skarels 	/*
581*21128Skarels 	 * Add the software and hardware hyperchannel headers.
582*21128Skarels 	 * If there's not enough space in the first mbuf, allocate another.
583*21128Skarels 	 * If that should fail, drop this sucker.
584*21128Skarels 	 * No extra space for headers is allocated.
585*21128Skarels 	 */
586*21128Skarels 	mp = mtod(m, char *);	/* save pointer to real message */
587*21128Skarels 	if (m->m_off > MMAXOFF ||
588*21128Skarels 	    MMINOFF + sizeof(struct hym_hdr) > m->m_off) {
589*21128Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
590*21128Skarels 		if (m == 0) {
591*21128Skarels 			m = m0;
592*21128Skarels 			error = ENOBUFS;
593*21128Skarels 			goto drop;
594*21128Skarels 		}
595*21128Skarels 		m->m_next = m0;
596*21128Skarels 		m->m_off = MMINOFF;
597*21128Skarels 		m->m_len = sizeof(struct hym_hdr);
598*21128Skarels 	} else {
599*21128Skarels 		m->m_off -= sizeof(struct hym_hdr);
600*21128Skarels 		m->m_len += sizeof(struct hym_hdr);
601*21128Skarels 	}
602*21128Skarels 
603*21128Skarels 	dlen += sizeof(struct hym_hdr) - HYM_SWLEN;
604*21128Skarels 
605*21128Skarels 	hym = mtod(m, struct hym_hdr *);
606*21128Skarels 
607*21128Skarels 	bzero((caddr_t)hym, sizeof(struct hym_hdr));
608*21128Skarels 
60911195Ssam 	switch(dst->sa_family) {
61011195Ssam 
61111195Ssam #ifdef INET
61211195Ssam 	case AF_INET: {
613*21128Skarels 		int i;
61411195Ssam 
61511195Ssam 		/*
616*21128Skarels 		 * if loopback address, swizzle ip header so when
617*21128Skarels 		 * it comes back it looks like it was addressed to us
61811195Ssam 		 */
619*21128Skarels 		i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym);
620*21128Skarels 		if (i < 0)
621*21128Skarels 			goto notfound;
622*21128Skarels 		if (i > 0) {
62311195Ssam 			struct in_addr temp;
62411195Ssam 
625*21128Skarels 			temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr;
626*21128Skarels 			((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr;
627*21128Skarels 			((struct ip *)mp)->ip_src.s_addr = temp.s_addr;
62811195Ssam 		}
62911195Ssam 		/*
63011195Ssam 		 * If entire packet won't fit in message proper, just
63111195Ssam 		 * send hyperchannel hardware header and ip header in
632*21128Skarels 		 * message proper.
63311195Ssam 		 *
63411195Ssam 		 * This insures that the associated data is at least a
63511195Ssam 		 * TCP/UDP header in length and thus prevents potential
63611195Ssam 		 * problems with very short word counts.
63711195Ssam 		 */
638*21128Skarels 		if (dlen > MPSIZE)
639*21128Skarels 			hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2);
640*21128Skarels 		hym->hym_type = HYLINK_IP;
64111195Ssam 		break;
64211195Ssam 	}
64311195Ssam #endif
64411195Ssam 
64511195Ssam 	default:
64611207Ssam 		printf("hy%d: can't handle af%d\n", ifp->if_unit,
64711207Ssam 			dst->sa_family);
64811195Ssam 		error = EAFNOSUPPORT;
64911195Ssam 		goto drop;
65011195Ssam 	}
65111195Ssam 
652*21128Skarels 
653*21128Skarels headerexists:
654*21128Skarels 
65511195Ssam 	/*
656*21128Skarels 	 * insure message proper is below the maximum
65711195Ssam 	 */
658*21128Skarels 	if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0))
659*21128Skarels 		hym->hym_mplen = MPSIZE;
66011195Ssam 
661*21128Skarels 	hym->hym_from = htons((u_short)ifp->if_host[0]);
662*21128Skarels 	if (hym->hym_mplen)
663*21128Skarels 		hym->hym_ctl |= H_ASSOC;
664*21128Skarels 	else
665*21128Skarels 		hym->hym_ctl &= ~H_ASSOC;
666*21128Skarels 	if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
667*21128Skarels 		ifp->if_unit, hym->hym_mplen, hym->hym_ctl,
668*21128Skarels 		hym->hym_access, hym->hym_to, hym->hym_from,
669*21128Skarels 		hym->hym_param, hym->hym_type);
67011195Ssam #ifdef DEBUG
671*21128Skarels 	printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
672*21128Skarels 		ifp->if_unit, hym->hym_mplen, hym->hym_ctl,
673*21128Skarels 		hym->hym_access, hym->hym_to, hym->hym_from,
674*21128Skarels 		hym->hym_param, hym->hym_type);
67511195Ssam #endif
67611195Ssam 	s = splimp();
67711195Ssam 	if (IF_QFULL(&ifp->if_snd)) {
67811195Ssam 		IF_DROP(&ifp->if_snd);
67911195Ssam 		error = ENOBUFS;
68011195Ssam 		splx(s);
68111195Ssam 		goto drop;
68211195Ssam 	}
68311195Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
68411195Ssam 	if (hy_softc[ifp->if_unit].hy_state == WAITING)
68511195Ssam 		hyact(hyinfo[ifp->if_unit]);
68611195Ssam 	splx(s);
68711207Ssam 	return (0);
68811195Ssam notfound:
689*21128Skarels 	error = EHOSTUNREACH;
69011195Ssam drop:
69111195Ssam 	m_freem(m);
69211207Ssam 	return (error);
69311207Ssam }
69411195Ssam 
695*21128Skarels int
696*21128Skarels hyroute(ifp, dest, hym)
697*21128Skarels 	register struct ifnet *ifp;
698*21128Skarels 	u_long dest;
699*21128Skarels 	register struct hym_hdr *hym;
700*21128Skarels {
701*21128Skarels #ifdef HYROUTE
702*21128Skarels 	register struct hy_route *rt = &hy_route[ifp->if_unit];
703*21128Skarels 	register struct hyr_hash *rhash;
704*21128Skarels 	register int i;
705*21128Skarels #endif
706*21128Skarels 
707*21128Skarels 	hym->hym_param = 0;
708*21128Skarels #ifdef HYROUTE
709*21128Skarels 	if (rt->hyr_lasttime != 0) {
710*21128Skarels 		i = HYRHASH(dest);
711*21128Skarels 		rhash = &rt->hyr_hash[i];
712*21128Skarels 		i = 0;
713*21128Skarels 		while (rhash->hyr_key != dest) {
714*21128Skarels 			if (rhash->hyr_flags == 0 || i > HYRSIZE)
715*21128Skarels 				return(-1);
716*21128Skarels 			rhash++; i++;
717*21128Skarels 			if (rhash >= &rt->hyr_hash[HYRSIZE])
718*21128Skarels 				rhash = &rt->hyr_hash[0];
719*21128Skarels 		}
720*21128Skarels 		if (rhash->hyr_flags & HYR_GATE) {
721*21128Skarels 			i = rhash->hyr_nextgate;
722*21128Skarels 			if (i >= rhash->hyr_egate)
723*21128Skarels 				rhash->hyr_nextgate = rhash->hyr_pgate;
724*21128Skarels 			else
725*21128Skarels 				rhash->hyr_nextgate++;
726*21128Skarels 			rhash = &rt->hyr_hash[rt->hyr_gateway[i]];
727*21128Skarels 			if ((rhash->hyr_flags & HYR_DIR) == 0)
728*21128Skarels 				return(-1);
729*21128Skarels 		} else if (rhash->hyr_flags & HYR_LOOP) {
730*21128Skarels 			hym->hym_param = H_LOOPBK;	/* adapter loopback */
731*21128Skarels 		} else if (rhash->hyr_flags & HYR_RLOOP) {
732*21128Skarels 			hym->hym_param = H_RLOOPBK;	/* A710 remote loopback */
733*21128Skarels 		}
734*21128Skarels 		hym->hym_ctl = rhash->hyr_ctl;
735*21128Skarels 		hym->hym_access = rhash->hyr_access;
736*21128Skarels 		hym->hym_to = rhash->hyr_dst;
737*21128Skarels 	} else {
738*21128Skarels #endif
739*21128Skarels 		hym->hym_ctl = H_XTRUNKS | H_RTRUNKS;
740*21128Skarels 		hym->hym_access = 0;
741*21128Skarels 		hym->hym_to = htons((u_short)dest);
742*21128Skarels 		if (dest & 0x010000)
743*21128Skarels 			hym->hym_param = H_LOOPBK;	/* adapter loopback */
744*21128Skarels 		else if (dest & 0x020000)
745*21128Skarels 			hym->hym_param = H_RLOOPBK;	/* A710 remote loopback */
746*21128Skarels #ifdef HYROUTE
747*21128Skarels 	}
748*21128Skarels #endif
749*21128Skarels 
750*21128Skarels 	hym->hym_from = htons((u_short)ifp->if_host[0]);
751*21128Skarels 	if (hym->hym_param == 0)
752*21128Skarels 		return(0);
753*21128Skarels 	else
754*21128Skarels 		return(1);
755*21128Skarels }
756*21128Skarels 
75711195Ssam hyact(ui)
75811195Ssam 	register struct uba_device *ui;
75911195Ssam {
76011195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
76111195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
76211195Ssam 
76311195Ssam actloop:
76411195Ssam #ifdef DEBUG
76511207Ssam 	printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
76611207Ssam 		hy_state_names[is->hy_state]);
76711195Ssam #endif
76811195Ssam 	switch (is->hy_state) {
76911195Ssam 
77011195Ssam 	case STARTUP:
77111195Ssam 		goto endintr;
77211195Ssam 
77311195Ssam 	case IDLE: {
77411195Ssam 		register rq = is->hy_flags;
77511195Ssam 
77611195Ssam 		if (rq & RQ_STATUS) {
77711195Ssam 			is->hy_flags &= ~RQ_STATUS;
77811195Ssam 			is->hy_state = STATSENT;
77911207Ssam 			hystart(ui, HYF_STATUS, sizeof (is->hy_status),
78013088Ssam 			    is->hy_ifuba.ifu_r.ifrw_info);
78111195Ssam 		} else if (rq & RQ_ENDOP) {
78211195Ssam 			is->hy_flags &= ~RQ_ENDOP;
78311195Ssam 			is->hy_state = ENDOPSENT;
78411195Ssam 			hystart(ui, HYF_END_OP, 0, 0);
78511195Ssam 		} else if (rq & RQ_STATISTICS) {
78611195Ssam 			is->hy_flags &= ~RQ_STATISTICS;
78711195Ssam 			is->hy_state = RSTATSENT;
78811207Ssam 			hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
78913088Ssam 			    is->hy_ifuba.ifu_r.ifrw_info);
79011207Ssam 		} else if (HYS_RECVDATA(addr)) {
79111195Ssam 			is->hy_state = RECVSENT;
79211195Ssam 			is->hy_retry = 0;
793*21128Skarels 			hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN);
79411195Ssam 		} else if (rq & RQ_REISSUE) {
79511195Ssam 			is->hy_flags &= ~RQ_REISSUE;
79611195Ssam 			is->hy_state = is->hy_savedstate;
79711195Ssam #ifdef DEBUG
79811207Ssam 			printD("hy%d: reissue cmd=0x%x count=%d",
79911207Ssam 			  ui->ui_unit, is->hy_savedcmd, is->hy_savedcount);
80011207Ssam 			printD(" ubaddr=0x%x retry=%d\n",
80111207Ssam 			  is->hy_savedaddr, is->hy_retry);
80211195Ssam #endif
80311207Ssam 			hystart(ui, is->hy_savedcmd, is->hy_savedcount,
80413088Ssam 			    is->hy_savedaddr);
80511195Ssam 		} else {
80611195Ssam 			register struct mbuf *m;
80711195Ssam 
80811195Ssam 			IF_DEQUEUE(&is->hy_if.if_snd, m);
80911207Ssam 			if (m != NULL) {
81011195Ssam 				register struct hym_hdr *hym;
81111195Ssam 				register int mplen;
81211195Ssam 				register int cmd;
81311195Ssam 
81411195Ssam 				is->hy_state = XMITSENT;
81511195Ssam 				is->hy_retry = 0;
81611195Ssam 				hym = mtod(m, struct hym_hdr *);
81711195Ssam #ifdef HYLOG
81811207Ssam 				hylog(HYL_XMIT, sizeof(struct hym_hdr),
81913088Ssam 				    (char *)hym);
82011195Ssam #endif
82111195Ssam 				mplen = hym->hym_mplen;
822*21128Skarels 				if (hym->hym_to_adapter == hym->hym_from_adapter)
82311207Ssam 					cmd = HYF_XMITLOCMSG;
82411207Ssam 				else
82511207Ssam 					cmd = HYF_XMITMSG;
82611195Ssam #ifdef DEBUG
82711195Ssam 				printD("hy%d: hym_hdr = ", ui->ui_unit);
82811207Ssam 				if (hy_debug_flag)
82911207Ssam 					hyprintdata((char *)hym,
83013088Ssam 					    sizeof (struct hym_hdr));
83111195Ssam #endif
832*21128Skarels 				is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN;
83311195Ssam 				if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
83411207Ssam 					UBAPURGE(is->hy_ifuba.ifu_uba,
83511207Ssam 						is->hy_ifuba.ifu_w.ifrw_bdp);
83611195Ssam #ifdef DEBUG
83711207Ssam 				printD(
83811207Ssam 		"hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
83911195Ssam 					ui->ui_unit, mplen, is->hy_olen);
84011207Ssam 				if (hy_debug_flag)
84111207Ssam 					hyprintdata(
84213088Ssam 					    is->hy_ifuba.ifu_w.ifrw_addr,
843*21128Skarels 					    is->hy_olen + HYM_SWLEN);
84411195Ssam #endif
845*21128Skarels 				if (mplen == 0) {
846*21128Skarels 					is->hy_flags &= ~RQ_XASSOC;
847*21128Skarels 					mplen = is->hy_olen;
848*21128Skarels 				} else {
84911195Ssam 					is->hy_flags |= RQ_XASSOC;
850*21128Skarels 				}
851*21128Skarels 				hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN);
85211195Ssam 			} else if (rq & RQ_MARKDOWN) {
85311195Ssam 				is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
85411195Ssam 				is->hy_state = MARKPORT;
85511195Ssam 				is->hy_retry = 0;
85611195Ssam 				/*
85711207Ssam 				 * Port number is taken from status data
85811195Ssam 				 */
85911207Ssam 				hystart(ui,
86012772Ssam 				 (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)),
86112772Ssam 				 0, 0);
86211195Ssam 			} else if (rq & RQ_MARKUP) {
86311195Ssam 				register struct ifnet *ifp = &is->hy_if;
86411207Ssam 				register struct sockaddr_in *sin =
86511207Ssam 				   (struct sockaddr_in *)&ifp->if_addr;
86611195Ssam 
86711207Ssam 				is->hy_flags &= ~RQ_MARKUP;
86811195Ssam 				is->hy_retry = 0;
86911195Ssam 				/*
87013065Ssam 				 * Fill in the host number
87111207Ssam 				 * from the status buffer
87211195Ssam 				 */
87311207Ssam 				printf(
87411207Ssam 	"hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
87511195Ssam 					ui->ui_unit,
87611195Ssam 					is->hy_stat.hyc_uaddr,
87711195Ssam 					PORTNUM(&is->hy_status),
87811207Ssam 					(is->hy_stat.hyc_atype[0]<<8) |
87911207Ssam 						is->hy_stat.hyc_atype[1],
88011195Ssam 					is->hy_stat.hyc_atype[2]);
88111195Ssam 
88211207Ssam 				ifp->if_host[0] =
88311207Ssam 				  (is->hy_stat.hyc_uaddr << 8) |
88411207Ssam 					PORTNUM(&is->hy_status);
88511195Ssam 				ifp->if_flags |= IFF_UP;
88611195Ssam 				if_rtinit(ifp, RTF_UP);
88711195Ssam #ifdef HYLOG
88811195Ssam 				hylog(HYL_UP, 0, (char *)0);
88911195Ssam #endif
89011195Ssam 			} else {
89111195Ssam 				is->hy_state = WAITING;
89211195Ssam 				is->hy_retry = 0;
89311195Ssam 				hystart(ui, HYF_WAITFORMSG, 0, 0);
89411195Ssam 			}
89511195Ssam 		}
89611207Ssam 		break;
89711195Ssam 	}
89811195Ssam 
89911195Ssam 	case STATSENT:
90012772Ssam 		bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status,
90111207Ssam 		  sizeof (struct hy_status));
90211195Ssam #ifdef DEBUG
90311207Ssam 		printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
90411207Ssam 			ui->ui_unit, is->hy_status.hys_gen_status,
90511207Ssam 			is->hy_status.hys_last_fcn,
90611207Ssam 			is->hy_status.hys_resp_trunk,
90711207Ssam 			is->hy_status.hys_status_trunk,
90811207Ssam 			is->hy_status.hys_recd_resp,
90911207Ssam 			is->hy_status.hys_error,
91011207Ssam 			is->hy_status.hys_caddr,
91111207Ssam 			is->hy_status.hys_pad);
91211195Ssam #endif
91311195Ssam 		is->hy_state = IDLE;
91411195Ssam #ifdef HYLOG
91511207Ssam 		hylog(HYL_STATUS, sizeof (struct hy_status),
91611207Ssam 			(char *)&is->hy_status);
91711195Ssam #endif
91811195Ssam #ifdef HYELOG
91911195Ssam 		{
92011195Ssam 			register int i;
92111195Ssam 
92211195Ssam 			i = is->hy_status.hys_error;
923*21128Skarels 			if (i > HYE_MAX)
92411195Ssam 				i = HYE_MAX;
92511195Ssam 			switch (is->hy_status.hys_last_fcn) {
92611195Ssam 				case HYF_XMITLOCMSG:
92711195Ssam 					i += HYE_MAX+1;	/* fall through */
92811195Ssam 				case HYF_XMITLSTDATA:
92911195Ssam 					i += HYE_MAX+1;	/* fall through */
93011195Ssam 				case HYF_XMITMSG:
93111195Ssam 					i += HYE_MAX+1;
93211195Ssam 			}
93311195Ssam 			hy_elog[i]++;
93411195Ssam 		}
93511195Ssam #endif
93611195Ssam 		break;
93711195Ssam 
93811195Ssam 	case RSTATSENT: {
93911207Ssam 		register struct hy_stat *p =
94011207Ssam 			(struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
94111195Ssam 
942*21128Skarels 		bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat));
94311195Ssam #ifdef DEBUG
944*21128Skarels 
945*21128Skarels 		printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n",
94611195Ssam 			ui->ui_unit,
947*21128Skarels 			(is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2],
948*21128Skarels 			(is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2],
949*21128Skarels 			(is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2],
950*21128Skarels 			(is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]);
951*21128Skarels 		printD("	ret0 %d ret1 %d ret2 %d ret3 %d\n",
952*21128Skarels 			(is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2],
953*21128Skarels 			(is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2],
954*21128Skarels 			(is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2],
955*21128Skarels 			(is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]);
956*21128Skarels 		printD("	cancel %d abort %d atype %x %x %x uaddr %x\n",
957*21128Skarels 			(is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1],
958*21128Skarels 			(is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1],
95911195Ssam 			is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
96011195Ssam 			is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
96111195Ssam #endif
96211195Ssam 		is->hy_state = IDLE;
96311195Ssam #ifdef HYLOG
96411207Ssam 		hylog(HYL_STATISTICS, sizeof (struct hy_stat),
96511207Ssam 			(char *)&is->hy_stat);
96611195Ssam #endif
96711195Ssam 		break;
96811195Ssam 	}
96911195Ssam 
97011195Ssam 	case CLEARSENT:
97111195Ssam 		is->hy_state = IDLE;
97211195Ssam 		break;
97311195Ssam 
97411195Ssam 	case ENDOPSENT:
97511195Ssam 		is->hy_state = IDLE;
97611195Ssam 		break;
97711195Ssam 
97811195Ssam 	case RECVSENT: {
979*21128Skarels 		register struct hym_hdr *hym;
98011207Ssam 		register unsigned len;
98111195Ssam 
98211207Ssam 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
98311207Ssam 			UBAPURGE(is->hy_ifuba.ifu_uba,
98413088Ssam 			    is->hy_ifuba.ifu_r.ifrw_bdp);
985*21128Skarels 		hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
98611207Ssam 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
98711207Ssam 		if (len > MPSIZE) {
98811207Ssam 			printf("hy%d: RECVD MP > MPSIZE (%d)\n",
98913088Ssam 			    ui->ui_unit, len);
990*21128Skarels 			is->hy_state = IDLE;
99111195Ssam #ifdef DEBUG
99211207Ssam 			hy_debug_flag = 1;
99311207Ssam 			printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
99411207Ssam 				ui->ui_unit, addr->hyd_csr, HY_CSR_BITS,
99511207Ssam 				addr->hyd_bar, addr->hyd_wcr);
99611195Ssam #endif
99711207Ssam 		}
998*21128Skarels 		hym->hym_mplen = len;
99911195Ssam #ifdef DEBUG
100011207Ssam 		printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
100111207Ssam 		if (hy_debug_flag)
1002*21128Skarels 			hyprintdata((char *)hym, len + HYM_SWLEN);
100311195Ssam #endif
1004*21128Skarels 		if (hym->hym_ctl & H_ASSOC) {
100511207Ssam 			is->hy_state = RECVDATASENT;
100611207Ssam 			is->hy_retry = 0;
100711207Ssam 			hystart(ui, HYF_INPUTDATA,
1008*21128Skarels 			    (int)(HYMTU + sizeof (struct hy_hdr) - len),
1009*21128Skarels 			    (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len));
101011207Ssam 		} else {
1011*21128Skarels 			hyrecvdata(ui, hym, (int)len + HYM_SWLEN);
101211207Ssam 			is->hy_state = IDLE;
101311195Ssam 		}
101411207Ssam 		break;
101511207Ssam 	}
101611195Ssam 
101711195Ssam 	case RECVDATASENT: {
1018*21128Skarels 		register struct hym_hdr *hym;
101911207Ssam 		register unsigned len;
102011195Ssam 
102111207Ssam 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
102211207Ssam 			UBAPURGE(is->hy_ifuba.ifu_uba,
102313088Ssam 			    is->hy_ifuba.ifu_r.ifrw_bdp);
1024*21128Skarels 		hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
102511207Ssam 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
102611195Ssam #ifdef DEBUG
102711207Ssam 		printD("hy%d: recvd assoc data, len = %d, data = ",
102811207Ssam 			ui->ui_unit, len);
102911207Ssam 		if (hy_debug_flag)
1030*21128Skarels 			hyprintdata((char *)hym + hym->hym_mplen, len);
103111195Ssam #endif
1032*21128Skarels 		hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN));
103311207Ssam 		is->hy_state = IDLE;
103411207Ssam 		break;
103511207Ssam 	}
103611195Ssam 
103711195Ssam 	case XMITSENT:
103811207Ssam 		if (is->hy_flags & RQ_XASSOC) {
103913196Sroot 			register int len;
104011195Ssam 
104111207Ssam 			is->hy_flags &= ~RQ_XASSOC;
104211207Ssam 			is->hy_state = XMITDATASENT;
104311207Ssam 			is->hy_retry = 0;
104411207Ssam 			len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
104511207Ssam 			if (len > is->hy_olen) {
104611207Ssam 				printf(
104711207Ssam 				"hy%d: xmit error - len > hy_olen [%d > %d]\n",
104811207Ssam 				ui->ui_unit, len, is->hy_olen);
104911195Ssam #ifdef DEBUG
105011207Ssam 				hy_debug_flag = 1;
105111195Ssam #endif
105211195Ssam 			}
105311207Ssam 			hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
1054*21128Skarels 			    is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len);
105511207Ssam 			break;
105611207Ssam 		}
105711207Ssam 		/* fall through to ... */
105811195Ssam 
105911195Ssam 	case XMITDATASENT:
106011207Ssam 		hyxmitdata(ui);
106111207Ssam 		is->hy_state = IDLE;
106211207Ssam 		break;
106311195Ssam 
106411195Ssam 	case WAITING:	/* wait for message complete or output requested */
106511207Ssam 		if (HYS_RECVDATA(addr))
106611195Ssam 			is->hy_state = IDLE;
106711195Ssam 		else {
106811195Ssam 			is->hy_state = CLEARSENT;
106911195Ssam 			is->hy_retry = 0;
107011195Ssam 			hystart(ui, HYF_CLRWFMSG, 0, 0);
107111195Ssam 		}
107211195Ssam 		break;
107311195Ssam 
107411195Ssam 	case MARKPORT:
107511195Ssam 		is->hy_state = STARTUP;
1076*21128Skarels 		if_down(&is->hy_if);
107711195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
107811195Ssam 		goto endintr;
107911195Ssam 
108011195Ssam 	default:
108111207Ssam 		printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
108211207Ssam 			ui->ui_unit, is->hy_state);
108311195Ssam 		panic("HYPERCHANNEL IN INVALID STATE");
108411195Ssam 		/*NOTREACHED*/
108511207Ssam 	}
108611195Ssam 	if (is->hy_state == IDLE)
108711195Ssam 		goto actloop;
108811195Ssam endintr:
108913088Ssam 	;
109011195Ssam #ifdef DEBUG
109111207Ssam 	printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit,
109211207Ssam 		hy_state_names[is->hy_state]);
109311195Ssam #endif
109411207Ssam }
109511195Ssam 
1096*21128Skarels struct sockproto hypproto = { PF_HYLINK };
1097*21128Skarels struct sockaddr_in hypdst = { AF_HYLINK };
1098*21128Skarels struct sockaddr_in hypsrc = { AF_HYLINK };
1099*21128Skarels 
110011195Ssam /*
110113088Ssam  * Called from device interrupt when receiving data.
110211195Ssam  * Examine packet to determine type.  Decapsulate packet
110311195Ssam  * based on type and pass to type specific higher-level
110411195Ssam  * input routine.
110511195Ssam  */
1106*21128Skarels hyrecvdata(ui, hym, len)
110711195Ssam 	struct uba_device *ui;
1108*21128Skarels 	register struct hym_hdr *hym;
110911195Ssam 	int len;
111011195Ssam {
111111195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
111211195Ssam     	struct mbuf *m;
111311195Ssam 	register struct ifqueue *inq;
111411195Ssam 
111511195Ssam 	is->hy_if.if_ipackets++;
111611195Ssam #ifdef DEBUG
1117*21128Skarels 	printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len);
111811195Ssam #endif
111911195Ssam #ifdef HYLOG
112011195Ssam 	{
112111195Ssam 		struct {
112211195Ssam 			short hlen;
1123*21128Skarels 			struct hym_hdr hhdr;
112411195Ssam 		} hh;
112511195Ssam 		hh.hlen = len;
1126*21128Skarels 		hh.hhdr = *hym;
112711195Ssam 		hylog(HYL_RECV, sizeof(hh), (char *)&hh);
112811195Ssam 	}
112911195Ssam #endif
113011195Ssam 	if (len > HYMTU + MPSIZE || len == 0)
113111195Ssam 		return;			/* sanity */
113211195Ssam 	/*
113311195Ssam 	 * Pull packet off interface.
113411195Ssam 	 */
113511195Ssam 	m = if_rubaget(&is->hy_ifuba, len, 0);
113611207Ssam 	if (m == NULL)
113711195Ssam 		return;
113811195Ssam 
1139*21128Skarels 	/*
1140*21128Skarels 	 * if normal or adapter loopback response packet believe hym_type,
1141*21128Skarels 	 * otherwise, use the raw input queue cause it's a response from an
1142*21128Skarels 	 * adapter command.
1143*21128Skarels 	 */
1144*21128Skarels 	if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff)
1145*21128Skarels 		goto rawlinkin;
1146*21128Skarels 
1147*21128Skarels 	switch (hym->hym_type) {
1148*21128Skarels 
114911195Ssam #ifdef INET
115011195Ssam 	case HYLINK_IP:
115111195Ssam 		schednetisr(NETISR_IP);
115211195Ssam 		inq = &ipintrq;
115311195Ssam 		break;
115411195Ssam #endif
115511195Ssam 	default:
1156*21128Skarels 	rawlinkin:
1157*21128Skarels 		{
1158*21128Skarels 			struct mbuf *m0;
1159*21128Skarels 
1160*21128Skarels 			MGET(m0, M_DONTWAIT, MT_DATA);
1161*21128Skarels 			if (m == 0) {
1162*21128Skarels 				m_freem(m);
1163*21128Skarels 				return;
1164*21128Skarels 			}
1165*21128Skarels 			m0->m_off = MMINOFF;
1166*21128Skarels 			m0->m_len = sizeof(struct hym_hdr);
1167*21128Skarels 			m0->m_next = m;
1168*21128Skarels 			bcopy((caddr_t)hym, mtod(m0, caddr_t), sizeof(struct hym_hdr));
1169*21128Skarels 			m = m0;
1170*21128Skarels 			hypproto.sp_protocol = 0;
1171*21128Skarels 			hypdst.sin_addr = ((struct sockaddr_in *)&is->hy_if.if_addr)->sin_addr;
1172*21128Skarels 			hypsrc.sin_addr = if_makeaddr(is->hy_if.if_net, is->hy_if.if_host[0]);
1173*21128Skarels 			raw_input(m, &hypproto, (struct sockaddr *)&hypsrc,
1174*21128Skarels 				(struct sockaddr *)&hypdst);
1175*21128Skarels 			return;
1176*21128Skarels 		}
117711195Ssam 	}
117811195Ssam 	if (IF_QFULL(inq)) {
117911195Ssam 		IF_DROP(inq);
118011195Ssam 		m_freem(m);
118111195Ssam 	} else
118211195Ssam 		IF_ENQUEUE(inq, m);
118311207Ssam }
118411195Ssam 
118511195Ssam /*
118611207Ssam  * Transmit done, release resources, bump counters.
118711195Ssam  */
118811195Ssam hyxmitdata(ui)
118911195Ssam 	struct uba_device *ui;
119011195Ssam {
119111195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
119211195Ssam 
119311195Ssam 	is->hy_if.if_opackets++;
119411207Ssam 	if (is->hy_ifuba.ifu_xtofree) {
119511195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
119611195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
119711195Ssam 	}
119811207Ssam }
119911195Ssam 
120011195Ssam hycancel(ui)
120111195Ssam 	register struct uba_device *ui;
120211195Ssam {
120311195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
120411195Ssam 
120511207Ssam 	if (is->hy_ifuba.ifu_xtofree) {
120611195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
120711195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
120811195Ssam 	}
1209*21128Skarels #ifdef HYLOG
1210*21128Skarels 	hylog(HYL_CANCEL, 0, (char *)0);
1211*21128Skarels #endif
121211195Ssam #ifdef DEBUG
121311207Ssam 	if (hy_nodebug & 1)
121411207Ssam 		hy_debug_flag = 1;
121511195Ssam #endif
121611195Ssam #ifdef DEBUG
121711195Ssam 	printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
121811195Ssam 		ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
121911195Ssam 		is->hy_savedcount, is->hy_savedaddr);
1220*21128Skarels 	printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
1221*21128Skarels 		is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry);
122211207Ssam 	printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
122311207Ssam 		is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr,
122411207Ssam 		is->hy_savedcmd);
122511195Ssam #endif
122611195Ssam 	is->hy_state = IDLE;
122711195Ssam 	is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
122811195Ssam 	hyact(ui);
122911207Ssam }
123011195Ssam 
123111195Ssam #ifdef DEBUG
123211195Ssam hyprintdata(cp, len)
123311195Ssam 	register char *cp;
123411195Ssam 	register int len;
123511195Ssam {
123611195Ssam 	register int count = 16;
123711195Ssam 	register char *fmt;
123811195Ssam 	static char regfmt[] = "\n\t %x";
123911195Ssam 
124011195Ssam 	fmt = &regfmt[2];
124111195Ssam 	while (--len >= 0) {
124211195Ssam 		printL(fmt, *cp++ & 0xff);
124311195Ssam 		fmt = &regfmt[2];
124411195Ssam 		if (--count <= 0) {
124511195Ssam 			fmt = &regfmt[0];
124611195Ssam 			count = 16;
124711195Ssam 		}
124811195Ssam 	}
124911195Ssam 	printL("\n");
125011195Ssam }
125111195Ssam #endif
125211195Ssam 
125311195Ssam hywatch(unit)
125413088Ssam 	int unit;
125511195Ssam {
125611195Ssam 	register struct hy_softc *is = &hy_softc[unit];
125711195Ssam 	register struct uba_device *ui = hyinfo[unit];
125811195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
125911195Ssam 	int s;
126011195Ssam 
126111195Ssam 	s = splimp();
126211195Ssam #ifdef PI13
126311195Ssam 	if ((addr->hyd_csr & S_POWEROFF) != 0) {
126411195Ssam 		addr->hyd_csr |= S_POWEROFF;
126511195Ssam 		DELAY(100);
126611195Ssam 		if ((addr->hyd_csr & S_POWEROFF) == 0) {
1267*21128Skarels 			printf("hy%d: Adapter Power Restored (hywatch)\n", unit);
126811195Ssam 			is->hy_state = IDLE;
126911207Ssam 			is->hy_flags |=
127011207Ssam 			  (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
127111195Ssam 			hyact(ui);
127211195Ssam 		}
127311195Ssam 	}
127411195Ssam #endif
1275*21128Skarels 	if (++is->hy_ntime >= 2 && is->hy_state != WAITING &&
1276*21128Skarels 	  is->hy_state != STARTUP && is->hy_state != IDLE) {
1277*21128Skarels #ifdef HYLOG
1278*21128Skarels 		printf("hy%d: watchdog timer expired in state \"%s\"\n", unit,
1279*21128Skarels 			hy_state_names[is->hy_state]);
1280*21128Skarels #else
1281*21128Skarels 		printf("hy%d: watchdog timer expired in state %d\n", unit,
1282*21128Skarels 			is->hy_state);
1283*21128Skarels #endif
1284*21128Skarels 		printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit,
1285*21128Skarels 			is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS);
1286*21128Skarels 		hycancel(ui);
1287*21128Skarels 	}
128811195Ssam 	splx(s);
1289*21128Skarels 	is->hy_if.if_timer = SCANINTERVAL;
129011195Ssam }
129111195Ssam 
129211195Ssam #ifdef HYLOG
129311195Ssam hylog(code, len, ptr)
129413088Ssam 	int code, len;
129511195Ssam 	char *ptr;
129611195Ssam {
129711195Ssam 	register unsigned char *p;
129811195Ssam 	int s;
129911195Ssam 
130011195Ssam 	s = splimp();
130111195Ssam 	if (hy_log.hyl_self != &hy_log) {
130211195Ssam 		hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
130311195Ssam 		hy_log.hyl_ptr = &hy_log.hyl_buf[0];
130411195Ssam 		hy_log.hyl_self = &hy_log;
1305*21128Skarels 		hy_log.hyl_enable = HYL_CONTINUOUS;
1306*21128Skarels 		hy_log.hyl_onerr = HYL_CONTINUOUS;
1307*21128Skarels 		hy_log.hyl_count = 0;
1308*21128Skarels 		hy_log.hyl_icount = 16;
1309*21128Skarels 		hy_log.hyl_filter = 0xffff;	/* enable all */
131011195Ssam 	}
1311*21128Skarels 	if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0)
131211207Ssam 		goto out;
131311195Ssam 	p = hy_log.hyl_ptr;
1314*21128Skarels 	if (p + len + 3 >= hy_log.hyl_eptr) {
131512772Ssam 		bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p));
131611195Ssam 		p = &hy_log.hyl_buf[0];
1317*21128Skarels 		if (hy_log.hyl_enable != HYL_CONTINUOUS) {
1318*21128Skarels 			hy_log.hyl_enable = HYL_DISABLED;
131911195Ssam 			goto out;
132011195Ssam 		}
132111195Ssam 	}
132211195Ssam 	*p++ = code;
132311195Ssam 	*p++ = len;
132413088Ssam 	bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len);
1325*21128Skarels 	if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) {
1326*21128Skarels 		*p++ = '\0';
1327*21128Skarels 		hy_log.hyl_enable = HYL_DISABLED;
1328*21128Skarels 		hy_log.hyl_count = hy_log.hyl_icount;
1329*21128Skarels 	}
1330*21128Skarels 	if (hy_log.hyl_wait != 0) {		/* wakeup HYGETLOG if wanted */
1331*21128Skarels 		hy_log.hyl_wait -= (p - hy_log.hyl_ptr) + len;
1332*21128Skarels 		if (hy_log.hyl_wait <= 0) {
1333*21128Skarels 			wakeup((caddr_t)&hy_log);
1334*21128Skarels 			hy_log.hyl_wait = 0;
1335*21128Skarels 		}
1336*21128Skarels 	}
133711195Ssam 	hy_log.hyl_ptr = p + len;
133811195Ssam out:
133911195Ssam 	splx(s);
134011195Ssam }
134111195Ssam #endif
134211195Ssam 
134312772Ssam /*ARGSUSED*/
134413058Ssam hyioctl(ifp, cmd, data)
134513058Ssam 	register struct ifnet *ifp;
134611207Ssam 	int cmd;
134711207Ssam 	caddr_t	data;
134811195Ssam {
1349*21128Skarels 	struct sockaddr_in *sin = (struct sockaddr_in *)data;
1350*21128Skarels 	struct hyrsetget *sg = (struct hyrsetget *)data;
1351*21128Skarels #if defined(HYLOG) || defined(HYELOG)
1352*21128Skarels 	struct hylsetget *sgl = (struct hylsetget *)data;
1353*21128Skarels #endif
1354*21128Skarels 	struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit];
135511207Ssam 	int s = splimp(), error = 0;
1356*21128Skarels #ifdef HYLOG
1357*21128Skarels 	struct hy_softc *is = &hy_softc[ifp->if_unit];
1358*21128Skarels 	struct {
1359*21128Skarels 		u_char	hstate;
1360*21128Skarels 		u_char	hflags;
1361*21128Skarels 		u_short	iflags;
1362*21128Skarels 		int	hcmd;
1363*21128Skarels 		int	herror;
1364*21128Skarels 		u_long	haddr;
1365*21128Skarels 		u_long	hmisc;
1366*21128Skarels 	} hil;
136711195Ssam 
1368*21128Skarels 	hil.hmisc = -1;
1369*21128Skarels 	hil.hstate = is->hy_state;
1370*21128Skarels 	hil.hflags = is->hy_flags;
1371*21128Skarels 	hil.hcmd = cmd;
1372*21128Skarels #endif
1373*21128Skarels 
137411195Ssam 	switch(cmd) {
137511195Ssam 
137613065Ssam 	case SIOCSIFADDR:
1377*21128Skarels 		if (sin->sin_family != AF_INET)
1378*21128Skarels 			return(EINVAL);
137913065Ssam 		if (ifp->if_flags & IFF_RUNNING)
138013065Ssam 			if_rtinit(ifp, -1);
1381*21128Skarels #ifdef HYLOG
1382*21128Skarels 		hil.haddr = ((struct sockaddr_in *)&ifp->if_addr)->sin_addr.s_addr;
1383*21128Skarels #endif
1384*21128Skarels 		ifp->if_addr = *(struct sockaddr *)sin;
138513065Ssam 		ifp->if_net = in_netof(sin->sin_addr);
1386*21128Skarels 		hyinit(ifp->if_unit);
138713065Ssam 		break;
138813065Ssam 
138911195Ssam 	case HYSETROUTE:
139011207Ssam 		if (!suser()) {
139111207Ssam 			error = EPERM;
1392*21128Skarels 			goto out;
139311195Ssam 		}
1394*21128Skarels 
1395*21128Skarels 		if (sg->hyrsg_len != sizeof(struct hy_route)) {
1396*21128Skarels 			error = EINVAL;
1397*21128Skarels 			goto out;
1398*21128Skarels 		}
1399*21128Skarels 		if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) {
1400*21128Skarels 			r->hyr_lasttime = 0;	/* disable further routing if trouble */
1401*21128Skarels 			error = EFAULT;
1402*21128Skarels 			goto out;
1403*21128Skarels 		}
1404*21128Skarels 		r->hyr_lasttime = time.tv_sec;
1405*21128Skarels #ifdef HYLOG
1406*21128Skarels 		hil.hmisc = r->hyr_lasttime;
1407*21128Skarels #endif
140811195Ssam 		break;
140911195Ssam 
141011195Ssam 	case HYGETROUTE:
1411*21128Skarels 		if (sg->hyrsg_len < sizeof(struct hy_route)) {
1412*21128Skarels 			error = EINVAL;
1413*21128Skarels 			goto out;
1414*21128Skarels 		}
1415*21128Skarels 		if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) {
1416*21128Skarels 			error = EFAULT;
1417*21128Skarels 			goto out;
1418*21128Skarels 		}
141911195Ssam 		break;
142011195Ssam 
1421*21128Skarels #ifdef HYELOG
1422*21128Skarels 	case HYGETELOG:
1423*21128Skarels 		if (sgl->hylsg_len < sizeof(hy_elog)) {
1424*21128Skarels 			error = EINVAL;
1425*21128Skarels 			goto out;
1426*21128Skarels 		}
1427*21128Skarels 		if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) {
1428*21128Skarels 			error = EFAULT;
1429*21128Skarels 			goto out;
1430*21128Skarels 		}
1431*21128Skarels 		if (sgl->hylsg_cmd) {
1432*21128Skarels 			if (!suser()) {
1433*21128Skarels 				error = EPERM;
1434*21128Skarels 				goto out;
1435*21128Skarels 			}
1436*21128Skarels 			bzero((caddr_t)hy_elog, sizeof(hy_elog));
1437*21128Skarels 		}
1438*21128Skarels 		break;
1439*21128Skarels #endif
1440*21128Skarels 
1441*21128Skarels #ifdef HYLOG
1442*21128Skarels 	case HYSETLOG:
1443*21128Skarels 		if (!suser()) {
1444*21128Skarels 			error = EPERM;
1445*21128Skarels 			goto out;
1446*21128Skarels 		}
1447*21128Skarels 		hy_log.hyl_enable = HYL_DISABLED;
1448*21128Skarels 		hylog(HYL_NOP, 0, (char *)0);		/* force log init */
1449*21128Skarels 		hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f;
1450*21128Skarels 		hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f;
1451*21128Skarels 		hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff;
1452*21128Skarels 		hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len;
1453*21128Skarels 		wakeup((caddr_t)&hy_log);	/* wakeup sleeping HYGETLOG */
1454*21128Skarels 		break;
1455*21128Skarels 
1456*21128Skarels 	case HYGETLOG:
1457*21128Skarels 		if (sgl->hylsg_len < sizeof(hy_log)) {
1458*21128Skarels 			error = EINVAL;
1459*21128Skarels 			goto out;
1460*21128Skarels 		}
1461*21128Skarels 		if (sgl->hylsg_cmd != 0) {
1462*21128Skarels 			if (hy_log.hyl_wait) {
1463*21128Skarels 				error = EBUSY;
1464*21128Skarels 				goto out;
1465*21128Skarels 			}
1466*21128Skarels 			hy_log.hyl_wait = sgl->hylsg_cmd;
1467*21128Skarels 			sleep((caddr_t)&hy_log);
1468*21128Skarels 		}
1469*21128Skarels 
1470*21128Skarels 		if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) {
1471*21128Skarels 			error = EFAULT;
1472*21128Skarels 			goto out;
1473*21128Skarels 		}
1474*21128Skarels 		break;
1475*21128Skarels #endif
1476*21128Skarels 
147711195Ssam 	default:
147813058Ssam 		error = EINVAL;
147911195Ssam 		break;
148011195Ssam 	}
1481*21128Skarels out:
1482*21128Skarels #ifdef HYLOG
1483*21128Skarels 	hil.herror = error;
1484*21128Skarels 	hil.iflags = ifp->if_flags;
1485*21128Skarels 	hil.haddr = ((struct sockaddr_in *)&ifp->if_addr)->sin_addr.s_addr;
1486*21128Skarels 	hylog(HYL_IOCTL, sizeof(hil), (char *)&hil);
1487*21128Skarels #endif
148811195Ssam 	splx(s);
148911207Ssam 	return (error);
149011195Ssam }
149111207Ssam #endif
1492