xref: /csrg-svn/sys/vax/if/if_hdh.c (revision 25461)
1*25461Skarels /*	@(#)if_hdh.c	6.2 (Berkeley) 11/11/85 */
224888Skarels 
324888Skarels 
424888Skarels /************************************************************************\
524888Skarels 
624888Skarels      ________________________________________________________
724888Skarels     /                                                        \
824888Skarels    |          AAA          CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
924888Skarels    |         AAAAA        CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
1024888Skarels    |        AAAAAAA       CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
1124888Skarels    |       AAAA AAAA      CCCC              CCCC              |
1224888Skarels    |      AAAA   AAAA     CCCC              CCCC              |
1324888Skarels    |     AAAA     AAAA    CCCC              CCCC              |
1424888Skarels    |    AAAA       AAAA   CCCC              CCCC              |
1524888Skarels    |   AAAA  AAAAAAAAAAA  CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC |
1624888Skarels    |  AAAA    AAAAAAAAAAA CCCCCCCCCCCCCCCC  CCCCCCCCCCCCCCCC  |
1724888Skarels    | AAAA      AAAAAAAAA   CCCCCCCCCCCCCC    CCCCCCCCCCCCCC   |
1824888Skarels     \________________________________________________________/
1924888Skarels 
2024888Skarels 	Copyright (c) 1984 by Advanced Computer Communications
2124888Skarels 	720 Santa Barbara Street, Santa Barbara, California  93101
2224888Skarels 	(805) 963-9431
2324888Skarels 
2424888Skarels 	This software may be duplicated and used on systems
2524888Skarels 	which are licensed to run U.C. Berkeley versions of
2624888Skarels 	the UNIX operating system.  Any duplication of any
2724888Skarels 	part of this software must include a copy of ACC's
2824888Skarels 	copyright notice.
2924888Skarels 
3024888Skarels 
3124888Skarels File:
3224888Skarels 		if_hdh.c
3324888Skarels 
3424888Skarels Author:
3524888Skarels 		Art Berggreen
3624888Skarels 
3724888Skarels Project:
3824888Skarels 		4.2BSD HDH
3924888Skarels 
4024888Skarels Function:
4124888Skarels 		Device specific driver for IF-11/HDH under 4.2BSD
4224888Skarels     		networking code.
4324888Skarels 
4424888Skarels Revision History:
4524888Skarels 		31-Aug-1984: V1.0 - First Implementation. A.B.
4624888Skarels 		 6-Nov-1984: V1.1 - Supress extra "LINE DOWN" msgs. A.B.
4724888Skarels 		13-Jan-1984: V1.2 - Add conditionals for TWG. A.B.
4824888Skarels 
4924888Skarels \************************************************************************/
5024888Skarels 
5124888Skarels 
5224888Skarels 
5324888Skarels 
5424888Skarels /* $Header$ */
5524888Skarels 
5624888Skarels #include "hdh.h"
5724888Skarels #ifdef NHDH > 0
5824888Skarels 
5924888Skarels /*
6024888Skarels  *
6124888Skarels  * ACC IF-11/HDH interface
6224888Skarels  *
6324888Skarels  */
6424888Skarels 
6524888Skarels #include "../machine/pte.h"
6624888Skarels 
67*25461Skarels #include "param.h"
68*25461Skarels #include "systm.h"
69*25461Skarels #include "mbuf.h"
70*25461Skarels #include "buf.h"
71*25461Skarels #include "protosw.h"
72*25461Skarels #include "socket.h"
73*25461Skarels #include "vmmac.h"
7424888Skarels 
7524888Skarels #include "../net/if.h"
7624888Skarels #include "../netimp/if_imp.h"
7724888Skarels 
7824888Skarels #include "../vax/cpu.h"
7924888Skarels #include "../vax/mtpr.h"
8024888Skarels #include "../vaxuba/ubareg.h"
8124888Skarels #include "../vaxuba/ubavar.h"
8224888Skarels 
83*25461Skarels #include "if_hdhreg.h"
84*25461Skarels #include "if_uba.h"
85*25461Skarels 
8624888Skarels int     hdhprobe(), hdhattach(), hdhrint(), hdhxint();
8724888Skarels struct  uba_device *hdhinfo[NHDH];
8824888Skarels u_short hdhstd[] = { 0 };
8924888Skarels struct  uba_driver hdhdriver =
9024888Skarels 	{ hdhprobe, 0, hdhattach, 0, hdhstd, "hdh", hdhinfo };
9124888Skarels 
9224888Skarels #define	HDHUNIT(x)	minor(x)
9324888Skarels 
9424888Skarels int	hdhinit(), hdhstart(), hdhreset();
9524888Skarels 
9624888Skarels /*
9724888Skarels  * "Lower half" of IMP interface driver.
9824888Skarels  *
9924888Skarels  * Each IMP interface is handled by a common module which handles
10024888Skarels  * the IMP-host protocol and a hardware driver which manages the
10124888Skarels  * hardware specific details of talking with the IMP.
10224888Skarels  *
10324888Skarels  * The hardware portion of the IMP driver handles DMA and related
10424888Skarels  * management of UNIBUS resources.  The IMP protocol module interprets
10524888Skarels  * contents of these messages and "controls" the actions of the
10624888Skarels  * hardware module during IMP resets, but not, for instance, during
10724888Skarels  * UNIBUS resets.
10824888Skarels  *
10924888Skarels  * The two modules are coupled at "attach time", and ever after,
11024888Skarels  * through the imp interface structure.  Higher level protocols,
11124888Skarels  * e.g. IP, interact with the IMP driver, rather than the HDH.
11224888Skarels  */
11324888Skarels 
11424888Skarels #define NHDHCH	2		/* no. of FDX channels for HDH */
11524888Skarels #define SUPR	0		/* supervisor channel */
11624888Skarels #define	DATA	1		/* data channel */
11724888Skarels #define HDHSUPR	0		/* supervisor read */
11824888Skarels #define HDHSUPW	1		/* supervisor write */
11924888Skarels #define HDHDATR	2		/* data read */
12024888Skarels #define HDHDATW	3		/* data write */
12124888Skarels 
12224888Skarels #define HDH_UP		2	/* HDH protocol is up */
12324888Skarels #define HDH_STARTED	1	/* HDH has been initialized */
12424888Skarels 
12524888Skarels #define HCBUSY	1		/* HDH HDX channel busy flag */
12624888Skarels 
12724888Skarels /*
12824888Skarels /* The IF-11/HDH has four independent dath flow channels between the
12924888Skarels /* front-end and the host.  Two are used for reading and writing
13024888Skarels /* control messages and two are used for data flow.  Each IF-11/HDH
13124888Skarels /* has a device dependent data structure (hdh_softc) which contains
13224888Skarels /* an array of four channel dependent structures (hdh_chan) to maintain
13324888Skarels /* the context of each channel.  Channel structures can be linked into
13424888Skarels /* a queue of I/O requests pending for the hardware interface.
13524888Skarels /* UNIBUS mapping resources are allocated for each channel pair.
13624888Skarels */
13724888Skarels 
13824888Skarels struct	hdh_chan {		/* HDH HDX channel structure */
13924888Skarels 	struct hdh_chan	*hc_next;	/* link for Start I/O queuing */
14024888Skarels 	char		hc_chan;	/* HDX chan number */
14124888Skarels 	char		hc_adx;		/* extended UNIBUS address bits */
14224888Skarels 	short		hc_addr;	/* lower UNIBUS address bits */
14324888Skarels 	short		hc_cnt;		/* byte count */
14424888Skarels 	char		hc_func;	/* UMC I/O function */
14524888Skarels 	char		hc_sbfc;	/* UMC I/O subfunction */
14624888Skarels 	short		hc_flags;	/* status flags */
14724888Skarels };
14824888Skarels 
14924888Skarels struct	hdh_sioq {		/* Start I/O queue head structure */
15024888Skarels 	struct hdh_chan *sioq_head;	/* pointer to queue head */
15124888Skarels 	struct hdh_chan *sioq_tail;	/* pointer to queue tail */
15224888Skarels };
15324888Skarels 
15424888Skarels struct	hdh_softc {		/* HDH device dependent structure */
15524888Skarels 	struct ifnet	*hdh_if;	/* pointer to IMP's ifnet struct */
15624888Skarels 	struct impcb	*hdh_ic;	/* data structure shared with IMP */
15724888Skarels 	struct ifuba	hdh_ifuba[NHDHCH]; /* UNIBUS resources */
15824888Skarels 	struct hdh_chan hdh_chan[2*NHDHCH]; /* HDX HDH channels */
15924888Skarels 	struct hdh_sioq hdh_sioq;	/* start i/o queue */
16024888Skarels 	short		hdh_flags;	/* various status conditions */
16124888Skarels } hdh_softc[NHDH];
16224888Skarels 
16324888Skarels 
16424888Skarels /*
16524888Skarels  * Normally, code goes here to cause the device to interrupt to determine its
16624888Skarels  * interrupt vector.  However, since the UMC must be told its vector in order
16724888Skarels  * to interrupt, we allocate and return an unused vector and initialize the
16824888Skarels  * UMC.
16924888Skarels  */
17024888Skarels hdhprobe(reg)
17124888Skarels caddr_t reg;
17224888Skarels {
17324888Skarels 	register int br, cvec;
17424888Skarels 	struct hdhregs *addr = (struct hdhregs *)reg;
17524888Skarels #ifdef lint
17624888Skarels 	br = 0; cvec = br; br = cvec;
17724888Skarels #endif
17824888Skarels 
17924888Skarels 	br = 0x15;			/* priority 21 (5 on UNIBUS) */
18024888Skarels 
18124888Skarels #ifdef HDHDEBUG
18224888Skarels 	cvec = 0270;			/* use constant for now ... */
18324888Skarels #else
18424888Skarels 
18524888Skarels #ifdef VAXVMS				/* if VMS */
18624888Skarels 	cvec = 0270;			/*   we can't allocate vectors */
18724888Skarels #else
18824888Skarels 	cvec = (uba_hd[numuba].uh_lastiv -= 4);  /* available vector */
18924888Skarels #endif VAXVMS
19024888Skarels 
19124888Skarels #endif HDHDEBUG
19224888Skarels 
19324888Skarels 	addr->ioini = (char) 0;		/* init UMC regs */
19424888Skarels 	addr->staack = (char) 0;	/*   pass vector */
19524888Skarels 	addr->ionmi = (char) 0;		/*     and kick UMC */
19624888Skarels 	addr->iochn = (char) (cvec >> 2);
19724888Skarels 	addr->csr = (short) HDH_RST;
19824888Skarels 	addr->csr = (short) (HDH_IEN|HDH_DMA|HDH_WRT); /* set enables */
19924888Skarels 	DELAY(5000);			/* give the UMC some time */
20024888Skarels 	return(1);
20124888Skarels }
20224888Skarels 
20324888Skarels /*
20424888Skarels  * Call the IMP module to allow it to set up its internal
20524888Skarels  * state, then tie the two modules together by setting up
20624888Skarels  * the back pointers to common data structures.
20724888Skarels  */
20824888Skarels hdhattach(ui)
20924888Skarels 	struct uba_device *ui;
21024888Skarels {
21124888Skarels 	register struct hdh_softc *sc = &hdh_softc[ui->ui_unit];
21224888Skarels 	register struct impcb *ip;
21324888Skarels 	struct ifimpcb {
21424888Skarels 		struct	ifnet ifimp_if;
21524888Skarels 		struct	impcb ifimp_impcb;
21624888Skarels 	} *ifimp;
21724888Skarels 
21824888Skarels 	if ((ifimp = (struct ifimpcb *)impattach(ui, hdhreset)) == 0)
219*25461Skarels 		return;;
22024888Skarels 	sc->hdh_if = &ifimp->ifimp_if;
22124888Skarels 	ip = &ifimp->ifimp_impcb;
22224888Skarels 	sc->hdh_ic = ip;
22324888Skarels 	ip->ic_init = hdhinit;
22424888Skarels 	ip->ic_start = hdhstart;
22524888Skarels 	sc->hdh_ifuba[ui->ui_unit].ifu_flags = UBA_CANTWAIT;
22624888Skarels }
22724888Skarels 
22824888Skarels /*
22924888Skarels  * Reset interface after UNIBUS reset.
23024888Skarels  */
23124888Skarels hdhreset(unit, uban)
23224888Skarels int unit, uban;
23324888Skarels {
23424888Skarels 	register struct uba_device *ui = hdhinfo[unit];
23524888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
23624888Skarels 
23724888Skarels #ifdef HDHDEBUG
23824888Skarels 	printf("HDH RESET\n");
23924888Skarels #endif HDHDEBUG
24024888Skarels 
24124888Skarels 	if ((unit >= NHDH) || (ui == 0) || (ui->ui_alive == 0)
24224888Skarels 	    || (ui->ui_ubanum != uban))
24324888Skarels 		return;
24424888Skarels 	printf(" hdh%d", unit);
245*25461Skarels 	sc->hdh_if->if_flags &= ~IFF_RUNNING;
246*25461Skarels 	sc->hdh_flags = 0;
24724888Skarels 	(*sc->hdh_if->if_init)(unit);
24824888Skarels }
24924888Skarels 
25024888Skarels /*
25124888Skarels  * Initialize the imp interface.
25224888Skarels  */
25324888Skarels 
25424888Skarels static char init_blk[] =
25524888Skarels     {
25624888Skarels 	HDHINIT,		/* SYSINIT opcode			*/
25724888Skarels 	HDHRQUP & 0xff,		/* control code (LSB)			*/
25824888Skarels 	(HDHRQUP>>8) & 0xff,	/* control code (MSB)			*/
25924888Skarels 	10,			/* command extension len		*/
26024888Skarels 	0,			/* loopback mode (off)			*/
26124888Skarels 	3,			/* our address (3=DTE)			*/
26224888Skarels 	1,			/* their address (1=DCE)		*/
26324888Skarels 	3,			/* frame ack t1 timeout			*/
26424888Skarels 	3,			/* poll ack timeout			*/
26524888Skarels 	30,			/* adm wait timeout			*/
26624888Skarels 	3,			/* rej wait timeout			*/
26724888Skarels 	10,			/* max retries				*/
26824888Skarels 	3,			/* watchdog timeout			*/
26924888Skarels 	0xaa			/* baud rate (0xaa=38.4KB)		*/
27024888Skarels 				/*   (output on RS-232 pin 24,		*/
27124888Skarels 				/*    send/receive timing is always	*/
27224888Skarels 				/*    taken from pins 15/17)		*/
27324888Skarels     };
27424888Skarels 
27524888Skarels hdhinit(unit)
27624888Skarels int unit;
27724888Skarels {
27824888Skarels 	register struct hdh_softc *sc;
27924888Skarels 	register struct hdhregs *addr;
28024888Skarels 	register struct uba_device *ui;
28124888Skarels 	register struct umc_chan *up;
28224888Skarels 	register struct mbuf *m, *n;
28324888Skarels 	int i, s, ubano;
28424888Skarels 
28524888Skarels #ifdef HDHDEBUG
28624888Skarels 	printf("HDH INIT\n");
28724888Skarels #endif HDHDEBUG
28824888Skarels 
28924888Skarels 	if (unit >= NHDH || (ui = hdhinfo[unit]) == NULL
29024888Skarels 	    || ui->ui_alive == 0) {
29124888Skarels 		printf("hdh%d: not alive\n", unit);
29224888Skarels 		return(0);
29324888Skarels 	}
29424888Skarels 	addr = (struct hdhregs *)ui->ui_addr;
29524888Skarels 	sc = &hdh_softc[unit];
29624888Skarels 
297*25461Skarels 	if (sc->hdh_flags & HDH_STARTED)
29824888Skarels 		return(1);
29924888Skarels 
30024888Skarels 	/*
30124888Skarels 	 * Alloc uba resources
30224888Skarels 	 */
30324888Skarels 	for(i=0;i<NHDHCH;i++) {
30424888Skarels 		if (if_ubainit(&sc->hdh_ifuba[i], ui->ui_ubanum, 0,
30524888Skarels 		    (int)btoc(IMPMTU)) == 0) {
30624888Skarels 			printf("hdh%d: cannot get chan %d uba resources\n",
30724888Skarels 				unit, i);
30824888Skarels 			ui->ui_alive = 0;
30924888Skarels 			return(0);
31024888Skarels 		}
31124888Skarels 	}
31224888Skarels 
313*25461Skarels 	sc->hdh_if->if_flags |= IFF_RUNNING;
31424888Skarels 	sc->hdh_flags = HDH_STARTED;
31524888Skarels 
31624888Skarels 	/*
31724888Skarels 	 * hang a supervisor read (for line status)
31824888Skarels 	 */
31924888Skarels 	hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB);
32024888Skarels 
32124888Skarels 	/*
32224888Skarels 	 * hang a data read
32324888Skarels 	 */
32424888Skarels 	hdh_iorq(unit, HDHDATR, IMPMTU, HDHRDB+HDHSTR);
32524888Skarels 
32624888Skarels 	/*
32724888Skarels 	 * bring up line to IMP
32824888Skarels 	 */
32924888Skarels 
33024888Skarels 	snd_supr(unit, init_blk, sizeof(init_blk));
33124888Skarels 
33224888Skarels 	return(1);
33324888Skarels }
33424888Skarels 
33524888Skarels /*
33624888Skarels  * Start an output operation on an mbuf.
33724888Skarels  */
33824888Skarels hdhstart(dev)
33924888Skarels dev_t dev;
34024888Skarels {
34124888Skarels 	int unit = HDHUNIT(dev);
34224888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
34324888Skarels 	register struct mbuf *m;
34424888Skarels         int len;
34524888Skarels 
34624888Skarels 	/*
34724888Skarels 	 * If output isn't active, attempt to
34824888Skarels 	 * start sending a new packet.
34924888Skarels 	 */
35024888Skarels 
35124888Skarels 	if (sc->hdh_ic->ic_oactive) {
35224888Skarels 		printf("hdh%d: start on active unit\n", unit);
35324888Skarels 		return;
35424888Skarels 	}
35524888Skarels 
35624888Skarels 	if ((sc->hdh_flags & HDH_UP) == 0) {
35724888Skarels 		sc->hdh_ic->ic_oactive = 0;	/* Link not up, can't xmit */
35824888Skarels 		return;
35924888Skarels 	}
36024888Skarels 
36124888Skarels 	IF_DEQUEUE(&sc->hdh_if->if_snd, m);
36224888Skarels 	if (m == 0) {
36324888Skarels 		sc->hdh_ic->ic_oactive = 0;
36424888Skarels 		return;
36524888Skarels 	}
36624888Skarels 
36724888Skarels 	len = if_wubaput(&sc->hdh_ifuba[DATA], m);	/* copy data to mapped mem */
36824888Skarels 	sc->hdh_ic->ic_oactive = 1;
36924888Skarels 
37024888Skarels 	hdh_iorq(unit, HDHDATW, len, HDHWRT+HDHEOS);
37124888Skarels }
37224888Skarels 
37324888Skarels /*
37424888Skarels  * Start i/o operation on a UMC logical channel
37524888Skarels  */
37624888Skarels hdh_iorq(unit, lcn, len, func)
37724888Skarels int unit, lcn, len, func;
37824888Skarels {
37924888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
38024888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
38124888Skarels 	register int info, s;
38224888Skarels 
38324888Skarels 	/*
38424888Skarels 	 * If channel is busy (shouldn't be), drop.
38524888Skarels 	 */
38624888Skarels 	if  (hc->hc_flags & HCBUSY) {
38724888Skarels 		printf("hdh%d: channel busy lcn=%d\n", unit, lcn);
38824888Skarels 		return;
38924888Skarels 	}
39024888Skarels 
39124888Skarels  	/* get appropriate UNIBUS mapping info */
39224888Skarels 
39324888Skarels 	if (lcn & 1)		/* read or write? */
39424888Skarels 		info = sc->hdh_ifuba[lcn>>1].ifu_w.ifrw_info;
39524888Skarels 	else
39624888Skarels 		info = sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_info;
39724888Skarels 
39824888Skarels 	/* set channel info */
39924888Skarels 
40024888Skarels 	hc->hc_flags |= HCBUSY;
40124888Skarels 	hc->hc_chan = lcn;
40224888Skarels 	hc->hc_adx = (char)((info & 0x30000) >> 12);
40324888Skarels 	hc->hc_addr = (unsigned short)(info & 0xffff);
40424888Skarels 	hc->hc_cnt = len;
40524888Skarels 	hc->hc_func = (char)func;
40624888Skarels 	hc->hc_sbfc = 0;
40724888Skarels 
40824888Skarels 	s = splimp();
40924888Skarels 	/*
41024888Skarels 	 * If UMC comm regs busy, queue start i/o for later.
41124888Skarels 	 */
41224888Skarels 	if (sc->hdh_sioq.sioq_head) {
41324888Skarels 		(sc->hdh_sioq.sioq_tail)->hc_next = hc;
41424888Skarels 		sc->hdh_sioq.sioq_tail = hc;
41524888Skarels 		hc->hc_next = 0;
41624888Skarels 		splx(s);
41724888Skarels 		return;
41824888Skarels 	}
41924888Skarels 
42024888Skarels 	/* start i/o on channel now */
42124888Skarels 
42224888Skarels 	sc->hdh_sioq.sioq_head = hc;
42324888Skarels 	sc->hdh_sioq.sioq_tail = hc;
42424888Skarels 	hc->hc_next = 0;
42524888Skarels 	start_chn(unit);
42624888Skarels 	splx(s);
42724888Skarels }
42824888Skarels 
42924888Skarels start_chn(unit)
43024888Skarels int unit;
43124888Skarels {
43224888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
43324888Skarels 	register struct hdh_chan *hc = sc->hdh_sioq.sioq_head;
43424888Skarels 	register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
43524888Skarels 
43624888Skarels 	/*
43724888Skarels 	 * Set up comm regs.
43824888Skarels 	 */
43924888Skarels 	addr->iochn = hc->hc_chan;
44024888Skarels 	addr->ioadx = hc->hc_adx;
44124888Skarels 	addr->ioadl = hc->hc_addr;
44224888Skarels 	addr->iocnt = hc->hc_cnt;
44324888Skarels 	addr->iofcn = hc->hc_func;
44424888Skarels 	addr->iosbf = hc->hc_sbfc;
44524888Skarels 	addr->ioini = 1;
44624888Skarels 
44724888Skarels 	/* signal UMC if necessary */
44824888Skarels 
44924888Skarels 	if (!(addr->ionmi)) {
45024888Skarels 		addr->ionmi = 1;
45124888Skarels 		addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
45224888Skarels 	}
45324888Skarels }
45424888Skarels 
45524888Skarels /*
45624888Skarels  * IF-11/HDH interrupt handler
45724888Skarels  */
45824888Skarels hdhintr(unit)
45924888Skarels int unit;
46024888Skarels {
46124888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
46224888Skarels 	register struct hdh_chan *hc;
46324888Skarels 	register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
46424888Skarels 	register struct mbuf *m;
46524888Skarels 	int lcn, type, cc, cnt, s;
46624888Skarels 
46724888Skarels 	/*
46824888Skarels 	 * Check for hardware errors.
46924888Skarels 	 */
47024888Skarels 	if (addr->csr & HDH_UER) {
47124888Skarels 		printf("hdh%d: hard error csr=%b\n", unit, addr->csr, HDH_BITS);
47224888Skarels 		addr->csr = 0;		/* disable i/f */
47324888Skarels 		return;
47424888Skarels 	}
47524888Skarels 	/*
47624888Skarels 	 * Get logical channel info.
47724888Skarels 	 */
47824888Skarels 	if ((lcn = addr->stachn) >= (NHDHCH*2)) {
47924888Skarels 		printf("hdh%d: unknown channel lcn=%d\n", unit, lcn);
48024888Skarels 		return;
48124888Skarels 	}
48224888Skarels 
48324888Skarels 	hc = &sc->hdh_chan[lcn];
48424888Skarels 
48524888Skarels 	type = addr->statyp;
48624888Skarels 	cc = addr->stacc;
48724888Skarels 	cnt = hc->hc_cnt - addr->stacnt;
48824888Skarels 
48924888Skarels 	/* Figure out what kind of interrupt it was */
49024888Skarels 
49124888Skarels 	switch(type) {
49224888Skarels 
49324888Skarels 	case HDHSACK:		/* start i/o accepted */
49424888Skarels 		if (hc != sc->hdh_sioq.sioq_head) {
49524888Skarels 			printf("hdh%d: STARTIO error lcn=%d hc=%x sq=%x\n",
49624888Skarels 				unit, lcn, hc, sc->hdh_sioq.sioq_head);
49724888Skarels 			return;
49824888Skarels 		}
49924888Skarels 
50024888Skarels 		/* try to start any queued i/o request */
50124888Skarels 
50224888Skarels 		if (sc->hdh_sioq.sioq_head = sc->hdh_sioq.sioq_head->hc_next) {
50324888Skarels 			start_chn(unit);
50424888Skarels 		}
50524888Skarels 		break;
50624888Skarels 
50724888Skarels 	case HDHDONE:		/* i/o completion */
50824888Skarels 		switch (cc) {
50924888Skarels 
51024888Skarels 		case HDHIOCABT:
51124888Skarels 			printf("hdh%d: I/O abort ", unit);
51224888Skarels 			goto daterr;
51324888Skarels 
51424888Skarels 		case HDHIOCERR:
51524888Skarels 			printf("hdh%d: program error ", unit);
51624888Skarels 			goto daterr;
51724888Skarels 
51824888Skarels 		case HDHIOCOVR:
51924888Skarels 			printf("hdh%d: overrun error ", unit);
52024888Skarels 			goto daterr;
52124888Skarels 
52224888Skarels 		case HDHIOCUBE:
52324888Skarels 			printf("hdh%d: NXM timeout or UB parity error ", unit);
52424888Skarels 
52524888Skarels 		daterr:
52624888Skarels 			printf("lcn=%d func=%x\n", lcn, hc->hc_func);
52724888Skarels 			if (hc->hc_func & HDHRDB)
52824888Skarels 				sc->hdh_if->if_ierrors++;
52924888Skarels 			else
53024888Skarels 				sc->hdh_if->if_oerrors++;
53124888Skarels 		}
53224888Skarels 
53324888Skarels 		hc->hc_flags &= ~HCBUSY;
53424888Skarels 
53524888Skarels 		/* was it supervisor or data traffic? */
53624888Skarels 
53724888Skarels 		if (lcn > HDHSUPW)
53824888Skarels 			hdh_data(unit, lcn, cc, cnt);
53924888Skarels 		else
54024888Skarels 			hdh_supr(unit, lcn, cc, cnt);
54124888Skarels 
54224888Skarels 	}
54324888Skarels 
54424888Skarels 	/*
54524888Skarels 	 * Ack the interrupt
54624888Skarels 	 */
54724888Skarels 	addr->staack = 1;
54824888Skarels 	if (!(addr->ionmi)) {
54924888Skarels 		addr->ionmi = 1;
55024888Skarels 		addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
55124888Skarels 	}
55224888Skarels }
55324888Skarels 
55424888Skarels /*
55524888Skarels  * data channel interrupt completion handler
55624888Skarels  */
55724888Skarels hdh_data(unit, lcn, cc, rcnt)
55824888Skarels int unit, lcn, cc, rcnt;
55924888Skarels {
56024888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
56124888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
56224888Skarels 	register struct mbuf *m;
56324888Skarels 
56424888Skarels 
56524888Skarels 	/* was it read or write? */
56624888Skarels 
56724888Skarels 	if (hc->hc_func & HDHRDB) {
56824888Skarels 		if (cc == HDHIOCOK) {
56924888Skarels 			/*
57024888Skarels 			 * Queue good packet for input
57124888Skarels 			 */
57224888Skarels 			sc->hdh_if->if_ipackets++;
573*25461Skarels 			m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0,
574*25461Skarels 				sc->hdh_if);
57524888Skarels 			impinput(unit, m);
57624888Skarels 		}
57724888Skarels 
57824888Skarels 		/* hang a new data read */
57924888Skarels 
58024888Skarels 		hdh_iorq(unit, lcn, IMPMTU, HDHRDB+HDHSTR);
58124888Skarels 
58224888Skarels 	} else {
58324888Skarels 		/*
58424888Skarels 		 * fire up next output
58524888Skarels 		 */
58624888Skarels 		sc->hdh_if->if_opackets++;
58724888Skarels 		sc->hdh_ic->ic_oactive = 0;
58824888Skarels 		hdhstart(unit);
58924888Skarels 	}
59024888Skarels }
59124888Skarels 
59224888Skarels /*
59324888Skarels  * supervisor channel interrupt completion handler
59424888Skarels  */
59524888Skarels hdh_supr(unit, lcn, cc, rcnt)
59624888Skarels int unit, lcn, cc, rcnt;
59724888Skarels {
59824888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
59924888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
60024888Skarels 	register struct uba_device *ui;
60124888Skarels 	short *p;
60224888Skarels 	int i;
60324888Skarels 
60424888Skarels 
60524888Skarels 	/* was it read or write? */
60624888Skarels 
60724888Skarels 	if (hc->hc_func & HDHRDB) {
60824888Skarels 		if (cc == HDHIOCOK) {
60924888Skarels 			p = (short *)(sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_addr);
61024888Skarels 
61124888Skarels 			/* figure out what kind of supervisor message */
61224888Skarels 
61324888Skarels 			switch (*p) {
61424888Skarels 
61524888Skarels 			case HDHIACK:
61624888Skarels 			case HDHLNACK:
61724888Skarels 				break;
61824888Skarels 
61924888Skarels 			case HDHLNUP:
62024888Skarels 				printf("hdh%d: LINE UP\n", unit);
62124888Skarels 				sc->hdh_flags |= HDH_UP;
62224888Skarels 				hdhstart(unit);
62324888Skarels 				break;
62424888Skarels 
62524888Skarels 			case HDHLNDN:
62624888Skarels 				if (sc->hdh_flags & HDH_UP)
62724888Skarels 					printf("hdh%d: LINE DOWN\n", unit);
62824888Skarels 				sc->hdh_flags &= ~HDH_UP;
62924888Skarels 				break;
63024888Skarels 
63124888Skarels 			case HDHLOOP:
63224888Skarels 				break;
63324888Skarels 
63424888Skarels 			case HDHSQERR:
63524888Skarels 				printf("hdh%d: HOST SEQUENCE ERROR\n", unit);
63624888Skarels 				break;
63724888Skarels 
63824888Skarels 			case HDHSQRCV:
63924888Skarels 				printf("hdh%d: IMP SEQUENCE ERROR\n", unit);
64024888Skarels 				break;
64124888Skarels 
64224888Skarels 			case HDHDTERR:
64324888Skarels 				printf("hdh%d: HOST DATA ERROR\n", unit);
64424888Skarels 				break;
64524888Skarels 
64624888Skarels 			case HDHTIMO:
64724888Skarels 				printf("hdh%d: TIMEOUT\n", unit);
64824888Skarels 				break;
64924888Skarels 
65024888Skarels 			default:
65124888Skarels 				printf("hdh%d: supervisor error, code=%x\n",
65224888Skarels 					unit, *p);
65324888Skarels 			}
65424888Skarels 		}
65524888Skarels 
65624888Skarels 		/* hang a new supr read */
65724888Skarels 
65824888Skarels 		hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB+HDHSTR);
65924888Skarels 	}
66024888Skarels }
66124888Skarels 
66224888Skarels snd_supr(unit, msg, len)
66324888Skarels int unit, len;
66424888Skarels char *msg;
66524888Skarels {
66624888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
66724888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[HDHSUPW];
66824888Skarels 	register struct mbuf *m;
66924888Skarels 	register char *p;
67024888Skarels 	register int cnt;
67124888Skarels 
67224888Skarels 	if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) {
67324888Skarels 		printf("hdh%d: cannot get supervisor cmnd buffer\n", unit);
67424888Skarels 			return(0);
67524888Skarels 	}
67624888Skarels 
67724888Skarels 	cnt = len;
67824888Skarels 	m->m_len = len;
67924888Skarels 	p = mtod(m, char *);
68024888Skarels 
68124888Skarels 	while(cnt--) *p++ = *msg++;
68224888Skarels 
68324888Skarels 	cnt = if_wubaput(&sc->hdh_ifuba[SUPR], m);
68424888Skarels 
68524888Skarels 	hdh_iorq(unit, HDHSUPW, cnt, HDHWRT+HDHEOS);
68624888Skarels 
68724888Skarels 	return(1);
68824888Skarels }
68924888Skarels 
69024888Skarels #endif NHDH
691