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

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



# gpg: Signature made Fri 18 Sep 2015 15:59:02 BST using RSA key ID AAFC390E
# gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>"

* remotes/jnsnow/tags/ide-pull-request:
  ahci: clean up initial d2h semantics
  ahci: remove cmd_fis argument from write_fis_d2h
  ahci: fix signature generation
  ahci: remove dead reset code
  atapi: abort transfers with 0 byte limits
  ide: fix ATAPI command permissions
  ide-test: add cdrom dma test
  ide-test: add cdrom pio test
  qtest/ahci: export generate_pattern
  qtest/ahci: use generate_pattern everywhere
  ide: unify io_buffer_offset increments

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents ffa4822c e47f9eb1
Loading
Loading
Loading
Loading
+37 −38
Original line number Diff line number Diff line
@@ -46,10 +46,9 @@ do { \
static void check_cmd(AHCIState *s, int port);
static int handle_cmd(AHCIState *s, int port, uint8_t slot);
static void ahci_reset_port(AHCIState *s, int port);
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
static bool ahci_write_fis_d2h(AHCIDevice *ad);
static void ahci_init_d2h(AHCIDevice *ad);
static int ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit);
static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes);
static bool ahci_map_clb_address(AHCIDevice *ad);
static bool ahci_map_fis_address(AHCIDevice *ad);
static void ahci_unmap_clb_address(AHCIDevice *ad);
@@ -296,7 +295,6 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
            if ((pr->cmd & PORT_CMD_FIS_ON) &&
                !s->dev[port].init_d2h_sent) {
                ahci_init_d2h(&s->dev[port]);
                s->dev[port].init_d2h_sent = true;
            }

            check_cmd(s, port);
@@ -539,20 +537,33 @@ static void ahci_check_cmd_bh(void *opaque)

static void ahci_init_d2h(AHCIDevice *ad)
{
    uint8_t init_fis[20];
    IDEState *ide_state = &ad->port.ifs[0];
    AHCIPortRegs *pr = &ad->port_regs;

    memset(init_fis, 0, sizeof(init_fis));

    init_fis[4] = 1;
    init_fis[12] = 1;
    if (ad->init_d2h_sent) {
        return;
    }

    if (ide_state->drive_kind == IDE_CD) {
        init_fis[5] = ide_state->lcyl;
        init_fis[6] = ide_state->hcyl;
    if (ahci_write_fis_d2h(ad)) {
        ad->init_d2h_sent = true;
        /* We're emulating receiving the first Reg H2D Fis from the device;
         * Update the SIG register, but otherwise proceed as normal. */
        pr->sig = (ide_state->hcyl << 24) |
            (ide_state->lcyl << 16) |
            (ide_state->sector << 8) |
            (ide_state->nsector & 0xFF);
    }
}

    ahci_write_fis_d2h(ad, init_fis);
static void ahci_set_signature(AHCIDevice *ad, uint32_t sig)
{
    IDEState *s = &ad->port.ifs[0];
    s->hcyl = sig >> 24 & 0xFF;
    s->lcyl = sig >> 16 & 0xFF;
    s->sector = sig >> 8 & 0xFF;
    s->nsector = sig & 0xFF;

    DPRINTF(ad->port_no, "set hcyl:lcyl:sect:nsect = 0x%08x\n", sig);
}

static void ahci_reset_port(AHCIState *s, int port)
@@ -603,17 +614,11 @@ static void ahci_reset_port(AHCIState *s, int port)
    }

    s->dev[port].port_state = STATE_RUN;
    if (!ide_state->blk) {
        pr->sig = 0;
        ide_state->status = SEEK_STAT | WRERR_STAT;
    } else if (ide_state->drive_kind == IDE_CD) {
        pr->sig = SATA_SIGNATURE_CDROM;
        ide_state->lcyl = 0x14;
        ide_state->hcyl = 0xeb;
        DPRINTF(port, "set lcyl = %d\n", ide_state->lcyl);
    if (ide_state->drive_kind == IDE_CD) {
        ahci_set_signature(d, SATA_SIGNATURE_CDROM);\
        ide_state->status = SEEK_STAT | WRERR_STAT | READY_STAT;
    } else {
        pr->sig = SATA_SIGNATURE_DISK;
        ahci_set_signature(d, SATA_SIGNATURE_DISK);
        ide_state->status = SEEK_STAT | WRERR_STAT;
    }

@@ -749,7 +754,7 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
    ahci_trigger_irq(ad->hba, ad, PORT_IRQ_PIOS_FIS);
}

static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
static bool ahci_write_fis_d2h(AHCIDevice *ad)
{
    AHCIPortRegs *pr = &ad->port_regs;
    uint8_t *d2h_fis;
@@ -757,7 +762,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
    IDEState *s = &ad->port.ifs[0];

    if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
        return;
        return false;
    }

    d2h_fis = &ad->res_fis[RES_FIS_RFIS];
@@ -790,6 +795,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
    }

    ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
    return true;
}

static int prdt_tbl_entry_size(const AHCI_SG *tbl)
@@ -1289,7 +1295,7 @@ out:
    s->data_ptr = s->data_end;

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

    s->end_transfer_func(s);

@@ -1331,9 +1337,8 @@ static void ahci_restart(IDEDMA *dma)
}

/**
 * Called in DMA R/W chains to read the PRDT, utilizing ahci_populate_sglist.
 * Not currently invoked by PIO R/W chains,
 * which invoke ahci_populate_sglist via ahci_start_transfer.
 * Called in DMA and PIO R/W chains to read the PRDT.
 * Not shared with NCQ pathways.
 */
static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit)
{
@@ -1352,21 +1357,16 @@ static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit)
}

/**
 * Destroys the scatter-gather list,
 * and updates the command header with a bytes-read value.
 * called explicitly via ahci_dma_rw_buf (ATAPI DMA),
 * and ahci_start_transfer (PIO R/W),
 * and called via callback from ide_dma_cb for DMA R/W paths.
 * Updates the command header with a bytes-read value.
 * Called via dma_buf_commit, for both DMA and PIO paths.
 * sglist destruction is handled within dma_buf_commit.
 */
static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes)
{
    AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
    IDEState *s = &ad->port.ifs[0];

    tx_bytes += le32_to_cpu(ad->cur_cmd->status);
    ad->cur_cmd->status = cpu_to_le32(tx_bytes);

    qemu_sglist_destroy(&s->sg);
}

static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
@@ -1387,10 +1387,9 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
    }

    /* free sglist, update byte count */
    ahci_commit_buf(dma, l);
    dma_buf_commit(s, l);

    s->io_buffer_index += l;
    s->io_buffer_offset += l;

    DPRINTF(ad->port_no, "len=%#x\n", l);

@@ -1404,7 +1403,7 @@ static void ahci_cmd_done(IDEDMA *dma)
    DPRINTF(ad->port_no, "cmd done\n");

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

    if (!ad->check_bh) {
        /* maybe we still have something to process, check later */
+27 −5
Original line number Diff line number Diff line
@@ -1169,20 +1169,28 @@ enum {
     * 4.1.8)
     */
    CHECK_READY = 0x02,

    /*
     * Commands flagged with NONDATA do not in any circumstances return
     * any data via ide_atapi_cmd_reply. These commands are exempt from
     * the normal byte_count_limit constraints.
     * See ATA8-ACS3 "7.21.5 Byte Count Limit"
     */
    NONDATA = 0x04,
};

static const struct {
    void (*handler)(IDEState *s, uint8_t *buf);
    int flags;
} atapi_cmd_table[0x100] = {
    [ 0x00 ] = { cmd_test_unit_ready,               CHECK_READY },
    [ 0x00 ] = { cmd_test_unit_ready,               CHECK_READY | NONDATA },
    [ 0x03 ] = { cmd_request_sense,                 ALLOW_UA },
    [ 0x12 ] = { cmd_inquiry,                       ALLOW_UA },
    [ 0x1b ] = { cmd_start_stop_unit,               0 }, /* [1] */
    [ 0x1e ] = { cmd_prevent_allow_medium_removal,  0 },
    [ 0x1b ] = { cmd_start_stop_unit,               NONDATA }, /* [1] */
    [ 0x1e ] = { cmd_prevent_allow_medium_removal,  NONDATA },
    [ 0x25 ] = { cmd_read_cdvd_capacity,            CHECK_READY },
    [ 0x28 ] = { cmd_read, /* (10) */               CHECK_READY },
    [ 0x2b ] = { cmd_seek,                          CHECK_READY },
    [ 0x2b ] = { cmd_seek,                          CHECK_READY | NONDATA },
    [ 0x43 ] = { cmd_read_toc_pma_atip,             CHECK_READY },
    [ 0x46 ] = { cmd_get_configuration,             ALLOW_UA },
    [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
@@ -1190,7 +1198,7 @@ static const struct {
    [ 0x5a ] = { cmd_mode_sense, /* (10) */         0 },
    [ 0xa8 ] = { cmd_read, /* (12) */               CHECK_READY },
    [ 0xad ] = { cmd_read_dvd_structure,            CHECK_READY },
    [ 0xbb ] = { cmd_set_speed,                     0 },
    [ 0xbb ] = { cmd_set_speed,                     NONDATA },
    [ 0xbd ] = { cmd_mechanism_status,              0 },
    [ 0xbe ] = { cmd_read_cd,                       CHECK_READY },
    /* [1] handler detects and reports not ready condition itself */
@@ -1251,6 +1259,20 @@ void ide_atapi_cmd(IDEState *s)
        return;
    }

    /* Nondata commands permit the byte_count_limit to be 0.
     * If this is a data-transferring PIO command and BCL is 0,
     * we abort at the /ATA/ level, not the ATAPI level.
     * See ATA8 ACS3 section 7.17.6.49 and 7.21.5 */
    if (!(atapi_cmd_table[s->io_buffer[0]].flags & NONDATA)) {
        /* TODO: Check IDENTIFY data word 125 for default BCL (currently 0) */
        uint16_t byte_count_limit = s->lcyl | (s->hcyl << 8);
        if (!(byte_count_limit || s->atapi_dma)) {
            /* TODO: Move abort back into core.c and make static inline again */
            ide_abort_command(s);
            return;
        }
    }

    /* Execute the command */
    if (atapi_cmd_table[s->io_buffer[0]].handler) {
        atapi_cmd_table[s->io_buffer[0]].handler(s, buf);
+18 −19
Original line number Diff line number Diff line
@@ -457,7 +457,7 @@ BlockAIOCB *ide_issue_trim(BlockBackend *blk,
    return &iocb->common;
}

static inline void ide_abort_command(IDEState *s)
void ide_abort_command(IDEState *s)
{
    ide_transfer_stop(s);
    s->status = READY_STAT | ERR_STAT;
@@ -591,7 +591,6 @@ static void ide_sector_read_cb(void *opaque, int ret)
    s->nsector -= n;
    /* Allow the guest to read the io_buffer */
    ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);
    s->io_buffer_offset += 512 * n;
    ide_set_irq(s->bus);
}

@@ -635,11 +634,12 @@ static void ide_sector_read(IDEState *s)
                                 ide_sector_read_cb, s);
}

static void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
{
    if (s->bus->dma->ops->commit_buf) {
        s->bus->dma->ops->commit_buf(s->bus->dma, tx_bytes);
    }
    s->io_buffer_offset += tx_bytes;
    qemu_sglist_destroy(&s->sg);
}

@@ -842,7 +842,6 @@ static void ide_sector_write_cb(void *opaque, int ret)
        n = s->req_nb_sectors;
    }
    s->nsector -= n;
    s->io_buffer_offset += 512 * n;

    ide_set_sector(s, ide_get_sector(s) + n);
    if (s->nsector == 0) {
@@ -1747,11 +1746,11 @@ static const struct {
} ide_cmd_table[0x100] = {
    /* NOP not implemented, mandatory for CD */
    [CFA_REQ_EXT_ERROR_CODE]      = { cmd_cfa_req_ext_error_code, CFA_OK },
    [WIN_DSM]                     = { cmd_data_set_management, ALL_OK },
    [WIN_DSM]                     = { cmd_data_set_management, HD_CFA_OK },
    [WIN_DEVICE_RESET]            = { cmd_device_reset, CD_OK },
    [WIN_RECAL]                   = { cmd_nop, HD_CFA_OK | SET_DSC},
    [WIN_READ]                    = { cmd_read_pio, ALL_OK },
    [WIN_READ_ONCE]               = { cmd_read_pio, ALL_OK },
    [WIN_READ_ONCE]               = { cmd_read_pio, HD_CFA_OK },
    [WIN_READ_EXT]                = { cmd_read_pio, HD_CFA_OK },
    [WIN_READDMA_EXT]             = { cmd_read_dma, HD_CFA_OK },
    [WIN_READ_NATIVE_MAX_EXT]     = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
@@ -1770,12 +1769,12 @@ static const struct {
    [CFA_TRANSLATE_SECTOR]        = { cmd_cfa_translate_sector, CFA_OK },
    [WIN_DIAGNOSE]                = { cmd_exec_dev_diagnostic, ALL_OK },
    [WIN_SPECIFY]                 = { cmd_nop, HD_CFA_OK | SET_DSC },
    [WIN_STANDBYNOW2]             = { cmd_nop, ALL_OK },
    [WIN_IDLEIMMEDIATE2]          = { cmd_nop, ALL_OK },
    [WIN_STANDBY2]                = { cmd_nop, ALL_OK },
    [WIN_SETIDLE2]                = { cmd_nop, ALL_OK },
    [WIN_CHECKPOWERMODE2]         = { cmd_check_power_mode, ALL_OK | SET_DSC },
    [WIN_SLEEPNOW2]               = { cmd_nop, ALL_OK },
    [WIN_STANDBYNOW2]             = { cmd_nop, HD_CFA_OK },
    [WIN_IDLEIMMEDIATE2]          = { cmd_nop, HD_CFA_OK },
    [WIN_STANDBY2]                = { cmd_nop, HD_CFA_OK },
    [WIN_SETIDLE2]                = { cmd_nop, HD_CFA_OK },
    [WIN_CHECKPOWERMODE2]         = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
    [WIN_SLEEPNOW2]               = { cmd_nop, HD_CFA_OK },
    [WIN_PACKETCMD]               = { cmd_packet, CD_OK },
    [WIN_PIDENTIFY]               = { cmd_identify_packet, CD_OK },
    [WIN_SMART]                   = { cmd_smart, HD_CFA_OK | SET_DSC },
@@ -1789,19 +1788,19 @@ static const struct {
    [WIN_WRITEDMA]                = { cmd_write_dma, HD_CFA_OK },
    [WIN_WRITEDMA_ONCE]           = { cmd_write_dma, HD_CFA_OK },
    [CFA_WRITE_MULTI_WO_ERASE]    = { cmd_write_multiple, CFA_OK },
    [WIN_STANDBYNOW1]             = { cmd_nop, ALL_OK },
    [WIN_IDLEIMMEDIATE]           = { cmd_nop, ALL_OK },
    [WIN_STANDBY]                 = { cmd_nop, ALL_OK },
    [WIN_SETIDLE1]                = { cmd_nop, ALL_OK },
    [WIN_CHECKPOWERMODE1]         = { cmd_check_power_mode, ALL_OK | SET_DSC },
    [WIN_SLEEPNOW1]               = { cmd_nop, ALL_OK },
    [WIN_STANDBYNOW1]             = { cmd_nop, HD_CFA_OK },
    [WIN_IDLEIMMEDIATE]           = { cmd_nop, HD_CFA_OK },
    [WIN_STANDBY]                 = { cmd_nop, HD_CFA_OK },
    [WIN_SETIDLE1]                = { cmd_nop, HD_CFA_OK },
    [WIN_CHECKPOWERMODE1]         = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
    [WIN_SLEEPNOW1]               = { cmd_nop, HD_CFA_OK },
    [WIN_FLUSH_CACHE]             = { cmd_flush_cache, ALL_OK },
    [WIN_FLUSH_CACHE_EXT]         = { cmd_flush_cache, HD_CFA_OK },
    [WIN_IDENTIFY]                = { cmd_identify, ALL_OK },
    [WIN_SETFEATURES]             = { cmd_set_features, ALL_OK | SET_DSC },
    [IBM_SENSE_CONDITION]         = { cmd_ibm_sense_condition, CFA_OK | SET_DSC },
    [CFA_WEAR_LEVEL]              = { cmd_cfa_erase_sectors, HD_CFA_OK | SET_DSC },
    [WIN_READ_NATIVE_MAX]         = { cmd_read_native_max, ALL_OK | SET_DSC },
    [WIN_READ_NATIVE_MAX]         = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
};

static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
+2 −0
Original line number Diff line number Diff line
@@ -536,7 +536,9 @@ int64_t ide_get_sector(IDEState *s);
void ide_set_sector(IDEState *s, int64_t sector_num);

void ide_start_dma(IDEState *s, BlockCompletionFunc *cb);
void dma_buf_commit(IDEState *s, uint32_t tx_bytes);
void ide_dma_error(IDEState *s);
void ide_abort_command(IDEState *s);

void ide_atapi_cmd_ok(IDEState *s);
void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc);
+3 −40
Original line number Diff line number Diff line
@@ -71,32 +71,6 @@ static void string_bswap16(uint16_t *s, size_t bytes)
    }
}

static void generate_pattern(void *buffer, size_t len, size_t cycle_len)
{
    int i, j;
    unsigned char *tx = (unsigned char *)buffer;
    unsigned char p;
    size_t *sx;

    /* Write an indicative pattern that varies and is unique per-cycle */
    p = rand() % 256;
    for (i = j = 0; i < len; i++, j++) {
        tx[i] = p;
        if (j % cycle_len == 0) {
            p = rand() % 256;
        }
    }

    /* force uniqueness by writing an id per-cycle */
    for (i = 0; i < len / cycle_len; i++) {
        j = i * cycle_len;
        if (j + sizeof(*sx) <= len) {
            sx = (size_t *)&tx[j];
            *sx = i;
        }
    }
}

/**
 * Verify that the transfer did not corrupt our state at all.
 */
@@ -1155,7 +1129,6 @@ static void ahci_migrate_simple(uint8_t cmd_read, uint8_t cmd_write)
    size_t bufsize = 4096;
    unsigned char *tx = g_malloc(bufsize);
    unsigned char *rx = g_malloc0(bufsize);
    unsigned i;
    const char *uri = "tcp:127.0.0.1:1234";

    src = ahci_boot_and_enable("-m 1024 -M q35 "
@@ -1171,9 +1144,7 @@ static void ahci_migrate_simple(uint8_t cmd_read, uint8_t cmd_write)
    ahci_port_clear(src, px);

    /* create pattern */
    for (i = 0; i < bufsize; i++) {
        tx[i] = (bufsize - i);
    }
    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);

    /* Write, migrate, then read. */
    ahci_io(src, px, cmd_write, tx, bufsize, 0);
@@ -1213,7 +1184,6 @@ static void ahci_halted_io_test(uint8_t cmd_read, uint8_t cmd_write)
    size_t bufsize = 4096;
    unsigned char *tx = g_malloc(bufsize);
    unsigned char *rx = g_malloc0(bufsize);
    unsigned i;
    uint64_t ptr;
    AHCICommand *cmd;

@@ -1231,11 +1201,8 @@ static void ahci_halted_io_test(uint8_t cmd_read, uint8_t cmd_write)
    port = ahci_port_select(ahci);
    ahci_port_clear(ahci, port);

    for (i = 0; i < bufsize; i++) {
        tx[i] = (bufsize - i);
    }

    /* create DMA source buffer and write pattern */
    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);
    ptr = ahci_alloc(ahci, bufsize);
    g_assert(ptr);
    memwrite(ptr, tx, bufsize);
@@ -1282,7 +1249,6 @@ static void ahci_migrate_halted_io(uint8_t cmd_read, uint8_t cmd_write)
    size_t bufsize = 4096;
    unsigned char *tx = g_malloc(bufsize);
    unsigned char *rx = g_malloc0(bufsize);
    unsigned i;
    uint64_t ptr;
    AHCICommand *cmd;
    const char *uri = "tcp:127.0.0.1:1234";
@@ -1310,10 +1276,7 @@ static void ahci_migrate_halted_io(uint8_t cmd_read, uint8_t cmd_write)
    /* Initialize and prepare */
    port = ahci_port_select(src);
    ahci_port_clear(src, port);

    for (i = 0; i < bufsize; i++) {
        tx[i] = (bufsize - i);
    }
    generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE);

    /* create DMA source buffer and write pattern */
    ptr = ahci_alloc(src, bufsize);
Loading