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