ibmvfc_discover_targets() sends both SCSI and NVMe discover-targets MADs
concurrently.  ibmvfc_discover_targets_done() unconditionally set
IBMVFC_HOST_ACTION_ALLOC_TGTS and woke the work thread on the first
completion to arrive.  ibmvfc_alloc_targets() then ran immediately,
reading both channels' disc_buf and num_targets fields.  If the second
MAD had not yet completed, the slower protocol's num_targets was still
zero from the previous discovery cycle, and all targets for that protocol
were silently dropped.  The second completion then attempted to transition
to ALLOC_TGTS again, but the state machine had already advanced, so the
transition was a no-op and ibmvfc_alloc_targets() was never re-run.

Fix this by adding a pending_disc:2 counter to ibmvfc_host.
ibmvfc_discover_targets() sets it to 1 before sending the SCSI MAD and
increments it to 2 before sending the NVMe MAD (skipped when NVMe is not
active, leaving the counter at 1).  ibmvfc_discover_targets_done()
decrements the counter on success and only calls
ibmvfc_set_host_action(ALLOC_TGTS) when it reaches zero, ensuring both
discovery buffers are fully written before target allocation starts.
Error paths already call ibmvfc_retry_host_init() or ibmvfc_link_down()
which reset the state machine, so they do not need to interact with the
counter.

Fixes: bffd16f59061 ("scsi: ibmvfc: add logic for protocol specific fabric 
logins")
Signed-off-by: Tyrel Datwyler <[email protected]>
---
 drivers/scsi/ibmvscsi/ibmvfc-core.c | 6 +++++-
 drivers/scsi/ibmvscsi/ibmvfc.h      | 1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c 
b/drivers/scsi/ibmvscsi/ibmvfc-core.c
index d79a6ae278a2..b0d9000b4a0d 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc-core.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c
@@ -5156,7 +5156,8 @@ static void ibmvfc_discover_targets_done(struct 
ibmvfc_event *evt)
                                              max_targets);
                ibmvfc_dbg(vhost, "%d %s targets found\n", 
channels->num_targets,
                           proto_type[channels->protocol]);
-               ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS);
+               if (!--vhost->pending_disc)
+                       ibmvfc_set_host_action(vhost, 
IBMVFC_HOST_ACTION_ALLOC_TGTS);
                break;
        case IBMVFC_MAD_FAILED:
                level += ibmvfc_retry_host_init(vhost);
@@ -5220,6 +5221,7 @@ static void ibmvfc_discover_targets(struct ibmvfc_host 
*vhost)
        }
 
        ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT);
+       vhost->pending_disc = 1;
 
        if (!ibmvfc_send_event(evt, vhost, default_timeout))
                ibmvfc_dbg(vhost, "Sent discover SCSI targets\n");
@@ -5236,6 +5238,8 @@ static void ibmvfc_discover_targets(struct ibmvfc_host 
*vhost)
                return;
        }
 
+       vhost->pending_disc++;
+
        if (!ibmvfc_send_event(evt, vhost, default_timeout))
                ibmvfc_dbg(vhost, "Sent discover NVMe targets\n");
        else
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index df0775183d72..a984b81f1d23 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -1006,6 +1006,7 @@ struct ibmvfc_host {
        unsigned int do_scsi_login:1;
        unsigned int do_nvme_login:1;
        unsigned int do_nvme_register:1;
+       unsigned int pending_disc:2;
        unsigned int aborting_passthru:1;
        unsigned int scan_complete:1;
        int scan_timeout;
-- 
2.55.0


Reply via email to