[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v7 01/11] hw/block/nvme: Add Commands Supported and Effects l
From: |
Klaus Jensen |
Subject: |
Re: [PATCH v7 01/11] hw/block/nvme: Add Commands Supported and Effects log |
Date: |
Mon, 19 Oct 2020 22:16:16 +0200 |
On Oct 19 11:17, Dmitry Fomichev wrote:
> This log page becomes necessary to implement to allow checking for
> Zone Append command support in Zoned Namespace Command Set.
>
> This commit adds the code to report this log page for NVM Command
> Set only. The parts that are specific to zoned operation will be
> added later in the series.
>
> All incoming admin and i/o commands are now only processed if their
> corresponding support bits are set in this log. This provides an
> easy way to control what commands to support and what not to
> depending on set CC.CSS.
>
> Signed-off-by: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> ---
> hw/block/nvme-ns.h | 1 +
> hw/block/nvme.c | 98 +++++++++++++++++++++++++++++++++++++++----
> hw/block/trace-events | 2 +
> include/block/nvme.h | 19 +++++++++
> 4 files changed, 111 insertions(+), 9 deletions(-)
>
> diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h
> index 83734f4606..ea8c2f785d 100644
> --- a/hw/block/nvme-ns.h
> +++ b/hw/block/nvme-ns.h
> @@ -29,6 +29,7 @@ typedef struct NvmeNamespace {
> int32_t bootindex;
> int64_t size;
> NvmeIdNs id_ns;
> + const uint32_t *iocs;
>
> NvmeNamespaceParams params;
> } NvmeNamespace;
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 9d30ca69dc..5a9493d89f 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -111,6 +111,28 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = {
> [NVME_TIMESTAMP] = NVME_FEAT_CAP_CHANGE,
> };
>
> +static const uint32_t nvme_cse_acs[256] = {
> + [NVME_ADM_CMD_DELETE_SQ] = NVME_CMD_EFF_CSUPP,
> + [NVME_ADM_CMD_CREATE_SQ] = NVME_CMD_EFF_CSUPP,
> + [NVME_ADM_CMD_DELETE_CQ] = NVME_CMD_EFF_CSUPP,
> + [NVME_ADM_CMD_CREATE_CQ] = NVME_CMD_EFF_CSUPP,
> + [NVME_ADM_CMD_IDENTIFY] = NVME_CMD_EFF_CSUPP,
> + [NVME_ADM_CMD_SET_FEATURES] = NVME_CMD_EFF_CSUPP,
> + [NVME_ADM_CMD_GET_FEATURES] = NVME_CMD_EFF_CSUPP,
> + [NVME_ADM_CMD_GET_LOG_PAGE] = NVME_CMD_EFF_CSUPP,
> + [NVME_ADM_CMD_ASYNC_EV_REQ] = NVME_CMD_EFF_CSUPP,
> +};
NVME_ADM_CMD_ABORT is missing. And since you added a (redundant) check
in nvme_admin_cmd that cheks this table, Abort is now an invalid
command.
Also, can you reorder it according to opcode instead of
pseudo-lexicographically?
> +
> +static const uint32_t nvme_cse_iocs_none[256] = {
> +};
[-pedantic] no need for the '= {}'
> +
> +static const uint32_t nvme_cse_iocs_nvm[256] = {
> + [NVME_CMD_FLUSH] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
> + [NVME_CMD_WRITE_ZEROES] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
> + [NVME_CMD_WRITE] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC,
> + [NVME_CMD_READ] = NVME_CMD_EFF_CSUPP,
> +};
> +
> static void nvme_process_sq(void *opaque);
>
> static uint16_t nvme_cid(NvmeRequest *req)
> @@ -1032,10 +1054,6 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest
> *req)
> trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req),
> req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode));
>
> - if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_ADMIN_ONLY) {
> - return NVME_INVALID_OPCODE | NVME_DNR;
> - }
> -
I would assume the device to respond with invalid opcode before
validating the nsid if it is an admin only device.
> if (!nvme_nsid_valid(n, nsid)) {
> return NVME_INVALID_NSID | NVME_DNR;
> }
> @@ -1045,6 +1063,11 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest
> *req)
> return NVME_INVALID_FIELD | NVME_DNR;
> }
>
> + if (!(req->ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
> + trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
> + return NVME_INVALID_OPCODE | NVME_DNR;
> + }
> +
> switch (req->cmd.opcode) {
> case NVME_CMD_FLUSH:
> return nvme_flush(n, req);
> @@ -1054,8 +1077,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest
> *req)
> case NVME_CMD_READ:
> return nvme_rw(n, req);
> default:
> - trace_pci_nvme_err_invalid_opc(req->cmd.opcode);
> - return NVME_INVALID_OPCODE | NVME_DNR;
> + assert(false);
> }
> }
>
> @@ -1291,6 +1313,39 @@ static uint16_t nvme_error_info(NvmeCtrl *n, uint8_t
> rae, uint32_t buf_len,
> DMA_DIRECTION_FROM_DEVICE, req);
> }
>
> +static uint16_t nvme_cmd_effects(NvmeCtrl *n, uint32_t buf_len,
> + uint64_t off, NvmeRequest *req)
> +{
> + NvmeEffectsLog log = {};
[-pedantic] and empty initializer list is not allowed, should be '{0}'.
> + const uint32_t *src_iocs = NULL;
> + uint32_t trans_len;
> +
> + trace_pci_nvme_cmd_supp_and_effects_log_read();
This has just been traced in nvme_admin_cmd and this doesn't add any
additional info.
> +
> + if (off >= sizeof(log)) {
> + trace_pci_nvme_err_invalid_effects_log_offset(off);
Can we do `trace_pci_nvme_err_invalid_log_page_offset(off) instead? Then
we can easily reuse it in the other log pages.
> + return NVME_INVALID_FIELD | NVME_DNR;
> + }
> +
> + switch (NVME_CC_CSS(n->bar.cc)) {
> + case NVME_CC_CSS_NVM:
> + src_iocs = nvme_cse_iocs_nvm;
> + case NVME_CC_CSS_ADMIN_ONLY:
> + break;
> + }
> +
> + memcpy(log.acs, nvme_cse_acs, sizeof(nvme_cse_acs));
> +
> + if (src_iocs) {
> + memcpy(log.iocs, src_iocs, sizeof(log.iocs));
> + }
> +
> + trans_len = MIN(sizeof(log) - off, buf_len);
> +
> + return nvme_dma(n, ((uint8_t *)&log) + off, trans_len,
> + DMA_DIRECTION_FROM_DEVICE, req);
> +}
> +
> static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest *req)
> {
> NvmeCmd *cmd = &req->cmd;
> @@ -1334,6 +1389,8 @@ static uint16_t nvme_get_log(NvmeCtrl *n, NvmeRequest
> *req)
> return nvme_smart_info(n, rae, len, off, req);
> case NVME_LOG_FW_SLOT_INFO:
> return nvme_fw_log_info(n, len, off, req);
> + case NVME_LOG_CMD_EFFECTS:
> + return nvme_cmd_effects(n, len, off, req);
> default:
> trace_pci_nvme_err_invalid_log_page(nvme_cid(req), lid);
> return NVME_INVALID_FIELD | NVME_DNR;
> @@ -1920,6 +1977,11 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n,
> NvmeRequest *req)
> trace_pci_nvme_admin_cmd(nvme_cid(req), nvme_sqid(req), req->cmd.opcode,
> nvme_adm_opc_str(req->cmd.opcode));
>
> + if (!(nvme_cse_acs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) {
> + trace_pci_nvme_err_invalid_admin_opc(req->cmd.opcode);
> + return NVME_INVALID_OPCODE | NVME_DNR;
> + }
> +
This is the (redundant) check that effectively makes Abort an invalid
command.
> switch (req->cmd.opcode) {
> case NVME_ADM_CMD_DELETE_SQ:
> return nvme_del_sq(n, req);
> @@ -1942,8 +2004,7 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeRequest
> *req)
> case NVME_ADM_CMD_ASYNC_EV_REQ:
> return nvme_aer(n, req);
> default:
> - trace_pci_nvme_err_invalid_admin_opc(req->cmd.opcode);
> - return NVME_INVALID_OPCODE | NVME_DNR;
> + assert(false);
> }
> }
>
> @@ -2031,6 +2092,23 @@ static void nvme_clear_ctrl(NvmeCtrl *n)
> n->bar.cc = 0;
> }
>
> +static void nvme_select_ns_iocs(NvmeCtrl *n)
> +{
> + NvmeNamespace *ns;
> + int i;
> +
> + for (i = 1; i <= n->num_namespaces; i++) {
> + ns = nvme_ns(n, i);
> + if (!ns) {
> + continue;
> + }
> + ns->iocs = nvme_cse_iocs_none;
> + if (NVME_CC_CSS(n->bar.cc) != NVME_CC_CSS_ADMIN_ONLY) {
> + ns->iocs = nvme_cse_iocs_nvm;
> + }
> + }
> +}
> +
> static int nvme_start_ctrl(NvmeCtrl *n)
> {
> uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12;
> @@ -2129,6 +2207,8 @@ static int nvme_start_ctrl(NvmeCtrl *n)
>
> QTAILQ_INIT(&n->aer_queue);
>
> + nvme_select_ns_iocs(n);
> +
> return 0;
> }
>
> @@ -2737,7 +2817,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice
> *pci_dev)
> id->acl = 3;
> id->aerl = n->params.aerl;
> id->frmw = (NVME_NUM_FW_SLOTS << 1) | NVME_FRMW_SLOT1_RO;
> - id->lpa = NVME_LPA_NS_SMART | NVME_LPA_EXTENDED;
> + id->lpa = NVME_LPA_NS_SMART | NVME_LPA_CSE | NVME_LPA_EXTENDED;
>
> /* recommended default value (~70 C) */
> id->wctemp = cpu_to_le16(NVME_TEMPERATURE_WARNING);
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index fac5995d94..0ae9cb0d35 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -85,6 +85,7 @@ pci_nvme_mmio_start_success(void) "setting controller
> enable bit succeeded"
> pci_nvme_mmio_stopped(void) "cleared controller enable bit"
> pci_nvme_mmio_shutdown_set(void) "shutdown bit set"
> pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
> +pci_nvme_cmd_supp_and_effects_log_read(void) "commands supported and effects
> log read"
>
> # nvme traces for error conditions
> pci_nvme_err_mdts(uint16_t cid, size_t len) "cid %"PRIu16" len %zu"
> @@ -104,6 +105,7 @@ pci_nvme_err_invalid_prp(void) "invalid PRP"
> pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8""
> pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8""
> pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit)
> "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64""
> +pci_nvme_err_invalid_effects_log_offset(uint64_t ofs) "commands supported
> and effects log offset must be 0, got %"PRIu64""
> pci_nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue
> deletion, sid=%"PRIu16""
> pci_nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating
> submission queue, invalid cqid=%"PRIu16""
> pci_nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating
> submission queue, invalid sqid=%"PRIu16""
> diff --git a/include/block/nvme.h b/include/block/nvme.h
> index 6de2d5aa75..4779495b7d 100644
> --- a/include/block/nvme.h
> +++ b/include/block/nvme.h
> @@ -744,10 +744,27 @@ enum NvmeSmartWarn {
> NVME_SMART_FAILED_VOLATILE_MEDIA = 1 << 4,
> };
>
> +typedef struct NvmeEffectsLog {
> + uint32_t acs[256];
> + uint32_t iocs[256];
> + uint8_t resv[2048];
> +} NvmeEffectsLog;
> +
> +enum {
> + NVME_CMD_EFF_CSUPP = 1 << 0,
> + NVME_CMD_EFF_LBCC = 1 << 1,
> + NVME_CMD_EFF_NCC = 1 << 2,
> + NVME_CMD_EFF_NIC = 1 << 3,
> + NVME_CMD_EFF_CCC = 1 << 4,
> + NVME_CMD_EFF_CSE_MASK = 3 << 16,
> + NVME_CMD_EFF_UUID_SEL = 1 << 19,
> +};
> +
> enum NvmeLogIdentifier {
> NVME_LOG_ERROR_INFO = 0x01,
> NVME_LOG_SMART_INFO = 0x02,
> NVME_LOG_FW_SLOT_INFO = 0x03,
> + NVME_LOG_CMD_EFFECTS = 0x05,
> };
>
> typedef struct QEMU_PACKED NvmePSD {
> @@ -860,6 +877,7 @@ enum NvmeIdCtrlFrmw {
>
> enum NvmeIdCtrlLpa {
> NVME_LPA_NS_SMART = 1 << 0,
> + NVME_LPA_CSE = 1 << 1,
> NVME_LPA_EXTENDED = 1 << 2,
> };
>
> @@ -1059,6 +1077,7 @@ static inline void _nvme_check_size(void)
> QEMU_BUILD_BUG_ON(sizeof(NvmeErrorLog) != 64);
> QEMU_BUILD_BUG_ON(sizeof(NvmeFwSlotInfoLog) != 512);
> QEMU_BUILD_BUG_ON(sizeof(NvmeSmartLog) != 512);
> + QEMU_BUILD_BUG_ON(sizeof(NvmeEffectsLog) != 4096);
> QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrl) != 4096);
> QEMU_BUILD_BUG_ON(sizeof(NvmeIdNs) != 4096);
> QEMU_BUILD_BUG_ON(sizeof(NvmeSglDescriptor) != 16);
> --
> 2.21.0
>
>
--
One of us - No more doubt, silence or taboo about mental illness.
signature.asc
Description: PGP signature
- [PATCH v7 00/11] hw/block/nvme: Support Namespace Types and Zoned Namespace Command Set, Dmitry Fomichev, 2020/10/18
- [PATCH v7 02/11] hw/block/nvme: Generate namespace UUIDs, Dmitry Fomichev, 2020/10/18
- [PATCH v7 01/11] hw/block/nvme: Add Commands Supported and Effects log, Dmitry Fomichev, 2020/10/18
- [PATCH v7 03/11] hw/block/nvme: Add support for Namespace Types, Dmitry Fomichev, 2020/10/18
- [PATCH v7 04/11] hw/block/nvme: Support allocated CNS command variants, Dmitry Fomichev, 2020/10/18
- [PATCH v7 06/11] hw/block/nvme: Introduce max active and open zone limits, Dmitry Fomichev, 2020/10/18