hw/block/nvme: support to map controller to a subsystem

nvme controller(nvme) can be mapped to a NVMe subsystem(nvme-subsys).
This patch maps a controller to a subsystem by adding a parameter
'subsys' to the nvme device.

To map a controller to a subsystem, we need to put nvme-subsys first and
then maps the subsystem to the controller:

  -device nvme-subsys,id=subsys0
  -device nvme,serial=foo,id=nvme0,subsys=subsys0

If 'subsys' property is not given to the nvme controller, then subsystem
NQN will be created with serial (e.g., 'foo' in above example),
Otherwise, it will be based on subsys id (e.g., 'subsys0' in above
example).

Signed-off-by: Minwoo Im <minwoo.im.dev@gmail.com>
Tested-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
This commit is contained in:
Minwoo Im 2021-01-24 11:54:46 +09:00 committed by Klaus Jensen
parent eb2e89747e
commit 982ed66bb2
2 changed files with 28 additions and 5 deletions

View File

@ -23,7 +23,8 @@
* [pmrdev=<mem_backend_file_id>,] \ * [pmrdev=<mem_backend_file_id>,] \
* max_ioqpairs=<N[optional]>, \ * max_ioqpairs=<N[optional]>, \
* aerl=<N[optional]>, aer_max_queued=<N[optional]>, \ * aerl=<N[optional]>, aer_max_queued=<N[optional]>, \
* mdts=<N[optional]>,zoned.append_size_limit=<N[optional]> \ * mdts=<N[optional]>,zoned.append_size_limit=<N[optional]>, \
* subsys=<subsys_id>
* -device nvme-ns,drive=<drive_id>,bus=<bus_name>,nsid=<nsid>,\ * -device nvme-ns,drive=<drive_id>,bus=<bus_name>,nsid=<nsid>,\
* zoned=<true|false[optional]> * zoned=<true|false[optional]>
* *
@ -53,6 +54,13 @@
* *
* nvme device parameters * nvme device parameters
* ~~~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~~~
* - `subsys`
* Specifying this parameter attaches the controller to the subsystem and
* the SUBNQN field in the controller will report the NQN of the subsystem
* device. This also enables multi controller capability represented in
* Identify Controller data structure in CMIC (Controller Multi-path I/O and
* Namesapce Sharing Capabilities).
*
* - `aerl` * - `aerl`
* The Asynchronous Event Request Limit (AERL). Indicates the maximum number * The Asynchronous Event Request Limit (AERL). Indicates the maximum number
* of concurrently outstanding Asynchronous Event Request commands support * of concurrently outstanding Asynchronous Event Request commands support
@ -4417,11 +4425,23 @@ static int nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
return 0; return 0;
} }
static void nvme_init_subnqn(NvmeCtrl *n)
{
NvmeSubsystem *subsys = n->subsys;
NvmeIdCtrl *id = &n->id_ctrl;
if (!subsys) {
snprintf((char *)id->subnqn, sizeof(id->subnqn),
"nqn.2019-08.org.qemu:%s", n->params.serial);
} else {
pstrcpy((char *)id->subnqn, sizeof(id->subnqn), (char*)subsys->subnqn);
}
}
static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
{ {
NvmeIdCtrl *id = &n->id_ctrl; NvmeIdCtrl *id = &n->id_ctrl;
uint8_t *pci_conf = pci_dev->config; uint8_t *pci_conf = pci_dev->config;
char *subnqn;
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID)); id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID)); id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
@ -4468,9 +4488,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN | id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN |
NVME_CTRL_SGLS_BITBUCKET); NVME_CTRL_SGLS_BITBUCKET);
subnqn = g_strdup_printf("nqn.2019-08.org.qemu:%s", n->params.serial); nvme_init_subnqn(n);
strpadcpy((char *)id->subnqn, sizeof(id->subnqn), subnqn, '\0');
g_free(subnqn);
id->psd[0].mp = cpu_to_le16(0x9c4); id->psd[0].mp = cpu_to_le16(0x9c4);
id->psd[0].enlat = cpu_to_le32(0x10); id->psd[0].enlat = cpu_to_le32(0x10);
@ -4562,6 +4580,8 @@ static Property nvme_props[] = {
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, namespace.blkconf), DEFINE_BLOCK_PROPERTIES(NvmeCtrl, namespace.blkconf),
DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmr.dev, TYPE_MEMORY_BACKEND, DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmr.dev, TYPE_MEMORY_BACKEND,
HostMemoryBackend *), HostMemoryBackend *),
DEFINE_PROP_LINK("subsys", NvmeCtrl, subsys, TYPE_NVME_SUBSYS,
NvmeSubsystem *),
DEFINE_PROP_STRING("serial", NvmeCtrl, params.serial), DEFINE_PROP_STRING("serial", NvmeCtrl, params.serial),
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, params.cmb_size_mb, 0), DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, params.cmb_size_mb, 0),
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, params.num_queues, 0), DEFINE_PROP_UINT32("num_queues", NvmeCtrl, params.num_queues, 0),

View File

@ -2,6 +2,7 @@
#define HW_NVME_H #define HW_NVME_H
#include "block/nvme.h" #include "block/nvme.h"
#include "nvme-subsys.h"
#include "nvme-ns.h" #include "nvme-ns.h"
#define NVME_MAX_NAMESPACES 256 #define NVME_MAX_NAMESPACES 256
@ -170,6 +171,8 @@ typedef struct NvmeCtrl {
uint8_t zasl; uint8_t zasl;
NvmeSubsystem *subsys;
NvmeNamespace namespace; NvmeNamespace namespace;
NvmeNamespace *namespaces[NVME_MAX_NAMESPACES]; NvmeNamespace *namespaces[NVME_MAX_NAMESPACES];
NvmeSQueue **sq; NvmeSQueue **sq;