]> Pileus Git - ~andy/linux/blobdiff - drivers/scsi/scsi_error.c
Merge branch 'x86-cpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[~andy/linux] / drivers / scsi / scsi_error.c
index 7ad53fa42766ad597df9b5e0c0739676211c90bc..2bf98469dc4c6df096def2338de1670a72605ba0 100644 (file)
@@ -39,6 +39,8 @@
 #include "scsi_logging.h"
 #include "scsi_transport_api.h"
 
+#include <trace/events/scsi.h>
+
 #define SENSE_TIMEOUT          (10*HZ)
 
 /*
@@ -52,6 +54,7 @@
 void scsi_eh_wakeup(struct Scsi_Host *shost)
 {
        if (shost->host_busy == shost->host_failed) {
+               trace_scsi_eh_wakeup(shost);
                wake_up_process(shost->ehandler);
                SCSI_LOG_ERROR_RECOVERY(5,
                                printk("Waking error handler thread\n"));
@@ -127,6 +130,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req)
        struct scsi_cmnd *scmd = req->special;
        enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
 
+       trace_scsi_dispatch_cmd_timeout(scmd);
        scsi_log_completion(scmd, TIMEOUT_ERROR);
 
        if (scmd->device->host->transportt->eh_timed_out)
@@ -303,6 +307,19 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
                    (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 (blk_barrier_rq(scmd->request))
                        /*
                         * barrier requests should always retry on UA
@@ -970,9 +987,10 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
                                                  "0x%p\n", current->comm,
                                                  scmd));
                rtn = scsi_try_to_abort_cmd(scmd);
-               if (rtn == SUCCESS) {
+               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD;
                        if (!scsi_device_online(scmd->device) ||
+                           rtn == FAST_IO_FAIL ||
                            !scsi_eh_tur(scmd)) {
                                scsi_eh_finish_cmd(scmd, done_q);
                        }
@@ -1099,8 +1117,9 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
                                                  " 0x%p\n", current->comm,
                                                  sdev));
                rtn = scsi_try_bus_device_reset(bdr_scmd);
-               if (rtn == SUCCESS) {
+               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        if (!scsi_device_online(sdev) ||
+                           rtn == FAST_IO_FAIL ||
                            !scsi_eh_tur(bdr_scmd)) {
                                list_for_each_entry_safe(scmd, next,
                                                         work_q, eh_entry) {
@@ -1163,10 +1182,11 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
                                                  "to target %d\n",
                                                  current->comm, id));
                rtn = scsi_try_target_reset(tgtr_scmd);
-               if (rtn == SUCCESS) {
+               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
                                if (id == scmd_id(scmd))
                                        if (!scsi_device_online(scmd->device) ||
+                                           rtn == FAST_IO_FAIL ||
                                            !scsi_eh_tur(tgtr_scmd))
                                                scsi_eh_finish_cmd(scmd,
                                                                   done_q);
@@ -1222,10 +1242,11 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
                                                  " %d\n", current->comm,
                                                  channel));
                rtn = scsi_try_bus_reset(chan_scmd);
-               if (rtn == SUCCESS) {
+               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
                                if (channel == scmd_channel(scmd))
                                        if (!scsi_device_online(scmd->device) ||
+                                           rtn == FAST_IO_FAIL ||
                                            !scsi_eh_tur(scmd))
                                                scsi_eh_finish_cmd(scmd,
                                                                   done_q);
@@ -1259,9 +1280,10 @@ static int scsi_eh_host_reset(struct list_head *work_q,
                                                  , current->comm));
 
                rtn = scsi_try_host_reset(scmd);
-               if (rtn == SUCCESS) {
+               if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
                                if (!scsi_device_online(scmd->device) ||
+                                   rtn == FAST_IO_FAIL ||
                                    (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) ||
                                    !scsi_eh_tur(scmd))
                                        scsi_eh_finish_cmd(scmd, done_q);
@@ -1753,6 +1775,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
@@ -1766,6 +1796,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);
@@ -1863,12 +1894,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;
 
@@ -1925,6 +1960,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);