From 8a9c16f69e3ecbcc6e6bc068012986b87412c876 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 13 Sep 2011 16:26:06 +0200 Subject: [PATCH] scsi-disk: report media changed via unit attention sense codes Building on the previous patch, this one adds a media change callback to scsi-disk. Signed-off-by: Paolo Bonzini Signed-off-by: Kevin Wolf --- hw/scsi-bus.c | 5 +++++ hw/scsi-disk.c | 29 ++++++++++++++++++++++++++++- hw/scsi.h | 2 ++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index c190509505..867b1a8ebe 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -847,6 +847,11 @@ const struct SCSISense sense_code_RESET = { .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00 }; +/* Unit attention, No medium */ +const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = { + .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00 +}; + /* Unit attention, Medium may have changed */ const struct SCSISense sense_code_MEDIUM_CHANGED = { .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00 diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index a6ef06005e..880cb22eb9 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -71,6 +71,7 @@ struct SCSIDiskState int cluster_size; uint32_t removable; uint64_t max_lba; + bool media_changed; QEMUBH *bh; char *version; char *serial; @@ -1198,7 +1199,21 @@ static void scsi_destroy(SCSIDevice *dev) static void scsi_cd_change_media_cb(void *opaque, bool load) { - ((SCSIDiskState *)opaque)->tray_open = !load; + SCSIDiskState *s = opaque; + + /* + * When a CD gets changed, we have to report an ejected state and + * then a loaded state to guests so that they detect tray + * open/close and media change events. Guests that do not use + * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close + * states rely on this behavior. + * + * media_changed governs the state machine used for unit attention + * report. media_event is used by GET EVENT STATUS NOTIFICATION. + */ + s->media_changed = load; + s->tray_open = !load; + s->qdev.unit_attention = SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM); } static bool scsi_cd_is_tray_open(void *opaque) @@ -1217,6 +1232,15 @@ static const BlockDevOps scsi_cd_block_ops = { .is_medium_locked = scsi_cd_is_medium_locked, }; +static void scsi_disk_unit_attention_reported(SCSIDevice *dev) +{ + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); + if (s->media_changed) { + s->media_changed = false; + s->qdev.unit_attention = SENSE_CODE(MEDIUM_CHANGED); + } +} + static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); @@ -1329,6 +1353,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { .init = scsi_hd_initfn, .destroy = scsi_destroy, .alloc_req = scsi_new_request, + .unit_attention_reported = scsi_disk_unit_attention_reported, .qdev.props = (Property[]) { DEFINE_SCSI_DISK_PROPERTIES(), DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), @@ -1343,6 +1368,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { .init = scsi_cd_initfn, .destroy = scsi_destroy, .alloc_req = scsi_new_request, + .unit_attention_reported = scsi_disk_unit_attention_reported, .qdev.props = (Property[]) { DEFINE_SCSI_DISK_PROPERTIES(), DEFINE_PROP_END_OF_LIST(), @@ -1356,6 +1382,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { .init = scsi_disk_initfn, .destroy = scsi_destroy, .alloc_req = scsi_new_request, + .unit_attention_reported = scsi_disk_unit_attention_reported, .qdev.props = (Property[]) { DEFINE_SCSI_DISK_PROPERTIES(), DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), diff --git a/hw/scsi.h b/hw/scsi.h index 6d40b8e4f9..7004aaaf5d 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -161,6 +161,8 @@ extern const struct SCSISense sense_code_IO_ERROR; extern const struct SCSISense sense_code_I_T_NEXUS_LOSS; /* Command aborted, Logical Unit failure */ extern const struct SCSISense sense_code_LUN_FAILURE; +/* LUN not ready, Medium not present */ +extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM; /* Unit attention, Power on, reset or bus device reset occurred */ extern const struct SCSISense sense_code_RESET; /* Unit attention, Medium may have changed*/