[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 2/2] virtio-blk: add SG_IO passthru support
From: |
Christoph Hellwig |
Subject: |
[Qemu-devel] [PATCH 2/2] virtio-blk: add SG_IO passthru support |
Date: |
Tue, 28 Apr 2009 11:57:14 +0200 |
User-agent: |
Mutt/1.3.28i |
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 aswell as doing asynchronous I/O.
Signed-off-by: Christoph Hellwig <address@hidden>
Index: qemu/hw/virtio-blk.h
===================================================================
--- qemu.orig/hw/virtio-blk.h 2009-04-28 11:42:14.059074434 +0200
+++ qemu/hw/virtio-blk.h 2009-04-28 11:44:24.930074531 +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-28 11:42:14.066074487 +0200
+++ qemu/hw/virtio-blk.c 2009-04-28 11:52:45.836079580 +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,8 @@ typedef struct VirtIOBlockReq
VirtQueueElement elem;
struct virtio_blk_inhdr *in;
struct virtio_blk_outhdr *out;
+ struct virtio_scsi_inhdr *scsi;
+ struct sg_io_hdr scsi_hdr;
QEMUIOVector qiov;
struct VirtIOBlockReq *next;
} VirtIOBlockReq;
@@ -103,6 +108,108 @@ static VirtIOBlockReq *virtio_blk_get_re
return req;
}
+#ifdef __linux__
+static void virtio_blk_scsi_complete(void *opaque, int ret)
+{
+ VirtIOBlockReq *req = opaque;
+ int status;
+
+ if (ret) {
+ status = VIRTIO_BLK_S_UNSUPP;
+ req->scsi_hdr.status = -ret;
+ req->scsi_hdr.resid = req->scsi_hdr.dxfer_len;
+ } else if (req->scsi_hdr.status) {
+ status = VIRTIO_BLK_S_IOERR;
+ } else {
+ status = VIRTIO_BLK_S_OK;
+ }
+
+ req->scsi->errors = req->scsi_hdr.status;
+ req->scsi->residual = req->scsi_hdr.resid;
+ req->scsi->sense_len = req->scsi_hdr.sb_len_wr;
+ req->scsi->data_len = req->scsi_hdr.dxfer_len;
+
+ virtio_blk_req_complete(req, status);
+}
+
+static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
+{
+ 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;
+
+ memset(&req->scsi_hdr, 0, sizeof(struct sg_io_hdr));
+ req->scsi_hdr.interface_id = 'S';
+ req->scsi_hdr.cmd_len = req->elem.out_sg[1].iov_len;
+ req->scsi_hdr.cmdp = req->elem.out_sg[1].iov_base;
+ req->scsi_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.
+ */
+ req->scsi_hdr.dxfer_direction = SG_DXFER_TO_DEV;
+ req->scsi_hdr.iovec_count = req->elem.out_num - 2;
+
+ for (i = 0; i < req->scsi_hdr.iovec_count; i++)
+ req->scsi_hdr.dxfer_len += req->elem.out_sg[i + 2].iov_len;
+ req->scsi_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.
+ */
+ req->scsi_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ req->scsi_hdr.iovec_count = req->elem.in_num - 3;
+
+ for (i = 0; i < req->scsi_hdr.iovec_count; i++)
+ req->scsi_hdr.dxfer_len += req->elem.in_sg[i].iov_len;
+ req->scsi_hdr.dxferp = req->elem.in_sg;
+ } else {
+ /*
+ * Some SCSI commands don't actually transfer any data.
+ */
+ req->scsi_hdr.dxfer_direction = SG_DXFER_NONE;
+ }
+
+ req->scsi_hdr.sbp = req->elem.in_sg[req->elem.in_num - 3].iov_base;
+ req->scsi_hdr.mx_sb_len = req->elem.in_sg[req->elem.in_num - 3].iov_len;
+
+ bdrv_aio_ioctl(req->dev->bs, SG_IO, &req->scsi_hdr,
+ virtio_blk_scsi_complete, req);
+}
+#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 +243,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 +305,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)
- Re: [Qemu-devel] Re: [PATCH] virtio-blk: add SGI_IO passthru support, (continued)
- Re: [Qemu-devel] Re: [PATCH] virtio-blk: add SGI_IO passthru support, Christoph Hellwig, 2009/04/29
- Re: [Qemu-devel] Re: [PATCH] virtio-blk: add SGI_IO passthru support, Paul Brook, 2009/04/29
- Re: [Qemu-devel] Re: [PATCH] virtio-blk: add SGI_IO passthru support, Christoph Hellwig, 2009/04/30
- Re: [Qemu-devel] Re: [PATCH] virtio-blk: add SGI_IO passthru support, Paul Brook, 2009/04/30
- Re: [Qemu-devel] Re: [PATCH] virtio-blk: add SGI_IO passthru support, Javier Guerra, 2009/04/30
- Re: [Qemu-devel] Re: [PATCH] virtio-blk: add SGI_IO passthru support, Christian Borntraeger, 2009/04/28
- Re: [Qemu-devel] Re: [PATCH] virtio-blk: add SGI_IO passthru support, Christoph Hellwig, 2009/04/29
- Re: [Qemu-devel] Re: [PATCH] virtio-blk: add SGI_IO passthru support, Christian Borntraeger, 2009/04/29
[Qemu-devel] [PATCH 2/2] virtio-blk: add SG_IO passthru support,
Christoph Hellwig <=