s->dev[port].finished |= finished;
*(uint32_t*)(sdb_fis + 4) = cpu_to_le32(s->dev[port].finished);
- ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_STAT_SDBS);
+ ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_SDB_FIS);
+}
+
+static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
+{
+ AHCIPortRegs *pr = &ad->port_regs;
+ uint8_t *pio_fis, *cmd_fis;
+ uint64_t tbl_addr;
+ dma_addr_t cmd_len = 0x80;
+
+ if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
+ return;
+ }
+
+ /* map cmd_fis */
+ tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr);
+ cmd_fis = dma_memory_map(ad->hba->as, tbl_addr, &cmd_len,
+ DMA_DIRECTION_TO_DEVICE);
+
+ if (cmd_fis == NULL) {
+ DPRINTF(ad->port_no, "dma_memory_map failed in ahci_write_fis_pio");
+ ahci_trigger_irq(ad->hba, ad, PORT_IRQ_HBUS_ERR);
+ return;
+ }
+
+ if (cmd_len != 0x80) {
+ DPRINTF(ad->port_no,
+ "dma_memory_map mapped too few bytes in ahci_write_fis_pio");
+ dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len,
+ DMA_DIRECTION_TO_DEVICE, cmd_len);
+ ahci_trigger_irq(ad->hba, ad, PORT_IRQ_HBUS_ERR);
+ return;
+ }
+
+ pio_fis = &ad->res_fis[RES_FIS_PSFIS];
+
+ 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[12] = cmd_fis[12];
+ pio_fis[13] = cmd_fis[13];
+ pio_fis[14] = 0;
+ pio_fis[15] = ad->port.ifs[0].status;
+ pio_fis[16] = len & 255;
+ pio_fis[17] = len >> 8;
+ pio_fis[18] = 0;
+ pio_fis[19] = 0;
+
+ if (pio_fis[2] & ERR_STAT) {
+ ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR);
+ }
+
+ ahci_trigger_irq(ad->hba, ad, PORT_IRQ_PIOS_FIS);
+
+ dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len,
+ DMA_DIRECTION_TO_DEVICE, cmd_len);
}
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
}
if (d2h_fis[2] & ERR_STAT) {
- ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_TFES);
+ ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR);
}
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
DPRINTF(ncq_tfs->drive->port_no, "NCQ transfer tag %d finished\n",
ncq_tfs->tag);
- bdrv_acct_done(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct);
+ block_acct_done(bdrv_get_stats(ncq_tfs->drive->port.ifs[0].bs),
+ &ncq_tfs->acct);
qemu_sglist_destroy(&ncq_tfs->sglist);
ncq_tfs->used = 0;
}
ncq_tfs->tag, ncq_tfs->lba);
dma_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
- &ncq_tfs->sglist, BDRV_ACCT_READ);
+ &ncq_tfs->sglist, BLOCK_ACCT_READ);
ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs,
&ncq_tfs->sglist, ncq_tfs->lba,
ncq_cb, ncq_tfs);
ncq_tfs->tag, ncq_tfs->lba);
dma_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct,
- &ncq_tfs->sglist, BDRV_ACCT_WRITE);
+ &ncq_tfs->sglist, BLOCK_ACCT_WRITE);
ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs,
&ncq_tfs->sglist, ncq_tfs->lba,
ncq_cb, ncq_tfs);
/* We're ready to process the command in FIS byte 2. */
ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
-
- if ((s->dev[port].port.ifs[0].status & (READY_STAT|DRQ_STAT|BUSY_STAT)) ==
- READY_STAT) {
- ahci_write_fis_d2h(&s->dev[port], cmd_fis);
- }
}
out:
s->end_transfer_func(s);
if (!(s->status & DRQ_STAT)) {
- /* done with DMA */
- ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
+ /* done with PIO send/receive */
+ ahci_write_fis_pio(ad, le32_to_cpu(ad->cur_cmd->status));
}
}
return 0;
}
-static void ahci_async_cmd_done(IDEDMA *dma)
+static void ahci_cmd_done(IDEDMA *dma)
{
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
- DPRINTF(ad->port_no, "async cmd done\n");
+ DPRINTF(ad->port_no, "cmd done\n");
/* update d2h status */
ahci_write_fis_d2h(ad, NULL);
.prepare_buf = ahci_dma_prepare_buf,
.rw_buf = ahci_dma_rw_buf,
.set_unit = ahci_dma_set_unit,
- .async_cmd_done = ahci_async_cmd_done,
+ .cmd_done = ahci_cmd_done,
.restart_cb = ahci_dma_restart_cb,
};
s->as = as;
s->ports = ports;
- s->dev = g_malloc0(sizeof(AHCIDevice) * ports);
+ s->dev = g_new0(AHCIDevice, ports);
ahci_reg_init(s);
/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
memory_region_init_io(&s->mem, OBJECT(qdev), &ahci_mem_ops, s,
void ahci_uninit(AHCIState *s)
{
- memory_region_destroy(&s->mem);
- memory_region_destroy(&s->idp);
g_free(s->dev);
}