Commit a7a7309c authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/jnsnow/tags/ide-pull-request' into staging



Pull request

# gpg: Signature made Fri 08 Jun 2018 18:46:24 BST
# gpg:                using RSA key 7DEF8106AAFC390E
# gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>"
# Primary key fingerprint: FAEB 9711 A12C F475 812F  18F2 88A9 064D 1835 61EB
#      Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76  CBD0 7DEF 8106 AAFC 390E

* remotes/jnsnow/tags/ide-pull-request: (30 commits)
  ide: introduce ide_transfer_start_norecurse
  atapi: call ide_set_irq before ide_transfer_start
  ide: make ide_transfer_stop idempotent
  ide: call ide_cmd_done from ide_transfer_stop
  ide: push end_transfer_func out of start_transfer callback, rename callback
  ahci: move PIO Setup FIS before transfer, fix it for ATAPI commands
  libqos/ahci: track sector size
  MAINTAINERS: Add the cdrom-test to John's section
  tests/cdrom-test: Test that -cdrom parameter is working
  tests/cdrom-test: Test booting from CD-ROM ISO image file
  tests/boot-sector: Add magic bytes to s390x boot code header
  ahci: make ahci_mem_write traces more descriptive
  ahci: delete old host register address definitions
  ahci: adjust ahci_mem_write to work on registers
  ahci: fix spacing damage on ahci_mem_write
  ahci: make mem_read_32 traces more descriptive
  ahci: modify ahci_mem_read_32 to work on register numbers
  ahci: fix host register max address
  ahci: add host register enumeration
  ahci: delete old port register address definitions
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 0d2fa03d c173723f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1003,6 +1003,7 @@ F: hw/block/cdrom.c
F: hw/block/hd-geometry.c
F: tests/ide-test.c
F: tests/ahci-test.c
F: tests/cdrom-test.c
F: tests/libqos/ahci*
T: git git://github.com/jnsnow/qemu.git ide

+216 −157
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include "hw/pci/pci.h"

#include "qemu/error-report.h"
#include "qemu/log.h"
#include "sysemu/block-backend.h"
#include "sysemu/dma.h"
#include "hw/ide/internal.h"
@@ -46,6 +47,44 @@ static bool ahci_map_fis_address(AHCIDevice *ad);
static void ahci_unmap_clb_address(AHCIDevice *ad);
static void ahci_unmap_fis_address(AHCIDevice *ad);

static const char *AHCIHostReg_lookup[AHCI_HOST_REG__COUNT] = {
    [AHCI_HOST_REG_CAP]        = "CAP",
    [AHCI_HOST_REG_CTL]        = "GHC",
    [AHCI_HOST_REG_IRQ_STAT]   = "IS",
    [AHCI_HOST_REG_PORTS_IMPL] = "PI",
    [AHCI_HOST_REG_VERSION]    = "VS",
    [AHCI_HOST_REG_CCC_CTL]    = "CCC_CTL",
    [AHCI_HOST_REG_CCC_PORTS]  = "CCC_PORTS",
    [AHCI_HOST_REG_EM_LOC]     = "EM_LOC",
    [AHCI_HOST_REG_EM_CTL]     = "EM_CTL",
    [AHCI_HOST_REG_CAP2]       = "CAP2",
    [AHCI_HOST_REG_BOHC]       = "BOHC",
};

static const char *AHCIPortReg_lookup[AHCI_PORT_REG__COUNT] = {
    [AHCI_PORT_REG_LST_ADDR]    = "PxCLB",
    [AHCI_PORT_REG_LST_ADDR_HI] = "PxCLBU",
    [AHCI_PORT_REG_FIS_ADDR]    = "PxFB",
    [AHCI_PORT_REG_FIS_ADDR_HI] = "PxFBU",
    [AHCI_PORT_REG_IRQ_STAT]    = "PxIS",
    [AHCI_PORT_REG_IRQ_MASK]    = "PXIE",
    [AHCI_PORT_REG_CMD]         = "PxCMD",
    [7]                         = "Reserved",
    [AHCI_PORT_REG_TFDATA]      = "PxTFD",
    [AHCI_PORT_REG_SIG]         = "PxSIG",
    [AHCI_PORT_REG_SCR_STAT]    = "PxSSTS",
    [AHCI_PORT_REG_SCR_CTL]     = "PxSCTL",
    [AHCI_PORT_REG_SCR_ERR]     = "PxSERR",
    [AHCI_PORT_REG_SCR_ACT]     = "PxSACT",
    [AHCI_PORT_REG_CMD_ISSUE]   = "PxCI",
    [AHCI_PORT_REG_SCR_NOTIF]   = "PxSNTF",
    [AHCI_PORT_REG_FIS_CTL]     = "PxFBS",
    [AHCI_PORT_REG_DEV_SLEEP]   = "PxDEVSLP",
    [18 ... 27]                 = "Reserved",
    [AHCI_PORT_REG_VENDOR_1 ...
     AHCI_PORT_REG_VENDOR_4]    = "PxVS",
};

static const char *AHCIPortIRQ_lookup[AHCI_PORT_IRQ__COUNT] = {
    [AHCI_PORT_IRQ_BIT_DHRS] = "DHRS",
    [AHCI_PORT_IRQ_BIT_PSS]  = "PSS",
@@ -71,38 +110,39 @@ static const char *AHCIPortIRQ_lookup[AHCI_PORT_IRQ__COUNT] = {
static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
{
    uint32_t val;
    AHCIPortRegs *pr;
    pr = &s->dev[port].port_regs;
    AHCIPortRegs *pr = &s->dev[port].port_regs;
    enum AHCIPortReg regnum = offset / sizeof(uint32_t);
    assert(regnum < (AHCI_PORT_ADDR_OFFSET_LEN / sizeof(uint32_t)));

    switch (offset) {
    case PORT_LST_ADDR:
    switch (regnum) {
    case AHCI_PORT_REG_LST_ADDR:
        val = pr->lst_addr;
        break;
    case PORT_LST_ADDR_HI:
    case AHCI_PORT_REG_LST_ADDR_HI:
        val = pr->lst_addr_hi;
        break;
    case PORT_FIS_ADDR:
    case AHCI_PORT_REG_FIS_ADDR:
        val = pr->fis_addr;
        break;
    case PORT_FIS_ADDR_HI:
    case AHCI_PORT_REG_FIS_ADDR_HI:
        val = pr->fis_addr_hi;
        break;
    case PORT_IRQ_STAT:
    case AHCI_PORT_REG_IRQ_STAT:
        val = pr->irq_stat;
        break;
    case PORT_IRQ_MASK:
    case AHCI_PORT_REG_IRQ_MASK:
        val = pr->irq_mask;
        break;
    case PORT_CMD:
    case AHCI_PORT_REG_CMD:
        val = pr->cmd;
        break;
    case PORT_TFDATA:
    case AHCI_PORT_REG_TFDATA:
        val = pr->tfdata;
        break;
    case PORT_SIG:
    case AHCI_PORT_REG_SIG:
        val = pr->sig;
        break;
    case PORT_SCR_STAT:
    case AHCI_PORT_REG_SCR_STAT:
        if (s->dev[port].port.ifs[0].blk) {
            val = SATA_SCR_SSTATUS_DET_DEV_PRESENT_PHY_UP |
                  SATA_SCR_SSTATUS_SPD_GEN1 | SATA_SCR_SSTATUS_IPM_ACTIVE;
@@ -110,28 +150,29 @@ static uint32_t ahci_port_read(AHCIState *s, int port, int offset)
            val = SATA_SCR_SSTATUS_DET_NODEV;
        }
        break;
    case PORT_SCR_CTL:
    case AHCI_PORT_REG_SCR_CTL:
        val = pr->scr_ctl;
        break;
    case PORT_SCR_ERR:
    case AHCI_PORT_REG_SCR_ERR:
        val = pr->scr_err;
        break;
    case PORT_SCR_ACT:
    case AHCI_PORT_REG_SCR_ACT:
        val = pr->scr_act;
        break;
    case PORT_CMD_ISSUE:
    case AHCI_PORT_REG_CMD_ISSUE:
        val = pr->cmd_issue;
        break;
    case PORT_RESERVED:
    default:
        trace_ahci_port_read_default(s, port, AHCIPortReg_lookup[regnum],
                                     offset);
        val = 0;
    }

    trace_ahci_port_read(s, port, offset, val);
    trace_ahci_port_read(s, port, AHCIPortReg_lookup[regnum], offset, val);
    return val;
}

static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
static void ahci_irq_raise(AHCIState *s)
{
    DeviceState *dev_state = s->container;
    PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
@@ -146,7 +187,7 @@ static void ahci_irq_raise(AHCIState *s, AHCIDevice *dev)
    }
}

static void ahci_irq_lower(AHCIState *s, AHCIDevice *dev)
static void ahci_irq_lower(AHCIState *s)
{
    DeviceState *dev_state = s->container;
    PCIDevice *pci_dev = (PCIDevice *) object_dynamic_cast(OBJECT(dev_state),
@@ -174,9 +215,9 @@ static void ahci_check_irq(AHCIState *s)
    trace_ahci_check_irq(s, old_irq, s->control_regs.irqstatus);
    if (s->control_regs.irqstatus &&
        (s->control_regs.ghc & HOST_CTL_IRQ_EN)) {
            ahci_irq_raise(s, NULL);
            ahci_irq_raise(s);
    } else {
        ahci_irq_lower(s, NULL);
        ahci_irq_lower(s);
    }
}

@@ -256,30 +297,32 @@ static int ahci_cond_start_engines(AHCIDevice *ad)
static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
{
    AHCIPortRegs *pr = &s->dev[port].port_regs;
    enum AHCIPortReg regnum = offset / sizeof(uint32_t);
    assert(regnum < (AHCI_PORT_ADDR_OFFSET_LEN / sizeof(uint32_t)));
    trace_ahci_port_write(s, port, AHCIPortReg_lookup[regnum], offset, val);

    trace_ahci_port_write(s, port, offset, val);
    switch (offset) {
        case PORT_LST_ADDR:
    switch (regnum) {
    case AHCI_PORT_REG_LST_ADDR:
        pr->lst_addr = val;
        break;
        case PORT_LST_ADDR_HI:
    case AHCI_PORT_REG_LST_ADDR_HI:
        pr->lst_addr_hi = val;
        break;
        case PORT_FIS_ADDR:
    case AHCI_PORT_REG_FIS_ADDR:
        pr->fis_addr = val;
        break;
        case PORT_FIS_ADDR_HI:
    case AHCI_PORT_REG_FIS_ADDR_HI:
        pr->fis_addr_hi = val;
        break;
        case PORT_IRQ_STAT:
    case AHCI_PORT_REG_IRQ_STAT:
        pr->irq_stat &= ~val;
        ahci_check_irq(s);
        break;
        case PORT_IRQ_MASK:
    case AHCI_PORT_REG_IRQ_MASK:
        pr->irq_mask = val & 0xfdc000ff;
        ahci_check_irq(s);
        break;
        case PORT_CMD:
    case AHCI_PORT_REG_CMD:
        /* Block any Read-only fields from being set;
         * including LIST_ON and FIS_ON.
         * The spec requires to set ICC bits to zero after the ICC change
@@ -303,34 +346,35 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)

        check_cmd(s, port);
        break;
        case PORT_TFDATA:
            /* Read Only. */
            break;
        case PORT_SIG:
            /* Read Only */
            break;
        case PORT_SCR_STAT:
    case AHCI_PORT_REG_TFDATA:
    case AHCI_PORT_REG_SIG:
    case AHCI_PORT_REG_SCR_STAT:
        /* Read Only */
        break;
        case PORT_SCR_CTL:
    case AHCI_PORT_REG_SCR_CTL:
        if (((pr->scr_ctl & AHCI_SCR_SCTL_DET) == 1) &&
            ((val & AHCI_SCR_SCTL_DET) == 0)) {
            ahci_reset_port(s, port);
        }
        pr->scr_ctl = val;
        break;
        case PORT_SCR_ERR:
    case AHCI_PORT_REG_SCR_ERR:
        pr->scr_err &= ~val;
        break;
        case PORT_SCR_ACT:
    case AHCI_PORT_REG_SCR_ACT:
        /* RW1 */
        pr->scr_act |= val;
        break;
        case PORT_CMD_ISSUE:
    case AHCI_PORT_REG_CMD_ISSUE:
        pr->cmd_issue |= val;
        check_cmd(s, port);
        break;
    default:
        trace_ahci_port_write_unimpl(s, port, AHCIPortReg_lookup[regnum],
                                     offset, val);
        qemu_log_mask(LOG_UNIMP, "Attempted write to unimplemented register: "
                      "AHCI port %d register %s, offset 0x%x: 0x%"PRIx32,
                      port, AHCIPortReg_lookup[regnum], offset, val);
        break;
    }
}
@@ -341,28 +385,37 @@ static uint64_t ahci_mem_read_32(void *opaque, hwaddr addr)
    uint32_t val = 0;

    if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
        switch (addr) {
        case HOST_CAP:
        enum AHCIHostReg regnum = addr / 4;
        assert(regnum < AHCI_HOST_REG__COUNT);

        switch (regnum) {
        case AHCI_HOST_REG_CAP:
            val = s->control_regs.cap;
            break;
        case HOST_CTL:
        case AHCI_HOST_REG_CTL:
            val = s->control_regs.ghc;
            break;
        case HOST_IRQ_STAT:
        case AHCI_HOST_REG_IRQ_STAT:
            val = s->control_regs.irqstatus;
            break;
        case HOST_PORTS_IMPL:
        case AHCI_HOST_REG_PORTS_IMPL:
            val = s->control_regs.impl;
            break;
        case HOST_VERSION:
        case AHCI_HOST_REG_VERSION:
            val = s->control_regs.version;
            break;
        default:
            trace_ahci_mem_read_32_host_default(s, AHCIHostReg_lookup[regnum],
                                                addr);
        }
        trace_ahci_mem_read_32_host(s, AHCIHostReg_lookup[regnum], addr, val);
    } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
               (addr < (AHCI_PORT_REGS_START_ADDR +
                (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
        val = ahci_port_read(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
                             addr & AHCI_PORT_ADDR_OFFSET_MASK);
    } else {
        trace_ahci_mem_read_32_default(s, addr, val);
    }

    trace_ahci_mem_read_32(s, addr, val);
@@ -415,11 +468,14 @@ static void ahci_mem_write(void *opaque, hwaddr addr,
    }

    if (addr < AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR) {
        switch (addr) {
            case HOST_CAP: /* R/WO, RO */
        enum AHCIHostReg regnum = addr / 4;
        assert(regnum < AHCI_HOST_REG__COUNT);

        switch (regnum) {
        case AHCI_HOST_REG_CAP: /* R/WO, RO */
            /* FIXME handle R/WO */
            break;
            case HOST_CTL: /* R/W */
        case AHCI_HOST_REG_CTL: /* R/W */
            if (val & HOST_CTL_RESET) {
                ahci_reset(s);
            } else {
@@ -427,26 +483,38 @@ static void ahci_mem_write(void *opaque, hwaddr addr,
                ahci_check_irq(s);
            }
            break;
            case HOST_IRQ_STAT: /* R/WC, RO */
        case AHCI_HOST_REG_IRQ_STAT: /* R/WC, RO */
            s->control_regs.irqstatus &= ~val;
            ahci_check_irq(s);
            break;
            case HOST_PORTS_IMPL: /* R/WO, RO */
        case AHCI_HOST_REG_PORTS_IMPL: /* R/WO, RO */
            /* FIXME handle R/WO */
            break;
            case HOST_VERSION: /* RO */
        case AHCI_HOST_REG_VERSION: /* RO */
            /* FIXME report write? */
            break;
        default:
                trace_ahci_mem_write_unknown(s, size, addr, val);
        }
            qemu_log_mask(LOG_UNIMP,
                          "Attempted write to unimplemented register: "
                          "AHCI host register %s, "
                          "offset 0x%"PRIx64": 0x%"PRIx64,
                          AHCIHostReg_lookup[regnum], addr, val);
            trace_ahci_mem_write_host_unimpl(s, size,
                                             AHCIHostReg_lookup[regnum], addr);
        }
        trace_ahci_mem_write_host(s, size, AHCIHostReg_lookup[regnum],
                                     addr, val);
    } else if ((addr >= AHCI_PORT_REGS_START_ADDR) &&
               (addr < (AHCI_PORT_REGS_START_ADDR +
                        (s->ports * AHCI_PORT_ADDR_OFFSET_LEN)))) {
        ahci_port_write(s, (addr - AHCI_PORT_REGS_START_ADDR) >> 7,
                        addr & AHCI_PORT_ADDR_OFFSET_MASK, val);
    } else {
        qemu_log_mask(LOG_UNIMP, "Attempted write to unimplemented register: "
                      "AHCI global register at offset 0x%"PRIx64": 0x%"PRIx64,
                      addr, val);
        trace_ahci_mem_write_unimpl(s, size, addr, val);
    }

}

static const MemoryRegionOps ahci_mem_ops = {
@@ -532,13 +600,6 @@ static void ahci_check_cmd_bh(void *opaque)
    qemu_bh_delete(ad->check_bh);
    ad->check_bh = NULL;

    if ((ad->busy_slot != -1) &&
        !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
        /* no longer busy */
        ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
        ad->busy_slot = -1;
    }

    check_cmd(ad->hba, ad->port_no);
}

@@ -1198,7 +1259,6 @@ static void handle_reg_h2d_fis(AHCIState *s, int port,
            g_free(pretty_fis);
        }
        s->dev[port].done_atapi_packet = false;
        /* XXX send PIO setup FIS */
    }

    ide_state->error = 0;
@@ -1280,8 +1340,8 @@ out:
    return 0;
}

/* DMA dev <-> ram */
static void ahci_start_transfer(IDEDMA *dma)
/* Transfer PIO data between RAM and device */
static void ahci_pio_transfer(IDEDMA *dma)
{
    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
    IDEState *s = &ad->port.ifs[0];
@@ -1292,10 +1352,12 @@ static void ahci_start_transfer(IDEDMA *dma)
    int is_atapi = opts & AHCI_CMD_ATAPI;
    int has_sglist = 0;

    /* PIO FIS gets written prior to transfer */
    ahci_write_fis_pio(ad, size);

    if (is_atapi && !ad->done_atapi_packet) {
        /* already prepopulated iobuffer */
        ad->done_atapi_packet = true;
        size = 0;
        goto out;
    }

@@ -1303,7 +1365,7 @@ static void ahci_start_transfer(IDEDMA *dma)
        has_sglist = 1;
    }

    trace_ahci_start_transfer(ad->hba, ad->port_no, is_write ? "writ" : "read",
    trace_ahci_pio_transfer(ad->hba, ad->port_no, is_write ? "writ" : "read",
                            size, is_atapi ? "atapi" : "ata",
                            has_sglist ? "" : "o");

@@ -1315,19 +1377,11 @@ static void ahci_start_transfer(IDEDMA *dma)
        }
    }

    /* Update number of transferred bytes, destroy sglist */
    dma_buf_commit(s, size);
out:
    /* declare that we processed everything */
    s->data_ptr = s->data_end;

    /* Update number of transferred bytes, destroy sglist */
    dma_buf_commit(s, size);

    s->end_transfer_func(s);

    if (!(s->status & DRQ_STAT)) {
        /* done with PIO send/receive */
        ahci_write_fis_pio(ad, le32_to_cpu(ad->cur_cmd->status));
    }
}

static void ahci_start_dma(IDEDMA *dma, IDEState *s,
@@ -1425,11 +1479,16 @@ static void ahci_cmd_done(IDEDMA *dma)

    trace_ahci_cmd_done(ad->hba, ad->port_no);

    /* no longer busy */
    if (ad->busy_slot != -1) {
        ad->port_regs.cmd_issue &= ~(1 << ad->busy_slot);
        ad->busy_slot = -1;
    }

    /* update d2h status */
    ahci_write_fis_d2h(ad);

    if (!ad->check_bh) {
        /* maybe we still have something to process, check later */
    if (ad->port_regs.cmd_issue && !ad->check_bh) {
        ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
        qemu_bh_schedule(ad->check_bh);
    }
@@ -1443,7 +1502,7 @@ static const IDEDMAOps ahci_dma_ops = {
    .start_dma = ahci_start_dma,
    .restart = ahci_restart,
    .restart_dma = ahci_restart_dma,
    .start_transfer = ahci_start_transfer,
    .pio_transfer = ahci_pio_transfer,
    .prepare_buf = ahci_dma_prepare_buf,
    .commit_buf = ahci_commit_buf,
    .rw_buf = ahci_dma_rw_buf,
+41 −22
Original line number Diff line number Diff line
@@ -55,11 +55,20 @@
#define RX_FIS_UNK                0x60 /* offset of Unknown FIS data */

/* global controller registers */
#define HOST_CAP                  0x00 /* host capabilities */
#define HOST_CTL                  0x04 /* global host control */
#define HOST_IRQ_STAT             0x08 /* interrupt status */
#define HOST_PORTS_IMPL           0x0c /* bitmap of implemented ports */
#define HOST_VERSION              0x10 /* AHCI spec. version compliancy */
enum AHCIHostReg {
    AHCI_HOST_REG_CAP        = 0,  /* CAP: host capabilities */
    AHCI_HOST_REG_CTL        = 1,  /* GHC: global host control */
    AHCI_HOST_REG_IRQ_STAT   = 2,  /* IS: interrupt status */
    AHCI_HOST_REG_PORTS_IMPL = 3,  /* PI: bitmap of implemented ports */
    AHCI_HOST_REG_VERSION    = 4,  /* VS: AHCI spec. version compliancy */
    AHCI_HOST_REG_CCC_CTL    = 5,  /* CCC_CTL: CCC Control */
    AHCI_HOST_REG_CCC_PORTS  = 6,  /* CCC_PORTS: CCC Ports */
    AHCI_HOST_REG_EM_LOC     = 7,  /* EM_LOC: Enclosure Mgmt Location */
    AHCI_HOST_REG_EM_CTL     = 8,  /* EM_CTL: Enclosure Mgmt Control */
    AHCI_HOST_REG_CAP2       = 9,  /* CAP2: host capabilities, extended */
    AHCI_HOST_REG_BOHC       = 10, /* BOHC: firmare/os handoff ctrl & status */
    AHCI_HOST_REG__COUNT     = 11
};

/* HOST_CTL bits */
#define HOST_CTL_RESET            (1 << 0)  /* reset controller; self-clear */
@@ -75,21 +84,32 @@
#define HOST_CAP_64               (1U << 31) /* PCI DAC (64-bit DMA) support */

/* registers for each SATA port */
#define PORT_LST_ADDR             0x00 /* command list DMA addr */
#define PORT_LST_ADDR_HI          0x04 /* command list DMA addr hi */
#define PORT_FIS_ADDR             0x08 /* FIS rx buf addr */
#define PORT_FIS_ADDR_HI          0x0c /* FIS rx buf addr hi */
#define PORT_IRQ_STAT             0x10 /* interrupt status */
#define PORT_IRQ_MASK             0x14 /* interrupt enable/disable mask */
#define PORT_CMD                  0x18 /* port command */
#define PORT_TFDATA               0x20 /* taskfile data */
#define PORT_SIG                  0x24 /* device TF signature */
#define PORT_SCR_STAT             0x28 /* SATA phy register: SStatus */
#define PORT_SCR_CTL              0x2c /* SATA phy register: SControl */
#define PORT_SCR_ERR              0x30 /* SATA phy register: SError */
#define PORT_SCR_ACT              0x34 /* SATA phy register: SActive */
#define PORT_CMD_ISSUE            0x38 /* command issue */
#define PORT_RESERVED             0x3c /* reserved */
enum AHCIPortReg {
    AHCI_PORT_REG_LST_ADDR    = 0, /* PxCLB: command list DMA addr */
    AHCI_PORT_REG_LST_ADDR_HI = 1, /* PxCLBU: command list DMA addr hi */
    AHCI_PORT_REG_FIS_ADDR    = 2, /* PxFB: FIS rx buf addr */
    AHCI_PORT_REG_FIS_ADDR_HI = 3, /* PxFBU: FIX rx buf addr hi */
    AHCI_PORT_REG_IRQ_STAT    = 4, /* PxIS: interrupt status */
    AHCI_PORT_REG_IRQ_MASK    = 5, /* PxIE: interrupt enable/disable mask */
    AHCI_PORT_REG_CMD         = 6, /* PxCMD: port command */
    /* RESERVED */
    AHCI_PORT_REG_TFDATA      = 8, /* PxTFD: taskfile data */
    AHCI_PORT_REG_SIG         = 9, /* PxSIG: device TF signature */
    AHCI_PORT_REG_SCR_STAT    = 10, /* PxSSTS: SATA phy register: SStatus */
    AHCI_PORT_REG_SCR_CTL     = 11, /* PxSCTL: SATA phy register: SControl */
    AHCI_PORT_REG_SCR_ERR     = 12, /* PxSERR: SATA phy register: SError */
    AHCI_PORT_REG_SCR_ACT     = 13, /* PxSACT: SATA phy register: SActive */
    AHCI_PORT_REG_CMD_ISSUE   = 14, /* PxCI: command issue */
    AHCI_PORT_REG_SCR_NOTIF   = 15, /* PxSNTF: SATA phy register: SNotification */
    AHCI_PORT_REG_FIS_CTL     = 16, /* PxFBS: Port multiplier switching ctl */
    AHCI_PORT_REG_DEV_SLEEP   = 17, /* PxDEVSLP: device sleep control */
    /* RESERVED */
    AHCI_PORT_REG_VENDOR_1    = 28, /* PxVS: Vendor Specific */
    AHCI_PORT_REG_VENDOR_2    = 29,
    AHCI_PORT_REG_VENDOR_3    = 30,
    AHCI_PORT_REG_VENDOR_4    = 31,
    AHCI_PORT_REG__COUNT      = 32
};

/* Port interrupt bit descriptors */
enum AHCIPortIRQ {
@@ -198,8 +218,7 @@ enum AHCIPortIRQ {
#define SATA_SIGNATURE_CDROM               0xeb140101
#define SATA_SIGNATURE_DISK                0x00000101

#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x20
                                            /* Shouldn't this be 0x2c? */
#define AHCI_GENERIC_HOST_CONTROL_REGS_MAX_ADDR 0x2c

#define AHCI_PORT_REGS_START_ADDR          0x100
#define AHCI_PORT_ADDR_OFFSET_MASK         0x7f
+24 −20
Original line number Diff line number Diff line
@@ -245,15 +245,11 @@ static uint16_t atapi_byte_count_limit(IDEState *s)
void ide_atapi_cmd_reply_end(IDEState *s)
{
    int byte_count_limit, size, ret;
    while (s->packet_transfer_size > 0) {
        trace_ide_atapi_cmd_reply_end(s, s->packet_transfer_size,
                                      s->elementary_transfer_size,
                                      s->io_buffer_index);
    if (s->packet_transfer_size <= 0) {
        /* end of transfer */
        ide_atapi_cmd_ok(s);
        ide_set_irq(s->bus);
        trace_ide_atapi_cmd_reply_end_eot(s, s->status);
    } else {

        /* see if a new sector must be read */
        if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) {
            if (!s->elementary_transfer_size) {
@@ -279,14 +275,10 @@ void ide_atapi_cmd_reply_end(IDEState *s)
            size = s->cd_sector_size - s->io_buffer_index;
            if (size > s->elementary_transfer_size)
                size = s->elementary_transfer_size;
            s->packet_transfer_size -= size;
            s->elementary_transfer_size -= size;
            s->io_buffer_index += size;
            ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
                               size, ide_atapi_cmd_reply_end);
        } else {
            /* a new transfer is needed */
            s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
            ide_set_irq(s->bus);
            byte_count_limit = atapi_byte_count_limit(s);
            trace_ide_atapi_cmd_reply_end_bcl(s, byte_count_limit);
            size = s->packet_transfer_size;
@@ -304,15 +296,27 @@ void ide_atapi_cmd_reply_end(IDEState *s)
                if (size > (s->cd_sector_size - s->io_buffer_index))
                    size = (s->cd_sector_size - s->io_buffer_index);
            }
            trace_ide_atapi_cmd_reply_end_new(s, s->status);
        }
        s->packet_transfer_size -= size;
        s->elementary_transfer_size -= size;
        s->io_buffer_index += size;
            ide_transfer_start(s, s->io_buffer + s->io_buffer_index - size,
                               size, ide_atapi_cmd_reply_end);
            ide_set_irq(s->bus);
            trace_ide_atapi_cmd_reply_end_new(s, s->status);

        /* Some adapters process PIO data right away.  In that case, we need
         * to avoid mutual recursion between ide_transfer_start
         * and ide_atapi_cmd_reply_end.
         */
        if (!ide_transfer_start_norecurse(s,
                                          s->io_buffer + s->io_buffer_index - size,
                                          size, ide_atapi_cmd_reply_end)) {
            return;
        }
    }

    /* end of transfer */
    trace_ide_atapi_cmd_reply_end_eot(s, s->status);
    ide_atapi_cmd_ok(s);
    ide_set_irq(s->bus);
}

/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */
+20 −19
Original line number Diff line number Diff line
@@ -523,18 +523,28 @@ static void ide_clear_retry(IDEState *s)
}

/* prepare data transfer and tell what to do after */
void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
bool ide_transfer_start_norecurse(IDEState *s, uint8_t *buf, int size,
                                  EndTransferFunc *end_transfer_func)
{
    s->end_transfer_func = end_transfer_func;
    s->data_ptr = buf;
    s->data_end = buf + size;
    ide_set_retry(s);
    if (!(s->status & ERR_STAT)) {
        s->status |= DRQ_STAT;
    }
    if (s->bus->dma->ops->start_transfer) {
        s->bus->dma->ops->start_transfer(s->bus->dma);
    if (!s->bus->dma->ops->pio_transfer) {
        s->end_transfer_func = end_transfer_func;
        return false;
    }
    s->bus->dma->ops->pio_transfer(s->bus->dma);
    return true;
}

void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
                        EndTransferFunc *end_transfer_func)
{
    if (ide_transfer_start_norecurse(s, buf, size, end_transfer_func)) {
        end_transfer_func(s);
    }
}

@@ -545,27 +555,18 @@ static void ide_cmd_done(IDEState *s)
    }
}

static void ide_transfer_halt(IDEState *s,
                              void(*end_transfer_func)(IDEState *),
                              bool notify)
static void ide_transfer_halt(IDEState *s)
{
    s->end_transfer_func = end_transfer_func;
    s->end_transfer_func = ide_transfer_stop;
    s->data_ptr = s->io_buffer;
    s->data_end = s->io_buffer;
    s->status &= ~DRQ_STAT;
    if (notify) {
        ide_cmd_done(s);
    }
}

void ide_transfer_stop(IDEState *s)
{
    ide_transfer_halt(s, ide_transfer_stop, true);
}

static void ide_transfer_cancel(IDEState *s)
{
    ide_transfer_halt(s, ide_transfer_cancel, false);
    ide_transfer_halt(s);
    ide_cmd_done(s);
}

int64_t ide_get_sector(IDEState *s)
@@ -1362,7 +1363,7 @@ static bool cmd_nop(IDEState *s, uint8_t cmd)
static bool cmd_device_reset(IDEState *s, uint8_t cmd)
{
    /* Halt PIO (in the DRQ phase), then DMA */
    ide_transfer_cancel(s);
    ide_transfer_halt(s);
    ide_cancel_dma_sync(s);

    /* Reset any PIO commands, reset signature, etc */
Loading