scsi: pm80xx: Make mpi_build_cmd locking consistent
authorpeter chang <dpf@google.com>
Mon, 2 Nov 2020 16:55:25 +0000 (22:25 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 5 Nov 2020 03:55:38 +0000 (22:55 -0500)
Driver submits all internal requests (like abort_task, event acknowledgment
etc.) through inbound queue 0. While submitting those, driver does not
acquire any lock and this may lead to a race when there is an I/O request
coming in on CPU0 and submitted through inbound queue 0.  To avoid this,
lock acquisition has been moved to pm8001_mpi_build_cmd().  All command
submission will go through this path.

Link: https://lore.kernel.org/r/20201102165528.26510-2-Viswas.G@microchip.com.com
Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com>
Signed-off-by: peter chang <dpf@google.com>
Signed-off-by: Viswas G <Viswas.G@microchip.com>
Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com>
Signed-off-by: Radha Ramachandran <radha@google.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm80xx_hwi.c

index 2b7b295..597d7a0 100644 (file)
@@ -1356,12 +1356,19 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
 {
        u32 Header = 0, hpriority = 0, bc = 1, category = 0x02;
        void *pMessage;
-
-       if (pm8001_mpi_msg_free_get(circularQ, pm8001_ha->iomb_size,
-               &pMessage) < 0) {
+       unsigned long flags;
+       int q_index = circularQ - pm8001_ha->inbnd_q_tbl;
+       int rv = -1;
+
+       WARN_ON(q_index >= PM8001_MAX_INB_NUM);
+       spin_lock_irqsave(&circularQ->iq_lock, flags);
+       rv = pm8001_mpi_msg_free_get(circularQ, pm8001_ha->iomb_size,
+                       &pMessage);
+       if (rv < 0) {
                PM8001_IO_DBG(pm8001_ha,
-                       pm8001_printk("No free mpi buffer\n"));
-               return -ENOMEM;
+                             pm8001_printk("No free mpi buffer\n"));
+               rv = -ENOMEM;
+               goto done;
        }
 
        if (nb > (pm8001_ha->iomb_size - sizeof(struct mpi_msg_hdr)))
@@ -1384,7 +1391,9 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
                pm8001_printk("INB Q %x OPCODE:%x , UPDATED PI=%d CI=%d\n",
                        responseQueue, opCode, circularQ->producer_idx,
                        circularQ->consumer_index));
-       return 0;
+done:
+       spin_unlock_irqrestore(&circularQ->iq_lock, flags);
+       return rv;
 }
 
 u32 pm8001_mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg,
index 7593f24..5fe50e0 100644 (file)
@@ -4281,7 +4281,6 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
        char *preq_dma_addr = NULL;
        __le64 tmp_addr;
        u32 i, length;
-       unsigned long flags;
 
        memset(&smp_cmd, 0, sizeof(smp_cmd));
        /*
@@ -4377,10 +4376,8 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
 
        build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag,
                                &smp_cmd, pm8001_ha->smp_exp_mode, length);
-       spin_lock_irqsave(&circularQ->iq_lock, flags);
        rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &smp_cmd,
                        sizeof(smp_cmd), 0);
-       spin_unlock_irqrestore(&circularQ->iq_lock, flags);
        if (rc)
                goto err_out_2;
        return 0;
@@ -4444,7 +4441,6 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
        u64 phys_addr, start_addr, end_addr;
        u32 end_addr_high, end_addr_low;
        struct inbound_queue_table *circularQ;
-       unsigned long flags;
        u32 q_index, cpu_id;
        u32 opc = OPC_INB_SSPINIIOSTART;
        memset(&ssp_cmd, 0, sizeof(ssp_cmd));
@@ -4582,10 +4578,8 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
                        ssp_cmd.esgl = 0;
                }
        }
-       spin_lock_irqsave(&circularQ->iq_lock, flags);
        ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc,
                        &ssp_cmd, sizeof(ssp_cmd), q_index);
-       spin_unlock_irqrestore(&circularQ->iq_lock, flags);
        return ret;
 }
 
@@ -4819,10 +4813,8 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
                        }
                }
        }
-       spin_lock_irqsave(&circularQ->iq_lock, flags);
        ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc,
                        &sata_cmd, sizeof(sata_cmd), q_index);
-       spin_unlock_irqrestore(&circularQ->iq_lock, flags);
        return ret;
 }