xref: /csrg-svn/sys/vax/if/if_hy.c (revision 11198)
1*11198Ssam /*	if_hy.c	4.2	83/02/21	*/
211195Ssam 
311195Ssam #include "hy.h"
411195Ssam #if NHY > 0
511195Ssam 
611195Ssam /*
711195Ssam  * Network Systems Copropration Hyperchanel interface
811195Ssam  *
911195Ssam  * MUST BE UPDATED FOR 4.1C
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/cpu.h"
2011195Ssam #include "../h/vmmac.h"
2111195Ssam #include "../h/dir.h"
2211195Ssam #include "../h/user.h"
2311195Ssam #include "../h/errno.h"
2411195Ssam 
2511195Ssam #include "../net/if.h"
2611195Ssam #include "../net/route.h"
2711195Ssam 
2811195Ssam #include "../netinet/in.h"
2911195Ssam #include "../netinet/in_systm.h"
3011195Ssam #include "../netinet/ip.h"
3111195Ssam #include "../netinet/ip_var.h"
3211195Ssam 
3311195Ssam #include "../vaxif/if_hy.h"
34*11198Ssam #include "../vaxif/if_hyreg.h"
3511195Ssam #include "../vaxif/if_uba.h"
3611195Ssam 
3711195Ssam #include "../vax/mtpr.h"
3811195Ssam #include "../vaxuba/ubareg.h"
3911195Ssam #include "../vaxuba/ubavar.h"
4011195Ssam 
4111195Ssam #define HYROUTE
4211195Ssam #define HYELOG
4311195Ssam #define	HYMTU	576
4411195Ssam 
4511195Ssam int	hyprobe(), hyattach(), hyinit(), 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 */
6611195Ssam 	short	hy_flags;		/* flags                        */
6711195Ssam 	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 */
7711195Ssam 	struct hy_stat	hy_stat;	/* statistics */
7811195Ssam 	struct hy_status hy_status;	/* status */
7911195Ssam } hy_softc[NHY];
8011195Ssam 
8111195Ssam #ifdef HYELOG
8211195Ssam #define HYE_MAX	0x18	/* max error code is 0x17, 0x18 bin gets out of range */
8311195Ssam 
8411195Ssam unsigned long	hy_elog[(HYE_MAX+1)*4];
8511195Ssam #endif
8611195Ssam 
8711195Ssam 
8811195Ssam #ifdef DEBUG
8911195Ssam #define printL	lprintf
9011195Ssam #define printD	if (hy_debug_flag) lprintf
9111195Ssam int	hy_debug_flag = 0;
9211195Ssam /*
9311195Ssam  * hy_nodebug bit 0x01	set hy_debug_flag on hycancel
9411195Ssam  * hy_nodebug bit 0x02	set hy_debug_flag on command reissue
9511195Ssam  * hy_nodebug bit 0x04	set hy_debug_flag on abnormal interrupt
9611195Ssam  * hy_nodebug bit 0x08	set hy_debug_flag on hyouput
9711195Ssam  * hy_nodebug bit 0x10	set hy_debug_flag on hyouput with associated data
9811195Ssam  */
9911195Ssam int	hy_nodebug = 0x0;
10011195Ssam #else
10111195Ssam #define printD	hyvoid
10211195Ssam #endif
10311195Ssam 
10411195Ssam /*
10511195Ssam  * requests for service (in order by descending priority)
10611195Ssam  */
10711195Ssam 
10811195Ssam #define RQ_ENDOP	001	/* end the last adapter function */
10911195Ssam #define RQ_REISSUE	002	/* reissue previous cmd after status */
11011195Ssam #define RQ_STATUS	004	/* get the status of the adapter */
11111195Ssam #define RQ_STATISTICS	010	/* get the statistics of the adapter */
11211195Ssam #define RQ_MARKDOWN	020	/* mark this adapter port down */
11311195Ssam #define RQ_MARKUP	040	/* mark this interface up */
11411195Ssam 
11511195Ssam /*
11611195Ssam  *  more flags
11711195Ssam  */
11811195Ssam 
11911195Ssam #define RQ_XASSOC	0100	/* associated data to transmit */
12011195Ssam 
12111195Ssam /*
12211195Ssam  * driver states
12311195Ssam  */
12411195Ssam 
12511195Ssam #define	STARTUP		0	/* initial state (before fully there) */
12611195Ssam #define	IDLE		1	/* idle state */
12711195Ssam #define	STATSENT	2	/* status cmd sent to adapter */
12811195Ssam #define	ENDOPSENT	3	/* end operation cmd sent */
12911195Ssam #define	RECVSENT	4	/* input message cmd sent */
13011195Ssam #define	RECVDATASENT	5	/* input data cmd sent */
13111195Ssam #define	XMITSENT	6	/* transmit message cmd sent */
13211195Ssam #define	XMITDATASENT	7	/* transmit data cmd sent */
13311195Ssam #define	WAITING		8	/* waiting for messages */
13411195Ssam #define	CLEARSENT	9	/* clear wait for message cmd sent */
13511195Ssam #define MARKPORT	10	/* mark this host's adapter port down issued */
13611195Ssam #define RSTATSENT	11	/* read statistics cmd sent to adapter */
13711195Ssam 
13811195Ssam #ifdef DEBUG
13911195Ssam char *hy_state_names[] = {
14011195Ssam 	"Startup",
14111195Ssam 	"Idle",
14211195Ssam 	"Status Sent",
14311195Ssam 	"End op Sent",
14411195Ssam 	"Recieve Message Proper Sent",
14511195Ssam 	"Recieve Data Sent",
14611195Ssam 	"Transmit Message Proper Sent",
14711195Ssam 	"Transmit Data Sent",
14811195Ssam 	"Wait for Message Sent",
14911195Ssam 	"Clear Wait for Message Sent",
15011195Ssam 	"Mark Port Down Sent",
15111195Ssam 	"Read Statistics Sent"
15211195Ssam };
15311195Ssam #endif
15411195Ssam 
15511195Ssam #define SCANINTERVAL	10	/* seconds */
15611195Ssam #define MAXINTERVAL	20	/* seconds (max action) */
15711195Ssam 
15811195Ssam /*
15911195Ssam  * Cause a device interrupt.  This code uses a buffer starting at
16011195Ssam  * location zero on the unibus (which is already mapped by the
16111195Ssam  * autoconfigure code in the kernel).
16211195Ssam  */
16311195Ssam hyprobe(reg)
16411195Ssam 	caddr_t reg;
16511195Ssam {
16611195Ssam 	register int br, cvec;		/* r11, r10 value-result */
16711195Ssam 	register struct hydevice *addr = (struct hydevice *) reg;
16811195Ssam 
16911195Ssam #ifdef lint
17011195Ssam 	br = 0; cvec = br; br = cvec;
17111195Ssam 	hyint(0);
17211195Ssam #endif
17311195Ssam 	/*
17411195Ssam 	 * request adapter status to a buffer starting at unibus location 0
17511195Ssam 	 */
17611195Ssam 	addr->hyd_bar = 0;
17711195Ssam 	addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1);
17811195Ssam 	addr->hyd_dbuf = HYF_STATUS;
17911195Ssam #ifdef PI13
18011195Ssam 	addr->hyd_csr |= S_GO | S_IE | S_IATTN;
18111195Ssam #else
18211195Ssam 	addr->hyd_csr |= S_GO | S_IE;
18311195Ssam #endif
18411195Ssam 	DELAY(10000);
18511195Ssam #ifdef PI13
18611195Ssam 	addr->hyd_csr |= S_CLRINT;	/* clear any stacked interrupts */
18711195Ssam #endif
18811195Ssam 	addr->hyd_csr &= ~(S_IE | S_CLRINT);	/* disable further interrupts */
18911195Ssam 	return(1);
19011195Ssam } /* hyprobe */
19111195Ssam 
19211195Ssam /*
19311195Ssam  * Interface exists: make available by filling in network interface
19411195Ssam  * record.  System will initialize the interface when it is ready
19511195Ssam  * to accept packets.
19611195Ssam  */
19711195Ssam hyattach(ui)
19811195Ssam 	struct uba_device *ui;
19911195Ssam {
20011195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
20111195Ssam 	register struct ifnet *ifp = &is->hy_if;
20211195Ssam 
20311195Ssam 	ifp->if_unit = ui->ui_unit;
20411195Ssam 	ifp->if_name = "hy";
20511195Ssam 	ifp->if_mtu = HYMTU;
20611195Ssam 	ifp->if_net = ui->ui_flags;
20711195Ssam 
20811195Ssam 	is->hy_state = STARTUP;		/* don't allow state transitions yet */
20911195Ssam 
21011195Ssam 	ifp->if_init = hyinit;
21111195Ssam 	ifp->if_output = hyoutput;
21211195Ssam 	ifp->if_ubareset = hyreset;
21311195Ssam 	ifp->if_watchdog = hywatch;
21411195Ssam 	ifp->if_timer = SCANINTERVAL;
21511195Ssam 	is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
21611195Ssam #ifdef SUPBDP
21711195Ssam 	is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
21811195Ssam #endif
21911195Ssam 	if_attach(ifp);
22011195Ssam } /* hyattach */
22111195Ssam 
22211195Ssam /*
22311195Ssam  * Reset of interface after UNIBUS reset.
22411195Ssam  * If interface is on specified uba, reset its state.
22511195Ssam  */
22611195Ssam hyreset(unit, uban)
22711195Ssam 	int unit, uban;
22811195Ssam {
22911195Ssam 	register struct uba_device *ui = hyinfo[unit];
23011195Ssam 	register struct hy_softc *is;
23111195Ssam 
23211195Ssam 	if (unit >= NHY || ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
23311195Ssam 		return;
23411195Ssam 
23511195Ssam 	printf(" hy%d", unit);
23611195Ssam 	hyinit(unit);
23711195Ssam } /* hyreset */
23811195Ssam 
23911195Ssam /*
24011195Ssam  * Initialization of interface; clear recorded pending
24111195Ssam  * operations, and reinitialize UNIBUS usage.
24211195Ssam  */
24311195Ssam hyinit(unit)
24411195Ssam 	int unit;
24511195Ssam {
24611195Ssam 	register struct hy_softc *is = &hy_softc[unit];
24711195Ssam 	register struct uba_device *ui = hyinfo[unit];
24811195Ssam 	int s;
24911195Ssam 
25011195Ssam 	if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
25111195Ssam 	    sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) {
25211195Ssam #ifdef DEBUG
25311195Ssam 		if (hy_nodebug & 4) hy_debug_flag = 1;
25411195Ssam #endif
25511195Ssam 		printf("hy%d: can't initialize\n", unit);
25611195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
25711195Ssam 		return;
25811195Ssam 	}
25911195Ssam 
26011195Ssam 	/*
26111195Ssam 	 * issue wait for message and start the state machine
26211195Ssam 	 */
26311195Ssam 	s = splimp();
26411195Ssam 	is->hy_state = IDLE;
26511195Ssam 	is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
26611195Ssam 	is->hy_retry = 0;
26711195Ssam 	hyact(ui);
26811195Ssam 	splx(s);
26911195Ssam } /* hyinit */
27011195Ssam 
27111195Ssam 
27211195Ssam /*
27311195Ssam  * issue a command to the adapter
27411195Ssam  */
27511195Ssam hystart(ui, cmd, count, ubaddr)
27611195Ssam 	struct uba_device *ui;
27711195Ssam 	int cmd;
27811195Ssam 	int count;
27911195Ssam 	int ubaddr;
28011195Ssam {
28111195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
28211195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
28311195Ssam 
28411195Ssam #ifdef DEBUG
28511195Ssam 	printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", ui->ui_unit, cmd, count, ubaddr);
28611195Ssam 	printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
28711195Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
28811195Ssam #endif
28911195Ssam 
29011195Ssam 	if (((is->hy_flags & RQ_REISSUE) == 0) && (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
29111195Ssam 		is->hy_savedstate = is->hy_state;
29211195Ssam 		is->hy_savedcmd = cmd;
29311195Ssam 		is->hy_savedcount = count;
29411195Ssam 		is->hy_savedaddr = ubaddr;
29511195Ssam 	}
29611195Ssam 
29711195Ssam 	addr->hyd_bar = ubaddr & 0xffff;
29811195Ssam 	addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);	/* was byte count */
29911195Ssam 	addr->hyd_dbuf = cmd;
30011195Ssam #ifdef PI13
30111195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN;
30211195Ssam #else
30311195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE;
30411195Ssam #endif
30511195Ssam #ifdef DEBUG
30611195Ssam 	printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
30711195Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
30811195Ssam #endif
30911195Ssam #ifdef HYLOG
31011195Ssam 	{
31111195Ssam 		struct {
31211195Ssam 			unsigned char hcmd;
31311195Ssam 			unsigned char hstate;
31411195Ssam 			short hcount;
31511195Ssam 		} hcl;
31611195Ssam 
31711195Ssam 		hcl.hcmd = cmd;
31811195Ssam 		hcl.hstate = is->hy_state;
31911195Ssam 		hcl.hcount = count;
32011195Ssam 		hylog(HYL_CMD, sizeof(hcl), (char *)&hcl);
32111195Ssam 	}
32211195Ssam #endif
32311195Ssam 	is->hy_ntime = 0;
32411195Ssam } /* hystart */
32511195Ssam 
32611195Ssam int hyint_active = 0;		/* set during hy interrupt */
32711195Ssam 
32811195Ssam /*
32911195Ssam  * hyperchannel interface interrupt.
33011195Ssam  *
33111195Ssam  * An interrupt can occur for many reasons.  Examine the status of
33211195Ssam  * the hyperchannel status bits to determine what to do next.
33311195Ssam  *
33411195Ssam  * If input error just drop packet.
33511195Ssam  * Otherwise purge input buffered data path and examine
33611195Ssam  * packet to determine type.  Othewise decapsulate
33711195Ssam  * packet based on type and pass to type specific higher-level
33811195Ssam  * input routine.
33911195Ssam  */
34011195Ssam hyint(unit)
34111195Ssam 	int unit;
34211195Ssam {
34311195Ssam 	register struct hy_softc *is = &hy_softc[unit];
34411195Ssam 	register struct uba_device *ui = hyinfo[unit];
34511195Ssam 	register struct hydevice *addr =
34611195Ssam 		(struct hydevice *)ui->ui_addr;
34711195Ssam 
34811195Ssam 	if (hyint_active) {
34911195Ssam 		panic("RECURSIVE HYPERCHANNEL INTERRUPT");
35011195Ssam 	}
35111195Ssam 
35211195Ssam 	hyint_active++;
35311195Ssam 
35411195Ssam #ifdef DEBUG
35511195Ssam 	printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
35611195Ssam 		unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
35711195Ssam #endif
35811195Ssam #ifdef HYLOG
35911195Ssam logit:
36011195Ssam 	{
36111195Ssam 		struct {
36211195Ssam 			unsigned char hstate;
36311195Ssam 			unsigned char hflags;
36411195Ssam 			short hcsr;
36511195Ssam 			short hwcr;
36611195Ssam 		} hil;
36711195Ssam 		hil.hstate = is->hy_state;
36811195Ssam 		hil.hflags = is->hy_flags;
36911195Ssam 		hil.hcsr = addr->hyd_csr;
37011195Ssam 		hil.hwcr = addr->hyd_wcr;
37111195Ssam 		hylog(HYL_INT, sizeof(hil), (char *)&hil);
37211195Ssam 	}
37311195Ssam #endif
37411195Ssam 
37511195Ssam 	if (ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
37611195Ssam 		/*
37711195Ssam 		 * error bit set, some sort of error in the interface
37811195Ssam 		 *
37911195Ssam 		 * the adapter sets attn on command completion so that's not
38011195Ssam 		 * a real error even though the interface considers it one
38111195Ssam 		 */
38211195Ssam #ifdef DEBUG
38311195Ssam 		if (hy_nodebug & 4) hy_debug_flag = 1;
38411195Ssam #endif
38511195Ssam 		printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
38611195Ssam 
38711195Ssam 		if ((addr->hyd_csr & S_NEX) != 0) {
38811195Ssam 			printf("hy%d: NEX - Non Existant Memory\n", unit);
38911195Ssam #ifdef PI13
39011195Ssam 			addr->hyd_csr |= S_NEX;  /* as per PI13 manual */
39111195Ssam #else
39211195Ssam 			addr->hyd_csr &= ~S_NEX;
39311195Ssam #endif
39411195Ssam 			hycancel(ui);
39511195Ssam #ifdef PI13
39611195Ssam 		} else if ((addr->hyd_csr & S_POWEROFF) != 0) {
39711195Ssam 			printf("hy%d: Power Off bit set, trying to reset\n", unit);
39811195Ssam 			addr->hyd_csr |= S_POWEROFF;
39911195Ssam 			DELAY(100);
40011195Ssam 			if ((addr->hyd_csr & S_POWEROFF) != 0) {
40111195Ssam 				if_down(&is->hy_if);
40211195Ssam 				is->hy_state = STARTUP;
40311195Ssam 				printf("hy%d: Power Off Error, network shutdown\n", unit);
40411195Ssam 			}
40511195Ssam #endif
40611195Ssam 		} else {
40711195Ssam 			printf("hy%d:  BAR overflow\n", unit);
40811195Ssam 			hycancel(ui);
40911195Ssam 		}
41011195Ssam 	} else if (NORMAL(addr)) {
41111195Ssam 		/*
41211195Ssam 		 * normal interrupt, bump state machine unless in state
41311195Ssam 		 * waiting and no data present (assumed to be word count
41411195Ssam 		 * zero interrupt or other hardware botch)
41511195Ssam 		 */
41611195Ssam 		if (is->hy_state != WAITING || RECV_DATA(addr))
41711195Ssam 			hyact(ui);
41811195Ssam 
41911195Ssam 	} else if (ABNORMAL(addr)) {
42011195Ssam 		/*
42111195Ssam 		 * abnormal termination.
42211195Ssam 		 * bump error counts, retry the last function
42311195Ssam 		 * 'MAXRETRY' times before kicking the bucket.
42411195Ssam 		 *
42511195Ssam 		 * don't reissue the cmd if in certain states, abnormal
42611195Ssam 		 * on a reissued cmd or max retry exceeded
42711195Ssam 		 */
42811195Ssam #ifdef HYLOG
42911195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
43011195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
43111195Ssam 			goto logit;
43211195Ssam 		}
43311195Ssam #endif
43411195Ssam #ifdef DEBUG
43511195Ssam 		if (hy_nodebug & 4) hy_debug_flag = 1;
43611195Ssam 		printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
43711195Ssam 			unit, hy_state_names[is->hy_state], is->hy_state);
43811195Ssam 		printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
43911195Ssam 			is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr, is->hy_retry,
44011195Ssam 			is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, is->hy_savedcmd);
44111195Ssam #endif
44211195Ssam #ifdef PI13
44311195Ssam 		addr->hyd_csr &= ~S_C;  /* clear the damned PI-13 */
44411195Ssam #endif
44511195Ssam 		if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) {
44611195Ssam 			is->hy_if.if_oerrors++;
44711195Ssam 		} else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) {
44811195Ssam 			is->hy_if.if_ierrors++;
44911195Ssam 		}
45011195Ssam 
45111195Ssam 		if (is->hy_state == XMITDATASENT ||
45211195Ssam 		    is->hy_state == RECVSENT ||
45311195Ssam 		    is->hy_state == RECVDATASENT ||
45411195Ssam 		    (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) {
45511195Ssam 			hycancel(ui);
45611195Ssam 		} else {
45711195Ssam #ifdef DEBUG
45811195Ssam 			if (hy_nodebug & 2) hy_debug_flag = 1;
45911195Ssam #endif
46011195Ssam 			is->hy_retry++;
46111195Ssam 			is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE;
46211195Ssam 			is->hy_state = IDLE;
46311195Ssam 			hyact(ui);
46411195Ssam 		}
46511195Ssam 	} else {
46611195Ssam 		/*
46711195Ssam 		 * Interrupt is neither normal, abnormal, or interface error.
46811195Ssam 		 * Ignore it. It's either stacked or a word count 0.
46911195Ssam 		 */
47011195Ssam #ifdef HYLOG
47111195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
47211195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
47311195Ssam 			goto logit;
47411195Ssam 		}
47511195Ssam #endif
47611195Ssam #ifdef DEBUG
47711195Ssam 		printD("hy%d: possible stacked interrupt ignored\n", unit);
47811195Ssam #endif
47911195Ssam 	}
48011195Ssam 
48111195Ssam #ifdef DEBUG
48211195Ssam 	printD("hy%d: hyint exit\n\n", unit);
48311195Ssam #endif
48411195Ssam 	hyint_active = 0;
48511195Ssam 
48611195Ssam } /* hyint */
48711195Ssam 
48811195Ssam /*
48911195Ssam  * Encapsulate a packet of type family for the local net.
49011195Ssam  * Use trailer local net encapsulation if enough data in first
49111195Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
49211195Ssam  */
49311195Ssam hyoutput(ifp, m0, dst)
49411195Ssam 	struct ifnet *ifp;
49511195Ssam 	struct mbuf *m0;
49611195Ssam 	struct sockaddr *dst;
49711195Ssam {
49811195Ssam 	register struct hym_hdr *hym;
49911195Ssam 	register struct mbuf *m;
50011195Ssam #ifdef HYROUTE
50111195Ssam 	register struct hyroute *r = &hy_route[ifp->if_unit];
50211195Ssam #endif
50311195Ssam 	short dtype;		/* packet type */
50411195Ssam 	int dhost;		/* destination adapter address */
50511195Ssam 	int dlen;
50611195Ssam 	int mplen = 0;		/* message proper length */
50711195Ssam 	short loopback = 0;	/* hardware loopback requested */
50811195Ssam 	int error = 0;
50911195Ssam 	int s;
51011195Ssam 
51111195Ssam #ifdef DEBUG
51211195Ssam 	if (hy_nodebug & 8) hy_debug_flag = 1;
51311195Ssam #endif
51411195Ssam 	dlen = 0;
51511195Ssam 	for (m = m0; m; m = m->m_next)
51611195Ssam 		dlen += m->m_len;
51711195Ssam 	m = m0;
51811195Ssam 
51911195Ssam 	switch(dst->sa_family) {
52011195Ssam 
52111195Ssam #ifdef INET
52211195Ssam 	case AF_INET: {
52311195Ssam 		register struct ip *ip = mtod(m, struct ip *);
52411195Ssam 		register struct sockaddr_in *sin = (struct sockaddr_in *)dst;
52511195Ssam 		register long hostaddr = in_lnaof(sin->sin_addr);
52611195Ssam 
52711195Ssam 		dhost = hostaddr & 0xffff;
52811195Ssam 		dtype = HYLINK_IP;
52911195Ssam #ifdef DEBUG
53011195Ssam 		printD("hy%d: output to host %x, dhost %x\n", ifp->if_unit, sin->sin_addr.s_addr, dhost);
53111195Ssam #endif
53211195Ssam 		/*
53311195Ssam 		 * debugging loopback support:
53411195Ssam 		 * upper byte of 24 bit host number interpreted as follows
53511195Ssam 		 *	0x00 --> no loopback
53611195Ssam 		 *	0x01 --> hardware loop through remote adapter
53711195Ssam 		 *	other --> software loop through remote ip layer
53811195Ssam 		 */
53911195Ssam 		if (hostaddr & 0xff0000) {
54011195Ssam 			struct in_addr temp;
54111195Ssam 
54211195Ssam 			temp = ip->ip_dst;
54311195Ssam 			ip->ip_dst = ip->ip_src;
54411195Ssam 			ip->ip_src = temp;
54511195Ssam 			if ((hostaddr & 0xff0000) == 0x10000)
54611195Ssam 				loopback = H_LOOPBK;
54711195Ssam 		}
54811195Ssam 		/*
54911195Ssam 		 * If entire packet won't fit in message proper, just
55011195Ssam 		 * send hyperchannel hardware header and ip header in
55111195Ssam 		 * message proper.  If that won't fit either, just send
55211195Ssam 		 * the maximum message proper.
55311195Ssam 		 *
55411195Ssam 		 * This insures that the associated data is at least a
55511195Ssam 		 * TCP/UDP header in length and thus prevents potential
55611195Ssam 		 * problems with very short word counts.
55711195Ssam 		 */
55811195Ssam 		if (dlen > MPSIZE - sizeof (struct hy_hdr)) {
55911195Ssam 			mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2);
56011195Ssam 			if (mplen > MPSIZE)
56111195Ssam 				mplen = MPSIZE;
56211195Ssam 		}
56311195Ssam 		break;
56411195Ssam 	}
56511195Ssam #endif
56611195Ssam 
56711195Ssam 	default:
56811195Ssam 		printf("hy%d: can't handle af%d\n", ifp->if_unit, dst->sa_family);
56911195Ssam #ifdef DEBUG
57011195Ssam 		if (hy_nodebug & 4) hy_debug_flag = 1;
57111195Ssam #endif
57211195Ssam 		error = EAFNOSUPPORT;
57311195Ssam 		goto drop;
57411195Ssam 	}
57511195Ssam 
57611195Ssam 	/*
57711195Ssam 	 * add the software and hardware hyperchannel headers.
57811195Ssam 	 * If there's not enough space in the first mbuf, allocate another.
57911195Ssam 	 * If that should fail, drop this sucker.
58011195Ssam 	 * No extra space for headers is allocated.
58111195Ssam 	 */
58211195Ssam 	if (m->m_off > MMAXOFF ||
58311195Ssam 	    MMINOFF + sizeof(struct hym_hdr) > m->m_off) {
58411195Ssam 		m = m_get(M_DONTWAIT);
58511195Ssam 		if (m == 0) {
58611195Ssam 			m = m0;
58711195Ssam 			error = ENOBUFS;
58811195Ssam 			goto drop;
58911195Ssam 		}
59011195Ssam 		m->m_next = m0;
59111195Ssam 		m->m_off = MMINOFF;
59211195Ssam 		m->m_len = sizeof(struct hym_hdr);
59311195Ssam 	} else {
59411195Ssam 		m->m_off -= sizeof(struct hym_hdr);
59511195Ssam 		m->m_len += sizeof(struct hym_hdr);
59611195Ssam 	}
59711195Ssam 	hym = mtod(m, struct hym_hdr *);
59811195Ssam 	hym->hym_mplen = mplen;
59911195Ssam 	hym->hym_hdr.hyh_type = dtype;
60011195Ssam 	hym->hym_hdr.hyh_off = 0;
60111195Ssam 	hym->hym_hdr.hyh_from = htons(ifp->if_host[0]);
60211195Ssam 	hym->hym_hdr.hyh_param = loopback;
60311195Ssam #ifdef HYROUTE
60411195Ssam 	if (r->hyr_lasttime != 0) {
60511195Ssam 		register struct hy_hash *rh;
60611195Ssam 		register int i;
60711195Ssam 
60811195Ssam 		i = HYRHASH(dhost);
60911195Ssam 		rh = &r->hyr_hash[i];
61011195Ssam 		i = 0;
61111195Ssam 		while (rh->hyr_key != dhost) {
61211195Ssam 			rh++; i++;
61311195Ssam 			if (rh > &r->hyr_hash[HYRSIZE])
61411195Ssam 				rh = &r->hyr_hash[0];
61511195Ssam 			if (rh->hyr_flags == 0 || i > HYRSIZE)
61611195Ssam 				goto notfound;
61711195Ssam 		}
61811195Ssam 		if (rh->hyr_flags & HYR_GATE) {
61911195Ssam 			loopback = 0;	/* no hardware loopback on gateways */
62011195Ssam 			i = rh->hyr_nextgate;
62111195Ssam 			if (i >= rh->hyr_egate)
62211195Ssam 				rh->hyr_nextgate = rh->hyr_pgate;
62311195Ssam 			else
62411195Ssam 				rh->hyr_nextgate++;
62511195Ssam 			rh = &r->hyr_hash[r->hyr_gateway[i]];
62611195Ssam 			if ((rh->hyr_flags & HYR_DIR) == 0)
62711195Ssam 				goto notfound;
62811195Ssam 		}
62911195Ssam 		hym->hym_hdr.hyh_ctl = rh->hyr_ctl;
63011195Ssam 		hym->hym_hdr.hyh_access = rh->hyr_access;
63111195Ssam 		hym->hym_hdr.hyh_to = rh->hyr_dst;
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 	}
63711195Ssam #else
63811195Ssam 	hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS;
63911195Ssam 	hym->hym_hdr.hyh_access = 0;
64011195Ssam 	hym->hym_hdr.hyh_to = htons(dhost);
64111195Ssam #endif
64211195Ssam 
64311195Ssam headerexists:
64411195Ssam 
64511195Ssam 	if (hym->hym_mplen) {
64611195Ssam 		hym->hym_hdr.hyh_ctl |= H_ASSOC;
64711195Ssam #ifdef DEBUG
64811195Ssam 		if (hy_nodebug & 16) hy_debug_flag = 1;
64911195Ssam #endif
65011195Ssam 	} else hym->hym_hdr.hyh_ctl &= ~H_ASSOC;
65111195Ssam 
65211195Ssam #ifdef DEBUG
65311195Ssam 	printD("hy%d: output mplen=%x ctl=%x access=%x to=%x (adapter %x) from=%x param=%x type=%x off=%x\n",
65411195Ssam 		ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl,
65511195Ssam 		hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to,
65611195Ssam 		hym->hym_hdr.hyh_to_adapter,
65711195Ssam 		hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param,
65811195Ssam 		hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off);
65911195Ssam #endif
66011195Ssam 
66111195Ssam 
66211195Ssam 	s = splimp();
66311195Ssam 	if (IF_QFULL(&ifp->if_snd)) {
66411195Ssam 		IF_DROP(&ifp->if_snd);
66511195Ssam 		error = ENOBUFS;
66611195Ssam 		splx(s);
66711195Ssam 		goto drop;
66811195Ssam 	}
66911195Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
67011195Ssam 	if (hy_softc[ifp->if_unit].hy_state == WAITING)
67111195Ssam 		hyact(hyinfo[ifp->if_unit]);
67211195Ssam 	splx(s);
67311195Ssam 	return(0);
67411195Ssam 
67511195Ssam notfound:
67611195Ssam 	error = ENETUNREACH;	/* KLUDGE - should produce better error number */
67711195Ssam drop:
67811195Ssam 	m_freem(m);
67911195Ssam 	return(error);
68011195Ssam } /* hyoutput */
68111195Ssam 
68211195Ssam hyact(ui)
68311195Ssam 	register struct uba_device *ui;
68411195Ssam {
68511195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
68611195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
68711195Ssam 
68811195Ssam actloop:
68911195Ssam 
69011195Ssam #ifdef DEBUG
69111195Ssam 	printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, hy_state_names[is->hy_state]);
69211195Ssam #endif
69311195Ssam 
69411195Ssam 	switch (is->hy_state) {
69511195Ssam 
69611195Ssam 	case STARTUP:
69711195Ssam 		goto endintr;
69811195Ssam 
69911195Ssam 	case IDLE: {
70011195Ssam 		register rq = is->hy_flags;
70111195Ssam 
70211195Ssam 		if (rq & RQ_STATUS) {
70311195Ssam 			is->hy_flags &= ~RQ_STATUS;
70411195Ssam 			is->hy_state = STATSENT;
70511195Ssam 			hystart(ui, HYF_STATUS, sizeof(is->hy_status), is->hy_ifuba.ifu_r.ifrw_info);
70611195Ssam 		} else if (rq & RQ_ENDOP) {
70711195Ssam 			is->hy_flags &= ~RQ_ENDOP;
70811195Ssam 			is->hy_state = ENDOPSENT;
70911195Ssam 			hystart(ui, HYF_END_OP, 0, 0);
71011195Ssam 		} else if (rq & RQ_STATISTICS) {
71111195Ssam 			is->hy_flags &= ~RQ_STATISTICS;
71211195Ssam 			is->hy_state = RSTATSENT;
71311195Ssam 			hystart(ui, HYF_RSTATS, sizeof(is->hy_stat), is->hy_ifuba.ifu_r.ifrw_info);
71411195Ssam 		} else if (RECV_DATA(addr)) {
71511195Ssam 			is->hy_state = RECVSENT;
71611195Ssam 			is->hy_retry = 0;
71711195Ssam 			hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info);
71811195Ssam 		} else if (rq & RQ_REISSUE) {
71911195Ssam 			is->hy_flags &= ~RQ_REISSUE;
72011195Ssam 			is->hy_state = is->hy_savedstate;
72111195Ssam #ifdef DEBUG
72211195Ssam 			printD("hy%d: reissue cmd=0x%x count=%d ubaddr=0x%x retry=%d\n",
72311195Ssam 				ui->ui_unit, is->hy_savedcmd,
72411195Ssam 				is->hy_savedcount, is->hy_savedaddr, is->hy_retry);
72511195Ssam #endif
72611195Ssam 			hystart(ui, is->hy_savedcmd, is->hy_savedcount, is->hy_savedaddr);
72711195Ssam 		} else {
72811195Ssam 			register struct mbuf *m;
72911195Ssam 
73011195Ssam 			IF_DEQUEUE(&is->hy_if.if_snd, m);
73111195Ssam 			if (m != 0) {
73211195Ssam 				register struct hym_hdr *hym;
73311195Ssam 				register int mplen;
73411195Ssam 				register int cmd;
73511195Ssam 
73611195Ssam 				is->hy_state = XMITSENT;
73711195Ssam 				is->hy_retry = 0;
73811195Ssam 				hym = mtod(m, struct hym_hdr *);
73911195Ssam #ifdef HYLOG
74011195Ssam 				hylog(HYL_XMIT, sizeof(struct hym_hdr), (char *)hym);
74111195Ssam #endif
74211195Ssam 				mplen = hym->hym_mplen;
74311195Ssam 				cmd = (hym->hym_hdr.hyh_to_adapter == hym->hym_hdr.hyh_from_adapter) ?
74411195Ssam 					HYF_XMITLOCMSG : HYF_XMITMSG;
74511195Ssam #ifdef DEBUG
74611195Ssam 				printD("hy%d: hym_hdr = ", ui->ui_unit);
74711195Ssam 				if (hy_debug_flag) hyprintdata((char *)hym, sizeof(struct hym_hdr));
74811195Ssam #endif
74911195Ssam 				/*
75011195Ssam 				 * strip off the software part of
75111195Ssam 				 * the hyperchannel header
75211195Ssam 				 */
75311195Ssam 				m->m_off += sizeof(struct hym_data);
75411195Ssam 				m->m_len -= sizeof(struct hym_data);
75511195Ssam 				is->hy_olen = if_wubaput(&is->hy_ifuba, m);
75611195Ssam #ifdef SUPBDP
75711195Ssam 				if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
75811195Ssam 					UBAPURGE(is->hy_ifuba.ifu_uba, is->hy_ifuba.ifu_w.ifrw_bdp);
75911195Ssam #endif
76011195Ssam #ifdef DEBUG
76111195Ssam 				printD("hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
76211195Ssam 					ui->ui_unit, mplen, is->hy_olen);
76311195Ssam 				if (hy_debug_flag) hyprintdata(is->hy_ifuba.ifu_w.ifrw_addr, is->hy_olen);
76411195Ssam #endif
76511195Ssam 				hystart(ui, cmd, (mplen == 0) ? is->hy_olen : mplen,
76611195Ssam 					is->hy_ifuba.ifu_w.ifrw_info);
76711195Ssam 				if (mplen != 0)
76811195Ssam 					is->hy_flags |= RQ_XASSOC;
76911195Ssam 			} else if (rq & RQ_MARKDOWN) {
77011195Ssam 				is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
77111195Ssam 				is->hy_state = MARKPORT;
77211195Ssam 				is->hy_retry = 0;
77311195Ssam 				/*
77411195Ssam 				 * port number is taken from status data
77511195Ssam 				 */
77611195Ssam 				hystart(ui, HYF_MARKP0 | (PORTNUM(&is->hy_status) << 2), 0, 0);
77711195Ssam 			} else if (rq & RQ_MARKUP) {
77811195Ssam 				register struct ifnet *ifp = &is->hy_if;
77911195Ssam 				register struct sockaddr_in *sin = (struct sockaddr_in *)&ifp->if_addr;
78011195Ssam 
78111195Ssam 				is->hy_flags &= ~(RQ_MARKUP);
78211195Ssam 				is->hy_retry = 0;
78311195Ssam 				/*
78411195Ssam 				 * Fill in the internet address from the status buffer
78511195Ssam 				 */
78611195Ssam 				printf("hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
78711195Ssam 					ui->ui_unit,
78811195Ssam 					is->hy_stat.hyc_uaddr,
78911195Ssam 					PORTNUM(&is->hy_status),
79011195Ssam 					(is->hy_stat.hyc_atype[0]<<8) | is->hy_stat.hyc_atype[1],
79111195Ssam 					is->hy_stat.hyc_atype[2]);
79211195Ssam 
79311195Ssam 				ifp->if_host[0] = (is->hy_stat.hyc_uaddr << 8) | PORTNUM(&is->hy_status);
79411195Ssam 				sin->sin_family = AF_INET;
79511195Ssam 				sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
79611195Ssam 				ifp->if_flags |= IFF_UP;
79711195Ssam 				if_rtinit(ifp, RTF_UP);
79811195Ssam #ifdef HYLOG
79911195Ssam 				hylog(HYL_UP, 0, (char *)0);
80011195Ssam #endif
80111195Ssam 
80211195Ssam 			} else {
80311195Ssam 				is->hy_state = WAITING;
80411195Ssam 				is->hy_retry = 0;
80511195Ssam 				hystart(ui, HYF_WAITFORMSG, 0, 0);
80611195Ssam 			}
80711195Ssam 		}
80811195Ssam 	}
80911195Ssam 	break;
81011195Ssam 
81111195Ssam 	case STATSENT:
81211195Ssam 
81311195Ssam 		bcopy(is->hy_ifuba.ifu_r.ifrw_addr, &is->hy_status, sizeof(struct hy_status));
81411195Ssam #ifdef DEBUG
81511195Ssam 		printD("hy%d: status - %x %x %x %x %x %x %x %x\n", ui->ui_unit,
81611195Ssam 			is->hy_status.hys_gen_status, is->hy_status.hys_last_fcn,
81711195Ssam 			is->hy_status.hys_resp_trunk, is->hy_status.hys_status_trunk,
81811195Ssam 			is->hy_status.hys_recd_resp, is->hy_status.hys_error,
81911195Ssam 			is->hy_status.hys_caddr, is->hy_status.hys_pad);
82011195Ssam #endif
82111195Ssam 		is->hy_state = IDLE;
82211195Ssam #ifdef HYLOG
82311195Ssam 		hylog(HYL_STATUS, sizeof(struct hy_status), (char *)&is->hy_status);
82411195Ssam #endif
82511195Ssam #ifdef HYELOG
82611195Ssam 		{
82711195Ssam 			register int i;
82811195Ssam 
82911195Ssam 			i = is->hy_status.hys_error;
83011195Ssam 			if (i < HYE_MAX)
83111195Ssam 				i = HYE_MAX;
83211195Ssam 			switch (is->hy_status.hys_last_fcn) {
83311195Ssam 				case HYF_XMITLOCMSG:
83411195Ssam 					i += HYE_MAX+1;	/* fall through */
83511195Ssam 				case HYF_XMITLSTDATA:
83611195Ssam 					i += HYE_MAX+1;	/* fall through */
83711195Ssam 				case HYF_XMITMSG:
83811195Ssam 					i += HYE_MAX+1;
83911195Ssam 			}
84011195Ssam 			hy_elog[i]++;
84111195Ssam 		}
84211195Ssam #endif
84311195Ssam 		break;
84411195Ssam 
84511195Ssam 	case RSTATSENT: {
84611195Ssam 		register struct hy_stat *p = (struct hy_stat *) is->hy_ifuba.ifu_r.ifrw_addr;
84711195Ssam 
84811195Ssam 		is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt);
84911195Ssam 		is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt);
85011195Ssam 		is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy);
85111195Ssam 		is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret);
85211195Ssam 		is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad);
85311195Ssam 		is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret);
85411195Ssam 		is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort);
85511195Ssam 		is->hy_stat.hyc_atype[0] = p->hyc_atype[0];
85611195Ssam 		is->hy_stat.hyc_atype[1] = p->hyc_atype[1];
85711195Ssam 		is->hy_stat.hyc_atype[2] = p->hyc_atype[2];
85811195Ssam 		is->hy_stat.hyc_uaddr = p->hyc_uaddr;
85911195Ssam 
86011195Ssam #ifdef DEBUG
86111195Ssam 		printD("hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n",
86211195Ssam 			ui->ui_unit,
86311195Ssam 			is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt,
86411195Ssam 			is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret,
86511195Ssam 			is->hy_stat.hyc_crcbad);
86611195Ssam 		printD("	mcret %d tdabort %d atype %x %x %x uaddr %x\n",
86711195Ssam 			is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort,
86811195Ssam 			is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
86911195Ssam 			is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
87011195Ssam #endif
87111195Ssam 		is->hy_state = IDLE;
87211195Ssam #ifdef HYLOG
87311195Ssam 		hylog(HYL_STATISTICS, sizeof(struct hy_stat), (char *)&is->hy_stat);
87411195Ssam #endif
87511195Ssam 		break;
87611195Ssam 	}
87711195Ssam 
87811195Ssam 	case CLEARSENT:
87911195Ssam 		is->hy_state = IDLE;
88011195Ssam 		break;
88111195Ssam 
88211195Ssam 	case ENDOPSENT:
88311195Ssam 		is->hy_state = IDLE;
88411195Ssam 		break;
88511195Ssam 
88611195Ssam 	case RECVSENT: {
88711195Ssam 			register struct hy_hdr *hyh;
88811195Ssam 			register unsigned len;
88911195Ssam 
89011195Ssam #ifdef SUPBDP
89111195Ssam 			if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)	/* purge the BDP */
89211195Ssam 				UBAPURGE(is->hy_ifuba.ifu_uba, is->hy_ifuba.ifu_r.ifrw_bdp);
89311195Ssam #endif
89411195Ssam 			hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
89511195Ssam 			len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
89611195Ssam 			if (len > MPSIZE) {
89711195Ssam 				printf("hy%d: RECVD MP > MPSIZE (%d)\n", ui->ui_unit, len);
89811195Ssam #ifdef DEBUG
89911195Ssam 				hy_debug_flag = 1;
90011195Ssam 				printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
90111195Ssam 					ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
90211195Ssam #endif
90311195Ssam 			}
90411195Ssam 
90511195Ssam #ifdef DEBUG
90611195Ssam 			printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
90711195Ssam 			if (hy_debug_flag) hyprintdata((char *)hyh, len);
90811195Ssam #endif
90911195Ssam 			if (hyh->hyh_ctl & H_ASSOC) {
91011195Ssam 				is->hy_state = RECVDATASENT;
91111195Ssam 				is->hy_ilen = len;
91211195Ssam 				is->hy_retry = 0;
91311195Ssam 				hystart(ui, HYF_INPUTDATA, HYMTU-len+sizeof(struct hy_hdr), is->hy_ifuba.ifu_r.ifrw_info + len);
91411195Ssam 			} else {
91511195Ssam 				hyrecvdata(ui, hyh, len);
91611195Ssam 				is->hy_state = IDLE;
91711195Ssam 			}
91811195Ssam 			break;
91911195Ssam 		}
92011195Ssam 
92111195Ssam 	case RECVDATASENT: {
92211195Ssam 			register struct hy_hdr *hyh;
92311195Ssam 			register unsigned len;
92411195Ssam 
92511195Ssam #ifdef SUPBDP
92611195Ssam 			if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)	/* purge the BDP */
92711195Ssam 				UBAPURGE(is->hy_ifuba.ifu_uba, is->hy_ifuba.ifu_r.ifrw_bdp);
92811195Ssam #endif
92911195Ssam 			hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
93011195Ssam 			len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
93111195Ssam #ifdef DEBUG
93211195Ssam 			printD("hy%d: recvd assoc data, len = %d, data = ", ui->ui_unit, len);
93311195Ssam 			if (hy_debug_flag) hyprintdata((char *)hyh + is->hy_ilen, len);
93411195Ssam #endif
93511195Ssam 			hyrecvdata(ui, hyh, len + is->hy_ilen);
93611195Ssam 			is->hy_state = IDLE;
93711195Ssam 			break;
93811195Ssam 		}
93911195Ssam 
94011195Ssam 	case XMITSENT:
94111195Ssam 			if (is->hy_flags & RQ_XASSOC) {
94211195Ssam 				register unsigned len;	/* number of bytes sent in message proper */
94311195Ssam 
94411195Ssam 				is->hy_flags &= ~RQ_XASSOC;
94511195Ssam 				is->hy_state = XMITDATASENT;
94611195Ssam 				is->hy_retry = 0;
94711195Ssam 				len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
94811195Ssam 				if (len > is->hy_olen) {
94911195Ssam 					printf("hy%d: xmit error - len > hy_olen [%d > %d]\n", ui->ui_unit, len, is->hy_olen);
95011195Ssam #ifdef DEBUG
95111195Ssam 					hy_debug_flag = 1;
95211195Ssam #endif
95311195Ssam 				}
95411195Ssam 				hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
95511195Ssam 					is->hy_ifuba.ifu_w.ifrw_info + len);
95611195Ssam 				break;
95711195Ssam 			}
95811195Ssam 
95911195Ssam 			/* fall through to ... */
96011195Ssam 
96111195Ssam 	case XMITDATASENT:
96211195Ssam 			hyxmitdata(ui);
96311195Ssam 			is->hy_state = IDLE;
96411195Ssam 			break;
96511195Ssam 
96611195Ssam 	case WAITING:	/* wait for message complete or output requested */
96711195Ssam 		if (RECV_DATA(addr))
96811195Ssam 			is->hy_state = IDLE;
96911195Ssam 		else {
97011195Ssam 			is->hy_state = CLEARSENT;
97111195Ssam 			is->hy_retry = 0;
97211195Ssam 			hystart(ui, HYF_CLRWFMSG, 0, 0);
97311195Ssam 		}
97411195Ssam 		break;
97511195Ssam 
97611195Ssam 	case MARKPORT:
97711195Ssam 		is->hy_state = STARTUP;
97811195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
97911195Ssam 		goto endintr;
98011195Ssam 
98111195Ssam 	default:
98211195Ssam 		printf("hy%d: DRIVER BUG - INVALID STATE %d\n", ui->ui_unit, is->hy_state);
98311195Ssam 		panic("HYPERCHANNEL IN INVALID STATE");
98411195Ssam 		/*NOTREACHED*/
98511195Ssam 
98611195Ssam 	} /* end of switch */
98711195Ssam 
98811195Ssam 	if (is->hy_state == IDLE)
98911195Ssam 		goto actloop;
99011195Ssam endintr:
99111195Ssam 
99211195Ssam #ifdef DEBUG
99311195Ssam 	printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, hy_state_names[is->hy_state]);
99411195Ssam #endif
99511195Ssam 	return(0);
99611195Ssam } /* hyact */
99711195Ssam 
99811195Ssam /*
99911195Ssam  * Called from device interrupt when recieving data.
100011195Ssam  * Examine packet to determine type.  Decapsulate packet
100111195Ssam  * based on type and pass to type specific higher-level
100211195Ssam  * input routine.
100311195Ssam  */
100411195Ssam hyrecvdata(ui, hyh0, len)
100511195Ssam 	struct uba_device *ui;
100611195Ssam 	struct hy_hdr *hyh0;
100711195Ssam 	int len;
100811195Ssam {
100911195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
101011195Ssam 	register struct hy_hdr *hyh = hyh0;
101111195Ssam     	struct mbuf *m;
101211195Ssam 	register struct ifqueue *inq;
101311195Ssam 
101411195Ssam 	is->hy_if.if_ipackets++;
101511195Ssam #ifdef DEBUG
101611195Ssam 	printD("hy%d: recieved packet, len = %d (actual %d)\n", ui->ui_unit, len, len - (hyh->hyh_off + sizeof(struct hy_hdr)));
101711195Ssam #endif
101811195Ssam #ifdef HYLOG
101911195Ssam 	{
102011195Ssam 		struct {
102111195Ssam 			short hlen;
102211195Ssam 			struct hy_hdr hhdr;
102311195Ssam 		} hh;
102411195Ssam 		hh.hlen = len;
102511195Ssam 		hh.hhdr = *hyh;
102611195Ssam 		hylog(HYL_RECV, sizeof(hh), (char *)&hh);
102711195Ssam 	}
102811195Ssam #endif
102911195Ssam 
103011195Ssam 	if (len > HYMTU + MPSIZE || len == 0)
103111195Ssam 		return;			/* sanity */
103211195Ssam 
103311195Ssam 	/*
103411195Ssam 	 * Pull packet off interface.
103511195Ssam 	 */
103611195Ssam 	m = if_rubaget(&is->hy_ifuba, len, 0);
103711195Ssam 	if (m == 0)
103811195Ssam 		return;
103911195Ssam 
104011195Ssam 	switch (hyh->hyh_type) {
104111195Ssam 
104211195Ssam #ifdef INET
104311195Ssam 	case HYLINK_IP:
104411195Ssam 		/*
104511195Ssam 		 * strip the variable portion of the hyperchannel header
104611195Ssam 		 * (fixed portion stripped in if_rubaget)
104711195Ssam 		 */
104811195Ssam 		m->m_len -= hyh->hyh_off;
104911195Ssam 		m->m_off += hyh->hyh_off;
105011195Ssam 		/*
105111195Ssam 		 * sent the packet up the chain to IP
105211195Ssam 		 */
105311195Ssam 		schednetisr(NETISR_IP);
105411195Ssam 		inq = &ipintrq;
105511195Ssam 		break;
105611195Ssam #endif
105711195Ssam 	default:
105811195Ssam 		m_freem(m);
105911195Ssam 		return;
106011195Ssam 	}
106111195Ssam 
106211195Ssam 	if (IF_QFULL(inq)) {
106311195Ssam 		IF_DROP(inq);
106411195Ssam 		m_freem(m);
106511195Ssam 	} else
106611195Ssam 		IF_ENQUEUE(inq, m);
106711195Ssam } /* hyrecvdata */
106811195Ssam 
106911195Ssam /*
107011195Ssam  * transmit done, release resources, bump counters
107111195Ssam  */
107211195Ssam hyxmitdata(ui)
107311195Ssam 	struct uba_device *ui;
107411195Ssam {
107511195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
107611195Ssam 
107711195Ssam 	is->hy_if.if_opackets++;
107811195Ssam 
107911195Ssam 	if (is->hy_ifuba.ifu_xtofree) {		/* free left over pages */
108011195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
108111195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
108211195Ssam 	}
108311195Ssam } /* hyxmitdata */
108411195Ssam 
108511195Ssam hycancel(ui)
108611195Ssam 	register struct uba_device *ui;
108711195Ssam {
108811195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
108911195Ssam 
109011195Ssam 	if (is->hy_ifuba.ifu_xtofree) {		/* free left over pages */
109111195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
109211195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
109311195Ssam 	}
109411195Ssam 
109511195Ssam #ifdef DEBUG
109611195Ssam 	if (hy_nodebug & 1) hy_debug_flag = 1;
109711195Ssam #endif
109811195Ssam 
109911195Ssam #ifdef DEBUG
110011195Ssam 	printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
110111195Ssam 		ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
110211195Ssam 		is->hy_savedcount, is->hy_savedaddr);
110311195Ssam 	printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
110411195Ssam 		is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr, is->hy_retry,
110511195Ssam 		is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, is->hy_savedcmd);
110611195Ssam #endif
110711195Ssam 	is->hy_state = IDLE;
110811195Ssam 	is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
110911195Ssam 	hyact(ui);
111011195Ssam } /* hycancel */
111111195Ssam 
111211195Ssam #ifdef DEBUG
111311195Ssam hyprintdata(cp, len)
111411195Ssam 	register char *cp;
111511195Ssam 	register int len;
111611195Ssam {
111711195Ssam 	register int count = 16;
111811195Ssam 	register char *fmt;
111911195Ssam 	static char regfmt[] = "\n\t %x";
112011195Ssam 
112111195Ssam 	fmt = &regfmt[2];
112211195Ssam 	while (--len >= 0) {
112311195Ssam 		printL(fmt, *cp++ & 0xff);
112411195Ssam 		fmt = &regfmt[2];
112511195Ssam 		if (--count <= 0) {
112611195Ssam 			fmt = &regfmt[0];
112711195Ssam 			count = 16;
112811195Ssam 		}
112911195Ssam 	}
113011195Ssam 	printL("\n");
113111195Ssam }
113211195Ssam #endif
113311195Ssam 
113411195Ssam hywatch(unit)
113511195Ssam int unit;
113611195Ssam {
113711195Ssam 	register struct hy_softc *is = &hy_softc[unit];
113811195Ssam 	register struct uba_device *ui = hyinfo[unit];
113911195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
114011195Ssam 	int s;
114111195Ssam 
114211195Ssam 	s = splimp();
114311195Ssam 	is->hy_if.if_timer = SCANINTERVAL;
114411195Ssam 	if (is->hy_ntime > 2 && is->hy_state != WAITING && is->hy_state != STARTUP && is->hy_state != IDLE) {
114511195Ssam 		printf("hy%d: watchdog timer expired\n", unit);
114611195Ssam 		hycancel(ui);
114711195Ssam 	}
114811195Ssam #ifdef PI13
114911195Ssam 	if ((addr->hyd_csr & S_POWEROFF) != 0) {
115011195Ssam 		addr->hyd_csr |= S_POWEROFF;
115111195Ssam 		DELAY(100);
115211195Ssam 		if ((addr->hyd_csr & S_POWEROFF) == 0) {
115311195Ssam 			printf("hy%d: adapter power restored\n", unit);
115411195Ssam 			is->hy_state = IDLE;
115511195Ssam 			is->hy_flags |= (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
115611195Ssam 			hyact(ui);
115711195Ssam 		}
115811195Ssam 	}
115911195Ssam #endif
116011195Ssam 	splx(s);
116111195Ssam }
116211195Ssam 
116311195Ssam #ifdef HYLOG
116411195Ssam hylog(code, len, ptr)
116511195Ssam 	int code;
116611195Ssam 	int len;
116711195Ssam 	char *ptr;
116811195Ssam {
116911195Ssam 	register unsigned char *p;
117011195Ssam 	int s;
117111195Ssam 
117211195Ssam 	s = splimp();
117311195Ssam 
117411195Ssam 	if (hy_log.hyl_self != &hy_log) {
117511195Ssam 		hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
117611195Ssam 		hy_log.hyl_ptr = &hy_log.hyl_buf[0];
117711195Ssam 		hy_log.hyl_self = &hy_log;
117811195Ssam 		hy_log.hyl_enable = HYL_DISABLED;
117911195Ssam 		hy_log.hyl_onerr = HYL_CATCH1;
118011195Ssam 	}
118111195Ssam 
118211195Ssam 	if (hy_log.hyl_enable == HYL_DISABLED
118311195Ssam 		|| hy_log.hyl_enable == HYL_CAUGHT1
118411195Ssam 		|| hy_log.hyl_enable == HYL_CAUGHTSTATUS
118511195Ssam 		|| (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS))
118611195Ssam 			goto out;
118711195Ssam 
118811195Ssam 	p = hy_log.hyl_ptr;
118911195Ssam 
119011195Ssam 	if (p + len + 2 >= hy_log.hyl_eptr) {
119111195Ssam 		bzero(p, hy_log.hyl_eptr - p);
119211195Ssam 		p = &hy_log.hyl_buf[0];
119311195Ssam 		if (hy_log.hyl_enable == HYL_CATCH1) {
119411195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1;
119511195Ssam 			goto out;
119611195Ssam 		}
119711195Ssam 		if (hy_log.hyl_enable == HYL_CATCHSTATUS) {
119811195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS;
119911195Ssam 			goto out;
120011195Ssam 		}
120111195Ssam 	}
120211195Ssam 
120311195Ssam 	*p++ = code;
120411195Ssam 	*p++ = len;
120511195Ssam 	bcopy(ptr, p, len);
120611195Ssam 	hy_log.hyl_ptr = p + len;
120711195Ssam out:
120811195Ssam 	splx(s);
120911195Ssam }
121011195Ssam #endif
121111195Ssam 
121211195Ssam hyioctl(dev, cmd, addr, flag)
121311195Ssam 	dev_t	dev;
121411195Ssam 	int	cmd;
121511195Ssam 	caddr_t	addr;
121611195Ssam 	int	flag;
121711195Ssam {
121811195Ssam 	register struct hyroute *r = &hy_route[minor(dev)];
121911195Ssam 	register int s;
122011195Ssam 
122111195Ssam 	if (minor(dev) >= NHY) {
122211195Ssam 		u.u_error = ENXIO;
122311195Ssam 		return;
122411195Ssam 	}
122511195Ssam 	s = splimp();
122611195Ssam 
122711195Ssam 	switch(cmd) {
122811195Ssam 
122911195Ssam 	case HYSETROUTE:
123011195Ssam 		if (suser()) {
123111195Ssam 			if (copyin(addr, (caddr_t)r, sizeof(*r)))
123211195Ssam 				u.u_error = EFAULT;
123311195Ssam 			r->hyr_lasttime = time;
123411195Ssam 		}
123511195Ssam 		break;
123611195Ssam 
123711195Ssam 	case HYGETROUTE:
123811195Ssam 		if (copyout((caddr_t)r, addr, sizeof(*r)))
123911195Ssam 			u.u_error = EFAULT;
124011195Ssam 		break;
124111195Ssam 
124211195Ssam 	default:
124311195Ssam 		u.u_error = ENXIO;
124411195Ssam 		break;
124511195Ssam 	}
124611195Ssam 	splx(s);
124711195Ssam }
1248