Skip to content

Commit

Permalink
hw/block/nvme: support namespace attachment command
Browse files Browse the repository at this point in the history
This patch supports Namespace Attachment command for the pre-defined
nvme-ns device nodes.  Of course, attach/detach namespace should only be
supported in case 'subsys' is given.  This is because if we detach a
namespace from a controller, somebody needs to manage the detached, but
allocated namespace in the NVMe subsystem.

As command effect for the namespace attachment command is registered,
the host will be notified that namespace inventory is changed so that
host will rescan the namespace inventory after this command.  For
example, kernel driver manages this command effect via passthru IOCTL.

Signed-off-by: Minwoo Im <minwoo.im.dev@gmail.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
Tested-by: Klaus Jensen <k.jensen@samsung.com>
[k.jensen: rebased for dma refactor]
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
  • Loading branch information
minwooim authored and birkelund committed Mar 9, 2021
1 parent 1f46660 commit 645ce1a
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 1 deletion.
10 changes: 10 additions & 0 deletions hw/block/nvme-subsys.h
Expand Up @@ -34,6 +34,16 @@ typedef struct NvmeSubsystem {
int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp);
int nvme_subsys_register_ns(NvmeNamespace *ns, Error **errp);

static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys,
uint32_t cntlid)
{
if (!subsys) {
return NULL;
}

return subsys->ctrls[cntlid];
}

/*
* Return allocated namespace of the specified nsid in the subsystem.
*/
Expand Down
60 changes: 59 additions & 1 deletion hw/block/nvme.c
Expand Up @@ -196,6 +196,7 @@ static const uint32_t nvme_cse_acs[256] = {
[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[256];
Expand Down Expand Up @@ -3905,6 +3906,61 @@ static uint16_t nvme_aer(NvmeCtrl *n, NvmeRequest *req)
return NVME_NO_COMPLETE;
}

static void __nvme_select_ns_iocs(NvmeCtrl *n, NvmeNamespace *ns);
static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
{
NvmeNamespace *ns;
NvmeCtrl *ctrl;
uint16_t list[NVME_CONTROLLER_LIST_SIZE] = {};
uint32_t nsid = le32_to_cpu(req->cmd.nsid);
uint32_t dw10 = le32_to_cpu(req->cmd.cdw10);
bool attach = !(dw10 & 0xf);
uint16_t *nr_ids = &list[0];
uint16_t *ids = &list[1];
uint16_t ret;
int i;

trace_pci_nvme_ns_attachment(nvme_cid(req), dw10 & 0xf);

ns = nvme_subsys_ns(n->subsys, nsid);
if (!ns) {
return NVME_INVALID_FIELD | NVME_DNR;
}

ret = nvme_h2c(n, (uint8_t *)list, 4096, req);
if (ret) {
return ret;
}

if (!*nr_ids) {
return NVME_NS_CTRL_LIST_INVALID | NVME_DNR;
}

for (i = 0; i < *nr_ids; i++) {
ctrl = nvme_subsys_ctrl(n->subsys, ids[i]);
if (!ctrl) {
return NVME_NS_CTRL_LIST_INVALID | NVME_DNR;
}

if (attach) {
if (nvme_ns_is_attached(ctrl, ns)) {
return NVME_NS_ALREADY_ATTACHED | NVME_DNR;
}

nvme_ns_attach(ctrl, ns);
__nvme_select_ns_iocs(ctrl, ns);
} else {
if (!nvme_ns_is_attached(ctrl, ns)) {
return NVME_NS_NOT_ATTACHED | NVME_DNR;
}

nvme_ns_detach(ctrl, ns);
}
}

return NVME_SUCCESS;
}

static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req)
{
trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), req->cmd.opcode,
Expand Down Expand Up @@ -3941,6 +3997,8 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest *req)
return nvme_get_feature(n, req);
case NVME_ADM_CMD_ASYNC_EV_REQ:
return nvme_aer(n, req);
case NVME_ADM_CMD_NS_ATTACHMENT:
return nvme_ns_attachment(n, req);
default:
assert(false);
}
Expand Down Expand Up @@ -4910,7 +4968,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(0);
id->oacs = cpu_to_le16(NVME_OACS_NS_MGMT);
id->cntrltype = 0x1;

/*
Expand Down
5 changes: 5 additions & 0 deletions hw/block/nvme.h
Expand Up @@ -235,6 +235,11 @@ static inline void nvme_ns_attach(NvmeCtrl *n, NvmeNamespace *ns)
n->namespaces[nvme_nsid(ns) - 1] = ns;
}

static inline void nvme_ns_detach(NvmeCtrl *n, NvmeNamespace *ns)
{
n->namespaces[nvme_nsid(ns) - 1] = NULL;
}

static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
{
NvmeSQueue *sq = req->sq;
Expand Down
2 changes: 2 additions & 0 deletions hw/block/trace-events
Expand Up @@ -84,6 +84,8 @@ pci_nvme_aer(uint16_t cid) "cid %"PRIu16""
pci_nvme_aer_aerl_exceeded(void) "aerl exceeded"
pci_nvme_aer_masked(uint8_t type, uint8_t mask) "type 0x%"PRIx8" mask 0x%"PRIx8""
pci_nvme_aer_post_cqe(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8""
pci_nvme_ns_attachment(uint16_t cid, uint8_t sel) "cid %"PRIu16", sel=0x%"PRIx8""
pci_nvme_ns_attachment_attach(uint16_t cntlid, uint32_t nsid) "cntlid=0x%"PRIx16", nsid=0x%"PRIx32""
pci_nvme_enqueue_event(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8""
pci_nvme_enqueue_event_noqueue(int queued) "queued %d"
pci_nvme_enqueue_event_masked(uint8_t typ) "type 0x%"PRIx8""
Expand Down
6 changes: 6 additions & 0 deletions include/block/nvme.h
Expand Up @@ -566,6 +566,7 @@ enum NvmeAdminCommands {
NVME_ADM_CMD_ASYNC_EV_REQ = 0x0c,
NVME_ADM_CMD_ACTIVATE_FW = 0x10,
NVME_ADM_CMD_DOWNLOAD_FW = 0x11,
NVME_ADM_CMD_NS_ATTACHMENT = 0x15,
NVME_ADM_CMD_FORMAT_NVM = 0x80,
NVME_ADM_CMD_SECURITY_SEND = 0x81,
NVME_ADM_CMD_SECURITY_RECV = 0x82,
Expand Down Expand Up @@ -836,6 +837,9 @@ enum NvmeStatusCodes {
NVME_FEAT_NOT_CHANGEABLE = 0x010e,
NVME_FEAT_NOT_NS_SPEC = 0x010f,
NVME_FW_REQ_SUSYSTEM_RESET = 0x0110,
NVME_NS_ALREADY_ATTACHED = 0x0118,
NVME_NS_NOT_ATTACHED = 0x011A,
NVME_NS_CTRL_LIST_INVALID = 0x011C,
NVME_CONFLICTING_ATTRS = 0x0180,
NVME_INVALID_PROT_INFO = 0x0181,
NVME_WRITE_TO_RO = 0x0182,
Expand Down Expand Up @@ -951,6 +955,7 @@ typedef struct QEMU_PACKED NvmePSD {
uint8_t resv[16];
} NvmePSD;

#define NVME_CONTROLLER_LIST_SIZE 2048
#define NVME_IDENTIFY_DATA_SIZE 4096

enum NvmeIdCns {
Expand Down Expand Up @@ -1055,6 +1060,7 @@ enum NvmeIdCtrlOacs {
NVME_OACS_SECURITY = 1 << 0,
NVME_OACS_FORMAT = 1 << 1,
NVME_OACS_FW = 1 << 2,
NVME_OACS_NS_MGMT = 1 << 3,
};

enum NvmeIdCtrlOncs {
Expand Down

0 comments on commit 645ce1a

Please sign in to comment.