diff --git a/src/libnvme.map b/src/libnvme.map index 6bb05b0f..eb27e59c 100644 --- a/src/libnvme.map +++ b/src/libnvme.map @@ -23,6 +23,8 @@ LIBNVME_1_6 { nvme_set_root; nvme_subsystem_get_iopolicy; nvme_subsystem_release_fds; + nvme_init_copy_range_f2; + nvme_init_copy_range_f3; }; LIBNVME_1_5 { diff --git a/src/nvme/ioctl.c b/src/nvme/ioctl.c index b5c27e32..3a068f27 100644 --- a/src/nvme/ioctl.c +++ b/src/nvme/ioctl.c @@ -1976,6 +1976,10 @@ int nvme_copy(struct nvme_copy_args *args) if (args->format == 1) data_len = args->nr * sizeof(struct nvme_copy_range_f1); + else if (args->format == 2) + data_len = args->nr * sizeof(struct nvme_copy_range_f2); + else if (args->format == 3) + data_len = args->nr * sizeof(struct nvme_copy_range_f3); else data_len = args->nr * sizeof(struct nvme_copy_range); diff --git a/src/nvme/types.h b/src/nvme/types.h index ac6d7816..c3804621 100644 --- a/src/nvme/types.h +++ b/src/nvme/types.h @@ -1506,6 +1506,14 @@ enum nvme_id_ctrl_cqes { * the Verify command. * @NVME_CTRL_ONCS_COPY: If set, then the controller supports * the copy command. + * @NVME_CTRL_ONCS_COPY_SINGLE_ATOMICITY: If set, then the write portion of a + * Copy command is performed as a single + * write command to which the same + * atomicity requirements that apply to + * a write command apply. + * @NVME_CTRL_ONCS_ALL_FAST_COPY: If set, then all copy operations for + * the Copy command are fast copy + * operations. */ enum nvme_id_ctrl_oncs { NVME_CTRL_ONCS_COMPARE = 1 << 0, @@ -1517,6 +1525,8 @@ enum nvme_id_ctrl_oncs { NVME_CTRL_ONCS_TIMESTAMP = 1 << 6, NVME_CTRL_ONCS_VERIFY = 1 << 7, NVME_CTRL_ONCS_COPY = 1 << 8, + NVME_CTRL_ONCS_COPY_SINGLE_ATOMICITY = 1 << 9, + NVME_CTRL_ONCS_ALL_FAST_COPY = 1 << 10, }; /** @@ -4802,6 +4812,66 @@ struct nvme_copy_range_f1 { __le16 elbatm; }; +/** + * enum nvme_copy_range_sopt - NVMe Copy Range Source Options + * @NVME_COPY_SOPT_FCO: NVMe Copy Source Option Fast Copy Only + */ +enum nvme_copy_range_sopt { + NVME_COPY_SOPT_FCO = 1 << 15, +}; + +/** + * struct nvme_copy_range_f2 - Copy - Source Range Entries Descriptor Format 2h + * @snsid: Source Namespace Identifier + * @rsvd4: Reserved + * @slba: Starting LBA + * @nlb: Number of Logical Blocks + * @rsvd18: Reserved + * @sopt: Source Options + * @eilbrt: Expected Initial Logical Block Reference Tag / + * Expected Logical Block Storage Tag + * @elbatm: Expected Logical Block Application Tag Mask + * @elbat: Expected Logical Block Application Tag + */ +struct nvme_copy_range_f2 { + __le32 snsid; + __u8 rsvd4[4]; + __le64 slba; + __le16 nlb; + __u8 rsvd18[4]; + __le16 sopt; + __le32 eilbrt; + __le16 elbat; + __le16 elbatm; +}; + +/** + * struct nvme_copy_range_f3 - Copy - Source Range Entries Descriptor Format 3h + * @snsid: Source Namespace Identifier + * @rsvd4: Reserved + * @slba: Starting LBA + * @nlb: Number of Logical Blocks + * @rsvd18: Reserved + * @sopt: Source Options + * @rsvd24: Reserved + * @elbt: Expected Initial Logical Block Reference Tag / + * Expected Logical Block Storage Tag + * @elbatm: Expected Logical Block Application Tag Mask + * @elbat: Expected Logical Block Application Tag + */ +struct nvme_copy_range_f3 { + __le32 snsid; + __u8 rsvd4[4]; + __le64 slba; + __le16 nlb; + __u8 rsvd18[4]; + __le16 sopt; + __u8 rsvd24[2]; + __u8 elbt[10]; + __le16 elbat; + __le16 elbatm; +}; + /** * struct nvme_registered_ctrl - Registered Controller Data Structure * @cntlid: Controller ID @@ -6254,6 +6324,21 @@ struct nvme_mi_vpd_hdr { * @NVME_SC_INVALID_PI: Invalid Protection Information * @NVME_SC_READ_ONLY: Attempted Write to Read Only Range * @NVME_SC_CMD_SIZE_LIMIT_EXCEEDED: Command Size Limit Exceeded + * @NVME_SC_INCOMPATIBLE_NS: Incompatible Namespace or Format: At + * least one source namespace and the + * destination namespace have incompatible + * formats. + * @NVME_SC_FAST_COPY_NOT_POSSIBLE: Fast Copy Not Possible: The Fast Copy + * Only (FCO) bit was set to ‘1’ in a Source + * Range entry and the controller was not + * able to use fast copy operations to copy + * the specified data. + * @NVME_SC_OVERLAPPING_IO_RANGE: Overlapping I/O Range: A source logical + * block range overlaps the destination + * logical block range. + * @NVME_SC_INSUFFICIENT_RESOURCES: Insufficient Resources: A resource + * shortage prevented the controller from + * performing the requested copy. * @NVME_SC_CONNECT_FORMAT: Incompatible Format: The NVM subsystem * does not support the record format * specified by the host. @@ -6499,6 +6584,10 @@ enum nvme_status_field { NVME_SC_INVALID_PI = 0x81, NVME_SC_READ_ONLY = 0x82, NVME_SC_CMD_SIZE_LIMIT_EXCEEDED = 0x83, + NVME_SC_INCOMPATIBLE_NS = 0x85, + NVME_SC_FAST_COPY_NOT_POSSIBLE = 0x86, + NVME_SC_OVERLAPPING_IO_RANGE = 0x87, + NVME_SC_INSUFFICIENT_RESOURCES = 0x89, /* * I/O Command Set Specific - Fabrics commands: diff --git a/src/nvme/util.c b/src/nvme/util.c index 20679685..e0db8c96 100644 --- a/src/nvme/util.c +++ b/src/nvme/util.c @@ -291,6 +291,10 @@ static const char * const nvm_status[] = { [NVME_SC_INVALID_PI] = "Invalid Protection Information: The command's Protection Information Field settings are invalid for the namespace's Protection Information format", [NVME_SC_READ_ONLY] = "Attempted Write to Read Only Range: The LBA range specified contains read-only blocks", [NVME_SC_CMD_SIZE_LIMIT_EXCEEDED] = "Command Size Limit Exceeded", + [NVME_SC_INCOMPATIBLE_NS] = "Incompatible Namespace or Format", + [NVME_SC_FAST_COPY_NOT_POSSIBLE] = "Fast Copy Not Possible", + [NVME_SC_OVERLAPPING_IO_RANGE] = "Overlapping I/O Range", + [NVME_SC_INSUFFICIENT_RESOURCES] = "Insufficient Resources", [NVME_SC_ZNS_INVALID_OP_REQUEST] = "Invalid Zone Operation Request: The operation requested is invalid", [NVME_SC_ZNS_ZRWA_RESOURCES_UNAVAILABLE] = "ZRWA Resources Unavailable: No ZRWAs are available", [NVME_SC_ZNS_BOUNDARY_ERROR] = "Zoned Boundary Error: Invalid Zone Boundary crossing", @@ -386,6 +390,15 @@ const char *nvme_status_to_string(int status, bool fabrics) return s; } +static inline void nvme_init_copy_range_elbt(__u8 *elbt, __u64 eilbrt) +{ + int j; + for (j = 0; j < 8; j++) + elbt[9 - j] = (eilbrt >> (8 * j)) & 0xff; + elbt[1] = 0; + elbt[0] = 0; +} + void nvme_init_copy_range(struct nvme_copy_range *copy, __u16 *nlbs, __u64 *slbas, __u32 *eilbrts, __u32 *elbatms, __u32 *elbats, __u16 nr) @@ -405,20 +418,53 @@ void nvme_init_copy_range_f1(struct nvme_copy_range_f1 *copy, __u16 *nlbs, __u64 *slbas, __u64 *eilbrts, __u32 *elbatms, __u32 *elbats, __u16 nr) { - int i, j; + int i; for (i = 0; i < nr; i++) { copy[i].nlb = cpu_to_le16(nlbs[i]); copy[i].slba = cpu_to_le64(slbas[i]); copy[i].elbatm = cpu_to_le16(elbatms[i]); copy[i].elbat = cpu_to_le16(elbats[i]); - for (j = 0; j < 8; j++) - copy[i].elbt[9 - j] = (eilbrts[i] >> (8 * j)) & 0xff; - copy[i].elbt[1] = 0; - copy[i].elbt[0] = 0; + nvme_init_copy_range_elbt(copy[i].elbt, eilbrts[i]); } } +void nvme_init_copy_range_f2(struct nvme_copy_range_f2 *copy, __u32 *snsids, + __u16 *nlbs, __u64 *slbas, __u16 *sopts, + __u32 *eilbrts, __u32 *elbatms, __u32 *elbats, + __u16 nr) +{ + int i; + + for (i = 0; i < nr; i++) { + copy[i].snsid = cpu_to_le32(snsids[i]); + copy[i].nlb = cpu_to_le16(nlbs[i]); + copy[i].slba = cpu_to_le64(slbas[i]); + copy[i].sopt = cpu_to_le16(sopts[i]); + copy[i].eilbrt = cpu_to_le32(eilbrts[i]); + copy[i].elbatm = cpu_to_le16(elbatms[i]); + copy[i].elbat = cpu_to_le16(elbats[i]); + } +} + +void nvme_init_copy_range_f3(struct nvme_copy_range_f3 *copy, __u32 *snsids, + __u16 *nlbs, __u64 *slbas, __u16 *sopts, + __u64 *eilbrts, __u32 *elbatms, __u32 *elbats, + __u16 nr) +{ + int i; + + for (i = 0; i < nr; i++) { + copy[i].snsid = cpu_to_le32(snsids[i]); + copy[i].nlb = cpu_to_le16(nlbs[i]); + copy[i].slba = cpu_to_le64(slbas[i]); + copy[i].sopt = cpu_to_le16(sopts[i]); + copy[i].elbatm = cpu_to_le16(elbatms[i]); + copy[i].elbat = cpu_to_le16(elbats[i]); + nvme_init_copy_range_elbt(copy[i].elbt, eilbrts[i]); + } +} + void nvme_init_dsm_range(struct nvme_dsm_range *dsm, __u32 *ctx_attrs, __u32 *llbas, __u64 *slbas, __u16 nr_ranges) { diff --git a/src/nvme/util.h b/src/nvme/util.h index efdf9757..16d5b9ca 100644 --- a/src/nvme/util.h +++ b/src/nvme/util.h @@ -150,6 +150,40 @@ void nvme_init_copy_range_f1(struct nvme_copy_range_f1 *copy, __u16 *nlbs, __u64 *slbas, __u64 *eilbrts, __u32 *elbatms, __u32 *elbats, __u16 nr); +/** + * nvme_init_copy_range_f2() - Constructs a copy range f2 structure + * @copy: Copy range array + * @snsids: Source namespace identifier + * @nlbs: Number of logical blocks + * @slbas: Starting LBA + * @sopts: Source options + * @eilbrts: Expected initial logical block reference tag + * @elbatms: Expected logical block application tag mask + * @elbats: Expected logical block application tag + * @nr: Number of descriptors to construct + */ +void nvme_init_copy_range_f2(struct nvme_copy_range_f2 *copy, __u32 *snsids, + __u16 *nlbs, __u64 *slbas, __u16 *sopts, + __u32 *eilbrts, __u32 *elbatms, __u32 *elbats, + __u16 nr); + +/** + * nvme_init_copy_range_f3() - Constructs a copy range f3 structure + * @copy: Copy range array + * @snsids: Source namespace identifier + * @nlbs: Number of logical blocks + * @slbas: Starting LBA + * @sopts: Source options + * @eilbrts: Expected initial logical block reference tag + * @elbatms: Expected logical block application tag mask + * @elbats: Expected logical block application tag + * @nr: Number of descriptors to construct + */ +void nvme_init_copy_range_f3(struct nvme_copy_range_f3 *copy, __u32 *snsids, + __u16 *nlbs, __u64 *slbas, __u16 *sopts, + __u64 *eilbrts, __u32 *elbatms, __u32 *elbats, + __u16 nr); + /** * nvme_get_feature_length() - Retreive the command payload length for a * specific feature identifier