xref: /csrg-svn/sys/vax/if/if_hdh.c (revision 26392)
1*26392Skarels /*	@(#)if_hdh.c	6.6 (Berkeley) 02/23/86 */
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 
6725461Skarels #include "param.h"
6825461Skarels #include "systm.h"
6925461Skarels #include "mbuf.h"
7025461Skarels #include "buf.h"
7125461Skarels #include "protosw.h"
7225461Skarels #include "socket.h"
7325461Skarels #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 
8325461Skarels #include "if_hdhreg.h"
8425461Skarels #include "if_uba.h"
8525461Skarels 
86*26392Skarels int     hdhprobe(), hdhattach(), hdhintr();
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;
177*26392Skarels 	hdhintr(0);
17824888Skarels #endif
17924888Skarels 
18024888Skarels 	br = 0x15;			/* priority 21 (5 on UNIBUS) */
18124888Skarels 
18224888Skarels #ifdef HDHDEBUG
18324888Skarels 	cvec = 0270;			/* use constant for now ... */
18424888Skarels #else
18524888Skarels 
18624888Skarels #ifdef VAXVMS				/* if VMS */
18724888Skarels 	cvec = 0270;			/*   we can't allocate vectors */
18824888Skarels #else
18924888Skarels 	cvec = (uba_hd[numuba].uh_lastiv -= 4);  /* available vector */
19024888Skarels #endif VAXVMS
19124888Skarels 
19224888Skarels #endif HDHDEBUG
19324888Skarels 
19424888Skarels 	addr->ioini = (char) 0;		/* init UMC regs */
19524888Skarels 	addr->staack = (char) 0;	/*   pass vector */
19624888Skarels 	addr->ionmi = (char) 0;		/*     and kick UMC */
19724888Skarels 	addr->iochn = (char) (cvec >> 2);
19824888Skarels 	addr->csr = (short) HDH_RST;
19924888Skarels 	addr->csr = (short) (HDH_IEN|HDH_DMA|HDH_WRT); /* set enables */
20024888Skarels 	DELAY(5000);			/* give the UMC some time */
20124888Skarels 	return(1);
20224888Skarels }
20324888Skarels 
20424888Skarels /*
20524888Skarels  * Call the IMP module to allow it to set up its internal
20624888Skarels  * state, then tie the two modules together by setting up
20724888Skarels  * the back pointers to common data structures.
20824888Skarels  */
20924888Skarels hdhattach(ui)
21024888Skarels 	struct uba_device *ui;
21124888Skarels {
21224888Skarels 	register struct hdh_softc *sc = &hdh_softc[ui->ui_unit];
21324888Skarels 	register struct impcb *ip;
21424888Skarels 	struct ifimpcb {
21524888Skarels 		struct	ifnet ifimp_if;
21624888Skarels 		struct	impcb ifimp_impcb;
21724888Skarels 	} *ifimp;
21824888Skarels 
21924888Skarels 	if ((ifimp = (struct ifimpcb *)impattach(ui, hdhreset)) == 0)
22025461Skarels 		return;;
22124888Skarels 	sc->hdh_if = &ifimp->ifimp_if;
22224888Skarels 	ip = &ifimp->ifimp_impcb;
22324888Skarels 	sc->hdh_ic = ip;
22424888Skarels 	ip->ic_init = hdhinit;
22524888Skarels 	ip->ic_start = hdhstart;
22624888Skarels 	sc->hdh_ifuba[ui->ui_unit].ifu_flags = UBA_CANTWAIT;
22724888Skarels }
22824888Skarels 
22924888Skarels /*
23024888Skarels  * Reset interface after UNIBUS reset.
23124888Skarels  */
23224888Skarels hdhreset(unit, uban)
23324888Skarels int unit, uban;
23424888Skarels {
23524888Skarels 	register struct uba_device *ui = hdhinfo[unit];
23624888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
23724888Skarels 
23824888Skarels #ifdef HDHDEBUG
23924888Skarels 	printf("HDH RESET\n");
24024888Skarels #endif HDHDEBUG
24124888Skarels 
24224888Skarels 	if ((unit >= NHDH) || (ui == 0) || (ui->ui_alive == 0)
24324888Skarels 	    || (ui->ui_ubanum != uban))
24424888Skarels 		return;
24524888Skarels 	printf(" hdh%d", unit);
24625461Skarels 	sc->hdh_if->if_flags &= ~IFF_RUNNING;
24725461Skarels 	sc->hdh_flags = 0;
24824888Skarels 	(*sc->hdh_if->if_init)(unit);
24924888Skarels }
25024888Skarels 
25124888Skarels /*
25224888Skarels  * Initialize the imp interface.
25324888Skarels  */
25424888Skarels 
25524888Skarels static char init_blk[] =
25624888Skarels     {
25724888Skarels 	HDHINIT,		/* SYSINIT opcode			*/
25824888Skarels 	HDHRQUP & 0xff,		/* control code (LSB)			*/
25924888Skarels 	(HDHRQUP>>8) & 0xff,	/* control code (MSB)			*/
26024888Skarels 	10,			/* command extension len		*/
26124888Skarels 	0,			/* loopback mode (off)			*/
26224888Skarels 	3,			/* our address (3=DTE)			*/
26324888Skarels 	1,			/* their address (1=DCE)		*/
26424888Skarels 	3,			/* frame ack t1 timeout			*/
26524888Skarels 	3,			/* poll ack timeout			*/
26624888Skarels 	30,			/* adm wait timeout			*/
26724888Skarels 	3,			/* rej wait timeout			*/
26824888Skarels 	10,			/* max retries				*/
26924888Skarels 	3,			/* watchdog timeout			*/
27024888Skarels 	0xaa			/* baud rate (0xaa=38.4KB)		*/
27124888Skarels 				/*   (output on RS-232 pin 24,		*/
27224888Skarels 				/*    send/receive timing is always	*/
27324888Skarels 				/*    taken from pins 15/17)		*/
27424888Skarels     };
27524888Skarels 
27624888Skarels hdhinit(unit)
27724888Skarels int unit;
27824888Skarels {
27924888Skarels 	register struct hdh_softc *sc;
28024888Skarels 	register struct uba_device *ui;
28126283Skarels 	int i;
28224888Skarels 
28324888Skarels #ifdef HDHDEBUG
28424888Skarels 	printf("HDH INIT\n");
28524888Skarels #endif HDHDEBUG
28624888Skarels 
28724888Skarels 	if (unit >= NHDH || (ui = hdhinfo[unit]) == NULL
28824888Skarels 	    || ui->ui_alive == 0) {
28924888Skarels 		printf("hdh%d: not alive\n", unit);
29024888Skarels 		return(0);
29124888Skarels 	}
29224888Skarels 	sc = &hdh_softc[unit];
29324888Skarels 
29425461Skarels 	if (sc->hdh_flags & HDH_STARTED)
29524888Skarels 		return(1);
29624888Skarels 
29724888Skarels 	/*
29824888Skarels 	 * Alloc uba resources
29924888Skarels 	 */
30024888Skarels 	for(i=0;i<NHDHCH;i++) {
30124888Skarels 		if (if_ubainit(&sc->hdh_ifuba[i], ui->ui_ubanum, 0,
30224888Skarels 		    (int)btoc(IMPMTU)) == 0) {
30324888Skarels 			printf("hdh%d: cannot get chan %d uba resources\n",
30424888Skarels 				unit, i);
30524888Skarels 			ui->ui_alive = 0;
30624888Skarels 			return(0);
30724888Skarels 		}
30824888Skarels 	}
30924888Skarels 
31025461Skarels 	sc->hdh_if->if_flags |= IFF_RUNNING;
31124888Skarels 	sc->hdh_flags = HDH_STARTED;
31224888Skarels 
31324888Skarels 	/*
31424888Skarels 	 * hang a supervisor read (for line status)
31524888Skarels 	 */
31624888Skarels 	hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB);
31724888Skarels 
31824888Skarels 	/*
31924888Skarels 	 * hang a data read
32024888Skarels 	 */
32124888Skarels 	hdh_iorq(unit, HDHDATR, IMPMTU, HDHRDB+HDHSTR);
32224888Skarels 
32324888Skarels 	/*
32424888Skarels 	 * bring up line to IMP
32524888Skarels 	 */
32624888Skarels 
32724888Skarels 	snd_supr(unit, init_blk, sizeof(init_blk));
32824888Skarels 
32924888Skarels 	return(1);
33024888Skarels }
33124888Skarels 
33224888Skarels /*
33324888Skarels  * Start an output operation on an mbuf.
33424888Skarels  */
33524888Skarels hdhstart(dev)
33624888Skarels dev_t dev;
33724888Skarels {
33824888Skarels 	int unit = HDHUNIT(dev);
33924888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
34024888Skarels 	register struct mbuf *m;
34124888Skarels         int len;
34224888Skarels 
34324888Skarels 	/*
34424888Skarels 	 * If output isn't active, attempt to
34524888Skarels 	 * start sending a new packet.
34624888Skarels 	 */
34724888Skarels 
34824888Skarels 	if (sc->hdh_ic->ic_oactive) {
34924888Skarels 		printf("hdh%d: start on active unit\n", unit);
35024888Skarels 		return;
35124888Skarels 	}
35224888Skarels 
35324888Skarels 	if ((sc->hdh_flags & HDH_UP) == 0) {
35424888Skarels 		sc->hdh_ic->ic_oactive = 0;	/* Link not up, can't xmit */
35524888Skarels 		return;
35624888Skarels 	}
35724888Skarels 
35824888Skarels 	IF_DEQUEUE(&sc->hdh_if->if_snd, m);
35924888Skarels 	if (m == 0) {
36024888Skarels 		sc->hdh_ic->ic_oactive = 0;
36124888Skarels 		return;
36224888Skarels 	}
36324888Skarels 
36424888Skarels 	len = if_wubaput(&sc->hdh_ifuba[DATA], m);	/* copy data to mapped mem */
36524888Skarels 	sc->hdh_ic->ic_oactive = 1;
36624888Skarels 
36724888Skarels 	hdh_iorq(unit, HDHDATW, len, HDHWRT+HDHEOS);
36824888Skarels }
36924888Skarels 
37024888Skarels /*
37124888Skarels  * Start i/o operation on a UMC logical channel
37224888Skarels  */
37324888Skarels hdh_iorq(unit, lcn, len, func)
37424888Skarels int unit, lcn, len, func;
37524888Skarels {
37624888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
37724888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
37824888Skarels 	register int info, s;
37924888Skarels 
38024888Skarels 	/*
38124888Skarels 	 * If channel is busy (shouldn't be), drop.
38224888Skarels 	 */
38324888Skarels 	if  (hc->hc_flags & HCBUSY) {
38424888Skarels 		printf("hdh%d: channel busy lcn=%d\n", unit, lcn);
38524888Skarels 		return;
38624888Skarels 	}
38724888Skarels 
38824888Skarels  	/* get appropriate UNIBUS mapping info */
38924888Skarels 
39024888Skarels 	if (lcn & 1)		/* read or write? */
39124888Skarels 		info = sc->hdh_ifuba[lcn>>1].ifu_w.ifrw_info;
39224888Skarels 	else
39324888Skarels 		info = sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_info;
39424888Skarels 
39524888Skarels 	/* set channel info */
39624888Skarels 
39724888Skarels 	hc->hc_flags |= HCBUSY;
39824888Skarels 	hc->hc_chan = lcn;
39924888Skarels 	hc->hc_adx = (char)((info & 0x30000) >> 12);
40024888Skarels 	hc->hc_addr = (unsigned short)(info & 0xffff);
40124888Skarels 	hc->hc_cnt = len;
40224888Skarels 	hc->hc_func = (char)func;
40324888Skarels 	hc->hc_sbfc = 0;
40424888Skarels 
40524888Skarels 	s = splimp();
40624888Skarels 	/*
40724888Skarels 	 * If UMC comm regs busy, queue start i/o for later.
40824888Skarels 	 */
40924888Skarels 	if (sc->hdh_sioq.sioq_head) {
41024888Skarels 		(sc->hdh_sioq.sioq_tail)->hc_next = hc;
41124888Skarels 		sc->hdh_sioq.sioq_tail = hc;
41224888Skarels 		hc->hc_next = 0;
41324888Skarels 		splx(s);
41424888Skarels 		return;
41524888Skarels 	}
41624888Skarels 
41724888Skarels 	/* start i/o on channel now */
41824888Skarels 
41924888Skarels 	sc->hdh_sioq.sioq_head = hc;
42024888Skarels 	sc->hdh_sioq.sioq_tail = hc;
42124888Skarels 	hc->hc_next = 0;
42224888Skarels 	start_chn(unit);
42324888Skarels 	splx(s);
42424888Skarels }
42524888Skarels 
42624888Skarels start_chn(unit)
42724888Skarels int unit;
42824888Skarels {
42924888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
43024888Skarels 	register struct hdh_chan *hc = sc->hdh_sioq.sioq_head;
43124888Skarels 	register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
43224888Skarels 
43324888Skarels 	/*
43424888Skarels 	 * Set up comm regs.
43524888Skarels 	 */
43624888Skarels 	addr->iochn = hc->hc_chan;
43724888Skarels 	addr->ioadx = hc->hc_adx;
43824888Skarels 	addr->ioadl = hc->hc_addr;
43924888Skarels 	addr->iocnt = hc->hc_cnt;
44024888Skarels 	addr->iofcn = hc->hc_func;
44124888Skarels 	addr->iosbf = hc->hc_sbfc;
44224888Skarels 	addr->ioini = 1;
44324888Skarels 
44424888Skarels 	/* signal UMC if necessary */
44524888Skarels 
44624888Skarels 	if (!(addr->ionmi)) {
44724888Skarels 		addr->ionmi = 1;
44824888Skarels 		addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
44924888Skarels 	}
45024888Skarels }
45124888Skarels 
45224888Skarels /*
45324888Skarels  * IF-11/HDH interrupt handler
45424888Skarels  */
45524888Skarels hdhintr(unit)
45624888Skarels int unit;
45724888Skarels {
45824888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
45924888Skarels 	register struct hdh_chan *hc;
46024888Skarels 	register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
46126283Skarels 	int lcn, type, cc, cnt;
46224888Skarels 
46324888Skarels 	/*
46424888Skarels 	 * Check for hardware errors.
46524888Skarels 	 */
46624888Skarels 	if (addr->csr & HDH_UER) {
46724888Skarels 		printf("hdh%d: hard error csr=%b\n", unit, addr->csr, HDH_BITS);
46824888Skarels 		addr->csr = 0;		/* disable i/f */
46924888Skarels 		return;
47024888Skarels 	}
47124888Skarels 	/*
47224888Skarels 	 * Get logical channel info.
47324888Skarels 	 */
47424888Skarels 	if ((lcn = addr->stachn) >= (NHDHCH*2)) {
47524888Skarels 		printf("hdh%d: unknown channel lcn=%d\n", unit, lcn);
47624888Skarels 		return;
47724888Skarels 	}
47824888Skarels 
47924888Skarels 	hc = &sc->hdh_chan[lcn];
48024888Skarels 
48124888Skarels 	type = addr->statyp;
48224888Skarels 	cc = addr->stacc;
48324888Skarels 	cnt = hc->hc_cnt - addr->stacnt;
48424888Skarels 
48524888Skarels 	/* Figure out what kind of interrupt it was */
48624888Skarels 
48724888Skarels 	switch(type) {
48824888Skarels 
48924888Skarels 	case HDHSACK:		/* start i/o accepted */
49024888Skarels 		if (hc != sc->hdh_sioq.sioq_head) {
49124888Skarels 			printf("hdh%d: STARTIO error lcn=%d hc=%x sq=%x\n",
49224888Skarels 				unit, lcn, hc, sc->hdh_sioq.sioq_head);
49324888Skarels 			return;
49424888Skarels 		}
49524888Skarels 
49624888Skarels 		/* try to start any queued i/o request */
49724888Skarels 
49824888Skarels 		if (sc->hdh_sioq.sioq_head = sc->hdh_sioq.sioq_head->hc_next) {
49924888Skarels 			start_chn(unit);
50024888Skarels 		}
50124888Skarels 		break;
50224888Skarels 
50324888Skarels 	case HDHDONE:		/* i/o completion */
50424888Skarels 		switch (cc) {
50524888Skarels 
50624888Skarels 		case HDHIOCABT:
50724888Skarels 			printf("hdh%d: I/O abort ", unit);
50824888Skarels 			goto daterr;
50924888Skarels 
51024888Skarels 		case HDHIOCERR:
51124888Skarels 			printf("hdh%d: program error ", unit);
51224888Skarels 			goto daterr;
51324888Skarels 
51424888Skarels 		case HDHIOCOVR:
51524888Skarels 			printf("hdh%d: overrun error ", unit);
51624888Skarels 			goto daterr;
51724888Skarels 
51824888Skarels 		case HDHIOCUBE:
51924888Skarels 			printf("hdh%d: NXM timeout or UB parity error ", unit);
52024888Skarels 
52124888Skarels 		daterr:
52224888Skarels 			printf("lcn=%d func=%x\n", lcn, hc->hc_func);
52324888Skarels 			if (hc->hc_func & HDHRDB)
52424888Skarels 				sc->hdh_if->if_ierrors++;
52524888Skarels 			else
52624888Skarels 				sc->hdh_if->if_oerrors++;
52724888Skarels 		}
52824888Skarels 
52924888Skarels 		hc->hc_flags &= ~HCBUSY;
53024888Skarels 
53124888Skarels 		/* was it supervisor or data traffic? */
53224888Skarels 
53324888Skarels 		if (lcn > HDHSUPW)
53424888Skarels 			hdh_data(unit, lcn, cc, cnt);
53524888Skarels 		else
53626310Skarels 			hdh_supr(unit, lcn, cc);
53724888Skarels 
53824888Skarels 	}
53924888Skarels 
54024888Skarels 	/*
54124888Skarels 	 * Ack the interrupt
54224888Skarels 	 */
54324888Skarels 	addr->staack = 1;
54424888Skarels 	if (!(addr->ionmi)) {
54524888Skarels 		addr->ionmi = 1;
54624888Skarels 		addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
54724888Skarels 	}
54824888Skarels }
54924888Skarels 
55024888Skarels /*
55124888Skarels  * data channel interrupt completion handler
55224888Skarels  */
55324888Skarels hdh_data(unit, lcn, cc, rcnt)
55424888Skarels int unit, lcn, cc, rcnt;
55524888Skarels {
55624888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
55724888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
55824888Skarels 	register struct mbuf *m;
55924888Skarels 
56024888Skarels 
56124888Skarels 	/* was it read or write? */
56224888Skarels 
56324888Skarels 	if (hc->hc_func & HDHRDB) {
56424888Skarels 		if (cc == HDHIOCOK) {
56524888Skarels 			/*
56624888Skarels 			 * Queue good packet for input
56724888Skarels 			 */
56824888Skarels 			sc->hdh_if->if_ipackets++;
56925461Skarels 			m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0,
57025461Skarels 				sc->hdh_if);
57124888Skarels 			impinput(unit, m);
57224888Skarels 		}
57324888Skarels 
57424888Skarels 		/* hang a new data read */
57524888Skarels 
57624888Skarels 		hdh_iorq(unit, lcn, IMPMTU, HDHRDB+HDHSTR);
57724888Skarels 
57824888Skarels 	} else {
57924888Skarels 		/*
58024888Skarels 		 * fire up next output
58124888Skarels 		 */
58224888Skarels 		sc->hdh_if->if_opackets++;
58324888Skarels 		sc->hdh_ic->ic_oactive = 0;
58424888Skarels 		hdhstart(unit);
58524888Skarels 	}
58624888Skarels }
58724888Skarels 
58824888Skarels /*
58924888Skarels  * supervisor channel interrupt completion handler
59024888Skarels  */
59126310Skarels hdh_supr(unit, lcn, cc)
59226310Skarels int unit, lcn, cc;
59324888Skarels {
59424888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
59524888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
59624888Skarels 	short *p;
59724888Skarels 
59824888Skarels 
59924888Skarels 	/* was it read or write? */
60024888Skarels 
60124888Skarels 	if (hc->hc_func & HDHRDB) {
60224888Skarels 		if (cc == HDHIOCOK) {
60324888Skarels 			p = (short *)(sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_addr);
60424888Skarels 
60524888Skarels 			/* figure out what kind of supervisor message */
60624888Skarels 
60724888Skarels 			switch (*p) {
60824888Skarels 
60924888Skarels 			case HDHIACK:
61024888Skarels 			case HDHLNACK:
61124888Skarels 				break;
61224888Skarels 
61324888Skarels 			case HDHLNUP:
61424888Skarels 				printf("hdh%d: LINE UP\n", unit);
61524888Skarels 				sc->hdh_flags |= HDH_UP;
61624888Skarels 				hdhstart(unit);
61724888Skarels 				break;
61824888Skarels 
61924888Skarels 			case HDHLNDN:
62024888Skarels 				if (sc->hdh_flags & HDH_UP)
62124888Skarels 					printf("hdh%d: LINE DOWN\n", unit);
62224888Skarels 				sc->hdh_flags &= ~HDH_UP;
62324888Skarels 				break;
62424888Skarels 
62524888Skarels 			case HDHLOOP:
62624888Skarels 				break;
62724888Skarels 
62824888Skarels 			case HDHSQERR:
62924888Skarels 				printf("hdh%d: HOST SEQUENCE ERROR\n", unit);
63024888Skarels 				break;
63124888Skarels 
63224888Skarels 			case HDHSQRCV:
63324888Skarels 				printf("hdh%d: IMP SEQUENCE ERROR\n", unit);
63424888Skarels 				break;
63524888Skarels 
63624888Skarels 			case HDHDTERR:
63724888Skarels 				printf("hdh%d: HOST DATA ERROR\n", unit);
63824888Skarels 				break;
63924888Skarels 
64024888Skarels 			case HDHTIMO:
64124888Skarels 				printf("hdh%d: TIMEOUT\n", unit);
64224888Skarels 				break;
64324888Skarels 
64424888Skarels 			default:
64524888Skarels 				printf("hdh%d: supervisor error, code=%x\n",
64624888Skarels 					unit, *p);
64724888Skarels 			}
64824888Skarels 		}
64924888Skarels 
65024888Skarels 		/* hang a new supr read */
65124888Skarels 
65224888Skarels 		hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB+HDHSTR);
65324888Skarels 	}
65424888Skarels }
65524888Skarels 
65624888Skarels snd_supr(unit, msg, len)
65724888Skarels int unit, len;
65824888Skarels char *msg;
65924888Skarels {
66024888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
66124888Skarels 	register struct mbuf *m;
66224888Skarels 	register char *p;
66324888Skarels 	register int cnt;
66424888Skarels 
66524888Skarels 	if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) {
66624888Skarels 		printf("hdh%d: cannot get supervisor cmnd buffer\n", unit);
66724888Skarels 			return(0);
66824888Skarels 	}
66924888Skarels 
67024888Skarels 	cnt = len;
67124888Skarels 	m->m_len = len;
67224888Skarels 	p = mtod(m, char *);
67324888Skarels 
67424888Skarels 	while(cnt--) *p++ = *msg++;
67524888Skarels 
67624888Skarels 	cnt = if_wubaput(&sc->hdh_ifuba[SUPR], m);
67724888Skarels 
67824888Skarels 	hdh_iorq(unit, HDHSUPW, cnt, HDHWRT+HDHEOS);
67924888Skarels 
68024888Skarels 	return(1);
68124888Skarels }
68224888Skarels #endif NHDH
683