mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 06:01:57 +00:00
scsi: lpfc: Fix unsolicited FLOGI kref imbalance when in direct attached topology
In direct attached topology, certain target vendors that are quick to issue FLOGI followed by a cable pull for more than dev_loss_tmo may result in a kref imbalance for the remote port ndlp object. Add an nlp_get when the defer_flogi_acc flag is set. This is expected to balance the nlp_put in the defer_flogi_acc clause in the lpfc_issue_els_flogi() routine. Because we need to retain the ndlp ptr, reorganize all of the defer_flogi_acc information into one lpfc_defer_flogi_acc struct. Signed-off-by: Justin Tee <justin.tee@broadcom.com> Link: https://lore.kernel.org/r/20240726231512.92867-6-justintee8345@gmail.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
3976beb1b4
commit
b5c18c9dd1
@ -306,6 +306,14 @@ struct lpfc_stats {
|
||||
|
||||
struct lpfc_hba;
|
||||
|
||||
/* Data structure to keep withheld FLOGI_ACC information */
|
||||
struct lpfc_defer_flogi_acc {
|
||||
bool flag;
|
||||
u16 rx_id;
|
||||
u16 ox_id;
|
||||
struct lpfc_nodelist *ndlp;
|
||||
|
||||
};
|
||||
|
||||
#define LPFC_VMID_TIMER 300 /* timer interval in seconds */
|
||||
|
||||
@ -1430,9 +1438,7 @@ struct lpfc_hba {
|
||||
uint16_t vlan_id;
|
||||
struct list_head fcf_conn_rec_list;
|
||||
|
||||
bool defer_flogi_acc_flag;
|
||||
uint16_t defer_flogi_acc_rx_id;
|
||||
uint16_t defer_flogi_acc_ox_id;
|
||||
struct lpfc_defer_flogi_acc defer_flogi_acc;
|
||||
|
||||
spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */
|
||||
struct list_head ct_ev_waiters;
|
||||
|
@ -1392,7 +1392,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
|
||||
|
||||
/* Check for a deferred FLOGI ACC condition */
|
||||
if (phba->defer_flogi_acc_flag) {
|
||||
if (phba->defer_flogi_acc.flag) {
|
||||
/* lookup ndlp for received FLOGI */
|
||||
ndlp = lpfc_findnode_did(vport, 0);
|
||||
if (!ndlp)
|
||||
@ -1406,34 +1406,38 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
|
||||
if (phba->sli_rev == LPFC_SLI_REV4) {
|
||||
bf_set(wqe_ctxt_tag,
|
||||
&defer_flogi_acc.wqe.xmit_els_rsp.wqe_com,
|
||||
phba->defer_flogi_acc_rx_id);
|
||||
phba->defer_flogi_acc.rx_id);
|
||||
bf_set(wqe_rcvoxid,
|
||||
&defer_flogi_acc.wqe.xmit_els_rsp.wqe_com,
|
||||
phba->defer_flogi_acc_ox_id);
|
||||
phba->defer_flogi_acc.ox_id);
|
||||
} else {
|
||||
icmd = &defer_flogi_acc.iocb;
|
||||
icmd->ulpContext = phba->defer_flogi_acc_rx_id;
|
||||
icmd->ulpContext = phba->defer_flogi_acc.rx_id;
|
||||
icmd->unsli3.rcvsli3.ox_id =
|
||||
phba->defer_flogi_acc_ox_id;
|
||||
phba->defer_flogi_acc.ox_id;
|
||||
}
|
||||
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
|
||||
"3354 Xmit deferred FLOGI ACC: rx_id: x%x,"
|
||||
" ox_id: x%x, hba_flag x%lx\n",
|
||||
phba->defer_flogi_acc_rx_id,
|
||||
phba->defer_flogi_acc_ox_id, phba->hba_flag);
|
||||
phba->defer_flogi_acc.rx_id,
|
||||
phba->defer_flogi_acc.ox_id, phba->hba_flag);
|
||||
|
||||
/* Send deferred FLOGI ACC */
|
||||
lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, &defer_flogi_acc,
|
||||
ndlp, NULL);
|
||||
|
||||
phba->defer_flogi_acc_flag = false;
|
||||
vport->fc_myDID = did;
|
||||
phba->defer_flogi_acc.flag = false;
|
||||
|
||||
/* Decrement ndlp reference count to indicate the node can be
|
||||
* released when other references are removed.
|
||||
/* Decrement the held ndlp that was incremented when the
|
||||
* deferred flogi acc flag was set.
|
||||
*/
|
||||
lpfc_nlp_put(ndlp);
|
||||
if (phba->defer_flogi_acc.ndlp) {
|
||||
lpfc_nlp_put(phba->defer_flogi_acc.ndlp);
|
||||
phba->defer_flogi_acc.ndlp = NULL;
|
||||
}
|
||||
|
||||
vport->fc_myDID = did;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -8456,9 +8460,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
|
||||
|
||||
/* Defer ACC response until AFTER we issue a FLOGI */
|
||||
if (!test_bit(HBA_FLOGI_ISSUED, &phba->hba_flag)) {
|
||||
phba->defer_flogi_acc_rx_id = bf_get(wqe_ctxt_tag,
|
||||
phba->defer_flogi_acc.rx_id = bf_get(wqe_ctxt_tag,
|
||||
&wqe->xmit_els_rsp.wqe_com);
|
||||
phba->defer_flogi_acc_ox_id = bf_get(wqe_rcvoxid,
|
||||
phba->defer_flogi_acc.ox_id = bf_get(wqe_rcvoxid,
|
||||
&wqe->xmit_els_rsp.wqe_com);
|
||||
|
||||
vport->fc_myDID = did;
|
||||
@ -8466,11 +8470,17 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
|
||||
"3344 Deferring FLOGI ACC: rx_id: x%x,"
|
||||
" ox_id: x%x, hba_flag x%lx\n",
|
||||
phba->defer_flogi_acc_rx_id,
|
||||
phba->defer_flogi_acc_ox_id, phba->hba_flag);
|
||||
phba->defer_flogi_acc.rx_id,
|
||||
phba->defer_flogi_acc.ox_id, phba->hba_flag);
|
||||
|
||||
phba->defer_flogi_acc_flag = true;
|
||||
phba->defer_flogi_acc.flag = true;
|
||||
|
||||
/* This nlp_get is paired with nlp_puts that reset the
|
||||
* defer_flogi_acc.flag back to false. We need to retain
|
||||
* a kref on the ndlp until the deferred FLOGI ACC is
|
||||
* processed or cancelled.
|
||||
*/
|
||||
phba->defer_flogi_acc.ndlp = lpfc_nlp_get(ndlp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -10506,7 +10516,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
|
||||
|
||||
lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
|
||||
/* retain node if our response is deferred */
|
||||
if (phba->defer_flogi_acc_flag)
|
||||
if (phba->defer_flogi_acc.flag)
|
||||
break;
|
||||
if (newnode)
|
||||
lpfc_disc_state_machine(vport, ndlp, NULL,
|
||||
|
@ -1255,7 +1255,14 @@ lpfc_linkdown(struct lpfc_hba *phba)
|
||||
lpfc_scsi_dev_block(phba);
|
||||
offline = pci_channel_offline(phba->pcidev);
|
||||
|
||||
phba->defer_flogi_acc_flag = false;
|
||||
/* Decrement the held ndlp if there is a deferred flogi acc */
|
||||
if (phba->defer_flogi_acc.flag) {
|
||||
if (phba->defer_flogi_acc.ndlp) {
|
||||
lpfc_nlp_put(phba->defer_flogi_acc.ndlp);
|
||||
phba->defer_flogi_acc.ndlp = NULL;
|
||||
}
|
||||
}
|
||||
phba->defer_flogi_acc.flag = false;
|
||||
|
||||
/* Clear external loopback plug detected flag */
|
||||
phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
|
||||
@ -1377,7 +1384,7 @@ lpfc_linkup_port(struct lpfc_vport *vport)
|
||||
(vport != phba->pport))
|
||||
return;
|
||||
|
||||
if (phba->defer_flogi_acc_flag) {
|
||||
if (phba->defer_flogi_acc.flag) {
|
||||
clear_bit(FC_ABORT_DISCOVERY, &vport->fc_flag);
|
||||
clear_bit(FC_RSCN_MODE, &vport->fc_flag);
|
||||
clear_bit(FC_NLP_MORE, &vport->fc_flag);
|
||||
|
Loading…
Reference in New Issue
Block a user