aboutsummaryrefslogtreecommitdiff
path: root/hw/ide.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ide.c')
-rw-r--r--hw/ide.c173
1 files changed, 103 insertions, 70 deletions
diff --git a/hw/ide.c b/hw/ide.c
index f6999b1..6ad1d08 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -3429,110 +3429,143 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
typedef struct MACIOIDEState {
IDEState ide_if[2];
- int stream_index;
+ BlockDriverAIOCB *aiocb;
} MACIOIDEState;
-static void pmac_atapi_read(DBDMA_io *io)
+static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
{
+ DBDMA_io *io = opaque;
MACIOIDEState *m = io->opaque;
IDEState *s = m->ide_if->cur_drive;
- int ret, len;
-
- while (io->len > 0 &&
- s->packet_transfer_size > 0) {
- len = s->cd_sector_size;
- ret = cd_read_sector(s->bs, s->lba, s->io_buffer, len);
- if (ret < 0) {
- io->dma_end(io);
- ide_transfer_stop(s);
- ide_atapi_io_error(s, ret);
- return;
- }
+ if (ret < 0) {
+ m->aiocb = NULL;
+ qemu_sglist_destroy(&s->sg);
+ ide_atapi_io_error(s, ret);
+ io->dma_end(opaque);
+ return;
+ }
- if (len > io->len)
- len = io->len;
+ if (s->io_buffer_size > 0) {
+ m->aiocb = NULL;
+ qemu_sglist_destroy(&s->sg);
- cpu_physical_memory_write(io->addr,
- s->io_buffer + m->stream_index, len);
+ s->packet_transfer_size -= s->io_buffer_size;
- /* db-dma can ask for 512 bytes whereas block size is 2048... */
+ s->io_buffer_index += s->io_buffer_size;
+ s->lba += s->io_buffer_index >> 11;
+ s->io_buffer_index &= 0x7ff;
+ }
- m->stream_index += len;
- s->lba += m->stream_index / s->cd_sector_size;
- m->stream_index %= s->cd_sector_size;
+ if (s->packet_transfer_size <= 0)
+ ide_atapi_cmd_ok(s);
- io->len -= len;
- io->addr += len;
- s->packet_transfer_size -= len;
+ if (io->len == 0) {
+ io->dma_end(opaque);
+ return;
}
- if (io->len <= 0)
- io->dma_end(io);
+ /* launch next transfer */
- if (s->packet_transfer_size <= 0) {
- s->status = READY_STAT | SEEK_STAT;
- s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO
- | ATAPI_INT_REASON_CD;
- ide_set_irq(s);
+ s->io_buffer_size = io->len;
+
+ qemu_sglist_init(&s->sg, io->len / TARGET_PAGE_SIZE + 1);
+ qemu_sglist_add(&s->sg, io->addr, io->len);
+ io->addr += io->len;
+ io->len = 0;
+
+ m->aiocb = dma_bdrv_read(s->bs, &s->sg,
+ (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9),
+ pmac_ide_atapi_transfer_cb, io);
+ if (!m->aiocb) {
+ qemu_sglist_destroy(&s->sg);
+ /* Note: media not present is the most likely case */
+ ide_atapi_cmd_error(s, SENSE_NOT_READY,
+ ASC_MEDIUM_NOT_PRESENT);
+ io->dma_end(opaque);
+ return;
}
}
-static void pmac_ide_transfer(DBDMA_io *io)
+static void pmac_ide_transfer_cb(void *opaque, int ret)
{
+ DBDMA_io *io = opaque;
MACIOIDEState *m = io->opaque;
IDEState *s = m->ide_if->cur_drive;
+ int n;
int64_t sector_num;
- int ret, n;
- int len;
- if (s->is_cdrom) {
- pmac_atapi_read(io);
+ if (ret < 0) {
+ m->aiocb = NULL;
+ qemu_sglist_destroy(&s->sg);
+ ide_dma_error(s);
+ io->dma_end(io);
return;
}
- while (io->len > 0 && s->nsector > 0) {
+ sector_num = ide_get_sector(s);
+ if (s->io_buffer_size > 0) {
+ m->aiocb = NULL;
+ qemu_sglist_destroy(&s->sg);
+ n = (s->io_buffer_size + 0x1ff) >> 9;
+ sector_num += n;
+ ide_set_sector(s, sector_num);
+ s->nsector -= n;
+ }
+
+ /* end of transfer ? */
+ if (s->nsector == 0) {
+ s->status = READY_STAT | SEEK_STAT;
+ ide_set_irq(s);
+ }
- sector_num = ide_get_sector(s);
+ /* end of DMA ? */
- n = s->nsector;
- if (n > IDE_DMA_BUF_SECTORS)
- n = IDE_DMA_BUF_SECTORS;
+ if (io->len == 0) {
+ io->dma_end(io);
+ return;
+ }
- len = n << 9;
- if (len > io->len)
- len = io->len;
- n = (len + 511) >> 9;
+ /* launch next transfer */
- if (s->is_read) {
- ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
- cpu_physical_memory_write(io->addr, s->io_buffer, len);
- } else {
- cpu_physical_memory_read(io->addr, s->io_buffer, len);
- ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
- }
+ s->io_buffer_index = 0;
+ s->io_buffer_size = io->len;
- if (ret != 0) {
- io->dma_end(io);
- ide_rw_error(s);
- return;
- }
+ qemu_sglist_init(&s->sg, io->len / TARGET_PAGE_SIZE + 1);
+ qemu_sglist_add(&s->sg, io->addr, io->len);
+ io->addr += io->len;
+ io->len = 0;
- io->len -= len;
- io->addr += len;
- ide_set_sector(s, sector_num + n);
- s->nsector -= n;
- }
+ if (s->is_read)
+ m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
+ pmac_ide_transfer_cb, io);
+ else
+ m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
+ pmac_ide_transfer_cb, io);
+ if (!m->aiocb)
+ pmac_ide_transfer_cb(io, -1);
+}
- if (io->len <= 0)
- io->dma_end(io);
+static void pmac_ide_transfer(DBDMA_io *io)
+{
+ MACIOIDEState *m = io->opaque;
+ IDEState *s = m->ide_if->cur_drive;
- if (s->nsector <= 0) {
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
+ s->io_buffer_size = 0;
+ if (s->is_cdrom) {
+ pmac_ide_atapi_transfer_cb(io, 0);
+ return;
}
- return;
+ pmac_ide_transfer_cb(io, 0);
+}
+
+static void pmac_ide_flush(DBDMA_io *io)
+{
+ MACIOIDEState *m = io->opaque;
+
+ if (m->aiocb)
+ qemu_aio_flush();
}
/* PowerMac IDE memory IO */
@@ -3712,7 +3745,7 @@ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq,
ide_init2(d->ide_if, hd_table[0], hd_table[1], irq);
if (dbdma)
- DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, d);
+ DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d);
pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
pmac_ide_write, d);