xref: /openbmc/qemu/hw/ide/ahci.c (revision 465f1ab16169f5d71e52f11d4c650a50fd681030)
1f6ad2e32SAlexander Graf /*
2f6ad2e32SAlexander Graf  * QEMU AHCI Emulation
3f6ad2e32SAlexander Graf  *
4f6ad2e32SAlexander Graf  * Copyright (c) 2010 qiaochong@loongson.cn
5f6ad2e32SAlexander Graf  * Copyright (c) 2010 Roland Elek <elek.roland@gmail.com>
6f6ad2e32SAlexander Graf  * Copyright (c) 2010 Sebastian Herbszt <herbszt@gmx.de>
7f6ad2e32SAlexander Graf  * Copyright (c) 2010 Alexander Graf <agraf@suse.de>
8f6ad2e32SAlexander Graf  *
9f6ad2e32SAlexander Graf  * This library is free software; you can redistribute it and/or
10f6ad2e32SAlexander Graf  * modify it under the terms of the GNU Lesser General Public
11f6ad2e32SAlexander Graf  * License as published by the Free Software Foundation; either
12f6ad2e32SAlexander Graf  * version 2 of the License, or (at your option) any later version.
13f6ad2e32SAlexander Graf  *
14f6ad2e32SAlexander Graf  * This library is distributed in the hope that it will be useful,
15f6ad2e32SAlexander Graf  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16f6ad2e32SAlexander Graf  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17f6ad2e32SAlexander Graf  * Lesser General Public License for more details.
18f6ad2e32SAlexander Graf  *
19f6ad2e32SAlexander Graf  * You should have received a copy of the GNU Lesser General Public
20f6ad2e32SAlexander Graf  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21f6ad2e32SAlexander Graf  *
22f6ad2e32SAlexander Graf  */
23f6ad2e32SAlexander Graf 
24f6ad2e32SAlexander Graf #include <hw/hw.h>
25f6ad2e32SAlexander Graf #include <hw/msi.h>
26f6ad2e32SAlexander Graf #include <hw/pc.h>
27f6ad2e32SAlexander Graf #include <hw/pci.h>
28f6ad2e32SAlexander Graf 
29f6ad2e32SAlexander Graf #include "monitor.h"
30f6ad2e32SAlexander Graf #include "dma.h"
31f6ad2e32SAlexander Graf #include "cpu-common.h"
32f6ad2e32SAlexander Graf #include "internal.h"
33f6ad2e32SAlexander Graf #include <hw/ide/pci.h>
3403c7a6a8SSebastian Herbszt #include <hw/ide/ahci.h>
35f6ad2e32SAlexander Graf 
36f6ad2e32SAlexander Graf /* #define DEBUG_AHCI */
37f6ad2e32SAlexander Graf 
38f6ad2e32SAlexander Graf #ifdef DEBUG_AHCI
39f6ad2e32SAlexander Graf #define DPRINTF(port, fmt, ...) \
40f6ad2e32SAlexander Graf do { fprintf(stderr, "ahci: %s: [%d] ", __FUNCTION__, port); \
41f6ad2e32SAlexander Graf      fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
42f6ad2e32SAlexander Graf #else
43f6ad2e32SAlexander Graf #define DPRINTF(port, fmt, ...) do {} while(0)
44f6ad2e32SAlexander Graf #endif
45f6ad2e32SAlexander Graf 
46f6ad2e32SAlexander Graf static void check_cmd(AHCIState *s, int port);
47f6ad2e32SAlexander Graf static int handle_cmd(AHCIState *s,int port,int slot);
48f6ad2e32SAlexander Graf static void ahci_reset_port(AHCIState *s, int port);
49f6ad2e32SAlexander Graf static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
5087e62065SAlexander Graf static void ahci_init_d2h(AHCIDevice *ad);
51f6ad2e32SAlexander Graf 
52f6ad2e32SAlexander Graf static uint32_t  ahci_port_read(AHCIState *s, int port, int offset)
53f6ad2e32SAlexander Graf {
54f6ad2e32SAlexander Graf     uint32_t val;
55f6ad2e32SAlexander Graf     AHCIPortRegs *pr;
56f6ad2e32SAlexander Graf     pr = &s->dev[port].port_regs;
57f6ad2e32SAlexander Graf 
58f6ad2e32SAlexander Graf     switch (offset) {
59f6ad2e32SAlexander Graf     case PORT_LST_ADDR:
60f6ad2e32SAlexander Graf         val = pr->lst_addr;
61f6ad2e32SAlexander Graf         break;
62f6ad2e32SAlexander Graf     case PORT_LST_ADDR_HI:
63f6ad2e32SAlexander Graf         val = pr->lst_addr_hi;
64f6ad2e32SAlexander Graf         break;
65f6ad2e32SAlexander Graf     case PORT_FIS_ADDR:
66f6ad2e32SAlexander Graf         val = pr->fis_addr;
67f6ad2e32SAlexander Graf         break;
68f6ad2e32SAlexander Graf     case PORT_FIS_ADDR_HI:
69f6ad2e32SAlexander Graf         val = pr->fis_addr_hi;
70f6ad2e32SAlexander Graf         break;
71f6ad2e32SAlexander Graf     case PORT_IRQ_STAT:
72f6ad2e32SAlexander Graf         val = pr->irq_stat;
73f6ad2e32SAlexander Graf         break;
74f6ad2e32SAlexander Graf     case PORT_IRQ_MASK:
75f6ad2e32SAlexander Graf         val = pr->irq_mask;
76f6ad2e32SAlexander Graf         break;
77f6ad2e32SAlexander Graf     case PORT_CMD:
78f6ad2e32SAlexander Graf         val = pr->cmd;
79f6ad2e32SAlexander Graf         break;
80f6ad2e32SAlexander Graf     case PORT_TFDATA:
81f6ad2e32SAlexander Graf         val = ((uint16_t)s->dev[port].port.ifs[0].error << 8) |
82f6ad2e32SAlexander Graf               s->dev[port].port.ifs[0].status;
83f6ad2e32SAlexander Graf         break;
84f6ad2e32SAlexander Graf     case PORT_SIG:
85f6ad2e32SAlexander Graf         val = pr->sig;
86f6ad2e32SAlexander Graf         break;
87f6ad2e32SAlexander Graf     case PORT_SCR_STAT:
88f6ad2e32SAlexander Graf         if (s->dev[port].port.ifs[0].bs) {
89f6ad2e32SAlexander Graf             val = SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP |
90f6ad2e32SAlexander Graf                   SATA_SCR_SSTATUS_SPD_GEN1 | SATA_SCR_SSTATUS_IPM_ACTIVE;
91f6ad2e32SAlexander Graf         } else {
92f6ad2e32SAlexander Graf             val = SATA_SCR_SSTATUS_DET_NODEV;
93f6ad2e32SAlexander Graf         }
94f6ad2e32SAlexander Graf         break;
95f6ad2e32SAlexander Graf     case PORT_SCR_CTL:
96f6ad2e32SAlexander Graf         val = pr->scr_ctl;
97f6ad2e32SAlexander Graf         break;
98f6ad2e32SAlexander Graf     case PORT_SCR_ERR:
99f6ad2e32SAlexander Graf         val = pr->scr_err;
100f6ad2e32SAlexander Graf         break;
101f6ad2e32SAlexander Graf     case PORT_SCR_ACT:
102f6ad2e32SAlexander Graf         pr->scr_act &= ~s->dev[port].finished;
103f6ad2e32SAlexander Graf         s->dev[port].finished = 0;
104f6ad2e32SAlexander Graf         val = pr->scr_act;
105f6ad2e32SAlexander Graf         break;
106f6ad2e32SAlexander Graf     case PORT_CMD_ISSUE:
107f6ad2e32SAlexander Graf         val = pr->cmd_issue;
108f6ad2e32SAlexander Graf         break;
109f6ad2e32SAlexander Graf     case PORT_RESERVED:
110f6ad2e32SAlexander Graf     default:
111f6ad2e32SAlexander Graf         val = 0;
112f6ad2e32SAlexander Graf     }
113f6ad2e32SAlexander Graf     DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
114f6ad2e32SAlexander Graf     return val;
115f6ad2e32SAlexander Graf 
116f6ad2e32SAlexander Graf }
117f6ad2e32SAlexander Graf 
118f6ad2e32SAlexander Graf static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
119f6ad2e32SAlexander Graf {
120f6ad2e32SAlexander Graf     struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
121f6ad2e32SAlexander Graf 
122f6ad2e32SAlexander Graf     DPRINTF(0, "raise irq\n");
123f6ad2e32SAlexander Graf 
124f6ad2e32SAlexander Graf     if (msi_enabled(&d->card)) {
125f6ad2e32SAlexander Graf         msi_notify(&d->card, 0);
126f6ad2e32SAlexander Graf     } else {
127f6ad2e32SAlexander Graf         qemu_irq_raise(s->irq);
128f6ad2e32SAlexander Graf     }
129f6ad2e32SAlexander Graf }
130f6ad2e32SAlexander Graf 
131f6ad2e32SAlexander Graf static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
132f6ad2e32SAlexander Graf {
133f6ad2e32SAlexander Graf     struct AHCIPCIState *d = container_of(s, AHCIPCIState, ahci);
134f6ad2e32SAlexander Graf 
135f6ad2e32SAlexander Graf     DPRINTF(0, "lower irq\n");
136f6ad2e32SAlexander Graf 
137f6ad2e32SAlexander Graf     if (!msi_enabled(&d->card)) {
138f6ad2e32SAlexander Graf         qemu_irq_lower(s->irq);
139f6ad2e32SAlexander Graf     }
140f6ad2e32SAlexander Graf }
141f6ad2e32SAlexander Graf 
142f6ad2e32SAlexander Graf static void ahci_check_irq(AHCIState *s)
143f6ad2e32SAlexander Graf {
144f6ad2e32SAlexander Graf     int i;
145f6ad2e32SAlexander Graf 
146f6ad2e32SAlexander Graf     DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus);
147f6ad2e32SAlexander Graf 
1482c4b9d0eSAlexander Graf     for (i = 0; i < s->ports; i++) {
149f6ad2e32SAlexander Graf         AHCIPortRegs *pr = &s->dev[i].port_regs;
150f6ad2e32SAlexander Graf         if (pr->irq_stat & pr->irq_mask) {
151f6ad2e32SAlexander Graf             s->control_regs.irqstatus |= (1 << i);
152f6ad2e32SAlexander Graf         }
153f6ad2e32SAlexander Graf     }
154f6ad2e32SAlexander Graf 
155f6ad2e32SAlexander Graf     if (s->control_regs.irqstatus &&
156f6ad2e32SAlexander Graf         (s->control_regs.ghc & HOST_CTL_IRQ_EN)) {
157f6ad2e32SAlexander Graf             ahci_irq_raise(s, NULL);
158f6ad2e32SAlexander Graf     } else {
159f6ad2e32SAlexander Graf         ahci_irq_lower(s, NULL);
160f6ad2e32SAlexander Graf     }
161f6ad2e32SAlexander Graf }
162f6ad2e32SAlexander Graf 
163f6ad2e32SAlexander Graf static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d,
164f6ad2e32SAlexander Graf                              int irq_type)
165f6ad2e32SAlexander Graf {
166f6ad2e32SAlexander Graf     DPRINTF(d->port_no, "trigger irq %#x -> %x\n",
167f6ad2e32SAlexander Graf             irq_type, d->port_regs.irq_mask & irq_type);
168f6ad2e32SAlexander Graf 
169f6ad2e32SAlexander Graf     d->port_regs.irq_stat |= irq_type;
170f6ad2e32SAlexander Graf     ahci_check_irq(s);
171f6ad2e32SAlexander Graf }
172f6ad2e32SAlexander Graf 
173f6ad2e32SAlexander Graf static void map_page(uint8_t **ptr, uint64_t addr, uint32_t wanted)
174f6ad2e32SAlexander Graf {
175f6ad2e32SAlexander Graf     target_phys_addr_t len = wanted;
176f6ad2e32SAlexander Graf 
177f6ad2e32SAlexander Graf     if (*ptr) {
178fe6ceac8SStefan Hajnoczi         cpu_physical_memory_unmap(*ptr, len, 1, len);
179f6ad2e32SAlexander Graf     }
180f6ad2e32SAlexander Graf 
181f6ad2e32SAlexander Graf     *ptr = cpu_physical_memory_map(addr, &len, 1);
182f6ad2e32SAlexander Graf     if (len < wanted) {
183fe6ceac8SStefan Hajnoczi         cpu_physical_memory_unmap(*ptr, len, 1, len);
184f6ad2e32SAlexander Graf         *ptr = NULL;
185f6ad2e32SAlexander Graf     }
186f6ad2e32SAlexander Graf }
187f6ad2e32SAlexander Graf 
188f6ad2e32SAlexander Graf static void  ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
189f6ad2e32SAlexander Graf {
190f6ad2e32SAlexander Graf     AHCIPortRegs *pr = &s->dev[port].port_regs;
191f6ad2e32SAlexander Graf 
192f6ad2e32SAlexander Graf     DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
193f6ad2e32SAlexander Graf     switch (offset) {
194f6ad2e32SAlexander Graf         case PORT_LST_ADDR:
195f6ad2e32SAlexander Graf             pr->lst_addr = val;
196f6ad2e32SAlexander Graf             map_page(&s->dev[port].lst,
197f6ad2e32SAlexander Graf                      ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
198f6ad2e32SAlexander Graf             s->dev[port].cur_cmd = NULL;
199f6ad2e32SAlexander Graf             break;
200f6ad2e32SAlexander Graf         case PORT_LST_ADDR_HI:
201f6ad2e32SAlexander Graf             pr->lst_addr_hi = val;
202f6ad2e32SAlexander Graf             map_page(&s->dev[port].lst,
203f6ad2e32SAlexander Graf                      ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
204f6ad2e32SAlexander Graf             s->dev[port].cur_cmd = NULL;
205f6ad2e32SAlexander Graf             break;
206f6ad2e32SAlexander Graf         case PORT_FIS_ADDR:
207f6ad2e32SAlexander Graf             pr->fis_addr = val;
208f6ad2e32SAlexander Graf             map_page(&s->dev[port].res_fis,
209f6ad2e32SAlexander Graf                      ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
210f6ad2e32SAlexander Graf             break;
211f6ad2e32SAlexander Graf         case PORT_FIS_ADDR_HI:
212f6ad2e32SAlexander Graf             pr->fis_addr_hi = val;
213f6ad2e32SAlexander Graf             map_page(&s->dev[port].res_fis,
214f6ad2e32SAlexander Graf                      ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
215f6ad2e32SAlexander Graf             break;
216f6ad2e32SAlexander Graf         case PORT_IRQ_STAT:
217f6ad2e32SAlexander Graf             pr->irq_stat &= ~val;
218f6ad2e32SAlexander Graf             break;
219f6ad2e32SAlexander Graf         case PORT_IRQ_MASK:
220f6ad2e32SAlexander Graf             pr->irq_mask = val & 0xfdc000ff;
221f6ad2e32SAlexander Graf             ahci_check_irq(s);
222f6ad2e32SAlexander Graf             break;
223f6ad2e32SAlexander Graf         case PORT_CMD:
224f6ad2e32SAlexander Graf             pr->cmd = val & ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON);
225f6ad2e32SAlexander Graf 
226f6ad2e32SAlexander Graf             if (pr->cmd & PORT_CMD_START) {
227f6ad2e32SAlexander Graf                 pr->cmd |= PORT_CMD_LIST_ON;
228f6ad2e32SAlexander Graf             }
229f6ad2e32SAlexander Graf 
230f6ad2e32SAlexander Graf             if (pr->cmd & PORT_CMD_FIS_RX) {
231f6ad2e32SAlexander Graf                 pr->cmd |= PORT_CMD_FIS_ON;
232f6ad2e32SAlexander Graf             }
233f6ad2e32SAlexander Graf 
23487e62065SAlexander Graf             /* XXX usually the FIS would be pending on the bus here and
23587e62065SAlexander Graf                    issuing deferred until the OS enables FIS receival.
23687e62065SAlexander Graf                    Instead, we only submit it once - which works in most
23787e62065SAlexander Graf                    cases, but is a hack. */
23887e62065SAlexander Graf             if ((pr->cmd & PORT_CMD_FIS_ON) &&
23987e62065SAlexander Graf                 !s->dev[port].init_d2h_sent) {
24087e62065SAlexander Graf                 ahci_init_d2h(&s->dev[port]);
24187e62065SAlexander Graf                 s->dev[port].init_d2h_sent = 1;
24287e62065SAlexander Graf             }
24387e62065SAlexander Graf 
244f6ad2e32SAlexander Graf             check_cmd(s, port);
245f6ad2e32SAlexander Graf             break;
246f6ad2e32SAlexander Graf         case PORT_TFDATA:
247f6ad2e32SAlexander Graf             s->dev[port].port.ifs[0].error = (val >> 8) & 0xff;
248f6ad2e32SAlexander Graf             s->dev[port].port.ifs[0].status = val & 0xff;
249f6ad2e32SAlexander Graf             break;
250f6ad2e32SAlexander Graf         case PORT_SIG:
251f6ad2e32SAlexander Graf             pr->sig = val;
252f6ad2e32SAlexander Graf             break;
253f6ad2e32SAlexander Graf         case PORT_SCR_STAT:
254f6ad2e32SAlexander Graf             pr->scr_stat = val;
255f6ad2e32SAlexander Graf             break;
256f6ad2e32SAlexander Graf         case PORT_SCR_CTL:
257f6ad2e32SAlexander Graf             if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) &&
258f6ad2e32SAlexander Graf                 ((val & AHCI_SCR_SCTL_DET) == 0)) {
259f6ad2e32SAlexander Graf                 ahci_reset_port(s, port);
260f6ad2e32SAlexander Graf             }
261f6ad2e32SAlexander Graf             pr->scr_ctl = val;
262f6ad2e32SAlexander Graf             break;
263f6ad2e32SAlexander Graf         case PORT_SCR_ERR:
264f6ad2e32SAlexander Graf             pr->scr_err &= ~val;
265f6ad2e32SAlexander Graf             break;
266f6ad2e32SAlexander Graf         case PORT_SCR_ACT:
267f6ad2e32SAlexander Graf             /* RW1 */
268f6ad2e32SAlexander Graf             pr->scr_act |= val;
269f6ad2e32SAlexander Graf             break;
270f6ad2e32SAlexander Graf         case PORT_CMD_ISSUE:
271f6ad2e32SAlexander Graf             pr->cmd_issue |= val;
272f6ad2e32SAlexander Graf             check_cmd(s, port);
273f6ad2e32SAlexander Graf             break;
274f6ad2e32SAlexander Graf         default:
275f6ad2e32SAlexander Graf             break;
276f6ad2e32SAlexander Graf     }
277f6ad2e32SAlexander Graf }
278f6ad2e32SAlexander Graf 
27967e576c2SAvi Kivity static uint64_t ahci_mem_read(void *opaque, target_phys_addr_t addr,
28067e576c2SAvi Kivity                               unsigned size)
281f6ad2e32SAlexander Graf {
28267e576c2SAvi Kivity     AHCIState *s = opaque;
283f6ad2e32SAlexander Graf     uint32_t val = 0;
284f6ad2e32SAlexander Graf 
285f6ad2e32SAlexander Graf     if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
286f6ad2e32SAlexander Graf         switch (addr) {
287f6ad2e32SAlexander Graf         case HOST_CAP:
288f6ad2e32SAlexander Graf             val = s->control_regs.cap;
289f6ad2e32SAlexander Graf             break;
290f6ad2e32SAlexander Graf         case HOST_CTL:
291f6ad2e32SAlexander Graf             val = s->control_regs.ghc;
292f6ad2e32SAlexander Graf             break;
293f6ad2e32SAlexander Graf         case HOST_IRQ_STAT:
294f6ad2e32SAlexander Graf             val = s->control_regs.irqstatus;
295f6ad2e32SAlexander Graf             break;
296f6ad2e32SAlexander Graf         case HOST_PORTS_IMPL:
297f6ad2e32SAlexander Graf             val = s->control_regs.impl;
298f6ad2e32SAlexander Graf             break;
299f6ad2e32SAlexander Graf         case HOST_VERSION:
300f6ad2e32SAlexander Graf             val = s->control_regs.version;
301f6ad2e32SAlexander Graf             break;
302f6ad2e32SAlexander Graf         }
303f6ad2e32SAlexander Graf 
304f6ad2e32SAlexander Graf         DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
305f6ad2e32SAlexander Graf     } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
3062c4b9d0eSAlexander Graf                (addr < (AHCI_PORT_REGS_START_ADDR +
3072c4b9d0eSAlexander Graf                 (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
308f6ad2e32SAlexander Graf         val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
309f6ad2e32SAlexander Graf                              addr & AHCI_PORT_ADDR_OFFSET_MASK);
310f6ad2e32SAlexander Graf     }
311f6ad2e32SAlexander Graf 
312f6ad2e32SAlexander Graf     return val;
313f6ad2e32SAlexander Graf }
314f6ad2e32SAlexander Graf 
315f6ad2e32SAlexander Graf 
316f6ad2e32SAlexander Graf 
31767e576c2SAvi Kivity static void ahci_mem_write(void *opaque, target_phys_addr_t addr,
31867e576c2SAvi Kivity                            uint64_t val, unsigned size)
319f6ad2e32SAlexander Graf {
32067e576c2SAvi Kivity     AHCIState *s = opaque;
321f6ad2e32SAlexander Graf 
322f6ad2e32SAlexander Graf     /* Only aligned reads are allowed on AHCI */
323f6ad2e32SAlexander Graf     if (addr & 3) {
324f6ad2e32SAlexander Graf         fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
325f6ad2e32SAlexander Graf                 TARGET_FMT_plx "\n", addr);
326f6ad2e32SAlexander Graf         return;
327f6ad2e32SAlexander Graf     }
328f6ad2e32SAlexander Graf 
329f6ad2e32SAlexander Graf     if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
330f6ad2e32SAlexander Graf         DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
331f6ad2e32SAlexander Graf 
332f6ad2e32SAlexander Graf         switch (addr) {
333f6ad2e32SAlexander Graf             case HOST_CAP: /* R/WO, RO */
334f6ad2e32SAlexander Graf                 /* FIXME handle R/WO */
335f6ad2e32SAlexander Graf                 break;
336f6ad2e32SAlexander Graf             case HOST_CTL: /* R/W */
337f6ad2e32SAlexander Graf                 if (val & HOST_CTL_RESET) {
338f6ad2e32SAlexander Graf                     DPRINTF(-1, "HBA Reset\n");
339760c3e44SAlexander Graf                     ahci_reset(container_of(s, AHCIPCIState, ahci));
340f6ad2e32SAlexander Graf                 } else {
341f6ad2e32SAlexander Graf                     s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
342f6ad2e32SAlexander Graf                     ahci_check_irq(s);
343f6ad2e32SAlexander Graf                 }
344f6ad2e32SAlexander Graf                 break;
345f6ad2e32SAlexander Graf             case HOST_IRQ_STAT: /* R/WC, RO */
346f6ad2e32SAlexander Graf                 s->control_regs.irqstatus &= ~val;
347f6ad2e32SAlexander Graf                 ahci_check_irq(s);
348f6ad2e32SAlexander Graf                 break;
349f6ad2e32SAlexander Graf             case HOST_PORTS_IMPL: /* R/WO, RO */
350f6ad2e32SAlexander Graf                 /* FIXME handle R/WO */
351f6ad2e32SAlexander Graf                 break;
352f6ad2e32SAlexander Graf             case HOST_VERSION: /* RO */
353f6ad2e32SAlexander Graf                 /* FIXME report write? */
354f6ad2e32SAlexander Graf                 break;
355f6ad2e32SAlexander Graf             default:
356f6ad2e32SAlexander Graf                 DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr);
357f6ad2e32SAlexander Graf         }
358f6ad2e32SAlexander Graf     } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
3592c4b9d0eSAlexander Graf                (addr < (AHCI_PORT_REGS_START_ADDR +
3602c4b9d0eSAlexander Graf                 (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
361f6ad2e32SAlexander Graf         ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
362f6ad2e32SAlexander Graf                         addr & AHCI_PORT_ADDR_OFFSET_MASK, val);
363f6ad2e32SAlexander Graf     }
364f6ad2e32SAlexander Graf 
365f6ad2e32SAlexander Graf }
366f6ad2e32SAlexander Graf 
36767e576c2SAvi Kivity static MemoryRegionOps ahci_mem_ops = {
36867e576c2SAvi Kivity     .read = ahci_mem_read,
36967e576c2SAvi Kivity     .write = ahci_mem_write,
37067e576c2SAvi Kivity     .endianness = DEVICE_LITTLE_ENDIAN,
371f6ad2e32SAlexander Graf };
372f6ad2e32SAlexander Graf 
373*465f1ab1SDaniel Verkamp static uint64_t ahci_idp_read(void *opaque, target_phys_addr_t addr,
374*465f1ab1SDaniel Verkamp                               unsigned size)
375*465f1ab1SDaniel Verkamp {
376*465f1ab1SDaniel Verkamp     AHCIState *s = opaque;
377*465f1ab1SDaniel Verkamp 
378*465f1ab1SDaniel Verkamp     if (addr == s->idp_offset) {
379*465f1ab1SDaniel Verkamp         /* index register */
380*465f1ab1SDaniel Verkamp         return s->idp_index;
381*465f1ab1SDaniel Verkamp     } else if (addr == s->idp_offset + 4) {
382*465f1ab1SDaniel Verkamp         /* data register - do memory read at location selected by index */
383*465f1ab1SDaniel Verkamp         return ahci_mem_read(opaque, s->idp_index, size);
384*465f1ab1SDaniel Verkamp     } else {
385*465f1ab1SDaniel Verkamp         return 0;
386*465f1ab1SDaniel Verkamp     }
387*465f1ab1SDaniel Verkamp }
388*465f1ab1SDaniel Verkamp 
389*465f1ab1SDaniel Verkamp static void ahci_idp_write(void *opaque, target_phys_addr_t addr,
390*465f1ab1SDaniel Verkamp                            uint64_t val, unsigned size)
391*465f1ab1SDaniel Verkamp {
392*465f1ab1SDaniel Verkamp     AHCIState *s = opaque;
393*465f1ab1SDaniel Verkamp 
394*465f1ab1SDaniel Verkamp     if (addr == s->idp_offset) {
395*465f1ab1SDaniel Verkamp         /* index register - mask off reserved bits */
396*465f1ab1SDaniel Verkamp         s->idp_index = (uint32_t)val & ((AHCI_MEM_BAR_SIZE - 1) & ~3);
397*465f1ab1SDaniel Verkamp     } else if (addr == s->idp_offset + 4) {
398*465f1ab1SDaniel Verkamp         /* data register - do memory write at location selected by index */
399*465f1ab1SDaniel Verkamp         ahci_mem_write(opaque, s->idp_index, val, size);
400*465f1ab1SDaniel Verkamp     }
401*465f1ab1SDaniel Verkamp }
402*465f1ab1SDaniel Verkamp 
403*465f1ab1SDaniel Verkamp static MemoryRegionOps ahci_idp_ops = {
404*465f1ab1SDaniel Verkamp     .read = ahci_idp_read,
405*465f1ab1SDaniel Verkamp     .write = ahci_idp_write,
406*465f1ab1SDaniel Verkamp     .endianness = DEVICE_LITTLE_ENDIAN,
407*465f1ab1SDaniel Verkamp };
408*465f1ab1SDaniel Verkamp 
409*465f1ab1SDaniel Verkamp 
410f6ad2e32SAlexander Graf static void ahci_reg_init(AHCIState *s)
411f6ad2e32SAlexander Graf {
412f6ad2e32SAlexander Graf     int i;
413f6ad2e32SAlexander Graf 
4142c4b9d0eSAlexander Graf     s->control_regs.cap = (s->ports - 1) |
415f6ad2e32SAlexander Graf                           (AHCI_NUM_COMMAND_SLOTS << 8) |
416f6ad2e32SAlexander Graf                           (AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) |
417f6ad2e32SAlexander Graf                           HOST_CAP_NCQ | HOST_CAP_AHCI;
418f6ad2e32SAlexander Graf 
4192c4b9d0eSAlexander Graf     s->control_regs.impl = (1 << s->ports) - 1;
420f6ad2e32SAlexander Graf 
421f6ad2e32SAlexander Graf     s->control_regs.version = AHCI_VERSION_1_0;
422f6ad2e32SAlexander Graf 
4232c4b9d0eSAlexander Graf     for (i = 0; i < s->ports; i++) {
424f6ad2e32SAlexander Graf         s->dev[i].port_state = STATE_RUN;
425f6ad2e32SAlexander Graf     }
426f6ad2e32SAlexander Graf }
427f6ad2e32SAlexander Graf 
428f6ad2e32SAlexander Graf static uint32_t read_from_sglist(uint8_t *buffer, uint32_t len,
429f6ad2e32SAlexander Graf                                  QEMUSGList *sglist)
430f6ad2e32SAlexander Graf {
431f6ad2e32SAlexander Graf     uint32_t i = 0;
432f6ad2e32SAlexander Graf     uint32_t total = 0, once;
433f6ad2e32SAlexander Graf     ScatterGatherEntry *cur_prd;
434f6ad2e32SAlexander Graf     uint32_t sgcount;
435f6ad2e32SAlexander Graf 
436f6ad2e32SAlexander Graf     cur_prd = sglist->sg;
437f6ad2e32SAlexander Graf     sgcount = sglist->nsg;
438f6ad2e32SAlexander Graf     for (i = 0; len && sgcount; i++) {
439f6ad2e32SAlexander Graf         once = MIN(cur_prd->len, len);
440f6ad2e32SAlexander Graf         cpu_physical_memory_read(cur_prd->base, buffer, once);
441f6ad2e32SAlexander Graf         cur_prd++;
442f6ad2e32SAlexander Graf         sgcount--;
443f6ad2e32SAlexander Graf         len -= once;
444f6ad2e32SAlexander Graf         buffer += once;
445f6ad2e32SAlexander Graf         total += once;
446f6ad2e32SAlexander Graf     }
447f6ad2e32SAlexander Graf 
448f6ad2e32SAlexander Graf     return total;
449f6ad2e32SAlexander Graf }
450f6ad2e32SAlexander Graf 
451f6ad2e32SAlexander Graf static uint32_t write_to_sglist(uint8_t *buffer, uint32_t len,
452f6ad2e32SAlexander Graf                                 QEMUSGList *sglist)
453f6ad2e32SAlexander Graf {
454f6ad2e32SAlexander Graf     uint32_t i = 0;
455f6ad2e32SAlexander Graf     uint32_t total = 0, once;
456f6ad2e32SAlexander Graf     ScatterGatherEntry *cur_prd;
457f6ad2e32SAlexander Graf     uint32_t sgcount;
458f6ad2e32SAlexander Graf 
459f6ad2e32SAlexander Graf     DPRINTF(-1, "total: 0x%x bytes\n", len);
460f6ad2e32SAlexander Graf 
461f6ad2e32SAlexander Graf     cur_prd = sglist->sg;
462f6ad2e32SAlexander Graf     sgcount = sglist->nsg;
463f6ad2e32SAlexander Graf     for (i = 0; len && sgcount; i++) {
464f6ad2e32SAlexander Graf         once = MIN(cur_prd->len, len);
465f6ad2e32SAlexander Graf         DPRINTF(-1, "write 0x%x bytes to 0x%lx\n", once, (long)cur_prd->base);
466f6ad2e32SAlexander Graf         cpu_physical_memory_write(cur_prd->base, buffer, once);
467f6ad2e32SAlexander Graf         cur_prd++;
468f6ad2e32SAlexander Graf         sgcount--;
469f6ad2e32SAlexander Graf         len -= once;
470f6ad2e32SAlexander Graf         buffer += once;
471f6ad2e32SAlexander Graf         total += once;
472f6ad2e32SAlexander Graf     }
473f6ad2e32SAlexander Graf 
474f6ad2e32SAlexander Graf     return total;
475f6ad2e32SAlexander Graf }
476f6ad2e32SAlexander Graf 
477f6ad2e32SAlexander Graf static void check_cmd(AHCIState *s, int port)
478f6ad2e32SAlexander Graf {
479f6ad2e32SAlexander Graf     AHCIPortRegs *pr = &s->dev[port].port_regs;
480f6ad2e32SAlexander Graf     int slot;
481f6ad2e32SAlexander Graf 
482f6ad2e32SAlexander Graf     if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
483f6ad2e32SAlexander Graf         for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
484f6ad2e32SAlexander Graf             if ((pr->cmd_issue & (1 << slot)) &&
485f6ad2e32SAlexander Graf                 !handle_cmd(s, port, slot)) {
486f6ad2e32SAlexander Graf                 pr->cmd_issue &= ~(1 << slot);
487f6ad2e32SAlexander Graf             }
488f6ad2e32SAlexander Graf         }
489f6ad2e32SAlexander Graf     }
490f6ad2e32SAlexander Graf }
491f6ad2e32SAlexander Graf 
492f6ad2e32SAlexander Graf static void ahci_check_cmd_bh(void *opaque)
493f6ad2e32SAlexander Graf {
494f6ad2e32SAlexander Graf     AHCIDevice *ad = opaque;
495f6ad2e32SAlexander Graf 
496f6ad2e32SAlexander Graf     qemu_bh_delete(ad->check_bh);
497f6ad2e32SAlexander Graf     ad->check_bh = NULL;
498f6ad2e32SAlexander Graf 
499f6ad2e32SAlexander Graf     if ((ad->busy_slot != -1) &&
500f6ad2e32SAlexander Graf         !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
501f6ad2e32SAlexander Graf         /* no longer busy */
502f6ad2e32SAlexander Graf         ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
503f6ad2e32SAlexander Graf         ad->busy_slot = -1;
504f6ad2e32SAlexander Graf     }
505f6ad2e32SAlexander Graf 
506f6ad2e32SAlexander Graf     check_cmd(ad->hba, ad->port_no);
507f6ad2e32SAlexander Graf }
508f6ad2e32SAlexander Graf 
50987e62065SAlexander Graf static void ahci_init_d2h(AHCIDevice *ad)
51087e62065SAlexander Graf {
51187e62065SAlexander Graf     uint8_t init_fis[0x20];
51287e62065SAlexander Graf     IDEState *ide_state = &ad->port.ifs[0];
51387e62065SAlexander Graf 
51487e62065SAlexander Graf     memset(init_fis, 0, sizeof(init_fis));
51587e62065SAlexander Graf 
51687e62065SAlexander Graf     init_fis[4] = 1;
51787e62065SAlexander Graf     init_fis[12] = 1;
51887e62065SAlexander Graf 
51987e62065SAlexander Graf     if (ide_state->drive_kind == IDE_CD) {
52087e62065SAlexander Graf         init_fis[5] = ide_state->lcyl;
52187e62065SAlexander Graf         init_fis[6] = ide_state->hcyl;
52287e62065SAlexander Graf     }
52387e62065SAlexander Graf 
52487e62065SAlexander Graf     ahci_write_fis_d2h(ad, init_fis);
52587e62065SAlexander Graf }
52687e62065SAlexander Graf 
527f6ad2e32SAlexander Graf static void ahci_reset_port(AHCIState *s, int port)
528f6ad2e32SAlexander Graf {
529f6ad2e32SAlexander Graf     AHCIDevice *d = &s->dev[port];
530f6ad2e32SAlexander Graf     AHCIPortRegs *pr = &d->port_regs;
531f6ad2e32SAlexander Graf     IDEState *ide_state = &d->port.ifs[0];
532f6ad2e32SAlexander Graf     int i;
533f6ad2e32SAlexander Graf 
534f6ad2e32SAlexander Graf     DPRINTF(port, "reset port\n");
535f6ad2e32SAlexander Graf 
536f6ad2e32SAlexander Graf     ide_bus_reset(&d->port);
537f6ad2e32SAlexander Graf     ide_state->ncq_queues = AHCI_MAX_CMDS;
538f6ad2e32SAlexander Graf 
539f6ad2e32SAlexander Graf     pr->scr_stat = 0;
540f6ad2e32SAlexander Graf     pr->scr_err = 0;
541f6ad2e32SAlexander Graf     pr->scr_act = 0;
542f6ad2e32SAlexander Graf     d->busy_slot = -1;
54387e62065SAlexander Graf     d->init_d2h_sent = 0;
544f6ad2e32SAlexander Graf 
545f6ad2e32SAlexander Graf     ide_state = &s->dev[port].port.ifs[0];
546f6ad2e32SAlexander Graf     if (!ide_state->bs) {
547f6ad2e32SAlexander Graf         return;
548f6ad2e32SAlexander Graf     }
549f6ad2e32SAlexander Graf 
550f6ad2e32SAlexander Graf     /* reset ncq queue */
551f6ad2e32SAlexander Graf     for (i = 0; i < AHCI_MAX_CMDS; i++) {
552f6ad2e32SAlexander Graf         NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i];
553f6ad2e32SAlexander Graf         if (!ncq_tfs->used) {
554f6ad2e32SAlexander Graf             continue;
555f6ad2e32SAlexander Graf         }
556f6ad2e32SAlexander Graf 
557f6ad2e32SAlexander Graf         if (ncq_tfs->aiocb) {
558f6ad2e32SAlexander Graf             bdrv_aio_cancel(ncq_tfs->aiocb);
559f6ad2e32SAlexander Graf             ncq_tfs->aiocb = NULL;
560f6ad2e32SAlexander Graf         }
561f6ad2e32SAlexander Graf 
562f6ad2e32SAlexander Graf         qemu_sglist_destroy(&ncq_tfs->sglist);
563f6ad2e32SAlexander Graf         ncq_tfs->used = 0;
564f6ad2e32SAlexander Graf     }
565f6ad2e32SAlexander Graf 
566f6ad2e32SAlexander Graf     s->dev[port].port_state = STATE_RUN;
567f6ad2e32SAlexander Graf     if (!ide_state->bs) {
568f6ad2e32SAlexander Graf         s->dev[port].port_regs.sig = 0;
569cdfe17dfSBlue Swirl         ide_state->status = SEEK_STAT | WRERR_STAT;
570f6ad2e32SAlexander Graf     } else if (ide_state->drive_kind == IDE_CD) {
571f6ad2e32SAlexander Graf         s->dev[port].port_regs.sig = SATA_SIGNATURE_CDROM;
572f6ad2e32SAlexander Graf         ide_state->lcyl = 0x14;
573f6ad2e32SAlexander Graf         ide_state->hcyl = 0xeb;
574f6ad2e32SAlexander Graf         DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl);
575f6ad2e32SAlexander Graf         ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT;
576f6ad2e32SAlexander Graf     } else {
577f6ad2e32SAlexander Graf         s->dev[port].port_regs.sig = SATA_SIGNATURE_DISK;
578f6ad2e32SAlexander Graf         ide_state->status = SEEK_STAT | WRERR_STAT;
579f6ad2e32SAlexander Graf     }
580f6ad2e32SAlexander Graf 
581f6ad2e32SAlexander Graf     ide_state->error = 1;
58287e62065SAlexander Graf     ahci_init_d2h(d);
583f6ad2e32SAlexander Graf }
584f6ad2e32SAlexander Graf 
585f6ad2e32SAlexander Graf static void debug_print_fis(uint8_t *fis, int cmd_len)
586f6ad2e32SAlexander Graf {
587f6ad2e32SAlexander Graf #ifdef DEBUG_AHCI
588f6ad2e32SAlexander Graf     int i;
589f6ad2e32SAlexander Graf 
590f6ad2e32SAlexander Graf     fprintf(stderr, "fis:");
591f6ad2e32SAlexander Graf     for (i = 0; i < cmd_len; i++) {
592f6ad2e32SAlexander Graf         if ((i & 0xf) == 0) {
593f6ad2e32SAlexander Graf             fprintf(stderr, "\n%02x:",i);
594f6ad2e32SAlexander Graf         }
595f6ad2e32SAlexander Graf         fprintf(stderr, "%02x ",fis[i]);
596f6ad2e32SAlexander Graf     }
597f6ad2e32SAlexander Graf     fprintf(stderr, "\n");
598f6ad2e32SAlexander Graf #endif
599f6ad2e32SAlexander Graf }
600f6ad2e32SAlexander Graf 
601f6ad2e32SAlexander Graf static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished)
602f6ad2e32SAlexander Graf {
603f6ad2e32SAlexander Graf     AHCIPortRegs *pr = &s->dev[port].port_regs;
604f6ad2e32SAlexander Graf     IDEState *ide_state;
605f6ad2e32SAlexander Graf     uint8_t *sdb_fis;
606f6ad2e32SAlexander Graf 
607f6ad2e32SAlexander Graf     if (!s->dev[port].res_fis ||
608f6ad2e32SAlexander Graf         !(pr->cmd & PORT_CMD_FIS_RX)) {
609f6ad2e32SAlexander Graf         return;
610f6ad2e32SAlexander Graf     }
611f6ad2e32SAlexander Graf 
612f6ad2e32SAlexander Graf     sdb_fis = &s->dev[port].res_fis[RES_FIS_SDBFIS];
613f6ad2e32SAlexander Graf     ide_state = &s->dev[port].port.ifs[0];
614f6ad2e32SAlexander Graf 
615f6ad2e32SAlexander Graf     /* clear memory */
616f6ad2e32SAlexander Graf     *(uint32_t*)sdb_fis = 0;
617f6ad2e32SAlexander Graf 
618f6ad2e32SAlexander Graf     /* write values */
619f6ad2e32SAlexander Graf     sdb_fis[0] = ide_state->error;
620f6ad2e32SAlexander Graf     sdb_fis[2] = ide_state->status & 0x77;
621f6ad2e32SAlexander Graf     s->dev[port].finished |= finished;
622f6ad2e32SAlexander Graf     *(uint32_t*)(sdb_fis + 4) = cpu_to_le32(s->dev[port].finished);
623f6ad2e32SAlexander Graf 
624f6ad2e32SAlexander Graf     ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_STAT_SDBS);
625f6ad2e32SAlexander Graf }
626f6ad2e32SAlexander Graf 
627f6ad2e32SAlexander Graf static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
628f6ad2e32SAlexander Graf {
629f6ad2e32SAlexander Graf     AHCIPortRegs *pr = &ad->port_regs;
630f6ad2e32SAlexander Graf     uint8_t *d2h_fis;
631f6ad2e32SAlexander Graf     int i;
632f6ad2e32SAlexander Graf     target_phys_addr_t cmd_len = 0x80;
633f6ad2e32SAlexander Graf     int cmd_mapped = 0;
634f6ad2e32SAlexander Graf 
635f6ad2e32SAlexander Graf     if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
636f6ad2e32SAlexander Graf         return;
637f6ad2e32SAlexander Graf     }
638f6ad2e32SAlexander Graf 
639f6ad2e32SAlexander Graf     if (!cmd_fis) {
640f6ad2e32SAlexander Graf         /* map cmd_fis */
641f6ad2e32SAlexander Graf         uint64_t tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr);
642f6ad2e32SAlexander Graf         cmd_fis = cpu_physical_memory_map(tbl_addr, &cmd_len, 0);
643f6ad2e32SAlexander Graf         cmd_mapped = 1;
644f6ad2e32SAlexander Graf     }
645f6ad2e32SAlexander Graf 
646f6ad2e32SAlexander Graf     d2h_fis = &ad->res_fis[RES_FIS_RFIS];
647f6ad2e32SAlexander Graf 
648f6ad2e32SAlexander Graf     d2h_fis[0] = 0x34;
649f6ad2e32SAlexander Graf     d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
650f6ad2e32SAlexander Graf     d2h_fis[2] = ad->port.ifs[0].status;
651f6ad2e32SAlexander Graf     d2h_fis[3] = ad->port.ifs[0].error;
652f6ad2e32SAlexander Graf 
653f6ad2e32SAlexander Graf     d2h_fis[4] = cmd_fis[4];
654f6ad2e32SAlexander Graf     d2h_fis[5] = cmd_fis[5];
655f6ad2e32SAlexander Graf     d2h_fis[6] = cmd_fis[6];
656f6ad2e32SAlexander Graf     d2h_fis[7] = cmd_fis[7];
657f6ad2e32SAlexander Graf     d2h_fis[8] = cmd_fis[8];
658f6ad2e32SAlexander Graf     d2h_fis[9] = cmd_fis[9];
659f6ad2e32SAlexander Graf     d2h_fis[10] = cmd_fis[10];
660f6ad2e32SAlexander Graf     d2h_fis[11] = cmd_fis[11];
661f6ad2e32SAlexander Graf     d2h_fis[12] = cmd_fis[12];
662f6ad2e32SAlexander Graf     d2h_fis[13] = cmd_fis[13];
663f6ad2e32SAlexander Graf     for (i = 14; i < 0x20; i++) {
664f6ad2e32SAlexander Graf         d2h_fis[i] = 0;
665f6ad2e32SAlexander Graf     }
666f6ad2e32SAlexander Graf 
667f6ad2e32SAlexander Graf     if (d2h_fis[2] & ERR_STAT) {
668f6ad2e32SAlexander Graf         ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_TFES);
669f6ad2e32SAlexander Graf     }
670f6ad2e32SAlexander Graf 
671f6ad2e32SAlexander Graf     ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
672f6ad2e32SAlexander Graf 
673f6ad2e32SAlexander Graf     if (cmd_mapped) {
674fe6ceac8SStefan Hajnoczi         cpu_physical_memory_unmap(cmd_fis, cmd_len, 0, cmd_len);
675f6ad2e32SAlexander Graf     }
676f6ad2e32SAlexander Graf }
677f6ad2e32SAlexander Graf 
678f6ad2e32SAlexander Graf static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
679f6ad2e32SAlexander Graf {
680f6ad2e32SAlexander Graf     AHCICmdHdr *cmd = ad->cur_cmd;
681f6ad2e32SAlexander Graf     uint32_t opts = le32_to_cpu(cmd->opts);
682f6ad2e32SAlexander Graf     uint64_t prdt_addr = le64_to_cpu(cmd->tbl_addr) + 0x80;
683f6ad2e32SAlexander Graf     int sglist_alloc_hint = opts >> AHCI_CMD_HDR_PRDT_LEN;
684f6ad2e32SAlexander Graf     target_phys_addr_t prdt_len = (sglist_alloc_hint * sizeof(AHCI_SG));
685f6ad2e32SAlexander Graf     target_phys_addr_t real_prdt_len = prdt_len;
686f6ad2e32SAlexander Graf     uint8_t *prdt;
687f6ad2e32SAlexander Graf     int i;
688f6ad2e32SAlexander Graf     int r = 0;
689f6ad2e32SAlexander Graf 
690f6ad2e32SAlexander Graf     if (!sglist_alloc_hint) {
691f6ad2e32SAlexander Graf         DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
692f6ad2e32SAlexander Graf         return -1;
693f6ad2e32SAlexander Graf     }
694f6ad2e32SAlexander Graf 
695f6ad2e32SAlexander Graf     /* map PRDT */
696f6ad2e32SAlexander Graf     if (!(prdt = cpu_physical_memory_map(prdt_addr, &prdt_len, 0))){
697f6ad2e32SAlexander Graf         DPRINTF(ad->port_no, "map failed\n");
698f6ad2e32SAlexander Graf         return -1;
699f6ad2e32SAlexander Graf     }
700f6ad2e32SAlexander Graf 
701f6ad2e32SAlexander Graf     if (prdt_len < real_prdt_len) {
702f6ad2e32SAlexander Graf         DPRINTF(ad->port_no, "mapped less than expected\n");
703f6ad2e32SAlexander Graf         r = -1;
704f6ad2e32SAlexander Graf         goto out;
705f6ad2e32SAlexander Graf     }
706f6ad2e32SAlexander Graf 
707f6ad2e32SAlexander Graf     /* Get entries in the PRDT, init a qemu sglist accordingly */
708f6ad2e32SAlexander Graf     if (sglist_alloc_hint > 0) {
709f6ad2e32SAlexander Graf         AHCI_SG *tbl = (AHCI_SG *)prdt;
710f6ad2e32SAlexander Graf 
711f6ad2e32SAlexander Graf         qemu_sglist_init(sglist, sglist_alloc_hint);
712f6ad2e32SAlexander Graf         for (i = 0; i < sglist_alloc_hint; i++) {
713f6ad2e32SAlexander Graf             /* flags_size is zero-based */
714f6ad2e32SAlexander Graf             qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
715f6ad2e32SAlexander Graf                             le32_to_cpu(tbl[i].flags_size) + 1);
716f6ad2e32SAlexander Graf         }
717f6ad2e32SAlexander Graf     }
718f6ad2e32SAlexander Graf 
719f6ad2e32SAlexander Graf out:
720fe6ceac8SStefan Hajnoczi     cpu_physical_memory_unmap(prdt, prdt_len, 0, prdt_len);
721f6ad2e32SAlexander Graf     return r;
722f6ad2e32SAlexander Graf }
723f6ad2e32SAlexander Graf 
724f6ad2e32SAlexander Graf static void ncq_cb(void *opaque, int ret)
725f6ad2e32SAlexander Graf {
726f6ad2e32SAlexander Graf     NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
727f6ad2e32SAlexander Graf     IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
728f6ad2e32SAlexander Graf 
729f6ad2e32SAlexander Graf     /* Clear bit for this tag in SActive */
730f6ad2e32SAlexander Graf     ncq_tfs->drive->port_regs.scr_act &= ~(1 << ncq_tfs->tag);
731f6ad2e32SAlexander Graf 
732f6ad2e32SAlexander Graf     if (ret < 0) {
733f6ad2e32SAlexander Graf         /* error */
734f6ad2e32SAlexander Graf         ide_state->error = ABRT_ERR;
735f6ad2e32SAlexander Graf         ide_state->status = READY_STAT | ERR_STAT;
736f6ad2e32SAlexander Graf         ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
737f6ad2e32SAlexander Graf     } else {
738f6ad2e32SAlexander Graf         ide_state->status = READY_STAT | SEEK_STAT;
739f6ad2e32SAlexander Graf     }
740f6ad2e32SAlexander Graf 
741f6ad2e32SAlexander Graf     ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs->drive->port_no,
742f6ad2e32SAlexander Graf                        (1 << ncq_tfs->tag));
743f6ad2e32SAlexander Graf 
744f6ad2e32SAlexander Graf     DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
745f6ad2e32SAlexander Graf             ncq_tfs->tag);
746f6ad2e32SAlexander Graf 
747a597e79cSChristoph Hellwig     bdrv_acct_done(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct);
748f6ad2e32SAlexander Graf     qemu_sglist_destroy(&ncq_tfs->sglist);
749f6ad2e32SAlexander Graf     ncq_tfs->used = 0;
750f6ad2e32SAlexander Graf }
751f6ad2e32SAlexander Graf 
752f6ad2e32SAlexander Graf static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
753f6ad2e32SAlexander Graf                                 int slot)
754f6ad2e32SAlexander Graf {
755f6ad2e32SAlexander Graf     NCQFrame *ncq_fis = (NCQFrame*)cmd_fis;
756f6ad2e32SAlexander Graf     uint8_t tag = ncq_fis->tag >> 3;
757f6ad2e32SAlexander Graf     NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[tag];
758f6ad2e32SAlexander Graf 
759f6ad2e32SAlexander Graf     if (ncq_tfs->used) {
760f6ad2e32SAlexander Graf         /* error - already in use */
761f6ad2e32SAlexander Graf         fprintf(stderr, "%s: tag %d already used\n", __FUNCTION__, tag);
762f6ad2e32SAlexander Graf         return;
763f6ad2e32SAlexander Graf     }
764f6ad2e32SAlexander Graf 
765f6ad2e32SAlexander Graf     ncq_tfs->used = 1;
766f6ad2e32SAlexander Graf     ncq_tfs->drive = &s->dev[port];
767f6ad2e32SAlexander Graf     ncq_tfs->slot = slot;
768f6ad2e32SAlexander Graf     ncq_tfs->lba = ((uint64_t)ncq_fis->lba5 << 40) |
769f6ad2e32SAlexander Graf                    ((uint64_t)ncq_fis->lba4 << 32) |
770f6ad2e32SAlexander Graf                    ((uint64_t)ncq_fis->lba3 << 24) |
771f6ad2e32SAlexander Graf                    ((uint64_t)ncq_fis->lba2 << 16) |
772f6ad2e32SAlexander Graf                    ((uint64_t)ncq_fis->lba1 << 8) |
773f6ad2e32SAlexander Graf                    (uint64_t)ncq_fis->lba0;
774f6ad2e32SAlexander Graf 
775f6ad2e32SAlexander Graf     /* Note: We calculate the sector count, but don't currently rely on it.
776f6ad2e32SAlexander Graf      * The total size of the DMA buffer tells us the transfer size instead. */
777f6ad2e32SAlexander Graf     ncq_tfs->sector_count = ((uint16_t)ncq_fis->sector_count_high << 8) |
778f6ad2e32SAlexander Graf                                 ncq_fis->sector_count_low;
779f6ad2e32SAlexander Graf 
780f6ad2e32SAlexander Graf     DPRINTF(port, "NCQ transfer LBA from %ld to %ld, drive max %ld\n",
781f6ad2e32SAlexander Graf             ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
782f6ad2e32SAlexander Graf             s->dev[port].port.ifs[0].nb_sectors - 1);
783f6ad2e32SAlexander Graf 
784f6ad2e32SAlexander Graf     ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist);
785f6ad2e32SAlexander Graf     ncq_tfs->tag = tag;
786f6ad2e32SAlexander Graf 
787f6ad2e32SAlexander Graf     switch(ncq_fis->command) {
788f6ad2e32SAlexander Graf         case READ_FPDMA_QUEUED:
789f6ad2e32SAlexander Graf             DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n",
790f6ad2e32SAlexander Graf                     ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
791f6ad2e32SAlexander Graf 
792f6ad2e32SAlexander Graf             DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba);
793a597e79cSChristoph Hellwig 
794a597e79cSChristoph Hellwig             bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
795a597e79cSChristoph Hellwig                             (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE,
796a597e79cSChristoph Hellwig                             BDRV_ACCT_READ);
797f6ad2e32SAlexander Graf             ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs,
798f6ad2e32SAlexander Graf                                            &ncq_tfs->sglist, ncq_tfs->lba,
799f6ad2e32SAlexander Graf                                            ncq_cb, ncq_tfs);
800f6ad2e32SAlexander Graf             break;
801f6ad2e32SAlexander Graf         case WRITE_FPDMA_QUEUED:
802f6ad2e32SAlexander Graf             DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n",
803f6ad2e32SAlexander Graf                     ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag);
804f6ad2e32SAlexander Graf 
805f6ad2e32SAlexander Graf             DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba);
806a597e79cSChristoph Hellwig 
807a597e79cSChristoph Hellwig             bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
808a597e79cSChristoph Hellwig                             (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE,
809a597e79cSChristoph Hellwig                             BDRV_ACCT_WRITE);
810f6ad2e32SAlexander Graf             ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs,
811f6ad2e32SAlexander Graf                                             &ncq_tfs->sglist, ncq_tfs->lba,
812f6ad2e32SAlexander Graf                                             ncq_cb, ncq_tfs);
813f6ad2e32SAlexander Graf             break;
814f6ad2e32SAlexander Graf         default:
815f6ad2e32SAlexander Graf             DPRINTF(port, "error: tried to process non-NCQ command as NCQ\n");
816f6ad2e32SAlexander Graf             qemu_sglist_destroy(&ncq_tfs->sglist);
817f6ad2e32SAlexander Graf             break;
818f6ad2e32SAlexander Graf     }
819f6ad2e32SAlexander Graf }
820f6ad2e32SAlexander Graf 
821f6ad2e32SAlexander Graf static int handle_cmd(AHCIState *s, int port, int slot)
822f6ad2e32SAlexander Graf {
823f6ad2e32SAlexander Graf     IDEState *ide_state;
824f6ad2e32SAlexander Graf     uint32_t opts;
825f6ad2e32SAlexander Graf     uint64_t tbl_addr;
826f6ad2e32SAlexander Graf     AHCICmdHdr *cmd;
827f6ad2e32SAlexander Graf     uint8_t *cmd_fis;
828f6ad2e32SAlexander Graf     target_phys_addr_t cmd_len;
829f6ad2e32SAlexander Graf 
830f6ad2e32SAlexander Graf     if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
831f6ad2e32SAlexander Graf         /* Engine currently busy, try again later */
832f6ad2e32SAlexander Graf         DPRINTF(port, "engine busy\n");
833f6ad2e32SAlexander Graf         return -1;
834f6ad2e32SAlexander Graf     }
835f6ad2e32SAlexander Graf 
836f6ad2e32SAlexander Graf     cmd = &((AHCICmdHdr *)s->dev[port].lst)[slot];
837f6ad2e32SAlexander Graf 
838f6ad2e32SAlexander Graf     if (!s->dev[port].lst) {
839f6ad2e32SAlexander Graf         DPRINTF(port, "error: lst not given but cmd handled");
840f6ad2e32SAlexander Graf         return -1;
841f6ad2e32SAlexander Graf     }
842f6ad2e32SAlexander Graf 
843f6ad2e32SAlexander Graf     /* remember current slot handle for later */
844f6ad2e32SAlexander Graf     s->dev[port].cur_cmd = cmd;
845f6ad2e32SAlexander Graf 
846f6ad2e32SAlexander Graf     opts = le32_to_cpu(cmd->opts);
847f6ad2e32SAlexander Graf     tbl_addr = le64_to_cpu(cmd->tbl_addr);
848f6ad2e32SAlexander Graf 
849f6ad2e32SAlexander Graf     cmd_len = 0x80;
850f6ad2e32SAlexander Graf     cmd_fis = cpu_physical_memory_map(tbl_addr, &cmd_len, 1);
851f6ad2e32SAlexander Graf 
852f6ad2e32SAlexander Graf     if (!cmd_fis) {
853f6ad2e32SAlexander Graf         DPRINTF(port, "error: guest passed us an invalid cmd fis\n");
854f6ad2e32SAlexander Graf         return -1;
855f6ad2e32SAlexander Graf     }
856f6ad2e32SAlexander Graf 
857f6ad2e32SAlexander Graf     /* The device we are working for */
858f6ad2e32SAlexander Graf     ide_state = &s->dev[port].port.ifs[0];
859f6ad2e32SAlexander Graf 
860f6ad2e32SAlexander Graf     if (!ide_state->bs) {
861f6ad2e32SAlexander Graf         DPRINTF(port, "error: guest accessed unused port");
862f6ad2e32SAlexander Graf         goto out;
863f6ad2e32SAlexander Graf     }
864f6ad2e32SAlexander Graf 
865f6ad2e32SAlexander Graf     debug_print_fis(cmd_fis, 0x90);
866f6ad2e32SAlexander Graf     //debug_print_fis(cmd_fis, (opts & AHCI_CMD_HDR_CMD_FIS_LEN) * 4);
867f6ad2e32SAlexander Graf 
868f6ad2e32SAlexander Graf     switch (cmd_fis[0]) {
869f6ad2e32SAlexander Graf         case SATA_FIS_TYPE_REGISTER_H2D:
870f6ad2e32SAlexander Graf             break;
871f6ad2e32SAlexander Graf         default:
872f6ad2e32SAlexander Graf             DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
873f6ad2e32SAlexander Graf                           "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
874f6ad2e32SAlexander Graf                           cmd_fis[2]);
875f6ad2e32SAlexander Graf             goto out;
876f6ad2e32SAlexander Graf             break;
877f6ad2e32SAlexander Graf     }
878f6ad2e32SAlexander Graf 
879f6ad2e32SAlexander Graf     switch (cmd_fis[1]) {
880f6ad2e32SAlexander Graf         case SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER:
881f6ad2e32SAlexander Graf             break;
882f6ad2e32SAlexander Graf         case 0:
883f6ad2e32SAlexander Graf             break;
884f6ad2e32SAlexander Graf         default:
885f6ad2e32SAlexander Graf             DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
886f6ad2e32SAlexander Graf                           "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
887f6ad2e32SAlexander Graf                           cmd_fis[2]);
888f6ad2e32SAlexander Graf             goto out;
889f6ad2e32SAlexander Graf             break;
890f6ad2e32SAlexander Graf     }
891f6ad2e32SAlexander Graf 
892f6ad2e32SAlexander Graf     switch (s->dev[port].port_state) {
893f6ad2e32SAlexander Graf         case STATE_RUN:
894f6ad2e32SAlexander Graf             if (cmd_fis[15] & ATA_SRST) {
895f6ad2e32SAlexander Graf                 s->dev[port].port_state = STATE_RESET;
896f6ad2e32SAlexander Graf             }
897f6ad2e32SAlexander Graf             break;
898f6ad2e32SAlexander Graf         case STATE_RESET:
899f6ad2e32SAlexander Graf             if (!(cmd_fis[15] & ATA_SRST)) {
900f6ad2e32SAlexander Graf                 ahci_reset_port(s, port);
901f6ad2e32SAlexander Graf             }
902f6ad2e32SAlexander Graf             break;
903f6ad2e32SAlexander Graf     }
904f6ad2e32SAlexander Graf 
905f6ad2e32SAlexander Graf     if (cmd_fis[1] == SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER) {
906f6ad2e32SAlexander Graf 
907f6ad2e32SAlexander Graf         /* Check for NCQ command */
908f6ad2e32SAlexander Graf         if ((cmd_fis[2] == READ_FPDMA_QUEUED) ||
909f6ad2e32SAlexander Graf             (cmd_fis[2] == WRITE_FPDMA_QUEUED)) {
910f6ad2e32SAlexander Graf             process_ncq_command(s, port, cmd_fis, slot);
911f6ad2e32SAlexander Graf             goto out;
912f6ad2e32SAlexander Graf         }
913f6ad2e32SAlexander Graf 
914f6ad2e32SAlexander Graf         /* Decompose the FIS  */
915f6ad2e32SAlexander Graf         ide_state->nsector = (int64_t)((cmd_fis[13] << 8) | cmd_fis[12]);
916f6ad2e32SAlexander Graf         ide_state->feature = cmd_fis[3];
917f6ad2e32SAlexander Graf         if (!ide_state->nsector) {
918f6ad2e32SAlexander Graf             ide_state->nsector = 256;
919f6ad2e32SAlexander Graf         }
920f6ad2e32SAlexander Graf 
921f6ad2e32SAlexander Graf         if (ide_state->drive_kind != IDE_CD) {
9221fddfba1SAlexander Graf             /*
9231fddfba1SAlexander Graf              * We set the sector depending on the sector defined in the FIS.
9241fddfba1SAlexander Graf              * Unfortunately, the spec isn't exactly obvious on this one.
9251fddfba1SAlexander Graf              *
9261fddfba1SAlexander Graf              * Apparently LBA48 commands set fis bytes 10,9,8,6,5,4 to the
9271fddfba1SAlexander Graf              * 48 bit sector number. ATA_CMD_READ_DMA_EXT is an example for
9281fddfba1SAlexander Graf              * such a command.
9291fddfba1SAlexander Graf              *
9301fddfba1SAlexander Graf              * Non-LBA48 commands however use 7[lower 4 bits],6,5,4 to define a
9311fddfba1SAlexander Graf              * 28-bit sector number. ATA_CMD_READ_DMA is an example for such
9321fddfba1SAlexander Graf              * a command.
9331fddfba1SAlexander Graf              *
9341fddfba1SAlexander Graf              * Since the spec doesn't explicitly state what each field should
9351fddfba1SAlexander Graf              * do, I simply assume non-used fields as reserved and OR everything
9361fddfba1SAlexander Graf              * together, independent of the command.
9371fddfba1SAlexander Graf              */
9381fddfba1SAlexander Graf             ide_set_sector(ide_state, ((uint64_t)cmd_fis[10] << 40)
9391fddfba1SAlexander Graf                                     | ((uint64_t)cmd_fis[9] << 32)
9401fddfba1SAlexander Graf                                     /* This is used for LBA48 commands */
9411fddfba1SAlexander Graf                                     | ((uint64_t)cmd_fis[8] << 24)
9421fddfba1SAlexander Graf                                     /* This is used for non-LBA48 commands */
9431fddfba1SAlexander Graf                                     | ((uint64_t)(cmd_fis[7] & 0xf) << 24)
9441fddfba1SAlexander Graf                                     | ((uint64_t)cmd_fis[6] << 16)
9451fddfba1SAlexander Graf                                     | ((uint64_t)cmd_fis[5] << 8)
9461fddfba1SAlexander Graf                                     | cmd_fis[4]);
947f6ad2e32SAlexander Graf         }
948f6ad2e32SAlexander Graf 
949f6ad2e32SAlexander Graf         /* Copy the ACMD field (ATAPI packet, if any) from the AHCI command
950f6ad2e32SAlexander Graf          * table to ide_state->io_buffer
951f6ad2e32SAlexander Graf          */
952f6ad2e32SAlexander Graf         if (opts & AHCI_CMD_ATAPI) {
953f6ad2e32SAlexander Graf             memcpy(ide_state->io_buffer, &cmd_fis[AHCI_COMMAND_TABLE_ACMD], 0x10);
954f6ad2e32SAlexander Graf             ide_state->lcyl = 0x14;
955f6ad2e32SAlexander Graf             ide_state->hcyl = 0xeb;
956f6ad2e32SAlexander Graf             debug_print_fis(ide_state->io_buffer, 0x10);
957f6ad2e32SAlexander Graf             ide_state->feature = IDE_FEATURE_DMA;
958f6ad2e32SAlexander Graf             s->dev[port].done_atapi_packet = 0;
959f6ad2e32SAlexander Graf             /* XXX send PIO setup FIS */
960f6ad2e32SAlexander Graf         }
961f6ad2e32SAlexander Graf 
962f6ad2e32SAlexander Graf         ide_state->error = 0;
963f6ad2e32SAlexander Graf 
964f6ad2e32SAlexander Graf         /* Reset transferred byte counter */
965f6ad2e32SAlexander Graf         cmd->status = 0;
966f6ad2e32SAlexander Graf 
967f6ad2e32SAlexander Graf         /* We're ready to process the command in FIS byte 2. */
968f6ad2e32SAlexander Graf         ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
969f6ad2e32SAlexander Graf 
970f6ad2e32SAlexander Graf         if (s->dev[port].port.ifs[0].status & READY_STAT) {
971f6ad2e32SAlexander Graf             ahci_write_fis_d2h(&s->dev[port], cmd_fis);
972f6ad2e32SAlexander Graf         }
973f6ad2e32SAlexander Graf     }
974f6ad2e32SAlexander Graf 
975f6ad2e32SAlexander Graf out:
976fe6ceac8SStefan Hajnoczi     cpu_physical_memory_unmap(cmd_fis, cmd_len, 1, cmd_len);
977f6ad2e32SAlexander Graf 
978f6ad2e32SAlexander Graf     if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
979f6ad2e32SAlexander Graf         /* async command, complete later */
980f6ad2e32SAlexander Graf         s->dev[port].busy_slot = slot;
981f6ad2e32SAlexander Graf         return -1;
982f6ad2e32SAlexander Graf     }
983f6ad2e32SAlexander Graf 
984f6ad2e32SAlexander Graf     /* done handling the command */
985f6ad2e32SAlexander Graf     return 0;
986f6ad2e32SAlexander Graf }
987f6ad2e32SAlexander Graf 
988f6ad2e32SAlexander Graf /* DMA dev <-> ram */
989f6ad2e32SAlexander Graf static int ahci_start_transfer(IDEDMA *dma)
990f6ad2e32SAlexander Graf {
991f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
992f6ad2e32SAlexander Graf     IDEState *s = &ad->port.ifs[0];
993f6ad2e32SAlexander Graf     uint32_t size = (uint32_t)(s->data_end - s->data_ptr);
994f6ad2e32SAlexander Graf     /* write == ram -> device */
995f6ad2e32SAlexander Graf     uint32_t opts = le32_to_cpu(ad->cur_cmd->opts);
996f6ad2e32SAlexander Graf     int is_write = opts & AHCI_CMD_WRITE;
997f6ad2e32SAlexander Graf     int is_atapi = opts & AHCI_CMD_ATAPI;
998f6ad2e32SAlexander Graf     int has_sglist = 0;
999f6ad2e32SAlexander Graf 
1000f6ad2e32SAlexander Graf     if (is_atapi && !ad->done_atapi_packet) {
1001f6ad2e32SAlexander Graf         /* already prepopulated iobuffer */
1002f6ad2e32SAlexander Graf         ad->done_atapi_packet = 1;
1003f6ad2e32SAlexander Graf         goto out;
1004f6ad2e32SAlexander Graf     }
1005f6ad2e32SAlexander Graf 
1006f6ad2e32SAlexander Graf     if (!ahci_populate_sglist(ad, &s->sg)) {
1007f6ad2e32SAlexander Graf         has_sglist = 1;
1008f6ad2e32SAlexander Graf     }
1009f6ad2e32SAlexander Graf 
1010f6ad2e32SAlexander Graf     DPRINTF(ad->port_no, "%sing %d bytes on %s w/%s sglist\n",
1011f6ad2e32SAlexander Graf             is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata",
1012f6ad2e32SAlexander Graf             has_sglist ? "" : "o");
1013f6ad2e32SAlexander Graf 
1014f6ad2e32SAlexander Graf     if (is_write && has_sglist && (s->data_ptr < s->data_end)) {
1015f6ad2e32SAlexander Graf         read_from_sglist(s->data_ptr, size, &s->sg);
1016f6ad2e32SAlexander Graf     }
1017f6ad2e32SAlexander Graf 
1018f6ad2e32SAlexander Graf     if (!is_write && has_sglist && (s->data_ptr < s->data_end)) {
1019f6ad2e32SAlexander Graf         write_to_sglist(s->data_ptr, size, &s->sg);
1020f6ad2e32SAlexander Graf     }
1021f6ad2e32SAlexander Graf 
1022f6ad2e32SAlexander Graf     /* update number of transferred bytes */
1023f6ad2e32SAlexander Graf     ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + size);
1024f6ad2e32SAlexander Graf 
1025f6ad2e32SAlexander Graf out:
1026f6ad2e32SAlexander Graf     /* declare that we processed everything */
1027f6ad2e32SAlexander Graf     s->data_ptr = s->data_end;
1028f6ad2e32SAlexander Graf 
1029f6ad2e32SAlexander Graf     if (has_sglist) {
1030f6ad2e32SAlexander Graf         qemu_sglist_destroy(&s->sg);
1031f6ad2e32SAlexander Graf     }
1032f6ad2e32SAlexander Graf 
1033f6ad2e32SAlexander Graf     s->end_transfer_func(s);
1034f6ad2e32SAlexander Graf 
1035f6ad2e32SAlexander Graf     if (!(s->status & DRQ_STAT)) {
1036f6ad2e32SAlexander Graf         /* done with DMA */
1037f6ad2e32SAlexander Graf         ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
1038f6ad2e32SAlexander Graf     }
1039f6ad2e32SAlexander Graf 
1040f6ad2e32SAlexander Graf     return 0;
1041f6ad2e32SAlexander Graf }
1042f6ad2e32SAlexander Graf 
1043f6ad2e32SAlexander Graf static void ahci_start_dma(IDEDMA *dma, IDEState *s,
1044f6ad2e32SAlexander Graf                            BlockDriverCompletionFunc *dma_cb)
1045f6ad2e32SAlexander Graf {
1046f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1047f6ad2e32SAlexander Graf 
1048f6ad2e32SAlexander Graf     DPRINTF(ad->port_no, "\n");
1049f6ad2e32SAlexander Graf     ad->dma_cb = dma_cb;
1050f6ad2e32SAlexander Graf     ad->dma_status |= BM_STATUS_DMAING;
1051f6ad2e32SAlexander Graf     dma_cb(s, 0);
1052f6ad2e32SAlexander Graf }
1053f6ad2e32SAlexander Graf 
1054f6ad2e32SAlexander Graf static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
1055f6ad2e32SAlexander Graf {
1056f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1057f6ad2e32SAlexander Graf     IDEState *s = &ad->port.ifs[0];
1058f6ad2e32SAlexander Graf     int i;
1059f6ad2e32SAlexander Graf 
1060f6ad2e32SAlexander Graf     ahci_populate_sglist(ad, &s->sg);
1061f6ad2e32SAlexander Graf 
1062f6ad2e32SAlexander Graf     s->io_buffer_size = 0;
1063f6ad2e32SAlexander Graf     for (i = 0; i < s->sg.nsg; i++) {
1064f6ad2e32SAlexander Graf         s->io_buffer_size += s->sg.sg[i].len;
1065f6ad2e32SAlexander Graf     }
1066f6ad2e32SAlexander Graf 
1067f6ad2e32SAlexander Graf     DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
1068f6ad2e32SAlexander Graf     return s->io_buffer_size != 0;
1069f6ad2e32SAlexander Graf }
1070f6ad2e32SAlexander Graf 
1071f6ad2e32SAlexander Graf static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
1072f6ad2e32SAlexander Graf {
1073f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1074f6ad2e32SAlexander Graf     IDEState *s = &ad->port.ifs[0];
1075f6ad2e32SAlexander Graf     uint8_t *p = s->io_buffer + s->io_buffer_index;
1076f6ad2e32SAlexander Graf     int l = s->io_buffer_size - s->io_buffer_index;
1077f6ad2e32SAlexander Graf 
1078f6ad2e32SAlexander Graf     if (ahci_populate_sglist(ad, &s->sg)) {
1079f6ad2e32SAlexander Graf         return 0;
1080f6ad2e32SAlexander Graf     }
1081f6ad2e32SAlexander Graf 
1082f6ad2e32SAlexander Graf     if (is_write) {
1083f6ad2e32SAlexander Graf         write_to_sglist(p, l, &s->sg);
1084f6ad2e32SAlexander Graf     } else {
1085f6ad2e32SAlexander Graf         read_from_sglist(p, l, &s->sg);
1086f6ad2e32SAlexander Graf     }
1087f6ad2e32SAlexander Graf 
1088f6ad2e32SAlexander Graf     /* update number of transferred bytes */
1089f6ad2e32SAlexander Graf     ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l);
1090f6ad2e32SAlexander Graf     s->io_buffer_index += l;
1091f6ad2e32SAlexander Graf 
1092f6ad2e32SAlexander Graf     DPRINTF(ad->port_no, "len=%#x\n", l);
1093f6ad2e32SAlexander Graf 
1094f6ad2e32SAlexander Graf     return 1;
1095f6ad2e32SAlexander Graf }
1096f6ad2e32SAlexander Graf 
1097f6ad2e32SAlexander Graf static int ahci_dma_set_unit(IDEDMA *dma, int unit)
1098f6ad2e32SAlexander Graf {
1099f6ad2e32SAlexander Graf     /* only a single unit per link */
1100f6ad2e32SAlexander Graf     return 0;
1101f6ad2e32SAlexander Graf }
1102f6ad2e32SAlexander Graf 
1103f6ad2e32SAlexander Graf static int ahci_dma_add_status(IDEDMA *dma, int status)
1104f6ad2e32SAlexander Graf {
1105f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1106f6ad2e32SAlexander Graf     ad->dma_status |= status;
1107f6ad2e32SAlexander Graf     DPRINTF(ad->port_no, "set status: %x\n", status);
1108f6ad2e32SAlexander Graf 
1109f6ad2e32SAlexander Graf     if (status & BM_STATUS_INT) {
1110f6ad2e32SAlexander Graf         ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
1111f6ad2e32SAlexander Graf     }
1112f6ad2e32SAlexander Graf 
1113f6ad2e32SAlexander Graf     return 0;
1114f6ad2e32SAlexander Graf }
1115f6ad2e32SAlexander Graf 
1116f6ad2e32SAlexander Graf static int ahci_dma_set_inactive(IDEDMA *dma)
1117f6ad2e32SAlexander Graf {
1118f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1119f6ad2e32SAlexander Graf 
1120f6ad2e32SAlexander Graf     DPRINTF(ad->port_no, "dma done\n");
1121f6ad2e32SAlexander Graf 
1122f6ad2e32SAlexander Graf     /* update d2h status */
1123f6ad2e32SAlexander Graf     ahci_write_fis_d2h(ad, NULL);
1124f6ad2e32SAlexander Graf 
1125f6ad2e32SAlexander Graf     ad->dma_cb = NULL;
1126f6ad2e32SAlexander Graf 
11274d29b50aSJan Kiszka     if (!ad->check_bh) {
1128f6ad2e32SAlexander Graf         /* maybe we still have something to process, check later */
1129f6ad2e32SAlexander Graf         ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
1130f6ad2e32SAlexander Graf         qemu_bh_schedule(ad->check_bh);
11314d29b50aSJan Kiszka     }
1132f6ad2e32SAlexander Graf 
1133f6ad2e32SAlexander Graf     return 0;
1134f6ad2e32SAlexander Graf }
1135f6ad2e32SAlexander Graf 
1136f6ad2e32SAlexander Graf static void ahci_irq_set(void *opaque, int n, int level)
1137f6ad2e32SAlexander Graf {
1138f6ad2e32SAlexander Graf }
1139f6ad2e32SAlexander Graf 
11401dfb4dd9SLuiz Capitulino static void ahci_dma_restart_cb(void *opaque, int running, RunState state)
1141f6ad2e32SAlexander Graf {
1142f6ad2e32SAlexander Graf }
1143f6ad2e32SAlexander Graf 
1144f6ad2e32SAlexander Graf static int ahci_dma_reset(IDEDMA *dma)
1145f6ad2e32SAlexander Graf {
1146f6ad2e32SAlexander Graf     return 0;
1147f6ad2e32SAlexander Graf }
1148f6ad2e32SAlexander Graf 
1149f6ad2e32SAlexander Graf static const IDEDMAOps ahci_dma_ops = {
1150f6ad2e32SAlexander Graf     .start_dma = ahci_start_dma,
1151f6ad2e32SAlexander Graf     .start_transfer = ahci_start_transfer,
1152f6ad2e32SAlexander Graf     .prepare_buf = ahci_dma_prepare_buf,
1153f6ad2e32SAlexander Graf     .rw_buf = ahci_dma_rw_buf,
1154f6ad2e32SAlexander Graf     .set_unit = ahci_dma_set_unit,
1155f6ad2e32SAlexander Graf     .add_status = ahci_dma_add_status,
1156f6ad2e32SAlexander Graf     .set_inactive = ahci_dma_set_inactive,
1157f6ad2e32SAlexander Graf     .restart_cb = ahci_dma_restart_cb,
1158f6ad2e32SAlexander Graf     .reset = ahci_dma_reset,
1159f6ad2e32SAlexander Graf };
1160f6ad2e32SAlexander Graf 
11612c4b9d0eSAlexander Graf void ahci_init(AHCIState *s, DeviceState *qdev, int ports)
1162f6ad2e32SAlexander Graf {
1163f6ad2e32SAlexander Graf     qemu_irq *irqs;
1164f6ad2e32SAlexander Graf     int i;
1165f6ad2e32SAlexander Graf 
11662c4b9d0eSAlexander Graf     s->ports = ports;
11677267c094SAnthony Liguori     s->dev = g_malloc0(sizeof(AHCIDevice) * ports);
1168f6ad2e32SAlexander Graf     ahci_reg_init(s);
116967e576c2SAvi Kivity     /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
1170*465f1ab1SDaniel Verkamp     memory_region_init_io(&s->mem, &ahci_mem_ops, s, "ahci", AHCI_MEM_BAR_SIZE);
1171*465f1ab1SDaniel Verkamp     memory_region_init_io(&s->idp, &ahci_idp_ops, s, "ahci-idp", 32);
1172*465f1ab1SDaniel Verkamp 
11732c4b9d0eSAlexander Graf     irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports);
1174f6ad2e32SAlexander Graf 
11752c4b9d0eSAlexander Graf     for (i = 0; i < s->ports; i++) {
1176f6ad2e32SAlexander Graf         AHCIDevice *ad = &s->dev[i];
1177f6ad2e32SAlexander Graf 
1178f6ad2e32SAlexander Graf         ide_bus_new(&ad->port, qdev, i);
1179f6ad2e32SAlexander Graf         ide_init2(&ad->port, irqs[i]);
1180f6ad2e32SAlexander Graf 
1181f6ad2e32SAlexander Graf         ad->hba = s;
1182f6ad2e32SAlexander Graf         ad->port_no = i;
1183f6ad2e32SAlexander Graf         ad->port.dma = &ad->dma;
1184f6ad2e32SAlexander Graf         ad->port.dma->ops = &ahci_dma_ops;
1185f6ad2e32SAlexander Graf         ad->port_regs.cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
1186f6ad2e32SAlexander Graf     }
1187f6ad2e32SAlexander Graf }
1188f6ad2e32SAlexander Graf 
11892c4b9d0eSAlexander Graf void ahci_uninit(AHCIState *s)
11902c4b9d0eSAlexander Graf {
119167e576c2SAvi Kivity     memory_region_destroy(&s->mem);
1192*465f1ab1SDaniel Verkamp     memory_region_destroy(&s->idp);
11937267c094SAnthony Liguori     g_free(s->dev);
11942c4b9d0eSAlexander Graf }
11952c4b9d0eSAlexander Graf 
119603c7a6a8SSebastian Herbszt void ahci_reset(void *opaque)
1197f6ad2e32SAlexander Graf {
1198f6ad2e32SAlexander Graf     struct AHCIPCIState *d = opaque;
1199a26a13daSAlexander Motin     AHCIPortRegs *pr;
1200f6ad2e32SAlexander Graf     int i;
1201f6ad2e32SAlexander Graf 
1202760c3e44SAlexander Graf     d->ahci.control_regs.irqstatus = 0;
1203760c3e44SAlexander Graf     d->ahci.control_regs.ghc = 0;
1204760c3e44SAlexander Graf 
12052c4b9d0eSAlexander Graf     for (i = 0; i < d->ahci.ports; i++) {
1206a26a13daSAlexander Motin         pr = &d->ahci.dev[i].port_regs;
1207a26a13daSAlexander Motin         pr->irq_stat = 0;
1208a26a13daSAlexander Motin         pr->irq_mask = 0;
1209a26a13daSAlexander Motin         pr->scr_ctl = 0;
1210f6ad2e32SAlexander Graf         ahci_reset_port(&d->ahci, i);
1211f6ad2e32SAlexander Graf     }
1212f6ad2e32SAlexander Graf }
1213