Commit 4d9ab994 authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc 8.3.5: fix reset path, ELS ordering and discovery issues



This patch includes the following fixes:
- Fixed panic during HBA reset.
- Fixed FCoE event tag passed in resume_rpi.
- Fix out of order ELS commands
- Fixed discovery issues found during VLAN testing.
- Fix UNREG_VPI failure on extended link pull
- Fixed crash while processing unsolicited FC frames.
- Clear retry count in the delayed ELS handler
- Fixed discovery failure during quick link bounce.

Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 1796e722
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ struct hbq_dmabuf {
	struct lpfc_dmabuf dbuf;
	uint32_t size;
	uint32_t tag;
	struct lpfc_rcqe rcqe;
	struct lpfc_cq_event cq_event;
};

/* Priority bit.  Set value to exceed low water mark in lpfc_mem. */
@@ -551,6 +551,7 @@ struct lpfc_hba {
	uint8_t fc_linkspeed;	/* Link speed after last READ_LA */

	uint32_t fc_eventTag;	/* event tag for link attention */
	uint32_t link_events;

	/* These fields used to be binfo */
	uint32_t fc_pref_DID;	/* preferred D_ID */
+9 −2
Original line number Diff line number Diff line
@@ -3815,7 +3815,11 @@ lpfc_get_stats(struct Scsi_Host *shost)
	hs->invalid_crc_count -= lso->invalid_crc_count;
	hs->error_frames -= lso->error_frames;

	if (phba->fc_topology == TOPOLOGY_LOOP) {
	if (phba->hba_flag & HBA_FCOE_SUPPORT) {
		hs->lip_count = -1;
		hs->nos_count = (phba->link_events >> 1);
		hs->nos_count -= lso->link_events;
	} else if (phba->fc_topology == TOPOLOGY_LOOP) {
		hs->lip_count = (phba->fc_eventTag >> 1);
		hs->lip_count -= lso->link_events;
		hs->nos_count = -1;
@@ -3906,6 +3910,9 @@ lpfc_reset_stats(struct Scsi_Host *shost)
	lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord;
	lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
	lso->error_frames = pmb->un.varRdLnk.crcCnt;
	if (phba->hba_flag & HBA_FCOE_SUPPORT)
		lso->link_events = (phba->link_events >> 1);
	else
		lso->link_events = (phba->fc_eventTag >> 1);

	psli->stats_start = get_seconds();
+1 −1
Original line number Diff line number Diff line
@@ -235,7 +235,7 @@ void lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *);
int lpfc_sli_check_eratt(struct lpfc_hba *);
void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
				    struct lpfc_sli_ring *, uint32_t);
int lpfc_sli4_handle_received_buffer(struct lpfc_hba *);
void lpfc_sli4_handle_received_buffer(struct lpfc_hba *, struct hbq_dmabuf *);
void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
			struct lpfc_iocbq *, uint32_t);
+1 −0
Original line number Diff line number Diff line
@@ -2452,6 +2452,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
	 */
	del_timer_sync(&ndlp->nlp_delayfunc);
	retry = ndlp->nlp_retry;
	ndlp->nlp_retry = 0;

	switch (cmd) {
	case ELS_CMD_FLOGI:
+56 −11
Original line number Diff line number Diff line
@@ -525,8 +525,6 @@ lpfc_work_done(struct lpfc_hba *phba)
			spin_unlock_irq(&phba->hbalock);
			lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
		}
		if (phba->hba_flag & HBA_RECEIVE_BUFFER)
			lpfc_sli4_handle_received_buffer(phba);
	}

	vports = lpfc_create_vport_work_array(phba);
@@ -568,8 +566,9 @@ lpfc_work_done(struct lpfc_hba *phba)
	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 ((status & HA_RXMASK) ||
	    (pring->flag & LPFC_DEFERRED_RING_EVENT) ||
	    (phba->hba_flag & HBA_RECEIVE_BUFFER)) {
		if (pring->flag & LPFC_STOP_IOCB_EVENT) {
			pring->flag |= LPFC_DEFERRED_RING_EVENT;
			/* Set the lpfc data pending flag */
@@ -688,7 +687,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
			lpfc_unreg_rpi(vport, ndlp);

		/* Leave Fabric nodes alone on link down */
		if (!remove && ndlp->nlp_type & NLP_FABRIC)
		if ((phba->sli_rev < LPFC_SLI_REV4) &&
		    (!remove && ndlp->nlp_type & NLP_FABRIC))
			continue;
		rc = lpfc_disc_state_machine(vport, ndlp, NULL,
					     remove
@@ -1015,10 +1015,10 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
		mempool_free(mboxq, phba->mbox_mem_pool);
		return;
	}
	if (vport->port_state != LPFC_FLOGI) {
		spin_lock_irqsave(&phba->hbalock, flags);
	phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE);
	phba->hba_flag &= ~FCF_DISC_INPROGRESS;
	if (vport->port_state != LPFC_FLOGI) {
		spin_lock_irqsave(&phba->hbalock, flags);
		spin_unlock_irqrestore(&phba->hbalock, flags);
		lpfc_initial_flogi(vport);
	}
@@ -1199,6 +1199,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)

	/* If the FCF is not availabe do nothing. */
	if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) {
		phba->hba_flag &= ~FCF_DISC_INPROGRESS;
		spin_unlock_irqrestore(&phba->hbalock, flags);
		return;
	}
@@ -1216,15 +1217,23 @@ lpfc_register_fcf(struct lpfc_hba *phba)

	fcf_mbxq = mempool_alloc(phba->mbox_mem_pool,
		GFP_KERNEL);
	if (!fcf_mbxq)
	if (!fcf_mbxq) {
		spin_lock_irqsave(&phba->hbalock, flags);
		phba->hba_flag &= ~FCF_DISC_INPROGRESS;
		spin_unlock_irqrestore(&phba->hbalock, flags);
		return;
	}

	lpfc_reg_fcfi(phba, fcf_mbxq);
	fcf_mbxq->vport = phba->pport;
	fcf_mbxq->mbox_cmpl = lpfc_mbx_cmpl_reg_fcfi;
	rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT);
	if (rc == MBX_NOT_FINISHED)
	if (rc == MBX_NOT_FINISHED) {
		spin_lock_irqsave(&phba->hbalock, flags);
		phba->hba_flag &= ~FCF_DISC_INPROGRESS;
		spin_unlock_irqrestore(&phba->hbalock, flags);
		mempool_free(fcf_mbxq, phba->mbox_mem_pool);
	}

	return;
}
@@ -1253,6 +1262,20 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
			uint16_t *vlan_id)
{
	struct lpfc_fcf_conn_entry *conn_entry;
	int i, j, fcf_vlan_id = 0;

	/* Find the lowest VLAN id in the FCF record */
	for (i = 0; i < 512; i++) {
		if (new_fcf_record->vlan_bitmap[i]) {
			fcf_vlan_id = i * 8;
			j = 0;
			while (!((new_fcf_record->vlan_bitmap[i] >> j) & 1)) {
				j++;
				fcf_vlan_id++;
			}
			break;
		}
	}

	/* If FCF not available return 0 */
	if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) ||
@@ -1286,6 +1309,10 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
		if (*addr_mode & LPFC_FCF_FPMA)
			*addr_mode = LPFC_FCF_FPMA;

		/* If FCF record report a vlan id use that vlan id */
		if (fcf_vlan_id)
			*vlan_id = fcf_vlan_id;
		else
			*vlan_id = 0xFFFF;
		return 1;
	}
@@ -1384,8 +1411,15 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
			(*addr_mode & LPFC_FCF_FPMA))
				*addr_mode = LPFC_FCF_FPMA;

		/* If matching connect list has a vlan id, use it */
		if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID)
			*vlan_id = conn_entry->conn_rec.vlan_tag;
		/*
		 * If no vlan id is specified in connect list, use the vlan id
		 * in the FCF record
		 */
		else if (fcf_vlan_id)
			*vlan_id = fcf_vlan_id;
		else
			*vlan_id = 0xFFFF;

@@ -1423,6 +1457,12 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)

	if (phba->link_state >= LPFC_LINK_UP)
		lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST);
	else
		/*
		 * Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
		 * flag
		 */
		phba->hba_flag &= ~FCF_DISC_INPROGRESS;

	if (unreg_fcf) {
		spin_lock_irq(&phba->hbalock);
@@ -2085,6 +2125,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
	else
		phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;

	phba->link_events++;
	if (la->attType == AT_LINK_UP && (!la->mm)) {
		phba->fc_stat.LinkUp++;
		if (phba->link_flag & LS_LOOPBACK_MODE) {
@@ -4409,6 +4450,8 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
	if (lpfc_fcf_inuse(phba))
		return;

	/* At this point, all discovery is aborted */
	phba->pport->port_state = LPFC_VPORT_UNKNOWN;

	/* Unregister VPIs */
	vports = lpfc_create_vport_work_array(phba);
@@ -4512,8 +4555,10 @@ lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba,

	/* Free the current connect table */
	list_for_each_entry_safe(conn_entry, next_conn_entry,
		&phba->fcf_conn_rec_list, list)
		&phba->fcf_conn_rec_list, list) {
		list_del_init(&conn_entry->list);
		kfree(conn_entry);
	}

	conn_hdr = (struct lpfc_fcf_conn_hdr *) buff;
	record_count = conn_hdr->length * sizeof(uint32_t)/
Loading