-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQIcBAABAgAGBQJWu44xAAoJEH3vgQaq/DkOegcP/0Nkwp6IhnoN60rqoqnwpRCA GIB2TIU23RrujH49YtssmjI8BTa0vruip96SHfuglwBclPwn8E2mIec9bwdfZkqT yE+g+WD9li0WODgcEFvefVzDxFCV65ZOTUjzKyA37OZIrCsgZMNQYvOG6R/ftHVm srydXF8R3fXahf9V9ggXZFbH+Pcf/Q89gz4So+rJzqW9K1f+NWVWl5hPBEX7eT/e t7biB//rcM6z2fMGYt+USnoznI447rsooukmS7BVs6AlVyQztWI7lAbJ5uhcUKYL Exu+fMY6tz0KiRx0xatB557MlK/dkBja7t5ga2cFVSo66aOrloLIZrCF9vIH4fJv ekfzehxZgGxzhCIhbgz4SCgKzBh2nTD//YpcthnumGSTpAGd8ohQonyVEgKSR0Pw Sdq5Epnc7QNU0TSK+yO96vxb5EI+2Qi4DqYnSdM/25qylv7Yu3S0WATcvAe23fyh TwloE/St2iz8Hly5kiAeINvTF/9UxzM3kczLDh6y0Ikyna16+ccODAbDMPfl8n58 crMckCkVUCXz5ySsgfmbRcZr/emZb2rDQCgNECosJBTQCAi+m0vvvdKXj25IiPtk ltpBDYVDyuETHSj3VtJCC/XEUOq9PfxNn3chO8ckSKjLWge2UP3UlASz1GHyBsKH EIPZUD7l3q2rkdustnkt =WuDA -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/jnsnow/tags/ide-pull-request' into 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>
This commit is contained in:
commit
f163684599
@ -41,14 +41,15 @@
|
|||||||
|
|
||||||
/********************************************************/
|
/********************************************************/
|
||||||
/* debug Floppy devices */
|
/* debug Floppy devices */
|
||||||
//#define DEBUG_FLOPPY
|
|
||||||
|
|
||||||
#ifdef DEBUG_FLOPPY
|
#define DEBUG_FLOPPY 0
|
||||||
|
|
||||||
#define FLOPPY_DPRINTF(fmt, ...) \
|
#define FLOPPY_DPRINTF(fmt, ...) \
|
||||||
do { printf("FLOPPY: " fmt , ## __VA_ARGS__); } while (0)
|
do { \
|
||||||
#else
|
if (DEBUG_FLOPPY) { \
|
||||||
#define FLOPPY_DPRINTF(fmt, ...)
|
fprintf(stderr, "FLOPPY: " fmt , ## __VA_ARGS__); \
|
||||||
#endif
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/********************************************************/
|
/********************************************************/
|
||||||
/* Floppy drive emulation */
|
/* Floppy drive emulation */
|
||||||
@ -353,7 +354,7 @@ static int pick_geometry(FDrive *drv)
|
|||||||
parse = &fd_formats[size_match];
|
parse = &fd_formats[size_match];
|
||||||
FLOPPY_DPRINTF("User requested floppy drive type '%s', "
|
FLOPPY_DPRINTF("User requested floppy drive type '%s', "
|
||||||
"but inserted medium appears to be a "
|
"but inserted medium appears to be a "
|
||||||
"%d sector '%s' type\n",
|
"%"PRId64" sector '%s' type\n",
|
||||||
FloppyDriveType_lookup[drv->drive],
|
FloppyDriveType_lookup[drv->drive],
|
||||||
nb_sectors,
|
nb_sectors,
|
||||||
FloppyDriveType_lookup[parse->drive]);
|
FloppyDriveType_lookup[parse->drive]);
|
||||||
|
@ -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
|
* Check the cmd register to see if we should start or stop
|
||||||
* the DMA or FIS RX engines.
|
* the DMA or FIS RX engines.
|
||||||
*
|
*
|
||||||
* @ad: Device to engage.
|
* @ad: Device to dis/engage.
|
||||||
* @allow_stop: Allow device to transition from started to stopped?
|
|
||||||
* 'no' is useful for migration post_load, which does not expect a transition.
|
|
||||||
*
|
*
|
||||||
* @return 0 on success, -1 on error.
|
* @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;
|
AHCIPortRegs *pr = &ad->port_regs;
|
||||||
|
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 (pr->cmd & PORT_CMD_START) {
|
if (cmd_start && !cmd_on) {
|
||||||
if (ahci_map_clb_address(ad)) {
|
if (!ahci_map_clb_address(ad)) {
|
||||||
pr->cmd |= PORT_CMD_LIST_ON;
|
pr->cmd &= ~PORT_CMD_START;
|
||||||
} else {
|
|
||||||
error_report("AHCI: Failed to start DMA engine: "
|
error_report("AHCI: Failed to start DMA engine: "
|
||||||
"bad command list buffer address");
|
"bad command list buffer address");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else if (pr->cmd & PORT_CMD_LIST_ON) {
|
} else if (!cmd_start && cmd_on) {
|
||||||
if (allow_stop) {
|
ahci_unmap_clb_address(ad);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pr->cmd & PORT_CMD_FIS_RX) {
|
if (fis_start && !fis_on) {
|
||||||
if (ahci_map_fis_address(ad)) {
|
if (!ahci_map_fis_address(ad)) {
|
||||||
pr->cmd |= PORT_CMD_FIS_ON;
|
pr->cmd &= ~PORT_CMD_FIS_RX;
|
||||||
} else {
|
|
||||||
error_report("AHCI: Failed to start FIS receive engine: "
|
error_report("AHCI: Failed to start FIS receive engine: "
|
||||||
"bad FIS receive buffer address");
|
"bad FIS receive buffer address");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else if (pr->cmd & PORT_CMD_FIS_ON) {
|
} else if (!fis_start && fis_on) {
|
||||||
if (allow_stop) {
|
ahci_unmap_fis_address(ad);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -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) |
|
pr->cmd = (pr->cmd & PORT_CMD_RO_MASK) |
|
||||||
(val & ~(PORT_CMD_RO_MASK|PORT_CMD_ICC_MASK));
|
(val & ~(PORT_CMD_RO_MASK|PORT_CMD_ICC_MASK));
|
||||||
|
|
||||||
/* Check FIS RX and CLB engines, allow transition to false: */
|
/* Check FIS RX and CLB engines */
|
||||||
ahci_cond_start_engines(&s->dev[port], true);
|
ahci_cond_start_engines(&s->dev[port]);
|
||||||
|
|
||||||
/* XXX usually the FIS would be pending on the bus here and
|
/* XXX usually the FIS would be pending on the bus here and
|
||||||
issuing deferred until the OS enables FIS receival.
|
issuing deferred until the OS enables FIS receival.
|
||||||
@ -657,11 +643,22 @@ static bool ahci_map_fis_address(AHCIDevice *ad)
|
|||||||
AHCIPortRegs *pr = &ad->port_regs;
|
AHCIPortRegs *pr = &ad->port_regs;
|
||||||
map_page(ad->hba->as, &ad->res_fis,
|
map_page(ad->hba->as, &ad->res_fis,
|
||||||
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
|
((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)
|
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_memory_unmap(ad->hba->as, ad->res_fis, 256,
|
||||||
DMA_DIRECTION_FROM_DEVICE, 256);
|
DMA_DIRECTION_FROM_DEVICE, 256);
|
||||||
ad->res_fis = NULL;
|
ad->res_fis = NULL;
|
||||||
@ -673,11 +670,22 @@ static bool ahci_map_clb_address(AHCIDevice *ad)
|
|||||||
ad->cur_cmd = NULL;
|
ad->cur_cmd = NULL;
|
||||||
map_page(ad->hba->as, &ad->lst,
|
map_page(ad->hba->as, &ad->lst,
|
||||||
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
|
((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)
|
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_memory_unmap(ad->hba->as, ad->lst, 1024,
|
||||||
DMA_DIRECTION_FROM_DEVICE, 1024);
|
DMA_DIRECTION_FROM_DEVICE, 1024);
|
||||||
ad->lst = NULL;
|
ad->lst = NULL;
|
||||||
@ -1552,14 +1560,28 @@ static int ahci_state_post_load(void *opaque, int version_id)
|
|||||||
int i, j;
|
int i, j;
|
||||||
struct AHCIDevice *ad;
|
struct AHCIDevice *ad;
|
||||||
NCQTransferState *ncq_tfs;
|
NCQTransferState *ncq_tfs;
|
||||||
|
AHCIPortRegs *pr;
|
||||||
AHCIState *s = opaque;
|
AHCIState *s = opaque;
|
||||||
|
|
||||||
for (i = 0; i < s->ports; i++) {
|
for (i = 0; i < s->ports; i++) {
|
||||||
ad = &s->dev[i];
|
ad = &s->dev[i];
|
||||||
|
pr = &ad->port_regs;
|
||||||
|
|
||||||
/* Only remap the CLB address if appropriate, disallowing a state
|
if (!(pr->cmd & PORT_CMD_START) && (pr->cmd & PORT_CMD_LIST_ON)) {
|
||||||
* transition from 'on' to 'off' it should be consistent here. */
|
error_report("AHCI: DMA engine should be off, but status bit "
|
||||||
if (ahci_cond_start_engines(ad, false) != 0) {
|
"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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
217
hw/ide/core.c
217
hw/ide/core.c
@ -487,13 +487,27 @@ static void ide_cmd_done(IDEState *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ide_transfer_stop(IDEState *s)
|
static void ide_transfer_halt(IDEState *s,
|
||||||
|
void(*end_transfer_func)(IDEState *),
|
||||||
|
bool notify)
|
||||||
{
|
{
|
||||||
s->end_transfer_func = ide_transfer_stop;
|
s->end_transfer_func = end_transfer_func;
|
||||||
s->data_ptr = s->io_buffer;
|
s->data_ptr = s->io_buffer;
|
||||||
s->data_end = s->io_buffer;
|
s->data_end = s->io_buffer;
|
||||||
s->status &= ~DRQ_STAT;
|
s->status &= ~DRQ_STAT;
|
||||||
ide_cmd_done(s);
|
if (notify) {
|
||||||
|
ide_cmd_done(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ide_transfer_stop(IDEState *s)
|
||||||
|
{
|
||||||
|
ide_transfer_halt(s, ide_transfer_stop, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ide_transfer_cancel(IDEState *s)
|
||||||
|
{
|
||||||
|
ide_transfer_halt(s, ide_transfer_cancel, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t ide_get_sector(IDEState *s)
|
int64_t ide_get_sector(IDEState *s)
|
||||||
@ -609,6 +623,51 @@ BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
|
|||||||
return aioreq;
|
return aioreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel all pending DMA requests.
|
||||||
|
* Any buffered DMA requests are instantly canceled,
|
||||||
|
* but any pending unbuffered DMA requests must be waited on.
|
||||||
|
*/
|
||||||
|
void ide_cancel_dma_sync(IDEState *s)
|
||||||
|
{
|
||||||
|
IDEBufferedRequest *req;
|
||||||
|
|
||||||
|
/* First invoke the callbacks of all buffered requests
|
||||||
|
* and flag those requests as orphaned. Ideally there
|
||||||
|
* are no unbuffered (Scatter Gather DMA Requests or
|
||||||
|
* write requests) pending and we can avoid to drain. */
|
||||||
|
QLIST_FOREACH(req, &s->buffered_requests, list) {
|
||||||
|
if (!req->orphaned) {
|
||||||
|
#ifdef DEBUG_IDE
|
||||||
|
printf("%s: invoking cb %p of buffered request %p with"
|
||||||
|
" -ECANCELED\n", __func__, req->original_cb, req);
|
||||||
|
#endif
|
||||||
|
req->original_cb(req->original_opaque, -ECANCELED);
|
||||||
|
}
|
||||||
|
req->orphaned = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can't cancel Scatter Gather DMA in the middle of the
|
||||||
|
* operation or a partial (not full) DMA transfer would reach
|
||||||
|
* the storage so we wait for completion instead (we beahve
|
||||||
|
* like if the DMA was completed by the time the guest trying
|
||||||
|
* to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
|
||||||
|
* set).
|
||||||
|
*
|
||||||
|
* In the future we'll be able to safely cancel the I/O if the
|
||||||
|
* whole DMA operation will be submitted to disk with a single
|
||||||
|
* aio operation with preadv/pwritev.
|
||||||
|
*/
|
||||||
|
if (s->bus->dma->aiocb) {
|
||||||
|
#ifdef DEBUG_IDE
|
||||||
|
printf("%s: draining all remaining requests", __func__);
|
||||||
|
#endif
|
||||||
|
blk_drain(s->blk);
|
||||||
|
assert(s->bus->dma->aiocb == NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ide_sector_read(IDEState *s);
|
static void ide_sector_read(IDEState *s);
|
||||||
|
|
||||||
static void ide_sector_read_cb(void *opaque, int ret)
|
static void ide_sector_read_cb(void *opaque, int ret)
|
||||||
@ -1175,11 +1234,86 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ide_reset(IDEState *s)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_IDE
|
||||||
|
printf("ide: reset\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (s->pio_aiocb) {
|
||||||
|
blk_aio_cancel(s->pio_aiocb);
|
||||||
|
s->pio_aiocb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->drive_kind == IDE_CFATA)
|
||||||
|
s->mult_sectors = 0;
|
||||||
|
else
|
||||||
|
s->mult_sectors = MAX_MULT_SECTORS;
|
||||||
|
/* ide regs */
|
||||||
|
s->feature = 0;
|
||||||
|
s->error = 0;
|
||||||
|
s->nsector = 0;
|
||||||
|
s->sector = 0;
|
||||||
|
s->lcyl = 0;
|
||||||
|
s->hcyl = 0;
|
||||||
|
|
||||||
|
/* lba48 */
|
||||||
|
s->hob_feature = 0;
|
||||||
|
s->hob_sector = 0;
|
||||||
|
s->hob_nsector = 0;
|
||||||
|
s->hob_lcyl = 0;
|
||||||
|
s->hob_hcyl = 0;
|
||||||
|
|
||||||
|
s->select = 0xa0;
|
||||||
|
s->status = READY_STAT | SEEK_STAT;
|
||||||
|
|
||||||
|
s->lba48 = 0;
|
||||||
|
|
||||||
|
/* ATAPI specific */
|
||||||
|
s->sense_key = 0;
|
||||||
|
s->asc = 0;
|
||||||
|
s->cdrom_changed = 0;
|
||||||
|
s->packet_transfer_size = 0;
|
||||||
|
s->elementary_transfer_size = 0;
|
||||||
|
s->io_buffer_index = 0;
|
||||||
|
s->cd_sector_size = 0;
|
||||||
|
s->atapi_dma = 0;
|
||||||
|
s->tray_locked = 0;
|
||||||
|
s->tray_open = 0;
|
||||||
|
/* ATA DMA state */
|
||||||
|
s->io_buffer_size = 0;
|
||||||
|
s->req_nb_sectors = 0;
|
||||||
|
|
||||||
|
ide_set_signature(s);
|
||||||
|
/* init the transfer handler so that 0xffff is returned on data
|
||||||
|
accesses */
|
||||||
|
s->end_transfer_func = ide_dummy_transfer_stop;
|
||||||
|
ide_dummy_transfer_stop(s);
|
||||||
|
s->media_changed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static bool cmd_nop(IDEState *s, uint8_t cmd)
|
static bool cmd_nop(IDEState *s, uint8_t cmd)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cmd_device_reset(IDEState *s, uint8_t cmd)
|
||||||
|
{
|
||||||
|
/* Halt PIO (in the DRQ phase), then DMA */
|
||||||
|
ide_transfer_cancel(s);
|
||||||
|
ide_cancel_dma_sync(s);
|
||||||
|
|
||||||
|
/* Reset any PIO commands, reset signature, etc */
|
||||||
|
ide_reset(s);
|
||||||
|
|
||||||
|
/* RESET: ATA8-ACS3 7.10.4 "Normal Outputs";
|
||||||
|
* ATA8-ACS3 Table 184 "Device Signatures for Normal Output" */
|
||||||
|
s->status = 0x00;
|
||||||
|
|
||||||
|
/* Do not overwrite status register */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static bool cmd_data_set_management(IDEState *s, uint8_t cmd)
|
static bool cmd_data_set_management(IDEState *s, uint8_t cmd)
|
||||||
{
|
{
|
||||||
switch (s->feature) {
|
switch (s->feature) {
|
||||||
@ -1496,15 +1630,6 @@ static bool cmd_exec_dev_diagnostic(IDEState *s, uint8_t cmd)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cmd_device_reset(IDEState *s, uint8_t cmd)
|
|
||||||
{
|
|
||||||
ide_set_signature(s);
|
|
||||||
s->status = 0x00; /* NOTE: READY is _not_ set */
|
|
||||||
s->error = 0x01;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cmd_packet(IDEState *s, uint8_t cmd)
|
static bool cmd_packet(IDEState *s, uint8_t cmd)
|
||||||
{
|
{
|
||||||
/* overlapping commands not supported */
|
/* overlapping commands not supported */
|
||||||
@ -1877,9 +2002,13 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only DEVICE RESET is allowed while BSY or/and DRQ are set */
|
/* Only RESET is allowed while BSY and/or DRQ are set,
|
||||||
if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET)
|
* and only to ATAPI devices. */
|
||||||
return;
|
if (s->status & (BUSY_STAT|DRQ_STAT)) {
|
||||||
|
if (val != WIN_DEVICE_RESET || s->drive_kind != IDE_CD) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!ide_cmd_permitted(s, val)) {
|
if (!ide_cmd_permitted(s, val)) {
|
||||||
ide_abort_command(s);
|
ide_abort_command(s);
|
||||||
@ -2179,64 +2308,6 @@ static void ide_dummy_transfer_stop(IDEState *s)
|
|||||||
s->io_buffer[3] = 0xff;
|
s->io_buffer[3] = 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ide_reset(IDEState *s)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_IDE
|
|
||||||
printf("ide: reset\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (s->pio_aiocb) {
|
|
||||||
blk_aio_cancel(s->pio_aiocb);
|
|
||||||
s->pio_aiocb = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s->drive_kind == IDE_CFATA)
|
|
||||||
s->mult_sectors = 0;
|
|
||||||
else
|
|
||||||
s->mult_sectors = MAX_MULT_SECTORS;
|
|
||||||
/* ide regs */
|
|
||||||
s->feature = 0;
|
|
||||||
s->error = 0;
|
|
||||||
s->nsector = 0;
|
|
||||||
s->sector = 0;
|
|
||||||
s->lcyl = 0;
|
|
||||||
s->hcyl = 0;
|
|
||||||
|
|
||||||
/* lba48 */
|
|
||||||
s->hob_feature = 0;
|
|
||||||
s->hob_sector = 0;
|
|
||||||
s->hob_nsector = 0;
|
|
||||||
s->hob_lcyl = 0;
|
|
||||||
s->hob_hcyl = 0;
|
|
||||||
|
|
||||||
s->select = 0xa0;
|
|
||||||
s->status = READY_STAT | SEEK_STAT;
|
|
||||||
|
|
||||||
s->lba48 = 0;
|
|
||||||
|
|
||||||
/* ATAPI specific */
|
|
||||||
s->sense_key = 0;
|
|
||||||
s->asc = 0;
|
|
||||||
s->cdrom_changed = 0;
|
|
||||||
s->packet_transfer_size = 0;
|
|
||||||
s->elementary_transfer_size = 0;
|
|
||||||
s->io_buffer_index = 0;
|
|
||||||
s->cd_sector_size = 0;
|
|
||||||
s->atapi_dma = 0;
|
|
||||||
s->tray_locked = 0;
|
|
||||||
s->tray_open = 0;
|
|
||||||
/* ATA DMA state */
|
|
||||||
s->io_buffer_size = 0;
|
|
||||||
s->req_nb_sectors = 0;
|
|
||||||
|
|
||||||
ide_set_signature(s);
|
|
||||||
/* init the transfer handler so that 0xffff is returned on data
|
|
||||||
accesses */
|
|
||||||
s->end_transfer_func = ide_dummy_transfer_stop;
|
|
||||||
ide_dummy_transfer_stop(s);
|
|
||||||
s->media_changed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ide_bus_reset(IDEBus *bus)
|
void ide_bus_reset(IDEBus *bus)
|
||||||
{
|
{
|
||||||
bus->unit = 0;
|
bus->unit = 0;
|
||||||
|
@ -586,6 +586,7 @@ BlockAIOCB *ide_issue_trim(BlockBackend *blk,
|
|||||||
BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
|
BlockAIOCB *ide_buffered_readv(IDEState *s, int64_t sector_num,
|
||||||
QEMUIOVector *iov, int nb_sectors,
|
QEMUIOVector *iov, int nb_sectors,
|
||||||
BlockCompletionFunc *cb, void *opaque);
|
BlockCompletionFunc *cb, void *opaque);
|
||||||
|
void ide_cancel_dma_sync(IDEState *s);
|
||||||
|
|
||||||
/* hw/ide/atapi.c */
|
/* hw/ide/atapi.c */
|
||||||
void ide_atapi_cmd(IDEState *s);
|
void ide_atapi_cmd(IDEState *s);
|
||||||
|
36
hw/ide/pci.c
36
hw/ide/pci.c
@ -234,41 +234,7 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val)
|
|||||||
/* Ignore writes to SSBM if it keeps the old value */
|
/* Ignore writes to SSBM if it keeps the old value */
|
||||||
if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
|
if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
|
||||||
if (!(val & BM_CMD_START)) {
|
if (!(val & BM_CMD_START)) {
|
||||||
/* First invoke the callbacks of all buffered requests
|
ide_cancel_dma_sync(idebus_active_if(bm->bus));
|
||||||
* and flag those requests as orphaned. Ideally there
|
|
||||||
* are no unbuffered (Scatter Gather DMA Requests or
|
|
||||||
* write requests) pending and we can avoid to drain. */
|
|
||||||
IDEBufferedRequest *req;
|
|
||||||
IDEState *s = idebus_active_if(bm->bus);
|
|
||||||
QLIST_FOREACH(req, &s->buffered_requests, list) {
|
|
||||||
if (!req->orphaned) {
|
|
||||||
#ifdef DEBUG_IDE
|
|
||||||
printf("%s: invoking cb %p of buffered request %p with"
|
|
||||||
" -ECANCELED\n", __func__, req->original_cb, req);
|
|
||||||
#endif
|
|
||||||
req->original_cb(req->original_opaque, -ECANCELED);
|
|
||||||
}
|
|
||||||
req->orphaned = true;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* We can't cancel Scatter Gather DMA in the middle of the
|
|
||||||
* operation or a partial (not full) DMA transfer would reach
|
|
||||||
* the storage so we wait for completion instead (we beahve
|
|
||||||
* like if the DMA was completed by the time the guest trying
|
|
||||||
* to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
|
|
||||||
* set).
|
|
||||||
*
|
|
||||||
* In the future we'll be able to safely cancel the I/O if the
|
|
||||||
* whole DMA operation will be submitted to disk with a single
|
|
||||||
* aio operation with preadv/pwritev.
|
|
||||||
*/
|
|
||||||
if (bm->bus->dma->aiocb) {
|
|
||||||
#ifdef DEBUG_IDE
|
|
||||||
printf("%s: draining all remaining requests", __func__);
|
|
||||||
#endif
|
|
||||||
blk_drain_all();
|
|
||||||
assert(bm->bus->dma->aiocb == NULL);
|
|
||||||
}
|
|
||||||
bm->status &= ~BM_STATUS_DMAING;
|
bm->status &= ~BM_STATUS_DMAING;
|
||||||
} else {
|
} else {
|
||||||
bm->cur_addr = bm->addr;
|
bm->cur_addr = bm->addr;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user