[SeaBIOS] [PATCH 1/5] nvme: support NVMe 1.0 controllers

Daniel Verkamp daniel at drv.nu
Fri Feb 24 07:27:53 CET 2017


Rather than using the Identify command with CNS 01b (GET_NS_LIST), which
was added in NVMe 1.1, we can just enumerate all of the possible
namespace IDs.

The relevant part of the NVMe spec reads:

  Namespaces shall be allocated in order (starting with 1) and packed
  sequentially.

Since the previously-used GET_NS_LIST only returns active namespaces, we
also need a check in nvme_probe_ns() to ensure that inactive namespaces
are not reported as boot devices.  This can be accomplished by checking
for non-zero block count - the spec indicates that Identify Namespace
for an inactive namespace ID will return all zeroes.

This should have no impact on the QEMU NVMe device model, since it
always reports exactly one namespace (NSID 1).

Signed-off-by: Daniel Verkamp <daniel at drv.nu>
---
 src/hw/nvme.c | 39 ++++++---------------------------------
 1 file changed, 6 insertions(+), 33 deletions(-)

diff --git a/src/hw/nvme.c b/src/hw/nvme.c
index 31edf29..c709a3a 100644
--- a/src/hw/nvme.c
+++ b/src/hw/nvme.c
@@ -218,13 +218,6 @@ nvme_admin_identify_ctrl(struct nvme_ctrl *ctrl)
     return &nvme_admin_identify(ctrl, NVME_ADMIN_IDENTIFY_CNS_ID_CTRL, 0)->ctrl;
 }
 
-static struct nvme_identify_ns_list *
-nvme_admin_identify_get_ns_list(struct nvme_ctrl *ctrl)
-{
-    return &nvme_admin_identify(ctrl, NVME_ADMIN_IDENTIFY_CNS_GET_NS_LIST,
-                                0)->ns_list;
-}
-
 static struct nvme_identify_ns *
 nvme_admin_identify_ns(struct nvme_ctrl *ctrl, u32 ns_id)
 {
@@ -253,6 +246,10 @@ nvme_probe_ns(struct nvme_ctrl *ctrl, struct nvme_namespace *ns, u32 ns_id)
     }
 
     ns->lba_count = id->nsze;
+    if (!ns->lba_count) {
+        dprintf(2, "NVMe NS %u is inactive.\n", ns_id);
+        goto free_buffer;
+    }
 
     struct nvme_lba_format *fmt = &id->lbaf[current_lba_format];
 
@@ -493,29 +490,10 @@ nvme_controller_enable(struct nvme_ctrl *ctrl)
     if (!ctrl->ns) goto out_of_memory;
     memset(ctrl->ns, 0, sizeof(*ctrl->ns) * ctrl->ns_count);
 
-    struct nvme_identify_ns_list *ns_list = nvme_admin_identify_get_ns_list(ctrl);
-    if (!ns_list) {
-        dprintf(2, "NVMe couldn't get namespace list.\n");
-        goto failed;
-    }
-
     /* Populate namespace IDs */
     int ns_idx;
-    for (ns_idx = 0;
-         ns_idx < ARRAY_SIZE(ns_list->ns_id)
-             && ns_idx < ctrl->ns_count
-             && ns_list->ns_id[ns_idx];
-         ns_idx++) {
-        nvme_probe_ns(ctrl, &ctrl->ns[ns_idx], ns_list->ns_id[ns_idx]);
-    }
-
-    free(ns_list);
-
-    /* If for some reason the namespace list gives us fewer namespaces, we just
-       go along. */
-    if (ns_idx != ctrl->ns_count) {
-        dprintf(2, "NVMe namespace list has only %u namespaces?\n", ns_idx);
-        ctrl->ns_count = ns_idx;
+    for (ns_idx = 0; ns_idx < ctrl->ns_count; ns_idx++) {
+        nvme_probe_ns(ctrl, &ctrl->ns[ns_idx], ns_idx + 1);
     }
 
     dprintf(3, "NVMe initialization complete!\n");
@@ -545,11 +523,6 @@ nvme_controller_setup(void *opaque)
             version >> 16, (version >> 8) & 0xFF, version & 0xFF);
     dprintf(3, "  Capabilities %016llx\n", reg->cap);
 
-    if (version < 0x00010100U) {
-        dprintf(3, "Need at least 1.1.0! Skipping.\n");
-        return;
-    }
-
     if (~reg->cap & NVME_CAP_CSS_NVME) {
         dprintf(3, "Controller doesn't speak NVMe command set. Skipping.\n");
         return;
-- 
2.11.1




More information about the SeaBIOS mailing list