[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v3 5/5] atapi: GESN: implement 'media' subcommand
From: |
Amit Shah |
Subject: |
[Qemu-devel] [PATCH v3 5/5] atapi: GESN: implement 'media' subcommand |
Date: |
Tue, 12 Apr 2011 17:13:24 +0530 |
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 <address@hidden>
---
hw/ide/core.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++--
hw/ide/internal.h | 6 +++
2 files changed, 110 insertions(+), 5 deletions(-)
diff --git a/hw/ide/core.c b/hw/ide/core.c
index a9bc1e3..1b2ed6a 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1084,6 +1084,49 @@ static int ide_dvd_read_structure(IDEState *s, int
format,
}
}
+static unsigned int event_status_media(IDEState *s,
+ uint8_t *buf,
+ unsigned int max_len)
+{
+ enum media_event_code {
+ no_change = 0, /* Status unchanged */
+ eject_requested, /* received a request from user to eject */
+ new_media, /* new media inserted and ready for access */
+ media_removal, /* only for media changers */
+ media_changed, /* only for media changers */
+ bg_format_completed, /* MRW or DVD+RW b/g format completed */
+ bg_format_restarted, /* MRW or DVD+RW b/g format restarted */
+ };
+ enum media_status {
+ tray_open = 1,
+ media_present = 2,
+ };
+ uint8_t event_code, media_status;
+
+ media_status = 0;
+ if (s->bs->tray_open) {
+ media_status = tray_open;
+ } else if (bdrv_is_inserted(s->bs)) {
+ media_status = media_present;
+ }
+
+ /* Event notification descriptor */
+ event_code = no_change;
+ if (media_status != tray_open && s->events.new_media) {
+ event_code = 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)
@@ -1104,6 +1147,26 @@ static void
handle_get_event_status_notification(IDEState *s,
uint8_t supported_events;
} __attribute((packed)) *gesn_event_header;
+ enum notification_class_request_type {
+ reserved1 = 1 << 0,
+ operational_change = 1 << 1,
+ power_management = 1 << 2,
+ external_request = 1 << 3,
+ media = 1 << 4,
+ multi_host = 1 << 5,
+ device_busy = 1 << 6,
+ 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;
@@ -1121,13 +1184,26 @@ 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 = media;
gesn_event_header->notification_class = 0;
- gesn_event_header->notification_class = 0x80; /* No event available */
- used_len = sizeof(*gesn_event_header);
-
+ /*
+ * 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 & media) {
+ gesn_event_header->notification_class |= enc_media;
+ used_len = event_status_media(s, buf, max_len);
+ } 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);
@@ -1657,6 +1733,7 @@ static void cdrom_change_cb(void *opaque, int reason)
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->bus);
}
@@ -2801,6 +2878,25 @@ static bool ide_drive_pio_state_needed(void *opaque)
return (s->status & DRQ_STAT) != 0;
}
+static bool ide_atapi_gesn_needed(void *opaque)
+{
+ IDEState *s = opaque;
+
+ return s->events.new_media || s->events.eject_request;
+}
+
+/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
+const VMStateDescription vmstate_ide_atapi_gesn_state = {
+ .name ="ide_drive/atapi/gesn_state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_BOOL(events.new_media, IDEState),
+ VMSTATE_BOOL(events.eject_request, IDEState),
+ }
+};
+
const VMStateDescription vmstate_ide_drive_pio_state = {
.name = "ide_drive/pio_state",
.version_id = 1,
@@ -2855,6 +2951,9 @@ const VMStateDescription vmstate_ide_drive = {
.vmsd = &vmstate_ide_drive_pio_state,
.needed = ide_drive_pio_state_needed,
}, {
+ .vmsd = &vmstate_ide_atapi_gesn_state,
+ .needed = ide_atapi_gesn_needed,
+ }, {
/* empty */
}
}
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index d533fb6..ba7e9a8 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -373,6 +373,11 @@ typedef int DMAFunc(IDEDMA *);
typedef int DMAIntFunc(IDEDMA *, int);
typedef void DMARestartFunc(void *, int, int);
+struct unreported_events {
+ bool eject_request;
+ bool new_media;
+};
+
/* NOTE: IDEState represents in fact one drive */
struct IDEState {
IDEBus *bus;
@@ -408,6 +413,7 @@ struct IDEState {
BlockDriverState *bs;
char version[9];
/* ATAPI specific */
+ struct unreported_events events;
uint8_t sense_key;
uint8_t asc;
uint8_t cdrom_changed;
--
1.7.4.2
- [Qemu-devel] [PATCH v3 2/5] atapi: Move GET_EVENT_STATUS_NOTIFICATION command handling to its own function, (continued)
[Qemu-devel] [PATCH v3 5/5] atapi: GESN: implement 'media' subcommand,
Amit Shah <=