On 05/12/2017 09:02 PM, Song Liu wrote:
>
>> On May 3, 2017, at 5:50 PM, Song Liu wrote:
>>
>> This patch adds capability for SCSI layer to generate uevent for SCSI
>> sense code. The feature is gated by CONFIG_SCSI_SENSE_UEVENT.
>>
>> We can configure which sense keys generate uevent for each device
>> through sysfs entry sense_event_filter. For example, the following
>> enables uevent for MEDIUM_ERROR (0x03) and HARDWARE_ERROR (0x04)
>> on scsi drive sdc:
>>
>>echo 0x000c > /sys/block/sdc/device/sense_event_filter
>>
>> Here is an example output captured by udevadm:
>>
>> KERNEL[1214.945358] change /devices/pci:00/XXX
>> ACTION=change
>> DEVPATH=/devices/pci:00/:00:01.0/:01:00.0/host6/XXX
>> DEVTYPE=scsi_device
>> DRIVER=sd
>> LBA=0
>> MODALIAS=scsi:t-0x00
>> SDEV_UA=SCSI_SENSE
>> SENSE_CODE=3/11/14
>> SEQNUM=4536
>> SIZE=4096
>> SUBSYSTEM=scsi
>>
>> Signed-off-by: Song Liu
>> ---
>> drivers/scsi/Kconfig | 14 +++
>> drivers/scsi/scsi_error.c | 26
>> drivers/scsi/scsi_lib.c| 27 +++--
>> drivers/scsi/scsi_sysfs.c | 60
>> ++
>> include/scsi/scsi_device.h | 26 +++-
>> 5 files changed, 150 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
>> index 3c52867..4f7f211 100644
>> --- a/drivers/scsi/Kconfig
>> +++ b/drivers/scsi/Kconfig
>> @@ -237,6 +237,20 @@ config SCSI_LOGGING
>>there should be no noticeable performance impact as long as you have
>>logging turned off.
>>
>> +config SCSI_SENSE_UEVENT
>> +bool "SCSI sense code logging"
>> +depends on SCSI
>> +default n
>> +---help---
>> + This turns on uevent for SCSI sense code.
>> +
>> + You can configure which sense keys generate uevent for each device
>> + through sysfs entry sense_event_filter. For example, the following
>> + enables uevent for MEDIUM_ERROR (0x03) and HARDWARE_ERROR (0x04)
>> + on scsi drive sdc:
>> +
>> + echo 0x000c > /sys/block/sdc/device/sense_event_filter
>> +
>> config SCSI_SCAN_ASYNC
>> bool "Asynchronous SCSI scanning"
>> depends on SCSI
>> diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
>> index d70c67c..eda150e 100644
>> --- a/drivers/scsi/scsi_error.c
>> +++ b/drivers/scsi/scsi_error.c
>> @@ -426,6 +426,31 @@ static void scsi_report_sense(struct scsi_device *sdev,
>> }
>> }
>>
>> +/*
>> + * generate uevent when receiving sense code from device
>> + */
>> +static void scsi_send_sense_uevent(struct scsi_device *sdev,
>> + struct scsi_cmnd *scmd,
>> + struct scsi_sense_hdr *sshdr)
>> +{
>> +#ifdef CONFIG_SCSI_SENSE_UEVENT
>> +struct scsi_event *evt;
>> +
>> +if (!test_bit(sshdr->sense_key & 0xf,
>> + &sdev->sense_event_filter))
>> +return;
>> +evt = sdev_evt_alloc(SDEV_EVT_SCSI_SENSE, GFP_ATOMIC);
>> +if (!evt)
>> +return;
>> +
>> +evt->sense_evt_data.lba = scsi_get_lba(scmd);
>> +evt->sense_evt_data.size = blk_rq_bytes(scmd->request);
>> +memcpy(&evt->sense_evt_data.sshdr, sshdr,
>> + sizeof(struct scsi_sense_hdr));
>> +sdev_evt_send(sdev, evt);
>> +#endif
>> +}
>> +
>> /**
>> * scsi_check_sense - Examine scsi cmd sense
>> * @scmd:Cmd to have sense checked.
>> @@ -446,6 +471,7 @@ int scsi_check_sense(struct scsi_cmnd *scmd)
>> return FAILED; /* no valid sense data */
>>
>> scsi_report_sense(sdev, &sshdr);
>> +scsi_send_sense_uevent(sdev, scmd, &sshdr);
>>
>> if (scsi_sense_is_deferred(&sshdr))
>> return NEEDS_RETRY;
>> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
>> index 95f963b..1095f27 100644
>> --- a/drivers/scsi/scsi_lib.c
>> +++ b/drivers/scsi/scsi_lib.c
>> @@ -2656,8 +2656,9 @@ EXPORT_SYMBOL(scsi_device_set_state);
>> */
>> static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
>> {
>> -int idx = 0;
>> -char *envp[3];
>> +int idx = 0, i;
>> +char *envp[5]; /* SDEV_EVT_SCSI_SENSE needs most entries (4) */
>> +int free_envp = -1;
>>
>> switch (evt->evt_type) {
>> case SDEV_EVT_MEDIA_CHANGE:
>> @@ -2682,6 +2683,23 @@ static void scsi_evt_emit(struct scsi_device *sdev,
>> struct scsi_event *evt)
>> case SDEV_EVT_ALUA_STATE_CHANGE_REPORTED:
>> envp[idx++] = "SDEV_UA=ASYMMETRIC_ACCESS_STATE_CHANGED";
>> break;
>> +#ifdef CONFIG_SCSI_SENSE_UEVENT
>> +case SDEV_EVT_SCSI_SENSE:
>> +envp[idx++] = "SDEV_UA=SCSI_SENSE";
>> +for (i = idx; i < idx + 3; ++i) {
>> +envp[i] = kzalloc(32, GFP_ATOMIC);
>> +if (!envp[i])
>> +break;
>> +free_envp = i;
>> +}
>> +snprintf(envp[idx++], 32, "LBA=%lu", evt->sense_evt_data.lba);
>> +