[SCSI] lpfc 8.2.3 : Miscellaneous Small Fixes - part 1

Miscellaneous Small Fixes - part 1
- Fix typo kmzlloc -> kzalloc
- Fix discovery ndlp use after free panic
- Fix link event causing flood of 0108 messages
- Relieve some mbox congestion on link up with 100 vports
- Fix broken vport parameters
- Prevent lock recursion in logo_reglogin_issue
- Split uses of error variable in lpfc_pci_probe_one into retval and error
- Remove completion code related to dev_loss_tmo
- Remove unused LPFC_MAX_HBQ #define
- Don't compare pointers to 0 for sparse
- Make 2 functions static for sparse
- Fix default rpi cleanup code causing rogue ndlps to remain on the NPR list
- Remove annoying ELS messages when driver is unloaded
- Fix Cannot issue Register Fabric login problems on link up
- Remove LPFC_EVT_DEV_LOSS_DELAY
- Fix FC port swap test leads to device going offline
- Fix vport CT flags to only be set when accepted
- Add code to handle signals during vport_create
- Fix too many retries in FC-AL mode
- Pull lpfc_port_link_failure out of lpfc_linkdown_port

Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index b73612d..813eeca 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -109,9 +109,10 @@
 
 	/* fill in BDEs for command */
 	/* Allocate buffer for command payload */
-	if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
-	    ((pcmd->virt = lpfc_mbuf_alloc(phba,
-					   MEM_PRI, &(pcmd->phys))) == 0)) {
+	pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+	if (pcmd)
+		pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys);
+	if (!pcmd || !pcmd->virt) {
 		kfree(pcmd);
 
 		lpfc_sli_release_iocbq(phba, elsiocb);
@@ -126,7 +127,7 @@
 		if (prsp)
 			prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
 						     &prsp->phys);
-		if (prsp == 0 || prsp->virt == 0) {
+		if (!prsp || !prsp->virt) {
 			kfree(prsp);
 			lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
 			kfree(pcmd);
@@ -143,7 +144,7 @@
 	if (pbuflist)
 		pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
 						 &pbuflist->phys);
-	if (pbuflist == 0 || pbuflist->virt == 0) {
+	if (!pbuflist || !pbuflist->virt) {
 		lpfc_sli_release_iocbq(phba, elsiocb);
 		lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
 		lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
@@ -234,15 +235,20 @@
 	struct lpfc_nodelist *ndlp;
 	struct serv_parm *sp;
 	int rc;
+	int err = 0;
 
 	sp = &phba->fc_fabparam;
 	ndlp = lpfc_findnode_did(vport, Fabric_DID);
-	if (!ndlp)
+	if (!ndlp) {
+		err = 1;
 		goto fail;
+	}
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-	if (!mbox)
+	if (!mbox) {
+		err = 2;
 		goto fail;
+	}
 
 	vport->port_state = LPFC_FABRIC_CFG_LINK;
 	lpfc_config_link(phba, mbox);
@@ -250,24 +256,32 @@
 	mbox->vport = vport;
 
 	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-	if (rc == MBX_NOT_FINISHED)
+	if (rc == MBX_NOT_FINISHED) {
+		err = 3;
 		goto fail_free_mbox;
+	}
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-	if (!mbox)
+	if (!mbox) {
+		err = 4;
 		goto fail;
+	}
 	rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
 			    0);
-	if (rc)
+	if (rc) {
+		err = 5;
 		goto fail_free_mbox;
+	}
 
 	mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
 	mbox->vport = vport;
 	mbox->context2 = lpfc_nlp_get(ndlp);
 
 	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-	if (rc == MBX_NOT_FINISHED)
+	if (rc == MBX_NOT_FINISHED) {
+		err = 6;
 		goto fail_issue_reg_login;
+	}
 
 	return 0;
 
@@ -282,7 +296,7 @@
 fail:
 	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-		"0249 Cannot issue Register Fabric login\n");
+		"0249 Cannot issue Register Fabric login: Err %d\n", err);
 	return -ENXIO;
 }
 
@@ -684,6 +698,9 @@
 	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_nodelist *ndlp;
 
+	vport->port_state = LPFC_FLOGI;
+	lpfc_set_disctmo(vport);
+
 	/* First look for the Fabric ndlp */
 	ndlp = lpfc_findnode_did(vport, Fabric_DID);
 	if (!ndlp) {
@@ -694,6 +711,12 @@
 		lpfc_nlp_init(vport, ndlp, Fabric_DID);
 	} else {
 		lpfc_dequeue_node(vport, ndlp);
+
+		/* If we go thru this path, Fabric_DID ndlp is in the process
+		 * of being removed. We need to bump the reference count by 1
+		 * so it stays around all through this link up period.
+		 */
+		lpfc_nlp_get(ndlp);
 	}
 	if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
 		lpfc_nlp_put(ndlp);
@@ -932,6 +955,7 @@
 	struct lpfc_hba  *phba = vport->phba;
 	struct serv_parm *sp;
 	IOCB_t *icmd;
+	struct lpfc_nodelist *ndlp;
 	struct lpfc_iocbq *elsiocb;
 	struct lpfc_sli_ring *pring;
 	struct lpfc_sli *psli;
@@ -942,8 +966,11 @@
 	psli = &phba->sli;
 	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
 
+	ndlp = lpfc_findnode_did(vport, did);
+	/* If ndlp if not NULL, we will bump the reference count on it */
+
 	cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
-	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
+	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
 				     ELS_CMD_PLOGI);
 	if (!elsiocb)
 		return 1;
@@ -1412,6 +1439,13 @@
 	psli = &phba->sli;
 	pring = &psli->ring[LPFC_ELS_RING];
 
+	spin_lock_irq(shost->host_lock);
+	if (ndlp->nlp_flag & NLP_LOGO_SND) {
+		spin_unlock_irq(shost->host_lock);
+		return 0;
+	}
+	spin_unlock_irq(shost->host_lock);
+
 	cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
 				     ndlp->nlp_DID, ELS_CMD_LOGO);
@@ -1758,6 +1792,7 @@
 	uint32_t *elscmd;
 	struct ls_rjt stat;
 	int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
+	int logerr = 0;
 	uint32_t cmd = 0;
 	uint32_t did;
 
@@ -1814,6 +1849,7 @@
 			break;
 
 		case IOERR_NO_RESOURCES:
+			logerr = 1; /* HBA out of resources */
 			retry = 1;
 			if (cmdiocb->retry > 100)
 				delay = 100;
@@ -1842,6 +1878,7 @@
 
 	case IOSTAT_NPORT_BSY:
 	case IOSTAT_FABRIC_BSY:
+		logerr = 1; /* Fabric / Remote NPort out of resources */
 		retry = 1;
 		break;
 
@@ -1922,6 +1959,15 @@
 	if (did == FDMI_DID)
 		retry = 1;
 
+	if ((cmd == ELS_CMD_FLOGI) &&
+	    (phba->fc_topology != TOPOLOGY_LOOP)) {
+		/* FLOGI retry policy */
+		retry = 1;
+		maxretry = 48;
+		if (cmdiocb->retry >= 32)
+			delay = 1000;
+	}
+
 	if ((++cmdiocb->retry) >= maxretry) {
 		phba->fc_stat.elsRetryExceeded++;
 		retry = 0;
@@ -2005,11 +2051,20 @@
 		}
 	}
 	/* No retry ELS command <elsCmd> to remote NPORT <did> */
-	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+	if (logerr) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+			 "0137 No retry ELS command x%x to remote "
+			 "NPORT x%x: Out of Resources: Error:x%x/%x\n",
+			 cmd, did, irsp->ulpStatus,
+			 irsp->un.ulpWord[4]);
+	}
+	else {
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
 			 "0108 No retry ELS command x%x to remote "
 			 "NPORT x%x Retried:%d Error:x%x/%x\n",
 			 cmd, did, cmdiocb->retry, irsp->ulpStatus,
 			 irsp->un.ulpWord[4]);
+	}
 	return 0;
 }
 
@@ -2089,6 +2144,12 @@
 	kfree(mp);
 	mempool_free(pmb, phba->mbox_mem_pool);
 	lpfc_nlp_put(ndlp);
+
+	/* This is the end of the default RPI cleanup logic for this
+	 * ndlp. If no other discovery threads are using this ndlp.
+	 * we should free all resources associated with it.
+	 */
+	lpfc_nlp_not_used(ndlp);
 	return;
 }
 
@@ -2118,6 +2179,9 @@
 			}
 			mempool_free(mbox, phba->mbox_mem_pool);
 		}
+		if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
+			if (lpfc_nlp_not_used(ndlp))
+				ndlp = NULL;
 		goto out;
 	}
 
@@ -2153,15 +2217,22 @@
 			    != MBX_NOT_FINISHED) {
 				goto out;
 			}
-			lpfc_nlp_put(ndlp);
-			/* NOTE: we should have messages for unsuccessful
-			   reglogin */
+
+			/* ELS rsp: Cannot issue reg_login for <NPortid> */
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				"0138 ELS rsp: Cannot issue reg_login for x%x "
+				"Data: x%x x%x x%x\n",
+				ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+				ndlp->nlp_rpi);
+
+			if (lpfc_nlp_not_used(ndlp))
+				ndlp = NULL;
 		} else {
 			/* 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;
+				if (lpfc_nlp_not_used(ndlp))
+					ndlp = NULL;
 			}
 		}
 		mp = (struct lpfc_dmabuf *) mbox->context1;
@@ -2350,10 +2421,14 @@
 	/* If the node is in the UNUSED state, and we are sending
 	 * a reject, we are done with it.  Release driver reference
 	 * count here.  The outstanding els will release its reference on
-	 * completion and the node can be freed then.
+	 * completion, as long as the ndlp stays in the UNUSED list,
+	 * and the node can be freed then.
 	 */
-	if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+	if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) &&
+		!(ndlp->nlp_flag & NLP_DELAYED_RM)) {
+		ndlp->nlp_flag |= NLP_DELAYED_RM;
 		lpfc_nlp_put(ndlp);
+	}
 
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
@@ -3466,8 +3541,6 @@
 				}
 			}
 
-			vport->port_state = LPFC_FLOGI;
-			lpfc_set_disctmo(vport);
 			lpfc_initial_flogi(vport);
 			return 0;
 		}
@@ -3747,11 +3820,11 @@
 			goto dropit;
 
 		lpfc_nlp_init(vport, ndlp, did);
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 		newnode = 1;
 		if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
 			ndlp->nlp_type |= NLP_FABRIC;
 		}
-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
 	}
 
 	phba->fc_stat.elsRcvFrame++;
@@ -3791,8 +3864,8 @@
 
 		phba->fc_stat.elsRcvFLOGI++;
 		lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
-		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
+			lpfc_nlp_put(ndlp);
 		break;
 	case ELS_CMD_LOGO:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3821,8 +3894,8 @@
 	case ELS_CMD_RSCN:
 		phba->fc_stat.elsRcvRSCN++;
 		lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
-		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
+			lpfc_nlp_put(ndlp);
 		break;
 	case ELS_CMD_ADISC:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3893,8 +3966,8 @@
 
 		phba->fc_stat.elsRcvLIRR++;
 		lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
-		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
+			lpfc_nlp_put(ndlp);
 		break;
 	case ELS_CMD_RPS:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3903,8 +3976,8 @@
 
 		phba->fc_stat.elsRcvRPS++;
 		lpfc_els_rcv_rps(vport, elsiocb, ndlp);
-		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
+			lpfc_nlp_put(ndlp);
 		break;
 	case ELS_CMD_RPL:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3913,8 +3986,8 @@
 
 		phba->fc_stat.elsRcvRPL++;
 		lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
-		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
+			lpfc_nlp_put(ndlp);
 		break;
 	case ELS_CMD_RNID:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3923,8 +3996,8 @@
 
 		phba->fc_stat.elsRcvRNID++;
 		lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
-		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
+			lpfc_nlp_put(ndlp);
 		break;
 	default:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3938,8 +4011,8 @@
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
 				 "0115 Unknown ELS command x%x "
 				 "received from NPORT x%x\n", cmd, did);
-		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+		if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM)))
+			lpfc_nlp_put(ndlp);
 		break;
 	}
 
@@ -3955,10 +4028,11 @@
 	return;
 
 dropit:
-	lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+	if (vport && !(vport->load_flag & FC_UNLOADING))
+		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
 			"(%d):0111 Dropping received ELS cmd "
 			"Data: x%x x%x x%x\n",
-			vport ? vport->vpi : 0xffff, icmd->ulpStatus,
+			vport->vpi, icmd->ulpStatus,
 			icmd->un.ulpWord[4], icmd->ulpTimeout);
 	phba->fc_stat.elsRcvDrop++;
 }