#include "../config-host.h" /* SPDX-License-Identifier: MIT */ /* * Description: mixed sqes utilizing basic nop and io_uring passthrough commands */ #include #include #include #include #include #include "helpers.h" #include "liburing.h" #include "nvme.h" #define len 0x1000 static unsigned char buf[len]; static int seq; static int test_single_nop(struct io_uring *ring) { struct io_uring_cqe *cqe; struct io_uring_sqe *sqe; int ret; sqe = io_uring_get_sqe(ring); if (!sqe) { fprintf(stderr, "get sqe failed\n"); return T_EXIT_FAIL; } io_uring_prep_nop(sqe); sqe->user_data = ++seq; ret = io_uring_submit(ring); if (ret <= 0) { fprintf(stderr, "sqe submit failed: %d\n", ret); return T_EXIT_FAIL; } ret = io_uring_wait_cqe(ring, &cqe); if (ret < 0) { fprintf(stderr, "wait completion %d\n", ret); } else if (cqe->user_data != seq) { fprintf(stderr, "Unexpected user_data: %ld\n", (long) cqe->user_data); } else { io_uring_cqe_seen(ring, cqe); return T_EXIT_PASS; } return T_EXIT_FAIL; } static int test_single_nvme_read(struct io_uring *ring, int fd) { struct nvme_uring_cmd *cmd; struct io_uring_cqe *cqe; struct io_uring_sqe *sqe; int ret; sqe = io_uring_get_sqe128(ring); if (!sqe) { fprintf(stderr, "get sqe failed\n"); return T_EXIT_FAIL; } io_uring_prep_uring_cmd128(sqe, NVME_URING_CMD_IO, fd); sqe->user_data = ++seq; cmd = (struct nvme_uring_cmd *)sqe->cmd; memset(cmd, 0, sizeof(struct nvme_uring_cmd)); cmd->opcode = nvme_cmd_read; cmd->cdw12 = (len >> lba_shift) - 1; cmd->addr = (__u64)(uintptr_t)buf; cmd->data_len = len; cmd->nsid = nsid; ret = io_uring_submit(ring); if (ret <= 0) { fprintf(stderr, "sqe submit failed: %d\n", ret); return T_EXIT_FAIL; } ret = io_uring_wait_cqe(ring, &cqe); if (ret < 0) { fprintf(stderr, "wait completion %d\n", ret); } else if (cqe->res != 0) { fprintf(stderr, "cqe res %d, wanted 0\n", cqe->res); } else if (cqe->user_data != seq) { fprintf(stderr, "Unexpected user_data: %ld\n", (long) cqe->user_data); } else { io_uring_cqe_seen(ring, cqe); return T_EXIT_PASS; } return T_EXIT_FAIL; } int main(int argc, char *argv[]) { struct io_uring ring; struct stat sb; int fd, ret, i; if (argc < 2) return T_EXIT_SKIP; ret = nvme_get_info(argv[1]); if (ret) return T_EXIT_SKIP; fd = open(argv[1], O_RDONLY); if (fd < 0) { if (errno == EACCES || errno == EPERM) return T_EXIT_SKIP; perror("file open"); return T_EXIT_FAIL; } if (fstat(fd, &sb) < 0) { perror("fstat"); ret = T_EXIT_FAIL; goto close; } if (!S_ISCHR(sb.st_mode)) { ret = T_EXIT_SKIP; goto close; } ret = io_uring_queue_init(8, &ring, IORING_SETUP_CQE_MIXED | IORING_SETUP_SQE_MIXED); if (ret) { if (ret == -EINVAL) { ret = T_EXIT_SKIP; } else { fprintf(stderr, "ring setup failed: %d\n", ret); ret = T_EXIT_FAIL; } goto close; } for (i = 0; i < 32; i++) { if (i & 1) ret = test_single_nvme_read(&ring, fd); else ret = test_single_nop(&ring); if (ret) break; } io_uring_queue_exit(&ring); close: close(fd); return ret; }