aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/message
diff options
context:
space:
mode:
authorMichael Reed <mdr@sgi.com>2006-05-24 16:07:40 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-06-10 17:00:03 -0400
commit419835e285c3e39cd62c8c8426da0aebea9cd89f (patch)
treee550176245f09598ccf7ffff915524ff07d75c88 /drivers/message
parentca2f938efe71ca48cbc689db4df8d4f04b5d8f07 (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>
Diffstat (limited to 'drivers/message')
-rw-r--r--drivers/message/fusion/mptbase.h1
-rw-r--r--drivers/message/fusion/mptfc.c36
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
875static void 875static void
876mptfc_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
900static void
876mptfc_rescan_devices(void *arg) 901mptfc_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) {