[PATCH 1/2] qla2xxx: add support for NPIV

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

 



Following patch adds support for NPIV (N-Port ID Virtualization) to the
qla2xxx.

- supported within switched-fabric topologies only.
- supports up to 63 virtual ports on each physical port.

The patch has been inlined and attached in a plain text format as well
to provide alternative way for using it in the case where the inlined
not working.
Also, the same patch can be downloaded from following link,
ftp://ftp.qlogic.com/outgoing/linux/patches/8.x/8.02.00-k1/0001-qla2xxx-
Add-support-for-NPIV-N-Port-ID-Virtualizat.patch


Signed-off-by: Seokmann Ju <seokmann.ju@xxxxxxxxxx>
---
 drivers/scsi/qla2xxx/Makefile   |    2 +-
 drivers/scsi/qla2xxx/qla_attr.c |  164 +++++++++++++
 drivers/scsi/qla2xxx/qla_dbg.h  |   10 +-
 drivers/scsi/qla2xxx/qla_def.h  |   83 +++++++
 drivers/scsi/qla2xxx/qla_fw.h   |   91 ++++++-
 drivers/scsi/qla2xxx/qla_gbl.h  |   39 +++-
 drivers/scsi/qla2xxx/qla_gs.c   |    3 +
 drivers/scsi/qla2xxx/qla_init.c |  168 ++++++++++++--
 drivers/scsi/qla2xxx/qla_iocb.c |   28 ++-
 drivers/scsi/qla2xxx/qla_isr.c  |   39 +++-
 drivers/scsi/qla2xxx/qla_mbx.c  |  396 ++++++++++++++++++++++++++++++-
 drivers/scsi/qla2xxx/qla_mid.c  |  497
+++++++++++++++++++++++++++++++++++++++
 drivers/scsi/qla2xxx/qla_os.c   |  229 +++++++++++--------
 13 files changed, 1594 insertions(+), 155 deletions(-)
 create mode 100644 drivers/scsi/qla2xxx/qla_mid.c

diff --git a/drivers/scsi/qla2xxx/Makefile
b/drivers/scsi/qla2xxx/Makefile
index 411663a..71ddb5d 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,4 +1,4 @@
 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_dbg.o qla_sup.o qla_attr.o qla_mid.o
 
 obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c
b/drivers/scsi/qla2xxx/qla_attr.c
index 8081b63..95bee23 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -6,8 +6,11 @@
  */
 #include "qla_def.h"
 
+#include <linux/kthread.h>
 #include <linux/vmalloc.h>
 
+int qla24xx_vport_disable(struct fc_vport *, bool);
+
 /* SYSFS attributes
--------------------------------------------------------- */
 
 static ssize_t
@@ -959,6 +962,122 @@ qla2x00_get_host_port_state(struct Scsi_Host
*shost)
 		fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
 }
 
+static int
+qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
+{
+	int	ret = 0;
+	scsi_qla_host_t *ha = (scsi_qla_host_t *)
fc_vport->shost->hostdata;
+	scsi_qla_host_t *vha;
+
+	ret = qla24xx_vport_create_req_sanity_check(fc_vport);
+	if (ret) {
+		DEBUG15(printk("qla24xx_vport_create_req_sanity_check
failed, "
+		    "status %x\n", ret));
+		return (ret);
+	}
+
+	vha = qla24xx_create_vhost(fc_vport);
+	if (vha == NULL) {
+		DEBUG15(printk ("qla24xx_create_vhost failed, vha =
%p\n",
+		    vha));
+		return FC_VPORT_FAILED;
+	}
+	if (disable) {
+		atomic_set(&vha->vp_state, VP_OFFLINE);
+		fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
+	} else
+		atomic_set(&vha->vp_state, VP_FAILED);
+
+	/* ready to create vport */
+	qla_printk(KERN_INFO, vha, "VP entry id %d assigned.\n",
vha->vp_idx);
+
+	/* initialized vport states */
+	atomic_set(&vha->loop_state, LOOP_DOWN);
+	vha->vp_err_state=  VP_ERR_PORTDWN;
+	vha->vp_prev_err_state=  VP_ERR_UNKWN;
+	/* Check if physical ha port is Up */
+	if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
+	    atomic_read(&ha->loop_state) == LOOP_DEAD) {
+		/* Don't retry or attempt login of this virtual port */
+		DEBUG15(printk ("scsi(%ld): pport loop_state is not
UP.\n",
+		    vha->host_no));
+		atomic_set(&vha->loop_state, LOOP_DEAD);
+		if (!disable)
+			fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
+	}
+
+	if (scsi_add_host(vha->host, &fc_vport->dev)) {
+		DEBUG15(printk("scsi(%ld): scsi_add_host failure for
VP[%d].\n",
+			vha->host_no, vha->vp_idx));
+		goto vport_create_failed_2;
+	}
+
+	/* initialize attributes */
+	fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
+	fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name);
+	fc_host_supported_classes(vha->host) =
+		fc_host_supported_classes(ha->host);
+	fc_host_supported_speeds(vha->host) =
+		fc_host_supported_speeds(ha->host);
+
+	qla24xx_vport_disable(fc_vport, disable);
+
+	return 0;
+vport_create_failed_2:
+	qla24xx_disable_vp(vha);
+	qla24xx_deallocate_vp_id(vha);
+	kfree(vha->port_name);
+	kfree(vha->node_name);
+	scsi_host_put(vha->host);
+    	return FC_VPORT_FAILED;
+}
+
+int
+qla24xx_vport_delete(struct fc_vport *fc_vport)
+{
+	scsi_qla_host_t *ha = (scsi_qla_host_t *)
fc_vport->shost->hostdata;
+	scsi_qla_host_t *vha = fc_vport->dd_data;
+
+	qla24xx_disable_vp(vha);
+	qla24xx_deallocate_vp_id(vha);
+
+	down(&ha->vport_sem);
+	ha->cur_vport_count--;
+	clear_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
+	up(&ha->vport_sem);
+
+	kfree(vha->node_name);
+	kfree(vha->port_name);
+
+	if (vha->timer_active) {
+		qla2x00_vp_stop_timer(vha);
+		DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p
"
+		    "has stopped\n",
+		    vha->host_no, vha->vp_idx, vha));
+        }
+
+	fc_remove_host(vha->host);
+
+	scsi_remove_host(vha->host);
+
+	scsi_host_put(vha->host);
+
+	return 0;
+}
+
+int
+qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
+{
+	scsi_qla_host_t *vha = fc_vport->dd_data;
+
+	if (disable)
+		qla24xx_disable_vp(vha);
+	else
+		qla24xx_enable_vp(vha);
+
+	return 0;
+}
+
 struct fc_function_template qla2xxx_transport_functions = {
 
 	.show_host_node_name = 1,
@@ -996,6 +1115,49 @@ struct fc_function_template
qla2xxx_transport_functions = {
 
 	.issue_fc_host_lip = qla2x00_issue_lip,
 	.get_fc_host_stats = qla2x00_get_fc_host_stats,
+
+	.vport_create = qla24xx_vport_create,
+	.vport_disable = qla24xx_vport_disable,
+	.vport_delete = qla24xx_vport_delete,
+};
+
+struct fc_function_template qla2xxx_transport_vport_functions = {
+
+	.show_host_node_name = 1,
+	.show_host_port_name = 1,
+	.show_host_supported_classes = 1,
+
+	.get_host_port_id = qla2x00_get_host_port_id,
+	.show_host_port_id = 1,
+	.get_host_speed = qla2x00_get_host_speed,
+	.show_host_speed = 1,
+	.get_host_port_type = qla2x00_get_host_port_type,
+	.show_host_port_type = 1,
+	.get_host_symbolic_name = qla2x00_get_host_symbolic_name,
+	.show_host_symbolic_name = 1,
+	.set_host_system_hostname = qla2x00_set_host_system_hostname,
+	.show_host_system_hostname = 1,
+	.get_host_fabric_name = qla2x00_get_host_fabric_name,
+	.show_host_fabric_name = 1,
+	.get_host_port_state = qla2x00_get_host_port_state,
+	.show_host_port_state = 1,
+
+	.dd_fcrport_size = sizeof(struct fc_port *),
+	.show_rport_supported_classes = 1,
+
+	.get_starget_node_name = qla2x00_get_starget_node_name,
+	.show_starget_node_name = 1,
+	.get_starget_port_name = qla2x00_get_starget_port_name,
+	.show_starget_port_name = 1,
+	.get_starget_port_id  = qla2x00_get_starget_port_id,
+	.show_starget_port_id = 1,
+
+	.get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
+	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
+	.show_rport_dev_loss_tmo = 1,
+
+	.issue_fc_host_lip = qla2x00_issue_lip,
+	.get_fc_host_stats = qla2x00_get_fc_host_stats,
 };
 
 void
@@ -1004,4 +1166,6 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha)
 	fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
 	fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
 	fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
+	fc_host_max_npiv_vports(ha->host) = MAX_NUM_VPORT_FABRIC;
+	fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count;
 }
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h
b/drivers/scsi/qla2xxx/qla_dbg.h
index 5b12278..49dffeb 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -21,6 +21,7 @@
 /* #define QL_DEBUG_LEVEL_12 */ /* Output IP trace msgs */
 /* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */
 /* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */
+/* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */
 /*
  *  Local Macro Definitions.
  */
@@ -30,7 +31,8 @@
     defined(QL_DEBUG_LEVEL_7)  || defined(QL_DEBUG_LEVEL_8) || \
     defined(QL_DEBUG_LEVEL_9)  || defined(QL_DEBUG_LEVEL_10) || \
     defined(QL_DEBUG_LEVEL_11) || defined(QL_DEBUG_LEVEL_12) || \
-    defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14)
+    defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14) || \
+    defined(QL_DEBUG_LEVEL_15)
     #define QL_DEBUG_ROUTINES
 #endif
 
@@ -125,6 +127,12 @@
 #define DEBUG14(x)	do {} while (0)
 #endif
 
+#if defined(QL_DEBUG_LEVEL_15)
+#define DEBUG15(x)      do {x;} while (0)
+#else
+#define DEBUG15(x)	do {} while (0)
+#endif
+
 /*
  * Firmware Dump structure definition
  */
diff --git a/drivers/scsi/qla2xxx/qla_def.h
b/drivers/scsi/qla2xxx/qla_def.h
index e8948b6..a1ca590 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1551,6 +1551,9 @@ typedef struct fc_port {
 
 	unsigned long last_queue_full;
 	unsigned long last_ramp_up;
+
+	struct list_head vp_fcport;
+	uint16_t vp_idx;
 } fc_port_t;
 
 /*
@@ -1999,6 +2002,36 @@ struct gid_list_info {
 };
 #define GID_LIST_SIZE (sizeof(struct gid_list_info) *
MAX_FIBRE_DEVICES)
 
+/* NPIV */
+typedef struct vport_info {
+	uint8_t		port_name[WWN_SIZE];
+	uint8_t		node_name[WWN_SIZE];
+	int		vp_id;
+	uint16_t	loop_id;
+	unsigned long	host_no;
+	uint8_t		port_id[3];
+	int		loop_state;
+} vport_info_t;
+
+typedef struct vport_params {
+	uint8_t 	port_name[WWN_SIZE];
+	uint8_t 	node_name[WWN_SIZE];
+	uint32_t 	options;
+#define	VP_OPTS_RETRY_ENABLE	BIT_0
+#define	VP_OPTS_VP_DISABLE	BIT_1
+} vport_params_t;
+
+/* NPIV - return codes of VP create and modify */
+#define VP_RET_CODE_OK			0
+#define VP_RET_CODE_FATAL		1
+#define VP_RET_CODE_WRONG_ID		2
+#define VP_RET_CODE_WWPN		3
+#define VP_RET_CODE_RESOURCES		4
+#define VP_RET_CODE_NO_MEM		5
+#define VP_RET_CODE_NOT_FOUND		6
+
+#define to_qla_parent(x) (((x)->parent) ? (x)->parent : (x))
+
 /*
  * ISP operations
  */
@@ -2073,6 +2106,16 @@ struct qla_msix_entry {
 	uint16_t msix_entry;
 };
 
+#define	WATCH_INTERVAL		1       /* number of seconds */
+
+/* NPIV */
+#define MAX_MULTI_ID_LOOP                     126
+#define MAX_MULTI_ID_FABRIC                    64
+#define MAX_NUM_VPORT_LOOP                      (MAX_MULTI_ID_LOOP - 1)
+#define MAX_NUM_VPORT_FABRIC                    (MAX_MULTI_ID_FABRIC -
1)
+#define MAX_NUM_VHBA_LOOP                       (MAX_MULTI_ID_LOOP - 1)
+#define MAX_NUM_VHBA_FABRIC                     (MAX_MULTI_ID_FABRIC -
1)
+
 /*
  * Linux Host Adapter structure
  */
@@ -2108,6 +2151,8 @@ typedef struct scsi_qla_host {
 		uint32_t	msix_enabled		:1;
 		uint32_t	disable_serdes		:1;
 		uint32_t	gpsc_supported		:1;
+		uint32_t        vsan_enabled            :1;
+		uint32_t	npiv_supported		:1;
 	} flags;
 
 	atomic_t	loop_state;
@@ -2147,6 +2192,7 @@ typedef struct scsi_qla_host {
 #define BEACON_BLINK_NEEDED	25
 #define REGISTER_FDMI_NEEDED	26
 #define FCPORT_UPDATE_NEEDED	27
+#define VP_DPC_NEEDED		28	/* wake up for VP dpc handling
*/
 
 	uint32_t	device_flags;
 #define DFLG_LOCAL_DEVICES		BIT_0
@@ -2237,6 +2283,11 @@ typedef struct scsi_qla_host {
 
 	/* ISP configuration data. */
 	uint16_t	loop_id;		/* Host adapter loop id
*/
+	uint16_t	switch_cap;
+#define FLOGI_SEQ_DEL		BIT_8
+#define FLOGI_MID_SUPPORT	BIT_10
+#define FLOGI_VSAN_SUPPORT	BIT_12
+#define FLOGI_SP_SUPPORT	BIT_13
 	uint16_t	fb_rev;
 
 	port_id_t	d_id;			/* Host adapter port id
*/
@@ -2344,6 +2395,7 @@ typedef struct scsi_qla_host {
 #define MBX_UPDATE_FLASH_ACTIVE	3
 
 	struct semaphore mbx_cmd_sem;	/* Serialialize mbx access */
+	struct semaphore vport_sem;	/* Virtual port synchronization
*/
 	struct semaphore mbx_intr_sem;  /* Used for completion
notification */
 
 	uint32_t	mbx_flags;
@@ -2428,6 +2480,37 @@ typedef struct scsi_qla_host {
 	struct fc_host_statistics fc_host_stat;
 
 	struct qla_msix_entry msix_entries[QLA_MSIX_ENTRIES];
+
+	struct list_head	vp_list;	/* list of VP */
+	struct fc_vport	*fc_vport;	/* holds fc_vport * for each
vport */
+	uint8_t		vp_idx_map[16];
+	uint16_t        num_vhosts;	/* number of vports created */
+	uint16_t        num_vsans;	/* number of vsan created */
+	uint16_t        vp_idx;		/* vport ID */
+
+	struct scsi_qla_host	*parent;	/* holds pport */
+	unsigned long		vp_flags;
+	struct list_head	vp_fcports;	/* list of fcports */
+#define VP_IDX_ACQUIRED		0	/* bit no 0 */
+#define VP_CREATE_NEEDED	1
+#define VP_BIND_NEEDED		2
+#define VP_DELETE_NEEDED	3
+#define VP_SCR_NEEDED		4	/* State Change Request
registration */
+	atomic_t 		vp_state;
+#define VP_OFFLINE		0
+#define VP_ACTIVE		1
+#define VP_FAILED		2
+// #define VP_DISABLE		3
+	uint16_t 	vp_err_state;
+	uint16_t	vp_prev_err_state;
+#define VP_ERR_UNKWN		0
+#define VP_ERR_PORTDWN		1
+#define VP_ERR_FAB_UNSUPPORTED	2
+#define VP_ERR_FAB_NORESOURCES	3
+#define VP_ERR_FAB_LOGOUT	4
+#define VP_ERR_ADAP_NORESOURCES	5
+	int		max_npiv_vports;	/* 63 or 125 per
topoloty */
+	int		cur_vport_count;
 } scsi_qla_host_t;
 
 
diff --git a/drivers/scsi/qla2xxx/qla_fw.h
b/drivers/scsi/qla2xxx/qla_fw.h
index a0a722c..63a11fe 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -69,6 +69,16 @@ struct port_database_24xx {
 	uint8_t reserved_3[24];
 };
 
+struct vp_database_24xx {
+	uint16_t vp_status;
+	uint8_t  options;
+	uint8_t  id;
+	uint8_t  port_name[WWN_SIZE];
+	uint8_t  node_name[WWN_SIZE];
+	uint16_t port_id_low;
+	uint16_t port_id_high;
+};
+
 struct nvram_24xx {
 	/* NVRAM header. */
 	uint8_t id[4];
@@ -962,6 +972,25 @@ struct mid_db_24xx {
 	struct mid_db_entry_24xx entries[MAX_MID_VPS];
 };
 
+ /*
+ * Virtual Fabric ID type definition.
+ */
+typedef struct vf_id {
+        uint16_t id : 12;
+        uint16_t priority : 4;
+} vf_id_t;
+
+/*
+ * Virtual Fabric HopCt type definition.
+ */
+typedef struct vf_hopct {
+        uint16_t reserved : 8;
+        uint16_t hopct : 8;
+} vf_hopct_t;
+
+/*
+ * Virtual Port Control IOCB
+ */
 #define VP_CTRL_IOCB_TYPE	0x30	/* Vitual Port Control entry. */
 struct vp_ctrl_entry_24xx {
 	uint8_t entry_type;		/* Entry type. */
@@ -974,6 +1003,7 @@ struct vp_ctrl_entry_24xx {
 	uint16_t vp_idx_failed;
 
 	uint16_t comp_status;		/* Completion status. */
+#define CS_VCE_IOCB_ERROR       0x01    /* Error processing IOCB */
 #define CS_VCE_ACQ_ID_ERROR	0x02	/* Error while acquireing ID. */
 #define CS_VCE_BUSY		0x05	/* Firmware not ready to accept
cmd. */
 
@@ -982,24 +1012,34 @@ struct vp_ctrl_entry_24xx {
 #define VCE_COMMAND_DISABLE_VPS	0x08	/* Disable VPs. */
 #define VCE_COMMAND_DISABLE_VPS_REINIT	0x09 /* Disable VPs and reinit
link. */
 #define VCE_COMMAND_DISABLE_VPS_LOGO	0x0a /* Disable VPs and LOGO
ports. */
+#define VCE_COMMAND_DISABLE_VPS_LOGO_ALL        0x0b /* Disable VPs and
LOGO ports. */
 
 	uint16_t vp_count;
 
 	uint8_t vp_idx_map[16];
-
-	uint8_t reserved_4[32];
+	uint16_t flags;
+	struct vf_id    id;
+	uint16_t reserved_4;
+	struct vf_hopct  hopct;
+	uint8_t reserved_5[8];
 };
 
+/*
+ * Modify Virtual Port Configuration IOCB
+ */
 #define VP_CONFIG_IOCB_TYPE	0x31	/* Vitual Port Config entry. */
 struct vp_config_entry_24xx {
 	uint8_t entry_type;		/* Entry type. */
 	uint8_t entry_count;		/* Entry count. */
-	uint8_t sys_define;		/* System defined. */
+	uint8_t handle_count;
 	uint8_t entry_status;		/* Entry Status. */
 
 	uint32_t handle;		/* System handle. */
 
-	uint16_t reserved_1;
+	uint16_t flags;
+#define CS_VF_BIND_VPORTS_TO_VF         BIT_0
+#define CS_VF_SET_QOS_OF_VPORTS         BIT_1
+#define CS_VF_SET_HOPS_OF_VPORTS        BIT_2
 
 	uint16_t comp_status;		/* Completion status. */
 #define CS_VCT_STS_ERROR	0x01	/* Specified VPs were not
disabled. */
@@ -1009,27 +1049,29 @@ struct vp_config_entry_24xx {
 #define CS_VCT_BUSY		0x05	/* Firmware not ready to accept
cmd. */
 
 	uint8_t command;
-#define VCT_COMMAND_MOD_VPS	0x00	/* Enable VPs. */
-#define VCT_COMMAND_MOD_ENABLE_VPS 0x08	/* Disable VPs. */
+#define VCT_COMMAND_MOD_VPS     0x00    /* Modify VP configurations. */
+#define VCT_COMMAND_MOD_ENABLE_VPS 0x01 /* Modify configuration &
enable VPs. */
 
 	uint8_t vp_count;
 
-	uint8_t vp_idx1;
-	uint8_t vp_idx2;
+	uint8_t vp_index1;
+	uint8_t vp_index2;
 
 	uint8_t options_idx1;
 	uint8_t hard_address_idx1;
-	uint16_t reserved_2;
+	uint16_t reserved_vp1;
 	uint8_t port_name_idx1[WWN_SIZE];
 	uint8_t node_name_idx1[WWN_SIZE];
 
 	uint8_t options_idx2;
 	uint8_t hard_address_idx2;
-	uint16_t reserved_3;
+	uint16_t reserved_vp2;
 	uint8_t port_name_idx2[WWN_SIZE];
 	uint8_t node_name_idx2[WWN_SIZE];
-
-	uint8_t reserved_4[8];
+	struct vf_id    id;
+	uint16_t reserved_4;
+	struct vf_hopct  hopct;
+	uint8_t reserved_5;
 };
 
 #define VP_RPT_ID_IOCB_TYPE	0x32	/* Report ID Acquisition entry.
*/
@@ -1054,5 +1096,30 @@ struct vp_rpt_id_entry_24xx {
 	uint8_t reserved_4[32];
 };
 
+#define VF_EVFP_IOCB_TYPE       0x26    /* Exchange Virtual Fabric
Parameters entry. */
+struct vf_evfp_entry_24xx {
+        uint8_t entry_type;             /* Entry type. */
+        uint8_t entry_count;            /* Entry count. */
+        uint8_t sys_define;             /* System defined. */
+        uint8_t entry_status;           /* Entry Status. */
+
+        uint32_t handle;                /* System handle. */
+        uint16_t comp_status;           /* Completion status. */
+        uint16_t timeout;               /* timeout */
+        uint16_t adim_tagging_mode;
+
+        uint16_t vfport_id;
+        uint32_t exch_addr;
+
+        uint16_t nport_handle;          /* N_PORT handle. */
+        uint16_t control_flags;
+        uint32_t io_parameter_0;
+        uint32_t io_parameter_1;
+        uint32_t tx_address[2];         /* Data segment 0 address. */
+        uint32_t tx_len;                /* Data segment 0 length. */
+        uint32_t rx_address[2];         /* Data segment 1 address. */
+        uint32_t rx_len;                /* Data segment 1 length. */
+};
+
 /* END MID Support
***********************************************************/
 #endif
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h
b/drivers/scsi/qla2xxx/qla_gbl.h
index 74544ae..b44eff2 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -62,6 +62,38 @@ extern int ql2xfdmienable;
 extern int ql2xallocfwdump;
 extern int ql2xextended_error_logging;
 extern int ql2xqfullrampup;
+extern int num_hosts;
+
+/*
+ * Global Functions in qla_mid.c source file.
+ */
+extern struct scsi_host_template qla2x00_driver_template;
+extern struct scsi_host_template qla24xx_driver_template;
+extern struct scsi_transport_template
*qla2xxx_transport_vport_template;
+extern uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+extern void qla2x00_timer(scsi_qla_host_t *);
+extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned
long);
+extern void qla2x00_stop_timer(scsi_qla_host_t *);
+extern uint32_t qla24xx_allocate_vp_id(scsi_qla_host_t *);
+extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *);
+extern int qla24xx_disable_vp (scsi_qla_host_t *);
+extern int qla24xx_enable_vp (scsi_qla_host_t *);
+extern void qla2x00_mem_free(scsi_qla_host_t *);
+extern int qla24xx_control_vp(scsi_qla_host_t *, int );
+extern int qla24xx_modify_vp_config(scsi_qla_host_t *);
+extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t,
uint16_t);
+extern void qla2x00_vp_stop_timer(scsi_qla_host_t *);
+extern int qla24xx_configure_vhba (scsi_qla_host_t *);
+extern int qla24xx_get_vp_entry(scsi_qla_host_t *, uint16_t, int);
+extern int qla24xx_get_vp_database(scsi_qla_host_t *, uint16_t);
+extern int qla2x00_do_dpc_vp(scsi_qla_host_t *);
+extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
+    struct vp_rpt_id_entry_24xx *);
+extern scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *,
+    uint8_t *);
+extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
+extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
+extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *);
 
 extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
 
@@ -77,6 +109,10 @@ extern struct fw_blob
*qla2x00_request_firmware(scsi_qla_host_t *);
 extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);
 
 extern void qla2xxx_wake_dpc(scsi_qla_host_t *);
+extern void qla2x00_alert_all_vps(scsi_qla_host_t *, uint16_t *);
+extern void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
+extern void qla2x00_vp_abort_isp(scsi_qla_host_t *);
+extern int qla24xx_vport_delete(struct fc_vport *);
 
 /*
  * Global Function Prototypes in qla_iocb.c source file.
@@ -128,7 +164,7 @@ qla2x00_abort_target(fc_port_t *);
 
 extern int
 qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *,
uint8_t *,
-    uint8_t *, uint16_t *);
+    uint8_t *, uint16_t *, uint16_t *);
 
 extern int
 qla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *, uint16_t
*);
@@ -303,6 +339,7 @@ struct class_device_attribute;
 extern struct class_device_attribute *qla2x00_host_attrs[];
 struct fc_function_template;
 extern struct fc_function_template qla2xxx_transport_functions;
+extern struct fc_function_template qla2xxx_transport_vport_functions;
 extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
 extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
 extern void qla2x00_init_host_attr(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c
b/drivers/scsi/qla2xxx/qla_gs.c
index ec5b2dd..a086b3f 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -88,6 +88,7 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *ha, uint32_t
req_size, uint32_t rsp_size)
 	ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
 	ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
 	ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+	ct_pkt->vp_index = ha->vp_idx;
 
 	return (ct_pkt);
 }
@@ -1186,6 +1187,7 @@ qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *ha,
uint32_t req_size,
 	ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
 	ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
 	ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+	ct_pkt->vp_index = ha->vp_idx;
 
 	return ct_pkt;
 }
@@ -1746,6 +1748,7 @@ qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha,
uint32_t req_size,
 	ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
 	ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
 	ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+	ct_pkt->vp_index = ha->vp_idx;
 
 	return ct_pkt;
 }
diff --git a/drivers/scsi/qla2xxx/qla_init.c
b/drivers/scsi/qla2xxx/qla_init.c
index 2a45aec..847066b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -899,6 +899,10 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
 				    &ha->fw_subminor_version,
 				    &ha->fw_attributes,
&ha->fw_memory_size);
 				qla2x00_resize_request_q(ha);
+				ha->flags.npiv_supported = 0;
+				if (IS_QLA24XX(ha) &&
+				    (ha->fw_attributes & BIT_2))
+					ha->flags.npiv_supported = 1;
 
 				if (ql2xallocfwdump)
 					qla2x00_alloc_fw_dump(ha);
@@ -1101,6 +1105,8 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
 	int	rval;
 	unsigned long flags = 0;
 	int cnt;
+	struct mid_init_cb_24xx *mid_init_cb =
+	    (struct mid_init_cb_24xx *) ha->init_cb;
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
@@ -1132,6 +1138,10 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
 	ha->isp_ops.update_fw_options(ha);
 
 	DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
+
+	mid_init_cb->count = MAX_NUM_VPORT_FABRIC;
+	ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC;
+
 	rval = qla2x00_init_firmware(ha, ha->init_cb_size);
 	if (rval) {
 		DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED
****.\n",
@@ -1263,6 +1273,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
 	int       rval;
 	uint16_t      loop_id;
 	uint16_t      topo;
+	uint16_t      sw_cap;
 	uint8_t       al_pa;
 	uint8_t       area;
 	uint8_t       domain;
@@ -1270,7 +1281,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
 
 	/* Get host addresses. */
 	rval = qla2x00_get_adapter_id(ha,
-	    &loop_id, &al_pa, &area, &domain, &topo);
+	    &loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
 	if (rval != QLA_SUCCESS) {
 		if (LOOP_TRANSITION(ha) ||
atomic_read(&ha->loop_down_timer) ||
 		    (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
@@ -1295,6 +1306,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
 	/* initialize */
 	ha->min_external_loopid = SNS_FIRST_LOOP_ID;
 	ha->operating_mode = LOOP;
+	ha->switch_cap = 0;
 
 	switch (topo) {
 	case 0:
@@ -1307,6 +1319,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
 	case 1:
 		DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
 		    ha->host_no));
+		ha->switch_cap = sw_cap;
 		ha->current_topology = ISP_CFG_FL;
 		strcpy(connect_type, "(FL_Port)");
 		break;
@@ -1322,6 +1335,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
 	case 3:
 		DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
 		    ha->host_no));
+		ha->switch_cap = sw_cap;
 		ha->operating_mode = P2P;
 		ha->current_topology = ISP_CFG_F;
 		strcpy(connect_type, "(F_Port)");
@@ -1743,7 +1757,6 @@ qla2x00_rport_del(void *data)
 	spin_unlock_irqrestore(&fcport->rport_lock, flags);
 	if (rport)
 		fc_remote_port_delete(rport);
-
 }
 
 /**
@@ -1765,6 +1778,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t
flags)
 	/* Setup fcport template structure. */
 	memset(fcport, 0, sizeof (fc_port_t));
 	fcport->ha = ha;
+	fcport->vp_idx = ha->vp_idx;
 	fcport->port_type = FCT_UNKNOWN;
 	fcport->loop_id = FC_NO_LOOP_ID;
 	atomic_set(&fcport->state, FCS_UNCONFIGURED);
@@ -1911,6 +1925,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
 	char		*id_iter;
 	uint16_t	loop_id;
 	uint8_t		domain, area, al_pa;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	found_devs = 0;
 	new_fcport = NULL;
@@ -1942,7 +1957,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
 	/*
 	 * Mark local devices that were present with FCF_DEVICE_LOST for
now.
 	 */
-	list_for_each_entry(fcport, &ha->fcports, list) {
+	list_for_each_entry(fcport, &pha->fcports, list) {
+		if (fcport->vp_idx != ha->vp_idx)
+			continue;
+
 		if (atomic_read(&fcport->state) == FCS_ONLINE &&
 		    fcport->port_type != FCT_BROADCAST &&
 		    (fcport->flags & FCF_FABRIC_DEVICE) == 0) {
@@ -1988,6 +2006,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
 		new_fcport->d_id.b.area = area;
 		new_fcport->d_id.b.al_pa = al_pa;
 		new_fcport->loop_id = loop_id;
+		new_fcport->vp_idx = ha->vp_idx;
 		rval2 = qla2x00_get_port_database(ha, new_fcport, 0);
 		if (rval2 != QLA_SUCCESS) {
 			DEBUG2(printk("scsi(%ld): Failed to retrieve
fcport "
@@ -2003,7 +2022,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
 		/* Check for matching device in port list. */
 		found = 0;
 		fcport = NULL;
-		list_for_each_entry(fcport, &ha->fcports, list) {
+		list_for_each_entry(fcport, &pha->fcports, list) {
+			if (fcport->vp_idx != ha->vp_idx)
+				continue;
+
 			if (memcmp(new_fcport->port_name,
fcport->port_name,
 			    WWN_SIZE))
 				continue;
@@ -2023,7 +2045,13 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
 		if (!found) {
 			/* New device, add to fcports list. */
 			new_fcport->flags &= ~FCF_PERSISTENT_BOUND;
-			list_add_tail(&new_fcport->list, &ha->fcports);
+			if (ha->parent) {
+				new_fcport->ha = ha;
+				new_fcport->vp_idx = ha->vp_idx;
+				list_add_tail(&new_fcport->vp_fcport,
+				    &ha->vp_fcports);
+			}
+			list_add_tail(&new_fcport->list, &pha->fcports);
 
 			/* Allocate a new replacement fcport. */
 			fcport = new_fcport;
@@ -2199,11 +2227,13 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha,
fc_port_t *fcport)
 void
 qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
+	scsi_qla_host_t *pha = to_qla_parent(ha);
+
 	fcport->ha = ha;
 	fcport->login_retry = 0;
-	fcport->port_login_retry_count = ha->port_down_retry_count *
+	fcport->port_login_retry_count = pha->port_down_retry_count *
 	    PORT_RETRY_TIME;
-	atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
+	atomic_set(&fcport->port_down_timer, pha->port_down_retry_count
*
 	    PORT_RETRY_TIME);
 	fcport->flags &= ~FCF_LOGIN_NEEDED;
 
@@ -2234,6 +2264,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
 	uint16_t	mb[MAILBOX_REGISTER_COUNT];
 	uint16_t	loop_id;
 	LIST_HEAD(new_fcports);
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	/* If FL port exists, then SNS is present */
 	if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
@@ -2307,7 +2338,10 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
 		 * Logout all previous fabric devices marked lost,
except
 		 * tape devices.
 		 */
-		list_for_each_entry(fcport, &ha->fcports, list) {
+		list_for_each_entry(fcport, &pha->fcports, list) {
+			if (fcport->vp_idx !=ha->vp_idx)
+				continue;
+
 			if (test_bit(LOOP_RESYNC_NEEDED,
&ha->dpc_flags))
 				break;
 
@@ -2332,13 +2366,16 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
 		}
 
 		/* Starting free loop ID. */
-		next_loopid = ha->min_external_loopid;
+		next_loopid = pha->min_external_loopid;
 
 		/*
 		 * Scan through our port list and login entries that
need to be
 		 * logged in.
 		 */
-		list_for_each_entry(fcport, &ha->fcports, list) {
+		list_for_each_entry(fcport, &pha->fcports, list) {
+			if (fcport->vp_idx != ha->vp_idx)
+				continue;
+
 			if (atomic_read(&ha->loop_down_timer) ||
 			    test_bit(LOOP_RESYNC_NEEDED,
&ha->dpc_flags))
 				break;
@@ -2380,11 +2417,18 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
 				break;
 			}
 
-			/* Remove device from the new list and add it to
DB */
-			list_move_tail(&fcport->list, &ha->fcports);
-
 			/* Login and update database */
 			qla2x00_fabric_dev_login(ha, fcport,
&next_loopid);
+
+			if (ha->parent) {
+				fcport->ha = ha;
+				fcport->vp_idx = ha->vp_idx;
+				list_add_tail(&fcport->vp_fcport,
+				    &ha->vp_fcports);
+				list_move_tail(&fcport->list,
+				    &ha->parent->fcports);
+			} else
+				list_move_tail(&fcport->list,
&ha->fcports);
 		}
 	} while (0);
 
@@ -2428,6 +2472,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha,
struct list_head *new_fcports)
 	int		swl_idx;
 	int		first_dev, last_dev;
 	port_id_t	wrap, nxt_d_id;
+	int 		vp_index;
+	int		empty_vp_index;
+	int		found_vp;
+	scsi_qla_host_t *vha;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	rval = QLA_SUCCESS;
 
@@ -2461,13 +2510,13 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t
*ha, struct list_head *new_fcports)
 		return (QLA_MEMORY_ALLOC_FAILED);
 	}
 	new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
-
+	new_fcport->vp_idx = ha->vp_idx;
 	/* Set start port ID scan at adapter ID. */
 	first_dev = 1;
 	last_dev = 0;
 
 	/* Starting free loop ID. */
-	loop_id = ha->min_external_loopid;
+	loop_id = pha->min_external_loopid;
 	for (; loop_id <= ha->last_loop_id; loop_id++) {
 		if (qla2x00_is_reserved_id(ha, loop_id))
 			continue;
@@ -2521,9 +2570,41 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha,
struct list_head *new_fcports)
 			break;
 		}
 
-		/* Bypass if host adapter. */
-		if (new_fcport->d_id.b24 == ha->d_id.b24)
-			continue;
+		/* Bypass if same physical adapter. */
+		if (new_fcport->d_id.b24 == pha->d_id.b24)
+ 			continue;
+
+		/* Bypass virtual ports of the same host. */
+		if (pha->num_vhosts) {
+			vp_index = find_next_bit(
+			    (unsigned long *)pha->vp_idx_map,
+			    MAX_MULTI_ID_FABRIC + 1, 1);
+
+			for (;vp_index <= MAX_MULTI_ID_FABRIC;
+			    vp_index = find_next_bit(
+			    (unsigned long *)pha->vp_idx_map,
+			    MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) {
+				empty_vp_index = 1;
+				found_vp = 0;
+				list_for_each_entry(vha, &pha->vp_list,
+				    vp_list) {
+					if (vp_index == vha->vp_idx) {
+						empty_vp_index = 0;
+						found_vp = 1;
+						break;
+					}
+				}
+
+				if (empty_vp_index)
+					continue;
+
+				if (found_vp &&
+				    new_fcport->d_id.b24 ==
vha->d_id.b24)
+					break;
+			}
+			if (vp_index <= MAX_MULTI_ID_FABRIC)
+				continue;
+		}
 
 		/* Bypass if same domain and area of adapter. */
 		if (((new_fcport->d_id.b24 & 0xffff00) ==
@@ -2537,7 +2618,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha,
struct list_head *new_fcports)
 
 		/* Locate matching device in database. */
 		found = 0;
-		list_for_each_entry(fcport, &ha->fcports, list) {
+		list_for_each_entry(fcport, &pha->fcports, list) {
+			if (new_fcport->vp_idx != fcport->vp_idx)
+				continue;
 			if (memcmp(new_fcport->port_name,
fcport->port_name,
 			    WWN_SIZE))
 				continue;
@@ -2605,6 +2688,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha,
struct list_head *new_fcports)
 		}
 		new_fcport->flags |= (FCF_FABRIC_DEVICE |
FCF_LOGIN_NEEDED);
 		new_fcport->d_id.b24 = nxt_d_id.b24;
+		new_fcport->vp_idx = ha->vp_idx;
 	}
 
 	kfree(swl);
@@ -2637,6 +2721,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *ha,
fc_port_t *dev)
 	int	found;
 	fc_port_t *fcport;
 	uint16_t first_loop_id;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	rval = QLA_SUCCESS;
 
@@ -2663,7 +2748,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *ha,
fc_port_t *dev)
 		/* Check for loop ID being already in use. */
 		found = 0;
 		fcport = NULL;
-		list_for_each_entry(fcport, &ha->fcports, list) {
+		list_for_each_entry(fcport, &pha->fcports, list) {
 			if (fcport->loop_id == dev->loop_id && fcport !=
dev) {
 				/* ID possibly in use */
 				found++;
@@ -2710,6 +2795,7 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
 	uint8_t rscn_out_iter;
 	uint8_t format;
 	port_id_t d_id;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	rval = QLA_RSCNS_HANDLED;
 
@@ -2776,7 +2862,10 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
 
 		rval = QLA_SUCCESS;
 
-		list_for_each_entry(fcport, &ha->fcports, list) {
+		list_for_each_entry(fcport, &pha->fcports, list) {
+			if (fcport->vp_idx != ha->vp_idx)
+				continue;
+
 			if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
 			    (fcport->d_id.b24 & mask) != d_id.b24 ||
 			    fcport->port_type == FCT_BROADCAST)
@@ -3940,3 +4029,40 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
 		ret = qla2x00_stop_firmware(ha);
 	}
 }
+
+int
+qla24xx_configure_vhba(scsi_qla_host_t *ha)
+{
+	int rval = QLA_SUCCESS;
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+	if (!ha->parent)
+		return -EINVAL;
+
+	rval = qla2x00_fw_ready(ha);
+	if (rval == QLA_SUCCESS) {
+		clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+		qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
+	}
+
+	ha->flags.management_server_logged_in = 0;
+
+	/* Login to SNS first */
+	qla24xx_login_fabric(ha, NPH_SNS, 0xff, 0xff, 0xfc,
+	    mb, BIT_1);
+	if (mb[0] != MBS_COMMAND_COMPLETE) {
+		DEBUG15(qla_printk(KERN_INFO, ha,
+		    "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
+		    "mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
+		    mb[0], mb[1], mb[2], mb[6], mb[7]));
+		return (QLA_FUNCTION_FAILED);
+	}
+
+	atomic_set(&ha->loop_down_timer, 0);
+	atomic_set(&ha->loop_state, LOOP_UP);
+	set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+	set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+	rval = qla2x00_loop_resync(ha);
+
+	return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c
b/drivers/scsi/qla2xxx/qla_iocb.c
index c517a14..c71863f 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -179,7 +179,6 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp,
cmd_entry_t *cmd_pkt,
 	cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
 
 	/* Load data segments */
-
 	scsi_for_each_sg(cmd, sg, tot_dsds, i) {
 		cont_entry_t *cont_pkt;
 
@@ -316,9 +315,14 @@ qla2x00_start_scsi(srb_t *sp)
 		goto queuing_error;
 
 	/* Map the sg table so we have an accurate count of sg entries
needed */
-	nseg = scsi_dma_map(cmd);
-	if (nseg < 0)
-		goto queuing_error;
+	if (scsi_sg_count(cmd)) {
+		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
+		    scsi_sg_count(cmd), cmd->sc_data_direction);
+		if (unlikely(!nseg))
+			goto queuing_error;
+	} else
+		nseg = 0;
+
 	tot_dsds = nseg;
 
 	/* Calculate the number of request entries needed. */
@@ -414,9 +418,10 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t
loop_id, uint16_t lun,
 {
 	mrk_entry_t *mrk;
 	struct mrk_entry_24xx *mrk24;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	mrk24 = NULL;
-	mrk = (mrk_entry_t *)qla2x00_req_pkt(ha);
+	mrk = (mrk_entry_t *)qla2x00_req_pkt(pha);
 	if (mrk == NULL) {
 		DEBUG2_3(printk("%s(%ld): failed to allocate Marker
IOCB.\n",
 		    __func__, ha->host_no));
@@ -433,6 +438,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t
loop_id, uint16_t lun,
 			mrk24->lun[1] = LSB(lun);
 			mrk24->lun[2] = MSB(lun);
 			host_to_fcp_swap(mrk24->lun,
sizeof(mrk24->lun));
+			mrk24->vp_index = ha->vp_idx;
 		} else {
 			SET_TARGET_ID(ha, mrk->target, loop_id);
 			mrk->lun = cpu_to_le16(lun);
@@ -440,7 +446,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t
loop_id, uint16_t lun,
 	}
 	wmb();
 
-	qla2x00_isp_cmd(ha);
+	qla2x00_isp_cmd(pha);
 
 	return (QLA_SUCCESS);
 }
@@ -712,9 +718,14 @@ qla24xx_start_scsi(srb_t *sp)
 		goto queuing_error;
 
 	/* Map the sg table so we have an accurate count of sg entries
needed */
-	nseg = scsi_dma_map(cmd);
-	if (nseg < 0)
+	if (scsi_sg_count(cmd)) {
+		nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
+		    scsi_sg_count(cmd), cmd->sc_data_direction);
+		if (unlikely(!nseg))
 			goto queuing_error;
+	} else
+		nseg = 0;
+
 	tot_dsds = nseg;
 
 	req_cnt = qla24xx_calc_iocbs(tot_dsds);
@@ -750,6 +761,7 @@ qla24xx_start_scsi(srb_t *sp)
 	cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
 	cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
 	cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+	cmd_pkt->vp_index = sp->fcport->vp_idx;
 
 	int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
 	host_to_fcp_swap((uint8_t *)&cmd_pkt->lun,
sizeof(cmd_pkt->lun));
diff --git a/drivers/scsi/qla2xxx/qla_isr.c
b/drivers/scsi/qla2xxx/qla_isr.c
index 6ce532c..0ba4c8d 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -9,7 +9,6 @@
 #include <scsi/scsi_tcq.h>
 
 static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
-static void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
 static void qla2x00_process_completed_request(struct scsi_qla_host *,
uint32_t);
 static void qla2x00_status_entry(scsi_qla_host_t *, void *);
 static void qla2x00_status_cont_entry(scsi_qla_host_t *,
sts_cont_entry_t *);
@@ -244,7 +243,7 @@ qla2x00_mbx_completion(scsi_qla_host_t *ha, uint16_t
mb0)
  * @ha: SCSI driver HA context
  * @mb: Mailbox registers (0 - 3)
  */
-static void
+void
 qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
 {
 #define LS_UNKNOWN	2
@@ -386,6 +385,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t
*mb)
 			qla2x00_mark_all_devices_lost(ha, 1);
 		}
 
+		if (ha->parent) {
+			atomic_set(&ha->vp_state, VP_FAILED);
+			fc_vport_set_state(ha->fc_vport,
FC_VPORT_FAILED);
+		}
+
 		set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
 
 		ha->flags.management_server_logged_in = 0;
@@ -422,6 +426,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t
*mb)
 			qla2x00_mark_all_devices_lost(ha, 1);
 		}
 
+		if (ha->parent) {
+			atomic_set(&ha->vp_state, VP_FAILED);
+			fc_vport_set_state(ha->fc_vport,
FC_VPORT_FAILED);
+		}
+
 		ha->flags.management_server_logged_in = 0;
 		ha->link_data_rate = PORT_SPEED_UNKNOWN;
 		if (ql2xfdmienable)
@@ -440,6 +449,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t
*mb)
 			qla2x00_mark_all_devices_lost(ha, 1);
 		}
 
+		if (ha->parent) {
+			atomic_set(&ha->vp_state, VP_FAILED);
+			fc_vport_set_state(ha->fc_vport,
FC_VPORT_FAILED);
+		}
+
 		set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
 
 		ha->operating_mode = LOOP;
@@ -465,6 +479,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t
*mb)
 			qla2x00_mark_all_devices_lost(ha, 1);
 		}
 
+		if (ha->parent) {
+			atomic_set(&ha->vp_state, VP_FAILED);
+			fc_vport_set_state(ha->fc_vport,
FC_VPORT_FAILED);
+		}
+
 		if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) {
 			set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
 		}
@@ -491,6 +510,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t
*mb)
 			qla2x00_mark_all_devices_lost(ha, 1);
 		}
 
+		if (ha->parent) {
+			atomic_set(&ha->vp_state, VP_FAILED);
+			fc_vport_set_state(ha->fc_vport,
FC_VPORT_FAILED);
+		}
+
 		set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
 		set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
 		break;
@@ -530,6 +554,10 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t
*mb)
 		break;
 
 	case MBA_RSCN_UPDATE:		/* State Change Registration */
+		/* Check if the Vport has issued a SCR */
+		if (ha->parent && test_bit(VP_SCR_NEEDED,
&ha->vp_flags))
+			break;
+
 		DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
 		    ha->host_no));
 		DEBUG(printk(KERN_INFO
@@ -589,6 +617,9 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t
*mb)
 		ha->host_no, mb[1], mb[2]));
 		break;
 	}
+
+	if (!ha->parent && ha->num_vhosts)
+		qla2x00_alert_all_vps(ha, mb);
 }
 
 static void
@@ -1393,6 +1424,10 @@ qla24xx_process_response_queue(struct
scsi_qla_host *ha)
 		case MS_IOCB_TYPE:
 			qla24xx_ms_entry(ha, (struct ct_entry_24xx
*)pkt);
 			break;
+		case VP_RPT_ID_IOCB_TYPE:
+			qla24xx_report_id_acquisition(ha,
+			    (struct vp_rpt_id_entry_24xx *)pkt);
+			break;
 		default:
 			/* Type Not Supported. */
 			DEBUG4(printk(KERN_WARNING
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c
b/drivers/scsi/qla2xxx/qla_mbx.c
index 71e32a2..ee2ab85 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -42,25 +42,29 @@ qla2x00_mbx_sem_timeout(unsigned long data)
  *	Kernel context.
  */
 static int
-qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
+qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 {
 	int		rval;
 	unsigned long    flags = 0;
-	device_reg_t __iomem *reg = ha->iobase;
+	device_reg_t __iomem *reg;
 	struct timer_list	tmp_intr_timer;
 	uint8_t		abort_active;
-	uint8_t		io_lock_on = ha->flags.init_done;
+	uint8_t		io_lock_on;
 	uint16_t	command;
 	uint16_t	*iptr;
 	uint16_t __iomem *optr;
 	uint32_t	cnt;
 	uint32_t	mboxes;
 	unsigned long	wait_time;
+	scsi_qla_host_t *ha = to_qla_parent(pvha);
+
+	reg = ha->iobase;
+	io_lock_on = ha->flags.init_done;
 
 	rval = QLA_SUCCESS;
 	abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
 
-	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, pvha->host_no));
 
 	/*
 	 * Wait for active mailbox commands to finish by waiting at most
tov
@@ -889,7 +893,7 @@ qla2x00_abort_target(fc_port_t *fcport)
  */
 int
 qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t
*al_pa,
-    uint8_t *area, uint8_t *domain, uint16_t *top)
+    uint8_t *area, uint8_t *domain, uint16_t *top, uint16_t *sw_cap)
 {
 	int rval;
 	mbx_cmd_t mc;
@@ -899,8 +903,9 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t
*id, uint8_t *al_pa,
 	    ha->host_no));
 
 	mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
+	mcp->mb[9] = ha->vp_idx;
 	mcp->out_mb = MBX_0;
-	mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->tov = 30;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
@@ -913,6 +918,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t
*id, uint8_t *al_pa,
 	*area = MSB(mcp->mb[2]);
 	*domain	= LSB(mcp->mb[3]);
 	*top = mcp->mb[6];
+	*sw_cap = mcp->mb[7];
 
 	if (rval != QLA_SUCCESS) {
 		/*EMPTY*/
@@ -1009,7 +1015,11 @@ qla2x00_init_firmware(scsi_qla_host_t *ha,
uint16_t size)
 	DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
 	    ha->host_no));
 
-	mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
+	if (ha->flags.npiv_supported)
+		mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;
+	else
+		mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
+
 	mcp->mb[2] = MSW(ha->init_cb_dma);
 	mcp->mb[3] = LSW(ha->init_cb_dma);
 	mcp->mb[4] = 0;
@@ -1081,7 +1091,8 @@ qla2x00_get_port_database(scsi_qla_host_t *ha,
fc_port_t *fcport, uint8_t opt)
 	mcp->mb[3] = LSW(pd_dma);
 	mcp->mb[6] = MSW(MSD(pd_dma));
 	mcp->mb[7] = LSW(MSD(pd_dma));
-	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+	mcp->mb[9] = ha->vp_idx;
+	mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
 	mcp->in_mb = MBX_0;
 	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
 		mcp->mb[1] = fcport->loop_id;
@@ -1259,7 +1270,8 @@ qla2x00_get_port_name(scsi_qla_host_t *ha,
uint16_t loop_id, uint8_t *name,
 	    ha->host_no));
 
 	mcp->mb[0] = MBC_GET_PORT_NAME;
-	mcp->out_mb = MBX_1|MBX_0;
+	mcp->mb[9] = ha->vp_idx;
+	mcp->out_mb = MBX_9|MBX_1|MBX_0;
 	if (HAS_EXTENDED_IDS(ha)) {
 		mcp->mb[1] = loop_id;
 		mcp->mb[10] = opt;
@@ -1447,6 +1459,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t
loop_id, uint8_t domain,
 	lg->port_id[0] = al_pa;
 	lg->port_id[1] = area;
 	lg->port_id[2] = domain;
+	lg->vp_index = cpu_to_le16(ha->vp_idx);
 	rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
 	if (rval != QLA_SUCCESS) {
 		DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB
"
@@ -1701,6 +1714,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha,
uint16_t loop_id, uint8_t domain,
 	lg->port_id[0] = al_pa;
 	lg->port_id[1] = area;
 	lg->port_id[2] = domain;
+	lg->vp_index = cpu_to_le16(ha->vp_idx);
 	rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
 	if (rval != QLA_SUCCESS) {
 		DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB
"
@@ -1863,7 +1877,8 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void
*id_list, dma_addr_t id_list_dma,
 		mcp->mb[6] = MSW(MSD(id_list_dma));
 		mcp->mb[7] = LSW(MSD(id_list_dma));
 		mcp->mb[8] = 0;
-		mcp->out_mb |= MBX_8|MBX_7|MBX_6|MBX_3|MBX_2;
+		mcp->mb[9] = ha->vp_idx;
+		mcp->out_mb |= MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2;
 	} else {
 		mcp->mb[1] = MSW(id_list_dma);
 		mcp->mb[2] = LSW(id_list_dma);
@@ -2212,6 +2227,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t
*sp)
 	abt->port_id[0] = fcport->d_id.b.al_pa;
 	abt->port_id[1] = fcport->d_id.b.area;
 	abt->port_id[2] = fcport->d_id.b.domain;
+	abt->vp_index = fcport->vp_idx;
 	rval = qla2x00_issue_iocb(ha, abt, abt_dma, 0);
 	if (rval != QLA_SUCCESS) {
 		DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB
(%x).\n",
@@ -2249,7 +2265,7 @@ qla24xx_abort_target(fc_port_t *fcport)
 	int		rval;
 	struct tsk_mgmt_cmd *tsk;
 	dma_addr_t	tsk_dma;
-	scsi_qla_host_t *ha;
+	scsi_qla_host_t *ha, *pha;
 
 	if (fcport == NULL)
 		return 0;
@@ -2257,7 +2273,8 @@ qla24xx_abort_target(fc_port_t *fcport)
 	DEBUG11(printk("%s(%ld): entered.\n", __func__,
fcport->ha->host_no));
 
 	ha = fcport->ha;
-	tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma);
+	pha = to_qla_parent(ha);
+	tsk = dma_pool_alloc(pha->s_dma_pool, GFP_KERNEL, &tsk_dma);
 	if (tsk == NULL) {
 		DEBUG2_3(printk("%s(%ld): failed to allocate Task
Management "
 		    "IOCB.\n", __func__, ha->host_no));
@@ -2273,6 +2290,8 @@ qla24xx_abort_target(fc_port_t *fcport)
 	tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa;
 	tsk->p.tsk.port_id[1] = fcport->d_id.b.area;
 	tsk->p.tsk.port_id[2] = fcport->d_id.b.domain;
+	tsk->p.tsk.vp_index = fcport->vp_idx;
+
 	rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0);
 	if (rval != QLA_SUCCESS) {
 		DEBUG2_3_11(printk("%s(%ld): failed to issue Target
Reset IOCB "
@@ -2303,7 +2322,7 @@ qla24xx_abort_target(fc_port_t *fcport)
 	}
 
 atarget_done:
-	dma_pool_free(ha->s_dma_pool, tsk, tsk_dma);
+	dma_pool_free(pha->s_dma_pool, tsk, tsk_dma);
 
 	return rval;
 }
@@ -2610,3 +2629,354 @@ qla2x00_set_idma_speed(scsi_qla_host_t *ha,
uint16_t loop_id,
 
 	return rval;
 }
+
+/*
+ * qla24xx_get_vp_database
+ *	Get the VP's database for all configured ports.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	size = size of initialization control block.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla24xx_get_vp_database(scsi_qla_host_t *ha, uint16_t size)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("scsi(%ld):%s - entered.\n",
+	    ha->host_no, __func__));
+
+	mcp->mb[0] = MBC_MID_GET_VP_DATABASE;
+	mcp->mb[2] = MSW(ha->init_cb_dma);
+	mcp->mb[3] = LSW(ha->init_cb_dma);
+	mcp->mb[4] = 0;
+	mcp->mb[5] = 0;
+	mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
+	mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
+	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+	mcp->in_mb = MBX_1|MBX_0;
+	mcp->buf_size = size;
+	mcp->flags = MBX_DMA_OUT;
+	mcp->tov = MBX_TOV_SECONDS;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("%s(%ld): failed=%x "
+		    "mb0=%x.\n",
+		    __func__, ha->host_no, rval, mcp->mb[0]));
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("%s(%ld): done.\n",
+		    __func__, ha->host_no));
+	}
+
+	return rval;
+}
+
+int
+qla24xx_get_vp_entry(scsi_qla_host_t *ha, uint16_t size, int vp_id)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	mcp->mb[0] = MBC_MID_GET_VP_ENTRY;
+	mcp->mb[2] = MSW(ha->init_cb_dma);
+	mcp->mb[3] = LSW(ha->init_cb_dma);
+	mcp->mb[4] = 0;
+	mcp->mb[5] = 0;
+	mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
+	mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
+	mcp->mb[9] = vp_id;
+	mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->buf_size = size;
+	mcp->flags = MBX_DMA_OUT;
+	mcp->tov = 30;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla24xx_get_vp_entry(%ld): failed=%x
"
+		    "mb0=%x.\n",
+		    ha->host_no, rval, mcp->mb[0]));
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla24xx_get_vp_entry(%ld): done.\n",
+		    ha->host_no));
+	}
+
+	return rval;
+}
+
+void
+qla24xx_report_id_acquisition(scsi_qla_host_t *ha,
+	struct vp_rpt_id_entry_24xx *rptid_entry)
+{
+	uint8_t vp_idx;
+	scsi_qla_host_t *vha;
+
+	if (rptid_entry->entry_status != 0)
+		return;
+	if (rptid_entry->entry_status !=
__constant_cpu_to_le16(CS_COMPLETE))
+		return;
+
+	if (rptid_entry->format == 0) {
+		DEBUG15(printk("%s:format 0 : scsi(%ld) number of VPs
setup %d,"
+			" number of VPs acquired %d\n", __func__,
ha->host_no,
+			MSB(rptid_entry->vp_count),
LSB(rptid_entry->vp_count)));
+		DEBUG15(printk("%s primary port id %02x%02x%02x\n",
__func__,
+			rptid_entry->port_id[2],
rptid_entry->port_id[1],
+			rptid_entry->port_id[0]));
+	} else if (rptid_entry->format == 1) {
+		vp_idx = LSB(rptid_entry->vp_idx);
+		DEBUG15(printk("%s:format 1: scsi(%ld): VP[%d] enabled "
+		    "- status %d - "
+		    "with port id %02x%02x%02x\n",__func__,ha->host_no,
+		    vp_idx, MSB(rptid_entry->vp_idx),
+		    rptid_entry->port_id[2], rptid_entry->port_id[1],
+		    rptid_entry->port_id[0]));
+		if (vp_idx == 0)
+			return;
+
+		if (MSB(rptid_entry->vp_idx) == 1)
+			return;
+
+		list_for_each_entry(vha, &ha->vp_list, vp_list)
+			if (vp_idx == vha->vp_idx)
+				break;
+
+		if (!vha)
+			return;
+
+		vha->d_id.b.domain = rptid_entry->port_id[2];
+		vha->d_id.b.area =  rptid_entry->port_id[1];
+		vha->d_id.b.al_pa = rptid_entry->port_id[0];
+
+		/*
+		 * Cannot configure here as we are still sitting on the
+		 * response queue. Handle it in dpc context.
+		 */
+		set_bit(VP_IDX_ACQUIRED, &vha->vp_flags);
+	    	set_bit(VP_DPC_NEEDED, &ha->dpc_flags);
+
+		wake_up_process(ha->dpc_thread);
+	}
+}
+
+/*
+ * qla24xx_modify_vp_config
+ *	Change VP configuration for vha
+ *
+ * Input:
+ *	vha = adapter block pointer.
+ *
+ * Returns:
+ *	qla2xxx local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla24xx_modify_vp_config(scsi_qla_host_t *vha)
+{
+	int		rval;
+	struct vp_config_entry_24xx *vpmod;
+	dma_addr_t	vpmod_dma;
+	scsi_qla_host_t *pha;
+
+	/* This can be called by the parent */
+	pha = to_qla_parent(vha);
+
+	vpmod = dma_pool_alloc(pha->s_dma_pool, GFP_KERNEL, &vpmod_dma);
+	if (!vpmod) {
+		DEBUG2_3(printk("%s(%ld): failed to allocate Modify VP "
+		    "IOCB.\n", __func__, pha->host_no));
+		return QLA_MEMORY_ALLOC_FAILED;
+	}
+
+	memset(vpmod, 0, sizeof(struct vp_config_entry_24xx));
+	vpmod->entry_type = VP_CONFIG_IOCB_TYPE;
+	vpmod->entry_count = 1;
+	vpmod->command = VCT_COMMAND_MOD_ENABLE_VPS;
+	vpmod->vp_count = 1;
+	vpmod->vp_index1 = vha->vp_idx;
+	vpmod->options_idx1 = BIT_3|BIT_4|BIT_5;
+	memcpy(vpmod->node_name_idx1, vha->node_name, WWN_SIZE);
+	memcpy(vpmod->port_name_idx1, vha->port_name, WWN_SIZE);
+	vpmod->entry_count = 1;
+
+	rval = qla2x00_issue_iocb(pha, vpmod, vpmod_dma, 0);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed to issue VP config
IOCB"
+			"(%x).\n", __func__, pha->host_no, rval));
+	} else if (vpmod->comp_status != 0) {
+		DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+			"-- error status (%x).\n", __func__,
pha->host_no,
+			vpmod->comp_status));
+		rval = QLA_FUNCTION_FAILED;
+	} else if (vpmod->comp_status !=
__constant_cpu_to_le16(CS_COMPLETE)) {
+		DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+		    "-- completion status (%x).\n", __func__,
pha->host_no,
+		    le16_to_cpu(vpmod->comp_status)));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		/* EMPTY */
+		DEBUG11(printk("%s(%ld): done.\n", __func__,
pha->host_no));
+		fc_vport_set_state(vha->fc_vport,
FC_VPORT_INITIALIZING);
+	}
+	dma_pool_free(pha->s_dma_pool, vpmod, vpmod_dma);
+
+	return rval;
+}
+
+/*
+ * qla24xx_control_vp
+ *	Enable a virtual port for given host
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	vhba = virtual adapter (unused)
+ *	index = index number for enabled VP
+ *
+ * Returns:
+ *	qla2xxx local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
+{
+	int		rval;
+	int		map, pos;
+	struct vp_ctrl_entry_24xx   *vce;
+	dma_addr_t	vce_dma;
+	scsi_qla_host_t *ha = vha->parent;
+	int	vp_index = vha->vp_idx;
+
+	DEBUG11(printk("%s(%ld): entered. Enabling index %d\n",
__func__,
+	    ha->host_no, vp_index));
+
+	if (vp_index == 0 || vp_index >= MAX_MULTI_ID_LOOP)
+		return QLA_PARAMETER_ERROR;
+
+	vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma);
+	if (!vce) {
+		DEBUG2_3(printk("%s(%ld): "
+		    "failed to allocate VP Control IOCB.\n", __func__,
+		    ha->host_no));
+		return QLA_MEMORY_ALLOC_FAILED;
+	}
+	memset(vce, 0, sizeof(struct vp_ctrl_entry_24xx));
+
+	vce->entry_type = VP_CTRL_IOCB_TYPE;
+	vce->entry_count = 1;
+	vce->command = cpu_to_le16(cmd);
+	vce->vp_count = __constant_cpu_to_le16(1);
+
+	/* index map in firmware starts with 1; decrement index
+	 * this is ok as we never use index 0
+	 */
+	map = (vp_index - 1) / 8;
+	pos = (vp_index - 1) & 7;
+	down(&ha->vport_sem);
+	vce->vp_idx_map[map] |= 1 << pos;
+	up(&ha->vport_sem);
+
+	rval = qla2x00_issue_iocb(ha, vce, vce_dma, 0);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed to issue VP control
IOCB"
+		    "(%x).\n", __func__, ha->host_no, rval));
+		printk("%s(%ld): failed to issue VP control IOCB"
+		    "(%x).\n", __func__, ha->host_no, rval);
+	} else if (vce->entry_status != 0) {
+		DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+		    "-- error status (%x).\n", __func__, ha->host_no,
+		    vce->entry_status));
+		printk("%s(%ld): failed to complete IOCB "
+		    "-- error status (%x).\n", __func__, ha->host_no,
+		    vce->entry_status);
+		rval = QLA_FUNCTION_FAILED;
+	} else if (vce->comp_status !=
__constant_cpu_to_le16(CS_COMPLETE)) {
+		DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+		    "-- completion status (%x).\n", __func__,
ha->host_no,
+		    le16_to_cpu(vce->comp_status)));
+		printk("%s(%ld): failed to complete IOCB "
+		    "-- completion status (%x).\n", __func__,
ha->host_no,
+		    le16_to_cpu(vce->comp_status));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		DEBUG2(printk("%s(%ld): done.\n", __func__,
ha->host_no));
+	}
+
+	dma_pool_free(ha->s_dma_pool, vce, vce_dma);
+
+	return rval;
+}
+
+/*
+ * qla2x00_send_change_request
+ *	Receive or disable RSCN request from fabric controller
+ *
+ * Input:
+ *	ha = adapter block pointer
+ *	format = registration format:
+ *		0 - Reserved
+ *		1 - Fabric detected registration
+ *		2 - N_port detected registration
+ *		3 - Full registration
+ *		FF - clear registration
+ *	vp_idx = Virtual port index
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel Context
+ */
+
+int
+qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format,
+			    uint16_t vp_idx)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	/*
+	 * This command is implicitly executed by firmware during login
for the
+	 * physical hosts
+	 */
+	if (vp_idx == 0)
+		return QLA_FUNCTION_FAILED;
+
+	mcp->mb[0] = MBC_SEND_CHANGE_REQUEST;
+	mcp->mb[1] = format;
+	mcp->mb[9] = vp_idx;
+	mcp->out_mb = MBX_9|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0|MBX_1;
+	mcp->tov = MBX_TOV_SECONDS;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval == QLA_SUCCESS) {
+		if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
+			rval = BIT_1;
+		}
+	} else
+		rval = BIT_1;
+
+	return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c
b/drivers/scsi/qla2xxx/qla_mid.c
new file mode 100644
index 0000000..8e0c57b
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -0,0 +1,497 @@
+/*
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2005 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
it
+ * under the terms of the GNU General Public License as published by
the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+#include "qla_def.h"
+
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/list.h>
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsicam.h>
+#include <linux/delay.h>
+
+void qla2x00_vp_stop_timer(scsi_qla_host_t *);
+
+void
+qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
+{
+	if (vha->parent && vha->timer_active) {
+		del_timer_sync(&vha->timer);
+		vha->timer_active = 0;
+	}
+}
+
+uint32_t
+qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
+{
+	uint32_t vp_id;
+	scsi_qla_host_t *ha = vha->parent;
+
+	/* Find an empty slot and assign an vp_id */
+	down(&ha->vport_sem);
+	vp_id = find_first_zero_bit((unsigned long *)ha->vp_idx_map,
+				MAX_MULTI_ID_FABRIC);
+	if (vp_id > MAX_MULTI_ID_FABRIC) {
+		DEBUG15(printk ("vp_id %d is bigger than
MAX_MULTI_ID_FABRID\n",
+		    vp_id));
+		up(&ha->vport_sem);
+		return vp_id;
+	}
+
+	set_bit(vp_id, (unsigned long *)ha->vp_idx_map);
+	ha->num_vhosts++;
+	vha->vp_idx = vp_id;
+	list_add_tail(&vha->vp_list, &ha->vp_list);
+	up(&ha->vport_sem);
+	return vp_id;
+}
+
+void
+qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
+{
+	uint16_t vp_id;
+	scsi_qla_host_t *ha = vha->parent;
+
+	down(&ha->vport_sem);
+	vp_id = vha->vp_idx;
+	ha->num_vhosts--;
+	clear_bit(vp_id, (unsigned long *)ha->vp_idx_map);
+	list_del(&vha->vp_list);
+	up(&ha->vport_sem);
+}
+
+scsi_qla_host_t *
+qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
+{
+	scsi_qla_host_t *vha;
+
+	/* Locate matching device in database. */
+	list_for_each_entry(vha, &ha->vp_list, vp_list) {
+		if (!memcmp(port_name, vha->port_name, WWN_SIZE))
+			return vha;
+	}
+	return NULL;
+}
+
+/*
+ * qla2x00_mark_vp_devices_dead
+ *	Updates fcport state when device goes offline.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	fcport = port structure pointer.
+ *
+ * Return:
+ *	None.
+ *
+ * Context:
+ */
+void
+qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
+{
+	fc_port_t *fcport;
+	scsi_qla_host_t *pha = to_qla_parent(vha);
+
+	list_for_each_entry(fcport, &pha->fcports, list) {
+		if (fcport->vp_idx != vha->vp_idx)
+			continue;
+
+		DEBUG15(printk("scsi(%ld): Marking port dead, "
+		    "loop_id=0x%04x :%x\n",
+		    vha->host_no, fcport->loop_id, fcport->vp_idx));
+
+		atomic_set(&fcport->state, FCS_DEVICE_DEAD);
+		qla2x00_mark_device_lost(vha, fcport, 0, 0);
+	}
+}
+
+int
+qla24xx_disable_vp(scsi_qla_host_t *vha)
+{
+	int ret;
+
+	ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
+	atomic_set(&vha->loop_state, LOOP_DOWN);
+	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+
+	/* Delete all vp's fcports from parent's list */
+	qla2x00_mark_vp_devices_dead(vha);
+	atomic_set(&vha->vp_state, VP_FAILED);
+	vha->flags.management_server_logged_in = 0;
+	if (ret == QLA_SUCCESS) {
+		fc_vport_set_state(vha->fc_vport, FC_VPORT_DISABLED);
+	} else {
+		fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
+		return -1;
+	}
+	return 0;
+}
+
+int
+qla24xx_enable_vp(scsi_qla_host_t *vha)
+{
+	int ret;
+	scsi_qla_host_t *ha = vha->parent;
+
+	/* Check if physical ha port is Up */
+	if (atomic_read(&ha->loop_state) == LOOP_DOWN  ||
+		atomic_read(&ha->loop_state) == LOOP_DEAD ) {
+		vha->vp_err_state =  VP_ERR_PORTDWN;
+		fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN);
+		goto enable_failed;
+	}
+
+	/* Initialize the new vport unless it is a persistent port */
+	down(&ha->vport_sem);
+	ret = qla24xx_modify_vp_config(vha);
+	up(&ha->vport_sem);
+
+	if (ret != QLA_SUCCESS) {
+		fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
+		goto enable_failed;
+	}
+
+	DEBUG15(qla_printk(KERN_INFO, ha,
+	    "Virtual port with id: %d - Enabled\n", vha->vp_idx));
+	return 0;
+
+enable_failed:
+	DEBUG15(qla_printk(KERN_INFO, ha,
+	    "Virtual port with id: %d - Disabled\n", vha->vp_idx));
+	return 1;
+}
+
+/**
+ * qla24xx_modify_vport() -  Modifies the virtual fabric port's
configuration
+ * @ha: HA context
+ * @vp: pointer to buffer of virtual port parameters.
+ * @ret_code: return error code:
+ *
+ * Returns the virtual port id, or MAX_VSAN_ID, if couldn't create.
+ */
+uint32_t
+qla24xx_modify_vhba(scsi_qla_host_t *ha, vport_params_t *vp, uint32_t
*vp_id)
+{
+	scsi_qla_host_t *vha;
+
+	vha = qla24xx_find_vhost_by_name(ha, vp->port_name);
+	if (!vha) {
+		*vp_id = MAX_NUM_VPORT_LOOP;
+		return VP_RET_CODE_WWPN;
+	}
+
+	if (qla24xx_enable_vp(vha)) {
+		scsi_host_put(vha->host);
+		qla2x00_mem_free(vha);
+		*vp_id = MAX_NUM_VPORT_LOOP;
+		return VP_RET_CODE_RESOURCES;
+	}
+
+	*vp_id = vha->vp_idx;
+	return VP_RET_CODE_OK;
+}
+
+void
+qla24xx_configure_vp(scsi_qla_host_t *vha)
+{
+	struct fc_vport *fc_vport;
+	int ret;
+
+	fc_vport = vha->fc_vport;
+
+	DEBUG15(printk("scsi(%ld): %s: change request #3 for this
host.\n",
+	    vha->host_no, __func__));
+	ret = qla2x00_send_change_request(vha, 0x3, vha->vp_idx);
+	if (ret != QLA_SUCCESS) {
+		DEBUG15(qla_printk(KERN_ERR, vha, "Failed to enable
receiving"
+		    " of RSCN requests: 0x%x\n", ret));
+		return;
+	} else {
+		/* Corresponds to SCR enabled */
+		clear_bit(VP_SCR_NEEDED, &vha->vp_flags);
+	}
+
+	vha->flags.online = 1;
+	if (qla24xx_configure_vhba(vha))
+		return;
+
+	atomic_set(&vha->vp_state, VP_ACTIVE);
+	fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
+}
+
+void
+qla2x00_alert_all_vps(scsi_qla_host_t *ha, uint16_t *mb)
+{
+	int i, vp_idx_matched;
+	scsi_qla_host_t *vha;
+
+	if (ha->parent)
+		return;
+
+	i = find_next_bit((unsigned long *)ha->vp_idx_map,
+	    MAX_MULTI_ID_FABRIC + 1, 1);
+	for (;i <= MAX_MULTI_ID_FABRIC;
+	    i = find_next_bit((unsigned long *)ha->vp_idx_map,
+	    MAX_MULTI_ID_FABRIC + 1, i + 1)) {
+		vp_idx_matched = 0;
+
+		list_for_each_entry(vha, &ha->vp_list, vp_list) {
+			if (i == vha->vp_idx) {
+				vp_idx_matched = 1;
+				break;
+			}
+		}
+
+		if (vp_idx_matched) {
+			switch (mb[0]) {
+			case MBA_LIP_OCCURRED:
+			case MBA_LOOP_UP:
+			case MBA_LOOP_DOWN:
+			case MBA_LIP_RESET:
+			case MBA_POINT_TO_POINT:
+			case MBA_CHG_IN_CONNECTION:
+			case MBA_PORT_UPDATE:
+			case MBA_RSCN_UPDATE:
+				DEBUG15(printk("scsi(%ld)%s: Async_event
for"
+				    " VP[%d], mb = 0x%x, vha=%p\n",
+				    vha->host_no, __func__,i, *mb,
vha));
+				qla2x00_async_event(vha, mb);
+				break;
+			}
+		}
+	}
+}
+
+void
+qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
+{
+	/*
+	 * Physical port will do most of the abort and recovery work. We
can
+	 * just treat it as a loop down
+	 */
+	if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+		atomic_set(&vha->loop_state, LOOP_DOWN);
+		qla2x00_mark_all_devices_lost(vha, 0);
+	} else {
+		if (!atomic_read(&vha->loop_down_timer))
+			atomic_set(&vha->loop_down_timer,
LOOP_DOWN_TIME);
+	}
+
+	DEBUG15(printk("scsi(%ld): Scheduling enable of Vport %d...\n",
+	    vha->host_no, vha->vp_idx));
+	qla24xx_enable_vp(vha);
+}
+
+int
+qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
+{
+	if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
+		/* VP acquired. complete port configuration */
+		qla24xx_configure_vp(vha);
+		return 0;
+	}
+
+	if (test_and_clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
+		qla2x00_vp_abort_isp(vha);
+
+	if (test_and_clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) &&
+	    (!(test_and_set_bit(RESET_ACTIVE, &vha->dpc_flags)))) {
+		clear_bit(RESET_ACTIVE, &vha->dpc_flags);
+	}
+
+	if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
+		if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
&vha->dpc_flags))) {
+			qla2x00_loop_resync(vha);
+			clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
+		}
+	}
+
+	return 0;
+}
+
+void
+qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
+{
+	int ret;
+	int i, vp_idx_matched;
+	scsi_qla_host_t *vha;
+
+	if (ha->parent)
+		return;
+	if (list_empty(&ha->vp_list))
+		return;
+
+	clear_bit(VP_DPC_NEEDED, &ha->dpc_flags);
+
+	i = find_next_bit((unsigned long *)ha->vp_idx_map,
+	    MAX_MULTI_ID_FABRIC + 1, 1);
+	for (;i <= MAX_MULTI_ID_FABRIC;
+	    i = find_next_bit((unsigned long *)ha->vp_idx_map,
+	    MAX_MULTI_ID_FABRIC + 1, i + 1)) {
+		vp_idx_matched = 0;
+
+		list_for_each_entry(vha, &ha->vp_list, vp_list) {
+			if (i == vha->vp_idx) {
+				vp_idx_matched = 1;
+				break;
+			}
+		}
+
+		if (vp_idx_matched)
+			ret = qla2x00_do_dpc_vp(vha);
+	}
+}
+
+int
+qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
+{
+	scsi_qla_host_t *ha = (scsi_qla_host_t *)
fc_vport->shost->hostdata;
+	scsi_qla_host_t *vha;
+	uint8_t port_name[WWN_SIZE];
+
+	if (fc_vport->roles != FC_PORT_ROLE_FCP_INITIATOR)
+		return VPCERR_UNSUPPORTED;
+
+	/* Check up the F/W and H/W support NPIV */
+	if (!ha->flags.npiv_supported)
+		return VPCERR_UNSUPPORTED;
+
+	/* Check up whether npiv supported switch presented */
+	if (!(ha->switch_cap & FLOGI_MID_SUPPORT))
+		return VPCERR_NO_FABRIC_SUPP;
+
+	/* Check up unique WWPN */
+	u64_to_wwn(fc_vport->port_name, port_name);
+	vha = qla24xx_find_vhost_by_name(ha, port_name);
+	if (vha)
+		return VPCERR_BAD_WWN;
+
+	/* Check up max-npiv-supports */
+	if (ha->num_vhosts > ha->max_npiv_vports) {
+		DEBUG15(printk("scsi(%ld): num_vhosts %d is bigger than
"
+		    "max_npv_vports %d.\n", ha->host_no,
+		    (uint16_t) ha->num_vhosts, (int)
ha->max_npiv_vports));
+		return VPCERR_UNSUPPORTED;
+	}
+	return 0;
+}
+
+scsi_qla_host_t *
+qla24xx_create_vhost(struct fc_vport *fc_vport)
+{
+	scsi_qla_host_t *ha = (scsi_qla_host_t *)
fc_vport->shost->hostdata;
+	scsi_qla_host_t *vha;
+	struct Scsi_Host *host;
+
+	host = scsi_host_alloc(&qla24xx_driver_template,
+	    sizeof(scsi_qla_host_t));
+	if (!host) {
+		printk(KERN_WARNING
+		    "qla2xxx: scsi_host_alloc() failed for vport\n");
+		return(NULL);
+	}
+
+	vha = (scsi_qla_host_t *)host->hostdata;
+
+	/* clone the parent hba */
+	memcpy(vha, ha, sizeof (scsi_qla_host_t));
+
+	fc_vport->dd_data = vha;
+
+	vha->node_name = kmalloc(WWN_SIZE * sizeof(char), GFP_KERNEL);
+	if (!vha->node_name)
+		goto create_vhost_failed_1;
+
+	vha->port_name = kmalloc(WWN_SIZE * sizeof(char), GFP_KERNEL);
+	if (!vha->port_name)
+		goto create_vhost_failed_2;
+
+	/* New host info */
+	u64_to_wwn(fc_vport->node_name, vha->node_name);
+	u64_to_wwn(fc_vport->port_name, vha->port_name);
+
+	vha->host = host;
+	vha->host_no = host->host_no;
+	vha->parent = ha;
+	vha->fc_vport = fc_vport;
+	vha->device_flags = 0;
+	vha->instance = num_hosts;
+	vha->vp_idx = qla24xx_allocate_vp_id(vha);
+	if (vha->vp_idx > ha->max_npiv_vports) {
+		DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
+			vha->host_no));
+		goto create_vhost_failed_3;
+	}
+	vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
+
+	init_MUTEX(&vha->mbx_cmd_sem);
+	init_MUTEX_LOCKED(&vha->mbx_intr_sem);
+
+	INIT_LIST_HEAD(&vha->list);
+	INIT_LIST_HEAD(&vha->fcports);
+	INIT_LIST_HEAD(&vha->vp_fcports);
+
+	vha->dpc_flags = 0L;
+	set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
+	set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
+
+	/*
+	 * To fix the issue of processing a parent's RSCN for the vport
before
+	 * its SCR is complete.
+	 */
+	set_bit(VP_SCR_NEEDED, &vha->vp_flags);
+	atomic_set(&vha->loop_state, LOOP_DOWN);
+	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+
+ 	qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL);
+
+	host->can_queue = vha->request_q_length + 128;
+	host->this_id = 255;
+	host->cmd_per_lun = 3;
+	host->max_cmd_len = MAX_CMDSZ;
+	host->max_channel = MAX_BUSES - 1;
+	host->max_lun = MAX_LUNS;
+	host->unique_id = vha->instance;
+	host->max_id = MAX_TARGETS_2200;
+	host->transportt = qla2xxx_transport_vport_template;
+
+	DEBUG15(printk("DEBUG: detect vport hba %ld at address = %p\n",
+	    vha->host_no, vha));
+
+	vha->flags.init_done = 1;
+	num_hosts++;
+
+	down(&ha->vport_sem);
+	set_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
+	ha->cur_vport_count++;
+	up(&ha->vport_sem);
+
+	return vha;
+
+create_vhost_failed_3:
+	kfree(vha->port_name);
+
+create_vhost_failed_2:
+	kfree(vha->node_name);
+
+create_vhost_failed_1:
+	return NULL;
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c
b/drivers/scsi/qla2xxx/qla_os.c
index 18baa5b..7333ca7 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -29,8 +29,7 @@ static struct kmem_cache *srb_cachep;
 /*
  * Ioctl related information.
  */
-static int num_hosts;
-
+int num_hosts;
 int ql2xlogintimeout = 20;
 module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
 MODULE_PARM_DESC(ql2xlogintimeout,
@@ -112,7 +111,7 @@ static int qla2x00_device_reset(scsi_qla_host_t *,
fc_port_t *);
 static int qla2x00_change_queue_depth(struct scsi_device *, int);
 static int qla2x00_change_queue_type(struct scsi_device *, int);
 
-static struct scsi_host_template qla2x00_driver_template = {
+struct scsi_host_template qla2x00_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= QLA2XXX_DRIVER_NAME,
 	.queuecommand		= qla2x00_queuecommand,
@@ -143,7 +142,7 @@ static struct scsi_host_template
qla2x00_driver_template = {
 	.shost_attrs		= qla2x00_host_attrs,
 };
 
-static struct scsi_host_template qla24xx_driver_template = {
+struct scsi_host_template qla24xx_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= QLA2XXX_DRIVER_NAME,
 	.queuecommand		= qla24xx_queuecommand,
@@ -171,21 +170,21 @@ static struct scsi_host_template
qla24xx_driver_template = {
 };
 
 static struct scsi_transport_template *qla2xxx_transport_template =
NULL;
+struct scsi_transport_template *qla2xxx_transport_vport_template =
NULL;
 
 /* TODO Convert to inlines
  *
  * Timer routines
  */
-#define	WATCH_INTERVAL		1       /* number of seconds */
 
-static void qla2x00_timer(scsi_qla_host_t *);
+void qla2x00_timer(scsi_qla_host_t *);
 
-static __inline__ void qla2x00_start_timer(scsi_qla_host_t *,
+__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
     void *, unsigned long);
 static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *,
unsigned long);
-static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
+__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
 
-static inline void
+__inline__ void
 qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long
interval)
 {
 	init_timer(&ha->timer);
@@ -202,7 +201,7 @@ qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned
long interval)
 	mod_timer(&ha->timer, jiffies + interval * HZ);
 }
 
-static __inline__ void
+__inline__ void
 qla2x00_stop_timer(scsi_qla_host_t *ha)
 {
 	del_timer_sync(&ha->timer);
@@ -213,8 +212,8 @@ static int qla2x00_do_dpc(void *data);
 
 static void qla2x00_rst_aen(scsi_qla_host_t *);
 
-static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
-static void qla2x00_mem_free(scsi_qla_host_t *ha);
+uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+void qla2x00_mem_free(scsi_qla_host_t *ha);
 static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
 static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
 static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
@@ -438,6 +437,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void
(*done)(struct scsi_cmnd *))
 	struct fc_rport *rport =
starget_to_rport(scsi_target(cmd->device));
 	srb_t *sp;
 	int rval;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	rval = fc_remote_port_chkready(rport);
 	if (rval) {
@@ -453,7 +453,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void
(*done)(struct scsi_cmnd *))
 
 	if (atomic_read(&fcport->state) != FCS_ONLINE) {
 		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
-		    atomic_read(&ha->loop_state) == LOOP_DEAD) {
+		    atomic_read(&pha->loop_state) == LOOP_DEAD) {
 			cmd->result = DID_NO_CONNECT << 16;
 			goto qc24_fail_command;
 		}
@@ -462,7 +462,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void
(*done)(struct scsi_cmnd *))
 
 	spin_unlock_irq(ha->host->host_lock);
 
-	sp = qla2x00_get_new_sp(ha, fcport, cmd, done);
+	sp = qla2x00_get_new_sp(pha, fcport, cmd, done);
 	if (!sp)
 		goto qc24_host_busy_lock;
 
@@ -475,8 +475,8 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void
(*done)(struct scsi_cmnd *))
 	return 0;
 
 qc24_host_busy_free_sp:
-	qla2x00_sp_free_dma(ha, sp);
-	mempool_free(sp, ha->srb_mempool);
+	qla2x00_sp_free_dma(pha, sp);
+	mempool_free(sp, pha->srb_mempool);
 
 qc24_host_busy_lock:
 	spin_lock_irq(ha->host->host_lock);
@@ -548,16 +548,17 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
 {
 	int		return_status;
 	unsigned long	wait_online;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
-	while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) ||
-	    test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
-	    test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) ||
-	    ha->dpc_active) && time_before(jiffies, wait_online)) {
+	while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) ||
+	    test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) ||
+	    test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) ||
+	    pha->dpc_active) && time_before(jiffies, wait_online)) {
 
 		msleep(1000);
 	}
-	if (ha->flags.online)
+	if (pha->flags.online)
 		return_status = QLA_SUCCESS;
 	else
 		return_status = QLA_FUNCTION_FAILED;
@@ -588,14 +589,15 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
 {
 	int 	 return_status = QLA_SUCCESS;
 	unsigned long loop_timeout ;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	/* wait for 5 min at the max for loop to be ready */
 	loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ);
 
-	while ((!atomic_read(&ha->loop_down_timer) &&
-	    atomic_read(&ha->loop_state) == LOOP_DOWN) ||
-	    atomic_read(&ha->loop_state) != LOOP_READY) {
-		if (atomic_read(&ha->loop_state) == LOOP_DEAD) {
+	while ((!atomic_read(&pha->loop_down_timer) &&
+	    atomic_read(&pha->loop_state) == LOOP_DOWN) ||
+	    atomic_read(&pha->loop_state) != LOOP_READY) {
+		if (atomic_read(&pha->loop_state) == LOOP_DEAD) {
 			return_status = QLA_FUNCTION_FAILED;
 			break;
 		}
@@ -650,6 +652,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 	unsigned long serial;
 	unsigned long flags;
 	int wait = 0;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	qla2x00_block_error_handler(cmd);
 
@@ -663,9 +666,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 	serial = cmd->serial_number;
 
 	/* Check active list for command command. */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
+	spin_lock_irqsave(&pha->hardware_lock, flags);
 	for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
-		sp = ha->outstanding_cmds[i];
+		sp = pha->outstanding_cmds[i];
 
 		if (sp == NULL)
 			continue;
@@ -677,7 +680,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 		    __func__, ha->host_no, sp, serial));
 		DEBUG3(qla2x00_print_scsi_cmd(cmd));
 
-		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		spin_unlock_irqrestore(&pha->hardware_lock, flags);
 		if (ha->isp_ops.abort_command(ha, sp)) {
 			DEBUG2(printk("%s(%ld): abort_command "
 			    "mbx failed.\n", __func__, ha->host_no));
@@ -686,11 +689,11 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
 			    "mbx success.\n", __func__, ha->host_no));
 			wait = 1;
 		}
-		spin_lock_irqsave(&ha->hardware_lock, flags);
+		spin_lock_irqsave(&pha->hardware_lock, flags);
 
 		break;
 	}
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	spin_unlock_irqrestore(&pha->hardware_lock, flags);
 
 	/* Wait for the command to be returned. */
 	if (wait) {
@@ -731,6 +734,7 @@
qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha,
unsigned int t)
 	srb_t		*sp;
 	struct scsi_cmnd *cmd;
 	unsigned long flags;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	status = 0;
 
@@ -739,19 +743,20 @@
qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha,
unsigned int t)
 	 * array
 	 */
 	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
-		spin_lock_irqsave(&ha->hardware_lock, flags);
-		sp = ha->outstanding_cmds[cnt];
+		spin_lock_irqsave(&pha->hardware_lock, flags);
+		sp = pha->outstanding_cmds[cnt];
 		if (sp) {
 			cmd = sp->cmd;
-			spin_unlock_irqrestore(&ha->hardware_lock,
flags);
-			if (cmd->device->id == t) {
+			spin_unlock_irqrestore(&pha->hardware_lock,
flags);
+			if (cmd->device->id == t &&
+			    ha->vp_idx == sp->ha->vp_idx) {
 				if (!qla2x00_eh_wait_on_command(ha,
cmd)) {
 					status = 1;
 					break;
 				}
 			}
 		} else {
-			spin_unlock_irqrestore(&ha->hardware_lock,
flags);
+			spin_unlock_irqrestore(&pha->hardware_lock,
flags);
 		}
 	}
 	return (status);
@@ -782,14 +787,12 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
 {
 	scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
 	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
-	int ret;
+	int ret = FAILED;
 	unsigned int id, lun;
 	unsigned long serial;
 
 	qla2x00_block_error_handler(cmd);
 
-	ret = FAILED;
-
 	id = cmd->device->id;
 	lun = cmd->device->lun;
 	serial = cmd->serial_number;
@@ -912,15 +915,14 @@ static int
 qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
 {
 	scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
-	int ret;
+	int ret = FAILED;
 	unsigned int id, lun;
 	unsigned long serial;
 
 	qla2x00_block_error_handler(cmd);
 
-	ret = FAILED;
-
 	id = cmd->device->id;
 	lun = cmd->device->lun;
 	serial = cmd->serial_number;
@@ -944,7 +946,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
 		goto eh_bus_reset_done;
 
 	/* Flush outstanding commands. */
-	if (!qla2x00_eh_wait_for_pending_commands(ha))
+	if (!qla2x00_eh_wait_for_pending_commands(pha))
 		ret = FAILED;
 
 eh_bus_reset_done:
@@ -974,14 +976,13 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
 {
 	scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
 	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
-	int ret;
+	int ret = FAILED;
 	unsigned int id, lun;
 	unsigned long serial;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	qla2x00_block_error_handler(cmd);
 
-	ret = FAILED;
-
 	id = cmd->device->id;
 	lun = cmd->device->lun;
 	serial = cmd->serial_number;
@@ -1004,21 +1005,24 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
 	 * while dpc is stuck for the mailbox to complete.
 	 */
 	qla2x00_wait_for_loop_ready(ha);
-	set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
-	if (qla2x00_abort_isp(ha)) {
-		clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+	set_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
+	if (qla2x00_abort_isp(pha)) {
+		clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
 		/* failed. schedule dpc to try */
-		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		set_bit(ISP_ABORT_NEEDED, &pha->dpc_flags);
 
 		if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
 			goto eh_host_reset_lock;
 	}
-	clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+	clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
 
 	/* Waiting for our command in done_queue to be returned to OS.*/
-	if (qla2x00_eh_wait_for_pending_commands(ha))
+	if (qla2x00_eh_wait_for_pending_commands(pha))
 		ret = SUCCESS;
 
+	if (ha->parent)
+		qla2x00_vp_abort_isp(ha);
+
 eh_host_reset_lock:
 	qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
 	    (ret == FAILED) ? "failed" : "succeded");
@@ -1435,6 +1439,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const
struct pci_device_id *id)
 	ha->host = host;
 	ha->host_no = host->host_no;
 	sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME,
ha->host_no);
+	ha->parent = NULL;
 
 	/* Set ISP-type information. */
 	qla2x00_set_isp_flags(ha);
@@ -1452,7 +1457,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const
struct pci_device_id *id)
 
 	ha->prev_topology = 0;
 	ha->init_cb_size = sizeof(init_cb_t);
-	ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
+	ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx;
 	ha->link_data_rate = PORT_SPEED_UNKNOWN;
 	ha->optrom_size = OPTROM_SIZE_2300;
 
@@ -1524,8 +1529,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const
struct pci_device_id *id)
 		ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
 		ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
 		ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
-		ha->init_cb_size = sizeof(struct init_cb_24xx);
-		ha->mgmt_svr_loop_id = 10;
+		ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
+		ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
 		ha->isp_ops.pci_config = qla24xx_pci_config;
 		ha->isp_ops.reset_chip = qla24xx_reset_chip;
 		ha->isp_ops.chip_diag = qla24xx_chip_diag;
@@ -1563,10 +1568,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const
struct pci_device_id *id)
 	ha->instance = num_hosts;
 
 	init_MUTEX(&ha->mbx_cmd_sem);
+	init_MUTEX(&ha->vport_sem);
 	init_MUTEX_LOCKED(&ha->mbx_intr_sem);
 
 	INIT_LIST_HEAD(&ha->list);
 	INIT_LIST_HEAD(&ha->fcports);
+	INIT_LIST_HEAD(&ha->vp_list);
+
+	set_bit(0, (unsigned long *) ha->vp_idx_map);
 
 	qla2x00_config_dma_addressing(ha);
 	if (qla2x00_mem_alloc(ha)) {
@@ -1789,7 +1798,8 @@ qla2x00_schedule_rport_del(struct scsi_qla_host
*ha, fc_port_t *fcport,
 void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
     int do_login, int defer)
 {
-	if (atomic_read(&fcport->state) == FCS_ONLINE)
+	if (atomic_read(&fcport->state) == FCS_ONLINE &&
+	    ha->vp_idx == fcport->vp_idx)
 		qla2x00_schedule_rport_del(ha, fcport, defer);
 
 	/*
@@ -1840,19 +1850,23 @@ void
 qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 {
 	fc_port_t *fcport;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
-	list_for_each_entry(fcport, &ha->fcports, list) {
-		if (fcport->port_type != FCT_TARGET)
+	list_for_each_entry(fcport, &pha->fcports, list) {
+		if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
 			continue;
-
 		/*
 		 * No point in marking the device as lost, if the device
is
 		 * already DEAD.
 		 */
 		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
 			continue;
-		if (atomic_read(&fcport->state) == FCS_ONLINE)
-			qla2x00_schedule_rport_del(ha, fcport, defer);
+		if (atomic_read(&fcport->state) == FCS_ONLINE) {
+			if (defer)
+				qla2x00_schedule_rport_del(ha, fcport,
defer);
+			else if (ha->vp_idx == fcport->vp_idx)
+				qla2x00_schedule_rport_del(ha, fcport,
defer);
+		}
 		atomic_set(&fcport->state, FCS_DEVICE_LOST);
 	}
 
@@ -1868,7 +1882,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha,
int defer)
 *      0  = success.
 *      1  = failure.
 */
-static uint8_t
+uint8_t
 qla2x00_mem_alloc(scsi_qla_host_t *ha)
 {
 	char	name[16];
@@ -1920,33 +1934,33 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
 			continue;
 		}
 
-		snprintf(name, sizeof(name), "%s_%ld",
QLA2XXX_DRIVER_NAME,
-		    ha->host_no);
-		ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
-		    DMA_POOL_SIZE, 8, 0);
-		if (ha->s_dma_pool == NULL) {
+		/* get consistent memory allocated for init control
block */
+		ha->init_cb = dma_alloc_coherent(&ha->pdev->dev,
+		    ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL);
+		if (ha->init_cb == NULL) {
 			qla_printk(KERN_WARNING, ha,
-			    "Memory Allocation failed - s_dma_pool\n");
+			    "Memory Allocation failed - init_cb\n");
 
 			qla2x00_mem_free(ha);
 			msleep(100);
 
 			continue;
 		}
+		memset(ha->init_cb, 0, ha->init_cb_size);
 
-		/* get consistent memory allocated for init control
block */
-		ha->init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
-		    &ha->init_cb_dma);
-		if (ha->init_cb == NULL) {
+		snprintf(name, sizeof(name), "%s_%ld",
QLA2XXX_DRIVER_NAME,
+		    ha->host_no);
+		ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+		    DMA_POOL_SIZE, 8, 0);
+		if (ha->s_dma_pool == NULL) {
 			qla_printk(KERN_WARNING, ha,
-			    "Memory Allocation failed - init_cb\n");
+			    "Memory Allocation failed - s_dma_pool\n");
 
 			qla2x00_mem_free(ha);
 			msleep(100);
 
 			continue;
 		}
-		memset(ha->init_cb, 0, ha->init_cb_size);
 
 		if (qla2x00_allocate_sp_pool(ha)) {
 			qla_printk(KERN_WARNING, ha,
@@ -2052,7 +2066,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
 * Input:
 *      ha = adapter block pointer.
 */
-static void
+void
 qla2x00_mem_free(scsi_qla_host_t *ha)
 {
 	struct list_head	*fcpl, *fcptemp;
@@ -2088,12 +2102,13 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
 	if (ha->ms_iocb)
 		dma_pool_free(ha->s_dma_pool, ha->ms_iocb,
ha->ms_iocb_dma);
 
-	if (ha->init_cb)
-		dma_pool_free(ha->s_dma_pool, ha->init_cb,
ha->init_cb_dma);
-
 	if (ha->s_dma_pool)
 		dma_pool_destroy(ha->s_dma_pool);
 
+	if (ha->init_cb)
+		dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, 
+		    ha->init_cb, ha->init_cb_dma);
+
 	if (ha->gid_list)
 		dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE,
ha->gid_list,
 		    ha->gid_list_dma);
@@ -2199,6 +2214,7 @@ qla2x00_free_sp_pool( scsi_qla_host_t *ha)
 static int
 qla2x00_do_dpc(void *data)
 {
+	int		rval;
 	scsi_qla_host_t *ha;
 	fc_port_t	*fcport;
 	uint8_t		status;
@@ -2347,7 +2363,7 @@ qla2x00_do_dpc(void *data)
 			if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
 			    &ha->dpc_flags))) {
 
-				qla2x00_loop_resync(ha);
+				rval = qla2x00_loop_resync(ha);
 
 				clear_bit(LOOP_RESYNC_ACTIVE,
&ha->dpc_flags);
 			}
@@ -2374,6 +2390,8 @@ qla2x00_do_dpc(void *data)
 		if (test_and_clear_bit(BEACON_BLINK_NEEDED,
&ha->dpc_flags))
 			ha->isp_ops.beacon_blink(ha);
 
+		qla2x00_do_dpc_all_vps(ha);
+
 		ha->dpc_active = 0;
 	} /* End of while(1) */
 
@@ -2452,7 +2470,7 @@ qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp)
 *
 * Context: Interrupt
 
************************************************************************
***/
-static void
+void
 qla2x00_timer(scsi_qla_host_t *ha)
 {
 	unsigned long	cpu_flags = 0;
@@ -2461,6 +2479,7 @@ qla2x00_timer(scsi_qla_host_t *ha)
 	int		index;
 	srb_t		*sp;
 	int		t;
+	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	/*
 	 * Ports - Port down timer.
@@ -2506,23 +2525,29 @@ qla2x00_timer(scsi_qla_host_t *ha)
 				atomic_set(&ha->loop_state, LOOP_DEAD);
 
 			/* Schedule an ISP abort to return any tape
commands. */
-			spin_lock_irqsave(&ha->hardware_lock,
cpu_flags);
-			for (index = 1; index <
MAX_OUTSTANDING_COMMANDS;
-			    index++) {
-				fc_port_t *sfcp;
+			/* NPIV - scan physical port only */
+			if (!ha->parent) {
+				spin_lock_irqsave(&ha->hardware_lock,
+				    cpu_flags);
+				for (index = 1;
+				    index < MAX_OUTSTANDING_COMMANDS;
+				    index++) {
+					fc_port_t *sfcp;
+
+					sp =
ha->outstanding_cmds[index];
+					if (!sp)
+						continue;
+					sfcp = sp->fcport;
+					if (!(sfcp->flags &
FCF_TAPE_PRESENT))
+						continue;
 
-				sp = ha->outstanding_cmds[index];
-				if (!sp)
-					continue;
-				sfcp = sp->fcport;
-				if (!(sfcp->flags & FCF_TAPE_PRESENT))
-					continue;
-
-				set_bit(ISP_ABORT_NEEDED,
&ha->dpc_flags);
-				break;
+					set_bit(ISP_ABORT_NEEDED,
+					    &ha->dpc_flags);
+					break;
+				}
+
spin_unlock_irqrestore(&ha->hardware_lock,
+				    cpu_flags);
 			}
-			spin_unlock_irqrestore(&ha->hardware_lock,
cpu_flags);
-
 			set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
 			start_dpc++;
 		}
@@ -2566,8 +2591,9 @@ qla2x00_timer(scsi_qla_host_t *ha)
 	    test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
 	    test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
 	    test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) ||
+	    test_bit(VP_DPC_NEEDED, &ha->dpc_flags) ||
 	    test_bit(RELOGIN_NEEDED, &ha->dpc_flags)))
-		qla2xxx_wake_dpc(ha);
+		qla2xxx_wake_dpc(pha);
 
 	qla2x00_restart_timer(ha, WATCH_INTERVAL);
 }
@@ -2711,14 +2737,24 @@ qla2x00_module_init(void)
 
 	qla2xxx_transport_template =
 	    fc_attach_transport(&qla2xxx_transport_functions);
-	if (!qla2xxx_transport_template)
+	if (!qla2xxx_transport_template) {
+		kmem_cache_destroy(srb_cachep);
+		return -ENODEV;
+	}
+	qla2xxx_transport_vport_template =
+	    fc_attach_transport(&qla2xxx_transport_vport_functions);
+	if (!qla2xxx_transport_vport_template) {
+		kmem_cache_destroy(srb_cachep);
+		fc_release_transport(qla2xxx_transport_template);
 		return -ENODEV;
+	}
 
 	printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
 	ret = pci_register_driver(&qla2xxx_pci_driver);
 	if (ret) {
 		kmem_cache_destroy(srb_cachep);
 		fc_release_transport(qla2xxx_transport_template);
+		fc_release_transport(qla2xxx_transport_vport_template);
 	}
 	return ret;
 }
@@ -2733,6 +2769,7 @@ qla2x00_module_exit(void)
 	qla2x00_release_firmware();
 	kmem_cache_destroy(srb_cachep);
 	fc_release_transport(qla2xxx_transport_template);
+	fc_release_transport(qla2xxx_transport_vport_template);
 }
 
 module_init(qla2x00_module_init);
-- 
1.5.2.2.603.g7c851

Attachment: 0001-qla2xxx-Add-support-for-NPIV-N-Port-ID-Virtualizat.patch
Description: 0001-qla2xxx-Add-support-for-NPIV-N-Port-ID-Virtualizat.patch


[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