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: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13897
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
This commit is contained in:
Changpeng Liu 2022-07-21 16:36:41 +08:00 committed by Tomasz Zawadzki
parent 295e54d144
commit 8b260d5c92
3 changed files with 77 additions and 2 deletions

View File

@ -53,6 +53,27 @@ int bdev_virtio_user_scsi_dev_create(const char *name, const char *path,
unsigned num_queues, unsigned queue_size, unsigned num_queues, unsigned queue_size,
bdev_virtio_create_cb cb_fn, void *cb_arg); 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 * Attach virtio-pci device. This creates a Virtio SCSI device with the same
* capabilities as the vhost-user equivalent. The device will be automatically * capabilities as the vhost-user equivalent. The device will be automatically

View File

@ -186,7 +186,7 @@ rpc_bdev_virtio_attach_controller(struct spdk_jsonrpc_request *request,
struct rpc_bdev_virtio_attach_controller_ctx *req; struct rpc_bdev_virtio_attach_controller_ctx *req;
struct spdk_bdev *bdev = NULL; struct spdk_bdev *bdev = NULL;
struct spdk_pci_addr pci_addr; struct spdk_pci_addr pci_addr;
int rc; int rc = 0;
req = calloc(1, sizeof(*req)); req = calloc(1, sizeof(*req));
if (!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) { } else if (strcmp(req->dev_type, "scsi") == 0) {
if (strcmp(req->trtype, "pci") == 0) { if (strcmp(req->trtype, "pci") == 0) {
rc = bdev_virtio_pci_scsi_dev_create(req->name, &pci_addr, rpc_create_virtio_dev_cb, req); 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, rc = bdev_virtio_user_scsi_dev_create(req->name, req->traddr, req->vq_count, req->vq_size,
rpc_create_virtio_dev_cb, req); 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) { if (rc < 0) {

View File

@ -1806,6 +1806,58 @@ bdev_virtio_user_scsi_dev_create(const char *base_name, const char *path,
return rc; 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 { struct bdev_virtio_pci_dev_create_ctx {
const char *name; const char *name;
bdev_virtio_create_cb cb_fn; bdev_virtio_create_cb cb_fn;