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