qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] hw/block/nvme: add administrative controller support
@ 2021-03-11  6:38 Klaus Jensen
  2021-03-11  6:38 ` [PATCH 1/3] hw/block/nvme: add oncs device parameter Klaus Jensen
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Klaus Jensen @ 2021-03-11  6:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fam Zheng, Kevin Wolf, qemu-block, Klaus Jensen, Max Reitz,
	Klaus Jensen, Stefan Hajnoczi, Keith Busch

From: Klaus Jensen <k.jensen@samsung.com>

This series allows the controller to behave as an Administrative
Controller. This is useful when emulating a subsystem.

Since some commands are prohibited for an Administrative Controller,
this series includes patches that make the CSE log page dynamic and
allows supported features and commands to be fine-tuned with the new
'oncs' and 'oacs' parameters. By default, the device supports as much as
possible.

Gollu Appalanaidu (2):
  hw/block/nvme: add oncs device parameter
  hw/block/nvme: add oacs device parameter

Padmakar Kalghatgi (1):
  hw/block/nvme: add administrative controller type

 hw/block/nvme.h        |  11 +++
 include/block/nvme.h   |   8 ++
 hw/block/nvme-subsys.c |   6 +-
 hw/block/nvme.c        | 193 +++++++++++++++++++++++++++++------------
 4 files changed, 162 insertions(+), 56 deletions(-)

-- 
2.30.1



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] hw/block/nvme: add oncs device parameter
  2021-03-11  6:38 [PATCH 0/3] hw/block/nvme: add administrative controller support Klaus Jensen
@ 2021-03-11  6:38 ` Klaus Jensen
  2021-03-11  6:38 ` [PATCH 2/3] hw/block/nvme: add oacs " Klaus Jensen
  2021-03-11  6:38 ` [PATCH 3/3] hw/block/nvme: add administrative controller type Klaus Jensen
  2 siblings, 0 replies; 4+ messages in thread
From: Klaus Jensen @ 2021-03-11  6:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fam Zheng, Kevin Wolf, qemu-block, Klaus Jensen,
	Gollu Appalanaidu, Max Reitz, Klaus Jensen, Stefan Hajnoczi,
	Keith Busch

From: Gollu Appalanaidu <anaidu.gollu@samsung.com>

Add the 'oncs' nvme device parameter to allow optional features to be
enabled/disabled explicitly. Since most of these are optional commands,
make the CSE log pages dynamic to account for the value of ONCS.

Signed-off-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
 hw/block/nvme.h |   7 ++++
 hw/block/nvme.c | 101 ++++++++++++++++++++++++++++++++----------------
 2 files changed, 74 insertions(+), 34 deletions(-)

diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 4955d649c7d4..65c80cfaef62 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -9,6 +9,7 @@
 
 #define NVME_DEFAULT_ZONE_SIZE   (128 * MiB)
 #define NVME_DEFAULT_MAX_ZA_SIZE (128 * KiB)
+#define NVME_MAX_COMMANDS 0x100
 
 /*
  * Subsystem namespace list for allocated namespaces should be larger than
@@ -28,6 +29,7 @@ typedef struct NvmeParams {
     bool     use_intel_id;
     uint8_t  zasl;
     bool     legacy_cmb;
+    uint16_t oncs;
 } NvmeParams;
 
 typedef struct NvmeAsyncEvent {
@@ -210,6 +212,11 @@ typedef struct NvmeCtrl {
     NvmeCQueue      admin_cq;
     NvmeIdCtrl      id_ctrl;
     NvmeFeatureVal  features;
+
+    struct {
+        uint32_t nvm[NVME_MAX_COMMANDS];
+        uint32_t zoned[NVME_MAX_COMMANDS];
+    } iocs;
 } NvmeCtrl;
 
 static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index d439e44db839..fbb578a6e669 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -84,6 +84,11 @@
  *   the minimum memory page size (CAP.MPSMIN). The default value is 0 (i.e.
  *   defaulting to the value of `mdts`).
  *
+ * - `oncs`
+ *   This field indicates the optional NVM commands and features supported
+ *   by the controller. To add support for the optional feature, needs to
+ *   set the corresponding support indicated bit.
+ *
  * nvme namespace device parameters
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  * - `subsys`
@@ -185,7 +190,7 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = {
     [NVME_TIMESTAMP]                = NVME_FEAT_CAP_CHANGE,
 };
 
-static const uint32_t nvme_cse_acs[256] = {
+static const uint32_t nvme_cse_acs[NVME_MAX_COMMANDS] = {
     [NVME_ADM_CMD_DELETE_SQ]        = NVME_CMD_EFF_CSUPP,
     [NVME_ADM_CMD_CREATE_SQ]        = NVME_CMD_EFF_CSUPP,
     [NVME_ADM_CMD_GET_LOG_PAGE]     = NVME_CMD_EFF_CSUPP,
@@ -199,30 +204,7 @@ static const uint32_t nvme_cse_acs[256] = {
     [NVME_ADM_CMD_NS_ATTACHMENT]    = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC,
 };
 
-static const uint32_t nvme_cse_iocs_none[256];
-
-static const uint32_t nvme_cse_iocs_nvm[256] = {
-    [NVME_CMD_FLUSH]                = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_WRITE_ZEROES]         = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_WRITE]                = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_READ]                 = NVME_CMD_EFF_CSUPP,
-    [NVME_CMD_DSM]                  = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_COPY]                 = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_COMPARE]              = NVME_CMD_EFF_CSUPP,
-};
-
-static const uint32_t nvme_cse_iocs_zoned[256] = {
-    [NVME_CMD_FLUSH]                = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_WRITE_ZEROES]         = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_WRITE]                = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_READ]                 = NVME_CMD_EFF_CSUPP,
-    [NVME_CMD_DSM]                  = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_COPY]                 = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_COMPARE]              = NVME_CMD_EFF_CSUPP,
-    [NVME_CMD_ZONE_APPEND]          = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_ZONE_MGMT_SEND]       = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
-    [NVME_CMD_ZONE_MGMT_RECV]       = NVME_CMD_EFF_CSUPP,
-};
+static const uint32_t nvme_cse_iocs_none[NVME_MAX_COMMANDS];
 
 static void nvme_process_sq(void *opaque);
 
@@ -3071,17 +3053,17 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
 
     switch (NVME_CC_CSS(n->bar.cc)) {
     case NVME_CC_CSS_NVM:
-        src_iocs = nvme_cse_iocs_nvm;
+        src_iocs = n->iocs.nvm;
         /* fall through */
     case NVME_CC_CSS_ADMIN_ONLY:
         break;
     case NVME_CC_CSS_CSI:
         switch (csi) {
         case NVME_CSI_NVM:
-            src_iocs = nvme_cse_iocs_nvm;
+            src_iocs = n->iocs.nvm;
             break;
         case NVME_CSI_ZONED:
-            src_iocs = nvme_cse_iocs_zoned;
+            src_iocs = n->iocs.zoned;
             break;
         }
     }
@@ -3684,6 +3666,10 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req)
         return NVME_INVALID_FIELD | NVME_DNR;
     }
 
+    if (!(le16_to_cpu(n->id_ctrl.oncs) & NVME_ONCS_FEATURES) && sel) {
+        return NVME_INVALID_FIELD | NVME_DNR;
+    }
+
     if (nvme_feature_cap[fid] & NVME_FEAT_CAP_NS) {
         if (!nvme_nsid_valid(n, nsid) || nsid == NVME_NSID_BROADCAST) {
             /*
@@ -3766,6 +3752,9 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req)
         result = n->features.async_config;
         goto out;
     case NVME_TIMESTAMP:
+        if (!(le16_to_cpu(n->id_ctrl.oncs) & NVME_ONCS_TIMESTAMP)) {
+            return NVME_INVALID_FIELD | NVME_DNR;
+        }
         return nvme_get_feature_timestamp(n, req);
     default:
         break;
@@ -3843,6 +3832,10 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
 
     trace_pci_nvme_setfeat(nvme_cid(req), nsid, fid, save, dw11);
 
+    if (save && !(le16_to_cpu(n->id_ctrl.oncs) & NVME_ONCS_FEATURES)) {
+        return NVME_INVALID_FIELD | NVME_DNR;
+    }
+
     if (save && !(nvme_feature_cap[fid] & NVME_FEAT_CAP_SAVE)) {
         return NVME_FID_NOT_SAVEABLE | NVME_DNR;
     }
@@ -3959,6 +3952,9 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
         n->features.async_config = dw11;
         break;
     case NVME_TIMESTAMP:
+        if (!(le16_to_cpu(n->id_ctrl.oncs) & NVME_ONCS_TIMESTAMP)) {
+            return NVME_INVALID_FIELD | NVME_DNR;
+        }
         return nvme_set_feature_timestamp(n, req);
     case NVME_COMMAND_SET_PROFILE:
         if (dw11 & 0x1ff) {
@@ -4201,14 +4197,14 @@ static void __nvme_select_ns_iocs(NvmeCtrl *n, NvmeNamespace *ns)
     switch (ns->csi) {
     case NVME_CSI_NVM:
         if (NVME_CC_CSS(n->bar.cc) != NVME_CC_CSS_ADMIN_ONLY) {
-            ns->iocs = nvme_cse_iocs_nvm;
+            ns->iocs = n->iocs.nvm;
         }
         break;
     case NVME_CSI_ZONED:
         if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_CSI) {
-            ns->iocs = nvme_cse_iocs_zoned;
+            ns->iocs = n->iocs.zoned;
         } else if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_NVM) {
-            ns->iocs = nvme_cse_iocs_nvm;
+            ns->iocs = n->iocs.nvm;
         }
         break;
     }
@@ -4838,6 +4834,40 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp)
     }
 }
 
+static void nvme_init_cse_iocs(NvmeCtrl *n)
+{
+    uint16_t oncs = n->params.oncs;
+
+    n->iocs.nvm[NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
+    n->iocs.nvm[NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
+    n->iocs.nvm[NVME_CMD_READ]  = NVME_CMD_EFF_CSUPP;
+
+    if (oncs & NVME_ONCS_WRITE_ZEROES) {
+        n->iocs.nvm[NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP |
+            NVME_CMD_EFF_LBCC;
+    }
+
+    if (oncs & NVME_ONCS_COMPARE) {
+        n->iocs.nvm[NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP;
+    }
+
+    if (oncs & NVME_ONCS_DSM) {
+        n->iocs.nvm[NVME_CMD_DSM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
+    }
+
+    if (oncs & NVME_ONCS_COPY) {
+        n->iocs.nvm[NVME_CMD_COPY] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
+    }
+
+    memcpy(n->iocs.zoned, n->iocs.nvm, sizeof(n->iocs.nvm));
+
+    n->iocs.zoned[NVME_CMD_ZONE_APPEND] = NVME_CMD_EFF_CSUPP |
+        NVME_CMD_EFF_LBCC;
+    n->iocs.zoned[NVME_CMD_ZONE_MGMT_SEND] = NVME_CMD_EFF_CSUPP |
+        NVME_CMD_EFF_LBCC;
+    n->iocs.zoned[NVME_CMD_ZONE_MGMT_RECV] = NVME_CMD_EFF_CSUPP;
+}
+
 static void nvme_init_state(NvmeCtrl *n)
 {
     n->num_namespaces = NVME_MAX_NAMESPACES;
@@ -4850,6 +4880,8 @@ static void nvme_init_state(NvmeCtrl *n)
     n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING;
     n->starttime_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
     n->aer_reqs = g_new0(NvmeRequest *, n->params.aerl + 1);
+
+    nvme_init_cse_iocs(n);
 }
 
 static int nvme_attach_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
@@ -5091,9 +5123,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
     id->sqes = (0x6 << 4) | 0x6;
     id->cqes = (0x4 << 4) | 0x4;
     id->nn = cpu_to_le32(n->num_namespaces);
-    id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP |
-                           NVME_ONCS_FEATURES | NVME_ONCS_DSM |
-                           NVME_ONCS_COMPARE | NVME_ONCS_COPY);
+    id->oncs = cpu_to_le16(n->params.oncs);
 
     /*
      * NOTE: If this device ever supports a command set that does NOT use 0x0
@@ -5239,6 +5269,9 @@ static Property nvme_props[] = {
     DEFINE_PROP_BOOL("use-intel-id", NvmeCtrl, params.use_intel_id, false),
     DEFINE_PROP_BOOL("legacy-cmb", NvmeCtrl, params.legacy_cmb, false),
     DEFINE_PROP_UINT8("zoned.zasl", NvmeCtrl, params.zasl, 0),
+    DEFINE_PROP_UINT16("oncs", NvmeCtrl, params.oncs, NVME_ONCS_WRITE_ZEROES |
+                       NVME_ONCS_TIMESTAMP | NVME_ONCS_DSM |
+                       NVME_ONCS_COMPARE | NVME_ONCS_FEATURES | NVME_ONCS_COPY),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-- 
2.30.1



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] hw/block/nvme: add oacs device parameter
  2021-03-11  6:38 [PATCH 0/3] hw/block/nvme: add administrative controller support Klaus Jensen
  2021-03-11  6:38 ` [PATCH 1/3] hw/block/nvme: add oncs device parameter Klaus Jensen
@ 2021-03-11  6:38 ` Klaus Jensen
  2021-03-11  6:38 ` [PATCH 3/3] hw/block/nvme: add administrative controller type Klaus Jensen
  2 siblings, 0 replies; 4+ messages in thread
From: Klaus Jensen @ 2021-03-11  6:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fam Zheng, Kevin Wolf, qemu-block, Gollu Appalanaidu, Max Reitz,
	Klaus Jensen, Stefan Hajnoczi, Keith Busch

From: Gollu Appalanaidu <anaidu.gollu@samsung.com>

Add the 'oacs' nvme device parameter to allow optional features to be
enabled/disabled explicitly. Since most of these are optional commands,
make the CSE log pages dynamic to account for the value of OACS once the
optional commands supported added to device.

Signed-off-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
---
 hw/block/nvme.h |  3 +++
 hw/block/nvme.c | 46 +++++++++++++++++++++++++++++-----------------
 2 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 65c80cfaef62..cebe6018a234 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -30,6 +30,7 @@ typedef struct NvmeParams {
     uint8_t  zasl;
     bool     legacy_cmb;
     uint16_t oncs;
+    uint16_t oacs;
 } NvmeParams;
 
 typedef struct NvmeAsyncEvent {
@@ -213,6 +214,8 @@ typedef struct NvmeCtrl {
     NvmeIdCtrl      id_ctrl;
     NvmeFeatureVal  features;
 
+    uint32_t acs[NVME_MAX_COMMANDS];
+
     struct {
         uint32_t nvm[NVME_MAX_COMMANDS];
         uint32_t zoned[NVME_MAX_COMMANDS];
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index fbb578a6e669..8b8be3b5f121 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -89,6 +89,11 @@
  *   by the controller. To add support for the optional feature, needs to
  *   set the corresponding support indicated bit.
  *
+ * - `oacs`
+ *   This field indicates the optional Admin commands and features supported
+ *   by the controller. To add support for the optional feature, needs to
+ *   set the corresponding support indicated bit.
+ *
  * nvme namespace device parameters
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  * - `subsys`
@@ -190,20 +195,6 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = {
     [NVME_TIMESTAMP]                = NVME_FEAT_CAP_CHANGE,
 };
 
-static const uint32_t nvme_cse_acs[NVME_MAX_COMMANDS] = {
-    [NVME_ADM_CMD_DELETE_SQ]        = NVME_CMD_EFF_CSUPP,
-    [NVME_ADM_CMD_CREATE_SQ]        = NVME_CMD_EFF_CSUPP,
-    [NVME_ADM_CMD_GET_LOG_PAGE]     = NVME_CMD_EFF_CSUPP,
-    [NVME_ADM_CMD_DELETE_CQ]        = NVME_CMD_EFF_CSUPP,
-    [NVME_ADM_CMD_CREATE_CQ]        = NVME_CMD_EFF_CSUPP,
-    [NVME_ADM_CMD_IDENTIFY]         = NVME_CMD_EFF_CSUPP,
-    [NVME_ADM_CMD_ABORT]            = NVME_CMD_EFF_CSUPP,
-    [NVME_ADM_CMD_SET_FEATURES]     = NVME_CMD_EFF_CSUPP,
-    [NVME_ADM_CMD_GET_FEATURES]     = NVME_CMD_EFF_CSUPP,
-    [NVME_ADM_CMD_ASYNC_EV_REQ]     = NVME_CMD_EFF_CSUPP,
-    [NVME_ADM_CMD_NS_ATTACHMENT]    = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC,
-};
-
 static const uint32_t nvme_cse_iocs_none[NVME_MAX_COMMANDS];
 
 static void nvme_process_sq(void *opaque);
@@ -3068,7 +3059,7 @@ static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint8_t csi, uint32_t buf_len,
         }
     }
 
-    memcpy(log.acs, nvme_cse_acs, sizeof(nvme_cse_acs));
+    memcpy(log.acs, n->acs, sizeof(n->acs));
 
     if (src_iocs) {
         memcpy(log.iocs, src_iocs, sizeof(log.iocs));
@@ -4057,7 +4048,7 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req)
     trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), req->cmd.opcode,
                              nvme_adm_opc_str(req->cmd.opcode));
 
-    if (!(nvme_cse_acs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
+    if (!(n->acs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
         trace_pci_nvme_err_invalid_admin_opc(req->cmd.opcode);
         return NVME_INVALID_OPCODE | NVME_DNR;
     }
@@ -4868,6 +4859,25 @@ static void nvme_init_cse_iocs(NvmeCtrl *n)
     n->iocs.zoned[NVME_CMD_ZONE_MGMT_RECV] = NVME_CMD_EFF_CSUPP;
 }
 
+static void nvme_init_cse_acs(NvmeCtrl *n)
+{
+    n->acs[NVME_ADM_CMD_DELETE_SQ] = NVME_CMD_EFF_CSUPP;
+    n->acs[NVME_ADM_CMD_CREATE_SQ] = NVME_CMD_EFF_CSUPP;
+    n->acs[NVME_ADM_CMD_GET_LOG_PAGE] = NVME_CMD_EFF_CSUPP;
+    n->acs[NVME_ADM_CMD_DELETE_CQ] = NVME_CMD_EFF_CSUPP;
+    n->acs[NVME_ADM_CMD_CREATE_CQ] = NVME_CMD_EFF_CSUPP;
+    n->acs[NVME_ADM_CMD_IDENTIFY] = NVME_CMD_EFF_CSUPP;
+    n->acs[NVME_ADM_CMD_ABORT] = NVME_CMD_EFF_CSUPP;
+    n->acs[NVME_ADM_CMD_SET_FEATURES] = NVME_CMD_EFF_CSUPP;
+    n->acs[NVME_ADM_CMD_GET_FEATURES] = NVME_CMD_EFF_CSUPP;
+    n->acs[NVME_ADM_CMD_ASYNC_EV_REQ] = NVME_CMD_EFF_CSUPP;
+
+    if (n->params.oacs & NVME_OACS_NS_MGMT) {
+        n->acs[NVME_ADM_CMD_NS_ATTACHMENT] =
+            NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_NIC;
+    }
+}
+
 static void nvme_init_state(NvmeCtrl *n)
 {
     n->num_namespaces = NVME_MAX_NAMESPACES;
@@ -4881,6 +4891,7 @@ static void nvme_init_state(NvmeCtrl *n)
     n->starttime_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
     n->aer_reqs = g_new0(NvmeRequest *, n->params.aerl + 1);
 
+    nvme_init_cse_acs(n);
     nvme_init_cse_iocs(n);
 }
 
@@ -5097,7 +5108,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
 
     id->mdts = n->params.mdts;
     id->ver = cpu_to_le32(NVME_SPEC_VER);
-    id->oacs = cpu_to_le16(NVME_OACS_NS_MGMT);
+    id->oacs = cpu_to_le16(n->params.oacs);
     id->cntrltype = 0x1;
 
     /*
@@ -5272,6 +5283,7 @@ static Property nvme_props[] = {
     DEFINE_PROP_UINT16("oncs", NvmeCtrl, params.oncs, NVME_ONCS_WRITE_ZEROES |
                        NVME_ONCS_TIMESTAMP | NVME_ONCS_DSM |
                        NVME_ONCS_COMPARE | NVME_ONCS_FEATURES | NVME_ONCS_COPY),
+    DEFINE_PROP_UINT16("oacs", NvmeCtrl, params.oacs, NVME_OACS_NS_MGMT),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-- 
2.30.1



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] hw/block/nvme: add administrative controller type
  2021-03-11  6:38 [PATCH 0/3] hw/block/nvme: add administrative controller support Klaus Jensen
  2021-03-11  6:38 ` [PATCH 1/3] hw/block/nvme: add oncs device parameter Klaus Jensen
  2021-03-11  6:38 ` [PATCH 2/3] hw/block/nvme: add oacs " Klaus Jensen
@ 2021-03-11  6:38 ` Klaus Jensen
  2 siblings, 0 replies; 4+ messages in thread
From: Klaus Jensen @ 2021-03-11  6:38 UTC (permalink / raw)
  To: qemu-devel
  Cc: Fam Zheng, Kevin Wolf, Padmakar Kalghatgi, qemu-block,
	Klaus Jensen, Gollu Appalanaidu, Max Reitz, Klaus Jensen,
	Stefan Hajnoczi, Keith Busch

From: Padmakar Kalghatgi <p.kalghatgi@samsung.com>

Add the 'administrative' nvme device parameter. This causes the
controller to behave as an Administrative Controller.

See NVM Express v1.4b, Section 7.1.2 ("Administrative Controller").

Signed-off-by: Padmakar Kalghatgi <p.kalghatgi@samsung.com>
Signed-off-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
 hw/block/nvme.h        |  1 +
 include/block/nvme.h   |  8 ++++
 hw/block/nvme-subsys.c |  6 ++-
 hw/block/nvme.c        | 86 ++++++++++++++++++++++++++++++------------
 4 files changed, 76 insertions(+), 25 deletions(-)

diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index cebe6018a234..364edb82b60e 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -31,6 +31,7 @@ typedef struct NvmeParams {
     bool     legacy_cmb;
     uint16_t oncs;
     uint16_t oacs;
+    bool     administrative;
 } NvmeParams;
 
 typedef struct NvmeAsyncEvent {
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 372d0f2799fb..907cd5a9cf62 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -586,6 +586,11 @@ enum NvmeIoCommands {
     NVME_CMD_ZONE_APPEND        = 0x7d,
 };
 
+enum NvmeIdCtrlCntrlType {
+    NVME_CNTRL_TYPE_IO          = 0x1,
+    NVME_CNTRL_TYPE_ADMIN       = 0x3,
+};
+
 typedef struct QEMU_PACKED NvmeDeleteQ {
     uint8_t     opcode;
     uint8_t     flags;
@@ -944,6 +949,8 @@ enum NvmeLogIdentifier {
     NVME_LOG_FW_SLOT_INFO   = 0x03,
     NVME_LOG_CHANGED_NSLIST = 0x04,
     NVME_LOG_CMD_EFFECTS    = 0x05,
+
+    NVME_LID_MAX            = 0x100,
 };
 
 typedef struct QEMU_PACKED NvmePSD {
@@ -1165,6 +1172,7 @@ enum NvmeFeatureIds {
     NVME_TIMESTAMP                  = 0xe,
     NVME_COMMAND_SET_PROFILE        = 0x19,
     NVME_SOFTWARE_PROGRESS_MARKER   = 0x80,
+
     NVME_FID_MAX                    = 0x100,
 };
 
diff --git a/hw/block/nvme-subsys.c b/hw/block/nvme-subsys.c
index af4804a819ee..051ef0f32b3f 100644
--- a/hw/block/nvme-subsys.c
+++ b/hw/block/nvme-subsys.c
@@ -60,7 +60,11 @@ int nvme_subsys_register_ns(NvmeNamespace *ns, Error **errp)
     for (i = 0; i < ARRAY_SIZE(subsys->ctrls); i++) {
         n = subsys->ctrls[i];
 
-        if (n && nvme_register_namespace(n, ns, errp)) {
+        if (!n || n->params.administrative) {
+            continue;
+        }
+
+        if (nvme_register_namespace(n, ns, errp)) {
             return -1;
         }
     }
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 8b8be3b5f121..f56748962e3f 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -94,6 +94,10 @@
  *   by the controller. To add support for the optional feature, needs to
  *   set the corresponding support indicated bit.
  *
+ * - 'administrative'
+ *   Set to true/on to make this an Administrative Controller. By default, the
+ *   controller will present itself as an I/O Controller.
+ *
  * nvme namespace device parameters
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  * - `subsys`
@@ -186,6 +190,15 @@ static const bool nvme_feature_support[NVME_FID_MAX] = {
     [NVME_TIMESTAMP]                = true,
 };
 
+static const bool nvme_admin_ctrl_feature_support[NVME_FID_MAX] = {
+    [NVME_POWER_MANAGEMENT]         = true,
+    [NVME_TEMPERATURE_THRESHOLD]    = true,
+    [NVME_INTERRUPT_COALESCING]     = true,
+    [NVME_INTERRUPT_VECTOR_CONF]    = true,
+    [NVME_ASYNCHRONOUS_EVENT_CONF]  = true,
+    [NVME_TIMESTAMP]                = true,
+};
+
 static const uint32_t nvme_feature_cap[NVME_FID_MAX] = {
     [NVME_TEMPERATURE_THRESHOLD]    = NVME_FEAT_CAP_CHANGE,
     [NVME_ERROR_RECOVERY]           = NVME_FEAT_CAP_CHANGE | NVME_FEAT_CAP_NS,
@@ -3634,6 +3647,12 @@ static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeRequest *req)
     return nvme_c2h(n, (uint8_t *)&timestamp, sizeof(timestamp), req);
 }
 
+static inline bool nvme_check_fid_support(NvmeCtrl *n, uint8_t fid)
+{
+    return n->params.administrative ?
+        nvme_admin_ctrl_feature_support[fid] : nvme_feature_support[fid];
+}
+
 static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req)
 {
     NvmeCmd *cmd = &req->cmd;
@@ -3653,7 +3672,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req)
 
     trace_pci_nvme_getfeat(nvme_cid(req), nsid, fid, sel, dw11);
 
-    if (!nvme_feature_support[fid]) {
+    if (!nvme_check_fid_support(n, fid)) {
         return NVME_INVALID_FIELD | NVME_DNR;
     }
 
@@ -3831,7 +3850,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
         return NVME_FID_NOT_SAVEABLE | NVME_DNR;
     }
 
-    if (!nvme_feature_support[fid]) {
+    if (!nvme_check_fid_support(n, fid)) {
         return NVME_INVALID_FIELD | NVME_DNR;
     }
 
@@ -4829,25 +4848,27 @@ static void nvme_init_cse_iocs(NvmeCtrl *n)
 {
     uint16_t oncs = n->params.oncs;
 
-    n->iocs.nvm[NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
-    n->iocs.nvm[NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
-    n->iocs.nvm[NVME_CMD_READ]  = NVME_CMD_EFF_CSUPP;
+    if (!n->params.administrative) {
+        n->iocs.nvm[NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
+        n->iocs.nvm[NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
+        n->iocs.nvm[NVME_CMD_READ]  = NVME_CMD_EFF_CSUPP;
 
-    if (oncs & NVME_ONCS_WRITE_ZEROES) {
-        n->iocs.nvm[NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP |
-            NVME_CMD_EFF_LBCC;
-    }
+        if (oncs & NVME_ONCS_WRITE_ZEROES) {
+            n->iocs.nvm[NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP |
+                NVME_CMD_EFF_LBCC;
+        }
 
-    if (oncs & NVME_ONCS_COMPARE) {
-        n->iocs.nvm[NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP;
-    }
+        if (oncs & NVME_ONCS_COMPARE) {
+            n->iocs.nvm[NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP;
+        }
 
-    if (oncs & NVME_ONCS_DSM) {
-        n->iocs.nvm[NVME_CMD_DSM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
-    }
+        if (oncs & NVME_ONCS_DSM) {
+            n->iocs.nvm[NVME_CMD_DSM] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
+        }
 
-    if (oncs & NVME_ONCS_COPY) {
-        n->iocs.nvm[NVME_CMD_COPY] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
+        if (oncs & NVME_ONCS_COPY) {
+            n->iocs.nvm[NVME_CMD_COPY] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC;
+        }
     }
 
     memcpy(n->iocs.zoned, n->iocs.nvm, sizeof(n->iocs.nvm));
@@ -4861,11 +4882,14 @@ static void nvme_init_cse_iocs(NvmeCtrl *n)
 
 static void nvme_init_cse_acs(NvmeCtrl *n)
 {
-    n->acs[NVME_ADM_CMD_DELETE_SQ] = NVME_CMD_EFF_CSUPP;
-    n->acs[NVME_ADM_CMD_CREATE_SQ] = NVME_CMD_EFF_CSUPP;
+    if (!n->params.administrative) {
+        n->acs[NVME_ADM_CMD_DELETE_SQ] = NVME_CMD_EFF_CSUPP;
+        n->acs[NVME_ADM_CMD_CREATE_SQ] = NVME_CMD_EFF_CSUPP;
+        n->acs[NVME_ADM_CMD_DELETE_CQ] = NVME_CMD_EFF_CSUPP;
+        n->acs[NVME_ADM_CMD_CREATE_CQ] = NVME_CMD_EFF_CSUPP;
+    }
+
     n->acs[NVME_ADM_CMD_GET_LOG_PAGE] = NVME_CMD_EFF_CSUPP;
-    n->acs[NVME_ADM_CMD_DELETE_CQ] = NVME_CMD_EFF_CSUPP;
-    n->acs[NVME_ADM_CMD_CREATE_CQ] = NVME_CMD_EFF_CSUPP;
     n->acs[NVME_ADM_CMD_IDENTIFY] = NVME_CMD_EFF_CSUPP;
     n->acs[NVME_ADM_CMD_ABORT] = NVME_CMD_EFF_CSUPP;
     n->acs[NVME_ADM_CMD_SET_FEATURES] = NVME_CMD_EFF_CSUPP;
@@ -4913,6 +4937,12 @@ int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
 {
     uint32_t nsid = nvme_nsid(ns);
 
+    if (n->params.administrative) {
+        error_setg(errp,
+                   "cannot attach namespace to administrative controller");
+        return -1;
+    }
+
     if (nsid > NVME_MAX_NAMESPACES) {
         error_setg(errp, "invalid namespace id (must be between 0 and %d)",
                    NVME_MAX_NAMESPACES);
@@ -5006,12 +5036,13 @@ static int nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
     uint8_t *pci_conf = pci_dev->config;
     uint64_t bar_size, msix_table_size, msix_pba_size;
     unsigned msix_table_offset, msix_pba_offset;
+    uint8_t prog_interface = n->params.administrative ? 0x3 : 0x2;
     int ret;
 
     Error *err = NULL;
 
     pci_conf[PCI_INTERRUPT_PIN] = 1;
-    pci_config_set_prog_interface(pci_conf, 0x2);
+    pci_config_set_prog_interface(pci_conf, prog_interface);
 
     if (n->params.use_intel_id) {
         pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
@@ -5109,7 +5140,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
     id->mdts = n->params.mdts;
     id->ver = cpu_to_le32(NVME_SPEC_VER);
     id->oacs = cpu_to_le16(n->params.oacs);
-    id->cntrltype = 0x1;
+    id->cntrltype = n->params.administrative ?
+        NVME_CNTRL_TYPE_ADMIN : NVME_CNTRL_TYPE_IO;
 
     /*
      * Because the controller always completes the Abort command immediately,
@@ -5159,7 +5191,12 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
         id->cmic |= NVME_CMIC_MULTI_CTRL;
     }
 
-    NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
+    if (n->params.administrative) {
+        NVME_CAP_SET_MQES(n->bar.cap, 0);
+    } else {
+        NVME_CAP_SET_MQES(n->bar.cap, 0x7ff);
+    }
+
     NVME_CAP_SET_CQR(n->bar.cap, 1);
     NVME_CAP_SET_TO(n->bar.cap, 0xf);
     NVME_CAP_SET_CSS(n->bar.cap, NVME_CAP_CSS_NVM);
@@ -5284,6 +5321,7 @@ static Property nvme_props[] = {
                        NVME_ONCS_TIMESTAMP | NVME_ONCS_DSM |
                        NVME_ONCS_COMPARE | NVME_ONCS_FEATURES | NVME_ONCS_COPY),
     DEFINE_PROP_UINT16("oacs", NvmeCtrl, params.oacs, NVME_OACS_NS_MGMT),
+    DEFINE_PROP_BOOL("administrative", NvmeCtrl, params.administrative, false),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-- 
2.30.1



^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-03-11  6:58 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-03-11  6:38 [PATCH 0/3] hw/block/nvme: add administrative controller support Klaus Jensen
2021-03-11  6:38 ` [PATCH 1/3] hw/block/nvme: add oncs device parameter Klaus Jensen
2021-03-11  6:38 ` [PATCH 2/3] hw/block/nvme: add oacs " Klaus Jensen
2021-03-11  6:38 ` [PATCH 3/3] hw/block/nvme: add administrative controller type Klaus Jensen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).