scsi: qla2xxx: Fix loss of NVMe namespaces after driver reload test
authorArun Easi <aeasi@marvell.com>
Thu, 10 Mar 2022 09:25:54 +0000 (01:25 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 15 Mar 2022 04:29:13 +0000 (00:29 -0400)
Driver registration of localport can race when it happens at the remote
port discovery time. Fix this by calling the registration under a mutex.

Link: https://lore.kernel.org/r/20220310092604.22950-4-njavali@marvell.com
Fixes: e84067d74301 ("scsi: qla2xxx: Add FC-NVMe F/W initialization and transport registration")
Cc: stable@vger.kernel.org
Reported-by: Marco Patalano <mpatalan@redhat.com>
Tested-by: Marco Patalano <mpatalan@redhat.com>
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Signed-off-by: Arun Easi <aeasi@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_nvme.c

index 5723082..3bf5cbd 100644 (file)
@@ -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);