xref: /csrg-svn/sys/vax/if/if_hy.c (revision 35322)
123294Smckusick /*
2*35322Sbostic  * Copyright (c) 1988 Regents of the University of California.
3*35322Sbostic  * All rights reserved.
4*35322Sbostic  *
5*35322Sbostic  * This code is derived from software contributed to Berkeley by
6*35322Sbostic  * Tektronix Inc.
7*35322Sbostic  *
8*35322Sbostic  * Redistribution and use in source and binary forms are permitted
9*35322Sbostic  * provided that the above copyright notice and this paragraph are
10*35322Sbostic  * duplicated in all such forms and that any documentation,
11*35322Sbostic  * advertising materials, and other materials related to such
12*35322Sbostic  * distribution and use acknowledge that the software was developed
13*35322Sbostic  * by the University of California, Berkeley.  The name of the
14*35322Sbostic  * University may not be used to endorse or promote products derived
15*35322Sbostic  * from this software without specific prior written permission.
16*35322Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17*35322Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18*35322Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19*35322Sbostic  *
20*35322Sbostic  *	@(#)if_hy.c	7.2 (Berkeley) 08/04/88
2123294Smckusick  */
2211195Ssam 
2321128Skarels /*
2421128Skarels  * 4.2 BSD Unix Kernel - Vax Network Interface Support
2521128Skarels  *
2621128Skarels  * $Header: if_hy.c,v 10.1 84/07/22 21:02:56 steveg Exp $
2721128Skarels  * $Locker:  $
2821128Skarels  *
2921128Skarels  * Modifications from Berkeley 4.2 BSD
3021128Skarels  * Copyright (c) 1983, Tektronix Inc.
3121128Skarels  * All Rights Reserved
3221128Skarels  *
3321128Skarels  * $Log:	if_hy.c,v $
3421128Skarels  *	Revision 10.1  84/07/22  21:02:56  steveg
3521128Skarels  *	define PI13 (moved from if_hyreg.h, somehow got dropped in the process)
3621128Skarels  *	rework hywatch to check for power fails first
3721128Skarels  *
3821128Skarels  *	Revision 10.0  84/06/30  19:54:27  steveg
3921128Skarels  *	Big Build
4021128Skarels  *
4121128Skarels  *	Revision 3.17  84/06/20  19:20:28  steveg
4221128Skarels  *	increment hy_ntime in hywatch
4321128Skarels  *	print out state name, csr, last command, and hy_flags when watchdog timer
4421128Skarels  *	expires
4521128Skarels  *
4621128Skarels  *	Revision 3.16  84/06/20  19:09:34  steveg
4721128Skarels  *	turn on continuous logging by default
4821128Skarels  *
4921128Skarels  *	Revision 3.15  84/05/30  22:19:09  steveg
5021128Skarels  *	changes to reflect new layout ot statistics data
5121128Skarels  *
5221128Skarels  *	Revision 3.14  84/05/30  19:25:15  steveg
5321128Skarels  *	move driver states to if_hy.h so log printing programs can use them
5421128Skarels  *
5521128Skarels  *	Revision 3.13  84/05/30  17:13:26  steveg
5621128Skarels  *	make it compile
5721128Skarels  *
5821128Skarels  *	Revision 3.12  84/05/30  13:46:16  steveg
5921128Skarels  *	rework logging
6021128Skarels  *
6121128Skarels  *	Revision 3.11  84/05/18  19:35:02  steveg
6221128Skarels  *	clear IFF_RUNNING and IFF_UP on unibus reset to force resource allocation
6321128Skarels  *	by the init routine
6421128Skarels  *
6521128Skarels  *	Revision 3.10  84/05/04  12:14:44  steveg
6621128Skarels  *	more rework to make it actually work under 4.2
6721128Skarels  *
6821128Skarels  *	Revision 3.9  84/05/01  23:34:52  steveg
6921128Skarels  *	fix typo so it compiles (unit -> ui->ui_unit)
7021128Skarels  *
7121128Skarels  *	Revision 3.8  84/05/01  23:18:30  steveg
7221128Skarels  *	changes after talking with rickk
7321128Skarels  *	- check power off more closely
7421128Skarels  *	- support remote loopback through A710 adapters
7521128Skarels  *	- IMPLINK -> HYLINK
7621128Skarels  *	- return EHOSTUNREACH on hyroute failure
7721128Skarels  *	- bump if_collisions on abnormal interrupts that aren't input or output
7821128Skarels  *
7921128Skarels  *
8021128Skarels  */
8121128Skarels 
8221128Skarels 
8311195Ssam #include "hy.h"
8411195Ssam #if NHY > 0
8511195Ssam 
8611195Ssam /*
8711195Ssam  * Network Systems Copropration Hyperchanel interface
8811195Ssam  */
8921128Skarels #include "machine/pte.h"
9011195Ssam 
9121775Skarels #include "param.h"
9221775Skarels #include "systm.h"
9321775Skarels #include "mbuf.h"
9421775Skarels #include "buf.h"
9521775Skarels #include "protosw.h"
9621775Skarels #include "socket.h"
9721775Skarels #include "vmmac.h"
9821775Skarels #include "errno.h"
9921775Skarels #include "time.h"
10021775Skarels #include "kernel.h"
10121775Skarels #include "ioctl.h"
10213088Ssam 
10311195Ssam #include "../net/if.h"
10411207Ssam #include "../net/netisr.h"
10511195Ssam #include "../net/route.h"
10624797Skarels 
10724797Skarels #ifdef	INET
10811195Ssam #include "../netinet/in.h"
10911195Ssam #include "../netinet/in_systm.h"
11024797Skarels #include "../netinet/in_var.h"
11111195Ssam #include "../netinet/ip.h"
11224797Skarels #endif
11311195Ssam 
11411207Ssam #include "../vax/cpu.h"
11511207Ssam #include "../vax/mtpr.h"
11611207Ssam #include "../vaxuba/ubareg.h"
11711207Ssam #include "../vaxuba/ubavar.h"
11811195Ssam 
11921128Skarels /*
12021128Skarels  * configuration specific paramters
12121128Skarels  *	- change as appropriate for particular installaions
12221128Skarels  */
12321128Skarels #define	HYROUTE
12421128Skarels #define	HYELOG
12521128Skarels #define	HYLOG
12621128Skarels #define	HYMTU	1100
12721128Skarels #define PI13
12811195Ssam 
12921128Skarels #ifdef	DEBUG
13021128Skarels #define	HYLOG
13121128Skarels #endif
13221128Skarels 
13321775Skarels #include "if_hy.h"
13421775Skarels #include "if_hyreg.h"
13521775Skarels #include "if_uba.h"
13621128Skarels 
13713058Ssam int	hyprobe(), hyattach(), hyinit(), hyioctl();
13813058Ssam int	hyoutput(), hyreset(), hywatch();
13911195Ssam struct	uba_device *hyinfo[NHY];
14011195Ssam u_short hystd[] = { 0772410, 0 };
14111195Ssam struct	uba_driver hydriver =
14211195Ssam 	{ hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo };
14311195Ssam 
14411195Ssam /*
14511195Ssam  * Hyperchannel software status per interface.
14611195Ssam  *
14711195Ssam  * Each interface is referenced by a network interface structure,
14811195Ssam  * hy_if, which the routing code uses to locate the interface.
14911195Ssam  * This structure contains the output queue for the interface, its address, ...
15011195Ssam  * We also have, for each interface, a UBA interface structure, which
15111195Ssam  * contains information about the UNIBUS resources held by the interface:
15211195Ssam  * map registers, buffered data paths, etc.  Information is cached in this
15311195Ssam  * structure for use by the if_uba.c routines in running the interface
15411195Ssam  * efficiently.
15511195Ssam  */
15611195Ssam struct	hy_softc {
15711195Ssam 	struct	ifnet hy_if;		/* network-visible interface */
15811195Ssam 	struct	ifuba hy_ifuba;		/* UNIBUS resources */
15911207Ssam 	short	hy_flags;		/* flags */
16011207Ssam 	short	hy_state;		/* driver state */
16121775Skarels 	u_short	hy_host;		/* local host number */
16221775Skarels 	struct	in_addr hy_addr;	/* internet address */
16311195Ssam 	int	hy_olen;		/* packet length on output */
16411195Ssam 	int	hy_lastwcr;		/* last command's word count */
16511195Ssam 	short	hy_savedstate;		/* saved for reissue after status */
16611195Ssam 	short	hy_savedcmd;		/* saved command for reissue */
16711195Ssam 	int	hy_savedcount;		/* saved byte count for reissue */
16811195Ssam 	int	hy_savedaddr;		/* saved unibus address for reissue */
16911195Ssam 	int	hy_ntime;		/* number of timeouts since last cmd */
17011195Ssam 	int	hy_retry;		/* retry counter */
17111207Ssam 	struct	hy_stat hy_stat;	/* statistics */
17211207Ssam 	struct	hy_status hy_status;	/* status */
17311195Ssam } hy_softc[NHY];
17411195Ssam 
17511195Ssam #ifdef HYELOG
17621128Skarels u_long	hy_elog[HYE_SIZE];
17711195Ssam #endif
17811195Ssam 
17921128Skarels #ifdef HYLOG
18021128Skarels struct hy_log hy_log;
18121128Skarels #endif
18221128Skarels 
18321128Skarels #ifdef HYROUTE
18421128Skarels struct hy_route hy_route[NHY];
18521128Skarels #endif
18621128Skarels 
18711195Ssam #ifdef DEBUG
18821128Skarels #define printL	printf
18921128Skarels #define printD	if (hy_debug_flag) printf
19011195Ssam int	hy_debug_flag = 0;
19111195Ssam /*
19211195Ssam  * hy_nodebug bit 0x01	set hy_debug_flag on hycancel
19311195Ssam  * hy_nodebug bit 0x02	set hy_debug_flag on command reissue
19411195Ssam  * hy_nodebug bit 0x04	set hy_debug_flag on abnormal interrupt
19511195Ssam  */
19611195Ssam int	hy_nodebug = 0x0;
19711195Ssam #endif
19811195Ssam 
19911195Ssam #define SCANINTERVAL	10	/* seconds */
20011195Ssam #define MAXINTERVAL	20	/* seconds (max action) */
20111195Ssam 
20211195Ssam /*
20311195Ssam  * Cause a device interrupt.  This code uses a buffer starting at
20411195Ssam  * location zero on the unibus (which is already mapped by the
20511195Ssam  * autoconfigure code in the kernel).
20611195Ssam  */
20711195Ssam hyprobe(reg)
20811195Ssam 	caddr_t reg;
20911195Ssam {
21011195Ssam 	register int br, cvec;		/* r11, r10 value-result */
21111195Ssam 	register struct hydevice *addr = (struct hydevice *) reg;
21211195Ssam 
21311195Ssam #ifdef lint
21411195Ssam 	br = 0; cvec = br; br = cvec;
21511195Ssam 	hyint(0);
21611195Ssam #endif
21711195Ssam 	/*
21811195Ssam 	 * request adapter status to a buffer starting at unibus location 0
21911195Ssam 	 */
22011195Ssam 	addr->hyd_bar = 0;
22111195Ssam 	addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1);
22211195Ssam 	addr->hyd_dbuf = HYF_STATUS;
22311195Ssam #ifdef PI13
22411195Ssam 	addr->hyd_csr |= S_GO | S_IE | S_IATTN;
22511195Ssam #else
22611195Ssam 	addr->hyd_csr |= S_GO | S_IE;
22711195Ssam #endif
22811195Ssam 	DELAY(10000);
22911195Ssam #ifdef PI13
23011195Ssam 	addr->hyd_csr |= S_CLRINT;	/* clear any stacked interrupts */
23111195Ssam #endif
23211195Ssam 	addr->hyd_csr &= ~(S_IE | S_CLRINT);	/* disable further interrupts */
23321128Skarels 	return(sizeof(struct hydevice));
23411207Ssam }
23511195Ssam 
23611195Ssam /*
23711195Ssam  * Interface exists: make available by filling in network interface
23811195Ssam  * record.  System will initialize the interface when it is ready
23911195Ssam  * to accept packets.
24011195Ssam  */
24111195Ssam hyattach(ui)
24211195Ssam 	struct uba_device *ui;
24311195Ssam {
24411195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
24511195Ssam 	register struct ifnet *ifp = &is->hy_if;
24611195Ssam 
24711195Ssam 	ifp->if_unit = ui->ui_unit;
24811195Ssam 	ifp->if_name = "hy";
24911195Ssam 	ifp->if_mtu = HYMTU;
25011195Ssam 	is->hy_state = STARTUP;		/* don't allow state transitions yet */
25111195Ssam 	ifp->if_init = hyinit;
25213058Ssam 	ifp->if_ioctl = hyioctl;
25311195Ssam 	ifp->if_output = hyoutput;
25411207Ssam 	ifp->if_reset = hyreset;
25511195Ssam 	ifp->if_watchdog = hywatch;
25611195Ssam 	ifp->if_timer = SCANINTERVAL;
25711195Ssam 	is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
25811207Ssam #ifdef notdef
25911195Ssam 	is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
26011195Ssam #endif
26111195Ssam 	if_attach(ifp);
26211207Ssam }
26311195Ssam 
26411195Ssam /*
26511195Ssam  * Reset of interface after UNIBUS reset.
26611195Ssam  * If interface is on specified uba, reset its state.
26711195Ssam  */
26811195Ssam hyreset(unit, uban)
26911195Ssam 	int unit, uban;
27011195Ssam {
27121128Skarels 	register struct uba_device *ui;
27221128Skarels 	register struct hy_softc *is;
27311195Ssam 
27421128Skarels 	if (unit >= NHY || (ui = hyinfo[unit]) == 0 || ui->ui_alive == 0 ||
27511207Ssam 	  ui->ui_ubanum != uban)
27611195Ssam 		return;
27711195Ssam 	printf(" hy%d", unit);
27821128Skarels 	is = &hy_softc[unit];		/* force unibus resource allocation */
27921128Skarels 	is->hy_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
28011195Ssam 	hyinit(unit);
28111207Ssam }
28211195Ssam 
28311195Ssam /*
28411195Ssam  * Initialization of interface; clear recorded pending
28511195Ssam  * operations, and reinitialize UNIBUS usage.
28611195Ssam  */
28711195Ssam hyinit(unit)
28811195Ssam 	int unit;
28911195Ssam {
29011195Ssam 	register struct hy_softc *is = &hy_softc[unit];
29111195Ssam 	register struct uba_device *ui = hyinfo[unit];
29221128Skarels 	register struct mbuf *m;
29311195Ssam 	int s;
29411195Ssam 
29521775Skarels 	if (is->hy_if.if_addrlist == 0)		/* address still unknown */
29613065Ssam 		return;
29721128Skarels 	if (is->hy_if.if_flags & IFF_RUNNING)	/* just reset the device */
29821128Skarels 		goto justreset;
29911195Ssam 	if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
30021128Skarels 	    sizeof (struct hym_hdr), (int)btoc(HYMTU)) == 0) {
30111195Ssam #ifdef DEBUG
30211207Ssam 		if (hy_nodebug & 4)
30311207Ssam 			hy_debug_flag = 1;
30411195Ssam #endif
30511195Ssam 		printf("hy%d: can't initialize\n", unit);
30611195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
30711195Ssam 		return;
30811195Ssam 	}
30913088Ssam 	is->hy_if.if_flags |= IFF_RUNNING;
31021128Skarels 
31121128Skarels justreset:
31211195Ssam 	/*
31321128Skarels 	 * remove any left over outgoing messages, reset the hardware and
31421128Skarels 	 * start the state machine
31511195Ssam 	 */
31611195Ssam 	s = splimp();
31721128Skarels #ifdef HYLOG
31821128Skarels 	hylog(HYL_RESET, 0, (char *)0);
31921128Skarels #endif
32011195Ssam 	is->hy_state = IDLE;
32111195Ssam 	is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
32211195Ssam 	is->hy_retry = 0;
32321128Skarels 	for(;;) {
32421128Skarels 		IF_DEQUEUE(&is->hy_if.if_snd, m);
32521128Skarels 		if (m != NULL)
32621128Skarels 			m_freem(m);
32721128Skarels 		else
32821128Skarels 			break;
32921128Skarels 	}
33021128Skarels 	hycancel(ui);		/* also bumps the state machine */
33111195Ssam 	splx(s);
33211207Ssam }
33311195Ssam 
33411195Ssam /*
33511207Ssam  * Issue a command to the adapter
33611195Ssam  */
33711195Ssam hystart(ui, cmd, count, ubaddr)
33811195Ssam 	struct uba_device *ui;
33911207Ssam 	int cmd, count, ubaddr;
34011195Ssam {
34111195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
34211195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
34311195Ssam 
34411195Ssam #ifdef DEBUG
34511207Ssam 	printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
34611207Ssam 		ui->ui_unit, cmd, count, ubaddr);
34711195Ssam 	printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
34811207Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
34911207Ssam 		addr->hyd_wcr);
35011195Ssam #endif
35111207Ssam 	if (((is->hy_flags & RQ_REISSUE) == 0) &&
35211207Ssam 	  (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
35311195Ssam 		is->hy_savedstate = is->hy_state;
35411195Ssam 		is->hy_savedcmd = cmd;
35511195Ssam 		is->hy_savedcount = count;
35611195Ssam 		is->hy_savedaddr = ubaddr;
35711195Ssam 	}
35821128Skarels #ifdef PI13
35921128Skarels 	if (addr->hyd_csr & S_POWEROFF) {
36021128Skarels 		printf("hy%d: \"Soft\" Adapter Power Failure (hystart)\n", ui->ui_unit);
36121128Skarels 		addr->hyd_csr |= S_POWEROFF;
36221128Skarels 		DELAY(100);
36321128Skarels 		if (addr->hyd_csr & S_POWEROFF) {
36421128Skarels 			printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hystart)\n", ui->ui_unit);
36521128Skarels 			if_down(&is->hy_if);
36621128Skarels 			is->hy_if.if_flags &= ~IFF_UP;
36721128Skarels 			is->hy_state = STARTUP;
36821128Skarels 		} else {
36921128Skarels 			printf("hy%d: Adapter Power Restored (hystart)\n", ui->ui_unit);
37021128Skarels 		}
37121128Skarels 		return;
37221128Skarels 	}
37321128Skarels #endif
37411195Ssam 	addr->hyd_bar = ubaddr & 0xffff;
37511207Ssam 	addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);
37611195Ssam 	addr->hyd_dbuf = cmd;
37711195Ssam #ifdef PI13
37811195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN;
37911195Ssam #else
38011195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE;
38111195Ssam #endif
38211195Ssam #ifdef DEBUG
38311195Ssam 	printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
38411207Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
38511207Ssam 		addr->hyd_wcr);
38611195Ssam #endif
38711195Ssam #ifdef HYLOG
38811195Ssam 	{
38911195Ssam 		struct {
39011207Ssam 			u_char	hcmd;
39111207Ssam 			u_char	hstate;
39211207Ssam 			short	hcount;
39311195Ssam 		} hcl;
39411195Ssam 
39511195Ssam 		hcl.hcmd = cmd;
39611195Ssam 		hcl.hstate = is->hy_state;
39711195Ssam 		hcl.hcount = count;
39811195Ssam 		hylog(HYL_CMD, sizeof(hcl), (char *)&hcl);
39911195Ssam 	}
40011195Ssam #endif
40111195Ssam 	is->hy_ntime = 0;
40211207Ssam }
40311195Ssam 
40411195Ssam int hyint_active = 0;		/* set during hy interrupt */
40511195Ssam /*
40611207Ssam  * Hyperchannel interface interrupt.
40711195Ssam  *
40811195Ssam  * An interrupt can occur for many reasons.  Examine the status of
40911195Ssam  * the hyperchannel status bits to determine what to do next.
41011195Ssam  *
41111195Ssam  * If input error just drop packet.
41211195Ssam  * Otherwise purge input buffered data path and examine
41311195Ssam  * packet to determine type.  Othewise decapsulate
41411195Ssam  * packet based on type and pass to type specific higher-level
41511195Ssam  * input routine.
41611195Ssam  */
41711195Ssam hyint(unit)
41811195Ssam 	int unit;
41911195Ssam {
42011195Ssam 	register struct hy_softc *is = &hy_softc[unit];
42111195Ssam 	register struct uba_device *ui = hyinfo[unit];
42211207Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
42311195Ssam 
42411207Ssam 	if (hyint_active)
42511195Ssam 		panic("RECURSIVE HYPERCHANNEL INTERRUPT");
42611195Ssam 	hyint_active++;
42711195Ssam #ifdef DEBUG
42811195Ssam 	printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
42911195Ssam 		unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
43011195Ssam #endif
43111195Ssam #ifdef HYLOG
43211195Ssam logit:
43311195Ssam 	{
43411195Ssam 		struct {
43511207Ssam 			u_char	hstate;
43611207Ssam 			u_char	hflags;
43711207Ssam 			short	hcsr;
43811207Ssam 			short	hwcr;
43911195Ssam 		} hil;
44011195Ssam 		hil.hstate = is->hy_state;
44111195Ssam 		hil.hflags = is->hy_flags;
44211195Ssam 		hil.hcsr = addr->hyd_csr;
44311195Ssam 		hil.hwcr = addr->hyd_wcr;
44411195Ssam 		hylog(HYL_INT, sizeof(hil), (char *)&hil);
44511195Ssam 	}
44611195Ssam #endif
44711207Ssam 	if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
44811195Ssam 		/*
44911207Ssam 		 * Error bit set, some sort of error in the interface.
45011195Ssam 		 *
45111207Ssam 		 * The adapter sets attn on command completion so that's not
45211207Ssam 		 * a real error even though the interface considers it one.
45311195Ssam 		 */
45411195Ssam #ifdef DEBUG
45511207Ssam 		if (hy_nodebug & 4)
45611207Ssam 			hy_debug_flag = 1;
45711195Ssam #endif
45811207Ssam 		printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n",
45911207Ssam 			addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
46011207Ssam 			addr->hyd_wcr);
46111207Ssam 		if (addr->hyd_csr & S_NEX) {
46211195Ssam 			printf("hy%d: NEX - Non Existant Memory\n", unit);
46311195Ssam #ifdef PI13
46411195Ssam 			addr->hyd_csr |= S_NEX;  /* as per PI13 manual */
46511195Ssam #else
46611195Ssam 			addr->hyd_csr &= ~S_NEX;
46711195Ssam #endif
46811195Ssam 			hycancel(ui);
46911195Ssam #ifdef PI13
47011207Ssam 		} else if (addr->hyd_csr & S_POWEROFF) {
47121128Skarels 			printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit);
47211195Ssam 			addr->hyd_csr |= S_POWEROFF;
47311195Ssam 			DELAY(100);
47411207Ssam 			if (addr->hyd_csr & S_POWEROFF) {
47521128Skarels 				printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit);
47611195Ssam 				if_down(&is->hy_if);
47721128Skarels 				is->hy_if.if_flags &= ~IFF_UP;
47811195Ssam 				is->hy_state = STARTUP;
47921128Skarels 			} else {
48021128Skarels 				printf("hy%d: Adapter Power Restored (hyint)\n", unit);
48111195Ssam 			}
48211195Ssam #endif
48311195Ssam 		} else {
48411195Ssam 			printf("hy%d:  BAR overflow\n", unit);
48511195Ssam 			hycancel(ui);
48611195Ssam 		}
48711207Ssam 	} else if (HYS_NORMAL(addr)) {
48811195Ssam 		/*
48911207Ssam 		 * Normal interrupt, bump state machine unless in state
49011195Ssam 		 * waiting and no data present (assumed to be word count
49111207Ssam 		 * zero interrupt or other hardware botch).
49211195Ssam 		 */
49311207Ssam 		if (is->hy_state != WAITING || HYS_RECVDATA(addr))
49411195Ssam 			hyact(ui);
49511207Ssam 	} else if (HYS_ABNORMAL(addr)) {
49611195Ssam 		/*
49711207Ssam 		 * Abnormal termination.
49811195Ssam 		 * bump error counts, retry the last function
49911195Ssam 		 * 'MAXRETRY' times before kicking the bucket.
50011195Ssam 		 *
50111207Ssam 		 * Don't reissue the cmd if in certain states, abnormal
50211207Ssam 		 * on a reissued cmd or max retry exceeded.
50311195Ssam 		 */
50411195Ssam #ifdef HYLOG
50511195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
50611195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
50711195Ssam 			goto logit;
50811195Ssam 		}
50911195Ssam #endif
51011195Ssam #ifdef DEBUG
51111207Ssam 		if (hy_nodebug & 4)
51211207Ssam 			hy_debug_flag = 1;
51311195Ssam 		printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
51411195Ssam 			unit, hy_state_names[is->hy_state], is->hy_state);
51521128Skarels 		printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
51621128Skarels 			is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry);
51711207Ssam 		printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
51811207Ssam 			is->hy_savedstate, is->hy_savedcount,
51911207Ssam 			is->hy_savedaddr, is->hy_savedcmd);
52011195Ssam #endif
52111195Ssam #ifdef PI13
52211195Ssam 		addr->hyd_csr &= ~S_C;  /* clear the damned PI-13 */
52311195Ssam #endif
52411207Ssam 		if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT)
52511195Ssam 			is->hy_if.if_oerrors++;
52621128Skarels 		else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT)
52711195Ssam 			is->hy_if.if_ierrors++;
52821128Skarels 		else
52921128Skarels 			is->hy_if.if_collisions++;	/* other errors */
53011195Ssam 		if (is->hy_state == XMITDATASENT ||
53111195Ssam 		    is->hy_state == RECVSENT ||
53211195Ssam 		    is->hy_state == RECVDATASENT ||
53311207Ssam 		    (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY)
53411195Ssam 			hycancel(ui);
53511207Ssam 		else {
53611195Ssam #ifdef DEBUG
53711207Ssam 			if (hy_nodebug & 2)
53811207Ssam 				hy_debug_flag = 1;
53911195Ssam #endif
54011195Ssam 			is->hy_retry++;
54111195Ssam 			is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE;
54211195Ssam 			is->hy_state = IDLE;
54311195Ssam 			hyact(ui);
54411195Ssam 		}
54511195Ssam 	} else {
54611195Ssam 		/*
54711195Ssam 		 * Interrupt is neither normal, abnormal, or interface error.
54811195Ssam 		 * Ignore it. It's either stacked or a word count 0.
54911195Ssam 		 */
55011195Ssam #ifdef HYLOG
55111195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
55211195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
55311195Ssam 			goto logit;
55411195Ssam 		}
55511195Ssam #endif
55611195Ssam #ifdef DEBUG
55711195Ssam 		printD("hy%d: possible stacked interrupt ignored\n", unit);
55811195Ssam #endif
55911195Ssam 	}
56011195Ssam #ifdef DEBUG
56111195Ssam 	printD("hy%d: hyint exit\n\n", unit);
56211195Ssam #endif
56311195Ssam 	hyint_active = 0;
56411195Ssam 
56511207Ssam }
56611195Ssam 
56721128Skarels int hyoutprint = 0;
56821128Skarels 
56911195Ssam /*
57011195Ssam  * Encapsulate a packet of type family for the local net.
57111195Ssam  */
57211195Ssam hyoutput(ifp, m0, dst)
57311195Ssam 	struct ifnet *ifp;
57411195Ssam 	struct mbuf *m0;
57511195Ssam 	struct sockaddr *dst;
57611195Ssam {
57711195Ssam 	register struct hym_hdr *hym;
57811195Ssam 	register struct mbuf *m;
57921128Skarels 	register char *mp;
58021128Skarels 	int dlen;	/* packet size, incl hardware header, but not sw header */
58111195Ssam 	int error = 0;
58211195Ssam 	int s;
58311195Ssam 
58421128Skarels 	/*
58521128Skarels 	 * Calculate packet length for later deciding whether it will fit
58621128Skarels 	 * in a message proper or we also need associated data.
58721128Skarels 	 */
58811195Ssam 	dlen = 0;
58911195Ssam 	for (m = m0; m; m = m->m_next)
59011195Ssam 		dlen += m->m_len;
59111195Ssam 	m = m0;
59221128Skarels 	if (dst->sa_family == AF_HYLINK) {	/* don't add header */
59321128Skarels 		dlen -= HYM_SWLEN;
59421128Skarels 		goto headerexists;
59521128Skarels 	}
59621128Skarels 
59721128Skarels 	/*
59821128Skarels 	 * Add the software and hardware hyperchannel headers.
59921128Skarels 	 * If there's not enough space in the first mbuf, allocate another.
60021128Skarels 	 * If that should fail, drop this sucker.
60121128Skarels 	 * No extra space for headers is allocated.
60221128Skarels 	 */
60321128Skarels 	mp = mtod(m, char *);	/* save pointer to real message */
60421128Skarels 	if (m->m_off > MMAXOFF ||
60521128Skarels 	    MMINOFF + sizeof(struct hym_hdr) > m->m_off) {
60621128Skarels 		m = m_get(M_DONTWAIT, MT_HEADER);
60721128Skarels 		if (m == 0) {
60821128Skarels 			m = m0;
60921128Skarels 			error = ENOBUFS;
61021128Skarels 			goto drop;
61121128Skarels 		}
61221128Skarels 		m->m_next = m0;
61321128Skarels 		m->m_off = MMINOFF;
61421128Skarels 		m->m_len = sizeof(struct hym_hdr);
61521128Skarels 	} else {
61621128Skarels 		m->m_off -= sizeof(struct hym_hdr);
61721128Skarels 		m->m_len += sizeof(struct hym_hdr);
61821128Skarels 	}
61921128Skarels 
62021128Skarels 	dlen += sizeof(struct hym_hdr) - HYM_SWLEN;
62121128Skarels 
62221128Skarels 	hym = mtod(m, struct hym_hdr *);
62321128Skarels 
62421128Skarels 	bzero((caddr_t)hym, sizeof(struct hym_hdr));
62521128Skarels 
62611195Ssam 	switch(dst->sa_family) {
62711195Ssam 
62811195Ssam #ifdef INET
62911195Ssam 	case AF_INET: {
63021128Skarels 		int i;
63111195Ssam 
63211195Ssam 		/*
63321128Skarels 		 * if loopback address, swizzle ip header so when
63421128Skarels 		 * it comes back it looks like it was addressed to us
63511195Ssam 		 */
63621128Skarels 		i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym);
63721128Skarels 		if (i < 0)
63821128Skarels 			goto notfound;
63921128Skarels 		if (i > 0) {
64011195Ssam 			struct in_addr temp;
64111195Ssam 
64221128Skarels 			temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr;
64321128Skarels 			((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr;
64421128Skarels 			((struct ip *)mp)->ip_src.s_addr = temp.s_addr;
64511195Ssam 		}
64611195Ssam 		/*
64711195Ssam 		 * If entire packet won't fit in message proper, just
64811195Ssam 		 * send hyperchannel hardware header and ip header in
64921128Skarels 		 * message proper.
65011195Ssam 		 *
65111195Ssam 		 * This insures that the associated data is at least a
65211195Ssam 		 * TCP/UDP header in length and thus prevents potential
65311195Ssam 		 * problems with very short word counts.
65411195Ssam 		 */
65521128Skarels 		if (dlen > MPSIZE)
65621128Skarels 			hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2);
65721128Skarels 		hym->hym_type = HYLINK_IP;
65811195Ssam 		break;
65911195Ssam 	}
66011195Ssam #endif
66111195Ssam 
66211195Ssam 	default:
66311207Ssam 		printf("hy%d: can't handle af%d\n", ifp->if_unit,
66411207Ssam 			dst->sa_family);
66511195Ssam 		error = EAFNOSUPPORT;
66611195Ssam 		goto drop;
66711195Ssam 	}
66811195Ssam 
66921128Skarels 
67021128Skarels headerexists:
67121128Skarels 
67211195Ssam 	/*
67321128Skarels 	 * insure message proper is below the maximum
67411195Ssam 	 */
67521128Skarels 	if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0))
67621128Skarels 		hym->hym_mplen = MPSIZE;
67711195Ssam 
67821775Skarels 	hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host);
67921128Skarels 	if (hym->hym_mplen)
68021128Skarels 		hym->hym_ctl |= H_ASSOC;
68121128Skarels 	else
68221128Skarels 		hym->hym_ctl &= ~H_ASSOC;
68321128Skarels 	if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
68421128Skarels 		ifp->if_unit, hym->hym_mplen, hym->hym_ctl,
68521128Skarels 		hym->hym_access, hym->hym_to, hym->hym_from,
68621128Skarels 		hym->hym_param, hym->hym_type);
68711195Ssam #ifdef DEBUG
68821128Skarels 	printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
68921128Skarels 		ifp->if_unit, hym->hym_mplen, hym->hym_ctl,
69021128Skarels 		hym->hym_access, hym->hym_to, hym->hym_from,
69121128Skarels 		hym->hym_param, hym->hym_type);
69211195Ssam #endif
69311195Ssam 	s = splimp();
69411195Ssam 	if (IF_QFULL(&ifp->if_snd)) {
69511195Ssam 		IF_DROP(&ifp->if_snd);
69611195Ssam 		error = ENOBUFS;
69711195Ssam 		splx(s);
69811195Ssam 		goto drop;
69911195Ssam 	}
70011195Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
70111195Ssam 	if (hy_softc[ifp->if_unit].hy_state == WAITING)
70211195Ssam 		hyact(hyinfo[ifp->if_unit]);
70311195Ssam 	splx(s);
70411207Ssam 	return (0);
70511195Ssam notfound:
70621128Skarels 	error = EHOSTUNREACH;
70711195Ssam drop:
70811195Ssam 	m_freem(m);
70911207Ssam 	return (error);
71011207Ssam }
71111195Ssam 
71221128Skarels int
71321128Skarels hyroute(ifp, dest, hym)
71421128Skarels 	register struct ifnet *ifp;
71521128Skarels 	u_long dest;
71621128Skarels 	register struct hym_hdr *hym;
71721128Skarels {
71821128Skarels #ifdef HYROUTE
71921128Skarels 	register struct hy_route *rt = &hy_route[ifp->if_unit];
72021128Skarels 	register struct hyr_hash *rhash;
72121128Skarels 	register int i;
72221128Skarels #endif
72321128Skarels 
72421128Skarels 	hym->hym_param = 0;
72521128Skarels #ifdef HYROUTE
72621128Skarels 	if (rt->hyr_lasttime != 0) {
72721128Skarels 		i = HYRHASH(dest);
72821128Skarels 		rhash = &rt->hyr_hash[i];
72921128Skarels 		i = 0;
73021128Skarels 		while (rhash->hyr_key != dest) {
73121128Skarels 			if (rhash->hyr_flags == 0 || i > HYRSIZE)
73221128Skarels 				return(-1);
73321128Skarels 			rhash++; i++;
73421128Skarels 			if (rhash >= &rt->hyr_hash[HYRSIZE])
73521128Skarels 				rhash = &rt->hyr_hash[0];
73621128Skarels 		}
73721128Skarels 		if (rhash->hyr_flags & HYR_GATE) {
73821128Skarels 			i = rhash->hyr_nextgate;
73921128Skarels 			if (i >= rhash->hyr_egate)
74021128Skarels 				rhash->hyr_nextgate = rhash->hyr_pgate;
74121128Skarels 			else
74221128Skarels 				rhash->hyr_nextgate++;
74321128Skarels 			rhash = &rt->hyr_hash[rt->hyr_gateway[i]];
74421128Skarels 			if ((rhash->hyr_flags & HYR_DIR) == 0)
74521128Skarels 				return(-1);
74621128Skarels 		} else if (rhash->hyr_flags & HYR_LOOP) {
74721128Skarels 			hym->hym_param = H_LOOPBK;	/* adapter loopback */
74821128Skarels 		} else if (rhash->hyr_flags & HYR_RLOOP) {
74921128Skarels 			hym->hym_param = H_RLOOPBK;	/* A710 remote loopback */
75021128Skarels 		}
75121128Skarels 		hym->hym_ctl = rhash->hyr_ctl;
75221128Skarels 		hym->hym_access = rhash->hyr_access;
75321128Skarels 		hym->hym_to = rhash->hyr_dst;
75421128Skarels 	} else {
75521128Skarels #endif
75621128Skarels 		hym->hym_ctl = H_XTRUNKS | H_RTRUNKS;
75721128Skarels 		hym->hym_access = 0;
75821128Skarels 		hym->hym_to = htons((u_short)dest);
75921128Skarels 		if (dest & 0x010000)
76021128Skarels 			hym->hym_param = H_LOOPBK;	/* adapter loopback */
76121128Skarels 		else if (dest & 0x020000)
76221128Skarels 			hym->hym_param = H_RLOOPBK;	/* A710 remote loopback */
76321128Skarels #ifdef HYROUTE
76421128Skarels 	}
76521128Skarels #endif
76621128Skarels 
76721128Skarels 	if (hym->hym_param == 0)
76821128Skarels 		return(0);
76921128Skarels 	else
77021128Skarels 		return(1);
77121128Skarels }
77221128Skarels 
77311195Ssam hyact(ui)
77411195Ssam 	register struct uba_device *ui;
77511195Ssam {
77611195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
77711195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
77811195Ssam 
77911195Ssam actloop:
78011195Ssam #ifdef DEBUG
78111207Ssam 	printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
78211207Ssam 		hy_state_names[is->hy_state]);
78311195Ssam #endif
78411195Ssam 	switch (is->hy_state) {
78511195Ssam 
78611195Ssam 	case STARTUP:
78711195Ssam 		goto endintr;
78811195Ssam 
78911195Ssam 	case IDLE: {
79011195Ssam 		register rq = is->hy_flags;
79111195Ssam 
79211195Ssam 		if (rq & RQ_STATUS) {
79311195Ssam 			is->hy_flags &= ~RQ_STATUS;
79411195Ssam 			is->hy_state = STATSENT;
79511207Ssam 			hystart(ui, HYF_STATUS, sizeof (is->hy_status),
79613088Ssam 			    is->hy_ifuba.ifu_r.ifrw_info);
79711195Ssam 		} else if (rq & RQ_ENDOP) {
79811195Ssam 			is->hy_flags &= ~RQ_ENDOP;
79911195Ssam 			is->hy_state = ENDOPSENT;
80011195Ssam 			hystart(ui, HYF_END_OP, 0, 0);
80111195Ssam 		} else if (rq & RQ_STATISTICS) {
80211195Ssam 			is->hy_flags &= ~RQ_STATISTICS;
80311195Ssam 			is->hy_state = RSTATSENT;
80411207Ssam 			hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
80513088Ssam 			    is->hy_ifuba.ifu_r.ifrw_info);
80611207Ssam 		} else if (HYS_RECVDATA(addr)) {
80711195Ssam 			is->hy_state = RECVSENT;
80811195Ssam 			is->hy_retry = 0;
80921128Skarels 			hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN);
81011195Ssam 		} else if (rq & RQ_REISSUE) {
81111195Ssam 			is->hy_flags &= ~RQ_REISSUE;
81211195Ssam 			is->hy_state = is->hy_savedstate;
81311195Ssam #ifdef DEBUG
81411207Ssam 			printD("hy%d: reissue cmd=0x%x count=%d",
81511207Ssam 			  ui->ui_unit, is->hy_savedcmd, is->hy_savedcount);
81611207Ssam 			printD(" ubaddr=0x%x retry=%d\n",
81711207Ssam 			  is->hy_savedaddr, is->hy_retry);
81811195Ssam #endif
81911207Ssam 			hystart(ui, is->hy_savedcmd, is->hy_savedcount,
82013088Ssam 			    is->hy_savedaddr);
82111195Ssam 		} else {
82211195Ssam 			register struct mbuf *m;
82311195Ssam 
82411195Ssam 			IF_DEQUEUE(&is->hy_if.if_snd, m);
82511207Ssam 			if (m != NULL) {
82611195Ssam 				register struct hym_hdr *hym;
82711195Ssam 				register int mplen;
82811195Ssam 				register int cmd;
82911195Ssam 
83011195Ssam 				is->hy_state = XMITSENT;
83111195Ssam 				is->hy_retry = 0;
83211195Ssam 				hym = mtod(m, struct hym_hdr *);
83311195Ssam #ifdef HYLOG
83411207Ssam 				hylog(HYL_XMIT, sizeof(struct hym_hdr),
83513088Ssam 				    (char *)hym);
83611195Ssam #endif
83711195Ssam 				mplen = hym->hym_mplen;
83821128Skarels 				if (hym->hym_to_adapter == hym->hym_from_adapter)
83911207Ssam 					cmd = HYF_XMITLOCMSG;
84011207Ssam 				else
84111207Ssam 					cmd = HYF_XMITMSG;
84211195Ssam #ifdef DEBUG
84311195Ssam 				printD("hy%d: hym_hdr = ", ui->ui_unit);
84411207Ssam 				if (hy_debug_flag)
84511207Ssam 					hyprintdata((char *)hym,
84613088Ssam 					    sizeof (struct hym_hdr));
84711195Ssam #endif
84821128Skarels 				is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN;
84911195Ssam 				if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
85011207Ssam 					UBAPURGE(is->hy_ifuba.ifu_uba,
85111207Ssam 						is->hy_ifuba.ifu_w.ifrw_bdp);
85211195Ssam #ifdef DEBUG
85311207Ssam 				printD(
85411207Ssam 		"hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
85511195Ssam 					ui->ui_unit, mplen, is->hy_olen);
85611207Ssam 				if (hy_debug_flag)
85711207Ssam 					hyprintdata(
85813088Ssam 					    is->hy_ifuba.ifu_w.ifrw_addr,
85921128Skarels 					    is->hy_olen + HYM_SWLEN);
86011195Ssam #endif
86121128Skarels 				if (mplen == 0) {
86221128Skarels 					is->hy_flags &= ~RQ_XASSOC;
86321128Skarels 					mplen = is->hy_olen;
86421128Skarels 				} else {
86511195Ssam 					is->hy_flags |= RQ_XASSOC;
86621128Skarels 				}
86721128Skarels 				hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN);
86811195Ssam 			} else if (rq & RQ_MARKDOWN) {
86911195Ssam 				is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
87011195Ssam 				is->hy_state = MARKPORT;
87111195Ssam 				is->hy_retry = 0;
87211195Ssam 				/*
87311207Ssam 				 * Port number is taken from status data
87411195Ssam 				 */
87511207Ssam 				hystart(ui,
87612772Ssam 				 (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)),
87712772Ssam 				 0, 0);
87811195Ssam 			} else if (rq & RQ_MARKUP) {
87911195Ssam 				register struct ifnet *ifp = &is->hy_if;
88011195Ssam 
88111207Ssam 				is->hy_flags &= ~RQ_MARKUP;
88211195Ssam 				is->hy_retry = 0;
88311195Ssam 				/*
88413065Ssam 				 * Fill in the host number
88511207Ssam 				 * from the status buffer
88611195Ssam 				 */
88711207Ssam 				printf(
88811207Ssam 	"hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
88911195Ssam 					ui->ui_unit,
89011195Ssam 					is->hy_stat.hyc_uaddr,
89111195Ssam 					PORTNUM(&is->hy_status),
89211207Ssam 					(is->hy_stat.hyc_atype[0]<<8) |
89311207Ssam 						is->hy_stat.hyc_atype[1],
89411195Ssam 					is->hy_stat.hyc_atype[2]);
89511195Ssam 
89621775Skarels 				is->hy_host =
89711207Ssam 				  (is->hy_stat.hyc_uaddr << 8) |
89811207Ssam 					PORTNUM(&is->hy_status);
89911195Ssam 				ifp->if_flags |= IFF_UP;
90011195Ssam #ifdef HYLOG
90111195Ssam 				hylog(HYL_UP, 0, (char *)0);
90211195Ssam #endif
90311195Ssam 			} else {
90411195Ssam 				is->hy_state = WAITING;
90511195Ssam 				is->hy_retry = 0;
90611195Ssam 				hystart(ui, HYF_WAITFORMSG, 0, 0);
90711195Ssam 			}
90811195Ssam 		}
90911207Ssam 		break;
91011195Ssam 	}
91111195Ssam 
91211195Ssam 	case STATSENT:
91312772Ssam 		bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status,
91411207Ssam 		  sizeof (struct hy_status));
91511195Ssam #ifdef DEBUG
91611207Ssam 		printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
91711207Ssam 			ui->ui_unit, is->hy_status.hys_gen_status,
91811207Ssam 			is->hy_status.hys_last_fcn,
91911207Ssam 			is->hy_status.hys_resp_trunk,
92011207Ssam 			is->hy_status.hys_status_trunk,
92111207Ssam 			is->hy_status.hys_recd_resp,
92211207Ssam 			is->hy_status.hys_error,
92311207Ssam 			is->hy_status.hys_caddr,
92411207Ssam 			is->hy_status.hys_pad);
92511195Ssam #endif
92611195Ssam 		is->hy_state = IDLE;
92711195Ssam #ifdef HYLOG
92811207Ssam 		hylog(HYL_STATUS, sizeof (struct hy_status),
92911207Ssam 			(char *)&is->hy_status);
93011195Ssam #endif
93111195Ssam #ifdef HYELOG
93211195Ssam 		{
93311195Ssam 			register int i;
93411195Ssam 
93511195Ssam 			i = is->hy_status.hys_error;
93621128Skarels 			if (i > HYE_MAX)
93711195Ssam 				i = HYE_MAX;
93811195Ssam 			switch (is->hy_status.hys_last_fcn) {
93911195Ssam 				case HYF_XMITLOCMSG:
94011195Ssam 					i += HYE_MAX+1;	/* fall through */
94111195Ssam 				case HYF_XMITLSTDATA:
94211195Ssam 					i += HYE_MAX+1;	/* fall through */
94311195Ssam 				case HYF_XMITMSG:
94411195Ssam 					i += HYE_MAX+1;
94511195Ssam 			}
94611195Ssam 			hy_elog[i]++;
94711195Ssam 		}
94811195Ssam #endif
94911195Ssam 		break;
95011195Ssam 
95111195Ssam 	case RSTATSENT: {
95211207Ssam 		register struct hy_stat *p =
95311207Ssam 			(struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
95411195Ssam 
95521128Skarels 		bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat));
95611195Ssam #ifdef DEBUG
95721128Skarels 
95821128Skarels 		printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n",
95911195Ssam 			ui->ui_unit,
96021128Skarels 			(is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2],
96121128Skarels 			(is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2],
96221128Skarels 			(is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2],
96321128Skarels 			(is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]);
96421128Skarels 		printD("	ret0 %d ret1 %d ret2 %d ret3 %d\n",
96521128Skarels 			(is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2],
96621128Skarels 			(is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2],
96721128Skarels 			(is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2],
96821128Skarels 			(is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]);
96921128Skarels 		printD("	cancel %d abort %d atype %x %x %x uaddr %x\n",
97021128Skarels 			(is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1],
97121128Skarels 			(is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1],
97211195Ssam 			is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
97311195Ssam 			is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
97411195Ssam #endif
97511195Ssam 		is->hy_state = IDLE;
97611195Ssam #ifdef HYLOG
97711207Ssam 		hylog(HYL_STATISTICS, sizeof (struct hy_stat),
97811207Ssam 			(char *)&is->hy_stat);
97911195Ssam #endif
98011195Ssam 		break;
98111195Ssam 	}
98211195Ssam 
98311195Ssam 	case CLEARSENT:
98411195Ssam 		is->hy_state = IDLE;
98511195Ssam 		break;
98611195Ssam 
98711195Ssam 	case ENDOPSENT:
98811195Ssam 		is->hy_state = IDLE;
98911195Ssam 		break;
99011195Ssam 
99111195Ssam 	case RECVSENT: {
99221128Skarels 		register struct hym_hdr *hym;
99311207Ssam 		register unsigned len;
99411195Ssam 
99511207Ssam 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
99611207Ssam 			UBAPURGE(is->hy_ifuba.ifu_uba,
99713088Ssam 			    is->hy_ifuba.ifu_r.ifrw_bdp);
99821128Skarels 		hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
99911207Ssam 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
100011207Ssam 		if (len > MPSIZE) {
100111207Ssam 			printf("hy%d: RECVD MP > MPSIZE (%d)\n",
100213088Ssam 			    ui->ui_unit, len);
100321128Skarels 			is->hy_state = IDLE;
100411195Ssam #ifdef DEBUG
100511207Ssam 			hy_debug_flag = 1;
100611207Ssam 			printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
100711207Ssam 				ui->ui_unit, addr->hyd_csr, HY_CSR_BITS,
100811207Ssam 				addr->hyd_bar, addr->hyd_wcr);
100911195Ssam #endif
101011207Ssam 		}
101121128Skarels 		hym->hym_mplen = len;
101211195Ssam #ifdef DEBUG
101311207Ssam 		printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
101411207Ssam 		if (hy_debug_flag)
101521128Skarels 			hyprintdata((char *)hym, len + HYM_SWLEN);
101611195Ssam #endif
101721128Skarels 		if (hym->hym_ctl & H_ASSOC) {
101811207Ssam 			is->hy_state = RECVDATASENT;
101911207Ssam 			is->hy_retry = 0;
102011207Ssam 			hystart(ui, HYF_INPUTDATA,
102121128Skarels 			    (int)(HYMTU + sizeof (struct hy_hdr) - len),
102221128Skarels 			    (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len));
102311207Ssam 		} else {
102421128Skarels 			hyrecvdata(ui, hym, (int)len + HYM_SWLEN);
102511207Ssam 			is->hy_state = IDLE;
102611195Ssam 		}
102711207Ssam 		break;
102811207Ssam 	}
102911195Ssam 
103011195Ssam 	case RECVDATASENT: {
103121128Skarels 		register struct hym_hdr *hym;
103211207Ssam 		register unsigned len;
103311195Ssam 
103411207Ssam 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
103511207Ssam 			UBAPURGE(is->hy_ifuba.ifu_uba,
103613088Ssam 			    is->hy_ifuba.ifu_r.ifrw_bdp);
103721128Skarels 		hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
103811207Ssam 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
103911195Ssam #ifdef DEBUG
104011207Ssam 		printD("hy%d: recvd assoc data, len = %d, data = ",
104111207Ssam 			ui->ui_unit, len);
104211207Ssam 		if (hy_debug_flag)
104321128Skarels 			hyprintdata((char *)hym + hym->hym_mplen, len);
104411195Ssam #endif
104521128Skarels 		hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN));
104611207Ssam 		is->hy_state = IDLE;
104711207Ssam 		break;
104811207Ssam 	}
104911195Ssam 
105011195Ssam 	case XMITSENT:
105111207Ssam 		if (is->hy_flags & RQ_XASSOC) {
105213196Sroot 			register int len;
105311195Ssam 
105411207Ssam 			is->hy_flags &= ~RQ_XASSOC;
105511207Ssam 			is->hy_state = XMITDATASENT;
105611207Ssam 			is->hy_retry = 0;
105711207Ssam 			len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
105811207Ssam 			if (len > is->hy_olen) {
105911207Ssam 				printf(
106011207Ssam 				"hy%d: xmit error - len > hy_olen [%d > %d]\n",
106111207Ssam 				ui->ui_unit, len, is->hy_olen);
106211195Ssam #ifdef DEBUG
106311207Ssam 				hy_debug_flag = 1;
106411195Ssam #endif
106511195Ssam 			}
106611207Ssam 			hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
106721128Skarels 			    is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len);
106811207Ssam 			break;
106911207Ssam 		}
107011207Ssam 		/* fall through to ... */
107111195Ssam 
107211195Ssam 	case XMITDATASENT:
107311207Ssam 		hyxmitdata(ui);
107411207Ssam 		is->hy_state = IDLE;
107511207Ssam 		break;
107611195Ssam 
107711195Ssam 	case WAITING:	/* wait for message complete or output requested */
107811207Ssam 		if (HYS_RECVDATA(addr))
107911195Ssam 			is->hy_state = IDLE;
108011195Ssam 		else {
108111195Ssam 			is->hy_state = CLEARSENT;
108211195Ssam 			is->hy_retry = 0;
108311195Ssam 			hystart(ui, HYF_CLRWFMSG, 0, 0);
108411195Ssam 		}
108511195Ssam 		break;
108611195Ssam 
108711195Ssam 	case MARKPORT:
108811195Ssam 		is->hy_state = STARTUP;
108921128Skarels 		if_down(&is->hy_if);
109011195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
109111195Ssam 		goto endintr;
109211195Ssam 
109311195Ssam 	default:
109411207Ssam 		printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
109511207Ssam 			ui->ui_unit, is->hy_state);
109611195Ssam 		panic("HYPERCHANNEL IN INVALID STATE");
109711195Ssam 		/*NOTREACHED*/
109811207Ssam 	}
109911195Ssam 	if (is->hy_state == IDLE)
110011195Ssam 		goto actloop;
110111195Ssam endintr:
110213088Ssam 	;
110311195Ssam #ifdef DEBUG
110411207Ssam 	printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit,
110511207Ssam 		hy_state_names[is->hy_state]);
110611195Ssam #endif
110711207Ssam }
110811195Ssam 
110921128Skarels struct sockproto hypproto = { PF_HYLINK };
111021128Skarels struct sockaddr_in hypdst = { AF_HYLINK };
111121128Skarels struct sockaddr_in hypsrc = { AF_HYLINK };
111221128Skarels 
111311195Ssam /*
111413088Ssam  * Called from device interrupt when receiving data.
111511195Ssam  * Examine packet to determine type.  Decapsulate packet
111611195Ssam  * based on type and pass to type specific higher-level
111711195Ssam  * input routine.
111811195Ssam  */
111921128Skarels hyrecvdata(ui, hym, len)
112011195Ssam 	struct uba_device *ui;
112121128Skarels 	register struct hym_hdr *hym;
112211195Ssam 	int len;
112311195Ssam {
112411195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
112511195Ssam     	struct mbuf *m;
112611195Ssam 	register struct ifqueue *inq;
112711195Ssam 
112811195Ssam 	is->hy_if.if_ipackets++;
112911195Ssam #ifdef DEBUG
113021128Skarels 	printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len);
113111195Ssam #endif
113211195Ssam #ifdef HYLOG
113311195Ssam 	{
113411195Ssam 		struct {
113511195Ssam 			short hlen;
113621128Skarels 			struct hym_hdr hhdr;
113711195Ssam 		} hh;
113811195Ssam 		hh.hlen = len;
113921128Skarels 		hh.hhdr = *hym;
114011195Ssam 		hylog(HYL_RECV, sizeof(hh), (char *)&hh);
114111195Ssam 	}
114211195Ssam #endif
114311195Ssam 	if (len > HYMTU + MPSIZE || len == 0)
114411195Ssam 		return;			/* sanity */
114511195Ssam 	/*
114611195Ssam 	 * Pull packet off interface.
114711195Ssam 	 */
114824797Skarels 	m = if_rubaget(&is->hy_ifuba, len, 0, &is->hy_if);
114911207Ssam 	if (m == NULL)
115011195Ssam 		return;
115111195Ssam 
115221128Skarels 	/*
115321128Skarels 	 * if normal or adapter loopback response packet believe hym_type,
115421128Skarels 	 * otherwise, use the raw input queue cause it's a response from an
115521128Skarels 	 * adapter command.
115621128Skarels 	 */
115721128Skarels 	if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff)
115821128Skarels 		goto rawlinkin;
115921128Skarels 
116021128Skarels 	switch (hym->hym_type) {
116121128Skarels 
116211195Ssam #ifdef INET
116311195Ssam 	case HYLINK_IP:
116411195Ssam 		schednetisr(NETISR_IP);
116511195Ssam 		inq = &ipintrq;
116611195Ssam 		break;
116711195Ssam #endif
116811195Ssam 	default:
116921128Skarels 	rawlinkin:
117021128Skarels 		{
117121128Skarels 			struct mbuf *m0;
117221128Skarels 
117321128Skarels 			MGET(m0, M_DONTWAIT, MT_DATA);
117424797Skarels 			if (m0 == 0) {
117521128Skarels 				m_freem(m);
117621128Skarels 				return;
117721128Skarels 			}
117821128Skarels 			m0->m_off = MMINOFF;
117921128Skarels 			m0->m_len = sizeof(struct hym_hdr);
118021128Skarels 			m0->m_next = m;
118121128Skarels 			bcopy((caddr_t)hym, mtod(m0, caddr_t), sizeof(struct hym_hdr));
118221128Skarels 			m = m0;
118321128Skarels 			hypproto.sp_protocol = 0;
118421775Skarels 			hypdst.sin_addr = is->hy_addr;
118521775Skarels 			hypsrc.sin_addr = is->hy_addr;
118621128Skarels 			raw_input(m, &hypproto, (struct sockaddr *)&hypsrc,
118721128Skarels 				(struct sockaddr *)&hypdst);
118821128Skarels 			return;
118921128Skarels 		}
119011195Ssam 	}
119111195Ssam 	if (IF_QFULL(inq)) {
119211195Ssam 		IF_DROP(inq);
119311195Ssam 		m_freem(m);
119411195Ssam 	} else
119511195Ssam 		IF_ENQUEUE(inq, m);
119611207Ssam }
119711195Ssam 
119811195Ssam /*
119911207Ssam  * Transmit done, release resources, bump counters.
120011195Ssam  */
120111195Ssam hyxmitdata(ui)
120211195Ssam 	struct uba_device *ui;
120311195Ssam {
120411195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
120511195Ssam 
120611195Ssam 	is->hy_if.if_opackets++;
120711207Ssam 	if (is->hy_ifuba.ifu_xtofree) {
120811195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
120911195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
121011195Ssam 	}
121111207Ssam }
121211195Ssam 
121311195Ssam hycancel(ui)
121411195Ssam 	register struct uba_device *ui;
121511195Ssam {
121611195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
121711195Ssam 
121811207Ssam 	if (is->hy_ifuba.ifu_xtofree) {
121911195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
122011195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
122111195Ssam 	}
122221128Skarels #ifdef HYLOG
122321128Skarels 	hylog(HYL_CANCEL, 0, (char *)0);
122421128Skarels #endif
122511195Ssam #ifdef DEBUG
122611207Ssam 	if (hy_nodebug & 1)
122711207Ssam 		hy_debug_flag = 1;
122811195Ssam #endif
122911195Ssam #ifdef DEBUG
123011195Ssam 	printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
123111195Ssam 		ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
123211195Ssam 		is->hy_savedcount, is->hy_savedaddr);
123321128Skarels 	printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
123421128Skarels 		is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry);
123511207Ssam 	printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
123611207Ssam 		is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr,
123711207Ssam 		is->hy_savedcmd);
123811195Ssam #endif
123911195Ssam 	is->hy_state = IDLE;
124011195Ssam 	is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
124111195Ssam 	hyact(ui);
124211207Ssam }
124311195Ssam 
124411195Ssam #ifdef DEBUG
124511195Ssam hyprintdata(cp, len)
124611195Ssam 	register char *cp;
124711195Ssam 	register int len;
124811195Ssam {
124911195Ssam 	register int count = 16;
125011195Ssam 	register char *fmt;
125111195Ssam 	static char regfmt[] = "\n\t %x";
125211195Ssam 
125311195Ssam 	fmt = &regfmt[2];
125411195Ssam 	while (--len >= 0) {
125511195Ssam 		printL(fmt, *cp++ & 0xff);
125611195Ssam 		fmt = &regfmt[2];
125711195Ssam 		if (--count <= 0) {
125811195Ssam 			fmt = &regfmt[0];
125911195Ssam 			count = 16;
126011195Ssam 		}
126111195Ssam 	}
126211195Ssam 	printL("\n");
126311195Ssam }
126411195Ssam #endif
126511195Ssam 
126611195Ssam hywatch(unit)
126713088Ssam 	int unit;
126811195Ssam {
126911195Ssam 	register struct hy_softc *is = &hy_softc[unit];
127011195Ssam 	register struct uba_device *ui = hyinfo[unit];
127111195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
127211195Ssam 	int s;
127311195Ssam 
127411195Ssam 	s = splimp();
127511195Ssam #ifdef PI13
127611195Ssam 	if ((addr->hyd_csr & S_POWEROFF) != 0) {
127711195Ssam 		addr->hyd_csr |= S_POWEROFF;
127811195Ssam 		DELAY(100);
127911195Ssam 		if ((addr->hyd_csr & S_POWEROFF) == 0) {
128021128Skarels 			printf("hy%d: Adapter Power Restored (hywatch)\n", unit);
128111195Ssam 			is->hy_state = IDLE;
128211207Ssam 			is->hy_flags |=
128311207Ssam 			  (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
128411195Ssam 			hyact(ui);
128511195Ssam 		}
128611195Ssam 	}
128711195Ssam #endif
128821128Skarels 	if (++is->hy_ntime >= 2 && is->hy_state != WAITING &&
128921128Skarels 	  is->hy_state != STARTUP && is->hy_state != IDLE) {
129021128Skarels #ifdef HYLOG
129121128Skarels 		printf("hy%d: watchdog timer expired in state \"%s\"\n", unit,
129221128Skarels 			hy_state_names[is->hy_state]);
129321128Skarels #else
129421128Skarels 		printf("hy%d: watchdog timer expired in state %d\n", unit,
129521128Skarels 			is->hy_state);
129621128Skarels #endif
129721128Skarels 		printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit,
129821128Skarels 			is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS);
129921128Skarels 		hycancel(ui);
130021128Skarels 	}
130111195Ssam 	splx(s);
130221128Skarels 	is->hy_if.if_timer = SCANINTERVAL;
130311195Ssam }
130411195Ssam 
130511195Ssam #ifdef HYLOG
130611195Ssam hylog(code, len, ptr)
130713088Ssam 	int code, len;
130811195Ssam 	char *ptr;
130911195Ssam {
131011195Ssam 	register unsigned char *p;
131111195Ssam 	int s;
131211195Ssam 
131311195Ssam 	s = splimp();
131411195Ssam 	if (hy_log.hyl_self != &hy_log) {
131511195Ssam 		hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
131611195Ssam 		hy_log.hyl_ptr = &hy_log.hyl_buf[0];
131711195Ssam 		hy_log.hyl_self = &hy_log;
131821128Skarels 		hy_log.hyl_enable = HYL_CONTINUOUS;
131921128Skarels 		hy_log.hyl_onerr = HYL_CONTINUOUS;
132021128Skarels 		hy_log.hyl_count = 0;
132121128Skarels 		hy_log.hyl_icount = 16;
132221128Skarels 		hy_log.hyl_filter = 0xffff;	/* enable all */
132311195Ssam 	}
132421128Skarels 	if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0)
132511207Ssam 		goto out;
132611195Ssam 	p = hy_log.hyl_ptr;
132721128Skarels 	if (p + len + 3 >= hy_log.hyl_eptr) {
132812772Ssam 		bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p));
132911195Ssam 		p = &hy_log.hyl_buf[0];
133021128Skarels 		if (hy_log.hyl_enable != HYL_CONTINUOUS) {
133121128Skarels 			hy_log.hyl_enable = HYL_DISABLED;
133211195Ssam 			goto out;
133311195Ssam 		}
133411195Ssam 	}
133511195Ssam 	*p++ = code;
133611195Ssam 	*p++ = len;
133713088Ssam 	bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len);
133821128Skarels 	if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) {
133921128Skarels 		*p++ = '\0';
134021128Skarels 		hy_log.hyl_enable = HYL_DISABLED;
134121128Skarels 		hy_log.hyl_count = hy_log.hyl_icount;
134221128Skarels 	}
134326285Skarels 	p += len;
134421128Skarels 	if (hy_log.hyl_wait != 0) {		/* wakeup HYGETLOG if wanted */
134526285Skarels 		if (hy_log.hyl_wait <= p - hy_log.hyl_ptr) {
134621128Skarels 			wakeup((caddr_t)&hy_log);
134721128Skarels 			hy_log.hyl_wait = 0;
134826285Skarels 		} else
134926285Skarels 			hy_log.hyl_wait -= p - hy_log.hyl_ptr;
135021128Skarels 	}
135126285Skarels 	hy_log.hyl_ptr = p;
135211195Ssam out:
135311195Ssam 	splx(s);
135411195Ssam }
135511195Ssam #endif
135611195Ssam 
135712772Ssam /*ARGSUSED*/
135813058Ssam hyioctl(ifp, cmd, data)
135913058Ssam 	register struct ifnet *ifp;
136011207Ssam 	int cmd;
136111207Ssam 	caddr_t	data;
136211195Ssam {
136321775Skarels 	struct ifaddr *ifa = (struct ifaddr *) data;
136421128Skarels 	struct hyrsetget *sg = (struct hyrsetget *)data;
136521128Skarels #if defined(HYLOG) || defined(HYELOG)
136621128Skarels 	struct hylsetget *sgl = (struct hylsetget *)data;
136721128Skarels #endif
136821128Skarels 	struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit];
136911207Ssam 	int s = splimp(), error = 0;
137021128Skarels #ifdef HYLOG
137121128Skarels 	struct hy_softc *is = &hy_softc[ifp->if_unit];
137221128Skarels 	struct {
137321128Skarels 		u_char	hstate;
137421128Skarels 		u_char	hflags;
137521128Skarels 		u_short	iflags;
137621128Skarels 		int	hcmd;
137721128Skarels 		int	herror;
137821128Skarels 		u_long	haddr;
137921128Skarels 		u_long	hmisc;
138021128Skarels 	} hil;
138111195Ssam 
138221128Skarels 	hil.hmisc = -1;
138321128Skarels 	hil.hstate = is->hy_state;
138421128Skarels 	hil.hflags = is->hy_flags;
138521128Skarels 	hil.hcmd = cmd;
138621128Skarels #endif
138721128Skarels 
138811195Ssam 	switch(cmd) {
138911195Ssam 
139013065Ssam 	case SIOCSIFADDR:
139124797Skarels 		if (ifa->ifa_addr.sa_family != AF_INET)
139221128Skarels 			return(EINVAL);
139321775Skarels 		if ((ifp->if_flags & IFF_RUNNING) == 0)
139421775Skarels 			hyinit(ifp->if_unit);
139521775Skarels 		hy_softc[ifp->if_unit].hy_addr = IA_SIN(ifa)->sin_addr;
139621128Skarels #ifdef HYLOG
139721775Skarels 		hil.haddr = is->hy_addr.s_addr;
139821128Skarels #endif
139913065Ssam 		break;
140013065Ssam 
140111195Ssam 	case HYSETROUTE:
140211207Ssam 		if (!suser()) {
140311207Ssam 			error = EPERM;
140421128Skarels 			goto out;
140511195Ssam 		}
140621128Skarels 
140721128Skarels 		if (sg->hyrsg_len != sizeof(struct hy_route)) {
140821128Skarels 			error = EINVAL;
140921128Skarels 			goto out;
141021128Skarels 		}
141121128Skarels 		if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) {
141221128Skarels 			r->hyr_lasttime = 0;	/* disable further routing if trouble */
141321128Skarels 			error = EFAULT;
141421128Skarels 			goto out;
141521128Skarels 		}
141621128Skarels 		r->hyr_lasttime = time.tv_sec;
141721128Skarels #ifdef HYLOG
141821128Skarels 		hil.hmisc = r->hyr_lasttime;
141921128Skarels #endif
142011195Ssam 		break;
142111195Ssam 
142211195Ssam 	case HYGETROUTE:
142321128Skarels 		if (sg->hyrsg_len < sizeof(struct hy_route)) {
142421128Skarels 			error = EINVAL;
142521128Skarels 			goto out;
142621128Skarels 		}
142721128Skarels 		if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) {
142821128Skarels 			error = EFAULT;
142921128Skarels 			goto out;
143021128Skarels 		}
143111195Ssam 		break;
143211195Ssam 
143321128Skarels #ifdef HYELOG
143421128Skarels 	case HYGETELOG:
143521128Skarels 		if (sgl->hylsg_len < sizeof(hy_elog)) {
143621128Skarels 			error = EINVAL;
143721128Skarels 			goto out;
143821128Skarels 		}
143921128Skarels 		if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) {
144021128Skarels 			error = EFAULT;
144121128Skarels 			goto out;
144221128Skarels 		}
144321128Skarels 		if (sgl->hylsg_cmd) {
144421128Skarels 			if (!suser()) {
144521128Skarels 				error = EPERM;
144621128Skarels 				goto out;
144721128Skarels 			}
144821128Skarels 			bzero((caddr_t)hy_elog, sizeof(hy_elog));
144921128Skarels 		}
145021128Skarels 		break;
145121128Skarels #endif
145221128Skarels 
145321128Skarels #ifdef HYLOG
145421128Skarels 	case HYSETLOG:
145521128Skarels 		if (!suser()) {
145621128Skarels 			error = EPERM;
145721128Skarels 			goto out;
145821128Skarels 		}
145921128Skarels 		hy_log.hyl_enable = HYL_DISABLED;
146021128Skarels 		hylog(HYL_NOP, 0, (char *)0);		/* force log init */
146121128Skarels 		hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f;
146221128Skarels 		hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f;
146321128Skarels 		hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff;
146421128Skarels 		hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len;
146521128Skarels 		wakeup((caddr_t)&hy_log);	/* wakeup sleeping HYGETLOG */
146621128Skarels 		break;
146721128Skarels 
146821128Skarels 	case HYGETLOG:
146921128Skarels 		if (sgl->hylsg_len < sizeof(hy_log)) {
147021128Skarels 			error = EINVAL;
147121128Skarels 			goto out;
147221128Skarels 		}
147321128Skarels 		if (sgl->hylsg_cmd != 0) {
147421128Skarels 			if (hy_log.hyl_wait) {
147521128Skarels 				error = EBUSY;
147621128Skarels 				goto out;
147721128Skarels 			}
147821128Skarels 			hy_log.hyl_wait = sgl->hylsg_cmd;
147926392Skarels 			sleep((caddr_t)&hy_log, PZERO - 1);
148021128Skarels 		}
148121128Skarels 
148221128Skarels 		if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) {
148321128Skarels 			error = EFAULT;
148421128Skarels 			goto out;
148521128Skarels 		}
148621128Skarels 		break;
148721128Skarels #endif
148821128Skarels 
148911195Ssam 	default:
149013058Ssam 		error = EINVAL;
149111195Ssam 		break;
149211195Ssam 	}
149321128Skarels out:
149421128Skarels #ifdef HYLOG
149521128Skarels 	hil.herror = error;
149621128Skarels 	hil.iflags = ifp->if_flags;
149721775Skarels 	hil.haddr = is->hy_addr.s_addr;
149821128Skarels 	hylog(HYL_IOCTL, sizeof(hil), (char *)&hil);
149921128Skarels #endif
150011195Ssam 	splx(s);
150111207Ssam 	return (error);
150211195Ssam }
150311207Ssam #endif
1504