[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 18/20] qdev/scsi: add scsi bus support to qdev, conv
From: |
Gerd Hoffmann |
Subject: |
[Qemu-devel] [PATCH 18/20] qdev/scsi: add scsi bus support to qdev, convert drivers. |
Date: |
Mon, 29 Jun 2009 14:46:19 +0200 |
* Add SCSIBus
* Add SCSIDeviceInfo, move device callbacks here.
* add qdev/scsi helper functions.
* convert drivers.
TODO:
* design a better way to link (guest) scsi devs to (host) bdrvs.
* figure whenever we can move bits from lsi / esp scsi host drivers
to scsi-bus.c (attach function?).
Signed-off-by: Gerd Hoffmann <address@hidden>
---
Makefile | 2 +-
hw/esp.c | 28 ++++++++++++----------
hw/lsi53c895a.c | 31 ++++++++++++++-----------
hw/qdev.c | 18 ---------------
hw/qdev.h | 4 ---
hw/scsi-bus.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++
hw/scsi-disk.c | 64 ++++++++++++++++++++++++++++++----------------------
hw/scsi-disk.h | 48 +++++++++++++++++++++++++++++++++------
hw/scsi-generic.c | 62 ++++++++++++++++++++++++++++++++-------------------
hw/usb-msd.c | 24 ++++++++++---------
10 files changed, 223 insertions(+), 119 deletions(-)
create mode 100644 hw/scsi-bus.c
diff --git a/Makefile b/Makefile
index e150ab1..3987f49 100644
--- a/Makefile
+++ b/Makefile
@@ -101,7 +101,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 3698917..1aa3e1a 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) {
@@ -634,13 +635,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,
@@ -684,7 +685,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 516a468..1c3d698 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 768431c..b5068ba 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -288,24 +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);
- }
-}
static TAILQ_HEAD(, BusState) buslist = TAILQ_HEAD_INITIALIZER(buslist);
BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
diff --git a/hw/qdev.h b/hw/qdev.h
index 2f4e4a4..5a84fbf 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -76,8 +76,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;
@@ -97,8 +95,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..17d3d16
--- /dev/null
+++ b/hw/scsi-bus.c
@@ -0,0 +1,61 @@
+#include "hw.h"
+#include "sysemu.h"
+#include "scsi-disk.h"
+#include "qdev.h"
+
+static struct BusInfo scsi_bus_info = {
+ .name = "SCSI",
+ .size = sizeof(SCSIBus),
+};
+
+/* Create a scsi bus, and attach devices to it. */
+SCSIBus *scsi_bus_new(DeviceState *host, int tcq,
+ SCSIAttachFn attach, scsi_completionfn complete)
+{
+ SCSIBus *bus;
+
+ bus = FROM_QBUS(SCSIBus, qbus_create(&scsi_bus_info, host, NULL));
+ 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->qbus.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..19b8ebd 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,32 @@ 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));
+
+ d = scsi_create_simple(bus, "scsi-disk");
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..5b5c0af 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,25 @@ 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;
-/* 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 535178f..22a1994 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.5
- [Qemu-devel] [PATCH 07/20] qdev/pci: hook up i440fx., (continued)
- [Qemu-devel] [PATCH 07/20] qdev/pci: hook up i440fx., Gerd Hoffmann, 2009/06/29
- [Qemu-devel] [PATCH 11/20] qdev: convert es1370., Gerd Hoffmann, 2009/06/29
- [Qemu-devel] [PATCH 12/20] qdev: convert ac97., Gerd Hoffmann, 2009/06/29
- [Qemu-devel] [PATCH 17/20] qdev: convert ohci., Gerd Hoffmann, 2009/06/29
- [Qemu-devel] [PATCH 16/20] qdev/usb: print usb dev info, Gerd Hoffmann, 2009/06/29
- [Qemu-devel] [PATCH 10/20] qdev: convert all vga, Gerd Hoffmann, 2009/06/29
- [Qemu-devel] [PATCH 13/20] qdev: convert uhci., Gerd Hoffmann, 2009/06/29
- [Qemu-devel] [PATCH 15/20] qdev/usb: make qemu aware of usb busses., Gerd Hoffmann, 2009/06/29
- [Qemu-devel] [PATCH 14/20] qdev/usb: add usb bus support to qdev, convert drivers., Gerd Hoffmann, 2009/06/29
- [Qemu-devel] [PATCH 19/20] debug/test patch: add ohci controller to pc, Gerd Hoffmann, 2009/06/29
- [Qemu-devel] [PATCH 18/20] qdev/scsi: add scsi bus support to qdev, convert drivers.,
Gerd Hoffmann <=
- [Qemu-devel] [PATCH 20/20] debug/test patch: allow specify busnr for -usbdevice, Gerd Hoffmann, 2009/06/29
- Re: [Qemu-devel] [PATCH 0/20] qdev patches., Anthony Liguori, 2009/06/29