Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 340e01248478ba8b78a6d4d1809b1eff > files > 267

kvm-83-270.el5_11.src.rpm

From 13519a81116ee984875cab045e3f1cacc0d22222 Mon Sep 17 00:00:00 2001
From: Markus Armbruster <armbru@redhat.com>
Date: Tue, 19 Apr 2011 15:10:21 -0300
Subject: [PATCH 09/10] atapi: GESN: implement 'media' subcommand

RH-Author: Markus Armbruster <armbru@redhat.com>
Message-id: <1303225822-22611-8-git-send-email-armbru@redhat.com>
Patchwork-id: 22560
O-Subject: [PATCH RHEL5 qemu-kvm 7/8] atapi: GESN: implement 'media' subcommand
Bugzilla: 652135
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
RH-Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com>
RH-Acked-by: Amit Shah <amit.shah@redhat.com>
RH-Acked-by: Alex Williamson <alex.williamson@redhat.com>

Implement the 'media' sub-command of the GET_EVENT_STATUS_NOTIFICATION
command.  This helps us report tray open, tray closed, no media, media
present states to the guest.

Newer Linux kernels (2.6.38+) rely on this command to revalidate discs
after media change.

This patch also sends out tray open/closed status to the guest driver
when requested e.g. via the CDROM_DRIVE_STATUS ioctl (thanks Markus).
Without such notification, the guest and qemu's tray open/close status
was frequently out of sync, causing installers like Anaconda detecting
no disc instead of tray open, confusing them terribly.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>

Manually cherry-picked from qemu commit 996faf1ad4a93342e381766d95686b16624f0dbd
Backported from vmstate to register_optional_savevm().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 qemu/hw/ide.c |  143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 139 insertions(+), 4 deletions(-)

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 qemu/hw/ide.c |  143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 139 insertions(+), 4 deletions(-)

diff --git a/qemu/hw/ide.c b/qemu/hw/ide.c
index 033ce62..c68bfae 100644
--- a/qemu/hw/ide.c
+++ b/qemu/hw/ide.c
@@ -22,6 +22,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include <stdbool.h>
 #include "hw.h"
 #include "pc.h"
 #include "pci.h"
@@ -375,6 +376,11 @@ struct IDEState;
 
 typedef void EndTransferFunc(struct IDEState *);
 
+struct unreported_events {
+    bool eject_request;
+    bool new_media;
+};
+
 /* NOTE: IDEState represents in fact one drive */
 typedef struct IDEState {
     /* ide config */
@@ -415,6 +421,7 @@ typedef struct IDEState {
     struct IDEState *cur_drive;
     BlockDriverState *bs;
     /* ATAPI specific */
+    struct unreported_events events;
     uint8_t sense_key;
     uint8_t asc;
     uint8_t cdrom_changed;
@@ -1614,6 +1621,48 @@ static int ide_dvd_read_structure(IDEState *s, int format,
     }
 }
 
+static unsigned int event_status_media(IDEState *s,
+                                       uint8_t *buf)
+{
+    enum media_event_code {
+        MEC_NO_CHANGE = 0,       /* Status unchanged */
+        MEC_EJECT_REQUESTED,     /* received a request from user to eject */
+        MEC_NEW_MEDIA,           /* new media inserted and ready for access */
+        MEC_MEDIA_REMOVAL,       /* only for media changers */
+        MEC_MEDIA_CHANGED,       /* only for media changers */
+        MEC_BG_FORMAT_COMPLETED, /* MRW or DVD+RW b/g format completed */
+        MEC_BG_FORMAT_RESTARTED, /* MRW or DVD+RW b/g format restarted */
+    };
+    enum media_status {
+        MS_TRAY_OPEN = 1,
+        MS_MEDIA_PRESENT = 2,
+    };
+    uint8_t event_code, media_status;
+
+    media_status = 0;
+    if (s->bs->tray_open) {
+        media_status = MS_TRAY_OPEN;
+    } else if (bdrv_is_inserted(s->bs)) {
+        media_status = MS_MEDIA_PRESENT;
+    }
+
+    /* 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;
+    }
+
+    buf[4] = event_code;
+    buf[5] = media_status;
+
+    /* These fields are reserved, just clear them. */
+    buf[6] = 0;
+    buf[7] = 0;
+
+    return 8; /* We wrote to 4 extra bytes from the header */
+}
+
 static void handle_get_event_status_notification(IDEState *s,
                                                  uint8_t *buf,
                                                  const uint8_t *packet)
@@ -1634,6 +1683,26 @@ static void handle_get_event_status_notification(IDEState *s,
         uint8_t supported_events;
     } __attribute((packed)) *gesn_event_header;
 
+    enum notification_class_request_type {
+        NCR_RESERVED1 = 1 << 0,
+        NCR_OPERATIONAL_CHANGE = 1 << 1,
+        NCR_POWER_MANAGEMENT = 1 << 2,
+        NCR_EXTERNAL_REQUEST = 1 << 3,
+        NCR_MEDIA = 1 << 4,
+        NCR_MULTI_HOST = 1 << 5,
+        NCR_DEVICE_BUSY = 1 << 6,
+        NCR_RESERVED2 = 1 << 7,
+    };
+    enum event_notification_class_field {
+        ENC_NO_EVENTS = 0,
+        ENC_OPERATIONAL_CHANGE,
+        ENC_POWER_MANAGEMENT,
+        ENC_EXTERNAL_REQUEST,
+        ENC_MEDIA,
+        ENC_MULTIPLE_HOSTS,
+        ENC_DEVICE_BUSY,
+        ENC_RESERVED,
+    };
     unsigned int max_len, used_len;
 
     gesn_cdb = (void *)packet;
@@ -1651,12 +1720,32 @@ static void handle_get_event_status_notification(IDEState *s,
 
     /* polling mode operation */
 
-    /* We don't support any event class (yet). */
-    gesn_event_header->supported_events = 0;
+    /*
+     * These are the supported events.
+     *
+     * We currently only support requests of the 'media' type.
+     */
+    gesn_event_header->supported_events = NCR_MEDIA;
 
-    gesn_event_header->notification_class = 0x80; /* No event available */
-    used_len = sizeof(*gesn_event_header);
+    /*
+     * We use |= below to set the class field; other bits in this byte
+     * are reserved now but this is useful to do if we have to use the
+     * reserved fields later.
+     */
+    gesn_event_header->notification_class = 0;
 
+    /*
+     * Responses to requests are to be based on request priority.  The
+     * notification_class_request_type enum above specifies the
+     * priority: upper elements are higher prio than lower ones.
+     */
+    if (gesn_cdb->class & NCR_MEDIA) {
+        gesn_event_header->notification_class |= ENC_MEDIA;
+        used_len = event_status_media(s, buf);
+    } else {
+        gesn_event_header->notification_class = 0x80; /* No event available */
+        used_len = sizeof(*gesn_event_header);
+    }
     gesn_event_header->len = cpu_to_be16(used_len
                                          - sizeof(*gesn_event_header));
     ide_atapi_cmd_reply(s, used_len, max_len);
@@ -2165,6 +2254,7 @@ static void cdrom_change_cb(void *opaque)
     s->sense_key = SENSE_UNIT_ATTENTION;
     s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED;
     s->cdrom_changed = 1;
+    s->events.new_media = true;
     ide_set_irq(s);
 }
 
@@ -3456,6 +3546,48 @@ static int pci_ide_pio_needed(void *opaque)
     return 0;
 }
 
+static void pci_ide_atapi_gesn_save(QEMUFile* f, void *opaque, int version_id)
+{
+    PCIIDEState *d = opaque;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        IDEState *s = &d->ide_if[i];
+
+        qemu_put_byte(f, s->events.new_media);
+        qemu_put_byte(f, s->events.eject_request);
+    }
+}
+
+static int pci_ide_atapi_gesn_load(QEMUFile* f, void *opaque, int version_id)
+{
+    PCIIDEState *d = opaque;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        IDEState *s = &d->ide_if[i];
+
+        s->events.new_media = qemu_get_byte(f);
+        s->events.eject_request = qemu_get_byte(f);
+    }
+    return 0;
+}
+
+static int pci_ide_atapi_gesn_needed(void *opaque)
+{
+    PCIIDEState *d = opaque;
+
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        IDEState *s = &d->ide_if[i];
+        if (s->events.new_media || s->events.eject_request) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
 /* XXX: call it also when the MRDMODE is changed from the PCI config
    registers */
 static void cmd646_update_irq(PCIIDEState *d)
@@ -3623,6 +3755,9 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
      * old->new migrations where we could lose inflight pio. */
     register_optional_savevm("ide/pio_state", 0, 1, pci_ide_pio_save,
                              pci_ide_pio_load, pci_ide_pio_needed, d);
+    register_optional_savevm("ide_drive/atapi/gesn_state", 0, 1,
+                             pci_ide_atapi_gesn_save, pci_ide_atapi_gesn_load,
+                             pci_ide_atapi_gesn_needed, d);
     register_savevm("ide", 0, version_id, pci_ide_save, pci_ide_load, d);
 }
 
-- 
1.7.5.141.g791a