mirror of
https://github.com/qemu/qemu.git
synced 2024-11-24 19:33:39 +08:00
atapi: abort transfers with 0 byte limits
We're supposed to abort on transfers like this, unless we fill Word 125 of our IDENTIFY data with a default transfer size, which we don't currently do. This is an ATA error, not a SCSI/ATAPI one. See ATA8-ACS3 sections 7.17.6.49 or 7.21.5. If we don't do this, QEMU will loop forever trying to transfer zero bytes, which isn't particularly useful. Signed-off-by: John Snow <jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Message-id: 1442253685-23349-2-git-send-email-jsnow@redhat.com
This commit is contained in:
parent
d9033e1d3a
commit
9ef2e93f9b
@ -1169,20 +1169,28 @@ enum {
|
||||
* 4.1.8)
|
||||
*/
|
||||
CHECK_READY = 0x02,
|
||||
|
||||
/*
|
||||
* Commands flagged with NONDATA do not in any circumstances return
|
||||
* any data via ide_atapi_cmd_reply. These commands are exempt from
|
||||
* the normal byte_count_limit constraints.
|
||||
* See ATA8-ACS3 "7.21.5 Byte Count Limit"
|
||||
*/
|
||||
NONDATA = 0x04,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
void (*handler)(IDEState *s, uint8_t *buf);
|
||||
int flags;
|
||||
} atapi_cmd_table[0x100] = {
|
||||
[ 0x00 ] = { cmd_test_unit_ready, CHECK_READY },
|
||||
[ 0x00 ] = { cmd_test_unit_ready, CHECK_READY | NONDATA },
|
||||
[ 0x03 ] = { cmd_request_sense, ALLOW_UA },
|
||||
[ 0x12 ] = { cmd_inquiry, ALLOW_UA },
|
||||
[ 0x1b ] = { cmd_start_stop_unit, 0 }, /* [1] */
|
||||
[ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 },
|
||||
[ 0x1b ] = { cmd_start_stop_unit, NONDATA }, /* [1] */
|
||||
[ 0x1e ] = { cmd_prevent_allow_medium_removal, NONDATA },
|
||||
[ 0x25 ] = { cmd_read_cdvd_capacity, CHECK_READY },
|
||||
[ 0x28 ] = { cmd_read, /* (10) */ CHECK_READY },
|
||||
[ 0x2b ] = { cmd_seek, CHECK_READY },
|
||||
[ 0x2b ] = { cmd_seek, CHECK_READY | NONDATA },
|
||||
[ 0x43 ] = { cmd_read_toc_pma_atip, CHECK_READY },
|
||||
[ 0x46 ] = { cmd_get_configuration, ALLOW_UA },
|
||||
[ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
|
||||
@ -1190,7 +1198,7 @@ static const struct {
|
||||
[ 0x5a ] = { cmd_mode_sense, /* (10) */ 0 },
|
||||
[ 0xa8 ] = { cmd_read, /* (12) */ CHECK_READY },
|
||||
[ 0xad ] = { cmd_read_dvd_structure, CHECK_READY },
|
||||
[ 0xbb ] = { cmd_set_speed, 0 },
|
||||
[ 0xbb ] = { cmd_set_speed, NONDATA },
|
||||
[ 0xbd ] = { cmd_mechanism_status, 0 },
|
||||
[ 0xbe ] = { cmd_read_cd, CHECK_READY },
|
||||
/* [1] handler detects and reports not ready condition itself */
|
||||
@ -1251,6 +1259,20 @@ void ide_atapi_cmd(IDEState *s)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Nondata commands permit the byte_count_limit to be 0.
|
||||
* If this is a data-transferring PIO command and BCL is 0,
|
||||
* we abort at the /ATA/ level, not the ATAPI level.
|
||||
* See ATA8 ACS3 section 7.17.6.49 and 7.21.5 */
|
||||
if (!(atapi_cmd_table[s->io_buffer[0]].flags & NONDATA)) {
|
||||
/* TODO: Check IDENTIFY data word 125 for default BCL (currently 0) */
|
||||
uint16_t byte_count_limit = s->lcyl | (s->hcyl << 8);
|
||||
if (!(byte_count_limit || s->atapi_dma)) {
|
||||
/* TODO: Move abort back into core.c and make static inline again */
|
||||
ide_abort_command(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute the command */
|
||||
if (atapi_cmd_table[s->io_buffer[0]].handler) {
|
||||
atapi_cmd_table[s->io_buffer[0]].handler(s, buf);
|
||||
|
@ -457,7 +457,7 @@ BlockAIOCB *ide_issue_trim(BlockBackend *blk,
|
||||
return &iocb->common;
|
||||
}
|
||||
|
||||
static inline void ide_abort_command(IDEState *s)
|
||||
void ide_abort_command(IDEState *s)
|
||||
{
|
||||
ide_transfer_stop(s);
|
||||
s->status = READY_STAT | ERR_STAT;
|
||||
|
@ -538,6 +538,7 @@ void ide_set_sector(IDEState *s, int64_t sector_num);
|
||||
void ide_start_dma(IDEState *s, BlockCompletionFunc *cb);
|
||||
void dma_buf_commit(IDEState *s, uint32_t tx_bytes);
|
||||
void ide_dma_error(IDEState *s);
|
||||
void ide_abort_command(IDEState *s);
|
||||
|
||||
void ide_atapi_cmd_ok(IDEState *s);
|
||||
void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc);
|
||||
|
Loading…
Reference in New Issue
Block a user