From: Oliver Smith-Denny <osmithde@cisco.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Sesidhar Baddela <sebaddel@cisco.com>,
Gian Carlo Boffa <gcboffa@cisco.com>,
linux-scsi@vger.kernel.org, target-devel@vger.kernel.org,
linux-kernel@vger.kernel.org,
Oliver Smith-Denny <osmithde@cisco.com>
Subject: [PATCH 05/10] staging: fnic2 add LIO interface
Date: Thu, 5 Apr 2018 14:20:17 -0700 [thread overview]
Message-ID: <20180405212017.GF12584@osmithde-lnx.cisco.com> (raw)
In-Reply-To: <20180405211519.GA12584@osmithde-lnx.cisco.com>
These files contains structures and callback functions
for communicating with LIO.
Signed-off-by: Oliver Smith-Denny <osmithde@cisco.com>
Signed-off-by: Sesidhar Baddela <sebaddel@cisco.com>
Signed-off-by: Anil Chintalapati <achintal@cisco.com>
Signed-off-by: Arulprabhu Ponnusamy <arulponn@cisco.com>
Signed-off-by: Gian Carlo Boffa <gcboffa@cisco.com>
Co-Developed-by: Arulprabhu Ponnusamy <arulponn@cisco.com>
Co-Developed-by: Gian Carlo Boffa <gcboffa@cisco.com>
Co-Developed-by: Oliver Smith-Denny <osmithde@cisco.com>
---
drivers/staging/fnic2/src/fnic2_lio.c | 815 ++++++++++++++++++++++++++++++++++
drivers/staging/fnic2/src/fnic2_lio.h | 113 +++++
2 files changed, 928 insertions(+)
create mode 100644 drivers/staging/fnic2/src/fnic2_lio.c
create mode 100644 drivers/staging/fnic2/src/fnic2_lio.h
diff --git a/drivers/staging/fnic2/src/fnic2_lio.c b/drivers/staging/fnic2/src/fnic2_lio.c
new file mode 100644
index 0000000..64ca5d2
--- /dev/null
+++ b/drivers/staging/fnic2/src/fnic2_lio.c
@@ -0,0 +1,815 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright 2017 Cisco Systems, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <generated/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_common.h>
+#include <scsi/scsi_proto.h>
+#include <scsi/fc/fc_fcp.h>
+#include "fnic2.h"
+#include "fnic2_lio.h"
+
+extern struct fnic2 *find_fnic2_wwpn(uint64_t wwpn);
+extern int fnic2_send_to_fw(struct fnic2_cmd *tcmd, int req_type);
+extern void fnic2_free_fw_res(struct fnic2_cmd *tcmd);
+extern void fnic2_free_tcmd(struct fnic2_cmd *tcmd);
+
+#define FT_VERSION "0.1"
+
+static const struct target_core_fabric_ops fnic2_ops;
+
+/*
+ * Parse WWN.
+ * If strict, we require lower-case hex and colon separators to be sure
+ * the name is the same as what would be generated by ft_format_wwn()
+ * so the name and wwn are mapped one-to-one.
+ */
+static ssize_t ft_parse_wwn(const char *name, uint64_t *wwn, int strict)
+{
+ const char *cp;
+ char c;
+ uint32_t byte = 0;
+ uint32_t pos = 0;
+ uint32_t err;
+ int val;
+
+ *wwn = 0;
+ for (cp = name; cp < &name[FNIC2_NAMELEN - 1]; cp++) {
+ c = *cp;
+ if (c == '\n' && cp[1] == '\0')
+ continue;
+ if (strict && pos++ == 2 && byte++ < 7) {
+ pos = 0;
+ if (c == ':')
+ continue;
+ err = 1;
+ goto fail;
+ }
+ if (c == '\0') {
+ err = 2;
+ if (strict && byte != 8)
+ goto fail;
+ return cp - name;
+ }
+ err = 3;
+ val = hex_to_bin(c);
+ if (val < 0 || (strict && isupper(c)))
+ goto fail;
+ *wwn = (*wwn << 4) | val;
+ }
+ err = 4;
+fail:
+ pr_debug("err %u len %zu pos %u byte %u\n",
+ err, cp - name, pos, byte);
+ return -1;
+}
+
+static int fnic2_parse_wwpn(const char *wwn, uint64_t *wwpn)
+{
+ int i;
+ int shift = 60;
+ unsigned char c;
+ unsigned long long uint64_t = 0, d64;
+
+ for (i = 0; i < 23; i++) {
+ c = wwn[i];
+ if (c == ':')
+ continue;
+
+ if (c >= '0' && c <= '9') {
+ d64 = c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ d64 = 0xA + (c - 'A');
+ } else if (c >= 'a' && c <= 'f') {
+ d64 = 0xA + (c - 'a');
+ } else {
+ pr_err("Invalid WWPN %c\n", c);
+ return -1;
+ }
+
+ uint64_t = (d64 << shift) | uint64_t;
+ shift = shift - 4;
+ }
+ *wwpn = uint64_t;
+ return 0;
+
+}
+
+static ssize_t ft_format_wwn(char *buf, size_t len, uint64_t wwn)
+{
+ uint8_t b[8];
+
+ put_unaligned_be64(wwn, b);
+ return snprintf(buf, len,
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+ b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+}
+
+static ssize_t ft_wwn_show(void *arg, char *buf)
+{
+ uint64_t *wwn = arg;
+ ssize_t len;
+
+ len = ft_format_wwn(buf, PAGE_SIZE - 2, *wwn);
+ buf[len++] = '\n';
+ return len;
+}
+
+static ssize_t ft_wwn_store(void *arg, const char *buf, size_t len)
+{
+ ssize_t ret;
+ uint64_t wwn;
+
+ ret = ft_parse_wwn(buf, &wwn, 0);
+ if (ret > 0)
+ *(uint64_t *)arg = wwn;
+ return ret;
+}
+
+/*
+ * ACL auth ops.
+ */
+
+static ssize_t ft_nacl_port_name_show(struct config_item *item, char *page)
+{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
+ struct ft_node_acl *acl = container_of(se_nacl,
+ struct ft_node_acl, se_node_acl);
+
+ return ft_wwn_show(&acl->node_auth.port_name, page);
+}
+
+static ssize_t ft_nacl_port_name_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
+ struct ft_node_acl *acl = container_of(se_nacl,
+ struct ft_node_acl, se_node_acl);
+
+ return ft_wwn_store(&acl->node_auth.port_name, page, count);
+}
+
+static ssize_t ft_nacl_node_name_show(struct config_item *item,
+ char *page)
+{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
+ struct ft_node_acl *acl = container_of(se_nacl,
+ struct ft_node_acl, se_node_acl);
+
+ return ft_wwn_show(&acl->node_auth.node_name, page);
+}
+
+static ssize_t ft_nacl_node_name_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
+ struct ft_node_acl *acl = container_of(se_nacl,
+ struct ft_node_acl, se_node_acl);
+
+ return ft_wwn_store(&acl->node_auth.node_name, page, count);
+}
+
+CONFIGFS_ATTR(ft_nacl_, node_name);
+CONFIGFS_ATTR(ft_nacl_, port_name);
+
+static ssize_t ft_nacl_tag_show(struct config_item *item,
+ char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%s", acl_to_nacl(item)->acl_tag);
+}
+
+static ssize_t ft_nacl_tag_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
+ int ret;
+
+ ret = core_tpg_set_initiator_node_tag(se_nacl->se_tpg, se_nacl, page);
+
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+CONFIGFS_ATTR(ft_nacl_, tag);
+
+static struct configfs_attribute *ft_nacl_base_attrs[] = {
+ &ft_nacl_attr_port_name,
+ &ft_nacl_attr_node_name,
+ &ft_nacl_attr_tag,
+ NULL,
+};
+
+/*
+ * ACL ops.
+ */
+
+static int ft_init_nodeacl(struct se_node_acl *nacl, const char *name)
+{
+ struct ft_node_acl *acl =
+ container_of(nacl, struct ft_node_acl, se_node_acl);
+ uint64_t wwpn;
+
+ pr_err("Creating ACL for %s\n", name);
+
+ if (ft_parse_wwn(name, &wwpn, 1) < 0)
+ return -EINVAL;
+ pr_err("Created ACL for %s %llx\n", name, wwpn);
+
+ acl->node_auth.port_name = wwpn;
+ return 0;
+}
+
+static ssize_t ft_wwn_version_show(struct config_item *item, char *page)
+{
+ return sprintf(page, "CISCO SYSTEMS, INC. " FT_VERSION " on %s/%s on "
+ ""UTS_RELEASE"\n", utsname()->sysname, utsname()->machine);
+}
+
+CONFIGFS_ATTR_RO(ft_wwn_, version);
+
+static struct configfs_attribute *ft_wwn_attrs[] = {
+ &ft_wwn_attr_version,
+ NULL,
+};
+
+/* fabric */
+static int fnic2_check_true(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int fnic2_check_false(struct se_portal_group *se_tpg)
+{
+ return 0;
+}
+
+static char *fnic2_get_fabric_name(void)
+{
+ return "fnic2";
+}
+
+static char *fnic2_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct fnic2_tpg *tpg = container_of(se_tpg,
+ struct fnic2_tpg, se_tpg);
+ struct fnic2_lio_lport *lport = tpg->lport;
+
+
+ return &lport->lport_name[0];
+}
+
+static uint16_t fnic2_get_tag(struct se_portal_group *se_tpg)
+{
+ struct fnic2_tpg *tpg = container_of(se_tpg,
+ struct fnic2_tpg, se_tpg);
+ return tpg->lport_tpgt;
+}
+
+static uint32_t fnic2_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int fnic2_check_stop_free(struct se_cmd *se_cmd)
+{
+ struct fnic2_cmd *tcmd = container_of(se_cmd,
+ struct fnic2_cmd, se_cmd);
+ pr_debug("check stop free for tag %x\n", tcmd->cmd_tag);
+ return target_put_sess_cmd(se_cmd);
+}
+
+static void fnic2_release_cmd(struct se_cmd *se_cmd)
+{
+ struct fnic2_cmd *tcmd = container_of(se_cmd,
+ struct fnic2_cmd, se_cmd);
+
+ pr_debug("DEBUG %s: %x, is_write: %d, rx_id: %x\n",
+ __func__, tcmd->cmd_tag, tcmd->flags & FNIC2_TCMD_WRITECMD, tcmd->rx_id);
+
+ if (tcmd->se_cmd.t_data_sg)
+ pr_err("t_data_sg not NULL\n");
+ fnic2_free_tcmd(tcmd);
+
+ return;
+}
+
+static uint32_t fnic2_sess_get_index(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static int fnic2_write_pending(struct se_cmd *se_cmd)
+{
+ struct fnic2_cmd *tcmd = container_of(se_cmd,
+ struct fnic2_cmd, se_cmd);
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tcmd->lock, flags);
+
+ if (tcmd->flags & FNIC2_TCMD_ABORTED) {
+ spin_unlock_irqrestore(&tcmd->lock, flags);
+ return 0;
+ }
+
+ spin_unlock_irqrestore(&tcmd->lock, flags);
+
+ pr_debug("DEBUG write_pending tag: %x\n", tcmd->cmd_tag);
+
+ /* Check the se->cmd status and process accordingly */
+ if (se_cmd->scsi_status != SAM_STAT_GOOD) {
+ pr_err("ERROR fn: %s ln: %d, sts: %d\n",
+ __func__, __LINE__, se_cmd->scsi_status);
+ /* TBD send_resp or wait for q_sts? */
+ return 0;
+ }
+
+ tcmd->data_len_xfer = se_cmd->data_length;
+ if (tcmd->data_len_req != tcmd->data_len_xfer) {
+ /* TBD */
+ pr_err("ERROR fn: %s ln: %d\n", __func__, __LINE__);
+ }
+
+ tcmd->sgcnt = se_cmd->t_data_nents;
+ tcmd->sgl = se_cmd->t_data_sg;
+ tcmd->dma_direction = PCI_DMA_FROMDEVICE;
+
+ ret = fnic2_send_to_fw(tcmd, FCPIO_TCMD_RECV_DATA);
+
+ return ret;
+}
+
+static int fnic2_queue_status(struct se_cmd *se_cmd)
+{
+ struct fnic2_cmd *tcmd = container_of(se_cmd,
+ struct fnic2_cmd, se_cmd);
+ unsigned long flags;
+
+ pr_debug("DEBUG queue_status tag: %x\n", tcmd->cmd_tag);
+
+ spin_lock_irqsave(&tcmd->lock, flags);
+
+ if (tcmd->flags & FNIC2_TCMD_ABORTED) {
+ spin_unlock_irqrestore(&tcmd->lock, flags);
+ return 0;
+ }
+
+ spin_unlock_irqrestore(&tcmd->lock, flags);
+
+ if (se_cmd->scsi_status != SAM_STAT_GOOD) {
+ pr_err("WARNING: Cmd %x SCSI Status Error: %x, cmd_tag: %x\n",
+ tcmd->ox_id, se_cmd->scsi_status, tcmd->cmd_tag);
+ }
+
+ fnic2_send_fcp_resp(tcmd);
+
+ /* Delete I/O timer if it is active */
+ if ((try_to_del_timer_sync(&tcmd->io_timer)) < 0)
+ pr_err("Could not delete timer on tcmd tag %x\n", tcmd->cmd_tag);
+
+ if (tcmd->flags & FNIC2_TCMD_WRITECMD)
+ fnic2_free_fw_res(tcmd);
+ else
+ transport_generic_free_cmd(se_cmd, 0);
+
+ return 0;
+}
+
+/*
+ * fnic2_queue_tm_rsp
+ * LIO has completed a task management command
+ * send a "bubble" command to fw that will be processed after
+ * all the aborted commands, then send the task mgmt response to initiator
+ */
+static void fnic2_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+ struct fnic2_cmd *tcmd = container_of(se_cmd,
+ struct fnic2_cmd, se_cmd);
+ struct fnic2 *fnic2 = tcmd->fnic2;
+ unsigned long flags;
+ struct fcpio_host_req *host_req;
+ struct fcpio_host_req *desc;
+ struct vnic_wq_copy *wq;
+
+ pr_err("TMR RESPONSE se_cmd %pK tcmd %pK\n", se_cmd, tcmd);
+
+ spin_lock_irqsave(&tcmd->lock, flags);
+
+ if (tcmd->flags & (FNIC2_TCMD_IS_ABTS | FNIC2_TCMD_ABORTED)) {
+ spin_unlock_irqrestore(&tcmd->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&tcmd->lock, flags);
+
+ /* Fill the structure to send it to fw */
+ host_req = kzalloc(sizeof(struct fcpio_host_req), GFP_KERNEL);
+ WARN_ON(host_req == NULL);
+ host_req->hdr.type = FCPIO_TCMD_TASK_MGMT;
+ host_req->hdr.fcpio_tag = tcmd->cmd_tag;
+
+ spin_lock_irqsave(&fnic2->wq_copy_lock[0], flags);
+ /* Use the Copy WQ to send it to FW */
+ wq = &fnic2->wq_copy[0];
+
+ if (vnic_wq_copy_desc_avail(wq) <= fnic2->wq_copy_desc_low[0])
+ free_wq_copy_descs(fnic2, wq);
+
+ if (unlikely(!vnic_wq_copy_desc_avail(wq))) {
+ pr_err("DEBUG ERROR no wq desc for free_cmd\n");
+ kfree(host_req);
+ spin_unlock_irqrestore(&fnic2->wq_copy_lock[0], flags);
+ return;
+ }
+
+ desc = vnic_wq_copy_next_desc(wq);
+ memcpy(desc, host_req, sizeof(struct fcpio_host_req));
+
+ vnic_wq_copy_post(wq);
+ spin_unlock_irqrestore(&fnic2->wq_copy_lock[0], flags);
+
+ kfree(host_req);
+}
+
+void fnic2_send_abort_to_lio(struct fnic2_cmd *abort_tcmd)
+{
+ int tmr_flags, ret;
+ struct fnic2_cmd *killed_tcmd = abort_tcmd->killed_tcmd;
+ struct fc_hdr *fchdr = (struct fc_hdr *)killed_tcmd->rx_frame;
+ struct fnic2 *fnic2 = killed_tcmd->fnic2;
+ struct fnic2_sess *sess;
+ uint32_t s_id;
+
+ s_id = ntoh24(fchdr->s_id);
+ sess = fnic2_find_sess_s_id(fnic2, s_id);
+
+ if (!sess) {
+ // TBD cleanup
+ return;
+ }
+
+ // TBD sanity check on killed_tcmd ???
+
+ tmr_flags = TARGET_SCF_ACK_KREF | TARGET_SCF_LOOKUP_LUN_FROM_TAG;
+
+ ret= target_submit_tmr(&abort_tcmd->se_cmd, sess->se_sess, NULL,
+ 0,
+ killed_tcmd,
+ TMR_ABORT_TASK, GFP_ATOMIC,
+ killed_tcmd->cmd_tag,
+ tmr_flags);
+
+ if (ret) {
+ pr_err("%s submitting tmr failed\n", __func__);
+ /* LIO failed the ABTS req, but I/O will be
+ * handled by Lun Reset or I/O timer reaper
+ */
+ }
+}
+
+/*
+ * fnic2_complete_tm_rsp
+ * fw has aborted all exchanges
+ * send the final task management function response to initiator
+ */
+void fnic2_complete_tm_rsp(struct fnic2_cmd *tcmd)
+{
+ struct se_cmd *se_cmd = &tcmd->se_cmd;
+ struct se_tmr_req *tmr = se_cmd->se_tmr_req;
+ enum fcp_resp_rsp_codes code;
+ unsigned long flags;
+
+ pr_err("TMR RESPONSE fw completed - se_cmd %pK tcmd %pK tmr %pK\n",
+ se_cmd, tcmd, tmr);
+
+ spin_lock_irqsave(&tcmd->lock, flags);
+
+ if (tcmd->flags & (FNIC2_TCMD_IS_ABTS | FNIC2_TCMD_ABORTED)) {
+ spin_unlock_irqrestore(&tcmd->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&tcmd->lock, flags);
+
+ switch (tmr->response) {
+ case TMR_FUNCTION_COMPLETE:
+ code = FCP_TMF_CMPL;
+ break;
+ case TMR_LUN_DOES_NOT_EXIST:
+ code = FCP_TMF_INVALID_LUN;
+ break;
+ case TMR_FUNCTION_REJECTED:
+ code = FCP_TMF_REJECTED;
+ break;
+ case TMR_TASK_DOES_NOT_EXIST:
+ case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:
+ default:
+ code = FCP_TMF_FAILED;
+ break;
+ }
+ pr_err("TMR RESPONSE fn %d resp %d fcp code %d\n",
+ tmr->function, tmr->response, code);
+
+ fnic2_send_tmr_resp(tcmd, SAM_STAT_GOOD, code);
+
+ transport_generic_free_cmd(se_cmd, 0);
+}
+
+/*
+ * fnic2_aborted_task
+ * callback from LIO for each aborted real task (by ABTS or LUN RESET)
+ */
+static void fnic2_aborted_task(struct se_cmd *se_cmd)
+{
+ struct fnic2_cmd *killed_tcmd = container_of(se_cmd, struct fnic2_cmd, se_cmd);
+ struct fnic2_cmd *abort_tcmd;
+
+ pr_err("tcmd %pK aborted by LIO\n", killed_tcmd);
+
+ if (killed_tcmd->flags & FNIC2_TCMD_ABORTED) {
+ /* ABTS path - already aborted with fw */
+ abort_tcmd = killed_tcmd->abort_tcmd;
+ transport_generic_free_cmd(&abort_tcmd->se_cmd, 0);
+ } else {
+ /* LUN RESET path - must abort with fw */
+ fnic2_send_abort_to_fw(killed_tcmd);
+ }
+}
+
+/*
+ * fnic2_fw_abort_done
+ * callback from fw for each aborted task (ABTS or LUN RESET)
+ */
+void fnic2_fw_abort_done(struct fnic2_cmd *tcmd)
+{
+ struct fnic2 *fnic2;
+ struct fc_hdr *fchdr;
+ struct fnic2_cmd *killed_tcmd;
+
+ pr_err("tcmd %pK aborted by fw\n", tcmd);
+
+ if (tcmd->flags & FNIC2_TCMD_IS_ABTS) {
+ /* ABTS path */
+ /* send ba_acc and abort with LIO */
+
+ killed_tcmd = tcmd->killed_tcmd;
+ // TBD killed_cmd sanity check
+
+ fnic2 = killed_tcmd->fnic2;
+ fchdr = (struct fc_hdr *)killed_tcmd->rx_frame;
+
+ fdls_send_ba_acc(&fnic2->lport, fchdr);
+ fnic2_send_abort_to_lio(tcmd);
+ }
+}
+
+/* configfs */
+
+static struct se_portal_group *fnic2_make_tpg(struct se_wwn *wwn,
+ struct config_group *group,
+ const char *name)
+{
+ struct fnic2_lio_lport *lport = container_of(wwn,
+ struct fnic2_lio_lport, lport_wwn);
+
+ struct fnic2_tpg *tpg;
+ unsigned long tpgt;
+ struct fnic2 *fnic2 = lport->fnic2;
+ int ret;
+
+ pr_debug("name: %s\n", name);
+
+ if (strstr(name, "tpgt_") != name)
+ return ERR_PTR(-EINVAL);
+ if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+ return ERR_PTR(-EINVAL);
+
+ tpg = kzalloc(sizeof(struct fnic2_tpg), GFP_KERNEL);
+ if (!tpg) {
+ pr_err("Unable to allocate struct fnic2_tpg\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ tpg->lport = lport;
+ tpg->lport_tpgt = tpgt;
+
+ ret = core_tpg_register(wwn, &tpg->se_tpg, SCSI_PROTOCOL_FCP);
+ if (ret < 0) {
+ pr_err("Error returned by core_tpg_register: %d\n",
+ ret);
+ kfree(tpg);
+ return ERR_PTR(-EFAULT);
+ }
+
+ fnic2 = lport->fnic2;
+ fnic2->lio.tpg = tpg;
+
+ return &tpg->se_tpg;
+}
+
+static void fnic2_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct fnic2_tpg *tpg = container_of(se_tpg,
+ struct fnic2_tpg, se_tpg);
+
+ core_tpg_deregister(se_tpg);
+ kfree(tpg);
+}
+
+static struct se_wwn *fnic2_make_lport(struct target_fabric_configfs *tf,
+ struct config_group *group,
+ const char *name)
+{
+ struct fnic2 *fnic2;
+ struct fnic2_lio_lport *lport;
+ uint64_t wwpn;
+
+ if (!name) {
+ pr_err("%s Null lport name received\n", __func__);
+ return NULL;
+
+ }
+ pr_debug("%s: lport name %s\n", __func__, name);
+
+ if (fnic2_parse_wwpn(name, &wwpn) < 0)
+ return ERR_PTR(-EINVAL);
+
+ pr_debug("%s: wwpn %llx\n", __func__, wwpn);
+
+ fnic2 = find_fnic2_wwpn(wwpn);
+ if (!fnic2) {
+ pr_err("Could not find fnic2 with wwpn: %llx\n",
+ wwpn);
+ return ERR_PTR(-EINVAL);
+ }
+ if (fnic2->lio.lport) {
+ pr_err("%s: lport already created %llx\n",
+ __func__, wwpn);
+ return ERR_PTR(-EEXIST);
+ }
+ lport = kzalloc(sizeof(struct fnic2_lio_lport), GFP_KERNEL);
+ if (!lport) {
+ pr_err("Unable to allocate struct fnic2_lio_lport\n");
+ WARN_ON(1);
+ return ERR_PTR(-ENOMEM);
+ }
+ lport->lport_wwpn = wwpn;
+
+ fnic2->lio.lport = lport;
+ lport->fnic2 = fnic2;
+
+ return (&lport->lport_wwn);
+}
+
+int fnic2_write_pending_status(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+void fnic2_set_default_node_attrs(struct se_node_acl *nacl)
+{
+ return;
+}
+
+int fnic2_get_cmd_state(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+int fnic2_queue_data_in(struct se_cmd *se_cmd)
+{
+ struct fnic2_cmd *tcmd = container_of(se_cmd,
+ struct fnic2_cmd, se_cmd);
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tcmd->lock, flags);
+
+ if (tcmd->flags & (FNIC2_TCMD_IS_ABTS | FNIC2_TCMD_ABORTED)) {
+ spin_unlock_irqrestore(&tcmd->lock, flags);
+ return 0;
+ }
+
+ spin_unlock_irqrestore(&tcmd->lock, flags);
+
+ pr_debug("DEBUG data_in tag: %x, sts: %x\n",
+ tcmd->cmd_tag, se_cmd->scsi_status);
+
+ /* Check the se->cmd status and process accordingly */
+ if (se_cmd->scsi_status != SAM_STAT_GOOD) {
+ /* TBD would LIO call data_in in case of error status? */
+ pr_err("Scsi status: %x, cmdtag: %d\n",
+ se_cmd->scsi_status, tcmd->cmd_tag);
+ return 0;
+ }
+
+ tcmd->data_len_xfer = se_cmd->data_length;
+
+ if (tcmd->data_len_xfer == 0) {
+ pr_debug("DEBUG Zero len Data tag: %x\n", tcmd->cmd_tag);
+ tcmd->rx_id = 0xffff;
+ fnic2_send_fcp_resp(tcmd);
+ transport_generic_free_cmd(&tcmd->se_cmd, 0);
+ return 0;
+ }
+
+ if (tcmd->data_len_req != tcmd->data_len_xfer) {
+ pr_debug("%s data_len_req: %d, data_len_xfer: %d\n",
+ __func__, tcmd->data_len_req, tcmd->data_len_xfer);
+ }
+ tcmd->sgcnt = se_cmd->t_data_nents;
+ tcmd->sgl = se_cmd->t_data_sg;
+ tcmd->dma_direction = PCI_DMA_TODEVICE;
+
+ ret = fnic2_send_to_fw(tcmd, FCPIO_TCMD_SEND_DATA);
+ return ret;
+}
+
+static void fnic2_drop_lport(struct se_wwn *wwn)
+{
+ struct fnic2_lio_lport *lport = container_of(wwn,
+ struct fnic2_lio_lport, lport_wwn);
+ struct fnic2 *fnic2;
+
+ /* Free from the corresponding fnic2 */
+ fnic2 = find_fnic2_wwpn(lport->lport_wwpn);
+ if (!fnic2) {
+ pr_err("%s: Unable to find fnic2 for the wwpn %llx\n",
+ __func__, lport->lport_wwpn);
+ return;
+ }
+ if (!fnic2->lio.lport) {
+ pr_err("%s lport does not exist %llx\n",
+ __func__, lport->lport_wwpn);
+ return;
+ }
+
+ fnic2->lio.lport = NULL;
+ kfree(lport);
+}
+
+
+/* Registration */
+
+static const struct target_core_fabric_ops fnic2_ops = {
+ .module = THIS_MODULE,
+ .name = "fnic2",
+ .node_acl_size = sizeof(struct ft_node_acl),
+ .get_fabric_name = fnic2_get_fabric_name,
+ .tpg_get_wwn = fnic2_get_fabric_wwn,
+ .tpg_get_tag = fnic2_get_tag,
+ .tpg_check_demo_mode = fnic2_check_false,
+ .tpg_check_demo_mode_cache = fnic2_check_true,
+ .tpg_check_demo_mode_write_protect = fnic2_check_false,
+ .tpg_check_prod_mode_write_protect = fnic2_check_false,
+ .tpg_get_inst_index = fnic2_tpg_get_inst_index,
+ .check_stop_free = fnic2_check_stop_free,
+ .release_cmd = fnic2_release_cmd,
+ .sess_get_index = fnic2_sess_get_index,
+ .sess_get_initiator_sid = NULL,
+ .write_pending = fnic2_write_pending,
+ .write_pending_status = fnic2_write_pending_status,
+ .set_default_node_attributes = fnic2_set_default_node_attrs,
+ .get_cmd_state = fnic2_get_cmd_state,
+ .queue_data_in = fnic2_queue_data_in,
+ .queue_status = fnic2_queue_status,
+ .queue_tm_rsp = fnic2_queue_tm_rsp,
+ .aborted_task = fnic2_aborted_task,
+ /*
+ * Setup function pointers for generic logic in target_core_fabric_configfs.c
+ */
+ .fabric_make_wwn = fnic2_make_lport,
+ .fabric_drop_wwn = fnic2_drop_lport,
+ .fabric_make_tpg = fnic2_make_tpg,
+ .fabric_drop_tpg = fnic2_drop_tpg,
+ .fabric_init_nodeacl = &ft_init_nodeacl,
+
+ .tfc_wwn_attrs = ft_wwn_attrs,
+ .tfc_tpg_nacl_base_attrs = ft_nacl_base_attrs,
+};
+
+int fnic2_lio_init(void)
+{
+ int ret = 0;
+
+ ret = target_register_template(&fnic2_ops);
+ return ret;
+};
+
+void fnic2_lio_cleanup(void)
+{
+ target_unregister_template(&fnic2_ops);
+};
diff --git a/drivers/staging/fnic2/src/fnic2_lio.h b/drivers/staging/fnic2/src/fnic2_lio.h
new file mode 100644
index 0000000..82f7c01
--- /dev/null
+++ b/drivers/staging/fnic2/src/fnic2_lio.h
@@ -0,0 +1,113 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright 2018 Cisco Systems, Inc.
+ */
+#ifndef _FNIC2_LIO_H_
+#define _FNIC2_LIO_H_
+
+#define FNIC2_VERSION "v0.1"
+#define FNIC2_NAMELEN 32
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+enum fnic2_cmd_flags {
+ FNIC2_TCMD_ABORTED = (1 << 0),
+ FNIC2_TCMD_IS_ABTS = (1 << 1),
+ FNIC2_TCMD_WRITECMD = (1 << 2)
+};
+
+struct fnic2_tpg {
+ /* FC lport target portal group tag for TCM */
+ uint16_t lport_tpgt;
+ /* Pointer back to fnic2_lport */
+ struct fnic2_lio_lport *lport;
+ /* Returned by fnic2_make_tpg() */
+ struct se_portal_group se_tpg;
+};
+
+/*
+ * Node ID and authentication.
+ */
+struct ft_node_auth {
+ uint64_t port_name;
+ uint64_t node_name;
+};
+
+/*
+ * Node ACL for remote port session.
+ */
+struct ft_node_acl {
+ struct se_node_acl se_node_acl;
+ struct ft_node_auth node_auth;
+};
+
+
+struct fnic2_lio_lport {
+ /* Binary World Wide unique Port Name for FC Target Lport */
+ uint64_t lport_wwpn;
+ /* ASCII formatted WWPN for FC Target Lport */
+ char lport_name[FNIC2_NAMELEN];
+ /* Returned by fnic2_make_lport() */
+ struct se_wwn lport_wwn;
+
+ struct fnic2 *fnic2;
+};
+
+struct fnic2_sess {
+ struct list_head list;
+ struct se_session *se_sess;
+ struct kref kref; /* ref for hash and outstanding I/Os */
+ struct fnic2_lio_lport *lport;
+ struct fnic2_rport *rport;
+ struct list_head cmd_list;
+ struct fnic2 *fnic2;
+ struct fc_logo_req timer_logo_req;
+ struct timer_list sess_timer;
+};
+
+struct fnic2_lio {
+ struct fnic2_tpg *tpg;
+ struct fnic2_lio_lport *lport;
+ struct list_head sess_list;
+ int sess_count;
+};
+
+struct fnic2_cmd {
+ struct list_head free_list;
+ struct fnic2 *fnic2;
+ struct fnic2_sess *sess;
+ uint32_t cmd_tag;
+ struct fnic2_cmd *killed_tcmd;
+ struct fnic2_cmd *abort_tcmd;
+ uint32_t abort_tag;
+ struct se_cmd se_cmd;
+ uint32_t ox_id;
+ uint32_t s_id;
+ uint16_t rx_id;
+ uint8_t flags; /* See #define above */
+ uint8_t data_dir;
+ uint32_t data_len_req; /* Requested Data Len */
+ struct scatterlist *sgl;
+ int sgcnt;
+ int data_len_xfer; /* Xfered Data Len */
+ uint8_t sense_buf[TRANSPORT_SENSE_BUFFER];
+ void *host_req;
+ void *rx_frame;
+ int frame_len;
+ int sg_desc_count;
+ struct host_sg_desc *sg_desc_va_unaligned;
+ struct host_sg_desc *sg_desc_va;
+ uint64_t sg_desc_pa;
+ int dma_direction;
+
+ void *kmap_addr[256];
+
+ struct work_struct work;
+ struct fcpio_fw_req fw_desc;
+
+ spinlock_t lock;
+ struct timer_list io_timer;
+};
+
+#endif /* _FNIC2_LIO_ */
--
1.8.3.1
next prev parent reply other threads:[~2018-04-05 21:20 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-04-05 21:15 [PATCH 00/10] staging: fnic2 Driver Introduction Oliver Smith-Denny
2018-04-05 21:16 ` [PATCH 01/10] staging: fnic2 add initialization Oliver Smith-Denny
2018-04-06 5:07 ` Greg Kroah-Hartman
2018-04-06 22:00 ` Oliver Smith-Denny
2018-04-07 6:09 ` Greg Kroah-Hartman
2018-04-09 19:49 ` Oliver Smith-Denny
2018-04-09 20:57 ` Martin K. Petersen
2018-04-12 17:32 ` Oliver Smith-Denny
2018-04-05 21:17 ` [PATCH 02/10] staging: fnic2 add resource allocation Oliver Smith-Denny
2018-04-06 5:08 ` Greg Kroah-Hartman
2018-04-05 21:18 ` [PATCH 03/10] staging: fnic2 add fip handling Oliver Smith-Denny
2018-04-06 5:08 ` Greg Kroah-Hartman
2018-04-05 21:19 ` [PATCH 04/10] staging: fnic2 add fdls system Oliver Smith-Denny
2018-04-05 21:20 ` Oliver Smith-Denny [this message]
2018-04-05 21:21 ` [PATCH 06/10] staging: fnic2 add main frame processing Oliver Smith-Denny
2018-04-05 21:21 ` [PATCH 07/10] staging: fnic2 add queue descriptors Oliver Smith-Denny
2018-04-05 21:22 ` [PATCH 08/10] staging: fnic2 add vnic queue interface Oliver Smith-Denny
2018-04-05 21:23 ` [PATCH 09/10] staging: fnic2 add vnic handling Oliver Smith-Denny
2018-04-05 21:24 ` [PATCH 10/10] staging: fnic2 add build and config Oliver Smith-Denny
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180405212017.GF12584@osmithde-lnx.cisco.com \
--to=osmithde@cisco.com \
--cc=gcboffa@cisco.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=sebaddel@cisco.com \
--cc=target-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®