[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#419175: Patch against sarge's kernel



I've been running with this patch against the 2.6.8 kernel for the last
5 days. It appears to fix the problem. However, I'm not certain that it
is the right work-around from an architectural perspective.

diff -ur orig/drivers/usb/storage/scsiglue.c kernel-source-2.6.8/drivers/usb/storage/scsiglue.c
--- orig/drivers/usb/storage/scsiglue.c	2004-08-14 01:36:58.000000000 -0400
+++ kernel-source-2.6.8/drivers/usb/storage/scsiglue.c	2007-04-15 16:48:18.000000000 -0400
@@ -354,6 +354,7 @@
 		DO_FLAG(SCM_MULT_TARG);
 		DO_FLAG(FIX_INQUIRY);
 		DO_FLAG(FIX_CAPACITY);
+		DO_FLAG(MUST_RESTART);
 
 		*(pos++) = '\n';
 	}
diff -ur orig/drivers/usb/storage/unusual_devs.h kernel-source-2.6.8/drivers/usb/storage/unusual_devs.h
--- orig/drivers/usb/storage/unusual_devs.h	2006-12-05 04:21:55.000000000 -0500
+++ kernel-source-2.6.8/drivers/usb/storage/unusual_devs.h	2007-04-15 16:45:34.000000000 -0400
@@ -730,6 +730,13 @@
                 "Optio S/S4",
                 US_SC_DEVICE, US_PR_DEVICE, NULL,
                 US_FL_FIX_INQUIRY ),
+
+/* Submitted by Greg Hartman <gghartma@cs.cmu.edu> */
+UNUSUAL_DEV (0x0bc2, 0x3000, 0x0000, 0x0000,
+		"Seagate",
+		"FreeAgentDesktop",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_MUST_RESTART ),
 		
 #ifdef CONFIG_USB_STORAGE_ISD200
 UNUSUAL_DEV(  0x0bf6, 0xa001, 0x0100, 0x0110,
diff -ur orig/drivers/usb/storage/usb.c kernel-source-2.6.8/drivers/usb/storage/usb.c
--- orig/drivers/usb/storage/usb.c	2004-08-14 01:36:32.000000000 -0400
+++ kernel-source-2.6.8/drivers/usb/storage/usb.c	2007-04-17 19:38:35.000000000 -0400
@@ -263,10 +263,41 @@
 	usb_stor_set_xfer_buf(data, data_len, us->srb);
 }
 
+static void start_done(struct scsi_cmnd *unused)
+{
+}
+
+static Scsi_Cmnd * make_start_srb(struct us_data *us)
+{
+	Scsi_Cmnd *start_srb;
+
+	start_srb = scsi_get_command(us->srb->device, GFP_KERNEL);
+	if (!start_srb) {
+		return start_srb;
+	}
+	start_srb->sc_magic = us->srb->sc_magic;
+	start_srb->sc_request = NULL;
+	start_srb->done = start_done;
+	start_srb->serial_number = 0x5511AA77;
+	start_srb->retries = 1;
+	start_srb->cmd_len = 6;
+	start_srb->sc_data_direction = DMA_NONE;
+	memset(start_srb->cmnd, 0, 6);
+	start_srb->cmnd[0] = START_STOP;
+	start_srb->cmnd[4] = 1;
+	start_srb->use_sg = 0;
+	start_srb->bufflen = 0;
+	start_srb->buffer = 0;
+	start_srb->request = NULL;
+
+	return start_srb;
+}
+
 static int usb_stor_control_thread(void * __us)
 {
 	struct us_data *us = (struct us_data *)__us;
 	struct Scsi_Host *host = us->host;
+	Scsi_Cmnd *start_srb = NULL;
 
 	lock_kernel();
 
@@ -360,6 +391,36 @@
 		else {
 			US_DEBUG(usb_stor_show_command(us->srb));
 			us->proto_handler(us->srb, us);
+	                if ((us->flags & US_FL_MUST_RESTART) &&
+			    (us->srb->result == SAM_STAT_CHECK_CONDITION)) {
+			    if (!start_srb) {
+			    /* Why do I have to do this here? Are there
+			     * multiple values for ->dev? If so, sharing
+			     * start_srb is bad
+			     */
+				start_srb = make_start_srb(us);
+				if (!start_srb) {
+					printk(KERN_NOTICE USB_STORAGE "MUST_RESTART failed: unable to allocate command\n");
+				}
+			    }
+			    if (start_srb) {
+				    printk("GSH: START on cmnd=0x%02x\n", us->srb->cmnd[0]);
+				    US_DEBUG(usb_stor_show_command(start_srb));
+				    us->proto_handler(start_srb, us);
+
+				    /* Now retry the command */
+
+				    US_DEBUG(usb_stor_show_command(us->srb));
+				    us->srb->result = SAM_STAT_GOOD;
+				    /* I need to clobber this to avoid I/O
+				     * errors in the higher layers. I don't know
+				     * how much clobbering is needed. Some
+				     * instances just clear 0, others 0 ... 16
+				     */
+				    memset(us->srb->sense_buffer, 0, sizeof(us->srb->sense_buffer));
+				    us->proto_handler(us->srb, us);
+			    }
+			}
 		}
 
 		/* lock access to the state */
@@ -393,6 +454,11 @@
 		up(&(us->dev_semaphore));
 	} /* for (;;) */
 
+	if (start_srb) {
+	  scsi_put_command(start_srb);
+	  start_srb = NULL;
+	}
+
 	/* notify the exit routine that we're actually exiting now 
 	 *
 	 * complete()/wait_for_completion() is similar to up()/down(),
diff -ur orig/drivers/usb/storage/usb.h kernel-source-2.6.8/drivers/usb/storage/usb.h
--- orig/drivers/usb/storage/usb.h	2006-12-05 04:21:54.000000000 -0500
+++ kernel-source-2.6.8/drivers/usb/storage/usb.h	2007-04-15 13:02:25.000000000 -0400
@@ -75,6 +75,7 @@
 #define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs faking   */
 #define US_FL_FIX_CAPACITY    0x00000080 /* READ CAPACITY response too big  */
 #define US_FL_IGNORE_RESIDUE  0x00000100 /* reported residue is wrong	    */
+#define US_FL_MUST_RESTART    0x00000200 /* Drive needs occasional START    */
 
 /* Dynamic flag definitions: used in set_bit() etc. */
 #define US_FLIDX_URB_ACTIVE	18  /* 0x00040000  current_urb is in use  */

Attachment: signature.asc
Description: OpenPGP digital signature


Reply to: