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:
commit
8680d6e364
@ -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
23
docs/specs/nvme.txt
Normal 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.
|
@ -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.
|
||||
|
||||
|
@ -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
168
hw/block/nvme-ns.c
Normal 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
74
hw/block/nvme-ns.h
Normal 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 */
|
921
hw/block/nvme.c
921
hw/block/nvme.c
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user