Annotation of coherent/b/STREAMS/io.386/haiCt.c, 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:  *  The philosophy of this driver is to support basic functions on
                      9:  *  the tape drive (read, write, retension, rewind, skip, etc). There
                     10:  *  are more features out there for all the SCSI tape drives out there
                     11:  *  than I know what to do with.  I leave custom support for these
                     12:  *  drives to the people who have them.  To this end this drive will
                     13:  *  blindly follow whatever information it can get using Mode Sense
                     14:  *  and Read Block Limits CDB's.  These tests are done at open time.
                     15:  *  An application can change the operation of the driver by applying
                     16:  *  the mode select command through I/O Control mechanism.
                     17:  *
                     18:  *  Copyright (c) 1993, Christopher Sean Hilton, All Rights Reserved.
                     19:  *
                     20:  *  Last Modified: Mon Jul 26 17:18:59 1993 by [chris]
                     21:  *
                     22:  *  $Id: haict.c,v 2.4 93/08/09 13:45:06 bin Exp Locker: bin $
                     23:  *
                     24:  *  $Log:      haict.c,v $
                     25:  * Revision 2.4  93/08/09  13:45:06  bin
                     26:  * Kernel 82 changes
                     27:  * 
                     28:  */
                     29: 
                     30: #include <stddef.h>
                     31: #include <sys/coherent.h>
                     32: #include <sys/buf.h>
                     33: #include <sys/inode.h>
                     34: #include <sys/stat.h>
                     35: #include <sys/sched.h>
                     36: #include <errno.h>
                     37: #include <sys/mtioctl.h>
                     38: #include <sys/file.h>          /* Louis */
                     39: 
                     40: #include <sys/haiscsi.h>
                     41: #include <sys/haiioctl.h>
                     42: 
                     43: #define REWINDTAPE      0x01
                     44: #define     IMMEDIATE   0x0010
                     45: #define REQSENSE        0x03
                     46: #define READBLKLMT      0x05
                     47: #define READ            0x08
                     48: #define WRITE           0x0a
                     49: #define WRITEFM         0x10
                     50: #define SPACE           0x11
                     51: #define     SKIP_BLK    0x00
                     52: #define     SKIP_FM     0x01
                     53: #define     SKIP_SEQFM  0x02
                     54: #define     SKIP_EOT    0x03
                     55: #define MODESELECT      0x15
                     56: #define ERASE           0x19
                     57: #define     ERASE_BLOCK 0x0000
                     58: #define     ERASE_TAPE  0x0001
                     59: #define MODESENSE       0x1a
                     60: #define LOAD            0x1b
                     61: #define     RETENSION   0x0020
                     62: 
                     63: /***********************************************************************
                     64:  *  The Tandberg TDC3600 requires special handling because it doesn't
                     65:  *  respond properly to a write when the tape is at the logical end
                     66:  *  of tape.  Tape should be organized as follows:
                     67:  *
                     68:  *  File 1 --------------| File 2-m
                     69:  *  DATA[1] | ...DATA[n] | FILEMARK | DATA[1-n] | FILEMARK | FILEMARK |
                     70:  *
                     71:  *  The double file marks signify the Logical End of Tape.  When a
                     72:  *  tape opened in write mode is written to and then closed on the
                     73:  *  no rewind device it is necessary to write a Logical End of tape
                     74:  *  and then skip backwards over one of the filemarks.  This leaves
                     75:  *  the tape positioned between the two filemarks. When this happens
                     76:  *  on my Tandberg the drive will then lock up (nice huh?) and fail
                     77:  *  to do anything until the tape is rewound or retensioned.
                     78:  */
                     79: 
                     80: 
                     81: #define CTDIRTY         0x0001
                     82: #define CTCLOSING       0x0002
                     83: 
                     84: #define CTILI           0x0020      /* Sensekey's Illegal Length Indicator */
                     85: #define CTEOM           0x0040      /* Sensekey's End OF Media bit */
                     86: #define CTFILEMARK      0x0080      /* Sensekey's Filemark bit */
                     87: #define     CTSKMASK    (CTILI | CTEOM | CTFILEMARK)
                     88: #define CTRDMD          0x0100      /* we are reading from the tape */
                     89: #define CTWRTMD         0x0200      /* we are writing to the tape */
                     90: 
                     91: #ifndef HAICACHESZ
                     92: /*
                     93:  *  There wasn't much of a difference in speed between 32 and 40 block
                     94:  *  in my experiance so save as much kalloc memory as possible.
                     95:  */
                     96: 
                     97: #define HAICACHESZ      (32 * BSIZE)/* 32 Block Cache for each device */
                     98: #endif
                     99: 
                    100: #ifndef HAICTVERBOSE
                    101: /*
                    102:  *  HAICTVERBOSE is done as a define because I wanted to be able to use two
                    103:  *  tape drives in my system at one time (why?!).  ld complains if it is a
                    104:  *  patchable constant.  This problem must be solved but products must also
                    105:  *  ship. [csh]
                    106:  */
                    107: 
                    108: #define HAICTVERBOSE    0x0001      /* Switch console messages on/off */
                    109: #endif
                    110: 
                    111: typedef enum {
                    112:     CTIDLE = 0,
                    113:     CTINIT,
                    114:     CTFBRD,
                    115:     CTVBRD,
                    116:     CTFBWRT,
                    117:     CTVBWRT,
                    118:     CTLASTWRT,
                    119:     CTSENSE,
                    120:     CTWRITEFM,
                    121:     CTSPACE,
                    122:     CTREWIND,
                    123:     CTERASE,
                    124:     CTLOADRETEN,
                    125:     CTIOCTL
                    126: } ctstate_t;
                    127: 
                    128: /* Block Descriptors in the mode sense command. */
                    129: 
                    130: typedef struct blkdscr_s *blkdscr_p;
                    131: 
                    132: typedef struct blkdscr_s {
                    133:     union {
                    134:         unsigned char   mediatype;
                    135:         unsigned long   totalblocks;
                    136:     } mt;
                    137:     union {
                    138:         unsigned char reserved;
                    139:         unsigned long blocksize;
                    140:     } rb;
                    141: } blkdscr_t;
                    142: 
                    143: typedef struct blklim_s *blklim_p;
                    144: 
                    145: typedef struct blklim_s {
                    146:     unsigned        blmax;      /* Maximum size for Reads/Writes */
                    147:     unsigned short  blmin;      /* Minimum size for Reads/Writes */
                    148: } blklim_t;
                    149: 
                    150: typedef struct ctctrl_s *ctctrl_p;
                    151: 
                    152: typedef struct ctctrl_s {
                    153:     char            *cache,     /* Transfer Cache */
                    154:                     *start;     /* Start of data in cache */
                    155:     size_t          cachesize,  /* Size of cache */
                    156:                     avail;      /* bytes availaible in cache */
                    157:     ctstate_t       state;
                    158:     unsigned        block,      /* Block size of device */
                    159:                     blmax;      /* Block limits maximum */
                    160:     unsigned short  blmin,      /* Block Limits minimum */
                    161:                     flags,      /* Flags from device */
                    162:                     inuse;      /* In Use flag */
                    163:     srb_t           srb;        /* SCSI Request block for transfers */
                    164: } ctctrl_t;
                    165: 
                    166: static int ctinit();        /* Initialize a SCSI device at (id) */
                    167: static void ctopen();       /* Open SCSI tape at (dev) */
                    168: static void ctclose();      /* Close a SCSI tape at (dev) */
                    169: static void ctread();       /* Read from SCSI tape at (dev) */
                    170: static void ctwrite();      /* Write SCSI tape at (dev) */
                    171: static void ctioctl();      /* I/O Control routine */
                    172: static int fillcache();     /* Fill the tape cache */
                    173: static int flushcache();    /* Flush the tape cache */
                    174: 
                    175: extern int nulldev();
                    176: extern int nonedev();
                    177: 
                    178: #define min(a, b)           ((a) < (b) ? (a) : (b))
                    179: 
                    180: #ifdef TDC3600
                    181: #define ctdca   haict3600
                    182: #endif
                    183: 
                    184: dca_t ctdca = {
                    185:     ctopen,         /* Open */
                    186:     ctclose,        /* Close */
                    187:     hainonblk,      /* No Block point here but don't just drop Buffers */
                    188:     ctread,         /* Read */
                    189:     ctwrite,        /* Write */
                    190:     ctioctl,        /* Ioctl */
                    191:     ctinit,         /* Load */
                    192:     nulldev,        /* Unload */
                    193:     nulldev         /* Poll */
                    194: };
                    195: 
                    196: static ctctrl_p         ctdevs[MAXDEVS];
                    197: 
                    198: /***********************************************************************
                    199:  *  Utility functions.                                                 *
                    200:  ***********************************************************************/
                    201: 
                    202: #define ctvmsg(l, cmd) { if (HAICTVERBOSE & (l)) { (cmd); } }
                    203: 
                    204: /***********************************************************************
                    205:  *  ctbusywait()
                    206:  *
                    207:  *  Wait for the tape drive state to return to idle.  This is easy
                    208:  *  for two reasons: 1) With no block entry point its safe to sleep
                    209:  *  at any time.  2) We shouldn't really need this anyhow.  This is
                    210:  *  unneccessary because without a block routine and with only one
                    211:  *  process able to open the tape drive at a time the state of the
                    212:  *  tape drive driver is well defined.  So, why is it here you ask?
                    213:  *  because one day some user might fork a process that owns the tape
                    214:  *  drive.  This would cause 40 days and nights worth of rain etc.
                    215:  *  Now all that will happen is both processes will be able to write/read
                    216:  *  from the tape drive and the data that they get will be complete
                    217:  *  garbage.  However, the kernel will not break.
                    218:  */
                    219: 
                    220: static int ctbusywait(c, newstate)
                    221: register ctctrl_p   c;
                    222: register ctstate_t  newstate;
                    223: {
                    224:     register int    s;
                    225:     int             retval;
                    226: 
                    227:     s = sphi();
                    228:     retval = 1;
                    229:     while (c->state != CTIDLE)
                    230:         if (x_sleep(&(c->srb. status), pritape, slpriSigCatch, "ctbsywt")) {
                    231:             u. u_error = EINTR;
                    232:             retval = 0;
                    233:             break;
                    234:         }
                    235:     c->state = newstate;
                    236:     spl(s);
                    237:     return retval;
                    238: }   /* ctbusywait() */
                    239: 
                    240: /***********************************************************************
                    241:  *  loadtape()
                    242:  *
                    243:  *  Move the tape to the load point.
                    244:  */
                    245: 
                    246: static int loadtape(c, opt)
                    247: register ctctrl_p c;
                    248: int opt;
                    249: {
                    250:     register srb_p      r = &(c->srb);
                    251:     register g0cmd_p    g0 = &(r->cdb. g0);
                    252: 
                    253:     if (!ctbusywait(c, CTLOADRETEN))
                    254:         return 0;
                    255:     r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
                    256:     r->xferdir = 0;
                    257:     r->timeout = 300;
                    258:     memset(g0, 0, sizeof(cdb_t));
                    259:     g0->opcode = LOAD;
                    260:     g0->xfr_len = 1;        /* Move tape to load point. */
                    261:     if (opt & IMMEDIATE)
                    262:         g0->lun_lba |= 1;
                    263:     if (opt & RETENSION)
                    264:         g0->xfr_len |= 2;
                    265:     doscsi(r, 4, pritape, slpriSigCatch, "loadtape");
                    266:     if (r->status != ST_GOOD && printerror(r, "Load failed"))
                    267:         u. u_error = EIO;
                    268: 
                    269:     c->state = CTIDLE;
                    270:     c->flags &= ~(CTFILEMARK | CTEOM);
                    271:     return (r->status == ST_GOOD);
                    272: }   /* loadtape() */
                    273: 
                    274: /***********************************************************************
                    275:  *  writefm()
                    276:  *
                    277:  *  Write Filemarks on the tape.
                    278:  */
                    279: 
                    280: static void writefm(c, count)
                    281: register ctctrl_p c;
                    282: int count;
                    283: {
                    284:     register srb_p      r = &(c->srb);
                    285:     register g0cmd_p    g0 = &(r->cdb. g0);
                    286: 
                    287:     if (!ctbusywait(c, CTWRITEFM))
                    288:         return;
                    289:     r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
                    290:     r->xferdir = 0;
                    291:     r->timeout = 40;
                    292:     g0->opcode = WRITEFM;
                    293:     g0->lun_lba = (r->lun << 5);
                    294:     g0->lba_mid = ((unsigned char *) &count)[2];
                    295:     g0->lba_low = ((unsigned char *) &count)[1];
                    296:     g0->xfr_len = ((unsigned char *) &count)[0];
                    297:     g0->control = 0;
                    298:     doscsi(r, 4, pritape, slpriSigCatch, "writefm");
                    299:     if (r->status != ST_GOOD && printerror(r, "Write filemarks failed"))
                    300:         u. u_error = EIO;
                    301:     c->state = CTIDLE;
                    302: }   /* writefm() */
                    303: 
                    304: /***********************************************************************
                    305:  *  space()
                    306:  *
                    307:  *  Space over blocks/filemarks/etc.
                    308:  */
                    309: 
                    310: static void space(c, count, object)
                    311: register ctctrl_p c;
                    312: int count;
                    313: int object;
                    314: {
                    315:     register srb_p      r = &(c->srb);
                    316:     register g0cmd_p    g0 = &(r->cdb. g0);
                    317: 
                    318:     if (!ctbusywait(c, CTSPACE))
                    319:         return;
                    320:     r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
                    321:     r->xferdir = 0;
                    322:     r->timeout = 300;
                    323:     g0->opcode = SPACE;
                    324:     g0->lun_lba = (r->lun << 5) | (object & 3);
                    325:     g0->lba_mid = ((unsigned char *) &count)[2];
                    326:     g0->lba_low = ((unsigned char *) &count)[1];
                    327:     g0->xfr_len = ((unsigned char *) &count)[0];
                    328:     g0->control = 0;
                    329:     doscsi(r, 2, pritape, slpriSigCatch, "space");
                    330:     if (r->status != ST_GOOD && printerror(r, "Space failed"))
                    331:         u. u_error = EIO;
                    332:     c->state = CTIDLE;
                    333: }   /* space() */
                    334: 
                    335: /***********************************************************************
                    336:  *  rewind()
                    337:  *
                    338:  *  Rewind the tape drive back to the load point.
                    339:  */
                    340: 
                    341: static void rewind(c, wait)
                    342: register ctctrl_p c;
                    343: int wait;
                    344: {
                    345:     register srb_p      r = &(c->srb);
                    346:     register g0cmd_p    g0 = &(r->cdb. g0);
                    347: 
                    348:     if (!ctbusywait(c, CTREWIND))
                    349:         return;
                    350:     r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
                    351:     r->timeout = 300;
                    352:     r->xferdir = 0;
                    353:     memset(g0, 0, sizeof(cdb_t));
                    354:     g0->opcode = REWINDTAPE;
                    355:     if (!wait)
                    356:         g0->lun_lba = (r->lun << 5) | 1;
                    357:     doscsi(r, 2, pritape, slpriSigCatch, "rewind");
                    358:     if (r->status != ST_GOOD && printerror(r, "Rewind failed"))
                    359:         u. u_error = EIO;
                    360:     c->flags = 0;
                    361:     c->state = CTIDLE;
                    362: }   /* rewind() */
                    363: 
                    364: static void erase(c, to_eot)
                    365: register ctctrl_p c;
                    366: int to_eot;
                    367: {
                    368:     register srb_p      r = &(c->srb);
                    369:     register g0cmd_p    g0 = &(r->cdb. g0);
                    370: 
                    371:     if (!ctbusywait(c, CTERASE))
                    372:         return;
                    373:     r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
                    374:     r->timeout = 300;
                    375:     r->xferdir = 0;
                    376:     memset(g0, 0, sizeof(cdb_t));
                    377:     g0->opcode = ERASE;
                    378:     g0->lun_lba = (r->lun << 5);
                    379:     if (to_eot)
                    380:         g0->lun_lba |= 1;
                    381:     doscsi(r, 2, pritape, slpriSigCatch, "erase");
                    382:     if (r->status != ST_GOOD && printerror(r, "Erase failed"))
                    383:         u. u_error = EIO;
                    384:     if (to_eot)
                    385:         c->flags &= ~(CTFILEMARK | CTEOM | CTILI | CTDIRTY);
                    386:     c->state = CTIDLE;
                    387: }   /* erase() */
                    388: 
                    389: /***********************************************************************
                    390:  *  Device Driver Entry Point routines.                                *
                    391:  ***********************************************************************/
                    392: 
                    393: /***********************************************************************
                    394:  *  ctinit()
                    395:  *
                    396:  *  Initialize the tape device at (id).  This doesn't do anything,
                    397:  *  not even verify that the drive is there because it could be powered
                    398:  *  off.
                    399:  */
                    400: 
                    401: static int ctinit(id)
                    402: register int id;
                    403: {
                    404:     register ctctrl_p c = kalloc(sizeof(ctctrl_t));
                    405: 
                    406:     if (!c) {
                    407:         printf("\tTape Driver: Could not allocate control structure.\n");
                    408:         return 0;
                    409:     }
                    410: 
                    411:     printf("\tCoherent SCSI Tape driver v1.1\n");
                    412:     memset(c, 0, sizeof(ctctrl_t));
                    413:     c->inuse = 0;
                    414:     c->cache = c->start = NULL;
                    415:     c->cachesize = HAICACHESZ;
                    416:     c->srb. target = id;
                    417:     c->srb. lun = 0;
                    418:     c->state = CTIDLE;
                    419:     ctdevs[id] = c;
                    420:     return 1;
                    421: }
                    422: 
                    423: static void ctopen(dev, mode)
                    424: dev_t   dev;
                    425: int mode;
                    426: {
                    427:     register ctctrl_p   c = ctdevs[tid(dev)];
                    428:     register srb_p      r = &(c->srb);
                    429:     register g0cmd_p    g0 = &(r->cdb. g0);
                    430:     int                 rblerf;         /* read block limits error flag */
                    431:     int                 s;
                    432:     char                buf[64];
                    433:     blkdscr_p           bd = (blkdscr_p) (buf + 4);
                    434:     blklim_p            bl = (blklim_p) (buf);
                    435: 
                    436:     if (!c) {
                    437:         u. u_error = ENXIO;
                    438:         return;
                    439:     }
                    440:     if ((mode != IPR) && (mode != IPW)) {
                    441:         u. u_error = EINVAL;
                    442:         return;
                    443:     }
                    444: 
                    445:     s = sphi();
                    446: 
                    447:     if (c->inuse) {
                    448:         u. u_error = EDBUSY;
                    449:         goto done;
                    450:     }
                    451: 
                    452:     c->inuse = 1;
                    453:     c->state = CTINIT;
                    454:     r->dev = dev;      /* Save the rewind bit for close. */
                    455: 
                    456: /***********************************************************************
                    457:  *  Repeat the test unit ready command to the tape drive.  This tells
                    458:  *  the state of the tape drive.  Repeating the command also clears out
                    459:  *  the request sense condition which comes after each time the user
                    460:  *  changes tapes.
                    461:  */
                    462: 
                    463:     r->timeout = 2;
                    464:     r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
                    465:     r->xferdir = 0;
                    466:     memset(g0, 0, sizeof(cdb_t));       /* Test Unit Ready */
                    467:     memset(r->sensebuf, 0, sizeof(r->sensebuf));
                    468:     doscsi(r, 4, pritape, slpriSigCatch, "ctopen");
                    469: 
                    470: /***********************************************************************
                    471:  *  If the command fails there probably wasn't a tape in the drive.
                    472:  */
                    473: 
                    474:     if (r->status != ST_GOOD) {     /* Is there a tape in the drive? */
                    475:         if (r->status != ST_USRABRT) {
                    476:             /* Otherwise assume no tape. */
                    477:             u. u_error = ENXIO;
                    478:             devmsg(r->dev, "Tape drive not ready.");
                    479:             goto openfailed;
                    480:         }
                    481:     }
                    482: #ifdef TDC3600
                    483: 
                    484: /***********************************************************************
                    485:  *  TDC3600's do a retension after all bus device resets and tape changes
                    486:  *  so I block in the open routine waiting for that operation to complete.
                    487:  *  This is a kludge to fix the author's system.  I anticipate that
                    488:  *  other host adapters may not be so kind about retrying commands
                    489:  *  until a device reports that it is no longer busy.  Hence the error
                    490:  *  message when this command fails. All this really does is allows
                    491:  *  me to safely start applications while the initial retension is still
                    492:  *  happening [csh].
                    493:  */
                    494: 
                    495:     else {
                    496:         if (r->sensebuf[0] == 0x70 && r->sensebuf[2] == 0x06) {
                    497: 
                    498:             /* Yep, The user just put it there */
                    499: 
                    500:             r->buf. space = (int) r->buf. addr. caddr = r->buf. size = 0;
                    501:             r->xferdir = 0;
                    502:             r->timeout = 300;
                    503:             memset(g0, 0, sizeof(cdb_t));
                    504:             g0->opcode = LOAD;
                    505:             g0->xfr_len = 1;        /* Move tape to load point. */
                    506:             doscsi(r, 4, pritape, slpriSigCatch, "ctopen");
                    507:             if (r->status != ST_GOOD &&
                    508:                 printerror(r, "Load failed - TDC3600 not ready")) {
                    509:                 u. u_error = ENXIO;
                    510:                 goto openfailed;
                    511:             }
                    512:         }
                    513:     }
                    514: #endif
                    515: 
                    516:     ctvmsg(0x0100, (devmsg(r->dev, "Read block limits.")));
                    517: #ifdef TDC3600
                    518:     c->blmin = c->blmax = 512;
                    519:     ctvmsg(0x0100, (devmsg(r->dev, "Tandberg TDC36XX - Block limits set")));
                    520:     rblerf = 0;
                    521: #else
                    522:     r->buf. space = KRNL_ADDR;
                    523:     r->buf. addr. caddr = (caddr_t) bl;
                    524:     r->buf. size = sizeof(blklim_t);
                    525:     r->xferdir = DMAREAD;
                    526:     r->timeout = 2;
                    527:     memset(g0, 0, sizeof(cdb_t));
                    528:     g0->opcode = READBLKLMT;
                    529:     g0->xfr_len = 6;
                    530:     doscsi(r, 3, pritape, slpriSigCatch, "ctopen");
                    531: 
                    532: /***********************************************************************
                    533:  *  This is a bit oblique:  The Read Block limits is used to determine
                    534:  *  what the tape drive that we have can do.  I have yet to run into
                    535:  *  a tape drive that can do variable mode yet so I'm just winging
                    536:  *  this.  In any case all I did was make it okay for the Archive Tape
                    537:  *  drives to say "I don't support that command".
                    538:  */
                    539: 
                    540:     if (rblerf = (r->status != ST_GOOD)) {
                    541:         ctvmsg(0x0010, (printerror(r, "Read Block LImits")));
                    542:         c->blmax = c->blmin = 0;
                    543:     }
                    544:     else {
                    545:         flip(bl->blmax);    /* SCSI to INTEL order */
                    546:         flip(bl->blmin);    /* Ditto */
                    547:         c->blmax = (bl->blmax & 0x00ffffff);
                    548:         c->blmin = bl->blmin;
                    549:     }
                    550: #endif
                    551: 
                    552: /***********************************************************************
                    553:  *  Use mode sense to find out if the tape is write protected and also
                    554:  *  to find out what the current tape blocksize is.
                    555:  */
                    556: 
                    557:     r->buf. space = KRNL_ADDR;
                    558:     r->buf. addr. caddr = (caddr_t) buf;
                    559:     r->buf. size = sizeof(buf);
                    560:     r->xferdir = DMAREAD;
                    561:     r->timeout = 2;
                    562:     memset(g0, 0, sizeof(cdb_t));
                    563:     g0->opcode = MODESENSE;
                    564:     g0->xfr_len = sizeof(buf);
                    565:     doscsi(r, 3, pritape, slpriSigCatch, "ctopen");
                    566:     if (r->status != ST_GOOD) {
                    567:         if (printerror(r, "Mode sense failed"))
                    568:             u. u_error = EIO;
                    569:         goto openfailed;
                    570:     }
                    571: 
                    572: /***********************************************************************
                    573:  *  If tape drive opened in write mode make sure the tape is not write
                    574:  *  protected now.
                    575:  */
                    576: 
                    577:     if (mode == IPW && (buf[2] & 0x80) != 0) {
                    578:         devmsg(dev, "Tape is write protected");
                    579:         u. u_error = ENXIO;
                    580:         goto openfailed;
                    581:     }
                    582: 
                    583: /***********************************************************************
                    584:  *  If mode sense returned any media descriptors take the first one,
                    585:  *  it's the default, and use it.
                    586:  *
                    587:  *  There are two possible pitfalls here:
                    588:  *
                    589:  *      1) According to SCSI-1 it not an error to return zero block
                    590:  *  descriptors.  If you're favorite drive returns zero block descriptors
                    591:  *  this driver will fail here.
                    592:  *
                    593:  *      2)  I am assuming that the first media descriptor returned is
                    594:  *  the "current" media type which the drive expects to use.  This
                    595:  *  works with SCSI-2 but SCSI-1 says that the first descriptor is
                    596:  *  the "default" media type.  SCSI-1 is lacking in the definition
                    597:  *  of "default" for my conservative taste (when programming is
                    598:  *  concerned).
                    599:  *
                    600:  *  I would like to put the issue of supporting real oddball tape drives
                    601:  *  like my Tandberg to rest and only have one source source file for
                    602:  *  scsi tape drives but I don't think that will work.  In the future
                    603:  *  there will probably be two or maybe three if DAT proves to be as
                    604:  *  much fun as this is.
                    605:  */
                    606: 
                    607:     if (buf[3]) {   /* If mode sense returned any media descriptors */
                    608:         bd->rb. blocksize &= 0xffffff00;
                    609:         flip(bd->rb. blocksize);
                    610:         c->block = bd->rb. blocksize;
                    611:         if (c->block && c->cachesize % c->block)
                    612:             c->cachesize -= (c->cachesize % c->block);
                    613:     }
                    614:     else {
                    615:         devmsg(r->dev, "No media descriptors: Contact Mark Williams Tech support");
                    616:         u. u_error = ENXIO;
                    617:         goto openfailed;
                    618:     }
                    619:     ctvmsg(0x0001, devmsg(dev, "Blocksize: %d bytes.", c->block));
                    620: 
                    621: /***********************************************************************
                    622:  *  One last check:  If we aren't using block mode (!c->block)
                    623:  *  and we didn't get any block limits then we cannot support this
                    624:  *  drive.
                    625:  */
                    626: 
                    627:     if (!c->block && rblerf) {
                    628:         devmsg(r->dev, "<No block limits on variable mode tape drive>");
                    629:         devmsg(r->dev, "<Contact Mark Williams Tech Support>");
                    630:         u. u_error = ENXIO;
                    631:         goto openfailed;
                    632:     }
                    633: 
                    634:     c->flags = (mode == IPR) ? CTRDMD : CTWRTMD;
                    635:     if (c->block) {
                    636:         c->cache = kalloc(HAICACHESZ);
                    637:         if (!c->cache) {
                    638:             devmsg(dev, "Could not allocate tape cache");
                    639:             u. u_error = ENOMEM;
                    640:             goto openfailed;
                    641:         }
                    642:         c->avail = (c->flags & CTRDMD) ? 0 : HAICACHESZ;
                    643:         c->start = c->cache;
                    644:     }
                    645:     c->state = CTIDLE;
                    646:     goto done;
                    647: 
                    648: openfailed:
                    649:     c->state = CTIDLE;
                    650:     c->inuse = 0;
                    651: 
                    652: done:
                    653:     spl(s);
                    654: }   /* ctopen() */
                    655: 
                    656: /***********************************************************************
                    657:  *  ctclose()
                    658:  *
                    659:  *  Close the SCSI Device at (dev).
                    660:  */
                    661: 
                    662: static void ctclose(dev)
                    663: register dev_t  dev;
                    664: {
                    665:     register ctctrl_p   c = ctdevs[tid(dev)];
                    666:     register srb_p      r = &(c->srb);
                    667:     int                 s;
                    668: 
                    669:     if (!c) {
                    670:         u. u_error = ENXIO;
                    671:         return;
                    672:     }
                    673: 
                    674:     s = sphi();
                    675:     if (c->block && (c->flags & CTWRTMD)) {
                    676:         if (ctbusywait(c, CTLASTWRT))
                    677:             flushcache(c);
                    678:         c->state = CTIDLE;
                    679:     }
                    680:     spl(s);
                    681:     if (c->cache) {
                    682:         kfree(c->cache);
                    683:         c->cache = c->start = NULL;
                    684:         c->avail = 0;
                    685:     }
                    686: 
                    687: #ifndef TDC3600
                    688: /*
                    689:  *  Write two filemarks (Logical End of Tape) and then skip backwards
                    690:  *  over one of them to ready for the another write operation on the
                    691:  *  no rewind device.  This code guarantees properly formed tapes according
                    692:  *  to the wisened old nine-track hacker that I work with.  The problem
                    693:  *  is that...
                    694:  */
                    695:     if (c->flags & CTDIRTY) {
                    696:         writefm(c, 1);         /* Write a file mark */
                    697:         writefm(c, 1);         /* Write another filemark */
                    698:         space(c, -1, SKIP_FM); /* Go back to the first filemark */
                    699:     }
                    700: #else
                    701: /*
                    702:  *  ... problem is that my Tandberg considers it an error to do anything
                    703:  *  after it has skipped past a filemark. So all commands except load and
                    704:  *  rewind fail after the previous code.  The following will work in
                    705:  *  all situations but there is a risk that a user's tapes will only
                    706:  *  have one filemark at Logical End-of-Tape if the user isn't careful
                    707:  *  to use the rewind device the last time he uses tape drive.  This is
                    708:  *  only a problem with drives which insist upon doing a Retension each
                    709:  *  time the tape is changed or the drive gets reset.
                    710:  */
                    711:     if (c->flags & CTDIRTY) {
                    712:         writefm(c, 1);
                    713:         if (r->dev & REWIND)
                    714:             writefm(c, 1);
                    715:     }
                    716: #endif
                    717: 
                    718:     if (r->dev & REWIND)
                    719:         rewind(c, 0);
                    720: 
                    721:     c->inuse = 0;
                    722:     return;
                    723: }   /* ctclose() */
                    724: 
                    725: /***********************************************************************
                    726:  *  fillcache() --  Read from the tape into the cache (really?)
                    727:  *
                    728:  *  return 0 and set u. u_error on any errors.
                    729:  */
                    730: 
                    731: static int fillcache(c)
                    732: register ctctrl_p   c;
                    733: {
                    734:     register srb_p      r = (&c->srb);
                    735:     register g0cmd_p    g0 = &(r->cdb. g0);
                    736:     size_t              blocks;
                    737:     extsense_p          e;
                    738:     int                 info;
                    739:     int                 retval = 0;
                    740: 
                    741:     r->buf. space = KRNL_ADDR;
                    742:     r->buf. addr. caddr = (caddr_t) c->cache;
                    743:     r->buf. size = HAICACHESZ;
                    744:     r->xferdir = DMAREAD;
                    745:     r->timeout = 30;
                    746:     r->tries = 0;
                    747:     g0->opcode = READ;
                    748:     g0->lun_lba = (r->lun << 5) | 1;
                    749:     blocks = HAICACHESZ / c->block;
                    750:     g0->lba_mid = ((unsigned char *) &blocks)[2];
                    751:     g0->lba_low = ((unsigned char *) &blocks)[1];
                    752:     g0->xfr_len = ((unsigned char *) &blocks)[0];
                    753:     g0->control = 0;
                    754:     doscsi(r, 1, pritape, slpriSigCatch, "ctblkrd");
                    755:     switch (r->status) {
                    756:     case ST_GOOD:
                    757:         c->start = c->cache;
                    758:         c->avail = r->buf. size;
                    759:         retval = 1;
                    760:         break;
                    761:     case ST_CHKCOND:
                    762:         e = r->sensebuf;
                    763:         if ((e->errorcode & 0x70) == 0x70) {
                    764:             info = 0;
                    765:             if (e->errorcode & 0x80) {
                    766:                 info = e->info;
                    767:                 flip(info);
                    768:             }
                    769:             if (e->sensekey & (CTFILEMARK | CTEOM)) {
                    770:                 c->flags |= (e->sensekey & (CTFILEMARK | CTEOM));
                    771:                 c->start = c->cache;
                    772:                 c->avail = HAICACHESZ - (info * c->block);
                    773:                 retval = 1;
                    774:                 break;
                    775:             }
                    776:         }
                    777:         printsense(r->dev, "Read failed", r->sensebuf);
                    778:         u. u_error = EIO;
                    779:         retval = 0;
                    780:         break;
                    781:     case ST_USRABRT:
                    782:         u. u_error = EINTR;
                    783:         c->start = c->cache;
                    784:         c->avail = 0;
                    785:         retval = 0;
                    786:         break;
                    787:     default:
                    788:         devmsg(r->dev, "Read failed: status (0x%x)", r->status);
                    789:         u. u_error = EIO;
                    790:         retval = 0;
                    791:         break;
                    792:     }
                    793:     return retval;
                    794: }   /* fillcache() */
                    795: 
                    796: /***********************************************************************
                    797:  *  ctfbrd()    --  Fixed block read handler.  Reads from the tape
                    798:  *                  drive through the cache when the tape drive is
                    799:  *                  in fixed block mode.
                    800:  */
                    801: 
                    802: static void ctfbrd(c, iop)
                    803: register ctctrl_p   c;
                    804: register IO         *iop;
                    805: {
                    806:     register size_t reqcount,   /* Total bytes transfered toward request */
                    807:                     xfrsize;    /* Current transfer size */
                    808:     size_t          total,      /* System global memory total transfer size */
                    809:                     size;       /* System global memory current transfer size */
                    810: 
                    811:     if (!ctbusywait(c, CTFBRD))
                    812:         return;
                    813:     reqcount = 0;
                    814:     while (iop->io_ioc) {
                    815:         xfrsize = min(c->avail, iop->io_ioc);
                    816:         if (xfrsize > 0) {
                    817:             switch (iop->io_seg) {
                    818:             case IOSYS:
                    819:                 memcpy(iop->io. vbase + reqcount, c->start, xfrsize);
                    820:                 break;
                    821:             case IOUSR:
                    822:                 kucopy(c->start, iop->io. vbase + reqcount, xfrsize);
                    823:                 break;
                    824:             case IOPHY:
                    825:                 total = 0;
                    826:                 while (total < xfrsize) {
                    827:                     size = min(xfrsize - total, NBPC);
                    828:                     xpcopy(c->start + total,
                    829:                            iop->io. pbase + reqcount + total,
                    830:                            size,
                    831:                            SEG_386_KD | SEG_VIRT);
                    832:                     total += size;
                    833:                 }
                    834:                 break;
                    835:             }
                    836:             c->start += xfrsize;
                    837:             c->avail -= xfrsize;
                    838:             reqcount += xfrsize;
                    839:             iop->io_ioc -= xfrsize;
                    840:         }
                    841:         if (iop->io_ioc) {
                    842:             if (c->flags & CTFILEMARK) {
                    843:                 c->flags &= ~CTFILEMARK;
                    844:                 break;
                    845:             }
                    846: 
                    847:             if (c->flags & CTEOM) {
                    848:                 u. u_error = EIO;
                    849:                 break;
                    850:             }
                    851: 
                    852:             if (!fillcache(c))
                    853:                 break;
                    854:         }
                    855:     }   /* while */
                    856:     c->state = CTIDLE;
                    857: }   /* ctfbrd() */
                    858: 
                    859: /***********************************************************************
                    860:  *  ctvbrd()    --  Variable block read entry point.
                    861:  */
                    862: 
                    863: static void ctvbrd(c, iop)
                    864: register ctctrl_p   c;
                    865: IO                  *iop;
                    866: {
                    867:     register srb_p      r = &(c->srb);
                    868:     register g0cmd_p    g0 = &(r->cdb. g0);
                    869:     size_t              xfrsize;
                    870:     extsense_p          e;
                    871:     int                 info;
                    872: 
                    873:     if (!ctbusywait(c, CTVBRD))
                    874:         return;
                    875: 
                    876:     if (c->flags & CTEOM) {
                    877:         u. u_error = EIO;
                    878:         return;
                    879:     }
                    880:     if (c->flags & CTFILEMARK) {
                    881:         c->flags &= ~CTFILEMARK;
                    882:         return;
                    883:     }
                    884:     switch (iop->io_seg) {
                    885:     case IOSYS:
                    886:         r->buf. space = KRNL_ADDR;
                    887:         r->buf. addr. caddr = iop->io. vbase;
                    888:         break;
                    889:     case IOUSR:
                    890:         r->buf. space = USER_ADDR;
                    891:         r->buf. addr. caddr = iop->io. vbase;
                    892:         break;
                    893:     case IOPHY:
                    894:         r->buf. space = PHYS_ADDR;
                    895:         r->buf. addr. paddr = iop->io. pbase;
                    896:         break;
                    897:     }
                    898:     r->buf. size = xfrsize = iop->io_ioc;
                    899:     r->xferdir = DMAREAD;
                    900:     r->timeout = 30;
                    901:     g0->opcode = READ;
                    902:     g0->lun_lba = (r->lun << 5);
                    903:     g0->lba_mid = ((unsigned char *) &xfrsize)[2];
                    904:     g0->lba_low = ((unsigned char *) &xfrsize)[1];
                    905:     g0->xfr_len = ((unsigned char *) &xfrsize)[0];
                    906:     g0->control = 0;
                    907:     doscsi(r, 1, pritape, slpriSigCatch, "ctvbrd");
                    908:     switch (r->status) {
                    909:     case ST_GOOD:
                    910:         iop->io_ioc -= r->buf. size;
                    911:         break;
                    912:     case ST_CHKCOND:
                    913:         e = r->sensebuf;
                    914:         if ((e->errorcode & 0x70) == 0x70) {
                    915:             info = 0;
                    916:             if (e->errorcode & 0x80) {
                    917:                 info = (long) e->info;
                    918:                 flip(info);
                    919:             }
                    920:             if (e->sensekey & (CTFILEMARK | CTEOM)) {
                    921:                 c->flags |= (e->sensekey & (CTFILEMARK | CTEOM));
                    922:                 break;
                    923:             }
                    924:             else if (e->sensekey & CTILI) {
                    925:                 devmsg(r->dev,
                    926:                        "Read failed buffer size %d blocksize %d",
                    927:                        xfrsize,
                    928:                        xfrsize - info);
                    929:                 if (info > 0)
                    930:                     iop->io_ioc -= (xfrsize - info);
                    931:                 else
                    932:                     u. u_error = EIO;
                    933:                 break;
                    934:             }
                    935:         }
                    936:         printsense(r->dev, "Read failed", r->sensebuf);
                    937:         u. u_error = EIO;
                    938:         break;
                    939:     case ST_USRABRT:
                    940:         break;
                    941:     default:
                    942:         devmsg(r->dev, "Read failed: status (0x%x)", r->status);
                    943:         u. u_error = EIO;
                    944:         break;
                    945:     }
                    946:     c->state = CTIDLE;
                    947: }   /* ctvbrd() */
                    948: 
                    949: /***********************************************************************
                    950:  *  ctread()    --  OS Read entry point.
                    951:  */
                    952: 
                    953: static void ctread(dev, iop)
                    954: dev_t       dev;
                    955: register IO *iop;
                    956: {
                    957:     register ctctrl_p   c = ctdevs[tid(dev)];
                    958: 
                    959:     if (!c) {
                    960:         u. u_error = EINVAL;
                    961:         return;
                    962:     }
                    963: 
                    964:     if (c->block)
                    965:         ctfbrd(c, iop);
                    966:     else
                    967:         ctvbrd(c, iop);
                    968: }   /* ctread() */
                    969: 
                    970: /***********************************************************************
                    971:  *  flushcache()    --  flush the data in the cache to the tape.
                    972:  *
                    973:  *  returns 0 and sets u. u_error on failure else returns 1.
                    974:  */
                    975: 
                    976: static int flushcache(c)
                    977: register ctctrl_p   c;
                    978: {
                    979:     register srb_p      r = (&c->srb);
                    980:     register g0cmd_p    g0 = &(r->cdb. g0);
                    981:     size_t              xfrsize;
                    982:     extsense_p          e;
                    983:     int                 info;
                    984:     int                 retval = 0;
                    985: 
                    986:     if (c->avail >= HAICACHESZ)
                    987:         return 1;
                    988: 
                    989:     r->buf. space = KRNL_ADDR;
                    990:     r->buf. addr. caddr = (caddr_t) c->cache;
                    991:     r->buf. size = xfrsize = HAICACHESZ - c->avail;
                    992:     r->xferdir = DMAWRITE;
                    993:     r->timeout = 30;
                    994:     r->tries = 0;
                    995:     g0->opcode = WRITE;
                    996:     g0->lun_lba = (r->lun << 5);
                    997:     if (c->block) {
                    998:         g0->lun_lba |= 1;
                    999:         xfrsize = (xfrsize + c->block - 1) / c->block;
                   1000:     }
                   1001:     g0->lba_mid = ((unsigned char *) &xfrsize)[2];
                   1002:     g0->lba_low = ((unsigned char *) &xfrsize)[1];
                   1003:     g0->xfr_len = ((unsigned char *) &xfrsize)[0];
                   1004:     g0->control = 0;
                   1005:     doscsi(r, 1, pritape, slpriSigCatch, "ctblkwrt");
                   1006:     switch (r->status) {
                   1007:     case ST_GOOD:
                   1008:         c->start = c->cache;
                   1009:         c->avail = HAICACHESZ;
                   1010:         retval = 1;
                   1011:         break;
                   1012:     case ST_CHKCOND:
                   1013:         e = r->sensebuf;
                   1014:         if ((e->errorcode & 0x70) == 0x70) {
                   1015:             info = 0;
                   1016:             if (e->errorcode & 0x80) {
                   1017:                 info = e->info;
                   1018:                 flip(info);
                   1019:             }
                   1020:             if (e->sensekey & CTEOM) {
                   1021:                 c->flags |= CTEOM;
                   1022:                 devmsg(r->dev, "End of tape on block write");
                   1023:             }
                   1024:         }
                   1025:         printsense(r->dev, "Read failed", r->sensebuf);
                   1026:         u. u_error = EIO;
                   1027:         retval = 0;
                   1028:         break;
                   1029:     case ST_USRABRT:
                   1030:         retval = 0;
                   1031:         break;
                   1032:     default:
                   1033:         devmsg(r->dev, "Read failed: status (0x%x)", r->status);
                   1034:         u. u_error = EIO;
                   1035:         retval = 0;
                   1036:         break;
                   1037:     }
                   1038:     return retval;
                   1039: }   /* flushcache() */
                   1040: 
                   1041: /***********************************************************************
                   1042:  *  ctfbwrt()   --  Fixed block write.  This should be fast because
                   1043:  *                  it uses the tapes drives optimum setting and it
                   1044:  *                  goes through a cache.
                   1045:  */
                   1046: 
                   1047: static void ctfbwrt(c, iop)
                   1048: register ctctrl_p   c;
                   1049: register IO         *iop;
                   1050: {
                   1051:     register size_t reqcount,   /* Total bytes transfered */
                   1052:                     xfrsize;    /* Current transfer size */
                   1053:     size_t          total,      /* System global memory total transfer size */
                   1054:                     size;       /* System global memory current transfer size */
                   1055: 
                   1056:     if (!ctbusywait(c, CTFBWRT))
                   1057:         return;
                   1058: 
                   1059:     reqcount = 0;
                   1060:     while (iop->io_ioc) {
                   1061:         xfrsize = min(c->avail, iop->io_ioc);
                   1062:         if (xfrsize) {
                   1063:             switch (iop->io_seg) {
                   1064:             case IOSYS:
                   1065:                 memcpy(c->start, iop->io. vbase + reqcount, xfrsize);
                   1066:                 break;
                   1067:             case IOUSR:
                   1068:                 ukcopy(iop->io. vbase + reqcount, c->start, xfrsize);
                   1069:                 break;
                   1070:             case IOPHY:
                   1071:                 total = 0;
                   1072:                 while (total < xfrsize) {
                   1073:                     size = min(xfrsize - total, NBPC);
                   1074:                     pxcopy(iop->io. pbase + reqcount + total,
                   1075:                            c->start + total,
                   1076:                            size,
                   1077:                            SEG_386_KD | SEG_VIRT);
                   1078:                     total += size;
                   1079:                 }
                   1080:                 break;
                   1081:             }
                   1082:             c->start += xfrsize;
                   1083:             c->avail -= xfrsize;
                   1084:             reqcount += xfrsize;
                   1085:             iop->io_ioc -= xfrsize;
                   1086:         }
                   1087:         if (iop->io_ioc) {
                   1088:             if (!flushcache(c))
                   1089:                 break;
                   1090:         }
                   1091:     }   /* while */
                   1092:     c->state = CTIDLE;
                   1093: }   /* ctfbwrt() */
                   1094: 
                   1095: /***********************************************************************
                   1096:  *  ctvbwrt()   --  Variable block writes.
                   1097:  */
                   1098: 
                   1099: static void ctvbwrt(c, iop)
                   1100: register ctctrl_p   c;
                   1101: register IO         *iop;
                   1102: {
                   1103:     register srb_p      r = &(c->srb);
                   1104:     register g0cmd_p    g0 = &(r->cdb. g0);
                   1105:     size_t              xfrsize;
                   1106:     extsense_p          e;
                   1107:     int                 info;
                   1108: 
                   1109:     if (!ctbusywait(c, CTVBWRT))
                   1110:         return;
                   1111: 
                   1112:     if (c->blmax && iop->io_ioc > c->blmax) {
                   1113:         devmsg(r->dev, "Tape Error: maximum read/write size is %d bytes.", c->blmax);
                   1114:         u. u_error = EIO;
                   1115:         return;
                   1116:     }
                   1117:     switch (iop->io_seg) {
                   1118:     case IOSYS:
                   1119:         r->buf. space = KRNL_ADDR;
                   1120:         r->buf. addr. caddr = iop->io. vbase;
                   1121:         break;
                   1122:     case IOUSR:
                   1123:         r->buf. space = USER_ADDR;
                   1124:         r->buf. addr. caddr = iop->io. vbase;
                   1125:         break;
                   1126:     case IOPHY:
                   1127:         r->buf. space = PHYS_ADDR;
                   1128:         r->buf. addr. paddr = iop->io. pbase;
                   1129:         break;
                   1130:     }
                   1131:     xfrsize = min(iop->io_ioc, c->blmin);
                   1132:     r->buf. size = xfrsize;
                   1133:     r->xferdir = DMAWRITE;
                   1134:     r->timeout = 30;
                   1135:     g0->opcode = WRITE;
                   1136:     g0->lun_lba = (r->lun << 5);
                   1137:     g0->lba_mid = ((unsigned char *) &xfrsize)[2];
                   1138:     g0->lba_low = ((unsigned char *) &xfrsize)[1];
                   1139:     g0->xfr_len = ((unsigned char *) &xfrsize)[0];
                   1140:     g0->control = 0;
                   1141:     doscsi(r, 1, pritape, slpriSigCatch, "ctvbwrt");
                   1142:     switch (r->status) {
                   1143:     case ST_GOOD:
                   1144:         iop->io_ioc -= r->buf. size;
                   1145:         break;
                   1146:     case ST_CHKCOND:
                   1147:         e = r->sensebuf;
                   1148:         if ((e->errorcode & 0x70) == 0x70) {
                   1149:             info = 0;
                   1150:             if (e->errorcode & 0x80) {
                   1151:                 info = (long) e->info;
                   1152:                 flip(info);
                   1153:             }
                   1154:             if (e->sensekey & CTEOM) {
                   1155:                 c->flags |= CTEOM;
                   1156:                 devmsg(r->dev, "End of tape");
                   1157:             }
                   1158:         }
                   1159:         printsense(r->dev, "Write failed", r->sensebuf);
                   1160:         u. u_error = EIO;
                   1161:         break;
                   1162:     case ST_USRABRT:
                   1163:         break;
                   1164:     default:
                   1165:         devmsg(r->dev, "Read failed: status (0x%x)", r->status);
                   1166:         u. u_error = EIO;
                   1167:         break;
                   1168:     }
                   1169:     c->state = CTIDLE;
                   1170: }   /* ctvbwrt() */
                   1171: 
                   1172: /***********************************************************************
                   1173:  *  ctwrite()   -- Write entry point for tape drive.
                   1174:  */
                   1175: 
                   1176: static void ctwrite(dev, iop)
                   1177: register dev_t  dev;
                   1178: register IO     *iop;
                   1179: {
                   1180:     register ctctrl_p c = ctdevs[tid(dev)];
                   1181: 
                   1182:     if (!c) {
                   1183:         u. u_error = ENXIO;
                   1184:         return;
                   1185:     }
                   1186: 
                   1187:     c->flags |= CTDIRTY;
                   1188:     if (c->block)
                   1189:         ctfbwrt(c, iop);
                   1190:     else
                   1191:         ctvbwrt(c, iop);
                   1192: }   /* ctwrite() */
                   1193: 
                   1194: /***********************************************************************
                   1195:  *  ctioctl()
                   1196:  *
                   1197:  *  I/O Control Entry point for Cartridge tape devices.
                   1198:  *
                   1199:  *  This function had been modified to allow applications level programs
                   1200:  *  to select modes and features for the tape drive. As stated above,
                   1201:  *  the philosophy of this driver is to provide least common denominator
                   1202:  *  support for all tape drives.  I know that you spend big bucks to
                   1203:  *  get that (insert your favorite drive brand/model).  If I decide
                   1204:  *  to support everything out there on the market then I won't be able
                   1205:  *  to write network drivers, serial drivers, etc.  So if you need
                   1206:  *  to do something to the tape drive to make it work (mode sense/select)
                   1207:  *  you can do it through this ctioctl as an applications program.
                   1208:  */
                   1209: 
                   1210: static void ctioctl(dev, cmd, vec)
                   1211: dev_t           dev;
                   1212: register int    cmd;
                   1213: char            *vec;
                   1214: {
                   1215:     register ctctrl_p   c = ctdevs[tid(dev)];
                   1216:     register srb_p      r = &(c->srb);
                   1217:     int                 s;
                   1218: 
                   1219:     if (!c) {
                   1220:         u. u_error = EINVAL;
                   1221:         return;
                   1222:     }
                   1223: 
                   1224:     switch (cmd) {
                   1225:     case MTREWIND:      /* Rewind */
                   1226:         rewind(c, 1);
                   1227:         break;
                   1228:     case MTWEOF:        /* Write end of file mark */
                   1229:         writefm(c, 1);
                   1230:         break;
                   1231:     case MTRSKIP:       /* Record skip */
                   1232:         space(c, 1, SKIP_BLK);
                   1233:         break;
                   1234:     case MTFSKIP:       /* File skip */
                   1235:         space(c, 1, SKIP_FM);
                   1236:         break;
                   1237:     case MTTENSE:       /* Tension tape */
                   1238:         loadtape(c, RETENSION);
                   1239:         break;
                   1240:     case MTERASE:       /* Erase tape */
                   1241:         erase(c, ERASE_TAPE);
                   1242:         break;
                   1243:     case MTDEC:         /* DEC mode */
                   1244:     case MTIBM:         /* IBM mode */
                   1245:     case MT800:         /* 800 bpi */
                   1246:     case MT1600:        /* 1600 bpi */
                   1247:     case MT6250:        /* 6250 bpi */
                   1248:         return;
                   1249:     default:
                   1250:         if (!ctbusywait(c, CTIOCTL))
                   1251:             return;
                   1252:         s = sphi();
                   1253:         haiioctl(r, cmd, vec);
                   1254:         c->state = CTIDLE;
                   1255:         spl(s);
                   1256:         break;
                   1257:     }
                   1258: }   /* ctioctl() */
                   1259: 
                   1260: /* 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.