aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2014-09-02 11:35:50 -0400
committerChristoph Hellwig <hch@lst.de>2014-09-15 19:01:58 -0400
commit50c4e96411a6cd728f04cf70d8d6def57828b320 (patch)
treefd47f80ec189ac23a75ddfcc82c24a428e8da3aa
parent64bdcbc449105377dd60c8da97cfc1663b39562c (diff)
scsi: don't store LUN bits in CDB[1] for USB mass-storage devices
The SCSI specification requires that the second Command Data Byte should contain the LUN value in its high-order bits if the recipient device reports SCSI level 2 or below. Nevertheless, some USB mass-storage devices use those bits for other purposes in vendor-specific commands. Currently Linux has no way to send such commands, because the SCSI stack always overwrites the LUN bits. Testing shows that Windows 7 and XP do not store the LUN bits in the CDB when sending commands to a USB device. This doesn't matter if the device uses the Bulk-Only or UAS transports (which virtually all modern USB mass-storage devices do), as these have a separate mechanism for sending the LUN value. Therefore this patch introduces a flag in the Scsi_Host structure to inform the SCSI midlayer that a transport does not require the LUN bits to be stored in the CDB, and it makes usb-storage set this flag for all devices using the Bulk-Only transport. (UAS is handled by a separate driver, but it doesn't really matter because no SCSI-2 or lower device is at all likely to use UAS.) The patch also cleans up the code responsible for storing the LUN value by adding a bitflag to the scsi_device structure. The test for whether to stick the LUN value in the CDB can be made when the device is probed, and stored for future use rather than being made over and over in the fast path. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Tiziano Bacocco <tiziano.bacocco@gmail.com> Acked-by: Martin K. Petersen <martin.petersen@oracle.com> Acked-by: James Bottomley <James.Bottomley@HansenPartnership.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--drivers/scsi/scsi.c8
-rw-r--r--drivers/scsi/scsi_scan.c10
-rw-r--r--drivers/scsi/scsi_sysfs.c12
-rw-r--r--drivers/usb/storage/usb.c8
-rw-r--r--include/scsi/scsi_device.h1
-rw-r--r--include/scsi/scsi_host.h3
6 files changed, 36 insertions, 6 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index d81f3cc43ff1..1423cb17fbfd 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -670,14 +670,10 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
670 return SCSI_MLQUEUE_DEVICE_BUSY; 670 return SCSI_MLQUEUE_DEVICE_BUSY;
671 } 671 }
672 672
673 /* 673 /* Store the LUN value in cmnd, if needed. */
674 * If SCSI-2 or lower, store the LUN value in cmnd. 674 if (cmd->device->lun_in_cdb)
675 */
676 if (cmd->device->scsi_level <= SCSI_2 &&
677 cmd->device->scsi_level != SCSI_UNKNOWN) {
678 cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) | 675 cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
679 (cmd->device->lun << 5 & 0xe0); 676 (cmd->device->lun << 5 & 0xe0);
680 }
681 677
682 scsi_log_send(cmd); 678 scsi_log_send(cmd);
683 679
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 56675dbbf681..f84c40188478 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -736,6 +736,16 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
736 sdev->scsi_level++; 736 sdev->scsi_level++;
737 sdev->sdev_target->scsi_level = sdev->scsi_level; 737 sdev->sdev_target->scsi_level = sdev->scsi_level;
738 738
739 /*
740 * If SCSI-2 or lower, and if the transport requires it,
741 * store the LUN value in CDB[1].
742 */
743 sdev->lun_in_cdb = 0;
744 if (sdev->scsi_level <= SCSI_2 &&
745 sdev->scsi_level != SCSI_UNKNOWN &&
746 !sdev->host->no_scsi2_lun_in_cdb)
747 sdev->lun_in_cdb = 1;
748
739 return 0; 749 return 0;
740} 750}
741 751
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 8b4105a22ac2..85e36f3a5585 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1263,7 +1263,19 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
1263 sdev->sdev_dev.class = &sdev_class; 1263 sdev->sdev_dev.class = &sdev_class;
1264 dev_set_name(&sdev->sdev_dev, "%d:%d:%d:%llu", 1264 dev_set_name(&sdev->sdev_dev, "%d:%d:%d:%llu",
1265 sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); 1265 sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
1266 /*
1267 * Get a default scsi_level from the target (derived from sibling
1268 * devices). This is the best we can do for guessing how to set
1269 * sdev->lun_in_cdb for the initial INQUIRY command. For LUN 0 the
1270 * setting doesn't matter, because all the bits are zero anyway.
1271 * But it does matter for higher LUNs.
1272 */
1266 sdev->scsi_level = starget->scsi_level; 1273 sdev->scsi_level = starget->scsi_level;
1274 if (sdev->scsi_level <= SCSI_2 &&
1275 sdev->scsi_level != SCSI_UNKNOWN &&
1276 !shost->no_scsi2_lun_in_cdb)
1277 sdev->lun_in_cdb = 1;
1278
1267 transport_setup_device(&sdev->sdev_gendev); 1279 transport_setup_device(&sdev->sdev_gendev);
1268 spin_lock_irqsave(shost->host_lock, flags); 1280 spin_lock_irqsave(shost->host_lock, flags);
1269 list_add_tail(&sdev->same_target_siblings, &starget->devices); 1281 list_add_tail(&sdev->same_target_siblings, &starget->devices);
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index cedb29252a92..bf3f8e2de046 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -983,6 +983,14 @@ int usb_stor_probe2(struct us_data *us)
983 if (!(us->fflags & US_FL_SCM_MULT_TARG)) 983 if (!(us->fflags & US_FL_SCM_MULT_TARG))
984 us_to_host(us)->max_id = 1; 984 us_to_host(us)->max_id = 1;
985 985
986 /*
987 * Like Windows, we won't store the LUN bits in CDB[1] for SCSI-2
988 * devices using the Bulk-Only transport (even though this violates
989 * the SCSI spec).
990 */
991 if (us->transport == usb_stor_Bulk_transport)
992 us_to_host(us)->no_scsi2_lun_in_cdb = 1;
993
986 /* Find the endpoints and calculate pipe values */ 994 /* Find the endpoints and calculate pipe values */
987 result = get_pipes(us); 995 result = get_pipes(us);
988 if (result) 996 if (result)
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 1a0d1842962e..27ecee73bd72 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -174,6 +174,7 @@ struct scsi_device {
174 unsigned wce_default_on:1; /* Cache is ON by default */ 174 unsigned wce_default_on:1; /* Cache is ON by default */
175 unsigned no_dif:1; /* T10 PI (DIF) should be disabled */ 175 unsigned no_dif:1; /* T10 PI (DIF) should be disabled */
176 unsigned broken_fua:1; /* Don't set FUA bit */ 176 unsigned broken_fua:1; /* Don't set FUA bit */
177 unsigned lun_in_cdb:1; /* Store LUN bits in CDB[1] */
177 178
178 atomic_t disk_events_disable_depth; /* disable depth for disk events */ 179 atomic_t disk_events_disable_depth; /* disable depth for disk events */
179 180
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index cafb260ef2d3..d0f69a3210df 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -693,6 +693,9 @@ struct Scsi_Host {
693 */ 693 */
694 struct workqueue_struct *tmf_work_q; 694 struct workqueue_struct *tmf_work_q;
695 695
696 /* The transport requires the LUN bits NOT to be stored in CDB[1] */
697 unsigned no_scsi2_lun_in_cdb:1;
698
696 /* 699 /*
697 * Value host_blocked counts down from 700 * Value host_blocked counts down from
698 */ 701 */