commit 66c6ef7678939f2119eb649074babf5d5b2666f6
Author: bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Date:   Sat Aug 19 11:44:21 2006 +0000

    better support of removable media
    
    
    git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2123 c046a42c-6fe2-441c-8c8c-71466251a162

diff --git a/hw/ide.c b/hw/ide.c
index b9bd607..6741cac 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++;
