diff options
-rw-r--r-- | drivers/scsi/scsi.c | 8 | ||||
-rw-r--r-- | drivers/scsi/sd.c | 46 | ||||
-rw-r--r-- | drivers/scsi/sd.h | 1 |
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 | */ |
1076 | int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, | 1076 | int 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 | ||
775 | out: | 777 | out: |
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 | ||
2646 | static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) | 2649 | static 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 | ||
2653 | static int sd_try_extended_inquiry(struct scsi_device *sdp) | 2671 | static 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) |