xref: /csrg-svn/sys/vax/if/if_hy.c (revision 13065)
1*13065Ssam /*	if_hy.c	4.7	83/06/13	*/
211195Ssam 
311195Ssam #include "hy.h"
411195Ssam #if NHY > 0
511195Ssam 
611195Ssam /*
711195Ssam  * Network Systems Copropration Hyperchanel interface
811195Ssam  *
913058Ssam  * UNTESTED WITH 4.2
1011195Ssam  */
1111195Ssam #include "../machine/pte.h"
1211195Ssam 
1311195Ssam #include "../h/param.h"
1411195Ssam #include "../h/systm.h"
1511195Ssam #include "../h/mbuf.h"
1611195Ssam #include "../h/buf.h"
1711195Ssam #include "../h/protosw.h"
1811195Ssam #include "../h/socket.h"
1911195Ssam #include "../h/vmmac.h"
2011195Ssam #include "../h/errno.h"
2111207Ssam #include "../h/time.h"
2211207Ssam #include "../h/kernel.h"
2311207Ssam #include "../h/ioctl.h"
2411195Ssam #include "../net/if.h"
2511207Ssam #include "../net/netisr.h"
2611195Ssam #include "../net/route.h"
2711195Ssam #include "../netinet/in.h"
2811195Ssam #include "../netinet/in_systm.h"
2911195Ssam #include "../netinet/ip.h"
3011195Ssam #include "../netinet/ip_var.h"
3111195Ssam 
3211207Ssam #include "../vax/cpu.h"
3311207Ssam #include "../vax/mtpr.h"
3411207Ssam #include "../vaxuba/ubareg.h"
3511207Ssam #include "../vaxuba/ubavar.h"
3611195Ssam #include "../vaxif/if_hy.h"
3711198Ssam #include "../vaxif/if_hyreg.h"
3811195Ssam #include "../vaxif/if_uba.h"
3911195Ssam 
4011195Ssam #define HYROUTE
4111195Ssam #define HYELOG
4211195Ssam #define	HYMTU	576
4311195Ssam 
4413058Ssam int	hyprobe(), hyattach(), hyinit(), hyioctl();
4513058Ssam int	hyoutput(), hyreset(), hywatch();
4611195Ssam struct	uba_device *hyinfo[NHY];
4711195Ssam u_short hystd[] = { 0772410, 0 };
4811195Ssam struct	uba_driver hydriver =
4911195Ssam 	{ hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo };
5011195Ssam 
5111195Ssam /*
5211195Ssam  * Hyperchannel software status per interface.
5311195Ssam  *
5411195Ssam  * Each interface is referenced by a network interface structure,
5511195Ssam  * hy_if, which the routing code uses to locate the interface.
5611195Ssam  * This structure contains the output queue for the interface, its address, ...
5711195Ssam  * We also have, for each interface, a UBA interface structure, which
5811195Ssam  * contains information about the UNIBUS resources held by the interface:
5911195Ssam  * map registers, buffered data paths, etc.  Information is cached in this
6011195Ssam  * structure for use by the if_uba.c routines in running the interface
6111195Ssam  * efficiently.
6211195Ssam  */
6311195Ssam struct	hy_softc {
6411195Ssam 	struct	ifnet hy_if;		/* network-visible interface */
6511195Ssam 	struct	ifuba hy_ifuba;		/* UNIBUS resources */
6611207Ssam 	short	hy_flags;		/* flags */
6711207Ssam 	short	hy_state;		/* driver state */
6811195Ssam 	int	hy_ilen;		/* mp length on input */
6911195Ssam 	int	hy_olen;		/* packet length on output */
7011195Ssam 	int	hy_lastwcr;		/* last command's word count */
7111195Ssam 	short	hy_savedstate;		/* saved for reissue after status */
7211195Ssam 	short	hy_savedcmd;		/* saved command for reissue */
7311195Ssam 	int	hy_savedcount;		/* saved byte count for reissue */
7411195Ssam 	int	hy_savedaddr;		/* saved unibus address for reissue */
7511195Ssam 	int	hy_ntime;		/* number of timeouts since last cmd */
7611195Ssam 	int	hy_retry;		/* retry counter */
7711207Ssam 	struct	hy_stat hy_stat;	/* statistics */
7811207Ssam 	struct	hy_status hy_status;	/* status */
7911195Ssam } hy_softc[NHY];
8011195Ssam 
8111195Ssam #ifdef HYELOG
8211207Ssam #define HYE_MAX	0x18
8311207Ssam u_long	hy_elog[(HYE_MAX+1)*4];
8411195Ssam #endif
8511195Ssam 
8611195Ssam #ifdef DEBUG
8711195Ssam #define printL	lprintf
8811195Ssam #define printD	if (hy_debug_flag) lprintf
8911195Ssam int	hy_debug_flag = 0;
9011195Ssam /*
9111195Ssam  * hy_nodebug bit 0x01	set hy_debug_flag on hycancel
9211195Ssam  * hy_nodebug bit 0x02	set hy_debug_flag on command reissue
9311195Ssam  * hy_nodebug bit 0x04	set hy_debug_flag on abnormal interrupt
9411195Ssam  * hy_nodebug bit 0x08	set hy_debug_flag on hyouput
9511195Ssam  * hy_nodebug bit 0x10	set hy_debug_flag on hyouput with associated data
9611195Ssam  */
9711195Ssam int	hy_nodebug = 0x0;
9811195Ssam #else
9911195Ssam #define printD	hyvoid
10011195Ssam #endif
10111195Ssam 
10211195Ssam /*
10311207Ssam  * Requests for service (in order by descending priority).
10411195Ssam  */
10511195Ssam #define RQ_ENDOP	001	/* end the last adapter function */
10611195Ssam #define RQ_REISSUE	002	/* reissue previous cmd after status */
10711195Ssam #define RQ_STATUS	004	/* get the status of the adapter */
10811195Ssam #define RQ_STATISTICS	010	/* get the statistics of the adapter */
10911195Ssam #define RQ_MARKDOWN	020	/* mark this adapter port down */
11011195Ssam #define RQ_MARKUP	040	/* mark this interface up */
11111195Ssam 
11211195Ssam #define RQ_XASSOC	0100	/* associated data to transmit */
11311195Ssam 
11411195Ssam /*
11511207Ssam  * Driver states.
11611195Ssam  */
11711195Ssam #define	STARTUP		0	/* initial state (before fully there) */
11811195Ssam #define	IDLE		1	/* idle state */
11911195Ssam #define	STATSENT	2	/* status cmd sent to adapter */
12011195Ssam #define	ENDOPSENT	3	/* end operation cmd sent */
12111195Ssam #define	RECVSENT	4	/* input message cmd sent */
12211195Ssam #define	RECVDATASENT	5	/* input data cmd sent */
12311195Ssam #define	XMITSENT	6	/* transmit message cmd sent */
12411195Ssam #define	XMITDATASENT	7	/* transmit data cmd sent */
12511195Ssam #define	WAITING		8	/* waiting for messages */
12611195Ssam #define	CLEARSENT	9	/* clear wait for message cmd sent */
12711195Ssam #define MARKPORT	10	/* mark this host's adapter port down issued */
12811195Ssam #define RSTATSENT	11	/* read statistics cmd sent to adapter */
12911195Ssam 
13011195Ssam #ifdef DEBUG
13111195Ssam char *hy_state_names[] = {
13211195Ssam 	"Startup",
13311195Ssam 	"Idle",
13411195Ssam 	"Status Sent",
13511195Ssam 	"End op Sent",
13611195Ssam 	"Recieve Message Proper Sent",
13711195Ssam 	"Recieve Data Sent",
13811195Ssam 	"Transmit Message Proper Sent",
13911195Ssam 	"Transmit Data Sent",
14011195Ssam 	"Wait for Message Sent",
14111195Ssam 	"Clear Wait for Message Sent",
14211195Ssam 	"Mark Port Down Sent",
14311195Ssam 	"Read Statistics Sent"
14411195Ssam };
14511195Ssam #endif
14611195Ssam 
14711195Ssam #define SCANINTERVAL	10	/* seconds */
14811195Ssam #define MAXINTERVAL	20	/* seconds (max action) */
14911195Ssam 
15011195Ssam /*
15111195Ssam  * Cause a device interrupt.  This code uses a buffer starting at
15211195Ssam  * location zero on the unibus (which is already mapped by the
15311195Ssam  * autoconfigure code in the kernel).
15411195Ssam  */
15511195Ssam hyprobe(reg)
15611195Ssam 	caddr_t reg;
15711195Ssam {
15811195Ssam 	register int br, cvec;		/* r11, r10 value-result */
15911195Ssam 	register struct hydevice *addr = (struct hydevice *) reg;
16011195Ssam 
16111195Ssam #ifdef lint
16211195Ssam 	br = 0; cvec = br; br = cvec;
16311195Ssam 	hyint(0);
16411195Ssam #endif
16511195Ssam 	/*
16611195Ssam 	 * request adapter status to a buffer starting at unibus location 0
16711195Ssam 	 */
16811195Ssam 	addr->hyd_bar = 0;
16911195Ssam 	addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1);
17011195Ssam 	addr->hyd_dbuf = HYF_STATUS;
17111195Ssam #ifdef PI13
17211195Ssam 	addr->hyd_csr |= S_GO | S_IE | S_IATTN;
17311195Ssam #else
17411195Ssam 	addr->hyd_csr |= S_GO | S_IE;
17511195Ssam #endif
17611195Ssam 	DELAY(10000);
17711195Ssam #ifdef PI13
17811195Ssam 	addr->hyd_csr |= S_CLRINT;	/* clear any stacked interrupts */
17911195Ssam #endif
18011195Ssam 	addr->hyd_csr &= ~(S_IE | S_CLRINT);	/* disable further interrupts */
18111195Ssam 	return(1);
18211207Ssam }
18311195Ssam 
18411195Ssam /*
18511195Ssam  * Interface exists: make available by filling in network interface
18611195Ssam  * record.  System will initialize the interface when it is ready
18711195Ssam  * to accept packets.
18811195Ssam  */
18911195Ssam hyattach(ui)
19011195Ssam 	struct uba_device *ui;
19111195Ssam {
19211195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
19311195Ssam 	register struct ifnet *ifp = &is->hy_if;
19411195Ssam 
19511195Ssam 	ifp->if_unit = ui->ui_unit;
19611195Ssam 	ifp->if_name = "hy";
19711195Ssam 	ifp->if_mtu = HYMTU;
19811195Ssam 	is->hy_state = STARTUP;		/* don't allow state transitions yet */
19911195Ssam 	ifp->if_init = hyinit;
20013058Ssam 	ifp->if_ioctl = hyioctl;
20111195Ssam 	ifp->if_output = hyoutput;
20211207Ssam 	ifp->if_reset = hyreset;
20311195Ssam 	ifp->if_watchdog = hywatch;
20411195Ssam 	ifp->if_timer = SCANINTERVAL;
20511195Ssam 	is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
20611207Ssam #ifdef notdef
20711195Ssam 	is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
20811195Ssam #endif
20911195Ssam 	if_attach(ifp);
21011207Ssam }
21111195Ssam 
21211195Ssam /*
21311195Ssam  * Reset of interface after UNIBUS reset.
21411195Ssam  * If interface is on specified uba, reset its state.
21511195Ssam  */
21611195Ssam hyreset(unit, uban)
21711195Ssam 	int unit, uban;
21811195Ssam {
21911195Ssam 	register struct uba_device *ui = hyinfo[unit];
22011195Ssam 
22111207Ssam 	if (unit >= NHY || ui == 0 || ui->ui_alive == 0 ||
22211207Ssam 	  ui->ui_ubanum != uban)
22311195Ssam 		return;
22411195Ssam 	printf(" hy%d", unit);
22511195Ssam 	hyinit(unit);
22611207Ssam }
22711195Ssam 
22811195Ssam /*
22911195Ssam  * Initialization of interface; clear recorded pending
23011195Ssam  * operations, and reinitialize UNIBUS usage.
23111195Ssam  */
23211195Ssam hyinit(unit)
23311195Ssam 	int unit;
23411195Ssam {
23511195Ssam 	register struct hy_softc *is = &hy_softc[unit];
23611195Ssam 	register struct uba_device *ui = hyinfo[unit];
237*13065Ssam 	struct sockaddr_in *sin;
23811195Ssam 	int s;
23911195Ssam 
240*13065Ssam 	sin = (struct sockaddr_in *)&is->is_if.if_addr;
241*13065Ssam 	if (in_netof(sin->sin_addr) == 0)
242*13065Ssam 		return;
24311195Ssam 	if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
24411195Ssam 	    sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) {
24511195Ssam #ifdef DEBUG
24611207Ssam 		if (hy_nodebug & 4)
24711207Ssam 			hy_debug_flag = 1;
24811195Ssam #endif
24911195Ssam 		printf("hy%d: can't initialize\n", unit);
25011195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
25111195Ssam 		return;
25211195Ssam 	}
25313059Ssam 	is->is_hy.if_flags |= IFF_RUNNING;
25411195Ssam 	/*
25511207Ssam 	 * Issue wait for message and start the state machine
25611195Ssam 	 */
25711195Ssam 	s = splimp();
25811195Ssam 	is->hy_state = IDLE;
25911195Ssam 	is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
26011195Ssam 	is->hy_retry = 0;
26111195Ssam 	hyact(ui);
26211195Ssam 	splx(s);
26311207Ssam }
26411195Ssam 
26511195Ssam /*
26611207Ssam  * Issue a command to the adapter
26711195Ssam  */
26811195Ssam hystart(ui, cmd, count, ubaddr)
26911195Ssam 	struct uba_device *ui;
27011207Ssam 	int cmd, count, ubaddr;
27111195Ssam {
27211195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
27311195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
27411195Ssam 
27511195Ssam #ifdef DEBUG
27611207Ssam 	printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
27711207Ssam 		ui->ui_unit, cmd, count, ubaddr);
27811195Ssam 	printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
27911207Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
28011207Ssam 		addr->hyd_wcr);
28111195Ssam #endif
28211207Ssam 	if (((is->hy_flags & RQ_REISSUE) == 0) &&
28311207Ssam 	  (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
28411195Ssam 		is->hy_savedstate = is->hy_state;
28511195Ssam 		is->hy_savedcmd = cmd;
28611195Ssam 		is->hy_savedcount = count;
28711195Ssam 		is->hy_savedaddr = ubaddr;
28811195Ssam 	}
28911195Ssam 	addr->hyd_bar = ubaddr & 0xffff;
29011207Ssam 	addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);
29111195Ssam 	addr->hyd_dbuf = cmd;
29211195Ssam #ifdef PI13
29311195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN;
29411195Ssam #else
29511195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE;
29611195Ssam #endif
29711195Ssam #ifdef DEBUG
29811195Ssam 	printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
29911207Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
30011207Ssam 		addr->hyd_wcr);
30111195Ssam #endif
30211195Ssam #ifdef HYLOG
30311195Ssam 	{
30411195Ssam 		struct {
30511207Ssam 			u_char	hcmd;
30611207Ssam 			u_char	hstate;
30711207Ssam 			short	hcount;
30811195Ssam 		} hcl;
30911195Ssam 
31011195Ssam 		hcl.hcmd = cmd;
31111195Ssam 		hcl.hstate = is->hy_state;
31211195Ssam 		hcl.hcount = count;
31311195Ssam 		hylog(HYL_CMD, sizeof(hcl), (char *)&hcl);
31411195Ssam 	}
31511195Ssam #endif
31611195Ssam 	is->hy_ntime = 0;
31711207Ssam }
31811195Ssam 
31911195Ssam int hyint_active = 0;		/* set during hy interrupt */
32011195Ssam /*
32111207Ssam  * Hyperchannel interface interrupt.
32211195Ssam  *
32311195Ssam  * An interrupt can occur for many reasons.  Examine the status of
32411195Ssam  * the hyperchannel status bits to determine what to do next.
32511195Ssam  *
32611195Ssam  * If input error just drop packet.
32711195Ssam  * Otherwise purge input buffered data path and examine
32811195Ssam  * packet to determine type.  Othewise decapsulate
32911195Ssam  * packet based on type and pass to type specific higher-level
33011195Ssam  * input routine.
33111195Ssam  */
33211195Ssam hyint(unit)
33311195Ssam 	int unit;
33411195Ssam {
33511195Ssam 	register struct hy_softc *is = &hy_softc[unit];
33611195Ssam 	register struct uba_device *ui = hyinfo[unit];
33711207Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
33811195Ssam 
33911207Ssam 	if (hyint_active)
34011195Ssam 		panic("RECURSIVE HYPERCHANNEL INTERRUPT");
34111195Ssam 	hyint_active++;
34211195Ssam #ifdef DEBUG
34311195Ssam 	printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
34411195Ssam 		unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
34511195Ssam #endif
34611195Ssam #ifdef HYLOG
34711195Ssam logit:
34811195Ssam 	{
34911195Ssam 		struct {
35011207Ssam 			u_char	hstate;
35111207Ssam 			u_char	hflags;
35211207Ssam 			short	hcsr;
35311207Ssam 			short	hwcr;
35411195Ssam 		} hil;
35511195Ssam 		hil.hstate = is->hy_state;
35611195Ssam 		hil.hflags = is->hy_flags;
35711195Ssam 		hil.hcsr = addr->hyd_csr;
35811195Ssam 		hil.hwcr = addr->hyd_wcr;
35911195Ssam 		hylog(HYL_INT, sizeof(hil), (char *)&hil);
36011195Ssam 	}
36111195Ssam #endif
36211207Ssam 	if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
36311195Ssam 		/*
36411207Ssam 		 * Error bit set, some sort of error in the interface.
36511195Ssam 		 *
36611207Ssam 		 * The adapter sets attn on command completion so that's not
36711207Ssam 		 * a real error even though the interface considers it one.
36811195Ssam 		 */
36911195Ssam #ifdef DEBUG
37011207Ssam 		if (hy_nodebug & 4)
37111207Ssam 			hy_debug_flag = 1;
37211195Ssam #endif
37311207Ssam 		printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n",
37411207Ssam 			addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
37511207Ssam 			addr->hyd_wcr);
37611207Ssam 		if (addr->hyd_csr & S_NEX) {
37711195Ssam 			printf("hy%d: NEX - Non Existant Memory\n", unit);
37811195Ssam #ifdef PI13
37911195Ssam 			addr->hyd_csr |= S_NEX;  /* as per PI13 manual */
38011195Ssam #else
38111195Ssam 			addr->hyd_csr &= ~S_NEX;
38211195Ssam #endif
38311195Ssam 			hycancel(ui);
38411195Ssam #ifdef PI13
38511207Ssam 		} else if (addr->hyd_csr & S_POWEROFF) {
38611207Ssam 			printf("hy%d: Power Off bit set, trying to reset\n",
38711207Ssam 				unit);
38811195Ssam 			addr->hyd_csr |= S_POWEROFF;
38911195Ssam 			DELAY(100);
39011207Ssam 			if (addr->hyd_csr & S_POWEROFF) {
39111195Ssam 				if_down(&is->hy_if);
39211195Ssam 				is->hy_state = STARTUP;
39311207Ssam 				printf(
39411207Ssam 				  "hy%d: Power Off Error, network shutdown\n",
39511207Ssam 				  unit);
39611195Ssam 			}
39711195Ssam #endif
39811195Ssam 		} else {
39911195Ssam 			printf("hy%d:  BAR overflow\n", unit);
40011195Ssam 			hycancel(ui);
40111195Ssam 		}
40211207Ssam 	} else if (HYS_NORMAL(addr)) {
40311195Ssam 		/*
40411207Ssam 		 * Normal interrupt, bump state machine unless in state
40511195Ssam 		 * waiting and no data present (assumed to be word count
40611207Ssam 		 * zero interrupt or other hardware botch).
40711195Ssam 		 */
40811207Ssam 		if (is->hy_state != WAITING || HYS_RECVDATA(addr))
40911195Ssam 			hyact(ui);
41011207Ssam 	} else if (HYS_ABNORMAL(addr)) {
41111195Ssam 		/*
41211207Ssam 		 * Abnormal termination.
41311195Ssam 		 * bump error counts, retry the last function
41411195Ssam 		 * 'MAXRETRY' times before kicking the bucket.
41511195Ssam 		 *
41611207Ssam 		 * Don't reissue the cmd if in certain states, abnormal
41711207Ssam 		 * on a reissued cmd or max retry exceeded.
41811195Ssam 		 */
41911195Ssam #ifdef HYLOG
42011195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
42111195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
42211195Ssam 			goto logit;
42311195Ssam 		}
42411195Ssam #endif
42511195Ssam #ifdef DEBUG
42611207Ssam 		if (hy_nodebug & 4)
42711207Ssam 			hy_debug_flag = 1;
42811195Ssam 		printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
42911195Ssam 			unit, hy_state_names[is->hy_state], is->hy_state);
43011207Ssam 		printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n",
43111207Ssam 			is->hy_flags, is->hy_ilen, is->hy_olen,
43211207Ssam 			is->hy_lastwcr, is->hy_retry);
43311207Ssam 		printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
43411207Ssam 			is->hy_savedstate, is->hy_savedcount,
43511207Ssam 			is->hy_savedaddr, is->hy_savedcmd);
43611195Ssam #endif
43711195Ssam #ifdef PI13
43811195Ssam 		addr->hyd_csr &= ~S_C;  /* clear the damned PI-13 */
43911195Ssam #endif
44011207Ssam 		if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT)
44111195Ssam 			is->hy_if.if_oerrors++;
44211207Ssam 		if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT)
44311195Ssam 			is->hy_if.if_ierrors++;
44411195Ssam 		if (is->hy_state == XMITDATASENT ||
44511195Ssam 		    is->hy_state == RECVSENT ||
44611195Ssam 		    is->hy_state == RECVDATASENT ||
44711207Ssam 		    (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY)
44811195Ssam 			hycancel(ui);
44911207Ssam 		else {
45011195Ssam #ifdef DEBUG
45111207Ssam 			if (hy_nodebug & 2)
45211207Ssam 				hy_debug_flag = 1;
45311195Ssam #endif
45411195Ssam 			is->hy_retry++;
45511195Ssam 			is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE;
45611195Ssam 			is->hy_state = IDLE;
45711195Ssam 			hyact(ui);
45811195Ssam 		}
45911195Ssam 	} else {
46011195Ssam 		/*
46111195Ssam 		 * Interrupt is neither normal, abnormal, or interface error.
46211195Ssam 		 * Ignore it. It's either stacked or a word count 0.
46311195Ssam 		 */
46411195Ssam #ifdef HYLOG
46511195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
46611195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
46711195Ssam 			goto logit;
46811195Ssam 		}
46911195Ssam #endif
47011195Ssam #ifdef DEBUG
47111195Ssam 		printD("hy%d: possible stacked interrupt ignored\n", unit);
47211195Ssam #endif
47311195Ssam 	}
47411195Ssam #ifdef DEBUG
47511195Ssam 	printD("hy%d: hyint exit\n\n", unit);
47611195Ssam #endif
47711195Ssam 	hyint_active = 0;
47811195Ssam 
47911207Ssam }
48011195Ssam 
48111195Ssam /*
48211195Ssam  * Encapsulate a packet of type family for the local net.
48311195Ssam  * Use trailer local net encapsulation if enough data in first
48411195Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
48511195Ssam  */
48611195Ssam hyoutput(ifp, m0, dst)
48711195Ssam 	struct ifnet *ifp;
48811195Ssam 	struct mbuf *m0;
48911195Ssam 	struct sockaddr *dst;
49011195Ssam {
49111195Ssam 	register struct hym_hdr *hym;
49211195Ssam 	register struct mbuf *m;
49311195Ssam #ifdef HYROUTE
49411195Ssam 	register struct hyroute *r = &hy_route[ifp->if_unit];
49511195Ssam #endif
49611195Ssam 	short dtype;		/* packet type */
49711195Ssam 	int dhost;		/* destination adapter address */
49811195Ssam 	int dlen;
49911195Ssam 	int mplen = 0;		/* message proper length */
50011195Ssam 	short loopback = 0;	/* hardware loopback requested */
50111195Ssam 	int error = 0;
50211195Ssam 	int s;
50311195Ssam 
50411195Ssam #ifdef DEBUG
50511207Ssam 	if (hy_nodebug & 8)
50611207Ssam 		hy_debug_flag = 1;
50711195Ssam #endif
50811195Ssam 	dlen = 0;
50911195Ssam 	for (m = m0; m; m = m->m_next)
51011195Ssam 		dlen += m->m_len;
51111195Ssam 	m = m0;
51211195Ssam 	switch(dst->sa_family) {
51311195Ssam 
51411195Ssam #ifdef INET
51511195Ssam 	case AF_INET: {
51611195Ssam 		register struct ip *ip = mtod(m, struct ip *);
51711195Ssam 		register struct sockaddr_in *sin = (struct sockaddr_in *)dst;
51811195Ssam 		register long hostaddr = in_lnaof(sin->sin_addr);
51911195Ssam 
52011195Ssam 		dhost = hostaddr & 0xffff;
52111195Ssam 		dtype = HYLINK_IP;
52211195Ssam #ifdef DEBUG
52311207Ssam 		printD("hy%d: output to host %x, dhost %x\n",
52411207Ssam 			ifp->if_unit, sin->sin_addr.s_addr, dhost);
52511195Ssam #endif
52611195Ssam 		/*
52711207Ssam 		 * Debugging loopback support:
52811195Ssam 		 * upper byte of 24 bit host number interpreted as follows
52911195Ssam 		 *	0x00 --> no loopback
53011195Ssam 		 *	0x01 --> hardware loop through remote adapter
53111195Ssam 		 *	other --> software loop through remote ip layer
53211195Ssam 		 */
53311195Ssam 		if (hostaddr & 0xff0000) {
53411195Ssam 			struct in_addr temp;
53511195Ssam 
53611195Ssam 			temp = ip->ip_dst;
53711195Ssam 			ip->ip_dst = ip->ip_src;
53811195Ssam 			ip->ip_src = temp;
53911195Ssam 			if ((hostaddr & 0xff0000) == 0x10000)
54011195Ssam 				loopback = H_LOOPBK;
54111195Ssam 		}
54211195Ssam 		/*
54311195Ssam 		 * If entire packet won't fit in message proper, just
54411195Ssam 		 * send hyperchannel hardware header and ip header in
54511195Ssam 		 * message proper.  If that won't fit either, just send
54611195Ssam 		 * the maximum message proper.
54711195Ssam 		 *
54811195Ssam 		 * This insures that the associated data is at least a
54911195Ssam 		 * TCP/UDP header in length and thus prevents potential
55011195Ssam 		 * problems with very short word counts.
55111195Ssam 		 */
55211195Ssam 		if (dlen > MPSIZE - sizeof (struct hy_hdr)) {
55311195Ssam 			mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2);
55411195Ssam 			if (mplen > MPSIZE)
55511195Ssam 				mplen = MPSIZE;
55611195Ssam 		}
55711195Ssam 		break;
55811195Ssam 	}
55911195Ssam #endif
56011195Ssam 
56111195Ssam 	default:
56211207Ssam 		printf("hy%d: can't handle af%d\n", ifp->if_unit,
56311207Ssam 			dst->sa_family);
56411195Ssam #ifdef DEBUG
56511207Ssam 		if (hy_nodebug & 4)
56611207Ssam 			hy_debug_flag = 1;
56711195Ssam #endif
56811195Ssam 		error = EAFNOSUPPORT;
56911195Ssam 		goto drop;
57011195Ssam 	}
57111195Ssam 
57211195Ssam 	/*
57311207Ssam 	 * Add the software and hardware hyperchannel headers.
57411195Ssam 	 * If there's not enough space in the first mbuf, allocate another.
57511195Ssam 	 * If that should fail, drop this sucker.
57611195Ssam 	 * No extra space for headers is allocated.
57711195Ssam 	 */
57811195Ssam 	if (m->m_off > MMAXOFF ||
57911195Ssam 	    MMINOFF + sizeof(struct hym_hdr) > m->m_off) {
58011207Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
58111195Ssam 		if (m == 0) {
58211195Ssam 			m = m0;
58311195Ssam 			error = ENOBUFS;
58411195Ssam 			goto drop;
58511195Ssam 		}
58611195Ssam 		m->m_next = m0;
58711195Ssam 		m->m_off = MMINOFF;
58811195Ssam 		m->m_len = sizeof(struct hym_hdr);
58911195Ssam 	} else {
59011195Ssam 		m->m_off -= sizeof(struct hym_hdr);
59111195Ssam 		m->m_len += sizeof(struct hym_hdr);
59211195Ssam 	}
59311195Ssam 	hym = mtod(m, struct hym_hdr *);
59411195Ssam 	hym->hym_mplen = mplen;
59511195Ssam 	hym->hym_hdr.hyh_type = dtype;
59611195Ssam 	hym->hym_hdr.hyh_off = 0;
59712772Ssam 	hym->hym_hdr.hyh_from = htons((u_short)ifp->if_host[0]);
59811195Ssam 	hym->hym_hdr.hyh_param = loopback;
59911195Ssam #ifdef HYROUTE
60011207Ssam 	if (r->hyr_lasttime.tv_sec != 0) {
60111195Ssam 		register struct hy_hash *rh;
60211195Ssam 		register int i;
60311195Ssam 
60411195Ssam 		i = HYRHASH(dhost);
60511195Ssam 		rh = &r->hyr_hash[i];
60611195Ssam 		i = 0;
60711195Ssam 		while (rh->hyr_key != dhost) {
60811195Ssam 			rh++; i++;
60911195Ssam 			if (rh > &r->hyr_hash[HYRSIZE])
61011195Ssam 				rh = &r->hyr_hash[0];
61111195Ssam 			if (rh->hyr_flags == 0 || i > HYRSIZE)
61211195Ssam 				goto notfound;
61311195Ssam 		}
61411195Ssam 		if (rh->hyr_flags & HYR_GATE) {
61511195Ssam 			loopback = 0;	/* no hardware loopback on gateways */
61611195Ssam 			i = rh->hyr_nextgate;
61711195Ssam 			if (i >= rh->hyr_egate)
61811195Ssam 				rh->hyr_nextgate = rh->hyr_pgate;
61911195Ssam 			else
62011195Ssam 				rh->hyr_nextgate++;
62111195Ssam 			rh = &r->hyr_hash[r->hyr_gateway[i]];
62211195Ssam 			if ((rh->hyr_flags & HYR_DIR) == 0)
62311195Ssam 				goto notfound;
62411195Ssam 		}
62511195Ssam 		hym->hym_hdr.hyh_ctl = rh->hyr_ctl;
62611195Ssam 		hym->hym_hdr.hyh_access = rh->hyr_access;
62711195Ssam 		hym->hym_hdr.hyh_to = rh->hyr_dst;
62811195Ssam 	} else {
62911195Ssam 		hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS;
63011195Ssam 		hym->hym_hdr.hyh_access = 0;
63112772Ssam 		hym->hym_hdr.hyh_to = htons((u_short)dhost);
63211195Ssam 	}
63311195Ssam #else
63411195Ssam 	hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS;
63511195Ssam 	hym->hym_hdr.hyh_access = 0;
63611195Ssam 	hym->hym_hdr.hyh_to = htons(dhost);
63711195Ssam #endif
63811195Ssam 
63911195Ssam 	if (hym->hym_mplen) {
64011195Ssam 		hym->hym_hdr.hyh_ctl |= H_ASSOC;
64111195Ssam #ifdef DEBUG
64211207Ssam 		if (hy_nodebug & 16)
64311207Ssam 			hy_debug_flag = 1;
64411195Ssam #endif
64511207Ssam 	} else
64611207Ssam 		hym->hym_hdr.hyh_ctl &= ~H_ASSOC;
64711195Ssam #ifdef DEBUG
64811207Ssam 	printD("hy%d: output mplen=%x ctl=%x access=%x to=%x",
64911195Ssam 		ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl,
65011207Ssam 		hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to);
65111207Ssam 	printD(" (adapter %x) from=%x param=%x type=%x off=%x\n",
65211195Ssam 		hym->hym_hdr.hyh_to_adapter,
65311195Ssam 		hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param,
65411195Ssam 		hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off);
65511195Ssam #endif
65611195Ssam 	s = splimp();
65711195Ssam 	if (IF_QFULL(&ifp->if_snd)) {
65811195Ssam 		IF_DROP(&ifp->if_snd);
65911195Ssam 		error = ENOBUFS;
66011195Ssam 		splx(s);
66111195Ssam 		goto drop;
66211195Ssam 	}
66311195Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
66411195Ssam 	if (hy_softc[ifp->if_unit].hy_state == WAITING)
66511195Ssam 		hyact(hyinfo[ifp->if_unit]);
66611195Ssam 	splx(s);
66711207Ssam 	return (0);
66811195Ssam notfound:
66911207Ssam 	error = ENETUNREACH;			/* XXX */
67011195Ssam drop:
67111195Ssam 	m_freem(m);
67211207Ssam 	return (error);
67311207Ssam }
67411195Ssam 
67511195Ssam hyact(ui)
67611195Ssam 	register struct uba_device *ui;
67711195Ssam {
67811195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
67911195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
68011195Ssam 
68111195Ssam actloop:
68211195Ssam #ifdef DEBUG
68311207Ssam 	printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
68411207Ssam 		hy_state_names[is->hy_state]);
68511195Ssam #endif
68611195Ssam 	switch (is->hy_state) {
68711195Ssam 
68811195Ssam 	case STARTUP:
68911195Ssam 		goto endintr;
69011195Ssam 
69111195Ssam 	case IDLE: {
69211195Ssam 		register rq = is->hy_flags;
69311195Ssam 
69411195Ssam 		if (rq & RQ_STATUS) {
69511195Ssam 			is->hy_flags &= ~RQ_STATUS;
69611195Ssam 			is->hy_state = STATSENT;
69711207Ssam 			hystart(ui, HYF_STATUS, sizeof (is->hy_status),
69811207Ssam 				is->hy_ifuba.ifu_r.ifrw_info);
69911195Ssam 		} else if (rq & RQ_ENDOP) {
70011195Ssam 			is->hy_flags &= ~RQ_ENDOP;
70111195Ssam 			is->hy_state = ENDOPSENT;
70211195Ssam 			hystart(ui, HYF_END_OP, 0, 0);
70311195Ssam 		} else if (rq & RQ_STATISTICS) {
70411195Ssam 			is->hy_flags &= ~RQ_STATISTICS;
70511195Ssam 			is->hy_state = RSTATSENT;
70611207Ssam 			hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
70711207Ssam 				is->hy_ifuba.ifu_r.ifrw_info);
70811207Ssam 		} else if (HYS_RECVDATA(addr)) {
70911195Ssam 			is->hy_state = RECVSENT;
71011195Ssam 			is->hy_retry = 0;
71111207Ssam 			hystart(ui, HYF_INPUTMSG, MPSIZE,
71211207Ssam 				is->hy_ifuba.ifu_r.ifrw_info);
71311195Ssam 		} else if (rq & RQ_REISSUE) {
71411195Ssam 			is->hy_flags &= ~RQ_REISSUE;
71511195Ssam 			is->hy_state = is->hy_savedstate;
71611195Ssam #ifdef DEBUG
71711207Ssam 			printD("hy%d: reissue cmd=0x%x count=%d",
71811207Ssam 			  ui->ui_unit, is->hy_savedcmd, is->hy_savedcount);
71911207Ssam 			printD(" ubaddr=0x%x retry=%d\n",
72011207Ssam 			  is->hy_savedaddr, is->hy_retry);
72111195Ssam #endif
72211207Ssam 			hystart(ui, is->hy_savedcmd, is->hy_savedcount,
72311207Ssam 				is->hy_savedaddr);
72411195Ssam 		} else {
72511195Ssam 			register struct mbuf *m;
72611195Ssam 
72711195Ssam 			IF_DEQUEUE(&is->hy_if.if_snd, m);
72811207Ssam 			if (m != NULL) {
72911195Ssam 				register struct hym_hdr *hym;
73011195Ssam 				register int mplen;
73111195Ssam 				register int cmd;
73211195Ssam 
73311195Ssam 				is->hy_state = XMITSENT;
73411195Ssam 				is->hy_retry = 0;
73511195Ssam 				hym = mtod(m, struct hym_hdr *);
73611195Ssam #ifdef HYLOG
73711207Ssam 				hylog(HYL_XMIT, sizeof(struct hym_hdr),
73811207Ssam 					(char *)hym);
73911195Ssam #endif
74011195Ssam 				mplen = hym->hym_mplen;
74111207Ssam 				if (hym->hym_hdr.hyh_to_adapter ==
74211207Ssam 				  hym->hym_hdr.hyh_from_adapter)
74311207Ssam 					cmd = HYF_XMITLOCMSG;
74411207Ssam 				else
74511207Ssam 					cmd = HYF_XMITMSG;
74611195Ssam #ifdef DEBUG
74711195Ssam 				printD("hy%d: hym_hdr = ", ui->ui_unit);
74811207Ssam 				if (hy_debug_flag)
74911207Ssam 					hyprintdata((char *)hym,
75011207Ssam 					  sizeof (struct hym_hdr));
75111195Ssam #endif
75211195Ssam 				/*
75311207Ssam 				 * Strip off the software part of
75411195Ssam 				 * the hyperchannel header
75511195Ssam 				 */
75611195Ssam 				m->m_off += sizeof(struct hym_data);
75711195Ssam 				m->m_len -= sizeof(struct hym_data);
75811195Ssam 				is->hy_olen = if_wubaput(&is->hy_ifuba, m);
75911195Ssam 				if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
76011207Ssam 					UBAPURGE(is->hy_ifuba.ifu_uba,
76111207Ssam 						is->hy_ifuba.ifu_w.ifrw_bdp);
76211195Ssam #ifdef DEBUG
76311207Ssam 				printD(
76411207Ssam 		"hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
76511195Ssam 					ui->ui_unit, mplen, is->hy_olen);
76611207Ssam 				if (hy_debug_flag)
76711207Ssam 					hyprintdata(
76811207Ssam 					  is->hy_ifuba.ifu_w.ifrw_addr,
76911207Ssam 					  is->hy_olen);
77011195Ssam #endif
77111207Ssam 				hystart(ui, cmd,
77211207Ssam 				   (mplen == 0) ? is->hy_olen : mplen,
77311207Ssam 				   is->hy_ifuba.ifu_w.ifrw_info);
77411195Ssam 				if (mplen != 0)
77511195Ssam 					is->hy_flags |= RQ_XASSOC;
77611195Ssam 			} else if (rq & RQ_MARKDOWN) {
77711195Ssam 				is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
77811195Ssam 				is->hy_state = MARKPORT;
77911195Ssam 				is->hy_retry = 0;
78011195Ssam 				/*
78111207Ssam 				 * Port number is taken from status data
78211195Ssam 				 */
78311207Ssam 				hystart(ui,
78412772Ssam 				 (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)),
78512772Ssam 				 0, 0);
78611195Ssam 			} else if (rq & RQ_MARKUP) {
78711195Ssam 				register struct ifnet *ifp = &is->hy_if;
78811207Ssam 				register struct sockaddr_in *sin =
78911207Ssam 				   (struct sockaddr_in *)&ifp->if_addr;
79011195Ssam 
79111207Ssam 				is->hy_flags &= ~RQ_MARKUP;
79211195Ssam 				is->hy_retry = 0;
79311195Ssam 				/*
794*13065Ssam 				 * Fill in the host number
79511207Ssam 				 * from the status buffer
79611195Ssam 				 */
79711207Ssam 				printf(
79811207Ssam 	"hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
79911195Ssam 					ui->ui_unit,
80011195Ssam 					is->hy_stat.hyc_uaddr,
80111195Ssam 					PORTNUM(&is->hy_status),
80211207Ssam 					(is->hy_stat.hyc_atype[0]<<8) |
80311207Ssam 						is->hy_stat.hyc_atype[1],
80411195Ssam 					is->hy_stat.hyc_atype[2]);
80511195Ssam 
80611207Ssam 				ifp->if_host[0] =
80711207Ssam 				  (is->hy_stat.hyc_uaddr << 8) |
80811207Ssam 					PORTNUM(&is->hy_status);
80911207Ssam 				sin->sin_addr =
81011207Ssam 				   if_makeaddr(ifp->if_net, ifp->if_host[0]);
81111195Ssam 				ifp->if_flags |= IFF_UP;
81211195Ssam 				if_rtinit(ifp, RTF_UP);
81311195Ssam #ifdef HYLOG
81411195Ssam 				hylog(HYL_UP, 0, (char *)0);
81511195Ssam #endif
81611195Ssam 			} else {
81711195Ssam 				is->hy_state = WAITING;
81811195Ssam 				is->hy_retry = 0;
81911195Ssam 				hystart(ui, HYF_WAITFORMSG, 0, 0);
82011195Ssam 			}
82111195Ssam 		}
82211207Ssam 		break;
82311195Ssam 	}
82411195Ssam 
82511195Ssam 	case STATSENT:
82612772Ssam 		bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status,
82711207Ssam 		  sizeof (struct hy_status));
82811195Ssam #ifdef DEBUG
82911207Ssam 		printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
83011207Ssam 			ui->ui_unit, is->hy_status.hys_gen_status,
83111207Ssam 			is->hy_status.hys_last_fcn,
83211207Ssam 			is->hy_status.hys_resp_trunk,
83311207Ssam 			is->hy_status.hys_status_trunk,
83411207Ssam 			is->hy_status.hys_recd_resp,
83511207Ssam 			is->hy_status.hys_error,
83611207Ssam 			is->hy_status.hys_caddr,
83711207Ssam 			is->hy_status.hys_pad);
83811195Ssam #endif
83911195Ssam 		is->hy_state = IDLE;
84011195Ssam #ifdef HYLOG
84111207Ssam 		hylog(HYL_STATUS, sizeof (struct hy_status),
84211207Ssam 			(char *)&is->hy_status);
84311195Ssam #endif
84411195Ssam #ifdef HYELOG
84511195Ssam 		{
84611195Ssam 			register int i;
84711195Ssam 
84811195Ssam 			i = is->hy_status.hys_error;
84911195Ssam 			if (i < HYE_MAX)
85011195Ssam 				i = HYE_MAX;
85111195Ssam 			switch (is->hy_status.hys_last_fcn) {
85211195Ssam 				case HYF_XMITLOCMSG:
85311195Ssam 					i += HYE_MAX+1;	/* fall through */
85411195Ssam 				case HYF_XMITLSTDATA:
85511195Ssam 					i += HYE_MAX+1;	/* fall through */
85611195Ssam 				case HYF_XMITMSG:
85711195Ssam 					i += HYE_MAX+1;
85811195Ssam 			}
85911195Ssam 			hy_elog[i]++;
86011195Ssam 		}
86111195Ssam #endif
86211195Ssam 		break;
86311195Ssam 
86411195Ssam 	case RSTATSENT: {
86511207Ssam 		register struct hy_stat *p =
86611207Ssam 			(struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
86711195Ssam 
86811195Ssam 		is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt);
86911195Ssam 		is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt);
87011195Ssam 		is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy);
87111195Ssam 		is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret);
87211195Ssam 		is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad);
87311195Ssam 		is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret);
87411195Ssam 		is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort);
87511195Ssam 		is->hy_stat.hyc_atype[0] = p->hyc_atype[0];
87611195Ssam 		is->hy_stat.hyc_atype[1] = p->hyc_atype[1];
87711195Ssam 		is->hy_stat.hyc_atype[2] = p->hyc_atype[2];
87811195Ssam 		is->hy_stat.hyc_uaddr = p->hyc_uaddr;
87911195Ssam #ifdef DEBUG
88011207Ssam 		printD(
88111207Ssam 	"hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n",
88211195Ssam 			ui->ui_unit,
88311195Ssam 			is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt,
88411195Ssam 			is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret,
88511195Ssam 			is->hy_stat.hyc_crcbad);
88611195Ssam 		printD("	mcret %d tdabort %d atype %x %x %x uaddr %x\n",
88711195Ssam 			is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort,
88811195Ssam 			is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
88911195Ssam 			is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
89011195Ssam #endif
89111195Ssam 		is->hy_state = IDLE;
89211195Ssam #ifdef HYLOG
89311207Ssam 		hylog(HYL_STATISTICS, sizeof (struct hy_stat),
89411207Ssam 			(char *)&is->hy_stat);
89511195Ssam #endif
89611195Ssam 		break;
89711195Ssam 	}
89811195Ssam 
89911195Ssam 	case CLEARSENT:
90011195Ssam 		is->hy_state = IDLE;
90111195Ssam 		break;
90211195Ssam 
90311195Ssam 	case ENDOPSENT:
90411195Ssam 		is->hy_state = IDLE;
90511195Ssam 		break;
90611195Ssam 
90711195Ssam 	case RECVSENT: {
90811207Ssam 		register struct hy_hdr *hyh;
90911207Ssam 		register unsigned len;
91011195Ssam 
91111207Ssam 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
91211207Ssam 			UBAPURGE(is->hy_ifuba.ifu_uba,
91311207Ssam 				is->hy_ifuba.ifu_r.ifrw_bdp);
91411207Ssam 		hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
91511207Ssam 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
91611207Ssam 		if (len > MPSIZE) {
91711207Ssam 			printf("hy%d: RECVD MP > MPSIZE (%d)\n",
91811207Ssam 				ui->ui_unit, len);
91911195Ssam #ifdef DEBUG
92011207Ssam 			hy_debug_flag = 1;
92111207Ssam 			printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
92211207Ssam 				ui->ui_unit, addr->hyd_csr, HY_CSR_BITS,
92311207Ssam 				addr->hyd_bar, addr->hyd_wcr);
92411195Ssam #endif
92511207Ssam 		}
92611195Ssam #ifdef DEBUG
92711207Ssam 		printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
92811207Ssam 		if (hy_debug_flag)
92911207Ssam 			hyprintdata((char *)hyh, len);
93011195Ssam #endif
93111207Ssam 		if (hyh->hyh_ctl & H_ASSOC) {
93211207Ssam 			is->hy_state = RECVDATASENT;
93311207Ssam 			is->hy_ilen = len;
93411207Ssam 			is->hy_retry = 0;
93511207Ssam 			hystart(ui, HYF_INPUTDATA,
93612772Ssam 			  (int)(HYMTU-len+sizeof (struct hy_hdr)),
93712772Ssam 			  (int)(is->hy_ifuba.ifu_r.ifrw_info + len));
93811207Ssam 		} else {
93912772Ssam 			hyrecvdata(ui, hyh, (int)len);
94011207Ssam 			is->hy_state = IDLE;
94111195Ssam 		}
94211207Ssam 		break;
94311207Ssam 	}
94411195Ssam 
94511195Ssam 	case RECVDATASENT: {
94611207Ssam 		register struct hy_hdr *hyh;
94711207Ssam 		register unsigned len;
94811195Ssam 
94911207Ssam 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
95011207Ssam 			UBAPURGE(is->hy_ifuba.ifu_uba,
95111207Ssam 				is->hy_ifuba.ifu_r.ifrw_bdp);
95211207Ssam 		hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
95311207Ssam 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
95411195Ssam #ifdef DEBUG
95511207Ssam 		printD("hy%d: recvd assoc data, len = %d, data = ",
95611207Ssam 			ui->ui_unit, len);
95711207Ssam 		if (hy_debug_flag)
95811207Ssam 			hyprintdata((char *)hyh + is->hy_ilen, len);
95911195Ssam #endif
96012772Ssam 		hyrecvdata(ui, hyh, (int)(len + is->hy_ilen));
96111207Ssam 		is->hy_state = IDLE;
96211207Ssam 		break;
96311207Ssam 	}
96411195Ssam 
96511195Ssam 	case XMITSENT:
96611207Ssam 		if (is->hy_flags & RQ_XASSOC) {
96711207Ssam 			register unsigned len;
96811195Ssam 
96911207Ssam 			is->hy_flags &= ~RQ_XASSOC;
97011207Ssam 			is->hy_state = XMITDATASENT;
97111207Ssam 			is->hy_retry = 0;
97211207Ssam 			len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
97311207Ssam 			if (len > is->hy_olen) {
97411207Ssam 				printf(
97511207Ssam 				"hy%d: xmit error - len > hy_olen [%d > %d]\n",
97611207Ssam 				ui->ui_unit, len, is->hy_olen);
97711195Ssam #ifdef DEBUG
97811207Ssam 				hy_debug_flag = 1;
97911195Ssam #endif
98011195Ssam 			}
98111207Ssam 			hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
98211207Ssam 				is->hy_ifuba.ifu_w.ifrw_info + len);
98311207Ssam 			break;
98411207Ssam 		}
98511207Ssam 		/* fall through to ... */
98611195Ssam 
98711195Ssam 	case XMITDATASENT:
98811207Ssam 		hyxmitdata(ui);
98911207Ssam 		is->hy_state = IDLE;
99011207Ssam 		break;
99111195Ssam 
99211195Ssam 	case WAITING:	/* wait for message complete or output requested */
99311207Ssam 		if (HYS_RECVDATA(addr))
99411195Ssam 			is->hy_state = IDLE;
99511195Ssam 		else {
99611195Ssam 			is->hy_state = CLEARSENT;
99711195Ssam 			is->hy_retry = 0;
99811195Ssam 			hystart(ui, HYF_CLRWFMSG, 0, 0);
99911195Ssam 		}
100011195Ssam 		break;
100111195Ssam 
100211195Ssam 	case MARKPORT:
100311195Ssam 		is->hy_state = STARTUP;
100411195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
100511195Ssam 		goto endintr;
100611195Ssam 
100711195Ssam 	default:
100811207Ssam 		printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
100911207Ssam 			ui->ui_unit, is->hy_state);
101011195Ssam 		panic("HYPERCHANNEL IN INVALID STATE");
101111195Ssam 		/*NOTREACHED*/
101211207Ssam 	}
101311195Ssam 	if (is->hy_state == IDLE)
101411195Ssam 		goto actloop;
101511195Ssam endintr:
101611195Ssam #ifdef DEBUG
101711207Ssam 	printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit,
101811207Ssam 		hy_state_names[is->hy_state]);
101911195Ssam #endif
102011207Ssam }
102111195Ssam 
102211195Ssam /*
102311195Ssam  * Called from device interrupt when recieving data.
102411195Ssam  * Examine packet to determine type.  Decapsulate packet
102511195Ssam  * based on type and pass to type specific higher-level
102611195Ssam  * input routine.
102711195Ssam  */
102811195Ssam hyrecvdata(ui, hyh0, len)
102911195Ssam 	struct uba_device *ui;
103011195Ssam 	struct hy_hdr *hyh0;
103111195Ssam 	int len;
103211195Ssam {
103311195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
103411195Ssam 	register struct hy_hdr *hyh = hyh0;
103511195Ssam     	struct mbuf *m;
103611195Ssam 	register struct ifqueue *inq;
103711195Ssam 
103811195Ssam 	is->hy_if.if_ipackets++;
103911195Ssam #ifdef DEBUG
104011207Ssam 	printD("hy%d: recieved packet, len = %d (actual %d)\n",
104111207Ssam 		ui->ui_unit, len,
104211207Ssam 		len - (hyh->hyh_off + sizeof (struct hy_hdr)));
104311195Ssam #endif
104411195Ssam #ifdef HYLOG
104511195Ssam 	{
104611195Ssam 		struct {
104711195Ssam 			short hlen;
104811195Ssam 			struct hy_hdr hhdr;
104911195Ssam 		} hh;
105011195Ssam 		hh.hlen = len;
105111195Ssam 		hh.hhdr = *hyh;
105211195Ssam 		hylog(HYL_RECV, sizeof(hh), (char *)&hh);
105311195Ssam 	}
105411195Ssam #endif
105511195Ssam 	if (len > HYMTU + MPSIZE || len == 0)
105611195Ssam 		return;			/* sanity */
105711195Ssam 	/*
105811195Ssam 	 * Pull packet off interface.
105911195Ssam 	 */
106011195Ssam 	m = if_rubaget(&is->hy_ifuba, len, 0);
106111207Ssam 	if (m == NULL)
106211195Ssam 		return;
106311195Ssam 	switch (hyh->hyh_type) {
106411195Ssam 
106511195Ssam #ifdef INET
106611195Ssam 	case HYLINK_IP:
106711195Ssam 		/*
106811207Ssam 		 * Strip the variable portion of the hyperchannel header
106911207Ssam 		 * (fixed portion stripped in if_rubaget).
107011195Ssam 		 */
107111195Ssam 		m->m_len -= hyh->hyh_off;
107211195Ssam 		m->m_off += hyh->hyh_off;
107311195Ssam 		schednetisr(NETISR_IP);
107411195Ssam 		inq = &ipintrq;
107511195Ssam 		break;
107611195Ssam #endif
107711195Ssam 	default:
107811195Ssam 		m_freem(m);
107911195Ssam 		return;
108011195Ssam 	}
108111195Ssam 	if (IF_QFULL(inq)) {
108211195Ssam 		IF_DROP(inq);
108311195Ssam 		m_freem(m);
108411195Ssam 	} else
108511195Ssam 		IF_ENQUEUE(inq, m);
108611207Ssam }
108711195Ssam 
108811195Ssam /*
108911207Ssam  * Transmit done, release resources, bump counters.
109011195Ssam  */
109111195Ssam hyxmitdata(ui)
109211195Ssam 	struct uba_device *ui;
109311195Ssam {
109411195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
109511195Ssam 
109611195Ssam 	is->hy_if.if_opackets++;
109711207Ssam 	if (is->hy_ifuba.ifu_xtofree) {
109811195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
109911195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
110011195Ssam 	}
110111207Ssam }
110211195Ssam 
110311195Ssam hycancel(ui)
110411195Ssam 	register struct uba_device *ui;
110511195Ssam {
110611195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
110711195Ssam 
110811207Ssam 	if (is->hy_ifuba.ifu_xtofree) {
110911195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
111011195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
111111195Ssam 	}
111211195Ssam #ifdef DEBUG
111311207Ssam 	if (hy_nodebug & 1)
111411207Ssam 		hy_debug_flag = 1;
111511195Ssam #endif
111611195Ssam #ifdef DEBUG
111711195Ssam 	printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
111811195Ssam 		ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
111911195Ssam 		is->hy_savedcount, is->hy_savedaddr);
112011207Ssam 	printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n",
112111207Ssam 		is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr,
112211207Ssam 		is->hy_retry);
112311207Ssam 	printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
112411207Ssam 		is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr,
112511207Ssam 		is->hy_savedcmd);
112611195Ssam #endif
112711195Ssam 	is->hy_state = IDLE;
112811195Ssam 	is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
112911195Ssam 	hyact(ui);
113011207Ssam }
113111195Ssam 
113211195Ssam #ifdef DEBUG
113311195Ssam hyprintdata(cp, len)
113411195Ssam 	register char *cp;
113511195Ssam 	register int len;
113611195Ssam {
113711195Ssam 	register int count = 16;
113811195Ssam 	register char *fmt;
113911195Ssam 	static char regfmt[] = "\n\t %x";
114011195Ssam 
114111195Ssam 	fmt = &regfmt[2];
114211195Ssam 	while (--len >= 0) {
114311195Ssam 		printL(fmt, *cp++ & 0xff);
114411195Ssam 		fmt = &regfmt[2];
114511195Ssam 		if (--count <= 0) {
114611195Ssam 			fmt = &regfmt[0];
114711195Ssam 			count = 16;
114811195Ssam 		}
114911195Ssam 	}
115011195Ssam 	printL("\n");
115111195Ssam }
115211195Ssam #endif
115311195Ssam 
115411195Ssam hywatch(unit)
115511195Ssam int unit;
115611195Ssam {
115711195Ssam 	register struct hy_softc *is = &hy_softc[unit];
115811195Ssam 	register struct uba_device *ui = hyinfo[unit];
115911195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
116011195Ssam 	int s;
116111195Ssam 
116211195Ssam 	s = splimp();
116311195Ssam 	is->hy_if.if_timer = SCANINTERVAL;
116411207Ssam 	if (is->hy_ntime > 2 && is->hy_state != WAITING &&
116511207Ssam 	  is->hy_state != STARTUP && is->hy_state != IDLE) {
116611195Ssam 		printf("hy%d: watchdog timer expired\n", unit);
116711195Ssam 		hycancel(ui);
116811195Ssam 	}
116911195Ssam #ifdef PI13
117011195Ssam 	if ((addr->hyd_csr & S_POWEROFF) != 0) {
117111195Ssam 		addr->hyd_csr |= S_POWEROFF;
117211195Ssam 		DELAY(100);
117311195Ssam 		if ((addr->hyd_csr & S_POWEROFF) == 0) {
117411195Ssam 			printf("hy%d: adapter power restored\n", unit);
117511195Ssam 			is->hy_state = IDLE;
117611207Ssam 			is->hy_flags |=
117711207Ssam 			  (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
117811195Ssam 			hyact(ui);
117911195Ssam 		}
118011195Ssam 	}
118111195Ssam #endif
118211195Ssam 	splx(s);
118311195Ssam }
118411195Ssam 
118511195Ssam #ifdef HYLOG
118611195Ssam hylog(code, len, ptr)
118711195Ssam 	int code;
118811195Ssam 	int len;
118911195Ssam 	char *ptr;
119011195Ssam {
119111195Ssam 	register unsigned char *p;
119211195Ssam 	int s;
119311195Ssam 
119411195Ssam 	s = splimp();
119511195Ssam 	if (hy_log.hyl_self != &hy_log) {
119611195Ssam 		hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
119711195Ssam 		hy_log.hyl_ptr = &hy_log.hyl_buf[0];
119811195Ssam 		hy_log.hyl_self = &hy_log;
119911195Ssam 		hy_log.hyl_enable = HYL_DISABLED;
120011195Ssam 		hy_log.hyl_onerr = HYL_CATCH1;
120111195Ssam 	}
120211207Ssam 	if (hy_log.hyl_enable == HYL_DISABLED ||
120311207Ssam 	  hy_log.hyl_enable == HYL_CAUGHT1 ||
120411207Ssam 	  hy_log.hyl_enable == HYL_CAUGHTSTATUS ||
120511207Ssam 	  (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS))
120611207Ssam 		goto out;
120711195Ssam 	p = hy_log.hyl_ptr;
120811195Ssam 	if (p + len + 2 >= hy_log.hyl_eptr) {
120912772Ssam 		bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p));
121011195Ssam 		p = &hy_log.hyl_buf[0];
121111195Ssam 		if (hy_log.hyl_enable == HYL_CATCH1) {
121211195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1;
121311195Ssam 			goto out;
121411195Ssam 		}
121511195Ssam 		if (hy_log.hyl_enable == HYL_CATCHSTATUS) {
121611195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS;
121711195Ssam 			goto out;
121811195Ssam 		}
121911195Ssam 	}
122011195Ssam 	*p++ = code;
122111195Ssam 	*p++ = len;
122212772Ssam 	bcopy(ptr, (caddr_t)p, (unsigned)len);
122311195Ssam 	hy_log.hyl_ptr = p + len;
122411195Ssam out:
122511195Ssam 	splx(s);
122611195Ssam }
122711195Ssam #endif
122811195Ssam 
122912772Ssam /*ARGSUSED*/
123013058Ssam hyioctl(ifp, cmd, data)
123113058Ssam 	register struct ifnet *ifp;
123211207Ssam 	int cmd;
123311207Ssam 	caddr_t	data;
123411195Ssam {
1235*13065Ssam 	struct sockaddr_in *sin;
123611207Ssam 	int s = splimp(), error = 0;
123711195Ssam 
123811195Ssam 	switch(cmd) {
123911195Ssam 
1240*13065Ssam 	case SIOCSIFADDR:
1241*13065Ssam 		if (ifp->if_flags & IFF_RUNNING)
1242*13065Ssam 			if_rtinit(ifp, -1);
1243*13065Ssam 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
1244*13065Ssam 		ifp->if_net = in_netof(sin->sin_addr);
1245*13065Ssam 		sin = (struct sockaddr_in *)&ifp->if_addr;
1246*13065Ssam 		sin->sin_family = AF_INET;
1247*13065Ssam 		sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
1248*13065Ssam 		if (ifp->if_flags & IFF_RUNNING)
1249*13065Ssam 			if_rtinit(ifp, RTF_UP);
1250*13065Ssam 		else
1251*13065Ssam 			hyinit(ifp->if_unit);
1252*13065Ssam 		break;
1253*13065Ssam 
125411195Ssam 	case HYSETROUTE:
125511207Ssam 		if (!suser()) {
125611207Ssam 			error = EPERM;
125711207Ssam 			goto bad;
125811195Ssam 		}
125913058Ssam 		hy_route[ifp->if_unit] = *(struct hyroute *)ifr->ifr_data;
126013058Ssam 		hy_route[ifp->if_unit].hyr_lasttime = time;
126111195Ssam 		break;
126211195Ssam 
126311195Ssam 	case HYGETROUTE:
126413058Ssam 		*(struct hyroute *)ifr->ifr_data = hy_route[ifp->if_unit];
126511195Ssam 		break;
126611195Ssam 
126711195Ssam 	default:
126813058Ssam 		error = EINVAL;
126911195Ssam 		break;
127011195Ssam 	}
127111207Ssam bad:
127211195Ssam 	splx(s);
127311207Ssam 	return (error);
127411195Ssam }
127511207Ssam #endif
1276