scsi: qla2xxx: Implement ref count for SRB
authorSaurav Kashyap <skashyap@marvell.com>
Mon, 10 Jan 2022 05:02:03 +0000 (21:02 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 25 Jan 2022 04:57:30 +0000 (23:57 -0500)
The timeout handler and the done function are racing. When
qla2x00_async_iocb_timeout() starts to run it can be preempted by the
normal response path (via the firmware?). qla24xx_async_gpsc_sp_done()
releases the SRB unconditionally. When scheduling back to
qla2x00_async_iocb_timeout() qla24xx_async_abort_cmd() will access an freed
sp->qpair pointer:

  qla2xxx [0000:83:00.0]-2871:0: Async-gpsc timeout - hdl=63d portid=234500 50:06:0e:80:08:77:b6:21.
  qla2xxx [0000:83:00.0]-2853:0: Async done-gpsc res 0, WWPN 50:06:0e:80:08:77:b6:21
  qla2xxx [0000:83:00.0]-2854:0: Async-gpsc OUT WWPN 20:45:00:27:f8:75:33:00 speeds=2c00 speed=0400.
  qla2xxx [0000:83:00.0]-28d8:0: qla24xx_handle_gpsc_event 50:06:0e:80:08:77:b6:21 DS 7 LS 6 rc 0 login 1|1 rscn 1|0 lid 5
  BUG: unable to handle kernel NULL pointer dereference at 0000000000000004
  IP: qla24xx_async_abort_cmd+0x1b/0x1c0 [qla2xxx]

Obvious solution to this is to introduce a reference counter. One reference
is taken for the normal code path (the 'good' case) and one for the timeout
path. As we always race between the normal good case and the timeout/abort
handler we need to serialize it. Also we cannot assume any order between
the handlers. Since this is slow path we can use proper synchronization via
locks.

When we are able to cancel a timer (del_timer returns 1) we know there
can't be any error handling in progress because the timeout handler hasn't
expired yet, thus we can safely decrement the refcounter by one.

If we are not able to cancel the timer, we know an abort handler is
running. We have to make sure we call sp->done() in the abort handlers
before calling kref_put().

Link: https://lore.kernel.org/r/20220110050218.3958-3-njavali@marvell.com
Cc: stable@vger.kernel.org
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Co-developed-by: Daniel Wagner <dwagner@suse.de>
Signed-off-by: Daniel Wagner <dwagner@suse.de>
Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
13 files changed:
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_edif.c
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_mr.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c

index 9da8034..c2f00f0 100644 (file)
@@ -29,7 +29,8 @@ void qla2x00_bsg_job_done(srb_t *sp, int res)
            "%s: sp hdl %x, result=%x bsg ptr %p\n",
            __func__, sp->handle, res, bsg_job);
 
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 
        bsg_reply->result = res;
        bsg_job_done(bsg_job, bsg_reply->result,
@@ -3013,7 +3014,8 @@ qla24xx_bsg_timeout(struct bsg_job *bsg_job)
 
 done:
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        return 0;
 }
 
index 9ebf4a2..a5fc01b 100644 (file)
@@ -726,6 +726,11 @@ typedef struct srb {
         * code.
         */
        void (*put_fn)(struct kref *kref);
+
+       /*
+        * Report completion for asynchronous commands.
+        */
+       void (*async_done)(struct srb *sp, int res);
 } srb_t;
 
 #define GET_CMD_SP(sp) (sp->u.scmd.cmd)
index 53d2b85..c04957c 100644 (file)
@@ -2146,7 +2146,8 @@ edif_doorbell_show(struct device *dev, struct device_attribute *attr,
 
 static void qla_noop_sp_done(srb_t *sp, int res)
 {
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 /*
index 5056564..3f8b8bb 100644 (file)
@@ -333,6 +333,7 @@ extern int qla24xx_get_one_block_sg(uint32_t, struct qla2_sgx *, uint32_t *);
 extern int qla24xx_configure_prot_mode(srb_t *, uint16_t *);
 extern int qla24xx_issue_sa_replace_iocb(scsi_qla_host_t *vha,
        struct qla_work_evt *e);
+void qla2x00_sp_release(struct kref *kref);
 
 /*
  * Global Function Prototypes in qla_mbx.c source file.
index 744eb31..a812f4a 100644 (file)
@@ -529,7 +529,6 @@ static void qla2x00_async_sns_sp_done(srb_t *sp, int rc)
                if (!e)
                        goto err2;
 
-               del_timer(&sp->u.iocb_cmd.timer);
                e->u.iosb.sp = sp;
                qla2x00_post_work(vha, e);
                return;
@@ -556,8 +555,8 @@ err2:
                        sp->u.iocb_cmd.u.ctarg.rsp = NULL;
                }
 
-               sp->free(sp);
-
+               /* ref: INIT */
+               kref_put(&sp->cmd_kref, qla2x00_sp_release);
                return;
        }
 
@@ -592,6 +591,7 @@ static int qla_async_rftid(scsi_qla_host_t *vha, port_id_t *d_id)
        if (!vha->flags.online)
                goto done;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -652,7 +652,8 @@ static int qla_async_rftid(scsi_qla_host_t *vha, port_id_t *d_id)
        }
        return rval;
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        return rval;
 }
@@ -687,6 +688,7 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id,
        srb_t *sp;
        struct ct_sns_pkt *ct_sns;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -747,7 +749,8 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id,
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        return rval;
 }
@@ -777,6 +780,7 @@ static int qla_async_rnnid(scsi_qla_host_t *vha, port_id_t *d_id,
        srb_t *sp;
        struct ct_sns_pkt *ct_sns;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -836,7 +840,8 @@ static int qla_async_rnnid(scsi_qla_host_t *vha, port_id_t *d_id,
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        return rval;
 }
@@ -882,6 +887,7 @@ static int qla_async_rsnn_nn(scsi_qla_host_t *vha)
        srb_t *sp;
        struct ct_sns_pkt *ct_sns;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -947,7 +953,8 @@ static int qla_async_rsnn_nn(scsi_qla_host_t *vha)
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        return rval;
 }
@@ -2887,7 +2894,8 @@ static void qla24xx_async_gpsc_sp_done(srb_t *sp, int res)
        qla24xx_handle_gpsc_event(vha, &ea);
 
 done:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport)
@@ -2899,6 +2907,7 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport)
        if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT))
                return rval;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -2938,7 +2947,8 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport)
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        return rval;
 }
@@ -2987,7 +2997,8 @@ void qla24xx_sp_unmap(scsi_qla_host_t *vha, srb_t *sp)
                break;
        }
 
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea)
@@ -3126,13 +3137,15 @@ static void qla2x00_async_gpnid_sp_done(srb_t *sp, int res)
        if (res) {
                if (res == QLA_FUNCTION_TIMEOUT) {
                        qla24xx_post_gpnid_work(sp->vha, &ea.id);
-                       sp->free(sp);
+                       /* ref: INIT */
+                       kref_put(&sp->cmd_kref, qla2x00_sp_release);
                        return;
                }
        } else if (sp->gen1) {
                /* There was another RSCN for this Nport ID */
                qla24xx_post_gpnid_work(sp->vha, &ea.id);
-               sp->free(sp);
+               /* ref: INIT */
+               kref_put(&sp->cmd_kref, qla2x00_sp_release);
                return;
        }
 
@@ -3153,7 +3166,8 @@ static void qla2x00_async_gpnid_sp_done(srb_t *sp, int res)
                                  sp->u.iocb_cmd.u.ctarg.rsp_dma);
                sp->u.iocb_cmd.u.ctarg.rsp = NULL;
 
-               sp->free(sp);
+               /* ref: INIT */
+               kref_put(&sp->cmd_kref, qla2x00_sp_release);
                return;
        }
 
@@ -3173,6 +3187,7 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id)
        if (!vha->flags.online)
                goto done;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -3189,7 +3204,8 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id)
                if (tsp->u.iocb_cmd.u.ctarg.id.b24 == id->b24) {
                        tsp->gen1++;
                        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
-                       sp->free(sp);
+                       /* ref: INIT */
+                       kref_put(&sp->cmd_kref, qla2x00_sp_release);
                        goto done;
                }
        }
@@ -3259,8 +3275,8 @@ done_free_sp:
                        sp->u.iocb_cmd.u.ctarg.rsp_dma);
                sp->u.iocb_cmd.u.ctarg.rsp = NULL;
        }
-
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        return rval;
 }
@@ -3315,7 +3331,8 @@ void qla24xx_async_gffid_sp_done(srb_t *sp, int res)
        ea.rc = res;
 
        qla24xx_handle_gffid_event(vha, &ea);
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 /* Get FC4 Feature with Nport ID. */
@@ -3328,6 +3345,7 @@ int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport)
        if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT))
                return rval;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp)
                return rval;
@@ -3366,7 +3384,8 @@ int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport)
 
        return rval;
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        fcport->flags &= ~FCF_ASYNC_SENT;
        return rval;
 }
@@ -3753,7 +3772,6 @@ static void qla2x00_async_gpnft_gnnft_sp_done(srb_t *sp, int res)
            "Async done-%s res %x FC4Type %x\n",
            sp->name, res, sp->gen2);
 
-       del_timer(&sp->u.iocb_cmd.timer);
        sp->rc = res;
        if (res) {
                unsigned long flags;
@@ -3921,8 +3939,8 @@ done_free_sp:
                    sp->u.iocb_cmd.u.ctarg.rsp_dma);
                sp->u.iocb_cmd.u.ctarg.rsp = NULL;
        }
-
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 
        spin_lock_irqsave(&vha->work_lock, flags);
        vha->scan.scan_flags &= ~SF_SCANNING;
@@ -3974,9 +3992,12 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp)
                ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff,
                    "%s: Performing FCP Scan\n", __func__);
 
-               if (sp)
-                       sp->free(sp); /* should not happen */
+               if (sp) {
+                       /* ref: INIT */
+                       kref_put(&sp->cmd_kref, qla2x00_sp_release);
+               }
 
+               /* ref: INIT */
                sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
                if (!sp) {
                        spin_lock_irqsave(&vha->work_lock, flags);
@@ -4021,6 +4042,7 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp)
                            sp->u.iocb_cmd.u.ctarg.req,
                            sp->u.iocb_cmd.u.ctarg.req_dma);
                        sp->u.iocb_cmd.u.ctarg.req = NULL;
+                       /* ref: INIT */
                        qla2x00_rel_sp(sp);
                        return rval;
                }
@@ -4083,7 +4105,8 @@ done_free_sp:
                sp->u.iocb_cmd.u.ctarg.rsp = NULL;
        }
 
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 
        spin_lock_irqsave(&vha->work_lock, flags);
        vha->scan.scan_flags &= ~SF_SCANNING;
@@ -4147,7 +4170,8 @@ static void qla2x00_async_gnnid_sp_done(srb_t *sp, int res)
 
        qla24xx_handle_gnnid_event(vha, &ea);
 
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport)
@@ -4160,6 +4184,7 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport)
                return rval;
 
        qla2x00_set_fcport_disc_state(fcport, DSC_GNN_ID);
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
        if (!sp)
                goto done;
@@ -4200,7 +4225,8 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport)
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        fcport->flags &= ~FCF_ASYNC_SENT;
 done:
        return rval;
@@ -4274,7 +4300,8 @@ static void qla2x00_async_gfpnid_sp_done(srb_t *sp, int res)
 
        qla24xx_handle_gfpnid_event(vha, &ea);
 
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport)
@@ -4286,6 +4313,7 @@ int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport)
        if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT))
                return rval;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC);
        if (!sp)
                goto done;
@@ -4326,7 +4354,8 @@ int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport)
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        return rval;
 }
index e6f13cb..38c11b7 100644 (file)
@@ -51,6 +51,9 @@ qla2x00_sp_timeout(struct timer_list *t)
        WARN_ON(irqs_disabled());
        iocb = &sp->u.iocb_cmd;
        iocb->timeout(sp);
+
+       /* ref: TMR */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 void qla2x00_sp_free(srb_t *sp)
@@ -125,8 +128,13 @@ static void qla24xx_abort_iocb_timeout(void *data)
        }
        spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
 
-       if (sp->cmd_sp)
+       if (sp->cmd_sp) {
+               /*
+                * This done function should take care of
+                * original command ref: INIT
+                */
                sp->cmd_sp->done(sp->cmd_sp, QLA_OS_TIMER_EXPIRED);
+       }
 
        abt->u.abt.comp_status = cpu_to_le16(CS_TIMEOUT);
        sp->done(sp, QLA_OS_TIMER_EXPIRED);
@@ -140,11 +148,11 @@ static void qla24xx_abort_sp_done(srb_t *sp, int res)
        if (orig_sp)
                qla_wait_nvme_release_cmd_kref(orig_sp);
 
-       del_timer(&sp->u.iocb_cmd.timer);
        if (sp->flags & SRB_WAKEUP_ON_COMP)
                complete(&abt->u.abt.comp);
        else
-               sp->free(sp);
+               /* ref: INIT */
+               kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
@@ -154,6 +162,7 @@ int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
        srb_t *sp;
        int rval = QLA_FUNCTION_FAILED;
 
+       /* ref: INIT for ABTS command */
        sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport,
                                  GFP_ATOMIC);
        if (!sp)
@@ -181,7 +190,8 @@ int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
 
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS) {
-               sp->free(sp);
+               /* ref: INIT */
+               kref_put(&sp->cmd_kref, qla2x00_sp_release);
                return rval;
        }
 
@@ -189,7 +199,8 @@ int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait)
                wait_for_completion(&abt_iocb->u.abt.comp);
                rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
                        QLA_SUCCESS : QLA_ERR_FROM_FW;
-               sp->free(sp);
+               /* ref: INIT */
+               kref_put(&sp->cmd_kref, qla2x00_sp_release);
        }
 
        return rval;
@@ -287,7 +298,8 @@ static void qla2x00_async_login_sp_done(srb_t *sp, int res)
                qla24xx_handle_plogi_done_event(vha, &ea);
        }
 
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int
@@ -306,6 +318,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
                return rval;
        }
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -354,7 +367,8 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        fcport->flags &= ~FCF_ASYNC_SENT;
 done:
        fcport->flags &= ~FCF_ASYNC_ACTIVE;
@@ -366,7 +380,8 @@ static void qla2x00_async_logout_sp_done(srb_t *sp, int res)
        sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
        sp->fcport->login_gen++;
        qlt_logo_completion_handler(sp->fcport, sp->u.iocb_cmd.u.logio.data[0]);
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int
@@ -376,6 +391,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
        int rval = QLA_FUNCTION_FAILED;
 
        fcport->flags |= FCF_ASYNC_SENT;
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -397,7 +413,8 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
        return rval;
@@ -423,7 +440,8 @@ static void qla2x00_async_prlo_sp_done(srb_t *sp, int res)
        if (!test_bit(UNLOADING, &vha->dpc_flags))
                qla2x00_post_async_prlo_done_work(sp->fcport->vha, sp->fcport,
                    lio->u.logio.data);
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int
@@ -433,6 +451,7 @@ qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport)
        int rval;
 
        rval = QLA_FUNCTION_FAILED;
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -454,7 +473,8 @@ qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport)
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        fcport->flags &= ~FCF_ASYNC_ACTIVE;
        return rval;
@@ -539,8 +559,8 @@ static void qla2x00_async_adisc_sp_done(srb_t *sp, int res)
        ea.sp = sp;
 
        qla24xx_handle_adisc_event(vha, &ea);
-
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int
@@ -555,6 +575,7 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
                return rval;
 
        fcport->flags |= FCF_ASYNC_SENT;
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -582,7 +603,8 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
        qla2x00_post_async_adisc_work(vha, fcport, data);
@@ -1063,7 +1085,8 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, int res)
        }
        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport)
@@ -1093,6 +1116,7 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport)
        vha->gnl.sent = 1;
        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -1125,7 +1149,8 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport)
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        fcport->flags &= ~(FCF_ASYNC_ACTIVE | FCF_ASYNC_SENT);
        return rval;
@@ -1171,7 +1196,7 @@ done:
        dma_pool_free(ha->s_dma_pool, sp->u.iocb_cmd.u.mbx.in,
                sp->u.iocb_cmd.u.mbx.in_dma);
 
-       sp->free(sp);
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int qla24xx_post_prli_work(struct scsi_qla_host *vha, fc_port_t *fcport)
@@ -1216,7 +1241,7 @@ static void qla2x00_async_prli_sp_done(srb_t *sp, int res)
                qla24xx_handle_prli_done_event(vha, &ea);
        }
 
-       sp->free(sp);
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int
@@ -1274,7 +1299,8 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport)
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        fcport->flags &= ~FCF_ASYNC_SENT;
        return rval;
 }
@@ -1359,7 +1385,7 @@ done_free_sp:
        if (pd)
                dma_pool_free(ha->s_dma_pool, pd, pd_dma);
 
-       sp->free(sp);
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        fcport->flags &= ~FCF_ASYNC_SENT;
 done:
        fcport->flags &= ~FCF_ASYNC_ACTIVE;
@@ -1945,6 +1971,7 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
        srb_t *sp;
        int rval = QLA_FUNCTION_FAILED;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -1988,7 +2015,8 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
        }
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        fcport->flags &= ~FCF_ASYNC_SENT;
 done:
        return rval;
index 5f3b799..db17f7f 100644 (file)
@@ -184,6 +184,8 @@ static void qla2xxx_init_sp(srb_t *sp, scsi_qla_host_t *vha,
        sp->vha = vha;
        sp->qpair = qpair;
        sp->cmd_type = TYPE_SRB;
+       /* ref : INIT - normal flow */
+       kref_init(&sp->cmd_kref);
        INIT_LIST_HEAD(&sp->elem);
 }
 
index 95aae9a..7dd8221 100644 (file)
@@ -2560,6 +2560,14 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
        }
 }
 
+void
+qla2x00_sp_release(struct kref *kref)
+{
+       struct srb *sp = container_of(kref, struct srb, cmd_kref);
+
+       sp->free(sp);
+}
+
 void
 qla2x00_init_async_sp(srb_t *sp, unsigned long tmo,
                     void (*done)(struct srb *sp, int res))
@@ -2655,7 +2663,9 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
               return -ENOMEM;
        }
 
-       /* Alloc SRB structure */
+       /* Alloc SRB structure
+        * ref: INIT
+        */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp) {
                kfree(fcport);
@@ -2687,7 +2697,8 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
                            GFP_KERNEL);
 
        if (!elsio->u.els_logo.els_logo_pyld) {
-               sp->free(sp);
+               /* ref: INIT */
+               kref_put(&sp->cmd_kref, qla2x00_sp_release);
                return QLA_FUNCTION_FAILED;
        }
 
@@ -2710,7 +2721,8 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
 
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS) {
-               sp->free(sp);
+               /* ref: INIT */
+               kref_put(&sp->cmd_kref, qla2x00_sp_release);
                return QLA_FUNCTION_FAILED;
        }
 
@@ -2721,7 +2733,8 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
 
        wait_for_completion(&elsio->u.els_logo.comp);
 
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        return rval;
 }
 
@@ -2854,7 +2867,6 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res)
            sp->name, res, sp->handle, fcport->d_id.b24, fcport->port_name);
 
        fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE);
-       del_timer(&sp->u.iocb_cmd.timer);
 
        if (sp->flags & SRB_WAKEUP_ON_COMP)
                complete(&lio->u.els_plogi.comp);
@@ -2964,7 +2976,8 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res)
                        struct srb_iocb *elsio = &sp->u.iocb_cmd;
 
                        qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi);
-                       sp->free(sp);
+                       /* ref: INIT */
+                       kref_put(&sp->cmd_kref, qla2x00_sp_release);
                        return;
                }
                e->u.iosb.sp = sp;
@@ -2982,7 +2995,9 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
        int rval = QLA_SUCCESS;
        void    *ptr, *resp_ptr;
 
-       /* Alloc SRB structure */
+       /* Alloc SRB structure
+        * ref: INIT
+        */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp) {
                ql_log(ql_log_info, vha, 0x70e6,
@@ -3071,7 +3086,8 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
 out:
        fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
        qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi);
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        return rval;
 }
@@ -3882,8 +3898,15 @@ qla2x00_start_sp(srb_t *sp)
                break;
        }
 
-       if (sp->start_timer)
+       if (sp->start_timer) {
+               /* ref: TMR timer ref
+                * this code should be just before start_iocbs function
+                * This will make sure that caller function don't to do
+                * kref_put even on failure
+                */
+               kref_get(&sp->cmd_kref);
                add_timer(&sp->u.iocb_cmd.timer);
+       }
 
        wmb();
        qla2x00_start_iocbs(vha, qp->req);
index 2aacd36..38e0f02 100644 (file)
@@ -6479,6 +6479,7 @@ int qla24xx_send_mb_cmd(struct scsi_qla_host *vha, mbx_cmd_t *mcp)
        if (!vha->hw->flags.fw_started)
                goto done;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -6524,7 +6525,8 @@ int qla24xx_send_mb_cmd(struct scsi_qla_host *vha, mbx_cmd_t *mcp)
        }
 
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        return rval;
 }
index c4a967c..e6b5c4c 100644 (file)
@@ -965,6 +965,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
        if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
                return QLA_PARAMETER_ERROR;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(base_vha, NULL, GFP_KERNEL);
        if (!sp)
                return rval;
@@ -1007,6 +1008,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
                break;
        }
 done:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        return rval;
 }
index e3ae089..f726eb8 100644 (file)
@@ -1787,6 +1787,7 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
        struct register_host_info *preg_hsi;
        struct new_utsname *p_sysid = NULL;
 
+       /* ref: INIT */
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp)
                goto done;
@@ -1973,7 +1974,8 @@ done_unmap_req:
                dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.req_len,
                    fdisc->u.fxiocb.req_addr, fdisc->u.fxiocb.req_dma_handle);
 done_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        return rval;
 }
index abcd309..0a7b00d 100644 (file)
@@ -728,7 +728,8 @@ void qla2x00_sp_compl(srb_t *sp, int res)
        struct scsi_cmnd *cmd = GET_CMD_SP(sp);
        struct completion *comp = sp->comp;
 
-       sp->free(sp);
+       /* kref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        cmd->result = res;
        CMD_SP(cmd) = NULL;
        scsi_done(cmd);
@@ -819,7 +820,8 @@ void qla2xxx_qpair_sp_compl(srb_t *sp, int res)
        struct scsi_cmnd *cmd = GET_CMD_SP(sp);
        struct completion *comp = sp->comp;
 
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
        cmd->result = res;
        CMD_SP(cmd) = NULL;
        scsi_done(cmd);
@@ -919,6 +921,7 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
                goto qc24_target_busy;
 
        sp = scsi_cmd_priv(cmd);
+       /* ref: INIT */
        qla2xxx_init_sp(sp, vha, vha->hw->base_qpair, fcport);
 
        sp->u.scmd.cmd = cmd;
@@ -938,7 +941,8 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
        return 0;
 
 qc24_host_busy_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 
 qc24_target_busy:
        return SCSI_MLQUEUE_TARGET_BUSY;
@@ -1008,6 +1012,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
                goto qc24_target_busy;
 
        sp = scsi_cmd_priv(cmd);
+       /* ref: INIT */
        qla2xxx_init_sp(sp, vha, qpair, fcport);
 
        sp->u.scmd.cmd = cmd;
@@ -1026,7 +1031,8 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
        return 0;
 
 qc24_host_busy_free_sp:
-       sp->free(sp);
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 
 qc24_target_busy:
        return SCSI_MLQUEUE_TARGET_BUSY;
index 83c8c55..b0990f2 100644 (file)
@@ -620,7 +620,7 @@ static void qla2x00_async_nack_sp_done(srb_t *sp, int res)
        }
        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
 
-       sp->free(sp);
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 }
 
 int qla24xx_async_notify_ack(scsi_qla_host_t *vha, fc_port_t *fcport,
@@ -672,7 +672,7 @@ int qla24xx_async_notify_ack(scsi_qla_host_t *vha, fc_port_t *fcport,
        return rval;
 
 done_free_sp:
-       sp->free(sp);
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
 done:
        fcport->flags &= ~FCF_ASYNC_SENT;
        return rval;