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, which is a bitmap of
"sense keys to generate uevent" 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[587.353177] change /devices/pci:00/XX
ACTION=change
CDB=\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00
DEVPATH=/devices/pci:00/:00:01.0/:01:00.0/host6/XX
DEVTYPE=scsi_device
DRIVER=sd
MODALIAS=scsi:t-0x00
SDEV_SENSE=1
SENSE_BUFFER=\x72\x03\x11\x14\x00\x00\x00\x34\x00\x0a\x80
SENSE_CODE=3/11/14
SEQNUM=4796
SUBSYSTEM=scsi
Signed-off-by: Song Liu
---
drivers/scsi/Kconfig | 14 +++
drivers/scsi/scsi_error.c | 43 ++
drivers/scsi/scsi_lib.c| 58 +-
drivers/scsi/scsi_sysfs.c | 51
include/scsi/scsi_common.h | 6 +
include/scsi/scsi_device.h | 27 -
6 files changed, 197 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index d384f4f..0fb672b 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -226,6 +226,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 ac31964..b8ef869 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -426,6 +426,48 @@ 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;
+ unsigned char sb_len;
+
+ if (!test_bit(sshdr->sense_key & 0xf,
+ >sense_event_filter))
+ return;
+ evt = sdev_evt_alloc(SDEV_EVT_SCSI_SENSE, GFP_ATOMIC);
+ if (!evt)
+ return;
+
+ evt->sense_evt_data.cmnd = kzalloc(scmd->cmd_len, GFP_ATOMIC);
+ if (!evt->sense_evt_data.cmnd)
+ goto alloc_cmd_fail;
+
+ sb_len = scsi_sense_data_length(scmd->sense_buffer);
+
+ evt->sense_evt_data.sense_buffer = kzalloc(sb_len, GFP_ATOMIC);
+ if (!evt->sense_evt_data.sense_buffer)
+ goto alloc_sense_fail;
+
+ evt->sense_evt_data.cmd_len = scmd->cmd_len;
+ evt->sense_evt_data.sb_len = sb_len;
+ memcpy(evt->sense_evt_data.cmnd, scmd->cmnd, scmd->cmd_len);
+ memcpy(evt->sense_evt_data.sense_buffer, scmd->sense_buffer, sb_len);
+
+ sdev_evt_send(sdev, evt);
+ return;
+alloc_sense_fail:
+ kfree(evt->sense_evt_data.cmnd);
+alloc_cmd_fail:
+ kfree(evt);
+#endif
+}
+
/**
* scsi_check_sense - Examine scsi cmd sense
* @scmd: Cmd to have sense checked.
@@ -446,6 +488,7 @@ int scsi_check_sense(struct scsi_cmnd *scmd)
return FAILED; /* no valid sense data */
scsi_report_sense(sdev, );
+ scsi_send_sense_uevent(sdev, scmd, );
if (scsi_sense_is_deferred())
return NEEDS_RETRY;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 41c19c7..67cc0fb 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2677,7 +2677,15 @@ 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];
+ char *envp[5]; /* SDEV_EVT_SCSI_SENSE needs most entries (4) */
+#ifdef CONFIG_SCSI_SENSE_UEVENT
+ char *buf = NULL;
+ int i;
+ int buf_size;
+ int offset;
+ struct scsi_sense_hdr sshdr;
+#endif
+
switch (evt->evt_type) {
case SDEV_EVT_MEDIA_CHANGE:
@@ -2702,6 +2710,49 @@ static void scsi_evt_emit(struct scsi_device *sdev,
struct scsi_event *evt)
case