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