xref: /csrg-svn/sys/vax/if/if_hdh.c (revision 26310)
1*26310Skarels /*	@(#)if_hdh.c	6.5 (Berkeley) 02/21/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 
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)
21925461Skarels 		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);
24525461Skarels 	sc->hdh_if->if_flags &= ~IFF_RUNNING;
24625461Skarels 	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 uba_device *ui;
28026283Skarels 	int i;
28124888Skarels 
28224888Skarels #ifdef HDHDEBUG
28324888Skarels 	printf("HDH INIT\n");
28424888Skarels #endif HDHDEBUG
28524888Skarels 
28624888Skarels 	if (unit >= NHDH || (ui = hdhinfo[unit]) == NULL
28724888Skarels 	    || ui->ui_alive == 0) {
28824888Skarels 		printf("hdh%d: not alive\n", unit);
28924888Skarels 		return(0);
29024888Skarels 	}
29124888Skarels 	sc = &hdh_softc[unit];
29224888Skarels 
29325461Skarels 	if (sc->hdh_flags & HDH_STARTED)
29424888Skarels 		return(1);
29524888Skarels 
29624888Skarels 	/*
29724888Skarels 	 * Alloc uba resources
29824888Skarels 	 */
29924888Skarels 	for(i=0;i<NHDHCH;i++) {
30024888Skarels 		if (if_ubainit(&sc->hdh_ifuba[i], ui->ui_ubanum, 0,
30124888Skarels 		    (int)btoc(IMPMTU)) == 0) {
30224888Skarels 			printf("hdh%d: cannot get chan %d uba resources\n",
30324888Skarels 				unit, i);
30424888Skarels 			ui->ui_alive = 0;
30524888Skarels 			return(0);
30624888Skarels 		}
30724888Skarels 	}
30824888Skarels 
30925461Skarels 	sc->hdh_if->if_flags |= IFF_RUNNING;
31024888Skarels 	sc->hdh_flags = HDH_STARTED;
31124888Skarels 
31224888Skarels 	/*
31324888Skarels 	 * hang a supervisor read (for line status)
31424888Skarels 	 */
31524888Skarels 	hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB);
31624888Skarels 
31724888Skarels 	/*
31824888Skarels 	 * hang a data read
31924888Skarels 	 */
32024888Skarels 	hdh_iorq(unit, HDHDATR, IMPMTU, HDHRDB+HDHSTR);
32124888Skarels 
32224888Skarels 	/*
32324888Skarels 	 * bring up line to IMP
32424888Skarels 	 */
32524888Skarels 
32624888Skarels 	snd_supr(unit, init_blk, sizeof(init_blk));
32724888Skarels 
32824888Skarels 	return(1);
32924888Skarels }
33024888Skarels 
33124888Skarels /*
33224888Skarels  * Start an output operation on an mbuf.
33324888Skarels  */
33424888Skarels hdhstart(dev)
33524888Skarels dev_t dev;
33624888Skarels {
33724888Skarels 	int unit = HDHUNIT(dev);
33824888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
33924888Skarels 	register struct mbuf *m;
34024888Skarels         int len;
34124888Skarels 
34224888Skarels 	/*
34324888Skarels 	 * If output isn't active, attempt to
34424888Skarels 	 * start sending a new packet.
34524888Skarels 	 */
34624888Skarels 
34724888Skarels 	if (sc->hdh_ic->ic_oactive) {
34824888Skarels 		printf("hdh%d: start on active unit\n", unit);
34924888Skarels 		return;
35024888Skarels 	}
35124888Skarels 
35224888Skarels 	if ((sc->hdh_flags & HDH_UP) == 0) {
35324888Skarels 		sc->hdh_ic->ic_oactive = 0;	/* Link not up, can't xmit */
35424888Skarels 		return;
35524888Skarels 	}
35624888Skarels 
35724888Skarels 	IF_DEQUEUE(&sc->hdh_if->if_snd, m);
35824888Skarels 	if (m == 0) {
35924888Skarels 		sc->hdh_ic->ic_oactive = 0;
36024888Skarels 		return;
36124888Skarels 	}
36224888Skarels 
36324888Skarels 	len = if_wubaput(&sc->hdh_ifuba[DATA], m);	/* copy data to mapped mem */
36424888Skarels 	sc->hdh_ic->ic_oactive = 1;
36524888Skarels 
36624888Skarels 	hdh_iorq(unit, HDHDATW, len, HDHWRT+HDHEOS);
36724888Skarels }
36824888Skarels 
36924888Skarels /*
37024888Skarels  * Start i/o operation on a UMC logical channel
37124888Skarels  */
37224888Skarels hdh_iorq(unit, lcn, len, func)
37324888Skarels int unit, lcn, len, func;
37424888Skarels {
37524888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
37624888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
37724888Skarels 	register int info, s;
37824888Skarels 
37924888Skarels 	/*
38024888Skarels 	 * If channel is busy (shouldn't be), drop.
38124888Skarels 	 */
38224888Skarels 	if  (hc->hc_flags & HCBUSY) {
38324888Skarels 		printf("hdh%d: channel busy lcn=%d\n", unit, lcn);
38424888Skarels 		return;
38524888Skarels 	}
38624888Skarels 
38724888Skarels  	/* get appropriate UNIBUS mapping info */
38824888Skarels 
38924888Skarels 	if (lcn & 1)		/* read or write? */
39024888Skarels 		info = sc->hdh_ifuba[lcn>>1].ifu_w.ifrw_info;
39124888Skarels 	else
39224888Skarels 		info = sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_info;
39324888Skarels 
39424888Skarels 	/* set channel info */
39524888Skarels 
39624888Skarels 	hc->hc_flags |= HCBUSY;
39724888Skarels 	hc->hc_chan = lcn;
39824888Skarels 	hc->hc_adx = (char)((info & 0x30000) >> 12);
39924888Skarels 	hc->hc_addr = (unsigned short)(info & 0xffff);
40024888Skarels 	hc->hc_cnt = len;
40124888Skarels 	hc->hc_func = (char)func;
40224888Skarels 	hc->hc_sbfc = 0;
40324888Skarels 
40424888Skarels 	s = splimp();
40524888Skarels 	/*
40624888Skarels 	 * If UMC comm regs busy, queue start i/o for later.
40724888Skarels 	 */
40824888Skarels 	if (sc->hdh_sioq.sioq_head) {
40924888Skarels 		(sc->hdh_sioq.sioq_tail)->hc_next = hc;
41024888Skarels 		sc->hdh_sioq.sioq_tail = hc;
41124888Skarels 		hc->hc_next = 0;
41224888Skarels 		splx(s);
41324888Skarels 		return;
41424888Skarels 	}
41524888Skarels 
41624888Skarels 	/* start i/o on channel now */
41724888Skarels 
41824888Skarels 	sc->hdh_sioq.sioq_head = hc;
41924888Skarels 	sc->hdh_sioq.sioq_tail = hc;
42024888Skarels 	hc->hc_next = 0;
42124888Skarels 	start_chn(unit);
42224888Skarels 	splx(s);
42324888Skarels }
42424888Skarels 
42524888Skarels start_chn(unit)
42624888Skarels int unit;
42724888Skarels {
42824888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
42924888Skarels 	register struct hdh_chan *hc = sc->hdh_sioq.sioq_head;
43024888Skarels 	register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
43124888Skarels 
43224888Skarels 	/*
43324888Skarels 	 * Set up comm regs.
43424888Skarels 	 */
43524888Skarels 	addr->iochn = hc->hc_chan;
43624888Skarels 	addr->ioadx = hc->hc_adx;
43724888Skarels 	addr->ioadl = hc->hc_addr;
43824888Skarels 	addr->iocnt = hc->hc_cnt;
43924888Skarels 	addr->iofcn = hc->hc_func;
44024888Skarels 	addr->iosbf = hc->hc_sbfc;
44124888Skarels 	addr->ioini = 1;
44224888Skarels 
44324888Skarels 	/* signal UMC if necessary */
44424888Skarels 
44524888Skarels 	if (!(addr->ionmi)) {
44624888Skarels 		addr->ionmi = 1;
44724888Skarels 		addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
44824888Skarels 	}
44924888Skarels }
45024888Skarels 
45124888Skarels /*
45224888Skarels  * IF-11/HDH interrupt handler
45324888Skarels  */
45424888Skarels hdhintr(unit)
45524888Skarels int unit;
45624888Skarels {
45724888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
45824888Skarels 	register struct hdh_chan *hc;
45924888Skarels 	register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
46026283Skarels 	int lcn, type, cc, cnt;
46124888Skarels 
46224888Skarels 	/*
46324888Skarels 	 * Check for hardware errors.
46424888Skarels 	 */
46524888Skarels 	if (addr->csr & HDH_UER) {
46624888Skarels 		printf("hdh%d: hard error csr=%b\n", unit, addr->csr, HDH_BITS);
46724888Skarels 		addr->csr = 0;		/* disable i/f */
46824888Skarels 		return;
46924888Skarels 	}
47024888Skarels 	/*
47124888Skarels 	 * Get logical channel info.
47224888Skarels 	 */
47324888Skarels 	if ((lcn = addr->stachn) >= (NHDHCH*2)) {
47424888Skarels 		printf("hdh%d: unknown channel lcn=%d\n", unit, lcn);
47524888Skarels 		return;
47624888Skarels 	}
47724888Skarels 
47824888Skarels 	hc = &sc->hdh_chan[lcn];
47924888Skarels 
48024888Skarels 	type = addr->statyp;
48124888Skarels 	cc = addr->stacc;
48224888Skarels 	cnt = hc->hc_cnt - addr->stacnt;
48324888Skarels 
48424888Skarels 	/* Figure out what kind of interrupt it was */
48524888Skarels 
48624888Skarels 	switch(type) {
48724888Skarels 
48824888Skarels 	case HDHSACK:		/* start i/o accepted */
48924888Skarels 		if (hc != sc->hdh_sioq.sioq_head) {
49024888Skarels 			printf("hdh%d: STARTIO error lcn=%d hc=%x sq=%x\n",
49124888Skarels 				unit, lcn, hc, sc->hdh_sioq.sioq_head);
49224888Skarels 			return;
49324888Skarels 		}
49424888Skarels 
49524888Skarels 		/* try to start any queued i/o request */
49624888Skarels 
49724888Skarels 		if (sc->hdh_sioq.sioq_head = sc->hdh_sioq.sioq_head->hc_next) {
49824888Skarels 			start_chn(unit);
49924888Skarels 		}
50024888Skarels 		break;
50124888Skarels 
50224888Skarels 	case HDHDONE:		/* i/o completion */
50324888Skarels 		switch (cc) {
50424888Skarels 
50524888Skarels 		case HDHIOCABT:
50624888Skarels 			printf("hdh%d: I/O abort ", unit);
50724888Skarels 			goto daterr;
50824888Skarels 
50924888Skarels 		case HDHIOCERR:
51024888Skarels 			printf("hdh%d: program error ", unit);
51124888Skarels 			goto daterr;
51224888Skarels 
51324888Skarels 		case HDHIOCOVR:
51424888Skarels 			printf("hdh%d: overrun error ", unit);
51524888Skarels 			goto daterr;
51624888Skarels 
51724888Skarels 		case HDHIOCUBE:
51824888Skarels 			printf("hdh%d: NXM timeout or UB parity error ", unit);
51924888Skarels 
52024888Skarels 		daterr:
52124888Skarels 			printf("lcn=%d func=%x\n", lcn, hc->hc_func);
52224888Skarels 			if (hc->hc_func & HDHRDB)
52324888Skarels 				sc->hdh_if->if_ierrors++;
52424888Skarels 			else
52524888Skarels 				sc->hdh_if->if_oerrors++;
52624888Skarels 		}
52724888Skarels 
52824888Skarels 		hc->hc_flags &= ~HCBUSY;
52924888Skarels 
53024888Skarels 		/* was it supervisor or data traffic? */
53124888Skarels 
53224888Skarels 		if (lcn > HDHSUPW)
53324888Skarels 			hdh_data(unit, lcn, cc, cnt);
53424888Skarels 		else
535*26310Skarels 			hdh_supr(unit, lcn, cc);
53624888Skarels 
53724888Skarels 	}
53824888Skarels 
53924888Skarels 	/*
54024888Skarels 	 * Ack the interrupt
54124888Skarels 	 */
54224888Skarels 	addr->staack = 1;
54324888Skarels 	if (!(addr->ionmi)) {
54424888Skarels 		addr->ionmi = 1;
54524888Skarels 		addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
54624888Skarels 	}
54724888Skarels }
54824888Skarels 
54924888Skarels /*
55024888Skarels  * data channel interrupt completion handler
55124888Skarels  */
55224888Skarels hdh_data(unit, lcn, cc, rcnt)
55324888Skarels int unit, lcn, cc, rcnt;
55424888Skarels {
55524888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
55624888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
55724888Skarels 	register struct mbuf *m;
55824888Skarels 
55924888Skarels 
56024888Skarels 	/* was it read or write? */
56124888Skarels 
56224888Skarels 	if (hc->hc_func & HDHRDB) {
56324888Skarels 		if (cc == HDHIOCOK) {
56424888Skarels 			/*
56524888Skarels 			 * Queue good packet for input
56624888Skarels 			 */
56724888Skarels 			sc->hdh_if->if_ipackets++;
56825461Skarels 			m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0,
56925461Skarels 				sc->hdh_if);
57024888Skarels 			impinput(unit, m);
57124888Skarels 		}
57224888Skarels 
57324888Skarels 		/* hang a new data read */
57424888Skarels 
57524888Skarels 		hdh_iorq(unit, lcn, IMPMTU, HDHRDB+HDHSTR);
57624888Skarels 
57724888Skarels 	} else {
57824888Skarels 		/*
57924888Skarels 		 * fire up next output
58024888Skarels 		 */
58124888Skarels 		sc->hdh_if->if_opackets++;
58224888Skarels 		sc->hdh_ic->ic_oactive = 0;
58324888Skarels 		hdhstart(unit);
58424888Skarels 	}
58524888Skarels }
58624888Skarels 
58724888Skarels /*
58824888Skarels  * supervisor channel interrupt completion handler
58924888Skarels  */
590*26310Skarels hdh_supr(unit, lcn, cc)
591*26310Skarels int unit, lcn, cc;
59224888Skarels {
59324888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
59424888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
59524888Skarels 	short *p;
59624888Skarels 
59724888Skarels 
59824888Skarels 	/* was it read or write? */
59924888Skarels 
60024888Skarels 	if (hc->hc_func & HDHRDB) {
60124888Skarels 		if (cc == HDHIOCOK) {
60224888Skarels 			p = (short *)(sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_addr);
60324888Skarels 
60424888Skarels 			/* figure out what kind of supervisor message */
60524888Skarels 
60624888Skarels 			switch (*p) {
60724888Skarels 
60824888Skarels 			case HDHIACK:
60924888Skarels 			case HDHLNACK:
61024888Skarels 				break;
61124888Skarels 
61224888Skarels 			case HDHLNUP:
61324888Skarels 				printf("hdh%d: LINE UP\n", unit);
61424888Skarels 				sc->hdh_flags |= HDH_UP;
61524888Skarels 				hdhstart(unit);
61624888Skarels 				break;
61724888Skarels 
61824888Skarels 			case HDHLNDN:
61924888Skarels 				if (sc->hdh_flags & HDH_UP)
62024888Skarels 					printf("hdh%d: LINE DOWN\n", unit);
62124888Skarels 				sc->hdh_flags &= ~HDH_UP;
62224888Skarels 				break;
62324888Skarels 
62424888Skarels 			case HDHLOOP:
62524888Skarels 				break;
62624888Skarels 
62724888Skarels 			case HDHSQERR:
62824888Skarels 				printf("hdh%d: HOST SEQUENCE ERROR\n", unit);
62924888Skarels 				break;
63024888Skarels 
63124888Skarels 			case HDHSQRCV:
63224888Skarels 				printf("hdh%d: IMP SEQUENCE ERROR\n", unit);
63324888Skarels 				break;
63424888Skarels 
63524888Skarels 			case HDHDTERR:
63624888Skarels 				printf("hdh%d: HOST DATA ERROR\n", unit);
63724888Skarels 				break;
63824888Skarels 
63924888Skarels 			case HDHTIMO:
64024888Skarels 				printf("hdh%d: TIMEOUT\n", unit);
64124888Skarels 				break;
64224888Skarels 
64324888Skarels 			default:
64424888Skarels 				printf("hdh%d: supervisor error, code=%x\n",
64524888Skarels 					unit, *p);
64624888Skarels 			}
64724888Skarels 		}
64824888Skarels 
64924888Skarels 		/* hang a new supr read */
65024888Skarels 
65124888Skarels 		hdh_iorq(unit, HDHSUPR, IMPMTU, HDHRDB+HDHSTR);
65224888Skarels 	}
65324888Skarels }
65424888Skarels 
65524888Skarels snd_supr(unit, msg, len)
65624888Skarels int unit, len;
65724888Skarels char *msg;
65824888Skarels {
65924888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
66024888Skarels 	register struct mbuf *m;
66124888Skarels 	register char *p;
66224888Skarels 	register int cnt;
66324888Skarels 
66424888Skarels 	if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) {
66524888Skarels 		printf("hdh%d: cannot get supervisor cmnd buffer\n", unit);
66624888Skarels 			return(0);
66724888Skarels 	}
66824888Skarels 
66924888Skarels 	cnt = len;
67024888Skarels 	m->m_len = len;
67124888Skarels 	p = mtod(m, char *);
67224888Skarels 
67324888Skarels 	while(cnt--) *p++ = *msg++;
67424888Skarels 
67524888Skarels 	cnt = if_wubaput(&sc->hdh_ifuba[SUPR], m);
67624888Skarels 
67724888Skarels 	hdh_iorq(unit, HDHSUPW, cnt, HDHWRT+HDHEOS);
67824888Skarels 
67924888Skarels 	return(1);
68024888Skarels }
68124888Skarels #endif NHDH
682