|
|
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 is only permitted until one year after the first shipment
9: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
10: * binary forms are permitted provided that: (1) source distributions retain
11: * this entire copyright notice and comment, and (2) distributions including
12: * binaries display the following acknowledgement: This product includes
13: * software developed by the University of California, Berkeley and its
14: * contributors'' in the documentation or other materials provided with the
15: * distribution and in all advertising materials mentioning features or use
16: * of this software. Neither the name of the University nor the names of
17: * its contributors may be used to endorse or promote products derived from
18: * this software without specific prior written permission.
19: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22: *
23: * @(#)cy.c 7.4 (Berkeley) 5/5/89
24: */
25:
26: #include "yc.h"
27: #if NCY > 0
28: /*
29: * Cipher Tapemaster driver.
30: */
31: #define CYDEBUG
32: #ifdef CYDEBUG
33: int cydebug = 0;
34: #define dlog(params) if (cydebug) log params
35: #else
36: #define dlog(params) /* */
37: #endif
38:
39: #include "param.h"
40: #include "systm.h"
41: #include "vm.h"
42: #include "buf.h"
43: #include "file.h"
44: #include "signal.h"
45: #include "ioctl.h"
46: #include "mtio.h"
47: #include "errno.h"
48: #include "cmap.h"
49: #include "time.h"
50: #include "kernel.h"
51: #include "syslog.h"
52: #include "tprintf.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: tpr_t yc_tpr; /* handle for tprintf */
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_tpr = tprintf_open();
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: tprintf_close(yc->yc_tpr);
374: yc->yc_openf = 0;
375: return (0);
376: }
377:
378: /*
379: * Execute a command on the tape drive a specified number of times.
380: */
381: cycommand(dev, com, count)
382: dev_t dev;
383: int com, count;
384: {
385: register struct buf *bp;
386: int s;
387:
388: bp = &ccybuf[CYUNIT(dev)];
389: s = spl3();
390: dlog((LOG_INFO, "cycommand(%o, %x, %d), b_flags %x\n",
391: dev, com, count, bp->b_flags));
392: while (bp->b_flags&B_BUSY) {
393: /*
394: * This special check is because B_BUSY never
395: * gets cleared in the non-waiting rewind case.
396: */
397: if (bp->b_repcnt == 0 && (bp->b_flags&B_DONE))
398: break;
399: bp->b_flags |= B_WANTED;
400: sleep((caddr_t)bp, PRIBIO);
401: }
402: bp->b_flags = B_BUSY|B_READ;
403: splx(s);
404: bp->b_dev = dev;
405: bp->b_repcnt = count;
406: bp->b_command = com;
407: bp->b_blkno = 0;
408: cystrategy(bp);
409: /*
410: * In case of rewind from close; don't wait.
411: * This is the only case where count can be 0.
412: */
413: if (count == 0)
414: return;
415: biowait(bp);
416: if (bp->b_flags&B_WANTED)
417: wakeup((caddr_t)bp);
418: bp->b_flags &= B_ERROR;
419: }
420:
421: cystrategy(bp)
422: register struct buf *bp;
423: {
424: int ycunit = YCUNIT(bp->b_dev);
425: register struct vba_ctlr *vm;
426: register struct buf *dp;
427: int s;
428:
429: /*
430: * Put transfer at end of unit queue.
431: */
432: dlog((LOG_INFO, "cystrategy(%o, %x)\n", bp->b_dev, bp->b_command));
433: dp = &ycutab[ycunit];
434: bp->av_forw = NULL;
435: vm = ycdinfo[ycunit]->ui_mi;
436: /* BEGIN GROT */
437: if (bp->b_flags & B_RAW) {
438: if (bp->b_bcount >= CYMAXIO) {
439: uprintf("cy%d: i/o size too large\n", vm->um_ctlr);
440: bp->b_error = EINVAL;
441: bp->b_resid = bp->b_bcount;
442: bp->b_flags |= B_ERROR;
443: biodone(bp);
444: return;
445: }
446: }
447: /* END GROT */
448: s = spl3();
449: if (dp->b_actf == NULL) {
450: dp->b_actf = bp;
451: /*
452: * Transport not already active...
453: * put at end of controller queue.
454: */
455: dp->b_forw = NULL;
456: if (vm->um_tab.b_actf == NULL)
457: vm->um_tab.b_actf = dp;
458: else
459: vm->um_tab.b_actl->b_forw = dp;
460: } else
461: dp->b_actl->av_forw = bp;
462: dp->b_actl = bp;
463: /*
464: * If the controller is not busy, get it going.
465: */
466: if (vm->um_tab.b_active == 0)
467: cystart(vm);
468: splx(s);
469: }
470:
471: /*
472: * Start activity on a cy controller.
473: */
474: cystart(vm)
475: register struct vba_ctlr *vm;
476: {
477: register struct buf *bp, *dp;
478: register struct yc_softc *yc;
479: register struct cy_softc *cy;
480: int ycunit;
481: daddr_t blkno;
482:
483: dlog((LOG_INFO, "cystart()\n"));
484: /*
485: * Look for an idle transport on the controller.
486: */
487: loop:
488: if ((dp = vm->um_tab.b_actf) == NULL)
489: return;
490: if ((bp = dp->b_actf) == NULL) {
491: vm->um_tab.b_actf = dp->b_forw;
492: goto loop;
493: }
494: ycunit = YCUNIT(bp->b_dev);
495: yc = &yc_softc[ycunit];
496: cy = &cy_softc[CYUNIT(bp->b_dev)];
497: /*
498: * Default is that last command was NOT a write command;
499: * if we do a write command we will notice this in cyintr().
500: */
501: yc->yc_lastiow = 0;
502: if (yc->yc_openf < 0 ||
503: (bp->b_command != CY_SENSE && (cy->cy_tpb.tpstatus&CYS_OL) == 0)) {
504: /*
505: * Have had a hard error on a non-raw tape
506: * or the tape unit is now unavailable (e.g.
507: * taken off line).
508: */
509: dlog((LOG_INFO, "openf %d command %x status %b\n",
510: yc->yc_openf, bp->b_command, cy->cy_tpb.tpstatus, CYS_BITS));
511: bp->b_flags |= B_ERROR;
512: goto next;
513: }
514: if (bp == &ccybuf[CYUNIT(bp->b_dev)]) {
515: /*
516: * Execute control operation with the specified count.
517: *
518: * Set next state; give 5 minutes to complete
519: * rewind or file mark search, or 10 seconds per
520: * iteration (minimum 60 seconds and max 5 minutes)
521: * to complete other ops.
522: */
523: if (bp->b_command == CY_REW) {
524: vm->um_tab.b_active = SREW;
525: yc->yc_timo = 5*60;
526: } else if (bp->b_command == CY_FSF ||
527: bp->b_command == CY_BSF) {
528: vm->um_tab.b_active = SCOM;
529: yc->yc_timo = 5*60;
530: } else {
531: vm->um_tab.b_active = SCOM;
532: yc->yc_timo = imin(imax(10*(int)bp->b_repcnt,60),5*60);
533: }
534: cy->cy_tpb.tprec = htoms(bp->b_repcnt);
535: dlog((LOG_INFO, "bpcmd "));
536: goto dobpcmd;
537: }
538: /*
539: * For raw I/O, save the current block
540: * number in case we have to retry.
541: */
542: if (bp->b_flags & B_RAW) {
543: if (vm->um_tab.b_errcnt == 0) {
544: yc->yc_blkno = bp->b_blkno;
545: yc->yc_nxrec = yc->yc_blkno + 1;
546: }
547: } else {
548: /*
549: * Handle boundary cases for operation
550: * on non-raw tapes.
551: */
552: if (bp->b_blkno > yc->yc_nxrec) {
553: /*
554: * Can't read past known end-of-file.
555: */
556: bp->b_flags |= B_ERROR;
557: bp->b_error = ENXIO;
558: goto next;
559: }
560: if (bp->b_blkno == yc->yc_nxrec && bp->b_flags&B_READ) {
561: /*
562: * Reading at end of file returns 0 bytes.
563: */
564: bp->b_resid = bp->b_bcount;
565: clrbuf(bp);
566: goto next;
567: }
568: if ((bp->b_flags&B_READ) == 0)
569: /*
570: * Writing sets EOF.
571: */
572: yc->yc_nxrec = bp->b_blkno + 1;
573: }
574: if ((blkno = yc->yc_blkno) == bp->b_blkno) {
575: caddr_t addr;
576: int cmd;
577:
578: /*
579: * Choose the appropriate i/o command based on the
580: * transfer size, the estimated block size,
581: * and the controller's internal buffer size.
582: * If the request length is longer than the tape
583: * block length, a buffered read will fail,
584: * thus, we request at most the size that we expect.
585: * We then check for larger records when the read completes.
586: * If we're retrying a read on a raw device because
587: * the original try was a buffer request which failed
588: * due to a record length error, then we force the use
589: * of the raw controller read (YECH!!!!).
590: */
591: if (bp->b_flags&B_READ) {
592: if (yc->yc_blksize <= cy->cy_bs &&
593: vm->um_tab.b_errcnt == 0)
594: cmd = CY_BRCOM;
595: else
596: cmd = CY_RCOM;
597: } else {
598: /*
599: * On write error retries erase the
600: * inter-record gap before rewriting.
601: */
602: if (vm->um_tab.b_errcnt &&
603: vm->um_tab.b_active != SERASED) {
604: vm->um_tab.b_active = SERASE;
605: bp->b_command = CY_ERASE;
606: yc->yc_timo = 60;
607: goto dobpcmd;
608: }
609: cmd = (bp->b_bcount > cy->cy_bs) ? CY_WCOM : CY_BWCOM;
610: }
611: vm->um_tab.b_active = SIO;
612: addr = (caddr_t)vbasetup(bp, &cy->cy_rbuf, 1);
613: cy->cy_tpb.tpcmd = cmd;
614: cy->cy_tpb.tpcontrol = yc->yc_dens;
615: if (cmd == CY_RCOM || cmd == CY_WCOM)
616: cy->cy_tpb.tpcontrol |= CYCW_LOCK;
617: cy->cy_tpb.tpstatus = 0;
618: cy->cy_tpb.tpcount = 0;
619: cyldmba(cy->cy_tpb.tpdata, (caddr_t)addr);
620: cy->cy_tpb.tprec = 0;
621: if (cmd == CY_BRCOM)
622: cy->cy_tpb.tpsize = htoms(imin(yc->yc_blksize,
623: (int)bp->b_bcount));
624: else
625: cy->cy_tpb.tpsize = htoms(bp->b_bcount);
626: cyldmba(cy->cy_tpb.tplink, (caddr_t)0);
627: do
628: uncache(&cy->cy_ccb.cbgate);
629: while (cy->cy_ccb.cbgate == GATE_CLOSED);
630: cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb);
631: cy->cy_ccb.cbcw = CBCW_IE;
632: cy->cy_ccb.cbgate = GATE_CLOSED;
633: dlog((LOG_INFO, "CY_GO(%x) cmd %x control %x size %d\n",
634: vm->um_addr, cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol,
635: htoms(cy->cy_tpb.tpsize)));
636: CY_GO(vm->um_addr);
637: return;
638: }
639: /*
640: * Tape positioned incorrectly; set to seek forwards
641: * or backwards to the correct spot. This happens
642: * for raw tapes only on error retries.
643: */
644: vm->um_tab.b_active = SSEEK;
645: if (blkno < bp->b_blkno) {
646: bp->b_command = CY_SFORW;
647: cy->cy_tpb.tprec = htoms(bp->b_blkno - blkno);
648: } else {
649: bp->b_command = CY_SREV;
650: cy->cy_tpb.tprec = htoms(blkno - bp->b_blkno);
651: }
652: yc->yc_timo = imin(imax((int)(10 * htoms(cy->cy_tpb.tprec)), 60), 5*60);
653: dobpcmd:
654: /*
655: * Do the command in bp. Reverse direction commands
656: * are indicated by having CYCW_REV or'd into their
657: * value. For these we must set the appropriate bit
658: * in the control field.
659: */
660: if (bp->b_command&CYCW_REV) {
661: cy->cy_tpb.tpcmd = bp->b_command &~ CYCW_REV;
662: cy->cy_tpb.tpcontrol = yc->yc_dens | CYCW_REV;
663: dlog((LOG_INFO, "cmd %x control %x\n", cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol));
664: } else {
665: cy->cy_tpb.tpcmd = bp->b_command;
666: cy->cy_tpb.tpcontrol = yc->yc_dens;
667: dlog((LOG_INFO, "cmd %x control %x\n", cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol));
668: }
669: cy->cy_tpb.tpstatus = 0;
670: cy->cy_tpb.tpcount = 0;
671: cyldmba(cy->cy_tpb.tplink, (caddr_t)0);
672: do
673: uncache(&cy->cy_ccb.cbgate);
674: while (cy->cy_ccb.cbgate == GATE_CLOSED);
675: cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb);
676: cy->cy_ccb.cbcw = CBCW_IE;
677: cy->cy_ccb.cbgate = GATE_CLOSED;
678: dlog((LOG_INFO, "CY_GO(%x) cmd %x control %x rec %d\n",
679: vm->um_addr, cy->cy_tpb.tpcmd, cy->cy_tpb.tpcontrol,
680: htoms(cy->cy_tpb.tprec)));
681: CY_GO(vm->um_addr);
682: return;
683: next:
684: /*
685: * Done with this operation due to error or the
686: * fact that it doesn't do anything.
687: * Dequeue the transfer and continue
688: * processing this slave.
689: */
690: vm->um_tab.b_errcnt = 0;
691: dp->b_actf = bp->av_forw;
692: biodone(bp);
693: goto loop;
694: }
695:
696: /*
697: * Cy interrupt routine.
698: */
699: cyintr(cyunit)
700: int cyunit;
701: {
702: struct buf *dp;
703: register struct buf *bp;
704: register struct vba_ctlr *vm = cyminfo[cyunit];
705: register struct cy_softc *cy;
706: register struct yc_softc *yc;
707: int err;
708: register state;
709:
710: dlog((LOG_INFO, "cyintr(%d)\n", cyunit));
711: /*
712: * First, turn off the interrupt from the controller
713: * (device uses Multibus non-vectored interrupts...yech).
714: */
715: cy = &cy_softc[vm->um_ctlr];
716: cy->cy_ccb.cbcw = CBCW_CLRINT;
717: cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_nop);
718: cy->cy_ccb.cbgate = GATE_CLOSED;
719: CY_GO(vm->um_addr);
720: if ((dp = vm->um_tab.b_actf) == NULL) {
721: dlog((LOG_ERR, "cy%d: stray interrupt", vm->um_ctlr));
722: return;
723: }
724: bp = dp->b_actf;
725: cy = &cy_softc[cyunit];
726: cyuncachetpb(cy);
727: yc = &yc_softc[YCUNIT(bp->b_dev)];
728: /*
729: * If last command was a rewind and tape is
730: * still moving, wait for the operation to complete.
731: */
732: if (vm->um_tab.b_active == SREW) {
733: vm->um_tab.b_active = SCOM;
734: if ((cy->cy_tpb.tpstatus&CYS_RDY) == 0) {
735: yc->yc_timo = 5*60; /* 5 minutes */
736: return;
737: }
738: }
739: /*
740: * An operation completed...record status.
741: */
742: yc->yc_timo = INF;
743: yc->yc_control = cy->cy_tpb.tpcontrol;
744: yc->yc_status = cy->cy_tpb.tpstatus;
745: yc->yc_resid = bp->b_bcount - htoms(cy->cy_tpb.tpcount);
746: dlog((LOG_INFO, "cmd %x control %b status %b resid %d\n",
747: cy->cy_tpb.tpcmd, yc->yc_control, CYCW_BITS,
748: yc->yc_status, CYS_BITS, yc->yc_resid));
749: if ((bp->b_flags&B_READ) == 0)
750: yc->yc_lastiow = 1;
751: state = vm->um_tab.b_active;
752: vm->um_tab.b_active = 0;
753: /*
754: * Check for errors.
755: */
756: if (cy->cy_tpb.tpstatus&CYS_ERR) {
757: err = cy->cy_tpb.tpstatus&CYS_ERR;
758: dlog((LOG_INFO, "error %d\n", err));
759: /*
760: * If we hit the end of tape file, update our position.
761: */
762: if (err == CYER_FM) {
763: yc->yc_status |= CYS_FM;
764: state = SCOM; /* force completion */
765: cyseteof(bp); /* set blkno and nxrec */
766: goto opdone;
767: }
768: /*
769: * Fix up errors which occur due to backspacing over
770: * the beginning of the tape.
771: */
772: if (err == CYER_BOT && cy->cy_tpb.tpcontrol&CYCW_REV) {
773: yc->yc_status |= CYS_BOT;
774: goto ignoreerr;
775: }
776: /*
777: * If we were reading raw tape and the only error was that the
778: * record was too long, then we don't consider this an error.
779: */
780: if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) &&
781: err == CYER_STROBE) {
782: /*
783: * Retry reads with the command changed to
784: * a raw read if necessary. Setting b_errcnt
785: * here causes cystart (above) to force a CY_RCOM.
786: */
787: if (cy->cy_tpb.tpcmd == CY_BRCOM &&
788: vm->um_tab.b_errcnt++ == 0) {
789: yc->yc_blkno++;
790: goto opcont;
791: } else
792: goto ignoreerr;
793: }
794: /*
795: * If error is not hard, and this was an i/o operation
796: * retry up to 8 times.
797: */
798: if (state == SIO && (CYMASK(err) &
799: ((bp->b_flags&B_READ) ? CYER_RSOFT : CYER_WSOFT))) {
800: if (++vm->um_tab.b_errcnt < 7) {
801: yc->yc_blkno++;
802: goto opcont;
803: }
804: } else
805: /*
806: * Hard or non-i/o errors on non-raw tape
807: * cause it to close.
808: */
809: if ((bp->b_flags&B_RAW) == 0 &&
810: yc->yc_openf > 0)
811: yc->yc_openf = -1;
812: /*
813: * Couldn't recover from error.
814: */
815: tprintf(yc->yc_tpr,
816: "yc%d: hard error bn%d status=%b, %s\n", YCUNIT(bp->b_dev),
817: bp->b_blkno, yc->yc_status, CYS_BITS,
818: (err < NCYERROR) ? cyerror[err] : "");
819: bp->b_flags |= B_ERROR;
820: goto opdone;
821: } else if (cy->cy_tpb.tpcmd == CY_BRCOM) {
822: int reclen = htoms(cy->cy_tpb.tprec);
823:
824: /*
825: * If we did a buffered read, check whether the read
826: * was long enough. If we asked the controller for less
827: * than the user asked for because the previous record
828: * was shorter, update our notion of record size
829: * and retry. If the record is longer than the buffer,
830: * bump the errcnt so the retry will use direct read.
831: */
832: if (reclen > yc->yc_blksize && bp->b_bcount > yc->yc_blksize) {
833: yc->yc_blksize = reclen;
834: if (reclen > cy->cy_bs)
835: vm->um_tab.b_errcnt++;
836: yc->yc_blkno++;
837: goto opcont;
838: }
839: }
840: /*
841: * Advance tape control FSM.
842: */
843: ignoreerr:
844: /*
845: * If we hit a tape mark update our position.
846: */
847: if (yc->yc_status&CYS_FM && bp->b_flags&B_READ) {
848: cyseteof(bp);
849: goto opdone;
850: }
851: switch (state) {
852:
853: case SIO:
854: /*
855: * Read/write increments tape block number.
856: */
857: yc->yc_blkno++;
858: yc->yc_blks++;
859: if (vm->um_tab.b_errcnt || yc->yc_status & CYS_CR)
860: yc->yc_softerrs++;
861: yc->yc_blksize = htoms(cy->cy_tpb.tpcount);
862: dlog((LOG_ERR, "blocksize %d", yc->yc_blksize));
863: goto opdone;
864:
865: case SCOM:
866: /*
867: * For forward/backward space record update current position.
868: */
869: if (bp == &ccybuf[CYUNIT(bp->b_dev)])
870: switch ((int)bp->b_command) {
871:
872: case CY_SFORW:
873: yc->yc_blkno -= bp->b_repcnt;
874: break;
875:
876: case CY_SREV:
877: yc->yc_blkno += bp->b_repcnt;
878: break;
879: }
880: goto opdone;
881:
882: case SSEEK:
883: yc->yc_blkno = bp->b_blkno;
884: goto opcont;
885:
886: case SERASE:
887: /*
888: * Completed erase of the inter-record gap due to a
889: * write error; now retry the write operation.
890: */
891: vm->um_tab.b_active = SERASED;
892: goto opcont;
893: }
894:
895: opdone:
896: /*
897: * Reset error count and remove from device queue.
898: */
899: vm->um_tab.b_errcnt = 0;
900: dp->b_actf = bp->av_forw;
901: /*
902: * Save resid and release resources.
903: */
904: bp->b_resid = bp->b_bcount - htoms(cy->cy_tpb.tpcount);
905: if (bp != &ccybuf[cyunit])
906: vbadone(bp, &cy->cy_rbuf);
907: biodone(bp);
908: /*
909: * Circulate slave to end of controller
910: * queue to give other slaves a chance.
911: */
912: vm->um_tab.b_actf = dp->b_forw;
913: if (dp->b_actf) {
914: dp->b_forw = NULL;
915: if (vm->um_tab.b_actf == NULL)
916: vm->um_tab.b_actf = dp;
917: else
918: vm->um_tab.b_actl->b_forw = dp;
919: }
920: if (vm->um_tab.b_actf == 0)
921: return;
922: opcont:
923: cystart(vm);
924: }
925:
926: cytimer(dev)
927: int dev;
928: {
929: register struct yc_softc *yc = &yc_softc[YCUNIT(dev)];
930: int s;
931:
932: if (yc->yc_openf == 0 && yc->yc_timo == INF) {
933: yc->yc_tact = 0;
934: return;
935: }
936: if (yc->yc_timo != INF && (yc->yc_timo -= 5) < 0) {
937: printf("yc%d: lost interrupt\n", YCUNIT(dev));
938: yc->yc_timo = INF;
939: s = spl3();
940: cyintr(CYUNIT(dev));
941: splx(s);
942: }
943: timeout(cytimer, (caddr_t)dev, 5*hz);
944: }
945:
946: cyseteof(bp)
947: register struct buf *bp;
948: {
949: register int cyunit = CYUNIT(bp->b_dev);
950: register struct cy_softc *cy = &cy_softc[cyunit];
951: register struct yc_softc *yc = &yc_softc[YCUNIT(bp->b_dev)];
952:
953: if (bp == &ccybuf[cyunit]) {
954: if (yc->yc_blkno > bp->b_blkno) {
955: /* reversing */
956: yc->yc_nxrec = bp->b_blkno - htoms(cy->cy_tpb.tpcount);
957: yc->yc_blkno = yc->yc_nxrec;
958: } else {
959: yc->yc_blkno = bp->b_blkno + htoms(cy->cy_tpb.tpcount);
960: yc->yc_nxrec = yc->yc_blkno - 1;
961: }
962: return;
963: }
964: /* eof on read */
965: yc->yc_nxrec = bp->b_blkno;
966: }
967:
968: /*ARGSUSED*/
969: cyioctl(dev, cmd, data, flag)
970: caddr_t data;
971: dev_t dev;
972: {
973: int ycunit = YCUNIT(dev);
974: register struct yc_softc *yc = &yc_softc[ycunit];
975: register struct buf *bp = &ccybuf[CYUNIT(dev)];
976: register callcount;
977: int fcount, op;
978: struct mtop *mtop;
979: struct mtget *mtget;
980: /* we depend of the values and order of the MT codes here */
981: static cyops[] =
982: {CY_WEOF,CY_FSF,CY_BSF,CY_SFORW,CY_SREV,CY_REW,CY_OFFL,CY_SENSE};
983:
984: switch (cmd) {
985:
986: case MTIOCTOP: /* tape operation */
987: mtop = (struct mtop *)data;
988: switch (op = mtop->mt_op) {
989:
990: case MTWEOF:
991: callcount = mtop->mt_count;
992: fcount = 1;
993: break;
994:
995: case MTFSR: case MTBSR:
996: callcount = 1;
997: fcount = mtop->mt_count;
998: break;
999:
1000: case MTFSF: case MTBSF:
1001: callcount = mtop->mt_count;
1002: fcount = 1;
1003: break;
1004:
1005: case MTREW: case MTOFFL: case MTNOP:
1006: callcount = 1;
1007: fcount = 1;
1008: break;
1009:
1010: default:
1011: return (ENXIO);
1012: }
1013: if (callcount <= 0 || fcount <= 0)
1014: return (EINVAL);
1015: while (--callcount >= 0) {
1016: #ifdef notdef
1017: /*
1018: * Gagh, this controller is the pits...
1019: */
1020: if (op == MTFSF || op == MTBSF) {
1021: do
1022: cycommand(dev, cyops[op], 1);
1023: while ((bp->b_flags&B_ERROR) == 0 &&
1024: (yc->yc_status&(CYS_EOT|CYS_BOT|CYS_FM)) == 0);
1025: } else
1026: #endif
1027: cycommand(dev, cyops[op], fcount);
1028: dlog((LOG_INFO,
1029: "cyioctl: status %x, b_flags %x, resid %d\n",
1030: yc->yc_status, bp->b_flags, bp->b_resid));
1031: if ((bp->b_flags&B_ERROR) ||
1032: (yc->yc_status&(CYS_BOT|CYS_EOT)))
1033: break;
1034: }
1035: bp->b_resid = callcount + 1;
1036: /*
1037: * Pick up the device's error number and pass it
1038: * to the user; if there is an error but the number
1039: * is 0 set a generalized code.
1040: */
1041: if ((bp->b_flags & B_ERROR) == 0)
1042: return (0);
1043: if (bp->b_error)
1044: return (bp->b_error);
1045: return (EIO);
1046:
1047: case MTIOCGET:
1048: cycommand(dev, CY_SENSE, 1);
1049: mtget = (struct mtget *)data;
1050: mtget->mt_dsreg = yc->yc_status;
1051: mtget->mt_erreg = yc->yc_control;
1052: mtget->mt_resid = yc->yc_resid;
1053: mtget->mt_type = MT_ISCY;
1054: break;
1055:
1056: default:
1057: return (ENXIO);
1058: }
1059: return (0);
1060: }
1061:
1062: /*
1063: * Poll until the controller is ready.
1064: */
1065: cywait(cp)
1066: register struct cyccb *cp;
1067: {
1068: register int i = 5000;
1069:
1070: uncache(&cp->cbgate);
1071: while (i-- > 0 && cp->cbgate == GATE_CLOSED) {
1072: DELAY(1000);
1073: uncache(&cp->cbgate);
1074: }
1075: return (i <= 0);
1076: }
1077:
1078: /*
1079: * Load a 20 bit pointer into a Tapemaster pointer.
1080: */
1081: cyldmba(reg, value)
1082: register u_char *reg;
1083: caddr_t value;
1084: {
1085: register int v = (int)value;
1086:
1087: *reg++ = v;
1088: *reg++ = v >> 8;
1089: *reg++ = 0;
1090: *reg = (v&0xf0000) >> 12;
1091: }
1092:
1093: /*
1094: * Unconditionally reset all controllers to their initial state.
1095: */
1096: cyreset(vba)
1097: int vba;
1098: {
1099: register caddr_t addr;
1100: register int ctlr;
1101:
1102: for (ctlr = 0; ctlr < NCY; ctlr++)
1103: if (cyminfo[ctlr] && cyminfo[ctlr]->um_vbanum == vba) {
1104: addr = cyminfo[ctlr]->um_addr;
1105: CY_RESET(addr);
1106: if (!cyinit(ctlr, addr)) {
1107: printf("cy%d: reset failed\n", ctlr);
1108: cyminfo[ctlr] = NULL;
1109: }
1110: }
1111: }
1112:
1113: cyuncachetpb(cy)
1114: struct cy_softc *cy;
1115: {
1116: register long *lp = (long *)&cy->cy_tpb;
1117: register int i;
1118:
1119: for (i = 0; i < howmany(sizeof (struct cytpb), sizeof (long)); i++)
1120: uncache(lp++);
1121: }
1122:
1123: /*
1124: * Dump routine.
1125: */
1126: #define DUMPREC (32*1024)
1127: cydump(dev)
1128: dev_t dev;
1129: {
1130: register struct cy_softc *cy;
1131: register int bs, num, start;
1132: register caddr_t addr;
1133: int unit = CYUNIT(dev), error;
1134:
1135: if (unit >= NCY || cyminfo[unit] == 0 ||
1136: (cy = &cy_softc[unit])->cy_bs == 0 || YCUNIT(dev) >= NYC)
1137: return (ENXIO);
1138: if (cywait(&cy->cy_ccb))
1139: return (EFAULT);
1140: #define phys(a) ((caddr_t)((int)(a)&~0xc0000000))
1141: addr = phys(cyminfo[unit]->um_addr);
1142: num = maxfree, start = NBPG*2;
1143: while (num > 0) {
1144: bs = num > btoc(DUMPREC) ? btoc(DUMPREC) : num;
1145: error = cydwrite(cy, start, bs, addr);
1146: if (error)
1147: return (error);
1148: start += bs, num -= bs;
1149: }
1150: cyweof(cy, addr);
1151: cyweof(cy, addr);
1152: uncache(&cy->cy_tpb);
1153: if (cy->cy_tpb.tpstatus&CYS_ERR)
1154: return (EIO);
1155: cyrewind(cy, addr);
1156: return (0);
1157: }
1158:
1159: cydwrite(cy, pf, npf, addr)
1160: register struct cy_softc *cy;
1161: int pf, npf;
1162: caddr_t addr;
1163: {
1164:
1165: cy->cy_tpb.tpcmd = CY_WCOM;
1166: cy->cy_tpb.tpcontrol = CYCW_LOCK|CYCW_25IPS|CYCW_16BITS;
1167: cy->cy_tpb.tpstatus = 0;
1168: cy->cy_tpb.tpsize = htoms(npf*NBPG);
1169: cyldmba(cy->cy_tpb.tplink, (caddr_t)0);
1170: cyldmba(cy->cy_tpb.tpdata, (caddr_t)(pf*NBPG));
1171: cyldmba(cy->cy_ccb.cbtpb, (caddr_t)&cy->cy_tpb);
1172: cy->cy_ccb.cbgate = GATE_CLOSED;
1173: CY_GO(addr);
1174: if (cywait(&cy->cy_ccb))
1175: return (EFAULT);
1176: uncache(&cy->cy_tpb);
1177: if (cy->cy_tpb.tpstatus&CYS_ERR)
1178: return (EIO);
1179: return (0);
1180: }
1181:
1182: cyweof(cy, addr)
1183: register struct cy_softc *cy;
1184: caddr_t addr;
1185: {
1186:
1187: cy->cy_tpb.tpcmd = CY_WEOF;
1188: cy->cy_tpb.tpcount = htoms(1);
1189: cy->cy_ccb.cbgate = GATE_CLOSED;
1190: CY_GO(addr);
1191: (void) cywait(&cy->cy_ccb);
1192: }
1193:
1194: cyrewind(cy, addr)
1195: register struct cy_softc *cy;
1196: caddr_t addr;
1197: {
1198:
1199: cy->cy_tpb.tpcmd = CY_REW;
1200: cy->cy_tpb.tpcount = htoms(1);
1201: cy->cy_ccb.cbgate = GATE_CLOSED;
1202: CY_GO(addr);
1203: (void) cywait(&cy->cy_ccb);
1204: }
1205: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.