xref: /csrg-svn/sys/vax/if/if_hdh.c (revision 33452)
1*33452Skarels /*	@(#)if_hdh.c	7.3 (Berkeley) 02/08/88 */
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:
45*33452Skarels 		Converted to 4.3, updated, UCB.
4624888Skarels 		31-Aug-1984: V1.0 - First Implementation. A.B.
4724888Skarels 		 6-Nov-1984: V1.1 - Supress extra "LINE DOWN" msgs. A.B.
4824888Skarels 		13-Jan-1984: V1.2 - Add conditionals for TWG. A.B.
4924888Skarels 
5024888Skarels \************************************************************************/
5124888Skarels 
5224888Skarels 
5324888Skarels 
5424888Skarels 
5524888Skarels /* $Header$ */
5624888Skarels 
5724888Skarels #include "hdh.h"
5824888Skarels #ifdef NHDH > 0
5924888Skarels 
6024888Skarels /*
6124888Skarels  *
6224888Skarels  * ACC IF-11/HDH interface
6324888Skarels  *
6424888Skarels  */
6524888Skarels 
6625461Skarels #include "param.h"
6725461Skarels #include "systm.h"
6825461Skarels #include "mbuf.h"
6925461Skarels #include "buf.h"
7025461Skarels #include "protosw.h"
7125461Skarels #include "socket.h"
7225461Skarels #include "vmmac.h"
7324888Skarels 
74*33452Skarels #include "../machine/pte.h"
75*33452Skarels 
7624888Skarels #include "../net/if.h"
7724888Skarels #include "../netimp/if_imp.h"
7824888Skarels 
7924888Skarels #include "../vax/cpu.h"
8024888Skarels #include "../vax/mtpr.h"
8124888Skarels #include "../vaxuba/ubareg.h"
8224888Skarels #include "../vaxuba/ubavar.h"
8324888Skarels 
8425461Skarels #include "if_hdhreg.h"
8525461Skarels #include "if_uba.h"
8625461Skarels 
8726392Skarels int     hdhprobe(), hdhattach(), hdhintr();
8824888Skarels struct  uba_device *hdhinfo[NHDH];
8924888Skarels u_short hdhstd[] = { 0 };
9024888Skarels struct  uba_driver hdhdriver =
9124888Skarels 	{ hdhprobe, 0, hdhattach, 0, hdhstd, "hdh", hdhinfo };
9224888Skarels 
9324888Skarels #define	HDHUNIT(x)	minor(x)
9424888Skarels 
95*33452Skarels int	hdhinit(), hdhoutput(), hdhreset();
9624888Skarels 
9724888Skarels /*
9824888Skarels  * "Lower half" of IMP interface driver.
9924888Skarels  *
10024888Skarels  * Each IMP interface is handled by a common module which handles
10124888Skarels  * the IMP-host protocol and a hardware driver which manages the
10224888Skarels  * hardware specific details of talking with the IMP.
10324888Skarels  *
10424888Skarels  * The hardware portion of the IMP driver handles DMA and related
10524888Skarels  * management of UNIBUS resources.  The IMP protocol module interprets
10624888Skarels  * contents of these messages and "controls" the actions of the
10724888Skarels  * hardware module during IMP resets, but not, for instance, during
10824888Skarels  * UNIBUS resets.
10924888Skarels  *
11024888Skarels  * The two modules are coupled at "attach time", and ever after,
11124888Skarels  * through the imp interface structure.  Higher level protocols,
11224888Skarels  * e.g. IP, interact with the IMP driver, rather than the HDH.
11324888Skarels  */
11424888Skarels 
11524888Skarels #define NHDHCH	2		/* no. of FDX channels for HDH */
11624888Skarels #define SUPR	0		/* supervisor channel */
11724888Skarels #define	DATA	1		/* data channel */
11824888Skarels #define HDHSUPR	0		/* supervisor read */
11924888Skarels #define HDHSUPW	1		/* supervisor write */
12024888Skarels #define HDHDATR	2		/* data read */
12124888Skarels #define HDHDATW	3		/* data write */
12224888Skarels 
12324888Skarels #define HDH_UP		2	/* HDH protocol is up */
12424888Skarels #define HDH_STARTED	1	/* HDH has been initialized */
12524888Skarels 
12624888Skarels #define HCBUSY	1		/* HDH HDX channel busy flag */
12724888Skarels 
12824888Skarels /*
12924888Skarels /* The IF-11/HDH has four independent dath flow channels between the
13024888Skarels /* front-end and the host.  Two are used for reading and writing
13124888Skarels /* control messages and two are used for data flow.  Each IF-11/HDH
13224888Skarels /* has a device dependent data structure (hdh_softc) which contains
13324888Skarels /* an array of four channel dependent structures (hdh_chan) to maintain
13424888Skarels /* the context of each channel.  Channel structures can be linked into
13524888Skarels /* a queue of I/O requests pending for the hardware interface.
13624888Skarels /* UNIBUS mapping resources are allocated for each channel pair.
13724888Skarels */
13824888Skarels 
13924888Skarels struct	hdh_chan {		/* HDH HDX channel structure */
14024888Skarels 	struct hdh_chan	*hc_next;	/* link for Start I/O queuing */
14124888Skarels 	char		hc_chan;	/* HDX chan number */
14224888Skarels 	char		hc_adx;		/* extended UNIBUS address bits */
14324888Skarels 	short		hc_addr;	/* lower UNIBUS address bits */
14424888Skarels 	short		hc_cnt;		/* byte count */
14524888Skarels 	char		hc_func;	/* UMC I/O function */
14624888Skarels 	char		hc_sbfc;	/* UMC I/O subfunction */
14724888Skarels 	short		hc_flags;	/* status flags */
14824888Skarels };
14924888Skarels 
15024888Skarels struct	hdh_sioq {		/* Start I/O queue head structure */
15124888Skarels 	struct hdh_chan *sioq_head;	/* pointer to queue head */
15224888Skarels 	struct hdh_chan *sioq_tail;	/* pointer to queue tail */
15324888Skarels };
15424888Skarels 
15524888Skarels struct	hdh_softc {		/* HDH device dependent structure */
156*33452Skarels 	struct imp_softc *hdh_imp;	/* pointer to IMP's imp_softc struct */
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;
17726392Skarels 	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 
215*33452Skarels 	if ((sc->hdh_imp = impattach(ui, hdhreset)) == 0)
21625461Skarels 		return;;
217*33452Skarels 	ip = &sc->hdh_imp->imp_cb;
21824888Skarels 	ip->ic_init = hdhinit;
219*33452Skarels 	ip->ic_output = hdhoutput;
22024888Skarels 	sc->hdh_ifuba[ui->ui_unit].ifu_flags = UBA_CANTWAIT;
22124888Skarels }
22224888Skarels 
22324888Skarels /*
22424888Skarels  * Reset interface after UNIBUS reset.
22524888Skarels  */
22624888Skarels hdhreset(unit, uban)
22724888Skarels int unit, uban;
22824888Skarels {
22924888Skarels 	register struct uba_device *ui = hdhinfo[unit];
23024888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
23124888Skarels 
23224888Skarels #ifdef HDHDEBUG
23324888Skarels 	printf("HDH RESET\n");
23424888Skarels #endif HDHDEBUG
23524888Skarels 
23624888Skarels 	if ((unit >= NHDH) || (ui == 0) || (ui->ui_alive == 0)
23724888Skarels 	    || (ui->ui_ubanum != uban))
23824888Skarels 		return;
23924888Skarels 	printf(" hdh%d", unit);
240*33452Skarels 	sc->hdh_imp->imp_if.if_flags &= ~IFF_RUNNING;
24125461Skarels 	sc->hdh_flags = 0;
242*33452Skarels 	(*sc->hdh_imp->imp_if.if_init)(sc->hdh_imp->imp_if.if_unit);
24324888Skarels }
24424888Skarels 
24524888Skarels /*
24624888Skarels  * Initialize the imp interface.
24724888Skarels  */
24824888Skarels 
24924888Skarels static char init_blk[] =
25024888Skarels     {
25124888Skarels 	HDHINIT,		/* SYSINIT opcode			*/
25224888Skarels 	HDHRQUP & 0xff,		/* control code (LSB)			*/
25324888Skarels 	(HDHRQUP>>8) & 0xff,	/* control code (MSB)			*/
25424888Skarels 	10,			/* command extension len		*/
25524888Skarels 	0,			/* loopback mode (off)			*/
25624888Skarels 	3,			/* our address (3=DTE)			*/
25724888Skarels 	1,			/* their address (1=DCE)		*/
25824888Skarels 	3,			/* frame ack t1 timeout			*/
25924888Skarels 	3,			/* poll ack timeout			*/
26024888Skarels 	30,			/* adm wait timeout			*/
26124888Skarels 	3,			/* rej wait timeout			*/
26224888Skarels 	10,			/* max retries				*/
26324888Skarels 	3,			/* watchdog timeout			*/
26424888Skarels 	0xaa			/* baud rate (0xaa=38.4KB)		*/
26524888Skarels 				/*   (output on RS-232 pin 24,		*/
26624888Skarels 				/*    send/receive timing is always	*/
26724888Skarels 				/*    taken from pins 15/17)		*/
26824888Skarels     };
26924888Skarels 
27024888Skarels hdhinit(unit)
27124888Skarels int unit;
27224888Skarels {
27324888Skarels 	register struct hdh_softc *sc;
27424888Skarels 	register struct uba_device *ui;
27526283Skarels 	int i;
27624888Skarels 
27724888Skarels #ifdef HDHDEBUG
27824888Skarels 	printf("HDH INIT\n");
27924888Skarels #endif HDHDEBUG
28024888Skarels 
28124888Skarels 	if (unit >= NHDH || (ui = hdhinfo[unit]) == NULL
28224888Skarels 	    || ui->ui_alive == 0) {
28324888Skarels 		printf("hdh%d: not alive\n", unit);
28424888Skarels 		return(0);
28524888Skarels 	}
28624888Skarels 	sc = &hdh_softc[unit];
28724888Skarels 
28825461Skarels 	if (sc->hdh_flags & HDH_STARTED)
28924888Skarels 		return(1);
29024888Skarels 
29124888Skarels 	/*
29224888Skarels 	 * Alloc uba resources
29324888Skarels 	 */
294*33452Skarels 	if ((sc->hdh_imp->imp_if.if_flags & IFF_RUNNING) == 0)
295*33452Skarels 	    for(i=0;i<NHDHCH;i++) {
29624888Skarels 		if (if_ubainit(&sc->hdh_ifuba[i], ui->ui_ubanum, 0,
297*33452Skarels 		    (int)btoc(IMP_RCVBUF)) == 0) {
29824888Skarels 			printf("hdh%d: cannot get chan %d uba resources\n",
29924888Skarels 				unit, i);
30024888Skarels 			ui->ui_alive = 0;
30124888Skarels 			return(0);
30224888Skarels 		}
30324888Skarels 	}
30424888Skarels 
305*33452Skarels 	sc->hdh_imp->imp_if.if_flags |= IFF_RUNNING;
30624888Skarels 	sc->hdh_flags = HDH_STARTED;
30724888Skarels 
30824888Skarels 	/*
30924888Skarels 	 * hang a supervisor read (for line status)
31024888Skarels 	 */
311*33452Skarels 	hdh_iorq(unit, HDHSUPR, IMP_RCVBUF, HDHRDB);
31224888Skarels 
31324888Skarels 	/*
31424888Skarels 	 * hang a data read
31524888Skarels 	 */
316*33452Skarels 	hdh_iorq(unit, HDHDATR, IMP_RCVBUF, HDHRDB+HDHSTR);
31724888Skarels 
31824888Skarels 	/*
31924888Skarels 	 * bring up line to IMP
32024888Skarels 	 */
32124888Skarels 
32224888Skarels 	snd_supr(unit, init_blk, sizeof(init_blk));
32324888Skarels 
32424888Skarels 	return(1);
32524888Skarels }
32624888Skarels 
32724888Skarels /*
32824888Skarels  * Start an output operation on an mbuf.
32924888Skarels  */
330*33452Skarels hdhoutput(unit, m)
331*33452Skarels 	int unit;
332*33452Skarels 	struct mbuf *m;
33324888Skarels {
33424888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
33524888Skarels         int len;
33624888Skarels 
33724888Skarels 	/*
33824888Skarels 	 * If output isn't active, attempt to
33924888Skarels 	 * start sending a new packet.
34024888Skarels 	 */
34124888Skarels 
342*33452Skarels 	if (sc->hdh_imp->imp_cb.ic_oactive) {
34324888Skarels 		printf("hdh%d: start on active unit\n", unit);
34424888Skarels 		return;
34524888Skarels 	}
34624888Skarels 
34724888Skarels 	if ((sc->hdh_flags & HDH_UP) == 0) {
348*33452Skarels 		/* Link not up, can't xmit */
34924888Skarels 		return;
35024888Skarels 	}
35124888Skarels 
35224888Skarels 	len = if_wubaput(&sc->hdh_ifuba[DATA], m);	/* copy data to mapped mem */
353*33452Skarels 	sc->hdh_imp->imp_cb.ic_oactive = 1;
35424888Skarels 
35524888Skarels 	hdh_iorq(unit, HDHDATW, len, HDHWRT+HDHEOS);
35624888Skarels }
35724888Skarels 
35824888Skarels /*
35924888Skarels  * Start i/o operation on a UMC logical channel
36024888Skarels  */
36124888Skarels hdh_iorq(unit, lcn, len, func)
36224888Skarels int unit, lcn, len, func;
36324888Skarels {
36424888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
36524888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
36624888Skarels 	register int info, s;
36724888Skarels 
36824888Skarels 	/*
36924888Skarels 	 * If channel is busy (shouldn't be), drop.
37024888Skarels 	 */
37124888Skarels 	if  (hc->hc_flags & HCBUSY) {
37224888Skarels 		printf("hdh%d: channel busy lcn=%d\n", unit, lcn);
37324888Skarels 		return;
37424888Skarels 	}
37524888Skarels 
37624888Skarels  	/* get appropriate UNIBUS mapping info */
37724888Skarels 
37824888Skarels 	if (lcn & 1)		/* read or write? */
37924888Skarels 		info = sc->hdh_ifuba[lcn>>1].ifu_w.ifrw_info;
38024888Skarels 	else
38124888Skarels 		info = sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_info;
38224888Skarels 
38324888Skarels 	/* set channel info */
38424888Skarels 
38524888Skarels 	hc->hc_flags |= HCBUSY;
38624888Skarels 	hc->hc_chan = lcn;
38724888Skarels 	hc->hc_adx = (char)((info & 0x30000) >> 12);
38824888Skarels 	hc->hc_addr = (unsigned short)(info & 0xffff);
38924888Skarels 	hc->hc_cnt = len;
39024888Skarels 	hc->hc_func = (char)func;
39124888Skarels 	hc->hc_sbfc = 0;
39224888Skarels 
39324888Skarels 	s = splimp();
39424888Skarels 	/*
39524888Skarels 	 * If UMC comm regs busy, queue start i/o for later.
39624888Skarels 	 */
39724888Skarels 	if (sc->hdh_sioq.sioq_head) {
39824888Skarels 		(sc->hdh_sioq.sioq_tail)->hc_next = hc;
39924888Skarels 		sc->hdh_sioq.sioq_tail = hc;
40024888Skarels 		hc->hc_next = 0;
40124888Skarels 		splx(s);
40224888Skarels 		return;
40324888Skarels 	}
40424888Skarels 
40524888Skarels 	/* start i/o on channel now */
40624888Skarels 
40724888Skarels 	sc->hdh_sioq.sioq_head = hc;
40824888Skarels 	sc->hdh_sioq.sioq_tail = hc;
40924888Skarels 	hc->hc_next = 0;
41024888Skarels 	start_chn(unit);
41124888Skarels 	splx(s);
41224888Skarels }
41324888Skarels 
41424888Skarels start_chn(unit)
41524888Skarels int unit;
41624888Skarels {
41724888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
41824888Skarels 	register struct hdh_chan *hc = sc->hdh_sioq.sioq_head;
41924888Skarels 	register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
42024888Skarels 
42124888Skarels 	/*
42224888Skarels 	 * Set up comm regs.
42324888Skarels 	 */
42424888Skarels 	addr->iochn = hc->hc_chan;
42524888Skarels 	addr->ioadx = hc->hc_adx;
42624888Skarels 	addr->ioadl = hc->hc_addr;
42724888Skarels 	addr->iocnt = hc->hc_cnt;
42824888Skarels 	addr->iofcn = hc->hc_func;
42924888Skarels 	addr->iosbf = hc->hc_sbfc;
43024888Skarels 	addr->ioini = 1;
43124888Skarels 
43224888Skarels 	/* signal UMC if necessary */
43324888Skarels 
43424888Skarels 	if (!(addr->ionmi)) {
43524888Skarels 		addr->ionmi = 1;
43624888Skarels 		addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
43724888Skarels 	}
43824888Skarels }
43924888Skarels 
44024888Skarels /*
44124888Skarels  * IF-11/HDH interrupt handler
44224888Skarels  */
44324888Skarels hdhintr(unit)
44424888Skarels int unit;
44524888Skarels {
44624888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
44724888Skarels 	register struct hdh_chan *hc;
44824888Skarels 	register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
44926283Skarels 	int lcn, type, cc, cnt;
45024888Skarels 
45124888Skarels 	/*
45224888Skarels 	 * Check for hardware errors.
45324888Skarels 	 */
45424888Skarels 	if (addr->csr & HDH_UER) {
45524888Skarels 		printf("hdh%d: hard error csr=%b\n", unit, addr->csr, HDH_BITS);
45624888Skarels 		addr->csr = 0;		/* disable i/f */
45724888Skarels 		return;
45824888Skarels 	}
45924888Skarels 	/*
46024888Skarels 	 * Get logical channel info.
46124888Skarels 	 */
46224888Skarels 	if ((lcn = addr->stachn) >= (NHDHCH*2)) {
46324888Skarels 		printf("hdh%d: unknown channel lcn=%d\n", unit, lcn);
46424888Skarels 		return;
46524888Skarels 	}
46624888Skarels 
46724888Skarels 	hc = &sc->hdh_chan[lcn];
46824888Skarels 
46924888Skarels 	type = addr->statyp;
47024888Skarels 	cc = addr->stacc;
47124888Skarels 	cnt = hc->hc_cnt - addr->stacnt;
47224888Skarels 
47324888Skarels 	/* Figure out what kind of interrupt it was */
47424888Skarels 
47524888Skarels 	switch(type) {
47624888Skarels 
47724888Skarels 	case HDHSACK:		/* start i/o accepted */
47824888Skarels 		if (hc != sc->hdh_sioq.sioq_head) {
47924888Skarels 			printf("hdh%d: STARTIO error lcn=%d hc=%x sq=%x\n",
48024888Skarels 				unit, lcn, hc, sc->hdh_sioq.sioq_head);
48124888Skarels 			return;
48224888Skarels 		}
48324888Skarels 
48424888Skarels 		/* try to start any queued i/o request */
48524888Skarels 
48624888Skarels 		if (sc->hdh_sioq.sioq_head = sc->hdh_sioq.sioq_head->hc_next) {
48724888Skarels 			start_chn(unit);
48824888Skarels 		}
48924888Skarels 		break;
49024888Skarels 
49124888Skarels 	case HDHDONE:		/* i/o completion */
49224888Skarels 		switch (cc) {
49324888Skarels 
49424888Skarels 		case HDHIOCABT:
49524888Skarels 			printf("hdh%d: I/O abort ", unit);
49624888Skarels 			goto daterr;
49724888Skarels 
49824888Skarels 		case HDHIOCERR:
49924888Skarels 			printf("hdh%d: program error ", unit);
50024888Skarels 			goto daterr;
50124888Skarels 
50224888Skarels 		case HDHIOCOVR:
50324888Skarels 			printf("hdh%d: overrun error ", unit);
50424888Skarels 			goto daterr;
50524888Skarels 
50624888Skarels 		case HDHIOCUBE:
50724888Skarels 			printf("hdh%d: NXM timeout or UB parity error ", unit);
50824888Skarels 
50924888Skarels 		daterr:
51024888Skarels 			printf("lcn=%d func=%x\n", lcn, hc->hc_func);
51124888Skarels 			if (hc->hc_func & HDHRDB)
512*33452Skarels 				sc->hdh_imp->imp_if.if_ierrors++;
51324888Skarels 			else
514*33452Skarels 				sc->hdh_imp->imp_if.if_oerrors++;
51524888Skarels 		}
51624888Skarels 
51724888Skarels 		hc->hc_flags &= ~HCBUSY;
51824888Skarels 
51924888Skarels 		/* was it supervisor or data traffic? */
52024888Skarels 
52124888Skarels 		if (lcn > HDHSUPW)
52224888Skarels 			hdh_data(unit, lcn, cc, cnt);
52324888Skarels 		else
52426310Skarels 			hdh_supr(unit, lcn, cc);
52524888Skarels 
52624888Skarels 	}
52724888Skarels 
52824888Skarels 	/*
52924888Skarels 	 * Ack the interrupt
53024888Skarels 	 */
53124888Skarels 	addr->staack = 1;
53224888Skarels 	if (!(addr->ionmi)) {
53324888Skarels 		addr->ionmi = 1;
53424888Skarels 		addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
53524888Skarels 	}
53624888Skarels }
53724888Skarels 
53824888Skarels /*
53924888Skarels  * data channel interrupt completion handler
54024888Skarels  */
54124888Skarels hdh_data(unit, lcn, cc, rcnt)
54224888Skarels int unit, lcn, cc, rcnt;
54324888Skarels {
54424888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
54524888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
54624888Skarels 	register struct mbuf *m;
54724888Skarels 
54824888Skarels 
54924888Skarels 	/* was it read or write? */
55024888Skarels 
55124888Skarels 	if (hc->hc_func & HDHRDB) {
55224888Skarels 		if (cc == HDHIOCOK) {
55324888Skarels 			/*
55424888Skarels 			 * Queue good packet for input
55524888Skarels 			 */
556*33452Skarels 			sc->hdh_imp->imp_if.if_ipackets++;
55725461Skarels 			m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0,
558*33452Skarels 				&sc->hdh_imp->imp_if);
55924888Skarels 			impinput(unit, m);
56024888Skarels 		}
56124888Skarels 
56224888Skarels 		/* hang a new data read */
56324888Skarels 
564*33452Skarels 		hdh_iorq(unit, lcn, IMP_RCVBUF, HDHRDB+HDHSTR);
56524888Skarels 
56624888Skarels 	} else {
56724888Skarels 		/*
56824888Skarels 		 * fire up next output
56924888Skarels 		 */
570*33452Skarels 		sc->hdh_imp->imp_if.if_opackets++;
571*33452Skarels 		sc->hdh_imp->imp_cb.ic_oactive = 0;
572*33452Skarels 		impstart(sc->hdh_imp->imp_if.if_unit);
57324888Skarels 	}
57424888Skarels }
57524888Skarels 
57624888Skarels /*
57724888Skarels  * supervisor channel interrupt completion handler
57824888Skarels  */
57926310Skarels hdh_supr(unit, lcn, cc)
58026310Skarels int unit, lcn, cc;
58124888Skarels {
58224888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
58324888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
58424888Skarels 	short *p;
58524888Skarels 
58624888Skarels 
58724888Skarels 	/* was it read or write? */
58824888Skarels 
58924888Skarels 	if (hc->hc_func & HDHRDB) {
59024888Skarels 		if (cc == HDHIOCOK) {
59124888Skarels 			p = (short *)(sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_addr);
59224888Skarels 
59324888Skarels 			/* figure out what kind of supervisor message */
59424888Skarels 
59524888Skarels 			switch (*p) {
59624888Skarels 
59724888Skarels 			case HDHIACK:
59824888Skarels 			case HDHLNACK:
59924888Skarels 				break;
60024888Skarels 
60124888Skarels 			case HDHLNUP:
60224888Skarels 				printf("hdh%d: LINE UP\n", unit);
60324888Skarels 				sc->hdh_flags |= HDH_UP;
604*33452Skarels 				impstart(sc->hdh_imp->imp_if.if_unit);
60524888Skarels 				break;
60624888Skarels 
60724888Skarels 			case HDHLNDN:
60824888Skarels 				if (sc->hdh_flags & HDH_UP)
60924888Skarels 					printf("hdh%d: LINE DOWN\n", unit);
61024888Skarels 				sc->hdh_flags &= ~HDH_UP;
61124888Skarels 				break;
61224888Skarels 
61324888Skarels 			case HDHLOOP:
61424888Skarels 				break;
61524888Skarels 
61624888Skarels 			case HDHSQERR:
61724888Skarels 				printf("hdh%d: HOST SEQUENCE ERROR\n", unit);
61824888Skarels 				break;
61924888Skarels 
62024888Skarels 			case HDHSQRCV:
62124888Skarels 				printf("hdh%d: IMP SEQUENCE ERROR\n", unit);
62224888Skarels 				break;
62324888Skarels 
62424888Skarels 			case HDHDTERR:
62524888Skarels 				printf("hdh%d: HOST DATA ERROR\n", unit);
62624888Skarels 				break;
62724888Skarels 
62824888Skarels 			case HDHTIMO:
62924888Skarels 				printf("hdh%d: TIMEOUT\n", unit);
63024888Skarels 				break;
63124888Skarels 
63224888Skarels 			default:
63324888Skarels 				printf("hdh%d: supervisor error, code=%x\n",
63424888Skarels 					unit, *p);
63524888Skarels 			}
63624888Skarels 		}
63724888Skarels 
63824888Skarels 		/* hang a new supr read */
63924888Skarels 
640*33452Skarels 		hdh_iorq(unit, HDHSUPR, IMP_RCVBUF, HDHRDB+HDHSTR);
64124888Skarels 	}
64224888Skarels }
64324888Skarels 
64424888Skarels snd_supr(unit, msg, len)
64524888Skarels int unit, len;
64624888Skarels char *msg;
64724888Skarels {
64824888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
64924888Skarels 	register struct mbuf *m;
65024888Skarels 	register char *p;
65124888Skarels 	register int cnt;
65224888Skarels 
65324888Skarels 	if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) {
65424888Skarels 		printf("hdh%d: cannot get supervisor cmnd buffer\n", unit);
65528951Skarels 			return;
65624888Skarels 	}
65724888Skarels 
65824888Skarels 	cnt = len;
65924888Skarels 	m->m_len = len;
66024888Skarels 	p = mtod(m, char *);
66124888Skarels 
66224888Skarels 	while(cnt--) *p++ = *msg++;
66324888Skarels 
66424888Skarels 	cnt = if_wubaput(&sc->hdh_ifuba[SUPR], m);
66524888Skarels 
66624888Skarels 	hdh_iorq(unit, HDHSUPW, cnt, HDHWRT+HDHEOS);
66724888Skarels }
66824888Skarels #endif NHDH
669