scsi: megaraid_sas: Handle missing interrupts while re-enabling IRQs
authorChandrakanth Patil <chandrakanth.patil@broadcom.com>
Fri, 28 May 2021 13:13:06 +0000 (18:43 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 20 Jul 2021 14:05:41 +0000 (16:05 +0200)
[ Upstream commit 9bedd36e9146b34dda4d6994e3aa1d72bc6442c1 ]

While reenabling the IRQ after IRQ poll there may be a small window for the
firmware to post the replies with interrupts raised. In that case the
driver will not see the interrupts which leads to I/O timeout.

This issue only happens when there are many I/O completions on a single
reply queue. This forces the driver to switch between the interrupt and IRQ
context.

Make the driver process the reply queue one more time after enabling the
IRQ.

Link: https://lore.kernel.org/linux-scsi/20201102072746.27410-1-sreekanth.reddy@broadcom.com/
Link: https://lore.kernel.org/r/20210528131307.25683-5-chandrakanth.patil@broadcom.com
Cc: Tomas Henzl <thenzl@redhat.com>
Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Sumit Saxena <sumit.saxena@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/scsi/megaraid/megaraid_sas_fusion.c

index 35925e6..13022a4 100644 (file)
@@ -3667,6 +3667,7 @@ static void megasas_sync_irqs(unsigned long instance_addr)
                if (irq_ctx->irq_poll_scheduled) {
                        irq_ctx->irq_poll_scheduled = false;
                        enable_irq(irq_ctx->os_irq);
+                       complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
                }
        }
 }
@@ -3698,6 +3699,7 @@ int megasas_irqpoll(struct irq_poll *irqpoll, int budget)
                irq_poll_complete(irqpoll);
                irq_ctx->irq_poll_scheduled = false;
                enable_irq(irq_ctx->os_irq);
+               complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx);
        }
 
        return num_entries;
@@ -3714,6 +3716,7 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
 {
        struct megasas_instance *instance =
                (struct megasas_instance *)instance_addr;
+       struct megasas_irq_context *irq_ctx = NULL;
        u32 count, MSIxIndex;
 
        count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
@@ -3722,8 +3725,10 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr)
        if (atomic_read(&instance->adprecovery) == MEGASAS_HW_CRITICAL_ERROR)
                return;
 
-       for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++)
-               complete_cmd_fusion(instance, MSIxIndex, NULL);
+       for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++) {
+               irq_ctx = &instance->irq_context[MSIxIndex];
+               complete_cmd_fusion(instance, MSIxIndex, irq_ctx);
+       }
 }
 
 /**