|
|
1.1 root 1: #define MWC_FT 1
2:
3: /*
4: * File: xlft.c
5: *
6: * Purpose: Floppy tape device control.
7: * Inspired by the Archive "xl" driver.
8: * Requires 765 controller module fdc.c
9: * FDC = floppy disk controller, e.g. NEC upd765
10: *
11: * Revised: Tue Jun 1 19:16:37 1993 CDT
12: */
13:
14: /*
15: * Here is the protocol for QIC report commands, I think:
16: *
17: * Send QIC report command to FDC (this will be an FDC seek command).
18: * FDC interrupts when step pulses are sent.
19: * Send Sense Interrupt Status to FDC. (Clears interrupt line.)
20: * Read interrupt status from FDC.
21: * - Get ACK from tape drive. Want Track 0 true. Variable latency.
22: * Do
23: * Send Sense Drive Status to FDC.
24: * Read drive status from FDC, including Track 0 bit.
25: * Until Track 0 true.
26: * - Get data bits for the report command.
27: * For number-of-data-bits-in-report times
28: * Send QIC Report Next Bit command to FDC.
29: * FDC interrupts when step pulses are sent.
30: * Send Sense Interrupt Status to FDC.
31: * Read interrupt status from FDC.
32: * Send Sense Drive Status to FDC.
33: * Read drive status from FDC, including Track 0 bit.
34: * Save Track 0 bit value into report data.
35: * End for
36: * - Get final Track 0 true from tape drive.
37: * Send QIC Report Next Bit command to FDC.
38: * FDC interrupts when step pulses are sent.
39: * Send Sense Interrupt Status to FDC.
40: * Read interrupt status from FDC.
41: * Send Sense Drive Status to FDC.
42: * Read drive status from FDC, including Track 0 bit.
43: * Track 0 bit must be true.
44: */
45:
46: /*
47: * ----------------------------------------------------------------------
48: * Includes.
49: */
50: #include <sys/coherent.h>
51:
52: #include <errno.h>
53: #include <sys/buf.h>
54: #include <sys/con.h>
55: #include <sys/devices.h>
56: #include <sys/fdc765.h>
57: #include <sys/fdioctl.h>
58: #include <sys/inode.h>
59: #include <sys/sched.h>
60: #include <sys/stat.h>
61: #include <sys/xl.h>
62: #include <sys/xlfdc.h>
63: #include <sys/xlft.h>
64: #include <sys/xl8237.h>
65:
66: /*
67: * ----------------------------------------------------------------------
68: * Definitions.
69: * Constants.
70: * Macros with argument lists.
71: * Typedefs.
72: * Enums.
73: */
74: #define HDRSZ 0x4000 /* 16k, size of qic-40 header */
75: #define BFRSZ 0x8000 /* 32k, size of qic-40 buffer */
76:
77: #define MAX_PCN 200
78:
79: /* compatibility area */
80:
81: #define bcopy(src, dest, nbytes) memcpy(dest, src, nbytes)
82: #define copyin(userSrc, drvrDest, nbytes) \
83: ukcopy(userSrc, drvrDest, nbytes)
84: #define copyout(drvrSrc, userDest, nbytes) \
85: kucopy(drvrSrc, userDest, nbytes)
86: #define getfdc(unit) setFtIntr(1)
87: #define getfdcn(unit) setFtIntr(1)
88: #define kvtophys(vaddr) vtop(vaddr)
89: #define relfdc() setFtIntr(0)
90: #define sleep(address, priority) \
91: x_sleep(address, pritape, slpriSigLjmp, #address)
92: #define spl5() sphi()
93: #define splx(lvl) spl(lvl)
94: #define tenmicrosec() busyWait2(NULL, 12)
95:
96: static void cmn_err();
97:
98: enum {
99: CE_CONT = 0, /* used to continue a previous message */
100: CE_NOTE, /* used to display a NOTICE: message */
101: CE_WARN, /* used to display a WARNING: message */
102: CE_PANIC, /* used to display a PANIC: message */
103: CE_INVALID /* used to warn about invalid severity */
104: };
105:
106: /************************************************************************/
107: /* Additional fdc equates */
108: /************************************************************************/
109:
110: #define FDTMO 65535 /* xlfdc_in_byte, xlfdc_out_byte timeout*/
111: #define IOTMO (12 * HZ) /* io timeout */
112: #define TMSKP 18 /* # segments missed if IOTMO */
113:
114: #define FT_ACK_TRIES 5 /* max # of tries for ACK to QIC rpt cmd*/
115:
116: /*
117: * ----------------------------------------------------------------------
118: * Functions.
119: * Import Functions.
120: * Export Functions.
121: * Local Functions.
122: */
123: extern int nulldev();
124:
125: extern int xl_tbi(); /* init ecc tables */
126: extern int xl_enc(); /* encode ecc data */
127: extern int xl_dec(); /* decode ecc data */
128:
129: /* CON entry points. */
130: static int ftblock();
131: static int ftclose();
132: static int ftioctl();
133: static int ftload();
134: static int ftopen();
135: static int ftread();
136: static int ftunload();
137: static int ftwrite();
138:
139: static int getmem();
140: static int putrb();
141: static struct rb *getrb();
142: static void stdma();
143: static void strbfm(); /* set up rb for format */
144: static void strbsg();
145: static void stseg();
146: static void wvtbl();
147:
148: static void xlcal(), xlcal0(), (*pfcal)(); /* calibrate */
149: static void xlcomplete();
150: static void xldelay(), (*pfdly)(); /* "delay" */
151: static void xldma();
152: static unchar xlfdc_in_byte();
153: static unchar xlfdc_out_byte();
154: static unchar xlfdc_out_str();
155: static void xlfdc_reset();
156: static void xlflush();
157: static void xlfmq(), xlfmq0(), xlfmq1(), xlfmq2(); /* format queue */
158: static void xlfms(), xlfm0(), (*pffms)(); /* format segment */
159: static int xlformat(); /* format main routine */
160: static void xlgtdat();
161: static void xlhalt(), (*pfhlt)(); /* halt tape motion */
162: static void xlintr(), (*pfint)(); /* xl2 ptr to intr handler */
163: static void xlnull();
164: static int xlopn();
165: static void xloutput_step(); /* output steps, exit=pfint */
166: static void xlpark(), (*pfprk)();
167: static void xlpark0(), xlpark1(), xlpark2();
168: static void xlpos(), xlpos0(), xlpos1(), xlpos2(), xlpos3(), (*pfpos)();
169: static void xlptdat();
170: static void xlque(), xlqr0(), xlqw0();
171: static void xlrds(), xlrd0(), xlrd1(), (*pfrds)(); /* read segment */
172: static void xlreadid(), xlreadid0(), (*pfrdi)(); /* read id */
173: static void xlready(), xlready0(), (*pfrdy)(); /* "wait" for ready */
174: static void xlrel();
175: static void xlreset(), xlreset0(), (*pfrst)(); /* reset drive */
176: static void xlrn9(), xlrn17();
177: static void xlrnb(), xlrnb0(), (*pfrnb)(); /* report next bits */
178: static void xlrqr();
179: static void xlseek(), (*pfsek)(); /* seek to tptrk */
180: static void xlseek0(), xlseek1();
181: static void xlsel();
182: static void xlskipb(), (*pfskp)(); /* skip n segs back */
183: static void xlskipb0(), xlskipb1(), xlskipb2();
184: static void xlstatus(), (*pfsts)(); /* get status */
185: static void xlstatus0(), xlstatus1();
186: static void xltimout(), xltimfn();
187: static int xlwait();
188: static void xlwds(), (*pfwds)(); /* write del adm segment */
189: static void xlwts(), (*pfwts)(); /* write segment */
190: static void xlwt0(), xlwt1();
191:
192: static void xlDbPrintErr(), xlDbPrintCmd(), xlDbPrintStat();
193:
194: static void ftDbPrtStat();
195: static int ftCmd();
196: static void ftIrqHandler();
197: static int ftRecal();
198: static void ftResetFDC();
199: static void ftRptBegin();
200: static void ftRptUpdate();
201: static void ftSelect();
202:
203: /*
204: * ----------------------------------------------------------------------
205: * Global Data.
206: * Import Variables.
207: * Export Variables.
208: * Local Variables.
209: */
210:
211: /* from assembler module */
212: extern ushort *xltbl; /* ptr to rb.tbl */
213: extern unchar xlbst; /* base sector for segment */
214: extern unchar xlsct; /* sector # for next chunk */
215: extern int xlcnt; /* # bytes to xfer next chunk */
216: extern int xlofs; /* offset for next chunk */
217:
218: CON ftxlcon = {
219: DFCHR, /* Flags */
220: FL_MAJOR, /* Major index */
221: ftopen, /* Open */
222: ftclose, /* Close */
223: ftblock, /* Block */
224: ftread, /* Read */
225: ftwrite, /* Write */
226: ftioctl, /* Ioctl */
227: nulldev, /* Powerfail */
228: nulldev, /* Timeout */
229: ftload, /* Load */
230: ftunload, /* Unload */
231: nulldev /* Poll */
232: };
233:
234: /*
235: * Patchable variables.
236: */
237: int XL_VERBOSE = 1;
238: int XL_NBUFS = 17; /* ~ 3K total 'DATA' for driver */
239: /* 1.25K for ecc, + XL_NBUFS * 94 */
240:
241: /* Parameters for FDC Specify Command */
242: int FT_SRT = 0xE;
243: int FT_HUT = 0xF;
244: int FT_HLT = 0x1;
245:
246: /************************************************************************/
247: /* UNIX data areas and externals */
248: /************************************************************************/
249: static ulong allocated_add; /* mem allocate addr for kernel buffer */
250:
251: /************************************************************************/
252: /* data area */
253: /************************************************************************/
254: static int xldataw; /* data queue wakeup flag */
255: static int xlcompw; /* completion wakeup flag */
256: static int xlfreew; /* free queue wakeup flag */
257: static int xlcompf; /* completion flag */
258: static int xlnactw; /* inactive wakeup flag */
259: static int xlskip_count; /* # segments to skip */
260:
261: static fplng ptr_header; /* ptr to header bfr */
262: static fplng ptr_buffer; /* ptr to bfr */
263:
264: static struct rb * rbmp; /* request packet pool */
265:
266: static struct rbq xlfree_q; /* free queue */
267: static struct rbq req; /* request queue */
268: static struct rbq data_queue; /* read data queue */
269:
270: static int xlmem_allocated = 0; /* set if memory allocated */
271:
272: static struct { /* flags */
273: unsigned short init :1;
274: unsigned short open :1;
275: unsigned short writ :1;
276: unsigned short cal :1;
277: unsigned short actv :1;
278: unsigned short tmov :1;
279: unsigned short werr :1;
280: }f;
281:
282: static int nseg_p_track; /* # segments/track */
283: static int nseg_p_head; /* # segments/head */
284: static int nseg_p_cyl; /* # segments/cylinder */
285:
286: static int fdcmd; /* last fdc cmd */
287:
288: static unchar status_buf[10]; /* status buffer */
289: /* bytes 0-6 = 8272 status */
290: /* 7 = nec phase err */
291: /* 8 = 8272 st3 */
292:
293: static ushort xlrnbw; /* xl2 report next bit word */
294: static unchar xlster; /* set if last bit not a 1 */
295: static unchar xl6sts; /* xl2 status */
296: static unchar xlests;
297: static ushort xl7sts;
298: static int xlbcnt; /* xlrnb counter, # of sts bits */
299:
300: static unchar fdstb[4] = { 0x1c, 0x2d, 0x4e, 0x8f };
301: static unchar fdsel, unit, fdselr, ftfmt;
302:
303: static ushort sgwrd; /* strbsg params */
304: static ulong sgmap;
305:
306: static paddr_t xadr; /* segment io params */
307: static struct rb *xprb;
308: static ushort xtbl;
309: static int xsct;
310: static int xrty;
311: static int xstop; /* stop io flag (close) */
312:
313: static int tptrk; /* current tape track */
314: static int tpseg; /* next tape segment */
315: static int fmtrk; /* format track */
316: static int vftrk; /* verify track (debug display) */
317:
318: static int xltimoutf = 0; /* timeout flag */
319:
320: /* fdc commands */
321: static unchar sf2cms[3] = { 0x03, 0xef, 0x02 };
322:
323: static unchar sf3cms[3] = { 0x03, 0xdf, 0x02 };
324: static unchar sekcms[3] = { 0x0f, 0x00, 0x00 };
325: static unchar rdicms[2] = { 0x4a, 0x00 };
326: static unchar rwdcms[9] = { 0x46, 0, 0, 0, 0, 3, 226, 1, 0xff };
327: static unchar fmtcms[6] = { 0x4d, 0, 3, 32, 233, 0x6d };
328: /* sekcms[2] = current track, see xlintr() */
329:
330: static unchar vtbl[] = "VTBL";
331: static unchar xnxnm[] = "unix";
332: static unchar xnxvs[20] = {
333: 0x55, 0xaa, 0x55, 0xaa, 0x02, 0x00, 0x00, 0x00,
334: 0x01, 0x00, 0x02, 0x00, 0x4f, 0x05, 0x00, 0x00,
335: 0x00, 0x00, 0x00, 0x00
336: };
337:
338: static int h0sgn, h1sgn; /* header seg # */
339: static int volume_seg_num; /* volume seg # */
340: static int data_seg_num; /* data seg # */
341: static int curr_seg_num; /* current seg # */
342: static int read_ahead_seg_num; /* read ahead seg # */
343: static struct rb *cprb; /* offset to current rb */
344: static fpchr cptr; /* ptr to current bfr */
345: static int cnbr; /* # bytes remaining */
346: static fpchr wptr; /* copy of cptr for write encod */
347: static int last_seg_num; /* last segment */
348: static int lnbr; /* last seg # bytes */
349:
350: static int rnbr; /* # requested bytes remaining */
351: static int rcnt; /* # bytes to copy */
352:
353: static struct rb *fprb; /* used to enque requests */
354:
355: static TIM xltmo, xldly;
356:
357: static struct FT {
358: unchar ft_pcn; /* present cylinder # */
359: unchar ft_bitsNeeded; /* # of Report Next Bit's to do */
360: unchar ft_bitsRcvd; /* # of report bits received */
361: unchar ft_wakeMeUp; /* 1 = sleeping til next FDC IRQ */
362: unchar ft_dumpIrq; /* 1 = dump IRQ status */
363: unchar ft_ackNeeded; /* 1 = awaiting ACK to rpt cmd */
364: ushort ft_report; /* where reported bits go */
365: TIM ft_tim;
366: } ft;
367:
368: /*
369: * ----------------------------------------------------------------------
370: * Code.
371: */
372:
373: /*
374: * CON struct routines.
375: */
376:
377: /************************************************************************/
378: /* ftblock */
379: /* */
380: /* Tape is not a block device, but we need a block entry point since */
381: /* the same driver controls diskette access. */
382: /************************************************************************/
383: static int
384: ftblock(bp)
385: BUF *bp;
386: {
387: u.u_error = EIO;
388: bp->b_flag |= BFERR;
389: bdone(bp);
390: return;
391: }
392:
393: /************************************************************************
394: * ftclose
395: *
396: ***********************************************************************/
397: static int
398: ftclose(dev, mode)
399: dev_t dev;
400: int mode;
401: {
402: #if 1
403: printf("ftclose ");
404: f.open = 0;
405: #else
406: if (f.open) {
407: /* f.open = 0; reset open flag U001 */
408: xlflush(); /* flush all bfrs */
409: if (f.werr) /* flag error if occurred */
410: u.u_error = EIO;
411:
412: getfdc(unit);
413: xlsel(unit);
414: if (minor(dev) & M_REW) { /* rewind if rewind_on_close */
415: pfprk = xlcomplete;/* clear drive status and rewind*/
416: xlpark();
417: xlwait();
418: } else {
419: pfsts = xlcomplete; /* clear drive status */
420: xlstatus();
421: xlwait();
422: }
423: xlrel();
424: relfdc();
425: f.open = 0; /* reset open flag U001 */
426: cmn_err(CE_CONT, "xlclose: xlster %x f.werr %d\n", xlster, f.werr);
427: }
428: #endif
429: }
430:
431: /************************************************************************/
432: /* ftioctl */
433: /* Handle tape drive & controller commands like erase, rewind, */
434: /* retension, read filemark, and write filemark */
435: /************************************************************************/
436: ftioctl(dev, cmd, arg)
437: register int dev, cmd;
438: int arg;
439: {
440: int xlarg; /* ioctl argument */
441: union xl_status xl; /* status structure */
442:
443: cmn_err(CE_CONT, "ftioctl: cmd %x\n", cmd);
444:
445: if ((cmd & 0xff00) != XLIOC) {
446: u.u_error = EINVAL;
447: return;
448: }
449:
450: getfdc(unit); /* get control of fdc */
451: xlsel(unit); /* select tape drive */
452:
453: switch (cmd) {
454: case XL_DEBUG:
455: if (copyin(arg, (caddr_t)&XL_VERBOSE, sizeof(int)) == -1)
456: u.u_error = EFAULT;
457: break;
458: case XL_STATUS: /* read status */
459: /*
460: * Report current status, then clear
461: * any errors by reading the status again.
462: */
463: xl.stat[0] = xl6sts;
464: xl.stat[1] = xl7sts;
465: xl.stat[2] = xl7sts >> 8;
466:
467: if (copyout(xl.stat, arg, sizeof(xl.stat)) == -1)
468: u.u_error = EFAULT;
469: else {
470: xlster = 0;
471: xlests = 0;
472: xl7sts = 0;
473: pfsts = xlcomplete;
474: xlstatus();
475: xlwait();
476: if (f.werr) /* flag error if occurred */
477: u.u_error = EIO;
478: break;
479:
480: case XL_RESET: /* reset drive */
481: pfrst = xlcomplete;
482: xlreset();
483: xlwait();
484: if (f.werr) /* flag error if occurred */
485: u.u_error = EIO;
486: break;
487:
488: case XL_RETEN : /* retention tape */
489: pfint = xlready;
490: pfrdy = xlcomplete;
491: xloutput_step(QIC_CMD_EOT);
492: xlwait();
493:
494: pfint = xlready;
495: pfrdy = xlcomplete;
496: xloutput_step(QIC_CMD_BOT);
497: xlwait();
498: if (xlster)
499: u.u_error = ENXIO;
500:
501: break;
502:
503: case XL_REWIND: /* rewind */
504: pfint = xlready;
505: pfrdy = xlcomplete;
506: xloutput_step(QIC_CMD_BOT);
507: xlwait();
508: if (xlster)
509: u.u_error = ENXIO;
510: break;
511:
512: case XL_ERASE: /* erase tape */
513: break;
514:
515: case XL_AMOUNT: /* report amount of data xfered */
516: /*if (copyout(&ct_amount, arg, sizeof(ct_amount)) == -1)
517: u.u_error = EFAULT;*/
518: break;
519:
520: case XL_FORMAT: /* format tape */
521: if (copyin(arg, (caddr_t) &xlarg, sizeof(int)) == -1)
522: u.u_error = EFAULT;
523:
524: else if ((xlarg >= 0 && xlarg <= 14 && ftfmt == 0) ||
525: (xlarg >= 0 && xlarg <= 28 && ftfmt == 1)) {
526: xlformat(xlarg);
527: if (f.werr) /* flag err if occurred */
528: u.u_error = EIO;
529: } else /* invalid track number */
530: u.u_error = EINVAL;
531: }
532: break;
533: case XL_RFM: /* read file mark */
534: ; /* not implemented */
535:
536: default:
537: u.u_error = EINVAL;
538: break;
539: }
540: xlrel(); /* release fdc */
541: relfdc();
542: cmn_err(CE_CONT, "xlioctl: returning\n");
543: }
544:
545: /************************************************************************/
546: /* ftload */
547: /************************************************************************/
548: static int
549: ftload()
550: {
551: register int eflag;
552: register int s, t;
553:
554: #if MWC_FT
555: ftIntr = ftIrqHandler;
556: #else
557: ftIntr = xlintr;
558: #endif
559:
560: f.init = 0; /* reset flags */
561: f.open = 0;
562: f.cal = 0;
563: f.actv = 0;
564: f.tmov = 0;
565: xlnactw = 0;
566: xlfreew = 0;
567: xldataw = 0;
568: xlcompw = 0;
569: xlcompf = 0;
570: xlster = 0;
571: status_buf[7] = 0;
572: pfint = xlnull; /* reset ptr to fun */
573: xl_tbi(); /* init ecc tables */
574: if(getmem())
575: printf("XL: getmem() failed.\n");
576: else
577: printf("Archive xl floppy tape driver v1.0 COH loaded\n");
578: }
579:
580: /************************************************************************
581: * ftopen
582: *
583: ***********************************************************************/
584: static int
585: ftopen(dev, mode)
586: dev_t dev;
587: int mode;
588: {
589: unsigned int drvStat;
590: int i;
591: int bit;
592: int result;
593:
594: printf("ftopen %x ", dev);
595:
596: /* Can't append to tape. */
597: if (mode & IPAPPEND) {
598: printf("can't append ");
599: u.u_error = EINVAL;
600: return;
601: }
602:
603: /* Only one open at a time. */
604: if (f.open) {
605: printf("only one ftopen at a time ");
606: u.u_error = EBUSY;
607: return;
608: }
609: f.open = 1;
610:
611: unit = FT_UNIT(dev); /* set unit # */
612:
613: if (! getfdcn(unit)) { /* get control of fdc */
614: printf("fdc unavailable ");
615: u.u_error = EBUSY; /* exit if fdc is being used */
616: f.open = 0;
617: return;
618: }
619:
620: #if MWC_FT
621: {
622: ftIntr = ftIrqHandler;
623:
624: /* Select tape drive. */
625: /* ftSelect(unit); */
626: fdcRate(FDC_RATE_500K); /* set transfer rate */
627: fdcDrvSelect(unit, FDC_MOTOR_ON); /* 1=motor on */
628:
629: /* Reset FDC and Initialize pseudo cylinder number for QIC commands. */
630: ftResetFDC(unit);
631:
632: fdcSpecify(FT_SRT, FT_HUT, FT_HLT);
633:
634: /* 80 MB nseg_p_track = 100, nseg_p_head = 600, nseg_p_cyl = 4 */
635: /* 40 MB nseg_p_track = 68, nseg_p_head = 680, nseg_p_cyl = 4 */
636: if (ftfmt) {
637: nseg_p_track = 100; /* set for 80 MB drive */
638: nseg_p_head = 600;
639: nseg_p_cyl = 4;
640: } else {
641: nseg_p_track = 68; /* set for 40 MB drive */
642: nseg_p_head = 680;
643: nseg_p_cyl = 4;
644: }
645:
646: if (ftCmd(QIC_CMD_RST)) {
647: printf("soft reset failed ");
648: u.u_error = EIO;
649: f.open = 0;
650: setFtIntr(0);
651: return;
652: }
653:
654: printf("zzz ");
655: /* Now wait a second. */
656: timeout(&ft.ft_tim, HZ, wakeup, &ft.ft_wakeMeUp);
657: x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRstWt");
658: printf("!! ");
659:
660: if (ftCmd(QIC_CMD_STS)) {
661: printf("get drive status failed ");
662: u.u_error = EIO;
663: f.open = 0;
664: setFtIntr(0);
665: return;
666: }
667: xlDbPrintStat(ft.ft_report);
668:
669: if (ftCmd(QIC_CMD_ECD)) {
670: printf("get error code failed ");
671: u.u_error = EIO;
672: f.open = 0;
673: setFtIntr(0);
674: return;
675: }
676: xlDbPrintErr(ft.ft_report);
677:
678: if (ftCmd(QIC_CMD_STS)) {
679: printf("get drive status failed ");
680: u.u_error = EIO;
681: f.open = 0;
682: setFtIntr(0);
683: return;
684: }
685: xlDbPrintStat(ft.ft_report);
686:
687: }
688: xlrel();
689: relfdc();
690: #else
691: xlsel(unit);
692:
693: if (0 == f.init) { /* init drive if 1st time */
694: pfrst = xlcomplete;
695: xlreset();
696: if (xlwait()) {
697: printf("init interrupted ");
698: u.u_error = EINTR;
699: f.open = 0;
700: relfdc();
701: return;
702: }
703: f.init = 1;
704: }
705:
706: if (!xlopn(minor(dev))) { /* open drive */
707: /* init current params */
708: read_ahead_seg_num = curr_seg_num = data_seg_num;
709: cmn_err(CE_CONT, "xlopen: volume_seg_num %d data_seg_num %d last_seg_num %d lnbr %d\n",
710: volume_seg_num, data_seg_num, last_seg_num, lnbr);
711:
712: cnbr = 0;
713: xstop = 0;
714: f.writ = 0;
715: f.werr = 0;
716: } else {
717: printf("xlopn failed ");
718: u.u_error = ENODEV; /* set no device */
719: f.open = 0;
720: }
721: xlrel(); /* release fdc */
722: relfdc();
723: cmn_err(CE_CONT, "xlopen: xlster %x, xl6sts %x, xlests %x, xl7sts %x\n",
724: xlster, xl6sts, xlests, xl7sts);
725: #endif
726: }
727:
728: /************************************************************************
729: * ftread
730: *
731: ***********************************************************************/
732: static int
733: ftread(dev, iop)
734: dev_t dev;
735: IO * iop;
736: {
737: if (!f.open) { /* exit if not open */
738: u.u_error = EIO;
739: return;
740: }
741: xlgtdat(iop);
742: }
743:
744: /************************************************************************
745: * ftunload
746: *
747: ***********************************************************************/
748: static int
749: ftunload()
750: {
751: }
752:
753: /************************************************************************
754: * ftwrite
755: *
756: ***********************************************************************/
757: static int
758: ftwrite(dev, iop)
759: dev_t dev;
760: IO * iop;
761: {
762: if (!f.open) { /* exit if not open */
763: u.u_error = EIO;
764: return;
765: }
766: if (xl6sts & XLSWRP) { /* exit if write protect */
767: u.u_error = EIO;
768: return;
769: }
770: while(fprb = getrb(&data_queue))/* rel any pending read bfrs*/
771: putrb(&xlfree_q, fprb);/* allows swt from read to write*/
772: f.writ = 1; /* set write flag */
773: xlptdat(iop);
774: if (f.werr) /* flag error if occurred */
775: u.u_error = EIO;
776: }
777:
778: /*
779: * Support routines.
780: */
781:
782: /************************************************************************/
783: /* cmn_err() - doesn't really belong here */
784: /************************************************************************/
785: static void
786: cmn_err(level, format)
787: int level;
788: char * format;
789: {
790: if (XL_VERBOSE)
791: printf("%r ", &format);
792: }
793:
794: /************************************************************************/
795: /* dsperr display floppy error */
796: /************************************************************************/
797: static int
798: dsperr()
799: { /* disregard fdc ecc error */
800: if (!(status_buf[0] == 0x41 &&
801: status_buf[1] == 0x20 &&
802: status_buf[2] == 0x20))
803: cmn_err(CE_CONT, "fdcerr: ST0=%x ST1=%x ST2=%x\n",
804: status_buf[0], status_buf[1], status_buf[2]);
805: }
806:
807: /*
808: * For debugging, print command status and interrupt status to console.
809: */
810: static void
811: ftDbPrtStat()
812: {
813: int i;
814:
815: printf("[[");
816: if (fdc.fdc_ncmdstat) {
817: printf("cmd ");
818: for (i = 0; i < fdc.fdc_ncmdstat; i++)
819: printf("%x ", fdc.fdc_cmdstat[i]);
820: }
821: if (fdc.fdc_nintstat) {
822: printf("int ");
823: for (i = 0; i < fdc.fdc_nintstat; i++)
824: printf("%x ", fdc.fdc_intstat[i]);
825: }
826: printf("]] ");
827: }
828:
829: /*
830: * Given a QIC-117 command number, cause that number of step pulses
831: * to be sent from the FDC by faking a seek command.
832: */
833: static int
834: ftCmdSend(cmd)
835: int cmd;
836: {
837: /* Like NEC - pcn=present cylinder #; ncn=new cylinder #. */
838: unsigned char ncn;
839:
840: xlDbPrintCmd(cmd);
841:
842: /*
843: * Will fake a seek command.
844: * Figure out whether to simulate seek to lower or higher
845: * cylinder number.
846: */
847: if (ft.ft_pcn + cmd <= MAX_PCN) {
848: ncn = ft.ft_pcn + cmd;
849: } else if (ft.ft_pcn - cmd >= 0) {
850: ncn = ft.ft_pcn - cmd;
851: } else {
852: printf("ftCmd %d invalid, pcn %d ", cmd, ft.ft_pcn);
853: return -1;
854: }
855:
856: ft.ft_dumpIrq = 1;
857: fdcSeek(unit, 0, ncn);
858: }
859:
860: /*
861: * Given a QIC-117 command number, send the command.
862: * If report bits are expected in response, initialize the bit counter.
863: * Then sleep until the commmand is done and report bits are gathered.
864: */
865: static int
866: ftCmd(cmd)
867: int cmd;
868: {
869: int bitsNeeded;
870:
871: /* Will sleep until command done and report bits are in. */
872: ft.ft_wakeMeUp = 1;
873:
874: /*
875: * The following commands expect report bits from the tape drive.
876: * After receiving the QIC command (and subsequent delay),
877: * the drive sends a leading ACK bit (always 1). This bit is
878: * not counted in the numbers below.
879: * Subseqeunt bits are sent in response to Report Next Bit,
880: * least significant bit first, then a trailing 1.
881: * The value of bitsNeeded is either one more than the number of
882: * data bits in the report, or zero.
883:
884: */
885: switch(cmd) {
886: case QIC_CMD_STS:
887: case QIC_CMD_DRVCN:
888: case QIC_CMD_ROMVN:
889: case QIC_CMD_TPSTAT:
890: bitsNeeded = 9;
891: break;
892: case QIC_CMD_ECD:
893: case QIC_CMD_VNDID:
894: bitsNeeded = 17;
895: break;
896: default:
897: bitsNeeded = 0;
898: }
899: ftRptBegin(bitsNeeded);
900:
901: ftCmdSend(cmd);
902:
903: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftCmd"))
904: /* Signal woke us prematurely. */
905: return -1;
906: else {
907: return 0;
908: }
909: }
910:
911: /*
912: * Interrupt handler.
913: */
914: static void
915: ftIrqHandler()
916: {
917: int i, bit, unit;
918:
919: /*
920: * Need to get FDC status from result phase - fdcCmdStatus -
921: * or clear interrupt - fdcIntStatus - that may have been
922: * generated by diskette change or seek/recal complete.
923: */
924: if (FDC_BUSY()) {
925: fdcCmdStatus();
926: } else {
927: fdcIntStatus();
928: /* WARNING - should squawk if wrong number of status bytes. */
929: ft.ft_pcn = fdc.fdc_intstat[1];
930: unit = fdc.fdc_intstat[0] & 3;
931: }
932:
933: /* If ACK needed, try several times to get it. */
934: if (ft.ft_ackNeeded) {
935: for (i = 0; i < FT_ACK_TRIES; i++) {
936: fdcDrvStatus(unit, FDC_HEAD_0);
937: fdcCmdStatus();
938: bit = (fdc.fdc_cmdstat[0] & ST3_T0) ? 1 : 0;
939: putchar(bit ? '|' : 'o');
940: if (bit) {
941: ft.ft_ackNeeded = 0;
942: break;
943: }
944: /* Wait about 20 usec. then try again. */
945: busyWait2(NULL, 20);
946: }
947:
948: if (ft.ft_ackNeeded) {
949: /* Need error recovery here! */
950: printf("<= Missing ACK ");
951: ft.ft_ackNeeded = 0;
952: }
953: } else if (ft.ft_bitsNeeded) {
954: /*
955: * If report bits are needed
956: * Get current report bit.
957: */
958:
959: /*
960: * Need unit # for Sense Drive Status command.
961: * Get it from preceding Sense Interrupt command.
962: */
963: fdcDrvStatus(unit, FDC_HEAD_0);
964: fdcCmdStatus();
965:
966: /* Get next report bit by checking Track Zero bit in ST3 */
967: if (fdc.fdc_ncmdstat == 1) {
968: int bit;
969:
970: bit = (fdc.fdc_cmdstat[0] & ST3_T0) ? 1 : 0;
971: printf("%d", bit);
972: ftRptUpdate(bit);
973: } else {
974: printf("rnb status bad ");
975: }
976: }
977:
978: /*
979: * If more report bits will be needed
980: * Send request for next bit.
981: * Else
982: * See if original requestor needs wakeup, etc.
983: */
984: if (ft.ft_bitsNeeded) {
985: ftCmdSend(QIC_CMD_RNB);
986: } else {
987: if (ft.ft_wakeMeUp) {
988: ft.ft_wakeMeUp = 0;
989: wakeup(&ft.ft_wakeMeUp);
990: }
991:
992: /* Print debug output if needed. */
993: if (ft.ft_dumpIrq) {
994: ft.ft_dumpIrq = 0;
995: defer(ftDbPrtStat);
996: }
997: }
998: }
999:
1000: /*
1001: * Send Recalibrate command to FDC and wait for it to finish.
1002: *
1003: * Return 0 if normal operation, -1 if signaled before recal complete.
1004: */
1005: static int
1006: ftRecal(unit)
1007: int unit;
1008: {
1009: ft.ft_wakeMeUp = 1;
1010: fdcRecal(unit);
1011: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRecal"))
1012: return -1;
1013: else
1014: return 0;
1015: }
1016:
1017: /************************************************************************
1018: * ftResetFDC
1019: *
1020: * Reset the FDC and wait for the resulting interrupt.
1021: * Reset is done keeping the unit in question selected.
1022: ***********************************************************************/
1023: static void
1024: ftResetFDC(unit)
1025: {
1026: /*
1027: * Since FDC reset generates an interrupt, we need to tell the
1028: * interrupt handler there will be *no* report bits incoming.
1029: */
1030: ftRptBegin(0);
1031:
1032: ft.ft_pcn = 0;
1033: ft.ft_wakeMeUp = 1;
1034: fdcResetSel(unit, FDC_MOTOR_ON);
1035: x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRstFDC");
1036: }
1037:
1038: /************************************************************************
1039: * ftRptBegin
1040: *
1041: * Initialize ft state information in preparation for QIC report command.
1042: *
1043: * Argument "bitCount" is the total number of bits expected, including
1044: * initial ACK and final TRUE. It is 1 more than the number of
1045: * Report Next Bit Commands that will be issued.
1046: ***********************************************************************/
1047: static void
1048: ftRptBegin(bitCount)
1049: int bitCount;
1050: {
1051: ft.ft_bitsNeeded = bitCount;
1052: ft.ft_bitsRcvd = 0;
1053: ft.ft_report = 0;
1054: ft.ft_ackNeeded = (bitCount) ? 1 : 0;
1055: }
1056:
1057: /************************************************************************
1058: * ftRptUpdate
1059: *
1060: * Acquire another bit for QIC report command.
1061: * Last bit is discarded. Other bits are accumulated,
1062: * least significant bit first, into ft_report.
1063: ***********************************************************************/
1064: static void
1065: ftRptUpdate(bit)
1066: int bit;
1067: {
1068: ft.ft_bitsNeeded--;
1069: ft.ft_bitsRcvd++;
1070:
1071: if (ft.ft_bitsNeeded == 0) {
1072: if (bit != 1)
1073: printf("Missing final TRUE ");
1074: } else {
1075: ft.ft_report |= (bit << (ft.ft_bitsRcvd - 1));
1076: }
1077: }
1078:
1079: /*
1080: * Select tape unit.
1081: */
1082: static void
1083: ftSelect(unit)
1084: int unit;
1085: {
1086: fdcRate(FDC_RATE_500K); /* set transfer rate */
1087: fdcDrvSelect(unit, 1); /* 1=motor on */
1088:
1089: /* Toggle FDC reset line, then wait for its interrupt. */
1090: ft.ft_wakeMeUp = 1;
1091: fdcResetSel(unit, 1); /* Reset, preserving selection */
1092: x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftSelect");
1093:
1094: fdcSpecify(FT_SRT, FT_HUT, FT_HLT);
1095:
1096: /* 80 MB nseg_p_track = 100, nseg_p_head = 600, nseg_p_cyl = 4 */
1097: /* 40 MB nseg_p_track = 68, nseg_p_head = 680, nseg_p_cyl = 4 */
1098: if (ftfmt) {
1099: nseg_p_track = 100; /* set for 80 MB drive */
1100: nseg_p_head = 600;
1101: nseg_p_cyl = 4;
1102: } else {
1103: nseg_p_track = 68; /* set for 40 MB drive */
1104: nseg_p_head = 680;
1105: nseg_p_cyl = 4;
1106: }
1107: }
1108:
1109: /************************************************************************
1110: * getmem
1111: *
1112: * Grab XL_NBUFS # of 32k DMA buffers.
1113: * Only use 16k of one of these, for QIC headers.
1114: *
1115: * Return 0 on success, 1 on failure.
1116: ***********************************************************************/
1117: static int
1118: getmem()
1119: {
1120: register int i, nb;
1121: struct rb *prb;
1122: unsigned int tmpad, highAddr;
1123:
1124: if (xlmem_allocated)
1125: return 0;
1126:
1127: nb = XL_NBUFS;
1128: if (nb < 4)
1129: nb = 4;
1130:
1131: rbmp = (struct rb *)kalloc(XL_NBUFS * sizeof(struct rb));
1132: if (rbmp == NULL) {
1133: printf("XL: initial kalloc() failed\n");
1134: return 1;
1135: }
1136:
1137: allocated_add = getDmaMem(nb * BFRSZ, BFRSZ);
1138: if (allocated_add == NULL) {
1139: printf("XL: getDmaMem() failed\n");
1140: return 1;
1141: }
1142:
1143: highAddr = allocated_add + (nb * BFRSZ);
1144:
1145: cmn_err(CE_CONT, "Allocated %d buffers. Virtual <%x-%x>. "
1146: "Physical <%x-%x>.\n",
1147: nb, allocated_add, highAddr, vtop(allocated_add), vtop(highAddr));
1148:
1149: /* tmpad = 1st 32k bfr adr */
1150: tmpad = (allocated_add + BFRSZ);
1151:
1152: ptr_header = (fplng)allocated_add;
1153:
1154: xlfree_q.top = prb = rbmp;/* build free pool */
1155: for (i = 0; i < (nb - 1); ++i) {
1156: xlfree_q.bot = prb;
1157: ++prb;
1158: xlfree_q.bot->nxt = prb;
1159: xlfree_q.bot->adr = tmpad;
1160: tmpad += BFRSZ;
1161: }
1162: xlfree_q.bot->nxt = 0;
1163:
1164: cmn_err(CE_CONT, "getmem: allocated %d buffers\n", nb);
1165:
1166: xlmem_allocated = 1;
1167: data_queue.top = 0;
1168: data_queue.bot = 0;
1169: return 0;
1170: }
1171:
1172: /************************************************************************/
1173: /* getrb get request buffer from queue */
1174: /************************************************************************/
1175: static struct rb *
1176: getrb(prbq)
1177: struct rbq *prbq;
1178: {
1179: struct rb *prb;
1180: int ilv;
1181:
1182: if (0 == (prb = prbq->top)) /* return if empty */
1183: return 0;
1184: ilv = spl5(); /* playing with queue */
1185: prbq->top = prb->nxt; /* advance top ptr */
1186: if (0 == prbq->top)
1187: prbq->bot = 0;
1188: splx(ilv); /* done with queue */
1189: return prb;
1190: }
1191:
1192: /************************************************************************/
1193: /* putrb add req buf to end of queue */
1194: /* return 1 if added to empty queue */
1195: /************************************************************************/
1196: static int
1197: putrb(prbq, prb)
1198: struct rbq *prbq;
1199: struct rb *prb;
1200: {
1201: int ilv;
1202:
1203: prb->nxt = 0; /* reset this buf's fwd ptr */
1204: ilv = spl5(); /* playing with queues */
1205: if (0 == prbq->top) { /* if empty queue, */
1206: prbq->top = prb; /* pnt top and bot to new buf */
1207: prbq->bot = prb;
1208: splx(ilv);
1209: return 1;
1210: } else {
1211: (prbq->bot)->nxt = prb;/* else pnt old end to new buf */
1212: prbq->bot = prb; /* and bot to new buf */
1213: splx(ilv);
1214: return 0;
1215: }
1216: }
1217:
1218: /************************************************************************/
1219: /* stdma set dma */
1220: /************************************************************************/
1221: static void
1222: stdma(mode, adr, count)
1223: int mode;
1224: paddr_t adr;
1225: int count;
1226: {
1227: cmn_err(CE_CONT, "dir: %x Vadd: %x, Padd: %x, count: %x\n",
1228: mode, adr, kvtophys(adr), count);
1229:
1230: /* dma_param(DMA_CH2, mode, kvtophys(adr), count - 1); */
1231: /* dma_enable(DMA_CH2); */
1232: xldma((char)(mode + DMA_CH2), (long)kvtophys(adr), count - 1);
1233: }
1234:
1235: /************************************************************************/
1236: /* strbfm set up rb params for format */
1237: /************************************************************************/
1238: static void
1239: strbfm(prb)
1240: struct rb *prb;
1241: {
1242: register fpchr p0;
1243: register int d0;
1244: int d1;
1245:
1246: d0 = prb->sgn; /* get segment # */
1247: prb->hed = d0/nseg_p_head; /* set up fdc params */
1248: d0 = d0 % nseg_p_head;
1249: prb->cyl = d0/nseg_p_cyl;
1250: prb->sct = ((d0 % nseg_p_cyl) << 5) + 1;
1251:
1252: p0 = (fpchr)cprb->adr;
1253:
1254: /* fill format bfr */
1255:
1256: d0 = prb->sct;
1257: for (d1 = d0 + 32; d0 != d1; ++d0) {
1258: *p0++ = prb->cyl;
1259: *p0++ = prb->hed;
1260: *p0++ = d0;
1261: *p0++ = 3;
1262: }
1263: }
1264:
1265: /************************************************************************/
1266: /* strbsg set up rb params for segment */
1267: /* should be called at task time */
1268: /* */
1269: /* rb.tbl is used to skip bad sectors in segments. */
1270: /* segments are split up into "chunks" */
1271: /* index into rb.tbl with relative sector. */
1272: /* each word in rb.tbl: */
1273: /* bits 15-10: sector count for chunk */
1274: /* bits 9- 5: dma offset for chunk */
1275: /* bits 4- 0: sector # for chunk */
1276: /************************************************************************/
1277: static void
1278: strbsg(prb)
1279: struct rb *prb;
1280: {
1281: register int d0, d1, d2;
1282: ushort *p0;
1283:
1284: prb->erc = 0; /* reset error count */
1285: d0 = prb->sgn; /* set tape params */
1286: prb->trk = d0 / nseg_p_track;
1287: prb->tps = d0 % nseg_p_track;
1288: prb->hed = d0 / nseg_p_head; /* set up fdc params */
1289: d0 = d0 % nseg_p_head;
1290: prb->cyl = d1 = d0 / nseg_p_cyl;
1291: prb->sct = d0 = ((d0 % nseg_p_cyl) << 5) + 1;
1292: if (d0 == 1) { /* set up position params */
1293: --d1;
1294: d0 = (nseg_p_cyl << 5) - 16;
1295: }
1296: else
1297: d0 -= 16;
1298: prb->idc = d1;
1299: prb->ids = d0;
1300: d2 = 32; /* set up rb.tbl */
1301: sgwrd = 0;
1302: sgmap = prb->map;
1303: p0 = prb->tbl;
1304: prb->nbk = 0;
1305: while(d2) {
1306: d0 = d2; /* d0 = # scts to skip */
1307: while(sgmap & 1) {
1308: --d2;
1309: sgmap >>= 1;
1310: }
1311: d0 -= d2;
1312: sgwrd += d0; /* bump sct # in sgwrd */
1313: if (!d2) /* exit if done */
1314: break;
1315: d1 = d2; /* d1 = # scts this chunk */
1316: while(d2 && 0 == (sgmap & 1)) {
1317: --d2;
1318: sgmap >>= 1;
1319: }
1320: d1 -= d2;
1321: prb->nbk += d1; /* adjust # blocks in segment */
1322: sgwrd += d1 << 10; /* set count in sgwrd */
1323: while(d0) { /* fill table for skipped scts */
1324: *p0++ = sgwrd;
1325: --d0;
1326: }
1327: while(d1) { /* for each sct xferred */
1328: *p0++ = sgwrd; /* store table entry */
1329: sgwrd += 0xfc21;/* dec cnt, bump ofset bump sct */
1330: --d1;
1331: }
1332: }
1333: for (++d0; d0; --d0) /* zero out rest of rb.tbl */
1334: *p0++ = 0;
1335: }
1336:
1337: /************************************************************************/
1338: /* stseg set up segment io */
1339: /************************************************************************/
1340: static void
1341: stseg(prb)
1342: struct rb *prb;
1343: {
1344: rwdcms[1] = unit; /* set rwdcmd constants */
1345: rwdcms[2] = prb->cyl;
1346: rwdcms[3] = prb->hed;
1347: xadr = prb->adr; /* set base adr */
1348: xsct = prb->sct; /* set base sct */
1349: xrty = 6; /* set default # retries */
1350: }
1351:
1352: /************************************************************************/
1353: /* wvtbl create volume table entry */
1354: /************************************************************************/
1355: static void
1356: wvtbl()
1357: {
1358: xlvtbl *p;
1359: int ilvl;
1360: int i;
1361:
1362: ilvl = spl5(); /* wait for a new buffer */
1363: while(!(cprb = getrb(&xlfree_q))) {
1364: if (!f.actv)
1365: xlque();
1366: xlfreew = 1;
1367: sleep(&xlfreew, PRIBIO);
1368: }
1369: splx(ilvl);
1370: p = (xlvtbl *)cprb->adr;
1371: wptr = (fpchr)p; /* save ptr for encode */
1372: for (i = 0; vtbl[i]; ++i)
1373: p->ident[i] = vtbl[i];
1374: p->data_seg_num = (unsigned short)data_seg_num;
1375: p->last_seg_num = (unsigned short)curr_seg_num - 1;
1376: for (i = 0; p->op_system[i] = xnxnm[i]; ++i);
1377:
1378: for (ilvl = 0; ilvl < 43; ++ilvl) /* fill zero not implemented */
1379: p->p1[ilvl] = 0;
1380: p->c_seq_num = 1; /* cartridge sequence # =1 */
1381:
1382: for (ilvl = 0; ilvl < 34; ++ilvl) /* fill zero */
1383: p->p3[ilvl] = 0;
1384:
1385: p->last_blk_size = (unsigned short)(lnbr - cnbr);
1386: cprb->sgn = volume_seg_num;
1387: cprb->map = ptr_header[volume_seg_num + 0x200];
1388: cprb->fun = RBFWT;
1389: strbsg(cprb);
1390: xl_enc(wptr, cprb->nbk);
1391: putrb(&req, cprb);
1392: ilvl = spl5();
1393: if (!f.actv)
1394: xlque();
1395: splx(ilvl);
1396: }
1397:
1398: /************************************************************************/
1399: /* xlcal() calibrate drive */
1400: /* exits via (*xlosb)() */
1401: /************************************************************************/
1402: static void
1403: xlcal()
1404: {
1405: if (xlster) { /* exit if error */
1406: (*pfcal)();
1407: return;
1408: }
1409: f.cal = 0; /* reset calibrate sent flag */
1410: pfrdy = xlcal0; /* wait for ready */
1411: xlready();
1412: }
1413:
1414: static void
1415: xlcal0()
1416: {
1417: if (xlster) { /* exit if error */
1418: (*pfcal)();
1419: return;
1420: }
1421: if ((xl6sts & 0xf7) == 0x65) {/* if ok, seek track 0, exit */
1422: printf("xlcal:Seek tk 0 ");
1423: tptrk = 0;
1424: pfsek = pfcal;
1425: xlseek();
1426: return;
1427: }
1428: if ((xl6sts & XLSREF) == 0) {/* if not referenced */
1429: printf("xlcal:calibrate ");
1430: if (f.cal) { /* and calibrate sent, exit */
1431: (*pfcal)();
1432: return;
1433: }
1434: f.cal = 1; /* else send calibrate */
1435: pfint = xlready;
1436: xloutput_step(QIC_CMD_CAL);
1437: return;
1438: }
1439: pfint = xlready; /* rewind tape */
1440: xloutput_step(QIC_CMD_BOT);
1441: }
1442:
1443: /************************************************************************/
1444: /* xlcomplete interrupt sequence complete */
1445: /************************************************************************/
1446: static void
1447: xlcomplete()
1448: {
1449: pfint = xlnull; /* clean up int handler */
1450: xlcompf = 1; /* indicate completion */
1451: if (xlcompw) { /* wake up if waiting */
1452: xlcompw = 0;
1453: wakeup(&xlcompw);
1454: }
1455: }
1456:
1457: /************************************************************************/
1458: /* xldelay delay for cnt ticks */
1459: /************************************************************************/
1460: static void
1461: xldelay(cnt)
1462: int cnt;
1463: {
1464: if (cnt)
1465: timeout(&xldly, cnt, pfdly, 0);
1466: else
1467: timeout(&xldly, cnt, NULL, 0);
1468: }
1469:
1470: /************************************************************************/
1471: /* xldma */
1472: /************************************************************************/
1473: static void
1474: xldma(rw, addr, count)
1475: char rw;
1476: long addr;
1477: int count;
1478: {
1479: int oldpri;
1480:
1481: oldpri = sphi();
1482: outb(DMA1CBPFF, 0);
1483: outb(DMA1WMR, rw);
1484: outb(DMA1BCA2, addr & 0xff);
1485: outb(DMA1BCA2, (addr >> 8) & 0xff);
1486: outb(DMACH2PG, (addr >> 16) & 0xff);
1487: tenmicrosec();
1488: outb(DMA1BCWC2, count & 0xff);
1489: outb(DMA1BCWC2, (count >> 8) & 0xff);
1490: spl(oldpri);
1491: outb(DMA1WSMR, 2);
1492: }
1493:
1494: /************************************************************************/
1495: /* xlfdc_in_byte input byte from fdc */
1496: /************************************************************************/
1497: static unchar
1498: xlfdc_in_byte() /* input byte from fdc */
1499: {
1500: register int d0;
1501:
1502: for (d0 = FDTMO; d0; --d0) { /* wait for ready */
1503:
1504: /* Wait for Request from Master asserted. */
1505: if (inb(FDSTAT) & 0x80) {
1506: /* exit if in output mode */
1507: if ((inb(FDSTAT) & 0x40) == 0)
1508: return(status_buf[7] = -1);
1509: return(inb(FDDATA));
1510: }
1511: }
1512: return(status_buf[7] = -1); /* exit if timeout */
1513: }
1514:
1515: /************************************************************************/
1516: /* xlfdc_out_byte output byte to fdc */
1517: /************************************************************************/
1518: static unchar
1519: xlfdc_out_byte(chr) /* output byte to fdc */
1520: int chr;
1521: {
1522: register int d0;
1523:
1524: for (d0 = FDTMO; d0; --d0) { /* wait for ready */
1525:
1526: /* Wait for Request from Master asserted. */
1527: if (inb(FDSTAT) & 0x80) {
1528: /* exit if in status mode */
1529: if (inb(FDSTAT) & 0x40)
1530: return(status_buf[7] = -1);
1531: outb(FDDATA, chr); /* output byte, exit ok */
1532: return 0;
1533: }
1534: }
1535: return(status_buf[7] = -1); /* exit if timeout */
1536: }
1537:
1538: /************************************************************************/
1539: /* xlfdc_out_str output cmd string to fdc */
1540: /************************************************************************/
1541: static unchar
1542: xlfdc_out_str(cms, cnt) /* output command string */
1543: unchar *cms;
1544: int cnt;
1545: {
1546: register unchar *p0, *p1;
1547:
1548: p0 = cms; /* set up for output */
1549: fdcmd = *p0; /* save command type */
1550: for (p1 = p0 + cnt; p0 != p1; ++p0) {
1551: if (xlfdc_out_byte((int)(*p0)))/* stop if error */
1552: break;
1553: }
1554: return(status_buf[7]); /* exit ok */
1555: }
1556:
1557: /************************************************************************/
1558: /* xlfdc_reset reset fdc */
1559: /************************************************************************/
1560: static void
1561: xlfdc_reset() /* fdc reset */
1562: {
1563: sekcms[1] = 0xff;
1564: status_buf[7] = 0; /* reset error flag */
1565: outb(FDCTRL, fdselr); /* reset fdc */
1566: outb(FDCTRL, fdsel);
1567: }
1568:
1569: /************************************************************************/
1570: /* xlflush flush any pending io's */
1571: /************************************************************************/
1572: static void
1573: xlflush(dev)
1574: {
1575: int ilvl;
1576:
1577: xstop = 1; /* stop any pending reads */
1578: if (f.writ) { /* flush any pending writes */
1579: if (cnbr && cprb->fun == RBFWT) {
1580: xl_enc(wptr, cprb->nbk);
1581: putrb(&req, cprb);
1582: }
1583: ilvl = spl5();
1584: if (!f.actv)
1585: xlque();
1586: splx(ilvl);
1587: wvtbl();
1588: }
1589: ilvl = spl5(); /* wait for idle state */
1590: while(f.actv) {
1591: xlnactw = 1;
1592: sleep(&xlnactw, PRIBIO);
1593: }
1594: splx(ilvl);
1595: cnbr = 0;
1596: xstop = 0;
1597: while(cprb = getrb(&data_queue))/* relse pending read bfrs */
1598: putrb(&xlfree_q, cprb);
1599: while(cprb = getrb(&req)) /* release any pending que bfrs */
1600: putrb(&xlfree_q, cprb);
1601: }
1602:
1603: /************************************************************************/
1604: /* xlfmq format queue handler */
1605: /************************************************************************/
1606: static void
1607: xlfmq()
1608: {
1609: while(xprb = getrb(&req)) { /* while more to do */
1610: if (!f.actv) { /* if not active, start tape */
1611: f.actv = 1;
1612: f.tmov = 1;
1613: pfint = xlfmq0;
1614: xloutput_step(QIC_CMD_FWD);
1615: return;
1616: }
1617: else{
1618: pffms = xlfmq1; /* else, continue format */
1619: xlfms();
1620: return;
1621: }
1622: }
1623:
1624: pfrdy = xlfmq2; /* wait for tape stopped */
1625: xlready();
1626: return;
1627: }
1628:
1629: static void
1630: xlfmq0()
1631: {
1632: pffms = xlfmq1;
1633: xlfms();
1634: return;
1635: }
1636:
1637: static void
1638: xlfmq1()
1639: {
1640: if (xprb->sts) /* set f.werr if error */
1641: f.werr = 1;
1642: putrb(&xlfree_q, xprb); /* relse bfr back to free pool */
1643: if (xlfreew) { /* wakeup if needed */
1644: xlfreew = 0;
1645: wakeup(&xlfreew);
1646: }
1647: xlfmq(); /* start next i/o */
1648: }
1649:
1650: static void
1651: xlfmq2()
1652: {
1653: if (xlnactw) { /* if sleepg on xlnactw, wakeup */
1654: xlnactw = 0;
1655: wakeup(&xlnactw);
1656: }
1657: f.actv = 0; /* rset actv, moving flgs, exit */
1658: f.tmov = 0;
1659: return;
1660: }
1661:
1662: /************************************************************************/
1663: /* xlfms format a segment */
1664: /************************************************************************/
1665: static void
1666: xlfms()
1667: {
1668: pfint = xlfm0; /* set up for format */
1669: xprb->sts = 0;
1670: if (f.werr) { /* if error, do idle int */
1671: xloutput_step(0);
1672: return;
1673: }
1674: fmtcms[1] = unit;
1675: stdma(DMA_Wrmode, xprb->adr, 128);
1676:
1677: xltimout(IOTMO); /* do the format */
1678: xlfdc_out_str(fmtcms, 6);
1679: if (status_buf[7]) { /* exit if nec error */
1680: xltimout(0);
1681: xlster |= XLSNEC;
1682: xprb->sts = 1;
1683: pfint = xlnull;
1684: (*pffms)();
1685: return;
1686: }
1687: }
1688:
1689: static void
1690: xlfm0()
1691: {
1692: if (status_buf[0] & 0xc0)
1693: xprb->sts = 1;
1694: (*pffms)();
1695: }
1696:
1697: /************************************************************************/
1698: /* xlformat format tape, task time */
1699: /************************************************************************/
1700: static int
1701: xlformat(ntrkf)
1702: int ntrkf;
1703: {
1704: int ilvl, i;
1705: fplng p0;
1706:
1707: cmn_err(CE_CONT, "xlformat: formatting %d tracks\n", ntrkf);
1708:
1709: pfint = xlready; /* rewind tape */
1710: pfrdy = xlcomplete;
1711: xloutput_step(QIC_CMD_BOT);
1712: xlwait();
1713: if (xlster)
1714: return 2;
1715:
1716: bcopy((fpchr)xnxvs, ptr_header, 20); /* init header */
1717: bcopy(ptr_header + 4, ptr_header + 5, 16 * 1024 - 20);
1718:
1719: pfint = xlcomplete; /* format mode */
1720: xloutput_step(QIC_CMD_FMD);
1721: xlwait();
1722:
1723: cmn_err(CE_CONT, "writing reference bursts...\n");
1724: pfint = xlready;
1725: pfrdy = xlcomplete;
1726: xloutput_step(QIC_CMD_WRF); /* start wrt reference bursts */
1727: xlwait();
1728:
1729: cmn_err(CE_CONT, "reference bursts write done, starting format...\n");
1730:
1731: f.werr = 0;
1732:
1733: for (fmtrk = 0; fmtrk < ntrkf; fmtrk += 2) {
1734:
1735: tptrk = fmtrk; /* set tape track */
1736: curr_seg_num = fmtrk * nseg_p_track;
1737:
1738: pfint = xlcomplete; /* normal mode */
1739: xloutput_step(QIC_CMD_NMD);
1740: xlwait();
1741:
1742: pfint = xlcomplete; /* format mode */
1743: xloutput_step(QIC_CMD_FMD);
1744: xlwait();
1745: /* format a track pair */
1746: do{
1747: cmn_err(CE_CONT, "\tformatting track %d\n", tptrk);
1748: pfsek = xlcomplete; /* seek to track */
1749: xlseek();
1750: xlwait();
1751: for (last_seg_num = curr_seg_num + nseg_p_track; curr_seg_num != last_seg_num; ++curr_seg_num) {
1752: /* wait for a new buffer */
1753: ilvl = spl5();
1754: while(!(cprb = getrb(&xlfree_q))) {
1755: if (!f.actv)
1756: xlfmq();
1757: xlfreew = 1;
1758: sleep(&xlfreew, PRIBIO);
1759: }
1760: splx(ilvl);
1761: /* set up buffer */
1762: cprb->sgn = curr_seg_num;
1763: strbfm(cprb);
1764: putrb(&req, cprb);
1765: } /* queue up format request */
1766:
1767: ilvl = spl5(); /* track done, wait for idle */
1768: while(f.actv) {
1769: xlnactw = 1;
1770: sleep(&xlnactw, PRIBIO);
1771: }
1772: splx(ilvl);
1773: ++tptrk;
1774: } while(tptrk & 1);
1775: if (f.werr) { /* exit if error formatting */
1776: pfprk = xlcomplete;
1777: xlpark();
1778: xlwait();
1779: return 1;
1780: }
1781:
1782: /* verify a track pair */
1783: pfint = xlcomplete; /* normal mode */
1784: xloutput_step(QIC_CMD_NMD);
1785: xlwait();
1786:
1787: pfint = xlcomplete; /* verify mode */
1788: xloutput_step(QIC_CMD_VMD);
1789: xlwait();
1790:
1791: /* set up for verify */
1792: curr_seg_num = fmtrk * nseg_p_track;
1793: xlrel();
1794: relfdc();
1795: vftrk = -1;
1796:
1797: read_ahead_seg_num = curr_seg_num;/* queue up requests */
1798: while(cprb = getrb(&xlfree_q)) {
1799: cprb->sgn = read_ahead_seg_num;
1800: cprb->map = 0L;
1801: cprb->fun = RBFRD;
1802: strbsg(cprb);
1803: cprb->erc = 3; /* no errors allowed */
1804: putrb(&req, cprb);
1805: ++read_ahead_seg_num;
1806: }
1807: for (last_seg_num = curr_seg_num + 2 * nseg_p_track; curr_seg_num != last_seg_num; ++curr_seg_num ) {
1808: ilvl = spl5(); /* wait for a new buffer */
1809: while(!(cprb = getrb(&data_queue))) {
1810: if (!f.actv)
1811: xlque();
1812: xldataw = 1;
1813: sleep(&xldataw, PRIBIO);
1814: }
1815: splx(ilvl);
1816: if (vftrk != cprb->trk) {
1817: vftrk = cprb->trk;
1818: cmn_err(CE_CONT, "\tverifying track %d\n", vftrk);
1819: }
1820: if (cprb->sts) /* mask out segment if error */
1821: *(ptr_header + 0x200 + cprb->sgn) = 0xffffffffL;
1822: /* generate another request or */
1823: if (read_ahead_seg_num != last_seg_num) {
1824: cprb->sgn = read_ahead_seg_num;
1825: cprb->map = 0L;
1826: cprb->fun = RBFRD;
1827: strbsg(cprb);
1828: cprb->erc = 3;
1829: putrb(&req, cprb);
1830: ++read_ahead_seg_num;
1831: } else {
1832: putrb(&xlfree_q, cprb);
1833: }
1834: } /* release buffer */
1835:
1836: ilvl = spl5(); /* track pair done, wait for idle */
1837: while(f.actv) {
1838: xlnactw = 1;
1839: sleep(&xlnactw, PRIBIO);
1840: }
1841: splx(ilvl);
1842:
1843: getfdc(unit); /* get fdc again */
1844: xlsel(unit);
1845: }
1846:
1847: if (xlster) { /* if fatal error, exit */
1848: pfprk = xlcomplete;
1849: xlpark();
1850: xlwait();
1851: return 1;
1852: }
1853:
1854: pfint = xlcomplete; /* normal mode */
1855: xloutput_step(QIC_CMD_NMD);
1856: xlwait();
1857:
1858: /* done with format / verify */
1859: /* now find out where headers and volumne table go */
1860:
1861: p0 = ptr_header + 0x200;
1862: for (i = 0; *p0++; ++i); /* set hdr segment #'s */
1863: ((fpwrd)ptr_header)[3] = h0sgn = i; /* and vol segment */
1864: do {
1865: ++i;
1866: } while(*p0++);
1867: ((fpwrd)ptr_header)[4] = h1sgn = i;
1868: do {
1869: ++i;
1870: } while(*p0++);
1871: ((fpwrd)ptr_header)[5] = volume_seg_num = i;
1872: /* set last seg number */
1873: ((fpwrd)ptr_header)[6] = last_seg_num = ntrkf * nseg_p_track - 1;
1874:
1875: cmn_err(CE_CONT,
1876: "xlformat: h0sgn %d h1sgn %d volume_seg_num %d last_seg_num %d\n",
1877: h0sgn, h1sgn, volume_seg_num, last_seg_num);
1878:
1879: pfprk = xlcomplete; /* park tape */
1880: xlpark();
1881: xlwait();
1882:
1883: if (volume_seg_num > 10) /* if too many bad segment exit */
1884: return 1;
1885:
1886: xlrel(); /* relse fdc, so xlque can work */
1887: relfdc();
1888:
1889: /* start header writes */
1890: for (curr_seg_num = 0; curr_seg_num <= volume_seg_num; ++curr_seg_num) {
1891: ilvl = spl5(); /* get a buffer */
1892: while(!(cprb = getrb(&xlfree_q))) {
1893: if (!f.actv)
1894: xlque();
1895: xlfreew = 1;
1896: sleep(&xlfreew, PRIBIO);
1897: }
1898: splx(ilvl);
1899: cprb->sgn = curr_seg_num;/* set up for hdr or del adm write */
1900: cprb->map = 0L;
1901: if (ptr_header[curr_seg_num + 0x200]) {
1902: cmn_err(CE_CONT, "-");
1903: cprb->fun = RBWFD;
1904: }
1905: else{
1906: cmn_err(CE_CONT, "*");
1907: cprb->fun = RBFWT;
1908: }
1909: strbsg(cprb);
1910: cptr = (fpchr)cprb->adr;
1911:
1912: bcopy(ptr_header, cptr, 16 * 1024);/* copy in header */
1913: bcopy(cptr + 16 * 1024 - 4, cptr + 16 * 1024, 13 * 1024 - 4);
1914: xl_enc(cptr, cprb->nbk);
1915: putrb(&req, cprb);
1916: } /* queue up the request */
1917:
1918: if (!f.actv) /* activate driver */
1919: xlque();
1920:
1921: ilvl = spl5(); /* wait for idle state */
1922: while(f.actv) {
1923: xlnactw = 1;
1924: sleep(&xlnactw, PRIBIO);
1925: }
1926: splx(ilvl);
1927:
1928: getfdc(unit); /* park tape */
1929: xlsel(unit);
1930: pfprk = xlcomplete;
1931: xlpark();
1932: xlwait();
1933: return 0;
1934: }
1935:
1936: /************************************************************************/
1937: /* xlgtdat get data */
1938: /************************************************************************/
1939: static void
1940: xlgtdat(iop)
1941: IO * iop;
1942: {
1943: caddr_t p0;
1944: fpchr p1;
1945: int ilvl;
1946:
1947: /* set up requests using all free buffers */
1948: xlrqr();
1949:
1950: /* set up to xfer data to user buffer */
1951:
1952: rnbr = iop->io_ioc; /* set request params */
1953: p0 = iop->io.vbase;
1954:
1955: p1 = cptr; /* use local copy of cptr */
1956:
1957: while(rnbr) { /* while more to xfer */
1958: if (curr_seg_num > last_seg_num) {
1959: break;
1960: }
1961: if (!cnbr) { /* if a new segment is needed */
1962: ilvl = spl5(); /* wait for data */
1963: while(!(cprb = getrb(&data_queue))) {
1964: if (!f.actv)
1965: xlque();
1966: xldataw = 1;
1967: sleep(&xldataw, PRIBIO);
1968: }
1969: splx(ilvl);
1970:
1971: /* just got a new buffer from data queue */
1972:
1973: p1 = (fpchr)cprb->adr;
1974: if (cprb->sts) {/* check for errors */
1975: u.u_error = EIO;
1976: }
1977: else{
1978: if (!xl_dec(p1, cprb->nbk, cprb->erc,
1979: cprb->ers[0], cprb->ers[1], cprb->ers[2])) {
1980: u.u_error = EIO;
1981: }
1982: }
1983: /* cnbr = # data bytes */
1984: cnbr = (cprb->nbk - 3) << 10;
1985: if (cprb->sgn != curr_seg_num)
1986: curr_seg_num = cprb->sgn;
1987: if (cprb->sgn == last_seg_num) {
1988: cnbr = lnbr;
1989: }
1990: }
1991: /* copy some data */
1992: rcnt = (cnbr >= rnbr) ? rnbr : cnbr;
1993: copyout(p1, p0, rcnt);
1994: p0 += rcnt; /* adjust pointers and counts */
1995: p1 += rcnt;
1996: rnbr -= rcnt;
1997: cnbr -= rcnt;
1998: iop->io_ioc -= rcnt;
1999: if (!cnbr) { /* release bfr if done */
2000: putrb(&xlfree_q, cprb);
2001: ++curr_seg_num;
2002: xlrqr();
2003: }
2004: } /* set up new read request */
2005:
2006: cptr = p1; /* update cptr */
2007: }
2008:
2009: /************************************************************************/
2010: /* xlhalt halt tape */
2011: /************************************************************************/
2012: static void
2013: xlhalt()
2014: {
2015: /* adjust tpseg for ramp down/up */
2016: if (f.tmov)
2017: tpseg += 2;
2018: f.tmov = 0; /* reset tape moving flag */
2019: if (xlster) { /* exit if error */
2020: (*pfhlt)();
2021: return;
2022: }
2023: pfint = xlready; /* after stop cmd wait for rdy */
2024: pfrdy = pfhlt; /* after ready, exit */
2025: xloutput_step(QIC_CMD_STOP);
2026: }
2027:
2028: /************************************************************************/
2029: /* xlintr xl interrupt handler */
2030: /************************************************************************/
2031: static void
2032: xlintr() /* fdc interrupt handler */
2033: {
2034: register unchar *p0, *p1;
2035:
2036: xltimout(0); /* reset interrupt timeout */
2037:
2038: /*
2039: * Wait for Request from Master asserted in Main Status -
2040: * indicates data register available for read/write.
2041: */
2042: while (inb(FDSTAT) & 0x80 == 0);
2043:
2044: /* FDC busy indicates read/write command in progress. */
2045: if (inb(FDSTAT) & 0x10) { /* br if non-data int */
2046: p0 = status_buf; /* set up */
2047: for (p1 = p0 + 7; p0 != p1; ++p0) {
2048: *p0 = xlfdc_in_byte(); /* store next byte */
2049: if (status_buf[7]) {
2050: xlster |= XLSNEC;
2051: break;
2052: }
2053: }
2054: } else {
2055: /* handle non-I/O int */
2056: for(;;) {
2057: if (xlfdc_out_byte(8))/* start sense int */
2058: break;
2059: status_buf[0] = xlfdc_in_byte();/* get 1st sts byte*/
2060: if (status_buf[7]) {
2061: xlster |= XLSNEC;
2062: break;
2063: }
2064: if (status_buf[0] == 0x80) {/* br if done */
2065: status_buf[0] = unit;
2066: if (xltimoutf) {
2067: xltimoutf = 0;
2068: status_buf[0] = 0xc0;
2069: }
2070: break;
2071: }
2072: status_buf[1] = xlfdc_in_byte();/* get 2nd sts byte*/
2073: /* update track if my unit */
2074: if (unit == (3 & status_buf[0])) {
2075: sekcms[2] = status_buf[1];
2076: }
2077: /* check for more bytes */
2078: }
2079: }
2080: (*pfint)(); /* exit via caller handler */
2081: return;
2082: }
2083:
2084: /************************************************************************/
2085: /* xlnull null interrupt handler */
2086: /************************************************************************/
2087: static void
2088: xlnull()
2089: {
2090: }
2091:
2092: /************************************************************************/
2093: /* xlopn open tape (task time call) */
2094: /************************************************************************/
2095: static int
2096: xlopn(dev)
2097: dev_t dev;
2098: {
2099: register int i;
2100: xlvtbl *pp;
2101:
2102: printf("xlopn ");
2103:
2104: /* try 100 times to see drive ready - will fix this later */
2105: for (i = 0; i < 100; i++) {
2106: xlster = 0; /* reset error status */
2107: xlests = 0;
2108: xl7sts = 0;
2109: pfsts = xlcomplete; /* get drive status */
2110: xlstatus();
2111: xlwait();
2112: printf("try:%d ", i+1);
2113: if (xl6sts & XLSRDY)
2114: break;
2115: }
2116:
2117: xlster &= ~XLSSFT; /* clear soft error bits */
2118: xlests = 0;
2119: xl7sts = 0;
2120:
2121: if (!(xl6sts & XLSCIN)) { /* exit if no cartridge */
2122: printf("no cart ");
2123: xlster |= XLSSFT;
2124: return 2;
2125: }
2126:
2127: if (xlster) { /* exit if fatal error */
2128: printf("fatal error ");
2129: return 2;
2130: }
2131:
2132: if (dev & M_CTL) { /* exit if control open */
2133: volume_seg_num = data_seg_num = 0;
2134: return 0;
2135: }
2136:
2137: if (dev & M_RET) { /* retension if retension_on_open */
2138: pfint = xlready;
2139: pfrdy = xlcomplete;
2140: xloutput_step(QIC_CMD_EOT);
2141: xlwait();
2142: if (xlster) {
2143: printf("another fatal error ");
2144: return 2;
2145: }
2146: }
2147: pfint = xlready; /* rewind tape */
2148: pfrdy = xlcomplete;
2149: xloutput_step(QIC_CMD_BOT);
2150: xlwait();
2151: printf("should now be at BOT ");
2152: if (xlster) {
2153: printf("yet another fatal error ");
2154: return 2;
2155: }
2156:
2157: pfcal = xlcomplete; /* calibrate drive */
2158: xlcal();
2159: xlwait();
2160: printf("should now be referenced ");
2161: if (xlster) { /* exit if fatal error */
2162: printf("still yet another fatal error ");
2163: return 2;
2164: }
2165: i = xl6sts & 0xf7;
2166: if (i == 0x45) { /* return if no ref bursts */
2167: printf("no ref bursts ");
2168: return 1;
2169: }
2170: if (i != 0x65) { /* return general error */
2171: printf("general error ");
2172: xlster |= XLSSFT;
2173: return 2;
2174: }
2175: xprb = getrb(&xlfree_q); /* get a buffer for open */
2176: xprb->sgn = 0; /* set up buffer */
2177: xlopn0:
2178: xprb->map = 0L;
2179: strbsg(xprb);
2180:
2181: ptr_buffer = (fplng)xprb->adr;
2182:
2183: pfpos = xlrds; /* read a segment */
2184: pfrds = xlcomplete;
2185: xlpos();
2186: xlwait();
2187:
2188: if (!xprb->sts) { /* ck for errors */
2189: printf("xlopn trying ecc ");
2190: if (!xl_dec(ptr_buffer, xprb->nbk, xprb->erc,
2191: xprb->ers[0], xprb->ers[1], xprb->ers[2])) {
2192: printf("failed ");
2193: xprb->sts = 1;
2194: } else {
2195: printf("succeeded ");
2196: }
2197: }
2198:
2199: if (xprb->sts) { /* if error, try next segment */
2200: ++xprb->sgn;
2201: if (xprb->sgn < 10 && !xlster) {
2202: goto xlopn0;
2203: }
2204: }
2205: if (xprb->sts) { /* if fatal, return bfr & exit */
2206: putrb(&xlfree_q, xprb);
2207: pfprk = xlcomplete;
2208: xlpark();
2209: xlwait();
2210: printf("fatal ");
2211: return 2;
2212: }
2213:
2214: bcopy(ptr_buffer, ptr_header, HDRSZ); /* copy header data */
2215:
2216: volume_seg_num = ((fpwrd)ptr_header)[5];/* set seg numbers */
2217: data_seg_num = volume_seg_num + 1;
2218:
2219: xprb->sgn = volume_seg_num; /* read in volume segment */
2220: xprb->map = ptr_header[volume_seg_num + 0x200];
2221: strbsg(xprb);
2222: pfpos = xlrds;
2223: pfrds = xlcomplete;
2224: xlpos();
2225: xlwait();
2226:
2227: if (!xprb->sts) { /* ck for errors */
2228: printf("xlopn trying 2nd ecc ");
2229: if (!xl_dec(ptr_buffer, xprb->nbk, xprb->erc,
2230: xprb->ers[0], xprb->ers[1], xprb->ers[2])) {
2231: printf("failed ");
2232: xprb->sts = 1;
2233: } else {
2234: printf("succeeded ");
2235: }
2236: }
2237:
2238: /* set last seg num */
2239: pp = (xlvtbl *)ptr_buffer;
2240: last_seg_num = (int)pp->last_seg_num;
2241: /* set last # bytes */
2242: lnbr = (int)pp->last_blk_size;
2243: putrb(&xlfree_q, xprb); /* return buffer */
2244: pfprk = xlcomplete; /* park tape */
2245: xlpark();
2246: xlwait();
2247: if (xprb->sts) { /* return error if error */
2248: printf("sts err ");
2249: return 2;
2250: }
2251: return 0;
2252: }
2253:
2254: /************************************************************************/
2255: /* xloutput_step output cnt steps */
2256: /************************************************************************/
2257: static void
2258: xloutput_step(cnt) /* output cnt steps */
2259: int cnt;
2260: {
2261:
2262: xlDbPrintCmd(cnt);
2263:
2264: sekcms[1] = unit;
2265: if (sekcms[2] > 80)
2266: sekcms[2] -= cnt;
2267: else
2268: sekcms[2] += cnt;
2269: xlfdc_out_str(sekcms, 3); /* start seek cmd */
2270: if (status_buf[7]) { /* exit if nec error */
2271: xlster |= XLSNEC;
2272: (*pfint)();
2273: }
2274: }
2275:
2276: /************************************************************************/
2277: /* xlpark park tape */
2278: /************************************************************************/
2279: static void
2280: xlpark()
2281: {
2282: if (xlster) { /* exit if error */
2283: (*pfprk)();
2284: return;
2285: }
2286: pfsts = xlpark0; /* clear any drive status */
2287: xlstatus();
2288: }
2289:
2290: static void
2291: xlpark0()
2292: {
2293: if (xlster) { /* exit if error */
2294: (*pfprk)();
2295: return;
2296: }
2297: pfint = xlpark1; /* set normal mode */
2298: xloutput_step(QIC_CMD_NMD);
2299: }
2300:
2301: static void
2302: xlpark1()
2303: {
2304: tpseg = tptrk = 0; /* reset current track, segment */
2305: pfsek = xlpark2; /* seek track 0 */
2306: xlseek();
2307: }
2308:
2309: static void
2310: xlpark2()
2311: {
2312: if (xlster) { /* exit if error */
2313: (*pfprk)();
2314: return;
2315: }
2316: pfint = xlready; /* after rewind, wait for rdy */
2317: pfrdy = pfprk; /* after ready, exit */
2318: xloutput_step(QIC_CMD_BOT); /* start rewind */
2319: }
2320:
2321: /************************************************************************/
2322: /* xlpos position to segment */
2323: /* in: xprb = pointer to r */
2324: /************************************************************************/
2325: static void
2326: xlpos()
2327: {
2328: register int d0;
2329:
2330: cmn_err(CE_CONT, "xlpos ");
2331:
2332: if (xlster) { /* exit if error */
2333: pfint = xlpos0; /* use null int to cleanup stak */
2334: xloutput_step(0);
2335: return;
2336: }
2337: d0 = xprb->trk;
2338: if (tptrk != d0) { /* if not same track */
2339: if ((tptrk ^ d0) & 1) /* adjust tpseg */
2340: tpseg = nseg_p_track + 5 - tpseg;
2341: /* adjust tpseg if 1st seg on trk */
2342: if (!xprb->tps)
2343: tpseg = nseg_p_track;
2344: printf("seek %d->%d ", tptrk, d0);
2345: tptrk = d0; /* seek track */
2346: pfsek = xlpos0;
2347: xlseek();
2348: return;
2349: }
2350:
2351: d0 = xprb->tps; /* d0 = new tpseg */
2352: /* adjust tpseg if 1st seg on trk */
2353: if (!d0)
2354: tpseg = nseg_p_track;
2355: if (d0 == tpseg && f.tmov == 1) { /* exit if on target */
2356: printf("xpos on target ");
2357: (*pfpos)();
2358: return;
2359: }
2360: if (d0 > tpseg) { /* if before target read id */
2361: printf("before: %d < %d ", tpseg, d0);
2362: pfrdi = xlpos2;
2363: if (f.tmov) {
2364: xlreadid();
2365: return;
2366: }
2367: f.tmov = 1;
2368: pfint = xlreadid;
2369: xloutput_step(QIC_CMD_FWD);
2370: return;
2371: }
2372: else{
2373: pfskp = xlpos1; /* else skip backwards */
2374: xlskipb(tpseg - d0);
2375: return;
2376: }
2377: }
2378:
2379: static void
2380: xlpos0() /* new track, tape stopped */
2381: {
2382: register int d0;
2383:
2384: if (xlster) { /* exit if error */
2385: (*pfpos)();
2386: return;
2387: }
2388: d0 = xprb->tps; /* d0 = new tpseg */
2389: /* adjust tpseg if 1st seg on trk */
2390: if (!d0)
2391: tpseg = nseg_p_track;
2392: if (d0 >= tpseg) { /* if before target */
2393: f.tmov = 1;
2394: pfint = xlreadid; /* start tape fwd and read id */
2395: pfrdi = xlpos2;
2396: xloutput_step(QIC_CMD_FWD);
2397: return;
2398: }
2399: else{
2400: pfskp = xlpos1; /* else skip backwards */
2401: xlskipb(tpseg - d0);
2402: return;
2403: }
2404: }
2405:
2406: static void
2407: xlpos1() /* skip backwards done */
2408: {
2409: cmn_err(CE_CONT, "xlpos1()\n");
2410:
2411: if (xlster) { /* exit if error */
2412: (*pfpos)();
2413: return;
2414: }
2415: f.tmov = 1;
2416: if (!xprb->tps) { /* check for 1st seg on trk */
2417: pfint = pfpos;
2418: xloutput_step(QIC_CMD_FWD);
2419: return;
2420: }
2421: pfint = xlreadid; /* start tape fwd and read id's */
2422: pfrdi = xlpos2;
2423: xloutput_step(QIC_CMD_FWD);
2424: }
2425:
2426: static void
2427: xlpos2() /* read id finished */
2428: {
2429: cmn_err(CE_CONT, "xlpos2()");
2430:
2431: if (xlster) { /* exit if error */
2432: (*pfpos)();
2433: return;
2434: }
2435: if (status_buf[0] & 0xc0) { /* error handler */
2436: /* if crc error, read id again */
2437: if (status_buf[1] & 0x20) {
2438: printf("crc err ");
2439: xlreadid();
2440: return;
2441: }
2442: pfhlt = xlpos3;
2443: xlhalt();
2444: return;
2445: }
2446: if (xprb->idc > status_buf[3] ||/* if bef tgt, read id again */
2447: xprb->ids > status_buf[5]) {
2448: printf("before target ");
2449: xlreadid();
2450: return;
2451: }
2452: if (xprb->cyl <= status_buf[3] && /* if past it back up */
2453: xprb->sct <= status_buf[5]) {
2454: pfskp = xlpos1;
2455: xlskipb(9);
2456: return;
2457: }
2458: /* we are at target spot */
2459: tpseg = xprb->tps; /* set tpseg and exit */
2460: (*pfpos)();
2461: }
2462:
2463: static void
2464: xlpos3() /* status complete tape stopped */
2465: {
2466: cmn_err(CE_CONT, "xlpos3()\n");
2467:
2468: if (xlster) { /* exit if error */
2469: (*pfpos)();
2470: return;
2471: }
2472: if (xl6sts & (XLSEOT | XLSBOT)) {/* if end track skip backwd */
2473: pfskp = xlpos1;
2474: xlskipb((int)(nseg_p_track + 5 - xprb->tps));
2475: return;
2476: }
2477: xlster |= XLSNID; /* else can't read id's */
2478: (*pfpos)();
2479: }
2480:
2481: /************************************************************************/
2482: /* xlptdat put data */
2483: /************************************************************************/
2484: static void
2485: xlptdat(iop)
2486: IO * iop;
2487: {
2488: caddr_t p0;
2489: fpchr p1;
2490: int ilvl;
2491:
2492: rnbr = iop->io_ioc; /* set request params */
2493: p0 = iop->io.vbase;
2494: while(rnbr) {
2495: if (!cnbr) { /* if a new buffer is needed */
2496: ilvl = spl5(); /* wait for a new buffer */
2497: while(!(cprb = getrb(&xlfree_q))) {
2498: if (!f.actv)
2499: xlque();
2500: xlfreew = 1;
2501: sleep(&xlfreew, PRIBIO);
2502: }
2503: splx(ilvl);
2504: do{
2505: /* set up segment */
2506: cprb->sgn = curr_seg_num;
2507: cprb->map = ptr_header[curr_seg_num + 0x200];
2508: cprb->fun = RBFWT;
2509: strbsg(cprb);
2510: ++curr_seg_num;
2511: }while(cprb->nbk < 4);
2512: cnbr = (cprb->nbk - 3) << 10; /* set params */
2513: lnbr = cnbr;
2514: cptr = (fpchr)cprb->adr;
2515: wptr = cptr;
2516: } /* save ptr for later encode */
2517: p1 = cptr; /* copy data */
2518: rcnt = (cnbr >= rnbr) ? rnbr : cnbr;
2519: copyin(p0, p1, rcnt);
2520: p0 += rcnt;
2521: p1 += rcnt;
2522: cptr = p1;
2523: rnbr -= rcnt; /* adjust count */
2524: cnbr -= rcnt;
2525: if (!cnbr) { /* if filled, encode and q bfr */
2526: xl_enc(wptr, cprb->nbk);
2527: putrb(&req, cprb);
2528: }
2529: }
2530: iop->io_ioc = 0;
2531: }
2532:
2533: /************************************************************************/
2534: /* xlque process queue request */
2535: /************************************************************************/
2536: static void
2537: xlque()
2538: {
2539: cmn_err(CE_CONT, "xlque()\n");
2540: xlque0:
2541: xprb = getrb(&req); /* get next request */
2542: if (!xprb) { /* if end queue and */
2543: if (f.tmov) { /* if tape moving, stop tape */
2544: cmn_err(CE_CONT, "xlque: stopping\n");
2545: pfhlt = xlque;
2546: xlhalt();
2547: return;
2548: }
2549: cmn_err(CE_CONT, "xlque: inactive\n");
2550:
2551: if (f.actv) { /* if active, release fdc */
2552: xlrel();
2553: relfdc();
2554: }
2555: if (xlnactw) { /* if sleeping on xlnactw, wakeup */
2556: xlnactw = 0;
2557: wakeup(&xlnactw);
2558: }
2559: f.actv = 0; /* reset active flag, exit */
2560: return;
2561: }
2562: if (!f.actv) { /* if called from task (not active) */
2563: getfdc(unit); /* get fdc */
2564: xlsel(unit);
2565: }
2566: f.actv = 1;
2567: switch(xprb->fun) {
2568: case RBFRD: /* read segment */
2569: if (xstop) { /* if stop, ignore request */
2570: putrb(&xlfree_q, xprb);
2571: goto xlque0;
2572: }
2573: pfpos = xlrds;
2574: pfrds = xlqr0;
2575: xlpos();
2576: return;
2577: case RBFWT: /* write segment */
2578: pfpos = xlwts;
2579: pfwts = xlqw0;
2580: xlpos();
2581: return;
2582: case RBWFD: /* write del adr mrk segment */
2583: pfpos = xlwds;
2584: pfwds = xlqw0;
2585: xlpos();
2586: return;
2587: default:
2588: ;
2589: }
2590: }
2591:
2592: static void
2593: xlqr0()
2594: {
2595: putrb(&data_queue, xprb); /* add to data queue */
2596: if (xldataw) { /* wakeup if needed */
2597: xldataw = 0;
2598: wakeup(&xldataw);
2599: }
2600: xlque(); /* start next i/o */
2601: }
2602:
2603: static void
2604: xlqw0()
2605: {
2606: if (xprb->sts) /* set f.werr if error */
2607: f.werr = 1;
2608: putrb(&xlfree_q, xprb); /* relse bfr back to free pool */
2609: if (xlfreew) { /* wakeup if needed */
2610: xlfreew = 0;
2611: wakeup(&xlfreew);
2612: }
2613: xlque(); /* start next i/o */
2614: }
2615:
2616: /************************************************************************/
2617: /* xlrds read segment */
2618: /* in: xprb = pointer to rb */
2619: /************************************************************************/
2620: static void
2621: xlrds()
2622: {
2623: if (xlster || xstop) { /* exit if error or stop */
2624: pfint = xlrd0; /* use null int to cleanup stck */
2625: xloutput_step(0);
2626: return;
2627: }
2628: rwdcms[0] = 0x46; /* set for read */
2629: stseg(xprb);
2630: xrty = 2; /* 2 tries per sector */
2631: xlrd0(); /* start io */
2632: }
2633:
2634: static void
2635: xlrd0() /* initiate io */
2636: {
2637: if (xlster || xstop) { /* exit if error or stop */
2638: printf("xlrd0 - err xlster=%x xstop=%x ", xlster, xstop);
2639: pfint = xlnull;
2640: xprb->sts = 1;
2641: (*pfrds)();
2642: return;
2643: }
2644: pfint = xlrd1; /* set int handler */
2645: xtbl = (xprb->tbl)[xsct - xprb->sct];/* get rb.tbl entry */
2646: if (xtbl) { /* if more data, start other read */
2647: rwdcms[4] = (xtbl & 0x1f) + xprb->sct;
2648: stdma(DMA_Rdmode, xadr | ((xtbl & 0x3e0) << 5), (int)(xtbl & 0xfc00));
2649: xltimout(IOTMO);
2650: xlfdc_out_str(rwdcms, 9);
2651: if (status_buf[7]) { /* exit if nec error */
2652: xltimout(0);
2653: xlster |= XLSNEC;
2654: pfint = xlnull;
2655: (*pfrds)();
2656: return;
2657: }
2658: return;
2659: }
2660: else{ /* else, seg is done */
2661: xprb->sts = 0;
2662: tpseg = xprb->tps + 1;
2663: if (tpseg == nseg_p_track) { /* if last seg on trk, */
2664: pfrdy = pfrds; /* exit via xlready */
2665: xlready();
2666: return;
2667: }
2668: pfint = xlnull; /* else just exit */
2669: (*pfrds)();
2670: return;
2671: }
2672: }
2673:
2674: static void
2675: xlrd1()
2676: {
2677: if (xlster || xstop) { /* exit if error or stop */
2678: printf("xlrd1 - err xlster=%x xstop=%x ", xlster, xstop);
2679: pfint = xlnull;
2680: xprb->sts = 1;
2681: (*pfrds)();
2682: return;
2683: }
2684: if (status_buf[0] & 0xc0) { /* if error */
2685: dsperr();
2686: if (status_buf[2] & 0x40) {/* if del adr mark, exit */
2687: ++tpseg;
2688: goto xlrd2;
2689: }
2690: if (status_buf[0] == 0xc0)/* adjust tpseg */
2691: tpseg += TMSKP;
2692: else{
2693: tpseg += 2;
2694: }
2695: if (tpseg > nseg_p_track)
2696: tpseg = nseg_p_track;
2697:
2698: if (status_buf[0] != 0xc0) { /* if not timeout */
2699: /* if no data read */
2700: if (xsct == status_buf[5]) {
2701: --xrty; /* skip sct if 2nd time */
2702: if (xrty == 0) {
2703: if (xprb->erc < 3) {
2704: xprb->ers[xprb->erc] = xsct-xprb->sct;
2705: ++xprb->erc;
2706: ++xsct;
2707: xrty = 2;
2708: }
2709: else{ /* fail if too many err */
2710: goto xlrd2;
2711: }
2712: }
2713: }
2714: else{ /* some data read in */
2715: xrty = 1; /* 1mor try on this sct */
2716: xsct = status_buf[5];
2717: }
2718: } /* update xsct */
2719: else{ /* if timeout */
2720: --xrty; /* fail if too many err */
2721: if (!xrty) {
2722: xlrd2:
2723: printf("xlrd2 - err xlster=%x xstop=%x ", xlster, xstop);
2724: xprb->sts = 1;
2725: pfint = xlnull;
2726: (*pfrds)();
2727: return;
2728: }
2729: }
2730: pfpos = xlrd0; /* restart io after positioning */
2731: xlpos();
2732: return;
2733: }
2734:
2735: /* no errors, start io for next part of segment (if any) */
2736:
2737: xsct = status_buf[5]; /* update xsct, start next io */
2738: xlrd0();
2739: }
2740:
2741: /************************************************************************/
2742: /* xlreadid read id */
2743: /************************************************************************/
2744: static void
2745: xlreadid()
2746: {
2747: cmn_err(CE_CONT, "xlreadid()");
2748:
2749: pfint = xlreadid0; /* set pfint */
2750: xltimout(IOTMO);
2751: xlfdc_out_str(rdicms, 2); /* start read id cmd */
2752: if (xlster) { /* exit if error */
2753: printf("readid err ");
2754: xltimout(0);
2755: pfint = xlnull;
2756: (*pfrdi)();
2757: return;
2758: }
2759: }
2760:
2761: static void
2762: xlreadid0()
2763: {
2764: pfint = xlnull; /* reset pfint */
2765: (*pfrdi)(); /* and exit */
2766: }
2767:
2768: /************************************************************************/
2769: /* xlready wait for ready */
2770: /************************************************************************/
2771: static void
2772: xlready()
2773: {
2774: if (xlster) { /* exit if error */
2775: (*pfrdy)();
2776: return;
2777: }
2778: pfsts = xlready0; /* get drive status */
2779: xlstatus();
2780: }
2781:
2782: static void
2783: xlready0()
2784: {
2785: if (xlster || (xl6sts & XLSRDY)) { /* exit if done */
2786: (*pfrdy)();
2787: return;
2788: }
2789: xlstatus(); /* else get status again */
2790: }
2791:
2792: /************************************************************************/
2793: /* xlrel release unit */
2794: /************************************************************************/
2795: static void
2796: xlrel()
2797: {
2798: while(0x80 != (0xc0 & inb(FDSTAT))); /* wait for ready */
2799: outb(FDCTRL, 0x0c); /* deselect all units */
2800: xlfdc_out_str(sf3cms, 3); /* set step rate to 3ms */
2801: }
2802:
2803: /************************************************************************/
2804: /* xlreset reset drive */
2805: /************************************************************************/
2806: static void
2807: xlreset()
2808: {
2809: pfint = xlreset0; /* output 1 step */
2810: xloutput_step(QIC_CMD_RST);
2811: }
2812:
2813: static void
2814: xlreset0()
2815: {
2816: pfint = xlnull; /* reset pfint */
2817: pfdly = xlready; /* after delay "wait" for ready */
2818: pfrdy = pfrst; /* after ready, exit via pfrst */
2819: xldelay(HZ); /* start delay */
2820: }
2821:
2822: /************************************************************************/
2823: /* xlrnb report next bit(s) */
2824: /************************************************************************/
2825: static void
2826: xlrnb(cnt)
2827: int cnt;
2828: {
2829: xlrnbw = 0; /* reset status int */
2830: pfint = xlrnb0; /* set int handler */
2831: xlbcnt = cnt; /* set up */
2832: xloutput_step(QIC_CMD_RNB); /* start 2 step seek */
2833: }
2834:
2835: static void
2836: xlrn9() /* get 9 bits */
2837: {
2838: unchar bit;
2839:
2840: /* Sense drive status. */
2841: xlfdc_out_byte(4);
2842: xlfdc_out_byte((int)unit);
2843:
2844: /* Read ST3, look at T0 bit. */
2845: bit = (0x10 & xlfdc_in_byte()) ? 1 : 0;
2846: printf("%d", bit);
2847:
2848: xlrnbw = 0;
2849: pfint = xlrnb0;
2850: xlbcnt = 9;
2851: xloutput_step(QIC_CMD_RNB);
2852: }
2853:
2854: static void
2855: xlrn17() /* get 17 bits */
2856: {
2857: xlrnbw = 0;
2858: pfint = xlrnb0;
2859: xlbcnt = 17;
2860: xloutput_step(QIC_CMD_RNB);
2861: }
2862:
2863: static void
2864: xlrnb0()
2865: {
2866: register int xlrnbb; /* xl2 status bit */
2867: int bit;
2868:
2869: /* Sense drive status. */
2870: xlfdc_out_byte(4);
2871: xlfdc_out_byte((int)unit);
2872:
2873: /* Read ST3, look at T0 bit. */
2874: bit = (0x10 & xlfdc_in_byte()) ? 1 : 0;
2875: printf("%d", bit);
2876:
2877: xlrnbb = bit ? 0x8000 : 0x0000;
2878: if (status_buf[7]) /* exit if nec handshake error */
2879: xlster |= XLSNEC;
2880: if (xlster) {
2881: pfint = xlnull;
2882: (*pfrnb)();
2883: return;
2884: }
2885: --xlbcnt;
2886: if (xlbcnt) { /* if not done, shift in bit */
2887: xlrnbw >>= 1; /* and continue */
2888: xlrnbw |= xlrnbb;
2889: xloutput_step(QIC_CMD_RNB);
2890: return;
2891: } else {
2892: if (!xlrnbb) /* last bit must = 1 */
2893: xlster |= XLSLSB;
2894: pfint = xlnull;
2895: (*pfrnb)(); /* call end step handler */
2896: return;
2897: }
2898: }
2899:
2900: /************************************************************************/
2901: /* xlrqr set up read requests */
2902: /************************************************************************/
2903: static void
2904: xlrqr()
2905: {
2906: while(fprb = getrb(&xlfree_q)) {/* enqueue any free bfrs */
2907: xlrqr0:
2908: if (read_ahead_seg_num > last_seg_num) {
2909: putrb(&xlfree_q, fprb);
2910: break;
2911: }
2912: fprb->sgn = read_ahead_seg_num;
2913: fprb->map = ptr_header[read_ahead_seg_num + 0x200];
2914: fprb->fun = RBFRD;
2915: strbsg(fprb);
2916: if (fprb->nbk < 4) { /* skip if < 4 sectors */
2917: ++read_ahead_seg_num;
2918: goto xlrqr0;
2919: }
2920: putrb(&req, fprb); /* add bfr to req queue */
2921: ++read_ahead_seg_num;
2922: }
2923: }
2924:
2925: /************************************************************************/
2926: /* xlseek seek head to tptrk */
2927: /************************************************************************/
2928: static void
2929: xlseek()
2930: {
2931: if (xlster) { /* exit if error */
2932: (*pfsek)();
2933: return;
2934: }
2935: pfhlt = xlseek0; /* halt tape */
2936: xlhalt();
2937: }
2938:
2939: static void
2940: xlseek0()
2941: {
2942: if (xlster) { /* exit if error */
2943: (*pfsek)();
2944: return;
2945: }
2946: pfint = xlseek1; /* do 13 steps */
2947: xloutput_step(QIC_CMD_SEEK);
2948: }
2949:
2950: static void
2951: xlseek1()
2952: {
2953: if (xlster) { /* exit if error */
2954: (*pfsek)();
2955: return;
2956: }
2957: pfint = xlready; /* after seek "wait" for rdy */
2958: pfrdy = pfsek; /* after ready, exit */
2959: xloutput_step(2 + tptrk);
2960: }
2961:
2962: /************************************************************************
2963: * xlsel select unit, wait for done
2964: ***********************************************************************/
2965: static void
2966: xlsel()
2967: {
2968: fdsel = fdstb[unit];
2969: fdselr = 0xfb & fdsel;
2970: outb(FDCSR1, 0); /* set 500khz speed */
2971: outb(FDCTRL, fdsel); /* select unit */
2972: pfint = xlcomplete; /* reset fdc */
2973: xlfdc_reset();
2974: xlwait();
2975: xlfdc_out_str(sf2cms, 3); /* set step rate to 2ms */
2976:
2977: /* 80 MB nseg_p_track = 100, nseg_p_head = 600, nseg_p_cyl = 4 */
2978: /* 40 MB nseg_p_track = 68, nseg_p_head = 680, nseg_p_cyl = 4 */
2979: if (ftfmt) {
2980: nseg_p_track = 100; /* set for 80 MB drive */
2981: nseg_p_head = 600;
2982: nseg_p_cyl = 4;
2983: } else {
2984: nseg_p_track = 68; /* set for 40 MB drive */
2985: nseg_p_head = 680;
2986: nseg_p_cyl = 4;
2987: }
2988: }
2989:
2990: /************************************************************************/
2991: /* xlskipb skip n segments back */
2992: /************************************************************************/
2993: static void
2994: xlskipb(cnt)
2995: int cnt;
2996: {
2997: if (xlster) { /* exit if error */
2998: (*pfskp)();
2999: return;
3000: }
3001: f.tmov = 0; /* tape will be halted */
3002: xlskip_count = cnt; /* set skip count */
3003: pfint = xlready; /* stop tape first */
3004: pfrdy = xlskipb0;
3005: xloutput_step(QIC_CMD_STOP);
3006: }
3007:
3008: static void
3009: xlskipb0()
3010: {
3011: pfint = xlskipb1; /* start skip back cmd */
3012: xloutput_step(QIC_CMD_SKPB);
3013: }
3014:
3015: static void
3016: xlskipb1()
3017: {
3018: if (xlster) { /* exit if error */
3019: (*pfskp)();
3020: return;
3021: }
3022: pfint = xlskipb2; /* issue 2nd part of cmd */
3023: xloutput_step(2 + (0xf & xlskip_count));
3024: }
3025:
3026: static void
3027: xlskipb2()
3028: {
3029: if (xlster) { /* exit if error */
3030: (*pfskp)();
3031: return;
3032: }
3033: /* after 3rd part cmd, wait for ready */
3034: pfint = xlready;
3035: pfrdy = pfskp; /* after ready, exit */
3036: /* start 3rd part cmd */
3037: xloutput_step(2 + (0xf & (xlskip_count >> 4)));
3038: }
3039:
3040: /************************************************************************/
3041: /* xlstatus() get drive status */
3042: /************************************************************************/
3043: static void
3044: xlstatus()
3045: {
3046: if (xlster) { /* exit if error */
3047: pfint = xlnull;
3048: (*pfsts)();
3049: return;
3050: }
3051: /* after 6 steps, get 9 report bits */
3052: pfint = xlrn9;
3053: pfrnb = xlstatus0; /* after 9 bits, goto xlstatus0 */
3054: xloutput_step(QIC_CMD_STS); /* start steps */
3055: }
3056:
3057: static void
3058: xlstatus0()
3059: {
3060: if (xlster) { /* exit if error */
3061: pfint = xlnull;
3062: (*pfsts)();
3063: return;
3064: }
3065:
3066: xl6sts = xlrnbw >> 8; /* set xl6sts */
3067:
3068: if (xl6sts == 0xff) { /* exit if not tape drive */
3069: xlster |= XLSNTD;
3070: pfint = xlnull;
3071: (*pfsts)();
3072: return;
3073: } else {
3074: xlDbPrintStat(xl6sts);
3075: }
3076:
3077: if (xl6sts & (XLSEXC | XLSCHG)) {/* if exception condition, */
3078: xlests = xl6sts; /* start type 7 status */
3079: pfint = xlrn17;
3080: pfrnb = xlstatus1;
3081: xloutput_step(QIC_CMD_ECD);
3082: return;
3083: }
3084:
3085: if (xlests || !(xl6sts & XLSCIN)) { /* set soft err if needed */
3086: printf("soft err ");
3087: xlster |= XLSSFT;
3088: }
3089:
3090: pfint = xlnull; /* exit */
3091: (*pfsts)();
3092: }
3093:
3094: static void
3095: xlstatus1()
3096: {
3097: if (xlster) { /* exit if error */
3098: pfint = xlnull;
3099: (*pfsts)();
3100: return;
3101: }
3102: xl7sts = xlrnbw; /* save type 7 status */
3103: xlDbPrintErr(xl7sts);
3104: pfint = xlrn9; /* restart normal status sequce */
3105: pfrnb = xlstatus0;
3106: xloutput_step(QIC_CMD_STS);
3107: }
3108:
3109: /************************************************************************
3110: * xltimout set timeout for int
3111: *
3112: * "cnt" is number of ticks. if zero, cancel any pending timeout
3113: ***********************************************************************/
3114: static void
3115: xltimout(cnt)
3116: int cnt;
3117: {
3118: if (cnt)
3119: timeout(&xltmo, cnt, xltimfn, 0);
3120: else
3121: timeout(&xltmo, cnt, NULL, 0);
3122: }
3123:
3124: static void
3125: xltimfn()
3126: {
3127: cmn_err(CE_CONT, "Timeout!!\n");
3128: xltimoutf = 1;
3129: xlfdc_reset();
3130: }
3131:
3132: /************************************************************************/
3133: /* xlwait wait for xlcomplete (xlcompw wakeup) */
3134: /************************************************************************/
3135: static int
3136: xlwait()
3137: {
3138: register int ilvl;
3139:
3140: ilvl = spl5();
3141: while(!xlcompf) { /* wait for xlcompf to be set */
3142: xlcompw = 1;
3143: if (x_sleep(&xlcompw, pritape, slpriSigCatch, "xlwait")) {
3144: printf("xlwait signaled ");
3145: return 1;
3146: }
3147: }
3148: xlcompf = 0; /* reset flag */
3149: splx(ilvl);
3150: return 0;
3151: }
3152:
3153: /************************************************************************/
3154: /* xlwds write del adm segment */
3155: /* in: xprb = pointer to rb */
3156: /************************************************************************/
3157: static void
3158: xlwds()
3159: {
3160: pfwts = pfwds; /* using xlwts */
3161: if (xlster) { /* exit if error */
3162: pfint = xlwt0; /* use null int to cleanup stck */
3163: xloutput_step(0);
3164: return;
3165: }
3166: rwdcms[0] = 0x49; /* set for write del adm */
3167: stseg(xprb);
3168: xrty = 2;
3169: pfint = xlwt1;
3170: xlwt0();
3171: }
3172:
3173: /************************************************************************/
3174: /* xlwts write segment */
3175: /* in: xprb = pointer to rb */
3176: /************************************************************************/
3177: static void
3178: xlwts()
3179: {
3180: if (xlster) { /* exit if error */
3181: pfint = xlwt0; /* use null int to cleanup stck */
3182: xloutput_step(0);
3183: return;
3184: }
3185: rwdcms[0] = 0x45; /* set for write */
3186: stseg(xprb);
3187: xlwt0();
3188: }
3189:
3190: static void
3191: xlwt0() /* start io */
3192: {
3193: if (xlster) { /* exit if error */
3194: xprb->sts = 1;
3195: pfint = xlnull;
3196: (*pfwts)();
3197: return;
3198: }
3199: xtbl = (xprb->tbl)[xsct - xprb->sct];/* get rb.tbl entry */
3200: if (xtbl) { /* if more data start other write */
3201: pfint = xlwt1;
3202: rwdcms[4] = (xtbl & 0x1f) + xprb->sct;
3203: stdma(DMA_Wrmode, xadr | ((xtbl & 0x3e0) << 5), (int)(xtbl & 0xfc00));
3204: xltimout(IOTMO);
3205: xlfdc_out_str(rwdcms, 9);
3206: if (status_buf[7]) { /* exit if nec error */
3207: xltimout(0);
3208: xlster |= XLSNEC;
3209: xprb->sts = 1;
3210: pfint = xlnull;
3211: (*pfwts)();
3212: return;
3213: }
3214: return;
3215: }
3216: else{ /* else, seg is ok */
3217: xprb->sts = 0;
3218: tpseg = xprb->tps + 1;
3219: if (tpseg == nseg_p_track) { /* if last seg on trk, */
3220: pfrdy = pfwts; /* exit via xlready */
3221: xlready();
3222: return;
3223: }
3224: pfint = xlnull; /* else just exit */
3225: (*pfwts)();
3226: return;
3227: }
3228: }
3229:
3230: static void
3231: xlwt1()
3232: {
3233: if (xlster) { /* exit if error */
3234: xprb->sts = 1;
3235: pfint = xlnull;
3236: (*pfwts)();
3237: return;
3238: }
3239: if (status_buf[0] & 0xc0) { /* check for io error */
3240: dsperr();
3241: if (status_buf[0] == 0xc0)/* adjust tpseg */
3242: tpseg += TMSKP;
3243: else
3244: tpseg += 2;
3245: if (status_buf[0] != 0xc0)/* update xsct */
3246: xsct = status_buf[5];
3247: --xrty; /* retry if more to try */
3248: if (xrty) {
3249: pfpos = xlwt0;
3250: xlpos();
3251: return;
3252: }
3253: else{
3254: /* if del adm write, continue */
3255: if (rwdcms[0] == 0x49) {
3256: ++xsct;
3257: xrty = 2;
3258: pfpos = xlwt0;
3259: xlpos();
3260: return;
3261: }
3262: xprb->sts = 1; /* give up on segment, exit */
3263: pfint = xlnull;
3264: (*pfwts)();
3265: return;
3266: }
3267: }
3268: xsct = status_buf[5]; /* if no error, start next io */
3269: xlwt0();
3270: }
3271:
3272: /******************* DEBUG AREA ******************/
3273: static char *qicErr[] = {
3274: "NULL err",
3275: "command received while drive not ready",
3276: "cartridge not present or removed",
3277: "motor speed error (not within 1%)",
3278: "motor speed fault (jammed, or gross speed error)",
3279: "cartridge write protected",
3280: "undefined or reserved command code",
3281: "illegal track address specified for seek",
3282: "illegal command in report subcontext",
3283: "illegal entry into a diagnostic mode",
3284: "broken tape detected (based on hole sensor)",
3285: "warning - read gain setting error",
3286: "command received while error status pending (obsolete)",
3287: "command received while new cartridge pending",
3288: "command illegal or undefined in primary mode",
3289: "command illegal or undefined in format mode",
3290: "command illegal or undefined in verify mode",
3291: "logical forward not at logical BOT in format mode",
3292: "logical EOT before all segments generated",
3293: "command illegal when cartridge not referenced",
3294: "self-diagnostic failed (cannot be cleared)",
3295: "warning EEPROM not initialized, defaults set",
3296: "EEPROM corrupt or hardware failure",
3297: "motion timeout error",
3298: "data segment too long - logical forward or pause",
3299: "transmit overrun (obsolete)",
3300: "power on reset occurred",
3301: "software reset occurred",
3302: "diagnostic mode 1 error",
3303: "diagnostic mode 2 error",
3304: "command received during noninterruptible process",
3305: "rate selection error",
3306: "illegal command while in high speed mode",
3307: "illegal seek segment value"
3308: };
3309:
3310: static char *qicStat[] = {
3311: "drive ready or idle",
3312: "error detected",
3313: "cartridge present",
3314: "cartridge write protected",
3315: "new cartridge",
3316: "cartridge referenced",
3317: "at physical BOT",
3318: "at physical EOT"
3319: };
3320:
3321: static char *qicCmd[] = {
3322: "NULL cmd",
3323: "soft reset",
3324: "report next bit",
3325: "pause",
3326: "micro step pause",
3327: "alternate command timeout",
3328: "report drive status",
3329: "report error code",
3330: "report drive configuration",
3331: "report ROM version",
3332: "logical forward",
3333: "physical reverse",
3334: "physical forward",
3335: "seek head to track",
3336: "seek load point",
3337: "enter format mode",
3338: "write reference burst",
3339: "enter verify mode",
3340: "stop tape",
3341: "reserved (19)",
3342: "reserved (20)",
3343: "micro step head up",
3344: "micro step head down",
3345: "reserved (23)",
3346: "reserved (24)",
3347: "skip n segments reverse",
3348: "skip n segments forward",
3349: "select rate",
3350: "enter diag mode 1",
3351: "enter diag mode 2",
3352: "enter primary mode",
3353: "reserved (31)",
3354: "report vendor ID",
3355: "report tape status",
3356: "skip n segments extended reverse",
3357: "skip n segments extended forward"
3358: };
3359:
3360: /* print 2-byte error status as <error-code,command> */
3361: static void
3362: xlDbPrintErr(errword)
3363: unsigned int errword;
3364: {
3365: unsigned int lo, hi;
3366:
3367: lo = errword & 0xff;
3368: hi = (errword >> 8) & 0xff;
3369:
3370: if (lo >= 1 && lo < sizeof(qicErr)/sizeof(qicErr[0]))
3371: printf("<%s,", qicErr[lo]);
3372: else
3373: printf("<%x,", lo);
3374:
3375: if (hi >= 1 && hi < sizeof(qicCmd)/sizeof(qicCmd[0]))
3376: printf("%s> ", qicCmd[hi]);
3377: else
3378: printf("%x> ", hi);
3379: }
3380:
3381: /* print command as [command] */
3382: static void
3383: xlDbPrintCmd(cmd)
3384: unsigned int cmd;
3385: {
3386: if (cmd >= 1 && cmd < sizeof(qicCmd)/sizeof(qicCmd[0])) {
3387: if (cmd == QIC_CMD_RNB)
3388: putchar ('.');
3389: else
3390: printf("[%s] ", qicCmd[cmd]);
3391: } else
3392: printf("[%d] ", cmd);
3393: }
3394:
3395: /* print tape status as { status string,... } */
3396: static void
3397: xlDbPrintStat(stat)
3398: unsigned int stat;
3399: {
3400: int i;
3401:
3402: printf("{ ");
3403: for (i = 0; i < 8; i++) {
3404: if (stat & (1 << i))
3405: printf("%s, ", qicStat[i]);
3406: }
3407: putchar('}');
3408: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.