Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2018-08-02 17:24:00 +0200
committerTakashi Iwai <tiwai@suse.de>2018-08-02 17:24:00 +0200
commite56f895e04266452c0629115b548d62104870ffe (patch)
tree34c41a2cd2a731b22bff2ef369d1dd1dca73dd50
parent79a523e93a075e9572bb27cb845ccae44d545657 (diff)
parent0d43d1b4ba12e9cf065e53566785f26c0379f18b (diff)
Merge branch 'users/hare/SLE15/for-next' into SLE15
Pull nvme fixes from Hannes Reinecke
-rw-r--r--patches.drivers/nvme-add-ANA-support.patch724
-rw-r--r--patches.drivers/nvme-remove-nvme_req_needs_failover.patch82
-rw-r--r--patches.drivers/nvme-simplify-the-API-for-getting-log-pages.patch118
-rw-r--r--patches.drivers/nvme.h-add-ANA-definitions.patch131
-rw-r--r--patches.drivers/nvme.h-add-support-for-the-log-specific-field.patch37
-rw-r--r--patches.drivers/nvmet-add-minimal-ANA-support.patch327
-rw-r--r--patches.drivers/nvmet-keep-a-port-pointer-in-nvmet_ctrl.patch49
-rw-r--r--patches.drivers/nvmet-support-configuring-ANA-groups.patch396
-rw-r--r--patches.drivers/nvmet-track-and-limit-the-number-of-namespaces-per-s.patch101
-rw-r--r--patches.drivers/nvmet-use-Retain-Async-Event-bit-to-clear-AEN.patch71
-rw-r--r--patches.fixes/nvmet-fixup-crash-on-NULL-device-path.patch56
-rw-r--r--patches.kabi/Revert-nvmet-constify-struct-nvmet_fabrics_ops.patch6
-rw-r--r--patches.kabi/nvme-guard-additional-fields-in-nvme-command-structu.patch77
-rw-r--r--patches.kabi/nvme-kABI-fix-for-ANA-support-in-nvme_ctrl.patch113
-rw-r--r--patches.kabi/nvme-kABI-fixes-for-nvme_ctrl.patch4
-rw-r--r--patches.kabi/nvme-kABI-fixes-for-nvmet.patch7
-rw-r--r--patches.kabi/nvme-partially-revert-nvme-remove-nvme_req_needs_fai.patch59
-rw-r--r--patches.kabi/nvme-reintroduce-nvme_get_log_ext.patch48
-rw-r--r--patches.kabi/nvmet-kABI-fixes-for-ANA-support.patch72
-rw-r--r--series.conf18
20 files changed, 2489 insertions, 7 deletions
diff --git a/patches.drivers/nvme-add-ANA-support.patch b/patches.drivers/nvme-add-ANA-support.patch
new file mode 100644
index 0000000000..cb9d3c553e
--- /dev/null
+++ b/patches.drivers/nvme-add-ANA-support.patch
@@ -0,0 +1,724 @@
+From: Christoph Hellwig <hch@lst.de>
+Date: Mon, 14 May 2018 08:48:54 +0200
+Subject: [PATCH] nvme: add ANA support
+Git-commit: 0d0b660f214dc4905db7b6bc998bad0c16dfb1ba
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: bsc#1054245
+
+Add support for Asynchronous Namespace Access as specified in NVMe 1.3
+TP 4004. With ANA each namespace attached to a controller belongs to an
+ANA group that describes the characteristics of accessing the namespaces
+through this controller. In the optimized and non-optimized states
+namespaces can be accessed regularly, although in a multi-pathing
+environment we should always prefer to access a namespace through a
+controller where an optimized relationship exists. Namespaces in
+Inaccessible, Permanent-Loss or Change state for a given controller
+should not be accessed.
+
+The states are updated through reading the ANA log page, which is read
+once during controller initialization, whenever the ANA change notice
+AEN is received, or when one of the ANA specific status codes that
+signal a state change is received on a command.
+
+The ANA state is kept in the nvme_ns structure, which makes the checks in
+the fast path very simple. Updating the ANA state when reading the log
+page is also very simple, the only downside is that finding the initial
+ANA state when scanning for namespaces is a bit cumbersome.
+
+The gendisk for a ns_head is only registered once a live path for it
+exists. Without that the kernel would hang during partition scanning.
+
+Includes fixes and improvements from Hannes Reinecke.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Keith Busch <keith.busch@intel.com>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+---
+ drivers/nvme/host/core.c | 34 ++++-
+ drivers/nvme/host/multipath.c | 345 ++++++++++++++++++++++++++++++++++++++++--
+ drivers/nvme/host/nvme.h | 51 ++++++-
+ 3 files changed, 407 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
+index 40ca63930261..e9f82814eb68 100644
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -1042,7 +1042,7 @@ int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
+ EXPORT_SYMBOL_GPL(nvme_set_queue_count);
+
+ #define NVME_AEN_SUPPORTED \
+- (NVME_AEN_CFG_NS_ATTR | NVME_AEN_CFG_FW_ACT)
++ (NVME_AEN_CFG_NS_ATTR | NVME_AEN_CFG_FW_ACT | NVME_AEN_CFG_ANA_CHANGE)
+
+ static void nvme_enable_aen(struct nvme_ctrl *ctrl)
+ {
+@@ -2373,6 +2373,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
+ nvme_set_queue_limits(ctrl, ctrl->admin_q);
+ ctrl->sgls = le32_to_cpu(id->sgls);
+ ctrl->kas = le16_to_cpu(id->kas);
++ ctrl->max_namespaces = le32_to_cpu(id->mnan);
+
+ if (id->rtd3e) {
+ /* us -> s */
+@@ -2432,8 +2433,12 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
+ ctrl->hmmaxd = le16_to_cpu(id->hmmaxd);
+ }
+
++ ret = nvme_mpath_init(ctrl, id);
+ kfree(id);
+
++ if (ret < 0)
++ return ret;
++
+ if (ctrl->apst_enabled && !prev_apst_enabled)
+ dev_pm_qos_expose_latency_tolerance(ctrl->device);
+ else if (!ctrl->apst_enabled && prev_apst_enabled)
+@@ -2652,6 +2657,10 @@ static struct attribute *nvme_ns_id_attrs[] = {
+ &dev_attr_nguid.attr,
+ &dev_attr_eui.attr,
+ &dev_attr_nsid.attr,
++#ifdef CONFIG_NVME_MULTIPATH
++ &dev_attr_ana_grpid.attr,
++ &dev_attr_ana_state.attr,
++#endif
+ NULL,
+ };
+
+@@ -2674,6 +2683,14 @@ static umode_t nvme_ns_id_attrs_are_visible(struct kobject *kobj,
+ if (!memchr_inv(ids->eui64, 0, sizeof(ids->eui64)))
+ return 0;
+ }
++#ifdef CONFIG_NVME_MULTIPATH
++ if (a == &dev_attr_ana_grpid.attr || a == &dev_attr_ana_state.attr) {
++ if (dev_to_disk(dev)->fops != &nvme_fops) /* per-path attr */
++ return 0;
++ if (!nvme_ctrl_use_ana(nvme_get_ns_from_dev(dev)->ctrl))
++ return 0;
++ }
++#endif
+ return a->mode;
+ }
+
+@@ -3047,8 +3064,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+
+ nvme_get_ctrl(ctrl);
+
+- kfree(id);
+-
+ device_add_disk(ctrl->device, ns->disk);
+ if (sysfs_create_group(&disk_to_dev(ns->disk)->kobj,
+ &nvme_ns_id_attr_group))
+@@ -3058,7 +3073,9 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+ pr_warn("%s: failed to register lightnvm sysfs group for identification\n",
+ ns->disk->disk_name);
+
+- nvme_mpath_add_disk(ns->head);
++ nvme_mpath_add_disk(ns, id);
++ kfree(id);
++
+ return;
+ out_unlink_ns:
+ mutex_lock(&ctrl->subsys->lock);
+@@ -3353,6 +3370,13 @@ static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result)
+ case NVME_AER_NOTICE_FW_ACT_STARTING:
+ queue_work(nvme_wq, &ctrl->fw_act_work);
+ break;
++#ifdef CONFIG_NVME_MULTIPATH
++ case NVME_AER_NOTICE_ANA:
++ if (!ctrl->ana_log_buf)
++ break;
++ queue_work(nvme_wq, &ctrl->ana_work);
++ break;
++#endif
+ default:
+ dev_warn(ctrl->device, "async event result %08x\n", result);
+ }
+@@ -3385,6 +3409,7 @@ EXPORT_SYMBOL_GPL(nvme_complete_async_event);
+
+ void nvme_stop_ctrl(struct nvme_ctrl *ctrl)
+ {
++ nvme_mpath_stop(ctrl);
+ nvme_stop_keep_alive(ctrl);
+ flush_work(&ctrl->async_event_work);
+ flush_work(&ctrl->scan_work);
+@@ -3420,6 +3445,7 @@ static void nvme_free_ctrl(struct device *dev)
+
+ ida_simple_remove(&nvme_instance_ida, ctrl->instance);
+ kfree(ctrl->effects);
++ nvme_mpath_uninit(ctrl);
+
+ if (subsys) {
+ mutex_lock(&subsys->lock);
+diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
+index 16996dea5900..420efcda33d9 100644
+--- a/drivers/nvme/host/multipath.c
++++ b/drivers/nvme/host/multipath.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2017 Christoph Hellwig.
++ * Copyright (c) 2017-2018 Christoph Hellwig.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+@@ -15,11 +15,18 @@
+ #include <trace/events/block.h>
+ #include "nvme.h"
+
++#define SECTOR_SHIFT 9
++
+ static bool multipath = true;
+ module_param(multipath, bool, 0444);
+ MODULE_PARM_DESC(multipath,
+ "turn on native support for multiple controllers per subsystem");
+
++inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
++{
++ return multipath && (ctrl->subsys->cmic & (1 << 3));
++}
++
+ /*
+ * If multipathing is enabled we need to always use the subsystem instance
+ * number for numbering our devices to avoid conflicts between subsystems that
+@@ -45,6 +52,7 @@ void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
+ void nvme_failover_req(struct request *req)
+ {
+ struct nvme_ns *ns = req->q->queuedata;
++ u16 status = nvme_req(req)->status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ns->head->requeue_lock, flags);
+@@ -52,7 +60,34 @@ void nvme_failover_req(struct request *req)
+ spin_unlock_irqrestore(&ns->head->requeue_lock, flags);
+ blk_mq_end_request(req, 0);
+
+- nvme_reset_ctrl(ns->ctrl);
++ switch (status & 0x7ff) {
++ case NVME_SC_ANA_TRANSITION:
++ case NVME_SC_ANA_INACCESSIBLE:
++ case NVME_SC_ANA_PERSISTENT_LOSS:
++ /*
++ * If we got back an ANA error we know the controller is alive,
++ * but not ready to serve this namespaces. The spec suggests
++ * we should update our general state here, but due to the fact
++ * that the admin and I/O queues are not serialized that is
++ * fundamentally racy. So instead just clear the current path,
++ * mark the the path as pending and kick of a re-read of the ANA
++ * log page ASAP.
++ */
++ nvme_mpath_clear_current_path(ns);
++ if (ns->ctrl->ana_log_buf) {
++ set_bit(NVME_NS_ANA_PENDING, &ns->flags);
++ queue_work(nvme_wq, &ns->ctrl->ana_work);
++ }
++ break;
++ default:
++ /*
++ * Reset the controller for any non-ANA error as we don't know
++ * what caused the error.
++ */
++ nvme_reset_ctrl(ns->ctrl);
++ break;
++ }
++
+ kblockd_schedule_work(&ns->head->requeue_work);
+ }
+
+@@ -68,25 +103,51 @@ void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
+ mutex_unlock(&ctrl->namespaces_mutex);
+ }
+
++static const char *nvme_ana_state_names[] = {
++ [0] = "invalid state",
++ [NVME_ANA_OPTIMIZED] = "optimized",
++ [NVME_ANA_NONOPTIMIZED] = "non-optimized",
++ [NVME_ANA_INACCESSIBLE] = "inaccessible",
++ [NVME_ANA_PERSISTENT_LOSS] = "persistent-loss",
++ [NVME_ANA_CHANGE] = "change",
++};
++
+ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head)
+ {
+- struct nvme_ns *ns;
++ struct nvme_ns *ns, *fallback = NULL;
+
+ list_for_each_entry_rcu(ns, &head->list, siblings) {
+- if (ns->ctrl->state == NVME_CTRL_LIVE) {
++ if (ns->ctrl->state != NVME_CTRL_LIVE ||
++ test_bit(NVME_NS_ANA_PENDING, &ns->flags))
++ continue;
++ switch (ns->ana_state) {
++ case NVME_ANA_OPTIMIZED:
+ rcu_assign_pointer(head->current_path, ns);
+ return ns;
++ case NVME_ANA_NONOPTIMIZED:
++ fallback = ns;
++ break;
++ default:
++ break;
+ }
+ }
+
+- return NULL;
++ if (fallback)
++ rcu_assign_pointer(head->current_path, fallback);
++ return fallback;
++}
++
++static inline bool nvme_path_is_optimized(struct nvme_ns *ns)
++{
++ return ns->ctrl->state == NVME_CTRL_LIVE &&
++ ns->ana_state == NVME_ANA_OPTIMIZED;
+ }
+
+ inline struct nvme_ns *nvme_find_path(struct nvme_ns_head *head)
+ {
+ struct nvme_ns *ns = srcu_dereference(head->current_path, &head->srcu);
+
+- if (unlikely(!ns || ns->ctrl->state != NVME_CTRL_LIVE))
++ if (unlikely(!ns || !nvme_path_is_optimized(ns)))
+ ns = __nvme_find_path(head);
+ return ns;
+ }
+@@ -135,7 +196,7 @@ static bool nvme_ns_head_poll(struct request_queue *q, blk_qc_t qc)
+
+ srcu_idx = srcu_read_lock(&head->srcu);
+ ns = srcu_dereference(head->current_path, &head->srcu);
+- if (likely(ns && ns->ctrl->state == NVME_CTRL_LIVE))
++ if (likely(ns && nvme_path_is_optimized(ns)))
+ found = ns->queue->poll_fn(q, qc);
+ srcu_read_unlock(&head->srcu, srcu_idx);
+ return found;
+@@ -169,6 +230,7 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
+ struct request_queue *q;
+ bool vwc = false;
+
++ mutex_init(&head->lock);
+ bio_list_init(&head->requeue_list);
+ spin_lock_init(&head->requeue_lock);
+ INIT_WORK(&head->requeue_work, nvme_requeue_work);
+@@ -213,29 +275,232 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
+ return -ENOMEM;
+ }
+
+-void nvme_mpath_add_disk(struct nvme_ns_head *head)
++static void nvme_mpath_set_live(struct nvme_ns *ns)
+ {
++ struct nvme_ns_head *head = ns->head;
++
++ lockdep_assert_held(&ns->head->lock);
++
+ if (!head->disk)
+ return;
+
+- mutex_lock(&head->subsys->lock);
+ if (!(head->disk->flags & GENHD_FL_UP)) {
+ device_add_disk(&head->subsys->dev, head->disk);
+ if (sysfs_create_group(&disk_to_dev(head->disk)->kobj,
+ &nvme_ns_id_attr_group))
+- pr_warn("%s: failed to create sysfs group for identification\n",
+- head->disk->disk_name);
++ dev_warn(&head->subsys->dev,
++ "failed to create id group.\n");
++ }
++
++ kblockd_schedule_work(&ns->head->requeue_work);
++}
++
++static int nvme_parse_ana_log(struct nvme_ctrl *ctrl, void *data,
++ int (*cb)(struct nvme_ctrl *ctrl, struct nvme_ana_group_desc *,
++ void *))
++{
++ void *base = ctrl->ana_log_buf;
++ size_t offset = sizeof(struct nvme_ana_rsp_hdr);
++ int error, i;
++
++ lockdep_assert_held(&ctrl->ana_lock);
++
++ for (i = 0; i < le16_to_cpu(ctrl->ana_log_buf->ngrps); i++) {
++ struct nvme_ana_group_desc *desc = base + offset;
++ u32 nr_nsids = le32_to_cpu(desc->nnsids);
++ size_t nsid_buf_size = nr_nsids * sizeof(__le32);
++
++ if (WARN_ON_ONCE(desc->grpid == 0))
++ return -EINVAL;
++ if (WARN_ON_ONCE(le32_to_cpu(desc->grpid) > ctrl->anagrpmax))
++ return -EINVAL;
++ if (WARN_ON_ONCE(desc->state == 0))
++ return -EINVAL;
++ if (WARN_ON_ONCE(desc->state > NVME_ANA_CHANGE))
++ return -EINVAL;
++
++ offset += sizeof(*desc);
++ if (WARN_ON_ONCE(offset > ctrl->ana_log_size - nsid_buf_size))
++ return -EINVAL;
++
++ error = cb(ctrl, desc, data);
++ if (error)
++ return error;
++
++ offset += nsid_buf_size;
++ if (WARN_ON_ONCE(offset > ctrl->ana_log_size - sizeof(*desc)))
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static inline bool nvme_state_is_live(enum nvme_ana_state state)
++{
++ return state == NVME_ANA_OPTIMIZED || state == NVME_ANA_NONOPTIMIZED;
++}
++
++static void nvme_update_ns_ana_state(struct nvme_ana_group_desc *desc,
++ struct nvme_ns *ns)
++{
++ enum nvme_ana_state old;
++
++ mutex_lock(&ns->head->lock);
++ old = ns->ana_state;
++ ns->ana_grpid = le32_to_cpu(desc->grpid);
++ ns->ana_state = desc->state;
++ clear_bit(NVME_NS_ANA_PENDING, &ns->flags);
++
++ if (nvme_state_is_live(ns->ana_state) && !nvme_state_is_live(old))
++ nvme_mpath_set_live(ns);
++ mutex_unlock(&ns->head->lock);
++}
++
++static int nvme_update_ana_state(struct nvme_ctrl *ctrl,
++ struct nvme_ana_group_desc *desc, void *data)
++{
++ u32 nr_nsids = le32_to_cpu(desc->nnsids), n = 0;
++ unsigned *nr_change_groups = data;
++ struct nvme_ns *ns;
++
++ dev_info(ctrl->device, "ANA group %d: %s.\n",
++ le32_to_cpu(desc->grpid),
++ nvme_ana_state_names[desc->state]);
++
++ if (desc->state == NVME_ANA_CHANGE)
++ (*nr_change_groups)++;
++
++ if (!nr_nsids)
++ return 0;
++
++ mutex_lock(&ctrl->namespaces_mutex);
++ list_for_each_entry(ns, &ctrl->namespaces, list) {
++ if (ns->head->ns_id != le32_to_cpu(desc->nsids[n]))
++ continue;
++ nvme_update_ns_ana_state(desc, ns);
++ if (++n == nr_nsids)
++ break;
++ }
++ mutex_unlock(&ctrl->namespaces_mutex);
++ WARN_ON_ONCE(n < nr_nsids);
++ return 0;
++}
++
++static int nvme_read_ana_log(struct nvme_ctrl *ctrl, bool groups_only)
++{
++ u32 nr_change_groups = 0;
++ int error;
++
++ mutex_lock(&ctrl->ana_lock);
++ error = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_ANA,
++ groups_only ? NVME_ANA_LOG_RGO : 0,
++ ctrl->ana_log_buf, ctrl->ana_log_size, 0);
++ if (error) {
++ dev_warn(ctrl->device, "Failed to get ANA log: %d\n", error);
++ goto out_unlock;
++ }
++
++ error = nvme_parse_ana_log(ctrl, &nr_change_groups,
++ nvme_update_ana_state);
++ if (error)
++ goto out_unlock;
++
++ /*
++ * In theory we should have an ANATT timer per group as they might enter
++ * the change state at different times. But that is a lot of overhead
++ * just to protect against a target that keeps entering new changes
++ * states while never finishing previous ones. But we'll still
++ * eventually time out once all groups are in change state, so this
++ * isn't a big deal.
++ *
++ * We also double the ANATT value to provide some slack for transports
++ * or AEN processing overhead.
++ */
++ if (nr_change_groups)
++ mod_timer(&ctrl->anatt_timer, ctrl->anatt * HZ * 2 + jiffies);
++ else
++ del_timer_sync(&ctrl->anatt_timer);
++out_unlock:
++ mutex_unlock(&ctrl->ana_lock);
++ return error;
++}
++
++static void nvme_ana_work(struct work_struct *work)
++{
++ struct nvme_ctrl *ctrl = container_of(work, struct nvme_ctrl, ana_work);
++
++ nvme_read_ana_log(ctrl, false);
++}
++
++static void nvme_anatt_timeout(unsigned long data)
++{
++ struct nvme_ctrl *ctrl = (struct nvme_ctrl *)data;
++
++ dev_info(ctrl->device, "ANATT timeout, resetting controller.\n");
++ nvme_reset_ctrl(ctrl);
++}
++
++void nvme_mpath_stop(struct nvme_ctrl *ctrl)
++{
++ if (!nvme_ctrl_use_ana(ctrl))
++ return;
++ del_timer_sync(&ctrl->anatt_timer);
++ cancel_work_sync(&ctrl->ana_work);
++}
++
++static ssize_t ana_grpid_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ return sprintf(buf, "%d\n", nvme_get_ns_from_dev(dev)->ana_grpid);
++}
++DEVICE_ATTR_RO(ana_grpid);
++
++static ssize_t ana_state_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
++
++ return sprintf(buf, "%s\n", nvme_ana_state_names[ns->ana_state]);
++}
++DEVICE_ATTR_RO(ana_state);
++
++static int nvme_set_ns_ana_state(struct nvme_ctrl *ctrl,
++ struct nvme_ana_group_desc *desc, void *data)
++{
++ struct nvme_ns *ns = data;
++
++ if (ns->ana_grpid == le32_to_cpu(desc->grpid)) {
++ nvme_update_ns_ana_state(desc, ns);
++ return -ENXIO; /* just break out of the loop */
++ }
++
++ return 0;
++}
++
++void nvme_mpath_add_disk(struct nvme_ns *ns, struct nvme_id_ns *id)
++{
++ if (nvme_ctrl_use_ana(ns->ctrl)) {
++ mutex_lock(&ns->ctrl->ana_lock);
++ ns->ana_grpid = le32_to_cpu(id->anagrpid);
++ nvme_parse_ana_log(ns->ctrl, ns, nvme_set_ns_ana_state);
++ mutex_unlock(&ns->ctrl->ana_lock);
++ } else {
++ mutex_lock(&ns->head->lock);
++ ns->ana_state = NVME_ANA_OPTIMIZED;
++ nvme_mpath_set_live(ns);
++ mutex_unlock(&ns->head->lock);
+ }
+- mutex_unlock(&head->subsys->lock);
+ }
+
+ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
+ {
+ if (!head->disk)
+ return;
+- sysfs_remove_group(&disk_to_dev(head->disk)->kobj,
+- &nvme_ns_id_attr_group);
+- del_gendisk(head->disk);
++ if (head->disk->flags & GENHD_FL_UP) {
++ sysfs_remove_group(&disk_to_dev(head->disk)->kobj,
++ &nvme_ns_id_attr_group);
++ del_gendisk(head->disk);
++ }
+ blk_set_queue_dying(head->disk->queue);
+ /* make sure all pending bios are cleaned up */
+ kblockd_schedule_work(&head->requeue_work);
+@@ -243,3 +508,53 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
+ blk_cleanup_queue(head->disk->queue);
+ put_disk(head->disk);
+ }
++
++int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
++{
++ int error;
++
++ if (!nvme_ctrl_use_ana(ctrl))
++ return 0;
++
++ ctrl->anacap = id->anacap;
++ ctrl->anatt = id->anatt;
++ ctrl->nanagrpid = le32_to_cpu(id->nanagrpid);
++ ctrl->anagrpmax = le32_to_cpu(id->anagrpmax);
++
++ mutex_init(&ctrl->ana_lock);
++ setup_timer(&ctrl->anatt_timer, nvme_anatt_timeout,
++ (unsigned long)ctrl);
++ ctrl->ana_log_size = sizeof(struct nvme_ana_rsp_hdr) +
++ ctrl->nanagrpid * sizeof(struct nvme_ana_group_desc);
++ if (!(ctrl->anacap & (1 << 6)))
++ ctrl->ana_log_size += ctrl->max_namespaces * sizeof(__le32);
++
++ if (ctrl->ana_log_size > ctrl->max_hw_sectors << SECTOR_SHIFT) {
++ dev_err(ctrl->device,
++ "ANA log page size (%zd) larger than MDTS (%d).\n",
++ ctrl->ana_log_size,
++ ctrl->max_hw_sectors << SECTOR_SHIFT);
++ dev_err(ctrl->device, "disabling ANA support.\n");
++ return 0;
++ }
++
++ INIT_WORK(&ctrl->ana_work, nvme_ana_work);
++ ctrl->ana_log_buf = kmalloc(ctrl->ana_log_size, GFP_KERNEL);
++ if (!ctrl->ana_log_buf)
++ goto out;
++
++ error = nvme_read_ana_log(ctrl, true);
++ if (error)
++ goto out_free_ana_log_buf;
++ return 0;
++out_free_ana_log_buf:
++ kfree(ctrl->ana_log_buf);
++out:
++ return -ENOMEM;
++}
++
++void nvme_mpath_uninit(struct nvme_ctrl *ctrl)
++{
++ kfree(ctrl->ana_log_buf);
++}
++
+diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
+index f4df6012d503..a2a16abed2bb 100644
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -173,6 +173,7 @@ struct nvme_ctrl {
+ u16 oacs;
+ u16 nssa;
+ u16 nr_streams;
++ u32 max_namespaces;
+ atomic_t abort_limit;
+ u8 vwc;
+ u32 vs;
+@@ -193,6 +194,19 @@ struct nvme_ctrl {
+ struct work_struct fw_act_work;
+ unsigned long events;
+
++#ifdef CONFIG_NVME_MULTIPATH
++ /* asymmetric namespace access: */
++ u8 anacap;
++ u8 anatt;
++ u32 anagrpmax;
++ u32 nanagrpid;
++ struct mutex ana_lock;
++ struct nvme_ana_rsp_hdr *ana_log_buf;
++ size_t ana_log_size;
++ struct timer_list anatt_timer;
++ struct work_struct ana_work;
++#endif
++
+ /* Power saving configuration */
+ u64 ps_max_latency_us;
+ bool apst_enabled;
+@@ -261,6 +275,7 @@ struct nvme_ns_head {
+ struct bio_list requeue_list;
+ spinlock_t requeue_lock;
+ struct work_struct requeue_work;
++ struct mutex lock;
+ #endif
+ struct list_head list;
+ struct srcu_struct srcu;
+@@ -278,6 +293,10 @@ struct nvme_ns {
+ struct nvme_ctrl *ctrl;
+ struct request_queue *queue;
+ struct gendisk *disk;
++#ifdef CONFIG_NVME_MULTIPATH
++ enum nvme_ana_state ana_state;
++ u32 ana_grpid;
++#endif
+ struct list_head siblings;
+ struct nvm_dev *ndev;
+ struct kref kref;
+@@ -290,8 +309,9 @@ struct nvme_ns {
+ bool ext;
+ u8 pi_type;
+ unsigned long flags;
+-#define NVME_NS_REMOVING 0
+-#define NVME_NS_DEAD 1
++#define NVME_NS_REMOVING 0
++#define NVME_NS_DEAD 1
++#define NVME_NS_ANA_PENDING 2
+ u16 noiob;
+ };
+
+@@ -418,13 +438,17 @@ extern const struct attribute_group nvme_ns_id_attr_group;
+ extern const struct block_device_operations nvme_ns_head_ops;
+
+ #ifdef CONFIG_NVME_MULTIPATH
++bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl);
+ void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
+ struct nvme_ctrl *ctrl, int *flags);
+ void nvme_failover_req(struct request *req);
+ void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl);
+ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head);
+-void nvme_mpath_add_disk(struct nvme_ns_head *head);
++void nvme_mpath_add_disk(struct nvme_ns *ns, struct nvme_id_ns *id);
+ void nvme_mpath_remove_disk(struct nvme_ns_head *head);
++int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id);
++void nvme_mpath_uninit(struct nvme_ctrl *ctrl);
++void nvme_mpath_stop(struct nvme_ctrl *ctrl);
+
+ static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns)
+ {
+@@ -443,7 +467,14 @@ static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
+ kblockd_schedule_work(&head->requeue_work);
+ }
+
++extern struct device_attribute dev_attr_ana_grpid;
++extern struct device_attribute dev_attr_ana_state;
++
+ #else
++static inline bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl)
++{
++ return false;
++}
+ /*
+ * Without the multipath code enabled, multiple controller per subsystems are
+ * visible as devices and thus we cannot use the subsystem instance.
+@@ -465,7 +496,8 @@ static inline int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,
+ {
+ return 0;
+ }
+-static inline void nvme_mpath_add_disk(struct nvme_ns_head *head)
++static inline void nvme_mpath_add_disk(struct nvme_ns *ns,
++ struct nvme_id_ns *id)
+ {
+ }
+ static inline void nvme_mpath_remove_disk(struct nvme_ns_head *head)
+@@ -477,6 +509,17 @@ static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns)
+ static inline void nvme_mpath_check_last_path(struct nvme_ns *ns)
+ {
+ }
++static inline int nvme_mpath_init(struct nvme_ctrl *ctrl,
++ struct nvme_id_ctrl *id)
++{
++ return 0;
++}
++static inline void nvme_mpath_uninit(struct nvme_ctrl *ctrl)
++{
++}
++static inline void nvme_mpath_stop(struct nvme_ctrl *ctrl)
++{
++}
+ #endif /* CONFIG_NVME_MULTIPATH */
+
+ #ifdef CONFIG_NVM
+--
+2.12.3
+
diff --git a/patches.drivers/nvme-remove-nvme_req_needs_failover.patch b/patches.drivers/nvme-remove-nvme_req_needs_failover.patch
new file mode 100644
index 0000000000..e5aa51d8c3
--- /dev/null
+++ b/patches.drivers/nvme-remove-nvme_req_needs_failover.patch
@@ -0,0 +1,82 @@
+From: Christoph Hellwig <hch@lst.de>
+Date: Mon, 4 Jun 2018 08:43:00 +0200
+Subject: [PATCH] nvme: remove nvme_req_needs_failover
+Git-commit: 8decf5d5b9f3f72b802a017b0b035f7db0592acf
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: bsc#1054245
+
+Now that we just call out to blk_path_error there isn't really any good
+reason to not merge it into the only caller.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Keith Busch <keith.busch@intel.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/nvme/host/core.c | 3 ++-
+ drivers/nvme/host/multipath.c | 7 -------
+ drivers/nvme/host/nvme.h | 6 ------
+ 3 files changed, 2 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
+index 001a9ba1aa97..40ca63930261 100644
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -237,7 +237,8 @@ void nvme_complete_rq(struct request *req)
+ trace_nvme_complete_rq(req);
+
+ if (unlikely(status != BLK_STS_OK && nvme_req_needs_retry(req))) {
+- if (nvme_req_needs_failover(req, status)) {
++ if ((req->cmd_flags & REQ_NVME_MPATH) &&
++ blk_path_error(status)) {
+ nvme_failover_req(req);
+ return;
+ }
+diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
+index 4e3490ddf0ee..16996dea5900 100644
+--- a/drivers/nvme/host/multipath.c
++++ b/drivers/nvme/host/multipath.c
+@@ -56,13 +56,6 @@ void nvme_failover_req(struct request *req)
+ kblockd_schedule_work(&ns->head->requeue_work);
+ }
+
+-bool nvme_req_needs_failover(struct request *req, blk_status_t error)
+-{
+- if (!(req->cmd_flags & REQ_NVME_MPATH))
+- return false;
+- return blk_path_error(error);
+-}
+-
+ void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
+ {
+ struct nvme_ns *ns;
+diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
+index 9eaa35dacd61..f4df6012d503 100644
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -421,7 +421,6 @@ extern const struct block_device_operations nvme_ns_head_ops;
+ void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
+ struct nvme_ctrl *ctrl, int *flags);
+ void nvme_failover_req(struct request *req);
+-bool nvme_req_needs_failover(struct request *req, blk_status_t error);
+ void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl);
+ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head);
+ void nvme_mpath_add_disk(struct nvme_ns_head *head);
+@@ -458,11 +457,6 @@ static inline void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
+ static inline void nvme_failover_req(struct request *req)
+ {
+ }
+-static inline bool nvme_req_needs_failover(struct request *req,
+- blk_status_t error)
+-{
+- return false;
+-}
+ static inline void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
+ {
+ }
+--
+2.12.3
+
diff --git a/patches.drivers/nvme-simplify-the-API-for-getting-log-pages.patch b/patches.drivers/nvme-simplify-the-API-for-getting-log-pages.patch
new file mode 100644
index 0000000000..74710ddd74
--- /dev/null
+++ b/patches.drivers/nvme-simplify-the-API-for-getting-log-pages.patch
@@ -0,0 +1,118 @@
+From: Christoph Hellwig <hch@lst.de>
+Date: Wed, 6 Jun 2018 14:39:00 +0200
+Subject: [PATCH] nvme: simplify the API for getting log pages
+Git-commit: 0e98719b0e4b48b61965e1d1cba037c2005d01d7
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: bsc#1054245
+
+Merge nvme_get_log and nvme_get_log_ext into a single helper, which takes
+a plain nsid instead of the nvme_ns pointer. Also add support for the
+log specific field while we're at it.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Keith Busch <keith.busch@intel.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/nvme/host/core.c | 32 +++++++++++---------------------
+ drivers/nvme/host/nvme.h | 4 ++--
+ 2 files changed, 13 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
+index 4c0d51ef27b5..001a9ba1aa97 100644
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -2252,21 +2252,16 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
+ return ret;
+ }
+
+-int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
+- u8 log_page, void *log,
+- size_t size, u64 offset)
++int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp,
++ void *log, size_t size, u64 offset)
+ {
+ struct nvme_command c = { };
+ unsigned long dwlen = size / 4 - 1;
+
+ c.get_log_page.opcode = nvme_admin_get_log_page;
+-
+- if (ns)
+- c.get_log_page.nsid = cpu_to_le32(ns->head->ns_id);
+- else
+- c.get_log_page.nsid = cpu_to_le32(NVME_NSID_ALL);
+-
++ c.get_log_page.nsid = cpu_to_le32(nsid);
+ c.get_log_page.lid = log_page;
++ c.get_log_page.lsp = lsp;
+ c.get_log_page.numdl = cpu_to_le16(dwlen & ((1 << 16) - 1));
+ c.get_log_page.numdu = cpu_to_le16(dwlen >> 16);
+ c.get_log_page.lpol = cpu_to_le32(lower_32_bits(offset));
+@@ -2275,12 +2270,6 @@ int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
+ return nvme_submit_sync_cmd(ctrl->admin_q, &c, log, size);
+ }
+
+-static int nvme_get_log(struct nvme_ctrl *ctrl, u8 log_page, void *log,
+- size_t size)
+-{
+- return nvme_get_log_ext(ctrl, NULL, log_page, log, size, 0);
+-}
+-
+ static int nvme_get_effects_log(struct nvme_ctrl *ctrl)
+ {
+ int ret;
+@@ -2291,8 +2280,8 @@ static int nvme_get_effects_log(struct nvme_ctrl *ctrl)
+ if (!ctrl->effects)
+ return 0;
+
+- ret = nvme_get_log(ctrl, NVME_LOG_CMD_EFFECTS, ctrl->effects,
+- sizeof(*ctrl->effects));
++ ret = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_CMD_EFFECTS, 0,
++ ctrl->effects, sizeof(*ctrl->effects), 0);
+ if (ret) {
+ kfree(ctrl->effects);
+ ctrl->effects = NULL;
+@@ -3202,7 +3191,8 @@ static void nvme_clear_changed_ns_log(struct nvme_ctrl *ctrl)
+ * raced with us in reading the log page, which could cause us to miss
+ * updates.
+ */
+- error = nvme_get_log(ctrl, NVME_LOG_CHANGED_NS, log, log_size);
++ error = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_CHANGED_NS, 0, log,
++ log_size, 0);
+ if (error)
+ dev_warn(ctrl->device,
+ "reading changed ns log failed: %d\n", error);
+@@ -3314,9 +3304,9 @@ static void nvme_get_fw_slot_info(struct nvme_ctrl *ctrl)
+ if (!log)
+ return;
+
+- if (nvme_get_log(ctrl, NVME_LOG_FW_SLOT, log, sizeof(*log)))
+- dev_warn(ctrl->device,
+- "Get FW SLOT INFO log error\n");
++ if (nvme_get_log(ctrl, NVME_NSID_ALL, 0, NVME_LOG_FW_SLOT, log,
++ sizeof(*log), 0))
++ dev_warn(ctrl->device, "Get FW SLOT INFO log error\n");
+ kfree(log);
+ }
+
+diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
+index d6f84501b676..9eaa35dacd61 100644
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -411,8 +411,8 @@ int nvme_reset_ctrl_sync(struct nvme_ctrl *ctrl);
+ int nvme_delete_ctrl(struct nvme_ctrl *ctrl);
+ int nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl);
+
+-int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
+- u8 log_page, void *log, size_t size, u64 offset);
++int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp,
++ void *log, size_t size, u64 offset);
+
+ extern const struct attribute_group nvme_ns_id_attr_group;
+ extern const struct block_device_operations nvme_ns_head_ops;
+--
+2.12.3
+
diff --git a/patches.drivers/nvme.h-add-ANA-definitions.patch b/patches.drivers/nvme.h-add-ANA-definitions.patch
new file mode 100644
index 0000000000..08c778aa30
--- /dev/null
+++ b/patches.drivers/nvme.h-add-ANA-definitions.patch
@@ -0,0 +1,131 @@
+From: Christoph Hellwig <hch@lst.de>
+Date: Sun, 13 May 2018 18:53:57 +0200
+Subject: [PATCH] nvme.h: add ANA definitions
+Git-commit: 1a37621658fe06b10cf8bac02c32304d2a1c888c
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: bsc#1054245
+
+Add various defintions from NVMe 1.3 TP 4004.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Keith Busch <keith.busch@intel.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ include/linux/nvme.h | 50 +++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 47 insertions(+), 3 deletions(-)
+
+diff --git a/include/linux/nvme.h b/include/linux/nvme.h
+index 32f24f4ca763..fdff3c37bdd9 100644
+--- a/include/linux/nvme.h
++++ b/include/linux/nvme.h
+@@ -242,7 +242,12 @@ struct nvme_id_ctrl {
+ __le32 sanicap;
+ __le32 hmminds;
+ __le16 hmmaxd;
+- __u8 rsvd338[174];
++ __u8 rsvd338[4];
++ __u8 anatt;
++ __u8 anacap;
++ __le32 anagrpmax;
++ __le32 nanagrpid;
++ __u8 rsvd352[160];
+ __u8 sqes;
+ __u8 cqes;
+ __le16 maxcmd;
+@@ -258,7 +263,8 @@ struct nvme_id_ctrl {
+ __le16 acwu;
+ __u8 rsvd534[2];
+ __le32 sgls;
+- __u8 rsvd540[228];
++ __le32 mnan;
++ __u8 rsvd544[224];
+ char subnqn[256];
+ __u8 rsvd1024[768];
+ __le32 ioccsz;
+@@ -312,7 +318,9 @@ struct nvme_id_ns {
+ __le16 nabspf;
+ __le16 noiob;
+ __u8 nvmcap[16];
+- __u8 rsvd64[40];
++ __u8 rsvd64[28];
++ __le32 anagrpid;
++ __u8 rsvd96[8];
+ __u8 nguid[16];
+ __u8 eui64[8];
+ struct nvme_lbaf lbaf[16];
+@@ -425,6 +433,32 @@ struct nvme_effects_log {
+ __u8 resv[2048];
+ };
+
++enum nvme_ana_state {
++ NVME_ANA_OPTIMIZED = 0x01,
++ NVME_ANA_NONOPTIMIZED = 0x02,
++ NVME_ANA_INACCESSIBLE = 0x03,
++ NVME_ANA_PERSISTENT_LOSS = 0x04,
++ NVME_ANA_CHANGE = 0x0f,
++};
++
++struct nvme_ana_group_desc {
++ __le32 grpid;
++ __le32 nnsids;
++ __le64 chgcnt;
++ __u8 state;
++ __u8 rsvd17[7];
++ __le32 nsids[];
++};
++
++/* flag for the log specific field of the ANA log */
++#define NVME_ANA_LOG_RGO (1 << 0)
++
++struct nvme_ana_rsp_hdr {
++ __le64 chgcnt;
++ __le16 ngrps;
++ __le16 rsvd10[3];
++};
++
+ enum {
+ NVME_SMART_CRIT_SPARE = 1 << 0,
+ NVME_SMART_CRIT_TEMPERATURE = 1 << 1,
+@@ -444,11 +478,13 @@ enum {
+ enum {
+ NVME_AER_NOTICE_NS_CHANGED = 0x00,
+ NVME_AER_NOTICE_FW_ACT_STARTING = 0x01,
++ NVME_AER_NOTICE_ANA = 0x03,
+ };
+
+ enum {
+ NVME_AEN_CFG_NS_ATTR = 1 << 8,
+ NVME_AEN_CFG_FW_ACT = 1 << 9,
++ NVME_AEN_CFG_ANA_CHANGE = 1 << 11,
+ };
+
+ struct nvme_lba_range_type {
+@@ -758,6 +794,7 @@ enum {
+ NVME_LOG_FW_SLOT = 0x03,
+ NVME_LOG_CHANGED_NS = 0x04,
+ NVME_LOG_CMD_EFFECTS = 0x05,
++ NVME_LOG_ANA = 0x0c,
+ NVME_LOG_DISC = 0x70,
+ NVME_LOG_RESERVATION = 0x80,
+ NVME_FWACT_REPL = (0 << 3),
+@@ -1180,6 +1217,13 @@ enum {
+ NVME_SC_ACCESS_DENIED = 0x286,
+ NVME_SC_UNWRITTEN_BLOCK = 0x287,
+
++ /*
++ * Path-related Errors:
++ */
++ NVME_SC_ANA_PERSISTENT_LOSS = 0x301,
++ NVME_SC_ANA_INACCESSIBLE = 0x302,
++ NVME_SC_ANA_TRANSITION = 0x303,
++
+ NVME_SC_DNR = 0x4000,
+ };
+
+--
+2.12.3
+
diff --git a/patches.drivers/nvme.h-add-support-for-the-log-specific-field.patch b/patches.drivers/nvme.h-add-support-for-the-log-specific-field.patch
new file mode 100644
index 0000000000..bb26d202c6
--- /dev/null
+++ b/patches.drivers/nvme.h-add-support-for-the-log-specific-field.patch
@@ -0,0 +1,37 @@
+From: Christoph Hellwig <hch@lst.de>
+Date: Sat, 12 May 2018 18:18:12 +0200
+Subject: [PATCH] nvme.h: add support for the log specific field
+Git-commit: 9b89bc3857a6c0dfda18ddae2a42c114ecc32753
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: bsc#1054245
+
+NVMe 1.3 added a new log specific field to the get log page CQ
+defintion, add it to our get_log_page SQ structure.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Keith Busch <keith.busch@intel.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ include/linux/nvme.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/linux/nvme.h b/include/linux/nvme.h
+index 2950ce957656..32f24f4ca763 100644
+--- a/include/linux/nvme.h
++++ b/include/linux/nvme.h
+@@ -880,7 +880,7 @@ struct nvme_get_log_page_command {
+ __u64 rsvd2[2];
+ union nvme_data_ptr dptr;
+ __u8 lid;
+- __u8 rsvd10;
++ __u8 lsp; /* upper 4 bits reserved */
+ __le16 numdl;
+ __le16 numdu;
+ __u16 rsvd11;
+--
+2.12.3
+
diff --git a/patches.drivers/nvmet-add-minimal-ANA-support.patch b/patches.drivers/nvmet-add-minimal-ANA-support.patch
new file mode 100644
index 0000000000..451d952e3c
--- /dev/null
+++ b/patches.drivers/nvmet-add-minimal-ANA-support.patch
@@ -0,0 +1,327 @@
+From: Christoph Hellwig <hch@lst.de>
+Date: Thu, 19 Jul 2018 07:35:20 -0700
+Subject: [PATCH] nvmet: add minimal ANA support
+Git-commit: 72efd25dcf4f6310e9e6fa85620aa443b27c23fe
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: bsc#1054245
+
+Add support for Asynchronous Namespace Access as specified in NVMe 1.3
+TP 4004.
+
+Just add a default ANA group 1 that is optimized on all ports. This is
+(and will remain) the default assignment for any namespace not epxlicitly
+assigned to another ANA group. The ANA state can be manually changed
+through the configfs interface, including the change state.
+
+Includes fixes and improvements from Hannes Reinecke.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Keith Busch <keith.busch@intel.com>
+Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/nvme/target/admin-cmd.c | 87 +++++++++++++++++++++++++++++++++++++++--
+ drivers/nvme/target/configfs.c | 10 +++++
+ drivers/nvme/target/core.c | 16 ++++++++
+ drivers/nvme/target/io-cmd.c | 18 +++++++++
+ drivers/nvme/target/nvmet.h | 15 +++++++
+ 5 files changed, 142 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
+index bf4d6002b3b4..a02cd29bba5c 100644
+--- a/drivers/nvme/target/admin-cmd.c
++++ b/drivers/nvme/target/admin-cmd.c
+@@ -151,6 +151,69 @@ static void copy_and_pad(char *dst, int dst_len, const char *src, int src_len)
+ memset(dst + len, ' ', dst_len - len);
+ }
+
++static u32 nvmet_format_ana_group(struct nvmet_req *req, u32 grpid,
++ struct nvme_ana_group_desc *desc)
++{
++ struct nvmet_ctrl *ctrl = req->sq->ctrl;
++ struct nvmet_ns *ns;
++ u32 count = 0;
++
++ if (!(req->cmd->get_log_page.lsp & NVME_ANA_LOG_RGO)) {
++ rcu_read_lock();
++ list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link)
++ if (ns->anagrpid == grpid)
++ desc->nsids[count++] = cpu_to_le32(ns->nsid);
++ rcu_read_unlock();
++ }
++
++ desc->grpid = cpu_to_le32(grpid);
++ desc->nnsids = cpu_to_le32(count);
++ desc->chgcnt = cpu_to_le64(nvmet_ana_chgcnt);
++ desc->state = req->port->ana_state[grpid];
++ memset(desc->rsvd17, 0, sizeof(desc->rsvd17));
++ return sizeof(struct nvme_ana_group_desc) + count * sizeof(__le32);
++}
++
++static void nvmet_execute_get_log_page_ana(struct nvmet_req *req)
++{
++ struct nvme_ana_rsp_hdr hdr = { 0, };
++ struct nvme_ana_group_desc *desc;
++ size_t offset = sizeof(struct nvme_ana_rsp_hdr); /* start beyond hdr */
++ size_t len;
++ u32 grpid;
++ u16 ngrps = 0;
++ u16 status;
++
++ status = NVME_SC_INTERNAL;
++ desc = kmalloc(sizeof(struct nvme_ana_group_desc) +
++ NVMET_MAX_NAMESPACES * sizeof(__le32), GFP_KERNEL);
++ if (!desc)
++ goto out;
++
++ down_read(&nvmet_ana_sem);
++ for (grpid = 1; grpid <= NVMET_MAX_ANAGRPS; grpid++) {
++ if (!nvmet_ana_group_enabled[grpid])
++ continue;
++ len = nvmet_format_ana_group(req, grpid, desc);
++ status = nvmet_copy_to_sgl(req, offset, desc, len);
++ if (status)
++ break;
++ offset += len;
++ ngrps++;
++ }
++
++ hdr.chgcnt = cpu_to_le64(nvmet_ana_chgcnt);
++ hdr.ngrps = cpu_to_le16(ngrps);
++ up_read(&nvmet_ana_sem);
++
++ kfree(desc);
++
++ /* copy the header last once we know the number of groups */
++ status = nvmet_copy_to_sgl(req, 0, &hdr, sizeof(hdr));
++out:
++ nvmet_req_complete(req, status);
++}
++
+ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
+ {
+ struct nvmet_ctrl *ctrl = req->sq->ctrl;
+@@ -181,8 +244,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
+ * the safest is to leave it as zeroes.
+ */
+
+- /* we support multiple ports and multiples hosts: */
+- id->cmic = (1 << 0) | (1 << 1);
++ /* we support multiple ports, multiples hosts and ANA: */
++ id->cmic = (1 << 0) | (1 << 1) | (1 << 3);
+
+ /* no limit on data transfer sizes for now */
+ id->mdts = 0;
+@@ -250,6 +313,11 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
+
+ id->msdbd = ctrl->ops->msdbd;
+
++ id->anacap = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
++ id->anatt = 10; /* random value */
++ id->anagrpmax = cpu_to_le32(NVMET_MAX_ANAGRPS);
++ id->nanagrpid = cpu_to_le32(NVMET_MAX_ANAGRPS);
++
+ /*
+ * Meh, we don't really support any power state. Fake up the same
+ * values that qemu does.
+@@ -291,8 +359,15 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
+ * nuse = ncap = nsze isn't always true, but we have no way to find
+ * that out from the underlying device.
+ */
+- id->ncap = id->nuse = id->nsze =
+- cpu_to_le64(ns->size >> ns->blksize_shift);
++ id->ncap = id->nsze = cpu_to_le64(ns->size >> ns->blksize_shift);
++ switch (req->port->ana_state[ns->anagrpid]) {
++ case NVME_ANA_INACCESSIBLE:
++ case NVME_ANA_PERSISTENT_LOSS:
++ break;
++ default:
++ id->nuse = id->nsze;
++ break;
++ }
+
+ /*
+ * We just provide a single LBA format that matches what the
+@@ -306,6 +381,7 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
+ * controllers, but also with any other user of the block device.
+ */
+ id->nmic = (1 << 0);
++ id->anagrpid = cpu_to_le32(ns->anagrpid);
+
+ memcpy(&id->nguid, &ns->nguid, sizeof(uuid_le));
+
+@@ -587,6 +663,9 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
+ case NVME_LOG_CHANGED_NS:
+ req->execute = nvmet_execute_get_log_changed_ns;
+ return 0;
++ case NVME_LOG_ANA:
++ req->execute = nvmet_execute_get_log_page_ana;
++ return 0;
+ }
+ break;
+ case nvme_admin_identify:
+diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
+index fce77db0d2f7..8700085af0e1 100644
+--- a/drivers/nvme/target/configfs.c
++++ b/drivers/nvme/target/configfs.c
+@@ -873,6 +873,7 @@ static void nvmet_port_release(struct config_item *item)
+ {
+ struct nvmet_port *port = to_nvmet_port(item);
+
++ kfree(port->ana_state);
+ kfree(port);
+ }
+
+@@ -908,6 +909,15 @@ static struct config_group *nvmet_ports_make(struct config_group *group,
+ if (!port)
+ return ERR_PTR(-ENOMEM);
+
++ port->ana_state = kcalloc(NVMET_MAX_ANAGRPS + 1,
++ sizeof(*port->ana_state), GFP_KERNEL);
++ if (!port->ana_state) {
++ kfree(port);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ port->ana_state[NVMET_DEFAULT_ANA_GRPID] = NVME_ANA_OPTIMIZED;
++
+ INIT_LIST_HEAD(&port->entry);
+ INIT_LIST_HEAD(&port->subsystems);
+ INIT_LIST_HEAD(&port->referrals);
+diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
+index 1203d1fface6..a848eb0182a9 100644
+--- a/drivers/nvme/target/core.c
++++ b/drivers/nvme/target/core.c
+@@ -39,6 +39,10 @@ static DEFINE_IDA(cntlid_ida);
+ */
+ DECLARE_RWSEM(nvmet_config_sem);
+
++u32 nvmet_ana_group_enabled[NVMET_MAX_ANAGRPS + 1];
++u64 nvmet_ana_chgcnt;
++DECLARE_RWSEM(nvmet_ana_sem);
++
+ static struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port,
+ const char *subsysnqn);
+
+@@ -429,6 +433,10 @@ void nvmet_ns_free(struct nvmet_ns *ns)
+ {
+ nvmet_ns_disable(ns);
+
++ down_write(&nvmet_ana_sem);
++ nvmet_ana_group_enabled[ns->anagrpid]--;
++ up_write(&nvmet_ana_sem);
++
+ kfree(ns->device_path);
+ kfree(ns);
+ }
+@@ -446,6 +454,12 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
+
+ ns->nsid = nsid;
+ ns->subsys = subsys;
++
++ down_write(&nvmet_ana_sem);
++ ns->anagrpid = NVMET_DEFAULT_ANA_GRPID;
++ nvmet_ana_group_enabled[ns->anagrpid]++;
++ up_write(&nvmet_ana_sem);
++
+ uuid_gen(&ns->uuid);
+
+ return ns;
+@@ -1103,6 +1117,8 @@ static int __init nvmet_init(void)
+ {
+ int error;
+
++ nvmet_ana_group_enabled[NVMET_DEFAULT_ANA_GRPID] = 1;
++
+ error = nvmet_init_discovery();
+ if (error)
+ goto out;
+diff --git a/drivers/nvme/target/io-cmd.c b/drivers/nvme/target/io-cmd.c
+index 28bbdff4a88b..b148ad770451 100644
+--- a/drivers/nvme/target/io-cmd.c
++++ b/drivers/nvme/target/io-cmd.c
+@@ -189,6 +189,20 @@ static void nvmet_execute_write_zeroes(struct nvmet_req *req)
+ }
+ }
+
++static inline u16 nvmet_check_ana_state(struct nvmet_port *port,
++ struct nvmet_ns *ns)
++{
++ enum nvme_ana_state state = port->ana_state[ns->anagrpid];
++
++ if (unlikely(state == NVME_ANA_INACCESSIBLE))
++ return NVME_SC_ANA_INACCESSIBLE;
++ if (unlikely(state == NVME_ANA_PERSISTENT_LOSS))
++ return NVME_SC_ANA_PERSISTENT_LOSS;
++ if (unlikely(state == NVME_ANA_CHANGE))
++ return NVME_SC_ANA_TRANSITION;
++ return 0;
++}
++
+ u16 nvmet_parse_io_cmd(struct nvmet_req *req)
+ {
+ struct nvme_command *cmd = req->cmd;
+@@ -204,6 +218,10 @@ u16 nvmet_parse_io_cmd(struct nvmet_req *req)
+ if (unlikely(!req->ns))
+ return NVME_SC_INVALID_NS | NVME_SC_DNR;
+
++ ret = nvmet_check_ana_state(req->port, req->ns);
++ if (unlikely(ret))
++ return ret;
++
+ switch (cmd->common.opcode) {
+ case nvme_cmd_read:
+ case nvme_cmd_write:
+diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
+index eec4725ea5b3..9b7cbf163f37 100644
+--- a/drivers/nvme/target/nvmet.h
++++ b/drivers/nvme/target/nvmet.h
+@@ -63,6 +63,7 @@ struct nvmet_ns {
+ loff_t size;
+ u8 nguid[16];
+ uuid_t uuid;
++ u32 anagrpid;
+
+ bool enabled;
+ struct nvmet_subsys *subsys;
+@@ -111,6 +112,7 @@ struct nvmet_port {
+ struct list_head subsystems;
+ struct config_group referrals_group;
+ struct list_head referrals;
++ enum nvme_ana_state *ana_state;
+ void *priv;
+ bool enabled;
+ };
+@@ -351,6 +353,15 @@ u32 nvmet_get_log_page_len(struct nvme_command *cmd);
+ */
+ #define NVMET_MAX_NAMESPACES 1024
+
++/*
++ * 0 is not a valid ANA group ID, so we start numbering at 1.
++ *
++ * ANA Group 1 exists without manual intervention, has namespaces assigned to it
++ * by default, and is available in an optimized state through all ports.
++ */
++#define NVMET_MAX_ANAGRPS 1
++#define NVMET_DEFAULT_ANA_GRPID 1
++
+ #define NVMET_KAS 10
+ #define NVMET_DISC_KATO 120
+
+@@ -364,6 +375,10 @@ extern struct nvmet_subsys *nvmet_disc_subsys;
+ extern u64 nvmet_genctr;
+ extern struct rw_semaphore nvmet_config_sem;
+
++extern u32 nvmet_ana_group_enabled[NVMET_MAX_ANAGRPS + 1];
++extern u64 nvmet_ana_chgcnt;
++extern struct rw_semaphore nvmet_ana_sem;
++
+ bool nvmet_host_allowed(struct nvmet_req *req, struct nvmet_subsys *subsys,
+ const char *hostnqn);
+
+--
+2.12.3
+
diff --git a/patches.drivers/nvmet-keep-a-port-pointer-in-nvmet_ctrl.patch b/patches.drivers/nvmet-keep-a-port-pointer-in-nvmet_ctrl.patch
new file mode 100644
index 0000000000..0a48673317
--- /dev/null
+++ b/patches.drivers/nvmet-keep-a-port-pointer-in-nvmet_ctrl.patch
@@ -0,0 +1,49 @@
+From: Christoph Hellwig <hch@lst.de>
+Date: Thu, 7 Jun 2018 15:09:50 +0200
+Subject: [PATCH] nvmet: keep a port pointer in nvmet_ctrl
+Git-commit: 4ee43280488b0f6cbd74702725a32f47d03d690b
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: bsc#1054245
+
+This will be needed for the ANA AEN code.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Keith Busch <keith.busch@intel.com>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/nvme/target/core.c | 2 ++
+ drivers/nvme/target/nvmet.h | 2 ++
+ 2 files changed, 4 insertions(+)
+
+diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
+index e4f3ce81fc3f..edd51b8fcd04 100644
+--- a/drivers/nvme/target/core.c
++++ b/drivers/nvme/target/core.c
+@@ -856,6 +856,8 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
+
+ nvmet_init_cap(ctrl);
+
++ ctrl->port = req->port;
++
+ INIT_WORK(&ctrl->async_event_work, nvmet_async_event_work);
+ INIT_LIST_HEAD(&ctrl->async_events);
+
+diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
+index 5d56aa61fcdb..4af3f537dcd2 100644
+--- a/drivers/nvme/target/nvmet.h
++++ b/drivers/nvme/target/nvmet.h
+@@ -135,6 +135,8 @@ struct nvmet_ctrl {
+ u16 cntlid;
+ u32 kato;
+
++ struct nvmet_port *port;
++
+ u32 aen_enabled;
+ unsigned long aen_masked;
+ struct nvmet_req *async_event_cmds[NVMET_ASYNC_EVENTS];
+--
+2.12.3
+
diff --git a/patches.drivers/nvmet-support-configuring-ANA-groups.patch b/patches.drivers/nvmet-support-configuring-ANA-groups.patch
new file mode 100644
index 0000000000..848dc3d6f1
--- /dev/null
+++ b/patches.drivers/nvmet-support-configuring-ANA-groups.patch
@@ -0,0 +1,396 @@
+From: Christoph Hellwig <hch@lst.de>
+Date: Fri, 1 Jun 2018 08:59:25 +0200
+Subject: [PATCH] nvmet: support configuring ANA groups
+Git-commit: 62ac0d32f74ea511d5813be728dc589d03f866a3
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: bsc#1054245
+
+Allow creating non-default ANA groups (group ID > 1). Groups are created
+either by assigning the group ID to a namespace, or by creating a configfs
+group object under a specific port. All namespaces assigned to a group
+that doesn't have a configfs object for a given port are marked as
+inaccessible.
+
+Allow changing the ANA state on a per-port basis by creating an
+ana_groups directory under each port, and another directory with an
+ana_state file in it. The default ANA group 1 directory is created
+automatically for each port.
+
+For all changes in ANA configuration the ANA change AEN is sent. We only
+keep a global changecount instead of additional per-group changecounts to
+keep the implementation as simple as possible.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Keith Busch <keith.busch@intel.com>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/nvme/target/admin-cmd.c | 1 +
+ drivers/nvme/target/configfs.c | 182 +++++++++++++++++++++++++++++++++++++++-
+ drivers/nvme/target/core.c | 27 ++++++
+ drivers/nvme/target/nvmet.h | 30 ++++++-
+ 4 files changed, 236 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
+index a02cd29bba5c..628270a5bda9 100644
+--- a/drivers/nvme/target/admin-cmd.c
++++ b/drivers/nvme/target/admin-cmd.c
+@@ -204,6 +204,7 @@ static void nvmet_execute_get_log_page_ana(struct nvmet_req *req)
+
+ hdr.chgcnt = cpu_to_le64(nvmet_ana_chgcnt);
+ hdr.ngrps = cpu_to_le16(ngrps);
++ clear_bit(NVME_AEN_CFG_ANA_CHANGE, &req->sq->ctrl->aen_masked);
+ up_read(&nvmet_ana_sem);
+
+ kfree(desc);
+diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
+index 8700085af0e1..c36838536def 100644
+--- a/drivers/nvme/target/configfs.c
++++ b/drivers/nvme/target/configfs.c
+@@ -390,6 +390,39 @@ static ssize_t nvmet_ns_device_nguid_store(struct config_item *item,
+
+ CONFIGFS_ATTR(nvmet_ns_, device_nguid);
+
++static ssize_t nvmet_ns_ana_grpid_show(struct config_item *item, char *page)
++{
++ return sprintf(page, "%u\n", to_nvmet_ns(item)->anagrpid);
++}
++
++static ssize_t nvmet_ns_ana_grpid_store(struct config_item *item,
++ const char *page, size_t count)
++{
++ struct nvmet_ns *ns = to_nvmet_ns(item);
++ u32 oldgrpid, newgrpid;
++ int ret;
++
++ ret = kstrtou32(page, 0, &newgrpid);
++ if (ret)
++ return ret;
++
++ if (newgrpid < 1 || newgrpid > NVMET_MAX_ANAGRPS)
++ return -EINVAL;
++
++ down_write(&nvmet_ana_sem);
++ oldgrpid = ns->anagrpid;
++ nvmet_ana_group_enabled[newgrpid]++;
++ ns->anagrpid = newgrpid;
++ nvmet_ana_group_enabled[oldgrpid]--;
++ nvmet_ana_chgcnt++;
++ up_write(&nvmet_ana_sem);
++
++ nvmet_send_ana_event(ns->subsys, NULL);
++ return count;
++}
++
++CONFIGFS_ATTR(nvmet_ns_, ana_grpid);
++
+ static ssize_t nvmet_ns_enable_show(struct config_item *item, char *page)
+ {
+ return sprintf(page, "%d\n", to_nvmet_ns(item)->enabled);
+@@ -419,6 +452,7 @@ static struct configfs_attribute *nvmet_ns_attrs[] = {
+ &nvmet_ns_attr_device_path,
+ &nvmet_ns_attr_device_nguid,
+ &nvmet_ns_attr_device_uuid,
++ &nvmet_ns_attr_ana_grpid,
+ &nvmet_ns_attr_enable,
+ NULL,
+ };
+@@ -866,6 +900,134 @@ static struct config_item_type nvmet_referrals_type = {
+ .ct_group_ops = &nvmet_referral_group_ops,
+ };
+
++static struct {
++ enum nvme_ana_state state;
++ const char *name;
++} nvmet_ana_state_names[] = {
++ { NVME_ANA_OPTIMIZED, "optimized" },
++ { NVME_ANA_NONOPTIMIZED, "non-optimized" },
++ { NVME_ANA_INACCESSIBLE, "inaccessible" },
++ { NVME_ANA_PERSISTENT_LOSS, "persistent-loss" },
++ { NVME_ANA_CHANGE, "change" },
++};
++
++static ssize_t nvmet_ana_group_ana_state_show(struct config_item *item,
++ char *page)
++{
++ struct nvmet_ana_group *grp = to_ana_group(item);
++ enum nvme_ana_state state = grp->port->ana_state[grp->grpid];
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(nvmet_ana_state_names); i++) {
++ if (state != nvmet_ana_state_names[i].state)
++ continue;
++ return sprintf(page, "%s\n", nvmet_ana_state_names[i].name);
++ }
++
++ return sprintf(page, "\n");
++}
++
++static ssize_t nvmet_ana_group_ana_state_store(struct config_item *item,
++ const char *page, size_t count)
++{
++ struct nvmet_ana_group *grp = to_ana_group(item);
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(nvmet_ana_state_names); i++) {
++ if (sysfs_streq(page, nvmet_ana_state_names[i].name))
++ goto found;
++ }
++
++ pr_err("Invalid value '%s' for ana_state\n", page);
++ return -EINVAL;
++
++found:
++ down_write(&nvmet_ana_sem);
++ grp->port->ana_state[grp->grpid] = nvmet_ana_state_names[i].state;
++ nvmet_ana_chgcnt++;
++ up_write(&nvmet_ana_sem);
++
++ nvmet_port_send_ana_event(grp->port);
++ return count;
++}
++
++CONFIGFS_ATTR(nvmet_ana_group_, ana_state);
++
++static struct configfs_attribute *nvmet_ana_group_attrs[] = {
++ &nvmet_ana_group_attr_ana_state,
++ NULL,
++};
++
++static void nvmet_ana_group_release(struct config_item *item)
++{
++ struct nvmet_ana_group *grp = to_ana_group(item);
++
++ if (grp == &grp->port->ana_default_group)
++ return;
++
++ down_write(&nvmet_ana_sem);
++ grp->port->ana_state[grp->grpid] = NVME_ANA_INACCESSIBLE;
++ nvmet_ana_group_enabled[grp->grpid]--;
++ up_write(&nvmet_ana_sem);
++
++ nvmet_port_send_ana_event(grp->port);
++ kfree(grp);
++}
++
++static struct configfs_item_operations nvmet_ana_group_item_ops = {
++ .release = nvmet_ana_group_release,
++};
++
++static struct config_item_type nvmet_ana_group_type = {
++ .ct_item_ops = &nvmet_ana_group_item_ops,
++ .ct_attrs = nvmet_ana_group_attrs,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_group *nvmet_ana_groups_make_group(
++ struct config_group *group, const char *name)
++{
++ struct nvmet_port *port = ana_groups_to_port(&group->cg_item);
++ struct nvmet_ana_group *grp;
++ u32 grpid;
++ int ret;
++
++ ret = kstrtou32(name, 0, &grpid);
++ if (ret)
++ goto out;
++
++ ret = -EINVAL;
++ if (grpid <= 1 || grpid > NVMET_MAX_ANAGRPS)
++ goto out;
++
++ ret = -ENOMEM;
++ grp = kzalloc(sizeof(*grp), GFP_KERNEL);
++ if (!grp)
++ goto out;
++ grp->port = port;
++ grp->grpid = grpid;
++
++ down_write(&nvmet_ana_sem);
++ nvmet_ana_group_enabled[grpid]++;
++ up_write(&nvmet_ana_sem);
++
++ nvmet_port_send_ana_event(grp->port);
++
++ config_group_init_type_name(&grp->group, name, &nvmet_ana_group_type);
++ return &grp->group;
++out:
++ return ERR_PTR(ret);
++}
++
++static struct configfs_group_operations nvmet_ana_groups_group_ops = {
++ .make_group = nvmet_ana_groups_make_group,
++};
++
++static struct config_item_type nvmet_ana_groups_type = {
++ .ct_group_ops = &nvmet_ana_groups_group_ops,
++ .ct_owner = THIS_MODULE,
++};
++
+ /*
+ * Ports definitions.
+ */
+@@ -901,6 +1063,7 @@ static struct config_group *nvmet_ports_make(struct config_group *group,
+ {
+ struct nvmet_port *port;
+ u16 portid;
++ u32 i;
+
+ if (kstrtou16(name, 0, &portid))
+ return ERR_PTR(-EINVAL);
+@@ -916,7 +1079,12 @@ static struct config_group *nvmet_ports_make(struct config_group *group,
+ return ERR_PTR(-ENOMEM);
+ }
+
+- port->ana_state[NVMET_DEFAULT_ANA_GRPID] = NVME_ANA_OPTIMIZED;
++ for (i = 1; i <= NVMET_MAX_ANAGRPS; i++) {
++ if (i == NVMET_DEFAULT_ANA_GRPID)
++ port->ana_state[1] = NVME_ANA_OPTIMIZED;
++ else
++ port->ana_state[i] = NVME_ANA_INACCESSIBLE;
++ }
+
+ INIT_LIST_HEAD(&port->entry);
+ INIT_LIST_HEAD(&port->subsystems);
+@@ -933,6 +1101,18 @@ static struct config_group *nvmet_ports_make(struct config_group *group,
+ "referrals", &nvmet_referrals_type);
+ configfs_add_default_group(&port->referrals_group, &port->group);
+
++ config_group_init_type_name(&port->ana_groups_group,
++ "ana_groups", &nvmet_ana_groups_type);
++ configfs_add_default_group(&port->ana_groups_group, &port->group);
++
++ port->ana_default_group.port = port;
++ port->ana_default_group.grpid = NVMET_DEFAULT_ANA_GRPID;
++ config_group_init_type_name(&port->ana_default_group.group,
++ __stringify(NVMET_DEFAULT_ANA_GRPID),
++ &nvmet_ana_group_type);
++ configfs_add_default_group(&port->ana_default_group.group,
++ &port->ana_groups_group);
++
+ return &port->group;
+ }
+
+diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
+index 9f965a3a9079..dba863b8a9ae 100644
+--- a/drivers/nvme/target/core.c
++++ b/drivers/nvme/target/core.c
+@@ -193,6 +193,33 @@ static void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid)
+ }
+ }
+
++void nvmet_send_ana_event(struct nvmet_subsys *subsys,
++ struct nvmet_port *port)
++{
++ struct nvmet_ctrl *ctrl;
++
++ mutex_lock(&subsys->lock);
++ list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) {
++ if (port && ctrl->port != port)
++ continue;
++ if (nvmet_aen_disabled(ctrl, NVME_AEN_CFG_ANA_CHANGE))
++ continue;
++ nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE,
++ NVME_AER_NOTICE_ANA, NVME_LOG_ANA);
++ }
++ mutex_unlock(&subsys->lock);
++}
++
++void nvmet_port_send_ana_event(struct nvmet_port *port)
++{
++ struct nvmet_subsys_link *p;
++
++ down_read(&nvmet_config_sem);
++ list_for_each_entry(p, &port->subsystems, entry)
++ nvmet_send_ana_event(p->subsys, port);
++ up_read(&nvmet_config_sem);
++}
++
+ int nvmet_register_transport(const struct nvmet_fabrics_ops *ops)
+ {
+ int ret = 0;
+diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
+index 4d4b9ed4e4bb..260f96fc8848 100644
+--- a/drivers/nvme/target/nvmet.h
++++ b/drivers/nvme/target/nvmet.h
+@@ -30,12 +30,11 @@
+ #define NVMET_ASYNC_EVENTS 4
+ #define NVMET_ERROR_LOG_SLOTS 128
+
+-
+ /*
+ * Supported optional AENs:
+ */
+ #define NVMET_AEN_CFG_OPTIONAL \
+- NVME_AEN_CFG_NS_ATTR
++ (NVME_AEN_CFG_NS_ATTR | NVME_AEN_CFG_ANA_CHANGE)
+
+ /*
+ * Plus mandatory SMART AENs (we'll never send them, but allow enabling them):
+@@ -95,6 +94,18 @@ struct nvmet_sq {
+ struct completion confirm_done;
+ };
+
++struct nvmet_ana_group {
++ struct config_group group;
++ struct nvmet_port *port;
++ u32 grpid;
++};
++
++static inline struct nvmet_ana_group *to_ana_group(struct config_item *item)
++{
++ return container_of(to_config_group(item), struct nvmet_ana_group,
++ group);
++}
++
+ /**
+ * struct nvmet_port - Common structure to keep port
+ * information for the target.
+@@ -112,6 +123,8 @@ struct nvmet_port {
+ struct list_head subsystems;
+ struct config_group referrals_group;
+ struct list_head referrals;
++ struct config_group ana_groups_group;
++ struct nvmet_ana_group ana_default_group;
+ enum nvme_ana_state *ana_state;
+ void *priv;
+ bool enabled;
+@@ -123,6 +136,13 @@ static inline struct nvmet_port *to_nvmet_port(struct config_item *item)
+ group);
+ }
+
++static inline struct nvmet_port *ana_groups_to_port(
++ struct config_item *item)
++{
++ return container_of(to_config_group(item), struct nvmet_port,
++ ana_groups_group);
++}
++
+ struct nvmet_ctrl {
+ struct nvmet_subsys *subsys;
+ struct nvmet_cq **cqs;
+@@ -326,6 +346,10 @@ void nvmet_ns_disable(struct nvmet_ns *ns);
+ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid);
+ void nvmet_ns_free(struct nvmet_ns *ns);
+
++void nvmet_send_ana_event(struct nvmet_subsys *subsys,
++ struct nvmet_port *port);
++void nvmet_port_send_ana_event(struct nvmet_port *port);
++
+ int nvmet_register_transport(const struct nvmet_fabrics_ops *ops);
+ void nvmet_unregister_transport(const struct nvmet_fabrics_ops *ops);
+
+@@ -359,7 +383,7 @@ u32 nvmet_get_log_page_len(struct nvme_command *cmd);
+ * ANA Group 1 exists without manual intervention, has namespaces assigned to it
+ * by default, and is available in an optimized state through all ports.
+ */
+-#define NVMET_MAX_ANAGRPS 1
++#define NVMET_MAX_ANAGRPS 128
+ #define NVMET_DEFAULT_ANA_GRPID 1
+
+ #define NVMET_KAS 10
+--
+2.12.3
+
diff --git a/patches.drivers/nvmet-track-and-limit-the-number-of-namespaces-per-s.patch b/patches.drivers/nvmet-track-and-limit-the-number-of-namespaces-per-s.patch
new file mode 100644
index 0000000000..4513b5614f
--- /dev/null
+++ b/patches.drivers/nvmet-track-and-limit-the-number-of-namespaces-per-s.patch
@@ -0,0 +1,101 @@
+From: Christoph Hellwig <hch@lst.de>
+Date: Sun, 13 May 2018 19:00:13 +0200
+Subject: [PATCH] nvmet: track and limit the number of namespaces per subsystem
+Git-commit: 793c7cfce02ce88b7bd67d43834c052d16c096e3
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: 1054245
+
+TP 4004 introduces a new 'Maximum Number of Allocated Namespaces' field
+in the Identify controller data to help the host size resources. Put
+an upper limit on the supported namespaces to be able to support this
+value as supporting 32-bits worth of namespaces would lead to very
+large buffers. The limit is completely arbitrary at this point.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Keith Busch <keith.busch@intel.com>
+Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+---
+ drivers/nvme/target/admin-cmd.c | 1 +
+ drivers/nvme/target/core.c | 8 +++++++-
+ drivers/nvme/target/nvmet.h | 8 ++++++++
+ 3 files changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
+index 30073d2ca76a..bf4d6002b3b4 100644
+--- a/drivers/nvme/target/admin-cmd.c
++++ b/drivers/nvme/target/admin-cmd.c
+@@ -220,6 +220,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
+ id->maxcmd = cpu_to_le16(NVMET_MAX_CMD);
+
+ id->nn = cpu_to_le32(ctrl->subsys->max_nsid);
++ id->mnan = cpu_to_le32(NVMET_MAX_NAMESPACES);
+ id->oncs = cpu_to_le16(NVME_CTRL_ONCS_DSM |
+ NVME_CTRL_ONCS_WRITE_ZEROES);
+
+diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
+index edd51b8fcd04..1203d1fface6 100644
+--- a/drivers/nvme/target/core.c
++++ b/drivers/nvme/target/core.c
+@@ -326,9 +326,13 @@ void nvmet_put_namespace(struct nvmet_ns *ns)
+ int nvmet_ns_enable(struct nvmet_ns *ns)
+ {
+ struct nvmet_subsys *subsys = ns->subsys;
+- int ret = 0;
++ int ret;
+
+ mutex_lock(&subsys->lock);
++ ret = -EMFILE;
++ if (subsys->nr_namespaces == NVMET_MAX_NAMESPACES)
++ goto out_unlock;
++ ret = 0;
+ if (ns->enabled)
+ goto out_unlock;
+
+@@ -370,6 +374,7 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
+
+ list_add_tail_rcu(&ns->dev_link, &old->dev_link);
+ }
++ subsys->nr_namespaces++;
+
+ nvmet_ns_changed(subsys, ns->nsid);
+ ns->enabled = true;
+@@ -411,6 +416,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns)
+ percpu_ref_exit(&ns->ref);
+
+ mutex_lock(&subsys->lock);
++ subsys->nr_namespaces--;
+ nvmet_ns_changed(subsys, ns->nsid);
+
+ if (ns->bdev)
+diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
+index 4af3f537dcd2..eec4725ea5b3 100644
+--- a/drivers/nvme/target/nvmet.h
++++ b/drivers/nvme/target/nvmet.h
+@@ -165,6 +165,7 @@ struct nvmet_subsys {
+ struct kref ref;
+
+ struct list_head namespaces;
++ unsigned int nr_namespaces;
+ unsigned int max_nsid;
+
+ struct list_head ctrls;
+@@ -343,6 +344,13 @@ u32 nvmet_get_log_page_len(struct nvme_command *cmd);
+ #define NVMET_QUEUE_SIZE 1024
+ #define NVMET_NR_QUEUES 128
+ #define NVMET_MAX_CMD NVMET_QUEUE_SIZE
++
++/*
++ * Nice round number that makes a list of nsids fit into a page.
++ * Should become tunable at some point in the future.
++ */
++#define NVMET_MAX_NAMESPACES 1024
++
+ #define NVMET_KAS 10
+ #define NVMET_DISC_KATO 120
+
+--
+2.12.3
+
diff --git a/patches.drivers/nvmet-use-Retain-Async-Event-bit-to-clear-AEN.patch b/patches.drivers/nvmet-use-Retain-Async-Event-bit-to-clear-AEN.patch
new file mode 100644
index 0000000000..68fae3d864
--- /dev/null
+++ b/patches.drivers/nvmet-use-Retain-Async-Event-bit-to-clear-AEN.patch
@@ -0,0 +1,71 @@
+From: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
+Date: Thu, 26 Jul 2018 14:00:41 -0700
+Subject: [PATCH] nvmet: use Retain Async Event bit to clear AEN
+Git-commit: b369b30cf510fe94d8884837039362e2ec223cec
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: bsc#1054245
+
+In the current implementation, we clear the AEN bit when we get the
+"get log page" command if given log page is associated with AEN.
+This patch allows optionally retaining the AEN for the ctrl
+under consideration when Retain Asynchronous Event (RAE) bit is set
+as a part of "get log page" command.
+
+This allows the host to read the Log page and optionally retaining the
+AEN associated with this log page when using userspace tools like
+nvme-cli.
+
+Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
+[hch: also use the new helper in the just merged ANA code]
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Hannes Reinecke <hare@suse.com>
+---
+ drivers/nvme/target/admin-cmd.c | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
+index 628270a5bda9..da2dac84752d 100644
+--- a/drivers/nvme/target/admin-cmd.c
++++ b/drivers/nvme/target/admin-cmd.c
+@@ -19,6 +19,19 @@
+ #include <asm/unaligned.h>
+ #include "nvmet.h"
+
++/*
++ * This helper allows us to clear the AEN based on the RAE bit,
++ * Please use this helper when processing the log pages which are
++ * associated with the AEN.
++ */
++static inline void nvmet_clear_aen(struct nvmet_req *req, u32 aen_bit)
++{
++ int rae = le32_to_cpu(req->cmd->common.cdw10[0]) & 1 << 15;
++
++ if (!rae)
++ clear_bit(aen_bit, &req->sq->ctrl->aen_masked);
++}
++
+ u32 nvmet_get_log_page_len(struct nvme_command *cmd)
+ {
+ u32 len = le16_to_cpu(cmd->get_log_page.numdu);
+@@ -136,7 +149,7 @@ static void nvmet_execute_get_log_changed_ns(struct nvmet_req *req)
+ if (!status)
+ status = nvmet_zero_sgl(req, len, req->data_len - len);
+ ctrl->nr_changed_ns = 0;
+- clear_bit(NVME_AEN_CFG_NS_ATTR, &ctrl->aen_masked);
++ nvmet_clear_aen(req, NVME_AEN_CFG_NS_ATTR);
+ mutex_unlock(&ctrl->lock);
+ out:
+ nvmet_req_complete(req, status);
+@@ -204,7 +217,7 @@ static void nvmet_execute_get_log_page_ana(struct nvmet_req *req)
+
+ hdr.chgcnt = cpu_to_le64(nvmet_ana_chgcnt);
+ hdr.ngrps = cpu_to_le16(ngrps);
+- clear_bit(NVME_AEN_CFG_ANA_CHANGE, &req->sq->ctrl->aen_masked);
++ nvmet_clear_aen(req, NVME_AEN_CFG_ANA_CHANGE);
+ up_read(&nvmet_ana_sem);
+
+ kfree(desc);
+--
+2.12.3
+
diff --git a/patches.fixes/nvmet-fixup-crash-on-NULL-device-path.patch b/patches.fixes/nvmet-fixup-crash-on-NULL-device-path.patch
new file mode 100644
index 0000000000..1147023a77
--- /dev/null
+++ b/patches.fixes/nvmet-fixup-crash-on-NULL-device-path.patch
@@ -0,0 +1,56 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Wed, 25 Jul 2018 08:35:17 +0200
+Subject: [PATCH] nvmet: fixup crash on NULL device path
+Git-commit: 5613d31214eb4c5c04cdfce4966bb661c8b43191
+Git-repo: git://git.infradead.org/nvme.git
+Patch-Mainline: queued
+References: bsc#1054245
+
+When writing an empty string into the device_path attribute the kernel
+will crash with
+
+nvmet: failed to open block device (null): (-22)
+BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
+
+This patch sanitizes the error handling for invalid device path settings.
+
+Fixes: a07b4970 ("nvmet: add a generic NVMe target")
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+---
+ drivers/nvme/target/configfs.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
+index 2360f4d65b4c..fce77db0d2f7 100644
+--- a/drivers/nvme/target/configfs.c
++++ b/drivers/nvme/target/configfs.c
+@@ -285,6 +285,7 @@ static ssize_t nvmet_ns_device_path_store(struct config_item *item,
+ {
+ struct nvmet_ns *ns = to_nvmet_ns(item);
+ struct nvmet_subsys *subsys = ns->subsys;
++ size_t len;
+ int ret;
+
+ mutex_lock(&subsys->lock);
+@@ -292,10 +293,14 @@ static ssize_t nvmet_ns_device_path_store(struct config_item *item,
+ if (ns->enabled)
+ goto out_unlock;
+
+- kfree(ns->device_path);
++ ret = -EINVAL;
++ len = strcspn(page, "\n");
++ if (!len)
++ goto out_unlock;
+
++ kfree(ns->device_path);
+ ret = -ENOMEM;
+- ns->device_path = kstrndup(page, strcspn(page, "\n"), GFP_KERNEL);
++ ns->device_path = kstrndup(page, len, GFP_KERNEL);
+ if (!ns->device_path)
+ goto out_unlock;
+
+--
+2.12.3
+
diff --git a/patches.kabi/Revert-nvmet-constify-struct-nvmet_fabrics_ops.patch b/patches.kabi/Revert-nvmet-constify-struct-nvmet_fabrics_ops.patch
index c34e338329..6a3d557172 100644
--- a/patches.kabi/Revert-nvmet-constify-struct-nvmet_fabrics_ops.patch
+++ b/patches.kabi/Revert-nvmet-constify-struct-nvmet_fabrics_ops.patch
@@ -30,7 +30,7 @@ index 90f4bcd8bfdd..e4f3ce81fc3f 100644
/*
@@ -189,7 +189,7 @@ static void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid)
- }
+ up_read(&nvmet_config_sem);
}
-int nvmet_register_transport(const struct nvmet_fabrics_ops *ops)
@@ -150,8 +150,8 @@ index 255a25db6b1f..8b02451bb38d 100644
void nvmet_req_execute(struct nvmet_req *req);
void nvmet_req_complete(struct nvmet_req *req, u16 status);
@@ -321,8 +321,8 @@ void nvmet_ns_disable(struct nvmet_ns *ns);
- struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid);
- void nvmet_ns_free(struct nvmet_ns *ns);
+ struct nvmet_port *port);
+ void nvmet_port_send_ana_event(struct nvmet_port *port);
-int nvmet_register_transport(const struct nvmet_fabrics_ops *ops);
-void nvmet_unregister_transport(const struct nvmet_fabrics_ops *ops);
diff --git a/patches.kabi/nvme-guard-additional-fields-in-nvme-command-structu.patch b/patches.kabi/nvme-guard-additional-fields-in-nvme-command-structu.patch
new file mode 100644
index 0000000000..0821aeea91
--- /dev/null
+++ b/patches.kabi/nvme-guard-additional-fields-in-nvme-command-structu.patch
@@ -0,0 +1,77 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Tue, 31 Jul 2018 16:25:03 +0200
+Subject: [PATCH] nvme: guard additional fields in nvme command structures
+References: bsc#1054245
+Patch-Mainline: never, kABI fix
+
+Renaming fields in the command structures break the kABI checker,
+so we need to guard them accordingly.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+---
+ include/linux/nvme.h | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/include/linux/nvme.h b/include/linux/nvme.h
+index fdff3c37bdd9..59e76517934c 100644
+--- a/include/linux/nvme.h
++++ b/include/linux/nvme.h
+@@ -242,12 +242,16 @@ struct nvme_id_ctrl {
+ __le32 sanicap;
+ __le32 hmminds;
+ __le16 hmmaxd;
++#ifdef __GENKSYMS__
++ __u8 rsvd338[174];
++#else
+ __u8 rsvd338[4];
+ __u8 anatt;
+ __u8 anacap;
+ __le32 anagrpmax;
+ __le32 nanagrpid;
+ __u8 rsvd352[160];
++#endif
+ __u8 sqes;
+ __u8 cqes;
+ __le16 maxcmd;
+@@ -263,8 +267,12 @@ struct nvme_id_ctrl {
+ __le16 acwu;
+ __u8 rsvd534[2];
+ __le32 sgls;
++#ifdef __GENKSYMS__
++ __u8 rsvd540[228];
++#else
+ __le32 mnan;
+ __u8 rsvd544[224];
++#endif
+ char subnqn[256];
+ __u8 rsvd1024[768];
+ __le32 ioccsz;
+@@ -318,9 +326,13 @@ struct nvme_id_ns {
+ __le16 nabspf;
+ __le16 noiob;
+ __u8 nvmcap[16];
++#ifdef __GENKSYMS__
++ __u8 rsvd64[40];
++#else
+ __u8 rsvd64[28];
+ __le32 anagrpid;
+ __u8 rsvd96[8];
++#endif
+ __u8 nguid[16];
+ __u8 eui64[8];
+ struct nvme_lbaf lbaf[16];
+@@ -917,7 +929,11 @@ struct nvme_get_log_page_command {
+ __u64 rsvd2[2];
+ union nvme_data_ptr dptr;
+ __u8 lid;
++#ifdef __GENKSYMS__
++ __u8 rsvd10;
++#else
+ __u8 lsp; /* upper 4 bits reserved */
++#endif
+ __le16 numdl;
+ __le16 numdu;
+ __u16 rsvd11;
+--
+2.12.3
+
diff --git a/patches.kabi/nvme-kABI-fix-for-ANA-support-in-nvme_ctrl.patch b/patches.kabi/nvme-kABI-fix-for-ANA-support-in-nvme_ctrl.patch
new file mode 100644
index 0000000000..ae797d979f
--- /dev/null
+++ b/patches.kabi/nvme-kABI-fix-for-ANA-support-in-nvme_ctrl.patch
@@ -0,0 +1,113 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Tue, 31 Jul 2018 15:06:51 +0200
+Subject: [PATCH] nvme: kABI fix for ANA support in nvme_ctrl
+References: bsc#1054245
+Patch-Mainline: never, kABI fix
+
+Guard additional fields in nvme_ctrl.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+---
+ drivers/nvme/host/nvme.h | 44 +++++++++++++++++++++++++-------------------
+ 1 file changed, 25 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
+index 5ff3d1fc8df3..5856616a5abc 100644
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -173,7 +173,6 @@ struct nvme_ctrl {
+ u16 oacs;
+ u16 nssa;
+ u16 nr_streams;
+- u32 max_namespaces;
+ atomic_t abort_limit;
+ u8 vwc;
+ u32 vs;
+@@ -194,19 +193,6 @@ struct nvme_ctrl {
+ struct nvme_command ka_cmd;
+ struct work_struct fw_act_work;
+
+-#ifdef CONFIG_NVME_MULTIPATH
+- /* asymmetric namespace access: */
+- u8 anacap;
+- u8 anatt;
+- u32 anagrpmax;
+- u32 nanagrpid;
+- struct mutex ana_lock;
+- struct nvme_ana_rsp_hdr *ana_log_buf;
+- size_t ana_log_size;
+- struct timer_list anatt_timer;
+- struct work_struct ana_work;
+-#endif
+-
+ /* Power saving configuration */
+ u64 ps_max_latency_us;
+ bool apst_enabled;
+@@ -228,6 +214,20 @@ struct nvme_ctrl {
+ #ifndef __GENKSYMS__
+ u32 oaes;
+ unsigned long events;
++ u32 max_namespaces;
++
++#ifdef CONFIG_NVME_MULTIPATH
++ /* asymmetric namespace access: */
++ u8 anacap;
++ u8 anatt;
++ u32 anagrpmax;
++ u32 nanagrpid;
++ struct mutex ana_lock;
++ struct nvme_ana_rsp_hdr *ana_log_buf;
++ size_t ana_log_size;
++ struct timer_list anatt_timer;
++ struct work_struct ana_work;
++#endif
+ #endif
+ };
+
+@@ -275,7 +275,6 @@ struct nvme_ns_head {
+ struct bio_list requeue_list;
+ spinlock_t requeue_lock;
+ struct work_struct requeue_work;
+- struct mutex lock;
+ #endif
+ struct list_head list;
+ struct srcu_struct srcu;
+@@ -285,6 +284,11 @@ struct nvme_ns_head {
+ struct list_head entry;
+ struct kref ref;
+ int instance;
++#ifndef __GENKSYMS__
++#ifdef CONFIG_NVME_MULTIPATH
++ struct mutex lock;
++#endif
++#endif
+ };
+
+ struct nvme_ns {
+@@ -293,10 +297,6 @@ struct nvme_ns {
+ struct nvme_ctrl *ctrl;
+ struct request_queue *queue;
+ struct gendisk *disk;
+-#ifdef CONFIG_NVME_MULTIPATH
+- enum nvme_ana_state ana_state;
+- u32 ana_grpid;
+-#endif
+ struct list_head siblings;
+ struct nvm_dev *ndev;
+ struct kref kref;
+@@ -313,6 +313,12 @@ struct nvme_ns {
+ #define NVME_NS_DEAD 1
+ #define NVME_NS_ANA_PENDING 2
+ u16 noiob;
++#ifndef __GENKSYMS__
++#ifdef CONFIG_NVME_MULTIPATH
++ enum nvme_ana_state ana_state;
++ u32 ana_grpid;
++#endif
++#endif
+ };
+
+ struct nvme_ctrl_ops {
+--
+2.12.3
+
diff --git a/patches.kabi/nvme-kABI-fixes-for-nvme_ctrl.patch b/patches.kabi/nvme-kABI-fixes-for-nvme_ctrl.patch
index efb5c706d8..5dff5a3fbd 100644
--- a/patches.kabi/nvme-kABI-fixes-for-nvme_ctrl.patch
+++ b/patches.kabi/nvme-kABI-fixes-for-nvme_ctrl.patch
@@ -31,8 +31,8 @@ index a5c1e28905d2..54480281d67f 100644
struct work_struct fw_act_work;
- unsigned long events;
- /* Power saving configuration */
- u64 ps_max_latency_us;
+ #ifdef CONFIG_NVME_MULTIPATH
+ /* asymmetric namespace access: */
@@ -213,6 +211,10 @@ struct nvme_ctrl {
u16 maxcmd;
int nr_reconnects;
diff --git a/patches.kabi/nvme-kABI-fixes-for-nvmet.patch b/patches.kabi/nvme-kABI-fixes-for-nvmet.patch
index 1bdfb96f2c..c539269020 100644
--- a/patches.kabi/nvme-kABI-fixes-for-nvmet.patch
+++ b/patches.kabi/nvme-kABI-fixes-for-nvmet.patch
@@ -16,16 +16,18 @@ diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 8b02451bb38d..6688b574c8af 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
-@@ -135,8 +135,6 @@ struct nvmet_ctrl {
+@@ -135,10 +135,6 @@ struct nvmet_ctrl {
u16 cntlid;
u32 kato;
+- struct nvmet_port *port;
+-
- u32 aen_enabled;
- unsigned long aen_masked;
struct nvmet_req *async_event_cmds[NVMET_ASYNC_EVENTS];
unsigned int nr_async_event_cmds;
struct list_head async_events;
-@@ -149,11 +147,14 @@ struct nvmet_ctrl {
+@@ -149,11 +147,15 @@ struct nvmet_ctrl {
struct nvmet_fabrics_ops *ops;
@@ -35,6 +37,7 @@ index 8b02451bb38d..6688b574c8af 100644
char subsysnqn[NVMF_NQN_FIELD_LEN];
char hostnqn[NVMF_NQN_FIELD_LEN];
+#ifndef __GENKSYMS__
++ struct nvmet_port *port;
+ u32 aen_enabled;
+ unsigned long aen_masked;
+ __le32 *changed_ns_list;
diff --git a/patches.kabi/nvme-partially-revert-nvme-remove-nvme_req_needs_fai.patch b/patches.kabi/nvme-partially-revert-nvme-remove-nvme_req_needs_fai.patch
new file mode 100644
index 0000000000..601e949514
--- /dev/null
+++ b/patches.kabi/nvme-partially-revert-nvme-remove-nvme_req_needs_fai.patch
@@ -0,0 +1,59 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Tue, 31 Jul 2018 11:56:42 +0200
+Subject: [PATCH] nvme: partially revert "nvme: remove nvme_req_needs_failover"
+References: bsc#1054245
+Patch-Mainline: never, kABI fix
+
+Removing this function will break the kABI, so better don't.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+---
+ drivers/nvme/host/multipath.c | 7 +++++++
+ drivers/nvme/host/nvme.h | 6 ++++++
+ 2 files changed, 13 insertions(+)
+
+diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
+index 420efcda33d9..c4c20ee6bf1e 100644
+--- a/drivers/nvme/host/multipath.c
++++ b/drivers/nvme/host/multipath.c
+@@ -91,6 +91,13 @@ void nvme_failover_req(struct request *req)
+ kblockd_schedule_work(&ns->head->requeue_work);
+ }
+
++bool nvme_req_needs_failover(struct request *req, blk_status_t error)
++{
++ if (!(req->cmd_flags & REQ_NVME_MPATH))
++ return false;
++ return blk_path_error(error);
++}
++
+ void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
+ {
+ struct nvme_ns *ns;
+diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
+index be4e2ab9f576..5ff3d1fc8df3 100644
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -444,6 +444,7 @@ bool nvme_ctrl_use_ana(struct nvme_ctrl *ctrl);
+ void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
+ struct nvme_ctrl *ctrl, int *flags);
+ void nvme_failover_req(struct request *req);
++bool nvme_req_needs_failover(struct request *req, blk_status_t error);
+ void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl);
+ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head);
+ void nvme_mpath_add_disk(struct nvme_ns *ns, struct nvme_id_ns *id);
+@@ -490,6 +491,11 @@ static inline void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
+ static inline void nvme_failover_req(struct request *req)
+ {
+ }
++static inline bool nvme_req_needs_failover(struct request *req,
++ blk_status_t error)
++{
++ return false;
++}
+ static inline void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
+ {
+ }
+--
+2.12.3
+
diff --git a/patches.kabi/nvme-reintroduce-nvme_get_log_ext.patch b/patches.kabi/nvme-reintroduce-nvme_get_log_ext.patch
new file mode 100644
index 0000000000..53526a8caa
--- /dev/null
+++ b/patches.kabi/nvme-reintroduce-nvme_get_log_ext.patch
@@ -0,0 +1,48 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Tue, 31 Jul 2018 11:54:06 +0200
+Subject: [PATCH] nvme: reintruduce nvme_get_log_ext()
+References: bsc#1054245
+Patch-Mainline: never, kABI fix
+
+The patch 'nvme: simplify the API for getting log pages' replaced
+nvme_get_log_ext() with nvme_get_log().
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+---
+ drivers/nvme/host/core.c | 6 ++++++
+ drivers/nvme/host/nvme.h | 2 ++
+ 2 files changed, 8 insertions(+)
+
+diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
+index e9f82814eb68..632aa4c194ea 100644
+--- a/drivers/nvme/host/core.c
++++ b/drivers/nvme/host/core.c
+@@ -2271,6 +2271,12 @@ int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp,
+ return nvme_submit_sync_cmd(ctrl->admin_q, &c, log, size);
+ }
+
++int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
++ u8 log_page, void *log, size_t size, u64 offset)
++{
++ return nvme_get_log(ctrl, NVME_NSID_ALL, log_page, 0, log, size, 0);
++}
++
+ static int nvme_get_effects_log(struct nvme_ctrl *ctrl)
+ {
+ int ret;
+diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
+index a2a16abed2bb..be4e2ab9f576 100644
+--- a/drivers/nvme/host/nvme.h
++++ b/drivers/nvme/host/nvme.h
+@@ -431,6 +431,8 @@ int nvme_reset_ctrl_sync(struct nvme_ctrl *ctrl);
+ int nvme_delete_ctrl(struct nvme_ctrl *ctrl);
+ int nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl);
+
++int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
++ u8 log_page, void *log, size_t size, u64 offset);
+ int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp,
+ void *log, size_t size, u64 offset);
+
+--
+2.12.3
+
diff --git a/patches.kabi/nvmet-kABI-fixes-for-ANA-support.patch b/patches.kabi/nvmet-kABI-fixes-for-ANA-support.patch
new file mode 100644
index 0000000000..8e4342607c
--- /dev/null
+++ b/patches.kabi/nvmet-kABI-fixes-for-ANA-support.patch
@@ -0,0 +1,72 @@
+From: Hannes Reinecke <hare@suse.de>
+Date: Tue, 31 Jul 2018 16:29:21 +0200
+Subject: [PATCH] nvmet: kABI fixes for ANA support
+References: bsc#1054245
+Patch-Mainline: never, kABI fix
+
+Guard additional fields for ANA support to avoid kABI breakage.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+---
+ drivers/nvme/target/nvmet.h | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
+index 6ff4adf1ce39..0239492fa672 100644
+--- a/drivers/nvme/target/nvmet.h
++++ b/drivers/nvme/target/nvmet.h
+@@ -62,7 +62,6 @@ struct nvmet_ns {
+ loff_t size;
+ u8 nguid[16];
+ uuid_t uuid;
+- u32 anagrpid;
+
+ bool enabled;
+ struct nvmet_subsys *subsys;
+@@ -72,6 +71,9 @@ struct nvmet_ns {
+ struct config_group group;
+
+ struct completion disable_done;
++#ifndef __GENKSYMS__
++ u32 anagrpid;
++#endif
+ };
+
+ static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item)
+@@ -123,11 +125,13 @@ struct nvmet_port {
+ struct list_head subsystems;
+ struct config_group referrals_group;
+ struct list_head referrals;
++ void *priv;
++ bool enabled;
++#ifndef __GENKSYMS__
+ struct config_group ana_groups_group;
+ struct nvmet_ana_group ana_default_group;
+ enum nvme_ana_state *ana_state;
+- void *priv;
+- bool enabled;
++#endif
+ };
+
+ static inline struct nvmet_port *to_nvmet_port(struct config_item *item)
+@@ -189,7 +193,6 @@ struct nvmet_subsys {
+ struct kref ref;
+
+ struct list_head namespaces;
+- unsigned int nr_namespaces;
+ unsigned int max_nsid;
+
+ struct list_head ctrls;
+@@ -207,6 +210,9 @@ struct nvmet_subsys {
+
+ struct config_group namespaces_group;
+ struct config_group allowed_hosts_group;
++#ifndef __GENKSYMS__
++ unsigned int nr_namespaces;
++#endif
+ };
+
+ static inline struct nvmet_subsys *to_subsys(struct config_item *item)
+--
+2.12.3
+
diff --git a/series.conf b/series.conf
index eb39cec9f0..cbe0b12c9a 100644
--- a/series.conf
+++ b/series.conf
@@ -15257,8 +15257,21 @@
patches.suse/0005-MODSIGN-Allow-the-db-UEFI-variable-to-be-suppressed.patch
patches.suse/0006-modsign-Use-secondary-trust-keyring-for-module-signi.patch
+ # git://git.infradead.org/nvme.git nvme-4.18
+ patches.fixes/nvmet-fixup-crash-on-NULL-device-path.patch
+
# git://git.infradead.org/nvme.git nvme-4.19
patches.drivers/nvme-move-init-of-keep_alive-work-item-to-controller.patch
+ patches.drivers/nvme.h-add-support-for-the-log-specific-field.patch
+ patches.drivers/nvme.h-add-ANA-definitions.patch
+ patches.drivers/nvme-simplify-the-API-for-getting-log-pages.patch
+ patches.drivers/nvme-remove-nvme_req_needs_failover.patch
+ patches.drivers/nvme-add-ANA-support.patch
+ patches.drivers/nvmet-keep-a-port-pointer-in-nvmet_ctrl.patch
+ patches.drivers/nvmet-track-and-limit-the-number-of-namespaces-per-s.patch
+ patches.drivers/nvmet-add-minimal-ANA-support.patch
+ patches.drivers/nvmet-support-configuring-ANA-groups.patch
+ patches.drivers/nvmet-use-Retain-Async-Event-bit-to-clear-AEN.patch
# jeyu/linux modules-next
patches.suse/0001-module-make-it-clear-when-we-re-handling-the-module-.patch
@@ -15918,6 +15931,11 @@
patches.kabi/Revert-nvme-mark-nvme_queue_scan-static.patch
patches.kabi/kABI-fixes-for-qla2xxx-Fix-inconsistent-DMA-mem-allo.patch
patches.kabi/kABI-fixes-for-nvme-if_ready-checks-fail-io-to-deletin.patch
+ patches.kabi/nvme-reintroduce-nvme_get_log_ext.patch
+ patches.kabi/nvme-partially-revert-nvme-remove-nvme_req_needs_fai.patch
+ patches.kabi/nvme-kABI-fix-for-ANA-support-in-nvme_ctrl.patch
+ patches.kabi/nvme-guard-additional-fields-in-nvme-command-structu.patch
+ patches.kabi/nvmet-kABI-fixes-for-ANA-support.patch
patches.kabi/rtlwifi-deferred-work-kabi-fix.patch
patches.kabi/of-device-kabi-fix.patch