diff --git a/include/spdk/nvme.h b/include/spdk/nvme.h index 4d2267c48..c8404004e 100644 --- a/include/spdk/nvme.h +++ b/include/spdk/nvme.h @@ -2899,6 +2899,10 @@ int spdk_nvme_cuse_register(struct spdk_nvme_ctrlr *ctrlr); */ void spdk_nvme_cuse_unregister(struct spdk_nvme_ctrlr *ctrlr); +int spdk_nvme_map_prps(void *prv, struct spdk_nvme_cmd *cmd, struct iovec *iovs, + uint32_t len, size_t mps, + void *(*gpa_to_vva)(void *prv, uint64_t addr, uint64_t len)); + struct nvme_request; struct spdk_nvme_transport; diff --git a/lib/nvme/nvme_ctrlr.c b/lib/nvme/nvme_ctrlr.c index b64eea387..672088660 100644 --- a/lib/nvme/nvme_ctrlr.c +++ b/lib/nvme/nvme_ctrlr.c @@ -3312,3 +3312,83 @@ spdk_nvme_ctrlr_get_transport_id(struct spdk_nvme_ctrlr *ctrlr) { return &ctrlr->trid; } + +/* FIXME need to specify max number of iovs */ +int +spdk_nvme_map_prps(void *prv, struct spdk_nvme_cmd *cmd, struct iovec *iovs, + uint32_t len, size_t mps, + void *(*gpa_to_vva)(void *prv, uint64_t addr, uint64_t len)) +{ + uint64_t prp1, prp2; + void *vva; + uint32_t i; + uint32_t residue_len, nents; + uint64_t *prp_list; + int iovcnt; + + prp1 = cmd->dptr.prp.prp1; + prp2 = cmd->dptr.prp.prp2; + + /* PRP1 may started with unaligned page address */ + residue_len = mps - (prp1 % mps); + residue_len = spdk_min(len, residue_len); + + vva = gpa_to_vva(prv, prp1, residue_len); + if (spdk_unlikely(vva == NULL)) { + SPDK_ERRLOG("GPA to VVA failed\n"); + return -1; + } + iovs[0].iov_base = vva; + iovs[0].iov_len = residue_len; + len -= residue_len; + + if (len) { + if (spdk_unlikely(prp2 == 0)) { + SPDK_ERRLOG("no PRP2, %d remaining\n", len); + return -1; + } + + if (len <= mps) { + /* 2 PRP used */ + iovcnt = 2; + vva = gpa_to_vva(prv, prp2, len); + if (spdk_unlikely(vva == NULL)) { + SPDK_ERRLOG("no VVA for %#lx, len%#x\n", + prp2, len); + return -1; + } + iovs[1].iov_base = vva; + iovs[1].iov_len = len; + } else { + /* PRP list used */ + nents = (len + mps - 1) / mps; + vva = gpa_to_vva(prv, prp2, nents * sizeof(*prp_list)); + if (spdk_unlikely(vva == NULL)) { + SPDK_ERRLOG("no VVA for %#lx, nents=%#x\n", + prp2, nents); + return -1; + } + prp_list = vva; + i = 0; + while (len != 0) { + residue_len = spdk_min(len, mps); + vva = gpa_to_vva(prv, prp_list[i], residue_len); + if (spdk_unlikely(vva == NULL)) { + SPDK_ERRLOG("no VVA for %#lx, residue_len=%#x\n", + prp_list[i], residue_len); + return -1; + } + iovs[i + 1].iov_base = vva; + iovs[i + 1].iov_len = residue_len; + len -= residue_len; + i++; + } + iovcnt = i + 1; + } + } else { + /* 1 PRP used */ + iovcnt = 1; + } + + return iovcnt; +} diff --git a/lib/vhost/vhost_nvme.c b/lib/vhost/vhost_nvme.c index a742eb3b3..0b9ed154d 100644 --- a/lib/vhost/vhost_nvme.c +++ b/lib/vhost/vhost_nvme.c @@ -248,74 +248,17 @@ spdk_vhost_nvme_get_queue_head(struct spdk_vhost_nvme_dev *nvme, uint32_t offset } static int -spdk_nvme_map_prps(struct spdk_vhost_nvme_dev *nvme, struct spdk_nvme_cmd *cmd, - struct spdk_vhost_nvme_task *task, uint32_t len) +spdk_vhost_nvme_map_prps(struct spdk_vhost_nvme_dev *nvme, struct spdk_nvme_cmd *cmd, + struct spdk_vhost_nvme_task *task, uint32_t len) { - struct spdk_vhost_session *vsession = nvme->vsession; - uint64_t prp1, prp2; - void *vva; - uint32_t i; - uint32_t residue_len, nents, mps = 4096; - uint64_t *prp_list; + int err; - prp1 = cmd->dptr.prp.prp1; - prp2 = cmd->dptr.prp.prp2; - - /* PRP1 may started with unaligned page address */ - residue_len = mps - (prp1 % mps); - residue_len = spdk_min(len, residue_len); - - vva = vhost_gpa_to_vva(vsession, prp1, residue_len); - if (spdk_unlikely(vva == NULL)) { - SPDK_ERRLOG("GPA to VVA failed\n"); - return -1; + err = spdk_nvme_map_prps(nvme->session, cmd, task->iovs, len, 4096, + vhost_gpa_to_vva); + if (spdk_unlikely(err < 0)) { + return err; } - task->iovs[0].iov_base = vva; - task->iovs[0].iov_len = residue_len; - len -= residue_len; - - if (len) { - if (spdk_unlikely(prp2 == 0)) { - SPDK_DEBUGLOG(SPDK_LOG_VHOST_NVME, "Invalid PRP2=0 in command\n"); - return -1; - } - - if (len <= mps) { - /* 2 PRP used */ - task->iovcnt = 2; - vva = vhost_gpa_to_vva(vsession, prp2, len); - if (spdk_unlikely(vva == NULL)) { - return -1; - } - task->iovs[1].iov_base = vva; - task->iovs[1].iov_len = len; - } else { - /* PRP list used */ - nents = (len + mps - 1) / mps; - vva = vhost_gpa_to_vva(vsession, prp2, nents * sizeof(*prp_list)); - if (spdk_unlikely(vva == NULL)) { - return -1; - } - prp_list = vva; - i = 0; - while (len != 0) { - residue_len = spdk_min(len, mps); - vva = vhost_gpa_to_vva(vsession, prp_list[i], residue_len); - if (spdk_unlikely(vva == NULL)) { - return -1; - } - task->iovs[i + 1].iov_base = vva; - task->iovs[i + 1].iov_len = residue_len; - len -= residue_len; - i++; - } - task->iovcnt = i + 1; - } - } else { - /* 1 PRP used */ - task->iovcnt = 1; - } - + task->iovcnt = err; return 0; } @@ -547,7 +490,7 @@ spdk_nvme_process_sq(struct spdk_vhost_nvme_dev *nvme, struct spdk_vhost_nvme_sq len = nlba * block_size; } - ret = spdk_nvme_map_prps(nvme, cmd, task, len); + ret = spdk_vhost_nvme_map_prps(nvme, cmd, task, len); if (spdk_unlikely(ret != 0)) { SPDK_ERRLOG("nvme command map prps failed\n"); task->dnr = 1;