]> err.no Git - linux-2.6/commitdiff
[SCSI] lpfc: bug fixes
authorJames Smart <James.Smart@Emulex.Com>
Mon, 18 Jun 2007 00:56:39 +0000 (19:56 -0500)
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>
Mon, 18 Jun 2007 03:38:11 +0000 (22:38 -0500)
 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>
19 files changed:
drivers/scsi/lpfc/Makefile
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_ct.c
drivers/scsi/lpfc/lpfc_debugfs.c [new file with mode: 0644]
drivers/scsi/lpfc/lpfc_debugfs.h [new file with mode: 0644]
drivers/scsi/lpfc/lpfc_disc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_hw.h
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_mem.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_vport.c

index d94c9e0212a739334e510a812a010902a7afd936..1c286707dd5f82ea4d9317e72164a393f39e192d 100644 (file)
@@ -28,4 +28,4 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o
 
 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
index 4b9019d7d508aae340b0bc69354921abe8f99cc2..f8f64d6485cdacbfdd88c4b86389c796deeeecb6 100644 (file)
@@ -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 @@ struct lpfc_sli2_slim;
 /* 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 @@ struct lpfc_vport {
 
        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 @@ struct lpfc_vport {
 #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 @@ struct lpfc_hba {
        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 @@ struct lpfc_hba {
        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 @@ struct lpfc_hba {
        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 *
index 5cb7924fe3d7d82a0eca71f11b43dbf180cf8473..6a2c1ac42442c69b69c68192da5b84fc8887d075 100644 (file)
@@ -282,9 +282,7 @@ lpfc_issue_lip(struct Scsi_Host *shost)
        }
 
        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 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
                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 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri,
                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 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri,
                *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 @@ lpfc_max_rpi_show(struct class_device *cdev, char *buf)
        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 @@ lpfc_used_rpi_show(struct class_device *cdev, char *buf)
        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 @@ lpfc_max_xri_show(struct class_device *cdev, char *buf)
        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 @@ lpfc_used_xri_show(struct class_device *cdev, char *buf)
        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 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
                 " 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 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
        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 @@ lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
        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 @@ lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
                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 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
        &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 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
 
                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 @@ lpfc_get_stats(struct Scsi_Host *shost)
                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 @@ lpfc_get_stats(struct Scsi_Host *shost)
                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 @@ lpfc_reset_stats(struct Scsi_Host *shost)
                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 @@ lpfc_reset_stats(struct Scsi_Host *shost)
                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_get_cfgparam(struct lpfc_hba *phba)
        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);
index 94e788199568e50b9a28dde52ab12435a20c5a83..e19d1a746586ecb624540e7f0844390ee9d98764 100644 (file)
@@ -23,6 +23,7 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
 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_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 
 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 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
 int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
                     struct serv_parm *, uint32_t);
 int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
+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_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
 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 @@ int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
 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_adisc(struct lpfc_vport *);
 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_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
 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 scsi_host_template lpfc_template;
 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 @@ void destroy_port(struct lpfc_vport *);
 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 *);
index 5584f395314c741ad9713e06750540afe7ab8923..ae9d6f385a6c11c6acc0369e7e70a4f3c196dd9e 100644 (file)
@@ -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 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
        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 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
                                    (!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 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
                                                        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 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
                                } 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 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        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 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        /* 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 @@ err1:
                                        (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 @@ err1:
                                        (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 @@ err1:
                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 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        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 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        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 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        }
                }
        }
+       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 @@ out:
                }
                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 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        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 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        }
 
 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 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
                      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 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
                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_mpvirt:
 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 @@ static void
 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 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        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_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                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 (file)
index 0000000..673cfe1
--- /dev/null
@@ -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 (file)
index 0000000..fffb678
--- /dev/null
@@ -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 */
index f23fe1e5fbb73df746c2cd57db5dbc012bd4a740..aacac9ac538190a6e42afd29562d737d8664ed1e 100644 (file)
@@ -36,6 +36,7 @@ enum lpfc_work_type {
        LPFC_EVT_WARM_START,
        LPFC_EVT_KILL,
        LPFC_EVT_ELS_RETRY,
+       LPFC_EVT_DEV_LOSS_DELAY,
        LPFC_EVT_DEV_LOSS,
 };
 
@@ -74,7 +75,6 @@ struct lpfc_nodelist {
 #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 @@ struct lpfc_nodelist {
                                           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 */
 
index f60c85d791c76950ab03d249934743e1d83da69c..33fbc166694678a2f5ed82f62575197e95eb32cd 100644 (file)
@@ -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 void lpfc_cmpl_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *,
 
 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 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                                        "%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 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
        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 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                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 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                /* 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 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
 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 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                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 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
        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 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        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 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                }
 
                /* 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 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
        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 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        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 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                }
                /* 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 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_rscn_disc(struct lpfc_vport *vport)
 {
        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 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        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 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                }
                /* 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 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        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 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        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 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
        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 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
        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 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
                       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 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        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 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        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 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        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 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        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 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                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 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        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 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 {
        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 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        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 @@ lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                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 @@ lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                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 @@ lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        /* 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 @@ lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 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 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                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 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                *((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 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                *((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 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
                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 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
 
 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 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
        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 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
                        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 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
        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 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
        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 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
                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 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
         * 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 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                          "%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 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
         * 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 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                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 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                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 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                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 @@ lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        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 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                        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 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                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 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
        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 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
                        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 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
                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 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
        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 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
                    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 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        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 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        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 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        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_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        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 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
        /* 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_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                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 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        "%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 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        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 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        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 @@ repeat:
                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 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
                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);
 
index 94ee9675b5b0c68c83dc2fdbd6343fc8e56506cc..f2f4639eab592466c6c2c919b9800b56b3c21c3f 100644 (file)
@@ -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 @@ lpfc_terminate_rport_io(struct fc_rport *rport)
 
        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 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
 {
        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 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                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 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                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 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
            (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 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
                if (put_rport)
                        put_device(&rport->dev);
        }
-       return;
 }
 
 
@@ -206,12 +265,17 @@ lpfc_work_list_done(struct lpfc_hba *phba)
                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_work_list_done(struct lpfc_hba *phba)
                        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 @@ lpfc_work_list_done(struct lpfc_hba *phba)
 
 }
 
-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 @@ lpfc_work_done(struct lpfc_hba *phba)
                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 @@ lpfc_work_done(struct lpfc_hba *phba)
        }
        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 @@ check_work_wait_done(struct lpfc_hba *phba)
 {
        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 @@ check_work_wait_done(struct lpfc_hba *phba)
                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 @@ lpfc_linkdown_port(struct lpfc_vport *vport)
 
        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 @@ lpfc_linkup_port(struct lpfc_vport *vport)
        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 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
                }
        } 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 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                                "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 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                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 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 
                        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 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
            ((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 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                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 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp)
 {
        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 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        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_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
                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 @@ lpfc_set_disctmo(struct lpfc_vport *vport)
                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 @@ lpfc_can_disctmo(struct lpfc_vport *vport)
        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 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 
        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 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
        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 @@ lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn)
        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 @@ lpfc_dev_loss_delay(unsigned long ptr)
        }
 
        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 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_nlp_release(struct kref *kref)
 {
        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);
 }
index 7fab93d34367187b08abd2c45aed5231659f818d..c2fb59f595f3ec58c699eaa133735e8450a89933 100644 (file)
@@ -1278,6 +1278,7 @@ typedef struct {          /* FireFly BIU registers */
 #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 @@ typedef struct {
 #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 @@ typedef struct {
        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 @@ lpfc_is_LC_HBA(unsigned short device)
        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));
+}
index 4dd0f1aa09e8c0a5bd876472ed8a8c7f99def936..350522cbf34383baecc0a5051a3a7ef3b8d4bb0a 100644 (file)
@@ -391,6 +391,9 @@ lpfc_config_port_post(struct lpfc_hba *phba)
         */
        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 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
        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_cleanup(struct lpfc_vport *vport)
        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_phba_timers(struct lpfc_hba *phba)
                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 @@ destroy_port(struct lpfc_vport *vport)
        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 @@ lpfc_get_instance(void)
        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 @@ int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
                                "%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 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        /* 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 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 
        shost = lpfc_shost_from_vport(vport);
        phba->pport = vport;
+       lpfc_debugfs_initialize(vport);
 
        pci_set_drvdata(pdev, shost);
 
@@ -1820,15 +1923,32 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
        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 @@ out_disable_device:
        pci_disable_device(pdev);
 out:
        pci_set_drvdata(pdev, NULL);
+       if (shost)
+               scsi_host_put(shost);
        return error;
 }
 
@@ -1878,6 +2000,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
        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_pci_remove_one(struct pci_dev *pdev)
        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 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
        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
index 277eb6132e8139f8a592318b30d447ee4f425d3d..8f42fbfdd29e5cb19f43d4a2a49d63bdb67cefd2 100644 (file)
@@ -81,6 +81,22 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
        return;
 }
 
+/**********************************************/
+/*  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 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        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;
index 6598e89627df541305a8fd8f1c03d2249c042a52..3594c469494face18a422e6811516cda4574d35a 100644 (file)
@@ -88,7 +88,8 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
        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;
index 50a247602a6bed8e1f40abedaabe2aaeb72cb06d..bca2f5c9b4baa9f7724800f7b7560972383a08cd 100644 (file)
@@ -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 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
        /* 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 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 
        /* 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 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        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 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                /* 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_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                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 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        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 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                   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 @@ lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
        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 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        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 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        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 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        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;
index af8f8968bfba9193b0fd4b2dc8cf49401f6f011c..2de4c4e1cd808b17097781b505dc6e7d373bef99 100644 (file)
@@ -1532,7 +1532,6 @@ struct scsi_host_template lpfc_template = {
        .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,
index a2927dc3161f3c23e46fa253296c810b0392a3a0..f4d5a6b00fde92c3234337c3576a410ad6124313 100644 (file)
@@ -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 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 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 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
        case MBX_LOAD_EXP_ROM:
        case MBX_REG_VPI:
        case MBX_UNREG_VPI:
+       case MBX_HEARTBEAT:
                ret = mbxCommand;
                break;
        default:
@@ -748,15 +741,18 @@ static void
 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 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
 
                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 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
                 * 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 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
                 */
                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 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba)
 
        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 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                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 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
                        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 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 /*
  * 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 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)
 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_sli_host_down(struct lpfc_vport *vport)
        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 @@ lpfc_sli_host_down(struct lpfc_vport *vport)
 
        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 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
        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 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        "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 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
            (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 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
                       &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 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
 {
        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 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
                                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 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
                 */
                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 @@ lpfc_intr_handler(int irq, void *dev_id)
        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 @@ lpfc_intr_handler(int irq, void *dev_id)
                }
 
                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 @@ lpfc_intr_handler(int irq, void *dev_id)
                        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 @@ lpfc_intr_handler(int irq, void *dev_id)
                                                "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 @@ send_next_mbox:
                        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 @@ send_next_mbox:
         */
        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 @@ send_next_mbox:
                 */
                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);
index 4c43a8fd699c9b1daac406bf356c50a349a2df58..76058505795ef55f87fb421b66385f726969d164 100644 (file)
@@ -73,7 +73,8 @@ struct lpfc_iocbq {
 #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 */
index 786125b7ad4c4df6be9d77b906ca9a2e9e2de857..85797dbf54789bbf7bad9959590547fa9131afb0 100644 (file)
@@ -82,7 +82,8 @@ lpfc_alloc_vpi(struct lpfc_hba *phba)
        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 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
                                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 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
        }
 
        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 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
         */
        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 @@ enable_vport(struct fc_vport *fc_vport)
         */
        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 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
        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 @@ skip_logo:
                                             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);