These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / SLOF / lib / libvirtio / virtio-blk.c
index 826f2ea..07ec104 100644 (file)
 #include <stdio.h>
 #include <cpu.h>
 #include <helpers.h>
+#include <byteorder.h>
 #include "virtio.h"
 #include "virtio-blk.h"
+#include "virtio-internal.h"
 
 #define DEFAULT_SECTOR_SIZE 512
+#define DRIVER_FEATURE_SUPPORT  (VIRTIO_BLK_F_BLK_SIZE | VIRTIO_F_VERSION_1)
+
+static struct vqs vq;
 
 /**
  * Initialize virtio-block device.
@@ -27,39 +32,54 @@ virtioblk_init(struct virtio_device *dev)
 {
        struct vring_avail *vq_avail;
        int blk_size = DEFAULT_SECTOR_SIZE;
-       int features;
+       uint64_t features;
+       int status = VIRTIO_STAT_ACKNOWLEDGE;
 
        /* Reset device */
-       // XXX That will clear the virtq base. We need to move
-       //     initializing it to here anyway
-       //
-       //       virtio_reset_device(dev);
+       virtio_reset_device(dev);
 
        /* Acknowledge device. */
-       virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+       virtio_set_status(dev, status);
 
        /* Tell HV that we know how to drive the device. */
-       virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
+       status |= VIRTIO_STAT_DRIVER;
+       virtio_set_status(dev, status);
+
+       if (dev->is_modern) {
+               /* Negotiate features and sets FEATURES_OK if successful */
+               if (virtio_negotiate_guest_features(dev, DRIVER_FEATURE_SUPPORT))
+                       goto dev_error;
+
+               virtio_get_status(dev, &status);
+       } else {
+               /* Device specific setup - we support F_BLK_SIZE */
+               virtio_set_guest_features(dev,  VIRTIO_BLK_F_BLK_SIZE);
+       }
 
-       /* Device specific setup - we support F_BLK_SIZE */
-       virtio_set_guest_features(dev,  VIRTIO_BLK_F_BLK_SIZE);
+       if (virtio_queue_init_vq(dev, &vq, 0))
+               goto dev_error;
 
        vq_avail = virtio_get_vring_avail(dev, 0);
-       vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
+       vq_avail->flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
        vq_avail->idx = 0;
 
        /* Tell HV that setup succeeded */
-       virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
-                               |VIRTIO_STAT_DRIVER_OK);
+       status |= VIRTIO_STAT_DRIVER_OK;
+       virtio_set_status(dev, status);
 
-       virtio_get_host_features(dev, &features);
+       features = virtio_get_host_features(dev);
        if (features & VIRTIO_BLK_F_BLK_SIZE) {
                blk_size = virtio_get_config(dev,
-                               offset_of(struct virtio_blk_cfg, blk_size),
-                               sizeof(blk_size));
+                                            offset_of(struct virtio_blk_cfg, blk_size),
+                                            sizeof(blk_size));
        }
 
        return blk_size;
+dev_error:
+       printf("%s: failed\n", __func__);
+       status |= VIRTIO_STAT_FAILED;
+       virtio_set_status(dev, status);
+       return 0;
 }
 
 
@@ -77,6 +97,19 @@ virtioblk_shutdown(struct virtio_device *dev)
        virtio_reset_device(dev);
 }
 
+static void fill_blk_hdr(struct virtio_blk_req *blkhdr, bool is_modern,
+                         uint32_t type, uint32_t ioprio, uint32_t sector)
+{
+       if (is_modern) {
+               blkhdr->type = cpu_to_le32(type);
+               blkhdr->ioprio = cpu_to_le32(ioprio);
+               blkhdr->sector = cpu_to_le64(sector);
+       } else {
+               blkhdr->type = type;
+               blkhdr->ioprio = ioprio;
+               blkhdr->sector = sector;
+       }
+}
 
 /**
  * Read blocks
@@ -87,7 +120,7 @@ virtioblk_shutdown(struct virtio_device *dev)
  * @return number of blocks that have been read successfully
  */
 int
-virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
+virtioblk_read(struct virtio_device *dev, char *buf, uint64_t blocknum, long cnt)
 {
        struct vring_desc *desc;
        int id;
@@ -100,7 +133,7 @@ virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
        struct vring_used *vq_used;             /* "Used" vring */
        volatile uint8_t status = -1;
        volatile uint16_t *current_used_idx;
-       uint16_t last_used_idx;
+       uint16_t last_used_idx, avail_idx;
        int blk_size = DEFAULT_SECTOR_SIZE;
 
        //printf("virtioblk_read: dev=%p buf=%p blocknum=%li count=%li\n",
@@ -128,41 +161,38 @@ virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
        vq_avail = virtio_get_vring_avail(dev, 0);
        vq_used = virtio_get_vring_used(dev, 0);
 
+       avail_idx = virtio_modern16_to_cpu(dev, vq_avail->idx);
+
        last_used_idx = vq_used->idx;
        current_used_idx = &vq_used->idx;
 
        /* Set up header */
-       blkhdr.type = VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER;
-       blkhdr.ioprio = 1;
-       blkhdr.sector = blocknum * blk_size / DEFAULT_SECTOR_SIZE;
+       fill_blk_hdr(&blkhdr, dev->is_modern, VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER,
+                    1, blocknum * blk_size / DEFAULT_SECTOR_SIZE);
 
        /* Determine descriptor index */
-       id = (vq_avail->idx * 3) % vq_size;
+       id = (avail_idx * 3) % vq_size;
 
        /* Set up virtqueue descriptor for header */
        desc = &vq_desc[id];
-       desc->addr = (uint64_t)&blkhdr;
-       desc->len = sizeof(struct virtio_blk_req);
-       desc->flags = VRING_DESC_F_NEXT;
-       desc->next = (id + 1) % vq_size;
+       virtio_fill_desc(desc, dev->is_modern, (uint64_t)&blkhdr,
+                        sizeof(struct virtio_blk_req),
+                        VRING_DESC_F_NEXT, (id + 1) % vq_size);
 
        /* Set up virtqueue descriptor for data */
        desc = &vq_desc[(id + 1) % vq_size];
-       desc->addr = (uint64_t)buf;
-       desc->len = cnt * blk_size;
-       desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
-       desc->next = (id + 2) % vq_size;
+       virtio_fill_desc(desc, dev->is_modern, (uint64_t)buf, cnt * blk_size,
+                        VRING_DESC_F_NEXT | VRING_DESC_F_WRITE,
+                        (id + 2) % vq_size);
 
        /* Set up virtqueue descriptor for status */
        desc = &vq_desc[(id + 2) % vq_size];
-       desc->addr = (uint64_t)&status;
-       desc->len = 1;
-       desc->flags = VRING_DESC_F_WRITE;
-       desc->next = 0;
+       virtio_fill_desc(desc, dev->is_modern, (uint64_t)&status, 1,
+                        VRING_DESC_F_WRITE, 0);
 
-       vq_avail->ring[vq_avail->idx % vq_size] = id;
+       vq_avail->ring[avail_idx % vq_size] = virtio_cpu_to_modern16 (dev, id);
        mb();
-       vq_avail->idx += 1;
+       vq_avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1);
 
        /* Tell HV that the queue is ready */
        virtio_queue_notify(dev, 0);