[PATCH] tcm_qla2xxx: Add initial HW and NPIV configfs handlers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx>

Hi Giridhar, Andrew and Co,

Attached is a functional control plane prototype that I have come up thus far
for lio-core-2.6.git/tcm_qla2xxx using ISP2532-based 8Gb adapters in a PTP
setup, with the tcm_qla2xxx side using host PCIe device passthrough for
individual ports into .37-rc1 KVM/QEMU guest.   I am interested to get some
feedback on the configfs enabled NPIV pieces especially (currently compile
tested only in PTP mode), but I think the non NPIV case is straight-forward
enough for the moment.

So, please have a look at the following and add your comments accordingly.

Thanks!

--nab

------------------------------------------------------------------------------

This patch adds the base tcm_qla2xxx HW configfs handler (non NPIV) in
tcm_qla2xxx_make_lport() that will walk the PCI device list looking for a
driver with MODE_TARGET supported and not already enabled, looking for a
matching struct scsi_qla_host->port_name for the passed configfs FC WWPN.

This patch also adds initial (compile tested) support for NPIV capable driver
by registering a second tcm_qla2xxx_npiv_ops during tcm_qla2xxx_register_configfs()
at module_init() time, and saves a global pointer to tcm_qla2xxx_npiv_fabric_configfs.
This means the seperate NPIV enabled code can be run from the same tcm_qla2xxx
LKM at /sys/kernel/config/target/qla2xxx_npiv/$WWPN+$WWNN using the same format as
the existing NPIV sysfs triggers at /sys/class/fc_host/$HOST/[create,delete]_vport.

This patch also adds special NPIV configfs handlers in tcm_qla2xxx_npiv_make_lport()
and tcm_qla2xxx_npiv_drop_lport() to call fc_vport_create() and fc_vport_terminate()
respectively to setup/release the NPIV port with libfc code.  Also included is a NPIV
version of tcm_qla2xxx_npiv_make_tpg() that references the NPIV global pointer directly.

For the non NPIV case the current control plane code looks like the following in action
for a matching vha->port_name containing a FC WWPN of 21:00:00:24:ff:31:4c:48

lenny64guest0:/usr/src/lio-core-2.6.git# insmod drivers/target/tcm_qla2xxx/tcm_qla2xxx.ko
lenny64guest0:/usr/src/lio-core-2.6.git# mkdir -p /sys/kernel/config/target/qla2xxx/21:00:00:24:ff:31:4c:48/tpgt_1/lun/lun_0
lenny64guest0:/usr/src/lio-core-2.6.git# cd /sys/kernel/config/target/qla2xxx/21:00:00:24:ff:31:4c:48/tpgt_1/lun/lun_0
lenny64guest0:/sys/kernel/config/target/qla2xxx/21:00:00:24:ff:31:4c:48/tpgt_1/lun/lun_0# ln -s /sys/kernel/config/target/core/fileio_0/sync_fileio qla2xxx_port

lenny64guest0:/sys/kernel/config/target/qla2xxx/21:00:00:24:ff:31:4c:48/tpgt_1/lun/lun_0# tree /sys/kernel/config/target/qla2xxx/
/sys/kernel/config/target/qla2xxx/
|-- 21:00:00:24:ff:31:4c:48
|   `-- tpgt_1
|       |-- acls
|       |-- attrib
|       |-- lun
|       |   `-- lun_0
|       |       |-- alua_tg_pt_gp
|       |       |-- alua_tg_pt_offline
|       |       |-- alua_tg_pt_status
|       |       |-- alua_tg_pt_write_md
|       |       `-- qla2xxx_port -> ../../../../../../target/core/fileio_0/sync_fileio
|       |-- np
|       `-- param
|-- discovery_auth
`-- version

and from the kernel log:

[15078.953293] TCM QLOGIC QLA2XXX fabric module v0.1 on Linux/x86_64 on 2.6.37-rc1+
[15078.953361] Setup generic discovery
[15078.953361] Setup generic wwn
[15078.953361] Setup generic tpg
[15078.953361] Setup generic tpg_base
[15078.953361] Setup generic tpg_port
[15078.957499] Setup generic tpg_lun
[15078.958080] Setup generic tpg_np
[15078.958640] Setup generic tpg_np_base
[15078.959273] Setup generic tpg_attrib
[15078.959891] Setup generic tpg_param
[15078.960494] Setup generic tpg_nacl
[15078.961085] Setup generic tpg_nacl_base
[15078.961481] Setup generic tpg_nacl_attrib
[15078.961481] Setup generic tpg_nacl_auth
[15078.961481] Setup generic tpg_nacl_param
[15078.961481] Setup generic tpg_mappedlun
[15078.961481] <<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>>>>>>>>>>>>>
[15078.965721] Initialized struct target_fabric_configfs: ffff88007494c890 for qla2xxx
[15078.967043] <<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>>>>>>
[15078.968185] TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_fabric_configfs
[15078.969311] Setup generic discovery
[15078.969696] Setup generic wwn
[15078.969696] Setup generic tpg
[15078.969696] Setup generic tpg_base
[15078.969696] Setup generic tpg_port
[15078.969696] Setup generic tpg_lun
[15078.969696] Setup generic tpg_np
[15078.969696] Setup generic tpg_np_base
[15078.973959] Setup generic tpg_attrib
[15078.974579] Setup generic tpg_param
[15078.975155] Setup generic tpg_nacl
[15078.975718] Setup generic tpg_nacl_base
[15078.976352] Setup generic tpg_nacl_attrib
[15078.977010] Setup generic tpg_nacl_auth
[15078.977793] Setup generic tpg_nacl_param
[15078.977939] Setup generic tpg_mappedlun
[15078.977939] <<<<<<<<<<<<<<<<<<<<<< BEGIN FABRIC API >>>>>>>>>>>>>>>>>>>>>>
[15078.977939] Initialized struct target_fabric_configfs: ffff88007494a850 for qla2xxx_npiv
[15078.981638] <<<<<<<<<<<<<<<<<<<<<< END FABRIC API >>>>>>>>>>>>>>>>>>>>>>
[15078.982750] TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_npiv_fabric_configfs
[15085.683873] Target_Core_ConfigFS: REGISTER -> group: ffffffffa05b2b00 name: qla2xxx
[15085.685184] Target_Core_ConfigFS: REGISTER -> Located fabric: qla2xxx
[15085.686270] Target_Core_ConfigFS: REGISTER tfc_wwn_cit -> ffff88007494cb98
[15085.686343] Target_Core_ConfigFS: REGISTER -> Allocated Fabric: qla2xxx
[15085.686343] Target_Core_ConfigFS: REGISTER -> Set tf->tf_fabric for qla2xxx
[15085.686343] qla2xxx HW vha->node_name: 20 00 00 24 ff 31 4c 48
[15085.690922] qla2xxx HW vha->port_name: 21 00 00 24 ff 31 4c 48
[15085.692079] qla2xxx passed configfs WWPN: 21 00 00 24 ff 31 4c 48
[15085.693276] qla2xxx: Found matching HW WWPN: 21:00:00:24:ff:31:4c:48 for lport
[15085.694349] TARGET_CORE[qla2xxx]: Allocated Normal struct se_portal_group for endpoint: 21:00:00:24:ff:31:4c:48, Portal Tag: 1
[15203.490029] fileio/qla2xxx: Adding to default ALUA Target Port Group: alua/default_tg_pt_gp
[15203.491497] qla2xxx_TPG[1]_LUN[0] - Activated qla2xxx Logical Unit from CORE HBA: 2

Signed-off-by: Nicholas A. Bellinger <nab@xxxxxxxxxxxxxxx>
---
 drivers/target/tcm_qla2xxx/Kbuild                 |    2 +-
 drivers/target/tcm_qla2xxx/tcm_qla2xxx_base.h     |   18 +
 drivers/target/tcm_qla2xxx/tcm_qla2xxx_configfs.c |  397 ++++++++++++++++++++-
 drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c   |   94 +++++-
 drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.h   |   22 +-
 5 files changed, 517 insertions(+), 16 deletions(-)

diff --git a/drivers/target/tcm_qla2xxx/Kbuild b/drivers/target/tcm_qla2xxx/Kbuild
index a527461..067cca1 100644
--- a/drivers/target/tcm_qla2xxx/Kbuild
+++ b/drivers/target/tcm_qla2xxx/Kbuild
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/drivers/scsi/ -I$(srctree)/include/scsi/ -I$(srctree)/drivers/target/tcm_qla2xxx
+EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/drivers/scsi/ -I$(srctree)/drivers/scsi/qla2xxx/ -I$(srctree)/include/scsi/ -I$(srctree)/drivers/target/tcm_qla2xxx/
 
 tcm_qla2xxx-objs		:= tcm_qla2xxx_fabric.o \
 				   tcm_qla2xxx_configfs.o \
diff --git a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_base.h b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_base.h
index 7c5f7ac..404f579 100644
--- a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_base.h
+++ b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_base.h
@@ -3,6 +3,12 @@
 #define TCM_QLA2XXX_VERSION	"v0.1"
 /* length of ASCII WWPNs including pad */
 #define TCM_QLA2XXX_NAMELEN	32
+/* lenth of ASCII NPIV 'WWPN+WWNN' including pad */
+#define TCM_QLA2XXX_NPIV_NAMELEN 66
+
+struct tcm_qla2xxx_cmd {
+	struct se_cmd se_cmd;
+};
 
 struct tcm_qla2xxx_nacl {
 	/* Binary World Wide unique Port Name for FC Initiator Nport */
@@ -27,8 +33,20 @@ struct tcm_qla2xxx_lport {
 	u8 lport_proto_id;
 	/* Binary World Wide unique Port Name for FC Target Lport */
 	u64 lport_wwpn;
+	/* Binary World Wide unique Port Name for FC NPIV Target Lport */
+	u64 lport_npiv_wwpn;
+	/* Binary World Wide unique Node Name for FC NPIV Target Lport */
+	u64 lport_npiv_wwnn;
 	/* ASCII formatted WWPN for FC Target Lport */
 	char lport_name[TCM_QLA2XXX_NAMELEN];
+	/* ASCII formatted WWPN+WWNN for NPIV FC Target Lport */
+	char lport_npiv_name[TCM_QLA2XXX_NPIV_NAMELEN];
+	/* Pointer to struct scsi_qla_host from qla2xxx LLD */
+	struct scsi_qla_host *qla_vha;
+	/* Pointer to struct scsi_qla_host for NPIV VP from qla2xxx LLD */
+	struct scsi_qla_host *qla_npiv_vp;
+	/* Pointer to struct fc_vport for NPIV vport from libfc */
+	struct fc_vport *npiv_vport;
 	/* Returned by tcm_qla2xxx_make_lport() */
 	struct se_wwn lport_wwn;
 };
diff --git a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_configfs.c b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_configfs.c
index 51091fd..c6308cf 100644
--- a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_configfs.c
+++ b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_configfs.c
@@ -56,6 +56,7 @@
 
 /* Local pointer to allocated TCM configfs fabric module */
 struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs;
+struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs;
 
 static struct se_node_acl *tcm_qla2xxx_make_nodeacl(
 	struct se_portal_group *se_tpg,
@@ -145,6 +146,56 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg)
 	kfree(tpg);
 }
 
+static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
+	struct se_wwn *wwn,
+	struct config_group *group,
+	const char *name)
+{
+	struct tcm_qla2xxx_lport *lport = container_of(wwn,
+			struct tcm_qla2xxx_lport, lport_wwn);
+	struct tcm_qla2xxx_tpg *tpg;
+	unsigned long tpgt;
+	int ret;
+
+	if (strstr(name, "tpgt_") != name)
+		return ERR_PTR(-EINVAL);
+	if (strict_strtoul(name + 5, 10, &tpgt) || tpgt > USHRT_MAX)
+		return ERR_PTR(-EINVAL);
+
+	tpg = kzalloc(sizeof(struct tcm_qla2xxx_tpg), GFP_KERNEL);
+	if (!(tpg)) {
+		printk(KERN_ERR "Unable to allocate struct tcm_qla2xxx_tpg\n");
+		return ERR_PTR(-ENOMEM);
+	}
+	tpg->lport = lport;
+	tpg->lport_tpgt = tpgt;
+
+	ret = core_tpg_register(&tcm_qla2xxx_npiv_fabric_configfs->tf_ops, wwn,
+				&tpg->se_tpg, (void *)tpg,
+				TRANSPORT_TPG_TYPE_NORMAL);
+	if (ret < 0) {
+		kfree(tpg);
+		return NULL;
+	}
+	return &tpg->se_tpg;
+}
+
+
+static void tcm_qla2xxx_init_lport(
+	struct tcm_qla2xxx_lport *lport,
+	struct scsi_qla_host *vha,
+	struct scsi_qla_host *npiv_vp)
+{
+	struct qla_hw_data *ha = vha->hw;
+
+	/*
+	 * Setup local pointer to vha, NPIV VP pointer (if present) and
+	 * vha->tcm_lport pointer
+	 */
+	lport->qla_vha = vha;
+	lport->qla_npiv_vp = npiv_vp;
+	ha->tcm_lport = lport;
+}
 
 static struct se_wwn *tcm_qla2xxx_make_lport(
 	struct target_fabric_configfs *tf,
@@ -152,7 +203,14 @@ static struct se_wwn *tcm_qla2xxx_make_lport(
 	const char *name)
 {
 	struct tcm_qla2xxx_lport *lport;
+	struct Scsi_Host *host = NULL;
+	struct pci_dev *dev = NULL;
+	struct scsi_qla_host *vha;
+	struct qla_hw_data *ha;
+	unsigned long flags;
 	u64 wwpn;
+	int i, ret = -ENODEV;
+	u8 b[8];
 
 	if (tcm_qla2xxx_parse_wwn(name, &wwpn, 1) < 0)
 		return ERR_PTR(-EINVAL);
@@ -165,21 +223,249 @@ static struct se_wwn *tcm_qla2xxx_make_lport(
 	lport->lport_wwpn = wwpn;
 	tcm_qla2xxx_format_wwn(&lport->lport_name[0], TCM_QLA2XXX_NAMELEN, wwpn);
 
+	while ((dev = pci_get_device(PCI_VENDOR_ID_QLOGIC, PCI_ANY_ID,
+					dev)) != NULL) {
+
+		vha = pci_get_drvdata(dev);
+		if (!vha)
+			continue;
+		ha = vha->hw;
+		if (!ha)
+			continue;
+		host = vha->host;
+		if (!host)
+			continue;
+
+		if (!(host->hostt->supported_mode & MODE_TARGET))
+			continue;
+
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+		if (host->active_mode & MODE_TARGET) {
+			printk(KERN_INFO "MODE_TARGET already active on qla2xxx"
+					"(%d)\n",  host->host_no);
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+			continue;
+		}
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+		if (!scsi_host_get(host)) {
+			printk(KERN_ERR "Unable to scsi_host_get() for"
+				" qla2xxx scsi_host\n");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		printk("qla2xxx HW vha->node_name: ");
+		for (i = 0; i < 8; i++)
+			printk("%02x ", vha->node_name[i]);
+		printk("\n");
+
+		printk("qla2xxx HW vha->port_name: ");
+		for (i = 0; i < 8; i++)
+			printk("%02x ", vha->port_name[i]);
+		printk("\n");
+
+		printk("qla2xxx passed configfs WWPN: ");
+		put_unaligned_be64(wwpn, b);
+		for (i = 0; i < 8; i++)
+			printk("%02x ", b[i]);
+		printk("\n");
+
+		if (memcmp(vha->port_name, b, 8)) {
+			scsi_host_put(host);
+			continue;
+		}
+		printk("qla2xxx: Found matching HW WWPN: %s for lport\n", name);
+		tcm_qla2xxx_init_lport(lport, vha, NULL);
+		ret = 0;
+		break;
+	}
+
+	if (ret != 0)
+		goto out;
+
+	return &lport->lport_wwn;
+out:
+	kfree(lport);
+	return ERR_PTR(ret);
+}
+
+static void tcm_qla2xxx_drop_lport(struct se_wwn *wwn)
+{
+	struct tcm_qla2xxx_lport *lport = container_of(wwn,
+			struct tcm_qla2xxx_lport, lport_wwn);
+	struct scsi_qla_host *vha = lport->qla_vha;
+	struct Scsi_Host *sh = vha->host;
+
+	scsi_host_put(sh);
+	kfree(lport);
+}
+
+static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
+	struct target_fabric_configfs *tf,
+	struct config_group *group,
+	const char *name)
+{
+	struct tcm_qla2xxx_lport *lport;
+	struct Scsi_Host *host = NULL;
+	struct pci_dev *dev = NULL;
+	struct scsi_qla_host *vha, *npiv_vp;
+	struct qla_hw_data *ha;
+	struct fc_vport_identifiers vid;
+	struct fc_vport *vport;
+	unsigned long flags;
+	u64 npiv_wwpn, npiv_wwnn;
+	int i, ret = -ENODEV;
+	u8 b[8], b2[8];
+
+	if (tcm_qla2xxx_npiv_parse_wwn(name, strlen(name)+1,
+				&npiv_wwpn, &npiv_wwnn) < 0)
+		return ERR_PTR(-EINVAL);
+
+	lport = kzalloc(sizeof(struct tcm_qla2xxx_lport), GFP_KERNEL);
+	if (!(lport)) {
+		printk(KERN_ERR "Unable to allocate struct tcm_qla2xxx_lport"
+				" for NPIV\n");
+		return ERR_PTR(-ENOMEM);
+	}
+	lport->lport_npiv_wwpn = npiv_wwpn;
+	lport->lport_npiv_wwnn = npiv_wwnn;
+	tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0],
+			TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn);
+
+	while ((dev = pci_get_device(PCI_VENDOR_ID_QLOGIC, PCI_ANY_ID,
+					dev)) != NULL) {
+
+		vha = pci_get_drvdata(dev);
+		if (!vha)
+			continue;
+		ha = vha->hw;
+		if (!ha)
+			continue;
+		host = vha->host;
+		if (!host)
+			continue;
+
+		if (!(host->hostt->supported_mode & MODE_TARGET))
+			continue;
+
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+		if (host->active_mode & MODE_TARGET) {
+			printk(KERN_INFO "MODE_TARGET already active on qla2xxx"
+					"(%d)\n",  host->host_no);
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+			continue;
+		}
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+		if (!scsi_host_get(host)) {
+			printk(KERN_ERR "Unable to scsi_host_get() for"
+				" qla2xxx scsi_host\n");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		printk("qla2xxx HW vha->node_name: ");
+		for (i = 0; i < 8; i++)
+			printk("%02x ", vha->node_name[i]);
+		printk("\n");
+
+		printk("qla2xxx HW vha->port_name: ");
+		for (i = 0; i < 8; i++)
+			printk("%02x ", vha->port_name[i]);
+		printk("\n");
+
+		printk("qla2xxx passed configfs NPIV WWPN: ");
+		put_unaligned_be64(npiv_wwpn, b);
+		for (i = 0; i < 8; i++)
+			printk("%02x ", b[i]);
+		printk("\n");
+
+		printk("qla2xxx passed configfs NPIV WWNN: ");
+		put_unaligned_be64(npiv_wwnn, b2);
+		for (i = 0; i < 8; i++)
+			printk("%02x ", b2[i]);
+		printk("\n");
+
+		spin_lock_irqsave(&ha->vport_slock, flags);
+		list_for_each_entry(npiv_vp, &ha->vp_list, list) {
+			if (!npiv_vp->vp_idx)
+				continue;
+
+			if (memcmp(npiv_vp->port_name, b, 8) ||
+			    memcmp(npiv_vp->node_name, b2, 8))
+				continue;
+
+#warning FIXME: Need to add atomic_inc(&npiv_vp->vref_count) before dropping ha->vport_slock..?
+			spin_unlock_irqrestore(&ha->vport_slock, flags);
+
+			printk("qla2xxx_npiv: Found matching NPIV WWPN+WWNN: %s "
+					" for lport\n", name);
+			tcm_qla2xxx_init_lport(lport, vha, npiv_vp);
+			/*
+			 * Setup fc_vport_identifiers for NPIV containing
+			 * the passed WWPN and WWNN for the new libfc vport.
+			 */
+			memset(&vid, 0, sizeof(vid));
+			vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
+			vid.vport_type = FC_PORTTYPE_NPIV;
+			vid.port_name = npiv_wwpn;
+			vid.node_name = npiv_wwnn;
+			/* vid.symbolic_name is already zero/NULL's */
+			vid.disable = false;	/* always enabled */
+
+			/* we only allow support on Channel 0 !!! */
+			vport = fc_vport_create(host, 0, &vid);
+			if (!vport) {
+				printk(KERN_ERR "fc_vport_create() failed for"
+						" NPIV tcm_qla2xxx\n");
+				scsi_host_put(host);
+				ret = -EINVAL;
+				goto out;
+			}
+			lport->npiv_vport = vport;
+			ret = 0;
+			spin_lock_irqsave(&ha->vport_slock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&ha->vport_slock, flags);
+
+		if (!ret)
+			break;
+
+		scsi_host_put(host);
+	}
+
+	if (ret != 0)
+		goto out;
+
 	return &lport->lport_wwn;
+out:
+	kfree(lport);
+	return ERR_PTR(ret);
 }
 
-static void tcm_qla2xxx_drop_lport(struct se_wwn_s *wwn)
+static void tcm_qla2xxx_npiv_drop_lport(struct se_wwn *wwn)
 {
 	struct tcm_qla2xxx_lport *lport = container_of(wwn,
 			struct tcm_qla2xxx_lport, lport_wwn);
+	struct scsi_qla_host *vha = lport->qla_vha;
+	struct Scsi_Host *sh = vha->host;
+	/*
+	 * Notify libfc that we want to release the lport->npiv_vport
+	 */
+	fc_vport_terminate(lport->npiv_vport);
+
+	scsi_host_put(sh);
 	kfree(lport);
 }
 
+
 static ssize_t tcm_qla2xxx_wwn_show_attr_version(
 	struct target_fabric_configfs *tf,
 	char *page)
 {
-	return sprintf(page, "TCM QLOGIC QLA2XXX fabric module %s on %s/%s"
+	return sprintf(page, "TCM QLOGIC QLA2XXX NPIV capable fabric module %s on %s/%s"
 		" on "UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname,
 		utsname()->machine);
 }
@@ -244,9 +530,62 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
 	.fabric_drop_nodeacl		= tcm_qla2xxx_drop_nodeacl,
 };
 
+static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
+	.get_fabric_name		= tcm_qla2xxx_npiv_get_fabric_name,
+	.get_fabric_proto_ident		= tcm_qla2xxx_get_fabric_proto_ident,
+	.tpg_get_wwn			= tcm_qla2xxx_npiv_get_fabric_wwn,
+	.tpg_get_tag			= tcm_qla2xxx_get_tag,
+	.tpg_get_default_depth		= tcm_qla2xxx_get_default_depth,
+	.tpg_get_pr_transport_id	= tcm_qla2xxx_get_pr_transport_id,
+	.tpg_get_pr_transport_id_len	= tcm_qla2xxx_get_pr_transport_id_len,
+	.tpg_parse_pr_out_transport_id	= tcm_qla2xxx_parse_pr_out_transport_id,
+	.tpg_check_demo_mode		= tcm_qla2xxx_check_false,
+	.tpg_check_demo_mode_cache	= tcm_qla2xxx_check_true,
+	.tpg_check_demo_mode_write_protect = tcm_qla2xxx_check_true,
+	.tpg_check_prod_mode_write_protect = tcm_qla2xxx_check_false,
+	.tpg_alloc_fabric_acl		= tcm_qla2xxx_alloc_fabric_acl,
+	.tpg_release_fabric_acl		= tcm_qla2xxx_release_fabric_acl,
+	.tpg_get_inst_index		= tcm_qla2xxx_tpg_get_inst_index,
+	.release_cmd_to_pool		= tcm_qla2xxx_release_cmd,
+	.release_cmd_direct		= tcm_qla2xxx_release_cmd,
+	.shutdown_session		= tcm_qla2xxx_shutdown_session,
+	.close_session			= tcm_qla2xxx_close_session,
+	.stop_session			= tcm_qla2xxx_stop_session,
+	.fall_back_to_erl0		= tcm_qla2xxx_reset_nexus,
+	.sess_logged_in			= tcm_qla2xxx_sess_logged_in,
+	.sess_get_index			= tcm_qla2xxx_sess_get_index,
+	.sess_get_initiator_sid		= NULL,
+	.write_pending			= tcm_qla2xxx_write_pending,
+	.write_pending_status		= tcm_qla2xxx_write_pending_status,
+	.set_default_node_attributes	= tcm_qla2xxx_set_default_node_attrs,
+	.get_task_tag			= tcm_qla2xxx_get_task_tag,
+	.get_cmd_state			= tcm_qla2xxx_get_cmd_state,
+	.new_cmd_failure		= tcm_qla2xxx_new_cmd_failure,
+	.queue_data_in			= tcm_qla2xxx_queue_data_in,
+	.queue_status			= tcm_qla2xxx_queue_status,
+	.queue_tm_rsp			= tcm_qla2xxx_queue_tm_rsp,
+	.get_fabric_sense_len		= tcm_qla2xxx_get_fabric_sense_len,
+	.set_fabric_sense_len		= tcm_qla2xxx_set_fabric_sense_len,
+	.is_state_remove		= tcm_qla2xxx_is_state_remove,
+	.pack_lun			= tcm_qla2xxx_pack_lun,
+	/*
+	 * Setup function pointers for generic logic in target_core_fabric_configfs.c
+	 */
+	.fabric_make_wwn		= tcm_qla2xxx_npiv_make_lport,
+	.fabric_drop_wwn		= tcm_qla2xxx_npiv_drop_lport,
+	.fabric_make_tpg		= tcm_qla2xxx_npiv_make_tpg,
+	.fabric_drop_tpg		= tcm_qla2xxx_drop_tpg,
+	.fabric_post_link		= NULL,
+	.fabric_pre_unlink		= NULL,
+	.fabric_make_np			= NULL,
+	.fabric_drop_np			= NULL,
+	.fabric_make_nodeacl		= tcm_qla2xxx_make_nodeacl,
+	.fabric_drop_nodeacl		= tcm_qla2xxx_drop_nodeacl,
+};
+
 static int tcm_qla2xxx_register_configfs(void)
 {
-	struct target_fabric_configfs *fabric;
+	struct target_fabric_configfs *fabric, *npiv_fabric;
 	int ret;
 
 	printk(KERN_INFO "TCM QLOGIC QLA2XXX fabric module %s on %s/%s"
@@ -290,7 +629,53 @@ static int tcm_qla2xxx_register_configfs(void)
 	 */
 	tcm_qla2xxx_fabric_configfs = fabric;	
 	printk(KERN_INFO "TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_fabric_configfs\n");
+
+	/*
+	 * Register the top level struct config_item_type for NPIV with TCM core
+	 */
+	npiv_fabric = target_fabric_configfs_init(THIS_MODULE, "qla2xxx_npiv");
+	if (!(npiv_fabric)) {
+		printk(KERN_ERR "target_fabric_configfs_init() failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	/*
+	 * Setup fabric->tf_ops from our local tcm_qla2xxx_npiv_ops
+	 */
+	npiv_fabric->tf_ops = tcm_qla2xxx_npiv_ops;
+	/*
+	 * Setup default attribute lists for various npiv_fabric->tf_cit_tmpl
+	 */
+	TF_CIT_TMPL(npiv_fabric)->tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
+	TF_CIT_TMPL(npiv_fabric)->tfc_tpg_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(npiv_fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(npiv_fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(npiv_fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(npiv_fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(npiv_fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(npiv_fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(npiv_fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+	/*
+	 * Register the npiv_fabric for use within TCM
+	 */
+	ret = target_fabric_configfs_register(npiv_fabric);
+	if (ret < 0) {
+		printk(KERN_ERR "target_fabric_configfs_register() failed"
+				" for TCM_QLA2XXX\n");
+		goto out;;
+	}
+	/*
+	 * Setup our local pointer to *npiv_fabric
+	 */
+	tcm_qla2xxx_npiv_fabric_configfs = npiv_fabric;
+	printk(KERN_INFO "TCM_QLA2XXX[0] - Set fabric -> tcm_qla2xxx_npiv_fabric_configfs\n");
+
 	return 0;
+out:
+	if (tcm_qla2xxx_fabric_configfs != NULL)
+		target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs);
+
+	return ret;
 }
 
 static void tcm_qla2xxx_deregister_configfs(void)
@@ -301,6 +686,10 @@ static void tcm_qla2xxx_deregister_configfs(void)
 	target_fabric_configfs_deregister(tcm_qla2xxx_fabric_configfs);
 	tcm_qla2xxx_fabric_configfs = NULL;
 	printk(KERN_INFO "TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_fabric_configfs\n");
+
+	target_fabric_configfs_deregister(tcm_qla2xxx_npiv_fabric_configfs);
+	tcm_qla2xxx_npiv_fabric_configfs = NULL;
+	printk(KERN_INFO "TCM_QLA2XXX[0] - Cleared tcm_qla2xxx_npiv_fabric_configfs\n");
 }
 
 static int __init tcm_qla2xxx_init(void)
@@ -320,7 +709,7 @@ static void __exit tcm_qla2xxx_exit(void)
 }
 
 #ifdef MODULE
-MODULE_DESCRIPTION("TCM QLA2XXX series fabric driver");
+MODULE_DESCRIPTION("TCM QLA2XXX series NPIV enabled fabric driver");
 MODULE_LICENSE("GPL");
 module_init(tcm_qla2xxx_init);
 module_exit(tcm_qla2xxx_exit);
diff --git a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c
index 347ad1e..f1cfd8c 100644
--- a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c
+++ b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.c
@@ -40,6 +40,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/libfc.h>
+#include <scsi/scsi_transport_fc.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_transport.h>
@@ -128,7 +129,87 @@ char *tcm_qla2xxx_get_fabric_name(void)
 	return "qla2xxx";
 }
 
-u8 tcm_qla2xxx_get_fabric_proto_ident(se_portal_group_t *se_tpg)
+/*
+ * From drivers/scsi/scsi_transport_fc.c:fc_parse_wwn
+ */
+static int tcm_qla2xxx_npiv_extract_wwn(const char *ns, u64 *nm)
+{
+	unsigned int i, j, value;
+	u8 wwn[8];
+
+	memset(wwn, 0, sizeof(wwn));
+
+	/* Validate and store the new name */
+	for (i = 0, j = 0; i < 16; i++) {
+		value = hex_to_bin(*ns++);
+		if (value >= 0)
+			j = (j << 4) | value;
+		else
+			return -EINVAL;
+
+		if (i % 2) {
+			wwn[i/2] = j & 0xff;
+			j = 0;
+		}
+	}
+
+	*nm = wwn_to_u64(wwn);
+	return 0;
+}
+
+/*
+ * This parsing logic follows drivers/scsi/scsi_transport_fc.c:store_fc_host_vport_create()
+ */
+int tcm_qla2xxx_npiv_parse_wwn(
+	const char *name,
+	size_t count,
+	u64 *wwpn,
+	u64 *wwnn)
+{
+	unsigned int cnt = count;
+	int rc;
+
+	*wwpn = 0;
+	*wwnn = 0;
+
+	/* count may include a LF at end of string */
+	if (name[cnt-1] == '\n')
+		cnt--;
+
+	/* validate we have enough characters for WWPN */
+	if ((cnt != (16+1+16)) || (name[16] != ':'))
+		return -EINVAL;
+
+	rc = tcm_qla2xxx_npiv_extract_wwn(&name[0], wwpn);
+	if (rc != 0)
+		return rc;
+
+	rc = tcm_qla2xxx_npiv_extract_wwn(&name[17], wwnn);
+	if (rc != 0)
+		return rc;
+
+	return 0;
+}
+
+ssize_t tcm_qla2xxx_npiv_format_wwn(char *buf, size_t len, u64 wwpn, u64 wwnn)
+{
+	u8 b[8], b2[8];
+
+	put_unaligned_be64(wwpn, b);
+	put_unaligned_be64(wwnn, b2);
+        return snprintf(buf, len,
+                "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x,"
+		"%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],
+		b2[0], b2[1], b2[2], b2[3], b2[4], b2[5], b2[6], b2[7]);
+}
+
+char *tcm_qla2xxx_npiv_get_fabric_name(void)
+{
+	return "qla2xxx_npiv";
+}
+
+u8 tcm_qla2xxx_get_fabric_proto_ident(struct se_portal_group *se_tpg)
 {
 	struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
 				struct tcm_qla2xxx_tpg, se_tpg);
@@ -154,7 +235,16 @@ char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg)
 	return &lport->lport_name[0];
 }
 
-u16 tcm_qla2xxx_get_tag(se_portal_group_t *se_tpg)
+char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+	struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
+				struct tcm_qla2xxx_tpg, se_tpg);
+	struct tcm_qla2xxx_lport *lport = tpg->lport;
+
+	return &lport->lport_npiv_name[0];
+}
+
+u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg)
 {
 	struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
 				struct tcm_qla2xxx_tpg, se_tpg);
diff --git a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.h b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.h
index 151d352..d0a5d01 100644
--- a/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.h
+++ b/drivers/target/tcm_qla2xxx/tcm_qla2xxx_fabric.h
@@ -3,15 +3,19 @@ extern int tcm_qla2xxx_check_false(struct se_portal_group *);
 extern ssize_t tcm_qla2xxx_parse_wwn(const char *, u64 *, int);
 extern ssize_t tcm_qla2xxx_format_wwn(char *, size_t, u64);
 extern char *tcm_qla2xxx_get_fabric_name(void);
-extern u8 tcm_qla2xxx_get_fabric_proto_ident(se_portal_group_t *);
-extern char *tcm_qla2xxx_get_fabric_wwn(se_portal_group_t *);
-extern u16 tcm_qla2xxx_get_tag(se_portal_group_t *);
-extern u32 tcm_qla2xxx_get_default_depth(se_portal_group_t *);
-extern u32 tcm_qla2xxx_get_pr_transport_id(se_portal_group_t *, se_node_acl_t *,
-				t10_pr_registration_t *, int *, unsigned char *);
-extern u32 tcm_qla2xxx_get_pr_transport_id_len(se_portal_group_t *, se_node_acl_t *,
-				t10_pr_registration_t *, int *);
-extern char *tcm_qla2xxx_parse_pr_out_transport_id(se_portal_group_t *, const char *,
+extern int tcm_qla2xxx_npiv_parse_wwn(const char *name, size_t, u64 *, u64 *);
+extern ssize_t tcm_qla2xxx_npiv_format_wwn(char *, size_t, u64, u64);
+extern char *tcm_qla2xxx_npiv_get_fabric_name(void);
+extern u8 tcm_qla2xxx_get_fabric_proto_ident(struct se_portal_group *);
+extern char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *);
+extern char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *);
+extern u16 tcm_qla2xxx_get_tag(struct se_portal_group *);
+extern u32 tcm_qla2xxx_get_default_depth(struct se_portal_group *);
+extern u32 tcm_qla2xxx_get_pr_transport_id(struct se_portal_group *, struct se_node_acl *,
+			struct t10_pr_registration *, int *, unsigned char *);
+extern u32 tcm_qla2xxx_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *,
+			struct t10_pr_registration *, int *);
+extern char *tcm_qla2xxx_parse_pr_out_transport_id(struct se_portal_group *, const char *,
 				u32 *, char **);
 extern struct se_node_acl *tcm_qla2xxx_alloc_fabric_acl(struct se_portal_group *);
 extern void tcm_qla2xxx_release_fabric_acl(struct se_portal_group *, struct se_node_acl *);
-- 
1.5.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux