[SCSI] mptfc: stall eh handlers if resetting while rport blocked
Thanks to James Smart for the inspiration. Stall error handler if attempting recovery while an rport is blocked. This avoids device offline scenarios due to errors in the error handler. Also verify that VirtDevice is available before issuing scsi command. VirtDevice is removed when fc transport removes a target. See James Smart's patch of 08/17/2006 for greater detail. http://marc.theaimsgroup.com/?l=linux-scsi&m=115583213624803&w=2 Also bump version number per Eric's request. Signed-off-by: Michael Reed <mdr@sgi.com> Acked-by: Eric Moore <eric.moore@lsil.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
parent
11010fecd2
commit
35508e46aa
2 changed files with 87 additions and 6 deletions
|
@ -75,8 +75,8 @@
|
||||||
#define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR
|
#define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MPT_LINUX_VERSION_COMMON "3.04.01"
|
#define MPT_LINUX_VERSION_COMMON "3.04.02"
|
||||||
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.01"
|
#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.02"
|
||||||
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
|
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
|
||||||
|
|
||||||
#define show_mptmod_ver(s,ver) \
|
#define show_mptmod_ver(s,ver) \
|
||||||
|
|
|
@ -96,6 +96,10 @@ static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
|
||||||
static void mptfc_target_destroy(struct scsi_target *starget);
|
static void mptfc_target_destroy(struct scsi_target *starget);
|
||||||
static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
|
static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
|
||||||
static void __devexit mptfc_remove(struct pci_dev *pdev);
|
static void __devexit mptfc_remove(struct pci_dev *pdev);
|
||||||
|
static int mptfc_abort(struct scsi_cmnd *SCpnt);
|
||||||
|
static int mptfc_dev_reset(struct scsi_cmnd *SCpnt);
|
||||||
|
static int mptfc_bus_reset(struct scsi_cmnd *SCpnt);
|
||||||
|
static int mptfc_host_reset(struct scsi_cmnd *SCpnt);
|
||||||
|
|
||||||
static struct scsi_host_template mptfc_driver_template = {
|
static struct scsi_host_template mptfc_driver_template = {
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
|
@ -110,10 +114,10 @@ static struct scsi_host_template mptfc_driver_template = {
|
||||||
.target_destroy = mptfc_target_destroy,
|
.target_destroy = mptfc_target_destroy,
|
||||||
.slave_destroy = mptscsih_slave_destroy,
|
.slave_destroy = mptscsih_slave_destroy,
|
||||||
.change_queue_depth = mptscsih_change_queue_depth,
|
.change_queue_depth = mptscsih_change_queue_depth,
|
||||||
.eh_abort_handler = mptscsih_abort,
|
.eh_abort_handler = mptfc_abort,
|
||||||
.eh_device_reset_handler = mptscsih_dev_reset,
|
.eh_device_reset_handler = mptfc_dev_reset,
|
||||||
.eh_bus_reset_handler = mptscsih_bus_reset,
|
.eh_bus_reset_handler = mptfc_bus_reset,
|
||||||
.eh_host_reset_handler = mptscsih_host_reset,
|
.eh_host_reset_handler = mptfc_host_reset,
|
||||||
.bios_param = mptscsih_bios_param,
|
.bios_param = mptscsih_bios_param,
|
||||||
.can_queue = MPT_FC_CAN_QUEUE,
|
.can_queue = MPT_FC_CAN_QUEUE,
|
||||||
.this_id = -1,
|
.this_id = -1,
|
||||||
|
@ -171,6 +175,77 @@ static struct fc_function_template mptfc_transport_functions = {
|
||||||
.show_host_symbolic_name = 1,
|
.show_host_symbolic_name = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
|
||||||
|
int (*func)(struct scsi_cmnd *SCpnt),
|
||||||
|
const char *caller)
|
||||||
|
{
|
||||||
|
struct scsi_device *sdev = SCpnt->device;
|
||||||
|
struct Scsi_Host *shost = sdev->host;
|
||||||
|
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
|
||||||
|
unsigned long flags;
|
||||||
|
int ready;
|
||||||
|
|
||||||
|
spin_lock_irqsave(shost->host_lock, flags);
|
||||||
|
while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
|
||||||
|
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||||
|
dfcprintk ((MYIOC_s_INFO_FMT
|
||||||
|
"mptfc_block_error_handler.%d: %d:%d, port status is "
|
||||||
|
"DID_IMM_RETRY, deferring %s recovery.\n",
|
||||||
|
((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
|
||||||
|
((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
|
||||||
|
SCpnt->device->id,SCpnt->device->lun,caller));
|
||||||
|
msleep(1000);
|
||||||
|
spin_lock_irqsave(shost->host_lock, flags);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||||
|
|
||||||
|
if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
|
||||||
|
dfcprintk ((MYIOC_s_INFO_FMT
|
||||||
|
"%s.%d: %d:%d, failing recovery, "
|
||||||
|
"port state %d, vdev %p.\n", caller,
|
||||||
|
((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
|
||||||
|
((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
|
||||||
|
SCpnt->device->id,SCpnt->device->lun,ready,
|
||||||
|
SCpnt->device->hostdata));
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
dfcprintk ((MYIOC_s_INFO_FMT
|
||||||
|
"%s.%d: %d:%d, executing recovery.\n", caller,
|
||||||
|
((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
|
||||||
|
((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
|
||||||
|
SCpnt->device->id,SCpnt->device->lun));
|
||||||
|
return (*func)(SCpnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mptfc_abort(struct scsi_cmnd *SCpnt)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
mptfc_block_error_handler(SCpnt, mptscsih_abort, __FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mptfc_dev_reset(struct scsi_cmnd *SCpnt)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
mptfc_block_error_handler(SCpnt, mptscsih_dev_reset, __FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mptfc_bus_reset(struct scsi_cmnd *SCpnt)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
mptfc_block_error_handler(SCpnt, mptscsih_bus_reset, __FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mptfc_host_reset(struct scsi_cmnd *SCpnt)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
mptfc_block_error_handler(SCpnt, mptscsih_host_reset, __FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
|
mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
|
||||||
{
|
{
|
||||||
|
@ -562,6 +637,12 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!SCpnt->device->hostdata) { /* vdev */
|
||||||
|
SCpnt->result = DID_NO_CONNECT << 16;
|
||||||
|
done(SCpnt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* dd_data is null until finished adding target */
|
/* dd_data is null until finished adding target */
|
||||||
ri = *((struct mptfc_rport_info **)rport->dd_data);
|
ri = *((struct mptfc_rport_info **)rport->dd_data);
|
||||||
if (unlikely(!ri)) {
|
if (unlikely(!ri)) {
|
||||||
|
|
Reference in a new issue