From: Klaus Birkelund Jensen Date: Fri, 5 Jul 2019 07:23:28 +0000 (+0200) Subject: nvme: add missing mandatory Features X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=88e81b41e20b302a753687973f0e1df6650ca076;p=people%2Fpauldu%2Fqemu.git nvme: add missing mandatory Features Add support for returning a resonable response to Get/Set Features of mandatory features. Signed-off-by: Klaus Birkelund Jensen --- diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 56235f7f5e..450c9e0c53 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -862,13 +862,24 @@ 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; + trace_nvme_getfeat(dw10); + switch (dw10) { + case NVME_ARBITRATION: + result = cpu_to_le32(n->features.arbitration); + break; + case NVME_POWER_MANAGEMENT: + result = cpu_to_le32(n->features.power_mgmt); + break; case NVME_TEMPERATURE_THRESHOLD: result = cpu_to_le32(n->features.temp_thresh); break; case NVME_ERROR_RECOVERY: + result = cpu_to_le32(n->features.err_rec); + break; case NVME_VOLATILE_WRITE_CACHE: result = blk_enable_write_cache(n->conf.blk); trace_nvme_getfeat_vwcache(result ? "enabled" : "disabled"); @@ -880,6 +891,19 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) break; case NVME_TIMESTAMP: return nvme_get_feature_timestamp(n, cmd); + case NVME_INTERRUPT_COALESCING: + result = cpu_to_le32(n->features.int_coalescing); + break; + case NVME_INTERRUPT_VECTOR_CONF: + if ((dw11 & 0xffff) > n->params.num_queues) { + return NVME_INVALID_FIELD | NVME_DNR; + } + + result = cpu_to_le32(n->features.int_vector_config[dw11 & 0xffff]); + break; + case NVME_WRITE_ATOMICITY: + result = cpu_to_le32(n->features.write_atomicity); + break; case NVME_ASYNCHRONOUS_EVENT_CONF: result = cpu_to_le32(n->features.async_config); break; @@ -915,6 +939,8 @@ 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); + trace_nvme_setfeat(dw10, dw11); + switch (dw10) { case NVME_TEMPERATURE_THRESHOLD: n->features.temp_thresh = dw11; @@ -939,6 +965,13 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) case NVME_ASYNCHRONOUS_EVENT_CONF: n->features.async_config = dw11; break; + case NVME_ARBITRATION: + case NVME_POWER_MANAGEMENT: + case NVME_ERROR_RECOVERY: + case NVME_INTERRUPT_COALESCING: + case NVME_INTERRUPT_VECTOR_CONF: + case NVME_WRITE_ATOMICITY: + return NVME_FEAT_NOT_CHANGABLE | NVME_DNR; default: trace_nvme_err_invalid_setfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; @@ -1695,6 +1728,14 @@ static void nvme_init_state(NvmeCtrl *n) n->aer_reqs = g_new0(NvmeRequest *, NVME_AERL + 1); n->temperature = NVME_TEMPERATURE; n->features.temp_thresh = 0x14d; + n->features.int_vector_config = g_malloc0_n(n->params.num_queues, + sizeof(*n->features.int_vector_config)); + + /* disable coalescing (not supported) */ + for (int i = 0; i < n->params.num_queues; i++) { + n->features.int_vector_config[i] = i | (1 << 16); + } + } static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev) @@ -1771,6 +1812,10 @@ static void nvme_init_ctrl(NvmeCtrl *n) id->nn = cpu_to_le32(n->num_namespaces); id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROS | NVME_ONCS_TIMESTAMP); + if (blk_enable_write_cache(n->conf.blk)) { + id->vwc = 1; + } + strcpy((char *) id->subnqn, "nqn.2014-08.org.nvmexpress:uuid:"); qemu_uuid_unparse(&qemu_uuid, (char *) id->subnqn + strlen((char *) id->subnqn)); @@ -1778,9 +1823,6 @@ static void nvme_init_ctrl(NvmeCtrl *n) id->psd[0].mp = cpu_to_le16(0x9c4); id->psd[0].enlat = cpu_to_le32(0x10); id->psd[0].exlat = cpu_to_le32(0x4); - if (blk_enable_write_cache(n->conf.blk)) { - id->vwc = 1; - } n->bar.cap = 0; NVME_CAP_SET_MQES(n->bar.cap, 0x7ff); @@ -1878,6 +1920,7 @@ static void nvme_exit(PCIDevice *pci_dev) g_free(n->sq); g_free(n->elpes); g_free(n->aer_reqs); + g_free(n->features.int_vector_config); if (n->params.cmb_size_mb) { g_free(n->cmbuf); diff --git a/hw/block/trace-events b/hw/block/trace-events index ed666bbc94..17485bb037 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -41,6 +41,8 @@ nvme_del_cq(uint16_t cqid) "deleted completion queue, sqid=%"PRIu16"" nvme_identify_ctrl(void) "identify controller" nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16"" nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16"" +nvme_getfeat(uint32_t fid) "fid 0x%"PRIx32"" +nvme_setfeat(uint32_t fid, uint32_t val) "fid 0x%"PRIx32" val 0x%"PRIx32"" nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s" nvme_getfeat_numq(int result) "get feature number of queues, result=%d" 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 5a10b8b674..d24b1f28e0 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -445,7 +445,8 @@ enum NvmeStatusCodes { NVME_FW_REQ_RESET = 0x010b, NVME_INVALID_QUEUE_DEL = 0x010c, NVME_FID_NOT_SAVEABLE = 0x010d, - NVME_FID_NOT_NSID_SPEC = 0x010f, + NVME_FEAT_NOT_CHANGABLE = 0x010e, + NVME_FEAT_NOT_NSID_SPEC = 0x010f, NVME_FW_REQ_SUSYSTEM_RESET = 0x0110, NVME_CONFLICTING_ATTRS = 0x0180, NVME_INVALID_PROT_INFO = 0x0181,