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 "block_int.h" 30 #include "dma.h" 31 32 #include <hw/ide/internal.h> 33 34 /***********************************************************/ 35 /* MacIO based PowerPC IDE */ 36 37 typedef struct MACIOIDEState { 38 MemoryRegion mem; 39 IDEBus bus; 40 BlockDriverAIOCB *aiocb; 41 } MACIOIDEState; 42 43 #define MACIO_PAGE_SIZE 4096 44 45 static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) 46 { 47 DBDMA_io *io = opaque; 48 MACIOIDEState *m = io->opaque; 49 IDEState *s = idebus_active_if(&m->bus); 50 51 if (ret < 0) { 52 m->aiocb = NULL; 53 qemu_sglist_destroy(&s->sg); 54 ide_atapi_io_error(s, ret); 55 io->dma_end(opaque); 56 return; 57 } 58 59 if (s->io_buffer_size > 0) { 60 m->aiocb = NULL; 61 qemu_sglist_destroy(&s->sg); 62 63 s->packet_transfer_size -= s->io_buffer_size; 64 65 s->io_buffer_index += s->io_buffer_size; 66 s->lba += s->io_buffer_index >> 11; 67 s->io_buffer_index &= 0x7ff; 68 } 69 70 if (s->packet_transfer_size <= 0) 71 ide_atapi_cmd_ok(s); 72 73 if (io->len == 0) { 74 io->dma_end(opaque); 75 return; 76 } 77 78 /* launch next transfer */ 79 80 s->io_buffer_size = io->len; 81 82 qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1); 83 qemu_sglist_add(&s->sg, io->addr, io->len); 84 io->addr += io->len; 85 io->len = 0; 86 87 m->aiocb = dma_bdrv_read(s->bs, &s->sg, 88 (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9), 89 pmac_ide_atapi_transfer_cb, io); 90 if (!m->aiocb) { 91 qemu_sglist_destroy(&s->sg); 92 /* Note: media not present is the most likely case */ 93 ide_atapi_cmd_error(s, SENSE_NOT_READY, 94 ASC_MEDIUM_NOT_PRESENT); 95 io->dma_end(opaque); 96 return; 97 } 98 } 99 100 static void pmac_ide_transfer_cb(void *opaque, int ret) 101 { 102 DBDMA_io *io = opaque; 103 MACIOIDEState *m = io->opaque; 104 IDEState *s = idebus_active_if(&m->bus); 105 int n; 106 int64_t sector_num; 107 108 if (ret < 0) { 109 m->aiocb = NULL; 110 qemu_sglist_destroy(&s->sg); 111 ide_dma_error(s); 112 io->dma_end(io); 113 return; 114 } 115 116 sector_num = ide_get_sector(s); 117 if (s->io_buffer_size > 0) { 118 m->aiocb = NULL; 119 qemu_sglist_destroy(&s->sg); 120 n = (s->io_buffer_size + 0x1ff) >> 9; 121 sector_num += n; 122 ide_set_sector(s, sector_num); 123 s->nsector -= n; 124 } 125 126 /* end of transfer ? */ 127 if (s->nsector == 0) { 128 s->status = READY_STAT | SEEK_STAT; 129 ide_set_irq(s->bus); 130 } 131 132 /* end of DMA ? */ 133 134 if (io->len == 0) { 135 io->dma_end(io); 136 return; 137 } 138 139 /* launch next transfer */ 140 141 s->io_buffer_index = 0; 142 s->io_buffer_size = io->len; 143 144 qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1); 145 qemu_sglist_add(&s->sg, io->addr, io->len); 146 io->addr += io->len; 147 io->len = 0; 148 149 switch (s->dma_cmd) { 150 case IDE_DMA_READ: 151 m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, 152 pmac_ide_transfer_cb, io); 153 break; 154 case IDE_DMA_WRITE: 155 m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, 156 pmac_ide_transfer_cb, io); 157 break; 158 case IDE_DMA_TRIM: 159 m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num, 160 ide_issue_trim, pmac_ide_transfer_cb, s, 1); 161 break; 162 } 163 164 if (!m->aiocb) 165 pmac_ide_transfer_cb(io, -1); 166 } 167 168 static void pmac_ide_transfer(DBDMA_io *io) 169 { 170 MACIOIDEState *m = io->opaque; 171 IDEState *s = idebus_active_if(&m->bus); 172 173 s->io_buffer_size = 0; 174 if (s->drive_kind == IDE_CD) { 175 pmac_ide_atapi_transfer_cb(io, 0); 176 return; 177 } 178 179 pmac_ide_transfer_cb(io, 0); 180 } 181 182 static void pmac_ide_flush(DBDMA_io *io) 183 { 184 MACIOIDEState *m = io->opaque; 185 186 if (m->aiocb) 187 qemu_aio_flush(); 188 } 189 190 /* PowerMac IDE memory IO */ 191 static void pmac_ide_writeb (void *opaque, 192 target_phys_addr_t addr, uint32_t val) 193 { 194 MACIOIDEState *d = opaque; 195 196 addr = (addr & 0xFFF) >> 4; 197 switch (addr) { 198 case 1 ... 7: 199 ide_ioport_write(&d->bus, addr, val); 200 break; 201 case 8: 202 case 22: 203 ide_cmd_write(&d->bus, 0, val); 204 break; 205 default: 206 break; 207 } 208 } 209 210 static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr) 211 { 212 uint8_t retval; 213 MACIOIDEState *d = opaque; 214 215 addr = (addr & 0xFFF) >> 4; 216 switch (addr) { 217 case 1 ... 7: 218 retval = ide_ioport_read(&d->bus, addr); 219 break; 220 case 8: 221 case 22: 222 retval = ide_status_read(&d->bus, 0); 223 break; 224 default: 225 retval = 0xFF; 226 break; 227 } 228 return retval; 229 } 230 231 static void pmac_ide_writew (void *opaque, 232 target_phys_addr_t addr, uint32_t val) 233 { 234 MACIOIDEState *d = opaque; 235 236 addr = (addr & 0xFFF) >> 4; 237 val = bswap16(val); 238 if (addr == 0) { 239 ide_data_writew(&d->bus, 0, val); 240 } 241 } 242 243 static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr) 244 { 245 uint16_t retval; 246 MACIOIDEState *d = opaque; 247 248 addr = (addr & 0xFFF) >> 4; 249 if (addr == 0) { 250 retval = ide_data_readw(&d->bus, 0); 251 } else { 252 retval = 0xFFFF; 253 } 254 retval = bswap16(retval); 255 return retval; 256 } 257 258 static void pmac_ide_writel (void *opaque, 259 target_phys_addr_t addr, uint32_t val) 260 { 261 MACIOIDEState *d = opaque; 262 263 addr = (addr & 0xFFF) >> 4; 264 val = bswap32(val); 265 if (addr == 0) { 266 ide_data_writel(&d->bus, 0, val); 267 } 268 } 269 270 static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr) 271 { 272 uint32_t retval; 273 MACIOIDEState *d = opaque; 274 275 addr = (addr & 0xFFF) >> 4; 276 if (addr == 0) { 277 retval = ide_data_readl(&d->bus, 0); 278 } else { 279 retval = 0xFFFFFFFF; 280 } 281 retval = bswap32(retval); 282 return retval; 283 } 284 285 static MemoryRegionOps pmac_ide_ops = { 286 .old_mmio = { 287 .write = { 288 pmac_ide_writeb, 289 pmac_ide_writew, 290 pmac_ide_writel, 291 }, 292 .read = { 293 pmac_ide_readb, 294 pmac_ide_readw, 295 pmac_ide_readl, 296 }, 297 }, 298 .endianness = DEVICE_NATIVE_ENDIAN, 299 }; 300 301 static const VMStateDescription vmstate_pmac = { 302 .name = "ide", 303 .version_id = 3, 304 .minimum_version_id = 0, 305 .minimum_version_id_old = 0, 306 .fields = (VMStateField []) { 307 VMSTATE_IDE_BUS(bus, MACIOIDEState), 308 VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState), 309 VMSTATE_END_OF_LIST() 310 } 311 }; 312 313 static void pmac_ide_reset(void *opaque) 314 { 315 MACIOIDEState *d = opaque; 316 317 ide_bus_reset(&d->bus); 318 } 319 320 /* hd_table must contain 4 block drivers */ 321 /* PowerMac uses memory mapped registers, not I/O. Return the memory 322 I/O index to access the ide. */ 323 MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq, 324 void *dbdma, int channel, qemu_irq dma_irq) 325 { 326 MACIOIDEState *d; 327 328 d = g_malloc0(sizeof(MACIOIDEState)); 329 ide_init2_with_non_qdev_drives(&d->bus, hd_table[0], hd_table[1], irq); 330 331 if (dbdma) 332 DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d); 333 334 memory_region_init_io(&d->mem, &pmac_ide_ops, d, "pmac-ide", 0x1000); 335 vmstate_register(NULL, 0, &vmstate_pmac, d); 336 qemu_register_reset(pmac_ide_reset, d); 337 338 return &d->mem; 339 } 340