scsi: ibmvfc: implement nvme-fc LS abort handling callback

Implement the NVMe FC-LS abort callback by issuing an ibmvfc cancel MAD
to the VIOS for the outstanding link-service request.

Use the saved event pointer from the original FC-LS request to identify
the command to cancel, submit the cancel operation, and complete the
abort request based on the returned status.

Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com>
Link: https://patch.msgid.link/20260723000149.969416-32-tyreld@linux.ibm.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Tyrel Datwyler
2026-07-22 17:01:47 -07:00
committed by Martin K. Petersen
parent 73c13e30c5
commit 20bec08f02

View File

@@ -13,6 +13,8 @@
#include "ibmvfc-nvme.h"
static unsigned int default_timeout = IBMVFC_DEFAULT_TIMEOUT;
static void ibmvfc_nvme_localport_delete(struct nvme_fc_local_port *lport)
{
struct ibmvfc_host *vhost = lport->private;
@@ -159,10 +161,72 @@ static int ibmvfc_nvme_ls_req(struct nvme_fc_local_port *lport,
return 0;
}
static void ibmvfc_sync_nvme_completion(struct ibmvfc_event *evt)
{
/* copy the response back */
if (evt->sync_iu)
*evt->sync_iu = *evt->xfer_iu;
complete(&evt->comp);
}
static void ibmvfc_init_ls_abort(struct ibmvfc_event *evt, struct nvmefc_ls_req *ls_abort)
{
struct ibmvfc_tmf *tmf;
struct ibmvfc_event *abt_evt = ls_abort->private;
struct ibmvfc_target *tgt = abt_evt->tgt;
struct ibmvfc_host *vhost = evt->vhost;
tmf = &evt->iu.tmf;
memset(tmf, 0, sizeof(*tmf));
tmf->common.version = cpu_to_be32(2);
tmf->target_wwpn = cpu_to_be64(tgt->wwpn);
tmf->common.opcode = cpu_to_be32(IBMVFC_NVMF_TMF_MAD);
tmf->common.length = cpu_to_be16(sizeof(*tmf));
if (vhost->state != IBMVFC_ACTIVE)
if (!ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPRESS_ABTS))
tmf->flags = cpu_to_be32(IBMVFC_TMF_SUPPRESS_ABTS);
tmf->cancel_key = cpu_to_be32((u64)abt_evt);
tmf->my_cancel_key = cpu_to_be32((u64)evt);
tmf->assoc_id = cpu_to_be64(tgt->assoc_id);
init_completion(&evt->comp);
}
static void ibmvfc_nvme_ls_abort(struct nvme_fc_local_port *lport,
struct nvme_fc_remote_port *rport,
struct nvmefc_ls_req *ls_abort)
{
struct ibmvfc_host *vhost = lport->private;
struct ibmvfc_target *tgt = rport->private;
struct ibmvfc_event *evt;
union ibmvfc_iu rsp;
unsigned long flags;
u16 status;
evt = ibmvfc_get_event(&vhost->crq);
if (!vhost->logged_in || !evt)
return;
spin_lock_irqsave(vhost->host->host_lock, flags);
kref_get(&tgt->kref);
ibmvfc_init_event(evt, ibmvfc_sync_nvme_completion, IBMVFC_MAD_FORMAT);
ibmvfc_init_ls_abort(evt, ls_abort);
evt->sync_iu = &rsp;
if (ibmvfc_send_event(evt, vhost, default_timeout))
goto out;
spin_unlock_irqrestore(vhost->host->host_lock, flags);
wait_for_completion(&evt->comp);
status = be16_to_cpu(rsp.mad_common.status);
spin_lock_irqsave(vhost->host->host_lock, flags);
ibmvfc_free_event(evt);
out:
spin_unlock_irqrestore(vhost->host->host_lock, flags);
ibmvfc_dbg(vhost, "ls_abort: cancel failed with rc=%x\n", status);
kref_put(&tgt->kref, ibmvfc_release_tgt);
}
static void ibmvfc_nvme_done(struct ibmvfc_event *evt)