qemu-nvme

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE28EdLTc7SjdV9QLsYlFWYQpPbMAFAl9Pro4ACgkQYlFWYQpP
 bMC1CRAAkawTI4mMcOfI3smFoMeiY8kZJWXJUBXfHbMJ4asaoIjTkH/lXRXBw7KQ
 sH5tB9CuOums3VjagkZ0Sw6R/kP1LbyJTAwq/pwOXwYRDc/E3zQpMblkIHH1boIM
 Bxl814hw3hBqV+D0wgeKpl83lbiOpd10Cbpdb/xNKat6qVquLGurSGKgA7jNuF4s
 oPTPtfZpyH9LUr4DV+sL+fGX6vaCdSFZPZUhJqwFfx79+r3+YiHGLAE6fgsdGDJt
 2RSSKMqBe2gg0BY5ToW9L55BsLnwMMrAZnGzEkeZvRKqm0JZBXQsERa61p4VEAJf
 uYkSEqOwsKjXQNTdDEekyH67AkgXaoqG0hiiOcgoLsla7C0zROtoKcfVM/+WC0LT
 T0/bfgubmoDV8kLzPuOV8xOGxjfbu4Qlxy1JsIC6BU4zBQvpDwOeTx3MUWaCUfvk
 YmDMEhZWGcZ3RBLrgQmzm4ZKMtGdYXnGQz5dwVkRRfghQs2fl5ZmUjGR7MqKe18n
 4K0nzhPiXbOTlqvLVvzVlrBzdc8ECAs1kVoJF7C3LwRmXbT2N/fUhZP/nYpeM2Hj
 DQNmA8KpXMKae2+2iDnQNWbvdpz3SiHD6dK7A1bEsdoG0L60xfyeAF+JuPiESUnd
 OAhf+muxKiInv2k5GNh7mDZPWM6nDepf/PZP6ohc7dKxVam7N2M=
 =Y23H
 -----END PGP SIGNATURE-----

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

qemu-nvme

# gpg: Signature made Wed 02 Sep 2020 15:39:10 BST
# 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-20200902: (39 commits)
  hw/block/nvme: remove explicit qsg/iov parameters
  hw/block/nvme: use preallocated qsg/iov in nvme_dma_prp
  hw/block/nvme: consolidate qsg/iov clearing
  hw/block/nvme: add ns/cmd references in NvmeRequest
  hw/block/nvme: be consistent about zeros vs zeroes
  hw/block/nvme: add check for mdts
  hw/block/nvme: refactor request bounds checking
  hw/block/nvme: verify validity of prp lists in the cmb
  hw/block/nvme: add request mapping helper
  hw/block/nvme: add tracing to nvme_map_prp
  hw/block/nvme: refactor dma read/write
  hw/block/nvme: destroy request iov before reuse
  hw/block/nvme: remove redundant has_sg member
  hw/block/nvme: replace dma_acct with blk_acct equivalent
  hw/block/nvme: add mapping helpers
  hw/block/nvme: memset preallocated requests structures
  hw/block/nvme: bump supported version to v1.3
  hw/block/nvme: provide the mandatory subnqn field
  hw/block/nvme: enforce valid queue creation sequence
  hw/block/nvme: reject invalid nsid values in active namespace id list
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-09-02 21:20:20 +01:00
commit e4d8b7c1a9
6 changed files with 1257 additions and 249 deletions

View File

@ -1856,10 +1856,12 @@ F: include/hw/virtio/virtio-mem.h
nvme
M: Keith Busch <kbusch@kernel.org>
M: Klaus Jensen <its@irrelevant.dk>
L: qemu-block@nongnu.org
S: Supported
F: hw/block/nvme*
F: tests/qtest/nvme-test.c
T: git git://git.infradead.org/qemu-nvme.git nvme-next
megasas
M: Hannes Reinecke <hare@suse.com>

View File

@ -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");
@ -537,7 +537,7 @@ static void nvme_identify(BlockDriverState *bs, int namespace, Error **errp)
s->page_size / sizeof(uint64_t) * s->page_size);
oncs = le16_to_cpu(idctrl->oncs);
s->supports_write_zeroes = !!(oncs & NVME_ONCS_WRITE_ZEROS);
s->supports_write_zeroes = !!(oncs & NVME_ONCS_WRITE_ZEROES);
s->supports_discard = !!(oncs & NVME_ONCS_DSM);
memset(resp, 0, 4096);
@ -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);
@ -1201,7 +1201,7 @@ static coroutine_fn int nvme_co_pwrite_zeroes(BlockDriverState *bs,
}
NvmeCmd cmd = {
.opcode = NVME_CMD_WRITE_ZEROS,
.opcode = NVME_CMD_WRITE_ZEROES,
.nsid = cpu_to_le32(s->nsid),
.cdw10 = cpu_to_le32((offset >> s->blkshift) & 0xFFFFFFFF),
.cdw11 = cpu_to_le32(((offset >> s->blkshift) >> 32) & 0xFFFFFFFF),

File diff suppressed because it is too large Load Diff

View File

@ -9,19 +9,23 @@ typedef struct NvmeParams {
uint32_t max_ioqpairs;
uint16_t msix_qsize;
uint32_t cmb_size_mb;
uint8_t aerl;
uint32_t aer_max_queued;
uint8_t mdts;
} NvmeParams;
typedef struct NvmeAsyncEvent {
QSIMPLEQ_ENTRY(NvmeAsyncEvent) entry;
QTAILQ_ENTRY(NvmeAsyncEvent) entry;
NvmeAerResult result;
} NvmeAsyncEvent;
typedef struct NvmeRequest {
struct NvmeSQueue *sq;
struct NvmeNamespace *ns;
BlockAIOCB *aiocb;
uint16_t status;
bool has_sg;
NvmeCqe cqe;
NvmeCmd cmd;
BlockAcctCookie acct;
QEMUSGList qsg;
QEMUIOVector iov;
@ -77,6 +81,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;
@ -85,6 +97,7 @@ typedef struct NvmeCtrl {
BlockConf conf;
NvmeParams params;
bool qs_created;
uint32_t page_size;
uint16_t page_bits;
uint16_t max_prp_ents;
@ -94,19 +107,28 @@ 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 */
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
uint64_t starttime_ms;
uint16_t temperature;
HostMemoryBackend *pmrdev;
uint8_t aer_mask;
NvmeRequest **aer_reqs;
QTAILQ_HEAD(, NvmeAsyncEvent) aer_queue;
int aer_queued;
NvmeNamespace *namespaces;
NvmeSQueue **sq;
NvmeCQueue **cq;
NvmeSQueue admin_sq;
NvmeCQueue admin_cq;
NvmeIdCtrl id_ctrl;
NvmeFeatureVal features;
} NvmeCtrl;
/* calculate the number of LBAs that the namespace can accomodate */

View File

@ -33,19 +33,44 @@ 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_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_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_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_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_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""
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""
@ -60,6 +85,7 @@ pci_nvme_mmio_shutdown_set(void) "shutdown bit set"
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_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_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64""
@ -85,6 +111,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"

View File

@ -1,7 +1,7 @@
#ifndef BLOCK_NVME_H
#define BLOCK_NVME_H
typedef struct NvmeBar {
typedef struct QEMU_PACKED NvmeBar {
uint64_t cap;
uint32_t vs;
uint32_t intms;
@ -21,7 +21,8 @@ typedef struct NvmeBar {
uint32_t pmrsts;
uint32_t pmrebs;
uint32_t pmrswtp;
uint32_t pmrmsc;
uint64_t pmrmsc;
uint8_t reserved[484];
} NvmeBar;
enum NvmeCapShift {
@ -377,15 +378,53 @@ enum NvmePmrmscMask {
#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \
(pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT)
typedef struct NvmeCmd {
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 QEMU_PACKED 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 QEMU_PACKED 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 +433,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,
@ -418,11 +460,11 @@ enum NvmeIoCommands {
NVME_CMD_READ = 0x02,
NVME_CMD_WRITE_UNCOR = 0x04,
NVME_CMD_COMPARE = 0x05,
NVME_CMD_WRITE_ZEROS = 0x08,
NVME_CMD_WRITE_ZEROES = 0x08,
NVME_CMD_DSM = 0x09,
};
typedef struct NvmeDeleteQ {
typedef struct QEMU_PACKED NvmeDeleteQ {
uint8_t opcode;
uint8_t flags;
uint16_t cid;
@ -432,7 +474,7 @@ typedef struct NvmeDeleteQ {
uint32_t rsvd11[5];
} NvmeDeleteQ;
typedef struct NvmeCreateCq {
typedef struct QEMU_PACKED NvmeCreateCq {
uint8_t opcode;
uint8_t flags;
uint16_t cid;
@ -449,7 +491,7 @@ typedef struct NvmeCreateCq {
#define NVME_CQ_FLAGS_PC(cq_flags) (cq_flags & 0x1)
#define NVME_CQ_FLAGS_IEN(cq_flags) ((cq_flags >> 1) & 0x1)
typedef struct NvmeCreateSq {
typedef struct QEMU_PACKED NvmeCreateSq {
uint8_t opcode;
uint8_t flags;
uint16_t cid;
@ -474,7 +516,7 @@ enum NvmeQueueFlags {
NVME_Q_PRIO_LOW = 3,
};
typedef struct NvmeIdentify {
typedef struct QEMU_PACKED NvmeIdentify {
uint8_t opcode;
uint8_t flags;
uint16_t cid;
@ -486,15 +528,14 @@ typedef struct NvmeIdentify {
uint32_t rsvd11[5];
} NvmeIdentify;
typedef struct NvmeRwCmd {
typedef struct QEMU_PACKED NvmeRwCmd {
uint8_t opcode;
uint8_t flags;
uint16_t cid;
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;
@ -528,14 +569,13 @@ enum {
NVME_RW_PRINFO_PRCHK_REF = 1 << 10,
};
typedef struct NvmeDsmCmd {
typedef struct QEMU_PACKED NvmeDsmCmd {
uint8_t opcode;
uint8_t flags;
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];
@ -547,7 +587,7 @@ enum {
NVME_DSMGMT_AD = 1 << 2,
};
typedef struct NvmeDsmRange {
typedef struct QEMU_PACKED NvmeDsmRange {
uint32_t cattr;
uint32_t nlb;
uint64_t slba;
@ -558,8 +598,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,
@ -569,14 +609,14 @@ enum NvmeAsyncEventRequest {
NVME_AER_INFO_SMART_SPARE_THRESH = 2,
};
typedef struct NvmeAerResult {
typedef struct QEMU_PACKED NvmeAerResult {
uint8_t event_type;
uint8_t event_info;
uint8_t log_page;
uint8_t resv;
} NvmeAerResult;
typedef struct NvmeCqe {
typedef struct QEMU_PACKED NvmeCqe {
uint32_t result;
uint32_t rsvd;
uint16_t sq_head;
@ -599,6 +639,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,
@ -617,7 +663,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_CHANGEABLE = 0x010e,
NVME_FEAT_NOT_NS_SPEC = 0x010f,
NVME_FW_REQ_SUSYSTEM_RESET = 0x0110,
NVME_CONFLICTING_ATTRS = 0x0180,
NVME_INVALID_PROT_INFO = 0x0181,
@ -634,7 +681,7 @@ enum NvmeStatusCodes {
NVME_NO_COMPLETE = 0xffff,
};
typedef struct NvmeFwSlotInfoLog {
typedef struct QEMU_PACKED NvmeFwSlotInfoLog {
uint8_t afi;
uint8_t reserved1[7];
uint8_t frs1[8];
@ -647,7 +694,7 @@ typedef struct NvmeFwSlotInfoLog {
uint8_t reserved2[448];
} NvmeFwSlotInfoLog;
typedef struct NvmeErrorLog {
typedef struct QEMU_PACKED NvmeErrorLog {
uint64_t error_count;
uint16_t sqid;
uint16_t cid;
@ -659,9 +706,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;
@ -687,13 +734,13 @@ 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,
};
typedef struct NvmePSD {
typedef struct QEMU_PACKED NvmePSD {
uint16_t mp;
uint16_t reserved;
uint32_t enlat;
@ -711,9 +758,10 @@ 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 {
typedef struct QEMU_PACKED NvmeIdCtrl {
uint16_t vid;
uint16_t ssvid;
uint8_t sn[20];
@ -723,7 +771,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 +787,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 +816,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;
@ -758,32 +838,37 @@ enum NvmeIdCtrlOncs {
NVME_ONCS_COMPARE = 1 << 0,
NVME_ONCS_WRITE_UNCORR = 1 << 1,
NVME_ONCS_DSM = 1 << 2,
NVME_ONCS_WRITE_ZEROS = 1 << 3,
NVME_ONCS_WRITE_ZEROES = 1 << 3,
NVME_ONCS_FEATURES = 1 << 4,
NVME_ONCS_RESRVATIONS = 1 << 5,
NVME_ONCS_TIMESTAMP = 1 << 6,
};
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)
#define NVME_CTRL_CQES_MAX(cqes) (((cqes) >> 4) & 0xf)
typedef struct NvmeFeatureVal {
uint32_t arbitration;
uint32_t power_mgmt;
uint32_t temp_thresh;
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_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)
#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)
@ -791,6 +876,21 @@ typedef struct NvmeFeatureVal {
#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
#define NVME_TEMP_TMPSEL(temp) ((temp >> 16) & 0xf)
#define NVME_TEMP_TMPSEL_COMPOSITE 0x0
#define NVME_TEMP_TMPTH(temp) (temp & 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,
@ -804,10 +904,37 @@ 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_FID_MAX = 0x100,
};
typedef struct NvmeRangeType {
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 QEMU_PACKED NvmeRangeType {
uint8_t type;
uint8_t attributes;
uint8_t rsvd2[14];
@ -817,13 +944,15 @@ typedef struct NvmeRangeType {
uint8_t rsvd48[16];
} NvmeRangeType;
typedef struct NvmeLBAF {
typedef struct QEMU_PACKED NvmeLBAF {
uint16_t ms;
uint8_t ds;
uint8_t rp;
} NvmeLBAF;
typedef struct NvmeIdNs {
#define NVME_NSID_BROADCAST 0xffffffff
typedef struct QEMU_PACKED NvmeIdNs {
uint64_t nsze;
uint64_t ncap;
uint64_t nuse;
@ -833,18 +962,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 QEMU_PACKED 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)
@ -879,6 +1033,7 @@ enum NvmeIdNsDps {
static inline void _nvme_check_size(void)
{
QEMU_BUILD_BUG_ON(sizeof(NvmeBar) != 4096);
QEMU_BUILD_BUG_ON(sizeof(NvmeAerResult) != 4);
QEMU_BUILD_BUG_ON(sizeof(NvmeCqe) != 16);
QEMU_BUILD_BUG_ON(sizeof(NvmeDsmRange) != 16);
@ -895,5 +1050,7 @@ static inline void _nvme_check_size(void)
QEMU_BUILD_BUG_ON(sizeof(NvmeSmartLog) != 512);
QEMU_BUILD_BUG_ON(sizeof(NvmeIdCtrl) != 4096);
QEMU_BUILD_BUG_ON(sizeof(NvmeIdNs) != 4096);
QEMU_BUILD_BUG_ON(sizeof(NvmeSglDescriptor) != 16);
QEMU_BUILD_BUG_ON(sizeof(NvmeIdNsDescr) != 4);
}
#endif