diff options
| author | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
|---|---|---|
| committer | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
| commit | 79828b4fa835f73cdaf4bffa48696abdcbea9d02 (patch) | |
| tree | 5e0fa7156acb75ba603022bc807df8f2fedb97a8 /drivers/scsi/scsi_error.c | |
| parent | 721b51fcf91898299d96f4b72cb9434cda29dce6 (diff) | |
| parent | 8c1a9d6323abf0fb1e5dad96cf3f1c783505ea5a (diff) | |
Merge remote-tracking branch 'asoc/fix/rt5645' into asoc-fix-rt5645
Diffstat (limited to 'drivers/scsi/scsi_error.c')
| -rw-r--r-- | drivers/scsi/scsi_error.c | 127 | 
1 files changed, 24 insertions, 103 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 106884a5444e..66a96cd98b97 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -26,7 +26,6 @@  #include <linux/blkdev.h>  #include <linux/delay.h>  #include <linux/jiffies.h> -#include <asm/unaligned.h>  #include <scsi/scsi.h>  #include <scsi/scsi_cmnd.h> @@ -34,9 +33,11 @@  #include <scsi/scsi_device.h>  #include <scsi/scsi_driver.h>  #include <scsi/scsi_eh.h> +#include <scsi/scsi_common.h>  #include <scsi/scsi_transport.h>  #include <scsi/scsi_host.h>  #include <scsi/scsi_ioctl.h> +#include <scsi/scsi_dh.h>  #include <scsi/sg.h>  #include "scsi_priv.h" @@ -421,6 +422,10 @@ static void scsi_report_sense(struct scsi_device *sdev,  			evt_type = SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED;  			sdev_printk(KERN_WARNING, sdev,  				    "Mode parameters changed"); +		} else if (sshdr->asc == 0x2a && sshdr->ascq == 0x06) { +			evt_type = SDEV_EVT_ALUA_STATE_CHANGE_REPORTED; +			sdev_printk(KERN_WARNING, sdev, +				    "Asymmetric access state changed");  		} else if (sshdr->asc == 0x2a && sshdr->ascq == 0x09) {  			evt_type = SDEV_EVT_CAPACITY_CHANGE_REPORTED;  			sdev_printk(KERN_WARNING, sdev, @@ -460,11 +465,10 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)  	if (scsi_sense_is_deferred(&sshdr))  		return NEEDS_RETRY; -	if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh && -			sdev->scsi_dh_data->scsi_dh->check_sense) { +	if (sdev->handler && sdev->handler->check_sense) {  		int rc; -		rc = sdev->scsi_dh_data->scsi_dh->check_sense(sdev, &sshdr); +		rc = sdev->handler->check_sense(sdev, &sshdr);  		if (rc != SCSI_RETURN_NOT_HANDLED)  			return rc;  		/* handler does not care. Drop down to default handling */ @@ -944,7 +948,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,  			    scmd->sdb.length);  		scmd->sdb.table.sgl = &ses->sense_sgl;  		scmd->sc_data_direction = DMA_FROM_DEVICE; -		scmd->sdb.table.nents = 1; +		scmd->sdb.table.nents = scmd->sdb.table.orig_nents = 1;  		scmd->cmnd[0] = REQUEST_SENSE;  		scmd->cmnd[4] = scmd->sdb.length;  		scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); @@ -1156,8 +1160,13 @@ int scsi_eh_get_sense(struct list_head *work_q,  	struct Scsi_Host *shost;  	int rtn; +	/* +	 * If SCSI_EH_ABORT_SCHEDULED has been set, it is timeout IO, +	 * should not get sense. +	 */  	list_for_each_entry_safe(scmd, next, work_q, eh_entry) {  		if ((scmd->eh_eflags & SCSI_EH_CANCEL_CMD) || +		    (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) ||  		    SCSI_SENSE_VALID(scmd))  			continue; @@ -2170,8 +2179,17 @@ int scsi_error_handler(void *data)  	 * We never actually get interrupted because kthread_run  	 * disables signal delivery for the created thread.  	 */ -	while (!kthread_should_stop()) { +	while (true) { +		/* +		 * The sequence in kthread_stop() sets the stop flag first +		 * then wakes the process.  To avoid missed wakeups, the task +		 * should always be in a non running state before the stop +		 * flag is checked +		 */  		set_current_state(TASK_INTERRUPTIBLE); +		if (kthread_should_stop()) +			break; +  		if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||  		    shost->host_failed != atomic_read(&shost->host_busy)) {  			SCSI_LOG_ERROR_RECOVERY(1, @@ -2408,45 +2426,6 @@ bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,  EXPORT_SYMBOL(scsi_command_normalize_sense);  /** - * scsi_sense_desc_find - search for a given descriptor type in	descriptor sense data format. - * @sense_buffer:	byte array of descriptor format sense data - * @sb_len:		number of valid bytes in sense_buffer - * @desc_type:		value of descriptor type to find - *			(e.g. 0 -> information) - * - * Notes: - *	only valid when sense data is in descriptor format - * - * Return value: - *	pointer to start of (first) descriptor if found else NULL - */ -const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, -				int desc_type) -{ -	int add_sen_len, add_len, desc_len, k; -	const u8 * descp; - -	if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7]))) -		return NULL; -	if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73)) -		return NULL; -	add_sen_len = (add_sen_len < (sb_len - 8)) ? -			add_sen_len : (sb_len - 8); -	descp = &sense_buffer[8]; -	for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { -		descp += desc_len; -		add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; -		desc_len = add_len + 2; -		if (descp[0] == desc_type) -			return descp; -		if (add_len < 0) // short descriptor ?? -			break; -	} -	return NULL; -} -EXPORT_SYMBOL(scsi_sense_desc_find); - -/**   * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format)   * @sense_buffer:	byte array of sense data   * @sb_len:		number of valid bytes in sense_buffer @@ -2495,61 +2474,3 @@ int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,  	}  }  EXPORT_SYMBOL(scsi_get_sense_info_fld); - -/** - * scsi_build_sense_buffer - build sense data in a buffer - * @desc:	Sense format (non zero == descriptor format, - * 		0 == fixed format) - * @buf:	Where to build sense data - * @key:	Sense key - * @asc:	Additional sense code - * @ascq:	Additional sense code qualifier - * - **/ -void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) -{ -	if (desc) { -		buf[0] = 0x72;	/* descriptor, current */ -		buf[1] = key; -		buf[2] = asc; -		buf[3] = ascq; -		buf[7] = 0; -	} else { -		buf[0] = 0x70;	/* fixed, current */ -		buf[2] = key; -		buf[7] = 0xa; -		buf[12] = asc; -		buf[13] = ascq; -	} -} -EXPORT_SYMBOL(scsi_build_sense_buffer); - -/** - * scsi_set_sense_information - set the information field in a - *		formatted sense data buffer - * @buf:	Where to build sense data - * @info:	64-bit information value to be set - * - **/ -void scsi_set_sense_information(u8 *buf, u64 info) -{ -	if ((buf[0] & 0x7f) == 0x72) { -		u8 *ucp, len; - -		len = buf[7]; -		ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0); -		if (!ucp) { -			buf[7] = len + 0xa; -			ucp = buf + 8 + len; -		} -		ucp[0] = 0; -		ucp[1] = 0xa; -		ucp[2] = 0x80; /* Valid bit */ -		ucp[3] = 0; -		put_unaligned_be64(info, &ucp[4]); -	} else if ((buf[0] & 0x7f) == 0x70) { -		buf[0] |= 0x80; -		put_unaligned_be64(info, &buf[3]); -	} -} -EXPORT_SYMBOL(scsi_set_sense_information);  |