Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/jnsnow/tags/ide-pull-request' i…
Browse files Browse the repository at this point in the history
…nto staging

# gpg: Signature made Wed 10 Feb 2016 19:23:29 GMT using RSA key ID AAFC390E
# gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>"

* remotes/jnsnow/tags/ide-pull-request:
  ahci: prohibit "restarting" the FIS or CLB engines
  ahci: explicitly reject bad engine states on post_load
  ahci: handle LIST_ON and FIS_ON in map helpers
  ahci: Do not unmap NULL addresses
  fdc: always compile-check debug prints
  ide: fix device_reset to not ignore pending AIO
  ide: Add silent DRQ cancellation
  ide: replace blk_drain_all by blk_drain
  ide: move buffered DMA cancel to core
  ide: code motion
  ide: Prohibit RESET on IDE drives

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Feb 11, 2016
2 parents 36a9abd + d590474 commit f163684
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 153 deletions.
15 changes: 8 additions & 7 deletions hw/block/fdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@

/********************************************************/
/* debug Floppy devices */
//#define DEBUG_FLOPPY

#ifdef DEBUG_FLOPPY
#define DEBUG_FLOPPY 0

#define FLOPPY_DPRINTF(fmt, ...) \
do { printf("FLOPPY: " fmt , ## __VA_ARGS__); } while (0)
#else
#define FLOPPY_DPRINTF(fmt, ...)
#endif
do { \
if (DEBUG_FLOPPY) { \
fprintf(stderr, "FLOPPY: " fmt , ## __VA_ARGS__); \
} \
} while (0)

/********************************************************/
/* Floppy drive emulation */
Expand Down Expand Up @@ -353,7 +354,7 @@ static int pick_geometry(FDrive *drv)
parse = &fd_formats[size_match];
FLOPPY_DPRINTF("User requested floppy drive type '%s', "
"but inserted medium appears to be a "
"%d sector '%s' type\n",
"%"PRId64" sector '%s' type\n",
FloppyDriveType_lookup[drv->drive],
nb_sectors,
FloppyDriveType_lookup[parse->drive]);
Expand Down
98 changes: 60 additions & 38 deletions hw/ide/ahci.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,52 +199,38 @@ static void map_page(AddressSpace *as, uint8_t **ptr, uint64_t addr,
* Check the cmd register to see if we should start or stop
* the DMA or FIS RX engines.
*
* @ad: Device to engage.
* @allow_stop: Allow device to transition from started to stopped?
* 'no' is useful for migration post_load, which does not expect a transition.
* @ad: Device to dis/engage.
*
* @return 0 on success, -1 on error.
*/
static int ahci_cond_start_engines(AHCIDevice *ad, bool allow_stop)
static int ahci_cond_start_engines(AHCIDevice *ad)
{
AHCIPortRegs *pr = &ad->port_regs;

if (pr->cmd & PORT_CMD_START) {
if (ahci_map_clb_address(ad)) {
pr->cmd |= PORT_CMD_LIST_ON;
} else {
bool cmd_start = pr->cmd & PORT_CMD_START;
bool cmd_on = pr->cmd & PORT_CMD_LIST_ON;
bool fis_start = pr->cmd & PORT_CMD_FIS_RX;
bool fis_on = pr->cmd & PORT_CMD_FIS_ON;

if (cmd_start && !cmd_on) {
if (!ahci_map_clb_address(ad)) {
pr->cmd &= ~PORT_CMD_START;
error_report("AHCI: Failed to start DMA engine: "
"bad command list buffer address");
return -1;
}
} else if (pr->cmd & PORT_CMD_LIST_ON) {
if (allow_stop) {
ahci_unmap_clb_address(ad);
pr->cmd = pr->cmd & ~(PORT_CMD_LIST_ON);
} else {
error_report("AHCI: DMA engine should be off, "
"but appears to still be running");
return -1;
}
} else if (!cmd_start && cmd_on) {
ahci_unmap_clb_address(ad);
}

if (pr->cmd & PORT_CMD_FIS_RX) {
if (ahci_map_fis_address(ad)) {
pr->cmd |= PORT_CMD_FIS_ON;
} else {
if (fis_start && !fis_on) {
if (!ahci_map_fis_address(ad)) {
pr->cmd &= ~PORT_CMD_FIS_RX;
error_report("AHCI: Failed to start FIS receive engine: "
"bad FIS receive buffer address");
return -1;
}
} else if (pr->cmd & PORT_CMD_FIS_ON) {
if (allow_stop) {
ahci_unmap_fis_address(ad);
pr->cmd = pr->cmd & ~(PORT_CMD_FIS_ON);
} else {
error_report("AHCI: FIS receive engine should be off, "
"but appears to still be running");
return -1;
}
} else if (!fis_start && fis_on) {
ahci_unmap_fis_address(ad);
}

return 0;
Expand Down Expand Up @@ -286,8 +272,8 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
pr->cmd = (pr->cmd & PORT_CMD_RO_MASK) |
(val & ~(PORT_CMD_RO_MASK|PORT_CMD_ICC_MASK));

/* Check FIS RX and CLB engines, allow transition to false: */
ahci_cond_start_engines(&s->dev[port], true);
/* Check FIS RX and CLB engines */
ahci_cond_start_engines(&s->dev[port]);

/* XXX usually the FIS would be pending on the bus here and
issuing deferred until the OS enables FIS receival.
Expand Down Expand Up @@ -657,11 +643,22 @@ static bool ahci_map_fis_address(AHCIDevice *ad)
AHCIPortRegs *pr = &ad->port_regs;
map_page(ad->hba->as, &ad->res_fis,
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
return ad->res_fis != NULL;
if (ad->res_fis != NULL) {
pr->cmd |= PORT_CMD_FIS_ON;
return true;
}

pr->cmd &= ~PORT_CMD_FIS_ON;
return false;
}

static void ahci_unmap_fis_address(AHCIDevice *ad)
{
if (ad->res_fis == NULL) {
DPRINTF(ad->port_no, "Attempt to unmap NULL FIS address\n");
return;
}
ad->port_regs.cmd &= ~PORT_CMD_FIS_ON;
dma_memory_unmap(ad->hba->as, ad->res_fis, 256,
DMA_DIRECTION_FROM_DEVICE, 256);
ad->res_fis = NULL;
Expand All @@ -673,11 +670,22 @@ static bool ahci_map_clb_address(AHCIDevice *ad)
ad->cur_cmd = NULL;
map_page(ad->hba->as, &ad->lst,
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
return ad->lst != NULL;
if (ad->lst != NULL) {
pr->cmd |= PORT_CMD_LIST_ON;
return true;
}

pr->cmd &= ~PORT_CMD_LIST_ON;
return false;
}

static void ahci_unmap_clb_address(AHCIDevice *ad)
{
if (ad->lst == NULL) {
DPRINTF(ad->port_no, "Attempt to unmap NULL CLB address\n");
return;
}
ad->port_regs.cmd &= ~PORT_CMD_LIST_ON;
dma_memory_unmap(ad->hba->as, ad->lst, 1024,
DMA_DIRECTION_FROM_DEVICE, 1024);
ad->lst = NULL;
Expand Down Expand Up @@ -1552,14 +1560,28 @@ static int ahci_state_post_load(void *opaque, int version_id)
int i, j;
struct AHCIDevice *ad;
NCQTransferState *ncq_tfs;
AHCIPortRegs *pr;
AHCIState *s = opaque;

for (i = 0; i < s->ports; i++) {
ad = &s->dev[i];
pr = &ad->port_regs;

if (!(pr->cmd & PORT_CMD_START) && (pr->cmd & PORT_CMD_LIST_ON)) {
error_report("AHCI: DMA engine should be off, but status bit "
"indicates it is still running.");
return -1;
}
if (!(pr->cmd & PORT_CMD_FIS_RX) && (pr->cmd & PORT_CMD_FIS_ON)) {
error_report("AHCI: FIS RX engine should be off, but status bit "
"indicates it is still running.");
return -1;
}

/* Only remap the CLB address if appropriate, disallowing a state
* transition from 'on' to 'off' it should be consistent here. */
if (ahci_cond_start_engines(ad, false) != 0) {
/* After a migrate, the DMA/FIS engines are "off" and
* need to be conditionally restarted */
pr->cmd &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON);
if (ahci_cond_start_engines(ad) != 0) {
return -1;
}

Expand Down
Loading

0 comments on commit f163684

Please sign in to comment.