1*25857Ssam /* vxc.c 1.3 86/01/12 */ 224002Ssam 324002Ssam #include "vx.h" 424002Ssam #if NVX > 0 524002Ssam /* 624002Ssam * VIOC driver 724002Ssam */ 824002Ssam #include "../h/param.h" 924002Ssam #include "../h/file.h" 1024002Ssam #include "../h/ioctl.h" 1124002Ssam #include "../h/tty.h" 1224002Ssam #include "../h/errno.h" 1324002Ssam #include "../h/time.h" 1424002Ssam #include "../h/kernel.h" 1525675Ssam #include "../h/proc.h" 1625675Ssam #include "../tahoevba/vioc.h" 1724002Ssam #include "../sna/snadebug.h" 1824002Ssam #ifdef VXPERF 1925675Ssam #include "../tahoevba/scope.h" 2024002Ssam #endif VXPERF 2124002Ssam 2224002Ssam #define CMDquals 0 2324002Ssam #define RSPquals 1 2424002Ssam #define UNSquals 2 2524002Ssam 2624002Ssam extern struct vcx vcx[] ; 2724002Ssam extern struct tty vx_tty[]; 2824002Ssam struct vcmds v_cmds[NVIOCX] ; 2924002Ssam 3024002Ssam extern char vxtype[]; 3124002Ssam extern char vxbbno; 3224002Ssam extern char vxbopno[]; 3324002Ssam #ifdef SNA_DEBUG 3424002Ssam extern vbrall(); 3524002Ssam #endif SNA_DEBUG 3624002Ssam extern struct vxcmd *vobtain(); 3724002Ssam 3824002Ssam #ifdef VX_DEBUG 3924002Ssam #include "../vba/vxdebug.h" 4024002Ssam #endif 4124002Ssam 4224002Ssam /* 4324002Ssam * Write a command out to the VIOC 4424002Ssam */ 4524002Ssam vcmd(n, cmdad) 4624002Ssam register int n ; 4724002Ssam register caddr_t cmdad ; /* command address */ 4824002Ssam { 4924002Ssam 5024002Ssam register struct vcmds *cp ; 5124002Ssam register struct vcx *xp; 5224002Ssam int s ; 5324002Ssam 5424002Ssam s = spl8() ; 5524002Ssam cp = &v_cmds[n] ; 5624002Ssam xp = &vcx[n]; 5724002Ssam if (xp->v_state&V_RESETTING && cmdad != NULL) { 5824002Ssam /* 5924002Ssam * When the vioc is resetting, don't process 6024002Ssam * anything other than LIDENT commands. 6124002Ssam */ 6225675Ssam register struct vxcmd *cmdp = (struct vxcmd *) 6325675Ssam ((char *)cmdad - sizeof(cmdp->c_fwd)); 6425675Ssam if (cmdp->cmd != LIDENT) { 6525675Ssam vrelease(xp, cmdp); 6624002Ssam return(0); 6724002Ssam } 6824002Ssam } 6924002Ssam if (cmdad != (caddr_t) 0) { 7024002Ssam cp->cmdbuf[cp->v_fill] = cmdad ; 7124002Ssam if( ++cp->v_fill >= VC_CMDBUFL ) cp->v_fill = 0 ; 7224002Ssam if(cp->v_fill == cp->v_empty) { 7324002Ssam vpanic("vc: CMD Q OVFLO") ; 7424002Ssam vxstreset(n); 7524002Ssam splx(s); 7624002Ssam return(0); 7724002Ssam } 7824002Ssam cp->v_cmdsem++; 7924002Ssam } 8024002Ssam if(cp->v_cmdsem && cp->v_curcnt < vcx[n].v_maxcmd) { 8124002Ssam cp->v_cmdsem--; 8224002Ssam cp->v_curcnt++; 8324002Ssam vinthandl(n, ((V_BSY | CMDquals) << 8) | V_INTR ) ; 8424002Ssam } 8524002Ssam splx(s) ; 8625675Ssam return(1); 8724002Ssam } 8824002Ssam 8924002Ssam /* 9024002Ssam * VIOC acknowledge interrupt. The VIOC has received the new 9124002Ssam * command. If no errors, the new command becomes one of 16 (max) 9224002Ssam * current commands being executed. 9324002Ssam */ 9424002Ssam vackint(n) 9524002Ssam register n ; /* VIOC number */ 9624002Ssam { 9724002Ssam 9824002Ssam register struct vblok *vp ; 9924002Ssam register struct vcmds *cp ; 10024002Ssam register s; 10124002Ssam 10224002Ssam #ifdef VXPERF 10324002Ssam scope_out(5); 10424002Ssam #endif VXPERF 10524002Ssam if (vxtype[n]) { /* Its a BOP */ 10624002Ssam #ifdef SNA_DEBUG 10724002Ssam if (snadebug & SVIOC) 10824002Ssam printf("vack: interrupt from BOP at VIOC%d,1st vector.\n",n); 10924002Ssam vbrall(n); /* Int. from BOP, port 0 */ 11024002Ssam #endif 11124002Ssam return; 11224002Ssam } 11324002Ssam s = spl8(); 11424002Ssam vp = VBAS(n) ; 11524002Ssam cp = &v_cmds[n] ; 11624002Ssam if( vp->v_vcid & V_ERR ) { 11724002Ssam register char *resp; 11824002Ssam register i; 11924002Ssam printf ("INTR ERR type = %x VIOC = %x, v_dcd: %lx\n", 12024002Ssam vp->v_vcid & 07, n, vp->v_dcd & 0xff); 12124002Ssam /* resp = (char *)vp + (vp->v_rspoff & 0x7FFF); */ 12224002Ssam resp = (char *)(&vcx[n])->v_mricmd; 12324002Ssam for(i=0; i<16; i++) 12424002Ssam printf("%x ", resp[i]&0xff); 12524002Ssam vpanic( "\nvcc: vackint") ; 12624002Ssam splx(s); 12724002Ssam vxstreset(n); 12824002Ssam return ; 12924002Ssam } else 13024002Ssam if((vp->v_hdwre&017) == CMDquals) { 13124002Ssam #ifdef VX_DEBUG 13224002Ssam if (vxintr4 & VXERR4) { /* causes VIOC INTR ERR 4 */ 13324002Ssam register struct vxcmd *cp1; 13424002Ssam register struct vxcmd *cp0 = (struct vxcmd *) 13524002Ssam ((long)cp->cmdbuf[cp->v_empty] - 4); 13624002Ssam if ((cp0->cmd == XMITDTA) || (cp0->cmd == XMITIMM)) { 13724002Ssam cp1 = vobtain(&vcx[n]); 13824002Ssam *cp1 = *cp0; 13924002Ssam vxintr4 &= ~VXERR4; 14025675Ssam (void) vcmd(n,&cp1->cmd); 14124002Ssam } 14224002Ssam } 14324002Ssam #endif 14424002Ssam cp->v_curcmd[vp->v_vcid & VCMDLEN-1] = cp->cmdbuf[cp->v_empty] ; 14524002Ssam if( ++cp->v_empty >= VC_CMDBUFL ) cp->v_empty = 0 ; 14624002Ssam } 14724002Ssam if( ++cp->v_itrempt >= VC_IQLEN ) cp->v_itrempt = 0 ; 14824002Ssam vintempt(n) ; 14924002Ssam splx(s); 15025675Ssam (void) vcmd(n, (caddr_t)0); /* queue next cmd, if any */ 15124002Ssam } 15224002Ssam 15324002Ssam /* 15424002Ssam * Command Response interrupt. The Vioc has completed 15524002Ssam * a command. The command may now be returned to 15624002Ssam * the appropriate device driver . 15724002Ssam */ 15824002Ssam vcmdrsp(n) 15924002Ssam register n ; 16024002Ssam { 16124002Ssam 16224002Ssam register struct vblok *vp ; 16324002Ssam register struct vcmds *cp ; 16424002Ssam register caddr_t cmd ; 16524002Ssam register char *resp ; 16624002Ssam register k ; 16724002Ssam register int s ; 16824002Ssam 16924002Ssam #ifdef VXPERF 17024002Ssam scope_out(6); 17124002Ssam #endif VXPERF 17224002Ssam if (vxtype[n]) { /* Its a BOP */ 17324002Ssam printf("vcmdrsp: stray interrupt from BOP at VIOC%d...\n",n); 17424002Ssam return; 17524002Ssam } 17624002Ssam s = spl8(); 17724002Ssam vp = VBAS(n) ; 17824002Ssam cp = &v_cmds[n] ; 17924002Ssam resp = (char *)vp; 18024002Ssam resp += vp->v_rspoff & 0x7FFF; 18124002Ssam 18224002Ssam if( (k=resp[1]) & V_UNBSY ) { 18324002Ssam k &= VCMDLEN-1; 18424002Ssam cmd = cp->v_curcmd[k]; 18524002Ssam cp->v_curcmd[k] = (caddr_t)0; 18624002Ssam cp->v_curcnt--; 18724002Ssam k = *((short *)&resp[4]); /* cmd operation code */ 18824002Ssam if((k & 0xFF00) == LIDENT) { /* want hiport number */ 18924002Ssam for(k=0; k<VRESPLEN; k++) 19024002Ssam cmd[k] = resp[k+4]; 19124002Ssam } 19224002Ssam resp[1] = 0; 19325675Ssam vxxint(n, (struct vxcmd *)cmd) ; 19424002Ssam if ((&vcx[n])->v_state == V_RESETTING) return; 19524002Ssam } 19624002Ssam else { 19724002Ssam vpanic( "vc, cmdresp debug") ; 19824002Ssam splx(s); 19924002Ssam vxstreset(n); 20024002Ssam return; 20124002Ssam } 20224002Ssam 20324002Ssam vinthandl(n, ( (V_BSY | RSPquals) << 8 ) | V_INTR ) ; 20424002Ssam splx(s); 20524002Ssam 20624002Ssam } 20724002Ssam 20824002Ssam 20924002Ssam /* 21024002Ssam * Unsolicited interrupt. 21124002Ssam */ 21224002Ssam vunsol(n) 21324002Ssam register(n) ; 21424002Ssam { 21524002Ssam 21624002Ssam register struct vblok *vp ; 21724002Ssam register s; 21824002Ssam 21924002Ssam #ifdef VXPERF 22024002Ssam scope_out(1); 22124002Ssam #endif VXPERF 22224002Ssam if (vxtype[n]) { /* Its a BOP */ 22324002Ssam printf("vunsol: stray interrupt from BOP at VIOC%d...\n",n); 22424002Ssam return; 22524002Ssam } 22624002Ssam s = spl8(); 22724002Ssam vp = VBAS(n) ; 22824002Ssam if(vp->v_uqual & V_UNBSY) { 22924002Ssam vxrint(n) ; 23024002Ssam vinthandl(n, ( (V_BSY | UNSquals) << 8 ) | V_INTR ) ; 231*25857Ssam #ifdef notdef 232*25857Ssam } else { 23324002Ssam vpanic("vc: UNSOL INT ERR") ; 23424002Ssam splx(s); 23524002Ssam vxstreset(n); 236*25857Ssam #endif 23724002Ssam } 238*25857Ssam splx(s); 23924002Ssam } 24024002Ssam 24124002Ssam /* 24224002Ssam * Enqueue an interrupt 24324002Ssam */ 24424002Ssam vinthandl(n, item) 24524002Ssam register int n ; 24624002Ssam register item ; 24724002Ssam { 24824002Ssam 24924002Ssam register struct vcmds *cp ; 25024002Ssam register int empflag = 0 ; 25124002Ssam 25224002Ssam cp = &v_cmds[n] ; 25324002Ssam if( cp->v_itrfill == cp->v_itrempt ) empflag++ ; 25424002Ssam cp->v_itrqueu[cp->v_itrfill] = item ; 25524002Ssam if( ++cp->v_itrfill >= VC_IQLEN ) cp->v_itrfill = 0 ; 25624002Ssam if(cp->v_itrfill == cp->v_itrempt) { 25724002Ssam vpanic( "vc: INT Q OVFLO" ) ; 25824002Ssam vxstreset(n); 25924002Ssam } 26024002Ssam else if( empflag ) vintempt(n) ; 26124002Ssam } 26224002Ssam 26324002Ssam vintempt(n) 26424002Ssam register int n ; 26524002Ssam { 26624002Ssam register struct vcmds *cp ; 26724002Ssam register struct vblok *vp ; 26824002Ssam register short item ; 26924002Ssam register short *intr ; 27024002Ssam 27124002Ssam vp = VBAS(n) ; 27224002Ssam if(vp->v_vioc & V_BSY) return ; 27324002Ssam cp = &v_cmds[n] ; 27424002Ssam if(cp->v_itrempt == cp->v_itrfill) return ; 27524002Ssam item = cp->v_itrqueu[cp->v_itrempt] ; 27624002Ssam intr = (short *)&vp->v_vioc ; 27724002Ssam switch( (item >> 8) & 03 ) { 27824002Ssam 27924002Ssam case CMDquals: /* command */ 28024002Ssam { 28124002Ssam int phys; 28224002Ssam 28324002Ssam if(cp->v_empty == cp->v_fill || vp->v_vcbsy&V_BSY) 28424002Ssam break; 28524002Ssam (&vcx[n])->v_mricmd = (caddr_t)cp->cmdbuf[cp->v_empty]; 28625675Ssam phys = vtoph((struct proc *)0, (unsigned)cp->cmdbuf[cp->v_empty]) ; /* should be a sys address */ 28724002Ssam vp->v_vcp[0] = ((short *)&phys)[0]; 28824002Ssam vp->v_vcp[1] = ((short *)&phys)[1]; 28924002Ssam vp->v_vcbsy = V_BSY ; 29024002Ssam *intr = item ; 29124002Ssam } 29224002Ssam #ifdef VXPERF 29324002Ssam scope_out(4); 29424002Ssam #endif VXPERF 29524002Ssam break ; 29624002Ssam 29724002Ssam case RSPquals: /* command response */ 29824002Ssam *intr = item ; 29924002Ssam #ifdef VXPERF 30024002Ssam scope_out(7); 30124002Ssam #endif VXPERF 30224002Ssam break ; 30324002Ssam 30424002Ssam case UNSquals: /* unsolicited interrupt */ 30524002Ssam vp->v_uqual = 0 ; 30624002Ssam *intr = item ; 30724002Ssam #ifdef VXPERF 30824002Ssam scope_out(2); 30924002Ssam #endif VXPERF 31024002Ssam break ; 31124002Ssam } 31224002Ssam } 31324002Ssam 31424002Ssam 31524002Ssam /* start a reset on a vioc after error (hopefully) */ 31624002Ssam vxstreset(n) 31724002Ssam register n; 31824002Ssam { 31924002Ssam register struct vcx *xp; 32024002Ssam register struct vblok *vp ; 32124002Ssam register struct vxcmd *cp; 32224002Ssam register int j; 32324002Ssam extern int vxinreset(); 32424002Ssam int s ; 32524002Ssam 32624002Ssam s = spl8() ; 32724002Ssam vp = VBAS(n); 32824002Ssam xp = &vcx[n]; 32924002Ssam 33024002Ssam if (xp->v_state&V_RESETTING) 33124002Ssam /* 33224002Ssam * Avoid infinite recursion. 33324002Ssam */ 33424002Ssam return; 33524002Ssam 33624002Ssam /* 33724002Ssam * Zero out the vioc structures, mark the vioc as being 33824002Ssam * reset, reinitialize the free command list, reset the vioc 33924002Ssam * and start a timer to check on the progress of the reset. 34024002Ssam */ 34125675Ssam bzero((caddr_t)&v_cmds[n], (unsigned)sizeof (struct vcmds)); 34225675Ssam bzero((caddr_t)xp, (unsigned)sizeof (struct vcx)); 34324002Ssam 34424002Ssam /* 34524002Ssam * Setting V_RESETTING prevents others from issuing 34624002Ssam * commands while allowing currently queued commands to 34724002Ssam * be passed to the VIOC. 34824002Ssam */ 34924002Ssam xp->v_state |= V_RESETTING; 35024002Ssam for(j=0; j<NVCXBUFS; j++) /* init all cmd buffers */ 35124002Ssam { 35224002Ssam cp = &xp->vx_lst[j]; /* index a buffer */ 35324002Ssam cp->c_fwd = &xp->vx_lst[j+1]; /* point to next buf */ 35424002Ssam } 35524002Ssam xp->vx_avail = &xp->vx_lst[0]; /* set idx to 1st free buf */ 35624002Ssam cp->c_fwd = (struct vxcmd *)0; /* mark last buf in free list */ 35724002Ssam 35824002Ssam printf("resetting VIOC %x .. ", n); 35924002Ssam 36024002Ssam vp->v_fault = 0 ; 36124002Ssam vp->v_vioc = V_BSY ; 36224002Ssam vp->v_hdwre = V_RESET ; /* reset interrupt */ 36324002Ssam 36424002Ssam timeout(vxinreset, (caddr_t)n, hz*5); 36524002Ssam splx(s); 36624002Ssam return; 36724002Ssam } 36824002Ssam 36924002Ssam /* continue processing a reset on a vioc after an error (hopefully) */ 37024002Ssam vxinreset(vioc) 37124002Ssam caddr_t vioc; 37224002Ssam { 37325675Ssam register int n = (int)vioc; 37424002Ssam register struct vblok *vp ; 37524002Ssam int s = spl8(); 37624002Ssam printf("vxinreset "); 37724002Ssam 37824002Ssam vp = VBAS(n); 37924002Ssam 38024002Ssam /* 38124002Ssam * See if the vioc has reset. 38224002Ssam */ 38324002Ssam if (vp->v_fault != VREADY) { 38424002Ssam printf("failed\n"); 38524002Ssam splx(s); 38624002Ssam return; 38724002Ssam } 38824002Ssam 38924002Ssam /* 39024002Ssam * Send a LIDENT to the vioc and mess with carrier flags 39124002Ssam * on parallel printer ports. 39224002Ssam */ 39325675Ssam vxinit(n, (long)0); 39424002Ssam splx(s); 39524002Ssam } 39624002Ssam 39724002Ssam /* 39824002Ssam * Restore modem control, parameters and restart output. 39924002Ssam * Since the vioc can handle no more then 24 commands at a time 40024002Ssam * and we could generate as many as 48 commands, we must do this in 40124002Ssam * phases, issuing no more then 16 commands at a time. 40224002Ssam */ 40324002Ssam /* finish the reset on the vioc after an error (hopefully) */ 40424002Ssam vxfnreset(n, cp) 40524002Ssam register int n; 40624002Ssam register struct vxcmd *cp; 40724002Ssam { 40824002Ssam register struct vcx *xp; 40924002Ssam register struct vblok *vp ; 41024002Ssam register struct tty *tp; 41124002Ssam register int i; 41225675Ssam #ifdef notdef 41324002Ssam register int on; 41425675Ssam #endif 41524002Ssam extern int vxrestart(); 41624002Ssam int s = spl8(); 41724002Ssam printf("vxfnreset "); 41824002Ssam 41924002Ssam vp = VBAS(n); 42024002Ssam xp = &vcx[n]; 42124002Ssam 42224002Ssam xp->v_loport = cp->par[5]; /* save low port number */ 42324002Ssam xp->v_hiport = cp->par[7];/* VIOC knows high port numbr */ 42424002Ssam vrelease(xp,cp); /* done with this control block */ 42524002Ssam xp->v_nbr = n; /* assign VIOC-X board number */ 42624002Ssam 42724002Ssam xp->v_state &= ~V_RESETTING; 42824002Ssam 42924002Ssam vp->v_vcid = 0; 43024002Ssam 43124002Ssam /* 43224002Ssam * Restore modem information and control. 43324002Ssam */ 43424002Ssam for(i=xp->v_loport; i<=xp->v_hiport; i++) { 43524002Ssam tp = &vx_tty[i+n*16]; 43624002Ssam if (tp->t_state&(TS_ISOPEN|TS_WOPEN)) { 43724002Ssam tp->t_state &= ~TS_CARR_ON; 43824002Ssam vcmodem(tp->t_dev, VMOD_ON); 43924002Ssam if (tp->t_state&TS_CARR_ON) { 44024002Ssam wakeup((caddr_t)&tp->t_canq) ; 44124002Ssam } 44224002Ssam else { 44324002Ssam if(tp->t_state & TS_ISOPEN) { 44424002Ssam ttyflush(tp, FREAD|FWRITE); 44524002Ssam if(tp->t_state&TS_FLUSH) 44624002Ssam wakeup((caddr_t)&tp->t_state) ; 44724002Ssam if((tp->t_flags&NOHANG)==0) { 44824002Ssam gsignal(tp->t_pgrp, SIGHUP) ; 44924002Ssam gsignal(tp->t_pgrp, SIGCONT); 45024002Ssam } 45124002Ssam } 45224002Ssam } 45324002Ssam } 45424002Ssam /* 45524002Ssam * If carrier has changed while we were resetting, 45624002Ssam * take appropriate action. 45724002Ssam */ 45825675Ssam #ifdef notdef 45924002Ssam on = vp->v_dcd & 1<<i; 46024002Ssam if (on && (tp->t_state&TS_CARR_ON) == 0) { 46124002Ssam tp->t_state |= TS_CARR_ON ; 46224002Ssam wakeup((caddr_t)&tp->t_canq) ; 46324002Ssam } else if (!on && tp->t_state&TS_CARR_ON) { 46424002Ssam tp->t_state &= ~TS_CARR_ON ; 46524002Ssam if(tp->t_state & TS_ISOPEN) { 46624002Ssam ttyflush(tp, FREAD|FWRITE); 46724002Ssam if(tp->t_state&TS_FLUSH) 46824002Ssam wakeup((caddr_t)&tp->t_state) ; 46924002Ssam if((tp->t_flags&NOHANG)==0) { 47024002Ssam gsignal(tp->t_pgrp, SIGHUP) ; 47124002Ssam gsignal(tp->t_pgrp, SIGCONT); 47224002Ssam } 47324002Ssam } 47424002Ssam } 47525675Ssam #endif 47624002Ssam } 47724002Ssam 47824002Ssam xp->v_state |= V_RESETTING; 47924002Ssam 48024002Ssam timeout(vxrestart, (caddr_t)n, hz); 48124002Ssam splx(s); 48224002Ssam } 48324002Ssam 48424002Ssam /* 48524002Ssam * Restore a particular aspect of the VIOC. 48624002Ssam */ 48724002Ssam vxrestart(vioc) 48824002Ssam caddr_t vioc; 48924002Ssam { 49024002Ssam register struct tty *tp, *tp0; 49124002Ssam register struct vcx *xp; 49224002Ssam register int i, cnt; 49324002Ssam register int n = (int)vioc; 49424002Ssam int s = spl8(); 49524002Ssam 49624002Ssam cnt = n>>8; 49724002Ssam printf("vxrestart %d ",cnt); 49824002Ssam n &= 0xff; 49924002Ssam 50024002Ssam tp0 = &vx_tty[n*16]; 50124002Ssam xp = &vcx[n]; 50224002Ssam 50324002Ssam xp->v_state &= ~V_RESETTING; 50424002Ssam 50524002Ssam for(i=xp->v_loport; i<=xp->v_hiport; i++) { 50624002Ssam tp = tp0 + i; 50724002Ssam if (cnt != 0) { 50824002Ssam tp->t_state &= ~(TS_BUSY|TS_TIMEOUT); 50924002Ssam if(tp->t_state&(TS_ISOPEN|TS_WOPEN)) /* restart pending output */ 51024002Ssam vxstart(tp); 51124002Ssam } else { 51224002Ssam if (tp->t_state&(TS_WOPEN|TS_ISOPEN)) 51324002Ssam vxcparam(tp->t_dev, 0); 51424002Ssam } 51524002Ssam } 51624002Ssam 51724002Ssam if (cnt == 0) { 51824002Ssam xp->v_state |= V_RESETTING; 51924002Ssam timeout(vxrestart, (caddr_t)(n + 1*256), hz); 52024002Ssam } else 52124002Ssam printf("done\n"); 52224002Ssam splx(s); 52324002Ssam } 52424002Ssam 52524002Ssam vxreset(dev) 52624002Ssam dev_t dev; 52724002Ssam { 52824002Ssam vxstreset(minor(dev)>>4); /* completes asynchronously */ 52924002Ssam } 53024002Ssam 53124002Ssam vxfreset(n) 53224002Ssam register int n; 53324002Ssam { 53424002Ssam 53524002Ssam if (n < 0 || n > NVX || VBAS(n) == NULL) 53624002Ssam return(ENODEV); 53724002Ssam vcx[n].v_state &= ~V_RESETTING; 53824002Ssam vxstreset(n); 53924002Ssam return(0); /* completes asynchronously */ 54024002Ssam } 54124002Ssam #endif 54224002Ssam 543