nvme: fix sgl processing for single sge payloads > 4KB
For the nvme readv/writev APIs, the PRP checking logic was incorrectly failing single SGE payloads that were larger than 4KB. This patch adds a test case for this scenario, and fixes the PRP checking logic. Signed-off-by: Jim Harris <james.r.harris@intel.com> Change-Id: I6357d620599666046d2cb74d7923dac1f75418c5
This commit is contained in:
parent
68cdd81a83
commit
de16fcca32
@ -827,6 +827,13 @@ _nvme_qpair_build_prps_sgl_request(struct spdk_nvme_qpair *qpair, struct nvme_re
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Confirm that this sge is prp compatible. */
|
||||||
|
if (phys_addr & 0x3 ||
|
||||||
|
(length < remaining_transfer_len && ((phys_addr + length) & (PAGE_SIZE - 1)))) {
|
||||||
|
_nvme_fail_request_bad_vtophys(qpair, tr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
data_transferred = nvme_min(remaining_transfer_len, length);
|
data_transferred = nvme_min(remaining_transfer_len, length);
|
||||||
|
|
||||||
nseg = data_transferred >> nvme_u32log2(PAGE_SIZE);
|
nseg = data_transferred >> nvme_u32log2(PAGE_SIZE);
|
||||||
@ -839,6 +846,7 @@ _nvme_qpair_build_prps_sgl_request(struct spdk_nvme_qpair *qpair, struct nvme_re
|
|||||||
if (total_nseg == 0) {
|
if (total_nseg == 0) {
|
||||||
req->cmd.psdt = SPDK_NVME_PSDT_PRP;
|
req->cmd.psdt = SPDK_NVME_PSDT_PRP;
|
||||||
req->cmd.dptr.prp.prp1 = phys_addr;
|
req->cmd.dptr.prp.prp1 = phys_addr;
|
||||||
|
phys_addr -= unaligned;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_nseg += nseg;
|
total_nseg += nseg;
|
||||||
@ -847,7 +855,7 @@ _nvme_qpair_build_prps_sgl_request(struct spdk_nvme_qpair *qpair, struct nvme_re
|
|||||||
|
|
||||||
if (total_nseg == 2) {
|
if (total_nseg == 2) {
|
||||||
if (sge_count == 1)
|
if (sge_count == 1)
|
||||||
tr->req->cmd.dptr.prp.prp2 = phys_addr + PAGE_SIZE - unaligned;
|
tr->req->cmd.dptr.prp.prp2 = phys_addr + PAGE_SIZE;
|
||||||
else if (sge_count == 2)
|
else if (sge_count == 2)
|
||||||
tr->req->cmd.dptr.prp.prp2 = phys_addr;
|
tr->req->cmd.dptr.prp.prp2 = phys_addr;
|
||||||
/* save prp2 value */
|
/* save prp2 value */
|
||||||
@ -862,20 +870,12 @@ _nvme_qpair_build_prps_sgl_request(struct spdk_nvme_qpair *qpair, struct nvme_re
|
|||||||
while (cur_nseg < nseg) {
|
while (cur_nseg < nseg) {
|
||||||
if (prp2) {
|
if (prp2) {
|
||||||
tr->u.prp[0] = prp2;
|
tr->u.prp[0] = prp2;
|
||||||
tr->u.prp[last_nseg + 1] = phys_addr + cur_nseg * PAGE_SIZE - unaligned;
|
tr->u.prp[last_nseg + 1] = phys_addr + cur_nseg * PAGE_SIZE;
|
||||||
} else
|
} else
|
||||||
tr->u.prp[last_nseg] = phys_addr + cur_nseg * PAGE_SIZE - unaligned;
|
tr->u.prp[last_nseg] = phys_addr + cur_nseg * PAGE_SIZE;
|
||||||
|
|
||||||
last_nseg++;
|
last_nseg++;
|
||||||
cur_nseg++;
|
cur_nseg++;
|
||||||
|
|
||||||
/* physical address and length check */
|
|
||||||
if (remaining_transfer_len || (!remaining_transfer_len && (cur_nseg < nseg))) {
|
|
||||||
if ((length & (PAGE_SIZE - 1)) || unaligned) {
|
|
||||||
_nvme_fail_request_bad_vtophys(qpair, tr);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,7 @@ struct io_request {
|
|||||||
uint32_t current_iov_bytes_left;
|
uint32_t current_iov_bytes_left;
|
||||||
struct sgl_element iovs[MAX_IOVS];
|
struct sgl_element iovs[MAX_IOVS];
|
||||||
uint32_t nseg;
|
uint32_t nseg;
|
||||||
|
uint32_t misalign;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void nvme_request_reset_sgl(void *cb_arg, uint32_t sgl_offset)
|
static void nvme_request_reset_sgl(void *cb_arg, uint32_t sgl_offset)
|
||||||
@ -216,6 +217,22 @@ static void build_io_request_6(struct io_request *req)
|
|||||||
req->iovs[1].len = 0x1000;
|
req->iovs[1].len = 0x1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void build_io_request_7(struct io_request *req)
|
||||||
|
{
|
||||||
|
uint8_t *base;
|
||||||
|
|
||||||
|
req->nseg = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a 64KB sge, but ensure it is *not* aligned on a 4KB
|
||||||
|
* boundary. This is valid for single element buffers with PRP.
|
||||||
|
*/
|
||||||
|
base = spdk_zmalloc(0x11000, 0x1000, NULL);
|
||||||
|
req->misalign = 64;
|
||||||
|
req->iovs[0].base = base + req->misalign;
|
||||||
|
req->iovs[0].len = 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
typedef void (*nvme_build_io_req_fn_t)(struct io_request *req);
|
typedef void (*nvme_build_io_req_fn_t)(struct io_request *req);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -228,7 +245,7 @@ free_req(struct io_request *req)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < req->nseg; i++) {
|
for (i = 0; i < req->nseg; i++) {
|
||||||
spdk_free(req->iovs[i].base);
|
spdk_free(req->iovs[i].base - req->misalign);
|
||||||
}
|
}
|
||||||
|
|
||||||
spdk_free(req);
|
spdk_free(req);
|
||||||
@ -432,7 +449,8 @@ int main(int argc, char **argv)
|
|||||||
|| TEST(build_io_request_3)
|
|| TEST(build_io_request_3)
|
||||||
|| TEST(build_io_request_4)
|
|| TEST(build_io_request_4)
|
||||||
|| TEST(build_io_request_5)
|
|| TEST(build_io_request_5)
|
||||||
|| TEST(build_io_request_6)) {
|
|| TEST(build_io_request_6)
|
||||||
|
|| TEST(build_io_request_7)) {
|
||||||
#undef TEST
|
#undef TEST
|
||||||
rc = 1;
|
rc = 1;
|
||||||
printf("%s: failed sgl tests\n", iter->name);
|
printf("%s: failed sgl tests\n", iter->name);
|
||||||
|
@ -340,15 +340,9 @@ test_sgl_req(void)
|
|||||||
req->cmd.cdw12 = 7 | 0;
|
req->cmd.cdw12 = 7 | 0;
|
||||||
req->payload_offset = 1;
|
req->payload_offset = 1;
|
||||||
|
|
||||||
CU_ASSERT(nvme_qpair_submit_request(&qpair, req) == 0);
|
CU_ASSERT(nvme_qpair_submit_request(&qpair, req) != 0);
|
||||||
CU_ASSERT(req->cmd.psdt == SPDK_NVME_PSDT_PRP);
|
CU_ASSERT(qpair.sq_tail == 0);
|
||||||
CU_ASSERT(req->cmd.dptr.prp.prp1 == 7);
|
|
||||||
CU_ASSERT(req->cmd.dptr.prp.prp2 == 4096);
|
|
||||||
|
|
||||||
sgl_tr = LIST_FIRST(&qpair.outstanding_tr);
|
|
||||||
LIST_REMOVE(sgl_tr, list);
|
|
||||||
cleanup_submit_request_test(&qpair);
|
cleanup_submit_request_test(&qpair);
|
||||||
nvme_free_request(req);
|
|
||||||
|
|
||||||
prepare_submit_request_test(&qpair, &ctrlr, ®s);
|
prepare_submit_request_test(&qpair, &ctrlr, ®s);
|
||||||
req = nvme_allocate_request(&payload, PAGE_SIZE, NULL, &io_req);
|
req = nvme_allocate_request(&payload, PAGE_SIZE, NULL, &io_req);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user