|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH v3 11/14] plat/drivers: Request interface for virtio block
This patch introduces the request interface.
The following steps are:
-> find a free spot in the queue
-> set the ring request
-> notify Backend
Supported operations are: read and write.
Signed-off-by: Roxana Nicolescu <nicolescu.roxana1996@xxxxxxxxx>
---
plat/drivers/include/virtio/virtio_blk.h | 22 +++
plat/drivers/virtio/virtio_blk.c | 192 +++++++++++++++++++++++
2 files changed, 214 insertions(+)
diff --git a/plat/drivers/include/virtio/virtio_blk.h
b/plat/drivers/include/virtio/virtio_blk.h
index 4877e404..8b50d889 100644
--- a/plat/drivers/include/virtio/virtio_blk.h
+++ b/plat/drivers/include/virtio/virtio_blk.h
@@ -60,4 +60,26 @@ struct virtio_blk_config {
__u16 num_queues;
} __packed;
+/*
+ * Command types
+ */
+
+/* These two define direction. */
+#define VIRTIO_BLK_T_IN 0
+#define VIRTIO_BLK_T_OUT 1
+
+/*
+ * This comes first in the read scatter-gather list.
+ * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
+ * this is the first element of the read scatter-gather list.
+ */
+struct virtio_blk_outhdr {
+ /* VIRTIO_BLK_T* */
+ __virtio_le32 type;
+ /* io priority. */
+ __virtio_le32 ioprio;
+ /* Sector (ie. 512 byte offset) */
+ __virtio_le64 sector;
+};
+
#endif /* __PLAT_DRV_VIRTIO_BLK_H */
diff --git a/plat/drivers/virtio/virtio_blk.c b/plat/drivers/virtio/virtio_blk.c
index ecd8e691..6bdefd9c 100644
--- a/plat/drivers/virtio/virtio_blk.c
+++ b/plat/drivers/virtio/virtio_blk.c
@@ -100,6 +100,197 @@ struct uk_blkdev_queue {
struct uk_sglist_seg *sgsegs;
};
+struct virtio_blkdev_request {
+ struct uk_blkreq *req;
+ struct virtio_blk_outhdr virtio_blk_outhdr;
+ uint8_t status;
+};
+
+static int virtio_blkdev_request_set_sglist(struct uk_blkdev_queue *queue,
+ struct virtio_blkdev_request *virtio_blk_req,
+ __sector sector_size)
+{
+ struct virtio_blk_device *vbdev;
+ struct uk_blkreq *req;
+ size_t data_size = 0;
+ size_t segment_size;
+ size_t segment_max_size;
+ size_t idx;
+ uintptr_t start_data;
+ int rc = 0;
+
+ UK_ASSERT(queue);
+ UK_ASSERT(virtio_blk_req);
+
+ req = virtio_blk_req->req;
+ vbdev = queue->vbd;
+ start_data = (uintptr_t)req->aio_buf;
+ data_size = req->nb_sectors * sector_size;
+ segment_max_size = vbdev->max_size_segment;
+
+ /* Prepare the sglist */
+ uk_sglist_reset(&queue->sg);
+ rc = uk_sglist_append(&queue->sg, &virtio_blk_req->virtio_blk_outhdr,
+ sizeof(struct virtio_blk_outhdr));
+ if (unlikely(rc != 0)) {
+ uk_pr_err("Failed to append to sg list %d\n", rc);
+ goto out;
+ }
+
+ for (idx = 0; idx < data_size; idx += segment_max_size) {
+ segment_size = data_size - idx;
+ segment_size = (segment_size > segment_max_size) ?
+ segment_max_size : segment_size;
+ rc = uk_sglist_append(&queue->sg,
+ (void *)(start_data + idx),
+ segment_size);
+ if (unlikely(rc != 0)) {
+ uk_pr_err("Failed to append to sg list %d\n",
+ rc);
+ goto out;
+ }
+ }
+
+ rc = uk_sglist_append(&queue->sg, &virtio_blk_req->status,
+ sizeof(uint8_t));
+ if (unlikely(rc != 0)) {
+ uk_pr_err("Failed to append to sg list %d\n", rc);
+ goto out;
+ }
+
+out:
+ return rc;
+}
+
+static int virtio_blkdev_request_write(struct uk_blkdev_queue *queue,
+ struct virtio_blkdev_request *virtio_blk_req,
+ __u16 *read_segs, __u16 *write_segs)
+{
+ struct virtio_blk_device *vbdev;
+ struct uk_blkdev_cap *cap;
+ struct uk_blkreq *req;
+ int rc = 0;
+
+ UK_ASSERT(queue);
+ UK_ASSERT(virtio_blk_req);
+
+ vbdev = queue->vbd;
+ cap = &vbdev->blkdev.capabilities;
+ req = virtio_blk_req->req;
+ if (req->operation == UK_BLKDEV_WRITE &&
+ cap->mode == O_RDONLY)
+ return -EPERM;
+
+ if (req->aio_buf == NULL)
+ return -EINVAL;
+
+ if (req->nb_sectors == 0)
+ return -EINVAL;
+
+ if (req->start_sector + req->nb_sectors > cap->sectors)
+ return -EINVAL;
+
+ if (req->nb_sectors > cap->max_sectors_per_req)
+ return -EINVAL;
+
+ rc = virtio_blkdev_request_set_sglist(queue, virtio_blk_req,
+ cap->ssize);
+ if (rc) {
+ uk_pr_err("Failed to set sglist %d\n", rc);
+ goto out;
+ }
+
+ if (req->operation == UK_BLKDEV_WRITE) {
+ *read_segs = queue->sg.sg_nseg - 1;
+ *write_segs = 1;
+ virtio_blk_req->virtio_blk_outhdr.type = VIRTIO_BLK_T_OUT;
+ } else if (req->operation == UK_BLKDEV_READ) {
+ *read_segs = 1;
+ *write_segs = queue->sg.sg_nseg - 1;
+ virtio_blk_req->virtio_blk_outhdr.type = VIRTIO_BLK_T_IN;
+ }
+
+out:
+ return rc;
+}
+
+static int virtio_blkdev_queue_enqueue(struct uk_blkdev_queue *queue,
+ struct uk_blkreq *req)
+{
+ struct virtio_blkdev_request *virtio_blk_req;
+ __u16 write_segs = 0;
+ __u16 read_segs = 0;
+ int rc = 0;
+
+ UK_ASSERT(queue);
+ UK_ASSERT(req);
+
+ if (virtqueue_is_full(queue->vq)) {
+ uk_pr_debug("The virtqueue is full\n");
+ return -ENOSPC;
+ }
+
+ virtio_blk_req = uk_malloc(a, sizeof(*virtio_blk_req));
+ if (!virtio_blk_req)
+ return -ENOMEM;
+
+ virtio_blk_req->req = req;
+ virtio_blk_req->virtio_blk_outhdr.sector = req->start_sector;
+ if (req->operation == UK_BLKDEV_WRITE ||
+ req->operation == UK_BLKDEV_READ)
+ rc = virtio_blkdev_request_write(queue, virtio_blk_req,
+ &read_segs, &write_segs);
+ else
+ return -EINVAL;
+
+ if (rc)
+ goto out;
+
+ rc = virtqueue_buffer_enqueue(queue->vq, virtio_blk_req, &queue->sg,
+ read_segs, write_segs);
+
+out:
+ return rc;
+}
+
+static int virtio_blkdev_submit_request(struct uk_blkdev *dev,
+ struct uk_blkdev_queue *queue,
+ struct uk_blkreq *req)
+{
+ int rc = 0;
+ int status = 0x0;
+
+ UK_ASSERT(req);
+ UK_ASSERT(queue);
+ UK_ASSERT(dev);
+
+ rc = virtio_blkdev_queue_enqueue(queue, req);
+ if (likely(rc >= 0)) {
+ uk_pr_debug("Success and more descriptors available\n");
+ status |= UK_BLKDEV_STATUS_SUCCESS;
+ /**
+ * Notify the host the new buffer.
+ */
+ virtqueue_host_notify(queue->vq);
+ /**
+ * When there is further space available in the ring
+ * return UK_BLKDEV_STATUS_MORE.
+ */
+ status |= likely(rc > 0) ? UK_BLKDEV_STATUS_MORE : 0x0;
+ } else if (rc == -ENOSPC) {
+ uk_pr_debug("No more descriptors available\n");
+ goto err;
+ } else {
+ uk_pr_err("Failed to enqueue descriptors into the ring: %d\n",
+ rc);
+ goto err;
+ }
+
+ return status;
+
+err:
+ return rc;
+}
static int virtio_blkdev_recv_done(struct virtqueue *vq, void *priv)
{
@@ -572,6 +763,7 @@ static int virtio_blk_add_dev(struct virtio_dev *vdev)
return -ENOMEM;
vbdev->vdev = vdev;
+ vbdev->blkdev.submit_one = virtio_blkdev_submit_request;
vbdev->blkdev.dev_ops = &virtio_blkdev_ops;
rc = uk_blkdev_drv_register(&vbdev->blkdev, a, drv_name);
--
2.17.1
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |