scsi: mpi3mr: Reduce VD queue depth on detecting throttling
authorSreekanth Reddy <sreekanth.reddy@broadcom.com>
Fri, 8 Jul 2022 19:50:20 +0000 (01:20 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 19 Jul 2022 03:03:28 +0000 (23:03 -0400)
Reduce the VD queue depth on detecting the throttling condition.

[mkp: incorporate fix for pointer cast issue reported by the test
robot and Guenter Roeck]

Link: https://lore.kernel.org/r/20220708195020.8323-3-sreekanth.reddy@broadcom.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 6bb3311..0935b2e 100644 (file)
@@ -436,6 +436,10 @@ struct mpi3mr_intr_info {
  * struct mpi3mr_throttle_group_info - Throttle group info
  *
  * @io_divert: Flag indicates io divert is on or off for the TG
+ * @need_qd_reduction: Flag to indicate QD reduction is needed
+ * @qd_reduction: Queue Depth reduction in units of 10%
+ * @fw_qd: QueueDepth value reported by the firmware
+ * @modified_qd: Modified QueueDepth value due to throttling
  * @id: Throttle Group ID.
  * @high: High limit to turn on throttling in 512 byte blocks
  * @low: Low limit to turn off throttling in 512 byte blocks
@@ -443,6 +447,10 @@ struct mpi3mr_intr_info {
  */
 struct mpi3mr_throttle_group_info {
        u8 io_divert;
+       u8 need_qd_reduction;
+       u8 qd_reduction;
+       u16 fw_qd;
+       u16 modified_qd;
        u16 id;
        u32 high;
        u32 low;
@@ -486,6 +494,7 @@ struct tgt_dev_pcie {
  * cached from firmware given data
  *
  * @state: State of the VD
+ * @tg_qd_reduction: Queue Depth reduction in units of 10%
  * @tg_id: VDs throttle group ID
  * @high: High limit to turn on throttling in 512 byte blocks
  * @low: Low limit to turn off throttling in 512 byte blocks
@@ -493,6 +502,7 @@ struct tgt_dev_pcie {
  */
 struct tgt_dev_vd {
        u8 state;
+       u8 tg_qd_reduction;
        u16 tg_id;
        u32 tg_high;
        u32 tg_low;
index ab79374..6e39f79 100644 (file)
@@ -4077,9 +4077,13 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
                tg = mrioc->throttle_groups;
                for (i = 0; i < mrioc->num_io_throttle_group; i++, tg++) {
                        tg->id = 0;
+                       tg->fw_qd = 0;
+                       tg->modified_qd = 0;
                        tg->io_divert = 0;
+                       tg->need_qd_reduction = 0;
                        tg->high = 0;
                        tg->low = 0;
+                       tg->qd_reduction = 0;
                        atomic_set(&tg->pend_large_data_sz, 0);
                }
        }
index e1ccb5f..4102636 100644 (file)
@@ -38,6 +38,8 @@ MODULE_PARM_DESC(logging_level,
 static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
        struct mpi3mr_drv_cmd *cmdparam, u32 event_ctx);
 
+#define MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION    (0xFFFF)
+
 /**
  * mpi3mr_host_tag_for_scmd - Get host tag for a scmd
  * @mrioc: Adapter instance reference
@@ -355,6 +357,50 @@ void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc)
 }
 
 /**
+ * mpi3mr_queue_qd_reduction_event - Queue TG QD reduction event
+ * @mrioc: Adapter instance reference
+ * @tg: Throttle group information pointer
+ *
+ * Accessor to queue on synthetically generated driver event to
+ * the event worker thread, the driver event will be used to
+ * reduce the QD of all VDs in the TG from the worker thread.
+ *
+ * Return: None.
+ */
+static void mpi3mr_queue_qd_reduction_event(struct mpi3mr_ioc *mrioc,
+       struct mpi3mr_throttle_group_info *tg)
+{
+       struct mpi3mr_fwevt *fwevt;
+       u16 sz = sizeof(struct mpi3mr_throttle_group_info *);
+
+       /*
+        * If the QD reduction event is already queued due to throttle and if
+        * the QD is not restored through device info change event
+        * then dont queue further reduction events
+        */
+       if (tg->fw_qd != tg->modified_qd)
+               return;
+
+       fwevt = mpi3mr_alloc_fwevt(sz);
+       if (!fwevt) {
+               ioc_warn(mrioc, "failed to queue TG QD reduction event\n");
+               return;
+       }
+       *(struct mpi3mr_throttle_group_info **)fwevt->event_data = tg;
+       fwevt->mrioc = mrioc;
+       fwevt->event_id = MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION;
+       fwevt->send_ack = 0;
+       fwevt->process_evt = 1;
+       fwevt->evt_ctx = 0;
+       fwevt->event_data_size = sz;
+       tg->modified_qd = max_t(u16, (tg->fw_qd * tg->qd_reduction) / 10, 8);
+
+       dprint_event_bh(mrioc, "qd reduction event queued for tg_id(%d)\n",
+           tg->id);
+       mpi3mr_fwevt_add_to_list(mrioc, fwevt);
+}
+
+/**
  * mpi3mr_invalidate_devhandles -Invalidate device handles
  * @mrioc: Adapter instance reference
  *
@@ -880,6 +926,7 @@ static int mpi3mr_change_queue_depth(struct scsi_device *sdev,
        else if (!q_depth)
                q_depth = MPI3MR_DEFAULT_SDEV_QD;
        retval = scsi_change_queue_depth(sdev, q_depth);
+       sdev->max_queue_depth = sdev->queue_depth;
 
        return retval;
 }
@@ -1100,6 +1147,11 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
                        tg->id = vdinf_io_throttle_group;
                        tg->high = tgtdev->dev_spec.vd_inf.tg_high;
                        tg->low = tgtdev->dev_spec.vd_inf.tg_low;
+                       tg->qd_reduction =
+                           tgtdev->dev_spec.vd_inf.tg_qd_reduction;
+                       if (is_added == true)
+                               tg->fw_qd = tgtdev->q_depth;
+                       tg->modified_qd = tgtdev->q_depth;
                }
                tgtdev->dev_spec.vd_inf.tg = tg;
                if (scsi_tgt_priv_data)
@@ -1494,6 +1546,60 @@ static void mpi3mr_logdata_evt_bh(struct mpi3mr_ioc *mrioc,
 }
 
 /**
+ * mpi3mr_update_sdev_qd - Update SCSI device queue depath
+ * @sdev: SCSI device reference
+ * @data: Queue depth reference
+ *
+ * This is an iterator function called for each SCSI device in a
+ * target to update the QD of each SCSI device.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_update_sdev_qd(struct scsi_device *sdev, void *data)
+{
+       u16 *q_depth = (u16 *)data;
+
+       scsi_change_queue_depth(sdev, (int)*q_depth);
+       sdev->max_queue_depth = sdev->queue_depth;
+}
+
+/**
+ * mpi3mr_set_qd_for_all_vd_in_tg -set QD for TG VDs
+ * @mrioc: Adapter instance reference
+ * @tg: Throttle group information pointer
+ *
+ * Accessor to reduce QD for each device associated with the
+ * given throttle group.
+ *
+ * Return: None.
+ */
+static void mpi3mr_set_qd_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc,
+       struct mpi3mr_throttle_group_info *tg)
+{
+       unsigned long flags;
+       struct mpi3mr_tgt_dev *tgtdev;
+       struct mpi3mr_stgt_priv_data *tgt_priv;
+
+
+       spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+       list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
+               if (tgtdev->starget && tgtdev->starget->hostdata) {
+                       tgt_priv = tgtdev->starget->hostdata;
+                       if (tgt_priv->throttle_group == tg) {
+                               dprint_event_bh(mrioc,
+                                   "updating qd due to throttling for persist_id(%d) original_qd(%d), reduced_qd (%d)\n",
+                                   tgt_priv->perst_id, tgtdev->q_depth,
+                                   tg->modified_qd);
+                               starget_for_each_device(tgtdev->starget,
+                                   (void *)&tg->modified_qd,
+                                   mpi3mr_update_sdev_qd);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+}
+
+/**
  * mpi3mr_fwevt_bh - Firmware event bottomhalf handler
  * @mrioc: Adapter instance reference
  * @fwevt: Firmware event reference
@@ -1550,6 +1656,20 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
                mpi3mr_logdata_evt_bh(mrioc, fwevt);
                break;
        }
+       case MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION:
+       {
+               struct mpi3mr_throttle_group_info *tg;
+
+               tg = *(struct mpi3mr_throttle_group_info **)fwevt->event_data;
+               dprint_event_bh(mrioc,
+                   "qd reduction event processed for tg_id(%d) reduction_needed(%d)\n",
+                   tg->id, tg->need_qd_reduction);
+               if (tg->need_qd_reduction) {
+                       mpi3mr_set_qd_for_all_vd_in_tg(mrioc, tg);
+                       tg->need_qd_reduction = 0;
+               }
+               break;
+       }
        default:
                break;
        }
@@ -4234,8 +4354,10 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
                            mrioc->io_throttle_high) ||
                            (tg_pend_data_len >= tg->high))) {
                                tg->io_divert = 1;
+                               tg->need_qd_reduction = 1;
                                mpi3mr_set_io_divert_for_all_vd_in_tg(mrioc,
                                    tg, 1);
+                               mpi3mr_queue_qd_reduction_event(mrioc, tg);
                        }
                } else {
                        ioc_pend_data_len = atomic_add_return(data_len_blks,