All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] virtio-blk: add SGI_IO passthru support
@ 2009-04-27  8:26 Christoph Hellwig
  2009-04-27  8:29   ` [Qemu-devel] " Christoph Hellwig
  0 siblings, 1 reply; 50+ messages in thread
From: Christoph Hellwig @ 2009-04-27  8:26 UTC (permalink / raw)
  To: qemu; +Cc: Rusty Russell, Hannes Reinecke, Christian Borntraeger, kvm

Add support for SG_IO passthru (packet commands) to the virtio-blk
backend.  Conceptually based on an older patch from Hannes Reinecke
but largely rewritten to match the code structure and layering in
virtio-blk.

Note that currently we issue the hose SG_IO synchronously.  We could
easily switch to async I/O, but that would required either bloating
the VirtIOBlockReq by the size of struct sg_io_hdr or an additional
memory allocation for each SG_IO request.


Signed-off-by: Christoph Hellwig <hch@lst.de>

Index: qemu/hw/virtio-blk.h
===================================================================
--- qemu.orig/hw/virtio-blk.h	2009-04-26 16:50:38.154074532 +0200
+++ qemu/hw/virtio-blk.h	2009-04-26 22:51:16.838076869 +0200
@@ -28,6 +28,9 @@
 #define VIRTIO_BLK_F_SIZE_MAX   1       /* Indicates maximum segment size */
 #define VIRTIO_BLK_F_SEG_MAX    2       /* Indicates maximum # of segments */
 #define VIRTIO_BLK_F_GEOMETRY   4       /* Indicates support of legacy geometry */
+#define VIRTIO_BLK_F_RO         5       /* Disk is read-only */
+#define VIRTIO_BLK_F_BLK_SIZE   6       /* Block size of disk is available*/
+#define VIRTIO_BLK_F_SCSI       7       /* Supports scsi command passthru */
 
 struct virtio_blk_config
 {
@@ -70,6 +73,15 @@ struct virtio_blk_inhdr
     unsigned char status;
 };
 
+/* SCSI pass-through header */
+struct virtio_scsi_inhdr
+{
+    uint32_t errors;
+    uint32_t data_len;
+    uint32_t sense_len;
+    uint32_t residual;
+};
+
 void *virtio_blk_init(PCIBus *bus, BlockDriverState *bs);
 
 #endif
Index: qemu/hw/virtio-blk.c
===================================================================
--- qemu.orig/hw/virtio-blk.c	2009-04-26 16:50:38.160074667 +0200
+++ qemu/hw/virtio-blk.c	2009-04-27 10:25:19.278074514 +0200
@@ -15,6 +15,9 @@
 #include <sysemu.h>
 #include "virtio-blk.h"
 #include "block_int.h"
+#ifdef __linux__
+# include <scsi/sg.h>
+#endif
 
 typedef struct VirtIOBlock
 {
@@ -35,6 +38,7 @@ typedef struct VirtIOBlockReq
     VirtQueueElement elem;
     struct virtio_blk_inhdr *in;
     struct virtio_blk_outhdr *out;
+    struct virtio_scsi_inhdr *scsi;
     QEMUIOVector qiov;
     struct VirtIOBlockReq *next;
 } VirtIOBlockReq;
@@ -103,6 +107,108 @@ static VirtIOBlockReq *virtio_blk_get_re
     return req;
 }
 
+#ifdef __linux__
+static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
+{
+    struct sg_io_hdr hdr;
+    int ret, size = 0;
+    int status;
+    int i;
+
+    /*
+     * We require at least one output segment each for the virtio_blk_outhdr
+     * and the SCSI command block.
+     *
+     * We also at least require the virtio_blk_inhdr, the virtio_scsi_inhdr
+     * and the sense buffer pointer in the input segments.
+     */
+    if (req->elem.out_num < 2 || req->elem.in_num < 3) {
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+        return;
+    }
+
+    /*
+     * No support for bidirection commands yet.
+     */
+    if (req->elem.out_num > 2 && req->elem.in_num > 3) {
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+        return;
+    }
+
+    /*
+     * The scsi inhdr is placed in the second-to-last input segment, just
+     * before the regular inhdr.
+     */
+    req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;
+    size = sizeof(*req->in) + sizeof(*req->scsi);
+
+    memset(&hdr, 0, sizeof(struct sg_io_hdr));
+    hdr.interface_id = 'S';
+    hdr.cmd_len = req->elem.out_sg[1].iov_len;
+    hdr.cmdp = req->elem.out_sg[1].iov_base;
+    hdr.dxfer_len = 0;
+
+    if (req->elem.out_num > 2) {
+        /*
+         * If there are more than the minimally required 2 output segments
+         * there is write payload starting from the third iovec.
+         */
+        hdr.dxfer_direction = SG_DXFER_TO_DEV;
+        hdr.iovec_count = req->elem.out_num - 2;
+
+        for (i = 0; i < hdr.iovec_count; i++)
+            hdr.dxfer_len += req->elem.out_sg[i + 2].iov_len;
+
+        hdr.dxferp = req->elem.out_sg + 2;
+
+    } else if (req->elem.in_num > 3) {
+        /*
+         * If we have more than 3 input segments the guest wants to actually
+         * read data.
+         */
+        hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+        hdr.iovec_count = req->elem.in_num - 3;
+        for (i = 0; i < hdr.iovec_count; i++)
+            hdr.dxfer_len += req->elem.in_sg[i].iov_len;
+
+        hdr.dxferp = req->elem.in_sg;
+        size += hdr.dxfer_len;
+    } else {
+        /*
+         * Some SCSI commands don't actually transfer any data.
+         */
+        hdr.dxfer_direction = SG_DXFER_NONE;
+    }
+
+    hdr.sbp = req->elem.in_sg[req->elem.in_num - 3].iov_base;
+    hdr.mx_sb_len = req->elem.in_sg[req->elem.in_num - 3].iov_len;
+    size += hdr.mx_sb_len;
+
+    ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr);
+    if (ret) {
+        status = VIRTIO_BLK_S_UNSUPP;
+        hdr.status = ret;
+        hdr.resid = hdr.dxfer_len;
+    } else if (hdr.status) {
+        status = VIRTIO_BLK_S_IOERR;
+    } else {
+        status = VIRTIO_BLK_S_OK;
+    }
+
+    req->scsi->errors = hdr.status;
+    req->scsi->residual = hdr.resid;
+    req->scsi->sense_len = hdr.sb_len_wr;
+    req->scsi->data_len = hdr.dxfer_len;
+
+    virtio_blk_req_complete(req, status);
+}
+#else
+static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
+{
+    virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+}
+#endif /* __linux__ */
+
 static void virtio_blk_handle_write(VirtIOBlockReq *req)
 {
     bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
@@ -136,12 +242,7 @@ static void virtio_blk_handle_output(Vir
         req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
 
         if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
-            unsigned int len = sizeof(*req->in);
-
-            req->in->status = VIRTIO_BLK_S_UNSUPP;
-            virtqueue_push(vq, &req->elem, len);
-            virtio_notify(vdev, vq);
-            qemu_free(req);
+            virtio_blk_handle_scsi(req);
         } else if (req->out->type & VIRTIO_BLK_T_OUT) {
             qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
                                      req->elem.out_num - 1);
@@ -203,7 +304,15 @@ static void virtio_blk_update_config(Vir
 
 static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
 {
-    return (1 << VIRTIO_BLK_F_SEG_MAX | 1 << VIRTIO_BLK_F_GEOMETRY);
+    uint32_t features = 0;
+
+    features |= (1 << VIRTIO_BLK_F_SEG_MAX);
+    features |= (1 << VIRTIO_BLK_F_GEOMETRY);
+#ifdef __linux__
+    features |= (1 << VIRTIO_BLK_F_SCSI);
+#endif
+
+    return features;
 }
 
 static void virtio_blk_save(QEMUFile *f, void *opaque)

^ permalink raw reply	[flat|nested] 50+ messages in thread

end of thread, other threads:[~2009-05-05  5:21 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-27  8:26 [PATCH] virtio-blk: add SGI_IO passthru support Christoph Hellwig
2009-04-27  8:29 ` Christoph Hellwig
2009-04-27  8:29   ` [Qemu-devel] " Christoph Hellwig
2009-04-27  9:15   ` Avi Kivity
2009-04-27  9:15     ` [Qemu-devel] " Avi Kivity
2009-04-28  9:47     ` Christoph Hellwig
2009-04-28  9:47       ` Christoph Hellwig
2009-04-27 14:36   ` Anthony Liguori
2009-04-27 14:36     ` [Qemu-devel] " Anthony Liguori
2009-04-28  9:51     ` Christoph Hellwig
2009-04-28  9:51       ` Christoph Hellwig
2009-04-28 16:37       ` Anthony Liguori
2009-04-28 16:52         ` Christian Borntraeger
2009-04-28 16:52           ` Christian Borntraeger
2009-04-29 10:48         ` Christoph Hellwig
2009-04-29 10:48           ` Christoph Hellwig
2009-04-29 11:11           ` Paul Brook
2009-04-29 11:11             ` Paul Brook
2009-04-29 11:19             ` Christian Borntraeger
2009-04-29 11:19               ` Christian Borntraeger
2009-04-29 11:29               ` Paul Brook
2009-04-29 11:29                 ` Paul Brook
2009-04-29 11:21             ` Christoph Hellwig
2009-04-29 11:21               ` Christoph Hellwig
2009-04-29 11:37               ` Paul Brook
2009-04-29 11:37                 ` Paul Brook
2009-04-30 20:13                 ` Christoph Hellwig
2009-04-30 20:13                   ` Christoph Hellwig
2009-04-30 20:55                   ` Nicholas A. Bellinger
2009-04-30 20:55                     ` Nicholas A. Bellinger
2009-04-30 21:49                   ` Paul Brook
2009-04-30 21:49                     ` Paul Brook
2009-04-30 21:56                     ` Javier Guerra
2009-04-30 21:56                       ` Javier Guerra
2009-05-01  7:24                     ` Christoph Hellwig
2009-05-01  7:24                       ` Christoph Hellwig
2009-05-01 11:08                       ` Jamie Lokier
2009-05-01 11:08                         ` Jamie Lokier
2009-05-01 14:28                         ` Christoph Hellwig
2009-05-01 14:28                           ` Christoph Hellwig
2009-05-05  5:21                   ` Rusty Russell
2009-05-05  5:21                     ` Rusty Russell
2009-04-28 19:09       ` Christian Borntraeger
2009-04-28 19:09         ` Christian Borntraeger
2009-04-29 10:50         ` Christoph Hellwig
2009-04-29 10:50           ` Christoph Hellwig
2009-04-29 11:07           ` Christian Borntraeger
2009-04-29 11:07             ` Christian Borntraeger
2009-04-28  9:57   ` [PATCH 2/2] virtio-blk: add SG_IO " Christoph Hellwig
2009-04-28  9:57     ` [Qemu-devel] " Christoph Hellwig

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.