]> err.no Git - linux-2.6/commitdiff
[SCSI] mptfc: fix fibre channel infinite request/response loop
authorMichael Reed <mdr@sgi.com>
Wed, 24 May 2006 20:07:40 +0000 (15:07 -0500)
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>
Sat, 10 Jun 2006 21:00:03 +0000 (16:00 -0500)
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>
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptfc.c

index 29f6b986946fef4faf5308afc18df981df7770fc..6d36ff5ee7218da4db7ef008e8a54b49079e9dfe 100644 (file)
@@ -635,6 +635,7 @@ typedef struct _MPT_ADAPTER
        int                      num_ports;
        struct work_struct       mptscsih_persistTask;
 
+       struct work_struct       fc_setup_reset_work;
        struct list_head         fc_rports;
        spinlock_t               fc_rescan_work_lock;
        int                      fc_rescan_work_count;
index 918aca0146ff8db6e77de396a7355f1f3c9e80fc..770df553047a02653c17398e62c30cfa45c1e3cf 100644 (file)
@@ -580,10 +580,10 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
 #ifdef DMPT_DEBUG_FC
        if (unlikely(err)) {
                dfcprintk ((MYIOC_s_INFO_FMT
-                       "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero.\n",
+                       "mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero, (%x).\n",
                        ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
                        ((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
-                       SCpnt->device->id,SCpnt->device->lun));
+                       SCpnt->device->id,SCpnt->device->lun,err));
        }
 #endif
        return err;
@@ -872,6 +872,31 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
        fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
 }
 
+static void
+mptfc_setup_reset(void *arg)
+{
+       MPT_ADAPTER             *ioc = (MPT_ADAPTER *)arg;
+       u64                     pn;
+       struct mptfc_rport_info *ri;
+
+       /* reset about to happen, delete (block) all rports */
+       list_for_each_entry(ri, &ioc->fc_rports, list) {
+               if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
+                       ri->flags &= ~MPT_RPORT_INFO_FLAGS_REGISTERED;
+                       fc_remote_port_delete(ri->rport);       /* won't sleep */
+                       ri->rport = NULL;
+
+                       pn = (u64)ri->pg0.WWPN.High << 32 |
+                            (u64)ri->pg0.WWPN.Low;
+                       dfcprintk ((MYIOC_s_INFO_FMT
+                               "mptfc_setup_reset.%d: %llx deleted\n",
+                               ioc->name,
+                               ioc->sh->host_no,
+                               (unsigned long long)pn));
+               }
+       }
+}
+
 static void
 mptfc_rescan_devices(void *arg)
 {
@@ -999,6 +1024,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        spin_lock_init(&ioc->fc_rescan_work_lock);
        INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc);
+       INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset, (void *)ioc);
 
        spin_lock_irqsave(&ioc->FreeQlock, flags);
 
@@ -1221,6 +1247,12 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
                reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
        if (reset_phase == MPT_IOC_SETUP_RESET) {
+               spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+               if (ioc->fc_rescan_work_q) {
+                       queue_work(ioc->fc_rescan_work_q,
+                                  &ioc->fc_setup_reset_work);
+               }
+               spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
        }
 
        else if (reset_phase == MPT_IOC_PRE_RESET) {