mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-10 11:04:58 -06:00
hw/nvme: add cross namespace copy support
Extend copy command to copy user data across different namespaces via support for specifying a namespace for each source range Signed-off-by: Arun Kumar <arun.kka@samsung.com> Reviewed-by: Klaus Jensen <k.jensen@samsung.com> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
This commit is contained in:
parent
c510fe78f1
commit
d522aef88d
2 changed files with 289 additions and 103 deletions
355
hw/nvme/ctrl.c
355
hw/nvme/ctrl.c
|
@ -2696,6 +2696,7 @@ typedef struct NvmeCopyAIOCB {
|
||||||
BlockAIOCB common;
|
BlockAIOCB common;
|
||||||
BlockAIOCB *aiocb;
|
BlockAIOCB *aiocb;
|
||||||
NvmeRequest *req;
|
NvmeRequest *req;
|
||||||
|
NvmeCtrl *n;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
void *ranges;
|
void *ranges;
|
||||||
|
@ -2714,6 +2715,8 @@ typedef struct NvmeCopyAIOCB {
|
||||||
uint64_t slba;
|
uint64_t slba;
|
||||||
|
|
||||||
NvmeZone *zone;
|
NvmeZone *zone;
|
||||||
|
NvmeNamespace *sns;
|
||||||
|
uint32_t tcl;
|
||||||
} NvmeCopyAIOCB;
|
} NvmeCopyAIOCB;
|
||||||
|
|
||||||
static void nvme_copy_cancel(BlockAIOCB *aiocb)
|
static void nvme_copy_cancel(BlockAIOCB *aiocb)
|
||||||
|
@ -2760,13 +2763,19 @@ static void nvme_copy_done(NvmeCopyAIOCB *iocb)
|
||||||
|
|
||||||
static void nvme_do_copy(NvmeCopyAIOCB *iocb);
|
static void nvme_do_copy(NvmeCopyAIOCB *iocb);
|
||||||
|
|
||||||
static void nvme_copy_source_range_parse_format0(void *ranges, int idx,
|
static void nvme_copy_source_range_parse_format0_2(void *ranges,
|
||||||
uint64_t *slba, uint32_t *nlb,
|
int idx, uint64_t *slba,
|
||||||
uint16_t *apptag,
|
uint32_t *nlb,
|
||||||
uint16_t *appmask,
|
uint32_t *snsid,
|
||||||
uint64_t *reftag)
|
uint16_t *apptag,
|
||||||
|
uint16_t *appmask,
|
||||||
|
uint64_t *reftag)
|
||||||
{
|
{
|
||||||
NvmeCopySourceRangeFormat0 *_ranges = ranges;
|
NvmeCopySourceRangeFormat0_2 *_ranges = ranges;
|
||||||
|
|
||||||
|
if (snsid) {
|
||||||
|
*snsid = le32_to_cpu(_ranges[idx].sparams);
|
||||||
|
}
|
||||||
|
|
||||||
if (slba) {
|
if (slba) {
|
||||||
*slba = le64_to_cpu(_ranges[idx].slba);
|
*slba = le64_to_cpu(_ranges[idx].slba);
|
||||||
|
@ -2789,13 +2798,19 @@ static void nvme_copy_source_range_parse_format0(void *ranges, int idx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvme_copy_source_range_parse_format1(void *ranges, int idx,
|
static void nvme_copy_source_range_parse_format1_3(void *ranges, int idx,
|
||||||
uint64_t *slba, uint32_t *nlb,
|
uint64_t *slba,
|
||||||
uint16_t *apptag,
|
uint32_t *nlb,
|
||||||
uint16_t *appmask,
|
uint32_t *snsid,
|
||||||
uint64_t *reftag)
|
uint16_t *apptag,
|
||||||
|
uint16_t *appmask,
|
||||||
|
uint64_t *reftag)
|
||||||
{
|
{
|
||||||
NvmeCopySourceRangeFormat1 *_ranges = ranges;
|
NvmeCopySourceRangeFormat1_3 *_ranges = ranges;
|
||||||
|
|
||||||
|
if (snsid) {
|
||||||
|
*snsid = le32_to_cpu(_ranges[idx].sparams);
|
||||||
|
}
|
||||||
|
|
||||||
if (slba) {
|
if (slba) {
|
||||||
*slba = le64_to_cpu(_ranges[idx].slba);
|
*slba = le64_to_cpu(_ranges[idx].slba);
|
||||||
|
@ -2827,18 +2842,20 @@ static void nvme_copy_source_range_parse_format1(void *ranges, int idx,
|
||||||
|
|
||||||
static void nvme_copy_source_range_parse(void *ranges, int idx, uint8_t format,
|
static void nvme_copy_source_range_parse(void *ranges, int idx, uint8_t format,
|
||||||
uint64_t *slba, uint32_t *nlb,
|
uint64_t *slba, uint32_t *nlb,
|
||||||
uint16_t *apptag, uint16_t *appmask,
|
uint32_t *snsid, uint16_t *apptag,
|
||||||
uint64_t *reftag)
|
uint16_t *appmask, uint64_t *reftag)
|
||||||
{
|
{
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case NVME_COPY_FORMAT_0:
|
case NVME_COPY_FORMAT_0:
|
||||||
nvme_copy_source_range_parse_format0(ranges, idx, slba, nlb, apptag,
|
case NVME_COPY_FORMAT_2:
|
||||||
appmask, reftag);
|
nvme_copy_source_range_parse_format0_2(ranges, idx, slba, nlb, snsid,
|
||||||
|
apptag, appmask, reftag);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NVME_COPY_FORMAT_1:
|
case NVME_COPY_FORMAT_1:
|
||||||
nvme_copy_source_range_parse_format1(ranges, idx, slba, nlb, apptag,
|
case NVME_COPY_FORMAT_3:
|
||||||
appmask, reftag);
|
nvme_copy_source_range_parse_format1_3(ranges, idx, slba, nlb, snsid,
|
||||||
|
apptag, appmask, reftag);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2854,10 +2871,10 @@ static inline uint16_t nvme_check_copy_mcl(NvmeNamespace *ns,
|
||||||
for (int idx = 0; idx < nr; idx++) {
|
for (int idx = 0; idx < nr; idx++) {
|
||||||
uint32_t nlb;
|
uint32_t nlb;
|
||||||
nvme_copy_source_range_parse(iocb->ranges, idx, iocb->format, NULL,
|
nvme_copy_source_range_parse(iocb->ranges, idx, iocb->format, NULL,
|
||||||
&nlb, NULL, NULL, NULL);
|
&nlb, NULL, NULL, NULL, NULL);
|
||||||
copy_len += nlb;
|
copy_len += nlb;
|
||||||
}
|
}
|
||||||
|
iocb->tcl = copy_len;
|
||||||
if (copy_len > ns->id_ns.mcl) {
|
if (copy_len > ns->id_ns.mcl) {
|
||||||
return NVME_CMD_SIZE_LIMIT | NVME_DNR;
|
return NVME_CMD_SIZE_LIMIT | NVME_DNR;
|
||||||
}
|
}
|
||||||
|
@ -2869,11 +2886,11 @@ static void nvme_copy_out_completed_cb(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
NvmeCopyAIOCB *iocb = opaque;
|
NvmeCopyAIOCB *iocb = opaque;
|
||||||
NvmeRequest *req = iocb->req;
|
NvmeRequest *req = iocb->req;
|
||||||
NvmeNamespace *ns = req->ns;
|
NvmeNamespace *dns = req->ns;
|
||||||
uint32_t nlb;
|
uint32_t nlb;
|
||||||
|
|
||||||
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, NULL,
|
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, NULL,
|
||||||
&nlb, NULL, NULL, NULL);
|
&nlb, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
iocb->ret = ret;
|
iocb->ret = ret;
|
||||||
|
@ -2882,8 +2899,8 @@ static void nvme_copy_out_completed_cb(void *opaque, int ret)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns->params.zoned) {
|
if (dns->params.zoned) {
|
||||||
nvme_advance_zone_wp(ns, iocb->zone, nlb);
|
nvme_advance_zone_wp(dns, iocb->zone, nlb);
|
||||||
}
|
}
|
||||||
|
|
||||||
iocb->idx++;
|
iocb->idx++;
|
||||||
|
@ -2896,25 +2913,25 @@ static void nvme_copy_out_cb(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
NvmeCopyAIOCB *iocb = opaque;
|
NvmeCopyAIOCB *iocb = opaque;
|
||||||
NvmeRequest *req = iocb->req;
|
NvmeRequest *req = iocb->req;
|
||||||
NvmeNamespace *ns = req->ns;
|
NvmeNamespace *dns = req->ns;
|
||||||
uint32_t nlb;
|
uint32_t nlb;
|
||||||
size_t mlen;
|
size_t mlen;
|
||||||
uint8_t *mbounce;
|
uint8_t *mbounce;
|
||||||
|
|
||||||
if (ret < 0 || iocb->ret < 0 || !ns->lbaf.ms) {
|
if (ret < 0 || iocb->ret < 0 || !dns->lbaf.ms) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, NULL,
|
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, NULL,
|
||||||
&nlb, NULL, NULL, NULL);
|
&nlb, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
mlen = nvme_m2b(ns, nlb);
|
mlen = nvme_m2b(dns, nlb);
|
||||||
mbounce = iocb->bounce + nvme_l2b(ns, nlb);
|
mbounce = iocb->bounce + nvme_l2b(dns, nlb);
|
||||||
|
|
||||||
qemu_iovec_reset(&iocb->iov);
|
qemu_iovec_reset(&iocb->iov);
|
||||||
qemu_iovec_add(&iocb->iov, mbounce, mlen);
|
qemu_iovec_add(&iocb->iov, mbounce, mlen);
|
||||||
|
|
||||||
iocb->aiocb = blk_aio_pwritev(ns->blkconf.blk, nvme_moff(ns, iocb->slba),
|
iocb->aiocb = blk_aio_pwritev(dns->blkconf.blk, nvme_moff(dns, iocb->slba),
|
||||||
&iocb->iov, 0, nvme_copy_out_completed_cb,
|
&iocb->iov, 0, nvme_copy_out_completed_cb,
|
||||||
iocb);
|
iocb);
|
||||||
|
|
||||||
|
@ -2928,12 +2945,15 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
NvmeCopyAIOCB *iocb = opaque;
|
NvmeCopyAIOCB *iocb = opaque;
|
||||||
NvmeRequest *req = iocb->req;
|
NvmeRequest *req = iocb->req;
|
||||||
NvmeNamespace *ns = req->ns;
|
NvmeNamespace *sns = iocb->sns;
|
||||||
|
NvmeNamespace *dns = req->ns;
|
||||||
|
NvmeCopyCmd *copy = NULL;
|
||||||
|
uint8_t *mbounce = NULL;
|
||||||
uint32_t nlb;
|
uint32_t nlb;
|
||||||
uint64_t slba;
|
uint64_t slba;
|
||||||
uint16_t apptag, appmask;
|
uint16_t apptag, appmask;
|
||||||
uint64_t reftag;
|
uint64_t reftag;
|
||||||
size_t len;
|
size_t len, mlen;
|
||||||
uint16_t status;
|
uint16_t status;
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -2944,43 +2964,51 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
|
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
|
||||||
&nlb, &apptag, &appmask, &reftag);
|
&nlb, NULL, &apptag, &appmask, &reftag);
|
||||||
len = nvme_l2b(ns, nlb);
|
|
||||||
|
|
||||||
trace_pci_nvme_copy_out(iocb->slba, nlb);
|
trace_pci_nvme_copy_out(iocb->slba, nlb);
|
||||||
|
|
||||||
if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) {
|
len = nvme_l2b(sns, nlb);
|
||||||
NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd;
|
|
||||||
|
if (NVME_ID_NS_DPS_TYPE(sns->id_ns.dps)) {
|
||||||
|
copy = (NvmeCopyCmd *)&req->cmd;
|
||||||
|
|
||||||
uint16_t prinfor = ((copy->control[0] >> 4) & 0xf);
|
uint16_t prinfor = ((copy->control[0] >> 4) & 0xf);
|
||||||
uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
|
|
||||||
|
|
||||||
size_t mlen = nvme_m2b(ns, nlb);
|
mlen = nvme_m2b(sns, nlb);
|
||||||
uint8_t *mbounce = iocb->bounce + nvme_l2b(ns, nlb);
|
mbounce = iocb->bounce + nvme_l2b(sns, nlb);
|
||||||
|
|
||||||
status = nvme_dif_mangle_mdata(ns, mbounce, mlen, slba);
|
status = nvme_dif_mangle_mdata(sns, mbounce, mlen, slba);
|
||||||
if (status) {
|
if (status) {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
status = nvme_dif_check(ns, iocb->bounce, len, mbounce, mlen, prinfor,
|
status = nvme_dif_check(sns, iocb->bounce, len, mbounce, mlen, prinfor,
|
||||||
slba, apptag, appmask, &reftag);
|
slba, apptag, appmask, &reftag);
|
||||||
if (status) {
|
if (status) {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
|
||||||
|
copy = (NvmeCopyCmd *)&req->cmd;
|
||||||
|
uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
|
||||||
|
|
||||||
|
mlen = nvme_m2b(dns, nlb);
|
||||||
|
mbounce = iocb->bounce + nvme_l2b(dns, nlb);
|
||||||
|
|
||||||
apptag = le16_to_cpu(copy->apptag);
|
apptag = le16_to_cpu(copy->apptag);
|
||||||
appmask = le16_to_cpu(copy->appmask);
|
appmask = le16_to_cpu(copy->appmask);
|
||||||
|
|
||||||
if (prinfow & NVME_PRINFO_PRACT) {
|
if (prinfow & NVME_PRINFO_PRACT) {
|
||||||
status = nvme_check_prinfo(ns, prinfow, iocb->slba, iocb->reftag);
|
status = nvme_check_prinfo(dns, prinfow, iocb->slba, iocb->reftag);
|
||||||
if (status) {
|
if (status) {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvme_dif_pract_generate_dif(ns, iocb->bounce, len, mbounce, mlen,
|
nvme_dif_pract_generate_dif(dns, iocb->bounce, len, mbounce, mlen,
|
||||||
apptag, &iocb->reftag);
|
apptag, &iocb->reftag);
|
||||||
} else {
|
} else {
|
||||||
status = nvme_dif_check(ns, iocb->bounce, len, mbounce, mlen,
|
status = nvme_dif_check(dns, iocb->bounce, len, mbounce, mlen,
|
||||||
prinfow, iocb->slba, apptag, appmask,
|
prinfow, iocb->slba, apptag, appmask,
|
||||||
&iocb->reftag);
|
&iocb->reftag);
|
||||||
if (status) {
|
if (status) {
|
||||||
|
@ -2989,13 +3017,13 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = nvme_check_bounds(ns, iocb->slba, nlb);
|
status = nvme_check_bounds(dns, iocb->slba, nlb);
|
||||||
if (status) {
|
if (status) {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns->params.zoned) {
|
if (dns->params.zoned) {
|
||||||
status = nvme_check_zone_write(ns, iocb->zone, iocb->slba, nlb);
|
status = nvme_check_zone_write(dns, iocb->zone, iocb->slba, nlb);
|
||||||
if (status) {
|
if (status) {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
|
@ -3008,7 +3036,10 @@ static void nvme_copy_in_completed_cb(void *opaque, int ret)
|
||||||
qemu_iovec_reset(&iocb->iov);
|
qemu_iovec_reset(&iocb->iov);
|
||||||
qemu_iovec_add(&iocb->iov, iocb->bounce, len);
|
qemu_iovec_add(&iocb->iov, iocb->bounce, len);
|
||||||
|
|
||||||
iocb->aiocb = blk_aio_pwritev(ns->blkconf.blk, nvme_l2b(ns, iocb->slba),
|
block_acct_start(blk_get_stats(dns->blkconf.blk), &iocb->acct.write, 0,
|
||||||
|
BLOCK_ACCT_WRITE);
|
||||||
|
|
||||||
|
iocb->aiocb = blk_aio_pwritev(dns->blkconf.blk, nvme_l2b(dns, iocb->slba),
|
||||||
&iocb->iov, 0, nvme_copy_out_cb, iocb);
|
&iocb->iov, 0, nvme_copy_out_cb, iocb);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -3023,23 +3054,22 @@ out:
|
||||||
static void nvme_copy_in_cb(void *opaque, int ret)
|
static void nvme_copy_in_cb(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
NvmeCopyAIOCB *iocb = opaque;
|
NvmeCopyAIOCB *iocb = opaque;
|
||||||
NvmeRequest *req = iocb->req;
|
NvmeNamespace *sns = iocb->sns;
|
||||||
NvmeNamespace *ns = req->ns;
|
|
||||||
uint64_t slba;
|
uint64_t slba;
|
||||||
uint32_t nlb;
|
uint32_t nlb;
|
||||||
|
|
||||||
if (ret < 0 || iocb->ret < 0 || !ns->lbaf.ms) {
|
if (ret < 0 || iocb->ret < 0 || !sns->lbaf.ms) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
|
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
|
||||||
&nlb, NULL, NULL, NULL);
|
&nlb, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
qemu_iovec_reset(&iocb->iov);
|
qemu_iovec_reset(&iocb->iov);
|
||||||
qemu_iovec_add(&iocb->iov, iocb->bounce + nvme_l2b(ns, nlb),
|
qemu_iovec_add(&iocb->iov, iocb->bounce + nvme_l2b(sns, nlb),
|
||||||
nvme_m2b(ns, nlb));
|
nvme_m2b(sns, nlb));
|
||||||
|
|
||||||
iocb->aiocb = blk_aio_preadv(ns->blkconf.blk, nvme_moff(ns, slba),
|
iocb->aiocb = blk_aio_preadv(sns->blkconf.blk, nvme_moff(sns, slba),
|
||||||
&iocb->iov, 0, nvme_copy_in_completed_cb,
|
&iocb->iov, 0, nvme_copy_in_completed_cb,
|
||||||
iocb);
|
iocb);
|
||||||
return;
|
return;
|
||||||
|
@ -3048,14 +3078,78 @@ out:
|
||||||
nvme_copy_in_completed_cb(iocb, ret);
|
nvme_copy_in_completed_cb(iocb, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool nvme_csi_supports_copy(uint8_t csi)
|
||||||
|
{
|
||||||
|
return csi == NVME_CSI_NVM || csi == NVME_CSI_ZONED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool nvme_copy_ns_format_match(NvmeNamespace *sns,
|
||||||
|
NvmeNamespace *dns)
|
||||||
|
{
|
||||||
|
return sns->lbaf.ds == dns->lbaf.ds && sns->lbaf.ms == dns->lbaf.ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nvme_copy_matching_ns_format(NvmeNamespace *sns, NvmeNamespace *dns,
|
||||||
|
bool pi_enable)
|
||||||
|
{
|
||||||
|
if (!nvme_csi_supports_copy(sns->csi) ||
|
||||||
|
!nvme_csi_supports_copy(dns->csi)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pi_enable && !nvme_copy_ns_format_match(sns, dns)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pi_enable && (!nvme_copy_ns_format_match(sns, dns) ||
|
||||||
|
sns->id_ns.dps != dns->id_ns.dps)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool nvme_copy_corresp_pi_match(NvmeNamespace *sns,
|
||||||
|
NvmeNamespace *dns)
|
||||||
|
{
|
||||||
|
return sns->lbaf.ms == 0 &&
|
||||||
|
((dns->lbaf.ms == 8 && dns->pif == 0) ||
|
||||||
|
(dns->lbaf.ms == 16 && dns->pif == 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nvme_copy_corresp_pi_format(NvmeNamespace *sns, NvmeNamespace *dns,
|
||||||
|
bool sns_pi_en)
|
||||||
|
{
|
||||||
|
if (!nvme_csi_supports_copy(sns->csi) ||
|
||||||
|
!nvme_csi_supports_copy(dns->csi)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sns_pi_en && !nvme_copy_corresp_pi_match(sns, dns)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sns_pi_en && !nvme_copy_corresp_pi_match(dns, sns)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void nvme_do_copy(NvmeCopyAIOCB *iocb)
|
static void nvme_do_copy(NvmeCopyAIOCB *iocb)
|
||||||
{
|
{
|
||||||
NvmeRequest *req = iocb->req;
|
NvmeRequest *req = iocb->req;
|
||||||
NvmeNamespace *ns = req->ns;
|
NvmeNamespace *sns;
|
||||||
|
NvmeNamespace *dns = req->ns;
|
||||||
|
NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd;
|
||||||
|
uint16_t prinfor = ((copy->control[0] >> 4) & 0xf);
|
||||||
|
uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
|
||||||
uint64_t slba;
|
uint64_t slba;
|
||||||
uint32_t nlb;
|
uint32_t nlb;
|
||||||
size_t len;
|
size_t len;
|
||||||
uint16_t status;
|
uint16_t status;
|
||||||
|
uint32_t dnsid = le32_to_cpu(req->cmd.nsid);
|
||||||
|
uint32_t snsid = dnsid;
|
||||||
|
|
||||||
if (iocb->ret < 0) {
|
if (iocb->ret < 0) {
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -3065,40 +3159,124 @@ static void nvme_do_copy(NvmeCopyAIOCB *iocb)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format, &slba,
|
if (iocb->format == 2 || iocb->format == 3) {
|
||||||
&nlb, NULL, NULL, NULL);
|
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format,
|
||||||
len = nvme_l2b(ns, nlb);
|
&slba, &nlb, &snsid, NULL, NULL, NULL);
|
||||||
|
if (snsid != dnsid) {
|
||||||
|
if (snsid == NVME_NSID_BROADCAST ||
|
||||||
|
!nvme_nsid_valid(iocb->n, snsid)) {
|
||||||
|
status = NVME_INVALID_NSID | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
iocb->sns = nvme_ns(iocb->n, snsid);
|
||||||
|
if (unlikely(!iocb->sns)) {
|
||||||
|
status = NVME_INVALID_FIELD | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (((slba + nlb) > iocb->slba) &&
|
||||||
|
((slba + nlb) < (iocb->slba + iocb->tcl))) {
|
||||||
|
status = NVME_CMD_OVERLAP_IO_RANGE | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nvme_copy_source_range_parse(iocb->ranges, iocb->idx, iocb->format,
|
||||||
|
&slba, &nlb, NULL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
sns = iocb->sns;
|
||||||
|
if ((snsid == dnsid) && NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
|
||||||
|
((prinfor & NVME_PRINFO_PRACT) != (prinfow & NVME_PRINFO_PRACT))) {
|
||||||
|
status = NVME_INVALID_FIELD | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
} else if (snsid != dnsid) {
|
||||||
|
if (!NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
|
||||||
|
!NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
|
||||||
|
if (!nvme_copy_matching_ns_format(sns, dns, false)) {
|
||||||
|
status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
|
||||||
|
NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
|
||||||
|
if ((prinfor & NVME_PRINFO_PRACT) !=
|
||||||
|
(prinfow & NVME_PRINFO_PRACT)) {
|
||||||
|
status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
} else {
|
||||||
|
if (!nvme_copy_matching_ns_format(sns, dns, true)) {
|
||||||
|
status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
|
||||||
|
NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
|
||||||
|
if (!(prinfow & NVME_PRINFO_PRACT)) {
|
||||||
|
status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
} else {
|
||||||
|
if (!nvme_copy_corresp_pi_format(sns, dns, false)) {
|
||||||
|
status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NVME_ID_NS_DPS_TYPE(sns->id_ns.dps) &&
|
||||||
|
!NVME_ID_NS_DPS_TYPE(dns->id_ns.dps)) {
|
||||||
|
if (!(prinfor & NVME_PRINFO_PRACT)) {
|
||||||
|
status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
} else {
|
||||||
|
if (!nvme_copy_corresp_pi_format(sns, dns, true)) {
|
||||||
|
status = NVME_CMD_INCOMP_NS_OR_FMT | NVME_DNR;
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len = nvme_l2b(sns, nlb);
|
||||||
|
|
||||||
trace_pci_nvme_copy_source_range(slba, nlb);
|
trace_pci_nvme_copy_source_range(slba, nlb);
|
||||||
|
|
||||||
if (nlb > le16_to_cpu(ns->id_ns.mssrl)) {
|
if (nlb > le16_to_cpu(sns->id_ns.mssrl)) {
|
||||||
status = NVME_CMD_SIZE_LIMIT | NVME_DNR;
|
status = NVME_CMD_SIZE_LIMIT | NVME_DNR;
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = nvme_check_bounds(ns, slba, nlb);
|
status = nvme_check_bounds(sns, slba, nlb);
|
||||||
if (status) {
|
if (status) {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NVME_ERR_REC_DULBE(ns->features.err_rec)) {
|
if (NVME_ERR_REC_DULBE(sns->features.err_rec)) {
|
||||||
status = nvme_check_dulbe(ns, slba, nlb);
|
status = nvme_check_dulbe(sns, slba, nlb);
|
||||||
if (status) {
|
if (status) {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns->params.zoned) {
|
if (sns->params.zoned) {
|
||||||
status = nvme_check_zone_read(ns, slba, nlb);
|
status = nvme_check_zone_read(sns, slba, nlb);
|
||||||
if (status) {
|
if (status) {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free(iocb->bounce);
|
||||||
|
iocb->bounce = g_malloc_n(le16_to_cpu(sns->id_ns.mssrl),
|
||||||
|
sns->lbasz + sns->lbaf.ms);
|
||||||
|
|
||||||
qemu_iovec_reset(&iocb->iov);
|
qemu_iovec_reset(&iocb->iov);
|
||||||
qemu_iovec_add(&iocb->iov, iocb->bounce, len);
|
qemu_iovec_add(&iocb->iov, iocb->bounce, len);
|
||||||
|
|
||||||
iocb->aiocb = blk_aio_preadv(ns->blkconf.blk, nvme_l2b(ns, slba),
|
block_acct_start(blk_get_stats(sns->blkconf.blk), &iocb->acct.read, 0,
|
||||||
|
BLOCK_ACCT_READ);
|
||||||
|
|
||||||
|
iocb->aiocb = blk_aio_preadv(sns->blkconf.blk, nvme_l2b(sns, slba),
|
||||||
&iocb->iov, 0, nvme_copy_in_cb, iocb);
|
&iocb->iov, 0, nvme_copy_in_cb, iocb);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -3117,9 +3295,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
|
||||||
nvme_misc_cb, req);
|
nvme_misc_cb, req);
|
||||||
uint16_t nr = copy->nr + 1;
|
uint16_t nr = copy->nr + 1;
|
||||||
uint8_t format = copy->control[0] & 0xf;
|
uint8_t format = copy->control[0] & 0xf;
|
||||||
uint16_t prinfor = ((copy->control[0] >> 4) & 0xf);
|
size_t len = sizeof(NvmeCopySourceRangeFormat0_2);
|
||||||
uint16_t prinfow = ((copy->control[2] >> 2) & 0xf);
|
|
||||||
size_t len = sizeof(NvmeCopySourceRangeFormat0);
|
|
||||||
|
|
||||||
uint16_t status;
|
uint16_t status;
|
||||||
|
|
||||||
|
@ -3128,13 +3304,9 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
|
||||||
iocb->ranges = NULL;
|
iocb->ranges = NULL;
|
||||||
iocb->zone = NULL;
|
iocb->zone = NULL;
|
||||||
|
|
||||||
if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) &&
|
if (!(n->id_ctrl.ocfs & (1 << format)) ||
|
||||||
((prinfor & NVME_PRINFO_PRACT) != (prinfow & NVME_PRINFO_PRACT))) {
|
((format == 2 || format == 3) &&
|
||||||
status = NVME_INVALID_FIELD | NVME_DNR;
|
!(n->features.hbs.cdfe & (1 << format)))) {
|
||||||
goto invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(n->id_ctrl.ocfs & (1 << format))) {
|
|
||||||
trace_pci_nvme_err_copy_invalid_format(format);
|
trace_pci_nvme_err_copy_invalid_format(format);
|
||||||
status = NVME_INVALID_FIELD | NVME_DNR;
|
status = NVME_INVALID_FIELD | NVME_DNR;
|
||||||
goto invalid;
|
goto invalid;
|
||||||
|
@ -3145,14 +3317,14 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ns->pif == 0x0 && format != 0x0) ||
|
if ((ns->pif == 0x0 && (format != 0x0 && format != 0x2)) ||
|
||||||
(ns->pif != 0x0 && format != 0x1)) {
|
(ns->pif != 0x0 && (format != 0x1 && format != 0x3))) {
|
||||||
status = NVME_INVALID_FORMAT | NVME_DNR;
|
status = NVME_INVALID_FORMAT | NVME_DNR;
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns->pif) {
|
if (ns->pif) {
|
||||||
len = sizeof(NvmeCopySourceRangeFormat1);
|
len = sizeof(NvmeCopySourceRangeFormat1_3);
|
||||||
}
|
}
|
||||||
|
|
||||||
iocb->format = format;
|
iocb->format = format;
|
||||||
|
@ -3188,17 +3360,13 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req)
|
||||||
iocb->idx = 0;
|
iocb->idx = 0;
|
||||||
iocb->reftag = le32_to_cpu(copy->reftag);
|
iocb->reftag = le32_to_cpu(copy->reftag);
|
||||||
iocb->reftag |= (uint64_t)le32_to_cpu(copy->cdw3) << 32;
|
iocb->reftag |= (uint64_t)le32_to_cpu(copy->cdw3) << 32;
|
||||||
iocb->bounce = g_malloc_n(le16_to_cpu(ns->id_ns.mssrl),
|
|
||||||
ns->lbasz + ns->lbaf.ms);
|
|
||||||
|
|
||||||
qemu_iovec_init(&iocb->iov, 1);
|
qemu_iovec_init(&iocb->iov, 1);
|
||||||
|
|
||||||
block_acct_start(blk_get_stats(ns->blkconf.blk), &iocb->acct.read, 0,
|
|
||||||
BLOCK_ACCT_READ);
|
|
||||||
block_acct_start(blk_get_stats(ns->blkconf.blk), &iocb->acct.write, 0,
|
|
||||||
BLOCK_ACCT_WRITE);
|
|
||||||
|
|
||||||
req->aiocb = &iocb->common;
|
req->aiocb = &iocb->common;
|
||||||
|
iocb->sns = req->ns;
|
||||||
|
iocb->n = n;
|
||||||
|
iocb->bounce = NULL;
|
||||||
nvme_do_copy(iocb);
|
nvme_do_copy(iocb);
|
||||||
|
|
||||||
return NVME_NO_COMPLETE;
|
return NVME_NO_COMPLETE;
|
||||||
|
@ -4407,10 +4575,6 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
|
||||||
trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req),
|
trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req),
|
||||||
req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode));
|
req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode));
|
||||||
|
|
||||||
if (!nvme_nsid_valid(n, nsid)) {
|
|
||||||
return NVME_INVALID_NSID | NVME_DNR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the base NVM command set, Flush may apply to all namespaces
|
* In the base NVM command set, Flush may apply to all namespaces
|
||||||
* (indicated by NSID being set to FFFFFFFFh). But if that feature is used
|
* (indicated by NSID being set to FFFFFFFFh). But if that feature is used
|
||||||
|
@ -4430,10 +4594,15 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req)
|
||||||
* device only supports namespace types that includes the NVM Flush command
|
* device only supports namespace types that includes the NVM Flush command
|
||||||
* (NVM and Zoned), so always do an NVM Flush.
|
* (NVM and Zoned), so always do an NVM Flush.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (req->cmd.opcode == NVME_CMD_FLUSH) {
|
if (req->cmd.opcode == NVME_CMD_FLUSH) {
|
||||||
return nvme_flush(n, req);
|
return nvme_flush(n, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!nvme_nsid_valid(n, nsid) || nsid == NVME_NSID_BROADCAST) {
|
||||||
|
return NVME_INVALID_NSID | NVME_DNR;
|
||||||
|
}
|
||||||
|
|
||||||
ns = nvme_ns(n, nsid);
|
ns = nvme_ns(n, nsid);
|
||||||
if (unlikely(!ns)) {
|
if (unlikely(!ns)) {
|
||||||
return NVME_INVALID_FIELD | NVME_DNR;
|
return NVME_INVALID_FIELD | NVME_DNR;
|
||||||
|
@ -8288,7 +8457,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
|
||||||
id->nn = cpu_to_le32(NVME_MAX_NAMESPACES);
|
id->nn = cpu_to_le32(NVME_MAX_NAMESPACES);
|
||||||
id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP |
|
id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP |
|
||||||
NVME_ONCS_FEATURES | NVME_ONCS_DSM |
|
NVME_ONCS_FEATURES | NVME_ONCS_DSM |
|
||||||
NVME_ONCS_COMPARE | NVME_ONCS_COPY);
|
NVME_ONCS_COMPARE | NVME_ONCS_COPY |
|
||||||
|
NVME_ONCS_NVMCSA | NVME_ONCS_NVMAFC);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: If this device ever supports a command set that does NOT use 0x0
|
* NOTE: If this device ever supports a command set that does NOT use 0x0
|
||||||
|
@ -8299,7 +8469,8 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
|
||||||
*/
|
*/
|
||||||
id->vwc = NVME_VWC_NSID_BROADCAST_SUPPORT | NVME_VWC_PRESENT;
|
id->vwc = NVME_VWC_NSID_BROADCAST_SUPPORT | NVME_VWC_PRESENT;
|
||||||
|
|
||||||
id->ocfs = cpu_to_le16(NVME_OCFS_COPY_FORMAT_0 | NVME_OCFS_COPY_FORMAT_1);
|
id->ocfs = cpu_to_le16(NVME_OCFS_COPY_FORMAT_0 | NVME_OCFS_COPY_FORMAT_1 |
|
||||||
|
NVME_OCFS_COPY_FORMAT_2 | NVME_OCFS_COPY_FORMAT_3);
|
||||||
id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN);
|
id->sgls = cpu_to_le32(NVME_CTRL_SGLS_SUPPORT_NO_ALIGN);
|
||||||
|
|
||||||
nvme_init_subnqn(n);
|
nvme_init_subnqn(n);
|
||||||
|
|
|
@ -799,6 +799,8 @@ typedef struct QEMU_PACKED NvmeDsmRange {
|
||||||
enum {
|
enum {
|
||||||
NVME_COPY_FORMAT_0 = 0x0,
|
NVME_COPY_FORMAT_0 = 0x0,
|
||||||
NVME_COPY_FORMAT_1 = 0x1,
|
NVME_COPY_FORMAT_1 = 0x1,
|
||||||
|
NVME_COPY_FORMAT_2 = 0x2,
|
||||||
|
NVME_COPY_FORMAT_3 = 0x3,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct QEMU_PACKED NvmeCopyCmd {
|
typedef struct QEMU_PACKED NvmeCopyCmd {
|
||||||
|
@ -820,25 +822,30 @@ typedef struct QEMU_PACKED NvmeCopyCmd {
|
||||||
uint16_t appmask;
|
uint16_t appmask;
|
||||||
} NvmeCopyCmd;
|
} NvmeCopyCmd;
|
||||||
|
|
||||||
typedef struct QEMU_PACKED NvmeCopySourceRangeFormat0 {
|
typedef struct QEMU_PACKED NvmeCopySourceRangeFormat0_2 {
|
||||||
uint8_t rsvd0[8];
|
uint32_t sparams;
|
||||||
|
uint8_t rsvd4[4];
|
||||||
uint64_t slba;
|
uint64_t slba;
|
||||||
uint16_t nlb;
|
uint16_t nlb;
|
||||||
uint8_t rsvd18[6];
|
uint8_t rsvd18[4];
|
||||||
|
uint16_t sopt;
|
||||||
uint32_t reftag;
|
uint32_t reftag;
|
||||||
uint16_t apptag;
|
uint16_t apptag;
|
||||||
uint16_t appmask;
|
uint16_t appmask;
|
||||||
} NvmeCopySourceRangeFormat0;
|
} NvmeCopySourceRangeFormat0_2;
|
||||||
|
|
||||||
typedef struct QEMU_PACKED NvmeCopySourceRangeFormat1 {
|
typedef struct QEMU_PACKED NvmeCopySourceRangeFormat1_3 {
|
||||||
uint8_t rsvd0[8];
|
uint32_t sparams;
|
||||||
|
uint8_t rsvd4[4];
|
||||||
uint64_t slba;
|
uint64_t slba;
|
||||||
uint16_t nlb;
|
uint16_t nlb;
|
||||||
uint8_t rsvd18[8];
|
uint8_t rsvd18[4];
|
||||||
|
uint16_t sopt;
|
||||||
|
uint8_t rsvd24[2];
|
||||||
uint8_t sr[10];
|
uint8_t sr[10];
|
||||||
uint16_t apptag;
|
uint16_t apptag;
|
||||||
uint16_t appmask;
|
uint16_t appmask;
|
||||||
} NvmeCopySourceRangeFormat1;
|
} NvmeCopySourceRangeFormat1_3;
|
||||||
|
|
||||||
enum NvmeAsyncEventRequest {
|
enum NvmeAsyncEventRequest {
|
||||||
NVME_AER_TYPE_ERROR = 0,
|
NVME_AER_TYPE_ERROR = 0,
|
||||||
|
@ -937,6 +944,8 @@ enum NvmeStatusCodes {
|
||||||
NVME_INVALID_PROT_INFO = 0x0181,
|
NVME_INVALID_PROT_INFO = 0x0181,
|
||||||
NVME_WRITE_TO_RO = 0x0182,
|
NVME_WRITE_TO_RO = 0x0182,
|
||||||
NVME_CMD_SIZE_LIMIT = 0x0183,
|
NVME_CMD_SIZE_LIMIT = 0x0183,
|
||||||
|
NVME_CMD_INCOMP_NS_OR_FMT = 0x0185,
|
||||||
|
NVME_CMD_OVERLAP_IO_RANGE = 0x0187,
|
||||||
NVME_INVALID_ZONE_OP = 0x01b6,
|
NVME_INVALID_ZONE_OP = 0x01b6,
|
||||||
NVME_NOZRWA = 0x01b7,
|
NVME_NOZRWA = 0x01b7,
|
||||||
NVME_ZONE_BOUNDARY_ERROR = 0x01b8,
|
NVME_ZONE_BOUNDARY_ERROR = 0x01b8,
|
||||||
|
@ -1195,11 +1204,15 @@ enum NvmeIdCtrlOncs {
|
||||||
NVME_ONCS_TIMESTAMP = 1 << 6,
|
NVME_ONCS_TIMESTAMP = 1 << 6,
|
||||||
NVME_ONCS_VERIFY = 1 << 7,
|
NVME_ONCS_VERIFY = 1 << 7,
|
||||||
NVME_ONCS_COPY = 1 << 8,
|
NVME_ONCS_COPY = 1 << 8,
|
||||||
|
NVME_ONCS_NVMCSA = 1 << 9,
|
||||||
|
NVME_ONCS_NVMAFC = 1 << 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NvmeIdCtrlOcfs {
|
enum NvmeIdCtrlOcfs {
|
||||||
NVME_OCFS_COPY_FORMAT_0 = 1 << NVME_COPY_FORMAT_0,
|
NVME_OCFS_COPY_FORMAT_0 = 1 << NVME_COPY_FORMAT_0,
|
||||||
NVME_OCFS_COPY_FORMAT_1 = 1 << NVME_COPY_FORMAT_1,
|
NVME_OCFS_COPY_FORMAT_1 = 1 << NVME_COPY_FORMAT_1,
|
||||||
|
NVME_OCFS_COPY_FORMAT_2 = 1 << NVME_COPY_FORMAT_2,
|
||||||
|
NVME_OCFS_COPY_FORMAT_3 = 1 << NVME_COPY_FORMAT_3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NvmeIdctrlVwc {
|
enum NvmeIdctrlVwc {
|
||||||
|
@ -1333,7 +1346,9 @@ typedef struct NvmeHostBehaviorSupport {
|
||||||
uint8_t acre;
|
uint8_t acre;
|
||||||
uint8_t etdas;
|
uint8_t etdas;
|
||||||
uint8_t lbafee;
|
uint8_t lbafee;
|
||||||
uint8_t rsvd3[509];
|
uint8_t rsvd3;
|
||||||
|
uint16_t cdfe;
|
||||||
|
uint8_t rsvd6[506];
|
||||||
} NvmeHostBehaviorSupport;
|
} NvmeHostBehaviorSupport;
|
||||||
|
|
||||||
typedef struct QEMU_PACKED NvmeLBAF {
|
typedef struct QEMU_PACKED NvmeLBAF {
|
||||||
|
@ -1833,8 +1848,8 @@ static inline void _nvme_check_size(void)
|
||||||
QEMU_BUILD_BUG_ON(sizeof(NvmeZonedResult) != 8);
|
QEMU_BUILD_BUG_ON(sizeof(NvmeZonedResult) != 8);
|
||||||
QEMU_BUILD_BUG_ON(sizeof(NvmeCqe) != 16);
|
QEMU_BUILD_BUG_ON(sizeof(NvmeCqe) != 16);
|
||||||
QEMU_BUILD_BUG_ON(sizeof(NvmeDsmRange) != 16);
|
QEMU_BUILD_BUG_ON(sizeof(NvmeDsmRange) != 16);
|
||||||
QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat0) != 32);
|
QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat0_2) != 32);
|
||||||
QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat1) != 40);
|
QEMU_BUILD_BUG_ON(sizeof(NvmeCopySourceRangeFormat1_3) != 40);
|
||||||
QEMU_BUILD_BUG_ON(sizeof(NvmeCmd) != 64);
|
QEMU_BUILD_BUG_ON(sizeof(NvmeCmd) != 64);
|
||||||
QEMU_BUILD_BUG_ON(sizeof(NvmeDeleteQ) != 64);
|
QEMU_BUILD_BUG_ON(sizeof(NvmeDeleteQ) != 64);
|
||||||
QEMU_BUILD_BUG_ON(sizeof(NvmeCreateCq) != 64);
|
QEMU_BUILD_BUG_ON(sizeof(NvmeCreateCq) != 64);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue