Skip to content

Commit 66c28f9

Browse files
martinkpetersenJames Bottomley
authored and
James Bottomley
committed
[SCSI] sd: Update WRITE SAME heuristics
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 <[email protected]> Tested-by: Bernd Schubert <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]> Cc: <[email protected]> Signed-off-by: James Bottomley <[email protected]>
1 parent 5d65f91 commit 66c28f9

File tree

3 files changed

+37
-18
lines changed

3 files changed

+37
-18
lines changed

drivers/scsi/scsi.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,8 +1070,8 @@ EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
10701070
* @opcode: opcode for command to look up
10711071
*
10721072
* Uses the REPORT SUPPORTED OPERATION CODES to look up the given
1073-
* opcode. Returns 0 if RSOC fails or if the command opcode is
1074-
* unsupported. Returns 1 if the device claims to support the command.
1073+
* opcode. Returns -EINVAL if RSOC fails, 0 if the command opcode is
1074+
* unsupported and 1 if the device claims to support the command.
10751075
*/
10761076
int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
10771077
unsigned int len, unsigned char opcode)
@@ -1081,7 +1081,7 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
10811081
int result;
10821082

10831083
if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3)
1084-
return 0;
1084+
return -EINVAL;
10851085

10861086
memset(cmd, 0, 16);
10871087
cmd[0] = MAINTENANCE_IN;
@@ -1097,7 +1097,7 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
10971097
if (result && scsi_sense_valid(&sshdr) &&
10981098
sshdr.sense_key == ILLEGAL_REQUEST &&
10991099
(sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00)
1100-
return 0;
1100+
return -EINVAL;
11011101

11021102
if ((buffer[1] & 3) == 3) /* Command supported */
11031103
return 1;

drivers/scsi/sd.c

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -442,8 +442,10 @@ sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr,
442442

443443
if (max == 0)
444444
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;
446447
sdkp->max_ws_blocks = max;
448+
}
447449

448450
sd_config_write_same(sdkp);
449451

@@ -750,7 +752,6 @@ static void sd_config_write_same(struct scsi_disk *sdkp)
750752
{
751753
struct request_queue *q = sdkp->disk->queue;
752754
unsigned int logical_block_size = sdkp->device->sector_size;
753-
unsigned int blocks = 0;
754755

755756
if (sdkp->device->no_write_same) {
756757
sdkp->max_ws_blocks = 0;
@@ -762,18 +763,20 @@ static void sd_config_write_same(struct scsi_disk *sdkp)
762763
* blocks per I/O unless the device explicitly advertises a
763764
* bigger limit.
764765
*/
765-
if (sdkp->max_ws_blocks == 0)
766-
sdkp->max_ws_blocks = SD_MAX_WS10_BLOCKS;
767-
768-
if (sdkp->ws16 || sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS)
769-
blocks = min_not_zero(sdkp->max_ws_blocks,
770-
(u32)SD_MAX_WS16_BLOCKS);
771-
else
772-
blocks = min_not_zero(sdkp->max_ws_blocks,
773-
(u32)SD_MAX_WS10_BLOCKS);
766+
if (sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS)
767+
sdkp->max_ws_blocks = min_not_zero(sdkp->max_ws_blocks,
768+
(u32)SD_MAX_WS16_BLOCKS);
769+
else if (sdkp->ws16 || sdkp->ws10 || sdkp->device->no_report_opcodes)
770+
sdkp->max_ws_blocks = min_not_zero(sdkp->max_ws_blocks,
771+
(u32)SD_MAX_WS10_BLOCKS);
772+
else {
773+
sdkp->device->no_write_same = 1;
774+
sdkp->max_ws_blocks = 0;
775+
}
774776

775777
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));
777780
}
778781

779782
/**
@@ -2645,9 +2648,24 @@ static void sd_read_block_provisioning(struct scsi_disk *sdkp)
26452648

26462649
static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
26472650
{
2648-
if (scsi_report_opcode(sdkp->device, buffer, SD_BUF_SIZE,
2649-
WRITE_SAME_16))
2651+
struct scsi_device *sdev = sdkp->device;
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)
26502665
sdkp->ws16 = 1;
2666+
2667+
if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME) == 1)
2668+
sdkp->ws10 = 1;
26512669
}
26522670

26532671
static int sd_try_extended_inquiry(struct scsi_device *sdp)

drivers/scsi/sd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ struct scsi_disk {
8484
unsigned lbpws : 1;
8585
unsigned lbpws10 : 1;
8686
unsigned lbpvpd : 1;
87+
unsigned ws10 : 1;
8788
unsigned ws16 : 1;
8889
};
8990
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)

0 commit comments

Comments
 (0)