Patchwork [05/11] QEMU NVMe: Add DSM command support

login
register
mail settings
Submitter Keith Busch
Date Feb. 27, 2013, 12:47 a.m.
Message ID <1361926034-21824-6-git-send-email-keith.busch@intel.com>
Download mbox | patch
Permalink /patch/223457/
State New
Headers show

Comments

Keith Busch - Feb. 27, 2013, 12:47 a.m.
This adds support for the optional data-set-management command. Action
is only done for the deallocate option.

Signed-off-by: Keith Busch <keith.busch@intel.com>
---
 hw/nvme.c |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 46 insertions(+), 0 deletions(-)

Patch

diff --git a/hw/nvme.c b/hw/nvme.c
index eeff762..69136e0 100644
--- a/hw/nvme.c
+++ b/hw/nvme.c
@@ -378,6 +378,47 @@  static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
     return ret;
 }
 
+static void nvme_dsm_dealloc(NvmeNamespace *ns, uint64_t slba, uint64_t nlb)
+{
+    uint64_t nr;
+    uint64_t elba = nlb + slba;
+    unsigned long *addr = ns->util;
+    for (nr = slba; nr < elba; nr++) {
+        if (test_and_clear_bit(nr, addr)) {
+            assert(ns->id_ns.nuse > 0);
+            --ns->id_ns.nuse;
+        }
+    }
+}
+
+static uint16_t nvme_dsm(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
+    NvmeRequest *req)
+{
+    uint16_t nr = (cmd->cdw10 & 0xff) + 1;
+    NvmeDsmRange range[nr];
+
+    if (nvme_dma_prp(cmd->prp1, cmd->prp2, sizeof(range), n, (uint8_t *)range,
+            DMA_DIRECTION_TO_DEVICE)) {
+        return NVME_INVALID_FIELD | NVME_DNR;
+    }
+
+    if (cmd->cdw11 & NVME_DSMGMT_AD) {
+        int i;
+        uint64_t slba;
+        uint32_t nlb;
+        for (i = 0; i < nr; i++) {
+            slba = range[i].slba;
+            nlb = range[i].nlb;
+            if (slba + nlb > ns->id_ns.ncap) {
+                return NVME_LBA_RANGE | NVME_DNR;
+            }
+            nvme_dsm_dealloc(ns, slba, nlb);
+            /* TODO: send bdrv_aio_discard request */
+        }
+    }
+    return NVME_SUCCESS;
+}
+
 static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
 {
     NvmeNamespace *ns;
@@ -392,6 +433,10 @@  static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
     case NVME_CMD_WRITE:
     case NVME_CMD_READ:
         return nvme_rw(n, ns, cmd, req);
+    case NVME_CMD_DSM:
+        return nvme_dsm(n, ns, cmd, req);
+    case NVME_CMD_COMPARE:
+    case NVME_CMD_WRITE_UNCOR:
     default:
         return NVME_INVALID_OPCODE | NVME_DNR;
     }
@@ -1345,6 +1390,7 @@  static int nvme_init(PCIDevice *pci_dev)
     id->sqes    = n->max_sqes << 4 | 0x6;
     id->cqes    = n->max_cqes << 4 | 0x4;
     id->nn      = n->num_namespaces;
+    id->oncs    = NVME_ONCS_DSM;
     id->vwc     = n->vwc;
     snprintf((char *)id->mn, sizeof(id->mn), "QEMU NVMe Ctrl");
     snprintf((char *)id->fr, sizeof(id->fr), "1.0");