[SCSI] lpfc: bug fixes

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

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

Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 5cb7924..6a2c1ac 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -282,9 +282,7 @@
 	}
 
 	lpfc_set_loopback_flag(phba);
-	if (mbxstatus == MBX_TIMEOUT)
-		pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-	else
+	if (mbxstatus != MBX_TIMEOUT)
 		mempool_free(pmboxq, phba->mbox_mem_pool);
 
 	if (mbxstatus == MBXERR_ERROR)
@@ -439,30 +437,11 @@
 		return -EIO;
 }
 
-static ssize_t
-lpfc_max_vpi_show(struct class_device *cdev, char *buf)
-{
-	struct Scsi_Host  *shost = class_to_shost(cdev);
-	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-	struct lpfc_hba   *phba = vport->phba;
-
-	return snprintf(buf, PAGE_SIZE, "%d\n", phba->max_vpi);
-}
-
-static ssize_t
-lpfc_used_vpi_show(struct class_device *cdev, char *buf)
-{
-	struct Scsi_Host  *shost = class_to_shost(cdev);
-	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-	struct lpfc_hba   *phba = vport->phba;
-
-	/* Don't count the physical port */
-	return snprintf(buf, PAGE_SIZE, "%d\n", phba->vpi_cnt-1);
-}
-
 int
-lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri,
-	uint32_t *axri, uint32_t *mrpi, uint32_t *arpi)
+lpfc_get_hba_info(struct lpfc_hba *phba,
+		  uint32_t *mxri, uint32_t *axri,
+		  uint32_t *mrpi, uint32_t *arpi,
+		  uint32_t *mvpi, uint32_t *avpi)
 {
 	struct lpfc_sli   *psli = &phba->sli;
 	LPFC_MBOXQ_t *pmboxq;
@@ -498,9 +477,7 @@
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
 
 	if (rc != MBX_SUCCESS) {
-		if (rc == MBX_TIMEOUT)
-			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		else
+		if (rc != MBX_TIMEOUT)
 			mempool_free(pmboxq, phba->mbox_mem_pool);
 		return 0;
 	}
@@ -513,6 +490,10 @@
 		*mxri = pmb->un.varRdConfig.max_xri;
 	if (axri)
 		*axri = pmb->un.varRdConfig.avail_xri;
+	if (mvpi)
+		*mvpi = pmb->un.varRdConfig.max_vpi;
+	if (avpi)
+		*avpi = pmb->un.varRdConfig.avail_vpi;
 
 	mempool_free(pmboxq, phba->mbox_mem_pool);
 	return 1;
@@ -526,7 +507,7 @@
 	struct lpfc_hba   *phba = vport->phba;
 	uint32_t cnt;
 
-	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL))
+	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL, NULL, NULL))
 		return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
 	return snprintf(buf, PAGE_SIZE, "Unknown\n");
 }
@@ -539,7 +520,7 @@
 	struct lpfc_hba   *phba = vport->phba;
 	uint32_t cnt, acnt;
 
-	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt))
+	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL))
 		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
 	return snprintf(buf, PAGE_SIZE, "Unknown\n");
 }
@@ -552,7 +533,7 @@
 	struct lpfc_hba   *phba = vport->phba;
 	uint32_t cnt;
 
-	if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL))
+	if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL, NULL, NULL))
 		return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
 	return snprintf(buf, PAGE_SIZE, "Unknown\n");
 }
@@ -565,7 +546,33 @@
 	struct lpfc_hba   *phba = vport->phba;
 	uint32_t cnt, acnt;
 
-	if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL))
+	if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL))
+		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+	return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_max_vpi_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host  *shost = class_to_shost(cdev);
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+	struct lpfc_hba   *phba = vport->phba;
+	uint32_t cnt;
+
+	if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, NULL))
+		return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
+	return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_used_vpi_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host  *shost = class_to_shost(cdev);
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+	struct lpfc_hba   *phba = vport->phba;
+	uint32_t cnt, acnt;
+
+	if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt))
 		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
 	return snprintf(buf, PAGE_SIZE, "Unknown\n");
 }
@@ -995,9 +1002,7 @@
 		 " 2 - select SLI-2 even on SLI-3 capable HBAs,"
 		 " 3 - select SLI-3");
 
-int  lpfc_npiv_enable = 0;
-module_param(lpfc_npiv_enable, int, 0);
-MODULE_PARM_DESC(lpfc_npiv_enable, "Enable NPIV functionality");
+LPFC_ATTR_R(npiv_enable, 0, 0, 1, "Enable NPIV functionality");
 
 /*
 # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -1052,6 +1057,24 @@
 	return -EINVAL;
 }
 
+static void
+lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *vport;
+	struct Scsi_Host  *shost;
+	struct lpfc_nodelist  *ndlp;
+
+	list_for_each_entry(vport, &phba->port_list, listentry) {
+		shost = lpfc_shost_from_vport(vport);
+		spin_lock_irq(shost->host_lock);
+		list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
+			if (ndlp->rport)
+				ndlp->rport->dev_loss_tmo =
+					phba->cfg_devloss_tmo;
+		spin_unlock_irq(shost->host_lock);
+	}
+}
+
 static int
 lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
 {
@@ -1067,6 +1090,7 @@
 	if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
 		phba->cfg_nodev_tmo = val;
 		phba->cfg_devloss_tmo = val;
+		lpfc_update_rport_devloss_tmo(phba);
 		return 0;
 	}
 
@@ -1102,6 +1126,7 @@
 		phba->cfg_nodev_tmo = val;
 		phba->cfg_devloss_tmo = val;
 		phba->dev_loss_tmo_changed = 1;
+		lpfc_update_rport_devloss_tmo(phba);
 		return 0;
 	}
 
@@ -1358,6 +1383,7 @@
 	&class_device_attr_lpfc_multi_ring_type,
 	&class_device_attr_lpfc_fdmi_on,
 	&class_device_attr_lpfc_max_luns,
+	&class_device_attr_lpfc_npiv_enable,
 	&class_device_attr_nport_evt_cnt,
 	&class_device_attr_management_version,
 	&class_device_attr_board_mode,
@@ -1641,8 +1667,6 @@
 
 		if (rc != MBX_SUCCESS) {
 			if (rc == MBX_TIMEOUT) {
-				phba->sysfs_mbox.mbox->mbox_cmpl =
-					lpfc_sli_def_mbox_cmpl;
 				phba->sysfs_mbox.mbox = NULL;
 			}
 			sysfs_mbox_idle(phba);
@@ -1886,9 +1910,7 @@
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
 
 	if (rc != MBX_SUCCESS) {
-		if (rc == MBX_TIMEOUT)
-			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		else
+		if (rc != MBX_TIMEOUT)
 			mempool_free(pmboxq, phba->mbox_mem_pool);
 		return NULL;
 	}
@@ -1913,9 +1935,7 @@
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
 
 	if (rc != MBX_SUCCESS) {
-		if (rc == MBX_TIMEOUT)
-			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		else
+		if (rc != MBX_TIMEOUT)
 			mempool_free(pmboxq, phba->mbox_mem_pool);
 		return NULL;
 	}
@@ -1993,9 +2013,7 @@
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
 
 	if (rc != MBX_SUCCESS) {
-		if (rc == MBX_TIMEOUT)
-			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		else
+		if (rc != MBX_TIMEOUT)
 			mempool_free(pmboxq, phba->mbox_mem_pool);
 		return;
 	}
@@ -2013,9 +2031,7 @@
 		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
 
 	if (rc != MBX_SUCCESS) {
-		if (rc == MBX_TIMEOUT)
-			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		else
+		if (rc != MBX_TIMEOUT)
 			mempool_free( pmboxq, phba->mbox_mem_pool);
 		return;
 	}
@@ -2253,6 +2269,7 @@
 	lpfc_max_luns_init(phba, lpfc_max_luns);
 	lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
 	lpfc_peer_port_login_init(phba, lpfc_peer_port_login);
+	lpfc_npiv_enable_init(phba, lpfc_npiv_enable);
 	lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login);
 	lpfc_use_msi_init(phba, lpfc_use_msi);
 	lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);