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

Next file: linux/drivers/scsi/st_options.h
Previous file: linux/drivers/scsi/sr.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.25/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
@@ -11,7 +11,7 @@
   Copyright 1992, 1993, 1994, 1995 Kai Makisara
 		 email [email protected]
 
-  Last modified: Sat Sep  2 11:50:15 1995 by [email protected]
+  Last modified: Sun Sep 10 20:33:24 1995 by [email protected]
 */
 #ifdef MODULE
 #include <linux/autoconf.h>
@@ -71,6 +71,7 @@
 #define ST_LONG_TIMEOUT (2000 * HZ)
 
 static int st_nbr_buffers;
+static int st_req_nbr_buffers;
 static ST_buffer **st_buffers;
 static int st_buffer_size = ST_BUFFER_SIZE;
 static int st_write_threshold = ST_WRITE_THRESHOLD;
@@ -78,7 +79,7 @@
 
 Scsi_Tape * scsi_tapes = NULL;
 
-static void st_init(void);
+static int st_init(void);
 static int st_attach(Scsi_Device *);
 static int st_detect(Scsi_Device *);
 static void st_detach(Scsi_Device *);
@@ -376,6 +377,14 @@
   STp = &(scsi_tapes[dev]);
   STbuffer = STp->buffer;
 
+
+  /*
+   * If there was a bus reset, block further access
+   * to this device.
+   */
+  if( STp->device->was_reset )
+    return (-EIO);
+
   if (STp->ready != ST_READY)
     return 0;
 
@@ -765,6 +774,14 @@
     STp = &(scsi_tapes[dev]);
     if (STp->ready != ST_READY)
       return (-EIO);
+
+    /*
+     * If there was a bus reset, block further access
+     * to this device.
+     */
+    if( STp->device->was_reset )
+      return (-EIO);
+
 #if DEBUG
     if (!STp->in_use) {
       printk("st%d: Incorrect device.\n", dev);
@@ -1790,6 +1807,15 @@
    }
 #endif
 
+   /*
+    * If this is something intended for the lower layer, just pass it
+    * through.
+    */
+   if( cmd_in == SCSI_IOCTL_GET_IDLUN || cmd_in == SCSI_IOCTL_PROBE_HOST )
+     {
+       return scsi_ioctl(STp->device, cmd_in, (void *) arg);
+     }
+   
    cmd = cmd_in & IOCCMD_MASK;
    if (cmd == (MTIOCTOP & IOCCMD_MASK)) {
 
@@ -1800,6 +1826,22 @@
      if (i)
 	return i;
 
+     /*
+      * If there was a bus reset, block further access
+      * to this device.  If the user wants to rewind the tape,
+      * then reset the flag and allow access again.
+      */
+     if( STp->device->was_reset) 
+       {
+	 if(mtc.mt_op != MTREW && 
+	    mtc.mt_op != MTOFFL &&
+	    mtc.mt_op != MTRESET && 
+	    mtc.mt_op != MTRETEN && 
+	    mtc.mt_op != MTEOM)
+	   return (-EIO);
+	 STp->device->was_reset = 0;
+       }
+
      memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop));
 
      i = flush_buffer(inode, file, mtc.mt_op == MTSEEK ||
@@ -2038,25 +2080,30 @@
 static int st_registered = 0;
 
 /* Driver initialization */
-static void st_init()
+static int st_init()
 {
   int i;
   Scsi_Tape * STp;
 
-  if (st_template.dev_noticed == 0) return;
+  if (st_template.dev_noticed == 0) return 0;
 
   if(!st_registered) {
     if (register_chrdev(SCSI_TAPE_MAJOR,"st",&st_fops)) {
       printk("Unable to get major %d for SCSI tapes\n",MAJOR_NR);
-      return;
+      return 1;
     }
     st_registered++;
   }
 
-  if (scsi_tapes) return;
+  if (scsi_tapes) return 0;
   scsi_tapes = (Scsi_Tape *) scsi_init_malloc(
   		(st_template.dev_noticed + ST_EXTRA_DEVS) * 
 					      sizeof(Scsi_Tape), GFP_ATOMIC);
+  if (scsi_tapes == NULL) {
+    printk("Unable to allocate descriptors for SCSI tapes.\n");
+    unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+    return 1;
+  }
   st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS;
 
 #if DEBUG
@@ -2091,11 +2138,24 @@
   }
 
   /* Allocate the buffers */
-  st_nbr_buffers = st_template.dev_noticed + ST_EXTRA_DEVS;
+  st_nbr_buffers = st_template.dev_noticed;
+  if (st_nbr_buffers < ST_EXTRA_DEVS)
+    st_nbr_buffers = ST_EXTRA_DEVS;
   if (st_nbr_buffers > st_max_buffers)
     st_nbr_buffers = st_max_buffers;
+  st_req_nbr_buffers = st_nbr_buffers;
   st_buffers = (ST_buffer **) scsi_init_malloc(st_nbr_buffers * 
-					       sizeof(ST_buffer *), GFP_ATOMIC);
+					       sizeof(ST_buffer *),
+					       GFP_ATOMIC);
+  if (st_buffers == NULL) {
+    printk("Unable to allocate tape buffer pointers.\n");
+    unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+    scsi_init_free((char *) scsi_tapes,
+		   (st_template.dev_noticed + ST_EXTRA_DEVS) 
+		   * sizeof(Scsi_Tape));
+    return 1;
+  }
+
   /* FIXME - if we are hitting this because we are loading a tape module
   as a loadable driver, we should not use kmalloc - it will allocate
   a 64Kb region in order to buffer about 32Kb.  Try using 31 blocks
@@ -2103,14 +2163,32 @@
   
   for (i=0; i < st_nbr_buffers; i++) {
     st_buffers[i] = (ST_buffer *) scsi_init_malloc(sizeof(ST_buffer) - 
-						   1 + st_buffer_size, GFP_ATOMIC | GFP_DMA);
+						   1 + st_buffer_size,
+						   GFP_ATOMIC | GFP_DMA);
+    if (st_buffers[i] == NULL) {
+      printk("Not enough memory for buffer %d.\n", i);
+      if (i == 0) {
+	unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+	scsi_init_free((char *) scsi_tapes,
+		       (st_template.dev_noticed + ST_EXTRA_DEVS) 
+		       * sizeof(Scsi_Tape));
+	scsi_init_free((char *) st_buffers,
+		       st_nbr_buffers * sizeof(ST_buffer *));
+	return 1;
+      }
+      st_nbr_buffers = i;
+      printk("Number of tape buffers adjusted.\n");
+      break;
+    }
+    else {
 #if DEBUG
 /*    printk("st: Buffer address: %p\n", st_buffers[i]); */
 #endif
-    st_buffers[i]->in_use = 0;
-    st_buffers[i]->writing = 0;
+      st_buffers[i]->in_use = 0;
+      st_buffers[i]->writing = 0;
+    }
   }
-  return;
+  return 0;
 }
 
 static void st_detach(Scsi_Device * SDp)
@@ -2153,13 +2231,17 @@
     scsi_init_free((char *) scsi_tapes,
 		   (st_template.dev_noticed + ST_EXTRA_DEVS) 
 		   * sizeof(Scsi_Tape));
-    
-    for (i=0; i < st_nbr_buffers; i++) {
-      scsi_init_free((char *) st_buffers[i],
-		     sizeof(ST_buffer) - 1 + st_buffer_size);
+
+    if (st_buffers != NULL) {
+      for (i=0; i < st_nbr_buffers; i++)
+	if (st_buffers[i] != NULL) {
+	  scsi_init_free((char *) st_buffers[i],
+			 sizeof(ST_buffer) - 1 + st_buffer_size);
+	}
+      
+      scsi_init_free((char *) st_buffers,
+		     st_req_nbr_buffers * sizeof(ST_buffer *));
     }
-    
-    scsi_init_free((char *) st_buffers, st_nbr_buffers * sizeof(ST_buffer *));
   }
   st_template.dev_max = 0;
 }

FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen, [email protected] with Sam's (original) version
of this