diff --git a/lib/bdev/virtio/bdev_virtio.c b/lib/bdev/virtio/bdev_virtio.c index f1fe1fdfa..0ab2fe307 100644 --- a/lib/bdev/virtio/bdev_virtio.c +++ b/lib/bdev/virtio/bdev_virtio.c @@ -57,6 +57,9 @@ #define CTRLQ_RING_SIZE 16 #define SCAN_REQUEST_RETRIES 5 +/* Number of non-request queues - eventq and controlq */ +#define SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED 2 + #define VIRTIO_SCSI_CONTROLQ 0 #define VIRTIO_SCSI_EVENTQ 1 #define VIRTIO_SCSI_REQUESTQ 2 @@ -123,6 +126,42 @@ struct bdev_virtio_io_channel { struct virtqueue *vq; }; +static int +virtio_pci_scsi_dev_create_cb(struct virtio_pci_ctx *pci_ctx) +{ + static int pci_dev_counter = 0; + struct virtio_dev *vdev; + char *name; + uint32_t num_queues; + int rc; + + vdev = calloc(1, sizeof(*vdev)); + if (vdev == NULL) { + SPDK_ERRLOG("virtio device calloc failed\n"); + return -1; + } + + name = spdk_sprintf_alloc("VirtioScsi%"PRIu32, ++pci_dev_counter); + if (name == NULL) { + free(vdev); + return -1; + } + + rc = virtio_pci_dev_init(vdev, name, pci_ctx); + free(name); + + if (rc != 0) { + free(vdev); + return -1; + } + + virtio_dev_read_dev_config(vdev, offsetof(struct virtio_scsi_config, num_queues), + &num_queues, sizeof(num_queues)); + vdev->max_queues = SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED + num_queues; + + return 0; +} + static int scan_target(struct virtio_scsi_scan_base *base); static int @@ -1179,7 +1218,7 @@ bdev_virtio_process_config(void) enable_pci = spdk_conf_section_get_boolval(sp, "Enable", false); if (enable_pci) { - rc = virtio_enumerate_pci(); + rc = virtio_pci_scsi_dev_enumerate(virtio_pci_scsi_dev_create_cb); } out: diff --git a/lib/bdev/virtio/rte_virtio/virtio.h b/lib/bdev/virtio/rte_virtio/virtio.h index 32f3836ec..2cbc21180 100644 --- a/lib/bdev/virtio/rte_virtio/virtio.h +++ b/lib/bdev/virtio/rte_virtio/virtio.h @@ -54,8 +54,7 @@ */ #define VQ_RING_DESC_CHAIN_END 32768 -/* Number of non-request queues - eventq and controlq */ -#define SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED 2 +#define SPDK_VIRTIO_MAX_VIRTQUEUES 0x100 /* Extra status define for readability */ #define VIRTIO_CONFIG_S_RESET 0 @@ -189,6 +188,16 @@ struct virtio_driver { extern struct virtio_driver g_virtio_driver; +/** Context for creating PCI virtio_devs */ +struct virtio_pci_ctx; + +/** + * Callback for creating virtio_dev from a PCI device. + * The first param is the PCI context to be associated with virtio_dev. + * \return 0 on success, -1 on error. + */ +typedef int (*virtio_pci_create_cb)(struct virtio_pci_ctx *pci_ctx); + /* Features desired/implemented by this driver. */ #define VIRTIO_SCSI_DEV_SUPPORTED_FEATURES \ (1ULL << VIRTIO_SCSI_F_INOUT | \ @@ -374,9 +383,14 @@ virtio_dev_has_feature(struct virtio_dev *vdev, uint64_t bit) void virtio_dev_dump_json_config(struct virtio_dev *vdev, struct spdk_json_write_ctx *w); /** - * Init all compatible Virtio PCI devices. + * Enumerate all PCI Virtio devices on the system. + * + * \param enum_cb a function to be called for each valid PCI device. + * \return if a virtio_dev is has been created, the callback should return 0. + * Returning any other value will cause the PCI context to be freed, + * making it unusable. */ -int virtio_enumerate_pci(void); +int virtio_pci_scsi_dev_enumerate(virtio_pci_create_cb enum_cb); /** * Connect to a vhost-user device and init corresponding virtio_dev struct. @@ -397,4 +411,19 @@ int virtio_user_dev_init(struct virtio_dev *vdev, const char *name, const char * uint16_t requested_queues, uint32_t queue_size, uint16_t fixed_queue_num); +/** + * Initialize a virtio_dev for the given PCI device. + * The virtio_dev will try to use \c SPDK_VIRTIO_MAX_VIRTQUEUES queues by + * default and might fail to start. It is advised to overwrite the + * `virtio_dev->max_queues` field manually starting the device. + * The virtio_dev has to be freed with \c virtio_dev_destruct. + * + * \param vdev preallocated vhost device struct to operate on + * \param name name of this virtio device + * \param pci_ctx context of the PCI device + * \return 0 on success, -1 on error. + */ +int virtio_pci_dev_init(struct virtio_dev *vdev, const char *name, + struct virtio_pci_ctx *pci_ctx); + #endif /* SPDK_VIRTIO_H */ diff --git a/lib/bdev/virtio/rte_virtio/virtio_pci.c b/lib/bdev/virtio/rte_virtio/virtio_pci.c index 10e60dee8..a1c9b8493 100644 --- a/lib/bdev/virtio/rte_virtio/virtio_pci.c +++ b/lib/bdev/virtio/rte_virtio/virtio_pci.c @@ -33,11 +33,10 @@ #include "spdk/stdinc.h" -#include - #include "spdk/mmio.h" #include "spdk/string.h" #include "spdk/env.h" +#include "spdk/pci_ids.h" #include "virtio.h" @@ -57,7 +56,9 @@ struct virtio_hw { struct virtio_pci_common_cfg *common_cfg; struct spdk_pci_device *pci_dev; - struct virtio_scsi_config *dev_cfg; + + /** Device-specific PCI config space */ + void *dev_cfg; }; /* @@ -69,8 +70,6 @@ struct virtio_hw { #define PCI_CAP_ID_VNDR 0x09 #define PCI_CAP_ID_MSIX 0x11 -static int g_dev_counter = 0; - static inline int check_vq_phys_addr_ok(struct virtqueue *vq) { @@ -414,27 +413,9 @@ next: } static int -virtio_dev_pci_init(struct virtio_dev *vdev) -{ - int vdev_id = ++g_dev_counter; - - vdev->name = spdk_sprintf_alloc("VirtioScsi%"PRIu32, vdev_id); - if (!vdev->name) { - return -1; - } - - virtio_dev_read_dev_config(vdev, offsetof(struct virtio_scsi_config, num_queues), - &vdev->max_queues, sizeof(vdev->max_queues)); - vdev->max_queues += SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED; - TAILQ_INSERT_TAIL(&g_virtio_driver.init_ctrlrs, vdev, tailq); - return 0; -} - -static int -pci_enum_virtio_probe_cb(void *ctx, struct spdk_pci_device *pci_dev) +virtio_pci_dev_probe(struct spdk_pci_device *pci_dev, virtio_pci_create_cb enum_cb) { struct virtio_hw *hw; - struct virtio_dev *vdev; uint8_t *bar_vaddr; uint64_t bar_paddr, bar_len; int rc; @@ -470,43 +451,63 @@ pci_enum_virtio_probe_cb(void *ctx, struct spdk_pci_device *pci_dev) return -1; } - vdev = calloc(1, sizeof(*vdev)); - if (vdev == NULL) { - SPDK_ERRLOG("calloc failed\n"); - free_virtio_hw(hw); - return -1; - } - - rc = virtio_dev_construct(vdev, &modern_ops, hw); + rc = enum_cb((struct virtio_pci_ctx *)hw); if (rc != 0) { - free(vdev); free_virtio_hw(hw); - return -1; - } - vdev->is_hw = 1; - vdev->modern = 1; - - rc = virtio_dev_pci_init(vdev); - if (rc != 0) { - goto err; } - return 0; + return rc; +} -err: - virtio_dev_destruct(vdev); - return -1; +static int +virtio_pci_scsi_dev_probe_cb(void *ctx, struct spdk_pci_device *pci_dev) +{ + virtio_pci_create_cb enum_cb = ctx; + uint16_t pci_device_id = spdk_pci_device_get_device_id(pci_dev); + + if (pci_device_id != PCI_DEVICE_ID_VIRTIO_SCSI_MODERN) { + return 1; + } + + return virtio_pci_dev_probe(pci_dev, enum_cb); } int -virtio_enumerate_pci(void) +virtio_pci_scsi_dev_enumerate(virtio_pci_create_cb enum_cb) { if (!spdk_process_is_primary()) { SPDK_WARNLOG("virtio_pci secondary process support is not implemented yet.\n"); return 0; } - return spdk_pci_virtio_enumerate(pci_enum_virtio_probe_cb, NULL); + return spdk_pci_virtio_enumerate(virtio_pci_scsi_dev_probe_cb, enum_cb); +} + +int +virtio_pci_dev_init(struct virtio_dev *vdev, const char *name, + struct virtio_pci_ctx *pci_ctx) +{ + int rc; + char *name_dup; + + name_dup = strdup(name); + if (name_dup == NULL) { + return -1; + } + + rc = virtio_dev_construct(vdev, &modern_ops, pci_ctx); + if (rc != 0) { + free(name_dup); + return -1; + } + + vdev->name = name_dup; + vdev->is_hw = 1; + vdev->modern = 1; + vdev->max_queues = SPDK_VIRTIO_MAX_VIRTQUEUES; + + TAILQ_INSERT_TAIL(&g_virtio_driver.init_ctrlrs, vdev, tailq); + return 0; } SPDK_LOG_REGISTER_TRACE_FLAG("virtio_pci", SPDK_TRACE_VIRTIO_PCI) diff --git a/lib/bdev/virtio/rte_virtio/virtio_user.c b/lib/bdev/virtio/rte_virtio/virtio_user.c index 5ec3af646..3ab9436b7 100644 --- a/lib/bdev/virtio/rte_virtio/virtio_user.c +++ b/lib/bdev/virtio/rte_virtio/virtio_user.c @@ -165,7 +165,7 @@ virtio_user_dev_setup(struct virtio_dev *vdev) dev->vhostfd = -1; - for (i = 0; i < VIRTIO_MAX_VIRTQUEUES; ++i) { + for (i = 0; i < SPDK_VIRTIO_MAX_VIRTQUEUES; ++i) { dev->callfds[i] = -1; dev->kickfds[i] = -1; } diff --git a/lib/bdev/virtio/rte_virtio/virtio_user/vhost.h b/lib/bdev/virtio/rte_virtio/virtio_user/vhost.h index 93e3c8928..0a9c5865a 100644 --- a/lib/bdev/virtio/rte_virtio/virtio_user/vhost.h +++ b/lib/bdev/virtio/rte_virtio/virtio_user/vhost.h @@ -42,8 +42,6 @@ #include "../virtio.h" -#define VIRTIO_MAX_VIRTQUEUES 0x100 - enum vhost_user_request { VHOST_USER_NONE = 0, VHOST_USER_GET_FEATURES = 1, @@ -74,13 +72,13 @@ struct virtio_user_dev { int vhostfd; /* for both vhost_user and vhost_kernel */ - int callfds[VIRTIO_MAX_VIRTQUEUES]; - int kickfds[VIRTIO_MAX_VIRTQUEUES]; + int callfds[SPDK_VIRTIO_MAX_VIRTQUEUES]; + int kickfds[SPDK_VIRTIO_MAX_VIRTQUEUES]; uint32_t queue_size; uint8_t status; char path[PATH_MAX]; - struct vring vrings[VIRTIO_MAX_VIRTQUEUES]; + struct vring vrings[SPDK_VIRTIO_MAX_VIRTQUEUES]; struct virtio_user_backend_ops *ops; };