aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 91e8a953d1de..34da1a1acb09 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
@@ -750,7 +752,6 @@ static void sd_config_write_same(struct scsi_disk *sdkp)
750{ 752{
751 struct request_queue *q = sdkp->disk->queue; 753 struct request_queue *q = sdkp->disk->queue;
752 unsigned int logical_block_size = sdkp->device->sector_size; 754 unsigned int logical_block_size = sdkp->device->sector_size;
753 unsigned int blocks = 0;
754 755
755 if (sdkp->device->no_write_same) { 756 if (sdkp->device->no_write_same) {
756 sdkp->max_ws_blocks = 0; 757 sdkp->max_ws_blocks = 0;
@@ -762,18 +763,20 @@ static void sd_config_write_same(struct scsi_disk *sdkp)
762 * blocks per I/O unless the device explicitly advertises a 763 * blocks per I/O unless the device explicitly advertises a
763 * bigger limit. 764 * bigger limit.
764 */ 765 */
765 if (sdkp->max_ws_blocks == 0) 766 if (sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS)
766 sdkp->max_ws_blocks = SD_MAX_WS10_BLOCKS; 767 sdkp->max_ws_blocks = min_not_zero(sdkp->max_ws_blocks,
767 768 (u32)SD_MAX_WS16_BLOCKS);
768 if (sdkp->ws16 || sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS) 769 else if (sdkp->ws16 || sdkp->ws10 || sdkp->device->no_report_opcodes)
769 blocks = min_not_zero(sdkp->max_ws_blocks, 770 sdkp->max_ws_blocks = min_not_zero(sdkp->max_ws_blocks,
770 (u32)SD_MAX_WS16_BLOCKS); 771 (u32)SD_MAX_WS10_BLOCKS);
771 else 772 else {
772 blocks = min_not_zero(sdkp->max_ws_blocks, 773 sdkp->device->no_write_same = 1;
773 (u32)SD_MAX_WS10_BLOCKS); 774 sdkp->max_ws_blocks = 0;
775 }
774 776
775out: 777out:
776 blk_queue_max_write_same_sectors(q, blocks * (logical_block_size >> 9)); 778 blk_queue_max_write_same_sectors(q, sdkp->max_ws_blocks *
779 (logical_block_size >> 9));
777} 780}
778 781
779/** 782/**
@@ -2645,9 +2648,24 @@ static void sd_read_block_provisioning(struct scsi_disk *sdkp)
2645 2648
2646static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) 2649static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
2647{ 2650{
2648 if (scsi_report_opcode(sdkp->device, buffer, SD_BUF_SIZE, 2651 struct scsi_device *sdev = sdkp->device;
2649 WRITE_SAME_16)) 2652
2653 if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY) < 0) {
2654 sdev->no_report_opcodes = 1;
2655
2656 /* Disable WRITE SAME if REPORT SUPPORTED OPERATION
2657 * CODES is unsupported and the device has an ATA
2658 * Information VPD page (SAT).
2659 */
2660 if (!scsi_get_vpd_page(sdev, 0x89, buffer, SD_BUF_SIZE))
2661 sdev->no_write_same = 1;
2662 }
2663
2664 if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME_16) == 1)
2650 sdkp->ws16 = 1; 2665 sdkp->ws16 = 1;
2666
2667 if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME) == 1)
2668 sdkp->ws10 = 1;
2651} 2669}
2652 2670
2653static int sd_try_extended_inquiry(struct scsi_device *sdp) 2671static 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)