diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 571e32dd66..f25bef501d 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1259,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; @@ -1353,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; } @@ -1376,19 +1377,12 @@ 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, diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c index 63e1f9b92d..7264e085d0 100644 --- a/tests/libqos/ahci.c +++ b/tests/libqos/ahci.c @@ -478,10 +478,10 @@ void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot) g_free(d2h); } -void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port, - uint8_t slot, size_t buffsize) +void ahci_port_check_pio_sanity(AHCIQState *ahci, AHCICommand *cmd) { PIOSetupFIS *pio = g_malloc0(0x20); + uint8_t port = cmd->port; /* We cannot check the Status or E_Status registers, because * the status may have again changed between the PIO Setup FIS @@ -489,15 +489,22 @@ void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port, qtest_memread(ahci->parent->qts, ahci->port[port].fb + 0x20, pio, 0x20); g_assert_cmphex(pio->fis_type, ==, 0x5f); - /* BUG: PIO Setup FIS as utilized by QEMU tries to fit the entire - * transfer size in a uint16_t field. The maximum transfer size can - * eclipse this; the field is meant to convey the size of data per - * each Data FIS, not the entire operation as a whole. For now, - * we will sanity check the broken case where applicable. */ - if (buffsize <= UINT16_MAX) { - g_assert_cmphex(le16_to_cpu(pio->tx_count), ==, buffsize); + /* Data transferred by PIO will either be: + * (1) 12 or 16 bytes for an ATAPI command packet (QEMU always uses 12), or + * (2) Actual data from the drive. + * If we do both, (2) winds up erasing any evidence of (1). + */ + if (cmd->props->atapi && (cmd->xbytes == 0 || cmd->props->dma)) { + g_assert(le16_to_cpu(pio->tx_count) == 12 || + le16_to_cpu(pio->tx_count) == 16); + } else { + /* The AHCI test suite here does not test any PIO command that specifies + * a DRQ block larger than one sector (like 0xC4), so this should always + * be one sector or less. */ + size_t pio_len = ((cmd->xbytes % cmd->sector_size) ? + (cmd->xbytes % cmd->sector_size) : cmd->sector_size); + g_assert_cmphex(le16_to_cpu(pio->tx_count), ==, pio_len); } - g_free(pio); } @@ -832,9 +839,9 @@ void ahci_command_enable_atapi_dma(AHCICommand *cmd) RegH2DFIS *fis = &(cmd->fis); g_assert(cmd->props->atapi); fis->feature_low |= 0x01; - cmd->interrupts &= ~AHCI_PX_IS_PSS; + /* PIO is still used to transfer the ATAPI command */ + g_assert(cmd->props->pio); cmd->props->dma = true; - cmd->props->pio = false; /* BUG: We expect the DMA Setup interrupt for DMA commands */ /* cmd->interrupts |= AHCI_PX_IS_DSS; */ } @@ -846,7 +853,7 @@ AHCICommand *ahci_command_create(uint8_t command_name) g_assert(props); cmd = g_new0(AHCICommand, 1); - g_assert(!(props->dma && props->pio)); + g_assert(!(props->dma && props->pio) || props->atapi); g_assert(!(props->lba28 && props->lba48)); g_assert(!(props->read && props->write)); g_assert(!props->size || props->data); @@ -1218,7 +1225,7 @@ void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd) ahci_port_check_d2h_sanity(ahci, port, slot); } if (cmd->props->pio) { - ahci_port_check_pio_sanity(ahci, port, slot, cmd->xbytes); + ahci_port_check_pio_sanity(ahci, cmd); } } diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h index 715ca1e226..13f6d87b75 100644 --- a/tests/libqos/ahci.h +++ b/tests/libqos/ahci.h @@ -596,8 +596,7 @@ void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, uint32_t intr_mask); void ahci_port_check_nonbusy(AHCIQState *ahci, uint8_t port, uint8_t slot); void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot); -void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port, - uint8_t slot, size_t buffsize); +void ahci_port_check_pio_sanity(AHCIQState *ahci, AHCICommand *cmd); void ahci_port_check_cmd_sanity(AHCIQState *ahci, AHCICommand *cmd); /* Misc */