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 <[email protected]> --- drivers/scsi/ibmvscsi/ibmvfc-nvme.c | 64 +++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/scsi/ibmvscsi/ibmvfc-nvme.c b/drivers/scsi/ibmvscsi/ibmvfc-nvme.c index bff469d0b47d..18e8657abc44 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc-nvme.c +++ b/drivers/scsi/ibmvscsi/ibmvfc-nvme.c @@ -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) -- 2.54.0
