summaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2012-04-14 13:18:27 +0200
committerIngo Molnar <mingo@kernel.org>2012-04-14 13:19:04 +0200
commit6ac1ef482d7ae0c690f1640bf6eb818ff9a2d91e (patch)
tree021cc9f6b477146fcebe6f3be4752abfa2ba18a9 /drivers/usb/storage
parent682968e0c425c60f0dde37977e5beb2b12ddc4cc (diff)
parenta385ec4f11bdcf81af094c03e2444ee9b7fad2e5 (diff)
Merge branch 'perf/core' into perf/uprobes
Merge in latest upstream (and the latest perf development tree), to prepare for tooling changes, and also to pick up v3.4 MM changes that the uprobes code needs to take care of. Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r--drivers/usb/storage/Kconfig2
-rw-r--r--drivers/usb/storage/alauda.c1
-rw-r--r--drivers/usb/storage/cypress_atacb.c1
-rw-r--r--drivers/usb/storage/datafab.c1
-rw-r--r--drivers/usb/storage/ene_ub6250.c27
-rw-r--r--drivers/usb/storage/freecom.c1
-rw-r--r--drivers/usb/storage/isd200.c1
-rw-r--r--drivers/usb/storage/jumpshot.c1
-rw-r--r--drivers/usb/storage/karma.c1
-rw-r--r--drivers/usb/storage/onetouch.c1
-rw-r--r--drivers/usb/storage/realtek_cr.c13
-rw-r--r--drivers/usb/storage/scsiglue.c55
-rw-r--r--drivers/usb/storage/sddr09.c1
-rw-r--r--drivers/usb/storage/sddr55.c1
-rw-r--r--drivers/usb/storage/shuttle_usbat.c1
-rw-r--r--drivers/usb/storage/transport.c3
-rw-r--r--drivers/usb/storage/transport.h39
-rw-r--r--drivers/usb/storage/uas.c328
-rw-r--r--drivers/usb/storage/usb.c21
19 files changed, 299 insertions, 200 deletions
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index fe2d803a634..7691c866637 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -222,7 +222,7 @@ config USB_LIBUSUAL
for usb-storage and ub drivers, and allows to switch binding
of these devices without rebuilding modules.
- Typical syntax of /etc/modprobe.conf is:
+ Typical syntax of /etc/modprobe.d/*conf is:
options libusual bias="ub"
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
index 51af2fee2ef..bab8c8fe829 100644
--- a/drivers/usb/storage/alauda.c
+++ b/drivers/usb/storage/alauda.c
@@ -1276,6 +1276,7 @@ static struct usb_driver alauda_driver = {
.post_reset = usb_stor_post_reset,
.id_table = alauda_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(alauda_driver);
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
index 387cbd47acc..5fe451d16e6 100644
--- a/drivers/usb/storage/cypress_atacb.c
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -272,6 +272,7 @@ static struct usb_driver cypress_driver = {
.post_reset = usb_stor_post_reset,
.id_table = cypress_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(cypress_driver);
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
index 15d41f2b3d6..35e9c51e669 100644
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -751,6 +751,7 @@ static struct usb_driver datafab_driver = {
.post_reset = usb_stor_post_reset,
.id_table = datafab_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(datafab_driver);
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index a6ade4071a9..e7e67810950 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -674,7 +674,7 @@ static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = blenByte;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[5] = (unsigned char)(bnByte);
bcb->CDB[4] = (unsigned char)(bnByte>>8);
@@ -858,7 +858,7 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x02; /* in init.c ENE_MSInit() is 0x01 */
@@ -877,7 +877,7 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
@@ -1170,7 +1170,7 @@ static int ms_read_eraseblock(struct us_data *us, u32 PhyBlockAddr)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF2;
bcb->CDB[1] = 0x06;
bcb->CDB[4] = (unsigned char)(bn);
@@ -1249,7 +1249,7 @@ static int ms_lib_overwrite_extra(struct us_data *us, u32 PhyBlockAddr,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF2;
bcb->CDB[1] = 0x05;
bcb->CDB[5] = (unsigned char)(PageNum);
@@ -1331,7 +1331,7 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
bcb->CDB[5] = (unsigned char)(PageNum);
@@ -1533,7 +1533,7 @@ static int ms_lib_read_extrablock(struct us_data *us, u32 PhyBlock,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4 * blen;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
bcb->CDB[5] = (unsigned char)(PageNum);
@@ -1650,7 +1650,7 @@ static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = blenByte;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x02;
bcb->CDB[5] = (unsigned char)(bn);
@@ -1694,7 +1694,7 @@ static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200 * len;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x02;
bcb->CDB[5] = (unsigned char)(blkno);
@@ -1827,7 +1827,7 @@ static int ene_get_card_type(struct us_data *us, u16 index, void *buf)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x01;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xED;
bcb->CDB[2] = (unsigned char)(index>>8);
bcb->CDB[3] = (unsigned char)index;
@@ -2083,7 +2083,7 @@ static int ene_ms_init(struct us_data *us)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x01;
@@ -2134,7 +2134,7 @@ static int ene_sd_init(struct us_data *us)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF2;
result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
@@ -2153,7 +2153,7 @@ static int ene_sd_init(struct us_data *us)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
@@ -2407,6 +2407,7 @@ static struct usb_driver ene_ub6250_driver = {
.post_reset = usb_stor_post_reset,
.id_table = ene_ub6250_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(ene_ub6250_driver);
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index fa161574847..042cf9ef315 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -553,6 +553,7 @@ static struct usb_driver freecom_driver = {
.post_reset = usb_stor_post_reset,
.id_table = freecom_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(freecom_driver);
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index bd550270083..31fa24e7e68 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -1566,6 +1566,7 @@ static struct usb_driver isd200_driver = {
.post_reset = usb_stor_post_reset,
.id_table = isd200_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(isd200_driver);
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
index a19211b5c26..e3b97383186 100644
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -677,6 +677,7 @@ static struct usb_driver jumpshot_driver = {
.post_reset = usb_stor_post_reset,
.id_table = jumpshot_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(jumpshot_driver);
diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
index e720f8ebdf9..a8708eae978 100644
--- a/drivers/usb/storage/karma.c
+++ b/drivers/usb/storage/karma.c
@@ -230,6 +230,7 @@ static struct usb_driver karma_driver = {
.post_reset = usb_stor_post_reset,
.id_table = karma_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(karma_driver);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index d75155c3820..886567a3806 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -312,6 +312,7 @@ static struct usb_driver onetouch_driver = {
.post_reset = usb_stor_post_reset,
.id_table = onetouch_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(onetouch_driver);
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
index d32f72061c0..63cf2822e29 100644
--- a/drivers/usb/storage/realtek_cr.c
+++ b/drivers/usb/storage/realtek_cr.c
@@ -219,7 +219,7 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun,
/* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(buf_len);
- bcb->Flags = (dir == DMA_FROM_DEVICE) ? 1 << 7 : 0;
+ bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
bcb->Tag = ++us->tag;
bcb->Lun = lun;
bcb->Length = cmd_len;
@@ -305,7 +305,7 @@ static int rts51x_bulk_transport_special(struct us_data *us, u8 lun,
/* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(buf_len);
- bcb->Flags = (dir == DMA_FROM_DEVICE) ? 1 << 7 : 0;
+ bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
bcb->Tag = ++us->tag;
bcb->Lun = lun;
bcb->Length = cmd_len;
@@ -507,9 +507,14 @@ static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)
{
int retval;
u8 cmnd[12] = {0};
+ u8 *buf;
US_DEBUGP("%s, addr = 0xfe47, len = %d\n", __FUNCTION__, len);
+ buf = kmemdup(data, len, GFP_NOIO);
+ if (!buf)
+ return USB_STOR_TRANSPORT_ERROR;
+
cmnd[0] = 0xF0;
cmnd[1] = 0x0E;
cmnd[2] = 0xfe;
@@ -517,7 +522,8 @@ static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)
cmnd[4] = (u8)(len >> 8);
cmnd[5] = (u8)len;
- retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, data, len, DMA_TO_DEVICE, NULL);
+ retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, buf, len, DMA_TO_DEVICE, NULL);
+ kfree(buf);
if (retval != USB_STOR_TRANSPORT_GOOD) {
return -EIO;
}
@@ -1100,6 +1106,7 @@ static struct usb_driver realtek_cr_driver = {
.id_table = realtek_cr_ids,
.soft_unbind = 1,
.supports_autosuspend = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(realtek_cr_driver);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 13b8bcdf3db..a324a5d21e9 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -78,8 +78,6 @@ static const char* host_info(struct Scsi_Host *host)
static int slave_alloc (struct scsi_device *sdev)
{
- struct us_data *us = host_to_us(sdev->host);
-
/*
* Set the INQUIRY transfer length to 36. We don't use any of
* the extra data and many devices choke if asked for more or
@@ -104,18 +102,6 @@ static int slave_alloc (struct scsi_device *sdev)
*/
blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
- /*
- * The UFI spec treates the Peripheral Qualifier bits in an
- * INQUIRY result as reserved and requires devices to set them
- * to 0. However the SCSI spec requires these bits to be set
- * to 3 to indicate when a LUN is not present.
- *
- * Let the scanning code know if this target merely sets
- * Peripheral Device Type to 0x1f to indicate no LUN.
- */
- if (us->subclass == USB_SC_UFI)
- sdev->sdev_target->pdt_1f_for_no_lun = 1;
-
return 0;
}
@@ -197,6 +183,9 @@ static int slave_configure(struct scsi_device *sdev)
* page x08, so we will skip it. */
sdev->skip_ms_page_8 = 1;
+ /* Some devices don't handle VPD pages correctly */
+ sdev->skip_vpd_pages = 1;
+
/* Some disks return the total number of blocks in response
* to READ CAPACITY rather than the highest block number.
* If this device makes that mistake, tell the sd driver. */
@@ -217,16 +206,6 @@ static int slave_configure(struct scsi_device *sdev)
if (sdev->scsi_level > SCSI_SPC_2)
us->fflags |= US_FL_SANE_SENSE;
- /* Some devices report a SCSI revision level above 2 but are
- * unable to handle the REPORT LUNS command (for which
- * support is mandatory at level 3). Since we already have
- * a Get-Max-LUN request, we won't lose much by setting the
- * revision level down to 2. The only devices that would be
- * affected are those with sparse LUNs. */
- if (sdev->scsi_level > SCSI_2)
- sdev->sdev_target->scsi_level =
- sdev->scsi_level = SCSI_2;
-
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
* Hardware Error) when any low-level error occurs,
* recoverable or not. Setting this flag tells the SCSI
@@ -283,6 +262,33 @@ static int slave_configure(struct scsi_device *sdev)
return 0;
}
+static int target_alloc(struct scsi_target *starget)
+{
+ struct us_data *us = host_to_us(dev_to_shost(starget->dev.parent));
+
+ /*
+ * Some USB drives don't support REPORT LUNS, even though they
+ * report a SCSI revision level above 2. Tell the SCSI layer
+ * not to issue that command; it will perform a normal sequential
+ * scan instead.
+ */
+ starget->no_report_luns = 1;
+
+ /*
+ * The UFI spec treats the Peripheral Qualifier bits in an
+ * INQUIRY result as reserved and requires devices to set them
+ * to 0. However the SCSI spec requires these bits to be set
+ * to 3 to indicate when a LUN is not present.
+ *
+ * Let the scanning code know if this target merely sets
+ * Peripheral Device Type to 0x1f to indicate no LUN.
+ */
+ if (us->subclass == USB_SC_UFI)
+ starget->pdt_1f_for_no_lun = 1;
+
+ return 0;
+}
+
/* queue a command */
/* This is always called with scsi_lock(host) held */
static int queuecommand_lck(struct scsi_cmnd *srb,
@@ -546,6 +552,7 @@ struct scsi_host_template usb_stor_host_template = {
.slave_alloc = slave_alloc,
.slave_configure = slave_configure,
+ .target_alloc = target_alloc,
/* lots of sg segments can be handled */
.sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 425df7df2e5..3252a62b31b 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -1787,6 +1787,7 @@ static struct usb_driver sddr09_driver = {
.post_reset = usb_stor_post_reset,
.id_table = sddr09_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(sddr09_driver);
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index e4ca5fcb7cc..c144078065a 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -1006,6 +1006,7 @@ static struct usb_driver sddr55_driver = {
.post_reset = usb_stor_post_reset,
.id_table = sddr55_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(sddr55_driver);
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 1369d259061..fa1ceebc465 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -1863,6 +1863,7 @@ static struct usb_driver usbat_driver = {
.post_reset = usb_stor_post_reset,
.id_table = usbat_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(usbat_driver);
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 0e5c91c6187..c70109e5d60 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1071,7 +1071,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
/* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(transfer_length);
- bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
+ bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ?
+ US_BULK_FLAG_IN : 0;
bcb->Tag = ++us->tag;
bcb->Lun = srb->device->lun;
if (us->fflags & US_FL_SCM_MULT_TARG)
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index 242ff5e791a..9369d752d41 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -42,45 +42,6 @@
#include <linux/blkdev.h>
/*
- * Bulk only data structures
- */
-
-/* command block wrapper */
-struct bulk_cb_wrap {
- __le32 Signature; /* contains 'USBC' */
- __u32 Tag; /* unique per command id */
- __le32 DataTransferLength; /* size of data */
- __u8 Flags; /* direction in bit 0 */
- __u8 Lun; /* LUN normally 0 */
- __u8 Length; /* of of the CDB */
- __u8 CDB[16]; /* max command */
-};
-
-#define US_BULK_CB_WRAP_LEN 31
-#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */
-#define US_BULK_FLAG_IN 1
-#define US_BULK_FLAG_OUT 0
-
-/* command status wrapper */
-struct bulk_cs_wrap {
- __le32 Signature; /* should = 'USBS' */
- __u32 Tag; /* same as original command */
- __le32 Residue; /* amount not transferred */
- __u8 Status; /* see below */
- __u8 Filler[18];
-};
-
-#define US_BULK_CS_WRAP_LEN 13
-#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */
-#define US_BULK_STAT_OK 0
-#define US_BULK_STAT_FAIL 1
-#define US_BULK_STAT_PHASE 2
-
-/* bulk-only class specific requests */
-#define US_BULK_RESET_REQUEST 0xff
-#define US_BULK_GET_MAX_LUN 0xfe
-
-/*
* usb_stor_bulk_transfer_xxx() return codes, in order of severity
*/
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index a33ead5dce2..8ec8a6e66f5 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -13,7 +13,9 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/usb/hcd.h>
#include <linux/usb/storage.h>
+#include <linux/usb/uas.h>
#include <scsi/scsi.h>
#include <scsi/scsi_dbg.h>
@@ -22,49 +24,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
-/* Common header for all IUs */
-struct iu {
- __u8 iu_id;
- __u8 rsvd1;
- __be16 tag;
-};
-
-enum {
- IU_ID_COMMAND = 0x01,
- IU_ID_STATUS = 0x03,
- IU_ID_RESPONSE = 0x04,
- IU_ID_TASK_MGMT = 0x05,
- IU_ID_READ_READY = 0x06,
- IU_ID_WRITE_READY = 0x07,
-};
-
-struct command_iu {
- __u8 iu_id;
- __u8 rsvd1;
- __be16 tag;
- __u8 prio_attr;
- __u8 rsvd5;
- __u8 len;
- __u8 rsvd7;
- struct scsi_lun lun;
- __u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
-};
-
-/*
- * Also used for the Read Ready and Write Ready IUs since they have the
- * same first four bytes
- */
-struct sense_iu {
- __u8 iu_id;
- __u8 rsvd1;
- __be16 tag;
- __be16 status_qual;
- __u8 status;
- __u8 rsvd7[7];
- __be16 len;
- __u8 sense[SCSI_SENSE_BUFFERSIZE];
-};
-
/*
* The r00-r01c specs define this version of the SENSE IU data structure.
* It's still in use by several different firmware releases.
@@ -79,18 +38,6 @@ struct sense_iu_old {
__u8 sense[SCSI_SENSE_BUFFERSIZE];
};
-enum {
- CMD_PIPE_ID = 1,
- STATUS_PIPE_ID = 2,
- DATA_IN_PIPE_ID = 3,
- DATA_OUT_PIPE_ID = 4,
-
- UAS_SIMPLE_TAG = 0,
- UAS_HEAD_TAG = 1,
- UAS_ORDERED_TAG = 2,
- UAS_ACA = 4,
-};
-
struct uas_dev_info {
struct usb_interface *intf;
struct usb_device *udev;
@@ -98,6 +45,8 @@ struct uas_dev_info {
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
unsigned use_streams:1;
unsigned uas_sense_old:1;
+ struct scsi_cmnd *cmnd;
+ struct urb *status_urb; /* used only if stream support is available */
};
enum {
@@ -109,6 +58,9 @@ enum {
SUBMIT_DATA_OUT_URB = (1 << 5),
ALLOC_CMD_URB = (1 << 6),
SUBMIT_CMD_URB = (1 << 7),
+ COMPLETED_DATA_IN = (1 << 8),
+ COMPLETED_DATA_OUT = (1 << 9),
+ DATA_COMPLETES_CMD = (1 << 10),
};
/* Overrides scsi_pointer */
@@ -116,6 +68,7 @@ struct uas_cmd_info {
unsigned int state;
unsigned int stream;
struct urb *cmd_urb;
+ /* status_urb is used only if stream support isn't available */
struct urb *status_urb;
struct urb *data_in_urb;
struct urb *data_out_urb;
@@ -125,33 +78,43 @@ struct uas_cmd_info {
/* I hate forward declarations, but I actually have a loop */
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
struct uas_dev_info *devinfo, gfp_t gfp);
+static void uas_do_work(struct work_struct *work);
+static DECLARE_WORK(uas_work, uas_do_work);
static DEFINE_SPINLOCK(uas_work_lock);
static LIST_HEAD(uas_work_list);
static void uas_do_work(struct work_struct *work)
{
struct uas_cmd_info *cmdinfo;
+ struct uas_cmd_info *temp;
struct list_head list;
+ int err;
spin_lock_irq(&uas_work_lock);
list_replace_init(&uas_work_list, &list);
spin_unlock_irq(&uas_work_lock);
- list_for_each_entry(cmdinfo, &list, list) {
+ list_for_each_entry_safe(cmdinfo, temp, &list, list) {
struct scsi_pointer *scp = (void *)cmdinfo;
struct scsi_cmnd *cmnd = container_of(scp,
struct scsi_cmnd, SCp);
- uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
+ err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
+ if (err) {
+ list_del(&cmdinfo->list);
+ spin_lock_irq(&uas_work_lock);
+ list_add_tail(&cmdinfo->list, &uas_work_list);
+ spin_unlock_irq(&uas_work_lock);
+ schedule_work(&uas_work);
+ }
}
}
-static DECLARE_WORK(uas_work, uas_do_work);
-
static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
{
struct sense_iu *sense_iu = urb->transfer_buffer;
struct scsi_device *sdev = cmnd->device;
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (urb->actual_length > 16) {
unsigned len = be16_to_cpup(&sense_iu->len);
@@ -169,16 +132,15 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
}
cmnd->result = sense_iu->status;
- if (sdev->current_cmnd)
- sdev->current_cmnd = NULL;
- cmnd->scsi_done(cmnd);
- usb_free_urb(urb);
+ if (!(cmdinfo->state & DATA_COMPLETES_CMD))
+ cmnd->scsi_done(cmnd);
}
static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
{
struct sense_iu_old *sense_iu = urb->transfer_buffer;
struct scsi_device *sdev = cmnd->device;
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (urb->actual_length > 8) {
unsigned len = be16_to_cpup(&sense_iu->len) - 2;
@@ -196,10 +158,8 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
}
cmnd->result = sense_iu->status;
- if (sdev->current_cmnd)
- sdev->current_cmnd = NULL;
- cmnd->scsi_done(cmnd);
- usb_free_urb(urb);
+ if (!(cmdinfo->state & DATA_COMPLETES_CMD))
+ cmnd->scsi_done(cmnd);
}
static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
@@ -208,7 +168,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
int err;
- cmdinfo->state = direction | SUBMIT_STATUS_URB;
+ cmdinfo->state = direction;
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
if (err) {
spin_lock(&uas_work_lock);
@@ -221,27 +181,61 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
static void uas_stat_cmplt(struct urb *urb)
{
struct iu *iu = urb->transfer_buffer;
- struct scsi_device *sdev = urb->context;
- struct uas_dev_info *devinfo = sdev->hostdata;
+ struct Scsi_Host *shost = urb->context;
+ struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
struct scsi_cmnd *cmnd;
+ struct uas_cmd_info *cmdinfo;
u16 tag;
+ int ret;
if (urb->status) {
dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
- usb_free_urb(urb);
+ if (devinfo->use_streams)
+ usb_free_urb(urb);
return;
}
tag = be16_to_cpup(&iu->tag) - 1;
- if (sdev->current_cmnd)
- cmnd = sdev->current_cmnd;
+ if (tag == 0)
+ cmnd = devinfo->cmnd;
else
- cmnd = scsi_find_tag(sdev, tag);
- if (!cmnd)
+ cmnd = scsi_host_find_tag(shost, tag - 1);
+ if (!cmnd) {
+ if (devinfo->use_streams) {
+ usb_free_urb(urb);
+ return;
+ }
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ dev_err(&urb->dev->dev, "failed submit status urb\n");
return;
+ }
+ cmdinfo = (void *)&cmnd->SCp;
switch (iu->iu_id) {
case IU_ID_STATUS:
+ if (devinfo->cmnd == cmnd)
+ devinfo->cmnd = NULL;
+
+ if (!(cmdinfo->state & COMPLETED_DATA_IN) &&
+ cmdinfo->data_in_urb) {
+ if (devinfo->use_streams) {
+ cmdinfo->state |= DATA_COMPLETES_CMD;
+ usb_unlink_urb(cmdinfo->data_in_urb);
+ } else {
+ usb_free_urb(cmdinfo->data_in_urb);
+ }
+ }
+ if (!(cmdinfo->state & COMPLETED_DATA_OUT) &&
+ cmdinfo->data_out_urb) {
+ if (devinfo->use_streams) {
+ cmdinfo->state |= DATA_COMPLETES_CMD;
+ usb_unlink_urb(cmdinfo->data_in_urb);
+ } else {
+ usb_free_urb(cmdinfo->data_out_urb);
+ }
+ }
+
if (urb->actual_length < 16)
devinfo->uas_sense_old = 1;
if (devinfo->uas_sense_old)
@@ -259,29 +253,70 @@ static void uas_stat_cmplt(struct urb *urb)
scmd_printk(KERN_ERR, cmnd,
"Bogus IU (%d) received on status pipe\n", iu->iu_id);
}
+
+ if (devinfo->use_streams) {
+ usb_free_urb(urb);
+ return;
+ }
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ dev_err(&urb->dev->dev, "failed submit status urb\n");
}
-static void uas_data_cmplt(struct urb *urb)
+static void uas_data_out_cmplt(struct urb *urb)
{
- struct scsi_data_buffer *sdb = urb->context;
+ struct scsi_cmnd *cmnd = urb->context;
+ struct scsi_data_buffer *sdb = scsi_out(cmnd);
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+
+ cmdinfo->state |= COMPLETED_DATA_OUT;
+
sdb->resid = sdb->length - urb->actual_length;
usb_free_urb(urb);
+
+ if (cmdinfo->state & DATA_COMPLETES_CMD)
+ cmnd->scsi_done(cmnd);
+}
+
+static void uas_data_in_cmplt(struct urb *urb)
+{
+ struct scsi_cmnd *cmnd = urb->context;
+ struct scsi_data_buffer *sdb = scsi_in(cmnd);
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+
+ cmdinfo->state |= COMPLETED_DATA_IN;
+
+ sdb->resid = sdb->length - urb->actual_length;
+ usb_free_urb(urb);
+
+ if (cmdinfo->state & DATA_COMPLETES_CMD)
+ cmnd->scsi_done(cmnd);
}
static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
- unsigned int pipe, u16 stream_id,
- struct scsi_data_buffer *sdb,
- enum dma_data_direction dir)
+ unsigned int pipe, struct scsi_cmnd *cmnd,
+ enum dma_data_direction dir)
{
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
struct usb_device *udev = devinfo->udev;
struct urb *urb = usb_alloc_urb(0, gfp);
+ struct scsi_data_buffer *sdb;
+ usb_complete_t complete_fn;
+ u16 stream_id = cmdinfo->stream;
if (!urb)
goto out;
- usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt,
- sdb);
- if (devinfo->use_streams)
- urb->stream_id = stream_id;
+ if (dir == DMA_FROM_DEVICE) {
+ sdb = scsi_in(cmnd);
+ complete_fn = uas_data_in_cmplt;
+ } else {
+ sdb = scsi_out(cmnd);
+ complete_fn = uas_data_out_cmplt;
+ }
+ usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
+ complete_fn, cmnd);
+ urb->stream_id = stream_id;
urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
urb->sg = sdb->table.sgl;
out:
@@ -289,7 +324,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
}
static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
- struct scsi_cmnd *cmnd, u16 stream_id)
+ struct Scsi_Host *shost, u16 stream_id)
{
struct usb_device *udev = devinfo->udev;
struct urb *urb = usb_alloc_urb(0, gfp);
@@ -303,7 +338,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto free;
usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
- uas_stat_cmplt, cmnd->device);
+ uas_stat_cmplt, shost);
urb->stream_id = stream_id;
urb->transfer_flags |= URB_FREE_BUFFER;
out:
@@ -334,7 +369,10 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto free;
iu->iu_id = IU_ID_COMMAND;
- iu->tag = cpu_to_be16(stream_id);
+ if (blk_rq_tagged(cmnd->request))
+ iu->tag = cpu_to_be16(cmnd->request->tag + 2);
+ else
+ iu->tag = cpu_to_be16(1);
iu->prio_attr = UAS_SIMPLE_TAG;
iu->len = len;
int_to_scsilun(sdev->lun, &iu->lun);
@@ -362,8 +400,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (cmdinfo->state & ALLOC_STATUS_URB) {
- cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd,
- cmdinfo->stream);
+ cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp,
+ cmnd->device->host, cmdinfo->stream);
if (!cmdinfo->status_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_STATUS_URB;
@@ -380,8 +418,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
if (cmdinfo->state & ALLOC_DATA_IN_URB) {
cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
- devinfo->data_in_pipe, cmdinfo->stream,
- scsi_in(cmnd), DMA_FROM_DEVICE);
+ devinfo->data_in_pipe, cmnd,
+ DMA_FROM_DEVICE);
if (!cmdinfo->data_in_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_DATA_IN_URB;
@@ -398,8 +436,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
- devinfo->data_out_pipe, cmdinfo->stream,
- scsi_out(cmnd), DMA_TO_DEVICE);
+ devinfo->data_out_pipe, cmnd,
+ DMA_TO_DEVICE);
if (!cmdinfo->data_out_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
@@ -444,13 +482,13 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
- if (!cmdinfo->status_urb && sdev->current_cmnd)
+ if (devinfo->cmnd)
return SCSI_MLQUEUE_DEVICE_BUSY;
if (blk_rq_tagged(cmnd->request)) {
- cmdinfo->stream = cmnd->request->tag + 1;
+ cmdinfo->stream = cmnd->request->tag + 2;
} else {
- sdev->current_cmnd = cmnd;
+ devinfo->cmnd = cmnd;
cmdinfo->stream = 1;
}
@@ -472,7 +510,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
}
if (!devinfo->use_streams) {
- cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
+ cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB |
+ ALLOC_STATUS_URB | SUBMIT_STATUS_URB);
cmdinfo->stream = 0;
}
@@ -551,7 +590,7 @@ static int uas_slave_configure(struct scsi_device *sdev)
{
struct uas_dev_info *devinfo = sdev->hostdata;
scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
- scsi_activate_tcq(sdev, devinfo->qdepth - 1);
+ scsi_activate_tcq(sdev, devinfo->qdepth - 2);
return 0;
}
@@ -589,22 +628,34 @@ static int uas_is_interface(struct usb_host_interface *intf)
intf->desc.bInterfaceProtocol == USB_PR_UAS);
}
+static int uas_isnt_supported(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ dev_warn(&udev->dev, "The driver for the USB controller %s does not "
+ "support scatter-gather which is\n",
+ hcd->driver->description);
+ dev_warn(&udev->dev, "required by the UAS driver. Please try an"
+ "alternative USB controller if you wish to use UAS.\n");
+ return -ENODEV;
+}
+
static int uas_switch_interface(struct usb_device *udev,
struct usb_interface *intf)
{
int i;
-
- if (uas_is_interface(intf->cur_altsetting))
- return 0;
+ int sg_supported = udev->bus->sg_tablesize != 0;
for (i = 0; i < intf->num_altsetting; i++) {
struct usb_host_interface *alt = &intf->altsetting[i];
- if (alt == intf->cur_altsetting)
- continue;
- if (uas_is_interface(alt))
+
+ if (uas_is_interface(alt)) {
+ if (!sg_supported)
+ return uas_isnt_supported(udev);
return usb_set_interface(udev,
alt->desc.bInterfaceNumber,
alt->desc.bAlternateSetting);
+ }
}
return -ENODEV;
@@ -619,6 +670,7 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints;
devinfo->uas_sense_old = 0;
+ devinfo->cmnd = NULL;
for (i = 0; i < n_endpoints; i++) {
unsigned char *extra = endpoint[i].extra;
@@ -670,6 +722,40 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
}
}
+static int uas_alloc_status_urb(struct uas_dev_info *devinfo,
+ struct Scsi_Host *shost)
+{
+ if (devinfo->use_streams) {
+ devinfo->status_urb = NULL;
+ return 0;
+ }
+
+ devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL,
+ shost, 0);
+ if (!devinfo->status_urb)
+ goto err_s_urb;
+
+ if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL))
+ goto err_submit_urb;
+
+ return 0;
+err_submit_urb:
+ usb_free_urb(devinfo->status_urb);
+err_s_urb:
+ return -ENOMEM;
+}
+
+static void uas_free_streams(struct uas_dev_info *devinfo)
+{
+ struct usb_device *udev = devinfo->udev;
+ struct usb_host_endpoint *eps[3];
+
+ eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
+ eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
+ eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
+ usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL);
+}
+
/*
* XXX: What I'd like to do here is register a SCSI host for each USB host in
* the system. Follow usb-storage's design of registering a SCSI host for
@@ -699,18 +785,33 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
shost->max_id = 1;
shost->sg_tablesize = udev->bus->sg_tablesize;
- result = scsi_add_host(shost, &intf->dev);
+ devinfo->intf = intf;
+ devinfo->udev = udev;
+ uas_configure_endpoints(devinfo);
+
+ result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
if (result)
goto free;
+
+ result = scsi_add_host(shost, &intf->dev);
+ if (result)
+ goto deconfig_eps;
+
shost->hostdata[0] = (unsigned long)devinfo;
- devinfo->intf = intf;
- devinfo->udev = udev;
- uas_configure_endpoints(devinfo);
+ result = uas_alloc_status_urb(devinfo, shost);
+ if (result)
+ goto err_alloc_status;
scsi_scan_host(shost);
usb_set_intfdata(intf, shost);
return result;
+
+err_alloc_status:
+ scsi_remove_host(shost);
+ shost = NULL;
+deconfig_eps:
+ uas_free_streams(devinfo);
free:
kfree(devinfo);
if (shost)
@@ -732,18 +833,13 @@ static int uas_post_reset(struct usb_interface *intf)
static void uas_disconnect(struct usb_interface *intf)
{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct usb_host_endpoint *eps[3];
struct Scsi_Host *shost = usb_get_intfdata(intf);
struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
scsi_remove_host(shost);
-
- eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
- eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
- eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
- usb_free_streams(intf, eps, 3, GFP_KERNEL);
-
+ usb_kill_urb(devinfo->status_urb);
+ usb_free_urb(devinfo->status_urb);
+ uas_free_streams(devinfo);
kfree(devinfo);
}
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index db51ba16dc0..c18538e4a6d 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -125,6 +125,9 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
{ } /* Terminating entry */
};
+static struct us_unusual_dev for_dynamic_ids =
+ USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0);
+
#undef UNUSUAL_DEV
#undef COMPLIANT_DEV
#undef USUAL_DEV
@@ -999,8 +1002,10 @@ EXPORT_SYMBOL_GPL(usb_stor_disconnect);
static int storage_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ struct us_unusual_dev *unusual_dev;
struct us_data *us;
int result;
+ int size;
/*
* If libusual is configured, let it decide whether a standard
@@ -1019,8 +1024,19 @@ static int storage_probe(struct usb_interface *intf,
* table, so we use the index of the id entry to find the
* corresponding unusual_devs entry.
*/
- result = usb_stor_probe1(&us, intf, id,
- (id - usb_storage_usb_ids) + us_unusual_dev_list);
+
+ size = ARRAY_SIZE(us_unusual_dev_list);
+ if (id >= usb_storage_usb_ids && id < usb_storage_usb_ids + size) {
+ unusual_dev = (id - usb_storage_usb_ids) + us_unusual_dev_list;
+ } else {
+ unusual_dev = &for_dynamic_ids;
+
+ US_DEBUGP("%s %s 0x%04x 0x%04x\n", "Use Bulk-Only transport",
+ "with the Transparent SCSI protocol for dynamic id:",
+ id->idVendor, id->idProduct);
+ }
+
+ result = usb_stor_probe1(&us, intf, id, unusual_dev);
if (result)
return result;
@@ -1046,7 +1062,6 @@ static struct usb_driver usb_storage_driver = {
.id_table = usb_storage_usb_ids,
.supports_autosuspend = 1,
.soft_unbind = 1,
- .no_dynamic_id = 1,
};
static int __init usb_stor_init(void)