From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MGukP-0001RE-PC for qemu-devel@nongnu.org; Wed, 17 Jun 2009 09:00:14 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MGukK-0001Ke-Gf for qemu-devel@nongnu.org; Wed, 17 Jun 2009 09:00:12 -0400 Received: from [199.232.76.173] (port=50796 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MGukK-0001KQ-90 for qemu-devel@nongnu.org; Wed, 17 Jun 2009 09:00:08 -0400 Received: from mx2.redhat.com ([66.187.237.31]:48443) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MGukJ-0004fT-2O for qemu-devel@nongnu.org; Wed, 17 Jun 2009 09:00:07 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n5HD05ho013699 for ; Wed, 17 Jun 2009 09:00:05 -0400 From: Gerd Hoffmann Date: Wed, 17 Jun 2009 14:59:25 +0200 Message-Id: <1245243565-24807-11-git-send-email-kraxel@redhat.com> In-Reply-To: <1245243565-24807-1-git-send-email-kraxel@redhat.com> References: <1245243565-24807-1-git-send-email-kraxel@redhat.com> Subject: [Qemu-devel] [PATCH 10/10] qdev-ify: scsi List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Gerd Hoffmann Signed-off-by: Gerd Hoffmann --- Makefile | 2 +- hw/esp.c | 28 +++++++++++---------- hw/lsi53c895a.c | 31 +++++++++++++---------- hw/qdev.c | 19 -------------- hw/qdev.h | 4 --- hw/scsi-bus.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++ hw/scsi-disk.c | 69 ++++++++++++++++++++++++++++++++-------------------- hw/scsi-disk.h | 49 +++++++++++++++++++++++++++++++------ hw/scsi-generic.c | 62 ++++++++++++++++++++++++++++++----------------- hw/usb-msd.c | 24 ++++++++++-------- 10 files changed, 233 insertions(+), 120 deletions(-) create mode 100644 hw/scsi-bus.c diff --git a/Makefile b/Makefile index 0ecac45..af998d2 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,7 @@ OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o OBJS+=tmp105.o lm832x.o eeprom93xx.o tsc2005.o OBJS+=scsi-disk.o cdrom.o -OBJS+=scsi-generic.o +OBJS+=scsi-generic.o scsi-bus.o OBJS+=usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o OBJS+=usb-serial.o usb-net.o usb-bus.o OBJS+=sd.o ssi-sd.o diff --git a/hw/esp.c b/hw/esp.c index 5fa910c..7127eca 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -63,6 +63,7 @@ struct ESPState { uint8_t ti_buf[TI_BUFSZ]; uint32_t sense; uint32_t dma; + SCSIBus *bus; SCSIDevice *scsi_dev[ESP_MAX_DEVS]; SCSIDevice *current_dev; uint8_t cmdbuf[TI_BUFSZ]; @@ -185,7 +186,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) if (s->current_dev) { /* Started a new command before the old one finished. Cancel it. */ - s->current_dev->cancel_io(s->current_dev, 0); + s->current_dev->info->cancel_io(s->current_dev, 0); s->async_len = 0; } @@ -208,7 +209,7 @@ static void do_cmd(ESPState *s, uint8_t *buf) DPRINTF("do_cmd: busid 0x%x\n", buf[0]); lun = buf[0] & 7; - datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun); + datalen = s->current_dev->info->send_command(s->current_dev, 0, &buf[1], lun); s->ti_size = datalen; if (datalen != 0) { s->rregs[ESP_RSTAT] = STAT_TC; @@ -216,10 +217,10 @@ static void do_cmd(ESPState *s, uint8_t *buf) s->dma_counter = 0; if (datalen > 0) { s->rregs[ESP_RSTAT] |= STAT_DI; - s->current_dev->read_data(s->current_dev, 0); + s->current_dev->info->read_data(s->current_dev, 0); } else { s->rregs[ESP_RSTAT] |= STAT_DO; - s->current_dev->write_data(s->current_dev, 0); + s->current_dev->info->write_data(s->current_dev, 0); } } s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; @@ -318,9 +319,9 @@ static void esp_do_dma(ESPState *s) if (s->async_len == 0) { if (to_device) { // ti_size is negative - s->current_dev->write_data(s->current_dev, 0); + s->current_dev->info->write_data(s->current_dev, 0); } else { - s->current_dev->read_data(s->current_dev, 0); + s->current_dev->info->read_data(s->current_dev, 0); /* If there is still data to be read from the device then complete the DMA operation immediately. Otherwise defer until the scsi layer has completed. */ @@ -334,10 +335,10 @@ static void esp_do_dma(ESPState *s) } } -static void esp_command_complete(void *opaque, int reason, uint32_t tag, +static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg) { - ESPState *s = (ESPState *)opaque; + ESPState *s = DO_UPCAST(ESPState, busdev.qdev, bus->qbus.parent); if (reason == SCSI_REASON_DONE) { DPRINTF("SCSI Command complete\n"); @@ -355,7 +356,7 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag, } else { DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); s->async_len = arg; - s->async_buf = s->current_dev->get_buf(s->current_dev, 0); + s->async_buf = s->current_dev->info->get_buf(s->current_dev, 0); if (s->dma_left) { esp_do_dma(s); } else if (s->dma_counter != 0 && s->ti_size <= 0) { @@ -636,13 +637,13 @@ static void esp_scsi_attach(DeviceState *host, BlockDriverState *bd, int id) } if (s->scsi_dev[id]) { DPRINTF("Destroying device %d\n", id); - s->scsi_dev[id]->destroy(s->scsi_dev[id]); + s->scsi_dev[id]->info->destroy(s->scsi_dev[id]); } DPRINTF("Attaching block device %d\n", id); /* Command queueing is not implemented. */ - s->scsi_dev[id] = scsi_generic_init(bd, 0, esp_command_complete, s); + s->scsi_dev[id] = scsi_generic_init(s->bus, bd); if (s->scsi_dev[id] == NULL) - s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s); + s->scsi_dev[id] = scsi_disk_init(s->bus, bd); } void esp_init(target_phys_addr_t espaddr, int it_shift, @@ -686,7 +687,8 @@ static void esp_init1(SysBusDevice *dev) qdev_init_gpio_in(&dev->qdev, parent_esp_reset, 1); - scsi_bus_new(&dev->qdev, esp_scsi_attach); + s->bus = scsi_bus_new(&dev->qdev, 0, esp_scsi_attach, esp_command_complete); + scsi_bus_attach_cmdline(s->bus); } static void esp_register_devices(void) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index b07424f..8c48e02 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -12,6 +12,7 @@ #include "hw.h" #include "pci.h" +#include "scsi.h" #include "scsi-disk.h" #include "block_int.h" @@ -190,6 +191,7 @@ typedef struct { * 2 if processing DMA from lsi_execute_script. * 3 if a DMA operation is in progress. */ int waiting; + SCSIBus *bus; SCSIDevice *scsi_dev[LSI_MAX_DEVS]; SCSIDevice *current_dev; int current_lun; @@ -508,8 +510,8 @@ static void lsi_do_dma(LSIState *s, int out) s->dbc -= count; if (s->dma_buf == NULL) { - s->dma_buf = s->current_dev->get_buf(s->current_dev, - s->current_tag); + s->dma_buf = s->current_dev->info->get_buf(s->current_dev, + s->current_tag); } /* ??? Set SFBR to first data byte. */ @@ -523,10 +525,10 @@ static void lsi_do_dma(LSIState *s, int out) s->dma_buf = NULL; if (out) { /* Write the data. */ - s->current_dev->write_data(s->current_dev, s->current_tag); + s->current_dev->info->write_data(s->current_dev, s->current_tag); } else { /* Request any remaining data. */ - s->current_dev->read_data(s->current_dev, s->current_tag); + s->current_dev->info->read_data(s->current_dev, s->current_tag); } } else { s->dma_buf += count; @@ -630,10 +632,10 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) } /* Callback to indicate that the SCSI layer has completed a transfer. */ -static void lsi_command_complete(void *opaque, int reason, uint32_t tag, +static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg) { - LSIState *s = (LSIState *)opaque; + LSIState *s = DO_UPCAST(LSIState, pci_dev.qdev, bus->qbus.parent); int out; out = (s->sstat1 & PHASE_MASK) == PHASE_DO; @@ -678,14 +680,14 @@ static void lsi_do_command(LSIState *s) cpu_physical_memory_read(s->dnad, buf, s->dbc); s->sfbr = buf[0]; s->command_complete = 0; - n = s->current_dev->send_command(s->current_dev, s->current_tag, buf, - s->current_lun); + n = s->current_dev->info->send_command(s->current_dev, s->current_tag, buf, + s->current_lun); if (n > 0) { lsi_set_phase(s, PHASE_DI); - s->current_dev->read_data(s->current_dev, s->current_tag); + s->current_dev->info->read_data(s->current_dev, s->current_tag); } else if (n < 0) { lsi_set_phase(s, PHASE_DO); - s->current_dev->write_data(s->current_dev, s->current_tag); + s->current_dev->info->write_data(s->current_dev, s->current_tag); } if (!s->command_complete) { @@ -1972,12 +1974,12 @@ void lsi_scsi_attach(DeviceState *host, BlockDriverState *bd, int id) } if (s->scsi_dev[id]) { DPRINTF("Destroying device %d\n", id); - s->scsi_dev[id]->destroy(s->scsi_dev[id]); + s->scsi_dev[id]->info->destroy(s->scsi_dev[id]); } DPRINTF("Attaching block device %d\n", id); - s->scsi_dev[id] = scsi_generic_init(bd, 1, lsi_command_complete, s); + s->scsi_dev[id] = scsi_generic_init(s->bus, bd); if (s->scsi_dev[id] == NULL) - s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s); + s->scsi_dev[id] = scsi_disk_init(s->bus, bd); bd->private = &s->pci_dev; } @@ -2032,7 +2034,8 @@ static void lsi_scsi_init(PCIDevice *dev) lsi_soft_reset(s); - scsi_bus_new(&dev->qdev, lsi_scsi_attach); + s->bus = scsi_bus_new(&dev->qdev, 1, lsi_scsi_attach, lsi_command_complete); + scsi_bus_attach_cmdline(s->bus); } static PCIDeviceInfo lsi_info = { diff --git a/hw/qdev.c b/hw/qdev.c index 3dc7076..c3ceff0 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -288,25 +288,6 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name) return NULL; } -static int next_scsi_bus; - -/* Create a scsi bus, and attach devices to it. */ -/* TODO: Actually create a scsi bus for hotplug to use. */ -void scsi_bus_new(DeviceState *host, SCSIAttachFn attach) -{ - int bus = next_scsi_bus++; - int unit; - int index; - - for (unit = 0; unit < MAX_SCSI_DEVS; unit++) { - index = drive_get_index(IF_SCSI, bus, unit); - if (index == -1) { - continue; - } - attach(host, drives_table[index].bdrv, unit); - } -} - BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name) { BusState *bus; diff --git a/hw/qdev.h b/hw/qdev.h index 18321b3..fa0e96b 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -73,8 +73,6 @@ typedef struct { } DevicePropList; typedef void (*qdev_initfn)(DeviceState *dev, DeviceInfo *info); -typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv, - int unit); struct DeviceInfo { const char *name; @@ -94,8 +92,6 @@ void qdev_register(DeviceInfo *info); void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n); void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n); -void scsi_bus_new(DeviceState *host, SCSIAttachFn attach); - CharDriverState *qdev_init_chardev(DeviceState *dev); BusState *qdev_get_parent_bus(DeviceState *dev); diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c new file mode 100644 index 0000000..31fb5d7 --- /dev/null +++ b/hw/scsi-bus.c @@ -0,0 +1,65 @@ +#include "hw.h" +#include "sysemu.h" +#include "scsi-disk.h" +#include "qdev.h" + +static struct BusInfo scsi_bus_info = { + .name = "SCSI", + .size = sizeof(SCSIBus), +}; +static int next_scsi_bus; + +/* Create a scsi bus, and attach devices to it. */ +SCSIBus *scsi_bus_new(DeviceState *host, int tcq, + SCSIAttachFn attach, scsi_completionfn complete) +{ + SCSIBus *bus; + char name[32]; + + snprintf(name, sizeof(name), "scsi%d", next_scsi_bus); + bus = FROM_QBUS(SCSIBus, qbus_create(&scsi_bus_info, host, name)); + bus->busnr = next_scsi_bus++; + bus->tcq = tcq; + bus->attach = attach; + bus->complete = complete; + return bus; +} + +void scsi_bus_attach_cmdline(SCSIBus *bus) +{ + int unit; + int index; + + for (unit = 0; unit < MAX_SCSI_DEVS; unit++) { + index = drive_get_index(IF_SCSI, bus->busnr, unit); + if (index == -1) { + continue; + } + bus->attach(bus->qbus.parent, drives_table[index].bdrv, unit); + } +} + +static void scsi_qdev_init(DeviceState *qdev, DeviceInfo *base) +{ + SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); + SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base); + + dev->info = info; + dev->info->init(dev); +} + +void scsi_qdev_register(SCSIDeviceInfo *info) +{ + info->qdev.bus_info = &scsi_bus_info; + info->qdev.init = scsi_qdev_init; + qdev_register(&info->qdev); +} + +SCSIDevice *scsi_create_simple(SCSIBus *bus, const char *name) +{ + DeviceState *dev; + + dev = qdev_create(&bus->qbus, name); + qdev_init(dev); + return DO_UPCAST(SCSIDevice, qdev, dev); +} diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index a0485db..c2d610a 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -45,6 +45,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #define SCSI_REQ_STATUS_RETRY 0x01 typedef struct SCSIRequest { + SCSIBus *bus; SCSIDeviceState *dev; uint32_t tag; /* ??? We should probably keep track of whether the data transfer is @@ -68,19 +69,15 @@ struct SCSIDeviceState int cluster_size; uint64_t max_lba; int sense; - int tcq; - /* Completion functions may be called from either scsi_{read,write}_data - or from the AIO completion routines. */ - scsi_completionfn completion; - void *opaque; char drive_serial_str[21]; }; /* Global pool of SCSIRequest structures. */ static SCSIRequest *free_requests = NULL; -static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag) +static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag) { + SCSIDeviceState *s = d->state; SCSIRequest *r; if (free_requests) { @@ -90,6 +87,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag) r = qemu_malloc(sizeof(SCSIRequest)); r->iov.iov_base = qemu_memalign(512, SCSI_DMA_BUF_SIZE); } + r->bus = scsi_bus_from_device(d); r->dev = s; r->tag = tag; r->sector_count = 0; @@ -143,7 +141,7 @@ static void scsi_command_complete(SCSIRequest *r, int status, int sense) s->sense = sense; tag = r->tag; scsi_remove_request(r); - s->completion(s->opaque, SCSI_REASON_DONE, tag, status); + r->bus->complete(r->bus, SCSI_REASON_DONE, tag, status); } /* Cancel a pending data transfer. */ @@ -164,17 +162,16 @@ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) static void scsi_read_complete(void * opaque, int ret) { SCSIRequest *r = (SCSIRequest *)opaque; - SCSIDeviceState *s = r->dev; if (ret) { DPRINTF("IO error\n"); - s->completion(s->opaque, SCSI_REASON_DATA, r->tag, 0); + r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, 0); scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE); return; } DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->iov.iov_len); - s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->iov.iov_len); + r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->iov.iov_len); } /* Read more data from scsi device into buffer. */ @@ -194,7 +191,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) if (r->sector_count == (uint32_t)-1) { DPRINTF("Read buf_len=%d\n", r->iov.iov_len); r->sector_count = 0; - s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->iov.iov_len); + r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->iov.iov_len); return; } DPRINTF("Read sector_count=%d\n", r->sector_count); @@ -239,7 +236,6 @@ static int scsi_handle_write_error(SCSIRequest *r, int error) static void scsi_write_complete(void * opaque, int ret) { SCSIRequest *r = (SCSIRequest *)opaque; - SCSIDeviceState *s = r->dev; uint32_t len; uint32_t n; @@ -262,7 +258,7 @@ static void scsi_write_complete(void * opaque, int ret) } r->iov.iov_len = len; DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len); - s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len); + r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, len); } } @@ -364,7 +360,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, } /* ??? Tags are not unique for different luns. We only implement a single lun, so this should not matter. */ - r = scsi_new_request(s, tag); + r = scsi_new_request(d, tag); outbuf = (uint8_t *)r->iov.iov_base; is_write = 0; DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); @@ -592,7 +588,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, outbuf[3] = 2; /* Format 2 */ outbuf[4] = len - 5; /* Additional Length = (Len - 1) - 4 */ /* Sync data transfer and TCQ. */ - outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0); + outbuf[7] = 0x10 | (r->bus->tcq ? 0x02 : 0); r->iov.iov_len = len; break; case 0x16: @@ -926,8 +922,7 @@ static void scsi_destroy(SCSIDevice *d) qemu_free(d); } -SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, - scsi_completionfn completion, void *opaque) +SCSIDevice *scsi_disk_init(SCSIBus *bus, BlockDriverState *bdrv) { SCSIDevice *d; SCSIDeviceState *s; @@ -935,9 +930,6 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState)); s->bdrv = bdrv; - s->tcq = tcq; - s->completion = completion; - s->opaque = opaque; if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) { s->cluster_size = 4; } else { @@ -953,14 +945,37 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, if (strlen(s->drive_serial_str) == 0) pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0"); qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s); - d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); + + if (bus) { + d = scsi_create_simple(bus, "scsi-disk"); + } else { + /* temporary until usb is qdev-ified */ + 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; } + +static void scsi_disk_initfn(SCSIDevice *dev) +{ + /* TODO */ +} + +static SCSIDeviceInfo scsi_disk_info = { + .qdev.name = "scsi-disk", + .qdev.size = sizeof(SCSIDevice), + .init = scsi_disk_initfn, + .destroy = scsi_destroy, + .send_command = scsi_send_command, + .read_data = scsi_read_data, + .write_data = scsi_write_data, + .cancel_io = scsi_cancel_io, + .get_buf = scsi_get_buf, +}; + +static void scsi_disk_register_devices(void) +{ + scsi_qdev_register(&scsi_disk_info); +} +device_init(scsi_disk_register_devices) diff --git a/hw/scsi-disk.h b/hw/scsi-disk.h index f42212b..53e93f9 100644 --- a/hw/scsi-disk.h +++ b/hw/scsi-disk.h @@ -1,20 +1,40 @@ #ifndef SCSI_DISK_H #define SCSI_DISK_H +#include "qdev.h" + /* scsi-disk.c */ enum scsi_reason { SCSI_REASON_DONE, /* Command complete. */ SCSI_REASON_DATA /* Transfer complete, more data required. */ }; +typedef struct SCSIBus SCSIBus; typedef struct SCSIDeviceState SCSIDeviceState; typedef struct SCSIDevice SCSIDevice; -typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag, +typedef struct SCSIDeviceInfo SCSIDeviceInfo; +typedef void (*scsi_completionfn)(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg); struct SCSIDevice { + DeviceState qdev; + SCSIDeviceInfo *info; SCSIDeviceState *state; +}; + +SCSIDevice *scsi_disk_init(SCSIBus *bus, BlockDriverState *bdrv); +SCSIDevice *scsi_generic_init(SCSIBus *bus, BlockDriverState *bdrv); + +/* cdrom.c */ +int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); +int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); + +/* scsi-bus.c */ +typedef void (*scsi_qdev_initfn)(SCSIDevice *dev); +struct SCSIDeviceInfo { + DeviceInfo qdev; + scsi_qdev_initfn init; void (*destroy)(SCSIDevice *s); int32_t (*send_command)(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); @@ -24,13 +44,26 @@ struct SCSIDevice uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag); }; -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); +typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv, + int unit); +struct SCSIBus { + BusState qbus; + int busnr; -/* cdrom.c */ -int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); -int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); + int tcq; + SCSIAttachFn attach; + scsi_completionfn complete; +}; + +SCSIBus *scsi_bus_new(DeviceState *host, int tcq, + SCSIAttachFn attach, scsi_completionfn complete); +void scsi_bus_attach_cmdline(SCSIBus *bus); +void scsi_qdev_register(SCSIDeviceInfo *info); +SCSIDevice *scsi_create_simple(SCSIBus *bus, const char *name); + +static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) +{ + return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus); +} #endif diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index c827c04..a67b668 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -17,8 +17,7 @@ #ifndef __linux__ -SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq, - scsi_completionfn completion, void *opaque) +SCSIDevice *scsi_generic_init(SCSIBus *bus, BlockDriverState *bdrv) { return NULL; } @@ -63,6 +62,7 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) typedef struct SCSIRequest { BlockDriverAIOCB *aiocb; struct SCSIRequest *next; + SCSIBus *bus; SCSIDeviceState *dev; uint32_t tag; uint8_t cmd[SCSI_CMD_BUF_SIZE]; @@ -80,8 +80,6 @@ struct SCSIDeviceState int type; int blocksize; int lun; - scsi_completionfn completion; - void *opaque; int driver_status; uint8_t sensebuf[SCSI_SENSE_BUF_SIZE]; uint8_t senselen; @@ -90,8 +88,9 @@ struct SCSIDeviceState /* Global pool of SCSIRequest structures. */ static SCSIRequest *free_requests = NULL; -static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag) +static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag) { + SCSIDeviceState *s = d->state; SCSIRequest *r; if (free_requests) { @@ -102,6 +101,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag) r->buf = NULL; r->buflen = 0; } + r->bus = scsi_bus_from_device(d); r->dev = s; r->tag = tag; memset(r->cmd, 0, sizeof(r->cmd)); @@ -178,7 +178,7 @@ static void scsi_command_complete(void *opaque, int ret) r, r->tag, status); tag = r->tag; scsi_remove_request(r); - s->completion(s->opaque, SCSI_REASON_DONE, tag, status); + r->bus->complete(r->bus, SCSI_REASON_DONE, tag, status); } /* Cancel a pending data transfer. */ @@ -225,7 +225,6 @@ static int execute_command(BlockDriverState *bdrv, static void scsi_read_complete(void * opaque, int ret) { SCSIRequest *r = (SCSIRequest *)opaque; - SCSIDeviceState *s = r->dev; int len; if (ret) { @@ -237,7 +236,7 @@ static void scsi_read_complete(void * opaque, int ret) 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); + r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, len); if (len == 0) scsi_command_complete(r, 0); } @@ -275,7 +274,7 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) DPRINTF("Sense: %d %d %d %d %d %d %d %d\n", r->buf[0], r->buf[1], r->buf[2], r->buf[3], r->buf[4], r->buf[5], r->buf[6], r->buf[7]); - s->completion(s->opaque, SCSI_REASON_DATA, r->tag, s->senselen); + r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, s->senselen); return; } @@ -325,7 +324,7 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) if (r->len == 0) { r->len = r->buflen; - s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->len); + r->bus->complete(r->bus, SCSI_REASON_DATA, r->tag, r->len); return 0; } @@ -518,6 +517,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, uint32_t len=0; int cmdlen=0; SCSIRequest *r; + SCSIBus *bus; int ret; if (s->type == TYPE_TAPE) { @@ -548,7 +548,8 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, s->sensebuf[6] = 0x00; s->senselen = 7; s->driver_status = SG_ERR_DRIVER_SENSE; - s->completion(s->opaque, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1); + bus = scsi_bus_from_device(d); + bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1); return 0; } @@ -557,7 +558,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, BADF("Tag 0x%x already in use %p\n", tag, r); scsi_cancel_io(d, tag); } - r = scsi_new_request(s, tag); + r = scsi_new_request(d, tag); memcpy(r->cmd, cmd, cmdlen); r->cmdlen = cmdlen; @@ -675,8 +676,7 @@ static void scsi_destroy(SCSIDevice *d) qemu_free(d); } -SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq, - scsi_completionfn completion, void *opaque) +SCSIDevice *scsi_generic_init(SCSIBus *bus, BlockDriverState *bdrv) { int sg_version; SCSIDevice *d; @@ -704,8 +704,6 @@ SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq, s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState)); s->bdrv = bdrv; s->requests = NULL; - s->completion = completion; - s->opaque = opaque; s->lun = scsiid.lun; DPRINTF("LUN %d\n", s->lun); s->type = scsiid.scsi_type; @@ -730,15 +728,33 @@ SCSIDevice *scsi_generic_init(BlockDriverState *bdrv, int tcq, /* define function to manage device */ - d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); + d = scsi_create_simple(bus, "scsi-generic"); 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; } + +static void scsi_generic_initfn(SCSIDevice *dev) +{ + /* TODO */ +} + +static SCSIDeviceInfo scsi_generic_info = { + .qdev.name = "scsi-generic", + .qdev.size = sizeof(SCSIDevice), + .init = scsi_generic_initfn, + .destroy = scsi_destroy, + .send_command = scsi_send_command, + .read_data = scsi_read_data, + .write_data = scsi_write_data, + .cancel_io = scsi_cancel_io, + .get_buf = scsi_get_buf, +}; + +static void scsi_generic_register_devices(void) +{ + scsi_qdev_register(&scsi_generic_info); +} +device_init(scsi_generic_register_devices) + #endif /* __linux__ */ diff --git a/hw/usb-msd.c b/hw/usb-msd.c index a4c53a7..8a92815 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -44,6 +44,7 @@ typedef struct { uint32_t residue; uint32_t tag; BlockDriverState *bs; + SCSIBus *bus; SCSIDevice *scsi_dev; int result; /* For async completion. */ @@ -150,9 +151,9 @@ static void usb_msd_copy_data(MSDState *s) s->data_len -= len; if (s->scsi_len == 0) { if (s->mode == USB_MSDM_DATAIN) { - s->scsi_dev->read_data(s->scsi_dev, s->tag); + s->scsi_dev->info->read_data(s->scsi_dev, s->tag); } else if (s->mode == USB_MSDM_DATAOUT) { - s->scsi_dev->write_data(s->scsi_dev, s->tag); + s->scsi_dev->info->write_data(s->scsi_dev, s->tag); } } } @@ -168,10 +169,10 @@ static void usb_msd_send_status(MSDState *s) memcpy(s->usb_buf, &csw, 13); } -static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag, +static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg) { - MSDState *s = (MSDState *)opaque; + MSDState *s = DO_UPCAST(MSDState, dev.qdev, bus->qbus.parent); USBPacket *p = s->packet; if (tag != s->tag) { @@ -205,7 +206,7 @@ static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag, return; } s->scsi_len = arg; - s->scsi_buf = s->scsi_dev->get_buf(s->scsi_dev, tag); + s->scsi_buf = s->scsi_dev->info->get_buf(s->scsi_dev, tag); if (p) { usb_msd_copy_data(s); if (s->usb_len == 0) { @@ -343,7 +344,7 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, static void usb_msd_cancel_io(USBPacket *p, void *opaque) { MSDState *s = opaque; - s->scsi_dev->cancel_io(s->scsi_dev, s->tag); + s->scsi_dev->info->cancel_io(s->scsi_dev, s->tag); s->packet = NULL; s->scsi_len = 0; } @@ -391,14 +392,14 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) 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; - s->scsi_dev->send_command(s->scsi_dev, s->tag, cbw.cmd, 0); + s->scsi_dev->info->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) { - s->scsi_dev->read_data(s->scsi_dev, s->tag); + s->scsi_dev->info->read_data(s->scsi_dev, s->tag); } else if (s->mode == USB_MSDM_DATAOUT) { - s->scsi_dev->write_data(s->scsi_dev, s->tag); + s->scsi_dev->info->write_data(s->scsi_dev, s->tag); } } ret = len; @@ -509,7 +510,7 @@ static void usb_msd_handle_destroy(USBDevice *dev) { MSDState *s = (MSDState *)dev; - s->scsi_dev->destroy(s->scsi_dev); + s->scsi_dev->info->destroy(s->scsi_dev); bdrv_delete(s->bs); qemu_free(s); } @@ -566,7 +567,8 @@ USBDevice *usb_msd_init(const char *filename) snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", filename); - s->scsi_dev = scsi_disk_init(bdrv, 0, usb_msd_command_complete, s); + s->bus = scsi_bus_new(&s->dev.qdev, 0, NULL, usb_msd_command_complete); + s->scsi_dev = scsi_disk_init(s->bus, bdrv); usb_msd_handle_reset((USBDevice *)s); return (USBDevice *)s; } -- 1.6.2.2