scsi: mpi3mr: Enable Enclosure device add event
authorSreekanth Reddy <sreekanth.reddy@broadcom.com>
Thu, 4 Aug 2022 13:12:15 +0000 (18:42 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 23 Aug 2022 03:34:05 +0000 (23:34 -0400)
Enable and process the Enclosure device add event.

Link: https://lore.kernel.org/r/20220804131226.16653-5-sreekanth.reddy@broadcom.com
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/mpi3mr/mpi3mr.h
drivers/scsi/mpi3mr/mpi3mr_fw.c
drivers/scsi/mpi3mr/mpi3mr_os.c

index 8af94d3..542b462 100644 (file)
@@ -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[];
 
index bfc4244..c732586 100644 (file)
@@ -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);
index a06135c..18a9bd0 100644 (file)
@@ -1018,6 +1018,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);
@@ -1028,8 +1029,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)
@@ -1257,6 +1267,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
@@ -1633,6 +1753,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);
@@ -2494,6 +2621,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;
@@ -2508,7 +2637,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:
@@ -4561,6 +4689,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);