xref: /csrg-svn/sys/vax/if/if_hy.c (revision 11207)
1*11207Ssam /*	if_hy.c	4.3	83/02/21	*/
211195Ssam 
311195Ssam #include "hy.h"
411195Ssam #if NHY > 0
511195Ssam 
611195Ssam /*
711195Ssam  * Network Systems Copropration Hyperchanel interface
811195Ssam  *
9*11207Ssam  * UNTESTED WITH 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/vmmac.h"
2011195Ssam #include "../h/errno.h"
21*11207Ssam #include "../h/time.h"
22*11207Ssam #include "../h/kernel.h"
23*11207Ssam #include "../h/ioctl.h"
2411195Ssam 
2511195Ssam #include "../net/if.h"
26*11207Ssam #include "../net/netisr.h"
2711195Ssam #include "../net/route.h"
2811195Ssam 
2911195Ssam #include "../netinet/in.h"
3011195Ssam #include "../netinet/in_systm.h"
3111195Ssam #include "../netinet/ip.h"
3211195Ssam #include "../netinet/ip_var.h"
3311195Ssam 
34*11207Ssam #include "../vax/cpu.h"
35*11207Ssam #include "../vax/mtpr.h"
36*11207Ssam 
37*11207Ssam #include "../vaxuba/ubareg.h"
38*11207Ssam #include "../vaxuba/ubavar.h"
39*11207Ssam 
4011195Ssam #include "../vaxif/if_hy.h"
4111198Ssam #include "../vaxif/if_hyreg.h"
4211195Ssam #include "../vaxif/if_uba.h"
4311195Ssam 
4411195Ssam #define HYROUTE
4511195Ssam #define HYELOG
4611195Ssam #define	HYMTU	576
4711195Ssam 
4811195Ssam int	hyprobe(), hyattach(), hyinit(), hyoutput(), hyreset(), hywatch();
4911195Ssam struct	uba_device *hyinfo[NHY];
5011195Ssam u_short hystd[] = { 0772410, 0 };
5111195Ssam struct	uba_driver hydriver =
5211195Ssam 	{ hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo };
5311195Ssam 
5411195Ssam /*
5511195Ssam  * Hyperchannel software status per interface.
5611195Ssam  *
5711195Ssam  * Each interface is referenced by a network interface structure,
5811195Ssam  * hy_if, which the routing code uses to locate the interface.
5911195Ssam  * This structure contains the output queue for the interface, its address, ...
6011195Ssam  * We also have, for each interface, a UBA interface structure, which
6111195Ssam  * contains information about the UNIBUS resources held by the interface:
6211195Ssam  * map registers, buffered data paths, etc.  Information is cached in this
6311195Ssam  * structure for use by the if_uba.c routines in running the interface
6411195Ssam  * efficiently.
6511195Ssam  */
6611195Ssam struct	hy_softc {
6711195Ssam 	struct	ifnet hy_if;		/* network-visible interface */
6811195Ssam 	struct	ifuba hy_ifuba;		/* UNIBUS resources */
69*11207Ssam 	short	hy_flags;		/* flags */
70*11207Ssam 	short	hy_state;		/* driver state */
7111195Ssam 	int	hy_ilen;		/* mp length on input */
7211195Ssam 	int	hy_olen;		/* packet length on output */
7311195Ssam 	int	hy_lastwcr;		/* last command's word count */
7411195Ssam 	short	hy_savedstate;		/* saved for reissue after status */
7511195Ssam 	short	hy_savedcmd;		/* saved command for reissue */
7611195Ssam 	int	hy_savedcount;		/* saved byte count for reissue */
7711195Ssam 	int	hy_savedaddr;		/* saved unibus address for reissue */
7811195Ssam 	int	hy_ntime;		/* number of timeouts since last cmd */
7911195Ssam 	int	hy_retry;		/* retry counter */
80*11207Ssam 	struct	hy_stat hy_stat;	/* statistics */
81*11207Ssam 	struct	hy_status hy_status;	/* status */
8211195Ssam } hy_softc[NHY];
8311195Ssam 
8411195Ssam #ifdef HYELOG
85*11207Ssam #define HYE_MAX	0x18
86*11207Ssam u_long	hy_elog[(HYE_MAX+1)*4];
8711195Ssam #endif
8811195Ssam 
8911195Ssam #ifdef DEBUG
9011195Ssam #define printL	lprintf
9111195Ssam #define printD	if (hy_debug_flag) lprintf
9211195Ssam int	hy_debug_flag = 0;
9311195Ssam /*
9411195Ssam  * hy_nodebug bit 0x01	set hy_debug_flag on hycancel
9511195Ssam  * hy_nodebug bit 0x02	set hy_debug_flag on command reissue
9611195Ssam  * hy_nodebug bit 0x04	set hy_debug_flag on abnormal interrupt
9711195Ssam  * hy_nodebug bit 0x08	set hy_debug_flag on hyouput
9811195Ssam  * hy_nodebug bit 0x10	set hy_debug_flag on hyouput with associated data
9911195Ssam  */
10011195Ssam int	hy_nodebug = 0x0;
10111195Ssam #else
10211195Ssam #define printD	hyvoid
10311195Ssam #endif
10411195Ssam 
10511195Ssam /*
106*11207Ssam  * Requests for service (in order by descending priority).
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 #define RQ_XASSOC	0100	/* associated data to transmit */
11611195Ssam 
11711195Ssam /*
118*11207Ssam  * Driver states.
11911195Ssam  */
12011195Ssam #define	STARTUP		0	/* initial state (before fully there) */
12111195Ssam #define	IDLE		1	/* idle state */
12211195Ssam #define	STATSENT	2	/* status cmd sent to adapter */
12311195Ssam #define	ENDOPSENT	3	/* end operation cmd sent */
12411195Ssam #define	RECVSENT	4	/* input message cmd sent */
12511195Ssam #define	RECVDATASENT	5	/* input data cmd sent */
12611195Ssam #define	XMITSENT	6	/* transmit message cmd sent */
12711195Ssam #define	XMITDATASENT	7	/* transmit data cmd sent */
12811195Ssam #define	WAITING		8	/* waiting for messages */
12911195Ssam #define	CLEARSENT	9	/* clear wait for message cmd sent */
13011195Ssam #define MARKPORT	10	/* mark this host's adapter port down issued */
13111195Ssam #define RSTATSENT	11	/* read statistics cmd sent to adapter */
13211195Ssam 
13311195Ssam #ifdef DEBUG
13411195Ssam char *hy_state_names[] = {
13511195Ssam 	"Startup",
13611195Ssam 	"Idle",
13711195Ssam 	"Status Sent",
13811195Ssam 	"End op Sent",
13911195Ssam 	"Recieve Message Proper Sent",
14011195Ssam 	"Recieve Data Sent",
14111195Ssam 	"Transmit Message Proper Sent",
14211195Ssam 	"Transmit Data Sent",
14311195Ssam 	"Wait for Message Sent",
14411195Ssam 	"Clear Wait for Message Sent",
14511195Ssam 	"Mark Port Down Sent",
14611195Ssam 	"Read Statistics Sent"
14711195Ssam };
14811195Ssam #endif
14911195Ssam 
15011195Ssam #define SCANINTERVAL	10	/* seconds */
15111195Ssam #define MAXINTERVAL	20	/* seconds (max action) */
15211195Ssam 
15311195Ssam /*
15411195Ssam  * Cause a device interrupt.  This code uses a buffer starting at
15511195Ssam  * location zero on the unibus (which is already mapped by the
15611195Ssam  * autoconfigure code in the kernel).
15711195Ssam  */
15811195Ssam hyprobe(reg)
15911195Ssam 	caddr_t reg;
16011195Ssam {
16111195Ssam 	register int br, cvec;		/* r11, r10 value-result */
16211195Ssam 	register struct hydevice *addr = (struct hydevice *) reg;
16311195Ssam 
16411195Ssam #ifdef lint
16511195Ssam 	br = 0; cvec = br; br = cvec;
16611195Ssam 	hyint(0);
16711195Ssam #endif
16811195Ssam 	/*
16911195Ssam 	 * request adapter status to a buffer starting at unibus location 0
17011195Ssam 	 */
17111195Ssam 	addr->hyd_bar = 0;
17211195Ssam 	addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1);
17311195Ssam 	addr->hyd_dbuf = HYF_STATUS;
17411195Ssam #ifdef PI13
17511195Ssam 	addr->hyd_csr |= S_GO | S_IE | S_IATTN;
17611195Ssam #else
17711195Ssam 	addr->hyd_csr |= S_GO | S_IE;
17811195Ssam #endif
17911195Ssam 	DELAY(10000);
18011195Ssam #ifdef PI13
18111195Ssam 	addr->hyd_csr |= S_CLRINT;	/* clear any stacked interrupts */
18211195Ssam #endif
18311195Ssam 	addr->hyd_csr &= ~(S_IE | S_CLRINT);	/* disable further interrupts */
18411195Ssam 	return(1);
185*11207Ssam }
18611195Ssam 
18711195Ssam /*
18811195Ssam  * Interface exists: make available by filling in network interface
18911195Ssam  * record.  System will initialize the interface when it is ready
19011195Ssam  * to accept packets.
19111195Ssam  */
19211195Ssam hyattach(ui)
19311195Ssam 	struct uba_device *ui;
19411195Ssam {
19511195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
19611195Ssam 	register struct ifnet *ifp = &is->hy_if;
19711195Ssam 
19811195Ssam 	ifp->if_unit = ui->ui_unit;
19911195Ssam 	ifp->if_name = "hy";
20011195Ssam 	ifp->if_mtu = HYMTU;
20111195Ssam 	ifp->if_net = ui->ui_flags;
20211195Ssam 	is->hy_state = STARTUP;		/* don't allow state transitions yet */
20311195Ssam 	ifp->if_init = hyinit;
20411195Ssam 	ifp->if_output = hyoutput;
205*11207Ssam 	ifp->if_reset = hyreset;
20611195Ssam 	ifp->if_watchdog = hywatch;
20711195Ssam 	ifp->if_timer = SCANINTERVAL;
20811195Ssam 	is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
209*11207Ssam #ifdef notdef
21011195Ssam 	is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
21111195Ssam #endif
21211195Ssam 	if_attach(ifp);
213*11207Ssam }
21411195Ssam 
21511195Ssam /*
21611195Ssam  * Reset of interface after UNIBUS reset.
21711195Ssam  * If interface is on specified uba, reset its state.
21811195Ssam  */
21911195Ssam hyreset(unit, uban)
22011195Ssam 	int unit, uban;
22111195Ssam {
22211195Ssam 	register struct uba_device *ui = hyinfo[unit];
22311195Ssam 	register struct hy_softc *is;
22411195Ssam 
225*11207Ssam 	if (unit >= NHY || ui == 0 || ui->ui_alive == 0 ||
226*11207Ssam 	  ui->ui_ubanum != uban)
22711195Ssam 		return;
22811195Ssam 	printf(" hy%d", unit);
22911195Ssam 	hyinit(unit);
230*11207Ssam }
23111195Ssam 
23211195Ssam /*
23311195Ssam  * Initialization of interface; clear recorded pending
23411195Ssam  * operations, and reinitialize UNIBUS usage.
23511195Ssam  */
23611195Ssam hyinit(unit)
23711195Ssam 	int unit;
23811195Ssam {
23911195Ssam 	register struct hy_softc *is = &hy_softc[unit];
24011195Ssam 	register struct uba_device *ui = hyinfo[unit];
24111195Ssam 	int s;
24211195Ssam 
24311195Ssam 	if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
24411195Ssam 	    sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) {
24511195Ssam #ifdef DEBUG
246*11207Ssam 		if (hy_nodebug & 4)
247*11207Ssam 			hy_debug_flag = 1;
24811195Ssam #endif
24911195Ssam 		printf("hy%d: can't initialize\n", unit);
25011195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
25111195Ssam 		return;
25211195Ssam 	}
25311195Ssam 	/*
254*11207Ssam 	 * Issue wait for message and start the state machine
25511195Ssam 	 */
25611195Ssam 	s = splimp();
25711195Ssam 	is->hy_state = IDLE;
25811195Ssam 	is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
25911195Ssam 	is->hy_retry = 0;
26011195Ssam 	hyact(ui);
26111195Ssam 	splx(s);
262*11207Ssam }
26311195Ssam 
26411195Ssam /*
265*11207Ssam  * Issue a command to the adapter
26611195Ssam  */
26711195Ssam hystart(ui, cmd, count, ubaddr)
26811195Ssam 	struct uba_device *ui;
269*11207Ssam 	int cmd, count, ubaddr;
27011195Ssam {
27111195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
27211195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
27311195Ssam 
27411195Ssam #ifdef DEBUG
275*11207Ssam 	printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
276*11207Ssam 		ui->ui_unit, cmd, count, ubaddr);
27711195Ssam 	printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
278*11207Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
279*11207Ssam 		addr->hyd_wcr);
28011195Ssam #endif
281*11207Ssam 	if (((is->hy_flags & RQ_REISSUE) == 0) &&
282*11207Ssam 	  (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
28311195Ssam 		is->hy_savedstate = is->hy_state;
28411195Ssam 		is->hy_savedcmd = cmd;
28511195Ssam 		is->hy_savedcount = count;
28611195Ssam 		is->hy_savedaddr = ubaddr;
28711195Ssam 	}
28811195Ssam 	addr->hyd_bar = ubaddr & 0xffff;
289*11207Ssam 	addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);
29011195Ssam 	addr->hyd_dbuf = cmd;
29111195Ssam #ifdef PI13
29211195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN;
29311195Ssam #else
29411195Ssam 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE;
29511195Ssam #endif
29611195Ssam #ifdef DEBUG
29711195Ssam 	printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
298*11207Ssam 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
299*11207Ssam 		addr->hyd_wcr);
30011195Ssam #endif
30111195Ssam #ifdef HYLOG
30211195Ssam 	{
30311195Ssam 		struct {
304*11207Ssam 			u_char	hcmd;
305*11207Ssam 			u_char	hstate;
306*11207Ssam 			short	hcount;
30711195Ssam 		} hcl;
30811195Ssam 
30911195Ssam 		hcl.hcmd = cmd;
31011195Ssam 		hcl.hstate = is->hy_state;
31111195Ssam 		hcl.hcount = count;
31211195Ssam 		hylog(HYL_CMD, sizeof(hcl), (char *)&hcl);
31311195Ssam 	}
31411195Ssam #endif
31511195Ssam 	is->hy_ntime = 0;
316*11207Ssam }
31711195Ssam 
31811195Ssam int hyint_active = 0;		/* set during hy interrupt */
31911195Ssam /*
320*11207Ssam  * Hyperchannel interface interrupt.
32111195Ssam  *
32211195Ssam  * An interrupt can occur for many reasons.  Examine the status of
32311195Ssam  * the hyperchannel status bits to determine what to do next.
32411195Ssam  *
32511195Ssam  * If input error just drop packet.
32611195Ssam  * Otherwise purge input buffered data path and examine
32711195Ssam  * packet to determine type.  Othewise decapsulate
32811195Ssam  * packet based on type and pass to type specific higher-level
32911195Ssam  * input routine.
33011195Ssam  */
33111195Ssam hyint(unit)
33211195Ssam 	int unit;
33311195Ssam {
33411195Ssam 	register struct hy_softc *is = &hy_softc[unit];
33511195Ssam 	register struct uba_device *ui = hyinfo[unit];
336*11207Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
33711195Ssam 
338*11207Ssam 	if (hyint_active)
33911195Ssam 		panic("RECURSIVE HYPERCHANNEL INTERRUPT");
34011195Ssam 	hyint_active++;
34111195Ssam #ifdef DEBUG
34211195Ssam 	printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
34311195Ssam 		unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
34411195Ssam #endif
34511195Ssam #ifdef HYLOG
34611195Ssam logit:
34711195Ssam 	{
34811195Ssam 		struct {
349*11207Ssam 			u_char	hstate;
350*11207Ssam 			u_char	hflags;
351*11207Ssam 			short	hcsr;
352*11207Ssam 			short	hwcr;
35311195Ssam 		} hil;
35411195Ssam 		hil.hstate = is->hy_state;
35511195Ssam 		hil.hflags = is->hy_flags;
35611195Ssam 		hil.hcsr = addr->hyd_csr;
35711195Ssam 		hil.hwcr = addr->hyd_wcr;
35811195Ssam 		hylog(HYL_INT, sizeof(hil), (char *)&hil);
35911195Ssam 	}
36011195Ssam #endif
361*11207Ssam 	if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
36211195Ssam 		/*
363*11207Ssam 		 * Error bit set, some sort of error in the interface.
36411195Ssam 		 *
365*11207Ssam 		 * The adapter sets attn on command completion so that's not
366*11207Ssam 		 * a real error even though the interface considers it one.
36711195Ssam 		 */
36811195Ssam #ifdef DEBUG
369*11207Ssam 		if (hy_nodebug & 4)
370*11207Ssam 			hy_debug_flag = 1;
37111195Ssam #endif
372*11207Ssam 		printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n",
373*11207Ssam 			addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
374*11207Ssam 			addr->hyd_wcr);
375*11207Ssam 		if (addr->hyd_csr & S_NEX) {
37611195Ssam 			printf("hy%d: NEX - Non Existant Memory\n", unit);
37711195Ssam #ifdef PI13
37811195Ssam 			addr->hyd_csr |= S_NEX;  /* as per PI13 manual */
37911195Ssam #else
38011195Ssam 			addr->hyd_csr &= ~S_NEX;
38111195Ssam #endif
38211195Ssam 			hycancel(ui);
38311195Ssam #ifdef PI13
384*11207Ssam 		} else if (addr->hyd_csr & S_POWEROFF) {
385*11207Ssam 			printf("hy%d: Power Off bit set, trying to reset\n",
386*11207Ssam 				unit);
38711195Ssam 			addr->hyd_csr |= S_POWEROFF;
38811195Ssam 			DELAY(100);
389*11207Ssam 			if (addr->hyd_csr & S_POWEROFF) {
39011195Ssam 				if_down(&is->hy_if);
39111195Ssam 				is->hy_state = STARTUP;
392*11207Ssam 				printf(
393*11207Ssam 				  "hy%d: Power Off Error, network shutdown\n",
394*11207Ssam 				  unit);
39511195Ssam 			}
39611195Ssam #endif
39711195Ssam 		} else {
39811195Ssam 			printf("hy%d:  BAR overflow\n", unit);
39911195Ssam 			hycancel(ui);
40011195Ssam 		}
401*11207Ssam 	} else if (HYS_NORMAL(addr)) {
40211195Ssam 		/*
403*11207Ssam 		 * Normal interrupt, bump state machine unless in state
40411195Ssam 		 * waiting and no data present (assumed to be word count
405*11207Ssam 		 * zero interrupt or other hardware botch).
40611195Ssam 		 */
407*11207Ssam 		if (is->hy_state != WAITING || HYS_RECVDATA(addr))
40811195Ssam 			hyact(ui);
409*11207Ssam 	} else if (HYS_ABNORMAL(addr)) {
41011195Ssam 		/*
411*11207Ssam 		 * Abnormal termination.
41211195Ssam 		 * bump error counts, retry the last function
41311195Ssam 		 * 'MAXRETRY' times before kicking the bucket.
41411195Ssam 		 *
415*11207Ssam 		 * Don't reissue the cmd if in certain states, abnormal
416*11207Ssam 		 * on a reissued cmd or max retry exceeded.
41711195Ssam 		 */
41811195Ssam #ifdef HYLOG
41911195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
42011195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
42111195Ssam 			goto logit;
42211195Ssam 		}
42311195Ssam #endif
42411195Ssam #ifdef DEBUG
425*11207Ssam 		if (hy_nodebug & 4)
426*11207Ssam 			hy_debug_flag = 1;
42711195Ssam 		printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
42811195Ssam 			unit, hy_state_names[is->hy_state], is->hy_state);
429*11207Ssam 		printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n",
430*11207Ssam 			is->hy_flags, is->hy_ilen, is->hy_olen,
431*11207Ssam 			is->hy_lastwcr, is->hy_retry);
432*11207Ssam 		printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
433*11207Ssam 			is->hy_savedstate, is->hy_savedcount,
434*11207Ssam 			is->hy_savedaddr, is->hy_savedcmd);
43511195Ssam #endif
43611195Ssam #ifdef PI13
43711195Ssam 		addr->hyd_csr &= ~S_C;  /* clear the damned PI-13 */
43811195Ssam #endif
439*11207Ssam 		if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT)
44011195Ssam 			is->hy_if.if_oerrors++;
441*11207Ssam 		if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT)
44211195Ssam 			is->hy_if.if_ierrors++;
44311195Ssam 		if (is->hy_state == XMITDATASENT ||
44411195Ssam 		    is->hy_state == RECVSENT ||
44511195Ssam 		    is->hy_state == RECVDATASENT ||
446*11207Ssam 		    (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY)
44711195Ssam 			hycancel(ui);
448*11207Ssam 		else {
44911195Ssam #ifdef DEBUG
450*11207Ssam 			if (hy_nodebug & 2)
451*11207Ssam 				hy_debug_flag = 1;
45211195Ssam #endif
45311195Ssam 			is->hy_retry++;
45411195Ssam 			is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE;
45511195Ssam 			is->hy_state = IDLE;
45611195Ssam 			hyact(ui);
45711195Ssam 		}
45811195Ssam 	} else {
45911195Ssam 		/*
46011195Ssam 		 * Interrupt is neither normal, abnormal, or interface error.
46111195Ssam 		 * Ignore it. It's either stacked or a word count 0.
46211195Ssam 		 */
46311195Ssam #ifdef HYLOG
46411195Ssam 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
46511195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr;
46611195Ssam 			goto logit;
46711195Ssam 		}
46811195Ssam #endif
46911195Ssam #ifdef DEBUG
47011195Ssam 		printD("hy%d: possible stacked interrupt ignored\n", unit);
47111195Ssam #endif
47211195Ssam 	}
47311195Ssam #ifdef DEBUG
47411195Ssam 	printD("hy%d: hyint exit\n\n", unit);
47511195Ssam #endif
47611195Ssam 	hyint_active = 0;
47711195Ssam 
478*11207Ssam }
47911195Ssam 
48011195Ssam /*
48111195Ssam  * Encapsulate a packet of type family for the local net.
48211195Ssam  * Use trailer local net encapsulation if enough data in first
48311195Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
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
504*11207Ssam 	if (hy_nodebug & 8)
505*11207Ssam 		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
522*11207Ssam 		printD("hy%d: output to host %x, dhost %x\n",
523*11207Ssam 			ifp->if_unit, sin->sin_addr.s_addr, dhost);
52411195Ssam #endif
52511195Ssam 		/*
526*11207Ssam 		 * 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:
561*11207Ssam 		printf("hy%d: can't handle af%d\n", ifp->if_unit,
562*11207Ssam 			dst->sa_family);
56311195Ssam #ifdef DEBUG
564*11207Ssam 		if (hy_nodebug & 4)
565*11207Ssam 			hy_debug_flag = 1;
56611195Ssam #endif
56711195Ssam 		error = EAFNOSUPPORT;
56811195Ssam 		goto drop;
56911195Ssam 	}
57011195Ssam 
57111195Ssam 	/*
572*11207Ssam 	 * 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) {
579*11207Ssam 		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;
59611195Ssam 	hym->hym_hdr.hyh_from = htons(ifp->if_host[0]);
59711195Ssam 	hym->hym_hdr.hyh_param = loopback;
59811195Ssam #ifdef HYROUTE
599*11207Ssam 	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;
63011195Ssam 		hym->hym_hdr.hyh_to = htons(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 headerexists:
63911195Ssam 	if (hym->hym_mplen) {
64011195Ssam 		hym->hym_hdr.hyh_ctl |= H_ASSOC;
64111195Ssam #ifdef DEBUG
642*11207Ssam 		if (hy_nodebug & 16)
643*11207Ssam 			hy_debug_flag = 1;
64411195Ssam #endif
645*11207Ssam 	} else
646*11207Ssam 		hym->hym_hdr.hyh_ctl &= ~H_ASSOC;
64711195Ssam #ifdef DEBUG
648*11207Ssam 	printD("hy%d: output mplen=%x ctl=%x access=%x to=%x",
64911195Ssam 		ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl,
650*11207Ssam 		hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to);
651*11207Ssam 	printD(" (adapter %x) from=%x param=%x type=%x off=%x\n",
65211195Ssam 		hym->hym_hdr.hyh_to_adapter,
65311195Ssam 		hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param,
65411195Ssam 		hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off);
65511195Ssam #endif
65611195Ssam 	s = splimp();
65711195Ssam 	if (IF_QFULL(&ifp->if_snd)) {
65811195Ssam 		IF_DROP(&ifp->if_snd);
65911195Ssam 		error = ENOBUFS;
66011195Ssam 		splx(s);
66111195Ssam 		goto drop;
66211195Ssam 	}
66311195Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
66411195Ssam 	if (hy_softc[ifp->if_unit].hy_state == WAITING)
66511195Ssam 		hyact(hyinfo[ifp->if_unit]);
66611195Ssam 	splx(s);
667*11207Ssam 	return (0);
66811195Ssam notfound:
669*11207Ssam 	error = ENETUNREACH;			/* XXX */
67011195Ssam drop:
67111195Ssam 	m_freem(m);
672*11207Ssam 	return (error);
673*11207Ssam }
67411195Ssam 
67511195Ssam hyact(ui)
67611195Ssam 	register struct uba_device *ui;
67711195Ssam {
67811195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
67911195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
68011195Ssam 
68111195Ssam actloop:
68211195Ssam #ifdef DEBUG
683*11207Ssam 	printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
684*11207Ssam 		hy_state_names[is->hy_state]);
68511195Ssam #endif
68611195Ssam 	switch (is->hy_state) {
68711195Ssam 
68811195Ssam 	case STARTUP:
68911195Ssam 		goto endintr;
69011195Ssam 
69111195Ssam 	case IDLE: {
69211195Ssam 		register rq = is->hy_flags;
69311195Ssam 
69411195Ssam 		if (rq & RQ_STATUS) {
69511195Ssam 			is->hy_flags &= ~RQ_STATUS;
69611195Ssam 			is->hy_state = STATSENT;
697*11207Ssam 			hystart(ui, HYF_STATUS, sizeof (is->hy_status),
698*11207Ssam 				is->hy_ifuba.ifu_r.ifrw_info);
69911195Ssam 		} else if (rq & RQ_ENDOP) {
70011195Ssam 			is->hy_flags &= ~RQ_ENDOP;
70111195Ssam 			is->hy_state = ENDOPSENT;
70211195Ssam 			hystart(ui, HYF_END_OP, 0, 0);
70311195Ssam 		} else if (rq & RQ_STATISTICS) {
70411195Ssam 			is->hy_flags &= ~RQ_STATISTICS;
70511195Ssam 			is->hy_state = RSTATSENT;
706*11207Ssam 			hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
707*11207Ssam 				is->hy_ifuba.ifu_r.ifrw_info);
708*11207Ssam 		} else if (HYS_RECVDATA(addr)) {
70911195Ssam 			is->hy_state = RECVSENT;
71011195Ssam 			is->hy_retry = 0;
711*11207Ssam 			hystart(ui, HYF_INPUTMSG, MPSIZE,
712*11207Ssam 				is->hy_ifuba.ifu_r.ifrw_info);
71311195Ssam 		} else if (rq & RQ_REISSUE) {
71411195Ssam 			is->hy_flags &= ~RQ_REISSUE;
71511195Ssam 			is->hy_state = is->hy_savedstate;
71611195Ssam #ifdef DEBUG
717*11207Ssam 			printD("hy%d: reissue cmd=0x%x count=%d",
718*11207Ssam 			  ui->ui_unit, is->hy_savedcmd, is->hy_savedcount);
719*11207Ssam 			printD(" ubaddr=0x%x retry=%d\n",
720*11207Ssam 			  is->hy_savedaddr, is->hy_retry);
72111195Ssam #endif
722*11207Ssam 			hystart(ui, is->hy_savedcmd, is->hy_savedcount,
723*11207Ssam 				is->hy_savedaddr);
72411195Ssam 		} else {
72511195Ssam 			register struct mbuf *m;
72611195Ssam 
72711195Ssam 			IF_DEQUEUE(&is->hy_if.if_snd, m);
728*11207Ssam 			if (m != NULL) {
72911195Ssam 				register struct hym_hdr *hym;
73011195Ssam 				register int mplen;
73111195Ssam 				register int cmd;
73211195Ssam 
73311195Ssam 				is->hy_state = XMITSENT;
73411195Ssam 				is->hy_retry = 0;
73511195Ssam 				hym = mtod(m, struct hym_hdr *);
73611195Ssam #ifdef HYLOG
737*11207Ssam 				hylog(HYL_XMIT, sizeof(struct hym_hdr),
738*11207Ssam 					(char *)hym);
73911195Ssam #endif
74011195Ssam 				mplen = hym->hym_mplen;
741*11207Ssam 				if (hym->hym_hdr.hyh_to_adapter ==
742*11207Ssam 				  hym->hym_hdr.hyh_from_adapter)
743*11207Ssam 					cmd = HYF_XMITLOCMSG;
744*11207Ssam 				else
745*11207Ssam 					cmd = HYF_XMITMSG;
74611195Ssam #ifdef DEBUG
74711195Ssam 				printD("hy%d: hym_hdr = ", ui->ui_unit);
748*11207Ssam 				if (hy_debug_flag)
749*11207Ssam 					hyprintdata((char *)hym,
750*11207Ssam 					  sizeof (struct hym_hdr));
75111195Ssam #endif
75211195Ssam 				/*
753*11207Ssam 				 * Strip off the software part of
75411195Ssam 				 * the hyperchannel header
75511195Ssam 				 */
75611195Ssam 				m->m_off += sizeof(struct hym_data);
75711195Ssam 				m->m_len -= sizeof(struct hym_data);
75811195Ssam 				is->hy_olen = if_wubaput(&is->hy_ifuba, m);
75911195Ssam 				if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
760*11207Ssam 					UBAPURGE(is->hy_ifuba.ifu_uba,
761*11207Ssam 						is->hy_ifuba.ifu_w.ifrw_bdp);
76211195Ssam #ifdef DEBUG
763*11207Ssam 				printD(
764*11207Ssam 		"hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
76511195Ssam 					ui->ui_unit, mplen, is->hy_olen);
766*11207Ssam 				if (hy_debug_flag)
767*11207Ssam 					hyprintdata(
768*11207Ssam 					  is->hy_ifuba.ifu_w.ifrw_addr,
769*11207Ssam 					  is->hy_olen);
77011195Ssam #endif
771*11207Ssam 				hystart(ui, cmd,
772*11207Ssam 				   (mplen == 0) ? is->hy_olen : mplen,
773*11207Ssam 				   is->hy_ifuba.ifu_w.ifrw_info);
77411195Ssam 				if (mplen != 0)
77511195Ssam 					is->hy_flags |= RQ_XASSOC;
77611195Ssam 			} else if (rq & RQ_MARKDOWN) {
77711195Ssam 				is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
77811195Ssam 				is->hy_state = MARKPORT;
77911195Ssam 				is->hy_retry = 0;
78011195Ssam 				/*
781*11207Ssam 				 * Port number is taken from status data
78211195Ssam 				 */
783*11207Ssam 				hystart(ui,
784*11207Ssam 				  HYF_MARKP0 | (PORTNUM(&is->hy_status) << 2),
785*11207Ssam 				  0, 0);
78611195Ssam 			} else if (rq & RQ_MARKUP) {
78711195Ssam 				register struct ifnet *ifp = &is->hy_if;
788*11207Ssam 				register struct sockaddr_in *sin =
789*11207Ssam 				   (struct sockaddr_in *)&ifp->if_addr;
79011195Ssam 
791*11207Ssam 				is->hy_flags &= ~RQ_MARKUP;
79211195Ssam 				is->hy_retry = 0;
79311195Ssam 				/*
794*11207Ssam 				 * Fill in the Internet address
795*11207Ssam 				 * from the status buffer
79611195Ssam 				 */
797*11207Ssam 				printf(
798*11207Ssam 	"hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
79911195Ssam 					ui->ui_unit,
80011195Ssam 					is->hy_stat.hyc_uaddr,
80111195Ssam 					PORTNUM(&is->hy_status),
802*11207Ssam 					(is->hy_stat.hyc_atype[0]<<8) |
803*11207Ssam 						is->hy_stat.hyc_atype[1],
80411195Ssam 					is->hy_stat.hyc_atype[2]);
80511195Ssam 
806*11207Ssam 				ifp->if_host[0] =
807*11207Ssam 				  (is->hy_stat.hyc_uaddr << 8) |
808*11207Ssam 					PORTNUM(&is->hy_status);
80911195Ssam 				sin->sin_family = AF_INET;
810*11207Ssam 				sin->sin_addr =
811*11207Ssam 				   if_makeaddr(ifp->if_net, ifp->if_host[0]);
81211195Ssam 				ifp->if_flags |= IFF_UP;
81311195Ssam 				if_rtinit(ifp, RTF_UP);
81411195Ssam #ifdef HYLOG
81511195Ssam 				hylog(HYL_UP, 0, (char *)0);
81611195Ssam #endif
81711195Ssam 			} else {
81811195Ssam 				is->hy_state = WAITING;
81911195Ssam 				is->hy_retry = 0;
82011195Ssam 				hystart(ui, HYF_WAITFORMSG, 0, 0);
82111195Ssam 			}
82211195Ssam 		}
823*11207Ssam 		break;
82411195Ssam 	}
82511195Ssam 
82611195Ssam 	case STATSENT:
827*11207Ssam 		bcopy(is->hy_ifuba.ifu_r.ifrw_addr, &is->hy_status,
828*11207Ssam 		  sizeof (struct hy_status));
82911195Ssam #ifdef DEBUG
830*11207Ssam 		printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
831*11207Ssam 			ui->ui_unit, is->hy_status.hys_gen_status,
832*11207Ssam 			is->hy_status.hys_last_fcn,
833*11207Ssam 			is->hy_status.hys_resp_trunk,
834*11207Ssam 			is->hy_status.hys_status_trunk,
835*11207Ssam 			is->hy_status.hys_recd_resp,
836*11207Ssam 			is->hy_status.hys_error,
837*11207Ssam 			is->hy_status.hys_caddr,
838*11207Ssam 			is->hy_status.hys_pad);
83911195Ssam #endif
84011195Ssam 		is->hy_state = IDLE;
84111195Ssam #ifdef HYLOG
842*11207Ssam 		hylog(HYL_STATUS, sizeof (struct hy_status),
843*11207Ssam 			(char *)&is->hy_status);
84411195Ssam #endif
84511195Ssam #ifdef HYELOG
84611195Ssam 		{
84711195Ssam 			register int i;
84811195Ssam 
84911195Ssam 			i = is->hy_status.hys_error;
85011195Ssam 			if (i < HYE_MAX)
85111195Ssam 				i = HYE_MAX;
85211195Ssam 			switch (is->hy_status.hys_last_fcn) {
85311195Ssam 				case HYF_XMITLOCMSG:
85411195Ssam 					i += HYE_MAX+1;	/* fall through */
85511195Ssam 				case HYF_XMITLSTDATA:
85611195Ssam 					i += HYE_MAX+1;	/* fall through */
85711195Ssam 				case HYF_XMITMSG:
85811195Ssam 					i += HYE_MAX+1;
85911195Ssam 			}
86011195Ssam 			hy_elog[i]++;
86111195Ssam 		}
86211195Ssam #endif
86311195Ssam 		break;
86411195Ssam 
86511195Ssam 	case RSTATSENT: {
866*11207Ssam 		register struct hy_stat *p =
867*11207Ssam 			(struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
86811195Ssam 
86911195Ssam 		is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt);
87011195Ssam 		is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt);
87111195Ssam 		is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy);
87211195Ssam 		is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret);
87311195Ssam 		is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad);
87411195Ssam 		is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret);
87511195Ssam 		is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort);
87611195Ssam 		is->hy_stat.hyc_atype[0] = p->hyc_atype[0];
87711195Ssam 		is->hy_stat.hyc_atype[1] = p->hyc_atype[1];
87811195Ssam 		is->hy_stat.hyc_atype[2] = p->hyc_atype[2];
87911195Ssam 		is->hy_stat.hyc_uaddr = p->hyc_uaddr;
88011195Ssam #ifdef DEBUG
881*11207Ssam 		printD(
882*11207Ssam 	"hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n",
88311195Ssam 			ui->ui_unit,
88411195Ssam 			is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt,
88511195Ssam 			is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret,
88611195Ssam 			is->hy_stat.hyc_crcbad);
88711195Ssam 		printD("	mcret %d tdabort %d atype %x %x %x uaddr %x\n",
88811195Ssam 			is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort,
88911195Ssam 			is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
89011195Ssam 			is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
89111195Ssam #endif
89211195Ssam 		is->hy_state = IDLE;
89311195Ssam #ifdef HYLOG
894*11207Ssam 		hylog(HYL_STATISTICS, sizeof (struct hy_stat),
895*11207Ssam 			(char *)&is->hy_stat);
89611195Ssam #endif
89711195Ssam 		break;
89811195Ssam 	}
89911195Ssam 
90011195Ssam 	case CLEARSENT:
90111195Ssam 		is->hy_state = IDLE;
90211195Ssam 		break;
90311195Ssam 
90411195Ssam 	case ENDOPSENT:
90511195Ssam 		is->hy_state = IDLE;
90611195Ssam 		break;
90711195Ssam 
90811195Ssam 	case RECVSENT: {
909*11207Ssam 		register struct hy_hdr *hyh;
910*11207Ssam 		register unsigned len;
91111195Ssam 
912*11207Ssam 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
913*11207Ssam 			UBAPURGE(is->hy_ifuba.ifu_uba,
914*11207Ssam 				is->hy_ifuba.ifu_r.ifrw_bdp);
915*11207Ssam 		hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
916*11207Ssam 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
917*11207Ssam 		if (len > MPSIZE) {
918*11207Ssam 			printf("hy%d: RECVD MP > MPSIZE (%d)\n",
919*11207Ssam 				ui->ui_unit, len);
92011195Ssam #ifdef DEBUG
921*11207Ssam 			hy_debug_flag = 1;
922*11207Ssam 			printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
923*11207Ssam 				ui->ui_unit, addr->hyd_csr, HY_CSR_BITS,
924*11207Ssam 				addr->hyd_bar, addr->hyd_wcr);
92511195Ssam #endif
926*11207Ssam 		}
92711195Ssam #ifdef DEBUG
928*11207Ssam 		printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
929*11207Ssam 		if (hy_debug_flag)
930*11207Ssam 			hyprintdata((char *)hyh, len);
93111195Ssam #endif
932*11207Ssam 		if (hyh->hyh_ctl & H_ASSOC) {
933*11207Ssam 			is->hy_state = RECVDATASENT;
934*11207Ssam 			is->hy_ilen = len;
935*11207Ssam 			is->hy_retry = 0;
936*11207Ssam 			hystart(ui, HYF_INPUTDATA,
937*11207Ssam 			  HYMTU-len+sizeof (struct hy_hdr),
938*11207Ssam 			  is->hy_ifuba.ifu_r.ifrw_info + len);
939*11207Ssam 		} else {
940*11207Ssam 			hyrecvdata(ui, hyh, len);
941*11207Ssam 			is->hy_state = IDLE;
94211195Ssam 		}
943*11207Ssam 		break;
944*11207Ssam 	}
94511195Ssam 
94611195Ssam 	case RECVDATASENT: {
947*11207Ssam 		register struct hy_hdr *hyh;
948*11207Ssam 		register unsigned len;
94911195Ssam 
950*11207Ssam 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
951*11207Ssam 			UBAPURGE(is->hy_ifuba.ifu_uba,
952*11207Ssam 				is->hy_ifuba.ifu_r.ifrw_bdp);
953*11207Ssam 		hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
954*11207Ssam 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
95511195Ssam #ifdef DEBUG
956*11207Ssam 		printD("hy%d: recvd assoc data, len = %d, data = ",
957*11207Ssam 			ui->ui_unit, len);
958*11207Ssam 		if (hy_debug_flag)
959*11207Ssam 			hyprintdata((char *)hyh + is->hy_ilen, len);
96011195Ssam #endif
961*11207Ssam 		hyrecvdata(ui, hyh, len + is->hy_ilen);
962*11207Ssam 		is->hy_state = IDLE;
963*11207Ssam 		break;
964*11207Ssam 	}
96511195Ssam 
96611195Ssam 	case XMITSENT:
967*11207Ssam 		if (is->hy_flags & RQ_XASSOC) {
968*11207Ssam 			register unsigned len;
96911195Ssam 
970*11207Ssam 			is->hy_flags &= ~RQ_XASSOC;
971*11207Ssam 			is->hy_state = XMITDATASENT;
972*11207Ssam 			is->hy_retry = 0;
973*11207Ssam 			len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
974*11207Ssam 			if (len > is->hy_olen) {
975*11207Ssam 				printf(
976*11207Ssam 				"hy%d: xmit error - len > hy_olen [%d > %d]\n",
977*11207Ssam 				ui->ui_unit, len, is->hy_olen);
97811195Ssam #ifdef DEBUG
979*11207Ssam 				hy_debug_flag = 1;
98011195Ssam #endif
98111195Ssam 			}
982*11207Ssam 			hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
983*11207Ssam 				is->hy_ifuba.ifu_w.ifrw_info + len);
984*11207Ssam 			break;
985*11207Ssam 		}
986*11207Ssam 		/* fall through to ... */
98711195Ssam 
98811195Ssam 	case XMITDATASENT:
989*11207Ssam 		hyxmitdata(ui);
990*11207Ssam 		is->hy_state = IDLE;
991*11207Ssam 		break;
99211195Ssam 
99311195Ssam 	case WAITING:	/* wait for message complete or output requested */
994*11207Ssam 		if (HYS_RECVDATA(addr))
99511195Ssam 			is->hy_state = IDLE;
99611195Ssam 		else {
99711195Ssam 			is->hy_state = CLEARSENT;
99811195Ssam 			is->hy_retry = 0;
99911195Ssam 			hystart(ui, HYF_CLRWFMSG, 0, 0);
100011195Ssam 		}
100111195Ssam 		break;
100211195Ssam 
100311195Ssam 	case MARKPORT:
100411195Ssam 		is->hy_state = STARTUP;
100511195Ssam 		is->hy_if.if_flags &= ~IFF_UP;
100611195Ssam 		goto endintr;
100711195Ssam 
100811195Ssam 	default:
1009*11207Ssam 		printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
1010*11207Ssam 			ui->ui_unit, is->hy_state);
101111195Ssam 		panic("HYPERCHANNEL IN INVALID STATE");
101211195Ssam 		/*NOTREACHED*/
1013*11207Ssam 	}
101411195Ssam 	if (is->hy_state == IDLE)
101511195Ssam 		goto actloop;
101611195Ssam endintr:
101711195Ssam #ifdef DEBUG
1018*11207Ssam 	printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit,
1019*11207Ssam 		hy_state_names[is->hy_state]);
102011195Ssam #endif
1021*11207Ssam 	return (0);
1022*11207Ssam }
102311195Ssam 
102411195Ssam /*
102511195Ssam  * Called from device interrupt when recieving data.
102611195Ssam  * Examine packet to determine type.  Decapsulate packet
102711195Ssam  * based on type and pass to type specific higher-level
102811195Ssam  * input routine.
102911195Ssam  */
103011195Ssam hyrecvdata(ui, hyh0, len)
103111195Ssam 	struct uba_device *ui;
103211195Ssam 	struct hy_hdr *hyh0;
103311195Ssam 	int len;
103411195Ssam {
103511195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
103611195Ssam 	register struct hy_hdr *hyh = hyh0;
103711195Ssam     	struct mbuf *m;
103811195Ssam 	register struct ifqueue *inq;
103911195Ssam 
104011195Ssam 	is->hy_if.if_ipackets++;
104111195Ssam #ifdef DEBUG
1042*11207Ssam 	printD("hy%d: recieved packet, len = %d (actual %d)\n",
1043*11207Ssam 		ui->ui_unit, len,
1044*11207Ssam 		len - (hyh->hyh_off + sizeof (struct hy_hdr)));
104511195Ssam #endif
104611195Ssam #ifdef HYLOG
104711195Ssam 	{
104811195Ssam 		struct {
104911195Ssam 			short hlen;
105011195Ssam 			struct hy_hdr hhdr;
105111195Ssam 		} hh;
105211195Ssam 		hh.hlen = len;
105311195Ssam 		hh.hhdr = *hyh;
105411195Ssam 		hylog(HYL_RECV, sizeof(hh), (char *)&hh);
105511195Ssam 	}
105611195Ssam #endif
105711195Ssam 	if (len > HYMTU + MPSIZE || len == 0)
105811195Ssam 		return;			/* sanity */
105911195Ssam 	/*
106011195Ssam 	 * Pull packet off interface.
106111195Ssam 	 */
106211195Ssam 	m = if_rubaget(&is->hy_ifuba, len, 0);
1063*11207Ssam 	if (m == NULL)
106411195Ssam 		return;
106511195Ssam 	switch (hyh->hyh_type) {
106611195Ssam 
106711195Ssam #ifdef INET
106811195Ssam 	case HYLINK_IP:
106911195Ssam 		/*
1070*11207Ssam 		 * Strip the variable portion of the hyperchannel header
1071*11207Ssam 		 * (fixed portion stripped in if_rubaget).
107211195Ssam 		 */
107311195Ssam 		m->m_len -= hyh->hyh_off;
107411195Ssam 		m->m_off += hyh->hyh_off;
107511195Ssam 		schednetisr(NETISR_IP);
107611195Ssam 		inq = &ipintrq;
107711195Ssam 		break;
107811195Ssam #endif
107911195Ssam 	default:
108011195Ssam 		m_freem(m);
108111195Ssam 		return;
108211195Ssam 	}
108311195Ssam 	if (IF_QFULL(inq)) {
108411195Ssam 		IF_DROP(inq);
108511195Ssam 		m_freem(m);
108611195Ssam 	} else
108711195Ssam 		IF_ENQUEUE(inq, m);
1088*11207Ssam }
108911195Ssam 
109011195Ssam /*
1091*11207Ssam  * Transmit done, release resources, bump counters.
109211195Ssam  */
109311195Ssam hyxmitdata(ui)
109411195Ssam 	struct uba_device *ui;
109511195Ssam {
109611195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
109711195Ssam 
109811195Ssam 	is->hy_if.if_opackets++;
1099*11207Ssam 	if (is->hy_ifuba.ifu_xtofree) {
110011195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
110111195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
110211195Ssam 	}
1103*11207Ssam }
110411195Ssam 
110511195Ssam hycancel(ui)
110611195Ssam 	register struct uba_device *ui;
110711195Ssam {
110811195Ssam 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
110911195Ssam 
1110*11207Ssam 	if (is->hy_ifuba.ifu_xtofree) {
111111195Ssam 		m_freem(is->hy_ifuba.ifu_xtofree);
111211195Ssam 		is->hy_ifuba.ifu_xtofree = 0;
111311195Ssam 	}
111411195Ssam #ifdef DEBUG
1115*11207Ssam 	if (hy_nodebug & 1)
1116*11207Ssam 		hy_debug_flag = 1;
111711195Ssam #endif
111811195Ssam #ifdef DEBUG
111911195Ssam 	printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
112011195Ssam 		ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
112111195Ssam 		is->hy_savedcount, is->hy_savedaddr);
1122*11207Ssam 	printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n",
1123*11207Ssam 		is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr,
1124*11207Ssam 		is->hy_retry);
1125*11207Ssam 	printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
1126*11207Ssam 		is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr,
1127*11207Ssam 		is->hy_savedcmd);
112811195Ssam #endif
112911195Ssam 	is->hy_state = IDLE;
113011195Ssam 	is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
113111195Ssam 	hyact(ui);
1132*11207Ssam }
113311195Ssam 
113411195Ssam #ifdef DEBUG
113511195Ssam hyprintdata(cp, len)
113611195Ssam 	register char *cp;
113711195Ssam 	register int len;
113811195Ssam {
113911195Ssam 	register int count = 16;
114011195Ssam 	register char *fmt;
114111195Ssam 	static char regfmt[] = "\n\t %x";
114211195Ssam 
114311195Ssam 	fmt = &regfmt[2];
114411195Ssam 	while (--len >= 0) {
114511195Ssam 		printL(fmt, *cp++ & 0xff);
114611195Ssam 		fmt = &regfmt[2];
114711195Ssam 		if (--count <= 0) {
114811195Ssam 			fmt = &regfmt[0];
114911195Ssam 			count = 16;
115011195Ssam 		}
115111195Ssam 	}
115211195Ssam 	printL("\n");
115311195Ssam }
115411195Ssam #endif
115511195Ssam 
115611195Ssam hywatch(unit)
115711195Ssam int unit;
115811195Ssam {
115911195Ssam 	register struct hy_softc *is = &hy_softc[unit];
116011195Ssam 	register struct uba_device *ui = hyinfo[unit];
116111195Ssam 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
116211195Ssam 	int s;
116311195Ssam 
116411195Ssam 	s = splimp();
116511195Ssam 	is->hy_if.if_timer = SCANINTERVAL;
1166*11207Ssam 	if (is->hy_ntime > 2 && is->hy_state != WAITING &&
1167*11207Ssam 	  is->hy_state != STARTUP && is->hy_state != IDLE) {
116811195Ssam 		printf("hy%d: watchdog timer expired\n", unit);
116911195Ssam 		hycancel(ui);
117011195Ssam 	}
117111195Ssam #ifdef PI13
117211195Ssam 	if ((addr->hyd_csr & S_POWEROFF) != 0) {
117311195Ssam 		addr->hyd_csr |= S_POWEROFF;
117411195Ssam 		DELAY(100);
117511195Ssam 		if ((addr->hyd_csr & S_POWEROFF) == 0) {
117611195Ssam 			printf("hy%d: adapter power restored\n", unit);
117711195Ssam 			is->hy_state = IDLE;
1178*11207Ssam 			is->hy_flags |=
1179*11207Ssam 			  (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
118011195Ssam 			hyact(ui);
118111195Ssam 		}
118211195Ssam 	}
118311195Ssam #endif
118411195Ssam 	splx(s);
118511195Ssam }
118611195Ssam 
118711195Ssam #ifdef HYLOG
118811195Ssam hylog(code, len, ptr)
118911195Ssam 	int code;
119011195Ssam 	int len;
119111195Ssam 	char *ptr;
119211195Ssam {
119311195Ssam 	register unsigned char *p;
119411195Ssam 	int s;
119511195Ssam 
119611195Ssam 	s = splimp();
119711195Ssam 	if (hy_log.hyl_self != &hy_log) {
119811195Ssam 		hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
119911195Ssam 		hy_log.hyl_ptr = &hy_log.hyl_buf[0];
120011195Ssam 		hy_log.hyl_self = &hy_log;
120111195Ssam 		hy_log.hyl_enable = HYL_DISABLED;
120211195Ssam 		hy_log.hyl_onerr = HYL_CATCH1;
120311195Ssam 	}
1204*11207Ssam 	if (hy_log.hyl_enable == HYL_DISABLED ||
1205*11207Ssam 	  hy_log.hyl_enable == HYL_CAUGHT1 ||
1206*11207Ssam 	  hy_log.hyl_enable == HYL_CAUGHTSTATUS ||
1207*11207Ssam 	  (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS))
1208*11207Ssam 		goto out;
120911195Ssam 	p = hy_log.hyl_ptr;
121011195Ssam 	if (p + len + 2 >= hy_log.hyl_eptr) {
121111195Ssam 		bzero(p, hy_log.hyl_eptr - p);
121211195Ssam 		p = &hy_log.hyl_buf[0];
121311195Ssam 		if (hy_log.hyl_enable == HYL_CATCH1) {
121411195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1;
121511195Ssam 			goto out;
121611195Ssam 		}
121711195Ssam 		if (hy_log.hyl_enable == HYL_CATCHSTATUS) {
121811195Ssam 			hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS;
121911195Ssam 			goto out;
122011195Ssam 		}
122111195Ssam 	}
122211195Ssam 	*p++ = code;
122311195Ssam 	*p++ = len;
122411195Ssam 	bcopy(ptr, p, len);
122511195Ssam 	hy_log.hyl_ptr = p + len;
122611195Ssam out:
122711195Ssam 	splx(s);
122811195Ssam }
122911195Ssam #endif
123011195Ssam 
1231*11207Ssam hyioctl(dev, cmd, data, flag)
1232*11207Ssam 	dev_t dev;
1233*11207Ssam 	int cmd;
1234*11207Ssam 	caddr_t	data;
1235*11207Ssam 	int flag;
123611195Ssam {
1237*11207Ssam 	int s = splimp(), error = 0;
123811195Ssam 
123911195Ssam 	if (minor(dev) >= NHY) {
1240*11207Ssam 		error = ENXIO;
1241*11207Ssam 		goto bad;
124211195Ssam 	}
124311195Ssam 	switch(cmd) {
124411195Ssam 
124511195Ssam 	case HYSETROUTE:
1246*11207Ssam 		if (!suser()) {
1247*11207Ssam 			error = EPERM;
1248*11207Ssam 			goto bad;
124911195Ssam 		}
1250*11207Ssam 		hy_route[minor(dev)] = *(struct hyroute *)data;
1251*11207Ssam 		hy_route[minor(dev)].hyr_lasttime = time;
125211195Ssam 		break;
125311195Ssam 
125411195Ssam 	case HYGETROUTE:
1255*11207Ssam 		*(struct hyroute *)data = hy_route[minor(dev)];
125611195Ssam 		break;
125711195Ssam 
125811195Ssam 	default:
1259*11207Ssam 		error = ENXIO;
126011195Ssam 		break;
126111195Ssam 	}
1262*11207Ssam bad:
126311195Ssam 	splx(s);
1264*11207Ssam 	return (error);
126511195Ssam }
1266*11207Ssam #endif
1267