Skip to contentSkip to conversation

qla2xxx: Add FC-NVMe Target support

PATCH Superseded Himanshu Madhani 3 participants 9 messages Nov 9, 2017 – Nov 10, 2017

Subsystems (3)

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

v2 cover qla2xxx: Add FC-NVMe Target support

Hi Christoph/Sagi,

I've corrected the mailing list and maintainers for this series.

This series adds support for FC-NVMe Target.

Patch #1 addes new qla_nvmet files for FC-NVMe Target support. Patch #2 adds Kconfig and Makefile changes to prepare code compile. Patch #3 and #4 has bulk of changes to handle FC-NVMe Target LS4 processing via Purex pass through path.

Note: All the patches in this series must be applied before they can be compilable.

These patches were cut against 4.15/scsi-queue.

Changes from v1 -> v2

o Fixed 0-day kernel warning and build regression.

Thanks,
Himanshu

Anil Gurumurthy (4):
qla2xxx_nvmet: Add files for FC-NVMe Target support
qla2xxx_nvmet: Added Makefile and Kconfig changes
qla2xxx_nvmet: Add FC-NVMe Target LS request handling
qla2xxx_nvmet: Add FC-NVMe Target handling

 drivers/scsi/qla2xxx/Kconfig      |   1 +
 drivers/scsi/qla2xxx/Makefile     |   3 +-
 drivers/scsi/qla2xxx/qla_dbg.c    |   1 +
 drivers/scsi/qla2xxx/qla_dbg.h    |   2 +
 drivers/scsi/qla2xxx/qla_def.h    |  35 +-
 drivers/scsi/qla2xxx/qla_fw.h     | 263 +++++++++++
 drivers/scsi/qla2xxx/qla_gbl.h    |  17 +-
 drivers/scsi/qla2xxx/qla_gs.c     |  15 +-
 drivers/scsi/qla2xxx/qla_init.c   |  49 +-
 drivers/scsi/qla2xxx/qla_iocb.c   |  42 +-
 drivers/scsi/qla2xxx/qla_isr.c    |  70 +++
 drivers/scsi/qla2xxx/qla_mbx.c    | 100 +++-
 drivers/scsi/qla2xxx/qla_nvme.h   |  33 --
 drivers/scsi/qla2xxx/qla_nvmet.c  | 783 ++++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_nvmet.h  | 130 ++++++
 drivers/scsi/qla2xxx/qla_os.c     |  75 ++-
 drivers/scsi/qla2xxx/qla_target.c | 932 +++++++++++++++++++++++++++++++++++++-
 drivers/scsi/qla2xxx/qla_target.h |  93 +++-
 18 files changed, 2585 insertions(+), 59 deletions(-)
 create mode 100644 drivers/scsi/qla2xxx/qla_nvmet.c
 create mode 100644 drivers/scsi/qla2xxx/qla_nvmet.h
Signature · 1 line
2.12.0
#1 lore raw

PATCH v2 1/4 qla2xxx_nvmet: Add files for FC-NVMe Target support

From: Anil Gurumurthy <[email protected]>

Signed-off-by Anil Gurumurthy <anil.gurumurthy at cavium.com>
Signed-off-by Giridhar Malavali <giridhar.malavali at cavium.com>
Signed-off-by Darren Trapp <darren.trapp at cavium.com>
Signed-off-by Himanshu Madhani <himanshu.madhani at cavium.com>
---
 drivers/scsi/qla2xxx/qla_nvmet.c | 783 +++++++++++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_nvmet.h | 130 +++++++
 2 files changed, 913 insertions(+)
 create mode 100644 drivers/scsi/qla2xxx/qla_nvmet.c
 create mode 100644 drivers/scsi/qla2xxx/qla_nvmet.h
drivers/scsi/qla2xxx/qla_nvmet.c new file +783 -0
new file mode 100644
index 000000000000..ed486a2f899f
@@ -0,0 +1,783 @@
+
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2017 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#include <linux/scatterlist.h>
+#include <linux/delay.h>
+#include <linux/nvme.h>
+#include <linux/nvme-fc.h>
+
+#include "qla_nvme.h"
+#include "qla_nvmet.h"
+
+#if	IS_ENABLED(CONFIG_NVME_TARGET_FC)
+static void qla_nvmet_send_resp_ctio(struct qla_qpair *qpair,
+	struct qla_nvmet_cmd *cmd, struct nvmefc_tgt_fcp_req *rsp);
+static void qla_nvmet_send_abts_ctio(struct scsi_qla_host *vha,
+		struct abts_recv_from_24xx *abts, bool flag);
+
+/*
+ * qla_nvmet_targetport_delete -
+ * Invoked by the nvmet to indicate that the target port has
+ * been deleted
+ */
+static void
+qla_nvmet_targetport_delete(struct nvmet_fc_target_port *targetport)
+{
+	struct qla_nvmet_tgtport *tport = targetport->private;
+
+	complete(&tport->tport_del);
+}
+#endif
+
+#if	IS_ENABLED(CONFIG_NVME_TARGET_FC)
+/*
+ * qlt_nvmet_ls_done -
+ * Invoked by the firmware interface to indicate the completion
+ * of an LS cmd
+ * Free all associated resources of the LS cmd
+ */
+static void qlt_nvmet_ls_done(void *ptr, int res)
+{
+	struct srb *sp = ptr;
+	struct srb_iocb   *nvme = &sp->u.iocb_cmd;
+	struct nvmefc_tgt_ls_req *rsp = nvme->u.nvme.desc;
+	struct qla_nvmet_cmd *tgt_cmd = nvme->u.nvme.cmd;
+
+	ql_log(ql_log_info, sp->vha, 0x11000,
+		"Done with NVME LS4 req\n");
+
+	ql_log(ql_log_info, sp->vha, 0x11001,
+		"sp: %p vha: %p, rsp: %p, cmd: %p\n",
+		sp, sp->vha, nvme->u.nvme.desc, nvme->u.nvme.cmd);
+
+	rsp->done(rsp);
+	/* Free tgt_cmd */
+	kfree(tgt_cmd->buf);
+	kfree(tgt_cmd);
+	qla2x00_rel_sp(sp);
+}
+
+/*
+ * qla_nvmet_ls_rsp -
+ * Invoked by the nvme-t to complete the LS req.
+ * Prepare and send a response CTIO to the firmware.
+ */
+static int
+qla_nvmet_ls_rsp(struct nvmet_fc_target_port *tgtport,
+			struct nvmefc_tgt_ls_req *rsp)
+{
+	struct qla_nvmet_cmd *tgt_cmd =
+		container_of(rsp, struct qla_nvmet_cmd, cmd.ls_req);
+	struct scsi_qla_host *vha = tgt_cmd->vha;
+	struct srb_iocb   *nvme;
+	int     rval = QLA_FUNCTION_FAILED;
+	srb_t *sp;
+
+	ql_log(ql_log_info, vha, 0x11002,
+		"Dumping the NVMET-LS response buffer\n");
+	ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2075,
+		(uint8_t *)rsp->rspbuf, rsp->rsplen);
+
+	/* Alloc SRB structure */
+	sp = qla2x00_get_sp(vha, NULL, GFP_ATOMIC);
+	if (!sp) {
+		ql_log(ql_log_info, vha, 0x11003, "Failed to allocate SRB\n");
+		return -ENOMEM;
+	}
+
+	sp->type = SRB_NVMET_LS;
+	sp->done = qlt_nvmet_ls_done;
+	sp->vha = vha;
+	sp->fcport = tgt_cmd->fcport;
+
+	nvme = &sp->u.iocb_cmd;
+	nvme->u.nvme.rsp_dma = rsp->rspdma;
+	nvme->u.nvme.rsp_len = rsp->rsplen;
+	nvme->u.nvme.exchange_address = tgt_cmd->atio.u.pt_ls4.exchange_address;
+	nvme->u.nvme.nport_handle = tgt_cmd->atio.u.pt_ls4.nport_handle;
+	nvme->u.nvme.vp_index = tgt_cmd->atio.u.pt_ls4.vp_index;
+
+	nvme->u.nvme.cmd = tgt_cmd; /* To be freed */
+	nvme->u.nvme.desc = rsp; /* Call back to nvmet */
+
+	rval = qla2x00_start_sp(sp);
+	if (rval != QLA_SUCCESS) {
+		ql_log(ql_log_warn, vha, 0x11004,
+			"qla2x00_start_sp failed = %d\n", rval);
+		return rval;
+	}
+
+	return 0;
+}
+
+/*
+ * qla_nvmet_fcp_op -
+ * Invoked by the nvme-t to complete the IO.
+ * Prepare and send a response CTIO to the firmware.
+ */
+static int
+qla_nvmet_fcp_op(struct nvmet_fc_target_port *tgtport,
+			struct nvmefc_tgt_fcp_req *rsp)
+{
+	struct qla_nvmet_cmd *tgt_cmd =
+		container_of(rsp, struct qla_nvmet_cmd, cmd.fcp_req);
+	struct scsi_qla_host *vha = tgt_cmd->vha;
+
+	/* Prepare and send CTIO 82h */
+	qla_nvmet_send_resp_ctio(vha->qpair, tgt_cmd, rsp);
+
+	return 0;
+}
+/*
+ * qla_nvmet_fcp_abort_done
+ * free up the used resources
+ */
+static void qla_nvmet_fcp_abort_done(void *ptr, int res)
+{
+	srb_t *sp = ptr;
+
+	qla2x00_rel_sp(sp);
+}
+
+/*
+ * qla_nvmet_fcp_abort -
+ * Invoked by the nvme-t to abort an IO
+ * Send an abort to the firmware
+ */
+static void
+qla_nvmet_fcp_abort(struct nvmet_fc_target_port *tgtport,
+			struct nvmefc_tgt_fcp_req *req)
+{
+	struct qla_nvmet_cmd *tgt_cmd =
+		container_of(req, struct qla_nvmet_cmd, cmd.fcp_req);
+	struct scsi_qla_host *vha = tgt_cmd->vha;
+	struct qla_hw_data *ha = vha->hw;
+	srb_t *sp;
+
+	/* Alloc SRB structure */
+	sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL);
+	if (!sp) {
+		ql_log(ql_log_info, vha, 0x11005, "Failed to allocate SRB\n");
+		return;
+	}
+
+	sp->type = SRB_NVMET_SEND_ABTS;
+	sp->done = qla_nvmet_fcp_abort_done;
+	sp->vha = vha;
+	sp->fcport = tgt_cmd->fcport;
+
+	ha->isp_ops->abort_command(sp);
+
+}
+
+/*
+ * qla_nvmet_fcp_req_release -
+ * Delete the cmd from the list and free the cmd
+ */
+
+static void
+qla_nvmet_fcp_req_release(struct nvmet_fc_target_port *tgtport,
+			struct nvmefc_tgt_fcp_req *rsp)
+{
+	struct qla_nvmet_cmd *tgt_cmd =
+		container_of(rsp, struct qla_nvmet_cmd, cmd.fcp_req);
+	scsi_qla_host_t *vha = tgt_cmd->vha;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vha->cmd_list_lock, flags);
+	list_del(&tgt_cmd->cmd_list);
+	spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
+
+	kfree(tgt_cmd);
+}
+
+static struct nvmet_fc_target_template qla_nvmet_fc_transport = {
+	.targetport_delete	= qla_nvmet_targetport_delete,
+	.xmt_ls_rsp		= qla_nvmet_ls_rsp,
+	.fcp_op			= qla_nvmet_fcp_op,
+	.fcp_abort		= qla_nvmet_fcp_abort,
+	.fcp_req_release	= qla_nvmet_fcp_req_release,
+	.max_hw_queues		= 8,
+	.max_sgl_segments	= 128,
+	.max_dif_sgl_segments	= 64,
+	.dma_boundary		= 0xFFFFFFFF,
+	.target_features	= NVMET_FCTGTFEAT_READDATA_RSP |
+					NVMET_FCTGTFEAT_CMD_IN_ISR |
+					NVMET_FCTGTFEAT_OPDONE_IN_ISR,
+	.target_priv_sz	= sizeof(struct nvme_private),
+};
+#endif
+/*
+ * qla_nvmet_create_targetport -
+ * Create a targetport. Registers the template with the nvme-t
+ * layer
+ */
+int qla_nvmet_create_targetport(struct scsi_qla_host *vha)
+{
+#if	IS_ENABLED(CONFIG_NVME_TARGET_FC)
+	struct nvmet_fc_port_info pinfo;
+	struct qla_nvmet_tgtport *tport;
+	int error = 0;
+
+	ql_dbg(ql_dbg_nvme, vha, 0xe081,
+		"Creating target port for :%p\n", vha);
+
+	memset(&pinfo, 0, (sizeof(struct nvmet_fc_port_info)));
+	pinfo.node_name = wwn_to_u64(vha->node_name);
+	pinfo.port_name = wwn_to_u64(vha->port_name);
+	pinfo.port_id	= vha->d_id.b24;
+
+	error = nvmet_fc_register_targetport(&pinfo,
+	    &qla_nvmet_fc_transport, &vha->hw->pdev->dev,
+	    &vha->targetport);
+
+	if (error) {
+		ql_dbg(ql_dbg_nvme, vha, 0xe082,
+			"Cannot register NVME transport:%d\n", error);
+		return error;
+	}
+	tport = (struct qla_nvmet_tgtport *)vha->targetport->private;
+	tport->vha = vha;
+	ql_dbg(ql_dbg_nvme, vha, 0xe082,
+		" Registered NVME transport:%p WWPN:%llx\n",
+		tport, pinfo.port_name);
+#endif
+	return 0;
+}
+
+/*
+ * qla_nvmet_delete -
+ * Delete a targetport.
+ */
+int qla_nvmet_delete(struct scsi_qla_host *vha)
+{
+#if	IS_ENABLED(CONFIG_NVME_TARGET_FC)
+	struct qla_nvmet_tgtport *tport;
+
+	if (!vha->flags.nvmet_enabled)
+		return 0;
+	if (vha->targetport) {
+		tport = (struct qla_nvmet_tgtport *)vha->targetport->private;
+
+		ql_dbg(ql_dbg_nvme, vha, 0xe083,
+			"Deleting target port :%p\n", tport);
+		init_completion(&tport->tport_del);
+		nvmet_fc_unregister_targetport(vha->targetport);
+		wait_for_completion_timeout(&tport->tport_del, 5);
+
+		nvmet_release_sessions(vha);
+	}
+#endif
+	return 0;
+}
+
+/*
+ * qla_nvmet_handle_ls -
+ * Handle a link service request from the initiator.
+ * Get the LS payload from the ATIO queue, invoke
+ * nvmet_fc_rcv_ls_req to pass the LS req to nvmet.
+ */
+int qla_nvmet_handle_ls(struct scsi_qla_host *vha,
+	struct pt_ls4_rx_unsol *pt_ls4, void *buf)
+{
+#if	IS_ENABLED(CONFIG_NVME_TARGET_FC)
+	struct qla_nvmet_cmd *tgt_cmd;
+	uint32_t size;
+	int ret;
+	uint32_t look_up_sid;
+	fc_port_t *sess = NULL;
+
+	look_up_sid = pt_ls4->s_id[2] << 16 |
+				pt_ls4->s_id[1] << 8 | pt_ls4->s_id[0];
+
+	ql_log(ql_log_info, vha, 0x11005,
+		"%s - Look UP sid: %#x\n", __func__, look_up_sid);
+
+	sess = qla_nvmet_find_sess_by_s_id(vha, look_up_sid);
+	if (unlikely(!sess))
+		WARN_ON(1);
+
+	size = cpu_to_le16(pt_ls4->desc_len) + 8;
+
+	tgt_cmd = kzalloc(sizeof(struct qla_nvmet_cmd), GFP_ATOMIC);
+	if (tgt_cmd == NULL) {
+		ql_dbg(ql_dbg_nvme, vha, 0xe084,
+			"Memory allocation failed\n");
+		return -ENOMEM;
+	}
+	tgt_cmd->vha = vha;
+	tgt_cmd->ox_id = pt_ls4->ox_id;
+	tgt_cmd->buf = buf;
+	/* Store the received nphdl, rx_exh_addr etc */
+	memcpy(&tgt_cmd->atio.u.pt_ls4, pt_ls4, sizeof(struct pt_ls4_rx_unsol));
+	tgt_cmd->fcport = sess;
+
+	ql_log(ql_log_info, vha, 0x11006,
+		"Dumping the PURLS-ATIO request\n");
+	ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2075,
+		(uint8_t *)pt_ls4, sizeof(struct pt_ls4_rx_unsol));
+
+	ql_log(ql_log_info, vha, 0x11007,
+		"Sending LS to nvmet buf: %p, len: %#x\n", buf, size);
+
+	ret = nvmet_fc_rcv_ls_req(vha->targetport,
+		&tgt_cmd->cmd.ls_req, buf, size);
+
+	if (ret == 0) {
+		ql_log(ql_log_info, vha, 0x11008,
+			"LS req handled successfully\n");
+		return 0;
+	}
+	ql_log(ql_log_warn, vha, 0x11009,
+		"LS req failed\n");
+
+	return ret;
+#else
+	return 0;
+#endif
+}
+
+/*
+ * qla_nvmet_process_cmd -
+ * Handle NVME cmd request from the initiator.
+ * Get the NVME payload from the ATIO queue, invoke
+ * nvmet_fc_rcv_ls_req to pass the LS req to nvmet.
+ * On a failure send an abts to the initiator?
+ */
+int qla_nvmet_process_cmd(struct scsi_qla_host *vha,
+	struct qla_nvmet_cmd *tgt_cmd)
+{
+#if	IS_ENABLED(CONFIG_NVME_TARGET_FC)
+	int ret;
+	struct atio7_nvme_cmnd *nvme_cmd;
+
+	nvme_cmd = (struct atio7_nvme_cmnd *)&tgt_cmd->nvme_cmd_iu;
+
+	ret = nvmet_fc_rcv_fcp_req(vha->targetport, &tgt_cmd->cmd.fcp_req,
+			nvme_cmd, tgt_cmd->cmd_len);
+	if (ret != 0) {
+		ql_log(ql_log_warn, vha, 0x1100a,
+			"%s-%d - Failed (ret: %#x) to process NVME command\n",
+				__func__, __LINE__, ret);
+		/* Send ABTS to initator ? */
+	}
+#endif
+	return 0;
+}
+
+/*
+ * qla_nvmet_handle_abts
+ * Handle an abort from the initiator
+ * Invoke nvmet_fc_rcv_fcp_abort to pass the abts to the nvmet
+ */
+int qla_nvmet_handle_abts(struct scsi_qla_host *vha,
+	struct abts_recv_from_24xx *abts)
+{
+#if	IS_ENABLED(CONFIG_NVME_TARGET_FC)
+	uint16_t ox_id = cpu_to_be16(abts->fcp_hdr_le.ox_id);
+	unsigned long flags;
+	struct qla_nvmet_cmd *cmd = NULL;
+
+	/* Retrieve the cmd from cmd list */
+	spin_lock_irqsave(&vha->cmd_list_lock, flags);
+	list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
+		if (cmd->ox_id == ox_id)
+			break; /* Found the cmd */
+	}
+	spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
+	if (!cmd) {
+		ql_log(ql_log_warn, vha, 0x1100b,
+			"%s-%d - Command not found\n", __func__, __LINE__);
+		/* Send a RJT */
+		qla_nvmet_send_abts_ctio(vha, abts, 0);
+		return 0;
+	}
+
+	nvmet_fc_rcv_fcp_abort(vha->targetport, &cmd->cmd.fcp_req);
+	/* Send an ACC */
+	qla_nvmet_send_abts_ctio(vha, abts, 1);
+#endif
+	return 0;
+}
+
+#if	IS_ENABLED(CONFIG_NVME_TARGET_FC)
+/*
+ * qla_nvmet_abts_done
+ * Complete the cmd back to the nvme-t and
+ * free up the used resources
+ */
+static void qla_nvmet_abts_done(void *ptr, int res)
+{
+	srb_t *sp = ptr;
+
+	qla2x00_rel_sp(sp);
+}
+/*
+ * qla_nvmet_fcp_done
+ * Complete the cmd back to the nvme-t and
+ * free up the used resources
+ */
+static void qla_nvmet_fcp_done(void *ptr, int res)
+{
+	srb_t *sp = ptr;
+	struct nvmefc_tgt_fcp_req *rsp;
+
+	rsp = sp->u.iocb_cmd.u.nvme.desc;
+
+	if (res) {
+		rsp->fcp_error = NVME_SC_SUCCESS;
+		if (rsp->op == NVMET_FCOP_RSP)
+			rsp->transferred_length = 0;
+		else
+			rsp->transferred_length = rsp->transfer_length;
+	} else {
+		rsp->fcp_error = NVME_SC_DATA_XFER_ERROR;
+		rsp->transferred_length = 0;
+	}
+	rsp->done(rsp);
+	qla2x00_rel_sp(sp);
+}
+
+/*
+ * qla_nvmet_send_resp_ctio
+ * Send the response CTIO to the firmware
+ */
+static void qla_nvmet_send_resp_ctio(struct qla_qpair *qpair,
+	struct qla_nvmet_cmd *cmd, struct nvmefc_tgt_fcp_req *rsp_buf)
+{
+	struct atio_from_isp *atio = &cmd->atio;
+	struct ctio_nvme_to_27xx *ctio;
+	struct scsi_qla_host *vha = cmd->vha;
+	struct qla_hw_data *ha = vha->hw;
+	struct fcp_hdr *fchdr = &atio->u.nvme_isp27.fcp_hdr;
+	srb_t *sp;
+	unsigned long flags;
+	uint16_t temp, c_flags = 0;
+	struct req_que *req = vha->hw->req_q_map[0];
+	uint32_t req_cnt = 1;
+	uint32_t *cur_dsd;
+	uint16_t avail_dsds;
+	uint16_t tot_dsds, i, cnt;
+	struct scatterlist *sgl, *sg;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Alloc SRB structure */
+	sp = qla2x00_get_sp(vha, cmd->fcport, GFP_KERNEL);
+	if (!sp) {
+		ql_log(ql_log_info, vha, 0x1100c, "Failed to allocate SRB\n");
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		return;
+	}
+
+	sp->type = SRB_NVMET_FCP;
+	sp->name = "nvmet_fcp";
+	sp->done = qla_nvmet_fcp_done;
+	sp->u.iocb_cmd.u.nvme.desc = rsp_buf;
+	sp->u.iocb_cmd.u.nvme.cmd = cmd;
+
+	ctio = (struct ctio_nvme_to_27xx *)qla2x00_alloc_iocbs(vha, sp);
+	if (!ctio) {
+		ql_dbg(ql_dbg_nvme, vha, 0x3067,
+		    "qla2x00t(%ld): %s failed: unable to allocate request packet",
+		    vha->host_no, __func__);
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		return;
+	}
+
+	ctio->entry_type = CTIO_NVME;
+	ctio->entry_count = 1;
+	ctio->handle = sp->handle;
+	ctio->nport_handle = cpu_to_le16(cmd->fcport->loop_id);
+	ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT);
+	ctio->vp_index = vha->vp_idx;
+	ctio->initiator_id[0] = fchdr->s_id[2];
+	ctio->initiator_id[1] = fchdr->s_id[1];
+	ctio->initiator_id[2] = fchdr->s_id[0];
+	ctio->exchange_addr = atio->u.nvme_isp27.exchange_addr;
+	temp = be16_to_cpu(fchdr->ox_id);
+	ctio->ox_id = cpu_to_le16(temp);
+	tot_dsds = ctio->dseg_count = cpu_to_le16(rsp_buf->sg_cnt);
+	c_flags = atio->u.nvme_isp27.attr << 9;
+
+	if ((ctio->dseg_count > 1) && (rsp_buf->op != NVMET_FCOP_RSP)) {
+		/* Check for additional continuation IOCB space */
+		req_cnt = qla24xx_calc_iocbs(vha, ctio->dseg_count);
+		ctio->entry_count = req_cnt;
+
+		if (req->cnt < (req_cnt + 2)) {
+			cnt = (uint16_t)RD_REG_DWORD_RELAXED(req->req_q_out);
+
+			if  (req->ring_index < cnt)
+				req->cnt = cnt - req->ring_index;
+			else
+				req->cnt = req->length -
+				    (req->ring_index - cnt);
+
+			if (unlikely(req->cnt < (req_cnt + 2))) {
+				ql_log(ql_log_warn, vha, 0xfff,
+					"Running out of IOCB space for continuation IOCBs\n");
+				goto err_exit;
+			}
+		}
+	}
+
+	switch (rsp_buf->op) {
+	case NVMET_FCOP_READDATA:
+	case NVMET_FCOP_READDATA_RSP:
+		/* Populate the CTIO resp with the SGL present in the rsp */
+		ql_log(ql_log_info, vha, 0x1100c,
+			"op: %#x, ox_id=%x c_flags=%x transfer_length: %#x req_cnt: %#x, tot_dsds: %#x\n",
+			rsp_buf->op, ctio->ox_id, c_flags,
+			rsp_buf->transfer_length, req_cnt, tot_dsds);
+
+		avail_dsds = 1;
+		cur_dsd = (uint32_t *)
+				&ctio->u.nvme_status_mode0.dsd0[0];
+		sgl = rsp_buf->sg;
+
+		/* Load data segments */
+		for_each_sg(sgl, sg, tot_dsds, i) {
+			dma_addr_t      sle_dma;
+			cont_a64_entry_t *cont_pkt;
+
+			/* Allocate additional continuation packets? */
+			if (avail_dsds == 0) {
+				/*
+				 * Five DSDs are available in the Cont
+				 * Type 1 IOCB.
+				 */
+
+				/* Adjust ring index */
+				req->ring_index++;
+				if (req->ring_index == req->length) {
+					req->ring_index = 0;
+					req->ring_ptr = req->ring;
+				} else {
+					req->ring_ptr++;
+				}
+				cont_pkt = (cont_a64_entry_t *)
+						req->ring_ptr;
+				*((uint32_t *)(&cont_pkt->entry_type)) =
+					cpu_to_le32(CONTINUE_A64_TYPE);
+
+				cur_dsd = (uint32_t *)
+						cont_pkt->dseg_0_address;
+				avail_dsds = 5;
+			}
+
+			sle_dma = sg_dma_address(sg);
+			*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+			*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+			*cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+			avail_dsds--;
+		}
+
+		ctio->u.nvme_status_mode0.transfer_len =
+			cpu_to_le32(rsp_buf->transfer_length);
+		ctio->u.nvme_status_mode0.relative_offset =
+			cpu_to_le32(rsp_buf->offset);
+		ctio->flags = cpu_to_le16(c_flags | 0x2);
+
+		if (rsp_buf->op == NVMET_FCOP_READDATA_RSP) {
+			if (rsp_buf->rsplen == 12) {
+				ctio->flags |=
+					NVMET_CTIO_STS_MODE0 |
+					NVMET_CTIO_SEND_STATUS;
+			} else if (rsp_buf->rsplen == 32) {
+				struct nvme_fc_ersp_iu *ersp =
+				    rsp_buf->rspaddr;
+				uint32_t iter = 4, *inbuf, *outbuf;
+
+				ctio->flags |=
+					NVMET_CTIO_STS_MODE1 |
+					NVMET_CTIO_SEND_STATUS;
+				inbuf = (uint32_t *)
+					&((uint8_t *)rsp_buf->rspaddr)[16];
+				outbuf = (uint32_t *)
+				    ctio->u.nvme_status_mode1.nvme_comp_q_entry;
+				for (; iter; iter--)
+					*outbuf++ = cpu_to_be32(*inbuf++);
+
+				ctio->u.nvme_status_mode1.rsp_seq_num =
+					cpu_to_be32(ersp->rsn);
+				ctio->u.nvme_status_mode1.transfer_len =
+					cpu_to_be32(ersp->xfrd_len);
+			} else
+				ql_log(ql_log_warn, vha, 0x1100d,
+						"unhandled resp len = %x\n",
+						rsp_buf->rsplen);
+		}
+		break;
+
+	case NVMET_FCOP_WRITEDATA:
+		/* Send transfer rdy */
+		ql_log(ql_log_info, vha, 0x1100e,
+			"FCOP_WRITE: ox_id=%x c_flags=%x transfer_length: %#x req_cnt: %#x, tot_dsds: %#x\n",
+			ctio->ox_id, c_flags, rsp_buf->transfer_length,
+			req_cnt, tot_dsds);
+
+		ctio->flags = cpu_to_le16(c_flags | 0x1);
+
+		avail_dsds = 1;
+		cur_dsd = (uint32_t *)&ctio->u.nvme_status_mode0.dsd0[0];
+		sgl = rsp_buf->sg;
+
+		/* Load data segments */
+		for_each_sg(sgl, sg, tot_dsds, i) {
+			dma_addr_t      sle_dma;
+			cont_a64_entry_t *cont_pkt;
+
+			/* Allocate additional continuation packets? */
+			if (avail_dsds == 0) {
+				/*
+				 * Five DSDs are available in the Continuation
+				 * Type 1 IOCB.
+				 */
+
+				/* Adjust ring index */
+				req->ring_index++;
+				if (req->ring_index == req->length) {
+					req->ring_index = 0;
+					req->ring_ptr = req->ring;
+				} else {
+					req->ring_ptr++;
+				}
+				cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
+				*((uint32_t *)(&cont_pkt->entry_type)) =
+					cpu_to_le32(CONTINUE_A64_TYPE);
+
+				cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
+				avail_dsds = 5;
+			}
+
+			sle_dma = sg_dma_address(sg);
+			*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+			*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+			*cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+			avail_dsds--;
+		}
+
+		ctio->u.nvme_status_mode0.transfer_len =
+			cpu_to_le32(rsp_buf->transfer_length);
+		ctio->u.nvme_status_mode0.relative_offset =
+			cpu_to_le32(rsp_buf->offset);
+
+		break;
+	case NVMET_FCOP_RSP:
+		/* Send a response frame */
+		ctio->flags = cpu_to_le16(c_flags);
+		if (rsp_buf->rsplen == 12) {
+			ctio->flags |=
+			NVMET_CTIO_STS_MODE0 | NVMET_CTIO_SEND_STATUS;
+		} else if (rsp_buf->rsplen == 32) {
+			struct nvme_fc_ersp_iu *ersp = rsp_buf->rspaddr;
+			uint32_t iter = 4, *inbuf, *outbuf;
+
+			ctio->flags |=
+				NVMET_CTIO_STS_MODE1 | NVMET_CTIO_SEND_STATUS;
+			inbuf = (uint32_t *)
+				&((uint8_t *)rsp_buf->rspaddr)[16];
+			outbuf = (uint32_t *)
+				ctio->u.nvme_status_mode1.nvme_comp_q_entry;
+			for (; iter; iter--)
+				*outbuf++ = cpu_to_be32(*inbuf++);
+			ctio->u.nvme_status_mode1.rsp_seq_num =
+						cpu_to_be32(ersp->rsn);
+			ctio->u.nvme_status_mode1.transfer_len =
+						cpu_to_be32(ersp->xfrd_len);
+
+			ql_log(ql_log_info, vha, 0x1100f,
+				"op: %#x, rsplen: %#x\n", rsp_buf->op,
+				rsp_buf->rsplen);
+		} else
+			ql_log(ql_log_warn, vha, 0x11010,
+				"unhandled resp len = %x for op NVMET_FCOP_RSP\n",
+				rsp_buf->rsplen);
+		break;
+	}
+
+	/* Memory Barrier */
+	wmb();
+
+	qla2x00_start_iocbs(vha, vha->hw->req_q_map[0]);
+err_exit:
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+/*
+ * qla_nvmet_send_abts_ctio
+ * Send the abts CTIO to the firmware
+ */
+static void qla_nvmet_send_abts_ctio(struct scsi_qla_host *vha,
+		struct abts_recv_from_24xx *rabts, bool flag)
+{
+	struct abts_resp_to_24xx *resp;
+	srb_t *sp;
+	uint32_t f_ctl;
+	uint8_t *p;
+
+	/* Alloc SRB structure */
+	sp = qla2x00_get_sp(vha, NULL, GFP_ATOMIC);
+	if (!sp) {
+		ql_log(ql_log_info, vha, 0x11011, "Failed to allocate SRB\n");
+		return;
+	}
+
+	sp->type = SRB_NVMET_ABTS;
+	sp->name = "nvmet_abts";
+	sp->done = qla_nvmet_abts_done;
+
+	resp = (struct abts_resp_to_24xx *)qla2x00_alloc_iocbs(vha, sp);
+	if (!resp) {
+		ql_dbg(ql_dbg_nvme, vha, 0x3067,
+		    "qla2x00t(%ld): %s failed: unable to allocate request packet",
+		    vha->host_no, __func__);
+		return;
+	}
+
+	resp->entry_type = ABTS_RESP_24XX;
+	resp->entry_count = 1;
+	resp->handle = sp->handle;
+
+	resp->nport_handle = rabts->nport_handle;
+	resp->vp_index = rabts->vp_index;
+	resp->exchange_address = rabts->exchange_addr_to_abort;
+	resp->fcp_hdr_le = rabts->fcp_hdr_le;
+	f_ctl = cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP |
+	    F_CTL_LAST_SEQ | F_CTL_END_SEQ |
+	    F_CTL_SEQ_INITIATIVE);
+	p = (uint8_t *)&f_ctl;
+	resp->fcp_hdr_le.f_ctl[0] = *p++;
+	resp->fcp_hdr_le.f_ctl[1] = *p++;
+	resp->fcp_hdr_le.f_ctl[2] = *p;
+
+	resp->fcp_hdr_le.d_id[0] = rabts->fcp_hdr_le.s_id[0];
+	resp->fcp_hdr_le.d_id[1] = rabts->fcp_hdr_le.s_id[1];
+	resp->fcp_hdr_le.d_id[2] = rabts->fcp_hdr_le.s_id[2];
+	resp->fcp_hdr_le.s_id[0] = rabts->fcp_hdr_le.d_id[0];
+	resp->fcp_hdr_le.s_id[1] = rabts->fcp_hdr_le.d_id[1];
+	resp->fcp_hdr_le.s_id[2] = rabts->fcp_hdr_le.d_id[2];
+
+	if (flag) { /* BA_ACC */
+		resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_ACC;
+		resp->payload.ba_acct.seq_id_valid = SEQ_ID_INVALID;
+		resp->payload.ba_acct.low_seq_cnt = 0x0000;
+		resp->payload.ba_acct.high_seq_cnt = 0xFFFF;
+		resp->payload.ba_acct.ox_id = rabts->fcp_hdr_le.ox_id;
+		resp->payload.ba_acct.rx_id = rabts->fcp_hdr_le.rx_id;
+	} else {
+		resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_RJT;
+		resp->payload.ba_rjt.reason_code =
+			BA_RJT_REASON_CODE_UNABLE_TO_PERFORM;
+	}
+	/* Memory Barrier */
+	wmb();
+
+	qla2x00_start_iocbs(vha, vha->hw->req_q_map[0]);
+}
+#endif
drivers/scsi/qla2xxx/qla_nvmet.h new file +130 -0

130 lines not on this page · raw message

Signature · 1 line
2.12.0
#2 lore raw

PATCH v2 1/4 qla2xxx_nvmet: Add files for FC-NVMe Target support

Quoted 6 lines · Himanshu Madhani
drivers/scsi/qla2xxx/qla_nvmet.c new file +5 -0
+static struct nvmet_fc_target_template qla_nvmet_fc_transport = {
+	.targetport_delete	= qla_nvmet_targetport_delete,
+	.xmt_ls_rsp		= qla_nvmet_ls_rsp,
+	.fcp_op			= qla_nvmet_fcp_op,
+	.fcp_abort		= qla_nvmet_fcp_abort,

drivers/scsi/qla2xxx/qla_nvmet.c line 212

Quoted 10 lines
drivers/scsi/qla2xxx/qla_nvmet.c new file +10 -0
+	.fcp_req_release	= qla_nvmet_fcp_req_release,
+	.max_hw_queues		= 8,
+	.max_sgl_segments	= 128,
+	.max_dif_sgl_segments	= 64,
+	.dma_boundary		= 0xFFFFFFFF,
+	.target_features	= NVMET_FCTGTFEAT_READDATA_RSP |
+					NVMET_FCTGTFEAT_CMD_IN_ISR |
+					NVMET_FCTGTFEAT_OPDONE_IN_ISR,
+	.target_priv_sz	= sizeof(struct nvme_private),
+};

From the patch set prior:

Quoted 1 line

Agree we do nvme_fc* callbacks in deferred context, but without the

xxx_IN_ISR flag during NVMe Target template registration, we were running into crash due to recursive spin_lock held as part of CTIO response in our driver.

Can you look into removing this recursive spin lock ? ?? I don't think it's a good idea to be holding a spin lock when upcalling the transport.

-- james

#3 lore raw

PATCH v2 1/4 qla2xxx_nvmet: Add files for FC-NVMe Target support

Hi James,

Quoted 19 lines · James Smart
Quoted 6 lines · Himanshu Madhani
drivers/scsi/qla2xxx/qla_nvmet.c new file +5 -0
+static struct nvmet_fc_target_template qla_nvmet_fc_transport = {
+	.targetport_delete	= qla_nvmet_targetport_delete,
+	.xmt_ls_rsp		= qla_nvmet_ls_rsp,
+	.fcp_op			= qla_nvmet_fcp_op,
+	.fcp_abort		= qla_nvmet_fcp_abort,

drivers/scsi/qla2xxx/qla_nvmet.c line 212

Quoted 10 lines
drivers/scsi/qla2xxx/qla_nvmet.c new file +10 -0
+	.fcp_req_release	= qla_nvmet_fcp_req_release,
+	.max_hw_queues		= 8,
+	.max_sgl_segments	= 128,
+	.max_dif_sgl_segments	= 64,
+	.dma_boundary		= 0xFFFFFFFF,
+	.target_features	= NVMET_FCTGTFEAT_READDATA_RSP |
+					NVMET_FCTGTFEAT_CMD_IN_ISR |
+					NVMET_FCTGTFEAT_OPDONE_IN_ISR,
+	.target_priv_sz	= sizeof(struct nvme_private),
+};

From the patch set prior:

Quoted 7 lines
Quoted 1 line

Agree we do nvme_fc* callbacks in deferred context, but without the

xxx_IN_ISR flag during NVMe Target template registration, we were running into crash due to recursive spin_lock held as part of CTIO response in our driver.

Can you look into removing this recursive spin lock ? ?? I don't think it's a good idea to be holding a spin lock when upcalling the transport.

Yes, Will work on removing spin lock.

Quoted 3 lines

-- james

#4 lore raw

PATCH v2 2/4 qla2xxx_nvmet: Added Makefile and Kconfig changes

In reply to Himanshu Madhani

From: Anil Gurumurthy <[email protected]>

Signed-off-by Anil Gurumurthy <anil.gurumurthy at cavium.com>
Signed-off-by Giridhar Malavali <giridhar.malavali at cavium.com>
Signed-off-by Himanshu Madhani <himanshu.madhani at cavium.com>
---
 drivers/scsi/qla2xxx/Kconfig  | 1 +
 drivers/scsi/qla2xxx/Makefile | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/scsi/qla2xxx/Kconfig +1 -0
index 036cc3f217b1..f1539d8b68ef 100644
@@ -3,6 +3,7 @@ config SCSI_QLA_FC
 	depends on PCI && SCSI
 	depends on SCSI_FC_ATTRS
 	depends on NVME_FC || !NVME_FC
+	depends on NVME_TARGET_FC || !NVME_TARGET_FC
 	select FW_LOADER
 	select BTREE
 	---help---
drivers/scsi/qla2xxx/Makefile +2 -1
index 0b767a0bb308..5b6838ac57bb 100644
@@ -1,6 +1,7 @@
 qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
 		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \
-		qla_nx.o qla_mr.o qla_nx2.o qla_target.o qla_tmpl.o qla_nvme.o
+		qla_nx.o qla_mr.o qla_nx2.o qla_target.o qla_tmpl.o qla_nvme.o \
+		qla_nvmet.o
 
 obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
 obj-$(CONFIG_TCM_QLA2XXX) += tcm_qla2xxx.o
Signature · 1 line
2.12.0
#5 lore raw

PATCH v2 3/4 qla2xxx_nvmet: Add FC-NVMe Target LS request handling

In reply to Himanshu Madhani

From: Anil Gurumurthy <[email protected]>

Signed-off-by Anil Gurumurthy <anil.gurumurthy at cavium.com>
Signed-off-by Giridhar Malavali <giridhar.malavali at cavium.com>
Signed-off-by Darren Trapp <darren.trapp at cavium.com>
Signed-off-by Himanshu Madhani <himanshu.madhani at cavium.com>
---
 drivers/scsi/qla2xxx/qla_dbg.c  |  1 +
 drivers/scsi/qla2xxx/qla_dbg.h  |  2 ++
 drivers/scsi/qla2xxx/qla_iocb.c | 42 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 44 insertions(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_dbg.c +1 -0
index 3e9dc54b89a3..974cae74072f 100644
@@ -67,6 +67,7 @@
  * | Target Mode Management	  |	  0xf09b       | 0xf002		|
  * |                              |                    | 0xf046-0xf049  |
  * | Target Mode Task Management  |	  0x1000d      |		|
+ * | NVME			  |	  0x11000      |		|
  * ----------------------------------------------------------------------
  */
 
drivers/scsi/qla2xxx/qla_dbg.h +2 -0
index 8877aa97d829..4ad97923e40b 100644
@@ -367,6 +367,8 @@ ql_log_qp(uint32_t, struct qla_qpair *, int32_t, const char *fmt, ...);
 #define ql_dbg_tgt_tmr	0x00001000 /* Target mode task management */
 #define ql_dbg_tgt_dif  0x00000800 /* Target mode dif */
 
+#define ql_dbg_nvme 0x00000400 /* NVME Target */
+
 extern int qla27xx_dump_mpi_ram(struct qla_hw_data *, uint32_t, uint32_t *,
 	uint32_t, void **);
 extern int qla24xx_dump_ram(struct qla_hw_data *, uint32_t, uint32_t *,
drivers/scsi/qla2xxx/qla_iocb.c +41 -1

66 lines not on this page · raw message

Signature · 1 line
2.12.0
#6 lore raw

PATCH v2 4/4 qla2xxx_nvmet: Add FC-NVMe Target handling

In reply to Himanshu Madhani

From: Anil Gurumurthy <[email protected]>

This patch Adds following code in the driver to
support FC-NVMe Target

- Updated ql2xenablenvme to allow FC-NVMe Target operation
- Added LS Request handling for NVMe Target
- Added passthr IOCB for LS4 request
- Added CTIO for sending response to FW
- Added FC4 Registration for FC-NVMe Target
- Added PUREX IOCB support for login processing in FC-NVMe Target mode
- Added Continuation IOCB for PUREX
- Added Session creation with PUREX IOCB in FC-NVMe Target mode

Signed-off-by Anil Gurumurthy <anil.gurumurthy at cavium.com>
Signed-off-by Giridhar Malavali <giridhar.malavali at cavium.com>
Signed-off-by Darren Trapp <darren.trapp at cavium.com>
Signed-off-by Himanshu Madhani <himanshu.madhani at cavium.com>
---
 drivers/scsi/qla2xxx/qla_def.h    |  35 +-
 drivers/scsi/qla2xxx/qla_fw.h     | 263 +++++++++++
 drivers/scsi/qla2xxx/qla_gbl.h    |  17 +-
 drivers/scsi/qla2xxx/qla_gs.c     |  15 +-
 drivers/scsi/qla2xxx/qla_init.c   |  49 +-
 drivers/scsi/qla2xxx/qla_isr.c    |  70 +++
 drivers/scsi/qla2xxx/qla_mbx.c    | 100 +++-
 drivers/scsi/qla2xxx/qla_nvme.h   |  33 --
 drivers/scsi/qla2xxx/qla_os.c     |  75 ++-
 drivers/scsi/qla2xxx/qla_target.c | 932 +++++++++++++++++++++++++++++++++++++-
 drivers/scsi/qla2xxx/qla_target.h |  93 +++-
 11 files changed, 1625 insertions(+), 57 deletions(-)
drivers/scsi/qla2xxx/qla_def.h +34 -1
index 01a9b8971e88..74813c144974 100644
@@ -447,13 +447,21 @@ struct srb_iocb {
 			uint32_t dl;
 			uint32_t timeout_sec;
 			struct	list_head   entry;
+			uint32_t exchange_address;
+			uint16_t nport_handle;
+			uint8_t vp_index;
+			void *cmd;
 		} nvme;
 	} u;
 
 	struct timer_list timer;
 	void (*timeout)(void *);
 };
-
+struct srb_nvme_els_rsp {
+		dma_addr_t dma_addr;
+		void *dma_ptr;
+		void *ptr;
+};
 /* Values for srb_ctx type */
 #define SRB_LOGIN_CMD	1
 #define SRB_LOGOUT_CMD	2
@@ -476,6 +484,11 @@ struct srb_iocb {
 #define SRB_NVME_CMD	19
 #define SRB_NVME_LS	20
 #define SRB_PRLI_CMD	21
+#define SRB_NVME_ELS_RSP 22
+#define SRB_NVMET_LS	23
+#define SRB_NVMET_FCP	24
+#define SRB_NVMET_ABTS	25
+#define SRB_NVMET_SEND_ABTS	26
 
 enum {
 	TYPE_SRB,
@@ -505,6 +518,7 @@ typedef struct srb {
 		struct srb_iocb iocb_cmd;
 		struct bsg_job *bsg_job;
 		struct srb_cmd scmd;
+		struct srb_nvme_els_rsp snvme_els;
 	} u;
 	void (*done)(void *, int);
 	void (*free)(void *);
@@ -2250,6 +2264,15 @@ struct qlt_plogi_ack_t {
 	void		*fcport;
 };
 
+/* NVMET */
+struct qlt_purex_plogi_ack_t {
+	struct list_head	list;
+	struct __fc_plogi rcvd_plogi;
+	port_id_t	id;
+	int		ref_count;
+	void		*fcport;
+};
+
 struct ct_sns_desc {
 	struct ct_sns_pkt	*ct_sns;
 	dma_addr_t		ct_sns_dma;
@@ -2346,6 +2369,8 @@ typedef struct fc_port {
 	struct work_struct free_work;
 
 	struct qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
+	/* NVMET */
+	struct qlt_purex_plogi_ack_t *purex_plogi_link[QLT_PLOGI_LINK_MAX];
 
 	uint16_t tgt_id;
 	uint16_t old_tgt_id;
@@ -3125,6 +3150,7 @@ enum qla_work_type {
 	QLA_EVT_UPD_FCPORT,
 	QLA_EVT_GNL,
 	QLA_EVT_NACK,
+	QLA_EVT_NEW_NVMET_SESS,
 };
 
 
@@ -4097,6 +4123,7 @@ typedef struct scsi_qla_host {
 		uint32_t	qpairs_req_created:1;
 		uint32_t	qpairs_rsp_created:1;
 		uint32_t	nvme_enabled:1;
+		uint32_t	nvmet_enabled:1;
 	} flags;
 
 	atomic_t	loop_state;
@@ -4139,6 +4166,7 @@ typedef struct scsi_qla_host {
 #define SET_ZIO_THRESHOLD_NEEDED	28
 #define DETECT_SFP_CHANGE	29
 #define N2N_LOGIN_NEEDED	30
+#define NVMET_PUREX		31
 
 	unsigned long	pci_flags;
 #define PFLG_DISCONNECTED	0	/* PCI device removed */
@@ -4179,6 +4207,7 @@ typedef struct scsi_qla_host {
 	uint8_t		fabric_node_name[WWN_SIZE];
 
 	struct		nvme_fc_local_port *nvme_local_port;
+	struct		nvmet_fc_target_port *targetport;
 	struct completion nvme_del_done;
 	struct list_head nvme_rport_list;
 	atomic_t 	nvme_active_aen_cnt;
@@ -4252,6 +4281,9 @@ typedef struct scsi_qla_host {
 	uint8_t n2n_node_name[WWN_SIZE];
 	uint8_t n2n_port_name[WWN_SIZE];
 	uint16_t	n2n_id;
+	/*NVMET*/
+	struct list_head	purex_atio_list;
+	struct completion	purex_plogi_sess;
 } scsi_qla_host_t;
 
 struct qla27xx_image_status {
@@ -4512,6 +4544,7 @@ struct sff_8247_a0 {
 	(IS_QLA27XX(_ha) || IS_QLA83XX(_ha)))
 
 #include "qla_target.h"
+#include "qla_nvmet.h"
 #include "qla_gbl.h"
 #include "qla_dbg.h"
 #include "qla_inline.h"
drivers/scsi/qla2xxx/qla_fw.h +263 -0

269 lines not on this page · raw message

drivers/scsi/qla2xxx/qla_gbl.h +15 -2
index 0a23af5aa479..166704019de6 100644
@@ -299,7 +299,10 @@ extern int
 qla2x00_set_fw_options(scsi_qla_host_t *, uint16_t *);
 
 extern int
-qla2x00_mbx_reg_test(scsi_qla_host_t *);
+qla2x00_set_purex_mode(scsi_qla_host_t *vha);
+
+extern int
+qla2x00_mbx_reg_test(scsi_qla_host_t *vha);
 
 extern int
 qla2x00_verify_checksum(scsi_qla_host_t *, uint32_t);
@@ -874,6 +877,16 @@ void qlt_update_host_map(struct scsi_qla_host *, port_id_t);
 void qlt_remove_target_resources(struct qla_hw_data *);
 void qlt_clr_qp_table(struct scsi_qla_host *vha);
 
+extern int qla2x00_get_plogi_template(scsi_qla_host_t *vha, dma_addr_t buf,
+	uint16_t length);
+extern void qlt_dequeue_purex(struct scsi_qla_host *vha);
+int qla24xx_post_nvmet_newsess_work(struct scsi_qla_host *vha, port_id_t *id,
+	u8 *port_name, void *pla);
+int qlt_send_els_resp(srb_t *sp, struct __els_pt *pkt);
+extern void nvmet_release_sessions(struct scsi_qla_host *vha);
+struct fc_port *qla_nvmet_find_sess_by_s_id(scsi_qla_host_t *vha,
+	const uint32_t s_id);
 void qla_nvme_cmpl_io(struct srb_iocb *);
-
+void qla24xx_nvmet_abts_resp_iocb(struct scsi_qla_host *vha,
+	struct abts_resp_to_24xx *pkt, struct req_que *req);
 #endif /* _QLA_GBL_H */
drivers/scsi/qla2xxx/qla_gs.c +10 -5
index bc3db6abc9a0..9b480ae2a5f5 100644
@@ -548,9 +548,10 @@ qla2x00_rft_id(scsi_qla_host_t *vha)
 	ct_req->req.rft_id.port_id[1] = vha->d_id.b.area;
 	ct_req->req.rft_id.port_id[2] = vha->d_id.b.al_pa;
 
-	ct_req->req.rft_id.fc4_types[2] = 0x01;		/* FCP-3 */
+	if (!vha->flags.nvmet_enabled)
+		ct_req->req.rft_id.fc4_types[2] = 0x01;		/* FCP-3 */
 
-	if (vha->flags.nvme_enabled)
+	if (vha->flags.nvme_enabled || vha->flags.nvmet_enabled)
 		ct_req->req.rft_id.fc4_types[6] = 1;    /* NVMe type 28h */
 	/* Execute MS IOCB */
 	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
@@ -592,6 +593,10 @@ qla2x00_rff_id(scsi_qla_host_t *vha, u8 type)
 		return (QLA_SUCCESS);
 	}
 
+	/* only single mode for now */
+	if ((vha->flags.nvmet_enabled) && (type == FC4_TYPE_FCP_SCSI))
+		return (QLA_SUCCESS);
+
 	arg.iocb = ha->ms_iocb;
 	arg.req_dma = ha->ct_sns_dma;
 	arg.rsp_dma = ha->ct_sns_dma;
@@ -613,7 +618,7 @@ qla2x00_rff_id(scsi_qla_host_t *vha, u8 type)
 	ct_req->req.rff_id.port_id[1] = vha->d_id.b.area;
 	ct_req->req.rff_id.port_id[2] = vha->d_id.b.al_pa;
 
-	qlt_rff_id(vha, ct_req);
+	qlt_rff_id(vha, ct_req, type);
 
 	ct_req->req.rff_id.fc4_type = type;		/* SCSI - FCP */
 
@@ -2166,7 +2171,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha)
 	    eiter->a.fc4_types[2],
 	    eiter->a.fc4_types[1]);
 
-	if (vha->flags.nvme_enabled) {
+	if (vha->flags.nvme_enabled || vha->flags.nvmet_enabled) {
 		eiter->a.fc4_types[6] = 1;	/* NVMe type 28h */
 		ql_dbg(ql_dbg_disc, vha, 0x211f,
 		    "NVME FC4 Type = %02x 0x0 0x0 0x0 0x0 0x0.\n",
@@ -2370,7 +2375,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha)
 	    "Port Active FC4 Type = %02x %02x.\n",
 	    eiter->a.port_fc4_type[2], eiter->a.port_fc4_type[1]);
 
-	if (vha->flags.nvme_enabled) {
+	if (vha->flags.nvme_enabled || vha->flags.nvmet_enabled) {
 		eiter->a.port_fc4_type[4] = 0;
 		eiter->a.port_fc4_type[5] = 0;
 		eiter->a.port_fc4_type[6] = 1;	/* NVMe type 28h */
drivers/scsi/qla2xxx/qla_init.c +44 -5

99 lines not on this page · raw message

drivers/scsi/qla2xxx/qla_isr.c +70 -0

104 lines not on this page · raw message

drivers/scsi/qla2xxx/qla_mbx.c +99 -1

120 lines not on this page · raw message

drivers/scsi/qla2xxx/qla_nvme.h +0 -33
index 7f05fa1c77db..be4e2d4f2aee 100644
@@ -103,39 +103,6 @@ struct pt_ls4_request {
 	uint32_t dseg1_address[2];
 	uint32_t dseg1_len;
 };
-
-#define PT_LS4_UNSOL 0x56	/* pass-up unsolicited rec FC-NVMe request */
-struct pt_ls4_rx_unsol {
-	uint8_t entry_type;
-	uint8_t entry_count;
-	uint16_t rsvd0;
-	uint16_t rsvd1;
-	uint8_t vp_index;
-	uint8_t rsvd2;
-	uint16_t rsvd3;
-	uint16_t nport_handle;
-	uint16_t frame_size;
-	uint16_t rsvd4;
-	uint32_t exchange_address;
-	uint8_t d_id[3];
-	uint8_t r_ctl;
-	uint8_t s_id[3];
-	uint8_t cs_ctl;
-	uint8_t f_ctl[3];
-	uint8_t type;
-	uint16_t seq_cnt;
-	uint8_t df_ctl;
-	uint8_t seq_id;
-	uint16_t rx_id;
-	uint16_t ox_id;
-	uint32_t param;
-	uint32_t desc0;
-#define PT_LS4_PAYLOAD_OFFSET 0x2c
-#define PT_LS4_FIRST_PACKET_LEN 20
-	uint32_t desc_len;
-	uint32_t payload[3];
-};
-
 /*
  * Global functions prototype in qla_nvme.c source file.
  */
drivers/scsi/qla2xxx/qla_os.c +73 -2

116 lines not on this page · raw message

drivers/scsi/qla2xxx/qla_target.c +925 -7

1,093 lines not on this page · raw message

drivers/scsi/qla2xxx/qla_target.h +92 -1

127 lines not on this page · raw message

Signature · 1 line
2.12.0
#7 lore raw

v2 cover qla2xxx: Add FC-NVMe Target support

In reply to Himanshu Madhani

Before even looking at the patches: they seem to add a lot of new sparse warnings, mostly about endianess issues. Given that FC-NVMe is a mix of BE and LE structures getting this right is important. Please fix them up first.

#8 lore raw

v2 cover qla2xxx: Add FC-NVMe Target support

Quoted 7 lines · Christoph Hellwig

Before even looking at the patches: they seem to add a lot of new sparse warnings, mostly about endianess issues. Given that FC-NVMe is a mix of BE and LE structures getting this right is important. Please fix them up first.

Sure, will fix up endianess warnings and resubmit patches.

Thanks,
Himanshu