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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Jul 2022 14:35:02 +0000 (16:35 +0200)
[ Upstream commit db212f2eb3fb7f546366777e93c8f54614d39269 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/scsi/qla2xxx/qla_nvme.c

index 42b29f4..1bf3ab1 100644 (file)
@@ -775,7 +775,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);
 
        qla_nvme_fc_transport.max_hw_queues =
            min((uint8_t)(qla_nvme_fc_transport.max_hw_queues),
@@ -786,13 +785,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);