* [PATCH v2 00/18] hw/block/nvme: bump to v1.3
@ 2020-07-03 6:34 Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 01/18] hw/block/nvme: bump spec data structures " Klaus Jensen
` (17 more replies)
0 siblings, 18 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
This adds mandatory features of NVM Express v1.3 to the emulated NVMe
device.
v2:
* hw/block/nvme: bump spec data structures to v1.3
- Shorten some constants. (Dmitry)
* hw/block/nvme: add temperature threshold feature
- Remove unused temp_thresh member. (Dmitry)
* hw/block/nvme: add support for the get log page command
- Change the temperature field in the NvmeSmartLog struct to be an
uint16_t and handle wierd alignment by adding QEMU_PACKED to the
struct. (Dmitry)
* hw/block/nvme: add remaining mandatory controller parameters
- Fix spelling. (Dmitry)
* hw/block/nvme: support the get/set features select and save fields
- Fix bad logic causing temperature thresholds to always report
defaults. (Dmitry)
* hw/block/nvme: reject invalid nsid values in active namespace id list
- Added patch; reject the 0xfffffffe and 0xffffffff nsid values.
Klaus Jensen (18):
hw/block/nvme: bump spec data structures to v1.3
hw/block/nvme: additional tracing
hw/block/nvme: add support for the abort command
hw/block/nvme: add temperature threshold feature
hw/block/nvme: mark fw slot 1 as read-only
hw/block/nvme: add support for the get log page command
hw/block/nvme: add support for the asynchronous event request command
hw/block/nvme: move NvmeFeatureVal into hw/block/nvme.h
hw/block/nvme: flush write cache when disabled
hw/block/nvme: fix missing endian conversion
hw/block/nvme: add remaining mandatory controller parameters
hw/block/nvme: support the get/set features select and save fields
hw/block/nvme: make sure ncqr and nsqr is valid
hw/block/nvme: support identify namespace descriptor list
hw/block/nvme: reject invalid nsid values in active namespace id list
hw/block/nvme: enforce valid queue creation sequence
hw/block/nvme: provide the mandatory subnqn field
hw/block/nvme: bump supported version to v1.3
block/nvme.c | 18 +-
hw/block/nvme.c | 611 ++++++++++++++++++++++++++++++++++++++++--
hw/block/nvme.h | 62 ++++-
hw/block/trace-events | 27 +-
include/block/nvme.h | 222 ++++++++++++---
5 files changed, 874 insertions(+), 66 deletions(-)
--
2.27.0
^ permalink raw reply [flat|nested] 42+ messages in thread
* [PATCH v2 01/18] hw/block/nvme: bump spec data structures to v1.3
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 02/18] hw/block/nvme: additional tracing Klaus Jensen
` (16 subsequent siblings)
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Fam Zheng, Dmitry Fomichev, Klaus Jensen, qemu-devel,
Max Reitz, Klaus Jensen, Keith Busch, Javier Gonzalez,
Maxim Levitsky, Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Add missing fields in the Identify Controller and Identify Namespace
data structures to bring them in line with NVMe v1.3.
This also adds data structures and defines for SGL support which
requires a couple of trivial changes to the nvme block driver as well.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Acked-by: Fam Zheng <fam@euphon.net>
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
---
block/nvme.c | 18 ++---
hw/block/nvme.c | 12 ++--
include/block/nvme.h | 156 ++++++++++++++++++++++++++++++++++++++-----
3 files changed, 154 insertions(+), 32 deletions(-)
diff --git a/block/nvme.c b/block/nvme.c
index 374e26891573..c1c4c07ac6cc 100644
--- a/block/nvme.c
+++ b/block/nvme.c
@@ -518,7 +518,7 @@ static void nvme_identify(BlockDriverState *bs, int namespace, Error **errp)
error_setg(errp, "Cannot map buffer for DMA");
goto out;
}
- cmd.prp1 = cpu_to_le64(iova);
+ cmd.dptr.prp1 = cpu_to_le64(iova);
if (nvme_cmd_sync(bs, s->queues[0], &cmd)) {
error_setg(errp, "Failed to identify controller");
@@ -629,7 +629,7 @@ static bool nvme_add_io_queue(BlockDriverState *bs, Error **errp)
}
cmd = (NvmeCmd) {
.opcode = NVME_ADM_CMD_CREATE_CQ,
- .prp1 = cpu_to_le64(q->cq.iova),
+ .dptr.prp1 = cpu_to_le64(q->cq.iova),
.cdw10 = cpu_to_le32(((queue_size - 1) << 16) | (n & 0xFFFF)),
.cdw11 = cpu_to_le32(0x3),
};
@@ -640,7 +640,7 @@ static bool nvme_add_io_queue(BlockDriverState *bs, Error **errp)
}
cmd = (NvmeCmd) {
.opcode = NVME_ADM_CMD_CREATE_SQ,
- .prp1 = cpu_to_le64(q->sq.iova),
+ .dptr.prp1 = cpu_to_le64(q->sq.iova),
.cdw10 = cpu_to_le32(((queue_size - 1) << 16) | (n & 0xFFFF)),
.cdw11 = cpu_to_le32(0x1 | (n << 16)),
};
@@ -988,16 +988,16 @@ try_map:
case 0:
abort();
case 1:
- cmd->prp1 = pagelist[0];
- cmd->prp2 = 0;
+ cmd->dptr.prp1 = pagelist[0];
+ cmd->dptr.prp2 = 0;
break;
case 2:
- cmd->prp1 = pagelist[0];
- cmd->prp2 = pagelist[1];
+ cmd->dptr.prp1 = pagelist[0];
+ cmd->dptr.prp2 = pagelist[1];
break;
default:
- cmd->prp1 = pagelist[0];
- cmd->prp2 = cpu_to_le64(req->prp_list_iova + sizeof(uint64_t));
+ cmd->dptr.prp1 = pagelist[0];
+ cmd->dptr.prp2 = cpu_to_le64(req->prp_list_iova + sizeof(uint64_t));
break;
}
trace_nvme_cmd_map_qiov(s, cmd, req, qiov, entries);
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 1aee042d4cb2..71b388aa0e20 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -397,8 +397,8 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
NvmeRwCmd *rw = (NvmeRwCmd *)cmd;
uint32_t nlb = le32_to_cpu(rw->nlb) + 1;
uint64_t slba = le64_to_cpu(rw->slba);
- uint64_t prp1 = le64_to_cpu(rw->prp1);
- uint64_t prp2 = le64_to_cpu(rw->prp2);
+ uint64_t prp1 = le64_to_cpu(rw->dptr.prp1);
+ uint64_t prp2 = le64_to_cpu(rw->dptr.prp2);
uint8_t lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds;
@@ -795,8 +795,8 @@ static inline uint64_t nvme_get_timestamp(const NvmeCtrl *n)
static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd)
{
- uint64_t prp1 = le64_to_cpu(cmd->prp1);
- uint64_t prp2 = le64_to_cpu(cmd->prp2);
+ uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
+ uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
uint64_t timestamp = nvme_get_timestamp(n);
@@ -834,8 +834,8 @@ static uint16_t nvme_set_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd)
{
uint16_t ret;
uint64_t timestamp;
- uint64_t prp1 = le64_to_cpu(cmd->prp1);
- uint64_t prp2 = le64_to_cpu(cmd->prp2);
+ uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
+ uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
ret = nvme_dma_write_prp(n, (uint8_t *)×tamp,
sizeof(timestamp), prp1, prp2);
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 1720ee1d5158..2a80d2a7ed89 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -377,15 +377,53 @@ enum NvmePmrmscMask {
#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \
(pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT)
+enum NvmeSglDescriptorType {
+ NVME_SGL_DESCR_TYPE_DATA_BLOCK = 0x0,
+ NVME_SGL_DESCR_TYPE_BIT_BUCKET = 0x1,
+ NVME_SGL_DESCR_TYPE_SEGMENT = 0x2,
+ NVME_SGL_DESCR_TYPE_LAST_SEGMENT = 0x3,
+ NVME_SGL_DESCR_TYPE_KEYED_DATA_BLOCK = 0x4,
+
+ NVME_SGL_DESCR_TYPE_VENDOR_SPECIFIC = 0xf,
+};
+
+enum NvmeSglDescriptorSubtype {
+ NVME_SGL_DESCR_SUBTYPE_ADDRESS = 0x0,
+};
+
+typedef struct NvmeSglDescriptor {
+ uint64_t addr;
+ uint32_t len;
+ uint8_t rsvd[3];
+ uint8_t type;
+} NvmeSglDescriptor;
+
+#define NVME_SGL_TYPE(type) ((type >> 4) & 0xf)
+#define NVME_SGL_SUBTYPE(type) (type & 0xf)
+
+typedef union NvmeCmdDptr {
+ struct {
+ uint64_t prp1;
+ uint64_t prp2;
+ };
+
+ NvmeSglDescriptor sgl;
+} NvmeCmdDptr;
+
+enum NvmePsdt {
+ PSDT_PRP = 0x0,
+ PSDT_SGL_MPTR_CONTIGUOUS = 0x1,
+ PSDT_SGL_MPTR_SGL = 0x2,
+};
+
typedef struct NvmeCmd {
uint8_t opcode;
- uint8_t fuse;
+ uint8_t flags;
uint16_t cid;
uint32_t nsid;
uint64_t res1;
uint64_t mptr;
- uint64_t prp1;
- uint64_t prp2;
+ NvmeCmdDptr dptr;
uint32_t cdw10;
uint32_t cdw11;
uint32_t cdw12;
@@ -394,6 +432,9 @@ typedef struct NvmeCmd {
uint32_t cdw15;
} NvmeCmd;
+#define NVME_CMD_FLAGS_FUSE(flags) (flags & 0x3)
+#define NVME_CMD_FLAGS_PSDT(flags) ((flags >> 6) & 0x3)
+
enum NvmeAdminCommands {
NVME_ADM_CMD_DELETE_SQ = 0x00,
NVME_ADM_CMD_CREATE_SQ = 0x01,
@@ -493,8 +534,7 @@ typedef struct NvmeRwCmd {
uint32_t nsid;
uint64_t rsvd2;
uint64_t mptr;
- uint64_t prp1;
- uint64_t prp2;
+ NvmeCmdDptr dptr;
uint64_t slba;
uint16_t nlb;
uint16_t control;
@@ -534,8 +574,7 @@ typedef struct NvmeDsmCmd {
uint16_t cid;
uint32_t nsid;
uint64_t rsvd2[2];
- uint64_t prp1;
- uint64_t prp2;
+ NvmeCmdDptr dptr;
uint32_t nr;
uint32_t attributes;
uint32_t rsvd12[4];
@@ -599,6 +638,12 @@ enum NvmeStatusCodes {
NVME_CMD_ABORT_MISSING_FUSE = 0x000a,
NVME_INVALID_NSID = 0x000b,
NVME_CMD_SEQ_ERROR = 0x000c,
+ NVME_INVALID_SGL_SEG_DESCR = 0x000d,
+ NVME_INVALID_NUM_SGL_DESCRS = 0x000e,
+ NVME_DATA_SGL_LEN_INVALID = 0x000f,
+ NVME_MD_SGL_LEN_INVALID = 0x0010,
+ NVME_SGL_DESCR_TYPE_INVALID = 0x0011,
+ NVME_INVALID_USE_OF_CMB = 0x0012,
NVME_LBA_RANGE = 0x0080,
NVME_CAP_EXCEEDED = 0x0081,
NVME_NS_NOT_READY = 0x0082,
@@ -687,7 +732,7 @@ enum NvmeSmartWarn {
NVME_SMART_FAILED_VOLATILE_MEDIA = 1 << 4,
};
-enum LogIdentifier {
+enum NvmeLogIdentifier {
NVME_LOG_ERROR_INFO = 0x01,
NVME_LOG_SMART_INFO = 0x02,
NVME_LOG_FW_SLOT_INFO = 0x03,
@@ -711,6 +756,7 @@ enum {
NVME_ID_CNS_NS = 0x0,
NVME_ID_CNS_CTRL = 0x1,
NVME_ID_CNS_NS_ACTIVE_LIST = 0x2,
+ NVME_ID_CNS_NS_DESCR_LIST = 0x3,
};
typedef struct NvmeIdCtrl {
@@ -723,7 +769,15 @@ typedef struct NvmeIdCtrl {
uint8_t ieee[3];
uint8_t cmic;
uint8_t mdts;
- uint8_t rsvd255[178];
+ uint16_t cntlid;
+ uint32_t ver;
+ uint32_t rtd3r;
+ uint32_t rtd3e;
+ uint32_t oaes;
+ uint32_t ctratt;
+ uint8_t rsvd100[12];
+ uint8_t fguid[16];
+ uint8_t rsvd128[128];
uint16_t oacs;
uint8_t acl;
uint8_t aerl;
@@ -731,10 +785,28 @@ typedef struct NvmeIdCtrl {
uint8_t lpa;
uint8_t elpe;
uint8_t npss;
- uint8_t rsvd511[248];
+ uint8_t avscc;
+ uint8_t apsta;
+ uint16_t wctemp;
+ uint16_t cctemp;
+ uint16_t mtfa;
+ uint32_t hmpre;
+ uint32_t hmmin;
+ uint8_t tnvmcap[16];
+ uint8_t unvmcap[16];
+ uint32_t rpmbs;
+ uint16_t edstt;
+ uint8_t dsto;
+ uint8_t fwug;
+ uint16_t kas;
+ uint16_t hctma;
+ uint16_t mntmt;
+ uint16_t mxtmt;
+ uint32_t sanicap;
+ uint8_t rsvd332[180];
uint8_t sqes;
uint8_t cqes;
- uint16_t rsvd515;
+ uint16_t maxcmd;
uint32_t nn;
uint16_t oncs;
uint16_t fuses;
@@ -742,8 +814,14 @@ typedef struct NvmeIdCtrl {
uint8_t vwc;
uint16_t awun;
uint16_t awupf;
- uint8_t rsvd703[174];
- uint8_t rsvd2047[1344];
+ uint8_t nvscc;
+ uint8_t rsvd531;
+ uint16_t acwu;
+ uint8_t rsvd534[2];
+ uint32_t sgls;
+ uint8_t rsvd540[228];
+ uint8_t subnqn[256];
+ uint8_t rsvd1024[1024];
NvmePSD psd[32];
uint8_t vs[1024];
} NvmeIdCtrl;
@@ -769,6 +847,16 @@ enum NvmeIdCtrlOncs {
#define NVME_CTRL_CQES_MIN(cqes) ((cqes) & 0xf)
#define NVME_CTRL_CQES_MAX(cqes) (((cqes) >> 4) & 0xf)
+#define NVME_CTRL_SGLS_SUPPORT_MASK (0x3 << 0)
+#define NVME_CTRL_SGLS_SUPPORT_NO_ALIGN (0x1 << 0)
+#define NVME_CTRL_SGLS_SUPPORT_DWORD_ALIGN (0x1 << 1)
+#define NVME_CTRL_SGLS_KEYED (0x1 << 2)
+#define NVME_CTRL_SGLS_BITBUCKET (0x1 << 16)
+#define NVME_CTRL_SGLS_MPTR_CONTIGUOUS (0x1 << 17)
+#define NVME_CTRL_SGLS_EXCESS_LENGTH (0x1 << 18)
+#define NVME_CTRL_SGLS_MPTR_SGL (0x1 << 19)
+#define NVME_CTRL_SGLS_ADDR_OFFSET (0x1 << 20)
+
typedef struct NvmeFeatureVal {
uint32_t arbitration;
uint32_t power_mgmt;
@@ -791,6 +879,15 @@ typedef struct NvmeFeatureVal {
#define NVME_INTC_THR(intc) (intc & 0xff)
#define NVME_INTC_TIME(intc) ((intc >> 8) & 0xff)
+#define NVME_TEMP_THSEL(temp) ((temp >> 20) & 0x3)
+#define NVME_TEMP_THSEL_OVER 0x0
+#define NVME_TEMP_THSEL_UNDER 0x1
+
+#define NVME_TEMP_TMPSEL(temp) ((temp >> 16) & 0xf)
+#define NVME_TEMP_TMPSEL_COMPOSITE 0x0
+
+#define NVME_TEMP_TMPTH(temp) ((temp >> 0) & 0xffff)
+
enum NvmeFeatureIds {
NVME_ARBITRATION = 0x1,
NVME_POWER_MANAGEMENT = 0x2,
@@ -833,18 +930,43 @@ typedef struct NvmeIdNs {
uint8_t mc;
uint8_t dpc;
uint8_t dps;
-
uint8_t nmic;
uint8_t rescap;
uint8_t fpi;
uint8_t dlfeat;
-
- uint8_t res34[94];
+ uint16_t nawun;
+ uint16_t nawupf;
+ uint16_t nacwu;
+ uint16_t nabsn;
+ uint16_t nabo;
+ uint16_t nabspf;
+ uint16_t noiob;
+ uint8_t nvmcap[16];
+ uint8_t rsvd64[40];
+ uint8_t nguid[16];
+ uint64_t eui64;
NvmeLBAF lbaf[16];
- uint8_t res192[192];
+ uint8_t rsvd192[192];
uint8_t vs[3712];
} NvmeIdNs;
+typedef struct NvmeIdNsDescr {
+ uint8_t nidt;
+ uint8_t nidl;
+ uint8_t rsvd2[2];
+} NvmeIdNsDescr;
+
+enum {
+ NVME_NIDT_EUI64_LEN = 8,
+ NVME_NIDT_NGUID_LEN = 16,
+ NVME_NIDT_UUID_LEN = 16,
+};
+
+enum NvmeNsIdentifierType {
+ NVME_NIDT_EUI64 = 0x1,
+ NVME_NIDT_NGUID = 0x2,
+ NVME_NIDT_UUID = 0x3,
+};
/*Deallocate Logical Block Features*/
#define NVME_ID_NS_DLFEAT_GUARD_CRC(dlfeat) ((dlfeat) & 0x10)
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 02/18] hw/block/nvme: additional tracing
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 01/18] hw/block/nvme: bump spec data structures " Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 8:03 ` Philippe Mathieu-Daudé
2020-07-03 6:34 ` [PATCH v2 03/18] hw/block/nvme: add support for the abort command Klaus Jensen
` (15 subsequent siblings)
17 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Add various additional tracing and streamline nvme_identify_ns and
nvme_identify_nslist (they do not need to repeat the command, it is
already in the trace name).
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 19 +++++++++++++++++++
hw/block/nvme.h | 14 ++++++++++++++
hw/block/trace-events | 13 +++++++++++--
3 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 71b388aa0e20..f5d9148f0936 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -331,6 +331,8 @@ static void nvme_post_cqes(void *opaque)
static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req)
{
assert(cq->cqid == req->sq->cqid);
+ trace_pci_nvme_enqueue_req_completion(nvme_cid(req), cq->cqid,
+ req->status);
QTAILQ_REMOVE(&req->sq->out_req_list, req, entry);
QTAILQ_INSERT_TAIL(&cq->req_list, req, entry);
timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
@@ -343,6 +345,8 @@ static void nvme_rw_cb(void *opaque, int ret)
NvmeCtrl *n = sq->ctrl;
NvmeCQueue *cq = n->cq[sq->cqid];
+ trace_pci_nvme_rw_cb(nvme_cid(req));
+
if (!ret) {
block_acct_done(blk_get_stats(n->conf.blk), &req->acct);
req->status = NVME_SUCCESS;
@@ -378,6 +382,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
uint64_t offset = slba << data_shift;
uint32_t count = nlb << data_shift;
+ trace_pci_nvme_write_zeroes(nvme_cid(req), slba, nlb);
+
if (unlikely(slba + nlb > ns->id_ns.nsze)) {
trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
return NVME_LBA_RANGE | NVME_DNR;
@@ -445,6 +451,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
NvmeNamespace *ns;
uint32_t nsid = le32_to_cpu(cmd->nsid);
+ trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req), cmd->opcode);
+
if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces);
return NVME_INVALID_NSID | NVME_DNR;
@@ -876,6 +884,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
{
+ trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), cmd->opcode);
+
switch (cmd->opcode) {
case NVME_ADM_CMD_DELETE_SQ:
return nvme_del_sq(n, cmd);
@@ -1204,6 +1214,8 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
uint8_t *ptr = (uint8_t *)&n->bar;
uint64_t val = 0;
+ trace_pci_nvme_mmio_read(addr);
+
if (unlikely(addr & (sizeof(uint32_t) - 1))) {
NVME_GUEST_ERR(pci_nvme_ub_mmiord_misaligned32,
"MMIO read not 32-bit aligned,"
@@ -1273,6 +1285,8 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
return;
}
+ trace_pci_nvme_mmio_doorbell_cq(cq->cqid, new_head);
+
start_sqs = nvme_cq_full(cq) ? 1 : 0;
cq->head = new_head;
if (start_sqs) {
@@ -1311,6 +1325,8 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
return;
}
+ trace_pci_nvme_mmio_doorbell_sq(sq->sqid, new_tail);
+
sq->tail = new_tail;
timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
}
@@ -1320,6 +1336,9 @@ static void nvme_mmio_write(void *opaque, hwaddr addr, uint64_t data,
unsigned size)
{
NvmeCtrl *n = (NvmeCtrl *)opaque;
+
+ trace_pci_nvme_mmio_write(addr, data);
+
if (addr < sizeof(n->bar)) {
nvme_write_bar(n, addr, data, size);
} else if (addr >= 0x1000) {
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 1d30c0bca283..1bf5c80ed843 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -115,4 +115,18 @@ static inline uint64_t nvme_ns_nlbas(NvmeCtrl *n, NvmeNamespace *ns)
return n->ns_size >> nvme_ns_lbads(ns);
}
+static inline uint16_t nvme_cid(NvmeRequest *req)
+{
+ if (req) {
+ return le16_to_cpu(req->cqe.cid);
+ }
+
+ return 0xffff;
+}
+
+static inline uint16_t nvme_sqid(NvmeRequest *req)
+{
+ return le16_to_cpu(req->sq->sqid);
+}
+
#endif /* HW_NVME_H */
diff --git a/hw/block/trace-events b/hw/block/trace-events
index 958fcc5508d1..c40c0d2e4b28 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -33,19 +33,28 @@ pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
pci_nvme_irq_pin(void) "pulsing IRQ pin"
pci_nvme_irq_masked(void) "IRQ is masked"
pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
+pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8""
+pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8""
pci_nvme_rw(const char *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64""
+pci_nvme_rw_cb(uint16_t cid) "cid %"PRIu16""
+pci_nvme_write_zeroes(uint16_t cid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" slba %"PRIu64" nlb %"PRIu32""
pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16""
pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d"
pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16""
pci_nvme_identify_ctrl(void) "identify controller"
-pci_nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16""
-pci_nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
+pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
+pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64""
pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64""
+pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16""
+pci_nvme_mmio_read(uint64_t addr) "addr 0x%"PRIx64""
+pci_nvme_mmio_write(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64""
+pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16""
+pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "cqid %"PRIu16" new_tail %"PRIu16""
pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 03/18] hw/block/nvme: add support for the abort command
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 01/18] hw/block/nvme: bump spec data structures " Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 02/18] hw/block/nvme: additional tracing Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 04/18] hw/block/nvme: add temperature threshold feature Klaus Jensen
` (14 subsequent siblings)
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Required for compliance with NVMe revision 1.3d. See NVM Express 1.3d,
Section 5.1 ("Abort command").
The Abort command is a best effort command; for now, the device always
fails to abort the given command.
Signed-off-by: Klaus Jensen <klaus.jensen@cnexlabs.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Acked-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index f5d9148f0936..b7037a7d3504 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -761,6 +761,18 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
}
}
+static uint16_t nvme_abort(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
+{
+ uint16_t sqid = le32_to_cpu(cmd->cdw10) & 0xffff;
+
+ req->cqe.result = 1;
+ if (nvme_check_sqid(n, sqid)) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ return NVME_SUCCESS;
+}
+
static inline void nvme_set_timestamp(NvmeCtrl *n, uint64_t ts)
{
trace_pci_nvme_setfeat_timestamp(ts);
@@ -897,6 +909,8 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
return nvme_create_cq(n, cmd);
case NVME_ADM_CMD_IDENTIFY:
return nvme_identify(n, cmd);
+ case NVME_ADM_CMD_ABORT:
+ return nvme_abort(n, cmd, req);
case NVME_ADM_CMD_SET_FEATURES:
return nvme_set_feature(n, cmd, req);
case NVME_ADM_CMD_GET_FEATURES:
@@ -1582,6 +1596,19 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->ieee[1] = 0x02;
id->ieee[2] = 0xb3;
id->oacs = cpu_to_le16(0);
+
+ /*
+ * Because the controller always completes the Abort command immediately,
+ * there can never be more than one concurrently executing Abort command,
+ * so this value is never used for anything. Note that there can easily be
+ * many Abort commands in the queues, but they are not considered
+ * "executing" until processed by nvme_abort.
+ *
+ * The specification recommends a value of 3 for Abort Command Limit (four
+ * concurrently outstanding Abort commands), so lets use that though it is
+ * inconsequential.
+ */
+ id->acl = 3;
id->frmw = 7 << 1;
id->lpa = 1 << 0;
id->sqes = (0x6 << 4) | 0x6;
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 04/18] hw/block/nvme: add temperature threshold feature
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (2 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 03/18] hw/block/nvme: add support for the abort command Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 8:08 ` Philippe Mathieu-Daudé
2020-07-03 6:34 ` [PATCH v2 05/18] hw/block/nvme: mark fw slot 1 as read-only Klaus Jensen
` (13 subsequent siblings)
17 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
It might seem weird to implement this feature for an emulated device,
but it is mandatory to support and the feature is useful for testing
asynchronous event request support, which will be added in a later
patch.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Acked-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
---
hw/block/nvme.c | 48 ++++++++++++++++++++++++++++++++++++++++++++
hw/block/nvme.h | 1 +
include/block/nvme.h | 5 ++++-
3 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index b7037a7d3504..5ca50646369e 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -59,6 +59,9 @@
#define NVME_DB_SIZE 4
#define NVME_CMB_BIR 2
#define NVME_PMR_BIR 2
+#define NVME_TEMPERATURE 0x143
+#define NVME_TEMPERATURE_WARNING 0x157
+#define NVME_TEMPERATURE_CRITICAL 0x175
#define NVME_GUEST_ERR(trace, fmt, ...) \
do { \
@@ -827,9 +830,31 @@ static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd)
static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
{
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
+ uint32_t dw11 = le32_to_cpu(cmd->cdw11);
uint32_t result;
switch (dw10) {
+ case NVME_TEMPERATURE_THRESHOLD:
+ result = 0;
+
+ /*
+ * The controller only implements the Composite Temperature sensor, so
+ * return 0 for all other sensors.
+ */
+ if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
+ break;
+ }
+
+ switch (NVME_TEMP_THSEL(dw11)) {
+ case NVME_TEMP_THSEL_OVER:
+ result = cpu_to_le16(n->features.temp_thresh_hi);
+ break;
+ case NVME_TEMP_THSEL_UNDER:
+ result = cpu_to_le16(n->features.temp_thresh_low);
+ break;
+ }
+
+ break;
case NVME_VOLATILE_WRITE_CACHE:
result = blk_enable_write_cache(n->conf.blk);
trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
@@ -874,6 +899,23 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
uint32_t dw11 = le32_to_cpu(cmd->cdw11);
switch (dw10) {
+ case NVME_TEMPERATURE_THRESHOLD:
+ if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
+ break;
+ }
+
+ switch (NVME_TEMP_THSEL(dw11)) {
+ case NVME_TEMP_THSEL_OVER:
+ n->features.temp_thresh_hi = NVME_TEMP_TMPTH(dw11);
+ break;
+ case NVME_TEMP_THSEL_UNDER:
+ n->features.temp_thresh_low = NVME_TEMP_TMPTH(dw11);
+ break;
+ default:
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ break;
case NVME_VOLATILE_WRITE_CACHE:
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
break;
@@ -1454,6 +1496,7 @@ static void nvme_init_state(NvmeCtrl *n)
n->namespaces = g_new0(NvmeNamespace, n->num_namespaces);
n->sq = g_new0(NvmeSQueue *, n->params.max_ioqpairs + 1);
n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1);
+ n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING;
}
static void nvme_init_blk(NvmeCtrl *n, Error **errp)
@@ -1611,6 +1654,11 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->acl = 3;
id->frmw = 7 << 1;
id->lpa = 1 << 0;
+
+ /* recommended default value (~70 C) */
+ id->wctemp = cpu_to_le16(NVME_TEMPERATURE_WARNING);
+ id->cctemp = cpu_to_le16(NVME_TEMPERATURE_CRITICAL);
+
id->sqes = (0x6 << 4) | 0x6;
id->cqes = (0x4 << 4) | 0x4;
id->nn = cpu_to_le32(n->num_namespaces);
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 1bf5c80ed843..3acde10e1d2a 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -107,6 +107,7 @@ typedef struct NvmeCtrl {
NvmeSQueue admin_sq;
NvmeCQueue admin_cq;
NvmeIdCtrl id_ctrl;
+ NvmeFeatureVal features;
} NvmeCtrl;
/* calculate the number of LBAs that the namespace can accomodate */
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 2a80d2a7ed89..d2c457695b38 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -860,7 +860,10 @@ enum NvmeIdCtrlOncs {
typedef struct NvmeFeatureVal {
uint32_t arbitration;
uint32_t power_mgmt;
- uint32_t temp_thresh;
+ struct {
+ uint16_t temp_thresh_hi;
+ uint16_t temp_thresh_low;
+ };
uint32_t err_rec;
uint32_t volatile_wc;
uint32_t num_queues;
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 05/18] hw/block/nvme: mark fw slot 1 as read-only
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (3 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 04/18] hw/block/nvme: add temperature threshold feature Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 06/18] hw/block/nvme: add support for the get log page command Klaus Jensen
` (12 subsequent siblings)
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Mark firmware slot 1 as read-only and only support that slot.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 3 ++-
include/block/nvme.h | 4 ++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 5ca50646369e..f8e91a6965ed 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -62,6 +62,7 @@
#define NVME_TEMPERATURE 0x143
#define NVME_TEMPERATURE_WARNING 0x157
#define NVME_TEMPERATURE_CRITICAL 0x175
+#define NVME_NUM_FW_SLOTS 1
#define NVME_GUEST_ERR(trace, fmt, ...) \
do { \
@@ -1652,7 +1653,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
* inconsequential.
*/
id->acl = 3;
- id->frmw = 7 << 1;
+ id->frmw = (NVME_NUM_FW_SLOTS << 1) | NVME_FRMW_SLOT1_RO;
id->lpa = 1 << 0;
/* recommended default value (~70 C) */
diff --git a/include/block/nvme.h b/include/block/nvme.h
index d2c457695b38..d639e8bbee92 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -842,6 +842,10 @@ enum NvmeIdCtrlOncs {
NVME_ONCS_TIMESTAMP = 1 << 6,
};
+enum NvmeIdCtrlFrmw {
+ NVME_FRMW_SLOT1_RO = 1 << 0,
+};
+
#define NVME_CTRL_SQES_MIN(sqes) ((sqes) & 0xf)
#define NVME_CTRL_SQES_MAX(sqes) (((sqes) >> 4) & 0xf)
#define NVME_CTRL_CQES_MIN(cqes) ((cqes) & 0xf)
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 06/18] hw/block/nvme: add support for the get log page command
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (4 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 05/18] hw/block/nvme: mark fw slot 1 as read-only Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 07/18] hw/block/nvme: add support for the asynchronous event request command Klaus Jensen
` (11 subsequent siblings)
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Add support for the Get Log Page command and basic implementations of
the mandatory Error Information, SMART / Health Information and Firmware
Slot Information log pages.
In violation of the specification, the SMART / Health Information log
page does not persist information over the lifetime of the controller
because the device has no place to store such persistent state.
Note that the LPA field in the Identify Controller data structure
intentionally has bit 0 cleared because there is no namespace specific
information in the SMART / Health information log page.
Required for compliance with NVMe revision 1.3d. See NVM Express 1.3d,
Section 5.14 ("Get Log Page command").
Signed-off-by: Klaus Jensen <klaus.jensen@cnexlabs.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Acked-by: Keith Busch <kbusch@kernel.org>
---
hw/block/nvme.c | 140 +++++++++++++++++++++++++++++++++++++++++-
hw/block/nvme.h | 2 +
hw/block/trace-events | 2 +
include/block/nvme.h | 8 ++-
4 files changed, 149 insertions(+), 3 deletions(-)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index f8e91a6965ed..0c018fd952ae 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -592,6 +592,140 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
return NVME_SUCCESS;
}
+static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
+ uint64_t off, NvmeRequest *req)
+{
+ uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
+ uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
+ uint32_t nsid = le32_to_cpu(cmd->nsid);
+
+ uint32_t trans_len;
+ time_t current_ms;
+ uint64_t units_read = 0, units_written = 0;
+ uint64_t read_commands = 0, write_commands = 0;
+ NvmeSmartLog smart;
+ BlockAcctStats *s;
+
+ if (nsid && nsid != 0xffffffff) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ s = blk_get_stats(n->conf.blk);
+
+ units_read = s->nr_bytes[BLOCK_ACCT_READ] >> BDRV_SECTOR_BITS;
+ units_written = s->nr_bytes[BLOCK_ACCT_WRITE] >> BDRV_SECTOR_BITS;
+ read_commands = s->nr_ops[BLOCK_ACCT_READ];
+ write_commands = s->nr_ops[BLOCK_ACCT_WRITE];
+
+ if (off > sizeof(smart)) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ trans_len = MIN(sizeof(smart) - off, buf_len);
+
+ memset(&smart, 0x0, sizeof(smart));
+
+ smart.data_units_read[0] = cpu_to_le64(units_read / 1000);
+ smart.data_units_written[0] = cpu_to_le64(units_written / 1000);
+ smart.host_read_commands[0] = cpu_to_le64(read_commands);
+ smart.host_write_commands[0] = cpu_to_le64(write_commands);
+
+ smart.temperature = cpu_to_le16(n->temperature);
+
+ if ((n->temperature >= n->features.temp_thresh_hi) ||
+ (n->temperature <= n->features.temp_thresh_low)) {
+ smart.critical_warning |= NVME_SMART_TEMPERATURE;
+ }
+
+ current_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
+ smart.power_on_hours[0] =
+ cpu_to_le64((((current_ms - n->starttime_ms) / 1000) / 60) / 60);
+
+ return nvme_dma_read_prp(n, (uint8_t *) &smart + off, trans_len, prp1,
+ prp2);
+}
+
+static uint16_t nvme_fw_log_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
+ uint64_t off, NvmeRequest *req)
+{
+ uint32_t trans_len;
+ uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
+ uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
+ NvmeFwSlotInfoLog fw_log = {
+ .afi = 0x1,
+ };
+
+ strpadcpy((char *)&fw_log.frs1, sizeof(fw_log.frs1), "1.0", ' ');
+
+ if (off > sizeof(fw_log)) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ trans_len = MIN(sizeof(fw_log) - off, buf_len);
+
+ return nvme_dma_read_prp(n, (uint8_t *) &fw_log + off, trans_len, prp1,
+ prp2);
+}
+
+static uint16_t nvme_error_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
+ uint64_t off, NvmeRequest *req)
+{
+ uint32_t trans_len;
+ uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
+ uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
+ NvmeErrorLog errlog;
+
+ if (off > sizeof(errlog)) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ memset(&errlog, 0x0, sizeof(errlog));
+
+ trans_len = MIN(sizeof(errlog) - off, buf_len);
+
+ return nvme_dma_read_prp(n, (uint8_t *)&errlog, trans_len, prp1, prp2);
+}
+
+static uint16_t nvme_get_log(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
+{
+ uint32_t dw10 = le32_to_cpu(cmd->cdw10);
+ uint32_t dw11 = le32_to_cpu(cmd->cdw11);
+ uint32_t dw12 = le32_to_cpu(cmd->cdw12);
+ uint32_t dw13 = le32_to_cpu(cmd->cdw13);
+ uint8_t lid = dw10 & 0xff;
+ uint8_t lsp = (dw10 >> 8) & 0xf;
+ uint8_t rae = (dw10 >> 15) & 0x1;
+ uint32_t numdl, numdu;
+ uint64_t off, lpol, lpou;
+ size_t len;
+
+ numdl = (dw10 >> 16);
+ numdu = (dw11 & 0xffff);
+ lpol = dw12;
+ lpou = dw13;
+
+ len = (((numdu << 16) | numdl) + 1) << 2;
+ off = (lpou << 32ULL) | lpol;
+
+ if (off & 0x3) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ trace_pci_nvme_get_log(nvme_cid(req), lid, lsp, rae, len, off);
+
+ switch (lid) {
+ case NVME_LOG_ERROR_INFO:
+ return nvme_error_info(n, cmd, len, off, req);
+ case NVME_LOG_SMART_INFO:
+ return nvme_smart_info(n, cmd, len, off, req);
+ case NVME_LOG_FW_SLOT_INFO:
+ return nvme_fw_log_info(n, cmd, len, off, req);
+ default:
+ trace_pci_nvme_err_invalid_log_page(nvme_cid(req), lid);
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+}
+
static void nvme_free_cq(NvmeCQueue *cq, NvmeCtrl *n)
{
n->cq[cq->cqid] = NULL;
@@ -946,6 +1080,8 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
return nvme_del_sq(n, cmd);
case NVME_ADM_CMD_CREATE_SQ:
return nvme_create_sq(n, cmd);
+ case NVME_ADM_CMD_GET_LOG_PAGE:
+ return nvme_get_log(n, cmd, req);
case NVME_ADM_CMD_DELETE_CQ:
return nvme_del_cq(n, cmd);
case NVME_ADM_CMD_CREATE_CQ:
@@ -1497,7 +1633,9 @@ static void nvme_init_state(NvmeCtrl *n)
n->namespaces = g_new0(NvmeNamespace, n->num_namespaces);
n->sq = g_new0(NvmeSQueue *, n->params.max_ioqpairs + 1);
n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1);
+ n->temperature = NVME_TEMPERATURE;
n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING;
+ n->starttime_ms = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
}
static void nvme_init_blk(NvmeCtrl *n, Error **errp)
@@ -1654,7 +1792,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
*/
id->acl = 3;
id->frmw = (NVME_NUM_FW_SLOTS << 1) | NVME_FRMW_SLOT1_RO;
- id->lpa = 1 << 0;
+ id->lpa = NVME_LPA_EXTENDED;
/* recommended default value (~70 C) */
id->wctemp = cpu_to_le16(NVME_TEMPERATURE_WARNING);
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 3acde10e1d2a..3ddbc3722d7c 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -98,6 +98,8 @@ typedef struct NvmeCtrl {
uint32_t irq_status;
uint64_t host_timestamp; /* Timestamp sent by the host */
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
+ uint64_t starttime_ms;
+ uint16_t temperature;
HostMemoryBackend *pmrdev;
diff --git a/hw/block/trace-events b/hw/block/trace-events
index c40c0d2e4b28..3330d74e48db 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -45,6 +45,7 @@ pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16""
pci_nvme_identify_ctrl(void) "identify controller"
pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
+pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
@@ -94,6 +95,7 @@ pci_nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completi
pci_nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16""
pci_nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32""
pci_nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32""
+pci_nvme_err_invalid_log_page(uint16_t cid, uint16_t lid) "cid %"PRIu16" lid 0x%"PRIx16""
pci_nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues"
pci_nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues"
pci_nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null"
diff --git a/include/block/nvme.h b/include/block/nvme.h
index d639e8bbee92..49ce97ae1ab4 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -704,9 +704,9 @@ typedef struct NvmeErrorLog {
uint8_t resv[35];
} NvmeErrorLog;
-typedef struct NvmeSmartLog {
+typedef struct QEMU_PACKED NvmeSmartLog {
uint8_t critical_warning;
- uint8_t temperature[2];
+ uint16_t temperature;
uint8_t available_spare;
uint8_t available_spare_threshold;
uint8_t percentage_used;
@@ -846,6 +846,10 @@ enum NvmeIdCtrlFrmw {
NVME_FRMW_SLOT1_RO = 1 << 0,
};
+enum NvmeIdCtrlLpa {
+ NVME_LPA_EXTENDED = 1 << 2,
+};
+
#define NVME_CTRL_SQES_MIN(sqes) ((sqes) & 0xf)
#define NVME_CTRL_SQES_MAX(sqes) (((sqes) >> 4) & 0xf)
#define NVME_CTRL_CQES_MIN(cqes) ((cqes) & 0xf)
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 07/18] hw/block/nvme: add support for the asynchronous event request command
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (5 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 06/18] hw/block/nvme: add support for the get log page command Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 08/18] hw/block/nvme: move NvmeFeatureVal into hw/block/nvme.h Klaus Jensen
` (10 subsequent siblings)
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Add support for the Asynchronous Event Request command. Required for
compliance with NVMe revision 1.3d. See NVM Express 1.3d, Section 5.2
("Asynchronous Event Request command").
Mostly imported from Keith's qemu-nvme tree. Modified with a max number
of queued events (controllable with the aer_max_queued device
parameter). The spec states that the controller *should* retain
events, so we do best effort here.
Signed-off-by: Klaus Jensen <klaus.jensen@cnexlabs.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Acked-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 180 ++++++++++++++++++++++++++++++++++++++++--
hw/block/nvme.h | 10 ++-
hw/block/trace-events | 9 +++
include/block/nvme.h | 8 +-
4 files changed, 198 insertions(+), 9 deletions(-)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 0c018fd952ae..3eac1e231bf9 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -342,6 +342,85 @@ static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req)
timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
}
+static void nvme_process_aers(void *opaque)
+{
+ NvmeCtrl *n = opaque;
+ NvmeAsyncEvent *event, *next;
+
+ trace_pci_nvme_process_aers(n->aer_queued);
+
+ QTAILQ_FOREACH_SAFE(event, &n->aer_queue, entry, next) {
+ NvmeRequest *req;
+ NvmeAerResult *result;
+
+ /* can't post cqe if there is nothing to complete */
+ if (!n->outstanding_aers) {
+ trace_pci_nvme_no_outstanding_aers();
+ break;
+ }
+
+ /* ignore if masked (cqe posted, but event not cleared) */
+ if (n->aer_mask & (1 << event->result.event_type)) {
+ trace_pci_nvme_aer_masked(event->result.event_type, n->aer_mask);
+ continue;
+ }
+
+ QTAILQ_REMOVE(&n->aer_queue, event, entry);
+ n->aer_queued--;
+
+ n->aer_mask |= 1 << event->result.event_type;
+ n->outstanding_aers--;
+
+ req = n->aer_reqs[n->outstanding_aers];
+
+ result = (NvmeAerResult *) &req->cqe.result;
+ result->event_type = event->result.event_type;
+ result->event_info = event->result.event_info;
+ result->log_page = event->result.log_page;
+ g_free(event);
+
+ req->status = NVME_SUCCESS;
+
+ trace_pci_nvme_aer_post_cqe(result->event_type, result->event_info,
+ result->log_page);
+
+ nvme_enqueue_req_completion(&n->admin_cq, req);
+ }
+}
+
+static void nvme_enqueue_event(NvmeCtrl *n, uint8_t event_type,
+ uint8_t event_info, uint8_t log_page)
+{
+ NvmeAsyncEvent *event;
+
+ trace_pci_nvme_enqueue_event(event_type, event_info, log_page);
+
+ if (n->aer_queued == n->params.aer_max_queued) {
+ trace_pci_nvme_enqueue_event_noqueue(n->aer_queued);
+ return;
+ }
+
+ event = g_new(NvmeAsyncEvent, 1);
+ event->result = (NvmeAerResult) {
+ .event_type = event_type,
+ .event_info = event_info,
+ .log_page = log_page,
+ };
+
+ QTAILQ_INSERT_TAIL(&n->aer_queue, event, entry);
+ n->aer_queued++;
+
+ nvme_process_aers(n);
+}
+
+static void nvme_clear_events(NvmeCtrl *n, uint8_t event_type)
+{
+ n->aer_mask &= ~(1 << event_type);
+ if (!QTAILQ_EMPTY(&n->aer_queue)) {
+ nvme_process_aers(n);
+ }
+}
+
static void nvme_rw_cb(void *opaque, int ret)
{
NvmeRequest *req = opaque;
@@ -592,8 +671,9 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd)
return NVME_SUCCESS;
}
-static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
- uint64_t off, NvmeRequest *req)
+static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd *cmd, uint8_t rae,
+ uint32_t buf_len, uint64_t off,
+ NvmeRequest *req)
{
uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
@@ -641,6 +721,10 @@ static uint16_t nvme_smart_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
smart.power_on_hours[0] =
cpu_to_le64((((current_ms - n->starttime_ms) / 1000) / 60) / 60);
+ if (!rae) {
+ nvme_clear_events(n, NVME_AER_TYPE_SMART);
+ }
+
return nvme_dma_read_prp(n, (uint8_t *) &smart + off, trans_len, prp1,
prp2);
}
@@ -667,14 +751,19 @@ static uint16_t nvme_fw_log_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
prp2);
}
-static uint16_t nvme_error_info(NvmeCtrl *n, NvmeCmd *cmd, uint32_t buf_len,
- uint64_t off, NvmeRequest *req)
+static uint16_t nvme_error_info(NvmeCtrl *n, NvmeCmd *cmd, uint8_t rae,
+ uint32_t buf_len, uint64_t off,
+ NvmeRequest *req)
{
uint32_t trans_len;
uint64_t prp1 = le64_to_cpu(cmd->dptr.prp1);
uint64_t prp2 = le64_to_cpu(cmd->dptr.prp2);
NvmeErrorLog errlog;
+ if (!rae) {
+ nvme_clear_events(n, NVME_AER_TYPE_ERROR);
+ }
+
if (off > sizeof(errlog)) {
return NVME_INVALID_FIELD | NVME_DNR;
}
@@ -715,9 +804,9 @@ static uint16_t nvme_get_log(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
switch (lid) {
case NVME_LOG_ERROR_INFO:
- return nvme_error_info(n, cmd, len, off, req);
+ return nvme_error_info(n, cmd, rae, len, off, req);
case NVME_LOG_SMART_INFO:
- return nvme_smart_info(n, cmd, len, off, req);
+ return nvme_smart_info(n, cmd, rae, len, off, req);
case NVME_LOG_FW_SLOT_INFO:
return nvme_fw_log_info(n, cmd, len, off, req);
default:
@@ -999,6 +1088,9 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
((n->params.max_ioqpairs - 1) << 16));
trace_pci_nvme_getfeat_numq(result);
break;
+ case NVME_ASYNCHRONOUS_EVENT_CONF:
+ result = cpu_to_le32(n->features.async_config);
+ break;
case NVME_TIMESTAMP:
return nvme_get_feature_timestamp(n, cmd);
default:
@@ -1050,6 +1142,14 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
return NVME_INVALID_FIELD | NVME_DNR;
}
+ if (((n->temperature >= n->features.temp_thresh_hi) ||
+ (n->temperature <= n->features.temp_thresh_low)) &&
+ NVME_AEC_SMART(n->features.async_config) & NVME_SMART_TEMPERATURE) {
+ nvme_enqueue_event(n, NVME_AER_TYPE_SMART,
+ NVME_AER_INFO_SMART_TEMP_THRESH,
+ NVME_LOG_SMART_INFO);
+ }
+
break;
case NVME_VOLATILE_WRITE_CACHE:
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
@@ -1062,6 +1162,9 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
req->cqe.result = cpu_to_le32((n->params.max_ioqpairs - 1) |
((n->params.max_ioqpairs - 1) << 16));
break;
+ case NVME_ASYNCHRONOUS_EVENT_CONF:
+ n->features.async_config = dw11;
+ break;
case NVME_TIMESTAMP:
return nvme_set_feature_timestamp(n, cmd);
default:
@@ -1071,6 +1174,25 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
return NVME_SUCCESS;
}
+static uint16_t nvme_aer(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
+{
+ trace_pci_nvme_aer(nvme_cid(req));
+
+ if (n->outstanding_aers > n->params.aerl) {
+ trace_pci_nvme_aer_aerl_exceeded();
+ return NVME_AER_LIMIT_EXCEEDED;
+ }
+
+ n->aer_reqs[n->outstanding_aers] = req;
+ n->outstanding_aers++;
+
+ if (!QTAILQ_EMPTY(&n->aer_queue)) {
+ nvme_process_aers(n);
+ }
+
+ return NVME_NO_COMPLETE;
+}
+
static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
{
trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), cmd->opcode);
@@ -1094,6 +1216,8 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
return nvme_set_feature(n, cmd, req);
case NVME_ADM_CMD_GET_FEATURES:
return nvme_get_feature(n, cmd, req);
+ case NVME_ADM_CMD_ASYNC_EV_REQ:
+ return nvme_aer(n, cmd, req);
default:
trace_pci_nvme_err_invalid_admin_opc(cmd->opcode);
return NVME_INVALID_OPCODE | NVME_DNR;
@@ -1148,6 +1272,15 @@ static void nvme_clear_ctrl(NvmeCtrl *n)
}
}
+ while (!QTAILQ_EMPTY(&n->aer_queue)) {
+ NvmeAsyncEvent *event = QTAILQ_FIRST(&n->aer_queue);
+ QTAILQ_REMOVE(&n->aer_queue, event, entry);
+ g_free(event);
+ }
+
+ n->aer_queued = 0;
+ n->outstanding_aers = 0;
+
blk_flush(n->conf.blk);
n->bar.cc = 0;
}
@@ -1244,6 +1377,8 @@ static int nvme_start_ctrl(NvmeCtrl *n)
nvme_set_timestamp(n, 0ULL);
+ QTAILQ_INIT(&n->aer_queue);
+
return 0;
}
@@ -1465,6 +1600,13 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
"completion queue doorbell write"
" for nonexistent queue,"
" sqid=%"PRIu32", ignoring", qid);
+
+ if (n->outstanding_aers) {
+ nvme_enqueue_event(n, NVME_AER_TYPE_ERROR,
+ NVME_AER_INFO_ERR_INVALID_DB_REGISTER,
+ NVME_LOG_ERROR_INFO);
+ }
+
return;
}
@@ -1475,6 +1617,13 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
" beyond queue size, sqid=%"PRIu32","
" new_head=%"PRIu16", ignoring",
qid, new_head);
+
+ if (n->outstanding_aers) {
+ nvme_enqueue_event(n, NVME_AER_TYPE_ERROR,
+ NVME_AER_INFO_ERR_INVALID_DB_VALUE,
+ NVME_LOG_ERROR_INFO);
+ }
+
return;
}
@@ -1505,6 +1654,13 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
"submission queue doorbell write"
" for nonexistent queue,"
" sqid=%"PRIu32", ignoring", qid);
+
+ if (n->outstanding_aers) {
+ nvme_enqueue_event(n, NVME_AER_TYPE_ERROR,
+ NVME_AER_INFO_ERR_INVALID_DB_REGISTER,
+ NVME_LOG_ERROR_INFO);
+ }
+
return;
}
@@ -1515,6 +1671,13 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
" beyond queue size, sqid=%"PRIu32","
" new_tail=%"PRIu16", ignoring",
qid, new_tail);
+
+ if (n->outstanding_aers) {
+ nvme_enqueue_event(n, NVME_AER_TYPE_ERROR,
+ NVME_AER_INFO_ERR_INVALID_DB_VALUE,
+ NVME_LOG_ERROR_INFO);
+ }
+
return;
}
@@ -1636,6 +1799,7 @@ static void nvme_init_state(NvmeCtrl *n)
n->temperature = NVME_TEMPERATURE;
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);
}
static void nvme_init_blk(NvmeCtrl *n, Error **errp)
@@ -1791,6 +1955,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
* inconsequential.
*/
id->acl = 3;
+ id->aerl = n->params.aerl;
id->frmw = (NVME_NUM_FW_SLOTS << 1) | NVME_FRMW_SLOT1_RO;
id->lpa = NVME_LPA_EXTENDED;
@@ -1865,6 +2030,7 @@ static void nvme_exit(PCIDevice *pci_dev)
g_free(n->namespaces);
g_free(n->cq);
g_free(n->sq);
+ g_free(n->aer_reqs);
if (n->params.cmb_size_mb) {
g_free(n->cmbuf);
@@ -1885,6 +2051,8 @@ static Property nvme_props[] = {
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, params.num_queues, 0),
DEFINE_PROP_UINT32("max_ioqpairs", NvmeCtrl, params.max_ioqpairs, 64),
DEFINE_PROP_UINT16("msix_qsize", NvmeCtrl, params.msix_qsize, 65),
+ DEFINE_PROP_UINT8("aerl", NvmeCtrl, params.aerl, 3),
+ DEFINE_PROP_UINT32("aer_max_queued", NvmeCtrl, params.aer_max_queued, 64),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 3ddbc3722d7c..1f64a0e94035 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -9,10 +9,12 @@ typedef struct NvmeParams {
uint32_t max_ioqpairs;
uint16_t msix_qsize;
uint32_t cmb_size_mb;
+ uint8_t aerl;
+ uint32_t aer_max_queued;
} NvmeParams;
typedef struct NvmeAsyncEvent {
- QSIMPLEQ_ENTRY(NvmeAsyncEvent) entry;
+ QTAILQ_ENTRY(NvmeAsyncEvent) entry;
NvmeAerResult result;
} NvmeAsyncEvent;
@@ -94,6 +96,7 @@ typedef struct NvmeCtrl {
uint32_t num_namespaces;
uint32_t max_q_ents;
uint64_t ns_size;
+ uint8_t outstanding_aers;
uint8_t *cmbuf;
uint32_t irq_status;
uint64_t host_timestamp; /* Timestamp sent by the host */
@@ -103,6 +106,11 @@ typedef struct NvmeCtrl {
HostMemoryBackend *pmrdev;
+ uint8_t aer_mask;
+ NvmeRequest **aer_reqs;
+ QTAILQ_HEAD(, NvmeAsyncEvent) aer_queue;
+ int aer_queued;
+
NvmeNamespace *namespaces;
NvmeSQueue **sq;
NvmeCQueue **cq;
diff --git a/hw/block/trace-events b/hw/block/trace-events
index 3330d74e48db..091af16ca7d7 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -51,6 +51,15 @@ pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64""
pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64""
+pci_nvme_process_aers(int queued) "queued %d"
+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_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""
+pci_nvme_no_outstanding_aers(void) "ignoring event; no outstanding AERs"
pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16""
pci_nvme_mmio_read(uint64_t addr) "addr 0x%"PRIx64""
pci_nvme_mmio_write(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64""
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 49ce97ae1ab4..2101292ed5e8 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -597,8 +597,8 @@ enum NvmeAsyncEventRequest {
NVME_AER_TYPE_SMART = 1,
NVME_AER_TYPE_IO_SPECIFIC = 6,
NVME_AER_TYPE_VENDOR_SPECIFIC = 7,
- NVME_AER_INFO_ERR_INVALID_SQ = 0,
- NVME_AER_INFO_ERR_INVALID_DB = 1,
+ NVME_AER_INFO_ERR_INVALID_DB_REGISTER = 0,
+ NVME_AER_INFO_ERR_INVALID_DB_VALUE = 1,
NVME_AER_INFO_ERR_DIAG_FAIL = 2,
NVME_AER_INFO_ERR_PERS_INTERNAL_ERR = 3,
NVME_AER_INFO_ERR_TRANS_INTERNAL_ERR = 4,
@@ -899,6 +899,10 @@ typedef struct NvmeFeatureVal {
#define NVME_TEMP_TMPTH(temp) ((temp >> 0) & 0xffff)
+#define NVME_AEC_SMART(aec) (aec & 0xff)
+#define NVME_AEC_NS_ATTR(aec) ((aec >> 8) & 0x1)
+#define NVME_AEC_FW_ACTIVATION(aec) ((aec >> 9) & 0x1)
+
enum NvmeFeatureIds {
NVME_ARBITRATION = 0x1,
NVME_POWER_MANAGEMENT = 0x2,
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 08/18] hw/block/nvme: move NvmeFeatureVal into hw/block/nvme.h
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (6 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 07/18] hw/block/nvme: add support for the asynchronous event request command Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 09/18] hw/block/nvme: flush write cache when disabled Klaus Jensen
` (9 subsequent siblings)
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
The NvmeFeatureVal does not belong with the spec-related data structures
in include/block/nvme.h that is shared between the block-level nvme
driver and the emulated nvme device.
Move it into the nvme device specific header file as it is the only
user of the structure. Also, remove the unused members.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.h | 8 ++++++++
include/block/nvme.h | 17 -----------------
2 files changed, 8 insertions(+), 17 deletions(-)
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 1f64a0e94035..f8940435f9ef 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -79,6 +79,14 @@ static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns)
#define NVME(obj) \
OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME)
+typedef struct NvmeFeatureVal {
+ struct {
+ uint16_t temp_thresh_hi;
+ uint16_t temp_thresh_low;
+ };
+ uint32_t async_config;
+} NvmeFeatureVal;
+
typedef struct NvmeCtrl {
PCIDevice parent_obj;
MemoryRegion iomem;
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 2101292ed5e8..0dce15af6bcf 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -865,23 +865,6 @@ enum NvmeIdCtrlLpa {
#define NVME_CTRL_SGLS_MPTR_SGL (0x1 << 19)
#define NVME_CTRL_SGLS_ADDR_OFFSET (0x1 << 20)
-typedef struct NvmeFeatureVal {
- uint32_t arbitration;
- uint32_t power_mgmt;
- struct {
- uint16_t temp_thresh_hi;
- uint16_t temp_thresh_low;
- };
- uint32_t err_rec;
- uint32_t volatile_wc;
- uint32_t num_queues;
- uint32_t int_coalescing;
- uint32_t *int_vector_config;
- uint32_t write_atomicity;
- uint32_t async_config;
- uint32_t sw_prog_marker;
-} NvmeFeatureVal;
-
#define NVME_ARB_AB(arb) (arb & 0x7)
#define NVME_ARB_LPW(arb) ((arb >> 8) & 0xff)
#define NVME_ARB_MPW(arb) ((arb >> 16) & 0xff)
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 09/18] hw/block/nvme: flush write cache when disabled
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (7 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 08/18] hw/block/nvme: move NvmeFeatureVal into hw/block/nvme.h Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 10/18] hw/block/nvme: fix missing endian conversion Klaus Jensen
` (8 subsequent siblings)
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
If the write cache is disabled with a Set Features command, flush it if
currently enabled.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 3eac1e231bf9..f3a5b857bc92 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -1152,6 +1152,10 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
break;
case NVME_VOLATILE_WRITE_CACHE:
+ if (!(dw11 & 0x1) && blk_enable_write_cache(n->conf.blk)) {
+ blk_flush(n->conf.blk);
+ }
+
blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
break;
case NVME_NUMBER_OF_QUEUES:
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 10/18] hw/block/nvme: fix missing endian conversion
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (8 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 09/18] hw/block/nvme: flush write cache when disabled Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 8:34 ` Philippe Mathieu-Daudé
2020-07-03 6:34 ` [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters Klaus Jensen
` (7 subsequent siblings)
17 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Fix a missing cpu_to conversion.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index f3a5b857bc92..ba523f6768bf 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -1080,7 +1080,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
break;
case NVME_VOLATILE_WRITE_CACHE:
- result = blk_enable_write_cache(n->conf.blk);
+ result = cpu_to_le32(blk_enable_write_cache(n->conf.blk));
trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
break;
case NVME_NUMBER_OF_QUEUES:
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (9 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 10/18] hw/block/nvme: fix missing endian conversion Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 8:31 ` Philippe Mathieu-Daudé
2020-07-03 6:34 ` [PATCH v2 12/18] hw/block/nvme: support the get/set features select and save fields Klaus Jensen
` (6 subsequent siblings)
17 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Add support for any remaining mandatory controller operating parameters
(features).
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 39 +++++++++++++++++++++++++++++++++------
hw/block/nvme.h | 18 ++++++++++++++++++
hw/block/trace-events | 2 ++
include/block/nvme.h | 7 +++++++
4 files changed, 60 insertions(+), 6 deletions(-)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index ba523f6768bf..affb9a967534 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -1056,8 +1056,16 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
uint32_t dw11 = le32_to_cpu(cmd->cdw11);
uint32_t result;
+ uint8_t fid = NVME_GETSETFEAT_FID(dw10);
+ uint16_t iv;
- switch (dw10) {
+ trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
+
+ if (!nvme_feature_support[fid]) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ switch (fid) {
case NVME_TEMPERATURE_THRESHOLD:
result = 0;
@@ -1088,14 +1096,27 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
((n->params.max_ioqpairs - 1) << 16));
trace_pci_nvme_getfeat_numq(result);
break;
+ case NVME_INTERRUPT_VECTOR_CONF:
+ iv = dw11 & 0xffff;
+ if (iv >= n->params.max_ioqpairs + 1) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ result = iv;
+ if (iv == n->admin_cq.vector) {
+ result |= NVME_INTVC_NOCOALESCING;
+ }
+
+ result = cpu_to_le32(result);
+ break;
case NVME_ASYNCHRONOUS_EVENT_CONF:
result = cpu_to_le32(n->features.async_config);
break;
case NVME_TIMESTAMP:
return nvme_get_feature_timestamp(n, cmd);
default:
- trace_pci_nvme_err_invalid_getfeat(dw10);
- return NVME_INVALID_FIELD | NVME_DNR;
+ result = cpu_to_le32(nvme_feature_default[fid]);
+ break;
}
req->cqe.result = result;
@@ -1124,8 +1145,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
{
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
uint32_t dw11 = le32_to_cpu(cmd->cdw11);
+ uint8_t fid = NVME_GETSETFEAT_FID(dw10);
- switch (dw10) {
+ trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
+
+ if (!nvme_feature_support[fid]) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
+ switch (fid) {
case NVME_TEMPERATURE_THRESHOLD:
if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
break;
@@ -1172,8 +1200,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
case NVME_TIMESTAMP:
return nvme_set_feature_timestamp(n, cmd);
default:
- trace_pci_nvme_err_invalid_setfeat(dw10);
- return NVME_INVALID_FIELD | NVME_DNR;
+ return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
}
return NVME_SUCCESS;
}
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index f8940435f9ef..8ad1e3c89cee 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -87,6 +87,24 @@ typedef struct NvmeFeatureVal {
uint32_t async_config;
} NvmeFeatureVal;
+static const uint32_t nvme_feature_default[0x100] = {
+ [NVME_ARBITRATION] = NVME_ARB_AB_NOLIMIT,
+};
+
+static const bool nvme_feature_support[0x100] = {
+ [NVME_ARBITRATION] = true,
+ [NVME_POWER_MANAGEMENT] = true,
+ [NVME_TEMPERATURE_THRESHOLD] = true,
+ [NVME_ERROR_RECOVERY] = true,
+ [NVME_VOLATILE_WRITE_CACHE] = true,
+ [NVME_NUMBER_OF_QUEUES] = true,
+ [NVME_INTERRUPT_COALESCING] = true,
+ [NVME_INTERRUPT_VECTOR_CONF] = true,
+ [NVME_WRITE_ATOMICITY] = true,
+ [NVME_ASYNCHRONOUS_EVENT_CONF] = true,
+ [NVME_TIMESTAMP] = true,
+};
+
typedef struct NvmeCtrl {
PCIDevice parent_obj;
MemoryRegion iomem;
diff --git a/hw/block/trace-events b/hw/block/trace-events
index 091af16ca7d7..42e62f4649f8 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -46,6 +46,8 @@ pci_nvme_identify_ctrl(void) "identify controller"
pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
+pci_nvme_getfeat(uint16_t cid, uint8_t fid, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" cdw11 0x%"PRIx32""
+pci_nvme_setfeat(uint16_t cid, uint8_t fid, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" cdw11 0x%"PRIx32""
pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 0dce15af6bcf..406648d4cf94 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -662,6 +662,7 @@ enum NvmeStatusCodes {
NVME_FW_REQ_RESET = 0x010b,
NVME_INVALID_QUEUE_DEL = 0x010c,
NVME_FID_NOT_SAVEABLE = 0x010d,
+ NVME_FEAT_NOT_CHANGEABLE = 0x010e,
NVME_FID_NOT_NSID_SPEC = 0x010f,
NVME_FW_REQ_SUSYSTEM_RESET = 0x0110,
NVME_CONFLICTING_ATTRS = 0x0180,
@@ -866,6 +867,7 @@ enum NvmeIdCtrlLpa {
#define NVME_CTRL_SGLS_ADDR_OFFSET (0x1 << 20)
#define NVME_ARB_AB(arb) (arb & 0x7)
+#define NVME_ARB_AB_NOLIMIT 0x7
#define NVME_ARB_LPW(arb) ((arb >> 8) & 0xff)
#define NVME_ARB_MPW(arb) ((arb >> 16) & 0xff)
#define NVME_ARB_HPW(arb) ((arb >> 24) & 0xff)
@@ -873,6 +875,8 @@ enum NvmeIdCtrlLpa {
#define NVME_INTC_THR(intc) (intc & 0xff)
#define NVME_INTC_TIME(intc) ((intc >> 8) & 0xff)
+#define NVME_INTVC_NOCOALESCING (0x1 << 16)
+
#define NVME_TEMP_THSEL(temp) ((temp >> 20) & 0x3)
#define NVME_TEMP_THSEL_OVER 0x0
#define NVME_TEMP_THSEL_UNDER 0x1
@@ -902,6 +906,9 @@ enum NvmeFeatureIds {
NVME_SOFTWARE_PROGRESS_MARKER = 0x80
};
+#define NVME_GETSETFEAT_FID_MASK 0xff
+#define NVME_GETSETFEAT_FID(dw10) (dw10 & NVME_GETSETFEAT_FID_MASK)
+
typedef struct NvmeRangeType {
uint8_t type;
uint8_t attributes;
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 12/18] hw/block/nvme: support the get/set features select and save fields
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (10 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 13/18] hw/block/nvme: make sure ncqr and nsqr is valid Klaus Jensen
` (5 subsequent siblings)
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Since the device does not have any persistent state storage, no
features are "saveable" and setting the Save (SV) field in any Set
Features command will result in a Feature Identifier Not Saveable status
code.
Similarly, if the Select (SEL) field is set to request saved values, the
devices will (as it should) return the default values instead.
Since this also introduces "Supported Capabilities", the nsid field is
now also checked for validity wrt. the feature being get/set'ed.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
hw/block/nvme.c | 95 +++++++++++++++++++++++++++++++++++++------
hw/block/nvme.h | 8 ++++
hw/block/trace-events | 4 +-
include/block/nvme.h | 27 +++++++++++-
4 files changed, 119 insertions(+), 15 deletions(-)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index affb9a967534..9cff0f45dd7e 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -1055,16 +1055,43 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
{
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
uint32_t dw11 = le32_to_cpu(cmd->cdw11);
+ uint32_t nsid = le32_to_cpu(cmd->nsid);
uint32_t result;
uint8_t fid = NVME_GETSETFEAT_FID(dw10);
+ NvmeGetFeatureSelect sel = NVME_GETFEAT_SELECT(dw10);
uint16_t iv;
- trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
+ trace_pci_nvme_getfeat(nvme_cid(req), fid, sel, dw11);
if (!nvme_feature_support[fid]) {
return NVME_INVALID_FIELD | NVME_DNR;
}
+ if (nvme_feature_cap[fid] & NVME_FEAT_CAP_NS) {
+ if (!nsid || nsid > n->num_namespaces) {
+ /*
+ * The Reservation Notification Mask and Reservation Persistence
+ * features require a status code of Invalid Field in Command when
+ * NSID is 0xFFFFFFFF. Since the device does not support those
+ * features we can always return Invalid Namespace or Format as we
+ * should do for all other features.
+ */
+ return NVME_INVALID_NSID | NVME_DNR;
+ }
+ }
+
+ switch (sel) {
+ case NVME_GETFEAT_SELECT_CURRENT:
+ break;
+ case NVME_GETFEAT_SELECT_SAVED:
+ /* no features are saveable by the controller; fallthrough */
+ case NVME_GETFEAT_SELECT_DEFAULT:
+ goto defaults;
+ case NVME_GETFEAT_SELECT_CAP:
+ result = cpu_to_le32(nvme_feature_cap[fid]);
+ goto out;
+ }
+
switch (fid) {
case NVME_TEMPERATURE_THRESHOLD:
result = 0;
@@ -1074,22 +1101,45 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
* return 0 for all other sensors.
*/
if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
- break;
+ goto out;
}
switch (NVME_TEMP_THSEL(dw11)) {
case NVME_TEMP_THSEL_OVER:
result = cpu_to_le16(n->features.temp_thresh_hi);
- break;
+ goto out;
case NVME_TEMP_THSEL_UNDER:
result = cpu_to_le16(n->features.temp_thresh_low);
- break;
+ goto out;
}
- break;
+ return NVME_INVALID_FIELD | NVME_DNR;
case NVME_VOLATILE_WRITE_CACHE:
result = cpu_to_le32(blk_enable_write_cache(n->conf.blk));
trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
+ goto out;
+ case NVME_ASYNCHRONOUS_EVENT_CONF:
+ result = cpu_to_le32(n->features.async_config);
+ goto out;
+ case NVME_TIMESTAMP:
+ return nvme_get_feature_timestamp(n, cmd);
+ default:
+ break;
+ }
+
+defaults:
+ switch (fid) {
+ case NVME_TEMPERATURE_THRESHOLD:
+ result = 0;
+
+ if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
+ break;
+ }
+
+ if (NVME_TEMP_THSEL(dw11) == NVME_TEMP_THSEL_OVER) {
+ result = cpu_to_le16(NVME_TEMPERATURE_WARNING);
+ }
+
break;
case NVME_NUMBER_OF_QUEUES:
result = cpu_to_le32((n->params.max_ioqpairs - 1) |
@@ -1109,16 +1159,12 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
result = cpu_to_le32(result);
break;
- case NVME_ASYNCHRONOUS_EVENT_CONF:
- result = cpu_to_le32(n->features.async_config);
- break;
- case NVME_TIMESTAMP:
- return nvme_get_feature_timestamp(n, cmd);
default:
result = cpu_to_le32(nvme_feature_default[fid]);
break;
}
+out:
req->cqe.result = result;
return NVME_SUCCESS;
}
@@ -1145,14 +1191,37 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
{
uint32_t dw10 = le32_to_cpu(cmd->cdw10);
uint32_t dw11 = le32_to_cpu(cmd->cdw11);
+ uint32_t nsid = le32_to_cpu(cmd->nsid);
uint8_t fid = NVME_GETSETFEAT_FID(dw10);
+ uint8_t save = NVME_SETFEAT_SAVE(dw10);
- trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
+ trace_pci_nvme_setfeat(nvme_cid(req), fid, save, dw11);
+
+ if (save) {
+ return NVME_FID_NOT_SAVEABLE | NVME_DNR;
+ }
if (!nvme_feature_support[fid]) {
return NVME_INVALID_FIELD | NVME_DNR;
}
+ if (nvme_feature_cap[fid] & NVME_FEAT_CAP_NS) {
+ if (!nsid || (nsid != NVME_NSID_BROADCAST &&
+ nsid > n->num_namespaces)) {
+ return NVME_INVALID_NSID | NVME_DNR;
+ }
+ } else if (nsid && nsid != NVME_NSID_BROADCAST) {
+ if (nsid > n->num_namespaces) {
+ return NVME_INVALID_NSID | NVME_DNR;
+ }
+
+ return NVME_FEAT_NOT_NS_SPEC | NVME_DNR;
+ }
+
+ if (!(nvme_feature_cap[fid] & NVME_FEAT_CAP_CHANGE)) {
+ return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
+ }
+
switch (fid) {
case NVME_TEMPERATURE_THRESHOLD:
if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
@@ -1997,7 +2066,9 @@ 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_ZEROS | NVME_ONCS_TIMESTAMP);
+ id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS | NVME_ONCS_TIMESTAMP |
+ NVME_ONCS_FEATURES);
+
id->psd[0].mp = cpu_to_le16(0x9c4);
id->psd[0].enlat = cpu_to_le32(0x10);
id->psd[0].exlat = cpu_to_le32(0x4);
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 8ad1e3c89cee..450e4294193a 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -87,6 +87,14 @@ typedef struct NvmeFeatureVal {
uint32_t async_config;
} NvmeFeatureVal;
+static const uint32_t nvme_feature_cap[0x100] = {
+ [NVME_TEMPERATURE_THRESHOLD] = NVME_FEAT_CAP_CHANGE,
+ [NVME_VOLATILE_WRITE_CACHE] = NVME_FEAT_CAP_CHANGE,
+ [NVME_NUMBER_OF_QUEUES] = NVME_FEAT_CAP_CHANGE,
+ [NVME_ASYNCHRONOUS_EVENT_CONF] = NVME_FEAT_CAP_CHANGE,
+ [NVME_TIMESTAMP] = NVME_FEAT_CAP_CHANGE,
+};
+
static const uint32_t nvme_feature_default[0x100] = {
[NVME_ARBITRATION] = NVME_ARB_AB_NOLIMIT,
};
diff --git a/hw/block/trace-events b/hw/block/trace-events
index 42e62f4649f8..4a4ef34071df 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -46,8 +46,8 @@ pci_nvme_identify_ctrl(void) "identify controller"
pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
-pci_nvme_getfeat(uint16_t cid, uint8_t fid, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" cdw11 0x%"PRIx32""
-pci_nvme_setfeat(uint16_t cid, uint8_t fid, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" cdw11 0x%"PRIx32""
+pci_nvme_getfeat(uint16_t cid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32""
+pci_nvme_setfeat(uint16_t cid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32""
pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
diff --git a/include/block/nvme.h b/include/block/nvme.h
index 406648d4cf94..36f7d76b3926 100644
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -663,7 +663,7 @@ enum NvmeStatusCodes {
NVME_INVALID_QUEUE_DEL = 0x010c,
NVME_FID_NOT_SAVEABLE = 0x010d,
NVME_FEAT_NOT_CHANGEABLE = 0x010e,
- NVME_FID_NOT_NSID_SPEC = 0x010f,
+ NVME_FEAT_NOT_NS_SPEC = 0x010f,
NVME_FW_REQ_SUSYSTEM_RESET = 0x0110,
NVME_CONFLICTING_ATTRS = 0x0180,
NVME_INVALID_PROT_INFO = 0x0181,
@@ -906,9 +906,32 @@ enum NvmeFeatureIds {
NVME_SOFTWARE_PROGRESS_MARKER = 0x80
};
+typedef enum NvmeFeatureCap {
+ NVME_FEAT_CAP_SAVE = 1 << 0,
+ NVME_FEAT_CAP_NS = 1 << 1,
+ NVME_FEAT_CAP_CHANGE = 1 << 2,
+} NvmeFeatureCap;
+
+typedef enum NvmeGetFeatureSelect {
+ NVME_GETFEAT_SELECT_CURRENT = 0x0,
+ NVME_GETFEAT_SELECT_DEFAULT = 0x1,
+ NVME_GETFEAT_SELECT_SAVED = 0x2,
+ NVME_GETFEAT_SELECT_CAP = 0x3,
+} NvmeGetFeatureSelect;
+
#define NVME_GETSETFEAT_FID_MASK 0xff
#define NVME_GETSETFEAT_FID(dw10) (dw10 & NVME_GETSETFEAT_FID_MASK)
+#define NVME_GETFEAT_SELECT_SHIFT 8
+#define NVME_GETFEAT_SELECT_MASK 0x7
+#define NVME_GETFEAT_SELECT(dw10) \
+ ((dw10 >> NVME_GETFEAT_SELECT_SHIFT) & NVME_GETFEAT_SELECT_MASK)
+
+#define NVME_SETFEAT_SAVE_SHIFT 31
+#define NVME_SETFEAT_SAVE_MASK 0x1
+#define NVME_SETFEAT_SAVE(dw10) \
+ ((dw10 >> NVME_SETFEAT_SAVE_SHIFT) & NVME_SETFEAT_SAVE_MASK)
+
typedef struct NvmeRangeType {
uint8_t type;
uint8_t attributes;
@@ -925,6 +948,8 @@ typedef struct NvmeLBAF {
uint8_t rp;
} NvmeLBAF;
+#define NVME_NSID_BROADCAST 0xffffffff
+
typedef struct NvmeIdNs {
uint64_t nsze;
uint64_t ncap;
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 13/18] hw/block/nvme: make sure ncqr and nsqr is valid
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (11 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 12/18] hw/block/nvme: support the get/set features select and save fields Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 14/18] hw/block/nvme: support identify namespace descriptor list Klaus Jensen
` (4 subsequent siblings)
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
0xffff is not an allowed value for NCQR and NSQR in Set Features on
Number of Queues.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Acked-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 9cff0f45dd7e..8230e0e3826b 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -1256,6 +1256,14 @@ 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:
+ /*
+ * NVMe v1.3, Section 5.21.1.7: 0xffff is not an allowed value for NCQR
+ * and NSQR.
+ */
+ if ((dw11 & 0xffff) == 0xffff || ((dw11 >> 16) & 0xffff) == 0xffff) {
+ return NVME_INVALID_FIELD | NVME_DNR;
+ }
+
trace_pci_nvme_setfeat_numq((dw11 & 0xFFFF) + 1,
((dw11 >> 16) & 0xFFFF) + 1,
n->params.max_ioqpairs,
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 14/18] hw/block/nvme: support identify namespace descriptor list
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (12 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 13/18] hw/block/nvme: make sure ncqr and nsqr is valid Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 8:27 ` Philippe Mathieu-Daudé
2020-07-03 6:34 ` [PATCH v2 15/18] hw/block/nvme: reject invalid nsid values in active namespace id list Klaus Jensen
` (3 subsequent siblings)
17 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Since we are not providing the NGUID or EUI64 fields, we must support
the Namespace UUID. We do not have any way of storing a persistent
unique identifier, so conjure up a UUID that is just the namespace id.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 41 +++++++++++++++++++++++++++++++++++++++++
hw/block/trace-events | 1 +
2 files changed, 42 insertions(+)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 8230e0e3826b..65c2fa3ac1f4 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -971,6 +971,45 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
return ret;
}
+static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeIdentify *c)
+{
+ uint32_t nsid = le32_to_cpu(c->nsid);
+ uint64_t prp1 = le64_to_cpu(c->prp1);
+ uint64_t prp2 = le64_to_cpu(c->prp2);
+
+ uint8_t list[NVME_IDENTIFY_DATA_SIZE];
+
+ struct data {
+ struct {
+ NvmeIdNsDescr hdr;
+ uint8_t v[16];
+ } uuid;
+ };
+
+ struct data *ns_descrs = (struct data *)list;
+
+ trace_pci_nvme_identify_ns_descr_list(nsid);
+
+ if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
+ trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces);
+ return NVME_INVALID_NSID | NVME_DNR;
+ }
+
+ memset(list, 0x0, sizeof(list));
+
+ /*
+ * Because the NGUID and EUI64 fields are 0 in the Identify Namespace data
+ * structure, a Namespace UUID (nidt = 0x3) must be reported in the
+ * Namespace Identification Descriptor. Add a very basic Namespace UUID
+ * here.
+ */
+ ns_descrs->uuid.hdr.nidt = NVME_NIDT_UUID;
+ ns_descrs->uuid.hdr.nidl = NVME_NIDT_UUID_LEN;
+ stl_be_p(&ns_descrs->uuid.v, nsid);
+
+ return nvme_dma_read_prp(n, list, NVME_IDENTIFY_DATA_SIZE, prp1, prp2);
+}
+
static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
{
NvmeIdentify *c = (NvmeIdentify *)cmd;
@@ -982,6 +1021,8 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
return nvme_identify_ctrl(n, c);
case NVME_ID_CNS_NS_ACTIVE_LIST:
return nvme_identify_nslist(n, c);
+ case NVME_ID_CNS_NS_DESCR_LIST:
+ return nvme_identify_ns_descr_list(n, c);
default:
trace_pci_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns));
return NVME_INVALID_FIELD | NVME_DNR;
diff --git a/hw/block/trace-events b/hw/block/trace-events
index 4a4ef34071df..7b7303cab1dd 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -45,6 +45,7 @@ pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16""
pci_nvme_identify_ctrl(void) "identify controller"
pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
+pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32""
pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
pci_nvme_getfeat(uint16_t cid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32""
pci_nvme_setfeat(uint16_t cid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32""
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 15/18] hw/block/nvme: reject invalid nsid values in active namespace id list
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (13 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 14/18] hw/block/nvme: support identify namespace descriptor list Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 8:20 ` Philippe Mathieu-Daudé
2020-07-03 6:34 ` [PATCH v2 16/18] hw/block/nvme: enforce valid queue creation sequence Klaus Jensen
` (2 subsequent siblings)
17 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Reject the nsid broadcast value (0xffffffff) and 0xfffffffe in the
Active Namespace ID list.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
hw/block/nvme.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 65c2fa3ac1f4..0dac7a41ddae 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -956,6 +956,10 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
trace_pci_nvme_identify_nslist(min_nsid);
+ if (min_nsid == 0xfffffffe || min_nsid == NVME_NSID_BROADCAST) {
+ return NVME_INVALID_NSID | NVME_DNR;
+ }
+
list = g_malloc0(data_len);
for (i = 0; i < n->num_namespaces; i++) {
if (i < min_nsid) {
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 16/18] hw/block/nvme: enforce valid queue creation sequence
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (14 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 15/18] hw/block/nvme: reject invalid nsid values in active namespace id list Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 17/18] hw/block/nvme: provide the mandatory subnqn field Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 18/18] hw/block/nvme: bump supported version to v1.3 Klaus Jensen
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
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>
---
hw/block/nvme.c | 12 ++++++++++++
hw/block/nvme.h | 1 +
2 files changed, 13 insertions(+)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 0dac7a41ddae..8138baa6fbd8 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -910,6 +910,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;
}
@@ -1301,6 +1308,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.
@@ -1433,6 +1444,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;
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index 450e4294193a..668d2cd3df16 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -121,6 +121,7 @@ typedef struct NvmeCtrl {
BlockConf conf;
NvmeParams params;
+ bool qs_created;
uint32_t page_size;
uint16_t page_bits;
uint16_t max_prp_ents;
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 17/18] hw/block/nvme: provide the mandatory subnqn field
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (15 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 16/18] hw/block/nvme: enforce valid queue creation sequence Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
2020-07-03 8:18 ` Philippe Mathieu-Daudé
2020-07-03 6:34 ` [PATCH v2 18/18] hw/block/nvme: bump supported version to v1.3 Klaus Jensen
17 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
The SUBNQN field is mandatory in NVM Express 1.3.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 8138baa6fbd8..5bbb6aa0efc3 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -2134,6 +2134,9 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS | NVME_ONCS_TIMESTAMP |
NVME_ONCS_FEATURES);
+ pstrcpy((char *) id->subnqn, sizeof(id->subnqn), "nqn.2019-08.org.qemu:");
+ pstrcat((char *) id->subnqn, sizeof(id->subnqn), n->params.serial);
+
id->psd[0].mp = cpu_to_le16(0x9c4);
id->psd[0].enlat = cpu_to_le32(0x10);
id->psd[0].exlat = cpu_to_le32(0x4);
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* [PATCH v2 18/18] hw/block/nvme: bump supported version to v1.3
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
` (16 preceding siblings ...)
2020-07-03 6:34 ` [PATCH v2 17/18] hw/block/nvme: provide the mandatory subnqn field Klaus Jensen
@ 2020-07-03 6:34 ` Klaus Jensen
17 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 6:34 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Klaus Jensen, Keith Busch, Javier Gonzalez, Maxim Levitsky,
Philippe Mathieu-Daudé
From: Klaus Jensen <k.jensen@samsung.com>
Bump the supported NVM Express version to v1.3.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
---
hw/block/nvme.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 5bbb6aa0efc3..204032aac2c8 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -57,6 +57,7 @@
#define NVME_MAX_IOQPAIRS 0xffff
#define NVME_REG_SIZE 0x1000
#define NVME_DB_SIZE 4
+#define NVME_SPEC_VER 0x00010300
#define NVME_CMB_BIR 2
#define NVME_PMR_BIR 2
#define NVME_TEMPERATURE 0x143
@@ -2106,6 +2107,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
id->ieee[0] = 0x00;
id->ieee[1] = 0x02;
id->ieee[2] = 0xb3;
+ id->ver = cpu_to_le32(NVME_SPEC_VER);
id->oacs = cpu_to_le16(0);
/*
@@ -2151,7 +2153,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
NVME_CAP_SET_CSS(n->bar.cap, 1);
NVME_CAP_SET_MPSMAX(n->bar.cap, 4);
- n->bar.vs = 0x00010200;
+ n->bar.vs = NVME_SPEC_VER;
n->bar.intmc = n->bar.intms = 0;
}
--
2.27.0
^ permalink raw reply related [flat|nested] 42+ messages in thread
* Re: [PATCH v2 02/18] hw/block/nvme: additional tracing
2020-07-03 6:34 ` [PATCH v2 02/18] hw/block/nvme: additional tracing Klaus Jensen
@ 2020-07-03 8:03 ` Philippe Mathieu-Daudé
2020-07-03 8:14 ` Klaus Jensen
0 siblings, 1 reply; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 8:03 UTC (permalink / raw)
To: Klaus Jensen, qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez, Maxim Levitsky
On 7/3/20 8:34 AM, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen@samsung.com>
>
> Add various additional tracing and streamline nvme_identify_ns and
> nvme_identify_nslist (they do not need to repeat the command, it is
> already in the trace name).
>
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> ---
> hw/block/nvme.c | 19 +++++++++++++++++++
> hw/block/nvme.h | 14 ++++++++++++++
> hw/block/trace-events | 13 +++++++++++--
> 3 files changed, 44 insertions(+), 2 deletions(-)
>
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 71b388aa0e20..f5d9148f0936 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -331,6 +331,8 @@ static void nvme_post_cqes(void *opaque)
> static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req)
> {
> assert(cq->cqid == req->sq->cqid);
> + trace_pci_nvme_enqueue_req_completion(nvme_cid(req), cq->cqid,
> + req->status);
> QTAILQ_REMOVE(&req->sq->out_req_list, req, entry);
> QTAILQ_INSERT_TAIL(&cq->req_list, req, entry);
> timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
> @@ -343,6 +345,8 @@ static void nvme_rw_cb(void *opaque, int ret)
> NvmeCtrl *n = sq->ctrl;
> NvmeCQueue *cq = n->cq[sq->cqid];
>
> + trace_pci_nvme_rw_cb(nvme_cid(req));
> +
> if (!ret) {
> block_acct_done(blk_get_stats(n->conf.blk), &req->acct);
> req->status = NVME_SUCCESS;
> @@ -378,6 +382,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
> uint64_t offset = slba << data_shift;
> uint32_t count = nlb << data_shift;
>
> + trace_pci_nvme_write_zeroes(nvme_cid(req), slba, nlb);
> +
> if (unlikely(slba + nlb > ns->id_ns.nsze)) {
> trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
> return NVME_LBA_RANGE | NVME_DNR;
> @@ -445,6 +451,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> NvmeNamespace *ns;
> uint32_t nsid = le32_to_cpu(cmd->nsid);
>
> + trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req), cmd->opcode);
> +
> if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
> trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces);
> return NVME_INVALID_NSID | NVME_DNR;
> @@ -876,6 +884,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>
> static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> {
> + trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), cmd->opcode);
> +
> switch (cmd->opcode) {
> case NVME_ADM_CMD_DELETE_SQ:
> return nvme_del_sq(n, cmd);
> @@ -1204,6 +1214,8 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
> uint8_t *ptr = (uint8_t *)&n->bar;
> uint64_t val = 0;
>
> + trace_pci_nvme_mmio_read(addr);
> +
> if (unlikely(addr & (sizeof(uint32_t) - 1))) {
> NVME_GUEST_ERR(pci_nvme_ub_mmiord_misaligned32,
> "MMIO read not 32-bit aligned,"
> @@ -1273,6 +1285,8 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
> return;
> }
>
> + trace_pci_nvme_mmio_doorbell_cq(cq->cqid, new_head);
> +
> start_sqs = nvme_cq_full(cq) ? 1 : 0;
> cq->head = new_head;
> if (start_sqs) {
> @@ -1311,6 +1325,8 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
> return;
> }
>
> + trace_pci_nvme_mmio_doorbell_sq(sq->sqid, new_tail);
> +
> sq->tail = new_tail;
> timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
> }
> @@ -1320,6 +1336,9 @@ static void nvme_mmio_write(void *opaque, hwaddr addr, uint64_t data,
> unsigned size)
> {
> NvmeCtrl *n = (NvmeCtrl *)opaque;
> +
> + trace_pci_nvme_mmio_write(addr, data);
> +
> if (addr < sizeof(n->bar)) {
> nvme_write_bar(n, addr, data, size);
> } else if (addr >= 0x1000) {
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index 1d30c0bca283..1bf5c80ed843 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -115,4 +115,18 @@ static inline uint64_t nvme_ns_nlbas(NvmeCtrl *n, NvmeNamespace *ns)
> return n->ns_size >> nvme_ns_lbads(ns);
> }
>
> +static inline uint16_t nvme_cid(NvmeRequest *req)
> +{
> + if (req) {
> + return le16_to_cpu(req->cqe.cid);
> + }
> +
> + return 0xffff;
In this case I find the inverted logic easier. Matter
of taste :)
> +}
> +
> +static inline uint16_t nvme_sqid(NvmeRequest *req)
> +{
> + return le16_to_cpu(req->sq->sqid);
> +}
Later I'd prefer we move these out of the header, and remove
the inline attribute.
I.e. nvme_ns_nlbas() is only used once.
OK for now.
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> +
> #endif /* HW_NVME_H */
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index 958fcc5508d1..c40c0d2e4b28 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -33,19 +33,28 @@ pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
> pci_nvme_irq_pin(void) "pulsing IRQ pin"
> pci_nvme_irq_masked(void) "IRQ is masked"
> pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
> +pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8""
> +pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8""
> pci_nvme_rw(const char *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64""
> +pci_nvme_rw_cb(uint16_t cid) "cid %"PRIu16""
> +pci_nvme_write_zeroes(uint16_t cid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" slba %"PRIu64" nlb %"PRIu32""
> pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16""
> pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d"
> pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
> pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16""
> pci_nvme_identify_ctrl(void) "identify controller"
> -pci_nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16""
> -pci_nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
> +pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
> +pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
> pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
> pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
> pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
> pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64""
> pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64""
> +pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16""
> +pci_nvme_mmio_read(uint64_t addr) "addr 0x%"PRIx64""
> +pci_nvme_mmio_write(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64""
> +pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16""
> +pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "cqid %"PRIu16" new_tail %"PRIu16""
> pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
> pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
> pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 04/18] hw/block/nvme: add temperature threshold feature
2020-07-03 6:34 ` [PATCH v2 04/18] hw/block/nvme: add temperature threshold feature Klaus Jensen
@ 2020-07-03 8:08 ` Philippe Mathieu-Daudé
2020-07-03 8:18 ` Klaus Jensen
0 siblings, 1 reply; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 8:08 UTC (permalink / raw)
To: Klaus Jensen, qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez, Maxim Levitsky
On 7/3/20 8:34 AM, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen@samsung.com>
>
> It might seem weird to implement this feature for an emulated device,
> but it is mandatory to support and the feature is useful for testing
> asynchronous event request support, which will be added in a later
> patch.
It might be interesting to plug that to the "temperature sensor
interface" I suggested here (I'll rework on it during 5.2):
https://www.mail-archive.com/qemu-block@nongnu.org/msg65192.html
>
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> Acked-by: Keith Busch <kbusch@kernel.org>
> Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
> ---
> hw/block/nvme.c | 48 ++++++++++++++++++++++++++++++++++++++++++++
> hw/block/nvme.h | 1 +
> include/block/nvme.h | 5 ++++-
> 3 files changed, 53 insertions(+), 1 deletion(-)
>
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index b7037a7d3504..5ca50646369e 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -59,6 +59,9 @@
> #define NVME_DB_SIZE 4
> #define NVME_CMB_BIR 2
> #define NVME_PMR_BIR 2
> +#define NVME_TEMPERATURE 0x143
> +#define NVME_TEMPERATURE_WARNING 0x157
> +#define NVME_TEMPERATURE_CRITICAL 0x175
>
> #define NVME_GUEST_ERR(trace, fmt, ...) \
> do { \
> @@ -827,9 +830,31 @@ static uint16_t nvme_get_feature_timestamp(NvmeCtrl *n, NvmeCmd *cmd)
> static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> {
> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> + uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> uint32_t result;
>
> switch (dw10) {
> + case NVME_TEMPERATURE_THRESHOLD:
> + result = 0;
> +
> + /*
> + * The controller only implements the Composite Temperature sensor, so
> + * return 0 for all other sensors.
> + */
> + if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> + break;
> + }
> +
> + switch (NVME_TEMP_THSEL(dw11)) {
> + case NVME_TEMP_THSEL_OVER:
> + result = cpu_to_le16(n->features.temp_thresh_hi);
> + break;
> + case NVME_TEMP_THSEL_UNDER:
> + result = cpu_to_le16(n->features.temp_thresh_low);
> + break;
> + }
> +
> + break;
> case NVME_VOLATILE_WRITE_CACHE:
> result = blk_enable_write_cache(n->conf.blk);
> trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
> @@ -874,6 +899,23 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
>
> switch (dw10) {
> + case NVME_TEMPERATURE_THRESHOLD:
> + if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> + break;
> + }
> +
> + switch (NVME_TEMP_THSEL(dw11)) {
> + case NVME_TEMP_THSEL_OVER:
> + n->features.temp_thresh_hi = NVME_TEMP_TMPTH(dw11);
> + break;
> + case NVME_TEMP_THSEL_UNDER:
> + n->features.temp_thresh_low = NVME_TEMP_TMPTH(dw11);
> + break;
> + default:
> + return NVME_INVALID_FIELD | NVME_DNR;
> + }
> +
> + break;
> case NVME_VOLATILE_WRITE_CACHE:
> blk_set_enable_write_cache(n->conf.blk, dw11 & 1);
> break;
> @@ -1454,6 +1496,7 @@ static void nvme_init_state(NvmeCtrl *n)
> n->namespaces = g_new0(NvmeNamespace, n->num_namespaces);
> n->sq = g_new0(NvmeSQueue *, n->params.max_ioqpairs + 1);
> n->cq = g_new0(NvmeCQueue *, n->params.max_ioqpairs + 1);
> + n->features.temp_thresh_hi = NVME_TEMPERATURE_WARNING;
> }
>
> static void nvme_init_blk(NvmeCtrl *n, Error **errp)
> @@ -1611,6 +1654,11 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
> id->acl = 3;
> id->frmw = 7 << 1;
> id->lpa = 1 << 0;
> +
> + /* recommended default value (~70 C) */
> + id->wctemp = cpu_to_le16(NVME_TEMPERATURE_WARNING);
> + id->cctemp = cpu_to_le16(NVME_TEMPERATURE_CRITICAL);
> +
> id->sqes = (0x6 << 4) | 0x6;
> id->cqes = (0x4 << 4) | 0x4;
> id->nn = cpu_to_le32(n->num_namespaces);
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index 1bf5c80ed843..3acde10e1d2a 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -107,6 +107,7 @@ typedef struct NvmeCtrl {
> NvmeSQueue admin_sq;
> NvmeCQueue admin_cq;
> NvmeIdCtrl id_ctrl;
> + NvmeFeatureVal features;
> } NvmeCtrl;
>
> /* calculate the number of LBAs that the namespace can accomodate */
> diff --git a/include/block/nvme.h b/include/block/nvme.h
> index 2a80d2a7ed89..d2c457695b38 100644
> --- a/include/block/nvme.h
> +++ b/include/block/nvme.h
> @@ -860,7 +860,10 @@ enum NvmeIdCtrlOncs {
> typedef struct NvmeFeatureVal {
> uint32_t arbitration;
> uint32_t power_mgmt;
> - uint32_t temp_thresh;
> + struct {
> + uint16_t temp_thresh_hi;
> + uint16_t temp_thresh_low;
> + };
> uint32_t err_rec;
> uint32_t volatile_wc;
> uint32_t num_queues;
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 02/18] hw/block/nvme: additional tracing
2020-07-03 8:03 ` Philippe Mathieu-Daudé
@ 2020-07-03 8:14 ` Klaus Jensen
0 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 8:14 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On Jul 3 10:03, Philippe Mathieu-Daudé wrote:
> On 7/3/20 8:34 AM, Klaus Jensen wrote:
> > From: Klaus Jensen <k.jensen@samsung.com>
> >
> > Add various additional tracing and streamline nvme_identify_ns and
> > nvme_identify_nslist (they do not need to repeat the command, it is
> > already in the trace name).
> >
> > Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> > Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> > ---
> > hw/block/nvme.c | 19 +++++++++++++++++++
> > hw/block/nvme.h | 14 ++++++++++++++
> > hw/block/trace-events | 13 +++++++++++--
> > 3 files changed, 44 insertions(+), 2 deletions(-)
> >
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index 71b388aa0e20..f5d9148f0936 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -331,6 +331,8 @@ static void nvme_post_cqes(void *opaque)
> > static void nvme_enqueue_req_completion(NvmeCQueue *cq, NvmeRequest *req)
> > {
> > assert(cq->cqid == req->sq->cqid);
> > + trace_pci_nvme_enqueue_req_completion(nvme_cid(req), cq->cqid,
> > + req->status);
> > QTAILQ_REMOVE(&req->sq->out_req_list, req, entry);
> > QTAILQ_INSERT_TAIL(&cq->req_list, req, entry);
> > timer_mod(cq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
> > @@ -343,6 +345,8 @@ static void nvme_rw_cb(void *opaque, int ret)
> > NvmeCtrl *n = sq->ctrl;
> > NvmeCQueue *cq = n->cq[sq->cqid];
> >
> > + trace_pci_nvme_rw_cb(nvme_cid(req));
> > +
> > if (!ret) {
> > block_acct_done(blk_get_stats(n->conf.blk), &req->acct);
> > req->status = NVME_SUCCESS;
> > @@ -378,6 +382,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
> > uint64_t offset = slba << data_shift;
> > uint32_t count = nlb << data_shift;
> >
> > + trace_pci_nvme_write_zeroes(nvme_cid(req), slba, nlb);
> > +
> > if (unlikely(slba + nlb > ns->id_ns.nsze)) {
> > trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
> > return NVME_LBA_RANGE | NVME_DNR;
> > @@ -445,6 +451,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> > NvmeNamespace *ns;
> > uint32_t nsid = le32_to_cpu(cmd->nsid);
> >
> > + trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req), cmd->opcode);
> > +
> > if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
> > trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces);
> > return NVME_INVALID_NSID | NVME_DNR;
> > @@ -876,6 +884,8 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> >
> > static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> > {
> > + trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), cmd->opcode);
> > +
> > switch (cmd->opcode) {
> > case NVME_ADM_CMD_DELETE_SQ:
> > return nvme_del_sq(n, cmd);
> > @@ -1204,6 +1214,8 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
> > uint8_t *ptr = (uint8_t *)&n->bar;
> > uint64_t val = 0;
> >
> > + trace_pci_nvme_mmio_read(addr);
> > +
> > if (unlikely(addr & (sizeof(uint32_t) - 1))) {
> > NVME_GUEST_ERR(pci_nvme_ub_mmiord_misaligned32,
> > "MMIO read not 32-bit aligned,"
> > @@ -1273,6 +1285,8 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
> > return;
> > }
> >
> > + trace_pci_nvme_mmio_doorbell_cq(cq->cqid, new_head);
> > +
> > start_sqs = nvme_cq_full(cq) ? 1 : 0;
> > cq->head = new_head;
> > if (start_sqs) {
> > @@ -1311,6 +1325,8 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val)
> > return;
> > }
> >
> > + trace_pci_nvme_mmio_doorbell_sq(sq->sqid, new_tail);
> > +
> > sq->tail = new_tail;
> > timer_mod(sq->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 500);
> > }
> > @@ -1320,6 +1336,9 @@ static void nvme_mmio_write(void *opaque, hwaddr addr, uint64_t data,
> > unsigned size)
> > {
> > NvmeCtrl *n = (NvmeCtrl *)opaque;
> > +
> > + trace_pci_nvme_mmio_write(addr, data);
> > +
> > if (addr < sizeof(n->bar)) {
> > nvme_write_bar(n, addr, data, size);
> > } else if (addr >= 0x1000) {
> > diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> > index 1d30c0bca283..1bf5c80ed843 100644
> > --- a/hw/block/nvme.h
> > +++ b/hw/block/nvme.h
> > @@ -115,4 +115,18 @@ static inline uint64_t nvme_ns_nlbas(NvmeCtrl *n, NvmeNamespace *ns)
> > return n->ns_size >> nvme_ns_lbads(ns);
> > }
> >
> > +static inline uint16_t nvme_cid(NvmeRequest *req)
> > +{
> > + if (req) {
> > + return le16_to_cpu(req->cqe.cid);
> > + }
> > +
> > + return 0xffff;
>
> In this case I find the inverted logic easier. Matter
> of taste :)
>
Your taste is definitely better than mine. I'll queue it up for a style
fix ;)
> > +}
> > +
> > +static inline uint16_t nvme_sqid(NvmeRequest *req)
> > +{
> > + return le16_to_cpu(req->sq->sqid);
> > +}
>
> Later I'd prefer we move these out of the header, and remove
> the inline attribute.
> I.e. nvme_ns_nlbas() is only used once.
>
> OK for now.
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
>
I agree, I'll also queue that up and include it if the series calls for
a v3.
> > +
> > #endif /* HW_NVME_H */
> > diff --git a/hw/block/trace-events b/hw/block/trace-events
> > index 958fcc5508d1..c40c0d2e4b28 100644
> > --- a/hw/block/trace-events
> > +++ b/hw/block/trace-events
> > @@ -33,19 +33,28 @@ pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u"
> > pci_nvme_irq_pin(void) "pulsing IRQ pin"
> > pci_nvme_irq_masked(void) "IRQ is masked"
> > pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64""
> > +pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8""
> > +pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8""
> > pci_nvme_rw(const char *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64""
> > +pci_nvme_rw_cb(uint16_t cid) "cid %"PRIu16""
> > +pci_nvme_write_zeroes(uint16_t cid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" slba %"PRIu64" nlb %"PRIu32""
> > pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16""
> > pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d"
> > pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16""
> > pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16""
> > pci_nvme_identify_ctrl(void) "identify controller"
> > -pci_nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16""
> > -pci_nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16""
> > +pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
> > +pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
> > pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
> > pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
> > pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
> > pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64""
> > pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64""
> > +pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16""
> > +pci_nvme_mmio_read(uint64_t addr) "addr 0x%"PRIx64""
> > +pci_nvme_mmio_write(uint64_t addr, uint64_t data) "addr 0x%"PRIx64" data 0x%"PRIx64""
> > +pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16""
> > +pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "cqid %"PRIu16" new_tail %"PRIu16""
> > pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64""
> > pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64""
> > pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64""
> >
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 17/18] hw/block/nvme: provide the mandatory subnqn field
2020-07-03 6:34 ` [PATCH v2 17/18] hw/block/nvme: provide the mandatory subnqn field Klaus Jensen
@ 2020-07-03 8:18 ` Philippe Mathieu-Daudé
2020-07-03 8:25 ` Klaus Jensen
0 siblings, 1 reply; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 8:18 UTC (permalink / raw)
To: Klaus Jensen, qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez, Maxim Levitsky
On 7/3/20 8:34 AM, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen@samsung.com>
>
> The SUBNQN field is mandatory in NVM Express 1.3.
>
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> ---
> hw/block/nvme.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 8138baa6fbd8..5bbb6aa0efc3 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -2134,6 +2134,9 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
> id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS | NVME_ONCS_TIMESTAMP |
> NVME_ONCS_FEATURES);
>
> + pstrcpy((char *) id->subnqn, sizeof(id->subnqn), "nqn.2019-08.org.qemu:");
> + pstrcat((char *) id->subnqn, sizeof(id->subnqn), n->params.serial);
What about using strpadcpy()?
char *subnqn = g_strdup_printf("nqn.2019-08.org.qemu:%s",
n->params.serial);
strpadcpy((char *)id->subnqn, sizeof(id->subnqn), subnqn, '\0');
g_free(subnqn);
> +
> id->psd[0].mp = cpu_to_le16(0x9c4);
> id->psd[0].enlat = cpu_to_le32(0x10);
> id->psd[0].exlat = cpu_to_le32(0x4);
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 04/18] hw/block/nvme: add temperature threshold feature
2020-07-03 8:08 ` Philippe Mathieu-Daudé
@ 2020-07-03 8:18 ` Klaus Jensen
0 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 8:18 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On Jul 3 10:08, Philippe Mathieu-Daudé wrote:
> On 7/3/20 8:34 AM, Klaus Jensen wrote:
> > From: Klaus Jensen <k.jensen@samsung.com>
> >
> > It might seem weird to implement this feature for an emulated device,
> > but it is mandatory to support and the feature is useful for testing
> > asynchronous event request support, which will be added in a later
> > patch.
>
> It might be interesting to plug that to the "temperature sensor
> interface" I suggested here (I'll rework on it during 5.2):
> https://www.mail-archive.com/qemu-block@nongnu.org/msg65192.html
>
That would be pretty cool, since currently only the thresholds can be
changed to cause a reaction.
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 15/18] hw/block/nvme: reject invalid nsid values in active namespace id list
2020-07-03 6:34 ` [PATCH v2 15/18] hw/block/nvme: reject invalid nsid values in active namespace id list Klaus Jensen
@ 2020-07-03 8:20 ` Philippe Mathieu-Daudé
2020-07-03 8:37 ` Klaus Jensen
0 siblings, 1 reply; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 8:20 UTC (permalink / raw)
To: Klaus Jensen, qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez, Maxim Levitsky
On 7/3/20 8:34 AM, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen@samsung.com>
>
> Reject the nsid broadcast value (0xffffffff) and 0xfffffffe in the
> Active Namespace ID list.
Can we have a definition instead of this 0xfffffffe magic value please?
>
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> ---
> hw/block/nvme.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 65c2fa3ac1f4..0dac7a41ddae 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -956,6 +956,10 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
>
> trace_pci_nvme_identify_nslist(min_nsid);
>
> + if (min_nsid == 0xfffffffe || min_nsid == NVME_NSID_BROADCAST) {
> + return NVME_INVALID_NSID | NVME_DNR;
> + }
> +
> list = g_malloc0(data_len);
> for (i = 0; i < n->num_namespaces; i++) {
> if (i < min_nsid) {
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 17/18] hw/block/nvme: provide the mandatory subnqn field
2020-07-03 8:18 ` Philippe Mathieu-Daudé
@ 2020-07-03 8:25 ` Klaus Jensen
0 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 8:25 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On Jul 3 10:18, Philippe Mathieu-Daudé wrote:
> On 7/3/20 8:34 AM, Klaus Jensen wrote:
> > From: Klaus Jensen <k.jensen@samsung.com>
> >
> > The SUBNQN field is mandatory in NVM Express 1.3.
> >
> > Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> > Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
> > Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> > ---
> > hw/block/nvme.c | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index 8138baa6fbd8..5bbb6aa0efc3 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -2134,6 +2134,9 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
> > id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS | NVME_ONCS_TIMESTAMP |
> > NVME_ONCS_FEATURES);
> >
> > + pstrcpy((char *) id->subnqn, sizeof(id->subnqn), "nqn.2019-08.org.qemu:");
> > + pstrcat((char *) id->subnqn, sizeof(id->subnqn), n->params.serial);
>
> What about using strpadcpy()?
>
> char *subnqn = g_strdup_printf("nqn.2019-08.org.qemu:%s",
> n->params.serial);
> strpadcpy((char *)id->subnqn, sizeof(id->subnqn), subnqn, '\0');
> g_free(subnqn);
>
Thanks, that's better. Fixed!
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 14/18] hw/block/nvme: support identify namespace descriptor list
2020-07-03 6:34 ` [PATCH v2 14/18] hw/block/nvme: support identify namespace descriptor list Klaus Jensen
@ 2020-07-03 8:27 ` Philippe Mathieu-Daudé
2020-07-03 10:00 ` Klaus Jensen
0 siblings, 1 reply; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 8:27 UTC (permalink / raw)
To: Klaus Jensen, qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez, Maxim Levitsky
On 7/3/20 8:34 AM, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen@samsung.com>
>
> Since we are not providing the NGUID or EUI64 fields, we must support
> the Namespace UUID. We do not have any way of storing a persistent
> unique identifier, so conjure up a UUID that is just the namespace id.
>
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> ---
> hw/block/nvme.c | 41 +++++++++++++++++++++++++++++++++++++++++
> hw/block/trace-events | 1 +
> 2 files changed, 42 insertions(+)
>
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 8230e0e3826b..65c2fa3ac1f4 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -971,6 +971,45 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
> return ret;
> }
>
> +static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeIdentify *c)
> +{
> + uint32_t nsid = le32_to_cpu(c->nsid);
> + uint64_t prp1 = le64_to_cpu(c->prp1);
> + uint64_t prp2 = le64_to_cpu(c->prp2);
> +
> + uint8_t list[NVME_IDENTIFY_DATA_SIZE];
> +
> + struct data {
> + struct {
> + NvmeIdNsDescr hdr;
> + uint8_t v[16];
You might consider to use QemuUUID from "qemu/uuid.h". The benefits
are you can use qemu_uuid_parse() qemu_uuid_unparse*() for tracing,
and DEFINE_PROP_UUID() in case you want to set a particular UUID
from command line, it case it is important to the guest.
> + } uuid;
> + };
> +
> + struct data *ns_descrs = (struct data *)list;
> +
> + trace_pci_nvme_identify_ns_descr_list(nsid);
> +
> + if (unlikely(nsid == 0 || nsid > n->num_namespaces)) {
> + trace_pci_nvme_err_invalid_ns(nsid, n->num_namespaces);
> + return NVME_INVALID_NSID | NVME_DNR;
> + }
> +
> + memset(list, 0x0, sizeof(list));
> +
> + /*
> + * Because the NGUID and EUI64 fields are 0 in the Identify Namespace data
> + * structure, a Namespace UUID (nidt = 0x3) must be reported in the
> + * Namespace Identification Descriptor. Add a very basic Namespace UUID
> + * here.
> + */
> + ns_descrs->uuid.hdr.nidt = NVME_NIDT_UUID;
> + ns_descrs->uuid.hdr.nidl = NVME_NIDT_UUID_LEN;
> + stl_be_p(&ns_descrs->uuid.v, nsid);
> +
> + return nvme_dma_read_prp(n, list, NVME_IDENTIFY_DATA_SIZE, prp1, prp2);
> +}
> +
> static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
> {
> NvmeIdentify *c = (NvmeIdentify *)cmd;
> @@ -982,6 +1021,8 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd)
> return nvme_identify_ctrl(n, c);
> case NVME_ID_CNS_NS_ACTIVE_LIST:
> return nvme_identify_nslist(n, c);
> + case NVME_ID_CNS_NS_DESCR_LIST:
> + return nvme_identify_ns_descr_list(n, c);
> default:
> trace_pci_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns));
> return NVME_INVALID_FIELD | NVME_DNR;
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index 4a4ef34071df..7b7303cab1dd 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -45,6 +45,7 @@ pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16""
> pci_nvme_identify_ctrl(void) "identify controller"
> pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
> pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
> +pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32""
> pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
> pci_nvme_getfeat(uint16_t cid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32""
> pci_nvme_setfeat(uint16_t cid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32""
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters
2020-07-03 6:34 ` [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters Klaus Jensen
@ 2020-07-03 8:31 ` Philippe Mathieu-Daudé
2020-07-03 8:46 ` Klaus Jensen
0 siblings, 1 reply; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 8:31 UTC (permalink / raw)
To: Klaus Jensen, qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez, Maxim Levitsky
On 7/3/20 8:34 AM, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen@samsung.com>
>
> Add support for any remaining mandatory controller operating parameters
> (features).
>
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> ---
> hw/block/nvme.c | 39 +++++++++++++++++++++++++++++++++------
> hw/block/nvme.h | 18 ++++++++++++++++++
> hw/block/trace-events | 2 ++
> include/block/nvme.h | 7 +++++++
> 4 files changed, 60 insertions(+), 6 deletions(-)
>
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index ba523f6768bf..affb9a967534 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -1056,8 +1056,16 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> uint32_t result;
> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> + uint16_t iv;
>
> - switch (dw10) {
> + trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
> +
> + if (!nvme_feature_support[fid]) {
> + return NVME_INVALID_FIELD | NVME_DNR;
> + }
> +
> + switch (fid) {
> case NVME_TEMPERATURE_THRESHOLD:
> result = 0;
>
> @@ -1088,14 +1096,27 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> ((n->params.max_ioqpairs - 1) << 16));
> trace_pci_nvme_getfeat_numq(result);
> break;
> + case NVME_INTERRUPT_VECTOR_CONF:
> + iv = dw11 & 0xffff;
> + if (iv >= n->params.max_ioqpairs + 1) {
> + return NVME_INVALID_FIELD | NVME_DNR;
> + }
> +
> + result = iv;
> + if (iv == n->admin_cq.vector) {
> + result |= NVME_INTVC_NOCOALESCING;
> + }
> +
> + result = cpu_to_le32(result);
> + break;
> case NVME_ASYNCHRONOUS_EVENT_CONF:
> result = cpu_to_le32(n->features.async_config);
> break;
> case NVME_TIMESTAMP:
> return nvme_get_feature_timestamp(n, cmd);
> default:
> - trace_pci_nvme_err_invalid_getfeat(dw10);
> - return NVME_INVALID_FIELD | NVME_DNR;
> + result = cpu_to_le32(nvme_feature_default[fid]);
So here we expect uninitialized fid entries to return 0, right?
> + break;
> }
>
> req->cqe.result = result;
> @@ -1124,8 +1145,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> {
> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
>
> - switch (dw10) {
> + trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
> +
> + if (!nvme_feature_support[fid]) {
> + return NVME_INVALID_FIELD | NVME_DNR;
> + }
> +
> + switch (fid) {
> case NVME_TEMPERATURE_THRESHOLD:
> if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> break;
> @@ -1172,8 +1200,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> case NVME_TIMESTAMP:
> return nvme_set_feature_timestamp(n, cmd);
> default:
> - trace_pci_nvme_err_invalid_setfeat(dw10);
> - return NVME_INVALID_FIELD | NVME_DNR;
> + return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
> }
> return NVME_SUCCESS;
> }
> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> index f8940435f9ef..8ad1e3c89cee 100644
> --- a/hw/block/nvme.h
> +++ b/hw/block/nvme.h
> @@ -87,6 +87,24 @@ typedef struct NvmeFeatureVal {
> uint32_t async_config;
> } NvmeFeatureVal;
>
> +static const uint32_t nvme_feature_default[0x100] = {
> + [NVME_ARBITRATION] = NVME_ARB_AB_NOLIMIT,
> +};
> +
> +static const bool nvme_feature_support[0x100] = {
> + [NVME_ARBITRATION] = true,
> + [NVME_POWER_MANAGEMENT] = true,
> + [NVME_TEMPERATURE_THRESHOLD] = true,
> + [NVME_ERROR_RECOVERY] = true,
> + [NVME_VOLATILE_WRITE_CACHE] = true,
> + [NVME_NUMBER_OF_QUEUES] = true,
> + [NVME_INTERRUPT_COALESCING] = true,
> + [NVME_INTERRUPT_VECTOR_CONF] = true,
> + [NVME_WRITE_ATOMICITY] = true,
> + [NVME_ASYNCHRONOUS_EVENT_CONF] = true,
> + [NVME_TIMESTAMP] = true,
> +};
Nack. No variable assignation in header please.
Move that to the source file.
> +
> typedef struct NvmeCtrl {
> PCIDevice parent_obj;
> MemoryRegion iomem;
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index 091af16ca7d7..42e62f4649f8 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -46,6 +46,8 @@ pci_nvme_identify_ctrl(void) "identify controller"
> pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
> pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
> pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
> +pci_nvme_getfeat(uint16_t cid, uint8_t fid, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" cdw11 0x%"PRIx32""
> +pci_nvme_setfeat(uint16_t cid, uint8_t fid, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" cdw11 0x%"PRIx32""
> pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
> pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
> pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
> diff --git a/include/block/nvme.h b/include/block/nvme.h
> index 0dce15af6bcf..406648d4cf94 100644
> --- a/include/block/nvme.h
> +++ b/include/block/nvme.h
> @@ -662,6 +662,7 @@ enum NvmeStatusCodes {
> NVME_FW_REQ_RESET = 0x010b,
> NVME_INVALID_QUEUE_DEL = 0x010c,
> NVME_FID_NOT_SAVEABLE = 0x010d,
> + NVME_FEAT_NOT_CHANGEABLE = 0x010e,
> NVME_FID_NOT_NSID_SPEC = 0x010f,
> NVME_FW_REQ_SUSYSTEM_RESET = 0x0110,
> NVME_CONFLICTING_ATTRS = 0x0180,
> @@ -866,6 +867,7 @@ enum NvmeIdCtrlLpa {
> #define NVME_CTRL_SGLS_ADDR_OFFSET (0x1 << 20)
>
> #define NVME_ARB_AB(arb) (arb & 0x7)
> +#define NVME_ARB_AB_NOLIMIT 0x7
> #define NVME_ARB_LPW(arb) ((arb >> 8) & 0xff)
> #define NVME_ARB_MPW(arb) ((arb >> 16) & 0xff)
> #define NVME_ARB_HPW(arb) ((arb >> 24) & 0xff)
> @@ -873,6 +875,8 @@ enum NvmeIdCtrlLpa {
> #define NVME_INTC_THR(intc) (intc & 0xff)
> #define NVME_INTC_TIME(intc) ((intc >> 8) & 0xff)
>
> +#define NVME_INTVC_NOCOALESCING (0x1 << 16)
> +
> #define NVME_TEMP_THSEL(temp) ((temp >> 20) & 0x3)
> #define NVME_TEMP_THSEL_OVER 0x0
> #define NVME_TEMP_THSEL_UNDER 0x1
> @@ -902,6 +906,9 @@ enum NvmeFeatureIds {
> NVME_SOFTWARE_PROGRESS_MARKER = 0x80
> };
>
> +#define NVME_GETSETFEAT_FID_MASK 0xff
> +#define NVME_GETSETFEAT_FID(dw10) (dw10 & NVME_GETSETFEAT_FID_MASK)
> +
> typedef struct NvmeRangeType {
> uint8_t type;
> uint8_t attributes;
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 10/18] hw/block/nvme: fix missing endian conversion
2020-07-03 6:34 ` [PATCH v2 10/18] hw/block/nvme: fix missing endian conversion Klaus Jensen
@ 2020-07-03 8:34 ` Philippe Mathieu-Daudé
2020-07-03 10:11 ` Klaus Jensen
0 siblings, 1 reply; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 8:34 UTC (permalink / raw)
To: Klaus Jensen, qemu-block
Cc: Kevin Wolf, Dmitry Fomichev, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez, Maxim Levitsky
On 7/3/20 8:34 AM, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen@samsung.com>
>
> Fix a missing cpu_to conversion.
>
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> ---
> hw/block/nvme.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index f3a5b857bc92..ba523f6768bf 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -1080,7 +1080,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>
> break;
> case NVME_VOLATILE_WRITE_CACHE:
> - result = blk_enable_write_cache(n->conf.blk);
> + result = cpu_to_le32(blk_enable_write_cache(n->conf.blk));
> trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
> break;
> case NVME_NUMBER_OF_QUEUES:
>
This doesn't look correct. What you probably want:
-- >8 --
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -815,8 +815,8 @@ static uint16_t nvme_get_feature(NvmeCtrl *n,
NvmeCmd *cmd, NvmeRequest *req)
trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
break;
case NVME_NUMBER_OF_QUEUES:
- result = cpu_to_le32((n->params.max_ioqpairs - 1) |
- ((n->params.max_ioqpairs - 1) << 16));
+ result = (n->params.max_ioqpairs - 1)
+ | ((n->params.max_ioqpairs - 1) << 16);
trace_pci_nvme_getfeat_numq(result);
break;
case NVME_TIMESTAMP:
@@ -825,8 +825,8 @@ static uint16_t nvme_get_feature(NvmeCtrl *n,
NvmeCmd *cmd, NvmeRequest *req)
trace_pci_nvme_err_invalid_getfeat(dw10);
return NVME_INVALID_FIELD | NVME_DNR;
}
+ req->cqe.result = cpu_to_le32(result);
- req->cqe.result = result;
return NVME_SUCCESS;
}
---
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 15/18] hw/block/nvme: reject invalid nsid values in active namespace id list
2020-07-03 8:20 ` Philippe Mathieu-Daudé
@ 2020-07-03 8:37 ` Klaus Jensen
2020-07-03 9:14 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 8:37 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On Jul 3 10:20, Philippe Mathieu-Daudé wrote:
> On 7/3/20 8:34 AM, Klaus Jensen wrote:
> > From: Klaus Jensen <k.jensen@samsung.com>
> >
> > Reject the nsid broadcast value (0xffffffff) and 0xfffffffe in the
> > Active Namespace ID list.
>
> Can we have a definition instead of this 0xfffffffe magic value please?
>
Hmm, not really actually. It's not a magic value, its just because the
logic in Active Namespace ID list would require that it should report
any namespaces with ids *higher* than the one specified, so since
0xffffffff (NVME_NSID_BROADCAST) is invalid, NVME_NSID_BROADCAST - 1
needs to be as well.
What do you say I change it to `min_nsid >= NVME_NSID_BROADCAST - 1`?
The original condition just reads well if you are sitting with the spec
on the side.
> >
> > Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> > ---
> > hw/block/nvme.c | 4 ++++
> > 1 file changed, 4 insertions(+)
> >
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index 65c2fa3ac1f4..0dac7a41ddae 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -956,6 +956,10 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
> >
> > trace_pci_nvme_identify_nslist(min_nsid);
> >
> > + if (min_nsid == 0xfffffffe || min_nsid == NVME_NSID_BROADCAST) {
> > + return NVME_INVALID_NSID | NVME_DNR;
> > + }
> > +
> > list = g_malloc0(data_len);
> > for (i = 0; i < n->num_namespaces; i++) {
> > if (i < min_nsid) {
> >
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters
2020-07-03 8:31 ` Philippe Mathieu-Daudé
@ 2020-07-03 8:46 ` Klaus Jensen
2020-07-03 9:21 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 8:46 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On Jul 3 10:31, Philippe Mathieu-Daudé wrote:
> On 7/3/20 8:34 AM, Klaus Jensen wrote:
> > From: Klaus Jensen <k.jensen@samsung.com>
> >
> > Add support for any remaining mandatory controller operating parameters
> > (features).
> >
> > Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> > Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> > ---
> > hw/block/nvme.c | 39 +++++++++++++++++++++++++++++++++------
> > hw/block/nvme.h | 18 ++++++++++++++++++
> > hw/block/trace-events | 2 ++
> > include/block/nvme.h | 7 +++++++
> > 4 files changed, 60 insertions(+), 6 deletions(-)
> >
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index ba523f6768bf..affb9a967534 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -1056,8 +1056,16 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> > uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> > uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> > uint32_t result;
> > + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> > + uint16_t iv;
> >
> > - switch (dw10) {
> > + trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
> > +
> > + if (!nvme_feature_support[fid]) {
> > + return NVME_INVALID_FIELD | NVME_DNR;
> > + }
> > +
> > + switch (fid) {
> > case NVME_TEMPERATURE_THRESHOLD:
> > result = 0;
> >
> > @@ -1088,14 +1096,27 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> > ((n->params.max_ioqpairs - 1) << 16));
> > trace_pci_nvme_getfeat_numq(result);
> > break;
> > + case NVME_INTERRUPT_VECTOR_CONF:
> > + iv = dw11 & 0xffff;
> > + if (iv >= n->params.max_ioqpairs + 1) {
> > + return NVME_INVALID_FIELD | NVME_DNR;
> > + }
> > +
> > + result = iv;
> > + if (iv == n->admin_cq.vector) {
> > + result |= NVME_INTVC_NOCOALESCING;
> > + }
> > +
> > + result = cpu_to_le32(result);
> > + break;
> > case NVME_ASYNCHRONOUS_EVENT_CONF:
> > result = cpu_to_le32(n->features.async_config);
> > break;
> > case NVME_TIMESTAMP:
> > return nvme_get_feature_timestamp(n, cmd);
> > default:
> > - trace_pci_nvme_err_invalid_getfeat(dw10);
> > - return NVME_INVALID_FIELD | NVME_DNR;
> > + result = cpu_to_le32(nvme_feature_default[fid]);
>
> So here we expect uninitialized fid entries to return 0, right?
>
Yes, if defaults are not 0 (like NVME_ARBITRATION), it is explicitly set.
> > + break;
> > }
> >
> > req->cqe.result = result;
> > @@ -1124,8 +1145,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> > {
> > uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> > uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> > + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> >
> > - switch (dw10) {
> > + trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
> > +
> > + if (!nvme_feature_support[fid]) {
> > + return NVME_INVALID_FIELD | NVME_DNR;
> > + }
> > +
> > + switch (fid) {
> > case NVME_TEMPERATURE_THRESHOLD:
> > if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> > break;
> > @@ -1172,8 +1200,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> > case NVME_TIMESTAMP:
> > return nvme_set_feature_timestamp(n, cmd);
> > default:
> > - trace_pci_nvme_err_invalid_setfeat(dw10);
> > - return NVME_INVALID_FIELD | NVME_DNR;
> > + return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
> > }
> > return NVME_SUCCESS;
> > }
> > diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> > index f8940435f9ef..8ad1e3c89cee 100644
> > --- a/hw/block/nvme.h
> > +++ b/hw/block/nvme.h
> > @@ -87,6 +87,24 @@ typedef struct NvmeFeatureVal {
> > uint32_t async_config;
> > } NvmeFeatureVal;
> >
> > +static const uint32_t nvme_feature_default[0x100] = {
> > + [NVME_ARBITRATION] = NVME_ARB_AB_NOLIMIT,
> > +};
> > +
> > +static const bool nvme_feature_support[0x100] = {
> > + [NVME_ARBITRATION] = true,
> > + [NVME_POWER_MANAGEMENT] = true,
> > + [NVME_TEMPERATURE_THRESHOLD] = true,
> > + [NVME_ERROR_RECOVERY] = true,
> > + [NVME_VOLATILE_WRITE_CACHE] = true,
> > + [NVME_NUMBER_OF_QUEUES] = true,
> > + [NVME_INTERRUPT_COALESCING] = true,
> > + [NVME_INTERRUPT_VECTOR_CONF] = true,
> > + [NVME_WRITE_ATOMICITY] = true,
> > + [NVME_ASYNCHRONOUS_EVENT_CONF] = true,
> > + [NVME_TIMESTAMP] = true,
> > +};
>
> Nack. No variable assignation in header please.
> Move that to the source file.
>
Understood :)
> > +
> > typedef struct NvmeCtrl {
> > PCIDevice parent_obj;
> > MemoryRegion iomem;
> > diff --git a/hw/block/trace-events b/hw/block/trace-events
> > index 091af16ca7d7..42e62f4649f8 100644
> > --- a/hw/block/trace-events
> > +++ b/hw/block/trace-events
> > @@ -46,6 +46,8 @@ pci_nvme_identify_ctrl(void) "identify controller"
> > pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
> > pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
> > pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
> > +pci_nvme_getfeat(uint16_t cid, uint8_t fid, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" cdw11 0x%"PRIx32""
> > +pci_nvme_setfeat(uint16_t cid, uint8_t fid, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" cdw11 0x%"PRIx32""
> > pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
> > pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
> > pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
> > diff --git a/include/block/nvme.h b/include/block/nvme.h
> > index 0dce15af6bcf..406648d4cf94 100644
> > --- a/include/block/nvme.h
> > +++ b/include/block/nvme.h
> > @@ -662,6 +662,7 @@ enum NvmeStatusCodes {
> > NVME_FW_REQ_RESET = 0x010b,
> > NVME_INVALID_QUEUE_DEL = 0x010c,
> > NVME_FID_NOT_SAVEABLE = 0x010d,
> > + NVME_FEAT_NOT_CHANGEABLE = 0x010e,
> > NVME_FID_NOT_NSID_SPEC = 0x010f,
> > NVME_FW_REQ_SUSYSTEM_RESET = 0x0110,
> > NVME_CONFLICTING_ATTRS = 0x0180,
> > @@ -866,6 +867,7 @@ enum NvmeIdCtrlLpa {
> > #define NVME_CTRL_SGLS_ADDR_OFFSET (0x1 << 20)
> >
> > #define NVME_ARB_AB(arb) (arb & 0x7)
> > +#define NVME_ARB_AB_NOLIMIT 0x7
> > #define NVME_ARB_LPW(arb) ((arb >> 8) & 0xff)
> > #define NVME_ARB_MPW(arb) ((arb >> 16) & 0xff)
> > #define NVME_ARB_HPW(arb) ((arb >> 24) & 0xff)
> > @@ -873,6 +875,8 @@ enum NvmeIdCtrlLpa {
> > #define NVME_INTC_THR(intc) (intc & 0xff)
> > #define NVME_INTC_TIME(intc) ((intc >> 8) & 0xff)
> >
> > +#define NVME_INTVC_NOCOALESCING (0x1 << 16)
> > +
> > #define NVME_TEMP_THSEL(temp) ((temp >> 20) & 0x3)
> > #define NVME_TEMP_THSEL_OVER 0x0
> > #define NVME_TEMP_THSEL_UNDER 0x1
> > @@ -902,6 +906,9 @@ enum NvmeFeatureIds {
> > NVME_SOFTWARE_PROGRESS_MARKER = 0x80
> > };
> >
> > +#define NVME_GETSETFEAT_FID_MASK 0xff
> > +#define NVME_GETSETFEAT_FID(dw10) (dw10 & NVME_GETSETFEAT_FID_MASK)
> > +
> > typedef struct NvmeRangeType {
> > uint8_t type;
> > uint8_t attributes;
> >
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 15/18] hw/block/nvme: reject invalid nsid values in active namespace id list
2020-07-03 8:37 ` Klaus Jensen
@ 2020-07-03 9:14 ` Philippe Mathieu-Daudé
2020-07-03 9:22 ` Klaus Jensen
0 siblings, 1 reply; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 9:14 UTC (permalink / raw)
To: Klaus Jensen
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On 7/3/20 10:37 AM, Klaus Jensen wrote:
> On Jul 3 10:20, Philippe Mathieu-Daudé wrote:
>> On 7/3/20 8:34 AM, Klaus Jensen wrote:
>>> From: Klaus Jensen <k.jensen@samsung.com>
>>>
>>> Reject the nsid broadcast value (0xffffffff) and 0xfffffffe in the
>>> Active Namespace ID list.
>>
>> Can we have a definition instead of this 0xfffffffe magic value please?
>>
>
> Hmm, not really actually. It's not a magic value, its just because the
> logic in Active Namespace ID list would require that it should report
> any namespaces with ids *higher* than the one specified, so since
> 0xffffffff (NVME_NSID_BROADCAST) is invalid, NVME_NSID_BROADCAST - 1
> needs to be as well.
OK.
>
> What do you say I change it to `min_nsid >= NVME_NSID_BROADCAST - 1`?
> The original condition just reads well if you are sitting with the spec
> on the side.
IMO this is clearer:
if (min_nsid + 1 >= NVME_NSID_BROADCAST) {
return NVME_INVALID_NSID | NVME_DNR;
}
Whichever form you prefer you can amend to the respin patch:
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
>
>>>
>>> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
>>> ---
>>> hw/block/nvme.c | 4 ++++
>>> 1 file changed, 4 insertions(+)
>>>
>>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
>>> index 65c2fa3ac1f4..0dac7a41ddae 100644
>>> --- a/hw/block/nvme.c
>>> +++ b/hw/block/nvme.c
>>> @@ -956,6 +956,10 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
>>>
>>> trace_pci_nvme_identify_nslist(min_nsid);
>>>
>>> + if (min_nsid == 0xfffffffe || min_nsid == NVME_NSID_BROADCAST) {
>>> + return NVME_INVALID_NSID | NVME_DNR;
>>> + }
>>> +
>>> list = g_malloc0(data_len);
>>> for (i = 0; i < n->num_namespaces; i++) {
>>> if (i < min_nsid) {
>>>
>>
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters
2020-07-03 8:46 ` Klaus Jensen
@ 2020-07-03 9:21 ` Philippe Mathieu-Daudé
2020-07-03 10:10 ` Klaus Jensen
0 siblings, 1 reply; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 9:21 UTC (permalink / raw)
To: Klaus Jensen
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On 7/3/20 10:46 AM, Klaus Jensen wrote:
> On Jul 3 10:31, Philippe Mathieu-Daudé wrote:
>> On 7/3/20 8:34 AM, Klaus Jensen wrote:
>>> From: Klaus Jensen <k.jensen@samsung.com>
>>>
>>> Add support for any remaining mandatory controller operating parameters
>>> (features).
>>>
>>> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
>>> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
>>> ---
>>> hw/block/nvme.c | 39 +++++++++++++++++++++++++++++++++------
>>> hw/block/nvme.h | 18 ++++++++++++++++++
>>> hw/block/trace-events | 2 ++
>>> include/block/nvme.h | 7 +++++++
>>> 4 files changed, 60 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
>>> index ba523f6768bf..affb9a967534 100644
>>> --- a/hw/block/nvme.c
>>> +++ b/hw/block/nvme.c
>>> @@ -1056,8 +1056,16 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
>>> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
>>> uint32_t result;
>>> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
>>> + uint16_t iv;
>>>
>>> - switch (dw10) {
>>> + trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
>>> +
>>> + if (!nvme_feature_support[fid]) {
>>> + return NVME_INVALID_FIELD | NVME_DNR;
>>> + }
>>> +
>>> + switch (fid) {
>>> case NVME_TEMPERATURE_THRESHOLD:
>>> result = 0;
>>>
>>> @@ -1088,14 +1096,27 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>> ((n->params.max_ioqpairs - 1) << 16));
>>> trace_pci_nvme_getfeat_numq(result);
>>> break;
>>> + case NVME_INTERRUPT_VECTOR_CONF:
>>> + iv = dw11 & 0xffff;
>>> + if (iv >= n->params.max_ioqpairs + 1) {
>>> + return NVME_INVALID_FIELD | NVME_DNR;
>>> + }
>>> +
>>> + result = iv;
>>> + if (iv == n->admin_cq.vector) {
>>> + result |= NVME_INTVC_NOCOALESCING;
>>> + }
>>> +
>>> + result = cpu_to_le32(result);
>>> + break;
>>> case NVME_ASYNCHRONOUS_EVENT_CONF:
>>> result = cpu_to_le32(n->features.async_config);
>>> break;
>>> case NVME_TIMESTAMP:
>>> return nvme_get_feature_timestamp(n, cmd);
>>> default:
>>> - trace_pci_nvme_err_invalid_getfeat(dw10);
>>> - return NVME_INVALID_FIELD | NVME_DNR;
>>> + result = cpu_to_le32(nvme_feature_default[fid]);
>>
>> So here we expect uninitialized fid entries to return 0, right?
>>
>
> Yes, if defaults are not 0 (like NVME_ARBITRATION), it is explicitly set.
>
>>> + break;
>>> }
>>>
>>> req->cqe.result = result;
>>> @@ -1124,8 +1145,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>> {
>>> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
>>> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
>>> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
>>>
>>> - switch (dw10) {
>>> + trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
>>> +
>>> + if (!nvme_feature_support[fid]) {
>>> + return NVME_INVALID_FIELD | NVME_DNR;
>>> + }
>>> +
>>> + switch (fid) {
>>> case NVME_TEMPERATURE_THRESHOLD:
>>> if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
>>> break;
>>> @@ -1172,8 +1200,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>> case NVME_TIMESTAMP:
>>> return nvme_set_feature_timestamp(n, cmd);
>>> default:
>>> - trace_pci_nvme_err_invalid_setfeat(dw10);
>>> - return NVME_INVALID_FIELD | NVME_DNR;
>>> + return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
>>> }
>>> return NVME_SUCCESS;
>>> }
>>> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
>>> index f8940435f9ef..8ad1e3c89cee 100644
>>> --- a/hw/block/nvme.h
>>> +++ b/hw/block/nvme.h
>>> @@ -87,6 +87,24 @@ typedef struct NvmeFeatureVal {
>>> uint32_t async_config;
>>> } NvmeFeatureVal;
What do you think about adding:
--- a/include/block/nvme.h
+++ b/include/block/nvme.h
@@ -804,7 +804,8 @@ enum NvmeFeatureIds {
NVME_WRITE_ATOMICITY = 0xa,
NVME_ASYNCHRONOUS_EVENT_CONF = 0xb,
NVME_TIMESTAMP = 0xe,
- NVME_SOFTWARE_PROGRESS_MARKER = 0x80
+ NVME_SOFTWARE_PROGRESS_MARKER = 0x80,
+ NVME_FEATURE_ID_COUNT = 0x100
};
>>>
>>> +static const uint32_t nvme_feature_default[0x100] = {
Why uint32_t and not uint16_t?
With the previously suggested enum you can now replace 0x100
by NVME_FEATURE_ID_COUNT.
>>> + [NVME_ARBITRATION] = NVME_ARB_AB_NOLIMIT,
>>> +};
>>> +
>>> +static const bool nvme_feature_support[0x100] = {
Ditto NVME_FEATURE_ID_COUNT.
>>> + [NVME_ARBITRATION] = true,
>>> + [NVME_POWER_MANAGEMENT] = true,
>>> + [NVME_TEMPERATURE_THRESHOLD] = true,
>>> + [NVME_ERROR_RECOVERY] = true,
>>> + [NVME_VOLATILE_WRITE_CACHE] = true,
>>> + [NVME_NUMBER_OF_QUEUES] = true,
>>> + [NVME_INTERRUPT_COALESCING] = true,
>>> + [NVME_INTERRUPT_VECTOR_CONF] = true,
>>> + [NVME_WRITE_ATOMICITY] = true,
>>> + [NVME_ASYNCHRONOUS_EVENT_CONF] = true,
>>> + [NVME_TIMESTAMP] = true,
>>> +};
>>
>> Nack. No variable assignation in header please.
Rationale is if another C source file include this header,
the array will be redeclared (statically) and eventually
unused.
>> Move that to the source file.
>>
>
> Understood :)
>
>>> +
>>> typedef struct NvmeCtrl {
>>> PCIDevice parent_obj;
>>> MemoryRegion iomem;
>>> diff --git a/hw/block/trace-events b/hw/block/trace-events
>>> index 091af16ca7d7..42e62f4649f8 100644
>>> --- a/hw/block/trace-events
>>> +++ b/hw/block/trace-events
>>> @@ -46,6 +46,8 @@ pci_nvme_identify_ctrl(void) "identify controller"
>>> pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32""
>>> pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32""
>>> pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64""
>>> +pci_nvme_getfeat(uint16_t cid, uint8_t fid, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" cdw11 0x%"PRIx32""
>>> +pci_nvme_setfeat(uint16_t cid, uint8_t fid, uint32_t cdw11) "cid %"PRIu16" fid 0x%"PRIx8" cdw11 0x%"PRIx32""
>>> pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s"
>>> pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d"
>>> pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d"
>>> diff --git a/include/block/nvme.h b/include/block/nvme.h
>>> index 0dce15af6bcf..406648d4cf94 100644
>>> --- a/include/block/nvme.h
>>> +++ b/include/block/nvme.h
>>> @@ -662,6 +662,7 @@ enum NvmeStatusCodes {
>>> NVME_FW_REQ_RESET = 0x010b,
>>> NVME_INVALID_QUEUE_DEL = 0x010c,
>>> NVME_FID_NOT_SAVEABLE = 0x010d,
>>> + NVME_FEAT_NOT_CHANGEABLE = 0x010e,
>>> NVME_FID_NOT_NSID_SPEC = 0x010f,
>>> NVME_FW_REQ_SUSYSTEM_RESET = 0x0110,
>>> NVME_CONFLICTING_ATTRS = 0x0180,
>>> @@ -866,6 +867,7 @@ enum NvmeIdCtrlLpa {
>>> #define NVME_CTRL_SGLS_ADDR_OFFSET (0x1 << 20)
>>>
>>> #define NVME_ARB_AB(arb) (arb & 0x7)
>>> +#define NVME_ARB_AB_NOLIMIT 0x7
>>> #define NVME_ARB_LPW(arb) ((arb >> 8) & 0xff)
>>> #define NVME_ARB_MPW(arb) ((arb >> 16) & 0xff)
>>> #define NVME_ARB_HPW(arb) ((arb >> 24) & 0xff)
>>> @@ -873,6 +875,8 @@ enum NvmeIdCtrlLpa {
>>> #define NVME_INTC_THR(intc) (intc & 0xff)
>>> #define NVME_INTC_TIME(intc) ((intc >> 8) & 0xff)
>>>
>>> +#define NVME_INTVC_NOCOALESCING (0x1 << 16)
>>> +
>>> #define NVME_TEMP_THSEL(temp) ((temp >> 20) & 0x3)
>>> #define NVME_TEMP_THSEL_OVER 0x0
>>> #define NVME_TEMP_THSEL_UNDER 0x1
>>> @@ -902,6 +906,9 @@ enum NvmeFeatureIds {
>>> NVME_SOFTWARE_PROGRESS_MARKER = 0x80
>>> };
>>>
>>> +#define NVME_GETSETFEAT_FID_MASK 0xff
>>> +#define NVME_GETSETFEAT_FID(dw10) (dw10 & NVME_GETSETFEAT_FID_MASK)
>>> +
>>> typedef struct NvmeRangeType {
>>> uint8_t type;
>>> uint8_t attributes;
>>>
>>
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 15/18] hw/block/nvme: reject invalid nsid values in active namespace id list
2020-07-03 9:14 ` Philippe Mathieu-Daudé
@ 2020-07-03 9:22 ` Klaus Jensen
2020-07-03 10:59 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 9:22 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On Jul 3 11:14, Philippe Mathieu-Daudé wrote:
> On 7/3/20 10:37 AM, Klaus Jensen wrote:
> > On Jul 3 10:20, Philippe Mathieu-Daudé wrote:
> >> On 7/3/20 8:34 AM, Klaus Jensen wrote:
> >>> From: Klaus Jensen <k.jensen@samsung.com>
> >>>
> >>> Reject the nsid broadcast value (0xffffffff) and 0xfffffffe in the
> >>> Active Namespace ID list.
> >>
> >> Can we have a definition instead of this 0xfffffffe magic value please?
> >>
> >
> > Hmm, not really actually. It's not a magic value, its just because the
> > logic in Active Namespace ID list would require that it should report
> > any namespaces with ids *higher* than the one specified, so since
> > 0xffffffff (NVME_NSID_BROADCAST) is invalid, NVME_NSID_BROADCAST - 1
> > needs to be as well.
>
> OK.
>
> >
> > What do you say I change it to `min_nsid >= NVME_NSID_BROADCAST - 1`?
> > The original condition just reads well if you are sitting with the spec
> > on the side.
>
> IMO this is clearer:
>
> if (min_nsid + 1 >= NVME_NSID_BROADCAST) {
> return NVME_INVALID_NSID | NVME_DNR;
> }
>
But since min_nsid is uint32_t that would not be wise ;)
I'll go with the - 1 and add a comment!
> Whichever form you prefer you can amend to the respin patch:
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
>
> >
> >>>
> >>> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> >>> ---
> >>> hw/block/nvme.c | 4 ++++
> >>> 1 file changed, 4 insertions(+)
> >>>
> >>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> >>> index 65c2fa3ac1f4..0dac7a41ddae 100644
> >>> --- a/hw/block/nvme.c
> >>> +++ b/hw/block/nvme.c
> >>> @@ -956,6 +956,10 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
> >>>
> >>> trace_pci_nvme_identify_nslist(min_nsid);
> >>>
> >>> + if (min_nsid == 0xfffffffe || min_nsid == NVME_NSID_BROADCAST) {
> >>> + return NVME_INVALID_NSID | NVME_DNR;
> >>> + }
> >>> +
> >>> list = g_malloc0(data_len);
> >>> for (i = 0; i < n->num_namespaces; i++) {
> >>> if (i < min_nsid) {
> >>>
> >>
> >
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 14/18] hw/block/nvme: support identify namespace descriptor list
2020-07-03 8:27 ` Philippe Mathieu-Daudé
@ 2020-07-03 10:00 ` Klaus Jensen
2020-07-03 11:00 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 10:00 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On Jul 3 10:27, Philippe Mathieu-Daudé wrote:
> On 7/3/20 8:34 AM, Klaus Jensen wrote:
> > From: Klaus Jensen <k.jensen@samsung.com>
> >
> > Since we are not providing the NGUID or EUI64 fields, we must support
> > the Namespace UUID. We do not have any way of storing a persistent
> > unique identifier, so conjure up a UUID that is just the namespace id.
> >
> > Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> > Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> > ---
> > hw/block/nvme.c | 41 +++++++++++++++++++++++++++++++++++++++++
> > hw/block/trace-events | 1 +
> > 2 files changed, 42 insertions(+)
> >
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index 8230e0e3826b..65c2fa3ac1f4 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -971,6 +971,45 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
> > return ret;
> > }
> >
> > +static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeIdentify *c)
> > +{
> > + uint32_t nsid = le32_to_cpu(c->nsid);
> > + uint64_t prp1 = le64_to_cpu(c->prp1);
> > + uint64_t prp2 = le64_to_cpu(c->prp2);
> > +
> > + uint8_t list[NVME_IDENTIFY_DATA_SIZE];
> > +
> > + struct data {
> > + struct {
> > + NvmeIdNsDescr hdr;
> > + uint8_t v[16];
>
> You might consider to use QemuUUID from "qemu/uuid.h". The benefits
> are you can use qemu_uuid_parse() qemu_uuid_unparse*() for tracing,
> and DEFINE_PROP_UUID() in case you want to set a particular UUID
> from command line, it case it is important to the guest.
>
Yes, definitely. Niklas also does this in his patch for namespace types
support. And I think that it's very important that it can be made
persistent, which would require a device property.
Thus, if it is OK with the rest of you, I would like to defer this to
when we merge the multiple namespaces patch and add "uuid" as a nvme-ns
device property there. Then, we do not have to add the uuid property on
the nvme device now and then have to keep it around when the namespace
related properties moves to the nvme-ns device.
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters
2020-07-03 9:21 ` Philippe Mathieu-Daudé
@ 2020-07-03 10:10 ` Klaus Jensen
2020-07-03 11:02 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 10:10 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Kevin Wolf, qemu-block, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez
On Jul 3 11:21, Philippe Mathieu-Daudé wrote:
> On 7/3/20 10:46 AM, Klaus Jensen wrote:
> > On Jul 3 10:31, Philippe Mathieu-Daudé wrote:
> >> On 7/3/20 8:34 AM, Klaus Jensen wrote:
> >>> From: Klaus Jensen <k.jensen@samsung.com>
> >>>
> >>> Add support for any remaining mandatory controller operating parameters
> >>> (features).
> >>>
> >>> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> >>> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> >>> ---
> >>> hw/block/nvme.c | 39 +++++++++++++++++++++++++++++++++------
> >>> hw/block/nvme.h | 18 ++++++++++++++++++
> >>> hw/block/trace-events | 2 ++
> >>> include/block/nvme.h | 7 +++++++
> >>> 4 files changed, 60 insertions(+), 6 deletions(-)
> >>>
> >>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> >>> index ba523f6768bf..affb9a967534 100644
> >>> --- a/hw/block/nvme.c
> >>> +++ b/hw/block/nvme.c
> >>> @@ -1056,8 +1056,16 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> >>> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> >>> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> >>> uint32_t result;
> >>> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> >>> + uint16_t iv;
> >>>
> >>> - switch (dw10) {
> >>> + trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
> >>> +
> >>> + if (!nvme_feature_support[fid]) {
> >>> + return NVME_INVALID_FIELD | NVME_DNR;
> >>> + }
> >>> +
> >>> + switch (fid) {
> >>> case NVME_TEMPERATURE_THRESHOLD:
> >>> result = 0;
> >>>
> >>> @@ -1088,14 +1096,27 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> >>> ((n->params.max_ioqpairs - 1) << 16));
> >>> trace_pci_nvme_getfeat_numq(result);
> >>> break;
> >>> + case NVME_INTERRUPT_VECTOR_CONF:
> >>> + iv = dw11 & 0xffff;
> >>> + if (iv >= n->params.max_ioqpairs + 1) {
> >>> + return NVME_INVALID_FIELD | NVME_DNR;
> >>> + }
> >>> +
> >>> + result = iv;
> >>> + if (iv == n->admin_cq.vector) {
> >>> + result |= NVME_INTVC_NOCOALESCING;
> >>> + }
> >>> +
> >>> + result = cpu_to_le32(result);
> >>> + break;
> >>> case NVME_ASYNCHRONOUS_EVENT_CONF:
> >>> result = cpu_to_le32(n->features.async_config);
> >>> break;
> >>> case NVME_TIMESTAMP:
> >>> return nvme_get_feature_timestamp(n, cmd);
> >>> default:
> >>> - trace_pci_nvme_err_invalid_getfeat(dw10);
> >>> - return NVME_INVALID_FIELD | NVME_DNR;
> >>> + result = cpu_to_le32(nvme_feature_default[fid]);
> >>
> >> So here we expect uninitialized fid entries to return 0, right?
> >>
> >
> > Yes, if defaults are not 0 (like NVME_ARBITRATION), it is explicitly set.
> >
> >>> + break;
> >>> }
> >>>
> >>> req->cqe.result = result;
> >>> @@ -1124,8 +1145,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> >>> {
> >>> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> >>> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> >>> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> >>>
> >>> - switch (dw10) {
> >>> + trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
> >>> +
> >>> + if (!nvme_feature_support[fid]) {
> >>> + return NVME_INVALID_FIELD | NVME_DNR;
> >>> + }
> >>> +
> >>> + switch (fid) {
> >>> case NVME_TEMPERATURE_THRESHOLD:
> >>> if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> >>> break;
> >>> @@ -1172,8 +1200,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> >>> case NVME_TIMESTAMP:
> >>> return nvme_set_feature_timestamp(n, cmd);
> >>> default:
> >>> - trace_pci_nvme_err_invalid_setfeat(dw10);
> >>> - return NVME_INVALID_FIELD | NVME_DNR;
> >>> + return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
> >>> }
> >>> return NVME_SUCCESS;
> >>> }
> >>> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> >>> index f8940435f9ef..8ad1e3c89cee 100644
> >>> --- a/hw/block/nvme.h
> >>> +++ b/hw/block/nvme.h
> >>> @@ -87,6 +87,24 @@ typedef struct NvmeFeatureVal {
> >>> uint32_t async_config;
> >>> } NvmeFeatureVal;
>
> What do you think about adding:
>
> --- a/include/block/nvme.h
> +++ b/include/block/nvme.h
> @@ -804,7 +804,8 @@ enum NvmeFeatureIds {
> NVME_WRITE_ATOMICITY = 0xa,
> NVME_ASYNCHRONOUS_EVENT_CONF = 0xb,
> NVME_TIMESTAMP = 0xe,
> - NVME_SOFTWARE_PROGRESS_MARKER = 0x80
> + NVME_SOFTWARE_PROGRESS_MARKER = 0x80,
> + NVME_FEATURE_ID_COUNT = 0x100
> };
>
I can definitely go with that. I added it as NVME_FID_MAX.
> >>>
> >>> +static const uint32_t nvme_feature_default[0x100] = {
>
> Why uint32_t and not uint16_t?
>
The feature values are by definition 32 bits wide, so even though the
defaults here do not require it, I think uin32_t should be used.
> With the previously suggested enum you can now replace 0x100
> by NVME_FEATURE_ID_COUNT.
>
> >>> + [NVME_ARBITRATION] = NVME_ARB_AB_NOLIMIT,
> >>> +};
> >>> +
> >>> +static const bool nvme_feature_support[0x100] = {
>
> Ditto NVME_FEATURE_ID_COUNT.
>
Fixed!
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 10/18] hw/block/nvme: fix missing endian conversion
2020-07-03 8:34 ` Philippe Mathieu-Daudé
@ 2020-07-03 10:11 ` Klaus Jensen
0 siblings, 0 replies; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 10:11 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Kevin Wolf, qemu-block, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez
On Jul 3 10:34, Philippe Mathieu-Daudé wrote:
> On 7/3/20 8:34 AM, Klaus Jensen wrote:
> > From: Klaus Jensen <k.jensen@samsung.com>
> >
> > Fix a missing cpu_to conversion.
> >
> > Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> > Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> > ---
> > hw/block/nvme.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> > index f3a5b857bc92..ba523f6768bf 100644
> > --- a/hw/block/nvme.c
> > +++ b/hw/block/nvme.c
> > @@ -1080,7 +1080,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> >
> > break;
> > case NVME_VOLATILE_WRITE_CACHE:
> > - result = blk_enable_write_cache(n->conf.blk);
> > + result = cpu_to_le32(blk_enable_write_cache(n->conf.blk));
> > trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
> > break;
> > case NVME_NUMBER_OF_QUEUES:
> >
>
> This doesn't look correct. What you probably want:
>
> -- >8 --
>
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -815,8 +815,8 @@ static uint16_t nvme_get_feature(NvmeCtrl *n,
> NvmeCmd *cmd, NvmeRequest *req)
> trace_pci_nvme_getfeat_vwcache(result ? "enabled" : "disabled");
> break;
> case NVME_NUMBER_OF_QUEUES:
> - result = cpu_to_le32((n->params.max_ioqpairs - 1) |
> - ((n->params.max_ioqpairs - 1) << 16));
> + result = (n->params.max_ioqpairs - 1)
> + | ((n->params.max_ioqpairs - 1) << 16);
> trace_pci_nvme_getfeat_numq(result);
> break;
> case NVME_TIMESTAMP:
> @@ -825,8 +825,8 @@ static uint16_t nvme_get_feature(NvmeCtrl *n,
> NvmeCmd *cmd, NvmeRequest *req)
> trace_pci_nvme_err_invalid_getfeat(dw10);
> return NVME_INVALID_FIELD | NVME_DNR;
> }
> + req->cqe.result = cpu_to_le32(result);
>
> - req->cqe.result = result;
> return NVME_SUCCESS;
> }
> ---
>
I replaced this patch with a new one earlier in the series that does
what you suggest and then let the change trickle down to other patches
that add feature cases.
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 15/18] hw/block/nvme: reject invalid nsid values in active namespace id list
2020-07-03 9:22 ` Klaus Jensen
@ 2020-07-03 10:59 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 10:59 UTC (permalink / raw)
To: Klaus Jensen
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On 7/3/20 11:22 AM, Klaus Jensen wrote:
> On Jul 3 11:14, Philippe Mathieu-Daudé wrote:
>> On 7/3/20 10:37 AM, Klaus Jensen wrote:
>>> On Jul 3 10:20, Philippe Mathieu-Daudé wrote:
>>>> On 7/3/20 8:34 AM, Klaus Jensen wrote:
>>>>> From: Klaus Jensen <k.jensen@samsung.com>
>>>>>
>>>>> Reject the nsid broadcast value (0xffffffff) and 0xfffffffe in the
>>>>> Active Namespace ID list.
>>>>
>>>> Can we have a definition instead of this 0xfffffffe magic value please?
>>>>
>>>
>>> Hmm, not really actually. It's not a magic value, its just because the
>>> logic in Active Namespace ID list would require that it should report
>>> any namespaces with ids *higher* than the one specified, so since
>>> 0xffffffff (NVME_NSID_BROADCAST) is invalid, NVME_NSID_BROADCAST - 1
>>> needs to be as well.
>>
>> OK.
>>
>>>
>>> What do you say I change it to `min_nsid >= NVME_NSID_BROADCAST - 1`?
>>> The original condition just reads well if you are sitting with the spec
>>> on the side.
>>
>> IMO this is clearer:
>>
>> if (min_nsid + 1 >= NVME_NSID_BROADCAST) {
>> return NVME_INVALID_NSID | NVME_DNR;
>> }
>>
>
> But since min_nsid is uint32_t that would not be wise ;)
Hmm indeed.
>
> I'll go with the - 1 and add a comment!
Good, thanks.
>
>> Whichever form you prefer you can amend to the respin patch:
>> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
>>
>>>
>>>>>
>>>>> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
>>>>> ---
>>>>> hw/block/nvme.c | 4 ++++
>>>>> 1 file changed, 4 insertions(+)
>>>>>
>>>>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
>>>>> index 65c2fa3ac1f4..0dac7a41ddae 100644
>>>>> --- a/hw/block/nvme.c
>>>>> +++ b/hw/block/nvme.c
>>>>> @@ -956,6 +956,10 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
>>>>>
>>>>> trace_pci_nvme_identify_nslist(min_nsid);
>>>>>
>>>>> + if (min_nsid == 0xfffffffe || min_nsid == NVME_NSID_BROADCAST) {
>>>>> + return NVME_INVALID_NSID | NVME_DNR;
>>>>> + }
>>>>> +
>>>>> list = g_malloc0(data_len);
>>>>> for (i = 0; i < n->num_namespaces; i++) {
>>>>> if (i < min_nsid) {
>>>>>
>>>>
>>>
>>
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 14/18] hw/block/nvme: support identify namespace descriptor list
2020-07-03 10:00 ` Klaus Jensen
@ 2020-07-03 11:00 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 11:00 UTC (permalink / raw)
To: Klaus Jensen
Cc: Kevin Wolf, qemu-block, Dmitry Fomichev, Klaus Jensen,
qemu-devel, Max Reitz, Keith Busch, Javier Gonzalez,
Maxim Levitsky
On 7/3/20 12:00 PM, Klaus Jensen wrote:
> On Jul 3 10:27, Philippe Mathieu-Daudé wrote:
>> On 7/3/20 8:34 AM, Klaus Jensen wrote:
>>> From: Klaus Jensen <k.jensen@samsung.com>
>>>
>>> Since we are not providing the NGUID or EUI64 fields, we must support
>>> the Namespace UUID. We do not have any way of storing a persistent
>>> unique identifier, so conjure up a UUID that is just the namespace id.
>>>
>>> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
>>> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
>>> ---
>>> hw/block/nvme.c | 41 +++++++++++++++++++++++++++++++++++++++++
>>> hw/block/trace-events | 1 +
>>> 2 files changed, 42 insertions(+)
>>>
>>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
>>> index 8230e0e3826b..65c2fa3ac1f4 100644
>>> --- a/hw/block/nvme.c
>>> +++ b/hw/block/nvme.c
>>> @@ -971,6 +971,45 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c)
>>> return ret;
>>> }
>>>
>>> +static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeIdentify *c)
>>> +{
>>> + uint32_t nsid = le32_to_cpu(c->nsid);
>>> + uint64_t prp1 = le64_to_cpu(c->prp1);
>>> + uint64_t prp2 = le64_to_cpu(c->prp2);
>>> +
>>> + uint8_t list[NVME_IDENTIFY_DATA_SIZE];
>>> +
>>> + struct data {
>>> + struct {
>>> + NvmeIdNsDescr hdr;
>>> + uint8_t v[16];
>>
>> You might consider to use QemuUUID from "qemu/uuid.h". The benefits
>> are you can use qemu_uuid_parse() qemu_uuid_unparse*() for tracing,
>> and DEFINE_PROP_UUID() in case you want to set a particular UUID
>> from command line, it case it is important to the guest.
>>
>
> Yes, definitely. Niklas also does this in his patch for namespace types
> support. And I think that it's very important that it can be made
> persistent, which would require a device property.
>
> Thus, if it is OK with the rest of you, I would like to defer this to
> when we merge the multiple namespaces patch and add "uuid" as a nvme-ns
> device property there. Then, we do not have to add the uuid property on
> the nvme device now and then have to keep it around when the namespace
> related properties moves to the nvme-ns device.
No objection, it was a simple suggestion to consider for later ;)
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters
2020-07-03 10:10 ` Klaus Jensen
@ 2020-07-03 11:02 ` Philippe Mathieu-Daudé
2020-07-03 14:37 ` Klaus Jensen
0 siblings, 1 reply; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-03 11:02 UTC (permalink / raw)
To: Klaus Jensen
Cc: Kevin Wolf, qemu-block, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez
On 7/3/20 12:10 PM, Klaus Jensen wrote:
> On Jul 3 11:21, Philippe Mathieu-Daudé wrote:
>> On 7/3/20 10:46 AM, Klaus Jensen wrote:
>>> On Jul 3 10:31, Philippe Mathieu-Daudé wrote:
>>>> On 7/3/20 8:34 AM, Klaus Jensen wrote:
>>>>> From: Klaus Jensen <k.jensen@samsung.com>
>>>>>
>>>>> Add support for any remaining mandatory controller operating parameters
>>>>> (features).
>>>>>
>>>>> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
>>>>> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
>>>>> ---
>>>>> hw/block/nvme.c | 39 +++++++++++++++++++++++++++++++++------
>>>>> hw/block/nvme.h | 18 ++++++++++++++++++
>>>>> hw/block/trace-events | 2 ++
>>>>> include/block/nvme.h | 7 +++++++
>>>>> 4 files changed, 60 insertions(+), 6 deletions(-)
>>>>>
>>>>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
>>>>> index ba523f6768bf..affb9a967534 100644
>>>>> --- a/hw/block/nvme.c
>>>>> +++ b/hw/block/nvme.c
>>>>> @@ -1056,8 +1056,16 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>>>> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
>>>>> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
>>>>> uint32_t result;
>>>>> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
>>>>> + uint16_t iv;
>>>>>
>>>>> - switch (dw10) {
>>>>> + trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
>>>>> +
>>>>> + if (!nvme_feature_support[fid]) {
>>>>> + return NVME_INVALID_FIELD | NVME_DNR;
>>>>> + }
>>>>> +
>>>>> + switch (fid) {
>>>>> case NVME_TEMPERATURE_THRESHOLD:
>>>>> result = 0;
>>>>>
>>>>> @@ -1088,14 +1096,27 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>>>> ((n->params.max_ioqpairs - 1) << 16));
>>>>> trace_pci_nvme_getfeat_numq(result);
>>>>> break;
>>>>> + case NVME_INTERRUPT_VECTOR_CONF:
>>>>> + iv = dw11 & 0xffff;
>>>>> + if (iv >= n->params.max_ioqpairs + 1) {
>>>>> + return NVME_INVALID_FIELD | NVME_DNR;
>>>>> + }
>>>>> +
>>>>> + result = iv;
>>>>> + if (iv == n->admin_cq.vector) {
>>>>> + result |= NVME_INTVC_NOCOALESCING;
>>>>> + }
>>>>> +
>>>>> + result = cpu_to_le32(result);
>>>>> + break;
>>>>> case NVME_ASYNCHRONOUS_EVENT_CONF:
>>>>> result = cpu_to_le32(n->features.async_config);
>>>>> break;
>>>>> case NVME_TIMESTAMP:
>>>>> return nvme_get_feature_timestamp(n, cmd);
>>>>> default:
>>>>> - trace_pci_nvme_err_invalid_getfeat(dw10);
>>>>> - return NVME_INVALID_FIELD | NVME_DNR;
>>>>> + result = cpu_to_le32(nvme_feature_default[fid]);
>>>>
>>>> So here we expect uninitialized fid entries to return 0, right?
>>>>
>>>
>>> Yes, if defaults are not 0 (like NVME_ARBITRATION), it is explicitly set.
>>>
>>>>> + break;
>>>>> }
>>>>>
>>>>> req->cqe.result = result;
>>>>> @@ -1124,8 +1145,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>>>> {
>>>>> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
>>>>> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
>>>>> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
>>>>>
>>>>> - switch (dw10) {
>>>>> + trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
>>>>> +
>>>>> + if (!nvme_feature_support[fid]) {
>>>>> + return NVME_INVALID_FIELD | NVME_DNR;
>>>>> + }
>>>>> +
>>>>> + switch (fid) {
>>>>> case NVME_TEMPERATURE_THRESHOLD:
>>>>> if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
>>>>> break;
>>>>> @@ -1172,8 +1200,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>>>> case NVME_TIMESTAMP:
>>>>> return nvme_set_feature_timestamp(n, cmd);
>>>>> default:
>>>>> - trace_pci_nvme_err_invalid_setfeat(dw10);
>>>>> - return NVME_INVALID_FIELD | NVME_DNR;
>>>>> + return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
>>>>> }
>>>>> return NVME_SUCCESS;
>>>>> }
>>>>> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
>>>>> index f8940435f9ef..8ad1e3c89cee 100644
>>>>> --- a/hw/block/nvme.h
>>>>> +++ b/hw/block/nvme.h
>>>>> @@ -87,6 +87,24 @@ typedef struct NvmeFeatureVal {
>>>>> uint32_t async_config;
>>>>> } NvmeFeatureVal;
>>
>> What do you think about adding:
>>
>> --- a/include/block/nvme.h
>> +++ b/include/block/nvme.h
>> @@ -804,7 +804,8 @@ enum NvmeFeatureIds {
>> NVME_WRITE_ATOMICITY = 0xa,
>> NVME_ASYNCHRONOUS_EVENT_CONF = 0xb,
>> NVME_TIMESTAMP = 0xe,
>> - NVME_SOFTWARE_PROGRESS_MARKER = 0x80
>> + NVME_SOFTWARE_PROGRESS_MARKER = 0x80,
>> + NVME_FEATURE_ID_COUNT = 0x100
>> };
>>
>
> I can definitely go with that. I added it as NVME_FID_MAX.
Good name.
>
>>>>>
>>>>> +static const uint32_t nvme_feature_default[0x100] = {
>>
>> Why uint32_t and not uint16_t?
>>
>
> The feature values are by definition 32 bits wide, so even though the
> defaults here do not require it, I think uin32_t should be used.
Can you prepend a new patch making nvme_get_feature() return uin32_t
instead of uint16_t? That would be clearer.
>
>> With the previously suggested enum you can now replace 0x100
>> by NVME_FEATURE_ID_COUNT.
>>
>>>>> + [NVME_ARBITRATION] = NVME_ARB_AB_NOLIMIT,
>>>>> +};
>>>>> +
>>>>> +static const bool nvme_feature_support[0x100] = {
>>
>> Ditto NVME_FEATURE_ID_COUNT.
>>
>
> Fixed!
>
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters
2020-07-03 11:02 ` Philippe Mathieu-Daudé
@ 2020-07-03 14:37 ` Klaus Jensen
2020-07-04 21:33 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 42+ messages in thread
From: Klaus Jensen @ 2020-07-03 14:37 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: Kevin Wolf, qemu-block, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez
On Jul 3 13:02, Philippe Mathieu-Daudé wrote:
> On 7/3/20 12:10 PM, Klaus Jensen wrote:
> > On Jul 3 11:21, Philippe Mathieu-Daudé wrote:
> >> On 7/3/20 10:46 AM, Klaus Jensen wrote:
> >>> On Jul 3 10:31, Philippe Mathieu-Daudé wrote:
> >>>> On 7/3/20 8:34 AM, Klaus Jensen wrote:
> >>>>> From: Klaus Jensen <k.jensen@samsung.com>
> >>>>>
> >>>>> Add support for any remaining mandatory controller operating parameters
> >>>>> (features).
> >>>>>
> >>>>> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> >>>>> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> >>>>> ---
> >>>>> hw/block/nvme.c | 39 +++++++++++++++++++++++++++++++++------
> >>>>> hw/block/nvme.h | 18 ++++++++++++++++++
> >>>>> hw/block/trace-events | 2 ++
> >>>>> include/block/nvme.h | 7 +++++++
> >>>>> 4 files changed, 60 insertions(+), 6 deletions(-)
> >>>>>
> >>>>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> >>>>> index ba523f6768bf..affb9a967534 100644
> >>>>> --- a/hw/block/nvme.c
> >>>>> +++ b/hw/block/nvme.c
> >>>>> @@ -1056,8 +1056,16 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> >>>>> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> >>>>> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> >>>>> uint32_t result;
> >>>>> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> >>>>> + uint16_t iv;
> >>>>>
> >>>>> - switch (dw10) {
> >>>>> + trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
> >>>>> +
> >>>>> + if (!nvme_feature_support[fid]) {
> >>>>> + return NVME_INVALID_FIELD | NVME_DNR;
> >>>>> + }
> >>>>> +
> >>>>> + switch (fid) {
> >>>>> case NVME_TEMPERATURE_THRESHOLD:
> >>>>> result = 0;
> >>>>>
> >>>>> @@ -1088,14 +1096,27 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> >>>>> ((n->params.max_ioqpairs - 1) << 16));
> >>>>> trace_pci_nvme_getfeat_numq(result);
> >>>>> break;
> >>>>> + case NVME_INTERRUPT_VECTOR_CONF:
> >>>>> + iv = dw11 & 0xffff;
> >>>>> + if (iv >= n->params.max_ioqpairs + 1) {
> >>>>> + return NVME_INVALID_FIELD | NVME_DNR;
> >>>>> + }
> >>>>> +
> >>>>> + result = iv;
> >>>>> + if (iv == n->admin_cq.vector) {
> >>>>> + result |= NVME_INTVC_NOCOALESCING;
> >>>>> + }
> >>>>> +
> >>>>> + result = cpu_to_le32(result);
> >>>>> + break;
> >>>>> case NVME_ASYNCHRONOUS_EVENT_CONF:
> >>>>> result = cpu_to_le32(n->features.async_config);
> >>>>> break;
> >>>>> case NVME_TIMESTAMP:
> >>>>> return nvme_get_feature_timestamp(n, cmd);
> >>>>> default:
> >>>>> - trace_pci_nvme_err_invalid_getfeat(dw10);
> >>>>> - return NVME_INVALID_FIELD | NVME_DNR;
> >>>>> + result = cpu_to_le32(nvme_feature_default[fid]);
> >>>>
> >>>> So here we expect uninitialized fid entries to return 0, right?
> >>>>
> >>>
> >>> Yes, if defaults are not 0 (like NVME_ARBITRATION), it is explicitly set.
> >>>
> >>>>> + break;
> >>>>> }
> >>>>>
> >>>>> req->cqe.result = result;
> >>>>> @@ -1124,8 +1145,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> >>>>> {
> >>>>> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
> >>>>> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
> >>>>> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
> >>>>>
> >>>>> - switch (dw10) {
> >>>>> + trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
> >>>>> +
> >>>>> + if (!nvme_feature_support[fid]) {
> >>>>> + return NVME_INVALID_FIELD | NVME_DNR;
> >>>>> + }
> >>>>> +
> >>>>> + switch (fid) {
> >>>>> case NVME_TEMPERATURE_THRESHOLD:
> >>>>> if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
> >>>>> break;
> >>>>> @@ -1172,8 +1200,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
> >>>>> case NVME_TIMESTAMP:
> >>>>> return nvme_set_feature_timestamp(n, cmd);
> >>>>> default:
> >>>>> - trace_pci_nvme_err_invalid_setfeat(dw10);
> >>>>> - return NVME_INVALID_FIELD | NVME_DNR;
> >>>>> + return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
> >>>>> }
> >>>>> return NVME_SUCCESS;
> >>>>> }
> >>>>> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
> >>>>> index f8940435f9ef..8ad1e3c89cee 100644
> >>>>> --- a/hw/block/nvme.h
> >>>>> +++ b/hw/block/nvme.h
> >>>>> @@ -87,6 +87,24 @@ typedef struct NvmeFeatureVal {
> >>>>> uint32_t async_config;
> >>>>> } NvmeFeatureVal;
> >>
> >> What do you think about adding:
> >>
> >> --- a/include/block/nvme.h
> >> +++ b/include/block/nvme.h
> >> @@ -804,7 +804,8 @@ enum NvmeFeatureIds {
> >> NVME_WRITE_ATOMICITY = 0xa,
> >> NVME_ASYNCHRONOUS_EVENT_CONF = 0xb,
> >> NVME_TIMESTAMP = 0xe,
> >> - NVME_SOFTWARE_PROGRESS_MARKER = 0x80
> >> + NVME_SOFTWARE_PROGRESS_MARKER = 0x80,
> >> + NVME_FEATURE_ID_COUNT = 0x100
> >> };
> >>
> >
> > I can definitely go with that. I added it as NVME_FID_MAX.
>
> Good name.
>
> >
> >>>>>
> >>>>> +static const uint32_t nvme_feature_default[0x100] = {
> >>
> >> Why uint32_t and not uint16_t?
> >>
> >
> > The feature values are by definition 32 bits wide, so even though the
> > defaults here do not require it, I think uin32_t should be used.
>
> Can you prepend a new patch making nvme_get_feature() return uin32_t
> instead of uint16_t? That would be clearer.
>
Ah. Now I see where the confusion comes from ;)
nvme_get_feature() does not return the value of the feature. It returns
a uint16_t with a value from the NvmeStatusCodes enum (which really
should be a typedef used all over the place.
^ permalink raw reply [flat|nested] 42+ messages in thread
* Re: [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters
2020-07-03 14:37 ` Klaus Jensen
@ 2020-07-04 21:33 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 42+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-07-04 21:33 UTC (permalink / raw)
To: Klaus Jensen
Cc: Kevin Wolf, qemu-block, Klaus Jensen, qemu-devel, Max Reitz,
Keith Busch, Javier Gonzalez
On 7/3/20 4:37 PM, Klaus Jensen wrote:
> On Jul 3 13:02, Philippe Mathieu-Daudé wrote:
>> On 7/3/20 12:10 PM, Klaus Jensen wrote:
>>> On Jul 3 11:21, Philippe Mathieu-Daudé wrote:
>>>> On 7/3/20 10:46 AM, Klaus Jensen wrote:
>>>>> On Jul 3 10:31, Philippe Mathieu-Daudé wrote:
>>>>>> On 7/3/20 8:34 AM, Klaus Jensen wrote:
>>>>>>> From: Klaus Jensen <k.jensen@samsung.com>
>>>>>>>
>>>>>>> Add support for any remaining mandatory controller operating parameters
>>>>>>> (features).
>>>>>>>
>>>>>>> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
>>>>>>> Reviewed-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
>>>>>>> ---
>>>>>>> hw/block/nvme.c | 39 +++++++++++++++++++++++++++++++++------
>>>>>>> hw/block/nvme.h | 18 ++++++++++++++++++
>>>>>>> hw/block/trace-events | 2 ++
>>>>>>> include/block/nvme.h | 7 +++++++
>>>>>>> 4 files changed, 60 insertions(+), 6 deletions(-)
>>>>>>>
>>>>>>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
>>>>>>> index ba523f6768bf..affb9a967534 100644
>>>>>>> --- a/hw/block/nvme.c
>>>>>>> +++ b/hw/block/nvme.c
>>>>>>> @@ -1056,8 +1056,16 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>>>>>> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
>>>>>>> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
>>>>>>> uint32_t result;
>>>>>>> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
>>>>>>> + uint16_t iv;
>>>>>>>
>>>>>>> - switch (dw10) {
>>>>>>> + trace_pci_nvme_getfeat(nvme_cid(req), fid, dw11);
>>>>>>> +
>>>>>>> + if (!nvme_feature_support[fid]) {
>>>>>>> + return NVME_INVALID_FIELD | NVME_DNR;
>>>>>>> + }
>>>>>>> +
>>>>>>> + switch (fid) {
>>>>>>> case NVME_TEMPERATURE_THRESHOLD:
>>>>>>> result = 0;
>>>>>>>
>>>>>>> @@ -1088,14 +1096,27 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>>>>>> ((n->params.max_ioqpairs - 1) << 16));
>>>>>>> trace_pci_nvme_getfeat_numq(result);
>>>>>>> break;
>>>>>>> + case NVME_INTERRUPT_VECTOR_CONF:
>>>>>>> + iv = dw11 & 0xffff;
>>>>>>> + if (iv >= n->params.max_ioqpairs + 1) {
>>>>>>> + return NVME_INVALID_FIELD | NVME_DNR;
>>>>>>> + }
>>>>>>> +
>>>>>>> + result = iv;
>>>>>>> + if (iv == n->admin_cq.vector) {
>>>>>>> + result |= NVME_INTVC_NOCOALESCING;
>>>>>>> + }
>>>>>>> +
>>>>>>> + result = cpu_to_le32(result);
>>>>>>> + break;
>>>>>>> case NVME_ASYNCHRONOUS_EVENT_CONF:
>>>>>>> result = cpu_to_le32(n->features.async_config);
>>>>>>> break;
>>>>>>> case NVME_TIMESTAMP:
>>>>>>> return nvme_get_feature_timestamp(n, cmd);
>>>>>>> default:
>>>>>>> - trace_pci_nvme_err_invalid_getfeat(dw10);
>>>>>>> - return NVME_INVALID_FIELD | NVME_DNR;
>>>>>>> + result = cpu_to_le32(nvme_feature_default[fid]);
>>>>>>
>>>>>> So here we expect uninitialized fid entries to return 0, right?
>>>>>>
>>>>>
>>>>> Yes, if defaults are not 0 (like NVME_ARBITRATION), it is explicitly set.
>>>>>
>>>>>>> + break;
>>>>>>> }
>>>>>>>
>>>>>>> req->cqe.result = result;
>>>>>>> @@ -1124,8 +1145,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>>>>>> {
>>>>>>> uint32_t dw10 = le32_to_cpu(cmd->cdw10);
>>>>>>> uint32_t dw11 = le32_to_cpu(cmd->cdw11);
>>>>>>> + uint8_t fid = NVME_GETSETFEAT_FID(dw10);
>>>>>>>
>>>>>>> - switch (dw10) {
>>>>>>> + trace_pci_nvme_setfeat(nvme_cid(req), fid, dw11);
>>>>>>> +
>>>>>>> + if (!nvme_feature_support[fid]) {
>>>>>>> + return NVME_INVALID_FIELD | NVME_DNR;
>>>>>>> + }
>>>>>>> +
>>>>>>> + switch (fid) {
>>>>>>> case NVME_TEMPERATURE_THRESHOLD:
>>>>>>> if (NVME_TEMP_TMPSEL(dw11) != NVME_TEMP_TMPSEL_COMPOSITE) {
>>>>>>> break;
>>>>>>> @@ -1172,8 +1200,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
>>>>>>> case NVME_TIMESTAMP:
>>>>>>> return nvme_set_feature_timestamp(n, cmd);
>>>>>>> default:
>>>>>>> - trace_pci_nvme_err_invalid_setfeat(dw10);
>>>>>>> - return NVME_INVALID_FIELD | NVME_DNR;
>>>>>>> + return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
>>>>>>> }
>>>>>>> return NVME_SUCCESS;
>>>>>>> }
>>>>>>> diff --git a/hw/block/nvme.h b/hw/block/nvme.h
>>>>>>> index f8940435f9ef..8ad1e3c89cee 100644
>>>>>>> --- a/hw/block/nvme.h
>>>>>>> +++ b/hw/block/nvme.h
>>>>>>> @@ -87,6 +87,24 @@ typedef struct NvmeFeatureVal {
>>>>>>> uint32_t async_config;
>>>>>>> } NvmeFeatureVal;
>>>>
>>>> What do you think about adding:
>>>>
>>>> --- a/include/block/nvme.h
>>>> +++ b/include/block/nvme.h
>>>> @@ -804,7 +804,8 @@ enum NvmeFeatureIds {
>>>> NVME_WRITE_ATOMICITY = 0xa,
>>>> NVME_ASYNCHRONOUS_EVENT_CONF = 0xb,
>>>> NVME_TIMESTAMP = 0xe,
>>>> - NVME_SOFTWARE_PROGRESS_MARKER = 0x80
>>>> + NVME_SOFTWARE_PROGRESS_MARKER = 0x80,
>>>> + NVME_FEATURE_ID_COUNT = 0x100
>>>> };
>>>>
>>>
>>> I can definitely go with that. I added it as NVME_FID_MAX.
>>
>> Good name.
>>
>>>
>>>>>>>
>>>>>>> +static const uint32_t nvme_feature_default[0x100] = {
>>>>
>>>> Why uint32_t and not uint16_t?
>>>>
>>>
>>> The feature values are by definition 32 bits wide, so even though the
>>> defaults here do not require it, I think uin32_t should be used.
>>
>> Can you prepend a new patch making nvme_get_feature() return uin32_t
>> instead of uint16_t? That would be clearer.
>>
>
> Ah. Now I see where the confusion comes from ;)
>
> nvme_get_feature() does not return the value of the feature. It returns
> a uint16_t with a value from the NvmeStatusCodes enum (which really
> should be a typedef used all over the place.
Ah! You are right, I misread it indeed :)
^ permalink raw reply [flat|nested] 42+ messages in thread
end of thread, other threads:[~2020-07-04 21:42 UTC | newest]
Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-03 6:34 [PATCH v2 00/18] hw/block/nvme: bump to v1.3 Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 01/18] hw/block/nvme: bump spec data structures " Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 02/18] hw/block/nvme: additional tracing Klaus Jensen
2020-07-03 8:03 ` Philippe Mathieu-Daudé
2020-07-03 8:14 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 03/18] hw/block/nvme: add support for the abort command Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 04/18] hw/block/nvme: add temperature threshold feature Klaus Jensen
2020-07-03 8:08 ` Philippe Mathieu-Daudé
2020-07-03 8:18 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 05/18] hw/block/nvme: mark fw slot 1 as read-only Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 06/18] hw/block/nvme: add support for the get log page command Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 07/18] hw/block/nvme: add support for the asynchronous event request command Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 08/18] hw/block/nvme: move NvmeFeatureVal into hw/block/nvme.h Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 09/18] hw/block/nvme: flush write cache when disabled Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 10/18] hw/block/nvme: fix missing endian conversion Klaus Jensen
2020-07-03 8:34 ` Philippe Mathieu-Daudé
2020-07-03 10:11 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 11/18] hw/block/nvme: add remaining mandatory controller parameters Klaus Jensen
2020-07-03 8:31 ` Philippe Mathieu-Daudé
2020-07-03 8:46 ` Klaus Jensen
2020-07-03 9:21 ` Philippe Mathieu-Daudé
2020-07-03 10:10 ` Klaus Jensen
2020-07-03 11:02 ` Philippe Mathieu-Daudé
2020-07-03 14:37 ` Klaus Jensen
2020-07-04 21:33 ` Philippe Mathieu-Daudé
2020-07-03 6:34 ` [PATCH v2 12/18] hw/block/nvme: support the get/set features select and save fields Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 13/18] hw/block/nvme: make sure ncqr and nsqr is valid Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 14/18] hw/block/nvme: support identify namespace descriptor list Klaus Jensen
2020-07-03 8:27 ` Philippe Mathieu-Daudé
2020-07-03 10:00 ` Klaus Jensen
2020-07-03 11:00 ` Philippe Mathieu-Daudé
2020-07-03 6:34 ` [PATCH v2 15/18] hw/block/nvme: reject invalid nsid values in active namespace id list Klaus Jensen
2020-07-03 8:20 ` Philippe Mathieu-Daudé
2020-07-03 8:37 ` Klaus Jensen
2020-07-03 9:14 ` Philippe Mathieu-Daudé
2020-07-03 9:22 ` Klaus Jensen
2020-07-03 10:59 ` Philippe Mathieu-Daudé
2020-07-03 6:34 ` [PATCH v2 16/18] hw/block/nvme: enforce valid queue creation sequence Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 17/18] hw/block/nvme: provide the mandatory subnqn field Klaus Jensen
2020-07-03 8:18 ` Philippe Mathieu-Daudé
2020-07-03 8:25 ` Klaus Jensen
2020-07-03 6:34 ` [PATCH v2 18/18] hw/block/nvme: bump supported version to v1.3 Klaus Jensen
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.