From e989738f3ab3283039385e5771e459b3f2ccfbf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 30 Jun 2020 13:04:27 +0200 Subject: hw/block/nvme: Use QEMU_PACKED on hardware/packet structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These structures either describe hardware registers, or commands ('packets') to send to the hardware. To forbid the compiler to optimize and change fields alignment, mark the structures as packed. Reviewed-by: Dmitry Fomichev Reviewed-by: Klaus Jensen Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200630110429.19972-3-philmd@redhat.com> Signed-off-by: Klaus Jensen --- include/block/nvme.h | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 1720ee1..71c5681 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -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; @@ -377,7 +377,7 @@ enum NvmePmrmscMask { #define NVME_PMRMSC_SET_CBA(pmrmsc, val) \ (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT) -typedef struct NvmeCmd { +typedef struct QEMU_PACKED NvmeCmd { uint8_t opcode; uint8_t fuse; uint16_t cid; @@ -422,7 +422,7 @@ enum NvmeIoCommands { NVME_CMD_DSM = 0x09, }; -typedef struct NvmeDeleteQ { +typedef struct QEMU_PACKED NvmeDeleteQ { uint8_t opcode; uint8_t flags; uint16_t cid; @@ -432,7 +432,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 +449,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 +474,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,7 +486,7 @@ 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; @@ -528,7 +528,7 @@ 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; @@ -547,7 +547,7 @@ enum { NVME_DSMGMT_AD = 1 << 2, }; -typedef struct NvmeDsmRange { +typedef struct QEMU_PACKED NvmeDsmRange { uint32_t cattr; uint32_t nlb; uint64_t slba; @@ -569,14 +569,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; @@ -634,7 +634,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 +647,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,7 +659,7 @@ typedef struct NvmeErrorLog { uint8_t resv[35]; } NvmeErrorLog; -typedef struct NvmeSmartLog { +typedef struct QEMU_PACKED NvmeSmartLog { uint8_t critical_warning; uint8_t temperature[2]; uint8_t available_spare; @@ -693,7 +693,7 @@ enum LogIdentifier { NVME_LOG_FW_SLOT_INFO = 0x03, }; -typedef struct NvmePSD { +typedef struct QEMU_PACKED NvmePSD { uint16_t mp; uint16_t reserved; uint32_t enlat; @@ -713,7 +713,7 @@ enum { NVME_ID_CNS_NS_ACTIVE_LIST = 0x2, }; -typedef struct NvmeIdCtrl { +typedef struct QEMU_PACKED NvmeIdCtrl { uint16_t vid; uint16_t ssvid; uint8_t sn[20]; @@ -807,7 +807,7 @@ enum NvmeFeatureIds { NVME_SOFTWARE_PROGRESS_MARKER = 0x80 }; -typedef struct NvmeRangeType { +typedef struct QEMU_PACKED NvmeRangeType { uint8_t type; uint8_t attributes; uint8_t rsvd2[14]; @@ -817,13 +817,13 @@ 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 { +typedef struct QEMU_PACKED NvmeIdNs { uint64_t nsze; uint64_t ncap; uint64_t nuse; -- cgit v1.1 From af4a367d15d26c5594b4c38060083aa77a649a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 30 Jun 2020 13:04:28 +0200 Subject: hw/block/nvme: Fix pmrmsc register size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Persistent Memory Region Controller Memory Space Control register is 64-bit wide. See 'Figure 68: Register Definition' of the 'NVM Express Base Specification Revision 1.4'. Fixes: 6cf9413229 ("introduce PMR support from NVMe 1.4 spec") Reported-by: Klaus Jensen Reviewed-by: Dmitry Fomichev Reviewed-by: Klaus Jensen Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200630110429.19972-4-philmd@redhat.com> Signed-off-by: Klaus Jensen --- include/block/nvme.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 71c5681..82c3846 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -21,7 +21,7 @@ typedef struct QEMU_PACKED NvmeBar { uint32_t pmrsts; uint32_t pmrebs; uint32_t pmrswtp; - uint32_t pmrmsc; + uint64_t pmrmsc; } NvmeBar; enum NvmeCapShift { -- cgit v1.1 From 74e18435c0eb59004e580f7103b3482fafab2c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 30 Jun 2020 13:04:29 +0200 Subject: hw/block/nvme: Align I/O BAR to 4 KiB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the NVMe emulated device by aligning the I/O BAR to 4 KiB. Reviewed-by: Dmitry Fomichev Reviewed-by: Klaus Jensen Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20200630110429.19972-5-philmd@redhat.com> Signed-off-by: Klaus Jensen --- include/block/nvme.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 82c3846..4e1cea5 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -22,6 +22,7 @@ typedef struct QEMU_PACKED NvmeBar { uint32_t pmrebs; uint32_t pmrswtp; uint64_t pmrmsc; + uint8_t reserved[484]; } NvmeBar; enum NvmeCapShift { @@ -879,6 +880,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); -- cgit v1.1 From c26f21737045a6c6ce7fbdea998868d9bcd9b489 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 6 Jul 2020 08:12:46 +0200 Subject: hw/block/nvme: bump spec data structures to v1.3 Add missing fields in the Identify Controller and Identify Namespace data structures to bring them in line with NVMe v1.3. This also adds data structures and defines for SGL support which requires a couple of trivial changes to the nvme block driver as well. Signed-off-by: Klaus Jensen Acked-by: Fam Zheng Reviewed-by: Maxim Levitsky Reviewed-by: Dmitry Fomichev Message-Id: <20200706061303.246057-2-its@irrelevant.dk> --- include/block/nvme.h | 158 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 141 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 4e1cea5..58f8e48 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -378,15 +378,53 @@ enum NvmePmrmscMask { #define NVME_PMRMSC_SET_CBA(pmrmsc, val) \ (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT) +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; @@ -395,6 +433,9 @@ typedef struct QEMU_PACKED 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, @@ -494,8 +535,7 @@ typedef struct QEMU_PACKED NvmeRwCmd { 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; @@ -535,8 +575,7 @@ typedef struct QEMU_PACKED NvmeDsmCmd { 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]; @@ -600,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, @@ -688,7 +733,7 @@ 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, @@ -712,6 +757,7 @@ 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 QEMU_PACKED NvmeIdCtrl { @@ -724,7 +770,15 @@ typedef struct QEMU_PACKED 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; @@ -732,10 +786,28 @@ typedef struct QEMU_PACKED 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; @@ -743,8 +815,14 @@ typedef struct QEMU_PACKED 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; @@ -770,6 +848,16 @@ enum NvmeIdCtrlOncs { #define NVME_CTRL_CQES_MIN(cqes) ((cqes) & 0xf) #define NVME_CTRL_CQES_MAX(cqes) (((cqes) >> 4) & 0xf) +#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) + typedef struct NvmeFeatureVal { uint32_t arbitration; uint32_t power_mgmt; @@ -792,6 +880,15 @@ typedef struct NvmeFeatureVal { #define NVME_INTC_THR(intc) (intc & 0xff) #define NVME_INTC_TIME(intc) ((intc >> 8) & 0xff) +#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) + enum NvmeFeatureIds { NVME_ARBITRATION = 0x1, NVME_POWER_MANAGEMENT = 0x2, @@ -834,18 +931,43 @@ typedef struct QEMU_PACKED 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) @@ -897,5 +1019,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 -- cgit v1.1 From 69ff06c49e9b0768bd68d887c2f29e8ff84dfaf3 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 6 Jul 2020 08:12:50 +0200 Subject: hw/block/nvme: add temperature threshold feature It might seem weird to implement this feature for an emulated device, but it is mandatory to support and the feature is useful for testing asynchronous event request support, which will be added in a later patch. Signed-off-by: Klaus Jensen Acked-by: Keith Busch Reviewed-by: Maxim Levitsky Reviewed-by: Dmitry Fomichev Message-Id: <20200706061303.246057-6-its@irrelevant.dk> --- include/block/nvme.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 58f8e48..273640c 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -861,7 +861,10 @@ enum NvmeIdCtrlOncs { typedef struct NvmeFeatureVal { uint32_t arbitration; uint32_t power_mgmt; - uint32_t temp_thresh; + struct { + uint16_t temp_thresh_hi; + uint16_t temp_thresh_low; + }; uint32_t err_rec; uint32_t volatile_wc; uint32_t num_queues; -- cgit v1.1 From 42a42e4610ab9e4ca0bcc976f4b19f9f612a085e Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 6 Jul 2020 08:12:51 +0200 Subject: hw/block/nvme: mark fw slot 1 as read-only Mark firmware slot 1 as read-only and only support that slot. Signed-off-by: Klaus Jensen Reviewed-by: Dmitry Fomichev Reviewed-by: Maxim Levitsky Message-Id: <20200706061303.246057-7-its@irrelevant.dk> --- include/block/nvme.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 273640c..f3fdb5b 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -843,6 +843,10 @@ enum NvmeIdCtrlOncs { NVME_ONCS_TIMESTAMP = 1 << 6, }; +enum NvmeIdCtrlFrmw { + NVME_FRMW_SLOT1_RO = 1 << 0, +}; + #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) -- cgit v1.1 From 94a7897c41db0596c544af1bd27eedb833eae496 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 6 Jul 2020 08:12:52 +0200 Subject: hw/block/nvme: add support for the get log page command Add support for the Get Log Page command and basic implementations of the mandatory Error Information, SMART / Health Information and Firmware Slot Information log pages. In violation of the specification, the SMART / Health Information log page does not persist information over the lifetime of the controller because the device has no place to store such persistent state. Note that the LPA field in the Identify Controller data structure intentionally has bit 0 cleared because there is no namespace specific information in the SMART / Health information log page. Required for compliance with NVMe revision 1.3d. See NVM Express 1.3d, Section 5.14 ("Get Log Page command"). Signed-off-by: Klaus Jensen Signed-off-by: Klaus Jensen Acked-by: Keith Busch Reviewed-by: Dmitry Fomichev Reviewed-by: Maxim Levitsky Message-Id: <20200706061303.246057-8-its@irrelevant.dk> --- include/block/nvme.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index f3fdb5b..9ec9f7d 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -707,7 +707,7 @@ typedef struct QEMU_PACKED NvmeErrorLog { 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; @@ -847,6 +847,10 @@ 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) -- cgit v1.1 From 5d5a53302b95c50197d007407d24e2da3397926a Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 6 Jul 2020 08:12:53 +0200 Subject: hw/block/nvme: add support for the asynchronous event request command Add support for the Asynchronous Event Request command. Required for compliance with NVMe revision 1.3d. See NVM Express 1.3d, Section 5.2 ("Asynchronous Event Request command"). Mostly imported from Keith's qemu-nvme tree. Modified with a max number of queued events (controllable with the aer_max_queued device parameter). The spec states that the controller *should* retain events, so we do best effort here. Signed-off-by: Klaus Jensen Signed-off-by: Klaus Jensen Acked-by: Keith Busch Reviewed-by: Maxim Levitsky Reviewed-by: Dmitry Fomichev Message-Id: <20200706061303.246057-9-its@irrelevant.dk> --- include/block/nvme.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 9ec9f7d..87fa60b 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -598,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, @@ -900,6 +900,10 @@ typedef struct NvmeFeatureVal { #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, -- cgit v1.1 From 46ac29c38bb45184db71dfbfbf5a31b3c12dbe29 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 6 Jul 2020 08:12:54 +0200 Subject: hw/block/nvme: move NvmeFeatureVal into hw/block/nvme.h The NvmeFeatureVal does not belong with the spec-related data structures in include/block/nvme.h that is shared between the block-level nvme driver and the emulated nvme device. Move it into the nvme device specific header file as it is the only user of the structure. Also, remove the unused members. Signed-off-by: Klaus Jensen Reviewed-by: Dmitry Fomichev Reviewed-by: Maxim Levitsky Message-Id: <20200706061303.246057-10-its@irrelevant.dk> --- include/block/nvme.h | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 87fa60b..58e0a07 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -866,23 +866,6 @@ enum NvmeIdCtrlLpa { #define NVME_CTRL_SGLS_MPTR_SGL (0x1 << 19) #define NVME_CTRL_SGLS_ADDR_OFFSET (0x1 << 20) -typedef struct NvmeFeatureVal { - uint32_t arbitration; - uint32_t power_mgmt; - struct { - uint16_t temp_thresh_hi; - uint16_t temp_thresh_low; - }; - 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_ARB_AB(arb) (arb & 0x7) #define NVME_ARB_LPW(arb) ((arb >> 8) & 0xff) #define NVME_ARB_MPW(arb) ((arb >> 16) & 0xff) -- cgit v1.1 From 1302e48e499c526583b3182ad8c9b7e32010ac53 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 6 Jul 2020 08:12:56 +0200 Subject: hw/block/nvme: add remaining mandatory controller parameters Add support for any remaining mandatory controller operating parameters (features). Signed-off-by: Klaus Jensen Reviewed-by: Dmitry Fomichev Reviewed-by: Maxim Levitsky Message-Id: <20200706061303.246057-12-its@irrelevant.dk> --- include/block/nvme.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 58e0a07..64d2cab 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -663,6 +663,7 @@ enum NvmeStatusCodes { NVME_FW_REQ_RESET = 0x010b, NVME_INVALID_QUEUE_DEL = 0x010c, NVME_FID_NOT_SAVEABLE = 0x010d, + NVME_FEAT_NOT_CHANGEABLE = 0x010e, NVME_FID_NOT_NSID_SPEC = 0x010f, NVME_FW_REQ_SUSYSTEM_RESET = 0x0110, NVME_CONFLICTING_ATTRS = 0x0180, @@ -867,6 +868,7 @@ enum NvmeIdCtrlLpa { #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) @@ -874,6 +876,8 @@ enum NvmeIdCtrlLpa { #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 @@ -900,9 +904,13 @@ 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, }; +#define NVME_GETSETFEAT_FID_MASK 0xff +#define NVME_GETSETFEAT_FID(dw10) (dw10 & NVME_GETSETFEAT_FID_MASK) + typedef struct QEMU_PACKED NvmeRangeType { uint8_t type; uint8_t attributes; -- cgit v1.1 From 7c46310d298d8caa9dd0e4c0846331dd148a575c Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 6 Jul 2020 08:12:57 +0200 Subject: hw/block/nvme: support the get/set features select and save fields Since the device does not have any persistent state storage, no features are "saveable" and setting the Save (SV) field in any Set Features command will result in a Feature Identifier Not Saveable status code. Similarly, if the Select (SEL) field is set to request saved values, the devices will (as it should) return the default values instead. Since this also introduces "Supported Capabilities", the nsid field is now also checked for validity wrt. the feature being get/set'ed. Signed-off-by: Klaus Jensen Reviewed-by: Dmitry Fomichev Reviewed-by: Maxim Levitsky Message-Id: <20200706061303.246057-13-its@irrelevant.dk> --- include/block/nvme.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 64d2cab..370df7f 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -664,7 +664,7 @@ enum NvmeStatusCodes { NVME_INVALID_QUEUE_DEL = 0x010c, NVME_FID_NOT_SAVEABLE = 0x010d, NVME_FEAT_NOT_CHANGEABLE = 0x010e, - NVME_FID_NOT_NSID_SPEC = 0x010f, + NVME_FEAT_NOT_NS_SPEC = 0x010f, NVME_FW_REQ_SUSYSTEM_RESET = 0x0110, NVME_CONFLICTING_ATTRS = 0x0180, NVME_INVALID_PROT_INFO = 0x0181, @@ -908,9 +908,32 @@ enum NvmeFeatureIds { NVME_FID_MAX = 0x100, }; +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; @@ -927,6 +950,8 @@ typedef struct QEMU_PACKED NvmeLBAF { uint8_t rp; } NvmeLBAF; +#define NVME_NSID_BROADCAST 0xffffffff + typedef struct QEMU_PACKED NvmeIdNs { uint64_t nsze; uint64_t ncap; -- cgit v1.1 From 69265150aa53f0e1dbc85809800df40ffc9e7d67 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 30 Mar 2020 23:10:13 +0200 Subject: hw/block/nvme: be consistent about zeros vs zeroes The NVM Express specification generally uses 'zeroes' and not 'zeros', so let us align with it. Cc: Fam Zheng Signed-off-by: Klaus Jensen Reviewed-by: Minwoo Im Reviewed-by: Maxim Levitsky --- include/block/nvme.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 370df7f..65e68a8 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -460,7 +460,7 @@ 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, }; @@ -838,7 +838,7 @@ 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, -- cgit v1.1