[PATCH v2 13/20] scsi: ibmvfc: make NVMe FCP abort callback asynchronous

From: Tyrel Datwyler

Date: Fri Sep 18 2026 - 21:34:52 EST


The nvme_fc_port_template fcp_abort callback is called by the NVMe-FC
transport from the block layer timeout workqueue. The current
implementation submits a cancel MAD and then blocks on
wait_for_completion() until the VIOS response arrives. This stalls the
timeout workqueue for the full MAD round-trip, preventing any other I/O
timeout from being processed in the meantime.

The nvme-fc-driver.h API contract is explicit: the LLDD must initiate
the abort and return immediately; the ABTS does not need to be complete
on return. The transport waits for the original exchange to complete
independently via fcp_req->done().

Replace the synchronous ibmvfc_sync_nvme_completion callback with a
dedicated ibmvfc_nvme_fcp_abort_done() that runs asynchronously when
the cancel MAD response arrives. The new callback logs any non-zero MAD
status, drops the target kref, and frees the event. ibmvfc_send_event()
guarantees the done callback is invoked on both success and failure
paths, so event ownership is fully transferred and ibmvfc_nvme_fcp_abort()
returns immediately after ibmvfc_send_event().

Drop the now-unnecessary init_completion() from ibmvfc_init_fcp_abort()
and the sync_iu / wait_for_completion / second lock-cycle from the abort
function itself.

Fixes: 4e70b8795ee3 ("scsi: ibmvfc: implement nvme-fc FCP abort callback")
Signed-off-by: Tyrel Datwyler <tyreld@xxxxxxxxxxxxx>
---
drivers/scsi/ibmvscsi/ibmvfc-nvme.c | 34 ++++++++++++-----------------
1 file changed, 14 insertions(+), 20 deletions(-)

diff --git a/drivers/scsi/ibmvscsi/ibmvfc-nvme.c b/drivers/scsi/ibmvscsi/ibmvfc-nvme.c
index a6fc9e8a35f6..d23e5f31f8b5 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc-nvme.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc-nvme.c
@@ -400,8 +400,18 @@ static void ibmvfc_init_fcp_abort(struct ibmvfc_event *evt,
tmf->target_wwpn = cpu_to_be64(tgt->wwpn);
tmf->assoc_id = cpu_to_be64(tgt->assoc_id);
tmf->task_tag = cpu_to_be64((u64)abt_evt);
+}

- init_completion(&evt->comp);
+static void ibmvfc_nvme_fcp_abort_done(struct ibmvfc_event *evt)
+{
+ u16 status = be16_to_cpu(evt->xfer_iu->mad_common.status);
+
+ if (status)
+ ibmvfc_dbg(evt->vhost, "fcp_abort: cancel MAD failed with rc=%x\n",
+ status);
+
+ kref_put(&evt->tgt->kref, ibmvfc_release_tgt);
+ ibmvfc_free_event(evt);
}

static void ibmvfc_nvme_fcp_abort(struct nvme_fc_local_port *lport,
@@ -413,9 +423,7 @@ static void ibmvfc_nvme_fcp_abort(struct nvme_fc_local_port *lport,
struct ibmvfc_target *tgt = rport->private;
struct ibmvfc_event *evt, *abt_evt = abort_req->private;
struct ibmvfc_queue *queue;
- union ibmvfc_iu rsp;
unsigned long flags;
- u16 status = 0;

if (!abt_evt)
return;
@@ -430,27 +438,13 @@ static void ibmvfc_nvme_fcp_abort(struct nvme_fc_local_port *lport,

spin_lock_irqsave(queue->q_lock, flags);
kref_get(&tgt->kref);
- ibmvfc_init_event(evt, ibmvfc_sync_nvme_completion, IBMVFC_MAD_FORMAT);
+ ibmvfc_init_event(evt, ibmvfc_nvme_fcp_abort_done, IBMVFC_MAD_FORMAT);
ibmvfc_init_fcp_abort(evt, abort_req);
- evt->sync_iu = &rsp;
+ evt->tgt = tgt;

if (ibmvfc_send_event(evt, vhost, default_timeout))
- goto out;
-
- spin_unlock_irqrestore(queue->q_lock, flags);
-
- wait_for_completion(&evt->comp);
- status = be16_to_cpu(rsp.mad_common.status);
-
- spin_lock_irqsave(queue->q_lock, flags);
- ibmvfc_free_event(evt);
-out:
+ kref_put(&tgt->kref, ibmvfc_release_tgt);
spin_unlock_irqrestore(queue->q_lock, flags);
-
- if (status)
- ibmvfc_dbg(vhost, "fcp_abort: cancel failed with rc=%x\n", status);
-
- kref_put(&tgt->kref, ibmvfc_release_tgt);
}

static struct nvme_fc_port_template ibmvfc_nvme_fc_transport = {
--
2.55.0