Commit a90f5684 authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.1.9 : Stall eh handlers if resetting while rport blocked

Stall error handler if attempting resets/aborts while an rport is blocked.
This avoids device offline scenarios due to errors in the error handler.

Background:
  Although the transport is using the scsi_timed_out functionality to
  restart the timeout if the rport is blocked, if the timeout has already
  fired before the block occurs, the eh handler still runs and can take
  the device offline. Ultimately, this window cannot be resolved without
  significant work in the error handler thread. Christoph noted the first
  level of these issues when he noted the poor error response handling
  by the error thread.

  We found, under heavy load and error testing, that time window from when
  the scsi_times_out() adds the io to the queue to when the scsi_error_handler
  gets around to servicing it, can be in the several seconds range. In most
  cases, these test conditions are highly unusual, but possible.
  As a result, we're stalling the error handler in this race window so that
  we can avoid the device_offline transitions.
Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 33ccf8d1
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h>
#include <scsi/scsi.h> #include <scsi/scsi.h>
#include <scsi/scsi_device.h> #include <scsi/scsi_device.h>
...@@ -841,6 +842,21 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) ...@@ -841,6 +842,21 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
return 0; return 0;
} }
static void
lpfc_block_error_handler(struct scsi_cmnd *cmnd)
{
struct Scsi_Host *shost = cmnd->device->host;
struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
spin_lock_irq(shost->host_lock);
while (rport->port_state == FC_PORTSTATE_BLOCKED) {
spin_unlock_irq(shost->host_lock);
msleep(1000);
spin_lock_irq(shost->host_lock);
}
spin_unlock_irq(shost->host_lock);
return;
}
static int static int
lpfc_abort_handler(struct scsi_cmnd *cmnd) lpfc_abort_handler(struct scsi_cmnd *cmnd)
...@@ -855,6 +871,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) ...@@ -855,6 +871,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
unsigned int loop_count = 0; unsigned int loop_count = 0;
int ret = SUCCESS; int ret = SUCCESS;
lpfc_block_error_handler(cmnd);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
...@@ -957,6 +974,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) ...@@ -957,6 +974,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
int ret = FAILED; int ret = FAILED;
int cnt, loopcnt; int cnt, loopcnt;
lpfc_block_error_handler(cmnd);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
/* /*
* If target is not in a MAPPED state, delay the reset until * If target is not in a MAPPED state, delay the reset until
...@@ -1073,6 +1091,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) ...@@ -1073,6 +1091,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
int cnt, loopcnt; int cnt, loopcnt;
struct lpfc_scsi_buf * lpfc_cmd; struct lpfc_scsi_buf * lpfc_cmd;
lpfc_block_error_handler(cmnd);
spin_lock_irq(shost->host_lock); spin_lock_irq(shost->host_lock);
lpfc_cmd = lpfc_get_scsi_buf(phba); lpfc_cmd = lpfc_get_scsi_buf(phba);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment