libmultipath: nvme: update to nvme-cli v1.9
authorMartin Wilck <mwilck@suse.com>
Sat, 12 Oct 2019 21:28:58 +0000 (21:28 +0000)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Mon, 2 Mar 2020 10:18:14 +0000 (11:18 +0100)
Update nvme code to nvme-cli v1.9 (977e7d4, Thu Aug 15 2019).

Signed-off-by: Martin Wilck <mwilck@suse.com>
libmultipath/nvme/linux/nvme.h
libmultipath/nvme/nvme-ioctl.c
libmultipath/nvme/nvme-ioctl.h
libmultipath/nvme/nvme.h

index 68000eb..a697554 100644 (file)
@@ -124,6 +124,9 @@ enum {
        NVME_REG_BPINFO = 0x0040,       /* Boot Partition Information */
        NVME_REG_BPRSEL = 0x0044,       /* Boot Partition Read Select */
        NVME_REG_BPMBL  = 0x0048,       /* Boot Partition Memory Buffer Location */
+       NVME_REG_PMRCAP = 0x0e00,       /* Persistent Memory Capabilities */
+       NVME_REG_PMRCTL = 0x0e04,       /* Persistent Memory Region Control */
+       NVME_REG_PMRSTS = 0x0e08,       /* Persistent Memory Region Status */
        NVME_REG_DBS    = 0x1000,       /* SQ 0 Tail Doorbell */
 };
 
@@ -221,7 +224,11 @@ struct nvme_id_ctrl {
        __le32                  oaes;
        __le32                  ctratt;
        __le16                  rrls;
-       __u8                    rsvd102[154];
+       __u8                    rsvd102[26];
+       __le16                  crdt1;
+       __le16                  crdt2;
+       __le16                  crdt3;
+       __u8                    rsvd134[122];
        __le16                  oacs;
        __u8                    acl;
        __u8                    aerl;
@@ -302,6 +309,8 @@ enum {
        NVME_CTRL_CTRATT_READ_RECV_LVLS         = 1 << 3,
        NVME_CTRL_CTRATT_ENDURANCE_GROUPS       = 1 << 4,
        NVME_CTRL_CTRATT_PREDICTABLE_LAT        = 1 << 5,
+       NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY  = 1 << 7,
+       NVME_CTRL_CTRATT_UUID_LIST              = 1 << 9,
 };
 
 struct nvme_lbaf {
@@ -332,7 +341,12 @@ struct nvme_id_ns {
        __le16                  nabspf;
        __le16                  noiob;
        __u8                    nvmcap[16];
-       __u8                    rsvd64[28];
+       __le16                  npwg;
+       __le16                  npwa;
+       __le16                  npdg;
+       __le16                  npda;
+       __le16                  nows;
+       __u8                    rsvd74[18];
        __le32                  anagrpid;
        __u8                    rsvd96[3];
        __u8                    nsattr;
@@ -355,6 +369,9 @@ enum {
        NVME_ID_CNS_NS_PRESENT          = 0x11,
        NVME_ID_CNS_CTRL_NS_LIST        = 0x12,
        NVME_ID_CNS_CTRL_LIST           = 0x13,
+       NVME_ID_CNS_SCNDRY_CTRL_LIST    = 0x15,
+       NVME_ID_CNS_NS_GRANULARITY      = 0x16,
+       NVME_ID_CNS_UUID_LIST           = 0x17,
 };
 
 enum {
@@ -425,26 +442,56 @@ struct nvme_id_nvmset {
        struct nvme_nvmset_attr_entry   ent[NVME_MAX_NVMSET];
 };
 
-/* Derived from 1.3a Figure 101: Get Log Page – Telemetry Host
- * -Initiated Log (Log Identifier 07h)
+struct nvme_id_ns_granularity_list_entry {
+       __le64                  namespace_size_granularity;
+       __le64                  namespace_capacity_granularity;
+};
+
+struct nvme_id_ns_granularity_list {
+       __le32                  attributes;
+       __u8                    num_descriptors;
+       __u8                    rsvd[27];
+       struct nvme_id_ns_granularity_list_entry entry[16];
+};
+
+#define NVME_MAX_UUID_ENTRIES  128
+struct nvme_id_uuid_list_entry {
+       __u8                    header;
+       __u8                    rsvd1[15];
+       __u8                    uuid[16];
+};
+
+struct nvme_id_uuid_list {
+       struct nvme_id_uuid_list_entry  entry[NVME_MAX_UUID_ENTRIES];
+};
+
+/**
+ * struct nvme_telemetry_log_page_hdr - structure for telemetry log page
+ * @lpi: Log page identifier
+ * @iee_oui: IEEE OUI Identifier
+ * @dalb1: Data area 1 last block
+ * @dalb2: Data area 2 last block
+ * @dalb3: Data area 3 last block
+ * @ctrlavail: Controller initiated data available
+ * @ctrldgn: Controller initiated telemetry Data Generation Number
+ * @rsnident: Reason Identifier
+ * @telemetry_dataarea: Contains telemetry data block
+ *
+ * This structure can be used for both telemetry host-initiated log page
+ * and controller-initiated log page.
  */
 struct nvme_telemetry_log_page_hdr {
-       __u8    lpi; /* Log page identifier */
-       __u8    rsvd[4];
-       __u8    iee_oui[3];
-       __u16   dalb1; /* Data area 1 last block */
-       __u16   dalb2; /* Data area 2 last block */
-       __u16   dalb3; /* Data area 3 last block */
-       __u8    rsvd1[368]; /* TODO verify */
-       __u8    ctrlavail; /* Controller initiated data avail?*/
-       __u8    ctrldgn; /* Controller initiated telemetry Data Gen # */
-       __u8    rsnident[128];
-       /* We'll have to double fetch so we can get the header,
-        * parse dalb1->3 determine how much size we need for the
-        * log then alloc below. Or just do a secondary non-struct
-        * allocation.
-        */
-       __u8    telemetry_dataarea[0];
+       __u8    lpi;
+       __u8    rsvd[4];
+       __u8    iee_oui[3];
+       __le16  dalb1;
+       __le16  dalb2;
+       __le16  dalb3;
+       __u8    rsvd1[368];
+       __u8    ctrlavail;
+       __u8    ctrldgn;
+       __u8    rsnident[128];
+       __u8    telemetry_dataarea[0];
 };
 
 struct nvme_endurance_group_log {
@@ -513,6 +560,21 @@ struct nvme_fw_slot_info_log {
        __u8                    rsvd64[448];
 };
 
+struct nvme_lba_status_desc {
+       __u64 dslba;
+       __u32 nlb;
+       __u8 rsvd_12;
+       __u8 status;
+       __u8 rsvd_15_14[2];
+};
+
+struct nvme_lba_status {
+       __u32 nlsd;
+       __u8 cmpc;
+       __u8 rsvd_7_5[3];
+       struct nvme_lba_status_desc descs[0];
+};
+
 /* NVMe Namespace Write Protect State */
 enum {
        NVME_NS_NO_WRITE_PROTECT = 0,
@@ -534,6 +596,7 @@ enum {
        NVME_CMD_EFFECTS_NIC            = 1 << 3,
        NVME_CMD_EFFECTS_CCC            = 1 << 4,
        NVME_CMD_EFFECTS_CSE_MASK       = 3 << 16,
+       NVME_CMD_EFFECTS_UUID_SEL       = 1 << 19,
 };
 
 struct nvme_effects_log {
@@ -581,9 +644,6 @@ enum {
        NVME_AER_SMART                  = 1,
        NVME_AER_CSS                    = 6,
        NVME_AER_VS                     = 7,
-       NVME_AER_NOTICE_NS_CHANGED      = 0x0002,
-       NVME_AER_NOTICE_ANA             = 0x0003,
-       NVME_AER_NOTICE_FW_ACT_STARTING = 0x0102,
 };
 
 struct nvme_lba_range_type {
@@ -606,12 +666,13 @@ enum {
        NVME_LBART_ATTRIB_HIDE  = 1 << 1,
 };
 
+/* Predictable Latency Mode - Deterministic Threshold Configuration Data */
 struct nvme_plm_config {
-       __u16   enable_event;
+       __le16  enable_event;
        __u8    rsvd2[30];
-       __u64   dtwin_reads_thresh;
-       __u64   dtwin_writes_thresh;
-       __u64   dtwin_time_thresh;
+       __le64  dtwin_reads_thresh;
+       __le64  dtwin_writes_thresh;
+       __le64  dtwin_time_thresh;
        __u8    rsvd56[456];
 };
 
@@ -665,6 +726,7 @@ enum nvme_opcode {
        nvme_cmd_compare        = 0x05,
        nvme_cmd_write_zeroes   = 0x08,
        nvme_cmd_dsm            = 0x09,
+       nvme_cmd_verify         = 0x0c,
        nvme_cmd_resv_register  = 0x0d,
        nvme_cmd_resv_report    = 0x0e,
        nvme_cmd_resv_acquire   = 0x11,
@@ -892,6 +954,7 @@ enum nvme_admin_opcode {
        nvme_admin_security_send        = 0x81,
        nvme_admin_security_recv        = 0x82,
        nvme_admin_sanitize_nvm         = 0x84,
+       nvme_admin_get_lba_status       = 0x86,
 };
 
 enum {
@@ -921,6 +984,8 @@ enum {
        NVME_FEAT_RRL           = 0x12,
        NVME_FEAT_PLM_CONFIG    = 0x13,
        NVME_FEAT_PLM_WINDOW    = 0x14,
+       NVME_FEAT_HOST_BEHAVIOR = 0x16,
+       NVME_FEAT_SANITIZE      = 0x17,
        NVME_FEAT_SW_PROGRESS   = 0x80,
        NVME_FEAT_HOST_ID       = 0x81,
        NVME_FEAT_RESV_MASK     = 0x82,
@@ -972,6 +1037,7 @@ enum {
        NVME_SANITIZE_LOG_COMPLETED_SUCCESS     = 0x0001,
        NVME_SANITIZE_LOG_IN_PROGESS            = 0x0002,
        NVME_SANITIZE_LOG_COMPLETED_FAILED      = 0x0003,
+       NVME_SANITIZE_LOG_ND_COMPLETED_SUCCESS  = 0x0004,
 };
 
 enum {
@@ -1131,6 +1197,9 @@ struct nvme_sanitize_log_page {
        __le32                  est_ovrwrt_time;
        __le32                  est_blk_erase_time;
        __le32                  est_crypto_erase_time;
+       __le32                  est_ovrwrt_time_with_no_deallocate;
+       __le32                  est_blk_erase_time_with_no_deallocate;
+       __le32                  est_crypto_erase_time_with_no_deallocate;
 };
 
 /*
@@ -1314,6 +1383,12 @@ static inline bool nvme_is_write(struct nvme_command *cmd)
        return cmd->common.opcode & 1;
 }
 
+enum {
+       NVME_SCT_GENERIC                = 0x0,
+       NVME_SCT_CMD_SPECIFIC           = 0x1,
+       NVME_SCT_MEDIA                  = 0x2,
+};
+
 enum {
        /*
         * Generic Command Status:
@@ -1344,6 +1419,7 @@ enum {
        NVME_SC_SANITIZE_IN_PROGRESS    = 0x1D,
 
        NVME_SC_NS_WRITE_PROTECTED      = 0x20,
+       NVME_SC_CMD_INTERRUPTED         = 0x21,
 
        NVME_SC_LBA_RANGE               = 0x80,
        NVME_SC_CAP_EXCEEDED            = 0x81,
@@ -1372,9 +1448,9 @@ enum {
        NVME_SC_FW_NEEDS_SUBSYS_RESET   = 0x110,
        NVME_SC_FW_NEEDS_RESET          = 0x111,
        NVME_SC_FW_NEEDS_MAX_TIME       = 0x112,
-       NVME_SC_FW_ACIVATE_PROHIBITED   = 0x113,
+       NVME_SC_FW_ACTIVATE_PROHIBITED  = 0x113,
        NVME_SC_OVERLAPPING_RANGE       = 0x114,
-       NVME_SC_NS_INSUFFICENT_CAP      = 0x115,
+       NVME_SC_NS_INSUFFICIENT_CAP     = 0x115,
        NVME_SC_NS_ID_UNAVAILABLE       = 0x116,
        NVME_SC_NS_ALREADY_ATTACHED     = 0x118,
        NVME_SC_NS_IS_PRIVATE           = 0x119,
@@ -1382,6 +1458,7 @@ enum {
        NVME_SC_THIN_PROV_NOT_SUPP      = 0x11b,
        NVME_SC_CTRL_LIST_INVALID       = 0x11c,
        NVME_SC_BP_WRITE_PROHIBITED     = 0x11e,
+       NVME_SC_PMR_SAN_PROHIBITED      = 0x123,
 
        /*
         * I/O Command Set Specific - NVM commands:
@@ -1422,6 +1499,7 @@ enum {
        NVME_SC_ANA_INACCESSIBLE        = 0x302,
        NVME_SC_ANA_TRANSITION          = 0x303,
 
+       NVME_SC_CRD                     = 0x1800,
        NVME_SC_DNR                     = 0x4000,
 };
 
index 70a16ce..6959976 100644 (file)
@@ -1,3 +1,4 @@
+#include <assert.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <string.h>
@@ -177,6 +178,22 @@ int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
                       reftag, apptag, appmask, data, metadata);
 }
 
+int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks,
+               __u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
+{
+       struct nvme_passthru_cmd cmd = {
+               .opcode         = nvme_cmd_verify,
+               .nsid           = nsid,
+               .cdw10          = slba & 0xffffffff,
+               .cdw11          = slba >> 32,
+               .cdw12          = nblocks | (control << 16),
+               .cdw14          = reftag,
+               .cdw15          = apptag | (appmask << 16),
+       };
+
+       return nvme_submit_io_passthru(fd, &cmd);
+}
+
 int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
                     __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10,
                     __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14,
@@ -370,6 +387,11 @@ int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
        return nvme_identify(fd, nsid, (cntid << 16) | cns, data);
 }
 
+int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
+{
+       return nvme_identify(fd, nsid, (cntid << 16) | NVME_ID_CNS_SCNDRY_CTRL_LIST, data);
+}
+
 int nvme_identify_ns_descs(int fd, __u32 nsid, void *data)
 {
 
@@ -381,8 +403,18 @@ int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data)
        return nvme_identify13(fd, 0, NVME_ID_CNS_NVMSET_LIST, nvmset_id, data);
 }
 
-int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
-                 __u16 lsi, bool rae, __u32 data_len, void *data)
+int nvme_identify_ns_granularity(int fd, void *data)
+{
+       return nvme_identify13(fd, 0, NVME_ID_CNS_NS_GRANULARITY, 0, data);
+}
+
+int nvme_identify_uuid(int fd, void *data)
+{
+       return nvme_identify(fd, 0, NVME_ID_CNS_UUID_LIST, data);
+}
+
+int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
+                 __u16 lsi, bool rae, __u8 uuid_ix, __u32 data_len, void *data)
 {
        struct nvme_admin_cmd cmd = {
                .opcode         = nvme_admin_get_log_page,
@@ -400,6 +432,7 @@ int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
        cmd.cdw11 = numdu | (lsi << 16);
        cmd.cdw12 = lpo;
        cmd.cdw13 = (lpo >> 32);
+       cmd.cdw14 = uuid_ix;
 
        return nvme_submit_admin_passthru(fd, &cmd);
 
@@ -498,7 +531,7 @@ int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log)
 
 int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log)
 {
-       return nvme_get_log(fd, 0, NVME_LOG_CMD_EFFECTS, false,
+       return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_CMD_EFFECTS, false,
                        sizeof(*effects_log), effects_log);
 }
 
@@ -542,77 +575,61 @@ int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, __u32 cdw12,
                            cdw12, data_len, data, result);
 }
 
-static int nvme_property(int fd, __u8 fctype, __le32 off, __le64 *value, __u8 attrib)
-{
-       int err;
-       struct nvme_admin_cmd cmd = {
-               .opcode         = nvme_fabrics_command,
-               .cdw10          = attrib,
-               .cdw11          = off,
-       };
-
-       if (!value) {
-               errno = EINVAL;
-               return -errno;
-       }
-
-       if (fctype == nvme_fabrics_type_property_get){
-               cmd.nsid = nvme_fabrics_type_property_get;
-       } else if(fctype == nvme_fabrics_type_property_set) {
-               cmd.nsid = nvme_fabrics_type_property_set;
-               cmd.cdw12 = *value;
-       } else {
-               errno = EINVAL;
-               return -errno;
-       }
 
-       err = nvme_submit_admin_passthru(fd, &cmd);
-       if (!err && fctype == nvme_fabrics_type_property_get)
-               *value = cpu_to_le64(cmd.result);
-       return err;
+/*
+ * Perform the opposite operation of the byte-swapping code at the start of the
+ * kernel function nvme_user_cmd().
+ */
+static void nvme_to_passthru_cmd(struct nvme_passthru_cmd *pcmd,
+                                const struct nvme_command *ncmd)
+{
+       assert(sizeof(*ncmd) < sizeof(*pcmd));
+       memset(pcmd, 0, sizeof(*pcmd));
+       pcmd->opcode = ncmd->common.opcode;
+       pcmd->flags = ncmd->common.flags;
+       pcmd->rsvd1 = ncmd->common.command_id;
+       pcmd->nsid = le32_to_cpu(ncmd->common.nsid);
+       pcmd->cdw2 = le32_to_cpu(ncmd->common.cdw2[0]);
+       pcmd->cdw3 = le32_to_cpu(ncmd->common.cdw2[1]);
+       /* Skip metadata and addr */
+       pcmd->cdw10 = le32_to_cpu(ncmd->common.cdw10[0]);
+       pcmd->cdw11 = le32_to_cpu(ncmd->common.cdw10[1]);
+       pcmd->cdw12 = le32_to_cpu(ncmd->common.cdw10[2]);
+       pcmd->cdw13 = le32_to_cpu(ncmd->common.cdw10[3]);
+       pcmd->cdw14 = le32_to_cpu(ncmd->common.cdw10[4]);
+       pcmd->cdw15 = le32_to_cpu(ncmd->common.cdw10[5]);
 }
 
-static int get_property_helper(int fd, int offset, void *value, int *advance)
+int nvme_get_property(int fd, int offset, uint64_t *value)
 {
-       __le64 value64;
-       int err = -EINVAL;
-
-       switch (offset) {
-       case NVME_REG_CAP:
-       case NVME_REG_ASQ:
-       case NVME_REG_ACQ:
-               *advance = 8;
-               break;
-       default:
-               *advance = 4;
-       }
-
-       if (!value)
-               return err;
-
-       err = nvme_property(fd, nvme_fabrics_type_property_get,
-                       cpu_to_le32(offset), &value64, (*advance == 8));
+       struct nvme_passthru_cmd pcmd;
+       struct nvmf_property_get_command pg = {
+               .opcode = nvme_fabrics_command,
+               .fctype = nvme_fabrics_type_property_get,
+               .offset = cpu_to_le32(offset),
+               .attrib = is_64bit_reg(offset),
+       };
+       struct nvme_command gcmd;
+       int err;
 
+       gcmd.prop_get = pg;
+       nvme_to_passthru_cmd(&pcmd, &gcmd);
+       err = nvme_submit_admin_passthru(fd, &pcmd);
        if (!err) {
-               if (*advance == 8)
-                       *((uint64_t *)value) = le64_to_cpu(value64);
-               else
-                       *((uint32_t *)value) = le32_to_cpu(value64);
+               /*
+                * nvme_submit_admin_passthru() stores the lower 32 bits
+                * of the property value in pcmd.result using CPU endianness.
+                */
+               *value = pcmd.result;
        }
-
        return err;
 }
 
-int nvme_get_property(int fd, int offset, uint64_t *value)
-{
-       int advance;
-       return get_property_helper(fd, offset, value, &advance);
-}
-
 int nvme_get_properties(int fd, void **pbar)
 {
-       int offset, advance;
-       int err, ret = -EINVAL;
+       int offset;
+       uint64_t value;
+       int err;
        int size = getpagesize();
 
        *pbar = malloc(size);
@@ -622,33 +639,42 @@ int nvme_get_properties(int fd, void **pbar)
        }
 
        memset(*pbar, 0xff, size);
-       for (offset = NVME_REG_CAP; offset <= NVME_REG_CMBSZ; offset += advance) {
-               err = get_property_helper(fd, offset, *pbar + offset, &advance);
-               if (!err)
-                       ret = 0;
+       for (offset = NVME_REG_CAP; offset <= NVME_REG_CMBSZ;) {
+               err = nvme_get_property(fd, offset, &value);
+               if (err > 0 && (err & 0xff) == NVME_SC_INVALID_FIELD) {
+                       err = 0;
+                       value = -1;
+               } else if (err) {
+                       free(*pbar);
+                       break;
+               }
+               if (is_64bit_reg(offset)) {
+                       *(uint64_t *)(*pbar + offset) = value;
+                       offset += 8;
+               } else {
+                       *(uint32_t *)(*pbar + offset) = value;
+                       offset += 4;
+               }
        }
 
-       return ret;
+       return err;
 }
 
-int nvme_set_property(int fd, int offset, int value)
+int nvme_set_property(int fd, int offset, uint64_t value)
 {
-       __le64 val = cpu_to_le64(value);
-       __le32 off = cpu_to_le32(offset);
-       bool is64bit;
-
-       switch (off) {
-       case NVME_REG_CAP:
-       case NVME_REG_ASQ:
-       case NVME_REG_ACQ:
-               is64bit = true;
-               break;
-       default:
-               is64bit = false;
-       }
+       struct nvmf_property_set_command ps = {
+               .opcode = nvme_fabrics_command,
+               .fctype = nvme_fabrics_type_property_set,
+               .offset = cpu_to_le32(offset),
+               .value = cpu_to_le64(value),
+               .attrib = is_64bit_reg(offset),
+       };
+       struct nvme_command scmd;
+       struct nvme_passthru_cmd pcmd;
 
-       return nvme_property(fd, nvme_fabrics_type_property_set,
-                       off, &val, is64bit ? 1: 0);
+       scmd.prop_set = ps;
+       nvme_to_passthru_cmd(&pcmd, &scmd);
+       return nvme_submit_admin_passthru(fd, &pcmd);
 }
 
 int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, __u32 cdw11,
@@ -675,7 +701,7 @@ int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
 }
 
 int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas,
-                  __u8 dps, __u8 nmic, __u32 *result)
+                  __u8 dps, __u8 nmic, __u32 timeout, __u32 *result)
 {
        struct nvme_id_ns ns = {
                .nsze           = cpu_to_le64(nsze),
@@ -689,6 +715,7 @@ int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas,
                .addr           = (__u64)(uintptr_t) ((void *)&ns),
                .cdw10          = 0,
                .data_len       = 0x1000,
+               .timeout_ms     = timeout,
        };
        int err;
 
@@ -698,12 +725,13 @@ int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas,
        return err;
 }
 
-int nvme_ns_delete(int fd, __u32 nsid)
+int nvme_ns_delete(int fd, __u32 nsid, __u32 timeout)
 {
        struct nvme_admin_cmd cmd = {
                .opcode         = nvme_admin_ns_mgmt,
                .nsid           = nsid,
                .cdw10          = 1,
+               .timeout_ms     = timeout,
        };
 
        return nvme_submit_admin_passthru(fd, &cmd);
@@ -803,6 +831,21 @@ int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
        return err;
 }
 
+int nvme_get_lba_status(int fd, __u64 slba, __u32 mndw, __u8 atype, __u16 rl,
+               void *data)
+{
+       struct nvme_admin_cmd cmd = {
+               .opcode =  nvme_admin_get_lba_status,
+               .addr = (__u64)(uintptr_t) data,
+               .cdw10 = slba & 0xffffffff,
+               .cdw11 = slba >> 32,
+               .cdw12 = mndw,
+               .cdw13 = (atype << 24) | rl,
+       };
+
+       return nvme_submit_admin_passthru(fd, &cmd);
+}
+
 int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
                   __u32 data_len, __u32 dw12, void *data, __u32 *result)
 {
@@ -867,3 +910,19 @@ int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10)
 
        return nvme_submit_admin_passthru(fd, &cmd);
 }
+
+int nvme_virtual_mgmt(int fd, __u32 cdw10, __u32 cdw11, __u32 *result)
+{
+       struct nvme_admin_cmd cmd = {
+               .opcode = nvme_admin_virtual_mgmt,
+               .cdw10  = cdw10,
+               .cdw11  = cdw11,
+       };
+       int err;
+
+       err = nvme_submit_admin_passthru(fd, &cmd);
+       if (!err && result)
+               *result = cmd.result;
+
+       return err;
+}
index 3fb740c..565f764 100644 (file)
@@ -6,6 +6,8 @@
 #include "linux/nvme_ioctl.h"
 #include "nvme.h"
 
+#define NVME_IOCTL_TIMEOUT 120000 /* in milliseconds */
+
 int nvme_get_nsid(int fd);
 
 /* Generic passthrough */
@@ -36,6 +38,9 @@ int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control,
                 __u32 dsmgmt, __u32 reftag, __u16 apptag,
                 __u16 appmask, void *data, void *metadata);
 
+int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks,
+               __u16 control, __u32 reftag, __u16 apptag, __u16 appmask);
+
 /* NVME_IO_CMD */
 int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
                     __u32 nsid, __u32 cdw2, __u32 cdw3,
@@ -73,11 +78,22 @@ int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data);
 int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
 int nvme_identify_ns_descs(int fd, __u32 nsid, void *data);
 int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data);
-int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
-                  __u16 group_id, bool rae, __u32 data_len, void *data);
+int nvme_identify_uuid(int fd, void *data);
+int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
+int nvme_identify_ns_granularity(int fd, void *data);
 int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
                 __u32 data_len, void *data);
-
+int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
+                  __u16 group_id, bool rae, __u8 uuid_ix,
+                  __u32 data_len, void *data);
+
+static inline int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp,
+                                __u64 lpo, __u16 lsi, bool rae, __u32 data_len,
+                                void *data)
+{
+       return nvme_get_log14(fd, nsid, log_id, lsp, lpo, lsi, rae, 0,
+                             data_len, data);
+}
 
 int nvme_get_telemetry_log(int fd, void *lp, int generate_report,
                           int ctrl_gen, size_t log_page_size, __u64 offset);
@@ -105,8 +121,8 @@ int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
                __u8 pil, __u8 ms, __u32 timeout);
 
 int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas,
-                  __u8 dps, __u8 nmic, __u32 *result);
-int nvme_ns_delete(int fd, __u32 nsid);
+                  __u8 dps, __u8 nmic, __u32 timeout, __u32 *result);
+int nvme_ns_delete(int fd, __u32 nsid, __u32 timeout);
 
 int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls,
                       __u16 *ctrlist, bool attach);
@@ -125,15 +141,18 @@ int nvme_subsystem_reset(int fd);
 int nvme_reset_controller(int fd);
 int nvme_ns_rescan(int fd);
 
+int nvme_get_lba_status(int fd, __u64 slba, __u32 mndw, __u8 atype, __u16 rl,
+               void *data);
 int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
                  __u32 data_len, __u32 dw12, void *data, __u32 *result);
 int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
                  __u32 data_len, __u32 dw12, void *data, __u32 *result);
 int nvme_get_properties(int fd, void **pbar);
-int nvme_set_property(int fd, int offset, int value);
+int nvme_set_property(int fd, int offset, uint64_t value);
 int nvme_get_property(int fd, int offset, uint64_t *value);
 int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
                  __u8 no_dealloc, __u32 ovrpat);
 int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10);
 int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log);
+int nvme_virtual_mgmt(int fd, __u32 cdw10, __u32 cdw11, __u32 *result);
 #endif                         /* _NVME_LIB_H */
index 685d179..7e0278b 100644 (file)
@@ -40,16 +40,16 @@ struct nvme_effects_log_page {
 };
 
 struct nvme_error_log_page {
-       __u64   error_count;
-       __u16   sqid;
-       __u16   cmdid;
-       __u16   status_field;
-       __u16   parm_error_location;
-       __u64   lba;
-       __u32   nsid;
+       __le64  error_count;
+       __le16  sqid;
+       __le16  cmdid;
+       __le16  status_field;
+       __le16  parm_error_location;
+       __le64  lba;
+       __le32  nsid;
        __u8    vs;
        __u8    resv[3];
-       __u64   cs;
+       __le64  cs;
        __u8    resv2[24];
 };
 
@@ -87,13 +87,30 @@ struct nvme_controller_list {
        __le16 identifier[];
 };
 
+struct nvme_secondary_controller_entry {
+       __le16 scid;    /* Secondary Controller Identifier */
+       __le16 pcid;    /* Primary Controller Identifier */
+       __u8   scs;     /* Secondary Controller State */
+       __u8   rsvd5[3];
+       __le16 vfn;     /* Virtual Function Number */
+       __le16 nvq;     /* Number of VQ Flexible Resources Assigned */
+       __le16 nvi;     /* Number of VI Flexible Resources Assigned */
+       __u8   rsvd14[18];
+};
+
+struct nvme_secondary_controllers_list {
+       __u8   num;
+       __u8   rsvd[31];
+       struct nvme_secondary_controller_entry sc_entry[127];
+};
+
 struct nvme_bar_cap {
        __u16   mqes;
        __u8    ams_cqr;
        __u8    to;
        __u16   bps_css_nssrs_dstrd;
        __u8    mpsmax_mpsmin;
-       __u8    reserved;
+       __u8    rsvd_pmrs;
 };
 
 #ifdef __CHECKER__
@@ -102,19 +119,31 @@ struct nvme_bar_cap {
 #define __force
 #endif
 
-#define cpu_to_le16(x) \
-       ((__force __le16)htole16(x))
-#define cpu_to_le32(x) \
-       ((__force __le32)htole32(x))
-#define cpu_to_le64(x) \
-       ((__force __le64)htole64(x))
-
-#define le16_to_cpu(x) \
-       le16toh((__force __u16)(x))
-#define le32_to_cpu(x) \
-       le32toh((__force __u32)(x))
-#define le64_to_cpu(x) \
-       le64toh((__force __u64)(x))
+static inline __le16 cpu_to_le16(uint16_t x)
+{
+       return (__force __le16)htole16(x);
+}
+static inline __le32 cpu_to_le32(uint32_t x)
+{
+       return (__force __le32)htole32(x);
+}
+static inline __le64 cpu_to_le64(uint64_t x)
+{
+       return (__force __le64)htole64(x);
+}
+
+static inline uint16_t le16_to_cpu(__le16 x)
+{
+       return le16toh((__force __u16)x);
+}
+static inline uint32_t le32_to_cpu(__le32 x)
+{
+       return le32toh((__force __u32)x);
+}
+static inline uint64_t le64_to_cpu(__le64 x)
+{
+       return le64toh((__force __u64)x);
+}
 
 #define MAX_LIST_ITEMS 256
 struct list_item {
@@ -131,6 +160,10 @@ struct ctrl_list_item {
        char *transport;
        char *state;
        char *ana_state;
+       char *subsysnqn;
+       char *traddr;
+       char *trsvcid;
+       char *host_traddr;
 };
 
 struct subsys_list_item {
@@ -146,6 +179,26 @@ enum {
        BINARY,
 };
 
+struct connect_args {
+       char *subsysnqn;
+       char *transport;
+       char *traddr;
+       char *trsvcid;
+       char *host_traddr;
+};
+
+#define SYS_NVME               "/sys/class/nvme"
+
+bool ctrl_matches_connectargs(char *name, struct connect_args *args);
+char *find_ctrl_with_connectargs(struct connect_args *args);
+char *__parse_connect_arg(char *conargs, const char delim, const char *fieldnm);
+
+extern const char *conarg_nqn;
+extern const char *conarg_transport;
+extern const char *conarg_traddr;
+extern const char *conarg_trsvcid;
+extern const char *conarg_host_traddr;
+
 void register_extension(struct plugin *plugin);
 
 #include "argconfig.h"
@@ -160,4 +213,28 @@ int        validate_output_format(char *format);
 struct subsys_list_item *get_subsys_list(int *subcnt, char *subsysnqn, __u32 nsid);
 void free_subsys_list(struct subsys_list_item *slist, int n);
 char *nvme_char_from_block(char *block);
+
+/*
+ * is_64bit_reg - It checks whether given offset of the controller register is
+ *                64bit or not.
+ * @offset: offset of controller register field in bytes
+ *
+ * It gives true if given offset is 64bit register, otherwise it returns false.
+ *
+ * Notes:  This function does not care about transport so that the offset is
+ * not going to be checked inside of this function for the unsupported fields
+ * in a specific transport.  For example, BPMBL(Boot Partition Memory Buffer
+ * Location) register is not supported by fabrics, but it can be chcked here.
+ */
+static inline bool is_64bit_reg(__u32 offset)
+{
+       if (offset == NVME_REG_CAP ||
+                       offset == NVME_REG_ASQ ||
+                       offset == NVME_REG_ACQ ||
+                       offset == NVME_REG_BPMBL)
+               return true;
+
+       return false;
+}
+
 #endif /* _NVME_H */