-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQIcBAABAgAGBQJXDYWGAAoJEH3vgQaq/DkOXI4QAKTyWzi6/wpvQX9hLQWO2Fug sMcSOheIQKhB6G09lGnzjkSRYiAb32qT2NEfuYzJnn5f+LY1dWZK/AhbrRIVafeC k0yu15EFCiclhHn57uwHEaNm0ZF4eM+06/lF9MgNKDPHBpcXJRVXH1s5PsjRn/pQ P7J2TV4h0zvFrv6Z0ds4q23IzU+M2J4za1yHS1xKIDv5RuFqVpWMSS7mr52ww9eG DxqnSnjI1csOiLB7lIjx2AZTzBZRx9B03+QfS/HM+6RULtA1W5q4uKuI7t2Z19RQ gYzZXQYT0bhBNpQ1zFTx7y3XB8rYYPU0Y8X6B/L8/CqSuuwc7of2eg5KqKBOqoow ZUh1NeahJ1UKc23selkKOa5Gb+kD10avNKxobtatS1xwG8wZEWVoI8nt89aJoGH7 goqLqG/b2oa6k3IyCfT2gfJpAUBCEu/GFmBUFws+ntZCTR6V8/fCS5yTG+Yv2dQx +Cb5bJLPZdQWWUbRHLpK6mR2G8GzSdyqOJfjxLwAi1pOREHJyXz+XNa2bQjvpovg Dbo1IEq53v1RvmW+r0IsMrZLqNnFw0VTldTxM4FIBGvpH0c1bqiG57D7cVnGojpU uB0XSxteW+dikuBtupBMbvDafzXfmEREb5kaDqo6NFWunJ4PX/lnAFcbjCb4nc5z 1lqtSWERfKVpFlM90s4g =pFKJ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/jnsnow/tags/ide-pull-request' into staging # gpg: Signature made Wed 13 Apr 2016 00:32:22 BST using RSA key ID AAFC390E # gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" * remotes/jnsnow/tags/ide-pull-request: ide: really restart pending and in-flight atapi dma ide: restart atapi dma by re-evaluating command packet ide: don't lose pending dma state xen: Fix IDE unplug Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c0bc0fa352
@ -375,16 +375,19 @@ static void ide_atapi_cmd_check_status(IDEState *s)
|
|||||||
}
|
}
|
||||||
/* ATAPI DMA support */
|
/* ATAPI DMA support */
|
||||||
|
|
||||||
/* XXX: handle read errors */
|
|
||||||
static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
|
static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
IDEState *s = opaque;
|
IDEState *s = opaque;
|
||||||
int data_offset, n;
|
int data_offset, n;
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ide_atapi_io_error(s, ret);
|
if (ide_handle_rw_error(s, -ret, ide_dma_cmd_to_retry(s->dma_cmd))) {
|
||||||
|
if (s->bus->error_status) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
goto eot;
|
goto eot;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (s->io_buffer_size > 0) {
|
if (s->io_buffer_size > 0) {
|
||||||
/*
|
/*
|
||||||
@ -481,21 +484,16 @@ static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Called by *_restart_bh when the transfer function points
|
|
||||||
* to ide_atapi_cmd
|
|
||||||
*/
|
|
||||||
void ide_atapi_dma_restart(IDEState *s)
|
void ide_atapi_dma_restart(IDEState *s)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* I'm not sure we have enough stored to restart the command
|
* At this point we can just re-evaluate the packet command and start over.
|
||||||
* safely, so give the guest an error it should recover from.
|
* The presence of ->dma_cb callback in the pre_save ensures that the packet
|
||||||
* I'm assuming most guests will try to recover from something
|
* command has been completely sent and we can safely restart command.
|
||||||
* listed as a medium error on a CD; it seems to work on Linux.
|
|
||||||
* This would be more of a problem if we did any other type of
|
|
||||||
* DMA operation.
|
|
||||||
*/
|
*/
|
||||||
ide_atapi_cmd_error(s, MEDIUM_ERROR, ASC_NO_SEEK_COMPLETE);
|
s->unit = s->bus->retry_unit;
|
||||||
|
s->bus->dma->ops->restart_dma(s->bus->dma);
|
||||||
|
ide_atapi_cmd(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index,
|
static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index,
|
||||||
|
@ -57,7 +57,6 @@ static const int smart_attributes[][12] = {
|
|||||||
{ 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
|
{ 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ide_handle_rw_error(IDEState *s, int error, int op);
|
|
||||||
static void ide_dummy_transfer_stop(IDEState *s);
|
static void ide_dummy_transfer_stop(IDEState *s);
|
||||||
|
|
||||||
static void padstr(char *str, const char *src, int len)
|
static void padstr(char *str, const char *src, int len)
|
||||||
@ -773,7 +772,7 @@ void ide_dma_error(IDEState *s)
|
|||||||
ide_set_irq(s->bus);
|
ide_set_irq(s->bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ide_handle_rw_error(IDEState *s, int error, int op)
|
int ide_handle_rw_error(IDEState *s, int error, int op)
|
||||||
{
|
{
|
||||||
bool is_read = (op & IDE_RETRY_READ) != 0;
|
bool is_read = (op & IDE_RETRY_READ) != 0;
|
||||||
BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
|
BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
|
||||||
@ -783,8 +782,10 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
|
|||||||
s->bus->error_status = op;
|
s->bus->error_status = op;
|
||||||
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
|
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
|
||||||
block_acct_failed(blk_get_stats(s->blk), &s->acct);
|
block_acct_failed(blk_get_stats(s->blk), &s->acct);
|
||||||
if (op & IDE_RETRY_DMA) {
|
if (IS_IDE_RETRY_DMA(op)) {
|
||||||
ide_dma_error(s);
|
ide_dma_error(s);
|
||||||
|
} else if (IS_IDE_RETRY_ATAPI(op)) {
|
||||||
|
ide_atapi_io_error(s, -error);
|
||||||
} else {
|
} else {
|
||||||
ide_rw_error(s);
|
ide_rw_error(s);
|
||||||
}
|
}
|
||||||
@ -804,14 +805,7 @@ static void ide_dma_cb(void *opaque, int ret)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
int op = IDE_RETRY_DMA;
|
if (ide_handle_rw_error(s, -ret, ide_dma_cmd_to_retry(s->dma_cmd))) {
|
||||||
|
|
||||||
if (s->dma_cmd == IDE_DMA_READ)
|
|
||||||
op |= IDE_RETRY_READ;
|
|
||||||
else if (s->dma_cmd == IDE_DMA_TRIM)
|
|
||||||
op |= IDE_RETRY_TRIM;
|
|
||||||
|
|
||||||
if (ide_handle_rw_error(s, -ret, op)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -879,6 +873,8 @@ static void ide_dma_cb(void *opaque, int ret)
|
|||||||
ide_issue_trim, ide_dma_cb, s,
|
ide_issue_trim, ide_dma_cb, s,
|
||||||
DMA_DIRECTION_TO_DEVICE);
|
DMA_DIRECTION_TO_DEVICE);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1641,6 +1637,9 @@ static bool cmd_packet(IDEState *s, uint8_t cmd)
|
|||||||
|
|
||||||
s->status = READY_STAT | SEEK_STAT;
|
s->status = READY_STAT | SEEK_STAT;
|
||||||
s->atapi_dma = s->feature & 1;
|
s->atapi_dma = s->feature & 1;
|
||||||
|
if (s->atapi_dma) {
|
||||||
|
s->dma_cmd = IDE_DMA_ATAPI;
|
||||||
|
}
|
||||||
s->nsector = 1;
|
s->nsector = 1;
|
||||||
ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
|
ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
|
||||||
ide_atapi_cmd);
|
ide_atapi_cmd);
|
||||||
@ -2525,15 +2524,13 @@ static void ide_restart_bh(void *opaque)
|
|||||||
if (s->bus->dma->ops->restart) {
|
if (s->bus->dma->ops->restart) {
|
||||||
s->bus->dma->ops->restart(s->bus->dma);
|
s->bus->dma->ops->restart(s->bus->dma);
|
||||||
}
|
}
|
||||||
}
|
} else if (IS_IDE_RETRY_DMA(error_status)) {
|
||||||
|
|
||||||
if (error_status & IDE_RETRY_DMA) {
|
|
||||||
if (error_status & IDE_RETRY_TRIM) {
|
if (error_status & IDE_RETRY_TRIM) {
|
||||||
ide_restart_dma(s, IDE_DMA_TRIM);
|
ide_restart_dma(s, IDE_DMA_TRIM);
|
||||||
} else {
|
} else {
|
||||||
ide_restart_dma(s, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
|
ide_restart_dma(s, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
|
||||||
}
|
}
|
||||||
} else if (error_status & IDE_RETRY_PIO) {
|
} else if (IS_IDE_RETRY_PIO(error_status)) {
|
||||||
if (is_read) {
|
if (is_read) {
|
||||||
ide_sector_read(s);
|
ide_sector_read(s);
|
||||||
} else {
|
} else {
|
||||||
@ -2541,15 +2538,11 @@ static void ide_restart_bh(void *opaque)
|
|||||||
}
|
}
|
||||||
} else if (error_status & IDE_RETRY_FLUSH) {
|
} else if (error_status & IDE_RETRY_FLUSH) {
|
||||||
ide_flush_cache(s);
|
ide_flush_cache(s);
|
||||||
} else {
|
} else if (IS_IDE_RETRY_ATAPI(error_status)) {
|
||||||
/*
|
assert(s->end_transfer_func == ide_atapi_cmd);
|
||||||
* We've not got any bits to tell us about ATAPI - but
|
|
||||||
* we do have the end_transfer_func that tells us what
|
|
||||||
* we're trying to do.
|
|
||||||
*/
|
|
||||||
if (s->end_transfer_func == ide_atapi_cmd) {
|
|
||||||
ide_atapi_dma_restart(s);
|
ide_atapi_dma_restart(s);
|
||||||
}
|
} else {
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,6 +338,7 @@ enum ide_dma_cmd {
|
|||||||
IDE_DMA_READ,
|
IDE_DMA_READ,
|
||||||
IDE_DMA_WRITE,
|
IDE_DMA_WRITE,
|
||||||
IDE_DMA_TRIM,
|
IDE_DMA_TRIM,
|
||||||
|
IDE_DMA_ATAPI,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ide_cmd_is_read(s) \
|
#define ide_cmd_is_read(s) \
|
||||||
@ -506,13 +507,45 @@ struct IDEDevice {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* These are used for the error_status field of IDEBus */
|
/* These are used for the error_status field of IDEBus */
|
||||||
|
#define IDE_RETRY_MASK 0xf8
|
||||||
#define IDE_RETRY_DMA 0x08
|
#define IDE_RETRY_DMA 0x08
|
||||||
#define IDE_RETRY_PIO 0x10
|
#define IDE_RETRY_PIO 0x10
|
||||||
|
#define IDE_RETRY_ATAPI 0x20 /* reused IDE_RETRY_READ bit */
|
||||||
#define IDE_RETRY_READ 0x20
|
#define IDE_RETRY_READ 0x20
|
||||||
#define IDE_RETRY_FLUSH 0x40
|
#define IDE_RETRY_FLUSH 0x40
|
||||||
#define IDE_RETRY_TRIM 0x80
|
#define IDE_RETRY_TRIM 0x80
|
||||||
#define IDE_RETRY_HBA 0x100
|
#define IDE_RETRY_HBA 0x100
|
||||||
|
|
||||||
|
#define IS_IDE_RETRY_DMA(_status) \
|
||||||
|
((_status) & IDE_RETRY_DMA)
|
||||||
|
|
||||||
|
#define IS_IDE_RETRY_PIO(_status) \
|
||||||
|
((_status) & IDE_RETRY_PIO)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The method of the IDE_RETRY_ATAPI determination is to use a previously
|
||||||
|
* impossible bit combination as a new status value.
|
||||||
|
*/
|
||||||
|
#define IS_IDE_RETRY_ATAPI(_status) \
|
||||||
|
(((_status) & IDE_RETRY_MASK) == IDE_RETRY_ATAPI)
|
||||||
|
|
||||||
|
static inline uint8_t ide_dma_cmd_to_retry(uint8_t dma_cmd)
|
||||||
|
{
|
||||||
|
switch (dma_cmd) {
|
||||||
|
case IDE_DMA_READ:
|
||||||
|
return IDE_RETRY_DMA | IDE_RETRY_READ;
|
||||||
|
case IDE_DMA_WRITE:
|
||||||
|
return IDE_RETRY_DMA;
|
||||||
|
case IDE_DMA_TRIM:
|
||||||
|
return IDE_RETRY_DMA | IDE_RETRY_TRIM;
|
||||||
|
case IDE_DMA_ATAPI:
|
||||||
|
return IDE_RETRY_ATAPI;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline IDEState *idebus_active_if(IDEBus *bus)
|
static inline IDEState *idebus_active_if(IDEBus *bus)
|
||||||
{
|
{
|
||||||
return bus->ifs + bus->unit;
|
return bus->ifs + bus->unit;
|
||||||
@ -597,4 +630,6 @@ void ide_bus_new(IDEBus *idebus, size_t idebus_size, DeviceState *dev,
|
|||||||
int bus_id, int max_units);
|
int bus_id, int max_units);
|
||||||
IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive);
|
IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive);
|
||||||
|
|
||||||
|
int ide_handle_rw_error(IDEState *s, int error, int op);
|
||||||
|
|
||||||
#endif /* HW_IDE_INTERNAL_H */
|
#endif /* HW_IDE_INTERNAL_H */
|
||||||
|
@ -346,6 +346,8 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
|||||||
case IDE_DMA_TRIM:
|
case IDE_DMA_TRIM:
|
||||||
pmac_dma_trim(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
|
pmac_dma_trim(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -308,6 +308,10 @@ static void ide_bmdma_pre_save(void *opaque)
|
|||||||
BMDMAState *bm = opaque;
|
BMDMAState *bm = opaque;
|
||||||
uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
|
uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
|
||||||
|
|
||||||
|
if (!(bm->status & BM_STATUS_DMAING) && bm->dma_cb) {
|
||||||
|
bm->bus->error_status =
|
||||||
|
ide_dma_cmd_to_retry(bmdma_active_if(bm)->dma_cmd);
|
||||||
|
}
|
||||||
bm->migration_retry_unit = bm->bus->retry_unit;
|
bm->migration_retry_unit = bm->bus->retry_unit;
|
||||||
bm->migration_retry_sector_num = bm->bus->retry_sector_num;
|
bm->migration_retry_sector_num = bm->bus->retry_sector_num;
|
||||||
bm->migration_retry_nsector = bm->bus->retry_nsector;
|
bm->migration_retry_nsector = bm->bus->retry_nsector;
|
||||||
|
@ -189,6 +189,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
|||||||
idedev = pci_ide->bus[di->bus].slave;
|
idedev = pci_ide->bus[di->bus].slave;
|
||||||
}
|
}
|
||||||
idedev->conf.blk = NULL;
|
idedev->conf.blk = NULL;
|
||||||
|
monitor_remove_blk(blk);
|
||||||
blk_unref(blk);
|
blk_unref(blk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user