Signed-off-by: Keith Busch <keith.bu...@intel.com> --- 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