Annotation of coherent/b/STREAMS/io.386/haictexp, revision 1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.