[SCSI] mpt2sas: Improvement were made to better protect the sas_device, raid_device...
authornagalakshmi.nandigama@lsi.com <nagalakshmi.nandigama@lsi.com>
Tue, 20 Mar 2012 06:36:50 +0000 (12:06 +0530)
committerJames Bottomley <JBottomley@Parallels.com>
Mon, 23 Apr 2012 18:27:15 +0000 (19:27 +0100)
There were possible race conditions surrounding reading an object
from the link list while from another context in the driver was
removing it. The nature of this enhancement is to rearrange locking
so the link lists are better protected.

Change set:
(1) numerous routines were rearranged so spin locks are held through
the entire time a link list object is being read from or written to.
(2) added new routines for object deletion from link list.  Thus ensuring
lock was held during the deletion of the link list object, then and memory
for object freed outside the lock. The memory was freed outside the lock
so driver had access to device object info which was required for
notifying the scsi mid layer that a device was getting deleted.
(3) added the ioc->blocking_handles parameter.  This is a bitmask used
to identify which devices need blocking when there is device loss.  This was
introduced so that lock can be held for the entire time traversing the link
list objects, and the bitmask was set to indicate which device handles need
blocking. Oustide the lock the ioc->blocking_handles bitmask is traversed,
with the respective device handle the scsi mid layer is called for moving
devices into blocking state.

Signed-off-by: Nagalakshmi Nandigama <nagalakshmi.nandigama@lsi.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/mpt2sas/mpt2sas_base.c
drivers/scsi/mpt2sas/mpt2sas_base.h
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/mpt2sas/mpt2sas_transport.c

index 8a59a772fdf22841ead34c937dd92e4ccb20f749..30d540a05ad834ae5abeff6e236d0cfb5c1678b1 100644 (file)
@@ -4279,7 +4279,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
                goto out_free_resources;
 
        init_waitqueue_head(&ioc->reset_wq);
-
        /* allocate memory pd handle bitmask list */
        ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8);
        if (ioc->facts.MaxDevHandle % 8)
@@ -4290,7 +4289,12 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
                r = -ENOMEM;
                goto out_free_resources;
        }
-
+       ioc->blocking_handles = kzalloc(ioc->pd_handles_sz,
+           GFP_KERNEL);
+       if (!ioc->blocking_handles) {
+               r = -ENOMEM;
+               goto out_free_resources;
+       }
        ioc->fwfault_debug = mpt2sas_fwfault_debug;
 
        /* base internal command bits */
@@ -4377,6 +4381,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
        if (ioc->is_warpdrive)
                kfree(ioc->reply_post_host_index);
        kfree(ioc->pd_handles);
+       kfree(ioc->blocking_handles);
        kfree(ioc->tm_cmds.reply);
        kfree(ioc->transport_cmds.reply);
        kfree(ioc->scsih_cmds.reply);
@@ -4418,6 +4423,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
        if (ioc->is_warpdrive)
                kfree(ioc->reply_post_host_index);
        kfree(ioc->pd_handles);
+       kfree(ioc->blocking_handles);
        kfree(ioc->pfacts);
        kfree(ioc->ctl_cmds.reply);
        kfree(ioc->ctl_cmds.sense);
index c7459fdc06cc746895c83f7eb865ec3cf49d76ce..5a0dc30ed41dfc6186a833e57321188496ac5d5f 100644 (file)
@@ -720,6 +720,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
  * @io_missing_delay: time for IO completed by fw when PDR enabled
  * @device_missing_delay: time for device missing by fw when PDR enabled
  * @sas_id : used for setting volume target IDs
+ * @blocking_handles: bitmask used to identify which devices need blocking
  * @pd_handles : bitmask for PD handles
  * @pd_handles_sz : size of pd_handle bitmask
  * @config_page_sz: config page size
@@ -889,7 +890,7 @@ struct MPT2SAS_ADAPTER {
        u8              io_missing_delay;
        u16             device_missing_delay;
        int             sas_id;
-
+       void            *blocking_handles;
        void            *pd_handles;
        u16             pd_handles_sz;
 
@@ -1058,7 +1059,8 @@ int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
 void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
 void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
 void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-void mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
+void mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+               u64 sas_address);
 struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
     u16 handle);
 struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
index d953a57e779dd83d60ae0a61d8b6d76f766101d2..9a739e6f2712cc478d336df743d41ef450b01958 100644 (file)
@@ -579,14 +579,12 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
                return;
 
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
-       if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
-           sas_device->sas_address)) {
-               list_del(&sas_device->list);
-               kfree(sas_device);
-       }
+       list_del(&sas_device->list);
+       kfree(sas_device);
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 }
 
+
 /**
  * _scsih_sas_device_add - insert sas_device to the list.
  * @ioc: per adapter object
@@ -645,8 +643,8 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
 
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
        list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
-       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
        _scsih_determine_boot_device(ioc, sas_device, 0);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 }
 
 /**
@@ -755,7 +753,6 @@ _scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
  * @ioc: per adapter object
  * @raid_device: raid_device object
  *
- * This is removed from the raid_device_list link list.
  */
 static void
 _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
@@ -765,7 +762,6 @@ _scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
 
        spin_lock_irqsave(&ioc->raid_device_lock, flags);
        list_del(&raid_device->list);
-       memset(raid_device, 0, sizeof(struct _raid_device));
        kfree(raid_device);
        spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
 }
@@ -1199,10 +1195,10 @@ _scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
        sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
           sas_device_priv_data->sas_target->sas_address);
-       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
        if (sas_device && sas_device->device_info &
            MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
                max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
  not_sata:
 
@@ -1299,7 +1295,8 @@ _scsih_target_alloc(struct scsi_target *starget)
                        sas_target_priv_data->handle = raid_device->handle;
                        sas_target_priv_data->sas_address = raid_device->wwid;
                        sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
-                       sas_target_priv_data->raid_device = raid_device;
+                       if (ioc->is_warpdrive)
+                               sas_target_priv_data->raid_device = raid_device;
                        raid_device->starget = starget;
                }
                spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
@@ -1465,12 +1462,12 @@ _scsih_slave_destroy(struct scsi_device *sdev)
 /**
  * _scsih_display_sata_capabilities - sata capabilities
  * @ioc: per adapter object
- * @sas_device: the sas_device object
+ * @handle: device handle
  * @sdev: scsi device struct
  */
 static void
 _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
-    struct _sas_device *sas_device, struct scsi_device *sdev)
+       u16 handle, struct scsi_device *sdev)
 {
        Mpi2ConfigReply_t mpi_reply;
        Mpi2SasDevicePage0_t sas_device_pg0;
@@ -1479,7 +1476,7 @@ _scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
        u32 device_info;
 
        if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
-           MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) {
+           MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
                printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
                    ioc->name, __FILE__, __LINE__, __func__);
                return;
@@ -1537,27 +1534,40 @@ _scsih_get_resync(struct device *dev)
        Mpi2RaidVolPage0_t vol_pg0;
        Mpi2ConfigReply_t mpi_reply;
        u32 volume_status_flags;
-       u8 percent_complete = 0;
+       u8 percent_complete;
+       u16 handle;
+
+       percent_complete = 0;
+       handle = 0;
+       if (ioc->is_warpdrive)
+               goto out;
 
        spin_lock_irqsave(&ioc->raid_device_lock, flags);
        raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
            sdev->channel);
+       if (raid_device) {
+               handle = raid_device->handle;
+               percent_complete = raid_device->percent_complete;
+       }
        spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
 
-       if (!raid_device || ioc->is_warpdrive)
+       if (!handle)
                goto out;
 
        if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
-            MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
+            MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
             sizeof(Mpi2RaidVolPage0_t))) {
                printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
                    ioc->name, __FILE__, __LINE__, __func__);
+               percent_complete = 0;
                goto out;
        }
 
        volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
-       if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)
-               percent_complete = raid_device->percent_complete;
+       if (!(volume_status_flags &
+           MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS))
+               percent_complete = 0;
+
  out:
        raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
 }
@@ -1577,17 +1587,20 @@ _scsih_get_state(struct device *dev)
        Mpi2ConfigReply_t mpi_reply;
        u32 volstate;
        enum raid_state state = RAID_STATE_UNKNOWN;
+       u16 handle = 0;
 
        spin_lock_irqsave(&ioc->raid_device_lock, flags);
        raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
            sdev->channel);
+       if (raid_device)
+               handle = raid_device->handle;
        spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
 
        if (!raid_device)
                goto out;
 
        if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
-            MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle,
+            MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
             sizeof(Mpi2RaidVolPage0_t))) {
                printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
                    ioc->name, __FILE__, __LINE__, __func__);
@@ -1620,14 +1633,14 @@ _scsih_get_state(struct device *dev)
 /**
  * _scsih_set_level - set raid level
  * @sdev: scsi device struct
- * @raid_device: raid_device object
+ * @volume_type: volume type
  */
 static void
-_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device)
+_scsih_set_level(struct scsi_device *sdev, u8 volume_type)
 {
        enum raid_level level = RAID_LEVEL_UNKNOWN;
 
-       switch (raid_device->volume_type) {
+       switch (volume_type) {
        case MPI2_RAID_VOL_TYPE_RAID0:
                level = RAID_LEVEL_0;
                break;
@@ -1722,6 +1735,7 @@ _scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
        struct _raid_device *raid_device;
        u16 handle;
        u16 ioc_status;
+       unsigned long flags;
 
        handle = 0xFFFF;
        while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
@@ -1731,9 +1745,11 @@ _scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
                if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
                        break;
                handle = le16_to_cpu(vol_pg1.DevHandle);
+               spin_lock_irqsave(&ioc->raid_device_lock, flags);
                raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
                if (raid_device)
                        raid_device->direct_io_enabled = 0;
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
        }
        return;
 }
@@ -1968,19 +1984,21 @@ _scsih_slave_configure(struct scsi_device *sdev)
        u8 ssp_target = 0;
        char *ds = "";
        char *r_level = "";
+       u16 handle, volume_handle = 0;
+       u64 volume_wwid = 0;
 
        qdepth = 1;
        sas_device_priv_data = sdev->hostdata;
        sas_device_priv_data->configured_lun = 1;
        sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
        sas_target_priv_data = sas_device_priv_data->sas_target;
+       handle = sas_target_priv_data->handle;
 
        /* raid volume handling */
        if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
 
                spin_lock_irqsave(&ioc->raid_device_lock, flags);
-               raid_device = _scsih_raid_device_find_by_handle(ioc,
-                    sas_target_priv_data->handle);
+               raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
                spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
                if (!raid_device) {
                        dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
@@ -1989,8 +2007,6 @@ _scsih_slave_configure(struct scsi_device *sdev)
                        return 1;
                }
 
-               _scsih_get_volume_capabilities(ioc, raid_device);
-
                if (_scsih_get_volume_capabilities(ioc, raid_device)) {
                        dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
                            "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
@@ -2058,68 +2074,67 @@ _scsih_slave_configure(struct scsi_device *sdev)
                _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
                /* raid transport support */
                if (!ioc->is_warpdrive)
-                       _scsih_set_level(sdev, raid_device);
+                       _scsih_set_level(sdev, raid_device->volume_type);
                return 0;
        }
 
        /* non-raid handling */
-       spin_lock_irqsave(&ioc->sas_device_lock, flags);
-       sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
-          sas_device_priv_data->sas_target->sas_address);
-       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-       if (sas_device) {
-               if (sas_target_priv_data->flags &
-                   MPT_TARGET_FLAGS_RAID_COMPONENT) {
-                       if (mpt2sas_config_get_volume_handle(ioc,
-                           sas_device->handle, &sas_device->volume_handle)) {
-                               dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
-                                   "failure at %s:%d/%s()!\n", ioc->name,
-                                   __FILE__, __LINE__, __func__));
-                               return 1;
-                       }
-                       if (sas_device->volume_handle &&
-                           mpt2sas_config_get_volume_wwid(ioc,
-                           sas_device->volume_handle,
-                           &sas_device->volume_wwid)) {
-                               dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
-                                   "failure at %s:%d/%s()!\n", ioc->name,
-                                   __FILE__, __LINE__, __func__));
-                               return 1;
-                       }
+       if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
+               if (mpt2sas_config_get_volume_handle(ioc, handle,
+                   &volume_handle)) {
+                       dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
+                           "failure at %s:%d/%s()!\n", ioc->name,
+                           __FILE__, __LINE__, __func__));
+                       return 1;
                }
-               if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
-                       qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
-                       ssp_target = 1;
-                       ds = "SSP";
-               } else {
-                       qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
-                       if (sas_device->device_info &
-                           MPI2_SAS_DEVICE_INFO_STP_TARGET)
-                               ds = "STP";
-                       else if (sas_device->device_info &
-                           MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
-                               ds = "SATA";
+               if (volume_handle && mpt2sas_config_get_volume_wwid(ioc,
+                   volume_handle, &volume_wwid)) {
+                       dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
+                           "failure at %s:%d/%s()!\n", ioc->name,
+                           __FILE__, __LINE__, __func__));
+                       return 1;
                }
+       }
 
-               sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
-                   "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
-                   ds, sas_device->handle,
-                   (unsigned long long)sas_device->sas_address,
-                   sas_device->phy,
-                   (unsigned long long)sas_device->device_name);
-               sdev_printk(KERN_INFO, sdev, "%s: "
-                   "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
-                   (unsigned long long) sas_device->enclosure_logical_id,
-                   sas_device->slot);
-
-               if (!ssp_target)
-                       _scsih_display_sata_capabilities(ioc, sas_device, sdev);
-       } else {
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+          sas_device_priv_data->sas_target->sas_address);
+       if (!sas_device) {
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
                dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
-                   "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
-                   __func__));
+                       "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
+                       __LINE__, __func__));
                return 1;
        }
+       sas_device->volume_handle = volume_handle;
+       sas_device->volume_wwid = volume_wwid;
+       if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
+               qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
+               ssp_target = 1;
+               ds = "SSP";
+       } else {
+               qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
+               if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
+                       ds = "STP";
+               else if (sas_device->device_info &
+                   MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
+                       ds = "SATA";
+       }
+       sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
+           "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
+           ds, sas_device->handle,
+           (unsigned long long)sas_device->sas_address,
+           sas_device->phy,
+           (unsigned long long)sas_device->device_name);
+       sdev_printk(KERN_INFO, sdev, "%s: "
+           "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
+           (unsigned long long) sas_device->enclosure_logical_id,
+           sas_device->slot);
+
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       if (!ssp_target)
+               _scsih_display_sata_capabilities(ioc, handle, sdev);
+
 
        _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
 
@@ -3006,10 +3021,10 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
                        sas_device =
                            mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
                           mpt2sas_port->remote_identify.sas_address);
+                       if (sas_device)
+                               set_bit(sas_device->handle,
+                                   ioc->blocking_handles);
                        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-                       if (!sas_device)
-                               continue;
-                       _scsih_block_io_device(ioc, sas_device->handle);
                }
        }
 
@@ -3020,12 +3035,9 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
                    SAS_EDGE_EXPANDER_DEVICE ||
                    mpt2sas_port->remote_identify.device_type ==
                    SAS_FANOUT_EXPANDER_DEVICE) {
-
-                       spin_lock_irqsave(&ioc->sas_node_lock, flags);
                        expander_sibling =
                            mpt2sas_scsih_expander_find_by_sas_address(
                            ioc, mpt2sas_port->remote_identify.sas_address);
-                       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
                        _scsih_block_io_to_children_attached_to_ex(ioc,
                            expander_sibling);
                }
@@ -3441,14 +3453,20 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
                _scsih_block_io_to_children_attached_directly(ioc, event_data);
                return;
        }
-
-       if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING
-        || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) {
+       if (event_data->ExpStatus ==
+           MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) {
+               /* put expander attached devices into blocking state */
                spin_lock_irqsave(&ioc->sas_node_lock, flags);
                sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
                    expander_handle);
-               spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
                _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
+               spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+               do {
+                       handle = find_first_bit(ioc->blocking_handles,
+                           ioc->facts.MaxDevHandle);
+                       if (handle < ioc->facts.MaxDevHandle)
+                               _scsih_block_io_device(ioc, handle);
+               } while (test_and_clear_bit(handle, ioc->blocking_handles));
        } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
                _scsih_block_io_to_children_attached_directly(ioc, event_data);
 
@@ -4446,8 +4464,8 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
            != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
                spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
                ioc->scsi_lookup[smid - 1].scmd = scmd;
-               spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
                _scsih_scsi_direct_io_set(ioc, smid, 0);
+               spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
                memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
                mpi_request->DevHandle =
                    cpu_to_le16(sas_device_priv_data->sas_target->handle);
@@ -5020,13 +5038,11 @@ mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
        spin_lock_irqsave(&ioc->sas_node_lock, flags);
        sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
            sas_address);
-       if (!sas_expander) {
-               spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-               return;
-       }
-       list_del(&sas_expander->list);
+       if (sas_expander)
+               list_del(&sas_expander->list);
        spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-       _scsih_expander_node_remove(ioc, sas_expander);
+       if (sas_expander)
+               _scsih_expander_node_remove(ioc, sas_expander);
 }
 
 /**
@@ -5106,6 +5122,7 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
        struct MPT2SAS_TARGET *sas_target_priv_data;
        u32 device_info;
 
+
        if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
            MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
                return;
@@ -5139,20 +5156,23 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
                sas_target_priv_data->handle = handle;
                sas_device->handle = handle;
        }
-       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
        /* check if device is present */
        if (!(le16_to_cpu(sas_device_pg0.Flags) &
            MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
                printk(MPT2SAS_ERR_FMT "device is not present "
                    "handle(0x%04x), flags!!!\n", ioc->name, handle);
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
                return;
        }
 
        /* check if there were any issues with discovery */
        if (_scsih_check_access_status(ioc, sas_address, handle,
-           sas_device_pg0.AccessStatus))
+           sas_device_pg0.AccessStatus)) {
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
                return;
+       }
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
        _scsih_ublock_io_device(ioc, handle);
 
 }
@@ -5280,54 +5300,71 @@ static void
 _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
     struct _sas_device *sas_device)
 {
-       struct _sas_device sas_device_backup;
        struct MPT2SAS_TARGET *sas_target_priv_data;
 
-       if (!sas_device)
-               return;
-
-       memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device));
-       _scsih_sas_device_remove(ioc, sas_device);
-
        dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
            "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
-           sas_device_backup.handle, (unsigned long long)
-           sas_device_backup.sas_address));
+               sas_device->handle, (unsigned long long)
+           sas_device->sas_address));
 
-       if (sas_device_backup.starget && sas_device_backup.starget->hostdata) {
-               sas_target_priv_data = sas_device_backup.starget->hostdata;
+       if (sas_device->starget && sas_device->starget->hostdata) {
+               sas_target_priv_data = sas_device->starget->hostdata;
                sas_target_priv_data->deleted = 1;
-               _scsih_ublock_io_device(ioc, sas_device_backup.handle);
+               _scsih_ublock_io_device(ioc, sas_device->handle);
                sas_target_priv_data->handle =
                     MPT2SAS_INVALID_DEVICE_HANDLE;
        }
 
-       _scsih_ublock_io_device(ioc, sas_device_backup.handle);
-
        if (!ioc->hide_drives)
                mpt2sas_transport_port_remove(ioc,
-                   sas_device_backup.sas_address,
-                   sas_device_backup.sas_address_parent);
+                   sas_device->sas_address,
+                   sas_device->sas_address_parent);
 
        printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
-           "(0x%016llx)\n", ioc->name, sas_device_backup.handle,
-           (unsigned long long) sas_device_backup.sas_address);
+           "(0x%016llx)\n", ioc->name, sas_device->handle,
+           (unsigned long long) sas_device->sas_address);
 
        dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
            "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
-           sas_device_backup.handle, (unsigned long long)
-           sas_device_backup.sas_address));
+           sas_device->handle, (unsigned long long)
+           sas_device->sas_address));
+       kfree(sas_device);
+}
+/**
+ * _scsih_device_remove_by_handle - removing device object by handle
+ * @ioc: per adapter object
+ * @handle: device handle
+ *
+ * Return nothing.
+ */
+static void
+_scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+       struct _sas_device *sas_device;
+       unsigned long flags;
+
+       if (ioc->shost_recovery)
+               return;
+
+       spin_lock_irqsave(&ioc->sas_device_lock, flags);
+       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       if (sas_device)
+               list_del(&sas_device->list);
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+       if (sas_device)
+               _scsih_remove_device(ioc, sas_device);
 }
 
 /**
- * mpt2sas_device_remove - removing device object
+ * mpt2sas_device_remove_by_sas_address - removing device object by sas address
  * @ioc: per adapter object
- * @sas_address: expander sas_address
+ * @sas_address: device sas_address
  *
  * Return nothing.
  */
 void
-mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
+mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
+       u64 sas_address)
 {
        struct _sas_device *sas_device;
        unsigned long flags;
@@ -5338,14 +5375,12 @@ mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
        sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
            sas_address);
-       if (!sas_device) {
-               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-               return;
-       }
+       if (sas_device)
+               list_del(&sas_device->list);
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-       _scsih_remove_device(ioc, sas_device);
+       if (sas_device)
+               _scsih_remove_device(ioc, sas_device);
 }
-
 #ifdef CONFIG_SCSI_MPT2SAS_LOGGING
 /**
  * _scsih_sas_topology_change_event_debug - debug for topology event
@@ -5442,7 +5477,6 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
        u16 reason_code;
        u8 phy_number, max_phys;
        struct _sas_node *sas_expander;
-       struct _sas_device *sas_device;
        u64 sas_address;
        unsigned long flags;
        u8 link_rate, prev_link_rate;
@@ -5477,15 +5511,17 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
        spin_lock_irqsave(&ioc->sas_node_lock, flags);
        sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
            parent_handle);
-       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
        if (sas_expander) {
                sas_address = sas_expander->sas_address;
                max_phys = sas_expander->num_phys;
        } else if (parent_handle < ioc->sas_hba.num_phys) {
                sas_address = ioc->sas_hba.sas_address;
                max_phys = ioc->sas_hba.num_phys;
-       } else
+       } else {
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
                return;
+       }
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 
        /* handle siblings events */
        for (i = 0; i < event_data->NumEntries; i++) {
@@ -5540,16 +5576,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
                        break;
                case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
 
-                       spin_lock_irqsave(&ioc->sas_device_lock, flags);
-                       sas_device = _scsih_sas_device_find_by_handle(ioc,
-                           handle);
-                       if (!sas_device) {
-                               spin_unlock_irqrestore(&ioc->sas_device_lock,
-                                   flags);
-                               break;
-                       }
-                       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-                       _scsih_remove_device(ioc, sas_device);
+                       _scsih_device_remove_by_handle(ioc, handle);
                        break;
                }
        }
@@ -5672,20 +5699,24 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
        sas_address = le64_to_cpu(event_data->SASAddress);
        sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
            sas_address);
-       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
-       if (!sas_device || !sas_device->starget)
+       if (!sas_device || !sas_device->starget) {
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
                return;
+       }
 
        target_priv_data = sas_device->starget->hostdata;
-       if (!target_priv_data)
+       if (!target_priv_data) {
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
                return;
+       }
 
        if (event_data->ReasonCode ==
            MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
                target_priv_data->tm_busy = 1;
        else
                target_priv_data->tm_busy = 0;
+       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 }
 
 #ifdef CONFIG_SCSI_MPT2SAS_LOGGING
@@ -5949,30 +5980,6 @@ _scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
        rc = scsi_device_reprobe(sdev);
 }
 
-/**
- * _scsih_reprobe_target - reprobing target
- * @starget: scsi target struct
- * @no_uld_attach: sdev->no_uld_attach flag setting
- *
- * Note: no_uld_attach flag determines whether the disk device is attached
- * to block layer. A value of `1` means to not attach.
- **/
-static void
-_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
-{
-       struct MPT2SAS_TARGET *sas_target_priv_data;
-
-       if (starget == NULL)
-               return;
-       sas_target_priv_data = starget->hostdata;
-       if (no_uld_attach)
-               sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
-       else
-               sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
-
-       starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL,
-           _scsih_reprobe_lun);
-}
 /**
  * _scsih_sas_volume_add - add new volume
  * @ioc: per adapter object
@@ -6024,8 +6031,11 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
                    raid_device->id, 0);
                if (rc)
                        _scsih_raid_device_remove(ioc, raid_device);
-       } else
+       } else {
+               spin_lock_irqsave(&ioc->raid_device_lock, flags);
                _scsih_determine_boot_device(ioc, raid_device, 1);
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+       }
 }
 
 /**
@@ -6042,21 +6052,25 @@ _scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
        struct _raid_device *raid_device;
        unsigned long flags;
        struct MPT2SAS_TARGET *sas_target_priv_data;
+       struct scsi_target *starget = NULL;
 
        spin_lock_irqsave(&ioc->raid_device_lock, flags);
        raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
-       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-       if (!raid_device)
-               return;
-       if (raid_device->starget) {
-               sas_target_priv_data = raid_device->starget->hostdata;
-               sas_target_priv_data->deleted = 1;
-               scsi_remove_target(&raid_device->starget->dev);
+       if (raid_device) {
+               if (raid_device->starget) {
+                       starget = raid_device->starget;
+                       sas_target_priv_data = starget->hostdata;
+                       sas_target_priv_data->deleted = 1;
+               }
+               printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
+                   "(0x%016llx)\n", ioc->name,  raid_device->handle,
+                   (unsigned long long) raid_device->wwid);
+               list_del(&raid_device->list);
+               kfree(raid_device);
        }
-       printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
-           "(0x%016llx)\n", ioc->name,  raid_device->handle,
-           (unsigned long long) raid_device->wwid);
-       _scsih_raid_device_remove(ioc, raid_device);
+       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+       if (starget)
+               scsi_remove_target(&starget->dev);
 }
 
 /**
@@ -6072,20 +6086,31 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
     Mpi2EventIrConfigElement_t *element)
 {
        struct _sas_device *sas_device;
+       struct scsi_target *starget = NULL;
+       struct MPT2SAS_TARGET *sas_target_priv_data;
        unsigned long flags;
        u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
 
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
        sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       if (sas_device) {
+               sas_device->volume_handle = 0;
+               sas_device->volume_wwid = 0;
+               clear_bit(handle, ioc->pd_handles);
+               if (sas_device->starget && sas_device->starget->hostdata) {
+                       starget = sas_device->starget;
+                       sas_target_priv_data = starget->hostdata;
+                       sas_target_priv_data->flags &=
+                           ~MPT_TARGET_FLAGS_RAID_COMPONENT;
+               }
+       }
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
        if (!sas_device)
                return;
 
        /* exposing raid component */
-       sas_device->volume_handle = 0;
-       sas_device->volume_wwid = 0;
-       clear_bit(handle, ioc->pd_handles);
-       _scsih_reprobe_target(sas_device->starget, 0);
+       if (starget)
+               starget_for_each_device(starget, NULL, _scsih_reprobe_lun);
 }
 
 /**
@@ -6101,23 +6126,38 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
     Mpi2EventIrConfigElement_t *element)
 {
        struct _sas_device *sas_device;
+       struct scsi_target *starget = NULL;
+       struct MPT2SAS_TARGET *sas_target_priv_data;
        unsigned long flags;
        u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
+       u16 volume_handle = 0;
+       u64 volume_wwid = 0;
+
+       mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle);
+       if (volume_handle)
+               mpt2sas_config_get_volume_wwid(ioc, volume_handle,
+                   &volume_wwid);
 
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
        sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+       if (sas_device) {
+               set_bit(handle, ioc->pd_handles);
+               if (sas_device->starget && sas_device->starget->hostdata) {
+                       starget = sas_device->starget;
+                       sas_target_priv_data = starget->hostdata;
+                       sas_target_priv_data->flags |=
+                           MPT_TARGET_FLAGS_RAID_COMPONENT;
+                       sas_device->volume_handle = volume_handle;
+                       sas_device->volume_wwid = volume_wwid;
+               }
+       }
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
        if (!sas_device)
                return;
 
        /* hiding raid component */
-       mpt2sas_config_get_volume_handle(ioc, handle,
-           &sas_device->volume_handle);
-       mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
-           &sas_device->volume_wwid);
-       set_bit(handle, ioc->pd_handles);
-       _scsih_reprobe_target(sas_device->starget, 1);
-
+       if (starget)
+               starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
 }
 
 /**
@@ -6132,16 +6172,9 @@ static void
 _scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
     Mpi2EventIrConfigElement_t *element)
 {
-       struct _sas_device *sas_device;
-       unsigned long flags;
        u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
 
-       spin_lock_irqsave(&ioc->sas_device_lock, flags);
-       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
-       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-       if (!sas_device)
-               return;
-       _scsih_remove_device(ioc, sas_device);
+       _scsih_device_remove_by_handle(ioc, handle);
 }
 
 /**
@@ -6583,18 +6616,13 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
        /* code added for raid transport support */
        if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
 
-               handle = le16_to_cpu(event_data->VolDevHandle);
-
                spin_lock_irqsave(&ioc->raid_device_lock, flags);
+               handle = le16_to_cpu(event_data->VolDevHandle);
                raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
-               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
-               if (!raid_device)
-                       return;
-
-               if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC)
+               if (raid_device)
                        raid_device->percent_complete =
                            event_data->PercentComplete;
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
        }
 }
 
@@ -6761,13 +6789,18 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
                         * required data for Direct IO
                         */
                        _scsih_init_warpdrive_properties(ioc, raid_device);
-                       if (raid_device->handle == handle)
+                       spin_lock_irqsave(&ioc->raid_device_lock, flags);
+                       if (raid_device->handle == handle) {
+                               spin_unlock_irqrestore(&ioc->raid_device_lock,
+                                   flags);
                                return;
+                       }
                        printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
                            raid_device->handle);
                        raid_device->handle = handle;
                        if (sas_target_priv_data)
                                sas_target_priv_data->handle = handle;
+                       spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
                        return;
                }
        }
@@ -6939,58 +6972,56 @@ static void
 _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
 {
        struct _sas_device *sas_device, *sas_device_next;
-       struct _sas_node *sas_expander;
+       struct _sas_node *sas_expander, *sas_expander_next;
        struct _raid_device *raid_device, *raid_device_next;
+       struct list_head tmp_list;
+       unsigned long flags;
 
        printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n",
            ioc->name);
 
+       /* removing unresponding end devices */
+       printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n",
+           ioc->name);
        list_for_each_entry_safe(sas_device, sas_device_next,
            &ioc->sas_device_list, list) {
-               if (sas_device->responding) {
+               if (!sas_device->responding)
+                       _scsih_device_remove_by_handle(ioc,
+                           sas_device->handle);
+               else
                        sas_device->responding = 0;
-                       continue;
-               }
-               if (sas_device->starget)
-                       starget_printk(KERN_INFO, sas_device->starget,
-                           "removing: handle(0x%04x), sas_addr(0x%016llx), "
-                           "enclosure logical id(0x%016llx), slot(%d)\n",
-                           sas_device->handle,
-                           (unsigned long long)sas_device->sas_address,
-                           (unsigned long long)
-                           sas_device->enclosure_logical_id,
-                           sas_device->slot);
-               _scsih_remove_device(ioc, sas_device);
        }
 
-       if (!ioc->ir_firmware)
-               goto retry_expander_search;
-
-       list_for_each_entry_safe(raid_device, raid_device_next,
-           &ioc->raid_device_list, list) {
-               if (raid_device->responding) {
-                       raid_device->responding = 0;
-                       continue;
-               }
-               if (raid_device->starget) {
-                       starget_printk(KERN_INFO, raid_device->starget,
-                           "removing: handle(0x%04x), wwid(0x%016llx)\n",
-                             raid_device->handle,
-                           (unsigned long long)raid_device->wwid);
-                       scsi_remove_target(&raid_device->starget->dev);
+       /* removing unresponding volumes */
+       if (ioc->ir_firmware) {
+               printk(MPT2SAS_INFO_FMT "removing unresponding devices: "
+                   "volumes\n", ioc->name);
+               list_for_each_entry_safe(raid_device, raid_device_next,
+                   &ioc->raid_device_list, list) {
+                       if (!raid_device->responding)
+                               _scsih_sas_volume_delete(ioc,
+                                   raid_device->handle);
+                       else
+                               raid_device->responding = 0;
                }
-               _scsih_raid_device_remove(ioc, raid_device);
        }
-
- retry_expander_search:
-       sas_expander = NULL;
-       list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
-               if (sas_expander->responding) {
+       /* removing unresponding expanders */
+       printk(MPT2SAS_INFO_FMT "removing unresponding devices: expanders\n",
+           ioc->name);
+       spin_lock_irqsave(&ioc->sas_node_lock, flags);
+       INIT_LIST_HEAD(&tmp_list);
+       list_for_each_entry_safe(sas_expander, sas_expander_next,
+           &ioc->sas_expander_list, list) {
+               if (!sas_expander->responding)
+                       list_move_tail(&sas_expander->list, &tmp_list);
+               else
                        sas_expander->responding = 0;
-                       continue;
-               }
-               mpt2sas_expander_remove(ioc, sas_expander->sas_address);
-               goto retry_expander_search;
+       }
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+       list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list,
+           list) {
+               list_del(&sas_expander->list);
+               _scsih_expander_node_remove(ioc, sas_expander);
        }
        printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n",
            ioc->name);
@@ -7043,6 +7074,7 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
        struct _sas_device *sas_device;
        struct _sas_node *expander_device;
        static struct _raid_device *raid_device;
+       unsigned long flags;
 
        printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name);
 
@@ -7057,8 +7089,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
                if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
                        break;
                handle = le16_to_cpu(expander_pg0.DevHandle);
+               spin_lock_irqsave(&ioc->sas_node_lock, flags);
                expander_device = mpt2sas_scsih_expander_find_by_sas_address(
                    ioc, le64_to_cpu(expander_pg0.SASAddress));
+               spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
                if (expander_device)
                        _scsih_refresh_expander_links(ioc, expander_device,
                            handle);
@@ -7080,7 +7114,9 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
                        break;
                phys_disk_num = pd_pg0.PhysDiskNum;
                handle = le16_to_cpu(pd_pg0.DevHandle);
+               spin_lock_irqsave(&ioc->sas_device_lock, flags);
                sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
                if (sas_device)
                        continue;
                if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
@@ -7107,8 +7143,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
                if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
                        break;
                handle = le16_to_cpu(volume_pg1.DevHandle);
+               spin_lock_irqsave(&ioc->raid_device_lock, flags);
                raid_device = _scsih_raid_device_find_by_wwid(ioc,
                    le64_to_cpu(volume_pg1.WWID));
+               spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
                if (raid_device)
                        continue;
                if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
@@ -7140,8 +7178,10 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
                if (!(_scsih_is_end_device(
                    le32_to_cpu(sas_device_pg0.DeviceInfo))))
                        continue;
+               spin_lock_irqsave(&ioc->sas_device_lock, flags);
                sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
                    le64_to_cpu(sas_device_pg0.SASAddress));
+               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
                if (sas_device)
                        continue;
                parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
@@ -7235,7 +7275,7 @@ _firmware_event_work(struct work_struct *work)
 
        switch (fw_event->event) {
        case MPT2SAS_REMOVE_UNRESPONDING_DEVICES:
-               while (scsi_host_in_recovery(ioc->shost))
+               while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery)
                        ssleep(1);
                _scsih_remove_unresponding_sas_devices(ioc);
                _scsih_scan_for_devices_after_reset(ioc);
@@ -7487,7 +7527,7 @@ _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
                        return;
                if (mpt2sas_port->remote_identify.device_type ==
                    SAS_END_DEVICE)
-                       mpt2sas_device_remove(ioc,
+                       mpt2sas_device_remove_by_sas_address(ioc,
                            mpt2sas_port->remote_identify.sas_address);
                else if (mpt2sas_port->remote_identify.device_type ==
                    SAS_EDGE_EXPANDER_DEVICE ||
@@ -7661,7 +7701,7 @@ _scsih_remove(struct pci_dev *pdev)
           &ioc->sas_hba.sas_port_list, port_list) {
                if (mpt2sas_port->remote_identify.device_type ==
                    SAS_END_DEVICE)
-                       mpt2sas_device_remove(ioc,
+                       mpt2sas_device_remove_by_sas_address(ioc,
                            mpt2sas_port->remote_identify.sas_address);
                else if (mpt2sas_port->remote_identify.device_type ==
                    SAS_EDGE_EXPANDER_DEVICE ||
@@ -7733,11 +7773,11 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
                if (rc)
                        _scsih_raid_device_remove(ioc, raid_device);
        } else {
+               spin_lock_irqsave(&ioc->sas_device_lock, flags);
                sas_device = device;
                handle = sas_device->handle;
                sas_address_parent = sas_device->sas_address_parent;
                sas_address = sas_device->sas_address;
-               spin_lock_irqsave(&ioc->sas_device_lock, flags);
                list_move_tail(&sas_device->list, &ioc->sas_device_list);
                spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
 
index 8b2a3db9ea69eebec7d3fbfd41a7f9ee4fca9f55..fed8b163afef19162c426fc2e6c8d889fa600d1d 100644 (file)
@@ -163,7 +163,7 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
                return -EIO;
        }
 
-       memset(identify, 0, sizeof(*identify));
+       memset(identify, 0, sizeof(struct sas_identify));
        device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
 
        /* sas_address */
@@ -484,7 +484,7 @@ _transport_delete_port(struct MPT2SAS_ADAPTER *ioc,
 
        ioc->logging_level |= MPT_DEBUG_TRANSPORT;
        if (device_type == SAS_END_DEVICE)
-               mpt2sas_device_remove(ioc, sas_address);
+               mpt2sas_device_remove_by_sas_address(ioc, sas_address);
        else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
            device_type == SAS_FANOUT_EXPANDER_DEVICE)
                mpt2sas_expander_remove(ioc, sas_address);
@@ -792,9 +792,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
        spin_lock_irqsave(&ioc->sas_node_lock, flags);
        sas_node = _transport_sas_node_find_by_sas_address(ioc,
            sas_address_parent);
-       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-       if (!sas_node)
+       if (!sas_node) {
+               spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
                return;
+       }
        list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
            port_list) {
                if (mpt2sas_port->remote_identify.sas_address != sas_address)
@@ -804,8 +805,10 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
                goto out;
        }
  out:
-       if (!found)
+       if (!found) {
+               spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
                return;
+       }
 
        for (i = 0; i < sas_node->num_phys; i++) {
                if (sas_node->phy[i].remote_identify.sas_address == sas_address)
@@ -813,6 +816,7 @@ mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
                            sizeof(struct sas_identify));
        }
 
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
        list_for_each_entry_safe(mpt2sas_phy, next_phy,
            &mpt2sas_port->phy_list, port_siblings) {
                if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
@@ -986,12 +990,14 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
 
        spin_lock_irqsave(&ioc->sas_node_lock, flags);
        sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
-       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-       if (!sas_node)
+       if (!sas_node) {
+               spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
                return;
+       }
 
        mpt2sas_phy = &sas_node->phy[phy_number];
        mpt2sas_phy->attached_handle = handle;
+       spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
        if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {
                _transport_set_identify(ioc, handle,
                    &mpt2sas_phy->remote_identify);
@@ -1310,17 +1316,20 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
        struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
        struct _sas_device *sas_device;
        unsigned long flags;
+       int rc;
 
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
        sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
            rphy->identify.sas_address);
+       if (sas_device) {
+               *identifier = sas_device->enclosure_logical_id;
+               rc = 0;
+       } else {
+               *identifier = 0;
+               rc = -ENXIO;
+       }
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
-       if (!sas_device)
-               return -ENXIO;
-
-       *identifier = sas_device->enclosure_logical_id;
-       return 0;
+       return rc;
 }
 
 /**
@@ -1335,16 +1344,17 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
        struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
        struct _sas_device *sas_device;
        unsigned long flags;
+       int rc;
 
        spin_lock_irqsave(&ioc->sas_device_lock, flags);
        sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
            rphy->identify.sas_address);
+       if (sas_device)
+               rc = sas_device->slot;
+       else
+               rc = -ENXIO;
        spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
-       if (!sas_device)
-               return -ENXIO;
-
-       return sas_device->slot;
+       return rc;
 }
 
 /* phy control request structure */