Commit 5db44863b6ebbb400c5e61d56ebe8f21ef48b1bd
Committed by
James Bottomley
1 parent
26e85fcd15
[SCSI] sd: Implement support for WRITE SAME
Implement support for WRITE SAME(10) and WRITE SAME(16) in the SCSI disk driver. - We set the default maximum to 0xFFFF because there are several devices out there that only support two-byte block counts even with WRITE SAME(16). We only enable transfers bigger than 0xFFFF if the device explicitly reports MAXIMUM WRITE SAME LENGTH in the BLOCK LIMITS VPD. - max_write_same_blocks can be overriden per-device basis in sysfs. - The UNMAP discovery heuristics remain unchanged but the discard limits are tweaked to match the "real" WRITE SAME commands. - In the error handling logic we now distinguish between WRITE SAME with and without UNMAP set. The discovery process heuristics are: - If the device reports a SCSI level of SPC-3 or greater we'll issue READ SUPPORTED OPERATION CODES to find out whether WRITE SAME(16) is supported. If that's the case we will use it. - If the device supports the block limits VPD and reports a MAXIMUM WRITE SAME LENGTH bigger than 0xFFFF we will use WRITE SAME(16). - Otherwise we will use WRITE SAME(10) unless the target LBA is beyond 0xFFFFFFFF or the block count exceeds 0xFFFF. - no_write_same is set for ATA, FireWire and USB. Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Mike Snitzer <snitzer@redhat.com> Reviewed-by: Jeff Garzik <jgarzik@redhat.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Showing 7 changed files with 191 additions and 16 deletions Side-by-side Diff
drivers/ata/libata-scsi.c
... | ... | @@ -1053,6 +1053,7 @@ |
1053 | 1053 | sdev->use_10_for_rw = 1; |
1054 | 1054 | sdev->use_10_for_ms = 1; |
1055 | 1055 | sdev->no_report_opcodes = 1; |
1056 | + sdev->no_write_same = 1; | |
1056 | 1057 | |
1057 | 1058 | /* Schedule policy is determined by ->qc_defer() callback and |
1058 | 1059 | * it needs to see every deferred qc. Set dev_blocked to 1 to |
drivers/firewire/sbp2.c
drivers/scsi/scsi_lib.c
... | ... | @@ -900,11 +900,23 @@ |
900 | 900 | action = ACTION_FAIL; |
901 | 901 | error = -EILSEQ; |
902 | 902 | /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ |
903 | - } else if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && | |
904 | - (cmd->cmnd[0] == UNMAP || | |
905 | - cmd->cmnd[0] == WRITE_SAME_16 || | |
906 | - cmd->cmnd[0] == WRITE_SAME)) { | |
907 | - description = "Discard failure"; | |
903 | + } else if (sshdr.asc == 0x20 || sshdr.asc == 0x24) { | |
904 | + switch (cmd->cmnd[0]) { | |
905 | + case UNMAP: | |
906 | + description = "Discard failure"; | |
907 | + break; | |
908 | + case WRITE_SAME: | |
909 | + case WRITE_SAME_16: | |
910 | + if (cmd->cmnd[1] & 0x8) | |
911 | + description = "Discard failure"; | |
912 | + else | |
913 | + description = | |
914 | + "Write same failure"; | |
915 | + break; | |
916 | + default: | |
917 | + description = "Invalid command failure"; | |
918 | + break; | |
919 | + } | |
908 | 920 | action = ACTION_FAIL; |
909 | 921 | error = -EREMOTEIO; |
910 | 922 | } else |
drivers/scsi/sd.c
... | ... | @@ -99,6 +99,7 @@ |
99 | 99 | #endif |
100 | 100 | |
101 | 101 | static void sd_config_discard(struct scsi_disk *, unsigned int); |
102 | +static void sd_config_write_same(struct scsi_disk *); | |
102 | 103 | static int sd_revalidate_disk(struct gendisk *); |
103 | 104 | static void sd_unlock_native_capacity(struct gendisk *disk); |
104 | 105 | static int sd_probe(struct device *); |
... | ... | @@ -395,6 +396,45 @@ |
395 | 396 | return err ? err : count; |
396 | 397 | } |
397 | 398 | |
399 | +static ssize_t | |
400 | +sd_show_write_same_blocks(struct device *dev, struct device_attribute *attr, | |
401 | + char *buf) | |
402 | +{ | |
403 | + struct scsi_disk *sdkp = to_scsi_disk(dev); | |
404 | + | |
405 | + return snprintf(buf, 20, "%u\n", sdkp->max_ws_blocks); | |
406 | +} | |
407 | + | |
408 | +static ssize_t | |
409 | +sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr, | |
410 | + const char *buf, size_t count) | |
411 | +{ | |
412 | + struct scsi_disk *sdkp = to_scsi_disk(dev); | |
413 | + struct scsi_device *sdp = sdkp->device; | |
414 | + unsigned long max; | |
415 | + int err; | |
416 | + | |
417 | + if (!capable(CAP_SYS_ADMIN)) | |
418 | + return -EACCES; | |
419 | + | |
420 | + if (sdp->type != TYPE_DISK) | |
421 | + return -EINVAL; | |
422 | + | |
423 | + err = kstrtoul(buf, 10, &max); | |
424 | + | |
425 | + if (err) | |
426 | + return err; | |
427 | + | |
428 | + if (max == 0) | |
429 | + sdp->no_write_same = 1; | |
430 | + else if (max <= SD_MAX_WS16_BLOCKS) | |
431 | + sdkp->max_ws_blocks = max; | |
432 | + | |
433 | + sd_config_write_same(sdkp); | |
434 | + | |
435 | + return count; | |
436 | +} | |
437 | + | |
398 | 438 | static struct device_attribute sd_disk_attrs[] = { |
399 | 439 | __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, |
400 | 440 | sd_store_cache_type), |
... | ... | @@ -410,6 +450,8 @@ |
410 | 450 | __ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL), |
411 | 451 | __ATTR(provisioning_mode, S_IRUGO|S_IWUSR, sd_show_provisioning_mode, |
412 | 452 | sd_store_provisioning_mode), |
453 | + __ATTR(max_write_same_blocks, S_IRUGO|S_IWUSR, | |
454 | + sd_show_write_same_blocks, sd_store_write_same_blocks), | |
413 | 455 | __ATTR(max_medium_access_timeouts, S_IRUGO|S_IWUSR, |
414 | 456 | sd_show_max_medium_access_timeouts, |
415 | 457 | sd_store_max_medium_access_timeouts), |
416 | 458 | |
417 | 459 | |
418 | 460 | |
... | ... | @@ -561,19 +603,23 @@ |
561 | 603 | return; |
562 | 604 | |
563 | 605 | case SD_LBP_UNMAP: |
564 | - max_blocks = min_not_zero(sdkp->max_unmap_blocks, 0xffffffff); | |
606 | + max_blocks = min_not_zero(sdkp->max_unmap_blocks, | |
607 | + (u32)SD_MAX_WS16_BLOCKS); | |
565 | 608 | break; |
566 | 609 | |
567 | 610 | case SD_LBP_WS16: |
568 | - max_blocks = min_not_zero(sdkp->max_ws_blocks, 0xffffffff); | |
611 | + max_blocks = min_not_zero(sdkp->max_ws_blocks, | |
612 | + (u32)SD_MAX_WS16_BLOCKS); | |
569 | 613 | break; |
570 | 614 | |
571 | 615 | case SD_LBP_WS10: |
572 | - max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff); | |
616 | + max_blocks = min_not_zero(sdkp->max_ws_blocks, | |
617 | + (u32)SD_MAX_WS10_BLOCKS); | |
573 | 618 | break; |
574 | 619 | |
575 | 620 | case SD_LBP_ZERO: |
576 | - max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff); | |
621 | + max_blocks = min_not_zero(sdkp->max_ws_blocks, | |
622 | + (u32)SD_MAX_WS10_BLOCKS); | |
577 | 623 | q->limits.discard_zeroes_data = 1; |
578 | 624 | break; |
579 | 625 | } |
... | ... | @@ -667,6 +713,83 @@ |
667 | 713 | return ret; |
668 | 714 | } |
669 | 715 | |
716 | +static void sd_config_write_same(struct scsi_disk *sdkp) | |
717 | +{ | |
718 | + struct request_queue *q = sdkp->disk->queue; | |
719 | + unsigned int logical_block_size = sdkp->device->sector_size; | |
720 | + unsigned int blocks = 0; | |
721 | + | |
722 | + if (sdkp->device->no_write_same) { | |
723 | + sdkp->max_ws_blocks = 0; | |
724 | + goto out; | |
725 | + } | |
726 | + | |
727 | + /* Some devices can not handle block counts above 0xffff despite | |
728 | + * supporting WRITE SAME(16). Consequently we default to 64k | |
729 | + * blocks per I/O unless the device explicitly advertises a | |
730 | + * bigger limit. | |
731 | + */ | |
732 | + if (sdkp->max_ws_blocks == 0) | |
733 | + sdkp->max_ws_blocks = SD_MAX_WS10_BLOCKS; | |
734 | + | |
735 | + if (sdkp->ws16 || sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS) | |
736 | + blocks = min_not_zero(sdkp->max_ws_blocks, | |
737 | + (u32)SD_MAX_WS16_BLOCKS); | |
738 | + else | |
739 | + blocks = min_not_zero(sdkp->max_ws_blocks, | |
740 | + (u32)SD_MAX_WS10_BLOCKS); | |
741 | + | |
742 | +out: | |
743 | + blk_queue_max_write_same_sectors(q, blocks * (logical_block_size >> 9)); | |
744 | +} | |
745 | + | |
746 | +/** | |
747 | + * sd_setup_write_same_cmnd - write the same data to multiple blocks | |
748 | + * @sdp: scsi device to operate one | |
749 | + * @rq: Request to prepare | |
750 | + * | |
751 | + * Will issue either WRITE SAME(10) or WRITE SAME(16) depending on | |
752 | + * preference indicated by target device. | |
753 | + **/ | |
754 | +static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq) | |
755 | +{ | |
756 | + struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); | |
757 | + struct bio *bio = rq->bio; | |
758 | + sector_t sector = blk_rq_pos(rq); | |
759 | + unsigned int nr_sectors = blk_rq_sectors(rq); | |
760 | + unsigned int nr_bytes = blk_rq_bytes(rq); | |
761 | + int ret; | |
762 | + | |
763 | + if (sdkp->device->no_write_same) | |
764 | + return BLKPREP_KILL; | |
765 | + | |
766 | + BUG_ON(bio_offset(bio) || bio_iovec(bio)->bv_len != sdp->sector_size); | |
767 | + | |
768 | + sector >>= ilog2(sdp->sector_size) - 9; | |
769 | + nr_sectors >>= ilog2(sdp->sector_size) - 9; | |
770 | + | |
771 | + rq->__data_len = sdp->sector_size; | |
772 | + rq->timeout = SD_WRITE_SAME_TIMEOUT; | |
773 | + memset(rq->cmd, 0, rq->cmd_len); | |
774 | + | |
775 | + if (sdkp->ws16 || sector > 0xffffffff || nr_sectors > 0xffff) { | |
776 | + rq->cmd_len = 16; | |
777 | + rq->cmd[0] = WRITE_SAME_16; | |
778 | + put_unaligned_be64(sector, &rq->cmd[2]); | |
779 | + put_unaligned_be32(nr_sectors, &rq->cmd[10]); | |
780 | + } else { | |
781 | + rq->cmd_len = 10; | |
782 | + rq->cmd[0] = WRITE_SAME; | |
783 | + put_unaligned_be32(sector, &rq->cmd[2]); | |
784 | + put_unaligned_be16(nr_sectors, &rq->cmd[7]); | |
785 | + } | |
786 | + | |
787 | + ret = scsi_setup_blk_pc_cmnd(sdp, rq); | |
788 | + rq->__data_len = nr_bytes; | |
789 | + | |
790 | + return ret; | |
791 | +} | |
792 | + | |
670 | 793 | static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) |
671 | 794 | { |
672 | 795 | rq->timeout = SD_FLUSH_TIMEOUT; |
... | ... | @@ -712,6 +835,9 @@ |
712 | 835 | if (rq->cmd_flags & REQ_DISCARD) { |
713 | 836 | ret = sd_setup_discard_cmnd(sdp, rq); |
714 | 837 | goto out; |
838 | + } else if (rq->cmd_flags & REQ_WRITE_SAME) { | |
839 | + ret = sd_setup_write_same_cmnd(sdp, rq); | |
840 | + goto out; | |
715 | 841 | } else if (rq->cmd_flags & REQ_FLUSH) { |
716 | 842 | ret = scsi_setup_flush_cmnd(sdp, rq); |
717 | 843 | goto out; |
718 | 844 | |
... | ... | @@ -1484,8 +1610,9 @@ |
1484 | 1610 | int sense_valid = 0; |
1485 | 1611 | int sense_deferred = 0; |
1486 | 1612 | unsigned char op = SCpnt->cmnd[0]; |
1613 | + unsigned char unmap = SCpnt->cmnd[1] & 8; | |
1487 | 1614 | |
1488 | - if (req->cmd_flags & REQ_DISCARD) { | |
1615 | + if (req->cmd_flags & REQ_DISCARD || req->cmd_flags & REQ_WRITE_SAME) { | |
1489 | 1616 | if (!result) { |
1490 | 1617 | good_bytes = blk_rq_bytes(req); |
1491 | 1618 | scsi_set_resid(SCpnt, 0); |
... | ... | @@ -1542,9 +1669,25 @@ |
1542 | 1669 | if (sshdr.asc == 0x10) /* DIX: Host detected corruption */ |
1543 | 1670 | good_bytes = sd_completed_bytes(SCpnt); |
1544 | 1671 | /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ |
1545 | - if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && | |
1546 | - (op == UNMAP || op == WRITE_SAME_16 || op == WRITE_SAME)) | |
1547 | - sd_config_discard(sdkp, SD_LBP_DISABLE); | |
1672 | + if (sshdr.asc == 0x20 || sshdr.asc == 0x24) { | |
1673 | + switch (op) { | |
1674 | + case UNMAP: | |
1675 | + sd_config_discard(sdkp, SD_LBP_DISABLE); | |
1676 | + break; | |
1677 | + case WRITE_SAME_16: | |
1678 | + case WRITE_SAME: | |
1679 | + if (unmap) | |
1680 | + sd_config_discard(sdkp, SD_LBP_DISABLE); | |
1681 | + else { | |
1682 | + sdkp->device->no_write_same = 1; | |
1683 | + sd_config_write_same(sdkp); | |
1684 | + | |
1685 | + good_bytes = 0; | |
1686 | + req->__data_len = blk_rq_bytes(req); | |
1687 | + req->cmd_flags |= REQ_QUIET; | |
1688 | + } | |
1689 | + } | |
1690 | + } | |
1548 | 1691 | break; |
1549 | 1692 | default: |
1550 | 1693 | break; |
... | ... | @@ -2380,9 +2523,7 @@ |
2380 | 2523 | if (buffer[3] == 0x3c) { |
2381 | 2524 | unsigned int lba_count, desc_count; |
2382 | 2525 | |
2383 | - sdkp->max_ws_blocks = | |
2384 | - (u32) min_not_zero(get_unaligned_be64(&buffer[36]), | |
2385 | - (u64)0xffffffff); | |
2526 | + sdkp->max_ws_blocks = (u32)get_unaligned_be64(&buffer[36]); | |
2386 | 2527 | |
2387 | 2528 | if (!sdkp->lbpme) |
2388 | 2529 | goto out; |
... | ... | @@ -2475,6 +2616,13 @@ |
2475 | 2616 | kfree(buffer); |
2476 | 2617 | } |
2477 | 2618 | |
2619 | +static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) | |
2620 | +{ | |
2621 | + if (scsi_report_opcode(sdkp->device, buffer, SD_BUF_SIZE, | |
2622 | + WRITE_SAME_16)) | |
2623 | + sdkp->ws16 = 1; | |
2624 | +} | |
2625 | + | |
2478 | 2626 | static int sd_try_extended_inquiry(struct scsi_device *sdp) |
2479 | 2627 | { |
2480 | 2628 | /* |
... | ... | @@ -2534,6 +2682,7 @@ |
2534 | 2682 | sd_read_write_protect_flag(sdkp, buffer); |
2535 | 2683 | sd_read_cache_type(sdkp, buffer); |
2536 | 2684 | sd_read_app_tag_own(sdkp, buffer); |
2685 | + sd_read_write_same(sdkp, buffer); | |
2537 | 2686 | } |
2538 | 2687 | |
2539 | 2688 | sdkp->first_scan = 0; |
... | ... | @@ -2551,6 +2700,7 @@ |
2551 | 2700 | blk_queue_flush(sdkp->disk->queue, flush); |
2552 | 2701 | |
2553 | 2702 | set_capacity(disk, sdkp->capacity); |
2703 | + sd_config_write_same(sdkp); | |
2554 | 2704 | kfree(buffer); |
2555 | 2705 | |
2556 | 2706 | out: |
drivers/scsi/sd.h
... | ... | @@ -14,6 +14,7 @@ |
14 | 14 | #define SD_TIMEOUT (30 * HZ) |
15 | 15 | #define SD_MOD_TIMEOUT (75 * HZ) |
16 | 16 | #define SD_FLUSH_TIMEOUT (60 * HZ) |
17 | +#define SD_WRITE_SAME_TIMEOUT (120 * HZ) | |
17 | 18 | |
18 | 19 | /* |
19 | 20 | * Number of allowed retries |
... | ... | @@ -39,6 +40,11 @@ |
39 | 40 | }; |
40 | 41 | |
41 | 42 | enum { |
43 | + SD_MAX_WS10_BLOCKS = 0xffff, | |
44 | + SD_MAX_WS16_BLOCKS = 0x7fffff, | |
45 | +}; | |
46 | + | |
47 | +enum { | |
42 | 48 | SD_LBP_FULL = 0, /* Full logical block provisioning */ |
43 | 49 | SD_LBP_UNMAP, /* Use UNMAP command */ |
44 | 50 | SD_LBP_WS16, /* Use WRITE SAME(16) with UNMAP bit */ |
... | ... | @@ -77,6 +83,7 @@ |
77 | 83 | unsigned lbpws : 1; |
78 | 84 | unsigned lbpws10 : 1; |
79 | 85 | unsigned lbpvpd : 1; |
86 | + unsigned ws16 : 1; | |
80 | 87 | }; |
81 | 88 | #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) |
82 | 89 |
drivers/usb/storage/scsiglue.c
... | ... | @@ -189,6 +189,9 @@ |
189 | 189 | /* Do not attempt to use REPORT SUPPORTED OPERATION CODES */ |
190 | 190 | sdev->no_report_opcodes = 1; |
191 | 191 | |
192 | + /* Do not attempt to use WRITE SAME */ | |
193 | + sdev->no_write_same = 1; | |
194 | + | |
192 | 195 | /* Some disks return the total number of blocks in response |
193 | 196 | * to READ CAPACITY rather than the highest block number. |
194 | 197 | * If this device makes that mistake, tell the sd driver. */ |
include/scsi/scsi_device.h
... | ... | @@ -136,6 +136,7 @@ |
136 | 136 | unsigned use_10_for_rw:1; /* first try 10-byte read / write */ |
137 | 137 | unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ |
138 | 138 | unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */ |
139 | + unsigned no_write_same:1; /* no WRITE SAME command */ | |
139 | 140 | unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ |
140 | 141 | unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ |
141 | 142 | unsigned skip_vpd_pages:1; /* do not read VPD pages */ |