diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/block/dataplane/virtio-blk.c | 5 | ||||
-rw-r--r-- | hw/ide/ahci.c | 107 | ||||
-rw-r--r-- | hw/ide/ahci.h | 8 | ||||
-rw-r--r-- | hw/ide/core.c | 11 | ||||
-rw-r--r-- | hw/ide/internal.h | 2 |
5 files changed, 87 insertions, 46 deletions
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 45b1164c3e..1222a37f4f 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -196,6 +196,11 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, blk_op_block_all(conf->conf.blk, s->blocker); blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker); blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker); + blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker); + blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT, s->blocker); + blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_MIRROR, s->blocker); + blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker); + blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker); *dataplane = s; } diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 70958e3655..61dbed1b97 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -49,6 +49,9 @@ static int handle_cmd(AHCIState *s,int port,int slot); static void ahci_reset_port(AHCIState *s, int port); static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis); static void ahci_init_d2h(AHCIDevice *ad); +static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write); +static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes); + static uint32_t ahci_port_read(AHCIState *s, int port, int offset) { @@ -567,24 +570,24 @@ static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished) AHCIDevice *ad = &s->dev[port]; AHCIPortRegs *pr = &ad->port_regs; IDEState *ide_state; - uint8_t *sdb_fis; + SDBFIS *sdb_fis; if (!s->dev[port].res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) { return; } - sdb_fis = &ad->res_fis[RES_FIS_SDBFIS]; + sdb_fis = (SDBFIS *)&ad->res_fis[RES_FIS_SDBFIS]; ide_state = &ad->port.ifs[0]; - /* clear memory */ - *(uint32_t*)sdb_fis = 0; - - /* write values */ - sdb_fis[0] = ide_state->error; - sdb_fis[2] = ide_state->status & 0x77; + sdb_fis->type = 0xA1; + /* Interrupt pending & Notification bit */ + sdb_fis->flags = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0); + sdb_fis->status = ide_state->status & 0x77; + sdb_fis->error = ide_state->error; + /* update SAct field in SDB_FIS */ s->dev[port].finished |= finished; - *(uint32_t*)(sdb_fis + 4) = cpu_to_le32(ad->finished); + sdb_fis->payload = cpu_to_le32(ad->finished); /* Update shadow registers (except BSY 0x80 and DRQ 0x08) */ pr->tfdata = (ad->port.ifs[0].error << 8) | @@ -600,6 +603,7 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len) uint8_t *pio_fis, *cmd_fis; uint64_t tbl_addr; dma_addr_t cmd_len = 0x80; + IDEState *s = &ad->port.ifs[0]; if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) { return; @@ -629,21 +633,21 @@ static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len) pio_fis[0] = 0x5f; pio_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0); - pio_fis[2] = ad->port.ifs[0].status; - pio_fis[3] = ad->port.ifs[0].error; - - pio_fis[4] = cmd_fis[4]; - pio_fis[5] = cmd_fis[5]; - pio_fis[6] = cmd_fis[6]; - pio_fis[7] = cmd_fis[7]; - pio_fis[8] = cmd_fis[8]; - pio_fis[9] = cmd_fis[9]; - pio_fis[10] = cmd_fis[10]; - pio_fis[11] = cmd_fis[11]; + pio_fis[2] = s->status; + pio_fis[3] = s->error; + + pio_fis[4] = s->sector; + pio_fis[5] = s->lcyl; + pio_fis[6] = s->hcyl; + pio_fis[7] = s->select; + pio_fis[8] = s->hob_sector; + pio_fis[9] = s->hob_lcyl; + pio_fis[10] = s->hob_hcyl; + pio_fis[11] = 0; pio_fis[12] = cmd_fis[12]; pio_fis[13] = cmd_fis[13]; pio_fis[14] = 0; - pio_fis[15] = ad->port.ifs[0].status; + pio_fis[15] = s->status; pio_fis[16] = len & 255; pio_fis[17] = len >> 8; pio_fis[18] = 0; @@ -670,6 +674,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis) int i; dma_addr_t cmd_len = 0x80; int cmd_mapped = 0; + IDEState *s = &ad->port.ifs[0]; if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) { return; @@ -687,17 +692,17 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis) d2h_fis[0] = 0x34; d2h_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0); - d2h_fis[2] = ad->port.ifs[0].status; - d2h_fis[3] = ad->port.ifs[0].error; - - d2h_fis[4] = cmd_fis[4]; - d2h_fis[5] = cmd_fis[5]; - d2h_fis[6] = cmd_fis[6]; - d2h_fis[7] = cmd_fis[7]; - d2h_fis[8] = cmd_fis[8]; - d2h_fis[9] = cmd_fis[9]; - d2h_fis[10] = cmd_fis[10]; - d2h_fis[11] = cmd_fis[11]; + d2h_fis[2] = s->status; + d2h_fis[3] = s->error; + + d2h_fis[4] = s->sector; + d2h_fis[5] = s->lcyl; + d2h_fis[6] = s->hcyl; + d2h_fis[7] = s->select; + d2h_fis[8] = s->hob_sector; + d2h_fis[9] = s->hob_lcyl; + d2h_fis[10] = s->hob_hcyl; + d2h_fis[11] = 0; d2h_fis[12] = cmd_fis[12]; d2h_fis[13] = cmd_fis[13]; for (i = 14; i < 20; i++) { @@ -1103,16 +1108,12 @@ static void ahci_start_transfer(IDEDMA *dma) } } - /* update number of transferred bytes */ - ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + size); - out: /* declare that we processed everything */ s->data_ptr = s->data_end; - if (has_sglist) { - qemu_sglist_destroy(&s->sg); - } + /* Update number of transferred bytes, destroy sglist */ + ahci_commit_buf(dma, size); s->end_transfer_func(s); @@ -1133,6 +1134,11 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s, dma_cb(s, 0); } +/** + * 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. + */ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); @@ -1145,6 +1151,24 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write) return s->io_buffer_size != 0; } +/** + * 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. + */ +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) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); @@ -1162,11 +1186,9 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write) dma_buf_write(p, l, &s->sg); } - /* free sglist that was created in ahci_populate_sglist() */ - qemu_sglist_destroy(&s->sg); + /* free sglist, update byte count */ + ahci_commit_buf(dma, l); - /* update number of transferred bytes */ - ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l); s->io_buffer_index += l; s->io_buffer_offset += l; @@ -1209,6 +1231,7 @@ static const IDEDMAOps ahci_dma_ops = { .start_dma = ahci_start_dma, .start_transfer = ahci_start_transfer, .prepare_buf = ahci_dma_prepare_buf, + .commit_buf = ahci_commit_buf, .rw_buf = ahci_dma_rw_buf, .set_unit = ahci_dma_set_unit, .cmd_done = ahci_cmd_done, diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index e8ea34a1df..b12323730b 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -327,6 +327,14 @@ typedef struct NCQFrame { uint8_t reserved10; } QEMU_PACKED NCQFrame; +typedef struct SDBFIS { + uint8_t type; + uint8_t flags; + uint8_t status; + uint8_t error; + uint32_t payload; +} QEMU_PACKED SDBFIS; + void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports); void ahci_uninit(AHCIState *s); diff --git a/hw/ide/core.c b/hw/ide/core.c index 44e3d502d4..d316ccf961 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -634,8 +634,11 @@ void ide_sector_read(IDEState *s) ide_sector_read_cb, s); } -static void dma_buf_commit(IDEState *s) +static 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); + } qemu_sglist_destroy(&s->sg); } @@ -650,6 +653,7 @@ void ide_set_inactive(IDEState *s, bool more) void ide_dma_error(IDEState *s) { + dma_buf_commit(s, 0); ide_abort_command(s); ide_set_inactive(s, false); ide_set_irq(s->bus); @@ -665,7 +669,6 @@ static int ide_handle_rw_error(IDEState *s, int error, int op) s->bus->error_status = op; } else if (action == BLOCK_ERROR_ACTION_REPORT) { if (op & IDE_RETRY_DMA) { - dma_buf_commit(s); ide_dma_error(s); } else { ide_rw_error(s); @@ -709,7 +712,8 @@ void ide_dma_cb(void *opaque, int ret) sector_num = ide_get_sector(s); if (n > 0) { - dma_buf_commit(s); + assert(s->io_buffer_size == s->sg.size); + dma_buf_commit(s, s->io_buffer_size); sector_num += n; ide_set_sector(s, sector_num); s->nsector -= n; @@ -740,7 +744,6 @@ void ide_dma_cb(void *opaque, int ret) if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) && !ide_sect_range_ok(s, sector_num, n)) { - dma_buf_commit(s); ide_dma_error(s); return; } diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 68ac610d6f..907493d0f8 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -322,6 +322,7 @@ typedef void EndTransferFunc(IDEState *); typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockCompletionFunc *); typedef void DMAVoidFunc(IDEDMA *); typedef int DMAIntFunc(IDEDMA *, int); +typedef void DMAu32Func(IDEDMA *, uint32_t); typedef void DMAStopFunc(IDEDMA *, bool); typedef void DMARestartFunc(void *, int, RunState); @@ -430,6 +431,7 @@ struct IDEDMAOps { DMAStartFunc *start_dma; DMAVoidFunc *start_transfer; DMAIntFunc *prepare_buf; + DMAu32Func *commit_buf; DMAIntFunc *rw_buf; DMAIntFunc *set_unit; DMAStopFunc *set_inactive; |