[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 3/3] hw/block/nvme: add administrative controller type
From: |
Klaus Jensen |
Subject: |
[PATCH 3/3] hw/block/nvme: add administrative controller type |
Date: |
Thu, 11 Mar 2021 07:38:51 +0100 |
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 *)×tamp, 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