xref: /qemu/hw/ide/macio.c (revision bd4214fc92090694aefa17882815c6109f0fd70c)
1b8842209SGerd Hoffmann /*
2b8842209SGerd Hoffmann  * QEMU IDE Emulation: MacIO support.
3b8842209SGerd Hoffmann  *
4b8842209SGerd Hoffmann  * Copyright (c) 2003 Fabrice Bellard
5b8842209SGerd Hoffmann  * Copyright (c) 2006 Openedhand Ltd.
6b8842209SGerd Hoffmann  *
7b8842209SGerd Hoffmann  * Permission is hereby granted, free of charge, to any person obtaining a copy
8b8842209SGerd Hoffmann  * of this software and associated documentation files (the "Software"), to deal
9b8842209SGerd Hoffmann  * in the Software without restriction, including without limitation the rights
10b8842209SGerd Hoffmann  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11b8842209SGerd Hoffmann  * copies of the Software, and to permit persons to whom the Software is
12b8842209SGerd Hoffmann  * furnished to do so, subject to the following conditions:
13b8842209SGerd Hoffmann  *
14b8842209SGerd Hoffmann  * The above copyright notice and this permission notice shall be included in
15b8842209SGerd Hoffmann  * all copies or substantial portions of the Software.
16b8842209SGerd Hoffmann  *
17b8842209SGerd Hoffmann  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18b8842209SGerd Hoffmann  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19b8842209SGerd Hoffmann  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20b8842209SGerd Hoffmann  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21b8842209SGerd Hoffmann  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22b8842209SGerd Hoffmann  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23b8842209SGerd Hoffmann  * THE SOFTWARE.
24b8842209SGerd Hoffmann  */
25baec1910SAndreas Färber #include "hw/hw.h"
26baec1910SAndreas Färber #include "hw/ppc/mac.h"
270d09e41aSPaolo Bonzini #include "hw/ppc/mac_dbdma.h"
284be74634SMarkus Armbruster #include "sysemu/block-backend.h"
299c17d615SPaolo Bonzini #include "sysemu/dma.h"
3059f2a787SGerd Hoffmann 
3159f2a787SGerd Hoffmann #include <hw/ide/internal.h>
32b8842209SGerd Hoffmann 
3333ce36bbSAlexander Graf /* debug MACIO */
3433ce36bbSAlexander Graf // #define DEBUG_MACIO
3533ce36bbSAlexander Graf 
3633ce36bbSAlexander Graf #ifdef DEBUG_MACIO
3733ce36bbSAlexander Graf static const int debug_macio = 1;
3833ce36bbSAlexander Graf #else
3933ce36bbSAlexander Graf static const int debug_macio = 0;
4033ce36bbSAlexander Graf #endif
4133ce36bbSAlexander Graf 
4233ce36bbSAlexander Graf #define MACIO_DPRINTF(fmt, ...) do { \
4333ce36bbSAlexander Graf         if (debug_macio) { \
4433ce36bbSAlexander Graf             printf(fmt , ## __VA_ARGS__); \
4533ce36bbSAlexander Graf         } \
4633ce36bbSAlexander Graf     } while (0)
4733ce36bbSAlexander Graf 
4833ce36bbSAlexander Graf 
49b8842209SGerd Hoffmann /***********************************************************/
50b8842209SGerd Hoffmann /* MacIO based PowerPC IDE */
51b8842209SGerd Hoffmann 
5202c7c992SBlue Swirl #define MACIO_PAGE_SIZE 4096
5302c7c992SBlue Swirl 
544827ac1eSMark Cave-Ayland static void pmac_dma_read(BlockBackend *blk,
554827ac1eSMark Cave-Ayland                           int64_t sector_num, int nb_sectors,
564827ac1eSMark Cave-Ayland                           void (*cb)(void *opaque, int ret), void *opaque)
574827ac1eSMark Cave-Ayland {
584827ac1eSMark Cave-Ayland     DBDMA_io *io = opaque;
594827ac1eSMark Cave-Ayland     MACIOIDEState *m = io->opaque;
604827ac1eSMark Cave-Ayland     IDEState *s = idebus_active_if(&m->bus);
614827ac1eSMark Cave-Ayland     dma_addr_t dma_addr, dma_len;
624827ac1eSMark Cave-Ayland     void *mem;
634827ac1eSMark Cave-Ayland     int nsector, remainder;
644827ac1eSMark Cave-Ayland 
654827ac1eSMark Cave-Ayland     qemu_iovec_destroy(&io->iov);
664827ac1eSMark Cave-Ayland     qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
674827ac1eSMark Cave-Ayland 
684827ac1eSMark Cave-Ayland     if (io->remainder_len > 0) {
694827ac1eSMark Cave-Ayland         /* Return remainder of request */
704827ac1eSMark Cave-Ayland         int transfer = MIN(io->remainder_len, io->len);
714827ac1eSMark Cave-Ayland 
724827ac1eSMark Cave-Ayland         MACIO_DPRINTF("--- DMA read pop     - bounce addr: %p addr: %"
734827ac1eSMark Cave-Ayland                       HWADDR_PRIx " remainder_len: %x\n",
744827ac1eSMark Cave-Ayland                       &io->remainder + (0x200 - transfer), io->addr,
754827ac1eSMark Cave-Ayland                       io->remainder_len);
764827ac1eSMark Cave-Ayland 
774827ac1eSMark Cave-Ayland         cpu_physical_memory_write(io->addr,
784827ac1eSMark Cave-Ayland                                   &io->remainder + (0x200 - transfer),
794827ac1eSMark Cave-Ayland                                   transfer);
804827ac1eSMark Cave-Ayland 
814827ac1eSMark Cave-Ayland         io->remainder_len -= transfer;
824827ac1eSMark Cave-Ayland         io->len -= transfer;
834827ac1eSMark Cave-Ayland         io->addr += transfer;
844827ac1eSMark Cave-Ayland 
854827ac1eSMark Cave-Ayland         s->io_buffer_index += transfer;
864827ac1eSMark Cave-Ayland         s->io_buffer_size -= transfer;
874827ac1eSMark Cave-Ayland 
884827ac1eSMark Cave-Ayland         if (io->remainder_len != 0) {
894827ac1eSMark Cave-Ayland             /* Still waiting for remainder */
904827ac1eSMark Cave-Ayland             return;
914827ac1eSMark Cave-Ayland         }
924827ac1eSMark Cave-Ayland 
934827ac1eSMark Cave-Ayland         if (io->len == 0) {
944827ac1eSMark Cave-Ayland             MACIO_DPRINTF("--- finished all read processing; go and finish\n");
954827ac1eSMark Cave-Ayland             cb(opaque, 0);
964827ac1eSMark Cave-Ayland             return;
974827ac1eSMark Cave-Ayland         }
984827ac1eSMark Cave-Ayland     }
994827ac1eSMark Cave-Ayland 
1004827ac1eSMark Cave-Ayland     if (s->drive_kind == IDE_CD) {
1014827ac1eSMark Cave-Ayland         sector_num = (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9);
1024827ac1eSMark Cave-Ayland     } else {
1034827ac1eSMark Cave-Ayland         sector_num = ide_get_sector(s) + (s->io_buffer_index >> 9);
1044827ac1eSMark Cave-Ayland     }
1054827ac1eSMark Cave-Ayland 
1064827ac1eSMark Cave-Ayland     nsector = ((io->len + 0x1ff) >> 9);
1074827ac1eSMark Cave-Ayland     remainder = (nsector << 9) - io->len;
1084827ac1eSMark Cave-Ayland 
1094827ac1eSMark Cave-Ayland     MACIO_DPRINTF("--- DMA read transfer - addr: %" HWADDR_PRIx " len: %x\n",
1104827ac1eSMark Cave-Ayland                   io->addr, io->len);
1114827ac1eSMark Cave-Ayland 
1124827ac1eSMark Cave-Ayland     dma_addr = io->addr;
1134827ac1eSMark Cave-Ayland     dma_len = io->len;
1144827ac1eSMark Cave-Ayland     mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
1154827ac1eSMark Cave-Ayland                          DMA_DIRECTION_FROM_DEVICE);
1164827ac1eSMark Cave-Ayland 
1174827ac1eSMark Cave-Ayland     if (!remainder) {
1184827ac1eSMark Cave-Ayland         MACIO_DPRINTF("--- DMA read aligned - addr: %" HWADDR_PRIx
1194827ac1eSMark Cave-Ayland                       " len: %x\n", io->addr, io->len);
1204827ac1eSMark Cave-Ayland         qemu_iovec_add(&io->iov, mem, io->len);
1214827ac1eSMark Cave-Ayland     } else {
1224827ac1eSMark Cave-Ayland         MACIO_DPRINTF("--- DMA read unaligned - addr: %" HWADDR_PRIx
1234827ac1eSMark Cave-Ayland                       " len: %x\n", io->addr, io->len);
1244827ac1eSMark Cave-Ayland         qemu_iovec_add(&io->iov, mem, io->len);
1254827ac1eSMark Cave-Ayland 
1264827ac1eSMark Cave-Ayland         MACIO_DPRINTF("--- DMA read push    - bounce addr: %p "
1274827ac1eSMark Cave-Ayland                       "remainder_len: %x\n",
1284827ac1eSMark Cave-Ayland                       &io->remainder + 0x200 - remainder, remainder);
1294827ac1eSMark Cave-Ayland         qemu_iovec_add(&io->iov, &io->remainder + 0x200 - remainder,
1304827ac1eSMark Cave-Ayland                        remainder);
1314827ac1eSMark Cave-Ayland 
1324827ac1eSMark Cave-Ayland         io->remainder_len = remainder;
1334827ac1eSMark Cave-Ayland     }
1344827ac1eSMark Cave-Ayland 
1354827ac1eSMark Cave-Ayland     s->io_buffer_size -= io->len;
1364827ac1eSMark Cave-Ayland     s->io_buffer_index += io->len;
1374827ac1eSMark Cave-Ayland 
1384827ac1eSMark Cave-Ayland     io->len = 0;
1394827ac1eSMark Cave-Ayland 
1404827ac1eSMark Cave-Ayland     MACIO_DPRINTF("--- Block read transfer   - sector_num: %"PRIx64"  "
1414827ac1eSMark Cave-Ayland                   "nsector: %x\n",
1424827ac1eSMark Cave-Ayland                   sector_num, nsector);
1434827ac1eSMark Cave-Ayland 
1444827ac1eSMark Cave-Ayland     m->aiocb = blk_aio_readv(blk, sector_num, &io->iov, nsector, cb, io);
1454827ac1eSMark Cave-Ayland }
1464827ac1eSMark Cave-Ayland 
147*bd4214fcSMark Cave-Ayland static void pmac_dma_write(BlockBackend *blk,
148*bd4214fcSMark Cave-Ayland                          int64_t sector_num, int nb_sectors,
149*bd4214fcSMark Cave-Ayland                          void (*cb)(void *opaque, int ret), void *opaque)
150*bd4214fcSMark Cave-Ayland {
151*bd4214fcSMark Cave-Ayland     DBDMA_io *io = opaque;
152*bd4214fcSMark Cave-Ayland     MACIOIDEState *m = io->opaque;
153*bd4214fcSMark Cave-Ayland     IDEState *s = idebus_active_if(&m->bus);
154*bd4214fcSMark Cave-Ayland     dma_addr_t dma_addr, dma_len;
155*bd4214fcSMark Cave-Ayland     void *mem;
156*bd4214fcSMark Cave-Ayland     int nsector, remainder;
157*bd4214fcSMark Cave-Ayland     int extra = 0;
158*bd4214fcSMark Cave-Ayland 
159*bd4214fcSMark Cave-Ayland     qemu_iovec_destroy(&io->iov);
160*bd4214fcSMark Cave-Ayland     qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
161*bd4214fcSMark Cave-Ayland 
162*bd4214fcSMark Cave-Ayland     if (io->remainder_len > 0) {
163*bd4214fcSMark Cave-Ayland         /* Return remainder of request */
164*bd4214fcSMark Cave-Ayland         int transfer = MIN(io->remainder_len, io->len);
165*bd4214fcSMark Cave-Ayland 
166*bd4214fcSMark Cave-Ayland         MACIO_DPRINTF("--- processing write remainder %x\n", transfer);
167*bd4214fcSMark Cave-Ayland         cpu_physical_memory_read(io->addr,
168*bd4214fcSMark Cave-Ayland                                  &io->remainder + (0x200 - transfer),
169*bd4214fcSMark Cave-Ayland                                  transfer);
170*bd4214fcSMark Cave-Ayland 
171*bd4214fcSMark Cave-Ayland         io->remainder_len -= transfer;
172*bd4214fcSMark Cave-Ayland         io->len -= transfer;
173*bd4214fcSMark Cave-Ayland         io->addr += transfer;
174*bd4214fcSMark Cave-Ayland 
175*bd4214fcSMark Cave-Ayland         s->io_buffer_index += transfer;
176*bd4214fcSMark Cave-Ayland         s->io_buffer_size -= transfer;
177*bd4214fcSMark Cave-Ayland 
178*bd4214fcSMark Cave-Ayland         if (io->remainder_len != 0) {
179*bd4214fcSMark Cave-Ayland             /* Still waiting for remainder */
180*bd4214fcSMark Cave-Ayland             return;
181*bd4214fcSMark Cave-Ayland         }
182*bd4214fcSMark Cave-Ayland 
183*bd4214fcSMark Cave-Ayland         MACIO_DPRINTF("--> prepending bounce buffer with size 0x200\n");
184*bd4214fcSMark Cave-Ayland 
185*bd4214fcSMark Cave-Ayland         /* Sector transfer complete - prepend to request */
186*bd4214fcSMark Cave-Ayland         qemu_iovec_add(&io->iov, &io->remainder, 0x200);
187*bd4214fcSMark Cave-Ayland         extra = 1;
188*bd4214fcSMark Cave-Ayland     }
189*bd4214fcSMark Cave-Ayland 
190*bd4214fcSMark Cave-Ayland     if (s->drive_kind == IDE_CD) {
191*bd4214fcSMark Cave-Ayland         sector_num = (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9);
192*bd4214fcSMark Cave-Ayland     } else {
193*bd4214fcSMark Cave-Ayland         sector_num = ide_get_sector(s) + (s->io_buffer_index >> 9);
194*bd4214fcSMark Cave-Ayland     }
195*bd4214fcSMark Cave-Ayland 
196*bd4214fcSMark Cave-Ayland     nsector = (io->len >> 9);
197*bd4214fcSMark Cave-Ayland     remainder = io->len - (nsector << 9);
198*bd4214fcSMark Cave-Ayland 
199*bd4214fcSMark Cave-Ayland     MACIO_DPRINTF("--- DMA write transfer - addr: %" HWADDR_PRIx " len: %x\n",
200*bd4214fcSMark Cave-Ayland                   io->addr, io->len);
201*bd4214fcSMark Cave-Ayland     MACIO_DPRINTF("xxx remainder: %x\n", remainder);
202*bd4214fcSMark Cave-Ayland     MACIO_DPRINTF("xxx sector_num: %"PRIx64"   nsector: %x\n",
203*bd4214fcSMark Cave-Ayland                   sector_num, nsector);
204*bd4214fcSMark Cave-Ayland 
205*bd4214fcSMark Cave-Ayland     dma_addr = io->addr;
206*bd4214fcSMark Cave-Ayland     dma_len = io->len;
207*bd4214fcSMark Cave-Ayland     mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
208*bd4214fcSMark Cave-Ayland                          DMA_DIRECTION_TO_DEVICE);
209*bd4214fcSMark Cave-Ayland 
210*bd4214fcSMark Cave-Ayland     if (!remainder) {
211*bd4214fcSMark Cave-Ayland         MACIO_DPRINTF("--- DMA write aligned - addr: %" HWADDR_PRIx
212*bd4214fcSMark Cave-Ayland                       " len: %x\n", io->addr, io->len);
213*bd4214fcSMark Cave-Ayland         qemu_iovec_add(&io->iov, mem, io->len);
214*bd4214fcSMark Cave-Ayland     } else {
215*bd4214fcSMark Cave-Ayland         /* Write up to last complete sector */
216*bd4214fcSMark Cave-Ayland         MACIO_DPRINTF("--- DMA write unaligned - addr: %" HWADDR_PRIx
217*bd4214fcSMark Cave-Ayland                       " len: %x\n", io->addr, (nsector << 9));
218*bd4214fcSMark Cave-Ayland         qemu_iovec_add(&io->iov, mem, (nsector << 9));
219*bd4214fcSMark Cave-Ayland 
220*bd4214fcSMark Cave-Ayland         MACIO_DPRINTF("--- DMA write read    - bounce addr: %p "
221*bd4214fcSMark Cave-Ayland                       "remainder_len: %x\n", &io->remainder, remainder);
222*bd4214fcSMark Cave-Ayland         cpu_physical_memory_read(io->addr + (nsector << 9), &io->remainder,
223*bd4214fcSMark Cave-Ayland                                  remainder);
224*bd4214fcSMark Cave-Ayland 
225*bd4214fcSMark Cave-Ayland         io->remainder_len = 0x200 - remainder;
226*bd4214fcSMark Cave-Ayland 
227*bd4214fcSMark Cave-Ayland         MACIO_DPRINTF("xxx remainder_len: %x\n", io->remainder_len);
228*bd4214fcSMark Cave-Ayland     }
229*bd4214fcSMark Cave-Ayland 
230*bd4214fcSMark Cave-Ayland     s->io_buffer_size -= ((nsector + extra) << 9);
231*bd4214fcSMark Cave-Ayland     s->io_buffer_index += ((nsector + extra) << 9);
232*bd4214fcSMark Cave-Ayland 
233*bd4214fcSMark Cave-Ayland     io->len = 0;
234*bd4214fcSMark Cave-Ayland 
235*bd4214fcSMark Cave-Ayland     MACIO_DPRINTF("--- Block write transfer   - sector_num: %"PRIx64"  "
236*bd4214fcSMark Cave-Ayland                   "nsector: %x\n", sector_num, nsector + extra);
237*bd4214fcSMark Cave-Ayland 
238*bd4214fcSMark Cave-Ayland     m->aiocb = blk_aio_writev(blk, sector_num, &io->iov, nsector + extra, cb,
239*bd4214fcSMark Cave-Ayland                               io);
240*bd4214fcSMark Cave-Ayland }
241*bd4214fcSMark Cave-Ayland 
242b8842209SGerd Hoffmann static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
243b8842209SGerd Hoffmann {
244b8842209SGerd Hoffmann     DBDMA_io *io = opaque;
245b8842209SGerd Hoffmann     MACIOIDEState *m = io->opaque;
246b8842209SGerd Hoffmann     IDEState *s = idebus_active_if(&m->bus);
2474827ac1eSMark Cave-Ayland     int64_t sector_num;
2484827ac1eSMark Cave-Ayland     int nsector, remainder;
2494827ac1eSMark Cave-Ayland 
2504827ac1eSMark Cave-Ayland     MACIO_DPRINTF("\ns is %p\n", s);
2514827ac1eSMark Cave-Ayland     MACIO_DPRINTF("io_buffer_index: %x\n", s->io_buffer_index);
2524827ac1eSMark Cave-Ayland     MACIO_DPRINTF("io_buffer_size: %x   packet_transfer_size: %x\n",
2534827ac1eSMark Cave-Ayland                   s->io_buffer_size, s->packet_transfer_size);
2544827ac1eSMark Cave-Ayland     MACIO_DPRINTF("lba: %x\n", s->lba);
2554827ac1eSMark Cave-Ayland     MACIO_DPRINTF("io_addr: %" HWADDR_PRIx "  io_len: %x\n", io->addr,
2564827ac1eSMark Cave-Ayland                   io->len);
257b8842209SGerd Hoffmann 
258b8842209SGerd Hoffmann     if (ret < 0) {
2594827ac1eSMark Cave-Ayland         MACIO_DPRINTF("THERE WAS AN ERROR!  %d\n", ret);
260b8842209SGerd Hoffmann         ide_atapi_io_error(s, ret);
261a597e79cSChristoph Hellwig         goto done;
262b8842209SGerd Hoffmann     }
263b8842209SGerd Hoffmann 
264cae32357SAlexander Graf     if (!m->dma_active) {
265cae32357SAlexander Graf         MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
266cae32357SAlexander Graf                       s->nsector, io->len, s->status);
267cae32357SAlexander Graf         /* data not ready yet, wait for the channel to get restarted */
268cae32357SAlexander Graf         io->processing = false;
269cae32357SAlexander Graf         return;
270cae32357SAlexander Graf     }
271cae32357SAlexander Graf 
2724827ac1eSMark Cave-Ayland     if (s->io_buffer_size <= 0) {
273b8842209SGerd Hoffmann         ide_atapi_cmd_ok(s);
274cae32357SAlexander Graf         m->dma_active = false;
275a597e79cSChristoph Hellwig         goto done;
276b8842209SGerd Hoffmann     }
277b8842209SGerd Hoffmann 
2784827ac1eSMark Cave-Ayland     if (io->len == 0) {
2794827ac1eSMark Cave-Ayland         MACIO_DPRINTF("End of DMA transfer\n");
2804827ac1eSMark Cave-Ayland         goto done;
28180fc95d8SAlexander Graf     }
28280fc95d8SAlexander Graf 
2834827ac1eSMark Cave-Ayland     if (s->lba == -1) {
2844827ac1eSMark Cave-Ayland         /* Non-block ATAPI transfer - just copy to RAM */
2854827ac1eSMark Cave-Ayland         s->io_buffer_size = MIN(s->io_buffer_size, io->len);
2864827ac1eSMark Cave-Ayland         cpu_physical_memory_write(io->addr, s->io_buffer, s->io_buffer_size);
2874827ac1eSMark Cave-Ayland         ide_atapi_cmd_ok(s);
2884827ac1eSMark Cave-Ayland         m->dma_active = false;
2894827ac1eSMark Cave-Ayland         goto done;
29080fc95d8SAlexander Graf     }
29180fc95d8SAlexander Graf 
2924827ac1eSMark Cave-Ayland     /* Calculate number of sectors */
2934827ac1eSMark Cave-Ayland     sector_num = (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9);
2944827ac1eSMark Cave-Ayland     nsector = (io->len + 0x1ff) >> 9;
2954827ac1eSMark Cave-Ayland     remainder = io->len & 0x1ff;
296b8842209SGerd Hoffmann 
2974827ac1eSMark Cave-Ayland     MACIO_DPRINTF("nsector: %d   remainder: %x\n", nsector, remainder);
2984827ac1eSMark Cave-Ayland     MACIO_DPRINTF("sector: %"PRIx64"   %zx\n", sector_num, io->iov.size / 512);
29933ce36bbSAlexander Graf 
3004827ac1eSMark Cave-Ayland     pmac_dma_read(s->blk, sector_num, nsector, pmac_ide_atapi_transfer_cb, io);
301a597e79cSChristoph Hellwig     return;
302a597e79cSChristoph Hellwig 
303a597e79cSChristoph Hellwig done:
3044827ac1eSMark Cave-Ayland     MACIO_DPRINTF("done DMA\n\n");
3054be74634SMarkus Armbruster     block_acct_done(blk_get_stats(s->blk), &s->acct);
306b8842209SGerd Hoffmann     io->dma_end(opaque);
3074827ac1eSMark Cave-Ayland 
3084827ac1eSMark Cave-Ayland     return;
309b8842209SGerd Hoffmann }
310b8842209SGerd Hoffmann 
311b8842209SGerd Hoffmann static void pmac_ide_transfer_cb(void *opaque, int ret)
312b8842209SGerd Hoffmann {
313b8842209SGerd Hoffmann     DBDMA_io *io = opaque;
314b8842209SGerd Hoffmann     MACIOIDEState *m = io->opaque;
315b8842209SGerd Hoffmann     IDEState *s = idebus_active_if(&m->bus);
316b8842209SGerd Hoffmann     int64_t sector_num;
317*bd4214fcSMark Cave-Ayland     int nsector, remainder;
318*bd4214fcSMark Cave-Ayland 
319*bd4214fcSMark Cave-Ayland     MACIO_DPRINTF("pmac_ide_transfer_cb\n");
320b8842209SGerd Hoffmann 
321b8842209SGerd Hoffmann     if (ret < 0) {
32233ce36bbSAlexander Graf         MACIO_DPRINTF("DMA error\n");
323b8842209SGerd Hoffmann         m->aiocb = NULL;
324b8842209SGerd Hoffmann         ide_dma_error(s);
32580fc95d8SAlexander Graf         io->remainder_len = 0;
326a597e79cSChristoph Hellwig         goto done;
327b8842209SGerd Hoffmann     }
328b8842209SGerd Hoffmann 
329cae32357SAlexander Graf     if (!m->dma_active) {
330cae32357SAlexander Graf         MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
331cae32357SAlexander Graf                       s->nsector, io->len, s->status);
332cae32357SAlexander Graf         /* data not ready yet, wait for the channel to get restarted */
333cae32357SAlexander Graf         io->processing = false;
334cae32357SAlexander Graf         return;
335cae32357SAlexander Graf     }
336cae32357SAlexander Graf 
337*bd4214fcSMark Cave-Ayland     if (s->io_buffer_size <= 0) {
33833ce36bbSAlexander Graf         MACIO_DPRINTF("end of transfer\n");
339b8842209SGerd Hoffmann         s->status = READY_STAT | SEEK_STAT;
3409cdd03a7SGerd Hoffmann         ide_set_irq(s->bus);
341cae32357SAlexander Graf         m->dma_active = false;
342a597e79cSChristoph Hellwig         goto done;
343b8842209SGerd Hoffmann     }
344b8842209SGerd Hoffmann 
345*bd4214fcSMark Cave-Ayland     if (io->len == 0) {
346*bd4214fcSMark Cave-Ayland         MACIO_DPRINTF("End of DMA transfer\n");
347*bd4214fcSMark Cave-Ayland         goto done;
348*bd4214fcSMark Cave-Ayland     }
349b8842209SGerd Hoffmann 
350*bd4214fcSMark Cave-Ayland     /* Calculate number of sectors */
351*bd4214fcSMark Cave-Ayland     sector_num = ide_get_sector(s) + (s->io_buffer_index >> 9);
352*bd4214fcSMark Cave-Ayland     nsector = (io->len + 0x1ff) >> 9;
353*bd4214fcSMark Cave-Ayland     remainder = io->len & 0x1ff;
354b8842209SGerd Hoffmann 
355*bd4214fcSMark Cave-Ayland     s->nsector -= nsector;
35680fc95d8SAlexander Graf 
357*bd4214fcSMark Cave-Ayland     MACIO_DPRINTF("nsector: %d   remainder: %x\n", nsector, remainder);
358*bd4214fcSMark Cave-Ayland     MACIO_DPRINTF("sector: %"PRIx64"   %x\n", sector_num, nsector);
35980fc95d8SAlexander Graf 
36080fc95d8SAlexander Graf     switch (s->dma_cmd) {
36180fc95d8SAlexander Graf     case IDE_DMA_READ:
362*bd4214fcSMark Cave-Ayland         pmac_dma_read(s->blk, sector_num, nsector, pmac_ide_transfer_cb, io);
36380fc95d8SAlexander Graf         break;
36480fc95d8SAlexander Graf     case IDE_DMA_WRITE:
365*bd4214fcSMark Cave-Ayland         pmac_dma_write(s->blk, sector_num, nsector, pmac_ide_transfer_cb, io);
36680fc95d8SAlexander Graf         break;
36780fc95d8SAlexander Graf     case IDE_DMA_TRIM:
368*bd4214fcSMark Cave-Ayland         MACIO_DPRINTF("TRIM command issued!");
369d353fb72SChristoph Hellwig         break;
3704e1e0051SChristoph Hellwig     }
3713e300fa6SAlexander Graf 
372a597e79cSChristoph Hellwig     return;
373b9b2008bSPaolo Bonzini 
374a597e79cSChristoph Hellwig done:
375a597e79cSChristoph Hellwig     if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
3764be74634SMarkus Armbruster         block_acct_done(blk_get_stats(s->blk), &s->acct);
377a597e79cSChristoph Hellwig     }
378*bd4214fcSMark Cave-Ayland     io->dma_end(opaque);
379b8842209SGerd Hoffmann }
380b8842209SGerd Hoffmann 
381b8842209SGerd Hoffmann static void pmac_ide_transfer(DBDMA_io *io)
382b8842209SGerd Hoffmann {
383b8842209SGerd Hoffmann     MACIOIDEState *m = io->opaque;
384b8842209SGerd Hoffmann     IDEState *s = idebus_active_if(&m->bus);
385b8842209SGerd Hoffmann 
38633ce36bbSAlexander Graf     MACIO_DPRINTF("\n");
38733ce36bbSAlexander Graf 
388cd8722bbSMarkus Armbruster     if (s->drive_kind == IDE_CD) {
3894be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->blk), &s->acct, io->len,
3905366d0c8SBenoît Canet                          BLOCK_ACCT_READ);
3914827ac1eSMark Cave-Ayland 
392b8842209SGerd Hoffmann         pmac_ide_atapi_transfer_cb(io, 0);
393b8842209SGerd Hoffmann         return;
394b8842209SGerd Hoffmann     }
395b8842209SGerd Hoffmann 
396a597e79cSChristoph Hellwig     switch (s->dma_cmd) {
397a597e79cSChristoph Hellwig     case IDE_DMA_READ:
3984be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->blk), &s->acct, io->len,
3995366d0c8SBenoît Canet                          BLOCK_ACCT_READ);
400a597e79cSChristoph Hellwig         break;
401a597e79cSChristoph Hellwig     case IDE_DMA_WRITE:
4024be74634SMarkus Armbruster         block_acct_start(blk_get_stats(s->blk), &s->acct, io->len,
4035366d0c8SBenoît Canet                          BLOCK_ACCT_WRITE);
404a597e79cSChristoph Hellwig         break;
405a597e79cSChristoph Hellwig     default:
406a597e79cSChristoph Hellwig         break;
407a597e79cSChristoph Hellwig     }
408a597e79cSChristoph Hellwig 
409b8842209SGerd Hoffmann     pmac_ide_transfer_cb(io, 0);
410b8842209SGerd Hoffmann }
411b8842209SGerd Hoffmann 
412b8842209SGerd Hoffmann static void pmac_ide_flush(DBDMA_io *io)
413b8842209SGerd Hoffmann {
414b8842209SGerd Hoffmann     MACIOIDEState *m = io->opaque;
415b8842209SGerd Hoffmann 
416922453bcSStefan Hajnoczi     if (m->aiocb) {
4174be74634SMarkus Armbruster         blk_drain_all();
418922453bcSStefan Hajnoczi     }
419b8842209SGerd Hoffmann }
420b8842209SGerd Hoffmann 
421b8842209SGerd Hoffmann /* PowerMac IDE memory IO */
422b8842209SGerd Hoffmann static void pmac_ide_writeb (void *opaque,
423a8170e5eSAvi Kivity                              hwaddr addr, uint32_t val)
424b8842209SGerd Hoffmann {
425b8842209SGerd Hoffmann     MACIOIDEState *d = opaque;
426b8842209SGerd Hoffmann 
427b8842209SGerd Hoffmann     addr = (addr & 0xFFF) >> 4;
428b8842209SGerd Hoffmann     switch (addr) {
429b8842209SGerd Hoffmann     case 1 ... 7:
430b8842209SGerd Hoffmann         ide_ioport_write(&d->bus, addr, val);
431b8842209SGerd Hoffmann         break;
432b8842209SGerd Hoffmann     case 8:
433b8842209SGerd Hoffmann     case 22:
434b8842209SGerd Hoffmann         ide_cmd_write(&d->bus, 0, val);
435b8842209SGerd Hoffmann         break;
436b8842209SGerd Hoffmann     default:
437b8842209SGerd Hoffmann         break;
438b8842209SGerd Hoffmann     }
439b8842209SGerd Hoffmann }
440b8842209SGerd Hoffmann 
441a8170e5eSAvi Kivity static uint32_t pmac_ide_readb (void *opaque,hwaddr addr)
442b8842209SGerd Hoffmann {
443b8842209SGerd Hoffmann     uint8_t retval;
444b8842209SGerd Hoffmann     MACIOIDEState *d = opaque;
445b8842209SGerd Hoffmann 
446b8842209SGerd Hoffmann     addr = (addr & 0xFFF) >> 4;
447b8842209SGerd Hoffmann     switch (addr) {
448b8842209SGerd Hoffmann     case 1 ... 7:
449b8842209SGerd Hoffmann         retval = ide_ioport_read(&d->bus, addr);
450b8842209SGerd Hoffmann         break;
451b8842209SGerd Hoffmann     case 8:
452b8842209SGerd Hoffmann     case 22:
453b8842209SGerd Hoffmann         retval = ide_status_read(&d->bus, 0);
454b8842209SGerd Hoffmann         break;
455b8842209SGerd Hoffmann     default:
456b8842209SGerd Hoffmann         retval = 0xFF;
457b8842209SGerd Hoffmann         break;
458b8842209SGerd Hoffmann     }
459b8842209SGerd Hoffmann     return retval;
460b8842209SGerd Hoffmann }
461b8842209SGerd Hoffmann 
462b8842209SGerd Hoffmann static void pmac_ide_writew (void *opaque,
463a8170e5eSAvi Kivity                              hwaddr addr, uint32_t val)
464b8842209SGerd Hoffmann {
465b8842209SGerd Hoffmann     MACIOIDEState *d = opaque;
466b8842209SGerd Hoffmann 
467b8842209SGerd Hoffmann     addr = (addr & 0xFFF) >> 4;
468b8842209SGerd Hoffmann     val = bswap16(val);
469b8842209SGerd Hoffmann     if (addr == 0) {
470b8842209SGerd Hoffmann         ide_data_writew(&d->bus, 0, val);
471b8842209SGerd Hoffmann     }
472b8842209SGerd Hoffmann }
473b8842209SGerd Hoffmann 
474a8170e5eSAvi Kivity static uint32_t pmac_ide_readw (void *opaque,hwaddr addr)
475b8842209SGerd Hoffmann {
476b8842209SGerd Hoffmann     uint16_t retval;
477b8842209SGerd Hoffmann     MACIOIDEState *d = opaque;
478b8842209SGerd Hoffmann 
479b8842209SGerd Hoffmann     addr = (addr & 0xFFF) >> 4;
480b8842209SGerd Hoffmann     if (addr == 0) {
481b8842209SGerd Hoffmann         retval = ide_data_readw(&d->bus, 0);
482b8842209SGerd Hoffmann     } else {
483b8842209SGerd Hoffmann         retval = 0xFFFF;
484b8842209SGerd Hoffmann     }
485b8842209SGerd Hoffmann     retval = bswap16(retval);
486b8842209SGerd Hoffmann     return retval;
487b8842209SGerd Hoffmann }
488b8842209SGerd Hoffmann 
489b8842209SGerd Hoffmann static void pmac_ide_writel (void *opaque,
490a8170e5eSAvi Kivity                              hwaddr addr, uint32_t val)
491b8842209SGerd Hoffmann {
492b8842209SGerd Hoffmann     MACIOIDEState *d = opaque;
493b8842209SGerd Hoffmann 
494b8842209SGerd Hoffmann     addr = (addr & 0xFFF) >> 4;
495b8842209SGerd Hoffmann     val = bswap32(val);
496b8842209SGerd Hoffmann     if (addr == 0) {
497b8842209SGerd Hoffmann         ide_data_writel(&d->bus, 0, val);
498b8842209SGerd Hoffmann     }
499b8842209SGerd Hoffmann }
500b8842209SGerd Hoffmann 
501a8170e5eSAvi Kivity static uint32_t pmac_ide_readl (void *opaque,hwaddr addr)
502b8842209SGerd Hoffmann {
503b8842209SGerd Hoffmann     uint32_t retval;
504b8842209SGerd Hoffmann     MACIOIDEState *d = opaque;
505b8842209SGerd Hoffmann 
506b8842209SGerd Hoffmann     addr = (addr & 0xFFF) >> 4;
507b8842209SGerd Hoffmann     if (addr == 0) {
508b8842209SGerd Hoffmann         retval = ide_data_readl(&d->bus, 0);
509b8842209SGerd Hoffmann     } else {
510b8842209SGerd Hoffmann         retval = 0xFFFFFFFF;
511b8842209SGerd Hoffmann     }
512b8842209SGerd Hoffmann     retval = bswap32(retval);
513b8842209SGerd Hoffmann     return retval;
514b8842209SGerd Hoffmann }
515b8842209SGerd Hoffmann 
516a348f108SStefan Weil static const MemoryRegionOps pmac_ide_ops = {
51723c5e4caSAvi Kivity     .old_mmio = {
51823c5e4caSAvi Kivity         .write = {
519b8842209SGerd Hoffmann             pmac_ide_writeb,
520b8842209SGerd Hoffmann             pmac_ide_writew,
521b8842209SGerd Hoffmann             pmac_ide_writel,
52223c5e4caSAvi Kivity         },
52323c5e4caSAvi Kivity         .read = {
524b8842209SGerd Hoffmann             pmac_ide_readb,
525b8842209SGerd Hoffmann             pmac_ide_readw,
526b8842209SGerd Hoffmann             pmac_ide_readl,
52723c5e4caSAvi Kivity         },
52823c5e4caSAvi Kivity     },
52923c5e4caSAvi Kivity     .endianness = DEVICE_NATIVE_ENDIAN,
530b8842209SGerd Hoffmann };
531b8842209SGerd Hoffmann 
53244bfa332SJuan Quintela static const VMStateDescription vmstate_pmac = {
53344bfa332SJuan Quintela     .name = "ide",
53444bfa332SJuan Quintela     .version_id = 3,
53544bfa332SJuan Quintela     .minimum_version_id = 0,
53644bfa332SJuan Quintela     .fields = (VMStateField[]) {
53744bfa332SJuan Quintela         VMSTATE_IDE_BUS(bus, MACIOIDEState),
53844bfa332SJuan Quintela         VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
53944bfa332SJuan Quintela         VMSTATE_END_OF_LIST()
540b8842209SGerd Hoffmann     }
54144bfa332SJuan Quintela };
542b8842209SGerd Hoffmann 
54307a7484eSAndreas Färber static void macio_ide_reset(DeviceState *dev)
544b8842209SGerd Hoffmann {
54507a7484eSAndreas Färber     MACIOIDEState *d = MACIO_IDE(dev);
546b8842209SGerd Hoffmann 
5474a643563SBlue Swirl     ide_bus_reset(&d->bus);
548b8842209SGerd Hoffmann }
549b8842209SGerd Hoffmann 
5504aa3510fSAlexander Graf static int ide_nop_int(IDEDMA *dma, int x)
5514aa3510fSAlexander Graf {
5524aa3510fSAlexander Graf     return 0;
5534aa3510fSAlexander Graf }
5544aa3510fSAlexander Graf 
5553251bdcfSJohn Snow static int32_t ide_nop_int32(IDEDMA *dma, int x)
5563251bdcfSJohn Snow {
5573251bdcfSJohn Snow     return 0;
5583251bdcfSJohn Snow }
5593251bdcfSJohn Snow 
5604aa3510fSAlexander Graf static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
561097310b5SMarkus Armbruster                             BlockCompletionFunc *cb)
5624aa3510fSAlexander Graf {
5634aa3510fSAlexander Graf     MACIOIDEState *m = container_of(dma, MACIOIDEState, dma);
5644827ac1eSMark Cave-Ayland     DBDMAState *dbdma = m->dbdma;
5654827ac1eSMark Cave-Ayland     DBDMA_io *io;
5664827ac1eSMark Cave-Ayland     int i;
5674827ac1eSMark Cave-Ayland 
5684827ac1eSMark Cave-Ayland     s->io_buffer_index = 0;
569*bd4214fcSMark Cave-Ayland     if (s->drive_kind == IDE_CD) {
5704827ac1eSMark Cave-Ayland         s->io_buffer_size = s->packet_transfer_size;
571*bd4214fcSMark Cave-Ayland     } else {
572*bd4214fcSMark Cave-Ayland         s->io_buffer_size = s->nsector * 0x200;
573*bd4214fcSMark Cave-Ayland     }
5744827ac1eSMark Cave-Ayland 
5754827ac1eSMark Cave-Ayland     MACIO_DPRINTF("\n\n------------ IDE transfer\n");
5764827ac1eSMark Cave-Ayland     MACIO_DPRINTF("buffer_size: %x   buffer_index: %x\n",
5774827ac1eSMark Cave-Ayland                   s->io_buffer_size, s->io_buffer_index);
5784827ac1eSMark Cave-Ayland     MACIO_DPRINTF("lba: %x    size: %x\n", s->lba, s->io_buffer_size);
5794827ac1eSMark Cave-Ayland     MACIO_DPRINTF("-------------------------\n");
5804827ac1eSMark Cave-Ayland 
5814827ac1eSMark Cave-Ayland     for (i = 0; i < DBDMA_CHANNELS; i++) {
5824827ac1eSMark Cave-Ayland         io = &dbdma->channels[i].io;
5834827ac1eSMark Cave-Ayland 
5844827ac1eSMark Cave-Ayland         if (io->opaque == m) {
5854827ac1eSMark Cave-Ayland             io->remainder_len = 0;
5864827ac1eSMark Cave-Ayland         }
5874827ac1eSMark Cave-Ayland     }
5884aa3510fSAlexander Graf 
5894aa3510fSAlexander Graf     MACIO_DPRINTF("\n");
590cae32357SAlexander Graf     m->dma_active = true;
5914aa3510fSAlexander Graf     DBDMA_kick(m->dbdma);
5924aa3510fSAlexander Graf }
5934aa3510fSAlexander Graf 
5944aa3510fSAlexander Graf static const IDEDMAOps dbdma_ops = {
5954aa3510fSAlexander Graf     .start_dma      = ide_dbdma_start,
5963251bdcfSJohn Snow     .prepare_buf    = ide_nop_int32,
5974aa3510fSAlexander Graf     .rw_buf         = ide_nop_int,
5984aa3510fSAlexander Graf };
5994aa3510fSAlexander Graf 
60007a7484eSAndreas Färber static void macio_ide_realizefn(DeviceState *dev, Error **errp)
601b8842209SGerd Hoffmann {
60207a7484eSAndreas Färber     MACIOIDEState *s = MACIO_IDE(dev);
603b8842209SGerd Hoffmann 
60407a7484eSAndreas Färber     ide_init2(&s->bus, s->irq);
6054aa3510fSAlexander Graf 
6064aa3510fSAlexander Graf     /* Register DMA callbacks */
6074aa3510fSAlexander Graf     s->dma.ops = &dbdma_ops;
6084aa3510fSAlexander Graf     s->bus.dma = &s->dma;
609b8842209SGerd Hoffmann }
61007a7484eSAndreas Färber 
61107a7484eSAndreas Färber static void macio_ide_initfn(Object *obj)
61207a7484eSAndreas Färber {
61307a7484eSAndreas Färber     SysBusDevice *d = SYS_BUS_DEVICE(obj);
61407a7484eSAndreas Färber     MACIOIDEState *s = MACIO_IDE(obj);
61507a7484eSAndreas Färber 
616c6baf942SAndreas Färber     ide_bus_new(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2);
6171437c94bSPaolo Bonzini     memory_region_init_io(&s->mem, obj, &pmac_ide_ops, s, "pmac-ide", 0x1000);
61807a7484eSAndreas Färber     sysbus_init_mmio(d, &s->mem);
61907a7484eSAndreas Färber     sysbus_init_irq(d, &s->irq);
62007a7484eSAndreas Färber     sysbus_init_irq(d, &s->dma_irq);
62107a7484eSAndreas Färber }
62207a7484eSAndreas Färber 
62307a7484eSAndreas Färber static void macio_ide_class_init(ObjectClass *oc, void *data)
62407a7484eSAndreas Färber {
62507a7484eSAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
62607a7484eSAndreas Färber 
62707a7484eSAndreas Färber     dc->realize = macio_ide_realizefn;
62807a7484eSAndreas Färber     dc->reset = macio_ide_reset;
62907a7484eSAndreas Färber     dc->vmsd = &vmstate_pmac;
63007a7484eSAndreas Färber }
63107a7484eSAndreas Färber 
63207a7484eSAndreas Färber static const TypeInfo macio_ide_type_info = {
63307a7484eSAndreas Färber     .name = TYPE_MACIO_IDE,
63407a7484eSAndreas Färber     .parent = TYPE_SYS_BUS_DEVICE,
63507a7484eSAndreas Färber     .instance_size = sizeof(MACIOIDEState),
63607a7484eSAndreas Färber     .instance_init = macio_ide_initfn,
63707a7484eSAndreas Färber     .class_init = macio_ide_class_init,
63807a7484eSAndreas Färber };
63907a7484eSAndreas Färber 
64007a7484eSAndreas Färber static void macio_ide_register_types(void)
64107a7484eSAndreas Färber {
64207a7484eSAndreas Färber     type_register_static(&macio_ide_type_info);
64307a7484eSAndreas Färber }
64407a7484eSAndreas Färber 
64514eefd0eSAlexander Graf /* hd_table must contain 2 block drivers */
64607a7484eSAndreas Färber void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table)
64707a7484eSAndreas Färber {
64807a7484eSAndreas Färber     int i;
64907a7484eSAndreas Färber 
65007a7484eSAndreas Färber     for (i = 0; i < 2; i++) {
65107a7484eSAndreas Färber         if (hd_table[i]) {
65207a7484eSAndreas Färber             ide_create_drive(&s->bus, i, hd_table[i]);
65307a7484eSAndreas Färber         }
65407a7484eSAndreas Färber     }
65507a7484eSAndreas Färber }
65607a7484eSAndreas Färber 
65707a7484eSAndreas Färber void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel)
65807a7484eSAndreas Färber {
6594aa3510fSAlexander Graf     s->dbdma = dbdma;
66007a7484eSAndreas Färber     DBDMA_register_channel(dbdma, channel, s->dma_irq,
66107a7484eSAndreas Färber                            pmac_ide_transfer, pmac_ide_flush, s);
66207a7484eSAndreas Färber }
66307a7484eSAndreas Färber 
66407a7484eSAndreas Färber type_init(macio_ide_register_types)
665