From 771dbc3ac484af35cddf7e4971e66a1fd1a07156 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Mon, 20 Feb 2023 12:59:24 +0100 Subject: hw/nvme: add basic endurance group support Add the mandatory Endurance Group identify data structures and log pages. For now, all namespaces in a subsystem belongs to a single Endurance Group. Reviewed-by: Keith Busch Signed-off-by: Klaus Jensen --- include/block/nvme.h | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 8027b71..4abc1bb 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -58,6 +58,24 @@ enum NvmeBarRegs { NVME_REG_PMRMSCU = offsetof(NvmeBar, pmrmscu), }; +typedef struct QEMU_PACKED NvmeEndGrpLog { + uint8_t critical_warning; + uint8_t rsvd[2]; + uint8_t avail_spare; + uint8_t avail_spare_thres; + uint8_t percet_used; + uint8_t rsvd1[26]; + uint64_t end_estimate[2]; + uint64_t data_units_read[2]; + uint64_t data_units_written[2]; + uint64_t media_units_written[2]; + uint64_t host_read_commands[2]; + uint64_t host_write_commands[2]; + uint64_t media_integrity_errors[2]; + uint64_t no_err_info_log_entries[2]; + uint8_t rsvd2[352]; +} NvmeEndGrpLog; + enum NvmeCapShift { CAP_MQES_SHIFT = 0, CAP_CQR_SHIFT = 16, @@ -1005,11 +1023,12 @@ enum { }; enum NvmeLogIdentifier { - NVME_LOG_ERROR_INFO = 0x01, - NVME_LOG_SMART_INFO = 0x02, - NVME_LOG_FW_SLOT_INFO = 0x03, - NVME_LOG_CHANGED_NSLIST = 0x04, - NVME_LOG_CMD_EFFECTS = 0x05, + NVME_LOG_ERROR_INFO = 0x01, + NVME_LOG_SMART_INFO = 0x02, + NVME_LOG_FW_SLOT_INFO = 0x03, + NVME_LOG_CHANGED_NSLIST = 0x04, + NVME_LOG_CMD_EFFECTS = 0x05, + NVME_LOG_ENDGRP = 0x09, }; typedef struct QEMU_PACKED NvmePSD { @@ -1091,7 +1110,10 @@ typedef struct QEMU_PACKED NvmeIdCtrl { uint16_t mntmt; uint16_t mxtmt; uint32_t sanicap; - uint8_t rsvd332[180]; + uint8_t rsvd332[6]; + uint16_t nsetidmax; + uint16_t endgidmax; + uint8_t rsvd342[170]; uint8_t sqes; uint8_t cqes; uint16_t maxcmd; @@ -1134,6 +1156,7 @@ enum NvmeIdCtrlOaes { }; enum NvmeIdCtrlCtratt { + NVME_CTRATT_ENDGRPS = 1 << 4, NVME_CTRATT_ELBAS = 1 << 15, }; @@ -1227,6 +1250,7 @@ enum NvmeNsAttachmentOperation { #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) +#define NVME_AEC_ENDGRP_NOTICE(aec) ((aec >> 14) & 0x1) #define NVME_ERR_REC_TLER(err_rec) (err_rec & 0xffff) #define NVME_ERR_REC_DULBE(err_rec) (err_rec & 0x10000) @@ -1338,7 +1362,10 @@ typedef struct QEMU_PACKED NvmeIdNs { uint16_t mssrl; uint32_t mcl; uint8_t msrc; - uint8_t rsvd81[23]; + uint8_t rsvd81[18]; + uint8_t nsattr; + uint16_t nvmsetid; + uint16_t endgid; uint8_t nguid[16]; uint64_t eui64; NvmeLBAF lbaf[NVME_MAX_NLBAF]; @@ -1655,5 +1682,6 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmePriCtrlCap) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeSecCtrlEntry) != 32); QEMU_BUILD_BUG_ON(sizeof(NvmeSecCtrlList) != 4096); + QEMU_BUILD_BUG_ON(sizeof(NvmeEndGrpLog) != 512); } #endif -- cgit v1.1 From e181d3da3967caf026d1ce91f9bfd847b66fdce9 Mon Sep 17 00:00:00 2001 From: Gollu Appalanaidu Date: Mon, 20 Feb 2023 12:59:25 +0100 Subject: hw/nvme: basic directives support Add support for the Directive Send and Recv commands and the Identify directive. Reviewed-by: Keith Busch Signed-off-by: Gollu Appalanaidu Signed-off-by: Klaus Jensen --- include/block/nvme.h | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index 4abc1bb..d463d0e 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -613,7 +613,9 @@ enum NvmeAdminCommands { NVME_ADM_CMD_ACTIVATE_FW = 0x10, NVME_ADM_CMD_DOWNLOAD_FW = 0x11, NVME_ADM_CMD_NS_ATTACHMENT = 0x15, + NVME_ADM_CMD_DIRECTIVE_SEND = 0x19, NVME_ADM_CMD_VIRT_MNGMT = 0x1c, + NVME_ADM_CMD_DIRECTIVE_RECV = 0x1a, NVME_ADM_CMD_DBBUF_CONFIG = 0x7c, NVME_ADM_CMD_FORMAT_NVM = 0x80, NVME_ADM_CMD_SECURITY_SEND = 0x81, @@ -1161,11 +1163,12 @@ enum NvmeIdCtrlCtratt { }; enum NvmeIdCtrlOacs { - NVME_OACS_SECURITY = 1 << 0, - NVME_OACS_FORMAT = 1 << 1, - NVME_OACS_FW = 1 << 2, - NVME_OACS_NS_MGMT = 1 << 3, - NVME_OACS_DBBUF = 1 << 8, + NVME_OACS_SECURITY = 1 << 0, + NVME_OACS_FORMAT = 1 << 1, + NVME_OACS_FW = 1 << 2, + NVME_OACS_NS_MGMT = 1 << 3, + NVME_OACS_DIRECTIVES = 1 << 5, + NVME_OACS_DBBUF = 1 << 8, }; enum NvmeIdCtrlOncs { @@ -1644,6 +1647,27 @@ typedef enum NvmeVirtualResourceType { NVME_VIRT_RES_INTERRUPT = 0x01, } NvmeVirtualResourceType; +typedef struct NvmeDirectiveIdentify { + uint8_t supported; + uint8_t unused1[31]; + uint8_t enabled; + uint8_t unused33[31]; + uint8_t rsvd64[4032]; +} NvmeDirectiveIdentify; + +enum NvmeDirective { + NVME_DIRECTIVE_SUPPORTED = 0x0, + NVME_DIRECTIVE_ENABLED = 0x1, +}; + +enum NvmeDirectiveTypes { + NVME_DIRECTIVE_IDENTIFY = 0x0, +}; + +enum NvmeDirectiveOperations { + NVME_DIRECTIVE_RETURN_PARAMS = 0x1, +}; + static inline void _nvme_check_size(void) { QEMU_BUILD_BUG_ON(sizeof(NvmeBar) != 4096); @@ -1683,5 +1707,6 @@ static inline void _nvme_check_size(void) QEMU_BUILD_BUG_ON(sizeof(NvmeSecCtrlEntry) != 32); QEMU_BUILD_BUG_ON(sizeof(NvmeSecCtrlList) != 4096); QEMU_BUILD_BUG_ON(sizeof(NvmeEndGrpLog) != 512); + QEMU_BUILD_BUG_ON(sizeof(NvmeDirectiveIdentify) != 4096); } #endif -- cgit v1.1 From 73064edfb864743cde2c08f319609344af02aeb3 Mon Sep 17 00:00:00 2001 From: Jesper Devantier Date: Mon, 20 Feb 2023 12:59:26 +0100 Subject: hw/nvme: flexible data placement emulation Add emulation of TP4146 ("Flexible Data Placement"). Reviewed-by: Keith Busch Signed-off-by: Jesper Devantier Signed-off-by: Klaus Jensen --- include/block/nvme.h | 173 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 165 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/block/nvme.h b/include/block/nvme.h index d463d0e..bb231d0 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -1,6 +1,8 @@ #ifndef BLOCK_NVME_H #define BLOCK_NVME_H +#include "hw/registerfields.h" + typedef struct QEMU_PACKED NvmeBar { uint64_t cap; uint32_t vs; @@ -631,7 +633,9 @@ enum NvmeIoCommands { NVME_CMD_WRITE_ZEROES = 0x08, NVME_CMD_DSM = 0x09, NVME_CMD_VERIFY = 0x0c, + NVME_CMD_IO_MGMT_RECV = 0x12, NVME_CMD_COPY = 0x19, + NVME_CMD_IO_MGMT_SEND = 0x1d, NVME_CMD_ZONE_MGMT_SEND = 0x79, NVME_CMD_ZONE_MGMT_RECV = 0x7a, NVME_CMD_ZONE_APPEND = 0x7d, @@ -724,7 +728,9 @@ typedef struct QEMU_PACKED NvmeRwCmd { uint64_t slba; uint16_t nlb; uint16_t control; - uint32_t dsmgmt; + uint8_t dsmgmt; + uint8_t rsvd; + uint16_t dspec; uint32_t reftag; uint16_t apptag; uint16_t appmask; @@ -895,6 +901,8 @@ enum NvmeStatusCodes { NVME_INVALID_PRP_OFFSET = 0x0013, NVME_CMD_SET_CMB_REJECTED = 0x002b, NVME_INVALID_CMD_SET = 0x002c, + NVME_FDP_DISABLED = 0x0029, + NVME_INVALID_PHID_LIST = 0x002a, NVME_LBA_RANGE = 0x0080, NVME_CAP_EXCEEDED = 0x0081, NVME_NS_NOT_READY = 0x0082, @@ -1031,6 +1039,10 @@ enum NvmeLogIdentifier { NVME_LOG_CHANGED_NSLIST = 0x04, NVME_LOG_CMD_EFFECTS = 0x05, NVME_LOG_ENDGRP = 0x09, + NVME_LOG_FDP_CONFS = 0x20, + NVME_LOG_FDP_RUH_USAGE = 0x21, + NVME_LOG_FDP_STATS = 0x22, + NVME_LOG_FDP_EVENTS = 0x23, }; typedef struct QEMU_PACKED NvmePSD { @@ -1160,6 +1172,7 @@ enum NvmeIdCtrlOaes { enum NvmeIdCtrlCtratt { NVME_CTRATT_ENDGRPS = 1 << 4, NVME_CTRATT_ELBAS = 1 << 15, + NVME_CTRATT_FDPS = 1 << 19, }; enum NvmeIdCtrlOacs { @@ -1273,6 +1286,8 @@ enum NvmeFeatureIds { NVME_TIMESTAMP = 0xe, NVME_HOST_BEHAVIOR_SUPPORT = 0x16, NVME_COMMAND_SET_PROFILE = 0x19, + NVME_FDP_MODE = 0x1d, + NVME_FDP_EVENTS = 0x1e, NVME_SOFTWARE_PROGRESS_MARKER = 0x80, NVME_FID_MAX = 0x100, }; @@ -1652,22 +1667,164 @@ typedef struct NvmeDirectiveIdentify { uint8_t unused1[31]; uint8_t enabled; uint8_t unused33[31]; - uint8_t rsvd64[4032]; + uint8_t persistent; + uint8_t unused65[31]; + uint8_t rsvd64[4000]; } NvmeDirectiveIdentify; -enum NvmeDirective { - NVME_DIRECTIVE_SUPPORTED = 0x0, - NVME_DIRECTIVE_ENABLED = 0x1, -}; - enum NvmeDirectiveTypes { - NVME_DIRECTIVE_IDENTIFY = 0x0, + NVME_DIRECTIVE_IDENTIFY = 0x0, + NVME_DIRECTIVE_DATA_PLACEMENT = 0x2, }; enum NvmeDirectiveOperations { NVME_DIRECTIVE_RETURN_PARAMS = 0x1, }; +typedef struct QEMU_PACKED NvmeFdpConfsHdr { + uint16_t num_confs; + uint8_t version; + uint8_t rsvd3; + uint32_t size; + uint8_t rsvd8[8]; +} NvmeFdpConfsHdr; + +REG8(FDPA, 0x0) + FIELD(FDPA, RGIF, 0, 4) + FIELD(FDPA, VWC, 4, 1) + FIELD(FDPA, VALID, 7, 1); + +typedef struct QEMU_PACKED NvmeFdpDescrHdr { + uint16_t descr_size; + uint8_t fdpa; + uint8_t vss; + uint32_t nrg; + uint16_t nruh; + uint16_t maxpids; + uint32_t nnss; + uint64_t runs; + uint32_t erutl; + uint8_t rsvd28[36]; +} NvmeFdpDescrHdr; + +enum NvmeRuhType { + NVME_RUHT_INITIALLY_ISOLATED = 1, + NVME_RUHT_PERSISTENTLY_ISOLATED = 2, +}; + +typedef struct QEMU_PACKED NvmeRuhDescr { + uint8_t ruht; + uint8_t rsvd1[3]; +} NvmeRuhDescr; + +typedef struct QEMU_PACKED NvmeRuhuLog { + uint16_t nruh; + uint8_t rsvd2[6]; +} NvmeRuhuLog; + +enum NvmeRuhAttributes { + NVME_RUHA_UNUSED = 0, + NVME_RUHA_HOST = 1, + NVME_RUHA_CTRL = 2, +}; + +typedef struct QEMU_PACKED NvmeRuhuDescr { + uint8_t ruha; + uint8_t rsvd1[7]; +} NvmeRuhuDescr; + +typedef struct QEMU_PACKED NvmeFdpStatsLog { + uint64_t hbmw[2]; + uint64_t mbmw[2]; + uint64_t mbe[2]; + uint8_t rsvd48[16]; +} NvmeFdpStatsLog; + +typedef struct QEMU_PACKED NvmeFdpEventsLog { + uint32_t num_events; + uint8_t rsvd4[60]; +} NvmeFdpEventsLog; + +enum NvmeFdpEventType { + FDP_EVT_RU_NOT_FULLY_WRITTEN = 0x0, + FDP_EVT_RU_ATL_EXCEEDED = 0x1, + FDP_EVT_CTRL_RESET_RUH = 0x2, + FDP_EVT_INVALID_PID = 0x3, + FDP_EVT_MEDIA_REALLOC = 0x80, + FDP_EVT_RUH_IMPLICIT_RU_CHANGE = 0x81, +}; + +enum NvmeFdpEventFlags { + FDPEF_PIV = 1 << 0, + FDPEF_NSIDV = 1 << 1, + FDPEF_LV = 1 << 2, +}; + +typedef struct QEMU_PACKED NvmeFdpEvent { + uint8_t type; + uint8_t flags; + uint16_t pid; + uint64_t timestamp; + uint32_t nsid; + uint64_t type_specific[2]; + uint16_t rgid; + uint8_t ruhid; + uint8_t rsvd35[5]; + uint64_t vendor[3]; +} NvmeFdpEvent; + +typedef struct QEMU_PACKED NvmePhidList { + uint16_t nnruhd; + uint8_t rsvd2[6]; +} NvmePhidList; + +typedef struct QEMU_PACKED NvmePhidDescr { + uint8_t ruht; + uint8_t rsvd1; + uint16_t ruhid; +} NvmePhidDescr; + +REG32(FEAT_FDP, 0x0) + FIELD(FEAT_FDP, FDPE, 0, 1) + FIELD(FEAT_FDP, CONF_NDX, 8, 8); + +typedef struct QEMU_PACKED NvmeFdpEventDescr { + uint8_t evt; + uint8_t evta; +} NvmeFdpEventDescr; + +REG32(NVME_IOMR, 0x0) + FIELD(NVME_IOMR, MO, 0, 8) + FIELD(NVME_IOMR, MOS, 16, 16); + +enum NvmeIomr2Mo { + NVME_IOMR_MO_NOP = 0x0, + NVME_IOMR_MO_RUH_STATUS = 0x1, + NVME_IOMR_MO_VENDOR_SPECIFIC = 0x255, +}; + +typedef struct QEMU_PACKED NvmeRuhStatus { + uint8_t rsvd0[14]; + uint16_t nruhsd; +} NvmeRuhStatus; + +typedef struct QEMU_PACKED NvmeRuhStatusDescr { + uint16_t pid; + uint16_t ruhid; + uint32_t earutr; + uint64_t ruamw; + uint8_t rsvd16[16]; +} NvmeRuhStatusDescr; + +REG32(NVME_IOMS, 0x0) + FIELD(NVME_IOMS, MO, 0, 8) + FIELD(NVME_IOMS, MOS, 16, 16); + +enum NvmeIoms2Mo { + NVME_IOMS_MO_NOP = 0x0, + NVME_IOMS_MO_RUH_UPDATE = 0x1, +}; + static inline void _nvme_check_size(void) { QEMU_BUILD_BUG_ON(sizeof(NvmeBar) != 4096); -- cgit v1.1