xref: /original-bsd/sys/tahoe/vba/vxc.c (revision e2944021)
1 /*	vxc.c	1.5	86/01/12	*/
2 
3 #include "vx.h"
4 #if NVX > 0
5 /*
6  * VIOC driver
7  */
8 #ifdef VXPERF
9 #define	DOSCOPE
10 #endif
11 
12 #include "param.h"
13 #include "file.h"
14 #include "ioctl.h"
15 #include "tty.h"
16 #include "errno.h"
17 #include "time.h"
18 #include "kernel.h"
19 #include "proc.h"
20 
21 #include "../tahoevba/vioc.h"
22 #include "../tahoesna/snadebug.h"
23 #include "../tahoevba/scope.h"
24 
25 #define CMDquals 0
26 #define RSPquals 1
27 #define UNSquals 2
28 
29 extern	struct	vcx	vcx[] ;
30 extern	struct	tty	vx_tty[];
31 struct	vcmds	v_cmds[NVIOCX] ;
32 
33 extern char vxtype[];
34 extern char vxbbno;
35 extern char vxbopno[];
36 #ifdef SNA_DEBUG
37 extern vbrall();
38 #endif SNA_DEBUG
39 extern struct vxcmd *vobtain();
40 
41 #ifdef VX_DEBUG
42 #include "../vba/vxdebug.h"
43 #endif
44 
45 /*
46  *  Write a command out to the VIOC
47  */
48 vcmd(n, cmdad)
49 register int	n ;
50 register caddr_t cmdad ;		/* command address */
51 {
52 
53 	register struct	vcmds *cp ;
54 	register struct vcx *xp;
55 	int	s ;
56 
57 	s = spl8() ;
58 	cp = &v_cmds[n] ;
59 	xp = &vcx[n];
60 	if (xp->v_state&V_RESETTING && cmdad != NULL) {
61 		/*
62 		 * When the vioc is resetting, don't process
63 		 * anything other than LIDENT commands.
64 		 */
65 		register struct vxcmd *cmdp = (struct vxcmd *)
66 				((char *)cmdad - sizeof(cmdp->c_fwd));
67 		if (cmdp->cmd != LIDENT) {
68 			vrelease(xp, cmdp);
69 			return(0);
70 		}
71 	}
72 	if (cmdad != (caddr_t) 0) {
73 		cp->cmdbuf[cp->v_fill] = cmdad ;
74 		if( ++cp->v_fill >= VC_CMDBUFL )  cp->v_fill = 0 ;
75 		if(cp->v_fill == cp->v_empty) {
76 			vpanic("vc: CMD Q OVFLO") ;
77 			vxstreset(n);
78 			splx(s);
79 			return(0);
80 		}
81 		cp->v_cmdsem++;
82 	}
83 	if(cp->v_cmdsem && cp->v_curcnt < vcx[n].v_maxcmd) {
84 		cp->v_cmdsem--;
85 		cp->v_curcnt++;
86 		vinthandl(n, ((V_BSY | CMDquals) << 8) | V_INTR ) ;
87 	}
88 	splx(s) ;
89 	return(1);
90 }
91 
92 /*
93  * VIOC acknowledge interrupt.  The VIOC has received the new
94  * command.  If no errors, the new command becomes one of 16 (max)
95  * current commands being executed.
96  */
97 vackint(n)
98 register n ;		/* VIOC number */
99 {
100 
101 	register struct	vblok	*vp ;
102 	register struct	vcmds	*cp ;
103 	register s;
104 
105 	scope_out(5);
106 	if (vxtype[n]) {	/* Its a BOP */
107 #ifdef SNA_DEBUG
108 		if (snadebug & SVIOC)
109 		printf("vack: interrupt from BOP at VIOC%d,1st vector.\n",n);
110 		vbrall(n); 	/* Int. from BOP, port 0 */
111 #endif
112 		return;
113 	}
114 	s = spl8();
115 	vp = VBAS(n) ;
116 	cp = &v_cmds[n] ;
117 	if( vp->v_vcid & V_ERR ) {
118 		register char *resp;
119 		register i;
120 		printf ("INTR ERR type = %x VIOC = %x, v_dcd: %lx\n",
121 			vp->v_vcid & 07, n, vp->v_dcd & 0xff);
122 		/* resp = (char *)vp + (vp->v_rspoff & 0x7FFF); */
123 		resp = (char *)(&vcx[n])->v_mricmd;
124 		for(i=0; i<16; i++)
125 			printf("%x ", resp[i]&0xff);
126 		vpanic( "\nvcc: vackint") ;
127 		splx(s);
128 		vxstreset(n);
129 		return ;
130 	} else
131 	if((vp->v_hdwre&017) == CMDquals)  {
132 #ifdef VX_DEBUG
133 		if (vxintr4 & VXERR4) {	/* causes VIOC INTR ERR 4 */
134 			register struct vxcmd *cp1;
135 			register struct vxcmd *cp0 = (struct vxcmd *)
136 				((long)cp->cmdbuf[cp->v_empty] - 4);
137 			if ((cp0->cmd == XMITDTA) || (cp0->cmd == XMITIMM)) {
138 				cp1 = vobtain(&vcx[n]);
139 				*cp1 = *cp0;
140 				vxintr4 &= ~VXERR4;
141 				(void) vcmd(n,&cp1->cmd);
142 			}
143 		}
144 #endif
145 		cp->v_curcmd[vp->v_vcid & VCMDLEN-1] = cp->cmdbuf[cp->v_empty] ;
146 		if( ++cp->v_empty >= VC_CMDBUFL )  cp->v_empty = 0 ;
147 	}
148 	if( ++cp->v_itrempt >= VC_IQLEN ) cp->v_itrempt = 0 ;
149 	vintempt(n) ;
150 	splx(s);
151 	(void) vcmd(n, (caddr_t)0);	/* queue next cmd, if any */
152 }
153 
154 /*
155  *  Command Response interrupt.  The Vioc has completed
156  *  a command.  The command may now be returned to
157  *  the appropriate device driver .
158  */
159 vcmdrsp(n)
160 register n ;
161 {
162 
163 	register struct	vblok	*vp ;
164 	register struct	vcmds	*cp ;
165 	register caddr_t cmd ;
166 	register char *resp ;
167 	register k ;
168 	register int s ;
169 
170 	scope_out(6);
171 	if (vxtype[n]) {	/* Its a BOP */
172 		printf("vcmdrsp: stray interrupt from BOP at VIOC%d...\n",n);
173 		return;
174 	}
175 	s = spl8();
176 	vp = VBAS(n) ;
177 	cp = &v_cmds[n] ;
178 	resp = (char *)vp;
179 	resp += vp->v_rspoff & 0x7FFF;
180 
181 	if( (k=resp[1]) & V_UNBSY )  {
182 		k &= VCMDLEN-1;
183 		cmd = cp->v_curcmd[k];
184 		cp->v_curcmd[k] = (caddr_t)0;
185 		cp->v_curcnt--;
186 		k = *((short *)&resp[4]);	/* cmd operation code */
187 		if((k & 0xFF00) == LIDENT) {	/* want hiport number */
188 			for(k=0; k<VRESPLEN; k++)
189 				cmd[k] = resp[k+4];
190 		}
191 		resp[1] = 0;
192 		vxxint(n, (struct vxcmd *)cmd) ;
193 		if ((&vcx[n])->v_state == V_RESETTING) return;
194 	}
195 	else {
196 		vpanic( "vc, cmdresp debug") ;
197 		splx(s);
198 		vxstreset(n);
199 		return;
200 	}
201 
202 	vinthandl(n, ( (V_BSY | RSPquals) << 8 ) | V_INTR ) ;
203 	splx(s);
204 
205 }
206 
207 
208 /*
209  * Unsolicited interrupt.
210  */
211 vunsol(n)
212 register(n) ;
213 {
214 
215 	register struct	vblok	*vp ;
216 	register s;
217 
218 	scope_out(1);
219 	if (vxtype[n]) {	/* Its a BOP */
220 		printf("vunsol: stray interrupt from BOP at VIOC%d...\n",n);
221 		return;
222 	}
223 	s = spl8();
224 	vp = VBAS(n) ;
225 	if(vp->v_uqual & V_UNBSY) {
226 		vxrint(n) ;
227 		vinthandl(n, ( (V_BSY | UNSquals) << 8 ) | V_INTR ) ;
228 #ifdef notdef
229 	} else {
230 		vpanic("vc: UNSOL INT ERR") ;
231 		splx(s);
232 		vxstreset(n);
233 #endif
234 	}
235 	splx(s);
236 }
237 
238 /*
239  * Enqueue an interrupt
240  */
241 vinthandl(n, item)
242 register int n ;
243 register item ;
244 {
245 
246 	register struct  vcmds *cp ;
247 	register int	empflag = 0 ;
248 
249 	cp = &v_cmds[n] ;
250 	if( cp->v_itrfill == cp->v_itrempt ) empflag++ ;
251 	cp->v_itrqueu[cp->v_itrfill] = item ;
252 	if( ++cp->v_itrfill >= VC_IQLEN ) cp->v_itrfill = 0 ;
253 	if(cp->v_itrfill == cp->v_itrempt) {
254 		vpanic( "vc: INT Q OVFLO" ) ;
255 		vxstreset(n);
256 	}
257 	else if( empflag ) vintempt(n) ;
258 }
259 
260 vintempt(n)
261 register int n ;
262 {
263 	register  struct  vcmds *cp ;
264 	register  struct  vblok *vp ;
265 	register  short   item ;
266 	register  short	*intr ;
267 
268 	vp = VBAS(n) ;
269 	if(vp->v_vioc & V_BSY) return ;
270 	cp = &v_cmds[n] ;
271 	if(cp->v_itrempt == cp->v_itrfill) return ;
272 	item = cp->v_itrqueu[cp->v_itrempt] ;
273 	intr = (short *)&vp->v_vioc ;
274 	switch( (item >> 8) & 03 ) {
275 
276 	case CMDquals:		/* command */
277 		{
278 		int phys;
279 
280 		if(cp->v_empty == cp->v_fill || vp->v_vcbsy&V_BSY)
281 			break;
282 		(&vcx[n])->v_mricmd = (caddr_t)cp->cmdbuf[cp->v_empty];
283 		phys = vtoph((struct proc *)0, (unsigned)cp->cmdbuf[cp->v_empty]) ; /* should be a sys address */
284 		vp->v_vcp[0] = ((short *)&phys)[0];
285 		vp->v_vcp[1] = ((short *)&phys)[1];
286 		vp->v_vcbsy = V_BSY ;
287 		*intr = item ;
288 		}
289 		scope_out(4);
290 		break ;
291 
292 	case RSPquals:		/* command response */
293 		*intr = item ;
294 		scope_out(7);
295 		break ;
296 
297 	case UNSquals:		/* unsolicited interrupt */
298 		vp->v_uqual = 0 ;
299 		*intr = item ;
300 		scope_out(2);
301 		break ;
302 	}
303 }
304 
305 
306 /* start a reset on a vioc after error (hopefully) */
307 vxstreset(n)
308 	register n;
309 {
310 	register struct vcx *xp;
311 	register struct	vblok *vp ;
312 	register struct vxcmd *cp;
313 	register int j;
314 	extern int vxinreset();
315 	int	s ;
316 
317 	s = spl8() ;
318 	vp = VBAS(n);
319 	xp = &vcx[n];
320 
321 	if (xp->v_state&V_RESETTING)
322 		/*
323 		 * Avoid infinite recursion.
324 		 */
325 		return;
326 
327 	/*
328 	 * Zero out the vioc structures, mark the vioc as being
329 	 * reset, reinitialize the free command list, reset the vioc
330 	 * and start a timer to check on the progress of the reset.
331 	 */
332 	bzero((caddr_t)&v_cmds[n], (unsigned)sizeof (struct vcmds));
333 	bzero((caddr_t)xp, (unsigned)sizeof (struct vcx));
334 
335 	/*
336 	 * Setting V_RESETTING prevents others from issuing
337 	 * commands while allowing currently queued commands to
338 	 * be passed to the VIOC.
339 	 */
340 	xp->v_state |= V_RESETTING;
341 	for(j=0; j<NVCXBUFS; j++)	/* init all cmd buffers */
342 	{
343 		cp = &xp->vx_lst[j];	/* index a buffer */
344 		cp->c_fwd = &xp->vx_lst[j+1];	/* point to next buf */
345 	}
346 	xp->vx_avail = &xp->vx_lst[0];	/* set idx to 1st free buf */
347 	cp->c_fwd = (struct vxcmd *)0;	/* mark last buf in free list */
348 
349 	printf("resetting VIOC %x .. ", n);
350 
351 	vp->v_fault = 0 ;
352 	vp->v_vioc = V_BSY ;
353 	vp->v_hdwre = V_RESET ;		/* reset interrupt */
354 
355 	timeout(vxinreset, (caddr_t)n, hz*5);
356 	splx(s);
357 	return;
358 }
359 
360 /* continue processing a reset on a vioc after an error (hopefully) */
361 vxinreset(vioc)
362 caddr_t vioc;
363 {
364 	register int n = (int)vioc;
365 	register struct	vblok *vp ;
366 	int s = spl8();
367 printf("vxinreset ");
368 
369 	vp = VBAS(n);
370 
371 	/*
372 	 * See if the vioc has reset.
373 	 */
374 	if (vp->v_fault != VREADY) {
375 		printf("failed\n");
376 		splx(s);
377 		return;
378 	}
379 
380 	/*
381 	 * Send a LIDENT to the vioc and mess with carrier flags
382 	 * on parallel printer ports.
383 	 */
384 	vxinit(n, (long)0);
385 	splx(s);
386 }
387 
388 /*
389  * Restore modem control, parameters and restart output.
390  * Since the vioc can handle no more then 24 commands at a time
391  * and we could generate as many as 48 commands, we must do this in
392  * phases, issuing no more then 16 commands at a time.
393  */
394 /* finish the reset on the vioc after an error (hopefully) */
395 vxfnreset(n, cp)
396 register int n;
397 register struct vxcmd *cp;
398 {
399 	register struct vcx *xp;
400 	register struct	vblok *vp ;
401 	register struct tty *tp;
402 	register int i;
403 #ifdef notdef
404 	register int on;
405 #endif
406 	extern int vxrestart();
407 	int s = spl8();
408 printf("vxfnreset ");
409 
410 	vp = VBAS(n);
411 	xp = &vcx[n];
412 
413 	xp->v_loport = cp->par[5];	/* save low port number */
414 	xp->v_hiport = cp->par[7];/* VIOC knows high port numbr */
415 	vrelease(xp,cp);	/* done with this control block */
416 	xp->v_nbr = n;		/* assign VIOC-X board number */
417 
418 	xp->v_state &= ~V_RESETTING;
419 
420 	vp->v_vcid = 0;
421 
422 	/*
423 	 * Restore modem information and control.
424 	 */
425 	for(i=xp->v_loport; i<=xp->v_hiport; i++) {
426 		tp = &vx_tty[i+n*16];
427 		if (tp->t_state&(TS_ISOPEN|TS_WOPEN)) {
428 			tp->t_state &= ~TS_CARR_ON;
429 			vcmodem(tp->t_dev, VMOD_ON);
430 			if (tp->t_state&TS_CARR_ON)  {
431 				wakeup((caddr_t)&tp->t_canq) ;
432 			}
433 			else {
434 				if(tp->t_state & TS_ISOPEN) {
435 					ttyflush(tp, FREAD|FWRITE);
436 					if(tp->t_state&TS_FLUSH)
437 						wakeup((caddr_t)&tp->t_state) ;
438 					if((tp->t_flags&NOHANG)==0) {
439 						gsignal(tp->t_pgrp, SIGHUP) ;
440 						gsignal(tp->t_pgrp, SIGCONT);
441 					}
442 				}
443 			}
444 		}
445 		/*
446 		 * If carrier has changed while we were resetting,
447 		 * take appropriate action.
448 		 */
449 #ifdef notdef
450 		on = vp->v_dcd & 1<<i;
451 		if (on && (tp->t_state&TS_CARR_ON) == 0) {
452 			tp->t_state |= TS_CARR_ON ;
453 			wakeup((caddr_t)&tp->t_canq) ;
454 		} else if (!on && tp->t_state&TS_CARR_ON) {
455 			tp->t_state &= ~TS_CARR_ON ;
456 			if(tp->t_state & TS_ISOPEN) {
457 				ttyflush(tp, FREAD|FWRITE);
458 				if(tp->t_state&TS_FLUSH)
459 					wakeup((caddr_t)&tp->t_state) ;
460 				if((tp->t_flags&NOHANG)==0) {
461 					gsignal(tp->t_pgrp, SIGHUP) ;
462 					gsignal(tp->t_pgrp, SIGCONT);
463 				}
464 			}
465 		}
466 #endif
467 	}
468 
469 	xp->v_state |= V_RESETTING;
470 
471 	timeout(vxrestart, (caddr_t)n, hz);
472 	splx(s);
473 }
474 
475 /*
476  * Restore a particular aspect of the VIOC.
477  */
478 vxrestart(vioc)
479 caddr_t vioc;
480 {
481 	register struct tty *tp, *tp0;
482 	register struct vcx *xp;
483 	register int i, cnt;
484 	register int n = (int)vioc;
485 	int s = spl8();
486 
487 	cnt = n>>8;
488 printf("vxrestart %d ",cnt);
489 	n &= 0xff;
490 
491 	tp0 = &vx_tty[n*16];
492 	xp = &vcx[n];
493 
494 	xp->v_state &= ~V_RESETTING;
495 
496 	for(i=xp->v_loport; i<=xp->v_hiport; i++) {
497 		tp = tp0 + i;
498 		if (cnt != 0) {
499 			tp->t_state &= ~(TS_BUSY|TS_TIMEOUT);
500 			if(tp->t_state&(TS_ISOPEN|TS_WOPEN))	/* restart pending output */
501 				vxstart(tp);
502 		} else {
503 			if (tp->t_state&(TS_WOPEN|TS_ISOPEN))
504 				vxcparam(tp->t_dev, 0);
505 		}
506 	}
507 
508 	if (cnt == 0) {
509 		xp->v_state |= V_RESETTING;
510 		timeout(vxrestart, (caddr_t)(n + 1*256), hz);
511 	} else
512 		printf("done\n");
513 	splx(s);
514 }
515 
516 vxreset(dev)
517 dev_t dev;
518 {
519 	vxstreset(minor(dev)>>4);	/* completes asynchronously */
520 }
521 
522 vxfreset(n)
523 register int n;
524 {
525 
526 	if (n < 0 || n > NVX || VBAS(n) == NULL)
527 		return(ENODEV);
528 	vcx[n].v_state &= ~V_RESETTING;
529 	vxstreset(n);
530 	return(0);		/* completes asynchronously */
531 }
532 #endif
533 
534