From 66c6ef7678939f2119eb649074babf5d5b2666f6 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 19 Aug 2006 11:44:21 +0000 Subject: [PATCH] better support of removable media git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2123 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/ide.c | 120 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 51 deletions(-) diff --git a/hw/ide.c b/hw/ide.c index b9bd607a4a..6741cac1f2 100644 --- a/hw/ide.c +++ b/hw/ide.c @@ -943,26 +943,44 @@ static void cd_data_to_raw(uint8_t *buf, int lba) memset(buf, 0, 288); } -static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, +static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, int sector_size) { + int ret; + switch(sector_size) { case 2048: - bdrv_read(bs, (int64_t)lba << 2, buf, 4); + ret = bdrv_read(bs, (int64_t)lba << 2, buf, 4); break; case 2352: - bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); + ret = bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4); + if (ret < 0) + return ret; cd_data_to_raw(buf, lba); break; default: + ret = -EIO; break; } + return ret; +} + +static void ide_atapi_io_error(IDEState *s, int ret) +{ + /* XXX: handle more errors */ + if (ret == -ENOMEDIUM) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + } else { + ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, + ASC_LOGICAL_BLOCK_OOR); + } } /* The whole ATAPI transfer logic is handled in this function */ static void ide_atapi_cmd_reply_end(IDEState *s) { - int byte_count_limit, size; + int byte_count_limit, size, ret; #ifdef DEBUG_IDE_ATAPI printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", s->packet_transfer_size, @@ -981,7 +999,12 @@ static void ide_atapi_cmd_reply_end(IDEState *s) } else { /* see if a new sector must be read */ if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { - cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); + ret = cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); + if (ret < 0) { + ide_transfer_stop(s); + ide_atapi_io_error(s, ret); + return; + } s->lba++; s->io_buffer_index = 0; } @@ -1070,6 +1093,11 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) IDEState *s = bm->ide_if; int data_offset, n; + if (ret < 0) { + ide_atapi_io_error(s, ret); + goto eot; + } + if (s->io_buffer_size > 0) { if (s->cd_sector_size == 2352) { n = 1; @@ -1114,6 +1142,12 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret) bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, s->io_buffer + data_offset, n * 4, ide_atapi_cmd_read_dma_cb, bm); + if (!bm->aiocb) { + /* Note: media not present is the most likely case */ + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + goto eot; + } } /* start a CD-CDROM read command with DMA */ @@ -1270,11 +1304,6 @@ static void ide_atapi_cmd(IDEState *s) { int nb_sectors, lba; - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } if (packet[0] == GPCMD_READ_10) nb_sectors = ube16_to_cpu(packet + 7); else @@ -1284,11 +1313,6 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_ok(s); break; } - if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } ide_atapi_cmd_read(s, lba, nb_sectors, 2048); } break; @@ -1296,22 +1320,12 @@ static void ide_atapi_cmd(IDEState *s) { int nb_sectors, lba, transfer_request; - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; lba = ube32_to_cpu(packet + 2); if (nb_sectors == 0) { ide_atapi_cmd_ok(s); break; } - if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } transfer_request = packet[9]; switch(transfer_request & 0xf8) { case 0x00: @@ -1336,13 +1350,17 @@ static void ide_atapi_cmd(IDEState *s) case GPCMD_SEEK: { int lba; - if (!bdrv_is_inserted(s->bs)) { + int64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors <= 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; } lba = ube32_to_cpu(packet + 2); - if (((int64_t)lba << 2) > s->nb_sectors) { + if (lba >= total_sectors) { ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR); break; @@ -1358,7 +1376,10 @@ static void ide_atapi_cmd(IDEState *s) if (eject && !start) { /* eject the disk */ - bdrv_close(s->bs); + bdrv_eject(s->bs, 1); + } else if (eject && start) { + /* close the tray */ + bdrv_eject(s->bs, 0); } ide_atapi_cmd_ok(s); } @@ -1379,8 +1400,11 @@ static void ide_atapi_cmd(IDEState *s) case GPCMD_READ_TOC_PMA_ATIP: { int format, msf, start_track, len; + int64_t total_sectors; - if (!bdrv_is_inserted(s->bs)) { + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors <= 0) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); break; @@ -1391,7 +1415,7 @@ static void ide_atapi_cmd(IDEState *s) start_track = packet[6]; switch(format) { case 0: - len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track); + len = cdrom_read_toc(total_sectors, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); @@ -1405,7 +1429,7 @@ static void ide_atapi_cmd(IDEState *s) ide_atapi_cmd_reply(s, 12, max_len); break; case 2: - len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track); + len = cdrom_read_toc_raw(total_sectors, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); @@ -1419,15 +1443,21 @@ static void ide_atapi_cmd(IDEState *s) } break; case GPCMD_READ_CDVD_CAPACITY: - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; + { + int64_t total_sectors; + + bdrv_get_geometry(s->bs, &total_sectors); + total_sectors >>= 2; + if (total_sectors <= 0) { + ide_atapi_cmd_error(s, SENSE_NOT_READY, + ASC_MEDIUM_NOT_PRESENT); + break; + } + /* NOTE: it is really the number of sectors minus 1 */ + cpu_to_ube32(buf, total_sectors - 1); + cpu_to_ube32(buf + 4, 2048); + ide_atapi_cmd_reply(s, 8, 8); } - /* NOTE: it is really the number of sectors minus 1 */ - cpu_to_ube32(buf, (s->nb_sectors >> 2) - 1); - cpu_to_ube32(buf + 4, 2048); - ide_atapi_cmd_reply(s, 8, 8); break; case GPCMD_INQUIRY: max_len = packet[4]; @@ -1451,17 +1481,6 @@ static void ide_atapi_cmd(IDEState *s) } } -/* called when the inserted state of the media has changed */ -static void cdrom_change_cb(void *opaque) -{ - IDEState *s = opaque; - int64_t nb_sectors; - - /* XXX: send interrupt too */ - bdrv_get_geometry(s->bs, &nb_sectors); - s->nb_sectors = nb_sectors; -} - static void ide_cmd_lba48_transform(IDEState *s, int lba48) { s->lba48 = lba48; @@ -2092,7 +2111,6 @@ static void ide_init2(IDEState *ide_state, } if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { s->is_cdrom = 1; - bdrv_set_change_cb(s->bs, cdrom_change_cb, s); } } s->drive_serial = drive_serial++;