# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.513   -> 1.514  
#	drivers/usb/storage/usb.c	1.33    -> 1.34   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/08/21	mdharm-usb@one-eyed-alien.net	1.514
# [PATCH] PATCH: fix devices which don't support START_STOP
# 
# Based on my discussions with Pete Zaitcev <zaitcev@redhat.com>, I'm
# convinced that globally re-writing the START_STOP command into a
# TEST_UNIT_READY command is a good idea.  This is supported by the fact
# that:
# 
# (1) Lots of devices don't support START_STOP
# (2) Those that do support it often don't do a good job
# (3) Win/Mac will never send these commands over a USB bus
# 
# So, here's a patch that re-writes them into Test Unit Ready commands.  It
# seems to work on my system, but needs more testing.  There may be a problem
# with this code still.... it seems that the SCSI layer can get convinced
# that the unit is not ready permanently.  I'm honestly not certain what bit
# of code is wrong where, so reports from others would be greatly
# appreciated.
# --------------------------------------------
#
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Wed Aug 21 15:45:30 2002
+++ b/drivers/usb/storage/usb.c	Wed Aug 21 15:45:30 2002
@@ -385,13 +385,6 @@
 			us->srb->result = DID_BAD_TARGET << 16;
 		}
 
-		/* handle those devices which can't do a START_STOP */
-		else if ((us->srb->cmnd[0] == START_STOP) &&
-		    (us->flags & US_FL_START_STOP)) {
-			US_DEBUGP("Skipping START_STOP command\n");
-			us->srb->result = GOOD << 1;
-		}
-
 		/* handle requests for EVPD, which most USB devices do
 		 * not support */
 		else if((us->srb->cmnd[0] == INQUIRY) &&
@@ -416,6 +409,7 @@
 				       sizeof(usb_stor_sense_notready));
 				us->srb->result = GOOD << 1;
 			} else if(us->srb->cmnd[0] == INQUIRY) {
+				/* INQUIRY should always work, per spec... */
 				unsigned char data_ptr[36] = {
 				    0x20, 0x80, 0x02, 0x02,
 				    0x1F, 0x00, 0x00, 0x00};
@@ -423,6 +417,7 @@
 				fill_inquiry_response(us, data_ptr, 36);
 				us->srb->result = GOOD << 1;
 			} else {
+				/* not ready */
 				memcpy(us->srb->sense_buffer, 
 				       usb_stor_sense_notready, 
 				       sizeof(usb_stor_sense_notready));
@@ -441,6 +436,35 @@
 			US_DEBUGP("Faking INQUIRY command\n");
 			fill_inquiry_response(us, data_ptr, 36);
 			us->srb->result = GOOD << 1;
+		}
+
+		/* Most USB devices can't handle START_STOP.  But we
+		 * need something for media-change, so we'll use TUR
+		 * instead.
+		 */
+		else if (us->srb->cmnd[0] == START_STOP) {
+			unsigned char saved_cdb[16]; /* largest SCSI-III cmd */
+			__u8 old_cmd_len;
+
+			US_DEBUGP("Converting START_STOP to TUR\n");
+
+			/* save old command */
+			memcpy(saved_cdb, us->srb->cmnd, us->srb->cmd_len);
+			old_cmd_len = us->srb->cmd_len;
+
+			/* set up new command -- preserve LUN */
+			us->srb->cmd_len = 6;
+			memset(us->srb->cmnd, 0, us->srb->cmd_len);
+			us->srb->cmnd[0] = TEST_UNIT_READY;
+			us->srb->cmnd[1] = saved_cdb[1] & 0xE0;
+
+			/* do command */
+			US_DEBUG(usb_stor_show_command(us->srb));
+			us->proto_handler(us->srb, us);
+
+			/* restore original command */
+			us->srb->cmd_len = old_cmd_len;
+			memcpy(us->srb->cmnd, saved_cdb, us->srb->cmd_len);
 		}
 
 		/* we've got a command, let's do it! */
