nvme: move spdk_nvme_map_cmd
to nvmf/vfio-user
Nvmf/vfio-user uses this API to map NVMe command sent from VM from Guest Physical Address to Host Virtual Address, so now we moved this API from the nvme library to nvmf/vfio-user as an internal API. UT code will be added back in coming patch. Change-Id: I54817fc9811ccd9ddd97b3aa6762a2fce4bbdda6 Signed-off-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/8574 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: <dongx.yi@intel.com> Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: GangCao <gang.cao@intel.com> Reviewed-by: Ziye Yang <ziye.yang@intel.com> Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com> Community-CI: Mellanox Build Bot
This commit is contained in:
parent
467f16bf7d
commit
695425c776
@ -50,6 +50,9 @@ Added the `nvmf_set_crdt` RPC for setting command retry delay times.
|
||||
|
||||
### nvme
|
||||
|
||||
`spdk_nvme_map_prps` and `spdk_nvme_map_cmd` were moved to nvmf/vfio-user as internal APIs
|
||||
as vfio-user is the only user for the above two APIs.
|
||||
|
||||
Added a new function `spdk_nvme_ns_cmd_copy` to submit a Simple Copy Command to a Namespace.
|
||||
|
||||
Update the spdk_nvme_generic_command_status_code structure with new status code
|
||||
|
@ -3587,25 +3587,6 @@ int spdk_nvme_cuse_register(struct spdk_nvme_ctrlr *ctrlr);
|
||||
*/
|
||||
int 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));
|
||||
|
||||
/**
|
||||
* Map NVMe command data buffers sent from Virtual Machine to virtual addresses
|
||||
*
|
||||
*\param prv Opaque handle to gpa_to_vva callback
|
||||
*\param cmd NVMe command
|
||||
*\param iovs IO vectors used to point the data buffers in NVMe command
|
||||
*\param max_iovcnt Maximum IO vectors that can be used
|
||||
*\param len Total buffer length for the NVMe command
|
||||
*\param mps Memory page size
|
||||
*\param gpa_to_vva Callback to map memory from Guest Physical address to Virtual address
|
||||
*/
|
||||
int spdk_nvme_map_cmd(void *prv, struct spdk_nvme_cmd *cmd, struct iovec *iovs, uint32_t max_iovcnt,
|
||||
uint32_t len, size_t mps,
|
||||
void *(*gpa_to_vva)(void *prv, uint64_t addr, uint64_t len));
|
||||
|
||||
/**
|
||||
* Opaque handle for a transport poll group. Used by the transport function table.
|
||||
*/
|
||||
|
@ -34,8 +34,8 @@
|
||||
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||
|
||||
SO_VER := 5
|
||||
SO_MINOR := 1
|
||||
SO_VER := 6
|
||||
SO_MINOR := 0
|
||||
|
||||
C_SRCS = nvme_ctrlr_cmd.c nvme_ctrlr.c nvme_fabric.c nvme_ns_cmd.c nvme_ns.c nvme_pcie_common.c nvme_pcie.c nvme_qpair.c nvme.c nvme_quirks.c nvme_transport.c \
|
||||
nvme_ctrlr_ocssd_cmd.c nvme_ns_ocssd_cmd.c nvme_tcp.c nvme_opal.c nvme_io_msg.c nvme_poll_group.c nvme_zns.c
|
||||
|
@ -4414,231 +4414,3 @@ spdk_nvme_ctrlr_free_qid(struct spdk_nvme_ctrlr *ctrlr, uint16_t qid)
|
||||
spdk_bit_array_set(ctrlr->free_io_qids, qid);
|
||||
nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock);
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_cmd_map_prps(void *prv, struct spdk_nvme_cmd *cmd, struct iovec *iovs,
|
||||
uint32_t max_iovcnt, 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;
|
||||
uint32_t iovcnt;
|
||||
|
||||
assert(max_iovcnt > 0);
|
||||
|
||||
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 -EINVAL;
|
||||
}
|
||||
len -= residue_len;
|
||||
if (len && max_iovcnt < 2) {
|
||||
SPDK_ERRLOG("Too many page entries, at least two iovs are required\n");
|
||||
return -ERANGE;
|
||||
}
|
||||
iovs[0].iov_base = vva;
|
||||
iovs[0].iov_len = residue_len;
|
||||
|
||||
if (len) {
|
||||
if (spdk_unlikely(prp2 == 0)) {
|
||||
SPDK_ERRLOG("no PRP2, %d remaining\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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 %#" PRIx64 ", len%#x\n",
|
||||
prp2, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
iovs[1].iov_base = vva;
|
||||
iovs[1].iov_len = len;
|
||||
} else {
|
||||
/* PRP list used */
|
||||
nents = (len + mps - 1) / mps;
|
||||
if (spdk_unlikely(nents + 1 > max_iovcnt)) {
|
||||
SPDK_ERRLOG("Too many page entries\n");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
vva = gpa_to_vva(prv, prp2, nents * sizeof(*prp_list));
|
||||
if (spdk_unlikely(vva == NULL)) {
|
||||
SPDK_ERRLOG("no VVA for %#" PRIx64 ", nents=%#x\n",
|
||||
prp2, nents);
|
||||
return -EINVAL;
|
||||
}
|
||||
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 %#" PRIx64 ", residue_len=%#x\n",
|
||||
prp_list[i], residue_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
assert(iovcnt <= max_iovcnt);
|
||||
return iovcnt;
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_cmd_map_sgls_data(void *prv, struct spdk_nvme_sgl_descriptor *sgls, uint32_t num_sgls,
|
||||
struct iovec *iovs, uint32_t max_iovcnt,
|
||||
void *(*gpa_to_vva)(void *prv, uint64_t addr, uint64_t len))
|
||||
{
|
||||
uint32_t i;
|
||||
void *vva;
|
||||
|
||||
if (spdk_unlikely(max_iovcnt < num_sgls)) {
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_sgls; i++) {
|
||||
if (spdk_unlikely(sgls[i].unkeyed.type != SPDK_NVME_SGL_TYPE_DATA_BLOCK)) {
|
||||
SPDK_ERRLOG("Invalid SGL type %u\n", sgls[i].unkeyed.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
vva = gpa_to_vva(prv, sgls[i].address, sgls[i].unkeyed.length);
|
||||
if (spdk_unlikely(vva == NULL)) {
|
||||
SPDK_ERRLOG("GPA to VVA failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
iovs[i].iov_base = vva;
|
||||
iovs[i].iov_len = sgls[i].unkeyed.length;
|
||||
}
|
||||
|
||||
return num_sgls;
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_cmd_map_sgls(void *prv, struct spdk_nvme_cmd *cmd, struct iovec *iovs, uint32_t max_iovcnt,
|
||||
uint32_t len, size_t mps,
|
||||
void *(*gpa_to_vva)(void *prv, uint64_t addr, uint64_t len))
|
||||
{
|
||||
struct spdk_nvme_sgl_descriptor *sgl, *last_sgl;
|
||||
uint32_t num_sgls, seg_len;
|
||||
void *vva;
|
||||
int ret;
|
||||
uint32_t total_iovcnt = 0;
|
||||
|
||||
/* SGL cases */
|
||||
sgl = &cmd->dptr.sgl1;
|
||||
|
||||
/* only one SGL segment */
|
||||
if (sgl->unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK) {
|
||||
assert(max_iovcnt > 0);
|
||||
vva = gpa_to_vva(prv, sgl->address, sgl->unkeyed.length);
|
||||
if (spdk_unlikely(vva == NULL)) {
|
||||
SPDK_ERRLOG("GPA to VVA failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
iovs[0].iov_base = vva;
|
||||
iovs[0].iov_len = sgl->unkeyed.length;
|
||||
assert(sgl->unkeyed.length == len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (spdk_unlikely((sgl->unkeyed.type != SPDK_NVME_SGL_TYPE_SEGMENT) &&
|
||||
(sgl->unkeyed.type != SPDK_NVME_SGL_TYPE_LAST_SEGMENT))) {
|
||||
SPDK_ERRLOG("Invalid SGL type %u\n", sgl->unkeyed.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
seg_len = sgl->unkeyed.length;
|
||||
if (spdk_unlikely(seg_len % sizeof(struct spdk_nvme_sgl_descriptor))) {
|
||||
SPDK_ERRLOG("Invalid SGL segment len %u\n", seg_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_sgls = seg_len / sizeof(struct spdk_nvme_sgl_descriptor);
|
||||
vva = gpa_to_vva(prv, sgl->address, sgl->unkeyed.length);
|
||||
if (spdk_unlikely(vva == NULL)) {
|
||||
SPDK_ERRLOG("GPA to VVA failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* sgl point to the first segment */
|
||||
sgl = (struct spdk_nvme_sgl_descriptor *)vva;
|
||||
last_sgl = &sgl[num_sgls - 1];
|
||||
|
||||
/* we are done */
|
||||
if (last_sgl->unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK) {
|
||||
/* map whole sgl list */
|
||||
ret = nvme_cmd_map_sgls_data(prv, sgl, num_sgls, &iovs[total_iovcnt],
|
||||
max_iovcnt - total_iovcnt, gpa_to_vva);
|
||||
if (spdk_unlikely(ret < 0)) {
|
||||
return ret;
|
||||
}
|
||||
total_iovcnt += ret;
|
||||
|
||||
return total_iovcnt;
|
||||
}
|
||||
|
||||
if (num_sgls > 1) {
|
||||
/* map whole sgl exclude last_sgl */
|
||||
ret = nvme_cmd_map_sgls_data(prv, sgl, num_sgls - 1, &iovs[total_iovcnt],
|
||||
max_iovcnt - total_iovcnt, gpa_to_vva);
|
||||
if (spdk_unlikely(ret < 0)) {
|
||||
return ret;
|
||||
}
|
||||
total_iovcnt += ret;
|
||||
}
|
||||
|
||||
/* move to next level's segments */
|
||||
sgl = last_sgl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
if (cmd->psdt == SPDK_NVME_PSDT_PRP) {
|
||||
return nvme_cmd_map_prps(prv, cmd, iovs, UINT32_MAX, len, mps, gpa_to_vva);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvme_map_cmd(void *prv, struct spdk_nvme_cmd *cmd, struct iovec *iovs, uint32_t max_iovcnt,
|
||||
uint32_t len, size_t mps,
|
||||
void *(*gpa_to_vva)(void *prv, uint64_t addr, uint64_t len))
|
||||
{
|
||||
if (cmd->psdt == SPDK_NVME_PSDT_PRP) {
|
||||
return nvme_cmd_map_prps(prv, cmd, iovs, max_iovcnt, len, mps, gpa_to_vva);
|
||||
}
|
||||
|
||||
return nvme_cmd_map_sgls(prv, cmd, iovs, max_iovcnt, len, mps, gpa_to_vva);
|
||||
}
|
||||
|
@ -175,9 +175,6 @@
|
||||
spdk_nvme_cuse_unregister;
|
||||
spdk_nvme_cuse_update_namespaces;
|
||||
|
||||
spdk_nvme_map_prps;
|
||||
spdk_nvme_map_cmd;
|
||||
|
||||
spdk_nvme_poll_group_get_stats;
|
||||
spdk_nvme_poll_group_free_stats;
|
||||
|
||||
|
@ -221,6 +221,221 @@ post_completion(struct nvmf_vfio_user_ctrlr *ctrlr, struct spdk_nvme_cmd *cmd,
|
||||
struct nvme_q *cq, uint32_t cdw0, uint16_t sc,
|
||||
uint16_t sct);
|
||||
|
||||
static int
|
||||
nvme_cmd_map_prps(void *prv, struct spdk_nvme_cmd *cmd, struct iovec *iovs,
|
||||
uint32_t max_iovcnt, 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;
|
||||
uint32_t iovcnt;
|
||||
|
||||
assert(max_iovcnt > 0);
|
||||
|
||||
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 -EINVAL;
|
||||
}
|
||||
len -= residue_len;
|
||||
if (len && max_iovcnt < 2) {
|
||||
SPDK_ERRLOG("Too many page entries, at least two iovs are required\n");
|
||||
return -ERANGE;
|
||||
}
|
||||
iovs[0].iov_base = vva;
|
||||
iovs[0].iov_len = residue_len;
|
||||
|
||||
if (len) {
|
||||
if (spdk_unlikely(prp2 == 0)) {
|
||||
SPDK_ERRLOG("no PRP2, %d remaining\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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 %#" PRIx64 ", len%#x\n",
|
||||
prp2, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
iovs[1].iov_base = vva;
|
||||
iovs[1].iov_len = len;
|
||||
} else {
|
||||
/* PRP list used */
|
||||
nents = (len + mps - 1) / mps;
|
||||
if (spdk_unlikely(nents + 1 > max_iovcnt)) {
|
||||
SPDK_ERRLOG("Too many page entries\n");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
vva = gpa_to_vva(prv, prp2, nents * sizeof(*prp_list));
|
||||
if (spdk_unlikely(vva == NULL)) {
|
||||
SPDK_ERRLOG("no VVA for %#" PRIx64 ", nents=%#x\n",
|
||||
prp2, nents);
|
||||
return -EINVAL;
|
||||
}
|
||||
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 %#" PRIx64 ", residue_len=%#x\n",
|
||||
prp_list[i], residue_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
assert(iovcnt <= max_iovcnt);
|
||||
return iovcnt;
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_cmd_map_sgls_data(void *prv, struct spdk_nvme_sgl_descriptor *sgls, uint32_t num_sgls,
|
||||
struct iovec *iovs, uint32_t max_iovcnt,
|
||||
void *(*gpa_to_vva)(void *prv, uint64_t addr, uint64_t len))
|
||||
{
|
||||
uint32_t i;
|
||||
void *vva;
|
||||
|
||||
if (spdk_unlikely(max_iovcnt < num_sgls)) {
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_sgls; i++) {
|
||||
if (spdk_unlikely(sgls[i].unkeyed.type != SPDK_NVME_SGL_TYPE_DATA_BLOCK)) {
|
||||
SPDK_ERRLOG("Invalid SGL type %u\n", sgls[i].unkeyed.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
vva = gpa_to_vva(prv, sgls[i].address, sgls[i].unkeyed.length);
|
||||
if (spdk_unlikely(vva == NULL)) {
|
||||
SPDK_ERRLOG("GPA to VVA failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
iovs[i].iov_base = vva;
|
||||
iovs[i].iov_len = sgls[i].unkeyed.length;
|
||||
}
|
||||
|
||||
return num_sgls;
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_cmd_map_sgls(void *prv, struct spdk_nvme_cmd *cmd, struct iovec *iovs, uint32_t max_iovcnt,
|
||||
uint32_t len, size_t mps,
|
||||
void *(*gpa_to_vva)(void *prv, uint64_t addr, uint64_t len))
|
||||
{
|
||||
struct spdk_nvme_sgl_descriptor *sgl, *last_sgl;
|
||||
uint32_t num_sgls, seg_len;
|
||||
void *vva;
|
||||
int ret;
|
||||
uint32_t total_iovcnt = 0;
|
||||
|
||||
/* SGL cases */
|
||||
sgl = &cmd->dptr.sgl1;
|
||||
|
||||
/* only one SGL segment */
|
||||
if (sgl->unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK) {
|
||||
assert(max_iovcnt > 0);
|
||||
vva = gpa_to_vva(prv, sgl->address, sgl->unkeyed.length);
|
||||
if (spdk_unlikely(vva == NULL)) {
|
||||
SPDK_ERRLOG("GPA to VVA failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
iovs[0].iov_base = vva;
|
||||
iovs[0].iov_len = sgl->unkeyed.length;
|
||||
assert(sgl->unkeyed.length == len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (spdk_unlikely((sgl->unkeyed.type != SPDK_NVME_SGL_TYPE_SEGMENT) &&
|
||||
(sgl->unkeyed.type != SPDK_NVME_SGL_TYPE_LAST_SEGMENT))) {
|
||||
SPDK_ERRLOG("Invalid SGL type %u\n", sgl->unkeyed.type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
seg_len = sgl->unkeyed.length;
|
||||
if (spdk_unlikely(seg_len % sizeof(struct spdk_nvme_sgl_descriptor))) {
|
||||
SPDK_ERRLOG("Invalid SGL segment len %u\n", seg_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_sgls = seg_len / sizeof(struct spdk_nvme_sgl_descriptor);
|
||||
vva = gpa_to_vva(prv, sgl->address, sgl->unkeyed.length);
|
||||
if (spdk_unlikely(vva == NULL)) {
|
||||
SPDK_ERRLOG("GPA to VVA failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* sgl point to the first segment */
|
||||
sgl = (struct spdk_nvme_sgl_descriptor *)vva;
|
||||
last_sgl = &sgl[num_sgls - 1];
|
||||
|
||||
/* we are done */
|
||||
if (last_sgl->unkeyed.type == SPDK_NVME_SGL_TYPE_DATA_BLOCK) {
|
||||
/* map whole sgl list */
|
||||
ret = nvme_cmd_map_sgls_data(prv, sgl, num_sgls, &iovs[total_iovcnt],
|
||||
max_iovcnt - total_iovcnt, gpa_to_vva);
|
||||
if (spdk_unlikely(ret < 0)) {
|
||||
return ret;
|
||||
}
|
||||
total_iovcnt += ret;
|
||||
|
||||
return total_iovcnt;
|
||||
}
|
||||
|
||||
if (num_sgls > 1) {
|
||||
/* map whole sgl exclude last_sgl */
|
||||
ret = nvme_cmd_map_sgls_data(prv, sgl, num_sgls - 1, &iovs[total_iovcnt],
|
||||
max_iovcnt - total_iovcnt, gpa_to_vva);
|
||||
if (spdk_unlikely(ret < 0)) {
|
||||
return ret;
|
||||
}
|
||||
total_iovcnt += ret;
|
||||
}
|
||||
|
||||
/* move to next level's segments */
|
||||
sgl = last_sgl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_map_cmd(void *prv, struct spdk_nvme_cmd *cmd, struct iovec *iovs, uint32_t max_iovcnt,
|
||||
uint32_t len, size_t mps,
|
||||
void *(*gpa_to_vva)(void *prv, uint64_t addr, uint64_t len))
|
||||
{
|
||||
if (cmd->psdt == SPDK_NVME_PSDT_PRP) {
|
||||
return nvme_cmd_map_prps(prv, cmd, iovs, max_iovcnt, len, mps, gpa_to_vva);
|
||||
}
|
||||
|
||||
return nvme_cmd_map_sgls(prv, cmd, iovs, max_iovcnt, len, mps, gpa_to_vva);
|
||||
}
|
||||
|
||||
static char *
|
||||
endpoint_id(struct nvmf_vfio_user_endpoint *endpoint)
|
||||
{
|
||||
@ -562,8 +777,8 @@ vfio_user_map_cmd(struct nvmf_vfio_user_ctrlr *ctrlr, struct spdk_nvmf_request *
|
||||
/* Map PRP list to from Guest physical memory to
|
||||
* virtual memory address.
|
||||
*/
|
||||
return spdk_nvme_map_cmd(req, &req->cmd->nvme_cmd, iov, NVMF_REQ_MAX_BUFFERS,
|
||||
length, 4096, _map_one);
|
||||
return nvme_map_cmd(req, &req->cmd->nvme_cmd, iov, NVMF_REQ_MAX_BUFFERS,
|
||||
length, 4096, _map_one);
|
||||
}
|
||||
|
||||
static struct spdk_nvmf_request *
|
||||
|
@ -2392,175 +2392,6 @@ test_nvme_ctrlr_add_remove_process(void)
|
||||
CU_ASSERT(TAILQ_EMPTY(&ctrlr.active_procs));
|
||||
}
|
||||
|
||||
static void *
|
||||
gpa_to_vva(void *prv, uint64_t addr, uint64_t len)
|
||||
{
|
||||
return (void *)(uintptr_t)addr;
|
||||
}
|
||||
|
||||
static void
|
||||
test_nvme_cmd_map_prps(void)
|
||||
{
|
||||
struct spdk_nvme_cmd cmd = {};
|
||||
struct iovec iovs[33];
|
||||
uint64_t phy_addr, *prp;
|
||||
uint32_t len;
|
||||
void *buf, *prps;
|
||||
int i, ret;
|
||||
size_t mps = 4096;
|
||||
|
||||
buf = spdk_zmalloc(132 * 1024, 4096, &phy_addr, 0, 0);
|
||||
CU_ASSERT(buf != NULL);
|
||||
prps = spdk_zmalloc(4096, 4096, &phy_addr, 0, 0);
|
||||
CU_ASSERT(prps != NULL);
|
||||
|
||||
/* test case 1: 4KiB with PRP1 only */
|
||||
cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf;
|
||||
len = 4096;
|
||||
ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
|
||||
CU_ASSERT(ret == 1);
|
||||
CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1);
|
||||
CU_ASSERT(iovs[0].iov_len == len);
|
||||
|
||||
/* test case 2: 4KiB with PRP1 and PRP2, 1KiB in first iov, and 3KiB in second iov */
|
||||
cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3;
|
||||
cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)buf + 4096;
|
||||
len = 4096;
|
||||
ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 1, len, mps, gpa_to_vva);
|
||||
CU_ASSERT(ret == -ERANGE);
|
||||
ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
|
||||
CU_ASSERT(ret == 2);
|
||||
CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1);
|
||||
CU_ASSERT(iovs[0].iov_len == 1024);
|
||||
CU_ASSERT(iovs[1].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp2);
|
||||
CU_ASSERT(iovs[1].iov_len == 1024 * 3);
|
||||
|
||||
/* test case 3: 128KiB with PRP list, 1KiB in first iov, 3KiB in last iov */
|
||||
cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3;
|
||||
cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)prps;
|
||||
len = 128 * 1024;
|
||||
prp = prps;
|
||||
for (i = 1; i < 33; i++) {
|
||||
*prp = (uint64_t)(uintptr_t)buf + i * 4096;
|
||||
prp++;
|
||||
}
|
||||
ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
|
||||
CU_ASSERT(ret == 33);
|
||||
CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)cmd.dptr.prp.prp1);
|
||||
CU_ASSERT(iovs[0].iov_len == 1024);
|
||||
for (i = 1; i < 32; i++) {
|
||||
CU_ASSERT(iovs[i].iov_base == (void *)((uintptr_t)buf + i * 4096));
|
||||
CU_ASSERT(iovs[i].iov_len == 4096);
|
||||
}
|
||||
CU_ASSERT(iovs[32].iov_base == (void *)((uintptr_t)buf + 32 * 4096));
|
||||
CU_ASSERT(iovs[32].iov_len == 1024 * 3);
|
||||
|
||||
/* test case 4: 256KiB with PRP list, not enough iovs */
|
||||
cmd.dptr.prp.prp1 = (uint64_t)(uintptr_t)buf + 1024 * 3;
|
||||
cmd.dptr.prp.prp2 = (uint64_t)(uintptr_t)prps;
|
||||
len = 256 * 1024;
|
||||
ret = nvme_cmd_map_prps(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
|
||||
CU_ASSERT(ret == -ERANGE);
|
||||
|
||||
spdk_free(buf);
|
||||
spdk_free(prps);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nvme_cmd_map_sgls(void)
|
||||
{
|
||||
struct spdk_nvme_cmd cmd = {};
|
||||
struct iovec iovs[33];
|
||||
uint64_t phy_addr;
|
||||
uint32_t len;
|
||||
void *buf, *sgls;
|
||||
struct spdk_nvme_sgl_descriptor *sgl;
|
||||
int i, ret;
|
||||
size_t mps = 4096;
|
||||
|
||||
buf = spdk_zmalloc(132 * 1024, 4096, &phy_addr, 0, 0);
|
||||
CU_ASSERT(buf != NULL);
|
||||
sgls = spdk_zmalloc(4096, 4096, &phy_addr, 0, 0);
|
||||
CU_ASSERT(sgls != NULL);
|
||||
|
||||
/* test case 1: 8KiB with 1 data block */
|
||||
len = 8192;
|
||||
cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
|
||||
cmd.dptr.sgl1.unkeyed.length = len;
|
||||
cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)buf;
|
||||
|
||||
ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
|
||||
CU_ASSERT(ret == 1);
|
||||
CU_ASSERT(iovs[0].iov_base == buf);
|
||||
CU_ASSERT(iovs[0].iov_len == 8192);
|
||||
|
||||
/* test case 2: 8KiB with 2 data blocks and 1 last segment */
|
||||
sgl = (struct spdk_nvme_sgl_descriptor *)sgls;
|
||||
sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
|
||||
sgl[0].unkeyed.length = 2048;
|
||||
sgl[0].address = (uint64_t)(uintptr_t)buf;
|
||||
sgl[1].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
|
||||
sgl[1].unkeyed.length = len - 2048;
|
||||
sgl[1].address = (uint64_t)(uintptr_t)buf + 16 * 1024;
|
||||
|
||||
cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT;
|
||||
cmd.dptr.sgl1.unkeyed.length = 2 * sizeof(*sgl);
|
||||
cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)sgls;
|
||||
|
||||
ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
|
||||
CU_ASSERT(ret == 2);
|
||||
CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)buf);
|
||||
CU_ASSERT(iovs[0].iov_len == 2048);
|
||||
CU_ASSERT(iovs[1].iov_base == (void *)((uintptr_t)buf + 16 * 1024));
|
||||
CU_ASSERT(iovs[1].iov_len == len - 2048);
|
||||
|
||||
/* test case 3: 8KiB with 1 segment, 1 last segment and 3 data blocks */
|
||||
sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
|
||||
sgl[0].unkeyed.length = 2048;
|
||||
sgl[0].address = (uint64_t)(uintptr_t)buf;
|
||||
sgl[1].unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT;
|
||||
sgl[1].unkeyed.length = 2 * sizeof(*sgl);
|
||||
sgl[1].address = (uint64_t)(uintptr_t)&sgl[9];
|
||||
|
||||
sgl[9].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
|
||||
sgl[9].unkeyed.length = 4096;
|
||||
sgl[9].address = (uint64_t)(uintptr_t)buf + 4 * 1024;
|
||||
sgl[10].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
|
||||
sgl[10].unkeyed.length = 2048;
|
||||
sgl[10].address = (uint64_t)(uintptr_t)buf + 16 * 1024;
|
||||
|
||||
cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_SEGMENT;
|
||||
cmd.dptr.sgl1.unkeyed.length = 2 * sizeof(*sgl);
|
||||
cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)&sgl[0];
|
||||
|
||||
ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 33, len, mps, gpa_to_vva);
|
||||
CU_ASSERT(ret == 3);
|
||||
CU_ASSERT(iovs[0].iov_base == (void *)(uintptr_t)buf);
|
||||
CU_ASSERT(iovs[0].iov_len == 2048);
|
||||
CU_ASSERT(iovs[1].iov_base == (void *)((uintptr_t)buf + 4 * 1024));
|
||||
CU_ASSERT(iovs[1].iov_len == 4096);
|
||||
CU_ASSERT(iovs[2].iov_base == (void *)((uintptr_t)buf + 16 * 1024));
|
||||
CU_ASSERT(iovs[2].iov_len == 2048);
|
||||
|
||||
/* test case 4: not enough iovs */
|
||||
len = 12 * 1024;
|
||||
for (i = 0; i < 6; i++) {
|
||||
sgl[0].unkeyed.type = SPDK_NVME_SGL_TYPE_DATA_BLOCK;
|
||||
sgl[0].unkeyed.length = 2048;
|
||||
sgl[0].address = (uint64_t)(uintptr_t)buf + i * 4096;
|
||||
}
|
||||
|
||||
cmd.dptr.sgl1.unkeyed.type = SPDK_NVME_SGL_TYPE_LAST_SEGMENT;
|
||||
cmd.dptr.sgl1.unkeyed.length = 6 * sizeof(*sgl);
|
||||
cmd.dptr.sgl1.address = (uint64_t)(uintptr_t)sgls;
|
||||
|
||||
ret = nvme_cmd_map_sgls(NULL, &cmd, iovs, 4, len, mps, gpa_to_vva);
|
||||
CU_ASSERT(ret == -ERANGE);
|
||||
|
||||
spdk_free(buf);
|
||||
spdk_free(sgls);
|
||||
}
|
||||
|
||||
static void
|
||||
test_nvme_ctrlr_set_arbitration_feature(void)
|
||||
{
|
||||
@ -3095,8 +2926,6 @@ int main(int argc, char **argv)
|
||||
CU_ADD_TEST(suite, test_nvme_ctrlr_init_set_keep_alive_timeout);
|
||||
CU_ADD_TEST(suite, test_alloc_io_qpair_fail);
|
||||
CU_ADD_TEST(suite, test_nvme_ctrlr_add_remove_process);
|
||||
CU_ADD_TEST(suite, test_nvme_cmd_map_prps);
|
||||
CU_ADD_TEST(suite, test_nvme_cmd_map_sgls);
|
||||
CU_ADD_TEST(suite, test_nvme_ctrlr_set_arbitration_feature);
|
||||
CU_ADD_TEST(suite, test_nvme_ctrlr_set_state);
|
||||
CU_ADD_TEST(suite, test_nvme_ctrlr_active_ns_list_v0);
|
||||
|
Loading…
Reference in New Issue
Block a user