]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
types: add cross-namespace copy formats, status codes, ONCS bits
authorJoy Gu <jgu@purestorage.com>
Wed, 25 Oct 2023 20:47:42 +0000 (13:47 -0700)
committerDaniel Wagner <dwagner@suse.de>
Thu, 2 Nov 2023 12:45:42 +0000 (13:45 +0100)
Add support for NVMe TP4130 ("Cross-Namespace Copy"):
- Add Copy Descriptor Formats 2h and 3h
- Add new status codes for Copy: Incompatible Namespace or Format, Fast
  Copy Not Possible, Overlapping I/O Range, and Insufficient Resources
- Add two new ONCS bits NVMCSA and NVMAFC
- Add Copy Descriptor Formats Enable (CDFE) to Host Behavior Support
  Data Structure

[dwagner: whitespace cleanups
          moved new functions to 1.7 linker section]
Signed-off-by: Daniel Wagner <dwagner@suse.de>
src/libnvme.map
src/nvme/ioctl.c
src/nvme/types.h
src/nvme/util.c
src/nvme/util.h

index 6bb05b0f838c67a87db1bb0c7623e3de5db8a7d4..7130894009b7d40ac6fecd07c64f2e7401a78ad3 100644 (file)
@@ -1,4 +1,10 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
+LIBNVME_1_7 {
+       global:
+               nvme_init_copy_range_f2;
+               nvme_init_copy_range_f3;
+};
+
 LIBNVME_1_6 {
        global:
                nvme_ctrl_config_match;
index b5c27e32fb27a08a6faea204ea90e6ef3705f3a4..3a068f270589a68dde94be69bc4458d1f11f2c18 100644 (file)
@@ -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);
 
index ac6d781633c14eac3d9bb0ee0c1de49b4576476d..e8dbea3774411810a61f1ebe27f993824b098e6b 100644 (file)
@@ -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,
 };
 
 /**
@@ -4734,10 +4744,14 @@ struct nvme_plm_config {
  * struct nvme_feat_host_behavior - Host Behavior Support - Data Structure
  * @acre:      Advanced Command Retry Enable
  * @rsvd1:     Reserved
+ * @cdfe:       Copy Descriptor Formats Enable
+ * @rsvd6:     Reserved
  */
 struct nvme_feat_host_behavior {
        __u8 acre;
-       __u8 rsvd1[511];
+        __u8 rsvd1[3];
+        __u16 cdfe;
+       __u8 rsvd6[506];
 };
 
 /**
@@ -4802,6 +4816,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 +6328,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 +6588,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:
index 20679685bc8b9794911b08774dc8817a9b832232..4bc66bc7d0c8b51084e4465a37124389cb109acb 100644 (file)
@@ -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,16 @@ 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 i;
+
+       for (i = 0; i < 8; i++)
+               elbt[9 - i] = (eilbrt >> (8 * i)) & 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 +419,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)
 {
index efdf9757b978c12a325aba56b249eeaac1db3391..16d5b9cad98d200f9ed72799256c402eb7896fb5 100644 (file)
@@ -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