[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 06/11] QEMU NVMe: Implement flush and dsm
From: |
Keith Busch |
Subject: |
[Qemu-devel] [PATCH 06/11] QEMU NVMe: Implement flush and dsm |
Date: |
Tue, 26 Feb 2013 17:47:09 -0700 |
Signed-off-by: Keith Busch <address@hidden>
---
hw/nvme.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
hw/nvme.h | 2 +
2 files changed, 67 insertions(+), 7 deletions(-)
diff --git a/hw/nvme.c b/hw/nvme.c
index 69136e0..087fce9 100644
--- a/hw/nvme.c
+++ b/hw/nvme.c
@@ -327,7 +327,6 @@ static void nvme_rw_cb(void *opaque, int ret)
n = sq->ctrl;
cq = n->cq[sq->cqid];
qemu_sglist_destroy(&req->qsg);
- req->aiocb = NULL;
nvme_update_stats(ns, req->nlb, req->rw);
if (!req->rw) {
@@ -391,10 +390,28 @@ static void nvme_dsm_dealloc(NvmeNamespace *ns, uint64_t
slba, uint64_t nlb)
}
}
+static void nvme_dsm_cb(void *opaque, int ret)
+{
+ NvmeRequest *req = opaque;
+ NvmeSQueue *sq = req->sq;
+ NvmeCtrl *n = sq->ctrl;
+ NvmeCQueue *cq = n->cq[sq->cqid];
+
+ if (ret && !req->cqe.status) {
+ req->cqe.status = NVME_INTERNAL_DEV_ERROR << 1;
+ }
+ if (!(--req->aio_count)) {
+ g_free(req->aiocb_dsm);
+ nvme_enqueue_req_completion(cq, req);
+ }
+}
+
static uint16_t nvme_dsm(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
NvmeRequest *req)
{
uint16_t nr = (cmd->cdw10 & 0xff) + 1;
+ uint8_t lba_index = NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas);
+ uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds;
NvmeDsmRange range[nr];
if (nvme_dma_prp(cmd->prp1, cmd->prp2, sizeof(range), n, (uint8_t *)range,
@@ -406,17 +423,55 @@ static uint16_t nvme_dsm(NvmeCtrl *n, NvmeNamespace *ns,
NvmeCmd *cmd,
int i;
uint64_t slba;
uint32_t nlb;
+ req->aiocb_dsm = g_malloc(nr * sizeof (*req->aiocb_dsm));
+ req->aio_count = nr;
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;
+ req->aio_count -= (nr - i);
+ if (req->aio_count) {
+ req->cqe.status = NVME_LBA_RANGE | NVME_DNR;
+ break;
+ }
+ else {
+ g_free(req->aiocb_dsm);
+ return NVME_LBA_RANGE | NVME_DNR;
+ }
}
nvme_dsm_dealloc(ns, slba, nlb);
- /* TODO: send bdrv_aio_discard request */
+ req->aiocb_dsm[i] = bdrv_aio_discard(n->conf.bs,
+ ns->start_block + (slba << (data_shift - 9)),
+ (nlb + 1) << (data_shift - 9), nvme_dsm_cb, req);
}
}
- return NVME_SUCCESS;
+ if (!req->aio_count) {
+ return NVME_SUCCESS;
+ }
+ return NVME_NO_COMPLETE;
+}
+
+static void nvme_flush_cb(void *opaque, int ret)
+{
+ NvmeRequest *req = opaque;
+ NvmeSQueue *sq = req->sq;
+ NvmeCtrl *n = sq->ctrl;
+ NvmeCQueue *cq = n->cq[sq->cqid];
+
+ if (!ret) {
+ req->cqe.status = NVME_SUCCESS << 1;
+ } else {
+ req->cqe.status = NVME_INTERNAL_DEV_ERROR << 1;
+ }
+ nvme_enqueue_req_completion(cq, req);
+}
+
+static uint16_t nvme_flush(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
+ NvmeRequest *req)
+{
+ req->ns = ns;
+ bdrv_aio_flush(n->conf.bs, nvme_flush_cb, req);
+ return NVME_NO_COMPLETE;
}
static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
@@ -429,7 +484,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd,
NvmeRequest *req)
ns = &n->namespaces[cmd->nsid - 1];
switch (cmd->opcode) {
case NVME_CMD_FLUSH:
- return NVME_SUCCESS;
+ return nvme_flush(n, ns, cmd, req);
case NVME_CMD_WRITE:
case NVME_CMD_READ:
return nvme_rw(n, ns, cmd, req);
@@ -466,8 +521,9 @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd)
sq = n->sq[c->qid];
while (!QTAILQ_EMPTY(&sq->out_req_list)) {
req = QTAILQ_FIRST(&sq->out_req_list);
- assert(req->aiocb);
- bdrv_aio_cancel(req->aiocb);
+ if (req->aiocb) {
+ bdrv_aio_cancel(req->aiocb);
+ }
}
if (!nvme_check_cqid(n, sq->cqid)) {
NvmeCQueue *cq = n->cq[sq->cqid];
@@ -1069,6 +1125,8 @@ static void nvme_sq_process(void *opaque)
QTAILQ_INSERT_TAIL(&sq->out_req_list, req, entry);
memset(&req->cqe, 0, sizeof(req->cqe));
req->cqe.cid = cmd.cid;
+ req->aiocb = NULL;
+ req->aiocb_dsm = NULL;
status = sq->id ? nvme_io_cmd(n, &cmd, req) :
nvme_admin_cmd(n, &cmd, req);
diff --git a/hw/nvme.h b/hw/nvme.h
index 964e91d..4dabb49 100644
--- a/hw/nvme.h
+++ b/hw/nvme.h
@@ -591,9 +591,11 @@ typedef struct NvmeRequest {
struct NvmeSQueue *sq;
struct NvmeNamespace *ns;
BlockDriverAIOCB *aiocb;
+ BlockDriverAIOCB **aiocb_dsm;
uint64_t slba;
uint16_t rw;
uint16_t nlb;
+ uint16_t aio_count;
NvmeCqe cqe;
QEMUSGList qsg;
QTAILQ_ENTRY(NvmeRequest)entry;
--
1.7.0.4
- [Qemu-devel] [PATCH 00/11] *** SUBJECT HERE ***, Keith Busch, 2013/02/26
- [Qemu-devel] [PATCH 08/11] QEMU NVMe: Enqueue critial temperature event, Keith Busch, 2013/02/26
- [Qemu-devel] [PATCH 03/11] QEMU NVMe: Implement NVMe features, Keith Busch, 2013/02/26
- [Qemu-devel] [PATCH 02/11] QEMU NVMe: Add command line options, Keith Busch, 2013/02/26
- [Qemu-devel] [PATCH 06/11] QEMU NVMe: Implement flush and dsm,
Keith Busch <=
- [Qemu-devel] [PATCH 07/11] QEMU NVMe: Set error pages with error data, Keith Busch, 2013/02/26
- [Qemu-devel] [PATCH 05/11] QEMU NVMe: Add DSM command support, Keith Busch, 2013/02/26
- [Qemu-devel] [PATCH 09/11] QEMU NVMe: Implement discontiguous queues, Keith Busch, 2013/02/26
- [Qemu-devel] [PATCH 04/11] QEMU NVMe: Implement additional admin commands, Keith Busch, 2013/02/26
- [Qemu-devel] [PATCH 10/11] QEMU NVMe: Add logging, Keith Busch, 2013/02/26
- [Qemu-devel] [PATCH 11/11] QEMU NVMe: Support NVMe DIF and Meta-data, Keith Busch, 2013/02/26
- [Qemu-devel] [PATCH 01/11] NVMe: Initial commit for NVM Express device, Keith Busch, 2013/02/26