|
|
1.1 ! root 1: /*********************************************************************** ! 2: * Module: haict.c ! 3: * ! 4: * Unix device driver functions for accessing SCSI tape drives as ! 5: * character devices. Conforms to Mark Williams Coherent definition ! 6: * of the Unix Device Driver interface for Coherent v4.0.1. ! 7: * ! 8: * Copyright (c) 1993, Christopher Sean Hilton, All Rights Reserved. ! 9: * ! 10: * Last Modified: Thu Jul 15 19:59:42 1993 by [chris] ! 11: * ! 12: * $Id: haictexp,v 1.1 93/07/20 11:21:24 bin Exp Locker: bin $ ! 13: */ ! 14: /*********************************************************************** ! 15: * READ THIS * READ THIS * READ THIS * READ THIS * READ THIS * ! 16: * ! 17: * This module is set up for my tape drive, a Tandberg TDC 3600 which ! 18: * is an oddball so here's why things are set up the way they are. ! 19: * This driver is set up for the possiblility that the tape drive ! 20: * is in an external cabinet from the PC. This means that the tape ! 21: * drive may not be turned on when Coherent comes up and runs through ! 22: * the init routines. Thus the init routine only prints a message ! 23: * to the effect that the driver is here. The open routine handles ! 24: * the details of initializing the tape drive. My TDC 3600 automatically ! 25: * retensions the tape cartridge after the tape is loaded and whenever ! 26: * the drive is reset. I've timed this process at about 160 seconds ! 27: * from start to finish. That is why the open routine will wait for ! 28: * 180 seconds testing the drive through the load/unload command with ! 29: * immediate return. This brings up the important fact that tape drives ! 30: * in general are slow devices and can take a long time to ! 31: * complete operations. During the time when a tape drive is busy ! 32: * handling some action the SCSI driver could be doing something ! 33: * else so use the immediate return options whenever possible. ! 34: */ ! 35: ! 36: #include <stddef.h> ! 37: #include <sys/coherent.h> ! 38: #include <sys/buf.h> ! 39: #include <sys/file.h> ! 40: #include <sys/stat.h> ! 41: #include <sys/sched.h> ! 42: #include <errno.h> ! 43: #include <sys/mtioctl.h> ! 44: ! 45: #include <sys/haiscsi.h> ! 46: ! 47: #define TDC3600 /* Compensate for weirdness */ ! 48: #define FIXED /* Fixed block length reads/writes okay */ ! 49: /* #define VARIABLE Variable Block length reads/writes okay */ ! 50: /* #define SHOWBLKSZ Report blocksize on first open */ ! 51: ! 52: #define REWINDTAPE 0x01 ! 53: #define IMMEDIATE 0x0010 ! 54: #define REQSENSE 0x03 ! 55: #define READBLKLMT 0x05 ! 56: #define READ 0x08 ! 57: #define WRITE 0x0a ! 58: #define WRITEFM 0x10 ! 59: #define SPACE 0x11 ! 60: #define SKIP_BLK 0x00 ! 61: #define SKIP_FM 0x01 ! 62: #define SKIP_SEQFM 0x02 ! 63: #define SKIP_EOT 0x03 ! 64: #define MODESELECT 0x15 ! 65: #define ERASE 0x19 ! 66: #define ERASE_BLOCK 0x0000 ! 67: #define ERASE_TAPE 0x0001 ! 68: #define MODESENSE 0x1a ! 69: #define LOAD 0x1b ! 70: #define RETENSION 0x0020 ! 71: ! 72: /*********************************************************************** ! 73: * The Tandberg TDC3600 requires special handling because it doesn't ! 74: * respond properly to a write when the tape is at the logical end ! 75: * of tape. Tape should be organized as follows: ! 76: * ! 77: * File 1 --------------| File 2-m ! 78: * DATA[1] | ...DATA[n] | FILEMARK | DATA[1-n] | FILEMARK | FILEMARK | ! 79: * ! 80: * The double file marks signify the Logical End of Tape. When a ! 81: * tape opened in write mode is written to and then closed on the ! 82: * no rewind device it is necessary to write a Logical End of tape ! 83: * and then skip backwards over one of the filemarks. This leaves ! 84: * the tape positioned between the two filemarks. When this happens ! 85: * on my Tandberg the drive will then lock up (nice huh?) and fail ! 86: * to do anything until the tape is rewound or retensioned. ! 87: */ ! 88: ! 89: ! 90: #define CTDIRTY 0x0001 ! 91: #define CTCLOSING 0x0002 ! 92: ! 93: #define CTILI 0x0020 /* Sensekey's Illegal Length Indicator */ ! 94: #define CTEOM 0x0040 /* Sensekey's End OF Media bit */ ! 95: #define CTFILEMARK 0x0080 /* Sensekey's Filemark bit */ ! 96: #define CTSKMASK (CTILI | CTEOM | CTFILEMARK) ! 97: #define CTRDMD 0x0100 /* We are reading from the tape */ ! 98: #define CTWRTMD 0x0200 /* we are writeing to the tape */ ! 99: int HAI_CACHESZ = 40 * BSIZE; /* 40 Block Cache for each device */ ! 100: ! 101: typedef enum { ! 102: CTIDLE = 0, ! 103: CTINIT, ! 104: CTFBRD, ! 105: CTVBRD, ! 106: CTFBWRT, ! 107: CTVBWRT, ! 108: CTSENSE, ! 109: CTWRITEFM, ! 110: CTSPACE, ! 111: CTREWIND, ! 112: CTERASE, ! 113: CTLOADRETEN ! 114: } ctstate_t; ! 115: ! 116: typedef struct blkdscr_s *blkdscr_p; ! 117: ! 118: typedef struct blkdscr_s { ! 119: union { ! 120: unsigned char mediatype; ! 121: unsigned long totalblocks; ! 122: } mt; ! 123: union { ! 124: unsigned char reserved; ! 125: unsigned long blocksize; ! 126: } rb; ! 127: } blkdscr_t; ! 128: ! 129: typedef struct ctctrl_s *ctctrl_p; ! 130: ! 131: typedef struct ctctrl_s { ! 132: char *cache, /* Transfer Cache */ ! 133: *start; /* Start of data in cache */ ! 134: size_t avail; /* bytes availaible in cache */ ! 135: ctstate_t state; ! 136: unsigned short inuse, /* In Use flag */ ! 137: flags, /* Flags from device */ ! 138: block; /* Block size of device */ ! 139: srb_t srb; /* SCSI Request block for transfers */ ! 140: } ctctrl_t; ! 141: ! 142: static int ctinit(); /* Initialize a SCSI device at (id) */ ! 143: static void ctopen(); /* Open SCSI tape at (dev) */ ! 144: static void ctclose(); /* Close a SCSI tape at (dev) */ ! 145: static void ctread(); /* Read from SCSI tape at (dev) */ ! 146: static void ctwrite(); /* Write SCSI tape at (dev) */ ! 147: static void ctioctl(); /* I/O Control routine */ ! 148: ! 149: extern int nulldev(); ! 150: extern int nonedev(); ! 151: ! 152: #define min(a, b) ((a) < (b) ? (a) : (b)) ! 153: ! 154: dca_t ctdca = { ! 155: ctopen, /* Open */ ! 156: ctclose, /* Close */ ! 157: nonedev, /* Block No Block point here */ ! 158: ctread, /* Read */ ! 159: ctwrite, /* Write */ ! 160: ctioctl, /* Ioctl */ ! 161: ctinit, /* Load */ ! 162: nulldev, /* Unload */ ! 163: nulldev /* Poll */ ! 164: }; ! 165: ! 166: static ctctrl_p ctdevs[MAXDEVS]; ! 167: ! 168: /*********************************************************************** ! 169: * Utility functions. * ! 170: ***********************************************************************/ ! 171: ! 172: /*********************************************************************** ! 173: * loadtape() ! 174: * ! 175: * Move the tape to the load point. ! 176: */ ! 177: ! 178: static int loadtape(c, opt) ! 179: register ctctrl_p c; ! 180: int opt; ! 181: { ! 182: register srb_p r = &(c->srb); ! 183: register g0cmd_p g0 = &(r->cdb. g0); ! 184: ! 185: c->state = CTLOADRETEN; ! 186: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0; ! 187: r->xferdir = 0; ! 188: r->timeout = 300; ! 189: memset(g0, 0, sizeof(cdb_t)); ! 190: g0->opcode = LOAD; ! 191: g0->xfr_len = 1; ! 192: if (opt & IMMEDIATE) ! 193: g0->lun_lba |= 1; ! 194: if (opt & RETENSION) ! 195: g0->xfr_len |= 2; ! 196: doscsi(r, 4, CVBLKIO, IVBLKIO, SVBLKIO, "loadtape"); ! 197: if (r->status != ST_GOOD && printerror(r, "Load failed")) ! 198: u. u_error = EIO; ! 199: ! 200: c->state = CTIDLE; ! 201: c->flags &= ~(CTFILEMARK | CTEOM); ! 202: return (r->status == ST_GOOD); ! 203: } /* loadtape() */ ! 204: ! 205: /*********************************************************************** ! 206: * writefm() ! 207: * ! 208: * Write Filemarks on the tape. ! 209: */ ! 210: ! 211: static void writefm(c, count) ! 212: register ctctrl_p c; ! 213: int count; ! 214: { ! 215: register srb_p r = &(c->srb); ! 216: register g0cmd_p g0 = &(r->cdb. g0); ! 217: ! 218: c->state = CTWRITEFM; ! 219: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0; ! 220: r->xferdir = 0; ! 221: r->timeout = 40; ! 222: g0->opcode = WRITEFM; ! 223: g0->lun_lba = (r->lun << 5); ! 224: g0->lba_mid = ((unsigned char *) &count)[2]; ! 225: g0->lba_low = ((unsigned char *) &count)[1]; ! 226: g0->xfr_len = ((unsigned char *) &count)[0]; ! 227: g0->control = 0; ! 228: doscsi(r, 4, CVBLKIO, IVBLKIO, SVBLKIO, "writefm"); ! 229: if (r->status != ST_GOOD && printerror(r, "Write filemarks failed")) ! 230: u. u_error = EIO; ! 231: c->state = CTIDLE; ! 232: } /* writefm() */ ! 233: ! 234: /*********************************************************************** ! 235: * space() ! 236: * ! 237: * Space over blocks/filemarks/etc. ! 238: */ ! 239: ! 240: static void space(c, count, object) ! 241: register ctctrl_p c; ! 242: int count; ! 243: int object; ! 244: { ! 245: register srb_p r = &(c->srb); ! 246: register g0cmd_p g0 = &(r->cdb. g0); ! 247: ! 248: c->state = CTSPACE; ! 249: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0; ! 250: r->xferdir = 0; ! 251: r->timeout = 300; ! 252: g0->opcode = SPACE; ! 253: g0->lun_lba = (r->lun << 5) | (object & 3); ! 254: g0->lba_mid = ((unsigned char *) &count)[2]; ! 255: g0->lba_low = ((unsigned char *) &count)[1]; ! 256: g0->xfr_len = ((unsigned char *) &count)[0]; ! 257: g0->control = 0; ! 258: doscsi(r, 2, CVBLKIO, IVBLKIO, SVBLKIO, "space"); ! 259: if (r->status != ST_GOOD && printerror(r, "Space failed")) ! 260: u. u_error = EIO; ! 261: c->state = CTIDLE; ! 262: } /* space() */ ! 263: ! 264: /*********************************************************************** ! 265: * rewind() ! 266: * ! 267: * Rewind the tape drive back to the load point. ! 268: */ ! 269: ! 270: static void rewind(c, wait) ! 271: register ctctrl_p c; ! 272: int wait; ! 273: { ! 274: register srb_p r = &(c->srb); ! 275: register g0cmd_p g0 = &(r->cdb. g0); ! 276: ! 277: c->state = CTREWIND; ! 278: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0; ! 279: r->timeout = 300; ! 280: r->xferdir = 0; ! 281: memset(g0, 0, sizeof(cdb_t)); ! 282: g0->opcode = REWINDTAPE; ! 283: if (!wait) ! 284: g0->lun_lba = (r->lun << 5) | 1; ! 285: doscsi(r, 2, CVBLKIO, IVBLKIO, SVBLKIO, "rewind"); ! 286: if (r->status != ST_GOOD && printerror(r, "Rewind failed")) ! 287: u. u_error = EIO; ! 288: c->flags = 0; ! 289: c->state = CTIDLE; ! 290: } /* rewind() */ ! 291: ! 292: static void erase(c, to_eot) ! 293: register ctctrl_p c; ! 294: int to_eot; ! 295: { ! 296: register srb_p r = &(c->srb); ! 297: register g0cmd_p g0 = &(r->cdb. g0); ! 298: ! 299: c->state = CTERASE; ! 300: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0; ! 301: r->timeout = 300; ! 302: r->xferdir = 0; ! 303: memset(g0, 0, sizeof(cdb_t)); ! 304: g0->opcode = ERASE; ! 305: g0->lun_lba = (r->lun << 5); ! 306: if (to_eot) ! 307: g0->lun_lba |= 1; ! 308: doscsi(r, 2, CVBLKIO, IVBLKIO, SVBLKIO, "erase"); ! 309: if (r->status != ST_GOOD && printerror(r, "Erase failed")) ! 310: u. u_error = EIO; ! 311: if (to_eot) ! 312: c->flags &= ~(CTFILEMARK | CTEOM | CTILI | CTDIRTY); ! 313: c->state = CTIDLE; ! 314: } /* erase() */ ! 315: ! 316: /*********************************************************************** ! 317: * Device Driver Entry Point routines. * ! 318: ***********************************************************************/ ! 319: ! 320: /*********************************************************************** ! 321: * ctinit() ! 322: * ! 323: * Initialize the tape device at (id). This doesn't do anything, ! 324: * not even verify that the drive is there because it could be powered ! 325: * off. ! 326: */ ! 327: ! 328: static int ctinit(id) ! 329: register int id; ! 330: { ! 331: register ctctrl_p c = kalloc(sizeof(ctctrl_t) /* + HAI_CACHESZ */); ! 332: ! 333: if (!c) { ! 334: printf("\tCould not allocate control structure.\n"); ! 335: return 0; ! 336: } ! 337: ! 338: printf("\tCoherent SCSI Tape driver v1.1\n"); ! 339: memset(c, 0, sizeof(ctctrl_t)); ! 340: c->inuse = 0; ! 341: c->cache = NULL; /* ((char *) c) + sizeof(ctctrl_t); */ ! 342: c->srb. target = id; ! 343: c->srb. lun = 0; ! 344: c->state = CTIDLE; ! 345: ctdevs[id] = c; ! 346: return 1; ! 347: } ! 348: ! 349: static void ctopen(dev, mode) ! 350: dev_t dev; ! 351: int mode; ! 352: { ! 353: register ctctrl_p c = ctdevs[tid(dev)]; ! 354: register srb_p r = &(c->srb); ! 355: register g0cmd_p g0 = &(r->cdb. g0); ! 356: int s; ! 357: unsigned long blim; ! 358: char buf[64]; ! 359: blkdscr_p bd = (blkdscr_p) (buf + 4); ! 360: ! 361: if (!c) { ! 362: u. u_error = ENXIO; ! 363: return; ! 364: } ! 365: if ((mode != IPR) && (mode != IPW)) { ! 366: u. u_error = EINVAL; ! 367: return; ! 368: } ! 369: ! 370: s = sphi(); ! 371: ! 372: if (c->inuse) { ! 373: u. u_error = EDBUSY; ! 374: goto done; ! 375: } ! 376: ! 377: c->inuse = 1; ! 378: c->state = CTINIT; ! 379: r->dev = dev; /* Save the rewind bit for close. */ ! 380: ! 381: /*********************************************************************** ! 382: * Repeat the test unit ready command to the tape drive. This should ! 383: * return one of three ways: ! 384: * ! 385: * Either there isn't a tape in the drive and the test unit ready ! 386: * will fail all the time: Sense Key 70 00 02 (Not Ready), ! 387: * ! 388: * Or there is a tape in the drive and the user just put it in ! 389: * there: Sense Key 70 00 06 (Unit Attention - tape changed) ! 390: * ! 391: * Or there is a tape in the drive and it's been in use for a ! 392: * used (No Sense Key data at all). ! 393: * ! 394: * If there is a new tape in the drive then do the load command ! 395: * to make sure that it is ready to go. ! 396: */ ! 397: ! 398: r->timeout = 2; ! 399: r->buf. space = r->buf. addr. vaddr = r->buf. size = 0; ! 400: r->xferdir = 0; ! 401: memset(g0, 0, sizeof(cdb_t)); /* Test Unit Ready */ ! 402: memset(r->sensebuf, 0, sizeof(r->sensebuf)); ! 403: doscsi(r, 4, CVBLKIO, IVBLKIO, SVBLKIO, "ctopen"); ! 404: ! 405: /*********************************************************************** ! 406: * If the command fails there probably wasn't a tape in the drive. ! 407: */ ! 408: ! 409: if (r->status != ST_GOOD) { ! 410: if (r->status != ST_USRABRT) ! 411: u. u_error = ENXIO; ! 412: goto openfailed; ! 413: } ! 414: ! 415: /*********************************************************************** ! 416: * Command Passed: check for sense data which would say that the tape ! 417: * was just loaded. If it was then block here because it is very ! 418: * inconvienent to do so in the block routine. (loadtape needs to ! 419: * use v_sleep). ! 420: */ ! 421: ! 422: else if (r->sensebuf[0] == 0x70 && r->sensebuf[2] == 0x06) { ! 423: if (!loadtape(c, 0)) ! 424: goto openfailed; ! 425: } ! 426: ! 427: /*********************************************************************** ! 428: * Do a mode sense right now to check if the tape is write protected ! 429: * and the user asked for write access. Also need to figure out block ! 430: * size for reads and writes. This will end this fixed/variable ! 431: * nonsense. If you need to use variable block mode I will provide ! 432: * an IO control to swap it. Also this way my Tandberg will be supported ! 433: * just like any other tape drive. ! 434: */ ! 435: ! 436: r->buf. space = KRNL_ADDR; ! 437: r->buf. addr. vaddr = (vaddr_t) buf; ! 438: r->buf. size = sizeof(buf); ! 439: r->xferdir = DMAREAD; ! 440: r->timeout = 2; ! 441: memset(g0, 0, sizeof(cdb_t)); ! 442: g0->opcode = MODESENSE; ! 443: g0->xfr_len = sizeof(buf); ! 444: doscsi(r, 3, CVBLKIO, IVBLKIO, SVBLKIO, "ctopen"); ! 445: if (r->status != ST_GOOD) { ! 446: if (printerror(r, "Mode sense failed")) ! 447: u. u_error = EIO; ! 448: goto openfailed; ! 449: } ! 450: ! 451: /*********************************************************************** ! 452: * If tape drive opened in write mode make sure the tape is not write ! 453: * protected now. ! 454: */ ! 455: ! 456: if (mode == IPW && (buf[2] & 0x80) != 0) { ! 457: devmsg(dev, "Tape is write protected"); ! 458: u. u_error = ENXIO; ! 459: goto openfailed; ! 460: } ! 461: ! 462: /*********************************************************************** ! 463: * If mode sense returned any media descriptors take the first one ! 464: * and use it. This should be the default media type. ! 465: */ ! 466: ! 467: if (buf[3]) { /* If mode sense returned any media descriptors */ ! 468: blim = (bd->rb. blocksize & 0xffffff00); ! 469: flip(blim); ! 470: c->block = blim; ! 471: if (c->block && HAI_CACHESZ % c->block) { ! 472: HAI_CACHESZ -= (HAI_CACHESZ % c->block); ! 473: devmsg(r->dev, "HAI_CACHESZ adjusted to %d bytes", HAI_CACHESZ); ! 474: } ! 475: } ! 476: else { ! 477: u. u_error = ENXIO; ! 478: goto openfailed; ! 479: } ! 480: #ifdef SHOWBLKSZ ! 481: devmsg(dev, "Using blocksize %d bytes", c->block); ! 482: #endif ! 483: ! 484: c->flags = (mode == IPR) ? CTRDMD : CTWRTMD; ! 485: if (c->block) { ! 486: c->cache = kalloc(HAI_CACHESZ); ! 487: if (!c->cache) { ! 488: devmsg(dev, "Could not allocate tape cache"); ! 489: u. u_error = ENOMEM; ! 490: goto openfailed; ! 491: } ! 492: c->avail = (c->flags & CTRDMD) ? 0 : HAI_CACHESZ; ! 493: c->start = c->cache; ! 494: } ! 495: c->state = CTIDLE; ! 496: goto done; ! 497: ! 498: openfailed: ! 499: c->state = CTIDLE; ! 500: c->inuse = 0; ! 501: ! 502: done: ! 503: spl(s); ! 504: } /* ctopen() */ ! 505: ! 506: /*********************************************************************** ! 507: * ctclose() ! 508: * ! 509: * Close the SCSI Device at (dev). ! 510: */ ! 511: ! 512: static void ctclose(dev) ! 513: register dev_t dev; ! 514: { ! 515: register ctctrl_p c = ctdevs[tid(dev)]; ! 516: register srb_p r = &(c->srb); ! 517: int s; ! 518: ! 519: if (!c) { ! 520: u. u_error = EINVAL; ! 521: return; ! 522: } ! 523: ! 524: s = sphi(); ! 525: c->flags |= CTCLOSING; ! 526: flushcache(c); ! 527: while (c->state != CTIDLE) { ! 528: /* x_sleep(&(c->flags), ...); */ ! 529: v_sleep(&(c->flags), CVBLKIO, IVBLKIO, SVBLKIO, "ctclose"); ! 530: if (nondsig()) { ! 531: u. u_error = EINTR; ! 532: break; ! 533: } ! 534: } ! 535: spl(s); ! 536: if (c->cache) { ! 537: kfree(c->cache); ! 538: c->cache = c->start = NULL; ! 539: c->avail = 0; ! 540: } ! 541: ! 542: #ifndef TDC3600 ! 543: /*********************************************************************** ! 544: * Write two filemarks (Logical End of Tape) and then skip backwards ! 545: * over one of them to ready for the another write operation on the ! 546: * no rewind device. This code guarantees properly formed tapes according ! 547: * to the wisened old nine-track hacker that I work with. The problem ! 548: * is that... ! 549: */ ! 550: if (c->flags & CTDIRTY) { ! 551: writefm(c, 1); /* Write a file mark */ ! 552: writefm(c, 1); /* Write another filemark */ ! 553: space(c, -1, SKIP_FM); /* Go back to the first filemark */ ! 554: } ! 555: #else ! 556: /* ! 557: * ... problem is that my Tandberg considers it an error to do anything ! 558: * after it has skipped past a filemark. So all commands except load and ! 559: * rewind fail after the the previous code. The following will work in ! 560: * all situations but there is a risk that a user's tapes will only ! 561: * have one filemark at Logical End-of-Tape if the user isn't careful ! 562: * to use the rewind device the last time he uses tape drive. This is ! 563: * only a problem with drives which insist upon doing a Retension each ! 564: * time the tape is changed or the drive gets reset. ! 565: */ ! 566: if (c->flags & CTDIRTY) { ! 567: writefm(c, 1); ! 568: if (r->dev & REWIND) ! 569: writefm(c, 1); ! 570: } ! 571: #endif ! 572: ! 573: if (r->dev & REWIND) ! 574: rewind(c, 0); ! 575: ! 576: c->inuse = 0; ! 577: return; ! 578: } /* ctclose() */ ! 579: ! 580: /*********************************************************************** ! 581: * fillcache() -- Read from the tape into the cache (really?) ! 582: * ! 583: * return 0 and set u. u_error on any errors. ! 584: */ ! 585: ! 586: static int fillcache(c) ! 587: register ctctrl_p c; ! 588: { ! 589: register srb_p r = (&c->srb); ! 590: register g0cmd_p g0 = &(r->cdb. g0); ! 591: size_t xfrsize; ! 592: extsense_p e; ! 593: int info; ! 594: int retval = 0; ! 595: ! 596: r->buf. space = KRNL_ADDR; ! 597: r->buf. addr. vaddr = (vaddr_t) c->cache; ! 598: r->buf. size = xfrsize = HAI_CACHESZ; ! 599: r->xferdir = DMAREAD; ! 600: r->timeout = 30; ! 601: r->tries = 0; ! 602: g0->opcode = READ; ! 603: g0->lun_lba = (r->lun << 5); ! 604: if (c->block) { ! 605: g0->lun_lba |= 1; ! 606: xfrsize = (xfrsize + c->block - 1) / c->block; ! 607: } ! 608: g0->lba_mid = ((unsigned char *) &xfrsize)[2]; ! 609: g0->lba_low = ((unsigned char *) &xfrsize)[1]; ! 610: g0->xfr_len = ((unsigned char *) &xfrsize)[0]; ! 611: g0->control = 0; ! 612: doscsi(r, 1, CVBLKIO, IVBLKIO, SVBLKIO, "ctblkrd"); ! 613: switch (r->status) { ! 614: case ST_GOOD: ! 615: c->start = c->cache; ! 616: c->avail = r->buf. size; ! 617: retval = 1; ! 618: break; ! 619: case ST_CHKCOND: ! 620: e = r->sensebuf; ! 621: if ((e->errorcode & 0x70) == 0x70) { ! 622: info = 0; ! 623: if (e->errorcode & 0x80) { ! 624: info = e->info; ! 625: flip(info); ! 626: } ! 627: if (e->sensekey & (CTFILEMARK | CTEOM)) { ! 628: c->flags |= (e->sensekey & (CTFILEMARK | CTEOM)); ! 629: c->start = c->cache; ! 630: c->avail = HAI_CACHESZ - (info * c->block); ! 631: retval = 1; ! 632: break; ! 633: } ! 634: } ! 635: printsense(r->dev, "Read failed", r->sensebuf); ! 636: u. u_error = EIO; ! 637: retval = 0; ! 638: break; ! 639: case ST_USRABRT: ! 640: retval = 0; ! 641: break; ! 642: default: ! 643: devmsg(r->dev, "Read failed: status (0x%x)", r->status); ! 644: u. u_error = EIO; ! 645: retval = 0; ! 646: break; ! 647: } ! 648: c->state = CTIDLE; ! 649: return retval; ! 650: } /* fillcache() */ ! 651: ! 652: /*********************************************************************** ! 653: * ctfbrd() -- Fixed block read handler. Reads from the tape ! 654: * drive through the cache when the tape drive is ! 655: * in fixed block mode. ! 656: */ ! 657: ! 658: static void ctfbrd(c, iop) ! 659: register ctctrl_p c; ! 660: register IO *iop; ! 661: { ! 662: register size_t reqcount, /* Total bytes transfered */ ! 663: xfrsize; /* Current transfer size */ ! 664: size_t total, /* System global memory total transfer size */ ! 665: size; /* System global memory current transfer size */ ! 666: ! 667: reqcount = 0; ! 668: while (iop->io_ioc) { ! 669: xfrsize = min(c->avail, iop->io_ioc); ! 670: if (xfrsize) { ! 671: switch (iop->io_seg) { ! 672: case IOSYS: ! 673: memcpy(iop->io. vbase + reqcount, c->start, xfrsize); ! 674: break; ! 675: case IOUSR: ! 676: kucopy(c->start, iop->io. vbase + reqcount, xfrsize); ! 677: break; ! 678: case IOPHY: ! 679: total = 0; ! 680: while (total < xfrsize) { ! 681: size = min(xfrsize - total, NBPC); ! 682: xpcopy(c->start + total, ! 683: iop->io. pbase + reqcount + total, ! 684: size, ! 685: SEG_386_KD | SEG_VIRT); ! 686: total += size; ! 687: } ! 688: break; ! 689: } ! 690: c->start += xfrsize; ! 691: c->avail -= xfrsize; ! 692: reqcount += xfrsize; ! 693: iop->io_ioc -= xfrsize; ! 694: } ! 695: if (iop->io_ioc) { ! 696: if (c->flags & CTFILEMARK) { ! 697: c->flags &= ~CTFILEMARK; ! 698: break; ! 699: } ! 700: ! 701: if (c->flags & CTEOM) { ! 702: u. u_error = EIO; ! 703: break; ! 704: } ! 705: ! 706: if (!fillcache(c)) ! 707: break; ! 708: } ! 709: } /* while */ ! 710: } /* ctfbrd() */ ! 711: ! 712: /*********************************************************************** ! 713: * ctvbrd() -- Variable block read entry point. ! 714: */ ! 715: ! 716: static void ctvbrd(c, iop) ! 717: register ctctrl_p c; ! 718: register IO *iop; ! 719: { ! 720: register srb_p r = &(c->srb); ! 721: register g0cmd_p g0 = &(r->cdb. g0); ! 722: size_t xfrsize; ! 723: extsense_p e; ! 724: int info; ! 725: ! 726: if (c->flags & CTEOM) { ! 727: u. u_error = EIO; ! 728: return; ! 729: } ! 730: if (c->flags & CTFILEMARK) { ! 731: c->flags &= ~CTFILEMARK; ! 732: return; ! 733: } ! 734: c->state = CTVBRD; ! 735: switch (iop->io_seg) { ! 736: case IOSYS: ! 737: r->buf. space = KRNL_ADDR; ! 738: r->buf. addr. vaddr = iop->io. vbase; ! 739: break; ! 740: case IOUSR: ! 741: r->buf. space = USER_ADDR; ! 742: r->buf. addr. vaddr = iop->io. vbase; ! 743: break; ! 744: case IOPHY: ! 745: r->buf. space = PHYS_ADDR; ! 746: r->buf. addr. paddr = iop->io. pbase; ! 747: break; ! 748: } ! 749: r->buf. size = xfrsize = iop->io_ioc; ! 750: r->xferdir = DMAREAD; ! 751: r->timeout = 30; ! 752: g0->opcode = READ; ! 753: g0->lun_lba = (r->lun << 5); ! 754: g0->lba_mid = ((unsigned char *) &xfrsize)[2]; ! 755: g0->lba_low = ((unsigned char *) &xfrsize)[1]; ! 756: g0->xfr_len = ((unsigned char *) &xfrsize)[0]; ! 757: g0->control = 0; ! 758: doscsi(r, 1, CVBLKIO, IVBLKIO, SVBLKIO, "ctvbrd"); ! 759: switch (r->status) { ! 760: case ST_GOOD: ! 761: iop->io_ioc -= r->buf. size; ! 762: break; ! 763: case ST_CHKCOND: ! 764: e = r->sensebuf; ! 765: if ((e->errorcode & 0x70) == 0x70) { ! 766: info = 0; ! 767: if (e->errorcode & 0x80) { ! 768: info = (long) e->info; ! 769: flip(info); ! 770: } ! 771: if (e->sensekey & (CTFILEMARK | CTEOM)) { ! 772: c->flags |= (e->sensekey & (CTFILEMARK | CTEOM)); ! 773: break; ! 774: } ! 775: else if (e->sensekey & CTILI) { ! 776: devmsg(r->dev, ! 777: "Read failed buffer size %d blocksize %d", ! 778: xfrsize, ! 779: xfrsize - info); ! 780: if (info > 0) ! 781: iop->io_ioc -= (xfrsize - info); ! 782: else ! 783: u. u_error = EIO; ! 784: break; ! 785: } ! 786: } ! 787: printsense(r->dev, "Read failed", r->sensebuf); ! 788: u. u_error = EIO; ! 789: break; ! 790: case ST_USRABRT: ! 791: break; ! 792: default: ! 793: devmsg(r->dev, "Read failed: status (0x%x)", r->status); ! 794: u. u_error = EIO; ! 795: break; ! 796: } ! 797: c->state = CTIDLE; ! 798: } /* ctvbrd() */ ! 799: ! 800: /*********************************************************************** ! 801: * ctread() -- OS Read entry point. ! 802: */ ! 803: ! 804: static void ctread(dev, iop) ! 805: dev_t dev; ! 806: register IO *iop; ! 807: { ! 808: register ctctrl_p c = ctdevs[tid(dev)]; ! 809: ! 810: if (!c) { ! 811: u. u_error = EINVAL; ! 812: return; ! 813: } ! 814: ! 815: if (c->block) ! 816: ctfbrd(c, iop); ! 817: else ! 818: ctvbrd(c, iop); ! 819: } /* ctread() */ ! 820: ! 821: /*********************************************************************** ! 822: * flushcache() -- flush the data in the cache to the tape. ! 823: * ! 824: * returns 0 and sets u. u_error on failure else returns 1. ! 825: */ ! 826: ! 827: static int flushcache(c) ! 828: register ctctrl_p c; ! 829: { ! 830: register srb_p r = (&c->srb); ! 831: register g0cmd_p g0 = &(r->cdb. g0); ! 832: size_t xfrsize; ! 833: extsense_p e; ! 834: int info; ! 835: int retval = 0; ! 836: ! 837: r->buf. space = KRNL_ADDR; ! 838: r->buf. addr. vaddr = (vaddr_t) c->cache; ! 839: r->buf. size = xfrsize = HAI_CACHESZ - c->avail; ! 840: r->xferdir = DMAWRITE; ! 841: r->timeout = 30; ! 842: r->tries = 0; ! 843: g0->opcode = WRITE; ! 844: g0->lun_lba = (r->lun << 5); ! 845: if (c->block) { ! 846: g0->lun_lba |= 1; ! 847: xfrsize = (xfrsize + c->block - 1) / c->block; ! 848: } ! 849: g0->lba_mid = ((unsigned char *) &xfrsize)[2]; ! 850: g0->lba_low = ((unsigned char *) &xfrsize)[1]; ! 851: g0->xfr_len = ((unsigned char *) &xfrsize)[0]; ! 852: g0->control = 0; ! 853: doscsi(r, 1, CVBLKIO, IVBLKIO, SVBLKIO, "ctblkwrt"); ! 854: switch (r->status) { ! 855: case ST_GOOD: ! 856: c->start = c->cache; ! 857: c->avail = HAI_CACHESZ; ! 858: retval = 1; ! 859: break; ! 860: case ST_CHKCOND: ! 861: e = r->sensebuf; ! 862: if ((e->errorcode & 0x70) == 0x70) { ! 863: info = 0; ! 864: if (e->errorcode & 0x80) { ! 865: info = e->info; ! 866: flip(info); ! 867: } ! 868: if (e->sensekey & CTEOM) { ! 869: c->flags |= CTEOM; ! 870: devmsg(r->dev, "End of tape on block write"); ! 871: } ! 872: } ! 873: printsense(r->dev, "Read failed", r->sensebuf); ! 874: u. u_error = EIO; ! 875: retval = 0; ! 876: break; ! 877: case ST_USRABRT: ! 878: retval = 0; ! 879: break; ! 880: default: ! 881: devmsg(r->dev, "Read failed: status (0x%x)", r->status); ! 882: u. u_error = EIO; ! 883: retval = 0; ! 884: break; ! 885: } ! 886: c->state = CTIDLE; ! 887: return retval; ! 888: } /* flushcache() */ ! 889: ! 890: /*********************************************************************** ! 891: * ctfbwrt() -- Fixed block write. This should be fast because ! 892: * it uses the tapes drives optimum setting and it ! 893: * goes through a cache. ! 894: */ ! 895: ! 896: static void ctfbwrt(c, iop) ! 897: register ctctrl_p c; ! 898: register IO *iop; ! 899: { ! 900: register size_t reqcount, /* Total bytes transfered */ ! 901: xfrsize; /* Current transfer size */ ! 902: size_t total, /* System global memory total transfer size */ ! 903: size; /* System global memory current transfer size */ ! 904: ! 905: reqcount = 0; ! 906: while (iop->io_ioc) { ! 907: xfrsize = min(c->avail, iop->io_ioc); ! 908: if (xfrsize) { ! 909: switch (iop->io_seg) { ! 910: case IOSYS: ! 911: memcpy(c->start, iop->io. vbase + reqcount, xfrsize); ! 912: break; ! 913: case IOUSR: ! 914: ukcopy(iop->io. vbase + reqcount, c->start, xfrsize); ! 915: break; ! 916: case IOPHY: ! 917: total = 0; ! 918: while (total < xfrsize) { ! 919: size = min(xfrsize - total, NBPC); ! 920: pxcopy(iop->io. pbase + reqcount + total, ! 921: c->start + total, ! 922: size, ! 923: SEG_386_KD | SEG_VIRT); ! 924: total += size; ! 925: } ! 926: break; ! 927: } ! 928: c->start += xfrsize; ! 929: c->avail -= xfrsize; ! 930: reqcount += xfrsize; ! 931: iop->io_ioc -= xfrsize; ! 932: } ! 933: if (iop->io_ioc) { ! 934: if (!flushcache(c)) ! 935: break; ! 936: } ! 937: } /* while */ ! 938: } /* ctfbwrt() */ ! 939: ! 940: /*********************************************************************** ! 941: * ctvbwrt() -- Variable block writes. ! 942: */ ! 943: ! 944: ! 945: static void ctvbwrt(c, iop) ! 946: register ctctrl_p c; ! 947: register IO *iop; ! 948: { ! 949: register srb_p r = &(c->srb); ! 950: register g0cmd_p g0 = &(r->cdb. g0); ! 951: size_t xfrsize; ! 952: extsense_p e; ! 953: int info; ! 954: ! 955: c->state = CTVBWRT; ! 956: switch (iop->io_seg) { ! 957: case IOSYS: ! 958: r->buf. space = KRNL_ADDR; ! 959: r->buf. addr. vaddr = iop->io. vbase; ! 960: break; ! 961: case IOUSR: ! 962: r->buf. space = USER_ADDR; ! 963: r->buf. addr. vaddr = iop->io. vbase; ! 964: break; ! 965: case IOPHY: ! 966: r->buf. space = PHYS_ADDR; ! 967: r->buf. addr. paddr = iop->io. pbase; ! 968: break; ! 969: } ! 970: xfrsize = iop->io_ioc; ! 971: r->buf. size = xfrsize; ! 972: r->xferdir = DMAWRITE; ! 973: r->timeout = 30; ! 974: g0->opcode = WRITE; ! 975: g0->lun_lba = (r->lun << 5); ! 976: g0->lba_mid = ((unsigned char *) &xfrsize)[2]; ! 977: g0->lba_low = ((unsigned char *) &xfrsize)[1]; ! 978: g0->xfr_len = ((unsigned char *) &xfrsize)[0]; ! 979: g0->control = 0; ! 980: doscsi(r, 1, CVBLKIO, IVBLKIO, SVBLKIO, "ctvbwrt"); ! 981: switch (r->status) { ! 982: case ST_GOOD: ! 983: iop->io_ioc -= r->buf. size; ! 984: break; ! 985: case ST_CHKCOND: ! 986: e = r->sensebuf; ! 987: if ((e->errorcode & 0x70) == 0x70) { ! 988: info = 0; ! 989: if (e->errorcode & 0x80) { ! 990: info = (long) e->info; ! 991: flip(info); ! 992: } ! 993: if (e->sensekey & CTEOM) { ! 994: c->flags |= CTEOM; ! 995: devmsg(r->dev, "End of tape"); ! 996: } ! 997: } ! 998: printsense(r->dev, "Write failed", r->sensebuf); ! 999: u. u_error = EIO; ! 1000: break; ! 1001: case ST_USRABRT: ! 1002: break; ! 1003: default: ! 1004: devmsg(r->dev, "Read failed: status (0x%x)", r->status); ! 1005: u. u_error = EIO; ! 1006: break; ! 1007: } ! 1008: c->state = CTIDLE; ! 1009: } /* ctvbwrt() */ ! 1010: ! 1011: /*********************************************************************** ! 1012: * ctwrite() -- Write entry point for tape drive. ! 1013: */ ! 1014: ! 1015: static void ctwrite(dev, iop) ! 1016: register dev_t dev; ! 1017: register IO *iop; ! 1018: { ! 1019: register ctctrl_p c = ctdevs[tid(dev)]; ! 1020: ! 1021: if (!c) { ! 1022: u. u_error = EINVAL; ! 1023: return; ! 1024: } ! 1025: ! 1026: if (c->block) ! 1027: ctfbwrt(c, iop); ! 1028: else ! 1029: ctvbwrt(c, iop); ! 1030: } /* ctwrite() */ ! 1031: ! 1032: /*********************************************************************** ! 1033: * ctioctl() ! 1034: * ! 1035: * I/O Control Entry point for Cartridge tape devices. ! 1036: */ ! 1037: ! 1038: static void ctioctl(dev, cmd /*, vec */) ! 1039: register dev_t dev; ! 1040: register int cmd; ! 1041: /* char *vec; */ ! 1042: { ! 1043: register ctctrl_p c = ctdevs[tid(dev)]; ! 1044: ! 1045: if (!c) { ! 1046: u. u_error = EINVAL; ! 1047: return; ! 1048: } ! 1049: ! 1050: switch (cmd) { ! 1051: case MTREWIND: /* Rewind */ ! 1052: rewind(c, 1); ! 1053: break; ! 1054: case MTWEOF: /* Write end of file mark */ ! 1055: writefm(c, 1); ! 1056: break; ! 1057: case MTRSKIP: /* Record skip */ ! 1058: space(c, 1, SKIP_BLK); ! 1059: break; ! 1060: case MTFSKIP: /* File skip */ ! 1061: space(c, 1, SKIP_FM); ! 1062: break; ! 1063: case MTTENSE: /* Tension tape */ ! 1064: loadtape(c, RETENSION); ! 1065: break; ! 1066: case MTERASE: /* Erase tape */ ! 1067: erase(c, ERASE_TAPE); ! 1068: break; ! 1069: case MTDEC: /* DEC mode */ ! 1070: case MTIBM: /* IBM mode */ ! 1071: case MT800: /* 800 bpi */ ! 1072: case MT1600: /* 1600 bpi */ ! 1073: case MT6250: /* 6250 bpi */ ! 1074: return; ! 1075: default: ! 1076: u. u_error = ENXIO; ! 1077: break; ! 1078: } ! 1079: } /* ctioctl() */ ! 1080: ! 1081: /* End of file */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.