patch-1.3.85 linux/drivers/scsi/st.c

Next file: linux/drivers/scsi/st.h
Previous file: linux/drivers/scsi/scsi_ioctl.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.84/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
@@ -8,10 +8,10 @@
   order) Klaus Ehrenfried, Steve Hirsch, Wolfgang Denk, Andreas Koppenh"ofer,
   J"org Weule, and Eric Youngdale.
 
-  Copyright 1992, 1993, 1994, 1995 Kai Makisara
+  Copyright 1992 - 1996 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Fri Mar 29 20:55:05 1996 by root@kai.makisara.fi
+  Last modified: Sun Apr  7 20:33:27 1996 by root@kai.makisara.fi
   Some small formal changes - aeb, 950809
 */
 
@@ -74,7 +74,8 @@
 #define ST_TIMEOUT (900 * HZ)
 #define ST_LONG_TIMEOUT (2000 * HZ)
 
-#define TAPE_NR(x) (MINOR(x) & 127)
+#define TAPE_NR(x) (MINOR(x) & ~(128 | ST_MODE_MASK))
+#define TAPE_MODE(x) ((MINOR(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
 
 static int st_nbr_buffers;
 static ST_buffer **st_buffers;
@@ -84,6 +85,8 @@
 
 Scsi_Tape * scsi_tapes = NULL;
 
+static int modes_defined = FALSE;
+
 static ST_buffer *new_tape_buffer(int, int);
 static int enlarge_buffer(ST_buffer *, int, int);
 static void normalize_buffer(ST_buffer *);
@@ -98,6 +101,8 @@
 					     st_detect, st_init,
 					     NULL, st_attach, st_detach};
 
+static int st_compression(Scsi_Tape *, int);
+
 static int st_int_ioctl(struct inode * inode,struct file * file,
 	     unsigned int cmd_in, unsigned long arg);
 
@@ -454,11 +459,13 @@
 scsi_tape_open(struct inode * inode, struct file * filp)
 {
     unsigned short flags;
-    int i, need_dma_buffer;
+    int i, need_dma_buffer, new_session = FALSE, setting_failed;
     unsigned char cmd[10];
     Scsi_Cmnd * SCpnt;
     Scsi_Tape * STp;
+    ST_mode * STm;
     int dev = TAPE_NR(inode->i_rdev);
+    int mode = TAPE_MODE(inode->i_rdev);
 
     if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
       return (-ENXIO);
@@ -471,6 +478,19 @@
     }
     STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
 
+    if (mode != STp->current_mode) {
+#if DEBUG
+      if (debugging)
+	printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n",
+	       dev, STp->current_mode, mode);
+#endif
+      /*      if (!STp->modes[mode].defined)
+	return (-ENXIO); */
+      new_session = TRUE;
+      STp->current_mode = mode;
+    }
+    STm = &(STp->modes[STp->current_mode]);
+
     /* Allocate buffer for this user */
     need_dma_buffer = STp->restr_dma;
     for (i=0; i < st_nbr_buffers; i++)
@@ -522,6 +542,7 @@
       (STp->mt_status)->mt_fileno = STp->drv_block = 0;
       STp->eof = ST_NOEOF;
       (STp->device)->was_reset = 0;
+      new_session = TRUE;
     }
 
     if ((STp->buffer)->last_result_fatal != 0) {
@@ -649,6 +670,46 @@
       }
     }
 
+    if (new_session) {
+      STp->density_changed = STp->blksize_changed = FALSE;
+      STp->compression_changed = FALSE;
+      if (!(STm->defaults_for_writes)) {
+	setting_failed = FALSE;
+	if (STm->default_blksize >= 0 &&
+	    STm->default_blksize != STp->block_size) {
+	  if (STm->default_density >= 0 &&
+	      STm->default_density != STp->density)
+	    STp->density = STm->default_density;  /* Dirty trick! */
+	  if (st_int_ioctl(inode, filp, MTSETBLK, STm->default_blksize)) {
+	    printk(KERN_WARNING "st%d: Can't set default block size to %d bytes.\n",
+		   dev, STm->default_blksize);
+	    if (modes_defined)
+	      setting_failed = TRUE;
+	  }
+	}
+	if (STm->default_density >= 0 &&
+	    STm->default_density != STp->density) {
+	  if (st_int_ioctl(inode, filp, MTSETDENSITY, STm->default_density)) {
+	    printk(KERN_WARNING "st%d: Can't set default density to %x.\n",
+		   dev, STm->default_density);
+	    if (modes_defined)
+	      setting_failed = TRUE;
+	  }
+	}
+	if (setting_failed) {
+	  (STp->buffer)->in_use = 0;
+	  STp->buffer = 0;
+	  STp->in_use = 0;
+	  return (-EINVAL);
+	}
+      }
+      if (STp->default_drvbuffer != 0xff) {
+	if (st_int_ioctl(inode, filp, MTSETDRVBUFFER, STp->default_drvbuffer))
+	  printk(KERN_WARNING "st%d: Can't set default drive buffering to %d.\n",
+		 dev, STp->default_drvbuffer);
+      }
+    }
+
     if (scsi_tapes[dev].device->host->hostt->usage_count)
       (*scsi_tapes[dev].device->host->hostt->usage_count)++;
     if(st_template.usage_count) (*st_template.usage_count)++;
@@ -714,12 +775,10 @@
 #endif
     }
     else if (!STp->rew_at_close) {
-#if ST_IN_FILE_POS
-      flush_buffer(inode, filp, 0);
-#else
-      if ((STp->eof == ST_FM) && !STp->eof_hit)
+      if (STp->can_bsr)
+	flush_buffer(inode, filp, 0);
+      else if ((STp->eof == ST_FM) && !STp->eof_hit)
 	back_over_eof(STp);
-#endif
     }
 
     if (STp->rew_at_close)
@@ -753,11 +812,15 @@
     const char *b_point;
     Scsi_Cmnd * SCpnt = NULL;
     Scsi_Tape * STp;
+    ST_mode * STm;
     int dev = TAPE_NR(inode->i_rdev);
 
     STp = &(scsi_tapes[dev]);
     if (STp->ready != ST_READY)
       return (-EIO);
+    STm = &(STp->modes[STp->current_mode]);
+    if (!STm->defined)
+      return (-ENXIO);
 
     /*
      * If there was a bus reset, block further access
@@ -791,6 +854,42 @@
        return retval;
       STp->rw = ST_WRITING;
     }
+    else if (STp->rw != ST_WRITING) {
+      if (STm->defaults_for_writes &&
+	  (STp->mt_status)->mt_fileno == 0 && STp->drv_block == 0) {
+	/* Force unless explicitly changed by the user */
+	if (!(STp->blksize_changed) && STm->default_blksize >= 0 &&
+	    STp->block_size != STm->default_blksize) {
+	  if (STm->default_density >= 0 &&
+	      STm->default_density != STp->density)
+	    STp->density = STm->default_density;  /* Dirty trick! */
+	  if (st_int_ioctl(inode, filp, MTSETBLK, STm->default_blksize)) {
+	    printk(KERN_WARNING "st%d: Can't set default block size to %d bytes.\n",
+		   dev, STm->default_blksize);
+	    if (modes_defined)
+	      return (-EINVAL);
+	  }
+	}
+	if (!(STp->density_changed) && STm->default_density >= 0 &&
+	    STm->default_density != STp->density) {
+	  if (st_int_ioctl(inode, filp, MTSETDENSITY, STm->default_density)) {
+	    printk(KERN_WARNING "st%d: Can't set default density %x.\n",
+		   dev, STm->default_density);
+	    if (modes_defined)
+	      return (-EINVAL);
+	  }
+	}
+      }
+      if (STm->default_compression != ST_DONT_TOUCH &&
+	  !(STp->compression_changed)) {
+	if (st_compression(STp, (STm->default_compression == ST_YES))) {
+	  printk(KERN_WARNING "st%d: Can't set default compression.\n",
+		 dev);
+	  if (modes_defined)
+	    return (-EINVAL);
+	}
+      }
+    }
 
     if (STp->moves_after_eof < 255)
       STp->moves_after_eof++;
@@ -817,14 +916,14 @@
     else if (STp->eof == ST_EOM_ERROR)
       return (-EIO);
 
-    if (!STp->do_buffer_writes) {
+    if (!STm->do_buffer_writes) {
       if (STp->block_size != 0 && (count % STp->block_size) != 0)
 	return (-EIO);   /* Write must be integral number of blocks */
       write_threshold = 1;
     }
     else
       write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
-    if (!STp->do_async_writes)
+    if (!STm->do_async_writes)
       write_threshold--;
 
     total = count;
@@ -836,7 +935,7 @@
     STp->rw = ST_WRITING;
 
     b_point = buf;
-    while((STp->block_size == 0 && !STp->do_async_writes && count > 0) ||
+    while((STp->block_size == 0 && !STm->do_async_writes && count > 0) ||
 	  (STp->block_size != 0 &&
 	   (STp->buffer)->buffer_bytes + count > write_threshold))
     {
@@ -951,7 +1050,7 @@
       return (STp->buffer)->last_result_fatal;
     }
 
-    if (STp->do_async_writes &&
+    if (STm->do_async_writes &&
 	((STp->buffer)->buffer_bytes >= STp->write_threshold ||
 	 STp->block_size == 0) ) {
       /* Schedule an asynchronous write */
@@ -1010,6 +1109,8 @@
     STp = &(scsi_tapes[dev]);
     if (STp->ready != ST_READY)
       return (-EIO);
+    if (!STp->modes[STp->current_mode].defined)
+      return (-ENXIO);
 #if DEBUG
     if (!STp->in_use) {
       printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
@@ -1239,48 +1340,238 @@
 
 
 /* Set the driver options */
+	static void
+st_log_options(Scsi_Tape *STp, ST_mode *STm, int dev)
+{
+  printk(KERN_INFO
+"st%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
+	 dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
+	 STp->do_read_ahead);
+  printk(KERN_INFO
+"st%d:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d, defs for wr: %d \n",
+	 dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock,
+	 STm->defaults_for_writes);
+#if DEBUG
+  printk(KERN_INFO
+	 "st%d:    debugging: %d\n",
+	 dev, debugging);
+#endif
+}
+
+  
 	static int
 st_set_options(struct inode * inode, long options)
 {
   int value;
+  long code;
   Scsi_Tape *STp;
+  ST_mode *STm;
   int dev = TAPE_NR(inode->i_rdev);
 
   STp = &(scsi_tapes[dev]);
-  if ((options & MT_ST_OPTIONS) == MT_ST_BOOLEANS) {
-    STp->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
-    STp->do_async_writes  = (options & MT_ST_ASYNC_WRITES) != 0;
+  STm = &(STp->modes[STp->current_mode]);
+  if (!STm->defined) {
+    memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
+    modes_defined = TRUE;
+#if DEBUG
+    if (debugging)
+      printk(ST_DEB_MSG "st%d: Initialized mode %d definition from mode 0\n",
+	     dev, STp->current_mode);
+#endif
+  }
+
+  code = options & MT_ST_OPTIONS;
+  if (code == MT_ST_BOOLEANS) {
+    STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
+    STm->do_async_writes  = (options & MT_ST_ASYNC_WRITES) != 0;
+    STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
     STp->do_read_ahead    = (options & MT_ST_READ_AHEAD) != 0;
     STp->two_fm		  = (options & MT_ST_TWO_FM) != 0;
     STp->fast_mteom	  = (options & MT_ST_FAST_MTEOM) != 0;
     STp->do_auto_lock     = (options & MT_ST_AUTO_LOCK) != 0;
+    STp->can_bsr          = (options & MT_ST_CAN_BSR) != 0;
 #if DEBUG
     debugging = (options & MT_ST_DEBUGGING) != 0;
-    printk(ST_DEB_MSG
-	   "st%d: options: buffer writes: %d, async writes: %d, read ahead: %d\n",
-	   dev, STp->do_buffer_writes, STp->do_async_writes, STp->do_read_ahead);
-    printk(ST_DEB_MSG
-	   "st%d:          two FMs: %d, fast mteom: %d auto lock: %d, debugging: %d\n",
-	   dev, STp->two_fm, STp->fast_mteom, STp->do_auto_lock, debugging);
 #endif
+    st_log_options(STp, STm, dev);
   }
-  else if ((options & MT_ST_OPTIONS) == MT_ST_WRITE_THRESHOLD) {
+  else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
+    value = (code == MT_ST_SETBOOLEANS);
+    if ((options & MT_ST_BUFFER_WRITES) != 0)
+      STm->do_buffer_writes = value;
+    if ((options & MT_ST_ASYNC_WRITES) != 0)
+      STm->do_async_writes = value;
+    if ((options & MT_ST_DEF_WRITES) != 0)
+      STm->defaults_for_writes = value;
+    if ((options & MT_ST_READ_AHEAD) != 0)
+      STp->do_read_ahead = value;
+    if ((options & MT_ST_TWO_FM) != 0)
+      STp->two_fm = value;
+    if ((options & MT_ST_FAST_MTEOM) != 0)
+      STp->fast_mteom = value;
+    if ((options & MT_ST_AUTO_LOCK) != 0)
+      STp->do_auto_lock = value;
+    if ((options & MT_ST_CAN_BSR) != 0)
+      STp->can_bsr = value;
+#if DEBUG
+    if ((options & MT_ST_DEBUGGING) != 0)
+      debugging = value;
+#endif
+    st_log_options(STp, STm, dev);
+  }
+  else if (code == MT_ST_WRITE_THRESHOLD) {
     value = (options & ~MT_ST_OPTIONS) * ST_BLOCK_SIZE;
     if (value < 1 || value > st_buffer_size) {
-      printk(KERN_WARNING "st: Write threshold %d too small or too large.\n",
-	     value);
+      printk(KERN_WARNING "st%d: Write threshold %d too small or too large.\n",
+	     dev, value);
       return (-EIO);
     }
     STp->write_threshold = value;
+    printk(KERN_INFO "st%d: Write threshold set to %d bytes.\n",
+	   dev, value);
+  }
+  else if (code == MT_ST_DEF_BLKSIZE) {
+    value = (options & ~MT_ST_OPTIONS);
+    if (value == ~MT_ST_OPTIONS) {
+      STm->default_blksize = (-1);
+      printk(KERN_INFO "st%d: Default block size disabled.\n", dev);
+    }
+    else {
+      STm->default_blksize = value;
+      printk(KERN_INFO "st%d: Default block size set to %d bytes.\n",
+	     dev, STm->default_blksize);
+    }
+  }
+  else if (code == MT_ST_DEF_OPTIONS) {
+    code = (options & ~MT_ST_CLEAR_DEFAULT);
+    value = (options & MT_ST_CLEAR_DEFAULT);
+    if (code == MT_ST_DEF_DENSITY) {
+      if (value == MT_ST_CLEAR_DEFAULT) {
+	STm->default_density = (-1);
+	printk(KERN_INFO "st%d: Density default disabled.\n", dev);
+      }
+      else {
+	STm->default_density = value & 0xff;
+	printk(KERN_INFO "st%d: Density default set to %x\n",
+	       dev, STm->default_density);
+      }
+    }
+    else if (code == MT_ST_DEF_DRVBUFFER) {
+      if (value == MT_ST_CLEAR_DEFAULT) {
+	STp->default_drvbuffer = 0xff;
+	printk(KERN_INFO "st%d: Drive buffer default disabled.\n", dev);
+      }
+      else {
+	STp->default_drvbuffer = value & 7;
+	printk(KERN_INFO "st%d: Drive buffer default set to %x\n",
+	       dev, STp->default_drvbuffer);
+      }
+    }
+    else if (code == MT_ST_DEF_COMPRESSION) {
+      if (value == MT_ST_CLEAR_DEFAULT) {
+	STm->default_compression = ST_DONT_TOUCH;
+	printk(KERN_INFO "st%d: Compression default disabled.\n", dev);
+      }
+      else {
+	STm->default_compression = (value & 1 ? ST_YES : ST_NO);
+	printk(KERN_INFO "st%d: Compression default set to %x\n",
+	       dev, (value & 1));
+      }
+    }
+  }
+  else
+    return (-EIO);
+
+  return 0;
+}
+
+
+#define COMPRESSION_PAGE        0x0f
+#define COMPRESSION_PAGE_LENGTH 16
+
+#define MODE_HEADER_LENGTH  4
+
+#define DCE_MASK  0x80
+#define DCC_MASK  0x40
+#define RED_MASK  0x60
+
+
+/* Control the compression with mode page 15. Algorithm not changed if zero. */
+	static int
+st_compression(Scsi_Tape * STp, int state)
+{
+  int dev;
+  unsigned char cmd[10];
+  Scsi_Cmnd * SCpnt = NULL;
+
+  /* Read the current page contents */
+  memset(cmd, 0, 10);
+  cmd[0] = MODE_SENSE;
+  cmd[1] = 8;
+  cmd[2] = COMPRESSION_PAGE;
+  cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+  SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], ST_TIMEOUT, 0);
+  dev = TAPE_NR(SCpnt->request.rq_dev);
+
+  if ((STp->buffer)->last_result_fatal != 0) {
 #if DEBUG
-    printk(ST_DEB_MSG "st%d: Write threshold set to %d bytes.\n", dev,
-	   STp->write_threshold);
+    if (debugging)
+      printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev);
 #endif
+    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+    return (-EIO);
+  }
+#if DEBUG
+  if (debugging)
+    printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev,
+	   ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0));
+#endif
+
+  /* Check if compression can be changed */
+  if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) {
+#if DEBUG
+    if (debugging)
+      printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev);
+#endif
+    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+    return (-EIO);
   }
+
+  /* Do the change */
+  if (state)
+    (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] |= DCE_MASK;
   else
+    (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] &= ~DCE_MASK;
+
+  memset(cmd, 0, 10);
+  cmd[0] = MODE_SELECT;
+  cmd[1] = 0x10;
+  cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+  (STp->buffer)->b_data[0] = 0;  /* Reserved data length */
+  (STp->buffer)->b_data[1] = 0;  /* Reserved media type byte */
+  (STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f;
+  SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], ST_TIMEOUT, 0);
+
+  if ((STp->buffer)->last_result_fatal != 0) {
+#if DEBUG
+    if (debugging)
+      printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev);
+#endif
+    SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
     return (-EIO);
+  }
 
-  return 0;
+#if DEBUG
+  if (debugging)
+    printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n",
+	   dev, state);
+#endif
+
+  SCpnt->request.rq_status = RQ_INACTIVE;  /* Mark as not busy */
+  STp->compression_changed = TRUE;
+  return 0;  /* Not implemented yet */
 }
 
 
@@ -1469,8 +1760,12 @@
        timeout = ST_LONG_TIMEOUT * 8;
 #endif
 #if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev);
+       if (debugging) {
+	 if (cmd_in != MTLOAD)
+	   printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev);
+	 else
+	   printk(ST_DEB_MSG "st%d: Loading tape.\n", dev);
+       }
 #endif
        fileno = blkno = at_sm = 0 ;
        break; 
@@ -1599,12 +1894,16 @@
 	 (STp->buffer)->b_data[2] = 
 	   STp->drv_buffer << 4;
        (STp->buffer)->b_data[3] = 8;     /* block descriptor length */
-       if (cmd_in == MTSETDENSITY)
+       if (cmd_in == MTSETDENSITY) {
 	 (STp->buffer)->b_data[4] = arg;
+	 STp->density_changed = TRUE;  /* At least we tried ;-) */
+       }
        else
 	 (STp->buffer)->b_data[4] = STp->density;
-       if (cmd_in == MTSETBLK)
+       if (cmd_in == MTSETBLK) {
 	 ltmp = arg;
+	 STp->blksize_changed = TRUE;  /* At least we tried ;-) */
+       }
        else
 	 ltmp = STp->block_size;
        (STp->buffer)->b_data[9] = (ltmp >> 16);
@@ -1684,7 +1983,6 @@
        STp->rew_at_close = 0;
      else if (cmd_in == MTLOAD)
        STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
-
    } else {  /* SCSI command was not completely successful */
      if (SCpnt->sense_buffer[2] & 0x40) {
        if (cmd_in != MTBSF && cmd_in != MTBSFM &&
@@ -1760,6 +2058,7 @@
    unsigned char scmd[10];
    Scsi_Cmnd *SCpnt;
    Scsi_Tape *STp;
+   ST_mode *STm;
    int dev = TAPE_NR(inode->i_rdev);
 
    STp = &(scsi_tapes[dev]);
@@ -1769,6 +2068,7 @@
      return (-EIO);
    }
 #endif
+   STm = &(STp->modes[STp->current_mode]);
 
    /*
     * If this is something intended for the lower layer, just pass it
@@ -1791,6 +2091,14 @@
 
      memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop));
 
+     if (mtc.mt_op == MTSETDRVBUFFER && !suser()) {
+       printk(KERN_WARNING "st%d: MTSETDRVBUFFER only allowed for root.\n", dev);
+       return (-EPERM);
+     }
+     if (!STm->defined &&
+	 (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0))
+       return (-ENXIO);
+
      if (!(STp->device)->was_reset) {
 
        if (STp->eof_hit) {
@@ -1807,7 +2115,8 @@
        i = flush_buffer(inode, file, mtc.mt_op == MTSEEK ||
 			mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
 			mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
-			mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD);
+			mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
+			mtc.mt_op == MTCOMPRESSION);
        if (i < 0)
 	 return i;
      }
@@ -1846,10 +2155,16 @@
      if (mtc.mt_op == MTSETDRVBUFFER &&
 	 (mtc.mt_count & MT_ST_OPTIONS) != 0)
        return st_set_options(inode, mtc.mt_count);
+     else if (mtc.mt_op == MTCOMPRESSION)
+       return st_compression(STp, (mtc.mt_count & 1));
      else
        return st_int_ioctl(inode, file, mtc.mt_op, mtc.mt_count);
    }
-   else if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
+
+   if (!STm->defined)
+     return (-ENXIO);
+
+   if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
 
      if (_IOC_SIZE(cmd_in) != sizeof(struct mtget))
        return (-EINVAL);
@@ -2135,18 +2450,33 @@
    tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
    tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
    tpnt->density = 0;
-   tpnt->do_buffer_writes = ST_BUFFER_WRITES;
-   tpnt->do_async_writes = ST_ASYNC_WRITES;
    tpnt->do_read_ahead = ST_READ_AHEAD;
    tpnt->do_auto_lock = ST_AUTO_LOCK;
+   tpnt->can_bsr = ST_IN_FILE_POS;
    tpnt->two_fm = ST_TWO_FM;
    tpnt->fast_mteom = ST_FAST_MTEOM;
    tpnt->write_threshold = st_write_threshold;
+   tpnt->default_drvbuffer = 0xff; /* No forced buffering */
    tpnt->drv_block = (-1);
    tpnt->moves_after_eof = 1;
    tpnt->at_sm = 0;
    (tpnt->mt_status)->mt_fileno = (tpnt->mt_status)->mt_blkno = (-1);
 
+   for (i=0; i < ST_NBR_MODES; i++) {
+     tpnt->modes[i].defined = FALSE;
+     tpnt->modes[i].defaults_for_writes = 0;
+     tpnt->modes[i].do_async_writes = ST_ASYNC_WRITES;
+     tpnt->modes[i].do_buffer_writes = ST_BUFFER_WRITES;
+     tpnt->modes[i].default_compression = ST_DONT_TOUCH;
+     tpnt->modes[i].default_blksize = (-1);  /* No forced size */
+     tpnt->modes[i].default_density = (-1);  /* No forced density */
+   }
+   tpnt->current_mode = 0;
+   tpnt->modes[0].defined = TRUE;
+
+   tpnt->density_changed = tpnt->compression_changed =
+     tpnt->blksize_changed = FALSE;
+
    st_template.nr_dev++;
    return 0;
 };
@@ -2187,6 +2517,8 @@
   st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS;
   if (st_template.dev_max < ST_MAX_TAPES)
     st_template.dev_max = ST_MAX_TAPES;
+  if (st_template.dev_max > 128 / ST_NBR_MODES)
+    printk(KERN_INFO "st: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
   scsi_tapes =
     (Scsi_Tape *) scsi_init_malloc(st_template.dev_max * sizeof(Scsi_Tape),
 				   GFP_ATOMIC);
@@ -2201,27 +2533,10 @@
 	 st_buffer_size, st_write_threshold);
 #endif
 
+  memset(scsi_tapes, 0, st_template.dev_max * sizeof(Scsi_Tape));
   for (i=0; i < st_template.dev_max; ++i) {
     STp = &(scsi_tapes[i]);
-    STp->device = NULL;
     STp->capacity = 0xfffff;
-    STp->dirty = 0;
-    STp->rw = ST_IDLE;
-    STp->eof = ST_NOEOF;
-    STp->waiting = NULL;
-    STp->in_use = 0;
-    STp->drv_buffer = 1;  /* Try buffering if no mode sense */
-    STp->density = 0;
-    STp->do_buffer_writes = ST_BUFFER_WRITES;
-    STp->do_async_writes = ST_ASYNC_WRITES;
-    STp->do_read_ahead = ST_READ_AHEAD;
-    STp->do_auto_lock = ST_AUTO_LOCK;
-    STp->two_fm = ST_TWO_FM;
-    STp->fast_mteom = ST_FAST_MTEOM;
-    STp->write_threshold = st_write_threshold;
-    STp->drv_block = 0;
-    STp->moves_after_eof = 1;
-    STp->at_sm = 0;
     STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget),
 						       GFP_ATOMIC);
     /* Initialize status */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this