Commit 8b260d5c authored by Changpeng Liu's avatar Changpeng Liu Committed by Tomasz Zawadzki
Browse files

virtio/vfio_user: add virtio_scsi device support



Example usage using `bdevperf` as the client:

Start `spdk_tgt` with created virtio_scsi device:
1. scripts/rpc.py bdev_malloc_create -b malloc0 $((512)) 512
2. scripts/rpc.py vfu_virtio_create_scsi_endpoint vfu.0 --cpumask 0x1 --num-io-queues=4 \
                                                  --qsize=128 --packed-ring
3. scripts/rpc.py vfu_virtio_scsi_add_target vfu.0 --scsi-target-num=0 --bdev-name malloc0

Start `bdevperf`:
1. test/bdev/bdevperf/bdevperf -r /var/tmp/spdk.sock.1 -g -s 2048 -q 128 -o 4096 \
                               -w randread -t 30 -m 0x2
2. scripts/rpc.py -s /var/tmp/spdk.sock.1 bdev_virtio_attach_controller --dev-type scsi \
                  --trtype vfio-user --traddr vfu.0 VirtioScsi0
3. test/bdev/bdevperf/bdevperf.py -s /var/tmp/spdk.sock.1 perform_tests

Change-Id: Id95908a5243e9a224a9bd709a22b87740c50b835
Signed-off-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13897


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
parent 295e54d1
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -53,6 +53,27 @@ int bdev_virtio_user_scsi_dev_create(const char *name, const char *path,
				     unsigned num_queues, unsigned queue_size,
				     bdev_virtio_create_cb cb_fn, void *cb_arg);

/**
 * Connect to a vfio-user Unix domain socket and create a Virtio SCSI device.
 * If the connection is successful, the device will be automatically scanned.
 * The scan consists of probing the targets on the device and will result in
 * creating possibly multiple Virtio SCSI bdevs - one for each target. Currently
 * only one LUN per target is detected - LUN0. Note that the bdev creation is
 * run asynchronously in the background. After it's finished, the `cb_fn`
 * callback is called.
 *
 * \param name name for the virtio device. It will be inherited by all created
 * bdevs, which are named in the following format: <name>t<target_id>
 * \param path path to the socket
 * \param cb_fn function to be called after scanning all targets on the virtio
 * device. It's optional, can be NULL. See \c bdev_virtio_create_cb.
 * \param cb_arg argument for the `cb_fn`
 * \return zero on success (device scan is started) or negative error code.
 * In case of error the \c cb_fn is not called.
 */
int bdev_vfio_user_scsi_dev_create(const char *base_name, const char *path,
				   bdev_virtio_create_cb cb_fn, void *cb_arg);

/**
 * Attach virtio-pci device. This creates a Virtio SCSI device with the same
 * capabilities as the vhost-user equivalent. The device will be automatically
+4 −2
Original line number Diff line number Diff line
@@ -186,7 +186,7 @@ rpc_bdev_virtio_attach_controller(struct spdk_jsonrpc_request *request,
	struct rpc_bdev_virtio_attach_controller_ctx *req;
	struct spdk_bdev *bdev = NULL;
	struct spdk_pci_addr pci_addr;
	int rc;
	int rc = 0;

	req = calloc(1, sizeof(*req));
	if (!req) {
@@ -248,9 +248,11 @@ rpc_bdev_virtio_attach_controller(struct spdk_jsonrpc_request *request,
	} else if (strcmp(req->dev_type, "scsi") == 0) {
		if (strcmp(req->trtype, "pci") == 0) {
			rc = bdev_virtio_pci_scsi_dev_create(req->name, &pci_addr, rpc_create_virtio_dev_cb, req);
		} else {
		} else if (strcmp(req->trtype, "user") == 0) {
			rc = bdev_virtio_user_scsi_dev_create(req->name, req->traddr, req->vq_count, req->vq_size,
							      rpc_create_virtio_dev_cb, req);
		} else if (strcmp(req->trtype, "vfio-user") == 0) {
			rc = bdev_vfio_user_scsi_dev_create(req->name, req->traddr, rpc_create_virtio_dev_cb, req);
		}

		if (rc < 0) {
+52 −0
Original line number Diff line number Diff line
@@ -1806,6 +1806,58 @@ bdev_virtio_user_scsi_dev_create(const char *base_name, const char *path,
	return rc;
}

int
bdev_vfio_user_scsi_dev_create(const char *base_name, const char *path,
			       bdev_virtio_create_cb cb_fn, void *cb_arg)
{
	struct virtio_scsi_dev *svdev;
	uint32_t num_queues = 0;
	int rc;

	svdev = calloc(1, sizeof(*svdev));
	if (svdev == NULL) {
		SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", base_name, path);
		return -ENOMEM;
	}

	rc = virtio_vfio_user_dev_init(&svdev->vdev, base_name, path);
	if (rc != 0) {
		SPDK_ERRLOG("Failed to create %s as virtio device\n", path);
		free(svdev);
		return -EFAULT;
	}

	rc = virtio_dev_read_dev_config(&svdev->vdev, offsetof(struct virtio_scsi_config, num_queues),
					&num_queues, sizeof(num_queues));
	if (rc) {
		SPDK_ERRLOG("%s: config read failed: %s\n", base_name, spdk_strerror(-rc));
		virtio_dev_destruct(&svdev->vdev);
		free(svdev);
		return rc;
	}

	if (num_queues < SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED) {
		SPDK_ERRLOG("%s: invalid num_queues %u\n", base_name, num_queues);
		virtio_dev_destruct(&svdev->vdev);
		free(svdev);
		return -EINVAL;
	}

	rc = virtio_scsi_dev_init(svdev, num_queues, VIRTIO_SCSI_DEV_SUPPORTED_FEATURES);
	if (rc != 0) {
		virtio_dev_destruct(&svdev->vdev);
		free(svdev);
		return -EFAULT;
	}

	rc = virtio_scsi_dev_scan(svdev, cb_fn, cb_arg);
	if (rc) {
		virtio_scsi_dev_remove(svdev, NULL, NULL);
	}

	return rc;
}

struct bdev_virtio_pci_dev_create_ctx {
	const char *name;
	bdev_virtio_create_cb cb_fn;