* [Qemu-devel] [PATCH 0/5] SCSI passthrough cleanup
@ 2008-01-23 16:12 Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 1/5] reverse scsi-generic Laurent Vivier
2008-01-23 20:52 ` [Qemu-devel] [PATCH 0/5] SCSI passthrough cleanup Fabrice Bellard
0 siblings, 2 replies; 8+ messages in thread
From: Laurent Vivier @ 2008-01-23 16:12 UTC (permalink / raw)
Cc: qemu-devel
This series of patches makes some cleanups in SCSI passthrough and
add functionnalities.
[PATCH 1/5] reverse scsi-generic
Reverse previous implementation and restore block-raw-posix.c.
[PATCH 2/5] Move AIO
This patche moves raw AIO part from block-raw-posix.c to qemu-aio-raw.c.
[PATCH 3/5] Add block SG interface
This patch re-implement scsi-generic.c using a new block interface.
[PATCH 4/5] DVD movie support
This patch allows to read a protected/encrypted movie from a DVD.
[PATCH 5/5] SCSI device DMA split
This patch allows to split a READ or WRITE into several READ or WRITE.
Laurent
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 1/5] reverse scsi-generic
2008-01-23 16:12 [Qemu-devel] [PATCH 0/5] SCSI passthrough cleanup Laurent Vivier
@ 2008-01-23 16:12 ` Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 2/5] Move AIO Laurent Vivier
2008-01-23 20:52 ` [Qemu-devel] [PATCH 0/5] SCSI passthrough cleanup Fabrice Bellard
1 sibling, 1 reply; 8+ messages in thread
From: Laurent Vivier @ 2008-01-23 16:12 UTC (permalink / raw)
Cc: qemu-devel
This patch removes modifications in block interface introduced by the
scsi-generic implementation, and disables scsi-generic support.
Files restored are:
block-raw-posix.c revision 1.2
block.c revision 1.52
block.h revision 1.5
block_int.h revision 1.15
Laurent
---
block-raw-posix.c | 23 +++--------------------
block.c | 16 ----------------
block.h | 2 --
block_int.h | 4 ----
hw/scsi-generic.c | 3 ++-
5 files changed, 5 insertions(+), 43 deletions(-)
Index: qemu/block.c
===================================================================
--- qemu.orig/block.c 2008-01-23 09:18:17.000000000 +0100
+++ qemu/block.c 2008-01-23 09:19:16.000000000 +0100
@@ -786,11 +786,6 @@ int bdrv_is_read_only(BlockDriverState *
return bs->read_only;
}
-int bdrv_is_sg(BlockDriverState *bs)
-{
- return bs->sg;
-}
-
/* XXX: no longer used */
void bdrv_set_change_cb(BlockDriverState *bs,
void (*change_cb)(void *opaque), void *opaque)
@@ -1399,14 +1394,3 @@ void bdrv_set_locked(BlockDriverState *b
drv->bdrv_set_locked(bs, locked);
}
}
-
-/* needed for generic scsi interface */
-
-int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
-{
- BlockDriver *drv = bs->drv;
-
- if (drv && drv->bdrv_ioctl)
- return drv->bdrv_ioctl(bs, req, buf);
- return -ENOTSUP;
-}
Index: qemu/block.h
===================================================================
--- qemu.orig/block.h 2008-01-23 09:18:17.000000000 +0100
+++ qemu/block.h 2008-01-23 09:19:16.000000000 +0100
@@ -119,7 +119,6 @@ int bdrv_get_type_hint(BlockDriverState
int bdrv_get_translation_hint(BlockDriverState *bs);
int bdrv_is_removable(BlockDriverState *bs);
int bdrv_is_read_only(BlockDriverState *bs);
-int bdrv_is_sg(BlockDriverState *bs);
int bdrv_is_inserted(BlockDriverState *bs);
int bdrv_media_changed(BlockDriverState *bs);
int bdrv_is_locked(BlockDriverState *bs);
@@ -149,7 +148,6 @@ int bdrv_snapshot_delete(BlockDriverStat
int bdrv_snapshot_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info);
char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
-int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
char *get_human_readable_size(char *buf, int buf_size, int64_t size);
int path_is_absolute(const char *path);
Index: qemu/block_int.h
===================================================================
--- qemu.orig/block_int.h 2008-01-23 09:18:17.000000000 +0100
+++ qemu/block_int.h 2008-01-23 09:19:16.000000000 +0100
@@ -82,9 +82,6 @@ struct BlockDriver {
int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
- /* to control generic scsi devices */
- int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf);
-
BlockDriverAIOCB *free_aiocb;
struct BlockDriver *next;
};
@@ -96,7 +93,6 @@ struct BlockDriverState {
int removable; /* if true, the media can be removed */
int locked; /* if true, the media cannot temporarily be ejected */
int encrypted; /* if true, the media is encrypted */
- int sg; /* if true, the device is a /dev/sg* */
/* event callback when inserting/removing */
void (*change_cb)(void *opaque);
void *change_opaque;
Index: qemu/block-raw-posix.c
===================================================================
--- qemu.orig/block-raw-posix.c 2008-01-23 09:18:17.000000000 +0100
+++ qemu/block-raw-posix.c 2008-01-23 09:19:16.000000000 +0100
@@ -151,7 +151,7 @@ static int raw_pread(BlockDriverState *b
if (ret < 0)
return ret;
- if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
+ if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
++(s->lseek_err_cnt);
if(s->lseek_err_cnt <= 10) {
DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
@@ -204,7 +204,7 @@ static int raw_pwrite(BlockDriverState *
if (ret < 0)
return ret;
- if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
+ if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
++(s->lseek_err_cnt);
if(s->lseek_err_cnt) {
DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%"
@@ -387,10 +387,7 @@ static RawAIOCB *raw_aio_setup(BlockDriv
acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
acb->aiocb.aio_buf = buf;
- if (nb_sectors < 0)
- acb->aiocb.aio_nbytes = -nb_sectors;
- else
- acb->aiocb.aio_nbytes = nb_sectors * 512;
+ acb->aiocb.aio_nbytes = nb_sectors * 512;
acb->aiocb.aio_offset = sector_num * 512;
acb->next = first_aio;
first_aio = acb;
@@ -682,8 +679,6 @@ static int hdev_open(BlockDriverState *b
s->fd_open_flags = open_flags;
/* open will not fail even if no floppy is inserted */
open_flags |= O_NONBLOCK;
- } else if (strstart(filename, "/dev/sg", NULL)) {
- bs->sg = 1;
}
#endif
fd = open(filename, open_flags, 0644);
@@ -863,12 +858,6 @@ static int raw_set_locked(BlockDriverSta
return 0;
}
-static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
-{
- BDRVRawState *s = bs->opaque;
-
- return ioctl(s->fd, req, buf);
-}
#else
static int raw_is_inserted(BlockDriverState *bs)
@@ -891,10 +880,6 @@ static int raw_set_locked(BlockDriverSta
return -ENOTSUP;
}
-static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
-{
- return -ENOTSUP;
-}
#endif /* !linux */
BlockDriver bdrv_host_device = {
@@ -921,6 +906,4 @@ BlockDriver bdrv_host_device = {
.bdrv_media_changed = raw_media_changed,
.bdrv_eject = raw_eject,
.bdrv_set_locked = raw_set_locked,
- /* generic scsi device */
- .bdrv_ioctl = raw_ioctl,
};
Index: qemu/hw/scsi-generic.c
===================================================================
--- qemu.orig/hw/scsi-generic.c 2008-01-23 09:18:17.000000000 +0100
+++ qemu/hw/scsi-generic.c 2008-01-23 09:19:16.000000000 +0100
@@ -15,7 +15,8 @@
#include "block.h"
#include "scsi-disk.h"
-#ifndef __linux__
+//#ifndef __linux__
+#if 1
SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq,
scsi_completionfn completion, void *opaque)
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 4/5] DVD movie support
2008-01-23 16:12 ` [Qemu-devel] [PATCH 3/5] Add block SG interface Laurent Vivier
@ 2008-01-23 16:12 ` Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 5/5] SCSI device DMA split Laurent Vivier
0 siblings, 1 reply; 8+ messages in thread
From: Laurent Vivier @ 2008-01-23 16:12 UTC (permalink / raw)
Cc: qemu-devel
This patch allows to read a protected/encrypted movie from a DVD.
(With a Movie Player having the key to decode it, tested with powerDVD)
Laurent
---
hw/scsi-generic.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
Index: qemu/hw/scsi-generic.c
===================================================================
--- qemu.orig/hw/scsi-generic.c 2008-01-23 14:03:01.000000000 +0100
+++ qemu/hw/scsi-generic.c 2008-01-23 14:03:02.000000000 +0100
@@ -46,9 +46,12 @@ do { fprintf(stderr, "scsi-generic: " fm
#include <scsi/scsi.h>
#include "block-sg.h"
+#define BLANK 0xa1
+#define SEND_KEY 0xa3
+#define REPORT_KEY 0xa4
#define LOAD_UNLOAD 0xa6
+#define READ_DVD_STRUCTURE 0xad
#define SET_CD_SPEED 0xbb
-#define BLANK 0xa1
#define SCSI_CMD_BUF_SIZE 16
#define SCSI_SENSE_BUF_SIZE 32
@@ -398,6 +401,12 @@ static int scsi_length(uint8_t *cmd, int
case READ_12:
*len *= blocksize;
break;
+ case READ_DVD_STRUCTURE:
+ case SEND_KEY:
+ case REPORT_KEY:
+ *len &= 0xffff;
+ break;
+
}
return 0;
}
@@ -435,6 +444,7 @@ static int is_write(int command)
case MEDIUM_SCAN:
case SEND_VOLUME_TAG:
case WRITE_LONG_2:
+ case SEND_KEY:
return 1;
}
return 0;
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 3/5] Add block SG interface
2008-01-23 16:12 ` [Qemu-devel] [PATCH 2/5] Move AIO Laurent Vivier
@ 2008-01-23 16:12 ` Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 4/5] DVD movie support Laurent Vivier
0 siblings, 1 reply; 8+ messages in thread
From: Laurent Vivier @ 2008-01-23 16:12 UTC (permalink / raw)
Cc: qemu-devel
This patch re-implement scsi-generic.c using a new block interface called
block-sg.c instead of block-raw-posix.c.
It adds a new interface (bdrv_execute) allowing to send command to the device.
Laurent
---
Makefile | 2
Makefile.target | 2
block-sg.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
block-sg.h | 18 +++++
block.c | 21 +++++
block.h | 4 +
block_int.h | 4 +
hw/scsi-generic.c | 176 +++++++++++++++++-------------------------------
8 files changed, 303 insertions(+), 118 deletions(-)
Index: qemu/block.c
===================================================================
--- qemu.orig/block.c 2008-01-23 16:02:32.000000000 +0100
+++ qemu/block.c 2008-01-23 16:43:01.000000000 +0100
@@ -126,13 +126,14 @@ void path_combine(char *dest, int dest_s
static void bdrv_register(BlockDriver *bdrv)
{
- if (!bdrv->bdrv_aio_read) {
+ if (!bdrv->bdrv_aio_read && !bdrv->bdrv_execute) {
/* add AIO emulation layer */
bdrv->bdrv_aio_read = bdrv_aio_read_em;
bdrv->bdrv_aio_write = bdrv_aio_write_em;
bdrv->bdrv_aio_cancel = bdrv_aio_cancel_em;
bdrv->aiocb_size = sizeof(BlockDriverAIOCBSync);
- } else if (!bdrv->bdrv_read && !bdrv->bdrv_pread) {
+ } else if (!bdrv->bdrv_read && !bdrv->bdrv_pread &&
+ !bdrv->bdrv_execute) {
/* add synchronous IO emulation layer */
bdrv->bdrv_read = bdrv_read_em;
bdrv->bdrv_write = bdrv_write_em;
@@ -267,6 +268,8 @@ static BlockDriver *find_image_format(co
struct stat st;
if (stat(filename, &st) >= 0 &&
(S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
+ if ((st.st_rdev >> 8) == 0x15) /* SG device */
+ return &bdrv_sg_device;
return &bdrv_host_device;
}
}
@@ -1289,6 +1292,7 @@ void bdrv_init(void)
bdrv_register(&bdrv_vvfat);
bdrv_register(&bdrv_qcow2);
bdrv_register(&bdrv_parallels);
+ bdrv_register(&bdrv_sg_device);
}
void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
@@ -1394,3 +1398,16 @@ void bdrv_set_locked(BlockDriverState *b
drv->bdrv_set_locked(bs, locked);
}
}
+
+/* send a command to a device, needed for generic scsi interface */
+
+int bdrv_execute(BlockDriverState *bs, void *request,
+ BlockDriverCompletionFunc *complete)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (drv && drv->bdrv_execute) {
+ return drv->bdrv_execute(bs, request, complete);
+ }
+ return -ENOTSUP;
+}
Index: qemu/block.h
===================================================================
--- qemu.orig/block.h 2008-01-23 16:02:32.000000000 +0100
+++ qemu/block.h 2008-01-23 16:02:32.000000000 +0100
@@ -16,6 +16,7 @@ extern BlockDriver bdrv_vpc;
extern BlockDriver bdrv_vvfat;
extern BlockDriver bdrv_qcow2;
extern BlockDriver bdrv_parallels;
+extern BlockDriver bdrv_sg_device;
typedef struct BlockDriverInfo {
/* in bytes, 0 if irrelevant */
@@ -148,6 +149,9 @@ int bdrv_snapshot_delete(BlockDriverStat
int bdrv_snapshot_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info);
char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
+int bdrv_execute(BlockDriverState *bs, void *request,
+ BlockDriverCompletionFunc *complete);
+
char *get_human_readable_size(char *buf, int buf_size, int64_t size);
int path_is_absolute(const char *path);
Index: qemu/block-sg.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu/block-sg.c 2008-01-23 16:41:58.000000000 +0100
@@ -0,0 +1,194 @@
+/*
+ * sg driver for RAW files
+ *
+ * Copyright (c) 2008 Bull S.A.S.
+ * Based on code by Fabrice Bellard
+ *
+ * Written by Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include "block_int.h"
+#include "qemu-aio-posix.h"
+
+#include <unistd.h>
+#include <scsi/sg.h>
+
+#include "block-sg.h"
+
+#include <sys/ioctl.h>
+
+//#define DEBUG_SG
+
+#ifdef DEBUG_SG
+#define DPRINTF(fmt, args...) \
+do { printf("block-sg: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+
+typedef struct BDRVSGState {
+ int fd; /* must be the first field for qemu-aio-posix.c */
+ int lun;
+} BDRVSGState;
+
+#define BADF(fmt, args...) \
+do { fprintf(stderr, "block-sg: " fmt , ##args); } while (0)
+
+static int sg_read(BlockDriverState *bs, uint8_t *buf, int count)
+{
+ BDRVSGState *s = bs->opaque;
+
+ return read(s->fd, buf, count);
+}
+
+static int sg_write(BlockDriverState *bs, const uint8_t *buf, int count)
+{
+ BDRVSGState *s = bs->opaque;
+
+ return write(s->fd, buf, count);
+}
+
+static BlockDriverAIOCB *sg_aio_read(BlockDriverState *bs,
+ int64_t offset, uint8_t *buf, int nb_bytes,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ RawAIOCB *acb;
+
+ DPRINTF("sg_aio_read: bs %p offset %d buf %p nb_bytes %d cb %p opaque %p\n",
+ bs, offset, buf, nb_bytes, cb, opaque);
+
+ acb = qemu_aio_read(bs, offset, buf, nb_bytes,
+ cb, opaque);
+
+ DPRINTF("acb: %p\n", acb);
+
+ return &acb->common;
+}
+
+static void sg_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ RawAIOCB *acb = (RawAIOCB *)blockacb;
+
+ qemu_aio_cancel(acb);
+}
+
+static void sg_close(BlockDriverState *bs)
+{
+ BDRVSGState *s = bs->opaque;
+ close(s->fd);
+}
+
+static int sg_open(BlockDriverState *bs, const char *filename, int flags)
+{
+ BDRVSGState *s = bs->opaque;
+ int fd, open_flags, ret;
+ int sg_version = 0;
+ struct sg_scsi_id scsiid;
+
+ open_flags = O_BINARY;
+ if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+ open_flags |= O_RDWR;
+ } else {
+ open_flags |= O_RDONLY;
+ bs->read_only = 1;
+ }
+
+ fd = open(filename, open_flags, 0644);
+ if (fd < 0) {
+ ret = -errno;
+ if (ret == -EROFS)
+ ret = -EACCES;
+ return ret;
+ }
+
+ /* check we are using a driver managing SG_IO (version 3 and after */
+
+ if (ioctl(fd, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+ sg_version < 30000)
+ return -EINVAL;
+
+ /* get LUN of the /dev/sg? */
+
+ if (ioctl(fd, SG_GET_SCSI_ID, &scsiid))
+ return -EINVAL;
+
+ s->fd = fd;
+ s->lun = scsiid.lun;
+
+ return 0;
+}
+
+int sg_execute(BlockDriverState *bs, void *request,
+ BlockDriverCompletionFunc *complete)
+{
+ BDRVSGState *s = bs->opaque;
+ SGRequest *r = (SGRequest *)request;
+
+ DPRINTF("sg_execute bs %p request %p complete %p\n",
+ bs, request, complete);
+
+ if (request == NULL)
+ return s->lun;
+
+ if (sg_write(bs, (const uint8_t *)&r->io_header,
+ sizeof(r->io_header)) == -1) {
+ BADF("execute_command: write failed ! (%d)\n", errno);
+ return -1;
+ }
+ if (complete == NULL) {
+ int ret;
+ r->aiocb = NULL;
+ while ((ret = sg_read(bs, (uint8_t *)&r->io_header,
+ sizeof(r->io_header))) == -1 &&
+ errno == EINTR);
+ if (ret == -1) {
+ BADF("execute_command: read failed !\n");
+ return -1;
+ }
+ return 0;
+ }
+
+ r->aiocb = sg_aio_read(bs, 0, (uint8_t*)&r->io_header,
+ sizeof(r->io_header), complete, r);
+ if (r->aiocb == NULL) {
+ BADF("execute_command: read failed !\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+BlockDriver bdrv_sg_device = {
+ "sg_device",
+ sizeof(BDRVSGState),
+ NULL,
+ sg_open,
+ NULL,
+ NULL,
+ sg_close,
+ NULL,
+ NULL,
+ .aiocb_size = sizeof(RawAIOCB),
+ .bdrv_aio_cancel = sg_aio_cancel,
+ /* generic scsi device */
+ .bdrv_execute = sg_execute,
+};
Index: qemu/hw/scsi-generic.c
===================================================================
--- qemu.orig/hw/scsi-generic.c 2008-01-23 16:02:32.000000000 +0100
+++ qemu/hw/scsi-generic.c 2008-01-23 16:41:58.000000000 +0100
@@ -13,10 +13,10 @@
#include "qemu-common.h"
#include "block.h"
+#include "block_int.h"
#include "scsi-disk.h"
-//#ifndef __linux__
-#if 1
+#ifndef __linux__
SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq,
scsi_completionfn completion, void *opaque)
@@ -44,6 +44,7 @@ do { fprintf(stderr, "scsi-generic: " fm
#include <unistd.h>
#include <scsi/sg.h>
#include <scsi/scsi.h>
+#include "block-sg.h"
#define LOAD_UNLOAD 0xa6
#define SET_CD_SPEED 0xbb
@@ -52,15 +53,12 @@ do { fprintf(stderr, "scsi-generic: " fm
#define SCSI_CMD_BUF_SIZE 16
#define SCSI_SENSE_BUF_SIZE 32
-#define SG_ERR_DRIVER_TIMEOUT 0x06
-#define SG_ERR_DRIVER_SENSE 0x08
-
#ifndef MAX_UINT
#define MAX_UINT ((unsigned int)-1)
#endif
typedef struct SCSIRequest {
- BlockDriverAIOCB *aiocb;
+ SGRequest sg;
struct SCSIRequest *next;
SCSIDeviceState *dev;
uint32_t tag;
@@ -69,7 +67,6 @@ typedef struct SCSIRequest {
uint8_t *buf;
int buflen;
int len;
- sg_io_hdr_t io_header;
} SCSIRequest;
struct SCSIDeviceState
@@ -77,9 +74,8 @@ struct SCSIDeviceState
SCSIRequest *requests;
BlockDriverState *bdrv;
int blocksize;
- int lun;
scsi_completionfn completion;
- void *opaque;
+ void *card;
int driver_status;
uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
};
@@ -102,10 +98,8 @@ static SCSIRequest *scsi_new_request(SCS
r->dev = s;
r->tag = tag;
memset(r->cmd, 0, sizeof(r->cmd));
- memset(&r->io_header, 0, sizeof(r->io_header));
r->cmdlen = 0;
r->len = 0;
- r->aiocb = NULL;
/* link */
@@ -147,14 +141,14 @@ static SCSIRequest *scsi_find_request(SC
}
/* Helper function for command completion. */
-static void scsi_command_complete(void *opaque, int ret)
+static void scsi_command_complete(void *request, int ret)
{
- SCSIRequest *r = (SCSIRequest *)opaque;
+ SCSIRequest *r = (SCSIRequest *)request;
SCSIDeviceState *s = r->dev;
uint32_t tag;
int sense;
- s->driver_status = r->io_header.driver_status;
+ s->driver_status = r->sg.io_header.driver_status;
if (ret != 0)
sense = HARDWARE_ERROR;
else {
@@ -167,10 +161,10 @@ static void scsi_command_complete(void *
sense = s->sensebuf[2] & 0x0f;
}
- DPRINTF("Command complete 0x%p tag=0x%x sense=%d\n", r, r->tag, sense);
+ DPRINTF("Command complete %p tag=0x%x sense=%d\n", r, r->tag, sense);
tag = r->tag;
scsi_remove_request(r);
- s->completion(s->opaque, SCSI_REASON_DONE, tag, sense);
+ s->completion(s->card, SCSI_REASON_DONE, tag, sense);
}
/* Cancel a pending data transfer. */
@@ -182,60 +176,35 @@ static void scsi_cancel_io(SCSIDevice *d
DPRINTF("Cancel tag=0x%x\n", tag);
r = scsi_find_request(s, tag);
if (r) {
- if (r->aiocb)
- bdrv_aio_cancel(r->aiocb);
- r->aiocb = NULL;
+ if (r->sg.aiocb)
+ bdrv_aio_cancel(r->sg.aiocb);
+ r->sg.aiocb = NULL;
scsi_remove_request(r);
}
}
static int execute_command(BlockDriverState *bdrv,
SCSIRequest *r, int direction,
- BlockDriverCompletionFunc *complete)
+ BlockDriverCompletionFunc *complete)
{
+ memset(&r->sg, 0, sizeof(r->sg));
+ r->sg.io_header.interface_id = 'S';
+ r->sg.io_header.dxfer_direction = direction;
+ r->sg.io_header.cmd_len = r->cmdlen;
+ r->sg.io_header.mx_sb_len = sizeof(r->dev->sensebuf);
+ r->sg.io_header.dxfer_len = r->buflen;
+ r->sg.io_header.dxferp = r->buf;
+ r->sg.io_header.cmdp = r->cmd;
+ r->sg.io_header.sbp = r->dev->sensebuf;
+ r->sg.io_header.timeout = MAX_UINT;
+ r->sg.io_header.flags |= SG_FLAG_DIRECT_IO;
- r->io_header.interface_id = 'S';
- r->io_header.dxfer_direction = direction;
- r->io_header.dxferp = r->buf;
- r->io_header.dxfer_len = r->buflen;
- r->io_header.cmdp = r->cmd;
- r->io_header.cmd_len = r->cmdlen;
- r->io_header.mx_sb_len = sizeof(r->dev->sensebuf);
- r->io_header.sbp = r->dev->sensebuf;
- r->io_header.timeout = MAX_UINT;
- r->io_header.usr_ptr = r;
- r->io_header.flags |= SG_FLAG_DIRECT_IO;
-
- if (bdrv_pwrite(bdrv, -1, &r->io_header, sizeof(r->io_header)) == -1) {
- BADF("execute_command: write failed ! (%d)\n", errno);
- return -1;
- }
- if (complete == NULL) {
- int ret;
- r->aiocb = NULL;
- while ((ret = bdrv_pread(bdrv, -1, &r->io_header,
- sizeof(r->io_header))) == -1 &&
- errno == EINTR);
- if (ret == -1) {
- BADF("execute_command: read failed !\n");
- return -1;
- }
- return 0;
- }
-
- r->aiocb = bdrv_aio_read(bdrv, 0, (uint8_t*)&r->io_header,
- -(int64_t)sizeof(r->io_header), complete, r);
- if (r->aiocb == NULL) {
- BADF("execute_command: read failed !\n");
- return -1;
- }
-
- return 0;
+ return bdrv_execute(bdrv, &r->sg, complete);
}
-static void scsi_read_complete(void * opaque, int ret)
+static void scsi_read_complete(void *request, int ret)
{
- SCSIRequest *r = (SCSIRequest *)opaque;
+ SCSIRequest *r = (SCSIRequest *)request;
SCSIDeviceState *s = r->dev;
int len;
@@ -244,11 +213,11 @@ static void scsi_read_complete(void * op
scsi_command_complete(r, ret);
return;
}
- len = r->io_header.dxfer_len - r->io_header.resid;
+ len = r->sg.io_header.dxfer_len - r->sg.io_header.resid;
DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, len);
r->len = -1;
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
+ s->completion(s->card, SCSI_REASON_DATA, r->tag, len);
}
/* Read more data from scsi device into buffer. */
@@ -275,9 +244,9 @@ static void scsi_read_data(SCSIDevice *d
if (r->cmd[0] == REQUEST_SENSE && s->driver_status & SG_ERR_DRIVER_SENSE)
{
memcpy(r->buf, s->sensebuf, 16);
- r->io_header.driver_status = 0;
+ r->sg.io_header.driver_status = 0;
r->len = -1;
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, 16);
+ s->completion(s->card, SCSI_REASON_DATA, r->tag, 16);
return;
}
@@ -288,10 +257,9 @@ static void scsi_read_data(SCSIDevice *d
}
}
-static void scsi_write_complete(void * opaque, int ret)
+static void scsi_write_complete(void* request, int ret)
{
- SCSIRequest *r = (SCSIRequest *)opaque;
-
+ SCSIRequest* r = (SCSIRequest*)request;
DPRINTF("scsi_write_complete() ret = %d\n", ret);
if (ret) {
DPRINTF("IO error\n");
@@ -321,7 +289,7 @@ static int scsi_write_data(SCSIDevice *d
if (r->len == 0) {
r->len = r->buflen;
- s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->len);
+ s->completion(s->card, SCSI_REASON_DATA, r->tag, r->len);
return 0;
}
@@ -339,11 +307,13 @@ static uint8_t *scsi_get_buf(SCSIDevice
{
SCSIDeviceState *s = d->state;
SCSIRequest *r;
+ DPRINTF("scsi_get_buf: %d\n", tag);
r = scsi_find_request(s, tag);
if (!r) {
BADF("Bad buffer tag 0x%x\n", tag);
return NULL;
}
+ DPRINTF("scsi_get_buf: r=%p buf=%p\n", r, r->buf);
return r->buf;
}
@@ -483,13 +453,16 @@ static int32_t scsi_send_command(SCSIDev
int cmdlen;
SCSIRequest *r;
int ret;
+ int target_lun;
/* ??? Tags are not unique for different luns. We only implement a
single lun, so this should not matter. */
- if (lun != s->lun || (cmd[1] >> 5) != s->lun) {
+ target_lun = bdrv_execute(s->bdrv, NULL, NULL);
+
+ if (lun != target_lun || (cmd[1] >> 5) != target_lun) {
DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5);
- s->completion(s->opaque, SCSI_REASON_DONE, tag, ILLEGAL_REQUEST);
+ s->completion(s->card, SCSI_REASON_DONE, tag, ILLEGAL_REQUEST);
return 0;
}
@@ -500,7 +473,6 @@ static int32_t scsi_send_command(SCSIDev
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x len %d\n", lun, tag,
cmd[0], len);
-
r = scsi_find_request(s, tag);
if (r) {
BADF("Tag 0x%x already in use %p\n", tag, r);
@@ -513,20 +485,18 @@ static int32_t scsi_send_command(SCSIDev
if (len == 0) {
if (r->buf != NULL)
- free(r->buf);
+ qemu_free(r->buf);
r->buflen = 0;
r->buf = NULL;
ret = execute_command(s->bdrv, r, SG_DXFER_NONE, scsi_command_complete);
- if (ret == -1) {
+ if (ret == -1)
scsi_command_complete(r, -EINVAL);
- return 0;
- }
return 0;
}
if (r->buflen != len) {
if (r->buf != NULL)
- free(r->buf);
+ qemu_free(r->buf);
r->buf = qemu_malloc(len);
r->buflen = len;
}
@@ -543,34 +513,28 @@ static int32_t scsi_send_command(SCSIDev
static int get_blocksize(BlockDriverState *bdrv)
{
+ SGRequest sg;
uint8_t cmd[10];
uint8_t buf[8];
uint8_t sensebuf[8];
- sg_io_hdr_t io_header;
int ret;
- memset(cmd, sizeof(cmd), 0);
- memset(buf, sizeof(buf), 0);
+ memset(cmd, 0, sizeof(cmd));
+ memset(buf, 0, sizeof(buf));
cmd[0] = READ_CAPACITY;
- memset(&io_header, 0, sizeof(io_header));
- io_header.interface_id = 'S';
- io_header.dxfer_direction = SG_DXFER_FROM_DEV;
- io_header.dxfer_len = sizeof(buf);
- io_header.dxferp = buf;
- io_header.cmdp = cmd;
- io_header.cmd_len = sizeof(cmd);
- io_header.mx_sb_len = sizeof(sensebuf);
- io_header.sbp = sensebuf;
- io_header.timeout = 6000; /* XXX */
-
- ret = bdrv_pwrite(bdrv, -1, &io_header, sizeof(io_header));
- if (ret == -1)
- return -1;
-
- while ((ret = bdrv_pread(bdrv, -1, &io_header, sizeof(io_header))) == -1 &&
- errno == EINTR);
+ memset(&sg.io_header, 0, sizeof(sg.io_header));
+ sg.io_header.interface_id = 'S';
+ sg.io_header.dxfer_direction = SG_DXFER_FROM_DEV;
+ sg.io_header.dxfer_len = sizeof(buf);
+ sg.io_header.dxferp = buf;
+ sg.io_header.cmdp = cmd;
+ sg.io_header.cmd_len = sizeof(cmd);
+ sg.io_header.mx_sb_len = sizeof(sensebuf);
+ sg.io_header.sbp = sensebuf;
+ sg.io_header.timeout = 6000; /* XXX */
+ ret = bdrv_execute(bdrv, &sg, NULL);
if (ret == -1)
return -1;
@@ -600,27 +564,12 @@ static void scsi_destroy(SCSIDevice *d)
}
SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq,
- scsi_completionfn completion, void *opaque)
+ scsi_completionfn completion, void *card)
{
- int sg_version;
SCSIDevice *d;
SCSIDeviceState *s;
- struct sg_scsi_id scsiid;
-
- /* check we are really using a /dev/sg* file */
-
- if (!bdrv_is_sg(bdrv))
- return NULL;
-
- /* check we are using a driver managing SG_IO (version 3 and after */
-
- if (bdrv_ioctl(bdrv, SG_GET_VERSION_NUM, &sg_version) < 0 ||
- sg_version < 30000)
- return NULL;
-
- /* get LUN of the /dev/sg? */
- if (bdrv_ioctl(bdrv, SG_GET_SCSI_ID, &scsiid))
+ if (bdrv->drv->bdrv_execute == NULL)
return NULL;
/* define device state */
@@ -629,8 +578,7 @@ SCSIDevice *scsi_generic_init(BlockDrive
s->bdrv = bdrv;
s->requests = NULL;
s->completion = completion;
- s->opaque = opaque;
- s->lun = scsiid.lun;
+ s->card = card;
s->blocksize = get_blocksize(s->bdrv);
s->driver_status = 0;
memset(s->sensebuf, 0, sizeof(s->sensebuf));
Index: qemu/Makefile.target
===================================================================
--- qemu.orig/Makefile.target 2008-01-23 16:02:32.000000000 +0100
+++ qemu/Makefile.target 2008-01-23 16:02:32.000000000 +0100
@@ -398,7 +398,7 @@ VL_OBJS=vl.o osdep.o monitor.o pci.o loa
ifdef CONFIG_WIN32
VL_OBJS+=block-raw-win32.o
else
-VL_OBJS+=block-raw-posix.o qemu-aio-posix.o
+VL_OBJS+=block-raw-posix.o block-sg.o qemu-aio-posix.o
endif
ifdef CONFIG_ALSA
Index: qemu/Makefile
===================================================================
--- qemu.orig/Makefile 2008-01-23 16:02:32.000000000 +0100
+++ qemu/Makefile 2008-01-23 16:02:32.000000000 +0100
@@ -40,7 +40,7 @@ recurse-all: $(patsubst %,subdir-%, $(TA
BLOCK_OBJS=cutils.o
BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
-BLOCK_OBJS+=block-qcow2.o block-parallels.o
+BLOCK_OBJS+=block-qcow2.o block-parallels.o block-sg.o
######################################################################
# libqemu_common.a: Target indepedent part of system emulation. The
Index: qemu/block-sg.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu/block-sg.h 2008-01-23 16:02:32.000000000 +0100
@@ -0,0 +1,18 @@
+/*
+ * Generic SCSI Device support
+ *
+ * Copyright (c) 2008 Bull S.A.S.
+ *
+ * Written by Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * This code is licenced under the LGPL.
+ *
+ */
+
+#define SG_ERR_DRIVER_TIMEOUT 0x06
+#define SG_ERR_DRIVER_SENSE 0x08
+
+typedef struct SGRequest {
+ sg_io_hdr_t io_header;
+ BlockDriverAIOCB *aiocb;
+} SGRequest;
Index: qemu/block_int.h
===================================================================
--- qemu.orig/block_int.h 2008-01-23 16:02:32.000000000 +0100
+++ qemu/block_int.h 2008-01-23 16:02:32.000000000 +0100
@@ -82,6 +82,10 @@ struct BlockDriver {
int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
+ /* SG device */
+ int (*bdrv_execute)(BlockDriverState *bs, void *request,
+ BlockDriverCompletionFunc *complete);
+
BlockDriverAIOCB *free_aiocb;
struct BlockDriver *next;
};
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 2/5] Move AIO
2008-01-23 16:12 ` [Qemu-devel] [PATCH 1/5] reverse scsi-generic Laurent Vivier
@ 2008-01-23 16:12 ` Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 3/5] Add block SG interface Laurent Vivier
0 siblings, 1 reply; 8+ messages in thread
From: Laurent Vivier @ 2008-01-23 16:12 UTC (permalink / raw)
Cc: qemu-devel
This patche moves raw AIO part from block-raw-posix.c to qemu-aio-raw.c to
be able to use raw AIO from other files.
Laurent
---
Makefile | 2
Makefile.target | 2
block-raw-posix.c | 205 ++-------------------------------------------
qemu-aio-posix.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
qemu-aio-posix.h | 39 ++++++++
5 files changed, 293 insertions(+), 196 deletions(-)
Index: qemu/Makefile.target
===================================================================
--- qemu.orig/Makefile.target 2008-01-23 09:18:17.000000000 +0100
+++ qemu/Makefile.target 2008-01-23 09:19:30.000000000 +0100
@@ -398,7 +398,7 @@ VL_OBJS=vl.o osdep.o monitor.o pci.o loa
ifdef CONFIG_WIN32
VL_OBJS+=block-raw-win32.o
else
-VL_OBJS+=block-raw-posix.o
+VL_OBJS+=block-raw-posix.o qemu-aio-posix.o
endif
ifdef CONFIG_ALSA
Index: qemu/block-raw-posix.c
===================================================================
--- qemu.orig/block-raw-posix.c 2008-01-23 09:19:16.000000000 +0100
+++ qemu/block-raw-posix.c 2008-01-23 09:19:30.000000000 +0100
@@ -28,7 +28,7 @@
#endif
#include "block_int.h"
#include <assert.h>
-#include <aio.h>
+#include "qemu-aio-posix.h"
#ifdef CONFIG_COCOA
#include <paths.h>
@@ -75,7 +75,7 @@
#define FD_OPEN_TIMEOUT 1000
typedef struct BDRVRawState {
- int fd;
+ int fd; /* must be the first field for qemu-aio-posix.c */
int type;
unsigned int lseek_err_cnt;
#if defined(__linux__)
@@ -233,180 +233,18 @@ label__raw_write__success:
/***********************************************************/
/* Unix AIO using POSIX AIO */
-typedef struct RawAIOCB {
- BlockDriverAIOCB common;
- struct aiocb aiocb;
- struct RawAIOCB *next;
-} RawAIOCB;
-
-static int aio_sig_num = SIGUSR2;
-static RawAIOCB *first_aio; /* AIO issued */
-static int aio_initialized = 0;
-
-static void aio_signal_handler(int signum)
-{
-#ifndef QEMU_IMG
- CPUState *env = cpu_single_env;
- if (env) {
- /* stop the currently executing cpu because a timer occured */
- cpu_interrupt(env, CPU_INTERRUPT_EXIT);
-#ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- kqemu_cpu_interrupt(env);
- }
-#endif
- }
-#endif
-}
-
-void qemu_aio_init(void)
-{
- struct sigaction act;
-
- aio_initialized = 1;
-
- sigfillset(&act.sa_mask);
- act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
- act.sa_handler = aio_signal_handler;
- sigaction(aio_sig_num, &act, NULL);
-
-#if defined(__GLIBC__) && defined(__linux__)
- {
- /* XXX: aio thread exit seems to hang on RedHat 9 and this init
- seems to fix the problem. */
- struct aioinit ai;
- memset(&ai, 0, sizeof(ai));
- ai.aio_threads = 1;
- ai.aio_num = 1;
- ai.aio_idle_time = 365 * 100000;
- aio_init(&ai);
- }
-#endif
-}
-
-void qemu_aio_poll(void)
-{
- RawAIOCB *acb, **pacb;
- int ret;
-
- for(;;) {
- pacb = &first_aio;
- for(;;) {
- acb = *pacb;
- if (!acb)
- goto the_end;
- ret = aio_error(&acb->aiocb);
- if (ret == ECANCELED) {
- /* remove the request */
- *pacb = acb->next;
- qemu_aio_release(acb);
- } else if (ret != EINPROGRESS) {
- /* end of aio */
- if (ret == 0) {
- ret = aio_return(&acb->aiocb);
- if (ret == acb->aiocb.aio_nbytes)
- ret = 0;
- else
- ret = -EINVAL;
- } else {
- ret = -ret;
- }
- /* remove the request */
- *pacb = acb->next;
- /* call the callback */
- acb->common.cb(acb->common.opaque, ret);
- qemu_aio_release(acb);
- break;
- } else {
- pacb = &acb->next;
- }
- }
- }
- the_end: ;
-}
-
-/* Wait for all IO requests to complete. */
-void qemu_aio_flush(void)
-{
- qemu_aio_wait_start();
- qemu_aio_poll();
- while (first_aio) {
- qemu_aio_wait();
- }
- qemu_aio_wait_end();
-}
-
-/* wait until at least one AIO was handled */
-static sigset_t wait_oset;
-
-void qemu_aio_wait_start(void)
-{
- sigset_t set;
-
- if (!aio_initialized)
- qemu_aio_init();
- sigemptyset(&set);
- sigaddset(&set, aio_sig_num);
- sigprocmask(SIG_BLOCK, &set, &wait_oset);
-}
-
-void qemu_aio_wait(void)
-{
- sigset_t set;
- int nb_sigs;
-
-#ifndef QEMU_IMG
- if (qemu_bh_poll())
- return;
-#endif
- sigemptyset(&set);
- sigaddset(&set, aio_sig_num);
- sigwait(&set, &nb_sigs);
- qemu_aio_poll();
-}
-
-void qemu_aio_wait_end(void)
-{
- sigprocmask(SIG_SETMASK, &wait_oset, NULL);
-}
-
-static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
+static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
int64_t sector_num, uint8_t *buf, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
- BDRVRawState *s = bs->opaque;
RawAIOCB *acb;
if (fd_open(bs) < 0)
return NULL;
- acb = qemu_aio_get(bs, cb, opaque);
- if (!acb)
- return NULL;
- acb->aiocb.aio_fildes = s->fd;
- acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
- acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
- acb->aiocb.aio_buf = buf;
- acb->aiocb.aio_nbytes = nb_sectors * 512;
- acb->aiocb.aio_offset = sector_num * 512;
- acb->next = first_aio;
- first_aio = acb;
- return acb;
-}
+ acb = qemu_aio_read(bs, sector_num * 512, buf, nb_sectors * 512,
+ cb, opaque);
-static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
- int64_t sector_num, uint8_t *buf, int nb_sectors,
- BlockDriverCompletionFunc *cb, void *opaque)
-{
- RawAIOCB *acb;
-
- acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
- if (!acb)
- return NULL;
- if (aio_read(&acb->aiocb) < 0) {
- qemu_aio_release(acb);
- return NULL;
- }
return &acb->common;
}
@@ -416,41 +254,20 @@ static BlockDriverAIOCB *raw_aio_write(B
{
RawAIOCB *acb;
- acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
- if (!acb)
- return NULL;
- if (aio_write(&acb->aiocb) < 0) {
- qemu_aio_release(acb);
+ if (fd_open(bs) < 0)
return NULL;
- }
+
+ acb = qemu_aio_write(bs, sector_num * 512, buf, nb_sectors * 512,
+ cb, opaque);
+
return &acb->common;
}
static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
{
- int ret;
RawAIOCB *acb = (RawAIOCB *)blockacb;
- RawAIOCB **pacb;
- ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
- if (ret == AIO_NOTCANCELED) {
- /* fail safe: if the aio could not be canceled, we wait for
- it */
- while (aio_error(&acb->aiocb) == EINPROGRESS);
- }
-
- /* remove the callback from the queue */
- pacb = &first_aio;
- for(;;) {
- if (*pacb == NULL) {
- break;
- } else if (*pacb == acb) {
- *pacb = acb->next;
- qemu_aio_release(acb);
- break;
- }
- pacb = &acb->next;
- }
+ qemu_aio_cancel(acb);
}
static void raw_close(BlockDriverState *bs)
Index: qemu/Makefile
===================================================================
--- qemu.orig/Makefile 2008-01-23 09:18:17.000000000 +0100
+++ qemu/Makefile 2008-01-23 09:19:30.000000000 +0100
@@ -136,7 +136,7 @@ QEMU_IMG_BLOCK_OBJS = $(BLOCK_OBJS)
ifdef CONFIG_WIN32
QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-win32.o
else
-QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-posix.o
+QEMU_IMG_BLOCK_OBJS += qemu-img-block-raw-posix.o qemu-img-qemu-aio-posix.o
endif
######################################################################
Index: qemu/qemu-aio-posix.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu/qemu-aio-posix.c 2008-01-23 09:19:30.000000000 +0100
@@ -0,0 +1,241 @@
+/*
+ * QEMU Asynchronous I/O
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu-common.h"
+#include <aio.h>
+#ifndef QEMU_IMG
+#include "qemu-timer.h"
+#include "exec-all.h"
+#endif
+#include "block_int.h"
+#include "qemu-aio-posix.h"
+
+static void aio_signal_handler(int signum)
+{
+#ifndef QEMU_IMG
+ CPUState *env = cpu_single_env;
+ if (env) {
+ /* stop the currently executing cpu because a timer occured */
+ cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+#ifdef USE_KQEMU
+ if (env->kqemu_enabled) {
+ kqemu_cpu_interrupt(env);
+ }
+#endif
+ }
+#endif
+}
+
+static int aio_initialized = 0;
+static int aio_sig_num = SIGUSR2;
+static RawAIOCB *first_aio; /* AIO issued */
+
+void qemu_aio_init(void)
+{
+ struct sigaction act;
+
+ aio_initialized = 1;
+
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
+ act.sa_handler = aio_signal_handler;
+ sigaction(aio_sig_num, &act, NULL);
+
+#if defined(__GLIBC__) && defined(__linux__)
+ {
+ /* XXX: aio thread exit seems to hang on RedHat 9 and this init
+ seems to fix the problem. */
+ struct aioinit ai;
+ memset(&ai, 0, sizeof(ai));
+ ai.aio_threads = 1;
+ ai.aio_num = 1;
+ ai.aio_idle_time = 365 * 100000;
+ aio_init(&ai);
+ }
+#endif
+}
+
+void qemu_aio_poll(void)
+{
+ RawAIOCB *acb, **pacb;
+ int ret;
+
+ for(;;) {
+ pacb = &first_aio;
+ for(;;) {
+ acb = *pacb;
+ if (!acb)
+ goto the_end;
+ ret = aio_error(&acb->aiocb);
+ if (ret == ECANCELED) {
+ /* remove the request */
+ *pacb = acb->next;
+ qemu_aio_release(acb);
+ } else if (ret != EINPROGRESS) {
+ /* end of aio */
+ if (ret == 0) {
+ ret = aio_return(&acb->aiocb);
+ if (ret == acb->aiocb.aio_nbytes)
+ ret = 0;
+ else
+ ret = -EINVAL;
+ } else {
+ ret = -ret;
+ }
+ /* remove the request */
+ *pacb = acb->next;
+ /* call the callback */
+ acb->common.cb(acb->common.opaque, ret);
+ qemu_aio_release(acb);
+ break;
+ } else {
+ pacb = &acb->next;
+ }
+ }
+ }
+ the_end: ;
+}
+
+/* Wait for all IO requests to complete. */
+void qemu_aio_flush(void)
+{
+ qemu_aio_wait_start();
+ qemu_aio_poll();
+ while (first_aio) {
+ qemu_aio_wait();
+ }
+ qemu_aio_wait_end();
+}
+
+/* wait until at least one AIO was handled */
+static sigset_t wait_oset;
+
+void qemu_aio_wait_start(void)
+{
+ sigset_t set;
+
+ if (!aio_initialized)
+ qemu_aio_init();
+ sigemptyset(&set);
+ sigaddset(&set, aio_sig_num);
+ sigprocmask(SIG_BLOCK, &set, &wait_oset);
+}
+
+void qemu_aio_wait(void)
+{
+ sigset_t set;
+ int nb_sigs;
+
+#ifndef QEMU_IMG
+ if (qemu_bh_poll())
+ return;
+#endif
+ sigemptyset(&set);
+ sigaddset(&set, aio_sig_num);
+ sigwait(&set, &nb_sigs);
+ qemu_aio_poll();
+}
+
+void qemu_aio_wait_end(void)
+{
+ sigprocmask(SIG_SETMASK, &wait_oset, NULL);
+}
+
+static RawAIOCB *qemu_aio_setup(BlockDriverState *bs,
+ int64_t offset, uint8_t *buf, int nb_bytes,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ int fd = *(int*)bs->opaque;
+ RawAIOCB *acb;
+
+ acb = qemu_aio_get(bs, cb, opaque);
+ if (!acb)
+ return NULL;
+ acb->aiocb.aio_fildes = fd;
+ acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
+ acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ acb->aiocb.aio_buf = buf;
+ acb->aiocb.aio_nbytes = nb_bytes;
+ acb->aiocb.aio_offset = offset;
+ acb->next = first_aio;
+ first_aio = acb;
+ return acb;
+}
+
+RawAIOCB *qemu_aio_read(BlockDriverState *bs,
+ int64_t offset, uint8_t *buf, int nb_bytes,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ RawAIOCB *acb;
+
+ acb = qemu_aio_setup(bs, offset, buf, nb_bytes, cb, opaque);
+ if (!acb)
+ return NULL;
+ if (aio_read(&acb->aiocb) < 0) {
+ qemu_aio_release(acb);
+ return NULL;
+ }
+ return acb;
+}
+
+RawAIOCB *qemu_aio_write(BlockDriverState *bs,
+ int64_t offset, const uint8_t *buf, int nb_bytes,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ RawAIOCB *acb;
+
+ acb = qemu_aio_setup(bs, offset, (uint8_t*)buf, nb_bytes, cb, opaque);
+ if (!acb)
+ return NULL;
+ if (aio_write(&acb->aiocb) < 0) {
+ qemu_aio_release(acb);
+ return NULL;
+ }
+ return acb;
+}
+
+void qemu_aio_cancel(RawAIOCB *acb)
+{
+ int ret;
+ RawAIOCB **pacb;
+
+ ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
+ if (ret == AIO_NOTCANCELED) {
+ /* fail safe: if the aio could not be canceled, we wait for
+ it */
+ while (aio_error(&acb->aiocb) == EINPROGRESS);
+ }
+
+ /* remove the callback from the queue */
+ pacb = &first_aio;
+ for(;;) {
+ if (*pacb == NULL) {
+ break;
+ } else if (*pacb == acb) {
+ *pacb = acb->next;
+ qemu_aio_release(acb);
+ break;
+ }
+ pacb = &acb->next;
+ }
+}
Index: qemu/qemu-aio-posix.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu/qemu-aio-posix.h 2008-01-23 09:19:30.000000000 +0100
@@ -0,0 +1,39 @@
+/*
+ * QEMU Asynchronous I/O
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <aio.h>
+
+typedef struct RawAIOCB {
+ BlockDriverAIOCB common;
+ struct aiocb aiocb;
+ struct RawAIOCB *next;
+} RawAIOCB;
+
+RawAIOCB *qemu_aio_read(BlockDriverState *bs,
+ int64_t offset, uint8_t *buf, int nb_bytes,
+ BlockDriverCompletionFunc *cb, void *opaque);
+RawAIOCB *qemu_aio_write(BlockDriverState *bs,
+ int64_t offset, const uint8_t *buf, int nb_bytes,
+ BlockDriverCompletionFunc *cb, void *opaque);
+void qemu_aio_cancel(RawAIOCB *acb);
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Qemu-devel] [PATCH 5/5] SCSI device DMA split
2008-01-23 16:12 ` [Qemu-devel] [PATCH 4/5] DVD movie support Laurent Vivier
@ 2008-01-23 16:12 ` Laurent Vivier
0 siblings, 0 replies; 8+ messages in thread
From: Laurent Vivier @ 2008-01-23 16:12 UTC (permalink / raw)
Cc: qemu-devel
With some emulated SCSI devices, like usb-storage or ide-scsi, DMA transfers
are limited to 64 kiB or 32 kiB.
This patch allows to split a READ or WRITE into several READ or WRITE.
Laurent
---
block-sg.c | 1
hw/scsi-generic.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 105 insertions(+), 6 deletions(-)
Index: qemu/hw/scsi-generic.c
===================================================================
--- qemu.orig/hw/scsi-generic.c 2008-01-23 15:29:26.000000000 +0100
+++ qemu/hw/scsi-generic.c 2008-01-23 15:29:26.000000000 +0100
@@ -60,6 +60,8 @@ do { fprintf(stderr, "scsi-generic: " fm
#define MAX_UINT ((unsigned int)-1)
#endif
+#define MAX_CHUNK 65536
+
typedef struct SCSIRequest {
SGRequest sg;
struct SCSIRequest *next;
@@ -70,6 +72,8 @@ typedef struct SCSIRequest {
uint8_t *buf;
int buflen;
int len;
+ int remaining;
+ int offset;
} SCSIRequest;
struct SCSIDeviceState
@@ -81,6 +85,7 @@ struct SCSIDeviceState
void *card;
int driver_status;
uint8_t sensebuf[SCSI_SENSE_BUF_SIZE];
+ int max_chunk;
};
/* Global pool of SCSIRequest structures. */
@@ -98,6 +103,7 @@ static SCSIRequest *scsi_new_request(SCS
r->buf = NULL;
r->buflen = 0;
}
+ r->offset = 0;
r->dev = s;
r->tag = tag;
memset(r->cmd, 0, sizeof(r->cmd));
@@ -186,23 +192,93 @@ static void scsi_cancel_io(SCSIDevice *d
}
}
+static void scsi_cmd_next(uint8_t *cmd, uint32_t inc)
+{
+ uint32_t addr;
+ switch (cmd[0] >> 5) {
+ case 0:
+ addr = cmd[3] | (cmd[2] << 8);
+ addr += inc;
+ cmd[2] = addr >> 8;
+ cmd[3] = addr;
+ break;
+ case 1:
+ case 2:
+ case 4:
+ case 5:
+ addr = cmd[5] | ((cmd[4] << 8) | ((cmd[3] << 16) | (cmd[2] << 24)));
+ addr += inc;
+ cmd[2] = addr >> 24;
+ cmd[3] = addr >> 16;
+ cmd[4] = addr >> 8;
+ cmd[5] = addr;
+ break;
+ }
+}
+static void scsi_set_length(uint8_t *cmd, uint32_t len)
+{
+ switch (cmd[0] >> 5) {
+ case 0:
+ cmd[4] = len;
+ break;
+ case 1:
+ case 2:
+ cmd[7] = (len >> 8);
+ cmd[8] = len;
+ break;
+ case 4:
+ cmd[10] = len >> 24;
+ cmd[11] = len >> 16;
+ cmd[12] = len >> 8;
+ cmd[13] = len;
+ break;
+ case 5:
+ cmd[6] = len >> 24;
+ cmd[7] = len >> 16;
+ cmd[8] = len >> 8;
+ cmd[9] = len;
+ break;
+ }
+}
+
+
static int execute_command(BlockDriverState *bdrv,
SCSIRequest *r, int direction,
BlockDriverCompletionFunc *complete)
{
+ int ret;
+ SCSIDeviceState *s = r->dev;
+
+ r->remaining = 0;
+retry:
+ if (s->max_chunk && r->buflen > s->max_chunk) {
+ r->remaining = r->buflen - s->max_chunk;
+ scsi_set_length(r->cmd, s->max_chunk / s->blocksize);
+ r->buflen = s->max_chunk;
+ }
memset(&r->sg, 0, sizeof(r->sg));
r->sg.io_header.interface_id = 'S';
+ r->sg.io_header.dxferp = r->buf + r->offset;
r->sg.io_header.dxfer_direction = direction;
r->sg.io_header.cmd_len = r->cmdlen;
- r->sg.io_header.mx_sb_len = sizeof(r->dev->sensebuf);
r->sg.io_header.dxfer_len = r->buflen;
- r->sg.io_header.dxferp = r->buf;
+ r->sg.io_header.mx_sb_len = sizeof(s->sensebuf);
+ r->sg.io_header.sbp = s->sensebuf;
r->sg.io_header.cmdp = r->cmd;
- r->sg.io_header.sbp = r->dev->sensebuf;
r->sg.io_header.timeout = MAX_UINT;
r->sg.io_header.flags |= SG_FLAG_DIRECT_IO;
- return bdrv_execute(bdrv, &r->sg, complete);
+ ret = bdrv_execute(bdrv, &r->sg, complete);
+ if (ret == -1 && errno == 12) {
+ if (!s->max_chunk) {
+ s->max_chunk = MAX_CHUNK;
+ goto retry;
+ } else if (s->max_chunk > s->blocksize) {
+ s->max_chunk >>= 1;
+ goto retry;
+ }
+ }
+ return ret;
}
static void scsi_read_complete(void *request, int ret)
@@ -216,7 +292,18 @@ static void scsi_read_complete(void *req
scsi_command_complete(r, ret);
return;
}
- len = r->sg.io_header.dxfer_len - r->sg.io_header.resid;
+ r->offset += r->sg.io_header.dxfer_len - r->sg.io_header.resid;
+ if (r->remaining != 0) {
+ scsi_cmd_next(r->cmd, r->buflen / s->blocksize);
+ scsi_set_length(r->cmd, r->remaining / s->blocksize);
+ r->buflen = r->remaining;
+ ret = execute_command(s->bdrv, r, SG_DXFER_FROM_DEV,
+ scsi_read_complete);
+ if (ret == -1)
+ scsi_command_complete(r, -EINVAL);
+ return;
+ }
+ len = r->offset;
DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, len);
r->len = -1;
@@ -263,12 +350,24 @@ static void scsi_read_data(SCSIDevice *d
static void scsi_write_complete(void* request, int ret)
{
SCSIRequest* r = (SCSIRequest*)request;
+ SCSIDeviceState *s = r->dev;
DPRINTF("scsi_write_complete() ret = %d\n", ret);
if (ret) {
DPRINTF("IO error\n");
scsi_command_complete(r, ret);
return;
}
+ r->offset += r->sg.io_header.dxfer_len - r->sg.io_header.resid;
+ if (r->remaining != 0) {
+ scsi_cmd_next(r->cmd, r->buflen / s->blocksize);
+ scsi_set_length(r->cmd, r->remaining / s->blocksize);
+ r->buflen = r->remaining;
+ ret = execute_command(s->bdrv, r, SG_DXFER_TO_DEV,
+ scsi_write_complete);
+ if (ret == -1)
+ scsi_command_complete(r, -EINVAL);
+ return;
+ }
scsi_command_complete(r, ret);
}
@@ -591,6 +690,7 @@ SCSIDevice *scsi_generic_init(BlockDrive
s->card = card;
s->blocksize = get_blocksize(s->bdrv);
s->driver_status = 0;
+ s->max_chunk = 0;
memset(s->sensebuf, 0, sizeof(s->sensebuf));
/* removable media returns 0 if not present */
if (s->blocksize <= 0)
Index: qemu/block-sg.c
===================================================================
--- qemu.orig/block-sg.c 2008-01-23 15:33:03.000000000 +0100
+++ qemu/block-sg.c 2008-01-23 15:33:28.000000000 +0100
@@ -151,7 +151,6 @@ int sg_execute(BlockDriverState *bs, voi
if (sg_write(bs, (const uint8_t *)&r->io_header,
sizeof(r->io_header)) == -1) {
- BADF("execute_command: write failed ! (%d)\n", errno);
return -1;
}
if (complete == NULL) {
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH 0/5] SCSI passthrough cleanup
2008-01-23 16:12 [Qemu-devel] [PATCH 0/5] SCSI passthrough cleanup Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 1/5] reverse scsi-generic Laurent Vivier
@ 2008-01-23 20:52 ` Fabrice Bellard
2008-01-24 8:17 ` Laurent Vivier
1 sibling, 1 reply; 8+ messages in thread
From: Fabrice Bellard @ 2008-01-23 20:52 UTC (permalink / raw)
To: Laurent Vivier, qemu-devel
Two questions:
- Why do you use AIO ? If the Linux sg device supports selects, then
using the QEMU select() callback suffices.
- Why do you use a block device ?
Regards,
Fabrice.
Laurent Vivier wrote:
> This series of patches makes some cleanups in SCSI passthrough and
> add functionnalities.
>
> [PATCH 1/5] reverse scsi-generic
>
> Reverse previous implementation and restore block-raw-posix.c.
>
> [PATCH 2/5] Move AIO
>
> This patche moves raw AIO part from block-raw-posix.c to qemu-aio-raw.c.
>
> [PATCH 3/5] Add block SG interface
>
> This patch re-implement scsi-generic.c using a new block interface.
>
> [PATCH 4/5] DVD movie support
>
> This patch allows to read a protected/encrypted movie from a DVD.
>
> [PATCH 5/5] SCSI device DMA split
>
> This patch allows to split a READ or WRITE into several READ or WRITE.
>
> Laurent
>
>
>
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] [PATCH 0/5] SCSI passthrough cleanup
2008-01-23 20:52 ` [Qemu-devel] [PATCH 0/5] SCSI passthrough cleanup Fabrice Bellard
@ 2008-01-24 8:17 ` Laurent Vivier
0 siblings, 0 replies; 8+ messages in thread
From: Laurent Vivier @ 2008-01-24 8:17 UTC (permalink / raw)
To: Fabrice Bellard; +Cc: qemu-devel
Le mercredi 23 janvier 2008 à 21:52 +0100, Fabrice Bellard a écrit :
> Two questions:
>
> - Why do you use AIO ? If the Linux sg device supports selects, then
> using the QEMU select() callback suffices.
Basically because when I want to have asynchronous I/O I use AIO...
If you explain me briefly how to use selects in Qemu I can try.
> - Why do you use a block device ?
Because to communicate with SG device we need a file descriptor, and
using current mechanism (with -drive) allows to have this file
descriptor without modifying anything else (without adding a new
parameter). Moreover, to use Qemu AIO I need a BlockDriverState (but it
related to the first question...)
I agree to change all of this if you give me tips to use selects in Qemu
and if you thing adding a new command line parameter is not an issue.
> Regards,
>
> Fabrice.
Thank you for your comments and help,
Laurent
> Laurent Vivier wrote:
> > This series of patches makes some cleanups in SCSI passthrough and
> > add functionnalities.
> >
> > [PATCH 1/5] reverse scsi-generic
> >
> > Reverse previous implementation and restore block-raw-posix.c.
> >
> > [PATCH 2/5] Move AIO
> >
> > This patche moves raw AIO part from block-raw-posix.c to qemu-aio-raw.c.
> >
> > [PATCH 3/5] Add block SG interface
> >
> > This patch re-implement scsi-generic.c using a new block interface.
> >
> > [PATCH 4/5] DVD movie support
> >
> > This patch allows to read a protected/encrypted movie from a DVD.
> >
> > [PATCH 5/5] SCSI device DMA split
> >
> > This patch allows to split a READ or WRITE into several READ or WRITE.
> >
> > Laurent
> >
> >
> >
> >
> >
>
>
--
----------------- Laurent.Vivier@bull.net ------------------
"La perfection est atteinte non quand il ne reste rien à
ajouter mais quand il ne reste rien à enlever." Saint Exupéry
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2008-01-24 8:18 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-23 16:12 [Qemu-devel] [PATCH 0/5] SCSI passthrough cleanup Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 1/5] reverse scsi-generic Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 2/5] Move AIO Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 3/5] Add block SG interface Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 4/5] DVD movie support Laurent Vivier
2008-01-23 16:12 ` [Qemu-devel] [PATCH 5/5] SCSI device DMA split Laurent Vivier
2008-01-23 20:52 ` [Qemu-devel] [PATCH 0/5] SCSI passthrough cleanup Fabrice Bellard
2008-01-24 8:17 ` Laurent Vivier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).