[LWN Logo]
[Timeline]
Date:	Wed, 21 Jun 2000 23:39:56 -0700
From:	Chip Salzenberg <chip@valinux.com>
To:	Alan Cox <alan@lxorguk.ukuu.org.uk>
Subject: [PATCH] SCSI, O_NONBLOCK, and removable media

I am using the below patches in a production kernel that needs to open
SCSI devices with removable media (/dev/sr# and /dev/sd[a-z]), even
when the media are missing.  This is of course what the O_NONBLOCK
flag was invented for.  But at least with the stock 2.2 kernel,
O_NONBLOCK doesn't work with SCSI devices.  (It does work with IDE
devices, fortunately.)

These patches make O_NONBLOCK work with SCSI devices.  I submitted
them for Eric Youngdale's examination several weeks ago, and confirmed
that he got them.  But he hasn't responded with either yea or nay.  So
I'd like to suggest that, in absence of commentary from Eric, these
patches be considered for the 2.2 tree.

The first patch is for SCSI disks; the second patch is for SCSI CDs.

------------------------------------------------------------------------
Index: drivers/scsi/sd.c
@@ -151,34 +151,41 @@ static int sd_open(struct inode * inode,
      * is being re-read.
      */
-
     while (rscsi_disks[target].device->busy)
         barrier();
-    if(rscsi_disks[target].device->removable) {
+
+    /*
+     * When opening removable disks, we check media...
+     * ... unless media don't matter, due to O_NONBLOCK.
+     */
+    if (rscsi_disks[target].device->removable
+        && !(filp->f_flags & O_NONBLOCK))
+    {
+        /*
+         * Note disk change and/or removal.
+         * Also try to read new partition table (if any).
+         */
 	check_disk_change(inode->i_rdev);
 
-	/*
-	 * If the drive is empty, just let the open fail.
-	 */
-	if ( !rscsi_disks[target].ready )
-	    return -ENXIO;
+        /*
+         * If the drive is empty, let the open fail.
+         */
+	if (rscsi_disks[target].ready)
+            return -ENXIO;
 
-	/*
-	 * Similarly, if the device has the write protect tab set,
-	 * have the open fail if the user expects to be able to write
-	 * to the thing.
-	 */
-	if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) )
-	    return -EROFS;
+        /*
+         * If the device has the write protect tab set,
+         * let the open fail if the user expects to be able to write.
+         */
+        if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) )
+            return -EROFS;
     }
 
     /*
-     * It is possible that the disk changing stuff resulted in the device being taken
-     * offline.  If this is the case, report this to the user, and don't pretend that
-     * the open actually succeeded.
+     * It is possible that the disk changing stuff (or something
+     * else?) resulted in the device being taken offline.
+     * If so, let the open fail.
      */
-    if( !rscsi_disks[target].device->online )
-    {
+    if (!rscsi_disks[target].device->online)
         return -ENXIO;
-    }
 
     /*
@@ -1069,5 +1076,4 @@ static int check_scsidisk_media_change(k
     int target;
     struct inode inode;
-    int flag = 0;
 
     target =  DEVICE_NR(full_dev);
@@ -1121,9 +1127,9 @@ static int check_scsidisk_media_change(k
      * struct and tested at open !  Daniel Roche ( dan@lectra.fr )
      */
-
     rscsi_disks[target].ready = 1;	/* FLOPTICAL */
 
     retval = rscsi_disks[target].device->changed;
-    if(!flag) rscsi_disks[target].device->changed = 0;
+    rscsi_disks[target].device->changed = 0;
+
     return retval;
 }
------------------------------------------------------------------------
Index: drivers/scsi/sr.h
@@ -29,5 +29,5 @@
 	unsigned char	sector_bit_size;	/* sector size = 2^sector_bit_size	*/
 	unsigned char	sector_bit_shift;	/* sectors/FS block = 2^sector_bit_shift*/
-	unsigned 	needs_sector_size:1;   	/* needs to get sector size */
+	unsigned 	:1;			/* (was needs_sector_size)		*/
 	unsigned 	ten:1;			/* support ten byte commands		*/
 	unsigned 	remap:1;		/* support remapping			*/

Index: drivers/scsi/sr.c
@@ -154,21 +154,17 @@ int sr_media_change(struct cdrom_device_
 	retval = scsi_CDs[MINOR(cdi->dev)].device->changed;
 	scsi_CDs[MINOR(cdi->dev)].device->changed = 0;
-	/* If the disk changed, the capacity will now be different,
-	 * so we force a re-read of this information */
+
+	/*
+	 * If the disk changed, the sector size and capacity may be
+	 * different, so we force a re-read of this information.
+	 */
 	if (retval) {
+		/* discover new sector size */
+		get_sectorsize(MINOR(cdi->dev));
+
 		/* check multisession offset etc */
 		sr_cd_check(cdi);
-
-		/* 
-		 * If the disk changed, the capacity will now be different,
-		 * so we force a re-read of this information 
-		 * Force 2048 for the sector size so that filesystems won't
-		 * be trying to use something that is too small if the disc
-		 * has changed.
-		 */
-		scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1;
-
-		scsi_CDs[MINOR(cdi->dev)].sector_size = 2048;
 	}
+
 	return retval;
 }
@@ -384,6 +380,4 @@ static void rw_intr(Scsi_Cmnd * SCpnt)
 static int sr_open(struct cdrom_device_info *cdi, int purpose)
 {
-	check_disk_change(cdi->dev);
-
 	if (MINOR(cdi->dev) >= sr_template.dev_max
 	    || !scsi_CDs[MINOR(cdi->dev)].device) {
@@ -403,12 +397,4 @@ static int sr_open(struct cdrom_device_i
 		__MOD_INC_USE_COUNT(sr_template.module);
 
-	/* If this device did not have media in the drive at boot time, then
-	 * we would have been unable to get the sector size.  Check to see if
-	 * this is the case, and try again.
-	 */
-
-	if (scsi_CDs[MINOR(cdi->dev)].needs_sector_size)
-		get_sectorsize(MINOR(cdi->dev));
-
 	return 0;
 }
@@ -894,5 +880,4 @@ void get_sectorsize(int i)
 		scsi_CDs[i].capacity = 0x1fffff;
 		scsi_CDs[i].sector_size = 2048;		/* A guess, just in case */
-		scsi_CDs[i].needs_sector_size = 1;
 	} else {
 #if 0
@@ -927,14 +912,14 @@ void get_sectorsize(int i)
 			       i, scsi_CDs[i].sector_size);
 			scsi_CDs[i].capacity = 0;
-			scsi_CDs[i].needs_sector_size = 1;
+			break;
 		}
+	}
+
+	/*
+	 * Add this so that we have the ability to correctly gauge
+	 * what the device is capable of.
+	 */
+	sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
 
-		/*
-		 * Add this so that we have the ability to correctly gauge
-		 * what the device is capable of.
-		 */
-		scsi_CDs[i].needs_sector_size = 0;
-		sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
-	};
 	scsi_free(buffer, 512);
 }
@@ -1021,5 +1006,5 @@ void get_capabilities(int i)
 			cdrom_number_of_slots(&(scsi_CDs[i].cdi));
 	if (scsi_CDs[i].cdi.capacity <= 1)
-                /* not a changer */
+		/* not a changer */
 		scsi_CDs[i].cdi.mask |= CDC_SELECT_DISC;
 	/*else    I don't think it can close its tray
@@ -1149,5 +1134,4 @@ void sr_finish()
 		scsi_CDs[i].capacity = 0x1fffff;
 		scsi_CDs[i].sector_size = 2048;		/* A guess, just in case */
-		scsi_CDs[i].needs_sector_size = 1;
 		scsi_CDs[i].device->changed = 1;	/* force recheck CD type */
 #if 0
------------------------------------------------------------------------

-- 
Chip Salzenberg              - a.k.a. -              <chip@valinux.com>
"I wanted to play hopscotch with the impenetrable mystery of existence,
    but he stepped in a wormhole and had to go in early."  // MST3K

-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@vger.rutgers.edu


----- End forwarded message -----

-- 
Chip Salzenberg              - a.k.a. -              <chip@valinux.com>
"I wanted to play hopscotch with the impenetrable mystery of existence,
    but he stepped in a wormhole and had to go in early."  // MST3K

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/