2017-05-30 21:13:50 +00:00
|
|
|
/*-
|
|
|
|
* BSD LICENSE
|
|
|
|
*
|
|
|
|
* Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2017-11-03 13:53:10 +00:00
|
|
|
#ifndef SPDK_VIRTIO_H
|
|
|
|
#define SPDK_VIRTIO_H
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-10-18 17:14:30 +00:00
|
|
|
#include "spdk/stdinc.h"
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-10-14 09:57:03 +00:00
|
|
|
#include <linux/virtio_ring.h>
|
2017-11-02 14:20:25 +00:00
|
|
|
#include <linux/virtio_pci.h>
|
|
|
|
#include <linux/virtio_config.h>
|
2017-10-14 09:57:03 +00:00
|
|
|
|
2017-10-14 10:43:58 +00:00
|
|
|
#include "spdk_internal/log.h"
|
2017-10-14 09:57:03 +00:00
|
|
|
#include "spdk/likely.h"
|
2017-10-18 17:14:30 +00:00
|
|
|
#include "spdk/queue.h"
|
2017-11-02 14:20:25 +00:00
|
|
|
#include "spdk/json.h"
|
2017-11-23 19:15:23 +00:00
|
|
|
#include "spdk/io_channel.h"
|
2017-10-14 09:57:03 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The maximum virtqueue size is 2^15. Use that value as the end of
|
|
|
|
* descriptor chain terminator since it will never be a valid index
|
|
|
|
* in the descriptor table. This is used to verify we are correctly
|
|
|
|
* handling vq_free_cnt.
|
|
|
|
*/
|
|
|
|
#define VQ_RING_DESC_CHAIN_END 32768
|
|
|
|
|
2017-11-02 14:20:25 +00:00
|
|
|
/* Number of non-request queues - eventq and controlq */
|
|
|
|
#define SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED 2
|
|
|
|
|
|
|
|
/* Extra status define for readability */
|
|
|
|
#define VIRTIO_CONFIG_S_RESET 0
|
|
|
|
|
2017-11-03 14:41:31 +00:00
|
|
|
struct virtio_dev_ops;
|
2017-11-15 12:25:38 +00:00
|
|
|
|
2017-09-01 17:33:53 +00:00
|
|
|
struct virtio_dev {
|
|
|
|
struct virtqueue **vqs;
|
2017-10-03 18:23:37 +00:00
|
|
|
|
|
|
|
/** Name of this virtio dev set by backend */
|
|
|
|
char *name;
|
2017-09-01 17:33:53 +00:00
|
|
|
uint16_t started;
|
2017-09-29 08:37:09 +00:00
|
|
|
|
|
|
|
/** Max number of queues the host supports. */
|
|
|
|
uint16_t max_queues;
|
|
|
|
|
2017-10-10 15:50:20 +00:00
|
|
|
/** Common device & guest features. */
|
2017-10-05 12:46:24 +00:00
|
|
|
uint64_t negotiated_features;
|
|
|
|
|
2017-09-01 17:33:53 +00:00
|
|
|
int is_hw;
|
2017-09-04 13:54:42 +00:00
|
|
|
|
|
|
|
/** Modern/legacy virtio device flag. */
|
2017-09-01 17:33:53 +00:00
|
|
|
uint8_t modern;
|
2017-09-25 18:41:05 +00:00
|
|
|
|
2017-10-10 18:44:35 +00:00
|
|
|
/** Mutex for asynchronous virtqueue-changing operations. */
|
|
|
|
pthread_mutex_t mutex;
|
|
|
|
|
2017-11-02 14:04:21 +00:00
|
|
|
/** Backend-specific callbacks. */
|
2017-11-03 14:41:31 +00:00
|
|
|
const struct virtio_dev_ops *backend_ops;
|
2017-11-02 14:04:21 +00:00
|
|
|
|
2017-11-15 12:25:38 +00:00
|
|
|
/** Context for the backend ops */
|
|
|
|
void *ctx;
|
|
|
|
|
2017-09-25 18:41:05 +00:00
|
|
|
TAILQ_ENTRY(virtio_dev) tailq;
|
2017-09-01 17:33:53 +00:00
|
|
|
};
|
|
|
|
|
2017-11-03 14:41:31 +00:00
|
|
|
struct virtio_dev_ops {
|
2017-11-02 14:20:25 +00:00
|
|
|
void (*read_dev_cfg)(struct virtio_dev *hw, size_t offset,
|
|
|
|
void *dst, int len);
|
|
|
|
void (*write_dev_cfg)(struct virtio_dev *hw, size_t offset,
|
|
|
|
const void *src, int len);
|
|
|
|
uint8_t (*get_status)(struct virtio_dev *hw);
|
|
|
|
void (*set_status)(struct virtio_dev *hw, uint8_t status);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get device features. The features might be already
|
|
|
|
* negotiated with driver (guest) features.
|
|
|
|
*/
|
|
|
|
uint64_t (*get_features)(struct virtio_dev *vdev);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Negotiate and set device features.
|
|
|
|
* The negotiation can fail with return code -1.
|
|
|
|
* This function should also set vdev->negotiated_features field.
|
|
|
|
*/
|
|
|
|
int (*set_features)(struct virtio_dev *vdev, uint64_t features);
|
|
|
|
|
|
|
|
/** Deinit and free virtio device */
|
|
|
|
void (*free_vdev)(struct virtio_dev *vdev);
|
|
|
|
|
|
|
|
uint16_t (*get_queue_num)(struct virtio_dev *hw, uint16_t queue_id);
|
|
|
|
int (*setup_queue)(struct virtio_dev *hw, struct virtqueue *vq);
|
|
|
|
void (*del_queue)(struct virtio_dev *hw, struct virtqueue *vq);
|
|
|
|
void (*notify_queue)(struct virtio_dev *hw, struct virtqueue *vq);
|
|
|
|
|
|
|
|
void (*dump_json_config)(struct virtio_dev *hw, struct spdk_json_write_ctx *w);
|
|
|
|
};
|
|
|
|
|
2017-10-14 09:57:03 +00:00
|
|
|
struct vq_desc_extra {
|
|
|
|
void *cookie;
|
|
|
|
uint16_t ndescs;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct virtqueue {
|
|
|
|
struct virtio_dev *vdev; /**< owner of this virtqueue */
|
|
|
|
struct vring vq_ring; /**< vring keeping desc, used and avail */
|
|
|
|
/**
|
|
|
|
* Last consumed descriptor in the used table,
|
|
|
|
* trails vq_ring.used->idx.
|
|
|
|
*/
|
|
|
|
uint16_t vq_used_cons_idx;
|
|
|
|
uint16_t vq_nentries; /**< vring desc numbers */
|
|
|
|
uint16_t vq_free_cnt; /**< num of desc available */
|
|
|
|
uint16_t vq_avail_idx; /**< sync until needed */
|
|
|
|
|
|
|
|
void *vq_ring_virt_mem; /**< virtual address of vring */
|
|
|
|
unsigned int vq_ring_size;
|
|
|
|
|
2017-11-03 16:37:51 +00:00
|
|
|
uint64_t vq_ring_mem; /**< physical address of vring */
|
2017-10-14 09:57:03 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Head of the free chain in the descriptor table. If
|
|
|
|
* there are no free descriptors, this will be set to
|
|
|
|
* VQ_RING_DESC_CHAIN_END.
|
|
|
|
*/
|
|
|
|
uint16_t vq_desc_head_idx;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Tail of the free chain in desc table. If
|
|
|
|
* there are no free descriptors, this will be set to
|
|
|
|
* VQ_RING_DESC_CHAIN_END.
|
|
|
|
*/
|
|
|
|
uint16_t vq_desc_tail_idx;
|
|
|
|
uint16_t vq_queue_index; /**< PCI queue index */
|
|
|
|
uint16_t *notify_addr;
|
|
|
|
|
2017-11-23 19:15:23 +00:00
|
|
|
/** Thread that's polling this queue. */
|
|
|
|
struct spdk_thread *owner_thread;
|
2017-10-10 18:44:35 +00:00
|
|
|
|
|
|
|
/** Response poller. */
|
2017-11-17 21:49:36 +00:00
|
|
|
struct spdk_poller *poller;
|
2017-10-10 18:44:35 +00:00
|
|
|
|
2017-10-11 11:45:53 +00:00
|
|
|
/** Context for response poller. */
|
|
|
|
void *poller_ctx;
|
|
|
|
|
2017-10-14 09:57:03 +00:00
|
|
|
struct vq_desc_extra vq_descx[0];
|
|
|
|
};
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
struct virtio_req {
|
|
|
|
struct iovec *iov;
|
2017-08-23 09:43:25 +00:00
|
|
|
struct iovec iov_req;
|
|
|
|
struct iovec iov_resp;
|
2017-05-30 21:13:50 +00:00
|
|
|
uint32_t iovcnt;
|
2017-08-23 09:43:25 +00:00
|
|
|
int is_write;
|
2017-05-30 21:13:50 +00:00
|
|
|
uint32_t data_transferred;
|
|
|
|
};
|
|
|
|
|
2017-11-02 14:20:25 +00:00
|
|
|
struct virtio_driver {
|
|
|
|
TAILQ_HEAD(, virtio_dev) init_ctrlrs;
|
|
|
|
TAILQ_HEAD(, virtio_dev) attached_ctrlrs;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern struct virtio_driver g_virtio_driver;
|
|
|
|
|
2017-05-30 21:13:50 +00:00
|
|
|
/* Features desired/implemented by this driver. */
|
2017-09-04 12:29:06 +00:00
|
|
|
#define VIRTIO_SCSI_DEV_SUPPORTED_FEATURES \
|
|
|
|
(1ULL << VIRTIO_SCSI_F_INOUT | \
|
2017-10-04 09:52:26 +00:00
|
|
|
1ULL << VIRTIO_F_VERSION_1)
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-08-21 13:42:00 +00:00
|
|
|
uint16_t virtio_recv_pkts(struct virtqueue *vq, struct virtio_req **reqs,
|
2017-10-18 17:06:51 +00:00
|
|
|
uint16_t nb_pkts);
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-10-17 12:25:17 +00:00
|
|
|
/**
|
|
|
|
* Put given request into the virtqueue. The virtio device owning
|
|
|
|
* the virtqueue must be started. This will also send an interrupt unless
|
|
|
|
* the host explicitly set VRING_USED_F_NO_NOTIFY in virtqueue flags.
|
|
|
|
*
|
|
|
|
* \param vq virtio queue
|
|
|
|
* \param req virtio request
|
|
|
|
* \return 0 on success, negative errno on error. In case the ring is full
|
|
|
|
* or no free descriptors are available -ENOMEM is returned. If virtio
|
|
|
|
* device owning the virtqueue is not started -EIO is returned.
|
|
|
|
*/
|
|
|
|
int virtio_xmit_pkt(struct virtqueue *vq, struct virtio_req *req);
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-11-15 12:25:38 +00:00
|
|
|
/**
|
|
|
|
* Construct virtio device. This will set vdev->id field.
|
|
|
|
* The device has to be freed with \c virtio_dev_free.
|
|
|
|
*
|
|
|
|
* \param ops backend callbacks
|
|
|
|
* \param ctx argument for the backend callbacks
|
|
|
|
*/
|
2017-11-03 14:41:31 +00:00
|
|
|
struct virtio_dev *virtio_dev_construct(const struct virtio_dev_ops *ops, void *ctx);
|
2017-11-15 12:25:38 +00:00
|
|
|
|
2017-09-29 11:03:45 +00:00
|
|
|
int virtio_dev_init(struct virtio_dev *hw, uint64_t req_features);
|
|
|
|
void virtio_dev_free(struct virtio_dev *dev);
|
2017-09-01 17:33:53 +00:00
|
|
|
int virtio_dev_start(struct virtio_dev *hw);
|
2017-05-30 21:13:50 +00:00
|
|
|
|
2017-10-10 18:44:35 +00:00
|
|
|
/**
|
2017-11-23 19:15:23 +00:00
|
|
|
* Bind a virtqueue with given index to the current thread;
|
2017-10-10 18:44:35 +00:00
|
|
|
*
|
|
|
|
* This function is thread-safe.
|
|
|
|
*
|
|
|
|
* \param vdev vhost device
|
|
|
|
* \param index virtqueue index
|
|
|
|
* \return 0 on success, -1 in case a virtqueue with given index either
|
|
|
|
* does not exists or is already acquired.
|
|
|
|
*/
|
|
|
|
int virtio_dev_acquire_queue(struct virtio_dev *vdev, uint16_t index);
|
|
|
|
|
|
|
|
/**
|
2017-11-23 19:15:23 +00:00
|
|
|
* Look for unused queue and bind it to the current thread. This will
|
2017-10-10 18:44:35 +00:00
|
|
|
* scan the queues in range from *start_index* (inclusive) up to
|
|
|
|
* vdev->max_queues (exclusive).
|
|
|
|
*
|
|
|
|
* This function is thread-safe.
|
|
|
|
*
|
|
|
|
* \param vdev vhost device
|
|
|
|
* \param start_index virtqueue index to start looking from
|
|
|
|
* \return index of acquired queue or -1 in case no unused queue in given range
|
|
|
|
* has been found
|
|
|
|
*/
|
|
|
|
int32_t virtio_dev_find_and_acquire_queue(struct virtio_dev *vdev, uint16_t start_index);
|
|
|
|
|
2017-11-23 19:34:44 +00:00
|
|
|
/**
|
|
|
|
* Get thread that acquired given virtqueue.
|
|
|
|
*
|
|
|
|
* This function is thread-safe.
|
|
|
|
*
|
|
|
|
* \param vdev vhost device
|
|
|
|
* \param index index of virtqueue
|
|
|
|
* \return thread that acquired given virtqueue. If the queue is unused
|
|
|
|
* or doesn't exist a NULL is returned.
|
|
|
|
*/
|
|
|
|
struct spdk_thread *virtio_dev_queue_get_thread(struct virtio_dev *vdev, uint16_t index);
|
|
|
|
|
2017-10-11 11:45:53 +00:00
|
|
|
/**
|
|
|
|
* Check if virtqueue with given index is acquired.
|
|
|
|
*
|
|
|
|
* This function is thread-safe.
|
|
|
|
*
|
|
|
|
* \param vdev vhost device
|
|
|
|
* \param index index of virtqueue
|
|
|
|
* \return virtqueue acquire status. in case of invalid index *false* is returned.
|
|
|
|
*/
|
|
|
|
bool virtio_dev_queue_is_acquired(struct virtio_dev *vdev, uint16_t index);
|
|
|
|
|
2017-10-10 18:44:35 +00:00
|
|
|
/**
|
|
|
|
* Release previously acquired queue.
|
|
|
|
*
|
|
|
|
* This function must be called from the thread that acquired the queue.
|
|
|
|
*
|
|
|
|
* \param vdev vhost device
|
|
|
|
* \param index index of virtqueue to release
|
|
|
|
*/
|
|
|
|
void virtio_dev_release_queue(struct virtio_dev *vdev, uint16_t index);
|
|
|
|
|
2017-11-02 16:10:56 +00:00
|
|
|
/**
|
|
|
|
* Reset given virtio device. This will leave the device in unusable state.
|
|
|
|
* To reuse the device, call \c virtio_dev_init.
|
|
|
|
*
|
|
|
|
* \param vdev virtio device
|
|
|
|
*/
|
|
|
|
void virtio_dev_reset(struct virtio_dev *vdev);
|
2017-11-02 14:20:25 +00:00
|
|
|
|
2017-11-02 16:10:56 +00:00
|
|
|
/**
|
|
|
|
* Get Virtio status flags.
|
|
|
|
*
|
|
|
|
* \param vdev virtio device
|
|
|
|
*/
|
|
|
|
uint8_t virtio_dev_get_status(struct virtio_dev *vdev);
|
2017-11-02 14:20:25 +00:00
|
|
|
|
2017-11-02 16:10:56 +00:00
|
|
|
/**
|
|
|
|
* Set Virtio status flag. The flags have to be set in very specific order
|
|
|
|
* defined the VirtIO 1.0 spec section 3.1.1. To unset the flags, call
|
|
|
|
* \c virtio_dev_reset or set \c VIRTIO_CONFIG_S_RESET flag. There is
|
|
|
|
* no way to unset particular flags.
|
|
|
|
*
|
|
|
|
* \param vdev virtio device
|
|
|
|
* \param flag flag to set
|
|
|
|
*/
|
|
|
|
void virtio_dev_set_status(struct virtio_dev *vdev, uint8_t flag);
|
2017-11-02 14:20:25 +00:00
|
|
|
|
2017-11-02 16:10:56 +00:00
|
|
|
/**
|
|
|
|
* Write raw data into the device config at given offset. This call does not
|
|
|
|
* provide any error checking.
|
|
|
|
*
|
|
|
|
* \param vdev virtio device
|
|
|
|
* \param offset offset in bytes
|
|
|
|
* \param src pointer to data to copy from
|
|
|
|
* \param len length of data to copy in bytes
|
|
|
|
*/
|
|
|
|
void virtio_dev_write_dev_config(struct virtio_dev *vdev, size_t offset, const void *src, int len);
|
2017-11-02 14:20:25 +00:00
|
|
|
|
2017-11-02 16:10:56 +00:00
|
|
|
/**
|
|
|
|
* Read raw data from the device config at given offset. This call does not
|
|
|
|
* provide any error checking.
|
|
|
|
*
|
|
|
|
* \param vdev virtio device
|
|
|
|
* \param offset offset in bytes
|
|
|
|
* \param dst pointer to buffer to copy data into
|
|
|
|
* \param len length of data to copy in bytes
|
|
|
|
*/
|
|
|
|
void virtio_dev_read_dev_config(struct virtio_dev *vdev, size_t offset, void *dst, int len);
|
2017-11-02 14:20:25 +00:00
|
|
|
|
2017-11-02 16:10:56 +00:00
|
|
|
/**
|
|
|
|
* Get backend-specific ops for given device.
|
|
|
|
*
|
|
|
|
* \param vdev virtio device
|
|
|
|
*/
|
2017-11-03 14:41:31 +00:00
|
|
|
const struct virtio_dev_ops *virtio_dev_backend_ops(struct virtio_dev *vdev);
|
2017-11-02 14:20:25 +00:00
|
|
|
|
2017-11-02 16:10:56 +00:00
|
|
|
/**
|
|
|
|
* Check if the device has negotiated given feature bit.
|
|
|
|
*
|
|
|
|
* \param vdev virtio device
|
|
|
|
* \param bit feature bit
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
virtio_dev_has_feature(struct virtio_dev *vdev, uint64_t bit)
|
2017-11-02 14:20:25 +00:00
|
|
|
{
|
2017-11-02 16:10:56 +00:00
|
|
|
return !!(vdev->negotiated_features & (1ULL << bit));
|
2017-11-02 14:20:25 +00:00
|
|
|
}
|
|
|
|
|
2017-11-02 16:10:56 +00:00
|
|
|
/**
|
|
|
|
* Dump all device specific information into given json stream.
|
|
|
|
*
|
|
|
|
* \param vdev virtio device
|
|
|
|
* \param w json stream
|
|
|
|
*/
|
|
|
|
void virtio_dev_dump_json_config(struct virtio_dev *vdev, struct spdk_json_write_ctx *w);
|
2017-11-02 14:20:25 +00:00
|
|
|
|
2017-11-02 14:31:11 +00:00
|
|
|
/**
|
|
|
|
* Init all compatible Virtio PCI devices.
|
|
|
|
*/
|
|
|
|
int virtio_enumerate_pci(void);
|
|
|
|
|
2017-11-03 12:22:50 +00:00
|
|
|
/**
|
|
|
|
* Connect to a vhost-user device and create corresponding virtio_dev.
|
|
|
|
*
|
|
|
|
* \param name name of this virtio device
|
|
|
|
* \param path path to the Unix domain socket of the vhost-user device
|
|
|
|
* \param requested_queues maximum number of request queues that this
|
|
|
|
* device will support
|
|
|
|
* \param queue_size size of each of the queues
|
|
|
|
* \param fixed_queue_num number of queues preceeding the first
|
|
|
|
* request queue. For Virtio-SCSI this is equal to 2, as there are
|
|
|
|
* additional event and control queues.
|
|
|
|
* \return virtio device
|
|
|
|
*/
|
|
|
|
struct virtio_dev *virtio_user_dev_init(const char *name, const char *path,
|
|
|
|
uint16_t requested_queues,
|
|
|
|
uint32_t queue_size, uint16_t fixed_queue_num);
|
|
|
|
|
2017-11-03 13:53:10 +00:00
|
|
|
#endif /* SPDK_VIRTIO_H */
|