Skip to contentSkip to conversation

Real SCSI device passthrough

PATCH In review Laurent Vivier 4 participants 8 messages Dec 7, 2007 – Dec 9, 2007 Kbuild

lore
Share & tools
lore
#0 lore raw

cover Real SCSI device passthrough

This series of patches allows to connect real SCSI device to the virtual SCSI controller of Qemu using the SCSI Generic interface (/dev/sg)

for instance:

qemu -hda my_disk.qcow2 -drive file=/dev/sg3,if=scsi

[PATCH 1/2] SCSI cleanup

This patch reworks the interface between SCSI controller and SCSI device.

[PATCH 2/2] Real SCSI device passthrough (v3)

This patch allows to connect the virtual SCSI interface of Qemu to a real SCSI device of the host.

Laurent

#1 lore raw

PATCH 1/2 SCSI cleanup

This patch reworks the interface between SCSI controller and SCSI device. It allows to connect something else than scsi-disk.c to the SCSI controller.

It is needed to use SCSI passthrough patch.

Laurent

---
 hw/esp.c        |   16 +++++++-------
 hw/lsi53c895a.c |   41 ++++++++++++++++++++++++-------------
 hw/scsi-disk.c  |   62 ++++++++++++++++++++++++++++++++++----------------------
 hw/scsi-disk.h  |   27 ++++++++++++------------
 hw/usb-msd.c    |   16 +++++++-------
 5 files changed, 95 insertions(+), 67 deletions(-)
hw/scsi-disk.c +38 -24
Index: qemu/hw/scsi-disk.c
===================================================================
@@ -37,7 +37,7 @@ do { fprintf(stderr, "scsi-disk: " fmt ,
 #define SCSI_DMA_BUF_SIZE    65536
 
 typedef struct SCSIRequest {
-    SCSIDevice *dev;
+    SCSIDeviceState *dev;
     uint32_t tag;
     /* ??? We should probably keep track of whether the data trasfer is
        a read or a write.  Currently we rely on the host getting it right.  */
@@ -51,7 +51,7 @@ typedef struct SCSIRequest {
     struct SCSIRequest *next;
 } SCSIRequest;
 
-struct SCSIDevice
+struct SCSIDeviceState
 {
     BlockDriverState *bdrv;
     SCSIRequest *requests;
@@ -69,7 +69,7 @@ struct SCSIDevice
 /* Global pool of SCSIRequest structures.  */
 static SCSIRequest *free_requests = NULL;
 
-static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag)
+static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
 {
     SCSIRequest *r;
 
@@ -94,7 +94,7 @@ static SCSIRequest *scsi_new_request(SCS
 static void scsi_remove_request(SCSIRequest *r)
 {
     SCSIRequest *last;
-    SCSIDevice *s = r->dev;
+    SCSIDeviceState *s = r->dev;
 
     if (s->requests == r) {
         s->requests = r->next;
@@ -112,7 +112,7 @@ static void scsi_remove_request(SCSIRequ
     free_requests = r;
 }
 
-static SCSIRequest *scsi_find_request(SCSIDevice *s, uint32_t tag)
+static SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag)
 {
     SCSIRequest *r;
 
@@ -126,7 +126,7 @@ static SCSIRequest *scsi_find_request(SC
 /* Helper function for command completion.  */
 static void scsi_command_complete(SCSIRequest *r, int sense)
 {
-    SCSIDevice *s = r->dev;
+    SCSIDeviceState *s = r->dev;
     uint32_t tag;
     DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense);
     s->sense = sense;
@@ -136,8 +136,9 @@ static void scsi_command_complete(SCSIRe
 }
 
 /* Cancel a pending data transfer.  */
-void scsi_cancel_io(SCSIDevice *s, uint32_t tag)
+static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
 {
+    SCSIDeviceState *s = d->state;
     SCSIRequest *r;
     DPRINTF("Cancel tag=0x%x\n", tag);
     r = scsi_find_request(s, tag);
@@ -152,7 +153,7 @@ void scsi_cancel_io(SCSIDevice *s, uint3
 static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIRequest *r = (SCSIRequest *)opaque;
-    SCSIDevice *s = r->dev;
+    SCSIDeviceState *s = r->dev;
 
     if (ret) {
         DPRINTF("IO error\n");
@@ -165,8 +166,9 @@ static void scsi_read_complete(void * op
 }
 
 /* Read more data from scsi device into buffer.  */
-void scsi_read_data(SCSIDevice *s, uint32_t tag)
+static void scsi_read_data(SCSIDevice *d, uint32_t tag)
 {
+    SCSIDeviceState *s = d->state;
     SCSIRequest *r;
     uint32_t n;
 
@@ -205,7 +207,7 @@ void scsi_read_data(SCSIDevice *s, uint3
 static void scsi_write_complete(void * opaque, int ret)
 {
     SCSIRequest *r = (SCSIRequest *)opaque;
-    SCSIDevice *s = r->dev;
+    SCSIDeviceState *s = r->dev;
     uint32_t len;
 
     if (ret) {
@@ -229,8 +231,9 @@ static void scsi_write_complete(void * o
 
 /* Write data to a scsi device.  Returns nonzero on failure.
    The transfer may complete asynchronously.  */
-int scsi_write_data(SCSIDevice *s, uint32_t tag)
+static int scsi_write_data(SCSIDevice *d, uint32_t tag)
 {
+    SCSIDeviceState *s = d->state;
     SCSIRequest *r;
     uint32_t n;
 
@@ -260,8 +263,9 @@ int scsi_write_data(SCSIDevice *s, uint3
 }
 
 /* Return a pointer to the data buffer.  */
-uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag)
+static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
 {
+    SCSIDeviceState *s = d->state;
     SCSIRequest *r;
 
     r = scsi_find_request(s, tag);
@@ -277,8 +281,10 @@ uint8_t *scsi_get_buf(SCSIDevice *s, uin
    (eg. disk reads), negative for transfers to the device (eg. disk writes),
    and zero if the command does not transfer any data.  */
 
-int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
+static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
+                                 uint8_t *buf, int lun)
 {
+    SCSIDeviceState *s = d->state;
     int64_t nb_sectors;
     uint32_t lba;
     uint32_t len;
@@ -292,7 +298,7 @@ int32_t scsi_send_command(SCSIDevice *s,
     r = scsi_find_request(s, tag);
     if (r) {
         BADF("Tag 0x%x already in use\n", tag);
-        scsi_cancel_io(s, tag);
+        scsi_cancel_io(d, tag);
     }
     /* ??? Tags are not unique for different luns.  We only implement a
        single lun, so this should not matter.  */
@@ -577,19 +583,19 @@ int32_t scsi_send_command(SCSIDevice *s,
     }
 }
 
-void scsi_disk_destroy(SCSIDevice *s)
+static void scsi_destroy(SCSIDevice *d)
 {
-    qemu_free(s);
+    qemu_free(d->state);
+    qemu_free(d);
 }
 
-SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
-                           int tcq,
-                           scsi_completionfn completion,
-                           void *opaque)
+SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
+                           scsi_completionfn completion, void *opaque)
 {
-    SCSIDevice *s;
+    SCSIDevice *d;
+    SCSIDeviceState *s;
 
-    s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
+    s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState));
     s->bdrv = bdrv;
     s->tcq = tcq;
     s->completion = completion;
@@ -600,6 +606,14 @@ SCSIDevice *scsi_disk_init(BlockDriverSt
         s->cluster_size = 1;
     }
 
-    return s;
-}
+    d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
+    d->state = s;
+    d->destroy = scsi_destroy;
+    d->send_command = scsi_send_command;
+    d->read_data = scsi_read_data;
+    d->write_data = scsi_write_data;
+    d->cancel_io = scsi_cancel_io;
+    d->get_buf = scsi_get_buf;
 
+    return d;
+}
hw/esp.c +8 -8
Index: qemu/hw/esp.c
===================================================================
@@ -165,7 +165,7 @@ static int get_cmd(ESPState *s, uint8_t 
 
     if (s->current_dev) {
         /* Started a new command before the old one finished.  Cancel it.  */
-        scsi_cancel_io(s->current_dev, 0);
+        s->current_dev->cancel_io(s->current_dev, 0);
         s->async_len = 0;
     }
 
@@ -188,7 +188,7 @@ static void do_cmd(ESPState *s, uint8_t 
 
     DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
     lun = buf[0] & 7;
-    datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
+    datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun);
     s->ti_size = datalen;
     if (datalen != 0) {
         s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC;
@@ -196,10 +196,10 @@ static void do_cmd(ESPState *s, uint8_t 
         s->dma_counter = 0;
         if (datalen > 0) {
             s->rregs[ESP_RSTAT] |= STAT_DI;
-            scsi_read_data(s->current_dev, 0);
+            s->current_dev->read_data(s->current_dev, 0);
         } else {
             s->rregs[ESP_RSTAT] |= STAT_DO;
-            scsi_write_data(s->current_dev, 0);
+            s->current_dev->write_data(s->current_dev, 0);
         }
     }
     s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
@@ -298,9 +298,9 @@ static void esp_do_dma(ESPState *s)
     if (s->async_len == 0) {
         if (to_device) {
             // ti_size is negative
-            scsi_write_data(s->current_dev, 0);
+            s->current_dev->write_data(s->current_dev, 0);
         } else {
-            scsi_read_data(s->current_dev, 0);
+            s->current_dev->read_data(s->current_dev, 0);
             /* If there is still data to be read from the device then
                complete the DMA operation immeriately.  Otherwise defer
                until the scsi layer has completed.  */
@@ -335,7 +335,7 @@ static void esp_command_complete(void *o
     } else {
         DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
         s->async_len = arg;
-        s->async_buf = scsi_get_buf(s->current_dev, 0);
+        s->async_buf = s->current_dev->get_buf(s->current_dev, 0);
         if (s->dma_left) {
             esp_do_dma(s);
         } else if (s->dma_counter != 0 && s->ti_size <= 0) {
@@ -611,7 +611,7 @@ void esp_scsi_attach(void *opaque, Block
     }
     if (s->scsi_dev[id]) {
         DPRINTF("Destroying device %d\n", id);
-        scsi_disk_destroy(s->scsi_dev[id]);
+        s->scsi_dev[id]->destroy(s->scsi_dev[id]);
     }
     DPRINTF("Attaching block device %d\n", id);
     /* Command queueing is not implemented.  */
hw/lsi53c895a.c +27 -14

90 lines not on this page · raw message

hw/usb-msd.c +8 -8
Index: qemu/hw/usb-msd.c
===================================================================
@@ -149,9 +149,9 @@ static void usb_msd_copy_data(MSDState *
     s->data_len -= len;
     if (s->scsi_len == 0) {
         if (s->mode == USB_MSDM_DATAIN) {
-            scsi_read_data(s->scsi_dev, s->tag);
+            s->scsi_dev->read_data(s->scsi_dev, s->tag);
         } else if (s->mode == USB_MSDM_DATAOUT) {
-            scsi_write_data(s->scsi_dev, s->tag);
+            s->scsi_dev->write_data(s->scsi_dev, s->tag);
         }
     }
 }
@@ -204,7 +204,7 @@ static void usb_msd_command_complete(voi
         return;
     }
     s->scsi_len = arg;
-    s->scsi_buf = scsi_get_buf(s->scsi_dev, tag);
+    s->scsi_buf = s->scsi_dev->get_buf(s->scsi_dev, tag);
     if (p) {
         usb_msd_copy_data(s);
         if (s->usb_len == 0) {
@@ -342,7 +342,7 @@ static int usb_msd_handle_control(USBDev
 static void usb_msd_cancel_io(USBPacket *p, void *opaque)
 {
     MSDState *s = opaque;
-    scsi_cancel_io(s->scsi_dev, s->tag);
+    s->scsi_dev->cancel_io(s->scsi_dev, s->tag);
     s->packet = NULL;
     s->scsi_len = 0;
 }
@@ -390,14 +390,14 @@ static int usb_msd_handle_data(USBDevice
             DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
                     s->tag, cbw.flags, cbw.cmd_len, s->data_len);
             s->residue = 0;
-            scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
+            s->scsi_dev->send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
             /* ??? Should check that USB and SCSI data transfer
                directions match.  */
             if (s->residue == 0) {
                 if (s->mode == USB_MSDM_DATAIN) {
-                    scsi_read_data(s->scsi_dev, s->tag);
+                    s->scsi_dev->read_data(s->scsi_dev, s->tag);
                 } else if (s->mode == USB_MSDM_DATAOUT) {
-                    scsi_write_data(s->scsi_dev, s->tag);
+                    s->scsi_dev->write_data(s->scsi_dev, s->tag);
                 }
             }
             ret = len;
@@ -508,7 +508,7 @@ static void usb_msd_handle_destroy(USBDe
 {
     MSDState *s = (MSDState *)dev;
 
-    scsi_disk_destroy(s->scsi_dev);
+    s->scsi_dev->destroy(s->scsi_dev);
     bdrv_delete(s->bs);
     qemu_free(s);
 }
hw/scsi-disk.h +14 -13
Index: qemu/hw/scsi-disk.h
===================================================================
@@ -7,24 +7,25 @@ enum scsi_reason {
     SCSI_REASON_DATA  /* Transfer complete, more data required.  */
 };
 
+typedef struct SCSIDeviceState SCSIDeviceState;
 typedef struct SCSIDevice SCSIDevice;
 typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag,
                                   uint32_t arg);
 
-SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
-                           int tcq,
-                           scsi_completionfn completion,
-                           void *opaque);
-void scsi_disk_destroy(SCSIDevice *s);
+struct SCSIDevice
+{
+    SCSIDeviceState *state;
+    void (*destroy)(SCSIDevice *s);
+    int32_t (*send_command)(SCSIDevice *s, uint32_t tag, uint8_t *buf,
+                            int lun);
+    void (*read_data)(SCSIDevice *s, uint32_t tag);
+    int (*write_data)(SCSIDevice *s, uint32_t tag);
+    void (*cancel_io)(SCSIDevice *s, uint32_t tag);
+    uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag);
+};
 
-int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun);
-/* SCSI data transfers are asynchrnonous.  However, unlike the block IO
-   layer the completion routine may be called directly by
-   scsi_{read,write}_data.  */
-void scsi_read_data(SCSIDevice *s, uint32_t tag);
-int scsi_write_data(SCSIDevice *s, uint32_t tag);
-void scsi_cancel_io(SCSIDevice *s, uint32_t tag);
-uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag);
+SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
+                           scsi_completionfn completion, void *opaque);
 
 /* cdrom.c */
 int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
#2 lore raw

PATCH 2/2 Real SCSI device passthrough (v3)

This patch allows to connect the virtual SCSI interface of Qemu to a real SCSI device of the host.
Using the devices /dev/sg, it allows to send the SCSI commands from the virtual SCSI interface to the real device.

It has been tested with a SATA disk and an ATA CD burner with ide-scsi module and wodim to burn a CD-RW.

v3 has moved SCSI clenup to a separate patch.

Laurent

---
 Makefile          |    1 
 block-raw.c       |   23 +
 block.c           |   16 +
 block.h           |    2 
 block_int.h       |    4 
 hw/esp.c          |    4 
 hw/lsi53c895a.c   |    8 
 hw/scsi-disk.h    |    2 
 hw/scsi-generic.c |  667 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 722 insertions(+), 5 deletions(-)
block-raw.c +20 -3
Index: qemu/block-raw.c
===================================================================
@@ -152,7 +152,7 @@ static int raw_pread(BlockDriverState *b
     if (ret < 0)
         return ret;
 
-    if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
+    if (offset >= 0 && 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
@@ -205,7 +205,7 @@ static int raw_pwrite(BlockDriverState *
     if (ret < 0)
         return ret;
 
-    if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
+    if (offset >= 0 && 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) [%"
@@ -388,7 +388,10 @@ 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;
-    acb->aiocb.aio_nbytes = nb_sectors * 512;
+    if (nb_sectors < 0)
+        acb->aiocb.aio_nbytes = -nb_sectors;
+    else
+        acb->aiocb.aio_nbytes = nb_sectors * 512;
     acb->aiocb.aio_offset = sector_num * 512;
     acb->next = first_aio;
     first_aio = acb;
@@ -680,6 +683,8 @@ 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);
@@ -859,6 +864,12 @@ 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)
@@ -881,6 +892,10 @@ 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 = {
@@ -907,6 +922,8 @@ 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,
 };
 
 #else /* _WIN32 */
block.c +16 -0
Index: qemu/block.c
===================================================================
@@ -796,6 +796,11 @@ int bdrv_is_cached(BlockDriverState *bs)
     return bs->cache;
 }
 
+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)
@@ -1404,3 +1409,14 @@ 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;
+}
block.h +2 -0
Index: qemu/block.h
===================================================================
@@ -120,6 +120,7 @@ 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_is_cached(BlockDriverState *bs);
 int bdrv_media_changed(BlockDriverState *bs);
@@ -150,6 +151,7 @@ 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);
block_int.h +4 -0
Index: qemu/block_int.h
===================================================================
@@ -82,6 +82,9 @@ 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, char *buf);
+
     BlockDriverAIOCB *free_aiocb;
     struct BlockDriver *next;
 };
@@ -93,6 +96,7 @@ 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;
hw/esp.c +3 -1
Index: qemu/hw/esp.c
===================================================================
@@ -615,7 +615,9 @@ void esp_scsi_attach(void *opaque, Block
     }
     DPRINTF("Attaching block device %d\n", id);
     /* Command queueing is not implemented.  */
-    s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
+    s->scsi_dev[id] = scsi_generic_init(bd, 0, esp_command_complete, s);
+    if (s->scsi_dev[id] == NULL)
+        s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
 }
 
 void *esp_init(target_phys_addr_t espaddr,
hw/lsi53c895a.c +7 -1
Index: qemu/hw/lsi53c895a.c
===================================================================
@@ -1236,6 +1236,8 @@ static uint8_t lsi_reg_readb(LSIState *s
         return s->sdid;
     case 0x07: /* GPREG0 */
         return 0x7f;
+    case 0x08: /* Revision ID */
+        return 0x00;
     case 0xa: /* SSID */
         return s->ssid;
     case 0xb: /* SBCL */
@@ -1281,6 +1283,8 @@ static uint8_t lsi_reg_readb(LSIState *s
         return s->ctest4;
     case 0x22: /* CTEST5 */
         return s->ctest5;
+    case 0x23: /* CTEST6 */
+         return 0;
     case 0x24: /* DBC[0:7] */
         return s->dbc & 0xff;
     case 0x25: /* DBC[8:15] */
@@ -1838,7 +1842,9 @@ void lsi_scsi_attach(void *opaque, Block
         s->scsi_dev[id]->destroy(s->scsi_dev[id]);
     }
     DPRINTF("Attaching block device %d\n", id);
-    s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s);
+    s->scsi_dev[id] = scsi_generic_init(bd, 1, lsi_command_complete, s);
+    if (s->scsi_dev[id] == NULL)
+        s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s);
 }
 
 void *lsi_scsi_init(PCIBus *bus, int devfn)
hw/scsi-generic.c new file +667 -0

667 lines not on this page · raw message

Makefile +1 -0
Index: qemu/Makefile
===================================================================
@@ -56,6 +56,7 @@ OBJS+=irq.o
 OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
 OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o
 OBJS+=scsi-disk.o cdrom.o
+OBJS+=scsi-generic.o
 OBJS+=usb.o usb-hub.o usb-linux.o usb-hid.o usb-msd.o usb-wacom.o
 OBJS+=sd.o ssi-sd.o
 
hw/scsi-disk.h +2 -0
Index: qemu/hw/scsi-disk.h
===================================================================
@@ -26,6 +26,8 @@ struct SCSIDevice
 
 SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
                            scsi_completionfn completion, void *opaque);
+SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq,
+                           scsi_completionfn completion, void *opaque);
 
 /* cdrom.c */
 int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
#3 lore raw

Re: [Qemu-devel] [PATCH 2/2] Real SCSI device passthrough (v3)

Quoted 5 lines · Laurent Vivier

-    acb->aiocb.aio_nbytes = nb_sectors * 512;
+    if (nb_sectors < 0)
+        acb->aiocb.aio_nbytes = -nb_sectors;
+    else
+        acb->aiocb.aio_nbytes = nb_sectors * 512;

Ugly hacks like this need at least a decent comment.

Paul

#4 lore raw

Re: [Qemu-devel] [PATCH 2/2] Real SCSI device passthrough (v3)

Quoted 8 lines · Paul Brook

block-raw.c static RawAIOCB *raw_aio_setup(BlockDriv · line 394

Quoted 5 lines · Laurent Vivier
block-raw.c +4 -1
-    acb->aiocb.aio_nbytes = nb_sectors * 512;
+    if (nb_sectors < 0)
+        acb->aiocb.aio_nbytes = -nb_sectors;
+    else
+        acb->aiocb.aio_nbytes = nb_sectors * 512;

Ugly hacks like this need at least a decent comment.

Yes, you're right but I'm always wondering if it is the good way to do what I want: read a number of bytes instead of a number of sectors. Perhaps I should define a new function in the qemu AIO interface ?

There is another ugly hack, did you find it ? ;-)

Laurent

Signature · 3 lines
------------- [email protected]  --------------
       "Any sufficiently advanced technology is
  indistinguishable from magic." - Arthur C. Clarke
#5 lore raw

Re: [Qemu-devel] [PATCH 2/2] Real SCSI device passthrough (v3)

Quoted 10 lines · Laurent Vivier
Quoted 8 lines · Paul Brook
Quoted 6 lines · Laurent Vivier
block-raw.c +4 -1
-    acb->aiocb.aio_nbytes = nb_sectors * 512;
+    if (nb_sectors < 0)
+        acb->aiocb.aio_nbytes = -nb_sectors;
+    else
+        acb->aiocb.aio_nbytes = nb_sectors * 512;
Quoted 7 lines
Quoted 2 lines

Ugly hacks like this need at least a decent comment.

Yes, you're right but I'm always wondering if it is the good way to do what I want: read a number of bytes instead of a number of sectors. Perhaps I should define a new function in the qemu AIO interface ?

I think the crux of the problem is that you're using the BlockDriver API for something that isn't actually a block driver.

Regards,

Anthony Liguori

Quoted 4 lines

There is another ugly hack, did you find it ? ;-)

Laurent

#6 lore raw

Re: [Qemu-devel] [PATCH 2/2] Real SCSI device passthrough (v3)

Quoted 14 lines · Anthony Liguori
Quoted 13 lines · Laurent Vivier
Quoted 10 lines · Paul Brook

block-raw.c static RawAIOCB *raw_aio_setup(BlockDriv · line 394

Quoted 6 lines · Laurent Vivier
block-raw.c +4 -1
-    acb->aiocb.aio_nbytes = nb_sectors * 512;
+    if (nb_sectors < 0)
+        acb->aiocb.aio_nbytes = -nb_sectors;
+    else
+        acb->aiocb.aio_nbytes = nb_sectors * 512;

Ugly hacks like this need at least a decent comment.

Quoted 7 lines
Quoted 4 lines

Yes, you're right but I'm always wondering if it is the good way to do what I want: read a number of bytes instead of a number of sectors. Perhaps I should define a new function in the qemu AIO interface ?

I think the crux of the problem is that you're using the BlockDriver API for something that isn't actually a block driver.

Yes, I know, but I don't want to rewrite all block-raw.c just to change the granularity of the I/O access. It is the best solution I found, if you have some better ideas (and I know you have lot of good ideas), I take them.

Regards,
Laurent

Signature · 3 lines
------------- [email protected]  --------------
       "Any sufficiently advanced technology is
  indistinguishable from magic." - Arthur C. Clarke
#7 lore raw
In reply to Laurent Vivier
Quoted 7 lines · Laurent Vivier

This series of patches allows to connect real SCSI device to the virtual SCSI controller of Qemu using the SCSI Generic interface (/dev/sg)

for instance:

qemu -hda my_disk.qcow2 -drive file=/dev/sg3,if=scsi

Please update also the documentation to mention this example.

Quoted 14 lines

[PATCH 1/2] SCSI cleanup

This patch reworks the interface between SCSI controller and SCSI device.

[PATCH 2/2] Real SCSI device passthrough (v3)

This patch allows to connect the virtual SCSI interface of Qemu to a real SCSI device of the host.

Laurent