From: Martin Wilck <mwilck@xxxxxxxx> Update nvme code to nvme-cli v1.9 (977e7d4, Thu Aug 15 2019). Signed-off-by: Martin Wilck <mwilck@xxxxxxxx> --- libmultipath/nvme/linux/nvme.h | 136 +++++++++++++++----- libmultipath/nvme/nvme-ioctl.c | 229 +++++++++++++++++++++------------ libmultipath/nvme/nvme-ioctl.h | 31 ++++- libmultipath/nvme/nvme.h | 121 +++++++++++++---- 4 files changed, 375 insertions(+), 142 deletions(-) diff --git a/libmultipath/nvme/linux/nvme.h b/libmultipath/nvme/linux/nvme.h index 68000eb8..a6975549 100644 --- a/libmultipath/nvme/linux/nvme.h +++ b/libmultipath/nvme/linux/nvme.h @@ -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, }; diff --git a/libmultipath/nvme/nvme-ioctl.c b/libmultipath/nvme/nvme-ioctl.c index 70a16ced..69599763 100644 --- a/libmultipath/nvme/nvme-ioctl.c +++ b/libmultipath/nvme/nvme-ioctl.c @@ -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; +} diff --git a/libmultipath/nvme/nvme-ioctl.h b/libmultipath/nvme/nvme-ioctl.h index 3fb740c3..565f7648 100644 --- a/libmultipath/nvme/nvme-ioctl.h +++ b/libmultipath/nvme/nvme-ioctl.h @@ -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 */ diff --git a/libmultipath/nvme/nvme.h b/libmultipath/nvme/nvme.h index 685d1799..7e0278b5 100644 --- a/libmultipath/nvme/nvme.h +++ b/libmultipath/nvme/nvme.h @@ -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 */ -- 2.23.0 -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel