|
|
1.1 root 1: extern int OUTB_DB;
2:
3: int FT_BLAB = 0;
4: int FT_ACKBLAB = 0;
5:
6: /*
7: * File: ft.c
8: *
9: * Purpose: Floppy tape device control.
10: * Requires 765 controller module fdc.c
11: * FDC = floppy disk controller, e.g. NEC upd765
12: *
13: * Revised: Tue Jun 29 08:22:14 1993 CDT
14: *
15: * To do:
16: * Read fractional segment or block, then come back for the rest.
17: * Coordinate conversion: tape <--> pseudo diskette
18: * Skip entire segment if bad block map says > 28 bad blocks.
19: * ECC.
20: * QIC-40.
21: * 205' cartridges.
22: * Write.
23: * Bad block map.
24: * Don't rewind on close (or on next open?).
25: * Timeout protection whenever sleeping on FDC interrupt.
26: * VTBL
27: * Ability to read/write DOS tapes.
28: * Compression.
29: * ioctl: get info and status
30: * ioctl: format
31: * ioctl: rewind, retension, wind to end of data
32: * Ioctl: mapPhysUser() for improved speed.
33: */
34:
35: /*
36: * Here is the protocol for QIC report commands, I think:
37: *
38: * Send QIC report command to FDC (this will be an FDC seek command).
39: * FDC interrupts when step pulses are sent.
40: * Send Sense Interrupt Status to FDC. (Clears interrupt line.)
41: * Read interrupt status from FDC.
42: * - Get ACK from tape drive. Want Track 0 true. Variable latency.
43: * Do
44: * Send Sense Drive Status to FDC.
45: * Read drive status from FDC, including Track 0 bit.
46: * Until Track 0 true.
47: * - Get data bits for the report command.
48: * For number-of-data-bits-in-report times
49: * Send QIC Report Next Bit command to FDC.
50: * FDC interrupts when step pulses are sent.
51: * Send Sense Interrupt Status to FDC.
52: * Read interrupt status from FDC.
53: * Send Sense Drive Status to FDC.
54: * Read drive status from FDC, including Track 0 bit.
55: * Save Track 0 bit value into report data.
56: * End for
57: * - Get final Track 0 true from tape drive.
58: * Send QIC Report Next Bit command to FDC.
59: * FDC interrupts when step pulses are sent.
60: * Send Sense Interrupt Status to FDC.
61: * Read interrupt status from FDC.
62: * Send Sense Drive Status to FDC.
63: * Read drive status from FDC, including Track 0 bit.
64: * Track 0 bit must be true.
65: */
66:
67: /*
68: * ----------------------------------------------------------------------
69: * Includes.
70: */
71: #include <sys/coherent.h>
72:
73: #include <errno.h>
74: #include <sys/buf.h>
75: #include <sys/con.h>
76: #include <sys/devices.h>
77: #include <sys/dmac.h>
78: #include <sys/fdc765.h>
79: #include <sys/fdioctl.h>
80: #include <sys/file.h>
81: #include <sys/sched.h>
82: #include <sys/stat.h>
83: #include <sys/xl.h>
84: #include <sys/xlfdc.h>
85: #include <sys/xlft.h>
86:
87: /*
88: * ----------------------------------------------------------------------
89: * Definitions.
90: * Constants.
91: * Macros with argument lists.
92: * Typedefs.
93: * Enums.
94: */
95: #define FT_MAX_NBUF 150 /* NBUF patch value is limited to this. */
96:
97: #define FT_BFRSZ 32768 /* 32k, size of QIC-80 segment */
98: #define FT_BLKSZ 1024 /* 1k, size of QIC-80 block */
99: #define FT_BLK_PER_SEG 32 /* 32 blocks per segment */
100: #define FT_NUM_ECC_BLKS 3 /* 3 ECC blocks per segment */
101:
102: #define FT_ACK_TRIES 20 /* max # of tries for ACK to QIC rpt cmd*/
103: #define FT_CAL_TRIES 2 /* max # of tries for seek load point */
104:
105: #define FT_CAL_SECS 120 /* max # seconds for seek load point */
106: #define FT_PAUSE_SECS 15 /* max # seconds for pause */
107: #define FT_RDY_SECS 120 /* max # seconds for drive ready */
108: #define FT_SEEK_SECS 15 /* max # seconds for seek head to track */
109: #define FT_WIND_SECS 180 /* max # seconds for wind or rewind */
110:
111: #define FT_INITIAL_TRACK 0
112: #define FT_INITIAL_PHY_SEG 3 /* Skip 2 format headers + VTBL */
113:
114: #define FT_OPEN_ERR(msg) {devmsg(dev,msg);goto badFtOpen;}
115: #define FT_READ_ERR(msg) {devmsg(dev,msg);goto badFtRead;}
116:
117: /*
118: * Macros to get information from tape unit number, which is 0..3.
119: * Unit 0 is soft select - no motor on.
120: * Units 1..3 are hardware select.
121: */
122: #define FT_DRIVE(unit) (unit)
123: #define FT_MOTOR(unit) ((unit > 0) ? FDC_MOTOR_ON : FDC_MOTOR_OFF)
124: #define FT_SOFT_SELECT(unit) (unit == 0)
125:
126: /* Divide, rounding up if remainder is nonzero. */
127: #define FT_DIV_RU(dividend, divisor) \
128: (((dividend) + (divisor) - 1) / (divisor))
129:
130: /* Real (tape) and pseudo (diskette) parameters for each cartridge format. */
131: struct FtParm {
132: /* Tape parameters. */
133: uint segPerTrk;
134: uint tracks;
135:
136: /* FDC pseudo parameters. */
137: uint blkPerTrk;
138: uint heads;
139: uint cyls;
140: };
141:
142: /* Driver state variables. */
143: struct FT {
144: /* booleans */
145: unchar ft_wakeMeUp; /* 1 = sleeping til next FDC IRQ */
146: unchar ft_dumpIrq; /* 1 = dump IRQ status */
147: unchar ft_ackNeeded; /* 1 = awaiting ACK to rpt cmd */
148: unchar ft_ackMissed; /* 1 = wanted ACK, didn't get */
149: unchar ft_open; /* 1 = device is open */
150: unchar ft_refd; /* 1 = found reference burst */
151: unchar ft_useEcc; /* 1 = Reed-Solomon enabled */
152: unchar ft_useBadMap; /* 1 = use bad block map */
153:
154: /* very short ints */
155: unchar ft_pcn; /* present cylinder # */
156: unchar ft_bitsNeeded; /* # of Report Next Bit's to do */
157: unchar ft_bitsRcvd; /* # of report bits received */
158: unchar ft_drv; /* drive number, 0..3 */
159: unchar ft_fmt; /* index into ftParm */
160:
161: unchar ft_cyl; /* cylinder FDC - C */
162: unchar ft_head; /* head FDC - H */
163: unchar ft_blk; /* block FDC - R */
164: unchar ft_ssz; /* record size FDC - N */
165:
166: /* short ints */
167: ushort ft_report; /* where reported bits go */
168: ushort ft_track; /* track for next access */
169: ushort ft_phySeg; /* segment # for next access */
170:
171: /* other structs */
172: TIM ft_tim;
173: };
174:
175: /* Descriptor for a run of good blocks within a single segment. */
176: struct FtRun {
177: uint blkToRead; /* Next block wanted from current segment */
178: uint blksRead; /* Number of blocks read from this seg */
179: uint runLength; /* Number of good blocks in current run */
180: };
181:
182: /*
183: * ----------------------------------------------------------------------
184: * Functions.
185: * Import Functions.
186: * Export Functions.
187: * Local Functions.
188: */
189: extern int nulldev();
190: extern char * getDmaMem();
191:
192: /* CON entry points. */
193: static int ftblock();
194: static int ftclose();
195: static int ftioctl();
196: static int ftload();
197: static int ftopen();
198: static int ftread();
199: static int ftunload();
200: static int ftwrite();
201:
202: /* Debug routines. */
203: static void ftDbPrintCmd();
204: static void ftDbPrintErr();
205: static void ftDbPrintPos();
206: static void ftDbPrintStat();
207: static void ftDbPrtStat();
208:
209: /* Support routines. */
210: static int ftCmd();
211: static int ftCmdArg();
212: static int ftCmdSend();
213: static void ftFdcPos();
214: static int ftGetBlkRun();
215: static void ftGetInfo();
216: static void ftIrqHandler();
217: static int ftReadBlkRun();
218: static int ftReadBlks();
219: static int ftReadID();
220: static int ftReadSegs();
221: static int ftReadyWait();
222: static int ftRecal();
223: static void ftResetFDC();
224: static void ftRptBegin();
225: static void ftRptUpdate();
226: static int ftSeg();
227: static void ftSelect();
228: static int ftSkipBack();
229: static int ftSkipFwd();
230: static int ftStartTape();
231: static int ftStopTape();
232: static int ftStsWthErr();
233: static int ftWait();
234:
235: /*
236: * ----------------------------------------------------------------------
237: * Global Data.
238: * Import Variables.
239: * Export Variables.
240: * Local Variables.
241: */
242:
243: CON ftcon = {
244: DFCHR, /* Flags */
245: FL_MAJOR, /* Major index */
246: ftopen, /* Open */
247: ftclose, /* Close */
248: ftblock, /* Block */
249: ftread, /* Read */
250: ftwrite, /* Write */
251: ftioctl, /* Ioctl */
252: nulldev, /* Powerfail */
253: nulldev, /* Timeout */
254: ftload, /* Load */
255: ftunload, /* Unload */
256: nulldev /* Poll */
257: };
258:
259: /*
260: * Patchable values.
261: *
262: * FT_NBUF = number of 32 Kbyte segment buffers allocated. In the
263: * present memory model, this buffer space cannot be used for
264: * anything else, and is part of the "PhysMem" pool reserved at
265: * startup. The buffer set is attached at ftBigBuf during ftload().
266: * FT_CUSHION = number of segments we try to have between current
267: * physical position of tape when stopped and the next segment to
268: * be accessed. The cushion allows time for the tape to come up to
269: * speed.
270: */
271:
272: int FT_NBUF = 16;
273: int FT_CUSHION = 5; /* # of segs passed during start/stop */
274:
275: /* Parameters for FDC Specify Command */
276: int FT_SRT_2 = 0xE;
277: int FT_SRT_3 = 0xD;
278: int FT_HUT = 0xF;
279: int FT_HLT = 0x1;
280:
281: static struct FT ft;
282: static struct FtParm ftParm[] = {
283: /* segments/track, tracks, blocks/pseudotrack, heads, cylinders */
284: { 150, 28, 128, 7, 150 }, /* QIC-80, 307.5' */
285: { 100, 28, 128, 5, 150 }, /* QIC-80, 205' */
286: { 102, 20, 128, 2, 255 }, /* QIC-40, 307.5' */
287: { 68, 20, 128, 2, 170 } /* QIC-40, 205' */
288: };
289:
290: /*
291: * DMA store.
292: * ftBigBuf is the virtual address of an aligned, physically contiguous
293: * buffer area, FT_NBUF segments in length.
294: * ftBufBlks[s] says how many blocks (0..32) in segment s of ftBigBuf were
295: * successfully read. These blocks are contiguous, aligned at the start
296: * of segment buffer s.
297: * ftBadBlkCt[s] says how many blocks in segment s of ftBigBuf could not be
298: * read due to FDC error. This number is in the range (0..2) =
299: * (0..FT_NUM_ECC_BLKS). It gives a count of blocks that should have
300: * been read (i.e., not listed in the bad block table) and that may be
301: * recovered using ecc.
302: * ftBadBlk[s][e] is the block number in segment s where read error
303: * number e (0..2) occurred.
304: * ftSegCt is the number of segment buffers in ftBigBuf which have data.
305: * ftCurrentSeg is the segment number being read, < ftSegCt.
306: * ftOffset is byte offset within current segment for next access.
307: */
308: static unchar * ftBigBuf;
309: static unchar ftBufBlks[FT_MAX_NBUF];
310: static unchar ftBadBlkCt[FT_MAX_NBUF];
311: static unchar ftBadBlk[FT_MAX_NBUF][FT_NUM_ECC_BLKS];
312: static int ftSegCt;
313: static int ftCurrentSeg;
314: static int ftOffset;
315:
316: /* Strings where multibyte FDC commands are built. */
317:
318: unchar rwCmd[] = {
319: 0x46, /* FDC read, skip deleted data, MFM. */
320: 0, /* Head 0, unit 0. */
321: 0, /* C = FDC cylinder */
322: 0, /* H = FDC head */
323: 1, /* R = FDC block number (1-based) */
324: 3, /* N = block length (3 = 1024 bytes) */
325: 226, /* EOT = last block number on cylinder */
326: 1, /* GPL = number of bytes in gap 3 */
327: 255 /* DTL, use 0xFF when N != 0 */
328: };
329:
330: /* Read/write command bytes. */
331: enum {
332: RW_CMD_RD = 0x46,
333: RW_CMD_WR = 0x45
334: };
335:
336: /* Offsets into rwCmd. */
337: enum {
338: RW_CMD_VERB = 0,
339: RW_CMD_UNIT = 1,
340: RW_CMD_CYL = 2,
341: RW_CMD_HEAD = 3,
342: RW_CMD_SCTR = 4,
343: RW_CMD_SCSZ = 5, /* encoded block length */
344: RW_CMD_SCHI = 6, /* high block number */
345: RW_CMD_GPL = 7,
346: RW_CMD_DTL = 8,
347: RW_CMD_LEN = 9
348: };
349:
350: /*
351: * ----------------------------------------------------------------------
352: * Code.
353: */
354:
355: /*
356: * CON struct routines.
357: */
358:
359: /************************************************************************
360: * ftblock
361: *
362: * Tape is not a block device, but we need a block entry point since
363: * the same driver controls diskette access.
364: ***********************************************************************/
365: static int
366: ftblock(bp)
367: BUF *bp;
368: {
369: u.u_error = EIO;
370: bp->b_flag |= BFERR;
371: bdone(bp);
372: return;
373: }
374:
375: /************************************************************************
376: * ftclose
377: *
378: ***********************************************************************/
379: static int
380: ftclose(dev, mode)
381: dev_t dev;
382: int mode;
383: {
384: printf("ftclose ");
385:
386: setFtIntr(1);
387: if (FT_SOFT_SELECT(ft.ft_drv))
388: ftCmd(QIC_CMD_SS_OFF);
389:
390: ft.ft_open = 0;
391: setFtIntr(0);
392: }
393:
394: /*************************************************************************
395: * ftioctl
396: * Handle tape drive & controller commands like erase, rewind,
397: * retension, read filemark, and write filemark
398: ************************************************************************/
399: ftioctl(dev, cmd, arg)
400: register int dev, cmd;
401: int arg;
402: {
403: }
404:
405: /*************************************************************************
406: * ftload
407: ************************************************************************/
408: static int
409: ftload()
410: {
411: uint bigBufLen;
412:
413: if (FT_NBUF > FT_MAX_NBUF)
414: FT_NBUF = FT_MAX_NBUF;
415:
416: bigBufLen = FT_NBUF * FT_BFRSZ;
417: ftIntr = ftIrqHandler;
418: if ((ftBigBuf = getDmaMem(bigBufLen, FT_BFRSZ)) == NULL)
419: printf("ERROR - can't allocate %d bytes for ft buffers\n",
420: bigBufLen);
421: }
422:
423: /************************************************************************
424: * ftopen
425: *
426: ***********************************************************************/
427: static int
428: ftopen(dev, mode)
429: dev_t dev;
430: int mode;
431: {
432: unsigned int drvStat;
433: int i;
434: int bit;
435: int result;
436: int notReady;
437: int drvStatus;
438: int putCount;
439:
440: /* Couldn't allocate buffer area. */
441: if (ftBigBuf == NULL) {
442: devmsg(dev, "no buffers ");
443: u.u_error = EIO;
444: return;
445: }
446:
447: /* Can't append to tape. */
448: if (mode & IPAPPEND) {
449: devmsg(dev, "can't append ");
450: u.u_error = EINVAL;
451: return;
452: }
453:
454: /* Only one open at a time. */
455: if (ft.ft_open) {
456: devmsg(dev, "only one ftopen at a time ");
457: u.u_error = EBUSY;
458: return;
459: }
460: ft.ft_open = 1;
461:
462: ft.ft_drv = FT_UNIT(dev);
463:
464: if (!setFtIntr(1))
465: FT_OPEN_ERR("fdc unavailable ");
466:
467: ftIntr = ftIrqHandler;
468:
469: /* Select tape drive. */
470: ftSelect(ft.ft_drv);
471:
472: if (ftCmd(QIC_CMD_RST))
473: FT_OPEN_ERR("soft reset failed ");
474:
475: /* Need to wait a second after QIC software reset. */
476: ftWait(HZ);
477:
478: /* Re-Select tape drive (reset clears soft select). */
479: ftSelect(ft.ft_drv);
480:
481: /* HERE is the test for tape drive present. */
482: drvStatus = ftStsWthErr();
483: if (drvStatus == -1)
484: FT_OPEN_ERR("get drive status failed ");
485:
486: /* Wait for drive to be ready, or give up. */
487: if(ftReadyWait(FT_RDY_SECS))
488: FT_OPEN_ERR("Tape Drive Not Ready");
489:
490: /* Need Cartridge Present to be true. */
491: if ((ft.ft_report & QIC_STAT_PRSNT) == 0)
492: FT_OPEN_ERR("No Cartridge");
493:
494: /* Initialize state variables & such. */
495: ft.ft_refd = 0;
496: ft.ft_fmt = 0; /* 307.5' QIC-80 */
497: ft.ft_useEcc = 0; /* No ECC. Yet. */
498: ft.ft_useBadMap = 0; /* No bad block map use. Yet. */
499:
500: /* Wrap-up. */
501: fdcSpecify(FT_SRT_3, FT_HUT, FT_HLT);
502: setFtIntr(0);
503: return;
504:
505: /* Error exit. */
506: badFtOpen:
507:
508: u.u_error = EIO;
509: ft.ft_open = 0;
510: fdcSpecify(FT_SRT_3, FT_HUT, FT_HLT);
511: fdcDrvSelect(0, FDC_MOTOR_OFF);
512: if (FT_SOFT_SELECT(ft.ft_drv))
513: ftCmd(QIC_CMD_SS_OFF);
514: setFtIntr(0);
515: return;
516: }
517:
518: /************************************************************************
519: * ftread
520: *
521: * if tape not referenced
522: * seek load point
523: * wait for ready
524: * if tape still not referenced
525: * abort read - tape not formatted
526: * set next access to track 0, segment 3
527: * while more data is to be read
528: * read as much as possible into DMA buffer area
529: * abort in case of read error
530: * iowrite() - copy DMA buffers into user space
531: ***********************************************************************/
532: static int
533: ftread(dev, iop)
534: dev_t dev;
535: IO * iop;
536: {
537: #if 0
538: unchar drvStatus;
539: uint calTries;
540: int segsWanted;
541: unchar * bufPtr;
542: int i;
543: int bytesInBuffer;
544: int dataBlksPerSeg;
545: int dataBytesPerSeg;
546:
547: /* Has reference burst been seen? */
548: drvStatus = ftStsWthErr();
549: if (drvStatus == -1)
550: FT_READ_ERR("get drive status failed ");
551:
552: /*
553: * If not, look for reference burst now.
554: * If this fails, it's probably due to unformatted tape.
555: */
556: if ((drvStatus & QIC_STAT_REFD) == 0) {
557: ftCmd(QIC_CMD_CAL);
558: if (ftReadyWait(FT_CAL_SECS))
559: FT_READ_ERR("seek load point failed");
560:
561: /* Again, has reference burst been seen? */
562: drvStatus = ftStsWthErr();
563: if (drvStatus == -1)
564: FT_READ_ERR("get drive status failed ");
565:
566: if ((drvStatus & QIC_STAT_REFD) == 0)
567: FT_READ_ERR("seek load point failed");
568:
569: /* Initialize access coordinates for next read. */
570: ft.ft_track = FT_INITIAL_TRACK;
571: ft.ft_phySeg = FT_INITIAL_PHY_SEG;
572: }
573:
574: /*
575: * Compute expected number of data blocks, and bytes, in a segment.
576: * This is an estimate, as it does not consider bad blocks that are
577: * mapped out.
578: */
579: dataBlksPerSeg = FT_BLK_PER_SEG;
580: if (ft.ft_useEcc)
581: dataBlksPerSeg -= FT_NUM_ECC_BLKS;
582: dataBytesPerSeg = dataBlksPerSeg * FT_BLKSZ;
583:
584: /*
585: * While there is input needed
586: * If DMA buffer is used up
587: * Load DMA buffer area from tape.
588: * Update DMA buffer stats:
589: * Number of valid segments = number of segments read
590: * Current segment and current offset both = 0
591: * Transfer data:
592: * Source is DMA buffer, current segment and offset.
593: * Destination is IO struct.
594: * Update DMA buffer current segment and offset.
595: */
596: while (iop->io_ioc) {
597:
598: /* Do we need to fill DMA buffer from tape? */
599: if (ftCurrentSeg >= ftSegCt) {
600:
601: /* Estimate how many segments will need to be read. */
602: segsWanted = FT_DIV_RU(iop->io_ioc, dataBytesPerSeg);
603:
604: /* Try to fill DMA buffer area. */
605: ftSegCt = ftReadSegs(segsWanted);
606:
607: /* Update current DMA data pointer. */
608: ftCurrentSeg = 0;
609: ftOffset = 0;
610:
611: /* Abort read if something went wrong. */
612: if (ftSegCt == -1)
613: FT_READ_ERR("ftBufRead failed");
614:
615: /* Terminate read if at end of tape. */
616: if (ftSegCt == 0)
617: break;
618:
619: /* HERE is where ecc will be done. */
620: /* This will involve decrementing ftBufBlks[?] by 3. */
621: }
622:
623: XXX
624: /* Transfer data from DMA buffer to IO area. */
625: while
626: for (i = 0, bufPtr = ftCurrentSeg;
627: bufPtr += FT_BFRSZ, i < ftSegCt; i++) {
628:
629: bytesInBuffer = ftBufBlks[i] * FT_BLKSZ;
630: if (bytesInBuffer != 0) {
631:
632: int transferCount = iop->io_ioc;
633:
634: if (transferCount > bytesInBuffer)
635: transferCount = bytesInBuffer;
636:
637: /* May transfer less than a segment. */
638: if (bytesInBuffer > iop->io_ioc)
639: bytesInBuffer = iop->io_ioc;
640: iowrite(iop, bufPtr, bytesInBuffer);
641: }
642: }
643: }
644:
645: return;
646:
647: badFtRead:
648: SET_U_ERROR(EIO, "ftread");
649: return;
650: #endif
651: }
652:
653: /************************************************************************
654: * ftunload
655: *
656: ***********************************************************************/
657: static int
658: ftunload()
659: {
660: }
661:
662: /************************************************************************
663: * ftwrite
664: *
665: ***********************************************************************/
666: static int
667: ftwrite(dev, iop)
668: dev_t dev;
669: IO * iop;
670: {
671: if (!ft.ft_open) { /* exit if not open */
672: u.u_error = EIO;
673: return;
674: }
675: }
676:
677: /*********************
678: **********************
679: **
680: ** Support routines.
681: **
682: **********************
683: **********************/
684:
685: /************************************************************************
686: * ftCmd
687: *
688: * Given a QIC-117 command number, send the command.
689: * If report bits are expected in response, initialize the bit counter.
690: * Then sleep until the commmand is done and report bits are gathered.
691: ***********************************************************************/
692: static int
693: ftCmd(cmd)
694: int cmd;
695: {
696: int bitsNeeded;
697:
698: if (cmd != QIC_CMD_STS)
699: printf("[%d]", cmd);
700:
701: /* Will sleep until command done and report bits are in. */
702: ft.ft_wakeMeUp = 1;
703:
704: /*
705: * The following commands expect report bits from the tape drive.
706: * After receiving the QIC command (and subsequent delay),
707: * the drive sends a leading ACK bit (always 1). This bit is
708: * not counted in the numbers below.
709: * Subseqeunt bits are sent in response to Report Next Bit,
710: * least significant bit first, then a trailing 1.
711: * The value of bitsNeeded is either one more than the number of
712: * data bits in the report, or zero.
713:
714: */
715: switch(cmd) {
716: case QIC_CMD_STS:
717: case QIC_CMD_DRVCN:
718: case QIC_CMD_ROMVN:
719: case QIC_CMD_TPSTAT:
720: bitsNeeded = 9;
721: break;
722: case QIC_CMD_ECD:
723: case QIC_CMD_VNDID:
724: bitsNeeded = 17;
725: break;
726: default:
727: bitsNeeded = 0;
728: }
729: ftRptBegin(bitsNeeded);
730: ft.ft_ackMissed = 0;
731:
732: ftCmdSend(cmd);
733:
734: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftCmd")) {
735: if (FT_BLAB)
736: printf("sig to cmd %d ", cmd);
737: /* Signal woke us prematurely. */
738: return -1;
739: } else if (ft.ft_ackMissed) {
740: if (FT_BLAB)
741: printf(" Ack missed ");
742: ft.ft_ackMissed = 0;
743: return -1;
744: } else
745: return 0;
746: }
747:
748: /************************************************************************
749: * ftCmdArg
750: *
751: * Like ftCmd, except this routine sends command arguments.
752: * No setup for report next bit.
753: * Different debug print handling.
754: ***********************************************************************/
755: static int
756: ftCmdArg(arg)
757: int arg;
758: {
759: int bitsNeeded;
760:
761: printf("(%d)", arg);
762:
763: /* Will sleep until stepper pulses sent. */
764: ft.ft_wakeMeUp = 1;
765:
766: bitsNeeded = 0;
767: ftRptBegin(bitsNeeded);
768: ft.ft_ackMissed = 0;
769:
770: ftCmdSend(arg);
771:
772: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftArg")) {
773:
774: /* Signal woke us prematurely. */
775: printf("sig to arg %d ", arg);
776:
777: return -1;
778: } else
779: return 0;
780: }
781:
782: /************************************************************************
783: * ftCmdSend
784: *
785: * Given a QIC-117 command number, cause that number of step pulses
786: * to be sent from the FDC by faking a seek command.
787: ***********************************************************************/
788: static int
789: ftCmdSend(cmd)
790: int cmd;
791: {
792: /* ncn = new cylinder #. */
793: unsigned char ncn;
794:
795: /*
796: * Will fake a seek command.
797: * Figure out whether to simulate seek to lower or higher
798: * cylinder number.
799: */
800: if (ft.ft_pcn >= cmd)
801: ncn = ft.ft_pcn - cmd;
802: else
803: ncn = ft.ft_pcn + cmd;
804:
805: fdcSeek(ft.ft_drv, 0, ncn);
806: }
807:
808: /************************************************************************
809: * ftFdcPos()
810: *
811: * Given track relative segment within the tape track, and relative block
812: * within the segment, store C/H/R (cylinder/head/record) diskette pseudo
813: * coordinates into 3-element unchar array given.
814: ***********************************************************************/
815: static void
816: ftFdcPos(track, segment, block, cmdTbl)
817: int track, segment;
818: unchar * cmdTbl;
819: {
820: }
821:
822: /************************************************************************
823: * ftGetBlkRun()
824: *
825: * Given the next block desired from the current segment, get starting
826: * block number and number of blocks in next run of consecutive good
827: * blocks.
828: * This routine checks the bad block map for the cartridge, if this
829: * feature is enabled.
830: * We are at a lower level than ecc, so all 32 blocks in a segment are
831: * considered. Ecc, if enabled, will be applied to the results of
832: * run-level processing.
833: * Return 0 if a run can be found, -1 if no further run of good blocks
834: * exists in the current segment.
835: ***********************************************************************/
836: static int
837: ftGetBlkRun(ftrp)
838: struct FtRun * ftrp;
839: {
840: int retval;
841:
842: if (ft.ft_useBadMap) {
843: printf("Bad block map not enabled yet.\n");
844: /* Will modify blkToRead and runLength fields here. */
845: retval = -1;
846: } else {
847: if (ftrp->blkToRead < FT_BLK_PER_SEG) {
848: ftrp->runLength = FT_BLK_PER_SEG - ftrp->blkToRead;
849: retval = -1;
850: } else
851: retval = 0;
852: }
853: return retval;
854: }
855:
856: /************************************************************************
857: * ftGetInfo
858: *
859: * Issue several QIC report commands - all but Report Drive Status
860: * and Report Error Code.
861: ***********************************************************************/
862: static void
863: ftGetInfo(dev)
864: dev_t dev;
865: {
866: if (ftCmd(QIC_CMD_DRVCN))
867: devmsg(dev, "Warning: get drive configuration failed");
868: else
869: devmsg(dev, "Drive Configuration = %x", ft.ft_report);
870:
871: if (ftCmd(QIC_CMD_ROMVN))
872: devmsg(dev, "Warning: get ROM version failed");
873: else
874: devmsg(dev, "Rom Version = 0x%x", ft.ft_report);
875:
876: if (ftCmd(QIC_CMD_VNDID))
877: devmsg(dev, "Warning: get vendor ID failed");
878: else
879: devmsg(dev, "Vendor ID = 0x%x", ft.ft_report);
880:
881: if (ftCmd(QIC_CMD_TPSTAT))
882: devmsg(dev, "Warning: get tape status failed");
883: else
884: devmsg(dev, "Tape Status = 0x%x", ft.ft_report);
885: }
886:
887: /************************************************************************
888: * ftIrqHandler
889: *
890: * Interrupt handler.
891: ***********************************************************************/
892: static void
893: ftIrqHandler()
894: {
895: int i, bit;
896:
897: /*
898: * Need to get FDC status from result phase - fdcCmdStatus -
899: * or clear interrupt - fdcIntStatus - that may have been
900: * generated by diskette change or seek/recal complete.
901: */
902: if (FDC_BUSY()) {
903: fdcCmdStatus();
904: } else {
905: fdcIntStatus();
906: /* WARNING - should squawk if wrong number of status bytes. */
907: ft.ft_pcn = fdc.fdc_intstat[1];
908: }
909:
910: /* If ACK needed, try several times to get it. */
911: if (ft.ft_ackNeeded) {
912: for (i = 0; i < FT_ACK_TRIES; i++) {
913: fdcDrvStatus(ft.ft_drv, FDC_HEAD_0);
914: fdcCmdStatus();
915: bit = (fdc.fdc_cmdstat[0] & ST3_T0) ? 1 : 0;
916: if (FT_ACKBLAB)
917: putchar(bit?'|':'o');
918: if (bit) {
919: ft.ft_ackNeeded = 0;
920: break;
921: }
922: /* Wait about 20 usec. then try again. */
923: busyWait2(NULL, 20);
924: }
925:
926: /*
927: * Tape Drive did not send ACK in response to QIC
928: * Report command. Probably the command is not
929: * supported by this drive, or there is no drive
930: * present. Set ackMissed flag and clean up.
931: */
932: if (ft.ft_ackNeeded) {
933: ft.ft_ackNeeded = 0;
934: ft.ft_ackMissed = 1;
935: ft.ft_bitsNeeded = 0;
936: if (ft.ft_wakeMeUp) {
937: ft.ft_wakeMeUp = 0;
938: wakeup(&ft.ft_wakeMeUp);
939: }
940: }
941: } else if (ft.ft_bitsNeeded) {
942:
943: /* Report bits are needed. Get ST3. */
944: fdcDrvStatus(ft.ft_drv, FDC_HEAD_0);
945: fdcCmdStatus();
946:
947: /* Get next report bit by checking Track Zero bit in ST3 */
948: if (fdc.fdc_ncmdstat == 1) {
949: int bit;
950:
951: bit = (fdc.fdc_cmdstat[0] & ST3_T0) ? 1 : 0;
952: ftRptUpdate(bit);
953: } else {
954: printf("rnb status bad ");
955: }
956: }
957:
958: /*
959: * If more report bits will be needed
960: * Send request for next bit.
961: * Else
962: * See if original requestor needs wakeup, etc.
963: */
964: if (ft.ft_bitsNeeded) {
965: ftCmdSend(QIC_CMD_RNB);
966: } else {
967: if (ft.ft_wakeMeUp) {
968: ft.ft_wakeMeUp = 0;
969: wakeup(&ft.ft_wakeMeUp);
970: }
971:
972: /* Print debug output if needed. */
973: if (ft.ft_dumpIrq) {
974: ft.ft_dumpIrq = 0;
975: defer(ftDbPrtStat);
976: }
977: }
978: }
979:
980: /***********************************************************************
981: * ftRead1Seg
982: *
983: * Given buffer number (0..FT_NBUF-1), try to read the next segment
984: * into that segment buffer in ftBigBuf DMA area.
985: * Set ftBufBlks[bufn] to the number of blocks not marked bad.
986: * Valid blocks are deposited contiguously starting at the beginning of
987: * segment buffer[bufn].
988: *
989: * Tape should be in properly positioned and in motion when this
990: * function is called.
991: *
992: * Initialize number of blocks read to 0, in local counter and in buffer
993: * table.
994: * Initialize number of next tape block (relative to start of segment)
995: * to read to 0.
996: * Loop
997: * Check bad block map (if using bad block map) to find the next run
998: * of readable blocks, if any, in the current segment.
999: * If there are no further runs of good blocks in the current segment
1000: * Exit loop.
1001: * Try to read the next run of blocks.
1002: * If successful, this will:
1003: * Increment number of blocks read by length of current run.
1004: * Update the number of the next block to read.
1005: * If too many read failures (> 3 if ecc, > 0 if no ecc)
1006: * Return -1 (segment read failed).
1007: * Endloop
1008: *
1009: * Store number of blocks read into ftBufBlks table.
1010: * Update current segment and track numbers. (Advance to next segment.)
1011: * Return 0 (success).
1012: ***********************************************************************/
1013: static int
1014: ftRead1Seg(bufn)
1015: uint bufn;
1016: {
1017: struct FtRun ftRun;
1018: struct FtParm *fp;
1019:
1020: /* Get parameter set pointer. */
1021: fp = ftParm + ft.ft_fmt;
1022:
1023: ftBufBlks[bufn] = 0;
1024: ftRun.blksRead = 0;
1025:
1026: ftRun.blkToRead = 0;
1027:
1028: for (;;) {
1029: if (ftGetBlkRun(&ftRun))
1030: break;
1031: if (ftReadBlkRun(&ftRun, bufn))
1032: return -1;
1033: }
1034:
1035: ftBufBlks[bufn] = ftRun.blksRead;
1036:
1037: ft.ft_phySeg++;
1038: if (ft.ft_phySeg == fp->segPerTrk
1039: && ft.ft_track <= (fp->tracks - 1)) {
1040: ft.ft_track++;
1041: ft.ft_phySeg = 0;
1042: }
1043:
1044: return 0;
1045: }
1046:
1047: /***********************************************************************
1048: * ftReadID
1049: *
1050: * Send FDC Read ID command and store results in ft context.
1051: * Return 0 on success, -1 on failure (signal).
1052: *
1053: * Of principal interest is fdc.fdc_cmdstat[5] - present block number.
1054: ***********************************************************************/
1055: static int
1056: ftReadID()
1057: {
1058: ft.ft_wakeMeUp = 1;
1059: fdcReadID(ft.ft_drv, 0);
1060: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftReadID"))
1061: return -1;
1062: else {
1063: if (fdc.fdc_ncmdstat != 7) {
1064: printf("ftReadID bad command status: %d",
1065: fdc.fdc_ncmdstat);
1066: return -1;
1067: } else {
1068: ft.ft_cyl = fdc.fdc_cmdstat[3];
1069: ft.ft_head = fdc.fdc_cmdstat[4];
1070: ft.ft_blk = fdc.fdc_cmdstat[5];
1071: ft.ft_ssz = fdc.fdc_cmdstat[6];
1072: }
1073: return 0;
1074: }
1075: }
1076:
1077: /***********************************************************************
1078: * ftReadSegs()
1079: *
1080: * Given a segment count, try to read the given number of segments from
1081: * the curent track.
1082: * Return the number of segments read (0 if at end of tape), -1 if failure.
1083: *
1084: * Reading a segment may yield from 0 to 32 blocks, depending on how
1085: * many bad blocks are marked in the segment and whether ecc is used.
1086: ***********************************************************************/
1087: static int
1088: ftReadSegs(segsWanted)
1089: uint segsWanted;
1090: {
1091: int segsOnTrack;
1092: int segsRead;
1093: struct FtParm *fp;
1094:
1095: /* Get parameter set pointer. */
1096: fp = ftParm + ft.ft_fmt;
1097:
1098: /*
1099: * Calculate how many segments are left on the current track.
1100: * If no segments left on current track
1101: * Return no segments read.
1102: */
1103: segsOnTrack = fp->segPerTrk - ft.ft_phySeg;
1104: if (segsOnTrack == 0)
1105: return 0;
1106:
1107: /*
1108: * Will do a multisegment read.
1109: * Requested number of segments will be the least of:
1110: * - number of segments wanted
1111: * - number of segments there is room for in DMA area
1112: * - number of segments remaining on current tape track
1113: */
1114: if (segsWanted > FT_NBUF)
1115: segsWanted = FT_NBUF;
1116: if (segsWanted > segsOnTrack)
1117: segsWanted = segsOnTrack;
1118:
1119: /*
1120: * Try to position and start tape.
1121: * Read as many segments as possible.
1122: * If there is an irrecoverable read error
1123: * Abort multisegment read.
1124: * Stop tape.
1125: */
1126: if (ftStartTape())
1127: return -1;
1128: for (segsRead = 0; segsRead < segsWanted; segsRead++) {
1129: if (ftRead1Seg(segsRead)) {
1130: segsRead = -1;
1131: break;
1132: }
1133: }
1134: ftStopTape();
1135:
1136: /* Return the number of segments successfully read. */
1137: return segsRead;
1138: }
1139:
1140: /***********************************************************************
1141: * ftReadyWait
1142: *
1143: * Keep checking drive status every second until drive is ready or
1144: * the specified number of seconds has elapsed.
1145: * Return 0 if drive ready, -1 if timeout or signal or protocol failure.
1146: ***********************************************************************/
1147: static int
1148: ftReadyWait(seconds)
1149: uint seconds;
1150: {
1151: uint i;
1152: int retval = -1;
1153: int drvStatus;
1154:
1155: for (i = 0; i < seconds; i++) {
1156: drvStatus = ftStsWthErr();
1157:
1158: /* Protocol failure? */
1159: if (drvStatus == -1)
1160: break;
1161:
1162: /* Drive ready? Change return value to show success. */
1163: if (drvStatus & QIC_STAT_RDY) {
1164: retval = 0;
1165: break;
1166: }
1167:
1168: /* Signal arrived while waiting a second? */
1169: if (ftWait(HZ))
1170: break;
1171: }
1172:
1173: return retval;
1174: }
1175:
1176: /************************************************************************
1177: * ftRecal
1178: *
1179: * Send Recalibrate command to FDC and wait for it to finish.
1180: * Return 0 if normal operation, -1 if signaled before recal complete.
1181: ***********************************************************************/
1182: static int
1183: ftRecal()
1184: {
1185: ft.ft_wakeMeUp = 1;
1186: fdcRecal(ft.ft_drv);
1187: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRecal"))
1188: return -1;
1189: else
1190: return 0;
1191: }
1192:
1193: /************************************************************************
1194: * ftResetFDC
1195: *
1196: * Reset the FDC and wait for the resulting interrupt.
1197: * Reset is done keeping the current unit selected.
1198: ***********************************************************************/
1199: static void
1200: ftResetFDC()
1201: {
1202: /*
1203: * Since FDC reset generates an interrupt, we need to tell the
1204: * interrupt handler there will be *no* report bits incoming.
1205: */
1206: ftRptBegin(0);
1207:
1208: ft.ft_pcn = 0;
1209: ft.ft_wakeMeUp = 1;
1210: fdcResetSel(FT_DRIVE(ft.ft_drv), FT_MOTOR(ft.ft_drv));
1211: x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRstFDC");
1212: }
1213:
1214: /************************************************************************
1215: * ftRptBegin
1216: *
1217: * Initialize ft state information in preparation for QIC report command.
1218: *
1219: * Argument "bitCount" is the total number of bits expected, including
1220: * initial ACK and final TRUE. It is 1 more than the number of
1221: * Report Next Bit Commands that will be issued.
1222: ***********************************************************************/
1223: static void
1224: ftRptBegin(bitCount)
1225: int bitCount;
1226: {
1227: ft.ft_bitsNeeded = bitCount;
1228: ft.ft_bitsRcvd = 0;
1229: ft.ft_report = 0;
1230: ft.ft_ackNeeded = (bitCount) ? 1 : 0;
1231: }
1232:
1233: /************************************************************************
1234: * ftSeg()
1235: *
1236: * Given pseudo cylinder, head, and block numbers from FDC,
1237: * calculate the segment number relative to start of current track.
1238: ***********************************************************************/
1239: static int
1240: ftSeg(c, h, r)
1241: int c, h, r;
1242: {
1243: int lsn; /* Logical block (not segment) number. */
1244: int seg;
1245: struct FtParm *fp;
1246:
1247: /* Get parameter set pointer. */
1248: fp = ftParm + ft.ft_fmt;
1249:
1250: /* Compute logical block number. */
1251: lsn = (r - 1) + c * fp->blkPerTrk + h * fp->blkPerTrk * fp->cyls;
1252:
1253: /* Divide with truncation to get containing segment number. */
1254: seg = lsn / FT_BLK_PER_SEG;
1255:
1256: /* Compute segment number relative to start of track. */
1257: seg %= fp->segPerTrk;
1258:
1259: return seg;
1260: }
1261:
1262: /************************************************************************
1263: * ftRptUpdate
1264: *
1265: * Acquire another bit for QIC report command.
1266: * Last bit is discarded. Other bits are accumulated,
1267: * least significant bit first, into ft_report.
1268: ***********************************************************************/
1269: static void
1270: ftRptUpdate(bit)
1271: int bit;
1272: {
1273: ft.ft_bitsNeeded--;
1274: ft.ft_bitsRcvd++;
1275:
1276: if (ft.ft_bitsNeeded == 0) {
1277: if (bit != 1)
1278: printf("Missing final TRUE ");
1279: } else {
1280: ft.ft_report |= (bit << (ft.ft_bitsRcvd - 1));
1281: }
1282: }
1283:
1284: /************************************************************************
1285: * ftSelect
1286: *
1287: * Select tape unit.
1288: ***********************************************************************/
1289: static void
1290: ftSelect()
1291: {
1292: fdcRate(FDC_RATE_500K);
1293: fdcDrvSelect(FT_DRIVE(ft.ft_drv), FT_MOTOR(ft.ft_drv));
1294:
1295: /* Reset FDC and Initialize pseudo cylinder number for QIC commands. */
1296: ftResetFDC(ft.ft_drv);
1297:
1298: fdcSpecify(FT_SRT_2, FT_HUT, FT_HLT);
1299:
1300: if (FT_SOFT_SELECT(ft.ft_drv)) {
1301: ftCmd(77);
1302: ftWait(2);
1303: ftCmd(QIC_CMD_SS1);
1304: ftWait(2);
1305: ftCmd(QIC_CMD_SS2);
1306: ftWait(2);
1307: }
1308:
1309: #if 0
1310: /* 80 MB nseg_p_track = 100, nseg_p_head = 600, nseg_p_cyl = 4 */
1311: /* 40 MB nseg_p_track = 68, nseg_p_head = 680, nseg_p_cyl = 4 */
1312: if (ftfmt) {
1313: nseg_p_track = 100; /* set for 80 MB drive */
1314: nseg_p_head = 600;
1315: nseg_p_cyl = 4;
1316: } else {
1317: nseg_p_track = 68; /* set for 40 MB drive */
1318: nseg_p_head = 680;
1319: nseg_p_cyl = 4;
1320: }
1321: #endif
1322: }
1323:
1324: /************************************************************************
1325: * ftSkipBack()
1326: *
1327: * Skip segments in logical backward direction.
1328: * Return 0 on success, -1 on failure.
1329: ***********************************************************************/
1330: static int
1331: ftSkipBack(segCount)
1332: uint segCount;
1333: {
1334: /* If possible, use short (non-extended) form of skip command. */
1335: if ((segCount & ~0xFF) == 0) {
1336: if (ftCmd(QIC_CMD_SKPB))
1337: return -1;
1338: ftCmdArg((segCount & 0xF) +2);
1339: ftCmdArg((segCount >> 4) +2);
1340: } else {
1341: if (ftCmd(QIC_CMD_SKPBX))
1342: return -1;
1343: ftCmdArg((segCount & 0xF) +2);
1344: ftCmdArg(((segCount >> 4) & 0xF) +2);
1345: ftCmdArg(((segCount >> 8) & 0xF) +2);
1346: }
1347: }
1348:
1349: /************************************************************************
1350: * ftSkipFwd()
1351: *
1352: * Skip segments in logical forward direction.
1353: * Return 0 on success, -1 on failure.
1354: ***********************************************************************/
1355: static int
1356: ftSkipFwd(segCount)
1357: int segCount;
1358: {
1359: /* If possible, use short (non-extended) form of skip command. */
1360: if ((segCount & ~0xFF) == 0) {
1361: if (ftCmd(QIC_CMD_SKPF))
1362: return -1;
1363: ftCmdArg((segCount & 0xF) +2);
1364: ftCmdArg((segCount >> 4) +2);
1365: } else {
1366: if (ftCmd(QIC_CMD_SKPFX))
1367: return -1;
1368: ftCmdArg((segCount & 0xF) +2);
1369: ftCmdArg(((segCount >> 4) & 0xF) +2);
1370: ftCmdArg(((segCount >> 8) & 0xF) +2);
1371: }
1372: }
1373:
1374: /************************************************************************
1375: * ftStartTape
1376: *
1377: * Try to get tape into position to read next segment of interest, then
1378: * put tape in motion.
1379: *
1380: * Return 0 on success.
1381: * Return -1 on failure and make sure tape is stopped.
1382: *
1383: * Seek head to current track.
1384: * Wait for drive ready.
1385: * If trying to read first segment of any track
1386: * If even track
1387: * Rewind tape.
1388: * Else (odd track)
1389: * Full forward tape.
1390: * Wait for drive ready.
1391: * Logical forward.
1392: * Else (reading after first segment)
1393: * Pause. (Backs up a couple segments.)
1394: * Wait for drive ready.
1395: * While (not in position)
1396: * Logical forward.
1397: * Read segment ID.
1398: * If current segment >= desired segment
1399: * Compute skip count.
1400: * Skip back some number of segments.
1401: * Wait for drive ready.
1402: * Else if current segment << desired segment
1403: * Compute skip count.
1404: * Skip forward some number of segments.
1405: * Wait for drive ready.
1406: * Else tape is in position.
1407: * Endwhile
1408: ***********************************************************************/
1409: static int
1410: ftStartTape()
1411: {
1412: int tries;
1413: int notInPlace;
1414: unchar currentSeg;
1415: int skipCount;
1416:
1417: ftCmd(QIC_CMD_SEEK);
1418: ftCmdArg(2);
1419: if(ftReadyWait(FT_SEEK_SECS))
1420: return -1;
1421:
1422: if (ft.ft_phySeg == 0) {
1423: if ((ft.ft_track & 1) == 0)
1424: ftCmd(QIC_CMD_BOT);
1425: else
1426: ftCmd(QIC_CMD_EOT);
1427: if(ftReadyWait(FT_WIND_SECS))
1428: return -1;
1429: ftCmd(QIC_CMD_FWD);
1430: } else {
1431: ftCmd(QIC_CMD_PAUS);
1432: if(ftReadyWait(FT_PAUSE_SECS))
1433: return -1;
1434:
1435: notInPlace = 1;
1436: for (tries = 0; tries < 4 && notInPlace; tries++) {
1437: ftCmd(QIC_CMD_FWD);
1438: if (ftReadID())
1439: continue; /* Will try again. */
1440: currentSeg = ftSeg(fdc.fdc_cmdstat[3],
1441: fdc.fdc_cmdstat[4], fdc.fdc_cmdstat[5]);
1442: if (currentSeg >= ft.ft_phySeg) {
1443: skipCount = currentSeg - ft.ft_phySeg
1444: + FT_CUSHION;
1445: ftSkipBack(skipCount);
1446: } else if (currentSeg < ft.ft_phySeg - FT_CUSHION) {
1447: skipCount = ft.ft_phySeg - currentSeg
1448: - FT_CUSHION;
1449: ftSkipFwd(skipCount);
1450: } else
1451: notInPlace = 0;
1452: } /* end for */
1453: }
1454:
1455: if (notInPlace) {
1456: ftStopTape();
1457: return -1;
1458: }
1459:
1460: return 0;
1461: }
1462:
1463: /************************************************************************
1464: * ftStopTape
1465: *
1466: * Send QIC stop tape command, then sleep til drive ready.
1467: * Return 0 if success, 1 if timed out before sensing drive ready.
1468: ***********************************************************************/
1469: static int
1470: ftStopTape()
1471: {
1472: /* Stop, wait for ready. */
1473: ftCmd(QIC_CMD_STOP);
1474: return ftReadyWait(15);
1475: }
1476:
1477: /************************************************************************
1478: * ftStsWthErr
1479: *
1480: * Do Report Drive Status.
1481: * If error detected, to Report Error Code.
1482: * Uses sleep, so may not be used in timeout/interrupt/load/unload, etc.
1483: * Return status if ok, -1 on protocol failure.
1484: ***********************************************************************/
1485: static int
1486: ftStsWthErr()
1487: {
1488: int retval;
1489:
1490: if (ftCmd(QIC_CMD_STS))
1491: return -1;
1492:
1493: retval = ft.ft_report;
1494:
1495: if (FT_BLAB)
1496: ftDbPrintStat(ft.ft_report);
1497:
1498: if (ft.ft_report & QIC_STAT_ERR) {
1499: if (ftCmd(QIC_CMD_ECD))
1500: return -1;
1501: ftDbPrintErr(ft.ft_report);
1502: }
1503: return retval;
1504: }
1505:
1506: /************************************************************************
1507: * ftWait
1508: *
1509: * Wait the specified number of ticks.
1510: * Return 0 if full wait occurs, -1 if signaled.
1511: * Uses sleep, so may not be used in timeout/interrupt/load/unload, etc.
1512: ***********************************************************************/
1513: static int
1514: ftWait(ticks)
1515: uint ticks;
1516: {
1517: timeout(&ft.ft_tim, ticks, wakeup, &ft.ft_wakeMeUp);
1518: return x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftWait");
1519: }
1520:
1521: /*********************
1522: **********************
1523: **
1524: ** Debug Area.
1525: **
1526: **********************
1527: **********************/
1528:
1529: static char *qicErr[] = {
1530: "NULL err",
1531: "command received while drive not ready",
1532: "cartridge not present or removed",
1533: "motor speed error (not within 1%)",
1534: "motor speed fault (jammed, or gross speed error)",
1535: "cartridge write protected",
1536: "undefined or reserved command code",
1537: "illegal track address specified for seek",
1538: "illegal command in report subcontext",
1539: "illegal entry into a diagnostic mode",
1540: "broken tape detected (based on hole sensor)",
1541: "warning - read gain setting error",
1542: "command received while error status pending (obsolete)",
1543: "command received while new cartridge pending",
1544: "command illegal or undefined in primary mode",
1545: "command illegal or undefined in format mode",
1546: "command illegal or undefined in verify mode",
1547: "logical forward not at logical BOT in format mode",
1548: "logical EOT before all segments generated",
1549: "command illegal when cartridge not referenced",
1550: "self-diagnostic failed (cannot be cleared)",
1551: "warning EEPROM not initialized, defaults set",
1552: "EEPROM corrupt or hardware failure",
1553: "motion timeout error",
1554: "data segment too long - logical forward or pause",
1555: "transmit overrun (obsolete)",
1556: "power on reset occurred",
1557: "software reset occurred",
1558: "diagnostic mode 1 error",
1559: "diagnostic mode 2 error",
1560: "command received during noninterruptible process",
1561: "rate selection error",
1562: "illegal command while in high speed mode",
1563: "illegal seek segment value"
1564: };
1565:
1566: static char *qicStat[] = {
1567: "drive ready or idle",
1568: "error detected",
1569: "cartridge present",
1570: "cartridge write protected",
1571: "new cartridge",
1572: "cartridge referenced",
1573: "at physical BOT",
1574: "at physical EOT"
1575: };
1576:
1577: static char *qicCmd[] = {
1578: "NULL cmd",
1579: "soft reset",
1580: "report next bit",
1581: "pause",
1582: "micro step pause",
1583: "alternate command timeout",
1584: "report drive status",
1585: "report error code",
1586: "report drive configuration",
1587: "report ROM version",
1588: "logical forward",
1589: "physical reverse",
1590: "physical forward",
1591: "seek head to track",
1592: "seek load point",
1593: "enter format mode",
1594: "write reference burst",
1595: "enter verify mode",
1596: "stop tape",
1597: "reserved (19)",
1598: "reserved (20)",
1599: "micro step head up",
1600: "micro step head down",
1601: "reserved (23)",
1602: "reserved (24)",
1603: "skip n segments reverse",
1604: "skip n segments forward",
1605: "select rate",
1606: "enter diag mode 1",
1607: "enter diag mode 2",
1608: "enter primary mode",
1609: "reserved (31)",
1610: "report vendor ID",
1611: "report tape status",
1612: "skip n segments extended reverse",
1613: "skip n segments extended forward"
1614: };
1615:
1616: /* print command as [command] */
1617: static void
1618: ftDbPrintCmd(cmd)
1619: unsigned int cmd;
1620: {
1621: if (cmd >= 1 && cmd < sizeof(qicCmd)/sizeof(qicCmd[0])) {
1622: if (cmd != QIC_CMD_RNB)
1623: printf("[%s] ", qicCmd[cmd]);
1624: } else
1625: printf("[%x] ", cmd);
1626: }
1627:
1628: /* print 2-byte error status as <error-code,command> */
1629: static void
1630: ftDbPrintErr(errword)
1631: unsigned int errword;
1632: {
1633: unsigned int lo, hi;
1634:
1635: lo = errword & 0xff;
1636: hi = (errword >> 8) & 0xff;
1637:
1638: if (lo >= 1 && lo < sizeof(qicErr)/sizeof(qicErr[0]))
1639: printf("<%s,", qicErr[lo]);
1640: else
1641: printf("<%x,", lo);
1642:
1643: if (hi >= 1 && hi < sizeof(qicCmd)/sizeof(qicCmd[0]))
1644: printf("%s> ", qicCmd[hi]);
1645: else
1646: printf("%x> ", hi);
1647: }
1648:
1649: /* print current FDC position as C= H= R= N=. */
1650: static void
1651: ftDbPrintPos()
1652: {
1653: printf("C=%d H=%d R=%d N=%d ",
1654: ft.ft_cyl, ft.ft_head, ft.ft_blk, ft.ft_ssz);
1655: }
1656:
1657: /* print tape status as { status string,... } */
1658: static void
1659: ftDbPrintStat(stat)
1660: unsigned int stat;
1661: {
1662: int i;
1663:
1664: printf("{ ");
1665: for (i = 0; i < 8; i++) {
1666: if (stat & (1 << i))
1667: printf("%s, ", qicStat[i]);
1668: }
1669: putchar('}');
1670: }
1671:
1672: /************************************************************************
1673: * ftDbPrtStat
1674: *
1675: * For debugging, print command status and interrupt status to console.
1676: ***********************************************************************/
1677: static void
1678: ftDbPrtStat()
1679: {
1680: int i;
1681:
1682: printf("[[");
1683: if (fdc.fdc_ncmdstat) {
1684: printf("cmd ");
1685: for (i = 0; i < fdc.fdc_ncmdstat; i++)
1686: printf("%x ", fdc.fdc_cmdstat[i]);
1687: }
1688: if (fdc.fdc_nintstat) {
1689: printf("int ");
1690: for (i = 0; i < fdc.fdc_nintstat; i++)
1691: printf("%x ", fdc.fdc_intstat[i]);
1692: }
1693: printf("]] ");
1694: }
1695:
1696: #if defined(FT_DEAD_CODE)
1697: /*********************
1698: **********************
1699: **
1700: ** Test Read of Segment 0.
1701: **
1702: **********************
1703: **********************/
1704: FT_BLAB = 0;
1705:
1706: #if 0
1707: /* Rewind, wait until ready. */
1708: ftCmd(QIC_CMD_BOT);
1709: if(ftReadyWait(15)) {
1710: printf("Not ready after rewind ");
1711: goto rd0done;
1712: }
1713:
1714: /* Stop, wait for ready. */
1715: ftCmd(QIC_CMD_STOP);
1716: if(ftReadyWait(15)) {
1717: printf("Not ready after stop tape 1 ");
1718: goto rd0done;
1719: }
1720: #endif
1721:
1722: /* Seek head to track 0, wait for ready. */
1723: ftCmd(QIC_CMD_SEEK);
1724: ftCmdArg(2);
1725: if(ftReadyWait(15)) {
1726: printf("Not ready after seek to track 0 ");
1727: goto rd0done;
1728: }
1729:
1730: #if 0
1731: /* Stop, wait for ready. */
1732: ftCmd(QIC_CMD_STOP);
1733: if(ftReadyWait(15)) {
1734: printf("Not ready after stop tape 2 ");
1735: goto rd0done;
1736: }
1737:
1738: /* Skip back 68 segments. SKPB. Wait for ready. */
1739: ftCmd(QIC_CMD_SKPB);
1740: ftCmdArg(6);
1741: ftCmdArg(6);
1742: if(ftReadyWait(15)) {
1743: printf("Not ready after skip back 68 ");
1744: goto rd0done;
1745: }
1746: #endif
1747:
1748: /* Logical forward. */
1749: ftCmd(QIC_CMD_FWD);
1750:
1751: for (i = 0; i < 3; i++) {
1752: /* Setup DMA */
1753: if (!dmaon(DMA_CH2, vtop(ftBigBuf)+(i*FT_BFRSZ), FT_BFRSZ, DMA_TO_MEM)) {
1754: printf("Ft dma straddle ");
1755: goto rd0done;
1756: }
1757: dmago(DMA_CH2);
1758:
1759: /* Send Read command to FDC */
1760: ft.ft_wakeMeUp = 1;
1761: ft.ft_dumpIrq = 1;
1762: rwCmd[4] = (i*32)+1;
1763: if ((putCount = fdcPutStr(rwCmd, RD_CMD_LEN)) != RD_CMD_LEN) {
1764: printf("only wrote %d bytes of rwCmd ", putCount);
1765: goto rd0done;
1766: }
1767:
1768: /* Wait for interrupt when read is done. */
1769: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRd0")) {
1770: printf("signaled before DMA done ");
1771: goto rd0done;
1772: }
1773:
1774: /* Turn off the DMA channel. */
1775: if ((putCount = dmaoff(DMA_CH2)) != 0) {
1776: printf("DMA residual %d bytes ", putCount);
1777: goto rd0done;
1778: }
1779: }
1780:
1781: /* Stop the tape. */
1782: ftCmd(QIC_CMD_STOP);
1783: if(ftReadyWait(15)) {
1784: printf("not ready after stop tape ");
1785: goto rd0done;
1786: }
1787:
1788: /* Quick check on data received. */
1789: for (i = 0; i < 4; i++)
1790: printf("%d:%x ", i, ftBigBuf[i]);
1791:
1792: rd0done:
1793: FT_BLAB = 0;
1794: /*********************
1795: **********************
1796: **
1797: ** End of Read Test.
1798: **
1799: **********************
1800: **********************/
1801: /* old stuff from read routine */
1802: uint src, dest;
1803: uint startSeg, endSeg;
1804:
1805: src = iop->io_seek;
1806: dest = iop->io.pbase;
1807:
1808: #if 0
1809: /*
1810: * Seek 0-32767 is header segment.
1811: */
1812: startSeg = src >> 15;
1813: endSeg = (src + iop->io_ioc - 1) >> 15;
1814:
1815: if (startSeg != endSeg || startSeg > 0) {
1816: u.u_error = EFAULT;
1817: return;
1818: }
1819: #endif
1820:
1821: src += (uint)ftBigBuf;
1822:
1823: iowrite(iop, src, iop->io_ioc);
1824:
1825: return;
1826: #endif
1827: #if 0
1828: /************************************************************************
1829: * ftBufRead
1830: *
1831: * Given a read count in bytes, read as much as possible into the DMA
1832: * buffer area.
1833: * Return the number of bytes retrieved, or -1 if total failure.
1834: ***********************************************************************/
1835: static int
1836: ftBufRead(bytesWanted)
1837: int bytesWanted;
1838: {
1839: int bytesToRead;
1840: uint bigBufLen = FT_NBUF * FT_BFRSZ;
1841: int blocksWanted, blocksRead;
1842: unchar * dmaBufPtr = ftBigBuf;
1843:
1844: /* Try for the smaller of amount wanted and buffer size. */
1845: bytesToRead = (bytesWanted > bigBufLen) ? bigBufLen : bytesWanted;
1846:
1847: /* WARNING: The following will change when we read the bad block map! */
1848:
1849: /* Calculate the number of 1K byte tape blocks to read. */
1850: blocksWanted = (bytesToRead + FT_BLKSZ - 1) / FT_BLKSZ;
1851:
1852: /* Keep asking for blocks until we have them all. */
1853: while (blocksWanted > 0) {
1854: blocksRead = ftReadBlks(dmaBufPtr, blocksWanted);
1855: if (blocksRead < 0) /* Failure! */
1856: break;
1857: dmaBufPtr += FT_BLKSZ;
1858: blocksWanted -= blocksRead;
1859: bytesToRead -= blocksRead * FT_BLKSZ;
1860: if (bytesToRead < 0)
1861: bytesToRead = 0;
1862: }
1863:
1864: /* Return the number of bytes read into the DMA buffer. */
1865: return bytesWanted - bytesToRead;
1866: }
1867:
1868: /***********************************************************************
1869: * ftReadBlkRun()
1870: *
1871: * Given the location of the next run of good blocks to read from tape
1872: * and the index where to put it, try to read a run of blocks into
1873: * DMA buffer area.
1874: *
1875: * Requirement: tape must be positioned properly and in motion.
1876: *
1877: * Return 0 on success (the number of failed block reads does not exceed
1878: * the maximum allowable), or -1 on failure.
1879: * On success, update blkToRead and blksRead fields of the FtRun struct
1880: * passed in. Also update error count and location tables for the current
1881: * segment buffer.
1882: *
1883: * Initialize retry count.
1884: * Initialize retry starting block.
1885: * While length of current run is > 0 blocks
1886: * Make a command to request the run of blocks from the FDC.
1887: * Send the command.
1888: * When FDC done, get report phase info from FDC.
1889: * Update blkToRead, blksRead, and runLength based on FDC report.
1890: * Conditionally update retry count and retry starting block.
1891: * If FDC reports error
1892: * If retry limit not exceeded
1893: * Increment retry count.
1894: * Reposition with micro step.
1895: * Else
1896: * If allowable error limit for this segment exceeded
1897: * Return read failure.
1898: * Else
1899: * Save relative block number of failed block for the segment.
1900: * Update bad read count for the segment.
1901: * Advance blkToRead, blksRead, and runLength to point past
1902: * current bad block (may decrement runLength to zero).
1903: * Endwhile
1904: *
1905: uint blkToRead; /* Next block wanted from current segment */
1906: uint blksRead; /* Number of blocks read from this seg */
1907: uint runLength; /* Number of good blocks in current run */
1908: ***********************************************************************/
1909: static int
1910: ftReadBlkRun(ftrp, bufn)
1911: struct FtRun * ftrp;
1912: int bufn;
1913: {
1914:
1915: #if 0
1916: int putCount;
1917: struct FtParm *fp;
1918:
1919: /* Get parameter set pointer. */
1920: fp = ftParm + ft.ft_fmt;
1921:
1922: /* Sanity check - don't try to read past end of track. */
1923: if (ft.ft_phySeg >= fp->segPerTrk)
1924: return -1;
1925:
1926: /* Set up DMA */
1927: if (!dmaon(DMA_CH2, vtop(ftBigBuf + (bufn * FT_BFRSZ)), FT_BFRSZ,
1928: DMA_TO_MEM)) {
1929: printf("Ft dma straddle ");
1930: return -1;
1931: }
1932: dmago(DMA_CH2);
1933:
1934: /*
1935: * Make a read command.
1936: * Enter diskette pseudo coordinates into FDC read command.
1937: * C = rwCmd[2], H = rwCmd[3], R = rwCmd[4]
1938: */
1939: rwCmd[RW_CMD_VERB] = RW_CMD_RD;
1940: rwCmd[RW_CMD_UNIT] = ft.ft_drv;
1941: ftFdcPos(ft.ft_track, ft.ft_phySeg, rwCmd + RW_CMD_CYL);
1942: rwCmd[RW_CMD_SCHI] = fp->blkPerTrk;
1943:
1944: /* Send Read command to FDC */
1945: ft.ft_wakeMeUp = 1;
1946: ft.ft_dumpIrq = 1;
1947: if ((putCount = fdcPutStr(rwCmd, RW_CMD_LEN)) != RW_CMD_LEN) {
1948: printf("only wrote %d bytes of rwCmd ", putCount);
1949: return -1;
1950: }
1951:
1952: /* Wait for interrupt when read is done. */
1953: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRd1S")) {
1954: printf("signaled before DMA done ");
1955: return -1;
1956: }
1957:
1958: /* Turn off the DMA channel. */
1959: if ((putCount = dmaoff(DMA_CH2)) != 0) {
1960: printf("DMA residual %d bytes ", putCount);
1961: return -1;
1962: }
1963:
1964: /* Update current segment pointer. */
1965: ft.ft_phySeg++;
1966: if (ft.ft_phySeg == fp->segPerTrk && ft.ft_track <= (fp->tracks - 1)) {
1967: ft.ft_track++;
1968: ft.ft_phySeg = 0;
1969: }
1970:
1971: return 0;
1972: #endif
1973: }
1974:
1975: /***********************************************************************
1976: * ftReadBlks()
1977: *
1978: * Given a pointer into the DMA buffer area and a block count, try to
1979: * read the given number of blocks. May read fewer due to error or
1980: * reaching end of track.
1981: * Return the number of blocks read, or -1 in case of total failure.
1982: ***********************************************************************/
1983: static int
1984: ftReadBlks(dmaBufPtr, blocksWanted);
1985: unchar * dmaBufPtr;
1986: uint blocksWanted;
1987: {
1988: int segsWanted, segsOnTrack;
1989:
1990: /*
1991: * See how many segments are left on the current track.
1992: * If no segments left on current track
1993: * If on last track of cartridge
1994: * Return failure.
1995: * Increment current track number.
1996: * Reset current segment number.
1997: */
1998: segsOnTrack = ft.ft_segsPerTrk - ft.ft_phySeg;
1999: if (segsOnTrack == 0) {
2000: if (ft.ft_track + 1 >= ft.ft_trksPerCart)
2001: return -1;
2002: ft.ft_track++;
2003: ft.ft_phySeg = 0;
2004: }
2005:
2006: /* WARNING: This will change with Reed-Solomon ecc. */
2007:
2008: /*
2009: * Calculate how many segments to go after.
2010: * First, round up the number of requested blocks.
2011: * Take the smaller of these.
2012: */
2013: segsWanted = (blocksWanted + FT_BLK_PER_SEG - 1) / FT_BLK_PER_SEG;
2014: if (segsWanted > segsOnTrk)
2015: segsWanted = segsOnTrk;
2016:
2017: /* Now ask for a bunch of segments, all from the same track. */
2018: return ftReadSegs(dmaBufPtr, segsWanted);
2019: }
2020:
2021: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.