xref: /openbmc/qemu/hw/ide/ahci.c (revision 40fe17bea478793fc9106a630fa3610dad51f939)
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>
25a2cb15b0SMichael S. Tsirkin #include <hw/pci/msi.h>
260d09e41aSPaolo Bonzini #include <hw/i386/pc.h>
27a2cb15b0SMichael S. Tsirkin #include <hw/pci/pci.h>
28f6ad2e32SAlexander Graf 
29d49b6836SMarkus Armbruster #include "qemu/error-report.h"
304be74634SMarkus Armbruster #include "sysemu/block-backend.h"
319c17d615SPaolo Bonzini #include "sysemu/dma.h"
32f6ad2e32SAlexander Graf #include "internal.h"
33f6ad2e32SAlexander Graf #include <hw/ide/pci.h>
3403c7a6a8SSebastian Herbszt #include <hw/ide/ahci.h>
35f6ad2e32SAlexander Graf 
36192cf55cSStefan Hajnoczi #define DEBUG_AHCI 0
37f6ad2e32SAlexander Graf 
38f6ad2e32SAlexander Graf #define DPRINTF(port, fmt, ...) \
39192cf55cSStefan Hajnoczi do { \
40192cf55cSStefan Hajnoczi     if (DEBUG_AHCI) { \
41192cf55cSStefan Hajnoczi         fprintf(stderr, "ahci: %s: [%d] ", __func__, port); \
42192cf55cSStefan Hajnoczi         fprintf(stderr, fmt, ## __VA_ARGS__); \
43192cf55cSStefan Hajnoczi     } \
44192cf55cSStefan Hajnoczi } while (0)
45f6ad2e32SAlexander Graf 
46f6ad2e32SAlexander Graf static void check_cmd(AHCIState *s, int port);
479364384dSJohn Snow static int handle_cmd(AHCIState *s, int port, uint8_t slot);
48f6ad2e32SAlexander Graf static void ahci_reset_port(AHCIState *s, int port);
49e47f9eb1SJohn Snow static bool ahci_write_fis_d2h(AHCIDevice *ad);
5087e62065SAlexander Graf static void ahci_init_d2h(AHCIDevice *ad);
51a718978eSJohn Snow static int ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit);
52a13ab5a3SJohn Snow static bool ahci_map_clb_address(AHCIDevice *ad);
53a13ab5a3SJohn Snow static bool ahci_map_fis_address(AHCIDevice *ad);
54fc3d8e11SJohn Snow static void ahci_unmap_clb_address(AHCIDevice *ad);
55fc3d8e11SJohn Snow static void ahci_unmap_fis_address(AHCIDevice *ad);
56659142ecSJohn Snow 
57f6ad2e32SAlexander Graf 
58f6ad2e32SAlexander Graf static uint32_t  ahci_port_read(AHCIState *s, int port, int offset)
59f6ad2e32SAlexander Graf {
60f6ad2e32SAlexander Graf     uint32_t val;
61f6ad2e32SAlexander Graf     AHCIPortRegs *pr;
62f6ad2e32SAlexander Graf     pr = &s->dev[port].port_regs;
63f6ad2e32SAlexander Graf 
64f6ad2e32SAlexander Graf     switch (offset) {
65f6ad2e32SAlexander Graf     case PORT_LST_ADDR:
66f6ad2e32SAlexander Graf         val = pr->lst_addr;
67f6ad2e32SAlexander Graf         break;
68f6ad2e32SAlexander Graf     case PORT_LST_ADDR_HI:
69f6ad2e32SAlexander Graf         val = pr->lst_addr_hi;
70f6ad2e32SAlexander Graf         break;
71f6ad2e32SAlexander Graf     case PORT_FIS_ADDR:
72f6ad2e32SAlexander Graf         val = pr->fis_addr;
73f6ad2e32SAlexander Graf         break;
74f6ad2e32SAlexander Graf     case PORT_FIS_ADDR_HI:
75f6ad2e32SAlexander Graf         val = pr->fis_addr_hi;
76f6ad2e32SAlexander Graf         break;
77f6ad2e32SAlexander Graf     case PORT_IRQ_STAT:
78f6ad2e32SAlexander Graf         val = pr->irq_stat;
79f6ad2e32SAlexander Graf         break;
80f6ad2e32SAlexander Graf     case PORT_IRQ_MASK:
81f6ad2e32SAlexander Graf         val = pr->irq_mask;
82f6ad2e32SAlexander Graf         break;
83f6ad2e32SAlexander Graf     case PORT_CMD:
84f6ad2e32SAlexander Graf         val = pr->cmd;
85f6ad2e32SAlexander Graf         break;
86f6ad2e32SAlexander Graf     case PORT_TFDATA:
87fac7aa7fSJohn Snow         val = pr->tfdata;
88f6ad2e32SAlexander Graf         break;
89f6ad2e32SAlexander Graf     case PORT_SIG:
90f6ad2e32SAlexander Graf         val = pr->sig;
91f6ad2e32SAlexander Graf         break;
92f6ad2e32SAlexander Graf     case PORT_SCR_STAT:
934be74634SMarkus Armbruster         if (s->dev[port].port.ifs[0].blk) {
94f6ad2e32SAlexander Graf             val = SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP |
95f6ad2e32SAlexander Graf                   SATA_SCR_SSTATUS_SPD_GEN1 | SATA_SCR_SSTATUS_IPM_ACTIVE;
96f6ad2e32SAlexander Graf         } else {
97f6ad2e32SAlexander Graf             val = SATA_SCR_SSTATUS_DET_NODEV;
98f6ad2e32SAlexander Graf         }
99f6ad2e32SAlexander Graf         break;
100f6ad2e32SAlexander Graf     case PORT_SCR_CTL:
101f6ad2e32SAlexander Graf         val = pr->scr_ctl;
102f6ad2e32SAlexander Graf         break;
103f6ad2e32SAlexander Graf     case PORT_SCR_ERR:
104f6ad2e32SAlexander Graf         val = pr->scr_err;
105f6ad2e32SAlexander Graf         break;
106f6ad2e32SAlexander Graf     case PORT_SCR_ACT:
107f6ad2e32SAlexander Graf         val = pr->scr_act;
108f6ad2e32SAlexander Graf         break;
109f6ad2e32SAlexander Graf     case PORT_CMD_ISSUE:
110f6ad2e32SAlexander Graf         val = pr->cmd_issue;
111f6ad2e32SAlexander Graf         break;
112f6ad2e32SAlexander Graf     case PORT_RESERVED:
113f6ad2e32SAlexander Graf     default:
114f6ad2e32SAlexander Graf         val = 0;
115f6ad2e32SAlexander Graf     }
116f6ad2e32SAlexander Graf     DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
117f6ad2e32SAlexander Graf     return val;
118f6ad2e32SAlexander Graf 
119f6ad2e32SAlexander Graf }
120f6ad2e32SAlexander Graf 
121f6ad2e32SAlexander Graf static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
122f6ad2e32SAlexander Graf {
123bb639f82SAlistair Francis     DeviceState *dev_state = s->container;
124bb639f82SAlistair Francis     PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
125bb639f82SAlistair Francis                                                            TYPE_PCI_DEVICE);
126f6ad2e32SAlexander Graf 
127f6ad2e32SAlexander Graf     DPRINTF(0, "raise irq\n");
128f6ad2e32SAlexander Graf 
129bd164307SRob Herring     if (pci_dev && msi_enabled(pci_dev)) {
1300d3aea56SAndreas Färber         msi_notify(pci_dev, 0);
131f6ad2e32SAlexander Graf     } else {
132f6ad2e32SAlexander Graf         qemu_irq_raise(s->irq);
133f6ad2e32SAlexander Graf     }
134f6ad2e32SAlexander Graf }
135f6ad2e32SAlexander Graf 
136f6ad2e32SAlexander Graf static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
137f6ad2e32SAlexander Graf {
138bb639f82SAlistair Francis     DeviceState *dev_state = s->container;
139bb639f82SAlistair Francis     PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
140bb639f82SAlistair Francis                                                            TYPE_PCI_DEVICE);
141f6ad2e32SAlexander Graf 
142f6ad2e32SAlexander Graf     DPRINTF(0, "lower irq\n");
143f6ad2e32SAlexander Graf 
144bd164307SRob Herring     if (!pci_dev || !msi_enabled(pci_dev)) {
145f6ad2e32SAlexander Graf         qemu_irq_lower(s->irq);
146f6ad2e32SAlexander Graf     }
147f6ad2e32SAlexander Graf }
148f6ad2e32SAlexander Graf 
149f6ad2e32SAlexander Graf static void ahci_check_irq(AHCIState *s)
150f6ad2e32SAlexander Graf {
151f6ad2e32SAlexander Graf     int i;
152f6ad2e32SAlexander Graf 
153f6ad2e32SAlexander Graf     DPRINTF(-1, "check irq %#x\n", s->control_regs.irqstatus);
154f6ad2e32SAlexander Graf 
155b8676728SAlexander Graf     s->control_regs.irqstatus = 0;
1562c4b9d0eSAlexander Graf     for (i = 0; i < s->ports; i++) {
157f6ad2e32SAlexander Graf         AHCIPortRegs *pr = &s->dev[i].port_regs;
158f6ad2e32SAlexander Graf         if (pr->irq_stat & pr->irq_mask) {
159f6ad2e32SAlexander Graf             s->control_regs.irqstatus |= (1 << i);
160f6ad2e32SAlexander Graf         }
161f6ad2e32SAlexander Graf     }
162f6ad2e32SAlexander Graf 
163f6ad2e32SAlexander Graf     if (s->control_regs.irqstatus &&
164f6ad2e32SAlexander Graf         (s->control_regs.ghc & HOST_CTL_IRQ_EN)) {
165f6ad2e32SAlexander Graf             ahci_irq_raise(s, NULL);
166f6ad2e32SAlexander Graf     } else {
167f6ad2e32SAlexander Graf         ahci_irq_lower(s, NULL);
168f6ad2e32SAlexander Graf     }
169f6ad2e32SAlexander Graf }
170f6ad2e32SAlexander Graf 
171f6ad2e32SAlexander Graf static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d,
172f6ad2e32SAlexander Graf                              int irq_type)
173f6ad2e32SAlexander Graf {
174f6ad2e32SAlexander Graf     DPRINTF(d->port_no, "trigger irq %#x -> %x\n",
175f6ad2e32SAlexander Graf             irq_type, d->port_regs.irq_mask & irq_type);
176f6ad2e32SAlexander Graf 
177f6ad2e32SAlexander Graf     d->port_regs.irq_stat |= irq_type;
178f6ad2e32SAlexander Graf     ahci_check_irq(s);
179f6ad2e32SAlexander Graf }
180f6ad2e32SAlexander Graf 
1815a18e67dSLe Tan static void map_page(AddressSpace *as, uint8_t **ptr, uint64_t addr,
1825a18e67dSLe Tan                      uint32_t wanted)
183f6ad2e32SAlexander Graf {
184a8170e5eSAvi Kivity     hwaddr len = wanted;
185f6ad2e32SAlexander Graf 
186f6ad2e32SAlexander Graf     if (*ptr) {
1875a18e67dSLe Tan         dma_memory_unmap(as, *ptr, len, DMA_DIRECTION_FROM_DEVICE, len);
188f6ad2e32SAlexander Graf     }
189f6ad2e32SAlexander Graf 
1905a18e67dSLe Tan     *ptr = dma_memory_map(as, addr, &len, DMA_DIRECTION_FROM_DEVICE);
191f6ad2e32SAlexander Graf     if (len < wanted) {
1925a18e67dSLe Tan         dma_memory_unmap(as, *ptr, len, DMA_DIRECTION_FROM_DEVICE, len);
193f6ad2e32SAlexander Graf         *ptr = NULL;
194f6ad2e32SAlexander Graf     }
195f6ad2e32SAlexander Graf }
196f6ad2e32SAlexander Graf 
197cd6cb73bSJohn Snow /**
198cd6cb73bSJohn Snow  * Check the cmd register to see if we should start or stop
199cd6cb73bSJohn Snow  * the DMA or FIS RX engines.
200cd6cb73bSJohn Snow  *
201cd6cb73bSJohn Snow  * @ad: Device to engage.
202cd6cb73bSJohn Snow  * @allow_stop: Allow device to transition from started to stopped?
203cd6cb73bSJohn Snow  *   'no' is useful for migration post_load, which does not expect a transition.
204cd6cb73bSJohn Snow  *
205cd6cb73bSJohn Snow  * @return 0 on success, -1 on error.
206cd6cb73bSJohn Snow  */
207cd6cb73bSJohn Snow static int ahci_cond_start_engines(AHCIDevice *ad, bool allow_stop)
208cd6cb73bSJohn Snow {
209cd6cb73bSJohn Snow     AHCIPortRegs *pr = &ad->port_regs;
210cd6cb73bSJohn Snow 
211cd6cb73bSJohn Snow     if (pr->cmd & PORT_CMD_START) {
212cd6cb73bSJohn Snow         if (ahci_map_clb_address(ad)) {
213cd6cb73bSJohn Snow             pr->cmd |= PORT_CMD_LIST_ON;
214cd6cb73bSJohn Snow         } else {
215cd6cb73bSJohn Snow             error_report("AHCI: Failed to start DMA engine: "
216cd6cb73bSJohn Snow                          "bad command list buffer address");
217cd6cb73bSJohn Snow             return -1;
218cd6cb73bSJohn Snow         }
219cd6cb73bSJohn Snow     } else if (pr->cmd & PORT_CMD_LIST_ON) {
220cd6cb73bSJohn Snow         if (allow_stop) {
221cd6cb73bSJohn Snow             ahci_unmap_clb_address(ad);
222cd6cb73bSJohn Snow             pr->cmd = pr->cmd & ~(PORT_CMD_LIST_ON);
223cd6cb73bSJohn Snow         } else {
224cd6cb73bSJohn Snow             error_report("AHCI: DMA engine should be off, "
225cd6cb73bSJohn Snow                          "but appears to still be running");
226cd6cb73bSJohn Snow             return -1;
227cd6cb73bSJohn Snow         }
228cd6cb73bSJohn Snow     }
229cd6cb73bSJohn Snow 
230cd6cb73bSJohn Snow     if (pr->cmd & PORT_CMD_FIS_RX) {
231cd6cb73bSJohn Snow         if (ahci_map_fis_address(ad)) {
232cd6cb73bSJohn Snow             pr->cmd |= PORT_CMD_FIS_ON;
233cd6cb73bSJohn Snow         } else {
234cd6cb73bSJohn Snow             error_report("AHCI: Failed to start FIS receive engine: "
235cd6cb73bSJohn Snow                          "bad FIS receive buffer address");
236cd6cb73bSJohn Snow             return -1;
237cd6cb73bSJohn Snow         }
238cd6cb73bSJohn Snow     } else if (pr->cmd & PORT_CMD_FIS_ON) {
239cd6cb73bSJohn Snow         if (allow_stop) {
240cd6cb73bSJohn Snow             ahci_unmap_fis_address(ad);
241cd6cb73bSJohn Snow             pr->cmd = pr->cmd & ~(PORT_CMD_FIS_ON);
242cd6cb73bSJohn Snow         } else {
243cd6cb73bSJohn Snow             error_report("AHCI: FIS receive engine should be off, "
244cd6cb73bSJohn Snow                          "but appears to still be running");
245cd6cb73bSJohn Snow             return -1;
246cd6cb73bSJohn Snow         }
247cd6cb73bSJohn Snow     }
248cd6cb73bSJohn Snow 
249cd6cb73bSJohn Snow     return 0;
250cd6cb73bSJohn Snow }
251cd6cb73bSJohn Snow 
252f6ad2e32SAlexander Graf static void  ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
253f6ad2e32SAlexander Graf {
254f6ad2e32SAlexander Graf     AHCIPortRegs *pr = &s->dev[port].port_regs;
255f6ad2e32SAlexander Graf 
256f6ad2e32SAlexander Graf     DPRINTF(port, "offset: 0x%x val: 0x%x\n", offset, val);
257f6ad2e32SAlexander Graf     switch (offset) {
258f6ad2e32SAlexander Graf         case PORT_LST_ADDR:
259f6ad2e32SAlexander Graf             pr->lst_addr = val;
260f6ad2e32SAlexander Graf             break;
261f6ad2e32SAlexander Graf         case PORT_LST_ADDR_HI:
262f6ad2e32SAlexander Graf             pr->lst_addr_hi = val;
263f6ad2e32SAlexander Graf             break;
264f6ad2e32SAlexander Graf         case PORT_FIS_ADDR:
265f6ad2e32SAlexander Graf             pr->fis_addr = val;
266f6ad2e32SAlexander Graf             break;
267f6ad2e32SAlexander Graf         case PORT_FIS_ADDR_HI:
268f6ad2e32SAlexander Graf             pr->fis_addr_hi = val;
269f6ad2e32SAlexander Graf             break;
270f6ad2e32SAlexander Graf         case PORT_IRQ_STAT:
271f6ad2e32SAlexander Graf             pr->irq_stat &= ~val;
272b8676728SAlexander Graf             ahci_check_irq(s);
273f6ad2e32SAlexander Graf             break;
274f6ad2e32SAlexander Graf         case PORT_IRQ_MASK:
275f6ad2e32SAlexander Graf             pr->irq_mask = val & 0xfdc000ff;
276f6ad2e32SAlexander Graf             ahci_check_irq(s);
277f6ad2e32SAlexander Graf             break;
278f6ad2e32SAlexander Graf         case PORT_CMD:
279fc3d8e11SJohn Snow             /* Block any Read-only fields from being set;
28009b61db7SStefan Fritsch              * including LIST_ON and FIS_ON.
28109b61db7SStefan Fritsch              * The spec requires to set ICC bits to zero after the ICC change
28209b61db7SStefan Fritsch              * is done. We don't support ICC state changes, therefore always
28309b61db7SStefan Fritsch              * force the ICC bits to zero.
28409b61db7SStefan Fritsch              */
28509b61db7SStefan Fritsch             pr->cmd = (pr->cmd & PORT_CMD_RO_MASK) |
28609b61db7SStefan Fritsch                       (val & ~(PORT_CMD_RO_MASK|PORT_CMD_ICC_MASK));
287f6ad2e32SAlexander Graf 
288cd6cb73bSJohn Snow             /* Check FIS RX and CLB engines, allow transition to false: */
289cd6cb73bSJohn Snow             ahci_cond_start_engines(&s->dev[port], true);
290f6ad2e32SAlexander Graf 
29187e62065SAlexander Graf             /* XXX usually the FIS would be pending on the bus here and
29287e62065SAlexander Graf                    issuing deferred until the OS enables FIS receival.
29387e62065SAlexander Graf                    Instead, we only submit it once - which works in most
29487e62065SAlexander Graf                    cases, but is a hack. */
29587e62065SAlexander Graf             if ((pr->cmd & PORT_CMD_FIS_ON) &&
29687e62065SAlexander Graf                 !s->dev[port].init_d2h_sent) {
29787e62065SAlexander Graf                 ahci_init_d2h(&s->dev[port]);
29887e62065SAlexander Graf             }
29987e62065SAlexander Graf 
300f6ad2e32SAlexander Graf             check_cmd(s, port);
301f6ad2e32SAlexander Graf             break;
302f6ad2e32SAlexander Graf         case PORT_TFDATA:
303fac7aa7fSJohn Snow             /* Read Only. */
304f6ad2e32SAlexander Graf             break;
305f6ad2e32SAlexander Graf         case PORT_SIG:
306fac7aa7fSJohn Snow             /* Read Only */
307f6ad2e32SAlexander Graf             break;
308f6ad2e32SAlexander Graf         case PORT_SCR_STAT:
309fac7aa7fSJohn Snow             /* Read Only */
310f6ad2e32SAlexander Graf             break;
311f6ad2e32SAlexander Graf         case PORT_SCR_CTL:
312f6ad2e32SAlexander Graf             if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) &&
313f6ad2e32SAlexander Graf                 ((val & AHCI_SCR_SCTL_DET) == 0)) {
314f6ad2e32SAlexander Graf                 ahci_reset_port(s, port);
315f6ad2e32SAlexander Graf             }
316f6ad2e32SAlexander Graf             pr->scr_ctl = val;
317f6ad2e32SAlexander Graf             break;
318f6ad2e32SAlexander Graf         case PORT_SCR_ERR:
319f6ad2e32SAlexander Graf             pr->scr_err &= ~val;
320f6ad2e32SAlexander Graf             break;
321f6ad2e32SAlexander Graf         case PORT_SCR_ACT:
322f6ad2e32SAlexander Graf             /* RW1 */
323f6ad2e32SAlexander Graf             pr->scr_act |= val;
324f6ad2e32SAlexander Graf             break;
325f6ad2e32SAlexander Graf         case PORT_CMD_ISSUE:
326f6ad2e32SAlexander Graf             pr->cmd_issue |= val;
327f6ad2e32SAlexander Graf             check_cmd(s, port);
328f6ad2e32SAlexander Graf             break;
329f6ad2e32SAlexander Graf         default:
330f6ad2e32SAlexander Graf             break;
331f6ad2e32SAlexander Graf     }
332f6ad2e32SAlexander Graf }
333f6ad2e32SAlexander Graf 
334e9ebb2f7SJohn Snow static uint64_t ahci_mem_read_32(void *opaque, hwaddr addr)
335f6ad2e32SAlexander Graf {
33667e576c2SAvi Kivity     AHCIState *s = opaque;
337f6ad2e32SAlexander Graf     uint32_t val = 0;
338f6ad2e32SAlexander Graf 
339f6ad2e32SAlexander Graf     if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
340f6ad2e32SAlexander Graf         switch (addr) {
341f6ad2e32SAlexander Graf         case HOST_CAP:
342f6ad2e32SAlexander Graf             val = s->control_regs.cap;
343f6ad2e32SAlexander Graf             break;
344f6ad2e32SAlexander Graf         case HOST_CTL:
345f6ad2e32SAlexander Graf             val = s->control_regs.ghc;
346f6ad2e32SAlexander Graf             break;
347f6ad2e32SAlexander Graf         case HOST_IRQ_STAT:
348f6ad2e32SAlexander Graf             val = s->control_regs.irqstatus;
349f6ad2e32SAlexander Graf             break;
350f6ad2e32SAlexander Graf         case HOST_PORTS_IMPL:
351f6ad2e32SAlexander Graf             val = s->control_regs.impl;
352f6ad2e32SAlexander Graf             break;
353f6ad2e32SAlexander Graf         case HOST_VERSION:
354f6ad2e32SAlexander Graf             val = s->control_regs.version;
355f6ad2e32SAlexander Graf             break;
356f6ad2e32SAlexander Graf         }
357f6ad2e32SAlexander Graf 
358f6ad2e32SAlexander Graf         DPRINTF(-1, "(addr 0x%08X), val 0x%08X\n", (unsigned) addr, val);
359f6ad2e32SAlexander Graf     } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
3602c4b9d0eSAlexander Graf                (addr < (AHCI_PORT_REGS_START_ADDR +
3612c4b9d0eSAlexander Graf                 (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
362f6ad2e32SAlexander Graf         val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
363f6ad2e32SAlexander Graf                              addr & AHCI_PORT_ADDR_OFFSET_MASK);
364f6ad2e32SAlexander Graf     }
365f6ad2e32SAlexander Graf 
366f6ad2e32SAlexander Graf     return val;
367f6ad2e32SAlexander Graf }
368f6ad2e32SAlexander Graf 
369f6ad2e32SAlexander Graf 
370e9ebb2f7SJohn Snow /**
371e9ebb2f7SJohn Snow  * AHCI 1.3 section 3 ("HBA Memory Registers")
372e9ebb2f7SJohn Snow  * Support unaligned 8/16/32 bit reads, and 64 bit aligned reads.
373e9ebb2f7SJohn Snow  * Caller is responsible for masking unwanted higher order bytes.
374e9ebb2f7SJohn Snow  */
375e9ebb2f7SJohn Snow static uint64_t ahci_mem_read(void *opaque, hwaddr addr, unsigned size)
376e9ebb2f7SJohn Snow {
377e9ebb2f7SJohn Snow     hwaddr aligned = addr & ~0x3;
378e9ebb2f7SJohn Snow     int ofst = addr - aligned;
379e9ebb2f7SJohn Snow     uint64_t lo = ahci_mem_read_32(opaque, aligned);
380e9ebb2f7SJohn Snow     uint64_t hi;
381e9ebb2f7SJohn Snow 
382e9ebb2f7SJohn Snow     /* if < 8 byte read does not cross 4 byte boundary */
383e9ebb2f7SJohn Snow     if (ofst + size <= 4) {
384e9ebb2f7SJohn Snow         return lo >> (ofst * 8);
385e9ebb2f7SJohn Snow     }
386e9ebb2f7SJohn Snow     g_assert_cmpint(size, >, 1);
387e9ebb2f7SJohn Snow 
388e9ebb2f7SJohn Snow     /* If the 64bit read is unaligned, we will produce undefined
389e9ebb2f7SJohn Snow      * results. AHCI does not support unaligned 64bit reads. */
390e9ebb2f7SJohn Snow     hi = ahci_mem_read_32(opaque, aligned + 4);
391e9ebb2f7SJohn Snow     return (hi << 32 | lo) >> (ofst * 8);
392e9ebb2f7SJohn Snow }
393e9ebb2f7SJohn Snow 
394f6ad2e32SAlexander Graf 
395a8170e5eSAvi Kivity static void ahci_mem_write(void *opaque, hwaddr addr,
39667e576c2SAvi Kivity                            uint64_t val, unsigned size)
397f6ad2e32SAlexander Graf {
39867e576c2SAvi Kivity     AHCIState *s = opaque;
399f6ad2e32SAlexander Graf 
400f6ad2e32SAlexander Graf     /* Only aligned reads are allowed on AHCI */
401f6ad2e32SAlexander Graf     if (addr & 3) {
402f6ad2e32SAlexander Graf         fprintf(stderr, "ahci: Mis-aligned write to addr 0x"
403f6ad2e32SAlexander Graf                 TARGET_FMT_plx "\n", addr);
404f6ad2e32SAlexander Graf         return;
405f6ad2e32SAlexander Graf     }
406f6ad2e32SAlexander Graf 
407f6ad2e32SAlexander Graf     if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
4083899edf7SMax Filippov         DPRINTF(-1, "(addr 0x%08X), val 0x%08"PRIX64"\n", (unsigned) addr, val);
409f6ad2e32SAlexander Graf 
410f6ad2e32SAlexander Graf         switch (addr) {
411f6ad2e32SAlexander Graf             case HOST_CAP: /* R/WO, RO */
412f6ad2e32SAlexander Graf                 /* FIXME handle R/WO */
413f6ad2e32SAlexander Graf                 break;
414f6ad2e32SAlexander Graf             case HOST_CTL: /* R/W */
415f6ad2e32SAlexander Graf                 if (val & HOST_CTL_RESET) {
416f6ad2e32SAlexander Graf                     DPRINTF(-1, "HBA Reset\n");
4178ab60a07SJan Kiszka                     ahci_reset(s);
418f6ad2e32SAlexander Graf                 } else {
419f6ad2e32SAlexander Graf                     s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
420f6ad2e32SAlexander Graf                     ahci_check_irq(s);
421f6ad2e32SAlexander Graf                 }
422f6ad2e32SAlexander Graf                 break;
423f6ad2e32SAlexander Graf             case HOST_IRQ_STAT: /* R/WC, RO */
424f6ad2e32SAlexander Graf                 s->control_regs.irqstatus &= ~val;
425f6ad2e32SAlexander Graf                 ahci_check_irq(s);
426f6ad2e32SAlexander Graf                 break;
427f6ad2e32SAlexander Graf             case HOST_PORTS_IMPL: /* R/WO, RO */
428f6ad2e32SAlexander Graf                 /* FIXME handle R/WO */
429f6ad2e32SAlexander Graf                 break;
430f6ad2e32SAlexander Graf             case HOST_VERSION: /* RO */
431f6ad2e32SAlexander Graf                 /* FIXME report write? */
432f6ad2e32SAlexander Graf                 break;
433f6ad2e32SAlexander Graf             default:
434f6ad2e32SAlexander Graf                 DPRINTF(-1, "write to unknown register 0x%x\n", (unsigned)addr);
435f6ad2e32SAlexander Graf         }
436f6ad2e32SAlexander Graf     } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
4372c4b9d0eSAlexander Graf                (addr < (AHCI_PORT_REGS_START_ADDR +
4382c4b9d0eSAlexander Graf                 (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
439f6ad2e32SAlexander Graf         ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
440f6ad2e32SAlexander Graf                         addr & AHCI_PORT_ADDR_OFFSET_MASK, val);
441f6ad2e32SAlexander Graf     }
442f6ad2e32SAlexander Graf 
443f6ad2e32SAlexander Graf }
444f6ad2e32SAlexander Graf 
445a348f108SStefan Weil static const MemoryRegionOps ahci_mem_ops = {
44667e576c2SAvi Kivity     .read = ahci_mem_read,
44767e576c2SAvi Kivity     .write = ahci_mem_write,
44867e576c2SAvi Kivity     .endianness = DEVICE_LITTLE_ENDIAN,
449f6ad2e32SAlexander Graf };
450f6ad2e32SAlexander Graf 
451a8170e5eSAvi Kivity static uint64_t ahci_idp_read(void *opaque, hwaddr addr,
452465f1ab1SDaniel Verkamp                               unsigned size)
453465f1ab1SDaniel Verkamp {
454465f1ab1SDaniel Verkamp     AHCIState *s = opaque;
455465f1ab1SDaniel Verkamp 
456465f1ab1SDaniel Verkamp     if (addr == s->idp_offset) {
457465f1ab1SDaniel Verkamp         /* index register */
458465f1ab1SDaniel Verkamp         return s->idp_index;
459465f1ab1SDaniel Verkamp     } else if (addr == s->idp_offset + 4) {
460465f1ab1SDaniel Verkamp         /* data register - do memory read at location selected by index */
461465f1ab1SDaniel Verkamp         return ahci_mem_read(opaque, s->idp_index, size);
462465f1ab1SDaniel Verkamp     } else {
463465f1ab1SDaniel Verkamp         return 0;
464465f1ab1SDaniel Verkamp     }
465465f1ab1SDaniel Verkamp }
466465f1ab1SDaniel Verkamp 
467a8170e5eSAvi Kivity static void ahci_idp_write(void *opaque, hwaddr addr,
468465f1ab1SDaniel Verkamp                            uint64_t val, unsigned size)
469465f1ab1SDaniel Verkamp {
470465f1ab1SDaniel Verkamp     AHCIState *s = opaque;
471465f1ab1SDaniel Verkamp 
472465f1ab1SDaniel Verkamp     if (addr == s->idp_offset) {
473465f1ab1SDaniel Verkamp         /* index register - mask off reserved bits */
474465f1ab1SDaniel Verkamp         s->idp_index = (uint32_t)val & ((AHCI_MEM_BAR_SIZE - 1) & ~3);
475465f1ab1SDaniel Verkamp     } else if (addr == s->idp_offset + 4) {
476465f1ab1SDaniel Verkamp         /* data register - do memory write at location selected by index */
477465f1ab1SDaniel Verkamp         ahci_mem_write(opaque, s->idp_index, val, size);
478465f1ab1SDaniel Verkamp     }
479465f1ab1SDaniel Verkamp }
480465f1ab1SDaniel Verkamp 
481a348f108SStefan Weil static const MemoryRegionOps ahci_idp_ops = {
482465f1ab1SDaniel Verkamp     .read = ahci_idp_read,
483465f1ab1SDaniel Verkamp     .write = ahci_idp_write,
484465f1ab1SDaniel Verkamp     .endianness = DEVICE_LITTLE_ENDIAN,
485465f1ab1SDaniel Verkamp };
486465f1ab1SDaniel Verkamp 
487465f1ab1SDaniel Verkamp 
488f6ad2e32SAlexander Graf static void ahci_reg_init(AHCIState *s)
489f6ad2e32SAlexander Graf {
490f6ad2e32SAlexander Graf     int i;
491f6ad2e32SAlexander Graf 
4922c4b9d0eSAlexander Graf     s->control_regs.cap = (s->ports - 1) |
493f6ad2e32SAlexander Graf                           (AHCI_NUM_COMMAND_SLOTS << 8) |
494f6ad2e32SAlexander Graf                           (AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) |
495f6ad2e32SAlexander Graf                           HOST_CAP_NCQ | HOST_CAP_AHCI;
496f6ad2e32SAlexander Graf 
4972c4b9d0eSAlexander Graf     s->control_regs.impl = (1 << s->ports) - 1;
498f6ad2e32SAlexander Graf 
499f6ad2e32SAlexander Graf     s->control_regs.version = AHCI_VERSION_1_0;
500f6ad2e32SAlexander Graf 
5012c4b9d0eSAlexander Graf     for (i = 0; i < s->ports; i++) {
502f6ad2e32SAlexander Graf         s->dev[i].port_state = STATE_RUN;
503f6ad2e32SAlexander Graf     }
504f6ad2e32SAlexander Graf }
505f6ad2e32SAlexander Graf 
506f6ad2e32SAlexander Graf static void check_cmd(AHCIState *s, int port)
507f6ad2e32SAlexander Graf {
508f6ad2e32SAlexander Graf     AHCIPortRegs *pr = &s->dev[port].port_regs;
5099364384dSJohn Snow     uint8_t slot;
510f6ad2e32SAlexander Graf 
511f6ad2e32SAlexander Graf     if ((pr->cmd & PORT_CMD_START) && pr->cmd_issue) {
512f6ad2e32SAlexander Graf         for (slot = 0; (slot < 32) && pr->cmd_issue; slot++) {
513ee25595fSPeter Maydell             if ((pr->cmd_issue & (1U << slot)) &&
514f6ad2e32SAlexander Graf                 !handle_cmd(s, port, slot)) {
515ee25595fSPeter Maydell                 pr->cmd_issue &= ~(1U << slot);
516f6ad2e32SAlexander Graf             }
517f6ad2e32SAlexander Graf         }
518f6ad2e32SAlexander Graf     }
519f6ad2e32SAlexander Graf }
520f6ad2e32SAlexander Graf 
521f6ad2e32SAlexander Graf static void ahci_check_cmd_bh(void *opaque)
522f6ad2e32SAlexander Graf {
523f6ad2e32SAlexander Graf     AHCIDevice *ad = opaque;
524f6ad2e32SAlexander Graf 
525f6ad2e32SAlexander Graf     qemu_bh_delete(ad->check_bh);
526f6ad2e32SAlexander Graf     ad->check_bh = NULL;
527f6ad2e32SAlexander Graf 
528f6ad2e32SAlexander Graf     if ((ad->busy_slot != -1) &&
529f6ad2e32SAlexander Graf         !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
530f6ad2e32SAlexander Graf         /* no longer busy */
531f6ad2e32SAlexander Graf         ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
532f6ad2e32SAlexander Graf         ad->busy_slot = -1;
533f6ad2e32SAlexander Graf     }
534f6ad2e32SAlexander Graf 
535f6ad2e32SAlexander Graf     check_cmd(ad->hba, ad->port_no);
536f6ad2e32SAlexander Graf }
537f6ad2e32SAlexander Graf 
53887e62065SAlexander Graf static void ahci_init_d2h(AHCIDevice *ad)
53987e62065SAlexander Graf {
54087e62065SAlexander Graf     IDEState *ide_state = &ad->port.ifs[0];
54133a983cbSJohn Snow     AHCIPortRegs *pr = &ad->port_regs;
54287e62065SAlexander Graf 
543e47f9eb1SJohn Snow     if (ad->init_d2h_sent) {
544e47f9eb1SJohn Snow         return;
545e47f9eb1SJohn Snow     }
546e47f9eb1SJohn Snow 
547e47f9eb1SJohn Snow     if (ahci_write_fis_d2h(ad)) {
548e47f9eb1SJohn Snow         ad->init_d2h_sent = true;
54933a983cbSJohn Snow         /* We're emulating receiving the first Reg H2D Fis from the device;
55033a983cbSJohn Snow          * Update the SIG register, but otherwise proceed as normal. */
551*40fe17beSPeter Maydell         pr->sig = ((uint32_t)ide_state->hcyl << 24) |
55233a983cbSJohn Snow             (ide_state->lcyl << 16) |
55333a983cbSJohn Snow             (ide_state->sector << 8) |
55433a983cbSJohn Snow             (ide_state->nsector & 0xFF);
555e47f9eb1SJohn Snow     }
55687e62065SAlexander Graf }
55787e62065SAlexander Graf 
55833a983cbSJohn Snow static void ahci_set_signature(AHCIDevice *ad, uint32_t sig)
55933a983cbSJohn Snow {
56033a983cbSJohn Snow     IDEState *s = &ad->port.ifs[0];
56133a983cbSJohn Snow     s->hcyl = sig >> 24 & 0xFF;
56233a983cbSJohn Snow     s->lcyl = sig >> 16 & 0xFF;
56333a983cbSJohn Snow     s->sector = sig >> 8 & 0xFF;
56433a983cbSJohn Snow     s->nsector = sig & 0xFF;
56533a983cbSJohn Snow 
56633a983cbSJohn Snow     DPRINTF(ad->port_no, "set hcyl:lcyl:sect:nsect = 0x%08x\n", sig);
56733a983cbSJohn Snow }
56833a983cbSJohn Snow 
569f6ad2e32SAlexander Graf static void ahci_reset_port(AHCIState *s, int port)
570f6ad2e32SAlexander Graf {
571f6ad2e32SAlexander Graf     AHCIDevice *d = &s->dev[port];
572f6ad2e32SAlexander Graf     AHCIPortRegs *pr = &d->port_regs;
573f6ad2e32SAlexander Graf     IDEState *ide_state = &d->port.ifs[0];
574f6ad2e32SAlexander Graf     int i;
575f6ad2e32SAlexander Graf 
576f6ad2e32SAlexander Graf     DPRINTF(port, "reset port\n");
577f6ad2e32SAlexander Graf 
578f6ad2e32SAlexander Graf     ide_bus_reset(&d->port);
579f6ad2e32SAlexander Graf     ide_state->ncq_queues = AHCI_MAX_CMDS;
580f6ad2e32SAlexander Graf 
581f6ad2e32SAlexander Graf     pr->scr_stat = 0;
582f6ad2e32SAlexander Graf     pr->scr_err = 0;
583f6ad2e32SAlexander Graf     pr->scr_act = 0;
584fac7aa7fSJohn Snow     pr->tfdata = 0x7F;
585fac7aa7fSJohn Snow     pr->sig = 0xFFFFFFFF;
586f6ad2e32SAlexander Graf     d->busy_slot = -1;
5874ac557c8SKevin Wolf     d->init_d2h_sent = false;
588f6ad2e32SAlexander Graf 
589f6ad2e32SAlexander Graf     ide_state = &s->dev[port].port.ifs[0];
5904be74634SMarkus Armbruster     if (!ide_state->blk) {
591f6ad2e32SAlexander Graf         return;
592f6ad2e32SAlexander Graf     }
593f6ad2e32SAlexander Graf 
594f6ad2e32SAlexander Graf     /* reset ncq queue */
595f6ad2e32SAlexander Graf     for (i = 0; i < AHCI_MAX_CMDS; i++) {
596f6ad2e32SAlexander Graf         NCQTransferState *ncq_tfs = &s->dev[port].ncq_tfs[i];
5977c03a691SJohn Snow         ncq_tfs->halt = false;
598f6ad2e32SAlexander Graf         if (!ncq_tfs->used) {
599f6ad2e32SAlexander Graf             continue;
600f6ad2e32SAlexander Graf         }
601f6ad2e32SAlexander Graf 
602f6ad2e32SAlexander Graf         if (ncq_tfs->aiocb) {
6034be74634SMarkus Armbruster             blk_aio_cancel(ncq_tfs->aiocb);
604f6ad2e32SAlexander Graf             ncq_tfs->aiocb = NULL;
605f6ad2e32SAlexander Graf         }
606f6ad2e32SAlexander Graf 
6074be74634SMarkus Armbruster         /* Maybe we just finished the request thanks to blk_aio_cancel() */
608c9b308d2SAlexander Graf         if (!ncq_tfs->used) {
609c9b308d2SAlexander Graf             continue;
610c9b308d2SAlexander Graf         }
611c9b308d2SAlexander Graf 
612f6ad2e32SAlexander Graf         qemu_sglist_destroy(&ncq_tfs->sglist);
613f6ad2e32SAlexander Graf         ncq_tfs->used = 0;
614f6ad2e32SAlexander Graf     }
615f6ad2e32SAlexander Graf 
616f6ad2e32SAlexander Graf     s->dev[port].port_state = STATE_RUN;
617f91a0aa3SJohn Snow     if (ide_state->drive_kind == IDE_CD) {
61833a983cbSJohn Snow         ahci_set_signature(d, SATA_SIGNATURE_CDROM);\
619f6ad2e32SAlexander Graf         ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT;
620f6ad2e32SAlexander Graf     } else {
62133a983cbSJohn Snow         ahci_set_signature(d, SATA_SIGNATURE_DISK);
622f6ad2e32SAlexander Graf         ide_state->status = SEEK_STAT | WRERR_STAT;
623f6ad2e32SAlexander Graf     }
624f6ad2e32SAlexander Graf 
625f6ad2e32SAlexander Graf     ide_state->error = 1;
62687e62065SAlexander Graf     ahci_init_d2h(d);
627f6ad2e32SAlexander Graf }
628f6ad2e32SAlexander Graf 
629f6ad2e32SAlexander Graf static void debug_print_fis(uint8_t *fis, int cmd_len)
630f6ad2e32SAlexander Graf {
631192cf55cSStefan Hajnoczi #if DEBUG_AHCI
632f6ad2e32SAlexander Graf     int i;
633f6ad2e32SAlexander Graf 
634f6ad2e32SAlexander Graf     fprintf(stderr, "fis:");
635f6ad2e32SAlexander Graf     for (i = 0; i < cmd_len; i++) {
636f6ad2e32SAlexander Graf         if ((i & 0xf) == 0) {
637f6ad2e32SAlexander Graf             fprintf(stderr, "\n%02x:",i);
638f6ad2e32SAlexander Graf         }
639f6ad2e32SAlexander Graf         fprintf(stderr, "%02x ",fis[i]);
640f6ad2e32SAlexander Graf     }
641f6ad2e32SAlexander Graf     fprintf(stderr, "\n");
642f6ad2e32SAlexander Graf #endif
643f6ad2e32SAlexander Graf }
644f6ad2e32SAlexander Graf 
645a13ab5a3SJohn Snow static bool ahci_map_fis_address(AHCIDevice *ad)
646a13ab5a3SJohn Snow {
647a13ab5a3SJohn Snow     AHCIPortRegs *pr = &ad->port_regs;
648a13ab5a3SJohn Snow     map_page(ad->hba->as, &ad->res_fis,
649a13ab5a3SJohn Snow              ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
650a13ab5a3SJohn Snow     return ad->res_fis != NULL;
651a13ab5a3SJohn Snow }
652a13ab5a3SJohn Snow 
653fc3d8e11SJohn Snow static void ahci_unmap_fis_address(AHCIDevice *ad)
654fc3d8e11SJohn Snow {
655fc3d8e11SJohn Snow     dma_memory_unmap(ad->hba->as, ad->res_fis, 256,
656fc3d8e11SJohn Snow                      DMA_DIRECTION_FROM_DEVICE, 256);
657fc3d8e11SJohn Snow     ad->res_fis = NULL;
658fc3d8e11SJohn Snow }
659fc3d8e11SJohn Snow 
660a13ab5a3SJohn Snow static bool ahci_map_clb_address(AHCIDevice *ad)
661a13ab5a3SJohn Snow {
662a13ab5a3SJohn Snow     AHCIPortRegs *pr = &ad->port_regs;
663a13ab5a3SJohn Snow     ad->cur_cmd = NULL;
664a13ab5a3SJohn Snow     map_page(ad->hba->as, &ad->lst,
665a13ab5a3SJohn Snow              ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
666a13ab5a3SJohn Snow     return ad->lst != NULL;
667a13ab5a3SJohn Snow }
668a13ab5a3SJohn Snow 
669fc3d8e11SJohn Snow static void ahci_unmap_clb_address(AHCIDevice *ad)
670fc3d8e11SJohn Snow {
671fc3d8e11SJohn Snow     dma_memory_unmap(ad->hba->as, ad->lst, 1024,
672fc3d8e11SJohn Snow                      DMA_DIRECTION_FROM_DEVICE, 1024);
673fc3d8e11SJohn Snow     ad->lst = NULL;
674fc3d8e11SJohn Snow }
675fc3d8e11SJohn Snow 
6767c649ac5SJohn Snow static void ahci_write_fis_sdb(AHCIState *s, NCQTransferState *ncq_tfs)
677f6ad2e32SAlexander Graf {
6787c649ac5SJohn Snow     AHCIDevice *ad = ncq_tfs->drive;
679fac7aa7fSJohn Snow     AHCIPortRegs *pr = &ad->port_regs;
680f6ad2e32SAlexander Graf     IDEState *ide_state;
68154a7f8f3SJohn Snow     SDBFIS *sdb_fis;
682f6ad2e32SAlexander Graf 
6837c649ac5SJohn Snow     if (!ad->res_fis ||
684f6ad2e32SAlexander Graf         !(pr->cmd & PORT_CMD_FIS_RX)) {
685f6ad2e32SAlexander Graf         return;
686f6ad2e32SAlexander Graf     }
687f6ad2e32SAlexander Graf 
68854a7f8f3SJohn Snow     sdb_fis = (SDBFIS *)&ad->res_fis[RES_FIS_SDBFIS];
689fac7aa7fSJohn Snow     ide_state = &ad->port.ifs[0];
690f6ad2e32SAlexander Graf 
69117fcb74aSStefan Hajnoczi     sdb_fis->type = SATA_FIS_TYPE_SDB;
69254a7f8f3SJohn Snow     /* Interrupt pending & Notification bit */
6937c649ac5SJohn Snow     sdb_fis->flags = 0x40; /* Interrupt bit, always 1 for NCQ */
69454a7f8f3SJohn Snow     sdb_fis->status = ide_state->status & 0x77;
69554a7f8f3SJohn Snow     sdb_fis->error = ide_state->error;
69654a7f8f3SJohn Snow     /* update SAct field in SDB_FIS */
69754a7f8f3SJohn Snow     sdb_fis->payload = cpu_to_le32(ad->finished);
698f6ad2e32SAlexander Graf 
699fac7aa7fSJohn Snow     /* Update shadow registers (except BSY 0x80 and DRQ 0x08) */
700fac7aa7fSJohn Snow     pr->tfdata = (ad->port.ifs[0].error << 8) |
701fac7aa7fSJohn Snow         (ad->port.ifs[0].status & 0x77) |
702fac7aa7fSJohn Snow         (pr->tfdata & 0x88);
7037c649ac5SJohn Snow     pr->scr_act &= ~ad->finished;
7047c649ac5SJohn Snow     ad->finished = 0;
705fac7aa7fSJohn Snow 
7067c649ac5SJohn Snow     /* Trigger IRQ if interrupt bit is set (which currently, it always is) */
7077c649ac5SJohn Snow     if (sdb_fis->flags & 0x40) {
708fac7aa7fSJohn Snow         ahci_trigger_irq(s, ad, PORT_IRQ_SDB_FIS);
709f6ad2e32SAlexander Graf     }
7107c649ac5SJohn Snow }
711f6ad2e32SAlexander Graf 
71208841520SPaolo Bonzini static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
71308841520SPaolo Bonzini {
71408841520SPaolo Bonzini     AHCIPortRegs *pr = &ad->port_regs;
715dd628221SJohn Snow     uint8_t *pio_fis;
7167b8bad1bSJohn Snow     IDEState *s = &ad->port.ifs[0];
71708841520SPaolo Bonzini 
71808841520SPaolo Bonzini     if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
71908841520SPaolo Bonzini         return;
72008841520SPaolo Bonzini     }
72108841520SPaolo Bonzini 
72208841520SPaolo Bonzini     pio_fis = &ad->res_fis[RES_FIS_PSFIS];
72308841520SPaolo Bonzini 
72417fcb74aSStefan Hajnoczi     pio_fis[0] = SATA_FIS_TYPE_PIO_SETUP;
72508841520SPaolo Bonzini     pio_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
7267b8bad1bSJohn Snow     pio_fis[2] = s->status;
7277b8bad1bSJohn Snow     pio_fis[3] = s->error;
72808841520SPaolo Bonzini 
7297b8bad1bSJohn Snow     pio_fis[4] = s->sector;
7307b8bad1bSJohn Snow     pio_fis[5] = s->lcyl;
7317b8bad1bSJohn Snow     pio_fis[6] = s->hcyl;
7327b8bad1bSJohn Snow     pio_fis[7] = s->select;
7337b8bad1bSJohn Snow     pio_fis[8] = s->hob_sector;
7347b8bad1bSJohn Snow     pio_fis[9] = s->hob_lcyl;
7357b8bad1bSJohn Snow     pio_fis[10] = s->hob_hcyl;
7367b8bad1bSJohn Snow     pio_fis[11] = 0;
737dd628221SJohn Snow     pio_fis[12] = s->nsector & 0xFF;
738dd628221SJohn Snow     pio_fis[13] = (s->nsector >> 8) & 0xFF;
73908841520SPaolo Bonzini     pio_fis[14] = 0;
7407b8bad1bSJohn Snow     pio_fis[15] = s->status;
74108841520SPaolo Bonzini     pio_fis[16] = len & 255;
74208841520SPaolo Bonzini     pio_fis[17] = len >> 8;
74308841520SPaolo Bonzini     pio_fis[18] = 0;
74408841520SPaolo Bonzini     pio_fis[19] = 0;
74508841520SPaolo Bonzini 
746fac7aa7fSJohn Snow     /* Update shadow registers: */
747fac7aa7fSJohn Snow     pr->tfdata = (ad->port.ifs[0].error << 8) |
748fac7aa7fSJohn Snow         ad->port.ifs[0].status;
749fac7aa7fSJohn Snow 
75008841520SPaolo Bonzini     if (pio_fis[2] & ERR_STAT) {
75108841520SPaolo Bonzini         ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR);
75208841520SPaolo Bonzini     }
75308841520SPaolo Bonzini 
75408841520SPaolo Bonzini     ahci_trigger_irq(ad->hba, ad, PORT_IRQ_PIOS_FIS);
75508841520SPaolo Bonzini }
75608841520SPaolo Bonzini 
757e47f9eb1SJohn Snow static bool ahci_write_fis_d2h(AHCIDevice *ad)
758f6ad2e32SAlexander Graf {
759f6ad2e32SAlexander Graf     AHCIPortRegs *pr = &ad->port_regs;
760f6ad2e32SAlexander Graf     uint8_t *d2h_fis;
761f6ad2e32SAlexander Graf     int i;
7627b8bad1bSJohn Snow     IDEState *s = &ad->port.ifs[0];
763f6ad2e32SAlexander Graf 
764f6ad2e32SAlexander Graf     if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
765e47f9eb1SJohn Snow         return false;
766f6ad2e32SAlexander Graf     }
767f6ad2e32SAlexander Graf 
768f6ad2e32SAlexander Graf     d2h_fis = &ad->res_fis[RES_FIS_RFIS];
769f6ad2e32SAlexander Graf 
77017fcb74aSStefan Hajnoczi     d2h_fis[0] = SATA_FIS_TYPE_REGISTER_D2H;
771f6ad2e32SAlexander Graf     d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
7727b8bad1bSJohn Snow     d2h_fis[2] = s->status;
7737b8bad1bSJohn Snow     d2h_fis[3] = s->error;
774f6ad2e32SAlexander Graf 
7757b8bad1bSJohn Snow     d2h_fis[4] = s->sector;
7767b8bad1bSJohn Snow     d2h_fis[5] = s->lcyl;
7777b8bad1bSJohn Snow     d2h_fis[6] = s->hcyl;
7787b8bad1bSJohn Snow     d2h_fis[7] = s->select;
7797b8bad1bSJohn Snow     d2h_fis[8] = s->hob_sector;
7807b8bad1bSJohn Snow     d2h_fis[9] = s->hob_lcyl;
7817b8bad1bSJohn Snow     d2h_fis[10] = s->hob_hcyl;
7827b8bad1bSJohn Snow     d2h_fis[11] = 0;
783dd628221SJohn Snow     d2h_fis[12] = s->nsector & 0xFF;
784dd628221SJohn Snow     d2h_fis[13] = (s->nsector >> 8) & 0xFF;
7854bb9c939SDaniel Verkamp     for (i = 14; i < 20; i++) {
786f6ad2e32SAlexander Graf         d2h_fis[i] = 0;
787f6ad2e32SAlexander Graf     }
788f6ad2e32SAlexander Graf 
789fac7aa7fSJohn Snow     /* Update shadow registers: */
790fac7aa7fSJohn Snow     pr->tfdata = (ad->port.ifs[0].error << 8) |
791fac7aa7fSJohn Snow         ad->port.ifs[0].status;
792fac7aa7fSJohn Snow 
793f6ad2e32SAlexander Graf     if (d2h_fis[2] & ERR_STAT) {
7941f88f773SPaolo Bonzini         ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR);
795f6ad2e32SAlexander Graf     }
796f6ad2e32SAlexander Graf 
797f6ad2e32SAlexander Graf     ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
798e47f9eb1SJohn Snow     return true;
799f6ad2e32SAlexander Graf }
800f6ad2e32SAlexander Graf 
801d02f8adcSReza Jelveh static int prdt_tbl_entry_size(const AHCI_SG *tbl)
802d02f8adcSReza Jelveh {
803a718978eSJohn Snow     /* flags_size is zero-based */
804d02f8adcSReza Jelveh     return (le32_to_cpu(tbl->flags_size) & AHCI_PRDT_SIZE_MASK) + 1;
805d02f8adcSReza Jelveh }
806d02f8adcSReza Jelveh 
8073251bdcfSJohn Snow static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist,
808c82bd3c8SJohn Snow                                 AHCICmdHdr *cmd, int64_t limit, int32_t offset)
809f6ad2e32SAlexander Graf {
810d56f4d69SJohn Snow     uint16_t opts = le16_to_cpu(cmd->opts);
811d56f4d69SJohn Snow     uint16_t prdtl = le16_to_cpu(cmd->prdtl);
812d56f4d69SJohn Snow     uint64_t cfis_addr = le64_to_cpu(cmd->tbl_addr);
813d56f4d69SJohn Snow     uint64_t prdt_addr = cfis_addr + 0x80;
814d56f4d69SJohn Snow     dma_addr_t prdt_len = (prdtl * sizeof(AHCI_SG));
81510ca2943SDavid Gibson     dma_addr_t real_prdt_len = prdt_len;
816f6ad2e32SAlexander Graf     uint8_t *prdt;
817f6ad2e32SAlexander Graf     int i;
818f6ad2e32SAlexander Graf     int r = 0;
8193251bdcfSJohn Snow     uint64_t sum = 0;
82061f52e06SJason Baron     int off_idx = -1;
8213251bdcfSJohn Snow     int64_t off_pos = -1;
82261f52e06SJason Baron     int tbl_entry_size;
823f487b677SPaolo Bonzini     IDEBus *bus = &ad->port;
824f487b677SPaolo Bonzini     BusState *qbus = BUS(bus);
825f6ad2e32SAlexander Graf 
8263251bdcfSJohn Snow     /*
8273251bdcfSJohn Snow      * Note: AHCI PRDT can describe up to 256GiB. SATA/ATA only support
8283251bdcfSJohn Snow      * transactions of up to 32MiB as of ATA8-ACS3 rev 1b, assuming a
8293251bdcfSJohn Snow      * 512 byte sector size. We limit the PRDT in this implementation to
8303251bdcfSJohn Snow      * a reasonably large 2GiB, which can accommodate the maximum transfer
8313251bdcfSJohn Snow      * request for sector sizes up to 32K.
8323251bdcfSJohn Snow      */
8333251bdcfSJohn Snow 
834d56f4d69SJohn Snow     if (!prdtl) {
835f6ad2e32SAlexander Graf         DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
836f6ad2e32SAlexander Graf         return -1;
837f6ad2e32SAlexander Graf     }
838f6ad2e32SAlexander Graf 
839f6ad2e32SAlexander Graf     /* map PRDT */
840df32fd1cSPaolo Bonzini     if (!(prdt = dma_memory_map(ad->hba->as, prdt_addr, &prdt_len,
84110ca2943SDavid Gibson                                 DMA_DIRECTION_TO_DEVICE))){
842f6ad2e32SAlexander Graf         DPRINTF(ad->port_no, "map failed\n");
843f6ad2e32SAlexander Graf         return -1;
844f6ad2e32SAlexander Graf     }
845f6ad2e32SAlexander Graf 
846f6ad2e32SAlexander Graf     if (prdt_len < real_prdt_len) {
847f6ad2e32SAlexander Graf         DPRINTF(ad->port_no, "mapped less than expected\n");
848f6ad2e32SAlexander Graf         r = -1;
849f6ad2e32SAlexander Graf         goto out;
850f6ad2e32SAlexander Graf     }
851f6ad2e32SAlexander Graf 
852f6ad2e32SAlexander Graf     /* Get entries in the PRDT, init a qemu sglist accordingly */
853d56f4d69SJohn Snow     if (prdtl > 0) {
854f6ad2e32SAlexander Graf         AHCI_SG *tbl = (AHCI_SG *)prdt;
85561f52e06SJason Baron         sum = 0;
856d56f4d69SJohn Snow         for (i = 0; i < prdtl; i++) {
857d02f8adcSReza Jelveh             tbl_entry_size = prdt_tbl_entry_size(&tbl[i]);
858a718978eSJohn Snow             if (offset < (sum + tbl_entry_size)) {
85961f52e06SJason Baron                 off_idx = i;
86061f52e06SJason Baron                 off_pos = offset - sum;
86161f52e06SJason Baron                 break;
86261f52e06SJason Baron             }
86361f52e06SJason Baron             sum += tbl_entry_size;
86461f52e06SJason Baron         }
86561f52e06SJason Baron         if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {
86661f52e06SJason Baron             DPRINTF(ad->port_no, "%s: Incorrect offset! "
8673251bdcfSJohn Snow                             "off_idx: %d, off_pos: %"PRId64"\n",
86861f52e06SJason Baron                             __func__, off_idx, off_pos);
86961f52e06SJason Baron             r = -1;
87061f52e06SJason Baron             goto out;
87161f52e06SJason Baron         }
87261f52e06SJason Baron 
873d56f4d69SJohn Snow         qemu_sglist_init(sglist, qbus->parent, (prdtl - off_idx),
874f487b677SPaolo Bonzini                          ad->hba->as);
875ac381236SJohn Snow         qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr) + off_pos,
876a718978eSJohn Snow                         MIN(prdt_tbl_entry_size(&tbl[off_idx]) - off_pos,
877a718978eSJohn Snow                             limit));
87861f52e06SJason Baron 
879a718978eSJohn Snow         for (i = off_idx + 1; i < prdtl && sglist->size < limit; i++) {
880f6ad2e32SAlexander Graf             qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
881a718978eSJohn Snow                             MIN(prdt_tbl_entry_size(&tbl[i]),
882a718978eSJohn Snow                                 limit - sglist->size));
8833251bdcfSJohn Snow             if (sglist->size > INT32_MAX) {
8843251bdcfSJohn Snow                 error_report("AHCI Physical Region Descriptor Table describes "
885594fd211SJohn Snow                              "more than 2 GiB.");
8863251bdcfSJohn Snow                 qemu_sglist_destroy(sglist);
8873251bdcfSJohn Snow                 r = -1;
8883251bdcfSJohn Snow                 goto out;
8893251bdcfSJohn Snow             }
890f6ad2e32SAlexander Graf         }
891f6ad2e32SAlexander Graf     }
892f6ad2e32SAlexander Graf 
893f6ad2e32SAlexander Graf out:
894df32fd1cSPaolo Bonzini     dma_memory_unmap(ad->hba->as, prdt, prdt_len,
89510ca2943SDavid Gibson                      DMA_DIRECTION_TO_DEVICE, prdt_len);
896f6ad2e32SAlexander Graf     return r;
897f6ad2e32SAlexander Graf }
898f6ad2e32SAlexander Graf 
899a55c8231SJohn Snow static void ncq_err(NCQTransferState *ncq_tfs)
900a55c8231SJohn Snow {
901a55c8231SJohn Snow     IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
902a55c8231SJohn Snow 
903a55c8231SJohn Snow     ide_state->error = ABRT_ERR;
904a55c8231SJohn Snow     ide_state->status = READY_STAT | ERR_STAT;
905a55c8231SJohn Snow     ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag);
906a55c8231SJohn Snow }
907a55c8231SJohn Snow 
90854f32237SJohn Snow static void ncq_finish(NCQTransferState *ncq_tfs)
909f6ad2e32SAlexander Graf {
9107c649ac5SJohn Snow     /* If we didn't error out, set our finished bit. Errored commands
9117c649ac5SJohn Snow      * do not get a bit set for the SDB FIS ACT register, nor do they
9127c649ac5SJohn Snow      * clear the outstanding bit in scr_act (PxSACT). */
9137c649ac5SJohn Snow     if (!(ncq_tfs->drive->port_regs.scr_err & (1 << ncq_tfs->tag))) {
9147c649ac5SJohn Snow         ncq_tfs->drive->finished |= (1 << ncq_tfs->tag);
9157c649ac5SJohn Snow     }
916f6ad2e32SAlexander Graf 
9177c649ac5SJohn Snow     ahci_write_fis_sdb(ncq_tfs->drive->hba, ncq_tfs);
918f6ad2e32SAlexander Graf 
919f6ad2e32SAlexander Graf     DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
920f6ad2e32SAlexander Graf             ncq_tfs->tag);
921f6ad2e32SAlexander Graf 
9224be74634SMarkus Armbruster     block_acct_done(blk_get_stats(ncq_tfs->drive->port.ifs[0].blk),
9235366d0c8SBenoît Canet                     &ncq_tfs->acct);
924f6ad2e32SAlexander Graf     qemu_sglist_destroy(&ncq_tfs->sglist);
925f6ad2e32SAlexander Graf     ncq_tfs->used = 0;
926f6ad2e32SAlexander Graf }
927f6ad2e32SAlexander Graf 
92854f32237SJohn Snow static void ncq_cb(void *opaque, int ret)
92954f32237SJohn Snow {
93054f32237SJohn Snow     NCQTransferState *ncq_tfs = (NCQTransferState *)opaque;
93154f32237SJohn Snow     IDEState *ide_state = &ncq_tfs->drive->port.ifs[0];
93254f32237SJohn Snow 
93354f32237SJohn Snow     if (ret == -ECANCELED) {
93454f32237SJohn Snow         return;
93554f32237SJohn Snow     }
93654f32237SJohn Snow 
93754f32237SJohn Snow     if (ret < 0) {
9387c03a691SJohn Snow         bool is_read = ncq_tfs->cmd == READ_FPDMA_QUEUED;
9397c03a691SJohn Snow         BlockErrorAction action = blk_get_error_action(ide_state->blk,
9407c03a691SJohn Snow                                                        is_read, -ret);
9417c03a691SJohn Snow         if (action == BLOCK_ERROR_ACTION_STOP) {
9427c03a691SJohn Snow             ncq_tfs->halt = true;
9437c03a691SJohn Snow             ide_state->bus->error_status = IDE_RETRY_HBA;
9447c03a691SJohn Snow         } else if (action == BLOCK_ERROR_ACTION_REPORT) {
94554f32237SJohn Snow             ncq_err(ncq_tfs);
9467c03a691SJohn Snow         }
9477c03a691SJohn Snow         blk_error_action(ide_state->blk, action, is_read, -ret);
94854f32237SJohn Snow     } else {
94954f32237SJohn Snow         ide_state->status = READY_STAT | SEEK_STAT;
95054f32237SJohn Snow     }
95154f32237SJohn Snow 
9527c03a691SJohn Snow     if (!ncq_tfs->halt) {
95354f32237SJohn Snow         ncq_finish(ncq_tfs);
95454f32237SJohn Snow     }
9557c03a691SJohn Snow }
95654f32237SJohn Snow 
95772a065dbSJohn Snow static int is_ncq(uint8_t ata_cmd)
95872a065dbSJohn Snow {
95972a065dbSJohn Snow     /* Based on SATA 3.2 section 13.6.3.2 */
96072a065dbSJohn Snow     switch (ata_cmd) {
96172a065dbSJohn Snow     case READ_FPDMA_QUEUED:
96272a065dbSJohn Snow     case WRITE_FPDMA_QUEUED:
96372a065dbSJohn Snow     case NCQ_NON_DATA:
96472a065dbSJohn Snow     case RECEIVE_FPDMA_QUEUED:
96572a065dbSJohn Snow     case SEND_FPDMA_QUEUED:
96672a065dbSJohn Snow         return 1;
96772a065dbSJohn Snow     default:
96872a065dbSJohn Snow         return 0;
96972a065dbSJohn Snow     }
97072a065dbSJohn Snow }
97172a065dbSJohn Snow 
972631ddc22SJohn Snow static void execute_ncq_command(NCQTransferState *ncq_tfs)
973631ddc22SJohn Snow {
974631ddc22SJohn Snow     AHCIDevice *ad = ncq_tfs->drive;
975631ddc22SJohn Snow     IDEState *ide_state = &ad->port.ifs[0];
976631ddc22SJohn Snow     int port = ad->port_no;
9777c03a691SJohn Snow 
978631ddc22SJohn Snow     g_assert(is_ncq(ncq_tfs->cmd));
9797c03a691SJohn Snow     ncq_tfs->halt = false;
980631ddc22SJohn Snow 
981631ddc22SJohn Snow     switch (ncq_tfs->cmd) {
982631ddc22SJohn Snow     case READ_FPDMA_QUEUED:
983631ddc22SJohn Snow         DPRINTF(port, "NCQ reading %d sectors from LBA %"PRId64", tag %d\n",
984631ddc22SJohn Snow                 ncq_tfs->sector_count, ncq_tfs->lba, ncq_tfs->tag);
985631ddc22SJohn Snow 
986631ddc22SJohn Snow         DPRINTF(port, "tag %d aio read %"PRId64"\n",
987631ddc22SJohn Snow                 ncq_tfs->tag, ncq_tfs->lba);
988631ddc22SJohn Snow 
989631ddc22SJohn Snow         dma_acct_start(ide_state->blk, &ncq_tfs->acct,
990631ddc22SJohn Snow                        &ncq_tfs->sglist, BLOCK_ACCT_READ);
991631ddc22SJohn Snow         ncq_tfs->aiocb = dma_blk_read(ide_state->blk, &ncq_tfs->sglist,
992631ddc22SJohn Snow                                       ncq_tfs->lba, ncq_cb, ncq_tfs);
993631ddc22SJohn Snow         break;
994631ddc22SJohn Snow     case WRITE_FPDMA_QUEUED:
995631ddc22SJohn Snow         DPRINTF(port, "NCQ writing %d sectors to LBA %"PRId64", tag %d\n",
996631ddc22SJohn Snow                 ncq_tfs->sector_count, ncq_tfs->lba, ncq_tfs->tag);
997631ddc22SJohn Snow 
998631ddc22SJohn Snow         DPRINTF(port, "tag %d aio write %"PRId64"\n",
999631ddc22SJohn Snow                 ncq_tfs->tag, ncq_tfs->lba);
1000631ddc22SJohn Snow 
1001631ddc22SJohn Snow         dma_acct_start(ide_state->blk, &ncq_tfs->acct,
1002631ddc22SJohn Snow                        &ncq_tfs->sglist, BLOCK_ACCT_WRITE);
1003631ddc22SJohn Snow         ncq_tfs->aiocb = dma_blk_write(ide_state->blk, &ncq_tfs->sglist,
1004631ddc22SJohn Snow                                        ncq_tfs->lba, ncq_cb, ncq_tfs);
1005631ddc22SJohn Snow         break;
1006631ddc22SJohn Snow     default:
1007631ddc22SJohn Snow         DPRINTF(port, "error: unsupported NCQ command (0x%02x) received\n",
1008631ddc22SJohn Snow                 ncq_tfs->cmd);
1009631ddc22SJohn Snow         qemu_sglist_destroy(&ncq_tfs->sglist);
1010631ddc22SJohn Snow         ncq_err(ncq_tfs);
1011631ddc22SJohn Snow     }
1012631ddc22SJohn Snow }
1013631ddc22SJohn Snow 
1014631ddc22SJohn Snow 
1015f6ad2e32SAlexander Graf static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
10169364384dSJohn Snow                                 uint8_t slot)
1017f6ad2e32SAlexander Graf {
1018b6fe41faSJohn Snow     AHCIDevice *ad = &s->dev[port];
1019b6fe41faSJohn Snow     IDEState *ide_state = &ad->port.ifs[0];
1020f6ad2e32SAlexander Graf     NCQFrame *ncq_fis = (NCQFrame*)cmd_fis;
1021f6ad2e32SAlexander Graf     uint8_t tag = ncq_fis->tag >> 3;
1022b6fe41faSJohn Snow     NCQTransferState *ncq_tfs = &ad->ncq_tfs[tag];
10233bcbe4aaSJohn Snow     size_t size;
1024f6ad2e32SAlexander Graf 
1025922f893eSJohn Snow     g_assert(is_ncq(ncq_fis->command));
1026f6ad2e32SAlexander Graf     if (ncq_tfs->used) {
1027f6ad2e32SAlexander Graf         /* error - already in use */
1028f6ad2e32SAlexander Graf         fprintf(stderr, "%s: tag %d already used\n", __FUNCTION__, tag);
1029f6ad2e32SAlexander Graf         return;
1030f6ad2e32SAlexander Graf     }
1031f6ad2e32SAlexander Graf 
1032f6ad2e32SAlexander Graf     ncq_tfs->used = 1;
1033b6fe41faSJohn Snow     ncq_tfs->drive = ad;
1034f6ad2e32SAlexander Graf     ncq_tfs->slot = slot;
1035c82bd3c8SJohn Snow     ncq_tfs->cmdh = &((AHCICmdHdr *)ad->lst)[slot];
10364614619eSJohn Snow     ncq_tfs->cmd = ncq_fis->command;
1037f6ad2e32SAlexander Graf     ncq_tfs->lba = ((uint64_t)ncq_fis->lba5 << 40) |
1038f6ad2e32SAlexander Graf                    ((uint64_t)ncq_fis->lba4 << 32) |
1039f6ad2e32SAlexander Graf                    ((uint64_t)ncq_fis->lba3 << 24) |
1040f6ad2e32SAlexander Graf                    ((uint64_t)ncq_fis->lba2 << 16) |
1041f6ad2e32SAlexander Graf                    ((uint64_t)ncq_fis->lba1 << 8) |
1042f6ad2e32SAlexander Graf                    (uint64_t)ncq_fis->lba0;
10433bcbe4aaSJohn Snow     ncq_tfs->tag = tag;
1044f6ad2e32SAlexander Graf 
10455d5f8921SJohn Snow     /* Sanity-check the NCQ packet */
10465d5f8921SJohn Snow     if (tag != slot) {
10475d5f8921SJohn Snow         DPRINTF(port, "Warn: NCQ slot (%d) did not match the given tag (%d)\n",
10485d5f8921SJohn Snow                 slot, tag);
10495d5f8921SJohn Snow     }
10505d5f8921SJohn Snow 
10515d5f8921SJohn Snow     if (ncq_fis->aux0 || ncq_fis->aux1 || ncq_fis->aux2 || ncq_fis->aux3) {
10525d5f8921SJohn Snow         DPRINTF(port, "Warn: Attempt to use NCQ auxiliary fields.\n");
10535d5f8921SJohn Snow     }
10545d5f8921SJohn Snow     if (ncq_fis->prio || ncq_fis->icc) {
10555d5f8921SJohn Snow         DPRINTF(port, "Warn: Unsupported attempt to use PRIO/ICC fields\n");
10565d5f8921SJohn Snow     }
10575d5f8921SJohn Snow     if (ncq_fis->fua & NCQ_FIS_FUA_MASK) {
10585d5f8921SJohn Snow         DPRINTF(port, "Warn: Unsupported attempt to use Force Unit Access\n");
10595d5f8921SJohn Snow     }
10605d5f8921SJohn Snow     if (ncq_fis->tag & NCQ_FIS_RARC_MASK) {
10615d5f8921SJohn Snow         DPRINTF(port, "Warn: Unsupported attempt to use Rebuild Assist\n");
10625d5f8921SJohn Snow     }
10635d5f8921SJohn Snow 
1064e08a9835SJohn Snow     ncq_tfs->sector_count = ((ncq_fis->sector_count_high << 8) |
1065e08a9835SJohn Snow                              ncq_fis->sector_count_low);
1066e08a9835SJohn Snow     if (!ncq_tfs->sector_count) {
1067e08a9835SJohn Snow         ncq_tfs->sector_count = 0x10000;
1068e08a9835SJohn Snow     }
10693bcbe4aaSJohn Snow     size = ncq_tfs->sector_count * 512;
1070c82bd3c8SJohn Snow     ahci_populate_sglist(ad, &ncq_tfs->sglist, ncq_tfs->cmdh, size, 0);
10713bcbe4aaSJohn Snow 
10723bcbe4aaSJohn Snow     if (ncq_tfs->sglist.size < size) {
10733bcbe4aaSJohn Snow         error_report("ahci: PRDT length for NCQ command (0x%zx) "
10743bcbe4aaSJohn Snow                      "is smaller than the requested size (0x%zx)",
10753bcbe4aaSJohn Snow                      ncq_tfs->sglist.size, size);
10763bcbe4aaSJohn Snow         qemu_sglist_destroy(&ncq_tfs->sglist);
10773bcbe4aaSJohn Snow         ncq_err(ncq_tfs);
10783bcbe4aaSJohn Snow         ahci_trigger_irq(ad->hba, ad, PORT_IRQ_OVERFLOW);
10793bcbe4aaSJohn Snow         return;
10805d5f8921SJohn Snow     } else if (ncq_tfs->sglist.size != size) {
10815d5f8921SJohn Snow         DPRINTF(port, "Warn: PRDTL (0x%zx)"
10825d5f8921SJohn Snow                 " does not match requested size (0x%zx)",
10835d5f8921SJohn Snow                 ncq_tfs->sglist.size, size);
10843bcbe4aaSJohn Snow     }
1085f6ad2e32SAlexander Graf 
10863899edf7SMax Filippov     DPRINTF(port, "NCQ transfer LBA from %"PRId64" to %"PRId64", "
10873899edf7SMax Filippov             "drive max %"PRId64"\n",
10880437d32aSJohn Snow             ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 1,
1089b6fe41faSJohn Snow             ide_state->nb_sectors - 1);
1090f6ad2e32SAlexander Graf 
1091631ddc22SJohn Snow     execute_ncq_command(ncq_tfs);
1092f6ad2e32SAlexander Graf }
1093f6ad2e32SAlexander Graf 
1094ee364416SJohn Snow static AHCICmdHdr *get_cmd_header(AHCIState *s, uint8_t port, uint8_t slot)
1095ee364416SJohn Snow {
1096ee364416SJohn Snow     if (port >= s->ports || slot >= AHCI_MAX_CMDS) {
1097ee364416SJohn Snow         return NULL;
1098ee364416SJohn Snow     }
1099ee364416SJohn Snow 
1100ee364416SJohn Snow     return s->dev[port].lst ? &((AHCICmdHdr *)s->dev[port].lst)[slot] : NULL;
1101ee364416SJohn Snow }
1102ee364416SJohn Snow 
1103107f0d46SJohn Snow static void handle_reg_h2d_fis(AHCIState *s, int port,
11049364384dSJohn Snow                                uint8_t slot, uint8_t *cmd_fis)
1105f6ad2e32SAlexander Graf {
1106107f0d46SJohn Snow     IDEState *ide_state = &s->dev[port].port.ifs[0];
1107ee364416SJohn Snow     AHCICmdHdr *cmd = get_cmd_header(s, port, slot);
1108d56f4d69SJohn Snow     uint16_t opts = le16_to_cpu(cmd->opts);
1109f6ad2e32SAlexander Graf 
1110102e5625SJohn Snow     if (cmd_fis[1] & 0x0F) {
1111102e5625SJohn Snow         DPRINTF(port, "Port Multiplier not supported."
1112102e5625SJohn Snow                 " cmd_fis[0]=%02x cmd_fis[1]=%02x cmd_fis[2]=%02x\n",
1113102e5625SJohn Snow                 cmd_fis[0], cmd_fis[1], cmd_fis[2]);
1114107f0d46SJohn Snow         return;
1115102e5625SJohn Snow     }
1116102e5625SJohn Snow 
1117102e5625SJohn Snow     if (cmd_fis[1] & 0x70) {
1118102e5625SJohn Snow         DPRINTF(port, "Reserved flags set in H2D Register FIS."
1119102e5625SJohn Snow                 " cmd_fis[0]=%02x cmd_fis[1]=%02x cmd_fis[2]=%02x\n",
1120102e5625SJohn Snow                 cmd_fis[0], cmd_fis[1], cmd_fis[2]);
1121107f0d46SJohn Snow         return;
1122f6ad2e32SAlexander Graf     }
1123f6ad2e32SAlexander Graf 
11241cbdd968SJohn Snow     if (!(cmd_fis[1] & SATA_FIS_REG_H2D_UPDATE_COMMAND_REGISTER)) {
1125f6ad2e32SAlexander Graf         switch (s->dev[port].port_state) {
1126f6ad2e32SAlexander Graf         case STATE_RUN:
1127f6ad2e32SAlexander Graf             if (cmd_fis[15] & ATA_SRST) {
1128f6ad2e32SAlexander Graf                 s->dev[port].port_state = STATE_RESET;
1129f6ad2e32SAlexander Graf             }
1130f6ad2e32SAlexander Graf             break;
1131f6ad2e32SAlexander Graf         case STATE_RESET:
1132f6ad2e32SAlexander Graf             if (!(cmd_fis[15] & ATA_SRST)) {
1133f6ad2e32SAlexander Graf                 ahci_reset_port(s, port);
1134f6ad2e32SAlexander Graf             }
1135f6ad2e32SAlexander Graf             break;
1136f6ad2e32SAlexander Graf         }
1137107f0d46SJohn Snow         return;
11381cbdd968SJohn Snow     }
1139f6ad2e32SAlexander Graf 
1140f6ad2e32SAlexander Graf     /* Check for NCQ command */
114172a065dbSJohn Snow     if (is_ncq(cmd_fis[2])) {
1142f6ad2e32SAlexander Graf         process_ncq_command(s, port, cmd_fis, slot);
1143107f0d46SJohn Snow         return;
1144f6ad2e32SAlexander Graf     }
1145f6ad2e32SAlexander Graf 
11461cbdd968SJohn Snow     /* Decompose the FIS:
11471cbdd968SJohn Snow      * AHCI does not interpret FIS packets, it only forwards them.
11481cbdd968SJohn Snow      * SATA 1.0 describes how to decode LBA28 and CHS FIS packets.
11491cbdd968SJohn Snow      * Later specifications, e.g, SATA 3.2, describe LBA48 FIS packets.
11501cbdd968SJohn Snow      *
11511cbdd968SJohn Snow      * ATA4 describes sector number for LBA28/CHS commands.
11521cbdd968SJohn Snow      * ATA6 describes sector number for LBA48 commands.
11531cbdd968SJohn Snow      * ATA8 deprecates CHS fully, describing only LBA28/48.
11541cbdd968SJohn Snow      *
11551cbdd968SJohn Snow      * We dutifully convert the FIS into IDE registers, and allow the
11561cbdd968SJohn Snow      * core layer to interpret them as needed. */
1157f6ad2e32SAlexander Graf     ide_state->feature = cmd_fis[3];
11581cbdd968SJohn Snow     ide_state->sector = cmd_fis[4];      /* LBA 7:0 */
11591cbdd968SJohn Snow     ide_state->lcyl = cmd_fis[5];        /* LBA 15:8  */
11601cbdd968SJohn Snow     ide_state->hcyl = cmd_fis[6];        /* LBA 23:16 */
11611cbdd968SJohn Snow     ide_state->select = cmd_fis[7];      /* LBA 27:24 (LBA28) */
11621cbdd968SJohn Snow     ide_state->hob_sector = cmd_fis[8];  /* LBA 31:24 */
11631cbdd968SJohn Snow     ide_state->hob_lcyl = cmd_fis[9];    /* LBA 39:32 */
11641cbdd968SJohn Snow     ide_state->hob_hcyl = cmd_fis[10];   /* LBA 47:40 */
11651cbdd968SJohn Snow     ide_state->hob_feature = cmd_fis[11];
11661cbdd968SJohn Snow     ide_state->nsector = (int64_t)((cmd_fis[13] << 8) | cmd_fis[12]);
11671cbdd968SJohn Snow     /* 14, 16, 17, 18, 19: Reserved (SATA 1.0) */
11681cbdd968SJohn Snow     /* 15: Only valid when UPDATE_COMMAND not set. */
1169f6ad2e32SAlexander Graf 
1170f6ad2e32SAlexander Graf     /* Copy the ACMD field (ATAPI packet, if any) from the AHCI command
1171107f0d46SJohn Snow      * table to ide_state->io_buffer */
1172f6ad2e32SAlexander Graf     if (opts & AHCI_CMD_ATAPI) {
1173f6ad2e32SAlexander Graf         memcpy(ide_state->io_buffer, &cmd_fis[AHCI_COMMAND_TABLE_ACMD], 0x10);
1174f6ad2e32SAlexander Graf         debug_print_fis(ide_state->io_buffer, 0x10);
11754ac557c8SKevin Wolf         s->dev[port].done_atapi_packet = false;
1176f6ad2e32SAlexander Graf         /* XXX send PIO setup FIS */
1177f6ad2e32SAlexander Graf     }
1178f6ad2e32SAlexander Graf 
1179f6ad2e32SAlexander Graf     ide_state->error = 0;
1180f6ad2e32SAlexander Graf 
1181f6ad2e32SAlexander Graf     /* Reset transferred byte counter */
1182f6ad2e32SAlexander Graf     cmd->status = 0;
1183f6ad2e32SAlexander Graf 
1184f6ad2e32SAlexander Graf     /* We're ready to process the command in FIS byte 2. */
1185f6ad2e32SAlexander Graf     ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
1186f6ad2e32SAlexander Graf }
1187f6ad2e32SAlexander Graf 
11889364384dSJohn Snow static int handle_cmd(AHCIState *s, int port, uint8_t slot)
1189107f0d46SJohn Snow {
1190107f0d46SJohn Snow     IDEState *ide_state;
1191107f0d46SJohn Snow     uint64_t tbl_addr;
1192107f0d46SJohn Snow     AHCICmdHdr *cmd;
1193107f0d46SJohn Snow     uint8_t *cmd_fis;
1194107f0d46SJohn Snow     dma_addr_t cmd_len;
1195107f0d46SJohn Snow 
1196107f0d46SJohn Snow     if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
1197107f0d46SJohn Snow         /* Engine currently busy, try again later */
1198107f0d46SJohn Snow         DPRINTF(port, "engine busy\n");
1199107f0d46SJohn Snow         return -1;
1200107f0d46SJohn Snow     }
1201107f0d46SJohn Snow 
1202107f0d46SJohn Snow     if (!s->dev[port].lst) {
1203107f0d46SJohn Snow         DPRINTF(port, "error: lst not given but cmd handled");
1204107f0d46SJohn Snow         return -1;
1205107f0d46SJohn Snow     }
1206ee364416SJohn Snow     cmd = get_cmd_header(s, port, slot);
1207107f0d46SJohn Snow     /* remember current slot handle for later */
1208107f0d46SJohn Snow     s->dev[port].cur_cmd = cmd;
1209107f0d46SJohn Snow 
1210107f0d46SJohn Snow     /* The device we are working for */
1211107f0d46SJohn Snow     ide_state = &s->dev[port].port.ifs[0];
1212107f0d46SJohn Snow     if (!ide_state->blk) {
1213107f0d46SJohn Snow         DPRINTF(port, "error: guest accessed unused port");
1214107f0d46SJohn Snow         return -1;
1215107f0d46SJohn Snow     }
1216107f0d46SJohn Snow 
1217107f0d46SJohn Snow     tbl_addr = le64_to_cpu(cmd->tbl_addr);
1218107f0d46SJohn Snow     cmd_len = 0x80;
1219107f0d46SJohn Snow     cmd_fis = dma_memory_map(s->as, tbl_addr, &cmd_len,
1220107f0d46SJohn Snow                              DMA_DIRECTION_FROM_DEVICE);
1221107f0d46SJohn Snow     if (!cmd_fis) {
1222107f0d46SJohn Snow         DPRINTF(port, "error: guest passed us an invalid cmd fis\n");
1223107f0d46SJohn Snow         return -1;
1224107f0d46SJohn Snow     } else if (cmd_len != 0x80) {
1225107f0d46SJohn Snow         ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_HBUS_ERR);
1226107f0d46SJohn Snow         DPRINTF(port, "error: dma_memory_map failed: "
1227107f0d46SJohn Snow                 "(len(%02"PRIx64") != 0x80)\n",
1228107f0d46SJohn Snow                 cmd_len);
1229107f0d46SJohn Snow         goto out;
1230107f0d46SJohn Snow     }
1231107f0d46SJohn Snow     debug_print_fis(cmd_fis, 0x80);
1232107f0d46SJohn Snow 
1233107f0d46SJohn Snow     switch (cmd_fis[0]) {
1234107f0d46SJohn Snow         case SATA_FIS_TYPE_REGISTER_H2D:
1235107f0d46SJohn Snow             handle_reg_h2d_fis(s, port, slot, cmd_fis);
1236107f0d46SJohn Snow             break;
1237107f0d46SJohn Snow         default:
1238107f0d46SJohn Snow             DPRINTF(port, "unknown command cmd_fis[0]=%02x cmd_fis[1]=%02x "
1239107f0d46SJohn Snow                           "cmd_fis[2]=%02x\n", cmd_fis[0], cmd_fis[1],
1240107f0d46SJohn Snow                           cmd_fis[2]);
1241107f0d46SJohn Snow             break;
1242107f0d46SJohn Snow     }
1243107f0d46SJohn Snow 
1244f6ad2e32SAlexander Graf out:
1245df32fd1cSPaolo Bonzini     dma_memory_unmap(s->as, cmd_fis, cmd_len, DMA_DIRECTION_FROM_DEVICE,
124610ca2943SDavid Gibson                      cmd_len);
1247f6ad2e32SAlexander Graf 
1248f6ad2e32SAlexander Graf     if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
1249f6ad2e32SAlexander Graf         /* async command, complete later */
1250f6ad2e32SAlexander Graf         s->dev[port].busy_slot = slot;
1251f6ad2e32SAlexander Graf         return -1;
1252f6ad2e32SAlexander Graf     }
1253f6ad2e32SAlexander Graf 
1254f6ad2e32SAlexander Graf     /* done handling the command */
1255f6ad2e32SAlexander Graf     return 0;
1256f6ad2e32SAlexander Graf }
1257f6ad2e32SAlexander Graf 
1258f6ad2e32SAlexander Graf /* DMA dev <-> ram */
125944635123SPaolo Bonzini static void ahci_start_transfer(IDEDMA *dma)
1260f6ad2e32SAlexander Graf {
1261f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1262f6ad2e32SAlexander Graf     IDEState *s = &ad->port.ifs[0];
1263f6ad2e32SAlexander Graf     uint32_t size = (uint32_t)(s->data_end - s->data_ptr);
1264f6ad2e32SAlexander Graf     /* write == ram -> device */
1265d56f4d69SJohn Snow     uint16_t opts = le16_to_cpu(ad->cur_cmd->opts);
1266f6ad2e32SAlexander Graf     int is_write = opts & AHCI_CMD_WRITE;
1267f6ad2e32SAlexander Graf     int is_atapi = opts & AHCI_CMD_ATAPI;
1268f6ad2e32SAlexander Graf     int has_sglist = 0;
1269f6ad2e32SAlexander Graf 
1270f6ad2e32SAlexander Graf     if (is_atapi && !ad->done_atapi_packet) {
1271f6ad2e32SAlexander Graf         /* already prepopulated iobuffer */
12724ac557c8SKevin Wolf         ad->done_atapi_packet = true;
1273a395f3faSJohn Snow         size = 0;
1274f6ad2e32SAlexander Graf         goto out;
1275f6ad2e32SAlexander Graf     }
1276f6ad2e32SAlexander Graf 
1277a718978eSJohn Snow     if (ahci_dma_prepare_buf(dma, size)) {
1278f6ad2e32SAlexander Graf         has_sglist = 1;
1279f6ad2e32SAlexander Graf     }
1280f6ad2e32SAlexander Graf 
1281f6ad2e32SAlexander Graf     DPRINTF(ad->port_no, "%sing %d bytes on %s w/%s sglist\n",
1282f6ad2e32SAlexander Graf             is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata",
1283f6ad2e32SAlexander Graf             has_sglist ? "" : "o");
1284f6ad2e32SAlexander Graf 
1285da221327SPaolo Bonzini     if (has_sglist && size) {
1286da221327SPaolo Bonzini         if (is_write) {
1287da221327SPaolo Bonzini             dma_buf_write(s->data_ptr, size, &s->sg);
1288da221327SPaolo Bonzini         } else {
1289da221327SPaolo Bonzini             dma_buf_read(s->data_ptr, size, &s->sg);
1290f6ad2e32SAlexander Graf         }
1291f6ad2e32SAlexander Graf     }
1292f6ad2e32SAlexander Graf 
1293f6ad2e32SAlexander Graf out:
1294f6ad2e32SAlexander Graf     /* declare that we processed everything */
1295f6ad2e32SAlexander Graf     s->data_ptr = s->data_end;
1296f6ad2e32SAlexander Graf 
1297659142ecSJohn Snow     /* Update number of transferred bytes, destroy sglist */
1298aaeda4a3SJohn Snow     dma_buf_commit(s, size);
1299f6ad2e32SAlexander Graf 
1300f6ad2e32SAlexander Graf     s->end_transfer_func(s);
130108841520SPaolo Bonzini 
130208841520SPaolo Bonzini     if (!(s->status & DRQ_STAT)) {
130308841520SPaolo Bonzini         /* done with PIO send/receive */
130408841520SPaolo Bonzini         ahci_write_fis_pio(ad, le32_to_cpu(ad->cur_cmd->status));
130508841520SPaolo Bonzini     }
1306f6ad2e32SAlexander Graf }
1307f6ad2e32SAlexander Graf 
1308f6ad2e32SAlexander Graf static void ahci_start_dma(IDEDMA *dma, IDEState *s,
1309097310b5SMarkus Armbruster                            BlockCompletionFunc *dma_cb)
1310f6ad2e32SAlexander Graf {
1311f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1312f6ad2e32SAlexander Graf     DPRINTF(ad->port_no, "\n");
131361f52e06SJason Baron     s->io_buffer_offset = 0;
1314f6ad2e32SAlexander Graf     dma_cb(s, 0);
1315f6ad2e32SAlexander Graf }
1316f6ad2e32SAlexander Graf 
1317e8ef8743SPaolo Bonzini static void ahci_restart_dma(IDEDMA *dma)
1318e8ef8743SPaolo Bonzini {
1319e8ef8743SPaolo Bonzini     /* Nothing to do, ahci_start_dma already resets s->io_buffer_offset.  */
1320e8ef8743SPaolo Bonzini }
1321e8ef8743SPaolo Bonzini 
1322659142ecSJohn Snow /**
13237c03a691SJohn Snow  * IDE/PIO restarts are handled by the core layer, but NCQ commands
13247c03a691SJohn Snow  * need an extra kick from the AHCI HBA.
13257c03a691SJohn Snow  */
13267c03a691SJohn Snow static void ahci_restart(IDEDMA *dma)
13277c03a691SJohn Snow {
13287c03a691SJohn Snow     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
13297c03a691SJohn Snow     int i;
13307c03a691SJohn Snow 
13317c03a691SJohn Snow     for (i = 0; i < AHCI_MAX_CMDS; i++) {
13327c03a691SJohn Snow         NCQTransferState *ncq_tfs = &ad->ncq_tfs[i];
13337c03a691SJohn Snow         if (ncq_tfs->halt) {
13347c03a691SJohn Snow             execute_ncq_command(ncq_tfs);
13357c03a691SJohn Snow         }
13367c03a691SJohn Snow     }
13377c03a691SJohn Snow }
13387c03a691SJohn Snow 
13397c03a691SJohn Snow /**
1340aaeda4a3SJohn Snow  * Called in DMA and PIO R/W chains to read the PRDT.
1341aaeda4a3SJohn Snow  * Not shared with NCQ pathways.
1342659142ecSJohn Snow  */
1343a718978eSJohn Snow static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit)
1344f6ad2e32SAlexander Graf {
1345f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1346f6ad2e32SAlexander Graf     IDEState *s = &ad->port.ifs[0];
1347f6ad2e32SAlexander Graf 
1348c82bd3c8SJohn Snow     if (ahci_populate_sglist(ad, &s->sg, ad->cur_cmd,
1349c82bd3c8SJohn Snow                              limit, s->io_buffer_offset) == -1) {
13503251bdcfSJohn Snow         DPRINTF(ad->port_no, "ahci_dma_prepare_buf failed.\n");
13513251bdcfSJohn Snow         return -1;
13523251bdcfSJohn Snow     }
1353da221327SPaolo Bonzini     s->io_buffer_size = s->sg.size;
1354f6ad2e32SAlexander Graf 
1355f6ad2e32SAlexander Graf     DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
13563251bdcfSJohn Snow     return s->io_buffer_size;
1357f6ad2e32SAlexander Graf }
1358f6ad2e32SAlexander Graf 
1359659142ecSJohn Snow /**
1360aaeda4a3SJohn Snow  * Updates the command header with a bytes-read value.
1361aaeda4a3SJohn Snow  * Called via dma_buf_commit, for both DMA and PIO paths.
1362aaeda4a3SJohn Snow  * sglist destruction is handled within dma_buf_commit.
1363659142ecSJohn Snow  */
1364659142ecSJohn Snow static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes)
1365659142ecSJohn Snow {
1366659142ecSJohn Snow     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1367659142ecSJohn Snow 
1368659142ecSJohn Snow     tx_bytes += le32_to_cpu(ad->cur_cmd->status);
1369659142ecSJohn Snow     ad->cur_cmd->status = cpu_to_le32(tx_bytes);
1370659142ecSJohn Snow }
1371659142ecSJohn Snow 
1372f6ad2e32SAlexander Graf static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
1373f6ad2e32SAlexander Graf {
1374f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1375f6ad2e32SAlexander Graf     IDEState *s = &ad->port.ifs[0];
1376f6ad2e32SAlexander Graf     uint8_t *p = s->io_buffer + s->io_buffer_index;
1377f6ad2e32SAlexander Graf     int l = s->io_buffer_size - s->io_buffer_index;
1378f6ad2e32SAlexander Graf 
1379c82bd3c8SJohn Snow     if (ahci_populate_sglist(ad, &s->sg, ad->cur_cmd, l, s->io_buffer_offset)) {
1380f6ad2e32SAlexander Graf         return 0;
1381f6ad2e32SAlexander Graf     }
1382f6ad2e32SAlexander Graf 
1383f6ad2e32SAlexander Graf     if (is_write) {
1384da221327SPaolo Bonzini         dma_buf_read(p, l, &s->sg);
1385f6ad2e32SAlexander Graf     } else {
1386da221327SPaolo Bonzini         dma_buf_write(p, l, &s->sg);
1387f6ad2e32SAlexander Graf     }
1388f6ad2e32SAlexander Graf 
1389659142ecSJohn Snow     /* free sglist, update byte count */
1390aaeda4a3SJohn Snow     dma_buf_commit(s, l);
1391ea8d82a1SJason Baron 
1392f6ad2e32SAlexander Graf     s->io_buffer_index += l;
1393f6ad2e32SAlexander Graf 
1394f6ad2e32SAlexander Graf     DPRINTF(ad->port_no, "len=%#x\n", l);
1395f6ad2e32SAlexander Graf 
1396f6ad2e32SAlexander Graf     return 1;
1397f6ad2e32SAlexander Graf }
1398f6ad2e32SAlexander Graf 
1399c7e73adbSPaolo Bonzini static void ahci_cmd_done(IDEDMA *dma)
1400a62eaa26SKevin Wolf {
1401f6ad2e32SAlexander Graf     AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
1402f6ad2e32SAlexander Graf 
1403c7e73adbSPaolo Bonzini     DPRINTF(ad->port_no, "cmd done\n");
1404f6ad2e32SAlexander Graf 
1405f6ad2e32SAlexander Graf     /* update d2h status */
140628ee8255SJohn Snow     ahci_write_fis_d2h(ad);
1407f6ad2e32SAlexander Graf 
14084d29b50aSJan Kiszka     if (!ad->check_bh) {
1409f6ad2e32SAlexander Graf         /* maybe we still have something to process, check later */
1410f6ad2e32SAlexander Graf         ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
1411f6ad2e32SAlexander Graf         qemu_bh_schedule(ad->check_bh);
14124d29b50aSJan Kiszka     }
1413f6ad2e32SAlexander Graf }
1414f6ad2e32SAlexander Graf 
1415f6ad2e32SAlexander Graf static void ahci_irq_set(void *opaque, int n, int level)
1416f6ad2e32SAlexander Graf {
1417f6ad2e32SAlexander Graf }
1418f6ad2e32SAlexander Graf 
1419f6ad2e32SAlexander Graf static const IDEDMAOps ahci_dma_ops = {
1420f6ad2e32SAlexander Graf     .start_dma = ahci_start_dma,
14217c03a691SJohn Snow     .restart = ahci_restart,
1422e8ef8743SPaolo Bonzini     .restart_dma = ahci_restart_dma,
1423f6ad2e32SAlexander Graf     .start_transfer = ahci_start_transfer,
1424f6ad2e32SAlexander Graf     .prepare_buf = ahci_dma_prepare_buf,
1425659142ecSJohn Snow     .commit_buf = ahci_commit_buf,
1426f6ad2e32SAlexander Graf     .rw_buf = ahci_dma_rw_buf,
1427c7e73adbSPaolo Bonzini     .cmd_done = ahci_cmd_done,
1428f6ad2e32SAlexander Graf };
1429f6ad2e32SAlexander Graf 
1430df32fd1cSPaolo Bonzini void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports)
1431f6ad2e32SAlexander Graf {
1432f6ad2e32SAlexander Graf     qemu_irq *irqs;
1433f6ad2e32SAlexander Graf     int i;
1434f6ad2e32SAlexander Graf 
1435df32fd1cSPaolo Bonzini     s->as = as;
14362c4b9d0eSAlexander Graf     s->ports = ports;
14375839e53bSMarkus Armbruster     s->dev = g_new0(AHCIDevice, ports);
1438bb639f82SAlistair Francis     s->container = qdev;
1439f6ad2e32SAlexander Graf     ahci_reg_init(s);
144067e576c2SAvi Kivity     /* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
14411437c94bSPaolo Bonzini     memory_region_init_io(&s->mem, OBJECT(qdev), &ahci_mem_ops, s,
14421437c94bSPaolo Bonzini                           "ahci", AHCI_MEM_BAR_SIZE);
14431437c94bSPaolo Bonzini     memory_region_init_io(&s->idp, OBJECT(qdev), &ahci_idp_ops, s,
14441437c94bSPaolo Bonzini                           "ahci-idp", 32);
1445465f1ab1SDaniel Verkamp 
14462c4b9d0eSAlexander Graf     irqs = qemu_allocate_irqs(ahci_irq_set, s, s->ports);
1447f6ad2e32SAlexander Graf 
14482c4b9d0eSAlexander Graf     for (i = 0; i < s->ports; i++) {
1449f6ad2e32SAlexander Graf         AHCIDevice *ad = &s->dev[i];
1450f6ad2e32SAlexander Graf 
1451c6baf942SAndreas Färber         ide_bus_new(&ad->port, sizeof(ad->port), qdev, i, 1);
1452f6ad2e32SAlexander Graf         ide_init2(&ad->port, irqs[i]);
1453f6ad2e32SAlexander Graf 
1454f6ad2e32SAlexander Graf         ad->hba = s;
1455f6ad2e32SAlexander Graf         ad->port_no = i;
1456f6ad2e32SAlexander Graf         ad->port.dma = &ad->dma;
1457f6ad2e32SAlexander Graf         ad->port.dma->ops = &ahci_dma_ops;
1458e8ef8743SPaolo Bonzini         ide_register_restart_cb(&ad->port);
1459f6ad2e32SAlexander Graf     }
1460f6ad2e32SAlexander Graf }
1461f6ad2e32SAlexander Graf 
14622c4b9d0eSAlexander Graf void ahci_uninit(AHCIState *s)
14632c4b9d0eSAlexander Graf {
14647267c094SAnthony Liguori     g_free(s->dev);
14652c4b9d0eSAlexander Graf }
14662c4b9d0eSAlexander Graf 
14678ab60a07SJan Kiszka void ahci_reset(AHCIState *s)
1468f6ad2e32SAlexander Graf {
1469a26a13daSAlexander Motin     AHCIPortRegs *pr;
1470f6ad2e32SAlexander Graf     int i;
1471f6ad2e32SAlexander Graf 
14728ab60a07SJan Kiszka     s->control_regs.irqstatus = 0;
147313164591SMichael S. Tsirkin     /* AHCI Enable (AE)
147413164591SMichael S. Tsirkin      * The implementation of this bit is dependent upon the value of the
147513164591SMichael S. Tsirkin      * CAP.SAM bit. If CAP.SAM is '0', then GHC.AE shall be read-write and
147613164591SMichael S. Tsirkin      * shall have a reset value of '0'. If CAP.SAM is '1', then AE shall be
147713164591SMichael S. Tsirkin      * read-only and shall have a reset value of '1'.
147813164591SMichael S. Tsirkin      *
147913164591SMichael S. Tsirkin      * We set HOST_CAP_AHCI so we must enable AHCI at reset.
148013164591SMichael S. Tsirkin      */
148113164591SMichael S. Tsirkin     s->control_regs.ghc = HOST_CTL_AHCI_EN;
1482760c3e44SAlexander Graf 
14838ab60a07SJan Kiszka     for (i = 0; i < s->ports; i++) {
14848ab60a07SJan Kiszka         pr = &s->dev[i].port_regs;
1485a26a13daSAlexander Motin         pr->irq_stat = 0;
1486a26a13daSAlexander Motin         pr->irq_mask = 0;
1487a26a13daSAlexander Motin         pr->scr_ctl = 0;
14882a4f4f34SJason Baron         pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
14898ab60a07SJan Kiszka         ahci_reset_port(s, i);
1490f6ad2e32SAlexander Graf     }
1491f6ad2e32SAlexander Graf }
1492d9fa31a3SRob Herring 
1493684d5013SJohn Snow static const VMStateDescription vmstate_ncq_tfs = {
1494684d5013SJohn Snow     .name = "ncq state",
1495684d5013SJohn Snow     .version_id = 1,
1496684d5013SJohn Snow     .fields = (VMStateField[]) {
1497684d5013SJohn Snow         VMSTATE_UINT32(sector_count, NCQTransferState),
1498684d5013SJohn Snow         VMSTATE_UINT64(lba, NCQTransferState),
1499684d5013SJohn Snow         VMSTATE_UINT8(tag, NCQTransferState),
1500684d5013SJohn Snow         VMSTATE_UINT8(cmd, NCQTransferState),
1501684d5013SJohn Snow         VMSTATE_UINT8(slot, NCQTransferState),
1502684d5013SJohn Snow         VMSTATE_BOOL(used, NCQTransferState),
1503684d5013SJohn Snow         VMSTATE_BOOL(halt, NCQTransferState),
1504684d5013SJohn Snow         VMSTATE_END_OF_LIST()
1505684d5013SJohn Snow     },
1506684d5013SJohn Snow };
1507684d5013SJohn Snow 
1508a2623021SJason Baron static const VMStateDescription vmstate_ahci_device = {
1509a2623021SJason Baron     .name = "ahci port",
1510a2623021SJason Baron     .version_id = 1,
1511a2623021SJason Baron     .fields = (VMStateField[]) {
1512a2623021SJason Baron         VMSTATE_IDE_BUS(port, AHCIDevice),
1513bd664910SJohn Snow         VMSTATE_IDE_DRIVE(port.ifs[0], AHCIDevice),
1514a2623021SJason Baron         VMSTATE_UINT32(port_state, AHCIDevice),
1515a2623021SJason Baron         VMSTATE_UINT32(finished, AHCIDevice),
1516a2623021SJason Baron         VMSTATE_UINT32(port_regs.lst_addr, AHCIDevice),
1517a2623021SJason Baron         VMSTATE_UINT32(port_regs.lst_addr_hi, AHCIDevice),
1518a2623021SJason Baron         VMSTATE_UINT32(port_regs.fis_addr, AHCIDevice),
1519a2623021SJason Baron         VMSTATE_UINT32(port_regs.fis_addr_hi, AHCIDevice),
1520a2623021SJason Baron         VMSTATE_UINT32(port_regs.irq_stat, AHCIDevice),
1521a2623021SJason Baron         VMSTATE_UINT32(port_regs.irq_mask, AHCIDevice),
1522a2623021SJason Baron         VMSTATE_UINT32(port_regs.cmd, AHCIDevice),
1523a2623021SJason Baron         VMSTATE_UINT32(port_regs.tfdata, AHCIDevice),
1524a2623021SJason Baron         VMSTATE_UINT32(port_regs.sig, AHCIDevice),
1525a2623021SJason Baron         VMSTATE_UINT32(port_regs.scr_stat, AHCIDevice),
1526a2623021SJason Baron         VMSTATE_UINT32(port_regs.scr_ctl, AHCIDevice),
1527a2623021SJason Baron         VMSTATE_UINT32(port_regs.scr_err, AHCIDevice),
1528a2623021SJason Baron         VMSTATE_UINT32(port_regs.scr_act, AHCIDevice),
1529a2623021SJason Baron         VMSTATE_UINT32(port_regs.cmd_issue, AHCIDevice),
1530a2623021SJason Baron         VMSTATE_BOOL(done_atapi_packet, AHCIDevice),
1531a2623021SJason Baron         VMSTATE_INT32(busy_slot, AHCIDevice),
1532a2623021SJason Baron         VMSTATE_BOOL(init_d2h_sent, AHCIDevice),
1533684d5013SJohn Snow         VMSTATE_STRUCT_ARRAY(ncq_tfs, AHCIDevice, AHCI_MAX_CMDS,
1534684d5013SJohn Snow                              1, vmstate_ncq_tfs, NCQTransferState),
1535a2623021SJason Baron         VMSTATE_END_OF_LIST()
1536a2623021SJason Baron     },
1537a2623021SJason Baron };
1538a2623021SJason Baron 
1539a2623021SJason Baron static int ahci_state_post_load(void *opaque, int version_id)
1540a2623021SJason Baron {
1541684d5013SJohn Snow     int i, j;
1542a2623021SJason Baron     struct AHCIDevice *ad;
1543684d5013SJohn Snow     NCQTransferState *ncq_tfs;
1544a2623021SJason Baron     AHCIState *s = opaque;
1545a2623021SJason Baron 
1546a2623021SJason Baron     for (i = 0; i < s->ports; i++) {
1547a2623021SJason Baron         ad = &s->dev[i];
1548a2623021SJason Baron 
1549cd6cb73bSJohn Snow         /* Only remap the CLB address if appropriate, disallowing a state
1550cd6cb73bSJohn Snow          * transition from 'on' to 'off' it should be consistent here. */
1551cd6cb73bSJohn Snow         if (ahci_cond_start_engines(ad, false) != 0) {
1552cd6cb73bSJohn Snow             return -1;
1553cd6cb73bSJohn Snow         }
1554cd6cb73bSJohn Snow 
1555684d5013SJohn Snow         for (j = 0; j < AHCI_MAX_CMDS; j++) {
1556684d5013SJohn Snow             ncq_tfs = &ad->ncq_tfs[j];
1557684d5013SJohn Snow             ncq_tfs->drive = ad;
1558684d5013SJohn Snow 
1559684d5013SJohn Snow             if (ncq_tfs->used != ncq_tfs->halt) {
1560684d5013SJohn Snow                 return -1;
1561684d5013SJohn Snow             }
1562684d5013SJohn Snow             if (!ncq_tfs->halt) {
1563684d5013SJohn Snow                 continue;
1564684d5013SJohn Snow             }
1565684d5013SJohn Snow             if (!is_ncq(ncq_tfs->cmd)) {
1566684d5013SJohn Snow                 return -1;
1567684d5013SJohn Snow             }
1568684d5013SJohn Snow             if (ncq_tfs->slot != ncq_tfs->tag) {
1569684d5013SJohn Snow                 return -1;
1570684d5013SJohn Snow             }
1571684d5013SJohn Snow             /* If ncq_tfs->halt is justly set, the engine should be engaged,
1572684d5013SJohn Snow              * and the command list buffer should be mapped. */
1573684d5013SJohn Snow             ncq_tfs->cmdh = get_cmd_header(s, i, ncq_tfs->slot);
1574684d5013SJohn Snow             if (!ncq_tfs->cmdh) {
1575684d5013SJohn Snow                 return -1;
1576684d5013SJohn Snow             }
1577684d5013SJohn Snow             ahci_populate_sglist(ncq_tfs->drive, &ncq_tfs->sglist,
1578684d5013SJohn Snow                                  ncq_tfs->cmdh, ncq_tfs->sector_count * 512,
1579684d5013SJohn Snow                                  0);
1580684d5013SJohn Snow             if (ncq_tfs->sector_count != ncq_tfs->sglist.size >> 9) {
1581684d5013SJohn Snow                 return -1;
1582684d5013SJohn Snow             }
1583684d5013SJohn Snow         }
1584684d5013SJohn Snow 
1585684d5013SJohn Snow 
1586a2623021SJason Baron         /*
1587e8ef8743SPaolo Bonzini          * If an error is present, ad->busy_slot will be valid and not -1.
1588e8ef8743SPaolo Bonzini          * In this case, an operation is waiting to resume and will re-check
1589e8ef8743SPaolo Bonzini          * for additional AHCI commands to execute upon completion.
1590e8ef8743SPaolo Bonzini          *
1591e8ef8743SPaolo Bonzini          * In the case where no error was present, busy_slot will be -1,
1592e8ef8743SPaolo Bonzini          * and we should check to see if there are additional commands waiting.
1593a2623021SJason Baron          */
1594e8ef8743SPaolo Bonzini         if (ad->busy_slot == -1) {
1595a2623021SJason Baron             check_cmd(s, i);
1596c27c73aaSJohn Snow         } else {
1597c27c73aaSJohn Snow             /* We are in the middle of a command, and may need to access
1598c27c73aaSJohn Snow              * the command header in guest memory again. */
1599c27c73aaSJohn Snow             if (ad->busy_slot < 0 || ad->busy_slot >= AHCI_MAX_CMDS) {
1600c27c73aaSJohn Snow                 return -1;
1601c27c73aaSJohn Snow             }
1602ee364416SJohn Snow             ad->cur_cmd = get_cmd_header(s, i, ad->busy_slot);
1603a2623021SJason Baron         }
1604e8ef8743SPaolo Bonzini     }
1605a2623021SJason Baron 
1606a2623021SJason Baron     return 0;
1607a2623021SJason Baron }
1608a2623021SJason Baron 
1609a2623021SJason Baron const VMStateDescription vmstate_ahci = {
1610a2623021SJason Baron     .name = "ahci",
1611a2623021SJason Baron     .version_id = 1,
1612a2623021SJason Baron     .post_load = ahci_state_post_load,
1613a2623021SJason Baron     .fields = (VMStateField[]) {
1614a2623021SJason Baron         VMSTATE_STRUCT_VARRAY_POINTER_INT32(dev, AHCIState, ports,
1615a2623021SJason Baron                                      vmstate_ahci_device, AHCIDevice),
1616a2623021SJason Baron         VMSTATE_UINT32(control_regs.cap, AHCIState),
1617a2623021SJason Baron         VMSTATE_UINT32(control_regs.ghc, AHCIState),
1618a2623021SJason Baron         VMSTATE_UINT32(control_regs.irqstatus, AHCIState),
1619a2623021SJason Baron         VMSTATE_UINT32(control_regs.impl, AHCIState),
1620a2623021SJason Baron         VMSTATE_UINT32(control_regs.version, AHCIState),
1621a2623021SJason Baron         VMSTATE_UINT32(idp_index, AHCIState),
1622ae2158adSMichael S. Tsirkin         VMSTATE_INT32_EQUAL(ports, AHCIState),
1623a2623021SJason Baron         VMSTATE_END_OF_LIST()
1624a2623021SJason Baron     },
1625a2623021SJason Baron };
1626a2623021SJason Baron 
1627d9fa31a3SRob Herring static const VMStateDescription vmstate_sysbus_ahci = {
1628d9fa31a3SRob Herring     .name = "sysbus-ahci",
1629a2623021SJason Baron     .fields = (VMStateField[]) {
1630bd164307SRob Herring         VMSTATE_AHCI(ahci, SysbusAHCIState),
1631a2623021SJason Baron         VMSTATE_END_OF_LIST()
1632a2623021SJason Baron     },
1633d9fa31a3SRob Herring };
1634d9fa31a3SRob Herring 
16358ab60a07SJan Kiszka static void sysbus_ahci_reset(DeviceState *dev)
16368ab60a07SJan Kiszka {
1637b3b162c3SHu Tao     SysbusAHCIState *s = SYSBUS_AHCI(dev);
16388ab60a07SJan Kiszka 
16398ab60a07SJan Kiszka     ahci_reset(&s->ahci);
16408ab60a07SJan Kiszka }
16418ab60a07SJan Kiszka 
16427acb423fSHu Tao static void sysbus_ahci_realize(DeviceState *dev, Error **errp)
1643d9fa31a3SRob Herring {
16447acb423fSHu Tao     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
1645b3b162c3SHu Tao     SysbusAHCIState *s = SYSBUS_AHCI(dev);
1646d9fa31a3SRob Herring 
1647bd164307SRob Herring     ahci_init(&s->ahci, dev, &address_space_memory, s->num_ports);
16487acb423fSHu Tao 
16497acb423fSHu Tao     sysbus_init_mmio(sbd, &s->ahci.mem);
16507acb423fSHu Tao     sysbus_init_irq(sbd, &s->ahci.irq);
1651d9fa31a3SRob Herring }
1652d9fa31a3SRob Herring 
165339bffca2SAnthony Liguori static Property sysbus_ahci_properties[] = {
165439bffca2SAnthony Liguori     DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, num_ports, 1),
165539bffca2SAnthony Liguori     DEFINE_PROP_END_OF_LIST(),
165639bffca2SAnthony Liguori };
165739bffca2SAnthony Liguori 
1658999e12bbSAnthony Liguori static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
1659999e12bbSAnthony Liguori {
166039bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
1661999e12bbSAnthony Liguori 
16627acb423fSHu Tao     dc->realize = sysbus_ahci_realize;
166339bffca2SAnthony Liguori     dc->vmsd = &vmstate_sysbus_ahci;
166439bffca2SAnthony Liguori     dc->props = sysbus_ahci_properties;
16658ab60a07SJan Kiszka     dc->reset = sysbus_ahci_reset;
1666125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1667999e12bbSAnthony Liguori }
1668999e12bbSAnthony Liguori 
16698c43a6f0SAndreas Färber static const TypeInfo sysbus_ahci_info = {
1670b3b162c3SHu Tao     .name          = TYPE_SYSBUS_AHCI,
167139bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
167239bffca2SAnthony Liguori     .instance_size = sizeof(SysbusAHCIState),
1673999e12bbSAnthony Liguori     .class_init    = sysbus_ahci_class_init,
1674d9fa31a3SRob Herring };
1675d9fa31a3SRob Herring 
167683f7d43aSAndreas Färber static void sysbus_ahci_register_types(void)
1677d9fa31a3SRob Herring {
167839bffca2SAnthony Liguori     type_register_static(&sysbus_ahci_info);
1679d9fa31a3SRob Herring }
1680d9fa31a3SRob Herring 
168183f7d43aSAndreas Färber type_init(sysbus_ahci_register_types)
1682d93162e1SJohn Snow 
1683d93162e1SJohn Snow void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd)
1684d93162e1SJohn Snow {
1685d93162e1SJohn Snow     AHCIPCIState *d = ICH_AHCI(dev);
1686d93162e1SJohn Snow     AHCIState *ahci = &d->ahci;
1687d93162e1SJohn Snow     int i;
1688d93162e1SJohn Snow 
1689d93162e1SJohn Snow     for (i = 0; i < ahci->ports; i++) {
1690d93162e1SJohn Snow         if (hd[i] == NULL) {
1691d93162e1SJohn Snow             continue;
1692d93162e1SJohn Snow         }
1693d93162e1SJohn Snow         ide_create_drive(&ahci->dev[i].port, 0, hd[i]);
1694d93162e1SJohn Snow     }
1695d93162e1SJohn Snow 
1696d93162e1SJohn Snow }
1697