xref: /csrg-svn/sys/vax/datakit/dkit_kmc.c (revision 45800)
138623Skarels /*
238623Skarels  * Datakit driver
338623Skarels  * KMC assistance, with or without DR11C
4*45800Sbostic  *	@(#)dkit_kmc.c	1.4 (Berkeley) 12/16/90
538623Skarels  */
638623Skarels 
738623Skarels #include "dkitkmc.h"
838623Skarels #if NDKITKMC>0
938623Skarels 
1038623Skarels #include "datakit.h"
1138623Skarels 
12*45800Sbostic #include "../include/pte.h"
13*45800Sbostic #include "sys/param.h"
14*45800Sbostic #include "sys/syslog.h"
15*45800Sbostic #include "sys/time.h"
16*45800Sbostic #include "sys/kernel.h"
17*45800Sbostic #include "sys/buf.h"
18*45800Sbostic #include "sys/mbuf.h"
19*45800Sbostic #include "sys/errno.h"
20*45800Sbostic #include "sys/socket.h"
21*45800Sbostic #include "net/if.h"
22*45800Sbostic #include "../if/if_uba.h"
23*45800Sbostic #include "../uba/ubareg.h"
24*45800Sbostic #include "../uba/ubavar.h"
2538623Skarels 
2638623Skarels #include "dkit.h"
2738623Skarels #include "dkkmc.h"
2838623Skarels #include "dk.h"
2938623Skarels 
3038625Skarels #define KMXSMALL	0
3138625Skarels #define KMXBIG		1
3238625Skarels 
3338623Skarels #define	MONITOR	1
3438623Skarels 
3538623Skarels #ifdef	MONITOR
3638623Skarels static	int	dummy ;
3738623Skarels int	*DKP = &dummy ;
3838623Skarels #define	M_ON(a)		*DKP |= (a)
3938623Skarels #define M_OFF(a)	*DKP &= ~(a)
4038623Skarels #define	M_TRACE(a)	*DKP |= (a);*DKP &= ~(a)
4138623Skarels 
4238623Skarels #define	Mxmit	01
4338623Skarels #define	Mrecv	02
4438623Skarels #define	Mkint	04
4538623Skarels #define	Mint	010
4638623Skarels #define	Mcmd	020
4738623Skarels 
4838623Skarels #else
4938623Skarels #define	M_ON(a)
5038623Skarels #define	M_OFF(a)
5138623Skarels #define	M_TRACE(a)
5238623Skarels #endif
5338623Skarels 
5438623Skarels extern int		dk_nchan;
5538623Skarels 
5638623Skarels struct dkchan	dkit[NDATAKIT];
5738623Skarels 
5838623Skarels #define	DKNCMDB	20
5938623Skarels #define	DKNSTB	20
6038623Skarels 
6138623Skarels int dkk_ncmd = DKNCMDB;
6238623Skarels struct dkkin dkkcmdbuf[DKNCMDB];
6338623Skarels int dkk_nstat = DKNSTB;
6438623Skarels struct dkkin dkkstat[DKNSTB];
6538623Skarels char dkkbuf[16*1024];
6638623Skarels int dkubmbuf;
6738623Skarels 
6838623Skarels static struct kdevice *dkkaddr;
6938623Skarels 
7038623Skarels /*
7138623Skarels  * initial information to the KMC
7238623Skarels  */
7338623Skarels struct dkinit {
7438623Skarels 	caddr_t	cmdaddr;	/* command buffer */
7538623Skarels 	caddr_t	stataddr;	/* status buffer  */
7638623Skarels 	caddr_t	bufaddr ;	/* kmc workspace  */
7738623Skarels 	caddr_t	csraddr;	/* for KMC/DR DR register address */
7838623Skarels } dkkmcinit;
7938623Skarels 
8038623Skarels /*
8138623Skarels  * structure of data in first mbuf on chain (type DKM_HDR)
8238623Skarels  *
8338623Skarels  */
8438623Skarels struct	mpacket {
8538623Skarels 	short	mp_len;		/* Total length left */
8638623Skarels 	char	mp_ctl;		/* Control character */
8738623Skarels 	int	mp_eob;		/* Send end-of-block indicator */
8838623Skarels 	int	(*mp_endfcn)();	/* End-action function */
8938623Skarels 	caddr_t	mp_endparm;	/* Parameter to above function */
9038623Skarels };
9138623Skarels 
9238623Skarels 
9338623Skarels /*
9438623Skarels  * The circular buffer, cmdbuf, is used to pass command to kmc:
9538623Skarels  * while the circular buffer statbuf is used to report status.
9638623Skarels  * There are 8 control and status registers (csr) accessible to
9738623Skarels  * both cpu and kmc.
9838623Skarels  * Csr4-csr5 are used to indicate the head and tail respectively
9938623Skarels  * of the cmdbuf.  Likewise, csr6-csr7 for statbuf.
10038623Skarels  * At initialization time, the cpu and kmc would agree on the beginning
10138623Skarels  * address of both buffers and their sizes.
10238623Skarels  */
10338623Skarels #define	csr0	dkkaddr->un.bsel.bsel0	/* kmc state */
10438623Skarels #define	csr1	dkkaddr->un.bsel.bsel1
10538623Skarels #define	csr2	dkkaddr->un.bsel.bsel2	/* used at init time, to pass */
10638623Skarels #define	csr3	dkkaddr->un.bsel.bsel3	/* addresses to the kmc       */
10738623Skarels #define	csr4	dkkaddr->un.bsel.bsel4  /* head cmdbuf */
10838623Skarels #define	csr5	dkkaddr->un.bsel.bsel5  /* tail cmdbuf */
10938623Skarels #define	csr6	dkkaddr->un.bsel.bsel6	/* head statbuf */
11038623Skarels #define	csr7	dkkaddr->un.bsel.bsel7	/* tail statbuf */
11138623Skarels 
11238623Skarels 
11338623Skarels /*
11438623Skarels  * kmc device registers
11538623Skarels  */
11638623Skarels struct kdevice {
11738623Skarels union {
11838623Skarels struct	{ short sel0, sel2, sel4, sel6;} wsel ;
11938623Skarels struct	{ char bsel0, bsel1, bsel2, bsel3;
12038623Skarels 	  char bsel4, bsel5, bsel6, bsel7; } bsel ;
12138623Skarels } un;
12238623Skarels };
12338623Skarels 
12438623Skarels 
12538623Skarels /*
12638623Skarels  * For the moment, only support one kmc (kmc0)
12738623Skarels  * More need be done for multiple kmc's
12838623Skarels  */
12938623Skarels 
13038623Skarels int	dkdebug = 512 ;
13138623Skarels int	dkactive = 0 ;
13238623Skarels int	dkbindex ;
13338623Skarels 	static int	kseqchk = 0;	/* used to check seq. #'s in statbuf */
13438623Skarels 	static int	dkpanic = 0;	/* # of dk_close(0)'s in this run */
13538623Skarels 	static int	kseq = 0;	/* # kmc responses mod 0377 */
13638623Skarels 	static int	pseq = 0;
13738623Skarels 
13838623Skarels 	static struct dkkin *cmd4;		/* dkkcmdbuf[csr4] pointer */
13938623Skarels 	static struct dkkin *stat7;		/* dkkstat[csr7] pointer */
14038623Skarels 
14138623Skarels int dkk_cnt ;
14238623Skarels static struct uba_device *ui;
14338623Skarels 
14438623Skarels dkkmc_attach(kui) struct uba_device *kui;
14538623Skarels {
14638623Skarels 	ui = kui;
14738623Skarels 	dkk_cnt = kui->ui_unit;
14838623Skarels }
14938623Skarels 
dk_init()15038623Skarels dk_init()
15138623Skarels {
15238623Skarels 	int t, kt ;
15338623Skarels 	extern dkkint() ;
15438623Skarels 
15538623Skarels 	/*
15638623Skarels 	 *  On the first open of the hardware interface
15738623Skarels 	 */
15838623Skarels 	if (!ui) return -ENXIO;
15938623Skarels 	if (kmcset((dkk_cnt)<<6,03,dkkint)) {
16038623Skarels /* debug */	log(LOG_ERR, "dkkmcinit bad: kmcset failed\n");
16138623Skarels 		return -1;
16238623Skarels 	}
16338623Skarels 	dkkaddr = ((struct kdevice *) ui->ui_addr);
16438623Skarels 
16538623Skarels 	/* if csr0 != 0, then error
16638623Skarels 	   else pass the address of struct init
16738623Skarels 	   in csr2~4 and set csr0 to 1	*/
16838623Skarels 
16938623Skarels 	if ((csr0 & 3) != 0) {
17038623Skarels /* debug */	log(LOG_ERR, "dkkmcinit: csr0 != 0\n");
17138623Skarels 		return EIO;
17238623Skarels 	}
17338623Skarels 
17438623Skarels 	/* Map UBA registers to point to our stuff */
17538623Skarels 	kt = dk_ubainit();
17638623Skarels 	if (kt == 0) {
17738623Skarels 		log(LOG_ERR, "dkkmcinit: no uba resources\n");
17838623Skarels 		return ENOBUFS;
17938623Skarels 	}
18038623Skarels 
18138623Skarels 	/* Address of DR11-C (if any) */
18238623Skarels 	t = ui->ui_flags & ~03 ;
18338623Skarels 	dkkmcinit.csraddr = (caddr_t) ((t<<16) + 3) ;	/* bits 17 + 18 must be 1 */
18438623Skarels 
18538623Skarels 	/* append new init info here, if it is needed */
18638623Skarels 
18745181Skarels 	dkkaddr->un.wsel.sel2 = (short)(UBAI_ADDR(kt) & 0xFFFF);/* bits 0-15 */
18845181Skarels 	dkkaddr->un.bsel.bsel4 = (char)(UBAI_ADDR(kt) >> 16);	/* bits 16-17 */
18938623Skarels 
19038623Skarels 	csr0 = 1;	/* tell KMC to read csr2 */
19138623Skarels 	kseq = 0 ;
19238623Skarels 
19338623Skarels 	cmd4 = &dkkcmdbuf[0] ;	/* driver's pointers into cmdbuf and statbuf */
19438623Skarels 	stat7 = &dkkstat[0] ;
19538623Skarels 	dkactive = 1 ;
19638623Skarels 	return 0 ;
19738623Skarels }
19838623Skarels 
19938623Skarels int	dk_ubaed = 0;
20038623Skarels 
dk_ubainit()20138623Skarels dk_ubainit()
20238623Skarels {
20338623Skarels 	int t;
20438623Skarels 	static int kt;
20538623Skarels 
20638623Skarels 	if (dk_ubaed) {
20738623Skarels 		if (dkdebug < dk_nchan)
20838623Skarels 			log(LOG_ERR, "dk_ubainit: reinit\n");
20938623Skarels 		return kt;
21038623Skarels 	}
21138623Skarels 	dk_ubaed = 1;
21238623Skarels 
21338623Skarels 	/* Initialization buffer */
21438623Skarels 	kt = uballoc(ui->ui_ubanum, (caddr_t) &dkkmcinit, sizeof dkkmcinit, UBA_CANTWAIT);
21538623Skarels 	if (kt == 0) return 0;
21638623Skarels 
21738623Skarels 	/* Command input buffer */
21838623Skarels 	t = uballoc(ui->ui_ubanum, (caddr_t) dkkcmdbuf, sizeof dkkcmdbuf, UBA_CANTWAIT) ;
21938623Skarels 	if (t == 0) return 0;
22045181Skarels 	dkkmcinit.cmdaddr = (caddr_t)((UBAI_ADDR(t)<<16) | ((UBAI_ADDR(t)>>16)));	/* must swap bytes for unibus */
22138623Skarels 
22238623Skarels 	/* Status out buffer */
22338623Skarels 	t = uballoc(ui->ui_ubanum, (caddr_t) dkkstat, sizeof dkkstat, UBA_CANTWAIT);
22438623Skarels 	if (t == 0) return 0;
22545181Skarels 	dkkmcinit.stataddr = (caddr_t)((UBAI_ADDR(t)<<16) | (UBAI_ADDR(t)>>16));
22638623Skarels 
22738623Skarels 	/* KMC buffer */
22838623Skarels 	dkubmbuf = uballoc(ui->ui_ubanum, (caddr_t) dkkbuf, sizeof dkkbuf, UBA_CANTWAIT);
22945181Skarels 	if (dkubmbuf == 0) return 0;
23045181Skarels 	dkkmcinit.bufaddr = (caddr_t) ((UBAI_ADDR(dkubmbuf)<<16) |
23145181Skarels 	    (UBAI_ADDR(dkubmbuf)>>16));
23238623Skarels 	if (dkdebug < dk_nchan)
23338623Skarels 		log(LOG_ERR, "dk_ubainit: bufaddr %x mapped %x\n", (caddr_t)dkkbuf,
23438623Skarels 		    dkubmbuf);
23538623Skarels 
23638623Skarels 	return kt;
23738623Skarels }
23838623Skarels 
dk_open(chan,supfcn)23938623Skarels dk_open(chan, supfcn)
24038623Skarels register chan ;
24138623Skarels int (*supfcn)() ;
24238623Skarels {
24338623Skarels 	register struct	dkchan	*dkp;
24438623Skarels 	register	s ;
24538623Skarels 	extern 	dkkint() ;
24638623Skarels 	extern int commchan;
24738623Skarels 	int init;
24838623Skarels 
24938623Skarels 	if (chan >= dk_nchan)
25038623Skarels 		return -ENXIO ;
25138623Skarels 	if (dkactive == -1)	/* fail request if reset is in progress */
25238623Skarels 		return(-ENETRESET) ;
25338623Skarels 	dkp = &dkit[chan] ;
25438623Skarels 	s = splimp() ;
25538623Skarels 	/*
25638623Skarels 	 * Channel 0 (0-3 in ISN) is reserved for maintenance.
25738623Skarels 	 * An open on channel 0 is interpreted as a request
25838623Skarels 	 * for an unused channel.  Channel 1 (4 in ISN or RADIAN)
25938623Skarels 	 * is the common supervisory channel.
26038623Skarels 	 */
26138623Skarels 	if (chan == 0) {
26238623Skarels 		chan = commchan+1;		/* Start above commchan */
26338623Skarels 		while (1) {
26438623Skarels 			dkp = &dkit[chan] ;
26538623Skarels 			if (dkp->dk_state == 0)
26638623Skarels 				break ;
26738623Skarels 			chan++ ;
26838623Skarels 			if (chan >= dk_nchan) {
26938623Skarels 				splx(s) ;
27038623Skarels 				return -EADDRNOTAVAIL ;
27138623Skarels 			}
27238623Skarels 		}
27338623Skarels 	}
27438623Skarels 	splx(s) ;
27538623Skarels 
27638623Skarels 	if (dkactive == 0)
27738623Skarels 		if ((init = dk_init()) < 0)
27838623Skarels 			return init ;
27938623Skarels 
28038623Skarels 	/*
28138623Skarels 	 * On first use of a channel, we must
28238623Skarels 	 * allocate per-channel UBA resource for transmit.
28338623Skarels 	 * Some day, when we convert the receivers to use mbufs,
28438623Skarels 	 * we'll do the same for reads.
28538623Skarels 	 * Note that these resources can't easily be freed (I think).
28638623Skarels 	 */
28738623Skarels 	if (!dkp->dk_uba.ifu_uba) {
28838623Skarels 		dkp->dk_uba.ifu_flags = UBA_CANTWAIT;
28938623Skarels 		if (if_ubaminit(&dkp->dk_uba.ifu_info, ui->ui_ubanum, 0,
29038623Skarels 		    btoc(CLBYTES),
29138623Skarels 		    &dkp->dk_uba.ifu_r, 0,
29238623Skarels 		    &dkp->dk_uba.ifu_xmt, 1) == 0) {
29338623Skarels 			log(LOG_ERR, "dkkmc: no ubamap for channel %d\n", chan);
29438623Skarels 			return -ENOBUFS;
29538623Skarels 		}
29638623Skarels 		dkp->dk_outq.ifq_maxlen = 20;
29738623Skarels 	}
29838623Skarels 
29938623Skarels 	/*
30038623Skarels 	 * Finish setting up dkp struct.
30138623Skarels 	 */
30238623Skarels 	if ((dkp->dk_state & DK_OPEN) ==0) {
30338625Skarels 		dkcmd(KC_XINIT, chan, (caddr_t)0, (unsigned) 0, KMXBIG, 0);
30438623Skarels 		flushall(dkp, 0);
30538623Skarels 		dkp->dk_state |= DK_OPEN;
30638625Skarels 		dkp->dk_state &= ~(DK_LINGR | DK_RESET);
30738623Skarels 		dkactive++ ;
30838623Skarels 	}
30938623Skarels 	dkp->dk_supfcn = supfcn ;
31038623Skarels 	return chan ;
31138623Skarels }
31238623Skarels 
31338623Skarels 
31438623Skarels /*
31538623Skarels  * Close a channel:
31638623Skarels  */
31738623Skarels 
dk_close(chan)31838623Skarels dk_close(chan)
31938623Skarels {
32038623Skarels 	register struct	dkchan	*dkp;
32138623Skarels 	register s ;
32238623Skarels 	int init;
32338623Skarels 
32438623Skarels 	if (dkkaddr == 0) return(-ENODEV);	/* if no init, can't close */
32538623Skarels 						/* ie: can't do dkmaint */
32638623Skarels 
32738623Skarels 	s = splimp() ;
32838623Skarels 	dkp = &dkit[chan] ;
32938623Skarels 	if (chan == 0) {
33038623Skarels 		for (dkp = &dkit[1]; dkp < &dkit[dk_nchan]; dkp++) {
33138623Skarels 			if (dkp->dk_state & (DK_OPEN|DK_BUSY|DK_RCV)) {
33238623Skarels 				dkp->dk_state |= DK_RESET ;
33338623Skarels 				flushall(dkp, 0) ;
33438623Skarels 				dkp->dk_state = DK_RESET ;
33538623Skarels 			}
33638623Skarels 		}
33738623Skarels 		dkpanic++ ;
33838623Skarels 		kseq = 0 ;
33938623Skarels 		pseq = 0 ;
34038623Skarels #ifdef notdef
34138623Skarels 		if(dkubmbuf){   /* only deallocate mem if still allocated */
34238623Skarels 			ubarelse(ui->ui_ubanum, &dkubmbuf);
34338623Skarels 			dkubmbuf = NULL;
34438623Skarels 		}
34538623Skarels #endif
34638623Skarels 		/* wait for protocols to close channels */
34738623Skarels 		dkactive = -1 ;
34838623Skarels 		DELAY(4 * hz) ;
34938623Skarels 		/* do a dk_free for all channels */
35038623Skarels 		for (dkp = &dkit[1]; dkp < &dkit[dk_nchan]; dkp++) {
35138623Skarels 			dkp->dk_state &= ~DK_LINGR ;
35238623Skarels 		}
35338623Skarels 		dkactive = 0 ;
35438623Skarels 		csr0 = 0 ;	/* set kmc to idle mode */
35538623Skarels 		if ((init = dk_init()) < 0) {
35638623Skarels 			splx(s) ;
35738623Skarels 			return init ;
35838623Skarels 		}
35938623Skarels 	} else {
36038623Skarels 		flushall(dkp, 0) ;
36138623Skarels 		dkp->dk_state = DK_LINGR ;	/* set while UNIXP protocol
36238623Skarels 						   closes up channel with DK */
36338623Skarels 	}
36438623Skarels 	splx(s) ;
36538623Skarels 	return 0;
36638623Skarels }
36738623Skarels 
36838623Skarels 
36938623Skarels 
37038623Skarels 
37138623Skarels /*
37238623Skarels  *	Close phase 2 - mark available for reassignment
37338623Skarels  */
dk_free(chan)37438623Skarels dk_free(chan)
37538623Skarels {
37638623Skarels 	if (chan > dkdebug)
37738623Skarels 		log(LOG_ERR, "dk_free %d\n", chan) ;
37838625Skarels 	dkit[chan].dk_state &= ~(DK_LINGR | DK_RESET);
37938623Skarels }
38038623Skarels 
38138623Skarels 
38238623Skarels /*
38338623Skarels  *	Reset a channel
38438623Skarels  *	 prevents further I/O until close
38538623Skarels  */
dk_reset(chan)38638623Skarels dk_reset(chan)
38738623Skarels {
38838623Skarels register struct dkchan *dkp ;
38938623Skarels register s ;
39038623Skarels 
39138623Skarels 	if (chan > dkdebug)
39238623Skarels 		log(LOG_ERR, "dk_reset %d\n", chan) ;
39338623Skarels 	s = splimp() ;
39438623Skarels 	dkp = &dkit[chan] ;
39538623Skarels 	dkp->dk_state |= DK_RESET ;
39638623Skarels 	flushall(dkp, 0) ;
39738623Skarels 	splx(s) ;
39838623Skarels }
39938623Skarels 
40038623Skarels 
40138623Skarels 
40238623Skarels /*
40338623Skarels  *	Xmit a short control (interrupt) packet (max 2 bytes)
40438623Skarels  */
dk_xint(chan,intr)40538623Skarels dk_xint(chan, intr)
40638623Skarels {
40738623Skarels register s ;
40838623Skarels 
40938623Skarels 	s = splimp() ;
41038623Skarels 	dkcmd(KC_SOI, chan, (caddr_t)0, (unsigned) intr, 0, 0) ;
41138623Skarels 	splx(s) ;
41238623Skarels 	return 0 ;
41338623Skarels }
41438623Skarels 
41538623Skarels 
41638623Skarels /*
41738623Skarels  * Adjust window size
41838623Skarels  */
41938623Skarels /*ARGSUSED*/
42038623Skarels dk_winsize(chan, win)
42138623Skarels 	struct diocxwin *win;
42238623Skarels {
42338623Skarels 	return EINVAL;		/* For now... */
42438623Skarels }
42538623Skarels 
42638623Skarels 
42738623Skarels 
42838623Skarels /*
42938623Skarels  * Xmit data on a channel
43038623Skarels  */
43138623Skarels dk_xmit(chan, m, eob, ctlchar, endfcn, endparm)
43238623Skarels 	struct mbuf *m ;
43338623Skarels 	int (*endfcn)() ;
43438623Skarels 	caddr_t endparm ;
43538623Skarels {
43638623Skarels 	register struct dkchan *dkp ;
43738623Skarels 	short s ;
43838623Skarels 	register struct mpacket *mbp ;
43938623Skarels 	register struct mbuf *mb;
44038623Skarels 	int len;
44138623Skarels 
44238623Skarels 	M_ON(Mxmit) ;
44338623Skarels 	s = splimp() ;
44438623Skarels 	dkp = &dkit[chan] ;
44538623Skarels 	if ((dkp->dk_state & DK_RESET) || (mb = m_get(M_DONTWAIT,DKMT_HDR)) == NULL) {
44638623Skarels 		m_freem(m);
44738623Skarels 		splx(s) ;
44838623Skarels 		return 0 ;
44938623Skarels 	}
45038623Skarels 
45138623Skarels 	mb->m_len = 0;
45238623Skarels 	mbp = mtod(mb, struct mpacket *);
45338623Skarels 	mbp->mp_endfcn = endfcn ;
45438623Skarels 	mbp->mp_endparm = endparm ;
45538623Skarels 	mbp->mp_eob = eob;
45638623Skarels 	mbp->mp_ctl = ctlchar;
45738623Skarels 
45838623Skarels 	if ((dkp->dk_state & DK_BUSY) == 0) {
45938623Skarels 		dkp->dk_state |= DK_BUSY ;
46038623Skarels 		dkp->dk_obuf = mbp ;
46138623Skarels 		mb->m_next = NULL;
46238623Skarels 		len = if_wubaput(&dkp->dk_uba, m);
46338623Skarels 		dkcmd(KC_SEND, chan, (caddr_t) UBAI_ADDR(dkp->dk_uba.ifu_w.ifrw_info),
46438623Skarels 		    (unsigned) len, eob ? SBOT : SBOTM, ctlchar) ;
46538623Skarels 		splx(s) ;
46638623Skarels 		M_OFF(Mxmit) ;
46738623Skarels 		return dkp->dk_state ;
46838623Skarels 	}
46938623Skarels 
47038623Skarels 	mb->m_next = m;
47138623Skarels 	if (IF_QFULL(&dkp->dk_outq)) {
47238623Skarels 		IF_DROP(&dkp->dk_outq);
47338623Skarels 		m_freem(mb);
47438623Skarels 	}
47538623Skarels 	else
47638623Skarels 		IF_ENQUEUE(&dkp->dk_outq, mb);
47738623Skarels 	splx(s) ;
47838623Skarels 	M_OFF(Mxmit) ;
47938623Skarels 	return dkp->dk_state ;
48038623Skarels }
48138623Skarels 
48238623Skarels /*
48338623Skarels  * Receive into a block buffer
48438623Skarels  */
dk_recv(chan,addr,len,mode,endfcn,endparm)48538623Skarels dk_recv(chan, addr, len, mode, endfcn, endparm)
48638623Skarels int len;
48738623Skarels int (*endfcn)() ;
48838623Skarels caddr_t addr, endparm ;
48938623Skarels {
49038623Skarels 	register struct dkchan *dkp ;
49138623Skarels 	int s;
49238623Skarels 
49338623Skarels 	s = splimp() ;
49438623Skarels 	M_ON(Mrecv) ;
49538623Skarels 	dkp = &dkit[chan] ;
49638623Skarels 	if (dkp->dk_state & (DK_RCV | DK_RESET)) {
49738623Skarels 		splx(s) ;
49838623Skarels 		return(0) ;
49938623Skarels 	}
50038623Skarels 	dkp->dk_ubmbase = uballoc(ui->ui_ubanum, addr, len, UBA_CANTWAIT);
50138623Skarels 	if (dkp->dk_ubmbase == NULL) {
50238623Skarels 		splx(s) ;
50338623Skarels 		return(0) ;
50438623Skarels 	}
50538623Skarels 	dkp->dk_state |= DK_RCV ;
50638623Skarels 	dkp->dk_endfcn = endfcn ;
50738623Skarels 	dkp->dk_endparm = endparm ;
50838623Skarels 	dkp->dk_rlen = len;
50938623Skarels 	dkcmd(KC_RCVB, chan, (caddr_t) UBAI_ADDR(dkp->dk_ubmbase), (unsigned) len, mode&0377, mode>>8);
51038623Skarels 	M_OFF(Mrecv) ;
51138623Skarels 	splx(s);
51238623Skarels 	return dkp->dk_state ;
51338623Skarels }
51438623Skarels 
51538623Skarels /* Abort pending receive */
51638623Skarels 
51738623Skarels 
51838623Skarels dk_rabort(chan, nendfcn, nendparm)
51938623Skarels int (*nendfcn)() ;
52038623Skarels caddr_t nendparm;
52138623Skarels {
52238623Skarels register struct dkchan *dkp ;
52338623Skarels register s ;
52438623Skarels 
52538623Skarels 	dkp = &dkit[chan] ;
52638623Skarels 	s = splimp() ;
52738623Skarels 	if (dkp->dk_state & DK_RCV) {	/* cancel outstanding receive */
52838623Skarels 		dkcmd(KC_RCVB, chan, (caddr_t)0, (unsigned) 0, 0, 0) ;
52938623Skarels 		dkp->dk_endfcn = nendfcn ;
53038623Skarels 		dkp->dk_endparm = nendparm ;
53138623Skarels 	}
53238623Skarels 	splx(s) ;
53338623Skarels 	return dkp->dk_state ;
53438623Skarels }
53538623Skarels 
53638623Skarels 
53738623Skarels 
dk_status(chan)53838623Skarels dk_status(chan)
53938623Skarels {
54038623Skarels 	if (chan >= dk_nchan)
54138623Skarels 		return 0 ;
54238623Skarels 	return dkit[chan].dk_state ;
54338623Skarels }
54438623Skarels 
54538623Skarels 
54638623Skarels /*
54738623Skarels  * Various control commands to KMC
54838623Skarels  */
dk_cmd(chan,cmd)54938623Skarels dk_cmd(chan, cmd)
55038623Skarels {
55138623Skarels 	register struct dkchan *dkp ;
55238623Skarels 	register s ;
55338623Skarels 
55438623Skarels 	dkp = &dkit[chan] ;
55538623Skarels 	if (cmd & (DKC_XINIT|DKC_FLUSH)) {
55638623Skarels 		/*for either command do the same thing:
55738623Skarels 		 * reinit the transmitter and flush any pending output.
55838623Skarels 		 * NOTE: for the kmc, there is no response to XINIT
55938623Skarels 		 * and no send complete for flush
56038623Skarels 		 */
56138623Skarels 		s = splimp() ;
56238625Skarels 		dkcmd(KC_XINIT, chan, (caddr_t)0, (unsigned) 0, KMXBIG, 0) ;
56338623Skarels 		flushall(dkp, -1) ;
56438623Skarels 		dkcmd(KC_CMD, chan, (caddr_t)0, (unsigned) DKC_FLUSH, 0, 0) ;
56538623Skarels 		splx(s);
56638623Skarels 		cmd &= ~(DKC_XINIT|DKC_FLUSH) ;
56738623Skarels 	}
56838623Skarels 	if (cmd)
56938623Skarels 		dkcmd(KC_CMD, chan, (caddr_t)0, (unsigned) cmd, 0, 0) ;
57038623Skarels }
57138623Skarels 
57238623Skarels 
57338623Skarels /*
57438623Skarels  *	Note that flushall is often recursive when a tty driver
57538623Skarels  *	is involved.
57638623Skarels  */
57738623Skarels 
57838623Skarels static
flushall(dkp,rwflag)57938623Skarels flushall(dkp, rwflag)
58038623Skarels register struct dkchan *dkp ;
58138623Skarels {
58238623Skarels 	register s ;
58338623Skarels 	register struct mpacket *mbp ;
58438623Skarels 	int (*endfcn)();
58538623Skarels 
58638623Skarels 	s = splimp() ;
58738623Skarels 	if ((dkp->dk_state & DK_RCV) && (rwflag >= 0)) {
58838623Skarels 		dkcmd(KC_RCVB, dkp-dkit, (caddr_t)0, (unsigned) 0, 0, 0) ;
58938623Skarels 		dkp->dk_state &= ~DK_RCV ;
59038623Skarels 		if (dkp->dk_ubmbase) {
59138623Skarels 			ubarelse(ui->ui_ubanum, &dkp->dk_ubmbase);
59238623Skarels 			dkp->dk_ubmbase = NULL;
59338623Skarels 		}
59438623Skarels 		if (endfcn = dkp->dk_endfcn) {
59538623Skarels 			dkp->dk_endfcn = NULL ;
59638623Skarels 			(*endfcn)(dkp->dk_endparm, dkp-dkit, dkp->dk_rlen, DKR_ABORT, 0) ;
59738623Skarels 		}
59838623Skarels 	}
59938623Skarels 
60038623Skarels 	/* flush all writes current and pending */
60138623Skarels 
60238623Skarels 	if ((dkp->dk_state & DK_BUSY) && (rwflag <= 0)) {
60338623Skarels 		register struct mbuf *m ;
60438623Skarels 
60538623Skarels 		/* flush current write */
60638623Skarels 		if (mbp = dkp->dk_obuf) {
60738623Skarels 			dkp->dk_obuf = NULL;
60838623Skarels 			if (endfcn = mbp->mp_endfcn) {
60938623Skarels 				mbp->mp_endfcn = NULL;
61038623Skarels 				(endfcn)(mbp->mp_endparm, dkp-dkit);
61138623Skarels 			}
61238623Skarels 			m_free(dtom(mbp));
61338623Skarels 		}
61438623Skarels 		/* flush any pending writes which may be queued up */
61538623Skarels 		while (1) {
61638623Skarels 			IF_DEQUEUE(&dkp->dk_outq, m);
61738623Skarels 			if (!m) break;
61838623Skarels 			mbp = mtod(m, struct mpacket *);
61938623Skarels 			if (endfcn = mbp->mp_endfcn) {
62038623Skarels 				mbp->mp_endfcn = NULL;
62138623Skarels 				(endfcn)(mbp->mp_endparm, dkp-dkit);
62238623Skarels 			}
62338623Skarels 			m_freem(m);
62438623Skarels 		}
62538623Skarels 		/* mark channel as not busy */
62638623Skarels 		dkp->dk_state &= ~DK_BUSY ;
62738623Skarels 	}
62838623Skarels 	if ((dkp->dk_state & DK_OPEN) && (rwflag >= 0)) {
62938623Skarels 		dkcmd(KC_CLOSE, dkp-dkit, (caddr_t)0, (unsigned) 0, 0, 0) ;
63038623Skarels 		if (dkp->dk_state & DK_BUSY){
63138623Skarels 			mbp = dkp->dk_obuf;
63238623Skarels 			dkp->dk_obuf = NULL;
63338623Skarels 			if (endfcn = mbp->mp_endfcn) {
63438623Skarels 				mbp->mp_endfcn = NULL;
63538623Skarels 				(endfcn)(mbp->mp_endparm, dkp-dkit);
63638623Skarels 			}
63738623Skarels 			m_free(dtom(mbp));
63838623Skarels 			dkp->dk_state &= ~DK_BUSY ;
63938623Skarels 		}
64038623Skarels 	}
64138623Skarels 	splx(s) ;
64238623Skarels }
64338623Skarels 
64438623Skarels 
64538623Skarels short dup_count = 0; /* counter for number of duplicate sends */
64638623Skarels 
64738623Skarels /*
64838623Skarels  * Routine to handle interrupts from the KMC
64938623Skarels  *
65038623Skarels  * This routine is called when
65138623Skarels  * the KMC generates an unsolicited interrupt (VEC4 == 1)
65238623Skarels  *
65338623Skarels  * These interrupts are used by the KMC to notify dkit_kmc.c
65438623Skarels  * of events such as output buffer completions
65538623Skarels  * csr6 & csr7 point to dkkstat
65638623Skarels  */
dkkint()65738623Skarels dkkint()
65838623Skarels {
65938623Skarels 	register struct dkchan *dkp;
66038623Skarels 	register struct dkkin *sp;
66138623Skarels 	register chan;
66238623Skarels 	struct mpacket *mbp ;
66338623Skarels 	int (*endfcn)();
66438623Skarels 
66538623Skarels 	M_ON(Mkint) ;
66638623Skarels 
66738623Skarels 	chan = csr0 ;	/* temp for cc -O bug */
66838623Skarels 	if((chan & 01) == 1)	/* 1 or 3 -> ignore */
66938623Skarels 		return;
67038623Skarels 	sp = stat7 ;	/* next response to be processed */
67138623Skarels 	while (csr6 != csr7) {
67238623Skarels 		if (kseqchk)
67338623Skarels 			if ((((sp->k_chan >> 8)&0377) != kseq) ||
67438623Skarels 			    (((sp->k_type >> 8)&0377) != kseq)) {
67538623Skarels 				log(LOG_ERR, "dkkint: kseq %x chan %d type %x\n",
67638623Skarels 					kseq, sp->k_chan, sp->k_type) ;
67738623Skarels 				goto reset ;
67838623Skarels 			}
67938623Skarels 		kseq = (kseq + 1) & 0377 ;
68038623Skarels 		sp->k_addr = pseq ;
68138623Skarels 		pseq++ ;
68238623Skarels 		chan = sp->k_chan & 0377 ;	/* mask off seq. # */
68338623Skarels 		dkp = &dkit[chan];
68438623Skarels 		if (chan > dkdebug) {
68538623Skarels 			log(LOG_ERR, " dkkint: head %d tail %d", csr6, csr7) ;
68638623Skarels 			log(LOG_ERR, " type %x chan %d len %d mode %x ctl %x\n", sp->k_type&0377, sp->k_chan&0377, sp->k_len, sp->k_mode, sp->k_ctl) ;
68738623Skarels 		}
68838623Skarels 		switch(sp->k_type & 0377) {
68938623Skarels 		case KS_CNTL:
69038623Skarels 			if (dkp->dk_supfcn)
69138623Skarels 				(*dkp->dk_supfcn)(chan, sp->k_ctl) ;
69238623Skarels 			break ;
69338623Skarels 		case KS_EOI:
69438623Skarels 			break ;
69538623Skarels 		case KS_SEND:
69638623Skarels 			mbp = dkp->dk_obuf ;
69738623Skarels 			if (mbp == NULL) {
69838623Skarels 				if (dkp->dk_state & (DK_RESET|DK_LINGR))
69938623Skarels 					break;	/* flushall was already called */
70038623Skarels 				log(LOG_ERR, "dkkint: xbufout chan %d state %x\n", chan, dkp->dk_state) ;
70138623Skarels 				log(LOG_ERR, "head %d tail %d", csr6, csr7) ;
70238623Skarels 				log(LOG_ERR, " type %x len %d mode %x ctl %x\n",
70338623Skarels 				sp->k_type&0377, sp->k_len, sp->k_mode, sp->k_ctl) ;
70438623Skarels 				break ;
70538623Skarels 			}
70638623Skarels 			dkp->dk_state &= ~DK_BUSY;
70738623Skarels 			dkp->dk_obuf = NULL ;
70838623Skarels 			if (endfcn = mbp->mp_endfcn) {
70938623Skarels 				mbp->mp_endfcn = NULL;
71038623Skarels 				(endfcn)(mbp->mp_endparm, chan) ;
71138623Skarels 			}
71238623Skarels 			m_free(dtom(mbp)) ;
71338623Skarels 			if (dkp->dk_uba.ifu_xtofree) {
71438623Skarels 				m_freem(dkp->dk_uba.ifu_xtofree);
71538623Skarels 				dkp->dk_uba.ifu_xtofree = 0;
71638623Skarels 			}
71738623Skarels 			if (dkp->dk_outq.ifq_head)
71838623Skarels 				dkstart(dkp) ;
71938623Skarels 			break;
72038623Skarels 		case KS_RDB:
72138623Skarels 			if (((dkp->dk_state & DK_RCV) == 0) && dkp->dk_endfcn) {
72238623Skarels 				log(LOG_ERR, "dkkint: rbufin chan %d state %x\n", chan, dkp->dk_state) ;
72338623Skarels 				log(LOG_ERR, " head %d tail %d\n", csr6, csr7) ;
72438623Skarels 				log(LOG_ERR, " type %x len %d mode %x ctl %x\n",
72538623Skarels 				sp->k_type&0377, sp->k_len, sp->k_mode, sp->k_ctl) ;
72638623Skarels 
72738623Skarels 				if (sp->k_ctl)
72838623Skarels 					break ;
72938623Skarels 				else {
73038623Skarels 					stat7 = sp ;	/* save it for dump */
73138623Skarels 					csr0 = 3 ;	/* stop KMC */
73238623Skarels 					panic("") ;	/* KMC probably wrote
73338623Skarels 						into a mbuf we don't own */
73438623Skarels 				}
73538623Skarels 			}
73638623Skarels 			dkp->dk_state &= ~DK_RCV ;
73738623Skarels 			if (dkp->dk_ubmbase) {
73838623Skarels 				ubarelse(ui->ui_ubanum, &dkp->dk_ubmbase);
73938623Skarels 				dkp->dk_ubmbase = NULL;
74038623Skarels 			}
74138623Skarels 			if (endfcn = dkp->dk_endfcn) {
74238623Skarels 				dkp->dk_endfcn = NULL;
74338623Skarels 				(endfcn)(dkp->dk_endparm, chan, sp->k_len, sp->k_mode, sp->k_ctl) ;
74438623Skarels 			}
74538623Skarels 			break;
74638623Skarels 		case KS_ERR:
74738623Skarels 			log(LOG_ERR, "dkkint: err : chan %d, code %x\nchead: %d, ctail: %d, rhead: %d, rtail: %d\n",
74838623Skarels 				chan, sp->k_len, csr4, csr5, csr6, csr7);
74938623Skarels 
75038623Skarels 			/* if error is duplicate send, only close that chan, */
75138623Skarels 			/* not the whole interface */
75238623Skarels 
75338623Skarels 			if (sp->k_len == E_DUP)  {
75438623Skarels 				dup_count++;
75538623Skarels 				if (dkp->dk_state & DK_OPEN)  {
75638623Skarels 					dk_reset(chan);
75738623Skarels 				}
75838623Skarels 				break;
75938623Skarels 			}
76038623Skarels reset:
76138623Skarels 			(void) dk_close(0) ;
76238623Skarels 			return ;
76338623Skarels 		default:
76438623Skarels 			log(LOG_ERR, "dkkint: chan %d, type %x, len %d, ctl %x, mode %x\n",
76538623Skarels 			chan, sp->k_type&0377, sp->k_len, sp->k_ctl, sp->k_mode);
76638623Skarels 			goto reset ;
76738623Skarels 		}	/* end switch */
76838623Skarels 
76938623Skarels 		if (csr7 == dkk_nstat-1) {
77038623Skarels 			csr7 = 0 ;
77138623Skarels 			sp = &dkkstat[0] ;
77238623Skarels 		} else {
77338623Skarels 			csr7++ ;
77438623Skarels 			sp++ ;
77538623Skarels 		}
77638623Skarels 
77738623Skarels 	}	/* end while */
77838623Skarels 	stat7 = sp ;
77938623Skarels 	M_OFF(Mkint) ;
78038623Skarels }
78138623Skarels 
78238623Skarels /*
78338623Skarels  * Start (Restart) transmission on the given line
78438623Skarels  */
dkstart(dkp)78538623Skarels dkstart(dkp)
78638623Skarels register struct dkchan *dkp;
78738623Skarels {
78838623Skarels 	register struct mpacket *mbp;
78938623Skarels 	register struct mbuf *m;
79038623Skarels 	int len;
79138623Skarels 
79238623Skarels 	/*
79338623Skarels 	 * If it is currently active, just return
79438623Skarels 	 */
79538623Skarels 	if (dkp->dk_state&DK_BUSY)
79638623Skarels 		return;
79738623Skarels 
79838623Skarels 	IF_DEQUEUE(&dkp->dk_outq, m);
79938623Skarels 	if (!m)
80038623Skarels 		return;
80138623Skarels 	mbp = mtod(m, struct mpacket *);
80238623Skarels 
80338623Skarels 	dkp->dk_state |= DK_BUSY ;
80438623Skarels 	dkp->dk_obuf = mbp ;
80538623Skarels 	len = if_wubaput(&dkp->dk_uba, m->m_next);
80638623Skarels 	dkcmd(KC_SEND, dkp-dkit, (caddr_t) UBAI_ADDR(dkp->dk_uba.ifu_w.ifrw_info),
80738623Skarels 	    (unsigned) len, mbp->mp_eob ? SBOT : SBOTM, mbp->mp_ctl) ;
80838623Skarels }
80938623Skarels 
81038623Skarels /*
81138623Skarels  * Put command in dkkcmdbuf which is pointed by csr4~5
81238623Skarels  */
dkcmd(type,chan,addr,len,mode,ctl)81338623Skarels dkcmd(type, chan, addr, len, mode, ctl)
81438623Skarels int type, chan;
81538623Skarels caddr_t addr ;
81638623Skarels unsigned len ;
81738623Skarels {
81838623Skarels 	register struct dkkin *sp;
81938623Skarels 	register s;
82038623Skarels 	register next;
82138625Skarels 	register loop;
82238623Skarels 	struct timeval tv1, tv2;
82338623Skarels 
82438623Skarels 	M_ON(Mcmd) ;
82538623Skarels 	s = csr0 ;
82638623Skarels 	if ((s & 3) != 2)
82738623Skarels 		return;
82838623Skarels 
82938623Skarels 	s = splimp();
83038623Skarels 	next = (csr4+1)%dkk_ncmd;
83138625Skarels 	loop = 0;
83238625Skarels 	while (csr5 == next) {
83338625Skarels 		/* give it a chance to empty the buffer */
83438625Skarels 		if (loop++>10000000) {
83538625Skarels 			log(LOG_ERR, "KMC DIED, restart\n");
83638625Skarels 			dk_close(0);
83738625Skarels 			splx(s);
83838625Skarels 			return;
83938625Skarels 		}
84038625Skarels 		log(LOG_ERR, "KMC cmd overrun for %ld\n", loop);
84138623Skarels 	}
84238623Skarels 
84338623Skarels 	sp = cmd4 ;
84438623Skarels 	sp->k_type = type | ((pseq&0177)<<9) ;
84538623Skarels 	sp->k_chan = chan | ((kseq&0377)<<8) ;
84638623Skarels 	sp->k_addr = ((int)addr << 16) + ((int)addr >> 16) ;
84738623Skarels 	sp->k_len = len ;
84838623Skarels 	sp->k_mode = mode ;
84938623Skarels 	sp->k_ctl = ctl ;
85038623Skarels 	pseq++ ;
85138623Skarels 
85238623Skarels 	csr4 = next;
85338623Skarels 	cmd4 = &dkkcmdbuf[next];
85438623Skarels 
85538623Skarels 	if (chan > dkdebug) {
85638623Skarels 	    	log(LOG_ERR, " dkcmd: head %d, tail %d", csr4, csr5);
85738623Skarels 	    	log(LOG_ERR, " type %x, chan %d, addr %x, len %d",
85838623Skarels 						type, chan, addr, len);
85938623Skarels 		log(LOG_ERR, " mode %x, ctl %x\n", mode, ctl);
86038623Skarels 	}
86138623Skarels 	splx(s) ;
86238623Skarels 	M_OFF(Mcmd) ;
86338623Skarels }
86438623Skarels 
86538623Skarels #endif
866