[PATCH v4 2/2] nvme: enable generic interface (/dev/ngXnY) for unknown command sets
Joel Granados
j.granados at samsung.com
Tue Jun 28 12:10:16 PDT 2022
Extend nvme_alloc_ns() and nvme_validate_ns() for unknown command-set as
well. Both are made to use a new helper (nvme_update_ns_info_cs_indep)
which is similar to nvme_update_ns_info but performs fewer operations
to get the generic interface up.
Suggested-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Joel Granados <j.granados at samsung.com>
Signed-off-by: Kanchan Joshi <joshi.k at samsung.com>
---
drivers/nvme/host/core.c | 164 +++++++++++++++++++++++++++------------
1 file changed, 115 insertions(+), 49 deletions(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 0fd6127da8d1..45ad1bbe0c33 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -1425,28 +1425,30 @@ static int nvme_identify_ns(struct nvme_ctrl *ctrl, unsigned nsid,
}
static int nvme_identify_ns_cs_indep(struct nvme_ctrl *ctrl, unsigned nsid,
- struct nvme_id_ns_cs_indep **id)
+ struct nvme_id_ns_cs_indep **indep_id)
{
struct nvme_command c = {
.identify.opcode = nvme_admin_identify,
.identify.nsid = cpu_to_le32(nsid),
.identify.cns = NVME_ID_CNS_NS_CS_INDEP,
};
+ struct nvme_id_ns_cs_indep *id;
int ret;
- *id = kmalloc(sizeof(**id), GFP_KERNEL);
- if (!*id)
+ id = kmalloc(sizeof(**indep_id), GFP_KERNEL);
+ if (!id)
return -ENOMEM;
- ret = nvme_submit_sync_cmd(ctrl->admin_q, &c, *id, sizeof(**id));
+ ret = nvme_submit_sync_cmd(ctrl->admin_q, &c, id, sizeof(**indep_id));
if (ret) {
dev_warn(ctrl->device,
"Identify namespace (CS independent) failed (%d)\n",
ret);
- kfree(*id);
+ kfree(id);
return ret;
}
+ *indep_id = id;
return 0;
}
@@ -1908,6 +1910,39 @@ static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)
blk_queue_chunk_sectors(ns->queue, iob);
}
+static void nvme_update_ns_mpath_info_general(struct nvme_ns *ns, __u8 nsattr)
+{
+ set_disk_ro(ns->head->disk,
+ (nsattr & NVME_NS_ATTR_RO) ||
+ test_bit(NVME_NS_FORCE_RO, &ns->flags));
+ nvme_mpath_revalidate_paths(ns);
+ blk_stack_limits(&ns->head->disk->queue->limits,
+ &ns->queue->limits, 0);
+}
+
+static int nvme_update_ns_info_cs_indep(struct nvme_ns *ns,
+ struct nvme_id_ns_cs_indep *id)
+{
+ blk_mq_freeze_queue(ns->disk->queue);
+ nvme_set_queue_limits(ns->ctrl, ns->queue);
+ set_disk_ro(ns->disk, (id->nsattr & NVME_NS_ATTR_RO) ||
+ test_bit(NVME_NS_FORCE_RO, &ns->flags));
+ blk_mq_unfreeze_queue(ns->disk->queue);
+
+ if (nvme_ns_head_multipath(ns->head)) {
+ blk_mq_freeze_queue(ns->head->disk->queue);
+ nvme_update_ns_mpath_info_general(ns, id->nsattr);
+ ns->head->disk->flags |= GENHD_FL_HIDDEN;
+ blk_mq_unfreeze_queue(ns->head->disk->queue);
+ }
+
+ /* Hide the block-interface for these devices */
+ ns->disk->flags |= GENHD_FL_HIDDEN;
+ set_bit(NVME_NS_READY, &ns->flags);
+
+ return 0;
+}
+
static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
{
unsigned lbaf = nvme_lbaf_index(id->flbas);
@@ -1941,12 +1976,7 @@ 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);
- set_disk_ro(ns->head->disk,
- (id->nsattr & NVME_NS_ATTR_RO) ||
- test_bit(NVME_NS_FORCE_RO, &ns->flags));
- nvme_mpath_revalidate_paths(ns);
- blk_stack_limits(&ns->head->disk->queue->limits,
- &ns->queue->limits, 0);
+ nvme_update_ns_mpath_info_general(ns, id->nsattr);
disk_update_readahead(ns->head->disk);
blk_mq_unfreeze_queue(ns->head->disk->queue);
}
@@ -3951,15 +3981,31 @@ static void nvme_ns_add_to_ctrl_list(struct nvme_ns *ns)
}
static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
- struct nvme_ns_ids *ids)
+ struct nvme_ns_ids *ids, struct nvme_id_ns_cs_indep *indep_id)
{
+ int ret = 0;
struct nvme_ns *ns;
struct gendisk *disk;
- struct nvme_id_ns *id;
+ struct nvme_id_ns *id = NULL;
int node = ctrl->numa_node;
+ __u8 nmic;
+ __le32 anagrpid;
- if (nvme_identify_ns(ctrl, nsid, ids, &id))
- return;
+ switch (ids->csi) {
+ case NVME_CSI_NVM:
+ case NVME_CSI_ZNS:
+ if (nvme_identify_ns(ctrl, nsid, ids, &id))
+ return;
+ nmic = id->nmic;
+ anagrpid = id->anagrpid;
+ break;
+ default:
+ if (!indep_id)
+ return;
+ nmic = indep_id->nmic;
+ anagrpid = indep_id->anagrpid;
+ break;
+ }
ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
if (!ns)
@@ -3984,7 +4030,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
ns->ctrl = ctrl;
kref_init(&ns->kref);
- if (nvme_init_ns_head(ns, nsid, ids, id->nmic & NVME_NS_NMIC_SHARED))
+ if (nvme_init_ns_head(ns, nsid, ids, nmic & NVME_NS_NMIC_SHARED))
goto out_cleanup_disk;
/*
@@ -4010,7 +4056,16 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
ns->head->instance);
}
- if (nvme_update_ns_info(ns, id))
+ switch (ids->csi) {
+ case NVME_CSI_NVM:
+ case NVME_CSI_ZNS:
+ ret = nvme_update_ns_info(ns, id);
+ break;
+ default:
+ ret = nvme_update_ns_info_cs_indep(ns, indep_id);
+ break;
+ }
+ if (ret)
goto out_unlink_ns;
down_write(&ctrl->namespaces_rwsem);
@@ -4024,11 +4079,10 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid,
if (!nvme_ns_head_multipath(ns->head))
nvme_add_ns_cdev(ns);
- nvme_mpath_add_disk(ns, id->anagrpid);
+ nvme_mpath_add_disk(ns, anagrpid);
nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name);
- kfree(id);
- return;
+ goto out_free_id;
out_cleanup_ns_from_list:
nvme_put_ctrl(ctrl);
@@ -4106,29 +4160,34 @@ static void nvme_ns_remove_by_nsid(struct nvme_ctrl *ctrl, u32 nsid)
}
}
-static void nvme_validate_ns(struct nvme_ns *ns, struct nvme_ns_ids *ids)
+static void nvme_validate_ns(struct nvme_ns *ns, struct nvme_ns_ids *ids,
+ struct nvme_id_ns_cs_indep *indep_id)
{
- struct nvme_id_ns *id;
+ struct nvme_id_ns *id = NULL;
int ret = NVME_SC_INVALID_NS | NVME_SC_DNR;
if (test_bit(NVME_NS_DEAD, &ns->flags))
goto out;
- ret = nvme_identify_ns(ns->ctrl, ns->head->ns_id, ids, &id);
- if (ret)
- goto out;
-
- ret = NVME_SC_INVALID_NS | NVME_SC_DNR;
- if (!nvme_ns_ids_equal(&ns->head->ids, ids)) {
- dev_err(ns->ctrl->device,
- "identifiers changed for nsid %d\n", ns->head->ns_id);
- goto out_free_id;
+ switch (ids->csi) {
+ case NVME_CSI_NVM:
+ case NVME_CSI_ZNS:
+ if (nvme_identify_ns(ns->ctrl, ns->head->ns_id, ids, &id))
+ goto out;
+ if (!nvme_ns_ids_equal(&ns->head->ids, ids))
+ dev_err(ns->ctrl->device,
+ "identifiers changed for nsid %d\n",
+ ns->head->ns_id);
+ else
+ ret = nvme_update_ns_info(ns, id);
+ kfree(id);
+ break;
+ default:
+ if (indep_id)
+ ret = nvme_update_ns_info_cs_indep(ns, indep_id);
+ break;
}
- ret = nvme_update_ns_info(ns, id);
-
-out_free_id:
- kfree(id);
out:
/*
* Only remove the namespace if we got a fatal error back from the
@@ -4143,36 +4202,34 @@ static void nvme_validate_ns(struct nvme_ns *ns, struct nvme_ns_ids *ids)
static void nvme_validate_or_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
{
struct nvme_ns_ids ids = { };
- struct nvme_id_ns_cs_indep *id;
+ struct nvme_id_ns_cs_indep *indep_id = NULL;
struct nvme_ns *ns;
- bool ready = true;
+ int ret;
if (nvme_identify_ns_descs(ctrl, nsid, &ids))
return;
+ ret = nvme_identify_ns_cs_indep(ctrl, nsid, &indep_id);
+
/*
* Check if the namespace is ready. If not ignore it, we will get an
* AEN once it becomes ready and restart the scan.
*/
- if ((ctrl->cap & NVME_CAP_CRMS_CRIMS) &&
- !nvme_identify_ns_cs_indep(ctrl, nsid, &id)) {
- ready = id->nstat & NVME_NSTAT_NRDY;
- kfree(id);
+ if ((ctrl->cap & NVME_CAP_CRMS_CRIMS) && !ret) {
+ if (!(indep_id->nstat & NVME_NSTAT_NRDY))
+ goto free_indep_id;
}
- if (!ready)
- return;
-
ns = nvme_find_get_ns(ctrl, nsid);
if (ns) {
- nvme_validate_ns(ns, &ids);
+ nvme_validate_ns(ns, &ids, indep_id);
nvme_put_ns(ns);
- return;
+ goto free_indep_id;
}
switch (ids.csi) {
case NVME_CSI_NVM:
- nvme_alloc_ns(ctrl, nsid, &ids);
+ nvme_alloc_ns(ctrl, nsid, &ids, indep_id);
break;
case NVME_CSI_ZNS:
if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
@@ -4187,13 +4244,22 @@ static void nvme_validate_or_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
nsid);
break;
}
- nvme_alloc_ns(ctrl, nsid, &ids);
+ nvme_alloc_ns(ctrl, nsid, &ids, indep_id);
break;
default:
- dev_warn(ctrl->device, "unknown csi %u for nsid %u\n",
+ /* enable char-interface for unknown command sets*/
+ if (!ret) {
+ nvme_alloc_ns(ctrl, nsid, &ids, indep_id);
+ break;
+ }
+ dev_warn(ctrl->device,
+ "unknown csi %u for nsid %u not supported\n",
ids.csi, nsid);
break;
}
+
+free_indep_id:
+ kfree(indep_id);
}
static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
--
2.30.2
More information about the Linux-nvme
mailing list