nvme queue
-----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEUigzqnXi3OaiR2bATeGvMW1PDekFAmklZyQACgkQTeGvMW1P DemROQf+IprPh+u3uPuJ51ED3JrvQ02D+djWmun77f0spF/hiCCEWE708voe3pfp 2QT3zCvCruqxBzzpirYZCALTpZ3cQfd5Fq2UuAOWzye4jE4yvgNHpV9vFbC7JY3w jJmRSuS3/m06MipEGmuoQGS0wNFpOaNLz15DMPWco0A+U2BgKmX/AVFpUJtvGYXz /E3VhwHwS9LCfOMEwZc+e9G4mzM0hB/xgg1qNPe1sp4Ao0hlVXvgVg1Bc6ujhFEc yrdCdzmDVwq/jAjYJDW0/5mXOPX+ugcyoMrFPkm0ABnksEnK6pPn6K7oMEXGZ4qr GyeSWtdyBZuK453sK3S1C/aX7izWeA== =GU3Z -----END PGP SIGNATURE----- Merge tag 'pull-nvme-20251125' of https://gitlab.com/birkelund/qemu into staging nvme queue # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEUigzqnXi3OaiR2bATeGvMW1PDekFAmklZyQACgkQTeGvMW1P # DemROQf+IprPh+u3uPuJ51ED3JrvQ02D+djWmun77f0spF/hiCCEWE708voe3pfp # 2QT3zCvCruqxBzzpirYZCALTpZ3cQfd5Fq2UuAOWzye4jE4yvgNHpV9vFbC7JY3w # jJmRSuS3/m06MipEGmuoQGS0wNFpOaNLz15DMPWco0A+U2BgKmX/AVFpUJtvGYXz # /E3VhwHwS9LCfOMEwZc+e9G4mzM0hB/xgg1qNPe1sp4Ao0hlVXvgVg1Bc6ujhFEc # yrdCdzmDVwq/jAjYJDW0/5mXOPX+ugcyoMrFPkm0ABnksEnK6pPn6K7oMEXGZ4qr # GyeSWtdyBZuK453sK3S1C/aX7izWeA== # =GU3Z # -----END PGP SIGNATURE----- # gpg: Signature made Tue 25 Nov 2025 12:21:56 AM PST # gpg: using RSA key 522833AA75E2DCE6A24766C04DE1AF316D4F0DE9 # gpg: Good signature from "Klaus Jensen <its@irrelevant.dk>" [unknown] # gpg: aka "Klaus Jensen <k.jensen@samsung.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: DDCA 4D9C 9EF9 31CC 3468 4272 63D5 6FC5 E55D A838 # Subkey fingerprint: 5228 33AA 75E2 DCE6 A247 66C0 4DE1 AF31 6D4F 0DE9 * tag 'pull-nvme-20251125' of https://gitlab.com/birkelund/qemu: hw/nvme: Validate PMR memory size hw/nvme: fix up extended protection information format hw/nvme: fix namespace atomic parameter setup Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
d25cba09a4
5 changed files with 209 additions and 154 deletions
128
hw/nvme/ctrl.c
128
hw/nvme/ctrl.c
|
|
@ -6524,6 +6524,53 @@ static uint16_t nvme_set_feature_fdp_events(NvmeCtrl *n, NvmeNamespace *ns,
|
|||
return NVME_SUCCESS;
|
||||
}
|
||||
|
||||
void nvme_atomic_configure_max_write_size(bool dn, uint16_t awun,
|
||||
uint16_t awupf, NvmeAtomic *atomic)
|
||||
{
|
||||
atomic->atomic_max_write_size = (dn ? awupf : awun) + 1;
|
||||
|
||||
if (atomic->atomic_max_write_size > 1) {
|
||||
atomic->atomic_writes = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t nvme_set_feature_write_atomicity(NvmeCtrl *n, NvmeRequest *req)
|
||||
{
|
||||
NvmeCmd *cmd = &req->cmd;
|
||||
|
||||
uint32_t dw11 = le32_to_cpu(cmd->cdw11);
|
||||
|
||||
uint16_t awun = le16_to_cpu(n->id_ctrl.awun);
|
||||
uint16_t awupf = le16_to_cpu(n->id_ctrl.awupf);
|
||||
|
||||
n->dn = dw11 & 0x1;
|
||||
|
||||
nvme_atomic_configure_max_write_size(n->dn, awun, awupf, &n->atomic);
|
||||
|
||||
for (int i = 1; i <= NVME_MAX_NAMESPACES; i++) {
|
||||
uint16_t nawun, nawupf, nabsn, nabspf;
|
||||
|
||||
NvmeNamespace *ns = nvme_ns(n, i);
|
||||
if (!ns) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nawun = le16_to_cpu(ns->id_ns.nawun);
|
||||
nawupf = le16_to_cpu(ns->id_ns.nawupf);
|
||||
|
||||
nvme_atomic_configure_max_write_size(n->dn, nawun, nawupf,
|
||||
&ns->atomic);
|
||||
|
||||
nabsn = le16_to_cpu(ns->id_ns.nabsn);
|
||||
nabspf = le16_to_cpu(ns->id_ns.nabspf);
|
||||
|
||||
nvme_ns_atomic_configure_boundary(n->dn, nabsn, nabspf,
|
||||
&ns->atomic);
|
||||
}
|
||||
|
||||
return NVME_SUCCESS;
|
||||
}
|
||||
|
||||
static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
|
||||
{
|
||||
NvmeNamespace *ns = NULL;
|
||||
|
|
@ -6536,8 +6583,6 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
|
|||
uint8_t save = NVME_SETFEAT_SAVE(dw10);
|
||||
uint16_t status;
|
||||
int i;
|
||||
NvmeIdCtrl *id = &n->id_ctrl;
|
||||
NvmeAtomic *atomic = &n->atomic;
|
||||
|
||||
trace_pci_nvme_setfeat(nvme_cid(req), nsid, fid, save, dw11);
|
||||
|
||||
|
|
@ -6691,50 +6736,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req)
|
|||
case NVME_FDP_EVENTS:
|
||||
return nvme_set_feature_fdp_events(n, ns, req);
|
||||
case NVME_WRITE_ATOMICITY:
|
||||
|
||||
n->dn = 0x1 & dw11;
|
||||
|
||||
if (n->dn) {
|
||||
atomic->atomic_max_write_size = le16_to_cpu(id->awupf) + 1;
|
||||
} else {
|
||||
atomic->atomic_max_write_size = le16_to_cpu(id->awun) + 1;
|
||||
}
|
||||
|
||||
if (atomic->atomic_max_write_size == 1) {
|
||||
atomic->atomic_writes = 0;
|
||||
} else {
|
||||
atomic->atomic_writes = 1;
|
||||
}
|
||||
for (i = 1; i <= NVME_MAX_NAMESPACES; i++) {
|
||||
ns = nvme_ns(n, i);
|
||||
if (ns && ns->atomic.atomic_writes) {
|
||||
if (n->dn) {
|
||||
ns->atomic.atomic_max_write_size =
|
||||
le16_to_cpu(ns->id_ns.nawupf) + 1;
|
||||
if (ns->id_ns.nabspf) {
|
||||
ns->atomic.atomic_boundary =
|
||||
le16_to_cpu(ns->id_ns.nabspf) + 1;
|
||||
} else {
|
||||
ns->atomic.atomic_boundary = 0;
|
||||
}
|
||||
} else {
|
||||
ns->atomic.atomic_max_write_size =
|
||||
le16_to_cpu(ns->id_ns.nawun) + 1;
|
||||
if (ns->id_ns.nabsn) {
|
||||
ns->atomic.atomic_boundary =
|
||||
le16_to_cpu(ns->id_ns.nabsn) + 1;
|
||||
} else {
|
||||
ns->atomic.atomic_boundary = 0;
|
||||
}
|
||||
}
|
||||
if (ns->atomic.atomic_max_write_size == 1) {
|
||||
ns->atomic.atomic_writes = 0;
|
||||
} else {
|
||||
ns->atomic.atomic_writes = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
return nvme_set_feature_write_atomicity(n, req);
|
||||
default:
|
||||
return NVME_FEAT_NOT_CHANGEABLE | NVME_DNR;
|
||||
}
|
||||
|
|
@ -7669,6 +7671,10 @@ static int nvme_atomic_boundary_check(NvmeCtrl *n, NvmeCmd *cmd,
|
|||
|
||||
imask = ~(atomic->atomic_boundary - 1);
|
||||
if ((slba & imask) != (elba & imask)) {
|
||||
/*
|
||||
* The write crosses an atomic boundary and the controller provides
|
||||
* no atomicity guarantees unless AWUN/AWUPF are non-zero.
|
||||
*/
|
||||
if (n->atomic.atomic_max_write_size &&
|
||||
((nlb + 1) <= n->atomic.atomic_max_write_size)) {
|
||||
return 1;
|
||||
|
|
@ -8709,7 +8715,6 @@ static void nvme_init_state(NvmeCtrl *n)
|
|||
NvmeSecCtrlEntry *list = n->sec_ctrl_list;
|
||||
NvmeSecCtrlEntry *sctrl;
|
||||
PCIDevice *pci = PCI_DEVICE(n);
|
||||
NvmeAtomic *atomic = &n->atomic;
|
||||
NvmeIdCtrl *id = &n->id_ctrl;
|
||||
uint8_t max_vfs;
|
||||
int i;
|
||||
|
|
@ -8781,19 +8786,9 @@ static void nvme_init_state(NvmeCtrl *n)
|
|||
id->awupf = 0;
|
||||
}
|
||||
|
||||
if (n->dn) {
|
||||
atomic->atomic_max_write_size = id->awupf + 1;
|
||||
} else {
|
||||
atomic->atomic_max_write_size = id->awun + 1;
|
||||
}
|
||||
|
||||
if (atomic->atomic_max_write_size == 1) {
|
||||
atomic->atomic_writes = 0;
|
||||
} else {
|
||||
atomic->atomic_writes = 1;
|
||||
}
|
||||
atomic->atomic_boundary = 0;
|
||||
atomic->atomic_nabo = 0;
|
||||
nvme_atomic_configure_max_write_size(n->dn, n->params.atomic_awun,
|
||||
n->params.atomic_awupf,
|
||||
&n->atomic);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -8819,10 +8814,15 @@ static void nvme_init_cmb(NvmeCtrl *n, PCIDevice *pci_dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void nvme_init_pmr(NvmeCtrl *n, PCIDevice *pci_dev)
|
||||
static bool nvme_init_pmr(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
|
||||
{
|
||||
uint32_t pmrcap = ldl_le_p(&n->bar.pmrcap);
|
||||
|
||||
if (memory_region_size(&n->pmr.dev->mr) < 16) {
|
||||
error_setg(errp, "PMR device must have at least 16 bytes");
|
||||
return false;
|
||||
}
|
||||
|
||||
NVME_PMRCAP_SET_RDS(pmrcap, 1);
|
||||
NVME_PMRCAP_SET_WDS(pmrcap, 1);
|
||||
NVME_PMRCAP_SET_BIR(pmrcap, NVME_PMR_BIR);
|
||||
|
|
@ -8837,6 +8837,8 @@ static void nvme_init_pmr(NvmeCtrl *n, PCIDevice *pci_dev)
|
|||
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmr.dev->mr);
|
||||
|
||||
memory_region_set_enabled(&n->pmr.dev->mr, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t nvme_mbar_size(unsigned total_queues, unsigned total_irqs,
|
||||
|
|
@ -9055,7 +9057,9 @@ static bool nvme_init_pci(NvmeCtrl *n, PCIDevice *pci_dev, Error **errp)
|
|||
}
|
||||
|
||||
if (n->pmr.dev) {
|
||||
nvme_init_pmr(n, pci_dev);
|
||||
if (!nvme_init_pmr(n, pci_dev, errp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
206
hw/nvme/ns.c
206
hw/nvme/ns.c
|
|
@ -32,11 +32,13 @@ void nvme_ns_init_format(NvmeNamespace *ns)
|
|||
NvmeIdNs *id_ns = &ns->id_ns;
|
||||
NvmeIdNsNvm *id_ns_nvm = &ns->id_ns_nvm;
|
||||
BlockDriverInfo bdi;
|
||||
int npdg, ret;
|
||||
int npdg, ret, index;
|
||||
int64_t nlbas;
|
||||
|
||||
index = NVME_ID_NS_FLBAS_INDEX(id_ns->flbas);
|
||||
ns->lbaf = id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)];
|
||||
ns->lbasz = 1 << ns->lbaf.ds;
|
||||
ns->pif = NVME_ID_NS_NVM_ELBAF_PIF(ns->id_ns_nvm.elbaf[index]);
|
||||
|
||||
nlbas = ns->size / (ns->lbasz + ns->lbaf.ms);
|
||||
|
||||
|
|
@ -112,8 +114,6 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
|
|||
id_ns->dps |= NVME_ID_NS_DPS_FIRST_EIGHT;
|
||||
}
|
||||
|
||||
ns->pif = ns->params.pif;
|
||||
|
||||
static const NvmeLBAF defaults[16] = {
|
||||
[0] = { .ds = 9 },
|
||||
[1] = { .ds = 9, .ms = 8 },
|
||||
|
|
@ -129,6 +129,12 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
|
|||
|
||||
memcpy(&id_ns->lbaf, &defaults, sizeof(defaults));
|
||||
|
||||
for (i = 0; i < ns->nlbaf; i++) {
|
||||
if (id_ns->lbaf[i].ms >= 16) {
|
||||
id_ns_nvm->elbaf[i] = (ns->params.pif & 0x3) << 7;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ns->nlbaf; i++) {
|
||||
NvmeLBAF *lbaf = &id_ns->lbaf[i];
|
||||
if (lbaf->ds == ds) {
|
||||
|
|
@ -142,13 +148,14 @@ static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
|
|||
/* add non-standard lba format */
|
||||
id_ns->lbaf[ns->nlbaf].ds = ds;
|
||||
id_ns->lbaf[ns->nlbaf].ms = ms;
|
||||
if (ms >= 16) {
|
||||
id_ns_nvm->elbaf[ns->nlbaf] = (ns->params.pif & 0x3) << 7;
|
||||
}
|
||||
ns->nlbaf++;
|
||||
|
||||
id_ns->flbas |= i;
|
||||
|
||||
|
||||
lbaf_found:
|
||||
id_ns_nvm->elbaf[i] = (ns->pif & 0x3) << 7;
|
||||
id_ns->nlbaf = ns->nlbaf - 1;
|
||||
nvme_ns_init_format(ns);
|
||||
|
||||
|
|
@ -718,85 +725,119 @@ static void nvme_ns_unrealize(DeviceState *dev)
|
|||
nvme_ns_cleanup(ns);
|
||||
}
|
||||
|
||||
void nvme_ns_atomic_configure_boundary(bool dn, uint16_t nabsn,
|
||||
uint16_t nabspf, NvmeAtomic *atomic)
|
||||
{
|
||||
atomic->atomic_boundary = dn ? nabspf : nabsn;
|
||||
|
||||
if (atomic->atomic_boundary > 0) {
|
||||
atomic->atomic_boundary += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool nvme_ns_set_nab(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
|
||||
{
|
||||
NvmeIdNs *id_ns = &ns->id_ns;
|
||||
NvmeIdCtrl *id_ctrl = &n->id_ctrl;
|
||||
|
||||
uint16_t nabsn = ns->params.atomic.nabsn;
|
||||
uint16_t nabspf = ns->params.atomic.nabspf;
|
||||
uint16_t nabo = ns->params.atomic.nabo;
|
||||
|
||||
if (nabsn && nabsn < le16_to_cpu(id_ctrl->awun)) {
|
||||
error_setg(errp, "nabsn must be greater than or equal to awun");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nabspf && nabspf < le16_to_cpu(id_ctrl->awupf)) {
|
||||
error_setg(errp, "nabspf must be greater than or equal to awupf");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (id_ns->nsfeat & NVME_ID_NS_NSFEAT_NSABP) {
|
||||
if (nabsn && nabsn < le16_to_cpu(id_ns->nawun)) {
|
||||
error_setg(errp, "nabsn must be greater than or equal to nawun");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nabspf && nabspf < le16_to_cpu(id_ns->nawupf)) {
|
||||
error_setg(errp, "nabspf must be great than or equal to nawupf");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (nabo && (nabo > nabsn || nabo > nabspf)) {
|
||||
error_setg(errp, "nabo must be less than or equal to nabsn and nabspf");
|
||||
return false;
|
||||
}
|
||||
|
||||
id_ns->nabsn = cpu_to_le16(nabsn);
|
||||
id_ns->nabspf = cpu_to_le16(nabspf);
|
||||
id_ns->nabo = cpu_to_le16(nabo);
|
||||
|
||||
ns->atomic.atomic_nabo = nabo;
|
||||
|
||||
nvme_ns_atomic_configure_boundary(n->dn, nabsn, nabspf, &ns->atomic);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nvme_ns_set_nsabp(NvmeCtrl *n, NvmeNamespace *ns, Error **errp)
|
||||
{
|
||||
NvmeIdNs *id_ns = &ns->id_ns;
|
||||
NvmeIdCtrl *id_ctrl = &n->id_ctrl;
|
||||
|
||||
uint16_t awun = le16_to_cpu(id_ctrl->awun);
|
||||
uint16_t awupf = le16_to_cpu(id_ctrl->awupf);
|
||||
|
||||
uint16_t nawun = ns->params.atomic.nawun;
|
||||
uint16_t nawupf = ns->params.atomic.nawupf;
|
||||
|
||||
if (nawupf > nawun) {
|
||||
if (nawun == 0) {
|
||||
nawun = nawupf;
|
||||
} else {
|
||||
error_setg(errp, "nawupf must be less than or equal to nawun");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* neither nawun or nawupf is set */
|
||||
if (nawun == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nawun < awun) {
|
||||
error_setg(errp, "nawun must be greater than or equal to awun");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nawupf < awupf) {
|
||||
error_setg(errp, "nawupf must be greater than or equal to awupf");
|
||||
return false;
|
||||
}
|
||||
|
||||
id_ns->nsfeat |= NVME_ID_NS_NSFEAT_NSABP;
|
||||
|
||||
id_ns->nawun = cpu_to_le16(nawun);
|
||||
id_ns->nawupf = cpu_to_le16(nawupf);
|
||||
|
||||
nvme_atomic_configure_max_write_size(n->dn, nawun, nawupf, &ns->atomic);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
NvmeSubsystem *subsys = n->subsys;
|
||||
NvmeIdCtrl *id = &n->id_ctrl;
|
||||
NvmeIdNs *id_ns = &ns->id_ns;
|
||||
uint32_t nsid = ns->params.nsid;
|
||||
int i;
|
||||
|
||||
assert(subsys);
|
||||
|
||||
/* Set atomic write parameters */
|
||||
if (ns->params.atomic_nsfeat) {
|
||||
id_ns->nsfeat |= NVME_ID_NS_NSFEAT_NSABPNS;
|
||||
id_ns->nawun = cpu_to_le16(ns->params.atomic_nawun);
|
||||
if (!id->awupf || (id_ns->nawun && (id_ns->nawun < id->awun))) {
|
||||
error_report("Invalid NAWUN: %x AWUN=%x", id_ns->nawun, id->awun);
|
||||
}
|
||||
id_ns->nawupf = cpu_to_le16(ns->params.atomic_nawupf);
|
||||
if (!id->awupf || (id_ns->nawupf && (id_ns->nawupf < id->awupf))) {
|
||||
error_report("Invalid NAWUPF: %x AWUPF=%x",
|
||||
id_ns->nawupf, id->awupf);
|
||||
}
|
||||
if (id_ns->nawupf > id_ns->nawun) {
|
||||
error_report("Invalid: NAWUN=%x NAWUPF=%x",
|
||||
id_ns->nawun, id_ns->nawupf);
|
||||
}
|
||||
id_ns->nabsn = cpu_to_le16(ns->params.atomic_nabsn);
|
||||
id_ns->nabspf = cpu_to_le16(ns->params.atomic_nabspf);
|
||||
id_ns->nabo = cpu_to_le16(ns->params.atomic_nabo);
|
||||
if (!id->awun || (id_ns->nabsn && ((id_ns->nabsn < id_ns->nawun) ||
|
||||
(id_ns->nabsn < id->awun)))) {
|
||||
error_report("Invalid NABSN: %x NAWUN=%x AWUN=%x",
|
||||
id_ns->nabsn, id_ns->nawun, id->awun);
|
||||
}
|
||||
if (!id->awupf || (id_ns->nabspf && ((id_ns->nabspf < id_ns->nawupf) ||
|
||||
(id_ns->nawupf < id->awupf)))) {
|
||||
error_report("Invalid NABSPF: %x NAWUPF=%x AWUPF=%x",
|
||||
id_ns->nabspf, id_ns->nawupf, id->awupf);
|
||||
}
|
||||
if (id_ns->nabo && ((id_ns->nabo > id_ns->nabsn) ||
|
||||
(id_ns->nabo > id_ns->nabspf))) {
|
||||
error_report("Invalid NABO: %x NABSN=%x NABSPF=%x",
|
||||
id_ns->nabo, id_ns->nabsn, id_ns->nabspf);
|
||||
}
|
||||
if (id_ns->nawupf > id_ns->nawun) {
|
||||
error_report("Invalid: NAWUN=%x NAWUPF=%x", id_ns->nawun,
|
||||
id_ns->nawupf);
|
||||
}
|
||||
}
|
||||
|
||||
if (id_ns->nawun || id_ns->nawupf) {
|
||||
NvmeAtomic *atomic = &ns->atomic;
|
||||
|
||||
if (n->dn) {
|
||||
atomic->atomic_max_write_size = cpu_to_le16(id_ns->nawupf) + 1;
|
||||
if (id_ns->nabspf) {
|
||||
atomic->atomic_boundary = cpu_to_le16(id_ns->nabspf) + 1;
|
||||
} else {
|
||||
atomic->atomic_boundary = 0;
|
||||
}
|
||||
} else {
|
||||
atomic->atomic_max_write_size = cpu_to_le16(id_ns->nawun) + 1;
|
||||
if (id_ns->nabsn) {
|
||||
atomic->atomic_boundary = cpu_to_le16(id_ns->nabsn) + 1;
|
||||
} else {
|
||||
atomic->atomic_boundary = 0;
|
||||
}
|
||||
}
|
||||
if (atomic->atomic_max_write_size == 1) {
|
||||
atomic->atomic_writes = 0;
|
||||
} else {
|
||||
atomic->atomic_writes = 1;
|
||||
}
|
||||
atomic->atomic_nabo = cpu_to_le16(id_ns->nabo);
|
||||
}
|
||||
|
||||
/* reparent to subsystem bus */
|
||||
if (!qdev_set_parent_bus(dev, &subsys->bus.parent_bus, errp)) {
|
||||
return;
|
||||
|
|
@ -804,6 +845,14 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
|
|||
ns->subsys = subsys;
|
||||
ns->endgrp = &subsys->endgrp;
|
||||
|
||||
if (!nvme_ns_set_nsabp(n, ns, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nvme_ns_set_nab(n, ns, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nvme_ns_setup(ns, errp)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -872,12 +921,11 @@ static const Property nvme_ns_props[] = {
|
|||
DEFINE_PROP_BOOL("eui64-default", NvmeNamespace, params.eui64_default,
|
||||
false),
|
||||
DEFINE_PROP_STRING("fdp.ruhs", NvmeNamespace, params.fdp.ruhs),
|
||||
DEFINE_PROP_UINT16("atomic.nawun", NvmeNamespace, params.atomic_nawun, 0),
|
||||
DEFINE_PROP_UINT16("atomic.nawupf", NvmeNamespace, params.atomic_nawupf, 0),
|
||||
DEFINE_PROP_UINT16("atomic.nabspf", NvmeNamespace, params.atomic_nabspf, 0),
|
||||
DEFINE_PROP_UINT16("atomic.nabsn", NvmeNamespace, params.atomic_nabsn, 0),
|
||||
DEFINE_PROP_UINT16("atomic.nabo", NvmeNamespace, params.atomic_nabo, 0),
|
||||
DEFINE_PROP_BOOL("atomic.nsfeat", NvmeNamespace, params.atomic_nsfeat, 0),
|
||||
DEFINE_PROP_UINT16("atomic.nawun", NvmeNamespace, params.atomic.nawun, 0),
|
||||
DEFINE_PROP_UINT16("atomic.nawupf", NvmeNamespace, params.atomic.nawupf, 0),
|
||||
DEFINE_PROP_UINT16("atomic.nabsn", NvmeNamespace, params.atomic.nabsn, 0),
|
||||
DEFINE_PROP_UINT16("atomic.nabspf", NvmeNamespace, params.atomic.nabspf, 0),
|
||||
DEFINE_PROP_UINT16("atomic.nabo", NvmeNamespace, params.atomic.nabo, 0),
|
||||
};
|
||||
|
||||
static void nvme_ns_class_init(ObjectClass *oc, const void *data)
|
||||
|
|
|
|||
|
|
@ -218,12 +218,14 @@ typedef struct NvmeNamespaceParams {
|
|||
struct {
|
||||
char *ruhs;
|
||||
} fdp;
|
||||
uint16_t atomic_nawun;
|
||||
uint16_t atomic_nawupf;
|
||||
uint16_t atomic_nabsn;
|
||||
uint16_t atomic_nabspf;
|
||||
uint16_t atomic_nabo;
|
||||
bool atomic_nsfeat;
|
||||
|
||||
struct {
|
||||
uint16_t nawun;
|
||||
uint16_t nawupf;
|
||||
uint16_t nabsn;
|
||||
uint16_t nabspf;
|
||||
uint16_t nabo;
|
||||
} atomic;
|
||||
} NvmeNamespaceParams;
|
||||
|
||||
typedef struct NvmeAtomic {
|
||||
|
|
@ -288,11 +290,7 @@ typedef struct NvmeNamespace {
|
|||
/* reclaim unit handle identifiers indexed by placement handle */
|
||||
uint16_t *phs;
|
||||
} fdp;
|
||||
uint16_t atomic_nawun;
|
||||
uint16_t atomic_nawupf;
|
||||
uint16_t atomic_nabsn;
|
||||
uint16_t atomic_nabspf;
|
||||
uint16_t atomic_nabo;
|
||||
|
||||
NvmeAtomic atomic;
|
||||
} NvmeNamespace;
|
||||
|
||||
|
|
@ -742,4 +740,9 @@ void nvme_rw_complete_cb(void *opaque, int ret);
|
|||
uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len,
|
||||
NvmeCmd *cmd);
|
||||
|
||||
void nvme_atomic_configure_max_write_size(bool dn, uint16_t awun,
|
||||
uint16_t awupf, NvmeAtomic *atomic);
|
||||
void nvme_ns_atomic_configure_boundary(bool dn, uint16_t nabsn,
|
||||
uint16_t nabspf, NvmeAtomic *atomic);
|
||||
|
||||
#endif /* HW_NVME_NVME_H */
|
||||
|
|
|
|||
|
|
@ -1589,7 +1589,7 @@ enum NvmeIdNsMc {
|
|||
|
||||
enum NvmeIdNsNsfeat {
|
||||
NVME_ID_NS_NSFEAT_THINP = 1 << 0,
|
||||
NVME_ID_NS_NSFEAT_NSABPNS = 1 << 1,
|
||||
NVME_ID_NS_NSFEAT_NSABP = 1 << 1,
|
||||
NVME_ID_NS_NSFEAT_DAE = 1 << 2,
|
||||
NVME_ID_NS_NSFEAT_UIDREUSE = 1 << 3,
|
||||
NVME_ID_NS_NSFEAT_OPTPERF_ALL = 3 << 4,
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ static void nvme_register_nodes(void)
|
|||
.before_cmd_line = "-drive id=drv0,if=none,file=null-co://,"
|
||||
"file.read-zeroes=on,format=raw "
|
||||
"-object memory-backend-ram,id=pmr0,"
|
||||
"share=on,size=8",
|
||||
"share=on,size=16",
|
||||
};
|
||||
|
||||
add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue