From: Saurav Kashyap <skashyap@xxxxxxxxxxx> commit 49b729f58e7a98a006a8a0c1dcca8a1a4f58d2a8 upstream. This done routine will delete the timer and check for its return value and decrease the reference count accordingly. This prevents boot hangs reported after commit 31e6cdbe0eae ("scsi: qla2xxx: Implement ref count for SRB") was merged. Link: https://lore.kernel.org/r/20220208093946.4471-1-njavali@xxxxxxxxxxx Fixes: 31e6cdbe0eae ("scsi: qla2xxx: Implement ref count for SRB") Reported-by: Ewan Milne <emilne@xxxxxxxxxx> Tested-by: Ewan D. Milne <emilne@xxxxxxxxxx> Reviewed-by: Himanshu Madhani <himanshu.madhani@xxxxxxxxxx> Signed-off-by: Saurav Kashyap <skashyap@xxxxxxxxxxx> Signed-off-by: Nilesh Javali <njavali@xxxxxxxxxxx> Signed-off-by: Martin K. Petersen <martin.petersen@xxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/scsi/qla2xxx/qla_iocb.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2560,6 +2560,20 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mg } } +static void +qla2x00_async_done(struct srb *sp, int res) +{ + if (del_timer(&sp->u.iocb_cmd.timer)) { + /* + * Successfully cancelled the timeout handler + * ref: TMR + */ + if (kref_put(&sp->cmd_kref, qla2x00_sp_release)) + return; + } + sp->async_done(sp, res); +} + void qla2x00_sp_release(struct kref *kref) { @@ -2573,7 +2587,8 @@ qla2x00_init_async_sp(srb_t *sp, unsigne void (*done)(struct srb *sp, int res)) { timer_setup(&sp->u.iocb_cmd.timer, qla2x00_sp_timeout, 0); - sp->done = done; + sp->done = qla2x00_async_done; + sp->async_done = done; sp->free = qla2x00_sp_free; sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ;