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