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