Print this page
MFV: illumos-gate@48d370f1e98a10b1bdf160dd83a49e0f49f6c1b7
9809 nvme driver should attach to all NVMe 1.x devices
9810 Update parts of NVMe headers for newer specs
9811 nvmeadm(1M) should have ctf
Reviewed by: Hans Rosenfeld <hans.rosenfeld@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Reviewed by: Andy Fiddaman <omnios@citrus-it.co.uk>
Approved by: Dan McDonald <danmcd@joyent.com>
Author: Robert Mustacchi <rm@joyent.com>
NEX-18067 Catch up with illumos 8806 8805
8806 xattr_dir_inactive() releases used vnode with kernel panic
Reviewed by: Marcel Telka <marcel@telka.sk>
Reviewed by: Gordon Ross <gordon.w.ross@gmail.com>
Approved by: Dan McDonald <danmcd@joyent.com>
8805 xattr_dir_lookup() can leak a vnode hold
Reviewed by: Marcel Telka <marcel@telka.sk>
Reviewed by: Gordon Ross <gordon.w.ross@gmail.com>
Approved by: Dan McDonald <danmcd@joyent.com>
NEX-17991 emulated NVMe controller on ESXi 6.7 fails to attach
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-16749 some NVMe controllers get upset about NS ID of 0 when checking "Error Recovery" feature
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-16880 update NVME code
8804 nvme: add alias for pciclass,010802
Reviewed by: Peter Tribble <peter.tribble@gmail.com>
Reviewed by: Michal Nowak <mnowak@startmail.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
8979 nvmeadm(1m): ctl/[ns] -> ctl[/ns]
Reviewed by: Yuri Pankov <yuripv@gmx.com>
Reviewed by: Rich Lowe <richlowe@richlowe.net>
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Dan McDonald <danmcd@joyent.com>
8945 nvme panics when async events are not supported
Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Reviewed by: Michal Nowak <mnowak@startmail.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
NEX-16549 nvme: "programming error: invalid NS/format" doing 'nvmeadm list' on a controller without namespaces
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-15208 nvme: Software Progress Marker feature is optional
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
NEX-8020 illumos nvme changes
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-7539 nvme fails to get error log page from Samsung PM1725
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-7538 nvme shouldn't ignore namespaces that support extended data LBAs
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-7373 nvme queue DMA attribute count_max is 0-based
Reviewed by: Gordon Ross <gordon.ross@nexenta.com
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-7369 bump nvme admin command timeout to 1s
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-6740 nvme checksum errors with blocksize < 4096
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-7349 nvme ignores interrupt enabling failure
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-7336 nvme initial interrupt issues
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-7322 nvme fix from Tegile needs a fix
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
NEX-7321 nvme version number check is broken again
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-7291 several small nvme fixes from Tegile
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-7290 nvme: id_nlbaf field is 0-based
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-7236 nvme shouldn't use ddi_intr_enable/disable to block interrupts
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com>
NEX-5192 Samsung SSD SM951-NVMe shows checksum errors
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-5792 support NVMe namespace EUI64
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-6132 nvmeadm(1M) get-feature command could use some cleanup
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-6130 basic NVMe 1.1 support
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-5791 support NVMe volatile write cache
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-4431 want NVMe management utility
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-4849 nvme version number check is broken
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Approved by: Robert Mustacchi <rm@joyent.com>
NEX-4850 off-by-one in nvme_get_logpage()
Reviewed by: Dan McDonald <danmcd@omniti.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Approved by: Robert Mustacchi <rm@joyent.com>
NEX-4427 blkdev should provide the device_error kstat for iostat -E
Reviewed by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
NEX-4424 kstat module needs cleanup
Reviewed by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
NEX-4420 format(1M) should be able to use device inquiry properties
Reviewed by: Dan McDonald <danmcd@omniti.com>
NEX-4419 blkdev and blkdev drivers should provide inquiry properties
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-2182 need driver for Intel NVM Express (nvme)
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
NEX-2182 need driver for Intel NVM Express (nvme) (preview)
Reviewed by: Dan Fields <dan.fields@nexenta.com>
        
*** 8,21 ****
   * source.  A copy of the CDDL is also available via the Internet at
   * http://www.illumos.org/license/CDDL.
   */
  
  /*
!  * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
   * Copyright 2016 Tegile Systems, Inc. All rights reserved.
   * Copyright (c) 2016 The MathWorks, Inc.  All rights reserved.
!  * Copyright 2017 Joyent, Inc.
   */
  
  /*
   * blkdev driver for NVMe compliant storage devices
   *
--- 8,21 ----
   * source.  A copy of the CDDL is also available via the Internet at
   * http://www.illumos.org/license/CDDL.
   */
  
  /*
!  * Copyright 2018 Nexenta Systems, Inc.
   * Copyright 2016 Tegile Systems, Inc. All rights reserved.
   * Copyright (c) 2016 The MathWorks, Inc.  All rights reserved.
!  * Copyright 2018 Joyent, Inc.
   */
  
  /*
   * blkdev driver for NVMe compliant storage devices
   *
*** 81,92 ****
   * Namespace Support:
   *
   * NVMe devices can have multiple namespaces, each being a independent data
   * store. The driver supports multiple namespaces and creates a blkdev interface
   * for each namespace found. Namespaces can have various attributes to support
!  * thin provisioning and protection information. This driver does not support
!  * any of this and ignores namespaces that have these attributes.
   *
   * As of NVMe 1.1 namespaces can have an 64bit Extended Unique Identifier
   * (EUI64). This driver uses the EUI64 if present to generate the devid and
   * passes it to blkdev to use it in the device node names. As this is currently
   * untested namespaces with EUI64 are ignored by default.
--- 81,92 ----
   * Namespace Support:
   *
   * NVMe devices can have multiple namespaces, each being a independent data
   * store. The driver supports multiple namespaces and creates a blkdev interface
   * for each namespace found. Namespaces can have various attributes to support
!  * protection information. This driver does not support any of this and ignores
!  * namespaces that have these attributes.
   *
   * As of NVMe 1.1 namespaces can have an 64bit Extended Unique Identifier
   * (EUI64). This driver uses the EUI64 if present to generate the devid and
   * passes it to blkdev to use it in the device node names. As this is currently
   * untested namespaces with EUI64 are ignored by default.
*** 194,204 ****
   * Driver Configuration:
   *
   * The following driver properties can be changed to control some aspects of the
   * drivers operation:
   * - strict-version: can be set to 0 to allow devices conforming to newer
!  *   versions or namespaces with EUI64 to be used
   * - ignore-unknown-vendor-status: can be set to 1 to not handle any vendor
   *   specific command status as a fatal error leading device faulting
   * - admin-queue-len: the maximum length of the admin queue (16-4096)
   * - io-queue-len: the maximum length of the I/O queues (16-65536)
   * - async-event-limit: the maximum number of asynchronous event requests to be
--- 194,204 ----
   * Driver Configuration:
   *
   * The following driver properties can be changed to control some aspects of the
   * drivers operation:
   * - strict-version: can be set to 0 to allow devices conforming to newer
!  *   major versions to be used
   * - ignore-unknown-vendor-status: can be set to 1 to not handle any vendor
   *   specific command status as a fatal error leading device faulting
   * - admin-queue-len: the maximum length of the admin queue (16-4096)
   * - io-queue-len: the maximum length of the I/O queues (16-65536)
   * - async-event-limit: the maximum number of asynchronous event requests to be
*** 256,269 ****
  #endif
  
  #include "nvme_reg.h"
  #include "nvme_var.h"
  
  
  /* NVMe spec version supported */
  static const int nvme_version_major = 1;
- static const int nvme_version_minor = 2;
  
  /* tunable for admin command timeout in seconds, default is 1s */
  int nvme_admin_cmd_timeout = 1;
  
  /* tunable for FORMAT NVM command timeout in seconds, default is 600s */
--- 256,290 ----
  #endif
  
  #include "nvme_reg.h"
  #include "nvme_var.h"
  
+ /*
+  * Assertions to make sure that we've properly captured various aspects of the
+  * packed structures and haven't broken them during updates.
+  */
+ CTASSERT(sizeof (nvme_identify_ctrl_t) == 0x1000);
+ CTASSERT(offsetof(nvme_identify_ctrl_t, id_oacs) == 256);
+ CTASSERT(offsetof(nvme_identify_ctrl_t, id_sqes) == 512);
+ CTASSERT(offsetof(nvme_identify_ctrl_t, id_subnqn) == 768);
+ CTASSERT(offsetof(nvme_identify_ctrl_t, id_nvmof) == 1792);
+ CTASSERT(offsetof(nvme_identify_ctrl_t, id_psd) == 2048);
+ CTASSERT(offsetof(nvme_identify_ctrl_t, id_vs) == 3072);
  
+ CTASSERT(sizeof (nvme_identify_nsid_t) == 0x1000);
+ CTASSERT(offsetof(nvme_identify_nsid_t, id_fpi) == 32);
+ CTASSERT(offsetof(nvme_identify_nsid_t, id_nguid) == 104);
+ CTASSERT(offsetof(nvme_identify_nsid_t, id_lbaf) == 128);
+ CTASSERT(offsetof(nvme_identify_nsid_t, id_vs) == 384);
+ 
+ CTASSERT(sizeof (nvme_identify_primary_caps_t) == 0x1000);
+ CTASSERT(offsetof(nvme_identify_primary_caps_t, nipc_vqfrt) == 32);
+ CTASSERT(offsetof(nvme_identify_primary_caps_t, nipc_vifrt) == 64);
+ 
+ 
  /* NVMe spec version supported */
  static const int nvme_version_major = 1;
  
  /* tunable for admin command timeout in seconds, default is 1s */
  int nvme_admin_cmd_timeout = 1;
  
  /* tunable for FORMAT NVM command timeout in seconds, default is 600s */
*** 1082,1092 ****
  
          case NVME_CQE_SC_GEN_INV_NS:
                  /* Invalid Namespace or Format */
                  if (!cmd->nc_dontpanic)
                          dev_err(cmd->nc_nvme->n_dip, CE_PANIC,
!                             "programming error: " "invalid NS/format in cmd %p",
                              (void *)cmd);
                  return (EINVAL);
  
          case NVME_CQE_SC_GEN_NVM_LBA_RANGE:
                  /* LBA Out Of Range */
--- 1103,1113 ----
  
          case NVME_CQE_SC_GEN_INV_NS:
                  /* Invalid Namespace or Format */
                  if (!cmd->nc_dontpanic)
                          dev_err(cmd->nc_nvme->n_dip, CE_PANIC,
!                             "programming error: invalid NS/format in cmd %p",
                              (void *)cmd);
                  return (EINVAL);
  
          case NVME_CQE_SC_GEN_NVM_LBA_RANGE:
                  /* LBA Out Of Range */
*** 1853,1896 ****
          cmd->nc_callback = nvme_wakeup_cmd;
          cmd->nc_sqe.sqe_opc = NVME_OPC_GET_FEATURES;
          cmd->nc_sqe.sqe_cdw10 = feature;
          cmd->nc_sqe.sqe_cdw11 = *res;
  
          switch (feature) {
          case NVME_FEAT_ARBITRATION:
          case NVME_FEAT_POWER_MGMT:
          case NVME_FEAT_TEMPERATURE:
-         case NVME_FEAT_ERROR:
          case NVME_FEAT_NQUEUES:
          case NVME_FEAT_INTR_COAL:
          case NVME_FEAT_INTR_VECT:
          case NVME_FEAT_WRITE_ATOM:
          case NVME_FEAT_ASYNC_EVENT:
-         case NVME_FEAT_PROGRESS:
                  break;
  
          case NVME_FEAT_WRITE_CACHE:
                  if (!nvme->n_write_cache_present)
                          goto fail;
                  break;
  
          case NVME_FEAT_LBA_RANGE:
                  if (!nvme->n_lba_range_supported)
                          goto fail;
  
-                 /*
-                  * The LBA Range Type feature is optional. There doesn't seem
-                  * be a method of detecting whether it is supported other than
-                  * using it. This will cause a "invalid field in command" error,
-                  * which is normally considered a programming error and causes
-                  * panic in nvme_check_generic_cmd_status().
-                  */
                  cmd->nc_dontpanic = B_TRUE;
                  cmd->nc_sqe.sqe_nsid = nsid;
                  ASSERT(bufsize != NULL);
                  *bufsize = NVME_LBA_RANGE_BUFSIZE;
- 
                  break;
  
          case NVME_FEAT_AUTO_PST:
                  if (!nvme->n_auto_pst_supported)
                          goto fail;
--- 1874,1926 ----
          cmd->nc_callback = nvme_wakeup_cmd;
          cmd->nc_sqe.sqe_opc = NVME_OPC_GET_FEATURES;
          cmd->nc_sqe.sqe_cdw10 = feature;
          cmd->nc_sqe.sqe_cdw11 = *res;
  
+         /*
+          * For some of the optional features there doesn't seem to be a method
+          * of detecting whether it is supported other than using it.  This will
+          * cause "Invalid Field in Command" error, which is normally considered
+          * a programming error.  Set the nc_dontpanic flag to override the panic
+          * in nvme_check_generic_cmd_status().
+          */
          switch (feature) {
          case NVME_FEAT_ARBITRATION:
          case NVME_FEAT_POWER_MGMT:
          case NVME_FEAT_TEMPERATURE:
          case NVME_FEAT_NQUEUES:
          case NVME_FEAT_INTR_COAL:
          case NVME_FEAT_INTR_VECT:
          case NVME_FEAT_WRITE_ATOM:
          case NVME_FEAT_ASYNC_EVENT:
                  break;
  
+         case NVME_FEAT_ERROR:
+                 /*
+                  * Per-namespace Deallocated or Unwritten Logical Block
+                  * Error Enable (DULBE) feature was added after initial NVMe
+                  * specification, but we currently only check this feature with
+                  * NS ID of 0 (the controller itself), and some controllers get
+                  * upset, reporting the error.  For the moment, override the
+                  * panic by setting the nc_dontpanic flag.
+                  */
+                 cmd->nc_dontpanic = B_TRUE;
+                 break;
+ 
          case NVME_FEAT_WRITE_CACHE:
                  if (!nvme->n_write_cache_present)
                          goto fail;
                  break;
  
          case NVME_FEAT_LBA_RANGE:
                  if (!nvme->n_lba_range_supported)
                          goto fail;
  
                  cmd->nc_dontpanic = B_TRUE;
                  cmd->nc_sqe.sqe_nsid = nsid;
                  ASSERT(bufsize != NULL);
                  *bufsize = NVME_LBA_RANGE_BUFSIZE;
                  break;
  
          case NVME_FEAT_AUTO_PST:
                  if (!nvme->n_auto_pst_supported)
                          goto fail;
*** 1897,1906 ****
--- 1927,1943 ----
  
                  ASSERT(bufsize != NULL);
                  *bufsize = NVME_AUTO_PST_BUFSIZE;
                  break;
  
+         case NVME_FEAT_PROGRESS:
+                 if (!nvme->n_progress_supported)
+                         goto fail;
+ 
+                 cmd->nc_dontpanic = B_TRUE;
+                 break;
+ 
          default:
                  goto fail;
          }
  
          if (bufsize != NULL && *bufsize != 0) {
*** 1931,1949 ****
          }
  
          nvme_admin_cmd(cmd, nvme_admin_cmd_timeout);
  
          if ((ret = nvme_check_cmd_status(cmd)) != 0) {
!                 if (feature == NVME_FEAT_LBA_RANGE &&
!                     cmd->nc_cqe.cqe_sf.sf_sct == NVME_CQE_SCT_GENERIC &&
!                     cmd->nc_cqe.cqe_sf.sf_sc == NVME_CQE_SC_GEN_INV_FLD)
                          nvme->n_lba_range_supported = B_FALSE;
!                 else
                          dev_err(nvme->n_dip, CE_WARN,
                              "!GET FEATURES %d failed with sct = %x, sc = %x",
                              feature, cmd->nc_cqe.cqe_sf.sf_sct,
                              cmd->nc_cqe.cqe_sf.sf_sc);
                  goto fail;
          }
  
          if (bufsize != NULL && *bufsize != 0) {
                  ASSERT(buf != NULL);
--- 1968,2005 ----
          }
  
          nvme_admin_cmd(cmd, nvme_admin_cmd_timeout);
  
          if ((ret = nvme_check_cmd_status(cmd)) != 0) {
!                 boolean_t known = B_TRUE;
! 
!                 /* Check if this is unsupported optional feature */
!                 if (cmd->nc_cqe.cqe_sf.sf_sct == NVME_CQE_SCT_GENERIC &&
!                     cmd->nc_cqe.cqe_sf.sf_sc == NVME_CQE_SC_GEN_INV_FLD) {
!                         switch (feature) {
!                         case NVME_FEAT_LBA_RANGE:
                                  nvme->n_lba_range_supported = B_FALSE;
!                                 break;
!                         case NVME_FEAT_PROGRESS:
!                                 nvme->n_progress_supported = B_FALSE;
!                                 break;
!                         default:
!                                 known = B_FALSE;
!                                 break;
!                         }
!                 } else {
!                         known = B_FALSE;
!                 }
! 
!                 /* Report the error otherwise */
!                 if (!known) {
                          dev_err(nvme->n_dip, CE_WARN,
                              "!GET FEATURES %d failed with sct = %x, sc = %x",
                              feature, cmd->nc_cqe.cqe_sf.sf_sct,
                              cmd->nc_cqe.cqe_sf.sf_sc);
+                 }
+ 
                  goto fail;
          }
  
          if (bufsize != NULL && *bufsize != 0) {
                  ASSERT(buf != NULL);
*** 2197,2216 ****
          if (ns->ns_best_block_size < nvme->n_min_block_size)
                  ns->ns_best_block_size = nvme->n_min_block_size;
  
          /*
           * We currently don't support namespaces that use either:
-          * - thin provisioning
           * - protection information
           * - illegal block size (< 512)
           */
!         if (idns->id_nsfeat.f_thin ||
!             idns->id_dps.dp_pinfo) {
                  dev_err(nvme->n_dip, CE_WARN,
!                     "!ignoring namespace %d, unsupported features: "
!                     "thin = %d, pinfo = %d", nsid,
!                     idns->id_nsfeat.f_thin, idns->id_dps.dp_pinfo);
                  ns->ns_ignore = B_TRUE;
          } else if (ns->ns_block_size < 512) {
                  dev_err(nvme->n_dip, CE_WARN,
                      "!ignoring namespace %d, unsupported block size %"PRIu64,
                      nsid, (uint64_t)ns->ns_block_size);
--- 2253,2269 ----
          if (ns->ns_best_block_size < nvme->n_min_block_size)
                  ns->ns_best_block_size = nvme->n_min_block_size;
  
          /*
           * We currently don't support namespaces that use either:
           * - protection information
           * - illegal block size (< 512)
           */
!         if (idns->id_dps.dp_pinfo) {
                  dev_err(nvme->n_dip, CE_WARN,
!                     "!ignoring namespace %d, unsupported feature: "
!                     "pinfo = %d", nsid, idns->id_dps.dp_pinfo);
                  ns->ns_ignore = B_TRUE;
          } else if (ns->ns_block_size < 512) {
                  dev_err(nvme->n_dip, CE_WARN,
                      "!ignoring namespace %d, unsupported block size %"PRIu64,
                      nsid, (uint64_t)ns->ns_block_size);
*** 2242,2255 ****
          nvme->n_version.v_major = vs.b.vs_mjr;
          nvme->n_version.v_minor = vs.b.vs_mnr;
          dev_err(nvme->n_dip, CE_CONT, "?NVMe spec version %d.%d",
              nvme->n_version.v_major, nvme->n_version.v_minor);
  
!         if (NVME_VERSION_HIGHER(&nvme->n_version,
!             nvme_version_major, nvme_version_minor)) {
!                 dev_err(nvme->n_dip, CE_WARN, "!no support for version > %d.%d",
!                     nvme_version_major, nvme_version_minor);
                  if (nvme->n_strict_version)
                          goto fail;
          }
  
          /* retrieve controller configuration */
--- 2295,2307 ----
          nvme->n_version.v_major = vs.b.vs_mjr;
          nvme->n_version.v_minor = vs.b.vs_mnr;
          dev_err(nvme->n_dip, CE_CONT, "?NVMe spec version %d.%d",
              nvme->n_version.v_major, nvme->n_version.v_minor);
  
!         if (nvme->n_version.v_major > nvme_version_major) {
!                 dev_err(nvme->n_dip, CE_WARN, "!no support for version > %d.x",
!                     nvme_version_major);
                  if (nvme->n_strict_version)
                          goto fail;
          }
  
          /* retrieve controller configuration */
*** 2519,2531 ****
--- 2571,2596 ----
          if (NVME_VERSION_ATLEAST(&nvme->n_version, 1, 1))
                  nvme->n_auto_pst_supported =
                      nvme->n_idctl->id_apsta.ap_sup == 0 ? B_FALSE : B_TRUE;
  
          /*
+          * Assume Software Progress Marker feature is supported.  If it isn't
+          * this will be set to B_FALSE by nvme_get_features().
+          */
+         nvme->n_progress_supported = B_TRUE;
+ 
+         /*
           * Identify Namespaces
           */
          nvme->n_namespace_count = nvme->n_idctl->id_nn;
+ 
+         if (nvme->n_namespace_count == 0) {
+                 dev_err(nvme->n_dip, CE_WARN,
+                     "!controllers without namespaces are not supported");
+                 goto fail;
+         }
+ 
          if (nvme->n_namespace_count > NVME_MINOR_MAX) {
                  dev_err(nvme->n_dip, CE_WARN,
                      "!too many namespaces: %d, limiting to %d\n",
                      nvme->n_namespace_count, NVME_MINOR_MAX);
                  nvme->n_namespace_count = NVME_MINOR_MAX;