OSDN Git Service

nvme-pci: Sync queues on reset
[uclinux-h8/linux.git] / drivers / nvme / host / core.c
index a6644a2..f6879e4 100644 (file)
@@ -1257,10 +1257,9 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
                return 0;
        }
 
+       effects |= nvme_known_admin_effects(opcode);
        if (ctrl->effects)
                effects = le32_to_cpu(ctrl->effects->acs[opcode]);
-       else
-               effects = nvme_known_admin_effects(opcode);
 
        /*
         * For simplicity, IO to all namespaces is quiesced even if the command
@@ -2342,20 +2341,35 @@ static const struct attribute_group *nvme_subsys_attrs_groups[] = {
        NULL,
 };
 
-static int nvme_active_ctrls(struct nvme_subsystem *subsys)
+static bool nvme_validate_cntlid(struct nvme_subsystem *subsys,
+               struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
 {
-       int count = 0;
-       struct nvme_ctrl *ctrl;
+       struct nvme_ctrl *tmp;
+
+       lockdep_assert_held(&nvme_subsystems_lock);
+
+       list_for_each_entry(tmp, &subsys->ctrls, subsys_entry) {
+               if (ctrl->state == NVME_CTRL_DELETING ||
+                   ctrl->state == NVME_CTRL_DEAD)
+                       continue;
+
+               if (tmp->cntlid == ctrl->cntlid) {
+                       dev_err(ctrl->device,
+                               "Duplicate cntlid %u with %s, rejecting\n",
+                               ctrl->cntlid, dev_name(tmp->device));
+                       return false;
+               }
+
+               if ((id->cmic & (1 << 1)) ||
+                   (ctrl->opts && ctrl->opts->discovery_nqn))
+                       continue;
 
-       mutex_lock(&subsys->lock);
-       list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) {
-               if (ctrl->state != NVME_CTRL_DELETING &&
-                   ctrl->state != NVME_CTRL_DEAD)
-                       count++;
+               dev_err(ctrl->device,
+                       "Subsystem does not support multiple controllers\n");
+               return false;
        }
-       mutex_unlock(&subsys->lock);
 
-       return count;
+       return true;
 }
 
 static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
@@ -2395,22 +2409,13 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
        mutex_lock(&nvme_subsystems_lock);
        found = __nvme_find_get_subsystem(subsys->subnqn);
        if (found) {
-               /*
-                * Verify that the subsystem actually supports multiple
-                * controllers, else bail out.
-                */
-               if (!(ctrl->opts && ctrl->opts->discovery_nqn) &&
-                   nvme_active_ctrls(found) && !(id->cmic & (1 << 1))) {
-                       dev_err(ctrl->device,
-                               "ignoring ctrl due to duplicate subnqn (%s).\n",
-                               found->subnqn);
-                       nvme_put_subsystem(found);
-                       ret = -EINVAL;
-                       goto out_unlock;
-               }
-
                __nvme_release_subsystem(subsys);
                subsys = found;
+
+               if (!nvme_validate_cntlid(subsys, ctrl, id)) {
+                       ret = -EINVAL;
+                       goto out_put_subsystem;
+               }
        } else {
                ret = device_add(&subsys->dev);
                if (ret) {
@@ -2422,23 +2427,20 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
                list_add_tail(&subsys->entry, &nvme_subsystems);
        }
 
-       ctrl->subsys = subsys;
-       mutex_unlock(&nvme_subsystems_lock);
-
        if (sysfs_create_link(&subsys->dev.kobj, &ctrl->device->kobj,
                        dev_name(ctrl->device))) {
                dev_err(ctrl->device,
                        "failed to create sysfs link from subsystem.\n");
-               /* the transport driver will eventually put the subsystem */
-               return -EINVAL;
+               goto out_put_subsystem;
        }
 
-       mutex_lock(&subsys->lock);
+       ctrl->subsys = subsys;
        list_add_tail(&ctrl->subsys_entry, &subsys->ctrls);
-       mutex_unlock(&subsys->lock);
-
+       mutex_unlock(&nvme_subsystems_lock);
        return 0;
 
+out_put_subsystem:
+       nvme_put_subsystem(subsys);
 out_unlock:
        mutex_unlock(&nvme_subsystems_lock);
        put_device(&subsys->dev);
@@ -3605,19 +3607,18 @@ static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result)
 {
        u32 aer_notice_type = (result & 0xff00) >> 8;
 
+       trace_nvme_async_event(ctrl, aer_notice_type);
+
        switch (aer_notice_type) {
        case NVME_AER_NOTICE_NS_CHANGED:
-               trace_nvme_async_event(ctrl, aer_notice_type);
                set_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events);
                nvme_queue_scan(ctrl);
                break;
        case NVME_AER_NOTICE_FW_ACT_STARTING:
-               trace_nvme_async_event(ctrl, aer_notice_type);
                queue_work(nvme_wq, &ctrl->fw_act_work);
                break;
 #ifdef CONFIG_NVME_MULTIPATH
        case NVME_AER_NOTICE_ANA:
-               trace_nvme_async_event(ctrl, aer_notice_type);
                if (!ctrl->ana_log_buf)
                        break;
                queue_work(nvme_wq, &ctrl->ana_work);
@@ -3696,10 +3697,10 @@ static void nvme_free_ctrl(struct device *dev)
        __free_page(ctrl->discard_page);
 
        if (subsys) {
-               mutex_lock(&subsys->lock);
+               mutex_lock(&nvme_subsystems_lock);
                list_del(&ctrl->subsys_entry);
-               mutex_unlock(&subsys->lock);
                sysfs_remove_link(&subsys->dev.kobj, dev_name(ctrl->device));
+               mutex_unlock(&nvme_subsystems_lock);
        }
 
        ctrl->ops->free_ctrl(ctrl);
@@ -3879,6 +3880,18 @@ void nvme_start_queues(struct nvme_ctrl *ctrl)
 }
 EXPORT_SYMBOL_GPL(nvme_start_queues);
 
+
+void nvme_sync_queues(struct nvme_ctrl *ctrl)
+{
+       struct nvme_ns *ns;
+
+       down_read(&ctrl->namespaces_rwsem);
+       list_for_each_entry(ns, &ctrl->namespaces, list)
+               blk_sync_queue(ns->queue);
+       up_read(&ctrl->namespaces_rwsem);
+}
+EXPORT_SYMBOL_GPL(nvme_sync_queues);
+
 /*
  * Check we didn't inadvertently grow the command structure sizes:
  */