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 <[EMAIL PROTECTED]> + * + * 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 <[EMAIL PROTECTED]> + * + * 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; };