scsi: mpt3sas: Add nvme device support in slave alloc, target alloc and probe
authorSuganath Prabu Subramani <suganath-prabu.subramani@broadcom.com>
Tue, 31 Oct 2017 12:32:27 +0000 (18:02 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 3 Nov 2017 16:20:52 +0000 (12:20 -0400)
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>
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_scsih.c

index 0fe3969dd8e7904a62d131666caf8722e7b96eaf..bafa90ab916c7cdd8b4892e57c44b80b356ce50d 100644 (file)
 #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;
index dee83082b5a6d48bfddb0fc685e579512105e12f..c8639975970536607f6fa87c579d2c6437f85551 100644 (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 (pcie_device)
+                       pcie_device_put(pcie_device);
+               spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
 
-       if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
+       } 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);