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

Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
James Smart 2013-12-17 20:29:47 -05:00 committed by James Bottomley
parent 0976e1a650
commit cff261f6bd
8 changed files with 110 additions and 32 deletions

View file

@ -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;

View file

@ -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 *);

View file

@ -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 {

View file

@ -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;
} }

View file

@ -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);
} }
} }

View file

@ -5059,6 +5059,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
/* Set up the hba's configuration parameters. */ /* Set up the hba's configuration parameters. */
rc = lpfc_sli4_read_config(phba); rc = lpfc_sli4_read_config(phba);
if (unlikely(rc))
goto out_free_bsmbx;
rc = lpfc_mem_alloc_active_rrq_pool_s4(phba);
if (unlikely(rc)) if (unlikely(rc))
goto out_free_bsmbx; goto out_free_bsmbx;

View file

@ -38,10 +38,28 @@
#include "lpfc_scsi.h" #include "lpfc_scsi.h"
#include "lpfc.h" #include "lpfc.h"
#include "lpfc_crtn.h" #include "lpfc_crtn.h"
#include "lpfc_logmsg.h"
#define LPFC_MBUF_POOL_SIZE 64 /* max elements in MBUF safety pool */ #define LPFC_MBUF_POOL_SIZE 64 /* max elements in MBUF safety pool */
#define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */ #define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */
int
lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *phba) {
size_t bytes;
int max_xri = phba->sli4_hba.max_cfg_param.max_xri;
if (max_xri <= 0)
return -ENOMEM;
bytes = ((BITS_PER_LONG - 1 + max_xri) / BITS_PER_LONG) *
sizeof(unsigned long);
phba->cfg_rrq_xri_bitmap_sz = bytes;
phba->active_rrq_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE,
bytes);
if (!phba->active_rrq_pool)
return -ENOMEM;
else
return 0;
}
/** /**
* lpfc_mem_alloc - create and allocate all PCI and memory pools * lpfc_mem_alloc - create and allocate all PCI and memory pools
@ -209,6 +227,10 @@ lpfc_mem_free(struct lpfc_hba *phba)
/* Free NLP memory pool */ /* Free NLP memory pool */
mempool_destroy(phba->nlp_mem_pool); mempool_destroy(phba->nlp_mem_pool);
phba->nlp_mem_pool = NULL; phba->nlp_mem_pool = NULL;
if (phba->sli_rev == LPFC_SLI_REV4 && phba->active_rrq_pool) {
mempool_destroy(phba->active_rrq_pool);
phba->active_rrq_pool = NULL;
}
/* Free mbox memory pool */ /* Free mbox memory pool */
mempool_destroy(phba->mbox_mem_pool); mempool_destroy(phba->mbox_mem_pool);

View file

@ -635,7 +635,7 @@ lpfc_clr_rrq_active(struct lpfc_hba *phba,
if (!ndlp) if (!ndlp)
goto out; goto out;
if (test_and_clear_bit(xritag, ndlp->active_rrqs.xri_bitmap)) { if (test_and_clear_bit(xritag, ndlp->active_rrqs_xri_bitmap)) {
rrq->send_rrq = 0; rrq->send_rrq = 0;
rrq->xritag = 0; rrq->xritag = 0;
rrq->rrq_stop_time = 0; rrq->rrq_stop_time = 0;
@ -813,7 +813,9 @@ lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
{ {
if (!ndlp) if (!ndlp)
return 0; return 0;
if (test_bit(xritag, ndlp->active_rrqs.xri_bitmap)) if (!ndlp->active_rrqs_xri_bitmap)
return 0;
if (test_bit(xritag, ndlp->active_rrqs_xri_bitmap))
return 1; return 1;
else else
return 0; return 0;
@ -863,7 +865,10 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING)) if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING))
goto out; goto out;
if (test_and_set_bit(xritag, ndlp->active_rrqs.xri_bitmap)) if (!ndlp->active_rrqs_xri_bitmap)
goto out;
if (test_and_set_bit(xritag, ndlp->active_rrqs_xri_bitmap))
goto out; goto out;
spin_unlock_irqrestore(&phba->hbalock, iflags); spin_unlock_irqrestore(&phba->hbalock, iflags);