]> git.karo-electronics.de Git - linux-beck.git/commitdiff
[SCSI] mpt2sas: Hold Controller reset when another reset is in progress
authorKashyap, Desai <kashyap.desai@lsi.com>
Thu, 17 Jun 2010 07:58:55 +0000 (13:28 +0530)
committerJames Bottomley <James.Bottomley@suse.de>
Tue, 27 Jul 2010 17:02:06 +0000 (12:02 -0500)
Driver should not allow multiple host reset when already host reset is in
progress. It is possible that host reset was sent by scsi mid layer while there was already an host reset active,
either issued via IOCTL interface or internaly, like a config page timeout.
Since there was a host reset active, the driver would return a FAILED response
to the scsi mid layer. The solution is make sure pending host resets will
wait for the active host reset to complete before returning control
back up the call stack.

Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/mpt2sas/mpt2sas_base.c
drivers/scsi/mpt2sas/mpt2sas_base.h
drivers/scsi/mpt2sas/mpt2sas_scsih.c

index 0ec1ed389c209b1e8273b0f4b6cdf97fc599a144..f0c0df4278d7cf921e620c01d7c4bd19be420f6e 100644 (file)
@@ -3804,7 +3804,7 @@ _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
                return;
 
        /* wait for pending commands to complete */
-       wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 3 * HZ);
+       wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ);
 }
 
 /**
@@ -3828,13 +3828,24 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
        if (mpt2sas_fwfault_debug)
                mpt2sas_halt_firmware(ioc);
 
-       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
-       if (ioc->shost_recovery) {
-               spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
-               printk(MPT2SAS_ERR_FMT "%s: busy\n",
-                   ioc->name, __func__);
-               return -EBUSY;
+       /* TODO - What we really should be doing is pulling
+        * out all the code associated with NO_SLEEP; its never used.
+        * That is legacy code from mpt fusion driver, ported over.
+        * I will leave this BUG_ON here for now till its been resolved.
+        */
+       BUG_ON(sleep_flag == NO_SLEEP);
+
+       /* wait for an active reset in progress to complete */
+       if (!mutex_trylock(&ioc->reset_in_progress_mutex)) {
+               do {
+                       ssleep(1);
+               } while (ioc->shost_recovery == 1);
+               dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: exit\n", ioc->name,
+                   __func__));
+               return ioc->ioc_reset_in_progress_status;
        }
+
+       spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
        ioc->shost_recovery = 1;
        spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
 
@@ -3853,9 +3864,13 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
            ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED")));
 
        spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
+       ioc->ioc_reset_in_progress_status = r;
        ioc->shost_recovery = 0;
        complete(&ioc->shost_recovery_done);
        spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+       mutex_unlock(&ioc->reset_in_progress_mutex);
 
+       dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: exit\n", ioc->name,
+           __func__));
        return r;
 }
index 0f41fcd4e52be8e4c58a45843148ecae739abad6..6032cbf31c7ec6bc4153d7a4e3aac5d8d851387c 100644 (file)
@@ -600,9 +600,13 @@ struct MPT2SAS_ADAPTER {
        int             aen_event_read_flag;
        u8              broadcast_aen_busy;
        u8              shost_recovery;
+
+       struct mutex    reset_in_progress_mutex;
        struct completion       shost_recovery_done;
        spinlock_t      ioc_reset_in_progress_lock;
        u8              ioc_link_reset_in_progress;
+       int             ioc_reset_in_progress_status;
+
        u8              ignore_loginfos;
        u8              remove_host;
        u8              wait_for_port_enable_to_complete;
index 456ea7c3b09962065a3debef35d1109b6c4d9ee1..9ce2253039387ac2a2e548dc3b7ac8cef2ad5288 100644 (file)
@@ -6557,6 +6557,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
        ioc->logging_level = logging_level;
        /* misc semaphores and spin locks */
+       mutex_init(&ioc->reset_in_progress_mutex);
        spin_lock_init(&ioc->ioc_reset_in_progress_lock);
        spin_lock_init(&ioc->scsi_lookup_lock);
        spin_lock_init(&ioc->sas_device_lock);