xref: /csrg-svn/sys/vax/datakit/dkit_kmc.c (revision 38623)
1*38623Skarels /*
2*38623Skarels  * Datakit driver
3*38623Skarels  * KMC assistance, with or without DR11C
4*38623Skarels  */
5*38623Skarels 
6*38623Skarels #include "dkitkmc.h"
7*38623Skarels #if NDKITKMC>0
8*38623Skarels 
9*38623Skarels #include "datakit.h"
10*38623Skarels 
11*38623Skarels #include "../machine/pte.h"
12*38623Skarels #include "param.h"
13*38623Skarels #include "syslog.h"
14*38623Skarels #include "time.h"
15*38623Skarels #include "kernel.h"
16*38623Skarels #include "buf.h"
17*38623Skarels #include "mbuf.h"
18*38623Skarels #include "errno.h"
19*38623Skarels #include "socket.h"
20*38623Skarels #include "../net/if.h"
21*38623Skarels #include "../vaxif/if_uba.h"
22*38623Skarels #include "../vaxuba/ubareg.h"
23*38623Skarels #include "../vaxuba/ubavar.h"
24*38623Skarels 
25*38623Skarels #include "dkit.h"
26*38623Skarels #include "dkkmc.h"
27*38623Skarels #include "dk.h"
28*38623Skarels 
29*38623Skarels #define	MONITOR	1
30*38623Skarels 
31*38623Skarels #ifdef	MONITOR
32*38623Skarels static	int	dummy ;
33*38623Skarels int	*DKP = &dummy ;
34*38623Skarels #define	M_ON(a)		*DKP |= (a)
35*38623Skarels #define M_OFF(a)	*DKP &= ~(a)
36*38623Skarels #define	M_TRACE(a)	*DKP |= (a);*DKP &= ~(a)
37*38623Skarels 
38*38623Skarels #define	Mxmit	01
39*38623Skarels #define	Mrecv	02
40*38623Skarels #define	Mkint	04
41*38623Skarels #define	Mint	010
42*38623Skarels #define	Mcmd	020
43*38623Skarels 
44*38623Skarels #else
45*38623Skarels #define	M_ON(a)
46*38623Skarels #define	M_OFF(a)
47*38623Skarels #define	M_TRACE(a)
48*38623Skarels #endif
49*38623Skarels 
50*38623Skarels extern int		dk_nchan;
51*38623Skarels 
52*38623Skarels struct dkchan	dkit[NDATAKIT];
53*38623Skarels 
54*38623Skarels #define	DKNCMDB	20
55*38623Skarels #define	DKNSTB	20
56*38623Skarels 
57*38623Skarels int dkk_ncmd = DKNCMDB;
58*38623Skarels struct dkkin dkkcmdbuf[DKNCMDB];
59*38623Skarels int dkk_nstat = DKNSTB;
60*38623Skarels struct dkkin dkkstat[DKNSTB];
61*38623Skarels char dkkbuf[16*1024];
62*38623Skarels int dkubmbuf;
63*38623Skarels 
64*38623Skarels static struct kdevice *dkkaddr;
65*38623Skarels 
66*38623Skarels /*
67*38623Skarels  * initial information to the KMC
68*38623Skarels  */
69*38623Skarels struct dkinit {
70*38623Skarels 	caddr_t	cmdaddr;	/* command buffer */
71*38623Skarels 	caddr_t	stataddr;	/* status buffer  */
72*38623Skarels 	caddr_t	bufaddr ;	/* kmc workspace  */
73*38623Skarels 	caddr_t	csraddr;	/* for KMC/DR DR register address */
74*38623Skarels } dkkmcinit;
75*38623Skarels 
76*38623Skarels /*
77*38623Skarels  * structure of data in first mbuf on chain (type DKM_HDR)
78*38623Skarels  *
79*38623Skarels  */
80*38623Skarels struct	mpacket {
81*38623Skarels 	short	mp_len;		/* Total length left */
82*38623Skarels 	char	mp_ctl;		/* Control character */
83*38623Skarels 	int	mp_eob;		/* Send end-of-block indicator */
84*38623Skarels 	int	(*mp_endfcn)();	/* End-action function */
85*38623Skarels 	caddr_t	mp_endparm;	/* Parameter to above function */
86*38623Skarels };
87*38623Skarels 
88*38623Skarels 
89*38623Skarels /*
90*38623Skarels  * The circular buffer, cmdbuf, is used to pass command to kmc:
91*38623Skarels  * while the circular buffer statbuf is used to report status.
92*38623Skarels  * There are 8 control and status registers (csr) accessible to
93*38623Skarels  * both cpu and kmc.
94*38623Skarels  * Csr4-csr5 are used to indicate the head and tail respectively
95*38623Skarels  * of the cmdbuf.  Likewise, csr6-csr7 for statbuf.
96*38623Skarels  * At initialization time, the cpu and kmc would agree on the beginning
97*38623Skarels  * address of both buffers and their sizes.
98*38623Skarels  */
99*38623Skarels #define	csr0	dkkaddr->un.bsel.bsel0	/* kmc state */
100*38623Skarels #define	csr1	dkkaddr->un.bsel.bsel1
101*38623Skarels #define	csr2	dkkaddr->un.bsel.bsel2	/* used at init time, to pass */
102*38623Skarels #define	csr3	dkkaddr->un.bsel.bsel3	/* addresses to the kmc       */
103*38623Skarels #define	csr4	dkkaddr->un.bsel.bsel4  /* head cmdbuf */
104*38623Skarels #define	csr5	dkkaddr->un.bsel.bsel5  /* tail cmdbuf */
105*38623Skarels #define	csr6	dkkaddr->un.bsel.bsel6	/* head statbuf */
106*38623Skarels #define	csr7	dkkaddr->un.bsel.bsel7	/* tail statbuf */
107*38623Skarels 
108*38623Skarels 
109*38623Skarels /*
110*38623Skarels  * kmc device registers
111*38623Skarels  */
112*38623Skarels struct kdevice {
113*38623Skarels union {
114*38623Skarels struct	{ short sel0, sel2, sel4, sel6;} wsel ;
115*38623Skarels struct	{ char bsel0, bsel1, bsel2, bsel3;
116*38623Skarels 	  char bsel4, bsel5, bsel6, bsel7; } bsel ;
117*38623Skarels } un;
118*38623Skarels };
119*38623Skarels 
120*38623Skarels 
121*38623Skarels /*
122*38623Skarels  * For the moment, only support one kmc (kmc0)
123*38623Skarels  * More need be done for multiple kmc's
124*38623Skarels  */
125*38623Skarels 
126*38623Skarels int	dkdebug = 512 ;
127*38623Skarels int	dkactive = 0 ;
128*38623Skarels int	dkbindex ;
129*38623Skarels 	static int	kseqchk = 0;	/* used to check seq. #'s in statbuf */
130*38623Skarels 	static int	dkpanic = 0;	/* # of dk_close(0)'s in this run */
131*38623Skarels 	static int	kseq = 0;	/* # kmc responses mod 0377 */
132*38623Skarels 	static int	pseq = 0;
133*38623Skarels 
134*38623Skarels 	static struct dkkin *cmd4;		/* dkkcmdbuf[csr4] pointer */
135*38623Skarels 	static struct dkkin *stat7;		/* dkkstat[csr7] pointer */
136*38623Skarels 
137*38623Skarels int dkk_cnt ;
138*38623Skarels static struct uba_device *ui;
139*38623Skarels 
140*38623Skarels dkkmc_attach(kui) struct uba_device *kui;
141*38623Skarels {
142*38623Skarels 	ui = kui;
143*38623Skarels 	dkk_cnt = kui->ui_unit;
144*38623Skarels }
145*38623Skarels 
146*38623Skarels dk_init()
147*38623Skarels {
148*38623Skarels 	int t, kt ;
149*38623Skarels 	extern dkkint() ;
150*38623Skarels 
151*38623Skarels 	/*
152*38623Skarels 	 *  On the first open of the hardware interface
153*38623Skarels 	 */
154*38623Skarels 	if (!ui) return -ENXIO;
155*38623Skarels 	if (kmcset((dkk_cnt)<<6,03,dkkint)) {
156*38623Skarels /* debug */	log(LOG_ERR, "dkkmcinit bad: kmcset failed\n");
157*38623Skarels 		return -1;
158*38623Skarels 	}
159*38623Skarels 	dkkaddr = ((struct kdevice *) ui->ui_addr);
160*38623Skarels 
161*38623Skarels 	/* if csr0 != 0, then error
162*38623Skarels 	   else pass the address of struct init
163*38623Skarels 	   in csr2~4 and set csr0 to 1	*/
164*38623Skarels 
165*38623Skarels 	if ((csr0 & 3) != 0) {
166*38623Skarels /* debug */	log(LOG_ERR, "dkkmcinit: csr0 != 0\n");
167*38623Skarels 		return EIO;
168*38623Skarels 	}
169*38623Skarels 
170*38623Skarels 	/* Map UBA registers to point to our stuff */
171*38623Skarels 	kt = dk_ubainit();
172*38623Skarels 	if (kt == 0) {
173*38623Skarels 		log(LOG_ERR, "dkkmcinit: no uba resources\n");
174*38623Skarels 		return ENOBUFS;
175*38623Skarels 	}
176*38623Skarels 
177*38623Skarels 	/* Address of DR11-C (if any) */
178*38623Skarels 	t = ui->ui_flags & ~03 ;
179*38623Skarels 	dkkmcinit.csraddr = (caddr_t) ((t<<16) + 3) ;	/* bits 17 + 18 must be 1 */
180*38623Skarels 
181*38623Skarels 	/* append new init info here, if it is needed */
182*38623Skarels 
183*38623Skarels 	dkkaddr->un.wsel.sel2 = (short)(kt & 0xFFFF);	/* bits 0-15 */
184*38623Skarels 	dkkaddr->un.bsel.bsel4 = (char)((kt & 0xFF0000) >> 16);	/* bits 16-23 */
185*38623Skarels 
186*38623Skarels 	csr0 = 1;	/* tell KMC to read csr2 */
187*38623Skarels 	kseq = 0 ;
188*38623Skarels 
189*38623Skarels 	cmd4 = &dkkcmdbuf[0] ;	/* driver's pointers into cmdbuf and statbuf */
190*38623Skarels 	stat7 = &dkkstat[0] ;
191*38623Skarels 	dkactive = 1 ;
192*38623Skarels 	return 0 ;
193*38623Skarels }
194*38623Skarels 
195*38623Skarels int	dk_ubaed = 0;
196*38623Skarels 
197*38623Skarels dk_ubainit()
198*38623Skarels {
199*38623Skarels 	int t;
200*38623Skarels 	static int kt;
201*38623Skarels 
202*38623Skarels 	if (dk_ubaed) {
203*38623Skarels 		if (dkdebug < dk_nchan)
204*38623Skarels 			log(LOG_ERR, "dk_ubainit: reinit\n");
205*38623Skarels 		return kt;
206*38623Skarels 	}
207*38623Skarels 	dk_ubaed = 1;
208*38623Skarels 
209*38623Skarels 	/* Initialization buffer */
210*38623Skarels 	kt = uballoc(ui->ui_ubanum, (caddr_t) &dkkmcinit, sizeof dkkmcinit, UBA_CANTWAIT);
211*38623Skarels 	if (kt == 0) return 0;
212*38623Skarels 
213*38623Skarels 	/* Command input buffer */
214*38623Skarels 	t = uballoc(ui->ui_ubanum, (caddr_t) dkkcmdbuf, sizeof dkkcmdbuf, UBA_CANTWAIT) ;
215*38623Skarels 	if (t == 0) return 0;
216*38623Skarels 	dkkmcinit.cmdaddr = (caddr_t) ((t<<16) + ((t>>16) & 03));	/* must swap bytes for unibus */
217*38623Skarels 
218*38623Skarels 	/* Status out buffer */
219*38623Skarels 	t = uballoc(ui->ui_ubanum, (caddr_t) dkkstat, sizeof dkkstat, UBA_CANTWAIT);
220*38623Skarels 	if (t == 0) return 0;
221*38623Skarels 	dkkmcinit.stataddr = (caddr_t) ((t<<16) + ((t>>16) & 03));
222*38623Skarels 
223*38623Skarels 	/* KMC buffer */
224*38623Skarels 	dkubmbuf = uballoc(ui->ui_ubanum, (caddr_t) dkkbuf, sizeof dkkbuf, UBA_CANTWAIT);
225*38623Skarels 	if (t == 0) return 0;
226*38623Skarels 	dkkmcinit.bufaddr = (caddr_t) ((dkubmbuf<<16) + ((dkubmbuf>>16) & 03));
227*38623Skarels 	if (dkdebug < dk_nchan)
228*38623Skarels 		log(LOG_ERR, "dk_ubainit: bufaddr %x mapped %x\n", (caddr_t)dkkbuf,
229*38623Skarels 		    dkubmbuf);
230*38623Skarels 
231*38623Skarels 	return kt;
232*38623Skarels }
233*38623Skarels 
234*38623Skarels dk_open(chan, supfcn)
235*38623Skarels register chan ;
236*38623Skarels int (*supfcn)() ;
237*38623Skarels {
238*38623Skarels 	register struct	dkchan	*dkp;
239*38623Skarels 	register	s ;
240*38623Skarels 	extern 	dkkint() ;
241*38623Skarels 	extern int commchan;
242*38623Skarels 	int init;
243*38623Skarels 
244*38623Skarels 	if (chan >= dk_nchan)
245*38623Skarels 		return -ENXIO ;
246*38623Skarels 	if (dkactive == -1)	/* fail request if reset is in progress */
247*38623Skarels 		return(-ENETRESET) ;
248*38623Skarels 	dkp = &dkit[chan] ;
249*38623Skarels 	s = splimp() ;
250*38623Skarels 	/*
251*38623Skarels 	 * Channel 0 (0-3 in ISN) is reserved for maintenance.
252*38623Skarels 	 * An open on channel 0 is interpreted as a request
253*38623Skarels 	 * for an unused channel.  Channel 1 (4 in ISN or RADIAN)
254*38623Skarels 	 * is the common supervisory channel.
255*38623Skarels 	 */
256*38623Skarels 	if (chan == 0) {
257*38623Skarels 		chan = commchan+1;		/* Start above commchan */
258*38623Skarels 		while (1) {
259*38623Skarels 			dkp = &dkit[chan] ;
260*38623Skarels 			if (dkp->dk_state == 0)
261*38623Skarels 				break ;
262*38623Skarels 			chan++ ;
263*38623Skarels 			if (chan >= dk_nchan) {
264*38623Skarels 				splx(s) ;
265*38623Skarels 				return -EADDRNOTAVAIL ;
266*38623Skarels 			}
267*38623Skarels 		}
268*38623Skarels 	}
269*38623Skarels 	splx(s) ;
270*38623Skarels 
271*38623Skarels 	if (dkactive == 0)
272*38623Skarels 		if ((init = dk_init()) < 0)
273*38623Skarels 			return init ;
274*38623Skarels 
275*38623Skarels 	/*
276*38623Skarels 	 * On first use of a channel, we must
277*38623Skarels 	 * allocate per-channel UBA resource for transmit.
278*38623Skarels 	 * Some day, when we convert the receivers to use mbufs,
279*38623Skarels 	 * we'll do the same for reads.
280*38623Skarels 	 * Note that these resources can't easily be freed (I think).
281*38623Skarels 	 */
282*38623Skarels 	if (!dkp->dk_uba.ifu_uba) {
283*38623Skarels 		dkp->dk_uba.ifu_flags = UBA_CANTWAIT;
284*38623Skarels 		if (if_ubaminit(&dkp->dk_uba.ifu_info, ui->ui_ubanum, 0,
285*38623Skarels 		    btoc(CLBYTES),
286*38623Skarels 		    &dkp->dk_uba.ifu_r, 0,
287*38623Skarels 		    &dkp->dk_uba.ifu_xmt, 1) == 0) {
288*38623Skarels 			log(LOG_ERR, "dkkmc: no ubamap for channel %d\n", chan);
289*38623Skarels 			return -ENOBUFS;
290*38623Skarels 		}
291*38623Skarels 		dkp->dk_outq.ifq_maxlen = 20;
292*38623Skarels 	}
293*38623Skarels 
294*38623Skarels 	/*
295*38623Skarels 	 * Finish setting up dkp struct.
296*38623Skarels 	 */
297*38623Skarels 	if ((dkp->dk_state & DK_OPEN) ==0) {
298*38623Skarels 		dkcmd(KC_XINIT, chan, (caddr_t)0, (unsigned) 0, 0, 0) ;
299*38623Skarels 		flushall(dkp, 0);
300*38623Skarels 		dkp->dk_state |= DK_OPEN;
301*38623Skarels 		dkp->dk_state &= ~DK_LINGR;
302*38623Skarels 		dkactive++ ;
303*38623Skarels 	}
304*38623Skarels 	dkp->dk_supfcn = supfcn ;
305*38623Skarels 	return chan ;
306*38623Skarels }
307*38623Skarels 
308*38623Skarels 
309*38623Skarels /*
310*38623Skarels  * Close a channel:
311*38623Skarels  */
312*38623Skarels 
313*38623Skarels dk_close(chan)
314*38623Skarels {
315*38623Skarels 	register struct	dkchan	*dkp;
316*38623Skarels 	register s ;
317*38623Skarels 	int init;
318*38623Skarels 
319*38623Skarels 	if (dkkaddr == 0) return(-ENODEV);	/* if no init, can't close */
320*38623Skarels 						/* ie: can't do dkmaint */
321*38623Skarels 
322*38623Skarels 	s = splimp() ;
323*38623Skarels 	dkp = &dkit[chan] ;
324*38623Skarels 	if (chan == 0) {
325*38623Skarels 		for (dkp = &dkit[1]; dkp < &dkit[dk_nchan]; dkp++) {
326*38623Skarels 			if (dkp->dk_state & (DK_OPEN|DK_BUSY|DK_RCV)) {
327*38623Skarels 				dkp->dk_state |= DK_RESET ;
328*38623Skarels 				flushall(dkp, 0) ;
329*38623Skarels 				dkp->dk_state = DK_RESET ;
330*38623Skarels 			}
331*38623Skarels 		}
332*38623Skarels 		dkpanic++ ;
333*38623Skarels 		kseq = 0 ;
334*38623Skarels 		pseq = 0 ;
335*38623Skarels #ifdef notdef
336*38623Skarels 		if(dkubmbuf){   /* only deallocate mem if still allocated */
337*38623Skarels 			ubarelse(ui->ui_ubanum, &dkubmbuf);
338*38623Skarels 			dkubmbuf = NULL;
339*38623Skarels 		}
340*38623Skarels #endif
341*38623Skarels 		/* wait for protocols to close channels */
342*38623Skarels 		dkactive = -1 ;
343*38623Skarels 		DELAY(4 * hz) ;
344*38623Skarels 		/* do a dk_free for all channels */
345*38623Skarels 		for (dkp = &dkit[1]; dkp < &dkit[dk_nchan]; dkp++) {
346*38623Skarels 			dkp->dk_state &= ~DK_LINGR ;
347*38623Skarels 		}
348*38623Skarels 		dkactive = 0 ;
349*38623Skarels 		csr0 = 0 ;	/* set kmc to idle mode */
350*38623Skarels 		if ((init = dk_init()) < 0) {
351*38623Skarels 			splx(s) ;
352*38623Skarels 			return init ;
353*38623Skarels 		}
354*38623Skarels 	} else {
355*38623Skarels 		flushall(dkp, 0) ;
356*38623Skarels 		dkp->dk_state = DK_LINGR ;	/* set while UNIXP protocol
357*38623Skarels 						   closes up channel with DK */
358*38623Skarels 	}
359*38623Skarels 	splx(s) ;
360*38623Skarels 	return 0;
361*38623Skarels }
362*38623Skarels 
363*38623Skarels 
364*38623Skarels 
365*38623Skarels 
366*38623Skarels /*
367*38623Skarels  *	Close phase 2 - mark available for reassignment
368*38623Skarels  */
369*38623Skarels dk_free(chan)
370*38623Skarels {
371*38623Skarels 	if (chan > dkdebug)
372*38623Skarels 		log(LOG_ERR, "dk_free %d\n", chan) ;
373*38623Skarels 	dkit[chan].dk_state &= ~DK_LINGR ;
374*38623Skarels }
375*38623Skarels 
376*38623Skarels 
377*38623Skarels /*
378*38623Skarels  *	Reset a channel
379*38623Skarels  *	 prevents further I/O until close
380*38623Skarels  */
381*38623Skarels dk_reset(chan)
382*38623Skarels {
383*38623Skarels register struct dkchan *dkp ;
384*38623Skarels register s ;
385*38623Skarels 
386*38623Skarels 	if (chan > dkdebug)
387*38623Skarels 		log(LOG_ERR, "dk_reset %d\n", chan) ;
388*38623Skarels 	s = splimp() ;
389*38623Skarels 	dkp = &dkit[chan] ;
390*38623Skarels 	dkp->dk_state |= DK_RESET ;
391*38623Skarels 	flushall(dkp, 0) ;
392*38623Skarels 	splx(s) ;
393*38623Skarels }
394*38623Skarels 
395*38623Skarels 
396*38623Skarels 
397*38623Skarels /*
398*38623Skarels  *	Xmit a short control (interrupt) packet (max 2 bytes)
399*38623Skarels  */
400*38623Skarels dk_xint(chan, intr)
401*38623Skarels {
402*38623Skarels register s ;
403*38623Skarels 
404*38623Skarels 	s = splimp() ;
405*38623Skarels 	dkcmd(KC_SOI, chan, (caddr_t)0, (unsigned) intr, 0, 0) ;
406*38623Skarels 	splx(s) ;
407*38623Skarels 	return 0 ;
408*38623Skarels }
409*38623Skarels 
410*38623Skarels 
411*38623Skarels /*
412*38623Skarels  * Adjust window size
413*38623Skarels  */
414*38623Skarels /*ARGSUSED*/
415*38623Skarels dk_winsize(chan, win)
416*38623Skarels 	struct diocxwin *win;
417*38623Skarels {
418*38623Skarels 	return EINVAL;		/* For now... */
419*38623Skarels }
420*38623Skarels 
421*38623Skarels 
422*38623Skarels 
423*38623Skarels /*
424*38623Skarels  * Xmit data on a channel
425*38623Skarels  */
426*38623Skarels dk_xmit(chan, m, eob, ctlchar, endfcn, endparm)
427*38623Skarels 	struct mbuf *m ;
428*38623Skarels 	int (*endfcn)() ;
429*38623Skarels 	caddr_t endparm ;
430*38623Skarels {
431*38623Skarels 	register struct dkchan *dkp ;
432*38623Skarels 	short s ;
433*38623Skarels 	register struct mpacket *mbp ;
434*38623Skarels 	register struct mbuf *mb;
435*38623Skarels 	int len;
436*38623Skarels 
437*38623Skarels 	M_ON(Mxmit) ;
438*38623Skarels 	s = splimp() ;
439*38623Skarels 	dkp = &dkit[chan] ;
440*38623Skarels 	if ((dkp->dk_state & DK_RESET) || (mb = m_get(M_DONTWAIT,DKMT_HDR)) == NULL) {
441*38623Skarels 		m_freem(m);
442*38623Skarels 		splx(s) ;
443*38623Skarels 		return 0 ;
444*38623Skarels 	}
445*38623Skarels 
446*38623Skarels 	mb->m_len = 0;
447*38623Skarels 	mbp = mtod(mb, struct mpacket *);
448*38623Skarels 	mbp->mp_endfcn = endfcn ;
449*38623Skarels 	mbp->mp_endparm = endparm ;
450*38623Skarels 	mbp->mp_eob = eob;
451*38623Skarels 	mbp->mp_ctl = ctlchar;
452*38623Skarels 
453*38623Skarels 	if ((dkp->dk_state & DK_BUSY) == 0) {
454*38623Skarels 		dkp->dk_state |= DK_BUSY ;
455*38623Skarels 		dkp->dk_obuf = mbp ;
456*38623Skarels 		mb->m_next = NULL;
457*38623Skarels 		len = if_wubaput(&dkp->dk_uba, m);
458*38623Skarels 		dkcmd(KC_SEND, chan, (caddr_t) UBAI_ADDR(dkp->dk_uba.ifu_w.ifrw_info),
459*38623Skarels 		    (unsigned) len, eob ? SBOT : SBOTM, ctlchar) ;
460*38623Skarels 		splx(s) ;
461*38623Skarels 		M_OFF(Mxmit) ;
462*38623Skarels 		return dkp->dk_state ;
463*38623Skarels 	}
464*38623Skarels 
465*38623Skarels 	mb->m_next = m;
466*38623Skarels 	if (IF_QFULL(&dkp->dk_outq)) {
467*38623Skarels 		IF_DROP(&dkp->dk_outq);
468*38623Skarels 		m_freem(mb);
469*38623Skarels 	}
470*38623Skarels 	else
471*38623Skarels 		IF_ENQUEUE(&dkp->dk_outq, mb);
472*38623Skarels 	splx(s) ;
473*38623Skarels 	M_OFF(Mxmit) ;
474*38623Skarels 	return dkp->dk_state ;
475*38623Skarels }
476*38623Skarels 
477*38623Skarels /*
478*38623Skarels  * Receive into a block buffer
479*38623Skarels  */
480*38623Skarels dk_recv(chan, addr, len, mode, endfcn, endparm)
481*38623Skarels int len;
482*38623Skarels int (*endfcn)() ;
483*38623Skarels caddr_t addr, endparm ;
484*38623Skarels {
485*38623Skarels 	register struct dkchan *dkp ;
486*38623Skarels 	int s;
487*38623Skarels 
488*38623Skarels 	s = splimp() ;
489*38623Skarels 	M_ON(Mrecv) ;
490*38623Skarels 	dkp = &dkit[chan] ;
491*38623Skarels 	if (dkp->dk_state & (DK_RCV | DK_RESET)) {
492*38623Skarels 		splx(s) ;
493*38623Skarels 		return(0) ;
494*38623Skarels 	}
495*38623Skarels 	dkp->dk_ubmbase = uballoc(ui->ui_ubanum, addr, len, UBA_CANTWAIT);
496*38623Skarels 	if (dkp->dk_ubmbase == NULL) {
497*38623Skarels 		splx(s) ;
498*38623Skarels 		return(0) ;
499*38623Skarels 	}
500*38623Skarels 	dkp->dk_state |= DK_RCV ;
501*38623Skarels 	dkp->dk_endfcn = endfcn ;
502*38623Skarels 	dkp->dk_endparm = endparm ;
503*38623Skarels 	dkp->dk_rlen = len;
504*38623Skarels 	dkcmd(KC_RCVB, chan, (caddr_t) UBAI_ADDR(dkp->dk_ubmbase), (unsigned) len, mode&0377, mode>>8);
505*38623Skarels 	M_OFF(Mrecv) ;
506*38623Skarels 	splx(s);
507*38623Skarels 	return dkp->dk_state ;
508*38623Skarels }
509*38623Skarels 
510*38623Skarels /* Abort pending receive */
511*38623Skarels 
512*38623Skarels 
513*38623Skarels dk_rabort(chan, nendfcn, nendparm)
514*38623Skarels int (*nendfcn)() ;
515*38623Skarels caddr_t nendparm;
516*38623Skarels {
517*38623Skarels register struct dkchan *dkp ;
518*38623Skarels register s ;
519*38623Skarels 
520*38623Skarels 	dkp = &dkit[chan] ;
521*38623Skarels 	s = splimp() ;
522*38623Skarels 	if (dkp->dk_state & DK_RCV) {	/* cancel outstanding receive */
523*38623Skarels 		dkcmd(KC_RCVB, chan, (caddr_t)0, (unsigned) 0, 0, 0) ;
524*38623Skarels 		dkp->dk_endfcn = nendfcn ;
525*38623Skarels 		dkp->dk_endparm = nendparm ;
526*38623Skarels 	}
527*38623Skarels 	splx(s) ;
528*38623Skarels 	return dkp->dk_state ;
529*38623Skarels }
530*38623Skarels 
531*38623Skarels 
532*38623Skarels 
533*38623Skarels dk_status(chan)
534*38623Skarels {
535*38623Skarels 	if (chan >= dk_nchan)
536*38623Skarels 		return 0 ;
537*38623Skarels 	return dkit[chan].dk_state ;
538*38623Skarels }
539*38623Skarels 
540*38623Skarels 
541*38623Skarels /*
542*38623Skarels  * Various control commands to KMC
543*38623Skarels  */
544*38623Skarels dk_cmd(chan, cmd)
545*38623Skarels {
546*38623Skarels 	register struct dkchan *dkp ;
547*38623Skarels 	register s ;
548*38623Skarels 
549*38623Skarels 	dkp = &dkit[chan] ;
550*38623Skarels 	if (cmd & (DKC_XINIT|DKC_FLUSH)) {
551*38623Skarels 		/*for either command do the same thing:
552*38623Skarels 		 * reinit the transmitter and flush any pending output.
553*38623Skarels 		 * NOTE: for the kmc, there is no response to XINIT
554*38623Skarels 		 * and no send complete for flush
555*38623Skarels 		 */
556*38623Skarels 		s = splimp() ;
557*38623Skarels 		dkcmd(KC_XINIT, chan, (caddr_t)0, (unsigned) 0, 0, 0) ;
558*38623Skarels 		flushall(dkp, -1) ;
559*38623Skarels 		dkcmd(KC_CMD, chan, (caddr_t)0, (unsigned) DKC_FLUSH, 0, 0) ;
560*38623Skarels 		splx(s);
561*38623Skarels 		cmd &= ~(DKC_XINIT|DKC_FLUSH) ;
562*38623Skarels 	}
563*38623Skarels 	if (cmd)
564*38623Skarels 		dkcmd(KC_CMD, chan, (caddr_t)0, (unsigned) cmd, 0, 0) ;
565*38623Skarels }
566*38623Skarels 
567*38623Skarels 
568*38623Skarels /*
569*38623Skarels  *	Note that flushall is often recursive when a tty driver
570*38623Skarels  *	is involved.
571*38623Skarels  */
572*38623Skarels 
573*38623Skarels static
574*38623Skarels flushall(dkp, rwflag)
575*38623Skarels register struct dkchan *dkp ;
576*38623Skarels {
577*38623Skarels 	register s ;
578*38623Skarels 	register struct mpacket *mbp ;
579*38623Skarels 	int (*endfcn)();
580*38623Skarels 
581*38623Skarels 	s = splimp() ;
582*38623Skarels 	if ((dkp->dk_state & DK_RCV) && (rwflag >= 0)) {
583*38623Skarels 		dkcmd(KC_RCVB, dkp-dkit, (caddr_t)0, (unsigned) 0, 0, 0) ;
584*38623Skarels 		dkp->dk_state &= ~DK_RCV ;
585*38623Skarels 		if (dkp->dk_ubmbase) {
586*38623Skarels 			ubarelse(ui->ui_ubanum, &dkp->dk_ubmbase);
587*38623Skarels 			dkp->dk_ubmbase = NULL;
588*38623Skarels 		}
589*38623Skarels 		if (endfcn = dkp->dk_endfcn) {
590*38623Skarels 			dkp->dk_endfcn = NULL ;
591*38623Skarels 			(*endfcn)(dkp->dk_endparm, dkp-dkit, dkp->dk_rlen, DKR_ABORT, 0) ;
592*38623Skarels 		}
593*38623Skarels 	}
594*38623Skarels 
595*38623Skarels 	/* flush all writes current and pending */
596*38623Skarels 
597*38623Skarels 	if ((dkp->dk_state & DK_BUSY) && (rwflag <= 0)) {
598*38623Skarels 		register struct mbuf *m ;
599*38623Skarels 
600*38623Skarels 		/* flush current write */
601*38623Skarels 		if (mbp = dkp->dk_obuf) {
602*38623Skarels 			dkp->dk_obuf = NULL;
603*38623Skarels 			if (endfcn = mbp->mp_endfcn) {
604*38623Skarels 				mbp->mp_endfcn = NULL;
605*38623Skarels 				(endfcn)(mbp->mp_endparm, dkp-dkit);
606*38623Skarels 			}
607*38623Skarels 			m_free(dtom(mbp));
608*38623Skarels 		}
609*38623Skarels 		/* flush any pending writes which may be queued up */
610*38623Skarels 		while (1) {
611*38623Skarels 			IF_DEQUEUE(&dkp->dk_outq, m);
612*38623Skarels 			if (!m) break;
613*38623Skarels 			mbp = mtod(m, struct mpacket *);
614*38623Skarels 			if (endfcn = mbp->mp_endfcn) {
615*38623Skarels 				mbp->mp_endfcn = NULL;
616*38623Skarels 				(endfcn)(mbp->mp_endparm, dkp-dkit);
617*38623Skarels 			}
618*38623Skarels 			m_freem(m);
619*38623Skarels 		}
620*38623Skarels 		/* mark channel as not busy */
621*38623Skarels 		dkp->dk_state &= ~DK_BUSY ;
622*38623Skarels 	}
623*38623Skarels 	if ((dkp->dk_state & DK_OPEN) && (rwflag >= 0)) {
624*38623Skarels 		dkcmd(KC_CLOSE, dkp-dkit, (caddr_t)0, (unsigned) 0, 0, 0) ;
625*38623Skarels 		if (dkp->dk_state & DK_BUSY){
626*38623Skarels 			mbp = dkp->dk_obuf;
627*38623Skarels 			dkp->dk_obuf = NULL;
628*38623Skarels 			if (endfcn = mbp->mp_endfcn) {
629*38623Skarels 				mbp->mp_endfcn = NULL;
630*38623Skarels 				(endfcn)(mbp->mp_endparm, dkp-dkit);
631*38623Skarels 			}
632*38623Skarels 			m_free(dtom(mbp));
633*38623Skarels 			dkp->dk_state &= ~DK_BUSY ;
634*38623Skarels 		}
635*38623Skarels 	}
636*38623Skarels 	splx(s) ;
637*38623Skarels }
638*38623Skarels 
639*38623Skarels 
640*38623Skarels short dup_count = 0; /* counter for number of duplicate sends */
641*38623Skarels 
642*38623Skarels /*
643*38623Skarels  * Routine to handle interrupts from the KMC
644*38623Skarels  *
645*38623Skarels  * This routine is called when
646*38623Skarels  * the KMC generates an unsolicited interrupt (VEC4 == 1)
647*38623Skarels  *
648*38623Skarels  * These interrupts are used by the KMC to notify dkit_kmc.c
649*38623Skarels  * of events such as output buffer completions
650*38623Skarels  * csr6 & csr7 point to dkkstat
651*38623Skarels  */
652*38623Skarels dkkint()
653*38623Skarels {
654*38623Skarels 	register struct dkchan *dkp;
655*38623Skarels 	register struct dkkin *sp;
656*38623Skarels 	register chan;
657*38623Skarels 	struct mpacket *mbp ;
658*38623Skarels 	int (*endfcn)();
659*38623Skarels 
660*38623Skarels 	M_ON(Mkint) ;
661*38623Skarels 
662*38623Skarels 	chan = csr0 ;	/* temp for cc -O bug */
663*38623Skarels 	if((chan & 01) == 1)	/* 1 or 3 -> ignore */
664*38623Skarels 		return;
665*38623Skarels 	sp = stat7 ;	/* next response to be processed */
666*38623Skarels 	while (csr6 != csr7) {
667*38623Skarels 		if (kseqchk)
668*38623Skarels 			if ((((sp->k_chan >> 8)&0377) != kseq) ||
669*38623Skarels 			    (((sp->k_type >> 8)&0377) != kseq)) {
670*38623Skarels 				log(LOG_ERR, "dkkint: kseq %x chan %d type %x\n",
671*38623Skarels 					kseq, sp->k_chan, sp->k_type) ;
672*38623Skarels 				goto reset ;
673*38623Skarels 			}
674*38623Skarels 		kseq = (kseq + 1) & 0377 ;
675*38623Skarels 		sp->k_addr = pseq ;
676*38623Skarels 		pseq++ ;
677*38623Skarels 		chan = sp->k_chan & 0377 ;	/* mask off seq. # */
678*38623Skarels 		dkp = &dkit[chan];
679*38623Skarels 		if (chan > dkdebug) {
680*38623Skarels 			log(LOG_ERR, " dkkint: head %d tail %d", csr6, csr7) ;
681*38623Skarels 			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) ;
682*38623Skarels 		}
683*38623Skarels 		switch(sp->k_type & 0377) {
684*38623Skarels 		case KS_CNTL:
685*38623Skarels 			if (dkp->dk_supfcn)
686*38623Skarels 				(*dkp->dk_supfcn)(chan, sp->k_ctl) ;
687*38623Skarels 			break ;
688*38623Skarels 		case KS_EOI:
689*38623Skarels 			break ;
690*38623Skarels 		case KS_SEND:
691*38623Skarels 			mbp = dkp->dk_obuf ;
692*38623Skarels 			if (mbp == NULL) {
693*38623Skarels 				if (dkp->dk_state & (DK_RESET|DK_LINGR))
694*38623Skarels 					break;	/* flushall was already called */
695*38623Skarels 				log(LOG_ERR, "dkkint: xbufout chan %d state %x\n", chan, dkp->dk_state) ;
696*38623Skarels 				log(LOG_ERR, "head %d tail %d", csr6, csr7) ;
697*38623Skarels 				log(LOG_ERR, " type %x len %d mode %x ctl %x\n",
698*38623Skarels 				sp->k_type&0377, sp->k_len, sp->k_mode, sp->k_ctl) ;
699*38623Skarels 				break ;
700*38623Skarels 			}
701*38623Skarels 			dkp->dk_state &= ~DK_BUSY;
702*38623Skarels 			dkp->dk_obuf = NULL ;
703*38623Skarels 			if (endfcn = mbp->mp_endfcn) {
704*38623Skarels 				mbp->mp_endfcn = NULL;
705*38623Skarels 				(endfcn)(mbp->mp_endparm, chan) ;
706*38623Skarels 			}
707*38623Skarels 			m_free(dtom(mbp)) ;
708*38623Skarels 			if (dkp->dk_uba.ifu_xtofree) {
709*38623Skarels 				m_freem(dkp->dk_uba.ifu_xtofree);
710*38623Skarels 				dkp->dk_uba.ifu_xtofree = 0;
711*38623Skarels 			}
712*38623Skarels 			if (dkp->dk_outq.ifq_head)
713*38623Skarels 				dkstart(dkp) ;
714*38623Skarels 			break;
715*38623Skarels 		case KS_RDB:
716*38623Skarels 			if (((dkp->dk_state & DK_RCV) == 0) && dkp->dk_endfcn) {
717*38623Skarels 				log(LOG_ERR, "dkkint: rbufin chan %d state %x\n", chan, dkp->dk_state) ;
718*38623Skarels 				log(LOG_ERR, " head %d tail %d\n", csr6, csr7) ;
719*38623Skarels 				log(LOG_ERR, " type %x len %d mode %x ctl %x\n",
720*38623Skarels 				sp->k_type&0377, sp->k_len, sp->k_mode, sp->k_ctl) ;
721*38623Skarels 
722*38623Skarels 				if (sp->k_ctl)
723*38623Skarels 					break ;
724*38623Skarels 				else {
725*38623Skarels 					stat7 = sp ;	/* save it for dump */
726*38623Skarels 					csr0 = 3 ;	/* stop KMC */
727*38623Skarels 					panic("") ;	/* KMC probably wrote
728*38623Skarels 						into a mbuf we don't own */
729*38623Skarels 				}
730*38623Skarels 			}
731*38623Skarels 			dkp->dk_state &= ~DK_RCV ;
732*38623Skarels 			if (dkp->dk_ubmbase) {
733*38623Skarels 				ubarelse(ui->ui_ubanum, &dkp->dk_ubmbase);
734*38623Skarels 				dkp->dk_ubmbase = NULL;
735*38623Skarels 			}
736*38623Skarels 			if (endfcn = dkp->dk_endfcn) {
737*38623Skarels 				dkp->dk_endfcn = NULL;
738*38623Skarels 				(endfcn)(dkp->dk_endparm, chan, sp->k_len, sp->k_mode, sp->k_ctl) ;
739*38623Skarels 			}
740*38623Skarels 			break;
741*38623Skarels 		case KS_ERR:
742*38623Skarels 			log(LOG_ERR, "dkkint: err : chan %d, code %x\nchead: %d, ctail: %d, rhead: %d, rtail: %d\n",
743*38623Skarels 				chan, sp->k_len, csr4, csr5, csr6, csr7);
744*38623Skarels 
745*38623Skarels 			/* if error is duplicate send, only close that chan, */
746*38623Skarels 			/* not the whole interface */
747*38623Skarels 
748*38623Skarels 			if (sp->k_len == E_DUP)  {
749*38623Skarels 				dup_count++;
750*38623Skarels 				if (dkp->dk_state & DK_OPEN)  {
751*38623Skarels 					dk_reset(chan);
752*38623Skarels 				}
753*38623Skarels 				break;
754*38623Skarels 			}
755*38623Skarels reset:
756*38623Skarels 			(void) dk_close(0) ;
757*38623Skarels 			return ;
758*38623Skarels 		default:
759*38623Skarels 			log(LOG_ERR, "dkkint: chan %d, type %x, len %d, ctl %x, mode %x\n",
760*38623Skarels 			chan, sp->k_type&0377, sp->k_len, sp->k_ctl, sp->k_mode);
761*38623Skarels 			goto reset ;
762*38623Skarels 		}	/* end switch */
763*38623Skarels 
764*38623Skarels 		if (csr7 == dkk_nstat-1) {
765*38623Skarels 			csr7 = 0 ;
766*38623Skarels 			sp = &dkkstat[0] ;
767*38623Skarels 		} else {
768*38623Skarels 			csr7++ ;
769*38623Skarels 			sp++ ;
770*38623Skarels 		}
771*38623Skarels 
772*38623Skarels 	}	/* end while */
773*38623Skarels 	stat7 = sp ;
774*38623Skarels 	M_OFF(Mkint) ;
775*38623Skarels }
776*38623Skarels 
777*38623Skarels /*
778*38623Skarels  * Start (Restart) transmission on the given line
779*38623Skarels  */
780*38623Skarels dkstart(dkp)
781*38623Skarels register struct dkchan *dkp;
782*38623Skarels {
783*38623Skarels 	register struct mpacket *mbp;
784*38623Skarels 	register struct mbuf *m;
785*38623Skarels 	int len;
786*38623Skarels 
787*38623Skarels 	/*
788*38623Skarels 	 * If it is currently active, just return
789*38623Skarels 	 */
790*38623Skarels 	if (dkp->dk_state&DK_BUSY)
791*38623Skarels 		return;
792*38623Skarels 
793*38623Skarels 	IF_DEQUEUE(&dkp->dk_outq, m);
794*38623Skarels 	if (!m)
795*38623Skarels 		return;
796*38623Skarels 	mbp = mtod(m, struct mpacket *);
797*38623Skarels 
798*38623Skarels 	dkp->dk_state |= DK_BUSY ;
799*38623Skarels 	dkp->dk_obuf = mbp ;
800*38623Skarels 	len = if_wubaput(&dkp->dk_uba, m->m_next);
801*38623Skarels 	dkcmd(KC_SEND, dkp-dkit, (caddr_t) UBAI_ADDR(dkp->dk_uba.ifu_w.ifrw_info),
802*38623Skarels 	    (unsigned) len, mbp->mp_eob ? SBOT : SBOTM, mbp->mp_ctl) ;
803*38623Skarels }
804*38623Skarels 
805*38623Skarels /*
806*38623Skarels  * Put command in dkkcmdbuf which is pointed by csr4~5
807*38623Skarels  */
808*38623Skarels dkcmd(type, chan, addr, len, mode, ctl)
809*38623Skarels int type, chan;
810*38623Skarels caddr_t addr ;
811*38623Skarels unsigned len ;
812*38623Skarels {
813*38623Skarels 	register struct dkkin *sp;
814*38623Skarels 	register s;
815*38623Skarels 	register next;
816*38623Skarels 	struct timeval tv1, tv2;
817*38623Skarels 
818*38623Skarels 	M_ON(Mcmd) ;
819*38623Skarels 	s = csr0 ;
820*38623Skarels 	if ((s & 3) != 2)
821*38623Skarels 		return;
822*38623Skarels 
823*38623Skarels 	s = splimp();
824*38623Skarels 	next = (csr4+1)%dkk_ncmd;
825*38623Skarels 	if (csr5 == next) {
826*38623Skarels 		struct dkchan *dkp;
827*38623Skarels 
828*38623Skarels 		csr0 = 3;
829*38623Skarels 		for (dkp = &dkit[1]; dkp < &dkit[dk_nchan]; dkp++)
830*38623Skarels 			if (dkp->dk_state & (DK_OPEN|DK_BUSY|DK_RCV))
831*38623Skarels 				dkp->dk_state |= DK_RESET;
832*38623Skarels 		splx(s);
833*38623Skarels 		log(LOG_ERR, "KMC RESET\n");
834*38623Skarels 		return;
835*38623Skarels 	}
836*38623Skarels 
837*38623Skarels 	sp = cmd4 ;
838*38623Skarels 	sp->k_type = type | ((pseq&0177)<<9) ;
839*38623Skarels 	sp->k_chan = chan | ((kseq&0377)<<8) ;
840*38623Skarels 	sp->k_addr = ((int)addr << 16) + ((int)addr >> 16) ;
841*38623Skarels 	sp->k_len = len ;
842*38623Skarels 	sp->k_mode = mode ;
843*38623Skarels 	sp->k_ctl = ctl ;
844*38623Skarels 	pseq++ ;
845*38623Skarels 
846*38623Skarels 	csr4 = next;
847*38623Skarels 	cmd4 = &dkkcmdbuf[next];
848*38623Skarels 
849*38623Skarels 	if (chan > dkdebug) {
850*38623Skarels 	    	log(LOG_ERR, " dkcmd: head %d, tail %d", csr4, csr5);
851*38623Skarels 	    	log(LOG_ERR, " type %x, chan %d, addr %x, len %d",
852*38623Skarels 						type, chan, addr, len);
853*38623Skarels 		log(LOG_ERR, " mode %x, ctl %x\n", mode, ctl);
854*38623Skarels 	}
855*38623Skarels 	splx(s) ;
856*38623Skarels 	M_OFF(Mcmd) ;
857*38623Skarels }
858*38623Skarels 
859*38623Skarels #endif
860