Blame SOURCES/0258-RHBZ-1634183-ANA-prioritizer.patch

4728c8
---
4728c8
 Makefile.inc                         |    1 
4728c8
 libmultipath/Makefile                |    7 
4728c8
 libmultipath/hwtable.c               |    1 
4728c8
 libmultipath/nvme-ioctl.c            |  869 ++++++++++++++++++++
4728c8
 libmultipath/nvme-ioctl.h            |  139 +++
4728c8
 libmultipath/nvme-lib.c              |   49 +
4728c8
 libmultipath/nvme-lib.h              |   39 
4728c8
 libmultipath/nvme/argconfig.h        |   99 ++
4728c8
 libmultipath/nvme/json.h             |   87 ++
4728c8
 libmultipath/nvme/linux/nvme.h       | 1450 +++++++++++++++++++++++++++++++++++
4728c8
 libmultipath/nvme/linux/nvme_ioctl.h |   67 +
4728c8
 libmultipath/nvme/nvme.h             |  163 +++
4728c8
 libmultipath/nvme/plugin.h           |   36 
4728c8
 libmultipath/prio.h                  |    1 
4728c8
 libmultipath/prioritizers/Makefile   |    4 
4728c8
 libmultipath/prioritizers/ana.c      |  236 +++++
4728c8
 libmultipath/propsel.c               |   10 
4728c8
 libmultipath/util.h                  |    2 
4728c8
 multipath/multipath.conf.5           |    3 
4728c8
 19 files changed, 3258 insertions(+), 5 deletions(-)
4728c8
4728c8
Index: multipath-tools-130222/libmultipath/nvme/argconfig.h
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/nvme/argconfig.h
4728c8
@@ -0,0 +1,99 @@
4728c8
+////////////////////////////////////////////////////////////////////////
4728c8
+//
4728c8
+// Copyright 2014 PMC-Sierra, Inc.
4728c8
+//
4728c8
+// This program is free software; you can redistribute it and/or
4728c8
+// modify it under the terms of the GNU General Public License
4728c8
+// as published by the Free Software Foundation; either version 2
4728c8
+// of the License, or (at your option) any later version.
4728c8
+//
4728c8
+// This program is distributed in the hope that it will be useful,
4728c8
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
4728c8
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4728c8
+// GNU General Public License for more details.
4728c8
+//
4728c8
+// You should have received a copy of the GNU General Public License
4728c8
+// along with this program; if not, write to the Free Software
4728c8
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
4728c8
+//
4728c8
+////////////////////////////////////////////////////////////////////////
4728c8
+
4728c8
+////////////////////////////////////////////////////////////////////////
4728c8
+//
4728c8
+//   Author: Logan Gunthorpe <logang@deltatee.com>
4728c8
+//           Logan Gunthorpe
4728c8
+//
4728c8
+//   Date:   Oct 23 2014
4728c8
+//
4728c8
+//   Description:
4728c8
+//     Header file for argconfig.c
4728c8
+//
4728c8
+////////////////////////////////////////////////////////////////////////
4728c8
+
4728c8
+#ifndef argconfig_H
4728c8
+#define argconfig_H
4728c8
+
4728c8
+#include <string.h>
4728c8
+#include <getopt.h>
4728c8
+#include <stdarg.h>
4728c8
+
4728c8
+enum argconfig_types {
4728c8
+	CFG_NONE,
4728c8
+	CFG_STRING,
4728c8
+	CFG_INT,
4728c8
+	CFG_SIZE,
4728c8
+	CFG_LONG,
4728c8
+	CFG_LONG_SUFFIX,
4728c8
+	CFG_DOUBLE,
4728c8
+	CFG_BOOL,
4728c8
+	CFG_BYTE,
4728c8
+	CFG_SHORT,
4728c8
+	CFG_POSITIVE,
4728c8
+	CFG_INCREMENT,
4728c8
+	CFG_SUBOPTS,
4728c8
+	CFG_FILE_A,
4728c8
+	CFG_FILE_W,
4728c8
+	CFG_FILE_R,
4728c8
+	CFG_FILE_AP,
4728c8
+	CFG_FILE_WP,
4728c8
+	CFG_FILE_RP,
4728c8
+};
4728c8
+
4728c8
+struct argconfig_commandline_options {
4728c8
+	const char *option;
4728c8
+	const char short_option;
4728c8
+	const char *meta;
4728c8
+	enum argconfig_types config_type;
4728c8
+	void *default_value;
4728c8
+	int argument_type;
4728c8
+	const char *help;
4728c8
+};
4728c8
+
4728c8
+#define CFG_MAX_SUBOPTS 500
4728c8
+#define MAX_HELP_FUNC 20
4728c8
+
4728c8
+#ifdef __cplusplus
4728c8
+extern "C" {
4728c8
+#endif
4728c8
+
4728c8
+typedef void argconfig_help_func(void);
4728c8
+void argconfig_append_usage(const char *str);
4728c8
+void argconfig_print_help(const char *program_desc,
4728c8
+			  const struct argconfig_commandline_options *options);
4728c8
+int argconfig_parse(int argc, char *argv[], const char *program_desc,
4728c8
+		    const struct argconfig_commandline_options *options,
4728c8
+		    void *config_out, size_t config_size);
4728c8
+int argconfig_parse_subopt_string(char *string, char **options,
4728c8
+				  size_t max_options);
4728c8
+unsigned argconfig_parse_comma_sep_array(char *string, int *ret,
4728c8
+					 unsigned max_length);
4728c8
+unsigned argconfig_parse_comma_sep_array_long(char *string,
4728c8
+					      unsigned long long *ret,
4728c8
+					      unsigned max_length);
4728c8
+void argconfig_register_help_func(argconfig_help_func * f);
4728c8
+
4728c8
+void print_word_wrapped(const char *s, int indent, int start);
4728c8
+#ifdef __cplusplus
4728c8
+}
4728c8
+#endif
4728c8
+#endif
4728c8
Index: multipath-tools-130222/libmultipath/nvme/json.h
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/nvme/json.h
4728c8
@@ -0,0 +1,87 @@
4728c8
+#ifndef __JSON__H
4728c8
+#define __JSON__H
4728c8
+
4728c8
+struct json_object;
4728c8
+struct json_array;
4728c8
+struct json_pair;
4728c8
+
4728c8
+#define JSON_TYPE_STRING 0
4728c8
+#define JSON_TYPE_INTEGER 1
4728c8
+#define JSON_TYPE_FLOAT 2
4728c8
+#define JSON_TYPE_OBJECT 3
4728c8
+#define JSON_TYPE_ARRAY 4
4728c8
+#define JSON_TYPE_UINT 5
4728c8
+#define JSON_PARENT_TYPE_PAIR 0
4728c8
+#define JSON_PARENT_TYPE_ARRAY 1
4728c8
+struct json_value {
4728c8
+	int type;
4728c8
+	union {
4728c8
+		long long integer_number;
4728c8
+		unsigned long long uint_number;
4728c8
+		long double float_number;
4728c8
+		char *string;
4728c8
+		struct json_object *object;
4728c8
+		struct json_array *array;
4728c8
+	};
4728c8
+	int parent_type;
4728c8
+	union {
4728c8
+		struct json_pair *parent_pair;
4728c8
+		struct json_array *parent_array;
4728c8
+	};
4728c8
+};
4728c8
+
4728c8
+struct json_array {
4728c8
+	struct json_value **values;
4728c8
+	int value_cnt;
4728c8
+	struct json_value *parent;
4728c8
+};
4728c8
+
4728c8
+struct json_object {
4728c8
+	struct json_pair **pairs;
4728c8
+	int pair_cnt;
4728c8
+	struct json_value *parent;
4728c8
+};
4728c8
+
4728c8
+struct json_pair {
4728c8
+	char *name;
4728c8
+	struct json_value *value;
4728c8
+	struct json_object *parent;
4728c8
+};
4728c8
+
4728c8
+struct json_object *json_create_object(void);
4728c8
+struct json_array *json_create_array(void);
4728c8
+
4728c8
+void json_free_object(struct json_object *obj);
4728c8
+
4728c8
+int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...);
4728c8
+#define json_object_add_value_int(obj, name, val) \
4728c8
+	json_object_add_value_type((obj), name, JSON_TYPE_INTEGER, (long long) (val))
4728c8
+#define json_object_add_value_uint(obj, name, val) \
4728c8
+	json_object_add_value_type((obj), name, JSON_TYPE_UINT, (unsigned long long) (val))
4728c8
+#define json_object_add_value_float(obj, name, val) \
4728c8
+	json_object_add_value_type((obj), name, JSON_TYPE_FLOAT, (val))
4728c8
+#define json_object_add_value_string(obj, name, val) \
4728c8
+	json_object_add_value_type((obj), name, JSON_TYPE_STRING, (val))
4728c8
+#define json_object_add_value_object(obj, name, val) \
4728c8
+	json_object_add_value_type((obj), name, JSON_TYPE_OBJECT, (val))
4728c8
+#define json_object_add_value_array(obj, name, val) \
4728c8
+	json_object_add_value_type((obj), name, JSON_TYPE_ARRAY, (val))
4728c8
+int json_array_add_value_type(struct json_array *array, int type, ...);
4728c8
+#define json_array_add_value_int(obj, val) \
4728c8
+	json_array_add_value_type((obj), JSON_TYPE_INTEGER, (val))
4728c8
+#define json_array_add_value_uint(obj, val) \
4728c8
+	json_array_add_value_type((obj), JSON_TYPE_UINT, (val))
4728c8
+#define json_array_add_value_float(obj, val) \
4728c8
+	json_array_add_value_type((obj), JSON_TYPE_FLOAT, (val))
4728c8
+#define json_array_add_value_string(obj, val) \
4728c8
+	json_array_add_value_type((obj), JSON_TYPE_STRING, (val))
4728c8
+#define json_array_add_value_object(obj, val) \
4728c8
+	json_array_add_value_type((obj), JSON_TYPE_OBJECT, (val))
4728c8
+#define json_array_add_value_array(obj, val) \
4728c8
+	json_array_add_value_type((obj), JSON_TYPE_ARRAY, (val))
4728c8
+
4728c8
+#define json_array_last_value_object(obj) \
4728c8
+	(obj->values[obj->value_cnt - 1]->object)
4728c8
+
4728c8
+void json_print_object(struct json_object *obj, void *);
4728c8
+#endif
4728c8
Index: multipath-tools-130222/libmultipath/nvme/nvme.h
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/nvme/nvme.h
4728c8
@@ -0,0 +1,163 @@
4728c8
+/*
4728c8
+ * Definitions for the NVM Express interface
4728c8
+ * Copyright (c) 2011-2014, Intel Corporation.
4728c8
+ *
4728c8
+ * This program is free software; you can redistribute it and/or modify it
4728c8
+ * under the terms and conditions of the GNU General Public License,
4728c8
+ * version 2, as published by the Free Software Foundation.
4728c8
+ *
4728c8
+ * This program is distributed in the hope it will be useful, but WITHOUT
4728c8
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4728c8
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
4728c8
+ * more details.
4728c8
+ */
4728c8
+
4728c8
+#ifndef _NVME_H
4728c8
+#define _NVME_H
4728c8
+
4728c8
+#include <stdbool.h>
4728c8
+#include <stdint.h>
4728c8
+#include <endian.h>
4728c8
+#include "plugin.h"
4728c8
+#include "json.h"
4728c8
+
4728c8
+#define unlikely(x) x
4728c8
+
4728c8
+#ifdef LIBUUID
4728c8
+#include <uuid/uuid.h>
4728c8
+#else
4728c8
+typedef struct {
4728c8
+	uint8_t b[16];
4728c8
+} uuid_t;
4728c8
+#endif
4728c8
+
4728c8
+#include "linux/nvme.h"
4728c8
+
4728c8
+struct nvme_effects_log_page {
4728c8
+	__le32 acs[256];
4728c8
+	__le32 iocs[256];
4728c8
+	__u8   resv[2048];
4728c8
+};
4728c8
+
4728c8
+struct nvme_error_log_page {
4728c8
+	__u64	error_count;
4728c8
+	__u16	sqid;
4728c8
+	__u16	cmdid;
4728c8
+	__u16	status_field;
4728c8
+	__u16	parm_error_location;
4728c8
+	__u64	lba;
4728c8
+	__u32	nsid;
4728c8
+	__u8	vs;
4728c8
+	__u8	resv[3];
4728c8
+	__u64	cs;
4728c8
+	__u8	resv2[24];
4728c8
+};
4728c8
+
4728c8
+struct nvme_firmware_log_page {
4728c8
+	__u8	afi;
4728c8
+	__u8	resv[7];
4728c8
+	__u64	frs[7];
4728c8
+	__u8	resv2[448];
4728c8
+};
4728c8
+
4728c8
+/* idle and active power scales occupy the last 2 bits of the field */
4728c8
+#define POWER_SCALE(s) ((s) >> 6)
4728c8
+
4728c8
+struct nvme_host_mem_buffer {
4728c8
+	__u32			hsize;
4728c8
+	__u32			hmdlal;
4728c8
+	__u32			hmdlau;
4728c8
+	__u32			hmdlec;
4728c8
+	__u8			rsvd16[4080];
4728c8
+};
4728c8
+
4728c8
+struct nvme_auto_pst {
4728c8
+	__u32	data;
4728c8
+	__u32	rsvd32;
4728c8
+};
4728c8
+
4728c8
+struct nvme_timestamp {
4728c8
+	__u8 timestamp[6];
4728c8
+	__u8 attr;
4728c8
+	__u8 rsvd;
4728c8
+};
4728c8
+
4728c8
+struct nvme_controller_list {
4728c8
+	__le16 num;
4728c8
+	__le16 identifier[];
4728c8
+};
4728c8
+
4728c8
+struct nvme_bar_cap {
4728c8
+	__u16	mqes;
4728c8
+	__u8	ams_cqr;
4728c8
+	__u8	to;
4728c8
+	__u16	bps_css_nssrs_dstrd;
4728c8
+	__u8	mpsmax_mpsmin;
4728c8
+	__u8	reserved;
4728c8
+};
4728c8
+
4728c8
+#ifdef __CHECKER__
4728c8
+#define __force       __attribute__((force))
4728c8
+#else
4728c8
+#define __force
4728c8
+#endif
4728c8
+
4728c8
+#define cpu_to_le16(x) \
4728c8
+	((__force __le16)htole16(x))
4728c8
+#define cpu_to_le32(x) \
4728c8
+	((__force __le32)htole32(x))
4728c8
+#define cpu_to_le64(x) \
4728c8
+	((__force __le64)htole64(x))
4728c8
+
4728c8
+#define le16_to_cpu(x) \
4728c8
+	le16toh((__force __u16)(x))
4728c8
+#define le32_to_cpu(x) \
4728c8
+	le32toh((__force __u32)(x))
4728c8
+#define le64_to_cpu(x) \
4728c8
+	le64toh((__force __u64)(x))
4728c8
+
4728c8
+#define MAX_LIST_ITEMS 256
4728c8
+struct list_item {
4728c8
+	char                node[1024];
4728c8
+	struct nvme_id_ctrl ctrl;
4728c8
+	int                 nsid;
4728c8
+	struct nvme_id_ns   ns;
4728c8
+	unsigned            block;
4728c8
+};
4728c8
+
4728c8
+struct ctrl_list_item {
4728c8
+	char *name;
4728c8
+	char *address;
4728c8
+	char *transport;
4728c8
+	char *state;
4728c8
+	char *ana_state;
4728c8
+};
4728c8
+
4728c8
+struct subsys_list_item {
4728c8
+	char *name;
4728c8
+	char *subsysnqn;
4728c8
+	int nctrls;
4728c8
+	struct ctrl_list_item *ctrls;
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NORMAL,
4728c8
+	JSON,
4728c8
+	BINARY,
4728c8
+};
4728c8
+
4728c8
+void register_extension(struct plugin *plugin);
4728c8
+
4728c8
+#include "argconfig.h"
4728c8
+int parse_and_open(int argc, char **argv, const char *desc,
4728c8
+	const struct argconfig_commandline_options *clo, void *cfg, size_t size);
4728c8
+
4728c8
+extern const char *devicename;
4728c8
+
4728c8
+int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin, void (*vs)(__u8 *vs, struct json_object *root));
4728c8
+int	validate_output_format(char *format);
4728c8
+
4728c8
+struct subsys_list_item *get_subsys_list(int *subcnt, char *subsysnqn, __u32 nsid);
4728c8
+void free_subsys_list(struct subsys_list_item *slist, int n);
4728c8
+char *nvme_char_from_block(char *block);
4728c8
+#endif /* _NVME_H */
4728c8
Index: multipath-tools-130222/libmultipath/nvme/plugin.h
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/nvme/plugin.h
4728c8
@@ -0,0 +1,36 @@
4728c8
+#ifndef PLUGIN_H
4728c8
+#define PLUGIN_H
4728c8
+
4728c8
+#include <stdbool.h>
4728c8
+
4728c8
+struct program {
4728c8
+	const char *name;
4728c8
+	const char *version;
4728c8
+	const char *usage;
4728c8
+	const char *desc;
4728c8
+	const char *more;
4728c8
+	struct command **commands;
4728c8
+	struct plugin *extensions;
4728c8
+};
4728c8
+
4728c8
+struct plugin {
4728c8
+	const char *name;
4728c8
+	const char *desc;
4728c8
+	struct command **commands;
4728c8
+	struct program *parent;
4728c8
+	struct plugin *next;
4728c8
+	struct plugin *tail;
4728c8
+};
4728c8
+
4728c8
+struct command {
4728c8
+	char *name;
4728c8
+	char *help;
4728c8
+	int (*fn)(int argc, char **argv, struct command *command, struct plugin *plugin);
4728c8
+	char *alias;
4728c8
+};
4728c8
+
4728c8
+void usage(struct plugin *plugin);
4728c8
+void general_help(struct plugin *plugin);
4728c8
+int handle_plugin(int argc, char **argv, struct plugin *plugin);
4728c8
+
4728c8
+#endif
4728c8
Index: multipath-tools-130222/libmultipath/nvme/linux/nvme.h
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/nvme/linux/nvme.h
4728c8
@@ -0,0 +1,1450 @@
4728c8
+/*
4728c8
+ * Definitions for the NVM Express interface
4728c8
+ * Copyright (c) 2011-2014, Intel Corporation.
4728c8
+ *
4728c8
+ * This program is free software; you can redistribute it and/or modify it
4728c8
+ * under the terms and conditions of the GNU General Public License,
4728c8
+ * version 2, as published by the Free Software Foundation.
4728c8
+ *
4728c8
+ * This program is distributed in the hope it will be useful, but WITHOUT
4728c8
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4728c8
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
4728c8
+ * more details.
4728c8
+ */
4728c8
+
4728c8
+#ifndef _LINUX_NVME_H
4728c8
+#define _LINUX_NVME_H
4728c8
+
4728c8
+#include <linux/types.h>
4728c8
+#include <linux/uuid.h>
4728c8
+
4728c8
+/* NQN names in commands fields specified one size */
4728c8
+#define NVMF_NQN_FIELD_LEN	256
4728c8
+
4728c8
+/* However the max length of a qualified name is another size */
4728c8
+#define NVMF_NQN_SIZE		223
4728c8
+
4728c8
+#define NVMF_TRSVCID_SIZE	32
4728c8
+#define NVMF_TRADDR_SIZE	256
4728c8
+#define NVMF_TSAS_SIZE		256
4728c8
+
4728c8
+#define NVME_DISC_SUBSYS_NAME	"nqn.2014-08.org.nvmexpress.discovery"
4728c8
+
4728c8
+#define NVME_RDMA_IP_PORT	4420
4728c8
+
4728c8
+#define NVME_NSID_ALL		0xffffffff
4728c8
+
4728c8
+enum nvme_subsys_type {
4728c8
+	NVME_NQN_DISC	= 1,		/* Discovery type target subsystem */
4728c8
+	NVME_NQN_NVME	= 2,		/* NVME type target subsystem */
4728c8
+};
4728c8
+
4728c8
+/* Address Family codes for Discovery Log Page entry ADRFAM field */
4728c8
+enum {
4728c8
+	NVMF_ADDR_FAMILY_PCI	= 0,	/* PCIe */
4728c8
+	NVMF_ADDR_FAMILY_IP4	= 1,	/* IP4 */
4728c8
+	NVMF_ADDR_FAMILY_IP6	= 2,	/* IP6 */
4728c8
+	NVMF_ADDR_FAMILY_IB	= 3,	/* InfiniBand */
4728c8
+	NVMF_ADDR_FAMILY_FC	= 4,	/* Fibre Channel */
4728c8
+};
4728c8
+
4728c8
+/* Transport Type codes for Discovery Log Page entry TRTYPE field */
4728c8
+enum {
4728c8
+	NVMF_TRTYPE_RDMA	= 1,	/* RDMA */
4728c8
+	NVMF_TRTYPE_FC		= 2,	/* Fibre Channel */
4728c8
+	NVMF_TRTYPE_TCP		= 3,	/* TCP */
4728c8
+	NVMF_TRTYPE_LOOP	= 254,	/* Reserved for host usage */
4728c8
+	NVMF_TRTYPE_MAX,
4728c8
+};
4728c8
+
4728c8
+/* Transport Requirements codes for Discovery Log Page entry TREQ field */
4728c8
+enum {
4728c8
+	NVMF_TREQ_NOT_SPECIFIED	= 0,		/* Not specified */
4728c8
+	NVMF_TREQ_REQUIRED	= 1,		/* Required */
4728c8
+	NVMF_TREQ_NOT_REQUIRED	= 2,		/* Not Required */
4728c8
+	NVMF_TREQ_DISABLE_SQFLOW = (1 << 2),	/* SQ flow control disable supported */
4728c8
+};
4728c8
+
4728c8
+/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
4728c8
+ * RDMA_QPTYPE field
4728c8
+ */
4728c8
+enum {
4728c8
+	NVMF_RDMA_QPTYPE_CONNECTED	= 1, /* Reliable Connected */
4728c8
+	NVMF_RDMA_QPTYPE_DATAGRAM	= 2, /* Reliable Datagram */
4728c8
+};
4728c8
+
4728c8
+/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
4728c8
+ * RDMA_QPTYPE field
4728c8
+ */
4728c8
+enum {
4728c8
+	NVMF_RDMA_PRTYPE_NOT_SPECIFIED	= 1, /* No Provider Specified */
4728c8
+	NVMF_RDMA_PRTYPE_IB		= 2, /* InfiniBand */
4728c8
+	NVMF_RDMA_PRTYPE_ROCE		= 3, /* InfiniBand RoCE */
4728c8
+	NVMF_RDMA_PRTYPE_ROCEV2		= 4, /* InfiniBand RoCEV2 */
4728c8
+	NVMF_RDMA_PRTYPE_IWARP		= 5, /* IWARP */
4728c8
+};
4728c8
+
4728c8
+/* RDMA Connection Management Service Type codes for Discovery Log Page
4728c8
+ * entry TSAS RDMA_CMS field
4728c8
+ */
4728c8
+enum {
4728c8
+	NVMF_RDMA_CMS_RDMA_CM	= 1, /* Sockets based endpoint addressing */
4728c8
+};
4728c8
+
4728c8
+/* TCP port security type for  Discovery Log Page entry TSAS
4728c8
+ */
4728c8
+enum {
4728c8
+	NVMF_TCP_SECTYPE_NONE	= 0, /* No Security */
4728c8
+	NVMF_TCP_SECTYPE_TLS	= 1, /* Transport Layer Security */
4728c8
+};
4728c8
+
4728c8
+#define NVME_AQ_DEPTH		32
4728c8
+#define NVME_NR_AEN_COMMANDS	1
4728c8
+#define NVME_AQ_BLK_MQ_DEPTH	(NVME_AQ_DEPTH - NVME_NR_AEN_COMMANDS)
4728c8
+
4728c8
+/*
4728c8
+ * Subtract one to leave an empty queue entry for 'Full Queue' condition. See
4728c8
+ * NVM-Express 1.2 specification, section 4.1.2.
4728c8
+ */
4728c8
+#define NVME_AQ_MQ_TAG_DEPTH	(NVME_AQ_BLK_MQ_DEPTH - 1)
4728c8
+
4728c8
+enum {
4728c8
+	NVME_REG_CAP	= 0x0000,	/* Controller Capabilities */
4728c8
+	NVME_REG_VS	= 0x0008,	/* Version */
4728c8
+	NVME_REG_INTMS	= 0x000c,	/* Interrupt Mask Set */
4728c8
+	NVME_REG_INTMC	= 0x0010,	/* Interrupt Mask Clear */
4728c8
+	NVME_REG_CC	= 0x0014,	/* Controller Configuration */
4728c8
+	NVME_REG_CSTS	= 0x001c,	/* Controller Status */
4728c8
+	NVME_REG_NSSR	= 0x0020,	/* NVM Subsystem Reset */
4728c8
+	NVME_REG_AQA	= 0x0024,	/* Admin Queue Attributes */
4728c8
+	NVME_REG_ASQ	= 0x0028,	/* Admin SQ Base Address */
4728c8
+	NVME_REG_ACQ	= 0x0030,	/* Admin CQ Base Address */
4728c8
+	NVME_REG_CMBLOC = 0x0038,	/* Controller Memory Buffer Location */
4728c8
+	NVME_REG_CMBSZ	= 0x003c,	/* Controller Memory Buffer Size */
4728c8
+	NVME_REG_BPINFO	= 0x0040,	/* Boot Partition Information */
4728c8
+	NVME_REG_BPRSEL	= 0x0044,	/* Boot Partition Read Select */
4728c8
+	NVME_REG_BPMBL	= 0x0048,	/* Boot Partition Memory Buffer Location */
4728c8
+	NVME_REG_DBS	= 0x1000,	/* SQ 0 Tail Doorbell */
4728c8
+};
4728c8
+
4728c8
+#define NVME_CAP_MQES(cap)	((cap) & 0xffff)
4728c8
+#define NVME_CAP_TIMEOUT(cap)	(((cap) >> 24) & 0xff)
4728c8
+#define NVME_CAP_STRIDE(cap)	(((cap) >> 32) & 0xf)
4728c8
+#define NVME_CAP_NSSRC(cap)	(((cap) >> 36) & 0x1)
4728c8
+#define NVME_CAP_MPSMIN(cap)	(((cap) >> 48) & 0xf)
4728c8
+#define NVME_CAP_MPSMAX(cap)	(((cap) >> 52) & 0xf)
4728c8
+
4728c8
+#define NVME_CMB_BIR(cmbloc)	((cmbloc) & 0x7)
4728c8
+#define NVME_CMB_OFST(cmbloc)	(((cmbloc) >> 12) & 0xfffff)
4728c8
+#define NVME_CMB_SZ(cmbsz)	(((cmbsz) >> 12) & 0xfffff)
4728c8
+#define NVME_CMB_SZU(cmbsz)	(((cmbsz) >> 8) & 0xf)
4728c8
+
4728c8
+#define NVME_CMB_WDS(cmbsz)	((cmbsz) & 0x10)
4728c8
+#define NVME_CMB_RDS(cmbsz)	((cmbsz) & 0x8)
4728c8
+#define NVME_CMB_LISTS(cmbsz)	((cmbsz) & 0x4)
4728c8
+#define NVME_CMB_CQS(cmbsz)	((cmbsz) & 0x2)
4728c8
+#define NVME_CMB_SQS(cmbsz)	((cmbsz) & 0x1)
4728c8
+
4728c8
+/*
4728c8
+ * Submission and Completion Queue Entry Sizes for the NVM command set.
4728c8
+ * (In bytes and specified as a power of two (2^n)).
4728c8
+ */
4728c8
+#define NVME_NVM_IOSQES		6
4728c8
+#define NVME_NVM_IOCQES		4
4728c8
+
4728c8
+enum {
4728c8
+	NVME_CC_ENABLE		= 1 << 0,
4728c8
+	NVME_CC_CSS_NVM		= 0 << 4,
4728c8
+	NVME_CC_EN_SHIFT	= 0,
4728c8
+	NVME_CC_CSS_SHIFT	= 4,
4728c8
+	NVME_CC_MPS_SHIFT	= 7,
4728c8
+	NVME_CC_AMS_SHIFT	= 11,
4728c8
+	NVME_CC_SHN_SHIFT	= 14,
4728c8
+	NVME_CC_IOSQES_SHIFT	= 16,
4728c8
+	NVME_CC_IOCQES_SHIFT	= 20,
4728c8
+	NVME_CC_AMS_RR		= 0 << NVME_CC_AMS_SHIFT,
4728c8
+	NVME_CC_AMS_WRRU	= 1 << NVME_CC_AMS_SHIFT,
4728c8
+	NVME_CC_AMS_VS		= 7 << NVME_CC_AMS_SHIFT,
4728c8
+	NVME_CC_SHN_NONE	= 0 << NVME_CC_SHN_SHIFT,
4728c8
+	NVME_CC_SHN_NORMAL	= 1 << NVME_CC_SHN_SHIFT,
4728c8
+	NVME_CC_SHN_ABRUPT	= 2 << NVME_CC_SHN_SHIFT,
4728c8
+	NVME_CC_SHN_MASK	= 3 << NVME_CC_SHN_SHIFT,
4728c8
+	NVME_CC_IOSQES		= NVME_NVM_IOSQES << NVME_CC_IOSQES_SHIFT,
4728c8
+	NVME_CC_IOCQES		= NVME_NVM_IOCQES << NVME_CC_IOCQES_SHIFT,
4728c8
+	NVME_CSTS_RDY		= 1 << 0,
4728c8
+	NVME_CSTS_CFS		= 1 << 1,
4728c8
+	NVME_CSTS_NSSRO		= 1 << 4,
4728c8
+	NVME_CSTS_PP		= 1 << 5,
4728c8
+	NVME_CSTS_SHST_NORMAL	= 0 << 2,
4728c8
+	NVME_CSTS_SHST_OCCUR	= 1 << 2,
4728c8
+	NVME_CSTS_SHST_CMPLT	= 2 << 2,
4728c8
+	NVME_CSTS_SHST_MASK	= 3 << 2,
4728c8
+};
4728c8
+
4728c8
+struct nvme_id_power_state {
4728c8
+	__le16			max_power;	/* centiwatts */
4728c8
+	__u8			rsvd2;
4728c8
+	__u8			flags;
4728c8
+	__le32			entry_lat;	/* microseconds */
4728c8
+	__le32			exit_lat;	/* microseconds */
4728c8
+	__u8			read_tput;
4728c8
+	__u8			read_lat;
4728c8
+	__u8			write_tput;
4728c8
+	__u8			write_lat;
4728c8
+	__le16			idle_power;
4728c8
+	__u8			idle_scale;
4728c8
+	__u8			rsvd19;
4728c8
+	__le16			active_power;
4728c8
+	__u8			active_work_scale;
4728c8
+	__u8			rsvd23[9];
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_PS_FLAGS_MAX_POWER_SCALE	= 1 << 0,
4728c8
+	NVME_PS_FLAGS_NON_OP_STATE	= 1 << 1,
4728c8
+};
4728c8
+
4728c8
+struct nvme_id_ctrl {
4728c8
+	__le16			vid;
4728c8
+	__le16			ssvid;
4728c8
+	char			sn[20];
4728c8
+	char			mn[40];
4728c8
+	char			fr[8];
4728c8
+	__u8			rab;
4728c8
+	__u8			ieee[3];
4728c8
+	__u8			cmic;
4728c8
+	__u8			mdts;
4728c8
+	__le16			cntlid;
4728c8
+	__le32			ver;
4728c8
+	__le32			rtd3r;
4728c8
+	__le32			rtd3e;
4728c8
+	__le32			oaes;
4728c8
+	__le32			ctratt;
4728c8
+	__le16			rrls;
4728c8
+	__u8			rsvd102[154];
4728c8
+	__le16			oacs;
4728c8
+	__u8			acl;
4728c8
+	__u8			aerl;
4728c8
+	__u8			frmw;
4728c8
+	__u8			lpa;
4728c8
+	__u8			elpe;
4728c8
+	__u8			npss;
4728c8
+	__u8			avscc;
4728c8
+	__u8			apsta;
4728c8
+	__le16			wctemp;
4728c8
+	__le16			cctemp;
4728c8
+	__le16			mtfa;
4728c8
+	__le32			hmpre;
4728c8
+	__le32			hmmin;
4728c8
+	__u8			tnvmcap[16];
4728c8
+	__u8			unvmcap[16];
4728c8
+	__le32			rpmbs;
4728c8
+	__le16			edstt;
4728c8
+	__u8			dsto;
4728c8
+	__u8			fwug;
4728c8
+	__le16			kas;
4728c8
+	__le16			hctma;
4728c8
+	__le16			mntmt;
4728c8
+	__le16			mxtmt;
4728c8
+	__le32			sanicap;
4728c8
+	__le32			hmminds;
4728c8
+	__le16			hmmaxd;
4728c8
+	__le16			nsetidmax;
4728c8
+	__u8			rsvd340[2];
4728c8
+	__u8			anatt;
4728c8
+	__u8			anacap;
4728c8
+	__le32			anagrpmax;
4728c8
+	__le32			nanagrpid;
4728c8
+	__u8			rsvd352[160];
4728c8
+	__u8			sqes;
4728c8
+	__u8			cqes;
4728c8
+	__le16			maxcmd;
4728c8
+	__le32			nn;
4728c8
+	__le16			oncs;
4728c8
+	__le16			fuses;
4728c8
+	__u8			fna;
4728c8
+	__u8			vwc;
4728c8
+	__le16			awun;
4728c8
+	__le16			awupf;
4728c8
+	__u8			nvscc;
4728c8
+	__u8			nwpc;
4728c8
+	__le16			acwu;
4728c8
+	__u8			rsvd534[2];
4728c8
+	__le32			sgls;
4728c8
+	__le32			mnan;
4728c8
+	__u8			rsvd544[224];
4728c8
+	char			subnqn[256];
4728c8
+	__u8			rsvd1024[768];
4728c8
+	__le32			ioccsz;
4728c8
+	__le32			iorcsz;
4728c8
+	__le16			icdoff;
4728c8
+	__u8			ctrattr;
4728c8
+	__u8			msdbd;
4728c8
+	__u8			rsvd1804[244];
4728c8
+	struct nvme_id_power_state	psd[32];
4728c8
+	__u8			vs[1024];
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_CTRL_ONCS_COMPARE			= 1 << 0,
4728c8
+	NVME_CTRL_ONCS_WRITE_UNCORRECTABLE	= 1 << 1,
4728c8
+	NVME_CTRL_ONCS_DSM			= 1 << 2,
4728c8
+	NVME_CTRL_ONCS_WRITE_ZEROES		= 1 << 3,
4728c8
+	NVME_CTRL_ONCS_TIMESTAMP		= 1 << 6,
4728c8
+	NVME_CTRL_VWC_PRESENT			= 1 << 0,
4728c8
+	NVME_CTRL_OACS_SEC_SUPP                 = 1 << 0,
4728c8
+	NVME_CTRL_OACS_DIRECTIVES		= 1 << 5,
4728c8
+	NVME_CTRL_OACS_DBBUF_SUPP		= 1 << 8,
4728c8
+	NVME_CTRL_LPA_CMD_EFFECTS_LOG		= 1 << 1,
4728c8
+	NVME_CTRL_CTRATT_128_ID			= 1 << 0,
4728c8
+	NVME_CTRL_CTRATT_NON_OP_PSP		= 1 << 1,
4728c8
+	NVME_CTRL_CTRATT_NVM_SETS		= 1 << 2,
4728c8
+	NVME_CTRL_CTRATT_READ_RECV_LVLS		= 1 << 3,
4728c8
+	NVME_CTRL_CTRATT_ENDURANCE_GROUPS	= 1 << 4,
4728c8
+	NVME_CTRL_CTRATT_PREDICTABLE_LAT	= 1 << 5,
4728c8
+};
4728c8
+
4728c8
+struct nvme_lbaf {
4728c8
+	__le16			ms;
4728c8
+	__u8			ds;
4728c8
+	__u8			rp;
4728c8
+};
4728c8
+
4728c8
+struct nvme_id_ns {
4728c8
+	__le64			nsze;
4728c8
+	__le64			ncap;
4728c8
+	__le64			nuse;
4728c8
+	__u8			nsfeat;
4728c8
+	__u8			nlbaf;
4728c8
+	__u8			flbas;
4728c8
+	__u8			mc;
4728c8
+	__u8			dpc;
4728c8
+	__u8			dps;
4728c8
+	__u8			nmic;
4728c8
+	__u8			rescap;
4728c8
+	__u8			fpi;
4728c8
+	__u8			dlfeat;
4728c8
+	__le16			nawun;
4728c8
+	__le16			nawupf;
4728c8
+	__le16			nacwu;
4728c8
+	__le16			nabsn;
4728c8
+	__le16			nabo;
4728c8
+	__le16			nabspf;
4728c8
+	__le16			noiob;
4728c8
+	__u8			nvmcap[16];
4728c8
+	__u8			rsvd64[28];
4728c8
+	__le32			anagrpid;
4728c8
+	__u8			rsvd96[3];
4728c8
+	__u8			nsattr;
4728c8
+	__le16			nvmsetid;
4728c8
+	__le16			endgid;
4728c8
+	__u8			nguid[16];
4728c8
+	__u8			eui64[8];
4728c8
+	struct nvme_lbaf	lbaf[16];
4728c8
+	__u8			rsvd192[192];
4728c8
+	__u8			vs[3712];
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_ID_CNS_NS			= 0x00,
4728c8
+	NVME_ID_CNS_CTRL		= 0x01,
4728c8
+	NVME_ID_CNS_NS_ACTIVE_LIST	= 0x02,
4728c8
+	NVME_ID_CNS_NS_DESC_LIST	= 0x03,
4728c8
+	NVME_ID_CNS_NVMSET_LIST		= 0x04,
4728c8
+	NVME_ID_CNS_NS_PRESENT_LIST	= 0x10,
4728c8
+	NVME_ID_CNS_NS_PRESENT		= 0x11,
4728c8
+	NVME_ID_CNS_CTRL_NS_LIST	= 0x12,
4728c8
+	NVME_ID_CNS_CTRL_LIST		= 0x13,
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_DIR_IDENTIFY		= 0x00,
4728c8
+	NVME_DIR_STREAMS		= 0x01,
4728c8
+	NVME_DIR_SND_ID_OP_ENABLE	= 0x01,
4728c8
+	NVME_DIR_SND_ST_OP_REL_ID	= 0x01,
4728c8
+	NVME_DIR_SND_ST_OP_REL_RSC	= 0x02,
4728c8
+	NVME_DIR_RCV_ID_OP_PARAM	= 0x01,
4728c8
+	NVME_DIR_RCV_ST_OP_PARAM	= 0x01,
4728c8
+	NVME_DIR_RCV_ST_OP_STATUS	= 0x02,
4728c8
+	NVME_DIR_RCV_ST_OP_RESOURCE	= 0x03,
4728c8
+	NVME_DIR_ENDIR			= 0x01,
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_NS_FEAT_THIN	= 1 << 0,
4728c8
+	NVME_NS_FLBAS_LBA_MASK	= 0xf,
4728c8
+	NVME_NS_FLBAS_META_EXT	= 0x10,
4728c8
+	NVME_LBAF_RP_BEST	= 0,
4728c8
+	NVME_LBAF_RP_BETTER	= 1,
4728c8
+	NVME_LBAF_RP_GOOD	= 2,
4728c8
+	NVME_LBAF_RP_DEGRADED	= 3,
4728c8
+	NVME_NS_DPC_PI_LAST	= 1 << 4,
4728c8
+	NVME_NS_DPC_PI_FIRST	= 1 << 3,
4728c8
+	NVME_NS_DPC_PI_TYPE3	= 1 << 2,
4728c8
+	NVME_NS_DPC_PI_TYPE2	= 1 << 1,
4728c8
+	NVME_NS_DPC_PI_TYPE1	= 1 << 0,
4728c8
+	NVME_NS_DPS_PI_FIRST	= 1 << 3,
4728c8
+	NVME_NS_DPS_PI_MASK	= 0x7,
4728c8
+	NVME_NS_DPS_PI_TYPE1	= 1,
4728c8
+	NVME_NS_DPS_PI_TYPE2	= 2,
4728c8
+	NVME_NS_DPS_PI_TYPE3	= 3,
4728c8
+};
4728c8
+
4728c8
+struct nvme_ns_id_desc {
4728c8
+	__u8 nidt;
4728c8
+	__u8 nidl;
4728c8
+	__le16 reserved;
4728c8
+};
4728c8
+
4728c8
+#define NVME_NIDT_EUI64_LEN	8
4728c8
+#define NVME_NIDT_NGUID_LEN	16
4728c8
+#define NVME_NIDT_UUID_LEN	16
4728c8
+
4728c8
+enum {
4728c8
+	NVME_NIDT_EUI64		= 0x01,
4728c8
+	NVME_NIDT_NGUID		= 0x02,
4728c8
+	NVME_NIDT_UUID		= 0x03,
4728c8
+};
4728c8
+
4728c8
+#define NVME_MAX_NVMSET		31
4728c8
+
4728c8
+struct nvme_nvmset_attr_entry {
4728c8
+	__le16			id;
4728c8
+	__le16			endurance_group_id;
4728c8
+	__u8			rsvd4[4];
4728c8
+	__le32			random_4k_read_typical;
4728c8
+	__le32			opt_write_size;
4728c8
+	__u8			total_nvmset_cap[16];
4728c8
+	__u8			unalloc_nvmset_cap[16];
4728c8
+	__u8			rsvd48[80];
4728c8
+};
4728c8
+
4728c8
+struct nvme_id_nvmset {
4728c8
+	__u8				nid;
4728c8
+	__u8				rsvd1[127];
4728c8
+	struct nvme_nvmset_attr_entry	ent[NVME_MAX_NVMSET];
4728c8
+};
4728c8
+
4728c8
+/* Derived from 1.3a Figure 101: Get Log Page – Telemetry Host
4728c8
+ * -Initiated Log (Log Identifier 07h)
4728c8
+ */
4728c8
+struct nvme_telemetry_log_page_hdr {
4728c8
+	__u8    lpi; /* Log page identifier */
4728c8
+	__u8    rsvd[4];
4728c8
+	__u8    iee_oui[3];
4728c8
+	__u16   dalb1; /* Data area 1 last block */
4728c8
+	__u16   dalb2; /* Data area 2 last block */
4728c8
+	__u16   dalb3; /* Data area 3 last block */
4728c8
+	__u8    rsvd1[368]; /* TODO verify */
4728c8
+	__u8    ctrlavail; /* Controller initiated data avail?*/
4728c8
+	__u8    ctrldgn; /* Controller initiated telemetry Data Gen # */
4728c8
+	__u8    rsnident[128];
4728c8
+	/* We'll have to double fetch so we can get the header,
4728c8
+	 * parse dalb1->3 determine how much size we need for the
4728c8
+	 * log then alloc below. Or just do a secondary non-struct
4728c8
+	 * allocation.
4728c8
+	 */
4728c8
+	__u8    telemetry_dataarea[0];
4728c8
+};
4728c8
+
4728c8
+struct nvme_endurance_group_log {
4728c8
+	__u32	rsvd0;
4728c8
+	__u8	avl_spare_threshold;
4728c8
+	__u8	percent_used;
4728c8
+	__u8	rsvd6[26];
4728c8
+	__u8	endurance_estimate[16];
4728c8
+	__u8	data_units_read[16];
4728c8
+	__u8	data_units_written[16];
4728c8
+	__u8	media_units_written[16];
4728c8
+	__u8	rsvd96[416];
4728c8
+};
4728c8
+
4728c8
+struct nvme_smart_log {
4728c8
+	__u8			critical_warning;
4728c8
+	__u8			temperature[2];
4728c8
+	__u8			avail_spare;
4728c8
+	__u8			spare_thresh;
4728c8
+	__u8			percent_used;
4728c8
+	__u8			rsvd6[26];
4728c8
+	__u8			data_units_read[16];
4728c8
+	__u8			data_units_written[16];
4728c8
+	__u8			host_reads[16];
4728c8
+	__u8			host_writes[16];
4728c8
+	__u8			ctrl_busy_time[16];
4728c8
+	__u8			power_cycles[16];
4728c8
+	__u8			power_on_hours[16];
4728c8
+	__u8			unsafe_shutdowns[16];
4728c8
+	__u8			media_errors[16];
4728c8
+	__u8			num_err_log_entries[16];
4728c8
+	__le32			warning_temp_time;
4728c8
+	__le32			critical_comp_time;
4728c8
+	__le16			temp_sensor[8];
4728c8
+	__le32			thm_temp1_trans_count;
4728c8
+	__le32			thm_temp2_trans_count;
4728c8
+	__le32			thm_temp1_total_time;
4728c8
+	__le32			thm_temp2_total_time;
4728c8
+	__u8			rsvd232[280];
4728c8
+};
4728c8
+
4728c8
+struct nvme_self_test_res {
4728c8
+	__u8 			device_self_test_status;
4728c8
+	__u8			segment_num;
4728c8
+	__u8			valid_diagnostic_info;
4728c8
+	__u8			rsvd;
4728c8
+	__le64			power_on_hours;
4728c8
+	__le32			nsid;
4728c8
+	__le64			failing_lba;
4728c8
+	__u8			status_code_type;
4728c8
+	__u8			status_code;
4728c8
+	__u8			vendor_specific[2];
4728c8
+} __attribute__((packed));
4728c8
+
4728c8
+struct nvme_self_test_log {
4728c8
+	__u8                      crnt_dev_selftest_oprn;
4728c8
+	__u8                      crnt_dev_selftest_compln;
4728c8
+	__u8                      rsvd[2];
4728c8
+	struct nvme_self_test_res result[20];
4728c8
+} __attribute__((packed));
4728c8
+
4728c8
+struct nvme_fw_slot_info_log {
4728c8
+	__u8			afi;
4728c8
+	__u8			rsvd1[7];
4728c8
+	__le64			frs[7];
4728c8
+	__u8			rsvd64[448];
4728c8
+};
4728c8
+
4728c8
+/* NVMe Namespace Write Protect State */
4728c8
+enum {
4728c8
+	NVME_NS_NO_WRITE_PROTECT = 0,
4728c8
+	NVME_NS_WRITE_PROTECT,
4728c8
+	NVME_NS_WRITE_PROTECT_POWER_CYCLE,
4728c8
+	NVME_NS_WRITE_PROTECT_PERMANENT,
4728c8
+};
4728c8
+
4728c8
+#define NVME_MAX_CHANGED_NAMESPACES     1024
4728c8
+
4728c8
+struct nvme_changed_ns_list_log {
4728c8
+	__le32			log[NVME_MAX_CHANGED_NAMESPACES];
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_CMD_EFFECTS_CSUPP		= 1 << 0,
4728c8
+	NVME_CMD_EFFECTS_LBCC		= 1 << 1,
4728c8
+	NVME_CMD_EFFECTS_NCC		= 1 << 2,
4728c8
+	NVME_CMD_EFFECTS_NIC		= 1 << 3,
4728c8
+	NVME_CMD_EFFECTS_CCC		= 1 << 4,
4728c8
+	NVME_CMD_EFFECTS_CSE_MASK	= 3 << 16,
4728c8
+};
4728c8
+
4728c8
+struct nvme_effects_log {
4728c8
+	__le32 acs[256];
4728c8
+	__le32 iocs[256];
4728c8
+	__u8   resv[2048];
4728c8
+};
4728c8
+
4728c8
+enum nvme_ana_state {
4728c8
+	NVME_ANA_OPTIMIZED		= 0x01,
4728c8
+	NVME_ANA_NONOPTIMIZED		= 0x02,
4728c8
+	NVME_ANA_INACCESSIBLE		= 0x03,
4728c8
+	NVME_ANA_PERSISTENT_LOSS	= 0x04,
4728c8
+	NVME_ANA_CHANGE			= 0x0f,
4728c8
+};
4728c8
+
4728c8
+struct nvme_ana_group_desc {
4728c8
+	__le32  grpid;
4728c8
+	__le32  nnsids;
4728c8
+	__le64  chgcnt;
4728c8
+	__u8    state;
4728c8
+	__u8    rsvd17[15];
4728c8
+	__le32  nsids[];
4728c8
+};
4728c8
+
4728c8
+/* flag for the log specific field of the ANA log */
4728c8
+#define NVME_ANA_LOG_RGO   (1 << 0)
4728c8
+
4728c8
+struct nvme_ana_rsp_hdr {
4728c8
+	__le64  chgcnt;
4728c8
+	__le16  ngrps;
4728c8
+	__le16  rsvd10[3];
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_SMART_CRIT_SPARE		= 1 << 0,
4728c8
+	NVME_SMART_CRIT_TEMPERATURE	= 1 << 1,
4728c8
+	NVME_SMART_CRIT_RELIABILITY	= 1 << 2,
4728c8
+	NVME_SMART_CRIT_MEDIA		= 1 << 3,
4728c8
+	NVME_SMART_CRIT_VOLATILE_MEMORY	= 1 << 4,
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_AER_ERROR			= 0,
4728c8
+	NVME_AER_SMART			= 1,
4728c8
+	NVME_AER_CSS			= 6,
4728c8
+	NVME_AER_VS			= 7,
4728c8
+	NVME_AER_NOTICE_NS_CHANGED	= 0x0002,
4728c8
+	NVME_AER_NOTICE_ANA		= 0x0003,
4728c8
+	NVME_AER_NOTICE_FW_ACT_STARTING = 0x0102,
4728c8
+};
4728c8
+
4728c8
+struct nvme_lba_range_type {
4728c8
+	__u8			type;
4728c8
+	__u8			attributes;
4728c8
+	__u8			rsvd2[14];
4728c8
+	__u64			slba;
4728c8
+	__u64			nlb;
4728c8
+	__u8			guid[16];
4728c8
+	__u8			rsvd48[16];
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_LBART_TYPE_FS	= 0x01,
4728c8
+	NVME_LBART_TYPE_RAID	= 0x02,
4728c8
+	NVME_LBART_TYPE_CACHE	= 0x03,
4728c8
+	NVME_LBART_TYPE_SWAP	= 0x04,
4728c8
+
4728c8
+	NVME_LBART_ATTRIB_TEMP	= 1 << 0,
4728c8
+	NVME_LBART_ATTRIB_HIDE	= 1 << 1,
4728c8
+};
4728c8
+
4728c8
+struct nvme_plm_config {
4728c8
+	__u16	enable_event;
4728c8
+	__u8	rsvd2[30];
4728c8
+	__u64	dtwin_reads_thresh;
4728c8
+	__u64	dtwin_writes_thresh;
4728c8
+	__u64	dtwin_time_thresh;
4728c8
+	__u8	rsvd56[456];
4728c8
+};
4728c8
+
4728c8
+struct nvme_reservation_status {
4728c8
+	__le32	gen;
4728c8
+	__u8	rtype;
4728c8
+	__u8	regctl[2];
4728c8
+	__u8	resv5[2];
4728c8
+	__u8	ptpls;
4728c8
+	__u8	resv10[13];
4728c8
+	struct {
4728c8
+		__le16	cntlid;
4728c8
+		__u8	rcsts;
4728c8
+		__u8	resv3[5];
4728c8
+		__le64	hostid;
4728c8
+		__le64	rkey;
4728c8
+	} regctl_ds[];
4728c8
+};
4728c8
+
4728c8
+struct nvme_reservation_status_ext {
4728c8
+	__le32	gen;
4728c8
+	__u8	rtype;
4728c8
+	__u8	regctl[2];
4728c8
+	__u8	resv5[2];
4728c8
+	__u8	ptpls;
4728c8
+	__u8	resv10[14];
4728c8
+	__u8	resv24[40];
4728c8
+	struct {
4728c8
+		__le16	cntlid;
4728c8
+		__u8	rcsts;
4728c8
+		__u8	resv3[5];
4728c8
+		__le64	rkey;
4728c8
+		__u8	hostid[16];
4728c8
+		__u8	resv32[32];
4728c8
+	} regctl_eds[];
4728c8
+};
4728c8
+
4728c8
+enum nvme_async_event_type {
4728c8
+	NVME_AER_TYPE_ERROR	= 0,
4728c8
+	NVME_AER_TYPE_SMART	= 1,
4728c8
+	NVME_AER_TYPE_NOTICE	= 2,
4728c8
+};
4728c8
+
4728c8
+/* I/O commands */
4728c8
+
4728c8
+enum nvme_opcode {
4728c8
+	nvme_cmd_flush		= 0x00,
4728c8
+	nvme_cmd_write		= 0x01,
4728c8
+	nvme_cmd_read		= 0x02,
4728c8
+	nvme_cmd_write_uncor	= 0x04,
4728c8
+	nvme_cmd_compare	= 0x05,
4728c8
+	nvme_cmd_write_zeroes	= 0x08,
4728c8
+	nvme_cmd_dsm		= 0x09,
4728c8
+	nvme_cmd_resv_register	= 0x0d,
4728c8
+	nvme_cmd_resv_report	= 0x0e,
4728c8
+	nvme_cmd_resv_acquire	= 0x11,
4728c8
+	nvme_cmd_resv_release	= 0x15,
4728c8
+};
4728c8
+
4728c8
+/*
4728c8
+ * Descriptor subtype - lower 4 bits of nvme_(keyed_)sgl_desc identifier
4728c8
+ *
4728c8
+ * @NVME_SGL_FMT_ADDRESS:     absolute address of the data block
4728c8
+ * @NVME_SGL_FMT_OFFSET:      relative offset of the in-capsule data block
4728c8
+ * @NVME_SGL_FMT_TRANSPORT_A: transport defined format, value 0xA
4728c8
+ * @NVME_SGL_FMT_INVALIDATE:  RDMA transport specific remote invalidation
4728c8
+ *                            request subtype
4728c8
+ */
4728c8
+enum {
4728c8
+	NVME_SGL_FMT_ADDRESS		= 0x00,
4728c8
+	NVME_SGL_FMT_OFFSET		= 0x01,
4728c8
+	NVME_SGL_FMT_TRANSPORT_A	= 0x0A,
4728c8
+	NVME_SGL_FMT_INVALIDATE		= 0x0f,
4728c8
+};
4728c8
+
4728c8
+/*
4728c8
+ * Descriptor type - upper 4 bits of nvme_(keyed_)sgl_desc identifier
4728c8
+ *
4728c8
+ * For struct nvme_sgl_desc:
4728c8
+ *   @NVME_SGL_FMT_DATA_DESC:		data block descriptor
4728c8
+ *   @NVME_SGL_FMT_SEG_DESC:		sgl segment descriptor
4728c8
+ *   @NVME_SGL_FMT_LAST_SEG_DESC:	last sgl segment descriptor
4728c8
+ *
4728c8
+ * For struct nvme_keyed_sgl_desc:
4728c8
+ *   @NVME_KEY_SGL_FMT_DATA_DESC:	keyed data block descriptor
4728c8
+ *
4728c8
+ * Transport-specific SGL types:
4728c8
+ *   @NVME_TRANSPORT_SGL_DATA_DESC:	Transport SGL data dlock descriptor
4728c8
+ */
4728c8
+enum {
4728c8
+	NVME_SGL_FMT_DATA_DESC		= 0x00,
4728c8
+	NVME_SGL_FMT_SEG_DESC		= 0x02,
4728c8
+	NVME_SGL_FMT_LAST_SEG_DESC	= 0x03,
4728c8
+	NVME_KEY_SGL_FMT_DATA_DESC	= 0x04,
4728c8
+	NVME_TRANSPORT_SGL_DATA_DESC	= 0x05,
4728c8
+};
4728c8
+
4728c8
+struct nvme_sgl_desc {
4728c8
+	__le64	addr;
4728c8
+	__le32	length;
4728c8
+	__u8	rsvd[3];
4728c8
+	__u8	type;
4728c8
+};
4728c8
+
4728c8
+struct nvme_keyed_sgl_desc {
4728c8
+	__le64	addr;
4728c8
+	__u8	length[3];
4728c8
+	__u8	key[4];
4728c8
+	__u8	type;
4728c8
+};
4728c8
+
4728c8
+union nvme_data_ptr {
4728c8
+	struct {
4728c8
+		__le64	prp1;
4728c8
+		__le64	prp2;
4728c8
+	};
4728c8
+	struct nvme_sgl_desc	sgl;
4728c8
+	struct nvme_keyed_sgl_desc ksgl;
4728c8
+};
4728c8
+
4728c8
+/*
4728c8
+ * Lowest two bits of our flags field (FUSE field in the spec):
4728c8
+ *
4728c8
+ * @NVME_CMD_FUSE_FIRST:   Fused Operation, first command
4728c8
+ * @NVME_CMD_FUSE_SECOND:  Fused Operation, second command
4728c8
+ *
4728c8
+ * Highest two bits in our flags field (PSDT field in the spec):
4728c8
+ *
4728c8
+ * @NVME_CMD_PSDT_SGL_METABUF:	Use SGLS for this transfer,
4728c8
+ *	If used, MPTR contains addr of single physical buffer (byte aligned).
4728c8
+ * @NVME_CMD_PSDT_SGL_METASEG:	Use SGLS for this transfer,
4728c8
+ *	If used, MPTR contains an address of an SGL segment containing
4728c8
+ *	exactly 1 SGL descriptor (qword aligned).
4728c8
+ */
4728c8
+enum {
4728c8
+	NVME_CMD_FUSE_FIRST	= (1 << 0),
4728c8
+	NVME_CMD_FUSE_SECOND	= (1 << 1),
4728c8
+
4728c8
+	NVME_CMD_SGL_METABUF	= (1 << 6),
4728c8
+	NVME_CMD_SGL_METASEG	= (1 << 7),
4728c8
+	NVME_CMD_SGL_ALL	= NVME_CMD_SGL_METABUF | NVME_CMD_SGL_METASEG,
4728c8
+};
4728c8
+
4728c8
+struct nvme_common_command {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__le32			nsid;
4728c8
+	__le32			cdw2[2];
4728c8
+	__le64			metadata;
4728c8
+	union nvme_data_ptr	dptr;
4728c8
+	__le32			cdw10[6];
4728c8
+};
4728c8
+
4728c8
+struct nvme_rw_command {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__le32			nsid;
4728c8
+	__u64			rsvd2;
4728c8
+	__le64			metadata;
4728c8
+	union nvme_data_ptr	dptr;
4728c8
+	__le64			slba;
4728c8
+	__le16			length;
4728c8
+	__le16			control;
4728c8
+	__le32			dsmgmt;
4728c8
+	__le32			reftag;
4728c8
+	__le16			apptag;
4728c8
+	__le16			appmask;
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_RW_LR			= 1 << 15,
4728c8
+	NVME_RW_FUA			= 1 << 14,
4728c8
+	NVME_RW_DEAC			= 1 << 9,
4728c8
+	NVME_RW_DSM_FREQ_UNSPEC		= 0,
4728c8
+	NVME_RW_DSM_FREQ_TYPICAL	= 1,
4728c8
+	NVME_RW_DSM_FREQ_RARE		= 2,
4728c8
+	NVME_RW_DSM_FREQ_READS		= 3,
4728c8
+	NVME_RW_DSM_FREQ_WRITES		= 4,
4728c8
+	NVME_RW_DSM_FREQ_RW		= 5,
4728c8
+	NVME_RW_DSM_FREQ_ONCE		= 6,
4728c8
+	NVME_RW_DSM_FREQ_PREFETCH	= 7,
4728c8
+	NVME_RW_DSM_FREQ_TEMP		= 8,
4728c8
+	NVME_RW_DSM_LATENCY_NONE	= 0 << 4,
4728c8
+	NVME_RW_DSM_LATENCY_IDLE	= 1 << 4,
4728c8
+	NVME_RW_DSM_LATENCY_NORM	= 2 << 4,
4728c8
+	NVME_RW_DSM_LATENCY_LOW		= 3 << 4,
4728c8
+	NVME_RW_DSM_SEQ_REQ		= 1 << 6,
4728c8
+	NVME_RW_DSM_COMPRESSED		= 1 << 7,
4728c8
+	NVME_RW_PRINFO_PRCHK_REF	= 1 << 10,
4728c8
+	NVME_RW_PRINFO_PRCHK_APP	= 1 << 11,
4728c8
+	NVME_RW_PRINFO_PRCHK_GUARD	= 1 << 12,
4728c8
+	NVME_RW_PRINFO_PRACT		= 1 << 13,
4728c8
+	NVME_RW_DTYPE_STREAMS		= 1 << 4,
4728c8
+};
4728c8
+
4728c8
+struct nvme_dsm_cmd {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__le32			nsid;
4728c8
+	__u64			rsvd2[2];
4728c8
+	union nvme_data_ptr	dptr;
4728c8
+	__le32			nr;
4728c8
+	__le32			attributes;
4728c8
+	__u32			rsvd12[4];
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_DSMGMT_IDR		= 1 << 0,
4728c8
+	NVME_DSMGMT_IDW		= 1 << 1,
4728c8
+	NVME_DSMGMT_AD		= 1 << 2,
4728c8
+};
4728c8
+
4728c8
+#define NVME_DSM_MAX_RANGES	256
4728c8
+
4728c8
+struct nvme_dsm_range {
4728c8
+	__le32			cattr;
4728c8
+	__le32			nlb;
4728c8
+	__le64			slba;
4728c8
+};
4728c8
+
4728c8
+struct nvme_write_zeroes_cmd {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__le32			nsid;
4728c8
+	__u64			rsvd2;
4728c8
+	__le64			metadata;
4728c8
+	union nvme_data_ptr	dptr;
4728c8
+	__le64			slba;
4728c8
+	__le16			length;
4728c8
+	__le16			control;
4728c8
+	__le32			dsmgmt;
4728c8
+	__le32			reftag;
4728c8
+	__le16			apptag;
4728c8
+	__le16			appmask;
4728c8
+};
4728c8
+
4728c8
+/* Features */
4728c8
+
4728c8
+struct nvme_feat_auto_pst {
4728c8
+	__le64 entries[32];
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_HOST_MEM_ENABLE	= (1 << 0),
4728c8
+	NVME_HOST_MEM_RETURN	= (1 << 1),
4728c8
+};
4728c8
+
4728c8
+/* Admin commands */
4728c8
+
4728c8
+enum nvme_admin_opcode {
4728c8
+	nvme_admin_delete_sq		= 0x00,
4728c8
+	nvme_admin_create_sq		= 0x01,
4728c8
+	nvme_admin_get_log_page		= 0x02,
4728c8
+	nvme_admin_delete_cq		= 0x04,
4728c8
+	nvme_admin_create_cq		= 0x05,
4728c8
+	nvme_admin_identify		= 0x06,
4728c8
+	nvme_admin_abort_cmd		= 0x08,
4728c8
+	nvme_admin_set_features		= 0x09,
4728c8
+	nvme_admin_get_features		= 0x0a,
4728c8
+	nvme_admin_async_event		= 0x0c,
4728c8
+	nvme_admin_ns_mgmt		= 0x0d,
4728c8
+	nvme_admin_activate_fw		= 0x10,
4728c8
+	nvme_admin_download_fw		= 0x11,
4728c8
+	nvme_admin_dev_self_test	= 0x14,
4728c8
+	nvme_admin_ns_attach		= 0x15,
4728c8
+	nvme_admin_keep_alive		= 0x18,
4728c8
+	nvme_admin_directive_send	= 0x19,
4728c8
+	nvme_admin_directive_recv	= 0x1a,
4728c8
+	nvme_admin_virtual_mgmt		= 0x1c,
4728c8
+	nvme_admin_nvme_mi_send		= 0x1d,
4728c8
+	nvme_admin_nvme_mi_recv		= 0x1e,
4728c8
+	nvme_admin_dbbuf		= 0x7C,
4728c8
+	nvme_admin_format_nvm		= 0x80,
4728c8
+	nvme_admin_security_send	= 0x81,
4728c8
+	nvme_admin_security_recv	= 0x82,
4728c8
+	nvme_admin_sanitize_nvm		= 0x84,
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_QUEUE_PHYS_CONTIG	= (1 << 0),
4728c8
+	NVME_CQ_IRQ_ENABLED	= (1 << 1),
4728c8
+	NVME_SQ_PRIO_URGENT	= (0 << 1),
4728c8
+	NVME_SQ_PRIO_HIGH	= (1 << 1),
4728c8
+	NVME_SQ_PRIO_MEDIUM	= (2 << 1),
4728c8
+	NVME_SQ_PRIO_LOW	= (3 << 1),
4728c8
+	NVME_FEAT_ARBITRATION	= 0x01,
4728c8
+	NVME_FEAT_POWER_MGMT	= 0x02,
4728c8
+	NVME_FEAT_LBA_RANGE	= 0x03,
4728c8
+	NVME_FEAT_TEMP_THRESH	= 0x04,
4728c8
+	NVME_FEAT_ERR_RECOVERY	= 0x05,
4728c8
+	NVME_FEAT_VOLATILE_WC	= 0x06,
4728c8
+	NVME_FEAT_NUM_QUEUES	= 0x07,
4728c8
+	NVME_FEAT_IRQ_COALESCE	= 0x08,
4728c8
+	NVME_FEAT_IRQ_CONFIG	= 0x09,
4728c8
+	NVME_FEAT_WRITE_ATOMIC	= 0x0a,
4728c8
+	NVME_FEAT_ASYNC_EVENT	= 0x0b,
4728c8
+	NVME_FEAT_AUTO_PST	= 0x0c,
4728c8
+	NVME_FEAT_HOST_MEM_BUF	= 0x0d,
4728c8
+	NVME_FEAT_TIMESTAMP	= 0x0e,
4728c8
+	NVME_FEAT_KATO		= 0x0f,
4728c8
+	NVME_FEAT_HCTM		= 0X10,
4728c8
+	NVME_FEAT_NOPSC		= 0X11,
4728c8
+	NVME_FEAT_RRL		= 0x12,
4728c8
+	NVME_FEAT_PLM_CONFIG	= 0x13,
4728c8
+	NVME_FEAT_PLM_WINDOW	= 0x14,
4728c8
+	NVME_FEAT_SW_PROGRESS	= 0x80,
4728c8
+	NVME_FEAT_HOST_ID	= 0x81,
4728c8
+	NVME_FEAT_RESV_MASK	= 0x82,
4728c8
+	NVME_FEAT_RESV_PERSIST	= 0x83,
4728c8
+	NVME_FEAT_WRITE_PROTECT	= 0x84,
4728c8
+	NVME_LOG_ERROR		= 0x01,
4728c8
+	NVME_LOG_SMART		= 0x02,
4728c8
+	NVME_LOG_FW_SLOT	= 0x03,
4728c8
+	NVME_LOG_CHANGED_NS	= 0x04,
4728c8
+	NVME_LOG_CMD_EFFECTS	= 0x05,
4728c8
+	NVME_LOG_DEVICE_SELF_TEST = 0x06,
4728c8
+	NVME_LOG_TELEMETRY_HOST = 0x07,
4728c8
+	NVME_LOG_TELEMETRY_CTRL = 0x08,
4728c8
+	NVME_LOG_ENDURANCE_GROUP = 0x09,
4728c8
+	NVME_LOG_ANA		= 0x0c,
4728c8
+	NVME_LOG_DISC		= 0x70,
4728c8
+	NVME_LOG_RESERVATION	= 0x80,
4728c8
+	NVME_LOG_SANITIZE	= 0x81,
4728c8
+	NVME_FWACT_REPL		= (0 << 3),
4728c8
+	NVME_FWACT_REPL_ACTV	= (1 << 3),
4728c8
+	NVME_FWACT_ACTV		= (2 << 3),
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	NVME_NO_LOG_LSP       = 0x0,
4728c8
+	NVME_NO_LOG_LPO       = 0x0,
4728c8
+	NVME_LOG_ANA_LSP_RGO  = 0x1,
4728c8
+	NVME_TELEM_LSP_CREATE = 0x1,
4728c8
+};
4728c8
+
4728c8
+/* Sanitize and Sanitize Monitor/Log */
4728c8
+enum {
4728c8
+	/* Sanitize */
4728c8
+	NVME_SANITIZE_NO_DEALLOC	= 0x00000200,
4728c8
+	NVME_SANITIZE_OIPBP		= 0x00000100,
4728c8
+	NVME_SANITIZE_OWPASS_SHIFT	= 0x00000004,
4728c8
+	NVME_SANITIZE_AUSE		= 0x00000008,
4728c8
+	NVME_SANITIZE_ACT_CRYPTO_ERASE	= 0x00000004,
4728c8
+	NVME_SANITIZE_ACT_OVERWRITE	= 0x00000003,
4728c8
+	NVME_SANITIZE_ACT_BLOCK_ERASE	= 0x00000002,
4728c8
+	NVME_SANITIZE_ACT_EXIT		= 0x00000001,
4728c8
+
4728c8
+	/* Sanitize Monitor/Log */
4728c8
+	NVME_SANITIZE_LOG_DATA_LEN		= 0x0014,
4728c8
+	NVME_SANITIZE_LOG_GLOBAL_DATA_ERASED	= 0x0100,
4728c8
+	NVME_SANITIZE_LOG_NUM_CMPLTED_PASS_MASK	= 0x00F8,
4728c8
+	NVME_SANITIZE_LOG_STATUS_MASK		= 0x0007,
4728c8
+	NVME_SANITIZE_LOG_NEVER_SANITIZED	= 0x0000,
4728c8
+	NVME_SANITIZE_LOG_COMPLETED_SUCCESS	= 0x0001,
4728c8
+	NVME_SANITIZE_LOG_IN_PROGESS		= 0x0002,
4728c8
+	NVME_SANITIZE_LOG_COMPLETED_FAILED	= 0x0003,
4728c8
+};
4728c8
+
4728c8
+enum {
4728c8
+	/* Self-test log Validation bits */
4728c8
+	NVME_SELF_TEST_VALID_NSID	= 1 << 0,
4728c8
+	NVME_SELF_TEST_VALID_FLBA	= 1 << 1,
4728c8
+	NVME_SELF_TEST_VALID_SCT	= 1 << 2,
4728c8
+	NVME_SELF_TEST_VALID_SC		= 1 << 3,
4728c8
+	NVME_SELF_TEST_REPORTS		= 20,
4728c8
+};
4728c8
+
4728c8
+struct nvme_identify {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__le32			nsid;
4728c8
+	__u64			rsvd2[2];
4728c8
+	union nvme_data_ptr	dptr;
4728c8
+	__u8			cns;
4728c8
+	__u8			rsvd3;
4728c8
+	__le16			ctrlid;
4728c8
+	__u32			rsvd11[5];
4728c8
+};
4728c8
+
4728c8
+#define NVME_IDENTIFY_DATA_SIZE 4096
4728c8
+
4728c8
+struct nvme_features {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__le32			nsid;
4728c8
+	__u64			rsvd2[2];
4728c8
+	union nvme_data_ptr	dptr;
4728c8
+	__le32			fid;
4728c8
+	__le32			dword11;
4728c8
+	__le32                  dword12;
4728c8
+	__le32                  dword13;
4728c8
+	__le32                  dword14;
4728c8
+	__le32                  dword15;
4728c8
+};
4728c8
+
4728c8
+struct nvme_host_mem_buf_desc {
4728c8
+	__le64			addr;
4728c8
+	__le32			size;
4728c8
+	__u32			rsvd;
4728c8
+};
4728c8
+
4728c8
+struct nvme_create_cq {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__u32			rsvd1[5];
4728c8
+	__le64			prp1;
4728c8
+	__u64			rsvd8;
4728c8
+	__le16			cqid;
4728c8
+	__le16			qsize;
4728c8
+	__le16			cq_flags;
4728c8
+	__le16			irq_vector;
4728c8
+	__u32			rsvd12[4];
4728c8
+};
4728c8
+
4728c8
+struct nvme_create_sq {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__u32			rsvd1[5];
4728c8
+	__le64			prp1;
4728c8
+	__u64			rsvd8;
4728c8
+	__le16			sqid;
4728c8
+	__le16			qsize;
4728c8
+	__le16			sq_flags;
4728c8
+	__le16			cqid;
4728c8
+	__u32			rsvd12[4];
4728c8
+};
4728c8
+
4728c8
+struct nvme_delete_queue {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__u32			rsvd1[9];
4728c8
+	__le16			qid;
4728c8
+	__u16			rsvd10;
4728c8
+	__u32			rsvd11[5];
4728c8
+};
4728c8
+
4728c8
+struct nvme_abort_cmd {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__u32			rsvd1[9];
4728c8
+	__le16			sqid;
4728c8
+	__u16			cid;
4728c8
+	__u32			rsvd11[5];
4728c8
+};
4728c8
+
4728c8
+struct nvme_download_firmware {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__u32			rsvd1[5];
4728c8
+	union nvme_data_ptr	dptr;
4728c8
+	__le32			numd;
4728c8
+	__le32			offset;
4728c8
+	__u32			rsvd12[4];
4728c8
+};
4728c8
+
4728c8
+struct nvme_format_cmd {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__le32			nsid;
4728c8
+	__u64			rsvd2[4];
4728c8
+	__le32			cdw10;
4728c8
+	__u32			rsvd11[5];
4728c8
+};
4728c8
+
4728c8
+struct nvme_get_log_page_command {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__le32			nsid;
4728c8
+	__u64			rsvd2[2];
4728c8
+	union nvme_data_ptr	dptr;
4728c8
+	__u8			lid;
4728c8
+	__u8			lsp;
4728c8
+	__le16			numdl;
4728c8
+	__le16			numdu;
4728c8
+	__u16			rsvd11;
4728c8
+	__le32			lpol;
4728c8
+	__le32			lpou;
4728c8
+	__u32			rsvd14[2];
4728c8
+};
4728c8
+
4728c8
+struct nvme_directive_cmd {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__le32			nsid;
4728c8
+	__u64			rsvd2[2];
4728c8
+	union nvme_data_ptr	dptr;
4728c8
+	__le32			numd;
4728c8
+	__u8			doper;
4728c8
+	__u8			dtype;
4728c8
+	__le16			dspec;
4728c8
+	__u8			endir;
4728c8
+	__u8			tdtype;
4728c8
+	__u16			rsvd15;
4728c8
+
4728c8
+	__u32			rsvd16[3];
4728c8
+};
4728c8
+
4728c8
+/* Sanitize Log Page */
4728c8
+struct nvme_sanitize_log_page {
4728c8
+	__le16			progress;
4728c8
+	__le16			status;
4728c8
+	__le32			cdw10_info;
4728c8
+	__le32			est_ovrwrt_time;
4728c8
+	__le32			est_blk_erase_time;
4728c8
+	__le32			est_crypto_erase_time;
4728c8
+};
4728c8
+
4728c8
+/*
4728c8
+ * Fabrics subcommands.
4728c8
+ */
4728c8
+enum nvmf_fabrics_opcode {
4728c8
+	nvme_fabrics_command		= 0x7f,
4728c8
+};
4728c8
+
4728c8
+enum nvmf_capsule_command {
4728c8
+	nvme_fabrics_type_property_set	= 0x00,
4728c8
+	nvme_fabrics_type_connect	= 0x01,
4728c8
+	nvme_fabrics_type_property_get	= 0x04,
4728c8
+};
4728c8
+
4728c8
+struct nvmf_common_command {
4728c8
+	__u8	opcode;
4728c8
+	__u8	resv1;
4728c8
+	__u16	command_id;
4728c8
+	__u8	fctype;
4728c8
+	__u8	resv2[35];
4728c8
+	__u8	ts[24];
4728c8
+};
4728c8
+
4728c8
+/*
4728c8
+ * The legal cntlid range a NVMe Target will provide.
4728c8
+ * Note that cntlid of value 0 is considered illegal in the fabrics world.
4728c8
+ * Devices based on earlier specs did not have the subsystem concept;
4728c8
+ * therefore, those devices had their cntlid value set to 0 as a result.
4728c8
+ */
4728c8
+#define NVME_CNTLID_MIN		1
4728c8
+#define NVME_CNTLID_MAX		0xffef
4728c8
+#define NVME_CNTLID_DYNAMIC	0xffff
4728c8
+
4728c8
+#define MAX_DISC_LOGS	255
4728c8
+
4728c8
+/* Discovery log page entry */
4728c8
+struct nvmf_disc_rsp_page_entry {
4728c8
+	__u8		trtype;
4728c8
+	__u8		adrfam;
4728c8
+	__u8		subtype;
4728c8
+	__u8		treq;
4728c8
+	__le16		portid;
4728c8
+	__le16		cntlid;
4728c8
+	__le16		asqsz;
4728c8
+	__u8		resv8[22];
4728c8
+	char		trsvcid[NVMF_TRSVCID_SIZE];
4728c8
+	__u8		resv64[192];
4728c8
+	char		subnqn[NVMF_NQN_FIELD_LEN];
4728c8
+	char		traddr[NVMF_TRADDR_SIZE];
4728c8
+	union tsas {
4728c8
+		char		common[NVMF_TSAS_SIZE];
4728c8
+		struct rdma {
4728c8
+			__u8	qptype;
4728c8
+			__u8	prtype;
4728c8
+			__u8	cms;
4728c8
+			__u8	resv3[5];
4728c8
+			__u16	pkey;
4728c8
+			__u8	resv10[246];
4728c8
+		} rdma;
4728c8
+		struct tcp {
4728c8
+			__u8	sectype;
4728c8
+		} tcp;
4728c8
+	} tsas;
4728c8
+};
4728c8
+
4728c8
+/* Discovery log page header */
4728c8
+struct nvmf_disc_rsp_page_hdr {
4728c8
+	__le64		genctr;
4728c8
+	__le64		numrec;
4728c8
+	__le16		recfmt;
4728c8
+	__u8		resv14[1006];
4728c8
+	struct nvmf_disc_rsp_page_entry entries[0];
4728c8
+};
4728c8
+
4728c8
+struct nvmf_connect_command {
4728c8
+	__u8		opcode;
4728c8
+	__u8		resv1;
4728c8
+	__u16		command_id;
4728c8
+	__u8		fctype;
4728c8
+	__u8		resv2[19];
4728c8
+	union nvme_data_ptr dptr;
4728c8
+	__le16		recfmt;
4728c8
+	__le16		qid;
4728c8
+	__le16		sqsize;
4728c8
+	__u8		cattr;
4728c8
+	__u8		resv3;
4728c8
+	__le32		kato;
4728c8
+	__u8		resv4[12];
4728c8
+};
4728c8
+
4728c8
+struct nvmf_connect_data {
4728c8
+	uuid_t		hostid;
4728c8
+	__le16		cntlid;
4728c8
+	char		resv4[238];
4728c8
+	char		subsysnqn[NVMF_NQN_FIELD_LEN];
4728c8
+	char		hostnqn[NVMF_NQN_FIELD_LEN];
4728c8
+	char		resv5[256];
4728c8
+};
4728c8
+
4728c8
+struct nvmf_property_set_command {
4728c8
+	__u8		opcode;
4728c8
+	__u8		resv1;
4728c8
+	__u16		command_id;
4728c8
+	__u8		fctype;
4728c8
+	__u8		resv2[35];
4728c8
+	__u8		attrib;
4728c8
+	__u8		resv3[3];
4728c8
+	__le32		offset;
4728c8
+	__le64		value;
4728c8
+	__u8		resv4[8];
4728c8
+};
4728c8
+
4728c8
+struct nvmf_property_get_command {
4728c8
+	__u8		opcode;
4728c8
+	__u8		resv1;
4728c8
+	__u16		command_id;
4728c8
+	__u8		fctype;
4728c8
+	__u8		resv2[35];
4728c8
+	__u8		attrib;
4728c8
+	__u8		resv3[3];
4728c8
+	__le32		offset;
4728c8
+	__u8		resv4[16];
4728c8
+};
4728c8
+
4728c8
+struct nvme_dbbuf {
4728c8
+	__u8			opcode;
4728c8
+	__u8			flags;
4728c8
+	__u16			command_id;
4728c8
+	__u32			rsvd1[5];
4728c8
+	__le64			prp1;
4728c8
+	__le64			prp2;
4728c8
+	__u32			rsvd12[6];
4728c8
+};
4728c8
+
4728c8
+struct streams_directive_params {
4728c8
+	__le16	msl;
4728c8
+	__le16	nssa;
4728c8
+	__le16	nsso;
4728c8
+	__u8	rsvd[10];
4728c8
+	__le32	sws;
4728c8
+	__le16	sgs;
4728c8
+	__le16	nsa;
4728c8
+	__le16	nso;
4728c8
+	__u8	rsvd2[6];
4728c8
+};
4728c8
+
4728c8
+struct nvme_command {
4728c8
+	union {
4728c8
+		struct nvme_common_command common;
4728c8
+		struct nvme_rw_command rw;
4728c8
+		struct nvme_identify identify;
4728c8
+		struct nvme_features features;
4728c8
+		struct nvme_create_cq create_cq;
4728c8
+		struct nvme_create_sq create_sq;
4728c8
+		struct nvme_delete_queue delete_queue;
4728c8
+		struct nvme_download_firmware dlfw;
4728c8
+		struct nvme_format_cmd format;
4728c8
+		struct nvme_dsm_cmd dsm;
4728c8
+		struct nvme_write_zeroes_cmd write_zeroes;
4728c8
+		struct nvme_abort_cmd abort;
4728c8
+		struct nvme_get_log_page_command get_log_page;
4728c8
+		struct nvmf_common_command fabrics;
4728c8
+		struct nvmf_connect_command connect;
4728c8
+		struct nvmf_property_set_command prop_set;
4728c8
+		struct nvmf_property_get_command prop_get;
4728c8
+		struct nvme_dbbuf dbbuf;
4728c8
+		struct nvme_directive_cmd directive;
4728c8
+	};
4728c8
+};
4728c8
+
4728c8
+static inline bool nvme_is_write(struct nvme_command *cmd)
4728c8
+{
4728c8
+	/*
4728c8
+	 * What a mess...
4728c8
+	 *
4728c8
+	 * Why can't we simply have a Fabrics In and Fabrics out command?
4728c8
+	 */
4728c8
+	if (unlikely(cmd->common.opcode == nvme_fabrics_command))
4728c8
+		return cmd->fabrics.fctype & 1;
4728c8
+	return cmd->common.opcode & 1;
4728c8
+}
4728c8
+
4728c8
+enum {
4728c8
+	/*
4728c8
+	 * Generic Command Status:
4728c8
+	 */
4728c8
+	NVME_SC_SUCCESS			= 0x0,
4728c8
+	NVME_SC_INVALID_OPCODE		= 0x1,
4728c8
+	NVME_SC_INVALID_FIELD		= 0x2,
4728c8
+	NVME_SC_CMDID_CONFLICT		= 0x3,
4728c8
+	NVME_SC_DATA_XFER_ERROR		= 0x4,
4728c8
+	NVME_SC_POWER_LOSS		= 0x5,
4728c8
+	NVME_SC_INTERNAL		= 0x6,
4728c8
+	NVME_SC_ABORT_REQ		= 0x7,
4728c8
+	NVME_SC_ABORT_QUEUE		= 0x8,
4728c8
+	NVME_SC_FUSED_FAIL		= 0x9,
4728c8
+	NVME_SC_FUSED_MISSING		= 0xa,
4728c8
+	NVME_SC_INVALID_NS		= 0xb,
4728c8
+	NVME_SC_CMD_SEQ_ERROR		= 0xc,
4728c8
+	NVME_SC_SGL_INVALID_LAST	= 0xd,
4728c8
+	NVME_SC_SGL_INVALID_COUNT	= 0xe,
4728c8
+	NVME_SC_SGL_INVALID_DATA	= 0xf,
4728c8
+	NVME_SC_SGL_INVALID_METADATA	= 0x10,
4728c8
+	NVME_SC_SGL_INVALID_TYPE	= 0x11,
4728c8
+
4728c8
+	NVME_SC_SGL_INVALID_OFFSET	= 0x16,
4728c8
+	NVME_SC_SGL_INVALID_SUBTYPE	= 0x17,
4728c8
+
4728c8
+	NVME_SC_SANITIZE_FAILED		= 0x1C,
4728c8
+	NVME_SC_SANITIZE_IN_PROGRESS	= 0x1D,
4728c8
+
4728c8
+	NVME_SC_NS_WRITE_PROTECTED	= 0x20,
4728c8
+
4728c8
+	NVME_SC_LBA_RANGE		= 0x80,
4728c8
+	NVME_SC_CAP_EXCEEDED		= 0x81,
4728c8
+	NVME_SC_NS_NOT_READY		= 0x82,
4728c8
+	NVME_SC_RESERVATION_CONFLICT	= 0x83,
4728c8
+
4728c8
+	/*
4728c8
+	 * Command Specific Status:
4728c8
+	 */
4728c8
+	NVME_SC_CQ_INVALID		= 0x100,
4728c8
+	NVME_SC_QID_INVALID		= 0x101,
4728c8
+	NVME_SC_QUEUE_SIZE		= 0x102,
4728c8
+	NVME_SC_ABORT_LIMIT		= 0x103,
4728c8
+	NVME_SC_ABORT_MISSING		= 0x104,
4728c8
+	NVME_SC_ASYNC_LIMIT		= 0x105,
4728c8
+	NVME_SC_FIRMWARE_SLOT		= 0x106,
4728c8
+	NVME_SC_FIRMWARE_IMAGE		= 0x107,
4728c8
+	NVME_SC_INVALID_VECTOR		= 0x108,
4728c8
+	NVME_SC_INVALID_LOG_PAGE	= 0x109,
4728c8
+	NVME_SC_INVALID_FORMAT		= 0x10a,
4728c8
+	NVME_SC_FW_NEEDS_CONV_RESET	= 0x10b,
4728c8
+	NVME_SC_INVALID_QUEUE		= 0x10c,
4728c8
+	NVME_SC_FEATURE_NOT_SAVEABLE	= 0x10d,
4728c8
+	NVME_SC_FEATURE_NOT_CHANGEABLE	= 0x10e,
4728c8
+	NVME_SC_FEATURE_NOT_PER_NS	= 0x10f,
4728c8
+	NVME_SC_FW_NEEDS_SUBSYS_RESET	= 0x110,
4728c8
+	NVME_SC_FW_NEEDS_RESET		= 0x111,
4728c8
+	NVME_SC_FW_NEEDS_MAX_TIME	= 0x112,
4728c8
+	NVME_SC_FW_ACIVATE_PROHIBITED	= 0x113,
4728c8
+	NVME_SC_OVERLAPPING_RANGE	= 0x114,
4728c8
+	NVME_SC_NS_INSUFFICENT_CAP	= 0x115,
4728c8
+	NVME_SC_NS_ID_UNAVAILABLE	= 0x116,
4728c8
+	NVME_SC_NS_ALREADY_ATTACHED	= 0x118,
4728c8
+	NVME_SC_NS_IS_PRIVATE		= 0x119,
4728c8
+	NVME_SC_NS_NOT_ATTACHED		= 0x11a,
4728c8
+	NVME_SC_THIN_PROV_NOT_SUPP	= 0x11b,
4728c8
+	NVME_SC_CTRL_LIST_INVALID	= 0x11c,
4728c8
+	NVME_SC_BP_WRITE_PROHIBITED	= 0x11e,
4728c8
+
4728c8
+	/*
4728c8
+	 * I/O Command Set Specific - NVM commands:
4728c8
+	 */
4728c8
+	NVME_SC_BAD_ATTRIBUTES		= 0x180,
4728c8
+	NVME_SC_INVALID_PI		= 0x181,
4728c8
+	NVME_SC_READ_ONLY		= 0x182,
4728c8
+	NVME_SC_ONCS_NOT_SUPPORTED	= 0x183,
4728c8
+
4728c8
+	/*
4728c8
+	 * I/O Command Set Specific - Fabrics commands:
4728c8
+	 */
4728c8
+	NVME_SC_CONNECT_FORMAT		= 0x180,
4728c8
+	NVME_SC_CONNECT_CTRL_BUSY	= 0x181,
4728c8
+	NVME_SC_CONNECT_INVALID_PARAM	= 0x182,
4728c8
+	NVME_SC_CONNECT_RESTART_DISC	= 0x183,
4728c8
+	NVME_SC_CONNECT_INVALID_HOST	= 0x184,
4728c8
+
4728c8
+	NVME_SC_DISCOVERY_RESTART	= 0x190,
4728c8
+	NVME_SC_AUTH_REQUIRED		= 0x191,
4728c8
+
4728c8
+	/*
4728c8
+	 * Media and Data Integrity Errors:
4728c8
+	 */
4728c8
+	NVME_SC_WRITE_FAULT		= 0x280,
4728c8
+	NVME_SC_READ_ERROR		= 0x281,
4728c8
+	NVME_SC_GUARD_CHECK		= 0x282,
4728c8
+	NVME_SC_APPTAG_CHECK		= 0x283,
4728c8
+	NVME_SC_REFTAG_CHECK		= 0x284,
4728c8
+	NVME_SC_COMPARE_FAILED		= 0x285,
4728c8
+	NVME_SC_ACCESS_DENIED		= 0x286,
4728c8
+	NVME_SC_UNWRITTEN_BLOCK		= 0x287,
4728c8
+
4728c8
+	/*
4728c8
+	 * Path-related Errors:
4728c8
+	 */
4728c8
+	NVME_SC_ANA_PERSISTENT_LOSS	= 0x301,
4728c8
+	NVME_SC_ANA_INACCESSIBLE	= 0x302,
4728c8
+	NVME_SC_ANA_TRANSITION		= 0x303,
4728c8
+
4728c8
+	NVME_SC_DNR			= 0x4000,
4728c8
+};
4728c8
+
4728c8
+struct nvme_completion {
4728c8
+	/*
4728c8
+	 * Used by Admin and Fabrics commands to return data:
4728c8
+	 */
4728c8
+	union nvme_result {
4728c8
+		__le16	u16;
4728c8
+		__le32	u32;
4728c8
+		__le64	u64;
4728c8
+	} result;
4728c8
+	__le16	sq_head;	/* how much of this queue may be reclaimed */
4728c8
+	__le16	sq_id;		/* submission queue that generated this entry */
4728c8
+	__u16	command_id;	/* of the command which completed */
4728c8
+	__le16	status;		/* did the command fail, and if so, why? */
4728c8
+};
4728c8
+
4728c8
+#define NVME_VS(major, minor, tertiary) \
4728c8
+	(((major) << 16) | ((minor) << 8) | (tertiary))
4728c8
+
4728c8
+#define NVME_MAJOR(ver)		((ver) >> 16)
4728c8
+#define NVME_MINOR(ver)		(((ver) >> 8) & 0xff)
4728c8
+#define NVME_TERTIARY(ver)	((ver) & 0xff)
4728c8
+
4728c8
+#endif /* _LINUX_NVME_H */
4728c8
Index: multipath-tools-130222/libmultipath/nvme/linux/nvme_ioctl.h
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/nvme/linux/nvme_ioctl.h
4728c8
@@ -0,0 +1,67 @@
4728c8
+/*
4728c8
+ * Definitions for the NVM Express ioctl interface
4728c8
+ * Copyright (c) 2011-2014, Intel Corporation.
4728c8
+ *
4728c8
+ * This program is free software; you can redistribute it and/or modify it
4728c8
+ * under the terms and conditions of the GNU General Public License,
4728c8
+ * version 2, as published by the Free Software Foundation.
4728c8
+ *
4728c8
+ * This program is distributed in the hope it will be useful, but WITHOUT
4728c8
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4728c8
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
4728c8
+ * more details.
4728c8
+ */
4728c8
+
4728c8
+#ifndef _UAPI_LINUX_NVME_IOCTL_H
4728c8
+#define _UAPI_LINUX_NVME_IOCTL_H
4728c8
+
4728c8
+#include <linux/types.h>
4728c8
+#include <sys/ioctl.h>
4728c8
+
4728c8
+struct nvme_user_io {
4728c8
+	__u8	opcode;
4728c8
+	__u8	flags;
4728c8
+	__u16	control;
4728c8
+	__u16	nblocks;
4728c8
+	__u16	rsvd;
4728c8
+	__u64	metadata;
4728c8
+	__u64	addr;
4728c8
+	__u64	slba;
4728c8
+	__u32	dsmgmt;
4728c8
+	__u32	reftag;
4728c8
+	__u16	apptag;
4728c8
+	__u16	appmask;
4728c8
+};
4728c8
+
4728c8
+struct nvme_passthru_cmd {
4728c8
+	__u8	opcode;
4728c8
+	__u8	flags;
4728c8
+	__u16	rsvd1;
4728c8
+	__u32	nsid;
4728c8
+	__u32	cdw2;
4728c8
+	__u32	cdw3;
4728c8
+	__u64	metadata;
4728c8
+	__u64	addr;
4728c8
+	__u32	metadata_len;
4728c8
+	__u32	data_len;
4728c8
+	__u32	cdw10;
4728c8
+	__u32	cdw11;
4728c8
+	__u32	cdw12;
4728c8
+	__u32	cdw13;
4728c8
+	__u32	cdw14;
4728c8
+	__u32	cdw15;
4728c8
+	__u32	timeout_ms;
4728c8
+	__u32	result;
4728c8
+};
4728c8
+
4728c8
+#define nvme_admin_cmd nvme_passthru_cmd
4728c8
+
4728c8
+#define NVME_IOCTL_ID		_IO('N', 0x40)
4728c8
+#define NVME_IOCTL_ADMIN_CMD	_IOWR('N', 0x41, struct nvme_admin_cmd)
4728c8
+#define NVME_IOCTL_SUBMIT_IO	_IOW('N', 0x42, struct nvme_user_io)
4728c8
+#define NVME_IOCTL_IO_CMD	_IOWR('N', 0x43, struct nvme_passthru_cmd)
4728c8
+#define NVME_IOCTL_RESET	_IO('N', 0x44)
4728c8
+#define NVME_IOCTL_SUBSYS_RESET	_IO('N', 0x45)
4728c8
+#define NVME_IOCTL_RESCAN	_IO('N', 0x46)
4728c8
+
4728c8
+#endif /* _UAPI_LINUX_NVME_IOCTL_H */
4728c8
Index: multipath-tools-130222/Makefile.inc
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/Makefile.inc
4728c8
+++ multipath-tools-130222/Makefile.inc
4728c8
@@ -37,6 +37,7 @@ mpathpersistdir = $(TOPDIR)/libmpathpers
4728c8
 includedir  = $(prefix)/usr/include
4728c8
 mpathcmddir = $(TOPDIR)/libmpathcmd
4728c8
 libdmmpdir     = $(TOPDIR)/libdmmp
4728c8
+nvmedir     = $(TOPDIR)/libmultipath/nvme
4728c8
 pkgconfdir     = $(prefix)/usr/$(LIB)/pkgconfig
4728c8
 
4728c8
 GZIP            = /bin/gzip -9 -c
4728c8
Index: multipath-tools-130222/libmultipath/Makefile
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/Makefile
4728c8
+++ multipath-tools-130222/libmultipath/Makefile
4728c8
@@ -8,7 +8,7 @@ SONAME=0
4728c8
 DEVLIB = libmultipath.so
4728c8
 LIBS = $(DEVLIB).$(SONAME)
4728c8
 LIBDEPS = -lpthread -ldl -ldevmapper -ludev -L$(mpathcmddir) -lmpathcmd -laio
4728c8
-CFLAGS += -fPIC -I$(mpathcmddir) -I$(mpathpersistdir)
4728c8
+CFLAGS += -fPIC -I$(mpathcmddir) -I$(mpathpersistdir) -I$(nvmedir)
4728c8
 
4728c8
 OBJS = memory.o parser.o vector.o devmapper.o \
4728c8
        hwtable.o blacklist.o util.o dmparser.o config.o \
4728c8
@@ -17,7 +17,7 @@ OBJS = memory.o parser.o vector.o devmap
4728c8
        switchgroup.o uxsock.o print.o alias.o log_pthread.o \
4728c8
        log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
4728c8
        lock.o waiter.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
4728c8
-       io_err_stat.o
4728c8
+       io_err_stat.o nvme-lib.o
4728c8
 
4728c8
 LIBDM_API_FLUSH = $(shell grep -Ecs '^[a-z]*[[:space:]]+dm_task_no_flush' /usr/include/libdevmapper.h)
4728c8
 
4728c8
@@ -46,6 +46,9 @@ endif
4728c8
 
4728c8
 all: $(LIBS)
4728c8
 
4728c8
+nvme-lib.o: nvme-lib.c nvme-ioctl.c nvme-ioctl.h
4728c8
+	$(CC) $(CFLAGS) -Wno-unused-function -c -o $@ $<
4728c8
+
4728c8
 $(LIBS): $(OBJS)
4728c8
 	$(CC) $(LDFLAGS) $(SHARED_FLAGS) -Wl,-soname=$@ $(CFLAGS) -o $@ $(OBJS) $(LIBDEPS)
4728c8
 	ln -sf $@ $(DEVLIB)
4728c8
Index: multipath-tools-130222/libmultipath/nvme-ioctl.c
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/nvme-ioctl.c
4728c8
@@ -0,0 +1,869 @@
4728c8
+#include <sys/ioctl.h>
4728c8
+#include <sys/stat.h>
4728c8
+#include <string.h>
4728c8
+#include <errno.h>
4728c8
+#include <unistd.h>
4728c8
+
4728c8
+#include <errno.h>
4728c8
+#include <getopt.h>
4728c8
+#include <fcntl.h>
4728c8
+#include <inttypes.h>
4728c8
+#include <locale.h>
4728c8
+#include <stdio.h>
4728c8
+#include <stdlib.h>
4728c8
+#include <string.h>
4728c8
+#include <unistd.h>
4728c8
+#include <math.h>
4728c8
+
4728c8
+#include "nvme-ioctl.h"
4728c8
+
4728c8
+static int nvme_verify_chr(int fd)
4728c8
+{
4728c8
+	static struct stat nvme_stat;
4728c8
+	int err = fstat(fd, &nvme_stat);
4728c8
+
4728c8
+	if (err < 0) {
4728c8
+		perror("fstat");
4728c8
+		return errno;
4728c8
+	}
4728c8
+	if (!S_ISCHR(nvme_stat.st_mode)) {
4728c8
+		fprintf(stderr,
4728c8
+			"Error: requesting reset on non-controller handle\n");
4728c8
+		return ENOTBLK;
4728c8
+	}
4728c8
+	return 0;
4728c8
+}
4728c8
+
4728c8
+static int nvme_subsystem_reset(int fd)
4728c8
+{
4728c8
+	int ret;
4728c8
+
4728c8
+	ret = nvme_verify_chr(fd);
4728c8
+	if (ret)
4728c8
+		return ret;
4728c8
+	return ioctl(fd, NVME_IOCTL_SUBSYS_RESET);
4728c8
+}
4728c8
+
4728c8
+static int nvme_reset_controller(int fd)
4728c8
+{
4728c8
+	int ret;
4728c8
+
4728c8
+	ret = nvme_verify_chr(fd);
4728c8
+	if (ret)
4728c8
+		return ret;
4728c8
+	return ioctl(fd, NVME_IOCTL_RESET);
4728c8
+}
4728c8
+
4728c8
+static int nvme_ns_rescan(int fd)
4728c8
+{
4728c8
+	int ret;
4728c8
+
4728c8
+	ret = nvme_verify_chr(fd);
4728c8
+	if (ret)
4728c8
+		return ret;
4728c8
+	return ioctl(fd, NVME_IOCTL_RESCAN);
4728c8
+}
4728c8
+
4728c8
+static int nvme_get_nsid(int fd)
4728c8
+{
4728c8
+	static struct stat nvme_stat;
4728c8
+	int err = fstat(fd, &nvme_stat);
4728c8
+
4728c8
+	if (err < 0)
4728c8
+		return -errno;
4728c8
+
4728c8
+	if (!S_ISBLK(nvme_stat.st_mode)) {
4728c8
+		fprintf(stderr,
4728c8
+			"Error: requesting namespace-id from non-block device\n");
4728c8
+		errno = ENOTBLK;
4728c8
+		return -errno;
4728c8
+	}
4728c8
+	return ioctl(fd, NVME_IOCTL_ID);
4728c8
+}
4728c8
+
4728c8
+static int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
4728c8
+			 struct nvme_passthru_cmd *cmd)
4728c8
+{
4728c8
+	return ioctl(fd, ioctl_cmd, cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd)
4728c8
+{
4728c8
+	return ioctl(fd, NVME_IOCTL_ADMIN_CMD, cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd)
4728c8
+{
4728c8
+	return ioctl(fd, NVME_IOCTL_IO_CMD, cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_passthru(int fd, unsigned long ioctl_cmd, __u8 opcode,
4728c8
+		  __u8 flags, __u16 rsvd,
4728c8
+		  __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10, __u32 cdw11,
4728c8
+		  __u32 cdw12, __u32 cdw13, __u32 cdw14, __u32 cdw15,
4728c8
+		  __u32 data_len, void *data, __u32 metadata_len,
4728c8
+		  void *metadata, __u32 timeout_ms, __u32 *result)
4728c8
+{
4728c8
+	struct nvme_passthru_cmd cmd = {
4728c8
+		.opcode		= opcode,
4728c8
+		.flags		= flags,
4728c8
+		.rsvd1		= rsvd,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw2		= cdw2,
4728c8
+		.cdw3		= cdw3,
4728c8
+		.metadata	= (__u64)(uintptr_t) metadata,
4728c8
+		.addr		= (__u64)(uintptr_t) data,
4728c8
+		.metadata_len	= metadata_len,
4728c8
+		.data_len	= data_len,
4728c8
+		.cdw10		= cdw10,
4728c8
+		.cdw11		= cdw11,
4728c8
+		.cdw12		= cdw12,
4728c8
+		.cdw13		= cdw13,
4728c8
+		.cdw14		= cdw14,
4728c8
+		.cdw15		= cdw15,
4728c8
+		.timeout_ms	= timeout_ms,
4728c8
+		.result		= 0,
4728c8
+	};
4728c8
+	int err;
4728c8
+
4728c8
+	err = nvme_submit_passthru(fd, ioctl_cmd, &cmd);
4728c8
+	if (!err && result)
4728c8
+		*result = cmd.result;
4728c8
+	return err;
4728c8
+}
4728c8
+
4728c8
+static int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control,
4728c8
+	    __u32 dsmgmt, __u32 reftag, __u16 apptag, __u16 appmask, void *data,
4728c8
+	    void *metadata)
4728c8
+{
4728c8
+	struct nvme_user_io io = {
4728c8
+		.opcode		= opcode,
4728c8
+		.flags		= 0,
4728c8
+		.control	= control,
4728c8
+		.nblocks	= nblocks,
4728c8
+		.rsvd		= 0,
4728c8
+		.metadata	= (__u64)(uintptr_t) metadata,
4728c8
+		.addr		= (__u64)(uintptr_t) data,
4728c8
+		.slba		= slba,
4728c8
+		.dsmgmt		= dsmgmt,
4728c8
+		.reftag		= reftag,
4728c8
+		.appmask	= appmask,
4728c8
+		.apptag		= apptag,
4728c8
+	};
4728c8
+	return ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io);
4728c8
+}
4728c8
+
4728c8
+static int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
4728c8
+	      __u32 reftag, __u16 apptag, __u16 appmask, void *data,
4728c8
+	      void *metadata)
4728c8
+{
4728c8
+	return nvme_io(fd, nvme_cmd_read, slba, nblocks, control, dsmgmt,
4728c8
+		       reftag, apptag, appmask, data, metadata);
4728c8
+}
4728c8
+
4728c8
+static int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
4728c8
+	       __u32 reftag, __u16 apptag, __u16 appmask, void *data,
4728c8
+	       void *metadata)
4728c8
+{
4728c8
+	return nvme_io(fd, nvme_cmd_write, slba, nblocks, control, dsmgmt,
4728c8
+		       reftag, apptag, appmask, data, metadata);
4728c8
+}
4728c8
+
4728c8
+static int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
4728c8
+		 __u32 reftag, __u16 apptag, __u16 appmask, void *data,
4728c8
+		 void *metadata)
4728c8
+{
4728c8
+	return nvme_io(fd, nvme_cmd_compare, slba, nblocks, control, dsmgmt,
4728c8
+		       reftag, apptag, appmask, data, metadata);
4728c8
+}
4728c8
+
4728c8
+static int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
4728c8
+		     __u32 nsid, __u32 cdw2, __u32 cdw3, __u32 cdw10,
4728c8
+		     __u32 cdw11, __u32 cdw12, __u32 cdw13, __u32 cdw14,
4728c8
+		     __u32 cdw15, __u32 data_len, void *data,
4728c8
+		     __u32 metadata_len, void *metadata, __u32 timeout_ms)
4728c8
+{
4728c8
+	return nvme_passthru(fd, NVME_IOCTL_IO_CMD, opcode, flags, rsvd, nsid,
4728c8
+			     cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14,
4728c8
+			     cdw15, data_len, data, metadata_len, metadata,
4728c8
+			     timeout_ms, NULL);
4728c8
+}
4728c8
+
4728c8
+static int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb,
4728c8
+		     __u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
4728c8
+{
4728c8
+	struct nvme_passthru_cmd cmd = {
4728c8
+		.opcode		= nvme_cmd_write_zeroes,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= slba & 0xffffffff,
4728c8
+		.cdw11		= slba >> 32,
4728c8
+		.cdw12		= nlb | (control << 16),
4728c8
+		.cdw14		= reftag,
4728c8
+		.cdw15		= apptag | (appmask << 16),
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_io_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb)
4728c8
+{
4728c8
+	struct nvme_passthru_cmd cmd = {
4728c8
+		.opcode		= nvme_cmd_write_uncor,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= slba & 0xffffffff,
4728c8
+		.cdw11		= slba >> 32,
4728c8
+		.cdw12		= nlb,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_io_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_flush(int fd, __u32 nsid)
4728c8
+{
4728c8
+	struct nvme_passthru_cmd cmd = {
4728c8
+		.opcode		= nvme_cmd_flush,
4728c8
+		.nsid		= nsid,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_io_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
4728c8
+	     __u16 nr_ranges)
4728c8
+{
4728c8
+	struct nvme_passthru_cmd cmd = {
4728c8
+		.opcode		= nvme_cmd_dsm,
4728c8
+		.nsid		= nsid,
4728c8
+		.addr		= (__u64)(uintptr_t) dsm,
4728c8
+		.data_len	= nr_ranges * sizeof(*dsm),
4728c8
+		.cdw10		= nr_ranges - 1,
4728c8
+		.cdw11		= cdw11,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_io_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas,
4728c8
+					    __u64 *slbas, __u16 nr_ranges)
4728c8
+{
4728c8
+	int i;
4728c8
+	struct nvme_dsm_range *dsm = malloc(nr_ranges * sizeof(*dsm));
4728c8
+
4728c8
+	if (!dsm) {
4728c8
+		fprintf(stderr, "malloc: %s\n", strerror(errno));
4728c8
+		return NULL;
4728c8
+	}
4728c8
+	for (i = 0; i < nr_ranges; i++) {
4728c8
+		dsm[i].cattr = cpu_to_le32(ctx_attrs[i]);
4728c8
+		dsm[i].nlb = cpu_to_le32(llbas[i]);
4728c8
+		dsm[i].slba = cpu_to_le64(slbas[i]);
4728c8
+	}
4728c8
+	return dsm;
4728c8
+}
4728c8
+
4728c8
+static int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
4728c8
+		      bool iekey, __u64 crkey, __u64 nrkey)
4728c8
+{
4728c8
+	__le64 payload[2] = { cpu_to_le64(crkey), cpu_to_le64(nrkey) };
4728c8
+	__u32 cdw10 = (racqa & 0x7) | (iekey ? 1 << 3 : 0) | rtype << 8;
4728c8
+	struct nvme_passthru_cmd cmd = {
4728c8
+		.opcode		= nvme_cmd_resv_acquire,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= cdw10,
4728c8
+		.addr		= (__u64)(uintptr_t) (payload),
4728c8
+		.data_len	= sizeof(payload),
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_io_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl,
4728c8
+		       bool iekey, __u64 crkey, __u64 nrkey)
4728c8
+{
4728c8
+	__le64 payload[2] = { cpu_to_le64(crkey), cpu_to_le64(nrkey) };
4728c8
+	__u32 cdw10 = (rrega & 0x7) | (iekey ? 1 << 3 : 0) | cptpl << 30;
4728c8
+
4728c8
+	struct nvme_passthru_cmd cmd = {
4728c8
+		.opcode		= nvme_cmd_resv_register,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= cdw10,
4728c8
+		.addr		= (__u64)(uintptr_t) (payload),
4728c8
+		.data_len	= sizeof(payload),
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_io_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela,
4728c8
+		      bool iekey, __u64 crkey)
4728c8
+{
4728c8
+	__le64 payload[1] = { cpu_to_le64(crkey) };
4728c8
+	__u32 cdw10 = (rrela & 0x7) | (iekey ? 1 << 3 : 0) | rtype << 8;
4728c8
+
4728c8
+	struct nvme_passthru_cmd cmd = {
4728c8
+		.opcode		= nvme_cmd_resv_release,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= cdw10,
4728c8
+		.addr		= (__u64)(uintptr_t) (payload),
4728c8
+		.data_len	= sizeof(payload),
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_io_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_resv_report(int fd, __u32 nsid, __u32 numd, __u32 cdw11, void *data)
4728c8
+{
4728c8
+	struct nvme_passthru_cmd cmd = {
4728c8
+		.opcode		= nvme_cmd_resv_report,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= numd,
4728c8
+		.cdw11		= cdw11,
4728c8
+		.addr		= (__u64)(uintptr_t) data,
4728c8
+		.data_len	= (numd + 1) << 2,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_io_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_identify13(int fd, __u32 nsid, __u32 cdw10, __u32 cdw11, void *data)
4728c8
+{
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_identify,
4728c8
+		.nsid		= nsid,
4728c8
+		.addr		= (__u64)(uintptr_t) data,
4728c8
+		.data_len	= NVME_IDENTIFY_DATA_SIZE,
4728c8
+		.cdw10		= cdw10,
4728c8
+		.cdw11		= cdw11,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_admin_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data)
4728c8
+{
4728c8
+	return nvme_identify13(fd, nsid, cdw10, 0, data);
4728c8
+}
4728c8
+
4728c8
+static int nvme_identify_ctrl(int fd, void *data)
4728c8
+{
4728c8
+	return nvme_identify(fd, 0, 1, data);
4728c8
+}
4728c8
+
4728c8
+static int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data)
4728c8
+{
4728c8
+	int cns = present ? NVME_ID_CNS_NS_PRESENT : NVME_ID_CNS_NS;
4728c8
+
4728c8
+	return nvme_identify(fd, nsid, cns, data);
4728c8
+}
4728c8
+
4728c8
+static int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data)
4728c8
+{
4728c8
+	int cns = all ? NVME_ID_CNS_NS_PRESENT_LIST : NVME_ID_CNS_NS_ACTIVE_LIST;
4728c8
+
4728c8
+	return nvme_identify(fd, nsid, cns, data);
4728c8
+}
4728c8
+
4728c8
+static int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
4728c8
+{
4728c8
+	int cns = nsid ? NVME_ID_CNS_CTRL_NS_LIST : NVME_ID_CNS_CTRL_LIST;
4728c8
+
4728c8
+	return nvme_identify(fd, nsid, (cntid << 16) | cns, data);
4728c8
+}
4728c8
+
4728c8
+static int nvme_identify_ns_descs(int fd, __u32 nsid, void *data)
4728c8
+{
4728c8
+
4728c8
+	return nvme_identify(fd, nsid, NVME_ID_CNS_NS_DESC_LIST, data);
4728c8
+}
4728c8
+
4728c8
+static int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data)
4728c8
+{
4728c8
+	return nvme_identify13(fd, 0, NVME_ID_CNS_NVMSET_LIST, nvmset_id, data);
4728c8
+}
4728c8
+
4728c8
+static int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
4728c8
+                 __u16 lsi, bool rae, __u32 data_len, void *data)
4728c8
+{
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_get_log_page,
4728c8
+		.nsid		= nsid,
4728c8
+		.addr		= (__u64)(uintptr_t) data,
4728c8
+		.data_len	= data_len,
4728c8
+	};
4728c8
+	__u32 numd = (data_len >> 2) - 1;
4728c8
+	__u16 numdu = numd >> 16, numdl = numd & 0xffff;
4728c8
+
4728c8
+	cmd.cdw10 = log_id | (numdl << 16) | (rae ? 1 << 15 : 0);
4728c8
+	if (lsp)
4728c8
+                cmd.cdw10 |= lsp << 8;
4728c8
+
4728c8
+	cmd.cdw11 = numdu | (lsi << 16);
4728c8
+	cmd.cdw12 = lpo;
4728c8
+	cmd.cdw13 = (lpo >> 32);
4728c8
+
4728c8
+	return nvme_submit_admin_passthru(fd, &cmd);
4728c8
+
4728c8
+}
4728c8
+
4728c8
+static int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
4728c8
+		 __u32 data_len, void *data)
4728c8
+{
4728c8
+	void *ptr = data;
4728c8
+	__u32 offset = 0, xfer_len = data_len;
4728c8
+	int ret;
4728c8
+
4728c8
+	/*
4728c8
+	 * 4k is the smallest possible transfer unit, so by
4728c8
+	 * restricting ourselves for 4k transfers we avoid having
4728c8
+	 * to check the MDTS value of the controller.
4728c8
+	 */
4728c8
+	do {
4728c8
+		xfer_len = data_len - offset;
4728c8
+		if (xfer_len > 4096)
4728c8
+			xfer_len = 4096;
4728c8
+
4728c8
+		ret = nvme_get_log13(fd, nsid, log_id, NVME_NO_LOG_LSP,
4728c8
+				     offset, 0, rae, xfer_len, ptr);
4728c8
+		if (ret)
4728c8
+			return ret;
4728c8
+
4728c8
+		offset += xfer_len;
4728c8
+		ptr += xfer_len;
4728c8
+	} while (offset < data_len);
4728c8
+
4728c8
+	return 0;
4728c8
+}
4728c8
+
4728c8
+static int nvme_get_telemetry_log(int fd, void *lp, int generate_report,
4728c8
+			   int ctrl_init, size_t log_page_size, __u64 offset)
4728c8
+{
4728c8
+	if (ctrl_init)
4728c8
+		return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_CTRL,
4728c8
+				      NVME_NO_LOG_LSP, offset,
4728c8
+				      0, 1, log_page_size, lp);
4728c8
+	if (generate_report)
4728c8
+		return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_HOST,
4728c8
+				      NVME_TELEM_LSP_CREATE, offset,
4728c8
+				      0, 1, log_page_size, lp);
4728c8
+	else
4728c8
+		return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_HOST,
4728c8
+				      NVME_NO_LOG_LSP, offset,
4728c8
+				      0, 1, log_page_size, lp);
4728c8
+}
4728c8
+
4728c8
+static int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log)
4728c8
+{
4728c8
+	return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_FW_SLOT, true,
4728c8
+			sizeof(*fw_log), fw_log);
4728c8
+}
4728c8
+
4728c8
+static int nvme_changed_ns_list_log(int fd, struct nvme_changed_ns_list_log *changed_ns_list_log)
4728c8
+{
4728c8
+	return nvme_get_log(fd, 0, NVME_LOG_CHANGED_NS, true,
4728c8
+			sizeof(changed_ns_list_log->log),
4728c8
+			changed_ns_list_log->log);
4728c8
+}
4728c8
+
4728c8
+static int nvme_error_log(int fd, int entries, struct nvme_error_log_page *err_log)
4728c8
+{
4728c8
+	return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_ERROR, false,
4728c8
+			entries * sizeof(*err_log), err_log);
4728c8
+}
4728c8
+
4728c8
+static int nvme_endurance_log(int fd, __u16 group_id, struct nvme_endurance_group_log *endurance_log)
4728c8
+{
4728c8
+	return nvme_get_log13(fd, 0, NVME_LOG_ENDURANCE_GROUP, 0, 0, group_id, 0,
4728c8
+			sizeof(*endurance_log), endurance_log);
4728c8
+}
4728c8
+
4728c8
+static int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log)
4728c8
+{
4728c8
+	return nvme_get_log(fd, nsid, NVME_LOG_SMART, false,
4728c8
+			sizeof(*smart_log), smart_log);
4728c8
+}
4728c8
+
4728c8
+static int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo)
4728c8
+{
4728c8
+	__u64 lpo = 0;
4728c8
+
4728c8
+	return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_ANA, rgo, lpo, 0,
4728c8
+			true, ana_log_len, ana_log);
4728c8
+}
4728c8
+
4728c8
+static int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log)
4728c8
+{
4728c8
+	return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_DEVICE_SELF_TEST, false,
4728c8
+		sizeof(*self_test_log), self_test_log);
4728c8
+}
4728c8
+
4728c8
+static int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log)
4728c8
+{
4728c8
+	return nvme_get_log(fd, 0, NVME_LOG_CMD_EFFECTS, false,
4728c8
+			sizeof(*effects_log), effects_log);
4728c8
+}
4728c8
+
4728c8
+static int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size)
4728c8
+{
4728c8
+	return nvme_get_log(fd, 0, NVME_LOG_DISC, false, size, log);
4728c8
+}
4728c8
+
4728c8
+static int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log)
4728c8
+{
4728c8
+	return nvme_get_log(fd, 0, NVME_LOG_SANITIZE, false,
4728c8
+			sizeof(*sanitize_log), sanitize_log);
4728c8
+}
4728c8
+
4728c8
+static int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11,
4728c8
+		 __u32 cdw12, __u32 data_len, void *data, __u32 *result)
4728c8
+{
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= opcode,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= cdw10,
4728c8
+		.cdw11		= cdw11,
4728c8
+		.cdw12		= cdw12,
4728c8
+		.addr		= (__u64)(uintptr_t) data,
4728c8
+		.data_len	= data_len,
4728c8
+	};
4728c8
+	int err;
4728c8
+
4728c8
+	err = nvme_submit_admin_passthru(fd, &cmd);
4728c8
+	if (!err && result)
4728c8
+		*result = cmd.result;
4728c8
+	return err;
4728c8
+}
4728c8
+
4728c8
+static int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, __u32 cdw12,
4728c8
+		     bool save, __u32 data_len, void *data, __u32 *result)
4728c8
+{
4728c8
+	__u32 cdw10 = fid | (save ? 0x80000000 : 0);
4728c8
+
4728c8
+	return nvme_feature(fd, nvme_admin_set_features, nsid, cdw10, value,
4728c8
+			    cdw12, data_len, data, result);
4728c8
+}
4728c8
+
4728c8
+static int nvme_property(int fd, __u8 fctype, __le32 off, __le64 *value, __u8 attrib)
4728c8
+{
4728c8
+	int err;
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_fabrics_command,
4728c8
+		.cdw10		= attrib,
4728c8
+		.cdw11		= off,
4728c8
+	};
4728c8
+
4728c8
+	if (!value) {
4728c8
+		errno = EINVAL;
4728c8
+		return -errno;
4728c8
+	}
4728c8
+
4728c8
+	if (fctype == nvme_fabrics_type_property_get){
4728c8
+		cmd.nsid = nvme_fabrics_type_property_get;
4728c8
+	} else if(fctype == nvme_fabrics_type_property_set) {
4728c8
+		cmd.nsid = nvme_fabrics_type_property_set;
4728c8
+		cmd.cdw12 = *value;
4728c8
+	} else {
4728c8
+		errno = EINVAL;
4728c8
+		return -errno;
4728c8
+	}
4728c8
+
4728c8
+	err = nvme_submit_admin_passthru(fd, &cmd);
4728c8
+	if (!err && fctype == nvme_fabrics_type_property_get)
4728c8
+		*value = cpu_to_le64(cmd.result);
4728c8
+	return err;
4728c8
+}
4728c8
+
4728c8
+static int get_property_helper(int fd, int offset, void *value, int *advance)
4728c8
+{
4728c8
+	__le64 value64;
4728c8
+	int err = -EINVAL;
4728c8
+
4728c8
+	switch (offset) {
4728c8
+	case NVME_REG_CAP:
4728c8
+	case NVME_REG_ASQ:
4728c8
+	case NVME_REG_ACQ:
4728c8
+		*advance = 8;
4728c8
+		break;
4728c8
+	default:
4728c8
+		*advance = 4;
4728c8
+	}
4728c8
+
4728c8
+	if (!value)
4728c8
+		return err;
4728c8
+
4728c8
+	err = nvme_property(fd, nvme_fabrics_type_property_get,
4728c8
+			cpu_to_le32(offset), &value64, (*advance == 8));
4728c8
+
4728c8
+	if (!err) {
4728c8
+		if (*advance == 8)
4728c8
+			*((uint64_t *)value) = le64_to_cpu(value64);
4728c8
+		else
4728c8
+			*((uint32_t *)value) = le32_to_cpu(value64);
4728c8
+	}
4728c8
+
4728c8
+	return err;
4728c8
+}
4728c8
+
4728c8
+static int nvme_get_property(int fd, int offset, uint64_t *value)
4728c8
+{
4728c8
+	int advance;
4728c8
+	return get_property_helper(fd, offset, value, &advance);
4728c8
+}
4728c8
+
4728c8
+static int nvme_get_properties(int fd, void **pbar)
4728c8
+{
4728c8
+	int offset, advance;
4728c8
+	int err, ret = -EINVAL;
4728c8
+	int size = getpagesize();
4728c8
+
4728c8
+	*pbar = malloc(size);
4728c8
+	if (!*pbar) {
4728c8
+		fprintf(stderr, "malloc: %s\n", strerror(errno));
4728c8
+		return -ENOMEM;
4728c8
+	}
4728c8
+
4728c8
+	memset(*pbar, 0xff, size);
4728c8
+	for (offset = NVME_REG_CAP; offset <= NVME_REG_CMBSZ; offset += advance) {
4728c8
+		err = get_property_helper(fd, offset, *pbar + offset, &advance);
4728c8
+		if (!err)
4728c8
+			ret = 0;
4728c8
+	}
4728c8
+
4728c8
+	return ret;
4728c8
+}
4728c8
+
4728c8
+static int nvme_set_property(int fd, int offset, int value)
4728c8
+{
4728c8
+	__le64 val = cpu_to_le64(value);
4728c8
+	__le32 off = cpu_to_le32(offset);
4728c8
+	bool is64bit;
4728c8
+
4728c8
+	switch (off) {
4728c8
+	case NVME_REG_CAP:
4728c8
+	case NVME_REG_ASQ:
4728c8
+	case NVME_REG_ACQ:
4728c8
+		is64bit = true;
4728c8
+		break;
4728c8
+	default:
4728c8
+		is64bit = false;
4728c8
+	}
4728c8
+
4728c8
+	return nvme_property(fd, nvme_fabrics_type_property_set,
4728c8
+			off, &val, is64bit ? 1: 0);
4728c8
+}
4728c8
+
4728c8
+static int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, __u32 cdw11,
4728c8
+		     __u32 data_len, void *data, __u32 *result)
4728c8
+{
4728c8
+	__u32 cdw10 = fid | sel << 8;
4728c8
+
4728c8
+	return nvme_feature(fd, nvme_admin_get_features, nsid, cdw10, cdw11,
4728c8
+			    0, data_len, data, result);
4728c8
+}
4728c8
+
4728c8
+static int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
4728c8
+		__u8 pil, __u8 ms, __u32 timeout)
4728c8
+{
4728c8
+	__u32 cdw10 = lbaf | ms << 4 | pi << 5 | pil << 8 | ses << 9;
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_format_nvm,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= cdw10,
4728c8
+		.timeout_ms	= timeout,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_admin_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas,
4728c8
+		   __u8 dps, __u8 nmic, __u32 *result)
4728c8
+{
4728c8
+	struct nvme_id_ns ns = {
4728c8
+		.nsze		= cpu_to_le64(nsze),
4728c8
+		.ncap		= cpu_to_le64(ncap),
4728c8
+		.flbas		= flbas,
4728c8
+		.dps		= dps,
4728c8
+		.nmic		= nmic,
4728c8
+	};
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_ns_mgmt,
4728c8
+		.addr		= (__u64)(uintptr_t) ((void *)&ns),
4728c8
+		.cdw10		= 0,
4728c8
+		.data_len	= 0x1000,
4728c8
+	};
4728c8
+	int err;
4728c8
+
4728c8
+	err = nvme_submit_admin_passthru(fd, &cmd);
4728c8
+	if (!err && result)
4728c8
+		*result = cmd.result;
4728c8
+	return err;
4728c8
+}
4728c8
+
4728c8
+static int nvme_ns_delete(int fd, __u32 nsid)
4728c8
+{
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_ns_mgmt,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= 1,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_admin_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist,
4728c8
+		       bool attach)
4728c8
+{
4728c8
+	int i;
4728c8
+	__u8 buf[0x1000];
4728c8
+	struct nvme_controller_list *cntlist =
4728c8
+					(struct nvme_controller_list *)buf;
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_ns_attach,
4728c8
+		.nsid		= nsid,
4728c8
+		.addr		= (__u64)(uintptr_t) cntlist,
4728c8
+		.cdw10		= attach ? 0 : 1,
4728c8
+		.data_len	= 0x1000,
4728c8
+	};
4728c8
+
4728c8
+	memset(buf, 0, sizeof(buf));
4728c8
+	cntlist->num = cpu_to_le16(num_ctrls);
4728c8
+	for (i = 0; i < num_ctrls; i++)
4728c8
+		cntlist->identifier[i] = cpu_to_le16(ctrlist[i]);
4728c8
+
4728c8
+	return nvme_submit_admin_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_ns_attach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist)
4728c8
+{
4728c8
+	return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, true);
4728c8
+}
4728c8
+
4728c8
+static int nvme_ns_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist)
4728c8
+{
4728c8
+	return nvme_ns_attachment(fd, nsid, num_ctrls, ctrlist, false);
4728c8
+}
4728c8
+
4728c8
+static int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data)
4728c8
+{
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_download_fw,
4728c8
+		.addr		= (__u64)(uintptr_t) data,
4728c8
+		.data_len	= data_len,
4728c8
+		.cdw10		= (data_len >> 2) - 1,
4728c8
+		.cdw11		= offset >> 2,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_admin_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid)
4728c8
+{
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_activate_fw,
4728c8
+		.cdw10		= (bpid << 31) | (action << 3) | slot,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_admin_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
4728c8
+		  __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result)
4728c8
+{
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_security_send,
4728c8
+		.addr		= (__u64)(uintptr_t) data,
4728c8
+		.data_len	= data_len,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= secp << 24 | spsp << 8 | nssf,
4728c8
+		.cdw11		= tl,
4728c8
+	};
4728c8
+	int err;
4728c8
+
4728c8
+	err = nvme_submit_admin_passthru(fd, &cmd);
4728c8
+	if (!err && result)
4728c8
+		*result = cmd.result;
4728c8
+	return err;
4728c8
+}
4728c8
+
4728c8
+static int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
4728c8
+		  __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result)
4728c8
+{
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_security_recv,
4728c8
+		.nsid		= nsid,
4728c8
+		.cdw10		= secp << 24 | spsp << 8 | nssf,
4728c8
+		.cdw11		= al,
4728c8
+		.addr		= (__u64)(uintptr_t) data,
4728c8
+		.data_len	= data_len,
4728c8
+	};
4728c8
+	int err;
4728c8
+
4728c8
+	err = nvme_submit_admin_passthru(fd, &cmd);
4728c8
+	if (!err && result)
4728c8
+		*result = cmd.result;
4728c8
+	return err;
4728c8
+}
4728c8
+
4728c8
+static int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
4728c8
+                  __u32 data_len, __u32 dw12, void *data, __u32 *result)
4728c8
+{
4728c8
+        struct nvme_admin_cmd cmd = {
4728c8
+                .opcode         = nvme_admin_directive_send,
4728c8
+                .addr           = (__u64)(uintptr_t) data,
4728c8
+                .data_len       = data_len,
4728c8
+                .nsid           = nsid,
4728c8
+                .cdw10          = data_len? (data_len >> 2) - 1 : 0,
4728c8
+                .cdw11          = dspec << 16 | dtype << 8 | doper,
4728c8
+                .cdw12          = dw12,
4728c8
+        };
4728c8
+        int err;
4728c8
+
4728c8
+        err = nvme_submit_admin_passthru(fd, &cmd);
4728c8
+        if (!err && result)
4728c8
+                *result = cmd.result;
4728c8
+        return err;
4728c8
+}
4728c8
+
4728c8
+static int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
4728c8
+                  __u32 data_len, __u32 dw12, void *data, __u32 *result)
4728c8
+{
4728c8
+        struct nvme_admin_cmd cmd = {
4728c8
+                .opcode         = nvme_admin_directive_recv,
4728c8
+                .addr           = (__u64)(uintptr_t) data,
4728c8
+                .data_len       = data_len,
4728c8
+                .nsid           = nsid,
4728c8
+                .cdw10          = data_len? (data_len >> 2) - 1 : 0,
4728c8
+                .cdw11          = dspec << 16 | dtype << 8 | doper,
4728c8
+                .cdw12          = dw12,
4728c8
+        };
4728c8
+        int err;
4728c8
+
4728c8
+        err = nvme_submit_admin_passthru(fd, &cmd);
4728c8
+        if (!err && result)
4728c8
+                *result = cmd.result;
4728c8
+        return err;
4728c8
+}
4728c8
+
4728c8
+static int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
4728c8
+		  __u8 no_dealloc, __u32 ovrpat)
4728c8
+{
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode		= nvme_admin_sanitize_nvm,
4728c8
+		.cdw10		= no_dealloc << 9 | oipbp << 8 |
4728c8
+				  owpass << NVME_SANITIZE_OWPASS_SHIFT |
4728c8
+				  ause << 3 | sanact,
4728c8
+		.cdw11		= ovrpat,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_admin_passthru(fd, &cmd);
4728c8
+}
4728c8
+
4728c8
+static int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10)
4728c8
+{
4728c8
+	struct nvme_admin_cmd cmd = {
4728c8
+		.opcode = nvme_admin_dev_self_test,
4728c8
+		.nsid = nsid,
4728c8
+		.cdw10 = cdw10,
4728c8
+	};
4728c8
+
4728c8
+	return nvme_submit_admin_passthru(fd, &cmd);
4728c8
+}
4728c8
Index: multipath-tools-130222/libmultipath/nvme-ioctl.h
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/nvme-ioctl.h
4728c8
@@ -0,0 +1,139 @@
4728c8
+#ifndef _NVME_LIB_H
4728c8
+#define _NVME_LIB_H
4728c8
+
4728c8
+#include <linux/types.h>
4728c8
+#include <stdbool.h>
4728c8
+#include "linux/nvme_ioctl.h"
4728c8
+#include "nvme.h"
4728c8
+
4728c8
+static int nvme_get_nsid(int fd);
4728c8
+
4728c8
+/* Generic passthrough */
4728c8
+static int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
4728c8
+			 struct nvme_passthru_cmd *cmd);
4728c8
+
4728c8
+static int nvme_passthru(int fd, unsigned long ioctl_cmd, __u8 opcode, __u8 flags,
4728c8
+		  __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3,
4728c8
+		  __u32 cdw10, __u32 cdw11, __u32 cdw12,
4728c8
+		  __u32 cdw13, __u32 cdw14, __u32 cdw15,
4728c8
+		  __u32 data_len, void *data, __u32 metadata_len,
4728c8
+		  void *metadata, __u32 timeout_ms, __u32 *result);
4728c8
+
4728c8
+/* NVME_SUBMIT_IO */
4728c8
+static int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control,
4728c8
+	      __u32 dsmgmt, __u32 reftag, __u16 apptag,
4728c8
+	      __u16 appmask, void *data, void *metadata);
4728c8
+
4728c8
+static int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control,
4728c8
+	      __u32 dsmgmt, __u32 reftag, __u16 apptag,
4728c8
+	      __u16 appmask, void *data, void *metadata);
4728c8
+
4728c8
+static int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control,
4728c8
+	       __u32 dsmgmt, __u32 reftag, __u16 apptag,
4728c8
+	       __u16 appmask, void *data, void *metadata);
4728c8
+
4728c8
+static int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control,
4728c8
+		 __u32 dsmgmt, __u32 reftag, __u16 apptag,
4728c8
+		 __u16 appmask, void *data, void *metadata);
4728c8
+
4728c8
+/* NVME_IO_CMD */
4728c8
+static int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
4728c8
+		     __u32 nsid, __u32 cdw2, __u32 cdw3,
4728c8
+		     __u32 cdw10, __u32 cdw11, __u32 cdw12,
4728c8
+		     __u32 cdw13, __u32 cdw14, __u32 cdw15,
4728c8
+		     __u32 data_len, void *data, __u32 metadata_len,
4728c8
+		     void *metadata, __u32 timeout);
4728c8
+
4728c8
+static int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb,
4728c8
+		     __u16 control, __u32 reftag, __u16 apptag, __u16 appmask);
4728c8
+
4728c8
+static int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb);
4728c8
+
4728c8
+static int nvme_flush(int fd, __u32 nsid);
4728c8
+
4728c8
+static int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
4728c8
+	     __u16 nr_ranges);
4728c8
+static struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs,
4728c8
+					    __u32 *llbas, __u64 *slbas,
4728c8
+					    __u16 nr_ranges);
4728c8
+
4728c8
+static int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
4728c8
+		      bool iekey, __u64 crkey, __u64 nrkey);
4728c8
+static int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl,
4728c8
+		       bool iekey, __u64 crkey, __u64 nrkey);
4728c8
+static int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela,
4728c8
+		      bool iekey, __u64 crkey);
4728c8
+static int nvme_resv_report(int fd, __u32 nsid, __u32 numd, __u32 cdw11, void *data);
4728c8
+
4728c8
+static int nvme_identify13(int fd, __u32 nsid, __u32 cdw10, __u32 cdw11, void *data);
4728c8
+static int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data);
4728c8
+static int nvme_identify_ctrl(int fd, void *data);
4728c8
+static int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data);
4728c8
+static int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data);
4728c8
+static int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
4728c8
+static int nvme_identify_ns_descs(int fd, __u32 nsid, void *data);
4728c8
+static int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data);
4728c8
+static int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
4728c8
+		   __u16 group_id, bool rae, __u32 data_len, void *data);
4728c8
+static int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
4728c8
+		 __u32 data_len, void *data);
4728c8
+
4728c8
+
4728c8
+static int nvme_get_telemetry_log(int fd, void *lp, int generate_report,
4728c8
+			   int ctrl_gen, size_t log_page_size, __u64 offset);
4728c8
+static int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log);
4728c8
+static int nvme_changed_ns_list_log(int fd,
4728c8
+		struct nvme_changed_ns_list_log *changed_ns_list_log);
4728c8
+static int nvme_error_log(int fd, int entries, struct nvme_error_log_page *err_log);
4728c8
+static int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log);
4728c8
+static int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo);
4728c8
+static int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log);
4728c8
+static int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size);
4728c8
+static int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log);
4728c8
+static int nvme_endurance_log(int fd, __u16 group_id,
4728c8
+		       struct nvme_endurance_group_log *endurance_log);
4728c8
+
4728c8
+static int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10,
4728c8
+		 __u32 cdw11, __u32 cdw12, __u32 data_len, void *data,
4728c8
+		 __u32 *result);
4728c8
+static int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, __u32 cdw12,
4728c8
+		     bool save, __u32 data_len, void *data, __u32 *result);
4728c8
+static int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel,
4728c8
+		     __u32 cdw11, __u32 data_len, void *data, __u32 *result);
4728c8
+
4728c8
+static int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
4728c8
+		__u8 pil, __u8 ms, __u32 timeout);
4728c8
+
4728c8
+static int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas,
4728c8
+		   __u8 dps, __u8 nmic, __u32 *result);
4728c8
+static int nvme_ns_delete(int fd, __u32 nsid);
4728c8
+
4728c8
+static int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls,
4728c8
+		       __u16 *ctrlist, bool attach);
4728c8
+static int nvme_ns_attach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist);
4728c8
+static int nvme_ns_detach_ctrls(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist);
4728c8
+
4728c8
+static int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data);
4728c8
+static int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid);
4728c8
+
4728c8
+static int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
4728c8
+		  __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result);
4728c8
+static int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
4728c8
+		  __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result);
4728c8
+
4728c8
+static int nvme_subsystem_reset(int fd);
4728c8
+static int nvme_reset_controller(int fd);
4728c8
+static int nvme_ns_rescan(int fd);
4728c8
+
4728c8
+static int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
4728c8
+		  __u32 data_len, __u32 dw12, void *data, __u32 *result);
4728c8
+static int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
4728c8
+		  __u32 data_len, __u32 dw12, void *data, __u32 *result);
4728c8
+static int nvme_get_properties(int fd, void **pbar);
4728c8
+static int nvme_set_property(int fd, int offset, int value);
4728c8
+static int nvme_get_property(int fd, int offset, uint64_t *value);
4728c8
+static int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
4728c8
+		  __u8 no_dealloc, __u32 ovrpat);
4728c8
+static int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10);
4728c8
+static int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log);
4728c8
+#endif				/* _NVME_LIB_H */
4728c8
Index: multipath-tools-130222/libmultipath/nvme-lib.c
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/nvme-lib.c
4728c8
@@ -0,0 +1,49 @@
4728c8
+#include <sys/types.h>
4728c8
+/* avoid inclusion of standard API */
4728c8
+#define _NVME_LIB_C 1
4728c8
+#include "nvme-lib.h"
4728c8
+#include "nvme-ioctl.c"
4728c8
+#include "debug.h"
4728c8
+
4728c8
+int log_nvme_errcode(int err, const char *dev, const char *msg)
4728c8
+{
4728c8
+	if (err > 0)
4728c8
+		condlog(3, "%s: %s: NVMe status %d", dev, msg, err);
4728c8
+	else if (err < 0)
4728c8
+		condlog(3, "%s: %s: %s", dev, msg, strerror(errno));
4728c8
+	return err;
4728c8
+}
4728c8
+
4728c8
+int libmp_nvme_get_nsid(int fd)
4728c8
+{
4728c8
+	return nvme_get_nsid(fd);
4728c8
+}
4728c8
+
4728c8
+int libmp_nvme_identify_ctrl(int fd, struct nvme_id_ctrl *ctrl)
4728c8
+{
4728c8
+	return nvme_identify_ctrl(fd, ctrl);
4728c8
+}
4728c8
+
4728c8
+int libmp_nvme_identify_ns(int fd, __u32 nsid, bool present,
4728c8
+			   struct nvme_id_ns *ns)
4728c8
+{
4728c8
+	return nvme_identify_ns(fd, nsid, present, ns);
4728c8
+}
4728c8
+
4728c8
+int libmp_nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo)
4728c8
+{
4728c8
+	return nvme_ana_log(fd, ana_log, ana_log_len, rgo);
4728c8
+}
4728c8
+
4728c8
+int nvme_id_ctrl_ana(int fd, struct nvme_id_ctrl *ctrl)
4728c8
+{
4728c8
+	int rc;
4728c8
+	struct nvme_id_ctrl c;
4728c8
+
4728c8
+	rc = nvme_identify_ctrl(fd, &c);
4728c8
+	if (rc < 0)
4728c8
+		return rc;
4728c8
+	if (ctrl)
4728c8
+		*ctrl = c;
4728c8
+	return c.cmic & (1 << 3) ? 1 : 0;
4728c8
+}
4728c8
Index: multipath-tools-130222/libmultipath/nvme-lib.h
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/nvme-lib.h
4728c8
@@ -0,0 +1,39 @@
4728c8
+#ifndef NVME_LIB_H
4728c8
+#define NVME_LIB_H
4728c8
+
4728c8
+#include "nvme.h"
4728c8
+
4728c8
+int log_nvme_errcode(int err, const char *dev, const char *msg);
4728c8
+int libmp_nvme_get_nsid(int fd);
4728c8
+int libmp_nvme_identify_ctrl(int fd, struct nvme_id_ctrl *ctrl);
4728c8
+int libmp_nvme_identify_ns(int fd, __u32 nsid, bool present,
4728c8
+			   struct nvme_id_ns *ns);
4728c8
+int libmp_nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo);
4728c8
+/*
4728c8
+ * Identify controller, and return true if ANA is supported
4728c8
+ * ctrl will be filled in if controller is identified, even w/o ANA
4728c8
+ * ctrl may be NULL
4728c8
+ */
4728c8
+int nvme_id_ctrl_ana(int fd, struct nvme_id_ctrl *ctrl);
4728c8
+
4728c8
+#ifndef _NVME_LIB_C
4728c8
+/*
4728c8
+ * In all files except nvme-lib.c, the nvme functions can be called
4728c8
+ * by their usual name.
4728c8
+ */
4728c8
+#define nvme_get_nsid libmp_nvme_get_nsid
4728c8
+#define nvme_identify_ctrl libmp_nvme_identify_ctrl
4728c8
+#define nvme_identify_ns libmp_nvme_identify_ns
4728c8
+#define nvme_ana_log libmp_nvme_ana_log
4728c8
+/*
4728c8
+ * Undefine these to avoid clashes with libmultipath's byteorder.h
4728c8
+ */
4728c8
+#undef cpu_to_le16
4728c8
+#undef cpu_to_le32
4728c8
+#undef cpu_to_le64
4728c8
+#undef le16_to_cpu
4728c8
+#undef le32_to_cpu
4728c8
+#undef le64_to_cpu
4728c8
+#endif
4728c8
+
4728c8
+#endif /* NVME_LIB_H */
4728c8
Index: multipath-tools-130222/libmultipath/prio.h
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/prio.h
4728c8
+++ multipath-tools-130222/libmultipath/prio.h
4728c8
@@ -29,6 +29,7 @@ struct path;
4728c8
 #define PRIO_RDAC "rdac"
4728c8
 #define PRIO_DATACORE "datacore"
4728c8
 #define PRIO_WEIGHTED_PATH "weightedpath"
4728c8
+#define PRIO_ANA "ana"
4728c8
 
4728c8
 /*
4728c8
  * Value used to mark the fact prio was not defined
4728c8
Index: multipath-tools-130222/libmultipath/prioritizers/Makefile
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/prioritizers/Makefile
4728c8
+++ multipath-tools-130222/libmultipath/prioritizers/Makefile
4728c8
@@ -2,6 +2,7 @@
4728c8
 #
4728c8
 # Copyright (C) 2007 Christophe Varoqui, <christophe.varoqui@opensvc.com>
4728c8
 #
4728c8
+TOPDIR = ../..
4728c8
 include ../../Makefile.inc
4728c8
 
4728c8
 LIBS = \
4728c8
@@ -15,9 +16,10 @@ LIBS = \
4728c8
 	libpriodatacore.so \
4728c8
 	libpriohds.so \
4728c8
 	libprioweightedpath.so \
4728c8
+	libprioana.so \
4728c8
 	libprioiet.so
4728c8
 
4728c8
-CFLAGS += -fPIC -I..
4728c8
+CFLAGS += -fPIC -I.. -I$(nvmedir)
4728c8
 
4728c8
 all: $(LIBS)
4728c8
 
4728c8
Index: multipath-tools-130222/libmultipath/prioritizers/ana.c
4728c8
===================================================================
4728c8
--- /dev/null
4728c8
+++ multipath-tools-130222/libmultipath/prioritizers/ana.c
4728c8
@@ -0,0 +1,236 @@
4728c8
+/*
4728c8
+ * (C) Copyright HUAWEI Technology Corp. 2017   All Rights Reserved.
4728c8
+ *
4728c8
+ * ana.c
4728c8
+ * Version 1.00
4728c8
+ *
4728c8
+ * Tool to make use of a NVMe-feature called  Asymmetric Namespace Access.
4728c8
+ * It determines the ANA state of a device and prints a priority value to stdout.
4728c8
+ *
4728c8
+ * Author(s): Cheng Jike <chengjike.cheng@huawei.com>
4728c8
+ *            Li Jie <lijie34@huawei.com>
4728c8
+ *
4728c8
+ * This file is released under the GPL version 2, or any later version.
4728c8
+ */
4728c8
+#include <stdio.h>
4728c8
+#include <sys/ioctl.h>
4728c8
+#include <sys/stat.h>
4728c8
+#include <sys/types.h>
4728c8
+#include <stdbool.h>
4728c8
+#include <libudev.h>
4728c8
+
4728c8
+#include "debug.h"
4728c8
+#include "nvme-lib.h"
4728c8
+#include "prio.h"
4728c8
+#include "util.h"
4728c8
+#include "structs.h"
4728c8
+#include "def_func.h"
4728c8
+
4728c8
+enum {
4728c8
+	ANA_ERR_GETCTRL_FAILED		= 1,
4728c8
+	ANA_ERR_NOT_NVME,
4728c8
+	ANA_ERR_NOT_SUPPORTED,
4728c8
+	ANA_ERR_GETANAS_OVERFLOW,
4728c8
+	ANA_ERR_GETANAS_NOTFOUND,
4728c8
+	ANA_ERR_GETANALOG_FAILED,
4728c8
+	ANA_ERR_GETNSID_FAILED,
4728c8
+	ANA_ERR_GETNS_FAILED,
4728c8
+	ANA_ERR_NO_MEMORY,
4728c8
+	ANA_ERR_NO_INFORMATION,
4728c8
+};
4728c8
+
4728c8
+static const char *ana_errmsg[] = {
4728c8
+	[ANA_ERR_GETCTRL_FAILED]	= "couldn't get ctrl info",
4728c8
+	[ANA_ERR_NOT_NVME]		= "not an NVMe device",
4728c8
+	[ANA_ERR_NOT_SUPPORTED]		= "ANA not supported",
4728c8
+	[ANA_ERR_GETANAS_OVERFLOW]	= "buffer overflow in ANA log",
4728c8
+	[ANA_ERR_GETANAS_NOTFOUND]	= "NSID or ANAGRPID not found",
4728c8
+	[ANA_ERR_GETANALOG_FAILED]	= "couldn't get ana log",
4728c8
+	[ANA_ERR_GETNSID_FAILED]	= "couldn't get NSID",
4728c8
+	[ANA_ERR_GETNS_FAILED]		= "couldn't get namespace info",
4728c8
+	[ANA_ERR_NO_MEMORY]		= "out of memory",
4728c8
+	[ANA_ERR_NO_INFORMATION]	= "invalid fd",
4728c8
+};
4728c8
+
4728c8
+static const char *anas_string[] = {
4728c8
+	[NVME_ANA_OPTIMIZED]			= "ANA Optimized State",
4728c8
+	[NVME_ANA_NONOPTIMIZED]			= "ANA Non-Optimized State",
4728c8
+	[NVME_ANA_INACCESSIBLE]			= "ANA Inaccessible State",
4728c8
+	[NVME_ANA_PERSISTENT_LOSS]		= "ANA Persistent Loss State",
4728c8
+	[NVME_ANA_CHANGE]			= "ANA Change state",
4728c8
+};
4728c8
+
4728c8
+static const char *aas_print_string(int rc)
4728c8
+{
4728c8
+	rc &= 0xff;
4728c8
+	if (rc >= 0 && rc < ARRAY_SIZE(anas_string) &&
4728c8
+	    anas_string[rc] != NULL)
4728c8
+		return anas_string[rc];
4728c8
+
4728c8
+	return "invalid ANA state";
4728c8
+}
4728c8
+
4728c8
+static int get_ana_state(__u32 nsid, __u32 anagrpid, void *ana_log,
4728c8
+			 size_t ana_log_len)
4728c8
+{
4728c8
+	void *base = ana_log;
4728c8
+	struct nvme_ana_rsp_hdr *hdr = base;
4728c8
+	struct nvme_ana_group_desc *ana_desc;
4728c8
+	size_t offset = sizeof(struct nvme_ana_rsp_hdr);
4728c8
+	__u32 nr_nsids;
4728c8
+	size_t nsid_buf_size;
4728c8
+	int i, j;
4728c8
+
4728c8
+	for (i = 0; i < le16_to_cpu(hdr->ngrps); i++) {
4728c8
+		ana_desc = base + offset;
4728c8
+
4728c8
+		offset += sizeof(*ana_desc);
4728c8
+		if (offset > ana_log_len)
4728c8
+			return -ANA_ERR_GETANAS_OVERFLOW;
4728c8
+
4728c8
+		nr_nsids = le32_to_cpu(ana_desc->nnsids);
4728c8
+		nsid_buf_size = nr_nsids * sizeof(__le32);
4728c8
+
4728c8
+		offset += nsid_buf_size;
4728c8
+		if (offset > ana_log_len)
4728c8
+			return -ANA_ERR_GETANAS_OVERFLOW;
4728c8
+
4728c8
+		for (j = 0; j < nr_nsids; j++) {
4728c8
+			if (nsid == le32_to_cpu(ana_desc->nsids[j]))
4728c8
+				return ana_desc->state;
4728c8
+		}
4728c8
+
4728c8
+		if (anagrpid != 0 && anagrpid == le32_to_cpu(ana_desc->grpid))
4728c8
+			return ana_desc->state;
4728c8
+
4728c8
+	}
4728c8
+	return -ANA_ERR_GETANAS_NOTFOUND;
4728c8
+}
4728c8
+
4728c8
+int get_ana_info(struct path * pp, unsigned int timeout)
4728c8
+{
4728c8
+	int	rc;
4728c8
+	__u32 nsid;
4728c8
+	struct nvme_id_ctrl ctrl;
4728c8
+	struct nvme_id_ns ns;
4728c8
+	void *ana_log;
4728c8
+	size_t ana_log_len;
4728c8
+	bool is_anagrpid_const;
4728c8
+
4728c8
+	rc = nvme_id_ctrl_ana(pp->fd, &ctrl);
4728c8
+	if (rc < 0) {
4728c8
+		log_nvme_errcode(rc, pp->dev, "nvme_identify_ctrl");
4728c8
+		return -ANA_ERR_GETCTRL_FAILED;
4728c8
+	} else if (rc == 0)
4728c8
+		return -ANA_ERR_NOT_SUPPORTED;
4728c8
+
4728c8
+	nsid = nvme_get_nsid(pp->fd);
4728c8
+	if (nsid <= 0) {
4728c8
+		log_nvme_errcode(rc, pp->dev, "nvme_get_nsid");
4728c8
+		return -ANA_ERR_GETNSID_FAILED;
4728c8
+	}
4728c8
+	is_anagrpid_const = ctrl.anacap & (1 << 6);
4728c8
+
4728c8
+	/*
4728c8
+	 * Code copied from nvme-cli/nvme.c. We don't need to allocate an
4728c8
+	 * [nanagrpid*mnan] array of NSIDs because each NSID can occur at most
4728c8
+	 * in one ANA group.
4728c8
+	 */
4728c8
+	ana_log_len = sizeof(struct nvme_ana_rsp_hdr) +
4728c8
+		le32_to_cpu(ctrl.nanagrpid)
4728c8
+		* sizeof(struct nvme_ana_group_desc);
4728c8
+
4728c8
+	if (is_anagrpid_const) {
4728c8
+		rc = nvme_identify_ns(pp->fd, nsid, 0, &ns);
4728c8
+		if (rc) {
4728c8
+			log_nvme_errcode(rc, pp->dev, "nvme_identify_ns");
4728c8
+			return -ANA_ERR_GETNS_FAILED;
4728c8
+		}
4728c8
+	} else
4728c8
+		ana_log_len += le32_to_cpu(ctrl.mnan) * sizeof(__le32);
4728c8
+
4728c8
+	ana_log = malloc(ana_log_len);
4728c8
+	if (!ana_log)
4728c8
+		return -ANA_ERR_NO_MEMORY;
4728c8
+	pthread_cleanup_push(free, ana_log);
4728c8
+	rc = nvme_ana_log(pp->fd, ana_log, ana_log_len,
4728c8
+			  is_anagrpid_const ? NVME_ANA_LOG_RGO : 0);
4728c8
+	if (rc) {
4728c8
+		log_nvme_errcode(rc, pp->dev, "nvme_ana_log");
4728c8
+		rc = -ANA_ERR_GETANALOG_FAILED;
4728c8
+	} else
4728c8
+		rc = get_ana_state(nsid,
4728c8
+				   is_anagrpid_const ?
4728c8
+				   le32_to_cpu(ns.anagrpid) : 0,
4728c8
+				   ana_log, ana_log_len);
4728c8
+	pthread_cleanup_pop(1);
4728c8
+	if (rc >= 0)
4728c8
+		condlog(3, "%s: ana state = %02x [%s]", pp->dev, rc,
4728c8
+			aas_print_string(rc));
4728c8
+	return rc;
4728c8
+}
4728c8
+
4728c8
+/*
4728c8
+ * Priorities modeled roughly after the ALUA model (alua.c/sysfs.c)
4728c8
+ * Reference: ANA Base Protocol (NVMe TP 4004a, 11/13/2018).
4728c8
+ *
4728c8
+ * Differences:
4728c8
+ *
4728c8
+ * - The ANA base spec defines no implicit or explicit (STPG) state management.
4728c8
+ *   If a state is encountered that doesn't allow normal I/O (all except
4728c8
+ *   OPTIMIZED and NON_OPTIMIZED), we can't do anything but either wait for a
4728c8
+ *   Access State Change Notice (can't do that in multipathd as we don't receive
4728c8
+ *   those), or retry commands in regular time intervals until ANATT is expired
4728c8
+ *   (not implemented). Mapping UNAVAILABLE state to ALUA STANDBY is the best we
4728c8
+ *   can currently do.
4728c8
+ *
4728c8
+ *   FIXME: Waiting for ANATT could be implemented with a "delayed failback"
4728c8
+ *   mechanism. The current "failback" method can't be used, as it would
4728c8
+ *   affect failback to every state, and here only failback to UNAVAILABLE
4728c8
+ *   should be delayed.
4728c8
+ *
4728c8
+ * - PERSISTENT_LOSS state is even below ALUA's UNAVAILABLE state.
4728c8
+ *   FIXME: According to the ANA TP, accessing paths in PERSISTENT_LOSS state
4728c8
+ *   in any way makes no sense (e.g. §8.19.6 - paths in this state shouldn't
4728c8
+ *   even be checked under "all paths down" conditions). Device mapper can,
4728c8
+ *   and will, select a PG for IO if it has non-failed paths, even if the
4728c8
+ *   PG has priority 0. We could avoid that only with an "ANA path checker".
4728c8
+ *
4728c8
+ * - ALUA has no CHANGE state. The ANA TP §8.18.3 / §8.19.4 suggests
4728c8
+ *   that CHANGE state should be treated in roughly the same way as
4728c8
+ *   INACCESSIBLE. Therefore we assign the same prio to it.
4728c8
+ *
4728c8
+ * - ALUA's LBA-dependent state has no ANA equivalent.
4728c8
+ */
4728c8
+
4728c8
+int getprio(struct path *pp, char *args)
4728c8
+{
4728c8
+	int rc;
4728c8
+
4728c8
+	if (pp->fd < 0)
4728c8
+		rc = -ANA_ERR_NO_INFORMATION;
4728c8
+	else
4728c8
+		rc = get_ana_info(pp, get_prio_timeout(60000));
4728c8
+
4728c8
+	switch (rc) {
4728c8
+	case NVME_ANA_OPTIMIZED:
4728c8
+		return 50;
4728c8
+	case NVME_ANA_NONOPTIMIZED:
4728c8
+		return 10;
4728c8
+	case NVME_ANA_INACCESSIBLE:
4728c8
+	case NVME_ANA_CHANGE:
4728c8
+		return 1;
4728c8
+	case NVME_ANA_PERSISTENT_LOSS:
4728c8
+		return 0;
4728c8
+	default:
4728c8
+		break;
4728c8
+	}
4728c8
+	if (rc < 0 && -rc < ARRAY_SIZE(ana_errmsg))
4728c8
+		condlog(2, "%s: ANA error: %s", pp->dev, ana_errmsg[-rc]);
4728c8
+	else
4728c8
+		condlog(1, "%s: invalid ANA rc code %d", pp->dev, rc);
4728c8
+	return -1;
4728c8
+}
4728c8
+
4728c8
+declare_nop_prio(initprio)
4728c8
+declare_nop_prio(freeprio)
4728c8
Index: multipath-tools-130222/libmultipath/util.h
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/util.h
4728c8
+++ multipath-tools-130222/libmultipath/util.h
4728c8
@@ -18,6 +18,8 @@ int parse_prkey(char *ptr, uint64_t *prk
4728c8
 int parse_prkey_flags(char *ptr, uint64_t *prkey, uint8_t *flags);
4728c8
 int safe_write(int fd, const void *buf, size_t count);
4728c8
 
4728c8
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
4728c8
+
4728c8
 #define safe_sprintf(var, format, args...)	\
4728c8
 	snprintf(var, sizeof(var), format, ##args) >= sizeof(var)
4728c8
 #define safe_snprintf(var, size, format, args...)      \
4728c8
Index: multipath-tools-130222/multipath/multipath.conf.5
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/multipath/multipath.conf.5
4728c8
+++ multipath-tools-130222/multipath/multipath.conf.5
4728c8
@@ -196,6 +196,9 @@ Generate the path priority for LSI/Engen
4728c8
 Generate the path priority for Compaq/HP controller in
4728c8
 active/standby mode.
4728c8
 .TP
4728c8
+.B ana
4728c8
+Generate the path priority based on the NVMe ANA settings.
4728c8
+.TP
4728c8
 .B hds
4728c8
 Generate the path priority for Hitachi HDS Modular storage arrays.
4728c8
 .TP
4728c8
Index: multipath-tools-130222/libmultipath/propsel.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/propsel.c
4728c8
+++ multipath-tools-130222/libmultipath/propsel.c
4728c8
@@ -5,6 +5,7 @@
4728c8
  */
4728c8
 #include <stdio.h>
4728c8
 
4728c8
+#include "nvme-lib.h"
4728c8
 #include "checkers.h"
4728c8
 #include "memory.h"
4728c8
 #include "vector.h"
4728c8
@@ -489,8 +490,13 @@ select_getuid (struct path * pp)
4728c8
 void
4728c8
 detect_prio(struct path * pp)
4728c8
 {
4728c8
-	if (detect_alua(pp))
4728c8
-		prio_get(&pp->prio, PRIO_ALUA, DEFAULT_PRIO_ARGS);
4728c8
+	if (pp->bus == SYSFS_BUS_NVME) {
4728c8
+		if (nvme_id_ctrl_ana(pp->fd, NULL) == 1)
4728c8
+			prio_get(&pp->prio, PRIO_ANA, DEFAULT_PRIO_ARGS);
4728c8
+	} else if (pp->bus == SYSFS_BUS_SCSI) {
4728c8
+		if (detect_alua(pp))
4728c8
+			prio_get(&pp->prio, PRIO_ALUA, DEFAULT_PRIO_ARGS);
4728c8
+	}
4728c8
 }
4728c8
 
4728c8
 extern int
4728c8
Index: multipath-tools-130222/libmultipath/hwtable.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/hwtable.c
4728c8
+++ multipath-tools-130222/libmultipath/hwtable.c
4728c8
@@ -1178,6 +1178,7 @@ static struct hwentry default_hw[] = {
4728c8
 		.vendor        = "NVME",
4728c8
 		.product       = ".*",
4728c8
 		.uid_attribute = "ID_WWN",
4728c8
+		.detect_prio   = DETECT_PRIO_ON,
4728c8
 		.checker_name  = NONE,
4728c8
 	},
4728c8
 	/*