From: Vaios Papadimitriou Date: Tue, 8 May 2012 22:01:25 +0000 (-0500) Subject: Fix for driver using duplicate RPIs after LPe16000 port reset (CR 126723) X-Git-Tag: v2.6.39-400.9.0~423^2~123^2~18 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=51d0143f91e1410a6b78c899baecd7dabf5f09d3;p=users%2Fjedix%2Flinux-maple.git Fix for driver using duplicate RPIs after LPe16000 port reset (CR 126723) The RPI bit map is reinitiatized in the adapter port 'online' path. SLI4 RPI are designed to be 'long lived', so when the adapter port is taken offline, the driver will reuse the RPI if the port is recovered within devloss tmo. These stale RPI values can collide when new RPIs are allocated. We now free RPIs on all active nodes and then allocate new RPIs commit id: 6b5151fd7baec6812fece993ddd7a2cf9fd0125f Signed-off-by: Maxim Uvarov --- diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index e159489a1a007..63759d7ee5c32 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -462,3 +462,4 @@ int lpfc_issue_unreg_vfi(struct lpfc_vport *); int lpfc_selective_reset(struct lpfc_hba *); int lpfc_sli4_read_config(struct lpfc_hba *phba); int lpfc_scsi_buf_update(struct lpfc_hba *phba); +void lpfc_sli4_node_prep(struct lpfc_hba *phba); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5f41787b9c4f6..b1af6624b94f0 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2501,6 +2501,42 @@ lpfc_block_mgmt_io(struct lpfc_hba * phba) } } +/** + * lpfc_sli4_node_prep - Assign RPIs for active nodes. + * @phba: pointer to lpfc hba data structure. + * + * Allocate RPIs for all active remote nodes. This is needed whenever + * an SLI4 adapter is reset and the driver is not unloading. Its purpose + * is to fixup the temporary rpi assignments. + **/ +void +lpfc_sli4_node_prep(struct lpfc_hba *phba) +{ + struct lpfc_nodelist *ndlp, *next_ndlp; + struct lpfc_vport **vports; + int i; + + if (phba->sli_rev != LPFC_SLI_REV4) + return; + + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + if (vports[i]->load_flag & FC_UNLOADING) + continue; + + list_for_each_entry_safe(ndlp, next_ndlp, + &vports[i]->fc_nodes, + nlp_listp) { + if (NLP_CHK_NODE_ACT(ndlp)) + ndlp->nlp_rpi = + lpfc_sli4_alloc_rpi(phba); + } + } + } + lpfc_destroy_vport_work_array(phba, vports); +} + /** * lpfc_online - Initialize and bring a HBA online * @phba: pointer to lpfc hba data structure. @@ -2642,6 +2678,15 @@ lpfc_offline_prep(struct lpfc_hba * phba) } spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; + + /* + * Whenever an SLI4 port goes offline, free the + * RPI. A new RPI when the adapter port comes + * back online. + */ + if (phba->sli_rev == LPFC_SLI_REV4) + lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); + spin_unlock_irq(shost->host_lock); lpfc_unreg_rpi(vports[i], ndlp); } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index c80bce633ae15..d1d23eed74006 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -5600,6 +5600,8 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) for (i = 0; i < count; i++) phba->sli4_hba.rpi_ids[i] = base + i; + lpfc_sli4_node_prep(phba); + /* VPIs. */ count = phba->sli4_hba.max_cfg_param.max_vpi; base = phba->sli4_hba.max_cfg_param.vpi_base;