[SCSI] lpfc: bug fixes

 Following the NPIV support, the following changes have been accumulated
 in the testing and qualification of the driver:

 - Fix affinity of ELS ring to slow/deferred event processing
 - Fix Ring attention masks
 - Defer dev_loss_tmo timeout handling to worker thread
 - Consolidate link down error classification for better error checking
 - Remove unused/deprecated nlp_initiator_tmr timer
 - Fix for async scan - move adapter init code back into pci_probe_one
   context. Fix async scan interfaces.
 - Expand validation of ability to create vports
 - Extract VPI resource cnt from firmware
 - Tuning of Login/Reject policies to better deal with overwhelmned targets
 - Misc ELS and discovery fixes
 - Export the npiv_enable attribute to sysfs
 - Mailbox handling fix
 - Add debugfs support
 - A few other small misc fixes:
    - wrong return values, double-frees, bad locking
 - Added adapter failure heartbeat

Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile
index d94c9e0..1c28670 100644
--- a/drivers/scsi/lpfc/Makefile
+++ b/drivers/scsi/lpfc/Makefile
@@ -28,4 +28,4 @@
 
 lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o	\
 	lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \
-	lpfc_vport.o
+	lpfc_vport.o lpfc_debugfs.o
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 4b9019d..f8f64d6 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -23,7 +23,6 @@
 
 struct lpfc_sli2_slim;
 
-
 #define LPFC_MAX_TARGET		256	/* max number of targets supported */
 #define LPFC_MAX_DISC_THREADS	64	/* max outstanding discovery els
 					   requests */
@@ -45,6 +44,9 @@
 /* Number of exchanges reserved for discovery to complete */
 #define LPFC_DISC_IOCB_BUFF_COUNT 20
 
+#define LPFC_HB_MBOX_INTERVAL   5	/* Heart beat interval in seconds. */
+#define LPFC_HB_MBOX_TIMEOUT    30 	/* Heart beat timeout  in seconds. */
+
 /* Define macros for 64 bit support */
 #define putPaddrLow(addr)    ((uint32_t) (0xffffffff & (u64)(addr)))
 #define putPaddrHigh(addr)   ((uint32_t) (0xffffffff & (((u64)(addr))>>32)))
@@ -308,13 +310,15 @@
 
 	spinlock_t work_port_lock;
 	uint32_t work_port_events; /* Timeout to be handled  */
-#define WORKER_DISC_TMO                0x1	/* Discovery timeout */
-#define WORKER_ELS_TMO                 0x2	/* ELS timeout */
-#define WORKER_MBOX_TMO                0x4	/* MBOX timeout */
-#define WORKER_FDMI_TMO                0x8	/* FDMI timeout */
-#define WORKER_FABRIC_BLOCK_TMO        0x10	/* fabric block timout */
-#define WORKER_RAMP_DOWN_QUEUE    0x20	/* Decrease Q depth */
-#define WORKER_RAMP_UP_QUEUE      0x40	/* Increase Q depth */
+#define WORKER_DISC_TMO                0x1	/* vport: Discovery timeout */
+#define WORKER_ELS_TMO                 0x2	/* vport: ELS timeout */
+#define WORKER_FDMI_TMO                0x4	/* vport: FDMI timeout */
+
+#define WORKER_MBOX_TMO                0x100	/* hba: MBOX timeout */
+#define WORKER_HB_TMO                  0x200	/* hba: Heart beat timeout */
+#define WORKER_FABRIC_BLOCK_TMO        0x400	/* hba: fabric block timout */
+#define WORKER_RAMP_DOWN_QUEUE         0x800	/* hba: Decrease Q depth */
+#define WORKER_RAMP_UP_QUEUE           0x1000	/* hba: Increase Q depth */
 
 	struct timer_list fc_fdmitmo;
 	struct timer_list els_tmofunc;
@@ -326,6 +330,14 @@
 #define FC_UNLOADING		0x2	/* HBA in process of unloading drvr */
 	char  *vname;		        /* Application assigned name */
 	struct fc_vport *fc_vport;
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+	struct dentry *debug_disc_trc;
+	struct dentry *debug_nodelist;
+	struct dentry *vport_debugfs_root;
+	struct lpfc_disc_trc *disc_trc;
+	atomic_t disc_trc_cnt;
+#endif
 };
 
 struct hbq_s {
@@ -408,6 +420,7 @@
 	uint32_t cfg_hba_queue_depth;
 	uint32_t cfg_peer_port_login;
 	uint32_t cfg_vport_restrict_login;
+	uint32_t cfg_npiv_enable;
 	uint32_t cfg_fcp_class;
 	uint32_t cfg_use_adisc;
 	uint32_t cfg_ack0;
@@ -513,10 +526,10 @@
 	mempool_t *nlp_mem_pool;
 
 	struct fc_host_statistics link_stats;
+
 	struct list_head port_list;
 	struct lpfc_vport *pport; /* physical lpfc_vport pointer */
 	uint16_t max_vpi;	/* Maximum virtual nports */
-	uint16_t vpi_cnt;	/* Nport count */
 #define LPFC_MAX_VPI 100  /* Max number of VPorts supported */
 	unsigned long *vpi_bmask; /* vpi allocation table */
 
@@ -531,6 +544,15 @@
 	unsigned long last_rsrc_error_time;
 	unsigned long last_ramp_down_time;
 	unsigned long last_ramp_up_time;
+#ifdef CONFIG_LPFC_DEBUG_FS
+	struct dentry *hba_debugfs_root;
+	atomic_t debugfs_vport_count;
+#endif
+
+	/* Fields used for heart beat. */
+	unsigned long last_completion_time;
+	struct timer_list hb_tmofunc;
+	uint8_t hb_outstanding;
 };
 
 static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 5cb7924f..6a2c1ac 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -282,9 +282,7 @@
 	}
 
 	lpfc_set_loopback_flag(phba);
-	if (mbxstatus == MBX_TIMEOUT)
-		pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-	else
+	if (mbxstatus != MBX_TIMEOUT)
 		mempool_free(pmboxq, phba->mbox_mem_pool);
 
 	if (mbxstatus == MBXERR_ERROR)
@@ -439,30 +437,11 @@
 		return -EIO;
 }
 
-static ssize_t
-lpfc_max_vpi_show(struct class_device *cdev, char *buf)
-{
-	struct Scsi_Host  *shost = class_to_shost(cdev);
-	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-	struct lpfc_hba   *phba = vport->phba;
-
-	return snprintf(buf, PAGE_SIZE, "%d\n", phba->max_vpi);
-}
-
-static ssize_t
-lpfc_used_vpi_show(struct class_device *cdev, char *buf)
-{
-	struct Scsi_Host  *shost = class_to_shost(cdev);
-	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-	struct lpfc_hba   *phba = vport->phba;
-
-	/* Don't count the physical port */
-	return snprintf(buf, PAGE_SIZE, "%d\n", phba->vpi_cnt-1);
-}
-
 int
-lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri,
-	uint32_t *axri, uint32_t *mrpi, uint32_t *arpi)
+lpfc_get_hba_info(struct lpfc_hba *phba,
+		  uint32_t *mxri, uint32_t *axri,
+		  uint32_t *mrpi, uint32_t *arpi,
+		  uint32_t *mvpi, uint32_t *avpi)
 {
 	struct lpfc_sli   *psli = &phba->sli;
 	LPFC_MBOXQ_t *pmboxq;
@@ -498,9 +477,7 @@
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
 
 	if (rc != MBX_SUCCESS) {
-		if (rc == MBX_TIMEOUT)
-			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		else
+		if (rc != MBX_TIMEOUT)
 			mempool_free(pmboxq, phba->mbox_mem_pool);
 		return 0;
 	}
@@ -513,6 +490,10 @@
 		*mxri = pmb->un.varRdConfig.max_xri;
 	if (axri)
 		*axri = pmb->un.varRdConfig.avail_xri;
+	if (mvpi)
+		*mvpi = pmb->un.varRdConfig.max_vpi;
+	if (avpi)
+		*avpi = pmb->un.varRdConfig.avail_vpi;
 
 	mempool_free(pmboxq, phba->mbox_mem_pool);
 	return 1;
@@ -526,7 +507,7 @@
 	struct lpfc_hba   *phba = vport->phba;
 	uint32_t cnt;
 
-	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL))
+	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL, NULL, NULL))
 		return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
 	return snprintf(buf, PAGE_SIZE, "Unknown\n");
 }
@@ -539,7 +520,7 @@
 	struct lpfc_hba   *phba = vport->phba;
 	uint32_t cnt, acnt;
 
-	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt))
+	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL))
 		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
 	return snprintf(buf, PAGE_SIZE, "Unknown\n");
 }
@@ -552,7 +533,7 @@
 	struct lpfc_hba   *phba = vport->phba;
 	uint32_t cnt;
 
-	if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL))
+	if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL, NULL, NULL))
 		return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
 	return snprintf(buf, PAGE_SIZE, "Unknown\n");
 }
@@ -565,7 +546,33 @@
 	struct lpfc_hba   *phba = vport->phba;
 	uint32_t cnt, acnt;
 
-	if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL))
+	if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL))
+		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+	return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_max_vpi_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host  *shost = class_to_shost(cdev);
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+	struct lpfc_hba   *phba = vport->phba;
+	uint32_t cnt;
+
+	if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, NULL))
+		return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
+	return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_used_vpi_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host  *shost = class_to_shost(cdev);
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+	struct lpfc_hba   *phba = vport->phba;
+	uint32_t cnt, acnt;
+
+	if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt))
 		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
 	return snprintf(buf, PAGE_SIZE, "Unknown\n");
 }
@@ -995,9 +1002,7 @@
 		 " 2 - select SLI-2 even on SLI-3 capable HBAs,"
 		 " 3 - select SLI-3");
 
-int  lpfc_npiv_enable = 0;
-module_param(lpfc_npiv_enable, int, 0);
-MODULE_PARM_DESC(lpfc_npiv_enable, "Enable NPIV functionality");
+LPFC_ATTR_R(npiv_enable, 0, 0, 1, "Enable NPIV functionality");
 
 /*
 # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -1052,6 +1057,24 @@
 	return -EINVAL;
 }
 
+static void
+lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport;
+	struct Scsi_Host  *shost;
+	struct lpfc_nodelist  *ndlp;
+
+	list_for_each_entry(vport, &phba->port_list, listentry) {
+		shost = lpfc_shost_from_vport(vport);
+		spin_lock_irq(shost->host_lock);
+		list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
+			if (ndlp->rport)
+				ndlp->rport->dev_loss_tmo =
+					phba->cfg_devloss_tmo;
+		spin_unlock_irq(shost->host_lock);
+	}
+}
+
 static int
 lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
 {
@@ -1067,6 +1090,7 @@
 	if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
 		phba->cfg_nodev_tmo = val;
 		phba->cfg_devloss_tmo = val;
+		lpfc_update_rport_devloss_tmo(phba);
 		return 0;
 	}
 
@@ -1102,6 +1126,7 @@
 		phba->cfg_nodev_tmo = val;
 		phba->cfg_devloss_tmo = val;
 		phba->dev_loss_tmo_changed = 1;
+		lpfc_update_rport_devloss_tmo(phba);
 		return 0;
 	}
 
@@ -1358,6 +1383,7 @@
 	&class_device_attr_lpfc_multi_ring_type,
 	&class_device_attr_lpfc_fdmi_on,
 	&class_device_attr_lpfc_max_luns,
+	&class_device_attr_lpfc_npiv_enable,
 	&class_device_attr_nport_evt_cnt,
 	&class_device_attr_management_version,
 	&class_device_attr_board_mode,
@@ -1641,8 +1667,6 @@
 
 		if (rc != MBX_SUCCESS) {
 			if (rc == MBX_TIMEOUT) {
-				phba->sysfs_mbox.mbox->mbox_cmpl =
-					lpfc_sli_def_mbox_cmpl;
 				phba->sysfs_mbox.mbox = NULL;
 			}
 			sysfs_mbox_idle(phba);
@@ -1886,9 +1910,7 @@
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
 
 	if (rc != MBX_SUCCESS) {
-		if (rc == MBX_TIMEOUT)
-			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		else
+		if (rc != MBX_TIMEOUT)
 			mempool_free(pmboxq, phba->mbox_mem_pool);
 		return NULL;
 	}
@@ -1913,9 +1935,7 @@
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
 
 	if (rc != MBX_SUCCESS) {
-		if (rc == MBX_TIMEOUT)
-			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		else
+		if (rc != MBX_TIMEOUT)
 			mempool_free(pmboxq, phba->mbox_mem_pool);
 		return NULL;
 	}
@@ -1993,9 +2013,7 @@
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
 
 	if (rc != MBX_SUCCESS) {
-		if (rc == MBX_TIMEOUT)
-			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		else
+		if (rc != MBX_TIMEOUT)
 			mempool_free(pmboxq, phba->mbox_mem_pool);
 		return;
 	}
@@ -2013,9 +2031,7 @@
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
 
 	if (rc != MBX_SUCCESS) {
-		if (rc == MBX_TIMEOUT)
-			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		else
+		if (rc != MBX_TIMEOUT)
 			mempool_free( pmboxq, phba->mbox_mem_pool);
 		return;
 	}
@@ -2253,6 +2269,7 @@
 	lpfc_max_luns_init(phba, lpfc_max_luns);
 	lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
 	lpfc_peer_port_login_init(phba, lpfc_peer_port_login);
+	lpfc_npiv_enable_init(phba, lpfc_npiv_enable);
 	lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login);
 	lpfc_use_msi_init(phba, lpfc_use_msi);
 	lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 94e7881..e19d1a7 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -23,6 +23,7 @@
 struct fc_rport;
 void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
 void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
 int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
 		 struct lpfc_dmabuf *mp);
 void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -45,6 +46,7 @@
 
 void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -85,6 +87,7 @@
 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 *);
+int lpfc_els_chk_latt(struct lpfc_vport *);
 int lpfc_els_abort_flogi(struct lpfc_hba *);
 int lpfc_initial_flogi(struct lpfc_vport *);
 int lpfc_initial_fdisc(struct lpfc_vport *);
@@ -96,10 +99,11 @@
 int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *);
 int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t);
 int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
+int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
 int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
 		     struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
 int lpfc_els_rsp_reject(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
-			struct lpfc_nodelist *);
+			struct lpfc_nodelist *, LPFC_MBOXQ_t *);
 int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *,
 			   struct lpfc_nodelist *);
 int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
@@ -107,6 +111,7 @@
 void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *);
 void lpfc_els_retry_delay(unsigned long);
 void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
+void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *);
 void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
 			  struct lpfc_iocbq *);
 int lpfc_els_handle_rscn(struct lpfc_vport *);
@@ -117,6 +122,8 @@
 int lpfc_els_disc_plogi(struct lpfc_vport *);
 void lpfc_els_timeout(unsigned long);
 void lpfc_els_timeout_handler(struct lpfc_vport *);
+void lpfc_hb_timeout(unsigned long);
+void lpfc_hb_timeout_handler(struct lpfc_hba *);
 
 void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
 			 struct lpfc_iocbq *);
@@ -238,7 +245,6 @@
 void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *);
 /* Function prototypes. */
 const char* lpfc_info(struct Scsi_Host *);
-void lpfc_scan_start(struct Scsi_Host *);
 int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
 
 void lpfc_get_cfgparam(struct lpfc_hba *);
@@ -249,7 +255,6 @@
 extern struct fc_function_template lpfc_transport_functions;
 extern struct fc_function_template lpfc_vport_transport_functions;
 extern int lpfc_sli_mode;
-extern int lpfc_npiv_enable;
 
 int  lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
 void lpfc_terminate_rport_io(struct fc_rport *);
@@ -262,6 +267,11 @@
 int lpfc_get_instance(void);
 void lpfc_host_attrib_init(struct Scsi_Host *);
 
+extern void lpfc_debugfs_initialize(struct lpfc_vport *);
+extern void lpfc_debugfs_terminate(struct lpfc_vport *);
+extern void lpfc_debugfs_disc_trc(struct lpfc_vport *, int, char *, uint32_t,
+	uint32_t, uint32_t);
+
 /* Interface exported by fabric iocb scheduler */
 int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
 void lpfc_fabric_abort_vport(struct lpfc_vport *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 5584f39..ae9d6f38 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -41,6 +41,7 @@
 #include "lpfc_crtn.h"
 #include "lpfc_version.h"
 #include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
 
 #define HBA_PORTSPEED_UNKNOWN               0	/* Unknown - transceiver
 						 * incapable of reporting */
@@ -251,6 +252,32 @@
 	return mlist;
 }
 
+int
+lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
+{
+	struct lpfc_dmabuf *buf_ptr;
+
+	if (ctiocb->context1) {
+		buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1;
+		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+		kfree(buf_ptr);
+		ctiocb->context1 = NULL;
+	}
+	if (ctiocb->context2) {
+		lpfc_free_ct_rsp(phba, (struct lpfc_dmabuf *) ctiocb->context2);
+		ctiocb->context2 = NULL;
+	}
+
+	if (ctiocb->context3) {
+		buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3;
+		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+		kfree(buf_ptr);
+		ctiocb->context1 = NULL;
+	}
+	lpfc_sli_release_iocbq(phba, ctiocb);
+	return 0;
+}
+
 static int
 lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
 	     struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
@@ -428,6 +455,13 @@
 				    (!phba->cfg_vport_restrict_login)) {
 					ndlp = lpfc_setup_disc_node(vport, Did);
 					if (ndlp) {
+						lpfc_debugfs_disc_trc(vport,
+						LPFC_DISC_TRC_CT,
+						"Parse GID_FTrsp: "
+						"did:x%x flg:x%x x%x",
+						Did, ndlp->nlp_flag,
+						vport->fc_flag);
+
 						lpfc_printf_log(phba, KERN_INFO,
 							LOG_DISCOVERY,
 							"%d (%d):0238 Process "
@@ -439,6 +473,13 @@
 							vport->fc_flag,
 							vport->fc_rscn_id_cnt);
 					} else {
+						lpfc_debugfs_disc_trc(vport,
+						LPFC_DISC_TRC_CT,
+						"Skip1 GID_FTrsp: "
+						"did:x%x flg:x%x cnt:%d",
+						Did, vport->fc_flag,
+						vport->fc_rscn_id_cnt);
+
 						lpfc_printf_log(phba, KERN_INFO,
 							LOG_DISCOVERY,
 							"%d (%d):0239 Skip x%x "
@@ -453,12 +494,26 @@
 				} else {
 					if (!(vport->fc_flag & FC_RSCN_MODE) ||
 					(lpfc_rscn_payload_check(vport, Did))) {
+						lpfc_debugfs_disc_trc(vport,
+						LPFC_DISC_TRC_CT,
+						"Query GID_FTrsp: "
+						"did:x%x flg:x%x cnt:%d",
+						Did, vport->fc_flag,
+						vport->fc_rscn_id_cnt);
+
 						if (lpfc_ns_cmd(vport,
 							SLI_CTNS_GFF_ID,
 							0, Did) == 0)
 							vport->num_disc_nodes++;
 					}
 					else {
+						lpfc_debugfs_disc_trc(vport,
+						LPFC_DISC_TRC_CT,
+						"Skip2 GID_FTrsp: "
+						"did:x%x flg:x%x cnt:%d",
+						Did, vport->fc_flag,
+						vport->fc_rscn_id_cnt);
+
 						lpfc_printf_log(phba, KERN_INFO,
 							LOG_DISCOVERY,
 							"%d (%d):0245 Skip x%x "
@@ -492,7 +547,6 @@
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	IOCB_t *irsp;
 	struct lpfc_dmabuf *bmp;
-	struct lpfc_dmabuf *inp;
 	struct lpfc_dmabuf *outp;
 	struct lpfc_sli_ct_request *CTrsp;
 	int rc;
@@ -500,31 +554,39 @@
 	/* we pass cmdiocb to state machine which needs rspiocb as well */
 	cmdiocb->context_un.rsp_iocb = rspiocb;
 
-	inp = (struct lpfc_dmabuf *) cmdiocb->context1;
 	outp = (struct lpfc_dmabuf *) cmdiocb->context2;
 	bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
+	irsp = &rspiocb->iocb;
+
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+		 "GID_FT cmpl:     status:x%x/x%x rtry:%d",
+		irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry);
 
 	/* Don't bother processing response if vport is being torn down. */
 	if (vport->load_flag & FC_UNLOADING)
 		goto out;
 
-	irsp = &rspiocb->iocb;
-	if (irsp->ulpStatus) {
-		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-			((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
-			 (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)))
-			goto err1;
 
+	if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
+		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+				"%d (%d):0216 Link event during NS query\n",
+				phba->brd_no, vport->vpi);
+		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+		goto out;
+	}
+
+	if (irsp->ulpStatus) {
 		/* Check for retry */
 		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
-			vport->fc_ns_retry++;
+			if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
+				(irsp->un.ulpWord[4] != IOERR_NO_RESOURCES))
+				vport->fc_ns_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;
 		}
-err1:
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
 			"%d (%d):0257 GID_FT Query error: 0x%x 0x%x\n",
@@ -553,6 +615,13 @@
 					(uint32_t) CTrsp->ReasonCode,
 					(uint32_t) CTrsp->Explanation,
 					vport->fc_flag);
+
+			lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+				"GID_FT rsp err1  cmd:x%x rsn:x%x exp:x%x",
+				(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+				(uint32_t) CTrsp->ReasonCode,
+				(uint32_t) CTrsp->Explanation);
+
 		} else {
 			/* NameServer Rsp Error */
 			lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
@@ -563,6 +632,12 @@
 					(uint32_t) CTrsp->ReasonCode,
 					(uint32_t) CTrsp->Explanation,
 					vport->fc_flag);
+
+			lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+				"GID_FT rsp err2  cmd:x%x rsn:x%x exp:x%x",
+				(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+				(uint32_t) CTrsp->ReasonCode,
+				(uint32_t) CTrsp->Explanation);
 		}
 	}
 	/* Link up / RSCN discovery */
@@ -586,12 +661,7 @@
 		lpfc_disc_start(vport);
 	}
 out:
-	lpfc_free_ct_rsp(phba, outp);
-	lpfc_mbuf_free(phba, inp->virt, inp->phys);
-	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-	kfree(inp);
-	kfree(bmp);
-	lpfc_sli_release_iocbq(phba, cmdiocb);
+	lpfc_ct_free_iocb(phba, cmdiocb);
 	return;
 }
 
@@ -602,7 +672,6 @@
 	struct lpfc_vport *vport = cmdiocb->vport;
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	IOCB_t *irsp = &rspiocb->iocb;
-	struct lpfc_dmabuf *bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
 	struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
 	struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
 	struct lpfc_sli_ct_request *CTrsp;
@@ -613,6 +682,10 @@
 	did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId;
 	did = be32_to_cpu(did);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+		"GFF_ID cmpl:     status:x%x/x%x did:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4], did);
+
 	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
 		/* Good status, continue checking */
 		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
@@ -632,6 +705,15 @@
 			}
 		}
 	}
+	else {
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+				"%d (%d):0267 NameServer GFF Rsp"
+				" x%x Error (%d %d) Data: x%x x%x\n",
+				phba->brd_no, vport->vpi, did,
+				irsp->ulpStatus, irsp->un.ulpWord[4],
+				vport->fc_flag, vport->fc_rscn_id_cnt)
+	}
+
 	/* This is a target port, unregistered port, or the GFF_ID failed */
 	ndlp = lpfc_setup_disc_node(vport, did);
 	if (ndlp) {
@@ -670,13 +752,7 @@
 		}
 		lpfc_disc_start(vport);
 	}
-
-	lpfc_free_ct_rsp(phba, outp);
-	lpfc_mbuf_free(phba, inp->virt, inp->phys);
-	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-	kfree(inp);
-	kfree(bmp);
-	lpfc_sli_release_iocbq(phba, cmdiocb);
+	lpfc_ct_free_iocb(phba, cmdiocb);
 	return;
 }
 
@@ -686,37 +762,45 @@
 			struct lpfc_iocbq *rspiocb)
 {
 	struct lpfc_vport *vport = cmdiocb->vport;
-	struct lpfc_dmabuf *bmp;
 	struct lpfc_dmabuf *inp;
 	struct lpfc_dmabuf *outp;
 	IOCB_t *irsp;
 	struct lpfc_sli_ct_request *CTrsp;
 	int cmdcode, rc;
 	uint8_t retry;
+	uint32_t latt;
 
 	/* we pass cmdiocb to state machine which needs rspiocb as well */
 	cmdiocb->context_un.rsp_iocb = rspiocb;
 
 	inp = (struct lpfc_dmabuf *) cmdiocb->context1;
 	outp = (struct lpfc_dmabuf *) cmdiocb->context2;
-	bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
 	irsp = &rspiocb->iocb;
 
 	cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)->
 					CommandResponse.bits.CmdRsp);
 	CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
 
-	/* NS request completes status <ulpStatus> CmdRsp <CmdRsp> */
+	latt = lpfc_els_chk_latt(vport);
+
+	/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0209 NS request %x completes "
-			"ulpStatus x%x / x%x "
-			"CmdRsp x%x, Context x%x, Tag x%x\n",
-			phba->brd_no, vport->vpi,
-			cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4],
+			"%d (%d):0209 RFT request completes, latt %d, "
+			"ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
+			phba->brd_no, vport->vpi, latt, irsp->ulpStatus,
 			CTrsp->CommandResponse.bits.CmdRsp,
 			cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+		"CT cmd cmpl:     status:x%x/x%x cmd:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode);
+
 	if (irsp->ulpStatus) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+			"%d (%d):0268 NS cmd %x Error (%d %d)\n",
+			phba->brd_no, vport->vpi, cmdcode,
+			irsp->ulpStatus, irsp->un.ulpWord[4]);
+
 		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
 			((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
 			 (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)))
@@ -736,12 +820,7 @@
 	}
 
 out:
-	lpfc_free_ct_rsp(phba, outp);
-	lpfc_mbuf_free(phba, inp->virt, inp->phys);
-	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-	kfree(inp);
-	kfree(bmp);
-	lpfc_sli_release_iocbq(phba, cmdiocb);
+	lpfc_ct_free_iocb(phba, cmdiocb);
 	return;
 }
 
@@ -840,31 +919,42 @@
 		      struct lpfc_iocbq *) = NULL;
 	uint32_t rsp_size = 1024;
 	size_t   size;
+	int rc = 0;
 
 	ndlp = lpfc_findnode_did(vport, NameServer_DID);
-	if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)
-		return 1;
+	if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) {
+		rc=1;
+		goto ns_cmd_exit;
+	}
 
 	/* fill in BDEs for command */
 	/* Allocate buffer for command payload */
 	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
-	if (!mp)
+	if (!mp) {
+		rc=2;
 		goto ns_cmd_exit;
+	}
 
 	INIT_LIST_HEAD(&mp->list);
 	mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
-	if (!mp->virt)
+	if (!mp->virt) {
+		rc=3;
 		goto ns_cmd_free_mp;
+	}
 
 	/* Allocate buffer for Buffer ptr list */
 	bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
-	if (!bmp)
+	if (!bmp) {
+		rc=4;
 		goto ns_cmd_free_mpvirt;
+	}
 
 	INIT_LIST_HEAD(&bmp->list);
 	bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(bmp->phys));
-	if (!bmp->virt)
+	if (!bmp->virt) {
+		rc=5;
 		goto ns_cmd_free_bmp;
+	}
 
 	/* NameServer Req */
 	lpfc_printf_log(phba, KERN_INFO ,LOG_DISCOVERY,
@@ -970,10 +1060,15 @@
 		break;
 	}
 
-	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry))
+	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
 		/* On success, The cmpl function will free the buffers */
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+			"Issue CT cmd:    cmd:x%x did:x%x",
+			cmdcode, ndlp->nlp_DID, 0);
 		return 0;
+	}
 
+	rc=6;
 	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
 ns_cmd_free_bmp:
 	kfree(bmp);
@@ -982,6 +1077,10 @@
 ns_cmd_free_mp:
 	kfree(mp);
 ns_cmd_exit:
+	lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+		"%d (%d):0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
+			phba->brd_no, vport->vpi, cmdcode, rc, vport->fc_flag,
+			vport->fc_rscn_id_cnt);
 	return 1;
 }
 
@@ -989,7 +1088,6 @@
 lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 		      struct lpfc_iocbq * rspiocb)
 {
-	struct lpfc_dmabuf *bmp = cmdiocb->context3;
 	struct lpfc_dmabuf *inp = cmdiocb->context1;
 	struct lpfc_dmabuf *outp = cmdiocb->context2;
 	struct lpfc_sli_ct_request *CTrsp = outp->virt;
@@ -998,6 +1096,25 @@
 	uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
 	uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
 	struct lpfc_vport *vport = cmdiocb->vport;
+	IOCB_t *irsp = &rspiocb->iocb;
+	uint32_t latt;
+
+	latt = lpfc_els_chk_latt(vport);
+
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+		"FDMI cmpl:       status:x%x/x%x latt:%d",
+		irsp->ulpStatus, irsp->un.ulpWord[4], latt);
+
+	if (latt || irsp->ulpStatus) {
+		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+			        "%d (%d):0229 FDMI cmd %04x failed, latt = %d "
+				"ulpStatus: x%x, rid x%x\n",
+			        phba->brd_no, vport->vpi,
+				be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
+				irsp->un.ulpWord[4]);
+		lpfc_ct_free_iocb(phba, cmdiocb);
+		return;
+	}
 
 	ndlp = lpfc_findnode_did(vport, FDMI_DID);
 	if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
@@ -1024,13 +1141,7 @@
 		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
 		break;
 	}
-
-	lpfc_free_ct_rsp(phba, outp);
-	lpfc_mbuf_free(phba, inp->virt, inp->phys);
-	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-	kfree(inp);
-	kfree(bmp);
-	lpfc_sli_release_iocbq(phba, cmdiocb);
+	lpfc_ct_free_iocb(phba, cmdiocb);
 	return;
 }
 
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
new file mode 100644
index 0000000..673cfe1
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -0,0 +1,508 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2007 Emulex.  All rights reserved.                *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
+#include "lpfc_version.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+/* debugfs interface
+ *
+ * To access this interface the user should:
+ * # mkdir /debug
+ * # mount -t debugfs none /debug
+ *
+ * The lpfc debugfs directory hierachy is:
+ * lpfc/lpfcX/vportY
+ * where X is the lpfc hba unique_id
+ * where Y is the vport VPI on that hba
+ *
+ * Debugging services available per vport:
+ * discovery_trace
+ * This is an ACSII readable file that contains a trace of the last
+ * lpfc_debugfs_max_disc_trc events that happened on a specific vport.
+ * See lpfc_debugfs.h for different categories of
+ * discovery events. To enable the discovery trace, the following
+ * module parameters must be set:
+ * lpfc_debugfs_enable=1         Turns on lpfc debugfs filesystem support
+ * lpfc_debugfs_max_disc_trc=X   Where X is the event trace depth for
+ *                               EACH vport. X MUST also be a power of 2.
+ * lpfc_debugfs_mask_disc_trc=Y  Where Y is an event mask as defined in
+ *                               lpfc_debugfs.h .
+ */
+static int lpfc_debugfs_enable = 0;
+module_param(lpfc_debugfs_enable, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
+
+static int lpfc_debugfs_max_disc_trc = 0;  /* This MUST be a power of 2 */
+module_param(lpfc_debugfs_max_disc_trc, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
+	"Set debugfs discovery trace depth");
+
+static int lpfc_debugfs_mask_disc_trc = 0;
+module_param(lpfc_debugfs_mask_disc_trc, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
+	"Set debugfs discovery trace mask");
+
+#include <linux/debugfs.h>
+
+/* size of discovery_trace output line */
+#define LPFC_DISC_TRC_ENTRY_SIZE 80
+
+/* nodelist output buffer size */
+#define LPFC_NODELIST_SIZE 8192
+#define LPFC_NODELIST_ENTRY_SIZE 120
+
+struct lpfc_debug {
+	char *buffer;
+	int  len;
+};
+
+atomic_t lpfc_debugfs_disc_trc_cnt = ATOMIC_INIT(0);
+unsigned long lpfc_debugfs_start_time = 0L;
+
+static int
+lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
+{
+	int i, index, len, enable;
+	uint32_t ms;
+	struct lpfc_disc_trc *dtp;
+	char buffer[80];
+
+
+	enable = lpfc_debugfs_enable;
+	lpfc_debugfs_enable = 0;
+
+	len = 0;
+	index = (atomic_read(&vport->disc_trc_cnt) + 1) &
+		(lpfc_debugfs_max_disc_trc - 1);
+	for (i = index; i < lpfc_debugfs_max_disc_trc; i++) {
+		dtp = vport->disc_trc + i;
+		if (!dtp->fmt)
+			continue;
+		ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
+		snprintf(buffer, 80, "%010d:%010d ms:%s\n",
+			dtp->seq_cnt, ms, dtp->fmt);
+		len +=  snprintf(buf+len, size-len, buffer,
+			dtp->data1, dtp->data2, dtp->data3);
+	}
+	for (i = 0; i < index; i++) {
+		dtp = vport->disc_trc + i;
+		if (!dtp->fmt)
+			continue;
+		ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
+		snprintf(buffer, 80, "%010d:%010d ms:%s\n",
+			dtp->seq_cnt, ms, dtp->fmt);
+		len +=  snprintf(buf+len, size-len, buffer,
+			dtp->data1, dtp->data2, dtp->data3);
+	}
+
+	lpfc_debugfs_enable = enable;
+	return len;
+}
+
+static int
+lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
+{
+	int len = 0;
+	int cnt;
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+	struct lpfc_nodelist *ndlp;
+	unsigned char *statep, *name;
+
+	cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE);
+
+	spin_lock_irq(shost->host_lock);
+	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+		if (!cnt) {
+			len +=  snprintf(buf+len, size-len,
+				"Missing Nodelist Entries\n");
+			break;
+		}
+		cnt--;
+		switch (ndlp->nlp_state) {
+		case NLP_STE_UNUSED_NODE:
+			statep = "UNUSED";
+			break;
+		case NLP_STE_PLOGI_ISSUE:
+			statep = "PLOGI ";
+			break;
+		case NLP_STE_ADISC_ISSUE:
+			statep = "ADISC ";
+			break;
+		case NLP_STE_REG_LOGIN_ISSUE:
+			statep = "REGLOG";
+			break;
+		case NLP_STE_PRLI_ISSUE:
+			statep = "PRLI  ";
+			break;
+		case NLP_STE_UNMAPPED_NODE:
+			statep = "UNMAP ";
+			break;
+		case NLP_STE_MAPPED_NODE:
+			statep = "MAPPED";
+			break;
+		case NLP_STE_NPR_NODE:
+			statep = "NPR   ";
+			break;
+		default:
+			statep = "UNKNOWN";
+		}
+		len +=  snprintf(buf+len, size-len, "%s DID:x%06x ",
+			statep, ndlp->nlp_DID);
+		name = (unsigned char *)&ndlp->nlp_portname;
+		len +=  snprintf(buf+len, size-len,
+			"WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ",
+			*name, *(name+1), *(name+2), *(name+3),
+			*(name+4), *(name+5), *(name+6), *(name+7));
+		name = (unsigned char *)&ndlp->nlp_nodename;
+		len +=  snprintf(buf+len, size-len,
+			"WWNN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ",
+			*name, *(name+1), *(name+2), *(name+3),
+			*(name+4), *(name+5), *(name+6), *(name+7));
+		len +=  snprintf(buf+len, size-len, "RPI:%03d flag:x%08x ",
+			ndlp->nlp_rpi, ndlp->nlp_flag);
+		if (!ndlp->nlp_type)
+			len +=  snprintf(buf+len, size-len, "UNKNOWN_TYPE");
+		if (ndlp->nlp_type & NLP_FC_NODE)
+			len +=  snprintf(buf+len, size-len, "FC_NODE ");
+		if (ndlp->nlp_type & NLP_FABRIC)
+			len +=  snprintf(buf+len, size-len, "FABRIC ");
+		if (ndlp->nlp_type & NLP_FCP_TARGET)
+			len +=  snprintf(buf+len, size-len, "FCP_TGT sid:%d ",
+				ndlp->nlp_sid);
+		if (ndlp->nlp_type & NLP_FCP_INITIATOR)
+			len +=  snprintf(buf+len, size-len, "FCP_INITIATOR");
+		len +=  snprintf(buf+len, size-len, "\n");
+	}
+	spin_unlock_irq(shost->host_lock);
+	return len;
+}
+#endif
+
+
+inline void
+lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt,
+	uint32_t data1, uint32_t data2, uint32_t data3)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+	struct lpfc_disc_trc *dtp;
+	int index;
+
+	if (!(lpfc_debugfs_mask_disc_trc & mask))
+		return;
+
+	if (!lpfc_debugfs_enable || !lpfc_debugfs_max_disc_trc ||
+		!vport || !vport->disc_trc)
+		return;
+
+	index = atomic_inc_return(&vport->disc_trc_cnt) &
+		(lpfc_debugfs_max_disc_trc - 1);
+	dtp = vport->disc_trc + index;
+	dtp->fmt = fmt;
+	dtp->data1 = data1;
+	dtp->data2 = data2;
+	dtp->data3 = data3;
+	dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_disc_trc_cnt);
+	dtp->jif = jiffies;
+#endif
+	return;
+}
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+static int
+lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file)
+{
+	struct lpfc_vport *vport = inode->i_private;
+	struct lpfc_debug *debug;
+	int size;
+	int rc = -ENOMEM;
+
+	if (!lpfc_debugfs_max_disc_trc) {
+		 rc = -ENOSPC;
+		goto out;
+	}
+
+	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+	if (!debug)
+		goto out;
+
+	/* Round to page boundry */
+	size =  (lpfc_debugfs_max_disc_trc * LPFC_DISC_TRC_ENTRY_SIZE);
+	size = PAGE_ALIGN(size);
+
+	debug->buffer = kmalloc(size, GFP_KERNEL);
+	if (!debug->buffer) {
+		kfree(debug);
+		goto out;
+	}
+
+	debug->len = lpfc_debugfs_disc_trc_data(vport, debug->buffer, size);
+	file->private_data = debug;
+
+	rc = 0;
+out:
+	return rc;
+}
+
+static int
+lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file)
+{
+	struct lpfc_vport *vport = 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_NODELIST_SIZE, GFP_KERNEL);
+	if (!debug->buffer) {
+		kfree(debug);
+		goto out;
+	}
+
+	debug->len = lpfc_debugfs_nodelist_data(vport, debug->buffer,
+		LPFC_NODELIST_SIZE);
+	file->private_data = debug;
+
+	rc = 0;
+out:
+	return rc;
+}
+
+static loff_t
+lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
+{
+	struct lpfc_debug *debug;
+	loff_t pos = -1;
+
+	debug = file->private_data;
+
+	switch (whence) {
+	case 0:
+		pos = off;
+		break;
+	case 1:
+		pos = file->f_pos + off;
+		break;
+	case 2:
+		pos = debug->len - off;
+	}
+	return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos);
+}
+
+static ssize_t
+lpfc_debugfs_read(struct file *file, char __user *buf,
+		  size_t nbytes, loff_t *ppos)
+{
+	struct lpfc_debug *debug = file->private_data;
+	return simple_read_from_buffer(buf, nbytes, ppos, debug->buffer,
+				       debug->len);
+}
+
+static int
+lpfc_debugfs_release(struct inode *inode, struct file *file)
+{
+	struct lpfc_debug *debug = file->private_data;
+
+	kfree(debug->buffer);
+	kfree(debug);
+
+	return 0;
+}
+
+#undef lpfc_debugfs_op_disc_trc
+static struct file_operations lpfc_debugfs_op_disc_trc = {
+	.owner =        THIS_MODULE,
+	.open =         lpfc_debugfs_disc_trc_open,
+	.llseek =       lpfc_debugfs_lseek,
+	.read =         lpfc_debugfs_read,
+	.release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_nodelist
+static struct file_operations lpfc_debugfs_op_nodelist = {
+	.owner =        THIS_MODULE,
+	.open =         lpfc_debugfs_nodelist_open,
+	.llseek =       lpfc_debugfs_lseek,
+	.read =         lpfc_debugfs_read,
+	.release =      lpfc_debugfs_release,
+};
+
+static struct dentry *lpfc_debugfs_root = NULL;
+static atomic_t lpfc_debugfs_hba_count;
+#endif
+
+inline void
+lpfc_debugfs_initialize(struct lpfc_vport *vport)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+	struct lpfc_hba   *phba = vport->phba;
+	char name[64];
+	uint32_t num, i;
+
+	if (!lpfc_debugfs_enable)
+		return;
+
+	if (lpfc_debugfs_max_disc_trc) {
+		num = lpfc_debugfs_max_disc_trc - 1;
+		if (num & lpfc_debugfs_max_disc_trc) {
+			/* Change to be a power of 2 */
+			num = lpfc_debugfs_max_disc_trc;
+			i = 0;
+			while (num > 1) {
+				num = num >> 1;
+				i++;
+			}
+			lpfc_debugfs_max_disc_trc = (1 << i);
+			printk(KERN_ERR
+				"lpfc_debugfs_max_disc_trc changed to %d\n",
+				lpfc_debugfs_max_disc_trc);
+		}
+	}
+
+	if (!lpfc_debugfs_root) {
+		lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
+		atomic_set(&lpfc_debugfs_hba_count, 0);
+		if (!lpfc_debugfs_root)
+			goto debug_failed;
+	}
+
+	snprintf(name, sizeof(name), "lpfc%d", phba->brd_no);
+	if (!phba->hba_debugfs_root) {
+		phba->hba_debugfs_root =
+			debugfs_create_dir(name, lpfc_debugfs_root);
+		if (!phba->hba_debugfs_root)
+			goto debug_failed;
+		atomic_inc(&lpfc_debugfs_hba_count);
+		atomic_set(&phba->debugfs_vport_count, 0);
+	}
+
+	snprintf(name, sizeof(name), "vport%d", vport->vpi);
+	if (!vport->vport_debugfs_root) {
+		vport->vport_debugfs_root =
+			debugfs_create_dir(name, phba->hba_debugfs_root);
+		if (!vport->vport_debugfs_root)
+			goto debug_failed;
+		atomic_inc(&phba->debugfs_vport_count);
+	}
+
+	if (!lpfc_debugfs_start_time)
+		lpfc_debugfs_start_time = jiffies;
+
+	vport->disc_trc = kmalloc(
+		(sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc),
+		GFP_KERNEL);
+
+	if (!vport->disc_trc)
+		goto debug_failed;
+	memset(vport->disc_trc, 0,
+		(sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc));
+
+	snprintf(name, sizeof(name), "discovery_trace");
+	vport->debug_disc_trc =
+		debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+				 vport->vport_debugfs_root,
+				 vport, &lpfc_debugfs_op_disc_trc);
+	if (!vport->debug_disc_trc) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"%d:0409 Cannot create debugfs",
+				phba->brd_no);
+		goto debug_failed;
+	}
+	snprintf(name, sizeof(name), "nodelist");
+	vport->debug_nodelist =
+		debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+				 vport->vport_debugfs_root,
+				 vport, &lpfc_debugfs_op_nodelist);
+	if (!vport->debug_nodelist) {
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"%d:0409 Cannot create debugfs",
+				phba->brd_no);
+		goto debug_failed;
+	}
+debug_failed:
+	return;
+#endif
+}
+
+
+inline void
+lpfc_debugfs_terminate(struct lpfc_vport *vport)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+	struct lpfc_hba   *phba = vport->phba;
+
+	if (vport->disc_trc) {
+		kfree(vport->disc_trc);
+		vport->disc_trc = NULL;
+	}
+	if (vport->debug_disc_trc) {
+		debugfs_remove(vport->debug_disc_trc); /* discovery_trace */
+		vport->debug_disc_trc = NULL;
+	}
+	if (vport->debug_nodelist) {
+		debugfs_remove(vport->debug_nodelist); /* nodelist */
+		vport->debug_nodelist = NULL;
+	}
+	if (vport->vport_debugfs_root) {
+		debugfs_remove(vport->vport_debugfs_root); /* vportX */
+		vport->vport_debugfs_root = NULL;
+		atomic_dec(&phba->debugfs_vport_count);
+	}
+	if (atomic_read(&phba->debugfs_vport_count) == 0) {
+		debugfs_remove(vport->phba->hba_debugfs_root); /* lpfcX */
+		vport->phba->hba_debugfs_root = NULL;
+		atomic_dec(&lpfc_debugfs_hba_count);
+		if (atomic_read(&lpfc_debugfs_hba_count) == 0) {
+			debugfs_remove(lpfc_debugfs_root); /* lpfc */
+			lpfc_debugfs_root = NULL;
+		}
+	}
+#endif
+}
+
+
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
new file mode 100644
index 0000000..fffb678
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -0,0 +1,50 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for         *
+ * Fibre Channel Host Bus Adapters.                                *
+ * Copyright (C) 2007 Emulex.  All rights reserved.                *
+ * EMULEX and SLI are trademarks of Emulex.                        *
+ * www.emulex.com                                                  *
+ *                                                                 *
+ * This program is free software; you can redistribute it and/or   *
+ * modify it under the terms of version 2 of the GNU General       *
+ * Public License as published by the Free Software Foundation.    *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
+ * more details, a copy of which can be found in the file COPYING  *
+ * included with this package.                                     *
+ *******************************************************************/
+
+#ifndef _H_LPFC_DEBUG_FS
+#define _H_LPFC_DEBUG_FS
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+struct lpfc_disc_trc {
+	char *fmt;
+	uint32_t data1;
+	uint32_t data2;
+	uint32_t data3;
+	uint32_t seq_cnt;
+	unsigned long jif;
+};
+#endif
+
+/* Mask for discovery_trace */
+#define LPFC_DISC_TRC_ELS_CMD		0x1	/* Trace ELS commands */
+#define LPFC_DISC_TRC_ELS_RSP		0x2	/* Trace ELS response */
+#define LPFC_DISC_TRC_ELS_UNSOL		0x4	/* Trace ELS rcv'ed   */
+#define LPFC_DISC_TRC_ELS_ALL		0x7	/* Trace ELS */
+#define LPFC_DISC_TRC_MBOX_VPORT	0x8	/* Trace vport MBOXs */
+#define LPFC_DISC_TRC_MBOX		0x10	/* Trace other MBOXs */
+#define LPFC_DISC_TRC_MBOX_ALL		0x18	/* Trace all MBOXs */
+#define LPFC_DISC_TRC_CT		0x20	/* Trace disc CT requests */
+#define LPFC_DISC_TRC_DSM		0x40    /* Trace DSM events */
+#define LPFC_DISC_TRC_RPORT		0x80    /* Trace rport events */
+#define LPFC_DISC_TRC_NODE		0x100   /* Trace ndlp state changes */
+
+#define LPFC_DISC_TRC_DISCOVERY		0xef    /* common mask for general
+						 * discovery */
+#endif /* H_LPFC_DEBUG_FS */
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index f23fe1e..aacac9a 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -36,6 +36,7 @@
 	LPFC_EVT_WARM_START,
 	LPFC_EVT_KILL,
 	LPFC_EVT_ELS_RETRY,
+	LPFC_EVT_DEV_LOSS_DELAY,
 	LPFC_EVT_DEV_LOSS,
 };
 
@@ -74,7 +75,6 @@
 #define NLP_FCP_2_DEVICE   0x10			/* FCP-2 device */
 
 	struct timer_list   nlp_delayfunc;	/* Used for delayed ELS cmds */
-	struct timer_list   nlp_initiator_tmr;	/* Used with dev_loss */
 	struct fc_rport *rport;			/* Corresponding FC transport
 						   port structure */
 	struct lpfc_vport *vport;
@@ -101,6 +101,7 @@
 					   ACC */
 #define NLP_NPR_ADISC      0x2000000	/* Issue ADISC when dq'ed from
 					   NPR list */
+#define NLP_RM_DFLT_RPI    0x4000000	/* need to remove leftover dflt RPI */
 #define NLP_NODEV_REMOVE   0x8000000	/* Defer removal till discovery ends */
 #define NLP_TARGET_REMOVE  0x10000000   /* Target remove in process */
 
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index f60c85d..33fbc16 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -36,6 +36,7 @@
 #include "lpfc_logmsg.h"
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
 
 static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
 			  struct lpfc_iocbq *);
@@ -44,7 +45,7 @@
 
 static int lpfc_max_els_tries = 3;
 
-static int
+int
 lpfc_els_chk_latt(struct lpfc_vport *vport)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
@@ -353,7 +354,6 @@
 					"%d:1817 Fabric does not support NPIV "
 					"- configuring single port mode.\n",
 					phba->brd_no);
-			phba->vpi_cnt = 1;
 			phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
 		}
 	}
@@ -406,7 +406,6 @@
 
 	spin_lock_irq(shost->host_lock);
 	vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
-	phba->vpi_cnt = 1;
 	spin_unlock_irq(shost->host_lock);
 
 	phba->fc_edtov = FF_DEF_EDTOV;
@@ -499,6 +498,11 @@
 		goto out;
 	}
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"FLOGI cmpl:      status:x%x/x%x state:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4],
+		vport->port_state);
+
 	if (irsp->ulpStatus) {
 		/* Check for retry */
 		if (lpfc_els_retry(phba, cmdiocb, rspiocb))
@@ -507,7 +511,6 @@
 		/* FLOGI failed, so there is no fabric */
 		spin_lock_irq(shost->host_lock);
 		vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
-		phba->vpi_cnt = 1;
 		spin_unlock_irq(shost->host_lock);
 
 		/* If private loop, then allow max outstanding els to be
@@ -560,11 +563,8 @@
 
 flogifail:
 	lpfc_nlp_put(ndlp);
-	phba->vpi_cnt = 1;
 
-	if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
-	    (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
-	     irsp->un.ulpWord[4] != IOERR_SLI_DOWN)) {
+	if (!lpfc_error_lost_link(irsp)) {
 		/* FLOGI failed, so just use loop map to make discovery list */
 		lpfc_disc_list_loopmap(vport);
 
@@ -627,6 +627,11 @@
 		icmd->ulpCt_l = 0;
 	}
 
+	if (phba->fc_topology != TOPOLOGY_LOOP) {
+		icmd->un.elsreq64.myID = 0;
+		icmd->un.elsreq64.fl = 1;
+	}
+
 	tmo = phba->fc_ratov;
 	phba->fc_ratov = LPFC_DISC_FLOGI_TMO;
 	lpfc_set_disctmo(vport);
@@ -634,6 +639,11 @@
 
 	phba->fc_stat.elsXmitFLOGI++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
+
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Issue FLOGI:     opt:x%x",
+		phba->sli3_options, 0, 0);
+
 	rc = lpfc_issue_fabric_iocb(phba, elsiocb);
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
@@ -816,6 +826,11 @@
 	cmdiocb->context_un.rsp_iocb = rspiocb;
 
 	irsp = &rspiocb->iocb;
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"PLOGI cmpl:      status:x%x/x%x did:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4],
+		irsp->un.elsreq64.remoteID);
+
 	ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
 	if (!ndlp) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
@@ -878,10 +893,7 @@
 		}
 
 		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
-		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-		    ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
-		     (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
-		     (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+		if (lpfc_error_lost_link(irsp)) {
 			rc = NLP_STE_FREED_NODE;
 		} else {
 			rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
@@ -966,6 +978,10 @@
 	if (sp->cmn.fcphHigh < FC_PH3)
 		sp->cmn.fcphHigh = FC_PH3;
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Issue PLOGI:     did:x%x",
+		did, 0, 0);
+
 	phba->fc_stat.elsXmitPLOGI++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
 	ret = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
@@ -997,6 +1013,11 @@
 	ndlp->nlp_flag &= ~NLP_PRLI_SND;
 	spin_unlock_irq(shost->host_lock);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"PRLI cmpl:       status:x%x/x%x did:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4],
+		ndlp->nlp_DID);
+
 	/* PRLI completes to NPort <nlp_DID> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 			"%d (%d):0103 PRLI completes to NPort x%x "
@@ -1018,10 +1039,7 @@
 		}
 		/* PRLI failed */
 		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
-		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-		    ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
-		    (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
-		     (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+		if (lpfc_error_lost_link(irsp)) {
 			goto out;
 		} else {
 			lpfc_disc_state_machine(vport, ndlp, cmdiocb,
@@ -1087,6 +1105,10 @@
 	npr->prliType = PRLI_FCP_TYPE;
 	npr->initiatorFunc = 1;
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Issue PRLI:      did:x%x",
+		ndlp->nlp_DID, 0, 0);
+
 	phba->fc_stat.elsXmitPRLI++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
 	spin_lock_irq(shost->host_lock);
@@ -1133,6 +1155,8 @@
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
+	lpfc_can_disctmo(vport);
+
 	/* RSCN discovery */
 	/* go thru NPR nodes and issue ELS PLOGIs */
 	if (vport->fc_npr_cnt)
@@ -1170,6 +1194,11 @@
 	irsp = &(rspiocb->iocb);
 	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"ADISC cmpl:      status:x%x/x%x did:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4],
+		ndlp->nlp_DID);
+
 	/* Since ndlp can be freed in the disc state machine, note if this node
 	 * is being used during discovery.
 	 */
@@ -1208,12 +1237,9 @@
 		}
 		/* ADISC failed */
 		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
-		if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
-		   ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
-		   (irsp->un.ulpWord[4] != IOERR_LINK_DOWN) &&
-		   (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) {
+		if (!lpfc_error_lost_link(irsp)) {
 			lpfc_disc_state_machine(vport, ndlp, cmdiocb,
-					NLP_EVT_CMPL_ADISC);
+						NLP_EVT_CMPL_ADISC);
 		}
 	} else {
 		/* Good status, call state machine */
@@ -1306,6 +1332,10 @@
 	memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
 	ap->DID = be32_to_cpu(vport->fc_myDID);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Issue ADISC:     did:x%x",
+		ndlp->nlp_DID, 0, 0);
+
 	phba->fc_stat.elsXmitADISC++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
 	spin_lock_irq(shost->host_lock);
@@ -1340,6 +1370,11 @@
 	ndlp->nlp_flag &= ~NLP_LOGO_SND;
 	spin_unlock_irq(shost->host_lock);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"LOGO cmpl:       status:x%x/x%x did:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4],
+		ndlp->nlp_DID);
+
 	/* LOGO completes to NPort <nlp_DID> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 			"%d (%d):0105 LOGO completes to NPort x%x "
@@ -1368,15 +1403,11 @@
 			goto out;
 		/* LOGO failed */
 		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
-		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-		    ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
-		     (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
-		     (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+		if (lpfc_error_lost_link(irsp))
 			goto out;
-		} else {
+		else
 			lpfc_disc_state_machine(vport, ndlp, cmdiocb,
 						NLP_EVT_CMPL_LOGO);
-		}
 	} else {
 		/* Good status, call state machine.
 		 * This will unregister the rpi if needed.
@@ -1423,6 +1454,10 @@
 	pcmd += sizeof(uint32_t);
 	memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Issue LOGO:      did:x%x",
+		ndlp->nlp_DID, 0, 0);
+
 	phba->fc_stat.elsXmitLOGO++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
 	spin_lock_irq(shost->host_lock);
@@ -1449,6 +1484,11 @@
 
 	irsp = &rspiocb->iocb;
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"ELS cmd cmpl:    status:x%x/x%x did:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4],
+		irsp->un.elsreq64.remoteID);
+
 	/* ELS cmd tag <ulpIoTag> completes */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 			"%d (%d):0106 ELS cmd tag x%x completes Data: x%x x%x "
@@ -1502,6 +1542,10 @@
 	memset(pcmd, 0, sizeof(SCR));
 	((SCR *) pcmd)->Function = SCR_FUNC_FULL;
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Issue SCR:       did:x%x",
+		ndlp->nlp_DID, 0, 0);
+
 	phba->fc_stat.elsXmitSCR++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
@@ -1569,6 +1613,10 @@
 		       sizeof(struct lpfc_name));
 	}
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Issue FARPR:     did:x%x",
+		ndlp->nlp_DID, 0, 0);
+
 	phba->fc_stat.elsXmitFARPR++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
@@ -1763,6 +1811,10 @@
 			return 1;
 	}
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Retry ELS:       wd7:x%x wd4:x%x did:x%x",
+		*(((uint32_t *) irsp) + 7), irsp->un.ulpWord[4], ndlp->nlp_DID);
+
 	switch (irsp->ulpStatus) {
 	case IOSTAT_FCP_RSP_ERROR:
 	case IOSTAT_REMOTE_STOP:
@@ -1776,10 +1828,6 @@
 			retry = 1;
 			break;
 
-		case IOERR_SEQUENCE_TIMEOUT:
-			retry = 1;
-			break;
-
 		case IOERR_ILLEGAL_COMMAND:
 			if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) &&
 			    (cmd == ELS_CMD_FDISC)) {
@@ -1794,10 +1842,18 @@
 			break;
 
 		case IOERR_NO_RESOURCES:
+			retry = 1;
+			if (cmdiocb->retry > 100)
+				delay = 100;
+			maxretry = 250;
+			break;
+
+		case IOERR_ILLEGAL_FRAME:
 			delay = 100;
 			retry = 1;
 			break;
 
+		case IOERR_SEQUENCE_TIMEOUT:
 		case IOERR_INVALID_RPI:
 			retry = 1;
 			break;
@@ -1852,7 +1908,8 @@
 			break;
 
 		case LSRJT_LOGICAL_BSY:
-			if (cmd == ELS_CMD_PLOGI) {
+			if ((cmd == ELS_CMD_PLOGI) ||
+			    (cmd == ELS_CMD_PRLI)) {
 				delay = 1000;
 				maxretry = 48;
 			} else if (cmd == ELS_CMD_FDISC) {
@@ -1908,7 +1965,11 @@
 				phba->brd_no, vport->vpi,
 				cmd, did, cmdiocb->retry, delay);
 
-		if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) {
+		if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) &&
+			((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
+			((irsp->un.ulpWord[4] & 0xff) != IOERR_NO_RESOURCES))) {
+			/* Don't reset timer for no resources */
+
 			/* If discovery / RSCN timer is running, reset it */
 			if (timer_pending(&vport->fc_disctmo) ||
 			    (vport->fc_flag & FC_RSCN_MODE))
@@ -1928,7 +1989,12 @@
 			spin_unlock_irq(shost->host_lock);
 
 			ndlp->nlp_prev_state = ndlp->nlp_state;
-			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+			if (cmd == ELS_CMD_PRLI)
+				lpfc_nlp_set_state(vport, ndlp,
+					NLP_STE_REG_LOGIN_ISSUE);
+			else
+				lpfc_nlp_set_state(vport, ndlp,
+					NLP_STE_NPR_NODE);
 			ndlp->nlp_last_elscmd = cmd;
 
 			return 1;
@@ -2015,6 +2081,12 @@
 {
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
 	struct lpfc_vport *vport = cmdiocb->vport;
+	IOCB_t *irsp;
+
+	irsp = &rspiocb->iocb;
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+		"ACC LOGO cmpl:   status:x%x/x%x did:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID);
 
 	/* ACC to LOGO completes to NPort <nlp_DID> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
@@ -2037,8 +2109,22 @@
 	return;
 }
 
+void
+lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+
+	pmb->context1 = NULL;
+	lpfc_mbuf_free(phba, mp->virt, mp->phys);
+	kfree(mp);
+	mempool_free(pmb, phba->mbox_mem_pool);
+	lpfc_nlp_put(ndlp);
+	return;
+}
+
 static void
-lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 		  struct lpfc_iocbq *rspiocb)
 {
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
@@ -2066,6 +2152,11 @@
 		goto out;
 	}
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+		"ACC cmpl:        status:x%x/x%x did:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4],
+		irsp->un.rcvels.remoteID);
+
 	/* ELS response tag <ulpIoTag> completes */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 			"%d (%d):0110 ELS response tag x%x completes "
@@ -2080,12 +2171,18 @@
 		if ((rspiocb->iocb.ulpStatus == 0)
 		    && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
 			lpfc_unreg_rpi(vport, ndlp);
-			mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
 			mbox->context2 = lpfc_nlp_get(ndlp);
 			mbox->vport = vport;
-			ndlp->nlp_prev_state = ndlp->nlp_state;
-			lpfc_nlp_set_state(vport, ndlp,
+			if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) {
+				mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
+				mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+			}
+			else {
+				mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
+				ndlp->nlp_prev_state = ndlp->nlp_state;
+				lpfc_nlp_set_state(vport, ndlp,
 					   NLP_STE_REG_LOGIN_ISSUE);
+			}
 			if (lpfc_sli_issue_mbox(phba, mbox,
 						(MBX_NOWAIT | MBX_STOP_IOCB))
 			    != MBX_NOT_FINISHED) {
@@ -2095,15 +2192,11 @@
 			/* NOTE: we should have messages for unsuccessful
 			   reglogin */
 		} else {
-			/* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */
-			if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
-			      ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
-			       (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
-			       (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
-				if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
-					lpfc_drop_node(vport, ndlp);
-					ndlp = NULL;
-				}
+			/* Do not drop node for lpfc_els_abort'ed ELS cmds */
+			if (!lpfc_error_lost_link(irsp) &&
+			    ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
+				lpfc_drop_node(vport, ndlp);
+				ndlp = NULL;
 			}
 		}
 		mp = (struct lpfc_dmabuf *) mbox->context1;
@@ -2116,7 +2209,7 @@
 out:
 	if (ndlp) {
 		spin_lock_irq(shost->host_lock);
-		ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN;
+		ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
 		spin_unlock_irq(shost->host_lock);
 	}
 	lpfc_els_free_iocb(phba, cmdiocb);
@@ -2161,6 +2254,10 @@
 		pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 		*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
 		pcmd += sizeof(uint32_t);
+
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+			"Issue ACC:       did:x%x flg:x%x",
+			ndlp->nlp_DID, ndlp->nlp_flag, 0);
 		break;
 	case ELS_CMD_PLOGI:
 		cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
@@ -2179,6 +2276,10 @@
 		*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
 		pcmd += sizeof(uint32_t);
 		memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
+
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+			"Issue ACC PLOGI: did:x%x flg:x%x",
+			ndlp->nlp_DID, ndlp->nlp_flag, 0);
 		break;
 	case ELS_CMD_PRLO:
 		cmdsize = sizeof(uint32_t) + sizeof(PRLO);
@@ -2196,6 +2297,10 @@
 		*((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
 		els_pkt_ptr = (ELS_PKT *) pcmd;
 		els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
+
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+			"Issue ACC PRLO:  did:x%x flg:x%x",
+			ndlp->nlp_DID, ndlp->nlp_flag, 0);
 		break;
 	default:
 		return 1;
@@ -2220,7 +2325,7 @@
 		spin_unlock_irq(shost->host_lock);
 		elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
 	} else {
-		elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+		elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	}
 
 	phba->fc_stat.elsXmitACC++;
@@ -2234,7 +2339,8 @@
 
 int
 lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
-		    struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
+		    struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
+		    LPFC_MBOXQ_t *mbox)
 {
 	struct lpfc_hba  *phba = vport->phba;
 	IOCB_t *icmd;
@@ -2264,6 +2370,11 @@
 	pcmd += sizeof(uint32_t);
 	*((uint32_t *) (pcmd)) = rejectError;
 
+	if (mbox) {
+		elsiocb->context_un.mbox = mbox;
+		elsiocb->context1 = lpfc_nlp_get(ndlp);
+	}
+
 	/* Xmit ELS RJT <err> response tag <ulpIoTag> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
 			"%d (%d):0129 Xmit ELS RJT x%x response tag x%x "
@@ -2273,8 +2384,12 @@
 			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
 			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+		"Issue LS_RJT:    did:x%x flg:x%x err:x%x",
+		ndlp->nlp_DID, ndlp->nlp_flag, rejectError);
+
 	phba->fc_stat.elsXmitLSRJT++;
-	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
@@ -2326,8 +2441,12 @@
 	memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
 	ap->DID = be32_to_cpu(vport->fc_myDID);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+		"Issue ACC ADISC: did:x%x flg:x%x",
+		ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
 	phba->fc_stat.elsXmitACC++;
-	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
@@ -2401,8 +2520,12 @@
 	npr->prliType = PRLI_FCP_TYPE;
 	npr->initiatorFunc = 1;
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+		"Issue ACC PRLI:  did:x%x flg:x%x",
+		ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
 	phba->fc_stat.elsXmitACC++;
-	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 
 	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
 	if (rc == IOCB_ERROR) {
@@ -2479,8 +2602,12 @@
 		break;
 	}
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+		"Issue ACC RNID:  did:x%x flg:x%x",
+		ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
 	phba->fc_stat.elsXmitACC++;
-	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	lpfc_nlp_put(ndlp);
 	elsiocb->context1 = NULL;  /* Don't need ndlp for cmpl,
 				    * it could be freed */
@@ -2703,6 +2830,10 @@
 	 * Discovery processing will satisfy it.
 	 */
 	if (vport->port_state <= LPFC_NS_QRY) {
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV RSCN ignore: did:x%x/ste:x%x flg:x%x",
+			ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
+
 		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
 				 newnode);
 		return 0;
@@ -2734,6 +2865,12 @@
 			  "%d (%d):0214 Ignore RSCN Data: x%x x%x x%x x%x\n",
 			  phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
 			  *lp, rscn_cnt);
+
+			lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+				"RCV RSCN vport:  did:x%x/ste:x%x flg:x%x",
+				ndlp->nlp_DID, vport->port_state,
+				ndlp->nlp_flag);
+
 			lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb,
 				ndlp, NULL, newnode);
 			return 0;
@@ -2744,6 +2881,10 @@
 	 * RSCN payload buffer, cmdiocb->context2 to process later.
 	 */
 	if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV RSCN defer:  did:x%x/ste:x%x flg:x%x",
+			ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
+
 		vport->fc_flag |= FC_RSCN_DEFERRED;
 		if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
 		    !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
@@ -2798,6 +2939,10 @@
 		return 0;
 	}
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+		"RCV RSCN:        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_MODE;
 	spin_unlock_irq(shost->host_lock);
@@ -2958,7 +3103,8 @@
 		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 		stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
 		stat.un.b.vendorUnique = 0;
-		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+			NULL);
 		return 1;
 	}
 
@@ -3001,7 +3147,8 @@
 		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 		stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
 		stat.un.b.vendorUnique = 0;
-		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+			NULL);
 	}
 	return 0;
 }
@@ -3017,7 +3164,7 @@
 	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 	stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
 	stat.un.b.vendorUnique = 0;
-	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
 	return 0;
 }
 
@@ -3089,7 +3236,7 @@
 			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
 			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
-	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	phba->fc_stat.elsXmitACC++;
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
 		lpfc_els_free_iocb(phba, elsiocb);
@@ -3114,7 +3261,8 @@
 		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 		stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
 		stat.un.b.vendorUnique = 0;
-		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+			NULL);
 	}
 
 	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -3150,7 +3298,7 @@
 	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 	stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
 	stat.un.b.vendorUnique = 0;
-	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
 	return 0;
 }
 
@@ -3202,7 +3350,7 @@
 			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
 			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 
-	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 
 	phba->fc_stat.elsXmitACC++;
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
@@ -3229,7 +3377,8 @@
 		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 		stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
 		stat.un.b.vendorUnique = 0;
-		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+			NULL);
 	}
 
 	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -3538,9 +3687,6 @@
 	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 	struct lpfc_iocbq *tmp_iocb, *piocb;
 	IOCB_t *cmd = NULL;
-	struct lpfc_dmabuf *pcmd;
-	uint32_t *elscmd;
-	uint32_t els_command;
 
 	lpfc_fabric_abort_vport(vport);
 
@@ -3559,10 +3705,6 @@
 		    cmd->ulpCommand == CMD_ABORT_XRI_CN)
 			continue;
 
-		pcmd = (struct lpfc_dmabuf *) piocb->context2;
-		elscmd = (uint32_t *) (pcmd->virt);
-		els_command = *elscmd;
-
 		if (piocb->vport != vport)
 			continue;
 
@@ -3618,8 +3760,13 @@
 	if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
 		lpfc_post_buffer(phba, pring, 1, 1);
 
-	if (icmd->ulpStatus)
+	did = icmd->un.rcvels.remoteID;
+	if (icmd->ulpStatus) {
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV Unsol ELS:  status:x%x/x%x did:x%x",
+			icmd->ulpStatus, icmd->un.ulpWord[4], did);
 		goto dropit;
+	}
 
 	/* Check to see if link went down during discovery */
 	if (lpfc_els_chk_latt(vport))
@@ -3629,7 +3776,6 @@
 	if (vport->load_flag & FC_UNLOADING)
 		goto dropit;
 
-	did = icmd->un.rcvels.remoteID;
 	ndlp = lpfc_findnode_did(vport, did);
 	if (!ndlp) {
 		/* Cannot find existing Fabric ndlp, so allocate a new one */
@@ -3662,35 +3808,51 @@
 
 	switch (cmd) {
 	case ELS_CMD_PLOGI:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV PLOGI:       did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvPLOGI++;
-		if ((vport->port_state < LPFC_DISC_AUTH) ||
-		    ((vport->port_type == LPFC_NPIV_PORT &&
-		      phba->cfg_vport_restrict_login))) {
-			rjt_err = 2;
+		ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
+
+		if (vport->port_state < LPFC_DISC_AUTH) {
+			rjt_err = LSRJT_UNABLE_TPC;
 			break;
 		}
-		ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
 		lpfc_disc_state_machine(vport, ndlp, elsiocb,
 					NLP_EVT_RCV_PLOGI);
+
 		break;
 	case ELS_CMD_FLOGI:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV FLOGI:       did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvFLOGI++;
 		lpfc_els_rcv_flogi(vport, elsiocb, ndlp, newnode);
 		if (newnode)
 			lpfc_drop_node(vport, ndlp);
 		break;
 	case ELS_CMD_LOGO:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV LOGO:        did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvLOGO++;
 		if (vport->port_state < LPFC_DISC_AUTH) {
-			rjt_err = 1;
+			rjt_err = LSRJT_UNABLE_TPC;
 			break;
 		}
 		lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
 		break;
 	case ELS_CMD_PRLO:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV PRLO:        did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvPRLO++;
 		if (vport->port_state < LPFC_DISC_AUTH) {
-			rjt_err = 1;
+			rjt_err = LSRJT_UNABLE_TPC;
 			break;
 		}
 		lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
@@ -3702,70 +3864,114 @@
 			lpfc_drop_node(vport, ndlp);
 		break;
 	case ELS_CMD_ADISC:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV ADISC:       did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvADISC++;
 		if (vport->port_state < LPFC_DISC_AUTH) {
-			rjt_err = 1;
+			rjt_err = LSRJT_UNABLE_TPC;
 			break;
 		}
 		lpfc_disc_state_machine(vport, ndlp, elsiocb,
 					NLP_EVT_RCV_ADISC);
 		break;
 	case ELS_CMD_PDISC:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV PDISC:       did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvPDISC++;
 		if (vport->port_state < LPFC_DISC_AUTH) {
-			rjt_err = 1;
+			rjt_err = LSRJT_UNABLE_TPC;
 			break;
 		}
 		lpfc_disc_state_machine(vport, ndlp, elsiocb,
 					NLP_EVT_RCV_PDISC);
 		break;
 	case ELS_CMD_FARPR:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV FARPR:       did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvFARPR++;
 		lpfc_els_rcv_farpr(vport, elsiocb, ndlp);
 		break;
 	case ELS_CMD_FARP:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV FARP:        did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvFARP++;
 		lpfc_els_rcv_farp(vport, elsiocb, ndlp);
 		break;
 	case ELS_CMD_FAN:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV FAN:         did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvFAN++;
 		lpfc_els_rcv_fan(vport, elsiocb, ndlp);
 		break;
 	case ELS_CMD_PRLI:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV PRLI:        did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvPRLI++;
 		if (vport->port_state < LPFC_DISC_AUTH) {
-			rjt_err = 1;
+			rjt_err = LSRJT_UNABLE_TPC;
 			break;
 		}
 		lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
 		break;
 	case ELS_CMD_LIRR:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV LIRR:        did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvLIRR++;
 		lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
 		if (newnode)
 			lpfc_drop_node(vport, ndlp);
 		break;
 	case ELS_CMD_RPS:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV RPS:         did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvRPS++;
 		lpfc_els_rcv_rps(vport, elsiocb, ndlp);
 		if (newnode)
 			lpfc_drop_node(vport, ndlp);
 		break;
 	case ELS_CMD_RPL:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV RPL:         did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvRPL++;
 		lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
 		if (newnode)
 			lpfc_drop_node(vport, ndlp);
 		break;
 	case ELS_CMD_RNID:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV RNID:        did:x%x/ste:x%x flg:x%x",
+			did, vport->port_state, ndlp->nlp_flag);
+
 		phba->fc_stat.elsRcvRNID++;
 		lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
 		if (newnode)
 			lpfc_drop_node(vport, ndlp);
 		break;
 	default:
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+			"RCV ELS cmd:     cmd:x%x did:x%x/ste:x%x",
+			cmd, did, vport->port_state);
+
 		/* Unsupported ELS command, reject */
-		rjt_err = 2;
+		rjt_err = LSRJT_INVALID_CMD;
 
 		/* Unknown ELS command <elsCmd> received from NPORT <did> */
 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
@@ -3780,12 +3986,10 @@
 	/* check if need to LS_RJT received ELS cmd */
 	if (rjt_err) {
 		memset(&stat, 0, sizeof(stat));
-		if (rjt_err == 1)
-			stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
-		else
-			stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
+		stat.un.b.lsRjtRsnCode = rjt_err;
 		stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
-		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp);
+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp,
+			NULL);
 		if (newnode)
 			lpfc_drop_node(vport, ndlp);
 	}
@@ -4044,6 +4248,10 @@
 		lpfc_set_disctmo(piocb->vport);
 	}
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"FDISC cmpl:      status:x%x/x%x prevdid:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
+
 	if (irsp->ulpStatus) {
 		/* Check for retry */
 		if (lpfc_els_retry(phba, cmdiocb, rspiocb))
@@ -4054,6 +4262,7 @@
 			"%d (%d):0124 FDISC failed. (%d/%d)\n",
 			phba->brd_no, vport->vpi,
 			irsp->ulpStatus, irsp->un.ulpWord[4]);
+
 		if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
 			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 
@@ -4113,14 +4322,11 @@
 	uint16_t cmdsize;
 	int did = ndlp->nlp_DID;
 	int rc;
-	int new_ndlp = 0;
 
 	cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
 				     ELS_CMD_FDISC);
 	if (!elsiocb) {
-		if (new_ndlp)
-			mempool_free(ndlp, phba->nlp_mem_pool);
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 
 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
@@ -4163,11 +4369,13 @@
 	phba->fc_stat.elsXmitFDISC++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_fdisc;
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Issue FDISC:     did:x%x",
+		did, 0, 0);
+
 	rc = lpfc_issue_fabric_iocb(phba, elsiocb);
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
-		if (new_ndlp)
-			mempool_free(ndlp, phba->nlp_mem_pool);
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 
 		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
@@ -4186,6 +4394,12 @@
 			struct lpfc_iocbq *rspiocb)
 {
 	struct lpfc_vport *vport = cmdiocb->vport;
+	IOCB_t *irsp;
+
+	irsp = &rspiocb->iocb;
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"LOGO npiv cmpl:  status:x%x/x%x did:x%x",
+		irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.rcvels.remoteID);
 
 	lpfc_els_free_iocb(phba, cmdiocb);
 	vport->unreg_vpi_cmpl = VPORT_ERROR;
@@ -4218,6 +4432,10 @@
 	pcmd += sizeof(uint32_t);
 	memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Issue LOGO npiv  did:x%x flg:x%x",
+		ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_npiv_logo;
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag |= NLP_LOGO_SND;
@@ -4277,6 +4495,10 @@
 		iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
 		iocb->iocb_flag |= LPFC_IO_FABRIC;
 
+		lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
+			"Fabric sched1:   ste:x%x",
+			iocb->vport->port_state, 0, 0);
+
 		ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
 
 		if (ret == IOCB_ERROR) {
@@ -4387,6 +4609,10 @@
 		iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
 		iocb->iocb_flag |= LPFC_IO_FABRIC;
 
+		lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
+			"Fabric sched2:   ste:x%x",
+			iocb->vport->port_state, 0, 0);
+
 		atomic_inc(&phba->fabric_iocb_count);
 		ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
 
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 94ee967..f2f4639 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -37,6 +37,7 @@
 #include "lpfc_logmsg.h"
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
 
 /* AlpaArray for assignment of scsid for scan-down and bind_method */
 static uint8_t lpfcAlpaArray[] = {
@@ -77,6 +78,10 @@
 
 	phba  = ndlp->vport->phba;
 
+	lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT,
+		"rport terminate: sid:x%x did:x%x flg:x%x",
+		ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
+
 	if (ndlp->nlp_sid != NLP_NO_SID) {
 		lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
 			ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
@@ -93,12 +98,10 @@
 {
 	struct lpfc_rport_data *rdata;
 	struct lpfc_nodelist * ndlp;
-	uint8_t *name;
-	int warn_on = 0;
-	struct lpfc_hba *phba;
 	struct lpfc_vport *vport;
-	int  put_node;
-	int  put_rport;
+	struct lpfc_hba   *phba;
+	struct completion devloss_compl;
+	struct lpfc_work_evt *evtp;
 
 	rdata = rport->dd_data;
 	ndlp = rdata->pnode;
@@ -112,7 +115,70 @@
 		return;
 	}
 
+	vport = ndlp->vport;
+	phba  = vport->phba;
+
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+		"rport devlosscb: sid:x%x did:x%x flg:x%x",
+		ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
+
+	init_completion(&devloss_compl);
+	evtp = &ndlp->dev_loss_evt;
+
+	if (!list_empty(&evtp->evt_listp))
+		return;
+
+	spin_lock_irq(&phba->hbalock);
+	evtp->evt_arg1  = ndlp;
+	evtp->evt_arg2  = &devloss_compl;
+	evtp->evt       = LPFC_EVT_DEV_LOSS;
+	list_add_tail(&evtp->evt_listp, &phba->work_list);
+	if (phba->work_wait)
+		wake_up(phba->work_wait);
+
+	spin_unlock_irq(&phba->hbalock);
+
+	wait_for_completion(&devloss_compl);
+
+	return;
+}
+
+/*
+ * This function is called from the worker thread when dev_loss_tmo
+ * expire.
+ */
+void
+lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+{
+	struct lpfc_rport_data *rdata;
+	struct fc_rport   *rport;
+	struct lpfc_vport *vport;
+	struct lpfc_hba   *phba;
+	uint8_t *name;
+	int warn_on = 0;
+
+	rport = ndlp->rport;
+
+	if (!rport)
+		return;
+
+	rdata = rport->dd_data;
+	name = (uint8_t *) &ndlp->nlp_portname;
+	vport = ndlp->vport;
+	phba  = vport->phba;
+
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+		"rport devlosstmo:did:x%x type:x%x id:x%x",
+		ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
+
+	if (!(vport->load_flag & FC_UNLOADING) &&
+	    ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+		return;
+
 	if (ndlp->nlp_type & NLP_FABRIC) {
+		int  put_node;
+		int  put_rport;
+
 		/* We will clean up these Nodes in linkup */
 		put_node = rdata->pnode != NULL;
 		put_rport = ndlp->rport != NULL;
@@ -125,15 +191,6 @@
 		return;
 	}
 
-	name = (uint8_t *)&ndlp->nlp_portname;
-	vport = ndlp->vport;
-	phba  = vport->phba;
-
-	if (!(vport->load_flag & FC_UNLOADING) &&
-	    ndlp->nlp_state == NLP_STE_MAPPED_NODE)
-		return;
-
-
 	if (ndlp->nlp_sid != NLP_NO_SID) {
 		warn_on = 1;
 		/* flush the target */
@@ -171,6 +228,9 @@
 	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
 		lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
 	else {
+		int  put_node;
+		int  put_rport;
+
 		put_node = rdata->pnode != NULL;
 		put_rport = ndlp->rport != NULL;
 		rdata->pnode = NULL;
@@ -180,7 +240,6 @@
 		if (put_rport)
 			put_device(&rport->dev);
 	}
-	return;
 }
 
 
@@ -206,12 +265,17 @@
 		spin_unlock_irq(&phba->hbalock);
 		free_evt = 1;
 		switch (evtp->evt) {
-		case LPFC_EVT_DEV_LOSS:
+		case LPFC_EVT_DEV_LOSS_DELAY:
 			free_evt = 0; /* evt is part of ndlp */
 			ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
 			vport = ndlp->vport;
 			if (!vport)
 				break;
+
+			lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+				"rport devlossdly:did:x%x flg:x%x",
+				ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
 			if (!(vport->load_flag & FC_UNLOADING) &&
 			    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
 			    !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
@@ -224,6 +288,14 @@
 			lpfc_els_retry_delay_handler(ndlp);
 			free_evt = 0; /* evt is part of ndlp */
 			break;
+		case LPFC_EVT_DEV_LOSS:
+			ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
+			lpfc_nlp_get(ndlp);
+			lpfc_dev_loss_tmo_handler(ndlp);
+			free_evt = 0;
+			complete((struct completion *)(evtp->evt_arg2));
+			lpfc_nlp_put(ndlp);
+			break;
 		case LPFC_EVT_ONLINE:
 			if (phba->link_state < LPFC_LINK_DOWN)
 				*(int *) (evtp->evt_arg1) = lpfc_online(phba);
@@ -272,13 +344,12 @@
 
 }
 
-static void
+void
 lpfc_work_done(struct lpfc_hba *phba)
 {
 	struct lpfc_sli_ring *pring;
-	uint32_t ha_copy, control, work_port_events;
+	uint32_t ha_copy, status, control, work_port_events;
 	struct lpfc_vport *vport;
-	int i;
 
 	spin_lock_irq(&phba->hbalock);
 	ha_copy = phba->work_ha;
@@ -310,6 +381,9 @@
 		if (work_port_events & WORKER_ELS_TMO)
 			lpfc_els_timeout_handler(vport);
 
+		if (work_port_events & WORKER_HB_TMO)
+			lpfc_hb_timeout_handler(phba);
+
 		if (work_port_events & WORKER_MBOX_TMO)
 			lpfc_mbox_timeout_handler(phba);
 
@@ -333,30 +407,31 @@
 	}
 	spin_unlock_irq(&phba->hbalock);
 
-	for (i = 0; i < phba->sli.num_rings; i++, ha_copy >>= 4) {
-		pring = &phba->sli.ring[i];
-		if ((ha_copy & HA_RXATT)
-		    || (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
-			if (pring->flag & LPFC_STOP_IOCB_MASK) {
-				pring->flag |= LPFC_DEFERRED_RING_EVENT;
-			} else {
-				lpfc_sli_handle_slow_ring_event(phba, pring,
-								(ha_copy &
-								 HA_RXMASK));
-				pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
-			}
-			/*
-			 * Turn on Ring interrupts
-			 */
-			spin_lock_irq(&phba->hbalock);
-			control = readl(phba->HCregaddr);
-			control |= (HC_R0INT_ENA << i);
+	pring = &phba->sli.ring[LPFC_ELS_RING];
+	status = (ha_copy & (HA_RXMASK  << (4*LPFC_ELS_RING)));
+	status >>= (4*LPFC_ELS_RING);
+	if ((status & HA_RXMASK)
+		|| (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
+		if (pring->flag & LPFC_STOP_IOCB_MASK) {
+			pring->flag |= LPFC_DEFERRED_RING_EVENT;
+		} else {
+			lpfc_sli_handle_slow_ring_event(phba, pring,
+							(status &
+							 HA_RXMASK));
+			pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
+		}
+		/*
+		 * Turn on Ring interrupts
+		 */
+		spin_lock_irq(&phba->hbalock);
+		control = readl(phba->HCregaddr);
+		if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
+			control |= (HC_R0INT_ENA << LPFC_ELS_RING);
 			writel(control, phba->HCregaddr);
 			readl(phba->HCregaddr); /* flush */
-			spin_unlock_irq(&phba->hbalock);
 		}
+		spin_unlock_irq(&phba->hbalock);
 	}
-
 	lpfc_work_list_done(phba);
 }
 
@@ -365,7 +440,7 @@
 {
 	struct lpfc_vport *vport;
 	struct lpfc_sli_ring *pring;
-	int i, rc = 0;
+	int rc = 0;
 
 	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry(vport, &phba->port_list, listentry) {
@@ -380,13 +455,10 @@
 		rc = 1;
 		goto exit;
 	}
-	for (i = 0; i < phba->sli.num_rings; i++) {
-		pring = &phba->sli.ring[i];
-		if (pring->flag & LPFC_DEFERRED_RING_EVENT) {
-			rc = 1;
-			goto exit;
-		}
-	}
+
+	pring = &phba->sli.ring[LPFC_ELS_RING];
+	if (pring->flag & LPFC_DEFERRED_RING_EVENT)
+		rc = 1;
 exit:
 	if (rc)
 		phba->work_found++;
@@ -506,6 +578,10 @@
 
 	fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Link Down:       state:x%x rtry:x%x flg:x%x",
+		vport->port_state, vport->fc_ns_retry, vport->fc_flag);
+
 	/* Cleanup any outstanding RSCN activity */
 	lpfc_els_flush_rscn(vport);
 
@@ -617,6 +693,10 @@
 	if ((vport->load_flag & FC_UNLOADING) != 0)
 		return;
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"Link Up:         top:x%x speed:x%x flg:x%x",
+		phba->fc_topology, phba->fc_linkspeed, phba->link_flag);
+
 	/* If NPIV is not enabled, only bring the physical port up */
 	if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
 		(vport != phba->pport))
@@ -935,7 +1015,7 @@
 		}
 	} else {
 		if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
-			if (phba->max_vpi && lpfc_npiv_enable &&
+			if (phba->max_vpi && phba->cfg_npiv_enable &&
 			   (phba->sli_rev == 3))
 				phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
 		}
@@ -1124,8 +1204,6 @@
 				"mb status = 0x%x\n",
 				phba->brd_no, vport->vpi, mb->mbxStatus);
 		break;
-	default:
-		phba->vpi_cnt--;
 	}
 	vport->unreg_vpi_cmpl = VPORT_OK;
 	mempool_free(pmb, phba->mbox_mem_pool);
@@ -1182,7 +1260,6 @@
 		vport->fc_myDID = 0;
 		goto out;
 	}
-	phba->vpi_cnt++;
 
 	vport->num_disc_nodes = 0;
 	/* go thru NPR list and issue ELS PLOGIs */
@@ -1257,16 +1334,13 @@
 
 			if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
 				lpfc_initial_fdisc(next_vport);
-			else {
-				if (phba->sli3_options &
-					LPFC_SLI3_NPIV_ENABLED) {
-					lpfc_vport_set_state(vport,
-						FC_VPORT_NO_FABRIC_SUPP);
-					lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+			else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+				lpfc_vport_set_state(vport,
+						     FC_VPORT_NO_FABRIC_SUPP);
+				lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
 						"%d (%d):0259 No NPIV Fabric "
 						"support\n",
 						phba->brd_no, vport->vpi);
-				}
 			}
 		}
 		lpfc_do_scr_ns_plogi(phba, vport);
@@ -1377,6 +1451,11 @@
 	    ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) {
 		lpfc_nlp_put(ndlp);
 	}
+
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+		"rport add:       did:x%x flg:x%x type x%x",
+		ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
+
 	ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids);
 	if (!rport || !get_device(&rport->dev)) {
 		dev_printk(KERN_WARNING, &phba->pcidev->dev,
@@ -1394,7 +1473,6 @@
 		rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
 	if (ndlp->nlp_type & NLP_FCP_INITIATOR)
 		rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
-	del_timer_sync(&ndlp->nlp_initiator_tmr);
 
 
 	if (rport_ids.roles !=  FC_RPORT_ROLE_UNKNOWN)
@@ -1412,6 +1490,10 @@
 {
 	struct fc_rport *rport = ndlp->rport;
 
+	lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT,
+		"rport delete:    did:x%x flg:x%x type x%x",
+		ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
+
 	fc_remote_port_delete(rport);
 
 	return;
@@ -1478,20 +1560,19 @@
 	if (new_state ==  NLP_STE_MAPPED_NODE ||
 	    new_state == NLP_STE_UNMAPPED_NODE) {
 		vport->phba->nport_event_cnt++;
-			/*
-			 * Tell the fc transport about the port, if we haven't
-			 * already. If we have, and it's a scsi entity, be
-			 * sure to unblock any attached scsi devices
-			 */
-			lpfc_register_remote_port(vport, ndlp);
+		/*
+		 * Tell the fc transport about the port, if we haven't
+		 * already. If we have, and it's a scsi entity, be
+		 * sure to unblock any attached scsi devices
+		 */
+		lpfc_register_remote_port(vport, ndlp);
 	}
-
-			/*
-			 * if we added to Mapped list, but the remote port
-			 * registration failed or assigned a target id outside
-			 * our presentable range - move the node to the
-			 * Unmapped List
-			 */
+	/*
+	 * if we added to Mapped list, but the remote port
+	 * registration failed or assigned a target id outside
+	 * our presentable range - move the node to the
+	 * Unmapped List
+	 */
 	if (new_state == NLP_STE_MAPPED_NODE &&
 	    (!ndlp->rport ||
 	     ndlp->rport->scsi_target_id == -1 ||
@@ -1533,11 +1614,16 @@
 	char name1[16], name2[16];
 
 	lpfc_printf_log(vport->phba, KERN_INFO, LOG_NODE,
-			"%d:0904 NPort state transition x%06x, %s -> %s\n",
-			vport->phba->brd_no,
+			"%d (%d):0904 NPort state transition x%06x, %s -> %s\n",
+			vport->phba->brd_no, vport->vpi,
 			ndlp->nlp_DID,
 			lpfc_nlp_state_name(name1, sizeof(name1), old_state),
 			lpfc_nlp_state_name(name2, sizeof(name2), state));
+
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
+		"node statechg    did:x%x old:%d ste:%d",
+		ndlp->nlp_DID, old_state, state);
+
 	if (old_state == NLP_STE_NPR_NODE &&
 	    (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 &&
 	    state != NLP_STE_NPR_NODE)
@@ -1571,7 +1657,8 @@
 	spin_lock_irq(shost->host_lock);
 	list_del_init(&ndlp->nlp_listp);
 	spin_unlock_irq(shost->host_lock);
-	lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, 0);
+	lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state,
+			       NLP_STE_UNUSED_NODE);
 }
 
 void
@@ -1585,6 +1672,7 @@
 		lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
 	spin_lock_irq(shost->host_lock);
 	list_del_init(&ndlp->nlp_listp);
+	ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
 	spin_unlock_irq(shost->host_lock);
 	lpfc_nlp_put(ndlp);
 }
@@ -1609,6 +1697,13 @@
 		tmo = ((phba->fc_ratov * 3) + 3);
 	}
 
+
+	if (!timer_pending(&vport->fc_disctmo)) {
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+			"set disc timer:  tmo:x%x state:x%x flg:x%x",
+			tmo, vport->port_state, vport->fc_flag);
+	}
+
 	mod_timer(&vport->fc_disctmo, jiffies + HZ * tmo);
 	spin_lock_irq(shost->host_lock);
 	vport->fc_flag |= FC_DISC_TMO;
@@ -1635,6 +1730,10 @@
 	struct lpfc_hba  *phba = vport->phba;
 	unsigned long iflags;
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"can disc timer:  state:x%x rtry:x%x flg:x%x",
+		vport->port_state, vport->fc_ns_retry, vport->fc_flag);
+
 	/* Turn off discovery timer if its running */
 	if (vport->fc_flag & FC_DISC_TMO) {
 		spin_lock_irqsave(shost->host_lock, iflags);
@@ -1898,13 +1997,17 @@
 
 	ndlp->nlp_last_elscmd = 0;
 	del_timer_sync(&ndlp->nlp_delayfunc);
-	del_timer_sync(&ndlp->nlp_initiator_tmr);
 
 	if (!list_empty(&ndlp->els_retry_evt.evt_listp))
 		list_del_init(&ndlp->els_retry_evt.evt_listp);
 	if (!list_empty(&ndlp->dev_loss_evt.evt_listp))
 		list_del_init(&ndlp->dev_loss_evt.evt_listp);
 
+	if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) {
+		list_del_init(&ndlp->dev_loss_evt.evt_listp);
+		complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2));
+	}
+
 	lpfc_unreg_rpi(vport, ndlp);
 
 	return 0;
@@ -2418,6 +2521,10 @@
 	vport->fc_flag &= ~FC_DISC_TMO;
 	spin_unlock_irq(shost->host_lock);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+		"disc timeout:    state:x%x rtry:x%x flg:x%x",
+		vport->port_state, vport->fc_ns_retry, vport->fc_flag);
+
 	switch (vport->port_state) {
 
 	case LPFC_LOCAL_CFG_LINK:
@@ -2743,7 +2850,7 @@
 	spin_lock_irq(shost->host_lock);
 	ndlp = __lpfc_find_node(vport, lpfc_filter_by_wwpn, wwpn);
 	spin_unlock_irq(shost->host_lock);
-	return NULL;
+	return ndlp;
 }
 
 void
@@ -2764,7 +2871,7 @@
 	}
 
 	evtp->evt_arg1  = ndlp;
-	evtp->evt       = LPFC_EVT_DEV_LOSS;
+	evtp->evt       = LPFC_EVT_DEV_LOSS_DELAY;
 	list_add_tail(&evtp->evt_listp, &phba->work_list);
 	if (phba->work_wait)
 		lpfc_worker_wake_up(phba);
@@ -2779,9 +2886,6 @@
 	memset(ndlp, 0, sizeof (struct lpfc_nodelist));
 	INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
 	INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp);
-	init_timer(&ndlp->nlp_initiator_tmr);
-	ndlp->nlp_initiator_tmr.function = lpfc_dev_loss_delay;
-	ndlp->nlp_initiator_tmr.data = (unsigned long)ndlp;
 	init_timer(&ndlp->nlp_delayfunc);
 	ndlp->nlp_delayfunc.function = lpfc_els_retry_delay;
 	ndlp->nlp_delayfunc.data = (unsigned long)ndlp;
@@ -2790,6 +2894,11 @@
 	ndlp->nlp_sid = NLP_NO_SID;
 	INIT_LIST_HEAD(&ndlp->nlp_listp);
 	kref_init(&ndlp->kref);
+
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
+		"node init:       did:x%x",
+		ndlp->nlp_DID, 0, 0);
+
 	return;
 }
 
@@ -2798,6 +2907,11 @@
 {
 	struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist,
 						  kref);
+
+	lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
+		"node release:    did:x%x flg:x%x type:x%x",
+		ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
+
 	lpfc_nlp_remove(ndlp->vport, ndlp);
 	mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool);
 }
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 7fab93d..c2fb59f 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1278,6 +1278,7 @@
 #define MBX_KILL_BOARD      0x24
 #define MBX_CONFIG_FARP     0x25
 #define MBX_BEACON          0x2A
+#define MBX_HEARTBEAT       0x31
 
 #define MBX_CONFIG_HBQ	    0x7C
 #define MBX_LOAD_AREA       0x81
@@ -1777,8 +1778,6 @@
 #define LMT_4Gb       0x040
 #define LMT_8Gb       0x080
 #define LMT_10Gb      0x100
-
-
 	uint32_t rsvd2;
 	uint32_t rsvd3;
 	uint32_t max_xri;
@@ -1787,7 +1786,10 @@
 	uint32_t avail_xri;
 	uint32_t avail_iocb;
 	uint32_t avail_rpi;
-	uint32_t default_rpi;
+	uint32_t max_vpi;
+	uint32_t rsvd4;
+	uint32_t rsvd5;
+	uint32_t avail_vpi;
 } READ_CONFIG_VAR;
 
 /* Structure for MB Command READ_RCONFIG (12) */
@@ -3171,3 +3173,16 @@
 	else
 		return 0;
 }
+
+/*
+ * Determine if an IOCB failed because of a link event or firmware reset.
+ */
+
+static inline int
+lpfc_error_lost_link(IOCB_t *iocbp)
+{
+	return (iocbp->ulpStatus == IOSTAT_LOCAL_REJECT &&
+		(iocbp->un.ulpWord[4] == IOERR_SLI_ABORTED ||
+		 iocbp->un.ulpWord[4] == IOERR_LINK_DOWN ||
+		 iocbp->un.ulpWord[4] == IOERR_SLI_DOWN));
+}
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 4dd0f1a..350522c 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -391,6 +391,9 @@
 	 */
 	timeout = phba->fc_ratov << 1;
 	mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
+	mod_timer(&phba->hb_tmofunc, jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+	phba->hb_outstanding = 0;
+	phba->last_completion_time = jiffies;
 
 	lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
 	pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -485,6 +488,119 @@
 	return 0;
 }
 
+/* HBA heart beat timeout handler */
+void
+lpfc_hb_timeout(unsigned long ptr)
+{
+	struct lpfc_hba *phba;
+	unsigned long iflag;
+
+	phba = (struct lpfc_hba *)ptr;
+	spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
+	if (!(phba->pport->work_port_events & WORKER_HB_TMO))
+		phba->pport->work_port_events |= WORKER_HB_TMO;
+	spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
+
+	if (phba->work_wait)
+		wake_up(phba->work_wait);
+	return;
+}
+
+static void
+lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
+{
+	unsigned long drvr_flag;
+
+	spin_lock_irqsave(&phba->hbalock, drvr_flag);
+	phba->hb_outstanding = 0;
+	spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
+
+	mempool_free(pmboxq, phba->mbox_mem_pool);
+	if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) &&
+		!(phba->link_state == LPFC_HBA_ERROR) &&
+		!(phba->pport->fc_flag & FC_UNLOADING))
+		mod_timer(&phba->hb_tmofunc,
+			jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+	return;
+}
+
+void
+lpfc_hb_timeout_handler(struct lpfc_hba *phba)
+{
+	LPFC_MBOXQ_t *pmboxq;
+	int retval;
+	struct lpfc_sli *psli = &phba->sli;
+
+	if ((phba->link_state == LPFC_HBA_ERROR) ||
+		(phba->pport->fc_flag & FC_UNLOADING) ||
+		(phba->pport->fc_flag & FC_OFFLINE_MODE))
+		return;
+
+	spin_lock_irq(&phba->pport->work_port_lock);
+	/* If the timer is already canceled do nothing */
+	if (!(phba->pport->work_port_events & WORKER_HB_TMO)) {
+		spin_unlock_irq(&phba->pport->work_port_lock);
+		return;
+	}
+
+	if (time_after(phba->last_completion_time + LPFC_HB_MBOX_INTERVAL * HZ,
+		jiffies)) {
+		spin_unlock_irq(&phba->pport->work_port_lock);
+		if (!phba->hb_outstanding)
+			mod_timer(&phba->hb_tmofunc,
+				jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+		else
+			mod_timer(&phba->hb_tmofunc,
+				jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
+		return;
+	}
+	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;
+		}
+
+		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_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,
+			"%d:0459 Adapter heartbeat failure, taking "
+			"this port offline.\n", phba->brd_no);
+
+		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_handle_eratt                                                 */
@@ -1190,9 +1306,6 @@
 	lpfc_can_disctmo(vport);
 	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
 		lpfc_nlp_put(ndlp);
-
-	INIT_LIST_HEAD(&vport->fc_nodes);
-
 	return;
 }
 
@@ -1238,6 +1351,8 @@
 		lpfc_stop_vport_timers(vport);
 	del_timer_sync(&phba->sli.mbox_tmo);
 	del_timer_sync(&phba->fabric_block_timer);
+	phba->hb_outstanding = 0;
+	del_timer_sync(&phba->hb_tmofunc);
 	return;
 }
 
@@ -1474,8 +1589,8 @@
 	struct lpfc_hba  *phba = vport->phba;
 
 	kfree(vport->vname);
-	lpfc_free_sysfs_attr(vport);
 
+	lpfc_debugfs_terminate(vport);
 	fc_remove_host(shost);
 	scsi_remove_host(shost);
 
@@ -1500,50 +1615,29 @@
 	return instance;
 }
 
-static void
-lpfc_remove_device(struct lpfc_vport *vport)
-{
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
-	lpfc_free_sysfs_attr(vport);
-
-	spin_lock_irq(shost->host_lock);
-	vport->fc_flag |= FC_UNLOADING;
-	spin_unlock_irq(shost->host_lock);
-
-	fc_remove_host(shost);
-	scsi_remove_host(shost);
-}
-
-void lpfc_scan_start(struct Scsi_Host *shost)
-{
-	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-	struct lpfc_hba   *phba = vport->phba;
-
-	if (lpfc_sli_hba_setup(phba))
-		goto error;
-
-	/*
-	 * hba setup may have changed the hba_queue_depth so we need to adjust
-	 * the value of can_queue.
-	 */
-	shost->can_queue = phba->cfg_hba_queue_depth - 10;
-	return;
-
-error:
-	lpfc_remove_device(vport);
-}
+/*
+ * Note: there is no scan_start function as adapter initialization
+ * will have asynchronously kicked off the link initialization.
+ */
 
 int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
+	int stat = 0;
 
+	spin_lock_irq(shost->host_lock);
+
+	if (vport->fc_flag & FC_UNLOADING) {
+		stat = 1;
+		goto finished;
+	}
 	if (time >= 30 * HZ) {
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
 				"%d:0461 Scanning longer than 30 "
 				"seconds.  Continuing initialization\n",
 				phba->brd_no);
+		stat = 1;
 		goto finished;
 	}
 	if (time >= 15 * HZ && phba->link_state <= LPFC_LINK_DOWN) {
@@ -1551,21 +1645,24 @@
 				"%d:0465 Link down longer than 15 "
 				"seconds.  Continuing initialization\n",
 				phba->brd_no);
+		stat = 1;
 		goto finished;
 	}
 
 	if (vport->port_state != LPFC_VPORT_READY)
-		return 0;
+		goto finished;
 	if (vport->num_disc_nodes || vport->fc_prli_sent)
-		return 0;
+		goto finished;
 	if (vport->fc_map_cnt == 0 && time < 2 * HZ)
-		return 0;
+		goto finished;
 	if ((phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) != 0)
-		return 0;
+		goto finished;
+
+	stat = 1;
 
 finished:
-	lpfc_host_attrib_init(shost);
-	return 1;
+	spin_unlock_irq(shost->host_lock);
+	return stat;
 }
 
 void lpfc_host_attrib_init(struct Scsi_Host *shost)
@@ -1656,7 +1753,12 @@
 	/* Initialize timers used by driver */
 	init_timer(&phba->fc_estabtmo);
 	phba->fc_estabtmo.function = lpfc_establish_link_tmo;
-	phba->fc_estabtmo.data = (unsigned long) phba;
+	phba->fc_estabtmo.data = (unsigned long)phba;
+
+	init_timer(&phba->hb_tmofunc);
+	phba->hb_tmofunc.function = lpfc_hb_timeout;
+	phba->hb_tmofunc.data = (unsigned long)phba;
+
 	psli = &phba->sli;
 	init_timer(&psli->mbox_tmo);
 	psli->mbox_tmo.function = lpfc_mbox_timeout;
@@ -1791,6 +1893,7 @@
 
 	shost = lpfc_shost_from_vport(vport);
 	phba->pport = vport;
+	lpfc_debugfs_initialize(vport);
 
 	pci_set_drvdata(pdev, shost);
 
@@ -1820,15 +1923,32 @@
 	if (lpfc_alloc_sysfs_attr(vport))
 		goto out_free_irq;
 
-	scsi_scan_host(shost);
+	if (lpfc_sli_hba_setup(phba))
+		goto out_remove_device;
+
+	/*
+	 * hba setup may have changed the hba_queue_depth so we need to adjust
+	 * the value of can_queue.
+	 */
+	shost->can_queue = phba->cfg_hba_queue_depth - 10;
+
+	lpfc_host_attrib_init(shost);
+
 	if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
 		spin_lock_irq(shost->host_lock);
 		lpfc_poll_start_timer(phba);
 		spin_unlock_irq(shost->host_lock);
 	}
 
+	scsi_scan_host(shost);
+
 	return 0;
 
+out_remove_device:
+	lpfc_free_sysfs_attr(vport);
+	spin_lock_irq(shost->host_lock);
+	vport->fc_flag |= FC_UNLOADING;
+	spin_unlock_irq(shost->host_lock);
 out_free_irq:
 	lpfc_stop_phba_timers(phba);
 	phba->pport->work_port_events = 0;
@@ -1865,6 +1985,8 @@
 	pci_disable_device(pdev);
 out:
 	pci_set_drvdata(pdev, NULL);
+	if (shost)
+		scsi_host_put(shost);
 	return error;
 }
 
@@ -1878,6 +2000,12 @@
 	list_for_each_entry(port_iterator, &phba->port_list, listentry)
 		port_iterator->load_flag |= FC_UNLOADING;
 
+	kfree(vport->vname);
+	lpfc_free_sysfs_attr(vport);
+
+	fc_remove_host(shost);
+	scsi_remove_host(shost);
+
 	/*
 	 * Bring down the SLI Layer. This step disable all interrupts,
 	 * clears the rings, discards all mailbox commands, and resets
@@ -1887,6 +2015,13 @@
 	lpfc_sli_brdrestart(phba);
 
 	lpfc_stop_phba_timers(phba);
+	spin_lock_irq(&phba->hbalock);
+	list_del_init(&vport->listentry);
+	spin_unlock_irq(&phba->hbalock);
+
+
+	lpfc_debugfs_terminate(vport);
+	lpfc_cleanup(vport);
 
 	kthread_stop(phba->worker_thread);
 
@@ -1894,9 +2029,8 @@
 	free_irq(phba->pcidev->irq, phba);
 	pci_disable_msi(phba->pcidev);
 
-	destroy_port(vport);
-
 	pci_set_drvdata(pdev, NULL);
+	scsi_host_put(shost);
 
 	/*
 	 * Call scsi_free before mem_free since scsi bufs are released to their
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 277eb61..8f42fbf 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -82,6 +82,22 @@
 }
 
 /**********************************************/
+/*  lpfc_heart_beat  Issue a HEART_BEAT       */
+/*                mailbox command             */
+/**********************************************/
+void
+lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+	mb->mbxCommand = MBX_HEARTBEAT;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+/**********************************************/
 /*  lpfc_read_la  Issue a READ LA             */
 /*                mailbox command             */
 /**********************************************/
@@ -676,7 +692,7 @@
 	if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
 		mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
 		mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */
-		if (phba->max_vpi && lpfc_npiv_enable &&
+		if (phba->max_vpi && phba->cfg_npiv_enable &&
 		    phba->vpd.sli3Feat.cmv) {
 			mb->un.varCfgPort.max_vpi = phba->max_vpi;
 			mb->un.varCfgPort.cmv = 1;
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 6598e89..3594c46 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -88,7 +88,8 @@
 	if (!phba->lpfc_hbq_pool)
 		goto fail_free_nlp_mem_pool;
 
-	longs = (phba->max_vpi + BITS_PER_LONG - 1) / BITS_PER_LONG;
+	/* vpi zero is reserved for the physical port so add 1 to max */
+	longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG;
 	phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
 	if (!phba->vpi_bmask)
 		goto fail_free_hbq_pool;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 50a2476..bca2f5c 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -36,6 +36,7 @@
 #include "lpfc_logmsg.h"
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
 
 
 /* Called to verify a rcv'ed ADISC was intended for us. */
@@ -204,11 +205,9 @@
 	/* First check the txq */
 	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
-		/* Check to see if iocb matches the nport we are looking
-		   for */
+		/* Check to see if iocb matches the nport we are looking for */
 		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
-			/* It matches, so deque and call compl with an
-			   error */
+			/* It matches, so deque and call compl with anp error */
 			list_move_tail(&iocb->list, &completions);
 			pring->txq_cnt--;
 		}
@@ -216,8 +215,7 @@
 
 	/* Next check the txcmplq */
 	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
-		/* Check to see if iocb matches the nport we are looking
-		   for */
+		/* Check to see if iocb matches the nport we are looking for */
 		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
 			lpfc_sli_issue_abort_iotag(phba, pring, iocb);
 		}
@@ -282,7 +280,7 @@
 			stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
 			stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
 			lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
-					    ndlp);
+					    ndlp, NULL);
 			return 0;
 		}
 	}
@@ -293,7 +291,8 @@
 		/* Reject this request because invalid parameters */
 		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 		stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
-		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+			NULL);
 		return 0;
 	}
 	icmd = &cmdiocb->iocb;
@@ -392,13 +391,30 @@
 		lpfc_els_abort(phba, ndlp);
 	}
 
+	if ((vport->port_type == LPFC_NPIV_PORT &&
+	      phba->cfg_vport_restrict_login)) {
+
+		/* In order to preserve RPIs, we want to cleanup
+		 * the default RPI the firmware created to rcv
+		 * this ELS request. The only way to do this is
+		 * to register, then unregister the RPI.
+		 */
+		spin_lock_irq(shost->host_lock);
+		ndlp->nlp_flag |= NLP_RM_DFLT_RPI;
+		spin_unlock_irq(shost->host_lock);
+		stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
+		stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
+			ndlp, mbox);
+		return 1;
+	}
 	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
 	return 1;
 
 out:
 	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 	stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
-	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
 	return 0;
 }
 
@@ -445,7 +461,7 @@
 	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 	stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
 	stat.un.b.vendorUnique = 0;
-	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
 
 	/* 1 sec timeout */
 	mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
@@ -535,6 +551,11 @@
 			roles |= FC_RPORT_ROLE_FCP_INITIATOR;
 		if (ndlp->nlp_type & NLP_FCP_TARGET)
 			roles |= FC_RPORT_ROLE_FCP_TARGET;
+
+		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+			"rport rolechg:   role:x%x did:x%x flg:x%x",
+			roles, ndlp->nlp_DID, ndlp->nlp_flag);
+
 		fc_remote_port_rolechg(rport, roles);
 	}
 }
@@ -657,7 +678,8 @@
 		   ours */
 		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 		stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS;
-		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+			NULL);
 	} else {
 		lpfc_rcv_plogi(vport, ndlp, cmdiocb);
 	} /* If our portname was less */
@@ -675,7 +697,7 @@
 	memset(&stat, 0, sizeof (struct ls_rjt));
 	stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
 	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
-	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
 	return ndlp->nlp_state;
 }
 
@@ -1335,6 +1357,10 @@
 
 	irsp = &rspiocb->iocb;
 	if (irsp->ulpStatus) {
+		if ((vport->port_type == LPFC_NPIV_PORT) &&
+			phba->cfg_vport_restrict_login) {
+			goto out;
+		}
 		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
 		return ndlp->nlp_state;
@@ -1355,6 +1381,7 @@
 	if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
 	    (vport->port_type == LPFC_NPIV_PORT) &&
 	     phba->cfg_vport_restrict_login) {
+out:
 		spin_lock_irq(shost->host_lock);
 		ndlp->nlp_flag |= NLP_TARGET_REMOVE;
 		spin_unlock_irq(shost->host_lock);
@@ -1606,7 +1633,7 @@
 	struct lpfc_iocbq *cmdiocb  = (struct lpfc_iocbq *) arg;
 
 	/* Ignore PLOGI if we have an outstanding LOGO */
-	if (ndlp->nlp_flag & NLP_LOGO_SND) {
+	if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) {
 		return ndlp->nlp_state;
 	}
 
@@ -1638,7 +1665,7 @@
 	memset(&stat, 0, sizeof (struct ls_rjt));
 	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
 	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
-	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
+	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
 
 	if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
 		if (ndlp->nlp_flag & NLP_NPR_ADISC) {
@@ -2035,6 +2062,10 @@
 			phba->brd_no, vport->vpi,
 			evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
+		 "DSM in:          evt:%d ste:%d did:x%x",
+		evt, cur_state, ndlp->nlp_DID);
+
 	func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt];
 	rc = (func) (vport, ndlp, arg, evt);
 
@@ -2045,6 +2076,10 @@
 			phba->brd_no, vport->vpi,
 			rc, ndlp->nlp_DID, ndlp->nlp_flag);
 
+	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
+		 "DSM out:         ste:%d did:x%x flg:x%x",
+		rc, ndlp->nlp_DID, ndlp->nlp_flag);
+
 	lpfc_nlp_put(ndlp);
 
 	return rc;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index af8f896..2de4c4e 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1532,7 +1532,6 @@
 	.slave_configure	= lpfc_slave_configure,
 	.slave_destroy		= lpfc_slave_destroy,
 	.scan_finished		= lpfc_scan_finished,
-	.scan_start		= lpfc_scan_start,
 	.this_id		= -1,
 	.sg_tablesize		= LPFC_SG_SEG_CNT,
 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index a2927dc..f4d5a6b 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -38,6 +38,7 @@
 #include "lpfc_crtn.h"
 #include "lpfc_logmsg.h"
 #include "lpfc_compat.h"
+#include "lpfc_debugfs.h"
 
 /*
  * Define macro to log: Mailbox command x%x cannot issue Data
@@ -269,20 +270,11 @@
 static struct lpfc_iocbq *
 lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 {
-	struct list_head *dlp;
 	struct lpfc_iocbq *cmd_iocb;
 
-	dlp = &pring->txq;
-	cmd_iocb = NULL;
-	list_remove_head((&pring->txq), cmd_iocb,
-			 struct lpfc_iocbq,
-			 list);
-	if (cmd_iocb) {
-		/* If the first ptr is not equal to the list header,
-		 * deque the IOCBQ_t and return it.
-		 */
+	list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list);
+	if (cmd_iocb != NULL)
 		pring->txq_cnt--;
-	}
 	return cmd_iocb;
 }
 
@@ -736,6 +728,7 @@
 	case MBX_LOAD_EXP_ROM:
 	case MBX_REG_VPI:
 	case MBX_UNREG_VPI:
+	case MBX_HEARTBEAT:
 		ret = mbxCommand;
 		break;
 	default:
@@ -748,15 +741,18 @@
 lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
 {
 	wait_queue_head_t *pdone_q;
+	unsigned long drvr_flag;
 
 	/*
 	 * If pdone_q is empty, the driver thread gave up waiting and
 	 * continued running.
 	 */
 	pmboxq->mbox_flag |= LPFC_MBX_WAKE;
+	spin_lock_irqsave(&phba->hbalock, drvr_flag);
 	pdone_q = (wait_queue_head_t *) pmboxq->context1;
 	if (pdone_q)
 		wake_up_interruptible(pdone_q);
+	spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 	return;
 }
 
@@ -817,6 +813,25 @@
 
 		pmbox = &pmb->mb;
 
+		if (pmbox->mbxCommand != MBX_HEARTBEAT) {
+			if (pmb->vport) {
+				lpfc_debugfs_disc_trc(pmb->vport,
+					LPFC_DISC_TRC_MBOX_VPORT,
+					"MBOX cmpl vport: cmd:x%x mb:x%x x%x",
+					(uint32_t)pmbox->mbxCommand,
+					pmbox->un.varWords[0],
+					pmbox->un.varWords[1]);
+			}
+			else {
+				lpfc_debugfs_disc_trc(phba->pport,
+					LPFC_DISC_TRC_MBOX,
+					"MBOX cmpl:       cmd:x%x mb:x%x x%x",
+					(uint32_t)pmbox->mbxCommand,
+					pmbox->un.varWords[0],
+					pmbox->un.varWords[1]);
+			}
+		}
+
 		/*
 		 * It is a fatal error if unknown mbox command completion.
 		 */
@@ -1309,6 +1324,7 @@
 		 * network byte order and pci byte orders are different.
 		 */
 		entry = lpfc_resp_iocb(phba, pring);
+		phba->last_completion_time = jiffies;
 
 		if (++pring->rspidx >= portRspMax)
 			pring->rspidx = 0;
@@ -1511,6 +1527,7 @@
 		 */
 		entry = lpfc_resp_iocb(phba, pring);
 
+		phba->last_completion_time = jiffies;
 		rspiocbp = __lpfc_sli_get_iocbq(phba);
 		if (rspiocbp == NULL) {
 			printk(KERN_ERR "%s: out of buffers! Failing "
@@ -2304,7 +2321,7 @@
 
 	switch (lpfc_sli_mode) {
 	case 2:
-		if (lpfc_npiv_enable) {
+		if (phba->cfg_npiv_enable) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
 				"%d:1824 NPIV enabled: Override lpfc_sli_mode "
 				"parameter (%d) to auto (0).\n",
@@ -2573,6 +2590,21 @@
 		psli->slistat.mbox_busy++;
 		spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
 
+		if (pmbox->vport) {
+			lpfc_debugfs_disc_trc(pmbox->vport,
+				LPFC_DISC_TRC_MBOX_VPORT,
+				"MBOX Bsy vport:  cmd:x%x mb:x%x x%x",
+				(uint32_t)mb->mbxCommand,
+				mb->un.varWords[0], mb->un.varWords[1]);
+		}
+		else {
+			lpfc_debugfs_disc_trc(phba->pport,
+				LPFC_DISC_TRC_MBOX,
+				"MBOX Bsy:        cmd:x%x mb:x%x x%x",
+				(uint32_t)mb->mbxCommand,
+				mb->un.varWords[0], mb->un.varWords[1]);
+		}
+
 		return MBX_BUSY;
 	}
 
@@ -2618,6 +2650,23 @@
 			mb->mbxCommand, phba->pport->port_state,
 			psli->sli_flag, flag);
 
+	if (mb->mbxCommand != MBX_HEARTBEAT) {
+		if (pmbox->vport) {
+			lpfc_debugfs_disc_trc(pmbox->vport,
+				LPFC_DISC_TRC_MBOX_VPORT,
+				"MBOX Send vport: cmd:x%x mb:x%x x%x",
+				(uint32_t)mb->mbxCommand,
+				mb->un.varWords[0], mb->un.varWords[1]);
+		}
+		else {
+			lpfc_debugfs_disc_trc(phba->pport,
+				LPFC_DISC_TRC_MBOX,
+				"MBOX Send:       cmd:x%x mb:x%x x%x",
+				(uint32_t)mb->mbxCommand,
+				mb->un.varWords[0], mb->un.varWords[1]);
+		}
+	}
+
 	psli->slistat.mbox_cmd++;
 	evtctr = psli->slistat.mbox_event;
 
@@ -2760,14 +2809,13 @@
 /*
  * Caller needs to hold lock.
  */
-static int
+static void
 __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		    struct lpfc_iocbq *piocb)
 {
 	/* Insert the caller's iocb in the txq tail for later processing. */
 	list_add_tail(&piocb->list, &pring->txq);
 	pring->txq_cnt++;
-	return 0;
 }
 
 static struct lpfc_iocbq *
@@ -3074,11 +3122,11 @@
 int
 lpfc_sli_host_down(struct lpfc_vport *vport)
 {
+	LIST_HEAD(completions);
 	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
 	struct lpfc_iocbq *iocb, *next_iocb;
-	IOCB_t *icmd = NULL;
 	int i;
 	unsigned long flags = 0;
 	uint16_t prev_pring_flag;
@@ -3086,31 +3134,20 @@
 	lpfc_cleanup_discovery_resources(vport);
 
 	spin_lock_irqsave(&phba->hbalock, flags);
-
 	for (i = 0; i < psli->num_rings; i++) {
 		pring = &psli->ring[i];
 		prev_pring_flag = pring->flag;
-		pring->flag |= LPFC_DEFERRED_RING_EVENT;
-
+		if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */
+			pring->flag |= LPFC_DEFERRED_RING_EVENT;
 		/*
 		 * Error everything on the txq since these iocbs have not been
 		 * given to the FW yet.
 		 */
-
 		list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
 			if (iocb->vport != vport)
 				continue;
-			list_del_init(&iocb->list);
+			list_move_tail(&iocb->list, &completions);
 			pring->txq_cnt--;
-			if (iocb->iocb_cmpl) {
-				icmd = &iocb->iocb;
-				icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
-				icmd->un.ulpWord[4] = IOERR_SLI_DOWN;
-				spin_unlock_irqrestore(&phba->hbalock, flags);
-				(iocb->iocb_cmpl) (phba, iocb, iocb);
-				spin_lock_irqsave(&phba->hbalock, flags);
-			} else
-				lpfc_sli_release_iocbq(phba, iocb);
 		}
 
 		/* Next issue ABTS for everything on the txcmplq */
@@ -3126,6 +3163,17 @@
 
 	spin_unlock_irqrestore(&phba->hbalock, flags);
 
+	while (!list_empty(&completions)) {
+		list_remove_head(&completions, iocb, struct lpfc_iocbq, list);
+
+		if (!iocb->iocb_cmpl)
+			lpfc_sli_release_iocbq(phba, iocb);
+		else {
+			iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
+			iocb->iocb.un.ulpWord[4] = IOERR_SLI_DOWN;
+			(iocb->iocb_cmpl) (phba, iocb, iocb);
+		}
+	}
 	return 1;
 }
 
@@ -3148,7 +3196,8 @@
 	spin_lock_irqsave(&phba->hbalock, flags);
 	for (i = 0; i < psli->num_rings; i++) {
 		pring = &psli->ring[i];
-		pring->flag |= LPFC_DEFERRED_RING_EVENT;
+		if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */
+			pring->flag |= LPFC_DEFERRED_RING_EVENT;
 
 		/*
 		 * Error everything on the txq since these iocbs have not been
@@ -3326,8 +3375,10 @@
 			"x%x x%x x%x\n",
 			phba->brd_no, irsp->ulpIoTag, irsp->ulpStatus,
 			irsp->un.ulpWord[4], irsp->ulpTimeout);
-
-	lpfc_els_free_iocb(phba, cmdiocb);
+	if (cmdiocb->iocb.ulpCommand == CMD_GEN_REQUEST64_CR)
+		lpfc_ct_free_iocb(phba, cmdiocb);
+	else
+		lpfc_els_free_iocb(phba, cmdiocb);
 	return;
 }
 
@@ -3352,10 +3403,11 @@
 	    (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
 		return 0;
 
-	/* If we're unloading, don't abort the iocb, but change the callback so
-	 * that nothing happens when it finishes.
+	/* If we're unloading, don't abort iocb on the ELS ring, but change the
+	 * callback so that nothing happens when it finishes.
 	 */
-	if (vport->load_flag & FC_UNLOADING) {
+	if ((vport->load_flag & FC_UNLOADING) &&
+	    (pring->ringno == LPFC_ELS_RING)) {
 		if (cmdiocb->iocb_flag & LPFC_IO_FABRIC)
 			cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
 		else
@@ -3540,9 +3592,9 @@
 		       &rspiocbq->iocb, sizeof(IOCB_t));
 
 	pdone_q = cmdiocbq->context_un.wait_queue;
-	spin_unlock_irqrestore(&phba->hbalock, iflags);
 	if (pdone_q)
 		wake_up(pdone_q);
+	spin_unlock_irqrestore(&phba->hbalock, iflags);
 	return;
 }
 
@@ -3638,6 +3690,7 @@
 {
 	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
 	int retval;
+	unsigned long flag;
 
 	/* The caller must leave context1 empty. */
 	if (pmboxq->context1 != 0)
@@ -3656,6 +3709,7 @@
 				pmboxq->mbox_flag & LPFC_MBX_WAKE,
 				timeout * HZ);
 
+		spin_lock_irqsave(&phba->hbalock, flag);
 		pmboxq->context1 = NULL;
 		/*
 		 * if LPFC_MBX_WAKE flag is set the mailbox is completed
@@ -3663,8 +3717,11 @@
 		 */
 		if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
 			retval = MBX_SUCCESS;
-		else
+		else {
 			retval = MBX_TIMEOUT;
+			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+		}
+		spin_unlock_irqrestore(&phba->hbalock, flag);
 	}
 
 	return retval;
@@ -3712,6 +3769,9 @@
 	uint32_t control;
 
 	MAILBOX_t *mbox, *pmbox;
+	struct lpfc_vport *vport;
+	struct lpfc_nodelist *ndlp;
+	struct lpfc_dmabuf *mp;
 	LPFC_MBOXQ_t *pmb;
 	int rc;
 
@@ -3780,18 +3840,23 @@
 		}
 
 		if (work_ha_copy & ~(HA_ERATT|HA_MBATT|HA_LATT)) {
-			for (i = 0; i < phba->sli.num_rings; i++) {
-				if (work_ha_copy & (HA_RXATT << (4*i))) {
-					/*
-					 * Turn off Slow Rings interrupts
-					 */
-					spin_lock(&phba->hbalock);
-					control = readl(phba->HCregaddr);
-					control &= ~(HC_R0INT_ENA << i);
+			/*
+			 * Turn off Slow Rings interrupts, LPFC_ELS_RING is
+			 * the only slow ring.
+			 */
+			status = (work_ha_copy &
+				(HA_RXMASK  << (4*LPFC_ELS_RING)));
+			status >>= (4*LPFC_ELS_RING);
+			if (status & HA_RXMASK) {
+				spin_lock(&phba->hbalock);
+				control = readl(phba->HCregaddr);
+				if (control & (HC_R0INT_ENA << LPFC_ELS_RING)) {
+					control &=
+					    ~(HC_R0INT_ENA << LPFC_ELS_RING);
 					writel(control, phba->HCregaddr);
 					readl(phba->HCregaddr); /* flush */
-					spin_unlock(&phba->hbalock);
 				}
+				spin_unlock(&phba->hbalock);
 			}
 		}
 
@@ -3819,6 +3884,7 @@
 			pmb = phba->sli.mbox_active;
 			pmbox = &pmb->mb;
 			mbox = &phba->slim2p->mbx;
+			vport = pmb->vport;
 
 			/* First check out the status word */
 			lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t));
@@ -3833,22 +3899,54 @@
 						"Interrupt mbxCommand x%x "
 						"mbxStatus x%x\n",
 						phba->brd_no,
-						(pmb->vport
-						 ? pmb->vport->vpi
-						 : 0),
+						(vport
+						 ? vport->vpi : 0),
 						pmbox->mbxCommand,
 						pmbox->mbxStatus);
 			}
+			phba->last_completion_time = jiffies;
 			del_timer_sync(&phba->sli.mbox_tmo);
 
-			spin_lock(&phba->pport->work_port_lock);
-			phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
-			spin_unlock(&phba->pport->work_port_lock);
 			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);
 		}
 		if ((work_ha_copy & HA_MBATT) &&
@@ -3858,7 +3956,7 @@
 			phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
 			pmb = lpfc_mbox_get(phba);
 			spin_unlock(&phba->hbalock);
-
+send_current_mbox:
 			/* Process next mailbox command if there is one */
 			if (pmb != NULL) {
 				rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
@@ -3891,7 +3989,7 @@
 	 */
 	status = (ha_copy & (HA_RXMASK  << (4*LPFC_FCP_RING)));
 	status >>= (4*LPFC_FCP_RING);
-	if (status & HA_RXATT)
+	if (status & HA_RXMASK)
 		lpfc_sli_handle_fast_ring_event(phba,
 						&phba->sli.ring[LPFC_FCP_RING],
 						status);
@@ -3904,7 +4002,7 @@
 		 */
 		status = (ha_copy & (HA_RXMASK  << (4*LPFC_EXTRA_RING)));
 		status >>= (4*LPFC_EXTRA_RING);
-		if (status & HA_RXATT) {
+		if (status & HA_RXMASK) {
 			lpfc_sli_handle_fast_ring_event(phba,
 					&phba->sli.ring[LPFC_EXTRA_RING],
 					status);
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 4c43a8f..76058505 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -73,7 +73,8 @@
 #define IOCB_ERROR          2
 #define IOCB_TIMEDOUT       3
 
-#define LPFC_MBX_WAKE	1
+#define LPFC_MBX_WAKE		1
+#define LPFC_MBX_IMED_UNREG	2
 
 typedef struct lpfcMboxq {
 	/* MBOXQs are used in single linked lists */
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 786125b..85797db 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -82,7 +82,8 @@
 	int  vpi;
 
 	spin_lock_irq(&phba->hbalock);
-	vpi = find_next_zero_bit(phba->vpi_bmask, phba->max_vpi, 1);
+	/* Start at bit 1 because vpi zero is reserved for the physical port */
+	vpi = find_next_zero_bit(phba->vpi_bmask, (phba->max_vpi + 1), 1);
 	if (vpi > phba->max_vpi)
 		vpi = 0;
 	else
@@ -131,7 +132,8 @@
 				mb->mbxCommand, mb->mbxStatus, rc);
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
-		mempool_free(pmb, phba->mbox_mem_pool);
+		if (rc != MBX_TIMEOUT)
+			mempool_free(pmb, phba->mbox_mem_pool);
 		return -EIO;
 	}
 
@@ -241,6 +243,8 @@
 	}
 
 	vport->vpi = vpi;
+	lpfc_debugfs_initialize(vport);
+
 	if (lpfc_vport_sparm(phba, vport)) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
 				"%d:1813 Create VPORT failed: vpi:%d "
@@ -306,8 +310,16 @@
 	 */
 	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
-		lpfc_set_disctmo(vport);
-		lpfc_initial_fdisc(vport);
+		if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
+			lpfc_set_disctmo(vport);
+			lpfc_initial_fdisc(vport);
+		} else {
+			lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
+			lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+					"%d (%d):0262 No NPIV Fabric "
+					"support\n",
+					phba->brd_no, vport->vpi);
+		}
 	} else {
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 	}
@@ -383,8 +395,16 @@
 	 */
 	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
-		lpfc_set_disctmo(vport);
-		lpfc_initial_fdisc(vport);
+		if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
+			lpfc_set_disctmo(vport);
+			lpfc_initial_fdisc(vport);
+		} else {
+			lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
+			lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+					"%d (%d):0264 No NPIV Fabric "
+					"support\n",
+					phba->brd_no, vport->vpi);
+		}
 	} else {
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 	}
@@ -441,6 +461,7 @@
 	vport->load_flag |= FC_UNLOADING;
 
 	kfree(vport->vname);
+	lpfc_debugfs_terminate(vport);
 	fc_remove_host(lpfc_shost_from_vport(vport));
 	scsi_remove_host(lpfc_shost_from_vport(vport));
 
@@ -476,12 +497,6 @@
 					     NLP_EVT_DEVICE_RM);
 	}
 
-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
-		/* free any ndlp's in unused state */
-		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
-			lpfc_drop_node(vport, ndlp);
-	}
-
 	lpfc_stop_vport_timers(vport);
 	lpfc_unreg_all_rpis(vport);
 	lpfc_unreg_default_rpis(vport);