* [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 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 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 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 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).