diff mbox

[12/35] scsi-disk: report media changed via GET EVENT STATUS NOTIFICATION

Message ID 1318503845-11473-13-git-send-email-pbonzini@redhat.com
State New
Headers show

Commit Message

Paolo Bonzini Oct. 13, 2011, 11:03 a.m. UTC
This adds support for media change notification via the GET EVENT STATUS
NOTIFICATION command, used by Linux versions 2.6.38 and newer.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi-disk.c |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 53 insertions(+), 4 deletions(-)

Comments

Kevin Wolf Oct. 21, 2011, 11:54 a.m. UTC | #1
Am 13.10.2011 13:03, schrieb Paolo Bonzini:
> This adds support for media change notification via the GET EVENT STATUS
> NOTIFICATION command, used by Linux versions 2.6.38 and newer.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Looks good, but the ATAPI version of the code is somewhat nicer to read.

Kevin
Paolo Bonzini Oct. 21, 2011, 1:08 p.m. UTC | #2
On 10/21/2011 01:54 PM, Kevin Wolf wrote:
>> This adds support for media change notification via the GET EVENT STATUS
>> >  NOTIFICATION command, used by Linux versions 2.6.38 and newer.
>> >
>> >  Signed-off-by: Paolo Bonzini<pbonzini@redhat.com>
> Looks good, but the ATAPI version of the code is somewhat nicer to read.

Yeah, on the other hand even the ATAPI version has a mix of structs and 
buffers (in event_status_media, which also assumes sizeof 
gesn_event_header == 4).

Paolo
diff mbox

Patch

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 14db6a0..ce71df4 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -72,6 +72,7 @@  struct SCSIDiskState
     uint32_t removable;
     uint64_t max_lba;
     bool media_changed;
+    bool media_event;
     QEMUBH *bh;
     char *version;
     char *serial;
@@ -682,11 +683,58 @@  fail:
     return -1;
 }
 
-static int scsi_get_event_status_notification(SCSIDiskState *s,
-                                              SCSIDiskReq *r, uint8_t *outbuf)
+static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
 {
-    scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
-    return -1;
+    uint8_t event_code, media_status;
+
+    media_status = 0;
+    if (s->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->media_event) {
+        event_code = MEC_NEW_MEDIA;
+        s->media_event = false;
+    }
+
+    outbuf[0] = event_code;
+    outbuf[1] = media_status;
+
+    /* These fields are reserved, just clear them. */
+    outbuf[2] = 0;
+    outbuf[3] = 0;
+    return 4;
+}
+
+static int scsi_get_event_status_notification(SCSIDiskState *s, SCSIDiskReq *r,
+                                              uint8_t *outbuf)
+{
+    int size;
+    uint8_t *buf = r->req.cmd.buf;
+    uint8_t notification_class_request = buf[4];
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    if ((buf[1] & 1) == 0) {
+        /* asynchronous */
+        return -1;
+    }
+
+    size = 4;
+    outbuf[0] = outbuf[1] = 0;
+    outbuf[3] = 1 << GESN_MEDIA; /* supported events */
+    if (notification_class_request & (1 << GESN_MEDIA)) {
+        outbuf[2] = GESN_MEDIA;
+        size += scsi_event_status_media(s, &outbuf[size]);
+    } else {
+        outbuf[2] = 0x80;
+    }
+    stw_be_p(outbuf, size - 4);
+    return size;
 }
 
 static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf)
@@ -1416,6 +1464,7 @@  static void scsi_cd_change_media_cb(void *opaque, bool load)
     s->media_changed = load;
     s->tray_open = !load;
     s->qdev.unit_attention = SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM);
+    s->media_event = true;
 }
 
 static bool scsi_cd_is_tray_open(void *opaque)