diff mbox series

[RFC,3/5] hw/nvme: add protection information pass parameter

Message ID 20221124155821.1501969-4-d.tihov@yadro.com
State New
Headers show
Series Protection information pass-through for block devices | expand

Commit Message

Dmitry Tihov Nov. 24, 2022, 3:58 p.m. UTC
Allow namespace to enable pass-through of protection information
between guest and integrity capable BlockBackend.

Signed-off-by: Dmitry Tihov <d.tihov@yadro.com>
---
 hw/nvme/ns.c   | 59 +++++++++++++++++++++++++++++++++++++++++++++-----
 hw/nvme/nvme.h |  2 ++
 2 files changed, 55 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c
index 62a1f97be0..da0cff71f8 100644
--- a/hw/nvme/ns.c
+++ b/hw/nvme/ns.c
@@ -35,7 +35,11 @@  void nvme_ns_init_format(NvmeNamespace *ns)
     ns->lbaf = id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)];
     ns->lbasz = 1 << ns->lbaf.ds;
 
-    nlbas = ns->size / (ns->lbasz + ns->lbaf.ms);
+    if (ns->pip) {
+        nlbas = ns->size / (ns->lbasz);
+    } else {
+        nlbas = ns->size / (ns->lbasz + ns->lbaf.ms);
+    }
 
     id_ns->nsze = cpu_to_le64(nlbas);
 
@@ -60,17 +64,22 @@  static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
     static uint64_t ns_count;
     NvmeIdNs *id_ns = &ns->id_ns;
     NvmeIdNsNvm *id_ns_nvm = &ns->id_ns_nvm;
+    BlockDriverInfo bdi;
     uint8_t ds;
     uint16_t ms;
-    int i;
+    int i, ret;
+
+    ns->pip = ns->params.pip;
 
     ns->csi = NVME_CSI_NVM;
     ns->status = 0x0;
 
     ns->id_ns.dlfeat = 0x1;
 
-    /* support DULBE and I/O optimization fields */
-    id_ns->nsfeat |= (0x4 | 0x10);
+    if (!ns->pip) {
+        /* support DULBE and I/O optimization fields */
+        id_ns->nsfeat |= (0x4 | 0x10);
+    }
 
     if (ns->params.shared) {
         id_ns->nmic |= NVME_NMIC_NS_SHARED;
@@ -89,7 +98,11 @@  static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
     id_ns->eui64 = cpu_to_be64(ns->params.eui64);
 
     ds = 31 - clz32(ns->blkconf.logical_block_size);
-    ms = ns->params.ms;
+    if (ns->pip) {
+        ms = 8;
+    } else {
+        ms = ns->params.ms;
+    }
 
     id_ns->mc = NVME_ID_NS_MC_EXTENDED | NVME_ID_NS_MC_SEPARATE;
 
@@ -105,6 +118,14 @@  static int nvme_ns_init(NvmeNamespace *ns, Error **errp)
 
     ns->pif = ns->params.pif;
 
+    if (ns->pip) {
+        ret = bdrv_get_info(blk_bs(ns->blkconf.blk), &bdi);
+        if (ret >= 0) {
+            id_ns->dps = bdi.protection_type;
+            ns->pif = NVME_PI_GUARD_16;
+        }
+    }
+
     static const NvmeLBAF lbaf[16] = {
         [0] = { .ds =  9           },
         [1] = { .ds =  9, .ms =  8 },
@@ -380,13 +401,38 @@  static void nvme_zoned_ns_shutdown(NvmeNamespace *ns)
 static int nvme_ns_check_constraints(NvmeNamespace *ns, Error **errp)
 {
     unsigned int pi_size;
+    BlockDriverInfo bdi;
+    int ret;
 
     if (!ns->blkconf.blk) {
         error_setg(errp, "block backend not configured");
         return -1;
     }
 
-    if (ns->params.pi) {
+    if (ns->params.pip) {
+        if (ns->params.mset) {
+            error_setg(errp, "invalid mset parameter, metadata must be "
+                "stored in a separate buffer to use integrity passthrough");
+            return -1;
+        }
+        ret = bdrv_get_info(blk_bs(ns->blkconf.blk), &bdi);
+        if (ret < 0) {
+            error_setg(errp, "could not determine host block device"
+                       " integrity information");
+            return -1;
+        }
+        if (!bdi.protection_type) {
+            error_setg(errp, "nvme-ns backend block device does not"
+                       " support integrity passthrough");
+            return -1;
+        }
+        if (bdi.protection_interval != ns->blkconf.logical_block_size) {
+            error_setg(errp, "logical block size parameter (%u bytes) must be"
+                " equal to protection information interval (%u bytes)",
+                ns->blkconf.logical_block_size, bdi.protection_interval);
+            return -1;
+        }
+    } else if (ns->params.pi) {
         if (ns->params.pi > NVME_ID_NS_DPS_TYPE_3) {
             error_setg(errp, "invalid 'pi' value");
             return -1;
@@ -623,6 +669,7 @@  static Property nvme_ns_props[] = {
     DEFINE_PROP_UINT8("pi", NvmeNamespace, params.pi, 0),
     DEFINE_PROP_UINT8("pil", NvmeNamespace, params.pil, 0),
     DEFINE_PROP_UINT8("pif", NvmeNamespace, params.pif, 0),
+    DEFINE_PROP_BOOL("pip", NvmeNamespace, params.pip, false),
     DEFINE_PROP_UINT16("mssrl", NvmeNamespace, params.mssrl, 128),
     DEFINE_PROP_UINT32("mcl", NvmeNamespace, params.mcl, 128),
     DEFINE_PROP_UINT8("msrc", NvmeNamespace, params.msrc, 127),
diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h
index 79f5c281c2..4876670d26 100644
--- a/hw/nvme/nvme.h
+++ b/hw/nvme/nvme.h
@@ -109,6 +109,7 @@  typedef struct NvmeNamespaceParams {
     uint8_t  pi;
     uint8_t  pil;
     uint8_t  pif;
+    bool     pip;
 
     uint16_t mssrl;
     uint32_t mcl;
@@ -143,6 +144,7 @@  typedef struct NvmeNamespace {
     uint16_t     status;
     int          attached;
     uint8_t      pif;
+    bool         pip;
 
     struct {
         uint16_t zrwas;