mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 22:14:03 +02:00
Merge patch series "ibmvfc: NVMe/FC support over IBM Virtual FC"
Tyrel Datwyler <tyreld@linux.ibm.com> says: This series adds NVMe/FC initiator support to the ibmvfc driver, enabling IBM POWER virtual machines to discover and use NVMe namespaces presented by the IBM Virtual I/O Server (VIOS) over the existing NPIV transport. The ibmvfc driver communicates with the VIOS via a CRQ-based protocol. With this series the VIOS can present both SCSI/FCP and NVMe/FC targets through parallel sets of protocol-specific MAD opcodes, fabric login flows, and sub-CRQ channels. The series is organized into three phases: Patches 1-5: Bug fixes and preparatory refactoring Four pre-existing bugs are fixed before any NVMe/FC work is introduced: a deadlock in the MAD send-failure path (locked done variant called with host_lock already held), a race during driver teardown where rport_add_work_q work items can outlive the FC host, a NULL event dereference in ibmvfc_tgt_implicit_logout_and_del, and an allocator mismatch where mempool-allocated ibmvfc_target structs are freed via kfree rather than mempool_free. Patch 5 moves the target list and count from struct ibmvfc_host into struct ibmvfc_channels as the structural prerequisite for independent per-protocol target tracking. Patches 6-27: Protocol interface and driver scaffolding Patch 6 extends ibmvfc.h with NVMe/FC protocol definitions: MAD opcodes, capability flags, the v3 command layout, the fabric login MAD, async sub-CRQ event format, and updated channel enquiry/setup fields. Patch 7 splits ibmvfc.c into ibmvfc-core.c and the new ibmvfc-nvme.c/h, registers an nvme_fc_port_template with stub callbacks, and adds NVMe module parameters. The remaining patches build the NVMe/FC plumbing: NVMe channel-group initialization, sub-CRQ lifecycle management, protocol- specific fabric login flow, target discovery, PLOGI/PRLI/query-target, implicit logout, move-login, protocol-driven target allocation, NVMe target deletion, state machine updates, and local/remote port registration with the NVMe-FC transport layer. Patches 28-33: NVMe-FC LLDD callbacks and I/O path Implements the full nvme_fc_port_template: create_queue/delete_queue map NVMe controller queues to sub-CRQ handles; ls_req submits FC-LS frames via the ibmvfc passthru MAD; fcp_io builds and submits NVMe FCP commands via the NVMe sub-CRQ and completes them via nvme_fc_rcv_fcp_rsp(); ls_abort and fcp_abort cancel outstanding requests via NVMF cancel MADs. Patch 33 extends the purge path to fail outstanding NVMe FCP and LS requests during host reset and link-down events. Link: https://patch.msgid.link/20260723000149.969416-1-tyreld@linux.ibm.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
commit
1cd82d710e
|
|
@ -1,3 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
ibmvfc-objs := ibmvfc-core.o ibmvfc-nvme.o
|
||||
|
||||
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi.o
|
||||
obj-$(CONFIG_SCSI_IBMVFC) += ibmvfc.o
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
573
drivers/scsi/ibmvscsi/ibmvfc-nvme.c
Normal file
573
drivers/scsi/ibmvscsi/ibmvfc-nvme.c
Normal file
|
|
@ -0,0 +1,573 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/*
|
||||
* ibmvfc-nvme.c -- IBM Power Virtual Fibre Channel NVMeoF HBA driver
|
||||
*
|
||||
* Written By: Tyrel Datwyler <tyreld@linux.ibm.com>, IBM Corporation
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2026
|
||||
*/
|
||||
|
||||
#include <linux/dmapool.h>
|
||||
#include <scsi/scsi_transport_fc.h>
|
||||
|
||||
#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;
|
||||
|
||||
vhost->nvme_local_port = NULL;
|
||||
complete(&vhost->nvme_delete_done);
|
||||
}
|
||||
|
||||
static void ibmvfc_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
|
||||
{
|
||||
struct ibmvfc_target *tgt = rport->private;
|
||||
|
||||
tgt->nvme_remote_port = NULL;
|
||||
complete(&tgt->nvme_delete_done);
|
||||
}
|
||||
|
||||
static int ibmvfc_nvme_create_queue(struct nvme_fc_local_port *lport, unsigned int qidx,
|
||||
u16 qsize, void **handle)
|
||||
{
|
||||
struct ibmvfc_host *vhost = lport->private;
|
||||
struct ibmvfc_nvme_qhandle *qhandle;
|
||||
|
||||
if (!vhost->nvme_scrqs.active_queues)
|
||||
return -ENODEV;
|
||||
|
||||
qhandle = kzalloc_obj(struct ibmvfc_nvme_qhandle);
|
||||
if (!qhandle)
|
||||
return -ENOMEM;
|
||||
|
||||
qhandle->cpu_id = raw_smp_processor_id();
|
||||
qhandle->qidx = qidx;
|
||||
|
||||
/* Admin and first IO queue are both mapped to index 0 */
|
||||
if (qidx)
|
||||
qhandle->index = (qidx - 1) % vhost->nvme_scrqs.active_queues;
|
||||
else
|
||||
qhandle->index = qidx;
|
||||
|
||||
qhandle->queue = &vhost->nvme_scrqs.scrqs[qhandle->index];
|
||||
|
||||
*handle = qhandle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ibmvfc_nvme_delete_queue(struct nvme_fc_local_port *lport, unsigned int qidx,
|
||||
void *handle)
|
||||
{
|
||||
kfree(handle);
|
||||
}
|
||||
|
||||
static void ibmvfc_ls_req_done(struct ibmvfc_event *evt)
|
||||
{
|
||||
struct ibmvfc_target *tgt = evt->tgt;
|
||||
struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru;
|
||||
struct fcnvme_ls_rqst_w0 *ls_rqst;
|
||||
struct fcnvme_ls_cr_assoc_acc *ls_resp;
|
||||
u32 status = be16_to_cpu(mad->common.status);
|
||||
int rc = 0;
|
||||
|
||||
ls_rqst = (struct fcnvme_ls_rqst_w0 *)evt->ls_req->rqstaddr;
|
||||
ls_resp = (struct fcnvme_ls_cr_assoc_acc *)evt->ls_req->rspaddr;
|
||||
|
||||
switch (status) {
|
||||
case IBMVFC_MAD_SUCCESS:
|
||||
tgt_dbg(tgt, "ls_req succeeded\n");
|
||||
if ((ls_rqst->ls_cmd == FCNVME_LS_CREATE_ASSOCIATION) &&
|
||||
(ls_resp->hdr.w0.ls_cmd == FCNVME_LS_ACC)) {
|
||||
tgt->assoc_id = be64_to_cpu(ls_resp->associd.association_id);
|
||||
tgt_dbg(tgt, "assoc_id 0x%llx\n", tgt->assoc_id);
|
||||
}
|
||||
break;
|
||||
case IBMVFC_MAD_DRIVER_FAILED:
|
||||
break;
|
||||
case IBMVFC_MAD_FAILED:
|
||||
default:
|
||||
tgt_info(tgt, "ls_req failed: %s (%x:%x) rc=0x%02X\n",
|
||||
ibmvfc_get_cmd_error(be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error)),
|
||||
be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error), status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (status)
|
||||
rc = -EIO;
|
||||
|
||||
evt->ls_req->done(evt->ls_req, rc);
|
||||
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
ibmvfc_free_event(evt);
|
||||
}
|
||||
|
||||
static void ibmvfc_init_ls_req(struct ibmvfc_event *evt, struct nvmefc_ls_req *ls_req)
|
||||
{
|
||||
struct ibmvfc_passthru_mad *mad = &evt->iu.passthru;
|
||||
|
||||
memset(mad, 0, sizeof(*mad));
|
||||
mad->common.version = cpu_to_be32(2);
|
||||
mad->common.opcode = cpu_to_be32(IBMVFC_NVMF_PASSTHRU);
|
||||
mad->common.length = cpu_to_be16(sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu));
|
||||
mad->cmd_ioba.va = cpu_to_be64((u64)be64_to_cpu(evt->crq.ioba) +
|
||||
offsetof(struct ibmvfc_passthru_mad, iu));
|
||||
mad->cmd_ioba.len = cpu_to_be32(sizeof(mad->iu));
|
||||
mad->iu.cmd_len = cpu_to_be32(ls_req->rqstlen);
|
||||
mad->iu.rsp_len = cpu_to_be32(ls_req->rsplen);
|
||||
mad->iu.cmd.va = cpu_to_be64(ls_req->rqstdma);
|
||||
mad->iu.cmd.len = cpu_to_be32(ls_req->rqstlen);
|
||||
mad->iu.rsp.va = cpu_to_be64(ls_req->rspdma);
|
||||
mad->iu.rsp.len = cpu_to_be32(ls_req->rsplen);
|
||||
}
|
||||
|
||||
static int ibmvfc_nvme_ls_req(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
struct nvmefc_ls_req *ls_req)
|
||||
{
|
||||
struct ibmvfc_host *vhost = lport->private;
|
||||
struct ibmvfc_target *tgt = rport->private;
|
||||
struct ibmvfc_passthru_mad *mad;
|
||||
struct ibmvfc_event *evt;
|
||||
|
||||
kref_get(&tgt->kref);
|
||||
evt = ibmvfc_get_event(&vhost->crq);
|
||||
if (!evt) {
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ibmvfc_init_event(evt, ibmvfc_ls_req_done, IBMVFC_MAD_FORMAT);
|
||||
evt->tgt = tgt;
|
||||
evt->ls_req = ls_req;
|
||||
ls_req->private = evt;
|
||||
|
||||
ibmvfc_init_ls_req(evt, ls_req);
|
||||
mad = &evt->iu.passthru;
|
||||
mad->iu.flags = cpu_to_be32(IBMVFC_FC4_LS_DSC_CTRL);
|
||||
mad->iu.scsi_id = cpu_to_be64(tgt->scsi_id);
|
||||
mad->iu.cancel_key = cpu_to_be32((u64)evt);
|
||||
mad->iu.target_wwpn = cpu_to_be64(tgt->wwpn);
|
||||
|
||||
ibmvfc_dbg(vhost, "nvme_ls_req\n");
|
||||
if (ibmvfc_send_event(evt, vhost, IBMVFC_FC4_LS_PLUS_CANCEL_TIMEOUT)) {
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd;
|
||||
struct nvmefc_fcp_req *fcp_req = evt->fcp_req;
|
||||
struct nvme_fc_ersp_iu *ersp = (struct nvme_fc_ersp_iu *)fcp_req->rspaddr;
|
||||
struct nvme_completion *cqe = &ersp->cqe;
|
||||
struct nvme_command *sqe = &((struct nvme_fc_cmd_iu *)fcp_req->cmdaddr)->sqe;
|
||||
|
||||
ibmvfc_dbg(evt->vhost, "fc_done: (%x:%x)\n", be16_to_cpu(vfc_cmd->status),
|
||||
be16_to_cpu(vfc_cmd->error));
|
||||
ibmvfc_dbg(evt->vhost, "fc_done: cmdlen: %d, rsplen %d, payload_len %d\n",
|
||||
fcp_req->cmdlen, fcp_req->rsplen, fcp_req->payload_length);
|
||||
|
||||
fcp_req->status = 0;
|
||||
if (!vfc_cmd->status) {
|
||||
fcp_req->rcv_rsplen = NVME_FC_SIZEOF_ZEROS_RSP;
|
||||
fcp_req->transferred_length = fcp_req->payload_length;
|
||||
} else if (be16_to_cpu(vfc_cmd->status) & IBMVFC_FC_NVME_STATUS) {
|
||||
fcp_req->rcv_rsplen = sizeof(struct nvme_fc_ersp_iu);
|
||||
fcp_req->transferred_length = be32_to_cpu(ersp->xfrd_len);
|
||||
if (be16_to_cpu(vfc_cmd->error) & IBMVFC_NVMS_VALID_NODMA_CQE)
|
||||
cqe->command_id = sqe->common.command_id;
|
||||
} else {
|
||||
fcp_req->rcv_rsplen = 0;
|
||||
fcp_req->transferred_length = 0;
|
||||
fcp_req->status = NVME_SC_INTERNAL;
|
||||
}
|
||||
|
||||
fcp_req->done(fcp_req);
|
||||
ibmvfc_free_event(evt);
|
||||
}
|
||||
|
||||
static struct ibmvfc_cmd *ibmvfc_nvme_init_vfc_cmd(struct ibmvfc_event *evt,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
struct nvmefc_fcp_req *fcp_req)
|
||||
{
|
||||
struct ibmvfc_target *tgt = rport->private;
|
||||
struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd;
|
||||
|
||||
memset(vfc_cmd, 0, sizeof(*vfc_cmd));
|
||||
|
||||
vfc_cmd->resp.va = cpu_to_be64(fcp_req->rspdma);
|
||||
vfc_cmd->resp.len = cpu_to_be32(fcp_req->rsplen);
|
||||
vfc_cmd->frame_type = cpu_to_be32(IBMVFC_NVME_FCP_TYPE);
|
||||
vfc_cmd->flags |= cpu_to_be16(IBMVFC_NVMEOF_PROTOCOL);
|
||||
vfc_cmd->payload_len = cpu_to_be32(fcp_req->cmdlen);
|
||||
vfc_cmd->resp_len = cpu_to_be32(fcp_req->rsplen);
|
||||
vfc_cmd->cancel_key = cpu_to_be32((u64)evt);
|
||||
vfc_cmd->target_wwpn = cpu_to_be64(rport->port_name);
|
||||
vfc_cmd->tgt_scsi_id = cpu_to_be64(rport->port_id);
|
||||
vfc_cmd->assoc_id = cpu_to_be64(tgt->assoc_id);
|
||||
|
||||
memcpy(&vfc_cmd->v3nvme.iu, fcp_req->cmdaddr, fcp_req->cmdlen);
|
||||
|
||||
return vfc_cmd;
|
||||
}
|
||||
|
||||
static void ibmvfc_nvme_map_sg_list(struct nvmefc_fcp_req *fcp_req,
|
||||
struct srp_direct_buf *md)
|
||||
{
|
||||
int i;
|
||||
struct scatterlist *sg;
|
||||
|
||||
for_each_sg(fcp_req->first_sgl, sg, fcp_req->sg_cnt, i) {
|
||||
md[i].va = cpu_to_be64(sg_dma_address(sg));
|
||||
md[i].len = cpu_to_be32(sg_dma_len(sg));
|
||||
md[i].key = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int ibmvfc_nvme_map_sg_data(struct nvmefc_fcp_req *fcp_req,
|
||||
struct ibmvfc_event *evt,
|
||||
struct ibmvfc_cmd *vfc_cmd)
|
||||
{
|
||||
struct srp_direct_buf *data = &vfc_cmd->ioba;
|
||||
struct ibmvfc_host *vhost = evt->vhost;
|
||||
|
||||
if (!fcp_req->sg_cnt) {
|
||||
vfc_cmd->flags |= cpu_to_be16(IBMVFC_NO_MEM_DESC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fcp_req->io_dir == NVMEFC_FCP_WRITE)
|
||||
vfc_cmd->flags |= cpu_to_be16(IBMVFC_WRITE);
|
||||
else
|
||||
vfc_cmd->flags |= cpu_to_be16(IBMVFC_READ);
|
||||
|
||||
if (fcp_req->sg_cnt == 1) {
|
||||
ibmvfc_nvme_map_sg_list(fcp_req, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfc_cmd->flags |= cpu_to_be16(IBMVFC_SCATTERLIST);
|
||||
|
||||
if (!evt->ext_list) {
|
||||
evt->ext_list = dma_pool_alloc(vhost->sg_pool, GFP_ATOMIC,
|
||||
&evt->ext_list_token);
|
||||
|
||||
if (!evt->ext_list)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ibmvfc_nvme_map_sg_list(fcp_req, evt->ext_list);
|
||||
|
||||
data->va = cpu_to_be64(evt->ext_list_token);
|
||||
data->len = cpu_to_be32(fcp_req->sg_cnt * sizeof(struct srp_direct_buf));
|
||||
data->key = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ibmvfc_nvme_fcp_io(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
void *hw_queue_handle,
|
||||
struct nvmefc_fcp_req *fcp_req)
|
||||
{
|
||||
struct ibmvfc_host *vhost = lport->private;
|
||||
struct ibmvfc_nvme_qhandle *qhandle = hw_queue_handle;
|
||||
struct ibmvfc_cmd *vfc_cmd;
|
||||
struct ibmvfc_event *evt;
|
||||
int rc;
|
||||
|
||||
ibmvfc_dbg(vhost, "nvme_fcp_io\n");
|
||||
evt = ibmvfc_get_event(qhandle->queue);
|
||||
if (!evt)
|
||||
return -EBUSY;
|
||||
|
||||
evt->hwq = qhandle->index;
|
||||
ibmvfc_dbg(vhost, "vfc-nvme-mq-%d\n", evt->hwq);
|
||||
|
||||
ibmvfc_init_event(evt, ibmvfc_nvme_done, IBMVFC_CMD_FORMAT);
|
||||
evt->fcp_req = fcp_req;
|
||||
fcp_req->private = evt;
|
||||
|
||||
vfc_cmd = ibmvfc_nvme_init_vfc_cmd(evt, rport, fcp_req);
|
||||
|
||||
vfc_cmd->correlation = cpu_to_be64((u64)evt);
|
||||
|
||||
if (likely(!(rc = ibmvfc_nvme_map_sg_data(fcp_req, evt, vfc_cmd))))
|
||||
return ibmvfc_send_event(evt, vhost, 0);
|
||||
|
||||
ibmvfc_free_event(evt);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ibmvfc_init_fcp_abort(struct ibmvfc_event *evt,
|
||||
struct nvmefc_fcp_req *abort_req)
|
||||
{
|
||||
struct ibmvfc_tmf *tmf;
|
||||
struct ibmvfc_event *abt_evt = abort_req->private;
|
||||
struct ibmvfc_target *tgt = abt_evt->tgt;
|
||||
|
||||
tmf = &evt->iu.tmf;
|
||||
memset(tmf, 0, sizeof(*tmf));
|
||||
tmf->common.version = cpu_to_be32(2);
|
||||
tmf->common.opcode = cpu_to_be32(IBMVFC_NVMF_TMF_MAD);
|
||||
tmf->common.length = cpu_to_be16(sizeof(*tmf));
|
||||
tmf->flags = cpu_to_be32(IBMVFC_TMF_ABORT_TASK | IBMVFC_TMF_NVMF_ASSOC);
|
||||
tmf->cancel_key = cpu_to_be32((u64)abt_evt);
|
||||
tmf->my_cancel_key = cpu_to_be32((u64)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(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
void *hw_queue_handle,
|
||||
struct nvmefc_fcp_req *abort_req)
|
||||
{
|
||||
struct ibmvfc_host *vhost = lport->private;
|
||||
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;
|
||||
|
||||
queue = abt_evt->queue;
|
||||
if (!vhost->logged_in || !queue)
|
||||
return;
|
||||
|
||||
evt = ibmvfc_get_event(queue);
|
||||
if (!evt)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(queue->q_lock, flags);
|
||||
kref_get(&tgt->kref);
|
||||
ibmvfc_init_event(evt, ibmvfc_sync_nvme_completion, IBMVFC_MAD_FORMAT);
|
||||
ibmvfc_init_fcp_abort(evt, abort_req);
|
||||
evt->sync_iu = &rsp;
|
||||
|
||||
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:
|
||||
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 = {
|
||||
.localport_delete = ibmvfc_nvme_localport_delete,
|
||||
.remoteport_delete = ibmvfc_nvme_remoteport_delete,
|
||||
.create_queue = ibmvfc_nvme_create_queue,
|
||||
.delete_queue = ibmvfc_nvme_delete_queue,
|
||||
.ls_req = ibmvfc_nvme_ls_req,
|
||||
.ls_abort = ibmvfc_nvme_ls_abort,
|
||||
.fcp_io = ibmvfc_nvme_fcp_io,
|
||||
.fcp_abort = ibmvfc_nvme_fcp_abort,
|
||||
.map_queues = NULL,
|
||||
.max_hw_queues = IBMVFC_NVME_HW_QUEUES,
|
||||
.max_sgl_segments = 1024,
|
||||
.max_dif_sgl_segments = 64,
|
||||
.dma_boundary = 0xFFFFFFFF,
|
||||
.local_priv_sz = sizeof(struct ibmvfc_host *),
|
||||
.remote_priv_sz = sizeof(struct ibmvfc_target *),
|
||||
.lsrqst_priv_sz = sizeof(struct ibmvfc_event *),
|
||||
.fcprqst_priv_sz = sizeof(struct ibmvfc_event *),
|
||||
};
|
||||
|
||||
int ibmvfc_nvme_register_remoteport(struct ibmvfc_target *tgt)
|
||||
{
|
||||
struct ibmvfc_host *vhost = tgt->vhost;
|
||||
struct nvme_fc_port_info pinfo;
|
||||
int rc;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NVME_FC))
|
||||
return 0;
|
||||
|
||||
if (!vhost->nvme_local_port) {
|
||||
dev_err(vhost->dev, "Attempt to register NVMe fc remoteport without valid localport\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&pinfo, 0, sizeof(struct nvme_fc_port_info));
|
||||
pinfo.node_name = tgt->ids.node_name;
|
||||
pinfo.port_name = tgt->ids.port_name;
|
||||
pinfo.port_id = tgt->ids.port_id;
|
||||
pinfo.port_role = FC_PORT_ROLE_NVME_TARGET;
|
||||
|
||||
rc = nvme_fc_register_remoteport(vhost->nvme_local_port, &pinfo,
|
||||
&tgt->nvme_remote_port);
|
||||
|
||||
if (!rc) {
|
||||
ibmvfc_log(vhost, 2, "register_remoteport: traddr=nn-0x%llx:pn-0x%llx PortID:%x\n",
|
||||
pinfo.node_name, pinfo.port_name, pinfo.port_id);
|
||||
tgt->nvme_remote_port->private = tgt;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ibmvfc_nvme_unregister_remoteport(struct ibmvfc_target *tgt)
|
||||
{
|
||||
struct ibmvfc_host *vhost = tgt->vhost;
|
||||
struct nvme_fc_remote_port *rport = tgt->nvme_remote_port;
|
||||
int rc;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NVME_FC))
|
||||
return;
|
||||
|
||||
if (!tgt->nvme_remote_port)
|
||||
return;
|
||||
|
||||
ibmvfc_log(vhost, 2, "unregister_remoteport: traddr=nn-0x%llx:pn-0x%llx PortID:%x\n",
|
||||
rport->node_name, rport->port_name, rport->port_id);
|
||||
init_completion(&tgt->nvme_delete_done);
|
||||
rc = nvme_fc_unregister_remoteport(tgt->nvme_remote_port);
|
||||
|
||||
if (!rc) {
|
||||
wait_for_completion(&tgt->nvme_delete_done);
|
||||
}
|
||||
}
|
||||
|
||||
int ibmvfc_nvme_register(struct ibmvfc_host *vhost)
|
||||
{
|
||||
struct nvme_fc_port_info pinfo;
|
||||
int rc;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NVME_FC))
|
||||
return 0;
|
||||
|
||||
pinfo.node_name = fc_host_node_name(vhost->host);
|
||||
pinfo.port_name = fc_host_port_name(vhost->host);
|
||||
pinfo.port_id = fc_host_port_id(vhost->host);
|
||||
pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR;
|
||||
pinfo.dev_loss_tmo = 0;
|
||||
|
||||
rc = nvme_fc_register_localport(&pinfo, &ibmvfc_nvme_fc_transport,
|
||||
get_device(vhost->dev),
|
||||
&vhost->nvme_local_port);
|
||||
|
||||
if (!rc) {
|
||||
ibmvfc_log(vhost, 2, "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n",
|
||||
pinfo.node_name, pinfo.port_name, pinfo.port_id);
|
||||
vhost->nvme_local_port->private = vhost;
|
||||
} else {
|
||||
dev_err(vhost->dev, "Failed to register NVMe fc localport (%d)\n", rc);
|
||||
put_device(vhost->dev);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ibmvfc_nvme_unregister(struct ibmvfc_host *vhost)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NVME_FC))
|
||||
return;
|
||||
|
||||
if (vhost->nvme_local_port) {
|
||||
ibmvfc_log(vhost, 2, "unregister_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n",
|
||||
vhost->nvme_local_port->node_name,
|
||||
vhost->nvme_local_port->port_name,
|
||||
vhost->nvme_local_port->port_id);
|
||||
init_completion(&vhost->nvme_delete_done);
|
||||
rc = nvme_fc_unregister_localport(vhost->nvme_local_port);
|
||||
if (!rc) {
|
||||
wait_for_completion(&vhost->nvme_delete_done);
|
||||
} else
|
||||
dev_err(vhost->dev, "Failed to unregister NVMe fc localport (%d)\n", rc);
|
||||
|
||||
put_device(vhost->dev);
|
||||
}
|
||||
}
|
||||
49
drivers/scsi/ibmvscsi/ibmvfc-nvme.h
Normal file
49
drivers/scsi/ibmvscsi/ibmvfc-nvme.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/*
|
||||
* ibmvfc-nvme.h -- IBM Power Virtual Fibre Channel NVMeoF HBA driver
|
||||
*
|
||||
* Written By: Tyrel Datwyler <tyreld@linux.ibm.com>, IBM Corporation
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2026
|
||||
*/
|
||||
|
||||
#ifndef _IBMVFC_NVME_H
|
||||
#define _IBMVFC_NVME_H
|
||||
|
||||
#include <scsi/fc/fc_fs.h>
|
||||
#include <scsi/fc/fc_els.h>
|
||||
#include <linux/nvme-fc-driver.h>
|
||||
#include <linux/nvme.h>
|
||||
#include <linux/nvme-fc.h>
|
||||
|
||||
#include "ibmvfc.h"
|
||||
|
||||
#define IBMVFC_NVME 0
|
||||
#define IBMVFC_NVME_HW_QUEUES 8
|
||||
#define IBMVFC_MAX_NVME_QUEUES 16
|
||||
#define IBMVFC_NVME_CHANNELS 8
|
||||
|
||||
#define IBMVFC_FC4_LS_TIMEOUT 15
|
||||
#define IBMVFC_FC4_LS_CANCEL_TIMEOUT 45
|
||||
#define IBMVFC_FC4_LS_PLUS_CANCEL_TIMEOUT \
|
||||
(IBMVFC_FC4_LS_TIMEOUT + IBMVFC_FC4_LS_CANCEL_TIMEOUT)
|
||||
|
||||
extern unsigned int ibmvfc_debug;
|
||||
|
||||
struct ibmvfc_host;
|
||||
struct ibmvfc_target;
|
||||
struct ibmvfc_queue;
|
||||
|
||||
struct ibmvfc_nvme_qhandle {
|
||||
unsigned int qidx;
|
||||
u16 cpu_id;
|
||||
unsigned long index;
|
||||
struct ibmvfc_queue *queue;
|
||||
};
|
||||
|
||||
int ibmvfc_nvme_register_remoteport(struct ibmvfc_target *tgt);
|
||||
void ibmvfc_nvme_unregister_remoteport(struct ibmvfc_target *tgt);
|
||||
int ibmvfc_nvme_register(struct ibmvfc_host *vhost);
|
||||
void ibmvfc_nvme_unregister(struct ibmvfc_host *vhost);
|
||||
#endif
|
||||
|
|
@ -1,20 +1,27 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/*
|
||||
* ibmvfc.h -- driver for IBM Power Virtual Fibre Channel Adapter
|
||||
*
|
||||
* Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2008
|
||||
* Copyright (C) IBM Corporation, 2008-2026
|
||||
*/
|
||||
|
||||
#ifndef _IBMVFC_H
|
||||
#define _IBMVFC_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/viosrp.h>
|
||||
#include <linux/nvme.h>
|
||||
#include <linux/nvme-fc.h>
|
||||
|
||||
#define IBMVFC_NAME "ibmvfc"
|
||||
#include "ibmvfc-nvme.h"
|
||||
|
||||
#define IBMVFC_NAME "ibmvfc"
|
||||
#define IBMVFC_DRIVER_VERSION "1.0.11"
|
||||
#define IBMVFC_DRIVER_DATE "(April 12, 2013)"
|
||||
|
||||
|
|
@ -92,6 +99,7 @@ enum ibmvfc_cmd_status_flags {
|
|||
IBMVFC_FC_SCSI_ERROR = 0x0008,
|
||||
IBMVFC_HW_EVENT_LOGGED = 0x0010,
|
||||
IBMVFC_VIOS_LOGGED = 0x0020,
|
||||
IBMVFC_FC_NVME_STATUS = 0x0040,
|
||||
};
|
||||
|
||||
enum ibmvfc_fabric_mapped_errors {
|
||||
|
|
@ -124,20 +132,37 @@ enum ibmvfc_vios_errors {
|
|||
IBMVFC_COMMAND_FAILED = 0x8000,
|
||||
};
|
||||
|
||||
enum ibmvfc_fc_nvme_errors {
|
||||
IBMVFC_NVMS_VALID_ERSP = 0x0001,
|
||||
IBMVFC_NVMS_VALID_NODMA_CQE = 0x0002,
|
||||
};
|
||||
|
||||
enum ibmvfc_mad_types {
|
||||
IBMVFC_NPIV_LOGIN = 0x0001,
|
||||
IBMVFC_DISC_TARGETS = 0x0002,
|
||||
IBMVFC_DISC_TARGETS = 0x0002,
|
||||
IBMVFC_DISC_NVMF_TARGETS = 0x0003,
|
||||
IBMVFC_PORT_LOGIN = 0x0004,
|
||||
IBMVFC_PROCESS_LOGIN = 0x0008,
|
||||
IBMVFC_QUERY_TARGET = 0x0010,
|
||||
IBMVFC_NVMF_PORT_LOGIN = 0x0005,
|
||||
IBMVFC_PROCESS_LOGIN = 0x0008,
|
||||
IBMVFC_NVMF_PROCESS_LOGIN = 0x0009,
|
||||
IBMVFC_QUERY_TARGET = 0x0010,
|
||||
IBMVFC_NVMF_QUERY_TARGET = 0x0011,
|
||||
IBMVFC_MOVE_LOGIN = 0x0020,
|
||||
IBMVFC_IMPLICIT_LOGOUT = 0x0040,
|
||||
IBMVFC_PASSTHRU = 0x0200,
|
||||
IBMVFC_TMF_MAD = 0x0100,
|
||||
IBMVFC_NPIV_LOGOUT = 0x0800,
|
||||
IBMVFC_CHANNEL_ENQUIRY = 0x1000,
|
||||
IBMVFC_CHANNEL_SETUP = 0x2000,
|
||||
IBMVFC_CONNECTION_INFO = 0x4000,
|
||||
IBMVFC_NVMF_MOVE_LOGIN = 0x0021,
|
||||
IBMVFC_IMPLICIT_LOGOUT = 0x0040,
|
||||
IBMVFC_NVMF_IMPLICIT_LOGOUT = 0x0041,
|
||||
IBMVFC_RNID = 0x0080,
|
||||
IBMVFC_NVMF_RNID = 0x0081,
|
||||
IBMVFC_TMF_MAD = 0x0100,
|
||||
IBMVFC_NVMF_TMF_MAD = 0x0101,
|
||||
IBMVFC_PASSTHRU = 0x0200,
|
||||
IBMVFC_NVMF_PASSTHRU = 0x0201,
|
||||
IBMVFC_NPIV_LOGOUT = 0x0800,
|
||||
IBMVFC_CHANNEL_ENQUIRY = 0x1000,
|
||||
IBMVFC_CHANNEL_SETUP = 0x2000,
|
||||
IBMVFC_CONNECTION_INFO = 0x4000,
|
||||
IBMVFC_FABRIC_LOGIN = 0x8000,
|
||||
IBMVFC_NVMF_FABRIC_LOGIN = 0x8001,
|
||||
};
|
||||
|
||||
struct ibmvfc_mad_common {
|
||||
|
|
@ -175,11 +200,16 @@ struct ibmvfc_npiv_login {
|
|||
#define IBMVFC_FLUSH_ON_HALT 0x02
|
||||
__be32 max_cmds;
|
||||
__be64 capabilities;
|
||||
#define IBMVFC_CAN_MIGRATE 0x01
|
||||
#define IBMVFC_CAN_USE_CHANNELS 0x02
|
||||
#define IBMVFC_CAN_HANDLE_FPIN 0x04
|
||||
#define IBMVFC_CAN_USE_MAD_VERSION 0x08
|
||||
#define IBMVFC_CAN_SEND_VF_WWPN 0x10
|
||||
#define IBMVFC_CAN_MIGRATE 0x001
|
||||
#define IBMVFC_CAN_USE_CHANNELS 0x002
|
||||
#define IBMVFC_CAN_HANDLE_FPIN 0x004
|
||||
#define IBMVFC_CAN_USE_MAD_VERSION 0x008
|
||||
#define IBMVFC_CAN_SEND_VF_WWPN 0x010
|
||||
#define IBMVFC_YES_NVMEOF 0x020
|
||||
#define IBMVFC_YES_SCSI 0x040
|
||||
#define IBMVFC_CAN_USE_WWPN_ALL 0x080
|
||||
#define IBMVFC_USE_ASYNC_SUBQ 0x100
|
||||
#define IBMVFC_CAN_USE_NOOP_CMD 0x200
|
||||
__be64 node_name;
|
||||
struct srp_direct_buf async;
|
||||
u8 partition_name[IBMVFC_MAX_NAME];
|
||||
|
|
@ -219,13 +249,18 @@ struct ibmvfc_npiv_login_resp {
|
|||
__be16 error;
|
||||
__be32 flags;
|
||||
#define IBMVFC_NATIVE_FC 0x01
|
||||
__be32 reserved;
|
||||
__be32 possible_nports;
|
||||
__be64 capabilities;
|
||||
#define IBMVFC_CAN_FLUSH_ON_HALT 0x08
|
||||
#define IBMVFC_CAN_SUPPRESS_ABTS 0x10
|
||||
#define IBMVFC_MAD_VERSION_CAP 0x20
|
||||
#define IBMVFC_HANDLE_VF_WWPN 0x40
|
||||
#define IBMVFC_CAN_SUPPORT_CHANNELS 0x80
|
||||
#define IBMVFC_CAN_FLUSH_ON_HALT 0x0008
|
||||
#define IBMVFC_CAN_SUPPRESS_ABTS 0x0010
|
||||
#define IBMVFC_MAD_VERSION_CAP 0x0020
|
||||
#define IBMVFC_HANDLE_VF_WWPN 0x0040
|
||||
#define IBMVFC_CAN_SUPPORT_CHANNELS 0x0080
|
||||
#define IBMVFC_SUPPORT_NVMEOF 0x0100
|
||||
#define IBMVFC_SUPPORT_SCSI 0x0200
|
||||
#define IBMVFC_SUPPORT_WWPN_ALL 0x0400
|
||||
#define IBMVFC_ASYNC_SUBQ 0x0800
|
||||
#define IBMVFC_SUPPORT_NOOP_CMD 0x1000
|
||||
__be32 max_cmds;
|
||||
__be32 scsi_id_sz;
|
||||
__be64 max_dma_len;
|
||||
|
|
@ -238,7 +273,7 @@ struct ibmvfc_npiv_login_resp {
|
|||
u8 port_loc_code[IBMVFC_MAX_NAME];
|
||||
u8 drc_name[IBMVFC_MAX_NAME];
|
||||
struct ibmvfc_service_parms service_parms;
|
||||
__be64 reserved2;
|
||||
__be64 reserved;
|
||||
} __packed __aligned(8);
|
||||
|
||||
union ibmvfc_npiv_login_data {
|
||||
|
|
@ -246,6 +281,17 @@ union ibmvfc_npiv_login_data {
|
|||
struct ibmvfc_npiv_login_resp resp;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_fabric_login_mad {
|
||||
struct ibmvfc_mad_common common;
|
||||
__be64 flags;
|
||||
__be64 capabilities;
|
||||
__be64 nport_id;
|
||||
__be16 status;
|
||||
__be16 error;
|
||||
__be32 reserved;
|
||||
__be64 reserved2[16];
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_discover_targets_entry {
|
||||
__be32 scsi_id;
|
||||
__be32 pad;
|
||||
|
|
@ -287,6 +333,7 @@ enum ibmvfc_fc_type {
|
|||
IBMVFC_FABRIC_BUSY = 0x04,
|
||||
IBMVFC_PORT_BUSY = 0x05,
|
||||
IBMVFC_BASIC_REJECT = 0x06,
|
||||
IBMVFC_FC4_LS_REJECT = 0x07,
|
||||
};
|
||||
|
||||
enum ibmvfc_gs_explain {
|
||||
|
|
@ -334,6 +381,7 @@ struct ibmvfc_move_login {
|
|||
struct ibmvfc_prli_svc_parms {
|
||||
u8 type;
|
||||
#define IBMVFC_SCSI_FCP_TYPE 0x08
|
||||
#define IBMVFC_NVME_FCP_TYPE 0x28
|
||||
u8 type_ext;
|
||||
__be16 flags;
|
||||
#define IBMVFC_PRLI_ORIG_PA_VALID 0x8000
|
||||
|
|
@ -349,6 +397,11 @@ struct ibmvfc_prli_svc_parms {
|
|||
#define IBMVFC_PRLI_TARGET_FUNC 0x00000010
|
||||
#define IBMVFC_PRLI_READ_FCP_XFER_RDY_DISABLED 0x00000002
|
||||
#define IBMVFC_PRLI_WR_FCP_XFER_RDY_DISABLED 0x00000001
|
||||
#define IBMVFC_PRLI_NVME_PI_CTRL 0x00000200
|
||||
#define IBMVFC_PRLI_NVME_SLER 0x00000100
|
||||
#define IBMVFC_PRLI_NVME_INITIATOR 0x00000020
|
||||
#define IBMVFC_PRLI_NVME_TARGET 0x00000010
|
||||
#define IBMVFC_PRLI_NVME_DISCOVERY 0x00000008
|
||||
} __packed __aligned(4);
|
||||
|
||||
struct ibmvfc_process_login {
|
||||
|
|
@ -377,20 +430,27 @@ struct ibmvfc_query_tgt {
|
|||
struct ibmvfc_implicit_logout {
|
||||
struct ibmvfc_mad_common common;
|
||||
__be64 old_scsi_id;
|
||||
__be64 reserved[2];
|
||||
__be64 reserved[8];
|
||||
__be64 target_wwpn;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_tmf {
|
||||
struct ibmvfc_mad_common common;
|
||||
__be64 scsi_id;
|
||||
struct scsi_lun lun;
|
||||
union {
|
||||
struct scsi_lun lun;
|
||||
__be64 assoc_id;
|
||||
};
|
||||
__be32 flags;
|
||||
#define IBMVFC_TMF_ABORT_TASK 0x02
|
||||
#define IBMVFC_TMF_ABORT_TASK_SET 0x04
|
||||
#define IBMVFC_TMF_LUN_RESET 0x10
|
||||
#define IBMVFC_TMF_TGT_RESET 0x20
|
||||
#define IBMVFC_TMF_LUA_VALID 0x40
|
||||
#define IBMVFC_TMF_SUPPRESS_ABTS 0x80
|
||||
#define IBMVFC_TMF_ABORT_TASK 0x002
|
||||
#define IBMVFC_TMF_ABORT_TASK_SET 0x004
|
||||
#define IBMVFC_TMF_LUN_RESET 0x010
|
||||
#define IBMVFC_TMF_TGT_RESET 0x020
|
||||
#define IBMVFC_TMF_LUA_VALID 0x040
|
||||
#define IBMVFC_TMF_SUPPRESS_ABTS 0x080
|
||||
#define IBMVFC_TMF_NVMF_ASSOC 0x100
|
||||
#define IBMVFC_TMF_NVMF_TARGET 0x200
|
||||
#define IBMVFC_TMF_BITMASK_VALID 0x400
|
||||
__be32 cancel_key;
|
||||
__be32 my_cancel_key;
|
||||
__be32 pad;
|
||||
|
|
@ -446,6 +506,8 @@ enum ibmvfc_cmd_flags {
|
|||
IBMVFC_WRITE = 0x0008,
|
||||
IBMVFC_TMF = 0x0080,
|
||||
IBMVFC_CLASS_3_ERR = 0x0100,
|
||||
IBMVFC_NVMEOF_PROTOCOL = 0x0200,
|
||||
IBMVFC_NVMF_SLER = 0x0400,
|
||||
};
|
||||
|
||||
enum ibmvfc_fc_task_attr {
|
||||
|
|
@ -493,7 +555,7 @@ struct ibmvfc_cmd {
|
|||
__be64 tgt_scsi_id;
|
||||
__be64 tag;
|
||||
__be64 target_wwpn;
|
||||
__be64 reserved3;
|
||||
__be64 assoc_id;
|
||||
union {
|
||||
struct {
|
||||
struct ibmvfc_fcp_cmd_iu iu;
|
||||
|
|
@ -504,6 +566,15 @@ struct ibmvfc_cmd {
|
|||
struct ibmvfc_fcp_cmd_iu iu;
|
||||
struct ibmvfc_fcp_rsp rsp;
|
||||
} v2;
|
||||
struct {
|
||||
__be64 reserved5[4];
|
||||
struct ibmvfc_fcp_cmd_iu iu;
|
||||
struct ibmvfc_fcp_rsp rsp;
|
||||
} v3scsi;
|
||||
struct {
|
||||
__be64 reserved[4];
|
||||
struct nvme_fc_cmd_iu iu;
|
||||
} v3nvme;
|
||||
};
|
||||
} __packed __aligned(8);
|
||||
|
||||
|
|
@ -522,6 +593,9 @@ struct ibmvfc_passthru_iu {
|
|||
__be32 flags;
|
||||
#define IBMVFC_FC_ELS 0x01
|
||||
#define IBMVFC_FC_CT_IU 0x02
|
||||
#define IBMVFC_PT_PRLI 0x04
|
||||
#define IBMVFC_FC4_LS_OTH 0x08
|
||||
#define IBMVFC_FC4_LS_DSC_CTRL 0x10
|
||||
__be32 cancel_key;
|
||||
#define IBMVFC_PASSTHRU_CANCEL_KEY 0x80000000
|
||||
#define IBMVFC_INTERNAL_CANCEL_KEY 0x80000001
|
||||
|
|
@ -549,9 +623,9 @@ struct ibmvfc_channel_enquiry {
|
|||
#define IBMVFC_SUPPORT_VARIABLE_SUBQ_MSG 0x02
|
||||
#define IBMVFC_NO_N_TO_M_CHANNELS_SUPPORT 0x04
|
||||
__be32 num_scsi_subq_channels;
|
||||
__be32 num_nvmeof_subq_channels;
|
||||
__be32 num_nvme_subq_channels;
|
||||
__be32 num_scsi_vas_channels;
|
||||
__be32 num_nvmeof_vas_channels;
|
||||
__be32 num_nvme_vas_channels;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_channel_setup_mad {
|
||||
|
|
@ -559,7 +633,7 @@ struct ibmvfc_channel_setup_mad {
|
|||
struct srp_direct_buf buffer;
|
||||
} __packed __aligned(8);
|
||||
|
||||
#define IBMVFC_MAX_CHANNELS 502
|
||||
#define IBMVFC_MAX_CHANNELS 501
|
||||
|
||||
struct ibmvfc_channel_setup {
|
||||
__be32 flags;
|
||||
|
|
@ -568,12 +642,13 @@ struct ibmvfc_channel_setup {
|
|||
#define IBMVFC_CHANNELS_CANCELED 0x04
|
||||
__be32 reserved;
|
||||
__be32 num_scsi_subq_channels;
|
||||
__be32 num_nvmeof_subq_channels;
|
||||
__be32 num_nvme_subq_channels;
|
||||
__be32 num_scsi_vas_channels;
|
||||
__be32 num_nvmeof_vas_channels;
|
||||
__be32 num_nvme_vas_channels;
|
||||
struct srp_direct_buf buffer;
|
||||
__be64 reserved2[5];
|
||||
__be64 channel_handles[IBMVFC_MAX_CHANNELS];
|
||||
__be64 async_sub_crq_handle;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_connection_info {
|
||||
|
|
@ -620,7 +695,8 @@ struct ibmvfc_trace_entry {
|
|||
|
||||
enum ibmvfc_crq_formats {
|
||||
IBMVFC_CMD_FORMAT = 0x01,
|
||||
IBMVFC_ASYNC_EVENT = 0x02,
|
||||
IBMVFC_ASYNC_EVENT = 0x02,
|
||||
IBMVFC_NOOP = 0x03,
|
||||
IBMVFC_MAD_FORMAT = 0x04,
|
||||
};
|
||||
|
||||
|
|
@ -639,6 +715,9 @@ enum ibmvfc_async_event {
|
|||
IBMVFC_AE_RESUME = 0x0800,
|
||||
IBMVFC_AE_ADAPTER_FAILED = 0x1000,
|
||||
IBMVFC_AE_FPIN = 0x2000,
|
||||
IBMVFC_NVME_DISCONNECT = 0x4000,
|
||||
IBMVFC_NVMEOF_PROTO_AVAIL = 0x40000000,
|
||||
IBMVFC_SCSI_PROTO_AVAIL = 0x80000000,
|
||||
};
|
||||
|
||||
struct ibmvfc_async_desc {
|
||||
|
|
@ -683,13 +762,30 @@ struct ibmvfc_async_crq {
|
|||
volatile __be64 scsi_id;
|
||||
volatile __be64 wwpn;
|
||||
volatile __be64 node_name;
|
||||
__be64 reserved;
|
||||
__be64 assoc_id;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_async_sub_crq {
|
||||
volatile u8 valid;
|
||||
u8 flags;
|
||||
#define IBMVFC_ASYNC_ID_IS_ASSOC_ID 0x01
|
||||
u8 link_state;
|
||||
u8 fpin_status;
|
||||
__be16 event;
|
||||
__be16 pad;
|
||||
__be64 wwpn;
|
||||
__be64 nport_id;
|
||||
union {
|
||||
__be64 node_name;
|
||||
__be64 assoc_id;
|
||||
} id;
|
||||
} __packed __aligned(8);
|
||||
|
||||
union ibmvfc_iu {
|
||||
struct ibmvfc_mad_common mad_common;
|
||||
struct ibmvfc_npiv_login_mad npiv_login;
|
||||
struct ibmvfc_npiv_logout_mad npiv_logout;
|
||||
struct ibmvfc_fabric_login_mad fabric_login;
|
||||
struct ibmvfc_discover_targets discover_targets;
|
||||
struct ibmvfc_port_login plogi;
|
||||
struct ibmvfc_process_login prli;
|
||||
|
|
@ -728,6 +824,7 @@ struct ibmvfc_target {
|
|||
u64 scsi_id;
|
||||
u64 wwpn;
|
||||
u64 new_scsi_id;
|
||||
u64 assoc_id;
|
||||
struct fc_rport *rport;
|
||||
int target_id;
|
||||
enum ibmvfc_target_action action;
|
||||
|
|
@ -743,6 +840,8 @@ struct ibmvfc_target {
|
|||
void (*job_step) (struct ibmvfc_target *);
|
||||
struct timer_list timer;
|
||||
struct kref kref;
|
||||
struct completion nvme_delete_done;
|
||||
struct nvme_fc_remote_port *nvme_remote_port;
|
||||
};
|
||||
|
||||
/* a unit of work for the hosting partition */
|
||||
|
|
@ -753,6 +852,8 @@ struct ibmvfc_event {
|
|||
struct ibmvfc_queue *queue;
|
||||
struct ibmvfc_target *tgt;
|
||||
struct scsi_cmnd *cmnd;
|
||||
struct nvmefc_ls_req *ls_req;
|
||||
struct nvmefc_fcp_req *fcp_req;
|
||||
atomic_t free;
|
||||
atomic_t active;
|
||||
union ibmvfc_iu *xfer_iu;
|
||||
|
|
@ -828,6 +929,8 @@ struct ibmvfc_channels {
|
|||
unsigned int active_queues;
|
||||
unsigned int desired_queues;
|
||||
unsigned int max_queues;
|
||||
int num_targets;
|
||||
struct list_head targets;
|
||||
int disc_buf_sz;
|
||||
struct ibmvfc_discover_targets_entry *disc_buf;
|
||||
dma_addr_t disc_buf_dma;
|
||||
|
|
@ -871,8 +974,6 @@ struct ibmvfc_host {
|
|||
#define IBMVFC_TRACE_SIZE (sizeof(struct ibmvfc_trace_entry) * IBMVFC_NUM_TRACE_ENTRIES)
|
||||
struct ibmvfc_trace_entry *trace;
|
||||
atomic_t trace_index;
|
||||
int num_targets;
|
||||
struct list_head targets;
|
||||
struct list_head purge;
|
||||
struct device *dev;
|
||||
struct dma_pool *sg_pool;
|
||||
|
|
@ -880,6 +981,7 @@ struct ibmvfc_host {
|
|||
struct ibmvfc_queue crq;
|
||||
struct ibmvfc_queue async_crq;
|
||||
struct ibmvfc_channels scsi_scrqs;
|
||||
struct ibmvfc_channels nvme_scrqs;
|
||||
struct ibmvfc_npiv_login login_info;
|
||||
union ibmvfc_npiv_login_data *login_buf;
|
||||
dma_addr_t login_buf_dma;
|
||||
|
|
@ -888,6 +990,7 @@ struct ibmvfc_host {
|
|||
int log_level;
|
||||
struct mutex passthru_mutex;
|
||||
unsigned int max_vios_scsi_channels;
|
||||
unsigned int max_vios_nvme_channels;
|
||||
int task_set;
|
||||
int init_retries;
|
||||
int discovery_threads;
|
||||
|
|
@ -899,6 +1002,9 @@ struct ibmvfc_host {
|
|||
unsigned int mq_enabled:1;
|
||||
unsigned int using_channels:1;
|
||||
unsigned int do_enquiry:1;
|
||||
unsigned int nvme_enabled:1;
|
||||
unsigned int do_scsi_login:1;
|
||||
unsigned int do_nvme_login:1;
|
||||
unsigned int aborting_passthru:1;
|
||||
unsigned int scan_complete:1;
|
||||
int scan_timeout;
|
||||
|
|
@ -914,8 +1020,37 @@ struct ibmvfc_host {
|
|||
struct work_struct rport_add_work_q;
|
||||
wait_queue_head_t init_wait_q;
|
||||
wait_queue_head_t work_wait_q;
|
||||
struct nvme_fc_local_port *nvme_local_port;
|
||||
struct completion nvme_delete_done;
|
||||
};
|
||||
|
||||
struct ibmvfc_event *__ibmvfc_get_event(struct ibmvfc_queue *queue, int reserved);
|
||||
#define ibmvfc_get_event(queue) __ibmvfc_get_event(queue, 0)
|
||||
#define ibmvfc_get_reserved_event(queue) __ibmvfc_get_event(queue, 1)
|
||||
|
||||
void ibmvfc_init_event(struct ibmvfc_event *evt, void (*done) (struct ibmvfc_event *), u8 format);
|
||||
void ibmvfc_free_event(struct ibmvfc_event *evt);
|
||||
void ibmvfc_release_tgt(struct kref *kref);
|
||||
int ibmvfc_send_event(struct ibmvfc_event *evt, struct ibmvfc_host *vhost, unsigned long timeout);
|
||||
const char *ibmvfc_get_cmd_error(u16 status, u16 error);
|
||||
|
||||
static inline int ibmvfc_check_caps(struct ibmvfc_host *vhost, unsigned long cap_flags)
|
||||
{
|
||||
u64 host_caps = be64_to_cpu(vhost->login_buf->resp.capabilities);
|
||||
|
||||
return (host_caps & cap_flags) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline struct ibmvfc_host *ibmvfc_channels_to_vhost(struct ibmvfc_channels *channels)
|
||||
{
|
||||
if (channels->protocol == IBMVFC_PROTO_SCSI)
|
||||
return container_of(channels, struct ibmvfc_host, scsi_scrqs);
|
||||
else if (channels->protocol == IBMVFC_PROTO_NVME)
|
||||
return container_of(channels, struct ibmvfc_host, nvme_scrqs);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define DBG_CMD(CMD) do { if (ibmvfc_debug) CMD; } while (0)
|
||||
|
||||
#define tgt_dbg(t, fmt, ...) \
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user