|
6 | 6 |
|
7 | 7 | #include <linux/async.h> |
8 | 8 | #include <linux/blkdev.h> |
| 9 | +#include <linux/blk-copy.h> |
9 | 10 | #include <linux/blk-mq.h> |
10 | 11 | #include <linux/blk-integrity.h> |
11 | 12 | #include <linux/compat.h> |
@@ -821,6 +822,87 @@ static inline void nvme_setup_flush(struct nvme_ns *ns, |
821 | 822 | cmnd->common.nsid = cpu_to_le32(ns->head->ns_id); |
822 | 823 | } |
823 | 824 |
|
| 825 | +/* |
| 826 | + * Translate REQ_OP_COPY_SRC and REQ_OP_COPY_DST bios into an NVMe Copy command. |
| 827 | + * The NVMe copy command supports multiple source LBA ranges, a single |
| 828 | + * destination LBA range, and also supports copying across NVMe namespaces. This |
| 829 | + * implementation supports all these features except copying across NVMe |
| 830 | + * namespaces. |
| 831 | + */ |
| 832 | +static inline blk_status_t nvme_setup_copy_offload(struct nvme_ns *ns, |
| 833 | + struct request *req, |
| 834 | + struct nvme_command *cmnd) |
| 835 | +{ |
| 836 | + const u32 nr_range = blk_copy_bio_count(req, REQ_OP_COPY_SRC); |
| 837 | + struct nvme_ns *src_ns, *dst_ns; |
| 838 | + struct bio *src_bio = NULL, *dst_bio; |
| 839 | + struct nvme_copy_range *range; |
| 840 | + u16 control = 0; |
| 841 | + u64 dlba; |
| 842 | + |
| 843 | + dst_bio = blk_first_copy_bio(req, REQ_OP_COPY_DST); |
| 844 | + |
| 845 | + if (WARN_ON_ONCE(!dst_bio)) |
| 846 | + return BLK_STS_IOERR; |
| 847 | + |
| 848 | + /* TO DO: derive dst_ns from dst_bio. */ |
| 849 | + dst_ns = ns; |
| 850 | + dlba = nvme_sect_to_lba(dst_ns->head, dst_bio->bi_iter.bi_sector); |
| 851 | + |
| 852 | + if (req->cmd_flags & REQ_FUA) |
| 853 | + control |= NVME_RW_FUA; |
| 854 | + |
| 855 | + if (req->cmd_flags & REQ_FAILFAST_DEV) |
| 856 | + control |= NVME_RW_LR; |
| 857 | + |
| 858 | + *cmnd = (typeof(*cmnd)){ |
| 859 | + .copy = { |
| 860 | + .opcode = nvme_cmd_copy, |
| 861 | + .nsid = cpu_to_le32(dst_ns->head->ns_id), |
| 862 | + .control = cpu_to_le16(control), |
| 863 | + .sdlba = cpu_to_le64(dlba), |
| 864 | + .desfmt_prinfor = 2, /* DESFMT=2 */ |
| 865 | + .nr_range = nr_range - 1, /* 0's based */ |
| 866 | + } |
| 867 | + }; |
| 868 | + |
| 869 | + range = kmalloc_array(nr_range, sizeof(*range), |
| 870 | + GFP_ATOMIC | __GFP_ZERO | __GFP_NOWARN); |
| 871 | + if (!range) |
| 872 | + return BLK_STS_RESOURCE; |
| 873 | + |
| 874 | + for (unsigned int i = 0; i < nr_range; i++) { |
| 875 | + u64 slba; |
| 876 | + u32 nslb; |
| 877 | + |
| 878 | + if (!src_bio) |
| 879 | + src_bio = blk_first_copy_bio(req, REQ_OP_COPY_SRC); |
| 880 | + else |
| 881 | + src_bio = blk_next_copy_bio(src_bio); |
| 882 | + if (WARN_ON_ONCE(!src_bio)) |
| 883 | + goto free_range; |
| 884 | + /* TO DO: derive src_ns from src_bio. */ |
| 885 | + src_ns = ns; |
| 886 | + slba = nvme_sect_to_lba(src_ns->head, |
| 887 | + src_bio->bi_iter.bi_sector); |
| 888 | + nslb = src_bio->bi_iter.bi_size >> src_ns->head->lba_shift; |
| 889 | + range[i].nsid = cpu_to_le32(src_ns->head->ns_id); /* requires DESFMT=2 */ |
| 890 | + range[i].slba = cpu_to_le64(slba); |
| 891 | + range[i].nlb = cpu_to_le16(nslb - 1); |
| 892 | + } |
| 893 | + |
| 894 | + req->special_vec.bv_page = virt_to_page(range); |
| 895 | + req->special_vec.bv_offset = offset_in_page(range); |
| 896 | + req->special_vec.bv_len = sizeof(*range) * nr_range; |
| 897 | + req->rq_flags |= RQF_SPECIAL_PAYLOAD; |
| 898 | + |
| 899 | + return BLK_STS_OK; |
| 900 | + |
| 901 | +free_range: |
| 902 | + kfree(range); |
| 903 | + return BLK_STS_IOERR; |
| 904 | +} |
| 905 | + |
824 | 906 | static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req, |
825 | 907 | struct nvme_command *cmnd) |
826 | 908 | { |
@@ -1122,6 +1204,10 @@ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req) |
1122 | 1204 | case REQ_OP_ZONE_APPEND: |
1123 | 1205 | ret = nvme_setup_rw(ns, req, cmd, nvme_cmd_zone_append); |
1124 | 1206 | break; |
| 1207 | + case REQ_OP_COPY_DST: |
| 1208 | + case REQ_OP_COPY_SRC: |
| 1209 | + ret = nvme_setup_copy_offload(ns, req, cmd); |
| 1210 | + break; |
1125 | 1211 | default: |
1126 | 1212 | WARN_ON_ONCE(1); |
1127 | 1213 | return BLK_STS_IOERR; |
@@ -1884,6 +1970,21 @@ static bool nvme_init_integrity(struct nvme_ns_head *head, |
1884 | 1970 | return true; |
1885 | 1971 | } |
1886 | 1972 |
|
| 1973 | +static void nvme_config_copy(struct nvme_ns *ns, struct nvme_id_ns *id, |
| 1974 | + struct queue_limits *lim) |
| 1975 | +{ |
| 1976 | + struct nvme_ctrl *ctrl = ns->ctrl; |
| 1977 | + |
| 1978 | + if (!(ctrl->oncs & NVME_CTRL_ONCS_COPY)) { |
| 1979 | + lim->max_copy_hw_sectors = 0; |
| 1980 | + return; |
| 1981 | + } |
| 1982 | + lim->max_copy_hw_sectors = nvme_lba_to_sect(ns->head, |
| 1983 | + le16_to_cpu(id->mssrl)); |
| 1984 | + lim->max_copy_src_segments = 256; |
| 1985 | + lim->max_copy_dst_segments = 1; |
| 1986 | +} |
| 1987 | + |
1887 | 1988 | static bool nvme_ns_ids_equal(struct nvme_ns_ids *a, struct nvme_ns_ids *b) |
1888 | 1989 | { |
1889 | 1990 | return uuid_equal(&a->uuid, &b->uuid) && |
@@ -2416,6 +2517,7 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns, |
2416 | 2517 | if (!nvme_update_disk_info(ns, id, nvm, &lim)) |
2417 | 2518 | capacity = 0; |
2418 | 2519 |
|
| 2520 | + nvme_config_copy(ns, id, &lim); |
2419 | 2521 | if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && |
2420 | 2522 | ns->head->ids.csi == NVME_CSI_ZNS) |
2421 | 2523 | nvme_update_zone_info(ns, &lim, &zi); |
@@ -2542,6 +2644,9 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info) |
2542 | 2644 | lim.physical_block_size = ns_lim->physical_block_size; |
2543 | 2645 | lim.io_min = ns_lim->io_min; |
2544 | 2646 | lim.io_opt = ns_lim->io_opt; |
| 2647 | + lim.max_copy_hw_sectors = UINT_MAX; |
| 2648 | + lim.max_copy_src_segments = U16_MAX; |
| 2649 | + lim.max_copy_dst_segments = U16_MAX; |
2545 | 2650 | queue_limits_stack_bdev(&lim, ns->disk->part0, 0, |
2546 | 2651 | ns->head->disk->disk_name); |
2547 | 2652 | if (unsupported) |
@@ -5368,6 +5473,7 @@ static inline void _nvme_check_size(void) |
5368 | 5473 | BUILD_BUG_ON(sizeof(struct nvme_download_firmware) != 64); |
5369 | 5474 | BUILD_BUG_ON(sizeof(struct nvme_format_cmd) != 64); |
5370 | 5475 | BUILD_BUG_ON(sizeof(struct nvme_dsm_cmd) != 64); |
| 5476 | + BUILD_BUG_ON(sizeof(struct nvme_copy_command) != 64); |
5371 | 5477 | BUILD_BUG_ON(sizeof(struct nvme_write_zeroes_cmd) != 64); |
5372 | 5478 | BUILD_BUG_ON(sizeof(struct nvme_abort_cmd) != 64); |
5373 | 5479 | BUILD_BUG_ON(sizeof(struct nvme_get_log_page_command) != 64); |
|
0 commit comments