scsi: qla2xxx: Prevent command send on chip reset
authorQuinn Tran <qutran@marvell.com>
Tue, 27 Feb 2024 16:41:17 +0000 (22:11 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sun, 10 Mar 2024 22:44:42 +0000 (18:44 -0400)
Currently IOCBs are allowed to push through while chip reset could be in
progress. During chip reset the outstanding_cmds array is cleared
twice. Once when any command on this array is returned as failed and
secondly when the array is initialize to zero. If a command is inserted on
to the array between these intervals, then the command will be lost.  Check
for chip reset before sending IOCB.

Cc: stable@vger.kernel.org
Signed-off-by: Quinn Tran <qutran@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Link: https://lore.kernel.org/r/20240227164127.36465-2-njavali@marvell.com
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c

index a314cfc5b263f223e4548c4647e1d645208db69f..2f456e69da91adc7b5ff2461b47749fbb9d5d091 100644 (file)
@@ -1193,8 +1193,12 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport)
        return rval;
 
 done_free_sp:
-       /* ref: INIT */
-       kref_put(&sp->cmd_kref, qla2x00_sp_release);
+       /*
+        * use qla24xx_async_gnl_sp_done to purge all pending gnl request.
+        * kref_put is call behind the scene.
+        */
+       sp->u.iocb_cmd.u.mbx.in_mb[0] = MBS_COMMAND_ERROR;
+       qla24xx_async_gnl_sp_done(sp, QLA_COMMAND_ERROR);
        fcport->flags &= ~(FCF_ASYNC_SENT);
 done:
        fcport->flags &= ~(FCF_ASYNC_ACTIVE);
index df90169f82440a3f665164e55153d9b560231b4b..0228c90b9fe817a10135321d870634c990c10518 100644 (file)
@@ -2587,6 +2587,33 @@ void
 qla2x00_sp_release(struct kref *kref)
 {
        struct srb *sp = container_of(kref, struct srb, cmd_kref);
+       struct scsi_qla_host *vha = sp->vha;
+
+       switch (sp->type) {
+       case SRB_CT_PTHRU_CMD:
+               /* GPSC & GFPNID use fcport->ct_desc.ct_sns for both req & rsp */
+               if (sp->u.iocb_cmd.u.ctarg.req &&
+                       (!sp->fcport ||
+                        sp->u.iocb_cmd.u.ctarg.req != sp->fcport->ct_desc.ct_sns)) {
+                       dma_free_coherent(&vha->hw->pdev->dev,
+                           sp->u.iocb_cmd.u.ctarg.req_allocated_size,
+                           sp->u.iocb_cmd.u.ctarg.req,
+                           sp->u.iocb_cmd.u.ctarg.req_dma);
+                       sp->u.iocb_cmd.u.ctarg.req = NULL;
+               }
+               if (sp->u.iocb_cmd.u.ctarg.rsp &&
+                       (!sp->fcport ||
+                        sp->u.iocb_cmd.u.ctarg.rsp != sp->fcport->ct_desc.ct_sns)) {
+                       dma_free_coherent(&vha->hw->pdev->dev,
+                           sp->u.iocb_cmd.u.ctarg.rsp_allocated_size,
+                           sp->u.iocb_cmd.u.ctarg.rsp,
+                           sp->u.iocb_cmd.u.ctarg.rsp_dma);
+                       sp->u.iocb_cmd.u.ctarg.rsp = NULL;
+               }
+               break;
+       default:
+               break;
+       }
 
        sp->free(sp);
 }
@@ -2692,7 +2719,7 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
         */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp) {
-               kfree(fcport);
+               qla2x00_free_fcport(fcport);
                ql_log(ql_log_info, vha, 0x70e6,
                 "SRB allocation failed\n");
                return -ENOMEM;
@@ -2747,6 +2774,7 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
        if (rval != QLA_SUCCESS) {
                /* ref: INIT */
                kref_put(&sp->cmd_kref, qla2x00_sp_release);
+               qla2x00_free_fcport(fcport);
                return QLA_FUNCTION_FAILED;
        }
 
@@ -2756,6 +2784,7 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
            fcport->d_id.b.area, fcport->d_id.b.al_pa);
 
        wait_for_completion(&elsio->u.els_logo.comp);
+       qla2x00_free_fcport(fcport);
 
        /* ref: INIT */
        kref_put(&sp->cmd_kref, qla2x00_sp_release);
@@ -3918,7 +3947,7 @@ qla2x00_start_sp(srb_t *sp)
                return -EAGAIN;
        }
 
-       pkt = __qla2x00_alloc_iocbs(sp->qpair, sp);
+       pkt = qla2x00_alloc_iocbs_ready(sp->qpair, sp);
        if (!pkt) {
                rval = -EAGAIN;
                ql_log(ql_log_warn, vha, 0x700c,