]> Git Repo - qemu.git/blobdiff - hw/ide/atapi.c
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
[qemu.git] / hw / ide / atapi.c
index 90b672969223b778604661e4bc4e90c1639b8ce9..3d92b52dbc1f0ca506a13697eb85b2fdcd935be6 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "hw/ide/internal.h"
-#include "hw/scsi.h"
+#include "hw/scsi/scsi.h"
 
 static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
 
@@ -174,9 +174,9 @@ void ide_atapi_cmd_reply_end(IDEState *s)
 #endif
     if (s->packet_transfer_size <= 0) {
         /* end of transfer */
-        ide_transfer_stop(s);
         s->status = READY_STAT | SEEK_STAT;
         s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+        ide_transfer_stop(s);
         ide_set_irq(s->bus);
 #ifdef DEBUG_IDE_ATAPI
         printf("status=0x%x\n", s->status);
@@ -255,8 +255,7 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
     if (s->atapi_dma) {
         bdrv_acct_start(s->bs, &s->acct, size, BDRV_ACCT_READ);
         s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
-        s->bus->dma->ops->start_dma(s->bus->dma, s,
-                                   ide_atapi_cmd_read_dma_cb);
+        ide_start_dma(s, ide_atapi_cmd_read_dma_cb);
     } else {
         s->status = READY_STAT | SEEK_STAT;
         ide_atapi_cmd_reply_end(s);
@@ -352,18 +351,11 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
     s->bus->dma->aiocb = bdrv_aio_readv(s->bs, (int64_t)s->lba << 2,
                                        &s->bus->dma->qiov, n * 4,
                                        ide_atapi_cmd_read_dma_cb, s);
-    if (!s->bus->dma->aiocb) {
-        /* Note: media not present is the most likely case */
-        ide_atapi_cmd_error(s, NOT_READY,
-                            ASC_MEDIUM_NOT_PRESENT);
-        goto eot;
-    }
-
     return;
+
 eot:
     bdrv_acct_done(s->bs, &s->acct);
-    s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
-    ide_set_inactive(s);
+    ide_set_inactive(s, false);
 }
 
 /* start a CD-CDROM read command with DMA */
@@ -381,8 +373,7 @@ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
 
     /* XXX: check if BUSY_STAT should be set */
     s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
-    s->bus->dma->ops->start_dma(s->bus->dma, s,
-                               ide_atapi_cmd_read_dma_cb);
+    ide_start_dma(s, ide_atapi_cmd_read_dma_cb);
 }
 
 static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
@@ -443,7 +434,7 @@ static int ide_dvd_read_structure(IDEState *s, int format,
                 cpu_to_ube32(buf + 16, total_sectors - 1); /* l0 end sector */
 
                 /* Size of buffer, not including 2 byte size field */
-                cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
+                stw_be_p(buf, 2048 + 2);
 
                 /* 2k data + 4 byte header */
                 return (2048 + 4);
@@ -454,7 +445,7 @@ static int ide_dvd_read_structure(IDEState *s, int format,
             buf[5] = 0; /* no region restrictions */
 
             /* Size of buffer, not including 2 byte size field */
-            cpu_to_be16wu((uint16_t *)buf, 4 + 2);
+            stw_be_p(buf, 4 + 2);
 
             /* 4 byte header + 4 byte data */
             return (4 + 4);
@@ -464,7 +455,7 @@ static int ide_dvd_read_structure(IDEState *s, int format,
 
         case 0x04: /* DVD disc manufacturing information */
             /* Size of buffer, not including 2 byte size field */
-            cpu_to_be16wu((uint16_t *)buf, 2048 + 2);
+            stw_be_p(buf, 2048 + 2);
 
             /* 2k data + 4 byte header */
             return (2048 + 4);
@@ -477,22 +468,22 @@ static int ide_dvd_read_structure(IDEState *s, int format,
 
             buf[4] = 0x00; /* Physical format */
             buf[5] = 0x40; /* Not writable, is readable */
-            cpu_to_be16wu((uint16_t *)(buf + 6), 2048 + 4);
+            stw_be_p(buf + 6, 2048 + 4);
 
             buf[8] = 0x01; /* Copyright info */
             buf[9] = 0x40; /* Not writable, is readable */
-            cpu_to_be16wu((uint16_t *)(buf + 10), 4 + 4);
+            stw_be_p(buf + 10, 4 + 4);
 
             buf[12] = 0x03; /* BCA info */
             buf[13] = 0x40; /* Not writable, is readable */
-            cpu_to_be16wu((uint16_t *)(buf + 14), 188 + 4);
+            stw_be_p(buf + 14, 188 + 4);
 
             buf[16] = 0x04; /* Manufacturing info */
             buf[17] = 0x40; /* Not writable, is readable */
-            cpu_to_be16wu((uint16_t *)(buf + 18), 2048 + 4);
+            stw_be_p(buf + 18, 2048 + 4);
 
             /* Size of buffer, not including 2 byte size field */
-            cpu_to_be16wu((uint16_t *)buf, 16 + 2);
+            stw_be_p(buf, 16 + 2);
 
             /* data written + 4 byte header */
             return (16 + 4);
@@ -516,9 +507,14 @@ static unsigned int event_status_media(IDEState *s,
 
     /* Event notification descriptor */
     event_code = MEC_NO_CHANGE;
-    if (media_status != MS_TRAY_OPEN && s->events.new_media) {
-        event_code = MEC_NEW_MEDIA;
-        s->events.new_media = false;
+    if (media_status != MS_TRAY_OPEN) {
+        if (s->events.new_media) {
+            event_code = MEC_NEW_MEDIA;
+            s->events.new_media = false;
+        } else if (s->events.eject_request) {
+            event_code = MEC_EJECT_REQUESTED;
+            s->events.eject_request = false;
+        }
     }
 
     buf[4] = event_code;
@@ -690,12 +686,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
     int action, code;
     int max_len;
 
-    if (buf[0] == GPCMD_MODE_SENSE_10) {
-        max_len = ube16_to_cpu(buf + 7);
-    } else {
-        max_len = buf[4];
-    }
-
+    max_len = ube16_to_cpu(buf + 7);
     action = buf[2] >> 6;
     code = buf[2] & 0x3f;
 
@@ -703,7 +694,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
     case 0: /* current values */
         switch(code) {
         case MODE_PAGE_R_W_ERROR: /* error recovery */
-            cpu_to_ube16(&buf[0], 16 + 6);
+            cpu_to_ube16(&buf[0], 16 - 2);
             buf[2] = 0x70;
             buf[3] = 0;
             buf[4] = 0;
@@ -722,7 +713,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             ide_atapi_cmd_reply(s, 16, max_len);
             break;
         case MODE_PAGE_AUDIO_CTL:
-            cpu_to_ube16(&buf[0], 24 + 6);
+            cpu_to_ube16(&buf[0], 24 - 2);
             buf[2] = 0x70;
             buf[3] = 0;
             buf[4] = 0;
@@ -741,7 +732,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             ide_atapi_cmd_reply(s, 24, max_len);
             break;
         case MODE_PAGE_CAPABILITIES:
-            cpu_to_ube16(&buf[0], 28 + 6);
+            cpu_to_ube16(&buf[0], 30 - 2);
             buf[2] = 0x70;
             buf[3] = 0;
             buf[4] = 0;
@@ -750,7 +741,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             buf[7] = 0;
 
             buf[8] = MODE_PAGE_CAPABILITIES;
-            buf[9] = 28 - 10;
+            buf[9] = 30 - 10;
             buf[10] = 0x3b; /* read CDR/CDRW/DVDROM/DVDR/DVDRAM */
             buf[11] = 0x00;
 
@@ -772,7 +763,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
             buf[25] = 0;
             buf[26] = 0;
             buf[27] = 0;
-            ide_atapi_cmd_reply(s, 28, max_len);
+            buf[28] = 0;
+            buf[29] = 0;
+            ide_atapi_cmd_reply(s, 30, max_len);
             break;
         default:
             goto error_cmd;
@@ -879,6 +872,12 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
     int sense;
     bool start = buf[4] & 1;
     bool loej = buf[4] & 2;     /* load on start, eject on !start */
+    int pwrcnd = buf[4] & 0xf0;
+
+    if (pwrcnd) {
+        /* eject/load only happens for power condition == 0 */
+        return;
+    }
 
     if (loej) {
         if (!start && !s->tray_open && s->tray_locked) {
@@ -887,8 +886,11 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
             ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
             return;
         }
-        bdrv_eject(s->bs, !start);
-        s->tray_open = !start;
+
+        if (s->tray_open != !start) {
+            bdrv_eject(s->bs, !start);
+            s->tray_open = !start;
+        }
     }
 
     ide_atapi_cmd_ok(s);
@@ -957,6 +959,36 @@ static void cmd_read_cdvd_capacity(IDEState *s, uint8_t* buf)
     ide_atapi_cmd_reply(s, 8, 8);
 }
 
+static void cmd_read_disc_information(IDEState *s, uint8_t* buf)
+{
+    uint8_t type = buf[1] & 7;
+    uint32_t max_len = ube16_to_cpu(buf + 7);
+
+    /* Types 1/2 are only defined for Blu-Ray.  */
+    if (type != 0) {
+        ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
+                            ASC_INV_FIELD_IN_CMD_PACKET);
+        return;
+    }
+
+    memset(buf, 0, 34);
+    buf[1] = 32;
+    buf[2] = 0xe; /* last session complete, disc finalized */
+    buf[3] = 1;   /* first track on disc */
+    buf[4] = 1;   /* # of sessions */
+    buf[5] = 1;   /* first track of last session */
+    buf[6] = 1;   /* last track of last session */
+    buf[7] = 0x20; /* unrestricted use */
+    buf[8] = 0x00; /* CD-ROM or DVD-ROM */
+    /* 9-10-11: most significant byte corresponding bytes 4-5-6 */
+    /* 12-23: not meaningful for CD-ROM or DVD-ROM */
+    /* 24-31: disc bar code */
+    /* 32: disc application code */
+    /* 33: number of OPC tables */
+
+    ide_atapi_cmd_reply(s, 34, max_len);
+}
+
 static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
 {
     int max_len;
@@ -1038,7 +1070,6 @@ static const struct {
     [ 0x00 ] = { cmd_test_unit_ready,               CHECK_READY },
     [ 0x03 ] = { cmd_request_sense,                 ALLOW_UA },
     [ 0x12 ] = { cmd_inquiry,                       ALLOW_UA },
-    [ 0x1a ] = { cmd_mode_sense, /* (6) */          0 },
     [ 0x1b ] = { cmd_start_stop_unit,               0 }, /* [1] */
     [ 0x1e ] = { cmd_prevent_allow_medium_removal,  0 },
     [ 0x25 ] = { cmd_read_cdvd_capacity,            CHECK_READY },
@@ -1047,6 +1078,7 @@ static const struct {
     [ 0x43 ] = { cmd_read_toc_pma_atip,             CHECK_READY },
     [ 0x46 ] = { cmd_get_configuration,             ALLOW_UA },
     [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA },
+    [ 0x51 ] = { cmd_read_disc_information,         CHECK_READY },
     [ 0x5a ] = { cmd_mode_sense, /* (10) */         0 },
     [ 0xa8 ] = { cmd_read, /* (12) */               CHECK_READY },
     [ 0xad ] = { cmd_read_dvd_structure,            CHECK_READY },
@@ -1089,12 +1121,17 @@ void ide_atapi_cmd(IDEState *s)
      * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
      * states rely on this behavior.
      */
-    if (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) {
-        ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+    if (!(atapi_cmd_table[s->io_buffer[0]].flags & ALLOW_UA) &&
+        !s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) {
+
+        if (s->cdrom_changed == 1) {
+            ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+            s->cdrom_changed = 2;
+        } else {
+            ide_atapi_cmd_error(s, UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED);
+            s->cdrom_changed = 0;
+        }
 
-        s->cdrom_changed = 0;
-        s->sense_key = UNIT_ATTENTION;
-        s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED;
         return;
     }
 
This page took 0.034013 seconds and 4 git commands to generate.