diff options
author | Michael Reed <mdr@sgi.com> | 2006-05-24 16:07:40 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-06-10 17:00:03 -0400 |
commit | 419835e285c3e39cd62c8c8426da0aebea9cd89f (patch) | |
tree | e550176245f09598ccf7ffff915524ff07d75c88 | |
parent | ca2f938efe71ca48cbc689db4df8d4f04b5d8f07 (diff) |
[SCSI] mptfc: fix fibre channel infinite request/response loop
While doing board reset testing I was able to put the system in
an infinite request/response loop between the scsi layer and
mptscsih_qcmd() by aborting the reset. This patch installs
a "SETUP RESET" handler which calls fc_remote_port_delete()
for all registered rports. This blocks the target which
prevents the loop. Additionally, should the reset fail to
complete, the transport will now terminate i/o to the target.
Signed-off-by: Michael Reed <mdr@sgi.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/message/fusion/mptbase.h | 1 | ||||
-rw-r--r-- | drivers/message/fusion/mptfc.c | 36 |
2 files changed, 35 insertions, 2 deletions
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 29f6b986946f..6d36ff5ee721 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h | |||
@@ -635,6 +635,7 @@ typedef struct _MPT_ADAPTER | |||
635 | int num_ports; | 635 | int num_ports; |
636 | struct work_struct mptscsih_persistTask; | 636 | struct work_struct mptscsih_persistTask; |
637 | 637 | ||
638 | struct work_struct fc_setup_reset_work; | ||
638 | struct list_head fc_rports; | 639 | struct list_head fc_rports; |
639 | spinlock_t fc_rescan_work_lock; | 640 | spinlock_t fc_rescan_work_lock; |
640 | int fc_rescan_work_count; | 641 | int fc_rescan_work_count; |
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 918aca0146ff..770df553047a 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c | |||
@@ -580,10 +580,10 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | |||
580 | #ifdef DMPT_DEBUG_FC | 580 | #ifdef DMPT_DEBUG_FC |
581 | if (unlikely(err)) { | 581 | if (unlikely(err)) { |
582 | dfcprintk ((MYIOC_s_INFO_FMT | 582 | dfcprintk ((MYIOC_s_INFO_FMT |
583 | "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero.\n", | 583 | "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero, (%x).\n", |
584 | ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name, | 584 | ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name, |
585 | ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no, | 585 | ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no, |
586 | SCpnt->device->id,SCpnt->device->lun)); | 586 | SCpnt->device->id,SCpnt->device->lun,err)); |
587 | } | 587 | } |
588 | #endif | 588 | #endif |
589 | return err; | 589 | return err; |
@@ -873,6 +873,31 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum) | |||
873 | } | 873 | } |
874 | 874 | ||
875 | static void | 875 | static void |
876 | mptfc_setup_reset(void *arg) | ||
877 | { | ||
878 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; | ||
879 | u64 pn; | ||
880 | struct mptfc_rport_info *ri; | ||
881 | |||
882 | /* reset about to happen, delete (block) all rports */ | ||
883 | list_for_each_entry(ri, &ioc->fc_rports, list) { | ||
884 | if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { | ||
885 | ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED; | ||
886 | fc_remote_port_delete(ri->rport); /* won't sleep */ | ||
887 | ri->rport = NULL; | ||
888 | |||
889 | pn = (u64)ri->pg0.WWPN.High << 32 | | ||
890 | (u64)ri->pg0.WWPN.Low; | ||
891 | dfcprintk ((MYIOC_s_INFO_FMT | ||
892 | "mptfc_setup_reset.%d: %llx deleted\n", | ||
893 | ioc->name, | ||
894 | ioc->sh->host_no, | ||
895 | (unsigned long long)pn)); | ||
896 | } | ||
897 | } | ||
898 | } | ||
899 | |||
900 | static void | ||
876 | mptfc_rescan_devices(void *arg) | 901 | mptfc_rescan_devices(void *arg) |
877 | { | 902 | { |
878 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; | 903 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; |
@@ -999,6 +1024,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
999 | 1024 | ||
1000 | spin_lock_init(&ioc->fc_rescan_work_lock); | 1025 | spin_lock_init(&ioc->fc_rescan_work_lock); |
1001 | INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc); | 1026 | INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc); |
1027 | INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset, (void *)ioc); | ||
1002 | 1028 | ||
1003 | spin_lock_irqsave(&ioc->FreeQlock, flags); | 1029 | spin_lock_irqsave(&ioc->FreeQlock, flags); |
1004 | 1030 | ||
@@ -1221,6 +1247,12 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) | |||
1221 | reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); | 1247 | reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); |
1222 | 1248 | ||
1223 | if (reset_phase == MPT_IOC_SETUP_RESET) { | 1249 | if (reset_phase == MPT_IOC_SETUP_RESET) { |
1250 | spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); | ||
1251 | if (ioc->fc_rescan_work_q) { | ||
1252 | queue_work(ioc->fc_rescan_work_q, | ||
1253 | &ioc->fc_setup_reset_work); | ||
1254 | } | ||
1255 | spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); | ||
1224 | } | 1256 | } |
1225 | 1257 | ||
1226 | else if (reset_phase == MPT_IOC_PRE_RESET) { | 1258 | else if (reset_phase == MPT_IOC_PRE_RESET) { |