aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2013-06-06 22:15:55 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-25 17:07:30 -0400
commit98dcc2946adbe4349ef1ef9b99873b912831edd4 (patch)
tree2b4a51a862e10f4cedc54c36d779e9ccfe69f962 /drivers/scsi
parent64ea2992a29aa0bdc4eaf457351b063caafb6655 (diff)
SCSI: sd: Update WRITE SAME heuristics
commit 66c28f97120e8a621afd5aa7a31c4b85c547d33d upstream. SATA drives located behind a SAS controller would incorrectly receive WRITE SAME commands. Tweak the heuristics so that: - If REPORT SUPPORTED OPERATION CODES is provided we will use that to choose between WRITE SAME(16), WRITE SAME(10) and disabled. This also fixes an issue with the old code which would issue WRITE SAME(10) despite the command not being whitelisted in REPORT SUPPORTED OPERATION CODES. - If REPORT SUPPORTED OPERATION CODES is not provided we will fall back to WRITE SAME(10) unless the device has an ATA Information VPD page. The assumption is that a SATL which is smart enough to implement WRITE SAME would also provide REPORT SUPPORTED OPERATION CODES. To facilitate the new heuristics scsi_report_opcode() has been modified to so we can distinguish between "operation not supported" and "RSOC not supported". Reported-by: H. Peter Anvin <hpa@zytor.com> Tested-by: Bernd Schubert <bernd.schubert@itwm.fraunhofer.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/scsi.c8
-rw-r--r--drivers/scsi/sd.c46
-rw-r--r--drivers/scsi/sd.h1
3 files changed, 37 insertions, 18 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 2c0d0ec8150b..3b1ea34e1f5a 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1070,8 +1070,8 @@ EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
1070 * @opcode: opcode for command to look up 1070 * @opcode: opcode for command to look up
1071 * 1071 *
1072 * Uses the REPORT SUPPORTED OPERATION CODES to look up the given 1072 * Uses the REPORT SUPPORTED OPERATION CODES to look up the given
1073 * opcode. Returns 0 if RSOC fails or if the command opcode is 1073 * opcode. Returns -EINVAL if RSOC fails, 0 if the command opcode is
1074 * unsupported. Returns 1 if the device claims to support the command. 1074 * unsupported and 1 if the device claims to support the command.
1075 */ 1075 */
1076int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, 1076int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
1077 unsigned int len, unsigned char opcode) 1077 unsigned int len, unsigned char opcode)
@@ -1081,7 +1081,7 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
1081 int result; 1081 int result;
1082 1082
1083 if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3) 1083 if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3)
1084 return 0; 1084 return -EINVAL;
1085 1085
1086 memset(cmd, 0, 16); 1086 memset(cmd, 0, 16);
1087 cmd[0] = MAINTENANCE_IN; 1087 cmd[0] = MAINTENANCE_IN;
@@ -1097,7 +1097,7 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
1097 if (result && scsi_sense_valid(&sshdr) && 1097 if (result && scsi_sense_valid(&sshdr) &&
1098 sshdr.sense_key == ILLEGAL_REQUEST && 1098 sshdr.sense_key == ILLEGAL_REQUEST &&
1099 (sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00) 1099 (sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00)
1100 return 0; 1100 return -EINVAL;
1101 1101
1102 if ((buffer[1] & 3) == 3) /* Command supported */ 1102 if ((buffer[1] & 3) == 3) /* Command supported */
1103 return 1; 1103 return 1;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 6f6a1b48f998..1b1125e67f1e 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -442,8 +442,10 @@ sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr,
442 442
443 if (max == 0) 443 if (max == 0)
444 sdp->no_write_same = 1; 444 sdp->no_write_same = 1;
445 else if (max <= SD_MAX_WS16_BLOCKS) 445 else if (max <= SD_MAX_WS16_BLOCKS) {
446 sdp->no_write_same = 0;
446 sdkp->max_ws_blocks = max; 447 sdkp->max_ws_blocks = max;
448 }
447 449
448 sd_config_write_same(sdkp); 450 sd_config_write_same(sdkp);
449 451
@@ -740,7 +742,6 @@ static void sd_config_write_same(struct scsi_disk *sdkp)
740{ 742{
741 struct request_queue *q = sdkp->disk->queue; 743 struct request_queue *q = sdkp->disk->queue;
742 unsigned int logical_block_size = sdkp->device->sector_size; 744 unsigned int logical_block_size = sdkp->device->sector_size;
743 unsigned int blocks = 0;
744 745
745 if (sdkp->device->no_write_same) { 746 if (sdkp->device->no_write_same) {
746 sdkp->max_ws_blocks = 0; 747 sdkp->max_ws_blocks = 0;
@@ -752,18 +753,20 @@ static void sd_config_write_same(struct scsi_disk *sdkp)
752 * blocks per I/O unless the device explicitly advertises a 753 * blocks per I/O unless the device explicitly advertises a
753 * bigger limit. 754 * bigger limit.
754 */ 755 */
755 if (sdkp->max_ws_blocks == 0) 756 if (sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS)
756 sdkp->max_ws_blocks = SD_MAX_WS10_BLOCKS; 757 sdkp->max_ws_blocks = min_not_zero(sdkp->max_ws_blocks,
757 758 (u32)SD_MAX_WS16_BLOCKS);
758 if (sdkp->ws16 || sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS) 759 else if (sdkp->ws16 || sdkp->ws10 || sdkp->device->no_report_opcodes)
759 blocks = min_not_zero(sdkp->max_ws_blocks, 760 sdkp->max_ws_blocks = min_not_zero(sdkp->max_ws_blocks,
760 (u32)SD_MAX_WS16_BLOCKS); 761 (u32)SD_MAX_WS10_BLOCKS);
761 else 762 else {
762 blocks = min_not_zero(sdkp->max_ws_blocks, 763 sdkp->device->no_write_same = 1;
763 (u32)SD_MAX_WS10_BLOCKS); 764 sdkp->max_ws_blocks = 0;
765 }
764 766
765out: 767out:
766 blk_queue_max_write_same_sectors(q, blocks * (logical_block_size >> 9)); 768 blk_queue_max_write_same_sectors(q, sdkp->max_ws_blocks *
769 (logical_block_size >> 9));
767} 770}
768 771
769/** 772/**
@@ -2635,9 +2638,24 @@ static void sd_read_block_provisioning(struct scsi_disk *sdkp)
2635 2638
2636static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) 2639static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
2637{ 2640{
2638 if (scsi_report_opcode(sdkp->device, buffer, SD_BUF_SIZE, 2641 struct scsi_device *sdev = sdkp->device;
2639 WRITE_SAME_16)) 2642
2643 if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY) < 0) {
2644 sdev->no_report_opcodes = 1;
2645
2646 /* Disable WRITE SAME if REPORT SUPPORTED OPERATION
2647 * CODES is unsupported and the device has an ATA
2648 * Information VPD page (SAT).
2649 */
2650 if (!scsi_get_vpd_page(sdev, 0x89, buffer, SD_BUF_SIZE))
2651 sdev->no_write_same = 1;
2652 }
2653
2654 if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME_16) == 1)
2640 sdkp->ws16 = 1; 2655 sdkp->ws16 = 1;
2656
2657 if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME) == 1)
2658 sdkp->ws10 = 1;
2641} 2659}
2642 2660
2643static int sd_try_extended_inquiry(struct scsi_device *sdp) 2661static int sd_try_extended_inquiry(struct scsi_device *sdp)
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 2386aeb41fe8..7a049de22051 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -84,6 +84,7 @@ struct scsi_disk {
84 unsigned lbpws : 1; 84 unsigned lbpws : 1;
85 unsigned lbpws10 : 1; 85 unsigned lbpws10 : 1;
86 unsigned lbpvpd : 1; 86 unsigned lbpvpd : 1;
87 unsigned ws10 : 1;
87 unsigned ws16 : 1; 88 unsigned ws16 : 1;
88}; 89};
89#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) 90#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)