1488570ebSJim Harris /* SPDX-License-Identifier: BSD-3-Clause
2*a6dbe372Spaul luse * Copyright (C) 2017 Intel Corporation.
307fe6a43SSeth Howell * All rights reserved.
407fe6a43SSeth Howell */
507fe6a43SSeth Howell
607fe6a43SSeth Howell #include "spdk/stdinc.h"
707fe6a43SSeth Howell
807fe6a43SSeth Howell #include "spdk/bdev.h"
907fe6a43SSeth Howell #include "spdk/endian.h"
1007fe6a43SSeth Howell #include "spdk/env.h"
1107fe6a43SSeth Howell #include "spdk/thread.h"
1207fe6a43SSeth Howell #include "spdk/string.h"
1307fe6a43SSeth Howell #include "spdk/util.h"
1407fe6a43SSeth Howell #include "spdk/json.h"
1507fe6a43SSeth Howell
1607fe6a43SSeth Howell #include "spdk_internal/assert.h"
1707fe6a43SSeth Howell #include "spdk/bdev_module.h"
184e8e97c8STomasz Zawadzki #include "spdk/log.h"
1907fe6a43SSeth Howell #include "spdk_internal/virtio.h"
20e7379fc2SChangpeng Liu #include "spdk_internal/vhost_user.h"
2107fe6a43SSeth Howell
2207fe6a43SSeth Howell #include <linux/virtio_blk.h>
234c890c31SJin Yu #include <linux/virtio_ids.h>
2407fe6a43SSeth Howell
2507fe6a43SSeth Howell #include "bdev_virtio.h"
2607fe6a43SSeth Howell
2707fe6a43SSeth Howell struct virtio_blk_dev {
2807fe6a43SSeth Howell struct virtio_dev vdev;
2907fe6a43SSeth Howell struct spdk_bdev bdev;
3007fe6a43SSeth Howell bool readonly;
3107fe6a43SSeth Howell bool unmap;
3207fe6a43SSeth Howell };
3307fe6a43SSeth Howell
3407fe6a43SSeth Howell struct virtio_blk_io_ctx {
3507fe6a43SSeth Howell struct iovec iov_req;
3607fe6a43SSeth Howell struct iovec iov_resp;
3707fe6a43SSeth Howell struct iovec iov_unmap;
3807fe6a43SSeth Howell struct virtio_blk_outhdr req;
3907fe6a43SSeth Howell struct virtio_blk_discard_write_zeroes unmap;
4007fe6a43SSeth Howell uint8_t resp;
4107fe6a43SSeth Howell };
4207fe6a43SSeth Howell
4307fe6a43SSeth Howell struct bdev_virtio_blk_io_channel {
4407fe6a43SSeth Howell struct virtio_dev *vdev;
4507fe6a43SSeth Howell
4607fe6a43SSeth Howell /** Virtqueue exclusively assigned to this channel. */
4707fe6a43SSeth Howell struct virtqueue *vq;
4807fe6a43SSeth Howell
4907fe6a43SSeth Howell /** Virtio response poller. */
5007fe6a43SSeth Howell struct spdk_poller *poller;
5107fe6a43SSeth Howell };
5207fe6a43SSeth Howell
5307fe6a43SSeth Howell /* Features desired/implemented by this driver. */
5407fe6a43SSeth Howell #define VIRTIO_BLK_DEV_SUPPORTED_FEATURES \
55b924daecSJin Yu (1ULL << VIRTIO_BLK_F_SIZE_MAX | \
56b924daecSJin Yu 1ULL << VIRTIO_BLK_F_SEG_MAX | \
57b924daecSJin Yu 1ULL << VIRTIO_BLK_F_BLK_SIZE | \
5807fe6a43SSeth Howell 1ULL << VIRTIO_BLK_F_TOPOLOGY | \
5907fe6a43SSeth Howell 1ULL << VIRTIO_BLK_F_MQ | \
6007fe6a43SSeth Howell 1ULL << VIRTIO_BLK_F_RO | \
6107fe6a43SSeth Howell 1ULL << VIRTIO_BLK_F_DISCARD | \
62515d028eSChangpeng Liu 1ULL << VIRTIO_RING_F_EVENT_IDX)
6307fe6a43SSeth Howell
64ebea4dd6SJin Yu /* 10 sec for max poll period */
65ebea4dd6SJin Yu #define VIRTIO_BLK_HOTPLUG_POLL_PERIOD_MAX 10000000ULL
66ebea4dd6SJin Yu /* Default poll period is 100ms */
67ebea4dd6SJin Yu #define VIRTIO_BLK_HOTPLUG_POLL_PERIOD_DEFAULT 100000ULL
68ebea4dd6SJin Yu
69ebea4dd6SJin Yu static struct spdk_poller *g_blk_hotplug_poller = NULL;
70ebea4dd6SJin Yu static int g_blk_hotplug_fd = -1;
71ebea4dd6SJin Yu
7207fe6a43SSeth Howell static int bdev_virtio_initialize(void);
7307fe6a43SSeth Howell static int bdev_virtio_blk_get_ctx_size(void);
7407fe6a43SSeth Howell
7507fe6a43SSeth Howell static struct spdk_bdev_module virtio_blk_if = {
7607fe6a43SSeth Howell .name = "virtio_blk",
7707fe6a43SSeth Howell .module_init = bdev_virtio_initialize,
7807fe6a43SSeth Howell .get_ctx_size = bdev_virtio_blk_get_ctx_size,
7907fe6a43SSeth Howell };
8007fe6a43SSeth Howell
8107fe6a43SSeth Howell SPDK_BDEV_MODULE_REGISTER(virtio_blk, &virtio_blk_if)
8207fe6a43SSeth Howell
8307fe6a43SSeth Howell static int bdev_virtio_blk_ch_create_cb(void *io_device, void *ctx_buf);
8407fe6a43SSeth Howell static void bdev_virtio_blk_ch_destroy_cb(void *io_device, void *ctx_buf);
8507fe6a43SSeth Howell
8607fe6a43SSeth Howell static struct virtio_blk_io_ctx *
bdev_virtio_blk_init_io_vreq(struct spdk_io_channel * ch,struct spdk_bdev_io * bdev_io)8707fe6a43SSeth Howell bdev_virtio_blk_init_io_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
8807fe6a43SSeth Howell {
8907fe6a43SSeth Howell struct virtio_blk_outhdr *req;
9007fe6a43SSeth Howell uint8_t *resp;
9107fe6a43SSeth Howell struct virtio_blk_discard_write_zeroes *desc;
9207fe6a43SSeth Howell
9307fe6a43SSeth Howell struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
9407fe6a43SSeth Howell
9507fe6a43SSeth Howell req = &io_ctx->req;
9607fe6a43SSeth Howell resp = &io_ctx->resp;
9707fe6a43SSeth Howell desc = &io_ctx->unmap;
9807fe6a43SSeth Howell
9907fe6a43SSeth Howell io_ctx->iov_req.iov_base = req;
10007fe6a43SSeth Howell io_ctx->iov_req.iov_len = sizeof(*req);
10107fe6a43SSeth Howell
10207fe6a43SSeth Howell io_ctx->iov_resp.iov_base = resp;
10307fe6a43SSeth Howell io_ctx->iov_resp.iov_len = sizeof(*resp);
10407fe6a43SSeth Howell
10507fe6a43SSeth Howell io_ctx->iov_unmap.iov_base = desc;
10607fe6a43SSeth Howell io_ctx->iov_unmap.iov_len = sizeof(*desc);
10707fe6a43SSeth Howell
10807fe6a43SSeth Howell memset(req, 0, sizeof(*req));
10907fe6a43SSeth Howell return io_ctx;
11007fe6a43SSeth Howell }
11107fe6a43SSeth Howell
11207fe6a43SSeth Howell static void
bdev_virtio_blk_send_io(struct spdk_io_channel * ch,struct spdk_bdev_io * bdev_io)11307fe6a43SSeth Howell bdev_virtio_blk_send_io(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
11407fe6a43SSeth Howell {
11507fe6a43SSeth Howell struct bdev_virtio_blk_io_channel *virtio_channel = spdk_io_channel_get_ctx(ch);
11607fe6a43SSeth Howell struct virtqueue *vq = virtio_channel->vq;
11707fe6a43SSeth Howell struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
11807fe6a43SSeth Howell int rc;
11907fe6a43SSeth Howell
12007fe6a43SSeth Howell rc = virtqueue_req_start(vq, bdev_io, bdev_io->u.bdev.iovcnt + 2);
12107fe6a43SSeth Howell if (rc == -ENOMEM) {
12207fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
12307fe6a43SSeth Howell return;
12407fe6a43SSeth Howell } else if (rc != 0) {
12507fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
12607fe6a43SSeth Howell return;
12707fe6a43SSeth Howell }
12807fe6a43SSeth Howell
12907fe6a43SSeth Howell virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
13007fe6a43SSeth Howell if (bdev_io->type == SPDK_BDEV_IO_TYPE_UNMAP) {
13107fe6a43SSeth Howell virtqueue_req_add_iovs(vq, &io_ctx->iov_unmap, 1, SPDK_VIRTIO_DESC_RO);
13207fe6a43SSeth Howell } else {
13307fe6a43SSeth Howell virtqueue_req_add_iovs(vq, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
13407fe6a43SSeth Howell bdev_io->type == SPDK_BDEV_IO_TYPE_READ ?
13507fe6a43SSeth Howell SPDK_VIRTIO_DESC_WR : SPDK_VIRTIO_DESC_RO);
13607fe6a43SSeth Howell }
13707fe6a43SSeth Howell virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
13807fe6a43SSeth Howell
13907fe6a43SSeth Howell virtqueue_req_flush(vq);
14007fe6a43SSeth Howell }
14107fe6a43SSeth Howell
14207fe6a43SSeth Howell static void
bdev_virtio_command(struct spdk_io_channel * ch,struct spdk_bdev_io * bdev_io)14307fe6a43SSeth Howell bdev_virtio_command(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
14407fe6a43SSeth Howell {
14507fe6a43SSeth Howell struct virtio_blk_io_ctx *io_ctx = bdev_virtio_blk_init_io_vreq(ch, bdev_io);
14607fe6a43SSeth Howell struct virtio_blk_outhdr *req = &io_ctx->req;
14707fe6a43SSeth Howell struct virtio_blk_discard_write_zeroes *desc = &io_ctx->unmap;
14807fe6a43SSeth Howell
14907fe6a43SSeth Howell if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
15007fe6a43SSeth Howell req->type = VIRTIO_BLK_T_IN;
15107fe6a43SSeth Howell } else if (bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) {
15207fe6a43SSeth Howell req->type = VIRTIO_BLK_T_OUT;
15307fe6a43SSeth Howell } else if (bdev_io->type == SPDK_BDEV_IO_TYPE_UNMAP) {
15407fe6a43SSeth Howell req->type = VIRTIO_BLK_T_DISCARD;
15507fe6a43SSeth Howell desc->sector = bdev_io->u.bdev.offset_blocks *
15607fe6a43SSeth Howell spdk_bdev_get_block_size(bdev_io->bdev) / 512;
15707fe6a43SSeth Howell desc->num_sectors = bdev_io->u.bdev.num_blocks *
15807fe6a43SSeth Howell spdk_bdev_get_block_size(bdev_io->bdev) / 512;
15907fe6a43SSeth Howell desc->flags = 0;
16007fe6a43SSeth Howell }
16107fe6a43SSeth Howell
16207fe6a43SSeth Howell req->sector = bdev_io->u.bdev.offset_blocks *
16307fe6a43SSeth Howell spdk_bdev_get_block_size(bdev_io->bdev) / 512;
16407fe6a43SSeth Howell
16507fe6a43SSeth Howell bdev_virtio_blk_send_io(ch, bdev_io);
16607fe6a43SSeth Howell }
16707fe6a43SSeth Howell
16807fe6a43SSeth Howell static void
bdev_virtio_get_buf_cb(struct spdk_io_channel * ch,struct spdk_bdev_io * bdev_io,bool success)16907fe6a43SSeth Howell bdev_virtio_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
17007fe6a43SSeth Howell bool success)
17107fe6a43SSeth Howell {
17207fe6a43SSeth Howell if (!success) {
17307fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
17407fe6a43SSeth Howell return;
17507fe6a43SSeth Howell }
17607fe6a43SSeth Howell
17707fe6a43SSeth Howell bdev_virtio_command(ch, bdev_io);
17807fe6a43SSeth Howell }
17907fe6a43SSeth Howell
18007fe6a43SSeth Howell static int
_bdev_virtio_submit_request(struct spdk_io_channel * ch,struct spdk_bdev_io * bdev_io)18107fe6a43SSeth Howell _bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
18207fe6a43SSeth Howell {
18307fe6a43SSeth Howell struct virtio_blk_dev *bvdev = bdev_io->bdev->ctxt;
18407fe6a43SSeth Howell
18507fe6a43SSeth Howell switch (bdev_io->type) {
18607fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ:
18707fe6a43SSeth Howell spdk_bdev_io_get_buf(bdev_io, bdev_virtio_get_buf_cb,
18807fe6a43SSeth Howell bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
18907fe6a43SSeth Howell return 0;
19007fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE:
19107fe6a43SSeth Howell if (bvdev->readonly) {
19207fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
19307fe6a43SSeth Howell } else {
19407fe6a43SSeth Howell bdev_virtio_command(ch, bdev_io);
19507fe6a43SSeth Howell }
19607fe6a43SSeth Howell return 0;
19707fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_RESET:
19807fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
19907fe6a43SSeth Howell return 0;
20007fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP:
20107fe6a43SSeth Howell if (bvdev->unmap) {
20207fe6a43SSeth Howell bdev_virtio_command(ch, bdev_io);
20307fe6a43SSeth Howell } else {
20407fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
20507fe6a43SSeth Howell }
20607fe6a43SSeth Howell return 0;
20707fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_FLUSH:
20807fe6a43SSeth Howell default:
20907fe6a43SSeth Howell return -1;
21007fe6a43SSeth Howell }
21107fe6a43SSeth Howell
21207fe6a43SSeth Howell SPDK_UNREACHABLE();
21307fe6a43SSeth Howell }
21407fe6a43SSeth Howell
21507fe6a43SSeth Howell static void
bdev_virtio_submit_request(struct spdk_io_channel * ch,struct spdk_bdev_io * bdev_io)21607fe6a43SSeth Howell bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
21707fe6a43SSeth Howell {
21807fe6a43SSeth Howell if (_bdev_virtio_submit_request(ch, bdev_io) < 0) {
21907fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
22007fe6a43SSeth Howell }
22107fe6a43SSeth Howell }
22207fe6a43SSeth Howell
22307fe6a43SSeth Howell static bool
bdev_virtio_io_type_supported(void * ctx,enum spdk_bdev_io_type io_type)22407fe6a43SSeth Howell bdev_virtio_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
22507fe6a43SSeth Howell {
22607fe6a43SSeth Howell struct virtio_blk_dev *bvdev = ctx;
22707fe6a43SSeth Howell
22807fe6a43SSeth Howell switch (io_type) {
22907fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_READ:
23007fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_RESET:
23107fe6a43SSeth Howell return true;
23207fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_WRITE:
23307fe6a43SSeth Howell return !bvdev->readonly;
23407fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_UNMAP:
23507fe6a43SSeth Howell return bvdev->unmap;
23607fe6a43SSeth Howell case SPDK_BDEV_IO_TYPE_FLUSH:
23707fe6a43SSeth Howell default:
23807fe6a43SSeth Howell return false;
23907fe6a43SSeth Howell }
24007fe6a43SSeth Howell }
24107fe6a43SSeth Howell
24207fe6a43SSeth Howell static struct spdk_io_channel *
bdev_virtio_get_io_channel(void * ctx)24307fe6a43SSeth Howell bdev_virtio_get_io_channel(void *ctx)
24407fe6a43SSeth Howell {
24507fe6a43SSeth Howell struct virtio_blk_dev *bvdev = ctx;
24607fe6a43SSeth Howell
24707fe6a43SSeth Howell return spdk_get_io_channel(bvdev);
24807fe6a43SSeth Howell }
24907fe6a43SSeth Howell
25007fe6a43SSeth Howell static void
virtio_blk_dev_unregister_cb(void * io_device)25107fe6a43SSeth Howell virtio_blk_dev_unregister_cb(void *io_device)
25207fe6a43SSeth Howell {
25307fe6a43SSeth Howell struct virtio_blk_dev *bvdev = io_device;
25407fe6a43SSeth Howell struct virtio_dev *vdev = &bvdev->vdev;
25507fe6a43SSeth Howell
25607fe6a43SSeth Howell virtio_dev_stop(vdev);
25707fe6a43SSeth Howell virtio_dev_destruct(vdev);
25807fe6a43SSeth Howell spdk_bdev_destruct_done(&bvdev->bdev, 0);
25907fe6a43SSeth Howell free(bvdev);
26007fe6a43SSeth Howell }
26107fe6a43SSeth Howell
26207fe6a43SSeth Howell static int
bdev_virtio_disk_destruct(void * ctx)26307fe6a43SSeth Howell bdev_virtio_disk_destruct(void *ctx)
26407fe6a43SSeth Howell {
26507fe6a43SSeth Howell struct virtio_blk_dev *bvdev = ctx;
26607fe6a43SSeth Howell
26707fe6a43SSeth Howell spdk_io_device_unregister(bvdev, virtio_blk_dev_unregister_cb);
26807fe6a43SSeth Howell return 1;
26907fe6a43SSeth Howell }
27007fe6a43SSeth Howell
27107fe6a43SSeth Howell int
bdev_virtio_blk_dev_remove(const char * name,bdev_virtio_remove_cb cb_fn,void * cb_arg)27207fe6a43SSeth Howell bdev_virtio_blk_dev_remove(const char *name, bdev_virtio_remove_cb cb_fn, void *cb_arg)
27307fe6a43SSeth Howell {
2744573e4ccSShuhei Matsumoto return spdk_bdev_unregister_by_name(name, &virtio_blk_if, cb_fn, cb_arg);
27507fe6a43SSeth Howell }
27607fe6a43SSeth Howell
27707fe6a43SSeth Howell static int
bdev_virtio_dump_json_config(void * ctx,struct spdk_json_write_ctx * w)27807fe6a43SSeth Howell bdev_virtio_dump_json_config(void *ctx, struct spdk_json_write_ctx *w)
27907fe6a43SSeth Howell {
28007fe6a43SSeth Howell struct virtio_blk_dev *bvdev = ctx;
28107fe6a43SSeth Howell
28207fe6a43SSeth Howell virtio_dev_dump_json_info(&bvdev->vdev, w);
28307fe6a43SSeth Howell return 0;
28407fe6a43SSeth Howell }
28507fe6a43SSeth Howell
28607fe6a43SSeth Howell static void
bdev_virtio_write_config_json(struct spdk_bdev * bdev,struct spdk_json_write_ctx * w)28707fe6a43SSeth Howell bdev_virtio_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
28807fe6a43SSeth Howell {
28907fe6a43SSeth Howell struct virtio_blk_dev *bvdev = bdev->ctxt;
29007fe6a43SSeth Howell
29107fe6a43SSeth Howell spdk_json_write_object_begin(w);
29207fe6a43SSeth Howell
2932aed03f0SMaciej Wawryk spdk_json_write_named_string(w, "method", "bdev_virtio_attach_controller");
29407fe6a43SSeth Howell
29507fe6a43SSeth Howell spdk_json_write_named_object_begin(w, "params");
29607fe6a43SSeth Howell spdk_json_write_named_string(w, "name", bvdev->vdev.name);
29707fe6a43SSeth Howell spdk_json_write_named_string(w, "dev_type", "blk");
29807fe6a43SSeth Howell
29907fe6a43SSeth Howell /* Write transport specific parameters. */
30007fe6a43SSeth Howell bvdev->vdev.backend_ops->write_json_config(&bvdev->vdev, w);
30107fe6a43SSeth Howell
30207fe6a43SSeth Howell spdk_json_write_object_end(w);
30307fe6a43SSeth Howell
30407fe6a43SSeth Howell spdk_json_write_object_end(w);
30507fe6a43SSeth Howell }
30607fe6a43SSeth Howell
30707fe6a43SSeth Howell static const struct spdk_bdev_fn_table virtio_fn_table = {
30807fe6a43SSeth Howell .destruct = bdev_virtio_disk_destruct,
30907fe6a43SSeth Howell .submit_request = bdev_virtio_submit_request,
31007fe6a43SSeth Howell .io_type_supported = bdev_virtio_io_type_supported,
31107fe6a43SSeth Howell .get_io_channel = bdev_virtio_get_io_channel,
31207fe6a43SSeth Howell .dump_info_json = bdev_virtio_dump_json_config,
31307fe6a43SSeth Howell .write_config_json = bdev_virtio_write_config_json,
31407fe6a43SSeth Howell };
31507fe6a43SSeth Howell
31607fe6a43SSeth Howell static void
bdev_virtio_io_cpl(struct spdk_bdev_io * bdev_io)31707fe6a43SSeth Howell bdev_virtio_io_cpl(struct spdk_bdev_io *bdev_io)
31807fe6a43SSeth Howell {
31907fe6a43SSeth Howell struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
32007fe6a43SSeth Howell
32107fe6a43SSeth Howell spdk_bdev_io_complete(bdev_io, io_ctx->resp == VIRTIO_BLK_S_OK ?
32207fe6a43SSeth Howell SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED);
32307fe6a43SSeth Howell }
32407fe6a43SSeth Howell
32507fe6a43SSeth Howell static int
bdev_virtio_poll(void * arg)32607fe6a43SSeth Howell bdev_virtio_poll(void *arg)
32707fe6a43SSeth Howell {
32807fe6a43SSeth Howell struct bdev_virtio_blk_io_channel *ch = arg;
32907fe6a43SSeth Howell void *io[32];
33007fe6a43SSeth Howell uint32_t io_len[32];
33107fe6a43SSeth Howell uint16_t i, cnt;
33207fe6a43SSeth Howell
33307fe6a43SSeth Howell cnt = virtio_recv_pkts(ch->vq, io, io_len, SPDK_COUNTOF(io));
33407fe6a43SSeth Howell for (i = 0; i < cnt; ++i) {
33507fe6a43SSeth Howell bdev_virtio_io_cpl(io[i]);
33607fe6a43SSeth Howell }
33707fe6a43SSeth Howell
33807fe6a43SSeth Howell return cnt;
33907fe6a43SSeth Howell }
34007fe6a43SSeth Howell
34107fe6a43SSeth Howell static int
bdev_virtio_blk_ch_create_cb(void * io_device,void * ctx_buf)34207fe6a43SSeth Howell bdev_virtio_blk_ch_create_cb(void *io_device, void *ctx_buf)
34307fe6a43SSeth Howell {
34407fe6a43SSeth Howell struct virtio_blk_dev *bvdev = io_device;
34507fe6a43SSeth Howell struct virtio_dev *vdev = &bvdev->vdev;
34607fe6a43SSeth Howell struct bdev_virtio_blk_io_channel *ch = ctx_buf;
34707fe6a43SSeth Howell struct virtqueue *vq;
34807fe6a43SSeth Howell int32_t queue_idx;
34907fe6a43SSeth Howell
35007fe6a43SSeth Howell queue_idx = virtio_dev_find_and_acquire_queue(vdev, 0);
35107fe6a43SSeth Howell if (queue_idx < 0) {
35207fe6a43SSeth Howell SPDK_ERRLOG("Couldn't get an unused queue for the io_channel.\n");
35307fe6a43SSeth Howell return -1;
35407fe6a43SSeth Howell }
35507fe6a43SSeth Howell
35607fe6a43SSeth Howell vq = vdev->vqs[queue_idx];
35707fe6a43SSeth Howell
35807fe6a43SSeth Howell ch->vdev = vdev;
35907fe6a43SSeth Howell ch->vq = vq;
36007fe6a43SSeth Howell
361ab0bc5c2SShuhei Matsumoto ch->poller = SPDK_POLLER_REGISTER(bdev_virtio_poll, ch, 0);
36207fe6a43SSeth Howell return 0;
36307fe6a43SSeth Howell }
36407fe6a43SSeth Howell
36507fe6a43SSeth Howell static void
bdev_virtio_blk_ch_destroy_cb(void * io_device,void * ctx_buf)36607fe6a43SSeth Howell bdev_virtio_blk_ch_destroy_cb(void *io_device, void *ctx_buf)
36707fe6a43SSeth Howell {
36807fe6a43SSeth Howell struct virtio_blk_dev *bvdev = io_device;
36907fe6a43SSeth Howell struct virtio_dev *vdev = &bvdev->vdev;
37007fe6a43SSeth Howell struct bdev_virtio_blk_io_channel *ch = ctx_buf;
37107fe6a43SSeth Howell struct virtqueue *vq = ch->vq;
37207fe6a43SSeth Howell
37307fe6a43SSeth Howell spdk_poller_unregister(&ch->poller);
37407fe6a43SSeth Howell virtio_dev_release_queue(vdev, vq->vq_queue_index);
37507fe6a43SSeth Howell }
37607fe6a43SSeth Howell
37707fe6a43SSeth Howell static int
virtio_blk_dev_init(struct virtio_blk_dev * bvdev,uint16_t max_queues)37807fe6a43SSeth Howell virtio_blk_dev_init(struct virtio_blk_dev *bvdev, uint16_t max_queues)
37907fe6a43SSeth Howell {
38007fe6a43SSeth Howell struct virtio_dev *vdev = &bvdev->vdev;
38107fe6a43SSeth Howell struct spdk_bdev *bdev = &bvdev->bdev;
38207fe6a43SSeth Howell uint64_t capacity, num_blocks;
383da625683SJin Yu uint32_t block_size, size_max, seg_max;
38407fe6a43SSeth Howell uint16_t host_max_queues;
38507fe6a43SSeth Howell int rc;
38607fe6a43SSeth Howell
38707fe6a43SSeth Howell if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_BLK_SIZE)) {
38807fe6a43SSeth Howell rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, blk_size),
38907fe6a43SSeth Howell &block_size, sizeof(block_size));
39007fe6a43SSeth Howell if (rc) {
39107fe6a43SSeth Howell SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
39207fe6a43SSeth Howell return rc;
39307fe6a43SSeth Howell }
39407fe6a43SSeth Howell
39507fe6a43SSeth Howell if (block_size == 0 || block_size % 512 != 0) {
39607fe6a43SSeth Howell SPDK_ERRLOG("%s: invalid block size (%"PRIu32"). Must be "
39707fe6a43SSeth Howell "a multiple of 512.\n", vdev->name, block_size);
39807fe6a43SSeth Howell return -EIO;
39907fe6a43SSeth Howell }
40007fe6a43SSeth Howell } else {
40107fe6a43SSeth Howell block_size = 512;
40207fe6a43SSeth Howell }
40307fe6a43SSeth Howell
40407fe6a43SSeth Howell rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, capacity),
40507fe6a43SSeth Howell &capacity, sizeof(capacity));
40607fe6a43SSeth Howell if (rc) {
40707fe6a43SSeth Howell SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
40807fe6a43SSeth Howell return rc;
40907fe6a43SSeth Howell }
41007fe6a43SSeth Howell
41107fe6a43SSeth Howell /* `capacity` is a number of 512-byte sectors. */
41207fe6a43SSeth Howell num_blocks = capacity * 512 / block_size;
41307fe6a43SSeth Howell if (num_blocks == 0) {
41407fe6a43SSeth Howell SPDK_ERRLOG("%s: size too small (size: %"PRIu64", blocksize: %"PRIu32").\n",
41507fe6a43SSeth Howell vdev->name, capacity * 512, block_size);
41607fe6a43SSeth Howell return -EIO;
41707fe6a43SSeth Howell }
41807fe6a43SSeth Howell
41907fe6a43SSeth Howell if ((capacity * 512) % block_size != 0) {
42007fe6a43SSeth Howell SPDK_WARNLOG("%s: size has been rounded down to the nearest block size boundary. "
42107fe6a43SSeth Howell "(block size: %"PRIu32", previous size: %"PRIu64", new size: %"PRIu64")\n",
42207fe6a43SSeth Howell vdev->name, block_size, capacity * 512, num_blocks * block_size);
42307fe6a43SSeth Howell }
42407fe6a43SSeth Howell
42507fe6a43SSeth Howell if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
42607fe6a43SSeth Howell rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
42707fe6a43SSeth Howell &host_max_queues, sizeof(host_max_queues));
42807fe6a43SSeth Howell if (rc) {
42907fe6a43SSeth Howell SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
43007fe6a43SSeth Howell return rc;
43107fe6a43SSeth Howell }
43207fe6a43SSeth Howell } else {
43307fe6a43SSeth Howell host_max_queues = 1;
43407fe6a43SSeth Howell }
43507fe6a43SSeth Howell
436da625683SJin Yu if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_SIZE_MAX)) {
437da625683SJin Yu rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, size_max),
438da625683SJin Yu &size_max, sizeof(size_max));
439da625683SJin Yu if (rc) {
440da625683SJin Yu SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
441da625683SJin Yu return rc;
442da625683SJin Yu }
443da625683SJin Yu
444da625683SJin Yu if (spdk_unlikely(size_max < block_size)) {
445da625683SJin Yu SPDK_WARNLOG("%s: minimum segment size is set to block size %u forcefully.\n",
446da625683SJin Yu vdev->name, block_size);
447da625683SJin Yu size_max = block_size;
448da625683SJin Yu }
449da625683SJin Yu
450da625683SJin Yu bdev->max_segment_size = size_max;
451da625683SJin Yu }
452da625683SJin Yu
453da625683SJin Yu if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_SEG_MAX)) {
454da625683SJin Yu rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, seg_max),
455da625683SJin Yu &seg_max, sizeof(seg_max));
456da625683SJin Yu if (rc) {
457da625683SJin Yu SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
458da625683SJin Yu return rc;
459da625683SJin Yu }
460da625683SJin Yu
461da625683SJin Yu if (spdk_unlikely(seg_max == 0)) {
462da625683SJin Yu SPDK_ERRLOG("%s: virtio blk SEG_MAX can't be 0\n", vdev->name);
463da625683SJin Yu return -EINVAL;
464da625683SJin Yu }
465da625683SJin Yu
466da625683SJin Yu bdev->max_num_segments = seg_max;
467da625683SJin Yu }
468da625683SJin Yu
46907fe6a43SSeth Howell if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_RO)) {
47007fe6a43SSeth Howell bvdev->readonly = true;
47107fe6a43SSeth Howell }
47207fe6a43SSeth Howell
47307fe6a43SSeth Howell if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
47407fe6a43SSeth Howell bvdev->unmap = true;
47507fe6a43SSeth Howell }
47607fe6a43SSeth Howell
47707fe6a43SSeth Howell if (max_queues == 0) {
47807fe6a43SSeth Howell SPDK_ERRLOG("%s: requested 0 request queues (%"PRIu16" available).\n",
47907fe6a43SSeth Howell vdev->name, host_max_queues);
48007fe6a43SSeth Howell return -EINVAL;
48107fe6a43SSeth Howell }
48207fe6a43SSeth Howell
48307fe6a43SSeth Howell if (max_queues > host_max_queues) {
48407fe6a43SSeth Howell SPDK_WARNLOG("%s: requested %"PRIu16" request queues "
48507fe6a43SSeth Howell "but only %"PRIu16" available.\n",
48607fe6a43SSeth Howell vdev->name, max_queues, host_max_queues);
48707fe6a43SSeth Howell max_queues = host_max_queues;
48807fe6a43SSeth Howell }
48907fe6a43SSeth Howell
49007fe6a43SSeth Howell /* bdev is tied with the virtio device; we can reuse the name */
49107fe6a43SSeth Howell bdev->name = vdev->name;
49207fe6a43SSeth Howell rc = virtio_dev_start(vdev, max_queues, 0);
49307fe6a43SSeth Howell if (rc != 0) {
49407fe6a43SSeth Howell return rc;
49507fe6a43SSeth Howell }
49607fe6a43SSeth Howell
49707fe6a43SSeth Howell bdev->product_name = "VirtioBlk Disk";
49807fe6a43SSeth Howell bdev->write_cache = 0;
49907fe6a43SSeth Howell bdev->blocklen = block_size;
50007fe6a43SSeth Howell bdev->blockcnt = num_blocks;
50107fe6a43SSeth Howell
50207fe6a43SSeth Howell bdev->ctxt = bvdev;
50307fe6a43SSeth Howell bdev->fn_table = &virtio_fn_table;
50407fe6a43SSeth Howell bdev->module = &virtio_blk_if;
50507fe6a43SSeth Howell
50607fe6a43SSeth Howell spdk_io_device_register(bvdev, bdev_virtio_blk_ch_create_cb,
50707fe6a43SSeth Howell bdev_virtio_blk_ch_destroy_cb,
50807fe6a43SSeth Howell sizeof(struct bdev_virtio_blk_io_channel),
50907fe6a43SSeth Howell vdev->name);
51007fe6a43SSeth Howell
51107fe6a43SSeth Howell rc = spdk_bdev_register(bdev);
51207fe6a43SSeth Howell if (rc) {
51307fe6a43SSeth Howell SPDK_ERRLOG("Failed to register bdev name=%s\n", bdev->name);
51407fe6a43SSeth Howell spdk_io_device_unregister(bvdev, NULL);
51507fe6a43SSeth Howell virtio_dev_stop(vdev);
51607fe6a43SSeth Howell return rc;
51707fe6a43SSeth Howell }
51807fe6a43SSeth Howell
51907fe6a43SSeth Howell return 0;
52007fe6a43SSeth Howell }
52107fe6a43SSeth Howell
52207fe6a43SSeth Howell static struct virtio_blk_dev *
virtio_pci_blk_dev_create(const char * name,struct virtio_pci_ctx * pci_ctx)52307fe6a43SSeth Howell virtio_pci_blk_dev_create(const char *name, struct virtio_pci_ctx *pci_ctx)
52407fe6a43SSeth Howell {
52507fe6a43SSeth Howell static int pci_dev_counter = 0;
52607fe6a43SSeth Howell struct virtio_blk_dev *bvdev;
52707fe6a43SSeth Howell struct virtio_dev *vdev;
52807fe6a43SSeth Howell char *default_name = NULL;
52907fe6a43SSeth Howell uint16_t num_queues;
53007fe6a43SSeth Howell int rc;
53107fe6a43SSeth Howell
53207fe6a43SSeth Howell bvdev = calloc(1, sizeof(*bvdev));
53307fe6a43SSeth Howell if (bvdev == NULL) {
53407fe6a43SSeth Howell SPDK_ERRLOG("virtio device calloc failed\n");
53507fe6a43SSeth Howell return NULL;
53607fe6a43SSeth Howell }
53707fe6a43SSeth Howell vdev = &bvdev->vdev;
53807fe6a43SSeth Howell
53907fe6a43SSeth Howell if (name == NULL) {
54007fe6a43SSeth Howell default_name = spdk_sprintf_alloc("VirtioBlk%"PRIu32, pci_dev_counter++);
54107fe6a43SSeth Howell if (default_name == NULL) {
54207fe6a43SSeth Howell free(vdev);
54307fe6a43SSeth Howell return NULL;
54407fe6a43SSeth Howell }
54507fe6a43SSeth Howell name = default_name;
54607fe6a43SSeth Howell }
54707fe6a43SSeth Howell
54807fe6a43SSeth Howell rc = virtio_pci_dev_init(vdev, name, pci_ctx);
54907fe6a43SSeth Howell free(default_name);
55007fe6a43SSeth Howell
55107fe6a43SSeth Howell if (rc != 0) {
55207fe6a43SSeth Howell free(bvdev);
55307fe6a43SSeth Howell return NULL;
55407fe6a43SSeth Howell }
55507fe6a43SSeth Howell
55607fe6a43SSeth Howell rc = virtio_dev_reset(vdev, VIRTIO_BLK_DEV_SUPPORTED_FEATURES);
55707fe6a43SSeth Howell if (rc != 0) {
55879c7744eSJin Yu goto fail;
55907fe6a43SSeth Howell }
56007fe6a43SSeth Howell
56107fe6a43SSeth Howell /* TODO: add a way to limit usable virtqueues */
56207fe6a43SSeth Howell if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
56307fe6a43SSeth Howell rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
56407fe6a43SSeth Howell &num_queues, sizeof(num_queues));
56507fe6a43SSeth Howell if (rc) {
56607fe6a43SSeth Howell SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
56779c7744eSJin Yu goto fail;
56807fe6a43SSeth Howell }
56907fe6a43SSeth Howell } else {
57007fe6a43SSeth Howell num_queues = 1;
57107fe6a43SSeth Howell }
57207fe6a43SSeth Howell
57307fe6a43SSeth Howell rc = virtio_blk_dev_init(bvdev, num_queues);
57407fe6a43SSeth Howell if (rc != 0) {
57579c7744eSJin Yu goto fail;
57607fe6a43SSeth Howell }
57707fe6a43SSeth Howell
57807fe6a43SSeth Howell return bvdev;
57979c7744eSJin Yu
58079c7744eSJin Yu fail:
58179c7744eSJin Yu vdev->ctx = NULL;
58279c7744eSJin Yu virtio_dev_destruct(vdev);
58379c7744eSJin Yu free(bvdev);
58479c7744eSJin Yu return NULL;
58507fe6a43SSeth Howell }
58607fe6a43SSeth Howell
58707fe6a43SSeth Howell static struct virtio_blk_dev *
virtio_user_blk_dev_create(const char * name,const char * path,uint16_t num_queues,uint32_t queue_size)58807fe6a43SSeth Howell virtio_user_blk_dev_create(const char *name, const char *path,
58907fe6a43SSeth Howell uint16_t num_queues, uint32_t queue_size)
59007fe6a43SSeth Howell {
59107fe6a43SSeth Howell struct virtio_blk_dev *bvdev;
592515d028eSChangpeng Liu uint64_t feature_bits;
59307fe6a43SSeth Howell int rc;
59407fe6a43SSeth Howell
59507fe6a43SSeth Howell bvdev = calloc(1, sizeof(*bvdev));
59607fe6a43SSeth Howell if (bvdev == NULL) {
59707fe6a43SSeth Howell SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", name, path);
59807fe6a43SSeth Howell return NULL;
59907fe6a43SSeth Howell }
60007fe6a43SSeth Howell
60107fe6a43SSeth Howell rc = virtio_user_dev_init(&bvdev->vdev, name, path, queue_size);
60207fe6a43SSeth Howell if (rc != 0) {
60307fe6a43SSeth Howell SPDK_ERRLOG("Failed to create virito device %s: %s\n", name, path);
60407fe6a43SSeth Howell free(bvdev);
60507fe6a43SSeth Howell return NULL;
60607fe6a43SSeth Howell }
60707fe6a43SSeth Howell
608515d028eSChangpeng Liu feature_bits = VIRTIO_BLK_DEV_SUPPORTED_FEATURES;
609515d028eSChangpeng Liu feature_bits |= (1ULL << VHOST_USER_F_PROTOCOL_FEATURES);
610515d028eSChangpeng Liu rc = virtio_dev_reset(&bvdev->vdev, feature_bits);
61107fe6a43SSeth Howell if (rc != 0) {
61207fe6a43SSeth Howell virtio_dev_destruct(&bvdev->vdev);
61307fe6a43SSeth Howell free(bvdev);
61407fe6a43SSeth Howell return NULL;
61507fe6a43SSeth Howell }
61607fe6a43SSeth Howell
61707fe6a43SSeth Howell rc = virtio_blk_dev_init(bvdev, num_queues);
61807fe6a43SSeth Howell if (rc != 0) {
61907fe6a43SSeth Howell virtio_dev_destruct(&bvdev->vdev);
62007fe6a43SSeth Howell free(bvdev);
62107fe6a43SSeth Howell return NULL;
62207fe6a43SSeth Howell }
62307fe6a43SSeth Howell
62407fe6a43SSeth Howell return bvdev;
62507fe6a43SSeth Howell }
62607fe6a43SSeth Howell
62707fe6a43SSeth Howell struct bdev_virtio_pci_dev_create_ctx {
62807fe6a43SSeth Howell const char *name;
62907fe6a43SSeth Howell struct virtio_blk_dev *ret;
63007fe6a43SSeth Howell };
63107fe6a43SSeth Howell
63207fe6a43SSeth Howell static int
bdev_virtio_pci_blk_dev_create_cb(struct virtio_pci_ctx * pci_ctx,void * ctx)63307fe6a43SSeth Howell bdev_virtio_pci_blk_dev_create_cb(struct virtio_pci_ctx *pci_ctx, void *ctx)
63407fe6a43SSeth Howell {
63507fe6a43SSeth Howell struct bdev_virtio_pci_dev_create_ctx *create_ctx = ctx;
63607fe6a43SSeth Howell
63707fe6a43SSeth Howell create_ctx->ret = virtio_pci_blk_dev_create(create_ctx->name, pci_ctx);
63807fe6a43SSeth Howell if (create_ctx->ret == NULL) {
63907fe6a43SSeth Howell return -1;
64007fe6a43SSeth Howell }
64107fe6a43SSeth Howell
64207fe6a43SSeth Howell return 0;
64307fe6a43SSeth Howell }
64407fe6a43SSeth Howell
64507fe6a43SSeth Howell struct spdk_bdev *
bdev_virtio_pci_blk_dev_create(const char * name,struct spdk_pci_addr * pci_addr)64607fe6a43SSeth Howell bdev_virtio_pci_blk_dev_create(const char *name, struct spdk_pci_addr *pci_addr)
64707fe6a43SSeth Howell {
64807fe6a43SSeth Howell struct bdev_virtio_pci_dev_create_ctx create_ctx;
64907fe6a43SSeth Howell
65007fe6a43SSeth Howell create_ctx.name = name;
65107fe6a43SSeth Howell create_ctx.ret = NULL;
65207fe6a43SSeth Howell
65307fe6a43SSeth Howell virtio_pci_dev_attach(bdev_virtio_pci_blk_dev_create_cb, &create_ctx,
6544c890c31SJin Yu VIRTIO_ID_BLOCK, pci_addr);
65507fe6a43SSeth Howell
65607fe6a43SSeth Howell if (create_ctx.ret == NULL) {
65707fe6a43SSeth Howell return NULL;
65807fe6a43SSeth Howell }
65907fe6a43SSeth Howell
66007fe6a43SSeth Howell return &create_ctx.ret->bdev;
66107fe6a43SSeth Howell }
66207fe6a43SSeth Howell
66307fe6a43SSeth Howell static int
bdev_virtio_pci_blk_monitor(void * arg)664ebea4dd6SJin Yu bdev_virtio_pci_blk_monitor(void *arg)
665ebea4dd6SJin Yu {
666ebea4dd6SJin Yu const char *vdev_name;
667ebea4dd6SJin Yu struct bdev_virtio_pci_dev_create_ctx create_ctx;
668ebea4dd6SJin Yu
669ebea4dd6SJin Yu while ((vdev_name = virtio_pci_dev_event_process(g_blk_hotplug_fd, VIRTIO_ID_BLOCK)) != NULL) {
670ebea4dd6SJin Yu bdev_virtio_blk_dev_remove(vdev_name, NULL, NULL);
671ebea4dd6SJin Yu }
672ebea4dd6SJin Yu
673ebea4dd6SJin Yu /* Enumerate virtio pci_blk device */
674ebea4dd6SJin Yu memset(&create_ctx, 0, sizeof(create_ctx));
675ebea4dd6SJin Yu virtio_pci_dev_enumerate(bdev_virtio_pci_blk_dev_create_cb, &create_ctx,
676ebea4dd6SJin Yu VIRTIO_ID_BLOCK);
677ebea4dd6SJin Yu
678ebea4dd6SJin Yu return SPDK_POLLER_BUSY;
679ebea4dd6SJin Yu }
680ebea4dd6SJin Yu
681ebea4dd6SJin Yu int
bdev_virtio_pci_blk_set_hotplug(bool enabled,uint64_t period_us)682ebea4dd6SJin Yu bdev_virtio_pci_blk_set_hotplug(bool enabled, uint64_t period_us)
683ebea4dd6SJin Yu {
684ebea4dd6SJin Yu if (enabled == true && !spdk_process_is_primary()) {
685ebea4dd6SJin Yu return -EPERM;
686ebea4dd6SJin Yu }
687ebea4dd6SJin Yu
688ebea4dd6SJin Yu if (g_blk_hotplug_poller) {
689ebea4dd6SJin Yu close(g_blk_hotplug_fd);
690ebea4dd6SJin Yu spdk_poller_unregister(&g_blk_hotplug_poller);
691ebea4dd6SJin Yu }
692ebea4dd6SJin Yu
693ebea4dd6SJin Yu if (!enabled) {
694ebea4dd6SJin Yu return 0;
695ebea4dd6SJin Yu }
696ebea4dd6SJin Yu
697ebea4dd6SJin Yu g_blk_hotplug_fd = spdk_pci_event_listen();
698ebea4dd6SJin Yu if (g_blk_hotplug_fd < 0) {
699ebea4dd6SJin Yu return g_blk_hotplug_fd;
700ebea4dd6SJin Yu }
701ebea4dd6SJin Yu
702ebea4dd6SJin Yu period_us = period_us ? period_us : VIRTIO_BLK_HOTPLUG_POLL_PERIOD_DEFAULT;
703ebea4dd6SJin Yu period_us = spdk_min(period_us, VIRTIO_BLK_HOTPLUG_POLL_PERIOD_MAX);
704ebea4dd6SJin Yu g_blk_hotplug_poller = spdk_poller_register(bdev_virtio_pci_blk_monitor, NULL, period_us);
705ebea4dd6SJin Yu if (!g_blk_hotplug_poller) {
706ebea4dd6SJin Yu close(g_blk_hotplug_fd);
707ebea4dd6SJin Yu return -1;
708ebea4dd6SJin Yu }
709ebea4dd6SJin Yu
710ebea4dd6SJin Yu return 0;
711ebea4dd6SJin Yu }
712ebea4dd6SJin Yu
713ebea4dd6SJin Yu static int
bdev_virtio_initialize(void)71407fe6a43SSeth Howell bdev_virtio_initialize(void)
71507fe6a43SSeth Howell {
71607fe6a43SSeth Howell return 0;
71707fe6a43SSeth Howell }
71807fe6a43SSeth Howell
71907fe6a43SSeth Howell struct spdk_bdev *
bdev_virtio_user_blk_dev_create(const char * name,const char * path,unsigned num_queues,unsigned queue_size)72007fe6a43SSeth Howell bdev_virtio_user_blk_dev_create(const char *name, const char *path,
72107fe6a43SSeth Howell unsigned num_queues, unsigned queue_size)
72207fe6a43SSeth Howell {
72307fe6a43SSeth Howell struct virtio_blk_dev *bvdev;
72407fe6a43SSeth Howell
72507fe6a43SSeth Howell bvdev = virtio_user_blk_dev_create(name, path, num_queues, queue_size);
72607fe6a43SSeth Howell if (bvdev == NULL) {
72707fe6a43SSeth Howell return NULL;
72807fe6a43SSeth Howell }
72907fe6a43SSeth Howell
73007fe6a43SSeth Howell return &bvdev->bdev;
73107fe6a43SSeth Howell }
73207fe6a43SSeth Howell
733295e54d1SChangpeng Liu struct spdk_bdev *
bdev_virtio_vfio_user_blk_dev_create(const char * name,const char * path)734295e54d1SChangpeng Liu bdev_virtio_vfio_user_blk_dev_create(const char *name, const char *path)
735295e54d1SChangpeng Liu {
736295e54d1SChangpeng Liu struct virtio_blk_dev *bvdev;
737295e54d1SChangpeng Liu uint16_t num_queues = 0;
738295e54d1SChangpeng Liu int rc;
739295e54d1SChangpeng Liu
740295e54d1SChangpeng Liu bvdev = calloc(1, sizeof(*bvdev));
741295e54d1SChangpeng Liu if (bvdev == NULL) {
742295e54d1SChangpeng Liu SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", name, path);
743295e54d1SChangpeng Liu return NULL;
744295e54d1SChangpeng Liu }
745295e54d1SChangpeng Liu
746295e54d1SChangpeng Liu rc = virtio_vfio_user_dev_init(&bvdev->vdev, name, path);
747295e54d1SChangpeng Liu if (rc != 0) {
748295e54d1SChangpeng Liu SPDK_ERRLOG("Failed to create %s as virtio device\n", path);
749295e54d1SChangpeng Liu free(bvdev);
750295e54d1SChangpeng Liu return NULL;
751295e54d1SChangpeng Liu }
752295e54d1SChangpeng Liu
753295e54d1SChangpeng Liu rc = virtio_dev_reset(&bvdev->vdev, VIRTIO_BLK_DEV_SUPPORTED_FEATURES);
754295e54d1SChangpeng Liu if (rc != 0) {
755295e54d1SChangpeng Liu SPDK_ERRLOG("Failed to reset %s as virtio device\n", path);
756295e54d1SChangpeng Liu virtio_dev_destruct(&bvdev->vdev);
757295e54d1SChangpeng Liu free(bvdev);
758295e54d1SChangpeng Liu return NULL;
759295e54d1SChangpeng Liu }
760295e54d1SChangpeng Liu
761295e54d1SChangpeng Liu if (virtio_dev_has_feature(&bvdev->vdev, VIRTIO_BLK_F_MQ)) {
762295e54d1SChangpeng Liu rc = virtio_dev_read_dev_config(&bvdev->vdev, offsetof(struct virtio_blk_config, num_queues),
763295e54d1SChangpeng Liu &num_queues, sizeof(num_queues));
764295e54d1SChangpeng Liu if (rc) {
765295e54d1SChangpeng Liu SPDK_ERRLOG("%s: config read failed: %s\n", name, spdk_strerror(-rc));
766295e54d1SChangpeng Liu virtio_dev_destruct(&bvdev->vdev);
767295e54d1SChangpeng Liu free(bvdev);
768295e54d1SChangpeng Liu return NULL;
769295e54d1SChangpeng Liu }
770295e54d1SChangpeng Liu } else {
771295e54d1SChangpeng Liu num_queues = 1;
772295e54d1SChangpeng Liu }
773295e54d1SChangpeng Liu
774295e54d1SChangpeng Liu rc = virtio_blk_dev_init(bvdev, num_queues);
775295e54d1SChangpeng Liu if (rc != 0) {
776295e54d1SChangpeng Liu SPDK_ERRLOG("Failed to initialize %s as virtio device\n", path);
777295e54d1SChangpeng Liu virtio_dev_destruct(&bvdev->vdev);
778295e54d1SChangpeng Liu free(bvdev);
779295e54d1SChangpeng Liu return NULL;
780295e54d1SChangpeng Liu }
781295e54d1SChangpeng Liu
782295e54d1SChangpeng Liu return &bvdev->bdev;
783295e54d1SChangpeng Liu }
784295e54d1SChangpeng Liu
78507fe6a43SSeth Howell static int
bdev_virtio_blk_get_ctx_size(void)78607fe6a43SSeth Howell bdev_virtio_blk_get_ctx_size(void)
78707fe6a43SSeth Howell {
78807fe6a43SSeth Howell return sizeof(struct virtio_blk_io_ctx);
78907fe6a43SSeth Howell }
79007fe6a43SSeth Howell
7912172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(virtio_blk)
792