Annotation of coherent/b/STREAMS/io.386/haictexp, revision 1.1.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.