aboutsummaryrefslogtreecommitdiff
path: root/hw/block/nvme.c
diff options
context:
space:
mode:
authorKlaus Jensen <k.jensen@samsung.com>2020-07-06 08:13:01 +0200
committerKlaus Jensen <k.jensen@samsung.com>2020-09-02 08:48:50 +0200
commit9e7ecdca26c34ffc5bda3d1d49e90bbb6b4f4422 (patch)
tree3c1abcccfdee565fb0bed6f9f36f16b9a2fb06df /hw/block/nvme.c
parent38a58e7ce38cf73f25e5242f5f1abcfcbd250a6d (diff)
downloadqemu-9e7ecdca26c34ffc5bda3d1d49e90bbb6b4f4422.zip
qemu-9e7ecdca26c34ffc5bda3d1d49e90bbb6b4f4422.tar.gz
qemu-9e7ecdca26c34ffc5bda3d1d49e90bbb6b4f4422.tar.bz2
hw/block/nvme: enforce valid queue creation sequence
Support returning Command Sequence Error if Set Features on Number of Queues is called after queues have been created. Signed-off-by: Klaus Jensen <k.jensen@samsung.com> Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com> Message-Id: <20200706061303.246057-17-its@irrelevant.dk>
Diffstat (limited to 'hw/block/nvme.c')
-rw-r--r--hw/block/nvme.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index d884ac1..41d4e37 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -961,6 +961,13 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd)
cq = g_malloc0(sizeof(*cq));
nvme_init_cq(cq, n, prp1, cqid, vector, qsize + 1,
NVME_CQ_FLAGS_IEN(qflags));
+
+ /*
+ * It is only required to set qs_created when creating a completion queue;
+ * creating a submission queue without a matching completion queue will
+ * fail.
+ */
+ n->qs_created = true;
return NVME_SUCCESS;
}
@@ -1361,6 +1368,10 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
break;
case NVME_NUMBER_OF_QUEUES:
+ if (n->qs_created) {
+ return NVME_CMD_SEQ_ERROR | NVME_DNR;
+ }
+
/*
* NVMe v1.3, Section 5.21.1.7: 0xffff is not an allowed value for NCQR
* and NSQR.
@@ -1493,6 +1504,7 @@ static void nvme_clear_ctrl(NvmeCtrl *n)
n->aer_queued = 0;
n->outstanding_aers = 0;
+ n->qs_created = false;
blk_flush(n->conf.blk);
n->bar.cc = 0;