lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 8 Sep 2015 17:25:35 +0530
From:	Sreekanth Reddy <sreekanth.reddy@...gotech.com>
To:	"Nicholas A. Bellinger" <nab@...erainc.com>
Cc:	linux-scsi <linux-scsi@...r.kernel.org>,
	linux-kernel <linux-kernel@...r.kernel.org>,
	James Bottomley <James.Bottomley@...senpartnership.com>,
	Calvin Owens <calvinowens@...com>,
	Christoph Hellwig <hch@...radead.org>,
	"MPT-FusionLinux.pdl" <MPT-FusionLinux.pdl@...gotech.com>,
	kernel-team <kernel-team@...com>,
	Nicholas Bellinger <nab@...ux-iscsi.org>,
	Chaitra Basappa <chaitra.basappa@...gotech.com>
Subject: Re: [PATCH-v2 1/2] mpt3sas: Refcount sas_device objects and fix
 unsafe list usage

On Sun, Aug 30, 2015 at 1:24 PM, Nicholas A. Bellinger
<nab@...erainc.com> wrote:
> From: Nicholas Bellinger <nab@...ux-iscsi.org>
>
> These objects can be referenced concurrently throughout the driver, we
> need a way to make sure threads can't delete them out from under
> each other. This patch adds the refcount, and refactors the code to use
> it.
>
> Additionally, we cannot iterate over the sas_device_list without
> holding the lock, or we risk corrupting random memory if items are
> added or deleted as we iterate. This patch refactors _scsih_probe_sas()
> to use the sas_device_list in a safe way.
>
> This patch is a port of Calvin's PATCH-v4 for mpt2sas code, atop
> mpt3sas changes in scsi.git/for-next.
>
> Cc: Calvin Owens <calvinowens@...com>
> Cc: Christoph Hellwig <hch@...radead.org>
> Cc: Sreekanth Reddy <sreekanth.reddy@...gotech.com>
> Cc: MPT-FusionLinux.pdl <MPT-FusionLinux.pdl@...gotech.com>
> Signed-off-by: Nicholas Bellinger <nab@...ux-iscsi.org>
> ---
>  drivers/scsi/mpt3sas/mpt3sas_base.h      |  25 +-
>  drivers/scsi/mpt3sas/mpt3sas_scsih.c     | 479 +++++++++++++++++++++----------
>  drivers/scsi/mpt3sas/mpt3sas_transport.c |  18 +-
>  3 files changed, 364 insertions(+), 158 deletions(-)
>
> diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
> index f0e462b..9a73c8b 100644
> --- a/drivers/scsi/mpt3sas/mpt3sas_base.h
> +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
> @@ -248,6 +248,7 @@ struct Mpi2ManufacturingPage11_t {
>   * @flags: MPT_TARGET_FLAGS_XXX flags
>   * @deleted: target flaged for deletion
>   * @tm_busy: target is busy with TM request.
> + * @sdev: The sas_device associated with this target
>   */
>  struct MPT3SAS_TARGET {
>         struct scsi_target *starget;
> @@ -257,6 +258,7 @@ struct MPT3SAS_TARGET {
>         u32     flags;
>         u8      deleted;
>         u8      tm_busy;
> +       struct  _sas_device *sdev;
>  };
>
>
> @@ -335,6 +337,9 @@ struct _internal_cmd {
>   * @pfa_led_on: flag for PFA LED status
>   * @pend_sas_rphy_add: flag to check if device is in sas_rphy_add()
>   *     addition routine.
> + * @enclosure_level: used for enclosure services
> + * @connector_name: ASCII value from pg0.ConnectorName
> + * @refcount: reference count for deletion
>   */
>  struct _sas_device {
>         struct list_head list;
> @@ -358,8 +363,24 @@ struct _sas_device {
>         u8      pend_sas_rphy_add;
>         u8      enclosure_level;
>         u8      connector_name[4];
> +       struct kref refcount;
>  };
>
> +static inline void sas_device_get(struct _sas_device *s)
> +{
> +       kref_get(&s->refcount);
> +}
> +
> +static inline void sas_device_free(struct kref *r)
> +{
> +       kfree(container_of(r, struct _sas_device, refcount));
> +}
> +
> +static inline void sas_device_put(struct _sas_device *s)
> +{
> +       kref_put(&s->refcount, sas_device_free);
> +}
> +
>  /**
>   * struct _raid_device - raid volume link list
>   * @list: sas device list
> @@ -1090,7 +1111,9 @@ struct _sas_node *mpt3sas_scsih_expander_find_by_handle(
>         struct MPT3SAS_ADAPTER *ioc, u16 handle);
>  struct _sas_node *mpt3sas_scsih_expander_find_by_sas_address(
>         struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
> -struct _sas_device *mpt3sas_scsih_sas_device_find_by_sas_address(
> +struct _sas_device *mpt3sas_get_sdev_by_addr(
> +        struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
> +struct _sas_device *__mpt3sas_get_sdev_by_addr(
>         struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
>
>  void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc);
> diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
> index 8ccef38..897153b 100644
> --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
> +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
> @@ -518,8 +518,61 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
>         }
>  }
>
> +static struct _sas_device *
> +__mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc,
> +       struct MPT3SAS_TARGET *tgt_priv)
> +{
> +       struct _sas_device *ret;
> +
> +       assert_spin_locked(&ioc->sas_device_lock);
> +
> +       ret = tgt_priv->sdev;
> +       if (ret)
> +               sas_device_get(ret);
> +
> +       return ret;
> +}
> +
> +static struct _sas_device *
> +mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc,
> +       struct MPT3SAS_TARGET *tgt_priv)
> +{
> +       struct _sas_device *ret;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&ioc->sas_device_lock, flags);
> +       ret = __mpt3sas_get_sdev_from_target(ioc, tgt_priv);
> +       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> +
> +       return ret;
> +}
> +
> +struct _sas_device *
> +__mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc,
> +       u64 sas_address)
> +{
> +       struct _sas_device *sas_device;
> +
> +       assert_spin_locked(&ioc->sas_device_lock);
> +
> +       list_for_each_entry(sas_device, &ioc->sas_device_list, list)
> +               if (sas_device->sas_address == sas_address)
> +                       goto found_device;
> +
> +       list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
> +               if (sas_device->sas_address == sas_address)
> +                       goto found_device;
> +
> +       return NULL;
> +
> +found_device:
> +       sas_device_get(sas_device);
> +       return sas_device;
> +}
> +
> +
>  /**
> - * mpt3sas_scsih_sas_device_find_by_sas_address - sas device search
> + * mpt3sas_get_sdev_by_addr - sas device search
>   * @ioc: per adapter object
>   * @sas_address: sas address
>   * Context: Calling function should acquire ioc->sas_device_lock
> @@ -528,24 +581,44 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
>   * object.
>   */
>  struct _sas_device *
> -mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
> +mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc,
>         u64 sas_address)
>  {
>         struct _sas_device *sas_device;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&ioc->sas_device_lock, flags);
> +       sas_device = __mpt3sas_get_sdev_by_addr(ioc,
> +                       sas_address);
> +       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> +
> +       return sas_device;
> +}
> +
> +static struct _sas_device *
> +__mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
> +{
> +       struct _sas_device *sas_device;
> +
> +       assert_spin_locked(&ioc->sas_device_lock);
>
>         list_for_each_entry(sas_device, &ioc->sas_device_list, list)
> -               if (sas_device->sas_address == sas_address)
> -                       return sas_device;
> +               if (sas_device->handle == handle)
> +                       goto found_device;
>
>         list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
> -               if (sas_device->sas_address == sas_address)
> -                       return sas_device;
> +               if (sas_device->handle == handle)
> +                       goto found_device;
>
>         return NULL;
> +
> +found_device:
> +       sas_device_get(sas_device);
> +       return sas_device;
>  }
>
>  /**
> - * _scsih_sas_device_find_by_handle - sas device search
> + * mpt3sas_get_sdev_by_handle - sas device search
>   * @ioc: per adapter object
>   * @handle: sas device handle (assigned by firmware)
>   * Context: Calling function should acquire ioc->sas_device_lock
> @@ -554,19 +627,16 @@ mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
>   * object.
>   */
>  static struct _sas_device *
> -_scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
> +mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>  {
>         struct _sas_device *sas_device;
> +       unsigned long flags;
>
> -       list_for_each_entry(sas_device, &ioc->sas_device_list, list)
> -               if (sas_device->handle == handle)
> -                       return sas_device;
> -
> -       list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
> -               if (sas_device->handle == handle)
> -                       return sas_device;
> +       spin_lock_irqsave(&ioc->sas_device_lock, flags);
> +       sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
> +       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>
> -       return NULL;
> +       return sas_device;
>  }
>
>  /**
> @@ -575,7 +645,7 @@ _scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>   * @sas_device: the sas_device object
>   * Context: This function will acquire ioc->sas_device_lock.
>   *
> - * Removing object and freeing associated memory from the ioc->sas_device_list.
> + * If sas_device is on the list, remove it and decrement its reference count.
>   */
>  static void
>  _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc,
> @@ -601,10 +671,15 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc,
>                    "removing enclosure level(0x%04x), connector name( %s)\n",
>                    ioc->name, sas_device->enclosure_level,
>                    sas_device->connector_name);
> -
> +       /*
> +        * The lock serializes access to the list, but we still need to verify
> +        * that nobody removed the entry while we were waiting on the lock.
> +        */
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -       list_del(&sas_device->list);
> -       kfree(sas_device);
> +       if (!list_empty(&sas_device->list)) {
> +               list_del_init(&sas_device->list);
> +               sas_device_put(sas_device);
> +       }
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>  }
>
> @@ -625,12 +700,17 @@ _scsih_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>                 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);
> +       sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
> +       if (sas_device) {
> +               list_del_init(&sas_device->list);
> +               sas_device_put(sas_device);
> +       }
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -       if (sas_device)
> +
> +       if (sas_device) {
>                 _scsih_remove_device(ioc, sas_device);
> +               sas_device_put(sas_device);
> +       }
>  }
>
>  /**
> @@ -651,13 +731,17 @@ mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
>                 return;
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -       sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> -           sas_address);
> -       if (sas_device)
> -               list_del(&sas_device->list);
> +       sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address);
> +       if (sas_device) {
> +               list_del_init(&sas_device->list);
> +               sas_device_put(sas_device);
> +       }
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -       if (sas_device)
> +
> +       if (sas_device) {
>                 _scsih_remove_device(ioc, sas_device);
> +               sas_device_put(sas_device);
> +       }
>  }
>
>  /**
> @@ -692,6 +776,7 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc,
>                     sas_device->enclosure_level, sas_device->connector_name));
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> +       sas_device_get(sas_device);
>         list_add_tail(&sas_device->list, &ioc->sas_device_list);
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>
> @@ -745,6 +830,7 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc,
>                     sas_device->connector_name));
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> +       sas_device_get(sas_device);
>         list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
>         _scsih_determine_boot_device(ioc, sas_device, 0);
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> @@ -1123,12 +1209,15 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
>                 goto not_sata;
>         if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
>                 goto not_sata;
> +
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -       sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> -          sas_device_priv_data->sas_target->sas_address);
> -       if (sas_device && sas_device->device_info &
> -           MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
> -               max_depth = MPT3SAS_SATA_QUEUE_DEPTH;
> +       sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
> +       if (sas_device) {
> +               if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
> +                       max_depth = MPT3SAS_SATA_QUEUE_DEPTH;
> +
> +               sas_device_put(sas_device);
> +       }
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>
>   not_sata:
> @@ -1185,12 +1274,13 @@ _scsih_target_alloc(struct scsi_target *starget)
>         /* sas/sata devices */
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
>         rphy = dev_to_rphy(starget->dev.parent);
> -       sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> +       sas_device = __mpt3sas_get_sdev_by_addr(ioc,
>            rphy->identify.sas_address);
>
>         if (sas_device) {
>                 sas_target_priv_data->handle = sas_device->handle;
>                 sas_target_priv_data->sas_address = sas_device->sas_address;
> +               sas_target_priv_data->sdev = sas_device;
>                 sas_device->starget = starget;
>                 sas_device->id = starget->id;
>                 sas_device->channel = starget->channel;
> @@ -1240,13 +1330,21 @@ _scsih_target_destroy(struct scsi_target *starget)
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
>         rphy = dev_to_rphy(starget->dev.parent);
> -       sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> -          rphy->identify.sas_address);
> +       sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
>         if (sas_device && (sas_device->starget == starget) &&
>             (sas_device->id == starget->id) &&
>             (sas_device->channel == starget->channel))
>                 sas_device->starget = NULL;
>
> +       if (sas_device) {
> +               /*
> +                * Corresponding get() is in _scsih_target_alloc()
> +                */
> +               sas_target_priv_data->sdev = NULL;
> +               sas_device_put(sas_device);
> +
> +               sas_device_put(sas_device);
> +       }
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>
>   out:
> @@ -1302,7 +1400,7 @@ _scsih_slave_alloc(struct scsi_device *sdev)
>
>         if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
>                 spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -               sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> +               sas_device = __mpt3sas_get_sdev_by_addr(ioc,
>                                         sas_target_priv_data->sas_address);
>                 if (sas_device && (sas_device->starget == NULL)) {
>                         sdev_printk(KERN_INFO, sdev,
> @@ -1310,6 +1408,10 @@ _scsih_slave_alloc(struct scsi_device *sdev)
>                                 __func__, __LINE__);
>                         sas_device->starget = starget;
>                 }
> +
> +               if (sas_device)
> +                       sas_device_put(sas_device);
> +
>                 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>         }
>
> @@ -1344,10 +1446,14 @@ _scsih_slave_destroy(struct scsi_device *sdev)
>
>         if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
>                 spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -               sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> -                  sas_target_priv_data->sas_address);
> +               sas_device = __mpt3sas_get_sdev_from_target(ioc,
> +                               sas_target_priv_data);
>                 if (sas_device && !sas_target_priv_data->num_luns)
>                         sas_device->starget = NULL;
> +
> +               if (sas_device)
> +                       sas_device_put(sas_device);
> +
>                 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>         }
>
> @@ -1783,7 +1889,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
>         }
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -       sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> +       sas_device = __mpt3sas_get_sdev_by_addr(ioc,
>            sas_device_priv_data->sas_target->sas_address);
>         if (!sas_device) {
>                 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> @@ -1823,12 +1929,12 @@ _scsih_slave_configure(struct scsi_device *sdev)
>                      ds, sas_device->enclosure_level,
>                      sas_device->connector_name);
>
> +       sas_device_put(sas_device);
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>
>         if (!ssp_target)
>                 _scsih_display_sata_capabilities(ioc, handle, sdev);
>
> -
>         _scsih_change_queue_depth(sdev, qdepth);
>
>         if (ssp_target) {
> @@ -2219,8 +2325,7 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
>                     device_str, (unsigned long long)priv_target->sas_address);
>         } else {
>                 spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -               sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> -                   priv_target->sas_address);
> +               sas_device = __mpt3sas_get_sdev_from_target(ioc, priv_target);
>                 if (sas_device) {
>                         if (priv_target->flags &
>                             MPT_TARGET_FLAGS_RAID_COMPONENT) {
> @@ -2246,8 +2351,9 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
>                                 "enclosure level(0x%04x),connector name(%s)\n",
>                                  sas_device->enclosure_level,
>                                  sas_device->connector_name);
> +
> +                       sas_device_put(sas_device);
>                 }
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>         }
>  }
>
> @@ -2321,10 +2427,11 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
>  {
>         struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
>         struct MPT3SAS_DEVICE *sas_device_priv_data;
> -       struct _sas_device *sas_device;
> -       unsigned long flags;
> +       struct _sas_device *sas_device = NULL;
>         u16     handle;
>         int r;
> +       struct scsi_target *starget = scmd->device->sdev_target;
> +       struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
>
>         sdev_printk(KERN_INFO, scmd->device,
>                 "attempting device reset! scmd(%p)\n", scmd);
> @@ -2344,12 +2451,10 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
>         handle = 0;
>         if (sas_device_priv_data->sas_target->flags &
>             MPT_TARGET_FLAGS_RAID_COMPONENT) {
> -               spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -               sas_device = _scsih_sas_device_find_by_handle(ioc,
> -                  sas_device_priv_data->sas_target->handle);
> +               sas_device = mpt3sas_get_sdev_from_target(ioc,
> +                               target_priv_data);
>                 if (sas_device)
>                         handle = sas_device->volume_handle;
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>         } else
>                 handle = sas_device_priv_data->sas_target->handle;
>
> @@ -2366,6 +2471,10 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
>   out:
>         sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
>             ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
> +
> +       if (sas_device)
> +               sas_device_put(sas_device);
> +
>         return r;
>  }
>
> @@ -2380,11 +2489,11 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
>  {
>         struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
>         struct MPT3SAS_DEVICE *sas_device_priv_data;
> -       struct _sas_device *sas_device;
> -       unsigned long flags;
> +       struct _sas_device *sas_device = NULL;
>         u16     handle;
>         int r;
>         struct scsi_target *starget = scmd->device->sdev_target;
> +       struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
>
>         starget_printk(KERN_INFO, starget, "attempting target reset! scmd(%p)\n",
>                 scmd);
> @@ -2404,12 +2513,10 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
>         handle = 0;
>         if (sas_device_priv_data->sas_target->flags &
>             MPT_TARGET_FLAGS_RAID_COMPONENT) {
> -               spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -               sas_device = _scsih_sas_device_find_by_handle(ioc,
> -                  sas_device_priv_data->sas_target->handle);
> +               sas_device = mpt3sas_get_sdev_from_target(ioc,
> +                               target_priv_data);
>                 if (sas_device)
>                         handle = sas_device->volume_handle;
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>         } else
>                 handle = sas_device_priv_data->sas_target->handle;
>
> @@ -2426,6 +2533,10 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
>   out:
>         starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
>             ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
> +
> +       if (sas_device)
> +               sas_device_put(sas_device);
> +
>         return r;
>  }
>
> @@ -2763,7 +2874,7 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>         struct scsi_device *sdev;
>         struct _sas_device *sas_device;
>

[Sreekanth] Here sas_device_lock spin lock needs to be acquired before calling
                  __mpt3sas_get_sdev_by_addr() function.

> -       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
> +       sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
>         if (!sas_device)
>                 return;
>
> @@ -2779,6 +2890,8 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>                         continue;
>                 _scsih_internal_device_block(sdev, sas_device_priv_data);
>         }
> +
> +       sas_device_put(sas_device);
>  }
>
>  /**
> @@ -2804,15 +2917,15 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc,
>
>         list_for_each_entry(mpt3sas_port,
>            &sas_expander->sas_port_list, port_list) {
> -               if (mpt3sas_port->remote_identify.device_type ==
> -                   SAS_END_DEVICE) {
> +               if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
>                         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -                       sas_device =
> -                           mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> -                          mpt3sas_port->remote_identify.sas_address);
> -                       if (sas_device)
> +                       sas_device = __mpt3sas_get_sdev_by_addr(ioc,
> +                                       mpt3sas_port->remote_identify.sas_address);
> +                       if (sas_device) {
>                                 set_bit(sas_device->handle,
> -                                   ioc->blocking_handles);
> +                                       ioc->blocking_handles);
> +                               sas_device_put(sas_device);
> +                       }
>                         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>                 }
>         }
> @@ -2880,7 +2993,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>  {
>         Mpi2SCSITaskManagementRequest_t *mpi_request;
>         u16 smid;
> -       struct _sas_device *sas_device;
> +       struct _sas_device *sas_device = NULL;
>         struct MPT3SAS_TARGET *sas_target_priv_data = NULL;
>         u64 sas_address = 0;
>         unsigned long flags;
> @@ -2913,7 +3026,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>                 return;
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
> +       sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
>         if (sas_device && sas_device->starget &&
>             sas_device->starget->hostdata) {
>                 sas_target_priv_data = sas_device->starget->hostdata;
> @@ -2947,14 +3060,14 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>         if (!smid) {
>                 delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
>                 if (!delayed_tr)
> -                       return;
> +                       goto out;
>                 INIT_LIST_HEAD(&delayed_tr->list);
>                 delayed_tr->handle = handle;
>                 list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
>                 dewtprintk(ioc, pr_info(MPT3SAS_FMT
>                     "DELAYED:tr:handle(0x%04x), (open)\n",
>                     ioc->name, handle));
> -               return;
> +               goto out;
>         }
>
>         dewtprintk(ioc, pr_info(MPT3SAS_FMT
> @@ -2968,6 +3081,9 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>         mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
>         mpt3sas_base_put_smid_hi_priority(ioc, smid);
>         mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
> +out:
> +       if (sas_device)
> +               sas_device_put(sas_device);
>  }
>
>  /**
> @@ -3818,7 +3934,6 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
>         char *desc_scsi_state = ioc->tmp_string;
>         u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
>         struct _sas_device *sas_device = NULL;
> -       unsigned long flags;
>         struct scsi_target *starget = scmd->device->sdev_target;
>         struct MPT3SAS_TARGET *priv_target = starget->hostdata;
>         char *device_str = NULL;
> @@ -3946,9 +4061,7 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
>                 pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
>                     device_str, (unsigned long long)priv_target->sas_address);
>         } else {
> -               spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -               sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> -                   priv_target->sas_address);
> +               sas_device = mpt3sas_get_sdev_from_target(ioc, priv_target);
>                 if (sas_device) {
>                         pr_warn(MPT3SAS_FMT
>                                 "\tsas_address(0x%016llx), phy(%d)\n",
> @@ -3967,8 +4080,9 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
>                                   " connector name( %s)\n", ioc->name,
>                                   sas_device->enclosure_level,
>                                   sas_device->connector_name);
> +
> +                       sas_device_put(sas_device);
>                 }
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>         }
>
>         pr_warn(MPT3SAS_FMT
> @@ -4020,7 +4134,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>         Mpi2SepRequest_t mpi_request;
>         struct _sas_device *sas_device;
>
> -       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
> +       sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
>         if (!sas_device)
>                 return;
>
> @@ -4035,7 +4149,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>             &mpi_request)) != 0) {
>                 pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name,
>                 __FILE__, __LINE__, __func__);
> -               return;
> +               goto out;
>         }
>         sas_device->pfa_led_on = 1;
>
> @@ -4044,8 +4158,10 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>                         "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n",
>                         ioc->name, le16_to_cpu(mpi_reply.IOCStatus),
>                     le32_to_cpu(mpi_reply.IOCLogInfo)));
> -               return;
> +               goto out;
>         }
> +out:
> +       sas_device_put(sas_device);
>  }
>  /**
>   * _scsih_turn_off_pfa_led - turn off Fault LED
> @@ -4128,19 +4244,17 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>
>         /* only handle non-raid devices */
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
> +       sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
>         if (!sas_device) {
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -               return;
> +               goto out_unlock;
>         }
>         starget = sas_device->starget;
>         sas_target_priv_data = starget->hostdata;
>
>         if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
> -          ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -               return;
> -       }
> +          ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)))
> +               goto out_unlock;
> +
>         if (sas_device->enclosure_handle != 0)
>                 starget_printk(KERN_INFO, starget, "predicted fault, "
>                         "enclosure logical id(0x%016llx), slot(%d)\n",
> @@ -4163,7 +4277,7 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>         if (!event_reply) {
>                 pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
>                     ioc->name, __FILE__, __LINE__, __func__);
> -               return;
> +               goto out;
>         }
>
>         event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
> @@ -4180,6 +4294,14 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
>         event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
>         mpt3sas_ctl_add_to_event_log(ioc, event_reply);
>         kfree(event_reply);
> +out:
> +       if (sas_device)
> +               sas_device_put(sas_device);
> +       return;
> +
> +out_unlock:
> +       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> +       goto out;
>  }
>
>  /**
> @@ -4933,13 +5055,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
>         sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
> -       sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> +       sas_device = __mpt3sas_get_sdev_by_addr(ioc,
>             sas_address);
>
> -       if (!sas_device) {
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -               return;
> -       }
> +       if (!sas_device)
> +               goto out_unlock;
>
>         if (unlikely(sas_device->handle != handle)) {
>                 starget = sas_device->starget;
> @@ -4967,20 +5087,24 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
>                 pr_err(MPT3SAS_FMT
>                         "device is not present handle(0x%04x), flags!!!\n",
>                         ioc->name, handle);
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -               return;
> +               goto out_unlock;
>         }
>
>         /* check if there were any issues with discovery */
>         if (_scsih_check_access_status(ioc, sas_address, handle,
> -           sas_device_pg0.AccessStatus)) {
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -               return;
> -       }
> +           sas_device_pg0.AccessStatus))
> +               goto out_unlock;
>
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>         _scsih_ublock_io_device(ioc, sas_address);
> +       if (sas_device)
> +               sas_device_put(sas_device);
> +       return;
>
> +out_unlock:
> +       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> +       if (sas_device)
> +               sas_device_put(sas_device);
>  }
>
>  /**
> @@ -5005,7 +5129,6 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
>         u32 ioc_status;
>         u64 sas_address;
>         u32 device_info;
> -       unsigned long flags;
>
>         if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
>             MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
> @@ -5041,13 +5164,11 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
>             sas_device_pg0.AccessStatus))
>                 return -1;
>
> -       spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -       sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> -           sas_address);
> -       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -
> -       if (sas_device)
> +       sas_device = mpt3sas_get_sdev_by_addr(ioc, sas_address);
> +       if (sas_device) {
> +               sas_device_put(sas_device);
>                 return -1;
> +       }
>
>         sas_device = kzalloc(sizeof(struct _sas_device),
>             GFP_KERNEL);
> @@ -5057,6 +5178,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
>                 return 0;
>         }
>
> +       kref_init(&sas_device->refcount);
>         sas_device->handle = handle;
>         if (_scsih_get_sas_address(ioc,
>             le16_to_cpu(sas_device_pg0.ParentDevHandle),
> @@ -5098,6 +5220,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
>         else
>                 _scsih_sas_device_add(ioc, sas_device);
>
> +       sas_device_put(sas_device);
>         return 0;
>  }
>
> @@ -5506,25 +5629,25 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc,
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
>         sas_address = le64_to_cpu(event_data->SASAddress);
> -       sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> -           sas_address);
> +       sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address);
>
> -       if (!sas_device || !sas_device->starget) {
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -               return;
> -       }
> +       if (!sas_device || !sas_device->starget)
> +               goto out;
>
>         target_priv_data = sas_device->starget->hostdata;
> -       if (!target_priv_data) {
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -               return;
> -       }
> +       if (!target_priv_data)
> +               goto out;
>
>         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;
> +
> +out:
> +       if (sas_device)
> +               sas_device_put(sas_device);
> +
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>  }
>
> @@ -6008,7 +6131,7 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc,
>         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);
> +       sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
>         if (sas_device) {
>                 sas_device->volume_handle = 0;
>                 sas_device->volume_wwid = 0;
> @@ -6027,6 +6150,8 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc,
>         /* exposing raid component */
>         if (starget)
>                 starget_for_each_device(starget, NULL, _scsih_reprobe_lun);
> +
> +       sas_device_put(sas_device);
>  }
>
>  /**
> @@ -6055,7 +6180,7 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc,
>                     &volume_wwid);
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -       sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
> +       sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
>         if (sas_device) {
>                 set_bit(handle, ioc->pd_handles);
>                 if (sas_device->starget && sas_device->starget->hostdata) {
> @@ -6075,6 +6200,8 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc,
>         _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum);
>         if (starget)
>                 starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
> +
> +       sas_device_put(sas_device);
>  }
>
>  /**
> @@ -6107,7 +6234,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
>         Mpi2EventIrConfigElement_t *element)
>  {
>         struct _sas_device *sas_device;
> -       unsigned long flags;
>         u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
>         Mpi2ConfigReply_t mpi_reply;
>         Mpi2SasDevicePage0_t sas_device_pg0;
> @@ -6117,11 +6243,10 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
>
>         set_bit(handle, ioc->pd_handles);
>
> -       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);
> +       sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
>         if (sas_device) {
>                 _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum);
> +               sas_device_put(sas_device);
>                 return;
>         }
>
> @@ -6398,7 +6523,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
>         u16 handle, parent_handle;
>         u32 state;
>         struct _sas_device *sas_device;
> -       unsigned long flags;
>         Mpi2ConfigReply_t mpi_reply;
>         Mpi2SasDevicePage0_t sas_device_pg0;
>         u32 ioc_status;
> @@ -6427,12 +6551,12 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
>         case MPI2_RAID_PD_STATE_HOT_SPARE:
>
>                 set_bit(handle, ioc->pd_handles);
> -               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)
> +               sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
> +               if (sas_device) {
> +                       sas_device_put(sas_device);
>                         return;
> +               }
>
>                 if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply,
>                     &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
> @@ -6906,6 +7030,7 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
>         struct _raid_device *raid_device, *raid_device_next;
>         struct list_head tmp_list;
>         unsigned long flags;
> +       LIST_HEAD(head);
>
>         pr_info(MPT3SAS_FMT "removing unresponding devices: start\n",
>             ioc->name);
> @@ -6913,14 +7038,29 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
>         /* removing unresponding end devices */
>         pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n",
>             ioc->name);
> +
> +       /*
> +        * Iterate, pulling off devices marked as non-responding. We become the
> +        * owner for the reference the list had on any object we prune.
> +        */
> +       spin_lock_irqsave(&ioc->sas_device_lock, flags);
>         list_for_each_entry_safe(sas_device, sas_device_next,
> -           &ioc->sas_device_list, list) {
> +                                &ioc->sas_device_list, list) {
>                 if (!sas_device->responding)
> -                       mpt3sas_device_remove_by_sas_address(ioc,
> -                           sas_device->sas_address);
> +                       list_move_tail(&sas_device->list, &head);
>                 else
>                         sas_device->responding = 0;
>         }
> +       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> +
> +       /*
> +        * Now, uninitialize and remove the unresponding devices we pruned.
> +        */
> +       list_for_each_entry_safe(sas_device, sas_device_next, &head, list) {
> +               _scsih_remove_device(ioc, sas_device);
> +               list_del_init(&sas_device->list);
> +               sas_device_put(sas_device);
> +       }
>
>         /* removing unresponding volumes */
>         if (ioc->ir_firmware) {
> @@ -7074,11 +7214,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
>                 }
>                 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)
> +               sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
> +               if (sas_device) {
> +                       sas_device_put(sas_device);
>                         continue;
> +               }
>                 if (mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply,
>                     &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
>                     handle) != 0)
> @@ -7199,12 +7339,12 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_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 = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> +               sas_device = mpt3sas_get_sdev_by_addr(ioc,
>                     le64_to_cpu(sas_device_pg0.SASAddress));
> -               spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> -               if (sas_device)
> +               if (sas_device) {
> +                       sas_device_put(sas_device);
>                         continue;
> +               }
>                 parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
>                 if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) {
>                         pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \
> @@ -7831,6 +7971,48 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc)
>         }
>  }
>
> +static struct _sas_device *get_next_sas_device(struct MPT3SAS_ADAPTER *ioc)
> +{
> +       struct _sas_device *sas_device = NULL;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&ioc->sas_device_lock, flags);
> +       if (!list_empty(&ioc->sas_device_init_list)) {
> +               sas_device = list_first_entry(&ioc->sas_device_init_list,
> +                               struct _sas_device, list);
> +               sas_device_get(sas_device);
> +       }
> +       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> +
> +       return sas_device;
> +}
> +
> +static void sas_device_make_active(struct MPT3SAS_ADAPTER *ioc,
> +               struct _sas_device *sas_device)
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&ioc->sas_device_lock, flags);
> +
> +       /*
> +        * Since we dropped the lock during the call to port_add(), we need to
> +        * be careful here that somebody else didn't move or delete this item
> +        * while we were busy with other things.
> +        *
> +        * If it was on the list, we need a put() for the reference the list
> +        * had. Either way, we need a get() for the destination list.
> +        */
> +       if (!list_empty(&sas_device->list)) {
> +               list_del_init(&sas_device->list);
> +               sas_device_put(sas_device);
> +       }
> +
> +       sas_device_get(sas_device);
> +       list_add_tail(&sas_device->list, &ioc->sas_device_list);
> +
> +       spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
> +}
> +
>  /**
>   * _scsih_probe_sas - reporting sas devices to sas transport
>   * @ioc: per adapter object
> @@ -7840,17 +8022,13 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc)
>  static void
>  _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
>  {
> -       struct _sas_device *sas_device, *next;
> -       unsigned long flags;
> -
> -       /* SAS Device List */
> -       list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
> -           list) {
> +       struct _sas_device *sas_device;
>
> +       while ((sas_device = get_next_sas_device(ioc))) {
>                 if (!mpt3sas_transport_port_add(ioc, sas_device->handle,
> -                   sas_device->sas_address_parent)) {
> -                       list_del(&sas_device->list);
> -                       kfree(sas_device);
> +                               sas_device->sas_address_parent)) {
> +                       _scsih_sas_device_remove(ioc, sas_device);
> +                       sas_device_put(sas_device);
>                         continue;
>                 } else if (!sas_device->starget) {
>                         /*
> @@ -7861,17 +8039,16 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
>                          */
>                         if (!ioc->is_driver_loading) {
>                                 mpt3sas_transport_port_remove(ioc,
> -                                   sas_device->sas_address,
> -                                   sas_device->sas_address_parent);
> -                               list_del(&sas_device->list);
> -                               kfree(sas_device);
> +                                               sas_device->sas_address,
> +                                               sas_device->sas_address_parent);
> +                               _scsih_sas_device_remove(ioc, sas_device);
> +                               sas_device_put(sas_device);
>                                 continue;
>                         }
>                 }
>
> -               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);
> +               sas_device_make_active(ioc, sas_device);
> +               sas_device_put(sas_device);
>         }
>  }
>
> diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
> index 70fd019..6074b11 100644
> --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
> +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
> @@ -734,7 +734,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
>         rphy->identify = mpt3sas_port->remote_identify;
>
>         if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {

[Sreekanth] Here also sas_device_lock spin lock needs to be acquired
before calling
                  __mpt3sas_get_sdev_by_addr() function.


> -               sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> +               sas_device = __mpt3sas_get_sdev_by_addr(ioc,
>                                     mpt3sas_port->remote_identify.sas_address);
>                 if (!sas_device) {
>                         dfailprintk(ioc, printk(MPT3SAS_FMT
> @@ -750,8 +750,10 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
>                     ioc->name, __FILE__, __LINE__, __func__);
>         }
>
> -       if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE)
> +       if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
>                 sas_device->pend_sas_rphy_add = 0;
> +               sas_device_put(sas_device);
> +       }
>
>         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
>                 dev_printk(KERN_INFO, &rphy->dev,
> @@ -1324,15 +1326,17 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
>         int rc;
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -       sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> +       sas_device = __mpt3sas_get_sdev_by_addr(ioc,
>             rphy->identify.sas_address);
>         if (sas_device) {
>                 *identifier = sas_device->enclosure_logical_id;
>                 rc = 0;
> +               sas_device_put(sas_device);
>         } else {
>                 *identifier = 0;
>                 rc = -ENXIO;
>         }
> +
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>         return rc;
>  }
> @@ -1352,12 +1356,14 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
>         int rc;
>
>         spin_lock_irqsave(&ioc->sas_device_lock, flags);
> -       sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
> +       sas_device = __mpt3sas_get_sdev_by_addr(ioc,
>             rphy->identify.sas_address);
> -       if (sas_device)
> +       if (sas_device) {
>                 rc = sas_device->slot;
> -       else
> +               sas_device_put(sas_device);
> +       } else {
>                 rc = -ENXIO;
> +       }
>         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
>         return rc;
>  }
> --
> 1.9.1
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ