From 85720d36676ef0b765a69f1e312b4c9d4ff6fa16 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sun, 18 May 2014 13:20:55 +0100 Subject: macio: handle non-block ATAPI DMA transfers Currently the macio DMA routines assume that all DMA requests are for read/write block transfers. This is not always the case for ATAPI, for example when requesting a TOC where the response is generated directly in the IDE buffer. Detect these non-block ATAPI DMA transfers (where no lba is specified in the command) and copy the results directly into RAM as indicated by the DBDMA descriptor. This fixes CDROM access under MorphOS. Signed-off-by: Mark Cave-Ayland Signed-off-by: Alexander Graf --- hw/ide/macio.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'hw/ide') diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 1c20616..af57168 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -337,6 +337,27 @@ static void pmac_ide_transfer(DBDMA_io *io) s->io_buffer_size = 0; if (s->drive_kind == IDE_CD) { + + /* Handle non-block ATAPI DMA transfers */ + if (s->lba == -1) { + s->io_buffer_size = MIN(io->len, s->packet_transfer_size); + bdrv_acct_start(s->bs, &s->acct, s->io_buffer_size, + BDRV_ACCT_READ); + MACIO_DPRINTF("non-block ATAPI DMA transfer size: %d\n", + s->io_buffer_size); + + /* Copy ATAPI buffer directly to RAM and finish */ + cpu_physical_memory_write(io->addr, s->io_buffer, + s->io_buffer_size); + ide_atapi_cmd_ok(s); + m->dma_active = false; + + MACIO_DPRINTF("end of non-block ATAPI DMA transfer\n"); + bdrv_acct_done(s->bs, &s->acct); + io->dma_end(io); + return; + } + bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ); pmac_ide_atapi_transfer_cb(io, 0); return; -- cgit v1.1 From 3e300fa6ad4ee19b16339c25773dec8df0bfb982 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 26 May 2014 10:27:58 +0200 Subject: macio ide: Do remainder access asynchronously The macio IDE controller has some pretty nasty magic in its implementation to allow for unaligned sector accesses. We used to handle these accesses synchronously inside the IO callback handler. However, the block infrastructure changed below our feet and now it's impossible to call a synchronous block read/write from the aio callback handler of a previous block access. Work around that limitation by making the unaligned handling bits also go through our asynchronous handler. This fixes booting Mac OS X for me. Reported-by: John Arbuckle Signed-off-by: Alexander Graf --- hw/ide/macio.c | 50 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) (limited to 'hw/ide') diff --git a/hw/ide/macio.c b/hw/ide/macio.c index af57168..c14a1dd 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -193,6 +193,11 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) goto done; } + if (--io->requests) { + /* More requests still in flight */ + return; + } + if (!m->dma_active) { MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n", s->nsector, io->len, s->status); @@ -212,6 +217,13 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) s->nsector -= n; } + if (io->finish_remain_read) { + /* Finish a stale read from the last iteration */ + io->finish_remain_read = false; + cpu_physical_memory_write(io->finish_addr, io->remainder, + io->finish_len); + } + MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d " "sector_num: %" PRId64 "\n", io->remainder_len, io->len, s->nsector, sector_num); @@ -229,7 +241,6 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) break; case IDE_DMA_WRITE: cpu_physical_memory_read(io->addr, p, remainder_len); - bdrv_write(s->bs, sector_num - 1, io->remainder, 1); break; case IDE_DMA_TRIM: break; @@ -237,6 +248,15 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) io->addr += remainder_len; io->len -= remainder_len; io->remainder_len -= remainder_len; + + if (s->dma_cmd == IDE_DMA_WRITE && !io->remainder_len) { + io->requests++; + qemu_iovec_reset(&io->iov); + qemu_iovec_add(&io->iov, io->remainder, 0x200); + + m->aiocb = bdrv_aio_writev(s->bs, sector_num - 1, &io->iov, 1, + pmac_ide_transfer_cb, io); + } } if (s->nsector == 0 && !io->remainder_len) { @@ -267,20 +287,25 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) switch (s->dma_cmd) { case IDE_DMA_READ: - bdrv_read(s->bs, sector_num + nsector, io->remainder, 1); - cpu_physical_memory_write(io->addr + io->len - unaligned, - io->remainder, unaligned); + io->requests++; + io->finish_addr = io->addr + io->len - unaligned; + io->finish_len = unaligned; + io->finish_remain_read = true; + qemu_iovec_reset(&io->iov); + qemu_iovec_add(&io->iov, io->remainder, 0x200); + + m->aiocb = bdrv_aio_readv(s->bs, sector_num + nsector, &io->iov, 1, + pmac_ide_transfer_cb, io); break; case IDE_DMA_WRITE: /* cache the contents in our io struct */ cpu_physical_memory_read(io->addr + io->len - unaligned, - io->remainder, unaligned); + io->remainder + io->remainder_len, + unaligned); break; case IDE_DMA_TRIM: break; } - - io->len -= unaligned; } MACIO_DPRINTF("io->len = %#x\n", io->len); @@ -292,10 +317,12 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) io->remainder_len = (0x200 - unaligned) & 0x1ff; MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len); - /* We would read no data from the block layer, thus not get a callback. - Just fake completion manually. */ + /* Only subsector reads happening */ if (!io->len) { - pmac_ide_transfer_cb(opaque, 0); + if (!io->requests) { + io->requests++; + pmac_ide_transfer_cb(opaque, ret); + } return; } @@ -319,6 +346,8 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) DMA_DIRECTION_TO_DEVICE); break; } + + io->requests++; return; done: @@ -374,6 +403,7 @@ static void pmac_ide_transfer(DBDMA_io *io) break; } + io->requests++; pmac_ide_transfer_cb(io, 0); } -- cgit v1.1