Skip to content

Commit b5c18c9

Browse files
Justin Teemartinkpetersen
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 3976beb commit b5c18c9

File tree

3 files changed

+46
-23
lines changed

3 files changed

+46
-23
lines changed

drivers/scsi/lpfc/lpfc.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,14 @@ struct lpfc_stats {
306306

307307
struct lpfc_hba;
308308

309+
/* Data structure to keep withheld FLOGI_ACC information */
310+
struct lpfc_defer_flogi_acc {
311+
bool flag;
312+
u16 rx_id;
313+
u16 ox_id;
314+
struct lpfc_nodelist *ndlp;
315+
316+
};
309317

310318
#define LPFC_VMID_TIMER 300 /* timer interval in seconds */
311319

@@ -1430,9 +1438,7 @@ struct lpfc_hba {
14301438
uint16_t vlan_id;
14311439
struct list_head fcf_conn_rec_list;
14321440

1433-
bool defer_flogi_acc_flag;
1434-
uint16_t defer_flogi_acc_rx_id;
1435-
uint16_t defer_flogi_acc_ox_id;
1441+
struct lpfc_defer_flogi_acc defer_flogi_acc;
14361442

14371443
spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */
14381444
struct list_head ct_ev_waiters;

drivers/scsi/lpfc/lpfc_els.c

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,7 +1392,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
13921392
phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
13931393

13941394
/* Check for a deferred FLOGI ACC condition */
1395-
if (phba->defer_flogi_acc_flag) {
1395+
if (phba->defer_flogi_acc.flag) {
13961396
/* lookup ndlp for received FLOGI */
13971397
ndlp = lpfc_findnode_did(vport, 0);
13981398
if (!ndlp)
@@ -1406,34 +1406,38 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
14061406
if (phba->sli_rev == LPFC_SLI_REV4) {
14071407
bf_set(wqe_ctxt_tag,
14081408
&defer_flogi_acc.wqe.xmit_els_rsp.wqe_com,
1409-
phba->defer_flogi_acc_rx_id);
1409+
phba->defer_flogi_acc.rx_id);
14101410
bf_set(wqe_rcvoxid,
14111411
&defer_flogi_acc.wqe.xmit_els_rsp.wqe_com,
1412-
phba->defer_flogi_acc_ox_id);
1412+
phba->defer_flogi_acc.ox_id);
14131413
} else {
14141414
icmd = &defer_flogi_acc.iocb;
1415-
icmd->ulpContext = phba->defer_flogi_acc_rx_id;
1415+
icmd->ulpContext = phba->defer_flogi_acc.rx_id;
14161416
icmd->unsli3.rcvsli3.ox_id =
1417-
phba->defer_flogi_acc_ox_id;
1417+
phba->defer_flogi_acc.ox_id;
14181418
}
14191419

14201420
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
14211421
"3354 Xmit deferred FLOGI ACC: rx_id: x%x,"
14221422
" ox_id: x%x, hba_flag x%lx\n",
1423-
phba->defer_flogi_acc_rx_id,
1424-
phba->defer_flogi_acc_ox_id, phba->hba_flag);
1423+
phba->defer_flogi_acc.rx_id,
1424+
phba->defer_flogi_acc.ox_id, phba->hba_flag);
14251425

14261426
/* Send deferred FLOGI ACC */
14271427
lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, &defer_flogi_acc,
14281428
ndlp, NULL);
14291429

1430-
phba->defer_flogi_acc_flag = false;
1431-
vport->fc_myDID = did;
1430+
phba->defer_flogi_acc.flag = false;
14321431

1433-
/* Decrement ndlp reference count to indicate the node can be
1434-
* released when other references are removed.
1432+
/* Decrement the held ndlp that was incremented when the
1433+
* deferred flogi acc flag was set.
14351434
*/
1436-
lpfc_nlp_put(ndlp);
1435+
if (phba->defer_flogi_acc.ndlp) {
1436+
lpfc_nlp_put(phba->defer_flogi_acc.ndlp);
1437+
phba->defer_flogi_acc.ndlp = NULL;
1438+
}
1439+
1440+
vport->fc_myDID = did;
14371441
}
14381442

14391443
return 0;
@@ -8456,21 +8460,27 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
84568460

84578461
/* Defer ACC response until AFTER we issue a FLOGI */
84588462
if (!test_bit(HBA_FLOGI_ISSUED, &phba->hba_flag)) {
8459-
phba->defer_flogi_acc_rx_id = bf_get(wqe_ctxt_tag,
8463+
phba->defer_flogi_acc.rx_id = bf_get(wqe_ctxt_tag,
84608464
&wqe->xmit_els_rsp.wqe_com);
8461-
phba->defer_flogi_acc_ox_id = bf_get(wqe_rcvoxid,
8465+
phba->defer_flogi_acc.ox_id = bf_get(wqe_rcvoxid,
84628466
&wqe->xmit_els_rsp.wqe_com);
84638467

84648468
vport->fc_myDID = did;
84658469

84668470
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
84678471
"3344 Deferring FLOGI ACC: rx_id: x%x,"
84688472
" ox_id: x%x, hba_flag x%lx\n",
8469-
phba->defer_flogi_acc_rx_id,
8470-
phba->defer_flogi_acc_ox_id, phba->hba_flag);
8473+
phba->defer_flogi_acc.rx_id,
8474+
phba->defer_flogi_acc.ox_id, phba->hba_flag);
84718475

8472-
phba->defer_flogi_acc_flag = true;
8476+
phba->defer_flogi_acc.flag = true;
84738477

8478+
/* This nlp_get is paired with nlp_puts that reset the
8479+
* defer_flogi_acc.flag back to false. We need to retain
8480+
* a kref on the ndlp until the deferred FLOGI ACC is
8481+
* processed or cancelled.
8482+
*/
8483+
phba->defer_flogi_acc.ndlp = lpfc_nlp_get(ndlp);
84748484
return 0;
84758485
}
84768486

@@ -10506,7 +10516,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
1050610516

1050710517
lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
1050810518
/* retain node if our response is deferred */
10509-
if (phba->defer_flogi_acc_flag)
10519+
if (phba->defer_flogi_acc.flag)
1051010520
break;
1051110521
if (newnode)
1051210522
lpfc_disc_state_machine(vport, ndlp, NULL,

drivers/scsi/lpfc/lpfc_hbadisc.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,7 +1255,14 @@ lpfc_linkdown(struct lpfc_hba *phba)
12551255
lpfc_scsi_dev_block(phba);
12561256
offline = pci_channel_offline(phba->pcidev);
12571257

1258-
phba->defer_flogi_acc_flag = false;
1258+
/* Decrement the held ndlp if there is a deferred flogi acc */
1259+
if (phba->defer_flogi_acc.flag) {
1260+
if (phba->defer_flogi_acc.ndlp) {
1261+
lpfc_nlp_put(phba->defer_flogi_acc.ndlp);
1262+
phba->defer_flogi_acc.ndlp = NULL;
1263+
}
1264+
}
1265+
phba->defer_flogi_acc.flag = false;
12591266

12601267
/* Clear external loopback plug detected flag */
12611268
phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
@@ -1377,7 +1384,7 @@ lpfc_linkup_port(struct lpfc_vport *vport)
13771384
(vport != phba->pport))
13781385
return;
13791386

1380-
if (phba->defer_flogi_acc_flag) {
1387+
if (phba->defer_flogi_acc.flag) {
13811388
clear_bit(FC_ABORT_DISCOVERY, &vport->fc_flag);
13821389
clear_bit(FC_RSCN_MODE, &vport->fc_flag);
13831390
clear_bit(FC_NLP_MORE, &vport->fc_flag);

0 commit comments

Comments
 (0)