diff mbox series

[04/15] mpi3mr: Enable Enclosure device add event

Message ID 20220729131627.15019-5-sreekanth.reddy@broadcom.com (mailing list archive)
State Superseded
Headers show
Series mpi3mr: Added Support for SAS Transport | expand

Commit Message

Sreekanth Reddy July 29, 2022, 1:16 p.m. UTC
Enable and process the Enclosure device add event.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h    |  19 +++++
 drivers/scsi/mpi3mr/mpi3mr_fw.c |   4 +
 drivers/scsi/mpi3mr/mpi3mr_os.c | 133 +++++++++++++++++++++++++++++++-
 3 files changed, 154 insertions(+), 2 deletions(-)

Comments

Himanshu Madhani July 29, 2022, 6:33 p.m. UTC | #1
> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Enable and process the Enclosure device add event.
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h    |  19 +++++
> drivers/scsi/mpi3mr/mpi3mr_fw.c |   4 +
> drivers/scsi/mpi3mr/mpi3mr_os.c | 133 +++++++++++++++++++++++++++++++-
> 3 files changed, 154 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index 8af94d3..542b462 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -461,6 +461,16 @@ struct mpi3mr_throttle_group_info {
> 	atomic_t pend_large_data_sz;
> };
> 
> +/**
> + * struct mpi3mr_enclosure_node - enclosure information
> + * @list: List of enclosures
> + * @pg0: Enclosure page 0;
> + */
> +struct mpi3mr_enclosure_node {
> +	struct list_head list;
> +	struct mpi3_enclosure_page0 pg0;
> +};
> +
> /**
>  * struct tgt_dev_sas_sata - SAS/SATA device specific
>  * information cached from firmware given data
> @@ -535,12 +545,14 @@ union _form_spec_inf {
>  * @slot: Slot number
>  * @encl_handle: FW enclosure handle
>  * @perst_id: FW assigned Persistent ID
> + * @devpg0_flag: Device Page0 flag
>  * @dev_type: SAS/SATA/PCIE device type
>  * @is_hidden: Should be exposed to upper layers or not
>  * @host_exposed: Already exposed to host or not
>  * @io_throttle_enabled: I/O throttling needed or not
>  * @q_depth: Device specific Queue Depth
>  * @wwid: World wide ID
> + * @enclosure_logical_id: Enclosure logical identifier
>  * @dev_spec: Device type specific information
>  * @ref_count: Reference count
>  */
> @@ -552,12 +564,14 @@ struct mpi3mr_tgt_dev {
> 	u16 slot;
> 	u16 encl_handle;
> 	u16 perst_id;
> +	u16 devpg0_flag;
> 	u8 dev_type;
> 	u8 is_hidden;
> 	u8 host_exposed;
> 	u8 io_throttle_enabled;
> 	u16 q_depth;
> 	u64 wwid;
> +	u64 enclosure_logical_id;
> 	union _form_spec_inf dev_spec;
> 	struct kref ref_count;
> };
> @@ -877,6 +891,7 @@ struct scmd_priv {
>  * @cfg_page: Default memory for configuration pages
>  * @cfg_page_dma: Configuration page DMA address
>  * @cfg_page_sz: Default configuration page memory size
> + * @enclosure_list: List of Enclosure objects
>  */
> struct mpi3mr_ioc {
> 	struct list_head list;
> @@ -1053,6 +1068,8 @@ struct mpi3mr_ioc {
> 	void *cfg_page;
> 	dma_addr_t cfg_page_dma;
> 	u16 cfg_page_sz;
> +
> +	struct list_head enclosure_list;
> };
> 
> /**
> @@ -1177,6 +1194,8 @@ int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc,
> 	struct mpi3mr_drv_cmd *drv_cmd);
> void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data,
> 	u16 event_data_size);
> +struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
> +	struct mpi3mr_ioc *mrioc, u16 handle);
> extern const struct attribute_group *mpi3mr_host_groups[];
> extern const struct attribute_group *mpi3mr_dev_groups[];
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 50e88d4..9c36f52 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -244,6 +244,9 @@ static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
> 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
> 		desc = "Enclosure Device Status Change";
> 		break;
> +	case MPI3_EVENT_ENCL_DEVICE_ADDED:
> +		desc = "Enclosure Added";
> +		break;
> 	case MPI3_EVENT_HARD_RESET_RECEIVED:
> 		desc = "Hard Reset Received";
> 		break;
> @@ -3660,6 +3663,7 @@ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
> +	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_ADDED);
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index 40bed22..ca718cb 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -1026,6 +1026,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> {
> 	u16 flags = 0;
> 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
> +	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
> 	u8 prot_mask = 0;
> 
> 	tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id);
> @@ -1036,8 +1037,17 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> 	tgtdev->slot = le16_to_cpu(dev_pg0->slot);
> 	tgtdev->q_depth = le16_to_cpu(dev_pg0->queue_depth);
> 	tgtdev->wwid = le64_to_cpu(dev_pg0->wwid);
> +	tgtdev->devpg0_flag = le16_to_cpu(dev_pg0->flags);
> +
> +	if (tgtdev->encl_handle)
> +		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
> +		    tgtdev->encl_handle);
> +	if (enclosure_dev)
> +		tgtdev->enclosure_logical_id = le64_to_cpu(
> +		    enclosure_dev->pg0.enclosure_logical_id);
> +
> +	flags = tgtdev->devpg0_flag;
> 
> -	flags = le16_to_cpu(dev_pg0->flags);
> 	tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN);
> 
> 	if (is_added == true)
> @@ -1265,6 +1275,116 @@ out:
> 		mpi3mr_tgtdev_put(tgtdev);
> }
> 
> +/**
> + * mpi3mr_enclosure_find_by_handle - enclosure search by handle
> + * @mrioc: Adapter instance reference
> + * @handle: Firmware device handle of the enclosure
> + *
> + * This searches for enclosure device based on handle, then returns the
> + * enclosure object.
> + *
> + * Return: Enclosure object reference or NULL
> + */
> +struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
> +	struct mpi3mr_ioc *mrioc, u16 handle)
> +{
> +	struct mpi3mr_enclosure_node *enclosure_dev, *r = NULL;
> +
> +	list_for_each_entry(enclosure_dev, &mrioc->enclosure_list, list) {
> +		if (le16_to_cpu(enclosure_dev->pg0.enclosure_handle) != handle)
> +			continue;
> +		r = enclosure_dev;
> +		goto out;
> +	}
> +out:
> +	return r;
> +}
> +
> +/**
> + * mpi3mr_encldev_add_chg_evt_debug - debug for enclosure event
> + * @mrioc: Adapter instance reference
> + * @encl_pg0: Enclosure page 0.
> + * @is_added: Added event or not
> + *
> + * Return nothing.
> + */
> +static void mpi3mr_encldev_add_chg_evt_debug(struct mpi3mr_ioc *mrioc,
> +	struct mpi3_enclosure_page0 *encl_pg0, u8 is_added)
> +{
> +	char *reason_str = NULL;
> +
> +	if (!(mrioc->logging_level & MPI3_DEBUG_EVENT_WORK_TASK))
> +		return;
> +
> +	if (is_added)
> +		reason_str = "enclosure added";
> +	else
> +		reason_str = "enclosure dev status changed";
> +
> +	ioc_info(mrioc,
> +	    "%s: handle(0x%04x), enclosure logical id(0x%016llx)\n",
> +	    reason_str, le16_to_cpu(encl_pg0->enclosure_handle),
> +	    (unsigned long long)le64_to_cpu(encl_pg0->enclosure_logical_id));
> +	ioc_info(mrioc,
> +	    "number of slots(%d), port(%d), flags(0x%04x), present(%d)\n",
> +	    le16_to_cpu(encl_pg0->num_slots), encl_pg0->io_unit_port,
> +	    le16_to_cpu(encl_pg0->flags),
> +	    ((le16_to_cpu(encl_pg0->flags) &
> +	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4));
> +}
> +
> +/**
> + * mpi3mr_encldev_add_chg_evt_bh - Enclosure evt bottomhalf
> + * @mrioc: Adapter instance reference
> + * @fwevt: Firmware event reference
> + *
> + * Prints information about the Enclosure device status or
> + * Enclosure add events if logging is enabled and add or remove
> + * the enclosure from the controller's internal list of
> + * enclosures.
> + *
> + * Return: Nothing.
> + */
> +static void mpi3mr_encldev_add_chg_evt_bh(struct mpi3mr_ioc *mrioc,
> +	struct mpi3mr_fwevt *fwevt)
> +{
> +	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
> +	struct mpi3_enclosure_page0 *encl_pg0;
> +	u16 encl_handle;
> +	u8 added, present;
> +
> +	encl_pg0 = (struct mpi3_enclosure_page0 *) fwevt->event_data;
> +	added = (fwevt->event_id == MPI3_EVENT_ENCL_DEVICE_ADDED) ? 1 : 0;
> +	mpi3mr_encldev_add_chg_evt_debug(mrioc, encl_pg0, added);
> +
> +
> +	encl_handle = le16_to_cpu(encl_pg0->enclosure_handle);
> +	present = ((le16_to_cpu(encl_pg0->flags) &
> +	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4);
> +
> +	if (encl_handle)
> +		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
> +		    encl_handle);
> +	if (!enclosure_dev && present) {
> +		enclosure_dev =
> +			kzalloc(sizeof(struct mpi3mr_enclosure_node),
> +			    GFP_KERNEL);
> +		if (!enclosure_dev)
> +			return;
> +		list_add_tail(&enclosure_dev->list,
> +		    &mrioc->enclosure_list);
> +	}
> +	if (enclosure_dev) {
> +		if (!present) {
> +			list_del(&enclosure_dev->list);
> +			kfree(enclosure_dev);
> +		} else
> +			memcpy(&enclosure_dev->pg0, encl_pg0,
> +			    sizeof(enclosure_dev->pg0));
> +
> +	}
> +}
> +
> /**
>  * mpi3mr_sastopochg_evt_debug - SASTopoChange details
>  * @mrioc: Adapter instance reference
> @@ -1641,6 +1761,13 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
> 		mpi3mr_devstatuschg_evt_bh(mrioc, fwevt);
> 		break;
> 	}
> +	case MPI3_EVENT_ENCL_DEVICE_ADDED:
> +	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
> +	{
> +		mpi3mr_encldev_add_chg_evt_bh(mrioc, fwevt);
> +		break;
> +	}
> +
> 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
> 	{
> 		mpi3mr_sastopochg_evt_bh(mrioc, fwevt);
> @@ -2502,6 +2629,8 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
> 	}
> 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
> 	case MPI3_EVENT_LOG_DATA:
> +	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
> +	case MPI3_EVENT_ENCL_DEVICE_ADDED:
> 	{
> 		process_evt_bh = 1;
> 		break;
> @@ -2516,7 +2645,6 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
> 		mpi3mr_cablemgmt_evt_th(mrioc, event_reply);
> 		break;
> 	}
> -	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
> 	case MPI3_EVENT_SAS_DISCOVERY:
> 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
> 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
> @@ -4569,6 +4697,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> 	INIT_LIST_HEAD(&mrioc->tgtdev_list);
> 	INIT_LIST_HEAD(&mrioc->delayed_rmhs_list);
> 	INIT_LIST_HEAD(&mrioc->delayed_evtack_cmds_list);
> +	INIT_LIST_HEAD(&mrioc->enclosure_list);
> 
> 	mutex_init(&mrioc->reset_mutex);
> 	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
> -- 
> 2.27.0
> 

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering
diff mbox series

Patch

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 8af94d3..542b462 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -461,6 +461,16 @@  struct mpi3mr_throttle_group_info {
 	atomic_t pend_large_data_sz;
 };
 
+/**
+ * struct mpi3mr_enclosure_node - enclosure information
+ * @list: List of enclosures
+ * @pg0: Enclosure page 0;
+ */
+struct mpi3mr_enclosure_node {
+	struct list_head list;
+	struct mpi3_enclosure_page0 pg0;
+};
+
 /**
  * struct tgt_dev_sas_sata - SAS/SATA device specific
  * information cached from firmware given data
@@ -535,12 +545,14 @@  union _form_spec_inf {
  * @slot: Slot number
  * @encl_handle: FW enclosure handle
  * @perst_id: FW assigned Persistent ID
+ * @devpg0_flag: Device Page0 flag
  * @dev_type: SAS/SATA/PCIE device type
  * @is_hidden: Should be exposed to upper layers or not
  * @host_exposed: Already exposed to host or not
  * @io_throttle_enabled: I/O throttling needed or not
  * @q_depth: Device specific Queue Depth
  * @wwid: World wide ID
+ * @enclosure_logical_id: Enclosure logical identifier
  * @dev_spec: Device type specific information
  * @ref_count: Reference count
  */
@@ -552,12 +564,14 @@  struct mpi3mr_tgt_dev {
 	u16 slot;
 	u16 encl_handle;
 	u16 perst_id;
+	u16 devpg0_flag;
 	u8 dev_type;
 	u8 is_hidden;
 	u8 host_exposed;
 	u8 io_throttle_enabled;
 	u16 q_depth;
 	u64 wwid;
+	u64 enclosure_logical_id;
 	union _form_spec_inf dev_spec;
 	struct kref ref_count;
 };
@@ -877,6 +891,7 @@  struct scmd_priv {
  * @cfg_page: Default memory for configuration pages
  * @cfg_page_dma: Configuration page DMA address
  * @cfg_page_sz: Default configuration page memory size
+ * @enclosure_list: List of Enclosure objects
  */
 struct mpi3mr_ioc {
 	struct list_head list;
@@ -1053,6 +1068,8 @@  struct mpi3mr_ioc {
 	void *cfg_page;
 	dma_addr_t cfg_page_dma;
 	u16 cfg_page_sz;
+
+	struct list_head enclosure_list;
 };
 
 /**
@@ -1177,6 +1194,8 @@  int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc,
 	struct mpi3mr_drv_cmd *drv_cmd);
 void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data,
 	u16 event_data_size);
+struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
+	struct mpi3mr_ioc *mrioc, u16 handle);
 extern const struct attribute_group *mpi3mr_host_groups[];
 extern const struct attribute_group *mpi3mr_dev_groups[];
 
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 50e88d4..9c36f52 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -244,6 +244,9 @@  static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
 		desc = "Enclosure Device Status Change";
 		break;
+	case MPI3_EVENT_ENCL_DEVICE_ADDED:
+		desc = "Enclosure Added";
+		break;
 	case MPI3_EVENT_HARD_RESET_RECEIVED:
 		desc = "Hard Reset Received";
 		break;
@@ -3660,6 +3663,7 @@  static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
+	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_ADDED);
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 40bed22..ca718cb 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -1026,6 +1026,7 @@  static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 {
 	u16 flags = 0;
 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
+	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
 	u8 prot_mask = 0;
 
 	tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id);
@@ -1036,8 +1037,17 @@  static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 	tgtdev->slot = le16_to_cpu(dev_pg0->slot);
 	tgtdev->q_depth = le16_to_cpu(dev_pg0->queue_depth);
 	tgtdev->wwid = le64_to_cpu(dev_pg0->wwid);
+	tgtdev->devpg0_flag = le16_to_cpu(dev_pg0->flags);
+
+	if (tgtdev->encl_handle)
+		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
+		    tgtdev->encl_handle);
+	if (enclosure_dev)
+		tgtdev->enclosure_logical_id = le64_to_cpu(
+		    enclosure_dev->pg0.enclosure_logical_id);
+
+	flags = tgtdev->devpg0_flag;
 
-	flags = le16_to_cpu(dev_pg0->flags);
 	tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN);
 
 	if (is_added == true)
@@ -1265,6 +1275,116 @@  out:
 		mpi3mr_tgtdev_put(tgtdev);
 }
 
+/**
+ * mpi3mr_enclosure_find_by_handle - enclosure search by handle
+ * @mrioc: Adapter instance reference
+ * @handle: Firmware device handle of the enclosure
+ *
+ * This searches for enclosure device based on handle, then returns the
+ * enclosure object.
+ *
+ * Return: Enclosure object reference or NULL
+ */
+struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
+	struct mpi3mr_ioc *mrioc, u16 handle)
+{
+	struct mpi3mr_enclosure_node *enclosure_dev, *r = NULL;
+
+	list_for_each_entry(enclosure_dev, &mrioc->enclosure_list, list) {
+		if (le16_to_cpu(enclosure_dev->pg0.enclosure_handle) != handle)
+			continue;
+		r = enclosure_dev;
+		goto out;
+	}
+out:
+	return r;
+}
+
+/**
+ * mpi3mr_encldev_add_chg_evt_debug - debug for enclosure event
+ * @mrioc: Adapter instance reference
+ * @encl_pg0: Enclosure page 0.
+ * @is_added: Added event or not
+ *
+ * Return nothing.
+ */
+static void mpi3mr_encldev_add_chg_evt_debug(struct mpi3mr_ioc *mrioc,
+	struct mpi3_enclosure_page0 *encl_pg0, u8 is_added)
+{
+	char *reason_str = NULL;
+
+	if (!(mrioc->logging_level & MPI3_DEBUG_EVENT_WORK_TASK))
+		return;
+
+	if (is_added)
+		reason_str = "enclosure added";
+	else
+		reason_str = "enclosure dev status changed";
+
+	ioc_info(mrioc,
+	    "%s: handle(0x%04x), enclosure logical id(0x%016llx)\n",
+	    reason_str, le16_to_cpu(encl_pg0->enclosure_handle),
+	    (unsigned long long)le64_to_cpu(encl_pg0->enclosure_logical_id));
+	ioc_info(mrioc,
+	    "number of slots(%d), port(%d), flags(0x%04x), present(%d)\n",
+	    le16_to_cpu(encl_pg0->num_slots), encl_pg0->io_unit_port,
+	    le16_to_cpu(encl_pg0->flags),
+	    ((le16_to_cpu(encl_pg0->flags) &
+	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4));
+}
+
+/**
+ * mpi3mr_encldev_add_chg_evt_bh - Enclosure evt bottomhalf
+ * @mrioc: Adapter instance reference
+ * @fwevt: Firmware event reference
+ *
+ * Prints information about the Enclosure device status or
+ * Enclosure add events if logging is enabled and add or remove
+ * the enclosure from the controller's internal list of
+ * enclosures.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_encldev_add_chg_evt_bh(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_fwevt *fwevt)
+{
+	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
+	struct mpi3_enclosure_page0 *encl_pg0;
+	u16 encl_handle;
+	u8 added, present;
+
+	encl_pg0 = (struct mpi3_enclosure_page0 *) fwevt->event_data;
+	added = (fwevt->event_id == MPI3_EVENT_ENCL_DEVICE_ADDED) ? 1 : 0;
+	mpi3mr_encldev_add_chg_evt_debug(mrioc, encl_pg0, added);
+
+
+	encl_handle = le16_to_cpu(encl_pg0->enclosure_handle);
+	present = ((le16_to_cpu(encl_pg0->flags) &
+	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4);
+
+	if (encl_handle)
+		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
+		    encl_handle);
+	if (!enclosure_dev && present) {
+		enclosure_dev =
+			kzalloc(sizeof(struct mpi3mr_enclosure_node),
+			    GFP_KERNEL);
+		if (!enclosure_dev)
+			return;
+		list_add_tail(&enclosure_dev->list,
+		    &mrioc->enclosure_list);
+	}
+	if (enclosure_dev) {
+		if (!present) {
+			list_del(&enclosure_dev->list);
+			kfree(enclosure_dev);
+		} else
+			memcpy(&enclosure_dev->pg0, encl_pg0,
+			    sizeof(enclosure_dev->pg0));
+
+	}
+}
+
 /**
  * mpi3mr_sastopochg_evt_debug - SASTopoChange details
  * @mrioc: Adapter instance reference
@@ -1641,6 +1761,13 @@  static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
 		mpi3mr_devstatuschg_evt_bh(mrioc, fwevt);
 		break;
 	}
+	case MPI3_EVENT_ENCL_DEVICE_ADDED:
+	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
+	{
+		mpi3mr_encldev_add_chg_evt_bh(mrioc, fwevt);
+		break;
+	}
+
 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
 	{
 		mpi3mr_sastopochg_evt_bh(mrioc, fwevt);
@@ -2502,6 +2629,8 @@  void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
 	}
 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
 	case MPI3_EVENT_LOG_DATA:
+	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
+	case MPI3_EVENT_ENCL_DEVICE_ADDED:
 	{
 		process_evt_bh = 1;
 		break;
@@ -2516,7 +2645,6 @@  void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
 		mpi3mr_cablemgmt_evt_th(mrioc, event_reply);
 		break;
 	}
-	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
 	case MPI3_EVENT_SAS_DISCOVERY:
 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
@@ -4569,6 +4697,7 @@  mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	INIT_LIST_HEAD(&mrioc->tgtdev_list);
 	INIT_LIST_HEAD(&mrioc->delayed_rmhs_list);
 	INIT_LIST_HEAD(&mrioc->delayed_evtack_cmds_list);
+	INIT_LIST_HEAD(&mrioc->enclosure_list);
 
 	mutex_init(&mrioc->reset_mutex);
 	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);