Commit d1cb5e49 authored by Sreekanth Reddy's avatar Sreekanth Reddy Committed by Martin K. Petersen

mpt3sas: Refcount sas_device objects and fix unsafe list usage

sas_device 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 ported from the following mpt2sas driver commit
d224fe0d ("mpt2sas: Refcount sas_device objects and fix unsafe list
usage").
Signed-off-by: default avatarSreekanth Reddy <Sreekanth.Reddy@avagotech.com>
Acked-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 42263095
...@@ -273,6 +273,7 @@ struct Mpi2ManufacturingPage11_t { ...@@ -273,6 +273,7 @@ struct Mpi2ManufacturingPage11_t {
* @flags: MPT_TARGET_FLAGS_XXX flags * @flags: MPT_TARGET_FLAGS_XXX flags
* @deleted: target flaged for deletion * @deleted: target flaged for deletion
* @tm_busy: target is busy with TM request. * @tm_busy: target is busy with TM request.
* @sdev: The sas_device associated with this target
*/ */
struct MPT3SAS_TARGET { struct MPT3SAS_TARGET {
struct scsi_target *starget; struct scsi_target *starget;
...@@ -283,6 +284,7 @@ struct MPT3SAS_TARGET { ...@@ -283,6 +284,7 @@ struct MPT3SAS_TARGET {
u32 flags; u32 flags;
u8 deleted; u8 deleted;
u8 tm_busy; u8 tm_busy;
struct _sas_device *sdev;
}; };
...@@ -389,8 +391,24 @@ struct _sas_device { ...@@ -389,8 +391,24 @@ struct _sas_device {
u8 pend_sas_rphy_add; u8 pend_sas_rphy_add;
u8 enclosure_level; u8 enclosure_level;
u8 connector_name[4]; 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 * struct _raid_device - raid volume link list
* @list: sas device list * @list: sas device list
...@@ -1148,7 +1166,9 @@ struct _sas_node *mpt3sas_scsih_expander_find_by_handle( ...@@ -1148,7 +1166,9 @@ struct _sas_node *mpt3sas_scsih_expander_find_by_handle(
struct MPT3SAS_ADAPTER *ioc, u16 handle); struct MPT3SAS_ADAPTER *ioc, u16 handle);
struct _sas_node *mpt3sas_scsih_expander_find_by_sas_address( struct _sas_node *mpt3sas_scsih_expander_find_by_sas_address(
struct MPT3SAS_ADAPTER *ioc, u64 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); struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc); void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc);
......
...@@ -502,8 +502,61 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, ...@@ -502,8 +502,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 * @ioc: per adapter object
* @sas_address: sas address * @sas_address: sas address
* Context: Calling function should acquire ioc->sas_device_lock * Context: Calling function should acquire ioc->sas_device_lock
...@@ -512,24 +565,44 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, ...@@ -512,24 +565,44 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
* object. * object.
*/ */
struct _sas_device * 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) u64 sas_address)
{ {
struct _sas_device *sas_device; 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);
list_for_each_entry(sas_device, &ioc->sas_device_list, list)
if (sas_device->sas_address == sas_address)
return sas_device; 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->handle == handle)
goto found_device;
list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
if (sas_device->sas_address == sas_address) if (sas_device->handle == handle)
return sas_device; goto found_device;
return NULL; 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 * @ioc: per adapter object
* @handle: sas device handle (assigned by firmware) * @handle: sas device handle (assigned by firmware)
* Context: Calling function should acquire ioc->sas_device_lock * Context: Calling function should acquire ioc->sas_device_lock
...@@ -538,19 +611,16 @@ mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, ...@@ -538,19 +611,16 @@ mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
* object. * object.
*/ */
static struct _sas_device * 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; struct _sas_device *sas_device;
unsigned long flags;
list_for_each_entry(sas_device, &ioc->sas_device_list, list) spin_lock_irqsave(&ioc->sas_device_lock, flags);
if (sas_device->handle == handle) sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
return sas_device; spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
if (sas_device->handle == handle)
return sas_device; return sas_device;
return NULL;
} }
/** /**
...@@ -559,7 +629,7 @@ _scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -559,7 +629,7 @@ _scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
* @sas_device: the sas_device object * @sas_device: the sas_device object
* Context: This function will acquire ioc->sas_device_lock. * 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 static void
_scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc,
...@@ -586,9 +656,15 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, ...@@ -586,9 +656,15 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc,
ioc->name, sas_device->enclosure_level, ioc->name, sas_device->enclosure_level,
sas_device->connector_name); 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); spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_del(&sas_device->list); if (!list_empty(&sas_device->list)) {
kfree(sas_device); list_del_init(&sas_device->list);
sas_device_put(sas_device);
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} }
...@@ -609,12 +685,16 @@ _scsih_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -609,12 +685,16 @@ _scsih_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
return; return;
spin_lock_irqsave(&ioc->sas_device_lock, flags); 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) if (sas_device) {
list_del(&sas_device->list); list_del_init(&sas_device->list);
sas_device_put(sas_device);
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (sas_device) if (sas_device) {
_scsih_remove_device(ioc, sas_device); _scsih_remove_device(ioc, sas_device);
sas_device_put(sas_device);
}
} }
/** /**
...@@ -635,13 +715,16 @@ mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, ...@@ -635,13 +715,16 @@ mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
return; return;
spin_lock_irqsave(&ioc->sas_device_lock, flags); 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_address);
sas_address); if (sas_device) {
if (sas_device) list_del_init(&sas_device->list);
list_del(&sas_device->list); sas_device_put(sas_device);
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (sas_device) if (sas_device) {
_scsih_remove_device(ioc, sas_device); _scsih_remove_device(ioc, sas_device);
sas_device_put(sas_device);
}
} }
/** /**
...@@ -676,6 +759,7 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, ...@@ -676,6 +759,7 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc,
sas_device->enclosure_level, sas_device->connector_name)); sas_device->enclosure_level, sas_device->connector_name));
spin_lock_irqsave(&ioc->sas_device_lock, flags); spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device_get(sas_device);
list_add_tail(&sas_device->list, &ioc->sas_device_list); list_add_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
...@@ -729,6 +813,7 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc, ...@@ -729,6 +813,7 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc,
sas_device->connector_name)); sas_device->connector_name));
spin_lock_irqsave(&ioc->sas_device_lock, flags); spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device_get(sas_device);
list_add_tail(&sas_device->list, &ioc->sas_device_init_list); list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
_scsih_determine_boot_device(ioc, sas_device, 0); _scsih_determine_boot_device(ioc, sas_device, 0);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
...@@ -1107,12 +1192,15 @@ scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) ...@@ -1107,12 +1192,15 @@ scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
goto not_sata; goto not_sata;
if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
goto not_sata; goto not_sata;
spin_lock_irqsave(&ioc->sas_device_lock, flags); spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
sas_device_priv_data->sas_target->sas_address); if (sas_device) {
if (sas_device && sas_device->device_info & if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
max_depth = MPT3SAS_SATA_QUEUE_DEPTH; max_depth = MPT3SAS_SATA_QUEUE_DEPTH;
sas_device_put(sas_device);
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
not_sata: not_sata:
...@@ -1171,12 +1259,13 @@ scsih_target_alloc(struct scsi_target *starget) ...@@ -1171,12 +1259,13 @@ scsih_target_alloc(struct scsi_target *starget)
/* sas/sata devices */ /* sas/sata devices */
spin_lock_irqsave(&ioc->sas_device_lock, flags); spin_lock_irqsave(&ioc->sas_device_lock, flags);
rphy = dev_to_rphy(starget->dev.parent); 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); rphy->identify.sas_address);
if (sas_device) { if (sas_device) {
sas_target_priv_data->handle = sas_device->handle; sas_target_priv_data->handle = sas_device->handle;
sas_target_priv_data->sas_address = sas_device->sas_address; sas_target_priv_data->sas_address = sas_device->sas_address;
sas_target_priv_data->sdev = sas_device;
sas_device->starget = starget; sas_device->starget = starget;
sas_device->id = starget->id; sas_device->id = starget->id;
sas_device->channel = starget->channel; sas_device->channel = starget->channel;
...@@ -1228,13 +1317,21 @@ scsih_target_destroy(struct scsi_target *starget) ...@@ -1228,13 +1317,21 @@ scsih_target_destroy(struct scsi_target *starget)
spin_lock_irqsave(&ioc->sas_device_lock, flags); spin_lock_irqsave(&ioc->sas_device_lock, flags);
rphy = dev_to_rphy(starget->dev.parent); rphy = dev_to_rphy(starget->dev.parent);
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
rphy->identify.sas_address);
if (sas_device && (sas_device->starget == starget) && if (sas_device && (sas_device->starget == starget) &&
(sas_device->id == starget->id) && (sas_device->id == starget->id) &&
(sas_device->channel == starget->channel)) (sas_device->channel == starget->channel))
sas_device->starget = NULL; 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); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
out: out:
...@@ -1290,7 +1387,7 @@ scsih_slave_alloc(struct scsi_device *sdev) ...@@ -1290,7 +1387,7 @@ scsih_slave_alloc(struct scsi_device *sdev)
if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
spin_lock_irqsave(&ioc->sas_device_lock, flags); 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); sas_target_priv_data->sas_address);
if (sas_device && (sas_device->starget == NULL)) { if (sas_device && (sas_device->starget == NULL)) {
sdev_printk(KERN_INFO, sdev, sdev_printk(KERN_INFO, sdev,
...@@ -1298,6 +1395,10 @@ scsih_slave_alloc(struct scsi_device *sdev) ...@@ -1298,6 +1395,10 @@ scsih_slave_alloc(struct scsi_device *sdev)
__func__, __LINE__); __func__, __LINE__);
sas_device->starget = starget; sas_device->starget = starget;
} }
if (sas_device)
sas_device_put(sas_device);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} }
...@@ -1332,10 +1433,13 @@ scsih_slave_destroy(struct scsi_device *sdev) ...@@ -1332,10 +1433,13 @@ scsih_slave_destroy(struct scsi_device *sdev)
if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
spin_lock_irqsave(&ioc->sas_device_lock, flags); spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, sas_device = __mpt3sas_get_sdev_from_target(ioc,
sas_target_priv_data->sas_address); sas_target_priv_data);
if (sas_device && !sas_target_priv_data->num_luns) if (sas_device && !sas_target_priv_data->num_luns)
sas_device->starget = NULL; sas_device->starget = NULL;
if (sas_device)
sas_device_put(sas_device);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} }
...@@ -1783,7 +1887,7 @@ scsih_slave_configure(struct scsi_device *sdev) ...@@ -1783,7 +1887,7 @@ scsih_slave_configure(struct scsi_device *sdev)
} }
spin_lock_irqsave(&ioc->sas_device_lock, flags); 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); sas_device_priv_data->sas_target->sas_address);
if (!sas_device) { if (!sas_device) {
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
...@@ -1823,6 +1927,7 @@ scsih_slave_configure(struct scsi_device *sdev) ...@@ -1823,6 +1927,7 @@ scsih_slave_configure(struct scsi_device *sdev)
ds, sas_device->enclosure_level, ds, sas_device->enclosure_level,
sas_device->connector_name); sas_device->connector_name);
sas_device_put(sas_device);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!ssp_target) if (!ssp_target)
...@@ -2222,8 +2327,7 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) ...@@ -2222,8 +2327,7 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
device_str, (unsigned long long)priv_target->sas_address); device_str, (unsigned long long)priv_target->sas_address);
} else { } else {
spin_lock_irqsave(&ioc->sas_device_lock, flags); spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, sas_device = __mpt3sas_get_sdev_from_target(ioc, priv_target);
priv_target->sas_address);
if (sas_device) { if (sas_device) {
if (priv_target->flags & if (priv_target->flags &
MPT_TARGET_FLAGS_RAID_COMPONENT) { MPT_TARGET_FLAGS_RAID_COMPONENT) {
...@@ -2249,6 +2353,8 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) ...@@ -2249,6 +2353,8 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
"enclosure level(0x%04x),connector name(%s)\n", "enclosure level(0x%04x),connector name(%s)\n",
sas_device->enclosure_level, sas_device->enclosure_level,
sas_device->connector_name); sas_device->connector_name);
sas_device_put(sas_device);
} }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} }
...@@ -2324,11 +2430,13 @@ scsih_dev_reset(struct scsi_cmnd *scmd) ...@@ -2324,11 +2430,13 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
{ {
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT3SAS_DEVICE *sas_device_priv_data; struct MPT3SAS_DEVICE *sas_device_priv_data;
struct _sas_device *sas_device; struct _sas_device *sas_device = NULL;
unsigned long flags;
u16 handle; u16 handle;
int r; int r;
struct scsi_target *starget = scmd->device->sdev_target;
struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
sdev_printk(KERN_INFO, scmd->device, sdev_printk(KERN_INFO, scmd->device,
"attempting device reset! scmd(%p)\n", scmd); "attempting device reset! scmd(%p)\n", scmd);
_scsih_tm_display_info(ioc, scmd); _scsih_tm_display_info(ioc, scmd);
...@@ -2347,12 +2455,10 @@ scsih_dev_reset(struct scsi_cmnd *scmd) ...@@ -2347,12 +2455,10 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
handle = 0; handle = 0;
if (sas_device_priv_data->sas_target->flags & if (sas_device_priv_data->sas_target->flags &
MPT_TARGET_FLAGS_RAID_COMPONENT) { MPT_TARGET_FLAGS_RAID_COMPONENT) {
spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt3sas_get_sdev_from_target(ioc,
sas_device = _scsih_sas_device_find_by_handle(ioc, target_priv_data);
sas_device_priv_data->sas_target->handle);
if (sas_device) if (sas_device)
handle = sas_device->volume_handle; handle = sas_device->volume_handle;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} else } else
handle = sas_device_priv_data->sas_target->handle; handle = sas_device_priv_data->sas_target->handle;
...@@ -2369,6 +2475,10 @@ scsih_dev_reset(struct scsi_cmnd *scmd) ...@@ -2369,6 +2475,10 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
out: out:
sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
if (sas_device)
sas_device_put(sas_device);
return r; return r;
} }
...@@ -2383,11 +2493,11 @@ scsih_target_reset(struct scsi_cmnd *scmd) ...@@ -2383,11 +2493,11 @@ scsih_target_reset(struct scsi_cmnd *scmd)
{ {
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT3SAS_DEVICE *sas_device_priv_data; struct MPT3SAS_DEVICE *sas_device_priv_data;
struct _sas_device *sas_device; struct _sas_device *sas_device = NULL;
unsigned long flags;
u16 handle; u16 handle;
int r; int r;
struct scsi_target *starget = scmd->device->sdev_target; 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", starget_printk(KERN_INFO, starget, "attempting target reset! scmd(%p)\n",
scmd); scmd);
...@@ -2407,12 +2517,10 @@ scsih_target_reset(struct scsi_cmnd *scmd) ...@@ -2407,12 +2517,10 @@ scsih_target_reset(struct scsi_cmnd *scmd)
handle = 0; handle = 0;
if (sas_device_priv_data->sas_target->flags & if (sas_device_priv_data->sas_target->flags &
MPT_TARGET_FLAGS_RAID_COMPONENT) { MPT_TARGET_FLAGS_RAID_COMPONENT) {
spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt3sas_get_sdev_from_target(ioc,
sas_device = _scsih_sas_device_find_by_handle(ioc, target_priv_data);
sas_device_priv_data->sas_target->handle);
if (sas_device) if (sas_device)
handle = sas_device->volume_handle; handle = sas_device->volume_handle;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} else } else
handle = sas_device_priv_data->sas_target->handle; handle = sas_device_priv_data->sas_target->handle;
...@@ -2429,6 +2537,10 @@ scsih_target_reset(struct scsi_cmnd *scmd) ...@@ -2429,6 +2537,10 @@ scsih_target_reset(struct scsi_cmnd *scmd)
out: out:
starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
if (sas_device)
sas_device_put(sas_device);
return r; return r;
} }
...@@ -2766,7 +2878,7 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -2766,7 +2878,7 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
struct scsi_device *sdev; struct scsi_device *sdev;
struct _sas_device *sas_device; 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) if (!sas_device)
return; return;
...@@ -2782,6 +2894,8 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -2782,6 +2894,8 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
continue; continue;
_scsih_internal_device_block(sdev, sas_device_priv_data); _scsih_internal_device_block(sdev, sas_device_priv_data);
} }
sas_device_put(sas_device);
} }
/** /**
...@@ -2810,12 +2924,13 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc, ...@@ -2810,12 +2924,13 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc,
if (mpt3sas_port->remote_identify.device_type == if (mpt3sas_port->remote_identify.device_type ==
SAS_END_DEVICE) { SAS_END_DEVICE) {
spin_lock_irqsave(&ioc->sas_device_lock, flags); spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = sas_device = __mpt3sas_get_sdev_by_addr(ioc,
mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
mpt3sas_port->remote_identify.sas_address); mpt3sas_port->remote_identify.sas_address);
if (sas_device) if (sas_device) {
set_bit(sas_device->handle, set_bit(sas_device->handle,
ioc->blocking_handles); ioc->blocking_handles);
sas_device_put(sas_device);
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} }
} }
...@@ -2883,7 +2998,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -2883,7 +2998,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{ {
Mpi2SCSITaskManagementRequest_t *mpi_request; Mpi2SCSITaskManagementRequest_t *mpi_request;
u16 smid; u16 smid;
struct _sas_device *sas_device; struct _sas_device *sas_device = NULL;
struct MPT3SAS_TARGET *sas_target_priv_data = NULL; struct MPT3SAS_TARGET *sas_target_priv_data = NULL;
u64 sas_address = 0; u64 sas_address = 0;
unsigned long flags; unsigned long flags;
...@@ -2916,7 +3031,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -2916,7 +3031,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
return; return;
spin_lock_irqsave(&ioc->sas_device_lock, flags); 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 && if (sas_device && sas_device->starget &&
sas_device->starget->hostdata) { sas_device->starget->hostdata) {
sas_target_priv_data = sas_device->starget->hostdata; sas_target_priv_data = sas_device->starget->hostdata;
...@@ -2950,14 +3065,14 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -2950,14 +3065,14 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
if (!smid) { if (!smid) {
delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
if (!delayed_tr) if (!delayed_tr)
return; goto out;
INIT_LIST_HEAD(&delayed_tr->list); INIT_LIST_HEAD(&delayed_tr->list);
delayed_tr->handle = handle; delayed_tr->handle = handle;
list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
dewtprintk(ioc, pr_info(MPT3SAS_FMT dewtprintk(ioc, pr_info(MPT3SAS_FMT
"DELAYED:tr:handle(0x%04x), (open)\n", "DELAYED:tr:handle(0x%04x), (open)\n",
ioc->name, handle)); ioc->name, handle));
return; goto out;
} }
dewtprintk(ioc, pr_info(MPT3SAS_FMT dewtprintk(ioc, pr_info(MPT3SAS_FMT
...@@ -2971,6 +3086,10 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -2971,6 +3086,10 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
mpt3sas_base_put_smid_hi_priority(ioc, smid); mpt3sas_base_put_smid_hi_priority(ioc, smid);
mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL); mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
out:
if (sas_device)
sas_device_put(sas_device);
} }
/** /**
...@@ -3839,7 +3958,6 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, ...@@ -3839,7 +3958,6 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
char *desc_scsi_state = ioc->tmp_string; char *desc_scsi_state = ioc->tmp_string;
u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
struct _sas_device *sas_device = NULL; struct _sas_device *sas_device = NULL;
unsigned long flags;
struct scsi_target *starget = scmd->device->sdev_target; struct scsi_target *starget = scmd->device->sdev_target;
struct MPT3SAS_TARGET *priv_target = starget->hostdata; struct MPT3SAS_TARGET *priv_target = starget->hostdata;
char *device_str = NULL; char *device_str = NULL;
...@@ -3970,9 +4088,7 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, ...@@ -3970,9 +4088,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, pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
device_str, (unsigned long long)priv_target->sas_address); device_str, (unsigned long long)priv_target->sas_address);
} else { } else {
spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt3sas_get_sdev_from_target(ioc, priv_target);
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
priv_target->sas_address);
if (sas_device) { if (sas_device) {
pr_warn(MPT3SAS_FMT pr_warn(MPT3SAS_FMT
"\tsas_address(0x%016llx), phy(%d)\n", "\tsas_address(0x%016llx), phy(%d)\n",
...@@ -3991,8 +4107,9 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, ...@@ -3991,8 +4107,9 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
" connector name( %s)\n", ioc->name, " connector name( %s)\n", ioc->name,
sas_device->enclosure_level, sas_device->enclosure_level,
sas_device->connector_name); sas_device->connector_name);
sas_device_put(sas_device);
} }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} }
pr_warn(MPT3SAS_FMT pr_warn(MPT3SAS_FMT
...@@ -4043,7 +4160,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -4043,7 +4160,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
Mpi2SepRequest_t mpi_request; Mpi2SepRequest_t mpi_request;
struct _sas_device *sas_device; 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) if (!sas_device)
return; return;
...@@ -4058,7 +4175,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -4058,7 +4175,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
&mpi_request)) != 0) { &mpi_request)) != 0) {
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name,
__FILE__, __LINE__, __func__); __FILE__, __LINE__, __func__);
return; goto out;
} }
sas_device->pfa_led_on = 1; sas_device->pfa_led_on = 1;
...@@ -4067,9 +4184,12 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -4067,9 +4184,12 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
"enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n",
ioc->name, le16_to_cpu(mpi_reply.IOCStatus), ioc->name, le16_to_cpu(mpi_reply.IOCStatus),
le32_to_cpu(mpi_reply.IOCLogInfo))); le32_to_cpu(mpi_reply.IOCLogInfo)));
return; goto out;
} }
out:
sas_device_put(sas_device);
} }
/** /**
* _scsih_turn_off_pfa_led - turn off Fault LED * _scsih_turn_off_pfa_led - turn off Fault LED
* @ioc: per adapter object * @ioc: per adapter object
...@@ -4108,6 +4228,7 @@ _scsih_turn_off_pfa_led(struct MPT3SAS_ADAPTER *ioc, ...@@ -4108,6 +4228,7 @@ _scsih_turn_off_pfa_led(struct MPT3SAS_ADAPTER *ioc,
return; return;
} }
} }
/** /**
* _scsih_send_event_to_turn_on_pfa_led - fire delayed event * _scsih_send_event_to_turn_on_pfa_led - fire delayed event
* @ioc: per adapter object * @ioc: per adapter object
...@@ -4151,19 +4272,17 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -4151,19 +4272,17 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
/* only handle non-raid devices */ /* only handle non-raid devices */
spin_lock_irqsave(&ioc->sas_device_lock, flags); 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) { if (!sas_device)
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); goto out_unlock;
return;
}
starget = sas_device->starget; starget = sas_device->starget;
sas_target_priv_data = starget->hostdata; sas_target_priv_data = starget->hostdata;
if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) || if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) { ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)))
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); goto out_unlock;
return;
}
if (sas_device->enclosure_handle != 0) if (sas_device->enclosure_handle != 0)
starget_printk(KERN_INFO, starget, "predicted fault, " starget_printk(KERN_INFO, starget, "predicted fault, "
"enclosure logical id(0x%016llx), slot(%d)\n", "enclosure logical id(0x%016llx), slot(%d)\n",
...@@ -4186,7 +4305,7 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -4186,7 +4305,7 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
if (!event_reply) { if (!event_reply) {
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__); ioc->name, __FILE__, __LINE__, __func__);
return; goto out;
} }
event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
...@@ -4203,6 +4322,14 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) ...@@ -4203,6 +4322,14 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address); event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
mpt3sas_ctl_add_to_event_log(ioc, event_reply); mpt3sas_ctl_add_to_event_log(ioc, event_reply);
kfree(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;
} }
/** /**
...@@ -4977,13 +5104,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, ...@@ -4977,13 +5104,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_device_lock, flags); spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_address = le64_to_cpu(sas_device_pg0.SASAddress); 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); sas_address);
if (!sas_device) { if (!sas_device)
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); goto out_unlock;
return;
}
if (unlikely(sas_device->handle != handle)) { if (unlikely(sas_device->handle != handle)) {
starget = sas_device->starget; starget = sas_device->starget;
...@@ -5011,20 +5136,25 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, ...@@ -5011,20 +5136,25 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
pr_err(MPT3SAS_FMT pr_err(MPT3SAS_FMT
"device is not present handle(0x%04x), flags!!!\n", "device is not present handle(0x%04x), flags!!!\n",
ioc->name, handle); ioc->name, handle);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); goto out_unlock;
return;
} }
/* check if there were any issues with discovery */ /* check if there were any issues with discovery */
if (_scsih_check_access_status(ioc, sas_address, handle, 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); goto out_unlock;
return;
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
_scsih_ublock_io_device(ioc, sas_address); _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);
} }
/** /**
...@@ -5049,7 +5179,6 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, ...@@ -5049,7 +5179,6 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
u32 ioc_status; u32 ioc_status;
u64 sas_address; u64 sas_address;
u32 device_info; u32 device_info;
unsigned long flags;
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
...@@ -5085,13 +5214,12 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, ...@@ -5085,13 +5214,12 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
sas_device_pg0.AccessStatus)) sas_device_pg0.AccessStatus))
return -1; return -1;
spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt3sas_get_sdev_by_addr(ioc,
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
sas_address); sas_address);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (sas_device) {
sas_device_put(sas_device);
if (sas_device)
return -1; return -1;
}
sas_device = kzalloc(sizeof(struct _sas_device), sas_device = kzalloc(sizeof(struct _sas_device),
GFP_KERNEL); GFP_KERNEL);
...@@ -5101,6 +5229,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, ...@@ -5101,6 +5229,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
return 0; return 0;
} }
kref_init(&sas_device->refcount);
sas_device->handle = handle; sas_device->handle = handle;
if (_scsih_get_sas_address(ioc, if (_scsih_get_sas_address(ioc,
le16_to_cpu(sas_device_pg0.ParentDevHandle), le16_to_cpu(sas_device_pg0.ParentDevHandle),
...@@ -5144,6 +5273,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, ...@@ -5144,6 +5273,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
else else
_scsih_sas_device_add(ioc, sas_device); _scsih_sas_device_add(ioc, sas_device);
sas_device_put(sas_device);
return 0; return 0;
} }
...@@ -5228,8 +5358,6 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, ...@@ -5228,8 +5358,6 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc,
"%s: exit: enclosure level(0x%04x), connector name(%s)\n", "%s: exit: enclosure level(0x%04x), connector name(%s)\n",
ioc->name, __func__, sas_device->enclosure_level, ioc->name, __func__, sas_device->enclosure_level,
sas_device->connector_name)); sas_device->connector_name));
kfree(sas_device);
} }
/** /**
...@@ -5546,26 +5674,28 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, ...@@ -5546,26 +5674,28 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_device_lock, flags); spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_address = le64_to_cpu(event_data->SASAddress); sas_address = le64_to_cpu(event_data->SASAddress);
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, sas_device = __mpt3sas_get_sdev_by_addr(ioc,
sas_address); sas_address);
if (!sas_device || !sas_device->starget) { if (!sas_device || !sas_device->starget)
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); goto out;
return;
}
target_priv_data = sas_device->starget->hostdata; target_priv_data = sas_device->starget->hostdata;
if (!target_priv_data) { if (!target_priv_data)
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); goto out;
return;
}
if (event_data->ReasonCode == if (event_data->ReasonCode ==
MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
target_priv_data->tm_busy = 1; target_priv_data->tm_busy = 1;
else else
target_priv_data->tm_busy = 0; target_priv_data->tm_busy = 0;
out:
if (sas_device)
sas_device_put(sas_device);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} }
/** /**
...@@ -6044,7 +6174,7 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc, ...@@ -6044,7 +6174,7 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc,
u16 handle = le16_to_cpu(element->PhysDiskDevHandle); u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
spin_lock_irqsave(&ioc->sas_device_lock, flags); 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) { if (sas_device) {
sas_device->volume_handle = 0; sas_device->volume_handle = 0;
sas_device->volume_wwid = 0; sas_device->volume_wwid = 0;
...@@ -6063,6 +6193,8 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc, ...@@ -6063,6 +6193,8 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc,
/* exposing raid component */ /* exposing raid component */
if (starget) if (starget)
starget_for_each_device(starget, NULL, _scsih_reprobe_lun); starget_for_each_device(starget, NULL, _scsih_reprobe_lun);
sas_device_put(sas_device);
} }
/** /**
...@@ -6091,7 +6223,7 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc, ...@@ -6091,7 +6223,7 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc,
&volume_wwid); &volume_wwid);
spin_lock_irqsave(&ioc->sas_device_lock, flags); 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) { if (sas_device) {
set_bit(handle, ioc->pd_handles); set_bit(handle, ioc->pd_handles);
if (sas_device->starget && sas_device->starget->hostdata) { if (sas_device->starget && sas_device->starget->hostdata) {
...@@ -6113,6 +6245,8 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc, ...@@ -6113,6 +6245,8 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc,
#endif #endif
if (starget) if (starget)
starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun); starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
sas_device_put(sas_device);
} }
/** /**
...@@ -6145,7 +6279,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, ...@@ -6145,7 +6279,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
Mpi2EventIrConfigElement_t *element) Mpi2EventIrConfigElement_t *element)
{ {
struct _sas_device *sas_device; struct _sas_device *sas_device;
unsigned long flags;
u16 handle = le16_to_cpu(element->PhysDiskDevHandle); u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Mpi2ConfigReply_t mpi_reply; Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0; Mpi2SasDevicePage0_t sas_device_pg0;
...@@ -6155,13 +6288,12 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, ...@@ -6155,13 +6288,12 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
set_bit(handle, ioc->pd_handles); set_bit(handle, ioc->pd_handles);
spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (sas_device) { if (sas_device) {
#ifndef SCSI_MPT2SAS #ifndef SCSI_MPT2SAS
_scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum);
#endif #endif
sas_device_put(sas_device);
return; return;
} }
...@@ -6443,7 +6575,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, ...@@ -6443,7 +6575,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
u16 handle, parent_handle; u16 handle, parent_handle;
u32 state; u32 state;
struct _sas_device *sas_device; struct _sas_device *sas_device;
unsigned long flags;
Mpi2ConfigReply_t mpi_reply; Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0; Mpi2SasDevicePage0_t sas_device_pg0;
u32 ioc_status; u32 ioc_status;
...@@ -6475,12 +6606,12 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, ...@@ -6475,12 +6606,12 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
if (!ioc->is_warpdrive) if (!ioc->is_warpdrive)
set_bit(handle, ioc->pd_handles); 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; return;
}
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply,
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
...@@ -6962,6 +7093,7 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) ...@@ -6962,6 +7093,7 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
struct _raid_device *raid_device, *raid_device_next; struct _raid_device *raid_device, *raid_device_next;
struct list_head tmp_list; struct list_head tmp_list;
unsigned long flags; unsigned long flags;
LIST_HEAD(head);
pr_info(MPT3SAS_FMT "removing unresponding devices: start\n", pr_info(MPT3SAS_FMT "removing unresponding devices: start\n",
ioc->name); ioc->name);
...@@ -6969,14 +7101,28 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) ...@@ -6969,14 +7101,28 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
/* removing unresponding end devices */ /* removing unresponding end devices */
pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n", pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n",
ioc->name); 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, list_for_each_entry_safe(sas_device, sas_device_next,
&ioc->sas_device_list, list) { &ioc->sas_device_list, list) {
if (!sas_device->responding) if (!sas_device->responding)
mpt3sas_device_remove_by_sas_address(ioc, list_move_tail(&sas_device->list, &head);
sas_device->sas_address);
else else
sas_device->responding = 0; 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 */ /* removing unresponding volumes */
if (ioc->ir_firmware) { if (ioc->ir_firmware) {
...@@ -7130,11 +7276,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ...@@ -7130,11 +7276,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
} }
phys_disk_num = pd_pg0.PhysDiskNum; phys_disk_num = pd_pg0.PhysDiskNum;
handle = le16_to_cpu(pd_pg0.DevHandle); handle = le16_to_cpu(pd_pg0.DevHandle);
spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle); if (sas_device) {
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); sas_device_put(sas_device);
if (sas_device)
continue; continue;
}
if (mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, if (mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply,
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
handle) != 0) handle) != 0)
...@@ -7255,12 +7401,12 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ...@@ -7255,12 +7401,12 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
if (!(_scsih_is_end_device( if (!(_scsih_is_end_device(
le32_to_cpu(sas_device_pg0.DeviceInfo)))) le32_to_cpu(sas_device_pg0.DeviceInfo))))
continue; continue;
spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = mpt3sas_get_sdev_by_addr(ioc,
sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
le64_to_cpu(sas_device_pg0.SASAddress)); 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; continue;
}
parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) {
pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \ pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \
...@@ -7907,6 +8053,48 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc) ...@@ -7907,6 +8053,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 * _scsih_probe_sas - reporting sas devices to sas transport
* @ioc: per adapter object * @ioc: per adapter object
...@@ -7916,20 +8104,16 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc) ...@@ -7916,20 +8104,16 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc)
static void static void
_scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
{ {
struct _sas_device *sas_device, *next; struct _sas_device *sas_device;
unsigned long flags;
/* SAS Device List */
list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
list) {
if (ioc->hide_drives) if (ioc->hide_drives)
return; return;
while ((sas_device = get_next_sas_device(ioc))) {
if (!mpt3sas_transport_port_add(ioc, sas_device->handle, if (!mpt3sas_transport_port_add(ioc, sas_device->handle,
sas_device->sas_address_parent)) { sas_device->sas_address_parent)) {
list_del(&sas_device->list); _scsih_sas_device_remove(ioc, sas_device);
kfree(sas_device); sas_device_put(sas_device);
continue; continue;
} else if (!sas_device->starget) { } else if (!sas_device->starget) {
/* /*
...@@ -7942,15 +8126,13 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) ...@@ -7942,15 +8126,13 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
mpt3sas_transport_port_remove(ioc, mpt3sas_transport_port_remove(ioc,
sas_device->sas_address, sas_device->sas_address,
sas_device->sas_address_parent); sas_device->sas_address_parent);
list_del(&sas_device->list); _scsih_sas_device_remove(ioc, sas_device);
kfree(sas_device); sas_device_put(sas_device);
continue; continue;
} }
} }
sas_device_make_active(ioc, sas_device);
spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device_put(sas_device);
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} }
} }
......
...@@ -734,7 +734,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, ...@@ -734,7 +734,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
rphy->identify = mpt3sas_port->remote_identify; rphy->identify = mpt3sas_port->remote_identify;
if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
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); mpt3sas_port->remote_identify.sas_address);
if (!sas_device) { if (!sas_device) {
dfailprintk(ioc, printk(MPT3SAS_FMT dfailprintk(ioc, printk(MPT3SAS_FMT
...@@ -750,8 +750,10 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, ...@@ -750,8 +750,10 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
ioc->name, __FILE__, __LINE__, __func__); 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->pend_sas_rphy_add = 0;
sas_device_put(sas_device);
}
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &rphy->dev, dev_printk(KERN_INFO, &rphy->dev,
...@@ -1324,15 +1326,17 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) ...@@ -1324,15 +1326,17 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
int rc; int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags); 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); rphy->identify.sas_address);
if (sas_device) { if (sas_device) {
*identifier = sas_device->enclosure_logical_id; *identifier = sas_device->enclosure_logical_id;
rc = 0; rc = 0;
sas_device_put(sas_device);
} else { } else {
*identifier = 0; *identifier = 0;
rc = -ENXIO; rc = -ENXIO;
} }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return rc; return rc;
} }
...@@ -1352,12 +1356,14 @@ _transport_get_bay_identifier(struct sas_rphy *rphy) ...@@ -1352,12 +1356,14 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
int rc; int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags); 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); rphy->identify.sas_address);
if (sas_device) if (sas_device) {
rc = sas_device->slot; rc = sas_device->slot;
else sas_device_put(sas_device);
} else {
rc = -ENXIO; rc = -ENXIO;
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return rc; return rc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment