Patch from Julian. Commit message by me.
[unix-history] / sys / scsi / st.c
index 1466544..871614d 100644 (file)
  * on the understanding that TFS is not responsible for the correct
  * functioning of this software in any circumstances.
  *
  * on the understanding that TFS is not responsible for the correct
  * functioning of this software in any circumstances.
  *
+ *
+ * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
+ * --------------------         -----   ----------------------
+ * CURRENT PATCH LEVEL:         1       00098
+ * --------------------         -----   ----------------------
+ *
+ * 16 Feb 93    Julian Elischer         ADDED for SCSI system
+ * 1.15 is the last version to support MACH and OSF/1
+ */
+/* $Revision: 1.14 $ */
+
+/*
  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
  * major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993
  *
  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
  * major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993
  *
- *     $Id: st.c,v 1.10 1993/10/11 04:53:23 rgrimes Exp $
+ *      $Id: st.c,v 1.14 1993/12/19 00:54:59 wollman Exp $
  */
 
  */
 
-
 /*
  * To do:
  * work out some better way of guessing what a good timeout is going
 /*
  * To do:
  * work out some better way of guessing what a good timeout is going
 #include <sys/user.h>
 #include <sys/mtio.h>
 
 #include <sys/user.h>
 #include <sys/mtio.h>
 
-
 #include <scsi/scsi_all.h>
 #include <scsi/scsi_tape.h>
 #include <scsi/scsiconf.h>
 
 #include <scsi/scsi_all.h>
 #include <scsi/scsi_tape.h>
 #include <scsi/scsiconf.h>
 
-
-long int ststrats,stqueues;
+u_int32 ststrats, stqueues;
 
 /* Defines for device specific stuff */
 #define                PAGE_0_SENSE_DATA_SIZE  12
 #define PAGESIZ        4096
 #define DEF_FIXED_BSIZE  512
 
 /* Defines for device specific stuff */
 #define                PAGE_0_SENSE_DATA_SIZE  12
 #define PAGESIZ        4096
 #define DEF_FIXED_BSIZE  512
-#define STQSIZE                4
-#define        ST_RETRIES      4
-
+#define        ST_RETRIES      4       /* only on non IO commands */
 
 #define MODE(z)                (  (minor(z)       & 0x03) )
 #define DSTY(z)         ( ((minor(z) >> 2) & 0x03) )
 #define UNIT(z)                (  (minor(z) >> 4) )
 
 #define MODE(z)                (  (minor(z)       & 0x03) )
 #define DSTY(z)         ( ((minor(z) >> 2) & 0x03) )
 #define UNIT(z)                (  (minor(z) >> 4) )
-
-#define DSTY3  3
-#define DSTY2  2
-#define DSTY1  1
+#define CTLMODE        3
 
 #define SCSI_2_MAX_DENSITY_CODE        0x17    /* maximum density code specified
 
 #define SCSI_2_MAX_DENSITY_CODE        0x17    /* maximum density code specified
-                                          in SCSI II spec. */
-/***************************************************************\
-* Define various devices that we know mis-behave in some way,  *
-* and note how they are bad, so we can correct for them                *
-\***************************************************************/
-struct modes
-{
-       int     quirks;         /* same definitions as in rogues */
-       char    density;
-       char    spare[3];
+                                        * in SCSI II spec. */
+/*
+ * Define various devices that we know mis-behave in some way,
+ * and note how they are bad, so we can correct for them
+ */
+struct modes {
+       u_int32 blksiz;
+       u_int32 quirks;         /* same definitions as in rogues */
+       char    density;
+       char    spare[3];
 };
 };
-struct rogues
-{
-       char    *name;
-        char    *manu;
-        char    *model;
-        char    *version;
-       int     quirks;         /* valid for all modes */
-       struct  modes   modes[4];       
+
+struct rogues {
+       char   *name;
+       char   *manu;
+       char   *model;
+       char   *version;
+       u_int32 quirks;         /* valid for all modes */
+       struct modes modes[4];
 };
 
 /* define behaviour codes (quirks) */
 #define        ST_Q_NEEDS_PAGE_0       0x00001
 #define        ST_Q_FORCE_FIXED_MODE   0x00002
 #define        ST_Q_FORCE_VAR_MODE     0x00004
 };
 
 /* define behaviour codes (quirks) */
 #define        ST_Q_NEEDS_PAGE_0       0x00001
 #define        ST_Q_FORCE_FIXED_MODE   0x00002
 #define        ST_Q_FORCE_VAR_MODE     0x00004
-#define        ST_Q_SNS_HLP            0x00008 /* must do READ for good MODE SENSE */
+#define        ST_Q_SNS_HLP            0x00008         /* must do READ for good MODE SENSE */
 #define        ST_Q_IGNORE_LOADS       0x00010
 #define        ST_Q_IGNORE_LOADS       0x00010
-#define        ST_Q_BLKSIZ             0x00020 /* variable-block media_blksiz > 0 */
+#define        ST_Q_BLKSIZ             0x00020         /* variable-block media_blksiz > 0 */
 
 
-static struct rogues gallery[] = /* ends with an all null entry */
+static struct rogues gallery[] =       /* ends with an all-null entry */
 {
 {
-       { "Such an old device ", "pre-scsi", " unknown model  ","????",
-               0,
-               { {ST_Q_FORCE_FIXED_MODE,0},            /* minor  0,1,2,3 */
-                 {ST_Q_FORCE_FIXED_MODE,QIC_24},       /* minor  4,5,6,7 */
-                 {ST_Q_FORCE_VAR_MODE,HALFINCH_1600},  /* minor  8,9,10,11*/
-                 {ST_Q_FORCE_VAR_MODE,HALFINCH_6250}   /* minor  12,13,14,15*/
-               }
-       },
-       { "Tandberg tdc3600", "TANDBERG", " TDC 3600","????",
-               ST_Q_NEEDS_PAGE_0,
-               { {0,0},                                /* minor  0,1,2,3*/
-                 {ST_Q_FORCE_VAR_MODE,QIC_525},        /* minor  4,5,6,7*/
-                 {0,QIC_150},                          /* minor  8,9,10,11*/
-                 {0,QIC_120}                           /* minor  12,13,14,15*/
-               }
-       },
-       { "Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462","-005",
-               0,
-               { {ST_Q_SNS_HLP,0},                     /* minor  0,1,2,3*/
-                 {ST_Q_SNS_HLP,QIC_525},               /* minor  4,5,6,7*/
-                 {0,QIC_150},                          /* minor  8,9,10,11*/
-                 {0,QIC_120}                           /* minor  12,13,14,15*/
-               }
-       },
-       { "Archive  Viper 150", "ARCHIVE ", "VIPER 150","????",
-               ST_Q_NEEDS_PAGE_0,
-               { {0,0},                                /* minor  0,1,2,3*/
-                 {0,QIC_150},                          /* minor  4,5,6,7*/
-                 {0,QIC_120},                          /* minor  8,9,10,11*/
-                 {0,QIC_24}                            /* minor  12,13,14,15*/
-               }
-       },
-       { "Wangtek 5525ES", "WANGTEK ", "5525ES SCSI REV7", "????",
-               0,
-               { {0,0},                                /* minor  0,1,2,3*/
-                 {ST_Q_BLKSIZ,QIC_525},                /* minor  4,5,6,7*/
-                 {0,QIC_150},                          /* minor  8,9,10,11*/
-                 {0,QIC_120}                           /* minor  12,13,14,15*/
-               }
-       },
-       {(char *)0}
+    {"Such an old device ", "pre-scsi", " unknown model  ", "????",
+       0,
+       {
+           {512, ST_Q_FORCE_FIXED_MODE, 0},    /* minor  0,1,2,3 */
+           {512, ST_Q_FORCE_FIXED_MODE, QIC_24},       /* minor  4,5,6,7 */
+           {0, ST_Q_FORCE_VAR_MODE, HALFINCH_1600},    /* minor  8,9,10,11 */
+           {0, ST_Q_FORCE_VAR_MODE, HALFINCH_6250}     /* minor  12,13,14,15 */
+       }
+    },
+    {"Tandberg tdc3600", "TANDBERG", " TDC 3600", "????",
+       ST_Q_NEEDS_PAGE_0,
+       {
+           {0, 0, 0},          /* minor  0,1,2,3 */
+           {0, ST_Q_FORCE_VAR_MODE, QIC_525},  /* minor  4,5,6,7 */
+           {0, 0, QIC_150},    /* minor  8,9,10,11 */
+           {0, 0, QIC_120}     /* minor  12,13,14,15 */
+       }
+    },
+    {"Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462", "-005",
+       0,
+       {
+           {0, ST_Q_SNS_HLP, 0},       /* minor  0,1,2,3 */
+           {0, ST_Q_SNS_HLP, QIC_525},         /* minor  4,5,6,7 */
+           {0, 0, QIC_150},    /* minor  8,9,10,11 */
+           {0, 0, QIC_120}     /* minor  12,13,14,15 */
+       }
+    },
+    {"Archive  Viper 150", "ARCHIVE ", "VIPER 150", "????",
+       ST_Q_NEEDS_PAGE_0,
+       {
+           {0, 0, 0},          /* minor  0,1,2,3 */
+           {0, 0, QIC_150},    /* minor  4,5,6,7 */
+           {0, 0, QIC_120},    /* minor  8,9,10,11 */
+           {0, 0, QIC_24}      /* minor  12,13,14,15 */
+       }
+    },
+    {"Wangtek 5525ES", "WANGTEK ", "5525ES SCSI REV7", "????",
+       0,
+       {
+           {0, 0, 0},          /* minor  0,1,2,3 */
+           {0, ST_Q_BLKSIZ, QIC_525},  /* minor  4,5,6,7 */
+           {0, 0, QIC_150},    /* minor  8,9,10,11 */
+           {0, 0, QIC_120}     /* minor  12,13,14,15 */
+       }
+    },
+    {"WangDAT model 1300", "WangDAT ", "Model 1300", "????",
+       0,
+       {
+           {0, 0, 0},                                  /* minor  0,1,2,3 */
+           {512, ST_Q_FORCE_FIXED_MODE, 0x13},         /* minor  4,5,6,7 */
+           {1024, ST_Q_FORCE_FIXED_MODE, 0x13},        /* minor  8,9,10,11 */
+           {0, ST_Q_FORCE_VAR_MODE, 0x13}              /* minor  12,13,14,15 */
+       }
+    },
+    {(char *) 0}
 };
 
 };
 
-
-int    ststrategy();
-void   stminphys();
+errval st_space __P((u_int32 unit, int32 number, u_int32 what, u_int32 flags));
+errval st_rewind __P((u_int32 unit, boolean immed, u_int32 flags));
+errval st_mode_sense __P((u_int32 unit, u_int32 flags));
+errval st_decide_mode __P((u_int32 unit, boolean first_read));
+errval st_rd_blk_lim __P((u_int32 unit, u_int32 flags));
+errval st_touch_tape __P((u_int32 unit));
+errval st_write_filemarks __P((u_int32 unit, int32 number, u_int32 flags));
+errval st_load __P((u_int32 unit, u_int32 type, u_int32 flags));
+errval st_mode_select __P((u_int32 unit, u_int32 flags));
+void    ststrategy();
+void    stminphys();
+int32   st_chkeod();
+errval  stattach();
+void    ststart();
+void   st_unmount();
+errval st_mount_tape();
+void   st_loadquirks();
+void   st_identify_drive();
+errval  st_interpret_sense();
 
 #define ESUCCESS 0
 
 #define ESUCCESS 0
+#define NOEJECT 0
+#define EJECT 1
 
 
-#ifdef STDEBUG
-int    st_debug = 1;
-#endif /*STDEBUG*/
-
-int stattach();
-int st_done();
-
-struct st_data
+struct scsi_device st_switch =
 {
 {
+    st_interpret_sense,                /* check errors with us first */
+    ststart,                   /* we have a queue, and this is how we service it */
+    NULL,
+    NULL,                      /* use the default 'done' routine */
+    "st",
+    0,
+    { 0, 0 }
+};
+
+struct st_data {
 /*--------------------present operating parameters, flags etc.----------------*/
 /*--------------------present operating parameters, flags etc.----------------*/
-       int     flags;                  /* see below                          */
-       int     blksiz;                 /* blksiz we are using                */
-       int     density;                /* present density                    */
-       int     quirks;                 /* quirks for the open mode           */
-       int     last_dsty;              /* last density used                  */
+       u_int32 flags;          /* see below                          */
+       u_int32 blksiz;         /* blksiz we are using                */
+       u_int32 density;        /* present density                    */
+       u_int32 quirks;         /* quirks for the open mode           */
+       u_int32 last_dsty;      /* last density openned               */
 /*--------------------device/scsi parameters----------------------------------*/
 /*--------------------device/scsi parameters----------------------------------*/
-       struct  scsi_switch *sc_sw;     /* address of scsi low level switch   */
-       int     ctlr;                   /* so they know which one we want     */
-       int     targ;                   /* our scsi target ID                 */
-       int     lu;                     /* our scsi lu                        */
+       struct scsi_link *sc_link;      /* our link to the adpter etc.        */
 /*--------------------parameters reported by the device ----------------------*/
 /*--------------------parameters reported by the device ----------------------*/
-       int     blkmin;                 /* min blk size                       */
-       int     blkmax;                 /* max blk size                       */
+       u_int32 blkmin;         /* min blk size                       */
+       u_int32 blkmax;         /* max blk size                       */
+       struct rogues *rogues;  /* if we have a rogue entry           */
 /*--------------------parameters reported by the device for this media--------*/
 /*--------------------parameters reported by the device for this media--------*/
-       int     numblks;                /* nominal blocks capacity            */
-       int     media_blksiz;           /* 0 if not ST_FIXEDBLOCKS            */
-       int     media_density;          /* this is what it said when asked    */
+       u_int32 numblks;        /* nominal blocks capacity            */
+       u_int32 media_blksiz;   /* 0 if not ST_FIXEDBLOCKS            */
+       u_int32 media_density;  /* this is what it said when asked    */
 /*--------------------quirks for the whole drive------------------------------*/
 /*--------------------quirks for the whole drive------------------------------*/
-       int     drive_quirks;           /* quirks of this drive               */
+       u_int32 drive_quirks;   /* quirks of this drive               */
 /*--------------------How we should set up when openning each minor device----*/
 /*--------------------How we should set up when openning each minor device----*/
-       struct  modes   modes[4];       /* plus more for each mode            */
+       struct modes modes[4];  /* plus more for each mode            */
+       u_int8  modeflags[4];   /* flags for the modes                */
+#define DENSITY_SET_BY_USER    0x01
+#define DENSITY_SET_BY_QUIRK   0x02
+#define BLKSIZE_SET_BY_USER    0x04
+#define BLKSIZE_SET_BY_QUIRK   0x08
 /*--------------------storage for sense data returned by the drive------------*/
 /*--------------------storage for sense data returned by the drive------------*/
-        unsigned char   sense_data[12]; /* additional sense data needed       */
-                                        /* for mode sense/select.            */
-       struct  buf *buf_queue;         /* the queue of pending IO operations */
-       struct  scsi_xfer scsi_xfer;    /* The scsi xfer struct for this drive*/
-       int     xfer_block_wait;        /* whether there is a process waiting */
-}*st_data[NST];
+       unsigned char sense_data[12];   /*
+                                        * additional sense data needed
+                                        * for mode sense/select.
+                                        */
+       struct buf *buf_queue;          /* the queue of pending IO operations */
+       struct scsi_xfer scsi_xfer;     /* scsi xfer struct for this drive */
+       u_int32 xfer_block_wait;        /* is a process waiting? */
+}      *st_data[NST];
+
 #define ST_INITIALIZED 0x01
 #define        ST_INFO_VALID   0x02
 #define ST_OPEN                0x04
 #define ST_INITIALIZED 0x01
 #define        ST_INFO_VALID   0x02
 #define ST_OPEN                0x04
-#define        ST_BLOCK_SET    0x08            /* block size, mode set by ioctl      */
-#define        ST_WRITTEN      0x10            /* data have been written, EOD needed */
+#define        ST_BLOCK_SET    0x08    /* block size, mode set by ioctl      */
+#define        ST_WRITTEN      0x10    /* data have been written, EOD needed */
 #define        ST_FIXEDBLOCKS  0x20
 #define        ST_AT_FILEMARK  0x40
 #define        ST_FIXEDBLOCKS  0x20
 #define        ST_AT_FILEMARK  0x40
-#define        ST_EIO_PENDING  0x80            /* we couldn't report it then (had data)*/
-#define        ST_AT_BOM       0x100           /* ops history suggests Beg of Medium */
-#define        ST_READONLY     0x200           /* st_mode_sense says write protected */
-#define        ST_FM_WRITTEN   0x400           /* EOF file mark written  -- */
-                                       /* used with ~ST_WRITTEN to indicate  */
-                                       /* that multiple file marks have been */
-                                       /* written                            */
-#define        ST_BLANK_READ   0x800           /* BLANK CHECK encountered already */
-#define        ST_2FM_AT_EOD   0x1000          /* write 2 file marks at EOD */
+#define        ST_EIO_PENDING  0x80    /* we couldn't report it then (had data) */
+#define        ST_NEW_MOUNT    0x100   /* still need to decide mode              */
+#define        ST_READONLY     0x200   /* st_mode_sense says write protected */
+#define        ST_FM_WRITTEN   0x400   /*
+                                * EOF file mark written  -- used with
+                                * ~ST_WRITTEN to indicate that multiple file
+                                * marks have been written
+                                */
+#define        ST_BLANK_READ   0x800   /* BLANK CHECK encountered already */
+#define        ST_2FM_AT_EOD   0x1000  /* write 2 file marks at EOD */
+#define        ST_MOUNTED      0x2000  /* Device is presently mounted */
 
 #define        ST_PER_ACTION   (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
 
 #define        ST_PER_ACTION   (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
-#define        ST_PER_OPEN     ST_OPEN
-#define        ST_PER_MEDIA    (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
-                       ST_FIXEDBLOCKS | ST_AT_BOM | ST_READONLY | \
+#define        ST_PER_MOUNT    (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
+                       ST_FIXEDBLOCKS | ST_READONLY | \
                        ST_FM_WRITTEN | ST_2FM_AT_EOD | ST_PER_ACTION)
 
                        ST_FM_WRITTEN | ST_2FM_AT_EOD | ST_PER_ACTION)
 
-static int     next_st_unit = 0;
-/***********************************************************************\
-* The routine called by the low level scsi routine when it discovers   *
-* A device suitable for this driver                                    *
-\***********************************************************************/
+static u_int32 next_st_unit = 0;
 
 
-int    stattach(ctlr,targ,lu,scsi_switch)
-struct scsi_switch *scsi_switch;
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * A device suitable for this driver
+ */
+
+errval 
+stattach(sc_link)
+       struct scsi_link *sc_link;
 {
 {
-       int     unit,i;
+       u_int32 unit;
        struct st_data *st;
 
        struct st_data *st;
 
-#ifdef STDEBUG
-       if(scsi_debug & PRINTROUTINES) printf("stattach: ");
-#endif /*STDEBUG*/
-       /*******************************************************\
-       * Check we have the resources for another drive         *
-       \*******************************************************/
+       SC_DEBUG(sc_link, SDEV_DB2, ("stattach: "));
+       /*
+        * Check we have the resources for another drive
+        */
        unit = next_st_unit++;
        unit = next_st_unit++;
-       if( unit >= NST)
-       {
+
+       if (unit >= NST) {
                printf("Too many scsi tapes..(%d > %d) reconfigure kernel\n",
                printf("Too many scsi tapes..(%d > %d) reconfigure kernel\n",
-                               (unit + 1),NST);
-               return(0);
+                   (unit + 1), NST);
+               return 0;
        }
        }
-       if(st_data[unit])
-       {
-               printf("st%d: Already has storage!\n",unit);
-               return(0);
+       if (st_data[unit]) {
+               printf("st%d: Already has storage!\n", unit);
+               return 0;
        }
        }
-       st = st_data[unit] = malloc(sizeof(struct st_data),M_DEVBUF,M_NOWAIT);
-       if(!st)
-       {
-               printf("st%d: malloc failed in st.c\n",unit);
-               return(0);
+       sc_link->device = &st_switch;
+       sc_link->dev_unit = unit;
+       st = st_data[unit] = malloc(sizeof(struct st_data), M_DEVBUF, M_NOWAIT);
+       if (!st) {
+               printf("st%d: malloc failed in st.c\n", unit);
+               return 0;
        }
        }
-       bzero(st,sizeof(struct st_data));
-
-       /*******************************************************\
-       * Store information needed to contact our base driver   *
-       \*******************************************************/
-       st->sc_sw       =       scsi_switch;
-       st->ctlr        =       ctlr;
-       st->targ        =       targ;
-       st->lu          =       lu;
-
-       /*******************************************************\
-       * Store information about default densities             *
-       \*******************************************************/
-       st->modes[DSTY1].density        =       QIC_525;
-       st->modes[DSTY2].density        =       QIC_150;
-       st->modes[DSTY3].density        =       QIC_120;
-
-       /*******************************************************\
-       * Check if the drive is a known criminal and take       *
-       * Any steps needed to bring it into line                *
-       \*******************************************************/
+       bzero(st, sizeof(struct st_data));
+
+       /*
+        * Store information needed to contact our base driver
+        */
+       st->sc_link = sc_link;
+
+       /*
+        * Check if the drive is a known criminal and take
+        * Any steps needed to bring it into line
+        */
        st_identify_drive(unit);
 
        st_identify_drive(unit);
 
-       /*******************************************************\
-       * Use the subdriver to request information regarding    *
-       * the drive. We cannot use interrupts yet, so the       *
-       * request must specify this.                            *
-       \*******************************************************/
-       if(st_mode_sense(unit, SCSI_NOSLEEP |  SCSI_NOMASK | SCSI_SILENT))
-       {
+       /*
+        * Use the subdriver to request information regarding
+        * the drive. We cannot use interrupts yet, so the
+        * request must specify this.
+        */
+       if (st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
                printf("st%d: drive offline\n", unit);
                printf("st%d: drive offline\n", unit);
-       }
-       else
-       {
-               if(!st_test_ready(unit,SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT))
-               {
-                       printf("st%d: density code 0x%x, ",
-                           unit, st->media_density);
-                       if (st->media_blksiz)
-                       {
+       } else {
+               printf("st%d: density code 0x%x, ", unit, st->media_density);
+               if (!scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
+                       if (st->media_blksiz) {
                                printf("%d-byte", st->media_blksiz);
                                printf("%d-byte", st->media_blksiz);
-                       }
-                       else
-                       {
+                       } else {
                                printf("variable");
                        }
                        printf(" blocks, write-%s\n",
                                printf("variable");
                        }
                        printf(" blocks, write-%s\n",
-                           st->flags & ST_READONLY ? "protected" : "enabled");
-               }
-               else
-               {
-                       printf("st%d: drive empty\n", unit);
+                           (st->flags & ST_READONLY) ? "protected" : "enabled");
+               } else {
+                       printf(" drive empty\n");
                }
        }
                }
        }
-       /*******************************************************\
-       * Set up the bufs for this device                       *
-       \*******************************************************/
-       st->buf_queue   =       0;
-
-
+       /*
+        * Set up the buf queue for this device
+        */
+       st->buf_queue = 0;
        st->flags |= ST_INITIALIZED;
        st->flags |= ST_INITIALIZED;
-       return;
-
+       return 0;
 }
 
 }
 
-/***********************************************************************\
-* Use the identify routine in 'scsiconf' to get drive info so we can   *
-* Further tailor our behaviour.                                                *
-\***********************************************************************/
-
+/*
+ * Use the inquiry routine in 'scsi_base' to get drive info so we can
+ * Further tailor our behaviour.
+ */
+void
 st_identify_drive(unit)
 st_identify_drive(unit)
-int    unit;
+       u_int32 unit;
 {
 {
-
-       struct  st_data *st = st_data[unit];
-       struct scsi_inquiry_data        inqbuf;
-       struct  rogues *finger;
-        char    manu[32];
-        char    model[32];
-        char    model2[32];
-        char    version[32];
-       int     model_len;
-
-
-       /*******************************************************\
-       * Get the device type information                       *
-       \*******************************************************/
-       if (scsi_inquire(st->ctlr, st->targ, st->lu, st->sc_sw, &inqbuf,
-               SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != COMPLETE)
-       {
+       struct st_data *st = st_data[unit];
+       struct scsi_inquiry_data inqbuf;
+       struct rogues *finger;
+       char    manu[32];
+       char    model[32];
+       char    model2[32];
+       char    version[32];
+       u_int32 model_len;
+
+       /*
+        * Get the device type information
+        */
+       if (scsi_inquire(st->sc_link, &inqbuf,
+               SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != 0) {
                printf("st%d: couldn't get device type, using default\n", unit);
                return;
        }
                printf("st%d: couldn't get device type, using default\n", unit);
                return;
        }
-       if((inqbuf.version & SID_ANSII) == 0)
-       {
-               /***********************************************\
-               * If not advanced enough, use default values    *
-               \***********************************************/
-               strncpy(manu,"pre-scsi",8);manu[8]=0;
-               strncpy(model," unknown model  ",16);model[16]=0;
-               strncpy(version,"????",4);version[4]=0;
-       }
-       else
-       {
-               strncpy(manu,inqbuf.vendor,8);manu[8]=0;
-               strncpy(model,inqbuf.product,16);model[16]=0;
-               strncpy(version,inqbuf.revision,4);version[4]=0;
+       if ((inqbuf.version & SID_ANSII) == 0) {
+               /*
+                * If not advanced enough, use default values
+                */
+               strncpy(manu, "pre-scsi", 8);
+               manu[8] = 0;
+               strncpy(model, " unknown model  ", 16);
+               model[16] = 0;
+               strncpy(version, "????", 4);
+               version[4] = 0;
+       } else {
+               strncpy(manu, inqbuf.vendor, 8);
+               manu[8] = 0;
+               strncpy(model, inqbuf.product, 16);
+               model[16] = 0;
+               strncpy(version, inqbuf.revision, 4);
+               version[4] = 0;
        }
        }
-        
-       /*******************************************************\
-       * Load the parameters for this kind of device, so we    *
-       * treat it as appropriate for each operating mode       *
-       * Only check the number of characters in the array's    *
-       * model entry, not the entire model string returned.    *
-       \*******************************************************/
+
+       /*
+        * Load the parameters for this kind of device, so we
+        * treat it as appropriate for each operating mode.
+        * Only check the number of characters in the array's
+        * model entry, not the entire model string returned.
+        */
        finger = gallery;
        finger = gallery;
-       while(finger->name)
-       {
+       while (finger->name) {
                model_len = 0;
                model_len = 0;
-               while(finger->model[model_len] && (model_len < 32))
-               {
+               while (finger->model[model_len] && (model_len < 32)) {
                        model2[model_len] = model[model_len];
                        model_len++;
                }
                model2[model_len] = 0;
                        model2[model_len] = model[model_len];
                        model_len++;
                }
                model2[model_len] = 0;
-               if ((strcmp(manu, finger->manu) == 0 )
-                       && (strcmp(model2, finger->model) == 0 ||
-                          strcmp("????????????????", finger->model) == 0)
-                       && (strcmp(version, finger->version) == 0 ||
-                          strcmp("????", finger->version) == 0))
-               {
-                       printf("st%d: %s is a known rogue\n", unit,finger->name);
-                       st->modes[0]    =       finger->modes[0];
-                       st->modes[1]    =       finger->modes[1];
-                       st->modes[2]    =       finger->modes[2];
-                       st->modes[3]    =       finger->modes[3];
-                       st->drive_quirks=       finger->quirks;
-                       st->quirks      =       finger->quirks; /*start value*/
+               if ((strcmp(manu, finger->manu) == 0)
+                   && (strcmp(model2, finger->model) == 0 ||
+                       strcmp("????????????????", finger->model) == 0)
+                   && (strcmp(version, finger->version) == 0 ||
+                       strcmp("????", finger->version) == 0)) {
+                       printf("st%d: %s is a known rogue\n", unit, finger->name);
+                       st->rogues = finger;
+                       st->drive_quirks = finger->quirks;
+                       st->quirks = finger->quirks;    /*start value */
+                       st_loadquirks(st);
                        break;
                        break;
-               }
-               else
-               {
+               } else {
                        finger++;       /* go to next suspect */
                }
        }
 }
 
                        finger++;       /* go to next suspect */
                }
        }
 }
 
-/*******************************************************\
-*      open the device.                                *
-\*******************************************************/
+/*
+ * initialise the subdevices to the default (QUIRK) state.
+ * this will remove any setting made by the system operator or previous
+ * operations.
+ */
+void
+st_loadquirks(st)
+       struct st_data *st;
+{
+       int     i;
+       struct  modes *mode;
+       struct  modes *mode2;
+
+       if (!st->rogues)
+               return;
+       mode = st->rogues->modes;
+       mode2 = st->modes;
+       for (i = 0; i < 4; i++) {
+               bzero(mode2, sizeof(struct modes));
+               st->modeflags[i] &= ~(BLKSIZE_SET_BY_QUIRK
+                   | DENSITY_SET_BY_QUIRK
+                   | BLKSIZE_SET_BY_USER
+                   | DENSITY_SET_BY_USER);
+               if (mode->blksiz && ((mode->quirks | st->drive_quirks)
+                       & (ST_Q_FORCE_FIXED_MODE))) {
+                       mode2->blksiz = mode->blksiz;
+                       st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK;
+               } else {
+                       if ((mode->quirks | st->drive_quirks)
+                           & ST_Q_FORCE_VAR_MODE) {
+                               mode2->blksiz = 0;
+                               st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK;
+                       }
+               }
+               if (mode->density) {
+                       mode2->density = mode->density;
+                       st->modeflags[i] |= DENSITY_SET_BY_QUIRK;
+               }
+               mode++;
+               mode2++;
+       }
+}
+
+/*
+ * open the device.
+ */
+errval 
 stopen(dev, flags)
 stopen(dev, flags)
-int    dev, flags;
+       dev_t   dev;
+       u_int32 flags;
 {
 {
-       int unit,mode,dsty;
-       int     errno = 0;
+       u_int32 unit, mode, dsty;
+       errval  errno = 0;
        struct st_data *st;
        struct st_data *st;
+       struct scsi_link *sc_link;
        unit = UNIT(dev);
        mode = MODE(dev);
        dsty = DSTY(dev);
 
        unit = UNIT(dev);
        mode = MODE(dev);
        dsty = DSTY(dev);
 
-       /*******************************************************\
-       * Check the unit is legal                               *
-       \*******************************************************/
-       if ( unit >= NST )
-       {
-               return(ENXIO);
+       /*
+        * Check the unit is legal
+        */
+       if (unit >= NST) {
+               return (ENXIO);
        }
        st = st_data[unit];
        }
        st = st_data[unit];
-       /*******************************************************\
-       * Make sure the device has been initialised             *
-       \*******************************************************/
+       /*
+        * Make sure the device has been initialised
+        */
        if ((st == NULL) || (!(st->flags & ST_INITIALIZED)))
        if ((st == NULL) || (!(st->flags & ST_INITIALIZED)))
-               return(ENXIO);
-
-       /*******************************************************\
-       * Only allow one at a time                              *
-       \*******************************************************/
-       if(st->flags & ST_OPEN)
-       {
-               return(ENXIO);
-       }
-
-       /*******************************************************\
-       * Throw out a dummy instruction to catch 'Unit attention*
-       * errors (the error handling will invalidate all our    *
-       * device info if we get one, but otherwise, ignore it   *
-       \*******************************************************/
-       st_test_ready(unit, SCSI_SILENT); 
-
-       /***************************************************************\
-       * Check that the device is ready to use  (media loaded?)        *
-       * This time take notice of the return result                    *
-       \***************************************************************/
-       if(errno = (st_test_ready(unit,0))) 
-       {
-               printf("st%d: not ready\n",unit);
-               return(errno);
-       }
-
-       /*******************************************************\
-       * Set up the mode flags according to the minor number   *
-       * ensure all open flags are in a known state            *
-       * if it's a different mode, dump all cached parameters  *
-       \*******************************************************/
-       if(st->last_dsty != dsty || !(st->flags & ST_INFO_VALID))
-       {
-               st->flags &= ~ST_INFO_VALID;
-               st->last_dsty = dsty;
-               st->quirks = st->drive_quirks | st->modes[dsty].quirks;
-               st->density = st->modes[dsty].density;
-       }
-       st->flags &= ~ST_PER_OPEN;
-
-#ifdef STDEBUG
-       if(scsi_debug & (PRINTROUTINES | TRACEOPENS))
-               printf("stopen: dev=0x%x (unit %d (of %d))\n"
-                               ,   dev,      unit,   NST);
-#endif /*STDEBUG*/
-       /***************************************************************\
-       * If the media is new, then make sure we give it a chance to    *
-       * to do a 'load' instruction.                                   *
-       \***************************************************************/
-       if(!(st->flags & ST_INFO_VALID))                /* is media new? */
-       {
-               if(errno = st_load(unit,LD_LOAD,0))
-               {
-                       return(errno);
-               }
-               st_test_ready(unit,0);
-               if(st->quirks & ST_Q_SNS_HLP)
-               {
-                       /***********************************************\
-                       * The quirk here is that the drive returns some *
-                       * value to st_mode_sense incorrectly until the  *
-                       * tape has actually passed by the head.         *
-                       *                                               *
-                       * The method is to set the drive to large       *
-                       * fixed-block state (user-specified density and *
-                       * 1024-byte blocks), then read and rewind to    *
-                       * get it to sense the tape.  If that doesn't    *
-                       * work, try 512-byte fixed blocks.  If that     *
-                       * doesn't work, as a last resort, try variable- *
-                       * length blocks.  The result will be the        *
-                       * ability to do an accurate st_mode_sense.      *
-                       *                                               *
-                       * We pretend not to be at beginning of medium   *
-                       * to keep st_read from calling st_decide_mode.  *
-                       *                                               *
-                       * We know we can do a rewind because we just    *
-                       * did a load, which implies rewind.  Rewind     *
-                       * seems preferable to space backward if we have *
-                       * a virgin tape.                                *
-                       *                                               *
-                       * The rest of the code for this quirk is in ILI *
-                       * processing and BLANK CHECK error processing,  *
-                       * both part of st_interpret_sense.              *
-                       \***********************************************/
-                       char    *buf;
-                       int     readsiz;
-
-                       buf = malloc(1024,M_TEMP,M_NOWAIT);
-                       if(!buf) return(ENOMEM);
-
-                       if (errno = st_mode_sense(unit, 0))
-                       {
-                               goto bad;
-                       }
-                       st->blksiz = 1024;
-                       do {
-                               switch (st->blksiz)
-                               {
-                               case    512:
-                               case    1024:
-                                       readsiz = st->blksiz;
-                                       st->flags |= ST_FIXEDBLOCKS;
-                                       break;
-                               default:
-                                       readsiz = 1;
-                                       st->flags &= ~ST_FIXEDBLOCKS;
-                               }
-                               if (errno = st_mode_select(unit, 0))
-                               {
-                                       goto bad;
-                               }
-                               st->flags &= ~ST_AT_BOM;
-                               st_read(unit, buf, readsiz, SCSI_SILENT);
-                               if (errno = st_rewind(unit, FALSE, 0))
-                               {
-bad:                                   free(buf,M_TEMP);
-                                       return(errno);
-                               }
-                       } while (readsiz != 1 && readsiz > st->blksiz);
-                       free(buf,M_TEMP);
-               }
+               return (ENXIO);
+
+       sc_link = st->sc_link;
+       SC_DEBUG(sc_link, SDEV_DB1, ("open: dev=0x%x (unit %d (of %d))\n"
+               ,dev, unit, NST));
+       /*
+        * Only allow one at a time
+        */
+       if (st->flags & ST_OPEN) {
+               return (EBUSY);
        }
        }
-
-       /*******************************************************\
-       * Load the physical device parameters                   *
-       * loads: blkmin, blkmax                                 *
-       \*******************************************************/
-       if(errno = st_rd_blk_lim(unit,0))
-       {
-               return(errno);
-       }
-
-       /*******************************************************\
-       * Load the media dependent parameters                   *
-       * includes: media_blksiz,media_density,numblks          *
-       \*******************************************************/
-       if(errno = st_mode_sense(unit,0))
-       {
-               return(errno);
+       /*
+        * Throw out a dummy instruction to catch 'Unit attention
+        * errors (the error handling will invalidate all our
+        * device info if we get one, but otherwise, ignore it)
+        */
+       scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+       sc_link->flags |= SDEV_OPEN;    /* unit attn are now errors */
+       /*
+        * If the mode is 3 (e.g. minor = 3,7,11,15)
+        * then the device has been openned to set defaults
+        * This mode does NOT ALLOW I/O, only ioctls
+        */
+       if (mode == CTLMODE)
+               return 0;
+
+       /*
+        * Check that the device is ready to use (media loaded?)
+        * This time take notice of the return result
+        */
+       if (errno = (scsi_test_unit_ready(sc_link, 0))) {
+               printf("st%d: not ready\n", unit);
+               st_unmount(unit, NOEJECT);
+               return (errno);
        }
        }
-
-       if (!(st->flags & ST_INFO_VALID) && dsty == 0)
-       {
-               /*******************************************************\
-               * If the user defaulted the density, use the drive's    *
-               * opinion of it.                                        *
-               \*******************************************************/
-               st->quirks = st->drive_quirks;
-               st->density = st->media_density;
-               do {
-                       if (st->density == st->modes[dsty].density)
-                       {
-                               st->quirks |= st->modes[dsty].quirks;
-#ifdef STDEBUG
-                               if(st_debug) printf("selected density %d\n", dsty);
-#endif /*STDEBUG*/
-                               break; /* only out of the loop*/
-                       }
-               } while (++dsty < 4);
-               /*******************************************************\
-               * If dsty got to 4, the drive must have reported a      *
-               * density which isn't in our density list (e.g. QIC-24  *
-               * for a default drive).  We can handle that, except     *
-               * there'd better be no density-specific quirks in the   *
-               * drive's behavior.                                     *
-               \*******************************************************/
+       /*
+        * if it's a different mode, or if the media has been
+        * invalidated, unmount the tape from the previous
+        * session but continue with open processing
+        */
+       if ((st->last_dsty != dsty)
+           || (!(sc_link->flags & SDEV_MEDIA_LOADED))) {
+               st_unmount(unit, NOEJECT);
        }
        }
-
-       /***************************************************************\
-       * Decide whether or not to write two file marks to signify end- *
-       * of-data.  Make the decision as a function of density.  If     *
-       * the decision is not to use a second file mark, the SCSI BLANK *
-       * CHECK condition code will be recognized as end-of-data when   *
-       * first read.                                                   *
-       \***************************************************************/
-       switch (st->density)
-       {
-/*     case    8 mm:   What is the SCSI density code for 8 mm, anyway? */
-       case    QIC_11:
-       case    QIC_24:
-       case    QIC_120:
-       case    QIC_150:
-       case    QIC_525:
-       case    QIC_1320:
-               st->flags &= ~ST_2FM_AT_EOD;
-               break;
-       default:
-               st->flags |= ST_2FM_AT_EOD;
+       /*
+        * If we are not mounted, then we should start a new 
+        * mount session.
+        */
+       if (!(st->flags & ST_MOUNTED)) {
+               st_mount_tape(dev, flags);
+               st->last_dsty = dsty;
        }
        }
-
-       /***************************************************************\
-       * Make sure that a tape opened in write-only mode will have     *
-       * file marks written on it.  This is the only way to write a    *
-       * zero-length file on tape.                                     *
-       \***************************************************************/
+       /*
+        * Make sure that a tape opened in write-only mode will have
+        * file marks written on it when closed, even if not written to.
+        * This is for SUN compatibility
+        */
        if ((flags & O_ACCMODE) == FWRITE)
                st->flags |= ST_WRITTEN;
 
        if ((flags & O_ACCMODE) == FWRITE)
                st->flags |= ST_WRITTEN;
 
-       st->flags |= ST_INFO_VALID;
-
-       st_prevent(unit,PR_PREVENT,0); /* who cares if it fails? */
-
-#ifdef STDEBUG
-       if(scsi_debug & TRACEOPENS)
-               printf("Params loaded ");
-#endif /*STDEBUG*/
+       SC_DEBUG(sc_link, SDEV_DB2, ("Open complete\n"));
 
        st->flags |= ST_OPEN;
 
        st->flags |= ST_OPEN;
-       return(0);
+       return (0);
 }
 
 }
 
-/*******************************************************\
-* close the device.. only called if we are the LAST    *
-* occurence of an open device                          *
-\*******************************************************/
+/*
+ * close the device.. only called if we are the LAST
+ * occurence of an open device
+ */
+errval 
 stclose(dev)
 stclose(dev)
+       dev_t   dev;
 {
 {
-       unsigned char unit,mode;
-       struct  st_data *st;
+       unsigned char unit, mode;
+       struct st_data *st;
+       struct scsi_link *sc_link;
 
        unit = UNIT(dev);
        mode = MODE(dev);
        st = st_data[unit];
 
        unit = UNIT(dev);
        mode = MODE(dev);
        st = st_data[unit];
-
-#ifdef STDEBUG
-       if(scsi_debug & TRACEOPENS)
-               printf("Closing device");
-#endif /*STDEBUG*/
-       switch(mode)
-       {
-       case    0:
-               st_rewind(unit,FALSE,SCSI_SILENT);
-               st_prevent(unit,PR_ALLOW,SCSI_SILENT);
-               st->flags &= ~ST_PER_MEDIA;
+       sc_link = st->sc_link;
+
+       SC_DEBUG(sc_link, SDEV_DB1, ("closing\n"));
+       if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
+               st_write_filemarks(unit, 1, 0);
+       switch (mode & 0x3) {
+       case 0:
+       case 3:         /* for now */
+               st_unmount(unit, NOEJECT);
                break;
                break;
-       case    1: /*non rewind*/
-               if((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
-                       st_write_filemarks(unit, 1, 0);
-               break;
-       case    2:
-               st_rewind(unit,FALSE,SCSI_SILENT);
-               st_prevent(unit,PR_ALLOW,SCSI_SILENT);
-               st_load(unit,LD_UNLOAD,SCSI_SILENT);
-               st->flags &= ~ST_PER_MEDIA;
+       case 1:         /*leave mounted unless media seems to have been removed */
+               if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
+                       st_unmount(unit, NOEJECT);
+               }
                break;
                break;
-       case    3:/* a bit silly really */
-               st_prevent(unit,PR_ALLOW,SCSI_SILENT);
-               st_load(unit,LD_UNLOAD,SCSI_SILENT);
-               st->flags &= ~ST_PER_MEDIA;
+       case 2:
+               st_unmount(unit, EJECT);
                break;
                break;
-       default:
-               printf("st%d: close: Bad mode (minor number)%d how's it open?\n"
-                               ,unit,mode);
-               return(EINVAL);
        }
        }
-       st->flags &= ~ST_PER_OPEN;
-       return(0);
+       sc_link->flags &= ~SDEV_OPEN;
+       st->flags &= ~ST_OPEN;
+       return (0);
 }
 
 }
 
-/***************************************************************\
-* Given all we know about the device, media, mode, 'quirks' and        *
-* initial operation, make a decision as to how we should be set        *
-* up.  First, choose the density, then variable/fixed blocks.  *
-\***************************************************************/
-st_decide_mode(unit, first_read)
-int    unit, first_read;
+/*
+ * Start a new mount session.
+ * Copy in all the default parameters from the selected device mode.
+ * and try guess any that seem to be defaulted.
+ */
+errval
+st_mount_tape(dev, flags)
+       dev_t   dev;
+       u_int32 flags;
 {
 {
-       int dsty, error;
-       struct st_data *st = st_data[unit];
+       u_int32 unit, mode, dsty;
+       struct st_data *st;
+       struct scsi_link *sc_link;
+       errval  errno = 0;
 
 
-       /***************************************************************\
-       * First, if our information about the tape is out of date, get  *
-       * new information.                                              *
-       \***************************************************************/
-       if (!(st->flags & ST_INFO_VALID))
-       {
-               if (error = st_mode_sense(unit, 0))
-                       return (error);
-               st->flags |= ST_INFO_VALID;
+       unit = UNIT(dev);
+       mode = MODE(dev);
+       dsty = DSTY(dev);
+       st = st_data[unit];
+       sc_link = st->sc_link;
+
+       if (st->flags & ST_MOUNTED)
+               return 0;
+
+       SC_DEBUG(sc_link, SDEV_DB1, ("mounting\n "));
+       st->flags |= ST_NEW_MOUNT;
+       st->quirks = st->drive_quirks | st->modes[dsty].quirks;
+       /*
+        * If the media is new, then make sure we give it a chance to
+        * to do a 'load' instruction. ( We assume it is new)
+        */
+       if (errno = st_load(unit, LD_LOAD, 0)) {
+               return (errno);
        }
        }
-#ifdef STDEBUG
-       if(st_debug) printf("starting mode decision\n");
-#endif /*STDEBUG*/
-
-       /***************************************************************\
-       * If the user has already specified fixed or variable-length    *
-       * blocks using an ioctl, just believe him. OVERRIDE ALL         *
-       \***************************************************************/
-       if (st->flags & ST_BLOCK_SET)
-       {
-#ifdef STDEBUG
-       if(st_debug) printf("user has specified %s mode\n",
-               st->flags & ST_FIXEDBLOCKS ?  "fixed" : "variable");
-#endif /*STDEBUG*/
-               goto done;
+       /*
+        * Throw another dummy instruction to catch
+        * 'Unit attention' errors. Some drives appear to give
+        * these after doing a Load instruction.
+        * (noteably some DAT drives)
+        */
+       scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+       /*
+        * Some devices can't tell you much until they have been
+        * asked to look at the media. This quirk does this.
+        */
+       if (st->quirks & ST_Q_SNS_HLP) {
+               if (errno = st_touch_tape(unit))
+                       return errno;
+       }
+       /*
+        * Load the physical device parameters
+        * loads: blkmin, blkmax
+        */
+       if (errno = st_rd_blk_lim(unit, 0)) {
+               return errno;
+       }
+       /*
+        * Load the media dependent parameters
+        * includes: media_blksiz,media_density,numblks
+        * As we have a tape in, it should be reflected here.
+        * If not you may need the "quirk" above.
+        */
+       if (errno = st_mode_sense(unit, 0)) {
+               return errno;
+       }
+       /*
+        * If we have gained a permanent density from somewhere,
+        * then use it in preference to the one supplied by
+        * default by the driver.
+        */
+       if (st->modeflags[dsty] & (DENSITY_SET_BY_QUIRK | DENSITY_SET_BY_USER)) {
+               st->density = st->modes[dsty].density;
+       } else {
+               st->density = st->media_density;
+       }
+       /*
+        * If we have gained a permanent blocksize
+        * then use it in preference to the one supplied by
+        * default by the driver.
+        */
+       st->flags &= ~ST_FIXEDBLOCKS;
+       if (st->modeflags[dsty] & (BLKSIZE_SET_BY_QUIRK | BLKSIZE_SET_BY_USER)) {
+               st->blksiz = st->modes[dsty].blksiz;
+               if (st->blksiz) {
+                       st->flags |= ST_FIXEDBLOCKS;
+               }
+       } else {
+               if (errno = st_decide_mode(unit, FALSE)) {
+                       return errno;
+               }
        }
        }
+       if (errno = st_mode_select(unit, 0)) {
+               printf("st%d: Cannot set selected mode", unit);
+               return errno;
+       }
+       scsi_prevent(sc_link, PR_PREVENT, 0);   /* who cares if it fails? */
+       st->flags &= ~ST_NEW_MOUNT;
+       st->flags |= ST_MOUNTED;
+       sc_link->flags |= SDEV_MEDIA_LOADED;    /* move earlier? */
 
 
-       /***************************************************************\
-       * If the user hasn't already specified fixed or variable-length *
-       * blocks and the block size (zero if variable-length), we'll    *
-       * have to try to figure them out ourselves.                     *
-       *                                                               *
-       * Our first shot at a method is, "The quirks made me do it!"    *
-       \***************************************************************/
-       switch (st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE))
-       {
-       case    (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE):
-               printf("st%d: bad quirks\n",unit);
+       return 0;
+}
+
+/*
+ * End the present mount session.
+ * Rewind, and optionally eject the tape.
+ * Reset various flags to indicate that all new
+ * operations require another mount operation
+ */
+void
+st_unmount(int unit, boolean eject)
+{
+       struct st_data *st = st_data[unit];
+       struct scsi_link *sc_link = st->sc_link;
+       int32   nmarks;
+
+       if (!(st->flags & ST_MOUNTED))
+               return;
+       SC_DEBUG(sc_link, SDEV_DB1, ("unmounting\n"));
+       st_chkeod(unit, FALSE, &nmarks, SCSI_SILENT);
+       st_rewind(unit, FALSE, SCSI_SILENT);
+       scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
+       if (eject) {
+               st_load(unit, LD_UNLOAD, SCSI_SILENT);
+       }
+       st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT);
+       sc_link->flags &= ~SDEV_MEDIA_LOADED;
+}
+
+/*
+ * Given all we know about the device, media, mode, 'quirks' and
+ * initial operation, make a decision as to how we should be set
+ * to run (regarding blocking and EOD marks)
+ */
+errval 
+st_decide_mode(unit, first_read)
+       u_int32 unit;
+       boolean first_read;
+{
+       struct st_data *st = st_data[unit];
+#ifdef SCSIDEBUG
+       struct scsi_link *sc_link = st->sc_link;
+#endif
+
+       SC_DEBUG(sc_link, SDEV_DB2, ("starting block mode decision\n"));
+
+       /*
+        * If the user hasn't already specified fixed or variable-length
+        * blocks and the block size (zero if variable-length), we'll
+        * have to try to figure them out ourselves.
+        *
+        * Our first shot at a method is, "The quirks made me do it!"
+        */
+       switch ((int)(st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE))) {
+       case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE):
+               printf("st%d: bad quirks\n", unit);
                return (EINVAL);
                return (EINVAL);
-       case    ST_Q_FORCE_FIXED_MODE:
+       case ST_Q_FORCE_FIXED_MODE:     /*specified fixed, but not what size */
                st->flags |= ST_FIXEDBLOCKS;
                if (st->blkmin && (st->blkmin == st->blkmax))
                        st->blksiz = st->blkmin;
                st->flags |= ST_FIXEDBLOCKS;
                if (st->blkmin && (st->blkmin == st->blkmax))
                        st->blksiz = st->blkmin;
-               else if(st->media_blksiz > 0)
+               else if (st->media_blksiz > 0)
                        st->blksiz = st->media_blksiz;
                else
                        st->blksiz = DEF_FIXED_BSIZE;
                        st->blksiz = st->media_blksiz;
                else
                        st->blksiz = DEF_FIXED_BSIZE;
-#ifdef STDEBUG
-               if(st_debug) printf("Quirks force fixed mode\n");
-#endif /*STDEBUG*/
+               SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force fixed mode(%d)\n",
+                       st->blksiz));
                goto done;
                goto done;
-       case    ST_Q_FORCE_VAR_MODE:
+       case ST_Q_FORCE_VAR_MODE:
                st->flags &= ~ST_FIXEDBLOCKS;
                st->blksiz = 0;
                st->flags &= ~ST_FIXEDBLOCKS;
                st->blksiz = 0;
-#ifdef STDEBUG
-               if(st_debug) printf("Quirks force variable mode\n");
-#endif /*STDEBUG*/
+               SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force variable mode\n"));
                goto done;
        }
                goto done;
        }
-
-       /***************************************************************\
-       * If the drive can only handle fixed-length blocks and only at  *
-       * one size, perhaps we should just do that.                     *
-       \***************************************************************/
-       if (st->blkmin && (st->blkmin == st->blkmax))
-       {
+               /*
+                * If the drive can only handle fixed-length blocks and only at
+                * one size, perhaps we should just do that.
+                */
+               if (st->blkmin && (st->blkmin == st->blkmax)) {
                st->flags |= ST_FIXEDBLOCKS;
                st->blksiz = st->blkmin;
                st->flags |= ST_FIXEDBLOCKS;
                st->blksiz = st->blkmin;
-#ifdef STDEBUG
-               if(st_debug) printf("blkmin == blkmax of %d\n",st->blkmin);
-#endif /*STDEBUG*/
+               SC_DEBUG(sc_link, SDEV_DB3,
+                   ("blkmin == blkmax of %d\n", st->blkmin));
                goto done;
        }
                goto done;
        }
-
-       /***************************************************************\
-       * If the tape density mandates use of fixed or variable-length  *
-       * blocks, comply.                                               *
-       \***************************************************************/
-       switch (st->density)
-       {
-       case    HALFINCH_800:
-       case    HALFINCH_1600:
-       case    HALFINCH_6250:
-       case    DDS:
+       /*
+        * If the tape density mandates (or even suggests) use of fixed
+        * or variable-length blocks, comply.
+        */
+       switch ((int)st->density) {
+       case HALFINCH_800:
+       case HALFINCH_1600:
+       case HALFINCH_6250:
+       case DDS:
                st->flags &= ~ST_FIXEDBLOCKS;
                st->blksiz = 0;
                st->flags &= ~ST_FIXEDBLOCKS;
                st->blksiz = 0;
-#ifdef STDEBUG
-       if(st_debug) printf("density specified variable\n");
-#endif /*STDEBUG*/
+               SC_DEBUG(sc_link, SDEV_DB3, ("density specified variable\n"));
                goto done;
                goto done;
-       case    QIC_11:
-       case    QIC_24:
-       case    QIC_120:
-       case    QIC_150:
+       case QIC_11:
+       case QIC_24:
+       case QIC_120:
+       case QIC_150:
+       case QIC_525:
+       case QIC_1320:
                st->flags |= ST_FIXEDBLOCKS;
                st->flags |= ST_FIXEDBLOCKS;
-               if (st->media_blksiz > 0)
+               if (st->media_blksiz > 0) {
                        st->blksiz = st->media_blksiz;
                        st->blksiz = st->media_blksiz;
-               else
+               } else {
                        st->blksiz = DEF_FIXED_BSIZE;
                        st->blksiz = DEF_FIXED_BSIZE;
-#ifdef STDEBUG
-       if(st_debug) printf("density specified fixed\n");
-#endif /*STDEBUG*/
+               }
+               SC_DEBUG(sc_link, SDEV_DB3, ("density specified fixed\n"));
                goto done;
        }
                goto done;
        }
-
-       /***************************************************************\
-       * If we're about to read the tape, perhaps we should choose     *
-       * fixed or variable-length blocks and block size according to   *
-       * what the drive found on the tape.                             *
-       \***************************************************************/
-       if (first_read && (!(st->quirks & ST_Q_BLKSIZ) || st->media_blksiz == 0
-           || st->media_blksiz == DEF_FIXED_BSIZE || st->media_blksiz == 1024))
-       {
-               if (st->media_blksiz == 0)
+       /*
+        * If we're about to read the tape, perhaps we should choose
+        * fixed or variable-length blocks and block size according to
+        * what the drive found on the tape.
+        */
+       if (first_read
+           && (!(st->quirks & ST_Q_BLKSIZ)
+               || (st->media_blksiz == 0)
+               || (st->media_blksiz == DEF_FIXED_BSIZE)
+               || (st->media_blksiz == 1024))) {
+               if (st->media_blksiz == 0) {
                        st->flags &= ~ST_FIXEDBLOCKS;
                        st->flags &= ~ST_FIXEDBLOCKS;
-               else
+               } else {
                        st->flags |= ST_FIXEDBLOCKS;
                        st->flags |= ST_FIXEDBLOCKS;
+               }
                st->blksiz = st->media_blksiz;
                st->blksiz = st->media_blksiz;
-#ifdef STDEBUG
-               if(st_debug) printf("Used media_blksiz of %d\n",st->media_blksiz);
-#endif /*STDEBUG*/
+               SC_DEBUG(sc_link, SDEV_DB3,
+                   ("Used media_blksiz of %d\n", st->media_blksiz));
                goto done;
        }
                goto done;
        }
-
-       /***************************************************************\
-       * We're getting no hints from any direction.  Choose variable-  *
-       * length blocks arbitrarily.                                    *
-       \***************************************************************/
+       /*
+        * We're getting no hints from any direction.  Choose variable-
+        * length blocks arbitrarily.
+        */
        st->flags &= ~ST_FIXEDBLOCKS;
        st->blksiz = 0;
        st->flags &= ~ST_FIXEDBLOCKS;
        st->blksiz = 0;
-#ifdef STDEBUG
-       if(st_debug) printf("Give up and default to variable mode\n");
-#endif /*STDEBUG*/
+       SC_DEBUG(sc_link, SDEV_DB3, ("Give up and default to variable mode\n"));
 done:
 done:
-       st->flags &= ~ST_AT_BOM;
-       return (st_mode_select(unit, 0));
+
+       /*
+        * Decide whether or not to write two file marks to signify end-
+        * of-data.  Make the decision as a function of density.  If
+        * the decision is not to use a second file mark, the SCSI BLANK
+        * CHECK condition code will be recognized as end-of-data when
+        * first read.
+        * (I think this should be a by-product of fixed/variable..julian)
+        */
+       switch ((int)st->density) {
+/*      case    8 mm:   What is the SCSI density code for 8 mm, anyway? */
+       case QIC_11:
+       case QIC_24:
+       case QIC_120:
+       case QIC_150:
+       case QIC_525:
+       case QIC_1320:
+               st->flags &= ~ST_2FM_AT_EOD;
+               break;
+       default:
+               st->flags |= ST_2FM_AT_EOD;
+       }
+       return 0;
 }
 
 }
 
-/*******************************************************\
-* trim the size of the transfer if needed,             *
-* called by physio                                     *
-* basically the smaller of our min and the scsi driver's*
-* minphys                                              *
-\*******************************************************/
-void   stminphys(bp)
-struct buf     *bp;
+/*
+ * trim the size of the transfer if needed,
+ * called by physio
+ * basically the smaller of our min and the scsi driver's
+ * minphys
+ */
+void 
+stminphys(bp)
+       struct buf *bp;
 {
 {
-       (*(st_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp);
+       (*(st_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
 }
 
 }
 
-/*******************************************************\
-* Actually translate the requested transfer into       *
-* one the physical driver can understand               *
-* The transfer is described by a buf and will include  *
-* only one physical transfer.                          *
-\*******************************************************/
-
-int    ststrategy(bp)
-struct buf     *bp;
+/*
+ * Actually translate the requested transfer into
+ * one the physical driver can understand
+ * The transfer is described by a buf and will include
+ * only one physical transfer.
+ */
+void 
+ststrategy(bp)
+       struct buf *bp;
 {
 {
-       struct  buf     **dp;
+       struct buf **dp;
        unsigned char unit;
        unsigned char unit;
-       unsigned int opri;
+       u_int32 opri;
        struct st_data *st;
 
        ststrats++;
        unit = UNIT((bp->b_dev));
        st = st_data[unit];
        struct st_data *st;
 
        ststrats++;
        unit = UNIT((bp->b_dev));
        st = st_data[unit];
-#ifdef STDEBUG
-       if(scsi_debug & PRINTROUTINES) printf("\nststrategy ");
-       if(scsi_debug & SHOWREQUESTS) printf("st%d: %d bytes @ blk%d\n",
-                                       unit,bp->b_bcount,bp->b_blkno);
-#endif /*STDEBUG*/
-       /*******************************************************\
-       * If it's a null transfer, return immediatly            *
-       \*******************************************************/
-       if (bp->b_bcount == 0)
-       {
+       SC_DEBUG(st->sc_link, SDEV_DB1,
+           (" strategy: %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno));
+       /*
+        * If it's a null transfer, return immediatly
+        */
+       if (bp->b_bcount == 0) {
                goto done;
        }
                goto done;
        }
-
-       /*******************************************************\
-       * If we're at beginning of medium, now is the time to   *
-       * set medium access density, fixed or variable-blocks   *
-       * and, if fixed, the block size.                        *
-       \*******************************************************/
-       if (st->flags & ST_AT_BOM &&
-           (bp->b_error = st_decide_mode(unit, (bp->b_flags & B_READ) != 0)))
-               goto bad;
-
-       /*******************************************************\
-       * Odd sized request on fixed drives are verboten        *
-       \*******************************************************/
-       if(st->flags & ST_FIXEDBLOCKS)
-       {
-               if(bp->b_bcount % st->blksiz)
-               {
+       /*
+        * Odd sized request on fixed drives are verboten
+        */
+       if (st->flags & ST_FIXEDBLOCKS) {
+               if (bp->b_bcount % st->blksiz) {
                        printf("st%d: bad request, must be multiple of %d\n",
                        printf("st%d: bad request, must be multiple of %d\n",
-                               unit, st->blksiz);
+                           unit, st->blksiz);
                        bp->b_error = EIO;
                        goto bad;
                }
        }
                        bp->b_error = EIO;
                        goto bad;
                }
        }
-       /*******************************************************\
-       * as are out-of-range requests on variable drives.      *
-       \*******************************************************/
-       else if(bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax)
-       {
+       /*
+        * as are out-of-range requests on variable drives.
+        */
+       else if (bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax) {
                printf("st%d: bad request, must be between %d and %d\n",
                printf("st%d: bad request, must be between %d and %d\n",
-                       unit, st->blkmin, st->blkmax);
+                   unit, st->blkmin, st->blkmax);
                bp->b_error = EIO;
                goto bad;
        }
                bp->b_error = EIO;
                goto bad;
        }
-
        stminphys(bp);
        opri = splbio();
 
        stminphys(bp);
        opri = splbio();
 
-       /*******************************************************\
-       * Place it in the queue of activities for this tape     *
-       * at the end (a bit silly because we only have on user..*
-       * (but it could fork() ))                               *
-       \*******************************************************/
+       /*
+        * Place it in the queue of activities for this tape
+        * at the end (a bit silly because we only have on user..
+        * (but it could fork() ))
+        */
        dp = &(st->buf_queue);
        dp = &(st->buf_queue);
-       while (*dp) 
-       {
+       while (*dp) {
                dp = &((*dp)->b_actf);
                dp = &((*dp)->b_actf);
-       }       
+       }
        *dp = bp;
        *dp = bp;
-       bp->b_actf = NULL,
+       bp->b_actf = NULL;
 
 
-       /*******************************************************\
-       * Tell the device to get going on the transfer if it's  *
-       * not doing anything, otherwise just wait for completion*
-       * (All a bit silly if we're only allowing 1 open but..) *
-       \*******************************************************/
+       /*
+        * Tell the device to get going on the transfer if it's
+        * not doing anything, otherwise just wait for completion
+        * (All a bit silly if we're only allowing 1 open but..)
+        */
        ststart(unit);
 
        splx(opri);
        ststart(unit);
 
        splx(opri);
@@ -928,1443 +935,994 @@ struct buf     *bp;
 bad:
        bp->b_flags |= B_ERROR;
 done:
 bad:
        bp->b_flags |= B_ERROR;
 done:
-       /*******************************************************\
-       * Correctly set the buf to indicate a completed xfer    *
-       \*******************************************************/
+       /*
+        * Correctly set the buf to indicate a completed xfer
+        */
        iodone(bp);
        return;
 }
 
        iodone(bp);
        return;
 }
 
+/*
+ * ststart looks to see if there is a buf waiting for the device
+ * and that the device is not already busy. If both are true,
+ * It dequeues the buf and creates a scsi command to perform the
+ * transfer required. The transfer request will call scsi_done
+ * on completion, which will in turn call this routine again
+ * so that the next queued transfer is performed.
+ * The bufs are queued by the strategy routine (ststrategy)
+ *
+ * This routine is also called after other non-queued requests
+ * have been made of the scsi driver, to ensure that the queue
+ * continues to be drained.
+ * ststart() is called at splbio
+ */
+void 
+ststart(unit)
+       u_int32 unit;
+{
+       struct st_data *st = st_data[unit];
+       struct scsi_link *sc_link = st->sc_link;
+       register struct buf *bp = 0;
+       struct scsi_rw_tape cmd;
+       u_int32 flags;
+
+       SC_DEBUG(sc_link, SDEV_DB2, ("ststart "));
+       /*
+        * See if there is a buf to do and we are not already
+        * doing one
+        */
+       while (sc_link->opennings != 0) {
+
+               /* if a special awaits, let it proceed first */
+               if (sc_link->flags & SDEV_WAITING) {
+                       sc_link->flags &= ~SDEV_WAITING;
+                       wakeup((caddr_t)sc_link);
+                       return;
+               }
+               if ((bp = st->buf_queue) == NULL) {
+                       return; /* no work to bother with */
+               }
+               st->buf_queue = bp->b_actf;
+
+               /*
+                * if the device has been unmounted byt the user
+                * then throw away all requests until done
+                */
+               if ((!(st->flags & ST_MOUNTED))
+                   || (!(sc_link->flags & SDEV_MEDIA_LOADED))) {
+                       /* make sure that one implies the other.. */
+                       sc_link->flags &= ~SDEV_MEDIA_LOADED;
+                       goto badnews;
+               }
+               /*
+                * only FIXEDBLOCK devices have pending operations
+                */
+               if (st->flags & ST_FIXEDBLOCKS) {
+                       /*
+                        * If we are at a filemark but have not reported it yet
+                        * then we should report it now
+                        */
+                       if (st->flags & ST_AT_FILEMARK) {
+                               if ((bp->b_flags & B_READ) == B_WRITE) {
+                                       /*
+                                        * Handling of ST_AT_FILEMARK in
+                                        * st_space will fill in the right file
+                                        * mark count.
+                                        * Back up over filemark
+                                        */
+                                       if (st_space(unit, 0, SP_FILEMARKS, 0) !=
+                                           ESUCCESS)
+                                               goto badnews;
+                               } else {
+                                       bp->b_resid = bp->b_bcount;
+                                       bp->b_error = 0;
+                                       bp->b_flags &= ~B_ERROR;
+                                       st->flags &= ~ST_AT_FILEMARK;
+                                       biodone(bp);
+                                       continue;       /* seek more work */
+                               }
+                       }
+                       /*
+                        * If we are at EIO (e.g. EOM) but have not reported it
+                        * yet then we should report it now
+                        */
+                       if (st->flags & ST_EIO_PENDING) {
+                               bp->b_resid = bp->b_bcount;
+                               bp->b_error = EIO;
+                               bp->b_flags |= B_ERROR;
+                               st->flags &= ~ST_EIO_PENDING;
+                               biodone(bp);
+                               continue;       /* seek more work */
+                       }
+               }
+               /*
+                *  Fill out the scsi command
+                */
+               bzero(&cmd, sizeof(cmd));
+               if ((bp->b_flags & B_READ) == B_WRITE) {
+                       cmd.op_code = WRITE_COMMAND_TAPE;
+                       st->flags &= ~ST_FM_WRITTEN;
+                       st->flags |= ST_WRITTEN;
+                       flags = SCSI_DATA_OUT;
+               } else {
+                       cmd.op_code = READ_COMMAND_TAPE;
+                       flags = SCSI_DATA_IN;
+               }
+               /*
+                * Handle "fixed-block-mode" tape drives by using the
+                * block count instead of the length.
+                */
+               if (st->flags & ST_FIXEDBLOCKS) {
+                       cmd.byte2 |= SRWT_FIXED;
+                       lto3b(bp->b_bcount / st->blksiz, cmd.len);
+               } else {
+                       lto3b(bp->b_bcount, cmd.len);
+               }
+               /*
+                * go ask the adapter to do all this for us
+                */
+               if (scsi_scsi_cmd(sc_link,
+                       (struct scsi_generic *) &cmd,
+                       sizeof(cmd),
+                       (u_char *) bp->b_un.b_addr,
+                       bp->b_bcount,
+                       0,      /* can't retry a read on a tape really */
+                       100000,
+                       bp,
+                       flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) {
+                       stqueues++;
+               } else {
+badnews:
+                       printf("st%d: oops not queued\n", unit);
+                       bp->b_flags |= B_ERROR;
+                       bp->b_error = EIO;
+                       biodone(bp);
+               }
+       } /* go back and see if we can cram more work in.. */
+}
 
 
-
-/*******************************************************\
-* Perform special action on behalf of the user         *
-* Knows about the internals of this device             *
-\*******************************************************/
-stioctl(dev, cmd, arg, mode)
-dev_t dev;
-int cmd;
-caddr_t arg;
+/*
+ * Perform special action on behalf of the user;
+ * knows about the internals of this device
+ */
+errval 
+stioctl(dev, cmd, arg, flag)
+       dev_t   dev;
+       int     cmd;
+       caddr_t arg;
+       int     flag;
 {
 {
-       int errcode = 0;
+       errval  errcode = 0;
        unsigned char unit;
        unsigned char unit;
-       int number,flags,dsty;
-        struct  st_data *st;
-       
-
-       /*******************************************************\
-       * Find the device that the user is talking about        *
-       \*******************************************************/
-       flags = 0;      /* give error messages, act on errors etc. */
+       u_int32 number, flags, dsty;
+       struct st_data *st;
+       u_int32 hold_blksiz;
+       u_int32 hold_density;
+       int32   nmarks;
+       struct mtop *mt = (struct mtop *) arg;
+
+       /*
+        * Find the device that the user is talking about
+        */
+       flags = 0;              /* give error messages, act on errors etc. */
        unit = UNIT(dev);
        dsty = DSTY(dev);
        unit = UNIT(dev);
        dsty = DSTY(dev);
-        st = st_data[unit];
+       st = st_data[unit];
+       hold_blksiz = st->blksiz;
+       hold_density = st->density;
 
 
-       switch(cmd)
-       {
+       switch (cmd) {
 
        case MTIOCGET:
 
        case MTIOCGET:
-           {
-               struct mtget *g = (struct mtget *) arg;
-
-               bzero(g, sizeof(struct mtget));
-               g->mt_type = 0x7;       /* Ultrix compat */ /*?*/
-                if (st->flags & ST_FIXEDBLOCKS) { 
-                        g->mt_bsiz = st->blksiz;
-                } else {
-                        g->mt_bsiz = 0;
-                }
-               g->mt_dns_dflt          = st->modes[0].density;
-               g->mt_dns_dsty1         = st->modes[DSTY1].density;
-               g->mt_dns_dsty2         = st->modes[DSTY2].density;
-               g->mt_dns_dsty3         = st->modes[DSTY3].density;
-               break;
-           }
-
-
+               {
+                       struct mtget *g = (struct mtget *) arg;
+
+                       SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: get status]\n"));
+                       bzero(g, sizeof(struct mtget));
+                       g->mt_type = 0x7;       /* Ultrix compat *//*? */
+                       g->mt_density = st->density;
+                       g->mt_blksiz = st->blksiz;
+                       g->mt_density0 = st->modes[0].density;
+                       g->mt_density1 = st->modes[1].density;
+                       g->mt_density2 = st->modes[2].density;
+                       g->mt_density3 = st->modes[3].density;
+                       g->mt_blksiz0 = st->modes[0].blksiz;
+                       g->mt_blksiz1 = st->modes[1].blksiz;
+                       g->mt_blksiz2 = st->modes[2].blksiz;
+                       g->mt_blksiz3 = st->modes[3].blksiz;
+                       break;
+               }
        case MTIOCTOP:
        case MTIOCTOP:
-           {
-               int nmarks;
-               struct mtop *mt = (struct mtop *) arg;
-
-#ifdef STDEBUG
-               if (st_debug)
-                       printf("[sctape_sstatus: %x %x]\n",
-                                mt->mt_op, mt->mt_count);
-#endif /*STDEBUG*/
-
+               {
 
 
+                       SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: op=0x%x count=0x%x]\n",
+                               mt->mt_op, mt->mt_count));
 
 
-               /* compat: in U*x it is a short */
-               number = mt->mt_count;
-               switch ((short)(mt->mt_op))
-               {
-               case MTWEOF:    /* write an end-of-file record */
-                       errcode = st_write_filemarks(unit,number,flags);
-                       break;
-               case MTBSF:     /* backward space file */
-                       number = -number;
-               case MTFSF:     /* forward space file */
-                       errcode = st_chkeod(unit, FALSE, &nmarks, flags);
-                       if (errcode == ESUCCESS)
-                               errcode = st_space(unit, number - nmarks,
-                                   SP_FILEMARKS, flags);
-                       break;
-               case MTBSR:     /* backward space record */
-                       number = -number;
-               case MTFSR:     /* forward space record */
-                       errcode = st_chkeod(unit, TRUE, &nmarks, flags);
-                       if (errcode == ESUCCESS)
-                               errcode = st_space(unit,number,SP_BLKS,flags);
-                       break;
-               case MTREW:     /* rewind */
-                       errcode = st_rewind(unit,FALSE,flags);
-                       break;
-               case MTOFFL:    /* rewind and put the drive offline */
-                       if(st_rewind(unit,FALSE,flags))
-                       {
-                               printf("st%d: rewind failed, unit still loaded\n",
-                                       unit);
-                       }
-                       else
-                       {
-                               st_prevent(unit,PR_ALLOW,0);
-                               st_load(unit,LD_UNLOAD,flags);
-                       }
-                       break;
-               case MTNOP:     /* no operation, sets status only */
-               case MTCACHE:   /* enable controller cache */
-               case MTNOCACHE: /* disable controller cache */
-                       break;
-               case MTSETBSIZ: /* Set block size for device */
-                       if (!(st->flags & ST_AT_BOM))
-                       {
-                               errcode =  EINVAL;
+                       /* compat: in U*x it is a short */
+                       number = mt->mt_count;
+                       switch ((short) (mt->mt_op)) {
+                       case MTWEOF:    /* write an end-of-file record */
+                               errcode = st_write_filemarks(unit, number, flags);
                                break;
                                break;
-                       }
-                       if (number == 0)
-                       {
-                               st->flags &= ~ST_FIXEDBLOCKS;
-                       }
-                       else
-                       {
-                               if ((st->blkmin || st->blkmax) /* they exist */
-                                 && ((number < st->blkmin 
-                                   || number > st->blkmax)))
-                               {
+                       case MTBSF:     /* backward space file */
+                               number = -number;
+                       case MTFSF:     /* forward space file */
+                               errcode = st_chkeod(unit, FALSE, &nmarks, flags);
+                               if (errcode == ESUCCESS)
+                                       errcode = st_space(unit, number - nmarks,
+                                           SP_FILEMARKS, flags);
+                               break;
+                       case MTBSR:     /* backward space record */
+                               number = -number;
+                       case MTFSR:     /* forward space record */
+                               errcode = st_chkeod(unit, TRUE, &nmarks, flags);
+                               if (errcode == ESUCCESS)
+                                       errcode = st_space(unit, number, SP_BLKS, flags);
+                               break;
+                       case MTREW:     /* rewind */
+                               errcode = st_rewind(unit, FALSE, flags);
+                               break;
+                       case MTOFFL:    /* rewind and put the drive offline */
+                               st_unmount(unit, EJECT);
+                               break;
+                       case MTNOP:     /* no operation, sets status only */
+                       case MTCACHE:   /* enable controller cache */
+                       case MTNOCACHE: /* disable controller cache */
+                               break;
+                       case MTSETBSIZ: /* Set block size for device */
+#ifdef NOTYET
+                               if (!(st->flags & ST_NEW_MOUNT)) {
+                                       uprintf("re-mount tape before changing blocksize");
                                        errcode = EINVAL;
                                        break;
                                }
                                        errcode = EINVAL;
                                        break;
                                }
-                               st->flags |= ST_FIXEDBLOCKS;
-                       }
-                       st->blksiz = number;
-                       st->flags |= ST_BLOCK_SET;
-                        break;
+#endif
+                               if (number == 0) {
+                                       st->flags &= ~ST_FIXEDBLOCKS;
+                               } else {
+                                       if ((st->blkmin || st->blkmax)  /* they exist */
+                                           &&((number < st->blkmin
+                                                   || number > st->blkmax))) {
+                                               errcode = EINVAL;
+                                               break;
+                                       }
+                                       st->flags |= ST_FIXEDBLOCKS;
+                               }
+                               st->blksiz = number;
+                               st->flags |= ST_BLOCK_SET;      /*XXX */
+                               goto try_new_value;
 
 
-                       /* How do we check that the drive can handle
-                          the requested density ? */
+                       case MTSETDNSTY:        /* Set density for device and mode */
+                               if (number > SCSI_2_MAX_DENSITY_CODE) {
+                                       errcode = EINVAL;
+                               } else {
+                                       st->density = number;
+                               }
+                               goto try_new_value;
 
 
-                case MTSETDNSTY: /* Set density for device and mode */
-                       if (number < 0 || number > SCSI_2_MAX_DENSITY_CODE)
-                       {
+                       default:
                                errcode = EINVAL;
                        }
                                errcode = EINVAL;
                        }
-                       else
-                       { 
-                               st->modes[dsty].density = number;
-                       }
                        break;
                        break;
-
-               default:
-                       errcode = EINVAL;
                }
                }
-               break;
-           }
        case MTIOCIEOT:
        case MTIOCEEOT:
                break;
        default:
        case MTIOCIEOT:
        case MTIOCEEOT:
                break;
        default:
-               errcode = EINVAL;
+               if(MODE(dev) == CTLMODE)
+                       errcode = scsi_do_ioctl(st->sc_link,cmd,arg,flag);
+               else
+                       errcode = ENOTTY;
+               break;
        }
        }
-
        return errcode;
        return errcode;
+/*-----------------------------*/
+try_new_value:
+       /*
+        * Check that the mode being asked for is aggreeable to the
+        * drive. If not, put it back the way it was.
+        */
+       if (errcode = st_mode_select(unit, 0)) {        /* put it back as it was */
+               printf("st%d: Cannot set selected mode", unit);
+               st->density = hold_density;
+               st->blksiz = hold_blksiz;
+               if (st->blksiz) {
+                       st->flags |= ST_FIXEDBLOCKS;
+               } else {
+                       st->flags &= ~ST_FIXEDBLOCKS;
+               }
+               return (errcode);
+       }
+       /*
+        * As the drive liked it, if we are setting a new default,
+        * set it into the structures as such.
+        * 
+        * The means for deciding this are not finalised yet
+        */
+       if (MODE(dev) == 0x03) {
+               /* special mode */
+               /* XXX */
+               switch ((short) (mt->mt_op)) {
+               case MTSETBSIZ:
+                       st->modes[dsty].blksiz = st->blksiz;
+                       st->modeflags[dsty] |= BLKSIZE_SET_BY_USER;
+                       break;
+               case MTSETDNSTY:
+                       st->modes[dsty].density = st->density;
+                       st->modeflags[dsty] |= DENSITY_SET_BY_USER;
+                       break;
+               }
+       }
+       return 0;
 }
 
 }
 
-/*******************************************************\
-* Do a synchronous read.                               *
-\*******************************************************/
-int st_read(unit, buf, size, flags)
-int    unit, size, flags;
-char   *buf;
+/*
+ * Do a synchronous read.
+ */
+errval 
+st_read(unit, buf, size, flags)
+       u_int32 unit, size, flags;
+       char   *buf;
 {
 {
-       int error;
        struct scsi_rw_tape scsi_cmd;
        struct st_data *st = st_data[unit];
 
        struct scsi_rw_tape scsi_cmd;
        struct st_data *st = st_data[unit];
 
-       /*******************************************************\
-       * If it's a null transfer, return immediatly            *
-       \*******************************************************/
-       if (size == 0)
-       {
-               return(ESUCCESS);
+       /*
+        * If it's a null transfer, return immediatly
+        */
+       if (size == 0) {
+               return (ESUCCESS);
        }
        }
-
-       /*******************************************************\
-       * If we're at beginning of medium, now is the time to   *
-       * set medium access density, fixed or variable-blocks   *
-       * and, if fixed, the block size.                        *
-       \*******************************************************/
-       if (st->flags & ST_AT_BOM && (error = st_decide_mode(unit, TRUE)))
-               return (error);
-
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = READ_COMMAND_TAPE;
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = READ_COMMAND_TAPE;
-       scsi_cmd.byte2 |= st->flags & ST_FIXEDBLOCKS ? SRWT_FIXED : 0;
-       lto3b(scsi_cmd.byte2 & SRWT_FIXED ?
-           size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE) : size,
-           scsi_cmd.len);
-       return (st_scsi_cmd(unit,
-                       &scsi_cmd,
-                       sizeof(scsi_cmd),
-                       buf,
-                       size,
-                       100000,
-                       NULL,
-                       flags | SCSI_DATA_IN));
-}
-
-/*******************************************************\
-* Get scsi driver to send a "are you ready" command    *
-\*******************************************************/
-st_test_ready(unit,flags)
-int    unit,flags;
-{
-       struct  scsi_test_unit_ready scsi_cmd;
-
-       bzero(&scsi_cmd, sizeof(scsi_cmd));
-       scsi_cmd.op_code = TEST_UNIT_READY;
-
-       return (st_scsi_cmd(unit,
-                       &scsi_cmd,
-                       sizeof(scsi_cmd),
-                       0,
-                       0,
-                       100000,
-                       NULL,
-                       flags));
+       if (st->flags & ST_FIXEDBLOCKS) {
+               scsi_cmd.byte2 |= SRWT_FIXED;
+               lto3b(size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE),
+                   scsi_cmd.len);
+       } else {
+               lto3b(size, scsi_cmd.len);
+       }
+       return (scsi_scsi_cmd(st->sc_link,
+               (struct scsi_generic *) &scsi_cmd,
+               sizeof(scsi_cmd),
+               (u_char *) buf,
+               size,
+               0,              /* not on io commands */
+               100000,
+               NULL,
+               flags | SCSI_DATA_IN));
 }
 }
-
-
 #ifdef __STDC__
 #define b2tol(a)       (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
 #else
 #define b2tol(a)       (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 )
 #endif
 
 #ifdef __STDC__
 #define b2tol(a)       (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
 #else
 #define b2tol(a)       (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 )
 #endif
 
-/*******************************************************\
-* Ask the drive what it's min and max blk sizes are.   *
-\*******************************************************/
+/*
+ * Ask the drive what it's min and max blk sizes are.
+ */
+errval 
 st_rd_blk_lim(unit, flags)
 st_rd_blk_lim(unit, flags)
-int    unit,flags;
+       u_int32 unit, flags;
 {
 {
-       struct  scsi_blk_limits scsi_cmd;
+       struct scsi_blk_limits scsi_cmd;
        struct scsi_blk_limits_data scsi_blkl;
        struct st_data *st = st_data[unit];
        struct scsi_blk_limits_data scsi_blkl;
        struct st_data *st = st_data[unit];
-       int     errno;
-
-       /*******************************************************\
-       * First check if we have it all loaded                  *
-       \*******************************************************/
-       if ((st->flags & ST_INFO_VALID)) return 0;
-
-       /*******************************************************\
-       * do a 'Read Block Limits'                              *
-       \*******************************************************/
+       errval  errno;
+       struct scsi_link *sc_link = st->sc_link;
+
+       /*
+        * First check if we have it all loaded
+        */
+       if ((sc_link->flags & SDEV_MEDIA_LOADED))
+               return 0;
+
+       /*
+        * do a 'Read Block Limits'
+        */
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = READ_BLK_LIMITS;
 
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = READ_BLK_LIMITS;
 
-       /*******************************************************\
-       * do the command,       update the global values        *
-       \*******************************************************/
-       if ( errno = st_scsi_cmd(unit,
-                       &scsi_cmd,
-                       sizeof(scsi_cmd),
-                       &scsi_blkl,
-                       sizeof(scsi_blkl),
-                       5000,
-                       NULL,
-                       flags | SCSI_DATA_IN))
-       {
+       /*
+        * do the command, update the global values
+        */
+       if (errno = scsi_scsi_cmd(sc_link,
+               (struct scsi_generic *) &scsi_cmd,
+               sizeof(scsi_cmd),
+               (u_char *) & scsi_blkl,
+               sizeof(scsi_blkl),
+               ST_RETRIES,
+               5000,
+               NULL,
+               flags | SCSI_DATA_IN)) {
                return errno;
                return errno;
-       } 
+       }
        st->blkmin = b2tol(scsi_blkl.min_length);
        st->blkmax = _3btol(&scsi_blkl.max_length_2);
 
        st->blkmin = b2tol(scsi_blkl.min_length);
        st->blkmax = _3btol(&scsi_blkl.max_length_2);
 
-#ifdef STDEBUG
-       if (st_debug)
-       {
-               printf("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax);
-       }
-#endif /*STDEBUG*/
+       SC_DEBUG(sc_link, SDEV_DB3,
+           ("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax));
        return 0;
 }
 
        return 0;
 }
 
-/*******************************************************\
-* Get the scsi driver to send a full inquiry to the    *
-* device and use the results to fill out the global    *
-* parameter structure.                                 *
-*                                                      *
-* called from:                                         *
-* attach                                               *
-* open                                                 *
-* ioctl (to reset original blksize)                    *
-\*******************************************************/
+/*
+ * Get the scsi driver to send a full inquiry to the
+ * device and use the results to fill out the global 
+ * parameter structure.
+ *
+ * called from:
+ * attach
+ * open
+ * ioctl (to reset original blksize)
+ */
+errval 
 st_mode_sense(unit, flags)
 st_mode_sense(unit, flags)
-int    unit,flags;
+       u_int32 unit, flags;
 {
 {
-       int     scsi_sense_len;
-       int     errno;
-       char    *scsi_sense_ptr;
-       struct scsi_mode_sense          scsi_cmd;
-       struct scsi_sense
-       {
-               struct  scsi_mode_header header;
-               struct  blk_desc        blk_desc;
-       }scsi_sense;
+       u_int32 scsi_sense_len;
+       errval  errno;
+       char   *scsi_sense_ptr;
+       struct scsi_mode_sense scsi_cmd;
+       struct scsi_sense {
+               struct scsi_mode_header header;
+               struct blk_desc blk_desc;
+       } scsi_sense;
+
+       struct scsi_sense_page_0 {
+               struct scsi_mode_header header;
+               struct blk_desc blk_desc;
+               unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
+                       /* Tandberg tape drives returns page 00
+                        * with the sense data, whether or not
+                        * you want it( ie the don't like you
+                        * saying you want anything less!!!!!
+                        * They also expect page 00
+                        * back when you issue a mode select
+                        */
+       } scsi_sense_page_0;
+       struct st_data *st = st_data[unit];
+       struct scsi_link *sc_link = st->sc_link;
 
 
-       struct scsi_sense_page_0
-       {
-               struct  scsi_mode_header header;
-               struct  blk_desc        blk_desc;
-                unsigned char   sense_data[PAGE_0_SENSE_DATA_SIZE];
-                        /* Tandberg tape drives returns page 00 */
-                        /* with the sense data, whether or not */
-                        /* you want it( ie the don't like you  */
-                        /* saying you want anything less!!!!!  */
-                        /* They also expect page 00 */
-                        /* back when you issue a mode select */
-       }scsi_sense_page_0;
-       struct  st_data *st = st_data[unit];
-       
-       /*******************************************************\
-       * First check if we have it all loaded                  *
-       \*******************************************************/
-       if ((st->flags & ST_INFO_VALID)) return 0;
-
-       /*******************************************************\
-       * Define what sort of structure we're working with      *
-       \*******************************************************/
-       if (st->quirks & ST_Q_NEEDS_PAGE_0)
-       {
+       /*
+        * Define what sort of structure we're working with
+        */
+       if (st->quirks & ST_Q_NEEDS_PAGE_0) {
                scsi_sense_len = sizeof(scsi_sense_page_0);
                scsi_sense_ptr = (char *) &scsi_sense_page_0;
                scsi_sense_len = sizeof(scsi_sense_page_0);
                scsi_sense_ptr = (char *) &scsi_sense_page_0;
-       }
-       else
-       {
+       } else {
                scsi_sense_len = sizeof(scsi_sense);
                scsi_sense_ptr = (char *) &scsi_sense;
        }
                scsi_sense_len = sizeof(scsi_sense);
                scsi_sense_ptr = (char *) &scsi_sense;
        }
-
-       /*******************************************************\
-       * Set up a mode sense                                   *
-       \*******************************************************/
+       /*
+        * Set up a mode sense 
+        */
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = MODE_SENSE;
        scsi_cmd.length = scsi_sense_len;
 
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = MODE_SENSE;
        scsi_cmd.length = scsi_sense_len;
 
-       /*******************************************************\
-       * do the command, but we don't need the results         *
-       * just print them for our interest's sake, if asked,    *
-       * or if we need it as a template for the mode select    *
-       * store it away.                                        *
-       \*******************************************************/
-       if (errno = st_scsi_cmd(unit,
-                       &scsi_cmd,
-                       sizeof(scsi_cmd),
-                       scsi_sense_ptr,
-                       scsi_sense_len,
-                       5000,
-                       NULL,
-                       flags | SCSI_DATA_IN) )
-       {
+       /*
+        * do the command, but we don't need the results
+        * just print them for our interest's sake, if asked,
+        * or if we need it as a template for the mode select
+        * store it away.
+        */
+       if (errno = scsi_scsi_cmd(sc_link,
+               (struct scsi_generic *) &scsi_cmd,
+               sizeof(scsi_cmd),
+               (u_char *) scsi_sense_ptr,
+               scsi_sense_len,
+               ST_RETRIES,
+               5000,
+               NULL,
+               flags | SCSI_DATA_IN)) {
                return errno;
                return errno;
-       } 
-       st->numblks = _3btol(&(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks));
-       st->media_blksiz = _3btol(&(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen));
-       st->media_density = ((struct scsi_sense *)scsi_sense_ptr)->blk_desc.density;
-       if (((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec &
-           SMH_DSP_WRITE_PROT)
+       }
+       st->numblks = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks);
+       st->media_blksiz = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen);
+       st->media_density = ((struct scsi_sense *) scsi_sense_ptr)->blk_desc.density;
+       if (((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec &
+           SMH_DSP_WRITE_PROT) {
                st->flags |= ST_READONLY;
                st->flags |= ST_READONLY;
-#ifdef STDEBUG
-       if (st_debug)
-       {
-               printf("st%d: density code 0x%x, %d-byte blocks, write-%s, ",
-                   unit, st->media_density, st->media_blksiz,
-                   st->flags & ST_READONLY ? "protected" : "enabled");
-               printf("%sbuffered\n",
-                   ((struct scsi_sense *)scsi_sense_ptr)->header.dev_spec
-                   & SMH_DSP_BUFF_MODE ? "" : "un");
        }
        }
-#endif /*STDEBUG*/
-       if (st->quirks & ST_Q_NEEDS_PAGE_0)
-       {
-               bcopy(((struct scsi_sense_page_0 *)scsi_sense_ptr)->sense_data, 
-                       st->sense_data, 
-                       sizeof(((struct scsi_sense_page_0 *)scsi_sense_ptr)->sense_data));
+       SC_DEBUG(sc_link, SDEV_DB3,
+           ("density code 0x%x, %d-byte blocks, write-%s, ",
+               st->media_density, st->media_blksiz,
+               st->flags & ST_READONLY ? "protected" : "enabled"));
+       SC_DEBUG(sc_link, SDEV_DB3,
+           ("%sbuffered\n",
+               ((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec
+               & SMH_DSP_BUFF_MODE ? "" : "un"));
+       if (st->quirks & ST_Q_NEEDS_PAGE_0) {
+               bcopy(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data,
+                   st->sense_data,
+                   sizeof(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data));
        }
        }
+       sc_link->flags |= SDEV_MEDIA_LOADED;
        return 0;
 }
 
        return 0;
 }
 
-/*******************************************************\
-* Send a filled out parameter structure to the drive to        *
-* set it into the desire modes etc.                    *
-\*******************************************************/
+/*
+ * Send a filled out parameter structure to the drive to
+ * set it into the desire modes etc.
+ */
+errval 
 st_mode_select(unit, flags)
 st_mode_select(unit, flags)
-int    unit, flags;
+       u_int32 unit, flags;
 {
 {
-       int     dat_len;
-       char    *dat_ptr;
+       u_int32 dat_len;
+       char   *dat_ptr;
        struct scsi_mode_select scsi_cmd;
        struct scsi_mode_select scsi_cmd;
-       struct dat
-       {
-               struct  scsi_mode_header header;
-               struct  blk_desc        blk_desc;
-       }dat;
-       struct dat_page_0
-       {
-               struct  scsi_mode_header header;
-               struct  blk_desc        blk_desc;
-                unsigned char   sense_data[PAGE_0_SENSE_DATA_SIZE];
-       }dat_page_0;
-       struct  st_data *st = st_data[unit];
-
-       /*******************************************************\
-       * Define what sort of structure we're working with      *
-       \*******************************************************/
-       if (st->quirks & ST_Q_NEEDS_PAGE_0)
-       {
+       struct dat {
+               struct scsi_mode_header header;
+               struct blk_desc blk_desc;
+       } dat;
+       struct dat_page_0 {
+               struct scsi_mode_header header;
+               struct blk_desc blk_desc;
+               unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
+       } dat_page_0;
+       struct st_data *st = st_data[unit];
+
+       /*
+        * Define what sort of structure we're working with
+        */
+       if (st->quirks & ST_Q_NEEDS_PAGE_0) {
                dat_len = sizeof(dat_page_0);
                dat_ptr = (char *) &dat_page_0;
                dat_len = sizeof(dat_page_0);
                dat_ptr = (char *) &dat_page_0;
-       }
-       else
-       {
+       } else {
                dat_len = sizeof(dat);
                dat_ptr = (char *) &dat;
        }
                dat_len = sizeof(dat);
                dat_ptr = (char *) &dat;
        }
-               
-       /*******************************************************\
-       * Set up for a mode select                              *
-       \*******************************************************/
+       /*
+        * Set up for a mode select
+        */
        bzero(dat_ptr, dat_len);
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = MODE_SELECT;
        scsi_cmd.length = dat_len;
        bzero(dat_ptr, dat_len);
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = MODE_SELECT;
        scsi_cmd.length = dat_len;
-       ((struct dat *)dat_ptr)->header.blk_desc_len = sizeof(struct  blk_desc);
-       ((struct dat *)dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
-       ((struct dat *)dat_ptr)->blk_desc.density = st->density;
-       if(st->flags & ST_FIXEDBLOCKS)
-       {
-               lto3b( st->blksiz , ((struct dat *)dat_ptr)->blk_desc.blklen);
+       ((struct dat *) dat_ptr)->header.blk_desc_len = sizeof(struct blk_desc);
+       ((struct dat *) dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
+       ((struct dat *) dat_ptr)->blk_desc.density = st->density;
+       if (st->flags & ST_FIXEDBLOCKS) {
+               lto3b(st->blksiz, ((struct dat *) dat_ptr)->blk_desc.blklen);
        }
        }
-       if (st->quirks & ST_Q_NEEDS_PAGE_0)
-       {
-               bcopy(st->sense_data, ((struct dat_page_0 *)dat_ptr)->sense_data, 
-                       sizeof(((struct dat_page_0 *)dat_ptr)->sense_data));
-                       /* the Tandberg tapes need the block size to */
-                       /* be set on each mode sense/select. */
+       if (st->quirks & ST_Q_NEEDS_PAGE_0) {
+               bcopy(st->sense_data, ((struct dat_page_0 *) dat_ptr)->sense_data,
+                   sizeof(((struct dat_page_0 *) dat_ptr)->sense_data));
+               /* the Tandberg tapes need the block size to */
+               /* be set on each mode sense/select. */
        }
        }
-       /*******************************************************\
-       * do the command                                        *
-       \*******************************************************/
-       return (st_scsi_cmd(unit,
-                       &scsi_cmd,
-                       sizeof(scsi_cmd),
-                       dat_ptr,
-                       dat_len,
-                       5000,
-                       NULL,
-                       flags | SCSI_DATA_OUT) );
+       /*
+        * do the command
+        */
+       return (scsi_scsi_cmd(st->sc_link,
+               (struct scsi_generic *) &scsi_cmd,
+               sizeof(scsi_cmd),
+               (u_char *) dat_ptr,
+               dat_len,
+               ST_RETRIES,
+               5000,
+               NULL,
+               flags | SCSI_DATA_OUT));
 }
 
 }
 
-/*******************************************************\
-* skip N blocks/filemarks/seq filemarks/eom            *
-\*******************************************************/
-st_space(unit,number,what,flags)
-int    unit,number,what,flags;
+/*
+ * skip N blocks/filemarks/seq filemarks/eom
+ */
+errval 
+st_space(unit, number, what, flags)
+       u_int32 unit, what, flags;
+       int32   number;
 {
 {
-       int error;
+       errval  error;
        struct scsi_space scsi_cmd;
        struct scsi_space scsi_cmd;
-       struct  st_data *st = st_data[unit];
-
-       /*******************************************************\
-       * If we're at beginning of medium, now is the time to   *
-       * set medium access density, fixed or variable-blocks   *
-       * and, if fixed, the block size.                        *
-       \*******************************************************/
-       if (st->flags & ST_AT_BOM &&
-           (error = st_decide_mode(unit, TRUE)))
-               return (error);
+       struct st_data *st = st_data[unit];
 
 
-       switch (what)
-       {
-       case    SP_BLKS:
-               if (st->flags & ST_PER_ACTION)
-               {
-                       if (number > 0)
-                       {
+       switch ((int)what) {
+       case SP_BLKS:
+               if (st->flags & ST_PER_ACTION) {
+                       if (number > 0) {
                                st->flags &= ~ST_PER_ACTION;
                                st->flags &= ~ST_PER_ACTION;
-                               return(EIO);
-                       }
-                       else if (number < 0)
-                       {
-                               if (st->flags & ST_AT_FILEMARK)
-                               {
-                                       /*******************************\
-                                       * Handling of ST_AT_FILEMARK    *
-                                       * in st_space will fill in the  *
-                                       * right file mark count.        *
-                                       \*******************************/
+                               return (EIO);
+                       } else if (number < 0) {
+                               if (st->flags & ST_AT_FILEMARK) {
+                                       /*
+                                        * Handling of ST_AT_FILEMARK
+                                        * in st_space will fill in the
+                                        * right file mark count.
+                                        */
                                        error = st_space(unit, 0, SP_FILEMARKS,
                                            flags);
                                        error = st_space(unit, 0, SP_FILEMARKS,
                                            flags);
-                                       if (error) return(error);
+                                       if (error)
+                                               return (error);
                                }
                                }
-                               if (st->flags & ST_BLANK_READ)
-                               {
+                               if (st->flags & ST_BLANK_READ) {
                                        st->flags &= ~ST_BLANK_READ;
                                        st->flags &= ~ST_BLANK_READ;
-                                       return(EIO);
+                                       return (EIO);
                                }
                                st->flags &= ~ST_EIO_PENDING;
                        }
                }
                break;
                                }
                                st->flags &= ~ST_EIO_PENDING;
                        }
                }
                break;
-       case    SP_FILEMARKS:
-               if (st->flags & ST_EIO_PENDING)
-               {
-                       if (number > 0)
-                       {
+       case SP_FILEMARKS:
+               if (st->flags & ST_EIO_PENDING) {
+                       if (number > 0) {       /* pretend we just discover the error */
                                st->flags &= ~ST_EIO_PENDING;
                                st->flags &= ~ST_EIO_PENDING;
-                               return(EIO);
-                       }
-                       else if (number < 0)
+                               return (EIO);
+                       } else if (number < 0) {        /* back away from the error */
                                st->flags &= ~ST_EIO_PENDING;
                                st->flags &= ~ST_EIO_PENDING;
+                       }
                }
                }
-               if (st->flags & ST_AT_FILEMARK)
-               {
+               if (st->flags & ST_AT_FILEMARK) {
                        st->flags &= ~ST_AT_FILEMARK;
                        number--;
                }
                        st->flags &= ~ST_AT_FILEMARK;
                        number--;
                }
-               if (st->flags & ST_BLANK_READ && number < 0)
-               {
+               if ((st->flags & ST_BLANK_READ) && (number < 0)) {      /* back away from unwritten tape */
                        st->flags &= ~ST_BLANK_READ;
                        st->flags &= ~ST_BLANK_READ;
-                       number++;
+                       number++;       /* dubious */
                }
        }
                }
        }
-       if (number == 0)
-               return(ESUCCESS);
+       if (number == 0) {
+               return (ESUCCESS);
+       }
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = SPACE;
        scsi_cmd.byte2 = what & SS_CODE;
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = SPACE;
        scsi_cmd.byte2 = what & SS_CODE;
-       lto3b(number,scsi_cmd.number);
-       return (st_scsi_cmd(unit,
-                       &scsi_cmd,
-                       sizeof(scsi_cmd),
-                       0,
-                       0,
-                       600000, /* 10 mins enough? */
-                       NULL,
-                       flags));
+       lto3b(number, scsi_cmd.number);
+       return (scsi_scsi_cmd(st->sc_link,
+               (struct scsi_generic *) &scsi_cmd,
+               sizeof(scsi_cmd),
+               0,
+               0,
+               0,              /* no retries please , just fail */
+               600000,         /* 10 mins enough? */
+               NULL,
+               flags));
 }
 }
-/*******************************************************\
-* write N filemarks                                    *
-\*******************************************************/
-st_write_filemarks(unit,number,flags)
-int    unit,number,flags;
+
+/*
+ * write N filemarks
+ */
+errval 
+st_write_filemarks(unit, number, flags)
+       u_int32 unit, flags;
+       int32   number;
 {
 {
-       int error;
        struct scsi_write_filemarks scsi_cmd;
        struct scsi_write_filemarks scsi_cmd;
-       struct  st_data *st = st_data[unit];
-
-       /*******************************************************\
-       * It's hard to write a negative number of file marks.   *
-       * Don't try.                                            *
-       \*******************************************************/
-       if (number < 0)
-               return (EINVAL);
-
-       /*******************************************************\
-       * If we're at beginning of medium, now is the time to   *
-       * set medium access density, fixed or variable-blocks   *
-       * and, if fixed, the block size.                        *
-       \*******************************************************/
-       if (st->flags & ST_AT_BOM && number > 0 &&
-           (error = st_decide_mode(unit, FALSE)))
-               return (error);
+       struct st_data *st = st_data[unit];
 
 
-       switch (number)
-       {
-       case    0:      /* really a command to sync the drive's buffers */
+       /*
+        * It's hard to write a negative number of file marks.
+        * Don't try.
+        */
+       if (number < 0) {
+               return EINVAL;
+       }
+       switch ((int)number) {
+       case 0:         /* really a command to sync the drive's buffers */
                break;
                break;
-       case    1:
-               if (st->flags & ST_FM_WRITTEN)
+       case 1:
+               if (st->flags & ST_FM_WRITTEN) {        /* already have one down */
                        st->flags &= ~ST_WRITTEN;
                        st->flags &= ~ST_WRITTEN;
-               else
+               } else {
                        st->flags |= ST_FM_WRITTEN;
                        st->flags |= ST_FM_WRITTEN;
+               }
                st->flags &= ~ST_PER_ACTION;
                break;
        default:
                st->flags &= ~(ST_PER_ACTION | ST_WRITTEN);
        }
                st->flags &= ~ST_PER_ACTION;
                break;
        default:
                st->flags &= ~(ST_PER_ACTION | ST_WRITTEN);
        }
-
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = WRITE_FILEMARKS;
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = WRITE_FILEMARKS;
-       lto3b(number,scsi_cmd.number);
-       return (st_scsi_cmd(unit,
-                       &scsi_cmd,
-                       sizeof(scsi_cmd),
-                       0,
-                       0,
-                       100000, /* 10 secs.. (may need to repos head )*/
-                       NULL,
-                       flags) );
+       lto3b(number, scsi_cmd.number);
+       return scsi_scsi_cmd(st->sc_link,
+               (struct scsi_generic *) &scsi_cmd,
+               sizeof(scsi_cmd),
+               0,
+               0,
+               0,              /* no retries, just fail */
+               100000,         /* 10 secs.. (may need to repos head ) */
+               NULL,
+               flags);
 }
 
 }
 
-/***************************************************************\
-* Make sure the right number of file marks is on tape if the   *
-* tape has been written.  If the position argument is true,    *
-* leave the tape positioned where it was originally.           *
-*                                                              *
-* nmarks returns the number of marks to skip (or, if position  *
-* true, which were skipped) to get back original position.     *
-\***************************************************************/
+/*
+ * Make sure the right number of file marks is on tape if the
+ * tape has been written.  If the position argument is true,
+ * leave the tape positioned where it was originally.
+ *
+ * nmarks returns the number of marks to skip (or, if position
+ * true, which were skipped) to get back original position.
+ */
+int32 
 st_chkeod(unit, position, nmarks, flags)
 st_chkeod(unit, position, nmarks, flags)
-int    unit;
-int    position;
-int    *nmarks;
-int    flags;
+       u_int32 unit;
+       boolean position;
+       int32  *nmarks;
+       u_int32 flags;
 {
 {
-       int     error;
-       struct  st_data *st = st_data[unit];
+       errval  error;
+       struct st_data *st = st_data[unit];
 
 
-       switch (st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD))
-       {
+       switch ((int)(st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD))) {
        default:
                *nmarks = 0;
        default:
                *nmarks = 0;
-               return(ESUCCESS);
-       case    ST_WRITTEN:
-       case    ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD:
+               return (ESUCCESS);
+       case ST_WRITTEN:
+       case ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD:
                *nmarks = 1;
                break;
                *nmarks = 1;
                break;
-       case    ST_WRITTEN | ST_2FM_AT_EOD:
+       case ST_WRITTEN | ST_2FM_AT_EOD:
                *nmarks = 2;
        }
        error = st_write_filemarks(unit, *nmarks, flags);
                *nmarks = 2;
        }
        error = st_write_filemarks(unit, *nmarks, flags);
-       if (position && error == ESUCCESS)
+       if (position && (error == ESUCCESS))
                error = st_space(unit, -*nmarks, SP_FILEMARKS, flags);
        return (error);
 }
 
                error = st_space(unit, -*nmarks, SP_FILEMARKS, flags);
        return (error);
 }
 
-/*******************************************************\
-* load/unload (with retension if true)                 *
-\*******************************************************/
-st_load(unit,type,flags)
-int    unit,type,flags;
+/*
+ * load/unload (with retension if true)
+ */
+errval 
+st_load(unit, type, flags)
+       u_int32 unit, type, flags;
 {
 {
-       struct  scsi_load  scsi_cmd;
-       struct  st_data *st = st_data[unit];
+       struct scsi_load scsi_cmd;
+       struct st_data *st = st_data[unit];
+       struct scsi_link *sc_link = st->sc_link;
 
 
-       st->flags &= ~ST_PER_MEDIA;
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        bzero(&scsi_cmd, sizeof(scsi_cmd));
-       if (type == LD_LOAD)
-       {
-               /*scsi_cmd.how |= LD_RETEN;*/
-               st->flags |= ST_AT_BOM;
-       }
-       else
-       {
-               int     error, nmarks;
+       if (type != LD_LOAD) {
+               errval  error;
+               int32   nmarks;
 
                error = st_chkeod(unit, FALSE, &nmarks, flags);
 
                error = st_chkeod(unit, FALSE, &nmarks, flags);
-               if (error != ESUCCESS) return(error);
-               st->flags &= ~ST_INFO_VALID;
+               if (error != ESUCCESS)
+                       return (error);
+               sc_link->flags &= ~SDEV_MEDIA_LOADED;
        }
        }
-       if(st->quirks & ST_Q_IGNORE_LOADS) return(0);
+       if (st->quirks & ST_Q_IGNORE_LOADS)
+               return (0);
        scsi_cmd.op_code = LOAD_UNLOAD;
        scsi_cmd.how |= type;
        scsi_cmd.op_code = LOAD_UNLOAD;
        scsi_cmd.how |= type;
-       return (st_scsi_cmd(unit,
-                       &scsi_cmd,
-                       sizeof(scsi_cmd),
-                       0,
-                       0,
-                       300000, /* 5 min */
-                       NULL,
-                       flags));
+       return (scsi_scsi_cmd(st->sc_link,
+               (struct scsi_generic *) &scsi_cmd,
+               sizeof(scsi_cmd),
+               0,
+               0,
+               ST_RETRIES,
+               300000,         /* 5 min */
+               NULL,
+               flags));
 }
 }
-/*******************************************************\
-* Prevent or allow the user to remove the tape         *
-\*******************************************************/
-st_prevent(unit,type,flags)
-int    unit,type,flags;
-{
-       struct  scsi_prevent    scsi_cmd;
-
-       if (type == PR_ALLOW)
-       {
-               int     error, nmarks;
 
 
-               error = st_chkeod(unit, TRUE, &nmarks, flags);
-               if (error != ESUCCESS) return(error);
-               st_data[unit]->flags &= ~ST_INFO_VALID;
-       }
-       bzero(&scsi_cmd, sizeof(scsi_cmd));
-       scsi_cmd.op_code = PREVENT_ALLOW;
-       scsi_cmd.how=type;
-       return (st_scsi_cmd(unit,
-                       &scsi_cmd,
-                       sizeof(scsi_cmd),
-                       0,
-                       0,
-                       5000,
-                       NULL,
-                       flags));
-}
-/*******************************************************\
-*  Rewind the device                                   *
-\*******************************************************/
-st_rewind(unit,immed,flags)
-int    unit,immed,flags;
+/*
+ *  Rewind the device
+ */
+errval 
+st_rewind(unit, immed, flags)
+       u_int32 unit, flags;
+       boolean immed;
 {
 {
-       struct  scsi_rewind     scsi_cmd;
-       struct  st_data *st = st_data[unit];
-       int     error, nmarks;
+       struct scsi_rewind scsi_cmd;
+       struct st_data *st = st_data[unit];
+       errval  error;
+       int32   nmarks;
 
        error = st_chkeod(unit, FALSE, &nmarks, flags);
 
        error = st_chkeod(unit, FALSE, &nmarks, flags);
-       if (error != ESUCCESS) return(error);
+       if (error != ESUCCESS)
+               return (error);
        st->flags &= ~ST_PER_ACTION;
        st->flags &= ~ST_PER_ACTION;
-       st->flags |= ST_AT_BOM;
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = REWIND;
        scsi_cmd.byte2 = immed ? SR_IMMED : 0;
        bzero(&scsi_cmd, sizeof(scsi_cmd));
        scsi_cmd.op_code = REWIND;
        scsi_cmd.byte2 = immed ? SR_IMMED : 0;
-       return (st_scsi_cmd(unit,
-                       &scsi_cmd,
-                       sizeof(scsi_cmd),
-                       0,
-                       0,
-                       immed?5000:300000, /* 5 sec or 5 min */
-                       NULL,
-                       flags));
-}
-
-/***************************************************************\
-* ststart looks to see if there is a buf waiting for the device        *
-* and that the device is not already busy. If both are true,   *
-* It deques the buf and creates a scsi command to perform the  *
-* transfer in the buf. The transfer request will call st_done  *
-* on completion, which will in turn call this routine again    *
-* so that the next queued transfer is performed.               *
-* The bufs are queued by the strategy routine (ststrategy)     *
-*                                                              *
-* This routine is also called after other non-queued requests  *
-* have been made of the scsi driver, to ensure that the queue  *
-* continues to be drained.                                     *
-\***************************************************************/
-/* ststart() is called at splbio */
-ststart(unit)
-{
-       int                     drivecount;
-       register struct buf     *bp = 0;
-       register struct buf     *dp;
-       struct  scsi_rw_tape    cmd;
-       int                     blkno, nblk;
-       struct  st_data         *st = st_data[unit];
-       int                     flags;
-
-
-
-#ifdef STDEBUG
-       if(scsi_debug & PRINTROUTINES) printf("ststart%d ",unit);
-#endif /*STDEBUG*/
-       /*******************************************************\
-       * See if there is a buf to do and we are not already    *
-       * doing one                                             *
-       \*******************************************************/
-       if(st->scsi_xfer.flags & INUSE)
-       {
-               return;    /* unit already underway */
-       }
-trynext:
-       if(st->xfer_block_wait) /* a special awaits, let it proceed first */
-       {
-               wakeup(&(st->xfer_block_wait));
-               return;
-       }
-
-       if ((bp = st->buf_queue) == NULL)
-       {
-               return; /* no work to bother with */
-       }
-       st->buf_queue = bp->b_actf;
-
-
-
-       /*******************************************************\
-       * only FIXEDBLOCK devices have pending operations       *
-       \*******************************************************/
-       if(st->flags & ST_FIXEDBLOCKS)
-       {
-               /*******************************************************\
-               *  If we are at a filemark but have not reported it yet *
-               * then we should report it now                          *
-               \*******************************************************/
-               if(st->flags & ST_AT_FILEMARK)
-               {
-                       if ((bp->b_flags & B_READ) == B_WRITE)
-                       {
-                               /***************************************\
-                               * Handling of ST_AT_FILEMARK in         *
-                               * st_space will fill in the right file  *
-                               * mark count.                           *
-                               \***************************************/
-                               if (st_space(unit, 0, SP_FILEMARKS, 0) !=
-                                   ESUCCESS) goto badnews;
-                       }
-                       else
-                       {
-                               bp->b_resid = bp->b_bcount;
-                               bp->b_error = 0;
-                               bp->b_flags &= ~B_ERROR;
-                               st->flags &= ~ST_AT_FILEMARK;
-                               biodone(bp);
-                               goto trynext;
-                       }
-               }
-               /*******************************************************\
-               *  If we are at EIO (e.g. EOM) but have not reported it *
-               * yet then we should report it now                      *
-               \*******************************************************/
-               if(st->flags & ST_EIO_PENDING)
-               {
-                       bp->b_resid = bp->b_bcount;
-                       bp->b_error = EIO;
-                       bp->b_flags |= B_ERROR;
-                       st->flags &= ~ST_EIO_PENDING;
-                       biodone(bp);
-                       goto trynext;
-               }
-       }
-       /*******************************************************\
-       *  Fill out the scsi command                            *
-       \*******************************************************/
-       bzero(&cmd, sizeof(cmd));
-       if((bp->b_flags & B_READ) == B_WRITE)
-       {
-               cmd.op_code = WRITE_COMMAND_TAPE;
-               st->flags &= ~ST_FM_WRITTEN;
-               st->flags |= ST_WRITTEN;
-               flags = SCSI_DATA_OUT;
-       }
-       else
-       {
-               cmd.op_code = READ_COMMAND_TAPE;
-               flags = SCSI_DATA_IN;
-       }
-
-       /*******************************************************\
-       * Handle "fixed-block-mode" tape drives by using the    *
-       * block count instead of the length.                    *
-       \*******************************************************/
-       if(st->flags & ST_FIXEDBLOCKS)
-       {
-               cmd.byte2 |= SRWT_FIXED;
-               lto3b(bp->b_bcount/st->blksiz,cmd.len);
-       }
-       else
-       {
-               lto3b(bp->b_bcount,cmd.len);
-       }
-
-       /*******************************************************\
-       * go ask the adapter to do all this for us              *
-       \*******************************************************/
-       if (st_scsi_cmd(unit,
-                       &cmd,
-                       sizeof(cmd),
-                       (u_char *)bp->b_un.b_addr,
-                       bp->b_bcount,
-                       100000,
-                       bp,
-                       flags | SCSI_NOSLEEP ) != SUCCESSFULLY_QUEUED)
-
-       {
-badnews:
-               printf("st%d: oops not queued\n",unit);
-               bp->b_flags |= B_ERROR;
-               bp->b_error = EIO;
-               biodone(bp);
-               return;
-       }
-       stqueues++;
+       return (scsi_scsi_cmd(st->sc_link,
+               (struct scsi_generic *) &scsi_cmd,
+               sizeof(scsi_cmd),
+               0,
+               0,
+               ST_RETRIES,
+               immed ? 5000 : 300000,  /* 5 sec or 5 min */
+               NULL,
+               flags));
 }
 
 }
 
-/*******************************************************\
-* This routine is called by the scsi interrupt when    *
-* the transfer is complete.
-\*******************************************************/
-int    st_done(unit,xs)
-int    unit;
-struct scsi_xfer       *xs;
-{
-       struct  buf             *bp;
-       int     retval;
-       struct  st_data *st = st_data[unit];
-
-#ifdef STDEBUG
-       if(scsi_debug & PRINTROUTINES) printf("st_done%d ",unit);
-#endif /*STDEBUG*/
-#ifdef PARANOID
-       if (! (xs->flags & INUSE))
-               panic("scsi_xfer not in use!");
-#endif /*PARANOID*/
-       if((bp = xs->bp)== NULL)
-       {
-               wakeup(xs);
-               return;
-       }
-       switch(xs->error)
-       {
-       case    XS_NOERROR:
-               bp->b_flags &= ~B_ERROR;
-               bp->b_error = 0;
-               bp->b_resid = 0;
-               break;
-       case    XS_SENSE:
-               retval = (st_interpret_sense(unit,xs));
-               bp->b_resid = xs->resid; /* already multiplied by blksiz */
-               if(retval)
-               {
-                       /***************************************\
-                       * We have a real error, the bit should  *
-                       * be set to indicate this. The return   *
-                       * value will contain the unix error code*
-                       * that the error interpretation routine *
-                       * thought was suitable, so pass this    *
-                       * value back in the buf structure.      *
-                       * Furthermore we return information     *
-                       * saying that no data was transferred   *
-                       * All status is now suspect             *
-                       \***************************************/
-                       bp->b_flags |= B_ERROR;
-                       bp->b_error = retval;
-                       bp->b_resid =  bp->b_bcount;
-                       st->flags &= ~ST_PER_ACTION;
-               }
-               else
-               {
-               /***********************************************\
-               * The error interpretation code has declared    *
-               * that it wasn't a real error, or at least that *
-               * we should be ignoring it if it was.           *
-               \***********************************************/
-                   if(xs->resid == 0)
-                   {
-                       /***************************************\
-                       * we apparently had a corrected error   *
-                       * or something.                         *
-                       * pretend the error never happenned     *
-                       \***************************************/
-                       bp->b_flags &= ~B_ERROR;
-                       bp->b_error = 0;
-                       break;
-                   }
-                   if ( xs->resid != xs->datalen )
-                   {
-                       /***************************************\
-                       * Here we have the tricky part..        *
-                       * We successfully read less data than   *
-                       * we requested. (but not 0)             *
-                       *------for variable blocksize tapes:----*
-                       * UNDER 386BSD:                         *
-                       * We should legitimatly have the error  *
-                       * bit set, with the error value set to  *
-                       * zero.. This is to indicate to the     *
-                       * physio code that while we didn't get  *
-                       * as much information as was requested, *
-                       * we did reach the end of the record    *
-                       * and so physio should not call us      *
-                       * again for more data... we have it all *
-                       * SO SET THE ERROR BIT!                 *
-                       *                                       *
-                       * UNDER NetBSD:                         *
-                       * To indicate the same as above, we     *
-                       * need only have a non 0 resid that is  *
-                       * less than the b_bcount, but the       *
-                       * ERROR BIT MUST BE CLEAR! (sigh)       *
-                       *                                       *
-                       *-------for fixed blocksize device------*
-                       * We read some successful records       *
-                       * before hitting the EOF or EOT. These  *
-                       * must be passed to the user, before we *
-                       * report the EOx.  We will report the   *
-                       * EOx NEXT time.                        *
-                       \***************************************/
-#ifdef NETBSD 
-                       bp->b_flags &= ~B_ERROR;
+#ifdef NETBSD
+#define        SIGNAL_SHORT_READ
 #else
 #else
-                       bp->b_flags |= B_ERROR;
-#endif 
-                       bp->b_error = 0;
-                       xs->error = XS_NOERROR;
-                       break;
-                   }
-                   else
-                   {
-                       /***************************************\
-                       * We have come out of the error handler *
-                       * with no error code.  We have also not *
-                       * transferred any data (would have gone *
-                       * to the previous clause).              *
-                       * This must be an EOF                   *
-                       *  Any caller request to read no        *
-                       * data would have been short-circuited  *
-                       * at st_read or ststrategy.             *
-                       *                                       *
-                       * At least all o/s agree that:          *
-                       * 0 bytes read with no error is EOF     *
-                       \***************************************/
-
-                       bp->b_error = 0;
-                       bp->b_flags &= ~B_ERROR;
-                       st->flags &= ~ST_AT_FILEMARK;
-                       break;
-                   }
-               }
-               break;
-
-       case    XS_TIMEOUT:
-               printf("st%d: timeout\n",unit);
-
-       case    XS_BUSY:        /* should retry */ /* how? */
-               /************************************************/
-               /* SHOULD put buf back at head of queue         */
-               /* and decrement retry count in (*xs)           */
-               /* HOWEVER, this should work as a kludge        */
-               /************************************************/
-               if(xs->retries--)
-               {
-                       xs->flags &= ~ITSDONE;
-                       xs->error = XS_NOERROR;
-                       if ( (*(st->sc_sw->scsi_cmd))(xs)
-                               == SUCCESSFULLY_QUEUED)
-                       {       /* don't wake the job, ok? */
-                               return;
-                       }
-                       printf("st%d: device busy\n",unit);
-                       xs->flags |= ITSDONE;
-               }
-
-       case    XS_DRIVER_STUFFUP:
-               bp->b_flags |= B_ERROR;
-               bp->b_error = EIO;
-               break;
-       default:
-               printf("st%d: unknown error category from scsi driver\n"
-                       ,unit);
-       }       
-       biodone(bp);
-       xs->flags = 0;  /* no longer in use */
-       ststart(unit);          /* If there's another waiting.. do it */
-}
-
-
+#define        SIGNAL_SHORT_READ bp->b_flags |= B_ERROR;
+#endif
 
 
-/*******************************************************\
-* ask the scsi driver to perform a command for us.     *
-* Call it through the switch table, and tell it which  *
-* sub-unit we want, and what target and lu we wish to  *
-* talk to. Also tell it where to find the command      *
-* how long int is.                                     *
-* Also tell it where to read/write the data, and how   *
-* long the data is supposed to be                      *
-\*******************************************************/
-int    st_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,bp,flags)
-
-int    unit,flags;
-struct scsi_generic *scsi_cmd;
-int    cmdlen;
-int    timeout;
-u_char *data_addr;
-struct buf *bp;
-int    datalen;
+/*
+ * Look at the returned sense and act on the error and detirmine
+ * The unix error number to pass back... (0 = report no error)
+ *                            (-1 = continue processing)
+ */
+errval 
+st_interpret_sense(xs)
+       struct scsi_xfer *xs;
 {
 {
-       struct  scsi_xfer *xs;
-       int     retval;
-       int     s;
-       struct  st_data *st = st_data[unit];
-
-#ifdef STDEBUG
-       if(scsi_debug & PRINTROUTINES) printf("\nst_scsi_cmd%d ",unit);
-#endif /*STDEBUG*/
-#ifdef PARANOID
-       if(st->sc_sw == NULL)   /* If we have no scsi driver */
-       {
-               printf("st%d: not set up\n",unit);
-               return(EINVAL);
+       struct scsi_link *sc_link = xs->sc_link;
+       struct scsi_sense_data *sense = &(xs->sense);
+       boolean silent = xs->flags & SCSI_SILENT;
+       struct buf *bp = xs->bp;
+       u_int32 unit = sc_link->dev_unit;
+       struct st_data *st = st_data[unit];
+       u_int32 key;
+       int32   info;
+
+       /*
+        * Get the sense fields and work out what code
+        */
+       if (sense->error_code & SSD_ERRCODE_VALID) {
+               info = ntohl(*((int32 *) sense->ext.extended.info));
+       } else {
+               info = xs->datalen;     /* bad choice if fixed blocks */
        }
        }
-#endif /*PARANOID*/
-
-       xs = &(st->scsi_xfer);
-       if(!(flags & SCSI_NOMASK))
-               s = splbio();
-       st->xfer_block_wait++;  /* there is someone waiting */
-       while (xs->flags & INUSE)
-       {
-               if(flags & SCSI_NOSLEEP)
-                       return EBUSY;
-               sleep(&(st->xfer_block_wait),PRIBIO+1);
+       if ((sense->error_code & SSD_ERRCODE) != 0x70) {
+               return (-1);    /* let the generic code handle it */
        }
        }
-       st->xfer_block_wait--;
-       xs->flags = INUSE;
-       if(!(flags & SCSI_NOMASK))
-               splx(s);
-
-       /*******************************************************\
-       * Fill out the scsi_xfer structure                      *
-       \*******************************************************/
-       xs->flags       |=      flags;
-       xs->adapter     =       st->ctlr;
-       xs->targ        =       st->targ;
-       xs->lu          =       st->lu;
-       xs->retries     =       bp?0:ST_RETRIES;/*can't retry on IO*/
-       xs->timeout     =       timeout;
-       xs->cmd         =       scsi_cmd;
-       xs->cmdlen      =       cmdlen;
-       xs->data        =       data_addr;
-       xs->datalen     =       datalen;
-       xs->resid       =       datalen;
-       xs->when_done   =       st_done;
-       xs->done_arg    =       unit;
-       xs->done_arg2   =       (int)xs;
-       xs->bp          =       bp;
-retry: xs->error       =       XS_NOERROR;
-
-       /***********************************************\
-       * Ask the adapter to do the command for us      *
-       \***********************************************/
-       retval = (*(st->sc_sw->scsi_cmd))(xs);
-
-       /***********************************************\
-       * IO operations are handled differently..       *
-       * Physio does the sleep, and error handling is  *
-       * Done in st_done at interrupt time             *
-       \***********************************************/
-       if(bp) return retval;   
-
-       /***********************************************\
-       * Wait for the result if queued, or handle the  *
-       * error if it was rejected..                    *
-       \***********************************************/
-       switch(retval)
-       {
-       case    SUCCESSFULLY_QUEUED:
-               s = splbio();
-               while(!(xs->flags & ITSDONE))
-                       sleep(xs,PRIBIO+1);
-               splx(s);
-               /*******************************\
-               * finished.. check for failure  *
-               * Fall through......            *
-               \*******************************/
-       case    HAD_ERROR:
-       case    COMPLETE:
-               switch(xs->error)
-               {
-               case    XS_NOERROR:
-                       retval = ESUCCESS;
-                       break;
-               case    XS_SENSE:
-                       retval = (st_interpret_sense(unit,xs));
-                       /* only useful for reads *//* why did I say that?*/
-                       if (retval)
-                       { /* error... don't care about filemarks */
-                               st->flags &= ~ST_PER_ACTION;
-                       }
-                       else
-                       {
-                               xs->error = XS_NOERROR;
-                               retval = ESUCCESS;
+       if (st->flags & ST_FIXEDBLOCKS) {
+               xs->resid = info * st->blksiz;
+               if (sense->ext.extended.flags & SSD_EOM) {
+                       st->flags |= ST_EIO_PENDING;
+                       if (bp) {
+                               bp->b_resid = xs->resid;
+                               SIGNAL_SHORT_READ
                        }
                        }
-                       break;
-               case    XS_DRIVER_STUFFUP:
-                       retval = EIO;
-                       break;
-               case    XS_BUSY:
-                       /* should sleep 1 sec here */
-               case    XS_TIMEOUT:
-                       if(xs->retries-- )
-                       {
-                               xs->flags &= ~ITSDONE;
-                               goto retry;
-                       }
-                       retval = EIO;
-                       break;
-               default:
-                       retval = EIO;
-                       printf("st%d: unknown error category from scsi driver\n"
-                               ,unit);
-                       break;
-               }       
-               break;
-       case    TRY_AGAIN_LATER:
-               if(xs->retries-- )
-               {
-                       xs->flags &= ~ITSDONE;
-                       /* should delay here */
-                       goto retry;
                }
                }
-               retval = EIO;
-               break;
-       default:
-               retval = EIO;
-       }
-       xs->flags = 0;  /* it's free! */
-       ststart(unit);
-       return(retval);
-}
-/***************************************************************\
-* Look at the returned sense and act on the error and detirmine        *
-* The unix error number to pass back... (0 = report no error)  *
-\***************************************************************/
-
-int    st_interpret_sense(unit,xs)
-int    unit;
-struct scsi_xfer       *xs;
-{
-       struct  scsi_sense_data *sense;
-       int     key;
-       int     silent = xs->flags & SCSI_SILENT;
-       struct  st_data *st = st_data[unit];
-       int     info;
-       static char *error_mes[] = {            "soft error (corrected)",
-               "not ready",                    "medium error",
-               "non-media hardware failure",   "illegal request",
-               "unit attention",               "tape is write-protected",
-               "no data found",                "vendor unique",
-               "copy aborted",                 "command aborted",
-               "search returned equal",        "volume overflow",
-               "verify miscompare",            "unknown error key"
-       };
-
-       /***************************************************************\
-       * If errors are ok, report a success                            *
-       \***************************************************************/
-       if(xs->flags & SCSI_ERR_OK) return(ESUCCESS);
-
-       /***************************************************************\
-       * Get the sense fields and work out what code                   *
-       \***************************************************************/
-       sense = &(xs->sense);
-#ifdef STDEBUG
-       if(st_debug)
-       {
-               int count = 0;
-               printf("code%x valid%x\n"
-                               ,sense->error_code & SSD_ERRCODE
-                               ,sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
-               printf("seg%x key%x ili%x eom%x fmark%x\n"
-                               ,sense->ext.extended.segment
-                               ,sense->ext.extended.flags & SSD_KEY
-                               ,sense->ext.extended.flags & SSD_ILI ? 1 : 0
-                               ,sense->ext.extended.flags & SSD_EOM ? 1 : 0
-                               ,sense->ext.extended.flags & SSD_FILEMARK ? 1 : 0);
-               printf("info: %x %x %x %x followed by %d extra bytes\n"
-                               ,sense->ext.extended.info[0]
-                               ,sense->ext.extended.info[1]
-                               ,sense->ext.extended.info[2]
-                               ,sense->ext.extended.info[3]
-                               ,sense->ext.extended.extra_len);
-               printf("extra: ");
-               while(count < sense->ext.extended.extra_len)
-               {
-                       printf ("%x ",sense->ext.extended.extra_bytes[count++]);
+               if (sense->ext.extended.flags & SSD_FILEMARK) {
+                       st->flags |= ST_AT_FILEMARK;
+                       if (bp) {
+                               bp->b_resid = xs->resid;
+                               SIGNAL_SHORT_READ
+                       }
                }
                }
-               printf("\n");
-       }
-#endif /*STDEBUG*/
-       if(sense->error_code & SSD_ERRCODE_VALID)
-       {
-               info = ntohl(*((long *)sense->ext.extended.info));
-       }
-       else
-       {
-               info = xs->datalen; /* bad choice if fixed blocks */
-       }
-
-
-       switch(sense->error_code & SSD_ERRCODE)
-       {
-       /***************************************************************\
-       * If it's code 70, use the extended stuff and interpret the key *
-       \***************************************************************/
-       case 0x70:
-               if(st->flags & ST_FIXEDBLOCKS)
-               {
-                       xs->resid = info * st->blksiz;
-                       if(sense->ext.extended.flags & SSD_EOM)
-                       {
-                               st->flags |= ST_EIO_PENDING;
+               if (sense->ext.extended.flags & SSD_ILI) {
+                       st->flags |= ST_EIO_PENDING;
+                       if (bp) {
+                               bp->b_resid = xs->resid;
+                               SIGNAL_SHORT_READ
                        }
                        }
-                       if(sense->ext.extended.flags & SSD_FILEMARK)
-                       {
-                               st->flags |= ST_AT_FILEMARK;
+                       if (sense->error_code & SSD_ERRCODE_VALID &&
+                           !silent)
+                               printf("st%d: block wrong size"
+                                   ", %d blocks residual\n", unit
+                                   ,info);
+
+                       /*
+                        * This quirk code helps the drive read
+                        * the first tape block, regardless of
+                        * format.  That is required for these
+                        * drives to return proper MODE SENSE
+                        * information.
+                        */
+                       if ((st->quirks & ST_Q_SNS_HLP) &&
+                           !(sc_link->flags & SDEV_MEDIA_LOADED)) {
+                               st->blksiz -= 512;
                        }
                        }
-                       if(sense->ext.extended.flags & SSD_ILI)
-                       {
-                               st->flags |= ST_EIO_PENDING;
-                               if (sense->error_code & SSD_ERRCODE_VALID &&
-                                   !silent)
-                                       printf("st%d: %d-byte block wrong size"
-                                           "\n", unit, xs->datalen - info);
-
-                               /***************************************\
-                               * This quirk code helps the drive read  *
-                               * the first tape block, regardless of   *
-                               * format.  That is required for these   *
-                               * drives to return proper MODE SENSE    *
-                               * information.                          *
-                               \***************************************/
-                               if ((st->quirks & ST_Q_SNS_HLP) &&
-                                   !(st->flags & ST_INFO_VALID))
-                               {
-                                       st->blksiz -= 512;
-                               }
+               }
+               /*
+                * If no data was tranfered, do it immediatly
+                */
+               if (xs->resid >= xs->datalen) {
+                       if (st->flags & ST_EIO_PENDING) {
+                               return EIO;
                        }
                        }
-                       /***********************************************\
-                       * If no data was tranfered, do it immediatly    *
-                       \***********************************************/
-                       if(xs->resid >= xs->datalen)
-                       {
-                               if(st->flags & ST_EIO_PENDING) 
-                               {
-                                       return EIO;
-                               }
-                               if(st->flags & ST_AT_FILEMARK) 
-                               {
-                                       return 0;
+                       if (st->flags & ST_AT_FILEMARK) {
+                               if (bp) {
+                                       bp->b_resid = xs->resid;
+                                       SIGNAL_SHORT_READ
                                }
                                }
+                               return 0;
                        }
                }
                        }
                }
-               else
-               {
-                       xs->resid = xs->datalen; /* to be sure */
-                       if(sense->ext.extended.flags & SSD_EOM)
-                       {
-                               return(EIO);
+       } else {                /* must be variable mode */
+               xs->resid = xs->datalen;        /* to be sure */
+               if (sense->ext.extended.flags & SSD_EOM) {
+                       return (EIO);
+               }
+               if (sense->ext.extended.flags & SSD_FILEMARK) {
+                       if (bp)
+                               bp->b_resid = bp->b_bcount;
+                       return 0;
+               }
+               if (sense->ext.extended.flags & SSD_ILI) {
+                       if (info < 0) {
+                               /*
+                                * the record was bigger than the read
+                                */
+                               if (!silent)
+                                       printf("st%d: %d-byte record "
+                                           "too big\n", unit,
+                                           xs->datalen - info);
+                               return (EIO);
                        }
                        }
-                       if(sense->ext.extended.flags & SSD_FILEMARK)
-                       {
-                               return 0;
+                       xs->resid = info;
+                       if (bp) {
+                               bp->b_resid = info;
+                               SIGNAL_SHORT_READ
                        }
                        }
-                       if(sense->ext.extended.flags & SSD_ILI)
-                       {
-                               if(info < 0)
-                               /***************************************\
-                               * the record was bigger than the read   *
-                               \***************************************/
-                               {
-                                       if (!silent)
-                                               printf("st%d: %d-byte record "
-                                                   "too big\n", unit,
-                                                   xs->datalen - info);
-                                       return(EIO);
-                               }
-                               xs->resid = info;
+               }
+       }
+       key = sense->ext.extended.flags & SSD_KEY;
+
+       if (key == 0x8) {
+               /*
+                * This quirk code helps the drive read the
+                * first tape block, regardless of format.  That
+                * is required for these drives to return proper
+                * MODE SENSE information.
+                */
+               if ((st->quirks & ST_Q_SNS_HLP) &&
+                   !(sc_link->flags & SDEV_MEDIA_LOADED)) {    /* still starting */
+                       st->blksiz -= 512;
+               } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) {
+                       st->flags |= ST_BLANK_READ;
+                       xs->resid = xs->datalen;
+                       if (bp) {
+                               bp->b_resid = xs->resid;
+                               /*return an EOF */
                        }
                        }
-               }/* there may be some other error. check the rest */
+                       return (ESUCCESS);
+               }
+       }
+       return (-1);            /* let the default/generic handler handle it */
+}
 
 
-               key=sense->ext.extended.flags & SSD_KEY;
+/*
+ * The quirk here is that the drive returns some value to st_mode_sense
+ * incorrectly until the tape has actually passed by the head.
+ *
+ * The method is to set the drive to large fixed-block state (user-specified
+ * density and 1024-byte blocks), then read and rewind to get it to sense the
+ * tape.  If that doesn't work, try 512-byte fixed blocks.  If that doesn't
+ * work, as a last resort, try variable- length blocks.  The result will be
+ * the ability to do an accurate st_mode_sense.
+ *
+ * We know we can do a rewind because we just did a load, which implies rewind.
+ * Rewind seems preferable to space backward if we have a virgin tape.
+ *
+ * The rest of the code for this quirk is in ILI processing and BLANK CHECK
+ * error processing, both part of st_interpret_sense.
+ */
+errval
+st_touch_tape(unit)
+       u_int32 unit;
+{
+       struct st_data *st = st_data[unit];
+       char   *buf;
+       u_int32 readsiz;
+       errval  errno;
 
 
-               if (!silent && key > 0 && (key != 0x8 ||
-                   st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ)))
-               {
-                       printf("st%d: %s", unit, error_mes[key - 1]);
-                       if(sense->error_code & SSD_ERRCODE_VALID)
-                       {
-                               switch (key)
-                               {
-                               case    0x2:            /* NOT READY */
-                               case    0x5:            /* ILLEGAL REQUEST */
-                               case    0x6:            /* UNIT ATTENTION */
-                               case    0x7:            /* DATA PROTECT */
-                                       break;
-                               case    0x8:            /* BLANK CHECK */
-                                       printf(", requested size: %d (decimal)",
-                                           info);
-                                       break;
-                               default:
-                                       printf(", info = %d (decimal)", info);
-                               }
-                       }
-                       printf("\n");
-               }
+       buf = malloc(1024, M_TEMP, M_NOWAIT);
+       if (!buf)
+               return (ENOMEM);
 
 
-               switch (key)
-               {
-               case    0x0:                            /* NO SENSE */
-               case    0x1:                            /* RECOVERED ERROR */
-                       if(xs->resid == xs->datalen) xs->resid = 0;
-               case    0xc:                            /* EQUAL */
-                       return(ESUCCESS);
-               case    0x2:                            /* NOT READY */
-                       return(ENODEV);
-               case    0x5:                            /* ILLEGAL REQUEST */
-                       return(EINVAL);
-               case    0x6:                            /* UNIT ATTENTION */
-                       st->flags &= ~ST_PER_MEDIA;
-                       if (st->flags & ST_OPEN) /* TEMP!!!! */
-                               return(EIO);
-                       else
-                               return(ESUCCESS);
-               case    0x7:                            /* DATA PROTECT */
-                       return(EACCES);
-               case    0xd:                            /* VOLUME OVERFLOW */
-                       return(ENOSPC);
-               case    0x8:                            /* BLANK CHECK */
-                       /***********************************************\
-                       * This quirk code helps the drive read the      *
-                       * first tape block, regardless of format.  That *
-                       * is required for these drives to return proper *
-                       * MODE SENSE information.                       *
-                       \***********************************************/
-                       if ((st->quirks & ST_Q_SNS_HLP) &&
-                           !(st->flags & ST_INFO_VALID))
-                       {
-                               st->blksiz -= 512;
-                       }
-                       else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ)))
-                       {
-                               st->flags |= ST_BLANK_READ;
-                               xs->resid = xs->datalen;
-                               return(ESUCCESS);
-                       }
+       if (errno = st_mode_sense(unit, 0)) {
+               goto bad;
+       }
+       st->blksiz = 1024;
+       do {
+               switch ((int)st->blksiz) {
+               case 512:
+               case 1024:
+                       readsiz = st->blksiz;
+                       st->flags |= ST_FIXEDBLOCKS;
+                       break;
                default:
                default:
-                       return(EIO);
+                       readsiz = 1;
+                       st->flags &= ~ST_FIXEDBLOCKS;
+               } if (errno = st_mode_select(unit, 0)) {
+                       goto bad;
                }
                }
-       /***************************************************************\
-       * If it's NOT code 70, just report it.                          *
-       \***************************************************************/
-       default:
-               if (!silent)
-               {
-                       printf("st%d: error code %d", unit,
-                               sense->error_code & SSD_ERRCODE);
-                       if(sense->error_code & SSD_ERRCODE_VALID)
-                       {
-                               printf(" at block no. %d (decimal)",
-                                       (sense->ext.unextended.blockhi << 16) +
-                                       (sense->ext.unextended.blockmed << 8) +
-                                       sense->ext.unextended.blocklow);
-                       }
-                       printf("\n");
+               st_read(unit, buf, readsiz, SCSI_SILENT);
+               if (errno = st_rewind(unit, FALSE, 0)) {
+bad:                   free(buf, M_TEMP);
+                       return (errno);
                }
                }
-               return(EIO);
-       }
+       } while (readsiz != 1 && readsiz > st->blksiz);
+       free(buf, M_TEMP);
+       return 0;
 }
 }