mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
hw/nvme: flexible data placement emulation
Add emulation of TP4146 ("Flexible Data Placement").
Reviewed-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Jesper Devantier <j.devantier@samsung.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
This commit is contained in:
committed by
Klaus Jensen
parent
e181d3da39
commit
73064edfb8
+695
-3
File diff suppressed because it is too large
Load Diff
+143
@@ -14,8 +14,10 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
||||
@@ -377,6 +379,130 @@ static void nvme_zoned_ns_shutdown(NvmeNamespace *ns)
|
||||
assert(ns->nr_open_zones == 0);
|
||||
}
|
||||
|
||||
static NvmeRuHandle *nvme_find_ruh_by_attr(NvmeEnduranceGroup *endgrp,
|
||||
uint8_t ruha, uint16_t *ruhid)
|
||||
{
|
||||
for (uint16_t i = 0; i < endgrp->fdp.nruh; i++) {
|
||||
NvmeRuHandle *ruh = &endgrp->fdp.ruhs[i];
|
||||
|
||||
if (ruh->ruha == ruha) {
|
||||
*ruhid = i;
|
||||
return ruh;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool nvme_ns_init_fdp(NvmeNamespace *ns, Error **errp)
|
||||
{
|
||||
NvmeEnduranceGroup *endgrp = ns->endgrp;
|
||||
NvmeRuHandle *ruh;
|
||||
uint8_t lbafi = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
|
||||
unsigned int *ruhid, *ruhids;
|
||||
char *r, *p, *token;
|
||||
uint16_t *ph;
|
||||
|
||||
if (!ns->params.fdp.ruhs) {
|
||||
ns->fdp.nphs = 1;
|
||||
ph = ns->fdp.phs = g_new(uint16_t, 1);
|
||||
|
||||
ruh = nvme_find_ruh_by_attr(endgrp, NVME_RUHA_CTRL, ph);
|
||||
if (!ruh) {
|
||||
ruh = nvme_find_ruh_by_attr(endgrp, NVME_RUHA_UNUSED, ph);
|
||||
if (!ruh) {
|
||||
error_setg(errp, "no unused reclaim unit handles left");
|
||||
return false;
|
||||
}
|
||||
|
||||
ruh->ruha = NVME_RUHA_CTRL;
|
||||
ruh->lbafi = lbafi;
|
||||
ruh->ruamw = endgrp->fdp.runs >> ns->lbaf.ds;
|
||||
|
||||
for (uint16_t rg = 0; rg < endgrp->fdp.nrg; rg++) {
|
||||
ruh->rus[rg].ruamw = ruh->ruamw;
|
||||
}
|
||||
} else if (ruh->lbafi != lbafi) {
|
||||
error_setg(errp, "lba format index of controller assigned "
|
||||
"reclaim unit handle does not match namespace lba "
|
||||
"format index");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ruhid = ruhids = g_new0(unsigned int, endgrp->fdp.nruh);
|
||||
r = p = strdup(ns->params.fdp.ruhs);
|
||||
|
||||
/* parse the placement handle identifiers */
|
||||
while ((token = qemu_strsep(&p, ";")) != NULL) {
|
||||
ns->fdp.nphs += 1;
|
||||
if (ns->fdp.nphs > NVME_FDP_MAXPIDS ||
|
||||
ns->fdp.nphs == endgrp->fdp.nruh) {
|
||||
error_setg(errp, "too many placement handles");
|
||||
free(r);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (qemu_strtoui(token, NULL, 0, ruhid++) < 0) {
|
||||
error_setg(errp, "cannot parse reclaim unit handle identifier");
|
||||
free(r);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
free(r);
|
||||
|
||||
ph = ns->fdp.phs = g_new(uint16_t, ns->fdp.nphs);
|
||||
|
||||
ruhid = ruhids;
|
||||
|
||||
/* verify the identifiers */
|
||||
for (unsigned int i = 0; i < ns->fdp.nphs; i++, ruhid++, ph++) {
|
||||
if (*ruhid >= endgrp->fdp.nruh) {
|
||||
error_setg(errp, "invalid reclaim unit handle identifier");
|
||||
return false;
|
||||
}
|
||||
|
||||
ruh = &endgrp->fdp.ruhs[*ruhid];
|
||||
|
||||
switch (ruh->ruha) {
|
||||
case NVME_RUHA_UNUSED:
|
||||
ruh->ruha = NVME_RUHA_HOST;
|
||||
ruh->lbafi = lbafi;
|
||||
ruh->ruamw = endgrp->fdp.runs >> ns->lbaf.ds;
|
||||
|
||||
for (uint16_t rg = 0; rg < endgrp->fdp.nrg; rg++) {
|
||||
ruh->rus[rg].ruamw = ruh->ruamw;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NVME_RUHA_HOST:
|
||||
if (ruh->lbafi != lbafi) {
|
||||
error_setg(errp, "lba format index of host assigned"
|
||||
"reclaim unit handle does not match namespace "
|
||||
"lba format index");
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NVME_RUHA_CTRL:
|
||||
error_setg(errp, "reclaim unit handle is controller assigned");
|
||||
return false;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
*ph = *ruhid;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp)
|
||||
{
|
||||
unsigned int pi_size;
|
||||
@@ -417,6 +543,11 @@ static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ns->params.zoned && ns->endgrp && ns->endgrp->fdp.enabled) {
|
||||
error_setg(errp, "cannot be a zoned- in an FDP configuration");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ns->params.zoned) {
|
||||
if (ns->params.max_active_zones) {
|
||||
if (ns->params.max_open_zones > ns->params.max_active_zones) {
|
||||
@@ -502,6 +633,12 @@ int nvme_ns_setup(NvmeNamespace *ns, Error **errp)
|
||||
nvme_ns_init_zoned(ns);
|
||||
}
|
||||
|
||||
if (ns->endgrp && ns->endgrp->fdp.enabled) {
|
||||
if (!nvme_ns_init_fdp(ns, errp)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -525,6 +662,10 @@ void nvme_ns_cleanup(NvmeNamespace *ns)
|
||||
g_free(ns->zone_array);
|
||||
g_free(ns->zd_extensions);
|
||||
}
|
||||
|
||||
if (ns->endgrp && ns->endgrp->fdp.enabled) {
|
||||
g_free(ns->fdp.phs);
|
||||
}
|
||||
}
|
||||
|
||||
static void nvme_ns_unrealize(DeviceState *dev)
|
||||
@@ -562,6 +703,7 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
ns->subsys = subsys;
|
||||
ns->endgrp = &subsys->endgrp;
|
||||
}
|
||||
|
||||
if (nvme_ns_setup(ns, errp)) {
|
||||
@@ -648,6 +790,7 @@ static Property nvme_ns_props[] = {
|
||||
DEFINE_PROP_SIZE("zoned.zrwafg", NvmeNamespace, params.zrwafg, -1),
|
||||
DEFINE_PROP_BOOL("eui64-default", NvmeNamespace, params.eui64_default,
|
||||
false),
|
||||
DEFINE_PROP_STRING("fdp.ruhs", NvmeNamespace, params.fdp.ruhs),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
+83
-2
@@ -27,6 +27,8 @@
|
||||
#define NVME_MAX_CONTROLLERS 256
|
||||
#define NVME_MAX_NAMESPACES 256
|
||||
#define NVME_EUI64_DEFAULT ((uint64_t)0x5254000000000000)
|
||||
#define NVME_FDP_MAX_EVENTS 63
|
||||
#define NVME_FDP_MAXPIDS 128
|
||||
|
||||
QEMU_BUILD_BUG_ON(NVME_MAX_NAMESPACES > NVME_NSID_BROADCAST - 1);
|
||||
|
||||
@@ -45,8 +47,47 @@ typedef struct NvmeBus {
|
||||
OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS)
|
||||
#define SUBSYS_SLOT_RSVD (void *)0xFFFF
|
||||
|
||||
typedef struct NvmeReclaimUnit {
|
||||
uint64_t ruamw;
|
||||
} NvmeReclaimUnit;
|
||||
|
||||
typedef struct NvmeRuHandle {
|
||||
uint8_t ruht;
|
||||
uint8_t ruha;
|
||||
uint64_t event_filter;
|
||||
uint8_t lbafi;
|
||||
uint64_t ruamw;
|
||||
|
||||
/* reclaim units indexed by reclaim group */
|
||||
NvmeReclaimUnit *rus;
|
||||
} NvmeRuHandle;
|
||||
|
||||
typedef struct NvmeFdpEventBuffer {
|
||||
NvmeFdpEvent events[NVME_FDP_MAX_EVENTS];
|
||||
unsigned int nelems;
|
||||
unsigned int start;
|
||||
unsigned int next;
|
||||
} NvmeFdpEventBuffer;
|
||||
|
||||
typedef struct NvmeEnduranceGroup {
|
||||
uint8_t event_conf;
|
||||
|
||||
struct {
|
||||
NvmeFdpEventBuffer host_events, ctrl_events;
|
||||
|
||||
uint16_t nruh;
|
||||
uint16_t nrg;
|
||||
uint8_t rgif;
|
||||
uint64_t runs;
|
||||
|
||||
uint64_t hbmw;
|
||||
uint64_t mbmw;
|
||||
uint64_t mbe;
|
||||
|
||||
bool enabled;
|
||||
|
||||
NvmeRuHandle *ruhs;
|
||||
} fdp;
|
||||
} NvmeEnduranceGroup;
|
||||
|
||||
typedef struct NvmeSubsystem {
|
||||
@@ -55,11 +96,19 @@ typedef struct NvmeSubsystem {
|
||||
uint8_t subnqn[256];
|
||||
char *serial;
|
||||
|
||||
NvmeCtrl *ctrls[NVME_MAX_CONTROLLERS];
|
||||
NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1];
|
||||
NvmeCtrl *ctrls[NVME_MAX_CONTROLLERS];
|
||||
NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1];
|
||||
NvmeEnduranceGroup endgrp;
|
||||
|
||||
struct {
|
||||
char *nqn;
|
||||
|
||||
struct {
|
||||
bool enabled;
|
||||
uint64_t runs;
|
||||
uint16_t nruh;
|
||||
uint32_t nrg;
|
||||
} fdp;
|
||||
} params;
|
||||
} NvmeSubsystem;
|
||||
|
||||
@@ -100,6 +149,21 @@ typedef struct NvmeZone {
|
||||
QTAILQ_ENTRY(NvmeZone) entry;
|
||||
} NvmeZone;
|
||||
|
||||
#define FDP_EVT_MAX 0xff
|
||||
#define NVME_FDP_MAX_NS_RUHS 32u
|
||||
#define FDPVSS 0
|
||||
|
||||
static const uint8_t nvme_fdp_evf_shifts[FDP_EVT_MAX] = {
|
||||
/* Host events */
|
||||
[FDP_EVT_RU_NOT_FULLY_WRITTEN] = 0,
|
||||
[FDP_EVT_RU_ATL_EXCEEDED] = 1,
|
||||
[FDP_EVT_CTRL_RESET_RUH] = 2,
|
||||
[FDP_EVT_INVALID_PID] = 3,
|
||||
/* CTRL events */
|
||||
[FDP_EVT_MEDIA_REALLOC] = 32,
|
||||
[FDP_EVT_RUH_IMPLICIT_RU_CHANGE] = 33,
|
||||
};
|
||||
|
||||
typedef struct NvmeNamespaceParams {
|
||||
bool detached;
|
||||
bool shared;
|
||||
@@ -129,6 +193,10 @@ typedef struct NvmeNamespaceParams {
|
||||
uint32_t numzrwa;
|
||||
uint64_t zrwas;
|
||||
uint64_t zrwafg;
|
||||
|
||||
struct {
|
||||
char *ruhs;
|
||||
} fdp;
|
||||
} NvmeNamespaceParams;
|
||||
|
||||
typedef struct NvmeNamespace {
|
||||
@@ -172,10 +240,17 @@ typedef struct NvmeNamespace {
|
||||
|
||||
NvmeNamespaceParams params;
|
||||
NvmeSubsystem *subsys;
|
||||
NvmeEnduranceGroup *endgrp;
|
||||
|
||||
struct {
|
||||
uint32_t err_rec;
|
||||
} features;
|
||||
|
||||
struct {
|
||||
uint16_t nphs;
|
||||
/* reclaim unit handle identifiers indexed by placement handle */
|
||||
uint16_t *phs;
|
||||
} fdp;
|
||||
} NvmeNamespace;
|
||||
|
||||
static inline uint32_t nvme_nsid(NvmeNamespace *ns)
|
||||
@@ -279,6 +354,12 @@ static inline void nvme_aor_dec_active(NvmeNamespace *ns)
|
||||
assert(ns->nr_active_zones >= 0);
|
||||
}
|
||||
|
||||
static inline void nvme_fdp_stat_inc(uint64_t *a, uint64_t b)
|
||||
{
|
||||
uint64_t ret = *a + b;
|
||||
*a = ret < *a ? UINT64_MAX : ret;
|
||||
}
|
||||
|
||||
void nvme_ns_init_format(NvmeNamespace *ns);
|
||||
int nvme_ns_setup(NvmeNamespace *ns, Error **errp);
|
||||
void nvme_ns_drain(NvmeNamespace *ns);
|
||||
|
||||
+92
-2
@@ -7,10 +7,13 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#include "nvme.h"
|
||||
|
||||
#define NVME_DEFAULT_RU_SIZE (96 * MiB)
|
||||
|
||||
static int nvme_subsys_reserve_cntlids(NvmeCtrl *n, int start, int num)
|
||||
{
|
||||
NvmeSubsystem *subsys = n->subsys;
|
||||
@@ -109,13 +112,95 @@ void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeCtrl *n)
|
||||
n->cntlid = -1;
|
||||
}
|
||||
|
||||
static void nvme_subsys_setup(NvmeSubsystem *subsys)
|
||||
static bool nvme_calc_rgif(uint16_t nruh, uint16_t nrg, uint8_t *rgif)
|
||||
{
|
||||
uint16_t val;
|
||||
unsigned int i;
|
||||
|
||||
if (unlikely(nrg == 1)) {
|
||||
/* PIDRG_NORGI scenario, all of pid is used for PHID */
|
||||
*rgif = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
val = nrg;
|
||||
i = 0;
|
||||
while (val) {
|
||||
val >>= 1;
|
||||
i++;
|
||||
}
|
||||
*rgif = i;
|
||||
|
||||
/* ensure remaining bits suffice to represent number of phids in a RG */
|
||||
if (unlikely((UINT16_MAX >> i) < nruh)) {
|
||||
*rgif = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nvme_subsys_setup_fdp(NvmeSubsystem *subsys, Error **errp)
|
||||
{
|
||||
NvmeEnduranceGroup *endgrp = &subsys->endgrp;
|
||||
|
||||
if (!subsys->params.fdp.runs) {
|
||||
error_setg(errp, "fdp.runs must be non-zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
endgrp->fdp.runs = subsys->params.fdp.runs;
|
||||
|
||||
if (!subsys->params.fdp.nrg) {
|
||||
error_setg(errp, "fdp.nrg must be non-zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
endgrp->fdp.nrg = subsys->params.fdp.nrg;
|
||||
|
||||
if (!subsys->params.fdp.nruh) {
|
||||
error_setg(errp, "fdp.nruh must be non-zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
endgrp->fdp.nruh = subsys->params.fdp.nruh;
|
||||
|
||||
if (!nvme_calc_rgif(endgrp->fdp.nruh, endgrp->fdp.nrg, &endgrp->fdp.rgif)) {
|
||||
error_setg(errp,
|
||||
"cannot derive a valid rgif (nruh %"PRIu16" nrg %"PRIu32")",
|
||||
endgrp->fdp.nruh, endgrp->fdp.nrg);
|
||||
return false;
|
||||
}
|
||||
|
||||
endgrp->fdp.ruhs = g_new(NvmeRuHandle, endgrp->fdp.nruh);
|
||||
|
||||
for (uint16_t ruhid = 0; ruhid < endgrp->fdp.nruh; ruhid++) {
|
||||
endgrp->fdp.ruhs[ruhid] = (NvmeRuHandle) {
|
||||
.ruht = NVME_RUHT_INITIALLY_ISOLATED,
|
||||
.ruha = NVME_RUHA_UNUSED,
|
||||
};
|
||||
|
||||
endgrp->fdp.ruhs[ruhid].rus = g_new(NvmeReclaimUnit, endgrp->fdp.nrg);
|
||||
}
|
||||
|
||||
endgrp->fdp.enabled = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nvme_subsys_setup(NvmeSubsystem *subsys, Error **errp)
|
||||
{
|
||||
const char *nqn = subsys->params.nqn ?
|
||||
subsys->params.nqn : subsys->parent_obj.id;
|
||||
|
||||
snprintf((char *)subsys->subnqn, sizeof(subsys->subnqn),
|
||||
"nqn.2019-08.org.qemu:%s", nqn);
|
||||
|
||||
if (subsys->params.fdp.enabled && !nvme_subsys_setup_fdp(subsys, errp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void nvme_subsys_realize(DeviceState *dev, Error **errp)
|
||||
@@ -124,11 +209,16 @@ static void nvme_subsys_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
qbus_init(&subsys->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, dev->id);
|
||||
|
||||
nvme_subsys_setup(subsys);
|
||||
nvme_subsys_setup(subsys, errp);
|
||||
}
|
||||
|
||||
static Property nvme_subsystem_props[] = {
|
||||
DEFINE_PROP_STRING("nqn", NvmeSubsystem, params.nqn),
|
||||
DEFINE_PROP_BOOL("fdp", NvmeSubsystem, params.fdp.enabled, false),
|
||||
DEFINE_PROP_SIZE("fdp.runs", NvmeSubsystem, params.fdp.runs,
|
||||
NVME_DEFAULT_RU_SIZE),
|
||||
DEFINE_PROP_UINT32("fdp.nrg", NvmeSubsystem, params.fdp.nrg, 1),
|
||||
DEFINE_PROP_UINT16("fdp.nruh", NvmeSubsystem, params.fdp.nruh, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ pci_nvme_clear_ns_reset(uint32_t state, uint64_t slba) "zone state=%"PRIu32", sl
|
||||
pci_nvme_zoned_zrwa_implicit_flush(uint64_t zslba, uint32_t nlb) "zslba 0x%"PRIx64" nlb %"PRIu32""
|
||||
pci_nvme_pci_reset(void) "PCI Function Level Reset"
|
||||
pci_nvme_virt_mngmt(uint16_t cid, uint16_t act, uint16_t cntlid, const char* rt, uint16_t nr) "cid %"PRIu16", act=0x%"PRIx16", ctrlid=%"PRIu16" %s nr=%"PRIu16""
|
||||
pci_nvme_fdp_ruh_change(uint16_t rgid, uint16_t ruhid) "change RU on RUH rgid=%"PRIu16", ruhid=%"PRIu16""
|
||||
|
||||
# error conditions
|
||||
pci_nvme_err_mdts(size_t len) "len %zu"
|
||||
|
||||
+165
-8
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user