Merge tag 'perf-tools-for-v5.15-2021-09-11' of git://git.kernel.org/pub/scm/linux...
[linux-2.6-microblaze.git] / drivers / nvme / host / core.c
index 11779be..7efb31b 100644 (file)
@@ -116,6 +116,8 @@ static struct class *nvme_ns_chr_class;
 static void nvme_put_subsystem(struct nvme_subsystem *subsys);
 static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
                                           unsigned nsid);
+static void nvme_update_keep_alive(struct nvme_ctrl *ctrl,
+                                  struct nvme_command *cmd);
 
 /*
  * Prepare a queue for teardown.
@@ -587,9 +589,6 @@ static void nvme_free_ns(struct kref *kref)
 {
        struct nvme_ns *ns = container_of(kref, struct nvme_ns, kref);
 
-       if (ns->ndev)
-               nvme_nvm_unregister(ns);
-
        put_disk(ns->disk);
        nvme_put_ns_head(ns->head);
        nvme_put_ctrl(ns->ctrl);
@@ -900,7 +899,10 @@ static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns,
                cpu_to_le64(nvme_sect_to_lba(ns, blk_rq_pos(req)));
        cmnd->write_zeroes.length =
                cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1);
-       cmnd->write_zeroes.control = 0;
+       if (nvme_ns_has_pi(ns))
+               cmnd->write_zeroes.control = cpu_to_le16(NVME_RW_PRINFO_PRACT);
+       else
+               cmnd->write_zeroes.control = 0;
        return BLK_STS_OK;
 }
 
@@ -965,12 +967,11 @@ void nvme_cleanup_cmd(struct request *req)
 {
        if (req->rq_flags & RQF_SPECIAL_PAYLOAD) {
                struct nvme_ctrl *ctrl = nvme_req(req)->ctrl;
-               struct page *page = req->special_vec.bv_page;
 
-               if (page == ctrl->discard_page)
+               if (req->special_vec.bv_page == ctrl->discard_page)
                        clear_bit_unlock(0, &ctrl->discard_page_busy);
                else
-                       kfree(page_address(page) + req->special_vec.bv_offset);
+                       kfree(bvec_virt(&req->special_vec));
        }
 }
 EXPORT_SYMBOL_GPL(nvme_cleanup_cmd);
@@ -1026,7 +1027,8 @@ blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req)
                return BLK_STS_IOERR;
        }
 
-       cmd->common.command_id = req->tag;
+       nvme_req(req)->genctr++;
+       cmd->common.command_id = nvme_cid(req);
        trace_nvme_setup_cmd(req, cmd);
        return ret;
 }
@@ -1152,7 +1154,8 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
        return effects;
 }
 
-static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
+static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects,
+                             struct nvme_command *cmd, int status)
 {
        if (effects & NVME_CMD_EFFECTS_CSE_MASK) {
                nvme_unfreeze(ctrl);
@@ -1167,6 +1170,26 @@ static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
                nvme_queue_scan(ctrl);
                flush_work(&ctrl->scan_work);
        }
+
+       switch (cmd->common.opcode) {
+       case nvme_admin_set_features:
+               switch (le32_to_cpu(cmd->common.cdw10) & 0xFF) {
+               case NVME_FEAT_KATO:
+                       /*
+                        * Keep alive commands interval on the host should be
+                        * updated when KATO is modified by Set Features
+                        * commands.
+                        */
+                       if (!status)
+                               nvme_update_keep_alive(ctrl, cmd);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
 }
 
 int nvme_execute_passthru_rq(struct request *rq)
@@ -1181,7 +1204,7 @@ int nvme_execute_passthru_rq(struct request *rq)
        effects = nvme_passthru_start(ctrl, ns, cmd->common.opcode);
        ret = nvme_execute_rq(disk, rq, false);
        if (effects) /* nothing to be done for zero cmd effects */
-               nvme_passthru_end(ctrl, effects);
+               nvme_passthru_end(ctrl, effects, cmd, ret);
 
        return ret;
 }
@@ -1269,6 +1292,21 @@ void nvme_stop_keep_alive(struct nvme_ctrl *ctrl)
 }
 EXPORT_SYMBOL_GPL(nvme_stop_keep_alive);
 
+static void nvme_update_keep_alive(struct nvme_ctrl *ctrl,
+                                  struct nvme_command *cmd)
+{
+       unsigned int new_kato =
+               DIV_ROUND_UP(le32_to_cpu(cmd->common.cdw11), 1000);
+
+       dev_info(ctrl->device,
+                "keep alive interval updated from %u ms to %u ms\n",
+                ctrl->kato * 1000 / 2, new_kato * 1000 / 2);
+
+       nvme_stop_keep_alive(ctrl);
+       ctrl->kato = new_kato;
+       nvme_start_keep_alive(ctrl);
+}
+
 /*
  * In NVMe 1.0 the CNS field was just a binary controller or namespace
  * flag, thus sending any new CNS opcodes has a big chance of not working.
@@ -1302,11 +1340,6 @@ static int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
        return error;
 }
 
-static bool nvme_multi_css(struct nvme_ctrl *ctrl)
-{
-       return (ctrl->ctrl_config & NVME_CC_CSS_MASK) == NVME_CC_CSS_CSI;
-}
-
 static int nvme_process_ns_desc(struct nvme_ctrl *ctrl, struct nvme_ns_ids *ids,
                struct nvme_ns_id_desc *cur, bool *csi_seen)
 {
@@ -1819,7 +1852,7 @@ static void nvme_update_disk_info(struct gendisk *disk,
 static inline bool nvme_first_scan(struct gendisk *disk)
 {
        /* nvme_alloc_ns() scans the disk prior to adding it */
-       return !(disk->flags & GENHD_FL_UP);
+       return !disk_live(disk);
 }
 
 static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)
@@ -1874,6 +1907,7 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
                        goto out_unfreeze;
        }
 
+       set_bit(NVME_NS_READY, &ns->flags);
        blk_mq_unfreeze_queue(ns->disk->queue);
 
        if (blk_queue_is_zoned(ns->queue)) {
@@ -1885,9 +1919,10 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
        if (nvme_ns_head_multipath(ns->head)) {
                blk_mq_freeze_queue(ns->head->disk->queue);
                nvme_update_disk_info(ns->head->disk, ns, id);
+               nvme_mpath_revalidate_paths(ns);
                blk_stack_limits(&ns->head->disk->queue->limits,
                                 &ns->queue->limits, 0);
-               blk_queue_update_readahead(ns->head->disk->queue);
+               disk_update_readahead(ns->head->disk);
                blk_mq_unfreeze_queue(ns->head->disk->queue);
        }
        return 0;
@@ -3215,9 +3250,6 @@ static const struct attribute_group nvme_ns_id_attr_group = {
 
 const struct attribute_group *nvme_ns_id_attr_groups[] = {
        &nvme_ns_id_attr_group,
-#ifdef CONFIG_NVM
-       &nvme_nvm_attr_group,
-#endif
        NULL,
 };
 
@@ -3726,9 +3758,14 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
        if (!ns)
                goto out_free_id;
 
-       ns->queue = blk_mq_init_queue(ctrl->tagset);
-       if (IS_ERR(ns->queue))
+       disk = blk_mq_alloc_disk(ctrl->tagset, ns);
+       if (IS_ERR(disk))
                goto out_free_ns;
+       disk->fops = &nvme_bdev_ops;
+       disk->private_data = ns;
+
+       ns->disk = disk;
+       ns->queue = disk->queue;
 
        if (ctrl->opts && ctrl->opts->data_digest)
                blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, ns->queue);
@@ -3737,20 +3774,12 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
        if (ctrl->ops->flags & NVME_F_PCI_P2PDMA)
                blk_queue_flag_set(QUEUE_FLAG_PCI_P2PDMA, ns->queue);
 
-       ns->queue->queuedata = ns;
        ns->ctrl = ctrl;
        kref_init(&ns->kref);
 
        if (nvme_init_ns_head(ns, nsid, ids, id->nmic & NVME_NS_NMIC_SHARED))
-               goto out_free_queue;
+               goto out_cleanup_disk;
 
-       disk = alloc_disk_node(0, node);
-       if (!disk)
-               goto out_unlink_ns;
-
-       disk->fops = &nvme_bdev_ops;
-       disk->private_data = ns;
-       disk->queue = ns->queue;
        /*
         * Without the multipath code enabled, multiple controller per
         * subsystems are visible as devices and thus we cannot use the
@@ -3759,17 +3788,9 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
        if (!nvme_mpath_set_disk_name(ns, disk->disk_name, &disk->flags))
                sprintf(disk->disk_name, "nvme%dn%d", ctrl->instance,
                        ns->head->instance);
-       ns->disk = disk;
 
        if (nvme_update_ns_info(ns, id))
-               goto out_put_disk;
-
-       if ((ctrl->quirks & NVME_QUIRK_LIGHTNVM) && id->vs[0] == 0x1) {
-               if (nvme_nvm_register(ns, disk->disk_name, node)) {
-                       dev_warn(ctrl->device, "LightNVM init failure\n");
-                       goto out_put_disk;
-               }
-       }
+               goto out_unlink_ns;
 
        down_write(&ctrl->namespaces_rwsem);
        list_add_tail(&ns->list, &ctrl->namespaces);
@@ -3777,7 +3798,9 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
 
        nvme_get_ctrl(ctrl);
 
-       device_add_disk(ctrl->device, ns->disk, nvme_ns_id_attr_groups);
+       if (device_add_disk(ctrl->device, ns->disk, nvme_ns_id_attr_groups))
+               goto out_cleanup_ns_from_list;
+
        if (!nvme_ns_head_multipath(ns->head))
                nvme_add_ns_cdev(ns);
 
@@ -3786,10 +3809,12 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
        kfree(id);
 
        return;
- out_put_disk:
-       /* prevent double queue cleanup */
-       ns->disk->queue = NULL;
-       put_disk(ns->disk);
+
+ out_cleanup_ns_from_list:
+       nvme_put_ctrl(ctrl);
+       down_write(&ctrl->namespaces_rwsem);
+       list_del_init(&ns->list);
+       up_write(&ctrl->namespaces_rwsem);
  out_unlink_ns:
        mutex_lock(&ctrl->subsys->lock);
        list_del_rcu(&ns->siblings);
@@ -3797,8 +3822,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
                list_del_init(&ns->head->entry);
        mutex_unlock(&ctrl->subsys->lock);
        nvme_put_ns_head(ns->head);
- out_free_queue:
-       blk_cleanup_queue(ns->queue);
+ out_cleanup_disk:
+       blk_cleanup_disk(disk);
  out_free_ns:
        kfree(ns);
  out_free_id:
@@ -3807,36 +3832,46 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
 
 static void nvme_ns_remove(struct nvme_ns *ns)
 {
+       bool last_path = false;
+
        if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
                return;
 
+       clear_bit(NVME_NS_READY, &ns->flags);
        set_capacity(ns->disk, 0);
        nvme_fault_inject_fini(&ns->fault_inject);
 
        mutex_lock(&ns->ctrl->subsys->lock);
        list_del_rcu(&ns->siblings);
-       if (list_empty(&ns->head->list))
-               list_del_init(&ns->head->entry);
        mutex_unlock(&ns->ctrl->subsys->lock);
 
-       synchronize_rcu(); /* guarantee not available in head->list */
-       nvme_mpath_clear_current_path(ns);
-       synchronize_srcu(&ns->head->srcu); /* wait for concurrent submissions */
-
-       if (ns->disk->flags & GENHD_FL_UP) {
-               if (!nvme_ns_head_multipath(ns->head))
-                       nvme_cdev_del(&ns->cdev, &ns->cdev_device);
-               del_gendisk(ns->disk);
-               blk_cleanup_queue(ns->queue);
-               if (blk_get_integrity(ns->disk))
-                       blk_integrity_unregister(ns->disk);
-       }
+       /* guarantee not available in head->list */
+       synchronize_rcu();
+
+       /* wait for concurrent submissions */
+       if (nvme_mpath_clear_current_path(ns))
+               synchronize_srcu(&ns->head->srcu);
+
+       if (!nvme_ns_head_multipath(ns->head))
+               nvme_cdev_del(&ns->cdev, &ns->cdev_device);
+       del_gendisk(ns->disk);
+       blk_cleanup_queue(ns->queue);
+       if (blk_get_integrity(ns->disk))
+               blk_integrity_unregister(ns->disk);
 
        down_write(&ns->ctrl->namespaces_rwsem);
        list_del_init(&ns->list);
        up_write(&ns->ctrl->namespaces_rwsem);
 
-       nvme_mpath_check_last_path(ns);
+       /* Synchronize with nvme_init_ns_head() */
+       mutex_lock(&ns->head->subsys->lock);
+       if (list_empty(&ns->head->list)) {
+               list_del_init(&ns->head->entry);
+               last_path = true;
+       }
+       mutex_unlock(&ns->head->subsys->lock);
+       if (last_path)
+               nvme_mpath_shutdown_disk(ns->head);
        nvme_put_ns(ns);
 }