From fa4cb77a8708209216494f37c5cc34fe66af5cc2 Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Mon, 9 May 2022 22:52:32 +0300 Subject: [PATCH] qla2x00t-32gbit: Fix crash during deregistering an NPIV port NPIV port deregistering processing is different from physical port processing. We use the same handling for both of them, which causes the crash when it's an NPIV port. Hence separate the common processing logic depending on the type of port. Reported-by: Rob Turk --- qla2x00t-32gbit/qla2x00-target/qla_tgt.c | 11 +++- qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c | 52 +++++++++++++++---- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/qla2x00t-32gbit/qla2x00-target/qla_tgt.c b/qla2x00t-32gbit/qla2x00-target/qla_tgt.c index 03fb20cc8..36b289603 100644 --- a/qla2x00t-32gbit/qla2x00-target/qla_tgt.c +++ b/qla2x00t-32gbit/qla2x00-target/qla_tgt.c @@ -47,9 +47,10 @@ size_t qlt_add_vtarget(u64 port_name, u64 node_name, u64 parent_host) { + struct fc_vport *vport; struct Scsi_Host *shost = NULL; + scsi_qla_host_t *vha = NULL, *npiv_vha; struct qla_tgt *tgt; - scsi_qla_host_t *vha = NULL; struct fc_vport_identifiers vid; uint8_t parent_wwn[WWN_SIZE]; @@ -78,8 +79,14 @@ size_t qlt_add_vtarget(u64 port_name, u64 node_name, u64 parent_host) vid.disable = false; /* always enabled */ /* We only allow support on Channel 0 !!! */ - if (!fc_vport_create(shost, 0, &vid)) + vport = fc_vport_create(shost, 0, &vid); + if (!vport) { + pr_err("fc_vport_create failed for qla2xxx_npiv\n"); return -EINVAL; + } + + npiv_vha = (struct scsi_qla_host *) vport->dd_data; + scsi_host_get(npiv_vha->host); return 0; } diff --git a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c index 5e1e35cb2..b208cc753 100644 --- a/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c +++ b/qla2x00t-32gbit/qla2x00-target/scst_qla2xxx.c @@ -1437,6 +1437,39 @@ static void sqa_qla2xxx_remove_target(struct scsi_qla_host *vha) scst_unregister_target(sqa_tgt->scst_tgt); TRACE_EXIT(); } + +static void sqa_qla2xxx_drop_lport(struct qla_tgt *tgt) +{ + struct scsi_qla_host *vha = tgt->vha; + + TRACE_ENTRY(); + + if (vha->vha_tgt.qla_tgt->tgt_stop && + !vha->vha_tgt.qla_tgt->tgt_stopped) { + PRINT_INFO("sqatgt(%ld/%d): calling qlt_stop_phase2.\n", + vha->host_no, vha->vp_idx); + qlt_stop_phase2(vha->vha_tgt.qla_tgt); + } + + qlt_lport_deregister(vha); + + TRACE_EXIT(); +} + +static void sqa_qla2xxx_npiv_drop_lport(struct qla_tgt *tgt) +{ + struct scsi_qla_host *npiv_vha = tgt->vha; + struct qla_hw_data *ha = npiv_vha->hw; + scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + + TRACE_ENTRY(); + + scsi_host_put(npiv_vha->host); + scsi_host_put(base_vha->host); + + TRACE_EXIT(); +} + /* * Must be called under tgt_host_action_mutex or sqa_unreg_rwsem write * locked. @@ -1450,21 +1483,20 @@ static int sqa_target_release(struct scst_tgt *scst_tgt) TRACE_ENTRY(); if (vha->vha_tgt.target_lport_ptr) { + if (!vha->vha_tgt.qla_tgt->tgt_stop && - !vha->vha_tgt.qla_tgt->tgt_stopped) { + !vha->vha_tgt.qla_tgt->tgt_stopped) { PRINT_INFO("sqatgt(%ld:%d: calling qlt_stop_phase1.\n", - vha->host_no, vha->vp_idx); + vha->host_no, vha->vp_idx); qlt_stop_phase1(vha->vha_tgt.qla_tgt); } - if (vha->vha_tgt.qla_tgt->tgt_stop && - !vha->vha_tgt.qla_tgt->tgt_stopped) { - PRINT_INFO("sqatgt(%ld/%d): calling qlt_stop_phase2.\n", - vha->host_no, vha->vp_idx); - qlt_stop_phase2(vha->vha_tgt.qla_tgt); - } - qlt_lport_deregister(tgt->vha); + if (vha->vp_idx) + sqa_qla2xxx_npiv_drop_lport(tgt); + else + sqa_qla2xxx_drop_lport(tgt); } + scst_tgt_set_tgt_priv(scst_tgt, NULL); mutex_lock(&sqa_mutex); @@ -1473,7 +1505,7 @@ static int sqa_target_release(struct scst_tgt *scst_tgt) mutex_unlock(&sqa_mutex); TRACE(TRACE_MGMT, "sqatgt(%ld/%d): Target release finished sqa_tgt %p", - vha->host_no, tgt->vha->vp_idx, sqa_tgt); + vha->host_no, vha->vp_idx, sqa_tgt); kfree(sqa_tgt);