scsi: mpt3sas: Add nvme device support in slave alloc, target alloc and probe

1) Added support for probing pcie device and adding NVMe drives to SML
and driver's internal list pcie_device_list.

2) Added support for determing NVMe as boot device.

3) Added nvme device support for call back functions scan_finished
target_alloc,slave_alloc,target destroy and slave destroy.

 a) During scan, pcie devices are probed and added to SML to drivers
internal list.

 b) target_alloc & slave alloc API's allocates resources for
(MPT3SAS_TARGET & MPT3SAS_DEVICE) private datas and holds information
like handle, target_id etc.

 c) slave_destroy & target_destroy are called when driver unregisters
or removes device. Also frees allocated resources and info.

Signed-off-by: Chaitra P B <chaitra.basappa@broadcom.com>
Signed-off-by: Suganath Prabu S <suganath-prabu.subramani@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Suganath Prabu Subramani 2017-10-31 18:02:27 +05:30 committed by Martin K. Petersen
parent b5c5d0adf7
commit d88e1eaba6
2 changed files with 506 additions and 34 deletions

View File

@ -161,6 +161,7 @@
#define MPT_TARGET_FLAGS_VOLUME 0x02
#define MPT_TARGET_FLAGS_DELETED 0x04
#define MPT_TARGET_FASTPATH_IO 0x08
#define MPT_TARGET_FLAGS_PCIE_DEVICE 0x10
#define SAS2_PCI_DEVICE_B0_REVISION (0x01)
#define SAS3_PCI_DEVICE_C0_REVISION (0x02)
@ -359,7 +360,8 @@ 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
* @sas_dev: The sas_device associated with this target
* @pcie_dev: The pcie device associated with this target
*/
struct MPT3SAS_TARGET {
struct scsi_target *starget;
@ -370,7 +372,8 @@ struct MPT3SAS_TARGET {
u32 flags;
u8 deleted;
u8 tm_busy;
struct _sas_device *sdev;
struct _sas_device *sas_dev;
struct _pcie_device *pcie_dev;
};
@ -514,6 +517,89 @@ static inline void sas_device_put(struct _sas_device *s)
kref_put(&s->refcount, sas_device_free);
}
/*
* struct _pcie_device - attached PCIe device information
* @list: pcie device list
* @starget: starget object
* @wwid: device WWID
* @handle: device handle
* @device_info: bitfield provides detailed info about the device
* @id: target id
* @channel: target channel
* @slot: slot number
* @port_num: port number
* @responding: used in _scsih_pcie_device_mark_responding
* @fast_path: fast path feature enable bit
* @nvme_mdts: MaximumDataTransferSize from PCIe Device Page 2 for
* NVMe device only
* @enclosure_handle: enclosure handle
* @enclosure_logical_id: enclosure logical identifier
* @enclosure_level: The level of device's enclosure from the controller
* @connector_name: ASCII value of the Connector's name
* @serial_number: pointer of serial number string allocated runtime
* @refcount: reference count for deletion
*/
struct _pcie_device {
struct list_head list;
struct scsi_target *starget;
u64 wwid;
u16 handle;
u32 device_info;
int id;
int channel;
u16 slot;
u8 port_num;
u8 responding;
u8 fast_path;
u32 nvme_mdts;
u16 enclosure_handle;
u64 enclosure_logical_id;
u8 enclosure_level;
u8 connector_name[4];
u8 *serial_number;
struct kref refcount;
};
/**
* pcie_device_get - Increment the pcie device reference count
*
* @p: pcie_device object
*
* When ever this function called it will increment the
* reference count of the pcie device for which this function called.
*
*/
static inline void pcie_device_get(struct _pcie_device *p)
{
kref_get(&p->refcount);
}
/**
* pcie_device_free - Release the pcie device object
* @r - kref object
*
* Free's the pcie device object. It will be called when reference count
* reaches to zero.
*/
static inline void pcie_device_free(struct kref *r)
{
kfree(container_of(r, struct _pcie_device, refcount));
}
/**
* pcie_device_put - Decrement the pcie device reference count
*
* @p: pcie_device object
*
* When ever this function called it will decrement the
* reference count of the pcie device for which this function called.
*
* When refernce count reaches to Zero, this will call pcie_device_free to the
* pcie_device object.
*/
static inline void pcie_device_put(struct _pcie_device *p)
{
kref_put(&p->refcount, pcie_device_free);
}
/**
* struct _raid_device - raid volume link list
* @list: sas device list
@ -562,12 +648,13 @@ struct _raid_device {
/**
* struct _boot_device - boot device info
* @is_raid: flag to indicate whether this is volume
* @device: holds pointer for either struct _sas_device or
* struct _raid_device
*
* @channel: sas, raid, or pcie channel
* @device: holds pointer for struct _sas_device, struct _raid_device or
* struct _pcie_device
*/
struct _boot_device {
u8 is_raid;
int channel;
void *device;
};
@ -831,6 +918,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @bars: bitmask of BAR's that must be configured
* @mask_interrupts: ignore interrupt
* @dma_mask: used to set the consistent dma mask
* @pci_access_mutex: Mutex to synchronize ioctl, sysfs show path and
* pci resource handling
* @fault_reset_work_q_name: fw fault work queue
* @fault_reset_work_q: ""
* @fault_reset_work: ""
@ -894,9 +983,13 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @sas_device_list: sas device object list
* @sas_device_init_list: sas device object list (used only at init time)
* @sas_device_lock:
* @pcie_device_list: pcie device object list
* @pcie_device_init_list: pcie device object list (used only at init time)
* @pcie_device_lock:
* @io_missing_delay: time for IO completed by fw when PDR enabled
* @device_missing_delay: time for device missing by fw when PDR enabled
* @sas_id : used for setting volume target IDs
* @pcie_target_id: used for setting pcie target IDs
* @blocking_handles: bitmask used to identify which devices need blocking
* @pd_handles : bitmask for PD handles
* @pd_handles_sz : size of pd_handle bitmask
@ -1092,11 +1185,16 @@ struct MPT3SAS_ADAPTER {
struct list_head sas_device_list;
struct list_head sas_device_init_list;
spinlock_t sas_device_lock;
struct list_head pcie_device_list;
struct list_head pcie_device_init_list;
spinlock_t pcie_device_lock;
struct list_head raid_device_list;
spinlock_t raid_device_lock;
u8 io_missing_delay;
u16 device_missing_delay;
int sas_id;
int pcie_target_id;
void *blocking_handles;
void *pd_handles;

View File

@ -60,6 +60,9 @@
#include "mpt3sas_base.h"
#define RAID_CHANNEL 1
#define PCIE_CHANNEL 2
/* forward proto's */
static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc,
struct _sas_node *sas_expander);
@ -442,21 +445,22 @@ _scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle,
/**
* _scsih_determine_boot_device - determine boot device.
* @ioc: per adapter object
* @device: either sas_device or raid_device object
* @is_raid: [flag] 1 = raid object, 0 = sas object
* @device: sas_device or pcie_device object
* @channel: SAS or PCIe channel
*
* Determines whether this device should be first reported device to
* to scsi-ml or sas transport, this purpose is for persistent boot device.
* There are primary, alternate, and current entries in bios page 2. The order
* priority is primary, alternate, then current. This routine saves
* the corresponding device object and is_raid flag in the ioc object.
* the corresponding device object.
* The saved data to be used later in _scsih_probe_boot_devices().
*/
static void
_scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
void *device, u8 is_raid)
_scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, void *device,
u32 channel)
{
struct _sas_device *sas_device;
struct _pcie_device *pcie_device;
struct _raid_device *raid_device;
u64 sas_address;
u64 device_name;
@ -471,18 +475,24 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
if (!ioc->bios_pg3.BiosVersion)
return;
if (!is_raid) {
sas_device = device;
sas_address = sas_device->sas_address;
device_name = sas_device->device_name;
enclosure_logical_id = sas_device->enclosure_logical_id;
slot = sas_device->slot;
} else {
if (channel == RAID_CHANNEL) {
raid_device = device;
sas_address = raid_device->wwid;
device_name = 0;
enclosure_logical_id = 0;
slot = 0;
} else if (channel == PCIE_CHANNEL) {
pcie_device = device;
sas_address = pcie_device->wwid;
device_name = 0;
enclosure_logical_id = 0;
slot = 0;
} else {
sas_device = device;
sas_address = sas_device->sas_address;
device_name = sas_device->device_name;
enclosure_logical_id = sas_device->enclosure_logical_id;
slot = sas_device->slot;
}
if (!ioc->req_boot_device.device) {
@ -496,7 +506,7 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
ioc->name, __func__,
(unsigned long long)sas_address));
ioc->req_boot_device.device = device;
ioc->req_boot_device.is_raid = is_raid;
ioc->req_boot_device.channel = channel;
}
}
@ -511,7 +521,7 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
ioc->name, __func__,
(unsigned long long)sas_address));
ioc->req_alt_boot_device.device = device;
ioc->req_alt_boot_device.is_raid = is_raid;
ioc->req_alt_boot_device.channel = channel;
}
}
@ -526,7 +536,7 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
ioc->name, __func__,
(unsigned long long)sas_address));
ioc->current_boot_device.device = device;
ioc->current_boot_device.is_raid = is_raid;
ioc->current_boot_device.channel = channel;
}
}
}
@ -539,7 +549,7 @@ __mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc,
assert_spin_locked(&ioc->sas_device_lock);
ret = tgt_priv->sdev;
ret = tgt_priv->sas_dev;
if (ret)
sas_device_get(ret);
@ -560,6 +570,44 @@ mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc,
return ret;
}
static struct _pcie_device *
__mpt3sas_get_pdev_from_target(struct MPT3SAS_ADAPTER *ioc,
struct MPT3SAS_TARGET *tgt_priv)
{
struct _pcie_device *ret;
assert_spin_locked(&ioc->pcie_device_lock);
ret = tgt_priv->pcie_dev;
if (ret)
pcie_device_get(ret);
return ret;
}
/**
* mpt3sas_get_pdev_from_target - pcie device search
* @ioc: per adapter object
* @tgt_priv: starget private object
*
* Context: This function will acquire ioc->pcie_device_lock and will release
* before returning the pcie_device object.
*
* This searches for pcie_device from target, then return pcie_device object.
*/
struct _pcie_device *
mpt3sas_get_pdev_from_target(struct MPT3SAS_ADAPTER *ioc,
struct MPT3SAS_TARGET *tgt_priv)
{
struct _pcie_device *ret;
unsigned long flags;
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
ret = __mpt3sas_get_pdev_from_target(ioc, tgt_priv);
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
return ret;
}
struct _sas_device *
__mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc,
@ -889,6 +937,146 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
struct _pcie_device *
__mpt3sas_get_pdev_by_wwid(struct MPT3SAS_ADAPTER *ioc, u64 wwid)
{
struct _pcie_device *pcie_device;
assert_spin_locked(&ioc->pcie_device_lock);
list_for_each_entry(pcie_device, &ioc->pcie_device_list, list)
if (pcie_device->wwid == wwid)
goto found_device;
list_for_each_entry(pcie_device, &ioc->pcie_device_init_list, list)
if (pcie_device->wwid == wwid)
goto found_device;
return NULL;
found_device:
pcie_device_get(pcie_device);
return pcie_device;
}
/**
* mpt3sas_get_pdev_by_wwid - pcie device search
* @ioc: per adapter object
* @wwid: wwid
*
* Context: This function will acquire ioc->pcie_device_lock and will release
* before returning the pcie_device object.
*
* This searches for pcie_device based on wwid, then return pcie_device object.
*/
struct _pcie_device *
mpt3sas_get_pdev_by_wwid(struct MPT3SAS_ADAPTER *ioc, u64 wwid)
{
struct _pcie_device *pcie_device;
unsigned long flags;
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device = __mpt3sas_get_pdev_by_wwid(ioc, wwid);
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
return pcie_device;
}
struct _pcie_device *
__mpt3sas_get_pdev_by_idchannel(struct MPT3SAS_ADAPTER *ioc, int id,
int channel)
{
struct _pcie_device *pcie_device;
assert_spin_locked(&ioc->pcie_device_lock);
list_for_each_entry(pcie_device, &ioc->pcie_device_list, list)
if (pcie_device->id == id && pcie_device->channel == channel)
goto found_device;
list_for_each_entry(pcie_device, &ioc->pcie_device_init_list, list)
if (pcie_device->id == id && pcie_device->channel == channel)
goto found_device;
return NULL;
found_device:
pcie_device_get(pcie_device);
return pcie_device;
}
/**
* mpt3sas_get_pdev_by_idchannel - pcie device search
* @ioc: per adapter object
* @id: Target ID
* @channel: Channel ID
*
* Context: This function will acquire ioc->pcie_device_lock and will release
* before returning the pcie_device object.
*
* This searches for pcie_device based on id and channel, then return
* pcie_device object.
*/
struct _pcie_device *
mpt3sas_get_pdev_by_idchannel(struct MPT3SAS_ADAPTER *ioc, int id, int channel)
{
struct _pcie_device *pcie_device;
unsigned long flags;
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device = __mpt3sas_get_pdev_by_idchannel(ioc, id, channel);
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
return pcie_device;
}
/**
* _scsih_pcie_device_remove - remove pcie_device from list.
* @ioc: per adapter object
* @pcie_device: the pcie_device object
* Context: This function will acquire ioc->pcie_device_lock.
*
* If pcie_device is on the list, remove it and decrement its reference count.
*/
static void
_scsih_pcie_device_remove(struct MPT3SAS_ADAPTER *ioc,
struct _pcie_device *pcie_device)
{
unsigned long flags;
int was_on_pcie_device_list = 0;
if (!pcie_device)
return;
pr_info(MPT3SAS_FMT
"removing handle(0x%04x), wwid(0x%016llx)\n",
ioc->name, pcie_device->handle,
(unsigned long long) pcie_device->wwid);
if (pcie_device->enclosure_handle != 0)
pr_info(MPT3SAS_FMT
"removing enclosure logical id(0x%016llx), slot(%d)\n",
ioc->name,
(unsigned long long)pcie_device->enclosure_logical_id,
pcie_device->slot);
if (pcie_device->connector_name[0] != '\0')
pr_info(MPT3SAS_FMT
"removing enclosure level(0x%04x), connector name( %s)\n",
ioc->name, pcie_device->enclosure_level,
pcie_device->connector_name);
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
if (!list_empty(&pcie_device->list)) {
list_del_init(&pcie_device->list);
was_on_pcie_device_list = 1;
}
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
if (was_on_pcie_device_list) {
kfree(pcie_device->serial_number);
pcie_device_put(pcie_device);
}
}
/**
* _scsih_raid_device_find_by_id - raid device search
* @ioc: per adapter object
@ -1316,6 +1504,7 @@ scsih_target_alloc(struct scsi_target *starget)
struct MPT3SAS_TARGET *sas_target_priv_data;
struct _sas_device *sas_device;
struct _raid_device *raid_device;
struct _pcie_device *pcie_device;
unsigned long flags;
struct sas_rphy *rphy;
@ -1345,6 +1534,28 @@ scsih_target_alloc(struct scsi_target *starget)
return 0;
}
/* PCIe devices */
if (starget->channel == PCIE_CHANNEL) {
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device = __mpt3sas_get_pdev_by_idchannel(ioc, starget->id,
starget->channel);
if (pcie_device) {
sas_target_priv_data->handle = pcie_device->handle;
sas_target_priv_data->sas_address = pcie_device->wwid;
sas_target_priv_data->pcie_dev = pcie_device;
pcie_device->starget = starget;
pcie_device->id = starget->id;
pcie_device->channel = starget->channel;
sas_target_priv_data->flags |=
MPT_TARGET_FLAGS_PCIE_DEVICE;
if (pcie_device->fast_path)
sas_target_priv_data->flags |=
MPT_TARGET_FASTPATH_IO;
}
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
return 0;
}
/* sas/sata devices */
spin_lock_irqsave(&ioc->sas_device_lock, flags);
rphy = dev_to_rphy(starget->dev.parent);
@ -1354,7 +1565,7 @@ scsih_target_alloc(struct scsi_target *starget)
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_target_priv_data->sas_dev = sas_device;
sas_device->starget = starget;
sas_device->id = starget->id;
sas_device->channel = starget->channel;
@ -1362,7 +1573,8 @@ scsih_target_alloc(struct scsi_target *starget)
sas_target_priv_data->flags |=
MPT_TARGET_FLAGS_RAID_COMPONENT;
if (sas_device->fast_path)
sas_target_priv_data->flags |= MPT_TARGET_FASTPATH_IO;
sas_target_priv_data->flags |=
MPT_TARGET_FASTPATH_IO;
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@ -1383,7 +1595,9 @@ scsih_target_destroy(struct scsi_target *starget)
struct MPT3SAS_TARGET *sas_target_priv_data;
struct _sas_device *sas_device;
struct _raid_device *raid_device;
struct _pcie_device *pcie_device;
unsigned long flags;
struct sas_rphy *rphy;
sas_target_priv_data = starget->hostdata;
if (!sas_target_priv_data)
@ -1401,7 +1615,29 @@ scsih_target_destroy(struct scsi_target *starget)
goto out;
}
if (starget->channel == PCIE_CHANNEL) {
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device = __mpt3sas_get_pdev_from_target(ioc,
sas_target_priv_data);
if (pcie_device && (pcie_device->starget == starget) &&
(pcie_device->id == starget->id) &&
(pcie_device->channel == starget->channel))
pcie_device->starget = NULL;
if (pcie_device) {
/*
* Corresponding get() is in _scsih_target_alloc()
*/
sas_target_priv_data->pcie_dev = NULL;
pcie_device_put(pcie_device);
pcie_device_put(pcie_device);
}
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
goto out;
}
spin_lock_irqsave(&ioc->sas_device_lock, flags);
rphy = dev_to_rphy(starget->dev.parent);
sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
if (sas_device && (sas_device->starget == starget) &&
(sas_device->id == starget->id) &&
@ -1412,7 +1648,7 @@ scsih_target_destroy(struct scsi_target *starget)
/*
* Corresponding get() is in _scsih_target_alloc()
*/
sas_target_priv_data->sdev = NULL;
sas_target_priv_data->sas_dev = NULL;
sas_device_put(sas_device);
sas_device_put(sas_device);
@ -1441,6 +1677,7 @@ scsih_slave_alloc(struct scsi_device *sdev)
struct scsi_target *starget;
struct _raid_device *raid_device;
struct _sas_device *sas_device;
struct _pcie_device *pcie_device;
unsigned long flags;
sas_device_priv_data = kzalloc(sizeof(*sas_device_priv_data),
@ -1469,8 +1706,22 @@ scsih_slave_alloc(struct scsi_device *sdev)
raid_device->sdev = sdev; /* raid is single lun */
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
}
if (starget->channel == PCIE_CHANNEL) {
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device = __mpt3sas_get_pdev_by_wwid(ioc,
sas_target_priv_data->sas_address);
if (pcie_device && (pcie_device->starget == NULL)) {
sdev_printk(KERN_INFO, sdev,
"%s : pcie_device->starget set to starget @ %d\n",
__func__, __LINE__);
pcie_device->starget = starget;
}
if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
if (pcie_device)
pcie_device_put(pcie_device);
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
} else if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = __mpt3sas_get_sdev_by_addr(ioc,
sas_target_priv_data->sas_address);
@ -1504,6 +1755,7 @@ scsih_slave_destroy(struct scsi_device *sdev)
struct Scsi_Host *shost;
struct MPT3SAS_ADAPTER *ioc;
struct _sas_device *sas_device;
struct _pcie_device *pcie_device;
unsigned long flags;
if (!sdev->hostdata)
@ -1516,7 +1768,19 @@ scsih_slave_destroy(struct scsi_device *sdev)
shost = dev_to_shost(&starget->dev);
ioc = shost_priv(shost);
if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_PCIE_DEVICE) {
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device = __mpt3sas_get_pdev_from_target(ioc,
sas_target_priv_data);
if (pcie_device && !sas_target_priv_data->num_luns)
pcie_device->starget = NULL;
if (pcie_device)
pcie_device_put(pcie_device);
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
} else if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = __mpt3sas_get_sdev_from_target(ioc,
sas_target_priv_data);
@ -8398,42 +8662,52 @@ scsih_shutdown(struct pci_dev *pdev)
static void
_scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc)
{
u8 is_raid;
u32 channel;
void *device;
struct _sas_device *sas_device;
struct _raid_device *raid_device;
struct _pcie_device *pcie_device;
u16 handle;
u64 sas_address_parent;
u64 sas_address;
unsigned long flags;
int rc;
int tid;
/* no Bios, return immediately */
if (!ioc->bios_pg3.BiosVersion)
return;
device = NULL;
is_raid = 0;
if (ioc->req_boot_device.device) {
device = ioc->req_boot_device.device;
is_raid = ioc->req_boot_device.is_raid;
channel = ioc->req_boot_device.channel;
} else if (ioc->req_alt_boot_device.device) {
device = ioc->req_alt_boot_device.device;
is_raid = ioc->req_alt_boot_device.is_raid;
channel = ioc->req_alt_boot_device.channel;
} else if (ioc->current_boot_device.device) {
device = ioc->current_boot_device.device;
is_raid = ioc->current_boot_device.is_raid;
channel = ioc->current_boot_device.channel;
}
if (!device)
return;
if (is_raid) {
if (channel == RAID_CHANNEL) {
raid_device = device;
rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
raid_device->id, 0);
if (rc)
_scsih_raid_device_remove(ioc, raid_device);
} else if (channel == PCIE_CHANNEL) {
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device = device;
tid = pcie_device->id;
list_move_tail(&pcie_device->list, &ioc->pcie_device_list);
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
rc = scsi_add_device(ioc->shost, PCIE_CHANNEL, tid, 0);
if (rc)
_scsih_pcie_device_remove(ioc, pcie_device);
} else {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = device;
@ -8565,6 +8839,101 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
}
}
/**
* get_next_pcie_device - Get the next pcie device
* @ioc: per adapter object
*
* Get the next pcie device from pcie_device_init_list list.
*
* Returns pcie device structure if pcie_device_init_list list is not empty
* otherwise returns NULL
*/
static struct _pcie_device *get_next_pcie_device(struct MPT3SAS_ADAPTER *ioc)
{
struct _pcie_device *pcie_device = NULL;
unsigned long flags;
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
if (!list_empty(&ioc->pcie_device_init_list)) {
pcie_device = list_first_entry(&ioc->pcie_device_init_list,
struct _pcie_device, list);
pcie_device_get(pcie_device);
}
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
return pcie_device;
}
/**
* pcie_device_make_active - Add pcie device to pcie_device_list list
* @ioc: per adapter object
* @pcie_device: pcie device object
*
* Add the pcie device which has registered with SCSI Transport Later to
* pcie_device_list list
*/
static void pcie_device_make_active(struct MPT3SAS_ADAPTER *ioc,
struct _pcie_device *pcie_device)
{
unsigned long flags;
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
if (!list_empty(&pcie_device->list)) {
list_del_init(&pcie_device->list);
pcie_device_put(pcie_device);
}
pcie_device_get(pcie_device);
list_add_tail(&pcie_device->list, &ioc->pcie_device_list);
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
}
/**
* _scsih_probe_pcie - reporting PCIe devices to scsi-ml
* @ioc: per adapter object
*
* Called during initial loading of the driver.
*/
static void
_scsih_probe_pcie(struct MPT3SAS_ADAPTER *ioc)
{
struct _pcie_device *pcie_device;
int rc;
/* PCIe Device List */
while ((pcie_device = get_next_pcie_device(ioc))) {
if (pcie_device->starget) {
pcie_device_put(pcie_device);
continue;
}
rc = scsi_add_device(ioc->shost, PCIE_CHANNEL,
pcie_device->id, 0);
if (rc) {
_scsih_pcie_device_remove(ioc, pcie_device);
pcie_device_put(pcie_device);
continue;
} else if (!pcie_device->starget) {
/*
* When async scanning is enabled, its not possible to
* remove devices while scanning is turned on due to an
* oops in scsi_sysfs_add_sdev()->add_device()->
* sysfs_addrm_start()
*/
if (!ioc->is_driver_loading) {
/* TODO-- Need to find out whether this condition will
* occur or not
*/
_scsih_pcie_device_remove(ioc, pcie_device);
pcie_device_put(pcie_device);
continue;
}
}
pcie_device_make_active(ioc, pcie_device);
pcie_device_put(pcie_device);
}
}
/**
* _scsih_probe_devices - probing for devices
* @ioc: per adapter object
@ -8593,8 +8962,10 @@ _scsih_probe_devices(struct MPT3SAS_ADAPTER *ioc)
_scsih_probe_sas(ioc);
_scsih_probe_raid(ioc);
}
} else
} else {
_scsih_probe_sas(ioc);
_scsih_probe_pcie(ioc);
}
}
/**
@ -8937,11 +9308,14 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ioc->sas_node_lock);
spin_lock_init(&ioc->fw_event_lock);
spin_lock_init(&ioc->raid_device_lock);
spin_lock_init(&ioc->pcie_device_lock);
spin_lock_init(&ioc->diag_trigger_lock);
INIT_LIST_HEAD(&ioc->sas_device_list);
INIT_LIST_HEAD(&ioc->sas_device_init_list);
INIT_LIST_HEAD(&ioc->sas_expander_list);
INIT_LIST_HEAD(&ioc->pcie_device_list);
INIT_LIST_HEAD(&ioc->pcie_device_init_list);
INIT_LIST_HEAD(&ioc->fw_event_list);
INIT_LIST_HEAD(&ioc->raid_device_list);
INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);