From: Vitaly Wool <vw...@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 <vw...@dev.rtsoft.ru> Signed-off-by: Nikita Yushchenko <nyushche...@dev.rtsoft.ru> Signed-off-by: Lim Key Seong <key.seong....@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 -- _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto