]> xenbits.xensource.com Git - seabios.git/commitdiff
nvme: support NVMe 1.0 controllers
authorDaniel Verkamp <daniel@drv.nu>
Fri, 24 Feb 2017 06:27:53 +0000 (23:27 -0700)
committerKevin O'Connor <kevin@koconnor.net>
Thu, 2 Mar 2017 14:45:45 +0000 (09:45 -0500)
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@drv.nu>
src/hw/nvme.c

index 31edf29220088c1f3e1766d8a1729dcce875ce8f..c709a3ae1b26611c5a70ab60848da76fc5fa1c2e 100644 (file)
@@ -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;