diff mbox series

[02/16] qla2xxx: Implement ref count for srb

Message ID 20211224070712.17905-3-njavali@marvell.com
State Superseded
Headers show
Series qla2xxx misc bug fixes and features | expand

Commit Message

Nilesh Javali Dec. 24, 2021, 7:06 a.m. UTC
From: Saurav Kashyap <skashyap@marvell.com>

Fix race between timeout handler and completion handler by introducing
a reference counter. One reference is taken for the normal code path
(the 'good case') and one for the timeout path.

Cc: stable@vger.kernel.org
Signed-off-by: Daniel Wagner <dwagner@suse.de>
Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
---
 drivers/scsi/qla2xxx/qla_bsg.c    |  6 ++-
 drivers/scsi/qla2xxx/qla_def.h    |  5 ++
 drivers/scsi/qla2xxx/qla_edif.c   |  3 +-
 drivers/scsi/qla2xxx/qla_gbl.h    |  1 +
 drivers/scsi/qla2xxx/qla_gs.c     | 85 +++++++++++++++++++++----------
 drivers/scsi/qla2xxx/qla_init.c   | 70 +++++++++++++++++--------
 drivers/scsi/qla2xxx/qla_inline.h |  2 +
 drivers/scsi/qla2xxx/qla_iocb.c   | 41 +++++++++++----
 drivers/scsi/qla2xxx/qla_mbx.c    |  4 +-
 drivers/scsi/qla2xxx/qla_mid.c    |  4 +-
 drivers/scsi/qla2xxx/qla_mr.c     |  4 +-
 drivers/scsi/qla2xxx/qla_os.c     | 14 +++--
 drivers/scsi/qla2xxx/qla_target.c |  4 +-
 13 files changed, 173 insertions(+), 70 deletions(-)

Comments

Daniel Wagner Dec. 28, 2021, 11:12 a.m. UTC | #1
Hi Saurav

On Thu, Dec 23, 2021 at 11:06:58PM -0800, Nilesh Javali wrote:
> From: Saurav Kashyap <skashyap@marvell.com>
> 
> Fix race between timeout handler and completion handler by introducing
> a reference counter. One reference is taken for the normal code path
> (the 'good case') and one for the timeout path.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>

Thanks picking the patch up and getting it into shape.  Highly
appreciated!

FWIW,

Reviewed-by: Daniel Wagner <dwagner@suse.de>

Daniel
Saurav Kashyap Dec. 28, 2021, 11:31 a.m. UTC | #2
Hi Daniel,

> -----Original Message-----
> From: Daniel Wagner <dwagner@suse.de>
> Sent: Tuesday, December 28, 2021 4:42 PM
> To: Nilesh Javali <njavali@marvell.com>
> Cc: martin.petersen@oracle.com; linux-scsi@vger.kernel.org; GR-QLogic-
> Storage-Upstream <GR-QLogic-Storage-Upstream@marvell.com>
> Subject: Re: [PATCH 02/16] qla2xxx: Implement ref count for srb
> 
> Hi Saurav
> 
> On Thu, Dec 23, 2021 at 11:06:58PM -0800, Nilesh Javali wrote:
> > From: Saurav Kashyap <skashyap@marvell.com>
> >
> > Fix race between timeout handler and completion handler by introducing
> > a reference counter. One reference is taken for the normal code path
> > (the 'good case') and one for the timeout path.
> >
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Daniel Wagner <dwagner@suse.de>
> > Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
> > Signed-off-by: Nilesh Javali <njavali@marvell.com>
> 
> Thanks picking the patch up and getting it into shape.  Highly
> appreciated!

Most welcome.

Thanks,
~Saurav
> 
> FWIW,
> 
> Reviewed-by: Daniel Wagner <dwagner@suse.de>
> 
> Daniel
Himanshu Madhani Jan. 3, 2022, 12:32 a.m. UTC | #3
> On Dec 23, 2021, at 11:06 PM, Nilesh Javali <njavali@marvell.com> wrote:
> 
> From: Saurav Kashyap <skashyap@marvell.com>
> 
> Fix race between timeout handler and completion handler by introducing
> a reference counter. One reference is taken for the normal code path
> (the 'good case') and one for the timeout path.
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Daniel Wagner <dwagner@suse.de>
> Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
> Signed-off-by: Nilesh Javali <njavali@marvell.com>
> ---
> drivers/scsi/qla2xxx/qla_bsg.c    |  6 ++-
> drivers/scsi/qla2xxx/qla_def.h    |  5 ++
> drivers/scsi/qla2xxx/qla_edif.c   |  3 +-
> drivers/scsi/qla2xxx/qla_gbl.h    |  1 +
> drivers/scsi/qla2xxx/qla_gs.c     | 85 +++++++++++++++++++++----------
> drivers/scsi/qla2xxx/qla_init.c   | 70 +++++++++++++++++--------
> drivers/scsi/qla2xxx/qla_inline.h |  2 +
> drivers/scsi/qla2xxx/qla_iocb.c   | 41 +++++++++++----
> drivers/scsi/qla2xxx/qla_mbx.c    |  4 +-
> drivers/scsi/qla2xxx/qla_mid.c    |  4 +-
> drivers/scsi/qla2xxx/qla_mr.c     |  4 +-
> drivers/scsi/qla2xxx/qla_os.c     | 14 +++--
> drivers/scsi/qla2xxx/qla_target.c |  4 +-
> 13 files changed, 173 insertions(+), 70 deletions(-)
> 
> diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> index 9da8034ccad4..c2f00f076f79 100644
> --- a/drivers/scsi/qla2xxx/qla_bsg.c
> +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> @@ -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 */

IMO, There is no need for this comment spread in this patch. Please explain If you think there is need for comment.

> +	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;
> }
> 
> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index 9ebf4a234d9a..a5fc01b4fa96 100644
> --- a/drivers/scsi/qla2xxx/qla_def.h
> +++ b/drivers/scsi/qla2xxx/qla_def.h
> @@ -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)
> diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
> index 53d2b8562027..c04957c363d8 100644
> --- a/drivers/scsi/qla2xxx/qla_edif.c
> +++ b/drivers/scsi/qla2xxx/qla_edif.c
> @@ -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);
> }
> 
> /*
> diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
> index 5056564f0d0c..3f8b8bbabe6d 100644
> --- a/drivers/scsi/qla2xxx/qla_gbl.h
> +++ b/drivers/scsi/qla2xxx/qla_gbl.h
> @@ -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.
> diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
> index 744eb3192056..a812f4a45232 100644
> --- a/drivers/scsi/qla2xxx/qla_gs.c
> +++ b/drivers/scsi/qla2xxx/qla_gs.c
> @@ -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 @@ static void qla2x00_async_sns_sp_done(srb_t *sp, int rc)
> 			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 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id)
> 			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 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *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 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *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;
> }
> diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
> index e6f13cb6fa28..38c11b75f644 100644
> --- a/drivers/scsi/qla2xxx/qla_init.c
> +++ b/drivers/scsi/qla2xxx/qla_init.c
> @@ -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 @@ static void qla24xx_async_gpdb_sp_done(srb_t *sp, int res)
> 	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 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt)
> 	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;
> diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
> index 5f3b7995cc8f..db17f7f410cd 100644
> --- a/drivers/scsi/qla2xxx/qla_inline.h
> +++ b/drivers/scsi/qla2xxx/qla_inline.h
> @@ -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);
> }
> 
> diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
> index 95aae9a9631e..7dd82214d59f 100644
> --- a/drivers/scsi/qla2xxx/qla_iocb.c
> +++ b/drivers/scsi/qla2xxx/qla_iocb.c
> @@ -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);
> diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
> index 2aacd3653245..38e0f02c75e1 100644
> --- a/drivers/scsi/qla2xxx/qla_mbx.c
> +++ b/drivers/scsi/qla2xxx/qla_mbx.c
> @@ -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;
> }
> diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
> index c4a967c96fd6..e6b5c4ccce97 100644
> --- a/drivers/scsi/qla2xxx/qla_mid.c
> +++ b/drivers/scsi/qla2xxx/qla_mid.c
> @@ -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;
> }
> diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
> index e3ae0894c7a8..f726eb8449c5 100644
> --- a/drivers/scsi/qla2xxx/qla_mr.c
> +++ b/drivers/scsi/qla2xxx/qla_mr.c
> @@ -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 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
> 		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;
> }
> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index abcd30917263..0a7b00d165c7 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
> @@ -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;
> diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
> index 83c8c55017d1..b0990f2ee91c 100644
> --- a/drivers/scsi/qla2xxx/qla_target.c
> +++ b/drivers/scsi/qla2xxx/qla_target.c
> @@ -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;
> -- 
> 2.23.1
> 

--
Himanshu Madhani	 Oracle Linux Engineering
Saurav Kashyap Jan. 3, 2022, 3:56 a.m. UTC | #4
Hi Himanshu,

> -----Original Message-----
> From: Himanshu Madhani <himanshu.madhani@oracle.com>
> Sent: Monday, January 3, 2022 6:03 AM
> To: Nilesh Javali <njavali@marvell.com>
> Cc: Martin Petersen <martin.petersen@oracle.com>; linux-
> scsi@vger.kernel.org; GR-QLogic-Storage-Upstream <GR-QLogic-Storage-
> Upstream@marvell.com>
> Subject: Re: [PATCH 02/16] qla2xxx: Implement ref count for srb
> 
> 
> 
> > On Dec 23, 2021, at 11:06 PM, Nilesh Javali <njavali@marvell.com> wrote:
> >
> > From: Saurav Kashyap <skashyap@marvell.com>
> >
> > Fix race between timeout handler and completion handler by introducing
> > a reference counter. One reference is taken for the normal code path
> > (the 'good case') and one for the timeout path.
> >
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Daniel Wagner <dwagner@suse.de>
> > Signed-off-by: Saurav Kashyap <skashyap@marvell.com>
> > Signed-off-by: Nilesh Javali <njavali@marvell.com>
> > ---
> > drivers/scsi/qla2xxx/qla_bsg.c    |  6 ++-
> > drivers/scsi/qla2xxx/qla_def.h    |  5 ++
> > drivers/scsi/qla2xxx/qla_edif.c   |  3 +-
> > drivers/scsi/qla2xxx/qla_gbl.h    |  1 +
> > drivers/scsi/qla2xxx/qla_gs.c     | 85 +++++++++++++++++++++----------
> > drivers/scsi/qla2xxx/qla_init.c   | 70 +++++++++++++++++--------
> > drivers/scsi/qla2xxx/qla_inline.h |  2 +
> > drivers/scsi/qla2xxx/qla_iocb.c   | 41 +++++++++++----
> > drivers/scsi/qla2xxx/qla_mbx.c    |  4 +-
> > drivers/scsi/qla2xxx/qla_mid.c    |  4 +-
> > drivers/scsi/qla2xxx/qla_mr.c     |  4 +-
> > drivers/scsi/qla2xxx/qla_os.c     | 14 +++--
> > drivers/scsi/qla2xxx/qla_target.c |  4 +-
> > 13 files changed, 173 insertions(+), 70 deletions(-)
> >
> > diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
> > index 9da8034ccad4..c2f00f076f79 100644
> > --- a/drivers/scsi/qla2xxx/qla_bsg.c
> > +++ b/drivers/scsi/qla2xxx/qla_bsg.c
> > @@ -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 */
> 
> IMO, There is no need for this comment spread in this patch. Please explain If
> you think there is need for comment.

<SK> Thanks for the review. The sp reference can be taken and released on various paths. These comments make 
life simpler during some ref issue and also make code more understandable. For various scenarios, this comments
helps in determining final reference count and check if its released properly or not.

Thanks,
~Saurav
Daniel Wagner Jan. 4, 2022, 12:32 p.m. UTC | #5
On Mon, Jan 03, 2022 at 03:56:06AM +0000, Saurav Kashyap wrote:
> > > -	sp->free(sp);
> > > +	/* ref: INIT */
> > 
> > IMO, There is no need for this comment spread in this patch. Please explain If
> > you think there is need for comment.
> 
> <SK> Thanks for the review. The sp reference can be taken and released on various paths. These comments make 
> life simpler during some ref issue and also make code more understandable. For various scenarios, this comments
> helps in determining final reference count and check if its released properly or not.

I think the better way to address is to get Sebastian's patch working:

https://lore.kernel.org/all/20131103193308.GA20998@linutronix.de/

Daniel
Himanshu Madhani Jan. 5, 2022, 1:55 a.m. UTC | #6
> On Jan 4, 2022, at 4:32 AM, Daniel Wagner <dwagner@suse.de> wrote:
> 
> On Mon, Jan 03, 2022 at 03:56:06AM +0000, Saurav Kashyap wrote:
>>>> -	sp->free(sp);
>>>> +	/* ref: INIT */
>>> 
>>> IMO, There is no need for this comment spread in this patch. Please explain If
>>> you think there is need for comment.
>> 
>> <SK> Thanks for the review. The sp reference can be taken and released on various paths. These comments make 
>> life simpler during some ref issue and also make code more understandable. For various scenarios, this comments
>> helps in determining final reference count and check if its released properly or not.
> 
> I think the better way to address is to get Sebastian's patch working:
> 
> https://lore.kernel.org/all/20131103193308.GA20998@linutronix.de/
> 
> Daniel

This patch would be good to get it working for debugging reference counter. However, for the current series, I am okay with this patch if better 
description is provided for the comment.

--
Himanshu Madhani	 Oracle Linux Engineering
Saurav Kashyap Jan. 5, 2022, 4:28 a.m. UTC | #7
Hi Himanshu,

> -----Original Message-----
> From: Himanshu Madhani <himanshu.madhani@oracle.com>
> Sent: Wednesday, January 5, 2022 7:26 AM
> To: Daniel Wagner <dwagner@suse.de>
> Cc: Saurav Kashyap <skashyap@marvell.com>; Nilesh Javali
> <njavali@marvell.com>; Martin Petersen <martin.petersen@oracle.com>;
> linux-scsi@vger.kernel.org; GR-QLogic-Storage-Upstream <GR-QLogic-Storage-
> Upstream@marvell.com>; Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Subject: [EXT] Re: [PATCH 02/16] qla2xxx: Implement ref count for srb
> 
> External Email
> 
> ----------------------------------------------------------------------
> 
> 
> > On Jan 4, 2022, at 4:32 AM, Daniel Wagner <dwagner@suse.de> wrote:
> >
> > On Mon, Jan 03, 2022 at 03:56:06AM +0000, Saurav Kashyap wrote:
> >>>> -	sp->free(sp);
> >>>> +	/* ref: INIT */
> >>>
> >>> IMO, There is no need for this comment spread in this patch. Please explain
> If
> >>> you think there is need for comment.
> >>
> >> <SK> Thanks for the review. The sp reference can be taken and released on
> various paths. These comments make
> >> life simpler during some ref issue and also make code more understandable.
> For various scenarios, this comments
> >> helps in determining final reference count and check if its released properly
> or not.
> >
> > I think the better way to address is to get Sebastian's patch working:
> >
> > https://urldefense.proofpoint.com/v2/url?u=https-
> 3A__lore.kernel.org_all_20131103193308.GA20998-
> 40linutronix.de_&d=DwIFAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=ZHZbmY_LbM3
> DUZK_BDO1OITP3ot_Vkb_5w-
> gas5TBMQ&m=pgQzCrwTlIOgowou6VpA1Ntie8bnWsKW6idQUvbA_vrFvKwgX-
> Nh8y6xHCE6ek37&s=6cEa2Qr6Pg9kxgvIV7vOvya2xWBK39Zr5XJygiIk5vw&e=
> >
> > Daniel
> 
> This patch would be good to get it working for debugging reference counter.
> However, for the current series, I am okay with this patch if better
> description is provided for the comment.


Thanks for review, will update the description.

Thanks,
~Saurav
> 
> --
> Himanshu Madhani	 Oracle Linux Engineering
diff mbox series

Patch

diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 9da8034ccad4..c2f00f076f79 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -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;
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 9ebf4a234d9a..a5fc01b4fa96 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -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)
diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
index 53d2b8562027..c04957c363d8 100644
--- a/drivers/scsi/qla2xxx/qla_edif.c
+++ b/drivers/scsi/qla2xxx/qla_edif.c
@@ -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);
 }
 
 /*
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 5056564f0d0c..3f8b8bbabe6d 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -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.
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 744eb3192056..a812f4a45232 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -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 @@  static void qla2x00_async_sns_sp_done(srb_t *sp, int rc)
 			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 @@  int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id)
 			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 @@  static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *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 @@  int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *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;
 }
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index e6f13cb6fa28..38c11b75f644 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -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 @@  static void qla24xx_async_gpdb_sp_done(srb_t *sp, int res)
 	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 @@  int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt)
 	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;
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 5f3b7995cc8f..db17f7f410cd 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -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);
 }
 
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 95aae9a9631e..7dd82214d59f 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -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);
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 2aacd3653245..38e0f02c75e1 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -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;
 }
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index c4a967c96fd6..e6b5c4ccce97 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -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;
 }
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index e3ae0894c7a8..f726eb8449c5 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -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 @@  qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type)
 		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;
 }
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index abcd30917263..0a7b00d165c7 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -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;
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 83c8c55017d1..b0990f2ee91c 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -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;