[SLOF] [PATCH v2] virtio-scsi: initialize vring avail queue buffers

Laurent Vivier lvivier at redhat.com
Tue Jan 17 21:04:42 AEDT 2017


From: Laurent Vivier <lvivier at ibm-p8-virt-03.lab.eng.rdu.redhat.com>

virtioscsi_init() uses the result of virtio_get_vring_avail() whereas
the queue is not enabled: on the first boot, its value is NULL and
the driver uses this to communicate with the device. After a reboot,
its value is the one given by the OS driver, and it works if the
address is in a range SLOF can access.

In some cases, for instance with NUMA nodes and hotplugged memory,
SLOF cannot access the address set by the kernel, and virtioscsi_init()
fails with a data storage exception.

To set the vring avail buffer address, we need to enable the queue, what
is done by virtio_set_qaddr().

This patch fixes the problem by calling virtio_queue_init_vq() (like other
virtio drivers) in virtioscsi_init() as it allocates memory and enables the
queue. virtio_queue_init_vq() also replaces the calls to virtio_vring_size()
and virtio_get_vring_avail().
---
v2: move vqs declarations to the function
    only call virtio_cpu_to_modern16() once
    add CC: to Nikunj

 lib/libvirtio/virtio-scsi.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/lib/libvirtio/virtio-scsi.c b/lib/libvirtio/virtio-scsi.c
index 36b62d1..e95352d 100644
--- a/lib/libvirtio/virtio-scsi.c
+++ b/lib/libvirtio/virtio-scsi.c
@@ -99,10 +99,9 @@ int virtioscsi_send(struct virtio_device *dev,
  */
 int virtioscsi_init(struct virtio_device *dev)
 {
-	struct vring_avail *vq_avail;
-	unsigned int idx = 0;
-	int qsize = 0;
+	struct vqs vq_ctrl, vq_event, vq_request;
 	int status = VIRTIO_STAT_ACKNOWLEDGE;
+	uint16_t flags;
 
 	/* Reset device */
 	// XXX That will clear the virtq base. We need to move
@@ -126,17 +125,20 @@ int virtioscsi_init(struct virtio_device *dev)
 		virtio_set_guest_features(dev, 0);
 	}
 
-	while(1) {
-		qsize = virtio_get_qsize(dev, idx);
-		if (!qsize)
-			break;
-		virtio_vring_size(qsize);
+	if (virtio_queue_init_vq(dev, &vq_ctrl, VIRTIO_SCSI_CONTROL_VQ) ||
+	    virtio_queue_init_vq(dev, &vq_event, VIRTIO_SCSI_EVENT_VQ) ||
+	    virtio_queue_init_vq(dev, &vq_request, VIRTIO_SCSI_REQUEST_VQ))
+		goto dev_error;
 
-		vq_avail = virtio_get_vring_avail(dev, idx);
-		vq_avail->flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
-		vq_avail->idx = 0;
-		idx++;
-	}
+	flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
+	vq_ctrl.avail->flags = flags;
+	vq_ctrl.avail->idx = 0;
+
+	vq_event.avail->flags = flags;
+	vq_event.avail->idx = 0;
+
+	vq_request.avail->flags = flags;
+	vq_request.avail->idx = 0;
 
 	/* Tell HV that setup succeeded */
 	status |= VIRTIO_STAT_DRIVER_OK;
-- 
2.7.4



More information about the SLOF mailing list