From: Arun Easi <aeasi@xxxxxxxxxxx> Driver registration of localport can race when it happens at the remote port discovery time. Fix this by calling the registration under a mutex. Reported-by: Marco Patalano <mpatalan@xxxxxxxxxx> Tested-by: Marco Patalano <mpatalan@xxxxxxxxxx> Cc: stable@xxxxxxxxxxxxxxx Fixes: e84067d74301 ("scsi: qla2xxx: Add FC-NVMe F/W initialization and transport registration") Signed-off-by: Arun Easi <aeasi@xxxxxxxxxxx> Signed-off-by: Nilesh Javali <njavali@xxxxxxxxxxx> Reviewed-by: Himanshu Madhani <himanshu.madhani@xxxxxxxxxx> --- drivers/scsi/qla2xxx/qla_nvme.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 5723082d94d6..3bf5cbd754a7 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -782,8 +782,6 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha) ha = vha->hw; tmpl = &qla_nvme_fc_transport; - WARN_ON(vha->nvme_local_port); - if (ql2xnvme_queues < MIN_NVME_HW_QUEUES || ql2xnvme_queues > MAX_NVME_HW_QUEUES) { ql_log(ql_log_warn, vha, 0xfffd, "ql2xnvme_queues=%d is out of range(MIN:%d - MAX:%d). Resetting ql2xnvme_queues to:%d\n", @@ -797,7 +795,7 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha) (uint8_t)(ha->max_qpairs ? ha->max_qpairs : 1)); ql_log(ql_log_info, vha, 0xfffb, - "Number of NVME queues used for this port: %d\n", + "Number of NVME queues used for this port: %d\n", qla_nvme_fc_transport.max_hw_queues); pinfo.node_name = wwn_to_u64(vha->node_name); @@ -805,13 +803,25 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha) pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR; pinfo.port_id = vha->d_id.b24; - ql_log(ql_log_info, vha, 0xffff, - "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n", - pinfo.node_name, pinfo.port_name, pinfo.port_id); - qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary; - - ret = nvme_fc_register_localport(&pinfo, tmpl, - get_device(&ha->pdev->dev), &vha->nvme_local_port); + mutex_lock(&ha->vport_lock); + /* + * Check again for nvme_local_port to see if any other thread raced + * with this one and finished registration. + */ + if (!vha->nvme_local_port) { + ql_log(ql_log_info, vha, 0xffff, + "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n", + pinfo.node_name, pinfo.port_name, pinfo.port_id); + qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary; + + ret = nvme_fc_register_localport(&pinfo, tmpl, + get_device(&ha->pdev->dev), + &vha->nvme_local_port); + mutex_unlock(&ha->vport_lock); + } else { + mutex_unlock(&ha->vport_lock); + return 0; + } if (ret) { ql_log(ql_log_warn, vha, 0xffff, "register_localport failed: ret=%x\n", ret); -- 2.19.0.rc0