qemu/hw/ide/macio.c
<<
>>
Prefs
   1/*
   2 * QEMU IDE Emulation: MacIO support.
   3 *
   4 * Copyright (c) 2003 Fabrice Bellard
   5 * Copyright (c) 2006 Openedhand Ltd.
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25#include <hw/hw.h>
  26#include <hw/ppc_mac.h>
  27#include <hw/mac_dbdma.h>
  28#include "block.h"
  29#include "dma.h"
  30
  31#include <hw/ide/internal.h>
  32
  33/***********************************************************/
  34/* MacIO based PowerPC IDE */
  35
  36typedef struct MACIOIDEState {
  37    MemoryRegion mem;
  38    IDEBus bus;
  39    BlockDriverAIOCB *aiocb;
  40} MACIOIDEState;
  41
  42#define MACIO_PAGE_SIZE 4096
  43
  44static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
  45{
  46    DBDMA_io *io = opaque;
  47    MACIOIDEState *m = io->opaque;
  48    IDEState *s = idebus_active_if(&m->bus);
  49
  50    if (ret < 0) {
  51        m->aiocb = NULL;
  52        qemu_sglist_destroy(&s->sg);
  53        ide_atapi_io_error(s, ret);
  54        goto done;
  55    }
  56
  57    if (s->io_buffer_size > 0) {
  58        m->aiocb = NULL;
  59        qemu_sglist_destroy(&s->sg);
  60
  61        s->packet_transfer_size -= s->io_buffer_size;
  62
  63        s->io_buffer_index += s->io_buffer_size;
  64        s->lba += s->io_buffer_index >> 11;
  65        s->io_buffer_index &= 0x7ff;
  66    }
  67
  68    if (s->packet_transfer_size <= 0)
  69        ide_atapi_cmd_ok(s);
  70
  71    if (io->len == 0) {
  72        goto done;
  73    }
  74
  75    /* launch next transfer */
  76
  77    s->io_buffer_size = io->len;
  78
  79    qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1);
  80    qemu_sglist_add(&s->sg, io->addr, io->len);
  81    io->addr += io->len;
  82    io->len = 0;
  83
  84    m->aiocb = dma_bdrv_read(s->bs, &s->sg,
  85                             (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9),
  86                             pmac_ide_atapi_transfer_cb, io);
  87    return;
  88
  89done:
  90    bdrv_acct_done(s->bs, &s->acct);
  91    io->dma_end(opaque);
  92    return;
  93}
  94
  95static void pmac_ide_transfer_cb(void *opaque, int ret)
  96{
  97    DBDMA_io *io = opaque;
  98    MACIOIDEState *m = io->opaque;
  99    IDEState *s = idebus_active_if(&m->bus);
 100    int n;
 101    int64_t sector_num;
 102
 103    if (ret < 0) {
 104        m->aiocb = NULL;
 105        qemu_sglist_destroy(&s->sg);
 106        ide_dma_error(s);
 107        goto done;
 108    }
 109
 110    sector_num = ide_get_sector(s);
 111    if (s->io_buffer_size > 0) {
 112        m->aiocb = NULL;
 113        qemu_sglist_destroy(&s->sg);
 114        n = (s->io_buffer_size + 0x1ff) >> 9;
 115        sector_num += n;
 116        ide_set_sector(s, sector_num);
 117        s->nsector -= n;
 118    }
 119
 120    /* end of transfer ? */
 121    if (s->nsector == 0) {
 122        s->status = READY_STAT | SEEK_STAT;
 123        ide_set_irq(s->bus);
 124    }
 125
 126    /* end of DMA ? */
 127    if (io->len == 0) {
 128        goto done;
 129    }
 130
 131    /* launch next transfer */
 132
 133    s->io_buffer_index = 0;
 134    s->io_buffer_size = io->len;
 135
 136    qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1);
 137    qemu_sglist_add(&s->sg, io->addr, io->len);
 138    io->addr += io->len;
 139    io->len = 0;
 140
 141    switch (s->dma_cmd) {
 142    case IDE_DMA_READ:
 143        m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
 144                                 pmac_ide_transfer_cb, io);
 145        break;
 146    case IDE_DMA_WRITE:
 147        m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
 148                                  pmac_ide_transfer_cb, io);
 149        break;
 150    case IDE_DMA_TRIM:
 151        m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
 152                               ide_issue_trim, pmac_ide_transfer_cb, s,
 153                               DMA_DIRECTION_TO_DEVICE);
 154        break;
 155    }
 156    return;
 157
 158done:
 159    if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
 160        bdrv_acct_done(s->bs, &s->acct);
 161    }
 162    io->dma_end(io);
 163}
 164
 165static void pmac_ide_transfer(DBDMA_io *io)
 166{
 167    MACIOIDEState *m = io->opaque;
 168    IDEState *s = idebus_active_if(&m->bus);
 169
 170    s->io_buffer_size = 0;
 171    if (s->drive_kind == IDE_CD) {
 172        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
 173        pmac_ide_atapi_transfer_cb(io, 0);
 174        return;
 175    }
 176
 177    switch (s->dma_cmd) {
 178    case IDE_DMA_READ:
 179        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
 180        break;
 181    case IDE_DMA_WRITE:
 182        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_WRITE);
 183        break;
 184    default:
 185        break;
 186    }
 187
 188    pmac_ide_transfer_cb(io, 0);
 189}
 190
 191static void pmac_ide_flush(DBDMA_io *io)
 192{
 193    MACIOIDEState *m = io->opaque;
 194
 195    if (m->aiocb) {
 196        bdrv_drain_all();
 197    }
 198}
 199
 200/* PowerMac IDE memory IO */
 201static void pmac_ide_writeb (void *opaque,
 202                             target_phys_addr_t addr, uint32_t val)
 203{
 204    MACIOIDEState *d = opaque;
 205
 206    addr = (addr & 0xFFF) >> 4;
 207    switch (addr) {
 208    case 1 ... 7:
 209        ide_ioport_write(&d->bus, addr, val);
 210        break;
 211    case 8:
 212    case 22:
 213        ide_cmd_write(&d->bus, 0, val);
 214        break;
 215    default:
 216        break;
 217    }
 218}
 219
 220static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr)
 221{
 222    uint8_t retval;
 223    MACIOIDEState *d = opaque;
 224
 225    addr = (addr & 0xFFF) >> 4;
 226    switch (addr) {
 227    case 1 ... 7:
 228        retval = ide_ioport_read(&d->bus, addr);
 229        break;
 230    case 8:
 231    case 22:
 232        retval = ide_status_read(&d->bus, 0);
 233        break;
 234    default:
 235        retval = 0xFF;
 236        break;
 237    }
 238    return retval;
 239}
 240
 241static void pmac_ide_writew (void *opaque,
 242                             target_phys_addr_t addr, uint32_t val)
 243{
 244    MACIOIDEState *d = opaque;
 245
 246    addr = (addr & 0xFFF) >> 4;
 247    val = bswap16(val);
 248    if (addr == 0) {
 249        ide_data_writew(&d->bus, 0, val);
 250    }
 251}
 252
 253static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr)
 254{
 255    uint16_t retval;
 256    MACIOIDEState *d = opaque;
 257
 258    addr = (addr & 0xFFF) >> 4;
 259    if (addr == 0) {
 260        retval = ide_data_readw(&d->bus, 0);
 261    } else {
 262        retval = 0xFFFF;
 263    }
 264    retval = bswap16(retval);
 265    return retval;
 266}
 267
 268static void pmac_ide_writel (void *opaque,
 269                             target_phys_addr_t addr, uint32_t val)
 270{
 271    MACIOIDEState *d = opaque;
 272
 273    addr = (addr & 0xFFF) >> 4;
 274    val = bswap32(val);
 275    if (addr == 0) {
 276        ide_data_writel(&d->bus, 0, val);
 277    }
 278}
 279
 280static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr)
 281{
 282    uint32_t retval;
 283    MACIOIDEState *d = opaque;
 284
 285    addr = (addr & 0xFFF) >> 4;
 286    if (addr == 0) {
 287        retval = ide_data_readl(&d->bus, 0);
 288    } else {
 289        retval = 0xFFFFFFFF;
 290    }
 291    retval = bswap32(retval);
 292    return retval;
 293}
 294
 295static const MemoryRegionOps pmac_ide_ops = {
 296    .old_mmio = {
 297        .write = {
 298            pmac_ide_writeb,
 299            pmac_ide_writew,
 300            pmac_ide_writel,
 301        },
 302        .read = {
 303            pmac_ide_readb,
 304            pmac_ide_readw,
 305            pmac_ide_readl,
 306        },
 307    },
 308    .endianness = DEVICE_NATIVE_ENDIAN,
 309};
 310
 311static const VMStateDescription vmstate_pmac = {
 312    .name = "ide",
 313    .version_id = 3,
 314    .minimum_version_id = 0,
 315    .minimum_version_id_old = 0,
 316    .fields      = (VMStateField []) {
 317        VMSTATE_IDE_BUS(bus, MACIOIDEState),
 318        VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
 319        VMSTATE_END_OF_LIST()
 320    }
 321};
 322
 323static void pmac_ide_reset(void *opaque)
 324{
 325    MACIOIDEState *d = opaque;
 326
 327    ide_bus_reset(&d->bus);
 328}
 329
 330/* hd_table must contain 4 block drivers */
 331/* PowerMac uses memory mapped registers, not I/O. Return the memory
 332   I/O index to access the ide. */
 333MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
 334                             void *dbdma, int channel, qemu_irq dma_irq)
 335{
 336    MACIOIDEState *d;
 337
 338    d = g_malloc0(sizeof(MACIOIDEState));
 339    ide_init2_with_non_qdev_drives(&d->bus, hd_table[0], hd_table[1], irq);
 340
 341    if (dbdma)
 342        DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d);
 343
 344    memory_region_init_io(&d->mem, &pmac_ide_ops, d, "pmac-ide", 0x1000);
 345    vmstate_register(NULL, 0, &vmstate_pmac, d);
 346    qemu_register_reset(pmac_ide_reset, d);
 347
 348    return &d->mem;
 349}
 350