nvme: create helper function to obtain command effects
authorLogan Gunthorpe <logang@deltatee.com>
Fri, 24 Jul 2020 17:25:13 +0000 (11:25 -0600)
committerChristoph Hellwig <hch@lst.de>
Wed, 29 Jul 2020 05:45:20 +0000 (07:45 +0200)
Separate the code to obtain command effects from the code
to start a passthru request and move the nvme_passthru_start() and
nvme_passthru_end() functions up above nvme_submit_user_cmd() in order
that they may be used in a new helper a subsequent patch.

The new helper function will be necessary for nvmet passthru
code to determine if we need to change out of interrupt context
to handle the effects. It is exported in the NVME_TARGET_PASSTHRU
namespace.

Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/host/core.c
drivers/nvme/host/nvme.h

index 2818c17..ab040ee 100644 (file)
@@ -928,6 +928,106 @@ out:
        return ERR_PTR(ret);
 }
 
+static u32 nvme_known_admin_effects(u8 opcode)
+{
+       switch (opcode) {
+       case nvme_admin_format_nvm:
+               return NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC |
+                       NVME_CMD_EFFECTS_CSE_MASK;
+       case nvme_admin_sanitize_nvm:
+               return NVME_CMD_EFFECTS_CSE_MASK;
+       default:
+               break;
+       }
+       return 0;
+}
+
+u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode)
+{
+       u32 effects = 0;
+
+       if (ns) {
+               if (ns->head->effects)
+                       effects = le32_to_cpu(ns->head->effects->iocs[opcode]);
+               if (effects & ~(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC))
+                       dev_warn(ctrl->device,
+                                "IO command:%02x has unhandled effects:%08x\n",
+                                opcode, effects);
+               return 0;
+       }
+
+       if (ctrl->effects)
+               effects = le32_to_cpu(ctrl->effects->acs[opcode]);
+       effects |= nvme_known_admin_effects(opcode);
+
+       return effects;
+}
+EXPORT_SYMBOL_NS_GPL(nvme_command_effects, NVME_TARGET_PASSTHRU);
+
+static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
+                              u8 opcode)
+{
+       u32 effects = nvme_command_effects(ctrl, ns, opcode);
+
+       /*
+        * For simplicity, IO to all namespaces is quiesced even if the command
+        * effects say only one namespace is affected.
+        */
+       if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK)) {
+               mutex_lock(&ctrl->scan_lock);
+               mutex_lock(&ctrl->subsys->lock);
+               nvme_mpath_start_freeze(ctrl->subsys);
+               nvme_mpath_wait_freeze(ctrl->subsys);
+               nvme_start_freeze(ctrl);
+               nvme_wait_freeze(ctrl);
+       }
+       return effects;
+}
+
+static void nvme_update_formats(struct nvme_ctrl *ctrl, u32 *effects)
+{
+       struct nvme_ns *ns;
+
+       down_read(&ctrl->namespaces_rwsem);
+       list_for_each_entry(ns, &ctrl->namespaces, list)
+               if (_nvme_revalidate_disk(ns->disk))
+                       nvme_set_queue_dying(ns);
+               else if (blk_queue_is_zoned(ns->disk->queue)) {
+                       /*
+                        * IO commands are required to fully revalidate a zoned
+                        * device. Force the command effects to trigger rescan
+                        * work so report zones can run in a context with
+                        * unfrozen IO queues.
+                        */
+                       *effects |= NVME_CMD_EFFECTS_NCC;
+               }
+       up_read(&ctrl->namespaces_rwsem);
+}
+
+static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
+{
+       /*
+        * Revalidate LBA changes prior to unfreezing. This is necessary to
+        * prevent memory corruption if a logical block size was changed by
+        * this command.
+        */
+       if (effects & NVME_CMD_EFFECTS_LBCC)
+               nvme_update_formats(ctrl, &effects);
+       if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK)) {
+               nvme_unfreeze(ctrl);
+               nvme_mpath_unfreeze(ctrl->subsys);
+               mutex_unlock(&ctrl->subsys->lock);
+               nvme_remove_invalid_namespaces(ctrl, NVME_NSID_ALL);
+               mutex_unlock(&ctrl->scan_lock);
+       }
+       if (effects & NVME_CMD_EFFECTS_CCC)
+               nvme_init_identify(ctrl);
+       if (effects & (NVME_CMD_EFFECTS_NIC | NVME_CMD_EFFECTS_NCC)) {
+               nvme_queue_scan(ctrl);
+               flush_work(&ctrl->scan_work);
+       }
+}
+
 static int nvme_submit_user_cmd(struct request_queue *q,
                struct nvme_command *cmd, void __user *ubuffer,
                unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
@@ -1394,98 +1494,6 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
                        metadata, meta_len, lower_32_bits(io.slba), NULL, 0);
 }
 
-static u32 nvme_known_admin_effects(u8 opcode)
-{
-       switch (opcode) {
-       case nvme_admin_format_nvm:
-               return NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC |
-                                       NVME_CMD_EFFECTS_CSE_MASK;
-       case nvme_admin_sanitize_nvm:
-               return NVME_CMD_EFFECTS_CSE_MASK;
-       default:
-               break;
-       }
-       return 0;
-}
-
-static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
-                                                               u8 opcode)
-{
-       u32 effects = 0;
-
-       if (ns) {
-               if (ns->head->effects)
-                       effects = le32_to_cpu(ns->head->effects->iocs[opcode]);
-               if (effects & ~(NVME_CMD_EFFECTS_CSUPP | NVME_CMD_EFFECTS_LBCC))
-                       dev_warn(ctrl->device,
-                                "IO command:%02x has unhandled effects:%08x\n",
-                                opcode, effects);
-               return 0;
-       }
-
-       if (ctrl->effects)
-               effects = le32_to_cpu(ctrl->effects->acs[opcode]);
-       effects |= nvme_known_admin_effects(opcode);
-
-       /*
-        * For simplicity, IO to all namespaces is quiesced even if the command
-        * effects say only one namespace is affected.
-        */
-       if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK)) {
-               mutex_lock(&ctrl->scan_lock);
-               mutex_lock(&ctrl->subsys->lock);
-               nvme_mpath_start_freeze(ctrl->subsys);
-               nvme_mpath_wait_freeze(ctrl->subsys);
-               nvme_start_freeze(ctrl);
-               nvme_wait_freeze(ctrl);
-       }
-       return effects;
-}
-
-static void nvme_update_formats(struct nvme_ctrl *ctrl, u32 *effects)
-{
-       struct nvme_ns *ns;
-
-       down_read(&ctrl->namespaces_rwsem);
-       list_for_each_entry(ns, &ctrl->namespaces, list)
-               if (_nvme_revalidate_disk(ns->disk))
-                       nvme_set_queue_dying(ns);
-               else if (blk_queue_is_zoned(ns->disk->queue)) {
-                       /*
-                        * IO commands are required to fully revalidate a zoned
-                        * device. Force the command effects to trigger rescan
-                        * work so report zones can run in a context with
-                        * unfrozen IO queues.
-                        */
-                       *effects |= NVME_CMD_EFFECTS_NCC;
-               }
-       up_read(&ctrl->namespaces_rwsem);
-}
-
-static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
-{
-       /*
-        * Revalidate LBA changes prior to unfreezing. This is necessary to
-        * prevent memory corruption if a logical block size was changed by
-        * this command.
-        */
-       if (effects & NVME_CMD_EFFECTS_LBCC)
-               nvme_update_formats(ctrl, &effects);
-       if (effects & (NVME_CMD_EFFECTS_LBCC | NVME_CMD_EFFECTS_CSE_MASK)) {
-               nvme_unfreeze(ctrl);
-               nvme_mpath_unfreeze(ctrl->subsys);
-               mutex_unlock(&ctrl->subsys->lock);
-               nvme_remove_invalid_namespaces(ctrl, NVME_NSID_ALL);
-               mutex_unlock(&ctrl->scan_lock);
-       }
-       if (effects & NVME_CMD_EFFECTS_CCC)
-               nvme_init_identify(ctrl);
-       if (effects & (NVME_CMD_EFFECTS_NIC | NVME_CMD_EFFECTS_NCC)) {
-               nvme_queue_scan(ctrl);
-               flush_work(&ctrl->scan_work);
-       }
-}
-
 static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
                        struct nvme_passthru_cmd __user *ucmd)
 {
index 1609267..25063f0 100644 (file)
@@ -790,4 +790,7 @@ void nvme_hwmon_init(struct nvme_ctrl *ctrl);
 static inline void nvme_hwmon_init(struct nvme_ctrl *ctrl) { }
 #endif
 
+u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
+                        u8 opcode);
+
 #endif /* _NVME_H */