aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_error.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_error.c')
-rw-r--r--drivers/scsi/scsi_error.c52
1 files changed, 42 insertions, 10 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index a5d630f5f519..1de30eb83bb0 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -307,7 +307,20 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
(sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
return FAILED;
- if (blk_barrier_rq(scmd->request))
+ 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 (scmd->request->cmd_flags & REQ_HARDBARRIER)
/*
* barrier requests should always retry on UA
* otherwise block will get a spurious error
@@ -460,14 +473,17 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
*/
return SUCCESS;
case RESERVATION_CONFLICT:
- /*
- * let issuer deal with this, it could be just fine
- */
- return SUCCESS;
+ if (scmd->cmnd[0] == TEST_UNIT_READY)
+ /* it is a success, we probed the device and
+ * found it */
+ return SUCCESS;
+ /* otherwise, we failed to send the command */
+ return FAILED;
case QUEUE_FULL:
scsi_handle_queue_full(scmd->device);
/* fall through */
case BUSY:
+ return NEEDS_RETRY;
default:
return FAILED;
}
@@ -1318,16 +1334,16 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd)
case DID_OK:
break;
case DID_BUS_BUSY:
- return blk_failfast_transport(scmd->request);
+ return (scmd->request->cmd_flags & REQ_FAILFAST_TRANSPORT);
case DID_PARITY:
- return blk_failfast_dev(scmd->request);
+ return (scmd->request->cmd_flags & REQ_FAILFAST_DEV);
case DID_ERROR:
if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
status_byte(scmd->result) == RESERVATION_CONFLICT)
return 0;
/* fall through */
case DID_SOFT_ERROR:
- return blk_failfast_driver(scmd->request);
+ return (scmd->request->cmd_flags & REQ_FAILFAST_DRIVER);
}
switch (status_byte(scmd->result)) {
@@ -1336,7 +1352,9 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd)
* assume caller has checked sense and determinted
* the check condition was retryable.
*/
- return blk_failfast_dev(scmd->request);
+ if (scmd->request->cmd_flags & REQ_FAILFAST_DEV ||
+ scmd->request->cmd_type == REQ_TYPE_BLOCK_PC)
+ return 1;
}
return 0;
@@ -1762,6 +1780,14 @@ int scsi_error_handler(void *data)
* what we need to do to get it up and online again (if we can).
* If we fail, we end up taking the thing offline.
*/
+ if (scsi_autopm_get_host(shost) != 0) {
+ SCSI_LOG_ERROR_RECOVERY(1,
+ printk(KERN_ERR "Error handler scsi_eh_%d "
+ "unable to autoresume\n",
+ shost->host_no));
+ continue;
+ }
+
if (shost->transportt->eh_strategy_handler)
shost->transportt->eh_strategy_handler(shost);
else
@@ -1775,6 +1801,7 @@ int scsi_error_handler(void *data)
* which are still online.
*/
scsi_restart_operations(shost);
+ scsi_autopm_put_host(shost);
set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);
@@ -1872,12 +1899,16 @@ scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
int
scsi_reset_provider(struct scsi_device *dev, int flag)
{
- struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL);
+ struct scsi_cmnd *scmd;
struct Scsi_Host *shost = dev->host;
struct request req;
unsigned long flags;
int rtn;
+ if (scsi_autopm_get_host(shost) < 0)
+ return FAILED;
+
+ scmd = scsi_get_command(dev, GFP_KERNEL);
blk_rq_init(NULL, &req);
scmd->request = &req;
@@ -1934,6 +1965,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scsi_run_host_queues(shost);
scsi_next_command(scmd);
+ scsi_autopm_put_host(shost);
return rtn;
}
EXPORT_SYMBOL(scsi_reset_provider);