[PATCH 1/2] nvme: Add 'partial_nid' quirk

hare at kernel.org hare at kernel.org
Mon Apr 14 02:09:58 PDT 2025


From: Hannes Reinecke <hare at kernel.org>

Add a quirk to handle NVMe devices for which not all NID values are unique,
and return a match from nvme_subsys_check_duplicate_ids() once the first
matching NID value is found.

Signed-off-by: Hannes Reinecke <hare at kernel.org>
---
 drivers/nvme/host/core.c | 28 ++++++++++++++++++++++------
 drivers/nvme/host/nvme.h |  5 +++++
 2 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 870314c52107..9e6f4037f33f 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -3576,18 +3576,30 @@ static int nvme_subsys_check_duplicate_ids(struct nvme_subsystem *subsys,
 	bool has_nguid = memchr_inv(ids->nguid, 0, sizeof(ids->nguid));
 	bool has_eui64 = memchr_inv(ids->eui64, 0, sizeof(ids->eui64));
 	struct nvme_ns_head *h;
+	bool match_nid = false;
 
 	lockdep_assert_held(&subsys->lock);
 
 	list_for_each_entry(h, &subsys->nsheads, entry) {
-		if (has_uuid && uuid_equal(&ids->uuid, &h->ids.uuid))
-			return -EINVAL;
-		if (has_nguid &&
-		    memcmp(&ids->nguid, &h->ids.nguid, sizeof(ids->nguid)) == 0)
-			return -EINVAL;
+		if (has_uuid) {
+			if (uuid_equal(&ids->uuid, &h->ids.uuid))
+				return -EINVAL;
+			match_nid = true;
+		}
+		if (has_nguid) {
+			if (memcmp(&ids->nguid, &h->ids.nguid, sizeof(ids->nguid)) == 0) {
+				if (match_nid)
+					return -ENOTUNIQ;
+				return -EINVAL;
+			}
+			match_nid = true;
+		}
 		if (has_eui64 &&
-		    memcmp(&ids->eui64, &h->ids.eui64, sizeof(ids->eui64)) == 0)
+		    memcmp(&ids->eui64, &h->ids.eui64, sizeof(ids->eui64)) == 0) {
+			if (match_nid)
+				return -ENOTUNIQ;
 			return -EINVAL;
+		}
 	}
 
 	return 0;
@@ -3752,6 +3764,8 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
 	int ret;
 
 	ret = nvme_global_check_duplicate_ids(ctrl->subsys, &info->ids);
+	if (ret == -ENOTUNIQ && ctrl->quirks & NVME_QUIRK_PARTIAL_NID)
+		ret = 0;
 	if (ret) {
 		/*
 		 * We've found two different namespaces on two different
@@ -3793,6 +3807,8 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
 	head = nvme_find_ns_head(ctrl, info->nsid);
 	if (!head) {
 		ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, &info->ids);
+		if (ret == -ENOTUNIQ && ctrl->quirks & NVME_QUIRK_PARTIAL_NID)
+			ret = 0;
 		if (ret) {
 			dev_err(ctrl->device,
 				"duplicate IDs in subsystem for nsid %d\n",
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 740ec758712f..8b386fcffa01 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -178,6 +178,11 @@ enum nvme_quirks {
 	 * Align dma pool segment size to 512 bytes
 	 */
 	NVME_QUIRK_DMAPOOL_ALIGN_512		= (1 << 22),
+
+	/*
+	 * Not all namespace identifiers are unique
+	 */
+	NVME_QUIRK_PARTIAL_NID			= (1 << 23),
 };
 
 /*
-- 
2.35.3




More information about the Linux-nvme mailing list