]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/scsi/scsi_error.c
[SCSI] qla4xxx: Use polling mode for disable interrupt mailbox completion
[mv-sheeva.git] / drivers / scsi / scsi_error.c
index 45c75649b9e083e489e1a935a2617a8d0461749f..633c2395a92a2c918cfd068d541f99063f9470f2 100644 (file)
@@ -3,14 +3,14 @@
  *
  *  SCSI error/timeout handling
  *      Initial versions: Eric Youngdale.  Based upon conversations with
- *                        Leonard Zubkoff and David Miller at Linux Expo, 
+ *                        Leonard Zubkoff and David Miller at Linux Expo,
  *                        ideas originating from all over the place.
  *
  *     Restructured scsi_unjam_host and associated functions.
  *     September 04, 2002 Mike Anderson (andmike@us.ibm.com)
  *
  *     Forward port of Russell King's (rmk@arm.linux.org.uk) changes and
- *     minor  cleanups.
+ *     minor cleanups.
  *     September 30, 2002 Mike Anderson (andmike@us.ibm.com)
  */
 
@@ -129,14 +129,15 @@ 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;
+       struct Scsi_Host *host = scmd->device->host;
 
        trace_scsi_dispatch_cmd_timeout(scmd);
        scsi_log_completion(scmd, TIMEOUT_ERROR);
 
-       if (scmd->device->host->transportt->eh_timed_out)
-               rtn = scmd->device->host->transportt->eh_timed_out(scmd);
-       else if (scmd->device->host->hostt->eh_timed_out)
-               rtn = scmd->device->host->hostt->eh_timed_out(scmd);
+       if (host->transportt->eh_timed_out)
+               rtn = host->transportt->eh_timed_out(scmd);
+       else if (host->hostt->eh_timed_out)
+               rtn = host->hostt->eh_timed_out(scmd);
 
        if (unlikely(rtn == BLK_EH_NOT_HANDLED &&
                     !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
@@ -195,7 +196,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
                                ++total_failures;
                                if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD)
                                        ++cmd_cancel;
-                               else 
+                               else
                                        ++cmd_failed;
                        }
                }
@@ -214,7 +215,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
 
        SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d"
                                          " devices require eh work\n",
-                                 total_failures, devices_failed));
+                                  total_failures, devices_failed));
 }
 #endif
 
@@ -223,7 +224,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
  * @scmd:      Cmd to have sense checked.
  *
  * Return value:
- *     SUCCESS or FAILED or NEEDS_RETRY
+ *     SUCCESS or FAILED or NEEDS_RETRY or TARGET_ERROR
  *
  * Notes:
  *     When a deferred error is detected the current command has
@@ -294,7 +295,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
                        return NEEDS_RETRY;
                }
                /*
-                * if the device is in the process of becoming ready, we 
+                * if the device is in the process of becoming ready, we
                 * should retry.
                 */
                if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01))
@@ -326,17 +327,19 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
                 */
                return SUCCESS;
 
-               /* these three are not supported */
+               /* these are not supported */
        case COPY_ABORTED:
        case VOLUME_OVERFLOW:
        case MISCOMPARE:
-               return SUCCESS;
+       case BLANK_CHECK:
+       case DATA_PROTECT:
+               return TARGET_ERROR;
 
        case MEDIUM_ERROR:
                if (sshdr.asc == 0x11 || /* UNRECOVERED READ ERR */
                    sshdr.asc == 0x13 || /* AMNF DATA FIELD */
                    sshdr.asc == 0x14) { /* RECORD NOT FOUND */
-                       return SUCCESS;
+                       return TARGET_ERROR;
                }
                return NEEDS_RETRY;
 
@@ -344,11 +347,9 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
                if (scmd->device->retry_hwerror)
                        return ADD_TO_MLQUEUE;
                else
-                       return SUCCESS;
+                       return TARGET_ERROR;
 
        case ILLEGAL_REQUEST:
-       case BLANK_CHECK:
-       case DATA_PROTECT:
        default:
                return SUCCESS;
        }
@@ -488,7 +489,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
  */
 static void scsi_eh_done(struct scsi_cmnd *scmd)
 {
-       struct completion     *eh_action;
+       struct completion *eh_action;
 
        SCSI_LOG_ERROR_RECOVERY(3,
                printk("%s scmd: %p result: %x\n",
@@ -507,22 +508,23 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd)
 {
        unsigned long flags;
        int rtn;
+       struct Scsi_Host *host = scmd->device->host;
+       struct scsi_host_template *hostt = host->hostt;
 
        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
                                          __func__));
 
-       if (!scmd->device->host->hostt->eh_host_reset_handler)
+       if (!hostt->eh_host_reset_handler)
                return FAILED;
 
-       rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd);
+       rtn = hostt->eh_host_reset_handler(scmd);
 
        if (rtn == SUCCESS) {
-               if (!scmd->device->host->hostt->skip_settle_delay)
+               if (!hostt->skip_settle_delay)
                        ssleep(HOST_RESET_SETTLE_TIME);
-               spin_lock_irqsave(scmd->device->host->host_lock, flags);
-               scsi_report_bus_reset(scmd->device->host,
-                                     scmd_channel(scmd));
-               spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+               spin_lock_irqsave(host->host_lock, flags);
+               scsi_report_bus_reset(host, scmd_channel(scmd));
+               spin_unlock_irqrestore(host->host_lock, flags);
        }
 
        return rtn;
@@ -536,22 +538,23 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
 {
        unsigned long flags;
        int rtn;
+       struct Scsi_Host *host = scmd->device->host;
+       struct scsi_host_template *hostt = host->hostt;
 
        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
                                          __func__));
 
-       if (!scmd->device->host->hostt->eh_bus_reset_handler)
+       if (!hostt->eh_bus_reset_handler)
                return FAILED;
 
-       rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd);
+       rtn = hostt->eh_bus_reset_handler(scmd);
 
        if (rtn == SUCCESS) {
-               if (!scmd->device->host->hostt->skip_settle_delay)
+               if (!hostt->skip_settle_delay)
                        ssleep(BUS_RESET_SETTLE_TIME);
-               spin_lock_irqsave(scmd->device->host->host_lock, flags);
-               scsi_report_bus_reset(scmd->device->host,
-                                     scmd_channel(scmd));
-               spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+               spin_lock_irqsave(host->host_lock, flags);
+               scsi_report_bus_reset(host, scmd_channel(scmd));
+               spin_unlock_irqrestore(host->host_lock, flags);
        }
 
        return rtn;
@@ -577,16 +580,18 @@ static int scsi_try_target_reset(struct scsi_cmnd *scmd)
 {
        unsigned long flags;
        int rtn;
+       struct Scsi_Host *host = scmd->device->host;
+       struct scsi_host_template *hostt = host->hostt;
 
-       if (!scmd->device->host->hostt->eh_target_reset_handler)
+       if (!hostt->eh_target_reset_handler)
                return FAILED;
 
-       rtn = scmd->device->host->hostt->eh_target_reset_handler(scmd);
+       rtn = hostt->eh_target_reset_handler(scmd);
        if (rtn == SUCCESS) {
-               spin_lock_irqsave(scmd->device->host->host_lock, flags);
+               spin_lock_irqsave(host->host_lock, flags);
                __starget_for_each_device(scsi_target(scmd->device), NULL,
                                          __scsi_report_device_reset);
-               spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+               spin_unlock_irqrestore(host->host_lock, flags);
        }
 
        return rtn;
@@ -605,27 +610,28 @@ static int scsi_try_target_reset(struct scsi_cmnd *scmd)
 static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
 {
        int rtn;
+       struct scsi_host_template *hostt = scmd->device->host->hostt;
 
-       if (!scmd->device->host->hostt->eh_device_reset_handler)
+       if (!hostt->eh_device_reset_handler)
                return FAILED;
 
-       rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd);
+       rtn = hostt->eh_device_reset_handler(scmd);
        if (rtn == SUCCESS)
                __scsi_report_device_reset(scmd->device, NULL);
        return rtn;
 }
 
-static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+static int scsi_try_to_abort_cmd(struct scsi_host_template *hostt, struct scsi_cmnd *scmd)
 {
-       if (!scmd->device->host->hostt->eh_abort_handler)
+       if (!hostt->eh_abort_handler)
                return FAILED;
 
-       return scmd->device->host->hostt->eh_abort_handler(scmd);
+       return hostt->eh_abort_handler(scmd);
 }
 
 static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
 {
-       if (scsi_try_to_abort_cmd(scmd) != SUCCESS)
+       if (scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd) != SUCCESS)
                if (scsi_try_bus_device_reset(scmd) != SUCCESS)
                        if (scsi_try_target_reset(scmd) != SUCCESS)
                                if (scsi_try_bus_reset(scmd) != SUCCESS)
@@ -787,6 +793,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
                case SUCCESS:
                case NEEDS_RETRY:
                case FAILED:
+               case TARGET_ERROR:
                        break;
                case ADD_TO_MLQUEUE:
                        rtn = NEEDS_RETRY;
@@ -845,7 +852,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
  *
  * Description:
  *    See if we need to request sense information.  if so, then get it
- *    now, so we have a better idea of what to do.  
+ *    now, so we have a better idea of what to do.
  *
  * Notes:
  *    This has the unfortunate side effect that if a shost adapter does
@@ -957,7 +964,7 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
                SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting cmd:"
                                                  "0x%p\n", current->comm,
                                                  scmd));
-               rtn = scsi_try_to_abort_cmd(scmd);
+               rtn = scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd);
                if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
                        scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD;
                        if (!scsi_device_online(scmd->device) ||
@@ -965,7 +972,6 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
                            !scsi_eh_tur(scmd)) {
                                scsi_eh_finish_cmd(scmd, done_q);
                        }
-                               
                } else
                        SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting"
                                                          " cmd failed:"
@@ -1009,7 +1015,7 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
  *
  * Notes:
  *    If commands are failing due to not ready, initializing command required,
- *     try revalidating the device, which will end up sending a start unit. 
+ *     try revalidating the device, which will end up sending a start unit.
  */
 static int scsi_eh_stu(struct Scsi_Host *shost,
                              struct list_head *work_q,
@@ -1063,7 +1069,7 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
  *    Try a bus device reset.  Still, look to see whether we have multiple
  *    devices that are jammed or not - if we have multiple devices, it
  *    makes no sense to try bus_device_reset - we really would need to try
- *    a bus_reset instead. 
+ *    a bus_reset instead.
  */
 static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
                                    struct list_head *work_q,
@@ -1163,7 +1169,7 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
 }
 
 /**
- * scsi_eh_bus_reset - send a bus reset 
+ * scsi_eh_bus_reset - send a bus reset
  * @shost:     &scsi host being recovered.
  * @work_q:     &list_head for pending commands.
  * @done_q:    &list_head for processed commands.
@@ -1180,7 +1186,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
         * we really want to loop over the various channels, and do this on
         * a channel by channel basis.  we should also check to see if any
         * of the failed commands are on soft_reset devices, and if so, skip
-        * the reset.  
+        * the reset.
         */
 
        for (channel = 0; channel <= shost->max_channel; channel++) {
@@ -1222,7 +1228,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
 }
 
 /**
- * scsi_eh_host_reset - send a host reset 
+ * scsi_eh_host_reset - send a host reset
  * @work_q:    list_head for processed commands.
  * @done_q:    list_head for processed commands.
  */
@@ -1375,7 +1381,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
                return SUCCESS;
                /*
                 * when the low level driver returns did_soft_error,
-                * it is responsible for keeping an internal retry counter 
+                * it is responsible for keeping an internal retry counter
                 * in order to avoid endless loops (db)
                 *
                 * actually this is a bug in this function here.  we should
@@ -1413,7 +1419,6 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
                         */
                        break;
                /* fallthrough */
-
        case DID_BUS_BUSY:
        case DID_PARITY:
                goto maybe_retry;
@@ -1469,6 +1474,14 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
                rtn = scsi_check_sense(scmd);
                if (rtn == NEEDS_RETRY)
                        goto maybe_retry;
+               else if (rtn == TARGET_ERROR) {
+                       /*
+                        * Need to modify host byte to signal a
+                        * permanent target failure
+                        */
+                       scmd->result |= (DID_TARGET_FAILURE << 16);
+                       rtn = SUCCESS;
+               }
                /* if rtn == FAILED, we have no sense information;
                 * returning FAILED will wake the error handler thread
                 * to collect the sense and redo the decide
@@ -1486,6 +1499,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
        case RESERVATION_CONFLICT:
                sdev_printk(KERN_INFO, scmd->device,
                            "reservation conflict\n");
+               scmd->result |= (DID_NEXUS_FAILURE << 16);
                return SUCCESS; /* causes immediate i/o error */
        default:
                return FAILED;
@@ -1972,7 +1986,7 @@ int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
                if (sb_len > 7)
                        sshdr->additional_length = sense_buffer[7];
        } else {
-               /* 
+               /*
                 * fixed format
                 */
                if (sb_len > 2)