Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2168

kernel-2.6.18-128.1.10.el5.src.rpm

From: Chip Coldwell <coldwell@redhat.com>
Date: Wed, 19 Dec 2007 17:32:10 -0500
Subject: [scsi] lpfc:  update to version 8.2.0.13
Message-id: alpine.LFD.0.9999.0712191425160.6018@localhost.localdomain
O-Subject: [RHEL-5.2 PATCH] bz426281 update lpfc (Emulex) driver to version 8.2.0.13
Bugzilla: 426281

Some serious deficiencies were discovered in the 8.2.0.8 lpfc driver
(already integrated into the 5.2 kernel, see bz252989).

* Changed version number to 8.2.0.13
* Enhance debugfs to dump HBA SLIM as well as Host SLIM
* Fix driver to recover properly from FAN timeout (CR 27723)
* Fix Unsolicited CT command handling (CR 27553)
* Force NPIV off for pt2pt mode between 2 NPorts (CR 27543)
* Fix up loopback ioctl to handle vports properly
* Check void pointer type condition with proper type
* Fix mbox race condition and a workaround on back-to-back mailbox
  commands (CR 27603)
* Fix panic when HBA generates ERATT interupt (CR 27531)
* Fix hbq initialization after HBA reset (CR 27581)
* Changed version number to 8.2.0.12
* Allow vports to be created when no fabric present
* Removed schedule call from the worker thread. (CR 27379, 27516, 27178,
  27203, 27349)
* Remove bogus message displayed when driver unloads (CR 27539)
* Added module parameter and sysfs interface to restrict PCI DMA length.
  (CR 27634)
* Perform target flush before releasing references with FC_UNLOADING
  (CR 27506)
* Fix instances of beXX_to_cpu() should actually be cpu_to_beXX()
  (CR 25073)
* Change del_timer_sync() in ISR to del_timer()
* Fixed System crash deleting vports with traffic running (CR 27280)
* Added support for direct download feature of offline utility.
  (CR 27546)
* Fixed a panic while running PCI loopback test with old libdfc.
  (CR 27456)
* Added code to report unknown link speed when link is down. (CR 27454)
* Enable PCI Enhanced Error Handling for RHEL 5 and SLES 10 SP1
* Make scatter gather Segment Count into a module parameter. (CR 27269)
* Added support for PCI loopback test. (CR 26350)
* Fixed HBQ dma buffer leak at dma_pool_destroy when unloading driver
  (CR 27069)
* Changed version number to 8.2.0.11
* Fix system panic'd when unloading the driver (CR 27275)
* Fix "bad status back" when hitting "initiate authentication" button
  (CR 27287)
* Fixed use after free of event buffers. (CR 26881)
* Make lpfc legacy I/O port free. (CR 27197)
* Log all temperature event messages. (CR 27228)
* Fix reauthenticate periodically with time interval does not work
  (CR 26867)
* Changed version number to 8.2.0.10
* Added support for SET_VARIABLE mailbox command in online mode.
  (CR 27125)
* Remove unused netlink-related #defines
* Fix incorrect queue tag handling. (CR 27032)
* Made link speed and link topology modifiable. (CR 27112)
* Fixed key calculation for low cost and MID range saturn HBAs.
  (CR 27111)
* Devloss timeouts with swap cable test (CR 27009)
* Add parameters to enable and disable heartbeat and hba resets
  (CR 27033)
* Increase Max Vport limit from 100 to 0xFFFF (CR 27038)
* Fixed error code returned from the driver when HBA is over heated.
  (CR 27029)
* Added code for event based abort completion. (CR 26653)
* Fix annoying messages that occur while executing fc swap test
  (CR 26960 26961)
* Fixed external loopback test. (CR 26881)
* Changed version number to 8.2.0.9
* Fixed a memory leak in an error path.
* SCSI 0x10000 errors during dt with HBA reset (CR 26082)
* Add retry mechanism for GFF_ID (CR 26728)
* Reset the FCP recovery flag when the node is not a FCP2 device.
* Fixed a discovery  issue. (CR 26424)
* ELS payload gets freed while firmware DMA is in progress (CR 26919)
* Fix potential overflow of hbqs array
* Clean up duplicate includes
* kmalloc + memset conversion to kzalloc
* Added support for extended mailbox commands for EFI boot manager.
  (CR 26707)
* Initiate Authentication succeeds when auth mode is disabled. (CR 26889)
* RSCN timeout messages displayed (CR 26826)
* Fix for internal loopback test. (CR 26315)
* Unable to get out of non-communicating mode. (CR 26869)
* Clear Link attention after Authentication failure. (CR 26838)
* The driver waits a long time for the authentication service. (CR 26798)
* Illegal state transition messages displayed (CR 26826)

So Emulex have asked us to incorporate the patch below.  All-arches
build at

 http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1087211

diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 9b1306a..64504cc 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -29,7 +29,8 @@ struct lpfc_sli2_slim;
 #define LPFC_MAX_NS_RETRY	3	/* Number of retry attempts to contact
 					   the NameServer  before giving up. */
 #define LPFC_CMD_PER_LUN	3	/* max outstanding cmds per lun */
-#define LPFC_SG_SEG_CNT		64	/* sg element count per scsi cmnd */
+#define LPFC_DEFAULT_SG_SEG_CNT	64	/* sg element count per scsi cmnd */
+#define LPFC_MAX_SG_SEG_CNT	256	/* sg element count per scsi cmnd */
 #define LPFC_IOCB_LIST_CNT	2250	/* list of IOCBs for fast-path usage. */
 #define LPFC_Q_RAMP_UP_INTERVAL 120     /* lun q_depth ramp up interval */
 
@@ -68,6 +69,7 @@ struct lpfc_dmabuf {
 	struct list_head list;
 	void *virt;		/* virtual address ptr */
 	dma_addr_t phys;	/* mapped address */
+	uint32_t   buffer_tag;	/* used for tagged queue ring */
 };
 
 struct lpfc_dma_pool {
@@ -201,7 +203,10 @@ struct lpfc_stats {
 enum sysfs_mbox_state {
 	SMBOX_IDLE,
 	SMBOX_WRITING,
-	SMBOX_READING
+	SMBOX_WRITING_MBEXT,
+	SMBOX_READING,
+	SMBOX_WRITING_BUFF,
+	SMBOX_READING_BUFF
 };
 
 struct lpfc_sysfs_mbox {
@@ -211,6 +216,10 @@ struct lpfc_sysfs_mbox {
 	/* process id of the mgmt application */
 	pid_t		      pid;
 	struct list_head      list;
+	uint8_t *             mbext;
+	uint32_t              extoff;
+	struct lpfc_dmabuf *  txmit_buff;
+	struct lpfc_dmabuf *  rcv_buff;
 };
 
 struct lpfc_hba;
@@ -294,6 +303,8 @@ struct lpfc_auth {
 	uint32_t challenge_len;
 	uint8_t *dh_pub_key;
 	uint32_t dh_pub_key_len;
+
+	unsigned long last_auth;
 };
 
 struct lpfc_vport {
@@ -477,8 +488,6 @@ struct lpfc_hba {
 
 	uint16_t pci_cfg_value;
 
-	uint8_t work_found;
-#define LPFC_MAX_WORKER_ITERATION  4
 
 	uint8_t fc_linkspeed;	/* Link speed after last READ_LA */
 
@@ -532,7 +541,9 @@ struct lpfc_hba {
 	uint64_t cfg_soft_wwnn;
 	uint64_t cfg_soft_wwpn;
 	uint32_t cfg_hba_queue_depth;
-
+	uint32_t cfg_enable_hba_reset;
+	uint32_t cfg_enable_hba_heartbeat;
+	uint32_t cfg_pci_max_read;
 
 	lpfc_vpd_t vpd;		/* vital product data */
 
@@ -546,6 +557,8 @@ struct lpfc_hba {
 	wait_queue_head_t    *work_wait;
 	struct task_struct   *worker_thread;
 
+	uint32_t hbq_in_use;		/* HBQs in use flag */
+	struct list_head hbqbuf_in_list;  /* in-fly hbq buffer list */
 	uint32_t hbq_count;	        /* Count of configured HBQs */
 	struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies  */
 
@@ -621,8 +634,7 @@ struct lpfc_hba {
 	struct list_head port_list;
 	struct lpfc_vport *pport;	/* physical lpfc_vport pointer */
 	uint16_t max_vpi;		/* Maximum virtual nports */
-#define LPFC_MAX_VPI 100		/* Max number of VPI supported */
-#define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */
+#define LPFC_MAX_VPI 0xFFFF		/* Max number of VPI supported */
 	unsigned long *vpi_bmask;	/* vpi allocation table */
 
 	/* Data structure used by fabric iocb scheduler */
@@ -640,18 +652,30 @@ struct lpfc_hba {
 	struct dentry *hba_debugfs_root;
 	atomic_t debugfs_vport_count;
 	struct dentry *debug_hbqinfo;
-	struct dentry *debug_dumpslim;
+	struct dentry *debug_dumpHostSlim;
+	struct dentry *debug_dumpHBASlim;
 	struct dentry *debug_slow_ring_trc;
 	struct lpfc_debugfs_trc *slow_ring_trc;
 	atomic_t slow_ring_trc_cnt;
 #endif
 
+	/* Used for deferred freeing of ELS data buffers */
+	struct list_head elsbuf;
+	int elsbuf_cnt;
+	int elsbuf_prev_cnt;
+
 	uint8_t temp_sensor_support;
 	/* Fields used for heart beat. */
 	unsigned long last_completion_time;
 	struct timer_list hb_tmofunc;
 	uint8_t hb_outstanding;
 	enum hba_temp_state over_temp_state;
+	/*
+	 * Following bit will be set for all buffer tags which are not
+	 * associated with any HBQ.
+	 */
+#define QUE_BUFTAG_BIT  (1<<31)
+	uint32_t buffer_tag_count;
 };
 
 static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 972705f..f934e2d 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -269,8 +269,7 @@ lpfc_issue_lip(struct Scsi_Host *shost)
 	int mbxstatus = MBXERR_ERROR;
 
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) ||
-	    (vport->port_state != LPFC_VPORT_READY))
+	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
 		return -EPERM;
 
 	pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
@@ -322,12 +321,14 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
 
 	psli = &phba->sli;
 
+	/* Wait a little for things to settle down, but not
+	 * long enough for dev loss timeout to expire.
+	 */
 	for (i = 0; i < psli->num_rings; i++) {
 		pring = &psli->ring[i];
-		/* The linkdown event takes 30 seconds to timeout. */
 		while (pring->txcmplq_cnt) {
 			msleep(10);
-			if (cnt++ > 3000) {
+			if (cnt++ > 500) {  /* 5 secs */
 				lpfc_printf_log(phba,
 					KERN_WARNING, LOG_INIT,
 					"0466 Outstanding IO when "
@@ -347,20 +348,22 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
 	return 0;
 }
 
-static int
+int
 lpfc_selective_reset(struct lpfc_hba *phba)
 {
 	struct completion online_compl;
 	int status = 0;
 
+	if (!phba->cfg_enable_hba_reset)
+		return -EIO;
+
 	status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 
 	if (status != 0)
 		return status;
 
 	init_completion(&online_compl);
-	lpfc_workq_post_event(phba, &status, &online_compl,
-			      LPFC_EVT_ONLINE);
+	lpfc_workq_post_event(phba, &status, &online_compl, LPFC_EVT_ONLINE);
 	wait_for_completion(&online_compl);
 
 	if (status != 0)
@@ -426,6 +429,8 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
 	struct completion online_compl;
 	int status=0;
 
+	if (!phba->cfg_enable_hba_reset)
+		return -EACCES;
 	init_completion(&online_compl);
 
 	if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
@@ -1101,10 +1106,12 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
 	unsigned int i, j, cnt=count;
 	u8 wwpn[8];
 
+	if (!phba->cfg_enable_hba_reset)
+		return -EACCES;
 	spin_lock_irq(&phba->hbalock);
 	if (phba->over_temp_state == HBA_OVER_TEMP) {
 		spin_unlock_irq(&phba->hbalock);
-		return -EPERM;
+		return -EACCES;
 	}
 	spin_unlock_irq(&phba->hbalock);
 	/* count may include a LF at end of string */
@@ -1328,46 +1335,90 @@ lpfc_nodev_tmo_set(struct lpfc_vport *vport, int val)
 			 val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
 	return -EINVAL;
 }
-
 lpfc_vport_param_store(nodev_tmo)
-
 static CLASS_DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR,
 			 lpfc_nodev_tmo_show, lpfc_nodev_tmo_store);
 
-
 static ssize_t
-lpfc_restart_auth (struct class_device *cdev, const char *buf, size_t count)
+lpfc_authenticate (struct class_device *cdev, const char *buf, size_t count)
 {
 	struct Scsi_Host *shost = class_to_shost(cdev);
 	struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
 	struct lpfc_nodelist *ndlp;
 	int status;
+	struct lpfc_name wwpn;
 
+	if (lpfc_parse_wwn(buf, wwpn.u.wwn))
+		return -EINVAL;
+
+	if (vport->port_state == LPFC_VPORT_FAILED) {
+		lpfc_issue_lip(shost);
+		return strlen(buf);
+	}
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-		(phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) ||
-		(!vport->cfg_enable_auth))
+	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) ||
+	    (!vport->cfg_enable_auth))
 		return -EPERM;
 
 	/* If vport already in the middle of authentication do not restart */
 	if ((vport->auth.auth_msg_state == LPFC_AUTH_NEGOTIATE) ||
 	    (vport->auth.auth_msg_state == LPFC_DHCHAP_CHALLENGE) ||
 	    (vport->auth.auth_msg_state == LPFC_DHCHAP_REPLY))
-		return -EPERM;
+		return -EAGAIN;
 
-	ndlp = lpfc_findnode_did(vport, Fabric_DID);
+	if (wwn_to_u64(wwpn.u.wwn) == AUTH_FABRIC_WWN)
+		ndlp = lpfc_findnode_did(vport, Fabric_DID);
+	else
+		ndlp = lpfc_findnode_wwnn(vport, &wwpn);
 	if (!ndlp)
 		return -EPERM;
 	status = lpfc_start_node_authentication(ndlp);
 	if (status)
 		return status;
-
 	return strlen(buf);
-
 }
+static CLASS_DEVICE_ATTR(lpfc_authenticate, S_IRUGO | S_IWUSR,
+			 NULL, lpfc_authenticate);
+
+static ssize_t
+lpfc_update_auth_config (struct class_device *cdev, const char *buf,
+			 size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+	struct lpfc_hba   *phba = vport->phba;
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_name wwpn;
+	int status;
+
+	if (lpfc_parse_wwn(buf, wwpn.u.wwn))
+		return -EINVAL;
+
+	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) ||
+	    (!vport->cfg_enable_auth))
+		return -EPERM;
 
-static CLASS_DEVICE_ATTR(lpfc_restart_auth, S_IRUGO | S_IWUSR,
-			 NULL, lpfc_restart_auth);
+	/* If vport already in the middle of authentication do not restart */
+	if ((vport->auth.auth_msg_state == LPFC_AUTH_NEGOTIATE) ||
+	    (vport->auth.auth_msg_state == LPFC_DHCHAP_CHALLENGE) ||
+	    (vport->auth.auth_msg_state == LPFC_DHCHAP_REPLY))
+		return -EAGAIN;
+
+	if (wwn_to_u64(wwpn.u.wwn) == AUTH_FABRIC_WWN)
+		ndlp = lpfc_findnode_did(vport, Fabric_DID);
+	else
+		ndlp = lpfc_findnode_wwnn(vport, &wwpn);
+	if (!ndlp)
+		return -EPERM;
+	status = lpfc_get_auth_config(ndlp);
+	if (status)
+		return -EPERM;
+	return strlen(buf);
+}
+static CLASS_DEVICE_ATTR(lpfc_update_auth_config, S_IRUGO | S_IWUSR,
+			 NULL, lpfc_update_auth_config);
 
 /*
 # lpfc_devloss_tmo: If set, it will hold all I/O errors on devices that
@@ -1553,7 +1604,33 @@ LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1,
 # Set loop mode if you want to run as an NL_Port. Value range is [0,0x6].
 # Default value is 0.
 */
-LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
+static int
+lpfc_topology_set(struct lpfc_hba *phba, int val)
+{
+	int err;
+	uint32_t prev_val;
+	if (val >= 0 && val <= 6) {
+		prev_val = phba->cfg_topology;
+		phba->cfg_topology = val;
+		err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
+		if (err)
+			phba->cfg_topology = prev_val;
+		return err;
+	}
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+		"%d:0467 lpfc_topology attribute cannot be set to %d, "
+		"allowed range is [0, 6]\n",
+		phba->brd_no, val);
+	return -EINVAL;
+}
+static int lpfc_topology = 0;
+module_param(lpfc_topology, int, 0);
+MODULE_PARM_DESC(lpfc_topology, "Select Fibre Channel topology");
+lpfc_param_show(topology)
+lpfc_param_init(topology, 0, 0, 6)
+lpfc_param_store(topology)
+static CLASS_DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR,
+		lpfc_topology_show, lpfc_topology_store);
 
 /*
 # lpfc_link_speed: Link speed selection for initializing the Fibre Channel
@@ -1565,6 +1642,36 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
 #       8  = 8 Gigabaud
 # Value range is [0,8]. Default value is 0.
 */
+static int
+lpfc_link_speed_set(struct lpfc_hba *phba, int val)
+{
+	int err;
+	uint32_t prev_val;
+
+	if (((val == LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
+		((val == LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
+		((val == LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
+		((val == LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
+		((val == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)))
+		return -EINVAL;
+
+	if ((val >= 0 && val <= 8)
+		&& (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
+		prev_val = phba->cfg_link_speed;
+		phba->cfg_link_speed = val;
+		err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
+		if (err)
+			phba->cfg_link_speed = prev_val;
+		return err;
+	}
+
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+		"%d:0469 lpfc_link_speed attribute cannot be set to %d, "
+		"allowed range is [0, 8]\n",
+		phba->brd_no, val);
+	return -EINVAL;
+}
+
 static int lpfc_link_speed = 0;
 module_param(lpfc_link_speed, int, 0);
 MODULE_PARM_DESC(lpfc_link_speed, "Select link speed");
@@ -1584,7 +1691,10 @@ lpfc_link_speed_init(struct lpfc_hba *phba, int val)
 	phba->cfg_link_speed = 0;
 	return -EINVAL;
 }
-static CLASS_DEVICE_ATTR(lpfc_link_speed, S_IRUGO , lpfc_link_speed_show, NULL);
+
+lpfc_param_store(link_speed)
+static CLASS_DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
+		lpfc_link_speed_show, lpfc_link_speed_store);
 
 /*
 # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
@@ -1725,6 +1835,80 @@ static CLASS_DEVICE_ATTR(lpfc_enable_auth, S_IRUGO | S_IWUSR,
 			 lpfc_enable_auth_show, lpfc_enable_auth_store);
 
 /*
+# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
+#       0  = HBA resets disabled
+#       1  = HBA resets enabled (default)
+# Value range is [0,1]. Default value is 1.
+*/
+LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver.");
+
+/*
+# lpfc_enable_hba_heartbeat: Enable HBA heartbeat timer..
+#       0  = HBA Heartbeat disabled
+#       1  = HBA Heartbeat enabled (default)
+# Value range is [0,1]. Default value is 1.
+*/
+LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
+
+/*
+ * lpfc_sg_seg_cnt: Initial Maximum DMA Segment Count
+ * This value can be set to values between 64 and 256. The default value is
+ * 64, but may be increased to allow for larger Max I/O sizes. The scsi layer
+ * will be allowed to request I/Os of sizes up to (MAX_SEG_COUNT * SEG_SIZE).
+ */
+LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT,
+	    LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count");
+
+/*
+# lpfc_pci_max_read:  Maximum DMA read byte count. This parameter can have
+# values 512, 1024, 2048, 4096. Default value is 2048.
+*/
+static int lpfc_pci_max_read = 2048;
+module_param(lpfc_pci_max_read, int, 0);
+MODULE_PARM_DESC(lpfc_pci_max_read,
+	"Maximum DMA read byte count. Allowed values:"
+		" 512,1024,2048,4096." );
+static ssize_t
+lpfc_pci_max_read_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host  *shost = class_to_shost(cdev);
+	struct lpfc_hba   *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+	uint32_t val = 0;
+	val = phba->cfg_pci_max_read;
+	return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static int
+lpfc_pci_max_read_init(struct lpfc_hba *phba, int val)
+{
+	phba->cfg_pci_max_read = 2048;
+	if ((val == 512) || (val == 1024) || (val == 2048)
+		|| (val == 4096))
+		phba->cfg_pci_max_read = val;
+	return 0;
+}
+
+static int
+lpfc_pci_max_read_set(struct lpfc_hba *phba, int val)
+{
+	uint32_t prev_val;
+	int ret;
+
+	prev_val = phba->cfg_pci_max_read;
+	phba->cfg_pci_max_read = val;
+	if ((ret = lpfc_sli_set_dma_length(phba, 0))) {
+		phba->cfg_pci_max_read = prev_val;
+		return ret;
+	} else
+		return 0;
+}
+
+lpfc_param_store(pci_max_read)
+
+static CLASS_DEVICE_ATTR(lpfc_pci_max_read, S_IRUGO | S_IWUSR,
+		lpfc_pci_max_read_show, lpfc_pci_max_read_store);
+
+/*
 # lpfc_dev_loss_initiator: FC transport layer waits for dev_loss timer to
 #	expire for FC Initiators before calling rport dev_loss callback routine
 #       0  = disabled (dev_loss callback called immediately after rport delete)
@@ -1751,6 +1935,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
 	&class_device_attr_lpfc_log_verbose,
 	&class_device_attr_lpfc_lun_queue_depth,
 	&class_device_attr_lpfc_hba_queue_depth,
+	&class_device_attr_lpfc_pci_max_read,
 	&class_device_attr_lpfc_peer_port_login,
 	&class_device_attr_lpfc_nodev_tmo,
 	&class_device_attr_lpfc_devloss_tmo,
@@ -1783,7 +1968,8 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
 	&class_device_attr_lpfc_poll_tmo,
 	&class_device_attr_lpfc_use_msi,
 	&class_device_attr_lpfc_enable_auth,
-	&class_device_attr_lpfc_restart_auth,
+	&class_device_attr_lpfc_authenticate,
+	&class_device_attr_lpfc_update_auth_config,
 	&class_device_attr_lpfc_dev_loss_initiator,
 	&class_device_attr_npiv_vports_inuse,
 	&class_device_attr_max_npiv_vports,
@@ -1792,6 +1978,9 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
 	&class_device_attr_lpfc_soft_wwnn,
 	&class_device_attr_lpfc_soft_wwpn,
 	&class_device_attr_lpfc_soft_wwn_enable,
+	&class_device_attr_lpfc_enable_hba_reset,
+	&class_device_attr_lpfc_enable_hba_heartbeat,
+	&class_device_attr_lpfc_sg_seg_cnt,
 	NULL,
 };
 
@@ -1812,6 +2001,7 @@ struct class_device_attribute *lpfc_hba_attrs_no_npiv[] = {
 	&class_device_attr_lpfc_log_verbose,
 	&class_device_attr_lpfc_lun_queue_depth,
 	&class_device_attr_lpfc_hba_queue_depth,
+	&class_device_attr_lpfc_pci_max_read,
 	&class_device_attr_lpfc_peer_port_login,
 	&class_device_attr_lpfc_nodev_tmo,
 	&class_device_attr_lpfc_devloss_tmo,
@@ -1844,7 +2034,8 @@ struct class_device_attribute *lpfc_hba_attrs_no_npiv[] = {
 	&class_device_attr_lpfc_poll_tmo,
 	&class_device_attr_lpfc_use_msi,
 	&class_device_attr_lpfc_enable_auth,
-	&class_device_attr_lpfc_restart_auth,
+	&class_device_attr_lpfc_authenticate,
+	&class_device_attr_lpfc_update_auth_config,
 	&class_device_attr_lpfc_dev_loss_initiator,
 	&class_device_attr_lpfc_soft_wwnn,
 	&class_device_attr_lpfc_soft_wwpn,
@@ -1997,9 +2188,118 @@ sysfs_mbox_idle(struct lpfc_hba *phba,
 		mempool_free(sysfs_mbox->mbox,
 			     phba->mbox_mem_pool);
 	}
+
+	if (sysfs_mbox->mbext)
+		kfree(sysfs_mbox->mbext);
+
+	/* If txmit buffer allocated free txmit buffer */
+	if (sysfs_mbox->txmit_buff) {
+		if (sysfs_mbox->txmit_buff->virt)
+			__lpfc_mbuf_free(phba,
+				sysfs_mbox->txmit_buff->virt,
+				sysfs_mbox->txmit_buff->phys);
+		kfree(sysfs_mbox->txmit_buff);
+	}
+
+	/* If rcv buffer allocated free txmit buffer */
+	if (sysfs_mbox->rcv_buff) {
+		if (sysfs_mbox->rcv_buff->virt)
+			__lpfc_mbuf_free(phba,
+				sysfs_mbox->rcv_buff->virt,
+				sysfs_mbox->rcv_buff->phys);
+		kfree(sysfs_mbox->rcv_buff);
+	}
+
 	kfree(sysfs_mbox);
 }
 
+static size_t
+lpfc_syfs_mbox_copy_rcv_buff(struct lpfc_hba *phba,
+		struct lpfc_sysfs_mbox *sysfs_mbox,
+		char *buf, loff_t off, size_t count)
+{
+	uint32_t size;
+	spin_lock_irq(&phba->hbalock);
+	if (!sysfs_mbox->mbox) {
+		sysfs_mbox_idle(phba, sysfs_mbox);
+		spin_unlock_irq(&phba->hbalock);
+		return -EAGAIN;
+	}
+
+	size = sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize;
+
+	if ((count + off) > size) {
+		sysfs_mbox_idle(phba, sysfs_mbox);
+		spin_unlock_irq(&phba->hbalock);
+		return -ERANGE;
+	}
+
+	if (size > LPFC_BPL_SIZE) {
+		sysfs_mbox_idle(phba, sysfs_mbox);
+		spin_unlock_irq(&phba->hbalock);
+		return -ERANGE;
+	}
+
+	if (sysfs_mbox->extoff != off) {
+		sysfs_mbox_idle(phba, sysfs_mbox);
+		spin_unlock_irq(&phba->hbalock);
+		return -EAGAIN;
+	}
+
+	memcpy(buf, (uint8_t *) sysfs_mbox->rcv_buff->virt + off, count);
+	sysfs_mbox->extoff = off + count;
+
+	if (sysfs_mbox->extoff >= size)
+		sysfs_mbox_idle(phba, sysfs_mbox);
+
+	spin_unlock_irq(&phba->hbalock);
+
+	return count;
+}
+
+static size_t
+lpfc_syfs_mbox_copy_txmit_buff(struct lpfc_hba *phba,
+		struct lpfc_sysfs_mbox *sysfs_mbox,
+		char *buf, loff_t off, size_t count)
+{
+	uint32_t size;
+	spin_lock_irq(&phba->hbalock);
+	if (!sysfs_mbox->mbox ||
+		(sysfs_mbox->offset != MAILBOX_CMD_SIZE)) {
+		sysfs_mbox_idle(phba, sysfs_mbox);
+		spin_unlock_irq(&phba->hbalock);
+		return -EAGAIN;
+	}
+
+	size = sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.xmit_bde64.
+			tus.f.bdeSize;
+
+	if ((count + off) > size) {
+		sysfs_mbox_idle(phba, sysfs_mbox);
+		spin_unlock_irq(&phba->hbalock);
+		return -ERANGE;
+	}
+
+	if (size > LPFC_BPL_SIZE) {
+		sysfs_mbox_idle(phba, sysfs_mbox);
+		spin_unlock_irq(&phba->hbalock);
+		return -ERANGE;
+	}
+
+	if (sysfs_mbox->extoff != off) {
+		sysfs_mbox_idle(phba, sysfs_mbox);
+		spin_unlock_irq(&phba->hbalock);
+		return -EAGAIN;
+	}
+
+	memcpy((uint8_t *) sysfs_mbox->txmit_buff->virt + off, buf, count);
+	sysfs_mbox->extoff = off + count;
+
+	spin_unlock_irq(&phba->hbalock);
+
+	return count;
+}
+
 static ssize_t
 sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
 {
@@ -2010,9 +2310,8 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
 	struct lpfc_hba   *phba = vport->phba;
 	struct lpfcMboxq  *mbox = NULL;
 	struct lpfc_sysfs_mbox *sysfs_mbox;
-
-	if ((count + off) > MAILBOX_CMD_SIZE)
-		return -ERANGE;
+	uint8_t *ext;
+	uint32_t size;
 
 	if (off % 4 ||  count % 4 || (unsigned long)buf % 4)
 		return -EINVAL;
@@ -2021,24 +2320,103 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
 		return 0;
 
 	if (off == 0) {
-		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-		if (!mbox)
-			return -ENOMEM;
-		memset(mbox, 0, sizeof (LPFC_MBOXQ_t));
-	}
-
-	if (off == 0) {
 		sysfs_mbox = lpfc_get_sysfs_mbox(phba, 1);
-		if (sysfs_mbox == NULL) {
-			mempool_free(mbox, phba->mbox_mem_pool);
+		if (sysfs_mbox == NULL)
 			return -ENOMEM;
+		/*
+		 * If sysfs expect the reading of buffer and
+		 * app doesnot know how to do it, use a different
+		 * context.
+		 */
+		if (sysfs_mbox->state == SMBOX_READING_BUFF) {
+			spin_lock_irq(&phba->hbalock);
+			sysfs_mbox_idle(phba, sysfs_mbox);
+			spin_unlock_irq(&phba->hbalock);
+			sysfs_mbox = lpfc_get_sysfs_mbox(phba, 1);
+			if (sysfs_mbox == NULL)
+				return -ENOMEM;
 		}
 	} else {
 		sysfs_mbox = lpfc_get_sysfs_mbox(phba, 0);
-		if (sysfs_mbox == NULL) {
-			mempool_free(mbox, phba->mbox_mem_pool);
+		if (sysfs_mbox == NULL)
+			return -EAGAIN;
+	}
+
+	spin_lock_irq(&phba->hbalock);
+
+	if (sysfs_mbox->state == SMBOX_WRITING_MBEXT) {
+		if (!sysfs_mbox->mbox ||
+		    (sysfs_mbox->offset != MAILBOX_CMD_SIZE)) {
+			sysfs_mbox_idle(phba, sysfs_mbox);
+			spin_unlock_irq(&phba->hbalock);
+			return -EAGAIN;
+		}
+
+		size = sysfs_mbox->mbox->mb.un.varUpdateCfg.byte_cnt;
+
+		if ((count + off) > size) {
+			sysfs_mbox_idle(phba, sysfs_mbox);
+			spin_unlock_irq(&phba->hbalock);
+			return -ERANGE;
+		}
+
+		if (size > MAILBOX_EXT_SIZE) {
+			sysfs_mbox_idle(phba, sysfs_mbox);
+			spin_unlock_irq(&phba->hbalock);
+			return -ERANGE;
+		}
+
+		if (!sysfs_mbox->mbext) {
+			spin_unlock_irq(&phba->hbalock);
+
+			ext = kzalloc(size, GFP_KERNEL);
+			if (!ext) {
+				spin_lock_irq(&phba->hbalock);
+				sysfs_mbox_idle(phba, sysfs_mbox);
+				spin_unlock_irq(&phba->hbalock);
+				return -ENOMEM;
+			}
+
+			spin_lock_irq(&phba->hbalock);
+			sysfs_mbox->mbext = ext;
+		}
+
+		if (sysfs_mbox->extoff != off) {
+			sysfs_mbox_idle(phba, sysfs_mbox);
+			spin_unlock_irq(&phba->hbalock);
 			return -EAGAIN;
 		}
+
+		memcpy((uint8_t *) sysfs_mbox->mbext + off, buf, count);
+		sysfs_mbox->extoff = off + count;
+
+		spin_unlock_irq(&phba->hbalock);
+
+		return count;
+	}
+
+	spin_unlock_irq(&phba->hbalock);
+
+	if (sysfs_mbox->state == SMBOX_WRITING_BUFF)
+		return lpfc_syfs_mbox_copy_txmit_buff(phba,
+				sysfs_mbox, buf, off, count);
+
+	if ((count + off) > MAILBOX_CMD_SIZE) {
+		spin_lock_irq(&phba->hbalock);
+		sysfs_mbox_idle(phba, sysfs_mbox);
+		spin_unlock_irq(&phba->hbalock);
+		return -ERANGE;
+	}
+
+	if (off == 0) {
+		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+		if (!mbox) {
+			spin_lock_irq(&phba->hbalock);
+			sysfs_mbox_idle(phba, sysfs_mbox);
+			spin_unlock_irq(&phba->hbalock);
+			return -ENOMEM;
+		}
+		memset(mbox, 0, sizeof (LPFC_MBOXQ_t));
 	}
 
 	spin_lock_irq(&phba->hbalock);
@@ -2064,6 +2442,58 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
 
 	sysfs_mbox->offset = off + count;
 
+	if ((sysfs_mbox->offset == MAILBOX_CMD_SIZE) &&
+		(sysfs_mbox->mbox->mb.mbxCommand == MBX_UPDATE_CFG)) {
+		/* If no extension data just break */
+		if (sysfs_mbox->mbox->mb.un.varUpdateCfg.co)
+			sysfs_mbox->state = SMBOX_WRITING_MBEXT;
+	} else if ((sysfs_mbox->offset == MAILBOX_CMD_SIZE) &&
+		(sysfs_mbox->mbox->mb.mbxCommand == MBX_RUN_BIU_DIAG64)) {
+			sysfs_mbox->state = SMBOX_WRITING_BUFF;
+			spin_unlock_irq(&phba->hbalock);
+
+			/* Allocate txmit buffer */
+			sysfs_mbox->txmit_buff =
+				kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+			if (!sysfs_mbox->txmit_buff) {
+				spin_lock_irq(&phba->hbalock);
+				sysfs_mbox_idle(phba, sysfs_mbox);
+				spin_unlock_irq(&phba->hbalock);
+				return -ENOMEM;
+			}
+			INIT_LIST_HEAD(&sysfs_mbox->txmit_buff->list);
+			sysfs_mbox->txmit_buff->virt =
+				lpfc_mbuf_alloc(phba, 0,
+					&(sysfs_mbox->txmit_buff->phys));
+			if (!sysfs_mbox->txmit_buff->virt) {
+				spin_lock_irq(&phba->hbalock);
+				sysfs_mbox_idle(phba, sysfs_mbox);
+				spin_unlock_irq(&phba->hbalock);
+				return -ENOMEM;
+			}
+
+			/* Allocate rcv buffer */
+			sysfs_mbox->rcv_buff =
+				kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+			if (!sysfs_mbox->rcv_buff) {
+				spin_lock_irq(&phba->hbalock);
+				sysfs_mbox_idle(phba, sysfs_mbox);
+				spin_unlock_irq(&phba->hbalock);
+				return -ENOMEM;
+			}
+			INIT_LIST_HEAD(&sysfs_mbox->rcv_buff->list);
+			sysfs_mbox->rcv_buff->virt =
+				lpfc_mbuf_alloc(phba, 0,
+					&(sysfs_mbox->rcv_buff->phys));
+			if (!sysfs_mbox->rcv_buff->virt) {
+				spin_lock_irq(&phba->hbalock);
+				sysfs_mbox_idle(phba, sysfs_mbox);
+				spin_unlock_irq(&phba->hbalock);
+				return -ENOMEM;
+			}
+			return count;
+	}
+
 	spin_unlock_irq(&phba->hbalock);
 
 	return count;
@@ -2079,6 +2509,28 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
 	struct lpfc_hba   *phba = vport->phba;
 	int rc;
 	struct lpfc_sysfs_mbox *sysfs_mbox;
+	ssize_t ret;
+	sysfs_mbox = lpfc_get_sysfs_mbox(phba, 0);
+
+	if (!sysfs_mbox)
+		return -EPERM;
+
+	/*
+	 * If sysfs expect the writing of buffer and
+	 * app doesnot know how to do it, fail the mailbox
+	 * command.
+	 */
+	if (sysfs_mbox->state == SMBOX_WRITING_BUFF) {
+		spin_lock_irq(&phba->hbalock);
+		sysfs_mbox_idle(phba, sysfs_mbox);
+		spin_unlock_irq(&phba->hbalock);
+		return -EINVAL;
+	}
+	if (sysfs_mbox->state == SMBOX_READING_BUFF) {
+		ret = lpfc_syfs_mbox_copy_rcv_buff(phba, sysfs_mbox,
+					buf, off, count);
+		return ret;
+	}
 
 	if (off > MAILBOX_CMD_SIZE)
 		return -ERANGE;
@@ -2092,21 +2544,18 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
 	if (off && count == 0)
 		return 0;
 
-	sysfs_mbox = lpfc_get_sysfs_mbox(phba, 0);
-
-	if (!sysfs_mbox)
-		return -EPERM;
-
 	spin_lock_irq(&phba->hbalock);
 
 	if (phba->over_temp_state == HBA_OVER_TEMP) {
 		sysfs_mbox_idle(phba, sysfs_mbox);
 		spin_unlock_irq(&phba->hbalock);
-		return  -EPERM;
+		return  -EACCES;
 	}
 
 	if (off == 0 &&
-	    sysfs_mbox->state  == SMBOX_WRITING &&
+	    ((sysfs_mbox->state  == SMBOX_WRITING)  ||
+	    (sysfs_mbox->state  == SMBOX_WRITING_MBEXT) ||
+	    (sysfs_mbox->state  == SMBOX_WRITING_BUFF) ) &&
 	    sysfs_mbox->offset >= 2 * sizeof(uint32_t)) {
 
 		switch (sysfs_mbox->mbox->mb.mbxCommand) {
@@ -2121,9 +2570,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
 		case MBX_DUMP_CONTEXT:
 		case MBX_RUN_DIAGS:
 		case MBX_RESTART:
-		case MBX_FLASH_WR_ULA:
 		case MBX_SET_MASK:
-		case MBX_SET_SLIM:
 			if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
 				printk(KERN_WARNING "mbox_read:Command 0x%x "
 				       "is illegal in on-line state\n",
@@ -2144,14 +2591,50 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
 		case MBX_READ_LNK_STAT:
 		case MBX_DUMP_MEMORY:
 		case MBX_DOWN_LOAD:
-		case MBX_UPDATE_CFG:
 		case MBX_KILL_BOARD:
 		case MBX_LOAD_AREA:
 		case MBX_LOAD_EXP_ROM:
 		case MBX_BEACON:
 		case MBX_DEL_LD_ENTRY:
 		case MBX_SET_DEBUG:
+		case MBX_SET_VARIABLE:
+		case MBX_WRITE_WWN:
+			break;
+		case MBX_UPDATE_CFG:
+			if (sysfs_mbox->state == SMBOX_WRITING_MBEXT) {
+				if (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE)) {
+					sysfs_mbox_idle(phba, sysfs_mbox);
+					spin_unlock_irq(&phba->hbalock);
+					return -EPERM;
+				}
+				sysfs_mbox->mbox->context2 = sysfs_mbox->mbext;
+			}
+			break;
+		case MBX_RUN_BIU_DIAG64:
+			if (sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.
+				xmit_bde64.tus.f.bdeSize) {
+				sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.
+					xmit_bde64.addrHigh =
+					putPaddrHigh(sysfs_mbox->
+						txmit_buff->phys);
+				sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.
+					xmit_bde64.addrLow =
+					putPaddrLow(sysfs_mbox->
+						txmit_buff->phys);
+			}
+
+			if (sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.
+				rcv_bde64.tus.f.bdeSize) {
+				sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.
+					rcv_bde64.addrHigh =
+					putPaddrHigh(sysfs_mbox->
+						rcv_buff->phys);
+				sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.
+				rcv_bde64.addrLow =
+				putPaddrLow(sysfs_mbox->rcv_buff->phys);
+			}
 			break;
+
 		case MBX_READ_SPARM64:
 		case MBX_READ_LA:
 		case MBX_READ_LA64:
@@ -2219,6 +2702,14 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
 
 	sysfs_mbox->offset = off + count;
 
+	if ((sysfs_mbox->offset == MAILBOX_CMD_SIZE) &&
+		(sysfs_mbox->mbox->mb.mbxCommand == MBX_RUN_BIU_DIAG64)) {
+		sysfs_mbox->state  = SMBOX_READING_BUFF;
+		sysfs_mbox->extoff = 0;
+		spin_unlock_irq(&phba->hbalock);
+		return count;
+	}
+
 	if (sysfs_mbox->offset == MAILBOX_CMD_SIZE)
 		sysfs_mbox_idle(phba,sysfs_mbox);
 
@@ -2233,7 +2724,7 @@ static struct bin_attribute sysfs_mbox_attr = {
 		.mode = S_IRUSR | S_IWUSR,
 		.owner = THIS_MODULE,
 	},
-	.size = MAILBOX_CMD_SIZE,
+	.size = MAILBOX_MAX_XMIT_SIZE,
 	.read = sysfs_mbox_read,
 	.write = sysfs_mbox_write,
 };
@@ -2372,7 +2863,8 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
 				fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 			break;
 		}
-	}
+	} else
+		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 
 	spin_unlock_irq(shost->host_lock);
 }
@@ -2392,7 +2884,7 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost)
 		node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn);
 	else
 		/* fabric is local port if there is no F/FL_Port */
-		node_name = wwn_to_u64(vport->fc_nodename.u.wwn);
+		node_name = 0;
 
 	spin_unlock_irq(shost->host_lock);
 
@@ -2785,26 +3277,29 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
 	lpfc_multi_ring_type_init(phba, lpfc_multi_ring_type);
 	lpfc_ack0_init(phba, lpfc_ack0);
 	lpfc_topology_init(phba, lpfc_topology);
+	lpfc_pci_max_read_init(phba, lpfc_pci_max_read);
 	lpfc_link_speed_init(phba, lpfc_link_speed);
 	lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
 	lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
 	lpfc_use_msi_init(phba, lpfc_use_msi);
+	lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
+	lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
 	lpfc_dev_loss_initiator_init(phba, lpfc_dev_loss_initiator);
 	phba->cfg_poll = lpfc_poll;
 	phba->cfg_soft_wwnn = 0L;
 	phba->cfg_soft_wwpn = 0L;
-	/*
-	 * The total number of segments is the configuration value plus 2
-	 * since the IOCB need a command and response bde.
-	 */
-	phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2;
+	lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
+	/* Also reinitialize the host templates with new values. */
+	lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
+	lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
 	/*
 	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
-	 * used to create the sg_dma_buf_pool must be dynamically calculated
+	 * used to create the sg_dma_buf_pool must be dynamically calculated.
+	 * 2 segments are added since the IOCB needs a command and response bde.
 	 */
 	phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
 			sizeof(struct fcp_rsp) +
-			(phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
+			((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64));
 	lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
 	return;
 }
diff --git a/drivers/scsi/lpfc/lpfc_auth.c b/drivers/scsi/lpfc/lpfc_auth.c
index 6141c3c..de1f79a 100644
--- a/drivers/scsi/lpfc/lpfc_auth.c
+++ b/drivers/scsi/lpfc/lpfc_auth.c
@@ -17,7 +17,7 @@
  * more details, a copy of which can be found in the file COPYING  *
  * included with this package.                                     *
  *******************************************************************/
-
+/* See Fibre Channel protocol T11 FC-SP for details */
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 
@@ -185,22 +185,22 @@ lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message,
 	uint32_t param_len;
 	int i, j = 0;
 
-	/* Following is the format of the message.
+	/* Following is the format of the message. Name Format.
 	 * uint16_t  nameTag;
 	 * uint16_t  nameLength;
 	 * uint8_t   name[8];
+	 * AUTH_Negotiate Message
 	 * uint32_t  NumberOfAuthProtocals
 	 * uint32_t  AuthProtParameter#1Len
 	 * uint32_t  AuthProtID#1  (DH-CHAP = 0x1)
-
+	 * AUTH_Negotiate DH-CHAP
 	 * uint16_t  DH-CHAPParameterTag (HashList = 0x1)
 	 * uint16_t  DH-CHAPParameterWordCount (number of uint32_t entries)
-	 * uint8_t   DH-CHAPParameter[];
-
+	 * uint8_t   DH-CHAPParameter[]; (uint32_t entries)
 	 * uint16_t  DH-CHAPParameterTag (DHglDList = 0x2)
 	 * uint16_t  DH-CHAPParameterWordCount (number of uint32_t entries)
-	 * uint8_t   DH-CHAPParameter[];
-
+	 * uint8_t   DH-CHAPParameter[]; (uint32_t entries)
+	 * DHCHAP_Challenge Message
 	 * uint32_t  hashIdentifier;
 	 * uint32_t  dhgroupIdentifier;
 	 * uint32_t  challengevalueLen;
@@ -231,10 +231,10 @@ lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message,
 	}
 	message += sizeof(uint16_t);
 
-	/* Remote Port Name */
+	/* Skip over Remote Port Name */
 	message += NAME_LEN;
 
-	 /* Number of Auth Protocols */
+	 /* Number of Auth Protocols must be 1 DH-CHAP */
 	if (be32_to_cpu(*(uint32_t *)message) != 1) {
 		*reason = AUTH_ERR;
 		*explanation = BAD_PAYLOAD;
@@ -249,7 +249,7 @@ lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message,
 	prot_len = be32_to_cpu(*(uint32_t *)message);
 	message += sizeof(uint32_t);
 
-	/* Protocol Paramter type */
+	/* Protocol Parameter type */
 	if (be32_to_cpu(*(uint32_t *)message) != FC_DHCHAP) {
 		*reason = AUTH_ERR;
 		*explanation = BAD_PAYLOAD;
@@ -266,7 +266,7 @@ lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message,
 		*explanation = BAD_PAYLOAD;
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY,
 				 "1010 Bad Tag 1 0x%x\n",
-				 be32_to_cpu(*(uint16_t *)message));
+				 be16_to_cpu(*(uint16_t *)message));
 		return 1;
 	}
 	message += sizeof(uint16_t);
@@ -295,13 +295,13 @@ lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message,
 	vport->auth.hash_id = vport->auth.hash_priority[i];
 	message += sizeof(uint32_t) * param_len;
 
-	/* Parameter #2 Tag*/
+	/* Parameter #2 Tag */
 	if (be16_to_cpu(*(uint16_t *)message) != DHGID_LIST_TAG) {
 		*reason = AUTH_ERR;
 		*explanation = BAD_PAYLOAD;
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY,
 				 "1012 Auth_negotiate Bad Tag 2 0x%x\n",
-				 be32_to_cpu(*(uint16_t *)message));
+				 be16_to_cpu(*(uint16_t *)message));
 		return 1;
 	}
 	message += sizeof(uint16_t);
@@ -339,7 +339,7 @@ lpfc_unpack_dhchap_challenge(struct lpfc_vport *vport, uint8_t *message,
 {
 	int i;
 
-	/* Following is the format of the message.
+	/* Following is the format of the message DHCHAP_Challenge.
 	 * uint16_t  nameTag;
 	 * uint16_t  nameLength;
 	 * uint8_t   name[8];
@@ -461,7 +461,7 @@ lpfc_unpack_dhchap_reply(struct lpfc_vport *vport, uint8_t *message,
 	uint32_t dh_len;
 	uint32_t challenge_len;
 
-	/* Following is the format of the message.
+	/* Following is the format of the message DHCHAP_Reply.
 	 * uint32_t	Response Value Length;
 	 * uint8_t	Response Value[];
 	 * uint32_t	DH Value Length;
@@ -501,9 +501,9 @@ lpfc_unpack_dhchap_success(struct lpfc_vport *vport, uint8_t *message,
 {
 	uint32_t rsp_len = 0;
 
-	/*
+	/* DHCHAP_Success.
 	 * uint32_t  responseValueLen;
-	 * uint8_t  response[];
+	 * uint8_t   response[];
 	 */
 
 	rsp_len = be32_to_cpu(*(uint32_t *)message);   /* Response Len */
@@ -538,7 +538,7 @@ lpfc_build_auth_neg(struct lpfc_vport *vport, uint8_t *message)
 	/* Because some of the fields are not static in length
 	 * and number we will pack on the fly.This will be expanded
 	 * in the future to optionally offer DHCHAP or FCAP or both.
-	 * The packing is done in Big Endian byte order.
+	 * The packing is done in Big Endian byte order DHCHAP_Reply.
 	 *
 	 * uint16_t nameTag;
 	 * uint16_t nameLength;
@@ -644,7 +644,7 @@ lpfc_build_dhchap_challenge(struct lpfc_vport *vport, uint8_t *message,
 
 	/* Because some of the fields are not static in length and number
 	 * we will pack on the fly. The packing is done in Big Endian byte
-	 * order.
+	 * order DHCHAP_Challenge.
 	 *
 	 * uint16_t  nameTag;
 	 * uint16_t  nameLength;
@@ -654,7 +654,7 @@ lpfc_build_dhchap_challenge(struct lpfc_vport *vport, uint8_t *message,
 	 * uint32_t  Challenge_Value_Length;
 	 * uint8_t   Challenge_Value[];
 	 * uint32_t  DH_Value_Length;
-	 * uint8_t	  DH_Value[];
+	 * uint8_t   DH_Value[];
 	 */
 
 	/* Name Tag */
@@ -724,7 +724,7 @@ lpfc_build_dhchap_reply(struct lpfc_vport *vport, uint8_t *message,
 	/*
 	 * Because some of the fields are not static in length and
 	 * number we will pack on the fly. The packing is done in
-	 * Big Endian byte order.
+	 * Big Endian byte order DHCHAP_Reply.
 	 *
 	 * uint32_t  ResonseLength;
 	 * uint8_t   ResponseValue[];
@@ -741,22 +741,22 @@ lpfc_build_dhchap_reply(struct lpfc_vport *vport, uint8_t *message,
 	 * ( g^y mod p ) is our public key which we send.
 	 * ( g^x mod p ) is their public key which we received.
 	 */
-
+	/* Response Value Length */
 	*((uint32_t *)message) = cpu_to_be32(fc_rsp->u.dhchap_reply.
 		our_challenge_rsp_len);
 
 	message += sizeof(uint32_t);
-
+	/* Response Value */
 	memcpy(message, fc_rsp->u.dhchap_reply.data,
 		fc_rsp->u.dhchap_reply.our_challenge_rsp_len);
 
 	message += fc_rsp->u.dhchap_reply.our_challenge_rsp_len;
-
+	/* DH Value Length */
 	*((uint32_t *)message) = cpu_to_be32(fc_rsp->u.dhchap_reply.
 			our_public_key_len);
 
 	message += sizeof(uint32_t);
-
+	/* DH Value */
 	memcpy(message, fc_rsp->u.dhchap_reply.data +
 				fc_rsp->u.dhchap_reply.our_challenge_rsp_len,
 				fc_rsp->u.dhchap_reply.our_public_key_len);
@@ -779,11 +779,11 @@ lpfc_build_dhchap_reply(struct lpfc_vport *vport, uint8_t *message,
 		       fc_rsp->u.dhchap_reply.our_challenge_rsp_len +
 		       fc_rsp->u.dhchap_reply.our_public_key_len,
 		       fc_rsp->u.dhchap_reply.our_challenge_len);
-
+		/* Challenge Value Length */
 		*((uint32_t *)message) = cpu_to_be32(fc_rsp->u.
 			dhchap_reply.our_challenge_len);
 		message += sizeof(uint32_t);
-
+		/* Challenge Value */
 		memcpy(message, fc_rsp->u.dhchap_reply.data +
 			fc_rsp->u.dhchap_reply.our_challenge_rsp_len +
 			fc_rsp->u.dhchap_reply.our_public_key_len,
@@ -810,7 +810,9 @@ lpfc_build_dhchap_success(struct lpfc_vport *vport, uint8_t *message,
 	/*
 	 * Because some of the fields are not static in length and number
 	 * we will pack on the fly. The packing is done in Big Endian byte
-	 * order.
+	 * order DHCHAP_Success.
+	 * uint32_t  responseValueLen;
+	 * uint8_t   response[];.
 	 */
 
 	*((uint32_t *)message) = cpu_to_be32(fc_rsp->u.
diff --git a/drivers/scsi/lpfc/lpfc_auth_access.h b/drivers/scsi/lpfc/lpfc_auth_access.h
index 9cbe1d5..a57f3ba 100644
--- a/drivers/scsi/lpfc/lpfc_auth_access.h
+++ b/drivers/scsi/lpfc/lpfc_auth_access.h
@@ -20,27 +20,6 @@
 
 #define to_fc_internal(tmpl)	container_of(tmpl, struct fc_internal, t)
 
-#define NLMSG_ALIGNTO	4
-#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
-#define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
-#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
-#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
-#define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
-#define NLMSG_NEXT(nlh,len)	 ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
-				  (struct nlmsghdr*)(((char*)(nlh)) + \
-				NLMSG_ALIGN((nlh)->nlmsg_len)))
-#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
-			   (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
-			   (nlh)->nlmsg_len <= (len))
-#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
-
-#define NLMSG_NOOP		0x1	/* Nothing.		*/
-#define NLMSG_ERROR		0x2	/* Error		*/
-#define NLMSG_DONE		0x3	/* End of a dump	*/
-#define NLMSG_OVERRUN		0x4	/* Data lost		*/
-
-#define NLMSG_MIN_TYPE		0x10	/* < 0x10: reserved control messages */
-
 /* scsi_nl_hdr->version value */
 #define SCSI_NL_VERSION				1
 
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 663c263..52df6e2 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -42,6 +42,7 @@ void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
 int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
 		   LPFC_MBOXQ_t *, uint32_t);
+void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
 void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
 void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
 void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
@@ -102,6 +103,9 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
 int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
 		     struct serv_parm *, uint32_t);
 int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_more_plogi(struct lpfc_vport *);
+void lpfc_more_adisc(struct lpfc_vport *);
+void lpfc_end_rscn(struct lpfc_vport *);
 int lpfc_els_chk_latt(struct lpfc_vport *);
 struct lpfc_iocbq *lpfc_prep_els_iocb(struct lpfc_vport *, uint8_t, uint16_t,
 				      uint8_t, struct lpfc_nodelist *, uint32_t,
@@ -168,6 +172,7 @@ void lpfc_offline(struct lpfc_hba *);
 
 int lpfc_sli_setup(struct lpfc_hba *);
 int lpfc_sli_queue_setup(struct lpfc_hba *);
+int  lpfc_sli_set_dma_length(struct lpfc_hba *, uint32_t);
 
 void lpfc_handle_eratt(struct lpfc_hba *);
 void lpfc_handle_latt(struct lpfc_hba *);
@@ -223,6 +228,11 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
 struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
 					     struct lpfc_sli_ring *,
 					     dma_addr_t);
+
+uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *);
+struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *,
+			struct lpfc_sli_ring *, uint32_t );
+
 int lpfc_sli_hbq_count(void);
 int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
 int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
@@ -288,12 +298,13 @@ void lpfc_terminate_rport_io(struct fc_rport *);
 void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
 
 struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct device *);
-void lpfc_mbx_unreg_vpi(struct lpfc_vport *);
+int lpfc_mbx_unreg_vpi(struct lpfc_vport *);
 void destroy_port(struct lpfc_vport *);
 int lpfc_get_instance(void);
 void lpfc_host_attrib_init(struct Scsi_Host *);
 
-int lpfc_security_wait(void);
+int lpfc_selective_reset(struct lpfc_hba *);
+int lpfc_security_wait(struct lpfc_hba *);
 int  lpfc_get_security_enabled(struct Scsi_Host *);
 void lpfc_security_service_online(struct Scsi_Host *);
 void lpfc_security_service_offline(struct Scsi_Host *);
@@ -303,6 +314,7 @@ void lpfc_dhchap_make_challenge(struct Scsi_Host *, int , void *, uint32_t);
 void lpfc_dhchap_make_response(struct Scsi_Host *, int , void *, uint32_t);
 void lpfc_dhchap_authenticate(struct Scsi_Host *, int , void *, uint32_t);
 int lpfc_start_node_authentication(struct lpfc_nodelist *);
+int lpfc_get_auth_config(struct lpfc_nodelist *);
 void lpfc_start_discovery(struct lpfc_vport *vport);
 
 void lpfc_start_authentication(struct lpfc_vport *, struct lpfc_nodelist *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 3b0dd49..bbce374 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -19,7 +19,7 @@
  *******************************************************************/
 
 /*
- * Fibre Channel SCSI LAN Device Driver CT support
+ * Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS
  */
 
 #include <linux/blkdev.h>
@@ -57,45 +57,27 @@
 
 static char *lpfc_release_version = LPFC_DRIVER_VERSION;
 
-/*
- * lpfc_ct_unsol_event
- */
 static void
-lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
-		     struct lpfc_dmabuf *mp, uint32_t size)
+lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+			  struct lpfc_dmabuf *mp, uint32_t size)
 {
 	if (!mp) {
-		printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, "
-		       "piocbq = %p, status = x%x, mp = %p, size = %d\n",
-		       __FUNCTION__, __LINE__,
-		       piocbq, piocbq->iocb.ulpStatus, mp, size);
+		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+				"0146 Ignoring unsolicted CT No HBQ "
+				"status = x%x\n",
+				piocbq->iocb.ulpStatus);
 	}
-
-	printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, "
-	       "buffer = %p, size = %d, status = x%x\n",
-	       __FUNCTION__, __LINE__,
-	       piocbq, mp, size,
-	       piocbq->iocb.ulpStatus);
-
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"0145 Ignoring unsolicted CT HBQ Size:%d "
+			"status = x%x\n",
+			piocbq->iocb.ulpStatus, size);
 }
 
 static void
-lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
-			  struct lpfc_dmabuf *mp, uint32_t size)
+lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+		     struct lpfc_dmabuf *mp, uint32_t size)
 {
-	if (!mp) {
-		printk(KERN_ERR "%s (%d): Unsolited CT, no "
-		       "HBQ buffer, piocbq = %p, status = x%x\n",
-		       __FUNCTION__, __LINE__,
-		       piocbq, piocbq->iocb.ulpStatus);
-	} else {
-		lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
-		printk(KERN_ERR "%s (%d): Ignoring unsolicted CT "
-		       "piocbq = %p, buffer = %p, size = %d, "
-		       "status = x%x\n",
-		       __FUNCTION__, __LINE__,
-		       piocbq, mp, size, piocbq->iocb.ulpStatus);
-	}
+	lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size);
 }
 
 void
@@ -109,11 +91,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	struct lpfc_iocbq *iocbq;
 	dma_addr_t paddr;
 	uint32_t size;
-	struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
-	struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
-
-	piocbq->context2 = NULL;
-	piocbq->context3 = NULL;
+	struct list_head head;
+	struct lpfc_dmabuf *bdeBuf;
 
 	if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
 		lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
@@ -133,38 +112,34 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		return;
 
 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
-		list_for_each_entry(iocbq, &piocbq->list, list) {
+		INIT_LIST_HEAD(&head);
+		list_add_tail(&head, &piocbq->list);
+		list_for_each_entry(iocbq, &head, list) {
 			icmd = &iocbq->iocb;
-			if (icmd->ulpBdeCount == 0) {
-				printk(KERN_ERR "%s (%d): Unsolited CT, no "
-				       "BDE, iocbq = %p, status = x%x\n",
-				       __FUNCTION__, __LINE__,
-				       iocbq, iocbq->iocb.ulpStatus);
+			if (icmd->ulpBdeCount == 0)
 				continue;
-			}
-
+			bdeBuf = iocbq->context2;
+			iocbq->context2 = NULL;
 			size  = icmd->un.cont64[0].tus.f.bdeSize;
-			lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size);
-			lpfc_in_buf_free(phba, bdeBuf1);
+			lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
+			lpfc_in_buf_free(phba, bdeBuf);
 			if (icmd->ulpBdeCount == 2) {
-				lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2,
-							  size);
-				lpfc_in_buf_free(phba, bdeBuf2);
+				bdeBuf = iocbq->context3;
+				iocbq->context3 = NULL;
+				size  = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize;
+				lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf,
+						     size);
+				lpfc_in_buf_free(phba, bdeBuf);
 			}
 		}
+		list_del(&head);
 	} else {
 		struct lpfc_iocbq  *next;
 
 		list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
 			icmd = &iocbq->iocb;
-			if (icmd->ulpBdeCount == 0) {
-				printk(KERN_ERR "%s (%d): Unsolited CT, no "
-				       "BDE, iocbq = %p, status = x%x\n",
-				       __FUNCTION__, __LINE__,
-				       iocbq, iocbq->iocb.ulpStatus);
-				continue;
-			}
-
+			if (icmd->ulpBdeCount == 0)
+				lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0);
 			for (i = 0; i < icmd->ulpBdeCount; i++) {
 				paddr = getPaddr(icmd->un.cont64[i].addrHigh,
 						 icmd->un.cont64[i].addrLow);
@@ -203,7 +178,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
 	struct lpfc_dmabuf *mp;
 	int cnt, i = 0;
 
-	/* We get chucks of FCELSSIZE */
+	/* We get chunks of FCELSSIZE */
 	cnt = size > FCELSSIZE ? FCELSSIZE: size;
 
 	while (size) {
@@ -426,6 +401,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
 
 	lpfc_set_disctmo(vport);
 	vport->num_disc_nodes = 0;
+	vport->fc_ns_retry = 0;
 
 
 	list_add_tail(&head, &mp->list);
@@ -506,7 +482,17 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
 						Did, vport->fc_flag,
 						vport->fc_rscn_id_cnt);
 
-						if (lpfc_ns_cmd(vport,
+						/* This NPortID was previously
+						 * a FCP target, * Don't even
+						 * bother to send GFF_ID.
+						 */
+						ndlp = lpfc_findnode_did(vport,
+							Did);
+						if (ndlp && (ndlp->nlp_type &
+							NLP_FCP_TARGET))
+							lpfc_setup_disc_node
+								(vport, Did);
+						else if (lpfc_ns_cmd(vport,
 							SLI_CTNS_GFF_ID,
 							0, Did) == 0)
 							vport->num_disc_nodes++;
@@ -554,7 +540,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	struct lpfc_dmabuf *outp;
 	struct lpfc_sli_ct_request *CTrsp;
 	struct lpfc_nodelist *ndlp;
-	int rc;
+	int rc, retry;
 
 	/* First save ndlp, before we overwrite it */
 	ndlp = cmdiocb->context_un.ndlp;
@@ -585,14 +571,35 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	if (irsp->ulpStatus) {
 		/* Check for retry */
 		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
-			if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
-				(irsp->un.ulpWord[4] != IOERR_NO_RESOURCES))
+			retry = 1;
+			if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+				switch (irsp->un.ulpWord[4]) {
+				case IOERR_NO_RESOURCES:
+					/* We don't increment the retry
+					 * count for this case.
+					 */
+					break;
+				case IOERR_LINK_DOWN:
+				case IOERR_SLI_ABORTED:
+				case IOERR_SLI_DOWN:
+					retry = 0;
+					break;
+				default:
+					vport->fc_ns_retry++;
+				}
+			}
+			else
 				vport->fc_ns_retry++;
-			/* CT command is being retried */
-			rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
+
+			if (retry) {
+				/* CT command is being retried */
+				rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
 					 vport->fc_ns_retry, 0);
-			if (rc == 0)
-				goto out;
+				if (rc == 0) {
+					/* success */
+					goto out;
+				}
+			}
 		}
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -698,7 +705,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
 	struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
 	struct lpfc_sli_ct_request *CTrsp;
-	int did;
+	int did, rc, retry;
 	uint8_t fbits;
 	struct lpfc_nodelist *ndlp;
 
@@ -729,6 +736,39 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 		}
 	}
 	else {
+		/* Check for retry */
+		if (cmdiocb->retry < LPFC_MAX_NS_RETRY) {
+			retry = 1;
+			if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+				switch (irsp->un.ulpWord[4]) {
+				case IOERR_NO_RESOURCES:
+					/* We don't increment the retry
+					 * count for this case.
+					 */
+					break;
+				case IOERR_LINK_DOWN:
+				case IOERR_SLI_ABORTED:
+				case IOERR_SLI_DOWN:
+					retry = 0;
+					break;
+				default:
+					cmdiocb->retry++;
+				}
+			}
+			else
+				cmdiocb->retry++;
+
+			if (retry) {
+				/* CT command is being retried */
+				rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID,
+					 cmdiocb->retry, did);
+				if (rc == 0) {
+					/* success */
+					lpfc_ct_free_iocb(phba, cmdiocb);
+					return;
+				}
+			}
+		}
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
 				 "0267 NameServer GFF Rsp "
 				 "x%x Error (%d %d) Data: x%x x%x\n",
@@ -1110,7 +1150,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
 	case SLI_CTNS_GFF_ID:
 		CtReq->CommandResponse.bits.CmdRsp =
 			be16_to_cpu(SLI_CTNS_GFF_ID);
-		CtReq->un.gff.PortId = be32_to_cpu(context);
+		CtReq->un.gff.PortId = cpu_to_be32(context);
 		cmpl = lpfc_cmpl_ct_cmd_gff_id;
 		break;
 
@@ -1118,7 +1158,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
 		vport->ct_flags &= ~FC_CT_RFT_ID;
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RFT_ID);
-		CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID);
+		CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID);
 		CtReq->un.rft.fcpReg = 1;
 		cmpl = lpfc_cmpl_ct_cmd_rft_id;
 		break;
@@ -1127,7 +1167,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
 		vport->ct_flags &= ~FC_CT_RNN_ID;
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RNN_ID);
-		CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID);
+		CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
 		memcpy(CtReq->un.rnn.wwnn,  &vport->fc_nodename,
 		       sizeof (struct lpfc_name));
 		cmpl = lpfc_cmpl_ct_cmd_rnn_id;
@@ -1137,7 +1177,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
 		vport->ct_flags &= ~FC_CT_RSPN_ID;
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RSPN_ID);
-		CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID);
+		CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID);
 		size = sizeof(CtReq->un.rspn.symbname);
 		CtReq->un.rspn.len =
 			lpfc_vport_symbolic_port_name(vport,
@@ -1160,14 +1200,14 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
 		/* Implement DA_ID Nameserver request */
 		CtReq->CommandResponse.bits.CmdRsp =
 			be16_to_cpu(SLI_CTNS_DA_ID);
-		CtReq->un.da_id.port_id = be32_to_cpu(vport->fc_myDID);
+		CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID);
 		cmpl = lpfc_cmpl_ct_cmd_da_id;
 		break;
 	case SLI_CTNS_RFF_ID:
 		vport->ct_flags &= ~FC_CT_RFF_ID;
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RFF_ID);
-		CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);;
+		CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);;
 		CtReq->un.rff.fbits = FC4_FEATURE_INIT;
 		CtReq->un.rff.type_code = FC_FCP_DATA;
 		cmpl = lpfc_cmpl_ct_cmd_rff_id;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 0929c0e..783d1ee 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -43,7 +43,7 @@
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
 #include "lpfc_version.h"
-#include "lpfc_vport.h"
+#include "lpfc_compat.h"
 #include "lpfc_debugfs.h"
 
 #ifdef CONFIG_LPFC_DEBUG_FS
@@ -76,18 +76,18 @@ module_param(lpfc_debugfs_enable, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
 
 /* This MUST be a power of 2 */
-static int lpfc_debugfs_max_disc_trc = 0;
+static int lpfc_debugfs_max_disc_trc;
 module_param(lpfc_debugfs_max_disc_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
 	"Set debugfs discovery trace depth");
 
 /* This MUST be a power of 2 */
-static int lpfc_debugfs_max_slow_ring_trc = 0;
+static int lpfc_debugfs_max_slow_ring_trc;
 module_param(lpfc_debugfs_max_slow_ring_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
 	"Set debugfs slow ring trace depth");
 
-static int lpfc_debugfs_mask_disc_trc = 0;
+int lpfc_debugfs_mask_disc_trc;
 module_param(lpfc_debugfs_mask_disc_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
 	"Set debugfs discovery trace mask");
@@ -101,8 +101,11 @@ MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
 #define LPFC_NODELIST_SIZE 8192
 #define LPFC_NODELIST_ENTRY_SIZE 120
 
-/* dumpslim output buffer size */
-#define LPFC_DUMPSLIM_SIZE 4096
+/* dumpHBASlim output buffer size */
+#define LPFC_DUMPHBASLIM_SIZE 4096
+
+/* dumpHostSlim output buffer size */
+#define LPFC_DUMPHOSTSLIM_SIZE 4096
 
 /* hbqinfo output buffer size */
 #define LPFC_HBQINFO_SIZE 8192
@@ -299,18 +302,58 @@ skipit:
 	return len;
 }
 
+static int lpfc_debugfs_last_hba_slim_off;
+
+static int
+lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
+{
+	int len = 0;
+	int i, off;
+	uint32_t *ptr;
+	char buffer[1024];
+
+	off = 0;
+	spin_lock_irq(&phba->hbalock);
+
+	len +=  snprintf(buf+len, size-len, "HBA SLIM\n");
+	lpfc_memcpy_from_slim(buffer,
+		((uint8_t *)phba->MBslimaddr) + lpfc_debugfs_last_hba_slim_off,
+		1024);
+
+	ptr = (uint32_t *)&buffer[0];
+	off = lpfc_debugfs_last_hba_slim_off;
+
+	/* Set it up for the next time */
+	lpfc_debugfs_last_hba_slim_off += 1024;
+	if (lpfc_debugfs_last_hba_slim_off >= 4096)
+		lpfc_debugfs_last_hba_slim_off = 0;
+
+	i = 1024;
+	while (i > 0) {
+		len +=  snprintf(buf+len, size-len,
+		"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+		off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
+		*(ptr+5), *(ptr+6), *(ptr+7));
+		ptr += 8;
+		i -= (8 * sizeof(uint32_t));
+		off += (8 * sizeof(uint32_t));
+	}
+
+	spin_unlock_irq(&phba->hbalock);
+	return len;
+}
+
 static int
-lpfc_debugfs_dumpslim_data(struct lpfc_hba *phba, char *buf, int size)
+lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
 {
 	int len = 0;
-	int cnt, i, off;
+	int i, off;
 	uint32_t word0, word1, word2, word3;
 	uint32_t *ptr;
 	struct lpfc_pgp *pgpp;
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
 
-	cnt = LPFC_DUMPSLIM_SIZE;
 	off = 0;
 	spin_lock_irq(&phba->hbalock);
 
@@ -622,7 +665,34 @@ out:
 }
 
 static int
-lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
+lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file)
+{
+	struct lpfc_hba *phba = inode->i_private;
+	struct lpfc_debug *debug;
+	int rc = -ENOMEM;
+
+	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+	if (!debug)
+		goto out;
+
+	/* Round to page boundry */
+	debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL);
+	if (!debug->buffer) {
+		kfree(debug);
+		goto out;
+	}
+
+	debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer,
+		LPFC_DUMPHBASLIM_SIZE);
+	file->private_data = debug;
+
+	rc = 0;
+out:
+	return rc;
+}
+
+static int
+lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file)
 {
 	struct lpfc_hba *phba = inode->i_private;
 	struct lpfc_debug *debug;
@@ -633,14 +703,14 @@ lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
 		goto out;
 
 	/* Round to page boundry */
-	debug->buffer = kmalloc(LPFC_DUMPSLIM_SIZE, GFP_KERNEL);
+	debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL);
 	if (!debug->buffer) {
 		kfree(debug);
 		goto out;
 	}
 
-	debug->len = lpfc_debugfs_dumpslim_data(phba, debug->buffer,
-		LPFC_DUMPSLIM_SIZE);
+	debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer,
+		LPFC_DUMPHOSTSLIM_SIZE);
 	file->private_data = debug;
 
 	rc = 0;
@@ -743,10 +813,19 @@ static struct file_operations lpfc_debugfs_op_hbqinfo = {
 	.release =      lpfc_debugfs_release,
 };
 
-#undef lpfc_debugfs_op_dumpslim
-static struct file_operations lpfc_debugfs_op_dumpslim = {
+#undef lpfc_debugfs_op_dumpHBASlim
+static struct file_operations lpfc_debugfs_op_dumpHBASlim = {
+	.owner =        THIS_MODULE,
+	.open =         lpfc_debugfs_dumpHBASlim_open,
+	.llseek =       lpfc_debugfs_lseek,
+	.read =         lpfc_debugfs_read,
+	.release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpHostSlim
+static struct file_operations lpfc_debugfs_op_dumpHostSlim = {
 	.owner =        THIS_MODULE,
-	.open =         lpfc_debugfs_dumpslim_open,
+	.open =         lpfc_debugfs_dumpHostSlim_open,
 	.llseek =       lpfc_debugfs_lseek,
 	.read =         lpfc_debugfs_read,
 	.release =      lpfc_debugfs_release,
@@ -814,15 +893,27 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
 			goto debug_failed;
 		}
 
-		/* Setup dumpslim */
-		snprintf(name, sizeof(name), "dumpslim");
-		phba->debug_dumpslim =
+		/* Setup dumpHBASlim */
+		snprintf(name, sizeof(name), "dumpHBASlim");
+		phba->debug_dumpHBASlim =
+			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+				 phba->hba_debugfs_root,
+				 phba, &lpfc_debugfs_op_dumpHBASlim);
+		if (!phba->debug_dumpHBASlim) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				"0409 Cannot create debugfs dumpHBASlim\n");
+			goto debug_failed;
+		}
+
+		/* Setup dumpHostSlim */
+		snprintf(name, sizeof(name), "dumpHostSlim");
+		phba->debug_dumpHostSlim =
 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
 				 phba->hba_debugfs_root,
-				 phba, &lpfc_debugfs_op_dumpslim);
-		if (!phba->debug_dumpslim) {
+				 phba, &lpfc_debugfs_op_dumpHostSlim);
+		if (!phba->debug_dumpHostSlim) {
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
-				"0409 Cannot create debugfs dumpslim\n");
+				"0409 Cannot create debugfs dumpHostSlim\n");
 			goto debug_failed;
 		}
 
@@ -903,7 +994,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
 		}
 	}
 
-	vport->disc_trc = kmalloc(
+	vport->disc_trc = kzalloc(
 		(sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc),
 		GFP_KERNEL);
 
@@ -914,8 +1005,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
 		goto debug_failed;
 	}
 	atomic_set(&vport->disc_trc_cnt, 0);
-	memset(vport->disc_trc, 0,
-		(sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc));
 
 	snprintf(name, sizeof(name), "discovery_trace");
 	vport->debug_disc_trc =
@@ -974,9 +1063,13 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
 			debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
 			phba->debug_hbqinfo = NULL;
 		}
-		if (phba->debug_dumpslim) {
-			debugfs_remove(phba->debug_dumpslim); /* dumpslim */
-			phba->debug_dumpslim = NULL;
+		if (phba->debug_dumpHBASlim) {
+			debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */
+			phba->debug_dumpHBASlim = NULL;
+		}
+		if (phba->debug_dumpHostSlim) {
+			debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */
+			phba->debug_dumpHostSlim = NULL;
 		}
 		if (phba->slow_ring_trc) {
 			kfree(phba->slow_ring_trc);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 94138fb..7ed27c3 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -18,7 +18,7 @@
  * more details, a copy of which can be found in the file COPYING  *
  * included with this package.                                     *
  *******************************************************************/
-
+/* See Fibre Channel protocol T11 FC-LS for details */
 #include <linux/blkdev.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
@@ -386,11 +386,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		}
 		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
 			lpfc_mbx_unreg_vpi(vport);
+			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+			spin_unlock_irq(shost->host_lock);
 		}
 	}
 
-	ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
 
 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
@@ -478,6 +479,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		lpfc_nlp_put(ndlp);
 	}
 
+	/* If we are pt2pt with another NPort, force NPIV off! */
+	phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
+
 	spin_lock_irq(shost->host_lock);
 	vport->fc_flag |= FC_PT2PT;
 	spin_unlock_irq(shost->host_lock);
@@ -565,8 +569,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			lpfc_printf_log(vport->phba,
 				KERN_WARNING,
 				LOG_SECURITY,
-				"%d:1030 Security config request: no buffers\n",
-				vport->phba->brd_no);
+				"1030 Security config request: no buffers\n");
 			phba->link_state = LPFC_HBA_ERROR;
 			goto flogifail;
 		}
@@ -802,11 +805,11 @@ lpfc_initial_fdisc(struct lpfc_vport *vport)
 	struct lpfc_nodelist *ndlp;
 
 	if (vport->cfg_enable_auth) {
-		lpfc_security_wait();
-		if (lpfc_security_service_state == SECURITY_OFFLINE) {
+		if (lpfc_security_wait(phba)) {
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY,
-					 "1049 Security is enabled but no "
-					 "security service!\n");
+					 "1049 Authentication is enabled but "
+					 "authentication service is not "
+					 "running\n");
 			vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN;
 			return 0;
 		}
@@ -828,7 +831,8 @@ lpfc_initial_fdisc(struct lpfc_vport *vport)
 	}
 	return 1;
 }
-static void
+
+void
 lpfc_more_plogi(struct lpfc_vport *vport)
 {
 	int sentplogi;
@@ -856,6 +860,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
 {
 	struct lpfc_vport    *vport = ndlp->vport;
 	struct lpfc_nodelist *new_ndlp;
+	struct lpfc_rport_data *rdata;
+	struct fc_rport *rport;
 	struct serv_parm *sp;
 	uint8_t  name[sizeof(struct lpfc_name)];
 	uint32_t rc;
@@ -892,6 +898,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
 	lpfc_unreg_rpi(vport, new_ndlp);
 	new_ndlp->nlp_DID = ndlp->nlp_DID;
 	new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
+
+	if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
+		new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+
 	lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
 
 	/* Move this back to NPR state */
@@ -899,6 +910,20 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
 		/* The new_ndlp is replacing ndlp totally, so we need
 		 * to put ndlp on UNUSED list and try to free it.
 		 */
+
+		/* Fix up the rport accordingly */
+		rport =  ndlp->rport;
+		if (rport) {
+			rdata = rport->dd_data;
+			if (rdata->pnode == ndlp) {
+				lpfc_nlp_put(ndlp);
+				ndlp->rport = NULL;
+				rdata->pnode = lpfc_nlp_get(new_ndlp);
+				new_ndlp->rport = rport;
+			}
+			new_ndlp->nlp_type = ndlp->nlp_type;
+		}
+
 		lpfc_drop_node(vport, ndlp);
 	}
 	else {
@@ -909,6 +934,27 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
 	return new_ndlp;
 }
 
+void
+lpfc_end_rscn(struct lpfc_vport *vport)
+{
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+	if (vport->fc_flag & FC_RSCN_MODE) {
+		/*
+		 * Check to see if more RSCNs came in while we were
+		 * processing this one.
+		 */
+		if (vport->fc_rscn_id_cnt ||
+		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
+			lpfc_els_handle_rscn(vport);
+		else {
+			spin_lock_irq(shost->host_lock);
+			vport->fc_flag &= ~FC_RSCN_MODE;
+			spin_unlock_irq(shost->host_lock);
+		}
+	}
+}
+
 static void
 lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 		    struct lpfc_iocbq *rspiocb)
@@ -1006,20 +1052,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			spin_unlock_irq(shost->host_lock);
 
 			lpfc_can_disctmo(vport);
-			if (vport->fc_flag & FC_RSCN_MODE) {
-				/*
-				 * Check to see if more RSCNs came in while
-				 * we were processing this one.
-				 */
-				if ((vport->fc_rscn_id_cnt == 0) &&
-				    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
-					spin_lock_irq(shost->host_lock);
-					vport->fc_flag &= ~FC_RSCN_MODE;
-					spin_unlock_irq(shost->host_lock);
-				} else {
-					lpfc_els_handle_rscn(vport);
-				}
-			}
+			lpfc_end_rscn(vport);
 		}
 	}
 
@@ -1214,7 +1247,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	return 0;
 }
 
-static void
+void
 lpfc_more_adisc(struct lpfc_vport *vport)
 {
 	int sentadisc;
@@ -1239,8 +1272,6 @@ lpfc_more_adisc(struct lpfc_vport *vport)
 static void
 lpfc_rscn_disc(struct lpfc_vport *vport)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
 	lpfc_can_disctmo(vport);
 
 	/* RSCN discovery */
@@ -1249,19 +1280,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport)
 		if (lpfc_els_disc_plogi(vport))
 			return;
 
-	if (vport->fc_flag & FC_RSCN_MODE) {
-		/* Check to see if more RSCNs came in while we were
-		 * processing this one.
-		 */
-		if ((vport->fc_rscn_id_cnt == 0) &&
-		    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
-			spin_lock_irq(shost->host_lock);
-			vport->fc_flag &= ~FC_RSCN_MODE;
-			spin_unlock_irq(shost->host_lock);
-		} else {
-			lpfc_els_handle_rscn(vport);
-		}
-	}
+	lpfc_end_rscn(vport);
 }
 
 static void
@@ -1711,27 +1730,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
 	return 0;
 }
 
-static void
-lpfc_end_rscn(struct lpfc_vport *vport)
-{
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
-	if (vport->fc_flag & FC_RSCN_MODE) {
-		/*
-		 * Check to see if more RSCNs came in while we were
-		 * processing this one.
-		 */
-		if (vport->fc_rscn_id_cnt ||
-		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
-			lpfc_els_handle_rscn(vport);
-		else {
-			spin_lock_irq(shost->host_lock);
-			vport->fc_flag &= ~FC_RSCN_MODE;
-			spin_unlock_irq(shost->host_lock);
-		}
-	}
-}
-
 void
 lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
 {
@@ -2159,6 +2157,32 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 }
 
 int
+lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1)
+{
+	struct lpfc_dmabuf *buf_ptr;
+
+	/* Free the response before processing the command.  */
+	if (!list_empty(&buf_ptr1->list)) {
+		list_remove_head(&buf_ptr1->list, buf_ptr,
+				 struct lpfc_dmabuf,
+				 list);
+		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+		kfree(buf_ptr);
+	}
+	lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
+	kfree(buf_ptr1);
+	return 0;
+}
+
+int
+lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr)
+{
+	lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+	kfree(buf_ptr);
+	return 0;
+}
+
+int
 lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
 {
 	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
@@ -2185,23 +2209,41 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
 	}
 	/* context2  = cmd,  context2->next = rsp, context3 = bpl */
 	if (elsiocb->context2) {
-		buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
-		/* Free the response before processing the command.  */
-		if (!list_empty(&buf_ptr1->list)) {
-			list_remove_head(&buf_ptr1->list, buf_ptr,
-					 struct lpfc_dmabuf,
-					 list);
-			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-			kfree(buf_ptr);
+		if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) {
+			/* Firmware could still be in progress of DMAing
+			 * payload, so don't free data buffer till after
+			 * a hbeat.
+			 */
+			elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE;
+			buf_ptr = elsiocb->context2;
+			elsiocb->context2 = NULL;
+			if (buf_ptr) {
+				buf_ptr1 = NULL;
+				spin_lock_irq(&phba->hbalock);
+				if (!list_empty(&buf_ptr->list)) {
+					list_remove_head(&buf_ptr->list,
+						buf_ptr1, struct lpfc_dmabuf,
+						list);
+					INIT_LIST_HEAD(&buf_ptr1->list);
+					list_add_tail(&buf_ptr1->list,
+						&phba->elsbuf);
+					phba->elsbuf_cnt++;
+				}
+				INIT_LIST_HEAD(&buf_ptr->list);
+				list_add_tail(&buf_ptr->list, &phba->elsbuf);
+				phba->elsbuf_cnt++;
+				spin_unlock_irq(&phba->hbalock);
+			}
+		}
+		else {
+			buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
+			lpfc_els_free_data(phba, buf_ptr1);
 		}
-		lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
-		kfree(buf_ptr1);
 	}
 
 	if (elsiocb->context3) {
 		buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
-		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-		kfree(buf_ptr);
+		lpfc_els_free_bpl(phba, buf_ptr);
 	}
 	lpfc_sli_release_iocbq(phba, elsiocb);
 	return 0;
@@ -2831,7 +2873,10 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport)
 			}
 		}
 	}
-	if (sentplogi == 0) {
+	if (sentplogi) {
+		lpfc_set_disctmo(vport);
+	}
+	else {
 		spin_lock_irq(shost->host_lock);
 		vport->fc_flag &= ~FC_NLP_MORE;
 		spin_unlock_irq(shost->host_lock);
@@ -3019,10 +3064,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 			"RCV RSCN defer:  did:x%x/ste:x%x flg:x%x",
 			ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
 
+		spin_lock_irq(shost->host_lock);
 		vport->fc_flag |= FC_RSCN_DEFERRED;
 		if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
 		    !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
-			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_RSCN_MODE;
 			spin_unlock_irq(shost->host_lock);
 			if (rscn_cnt) {
@@ -3051,7 +3096,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 					 vport->fc_rscn_id_cnt, vport->fc_flag,
 					 vport->port_state);
 		} else {
-			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_RSCN_DISCOVERY;
 			spin_unlock_irq(shost->host_lock);
 			/* ReDiscovery RSCN */
@@ -3066,7 +3110,9 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 
 		/* send RECOVERY event for ALL nodes that match RSCN payload */
 		lpfc_rscn_recovery_check(vport);
+		spin_lock_irq(shost->host_lock);
 		vport->fc_flag &= ~FC_RSCN_DEFERRED;
+		spin_unlock_irq(shost->host_lock);
 		return 0;
 	}
 
@@ -3118,6 +3164,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
 
 	/* To process RSCN, first compare RSCN data with NameServer */
 	vport->fc_ns_retry = 0;
+	vport->num_disc_nodes = 0;
+
 	ndlp = lpfc_findnode_did(vport, NameServer_DID);
 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
 		/* Good ndlp, issue CT Request to NameServer */
@@ -3348,13 +3396,13 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 		status |= 0x4;
 
 	rps_rsp->rsvd1 = 0;
-	rps_rsp->portStatus = be16_to_cpu(status);
-	rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
-	rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
-	rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
-	rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
-	rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
-	rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
+	rps_rsp->portStatus = cpu_to_be16(status);
+	rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
+	rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
+	rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
+	rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
+	rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
+	rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
 	/* Xmit ELS RPS ACC response tag <ulpIoTag> */
 	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
 			 "0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
@@ -4038,6 +4086,7 @@ lpfc_els_rcv_auth_rjt(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 	uint32_t message_len;
 	uint32_t trans_id;
 	struct lpfc_auth_reject *rjt;
+	struct lpfc_hba *phba = vport->phba;
 
 	authcmd = pcmd->virt;
 	rjt = (struct lpfc_auth_reject *)authcmd->data;
@@ -4047,7 +4096,6 @@ lpfc_els_rcv_auth_rjt(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 
 	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
 
-
 	if (vport->auth.auth_state == LPFC_AUTH_SUCCESS) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY,
 				 "1036 Authentication transaction reject - "
@@ -4069,11 +4117,15 @@ lpfc_els_rcv_auth_rjt(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 			lpfc_start_authentication(vport, ndlp);
 		} else {
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY,
-				"%d:1038 Authentication transaction "
+				"1057 Authentication transaction "
 				"reject. reason 0x%x exp 0x%x\n",
-				vport->phba->brd_no,
 				rjt->reason, rjt->explanation);
 			vport->auth.auth_msg_state = LPFC_AUTH_REJECT;
+			if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+			    (phba->link_state != LPFC_CLEAR_LA)) {
+				/* If Auth failed enable link interrupt. */
+				lpfc_issue_clear_la(phba, vport);
+			}
 		}
 	}
 }
@@ -4240,6 +4292,7 @@ lpfc_els_rcv_chap_suc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 				"1042 Re-Authentication Successful\n");
 		}
 		/* If config requires re-authentication start the timer */
+		vport->auth.last_auth = jiffies;
 		if (vport->auth.reauth_interval)
 			mod_timer(&ndlp->nlp_reauth_tmr, jiffies +
 				vport->auth.reauth_interval * 60 * HZ);
@@ -4709,7 +4762,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
 	MAILBOX_t *mb = &pmb->mb;
 
+	spin_lock_irq(shost->host_lock);
 	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+	spin_unlock_irq(shost->host_lock);
 	lpfc_nlp_put(ndlp);
 
 	if (mb->mbxStatus) {
@@ -4730,7 +4785,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 		default:
 			/* Try to recover from this error */
 			lpfc_mbx_unreg_vpi(vport);
+			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+			spin_unlock_irq(shost->host_lock);
 			lpfc_initial_fdisc(vport);
 			break;
 		}
@@ -4752,6 +4809,7 @@ void
 lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
 			struct lpfc_nodelist *ndlp)
 {
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	LPFC_MBOXQ_t *mbox;
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -4763,7 +4821,9 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
 		if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
 		    == MBX_NOT_FINISHED) {
 			mempool_free(mbox, phba->mbox_mem_pool);
+			spin_lock_irq(shost->host_lock);
 			vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+			spin_unlock_irq(shost->host_lock);
 
 			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
@@ -4775,7 +4835,9 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
 				 "0254 Register VPI: no memory\n");
 
+		spin_lock_irq(shost->host_lock);
 		vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+		spin_unlock_irq(shost->host_lock);
 		lpfc_nlp_put(ndlp);
 	}
 }
@@ -4835,8 +4897,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			GFP_KERNEL)) == 0) {
 			lpfc_printf_log(vport->phba,
 				KERN_WARNING, LOG_SECURITY,
-				"%d:1050 Security config request: no buffers\n",
-				vport->phba->brd_no);
+				"1050 Security config request: no buffers\n");
 			goto fdisc_failed;
 		}
 		vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN;
@@ -4845,7 +4906,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			auth_rsp, sizeof(struct fc_auth_rsp))) {
 			kfree(auth_rsp);
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY,
-					 "1053 Unable to get security "
+					 "1054 Unable to get security "
 					 "config.\n");
 			goto fdisc_failed;
 		}
@@ -4902,7 +4963,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			lpfc_unreg_rpi(vport, np);
 		}
 		lpfc_mbx_unreg_vpi(vport);
+		spin_lock_irq(shost->host_lock);
 		vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+		spin_unlock_irq(shost->host_lock);
 	}
 
 	if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
@@ -5383,11 +5446,12 @@ lpfc_cmpl_els_auth(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			}
 			if (vport->auth.auth_mode == FC_AUTHMODE_ACTIVE) {
 				lpfc_can_disctmo(vport);
-				lpfc_nlp_set_state(vport, ndlp,
-						   NLP_STE_NPR_NODE);
-				lpfc_issue_els_logo(vport, ndlp, 0);
+				lpfc_port_auth_failed(ndlp);
 			}
 		}
+		if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+		    (phba->link_state != LPFC_CLEAR_LA))
+			lpfc_issue_clear_la(phba, vport);
 		lpfc_els_free_iocb(phba, cmdiocb);
 		return;
 	}
@@ -5419,6 +5483,7 @@ lpfc_cmpl_els_auth(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			}
 		}
 		/* restart authentication timer */
+		vport->auth.last_auth = jiffies;
 		if (vport->auth.reauth_interval)
 			mod_timer(&ndlp->nlp_reauth_tmr,
 				jiffies +
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 1caf802..c442d52 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -77,7 +77,7 @@ lpfc_start_discovery(struct lpfc_vport *vport)
 	}
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
 				continue;
 			if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
@@ -90,7 +90,7 @@ lpfc_start_discovery(struct lpfc_vport *vport)
 						 "support\n");
 			}
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	lpfc_do_scr_ns_plogi(phba, vport);
 }
 
@@ -149,15 +149,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
 
 	rdata = rport->dd_data;
 	ndlp = rdata->pnode;
-
-	if (!ndlp) {
-		if (rport->scsi_target_id != -1) {
-			printk(KERN_ERR "Cannot find remote node"
-				" for rport in dev_loss_tmo_callbk x%x\n",
-				rport->port_id);
-		}
+	if (!ndlp)
 		return;
-	}
 
 	vport = ndlp->vport;
 	phba  = vport->phba;
@@ -237,6 +230,12 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
 	 * appropriately we just need to cleanup the ndlp rport info here.
 	 */
 	if (vport->load_flag & FC_UNLOADING) {
+		if (ndlp->nlp_sid != NLP_NO_SID) {
+			/* flush the target */
+			lpfc_sli_abort_iocb(vport,
+					&phba->sli.ring[phba->sli.fcp_ring],
+					ndlp->nlp_sid, 0, LPFC_CTX_TGT);
+		}
 		put_node = rdata->pnode != NULL;
 		put_rport = ndlp->rport != NULL;
 		rdata->pnode = NULL;
@@ -463,7 +462,7 @@ lpfc_work_done(struct lpfc_hba *phba)
 		lpfc_handle_latt(phba);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS; i++) {
+		for(i = 0; i <= phba->max_vpi; i++) {
 			/*
 			 * We could have no vports in array if unloading, so if
 			 * this happens then just use the pport
@@ -495,7 +494,7 @@ lpfc_work_done(struct lpfc_hba *phba)
 			vport->work_port_events &= ~work_port_events;
 			spin_unlock_irq(&vport->work_port_lock);
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 
 	pring = &phba->sli.ring[LPFC_ELS_RING];
 	status = (ha_copy & (HA_RXMASK  << (4*LPFC_ELS_RING)));
@@ -539,23 +538,21 @@ check_work_wait_done(struct lpfc_hba *phba)
 {
 	struct lpfc_vport *vport;
 	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
-	int rc = 0;
 
 	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry(vport, &phba->port_list, listentry) {
 		if (vport->work_port_events) {
-			rc = 1;
-			break;
+			spin_unlock_irq(&phba->hbalock);
+			return 1;
 		}
 	}
-	if (rc || phba->work_ha || (!list_empty(&phba->work_list)) ||
+	if (phba->work_ha || (!list_empty(&phba->work_list)) ||
 	    kthread_should_stop() || pring->flag & LPFC_DEFERRED_RING_EVENT) {
-		rc = 1;
-		phba->work_found++;
-	} else
-		phba->work_found = 0;
+		spin_unlock_irq(&phba->hbalock);
+		return 1;
+	}
 	spin_unlock_irq(&phba->hbalock);
-	return rc;
+	return 0;
 }
 
 
@@ -568,7 +565,6 @@ lpfc_do_work(void *p)
 
 	set_user_nice(current, -20);
 	phba->work_wait = &work_waitq;
-	phba->work_found = 0;
 
 	while (1) {
 
@@ -581,18 +577,6 @@ lpfc_do_work(void *p)
 			break;
 
 		lpfc_work_done(phba);
-
-		/* If there is alot of slow ring work, like during link up
-		 * check_work_wait_done() may cause this thread to not give
-		 * up the CPU for very long periods of time. This may cause
-		 * soft lockups or other problems. To avoid these situations
-		 * give up the CPU here after LPFC_MAX_WORKER_ITERATION
-		 * consecutive iterations.
-		 */
-		if (phba->work_found >= LPFC_MAX_WORKER_ITERATION) {
-			phba->work_found = 0;
-			schedule();
-		}
 	}
 	phba->work_wait = NULL;
 	return 0;
@@ -634,6 +618,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
 void
 lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
 {
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
 	struct lpfc_nodelist *ndlp, *next_ndlp;
 	int  rc;
@@ -659,8 +644,10 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
 					     : NLP_EVT_DEVICE_RECOVERY);
 	}
 	if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) {
-		lpfc_mbx_unreg_vpi(vport);
+		rc = lpfc_mbx_unreg_vpi(vport);
+		spin_lock_irq(shost->host_lock);
 		vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+		spin_unlock_irq(shost->host_lock);
 	}
 }
 
@@ -706,6 +693,7 @@ lpfc_port_auth_failed(struct lpfc_nodelist *ndlp)
 	struct lpfc_vport *vport = ndlp->vport;
 
 	vport->auth.auth_state = LPFC_AUTH_FAIL;
+	vport->auth.auth_msg_state = LPFC_AUTH_NONE;
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 	if (ndlp->nlp_type & NLP_FABRIC) {
 		lpfc_port_link_failure (vport);
@@ -734,11 +722,11 @@ lpfc_linkdown(struct lpfc_hba *phba)
 	spin_unlock_irq(&phba->hbalock);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			/* Issue a LINK DOWN event to all nodes */
 			lpfc_linkdown_port(vports[i]);
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	/* Clean up any firmware default rpi's */
 	mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (mb) {
@@ -843,9 +831,9 @@ lpfc_linkup(struct lpfc_hba *phba)
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
 			lpfc_linkup_port(vports[i]);
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
 		lpfc_issue_clear_la(phba, phba->pport);
 
@@ -1310,7 +1298,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 		scsi_host_put(shost);
 }
 
-void
+int
 lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
 {
 	struct lpfc_hba  *phba = vport->phba;
@@ -1319,7 +1307,7 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!mbox)
-		return;
+		return 1;
 
 	lpfc_unreg_vpi(phba, vport->vpi, mbox);
 	mbox->vport = vport;
@@ -1330,7 +1318,9 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
 				 "1800 Could not issue unreg_vpi\n");
 		mempool_free(mbox, phba->mbox_mem_pool);
 		vport->unreg_vpi_cmpl = VPORT_ERROR;
+		return rc;
 	}
+	return 0;
 }
 
 static void
@@ -1989,7 +1979,8 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport)
 		lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox);
 		mbox->vport = vport;
 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+		mbox->context1 = NULL;
+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
 		if (rc == MBX_NOT_FINISHED) {
 			mempool_free(mbox, phba->mbox_mem_pool);
 		}
@@ -2008,7 +1999,8 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport)
 		lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox);
 		mbox->vport = vport;
 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+		mbox->context1 = NULL;
+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
 		if (rc == MBX_NOT_FINISHED) {
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
 					 "1815 Could not issue "
@@ -2655,6 +2647,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 		}
 		if (vport->port_state != LPFC_FLOGI) {
 			lpfc_initial_flogi(vport);
+			return;
 		}
 		break;
 
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index fddca02..5fc08c6 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1303,7 +1303,7 @@ typedef struct {		/* FireFly BIU registers */
 #define MBX_DEL_LD_ENTRY    0x1D
 #define MBX_RUN_PROGRAM     0x1E
 #define MBX_SET_MASK        0x20
-#define MBX_SET_SLIM        0x21
+#define MBX_SET_VARIABLE    0x21
 #define MBX_UNREG_D_ID      0x23
 #define MBX_KILL_BOARD      0x24
 #define MBX_CONFIG_FARP     0x25
@@ -1325,7 +1325,7 @@ typedef struct {		/* FireFly BIU registers */
 #define MBX_REG_VNPID	    0x96
 #define MBX_UNREG_VNPID	    0x97
 
-#define MBX_FLASH_WR_ULA    0x98
+#define MBX_WRITE_WWN       0x98
 #define MBX_SET_DEBUG       0x99
 #define MBX_LOAD_EXP_ROM    0x9C
 
@@ -1397,6 +1397,7 @@ typedef struct {		/* FireFly BIU registers */
 #define CMD_FCP_TRECEIVE64_CX   0xA1
 #define CMD_FCP_TRSP64_CX       0xA3
 
+#define CMD_QUE_XRI64_CX	0xB3
 #define CMD_IOCB_RCV_SEQ64_CX	0xB5
 #define CMD_IOCB_RCV_ELS64_CX	0xB7
 #define CMD_IOCB_RCV_CONT64_CX	0xBB
@@ -1430,6 +1431,7 @@ typedef struct {		/* FireFly BIU registers */
 #define MBXERR_BAD_RCV_LENGTH       14
 #define MBXERR_DMA_ERROR            15
 #define MBXERR_ERROR                16
+#define MBXERR_UNKNOWN_CMD          18
 #define MBX_NOT_FINISHED           255
 
 #define MBX_BUSY                   0xffffff /* Attempted cmd to busy Mailbox */
@@ -2297,6 +2299,14 @@ typedef struct {
 	uint32_t rsvd1;
 } CLEAR_LA_VAR;
 
+/* Structure for MB Command SET_SLIM (33) */
+/* Values needed to set MAX_DMA_LENGTH parameter */
+#define SLIM_VAR_MAX_DMA_LENGTH 0x100506
+#define SLIM_VAL_MAX_DMA_512    0x0
+#define SLIM_VAL_MAX_DMA_1024   0x1
+#define SLIM_VAL_MAX_DMA_2048   0x2
+#define SLIM_VAL_MAX_DMA_4096   0x3
+
 /* Structure for MB Command DUMP */
 
 typedef struct {
@@ -2331,6 +2341,37 @@ typedef struct {
 #define  DMP_RSP_OFFSET          0x14   /* word 5 contains first word of rsp */
 #define  DMP_RSP_SIZE            0x6C   /* maximum of 27 words of rsp data */
 
+/* Structure for MB Command UPDATE_CFG (0x1B) */
+
+struct update_cfg_var {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd2:16;
+	uint32_t type:8;
+	uint32_t rsvd:1;
+	uint32_t ra:1;
+	uint32_t co:1;
+	uint32_t cv:1;
+	uint32_t req:4;
+	uint32_t entry_length:16;
+	uint32_t region_id:16;
+#else  /*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t req:4;
+	uint32_t cv:1;
+	uint32_t co:1;
+	uint32_t ra:1;
+	uint32_t rsvd:1;
+	uint32_t type:8;
+	uint32_t rsvd2:16;
+	uint32_t region_id:16;
+	uint32_t entry_length:16;
+#endif
+
+	uint32_t resp_info;
+	uint32_t byte_cnt;
+	uint32_t data_offset;
+};
+
+
 struct hbq_mask {
 #ifdef __BIG_ENDIAN_BITFIELD
 	uint8_t tmatch;
@@ -2652,6 +2693,9 @@ typedef struct {
 /* Union of all Mailbox Command types */
 #define MAILBOX_CMD_WSIZE	32
 #define MAILBOX_CMD_SIZE	(MAILBOX_CMD_WSIZE * sizeof(uint32_t))
+#define MAILBOX_EXT_WSIZE	64
+#define MAILBOX_EXT_SIZE	(MAILBOX_EXT_WSIZE * sizeof(uint32_t))
+#define MAILBOX_MAX_XMIT_SIZE   1024
 
 typedef union {
 	uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/
@@ -2685,6 +2729,7 @@ typedef union {
 					 * NEW_FEATURE
 					 */
 	struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ)  */
+	struct update_cfg_var varUpdateCfg; /* cmd = 0x1B (UPDATE_CFG)*/
 	CONFIG_PORT_VAR varCfgPort;	/* cmd = 0x88 (CONFIG_PORT)  */
 	REG_VPI_VAR varRegVpi;		/* cmd = 0x96 (REG_VPI) */
 	UNREG_VPI_VAR varUnregVpi;	/* cmd = 0x97 (UNREG_VPI) */
@@ -3017,6 +3062,34 @@ typedef struct {
 #endif
 } RCV_ELS_REQ64;
 
+/* IOCB Command template for RCV_SEQ64 */
+struct rcv_seq64 {
+	struct ulp_bde64 elsReq;
+	uint32_t hbq_1;
+	uint32_t parmRo;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rctl:8;
+	uint32_t type:8;
+	uint32_t dfctl:8;
+	uint32_t ls:1;
+	uint32_t fs:1;
+	uint32_t rsvd2:3;
+	uint32_t si:1;
+	uint32_t bc:1;
+	uint32_t rsvd3:1;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t rsvd3:1;
+	uint32_t bc:1;
+	uint32_t si:1;
+	uint32_t rsvd2:3;
+	uint32_t fs:1;
+	uint32_t ls:1;
+	uint32_t dfctl:8;
+	uint32_t type:8;
+	uint32_t rctl:8;
+#endif
+};
+
 /* IOCB Command template for all 64 bit FCP Initiator commands */
 typedef struct {
 	ULP_BDL bdl;
@@ -3063,7 +3136,26 @@ struct rcv_sli3 {
 	struct ulp_bde64 bde2;
 };
 
+/* Structure used for a single HBQ entry */
+struct lpfc_hbq_entry {
+	struct ulp_bde64 bde;
+	uint32_t buffer_tag;
+};
 
+/* IOCB Command template for QUE_XRI64_CX (0xB3) command */
+typedef struct {
+	struct lpfc_hbq_entry   buff;
+	uint32_t                rsvd;
+	uint32_t		rsvd1;
+} QUE_XRI64_CX_FIELDS;
+
+struct que_xri64cx_ext_fields {
+	uint32_t	iotag64_low;
+	uint32_t	iotag64_high;
+	uint32_t	ebde_count;
+	uint32_t	rsvd;
+	struct lpfc_hbq_entry	buff[5];
+};
 
 typedef struct _IOCB {	/* IOCB structure */
 	union {
@@ -3088,6 +3180,8 @@ typedef struct _IOCB {	/* IOCB structure */
 		FCPI_FIELDS64 fcpi64;	/* FCP 64 bit Initiator template */
 		FCPT_FIELDS64 fcpt64;	/* FCP 64 bit target template */
 		ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */
+		QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */
+		struct rcv_seq64 rcvseq64;	/* RCV_SEQ64 and RCV_CONT64 */
 
 		uint32_t ulpWord[IOCB_WORD_SZ - 2];	/* generic 6 'words' */
 	} un;
@@ -3145,6 +3239,10 @@ typedef struct _IOCB {	/* IOCB structure */
 
 	union {
 		struct rcv_sli3 rcvsli3; /* words 8 - 15 */
+
+		/* words 8-31 used for que_xri_cx iocb */
+		struct que_xri64cx_ext_fields que_xri64cx_ext_words;
+
 		uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */
 	} unsli3;
 
@@ -3184,12 +3282,6 @@ typedef struct _IOCB {	/* IOCB structure */
 
 } IOCB_t;
 
-/* Structure used for a single HBQ entry */
-struct lpfc_hbq_entry {
-	struct ulp_bde64 bde;
-	uint32_t buffer_tag;
-};
-
 
 #define SLI1_SLIM_SIZE   (4 * 1024)
 
@@ -3232,6 +3324,8 @@ lpfc_is_LC_HBA(unsigned short device)
 	    (device == PCI_DEVICE_ID_BSMB) ||
 	    (device == PCI_DEVICE_ID_ZMID) ||
 	    (device == PCI_DEVICE_ID_ZSMB) ||
+	    (device == PCI_DEVICE_ID_SAT_MID) ||
+	    (device == PCI_DEVICE_ID_SAT_SMB) ||
 	    (device == PCI_DEVICE_ID_RFLY))
 		return 1;
 	else
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 71c72d6..f375894 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -43,7 +43,6 @@
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
 #include "lpfc_version.h"
-#include "lpfc_vport.h"
 #include "lpfc_auth_access.h"
 #include "lpfc_ioctl.h"
 #include "lpfc_security.h"
@@ -73,6 +72,43 @@ static DEFINE_IDR(lpfc_hba_index);
 
 
 
+int pci_select_bars(struct pci_dev *dev, unsigned long flags)
+{
+	int i, bars = 0;
+	for (i = 0; i < PCI_NUM_RESOURCES; i++)
+		if (pci_resource_flags(dev, i) & flags)
+			bars |= (1 << i);
+	return bars;
+}
+
+int pci_request_selected_regions(struct pci_dev *pdev, int bars,
+				 char *res_name)
+{
+	int i;
+
+	for (i = 0; i < 6; i++)
+		if (bars & (1 << i))
+			if(pci_request_region(pdev, i, res_name))
+				goto err_out;
+	return 0;
+
+err_out:
+	while(--i >= 0)
+		if (bars & (1 << i))
+			pci_release_region(pdev, i);
+
+	return -EBUSY;
+}
+
+void pci_release_selected_regions(struct pci_dev *pdev, int bars)
+{
+	int i;
+
+	for (i = 0; i < 6; i++)
+		if (bars & (1 << i))
+			pci_release_region(pdev, i);
+}
+
 /************************************************************************/
 /*                                                                      */
 /*    lpfc_config_port_prep                                             */
@@ -428,11 +464,10 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 	phba->last_completion_time = jiffies;
 
 	if (vport->cfg_enable_auth) {
-		lpfc_security_wait();
 		if (lpfc_security_service_state == SECURITY_OFFLINE) {
 			lpfc_printf_log(vport->phba, KERN_ERR, LOG_SECURITY,
-				"1029 Authentication is enabled but security "
-				"service is not running!\n");
+				"1029 Authentication is enabled but "
+				"authentication service is not running\n");
 			vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN;
 			phba->link_state = LPFC_HBA_ERROR;
 			mempool_free( pmb, phba->mbox_mem_pool);
@@ -520,6 +555,9 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
 	struct lpfc_dmabuf *mp, *next_mp;
+	struct lpfc_iocbq *iocb;
+	IOCB_t *cmd = NULL;
+	LIST_HEAD(completions);
 	int i;
 
 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
@@ -535,10 +573,36 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
 		}
 	}
 
+	spin_lock_irq(&phba->hbalock);
 	for (i = 0; i < psli->num_rings; i++) {
 		pring = &psli->ring[i];
+
+		/* At this point in time the HBA is either reset or DOA. Either
+		 * way, nothing should be on txcmplq as it will NEVER complete.
+		 */
+		list_splice_init(&pring->txcmplq, &completions);
+		pring->txcmplq_cnt = 0;
+		spin_unlock_irq(&phba->hbalock);
+
+		while (!list_empty(&completions)) {
+			iocb = list_get_first(&completions, struct lpfc_iocbq,
+				list);
+			cmd = &iocb->iocb;
+			list_del_init(&iocb->list);
+
+			if (!iocb->iocb_cmpl)
+				lpfc_sli_release_iocbq(phba, iocb);
+			else {
+				cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+				cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+				(iocb->iocb_cmpl) (phba, iocb, iocb);
+			}
+		}
+
 		lpfc_sli_abort_iocb_ring(phba, pring);
+		spin_lock_irq(&phba->hbalock);
 	}
+	spin_unlock_irq(&phba->hbalock);
 
 	return 0;
 }
@@ -583,8 +647,10 @@ void
 lpfc_hb_timeout_handler(struct lpfc_hba *phba)
 {
 	LPFC_MBOXQ_t *pmboxq;
+	struct lpfc_dmabuf *buf_ptr;
 	int retval;
 	struct lpfc_sli *psli = &phba->sli;
+	LIST_HEAD(completions);
 
 	if ((phba->link_state == LPFC_HBA_ERROR) ||
 		(phba->pport->load_flag & FC_UNLOADING) ||
@@ -611,49 +677,88 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
 	}
 	spin_unlock_irq(&phba->pport->work_port_lock);
 
-	/* If there is no heart beat outstanding, issue a heartbeat command */
-	if (!phba->hb_outstanding) {
-		pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
-		if (!pmboxq) {
-			mod_timer(&phba->hb_tmofunc,
-				jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
-			return;
+	if (phba->elsbuf_cnt &&
+		(phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) {
+		spin_lock_irq(&phba->hbalock);
+		list_splice_init(&phba->elsbuf, &completions);
+		phba->elsbuf_cnt = 0;
+		phba->elsbuf_prev_cnt = 0;
+		spin_unlock_irq(&phba->hbalock);
+
+		while (!list_empty(&completions)) {
+			list_remove_head(&completions, buf_ptr,
+				struct lpfc_dmabuf, list);
+			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+			kfree(buf_ptr);
 		}
+	}
+	phba->elsbuf_prev_cnt = phba->elsbuf_cnt;
 
-		lpfc_heart_beat(phba, pmboxq);
-		pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
-		pmboxq->vport = phba->pport;
-		retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+	/* If there is no heart beat outstanding, issue a heartbeat command */
+	if (phba->cfg_enable_hba_heartbeat) {
+		if (!phba->hb_outstanding) {
+			pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
+			if (!pmboxq) {
+				mod_timer(&phba->hb_tmofunc,
+					  jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+				return;
+			}
 
-		if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
-			mempool_free(pmboxq, phba->mbox_mem_pool);
+			lpfc_heart_beat(phba, pmboxq);
+			pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
+			pmboxq->vport = phba->pport;
+			retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+
+			if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
+				mempool_free(pmboxq, phba->mbox_mem_pool);
+				mod_timer(&phba->hb_tmofunc,
+					  jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+				return;
+			}
 			mod_timer(&phba->hb_tmofunc,
-				jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+				  jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
+			phba->hb_outstanding = 1;
 			return;
+		} else {
+			/*
+			* If heart beat timeout called with hb_outstanding set
+			* we need to take the HBA offline.
+			*/
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0459 Adapter heartbeat failure, "
+					"taking this port offline.\n");
+
+			spin_lock_irq(&phba->hbalock);
+			psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+			spin_unlock_irq(&phba->hbalock);
+
+			lpfc_offline_prep(phba);
+			lpfc_offline(phba);
+			lpfc_unblock_mgmt_io(phba);
+			phba->link_state = LPFC_HBA_ERROR;
+			lpfc_hba_down_post(phba);
 		}
-		mod_timer(&phba->hb_tmofunc,
-			jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
-		phba->hb_outstanding = 1;
-		return;
-	} else {
-		/*
-		 * If heart beat timeout called with hb_outstanding set we
-		 * need to take the HBA offline.
-		 */
-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"0459 Adapter heartbeat failure, taking "
-				"this port offline.\n");
+	}
+}
 
-		spin_lock_irq(&phba->hbalock);
-		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
-		spin_unlock_irq(&phba->hbalock);
+static void
+lpfc_offline_eratt(struct lpfc_hba *phba)
+{
+	struct lpfc_sli   *psli = &phba->sli;
 
-		lpfc_offline_prep(phba);
-		lpfc_offline(phba);
-		lpfc_unblock_mgmt_io(phba);
-		phba->link_state = LPFC_HBA_ERROR;
-		lpfc_hba_down_post(phba);
-	}
+	spin_lock_irq(&phba->hbalock);
+	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+	spin_unlock_irq(&phba->hbalock);
+	lpfc_offline_prep(phba);
+
+	lpfc_offline(phba);
+	lpfc_reset_barrier(phba);
+	lpfc_sli_brdreset(phba);
+	lpfc_hba_down_post(phba);
+	lpfc_sli_brdready(phba, HS_MBRDY);
+	lpfc_unblock_mgmt_io(phba);
+	phba->link_state = LPFC_HBA_ERROR;
+	return;
 }
 
 /************************************************************************/
@@ -677,6 +782,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 	struct Scsi_Host  *shost;
 	int i;
 
+	/* If resets are disabled then leave the HBA alone and return */
+	if (!phba->cfg_enable_hba_reset)
+		return;
 
 	if (phba->work_hs & HS_FFER6 ||
 	    phba->work_hs & HS_FFER5) {
@@ -689,14 +797,14 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 		vports = lpfc_create_vport_work_array(phba);
 		if (vports != NULL)
 			for(i = 0;
-			    i < LPFC_MAX_VPORTS && vports[i] != NULL;
+			    i <= phba->max_vpi && vports[i] != NULL;
 			    i++){
 				shost = lpfc_shost_from_vport(vports[i]);
 				spin_lock_irq(shost->host_lock);
 				vports[i]->fc_flag |= FC_ESTABLISH_LINK;
 				spin_unlock_irq(shost->host_lock);
 			}
-		lpfc_destroy_vport_work_array(vports);
+		lpfc_destroy_vport_work_array(phba, vports);
 		spin_lock_irq(&phba->hbalock);
 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
 		spin_unlock_irq(&phba->hbalock);
@@ -745,14 +853,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 					  | PCI_VENDOR_ID_EMULEX);
 
 		spin_lock_irq(&phba->hbalock);
-		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
 		phba->over_temp_state = HBA_OVER_TEMP;
 		spin_unlock_irq(&phba->hbalock);
-		lpfc_offline_prep(phba);
-		lpfc_offline(phba);
-		lpfc_unblock_mgmt_io(phba);
-		phba->link_state = LPFC_HBA_ERROR;
-		lpfc_hba_down_post(phba);
+		lpfc_offline_eratt(phba);
 
 	} else {
 		/* The if clause above forces this code path when the status
@@ -771,14 +874,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 				sizeof(event_data), (char *) &event_data,
 				SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
 
-		spin_lock_irq(&phba->hbalock);
-		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
-		spin_unlock_irq(&phba->hbalock);
-		lpfc_offline_prep(phba);
-		lpfc_offline(phba);
-		lpfc_unblock_mgmt_io(phba);
-		phba->link_state = LPFC_HBA_ERROR;
-		lpfc_hba_down_post(phba);
+		lpfc_offline_eratt(phba);
 	}
 }
 
@@ -798,21 +894,25 @@ lpfc_handle_latt(struct lpfc_hba *phba)
 	LPFC_MBOXQ_t *pmb;
 	volatile uint32_t control;
 	struct lpfc_dmabuf *mp;
-	int rc = -ENOMEM;
+	int rc = 0;
 
 	pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-	if (!pmb)
+	if (!pmb) {
+		rc = 1;
 		goto lpfc_handle_latt_err_exit;
+	}
 
 	mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-	if (!mp)
+	if (!mp) {
+		rc = 2;
 		goto lpfc_handle_latt_free_pmb;
+	}
 
 	mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
-	if (!mp->virt)
+	if (!mp->virt) {
+		rc = 3;
 		goto lpfc_handle_latt_free_mp;
-
-	rc = -EIO;
+	}
 
 	/* Cleanup any outstanding ELS commands */
 	lpfc_els_flush_all_cmd(phba);
@@ -822,8 +922,10 @@ lpfc_handle_latt(struct lpfc_hba *phba)
 	pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
 	pmb->vport = vport;
 	rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT);
-	if (rc == MBX_NOT_FINISHED)
+	if (rc == MBX_NOT_FINISHED) {
+		rc = 4;
 		goto lpfc_handle_latt_free_mbuf;
+	}
 
 	/* Clear Link Attention in HA REG */
 	spin_lock_irq(&phba->hbalock);
@@ -855,10 +957,8 @@ lpfc_handle_latt_err_exit:
 	lpfc_linkdown(phba);
 	phba->link_state = LPFC_HBA_ERROR;
 
-	/* The other case is an error from issue_mbox */
-	if (rc == -ENOMEM)
-		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
-			        "0300 READ_LA: no buffers\n");
+	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+		     "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc);
 
 	return;
 }
@@ -1364,11 +1464,10 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
 	uint32_t *HashWorking;
 	uint32_t *pwwnn = (uint32_t *) phba->wwnn;
 
-	HashWorking = kmalloc(80 * sizeof(uint32_t), GFP_KERNEL);
+	HashWorking = kcalloc(80, sizeof(uint32_t), GFP_KERNEL);
 	if (!HashWorking)
 		return;
 
-	memset(HashWorking, 0, (80 * sizeof(uint32_t)));
 	HashWorking[0] = HashWorking[78] = *pwwnn++;
 	HashWorking[1] = HashWorking[79] = *pwwnn;
 
@@ -1431,14 +1530,14 @@ lpfc_establish_link_tmo(unsigned long ptr)
 			phba->pport->fc_flag, phba->pport->port_state);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			struct Scsi_Host *shost;
 			shost = lpfc_shost_from_vport(vports[i]);
 			spin_lock_irqsave(shost->host_lock, iflag);
 			vports[i]->fc_flag &= ~FC_ESTABLISH_LINK;
 			spin_unlock_irqrestore(shost->host_lock, iflag);
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 }
 
 void
@@ -1493,7 +1592,7 @@ lpfc_online(struct lpfc_hba *phba)
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			struct Scsi_Host *shost;
 			shost = lpfc_shost_from_vport(vports[i]);
 			spin_lock_irq(shost->host_lock);
@@ -1502,7 +1601,7 @@ lpfc_online(struct lpfc_hba *phba)
 				vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
 			spin_unlock_irq(shost->host_lock);
 		}
-		lpfc_destroy_vport_work_array(vports);
+		lpfc_destroy_vport_work_array(phba, vports);
 
 	lpfc_unblock_mgmt_io(phba);
 	return 0;
@@ -1546,7 +1645,7 @@ lpfc_offline_prep(struct lpfc_hba * phba)
 	/* Issue an unreg_login to all nodes on all vports */
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL) {
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			struct Scsi_Host *shost;
 
 			if (vports[i]->load_flag & FC_UNLOADING)
@@ -1570,7 +1669,7 @@ lpfc_offline_prep(struct lpfc_hba * phba)
 			}
 		}
 	}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 
 	lpfc_sli_flush_mbox_queue(phba);
 }
@@ -1589,9 +1688,9 @@ lpfc_offline(struct lpfc_hba *phba)
 	lpfc_stop_phba_timers(phba);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
 			lpfc_stop_vport_timers(vports[i]);
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 			"0460 Bring Adapter offline\n");
 	/* Bring down the SLI Layer and cleanup.  The HBA is offline
@@ -1602,14 +1701,14 @@ lpfc_offline(struct lpfc_hba *phba)
 	spin_unlock_irq(&phba->hbalock);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			shost = lpfc_shost_from_vport(vports[i]);
 			spin_lock_irq(shost->host_lock);
 			vports[i]->work_port_events = 0;
 			vports[i]->fc_flag |= FC_OFFLINE_MODE;
 			spin_unlock_irq(shost->host_lock);
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 }
 
 /******************************************************************************
@@ -1866,6 +1965,37 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
 	spin_unlock_irq(shost->host_lock);
 }
 
+void
+lpfc_setup_max_dma_length(struct lpfc_hba * phba)
+{
+	struct pci_dev *pdev = phba->pcidev;
+	struct pci_bus *bus = pdev->bus;
+	uint8_t rev;
+
+	while (bus) {
+		/*
+		 * 0x7450 == PCI_DEVICE_ID_AMD_8131_BRIDGE for 2.6 kernels
+		 * 0x7450 == PCI_DEVICE_ID_AMD_8131_APIC   for 2.4 kernels
+		 */
+		if ( bus->self &&
+		    (bus->self->vendor == PCI_VENDOR_ID_AMD) &&
+		    (bus->self->device == 0x7450)) {
+			pci_read_config_byte(bus->self, 0x08, &rev);
+			if (rev == 0x13) {
+				/*
+				 * If set a value in module paramter,
+				 * use that value.
+				 */
+				if (phba->cfg_pci_max_read == 2048)
+					phba->cfg_pci_max_read = 1024;
+				return;
+			}
+		}
+		bus = bus->parent;
+	}
+	return;
+}
+
 static int __devinit
 lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
@@ -1879,11 +2009,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	int error = -ENODEV, retval;
 	int  i, hbq_count;
 	uint16_t iotag;
+	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 	unsigned long start;
 
-	if (pci_enable_device(pdev))
+	if (pci_enable_device_bars(pdev, bars))
 		goto out;
-	if (pci_request_regions(pdev, LPFC_DRIVER_NAME))
+	if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
 		goto out_disable_device;
 
 	phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL);
@@ -1904,6 +2035,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	 * establish the host.
 	 */
 	lpfc_get_cfgparam(phba);
+
+	/* Check if we need to change the DMA length */
+	lpfc_setup_max_dma_length(phba);
+
 	phba->max_vpi = LPFC_MAX_VPI;
 
 	/* Initialize timers used by driver */
@@ -1992,6 +2127,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 
 	memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size());
 
+	INIT_LIST_HEAD(&phba->hbqbuf_in_list);
+
 	/* Initialize the SLI Layer to run with lpfc HBAs. */
 	lpfc_sli_setup(phba);
 	lpfc_sli_queue_setup(phba);
@@ -2055,6 +2192,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	/* Initialize list of fabric iocbs */
 	INIT_LIST_HEAD(&phba->fabric_iocb_list);
 
+	/* Initialize list to save ELS buffers */
+	INIT_LIST_HEAD(&phba->elsbuf);
+
 	/* Initialize list of sysfs mailbox commands */
 	INIT_LIST_HEAD(&phba->sysfs_mbox_list);
 
@@ -2188,7 +2328,7 @@ out_idr_remove:
 out_free_phba:
 	kfree(phba);
 out_release_regions:
-	pci_release_regions(pdev);
+	pci_release_selected_regions(pdev, bars);
 out_disable_device:
 	pci_disable_device(pdev);
 out:
@@ -2204,6 +2344,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 	struct Scsi_Host  *shost = pci_get_drvdata(pdev);
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
+	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 	struct lpfc_vport **vports;
 	int i;
 
@@ -2219,12 +2360,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
 				continue;
 			lpfc_vport_delete(lpfc_shost_from_vport(vports[i]));
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	fc_remove_host(shost);
 	scsi_remove_host(shost);
 	lpfc_cleanup(vport);
@@ -2276,10 +2417,102 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 
 	kfree(phba);
 
-	pci_release_regions(pdev);
+	pci_release_selected_regions(pdev, bars);
 	pci_disable_device(pdev);
 }
 
+/**
+ * lpfc_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci conneection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
+				pci_channel_state_t state)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_sli_ring  *pring;
+
+	if (state == pci_channel_io_perm_failure)
+		return PCI_ERS_RESULT_DISCONNECT;
+
+	pci_disable_device(pdev);
+	/*
+	 * There may be I/Os dropped by the firmware.
+	 * Error iocb (I/O) on txcmplq and let the SCSI layer
+	 * retry it after re-establishing link.
+	 */
+	pring = &psli->ring[psli->fcp_ring];
+	lpfc_sli_abort_iocb_ring(phba, pring);
+
+	/* Release the irq reservation */
+	free_irq(phba->pcidev->irq, phba);
+	if (phba->using_msi)
+		pci_disable_msi(phba->pcidev);
+
+	/* Request a slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * lpfc_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+	struct lpfc_sli *psli = &phba->sli;
+	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
+
+	dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
+	if (pci_enable_device_bars(pdev, bars)) {
+		printk(KERN_ERR "lpfc: Cannot re-enable "
+			"PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+
+	pci_set_master(pdev);
+
+	/* Re-establishing Link */
+	spin_lock_irq(shost->host_lock);
+	phba->pport->fc_flag |= FC_ESTABLISH_LINK;
+	spin_unlock_irq(shost->host_lock);
+
+	spin_lock_irq(&phba->hbalock);
+	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+	spin_unlock_irq(&phba->hbalock);
+
+
+	/* Take device offline; this will perform cleanup */
+	lpfc_offline(phba);
+	lpfc_sli_brdrestart(phba);
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * lpfc_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void lpfc_io_resume(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+	if (lpfc_online(phba) == 0) {
+		mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
+	}
+}
 
 static struct pci_device_id lpfc_id_table[] = {
 	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,
@@ -2353,12 +2586,18 @@ static struct pci_device_id lpfc_id_table[] = {
 
 MODULE_DEVICE_TABLE(pci, lpfc_id_table);
 
+static struct pci_error_handlers lpfc_err_handler = {
+	.error_detected = lpfc_io_error_detected,
+	.slot_reset = lpfc_io_slot_reset,
+	.resume = lpfc_io_resume,
+};
 
 static struct pci_driver lpfc_driver = {
 	.name		= LPFC_DRIVER_NAME,
 	.id_table	= lpfc_id_table,
 	.probe		= lpfc_pci_probe_one,
 	.remove		= __devexit_p(lpfc_pci_remove_one),
+	.err_handler    = &lpfc_err_handler,
 };
 
 static int __init
@@ -2382,26 +2621,21 @@ lpfc_init(void)
 		}
 	}
 
-	if (netlink_register_notifier(&lpfc_fc_netlink_notifier))
-		return 1;
+	error = netlink_register_notifier(&lpfc_fc_netlink_notifier);
+	if (error)
+		goto out_release_transport;
 	fc_nl_sock = netlink_kernel_create(NETLINK_FCTRANSPORT, FC_NL_GROUP_CNT,
 					   lpfc_fc_nl_rcv, THIS_MODULE);
-	if (!fc_nl_sock) {
-		netlink_unregister_notifier(&lpfc_fc_netlink_notifier);
-		return 1;
-	}
+	if (!fc_nl_sock)
+		goto out_unregister_notifier;
 	snprintf(security_work_q_name, KOBJ_NAME_LEN, "fc_sc_wq");
 	security_work_q = create_singlethread_workqueue(security_work_q_name);
-	if (!security_work_q) {
-		netlink_unregister_notifier(&lpfc_fc_netlink_notifier);
-		sock_release(fc_nl_sock->sk_socket);
-		return 1;
-	}
+	if (!security_work_q)
+		goto out_sock_release;
 	INIT_LIST_HEAD(&fc_security_user_list);
 	error = pci_register_driver(&lpfc_driver);
 	if (error)
-		goto out_release_transport;
-
+		goto out_destroy_workqueue;
 	error = lpfc_cdev_init();
 	if (error)
 		goto out_pci_unregister;
@@ -2410,9 +2644,18 @@ lpfc_init(void)
 
 out_pci_unregister:
 	pci_unregister_driver(&lpfc_driver);
+out_destroy_workqueue:
+	destroy_workqueue(security_work_q);
+	security_work_q = NULL;
+out_sock_release:
+	sock_release(fc_nl_sock->sk_socket);
+	fc_nl_sock = NULL;
+out_unregister_notifier:
+	netlink_unregister_notifier(&lpfc_fc_netlink_notifier);
 out_release_transport:
 	fc_release_transport(lpfc_transport_template);
-	fc_release_transport(lpfc_vport_transport_template);
+	if (lpfc_enable_npiv)
+		fc_release_transport(lpfc_vport_transport_template);
 
 	return error;
 }
@@ -2421,12 +2664,14 @@ static void __exit
 lpfc_exit(void)
 {
 	pci_unregister_driver(&lpfc_driver);
-
-	if (fc_nl_sock)
+	if (security_work_q)
+		destroy_workqueue(security_work_q);
+	security_work_q = NULL;
+	if (fc_nl_sock) {
 		sock_release(fc_nl_sock->sk_socket);
-	netlink_unregister_notifier(&lpfc_fc_netlink_notifier);
-	fc_nl_sock = NULL;
-
+		netlink_unregister_notifier(&lpfc_fc_netlink_notifier);
+		fc_nl_sock = NULL;
+	}
 	fc_release_transport(lpfc_transport_template);
 	if (lpfc_enable_npiv)
 		fc_release_transport(lpfc_vport_transport_template);
diff --git a/drivers/scsi/lpfc/lpfc_ioctl.c b/drivers/scsi/lpfc/lpfc_ioctl.c
index 20f0c2e..0e890fa 100644
--- a/drivers/scsi/lpfc/lpfc_ioctl.c
+++ b/drivers/scsi/lpfc/lpfc_ioctl.c
@@ -34,6 +34,7 @@
 #include "lpfc_crtn.h"
 #include "lpfc_ioctl.h"
 #include "lpfc_logmsg.h"
+#include "lpfc_vport.h"
 
 
 struct lpfcdfc_event {
@@ -1065,11 +1066,12 @@ static int
 lpfc_ioctl_loopback_mode(struct lpfc_hba *phba,
 		   struct lpfcCmdInput  *cip, void *dataout)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport);
+	struct Scsi_Host *shost;
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING];
 	uint32_t link_flags = cip->lpfc_arg4;
 	uint32_t timeout = cip->lpfc_arg5 * 100;
+	struct lpfc_vport **vports;
 	LPFC_MBOXQ_t *pmboxq;
 	int mbxstatus;
 	int i = 0;
@@ -1083,7 +1085,18 @@ lpfc_ioctl_loopback_mode(struct lpfc_hba *phba,
 	if ((pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL)) == 0)
 		return ENOMEM;
 
-	scsi_block_requests(shost);
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++){
+			shost = lpfc_shost_from_vport(vports[i]);
+			scsi_block_requests(shost);
+		}
+		lpfc_destroy_vport_work_array(phba, vports);
+	}
+	else {
+		shost = lpfc_shost_from_vport(phba->pport);
+		scsi_block_requests(shost);
+	}
 
 	while (pring->txcmplq_cnt) {
 		if (i++ > 500)	/* wait up to 5 seconds */
@@ -1143,7 +1156,18 @@ lpfc_ioctl_loopback_mode(struct lpfc_hba *phba,
 		rc = ENODEV;
 
 loopback_mode_exit:
-	scsi_unblock_requests(shost);
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++){
+			shost = lpfc_shost_from_vport(vports[i]);
+			scsi_unblock_requests(shost);
+		}
+		lpfc_destroy_vport_work_array(phba, vports);
+	}
+	else {
+		shost = lpfc_shost_from_vport(phba->pport);
+		scsi_unblock_requests(shost);
+	}
 
 	/*
 	 * Let SLI layer release mboxq if mbox command completed after timeout.
@@ -1406,17 +1430,35 @@ static int lpfcdfc_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,
 		mp[i] = list_entry(curr, struct lpfc_dmabuf, list);
 		list_del(curr);
 
-		cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys);
-		cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys);
-		cmd->un.cont64[i].tus.f.bdeSize =
-			((struct lpfc_dmabufext *)mp[i])->size;
-		cmd->ulpBdeCount = ++i;
+		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+			mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba);
+			cmd->un.quexri64cx.buff.bde.addrHigh =
+				putPaddrHigh(mp[i]->phys);
+			cmd->un.quexri64cx.buff.bde.addrLow =
+				putPaddrLow(mp[i]->phys);
+			cmd->un.quexri64cx.buff.bde.tus.f.bdeSize =
+				((struct lpfc_dmabufext *)mp[i])->size;
+			cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag;
+			cmd->ulpCommand = CMD_QUE_XRI64_CX;
+			cmd->ulpPU = 0;
+			cmd->ulpLe = 1;
+			cmd->ulpBdeCount = 1;
+			cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0;
 
-		if ((--num_bde > 0) && (i < 2))
-			continue;
+		} else {
+			cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys);
+			cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys);
+			cmd->un.cont64[i].tus.f.bdeSize =
+				((struct lpfc_dmabufext *)mp[i])->size;
+					cmd->ulpBdeCount = ++i;
+
+			if ((--num_bde > 0) && (i < 2))
+				continue;
+
+			cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX;
+			cmd->ulpLe = 1;
+		}
 
-		cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX;
-		cmd->ulpLe = 1;
 		cmd->ulpClass = CLASS3;
 		cmd->ulpContext = rxxri;
 
@@ -1630,19 +1672,20 @@ lpfc_ioctl_loopback_test(struct lpfc_hba *phba,
 	}
 	evt->waiting = 0;
 
-	mutex_lock(&lpfcdfc_lock);
-	lpfcdfc_event_unref(evt); /* release ref */
-	lpfcdfc_event_unref(evt); /* delete */
-	mutex_unlock(&lpfcdfc_lock);
-
 	if (rx_databuf == NULL) {
 		rc = EIO;
-		goto err_loopback_test_exit;
+		goto err_loopback_free_evt_exit;
 	}
 
 	rx_databuf += ELX_LOOPBACK_HEADER_SZ;
 	memcpy(ptr, rx_databuf, size);
 
+err_loopback_free_evt_exit:
+	mutex_lock(&lpfcdfc_lock);
+	lpfcdfc_event_unref(evt); /* release ref */
+	lpfcdfc_event_unref(evt); /* delete */
+	mutex_unlock(&lpfcdfc_lock);
+
 err_loopback_test_exit:
 	lpfcdfc_loop_self_unreg(phba, rpi);
 
@@ -1786,7 +1829,6 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba,
 			    struct lpfc_iocbq * piocbq)
 {
 	struct lpfcdfc_host * dfchba = lpfcdfc_host_from_hba(phba);
-	uint32_t evt_type;
 	uint32_t evt_req_id = 0;
 	uint32_t cmd;
 	uint32_t len;
@@ -1801,10 +1843,10 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba,
 	int i;
 	struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
 	struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
+	struct lpfc_hbq_entry *hbqe;
 
 	BUG_ON(&dfchba->node == &lpfcdfc_hosts);
 	INIT_LIST_HEAD(&head);
-	evt_type = FC_REG_CT_EVENT;
 	if (piocbq->iocb.ulpBdeCount == 0 ||
 	    piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0)
 		goto error_unsol_ct_exit;
@@ -1842,10 +1884,27 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba,
 
 		INIT_LIST_HEAD(&head);
 		list_add_tail(&head, &piocbq->list);
-		list_for_each_entry(iocbq, &head, list)
-			for (i = 0; i < iocbq->iocb.ulpBdeCount; i++)
-				evt_dat->len +=
+		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+			list_for_each_entry(iocbq, &head, list) {
+				if (iocbq->iocb.ulpBdeCount != 0) {
+					hbqe = (struct lpfc_hbq_entry *)
+						&iocbq->iocb.un.ulpWord[0];
+					evt_dat->len += hbqe->bde.tus.f.bdeSize;
+				}
+				if (iocbq->iocb.ulpBdeCount == 2) {
+					hbqe = (struct lpfc_hbq_entry *)
+					&iocbq->iocb.unsli3.sli3Words[4];
+					evt_dat->len += hbqe->bde.tus.f.bdeSize;
+				}
+			}
+		} else {
+			list_for_each_entry(iocbq, &head, list) {
+				for (i = 0; i < iocbq->iocb.ulpBdeCount; i++)
+					evt_dat->len +=
 					iocbq->iocb.un.cont64[i].tus.f.bdeSize;
+			}
+		}
+
 
 		evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL);
 		if (evt_dat->data == NULL) {
@@ -1856,17 +1915,33 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba,
 			goto error_unsol_ct_exit;
 		}
 
-		list_for_each_entry(iocbq, &head, list)
+		list_for_each_entry(iocbq, &head, list) {
+			if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+				bdeBuf1 = iocbq->context2;
+				bdeBuf2 = iocbq->context3;
+			}
 			for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) {
-				int size;
-				size = iocbq->iocb.un.cont64[i].tus.f.bdeSize;
+				int size = 0;
+
 				if (phba->sli3_options &
 				    LPFC_SLI3_HBQ_ENABLED) {
-					if (i == 0)
+					BUG_ON(i>1);
+
+					if (i == 0) {
+						hbqe = (struct lpfc_hbq_entry *)
+						  &iocbq->iocb.un.ulpWord[0];
+						size = hbqe->bde.tus.f.bdeSize;
 						dmabuf = bdeBuf1;
-					else if (i == 1)
+					} else if (i == 1) {
+						hbqe = (struct lpfc_hbq_entry *)
+							&iocbq->iocb.unsli3.
+							sli3Words[4];
+						size = hbqe->bde.tus.f.bdeSize;
 						dmabuf = bdeBuf2;
+					}
 				} else {
+					size = iocbq->iocb.un.cont64[i].
+						tus.f.bdeSize;
 					bde = &iocbq->iocb.un.cont64[i];
 					dma_addr = getPaddr(bde->addrHigh,
 							    bde->addrLow);
@@ -1903,15 +1978,15 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba,
 							lpfc_post_buffer(phba,
 									 pring,
 									 1, 1);
-						lpfc_in_buf_free(phba, dmabuf);
 						break;
 					};
 				}
 			}
+		}
 
 		mutex_lock(&lpfcdfc_lock);
 		evt_dat->immed_dat = piocbq->iocb.ulpContext;
-		evt_dat->type = evt_type;
+		evt_dat->type = FC_REG_CT_EVENT;
 		list_add(&evt_dat->node, &evt->events_to_see);
 		wake_up_interruptible(&evt->wq);
 		lpfcdfc_event_unref(evt);
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 872190d..60db1d5 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -542,6 +542,32 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
 	}
 }
 
+/***********************************************/
+/*                  command to write slim      */
+/***********************************************/
+void
+lpfc_set_var(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint32_t addr,
+	      uint32_t value)
+{
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+	/*
+	 * Always turn on DELAYED ABTS for ELS timeouts
+	 */
+	if ((addr == 0x052198) && (value == 0))
+		value = 1;
+
+	mb->un.varWords[0] = addr;
+	mb->un.varWords[1] = value;
+
+	mb->mbxCommand = MBX_SET_VARIABLE;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
 void
 lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 {
@@ -902,7 +928,7 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
 	case MBX_DOWN_LOAD:	/* 0x1C */
 	case MBX_DEL_LD_ENTRY:	/* 0x1D */
 	case MBX_LOAD_AREA:	/* 0x81 */
-	case MBX_FLASH_WR_ULA:  /* 0x98 */
+	case MBX_WRITE_WWN:     /* 0x98 */
 	case MBX_LOAD_EXP_ROM:	/* 0x9C */
 		return LPFC_MBOX_TMO_FLASH_CMD;
 	}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 43c3b8a..8daa385 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -98,6 +98,7 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
 
  fail_free_hbq_pool:
 	lpfc_sli_hbqbuf_free_all(phba);
+	pci_pool_destroy(phba->lpfc_hbq_pool);
  fail_free_nlp_mem_pool:
 	mempool_destroy(phba->nlp_mem_pool);
 	phba->nlp_mem_pool = NULL;
@@ -236,11 +237,11 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba)
 {
 	struct hbq_dmabuf *hbqbp;
 
-	hbqbp = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL);
+	hbqbp = kmalloc(sizeof(struct hbq_dmabuf), GFP_ATOMIC);
 	if (!hbqbp)
 		return NULL;
 
-	hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL,
+	hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_ATOMIC,
 					  &hbqbp->dbuf.phys);
 	if (!hbqbp->dbuf.virt) {
 		kfree(hbqbp);
@@ -263,15 +264,24 @@ void
 lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
 {
 	struct hbq_dmabuf *hbq_entry;
+	unsigned long flags;
 
 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+		/* Check whether HBQ is still in use */
+		spin_lock_irqsave(&phba->hbalock, flags);
+		if (!phba->hbq_in_use) {
+			spin_unlock_irqrestore(&phba->hbalock, flags);
+			return;
+		}
 		hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf);
+		list_del(&hbq_entry->dbuf.list);
 		if (hbq_entry->tag == -1) {
 			(phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
 				(phba, hbq_entry);
 		} else {
 			lpfc_sli_free_hbq(phba, hbq_entry);
 		}
+		spin_unlock_irqrestore(&phba->hbalock, flags);
 	} else {
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 346999a..fbe62d8 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -442,6 +442,40 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			spin_lock_irq(shost->host_lock);
 			ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
 			spin_unlock_irq(shost->host_lock);
+
+			if ((ndlp->nlp_flag & NLP_ADISC_SND) &&
+				(vport->num_disc_nodes)) {
+				/* Check to see if there are more
+				 * ADISCs to be sent
+				 */
+				lpfc_more_adisc(vport);
+
+				if ((vport->num_disc_nodes == 0) &&
+					(vport->fc_npr_cnt))
+					lpfc_els_disc_plogi(vport);
+
+				if (vport->num_disc_nodes == 0) {
+					spin_lock_irq(shost->host_lock);
+					vport->fc_flag &= ~FC_NDISC_ACTIVE;
+					spin_unlock_irq(shost->host_lock);
+					lpfc_can_disctmo(vport);
+					lpfc_end_rscn(vport);
+				}
+			}
+			else if (vport->num_disc_nodes) {
+				/* Check to see if there are more
+				 * PLOGIs to be sent
+				 */
+				lpfc_more_plogi(vport);
+
+				if (vport->num_disc_nodes == 0) {
+					spin_lock_irq(shost->host_lock);
+					vport->fc_flag &= ~FC_NDISC_ACTIVE;
+					spin_unlock_irq(shost->host_lock);
+					lpfc_can_disctmo(vport);
+					lpfc_end_rscn(vport);
+				}
+			}
 		}
 	}
 
@@ -629,6 +663,25 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	return ndlp->nlp_state;
 }
 
+static uint32_t
+lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+		  void *arg, uint32_t evt)
+{
+	/* This transition is only legal if we previously
+	 * rcv'ed a PLOGI. Since we don't want 2 discovery threads
+	 * working on the same NPortID, do nothing for this thread
+	 * to stop it.
+	 */
+	if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+			 "0253 Illegal State Transition: node x%x "
+			 "event x%x, state x%x Data: x%x x%x\n",
+			 ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
+			 ndlp->nlp_flag);
+	}
+	return ndlp->nlp_state;
+}
+
 /* Start of Discovery State Machine routines */
 
 static uint32_t
@@ -780,6 +833,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
 			    uint32_t evt)
 {
 	struct lpfc_hba    *phba = vport->phba;
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_iocbq  *cmdiocb, *rspiocb;
 	struct lpfc_dmabuf *pcmd, *prsp, *mp;
 	uint32_t *lp;
@@ -897,11 +951,27 @@ out:
 				 "0261 Cannot Register NameServer login\n");
 	}
 
+	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag |= NLP_DEFER_RM;
+	spin_unlock_irq(shost->host_lock);
 	return NLP_STE_FREED_NODE;
 }
 
 static uint32_t
+lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+			   void *arg, uint32_t evt)
+{
+	return ndlp->nlp_state;
+}
+
+static uint32_t
+lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
+	struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
+{
+	return ndlp->nlp_state;
+}
+
+static uint32_t
 lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			   void *arg, uint32_t evt)
 {
@@ -1978,9 +2048,9 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
 	lpfc_rcv_els_plogi_issue,	/* RCV_PRLO        */
 	lpfc_cmpl_plogi_plogi_issue,	/* CMPL_PLOGI      */
 	lpfc_disc_illegal,		/* CMPL_PRLI       */
-	lpfc_disc_illegal,		/* CMPL_LOGO       */
+	lpfc_cmpl_logo_plogi_issue,	/* CMPL_LOGO       */
 	lpfc_disc_illegal,		/* CMPL_ADISC      */
-	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
+	lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN  */
 	lpfc_device_rm_plogi_issue,	/* DEVICE_RM       */
 	lpfc_device_recov_plogi_issue,	/* DEVICE_RECOVERY */
 
@@ -2004,7 +2074,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
 	lpfc_rcv_padisc_reglogin_issue,	/* RCV_ADISC       */
 	lpfc_rcv_padisc_reglogin_issue,	/* RCV_PDISC       */
 	lpfc_rcv_prlo_reglogin_issue,	/* RCV_PRLO        */
-	lpfc_disc_illegal,		/* CMPL_PLOGI      */
+	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
 	lpfc_disc_illegal,		/* CMPL_PRLI       */
 	lpfc_disc_illegal,		/* CMPL_LOGO       */
 	lpfc_disc_illegal,		/* CMPL_ADISC      */
@@ -2018,7 +2088,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
 	lpfc_rcv_padisc_prli_issue,	/* RCV_ADISC       */
 	lpfc_rcv_padisc_prli_issue,	/* RCV_PDISC       */
 	lpfc_rcv_prlo_prli_issue,	/* RCV_PRLO        */
-	lpfc_disc_illegal,		/* CMPL_PLOGI      */
+	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
 	lpfc_cmpl_prli_prli_issue,	/* CMPL_PRLI       */
 	lpfc_disc_illegal,		/* CMPL_LOGO       */
 	lpfc_disc_illegal,		/* CMPL_ADISC      */
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index bb8d833..82c6bd4 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -130,7 +130,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			shost = lpfc_shost_from_vport(vports[i]);
 			shost_for_each_device(sdev, shost) {
 				new_queue_depth =
@@ -151,7 +151,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
 							new_queue_depth);
 			}
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	atomic_set(&phba->num_rsrc_err, 0);
 	atomic_set(&phba->num_cmd_success, 0);
 }
@@ -166,7 +166,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			shost = lpfc_shost_from_vport(vports[i]);
 			shost_for_each_device(sdev, shost) {
 				if (sdev->ordered_tags)
@@ -179,7 +179,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
 							sdev->queue_depth+1);
 			}
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	atomic_set(&phba->num_rsrc_err, 0);
 	atomic_set(&phba->num_cmd_success, 0);
 }
@@ -202,10 +202,9 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)
 	dma_addr_t pdma_phys;
 	uint16_t iotag;
 
-	psb = kmalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
+	psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
 	if (!psb)
 		return NULL;
-	memset(psb, 0, sizeof (struct lpfc_scsi_buf));
 
 	/*
 	 * Get memory from the pci pool to map the virt space to pci bus space
@@ -411,7 +410,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
 		(num_bde * sizeof (struct ulp_bde64));
 	iocb_cmd->ulpBdeCount = 1;
 	iocb_cmd->ulpLe = 1;
-	fcp_cmnd->fcpDl = be32_to_cpu(scsi_cmnd->request_bufflen);
+	fcp_cmnd->fcpDl = cpu_to_be32(scsi_cmnd->request_bufflen);
 	return 0;
 }
 
@@ -437,8 +436,8 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
 }
 
 static void
-lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
-		    struct lpfc_iocbq *rsp_iocb)
+lpfc_handle_fcp_err(struct lpfc_hba *phba, struct lpfc_vport *vport,
+		    struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
 {
 	struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
 	struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
@@ -475,15 +474,16 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 	if (!scsi_status && (resp_info & RESID_UNDER))
 		logit = LOG_FCP;
 
-	lpfc_printf_vlog(vport, KERN_WARNING, logit,
-			 "0730 FCP command x%x failed: x%x SNS x%x x%x "
-			 "Data: x%x x%x x%x x%x x%x\n",
-			 cmnd->cmnd[0], scsi_status,
-			 be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
-			 be32_to_cpu(fcprsp->rspResId),
-			 be32_to_cpu(fcprsp->rspSnsLen),
-			 be32_to_cpu(fcprsp->rspRspLen),
-			 fcprsp->rspInfo3);
+	lpfc_printf_log(phba, KERN_WARNING, logit,
+			"(%d)0730 FCP command x%x failed: x%x SNS x%x x%x "
+			"Data: x%x x%x x%x x%x x%x\n",
+			(vport ? vport->vpi : 0),
+			cmnd->cmnd[0], scsi_status,
+			be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
+			be32_to_cpu(fcprsp->rspResId),
+			be32_to_cpu(fcprsp->rspSnsLen),
+			be32_to_cpu(fcprsp->rspRspLen),
+			fcprsp->rspInfo3);
 
 	if (resp_info & RSP_LEN_VALID) {
 		rsplen = be32_to_cpu(fcprsp->rspRspLen);
@@ -498,12 +498,13 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 	if (resp_info & RESID_UNDER) {
 		cmnd->resid = be32_to_cpu(fcprsp->rspResId);
 
-		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
-				 "0716 FCP Read Underrun, expected %d, "
-				 "residual %d Data: x%x x%x x%x\n",
-				 be32_to_cpu(fcpcmd->fcpDl),
-				 cmnd->resid, fcpi_parm, cmnd->cmnd[0],
-				 cmnd->underflow);
+		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+				"(%d)0716 FCP Read Underrun, expected %d, "
+				"residual %d Data: x%x x%x x%x\n",
+				(vport ? vport->vpi : 0),
+				be32_to_cpu(fcpcmd->fcpDl),
+				cmnd->resid, fcpi_parm, cmnd->cmnd[0],
+				cmnd->underflow);
 		/*
 		 * If there is an under run check if under run reported by
 		 * storage array is same as the under run reported by HBA.
@@ -512,12 +513,14 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 		if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
 			fcpi_parm &&
 			(cmnd->resid != fcpi_parm)) {
-			lpfc_printf_vlog(vport, KERN_WARNING,
-					 LOG_FCP | LOG_FCP_ERROR,
-					 "0735 FCP Read Check Error "
-					 "and Underrun Data: x%x x%x x%x x%x\n",
-					 be32_to_cpu(fcpcmd->fcpDl),
-					 cmnd->resid, fcpi_parm, cmnd->cmnd[0]);
+			lpfc_printf_log(phba, KERN_WARNING,
+					LOG_FCP | LOG_FCP_ERROR,
+					"(%d)0735 FCP Read Check Error "
+					"and Underrun Data: x%x x%x x%x x%x\n",
+					(vport ? vport->vpi : 0),
+					be32_to_cpu(fcpcmd->fcpDl),
+					cmnd->resid, fcpi_parm,
+					cmnd->cmnd[0]);
 			cmnd->resid = cmnd->request_bufflen;
 			host_status = DID_ERROR;
 		}
@@ -530,19 +533,22 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 		if (!(resp_info & SNS_LEN_VALID) &&
 		    (scsi_status == SAM_STAT_GOOD) &&
 		    (cmnd->request_bufflen - cmnd->resid) < cmnd->underflow) {
-			lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
-					 "0717 FCP command x%x residual "
-					 "underrun converted to error "
-					 "Data: x%x x%x x%x\n",
-					 cmnd->cmnd[0], cmnd->request_bufflen,
-					 cmnd->resid, cmnd->underflow);
+			lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
+					"(%d)0717 FCP command x%x residual "
+					"underrun converted to error "
+					"Data: x%x x%x x%x\n",
+					(vport ? vport->vpi : 0),
+					cmnd->cmnd[0], cmnd->request_bufflen,
+					cmnd->resid, cmnd->underflow);
 			host_status = DID_ERROR;
 		}
 	} else if (resp_info & RESID_OVER) {
-		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
-				 "0720 FCP command x%x residual overrun error. "
-				 "Data: x%x x%x \n", cmnd->cmnd[0],
-				 cmnd->request_bufflen, cmnd->resid);
+		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
+				"(%d)0720 FCP command x%x residual "
+				"overrun error. Data: x%x x%x \n",
+				(vport ? vport->vpi : 0),
+				cmnd->cmnd[0],
+				cmnd->request_bufflen, cmnd->resid);
 		host_status = DID_ERROR;
 
 	/*
@@ -551,12 +557,14 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 	 */
 	} else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm &&
 			(cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
-		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
-				 "0734 FCP Read Check Error Data: "
-				 "x%x x%x x%x x%x\n",
-				 be32_to_cpu(fcpcmd->fcpDl),
-				 be32_to_cpu(fcprsp->rspResId),
-				 fcpi_parm, cmnd->cmnd[0]);
+		lpfc_printf_log(phba, KERN_WARNING,
+				LOG_FCP | LOG_FCP_ERROR,
+				"(%d)0734 FCP Read Check Error Data: "
+				"x%x x%x x%x x%x\n",
+				(vport ? vport->vpi : 0),
+				be32_to_cpu(fcpcmd->fcpDl),
+				be32_to_cpu(fcprsp->rspResId),
+				fcpi_parm, cmnd->cmnd[0]);
 		host_status = DID_ERROR;
 		cmnd->resid = cmnd->request_bufflen;
 	}
@@ -578,6 +586,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 	int result;
 	struct scsi_device *sdev, *tmp_sdev;
 	int depth = 0;
+	unsigned long flags;
 
 	lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
 	lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
@@ -589,11 +598,11 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 		else if (lpfc_cmd->status >= IOSTAT_CNT)
 			lpfc_cmd->status = IOSTAT_DEFAULT;
 
-		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
 				 "0729 FCP cmd x%x failed <%d/%d> "
 				 "status: x%x result: x%x Data: x%x x%x\n",
 				 cmd->cmnd[0],
-				 cmd->device ? cmd->device->id : 0xffff,
+				 vport ? vport->vpi : 0,
 				 cmd->device ? cmd->device->lun : 0xffff,
 				 lpfc_cmd->status, lpfc_cmd->result,
 				 pIocbOut->iocb.ulpContext,
@@ -602,7 +611,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 		switch (lpfc_cmd->status) {
 		case IOSTAT_FCP_RSP_ERROR:
 			/* Call FCP RSP handler to determine result */
-			lpfc_handle_fcp_err(vport, lpfc_cmd, pIocbOut);
+			lpfc_handle_fcp_err(phba, vport, lpfc_cmd, pIocbOut);
 			break;
 		case IOSTAT_NPORT_BSY:
 		case IOSTAT_FABRIC_BSY:
@@ -630,10 +639,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 	if (cmd->result || lpfc_cmd->fcp_rsp->rspSnsLen) {
 		uint32_t *lp = (uint32_t *)cmd->sense_buffer;
 
-		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
 				 "0710 Iodone <%d/%d> cmd %p, error "
 				 "x%x SNS x%x x%x Data: x%x x%x\n",
-				 cmd->device->id, cmd->device->lun, cmd,
+				 vport ? vport->vpi : 0, cmd->device->lun, cmd,
 				 cmd->result, *lp, *(lp + 3), cmd->retries,
 				 cmd->resid);
 	}
@@ -644,10 +653,21 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 	cmd->scsi_done(cmd);
 
 	if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
+		/*
+		 * If there is a thread waiting for command completion
+		 * wake up the thread.
+		 */
+		spin_lock_irqsave(sdev->host->host_lock, flags);
+		lpfc_cmd->pCmd = NULL;
+		if (lpfc_cmd->waitq)
+			wake_up(lpfc_cmd->waitq);
+		spin_unlock_irqrestore(sdev->host->host_lock, flags);
 		lpfc_release_scsi_buf(phba, lpfc_cmd);
 		return;
 	}
 
+	if (!vport)
+		goto out_vport_deleted;
 
 	if (!result)
 		lpfc_rampup_queue_depth(vport, sdev);
@@ -705,6 +725,17 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 		}
 	}
 
+ out_vport_deleted:
+	/*
+	 * If there is a thread waiting for command completion
+	 * wake up the thread.
+	 */
+	spin_lock_irqsave(sdev->host->host_lock, flags);
+	lpfc_cmd->pCmd = NULL;
+	if (lpfc_cmd->waitq)
+		wake_up(lpfc_cmd->waitq);
+	spin_unlock_irqrestore(sdev->host->host_lock, flags);
+
 	lpfc_release_scsi_buf(phba, lpfc_cmd);
 }
 
@@ -718,6 +749,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 	IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
 	struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq);
 	int datadir = scsi_cmnd->sc_data_direction;
+	char tag[2];
 
 	lpfc_cmd->fcp_rsp->rspSnsLen = 0;
 	/* clear task management bits */
@@ -728,8 +760,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 
 	memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16);
 
-	if (scsi_cmnd->device->tagged_supported) {
-		switch (scsi_cmnd->tag) {
+	if (scsi_populate_tag_msg(scsi_cmnd, tag)) {
+		switch (tag[0]) {
 		case HEAD_OF_QUEUE_TAG:
 			fcp_cmnd->fcpCntl1 = HEAD_OF_Q;
 			break;
@@ -794,6 +826,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 	piocbq->iocb.ulpContext = pnode->nlp_rpi;
 	if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE)
 		piocbq->iocb.ulpFCP2Rcvy = 1;
+	else
+		piocbq->iocb.ulpFCP2Rcvy = 0;
 
 	piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f);
 	piocbq->context1  = lpfc_cmd;
@@ -975,12 +1009,33 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
 	struct lpfc_rport_data *rdata = cmnd->device->hostdata;
 	struct lpfc_nodelist *ndlp = rdata->pnode;
 	struct lpfc_scsi_buf *lpfc_cmd;
+	struct scsi_device *sdev;
 	struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
 	int err;
 
 	err = fc_remote_port_chkready(rport);
 	if (err) {
 		cmnd->result = err;
+		sdev = cmnd->device;
+		if ((phba->link_state == LPFC_HBA_ERROR) &&
+			(cmnd->result == ScsiResult(DID_NO_CONNECT, 0)) &&
+			(sdev->queue_depth != 1)) {
+
+			/* If we reach this point, the HBA is not responding
+			 * and has been taken offline. If alot of SCSI IO
+			 * was active, this could cause a massive amount of
+			 * SCSI layer initiated logging. On some systems,
+			 * this massive amount of logging has been known to
+			 * cause CPU soft lockups. In an attempt to throttle
+			 * the amount of logging, set the sdev queue depth to 1.
+			 */
+			if (sdev->ordered_tags)
+				scsi_adjust_queue_depth(sdev,
+					MSG_ORDERED_TAG, 1);
+			else
+				scsi_adjust_queue_depth(sdev,
+					MSG_SIMPLE_TAG, 1);
+		}
 		goto out_fail_command;
 	}
 
@@ -1072,8 +1127,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 	struct lpfc_iocbq *abtsiocb;
 	struct lpfc_scsi_buf *lpfc_cmd;
 	IOCB_t *cmd, *icmd;
-	unsigned int loop_count = 0;
 	int ret = SUCCESS;
+	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
+
 
 	lpfc_block_error_handler(cmnd);
 	lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
@@ -1128,17 +1184,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 	if (phba->cfg_poll & DISABLE_FCP_RING_INT)
 		lpfc_sli_poll_fcp_ring (phba);
 
+	lpfc_cmd->waitq = &waitq;
 	/* Wait for abort to complete */
-	while (lpfc_cmd->pCmd == cmnd)
-	{
-		if (phba->cfg_poll & DISABLE_FCP_RING_INT)
-			lpfc_sli_poll_fcp_ring (phba);
+	wait_event_timeout(waitq,
+			  (lpfc_cmd->pCmd != cmnd),
+			   (2*vport->cfg_devloss_tmo*HZ));
 
-		schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ);
-		if (++loop_count
-		    > (2 * vport->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
-			break;
-	}
+	spin_lock_irq(shost->host_lock);
+	lpfc_cmd->waitq = NULL;
+	spin_unlock_irq(shost->host_lock);
 
 	if (lpfc_cmd->pCmd == cmnd) {
 		ret = FAILED;
@@ -1491,7 +1545,7 @@ struct scsi_host_template lpfc_template = {
 	.slave_configure	= lpfc_slave_configure,
 	.slave_destroy		= lpfc_slave_destroy,
 	.this_id		= -1,
-	.sg_tablesize		= LPFC_SG_SEG_CNT,
+	.sg_tablesize		= LPFC_DEFAULT_SG_SEG_CNT,
 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.shost_attrs		= lpfc_hba_attrs,
@@ -1510,7 +1564,7 @@ struct scsi_host_template lpfc_template_no_npiv = {
 	.slave_configure	= lpfc_slave_configure,
 	.slave_destroy		= lpfc_slave_destroy,
 	.this_id		= -1,
-	.sg_tablesize		= LPFC_SG_SEG_CNT,
+	.sg_tablesize		= LPFC_DEFAULT_SG_SEG_CNT,
 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.shost_attrs		= lpfc_hba_attrs_no_npiv,
@@ -1529,7 +1583,7 @@ struct scsi_host_template lpfc_vport_template = {
 	.slave_configure	= lpfc_slave_configure,
 	.slave_destroy		= lpfc_slave_destroy,
 	.this_id		= -1,
-	.sg_tablesize		= LPFC_SG_SEG_CNT,
+	.sg_tablesize		= LPFC_DEFAULT_SG_SEG_CNT,
 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.shost_attrs		= lpfc_vport_attrs,
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index 31787bb..daba923 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -138,6 +138,7 @@ struct lpfc_scsi_buf {
 	 * Iotag is in here
 	 */
 	struct lpfc_iocbq cur_iocbq;
+	wait_queue_head_t *waitq;
 };
 
 #define LPFC_SCSI_DMA_EXT_SIZE 264
diff --git a/drivers/scsi/lpfc/lpfc_security.c b/drivers/scsi/lpfc/lpfc_security.c
index 413b022..6cf4d96 100644
--- a/drivers/scsi/lpfc/lpfc_security.c
+++ b/drivers/scsi/lpfc/lpfc_security.c
@@ -39,7 +39,13 @@ uint8_t lpfc_security_service_state = SECURITY_OFFLINE;
 void
 lpfc_security_service_online(struct Scsi_Host *shost)
 {
+	struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
+
 	lpfc_security_service_state = SECURITY_ONLINE;
+	if (vport->cfg_enable_auth &&
+	    vport->auth.auth_mode == FC_AUTHMODE_UNKNOWN &&
+	    vport->phba->link_state == LPFC_HBA_ERROR)
+		lpfc_selective_reset(vport->phba);
 }
 
 void
@@ -54,66 +60,79 @@ lpfc_security_config(struct Scsi_Host *shost, int status, void *rsp)
 	struct fc_auth_rsp *auth_rsp = (struct fc_auth_rsp *)rsp;
 	struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
 	struct lpfc_nodelist *ndlp;
+	uint32_t old_interval, new_interval;
+	unsigned long new_jiffies, temp_jiffies;
 
-	if (status == 0) {
-		vport->auth.bidirectional =
-			auth_rsp->u.dhchap_security_config.bidirectional;
-		memcpy(&vport->auth.hash_priority[0],
-			&auth_rsp->u.dhchap_security_config.hash_priority[0],
-			sizeof(vport->auth.hash_priority));
-		vport->auth.hash_len =
-			auth_rsp->u.dhchap_security_config.hash_len;
-		memcpy(&vport->auth.dh_group_priority[0],
-			&auth_rsp->u.dhchap_security_config.
-			dh_group_priority[0],
-			sizeof(vport->auth.dh_group_priority));
-		vport->auth.dh_group_len =
-			auth_rsp->u.dhchap_security_config.dh_group_len;
-		vport->auth.reauth_interval =
-			auth_rsp->u.dhchap_security_config.reauth_interval;
-		vport->auth.auth_mode =
-			auth_rsp->u.dhchap_security_config.auth_mode;
-
-		lpfc_printf_vlog(vport, KERN_INFO, LOG_SECURITY,
-			"1025 Received security config local_wwpn:"
-			"%llX remote_wwpn:%llX \nmode:0x%x "
-			"hash(%d):%x:%x:%x:%x bidir:0x%x "
-			"dh_group(%d):%x:%x:%x:%x:%x:%x:%x:%x "
-			"reauth_interval:0x%x\n",
-			(unsigned long long)auth_rsp->local_wwpn,
-			(unsigned long long)auth_rsp->remote_wwpn,
-			auth_rsp->u.dhchap_security_config.auth_mode,
-			auth_rsp->u.dhchap_security_config.hash_len,
-			auth_rsp->u.dhchap_security_config.hash_priority[0],
-			auth_rsp->u.dhchap_security_config.hash_priority[1],
-			auth_rsp->u.dhchap_security_config.hash_priority[2],
-			auth_rsp->u.dhchap_security_config.hash_priority[3],
-			auth_rsp->u.dhchap_security_config.bidirectional,
-			auth_rsp->u.dhchap_security_config.dh_group_len,
-			auth_rsp->u.dhchap_security_config.dh_group_priority[0],
-			auth_rsp->u.dhchap_security_config.dh_group_priority[1],
-			auth_rsp->u.dhchap_security_config.dh_group_priority[2],
-			auth_rsp->u.dhchap_security_config.dh_group_priority[3],
-			auth_rsp->u.dhchap_security_config.dh_group_priority[4],
-			auth_rsp->u.dhchap_security_config.dh_group_priority[5],
-			auth_rsp->u.dhchap_security_config.dh_group_priority[6],
-			auth_rsp->u.dhchap_security_config.dh_group_priority[7],
-			auth_rsp->u.dhchap_security_config.reauth_interval);
-		kfree(auth_rsp);
-	}
-
-	/* re-authenticate whenever we get new configs */
-	ndlp = lpfc_findnode_did(vport, Fabric_DID);
-	if (!ndlp) {
-		lpfc_printf_vlog(vport, KERN_WARNING, LOG_SECURITY,
-				 "1026 Unable to find ndlp. \n");
+	if (status)
 		return;
+	ndlp = lpfc_findnode_did(vport, Fabric_DID);
+	vport->auth.bidirectional =
+		auth_rsp->u.dhchap_security_config.bidirectional;
+	memcpy(&vport->auth.hash_priority[0],
+	       &auth_rsp->u.dhchap_security_config.hash_priority[0],
+	       sizeof(vport->auth.hash_priority));
+	vport->auth.hash_len = auth_rsp->u.dhchap_security_config.hash_len;
+	memcpy(&vport->auth.dh_group_priority[0],
+	       &auth_rsp->u.dhchap_security_config.
+	       dh_group_priority[0],
+	       sizeof(vport->auth.dh_group_priority));
+	vport->auth.dh_group_len =
+		auth_rsp->u.dhchap_security_config.dh_group_len;
+	old_interval = vport->auth.reauth_interval;
+	vport->auth.reauth_interval =
+		auth_rsp->u.dhchap_security_config.reauth_interval;
+	new_interval = vport->auth.reauth_interval;
+	/*
+	 * If interval changed we need to adjust the running timer
+	 *  If enabled then start timer now.
+	 *  If disabled then stop the timer.
+	 *  If changed to chorter then elapsed time, then set to fire now
+	 *  If changed to longer than elapsed time, extend the timer.
+	 */
+	if (old_interval != new_interval &&
+	    vport->auth.auth_state == LPFC_AUTH_SUCCESS) {
+		new_jiffies = msecs_to_jiffies(new_interval * 60000);
+		del_timer_sync(&ndlp->nlp_reauth_tmr);
+		if (old_interval == 0)
+			temp_jiffies = jiffies + new_jiffies;
+		if (new_interval == 0)
+			temp_jiffies = 0;
+		else if (new_jiffies < (jiffies - vport->auth.last_auth))
+			temp_jiffies = jiffies + msecs_to_jiffies(1);
+		else
+			temp_jiffies = jiffies + (new_jiffies -
+				(jiffies - vport->auth.last_auth));
+		if (temp_jiffies)
+			mod_timer(&ndlp->nlp_reauth_tmr, temp_jiffies);
 	}
-	if (vport->port_state == LPFC_VPORT_READY) {
-		lpfc_printf_vlog(vport, KERN_WARNING, LOG_SECURITY,
-				 "1027 Re-Authentication triggered. \n");
-		lpfc_start_authentication(vport, ndlp);
-	}
+	vport->auth.auth_mode =
+		auth_rsp->u.dhchap_security_config.auth_mode;
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_SECURITY,
+		"1025 Received security config local_wwpn:"
+		 "%llX remote_wwpn:%llX \nmode:0x%x "
+		 "hash(%d):%x:%x:%x:%x bidir:0x%x "
+		 "dh_group(%d):%x:%x:%x:%x:%x:%x:%x:%x "
+		 "reauth_interval:0x%x\n",
+		 (unsigned long long)auth_rsp->local_wwpn,
+		 (unsigned long long)auth_rsp->remote_wwpn,
+		 auth_rsp->u.dhchap_security_config.auth_mode,
+		 auth_rsp->u.dhchap_security_config.hash_len,
+		 auth_rsp->u.dhchap_security_config.hash_priority[0],
+		 auth_rsp->u.dhchap_security_config.hash_priority[1],
+		 auth_rsp->u.dhchap_security_config.hash_priority[2],
+		 auth_rsp->u.dhchap_security_config.hash_priority[3],
+		 auth_rsp->u.dhchap_security_config.bidirectional,
+		 auth_rsp->u.dhchap_security_config.dh_group_len,
+		 auth_rsp->u.dhchap_security_config.dh_group_priority[0],
+		 auth_rsp->u.dhchap_security_config.dh_group_priority[1],
+		 auth_rsp->u.dhchap_security_config.dh_group_priority[2],
+		 auth_rsp->u.dhchap_security_config.dh_group_priority[3],
+		 auth_rsp->u.dhchap_security_config.dh_group_priority[4],
+		 auth_rsp->u.dhchap_security_config.dh_group_priority[5],
+		 auth_rsp->u.dhchap_security_config.dh_group_priority[6],
+		 auth_rsp->u.dhchap_security_config.dh_group_priority[7],
+		 auth_rsp->u.dhchap_security_config.reauth_interval);
+	kfree(auth_rsp);
 }
 
 int
@@ -125,17 +144,22 @@ lpfc_get_security_enabled(struct Scsi_Host *shost)
 }
 
 int
-lpfc_security_wait(void)
+lpfc_security_wait(struct lpfc_hba *phba)
 {
 	int i = 0;
+	if (lpfc_security_service_state == SECURITY_ONLINE)
+		return 0;
+	lpfc_printf_log(phba, KERN_WARNING, LOG_SECURITY,
+			"1058 Waiting for authentication service...\n");
 	while (lpfc_security_service_state == SECURITY_OFFLINE) {
 		i++;
-		if (i > 240) {
+		if (i > SECURITY_WAIT_TMO * 2)
 			return -ETIMEDOUT;
-		}
 		/* Delay for half of a second */
 		msleep(500);
 	}
+	lpfc_printf_log(phba, KERN_WARNING, LOG_SECURITY,
+			"1059 Authentication service online.\n");
 	return 0;
 }
 
@@ -206,6 +230,35 @@ int
 lpfc_start_node_authentication(struct lpfc_nodelist *ndlp)
 {
 	struct lpfc_vport *vport;
+	int ret;
+
+	vport = ndlp->vport;
+	/* If there is authentication timer cancel the timer */
+	del_timer_sync(&ndlp->nlp_reauth_tmr);
+	if ((ret = lpfc_get_auth_config(ndlp)))
+		return ret;
+	if ((ret = lpfc_security_config_wait(vport))) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY,
+				 "1032 Start Authentication: get config "
+				 "timed out.\n");
+		return ret;
+	}
+	/* no need to authenticate if mode is disabled (not an error) */
+	if (vport->auth.auth_mode == FC_AUTHMODE_NONE)
+		return 0;
+	/* re-authenticate after getting new configs */
+	if (vport->port_state == LPFC_VPORT_READY) {
+		lpfc_printf_vlog(vport, KERN_WARNING, LOG_SECURITY,
+				 "1027 Re-Authentication triggered. \n");
+		lpfc_start_authentication(vport, ndlp);
+	}
+	return 0;
+}
+
+int
+lpfc_get_auth_config(struct lpfc_nodelist *ndlp)
+{
+	struct lpfc_vport *vport;
 	struct fc_auth_req auth_req;
 	struct fc_auth_rsp *auth_rsp;
 	struct Scsi_Host   *shost;
@@ -214,9 +267,6 @@ lpfc_start_node_authentication(struct lpfc_nodelist *ndlp)
 	vport = ndlp->vport;
 	shost = lpfc_shost_from_vport(vport);
 
-	/* If there is authentication timer cancel the timer */
-	del_timer_sync(&ndlp->nlp_reauth_tmr);
-
 	auth_req.local_wwpn = wwn_to_u64(vport->fc_portname.u.wwn);
 	if (ndlp->nlp_type & NLP_FABRIC)
 		auth_req.remote_wwpn = AUTH_FABRIC_WWN;
@@ -235,6 +285,7 @@ lpfc_start_node_authentication(struct lpfc_nodelist *ndlp)
 		return -ENOMEM;
 	}
 
+	vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN;
 	if ((ret = lpfc_fc_security_get_config(shost, &auth_req,
 					       sizeof(struct fc_auth_req),
 					       auth_rsp,
@@ -245,11 +296,5 @@ lpfc_start_node_authentication(struct lpfc_nodelist *ndlp)
 		kfree(auth_rsp);
 		return ret;
 	}
-	if ((ret = lpfc_security_config_wait(vport))) {
-		lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY,
-				 "1032 Start Authentication: get config "
-				 "timed out.\n");
-		return ret;
-	}
 	return 0;
 }
diff --git a/drivers/scsi/lpfc/lpfc_security.h b/drivers/scsi/lpfc/lpfc_security.h
index c86d36d..2d5fe20 100644
--- a/drivers/scsi/lpfc/lpfc_security.h
+++ b/drivers/scsi/lpfc/lpfc_security.h
@@ -20,3 +20,5 @@
 
 #define SECURITY_OFFLINE     0x0
 #define SECURITY_ONLINE      0x1
+
+#define SECURITY_WAIT_TMO    30	/* seconds to wait for the auth service */
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 1d807ff..806723b 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -529,10 +529,13 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
 {
 	struct lpfc_dmabuf *dmabuf, *next_dmabuf;
 	struct hbq_dmabuf *hbq_buf;
+	unsigned long flags;
 	int i, hbq_count;
+	uint32_t hbqno;
 
 	hbq_count = lpfc_sli_hbq_count();
 	/* Return all memory used by all HBQs */
+	spin_lock_irqsave(&phba->hbalock, flags);
 	for (i = 0; i < hbq_count; ++i) {
 		list_for_each_entry_safe(dmabuf, next_dmabuf,
 				&phba->hbqs[i].hbq_buffer_list, list) {
@@ -542,6 +545,28 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
 		}
 		phba->hbqs[i].buffer_count = 0;
 	}
+	/* Return all HBQ buffer that are in-fly */
+	list_for_each_entry_safe(dmabuf, next_dmabuf,
+			&phba->hbqbuf_in_list, list) {
+		hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
+		list_del(&hbq_buf->dbuf.list);
+		if (hbq_buf->tag == -1) {
+			(phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
+				(phba, hbq_buf);
+		} else {
+			hbqno = hbq_buf->tag >> 16;
+			if (hbqno >= LPFC_MAX_HBQS)
+				(phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
+					(phba, hbq_buf);
+			else
+				(phba->hbqs[hbqno].hbq_free_buffer)(phba,
+					hbq_buf);
+		}
+	}
+
+	/* Mark the HBQs not in use */
+	phba->hbq_in_use = 0;
+	spin_unlock_irqrestore(&phba->hbalock, flags);
 }
 
 static struct lpfc_hbq_entry *
@@ -603,6 +628,7 @@ static int
 lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
 {
 	uint32_t i, start, end;
+	unsigned long flags;
 	struct hbq_dmabuf *hbq_buffer;
 
 	if (!phba->hbqs[hbqno].hbq_alloc_buffer) {
@@ -615,6 +641,13 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
 		end = lpfc_hbq_defs[hbqno]->entry_count;
 	}
 
+	/* Check whether HBQ is still in use */
+	spin_lock_irqsave(&phba->hbalock, flags);
+	if (!phba->hbq_in_use) {
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		return 0;
+	}
+
 	/* Populate HBQ entries */
 	for (i = start; i < end; i++) {
 		hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
@@ -626,6 +659,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
 		else
 			(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
 	}
+
+	spin_unlock_irqrestore(&phba->hbalock, flags);
 	return 0;
 }
 
@@ -651,7 +686,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
 	uint32_t hbqno;
 
 	hbqno = tag >> 16;
-	if (hbqno > LPFC_MAX_HBQS)
+	if (hbqno >= LPFC_MAX_HBQS)
 		return NULL;
 
 	list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
@@ -716,7 +751,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
 	case MBX_DEL_LD_ENTRY:
 	case MBX_RUN_PROGRAM:
 	case MBX_SET_MASK:
-	case MBX_SET_SLIM:
+	case MBX_SET_VARIABLE:
 	case MBX_UNREG_D_ID:
 	case MBX_KILL_BOARD:
 	case MBX_CONFIG_FARP:
@@ -728,7 +763,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
 	case MBX_READ_RPI64:
 	case MBX_REG_LOGIN64:
 	case MBX_READ_LA64:
-	case MBX_FLASH_WR_ULA:
+	case MBX_WRITE_WWN:
 	case MBX_SET_DEBUG:
 	case MBX_LOAD_EXP_ROM:
 	case MBX_ASYNCEVT_ENABLE:
@@ -910,16 +945,29 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
 	uint32_t hbqno;
 	void *virt;		/* virtual address ptr */
 	dma_addr_t phys;	/* mapped address */
+	unsigned long flags;
+
+	/* Check whether HBQ is still in use */
+	spin_lock_irqsave(&phba->hbalock, flags);
+	if (!phba->hbq_in_use) {
+		spin_unlock_irqrestore(&phba->hbalock, flags);
+		return NULL;
+	}
 
 	hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
-	if (hbq_entry == NULL)
+	if (hbq_entry == NULL) {
+		spin_unlock_irqrestore(&phba->hbalock, flags);
 		return NULL;
+	}
 	list_del(&hbq_entry->dbuf.list);
 
 	hbqno = tag >> 16;
 	new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
-	if (new_hbq_entry == NULL)
+	if (new_hbq_entry == NULL) {
+		list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list);
+		spin_unlock_irqrestore(&phba->hbalock, flags);
 		return &hbq_entry->dbuf;
+	}
 	new_hbq_entry->tag = -1;
 	phys = new_hbq_entry->dbuf.phys;
 	virt = new_hbq_entry->dbuf.virt;
@@ -928,9 +976,22 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
 	hbq_entry->dbuf.phys = phys;
 	hbq_entry->dbuf.virt = virt;
 	lpfc_sli_free_hbq(phba, hbq_entry);
+	list_add_tail(&new_hbq_entry->dbuf.list, &phba->hbqbuf_in_list);
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+
 	return &new_hbq_entry->dbuf;
 }
 
+static struct lpfc_dmabuf *
+lpfc_sli_get_buff(struct lpfc_hba *phba,
+			struct lpfc_sli_ring *pring,
+			uint32_t tag)
+{
+	if (tag & QUE_BUFTAG_BIT)
+		return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
+	else
+		return lpfc_sli_replace_hbqbuff(phba, tag);
+}
 
 static int
 lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
@@ -940,10 +1001,13 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	WORD5            * w5p;
 	uint32_t           Rctl, Type;
 	uint32_t           match, i;
+	struct lpfc_iocbq *iocbq;
 
 	match = 0;
 	irsp = &(saveq->iocb);
 
+	if (irsp->ulpStatus == IOSTAT_NEED_BUFFER)
+		return 1;
 	if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
 		if (pring->lpfc_sli_rcv_async_status)
 			pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
@@ -959,16 +1023,90 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		return 1;
 	}
 
-	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX)
-	    || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)
-	    || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)
-	    || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) {
+	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+		if (irsp->ulpBdeCount != 0) {
+			saveq->context2 = lpfc_sli_get_buff(phba, pring,
+						irsp->un.ulpWord[3]);
+			if (!saveq->context2)
+				lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_SLI,
+					"0341 Ring %d Cannot find buffer for "
+					"an unsolicited iocb. tag 0x%x\n",
+					pring->ringno,
+					irsp->un.ulpWord[3]);
+		}
+		if (irsp->ulpBdeCount == 2) {
+			saveq->context3 = lpfc_sli_get_buff(phba, pring,
+						irsp->unsli3.sli3Words[7]);
+			if (!saveq->context3)
+				lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_SLI,
+					"0342 Ring %d Cannot find buffer for an"
+					" unsolicited iocb. tag 0x%x\n",
+					pring->ringno,
+					irsp->unsli3.sli3Words[7]);
+		}
+		list_for_each_entry(iocbq, &saveq->list, list) {
+			irsp = &(iocbq->iocb);
+			if (irsp->ulpBdeCount != 0) {
+				iocbq->context2 = lpfc_sli_get_buff(phba, pring,
+							irsp->un.ulpWord[3]);
+				if (!iocbq->context2)
+					lpfc_printf_log(phba,
+						KERN_ERR,
+						LOG_SLI,
+						"0343 Ring %d Cannot find "
+						"buffer for an unsolicited iocb"
+						". tag 0x%x\n", pring->ringno,
+						irsp->un.ulpWord[3]);
+			}
+			if (irsp->ulpBdeCount == 2) {
+				iocbq->context3 = lpfc_sli_get_buff(phba, pring,
+						irsp->unsli3.sli3Words[7]);
+				if (!iocbq->context3)
+					lpfc_printf_log(phba,
+						KERN_ERR,
+						LOG_SLI,
+						"0344 Ring %d Cannot find "
+						"buffer for an unsolicited "
+						"iocb. tag 0x%x\n",
+						pring->ringno,
+						irsp->unsli3.sli3Words[7]);
+			}
+		}
+	}
+	if (irsp->ulpBdeCount != 0 &&
+	    (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX ||
+	     irsp->ulpStatus == IOSTAT_INTERMED_RSP)) {
+		int found = 0;
+
+		/* search continue save q for same XRI */
+		list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) {
+			if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) {
+				list_add_tail(&saveq->list, &iocbq->list);
+				found = 1;
+				break;
+			}
+		}
+		if (!found)
+			list_add_tail(&saveq->clist,
+				      &pring->iocb_continue_saveq);
+		if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) {
+			list_del_init(&iocbq->clist);
+			saveq = iocbq;
+			irsp = &(saveq->iocb);
+		} else
+			return 0;
+	}
+	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) ||
+	    (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) ||
+	    (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) {
 		Rctl = FC_ELS_REQ;
 		Type = FC_ELS_DATA;
 	} else {
-		w5p =
-		    (WORD5 *) & (saveq->iocb.un.
-				 ulpWord[5]);
+		w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]);
 		Rctl = w5p->hcsw.Rctl;
 		Type = w5p->hcsw.Type;
 
@@ -983,15 +1121,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		}
 	}
 
-	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
-		if (irsp->ulpBdeCount != 0)
-			saveq->context2 = lpfc_sli_replace_hbqbuff(phba,
-						irsp->un.ulpWord[3]);
-		if (irsp->ulpBdeCount == 2)
-			saveq->context3 = lpfc_sli_replace_hbqbuff(phba,
-						irsp->unsli3.sli3Words[7]);
-	}
-
 	/* unSolicited Responses */
 	if (pring->prt[0].profile) {
 		if (pring->prt[0].lpfc_sli_rcv_unsol_event)
@@ -1001,12 +1130,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	} else {
 		/* We must search, based on rctl / type
 		   for the right routine */
-		for (i = 0; i < pring->num_mask;
-		     i++) {
-			if ((pring->prt[i].rctl ==
-			     Rctl)
-			    && (pring->prt[i].
-				type == Type)) {
+		for (i = 0; i < pring->num_mask; i++) {
+			if ((pring->prt[i].rctl == Rctl)
+			    && (pring->prt[i].type == Type)) {
 				if (pring->prt[i].lpfc_sli_rcv_unsol_event)
 					(pring->prt[i].lpfc_sli_rcv_unsol_event)
 							(phba, pring, saveq);
@@ -1079,6 +1205,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 						IOSTAT_LOCAL_REJECT;
 					saveq->iocb.un.ulpWord[4] =
 						IOERR_SLI_ABORTED;
+
+					/* Firmware could still be in progress
+					 * of DMAing payload, so don't free data
+					 * buffer till after a hbeat.
+					 */
+					saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
 				}
 			}
 			(cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -1565,12 +1697,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 
 		writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
 
-		if (list_empty(&(pring->iocb_continueq))) {
-			list_add(&rspiocbp->list, &(pring->iocb_continueq));
-		} else {
-			list_add_tail(&rspiocbp->list,
-				      &(pring->iocb_continueq));
-		}
+		list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));
 
 		pring->iocb_continueq_cnt++;
 		if (irsp->ulpLe) {
@@ -1635,17 +1762,17 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 			iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
 			type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
 			if (type == LPFC_SOL_IOCB) {
-				spin_unlock_irqrestore(&phba->hbalock,
-						       iflag);
+				spin_unlock_irqrestore(&phba->hbalock, iflag);
 				rc = lpfc_sli_process_sol_iocb(phba, pring,
 							       saveq);
 				spin_lock_irqsave(&phba->hbalock, iflag);
 			} else if (type == LPFC_UNSOL_IOCB) {
-				spin_unlock_irqrestore(&phba->hbalock,
-						       iflag);
+				spin_unlock_irqrestore(&phba->hbalock, iflag);
 				rc = lpfc_sli_process_unsol_iocb(phba, pring,
 								 saveq);
 				spin_lock_irqsave(&phba->hbalock, iflag);
+				if (!rc)
+					free_saveq = 0;
 			} else if (type == LPFC_ABORT_IOCB) {
 				if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
 				    ((cmdiocbp =
@@ -2026,6 +2153,72 @@ lpfc_sli_brdreset(struct lpfc_hba *phba)
 }
 
 int
+lpfc_sli_set_dma_length(struct lpfc_hba * phba, uint32_t polling)
+{
+	uint32_t dma_length;
+	LPFC_MBOXQ_t *mbox;
+	int ret = 0;
+
+	switch (phba->cfg_pci_max_read) {
+		case 512:
+			dma_length = SLIM_VAL_MAX_DMA_512;
+			break;
+		case 1024:
+			dma_length = SLIM_VAL_MAX_DMA_1024;
+			break;
+		case 2048:
+			dma_length = SLIM_VAL_MAX_DMA_2048;
+			break;
+		case 4096:
+			dma_length = SLIM_VAL_MAX_DMA_4096;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!mbox)
+		goto failed;
+
+	lpfc_set_var(phba, mbox, SLIM_VAR_MAX_DMA_LENGTH, dma_length);
+
+	if (polling)
+		ret = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
+	else
+		ret = lpfc_sli_issue_mbox_wait(phba, mbox,
+			LPFC_MBOX_TMO * 2);
+
+	if (ret != MBX_SUCCESS) {
+		if (mbox->mb.mbxStatus != MBXERR_UNKNOWN_CMD)
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"%d:0443 Adapter failed to set maximum"
+				" DMA length mbxStatus x%x \n",
+				phba->brd_no, mbox->mb.mbxStatus)
+		else
+			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+				"%d:0447 Adapter failed to set maximum"
+				" DMA length mbxStatus x%x \n",
+				phba->brd_no, mbox->mb.mbxStatus);
+		goto failed;
+	}
+
+	mempool_free( mbox, phba->mbox_mem_pool);
+	return 0;
+
+failed:
+	/* If mailbox command failed, reset the value to default value */
+	phba->cfg_pci_max_read = 2048;
+	if (ret == MBX_TIMEOUT) {
+		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+		return -EPERM;
+	} else if (mbox) {
+		mempool_free( mbox, phba->mbox_mem_pool);
+		return -EPERM;
+	} else
+		return -ENOMEM;
+}
+
+int
 lpfc_sli_brdrestart(struct lpfc_hba *phba)
 {
 	MAILBOX_t *mb;
@@ -2194,18 +2387,13 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba)
 	uint32_t hbqno;
 	uint32_t hbq_entry_index;
 
-				/* Get a Mailbox buffer to setup mailbox
-				 * commands for HBA initialization
-				 */
 	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-
 	if (!pmb)
 		return -ENOMEM;
-
 	pmbox = &pmb->mb;
-
 	/* Initialize the struct lpfc_sli_hbq structure for each hbq */
 	phba->link_state = LPFC_INIT_MBX_CMDS;
+	phba->hbq_in_use = 1;
 
 	hbq_entry_index = 0;
 	for (hbqno = 0; hbqno < hbq_count; ++hbqno) {
@@ -2215,20 +2403,16 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba)
 		phba->hbqs[hbqno].entry_count =
 			lpfc_hbq_defs[hbqno]->entry_count;
 		lpfc_config_hbq(phba, hbqno, lpfc_hbq_defs[hbqno],
-			hbq_entry_index, pmb);
+				hbq_entry_index, pmb);
 		hbq_entry_index += phba->hbqs[hbqno].entry_count;
 
 		if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
-			/* Adapter failed to init, mbxCmd <cmd> CFG_RING,
-			   mbxStatus <status>, ring <num> */
-
 			lpfc_printf_log(phba, KERN_ERR,
 					LOG_SLI | LOG_VPORT,
 					"1805 Adapter failed to init. "
 					"Data: x%x x%x x%x\n",
 					pmbox->mbxCommand,
 					pmbox->mbxStatus, hbqno);
-
 			phba->link_state = LPFC_HBA_ERROR;
 			mempool_free(pmb, phba->mbox_mem_pool);
 			return ENXIO;
@@ -2379,6 +2563,9 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
 	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 			"0444 Firmware in SLI %x mode. Max_vpi %d\n",
 			phba->sli_rev, phba->max_vpi);
+
+	lpfc_sli_set_dma_length(phba,1);
+
 	rc = lpfc_sli_ring_map(phba);
 
 	if (rc)
@@ -2478,11 +2665,16 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
 	lpfc_sli_abort_iocb_ring(phba, pring);
 
 	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
-			"0316 Resetting board due to mailbox timeout\n");
+			"0345 Resetting board due to mailbox timeout\n");
 	/*
 	 * lpfc_offline calls lpfc_sli_hba_down which will clean up
 	 * on oustanding mailbox commands.
 	 */
+	/* If resets are disabled then set error state and return. */
+	if (!phba->cfg_enable_hba_reset) {
+		phba->link_state = LPFC_HBA_ERROR;
+		return;
+	}
 	lpfc_offline_prep(phba);
 	lpfc_offline(phba);
 	lpfc_sli_brdrestart(phba);
@@ -2646,6 +2838,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 	if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
 		/* First copy command data to host SLIM area */
 		lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE);
+		if ((mb->mbxCommand == MBX_UPDATE_CFG) && pmbox->context2)
+			lpfc_sli_pcimem_bcopy(pmbox->context2,
+				(uint8_t*)&phba->slim2p->mbx +
+				mb->un.varUpdateCfg.data_offset,
+				mb->un.varUpdateCfg.byte_cnt);
+
 	} else {
 		if (mb->mbxCommand == MBX_CONFIG_PORT) {
 			/* copy command data into host mbox for cmpl */
@@ -2672,18 +2870,24 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 	}
 
 	wmb();
-	/* interrupt board to doit right away */
-	writel(CA_MBATT, phba->CAregaddr);
-	readl(phba->CAregaddr); /* flush */
 
 	switch (flag) {
 	case MBX_NOWAIT:
-		/* Don't wait for it to finish, just return */
+		/* Set up reference to mailbox command */
 		psli->mbox_active = pmbox;
+		/* Interrupt board to do it */
+		writel(CA_MBATT, phba->CAregaddr);
+		readl(phba->CAregaddr); /* flush */
+		/* Don't wait for it to finish, just return */
 		break;
 
 	case MBX_POLL:
+		/* Set up null reference to mailbox command */
 		psli->mbox_active = NULL;
+		/* Interrupt board to do it */
+		writel(CA_MBATT, phba->CAregaddr);
+		readl(phba->CAregaddr); /* flush */
+
 		if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
 			/* First read mbox status word */
 			word0 = *((volatile uint32_t *)&phba->slim2p->mbx);
@@ -2967,7 +3171,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba,
 		lpfc_printf_log(phba,
 			KERN_ERR,
 			LOG_SLI,
-			"0327 Ring %d handler: unexpected ASYNC_STATUS"
+			"0346 Ring %d handler: unexpected ASYNC_STATUS"
 			" evt_code 0x%x\n",
 			pring->ringno,
 			icmd->un.asyncstat.evt_code);
@@ -2978,16 +3182,16 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba,
 	if (evt_code == ASYNC_TEMP_WARN) {
 		temp_event_data.event_code = LPFC_THRESHOLD_TEMP;
 		lpfc_printf_log(phba,
-				KERN_WARNING,
+				KERN_ERR,
 				LOG_TEMP,
-				"0339 Adapter is very hot, please take "
+				"0347 Adapter is very hot, please take "
 				"corrective action. temperature : %d Celsius\n",
 				temp);
 	}
 	if (evt_code == ASYNC_TEMP_SAFE) {
 		temp_event_data.event_code = LPFC_NORMAL_TEMP;
 		lpfc_printf_log(phba,
-				KERN_INFO,
+				KERN_ERR,
 				LOG_TEMP,
 				"0340 Adapter temperature is OK now. "
 				"temperature : %d Celsius\n",
@@ -3135,6 +3339,7 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)
 		INIT_LIST_HEAD(&pring->txq);
 		INIT_LIST_HEAD(&pring->txcmplq);
 		INIT_LIST_HEAD(&pring->iocb_continueq);
+		INIT_LIST_HEAD(&pring->iocb_continue_saveq);
 		INIT_LIST_HEAD(&pring->postbufq);
 	}
 	spin_unlock_irq(&phba->hbalock);
@@ -3205,6 +3410,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
 	LIST_HEAD(completions);
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
+	struct lpfc_dmabuf *buf_ptr;
 	LPFC_MBOXQ_t *pmb;
 	struct lpfc_iocbq *iocb;
 	IOCB_t *cmd = NULL;
@@ -3244,6 +3450,19 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
 		}
 	}
 
+	spin_lock_irqsave(&phba->hbalock, flags);
+	list_splice_init(&phba->elsbuf, &completions);
+	phba->elsbuf_cnt = 0;
+	phba->elsbuf_prev_cnt = 0;
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+
+	while (!list_empty(&completions)) {
+		list_remove_head(&completions, buf_ptr,
+			struct lpfc_dmabuf, list);
+		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+		kfree(buf_ptr);
+	}
+
 	/* Return any active mbox cmds */
 	del_timer_sync(&psli->mbox_tmo);
 	spin_lock_irqsave(&phba->hbalock, flags);
@@ -3306,6 +3525,47 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	return 0;
 }
 
+uint32_t
+lpfc_sli_get_buffer_tag(struct lpfc_hba *phba)
+{
+	spin_lock_irq(&phba->hbalock);
+	phba->buffer_tag_count++;
+	/*
+	 * Always set the QUE_BUFTAG_BIT to distiguish between
+	 * a tag assigned by HBQ.
+	 */
+	phba->buffer_tag_count |= QUE_BUFTAG_BIT;
+	spin_unlock_irq(&phba->hbalock);
+	return phba->buffer_tag_count;
+}
+
+struct lpfc_dmabuf *
+lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+			uint32_t tag)
+{
+	struct lpfc_dmabuf *mp, *next_mp;
+	struct list_head *slp = &pring->postbufq;
+
+	/* Search postbufq, from the begining, looking for a match on tag */
+	spin_lock_irq(&phba->hbalock);
+	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
+		if (mp->buffer_tag == tag) {
+			list_del_init(&mp->list);
+			pring->postbufq_cnt--;
+			spin_unlock_irq(&phba->hbalock);
+			return mp;
+		}
+	}
+
+	spin_unlock_irq(&phba->hbalock);
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"0410 Cannot find virtual addr for buffer tag on "
+			"ring %d Data x%lx x%p x%p x%x\n",
+			pring->ringno, (unsigned long) tag,
+			slp->next, slp->prev, pring->postbufq_cnt);
+
+	return NULL;
+}
 
 struct lpfc_dmabuf *
 lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
@@ -3373,6 +3633,12 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			pring->txcmplq_cnt--;
 			spin_unlock_irq(&phba->hbalock);
 
+			/* Firmware could still be in progress of DMAing
+			 * payload, so don't free data buffer till after
+			 * a hbeat.
+			 */
+			abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;
+
 			abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
 			abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
 			abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED;
@@ -3411,7 +3677,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	struct lpfc_iocbq *abtsiocbp;
 	IOCB_t *icmd = NULL;
 	IOCB_t *iabt = NULL;
-	int retval = IOCB_ERROR;
+	int retval;
 
 	/*
 	 * There are certain command types we don't want to abort.  And we
@@ -3433,19 +3699,22 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 			cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
 		else
 			cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl;
-		goto abort_iotag_exit;
+		return 0;
 	}
 
 	/* issue ABTS for this IOCB based on iotag */
 	abtsiocbp = __lpfc_sli_get_iocbq(phba);
 	if (abtsiocbp == NULL)
-		return 0;
+		return IOCB_ERROR;
 
 	/* This signals the response to set the correct status
 	 * before calling the completion handler.
 	 */
 	cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED;
 
+	if (vport->load_flag & FC_UNLOADING)
+		cmdiocb->vport = NULL;
+
 	iabt = &abtsiocbp->iocb;
 	iabt->un.acxri.abortType = ABORT_TYPE_ABTS;
 	iabt->un.acxri.abortContextTag = icmd->ulpContext;
@@ -3467,7 +3736,9 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 			 iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
 	retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
 
-abort_iotag_exit:
+	if (retval)
+		__lpfc_sli_release_iocbq(phba, abtsiocbp);
+
 	/*
 	 * Caller to this routine should check for IOCB_ERROR
 	 * and handle it properly.  This routine no longer removes
@@ -3713,7 +3984,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
 	unsigned long flag;
 
 	/* The caller must leave context1 empty. */
-	if (pmboxq->context1 != 0)
+	if (pmboxq->context1)
 		return MBX_NOT_FINISHED;
 
 	/* setup wake call as IOCB callback */
@@ -3898,7 +4169,6 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
 		}
 
 		if (work_ha_copy & HA_ERATT) {
-			phba->link_state = LPFC_HBA_ERROR;
 			/*
 			 * There was a link/board error.  Read the
 			 * status register to retrieve the error event
@@ -3930,7 +4200,7 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
 				 * Stray Mailbox Interrupt, mbxCommand <cmd>
 				 * mbxStatus <status>
 				 */
-				lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX |
+				lpfc_printf_log(phba, KERN_ERR, LOG_MBOX |
 						LOG_SLI,
 						"(%d):0304 Stray Mailbox "
 						"Interrupt mbxCommand x%x "
@@ -3938,51 +4208,60 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
 						(vport ? vport->vpi : 0),
 						pmbox->mbxCommand,
 						pmbox->mbxStatus);
-			}
-			phba->last_completion_time = jiffies;
-			del_timer_sync(&phba->sli.mbox_tmo);
-
-			phba->sli.mbox_active = NULL;
-			if (pmb->mbox_cmpl) {
-				lpfc_sli_pcimem_bcopy(mbox, pmbox,
-						      MAILBOX_CMD_SIZE);
-			}
-			if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
-				pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
+				/* clear mailbox attention bit */
+				work_ha_copy &= ~HA_MBATT;
+			} else {
+				phba->last_completion_time = jiffies;
+				del_timer(&phba->sli.mbox_tmo);
 
-				lpfc_debugfs_disc_trc(vport,
-					LPFC_DISC_TRC_MBOX_VPORT,
-					"MBOX dflt rpi: : status:x%x rpi:x%x",
-					(uint32_t)pmbox->mbxStatus,
-					pmbox->un.varWords[0], 0);
-
-				if ( !pmbox->mbxStatus) {
-					mp = (struct lpfc_dmabuf *)
-						(pmb->context1);
-					ndlp = (struct lpfc_nodelist *)
-						pmb->context2;
-
-					/* Reg_LOGIN of dflt RPI was successful.
-					 * new lets get rid of the RPI using the
-					 * same mbox buffer.
-					 */
-					lpfc_unreg_login(phba, vport->vpi,
-						pmbox->un.varWords[0], pmb);
-					pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
-					pmb->context1 = mp;
-					pmb->context2 = ndlp;
-					pmb->vport = vport;
-					spin_lock(&phba->hbalock);
-					phba->sli.sli_flag &=
-						~LPFC_SLI_MBOX_ACTIVE;
-					spin_unlock(&phba->hbalock);
-					goto send_current_mbox;
+				phba->sli.mbox_active = NULL;
+				if (pmb->mbox_cmpl) {
+					lpfc_sli_pcimem_bcopy(mbox, pmbox,
+							MAILBOX_CMD_SIZE);
+				}
+				if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
+					pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
+
+					lpfc_debugfs_disc_trc(vport,
+						LPFC_DISC_TRC_MBOX_VPORT,
+						"MBOX dflt rpi: : "
+						"status:x%x rpi:x%x",
+						(uint32_t)pmbox->mbxStatus,
+						pmbox->un.varWords[0], 0);
+
+					if (!pmbox->mbxStatus) {
+						mp = (struct lpfc_dmabuf *)
+							(pmb->context1);
+						ndlp = (struct lpfc_nodelist *)
+							pmb->context2;
+
+						/* Reg_LOGIN of dflt RPI was
+						 * successful. new lets get
+						 * rid of the RPI using the
+						 * same mbox buffer.
+						 */
+						lpfc_unreg_login(phba,
+							vport->vpi,
+							pmbox->un.varWords[0],
+							pmb);
+						pmb->mbox_cmpl =
+							lpfc_mbx_cmpl_dflt_rpi;
+						pmb->context1 = mp;
+						pmb->context2 = ndlp;
+						pmb->vport = vport;
+						spin_lock(&phba->hbalock);
+						phba->sli.sli_flag &=
+							~LPFC_SLI_MBOX_ACTIVE;
+						spin_unlock(&phba->hbalock);
+						goto send_current_mbox;
+					}
 				}
+				spin_lock(&phba->pport->work_port_lock);
+				phba->pport->work_port_events &=
+					~WORKER_MBOX_TMO;
+				spin_unlock(&phba->pport->work_port_lock);
+				lpfc_mbox_cmpl_put(phba, pmb);
 			}
-			spin_lock(&phba->pport->work_port_lock);
-			phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
-			spin_unlock(&phba->pport->work_port_lock);
-			lpfc_mbox_cmpl_put(phba, pmb);
 		}
 		if ((work_ha_copy & HA_MBATT) &&
 		    (phba->sli.mbox_active == NULL)) {
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 5fcfe88..7249fd2 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -33,6 +33,7 @@ typedef enum _lpfc_ctx_cmd {
 struct lpfc_iocbq {
 	/* lpfc_iocbqs are used in double linked lists */
 	struct list_head list;
+	struct list_head clist;
 	uint16_t iotag;         /* pre-assigned IO tag */
 	uint16_t rsvd1;
 
@@ -44,6 +45,7 @@ struct lpfc_iocbq {
 #define LPFC_IO_FCP		4	/* FCP command -- iocbq in scsi_buf */
 #define LPFC_DRIVER_ABORTED	8	/* driver aborted this request */
 #define LPFC_IO_FABRIC		0x10	/* Iocb send using fabric scheduler */
+#define LPFC_DELAY_MEM_FREE	0x20    /* Defer free'ing of FC data */
 
 	uint8_t abort_count;
 	uint8_t rsvd2;
@@ -159,6 +161,7 @@ struct lpfc_sli_ring {
 	struct list_head iocb_continueq;
 	uint16_t iocb_continueq_cnt;	/* current length of queue */
 	uint16_t iocb_continueq_max;	/* max length */
+	struct list_head iocb_continue_saveq;
 
 	struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK];
 	uint32_t num_mask;	/* number of mask entries in prt array */
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 2dac2dd..0f21b32 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.2.0.8"
+#define LPFC_DRIVER_VERSION "8.2.0.13"
 
 #define LPFC_DRIVER_NAME "lpfc"
 
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index b32c5a6..7f97b86 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -207,8 +207,7 @@ lpfc_vport_create(struct Scsi_Host *shost, const uint8_t *wwnn,
 	int rc = VPORT_ERROR;
 	int status;
 
-	if ((phba->sli_rev < 3) ||
-		!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
+	if ((phba->sli_rev < 3) || !phba->cfg_enable_npiv) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
 				"1808 Create VPORT failed: "
 				"NPIV is not enabled: SLImode:%d\n",
@@ -395,8 +394,13 @@ lpfc_vport_delete(struct Scsi_Host *shost)
 	 * initiated after we've disposed of all other resources associated
 	 * with the port.
 	 */
-	if (!scsi_host_get(shost) || !scsi_host_get(shost))
+	if (!scsi_host_get(shost))
 		return VPORT_INVAL;
+	if (!scsi_host_get(shost)) {
+		scsi_host_put(shost);
+		return VPORT_INVAL;
+	}
+
 	spin_lock_irq(&phba->hbalock);
 	vport->load_flag |= FC_UNLOADING;
 	spin_unlock_irq(&phba->hbalock);
@@ -450,7 +454,18 @@ skip_logo:
 		 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi)
 		 * does the scsi_host_put() to release the vport.
 		 */
-		lpfc_mbx_unreg_vpi(vport);
+		if (lpfc_mbx_unreg_vpi(vport)) {
+			/*
+			 * Need to release the reference count to shost
+			 */
+			scsi_host_put(shost);
+		}
+	}
+	else {
+		/*
+		 * Need to release the reference count to shost
+		 */
+		scsi_host_put(shost);
 	}
 
 	lpfc_free_vpi(phba, vport->vpi);
@@ -473,7 +488,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
 	struct lpfc_vport *port_iterator;
 	struct lpfc_vport **vports;
 	int index = 0;
-	vports = kzalloc(LPFC_MAX_VPORTS * sizeof(struct lpfc_vport *),
+	vports = kzalloc((phba->max_vpi + 1) * sizeof(struct lpfc_vport *),
 			 GFP_KERNEL);
 	if (vports == NULL)
 		return NULL;
@@ -492,12 +507,12 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
 }
 
 void
-lpfc_destroy_vport_work_array(struct lpfc_vport **vports)
+lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports)
 {
 	int i;
 	if (vports == NULL)
 		return;
-	for (i=0; vports[i] != NULL && i < LPFC_MAX_VPORTS; i++)
+	for (i=0; vports[i] != NULL && i <= phba->max_vpi; i++)
 		scsi_host_put(lpfc_shost_from_vport(vports[i]));
 	kfree(vports);
 }
diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h
index c689ed8..345ce7a 100644
--- a/drivers/scsi/lpfc/lpfc_vport.h
+++ b/drivers/scsi/lpfc/lpfc_vport.h
@@ -89,7 +89,7 @@ int lpfc_vport_delete(struct Scsi_Host *);
 int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
 int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
 struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *);
-void lpfc_destroy_vport_work_array(struct lpfc_vport **);
+void lpfc_destroy_vport_work_array(struct lpfc_hba *, struct lpfc_vport **);
 
 /*
  *  queuecommand  VPORT-specific return codes. Specified in  the host byte code.