xref: /csrg-svn/sys/vax/if/if_hy.c (revision 13196)
1*13196Sroot /*	if_hy.c	4.9	83/06/19	*/
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"
2413088Ssam 
2511195Ssam #include "../net/if.h"
2611207Ssam #include "../net/netisr.h"
2711195Ssam #include "../net/route.h"
2811195Ssam #include "../netinet/in.h"
2911195Ssam #include "../netinet/in_systm.h"
3011195Ssam #include "../netinet/ip.h"
3111195Ssam #include "../netinet/ip_var.h"
3211195Ssam 
3311207Ssam #include "../vax/cpu.h"
3411207Ssam #include "../vax/mtpr.h"
3511207Ssam #include "../vaxuba/ubareg.h"
3611207Ssam #include "../vaxuba/ubavar.h"
3711195Ssam #include "../vaxif/if_hy.h"
3811198Ssam #include "../vaxif/if_hyreg.h"
3911195Ssam #include "../vaxif/if_uba.h"
4011195Ssam 
4111195Ssam #define HYROUTE
4211195Ssam #define HYELOG
4311195Ssam #define	HYMTU	576
4411195Ssam 
4513058Ssam int	hyprobe(), hyattach(), hyinit(), hyioctl();
4613058Ssam int	hyoutput(), hyreset(), hywatch();
4711195Ssam struct	uba_device *hyinfo[NHY];
4811195Ssam u_short hystd[] = { 0772410, 0 };
4911195Ssam struct	uba_driver hydriver =
5011195Ssam 	{ hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo };
5111195Ssam 
5211195Ssam /*
5311195Ssam  * Hyperchannel software status per interface.
5411195Ssam  *
5511195Ssam  * Each interface is referenced by a network interface structure,
5611195Ssam  * hy_if, which the routing code uses to locate the interface.
5711195Ssam  * This structure contains the output queue for the interface, its address, ...
5811195Ssam  * We also have, for each interface, a UBA interface structure, which
5911195Ssam  * contains information about the UNIBUS resources held by the interface:
6011195Ssam  * map registers, buffered data paths, etc.  Information is cached in this
6111195Ssam  * structure for use by the if_uba.c routines in running the interface
6211195Ssam  * efficiently.
6311195Ssam  */
6411195Ssam struct	hy_softc {
6511195Ssam 	struct	ifnet hy_if;		/* network-visible interface */
6611195Ssam 	struct	ifuba hy_ifuba;		/* UNIBUS resources */
6711207Ssam 	short	hy_flags;		/* flags */
6811207Ssam 	short	hy_state;		/* driver state */
6911195Ssam 	int	hy_ilen;		/* mp length on input */
7011195Ssam 	int	hy_olen;		/* packet length on output */
7111195Ssam 	int	hy_lastwcr;		/* last command's word count */
7211195Ssam 	short	hy_savedstate;		/* saved for reissue after status */
7311195Ssam 	short	hy_savedcmd;		/* saved command for reissue */
7411195Ssam 	int	hy_savedcount;		/* saved byte count for reissue */
7511195Ssam 	int	hy_savedaddr;		/* saved unibus address for reissue */
7611195Ssam 	int	hy_ntime;		/* number of timeouts since last cmd */
7711195Ssam 	int	hy_retry;		/* retry counter */
7811207Ssam 	struct	hy_stat hy_stat;	/* statistics */
7911207Ssam 	struct	hy_status hy_status;	/* status */
8011195Ssam } hy_softc[NHY];
8111195Ssam 
8211195Ssam #ifdef HYELOG
8311207Ssam #define HYE_MAX	0x18
8411207Ssam u_long	hy_elog[(HYE_MAX+1)*4];
8511195Ssam #endif
8611195Ssam 
8711195Ssam #ifdef DEBUG
8811195Ssam #define printL	lprintf
8911195Ssam #define printD	if (hy_debug_flag) lprintf
9011195Ssam int	hy_debug_flag = 0;
9111195Ssam /*
9211195Ssam  * hy_nodebug bit 0x01	set hy_debug_flag on hycancel
9311195Ssam  * hy_nodebug bit 0x02	set hy_debug_flag on command reissue
9411195Ssam  * hy_nodebug bit 0x04	set hy_debug_flag on abnormal interrupt
9511195Ssam  * hy_nodebug bit 0x08	set hy_debug_flag on hyouput
9611195Ssam  * hy_nodebug bit 0x10	set hy_debug_flag on hyouput with associated data
9711195Ssam  */
9811195Ssam int	hy_nodebug = 0x0;
9911195Ssam #else
10011195Ssam #define printD	hyvoid
10111195Ssam #endif
10211195Ssam 
10311195Ssam /*
10411207Ssam  * Requests for service (in order by descending priority).
10511195Ssam  */
10611195Ssam #define RQ_ENDOP	001	/* end the last adapter function */
10711195Ssam #define RQ_REISSUE	002	/* reissue previous cmd after status */
10811195Ssam #define RQ_STATUS	004	/* get the status of the adapter */
10911195Ssam #define RQ_STATISTICS	010	/* get the statistics of the adapter */
11011195Ssam #define RQ_MARKDOWN	020	/* mark this adapter port down */
11111195Ssam #define RQ_MARKUP	040	/* mark this interface up */
11211195Ssam 
11311195Ssam #define RQ_XASSOC	0100	/* associated data to transmit */
11411195Ssam 
11511195Ssam /*
11611207Ssam  * Driver states.
11711195Ssam  */
11811195Ssam #define	STARTUP		0	/* initial state (before fully there) */
11911195Ssam #define	IDLE		1	/* idle state */
12011195Ssam #define	STATSENT	2	/* status cmd sent to adapter */
12111195Ssam #define	ENDOPSENT	3	/* end operation cmd sent */
12211195Ssam #define	RECVSENT	4	/* input message cmd sent */
12311195Ssam #define	RECVDATASENT	5	/* input data cmd sent */
12411195Ssam #define	XMITSENT	6	/* transmit message cmd sent */
12511195Ssam #define	XMITDATASENT	7	/* transmit data cmd sent */
12611195Ssam #define	WAITING		8	/* waiting for messages */
12711195Ssam #define	CLEARSENT	9	/* clear wait for message cmd sent */
12811195Ssam #define MARKPORT	10	/* mark this host's adapter port down issued */
12911195Ssam #define RSTATSENT	11	/* read statistics cmd sent to adapter */
13011195Ssam 
13111195Ssam #ifdef DEBUG
13211195Ssam char *hy_state_names[] = {
13311195Ssam 	"Startup",
13411195Ssam 	"Idle",
13511195Ssam 	"Status Sent",
13611195Ssam 	"End op Sent",
13711195Ssam 	"Recieve Message Proper Sent",
13811195Ssam 	"Recieve Data Sent",
13911195Ssam 	"Transmit Message Proper Sent",
14011195Ssam 	"Transmit Data Sent",
14111195Ssam 	"Wait for Message Sent",
14211195Ssam 	"Clear Wait for Message Sent",
14311195Ssam 	"Mark Port Down Sent",
14411195Ssam 	"Read Statistics Sent"
14511195Ssam };
14611195Ssam #endif
14711195Ssam 
14811195Ssam #define SCANINTERVAL	10	/* seconds */
14911195Ssam #define MAXINTERVAL	20	/* seconds (max action) */
15011195Ssam 
15111195Ssam /*
15211195Ssam  * Cause a device interrupt.  This code uses a buffer starting at
15311195Ssam  * location zero on the unibus (which is already mapped by the
15411195Ssam  * autoconfigure code in the kernel).
15511195Ssam  */
15611195Ssam hyprobe(reg)
15711195Ssam 	caddr_t reg;
15811195Ssam {
15911195Ssam 	register int br, cvec;		/* r11, r10 value-result */
16011195Ssam 	register struct hydevice *addr = (struct hydevice *) reg;
16111195Ssam 
16211195Ssam #ifdef lint
16311195Ssam 	br = 0; cvec = br; br = cvec;
16411195Ssam 	hyint(0);
16511195Ssam #endif
16611195Ssam 	/*
16711195Ssam 	 * request adapter status to a buffer starting at unibus location 0
16811195Ssam 	 */
16911195Ssam 	addr->hyd_bar = 0;
17011195Ssam 	addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1);
17111195Ssam 	addr->hyd_dbuf = HYF_STATUS;
17211195Ssam #ifdef PI13
17311195Ssam 	addr->hyd_csr |= S_GO | S_IE | S_IATTN;
17411195Ssam #else
17511195Ssam 	addr->hyd_csr |= S_GO | S_IE;
17611195Ssam #endif
17711195Ssam 	DELAY(10000);
17811195Ssam #ifdef PI13
17911195Ssam 	addr->hyd_csr |= S_CLRINT;	/* clear any stacked interrupts */
18011195Ssam #endif
18111195Ssam 	addr->hyd_csr &= ~(S_IE | S_CLRINT);	/* disable further interrupts */
18211195Ssam 	return(1);
18311207Ssam }
18411195Ssam 
18511195Ssam /*
18611195Ssam  * Interface exists: make available by filling in network interface
18711195Ssam  * record.  System will initialize the interface when it is ready
18811195Ssam  * to accept packets.
18911195Ssam  */
19011195Ssam hyattach(ui)
19111195Ssam 	struct uba_device *ui;
19211195Ssam {
19311195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
19411195Ssam 	register struct ifnet *ifp = &is->hy_if;
19511195Ssam 
19611195Ssam 	ifp->if_unit = ui->ui_unit;
19711195Ssam 	ifp->if_name = "hy";
19811195Ssam 	ifp->if_mtu = HYMTU;
19911195Ssam 	is->hy_state = STARTUP;		/* don't allow state transitions yet */
20011195Ssam 	ifp->if_init = hyinit;
20113058Ssam 	ifp->if_ioctl = hyioctl;
20211195Ssam 	ifp->if_output = hyoutput;
20311207Ssam 	ifp->if_reset = hyreset;
20411195Ssam 	ifp->if_watchdog = hywatch;
20511195Ssam 	ifp->if_timer = SCANINTERVAL;
20611195Ssam 	is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
20711207Ssam #ifdef notdef
20811195Ssam 	is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
20911195Ssam #endif
21011195Ssam 	if_attach(ifp);
21111207Ssam }
21211195Ssam 
21311195Ssam /*
21411195Ssam  * Reset of interface after UNIBUS reset.
21511195Ssam  * If interface is on specified uba, reset its state.
21611195Ssam  */
21711195Ssam hyreset(unit, uban)
21811195Ssam 	int unit, uban;
21911195Ssam {
22011195Ssam 	register struct uba_device *ui = hyinfo[unit];
22111195Ssam 
22211207Ssam 	if (unit >= NHY || ui == 0 || ui->ui_alive == 0 ||
22311207Ssam 	  ui->ui_ubanum != uban)
22411195Ssam 		return;
22511195Ssam 	printf(" hy%d", unit);
22611195Ssam 	hyinit(unit);
22711207Ssam }
22811195Ssam 
22911195Ssam /*
23011195Ssam  * Initialization of interface; clear recorded pending
23111195Ssam  * operations, and reinitialize UNIBUS usage.
23211195Ssam  */
23311195Ssam hyinit(unit)
23411195Ssam 	int unit;
23511195Ssam {
23611195Ssam 	register struct hy_softc *is = &hy_softc[unit];
23711195Ssam 	register struct uba_device *ui = hyinfo[unit];
23813065Ssam 	struct sockaddr_in *sin;
23911195Ssam 	int s;
24011195Ssam 
24113088Ssam 	sin = (struct sockaddr_in *)&is->hy_if.if_addr;
24213065Ssam 	if (in_netof(sin->sin_addr) == 0)
24313065Ssam 		return;
24411195Ssam 	if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
24511195Ssam 	    sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) {
24611195Ssam #ifdef DEBUG
24711207Ssam 		if (hy_nodebug & 4)
24811207Ssam 			hy_debug_flag = 1;
24911195Ssam #endif
25011195Ssam 		printf("hy%d: can't initialize\n", unit);
25111195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
25211195Ssam 		return;
25311195Ssam 	}
25413088Ssam 	is->hy_if.if_flags |= IFF_RUNNING;
25511195Ssam 	/*
25611207Ssam 	 * Issue wait for message and start the state machine
25711195Ssam 	 */
25811195Ssam 	s = splimp();
25911195Ssam 	is->hy_state = IDLE;
26011195Ssam 	is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
26111195Ssam 	is->hy_retry = 0;
26211195Ssam 	hyact(ui);
26311195Ssam 	splx(s);
26411207Ssam }
26511195Ssam 
26611195Ssam /*
26711207Ssam  * Issue a command to the adapter
26811195Ssam  */
26911195Ssam hystart(ui, cmd, count, ubaddr)
27011195Ssam 	struct uba_device *ui;
27111207Ssam 	int cmd, count, ubaddr;
27211195Ssam {
27311195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
27411195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
27511195Ssam 
27611195Ssam #ifdef DEBUG
27711207Ssam 	printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
27811207Ssam 		ui->ui_unit, cmd, count, ubaddr);
27911195Ssam 	printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
28011207Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
28111207Ssam 		addr->hyd_wcr);
28211195Ssam #endif
28311207Ssam 	if (((is->hy_flags & RQ_REISSUE) == 0) &&
28411207Ssam 	  (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
28511195Ssam 		is->hy_savedstate = is->hy_state;
28611195Ssam 		is->hy_savedcmd = cmd;
28711195Ssam 		is->hy_savedcount = count;
28811195Ssam 		is->hy_savedaddr = ubaddr;
28911195Ssam 	}
29011195Ssam 	addr->hyd_bar = ubaddr & 0xffff;
29111207Ssam 	addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);
29211195Ssam 	addr->hyd_dbuf = cmd;
29311195Ssam #ifdef PI13
29411195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN;
29511195Ssam #else
29611195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE;
29711195Ssam #endif
29811195Ssam #ifdef DEBUG
29911195Ssam 	printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
30011207Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
30111207Ssam 		addr->hyd_wcr);
30211195Ssam #endif
30311195Ssam #ifdef HYLOG
30411195Ssam 	{
30511195Ssam 		struct {
30611207Ssam 			u_char	hcmd;
30711207Ssam 			u_char	hstate;
30811207Ssam 			short	hcount;
30911195Ssam 		} hcl;
31011195Ssam 
31111195Ssam 		hcl.hcmd = cmd;
31211195Ssam 		hcl.hstate = is->hy_state;
31311195Ssam 		hcl.hcount = count;
31411195Ssam 		hylog(HYL_CMD, sizeof(hcl), (char *)&hcl);
31511195Ssam 	}
31611195Ssam #endif
31711195Ssam 	is->hy_ntime = 0;
31811207Ssam }
31911195Ssam 
32011195Ssam int hyint_active = 0;		/* set during hy interrupt */
32111195Ssam /*
32211207Ssam  * Hyperchannel interface interrupt.
32311195Ssam  *
32411195Ssam  * An interrupt can occur for many reasons.  Examine the status of
32511195Ssam  * the hyperchannel status bits to determine what to do next.
32611195Ssam  *
32711195Ssam  * If input error just drop packet.
32811195Ssam  * Otherwise purge input buffered data path and examine
32911195Ssam  * packet to determine type.  Othewise decapsulate
33011195Ssam  * packet based on type and pass to type specific higher-level
33111195Ssam  * input routine.
33211195Ssam  */
33311195Ssam hyint(unit)
33411195Ssam 	int unit;
33511195Ssam {
33611195Ssam 	register struct hy_softc *is = &hy_softc[unit];
33711195Ssam 	register struct uba_device *ui = hyinfo[unit];
33811207Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
33911195Ssam 
34011207Ssam 	if (hyint_active)
34111195Ssam 		panic("RECURSIVE HYPERCHANNEL INTERRUPT");
34211195Ssam 	hyint_active++;
34311195Ssam #ifdef DEBUG
34411195Ssam 	printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
34511195Ssam 		unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
34611195Ssam #endif
34711195Ssam #ifdef HYLOG
34811195Ssam logit:
34911195Ssam 	{
35011195Ssam 		struct {
35111207Ssam 			u_char	hstate;
35211207Ssam 			u_char	hflags;
35311207Ssam 			short	hcsr;
35411207Ssam 			short	hwcr;
35511195Ssam 		} hil;
35611195Ssam 		hil.hstate = is->hy_state;
35711195Ssam 		hil.hflags = is->hy_flags;
35811195Ssam 		hil.hcsr = addr->hyd_csr;
35911195Ssam 		hil.hwcr = addr->hyd_wcr;
36011195Ssam 		hylog(HYL_INT, sizeof(hil), (char *)&hil);
36111195Ssam 	}
36211195Ssam #endif
36311207Ssam 	if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
36411195Ssam 		/*
36511207Ssam 		 * Error bit set, some sort of error in the interface.
36611195Ssam 		 *
36711207Ssam 		 * The adapter sets attn on command completion so that's not
36811207Ssam 		 * a real error even though the interface considers it one.
36911195Ssam 		 */
37011195Ssam #ifdef DEBUG
37111207Ssam 		if (hy_nodebug & 4)
37211207Ssam 			hy_debug_flag = 1;
37311195Ssam #endif
37411207Ssam 		printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n",
37511207Ssam 			addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
37611207Ssam 			addr->hyd_wcr);
37711207Ssam 		if (addr->hyd_csr & S_NEX) {
37811195Ssam 			printf("hy%d: NEX - Non Existant Memory\n", unit);
37911195Ssam #ifdef PI13
38011195Ssam 			addr->hyd_csr |= S_NEX;  /* as per PI13 manual */
38111195Ssam #else
38211195Ssam 			addr->hyd_csr &= ~S_NEX;
38311195Ssam #endif
38411195Ssam 			hycancel(ui);
38511195Ssam #ifdef PI13
38611207Ssam 		} else if (addr->hyd_csr & S_POWEROFF) {
38711207Ssam 			printf("hy%d: Power Off bit set, trying to reset\n",
38811207Ssam 				unit);
38911195Ssam 			addr->hyd_csr |= S_POWEROFF;
39011195Ssam 			DELAY(100);
39111207Ssam 			if (addr->hyd_csr & S_POWEROFF) {
39211195Ssam 				if_down(&is->hy_if);
39311195Ssam 				is->hy_state = STARTUP;
39411207Ssam 				printf(
39511207Ssam 				  "hy%d: Power Off Error, network shutdown\n",
39611207Ssam 				  unit);
39711195Ssam 			}
39811195Ssam #endif
39911195Ssam 		} else {
40011195Ssam 			printf("hy%d:  BAR overflow\n", unit);
40111195Ssam 			hycancel(ui);
40211195Ssam 		}
40311207Ssam 	} else if (HYS_NORMAL(addr)) {
40411195Ssam 		/*
40511207Ssam 		 * Normal interrupt, bump state machine unless in state
40611195Ssam 		 * waiting and no data present (assumed to be word count
40711207Ssam 		 * zero interrupt or other hardware botch).
40811195Ssam 		 */
40911207Ssam 		if (is->hy_state != WAITING || HYS_RECVDATA(addr))
41011195Ssam 			hyact(ui);
41111207Ssam 	} else if (HYS_ABNORMAL(addr)) {
41211195Ssam 		/*
41311207Ssam 		 * Abnormal termination.
41411195Ssam 		 * bump error counts, retry the last function
41511195Ssam 		 * 'MAXRETRY' times before kicking the bucket.
41611195Ssam 		 *
41711207Ssam 		 * Don't reissue the cmd if in certain states, abnormal
41811207Ssam 		 * on a reissued cmd or max retry exceeded.
41911195Ssam 		 */
42011195Ssam #ifdef HYLOG
42111195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
42211195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
42311195Ssam 			goto logit;
42411195Ssam 		}
42511195Ssam #endif
42611195Ssam #ifdef DEBUG
42711207Ssam 		if (hy_nodebug & 4)
42811207Ssam 			hy_debug_flag = 1;
42911195Ssam 		printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
43011195Ssam 			unit, hy_state_names[is->hy_state], is->hy_state);
43111207Ssam 		printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n",
43211207Ssam 			is->hy_flags, is->hy_ilen, is->hy_olen,
43311207Ssam 			is->hy_lastwcr, is->hy_retry);
43411207Ssam 		printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
43511207Ssam 			is->hy_savedstate, is->hy_savedcount,
43611207Ssam 			is->hy_savedaddr, is->hy_savedcmd);
43711195Ssam #endif
43811195Ssam #ifdef PI13
43911195Ssam 		addr->hyd_csr &= ~S_C;  /* clear the damned PI-13 */
44011195Ssam #endif
44111207Ssam 		if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT)
44211195Ssam 			is->hy_if.if_oerrors++;
44311207Ssam 		if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT)
44411195Ssam 			is->hy_if.if_ierrors++;
44511195Ssam 		if (is->hy_state == XMITDATASENT ||
44611195Ssam 		    is->hy_state == RECVSENT ||
44711195Ssam 		    is->hy_state == RECVDATASENT ||
44811207Ssam 		    (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY)
44911195Ssam 			hycancel(ui);
45011207Ssam 		else {
45111195Ssam #ifdef DEBUG
45211207Ssam 			if (hy_nodebug & 2)
45311207Ssam 				hy_debug_flag = 1;
45411195Ssam #endif
45511195Ssam 			is->hy_retry++;
45611195Ssam 			is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE;
45711195Ssam 			is->hy_state = IDLE;
45811195Ssam 			hyact(ui);
45911195Ssam 		}
46011195Ssam 	} else {
46111195Ssam 		/*
46211195Ssam 		 * Interrupt is neither normal, abnormal, or interface error.
46311195Ssam 		 * Ignore it. It's either stacked or a word count 0.
46411195Ssam 		 */
46511195Ssam #ifdef HYLOG
46611195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
46711195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
46811195Ssam 			goto logit;
46911195Ssam 		}
47011195Ssam #endif
47111195Ssam #ifdef DEBUG
47211195Ssam 		printD("hy%d: possible stacked interrupt ignored\n", unit);
47311195Ssam #endif
47411195Ssam 	}
47511195Ssam #ifdef DEBUG
47611195Ssam 	printD("hy%d: hyint exit\n\n", unit);
47711195Ssam #endif
47811195Ssam 	hyint_active = 0;
47911195Ssam 
48011207Ssam }
48111195Ssam 
48211195Ssam /*
48311195Ssam  * Encapsulate a packet of type family for the local net.
48411195Ssam  */
48511195Ssam hyoutput(ifp, m0, dst)
48611195Ssam 	struct ifnet *ifp;
48711195Ssam 	struct mbuf *m0;
48811195Ssam 	struct sockaddr *dst;
48911195Ssam {
49011195Ssam 	register struct hym_hdr *hym;
49111195Ssam 	register struct mbuf *m;
49211195Ssam #ifdef HYROUTE
49311195Ssam 	register struct hyroute *r = &hy_route[ifp->if_unit];
49411195Ssam #endif
49511195Ssam 	short dtype;		/* packet type */
49611195Ssam 	int dhost;		/* destination adapter address */
49711195Ssam 	int dlen;
49811195Ssam 	int mplen = 0;		/* message proper length */
49911195Ssam 	short loopback = 0;	/* hardware loopback requested */
50011195Ssam 	int error = 0;
50111195Ssam 	int s;
50211195Ssam 
50311195Ssam #ifdef DEBUG
50411207Ssam 	if (hy_nodebug & 8)
50511207Ssam 		hy_debug_flag = 1;
50611195Ssam #endif
50711195Ssam 	dlen = 0;
50811195Ssam 	for (m = m0; m; m = m->m_next)
50911195Ssam 		dlen += m->m_len;
51011195Ssam 	m = m0;
51111195Ssam 	switch(dst->sa_family) {
51211195Ssam 
51311195Ssam #ifdef INET
51411195Ssam 	case AF_INET: {
51511195Ssam 		register struct ip *ip = mtod(m, struct ip *);
51611195Ssam 		register struct sockaddr_in *sin = (struct sockaddr_in *)dst;
51711195Ssam 		register long hostaddr = in_lnaof(sin->sin_addr);
51811195Ssam 
51911195Ssam 		dhost = hostaddr & 0xffff;
52011195Ssam 		dtype = HYLINK_IP;
52111195Ssam #ifdef DEBUG
52211207Ssam 		printD("hy%d: output to host %x, dhost %x\n",
52311207Ssam 			ifp->if_unit, sin->sin_addr.s_addr, dhost);
52411195Ssam #endif
52511195Ssam 		/*
52611207Ssam 		 * Debugging loopback support:
52711195Ssam 		 * upper byte of 24 bit host number interpreted as follows
52811195Ssam 		 *	0x00 --> no loopback
52911195Ssam 		 *	0x01 --> hardware loop through remote adapter
53011195Ssam 		 *	other --> software loop through remote ip layer
53111195Ssam 		 */
53211195Ssam 		if (hostaddr & 0xff0000) {
53311195Ssam 			struct in_addr temp;
53411195Ssam 
53511195Ssam 			temp = ip->ip_dst;
53611195Ssam 			ip->ip_dst = ip->ip_src;
53711195Ssam 			ip->ip_src = temp;
53811195Ssam 			if ((hostaddr & 0xff0000) == 0x10000)
53911195Ssam 				loopback = H_LOOPBK;
54011195Ssam 		}
54111195Ssam 		/*
54211195Ssam 		 * If entire packet won't fit in message proper, just
54311195Ssam 		 * send hyperchannel hardware header and ip header in
54411195Ssam 		 * message proper.  If that won't fit either, just send
54511195Ssam 		 * the maximum message proper.
54611195Ssam 		 *
54711195Ssam 		 * This insures that the associated data is at least a
54811195Ssam 		 * TCP/UDP header in length and thus prevents potential
54911195Ssam 		 * problems with very short word counts.
55011195Ssam 		 */
55111195Ssam 		if (dlen > MPSIZE - sizeof (struct hy_hdr)) {
55211195Ssam 			mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2);
55311195Ssam 			if (mplen > MPSIZE)
55411195Ssam 				mplen = MPSIZE;
55511195Ssam 		}
55611195Ssam 		break;
55711195Ssam 	}
55811195Ssam #endif
55911195Ssam 
56011195Ssam 	default:
56111207Ssam 		printf("hy%d: can't handle af%d\n", ifp->if_unit,
56211207Ssam 			dst->sa_family);
56311195Ssam #ifdef DEBUG
56411207Ssam 		if (hy_nodebug & 4)
56511207Ssam 			hy_debug_flag = 1;
56611195Ssam #endif
56711195Ssam 		error = EAFNOSUPPORT;
56811195Ssam 		goto drop;
56911195Ssam 	}
57011195Ssam 
57111195Ssam 	/*
57211207Ssam 	 * Add the software and hardware hyperchannel headers.
57311195Ssam 	 * If there's not enough space in the first mbuf, allocate another.
57411195Ssam 	 * If that should fail, drop this sucker.
57511195Ssam 	 * No extra space for headers is allocated.
57611195Ssam 	 */
57711195Ssam 	if (m->m_off > MMAXOFF ||
57811195Ssam 	    MMINOFF + sizeof(struct hym_hdr) > m->m_off) {
57911207Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
58011195Ssam 		if (m == 0) {
58111195Ssam 			m = m0;
58211195Ssam 			error = ENOBUFS;
58311195Ssam 			goto drop;
58411195Ssam 		}
58511195Ssam 		m->m_next = m0;
58611195Ssam 		m->m_off = MMINOFF;
58711195Ssam 		m->m_len = sizeof(struct hym_hdr);
58811195Ssam 	} else {
58911195Ssam 		m->m_off -= sizeof(struct hym_hdr);
59011195Ssam 		m->m_len += sizeof(struct hym_hdr);
59111195Ssam 	}
59211195Ssam 	hym = mtod(m, struct hym_hdr *);
59311195Ssam 	hym->hym_mplen = mplen;
59411195Ssam 	hym->hym_hdr.hyh_type = dtype;
59511195Ssam 	hym->hym_hdr.hyh_off = 0;
59612772Ssam 	hym->hym_hdr.hyh_from = htons((u_short)ifp->if_host[0]);
59711195Ssam 	hym->hym_hdr.hyh_param = loopback;
59811195Ssam #ifdef HYROUTE
59911207Ssam 	if (r->hyr_lasttime.tv_sec != 0) {
60011195Ssam 		register struct hy_hash *rh;
60111195Ssam 		register int i;
60211195Ssam 
60311195Ssam 		i = HYRHASH(dhost);
60411195Ssam 		rh = &r->hyr_hash[i];
60511195Ssam 		i = 0;
60611195Ssam 		while (rh->hyr_key != dhost) {
60711195Ssam 			rh++; i++;
60811195Ssam 			if (rh > &r->hyr_hash[HYRSIZE])
60911195Ssam 				rh = &r->hyr_hash[0];
61011195Ssam 			if (rh->hyr_flags == 0 || i > HYRSIZE)
61111195Ssam 				goto notfound;
61211195Ssam 		}
61311195Ssam 		if (rh->hyr_flags & HYR_GATE) {
61411195Ssam 			loopback = 0;	/* no hardware loopback on gateways */
61511195Ssam 			i = rh->hyr_nextgate;
61611195Ssam 			if (i >= rh->hyr_egate)
61711195Ssam 				rh->hyr_nextgate = rh->hyr_pgate;
61811195Ssam 			else
61911195Ssam 				rh->hyr_nextgate++;
62011195Ssam 			rh = &r->hyr_hash[r->hyr_gateway[i]];
62111195Ssam 			if ((rh->hyr_flags & HYR_DIR) == 0)
62211195Ssam 				goto notfound;
62311195Ssam 		}
62411195Ssam 		hym->hym_hdr.hyh_ctl = rh->hyr_ctl;
62511195Ssam 		hym->hym_hdr.hyh_access = rh->hyr_access;
62611195Ssam 		hym->hym_hdr.hyh_to = rh->hyr_dst;
62711195Ssam 	} else {
62811195Ssam 		hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS;
62911195Ssam 		hym->hym_hdr.hyh_access = 0;
63012772Ssam 		hym->hym_hdr.hyh_to = htons((u_short)dhost);
63111195Ssam 	}
63211195Ssam #else
63311195Ssam 	hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS;
63411195Ssam 	hym->hym_hdr.hyh_access = 0;
63511195Ssam 	hym->hym_hdr.hyh_to = htons(dhost);
63611195Ssam #endif
63711195Ssam 
63811195Ssam 	if (hym->hym_mplen) {
63911195Ssam 		hym->hym_hdr.hyh_ctl |= H_ASSOC;
64011195Ssam #ifdef DEBUG
64111207Ssam 		if (hy_nodebug & 16)
64211207Ssam 			hy_debug_flag = 1;
64311195Ssam #endif
64411207Ssam 	} else
64511207Ssam 		hym->hym_hdr.hyh_ctl &= ~H_ASSOC;
64611195Ssam #ifdef DEBUG
64711207Ssam 	printD("hy%d: output mplen=%x ctl=%x access=%x to=%x",
64811195Ssam 		ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl,
64911207Ssam 		hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to);
65011207Ssam 	printD(" (adapter %x) from=%x param=%x type=%x off=%x\n",
65111195Ssam 		hym->hym_hdr.hyh_to_adapter,
65211195Ssam 		hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param,
65311195Ssam 		hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off);
65411195Ssam #endif
65511195Ssam 	s = splimp();
65611195Ssam 	if (IF_QFULL(&ifp->if_snd)) {
65711195Ssam 		IF_DROP(&ifp->if_snd);
65811195Ssam 		error = ENOBUFS;
65911195Ssam 		splx(s);
66011195Ssam 		goto drop;
66111195Ssam 	}
66211195Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
66311195Ssam 	if (hy_softc[ifp->if_unit].hy_state == WAITING)
66411195Ssam 		hyact(hyinfo[ifp->if_unit]);
66511195Ssam 	splx(s);
66611207Ssam 	return (0);
66711195Ssam notfound:
66811207Ssam 	error = ENETUNREACH;			/* XXX */
66911195Ssam drop:
67011195Ssam 	m_freem(m);
67111207Ssam 	return (error);
67211207Ssam }
67311195Ssam 
67411195Ssam hyact(ui)
67511195Ssam 	register struct uba_device *ui;
67611195Ssam {
67711195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
67811195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
67911195Ssam 
68011195Ssam actloop:
68111195Ssam #ifdef DEBUG
68211207Ssam 	printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
68311207Ssam 		hy_state_names[is->hy_state]);
68411195Ssam #endif
68511195Ssam 	switch (is->hy_state) {
68611195Ssam 
68711195Ssam 	case STARTUP:
68811195Ssam 		goto endintr;
68911195Ssam 
69011195Ssam 	case IDLE: {
69111195Ssam 		register rq = is->hy_flags;
69211195Ssam 
69311195Ssam 		if (rq & RQ_STATUS) {
69411195Ssam 			is->hy_flags &= ~RQ_STATUS;
69511195Ssam 			is->hy_state = STATSENT;
69611207Ssam 			hystart(ui, HYF_STATUS, sizeof (is->hy_status),
69713088Ssam 			    is->hy_ifuba.ifu_r.ifrw_info);
69811195Ssam 		} else if (rq & RQ_ENDOP) {
69911195Ssam 			is->hy_flags &= ~RQ_ENDOP;
70011195Ssam 			is->hy_state = ENDOPSENT;
70111195Ssam 			hystart(ui, HYF_END_OP, 0, 0);
70211195Ssam 		} else if (rq & RQ_STATISTICS) {
70311195Ssam 			is->hy_flags &= ~RQ_STATISTICS;
70411195Ssam 			is->hy_state = RSTATSENT;
70511207Ssam 			hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
70613088Ssam 			    is->hy_ifuba.ifu_r.ifrw_info);
70711207Ssam 		} else if (HYS_RECVDATA(addr)) {
70811195Ssam 			is->hy_state = RECVSENT;
70911195Ssam 			is->hy_retry = 0;
71011207Ssam 			hystart(ui, HYF_INPUTMSG, MPSIZE,
71113088Ssam 			    is->hy_ifuba.ifu_r.ifrw_info);
71211195Ssam 		} else if (rq & RQ_REISSUE) {
71311195Ssam 			is->hy_flags &= ~RQ_REISSUE;
71411195Ssam 			is->hy_state = is->hy_savedstate;
71511195Ssam #ifdef DEBUG
71611207Ssam 			printD("hy%d: reissue cmd=0x%x count=%d",
71711207Ssam 			  ui->ui_unit, is->hy_savedcmd, is->hy_savedcount);
71811207Ssam 			printD(" ubaddr=0x%x retry=%d\n",
71911207Ssam 			  is->hy_savedaddr, is->hy_retry);
72011195Ssam #endif
72111207Ssam 			hystart(ui, is->hy_savedcmd, is->hy_savedcount,
72213088Ssam 			    is->hy_savedaddr);
72311195Ssam 		} else {
72411195Ssam 			register struct mbuf *m;
72511195Ssam 
72611195Ssam 			IF_DEQUEUE(&is->hy_if.if_snd, m);
72711207Ssam 			if (m != NULL) {
72811195Ssam 				register struct hym_hdr *hym;
72911195Ssam 				register int mplen;
73011195Ssam 				register int cmd;
73111195Ssam 
73211195Ssam 				is->hy_state = XMITSENT;
73311195Ssam 				is->hy_retry = 0;
73411195Ssam 				hym = mtod(m, struct hym_hdr *);
73511195Ssam #ifdef HYLOG
73611207Ssam 				hylog(HYL_XMIT, sizeof(struct hym_hdr),
73713088Ssam 				    (char *)hym);
73811195Ssam #endif
73911195Ssam 				mplen = hym->hym_mplen;
74011207Ssam 				if (hym->hym_hdr.hyh_to_adapter ==
74113088Ssam 				    hym->hym_hdr.hyh_from_adapter)
74211207Ssam 					cmd = HYF_XMITLOCMSG;
74311207Ssam 				else
74411207Ssam 					cmd = HYF_XMITMSG;
74511195Ssam #ifdef DEBUG
74611195Ssam 				printD("hy%d: hym_hdr = ", ui->ui_unit);
74711207Ssam 				if (hy_debug_flag)
74811207Ssam 					hyprintdata((char *)hym,
74913088Ssam 					    sizeof (struct hym_hdr));
75011195Ssam #endif
75111195Ssam 				/*
75211207Ssam 				 * Strip off the software part of
75311195Ssam 				 * the hyperchannel header
75411195Ssam 				 */
75511195Ssam 				m->m_off += sizeof(struct hym_data);
75611195Ssam 				m->m_len -= sizeof(struct hym_data);
75711195Ssam 				is->hy_olen = if_wubaput(&is->hy_ifuba, m);
75811195Ssam 				if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
75911207Ssam 					UBAPURGE(is->hy_ifuba.ifu_uba,
76011207Ssam 						is->hy_ifuba.ifu_w.ifrw_bdp);
76111195Ssam #ifdef DEBUG
76211207Ssam 				printD(
76311207Ssam 		"hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
76411195Ssam 					ui->ui_unit, mplen, is->hy_olen);
76511207Ssam 				if (hy_debug_flag)
76611207Ssam 					hyprintdata(
76713088Ssam 					    is->hy_ifuba.ifu_w.ifrw_addr,
76813088Ssam 					    is->hy_olen);
76911195Ssam #endif
77011207Ssam 				hystart(ui, cmd,
77113088Ssam 				    (mplen == 0) ? is->hy_olen : mplen,
77213088Ssam 				    is->hy_ifuba.ifu_w.ifrw_info);
77311195Ssam 				if (mplen != 0)
77411195Ssam 					is->hy_flags |= RQ_XASSOC;
77511195Ssam 			} else if (rq & RQ_MARKDOWN) {
77611195Ssam 				is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
77711195Ssam 				is->hy_state = MARKPORT;
77811195Ssam 				is->hy_retry = 0;
77911195Ssam 				/*
78011207Ssam 				 * Port number is taken from status data
78111195Ssam 				 */
78211207Ssam 				hystart(ui,
78312772Ssam 				 (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)),
78412772Ssam 				 0, 0);
78511195Ssam 			} else if (rq & RQ_MARKUP) {
78611195Ssam 				register struct ifnet *ifp = &is->hy_if;
78711207Ssam 				register struct sockaddr_in *sin =
78811207Ssam 				   (struct sockaddr_in *)&ifp->if_addr;
78911195Ssam 
79011207Ssam 				is->hy_flags &= ~RQ_MARKUP;
79111195Ssam 				is->hy_retry = 0;
79211195Ssam 				/*
79313065Ssam 				 * Fill in the host number
79411207Ssam 				 * from the status buffer
79511195Ssam 				 */
79611207Ssam 				printf(
79711207Ssam 	"hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
79811195Ssam 					ui->ui_unit,
79911195Ssam 					is->hy_stat.hyc_uaddr,
80011195Ssam 					PORTNUM(&is->hy_status),
80111207Ssam 					(is->hy_stat.hyc_atype[0]<<8) |
80211207Ssam 						is->hy_stat.hyc_atype[1],
80311195Ssam 					is->hy_stat.hyc_atype[2]);
80411195Ssam 
80511207Ssam 				ifp->if_host[0] =
80611207Ssam 				  (is->hy_stat.hyc_uaddr << 8) |
80711207Ssam 					PORTNUM(&is->hy_status);
80811207Ssam 				sin->sin_addr =
80911207Ssam 				   if_makeaddr(ifp->if_net, ifp->if_host[0]);
81011195Ssam 				ifp->if_flags |= IFF_UP;
81111195Ssam 				if_rtinit(ifp, RTF_UP);
81211195Ssam #ifdef HYLOG
81311195Ssam 				hylog(HYL_UP, 0, (char *)0);
81411195Ssam #endif
81511195Ssam 			} else {
81611195Ssam 				is->hy_state = WAITING;
81711195Ssam 				is->hy_retry = 0;
81811195Ssam 				hystart(ui, HYF_WAITFORMSG, 0, 0);
81911195Ssam 			}
82011195Ssam 		}
82111207Ssam 		break;
82211195Ssam 	}
82311195Ssam 
82411195Ssam 	case STATSENT:
82512772Ssam 		bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status,
82611207Ssam 		  sizeof (struct hy_status));
82711195Ssam #ifdef DEBUG
82811207Ssam 		printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
82911207Ssam 			ui->ui_unit, is->hy_status.hys_gen_status,
83011207Ssam 			is->hy_status.hys_last_fcn,
83111207Ssam 			is->hy_status.hys_resp_trunk,
83211207Ssam 			is->hy_status.hys_status_trunk,
83311207Ssam 			is->hy_status.hys_recd_resp,
83411207Ssam 			is->hy_status.hys_error,
83511207Ssam 			is->hy_status.hys_caddr,
83611207Ssam 			is->hy_status.hys_pad);
83711195Ssam #endif
83811195Ssam 		is->hy_state = IDLE;
83911195Ssam #ifdef HYLOG
84011207Ssam 		hylog(HYL_STATUS, sizeof (struct hy_status),
84111207Ssam 			(char *)&is->hy_status);
84211195Ssam #endif
84311195Ssam #ifdef HYELOG
84411195Ssam 		{
84511195Ssam 			register int i;
84611195Ssam 
84711195Ssam 			i = is->hy_status.hys_error;
84811195Ssam 			if (i < HYE_MAX)
84911195Ssam 				i = HYE_MAX;
85011195Ssam 			switch (is->hy_status.hys_last_fcn) {
85111195Ssam 				case HYF_XMITLOCMSG:
85211195Ssam 					i += HYE_MAX+1;	/* fall through */
85311195Ssam 				case HYF_XMITLSTDATA:
85411195Ssam 					i += HYE_MAX+1;	/* fall through */
85511195Ssam 				case HYF_XMITMSG:
85611195Ssam 					i += HYE_MAX+1;
85711195Ssam 			}
85811195Ssam 			hy_elog[i]++;
85911195Ssam 		}
86011195Ssam #endif
86111195Ssam 		break;
86211195Ssam 
86311195Ssam 	case RSTATSENT: {
86411207Ssam 		register struct hy_stat *p =
86511207Ssam 			(struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
86611195Ssam 
86711195Ssam 		is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt);
86811195Ssam 		is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt);
86911195Ssam 		is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy);
87011195Ssam 		is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret);
87111195Ssam 		is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad);
87211195Ssam 		is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret);
87311195Ssam 		is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort);
87411195Ssam 		is->hy_stat.hyc_atype[0] = p->hyc_atype[0];
87511195Ssam 		is->hy_stat.hyc_atype[1] = p->hyc_atype[1];
87611195Ssam 		is->hy_stat.hyc_atype[2] = p->hyc_atype[2];
87711195Ssam 		is->hy_stat.hyc_uaddr = p->hyc_uaddr;
87811195Ssam #ifdef DEBUG
87911207Ssam 		printD(
88011207Ssam 	"hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n",
88111195Ssam 			ui->ui_unit,
88211195Ssam 			is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt,
88311195Ssam 			is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret,
88411195Ssam 			is->hy_stat.hyc_crcbad);
88511195Ssam 		printD("	mcret %d tdabort %d atype %x %x %x uaddr %x\n",
88611195Ssam 			is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort,
88711195Ssam 			is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
88811195Ssam 			is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
88911195Ssam #endif
89011195Ssam 		is->hy_state = IDLE;
89111195Ssam #ifdef HYLOG
89211207Ssam 		hylog(HYL_STATISTICS, sizeof (struct hy_stat),
89311207Ssam 			(char *)&is->hy_stat);
89411195Ssam #endif
89511195Ssam 		break;
89611195Ssam 	}
89711195Ssam 
89811195Ssam 	case CLEARSENT:
89911195Ssam 		is->hy_state = IDLE;
90011195Ssam 		break;
90111195Ssam 
90211195Ssam 	case ENDOPSENT:
90311195Ssam 		is->hy_state = IDLE;
90411195Ssam 		break;
90511195Ssam 
90611195Ssam 	case RECVSENT: {
90711207Ssam 		register struct hy_hdr *hyh;
90811207Ssam 		register unsigned len;
90911195Ssam 
91011207Ssam 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
91111207Ssam 			UBAPURGE(is->hy_ifuba.ifu_uba,
91213088Ssam 			    is->hy_ifuba.ifu_r.ifrw_bdp);
91311207Ssam 		hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
91411207Ssam 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
91511207Ssam 		if (len > MPSIZE) {
91611207Ssam 			printf("hy%d: RECVD MP > MPSIZE (%d)\n",
91713088Ssam 			    ui->ui_unit, len);
91811195Ssam #ifdef DEBUG
91911207Ssam 			hy_debug_flag = 1;
92011207Ssam 			printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
92111207Ssam 				ui->ui_unit, addr->hyd_csr, HY_CSR_BITS,
92211207Ssam 				addr->hyd_bar, addr->hyd_wcr);
92311195Ssam #endif
92411207Ssam 		}
92511195Ssam #ifdef DEBUG
92611207Ssam 		printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
92711207Ssam 		if (hy_debug_flag)
92811207Ssam 			hyprintdata((char *)hyh, len);
92911195Ssam #endif
93011207Ssam 		if (hyh->hyh_ctl & H_ASSOC) {
93111207Ssam 			is->hy_state = RECVDATASENT;
93211207Ssam 			is->hy_ilen = len;
93311207Ssam 			is->hy_retry = 0;
93411207Ssam 			hystart(ui, HYF_INPUTDATA,
93513088Ssam 			    (int)(HYMTU-len+sizeof (struct hy_hdr)),
93613088Ssam 			    (int)(is->hy_ifuba.ifu_r.ifrw_info + len));
93711207Ssam 		} else {
93812772Ssam 			hyrecvdata(ui, hyh, (int)len);
93911207Ssam 			is->hy_state = IDLE;
94011195Ssam 		}
94111207Ssam 		break;
94211207Ssam 	}
94311195Ssam 
94411195Ssam 	case RECVDATASENT: {
94511207Ssam 		register struct hy_hdr *hyh;
94611207Ssam 		register unsigned len;
94711195Ssam 
94811207Ssam 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
94911207Ssam 			UBAPURGE(is->hy_ifuba.ifu_uba,
95013088Ssam 			    is->hy_ifuba.ifu_r.ifrw_bdp);
95111207Ssam 		hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
95211207Ssam 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
95311195Ssam #ifdef DEBUG
95411207Ssam 		printD("hy%d: recvd assoc data, len = %d, data = ",
95511207Ssam 			ui->ui_unit, len);
95611207Ssam 		if (hy_debug_flag)
95711207Ssam 			hyprintdata((char *)hyh + is->hy_ilen, len);
95811195Ssam #endif
95912772Ssam 		hyrecvdata(ui, hyh, (int)(len + is->hy_ilen));
96011207Ssam 		is->hy_state = IDLE;
96111207Ssam 		break;
96211207Ssam 	}
96311195Ssam 
96411195Ssam 	case XMITSENT:
96511207Ssam 		if (is->hy_flags & RQ_XASSOC) {
966*13196Sroot 			register int len;
96711195Ssam 
96811207Ssam 			is->hy_flags &= ~RQ_XASSOC;
96911207Ssam 			is->hy_state = XMITDATASENT;
97011207Ssam 			is->hy_retry = 0;
97111207Ssam 			len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
97211207Ssam 			if (len > is->hy_olen) {
97311207Ssam 				printf(
97411207Ssam 				"hy%d: xmit error - len > hy_olen [%d > %d]\n",
97511207Ssam 				ui->ui_unit, len, is->hy_olen);
97611195Ssam #ifdef DEBUG
97711207Ssam 				hy_debug_flag = 1;
97811195Ssam #endif
97911195Ssam 			}
98011207Ssam 			hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
98113088Ssam 			    is->hy_ifuba.ifu_w.ifrw_info + len);
98211207Ssam 			break;
98311207Ssam 		}
98411207Ssam 		/* fall through to ... */
98511195Ssam 
98611195Ssam 	case XMITDATASENT:
98711207Ssam 		hyxmitdata(ui);
98811207Ssam 		is->hy_state = IDLE;
98911207Ssam 		break;
99011195Ssam 
99111195Ssam 	case WAITING:	/* wait for message complete or output requested */
99211207Ssam 		if (HYS_RECVDATA(addr))
99311195Ssam 			is->hy_state = IDLE;
99411195Ssam 		else {
99511195Ssam 			is->hy_state = CLEARSENT;
99611195Ssam 			is->hy_retry = 0;
99711195Ssam 			hystart(ui, HYF_CLRWFMSG, 0, 0);
99811195Ssam 		}
99911195Ssam 		break;
100011195Ssam 
100111195Ssam 	case MARKPORT:
100211195Ssam 		is->hy_state = STARTUP;
100311195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
100411195Ssam 		goto endintr;
100511195Ssam 
100611195Ssam 	default:
100711207Ssam 		printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
100811207Ssam 			ui->ui_unit, is->hy_state);
100911195Ssam 		panic("HYPERCHANNEL IN INVALID STATE");
101011195Ssam 		/*NOTREACHED*/
101111207Ssam 	}
101211195Ssam 	if (is->hy_state == IDLE)
101311195Ssam 		goto actloop;
101411195Ssam endintr:
101513088Ssam 	;
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 /*
102313088Ssam  * Called from device interrupt when receiving data.
102411195Ssam  * Examine packet to determine type.  Decapsulate packet
102511195Ssam  * based on type and pass to type specific higher-level
102611195Ssam  * input routine.
102711195Ssam  */
102813088Ssam hyrecvdata(ui, hyh, len)
102911195Ssam 	struct uba_device *ui;
103013088Ssam 	register struct hy_hdr *hyh;
103111195Ssam 	int len;
103211195Ssam {
103311195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
103411195Ssam     	struct mbuf *m;
103511195Ssam 	register struct ifqueue *inq;
103611195Ssam 
103711195Ssam 	is->hy_if.if_ipackets++;
103811195Ssam #ifdef DEBUG
103911207Ssam 	printD("hy%d: recieved packet, len = %d (actual %d)\n",
104011207Ssam 		ui->ui_unit, len,
104111207Ssam 		len - (hyh->hyh_off + sizeof (struct hy_hdr)));
104211195Ssam #endif
104311195Ssam #ifdef HYLOG
104411195Ssam 	{
104511195Ssam 		struct {
104611195Ssam 			short hlen;
104711195Ssam 			struct hy_hdr hhdr;
104811195Ssam 		} hh;
104911195Ssam 		hh.hlen = len;
105011195Ssam 		hh.hhdr = *hyh;
105111195Ssam 		hylog(HYL_RECV, sizeof(hh), (char *)&hh);
105211195Ssam 	}
105311195Ssam #endif
105411195Ssam 	if (len > HYMTU + MPSIZE || len == 0)
105511195Ssam 		return;			/* sanity */
105611195Ssam 	/*
105711195Ssam 	 * Pull packet off interface.
105811195Ssam 	 */
105911195Ssam 	m = if_rubaget(&is->hy_ifuba, len, 0);
106011207Ssam 	if (m == NULL)
106111195Ssam 		return;
106211195Ssam 	switch (hyh->hyh_type) {
106311195Ssam 
106411195Ssam #ifdef INET
106511195Ssam 	case HYLINK_IP:
106611195Ssam 		/*
106711207Ssam 		 * Strip the variable portion of the hyperchannel header
106811207Ssam 		 * (fixed portion stripped in if_rubaget).
106911195Ssam 		 */
107011195Ssam 		m->m_len -= hyh->hyh_off;
107111195Ssam 		m->m_off += hyh->hyh_off;
107211195Ssam 		schednetisr(NETISR_IP);
107311195Ssam 		inq = &ipintrq;
107411195Ssam 		break;
107511195Ssam #endif
107611195Ssam 	default:
107711195Ssam 		m_freem(m);
107811195Ssam 		return;
107911195Ssam 	}
108011195Ssam 	if (IF_QFULL(inq)) {
108111195Ssam 		IF_DROP(inq);
108211195Ssam 		m_freem(m);
108311195Ssam 	} else
108411195Ssam 		IF_ENQUEUE(inq, m);
108511207Ssam }
108611195Ssam 
108711195Ssam /*
108811207Ssam  * Transmit done, release resources, bump counters.
108911195Ssam  */
109011195Ssam hyxmitdata(ui)
109111195Ssam 	struct uba_device *ui;
109211195Ssam {
109311195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
109411195Ssam 
109511195Ssam 	is->hy_if.if_opackets++;
109611207Ssam 	if (is->hy_ifuba.ifu_xtofree) {
109711195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
109811195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
109911195Ssam 	}
110011207Ssam }
110111195Ssam 
110211195Ssam hycancel(ui)
110311195Ssam 	register struct uba_device *ui;
110411195Ssam {
110511195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
110611195Ssam 
110711207Ssam 	if (is->hy_ifuba.ifu_xtofree) {
110811195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
110911195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
111011195Ssam 	}
111111195Ssam #ifdef DEBUG
111211207Ssam 	if (hy_nodebug & 1)
111311207Ssam 		hy_debug_flag = 1;
111411195Ssam #endif
111511195Ssam #ifdef DEBUG
111611195Ssam 	printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
111711195Ssam 		ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
111811195Ssam 		is->hy_savedcount, is->hy_savedaddr);
111911207Ssam 	printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n",
112011207Ssam 		is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr,
112111207Ssam 		is->hy_retry);
112211207Ssam 	printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
112311207Ssam 		is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr,
112411207Ssam 		is->hy_savedcmd);
112511195Ssam #endif
112611195Ssam 	is->hy_state = IDLE;
112711195Ssam 	is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
112811195Ssam 	hyact(ui);
112911207Ssam }
113011195Ssam 
113111195Ssam #ifdef DEBUG
113211195Ssam hyprintdata(cp, len)
113311195Ssam 	register char *cp;
113411195Ssam 	register int len;
113511195Ssam {
113611195Ssam 	register int count = 16;
113711195Ssam 	register char *fmt;
113811195Ssam 	static char regfmt[] = "\n\t %x";
113911195Ssam 
114011195Ssam 	fmt = &regfmt[2];
114111195Ssam 	while (--len >= 0) {
114211195Ssam 		printL(fmt, *cp++ & 0xff);
114311195Ssam 		fmt = &regfmt[2];
114411195Ssam 		if (--count <= 0) {
114511195Ssam 			fmt = &regfmt[0];
114611195Ssam 			count = 16;
114711195Ssam 		}
114811195Ssam 	}
114911195Ssam 	printL("\n");
115011195Ssam }
115111195Ssam #endif
115211195Ssam 
115311195Ssam hywatch(unit)
115413088Ssam 	int unit;
115511195Ssam {
115611195Ssam 	register struct hy_softc *is = &hy_softc[unit];
115711195Ssam 	register struct uba_device *ui = hyinfo[unit];
115811195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
115911195Ssam 	int s;
116011195Ssam 
116111195Ssam 	s = splimp();
116211195Ssam 	is->hy_if.if_timer = SCANINTERVAL;
116311207Ssam 	if (is->hy_ntime > 2 && is->hy_state != WAITING &&
116411207Ssam 	  is->hy_state != STARTUP && is->hy_state != IDLE) {
116511195Ssam 		printf("hy%d: watchdog timer expired\n", unit);
116611195Ssam 		hycancel(ui);
116711195Ssam 	}
116811195Ssam #ifdef PI13
116911195Ssam 	if ((addr->hyd_csr & S_POWEROFF) != 0) {
117011195Ssam 		addr->hyd_csr |= S_POWEROFF;
117111195Ssam 		DELAY(100);
117211195Ssam 		if ((addr->hyd_csr & S_POWEROFF) == 0) {
117311195Ssam 			printf("hy%d: adapter power restored\n", unit);
117411195Ssam 			is->hy_state = IDLE;
117511207Ssam 			is->hy_flags |=
117611207Ssam 			  (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
117711195Ssam 			hyact(ui);
117811195Ssam 		}
117911195Ssam 	}
118011195Ssam #endif
118111195Ssam 	splx(s);
118211195Ssam }
118311195Ssam 
118411195Ssam #ifdef HYLOG
118511195Ssam hylog(code, len, ptr)
118613088Ssam 	int code, len;
118711195Ssam 	char *ptr;
118811195Ssam {
118911195Ssam 	register unsigned char *p;
119011195Ssam 	int s;
119111195Ssam 
119211195Ssam 	s = splimp();
119311195Ssam 	if (hy_log.hyl_self != &hy_log) {
119411195Ssam 		hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
119511195Ssam 		hy_log.hyl_ptr = &hy_log.hyl_buf[0];
119611195Ssam 		hy_log.hyl_self = &hy_log;
119711195Ssam 		hy_log.hyl_enable = HYL_DISABLED;
119811195Ssam 		hy_log.hyl_onerr = HYL_CATCH1;
119911195Ssam 	}
120011207Ssam 	if (hy_log.hyl_enable == HYL_DISABLED ||
120111207Ssam 	  hy_log.hyl_enable == HYL_CAUGHT1 ||
120211207Ssam 	  hy_log.hyl_enable == HYL_CAUGHTSTATUS ||
120311207Ssam 	  (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS))
120411207Ssam 		goto out;
120511195Ssam 	p = hy_log.hyl_ptr;
120611195Ssam 	if (p + len + 2 >= hy_log.hyl_eptr) {
120712772Ssam 		bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p));
120811195Ssam 		p = &hy_log.hyl_buf[0];
120911195Ssam 		if (hy_log.hyl_enable == HYL_CATCH1) {
121011195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1;
121111195Ssam 			goto out;
121211195Ssam 		}
121311195Ssam 		if (hy_log.hyl_enable == HYL_CATCHSTATUS) {
121411195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS;
121511195Ssam 			goto out;
121611195Ssam 		}
121711195Ssam 	}
121811195Ssam 	*p++ = code;
121911195Ssam 	*p++ = len;
122013088Ssam 	bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len);
122111195Ssam 	hy_log.hyl_ptr = p + len;
122211195Ssam out:
122311195Ssam 	splx(s);
122411195Ssam }
122511195Ssam #endif
122611195Ssam 
122712772Ssam /*ARGSUSED*/
122813058Ssam hyioctl(ifp, cmd, data)
122913058Ssam 	register struct ifnet *ifp;
123011207Ssam 	int cmd;
123111207Ssam 	caddr_t	data;
123211195Ssam {
123313065Ssam 	struct sockaddr_in *sin;
123413088Ssam 	struct ifreq *ifr = (struct ifreq *)data;
123511207Ssam 	int s = splimp(), error = 0;
123611195Ssam 
123711195Ssam 	switch(cmd) {
123811195Ssam 
123913065Ssam 	case SIOCSIFADDR:
124013065Ssam 		if (ifp->if_flags & IFF_RUNNING)
124113065Ssam 			if_rtinit(ifp, -1);
124213065Ssam 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
124313065Ssam 		ifp->if_net = in_netof(sin->sin_addr);
124413065Ssam 		sin = (struct sockaddr_in *)&ifp->if_addr;
124513065Ssam 		sin->sin_family = AF_INET;
124613065Ssam 		sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
124713065Ssam 		if (ifp->if_flags & IFF_RUNNING)
124813065Ssam 			if_rtinit(ifp, RTF_UP);
124913065Ssam 		else
125013065Ssam 			hyinit(ifp->if_unit);
125113065Ssam 		break;
125213065Ssam 
125311195Ssam 	case HYSETROUTE:
125411207Ssam 		if (!suser()) {
125511207Ssam 			error = EPERM;
125611207Ssam 			goto bad;
125711195Ssam 		}
125813058Ssam 		hy_route[ifp->if_unit] = *(struct hyroute *)ifr->ifr_data;
125913058Ssam 		hy_route[ifp->if_unit].hyr_lasttime = time;
126011195Ssam 		break;
126111195Ssam 
126211195Ssam 	case HYGETROUTE:
126313058Ssam 		*(struct hyroute *)ifr->ifr_data = hy_route[ifp->if_unit];
126411195Ssam 		break;
126511195Ssam 
126611195Ssam 	default:
126713058Ssam 		error = EINVAL;
126811195Ssam 		break;
126911195Ssam 	}
127011207Ssam bad:
127111195Ssam 	splx(s);
127211207Ssam 	return (error);
127311195Ssam }
127411207Ssam #endif
1275