aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2010-11-30 15:25:34 -0600
committerAnthony Liguori <aliguori@us.ibm.com>2010-11-30 15:25:34 -0600
commit09fa35e5cdc7d17ed3e1528ca743893ae77a0ea2 (patch)
treeb11bb495700b297a4d49692bfd8d6070a1b74e0b
parent9233da785f55c924c5850cd1ce1b7f5f200d631b (diff)
parentb76876e602ca09ff848d99595a506feb1fd54ff4 (diff)
downloadqemu-09fa35e5cdc7d17ed3e1528ca743893ae77a0ea2.zip
qemu-09fa35e5cdc7d17ed3e1528ca743893ae77a0ea2.tar.gz
qemu-09fa35e5cdc7d17ed3e1528ca743893ae77a0ea2.tar.bz2
Merge remote branch 'kwolf/for-anthony' into staging
-rw-r--r--block-migration.c14
-rw-r--r--block/qcow.c1
-rw-r--r--block/qcow2.h1
-rw-r--r--block/raw-posix.c2
-rw-r--r--block/vdi.c1
-rw-r--r--block/vmdk.c1
-rw-r--r--block/vpc.c2
-rw-r--r--blockdev.c39
-rw-r--r--blockdev.h3
-rw-r--r--hmp-commands.hx18
-rw-r--r--hw/ide/cmd646.c8
-rw-r--r--hw/ide/core.c31
-rw-r--r--hw/ide/internal.h2
-rw-r--r--hw/ide/pci.c131
-rw-r--r--hw/ide/pci.h7
-rw-r--r--hw/ide/piix.c8
-rw-r--r--hw/ide/via.c8
-rw-r--r--hw/scsi-bus.c12
-rw-r--r--hw/scsi-defs.h20
-rw-r--r--hw/scsi-disk.c137
-rw-r--r--hw/scsi-generic.c10
-rw-r--r--hw/scsi.h11
-rw-r--r--hw/xen_disk.c12
23 files changed, 234 insertions, 245 deletions
diff --git a/block-migration.c b/block-migration.c
index 3e66f49..1475325 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -146,8 +146,7 @@ static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
{
int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
- if (bmds->aio_bitmap &&
- (sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) {
+ if ((sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) {
return !!(bmds->aio_bitmap[chunk / (sizeof(unsigned long) * 8)] &
(1UL << (chunk % (sizeof(unsigned long) * 8))));
} else {
@@ -169,13 +168,9 @@ static void bmds_set_aio_inflight(BlkMigDevState *bmds, int64_t sector_num,
bit = start % (sizeof(unsigned long) * 8);
val = bmds->aio_bitmap[idx];
if (set) {
- if (!(val & (1UL << bit))) {
- val |= 1UL << bit;
- }
+ val |= 1UL << bit;
} else {
- if (val & (1UL << bit)) {
- val &= ~(1UL << bit);
- }
+ val &= ~(1UL << bit);
}
bmds->aio_bitmap[idx] = val;
}
@@ -385,8 +380,9 @@ static int mig_save_device_dirty(Monitor *mon, QEMUFile *f,
int nr_sectors;
for (sector = bmds->cur_dirty; sector < bmds->total_sectors;) {
- if (bmds_aio_inflight(bmds, sector))
+ if (bmds_aio_inflight(bmds, sector)) {
qemu_aio_flush();
+ }
if (bdrv_get_dirty(bmds->bs, sector)) {
if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
diff --git a/block/qcow.c b/block/qcow.c
index 9cd547d..f67d3d3 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -54,7 +54,6 @@ typedef struct QCowHeader {
#define L2_CACHE_SIZE 16
typedef struct BDRVQcowState {
- BlockDriverState *hd;
int cluster_bits;
int cluster_size;
int cluster_sectors;
diff --git a/block/qcow2.h b/block/qcow2.h
index 2d22e5e..5217bea 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -79,7 +79,6 @@ typedef struct QCowSnapshot {
} QCowSnapshot;
typedef struct BDRVQcowState {
- BlockDriverState *hd;
int cluster_bits;
int cluster_size;
int cluster_sectors;
diff --git a/block/raw-posix.c b/block/raw-posix.c
index d0960b8..9286fb8 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -463,7 +463,7 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset,
count -= ret;
sum += ret;
}
- /* here, count < 512 because (count & ~sector_mask) == 0 */
+ /* here, count < sector_size because (count & ~sector_mask) == 0 */
if (count) {
ret = raw_pread_aligned(bs, offset, s->aligned_buf,
bs->buffer_alignment);
diff --git a/block/vdi.c b/block/vdi.c
index 3b51e53..ab8f70f 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -186,7 +186,6 @@ typedef struct {
} VdiHeader;
typedef struct {
- BlockDriverState *hd;
/* The block map entries are little endian (even in memory). */
uint32_t *bmap;
/* Size of block (bytes). */
diff --git a/block/vmdk.c b/block/vmdk.c
index 872aeba..8fc9d67 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -61,7 +61,6 @@ typedef struct {
#define L2_CACHE_SIZE 16
typedef struct BDRVVmdkState {
- BlockDriverState *hd;
int64_t l1_table_offset;
int64_t l1_backup_table_offset;
uint32_t *l1_table;
diff --git a/block/vpc.c b/block/vpc.c
index 416f489..21e2a68 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -110,8 +110,6 @@ struct vhd_dyndisk_header {
};
typedef struct BDRVVPCState {
- BlockDriverState *hd;
-
uint8_t footer_buf[HEADER_SIZE];
uint64_t free_data_block_offset;
int max_table_entries;
diff --git a/blockdev.c b/blockdev.c
index 6cb179a..f6ac439 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -14,6 +14,8 @@
#include "qemu-option.h"
#include "qemu-config.h"
#include "sysemu.h"
+#include "hw/qdev.h"
+#include "block_int.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
@@ -597,3 +599,40 @@ int do_change_block(Monitor *mon, const char *device,
}
return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
}
+
+int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *id = qdict_get_str(qdict, "id");
+ BlockDriverState *bs;
+ BlockDriverState **ptr;
+ Property *prop;
+
+ bs = bdrv_find(id);
+ if (!bs) {
+ qerror_report(QERR_DEVICE_NOT_FOUND, id);
+ return -1;
+ }
+
+ /* quiesce block driver; prevent further io */
+ qemu_aio_flush();
+ bdrv_flush(bs);
+ bdrv_close(bs);
+
+ /* clean up guest state from pointing to host resource by
+ * finding and removing DeviceState "drive" property */
+ for (prop = bs->peer->info->props; prop && prop->name; prop++) {
+ if (prop->info->type == PROP_TYPE_DRIVE) {
+ ptr = qdev_get_prop_ptr(bs->peer, prop);
+ if ((*ptr) == bs) {
+ bdrv_detach(bs, bs->peer);
+ *ptr = NULL;
+ break;
+ }
+ }
+ }
+
+ /* clean up host side */
+ drive_uninit(drive_get_by_blockdev(bs));
+
+ return 0;
+}
diff --git a/blockdev.h b/blockdev.h
index 653affc..4cb8ca9 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -32,7 +32,7 @@ struct DriveInfo {
};
#define MAX_IDE_DEVS 2
-#define MAX_SCSI_DEVS 7
+#define MAX_SCSI_DEVS 255
DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
int drive_get_max_bus(BlockInterfaceType type);
@@ -51,5 +51,6 @@ int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_change_block(Monitor *mon, const char *device,
const char *filename, const char *fmt);
+int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
#endif
diff --git a/hmp-commands.hx b/hmp-commands.hx
index e5585ba..23024ba 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -68,6 +68,24 @@ Eject a removable medium (use -f to force it).
ETEXI
{
+ .name = "drive_del",
+ .args_type = "id:s",
+ .params = "device",
+ .help = "remove host block device",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_drive_del,
+ },
+
+STEXI
+@item drive_del @var{device}
+@findex drive_del
+Remove host block device. The result is that guest generated IO is no longer
+submitted against the host device underlying the disk. Once a drive has
+been deleted, the QEMU Block layer returns -EIO which results in IO
+errors in the guest for applications that are reading/writing to the device.
+ETEXI
+
+ {
.name = "change",
.args_type = "device:B,target:F,arg:s?",
.params = "device filename [format]",
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index ff80dd5..dfe6091 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -179,12 +179,8 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
}
- register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
- register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
- register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
- register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
- register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
- register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
+ iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
+ ioport_register(&bm->addr_ioport);
addr += 8;
}
}
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 484e0ca..430350f 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -473,11 +473,21 @@ static void dma_buf_commit(IDEState *s, int is_write)
qemu_sglist_destroy(&s->sg);
}
+static void ide_dma_set_inactive(BMDMAState *bm)
+{
+ bm->status &= ~BM_STATUS_DMAING;
+ bm->dma_cb = NULL;
+ bm->unit = -1;
+ bm->aiocb = NULL;
+}
+
void ide_dma_error(IDEState *s)
{
ide_transfer_stop(s);
s->error = ABRT_ERR;
s->status = READY_STAT | ERR_STAT;
+ ide_dma_set_inactive(s->bus->bmdma);
+ s->bus->bmdma->status |= BM_STATUS_INT;
ide_set_irq(s->bus);
}
@@ -587,11 +597,8 @@ static void ide_read_dma_cb(void *opaque, int ret)
s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s->bus);
eot:
- bm->status &= ~BM_STATUS_DMAING;
bm->status |= BM_STATUS_INT;
- bm->dma_cb = NULL;
- bm->unit = -1;
- bm->aiocb = NULL;
+ ide_dma_set_inactive(bm);
return;
}
@@ -733,11 +740,8 @@ static void ide_write_dma_cb(void *opaque, int ret)
s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s->bus);
eot:
- bm->status &= ~BM_STATUS_DMAING;
bm->status |= BM_STATUS_INT;
- bm->dma_cb = NULL;
- bm->unit = -1;
- bm->aiocb = NULL;
+ ide_dma_set_inactive(bm);
return;
}
@@ -1061,11 +1065,8 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
ide_set_irq(s->bus);
eot:
- bm->status &= ~BM_STATUS_DMAING;
bm->status |= BM_STATUS_INT;
- bm->dma_cb = NULL;
- bm->unit = -1;
- bm->aiocb = NULL;
+ ide_dma_set_inactive(bm);
return;
}
@@ -2954,12 +2955,10 @@ void ide_dma_cancel(BMDMAState *bm)
printf("aio_cancel\n");
#endif
bdrv_aio_cancel(bm->aiocb);
- bm->aiocb = NULL;
}
- bm->status &= ~BM_STATUS_DMAING;
+
/* cancel DMA request */
- bm->unit = -1;
- bm->dma_cb = NULL;
+ ide_dma_set_inactive(bm);
}
}
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index d652e06..85f4a16 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -8,6 +8,7 @@
*/
#include <hw/ide.h>
#include "block_int.h"
+#include "iorange.h"
/* debug IDE devices */
//#define DEBUG_IDE
@@ -496,6 +497,7 @@ struct BMDMAState {
QEMUIOVector qiov;
int64_t sector_num;
uint32_t nsector;
+ IORange addr_ioport;
QEMUBH *bh;
};
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index ec90f26..ad406ee 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -39,106 +39,75 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
#ifdef DEBUG_IDE
printf("%s: 0x%08x\n", __func__, val);
#endif
- if (!(val & BM_CMD_START)) {
- /*
- * We can't cancel Scatter Gather DMA in the middle of the
- * operation or a partial (not full) DMA transfer would reach
- * the storage so we wait for completion instead (we beahve
- * like if the DMA was completed by the time the guest trying
- * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
- * set).
- *
- * In the future we'll be able to safely cancel the I/O if the
- * whole DMA operation will be submitted to disk with a single
- * aio operation with preadv/pwritev.
- */
- if (bm->aiocb) {
- qemu_aio_flush();
+
+ /* Ignore writes to SSBM if it keeps the old value */
+ if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
+ if (!(val & BM_CMD_START)) {
+ /*
+ * We can't cancel Scatter Gather DMA in the middle of the
+ * operation or a partial (not full) DMA transfer would reach
+ * the storage so we wait for completion instead (we beahve
+ * like if the DMA was completed by the time the guest trying
+ * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
+ * set).
+ *
+ * In the future we'll be able to safely cancel the I/O if the
+ * whole DMA operation will be submitted to disk with a single
+ * aio operation with preadv/pwritev.
+ */
+ if (bm->aiocb) {
+ qemu_aio_flush();
#ifdef DEBUG_IDE
- if (bm->aiocb)
- printf("ide_dma_cancel: aiocb still pending");
- if (bm->status & BM_STATUS_DMAING)
- printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
+ if (bm->aiocb)
+ printf("ide_dma_cancel: aiocb still pending");
+ if (bm->status & BM_STATUS_DMAING)
+ printf("ide_dma_cancel: BM_STATUS_DMAING still pending");
#endif
+ }
+ } else {
+ bm->cur_addr = bm->addr;
+ if (!(bm->status & BM_STATUS_DMAING)) {
+ bm->status |= BM_STATUS_DMAING;
+ /* start dma transfer if possible */
+ if (bm->dma_cb)
+ bm->dma_cb(bm, 0);
+ }
}
- bm->cmd = val & 0x09;
- } else {
- if (!(bm->status & BM_STATUS_DMAING)) {
- bm->status |= BM_STATUS_DMAING;
- /* start dma transfer if possible */
- if (bm->dma_cb)
- bm->dma_cb(bm, 0);
- }
- bm->cmd = val & 0x09;
}
-}
-uint32_t bmdma_addr_readb(void *opaque, uint32_t addr)
-{
- BMDMAState *bm = opaque;
- uint32_t val;
- val = (bm->addr >> ((addr & 3) * 8)) & 0xff;
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
-#endif
- return val;
+ bm->cmd = val & 0x09;
}
-void bmdma_addr_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void bmdma_addr_read(IORange *ioport, uint64_t addr,
+ unsigned width, uint64_t *data)
{
- BMDMAState *bm = opaque;
- int shift = (addr & 3) * 8;
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
-#endif
- bm->addr &= ~(0xFF << shift);
- bm->addr |= ((val & 0xFF) << shift) & ~3;
- bm->cur_addr = bm->addr;
-}
+ BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+ uint32_t mask = (1ULL << (width * 8)) - 1;
-uint32_t bmdma_addr_readw(void *opaque, uint32_t addr)
-{
- BMDMAState *bm = opaque;
- uint32_t val;
- val = (bm->addr >> ((addr & 3) * 8)) & 0xffff;
+ *data = (bm->addr >> (addr * 8)) & mask;
#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
+ printf("%s: 0x%08x\n", __func__, (unsigned)*data);
#endif
- return val;
}
-void bmdma_addr_writew(void *opaque, uint32_t addr, uint32_t val)
+static void bmdma_addr_write(IORange *ioport, uint64_t addr,
+ unsigned width, uint64_t data)
{
- BMDMAState *bm = opaque;
- int shift = (addr & 3) * 8;
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
-#endif
- bm->addr &= ~(0xFFFF << shift);
- bm->addr |= ((val & 0xFFFF) << shift) & ~3;
- bm->cur_addr = bm->addr;
-}
+ BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+ int shift = addr * 8;
+ uint32_t mask = (1ULL << (width * 8)) - 1;
-uint32_t bmdma_addr_readl(void *opaque, uint32_t addr)
-{
- BMDMAState *bm = opaque;
- uint32_t val;
- val = bm->addr;
#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
+ printf("%s: 0x%08x\n", __func__, (unsigned)data);
#endif
- return val;
+ bm->addr &= ~(mask << shift);
+ bm->addr |= ((data & mask) << shift) & ~3;
}
-void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- BMDMAState *bm = opaque;
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
-#endif
- bm->addr = val & ~3;
- bm->cur_addr = bm->addr;
-}
+const IORangeOps bmdma_addr_ioport_ops = {
+ .read = bmdma_addr_read,
+ .write = bmdma_addr_write,
+};
static bool ide_bmdma_current_needed(void *opaque)
{
diff --git a/hw/ide/pci.h b/hw/ide/pci.h
index d46a95e..b81b26c 100644
--- a/hw/ide/pci.h
+++ b/hw/ide/pci.h
@@ -11,12 +11,7 @@ typedef struct PCIIDEState {
} PCIIDEState;
void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val);
-uint32_t bmdma_addr_readb(void *opaque, uint32_t addr);
-void bmdma_addr_writeb(void *opaque, uint32_t addr, uint32_t val);
-uint32_t bmdma_addr_readw(void *opaque, uint32_t addr);
-void bmdma_addr_writew(void *opaque, uint32_t addr, uint32_t val);
-uint32_t bmdma_addr_readl(void *opaque, uint32_t addr);
-void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val);
+extern const IORangeOps bmdma_addr_ioport_ops;
void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
extern const VMStateDescription vmstate_ide_pci;
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 07483e8..e02b89a 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -85,12 +85,8 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
register_ioport_read(addr, 4, 1, bmdma_readb, bm);
- register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
- register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
- register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
- register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
- register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
- register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
+ iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
+ ioport_register(&bm->addr_ioport);
addr += 8;
}
}
diff --git a/hw/ide/via.c b/hw/ide/via.c
index b2c7cad..3e41d00 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -87,12 +87,8 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num,
register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
register_ioport_read(addr, 4, 1, bmdma_readb, bm);
- register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
- register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
- register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
- register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
- register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
- register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
+ iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
+ ioport_register(&bm->addr_ioport);
addr += 8;
}
}
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 5a3fd4b..93f0e9a 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -108,7 +108,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
int res = 0, unit;
loc_push_none(&loc);
- for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
+ for (unit = 0; unit < bus->ndev; unit++) {
dinfo = drive_get(IF_SCSI, bus->busnr, unit);
if (dinfo == NULL) {
continue;
@@ -123,16 +123,6 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
return res;
}
-void scsi_dev_clear_sense(SCSIDevice *dev)
-{
- memset(&dev->sense, 0, sizeof(dev->sense));
-}
-
-void scsi_dev_set_sense(SCSIDevice *dev, uint8_t key)
-{
- dev->sense.key = key;
-}
-
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun)
{
SCSIRequest *req;
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index a4a3518..1473ecb 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -111,18 +111,20 @@
#define BLANK 0xa1
/*
- * Status codes
+ * SAM Status codes
*/
#define GOOD 0x00
-#define CHECK_CONDITION 0x01
-#define CONDITION_GOOD 0x02
-#define BUSY 0x04
-#define INTERMEDIATE_GOOD 0x08
-#define INTERMEDIATE_C_GOOD 0x0a
-#define RESERVATION_CONFLICT 0x0c
-#define COMMAND_TERMINATED 0x11
-#define QUEUE_FULL 0x14
+#define CHECK_CONDITION 0x02
+#define CONDITION_GOOD 0x04
+#define BUSY 0x08
+#define INTERMEDIATE_GOOD 0x10
+#define INTERMEDIATE_C_GOOD 0x14
+#define RESERVATION_CONFLICT 0x18
+#define COMMAND_TERMINATED 0x22
+#define TASK_SET_FULL 0x28
+#define ACA_ACTIVE 0x30
+#define TASK_ABORTED 0x40
#define STATUS_MASK 0x3e
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index dc71957..6e49404 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -49,6 +49,10 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
typedef struct SCSIDiskState SCSIDiskState;
+typedef struct SCSISense {
+ uint8_t key;
+} SCSISense;
+
typedef struct SCSIDiskReq {
SCSIRequest req;
/* ??? We should probably keep track of whether the data transfer is
@@ -72,6 +76,7 @@ struct SCSIDiskState
QEMUBH *bh;
char *version;
char *serial;
+ SCSISense sense;
};
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
@@ -100,10 +105,22 @@ static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag)
return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag));
}
-static void scsi_req_set_status(SCSIRequest *req, int status, int sense_code)
+static void scsi_disk_clear_sense(SCSIDiskState *s)
+{
+ memset(&s->sense, 0, sizeof(s->sense));
+}
+
+static void scsi_disk_set_sense(SCSIDiskState *s, uint8_t key)
{
- req->status = status;
- scsi_dev_set_sense(req->dev, sense_code);
+ s->sense.key = key;
+}
+
+static void scsi_req_set_status(SCSIDiskReq *r, int status, int sense_code)
+{
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+ r->req.status = status;
+ scsi_disk_set_sense(s, sense_code);
}
/* Helper function for command completion. */
@@ -111,7 +128,7 @@ static void scsi_command_complete(SCSIDiskReq *r, int status, int sense)
{
DPRINTF("Command complete tag=0x%x status=%d sense=%d\n",
r->req.tag, status, sense);
- scsi_req_set_status(&r->req, status, sense);
+ scsi_req_set_status(r, status, sense);
scsi_req_complete(&r->req);
scsi_remove_request(r);
}
@@ -170,6 +187,9 @@ static void scsi_read_request(SCSIDiskReq *r)
return;
}
+ /* No data transfer may already be in progress */
+ assert(r->req.aiocb == NULL);
+
n = r->sector_count;
if (n > SCSI_DMA_BUF_SIZE / 512)
n = SCSI_DMA_BUF_SIZE / 512;
@@ -197,9 +217,6 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
return;
}
- /* No data transfer may already be in progress */
- assert(r->req.aiocb == NULL);
-
scsi_read_request(r);
}
@@ -269,6 +286,9 @@ static void scsi_write_request(SCSIDiskReq *r)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
+ /* No data transfer may already be in progress */
+ assert(r->req.aiocb == NULL);
+
n = r->iov.iov_len / 512;
if (n) {
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
@@ -298,9 +318,6 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
return 1;
}
- /* No data transfer may already be in progress */
- assert(r->req.aiocb == NULL);
-
scsi_write_request(r);
return 0;
@@ -398,15 +415,20 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
switch (page_code) {
case 0x00: /* Supported page codes, mandatory */
+ {
+ int pages;
DPRINTF("Inquiry EVPD[Supported pages] "
"buffer size %zd\n", req->cmd.xfer);
- outbuf[buflen++] = 4; // number of pages
+ pages = buflen++;
outbuf[buflen++] = 0x00; // list of supported pages (this page)
outbuf[buflen++] = 0x80; // unit serial number
outbuf[buflen++] = 0x83; // device identification
- outbuf[buflen++] = 0xb0; // block device characteristics
+ if (bdrv_get_type_hint(s->bs) != BDRV_TYPE_CDROM) {
+ outbuf[buflen++] = 0xb0; // block device characteristics
+ }
+ outbuf[pages] = buflen - pages - 1; // number of pages
break;
-
+ }
case 0x80: /* Device serial number, optional */
{
int l = strlen(s->serial);
@@ -434,7 +456,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
DPRINTF("Inquiry EVPD[Device identification] "
"buffer size %zd\n", req->cmd.xfer);
- outbuf[buflen++] = 3 + id_len;
+ outbuf[buflen++] = 4 + id_len;
outbuf[buflen++] = 0x2; // ASCII
outbuf[buflen++] = 0; // not officially assigned
outbuf[buflen++] = 0; // reserved
@@ -451,6 +473,11 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
unsigned int opt_io_size =
s->qdev.conf.opt_io_size / s->qdev.blocksize;
+ if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
+ DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
+ page_code);
+ return -1;
+ }
/* required VPD size with unmap support */
outbuf[3] = buflen = 0x3c;
@@ -812,7 +839,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
goto illegal_request;
memset(outbuf, 0, 4);
buflen = 4;
- if (req->dev->sense.key == NOT_READY && req->cmd.xfer >= 18) {
+ if (s->sense.key == NOT_READY && req->cmd.xfer >= 18) {
memset(outbuf, 0, 18);
buflen = 18;
outbuf[7] = 10;
@@ -822,8 +849,8 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
}
outbuf[0] = 0xf0;
outbuf[1] = 0;
- outbuf[2] = req->dev->sense.key;
- scsi_dev_clear_sense(req->dev);
+ outbuf[2] = s->sense.key;
+ scsi_disk_clear_sense(s);
break;
case INQUIRY:
buflen = scsi_disk_emulate_inquiry(req, outbuf);
@@ -956,7 +983,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
default:
goto illegal_request;
}
- scsi_req_set_status(req, GOOD, NO_SENSE);
+ scsi_req_set_status(r, GOOD, NO_SENSE);
return buflen;
not_ready:
@@ -977,9 +1004,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
uint8_t *buf, int lun)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
- uint64_t lba;
uint32_t len;
- int cmdlen;
int is_write;
uint8_t command;
uint8_t *outbuf;
@@ -998,55 +1023,21 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t 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]);
- switch (command >> 5) {
- case 0:
- lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
- (((uint64_t) buf[1] & 0x1f) << 16);
- len = buf[4];
- cmdlen = 6;
- break;
- case 1:
- case 2:
- lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
- ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
- len = buf[8] | (buf[7] << 8);
- cmdlen = 10;
- break;
- case 4:
- lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
- ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
- ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
- ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
- len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
- cmdlen = 16;
- break;
- case 5:
- lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
- ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
- len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
- cmdlen = 12;
- break;
- default:
+
+ if (scsi_req_parse(&r->req, buf) != 0) {
BADF("Unsupported command length, command %x\n", command);
goto fail;
}
#ifdef DEBUG_SCSI
{
int i;
- for (i = 1; i < cmdlen; i++) {
+ for (i = 1; i < r->req.cmd.len; i++) {
printf(" 0x%02x", buf[i]);
}
printf("\n");
}
#endif
- if (scsi_req_parse(&r->req, buf) != 0) {
- BADF("Unsupported command length, command %x\n", command);
- goto fail;
- }
- assert(r->req.cmd.len == cmdlen);
- assert(r->req.cmd.lba == lba);
-
if (lun || buf[1] >> 5) {
/* Only LUN 0 supported. */
DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
@@ -1084,10 +1075,11 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case READ_10:
case READ_12:
case READ_16:
- DPRINTF("Read (sector %" PRId64 ", count %d)\n", lba, len);
- if (lba > s->max_lba)
+ len = r->req.cmd.xfer / d->blocksize;
+ DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
+ if (r->req.cmd.lba > s->max_lba)
goto illegal_lba;
- r->sector = lba * s->cluster_size;
+ r->sector = r->req.cmd.lba * s->cluster_size;
r->sector_count = len * s->cluster_size;
break;
case WRITE_6:
@@ -1097,42 +1089,45 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case WRITE_VERIFY:
case WRITE_VERIFY_12:
case WRITE_VERIFY_16:
+ len = r->req.cmd.xfer / d->blocksize;
DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
- (command & 0xe) == 0xe ? "And Verify " : "", lba, len);
- if (lba > s->max_lba)
+ (command & 0xe) == 0xe ? "And Verify " : "",
+ r->req.cmd.lba, len);
+ if (r->req.cmd.lba > s->max_lba)
goto illegal_lba;
- r->sector = lba * s->cluster_size;
+ r->sector = r->req.cmd.lba * s->cluster_size;
r->sector_count = len * s->cluster_size;
is_write = 1;
break;
case MODE_SELECT:
- DPRINTF("Mode Select(6) (len %d)\n", len);
+ DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
/* We don't support mode parameter changes.
Allow the mode parameter header + block descriptors only. */
- if (len > 12) {
+ if (r->req.cmd.xfer > 12) {
goto fail;
}
break;
case MODE_SELECT_10:
- DPRINTF("Mode Select(10) (len %d)\n", len);
+ DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
/* We don't support mode parameter changes.
Allow the mode parameter header + block descriptors only. */
- if (len > 16) {
+ if (r->req.cmd.xfer > 16) {
goto fail;
}
break;
case SEEK_6:
case SEEK_10:
- DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10, lba);
- if (lba > s->max_lba) {
+ DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
+ r->req.cmd.lba);
+ if (r->req.cmd.lba > s->max_lba) {
goto illegal_lba;
}
break;
default:
- DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
+ DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
fail:
scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
- return 0;
+ return 0;
illegal_lba:
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
return 0;
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 7212091..9be1cca 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -96,17 +96,17 @@ static void scsi_command_complete(void *opaque, int ret)
s->senselen = r->io_header.sb_len_wr;
if (ret != 0)
- r->req.status = BUSY << 1;
+ r->req.status = BUSY;
else {
if (s->driver_status & SG_ERR_DRIVER_TIMEOUT) {
- r->req.status = BUSY << 1;
+ r->req.status = BUSY;
BADF("Driver Timeout\n");
} else if (r->io_header.status)
r->req.status = r->io_header.status;
else if (s->driver_status & SG_ERR_DRIVER_SENSE)
- r->req.status = CHECK_CONDITION << 1;
+ r->req.status = CHECK_CONDITION;
else
- r->req.status = GOOD << 1;
+ r->req.status = GOOD;
}
DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
r, r->req.tag, r->req.status);
@@ -333,7 +333,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
s->senselen = 7;
s->driver_status = SG_ERR_DRIVER_SENSE;
bus = scsi_bus_from_device(d);
- bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION << 1);
+ bus->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION);
return 0;
}
diff --git a/hw/scsi.h b/hw/scsi.h
index cb06d6d..bf02adf 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -3,6 +3,7 @@
#include "qdev.h"
#include "block.h"
+#include "blockdev.h"
#include "block_int.h"
#define SCSI_CMD_BUF_SIZE 16
@@ -25,10 +26,6 @@ enum SCSIXferMode {
SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */
};
-typedef struct SCSISense {
- uint8_t key;
-} SCSISense;
-
typedef struct SCSIRequest {
SCSIBus *bus;
SCSIDevice *dev;
@@ -56,7 +53,6 @@ struct SCSIDevice
QTAILQ_HEAD(, SCSIRequest) requests;
int blocksize;
int type;
- struct SCSISense sense;
};
/* cdrom.c */
@@ -86,7 +82,7 @@ struct SCSIBus {
int tcq, ndev;
scsi_completionfn complete;
- SCSIDevice *devs[8];
+ SCSIDevice *devs[MAX_SCSI_DEVS];
};
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
@@ -101,9 +97,6 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit);
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
-void scsi_dev_clear_sense(SCSIDevice *dev);
-void scsi_dev_set_sense(SCSIDevice *dev, uint8_t key);
-
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun);
SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag);
void scsi_req_free(SCSIRequest *req);
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 134ac33..85a1c85 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -181,6 +181,10 @@ static int ioreq_parse(struct ioreq *ioreq)
ioreq->prot = PROT_WRITE; /* to memory */
break;
case BLKIF_OP_WRITE_BARRIER:
+ if (!ioreq->req.nr_segments) {
+ ioreq->presync = 1;
+ return 0;
+ }
if (!syncwrite)
ioreq->presync = ioreq->postsync = 1;
/* fall through */
@@ -305,7 +309,7 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
int i, rc, len = 0;
off_t pos;
- if (ioreq_map(ioreq) == -1)
+ if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
goto err;
if (ioreq->presync)
bdrv_flush(blkdev->bs);
@@ -329,6 +333,8 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
break;
case BLKIF_OP_WRITE:
case BLKIF_OP_WRITE_BARRIER:
+ if (!ioreq->req.nr_segments)
+ break;
pos = ioreq->start;
for (i = 0; i < ioreq->v.niov; i++) {
rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE,
@@ -386,7 +392,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
{
struct XenBlkDev *blkdev = ioreq->blkdev;
- if (ioreq_map(ioreq) == -1)
+ if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
goto err;
ioreq->aio_inflight++;
@@ -403,6 +409,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
case BLKIF_OP_WRITE:
case BLKIF_OP_WRITE_BARRIER:
ioreq->aio_inflight++;
+ if (!ioreq->req.nr_segments)
+ break;
bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
qemu_aio_complete, ioreq);