xref: /csrg-svn/sys/vax/if/if_hdh.c (revision 45801)
1*45801Sbostic /*	@(#)if_hdh.c	7.7 (Berkeley) 12/16/90 */
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:
4533452Skarels 		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 
66*45801Sbostic #include "sys/param.h"
67*45801Sbostic #include "sys/systm.h"
68*45801Sbostic #include "sys/mbuf.h"
69*45801Sbostic #include "sys/buf.h"
70*45801Sbostic #include "sys/protosw.h"
71*45801Sbostic #include "sys/socket.h"
72*45801Sbostic #include "sys/vmmac.h"
7324888Skarels 
74*45801Sbostic #include "../include/pte.h"
7533452Skarels 
76*45801Sbostic #include "net/if.h"
77*45801Sbostic #include "netimp/if_imp.h"
7824888Skarels 
79*45801Sbostic #include "../include/cpu.h"
80*45801Sbostic #include "../include/mtpr.h"
81*45801Sbostic #include "../uba/ubareg.h"
82*45801Sbostic #include "../uba/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 
9533452Skarels 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 */
15633452Skarels 	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  */
hdhprobe(reg)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  */
hdhattach(ui)20924888Skarels hdhattach(ui)
21034273Skarels 	register struct uba_device *ui;
21124888Skarels {
21224888Skarels 	register struct hdh_softc *sc = &hdh_softc[ui->ui_unit];
21324888Skarels 	register struct impcb *ip;
21424888Skarels 
21534273Skarels 	if ((sc->hdh_imp = impattach(ui->ui_driver->ud_dname, ui->ui_unit,
21634273Skarels 	    hdhreset)) == 0)
21734273Skarels 		return;
21833452Skarels 	ip = &sc->hdh_imp->imp_cb;
21924888Skarels 	ip->ic_init = hdhinit;
22033452Skarels 	ip->ic_output = hdhoutput;
22124888Skarels 	sc->hdh_ifuba[ui->ui_unit].ifu_flags = UBA_CANTWAIT;
22224888Skarels }
22324888Skarels 
22424888Skarels /*
22524888Skarels  * Reset interface after UNIBUS reset.
22624888Skarels  */
hdhreset(unit,uban)22724888Skarels hdhreset(unit, uban)
22824888Skarels int unit, uban;
22924888Skarels {
23024888Skarels 	register struct uba_device *ui = hdhinfo[unit];
23124888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
23224888Skarels 
23324888Skarels #ifdef HDHDEBUG
23424888Skarels 	printf("HDH RESET\n");
23524888Skarels #endif HDHDEBUG
23624888Skarels 
23724888Skarels 	if ((unit >= NHDH) || (ui == 0) || (ui->ui_alive == 0)
23824888Skarels 	    || (ui->ui_ubanum != uban))
23924888Skarels 		return;
24024888Skarels 	printf(" hdh%d", unit);
24133452Skarels 	sc->hdh_imp->imp_if.if_flags &= ~IFF_RUNNING;
24234273Skarels 	sc->hdh_imp->imp_cb.ic_oactive = 0;
24325461Skarels 	sc->hdh_flags = 0;
24433452Skarels 	(*sc->hdh_imp->imp_if.if_init)(sc->hdh_imp->imp_if.if_unit);
24524888Skarels }
24624888Skarels 
24724888Skarels /*
24824888Skarels  * Initialize the imp interface.
24924888Skarels  */
25024888Skarels 
25124888Skarels static char init_blk[] =
25224888Skarels     {
25324888Skarels 	HDHINIT,		/* SYSINIT opcode			*/
25424888Skarels 	HDHRQUP & 0xff,		/* control code (LSB)			*/
25524888Skarels 	(HDHRQUP>>8) & 0xff,	/* control code (MSB)			*/
25624888Skarels 	10,			/* command extension len		*/
25724888Skarels 	0,			/* loopback mode (off)			*/
25824888Skarels 	3,			/* our address (3=DTE)			*/
25924888Skarels 	1,			/* their address (1=DCE)		*/
26024888Skarels 	3,			/* frame ack t1 timeout			*/
26124888Skarels 	3,			/* poll ack timeout			*/
26224888Skarels 	30,			/* adm wait timeout			*/
26324888Skarels 	3,			/* rej wait timeout			*/
26424888Skarels 	10,			/* max retries				*/
26524888Skarels 	3,			/* watchdog timeout			*/
26624888Skarels 	0xaa			/* baud rate (0xaa=38.4KB)		*/
26724888Skarels 				/*   (output on RS-232 pin 24,		*/
26824888Skarels 				/*    send/receive timing is always	*/
26924888Skarels 				/*    taken from pins 15/17)		*/
27024888Skarels     };
27124888Skarels 
hdhinit(unit)27224888Skarels hdhinit(unit)
27324888Skarels int unit;
27424888Skarels {
27524888Skarels 	register struct hdh_softc *sc;
27624888Skarels 	register struct uba_device *ui;
27726283Skarels 	int i;
27824888Skarels 
27924888Skarels #ifdef HDHDEBUG
28024888Skarels 	printf("HDH INIT\n");
28124888Skarels #endif HDHDEBUG
28224888Skarels 
28324888Skarels 	if (unit >= NHDH || (ui = hdhinfo[unit]) == NULL
28424888Skarels 	    || ui->ui_alive == 0) {
28524888Skarels 		printf("hdh%d: not alive\n", unit);
28624888Skarels 		return(0);
28724888Skarels 	}
28824888Skarels 	sc = &hdh_softc[unit];
28924888Skarels 
29025461Skarels 	if (sc->hdh_flags & HDH_STARTED)
29124888Skarels 		return(1);
29224888Skarels 
29324888Skarels 	/*
29424888Skarels 	 * Alloc uba resources
29524888Skarels 	 */
29633452Skarels 	if ((sc->hdh_imp->imp_if.if_flags & IFF_RUNNING) == 0)
29733452Skarels 	    for(i=0;i<NHDHCH;i++) {
29824888Skarels 		if (if_ubainit(&sc->hdh_ifuba[i], ui->ui_ubanum, 0,
29933452Skarels 		    (int)btoc(IMP_RCVBUF)) == 0) {
30024888Skarels 			printf("hdh%d: cannot get chan %d uba resources\n",
30124888Skarels 				unit, i);
30224888Skarels 			ui->ui_alive = 0;
30324888Skarels 			return(0);
30424888Skarels 		}
30524888Skarels 	}
30624888Skarels 
30733452Skarels 	sc->hdh_imp->imp_if.if_flags |= IFF_RUNNING;
30824888Skarels 	sc->hdh_flags = HDH_STARTED;
30924888Skarels 
31024888Skarels 	/*
31124888Skarels 	 * hang a supervisor read (for line status)
31224888Skarels 	 */
31333452Skarels 	hdh_iorq(unit, HDHSUPR, IMP_RCVBUF, HDHRDB);
31424888Skarels 
31524888Skarels 	/*
31624888Skarels 	 * hang a data read
31724888Skarels 	 */
31833452Skarels 	hdh_iorq(unit, HDHDATR, IMP_RCVBUF, HDHRDB+HDHSTR);
31924888Skarels 
32024888Skarels 	/*
32124888Skarels 	 * bring up line to IMP
32224888Skarels 	 */
32324888Skarels 
32424888Skarels 	snd_supr(unit, init_blk, sizeof(init_blk));
32524888Skarels 
32624888Skarels 	return(1);
32724888Skarels }
32824888Skarels 
32924888Skarels /*
33024888Skarels  * Start an output operation on an mbuf.
33124888Skarels  */
hdhoutput(unit,m)33233452Skarels hdhoutput(unit, m)
33333452Skarels 	int unit;
33433452Skarels 	struct mbuf *m;
33524888Skarels {
33624888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
33724888Skarels         int len;
33824888Skarels 
33924888Skarels 	/*
34024888Skarels 	 * If output isn't active, attempt to
34124888Skarels 	 * start sending a new packet.
34224888Skarels 	 */
34324888Skarels 
34433452Skarels 	if (sc->hdh_imp->imp_cb.ic_oactive) {
34524888Skarels 		printf("hdh%d: start on active unit\n", unit);
34624888Skarels 		return;
34724888Skarels 	}
34824888Skarels 
34924888Skarels 	if ((sc->hdh_flags & HDH_UP) == 0) {
35033452Skarels 		/* Link not up, can't xmit */
35124888Skarels 		return;
35224888Skarels 	}
35324888Skarels 
35424888Skarels 	len = if_wubaput(&sc->hdh_ifuba[DATA], m);	/* copy data to mapped mem */
35533452Skarels 	sc->hdh_imp->imp_cb.ic_oactive = 1;
35624888Skarels 
35724888Skarels 	hdh_iorq(unit, HDHDATW, len, HDHWRT+HDHEOS);
35824888Skarels }
35924888Skarels 
36024888Skarels /*
36124888Skarels  * Start i/o operation on a UMC logical channel
36224888Skarels  */
hdh_iorq(unit,lcn,len,func)36324888Skarels hdh_iorq(unit, lcn, len, func)
36424888Skarels int unit, lcn, len, func;
36524888Skarels {
36624888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
36724888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
36824888Skarels 	register int info, s;
36924888Skarels 
37024888Skarels 	/*
37124888Skarels 	 * If channel is busy (shouldn't be), drop.
37224888Skarels 	 */
37324888Skarels 	if  (hc->hc_flags & HCBUSY) {
37424888Skarels 		printf("hdh%d: channel busy lcn=%d\n", unit, lcn);
37524888Skarels 		return;
37624888Skarels 	}
37724888Skarels 
37824888Skarels  	/* get appropriate UNIBUS mapping info */
37924888Skarels 
38024888Skarels 	if (lcn & 1)		/* read or write? */
38124888Skarels 		info = sc->hdh_ifuba[lcn>>1].ifu_w.ifrw_info;
38224888Skarels 	else
38324888Skarels 		info = sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_info;
38424888Skarels 
38524888Skarels 	/* set channel info */
38624888Skarels 
38724888Skarels 	hc->hc_flags |= HCBUSY;
38824888Skarels 	hc->hc_chan = lcn;
38924888Skarels 	hc->hc_adx = (char)((info & 0x30000) >> 12);
39024888Skarels 	hc->hc_addr = (unsigned short)(info & 0xffff);
39124888Skarels 	hc->hc_cnt = len;
39224888Skarels 	hc->hc_func = (char)func;
39324888Skarels 	hc->hc_sbfc = 0;
39424888Skarels 
39524888Skarels 	s = splimp();
39624888Skarels 	/*
39724888Skarels 	 * If UMC comm regs busy, queue start i/o for later.
39824888Skarels 	 */
39924888Skarels 	if (sc->hdh_sioq.sioq_head) {
40024888Skarels 		(sc->hdh_sioq.sioq_tail)->hc_next = hc;
40124888Skarels 		sc->hdh_sioq.sioq_tail = hc;
40224888Skarels 		hc->hc_next = 0;
40324888Skarels 		splx(s);
40424888Skarels 		return;
40524888Skarels 	}
40624888Skarels 
40724888Skarels 	/* start i/o on channel now */
40824888Skarels 
40924888Skarels 	sc->hdh_sioq.sioq_head = hc;
41024888Skarels 	sc->hdh_sioq.sioq_tail = hc;
41124888Skarels 	hc->hc_next = 0;
41224888Skarels 	start_chn(unit);
41324888Skarels 	splx(s);
41424888Skarels }
41524888Skarels 
start_chn(unit)41624888Skarels start_chn(unit)
41724888Skarels int unit;
41824888Skarels {
41924888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
42024888Skarels 	register struct hdh_chan *hc = sc->hdh_sioq.sioq_head;
42124888Skarels 	register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
42224888Skarels 
42324888Skarels 	/*
42424888Skarels 	 * Set up comm regs.
42524888Skarels 	 */
42624888Skarels 	addr->iochn = hc->hc_chan;
42724888Skarels 	addr->ioadx = hc->hc_adx;
42824888Skarels 	addr->ioadl = hc->hc_addr;
42924888Skarels 	addr->iocnt = hc->hc_cnt;
43024888Skarels 	addr->iofcn = hc->hc_func;
43124888Skarels 	addr->iosbf = hc->hc_sbfc;
43224888Skarels 	addr->ioini = 1;
43324888Skarels 
43424888Skarels 	/* signal UMC if necessary */
43524888Skarels 
43624888Skarels 	if (!(addr->ionmi)) {
43724888Skarels 		addr->ionmi = 1;
43824888Skarels 		addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
43924888Skarels 	}
44024888Skarels }
44124888Skarels 
44224888Skarels /*
44324888Skarels  * IF-11/HDH interrupt handler
44424888Skarels  */
hdhintr(unit)44524888Skarels hdhintr(unit)
44624888Skarels int unit;
44724888Skarels {
44824888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
44924888Skarels 	register struct hdh_chan *hc;
45024888Skarels 	register struct hdhregs *addr = (struct hdhregs *)hdhinfo[unit]->ui_addr;
45126283Skarels 	int lcn, type, cc, cnt;
45224888Skarels 
45324888Skarels 	/*
45424888Skarels 	 * Check for hardware errors.
45524888Skarels 	 */
45624888Skarels 	if (addr->csr & HDH_UER) {
45724888Skarels 		printf("hdh%d: hard error csr=%b\n", unit, addr->csr, HDH_BITS);
45824888Skarels 		addr->csr = 0;		/* disable i/f */
45924888Skarels 		return;
46024888Skarels 	}
46124888Skarels 	/*
46224888Skarels 	 * Get logical channel info.
46324888Skarels 	 */
46424888Skarels 	if ((lcn = addr->stachn) >= (NHDHCH*2)) {
46524888Skarels 		printf("hdh%d: unknown channel lcn=%d\n", unit, lcn);
46624888Skarels 		return;
46724888Skarels 	}
46824888Skarels 
46924888Skarels 	hc = &sc->hdh_chan[lcn];
47024888Skarels 
47124888Skarels 	type = addr->statyp;
47224888Skarels 	cc = addr->stacc;
47324888Skarels 	cnt = hc->hc_cnt - addr->stacnt;
47424888Skarels 
47524888Skarels 	/* Figure out what kind of interrupt it was */
47624888Skarels 
47724888Skarels 	switch(type) {
47824888Skarels 
47924888Skarels 	case HDHSACK:		/* start i/o accepted */
48024888Skarels 		if (hc != sc->hdh_sioq.sioq_head) {
48124888Skarels 			printf("hdh%d: STARTIO error lcn=%d hc=%x sq=%x\n",
48224888Skarels 				unit, lcn, hc, sc->hdh_sioq.sioq_head);
48324888Skarels 			return;
48424888Skarels 		}
48524888Skarels 
48624888Skarels 		/* try to start any queued i/o request */
48724888Skarels 
48824888Skarels 		if (sc->hdh_sioq.sioq_head = sc->hdh_sioq.sioq_head->hc_next) {
48924888Skarels 			start_chn(unit);
49024888Skarels 		}
49124888Skarels 		break;
49224888Skarels 
49324888Skarels 	case HDHDONE:		/* i/o completion */
49424888Skarels 		switch (cc) {
49524888Skarels 
49624888Skarels 		case HDHIOCABT:
49724888Skarels 			printf("hdh%d: I/O abort ", unit);
49824888Skarels 			goto daterr;
49924888Skarels 
50024888Skarels 		case HDHIOCERR:
50124888Skarels 			printf("hdh%d: program error ", unit);
50224888Skarels 			goto daterr;
50324888Skarels 
50424888Skarels 		case HDHIOCOVR:
50524888Skarels 			printf("hdh%d: overrun error ", unit);
50624888Skarels 			goto daterr;
50724888Skarels 
50824888Skarels 		case HDHIOCUBE:
50924888Skarels 			printf("hdh%d: NXM timeout or UB parity error ", unit);
51024888Skarels 
51124888Skarels 		daterr:
51224888Skarels 			printf("lcn=%d func=%x\n", lcn, hc->hc_func);
51324888Skarels 			if (hc->hc_func & HDHRDB)
51433452Skarels 				sc->hdh_imp->imp_if.if_ierrors++;
51524888Skarels 			else
51633452Skarels 				sc->hdh_imp->imp_if.if_oerrors++;
51724888Skarels 		}
51824888Skarels 
51924888Skarels 		hc->hc_flags &= ~HCBUSY;
52024888Skarels 
52124888Skarels 		/* was it supervisor or data traffic? */
52224888Skarels 
52324888Skarels 		if (lcn > HDHSUPW)
52424888Skarels 			hdh_data(unit, lcn, cc, cnt);
52524888Skarels 		else
52626310Skarels 			hdh_supr(unit, lcn, cc);
52724888Skarels 
52824888Skarels 	}
52924888Skarels 
53024888Skarels 	/*
53124888Skarels 	 * Ack the interrupt
53224888Skarels 	 */
53324888Skarels 	addr->staack = 1;
53424888Skarels 	if (!(addr->ionmi)) {
53524888Skarels 		addr->ionmi = 1;
53624888Skarels 		addr->csr = HDH_DMA|HDH_WRT|HDH_IEN|HDH_NMI;
53724888Skarels 	}
53824888Skarels }
53924888Skarels 
54024888Skarels /*
54124888Skarels  * data channel interrupt completion handler
54224888Skarels  */
hdh_data(unit,lcn,cc,rcnt)54324888Skarels hdh_data(unit, lcn, cc, rcnt)
54424888Skarels int unit, lcn, cc, rcnt;
54524888Skarels {
54624888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
54724888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
54824888Skarels 	register struct mbuf *m;
54924888Skarels 
55024888Skarels 
55124888Skarels 	/* was it read or write? */
55224888Skarels 
55324888Skarels 	if (hc->hc_func & HDHRDB) {
55424888Skarels 		if (cc == HDHIOCOK) {
55524888Skarels 			/*
55624888Skarels 			 * Queue good packet for input
55724888Skarels 			 */
55833452Skarels 			sc->hdh_imp->imp_if.if_ipackets++;
55925461Skarels 			m = if_rubaget(&sc->hdh_ifuba[lcn>>1], rcnt, 0,
56033452Skarels 				&sc->hdh_imp->imp_if);
56124888Skarels 			impinput(unit, m);
56224888Skarels 		}
56324888Skarels 
56424888Skarels 		/* hang a new data read */
56524888Skarels 
56633452Skarels 		hdh_iorq(unit, lcn, IMP_RCVBUF, HDHRDB+HDHSTR);
56724888Skarels 
56824888Skarels 	} else {
56924888Skarels 		/*
57024888Skarels 		 * fire up next output
57124888Skarels 		 */
57233452Skarels 		sc->hdh_imp->imp_if.if_opackets++;
57333452Skarels 		sc->hdh_imp->imp_cb.ic_oactive = 0;
57434503Skarels 		impstart(sc->hdh_imp);
57524888Skarels 	}
57624888Skarels }
57724888Skarels 
57824888Skarels /*
57924888Skarels  * supervisor channel interrupt completion handler
58024888Skarels  */
hdh_supr(unit,lcn,cc)58126310Skarels hdh_supr(unit, lcn, cc)
58226310Skarels int unit, lcn, cc;
58324888Skarels {
58424888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
58524888Skarels 	register struct hdh_chan *hc = &sc->hdh_chan[lcn];
58624888Skarels 	short *p;
58724888Skarels 
58824888Skarels 
58924888Skarels 	/* was it read or write? */
59024888Skarels 
59124888Skarels 	if (hc->hc_func & HDHRDB) {
59224888Skarels 		if (cc == HDHIOCOK) {
59324888Skarels 			p = (short *)(sc->hdh_ifuba[lcn>>1].ifu_r.ifrw_addr);
59424888Skarels 
59524888Skarels 			/* figure out what kind of supervisor message */
59624888Skarels 
59724888Skarels 			switch (*p) {
59824888Skarels 
59924888Skarels 			case HDHIACK:
60024888Skarels 			case HDHLNACK:
60124888Skarels 				break;
60224888Skarels 
60324888Skarels 			case HDHLNUP:
60424888Skarels 				printf("hdh%d: LINE UP\n", unit);
60524888Skarels 				sc->hdh_flags |= HDH_UP;
60634503Skarels 				impstart(sc->hdh_imp);
60724888Skarels 				break;
60824888Skarels 
60924888Skarels 			case HDHLNDN:
61024888Skarels 				if (sc->hdh_flags & HDH_UP)
61124888Skarels 					printf("hdh%d: LINE DOWN\n", unit);
61224888Skarels 				sc->hdh_flags &= ~HDH_UP;
61324888Skarels 				break;
61424888Skarels 
61524888Skarels 			case HDHLOOP:
61624888Skarels 				break;
61724888Skarels 
61824888Skarels 			case HDHSQERR:
61924888Skarels 				printf("hdh%d: HOST SEQUENCE ERROR\n", unit);
62024888Skarels 				break;
62124888Skarels 
62224888Skarels 			case HDHSQRCV:
62324888Skarels 				printf("hdh%d: IMP SEQUENCE ERROR\n", unit);
62424888Skarels 				break;
62524888Skarels 
62624888Skarels 			case HDHDTERR:
62724888Skarels 				printf("hdh%d: HOST DATA ERROR\n", unit);
62824888Skarels 				break;
62924888Skarels 
63024888Skarels 			case HDHTIMO:
63124888Skarels 				printf("hdh%d: TIMEOUT\n", unit);
63224888Skarels 				break;
63324888Skarels 
63424888Skarels 			default:
63524888Skarels 				printf("hdh%d: supervisor error, code=%x\n",
63624888Skarels 					unit, *p);
63724888Skarels 			}
63824888Skarels 		}
63924888Skarels 
64024888Skarels 		/* hang a new supr read */
64124888Skarels 
64233452Skarels 		hdh_iorq(unit, HDHSUPR, IMP_RCVBUF, HDHRDB+HDHSTR);
64324888Skarels 	}
64424888Skarels }
64524888Skarels 
snd_supr(unit,msg,len)64624888Skarels snd_supr(unit, msg, len)
64724888Skarels int unit, len;
64824888Skarels char *msg;
64924888Skarels {
65024888Skarels 	register struct hdh_softc *sc = &hdh_softc[unit];
65124888Skarels 	register struct mbuf *m;
65224888Skarels 	register char *p;
65324888Skarels 	register int cnt;
65424888Skarels 
65524888Skarels 	if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) {
65624888Skarels 		printf("hdh%d: cannot get supervisor cmnd buffer\n", unit);
65728951Skarels 			return;
65824888Skarels 	}
65924888Skarels 
66024888Skarels 	cnt = len;
66124888Skarels 	m->m_len = len;
66224888Skarels 	p = mtod(m, char *);
66324888Skarels 
66424888Skarels 	while(cnt--) *p++ = *msg++;
66524888Skarels 
66624888Skarels 	cnt = if_wubaput(&sc->hdh_ifuba[SUPR], m);
66724888Skarels 
66824888Skarels 	hdh_iorq(unit, HDHSUPW, cnt, HDHWRT+HDHEOS);
66924888Skarels }
67024888Skarels #endif NHDH
671