Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[SCSI] lpfc 8.3.44: Fix kernel panics from corrupted ndlp list

parent 0976e1a6
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -730,6 +730,7 @@ struct lpfc_hba {
	uint32_t cfg_request_firmware_upgrade;
	uint32_t cfg_request_firmware_upgrade;
	uint32_t cfg_iocb_cnt;
	uint32_t cfg_iocb_cnt;
	uint32_t cfg_suppress_link_up;
	uint32_t cfg_suppress_link_up;
	uint32_t cfg_rrq_xri_bitmap_sz;
#define LPFC_INITIALIZE_LINK              0	/* do normal init_link mbox */
#define LPFC_INITIALIZE_LINK              0	/* do normal init_link mbox */
#define LPFC_DELAY_INIT_LINK              1	/* layered driver hold off */
#define LPFC_DELAY_INIT_LINK              1	/* layered driver hold off */
#define LPFC_DELAY_INIT_LINK_INDEFINITELY 2	/* wait, manual intervention */
#define LPFC_DELAY_INIT_LINK_INDEFINITELY 2	/* wait, manual intervention */
@@ -835,6 +836,7 @@ struct lpfc_hba {
	mempool_t *mbox_mem_pool;
	mempool_t *mbox_mem_pool;
	mempool_t *nlp_mem_pool;
	mempool_t *nlp_mem_pool;
	mempool_t *rrq_pool;
	mempool_t *rrq_pool;
	mempool_t *active_rrq_pool;


	struct fc_host_statistics link_stats;
	struct fc_host_statistics link_stats;
	enum intr_type_t intr_type;
	enum intr_type_t intr_type;
+1 −0
Original line number Original line Diff line number Diff line
@@ -242,6 +242,7 @@ int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t);
void lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *);
void lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *);


int lpfc_mem_alloc(struct lpfc_hba *, int align);
int lpfc_mem_alloc(struct lpfc_hba *, int align);
int lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
void lpfc_mem_free_all(struct lpfc_hba *);
void lpfc_mem_free_all(struct lpfc_hba *);
void lpfc_stop_vport_timers(struct lpfc_vport *);
void lpfc_stop_vport_timers(struct lpfc_vport *);
+1 −1
Original line number Original line Diff line number Diff line
@@ -116,7 +116,7 @@ struct lpfc_nodelist {
	atomic_t cmd_pending;
	atomic_t cmd_pending;
	uint32_t cmd_qdepth;
	uint32_t cmd_qdepth;
	unsigned long last_change_time;
	unsigned long last_change_time;
	struct lpfc_node_rrqs active_rrqs;
	unsigned long *active_rrqs_xri_bitmap;
	struct lpfc_scsicmd_bkt *lat_data;	/* Latency data */
	struct lpfc_scsicmd_bkt *lat_data;	/* Latency data */
};
};
struct lpfc_node_rrq {
struct lpfc_node_rrq {
+55 −25
Original line number Original line Diff line number Diff line
@@ -1516,7 +1516,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
	uint32_t rc, keepDID = 0;
	uint32_t rc, keepDID = 0;
	int  put_node;
	int  put_node;
	int  put_rport;
	int  put_rport;
	struct lpfc_node_rrqs rrq;
	unsigned long *active_rrqs_xri_bitmap = NULL;


	/* Fabric nodes can have the same WWPN so we don't bother searching
	/* Fabric nodes can have the same WWPN so we don't bother searching
	 * by WWPN.  Just return the ndlp that was given to us.
	 * by WWPN.  Just return the ndlp that was given to us.
@@ -1534,7 +1534,13 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,


	if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp))
	if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp))
		return ndlp;
		return ndlp;
	memset(&rrq.xri_bitmap, 0, sizeof(new_ndlp->active_rrqs.xri_bitmap));
	if (phba->sli_rev == LPFC_SLI_REV4) {
		active_rrqs_xri_bitmap = mempool_alloc(phba->active_rrq_pool,
						       GFP_KERNEL);
		if (active_rrqs_xri_bitmap)
			memset(active_rrqs_xri_bitmap, 0,
			       phba->cfg_rrq_xri_bitmap_sz);
	}


	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
		 "3178 PLOGI confirm: ndlp %p x%x: new_ndlp %p\n",
		 "3178 PLOGI confirm: ndlp %p x%x: new_ndlp %p\n",
@@ -1543,41 +1549,58 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
	if (!new_ndlp) {
	if (!new_ndlp) {
		rc = memcmp(&ndlp->nlp_portname, name,
		rc = memcmp(&ndlp->nlp_portname, name,
			    sizeof(struct lpfc_name));
			    sizeof(struct lpfc_name));
		if (!rc)
		if (!rc) {
			if (active_rrqs_xri_bitmap)
				mempool_free(active_rrqs_xri_bitmap,
					     phba->active_rrq_pool);
			return ndlp;
			return ndlp;
		}
		new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
		new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
		if (!new_ndlp)
		if (!new_ndlp) {
			if (active_rrqs_xri_bitmap)
				mempool_free(active_rrqs_xri_bitmap,
					     phba->active_rrq_pool);
			return ndlp;
			return ndlp;
		}
		lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
		lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
	} else if (!NLP_CHK_NODE_ACT(new_ndlp)) {
	} else if (!NLP_CHK_NODE_ACT(new_ndlp)) {
		rc = memcmp(&ndlp->nlp_portname, name,
		rc = memcmp(&ndlp->nlp_portname, name,
			    sizeof(struct lpfc_name));
			    sizeof(struct lpfc_name));
		if (!rc)
		if (!rc) {
			if (active_rrqs_xri_bitmap)
				mempool_free(active_rrqs_xri_bitmap,
					     phba->active_rrq_pool);
			return ndlp;
			return ndlp;
		}
		new_ndlp = lpfc_enable_node(vport, new_ndlp,
		new_ndlp = lpfc_enable_node(vport, new_ndlp,
						NLP_STE_UNUSED_NODE);
						NLP_STE_UNUSED_NODE);
		if (!new_ndlp)
		if (!new_ndlp) {
			if (active_rrqs_xri_bitmap)
				mempool_free(active_rrqs_xri_bitmap,
					     phba->active_rrq_pool);
			return ndlp;
			return ndlp;
		}
		keepDID = new_ndlp->nlp_DID;
		keepDID = new_ndlp->nlp_DID;
		if (phba->sli_rev == LPFC_SLI_REV4)
		if ((phba->sli_rev == LPFC_SLI_REV4) && active_rrqs_xri_bitmap)
			memcpy(&rrq.xri_bitmap,
			memcpy(active_rrqs_xri_bitmap,
				&new_ndlp->active_rrqs.xri_bitmap,
			       new_ndlp->active_rrqs_xri_bitmap,
				sizeof(new_ndlp->active_rrqs.xri_bitmap));
			       phba->cfg_rrq_xri_bitmap_sz);
	} else {
	} else {
		keepDID = new_ndlp->nlp_DID;
		keepDID = new_ndlp->nlp_DID;
		if (phba->sli_rev == LPFC_SLI_REV4)
		if (phba->sli_rev == LPFC_SLI_REV4 &&
			memcpy(&rrq.xri_bitmap,
		    active_rrqs_xri_bitmap)
				&new_ndlp->active_rrqs.xri_bitmap,
			memcpy(active_rrqs_xri_bitmap,
				sizeof(new_ndlp->active_rrqs.xri_bitmap));
			       new_ndlp->active_rrqs_xri_bitmap,
			       phba->cfg_rrq_xri_bitmap_sz);
	}
	}


	lpfc_unreg_rpi(vport, new_ndlp);
	lpfc_unreg_rpi(vport, new_ndlp);
	new_ndlp->nlp_DID = ndlp->nlp_DID;
	new_ndlp->nlp_DID = ndlp->nlp_DID;
	new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
	new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
	if (phba->sli_rev == LPFC_SLI_REV4)
	if (phba->sli_rev == LPFC_SLI_REV4)
		memcpy(new_ndlp->active_rrqs.xri_bitmap,
		memcpy(new_ndlp->active_rrqs_xri_bitmap,
			&ndlp->active_rrqs.xri_bitmap,
		       ndlp->active_rrqs_xri_bitmap,
			sizeof(ndlp->active_rrqs.xri_bitmap));
		       phba->cfg_rrq_xri_bitmap_sz);


	if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
	if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
		new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
		new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
@@ -1619,10 +1642,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,


		/* Two ndlps cannot have the same did on the nodelist */
		/* Two ndlps cannot have the same did on the nodelist */
		ndlp->nlp_DID = keepDID;
		ndlp->nlp_DID = keepDID;
		if (phba->sli_rev == LPFC_SLI_REV4)
		if (phba->sli_rev == LPFC_SLI_REV4 &&
			memcpy(&ndlp->active_rrqs.xri_bitmap,
		    active_rrqs_xri_bitmap)
				&rrq.xri_bitmap,
			memcpy(ndlp->active_rrqs_xri_bitmap,
				sizeof(ndlp->active_rrqs.xri_bitmap));
			       active_rrqs_xri_bitmap,
			       phba->cfg_rrq_xri_bitmap_sz);
		lpfc_drop_node(vport, ndlp);
		lpfc_drop_node(vport, ndlp);
	}
	}
	else {
	else {
@@ -1634,10 +1658,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,


		/* Two ndlps cannot have the same did */
		/* Two ndlps cannot have the same did */
		ndlp->nlp_DID = keepDID;
		ndlp->nlp_DID = keepDID;
		if (phba->sli_rev == LPFC_SLI_REV4)
		if (phba->sli_rev == LPFC_SLI_REV4 &&
			memcpy(&ndlp->active_rrqs.xri_bitmap,
		    active_rrqs_xri_bitmap)
				&rrq.xri_bitmap,
			memcpy(ndlp->active_rrqs_xri_bitmap,
				sizeof(ndlp->active_rrqs.xri_bitmap));
			       active_rrqs_xri_bitmap,
			       phba->cfg_rrq_xri_bitmap_sz);


		/* Since we are swapping the ndlp passed in with the new one
		/* Since we are swapping the ndlp passed in with the new one
		 * and the did has already been swapped, copy over state.
		 * and the did has already been swapped, copy over state.
@@ -1668,6 +1693,10 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
				put_device(&rport->dev);
				put_device(&rport->dev);
		}
		}
	}
	}
	if (phba->sli_rev == LPFC_SLI_REV4 &&
	    active_rrqs_xri_bitmap)
		mempool_free(active_rrqs_xri_bitmap,
			     phba->active_rrq_pool);
	return new_ndlp;
	return new_ndlp;
}
}


@@ -2772,6 +2801,7 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
	/* This will cause the callback-function lpfc_cmpl_els_cmd to
	/* This will cause the callback-function lpfc_cmpl_els_cmd to
	 * trigger the release of node.
	 * trigger the release of node.
	 */
	 */

	lpfc_nlp_put(ndlp);
	lpfc_nlp_put(ndlp);
	return 0;
	return 0;
}
}
+18 −3
Original line number Original line Diff line number Diff line
@@ -4186,6 +4186,7 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	struct lpfc_hba *phba = vport->phba;
	struct lpfc_hba *phba = vport->phba;
	uint32_t did;
	uint32_t did;
	unsigned long flags;
	unsigned long flags;
	unsigned long *active_rrqs_xri_bitmap = NULL;


	if (!ndlp)
	if (!ndlp)
		return NULL;
		return NULL;
@@ -4214,12 +4215,17 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,


	/* Keep the original DID */
	/* Keep the original DID */
	did = ndlp->nlp_DID;
	did = ndlp->nlp_DID;
	if (phba->sli_rev == LPFC_SLI_REV4)
		active_rrqs_xri_bitmap = ndlp->active_rrqs_xri_bitmap;


	/* re-initialize ndlp except of ndlp linked list pointer */
	/* re-initialize ndlp except of ndlp linked list pointer */
	memset((((char *)ndlp) + sizeof (struct list_head)), 0,
	memset((((char *)ndlp) + sizeof (struct list_head)), 0,
		sizeof (struct lpfc_nodelist) - sizeof (struct list_head));
		sizeof (struct lpfc_nodelist) - sizeof (struct list_head));
	lpfc_initialize_node(vport, ndlp, did);
	lpfc_initialize_node(vport, ndlp, did);


	if (phba->sli_rev == LPFC_SLI_REV4)
		ndlp->active_rrqs_xri_bitmap = active_rrqs_xri_bitmap;

	spin_unlock_irqrestore(&phba->ndlp_lock, flags);
	spin_unlock_irqrestore(&phba->ndlp_lock, flags);
	if (vport->phba->sli_rev == LPFC_SLI_REV4)
	if (vport->phba->sli_rev == LPFC_SLI_REV4)
		ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba);
		ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba);
@@ -4805,9 +4811,10 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
				 ((uint32_t) ndlp->nlp_rpi & 0xff));
				 ((uint32_t) ndlp->nlp_rpi & 0xff));
			lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
			lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
					 "0929 FIND node DID "
					 "0929 FIND node DID "
					 "Data: x%p x%x x%x x%x\n",
					 "Data: x%p x%x x%x x%x %p\n",
					 ndlp, ndlp->nlp_DID,
					 ndlp, ndlp->nlp_DID,
					 ndlp->nlp_flag, data1);
					 ndlp->nlp_flag, data1,
					 ndlp->active_rrqs_xri_bitmap);
			return ndlp;
			return ndlp;
		}
		}
	}
	}
@@ -5624,8 +5631,13 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,


	lpfc_initialize_node(vport, ndlp, did);
	lpfc_initialize_node(vport, ndlp, did);
	INIT_LIST_HEAD(&ndlp->nlp_listp);
	INIT_LIST_HEAD(&ndlp->nlp_listp);
	if (vport->phba->sli_rev == LPFC_SLI_REV4)
	if (vport->phba->sli_rev == LPFC_SLI_REV4) {
		ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba);
		ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba);
		ndlp->active_rrqs_xri_bitmap =
				mempool_alloc(vport->phba->active_rrq_pool,
					      GFP_KERNEL);
	}





	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
@@ -5670,6 +5682,9 @@ lpfc_nlp_release(struct kref *kref)
	/* free ndlp memory for final ndlp release */
	/* free ndlp memory for final ndlp release */
	if (NLP_CHK_FREE_REQ(ndlp)) {
	if (NLP_CHK_FREE_REQ(ndlp)) {
		kfree(ndlp->lat_data);
		kfree(ndlp->lat_data);
		if (phba->sli_rev == LPFC_SLI_REV4)
			mempool_free(ndlp->active_rrqs_xri_bitmap,
				     ndlp->phba->active_rrq_pool);
		mempool_free(ndlp, ndlp->phba->nlp_mem_pool);
		mempool_free(ndlp, ndlp->phba->nlp_mem_pool);
	}
	}
}
}
Loading