From 94fd64ded3b1c44ba74e50e7e65d1006e887d316 Mon Sep 17 00:00:00 2001
Message-Id: <94fd64ded3b1c44ba74e50e7e65d1006e887d316.1350309834.git.minovotn@redhat.com>
In-Reply-To: <14b740b7e3fbafdbfe2e6a302f51d6aa4fa96bf7.1350309834.git.minovotn@redhat.com>
References: <14b740b7e3fbafdbfe2e6a302f51d6aa4fa96bf7.1350309834.git.minovotn@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Fri, 12 Oct 2012 16:22:39 +0200
Subject: [PATCH 07/17] scsi: establish precedence levels for unit attention

RH-Author: Paolo Bonzini <pbonzini@redhat.com>
Message-id: <1350058967-27351-3-git-send-email-pbonzini@redhat.com>
Patchwork-id: 43058
O-Subject: [RHEL 6.4 qemu-kvm PATCH v2 02/10] scsi: establish precedence levels for unit attention
Bugzilla: 808660
RH-Acked-by: Markus Armbruster <armbru@redhat.com>
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
RH-Acked-by: Orit Wasserman <owasserm@redhat.com>

Bugzilla: 808660

When a device is resized, we will report a unit attention condition
for CAPACITY DATA HAS CHANGED.  However, we should ensure that this
condition does not override a more important unit attention condition.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit e48e84ea80cb2e7fe6e48196ce187cfba6e3eb2c)

Conflicts:
	trace-events
---
 hw/scsi-bus.c  | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 hw/scsi-disk.c |  4 ++--
 hw/scsi.h      |  1 +
 trace-events   |  1 +
 4 file modificati, 55 inserzioni(+), 3 rimozioni(-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 hw/scsi-bus.c  | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 hw/scsi-disk.c |  4 ++--
 hw/scsi.h      |  1 +
 trace-events   |  1 +
 4 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 8b47780..ff2dd2b 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1425,6 +1425,55 @@ void scsi_req_abort(SCSIRequest *req, int status)
     scsi_req_unref(req);
 }
 
+static int scsi_ua_precedence(SCSISense sense)
+{
+    if (sense.key != UNIT_ATTENTION) {
+        return INT_MAX;
+    }
+    if (sense.asc == 0x29 && sense.ascq == 0x04) {
+        /* DEVICE INTERNAL RESET goes with POWER ON OCCURRED */
+        return 1;
+    } else if (sense.asc == 0x3F && sense.ascq == 0x01) {
+        /* MICROCODE HAS BEEN CHANGED goes with SCSI BUS RESET OCCURRED */
+        return 2;
+    } else if (sense.asc == 0x29 && (sense.ascq == 0x05 || sense.ascq == 0x06)) {
+        /* These two go with "all others". */
+        ;
+    } else if (sense.asc == 0x29 && sense.ascq <= 0x07) {
+        /* POWER ON, RESET OR BUS DEVICE RESET OCCURRED = 0
+         * POWER ON OCCURRED = 1
+         * SCSI BUS RESET OCCURRED = 2
+         * BUS DEVICE RESET FUNCTION OCCURRED = 3
+         * I_T NEXUS LOSS OCCURRED = 7
+         */
+        return sense.ascq;
+    } else if (sense.asc == 0x2F && sense.ascq == 0x01) {
+        /* COMMANDS CLEARED BY POWER LOSS NOTIFICATION  */
+        return 8;
+    }
+    return (sense.asc << 8) | sense.ascq;
+}
+
+void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense)
+{
+    int prec1, prec2;
+    if (sense.key != UNIT_ATTENTION) {
+        return;
+    }
+    trace_scsi_device_set_ua(sdev->id, sdev->lun, sense.key,
+                             sense.asc, sense.ascq);
+
+    /*
+     * Override a pre-existing unit attention condition, except for a more
+     * important reset condition.
+    */
+    prec1 = scsi_ua_precedence(sdev->unit_attention);
+    prec2 = scsi_ua_precedence(sense);
+    if (prec2 < prec1) {
+        sdev->unit_attention = sense;
+    }
+}
+
 void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
 {
     SCSIRequest *req;
@@ -1433,7 +1482,8 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
         req = QTAILQ_FIRST(&sdev->requests);
         scsi_req_cancel(req);
     }
-    sdev->unit_attention = sense;
+
+    scsi_device_set_ua(sdev, sense);
 }
 
 static char *scsibus_get_dev_path(DeviceState *dev)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 212018a..97bb0e5 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1633,7 +1633,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);
+    scsi_device_set_ua(&s->qdev, SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM));
     s->media_event = true;
     s->eject_request = false;
 }
@@ -1670,7 +1670,7 @@ 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);
+        scsi_device_set_ua(&s->qdev, SENSE_CODE(MEDIUM_CHANGED));
     }
 }
 
diff --git a/hw/scsi.h b/hw/scsi.h
index 0802d72..ec90005 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -227,6 +227,7 @@ void scsi_req_abort(SCSIRequest *req, int status);
 void scsi_req_cancel(SCSIRequest *req);
 void scsi_req_retry(SCSIRequest *req);
 void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
+void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense);
 int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
 SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
 
diff --git a/trace-events b/trace-events
index 39db8eb..f3c9e90 100644
--- a/trace-events
+++ b/trace-events
@@ -159,6 +159,7 @@ disable scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfe
 disable scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64""
 disable scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d"
 disable scsi_req_build_sense(int target, int lun, int tag, int key, int asc, int ascq) "target %d lun %d tag %d key %#02x asc %#02x ascq %#02x"
+disable scsi_device_set_ua(int target, int lun, int key, int asc, int ascq) "target %d lun %d key %#02x asc %#02x ascq %#02x"
 disable scsi_report_luns(int target, int lun, int tag) "target %d lun %d tag %d"
 disable scsi_inquiry(int target, int lun, int tag, int cdb1, int cdb2) "target %d lun %d tag %d page %#02x/%#02x"
 disable scsi_test_unit_ready(int target, int lun, int tag) "target %d lun %d tag %d"
-- 
1.7.11.7

