|
|
1.1 root 1: /*
2: * Copyright (c) 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Computer Consoles Inc.
7: *
8: * Redistribution and use in source and binary forms are permitted
9: * provided that the above copyright notice and this paragraph are
10: * duplicated in all such forms and that any documentation,
11: * advertising materials, and other materials related to such
12: * distribution and use acknowledge that the software was developed
13: * by the University of California, Berkeley. The name of the
14: * University may not be used to endorse or promote products derived
15: * from this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)cy.c 7.2 (Berkeley) 6/29/88
21: */
22:
23: #include "yc.h"
24: #if NCY > 0
25: /*
26: * Cipher Tapemaster driver.
27: */
28: #define CYDEBUG
29: #ifdef CYDEBUG
30: int cydebug = 0;
31: #define dlog(params) if (cydebug) log params
32: #else
33: #define dlog(params) /* */
34: #endif
35:
36: #include "param.h"
37: #include "systm.h"
38: #include "vm.h"
39: #include "buf.h"
40: #include "file.h"
41: #include "dir.h"
42: #include "user.h"
43: #include "proc.h"
44: #include "signal.h"
45: #include "uio.h"
46: #include "ioctl.h"
47: #include "mtio.h"
48: #include "errno.h"
49: #include "cmap.h"
50: #include "kernel.h"
51: #include "syslog.h"
52: #include "tty.h"
53:
54: #include "../tahoe/cpu.h"
55: #include "../tahoe/mtpr.h"
56: #include "../tahoe/pte.h"
57:
58: #include "../tahoevba/vbavar.h"
59: #define CYERROR
60: #include "../tahoevba/cyreg.h"
61:
62: /*
63: * There is a ccybuf per tape controller.
64: * It is used as the token to pass to the internal routines
65: * to execute tape ioctls, and also acts as a lock on the slaves
66: * on the controller, since there is only one per controller.
67: * In particular, when the tape is rewinding on close we release
68: * the user process but any further attempts to use the tape drive
69: * before the rewind completes will hang waiting for ccybuf.
70: */
71: struct buf ccybuf[NCY];
72:
73: int cyprobe(), cyslave(), cyattach();
74: struct buf ycutab[NYC];
75: short yctocy[NYC];
76: struct vba_ctlr *cyminfo[NCY];
77: struct vba_device *ycdinfo[NYC];
78: long cystd[] = { 0 };
79: struct vba_driver cydriver =
80: { cyprobe, cyslave, cyattach, 0, cystd, "yc", ycdinfo, "cy", cyminfo };
81:
82: /* bits in minor device */
83: #define YCUNIT(dev) (minor(dev)&03)
84: #define CYUNIT(dev) (yctocy[YCUNIT(dev)])
85: #define T_NOREWIND 0x04
86: #define T_1600BPI 0x00 /* pseudo */
87: #define T_3200BPI 0x08 /* unused */
88:
89: #define INF 1000000L /* close to infinity */
90:
91: /*
92: * Software state and shared command areas per controller.
93: *
94: * The i/o intermediate buffer must be allocated in startup()
95: * so its address will fit in 20-bits (YECH!!!!!!!!!!!!!!).
96: */
97: struct cy_softc {
98: int cy_bs; /* controller's buffer size */
99: struct cyscp *cy_scp; /* system configuration block address */
100: struct cyccb cy_ccb; /* channel control block */
101: struct cyscb cy_scb; /* system configuration block */
102: struct cytpb cy_tpb; /* tape parameter block */
103: struct cytpb cy_nop; /* nop parameter block for cyintr */
104: struct vb_buf cy_rbuf; /* vba resources */
105: } cy_softc[NCY];
106:
107: /*
108: * Software state per tape transport.
109: */
110: struct yc_softc {
111: char yc_openf; /* lock against multiple opens */
112: char yc_lastiow; /* last operation was a write */
113: short yc_tact; /* timeout is active */
114: long yc_timo; /* time until timeout expires */
115: u_short yc_control; /* copy of last tpcb.tpcontrol */
116: u_short yc_status; /* copy of last tpcb.tpstatus */
117: u_short yc_resid; /* copy of last bc */
118: u_short yc_dens; /* prototype control word with density info */
119: struct tty *yc_ttyp; /* user's tty for errors */
120: daddr_t yc_blkno; /* block number, for block device tape */
121: daddr_t yc_nxrec; /* position of end of tape, if known */
122: int yc_blksize; /* current tape blocksize estimate */
123: int yc_blks; /* number of I/O operations since open */
124: int yc_softerrs; /* number of soft I/O errors since open */
125: } yc_softc[NYC];
126:
127: /*
128: * States for vm->um_tab.b_active, the per controller state flag.
129: * This is used to sequence control in the driver.
130: */
131: #define SSEEK 1 /* seeking */
132: #define SIO 2 /* doing seq i/o */
133: #define SCOM 3 /* sending control command */
134: #define SREW 4 /* sending a rewind */
135: #define SERASE 5 /* erase inter-record gap */
136: #define SERASED 6 /* erased inter-record gap */
137:
138: /* there's no way to figure these out dynamically? -- yech */
139: struct cyscp *cyscp[] =
140: { (struct cyscp *)0xc0000c06, (struct cyscp *)0xc0000c16 };
141: #define NCYSCP (sizeof (cyscp) / sizeof (cyscp[0]))
142:
143: cyprobe(reg, vm)
144: caddr_t reg;
145: struct vba_ctlr *vm;
146: {
147: register br, cvec; /* must be r12, r11 */
148: register struct cy_softc *cy;
149: int ctlr = vm->um_ctlr;
150:
151: #ifdef lint
152: br = 0; cvec = br; br = cvec;
153: cyintr(0);
154: #endif
155: if (badcyaddr(reg+1))
156: return (0);
157: if (ctlr > NCYSCP || cyscp[ctlr] == 0) /* XXX */
158: return (0);
159: cy = &cy_softc[ctlr];
160: cy->cy_scp = cyscp[ctlr]; /* XXX */
161: /*
162: * Tapemaster controller must have interrupt handler
163: * disable interrupt, so we'll just kludge things
164: * (stupid multibus non-vectored interrupt crud).
165: */
166: if (cyinit(ctlr, reg)) {
167: uncache(&cy->cy_tpb.tpcount);
168: cy->cy_bs = htoms(cy->cy_tpb.tpcount);
169: /*
170: * Setup nop parameter block for clearing interrupts.
171: */
172: cy->cy_nop.tpcmd = CY_NOP;
173: cy->cy_nop.tpcontrol = 0;
174: /*
175: * Allocate page tables.
176: */
177: if (cybuf == 0) {
178: printf("no cy buffer!!!\n");
179: return (0);
180: }
181: cy->cy_rbuf.vb_rawbuf = cybuf + ctlr * CYMAXIO;
182: if (vbainit(&cy->cy_rbuf, CYMAXIO, VB_20BIT) == 0) {
183: printf("cy%d: vbainit failed\n", ctlr);
184: return (0);
185: }
186:
187: br = 0x13, cvec = 0x80; /* XXX */
188: return (sizeof (struct cyccb));
189: } else
190: return (0);
191: }
192:
193: /*
194: * Check to see if a drive is attached to a controller.
195: * Since we can only tell that a drive is there if a tape is loaded and
196: * the drive is placed online, we always indicate the slave is present.
197: */
198: cyslave(vi, addr)
199: struct vba_device *vi;
200: caddr_t addr;
201: {
202:
203: #ifdef lint
204: vi = vi; addr = addr;
205: #endif
206: return (1);
207: }
208:
209: cyattach(vi)
210: struct vba_device *vi;
211: {
212: register struct cy_softc *cy;
213: int ctlr = vi->ui_mi->um_ctlr;
214:
215: yctocy[vi->ui_unit] = ctlr;
216: cy = &cy_softc[ctlr];
217: if (vi->ui_slave == 0 && cy->cy_bs)
218: printf("; %dkb buffer", cy->cy_bs/1024);
219: }
220:
221: /*
222: * Initialize the controller after a controller reset or
223: * during autoconfigure. All of the system control blocks
224: * are initialized and the controller is asked to configure
225: * itself for later use.
226: */
227: cyinit(ctlr, addr)
228: int ctlr;
229: register caddr_t addr;
230: {
231: register struct cy_softc *cy = &cy_softc[ctlr];
232: register int *pte;
233:
234: /*
235: * Initialize the system configuration pointer.
236: */
237: /* make kernel writable */
238: pte = (int *)&Sysmap[btop((int)cy->cy_scp &~ KERNBASE)];
239: *pte &= ~PG_PROT; *pte |= PG_KW;
240: mtpr(TBIS, cy->cy_scp);
241: /* load the correct values in the scp */
242: cy->cy_scp->csp_buswidth = CSP_16BITS;
243: cyldmba(cy->cy_scp->csp_scb, (caddr_t)&cy->cy_scb);
244: /* put it back to read-only */
245: *pte &= ~PG_PROT; *pte |= PG_KR;
246: mtpr(TBIS, cy->cy_scp);
247:
248: /*
249: * Init system configuration block.
250: */
251: cy->cy_scb.csb_fixed = CSB_FIXED;
252: /* set pointer to the channel control block */
253: cyldmba(cy->cy_scb.csb_ccb, (caddr_t)&cy->cy_ccb);
254:
255: /*
256: * Initialize the chanel control block.
257: */
258: cy->cy_ccb.cbcw = CBCW_CLRINT;
259: cy->cy_ccb.cbgate = GATE_OPEN;
260: /* set pointer to the tape parameter block */
261: cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb);
262:
263: /*
264: * Issue a nop cmd and get the internal buffer size for buffered i/o.
265: */
266: cy->cy_tpb.tpcmd = CY_NOP;
267: cy->cy_tpb.tpcontrol = CYCW_16BITS;
268: cy->cy_ccb.cbgate = GATE_CLOSED;
269: CY_GO(addr);
270: if (cywait(&cy->cy_ccb) || (cy->cy_tpb.tpstatus&CYS_ERR)) {
271: uncache(&cy->cy_tpb.tpstatus);
272: printf("cy%d: timeout or err during init, status=%b\n", ctlr,
273: cy->cy_tpb.tpstatus, CYS_BITS);
274: return (0);
275: }
276: cy->cy_tpb.tpcmd = CY_CONFIG;
277: cy->cy_tpb.tpcontrol = CYCW_16BITS;
278: cy->cy_ccb.cbgate = GATE_CLOSED;
279: CY_GO(addr);
280: if (cywait(&cy->cy_ccb) || (cy->cy_tpb.tpstatus&CYS_ERR)) {
281: uncache(&cy->cy_tpb.tpstatus);
282: printf("cy%d: configuration failure, status=%b\n", ctlr,
283: cy->cy_tpb.tpstatus, CYS_BITS);
284: return (0);
285: }
286: return (1);
287: }
288:
289: int cytimer();
290: /*
291: * Open the device. Tapes are unique open
292: * devices, so we refuse if it is already open.
293: * We also check that a tape is available, and
294: * don't block waiting here; if you want to wait
295: * for a tape you should timeout in user code.
296: */
297: cyopen(dev, flag)
298: dev_t dev;
299: register int flag;
300: {
301: register int ycunit;
302: register struct vba_device *vi;
303: register struct yc_softc *yc;
304:
305: ycunit = YCUNIT(dev);
306: if (ycunit >= NYC || (vi = ycdinfo[ycunit]) == 0 || vi->ui_alive == 0)
307: return (ENXIO);
308: if ((yc = &yc_softc[ycunit])->yc_openf)
309: return (EBUSY);
310: yc->yc_openf = 1;
311: #define PACKUNIT(vi) \
312: (((vi->ui_slave&1)<<11)|((vi->ui_slave&2)<<9)|((vi->ui_slave&4)>>2))
313: /* no way to select density */
314: yc->yc_dens = PACKUNIT(vi)|CYCW_IE|CYCW_16BITS;
315: if (yc->yc_tact == 0) {
316: yc->yc_timo = INF;
317: yc->yc_tact = 1;
318: timeout(cytimer, (caddr_t)dev, 5*hz);
319: }
320: cycommand(dev, CY_SENSE, 1);
321: if ((yc->yc_status&CYS_OL) == 0) { /* not on-line */
322: uprintf("cy%d: not online\n", ycunit);
323: yc->yc_openf = 0;
324: return (EIO);
325: }
326: if ((flag&FWRITE) && (yc->yc_status&CYS_WP)) {
327: uprintf("cy%d: no write ring\n", ycunit);
328: yc->yc_openf = 0;
329: return (EIO);
330: }
331: yc->yc_blkno = (daddr_t)0;
332: yc->yc_nxrec = INF;
333: yc->yc_lastiow = 0;
334: yc->yc_blksize = CYMAXIO; /* guess > 0 */
335: yc->yc_blks = 0;
336: yc->yc_softerrs = 0;
337: yc->yc_ttyp = u.u_ttyp;
338: return (0);
339: }
340:
341: /*
342: * Close tape device.
343: *
344: * If tape was open for writing or last operation was a write,
345: * then write two EOF's and backspace over the last one.
346: * Unless this is a non-rewinding special file, rewind the tape.
347: * Make the tape available to others.
348: */
349: cyclose(dev, flag)
350: dev_t dev;
351: int flag;
352: {
353: struct yc_softc *yc = &yc_softc[YCUNIT(dev)];
354:
355: if (flag == FWRITE || (flag&FWRITE) && yc->yc_lastiow) {
356: cycommand(dev, CY_WEOF, 1); /* can't use count with WEOF */
357: cycommand(dev, CY_WEOF, 1);
358: cycommand(dev, CY_SREV, 1);
359: }
360: if ((minor(dev)&T_NOREWIND) == 0)
361: /*
362: * 0 count means don't hang waiting for rewind complete
363: * rather ccybuf stays busy until the operation completes
364: * preventing further opens from completing by preventing
365: * a CY_SENSE from completing.
366: */
367: cycommand(dev, CY_REW, 0);
368: if (yc->yc_blks > 10 && yc->yc_softerrs > yc->yc_blks / 10)
369: log(LOG_INFO, "yc%d: %d soft errors in %d blocks\n",
370: YCUNIT(dev), yc->yc_softerrs, yc->yc_blks);
371: dlog((LOG_INFO, "%d soft errors in %d blocks\n",
372: yc->yc_softerrs, yc->yc_blks));
373: yc->yc_openf = 0;
374: return (0);
375: }
376:
377: /*
378: * Execute a command on the tape drive a specified number of times.
379: */
380: cycommand(dev, com, count)
381: dev_t dev;
382: int com, count;
383: {
384: register struct buf *bp;
385: int s;
386:
387: bp = &ccybuf[CYUNIT(dev)];
388: s = spl3();
389: dlog((LOG_INFO, "cycommand(%o, %x, %d), b_flags %x\n",
390: dev, com, count, bp->b_flags));
391: while (bp->b_flags&B_BUSY) {
392: /*
393: * This special check is because B_BUSY never
394: * gets cleared in the non-waiting rewind case.
395: */
396: if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
397: break;
398: bp->b_flags |= B_WANTED;
399: sleep((caddr_t)bp, PRIBIO);
400: }
401: bp->b_flags = B_BUSY|B_READ;
402: splx(s);
403: bp->b_dev = dev;
404: bp->b_repcnt = count;
405: bp->b_command = com;
406: bp->b_blkno = 0;
407: cystrategy(bp);
408: /*
409: * In case of rewind from close; don't wait.
410: * This is the only case where count can be 0.
411: */
412: if (count == 0)
413: return;
414: biowait(bp);
415: if (bp->b_flags&B_WANTED)
416: wakeup((caddr_t)bp);
417: bp->b_flags &= B_ERROR;
418: }
419:
420: cystrategy(bp)
421: register struct buf *bp;
422: {
423: int ycunit = YCUNIT(bp->b_dev);
424: register struct vba_ctlr *vm;
425: register struct buf *dp;
426: int s;
427:
428: /*
429: * Put transfer at end of unit queue.
430: */
431: dlog((LOG_INFO, "cystrategy(%o, %x)\n", bp->b_dev, bp->b_command));
432: dp = &ycutab[ycunit];
433: bp->av_forw = NULL;
434: vm = ycdinfo[ycunit]->ui_mi;
435: /* BEGIN GROT */
436: if (bp->b_flags & B_RAW) {
437: if (bp->b_bcount >= CYMAXIO) {
438: uprintf("cy%d: i/o size too large\n", vm->um_ctlr);
439: bp->b_error = EINVAL;
440: bp->b_resid = bp->b_bcount;
441: bp->b_flags |= B_ERROR;
442: biodone(bp);
443: return;
444: }
445: }
446: /* END GROT */
447: s = spl3();
448: if (dp->b_actf == NULL) {
449: dp->b_actf = bp;
450: /*
451: * Transport not already active...
452: * put at end of controller queue.
453: */
454: dp->b_forw = NULL;
455: if (vm->um_tab.b_actf == NULL)
456: vm->um_tab.b_actf = dp;
457: else
458: vm->um_tab.b_actl->b_forw = dp;
459: } else
460: dp->b_actl->av_forw = bp;
461: dp->b_actl = bp;
462: /*
463: * If the controller is not busy, get it going.
464: */
465: if (vm->um_tab.b_active == 0)
466: cystart(vm);
467: splx(s);
468: }
469:
470: /*
471: * Start activity on a cy controller.
472: */
473: cystart(vm)
474: register struct vba_ctlr *vm;
475: {
476: register struct buf *bp, *dp;
477: register struct yc_softc *yc;
478: register struct cy_softc *cy;
479: int ycunit;
480: daddr_t blkno;
481:
482: dlog((LOG_INFO, "cystart()\n"));
483: /*
484: * Look for an idle transport on the controller.
485: */
486: loop:
487: if ((dp = vm->um_tab.b_actf) == NULL)
488: return;
489: if ((bp = dp->b_actf) == NULL) {
490: vm->um_tab.b_actf = dp->b_forw;
491: goto loop;
492: }
493: ycunit = YCUNIT(bp->b_dev);
494: yc = &yc_softc[ycunit];
495: cy = &cy_softc[CYUNIT(bp->b_dev)];
496: /*
497: * Default is that last command was NOT a write command;
498: * if we do a write command we will notice this in cyintr().
499: */
500: yc->yc_lastiow = 0;
501: if (yc->yc_openf < 0 ||
502: (bp->b_command != CY_SENSE && (cy->cy_tpb.tpstatus&CYS_OL) == 0)) {
503: /*
504: * Have had a hard error on a non-raw tape
505: * or the tape unit is now unavailable (e.g.
506: * taken off line).
507: */
508: dlog((LOG_INFO, "openf %d command %x status %b\n",
509: yc->yc_openf, bp->b_command, cy->cy_tpb.tpstatus, CYS_BITS));
510: bp->b_flags |= B_ERROR;
511: goto next;
512: }
513: if (bp == &ccybuf[CYUNIT(bp->b_dev)]) {
514: /*
515: * Execute control operation with the specified count.
516: *
517: * Set next state; give 5 minutes to complete
518: * rewind or file mark search, or 10 seconds per
519: * iteration (minimum 60 seconds and max 5 minutes)
520: * to complete other ops.
521: */
522: if (bp->b_command == CY_REW) {
523: vm->um_tab.b_active = SREW;
524: yc->yc_timo = 5*60;
525: } else if (bp->b_command == CY_FSF ||
526: bp->b_command == CY_BSF) {
527: vm->um_tab.b_active = SCOM;
528: yc->yc_timo = 5*60;
529: } else {
530: vm->um_tab.b_active = SCOM;
531: yc->yc_timo = imin(imax(10*(int)bp->b_repcnt,60),5*60);
532: }
533: cy->cy_tpb.tprec = htoms(bp->b_repcnt);
534: dlog((LOG_INFO, "bpcmd "));
535: goto dobpcmd;
536: }
537: /*
538: * For raw I/O, save the current block
539: * number in case we have to retry.
540: */
541: if (bp->b_flags & B_RAW) {
542: if (vm->um_tab.b_errcnt == 0) {
543: yc->yc_blkno = bp->b_blkno;
544: yc->yc_nxrec = yc->yc_blkno + 1;
545: }
546: } else {
547: /*
548: * Handle boundary cases for operation
549: * on non-raw tapes.
550: */
551: if (bp->b_blkno > yc->yc_nxrec) {
552: /*
553: * Can't read past known end-of-file.
554: */
555: bp->b_flags |= B_ERROR;
556: bp->b_error = ENXIO;
557: goto next;
558: }
559: if (bp->b_blkno == yc->yc_nxrec && bp->b_flags&B_READ) {
560: /*
561: * Reading at end of file returns 0 bytes.
562: */
563: bp->b_resid = bp->b_bcount;
564: clrbuf(bp);
565: goto next;
566: }
567: if ((bp->b_flags&B_READ) == 0)
568: /*
569: * Writing sets EOF.
570: */
571: yc->yc_nxrec = bp->b_blkno + 1;
572: }
573: if ((blkno = yc->yc_blkno) == bp->b_blkno) {
574: caddr_t addr;
575: int cmd;
576:
577: /*
578: * Choose the appropriate i/o command based on the
579: * transfer size, the estimated block size,
580: * and the controller's internal buffer size.
581: * If the request length is longer than the tape
582: * block length, a buffered read will fail,
583: * thus, we request at most the size that we expect.
584: * We then check for larger records when the read completes.
585: * If we're retrying a read on a raw device because
586: * the original try was a buffer request which failed
587: * due to a record length error, then we force the use
588: * of the raw controller read (YECH!!!!).
589: */
590: if (bp->b_flags&B_READ) {
591: if (yc->yc_blksize <= cy->cy_bs &&
592: vm->um_tab.b_errcnt == 0)
593: cmd = CY_BRCOM;
594: else
595: cmd = CY_RCOM;
596: } else {
597: /*
598: * On write error retries erase the
599: * inter-record gap before rewriting.
600: */
601: if (vm->um_tab.b_errcnt &&
602: vm->um_tab.b_active != SERASED) {
603: vm->um_tab.b_active = SERASE;
604: bp->b_command = CY_ERASE;
605: yc->yc_timo = 60;
606: goto dobpcmd;
607: }
608: cmd = (bp->b_bcount > cy->cy_bs) ? CY_WCOM : CY_BWCOM;
609: }
610: vm->um_tab.b_active = SIO;
611: addr = (caddr_t)vbasetup(bp, &cy->cy_rbuf, 1);
612: cy->cy_tpb.tpcmd = cmd;
613: cy->cy_tpb.tpcontrol = yc->yc_dens;
614: if (cmd == CY_RCOM || cmd == CY_WCOM)
615: cy->cy_tpb.tpcontrol |= CYCW_LOCK;
616: cy->cy_tpb.tpstatus = 0;
617: cy->cy_tpb.tpcount = 0;
618: cyldmba(cy->cy_tpb.tpdata, (caddr_t)addr);
619: cy->cy_tpb.tprec = 0;
620: if (cmd == CY_BRCOM)
621: cy->cy_tpb.tpsize = htoms(imin(yc->yc_blksize,
622: (int)bp->b_bcount));
623: else
624: cy->cy_tpb.tpsize = htoms(bp->b_bcount);
625: cyldmba(cy->cy_tpb.tplink, (caddr_t)0);
626: do
627: uncache(&cy->cy_ccb.cbgate);
628: while (cy->cy_ccb.cbgate == GATE_CLOSED);
629: cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb);
630: cy->cy_ccb.cbcw = CBCW_IE;
631: cy->cy_ccb.cbgate = GATE_CLOSED;
632: dlog((LOG_INFO, "CY_GO(%x) cmd %x control %x size %d\n",
633: vm->um_addr, cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol,
634: htoms(cy->cy_tpb.tpsize)));
635: CY_GO(vm->um_addr);
636: return;
637: }
638: /*
639: * Tape positioned incorrectly; set to seek forwards
640: * or backwards to the correct spot. This happens
641: * for raw tapes only on error retries.
642: */
643: vm->um_tab.b_active = SSEEK;
644: if (blkno < bp->b_blkno) {
645: bp->b_command = CY_SFORW;
646: cy->cy_tpb.tprec = htoms(bp->b_blkno - blkno);
647: } else {
648: bp->b_command = CY_SREV;
649: cy->cy_tpb.tprec = htoms(blkno - bp->b_blkno);
650: }
651: yc->yc_timo = imin(imax((int)(10 * htoms(cy->cy_tpb.tprec)), 60), 5*60);
652: dobpcmd:
653: /*
654: * Do the command in bp. Reverse direction commands
655: * are indicated by having CYCW_REV or'd into their
656: * value. For these we must set the appropriate bit
657: * in the control field.
658: */
659: if (bp->b_command&CYCW_REV) {
660: cy->cy_tpb.tpcmd = bp->b_command &~ CYCW_REV;
661: cy->cy_tpb.tpcontrol = yc->yc_dens | CYCW_REV;
662: dlog((LOG_INFO, "cmd %x control %x\n", cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol));
663: } else {
664: cy->cy_tpb.tpcmd = bp->b_command;
665: cy->cy_tpb.tpcontrol = yc->yc_dens;
666: dlog((LOG_INFO, "cmd %x control %x\n", cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol));
667: }
668: cy->cy_tpb.tpstatus = 0;
669: cy->cy_tpb.tpcount = 0;
670: cyldmba(cy->cy_tpb.tplink, (caddr_t)0);
671: do
672: uncache(&cy->cy_ccb.cbgate);
673: while (cy->cy_ccb.cbgate == GATE_CLOSED);
674: cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb);
675: cy->cy_ccb.cbcw = CBCW_IE;
676: cy->cy_ccb.cbgate = GATE_CLOSED;
677: dlog((LOG_INFO, "CY_GO(%x) cmd %x control %x rec %d\n",
678: vm->um_addr, cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol,
679: htoms(cy->cy_tpb.tprec)));
680: CY_GO(vm->um_addr);
681: return;
682: next:
683: /*
684: * Done with this operation due to error or the
685: * fact that it doesn't do anything.
686: * Dequeue the transfer and continue
687: * processing this slave.
688: */
689: vm->um_tab.b_errcnt = 0;
690: dp->b_actf = bp->av_forw;
691: biodone(bp);
692: goto loop;
693: }
694:
695: /*
696: * Cy interrupt routine.
697: */
698: cyintr(cyunit)
699: int cyunit;
700: {
701: struct buf *dp;
702: register struct buf *bp;
703: register struct vba_ctlr *vm = cyminfo[cyunit];
704: register struct cy_softc *cy;
705: register struct yc_softc *yc;
706: int err;
707: register state;
708:
709: dlog((LOG_INFO, "cyintr(%d)\n", cyunit));
710: /*
711: * First, turn off the interrupt from the controller
712: * (device uses Multibus non-vectored interrupts...yech).
713: */
714: cy = &cy_softc[vm->um_ctlr];
715: cy->cy_ccb.cbcw = CBCW_CLRINT;
716: cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_nop);
717: cy->cy_ccb.cbgate = GATE_CLOSED;
718: CY_GO(vm->um_addr);
719: if ((dp = vm->um_tab.b_actf) == NULL) {
720: dlog((LOG_ERR, "cy%d: stray interrupt", vm->um_ctlr));
721: return;
722: }
723: bp = dp->b_actf;
724: cy = &cy_softc[cyunit];
725: cyuncachetpb(cy);
726: yc = &yc_softc[YCUNIT(bp->b_dev)];
727: /*
728: * If last command was a rewind and tape is
729: * still moving, wait for the operation to complete.
730: */
731: if (vm->um_tab.b_active == SREW) {
732: vm->um_tab.b_active = SCOM;
733: if ((cy->cy_tpb.tpstatus&CYS_RDY) == 0) {
734: yc->yc_timo = 5*60; /* 5 minutes */
735: return;
736: }
737: }
738: /*
739: * An operation completed...record status.
740: */
741: yc->yc_timo = INF;
742: yc->yc_control = cy->cy_tpb.tpcontrol;
743: yc->yc_status = cy->cy_tpb.tpstatus;
744: yc->yc_resid = bp->b_bcount - htoms(cy->cy_tpb.tpcount);
745: dlog((LOG_INFO, "cmd %x control %b status %b resid %d\n",
746: cy->cy_tpb.tpcmd, yc->yc_control, CYCW_BITS,
747: yc->yc_status, CYS_BITS, yc->yc_resid));
748: if ((bp->b_flags&B_READ) == 0)
749: yc->yc_lastiow = 1;
750: state = vm->um_tab.b_active;
751: vm->um_tab.b_active = 0;
752: /*
753: * Check for errors.
754: */
755: if (cy->cy_tpb.tpstatus&CYS_ERR) {
756: err = cy->cy_tpb.tpstatus&CYS_ERR;
757: dlog((LOG_INFO, "error %d\n", err));
758: /*
759: * If we hit the end of tape file, update our position.
760: */
761: if (err == CYER_FM) {
762: yc->yc_status |= CYS_FM;
763: state = SCOM; /* force completion */
764: cyseteof(bp); /* set blkno and nxrec */
765: goto opdone;
766: }
767: /*
768: * Fix up errors which occur due to backspacing over
769: * the beginning of the tape.
770: */
771: if (err == CYER_BOT && cy->cy_tpb.tpcontrol&CYCW_REV) {
772: yc->yc_status |= CYS_BOT;
773: goto ignoreerr;
774: }
775: /*
776: * If we were reading raw tape and the only error was that the
777: * record was too long, then we don't consider this an error.
778: */
779: if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) &&
780: err == CYER_STROBE) {
781: /*
782: * Retry reads with the command changed to
783: * a raw read if necessary. Setting b_errcnt
784: * here causes cystart (above) to force a CY_RCOM.
785: */
786: if (cy->cy_tpb.tpcmd == CY_BRCOM &&
787: vm->um_tab.b_errcnt++ == 0) {
788: yc->yc_blkno++;
789: goto opcont;
790: } else
791: goto ignoreerr;
792: }
793: /*
794: * If error is not hard, and this was an i/o operation
795: * retry up to 8 times.
796: */
797: if (state == SIO && (CYMASK(err) &
798: ((bp->b_flags&B_READ) ? CYER_RSOFT : CYER_WSOFT))) {
799: if (++vm->um_tab.b_errcnt < 7) {
800: yc->yc_blkno++;
801: goto opcont;
802: }
803: } else
804: /*
805: * Hard or non-i/o errors on non-raw tape
806: * cause it to close.
807: */
808: if ((bp->b_flags&B_RAW) == 0 &&
809: yc->yc_openf > 0)
810: yc->yc_openf = -1;
811: /*
812: * Couldn't recover from error.
813: */
814: tprintf(yc->yc_ttyp,
815: "yc%d: hard error bn%d status=%b, %s\n", YCUNIT(bp->b_dev),
816: bp->b_blkno, yc->yc_status, CYS_BITS,
817: (err < NCYERROR) ? cyerror[err] : "");
818: bp->b_flags |= B_ERROR;
819: goto opdone;
820: } else if (cy->cy_tpb.tpcmd == CY_BRCOM) {
821: int reclen = htoms(cy->cy_tpb.tprec);
822:
823: /*
824: * If we did a buffered read, check whether the read
825: * was long enough. If we asked the controller for less
826: * than the user asked for because the previous record
827: * was shorter, update our notion of record size
828: * and retry. If the record is longer than the buffer,
829: * bump the errcnt so the retry will use direct read.
830: */
831: if (reclen > yc->yc_blksize && bp->b_bcount > yc->yc_blksize) {
832: yc->yc_blksize = reclen;
833: if (reclen > cy->cy_bs)
834: vm->um_tab.b_errcnt++;
835: yc->yc_blkno++;
836: goto opcont;
837: }
838: }
839: /*
840: * Advance tape control FSM.
841: */
842: ignoreerr:
843: /*
844: * If we hit a tape mark update our position.
845: */
846: if (yc->yc_status&CYS_FM && bp->b_flags&B_READ) {
847: cyseteof(bp);
848: goto opdone;
849: }
850: switch (state) {
851:
852: case SIO:
853: /*
854: * Read/write increments tape block number.
855: */
856: yc->yc_blkno++;
857: yc->yc_blks++;
858: if (vm->um_tab.b_errcnt || yc->yc_status & CYS_CR)
859: yc->yc_softerrs++;
860: yc->yc_blksize = htoms(cy->cy_tpb.tpcount);
861: dlog((LOG_ERR, "blocksize %d", yc->yc_blksize));
862: goto opdone;
863:
864: case SCOM:
865: /*
866: * For forward/backward space record update current position.
867: */
868: if (bp == &ccybuf[CYUNIT(bp->b_dev)])
869: switch ((int)bp->b_command) {
870:
871: case CY_SFORW:
872: yc->yc_blkno -= bp->b_repcnt;
873: break;
874:
875: case CY_SREV:
876: yc->yc_blkno += bp->b_repcnt;
877: break;
878: }
879: goto opdone;
880:
881: case SSEEK:
882: yc->yc_blkno = bp->b_blkno;
883: goto opcont;
884:
885: case SERASE:
886: /*
887: * Completed erase of the inter-record gap due to a
888: * write error; now retry the write operation.
889: */
890: vm->um_tab.b_active = SERASED;
891: goto opcont;
892: }
893:
894: opdone:
895: /*
896: * Reset error count and remove from device queue.
897: */
898: vm->um_tab.b_errcnt = 0;
899: dp->b_actf = bp->av_forw;
900: /*
901: * Save resid and release resources.
902: */
903: bp->b_resid = bp->b_bcount - htoms(cy->cy_tpb.tpcount);
904: if (bp != &ccybuf[cyunit])
905: vbadone(bp, &cy->cy_rbuf);
906: biodone(bp);
907: /*
908: * Circulate slave to end of controller
909: * queue to give other slaves a chance.
910: */
911: vm->um_tab.b_actf = dp->b_forw;
912: if (dp->b_actf) {
913: dp->b_forw = NULL;
914: if (vm->um_tab.b_actf == NULL)
915: vm->um_tab.b_actf = dp;
916: else
917: vm->um_tab.b_actl->b_forw = dp;
918: }
919: if (vm->um_tab.b_actf == 0)
920: return;
921: opcont:
922: cystart(vm);
923: }
924:
925: cytimer(dev)
926: int dev;
927: {
928: register struct yc_softc *yc = &yc_softc[YCUNIT(dev)];
929: int s;
930:
931: if (yc->yc_openf == 0 && yc->yc_timo == INF) {
932: yc->yc_tact = 0;
933: return;
934: }
935: if (yc->yc_timo != INF && (yc->yc_timo -= 5) < 0) {
936: printf("yc%d: lost interrupt\n", YCUNIT(dev));
937: yc->yc_timo = INF;
938: s = spl3();
939: cyintr(CYUNIT(dev));
940: splx(s);
941: }
942: timeout(cytimer, (caddr_t)dev, 5*hz);
943: }
944:
945: cyseteof(bp)
946: register struct buf *bp;
947: {
948: register int cyunit = CYUNIT(bp->b_dev);
949: register struct cy_softc *cy = &cy_softc[cyunit];
950: register struct yc_softc *yc = &yc_softc[YCUNIT(bp->b_dev)];
951:
952: if (bp == &ccybuf[cyunit]) {
953: if (yc->yc_blkno > bp->b_blkno) {
954: /* reversing */
955: yc->yc_nxrec = bp->b_blkno - htoms(cy->cy_tpb.tpcount);
956: yc->yc_blkno = yc->yc_nxrec;
957: } else {
958: yc->yc_blkno = bp->b_blkno + htoms(cy->cy_tpb.tpcount);
959: yc->yc_nxrec = yc->yc_blkno - 1;
960: }
961: return;
962: }
963: /* eof on read */
964: yc->yc_nxrec = bp->b_blkno;
965: }
966:
967: /*ARGSUSED*/
968: cyioctl(dev, cmd, data, flag)
969: caddr_t data;
970: dev_t dev;
971: {
972: int ycunit = YCUNIT(dev);
973: register struct yc_softc *yc = &yc_softc[ycunit];
974: register struct buf *bp = &ccybuf[CYUNIT(dev)];
975: register callcount;
976: int fcount, op;
977: struct mtop *mtop;
978: struct mtget *mtget;
979: /* we depend of the values and order of the MT codes here */
980: static cyops[] =
981: {CY_WEOF,CY_FSF,CY_BSF,CY_SFORW,CY_SREV,CY_REW,CY_OFFL,CY_SENSE};
982:
983: switch (cmd) {
984:
985: case MTIOCTOP: /* tape operation */
986: mtop = (struct mtop *)data;
987: switch (op = mtop->mt_op) {
988:
989: case MTWEOF:
990: callcount = mtop->mt_count;
991: fcount = 1;
992: break;
993:
994: case MTFSR: case MTBSR:
995: callcount = 1;
996: fcount = mtop->mt_count;
997: break;
998:
999: case MTFSF: case MTBSF:
1000: callcount = mtop->mt_count;
1001: fcount = 1;
1002: break;
1003:
1004: case MTREW: case MTOFFL: case MTNOP:
1005: callcount = 1;
1006: fcount = 1;
1007: break;
1008:
1009: default:
1010: return (ENXIO);
1011: }
1012: if (callcount <= 0 || fcount <= 0)
1013: return (EINVAL);
1014: while (--callcount >= 0) {
1015: #ifdef notdef
1016: /*
1017: * Gagh, this controller is the pits...
1018: */
1019: if (op == MTFSF || op == MTBSF) {
1020: do
1021: cycommand(dev, cyops[op], 1);
1022: while ((bp->b_flags&B_ERROR) == 0 &&
1023: (yc->yc_status&(CYS_EOT|CYS_BOT|CYS_FM)) == 0);
1024: } else
1025: #endif
1026: cycommand(dev, cyops[op], fcount);
1027: dlog((LOG_INFO,
1028: "cyioctl: status %x, b_flags %x, resid %d\n",
1029: yc->yc_status, bp->b_flags, bp->b_resid));
1030: if ((bp->b_flags&B_ERROR) ||
1031: (yc->yc_status&(CYS_BOT|CYS_EOT)))
1032: break;
1033: }
1034: bp->b_resid = callcount + 1;
1035: return (geterror(bp));
1036:
1037: case MTIOCGET:
1038: cycommand(dev, CY_SENSE, 1);
1039: mtget = (struct mtget *)data;
1040: mtget->mt_dsreg = yc->yc_status;
1041: mtget->mt_erreg = yc->yc_control;
1042: mtget->mt_resid = yc->yc_resid;
1043: mtget->mt_type = MT_ISCY;
1044: break;
1045:
1046: default:
1047: return (ENXIO);
1048: }
1049: return (0);
1050: }
1051:
1052: /*
1053: * Poll until the controller is ready.
1054: */
1055: cywait(cp)
1056: register struct cyccb *cp;
1057: {
1058: register int i = 5000;
1059:
1060: uncache(&cp->cbgate);
1061: while (i-- > 0 && cp->cbgate == GATE_CLOSED) {
1062: DELAY(1000);
1063: uncache(&cp->cbgate);
1064: }
1065: return (i <= 0);
1066: }
1067:
1068: /*
1069: * Load a 20 bit pointer into a Tapemaster pointer.
1070: */
1071: cyldmba(reg, value)
1072: register u_char *reg;
1073: caddr_t value;
1074: {
1075: register int v = (int)value;
1076:
1077: *reg++ = v;
1078: *reg++ = v >> 8;
1079: *reg++ = 0;
1080: *reg = (v&0xf0000) >> 12;
1081: }
1082:
1083: /*
1084: * Unconditionally reset all controllers to their initial state.
1085: */
1086: cyreset(vba)
1087: int vba;
1088: {
1089: register caddr_t addr;
1090: register int ctlr;
1091:
1092: for (ctlr = 0; ctlr < NCY; ctlr++)
1093: if (cyminfo[ctlr] && cyminfo[ctlr]->um_vbanum == vba) {
1094: addr = cyminfo[ctlr]->um_addr;
1095: CY_RESET(addr);
1096: if (!cyinit(ctlr, addr)) {
1097: printf("cy%d: reset failed\n", ctlr);
1098: cyminfo[ctlr] = NULL;
1099: }
1100: }
1101: }
1102:
1103: cyuncachetpb(cy)
1104: struct cy_softc *cy;
1105: {
1106: register long *lp = (long *)&cy->cy_tpb;
1107: register int i;
1108:
1109: for (i = 0; i < howmany(sizeof (struct cytpb), sizeof (long)); i++)
1110: uncache(lp++);
1111: }
1112:
1113: /*
1114: * Dump routine.
1115: */
1116: #define DUMPREC (32*1024)
1117: cydump(dev)
1118: dev_t dev;
1119: {
1120: register struct cy_softc *cy;
1121: register int bs, num, start;
1122: register caddr_t addr;
1123: int unit = CYUNIT(dev), error;
1124:
1125: if (unit >= NCY || cyminfo[unit] == 0 ||
1126: (cy = &cy_softc[unit])->cy_bs == 0 || YCUNIT(dev) >= NYC)
1127: return (ENXIO);
1128: if (cywait(&cy->cy_ccb))
1129: return (EFAULT);
1130: #define phys(a) ((caddr_t)((int)(a)&~0xc0000000))
1131: addr = phys(cyminfo[unit]->um_addr);
1132: num = maxfree, start = NBPG*2;
1133: while (num > 0) {
1134: bs = num > btoc(DUMPREC) ? btoc(DUMPREC) : num;
1135: error = cydwrite(cy, start, bs, addr);
1136: if (error)
1137: return (error);
1138: start += bs, num -= bs;
1139: }
1140: cyweof(cy, addr);
1141: cyweof(cy, addr);
1142: uncache(&cy->cy_tpb);
1143: if (cy->cy_tpb.tpstatus&CYS_ERR)
1144: return (EIO);
1145: cyrewind(cy, addr);
1146: return (0);
1147: }
1148:
1149: cydwrite(cy, pf, npf, addr)
1150: register struct cy_softc *cy;
1151: int pf, npf;
1152: caddr_t addr;
1153: {
1154:
1155: cy->cy_tpb.tpcmd = CY_WCOM;
1156: cy->cy_tpb.tpcontrol = CYCW_LOCK|CYCW_25IPS|CYCW_16BITS;
1157: cy->cy_tpb.tpstatus = 0;
1158: cy->cy_tpb.tpsize = htoms(npf*NBPG);
1159: cyldmba(cy->cy_tpb.tplink, (caddr_t)0);
1160: cyldmba(cy->cy_tpb.tpdata, (caddr_t)(pf*NBPG));
1161: cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb);
1162: cy->cy_ccb.cbgate = GATE_CLOSED;
1163: CY_GO(addr);
1164: if (cywait(&cy->cy_ccb))
1165: return (EFAULT);
1166: uncache(&cy->cy_tpb);
1167: if (cy->cy_tpb.tpstatus&CYS_ERR)
1168: return (EIO);
1169: return (0);
1170: }
1171:
1172: cyweof(cy, addr)
1173: register struct cy_softc *cy;
1174: caddr_t addr;
1175: {
1176:
1177: cy->cy_tpb.tpcmd = CY_WEOF;
1178: cy->cy_tpb.tpcount = htoms(1);
1179: cy->cy_ccb.cbgate = GATE_CLOSED;
1180: CY_GO(addr);
1181: (void) cywait(&cy->cy_ccb);
1182: }
1183:
1184: cyrewind(cy, addr)
1185: register struct cy_softc *cy;
1186: caddr_t addr;
1187: {
1188:
1189: cy->cy_tpb.tpcmd = CY_REW;
1190: cy->cy_tpb.tpcount = htoms(1);
1191: cy->cy_ccb.cbgate = GATE_CLOSED;
1192: CY_GO(addr);
1193: (void) cywait(&cy->cy_ccb);
1194: }
1195: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.