xref: /spdk/module/bdev/virtio/bdev_virtio_blk.c (revision 9889ab2dc80e40dae92dcef361d53dcba722043d)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk/bdev.h"
37 #include "spdk/conf.h"
38 #include "spdk/endian.h"
39 #include "spdk/env.h"
40 #include "spdk/thread.h"
41 #include "spdk/string.h"
42 #include "spdk/util.h"
43 #include "spdk/json.h"
44 
45 #include "spdk_internal/assert.h"
46 #include "spdk/bdev_module.h"
47 #include "spdk_internal/log.h"
48 #include "spdk_internal/virtio.h"
49 
50 #include <linux/virtio_blk.h>
51 
52 #include "bdev_virtio.h"
53 
54 struct virtio_blk_dev {
55 	struct virtio_dev		vdev;
56 	struct spdk_bdev		bdev;
57 	bool				readonly;
58 	bool				unmap;
59 };
60 
61 struct virtio_blk_io_ctx {
62 	struct iovec				iov_req;
63 	struct iovec				iov_resp;
64 	struct iovec				iov_unmap;
65 	struct virtio_blk_outhdr		req;
66 	struct virtio_blk_discard_write_zeroes	unmap;
67 	uint8_t					resp;
68 };
69 
70 struct bdev_virtio_blk_io_channel {
71 	struct virtio_dev		*vdev;
72 
73 	/** Virtqueue exclusively assigned to this channel. */
74 	struct virtqueue		*vq;
75 
76 	/** Virtio response poller. */
77 	struct spdk_poller		*poller;
78 };
79 
80 /* Features desired/implemented by this driver. */
81 #define VIRTIO_BLK_DEV_SUPPORTED_FEATURES		\
82 	(1ULL << VIRTIO_BLK_F_BLK_SIZE		|	\
83 	 1ULL << VIRTIO_BLK_F_TOPOLOGY		|	\
84 	 1ULL << VIRTIO_BLK_F_MQ		|	\
85 	 1ULL << VIRTIO_BLK_F_RO		|	\
86 	 1ULL << VIRTIO_BLK_F_DISCARD		|	\
87 	 1ULL << VIRTIO_RING_F_EVENT_IDX	|	\
88 	 1ULL << VHOST_USER_F_PROTOCOL_FEATURES)
89 
90 static int bdev_virtio_initialize(void);
91 static int bdev_virtio_blk_get_ctx_size(void);
92 
93 static struct spdk_bdev_module virtio_blk_if = {
94 	.name = "virtio_blk",
95 	.module_init = bdev_virtio_initialize,
96 	.get_ctx_size = bdev_virtio_blk_get_ctx_size,
97 };
98 
99 SPDK_BDEV_MODULE_REGISTER(virtio_blk, &virtio_blk_if)
100 
101 static int bdev_virtio_blk_ch_create_cb(void *io_device, void *ctx_buf);
102 static void bdev_virtio_blk_ch_destroy_cb(void *io_device, void *ctx_buf);
103 
104 static struct virtio_blk_io_ctx *
105 bdev_virtio_blk_init_io_vreq(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
106 {
107 	struct virtio_blk_outhdr *req;
108 	uint8_t *resp;
109 	struct virtio_blk_discard_write_zeroes *desc;
110 
111 	struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
112 
113 	req = &io_ctx->req;
114 	resp = &io_ctx->resp;
115 	desc = &io_ctx->unmap;
116 
117 	io_ctx->iov_req.iov_base = req;
118 	io_ctx->iov_req.iov_len = sizeof(*req);
119 
120 	io_ctx->iov_resp.iov_base = resp;
121 	io_ctx->iov_resp.iov_len = sizeof(*resp);
122 
123 	io_ctx->iov_unmap.iov_base = desc;
124 	io_ctx->iov_unmap.iov_len = sizeof(*desc);
125 
126 	memset(req, 0, sizeof(*req));
127 	return io_ctx;
128 }
129 
130 static void
131 bdev_virtio_blk_send_io(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
132 {
133 	struct bdev_virtio_blk_io_channel *virtio_channel = spdk_io_channel_get_ctx(ch);
134 	struct virtqueue *vq = virtio_channel->vq;
135 	struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
136 	int rc;
137 
138 	rc = virtqueue_req_start(vq, bdev_io, bdev_io->u.bdev.iovcnt + 2);
139 	if (rc == -ENOMEM) {
140 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
141 		return;
142 	} else if (rc != 0) {
143 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
144 		return;
145 	}
146 
147 	virtqueue_req_add_iovs(vq, &io_ctx->iov_req, 1, SPDK_VIRTIO_DESC_RO);
148 	if (bdev_io->type == SPDK_BDEV_IO_TYPE_UNMAP) {
149 		virtqueue_req_add_iovs(vq, &io_ctx->iov_unmap, 1, SPDK_VIRTIO_DESC_RO);
150 	} else {
151 		virtqueue_req_add_iovs(vq, bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
152 				       bdev_io->type == SPDK_BDEV_IO_TYPE_READ ?
153 				       SPDK_VIRTIO_DESC_WR : SPDK_VIRTIO_DESC_RO);
154 	}
155 	virtqueue_req_add_iovs(vq, &io_ctx->iov_resp, 1, SPDK_VIRTIO_DESC_WR);
156 
157 	virtqueue_req_flush(vq);
158 }
159 
160 static void
161 bdev_virtio_command(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
162 {
163 	struct virtio_blk_io_ctx *io_ctx = bdev_virtio_blk_init_io_vreq(ch, bdev_io);
164 	struct virtio_blk_outhdr *req = &io_ctx->req;
165 	struct virtio_blk_discard_write_zeroes *desc = &io_ctx->unmap;
166 
167 	if (bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
168 		req->type = VIRTIO_BLK_T_IN;
169 	} else if (bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) {
170 		req->type = VIRTIO_BLK_T_OUT;
171 	} else if (bdev_io->type == SPDK_BDEV_IO_TYPE_UNMAP) {
172 		req->type = VIRTIO_BLK_T_DISCARD;
173 		desc->sector = bdev_io->u.bdev.offset_blocks *
174 			       spdk_bdev_get_block_size(bdev_io->bdev) / 512;
175 		desc->num_sectors = bdev_io->u.bdev.num_blocks *
176 				    spdk_bdev_get_block_size(bdev_io->bdev) / 512;
177 		desc->flags = 0;
178 	}
179 
180 	req->sector = bdev_io->u.bdev.offset_blocks *
181 		      spdk_bdev_get_block_size(bdev_io->bdev) / 512;
182 
183 	bdev_virtio_blk_send_io(ch, bdev_io);
184 }
185 
186 static void
187 bdev_virtio_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
188 		       bool success)
189 {
190 	if (!success) {
191 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
192 		return;
193 	}
194 
195 	bdev_virtio_command(ch, bdev_io);
196 }
197 
198 static int
199 _bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
200 {
201 	struct virtio_blk_dev *bvdev = bdev_io->bdev->ctxt;
202 
203 	switch (bdev_io->type) {
204 	case SPDK_BDEV_IO_TYPE_READ:
205 		spdk_bdev_io_get_buf(bdev_io, bdev_virtio_get_buf_cb,
206 				     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
207 		return 0;
208 	case SPDK_BDEV_IO_TYPE_WRITE:
209 		if (bvdev->readonly) {
210 			spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
211 		} else {
212 			bdev_virtio_command(ch, bdev_io);
213 		}
214 		return 0;
215 	case SPDK_BDEV_IO_TYPE_RESET:
216 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
217 		return 0;
218 	case SPDK_BDEV_IO_TYPE_UNMAP:
219 		if (bvdev->unmap) {
220 			bdev_virtio_command(ch, bdev_io);
221 		} else {
222 			spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
223 		}
224 		return 0;
225 	case SPDK_BDEV_IO_TYPE_FLUSH:
226 	default:
227 		return -1;
228 	}
229 
230 	SPDK_UNREACHABLE();
231 }
232 
233 static void
234 bdev_virtio_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
235 {
236 	if (_bdev_virtio_submit_request(ch, bdev_io) < 0) {
237 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
238 	}
239 }
240 
241 static bool
242 bdev_virtio_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
243 {
244 	struct virtio_blk_dev *bvdev = ctx;
245 
246 	switch (io_type) {
247 	case SPDK_BDEV_IO_TYPE_READ:
248 	case SPDK_BDEV_IO_TYPE_RESET:
249 		return true;
250 	case SPDK_BDEV_IO_TYPE_WRITE:
251 		return !bvdev->readonly;
252 	case SPDK_BDEV_IO_TYPE_UNMAP:
253 		return bvdev->unmap;
254 	case SPDK_BDEV_IO_TYPE_FLUSH:
255 	default:
256 		return false;
257 	}
258 }
259 
260 static struct spdk_io_channel *
261 bdev_virtio_get_io_channel(void *ctx)
262 {
263 	struct virtio_blk_dev *bvdev = ctx;
264 
265 	return spdk_get_io_channel(bvdev);
266 }
267 
268 static void
269 virtio_blk_dev_unregister_cb(void *io_device)
270 {
271 	struct virtio_blk_dev *bvdev = io_device;
272 	struct virtio_dev *vdev = &bvdev->vdev;
273 
274 	virtio_dev_stop(vdev);
275 	virtio_dev_destruct(vdev);
276 	spdk_bdev_destruct_done(&bvdev->bdev, 0);
277 	free(bvdev);
278 }
279 
280 static int
281 bdev_virtio_disk_destruct(void *ctx)
282 {
283 	struct virtio_blk_dev *bvdev = ctx;
284 
285 	spdk_io_device_unregister(bvdev, virtio_blk_dev_unregister_cb);
286 	return 1;
287 }
288 
289 int
290 bdev_virtio_blk_dev_remove(const char *name, bdev_virtio_remove_cb cb_fn, void *cb_arg)
291 {
292 	struct spdk_bdev *bdev;
293 
294 	bdev = spdk_bdev_get_by_name(name);
295 	if (bdev == NULL) {
296 		return -ENODEV;
297 	}
298 
299 	if (bdev->module != &virtio_blk_if) {
300 		return -ENODEV;
301 	}
302 
303 	spdk_bdev_unregister(bdev, cb_fn, cb_arg);
304 
305 	return 0;
306 }
307 
308 static int
309 bdev_virtio_dump_json_config(void *ctx, struct spdk_json_write_ctx *w)
310 {
311 	struct virtio_blk_dev *bvdev = ctx;
312 
313 	virtio_dev_dump_json_info(&bvdev->vdev, w);
314 	return 0;
315 }
316 
317 static void
318 bdev_virtio_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
319 {
320 	struct virtio_blk_dev *bvdev = bdev->ctxt;
321 
322 	spdk_json_write_object_begin(w);
323 
324 	spdk_json_write_named_string(w, "method", "bdev_virtio_attach_controller");
325 
326 	spdk_json_write_named_object_begin(w, "params");
327 	spdk_json_write_named_string(w, "name", bvdev->vdev.name);
328 	spdk_json_write_named_string(w, "dev_type", "blk");
329 
330 	/* Write transport specific parameters. */
331 	bvdev->vdev.backend_ops->write_json_config(&bvdev->vdev, w);
332 
333 	spdk_json_write_object_end(w);
334 
335 	spdk_json_write_object_end(w);
336 }
337 
338 static const struct spdk_bdev_fn_table virtio_fn_table = {
339 	.destruct		= bdev_virtio_disk_destruct,
340 	.submit_request		= bdev_virtio_submit_request,
341 	.io_type_supported	= bdev_virtio_io_type_supported,
342 	.get_io_channel		= bdev_virtio_get_io_channel,
343 	.dump_info_json		= bdev_virtio_dump_json_config,
344 	.write_config_json	= bdev_virtio_write_config_json,
345 };
346 
347 static void
348 bdev_virtio_io_cpl(struct spdk_bdev_io *bdev_io)
349 {
350 	struct virtio_blk_io_ctx *io_ctx = (struct virtio_blk_io_ctx *)bdev_io->driver_ctx;
351 
352 	spdk_bdev_io_complete(bdev_io, io_ctx->resp == VIRTIO_BLK_S_OK ?
353 			      SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED);
354 }
355 
356 static int
357 bdev_virtio_poll(void *arg)
358 {
359 	struct bdev_virtio_blk_io_channel *ch = arg;
360 	void *io[32];
361 	uint32_t io_len[32];
362 	uint16_t i, cnt;
363 
364 	cnt = virtio_recv_pkts(ch->vq, io, io_len, SPDK_COUNTOF(io));
365 	for (i = 0; i < cnt; ++i) {
366 		bdev_virtio_io_cpl(io[i]);
367 	}
368 
369 	return cnt;
370 }
371 
372 static int
373 bdev_virtio_blk_ch_create_cb(void *io_device, void *ctx_buf)
374 {
375 	struct virtio_blk_dev *bvdev = io_device;
376 	struct virtio_dev *vdev = &bvdev->vdev;
377 	struct bdev_virtio_blk_io_channel *ch = ctx_buf;
378 	struct virtqueue *vq;
379 	int32_t queue_idx;
380 
381 	queue_idx = virtio_dev_find_and_acquire_queue(vdev, 0);
382 	if (queue_idx < 0) {
383 		SPDK_ERRLOG("Couldn't get an unused queue for the io_channel.\n");
384 		return -1;
385 	}
386 
387 	vq = vdev->vqs[queue_idx];
388 
389 	ch->vdev = vdev;
390 	ch->vq = vq;
391 
392 	ch->poller = spdk_poller_register(bdev_virtio_poll, ch, 0);
393 	return 0;
394 }
395 
396 static void
397 bdev_virtio_blk_ch_destroy_cb(void *io_device, void *ctx_buf)
398 {
399 	struct virtio_blk_dev *bvdev = io_device;
400 	struct virtio_dev *vdev = &bvdev->vdev;
401 	struct bdev_virtio_blk_io_channel *ch = ctx_buf;
402 	struct virtqueue *vq = ch->vq;
403 
404 	spdk_poller_unregister(&ch->poller);
405 	virtio_dev_release_queue(vdev, vq->vq_queue_index);
406 }
407 
408 static int
409 virtio_blk_dev_init(struct virtio_blk_dev *bvdev, uint16_t max_queues)
410 {
411 	struct virtio_dev *vdev = &bvdev->vdev;
412 	struct spdk_bdev *bdev = &bvdev->bdev;
413 	uint64_t capacity, num_blocks;
414 	uint32_t block_size;
415 	uint16_t host_max_queues;
416 	int rc;
417 
418 	if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_BLK_SIZE)) {
419 		rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, blk_size),
420 						&block_size, sizeof(block_size));
421 		if (rc) {
422 			SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
423 			return rc;
424 		}
425 
426 		if (block_size == 0 || block_size % 512 != 0) {
427 			SPDK_ERRLOG("%s: invalid block size (%"PRIu32"). Must be "
428 				    "a multiple of 512.\n", vdev->name, block_size);
429 			return -EIO;
430 		}
431 	} else {
432 		block_size = 512;
433 	}
434 
435 	rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, capacity),
436 					&capacity, sizeof(capacity));
437 	if (rc) {
438 		SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
439 		return rc;
440 	}
441 
442 	/* `capacity` is a number of 512-byte sectors. */
443 	num_blocks = capacity * 512 / block_size;
444 	if (num_blocks == 0) {
445 		SPDK_ERRLOG("%s: size too small (size: %"PRIu64", blocksize: %"PRIu32").\n",
446 			    vdev->name, capacity * 512, block_size);
447 		return -EIO;
448 	}
449 
450 	if ((capacity * 512) % block_size != 0) {
451 		SPDK_WARNLOG("%s: size has been rounded down to the nearest block size boundary. "
452 			     "(block size: %"PRIu32", previous size: %"PRIu64", new size: %"PRIu64")\n",
453 			     vdev->name, block_size, capacity * 512, num_blocks * block_size);
454 	}
455 
456 	if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
457 		rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
458 						&host_max_queues, sizeof(host_max_queues));
459 		if (rc) {
460 			SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
461 			return rc;
462 		}
463 	} else {
464 		host_max_queues = 1;
465 	}
466 
467 	if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_RO)) {
468 		bvdev->readonly = true;
469 	}
470 
471 	if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
472 		bvdev->unmap = true;
473 	}
474 
475 	if (max_queues == 0) {
476 		SPDK_ERRLOG("%s: requested 0 request queues (%"PRIu16" available).\n",
477 			    vdev->name, host_max_queues);
478 		return -EINVAL;
479 	}
480 
481 	if (max_queues > host_max_queues) {
482 		SPDK_WARNLOG("%s: requested %"PRIu16" request queues "
483 			     "but only %"PRIu16" available.\n",
484 			     vdev->name, max_queues, host_max_queues);
485 		max_queues = host_max_queues;
486 	}
487 
488 	/* bdev is tied with the virtio device; we can reuse the name */
489 	bdev->name = vdev->name;
490 	rc = virtio_dev_start(vdev, max_queues, 0);
491 	if (rc != 0) {
492 		return rc;
493 	}
494 
495 	bdev->product_name = "VirtioBlk Disk";
496 	bdev->write_cache = 0;
497 	bdev->blocklen = block_size;
498 	bdev->blockcnt = num_blocks;
499 
500 	bdev->ctxt = bvdev;
501 	bdev->fn_table = &virtio_fn_table;
502 	bdev->module = &virtio_blk_if;
503 
504 	spdk_io_device_register(bvdev, bdev_virtio_blk_ch_create_cb,
505 				bdev_virtio_blk_ch_destroy_cb,
506 				sizeof(struct bdev_virtio_blk_io_channel),
507 				vdev->name);
508 
509 	rc = spdk_bdev_register(bdev);
510 	if (rc) {
511 		SPDK_ERRLOG("Failed to register bdev name=%s\n", bdev->name);
512 		spdk_io_device_unregister(bvdev, NULL);
513 		virtio_dev_stop(vdev);
514 		return rc;
515 	}
516 
517 	return 0;
518 }
519 
520 static struct virtio_blk_dev *
521 virtio_pci_blk_dev_create(const char *name, struct virtio_pci_ctx *pci_ctx)
522 {
523 	static int pci_dev_counter = 0;
524 	struct virtio_blk_dev *bvdev;
525 	struct virtio_dev *vdev;
526 	char *default_name = NULL;
527 	uint16_t num_queues;
528 	int rc;
529 
530 	bvdev = calloc(1, sizeof(*bvdev));
531 	if (bvdev == NULL) {
532 		SPDK_ERRLOG("virtio device calloc failed\n");
533 		return NULL;
534 	}
535 	vdev = &bvdev->vdev;
536 
537 	if (name == NULL) {
538 		default_name = spdk_sprintf_alloc("VirtioBlk%"PRIu32, pci_dev_counter++);
539 		if (default_name == NULL) {
540 			free(vdev);
541 			return NULL;
542 		}
543 		name = default_name;
544 	}
545 
546 	rc = virtio_pci_dev_init(vdev, name, pci_ctx);
547 	free(default_name);
548 
549 	if (rc != 0) {
550 		free(bvdev);
551 		return NULL;
552 	}
553 
554 	rc = virtio_dev_reset(vdev, VIRTIO_BLK_DEV_SUPPORTED_FEATURES);
555 	if (rc != 0) {
556 		virtio_dev_destruct(vdev);
557 		free(bvdev);
558 		return NULL;
559 	}
560 
561 	/* TODO: add a way to limit usable virtqueues */
562 	if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
563 		rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
564 						&num_queues, sizeof(num_queues));
565 		if (rc) {
566 			SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
567 			virtio_dev_destruct(vdev);
568 			free(bvdev);
569 			return NULL;
570 		}
571 	} else {
572 		num_queues = 1;
573 	}
574 
575 	rc = virtio_blk_dev_init(bvdev, num_queues);
576 	if (rc != 0) {
577 		virtio_dev_destruct(vdev);
578 		free(bvdev);
579 		return NULL;
580 	}
581 
582 	return bvdev;
583 }
584 
585 static struct virtio_blk_dev *
586 virtio_user_blk_dev_create(const char *name, const char *path,
587 			   uint16_t num_queues, uint32_t queue_size)
588 {
589 	struct virtio_blk_dev *bvdev;
590 	int rc;
591 
592 	bvdev = calloc(1, sizeof(*bvdev));
593 	if (bvdev == NULL) {
594 		SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", name, path);
595 		return NULL;
596 	}
597 
598 	rc = virtio_user_dev_init(&bvdev->vdev, name, path, queue_size);
599 	if (rc != 0) {
600 		SPDK_ERRLOG("Failed to create virito device %s: %s\n", name, path);
601 		free(bvdev);
602 		return NULL;
603 	}
604 
605 	rc = virtio_dev_reset(&bvdev->vdev, VIRTIO_BLK_DEV_SUPPORTED_FEATURES);
606 	if (rc != 0) {
607 		virtio_dev_destruct(&bvdev->vdev);
608 		free(bvdev);
609 		return NULL;
610 	}
611 
612 	rc = virtio_blk_dev_init(bvdev, num_queues);
613 	if (rc != 0) {
614 		virtio_dev_destruct(&bvdev->vdev);
615 		free(bvdev);
616 		return NULL;
617 	}
618 
619 	return bvdev;
620 }
621 
622 struct bdev_virtio_pci_dev_create_ctx {
623 	const char *name;
624 	struct virtio_blk_dev *ret;
625 };
626 
627 static int
628 bdev_virtio_pci_blk_dev_create_cb(struct virtio_pci_ctx *pci_ctx, void *ctx)
629 {
630 	struct bdev_virtio_pci_dev_create_ctx *create_ctx = ctx;
631 
632 	create_ctx->ret = virtio_pci_blk_dev_create(create_ctx->name, pci_ctx);
633 	if (create_ctx->ret == NULL) {
634 		return -1;
635 	}
636 
637 	return 0;
638 }
639 
640 struct spdk_bdev *
641 bdev_virtio_pci_blk_dev_create(const char *name, struct spdk_pci_addr *pci_addr)
642 {
643 	struct bdev_virtio_pci_dev_create_ctx create_ctx;
644 
645 	create_ctx.name = name;
646 	create_ctx.ret = NULL;
647 
648 	virtio_pci_dev_attach(bdev_virtio_pci_blk_dev_create_cb, &create_ctx,
649 			      PCI_DEVICE_ID_VIRTIO_BLK_MODERN, pci_addr);
650 
651 	if (create_ctx.ret == NULL) {
652 		return NULL;
653 	}
654 
655 	return &create_ctx.ret->bdev;
656 }
657 
658 static int
659 virtio_pci_blk_dev_enumerate_cb(struct virtio_pci_ctx *pci_ctx, void *ctx)
660 {
661 	struct virtio_blk_dev *bvdev;
662 
663 	bvdev = virtio_pci_blk_dev_create(NULL, pci_ctx);
664 	return bvdev == NULL ? -1 : 0;
665 }
666 
667 static int
668 bdev_virtio_initialize(void)
669 {
670 	struct spdk_conf_section *sp;
671 	struct virtio_blk_dev *bvdev;
672 	char *default_name = NULL;
673 	char *path, *type, *name;
674 	unsigned vdev_num;
675 	int num_queues;
676 	bool enable_pci;
677 	int rc = 0;
678 
679 	for (sp = spdk_conf_first_section(NULL); sp != NULL; sp = spdk_conf_next_section(sp)) {
680 		if (!spdk_conf_section_match_prefix(sp, "VirtioUser")) {
681 			continue;
682 		}
683 
684 		if (sscanf(spdk_conf_section_get_name(sp), "VirtioUser%u", &vdev_num) != 1) {
685 			SPDK_ERRLOG("Section '%s' has non-numeric suffix.\n",
686 				    spdk_conf_section_get_name(sp));
687 			return -1;
688 		}
689 
690 		path = spdk_conf_section_get_val(sp, "Path");
691 		if (path == NULL) {
692 			SPDK_ERRLOG("VirtioUserBlk%u: missing Path\n", vdev_num);
693 			return -1;
694 		}
695 
696 		type = spdk_conf_section_get_val(sp, "Type");
697 		if (type == NULL || strcmp(type, "Blk") != 0) {
698 			continue;
699 		}
700 
701 		num_queues = spdk_conf_section_get_intval(sp, "Queues");
702 		if (num_queues < 1) {
703 			num_queues = 1;
704 		}
705 
706 		name = spdk_conf_section_get_val(sp, "Name");
707 		if (name == NULL) {
708 			default_name = spdk_sprintf_alloc("VirtioBlk%u", vdev_num);
709 			name = default_name;
710 		}
711 
712 		bvdev = virtio_user_blk_dev_create(name, path, num_queues, 512);
713 		free(default_name);
714 		default_name = NULL;
715 
716 		if (bvdev == NULL) {
717 			return -1;
718 		}
719 	}
720 
721 	sp = spdk_conf_find_section(NULL, "VirtioPci");
722 	if (sp == NULL) {
723 		return 0;
724 	}
725 
726 	enable_pci = spdk_conf_section_get_boolval(sp, "Enable", false);
727 	if (enable_pci) {
728 		rc = virtio_pci_dev_enumerate(virtio_pci_blk_dev_enumerate_cb, NULL,
729 					      PCI_DEVICE_ID_VIRTIO_BLK_MODERN);
730 	}
731 
732 	return rc;
733 }
734 
735 struct spdk_bdev *
736 bdev_virtio_user_blk_dev_create(const char *name, const char *path,
737 				unsigned num_queues, unsigned queue_size)
738 {
739 	struct virtio_blk_dev *bvdev;
740 
741 	bvdev = virtio_user_blk_dev_create(name, path, num_queues, queue_size);
742 	if (bvdev == NULL) {
743 		return NULL;
744 	}
745 
746 	return &bvdev->bdev;
747 }
748 
749 static int
750 bdev_virtio_blk_get_ctx_size(void)
751 {
752 	return sizeof(struct virtio_blk_io_ctx);
753 }
754 
755 SPDK_LOG_REGISTER_COMPONENT("virtio_blk", SPDK_LOG_VIRTIO_BLK)
756