# 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 , 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! */