macio.c 8.2 KB
Newer Older
G
Gerd Hoffmann 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * QEMU IDE Emulation: MacIO support.
 *
 * Copyright (c) 2003 Fabrice Bellard
 * Copyright (c) 2006 Openedhand Ltd.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
G
Gerd Hoffmann 已提交
25 26 27
#include <hw/hw.h>
#include <hw/ppc_mac.h>
#include <hw/mac_dbdma.h>
G
Gerd Hoffmann 已提交
28 29 30
#include "block.h"
#include "block_int.h"
#include "dma.h"
G
Gerd Hoffmann 已提交
31 32

#include <hw/ide/internal.h>
G
Gerd Hoffmann 已提交
33 34 35 36 37 38 39 40 41

/***********************************************************/
/* MacIO based PowerPC IDE */

typedef struct MACIOIDEState {
    IDEBus bus;
    BlockDriverAIOCB *aiocb;
} MACIOIDEState;

B
Blue Swirl 已提交
42 43
#define MACIO_PAGE_SIZE 4096

G
Gerd Hoffmann 已提交
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
{
    DBDMA_io *io = opaque;
    MACIOIDEState *m = io->opaque;
    IDEState *s = idebus_active_if(&m->bus);

    if (ret < 0) {
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);
        ide_atapi_io_error(s, ret);
        io->dma_end(opaque);
        return;
    }

    if (s->io_buffer_size > 0) {
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);

        s->packet_transfer_size -= s->io_buffer_size;

        s->io_buffer_index += s->io_buffer_size;
	s->lba += s->io_buffer_index >> 11;
        s->io_buffer_index &= 0x7ff;
    }

    if (s->packet_transfer_size <= 0)
        ide_atapi_cmd_ok(s);

    if (io->len == 0) {
        io->dma_end(opaque);
        return;
    }

    /* launch next transfer */

    s->io_buffer_size = io->len;

B
Blue Swirl 已提交
81
    qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1);
G
Gerd Hoffmann 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
    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_cb(void *opaque, int ret)
{
    DBDMA_io *io = opaque;
    MACIOIDEState *m = io->opaque;
    IDEState *s = idebus_active_if(&m->bus);
    int n;
    int64_t sector_num;

    if (ret < 0) {
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);
	ide_dma_error(s);
        io->dma_end(io);
        return;
    }

    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;
128
        ide_set_irq(s->bus);
G
Gerd Hoffmann 已提交
129 130 131 132 133 134 135 136 137 138 139 140 141 142
    }

    /* end of DMA ? */

    if (io->len == 0) {
        io->dma_end(io);
	return;
    }

    /* launch next transfer */

    s->io_buffer_index = 0;
    s->io_buffer_size = io->len;

B
Blue Swirl 已提交
143
    qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1);
G
Gerd Hoffmann 已提交
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
    qemu_sglist_add(&s->sg, io->addr, io->len);
    io->addr += io->len;
    io->len = 0;

    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);
}

static void pmac_ide_transfer(DBDMA_io *io)
{
    MACIOIDEState *m = io->opaque;
    IDEState *s = idebus_active_if(&m->bus);

    s->io_buffer_size = 0;
164
    if (s->drive_kind == IDE_CD) {
G
Gerd Hoffmann 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
        pmac_ide_atapi_transfer_cb(io, 0);
        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 */
static void pmac_ide_writeb (void *opaque,
A
Anthony Liguori 已提交
182
                             target_phys_addr_t addr, uint32_t val)
G
Gerd Hoffmann 已提交
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
{
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    switch (addr) {
    case 1 ... 7:
        ide_ioport_write(&d->bus, addr, val);
        break;
    case 8:
    case 22:
        ide_cmd_write(&d->bus, 0, val);
        break;
    default:
        break;
    }
}

A
Anthony Liguori 已提交
200
static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr)
G
Gerd Hoffmann 已提交
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
{
    uint8_t retval;
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    switch (addr) {
    case 1 ... 7:
        retval = ide_ioport_read(&d->bus, addr);
        break;
    case 8:
    case 22:
        retval = ide_status_read(&d->bus, 0);
        break;
    default:
        retval = 0xFF;
        break;
    }
    return retval;
}

static void pmac_ide_writew (void *opaque,
A
Anthony Liguori 已提交
222
                             target_phys_addr_t addr, uint32_t val)
G
Gerd Hoffmann 已提交
223 224 225 226 227 228 229 230 231 232
{
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    val = bswap16(val);
    if (addr == 0) {
        ide_data_writew(&d->bus, 0, val);
    }
}

A
Anthony Liguori 已提交
233
static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr)
G
Gerd Hoffmann 已提交
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
{
    uint16_t retval;
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    if (addr == 0) {
        retval = ide_data_readw(&d->bus, 0);
    } else {
        retval = 0xFFFF;
    }
    retval = bswap16(retval);
    return retval;
}

static void pmac_ide_writel (void *opaque,
A
Anthony Liguori 已提交
249
                             target_phys_addr_t addr, uint32_t val)
G
Gerd Hoffmann 已提交
250 251 252 253 254 255 256 257 258 259
{
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    val = bswap32(val);
    if (addr == 0) {
        ide_data_writel(&d->bus, 0, val);
    }
}

A
Anthony Liguori 已提交
260
static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr)
G
Gerd Hoffmann 已提交
261 262 263 264 265 266 267 268 269 270 271 272 273 274
{
    uint32_t retval;
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    if (addr == 0) {
        retval = ide_data_readl(&d->bus, 0);
    } else {
        retval = 0xFFFFFFFF;
    }
    retval = bswap32(retval);
    return retval;
}

275
static CPUWriteMemoryFunc * const pmac_ide_write[] = {
G
Gerd Hoffmann 已提交
276 277 278 279 280
    pmac_ide_writeb,
    pmac_ide_writew,
    pmac_ide_writel,
};

281
static CPUReadMemoryFunc * const pmac_ide_read[] = {
G
Gerd Hoffmann 已提交
282 283 284 285 286
    pmac_ide_readb,
    pmac_ide_readw,
    pmac_ide_readl,
};

J
Juan Quintela 已提交
287 288 289 290 291 292 293 294 295
static const VMStateDescription vmstate_pmac = {
    .name = "ide",
    .version_id = 3,
    .minimum_version_id = 0,
    .minimum_version_id_old = 0,
    .fields      = (VMStateField []) {
        VMSTATE_IDE_BUS(bus, MACIOIDEState),
        VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
        VMSTATE_END_OF_LIST()
G
Gerd Hoffmann 已提交
296
    }
J
Juan Quintela 已提交
297
};
G
Gerd Hoffmann 已提交
298 299 300 301 302

static void pmac_ide_reset(void *opaque)
{
    MACIOIDEState *d = opaque;

B
Blue Swirl 已提交
303
    ide_bus_reset(&d->bus);
G
Gerd Hoffmann 已提交
304 305 306 307 308
}

/* hd_table must contain 4 block drivers */
/* PowerMac uses memory mapped registers, not I/O. Return the memory
   I/O index to access the ide. */
309
int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
G
Gerd Hoffmann 已提交
310 311 312 313 314 315
		   void *dbdma, int channel, qemu_irq dma_irq)
{
    MACIOIDEState *d;
    int pmac_ide_memory;

    d = qemu_mallocz(sizeof(MACIOIDEState));
316
    ide_init2_with_non_qdev_drives(&d->bus, hd_table[0], hd_table[1], irq);
G
Gerd Hoffmann 已提交
317 318 319 320 321

    if (dbdma)
        DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d);

    pmac_ide_memory = cpu_register_io_memory(pmac_ide_read,
322 323
                                             pmac_ide_write, d,
                                             DEVICE_NATIVE_ENDIAN);
A
Alex Williamson 已提交
324
    vmstate_register(NULL, 0, &vmstate_pmac, d);
G
Gerd Hoffmann 已提交
325 326 327 328
    qemu_register_reset(pmac_ide_reset, d);

    return pmac_ide_memory;
}