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 "sysemu.h" 31 #include "dma.h" 32 33 #include <hw/ide/internal.h> 34 35 /***********************************************************/ 36 /* MacIO based PowerPC IDE */ 37 38 typedef struct MACIOIDEState { 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 if (s->is_read) 150 m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, 151 pmac_ide_transfer_cb, io); 152 else 153 m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, 154 pmac_ide_transfer_cb, io); 155 if (!m->aiocb) 156 pmac_ide_transfer_cb(io, -1); 157 } 158 159 static void pmac_ide_transfer(DBDMA_io *io) 160 { 161 MACIOIDEState *m = io->opaque; 162 IDEState *s = idebus_active_if(&m->bus); 163 164 s->io_buffer_size = 0; 165 if (s->drive_kind == IDE_CD) { 166 pmac_ide_atapi_transfer_cb(io, 0); 167 return; 168 } 169 170 pmac_ide_transfer_cb(io, 0); 171 } 172 173 static void pmac_ide_flush(DBDMA_io *io) 174 { 175 MACIOIDEState *m = io->opaque; 176 177 if (m->aiocb) 178 qemu_aio_flush(); 179 } 180 181 /* PowerMac IDE memory IO */ 182 static void pmac_ide_writeb (void *opaque, 183 target_phys_addr_t addr, uint32_t val) 184 { 185 MACIOIDEState *d = opaque; 186 187 addr = (addr & 0xFFF) >> 4; 188 switch (addr) { 189 case 1 ... 7: 190 ide_ioport_write(&d->bus, addr, val); 191 break; 192 case 8: 193 case 22: 194 ide_cmd_write(&d->bus, 0, val); 195 break; 196 default: 197 break; 198 } 199 } 200 201 static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr) 202 { 203 uint8_t retval; 204 MACIOIDEState *d = opaque; 205 206 addr = (addr & 0xFFF) >> 4; 207 switch (addr) { 208 case 1 ... 7: 209 retval = ide_ioport_read(&d->bus, addr); 210 break; 211 case 8: 212 case 22: 213 retval = ide_status_read(&d->bus, 0); 214 break; 215 default: 216 retval = 0xFF; 217 break; 218 } 219 return retval; 220 } 221 222 static void pmac_ide_writew (void *opaque, 223 target_phys_addr_t addr, uint32_t val) 224 { 225 MACIOIDEState *d = opaque; 226 227 addr = (addr & 0xFFF) >> 4; 228 val = bswap16(val); 229 if (addr == 0) { 230 ide_data_writew(&d->bus, 0, val); 231 } 232 } 233 234 static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr) 235 { 236 uint16_t retval; 237 MACIOIDEState *d = opaque; 238 239 addr = (addr & 0xFFF) >> 4; 240 if (addr == 0) { 241 retval = ide_data_readw(&d->bus, 0); 242 } else { 243 retval = 0xFFFF; 244 } 245 retval = bswap16(retval); 246 return retval; 247 } 248 249 static void pmac_ide_writel (void *opaque, 250 target_phys_addr_t addr, uint32_t val) 251 { 252 MACIOIDEState *d = opaque; 253 254 addr = (addr & 0xFFF) >> 4; 255 val = bswap32(val); 256 if (addr == 0) { 257 ide_data_writel(&d->bus, 0, val); 258 } 259 } 260 261 static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr) 262 { 263 uint32_t retval; 264 MACIOIDEState *d = opaque; 265 266 addr = (addr & 0xFFF) >> 4; 267 if (addr == 0) { 268 retval = ide_data_readl(&d->bus, 0); 269 } else { 270 retval = 0xFFFFFFFF; 271 } 272 retval = bswap32(retval); 273 return retval; 274 } 275 276 static CPUWriteMemoryFunc * const pmac_ide_write[] = { 277 pmac_ide_writeb, 278 pmac_ide_writew, 279 pmac_ide_writel, 280 }; 281 282 static CPUReadMemoryFunc * const pmac_ide_read[] = { 283 pmac_ide_readb, 284 pmac_ide_readw, 285 pmac_ide_readl, 286 }; 287 288 static const VMStateDescription vmstate_pmac = { 289 .name = "ide", 290 .version_id = 3, 291 .minimum_version_id = 0, 292 .minimum_version_id_old = 0, 293 .fields = (VMStateField []) { 294 VMSTATE_IDE_BUS(bus, MACIOIDEState), 295 VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState), 296 VMSTATE_END_OF_LIST() 297 } 298 }; 299 300 static void pmac_ide_reset(void *opaque) 301 { 302 MACIOIDEState *d = opaque; 303 304 ide_bus_reset(&d->bus); 305 } 306 307 /* hd_table must contain 4 block drivers */ 308 /* PowerMac uses memory mapped registers, not I/O. Return the memory 309 I/O index to access the ide. */ 310 int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq, 311 void *dbdma, int channel, qemu_irq dma_irq) 312 { 313 MACIOIDEState *d; 314 int pmac_ide_memory; 315 316 d = qemu_mallocz(sizeof(MACIOIDEState)); 317 ide_init2_with_non_qdev_drives(&d->bus, hd_table[0], hd_table[1], irq); 318 319 if (dbdma) 320 DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d); 321 322 pmac_ide_memory = cpu_register_io_memory(pmac_ide_read, 323 pmac_ide_write, d); 324 vmstate_register(NULL, 0, &vmstate_pmac, d); 325 qemu_register_reset(pmac_ide_reset, d); 326 327 return pmac_ide_memory; 328 } 329