]> Git Repo - qemu.git/blobdiff - hw/scsi/virtio-scsi.c
virtio: add feature checking helpers
[qemu.git] / hw / scsi / virtio-scsi.c
index fdcacfd79abbe809e68801364a4733abcee75b71..c5d910995f21745bae2d1f76cb73ec3b6fcc5c61 100644 (file)
@@ -13,6 +13,7 @@
  *
  */
 
+#include "standard-headers/linux/virtio_ids.h"
 #include "hw/virtio/virtio-scsi.h"
 #include "qemu/error-report.h"
 #include "qemu/iov.h"
@@ -118,6 +119,7 @@ static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov,
 static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
                                  unsigned req_size, unsigned resp_size)
 {
+    VirtIODevice *vdev = (VirtIODevice *) req->dev;
     size_t in_size, out_size;
 
     if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
@@ -130,8 +132,24 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
                               resp_size) < resp_size) {
         return -EINVAL;
     }
+
     req->resp_size = resp_size;
 
+    /* Old BIOSes left some padding by mistake after the req_size/resp_size.
+     * As a workaround, always consider the first buffer as the virtio-scsi
+     * request/response, making the payload start at the second element
+     * of the iovec.
+     *
+     * The actual length of the response header, stored in req->resp_size,
+     * does not change.
+     *
+     * TODO: always disable this workaround for virtio 1.0 devices.
+     */
+    if (!virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) {
+        req_size = req->elem.out_sg[0].iov_len;
+        resp_size = req->elem.in_sg[0].iov_len;
+    }
+
     out_size = qemu_sgl_concat(req, req->elem.out_sg,
                                &req->elem.out_addr[0], req->elem.out_num,
                                req_size);
@@ -731,7 +749,7 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
     VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
     VirtIODevice *vdev = VIRTIO_DEVICE(s);
 
-    if (((vdev->guest_features >> VIRTIO_SCSI_F_CHANGE) & 1) &&
+    if (virtio_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) &&
         dev->type != TYPE_ROM) {
         virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
                                sense.asc | (sense.ascq << 8));
@@ -752,7 +770,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
         blk_op_block_all(sd->conf.blk, s->blocker);
     }
 
-    if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
+    if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
         virtio_scsi_push_event(s, sd,
                                VIRTIO_SCSI_T_TRANSPORT_RESET,
                                VIRTIO_SCSI_EVT_RESET_RESCAN);
@@ -766,7 +784,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
     VirtIOSCSI *s = VIRTIO_SCSI(vdev);
     SCSIDevice *sd = SCSI_DEVICE(dev);
 
-    if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
+    if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
         virtio_scsi_push_event(s, sd,
                                VIRTIO_SCSI_T_TRANSPORT_RESET,
                                VIRTIO_SCSI_EVT_RESET_REMOVED);
@@ -812,7 +830,7 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
         virtio_cleanup(vdev);
         return;
     }
-    s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *));
+    s->cmd_vqs = g_new0(VirtQueue *, s->conf.num_queues);
     s->sense_size = VIRTIO_SCSI_SENSE_SIZE;
     s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
 
This page took 0.025657 seconds and 4 git commands to generate.