[SCSI] Generate uevents on certain unit attention codes

Generate a uevent when the following Unit Attention ASC/ASCQ
codes are received:

    2A/01  MODE PARAMETERS CHANGED
    2A/09  CAPACITY DATA HAS CHANGED
    38/07  THIN PROVISIONING SOFT THRESHOLD REACHED
    3F/03  INQUIRY DATA HAS CHANGED
    3F/0E  REPORTED LUNS DATA HAS CHANGED

Log kernel messages when the following Unit Attention ASC/ASCQ
codes are received that are not as specific as those above:

    2A/xx  PARAMETERS CHANGED
    3F/xx  TARGET OPERATING CONDITIONS HAVE CHANGED

Added logic to set expecting_lun_change for other LUNs on the target
after REPORTED LUNS DATA HAS CHANGED is received, so that duplicate
uevents are not generated, and clear expecting_lun_change when a
REPORT LUNS command completes, in accordance with the SPC-3
specification regarding reporting of the 3F 0E ASC/ASCQ UA.

[jejb: remove SPC3 test in scsi_report_lun_change and some docbook fixes and
       unused variable fix, both reported by Fengguang Wu]
Signed-off-by: Ewan D. Milne <emilne@redhat.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
Ewan D. Milne
2013-08-08 15:07:48 -04:00
committed by James Bottomley
parent f8813d260e
commit 279afdfe78
4 changed files with 127 additions and 22 deletions

View File

@@ -223,6 +223,74 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
}
#endif
/**
* scsi_report_lun_change - Set flag on all *other* devices on the same target
* to indicate that a UNIT ATTENTION is expected.
* @sdev: Device reporting the UNIT ATTENTION
*/
static void scsi_report_lun_change(struct scsi_device *sdev)
{
sdev->sdev_target->expecting_lun_change = 1;
}
/**
* scsi_report_sense - Examine scsi sense information and log messages for
* certain conditions, also issue uevents for some of them.
* @sdev: Device reporting the sense code
* @sshdr: sshdr to be examined
*/
static void scsi_report_sense(struct scsi_device *sdev,
struct scsi_sense_hdr *sshdr)
{
enum scsi_device_event evt_type = SDEV_EVT_MAXBITS; /* i.e. none */
if (sshdr->sense_key == UNIT_ATTENTION) {
if (sshdr->asc == 0x3f && sshdr->ascq == 0x03) {
evt_type = SDEV_EVT_INQUIRY_CHANGE_REPORTED;
sdev_printk(KERN_WARNING, sdev,
"Inquiry data has changed");
} else if (sshdr->asc == 0x3f && sshdr->ascq == 0x0e) {
evt_type = SDEV_EVT_LUN_CHANGE_REPORTED;
scsi_report_lun_change(sdev);
sdev_printk(KERN_WARNING, sdev,
"Warning! Received an indication that the "
"LUN assignments on this target have "
"changed. The Linux SCSI layer does not "
"automatically remap LUN assignments.\n");
} else if (sshdr->asc == 0x3f)
sdev_printk(KERN_WARNING, sdev,
"Warning! Received an indication that the "
"operating parameters on this target have "
"changed. The Linux SCSI layer does not "
"automatically adjust these parameters.\n");
if (sshdr->asc == 0x38 && sshdr->ascq == 0x07) {
evt_type = SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED;
sdev_printk(KERN_WARNING, sdev,
"Warning! Received an indication that the "
"LUN reached a thin provisioning soft "
"threshold.\n");
}
if (sshdr->asc == 0x2a && sshdr->ascq == 0x01) {
evt_type = SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED;
sdev_printk(KERN_WARNING, sdev,
"Mode parameters changed");
} else if (sshdr->asc == 0x2a && sshdr->ascq == 0x09) {
evt_type = SDEV_EVT_CAPACITY_CHANGE_REPORTED;
sdev_printk(KERN_WARNING, sdev,
"Capacity data has changed");
} else if (sshdr->asc == 0x2a)
sdev_printk(KERN_WARNING, sdev,
"Parameters changed");
}
if (evt_type != SDEV_EVT_MAXBITS) {
set_bit(evt_type, sdev->pending_events);
schedule_work(&sdev->event_work);
}
}
/**
* scsi_check_sense - Examine scsi cmd sense
* @scmd: Cmd to have sense checked.
@@ -250,6 +318,8 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
*/
return SUCCESS;
scsi_report_sense(sdev, &sshdr);
if (scsi_sense_is_deferred(&sshdr))
return NEEDS_RETRY;
@@ -314,6 +384,14 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
return NEEDS_RETRY;
}
}
/*
* we might also expect a cc/ua if another LUN on the target
* reported a UA with an ASC/ASCQ of 3F 0E -
* REPORTED LUNS DATA HAS CHANGED.
*/
if (scmd->device->sdev_target->expecting_lun_change &&
sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
return NEEDS_RETRY;
/*
* if the device is in the process of becoming ready, we
* should retry.
@@ -327,26 +405,6 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
if (scmd->device->allow_restart &&
(sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
return FAILED;
if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e)
scmd_printk(KERN_WARNING, scmd,
"Warning! Received an indication that the "
"LUN assignments on this target have "
"changed. The Linux SCSI layer does not "
"automatically remap LUN assignments.\n");
else if (sshdr.asc == 0x3f)
scmd_printk(KERN_WARNING, scmd,
"Warning! Received an indication that the "
"operating parameters on this target have "
"changed. The Linux SCSI layer does not "
"automatically adjust these parameters.\n");
if (sshdr.asc == 0x38 && sshdr.ascq == 0x07)
scmd_printk(KERN_WARNING, scmd,
"Warning! Received an indication that the "
"LUN reached a thin provisioning soft "
"threshold.\n");
/*
* Pass the UA upwards for a determination in the completion
* functions.
@@ -1574,6 +1632,8 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
*/
return ADD_TO_MLQUEUE;
case GOOD:
if (scmd->cmnd[0] == REPORT_LUNS)
scmd->device->sdev_target->expecting_lun_change = 0;
scsi_handle_queue_ramp_up(scmd->device);
case COMMAND_TERMINATED:
return SUCCESS;