[PATCH 19/20] scsi: ibmvfc: fix concurrent SCSI and NVMe discover-targets race dropping targets

From: Tyrel Datwyler

Date: Wed Sep 16 2026 - 19:16:55 EST


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 <tyreld@xxxxxxxxxxxxx>
---
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