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 <[EMAIL PROTECTED]> */ +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 */
signature.asc
Description: OpenPGP digital signature