[linux-yocto] [PATCH 7/8] scsi_lib: add extended information to MEDIA_CHANGE
Yong, Jonathan
jonathan.yong at intel.com
Thu Jun 30 00:06:53 PDT 2016
From: Vitaly Wool <vwool at dev.rtsoft.ru>
Add media change reason string to SDEV_MEDIA_CHANGE uevent
in the format of "SDEV_MEDIA_CHANGE_REASON=<reason>, where
reason is one of MEDIA_DETACH, MEDIA_ATTACH and MEDIA_BAD.
Signed-off-by: Vitaly Wool <vwool at dev.rtsoft.ru>
Signed-off-by: Nikita Yushchenko <nyushchenko at dev.rtsoft.ru>
Signed-off-by: Lim Key Seong <key.seong.lim at intel.com>
---
drivers/scsi/scsi_lib.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/scsi/sr.c | 1 +
include/scsi/scsi_device.h | 18 +++++++++++++
3 files changed, 85 insertions(+)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 448ebda..de991c4 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2676,6 +2676,64 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
}
EXPORT_SYMBOL(scsi_device_set_state);
+#define MAX_RETRIES 3
+#define SR_TIMEOUT (3 * HZ)
+
+/**
+ * get_change_reason - Obtain media change reason by querying the device
+ * @sdev: scsi device to get media change reason from.
+ *
+ * Returns reason as specified in @scsi_media_change_reason
+ */
+static enum scsi_media_change_reason get_change_reason(struct scsi_device *sdev)
+{
+ int ret, is_good;
+ enum scsi_media_change_reason reason = SDEV_MEDIA_BAD;
+ struct scsi_sense_hdr sshdr;
+
+ ret = scsi_test_unit_ready(sdev, SR_TIMEOUT, MAX_RETRIES, &sshdr);
+ is_good = scsi_status_is_good(ret);
+ pr_debug("%s: changed %d, is_good %d, asc 0x%x, ascq 0x%x\n",
+ __func__, sdev->changed, is_good, sshdr.asc, sshdr.ascq);
+
+ if (is_good)
+ reason = SDEV_MEDIA_ATTACH;
+ else {
+ switch (sshdr.asc) {
+ case 0x28:
+ case 0x29:
+ reason = SDEV_MEDIA_UNDEF;
+ break;
+
+ case 0x04:
+ if (sshdr.ascq == 0x01) {
+ reason = SDEV_MEDIA_UNDEF;
+ break;
+ }
+ /* otherwise fall through */
+ case 0x3A:
+ reason = SDEV_MEDIA_DETACH;
+ break;
+
+ default:
+ reason = SDEV_MEDIA_BAD;
+ break;
+ }
+ }
+ if (!sdev->changed && reason == sdev->last_change_reason)
+ reason = SDEV_MEDIA_UNDEF;
+ else
+ sdev->last_change_reason = reason;
+ return reason;
+}
+
+static char *media_change_reasons[SDEV_MEDIA_REASON_MAX + 1] = {
+ [SDEV_MEDIA_ATTACH] = "SDEV_MEDIA_CHANGE_REASON=MEDIA_ATTACH",
+ [SDEV_MEDIA_DETACH] = "SDEV_MEDIA_CHANGE_REASON=MEDIA_DETACH",
+ [SDEV_MEDIA_BAD] = "SDEV_MEDIA_CHANGE_REASON=MEDIA_BAD",
+};
+
+
/**
* sdev_evt_emit - emit a single SCSI device uevent
* @sdev: associated SCSI device
@@ -2687,10 +2745,18 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
{
int idx = 0;
char *envp[3];
+ enum scsi_media_change_reason r;
switch (evt->evt_type) {
case SDEV_EVT_MEDIA_CHANGE:
envp[idx++] = "SDEV_MEDIA_CHANGE=1";
+ if (sdev->add_change_reason) {
+ r = get_change_reason(sdev);
+ if (media_change_reasons[r])
+ envp[idx++] = media_change_reasons[r];
+ pr_debug("%s: reason %s\n", __func__,
+ media_change_reasons[r] ?: "n/a");
+ }
break;
case SDEV_EVT_INQUIRY_CHANGE_REPORTED:
envp[idx++] = "SDEV_UA=INQUIRY_DATA_HAS_CHANGED";
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 64c8674..ca8883c 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -732,6 +732,7 @@ static int sr_probe(struct device *dev)
disk->flags |= GENHD_FL_REMOVABLE;
add_disk(disk);
+ sdev->add_change_reason = 1; /* Let SCSI add change reason to uevent */
sdev_printk(KERN_DEBUG, sdev,
"Attached scsi CD-ROM %s\n", cd->cdi.name);
scsi_autopm_put_device(cd->device);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index a4c9336..012626f 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -64,6 +64,21 @@ enum scsi_device_event {
SDEV_EVT_MAXBITS = SDEV_EVT_LAST + 1
};
+/**
+ * SCSI media change event reasons
+ * @SDEV_MEDIA_ATTACH: a valid medium has been inserted
+ * @SDEV_MEDIA_BAD: an unreadable medium has been inserted into the drive
+ * @SDEV_MEDIA_DETACH: a medium has been removed
+ * @SDEV_MEDIA_UNDEF: no valid reason has been detected
+ */
+enum scsi_media_change_reason {
+ SDEV_MEDIA_ATTACH = 1,
+ SDEV_MEDIA_BAD,
+ SDEV_MEDIA_DETACH,
+ SDEV_MEDIA_UNDEF,
+ SDEV_MEDIA_REASON_MAX = SDEV_MEDIA_UNDEF
+};
+
struct scsi_event {
enum scsi_device_event evt_type;
struct list_head node;
@@ -172,6 +187,7 @@ struct scsi_device {
unsigned is_visible:1; /* is the device visible in sysfs */
unsigned wce_default_on:1; /* Cache is ON by default */
unsigned no_dif:1; /* T10 PI (DIF) should be disabled */
+ unsigned add_change_reason:1; /* Add media change reason? */
unsigned broken_fua:1; /* Don't set FUA bit */
unsigned lun_in_cdb:1; /* Store LUN bits in CDB[1] */
@@ -197,6 +213,8 @@ struct scsi_device {
struct scsi_dh_data *scsi_dh_data;
enum scsi_device_state sdev_state;
+
+ enum scsi_media_change_reason last_change_reason;
unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
--
2.7.3
More information about the linux-yocto
mailing list