]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
scsi: mpi3mr: Avoid reply queue full condition
authorRanjan Kumar <ranjan.kumar@broadcom.com>
Wed, 29 Jan 2025 10:08:47 +0000 (15:38 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 4 Feb 2025 02:46:40 +0000 (21:46 -0500)
To avoid reply queue full condition, update the driver to check IOCFacts
capabilities for qfull.

Update the operational reply queue's Consumer Index after processing 100
replies. If pending I/Os on a reply queue exceeds a threshold
(reply_queue_depth - 200), then return I/O back to OS to retry.

Also increase default admin reply queue size to 2K.

Signed-off-by: Sumit Saxena <sumit.saxena@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
Link: https://lore.kernel.org/r/20250129100850.25430-2-ranjan.kumar@broadcom.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/mpi3mr/mpi3mr.h
drivers/scsi/mpi3mr/mpi3mr_app.c
drivers/scsi/mpi3mr/mpi3mr_fw.c

index 0d72b5f1b69df1fe6a151db0b59de7e3fdd0b23b..9ed20ed581be6be769db4b61a52a1a16d65b9146 100644 (file)
@@ -80,13 +80,14 @@ extern atomic64_t event_counter;
 
 /* Admin queue management definitions */
 #define MPI3MR_ADMIN_REQ_Q_SIZE                (2 * MPI3MR_PAGE_SIZE_4K)
-#define MPI3MR_ADMIN_REPLY_Q_SIZE      (4 * MPI3MR_PAGE_SIZE_4K)
+#define MPI3MR_ADMIN_REPLY_Q_SIZE      (8 * MPI3MR_PAGE_SIZE_4K)
 #define MPI3MR_ADMIN_REQ_FRAME_SZ      128
 #define MPI3MR_ADMIN_REPLY_FRAME_SZ    16
 
 /* Operational queue management definitions */
 #define MPI3MR_OP_REQ_Q_QD             512
 #define MPI3MR_OP_REP_Q_QD             1024
+#define MPI3MR_OP_REP_Q_QD2K           2048
 #define MPI3MR_OP_REP_Q_QD4K           4096
 #define MPI3MR_OP_REQ_Q_SEG_SIZE       4096
 #define MPI3MR_OP_REP_Q_SEG_SIZE       4096
@@ -328,6 +329,7 @@ enum mpi3mr_reset_reason {
 #define MPI3MR_RESET_REASON_OSTYPE_SHIFT       28
 #define MPI3MR_RESET_REASON_IOCNUM_SHIFT       20
 
+
 /* Queue type definitions */
 enum queue_type {
        MPI3MR_DEFAULT_QUEUE = 0,
@@ -387,6 +389,7 @@ struct mpi3mr_ioc_facts {
        u16 max_msix_vectors;
        u8 personality;
        u8 dma_mask;
+       bool max_req_limit;
        u8 protocol_flags;
        u8 sge_mod_mask;
        u8 sge_mod_value;
@@ -456,6 +459,8 @@ struct op_req_qinfo {
  * @enable_irq_poll: Flag to indicate polling is enabled
  * @in_use: Queue is handled by poll/ISR
  * @qtype: Type of queue (types defined in enum queue_type)
+ * @qfull_watermark: Watermark defined in reply queue to avoid
+ *                    reply queue full
  */
 struct op_reply_qinfo {
        u16 ci;
@@ -471,6 +476,7 @@ struct op_reply_qinfo {
        bool enable_irq_poll;
        atomic_t in_use;
        enum queue_type qtype;
+       u16 qfull_watermark;
 };
 
 /**
@@ -1153,6 +1159,8 @@ struct scmd_priv {
  * @snapdump_trigger_active: Snapdump trigger active flag
  * @pci_err_recovery: PCI error recovery in progress
  * @block_on_pci_err: Block IO during PCI error recovery
+ * @reply_qfull_count: Occurences of reply queue full avoidance kicking-in
+ * @prevent_reply_qfull: Enable reply queue prevention
  */
 struct mpi3mr_ioc {
        struct list_head list;
@@ -1351,6 +1359,8 @@ struct mpi3mr_ioc {
        bool fw_release_trigger_active;
        bool pci_err_recovery;
        bool block_on_pci_err;
+       atomic_t reply_qfull_count;
+       bool prevent_reply_qfull;
 };
 
 /**
index 7589f48aebc80f53949426b81bb16fc841431d0e..1532436f0f3af11096e4340fb3c433c9b4866705 100644 (file)
@@ -3060,6 +3060,29 @@ reply_queue_count_show(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR_RO(reply_queue_count);
 
+/**
+ * reply_qfull_count_show - Show reply qfull count
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * Retrieves the current value of the reply_qfull_count from the mrioc structure and
+ * formats it as a string for display.
+ *
+ * Return: sysfs_emit() return
+ */
+static ssize_t
+reply_qfull_count_show(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct mpi3mr_ioc *mrioc = shost_priv(shost);
+
+       return sysfs_emit(buf, "%u\n", atomic_read(&mrioc->reply_qfull_count));
+}
+
+static DEVICE_ATTR_RO(reply_qfull_count);
+
 /**
  * logging_level_show - Show controller debug level
  * @dev: class device
@@ -3152,6 +3175,7 @@ static struct attribute *mpi3mr_host_attrs[] = {
        &dev_attr_fw_queue_depth.attr,
        &dev_attr_op_req_q_count.attr,
        &dev_attr_reply_queue_count.attr,
+       &dev_attr_reply_qfull_count.attr,
        &dev_attr_logging_level.attr,
        &dev_attr_adp_state.attr,
        NULL,
index 5ed31fe57474a3f62b4316140b1ced5eab957f29..656108dd2ee30e9dade9135e4c8c6bdc4f270245 100644 (file)
@@ -2104,15 +2104,22 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
        }
 
        reply_qid = qidx + 1;
-       op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
-       if ((mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) &&
-               !mrioc->pdev->revision)
-               op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K;
+
+       if (mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) {
+               if (mrioc->pdev->revision)
+                       op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD;
+               else
+                       op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K;
+       } else
+               op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD2K;
+
        op_reply_q->ci = 0;
        op_reply_q->ephase = 1;
        atomic_set(&op_reply_q->pend_ios, 0);
        atomic_set(&op_reply_q->in_use, 0);
        op_reply_q->enable_irq_poll = false;
+       op_reply_q->qfull_watermark =
+               op_reply_q->num_replies - (MPI3MR_THRESHOLD_REPLY_COUNT * 2);
 
        if (!op_reply_q->q_segments) {
                retval = mpi3mr_alloc_op_reply_q_segments(mrioc, qidx);
@@ -2416,8 +2423,10 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
        void *segment_base_addr;
        u16 req_sz = mrioc->facts.op_req_sz;
        struct segments *segments = op_req_q->q_segments;
+       struct op_reply_qinfo *op_reply_q = NULL;
 
        reply_qidx = op_req_q->reply_qid - 1;
+       op_reply_q = mrioc->op_reply_qinfo + reply_qidx;
 
        if (mrioc->unrecoverable)
                return -EFAULT;
@@ -2448,6 +2457,15 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
                goto out;
        }
 
+       /* Reply queue is nearing to get full, push back IOs to SML */
+       if ((mrioc->prevent_reply_qfull == true) &&
+               (atomic_read(&op_reply_q->pend_ios) >
+            (op_reply_q->qfull_watermark))) {
+               atomic_inc(&mrioc->reply_qfull_count);
+               retval = -EAGAIN;
+               goto out;
+       }
+
        segment_base_addr = segments[pi / op_req_q->segment_qd].segment;
        req_entry = (u8 *)segment_base_addr +
            ((pi % op_req_q->segment_qd) * req_sz);
@@ -3091,6 +3109,9 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
        mrioc->facts.dma_mask = (facts_flags &
            MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
            MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
+       mrioc->facts.dma_mask = (facts_flags &
+           MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >>
+           MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT;
        mrioc->facts.protocol_flags = facts_data->protocol_flags;
        mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word);
        mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_requests);
@@ -4214,6 +4235,9 @@ retry_init:
                mrioc->shost->transportt = mpi3mr_transport_template;
        }
 
+       if (mrioc->facts.max_req_limit)
+               mrioc->prevent_reply_qfull = true;
+
        mrioc->reply_sz = mrioc->facts.reply_sz;
 
        retval = mpi3mr_check_reset_dma_mask(mrioc);