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