nvme pull 2 Nov 2020

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE28EdLTc7SjdV9QLsYlFWYQpPbMAFAl+gI74ACgkQYlFWYQpP
 bMCBrA/9GXMZZGDfHFenXF+rS6J+ZKxtk29vq9Ly8KZ9YW7CzF9MP8qE/5iyFfmx
 d1BknXGQerW2kAzpkOq2/MKDklOc+0BAhaTdUaFR/ao5ZKuv2LQ8uFnKVoTrhTx9
 +HVkTVUTnez6ReCZVIrtN4+XVdyQTeQotJg6H2m5Q/BxQKcj6OMOlneuSGDn5vFN
 EWgDvEmfFEkzbN8FMXtkT35bg3vA5TGmfQRMk1SMMREOPxF04CaTVTxYscCpS0WC
 Cl+62mx4XLjscK7hwXuTNTrxeOLxZ2xLK5dhDd/qxBveio07mIM5X2psdKR0t5qX
 HLtm437T9CAYmyo8jgvM4KL8f+rbJnLd579qyVwIMsue28Qisj9nuWCTcaEpjfck
 4krhxJwxenRtqQ9wYrnbnQI5yQDIE6iUGf0toXwCNdJIr+FvyIcT7vJtTzZXtRI8
 sxwK5wfJ/WSey9uNLZGFbQuv4vjOMV+Nk3mEi1gUV8ujogo+2U6WUAE3NhqFLKn1
 YT6AJhDZvqL1f8gFrbiqR8xwvPrYmwK/tK38X1exSDOqiB7UNzR/apAb1oniul0e
 rS5xWzIs9APvkdWQssCHvrVDdh6VISXQ5bnT8lkfmvYrCTn2gUGAFXDrxZjXIaL9
 scCr8N9STkHmoYpc2ACRKIpfK3E1sDjGA8mAPemkxsLakNwBS4o=
 =s4KC
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/nvme/tags/pull-nvme-20201102' into staging

nvme pull 2 Nov 2020

# gpg: Signature made Mon 02 Nov 2020 15:20:30 GMT
# gpg:                using RSA key DBC11D2D373B4A3755F502EC625156610A4F6CC0
# gpg: Good signature from "Keith Busch <kbusch@kernel.org>" [unknown]
# gpg:                 aka "Keith Busch <keith.busch@gmail.com>" [unknown]
# gpg:                 aka "Keith Busch <keith.busch@intel.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: DBC1 1D2D 373B 4A37 55F5  02EC 6251 5661 0A4F 6CC0

* remotes/nvme/tags/pull-nvme-20201102: (30 commits)
  hw/block/nvme: fix queue identifer validation
  hw/block/nvme: fix create IO SQ/CQ status codes
  hw/block/nvme: fix prp mapping status codes
  hw/block/nvme: report actual LBA data shift in LBAF
  hw/block/nvme: add trace event for requests with non-zero status code
  hw/block/nvme: add nsid to get/setfeat trace events
  hw/block/nvme: reject io commands if only admin command set selected
  hw/block/nvme: support for admin-only command set
  hw/block/nvme: validate command set selected
  hw/block/nvme: support per-namespace smart log
  hw/block/nvme: fix log page offset check
  hw/block/nvme: remove pointless rw indirection
  hw/block/nvme: update nsid when registered
  hw/block/nvme: change controller pci id
  pci: allocate pci id for nvme
  hw/block/nvme: support multiple namespaces
  hw/block/nvme: refactor identify active namespace id list
  hw/block/nvme: add support for sgl bit bucket descriptor
  hw/block/nvme: add support for scatter gather lists
  hw/block/nvme: harden cmb access
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-11-02 17:17:29 +00:00
commit 8680d6e364
12 changed files with 1025 additions and 303 deletions

View File

@ -1879,6 +1879,7 @@ L: qemu-block@nongnu.org
S: Supported
F: hw/block/nvme*
F: tests/qtest/nvme-test.c
F: docs/specs/nvme.txt
T: git git://git.infradead.org/qemu-nvme.git nvme-next
megasas

23
docs/specs/nvme.txt Normal file
View File

@ -0,0 +1,23 @@
NVM Express Controller
======================
The nvme device (-device nvme) emulates an NVM Express Controller.
Reference Specifications
------------------------
The device currently implements most mandatory features of NVMe v1.3d, see
https://nvmexpress.org/resources/specifications/
for the specification.
Known issues
------------
* The accounting numbers in the SMART/Health are reset across power cycles
* Interrupt Coalescing is not supported and is disabled by default in volation
of the specification.

View File

@ -63,6 +63,7 @@ PCI devices (other than virtio):
1b36:000b PCIe Expander Bridge (-device pxb-pcie)
1b36:000d PCI xhci usb host adapter
1b36:000f mdpy (mdev sample device), linux/samples/vfio-mdev/mdpy.c
1b36:0010 PCIe NVMe device (-device nvme)
All these devices are documented in docs/specs.

View File

@ -13,7 +13,7 @@ softmmu_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c'))
softmmu_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c'))
softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c'))
softmmu_ss.add(when: 'CONFIG_SH4', if_true: files('tc58128.c'))
softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c'))
softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c', 'nvme-ns.c'))
specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))

168
hw/block/nvme-ns.c Normal file
View File

@ -0,0 +1,168 @@
/*
* QEMU NVM Express Virtual Namespace
*
* Copyright (c) 2019 CNEX Labs
* Copyright (c) 2020 Samsung Electronics
*
* Authors:
* Klaus Jensen <k.jensen@samsung.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See the
* COPYING file in the top-level directory.
*
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
#include "hw/block/block.h"
#include "hw/pci/pci.h"
#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
#include "qapi/error.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-core.h"
#include "nvme.h"
#include "nvme-ns.h"
static void nvme_ns_init(NvmeNamespace *ns)
{
NvmeIdNs *id_ns = &ns->id_ns;
int lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
if (blk_get_flags(ns->blkconf.blk) & BDRV_O_UNMAP) {
ns->id_ns.dlfeat = 0x9;
}
id_ns->lbaf[lba_index].ds = 31 - clz32(ns->blkconf.logical_block_size);
id_ns->nsze = cpu_to_le64(nvme_ns_nlbas(ns));
/* no thin provisioning */
id_ns->ncap = id_ns->nsze;
id_ns->nuse = id_ns->ncap;
}
static int nvme_ns_init_blk(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
{
if (!blkconf_blocksizes(&ns->blkconf, errp)) {
return -1;
}
if (!blkconf_apply_backend_options(&ns->blkconf,
blk_is_read_only(ns->blkconf.blk),
false, errp)) {
return -1;
}
ns->size = blk_getlength(ns->blkconf.blk);
if (ns->size < 0) {
error_setg_errno(errp, -ns->size, "could not get blockdev size");
return -1;
}
if (blk_enable_write_cache(ns->blkconf.blk)) {
n->features.vwc = 0x1;
}
return 0;
}
static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp)
{
if (!ns->blkconf.blk) {
error_setg(errp, "block backend not configured");
return -1;
}
return 0;
}
int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
{
if (nvme_ns_check_constraints(ns, errp)) {
return -1;
}
if (nvme_ns_init_blk(n, ns, errp)) {
return -1;
}
nvme_ns_init(ns);
if (nvme_register_namespace(n, ns, errp)) {
return -1;
}
return 0;
}
void nvme_ns_drain(NvmeNamespace *ns)
{
blk_drain(ns->blkconf.blk);
}
void nvme_ns_flush(NvmeNamespace *ns)
{
blk_flush(ns->blkconf.blk);
}
static void nvme_ns_realize(DeviceState *dev, Error **errp)
{
NvmeNamespace *ns = NVME_NS(dev);
BusState *s = qdev_get_parent_bus(dev);
NvmeCtrl *n = NVME(s->parent);
Error *local_err = NULL;
if (nvme_ns_setup(n, ns, &local_err)) {
error_propagate_prepend(errp, local_err,
"could not setup namespace: ");
return;
}
}
static Property nvme_ns_props[] = {
DEFINE_BLOCK_PROPERTIES(NvmeNamespace, blkconf),
DEFINE_PROP_UINT32("nsid", NvmeNamespace, params.nsid, 0),
DEFINE_PROP_END_OF_LIST(),
};
static void nvme_ns_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->bus_type = TYPE_NVME_BUS;
dc->realize = nvme_ns_realize;
device_class_set_props(dc, nvme_ns_props);
dc->desc = "Virtual NVMe namespace";
}
static void nvme_ns_instance_init(Object *obj)
{
NvmeNamespace *ns = NVME_NS(obj);
char *bootindex = g_strdup_printf("/namespace@%d,0", ns->params.nsid);
device_add_bootindex_property(obj, &ns->bootindex, "bootindex",
bootindex, DEVICE(obj));
g_free(bootindex);
}
static const TypeInfo nvme_ns_info = {
.name = TYPE_NVME_NS,
.parent = TYPE_DEVICE,
.class_init = nvme_ns_class_init,
.instance_size = sizeof(NvmeNamespace),
.instance_init = nvme_ns_instance_init,
};
static void nvme_ns_register_types(void)
{
type_register_static(&nvme_ns_info);
}
type_init(nvme_ns_register_types)

74
hw/block/nvme-ns.h Normal file
View File

@ -0,0 +1,74 @@
/*
* QEMU NVM Express Virtual Namespace
*
* Copyright (c) 2019 CNEX Labs
* Copyright (c) 2020 Samsung Electronics
*
* Authors:
* Klaus Jensen <k.jensen@samsung.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See the
* COPYING file in the top-level directory.
*
*/
#ifndef NVME_NS_H
#define NVME_NS_H
#define TYPE_NVME_NS "nvme-ns"
#define NVME_NS(obj) \
OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS)
typedef struct NvmeNamespaceParams {
uint32_t nsid;
} NvmeNamespaceParams;
typedef struct NvmeNamespace {
DeviceState parent_obj;
BlockConf blkconf;
int32_t bootindex;
int64_t size;
NvmeIdNs id_ns;
NvmeNamespaceParams params;
} NvmeNamespace;
static inline uint32_t nvme_nsid(NvmeNamespace *ns)
{
if (ns) {
return ns->params.nsid;
}
return -1;
}
static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns)
{
NvmeIdNs *id_ns = &ns->id_ns;
return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)];
}
static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns)
{
return nvme_ns_lbaf(ns)->ds;
}
/* calculate the number of LBAs that the namespace can accomodate */
static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns)
{
return ns->size >> nvme_ns_lbads(ns);
}
/* convert an LBA to the equivalent in bytes */
static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba)
{
return lba << nvme_ns_lbads(ns);
}
typedef struct NvmeCtrl NvmeCtrl;
int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
void nvme_ns_drain(NvmeNamespace *ns);
void nvme_ns_flush(NvmeNamespace *ns);
#endif /* NVME_NS_H */

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,9 @@
#define HW_NVME_H
#include "block/nvme.h"
#include "nvme-ns.h"
#define NVME_MAX_NAMESPACES 256
typedef struct NvmeParams {
char *serial;
@ -12,6 +15,7 @@ typedef struct NvmeParams {
uint8_t aerl;
uint32_t aer_max_queued;
uint8_t mdts;
bool use_intel_id;
} NvmeParams;
typedef struct NvmeAsyncEvent {
@ -32,6 +36,34 @@ typedef struct NvmeRequest {
QTAILQ_ENTRY(NvmeRequest)entry;
} NvmeRequest;
static inline const char *nvme_adm_opc_str(uint8_t opc)
{
switch (opc) {
case NVME_ADM_CMD_DELETE_SQ: return "NVME_ADM_CMD_DELETE_SQ";
case NVME_ADM_CMD_CREATE_SQ: return "NVME_ADM_CMD_CREATE_SQ";
case NVME_ADM_CMD_GET_LOG_PAGE: return "NVME_ADM_CMD_GET_LOG_PAGE";
case NVME_ADM_CMD_DELETE_CQ: return "NVME_ADM_CMD_DELETE_CQ";
case NVME_ADM_CMD_CREATE_CQ: return "NVME_ADM_CMD_CREATE_CQ";
case NVME_ADM_CMD_IDENTIFY: return "NVME_ADM_CMD_IDENTIFY";
case NVME_ADM_CMD_ABORT: return "NVME_ADM_CMD_ABORT";
case NVME_ADM_CMD_SET_FEATURES: return "NVME_ADM_CMD_SET_FEATURES";
case NVME_ADM_CMD_GET_FEATURES: return "NVME_ADM_CMD_GET_FEATURES";
case NVME_ADM_CMD_ASYNC_EV_REQ: return "NVME_ADM_CMD_ASYNC_EV_REQ";
default: return "NVME_ADM_CMD_UNKNOWN";
}
}
static inline const char *nvme_io_opc_str(uint8_t opc)
{
switch (opc) {
case NVME_CMD_FLUSH: return "NVME_NVM_CMD_FLUSH";
case NVME_CMD_WRITE: return "NVME_NVM_CMD_WRITE";
case NVME_CMD_READ: return "NVME_NVM_CMD_READ";
case NVME_CMD_WRITE_ZEROES: return "NVME_NVM_CMD_WRITE_ZEROES";
default: return "NVME_NVM_CMD_UNKNOWN";
}
}
typedef struct NvmeSQueue {
struct NvmeCtrl *ctrl;
uint16_t sqid;
@ -62,20 +94,12 @@ typedef struct NvmeCQueue {
QTAILQ_HEAD(, NvmeRequest) req_list;
} NvmeCQueue;
typedef struct NvmeNamespace {
NvmeIdNs id_ns;
} NvmeNamespace;
#define TYPE_NVME_BUS "nvme-bus"
#define NVME_BUS(obj) OBJECT_CHECK(NvmeBus, (obj), TYPE_NVME_BUS)
static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns)
{
NvmeIdNs *id_ns = &ns->id_ns;
return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)];
}
static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns)
{
return nvme_ns_lbaf(ns)->ds;
}
typedef struct NvmeBus {
BusState parent_bus;
} NvmeBus;
#define TYPE_NVME "nvme"
#define NVME(obj) \
@ -87,6 +111,7 @@ typedef struct NvmeFeatureVal {
uint16_t temp_thresh_low;
};
uint32_t async_config;
uint32_t vwc;
} NvmeFeatureVal;
typedef struct NvmeCtrl {
@ -94,8 +119,9 @@ typedef struct NvmeCtrl {
MemoryRegion iomem;
MemoryRegion ctrl_mem;
NvmeBar bar;
BlockConf conf;
NvmeParams params;
NvmeBus bus;
BlockConf conf;
bool qs_created;
uint32_t page_size;
@ -106,7 +132,6 @@ typedef struct NvmeCtrl {
uint32_t reg_size;
uint32_t num_namespaces;
uint32_t max_q_ents;
uint64_t ns_size;
uint8_t outstanding_aers;
uint8_t *cmbuf;
uint32_t irq_status;
@ -122,7 +147,8 @@ typedef struct NvmeCtrl {
QTAILQ_HEAD(, NvmeAsyncEvent) aer_queue;
int aer_queued;
NvmeNamespace *namespaces;
NvmeNamespace namespace;
NvmeNamespace *namespaces[NVME_MAX_NAMESPACES];
NvmeSQueue **sq;
NvmeCQueue **cq;
NvmeSQueue admin_sq;
@ -131,10 +157,29 @@ typedef struct NvmeCtrl {
NvmeFeatureVal features;
} NvmeCtrl;
/* calculate the number of LBAs that the namespace can accomodate */
static inline uint64_t nvme_ns_nlbas(NvmeCtrl *n, NvmeNamespace *ns)
static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
{
return n->ns_size >> nvme_ns_lbads(ns);
if (!nsid || nsid > n->num_namespaces) {
return NULL;
}
return n->namespaces[nsid - 1];
}
static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
{
NvmeSQueue *sq = req->sq;
NvmeCtrl *n = sq->ctrl;
return n->cq[sq->cqid];
}
static inline NvmeCtrl *nvme_ctrl(NvmeRequest *req)
{
NvmeSQueue *sq = req->sq;
return sq->ctrl;
}
int nvme_register_namespace(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
#endif /* HW_NVME_H */

View File

@ -29,6 +29,7 @@ hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int t
# nvme.c
# nvme traces for successful events
pci_nvme_register_namespace(uint32_t nsid) "nsid %"PRIu32""
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"
@ -36,11 +37,12 @@ pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2
pci_nvme_map_addr(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64""
pci_nvme_map_addr_cmb(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64""
pci_nvme_map_prp(uint64_t trans_len, uint32_t len, uint64_t prp1, uint64_t prp2, int num_prps) "trans_len %"PRIu64" len %"PRIu32" prp1 0x%"PRIx64" prp2 0x%"PRIx64" num_prps %d"
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_map_sgl(uint16_t cid, uint8_t typ, uint64_t len) "cid %"PRIu16" type 0x%"PRIx8" len %"PRIu64""
pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'"
pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'"
pci_nvme_rw(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64""
pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'"
pci_nvme_write_zeroes(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" 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""
@ -50,8 +52,8 @@ 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""
pci_nvme_getfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32""
pci_nvme_setfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" 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"
@ -70,7 +72,7 @@ pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "c
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_doorbell_sq(uint16_t sqid, uint16_t new_tail) "sqid %"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""
@ -86,12 +88,17 @@ pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
# nvme traces for error conditions
pci_nvme_err_mdts(uint16_t cid, size_t len) "cid %"PRIu16" len %zu"
pci_nvme_err_req_status(uint16_t cid, uint32_t nsid, uint16_t status, uint8_t opc) "cid %"PRIu16" nsid %"PRIu32" status 0x%"PRIx16" opc 0x%"PRIx8""
pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64""
pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64""
pci_nvme_err_cfs(void) "controller fatal status"
pci_nvme_err_aio(uint16_t cid, const char *errname, uint16_t status) "cid %"PRIu16" err '%s' status 0x%"PRIx16""
pci_nvme_err_invalid_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8""
pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8""
pci_nvme_err_invalid_sgl_excess_length(uint16_t cid) "cid %"PRIu16""
pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size"
pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64""
pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is not page aligned: 0x%"PRIx64""
pci_nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
pci_nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred"
pci_nvme_err_invalid_prp(void) "invalid PRP"
pci_nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u"
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""
@ -124,6 +131,7 @@ pci_nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_
pci_nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u"
pci_nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u"
pci_nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u"
pci_nvme_err_startfail_css(uint8_t css) "nvme_start_ctrl failed because invalid command set selected:%u"
pci_nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero"
pci_nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero"
pci_nvme_err_startfail(void) "setting controller enable bit failed"

View File

@ -34,6 +34,7 @@ GlobalProperty hw_compat_5_1[] = {
{ "vhost-user-scsi", "num_queues", "1"},
{ "virtio-blk-device", "num-queues", "1"},
{ "virtio-scsi-device", "num_queues", "1"},
{ "nvme", "use-intel-id", "on"},
};
const size_t hw_compat_5_1_len = G_N_ELEMENTS(hw_compat_5_1);

View File

@ -82,6 +82,11 @@ enum NvmeCapMask {
#define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMR_MASK)\
<< CAP_PMR_SHIFT)
enum NvmeCapCss {
NVME_CAP_CSS_NVM = 1 << 0,
NVME_CAP_CSS_ADMIN_ONLY = 1 << 7,
};
enum NvmeCcShift {
CC_EN_SHIFT = 0,
CC_CSS_SHIFT = 4,
@ -110,6 +115,11 @@ enum NvmeCcMask {
#define NVME_CC_IOSQES(cc) ((cc >> CC_IOSQES_SHIFT) & CC_IOSQES_MASK)
#define NVME_CC_IOCQES(cc) ((cc >> CC_IOCQES_SHIFT) & CC_IOCQES_MASK)
enum NvmeCcCss {
NVME_CC_CSS_NVM = 0x0,
NVME_CC_CSS_ADMIN_ONLY = 0x7,
};
enum NvmeCstsShift {
CSTS_RDY_SHIFT = 0,
CSTS_CFS_SHIFT = 1,
@ -412,9 +422,9 @@ typedef union NvmeCmdDptr {
} NvmeCmdDptr;
enum NvmePsdt {
PSDT_PRP = 0x0,
PSDT_SGL_MPTR_CONTIGUOUS = 0x1,
PSDT_SGL_MPTR_SGL = 0x2,
NVME_PSDT_PRP = 0x0,
NVME_PSDT_SGL_MPTR_CONTIGUOUS = 0x1,
NVME_PSDT_SGL_MPTR_SGL = 0x2,
};
typedef struct QEMU_PACKED NvmeCmd {
@ -645,6 +655,7 @@ enum NvmeStatusCodes {
NVME_MD_SGL_LEN_INVALID = 0x0010,
NVME_SGL_DESCR_TYPE_INVALID = 0x0011,
NVME_INVALID_USE_OF_CMB = 0x0012,
NVME_INVALID_PRP_OFFSET = 0x0013,
NVME_LBA_RANGE = 0x0080,
NVME_CAP_EXCEEDED = 0x0081,
NVME_NS_NOT_READY = 0x0082,
@ -849,6 +860,7 @@ enum NvmeIdCtrlFrmw {
};
enum NvmeIdCtrlLpa {
NVME_LPA_NS_SMART = 1 << 0,
NVME_LPA_EXTENDED = 1 << 2,
};

View File

@ -106,6 +106,7 @@ extern bool pci_available;
#define PCI_DEVICE_ID_REDHAT_XHCI 0x000d
#define PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE 0x000e
#define PCI_DEVICE_ID_REDHAT_MDPY 0x000f
#define PCI_DEVICE_ID_REDHAT_NVME 0x0010
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100
#define FMT_PCIBUS PRIx64
@ -783,8 +784,7 @@ static inline AddressSpace *pci_get_address_space(PCIDevice *dev)
static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr,
void *buf, dma_addr_t len, DMADirection dir)
{
dma_memory_rw(pci_get_address_space(dev), addr, buf, len, dir);
return 0;
return dma_memory_rw(pci_get_address_space(dev), addr, buf, len, dir);
}
static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr,