|
|
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.