From 54e16f96b34b7a4d2cac935fcde164b7462d7014 Mon Sep 17 00:00:00 2001 From: Edward Yang Date: Sat, 13 May 2017 13:12:13 -0700 Subject: [PATCH] bdev: Add spdk_bdev_nvme_admin_passthru Support passthru for NVMe admin commands. Change-Id: If926f2ecabb078a553158f544c10a92452dbdb39 Signed-off-by: Edward Yang Reviewed-on: https://review.gerrithub.io/363294 Reviewed-by: Daniel Verkamp Tested-by: SPDK Automated Test System Reviewed-by: Ben Walker --- include/spdk/bdev.h | 7 +++++ include/spdk_internal/bdev.h | 10 ++++++ lib/bdev/bdev.c | 32 +++++++++++++++++++ lib/bdev/nvme/blockdev_nvme.c | 59 +++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+) diff --git a/include/spdk/bdev.h b/include/spdk/bdev.h index 5d7e044fcd..a2934e7381 100644 --- a/include/spdk/bdev.h +++ b/include/spdk/bdev.h @@ -43,6 +43,7 @@ #include "spdk/event.h" #include "spdk/scsi_spec.h" +#include "spdk/nvme_spec.h" #define SPDK_BDEV_SMALL_BUF_MAX_SIZE 8192 #define SPDK_BDEV_LARGE_BUF_MAX_SIZE (64 * 1024) @@ -82,6 +83,7 @@ enum spdk_bdev_io_type { SPDK_BDEV_IO_TYPE_UNMAP, SPDK_BDEV_IO_TYPE_FLUSH, SPDK_BDEV_IO_TYPE_RESET, + SPDK_BDEV_IO_TYPE_NVME_ADMIN, }; /** @@ -223,6 +225,11 @@ struct spdk_bdev_io *spdk_bdev_flush(struct spdk_bdev *bdev, struct spdk_io_chan spdk_bdev_io_completion_cb cb, void *cb_arg); void spdk_bdev_get_io_stat(struct spdk_bdev *bdev, struct spdk_io_channel *ch, struct spdk_bdev_io_stat *stat); +struct spdk_bdev_io *spdk_bdev_nvme_admin_passthru(struct spdk_bdev *bdev, + struct spdk_io_channel *ch, + const struct spdk_nvme_cmd *cmd, + void *buf, size_t nbytes, + spdk_bdev_io_completion_cb cb, void *cb_arg); int spdk_bdev_free_io(struct spdk_bdev_io *bdev_io); int spdk_bdev_reset(struct spdk_bdev *bdev, struct spdk_io_channel *ch, spdk_bdev_io_completion_cb cb, void *cb_arg); diff --git a/include/spdk_internal/bdev.h b/include/spdk_internal/bdev.h index 02df247686..395b750e1d 100644 --- a/include/spdk_internal/bdev.h +++ b/include/spdk_internal/bdev.h @@ -285,6 +285,16 @@ struct spdk_bdev_io { /** Represents the number of bytes to be flushed, starting at offset. */ uint64_t length; } flush; + struct { + /* The NVMe command to execute */ + struct spdk_nvme_cmd cmd; + + /* The data buffer to transfer */ + void *buf; + + /* The number of bytes to transfer */ + size_t nbytes; + } nvme_passthru; } u; /** Status for the IO */ diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c index 8cc7d285a5..291059fd93 100644 --- a/lib/bdev/bdev.c +++ b/lib/bdev/bdev.c @@ -964,6 +964,38 @@ spdk_bdev_get_io_stat(struct spdk_bdev *bdev, struct spdk_io_channel *ch, memset(&channel->stat, 0, sizeof(channel->stat)); } +struct spdk_bdev_io * +spdk_bdev_nvme_admin_passthru(struct spdk_bdev *bdev, struct spdk_io_channel *ch, + const struct spdk_nvme_cmd *cmd, void *buf, size_t nbytes, + spdk_bdev_io_completion_cb cb, void *cb_arg) +{ + struct spdk_bdev_io *bdev_io; + struct spdk_bdev_channel *channel = spdk_io_channel_get_ctx(ch); + int rc; + + bdev_io = spdk_bdev_get_io(); + if (!bdev_io) { + SPDK_ERRLOG("bdev_io memory allocation failed during nvme_admin_passthru\n"); + return NULL; + } + + bdev_io->ch = channel; + bdev_io->type = SPDK_BDEV_IO_TYPE_NVME_ADMIN; + bdev_io->u.nvme_passthru.cmd = *cmd; + bdev_io->u.nvme_passthru.buf = buf; + bdev_io->u.nvme_passthru.nbytes = nbytes; + + spdk_bdev_io_init(bdev_io, bdev, cb_arg, cb); + + rc = spdk_bdev_io_submit(bdev_io); + if (rc < 0) { + spdk_bdev_put_io(bdev_io); + return NULL; + } + + return bdev_io; +} + int spdk_bdev_free_io(struct spdk_bdev_io *bdev_io) { diff --git a/lib/bdev/nvme/blockdev_nvme.c b/lib/bdev/nvme/blockdev_nvme.c index 9a194b4609..a78babf86e 100644 --- a/lib/bdev/nvme/blockdev_nvme.c +++ b/lib/bdev/nvme/blockdev_nvme.c @@ -92,6 +92,12 @@ struct nvme_bdev_io { /** Offset in current iovec. */ uint32_t iov_offset; + + /** Saved status for admin passthru completion event. */ + struct spdk_nvme_cpl cpl; + + /** Event pointer for admin passthru completion. */ + struct spdk_event *admin_passthru_completion_event; }; enum data_direction { @@ -131,6 +137,8 @@ static int bdev_nvme_queue_cmd(struct nvme_bdev *bdev, struct spdk_nvme_qpair *q struct nvme_bdev_io *bio, int direction, struct iovec *iov, int iovcnt, uint64_t nbytes, uint64_t offset); +static int bdev_nvme_admin_passthru(struct nvme_bdev *nbdev, struct nvme_bdev_io *bio, + struct spdk_nvme_cmd *cmd, void *buf, size_t nbytes); static int bdev_nvme_get_ctx_size(void) @@ -296,6 +304,13 @@ _bdev_nvme_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_ bdev_io->u.flush.offset, bdev_io->u.flush.length); + case SPDK_BDEV_IO_TYPE_NVME_ADMIN: + return bdev_nvme_admin_passthru((struct nvme_bdev *)bdev_io->bdev->ctxt, + (struct nvme_bdev_io *)bdev_io->driver_ctx, + &bdev_io->u.nvme_passthru.cmd, + bdev_io->u.nvme_passthru.buf, + bdev_io->u.nvme_passthru.nbytes); + default: return -EINVAL; } @@ -321,6 +336,7 @@ bdev_nvme_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) case SPDK_BDEV_IO_TYPE_WRITE: case SPDK_BDEV_IO_TYPE_RESET: case SPDK_BDEV_IO_TYPE_FLUSH: + case SPDK_BDEV_IO_TYPE_NVME_ADMIN: return true; case SPDK_BDEV_IO_TYPE_UNMAP: @@ -962,6 +978,25 @@ bdev_nvme_queued_done(void *ref, const struct spdk_nvme_cpl *cpl) spdk_bdev_io_complete_nvme_status(bdev_io, cpl->status.sct, cpl->status.sc); } +static void +bdev_nvme_admin_passthru_completion(void *arg1, void *arg2) +{ + struct spdk_bdev_io *bdev_io = arg1; + struct nvme_bdev_io *bio = arg2; + + spdk_bdev_io_complete_nvme_status(bdev_io, + bio->cpl.status.sct, bio->cpl.status.sc); +} + +static void +bdev_nvme_admin_passthru_done(void *ref, const struct spdk_nvme_cpl *cpl) +{ + struct nvme_bdev_io *bio = ref; + + bio->cpl = *cpl; + spdk_event_call(bio->admin_passthru_completion_event); +} + static void bdev_nvme_queued_reset_sgl(void *ref, uint32_t sgl_offset) { @@ -1075,6 +1110,30 @@ bdev_nvme_unmap(struct nvme_bdev *nbdev, struct spdk_io_channel *ch, return rc; } +static int +bdev_nvme_admin_passthru(struct nvme_bdev *nbdev, struct nvme_bdev_io *bio, + struct spdk_nvme_cmd *cmd, void *buf, size_t nbytes) +{ + struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(bio); + + if (nbytes > UINT32_MAX) { + SPDK_ERRLOG("nbytes is greater than UINT32_MAX.\n"); + return -EINVAL; + } + + bio->admin_passthru_completion_event = + spdk_event_allocate(spdk_env_get_current_core(), bdev_nvme_admin_passthru_completion, + bdev_io, bio); + + if (bio->admin_passthru_completion_event == NULL) { + SPDK_ERRLOG("memory allocation for bio->admin_passthru_completion_event failed.\n"); + return -ENOMEM; + } + + return spdk_nvme_ctrlr_cmd_admin_raw(nbdev->nvme_ctrlr->ctrlr, cmd, buf, + (uint32_t)nbytes, bdev_nvme_admin_passthru_done, bio); +} + static void bdev_nvme_get_spdk_running_config(FILE *fp) {