diff options
author | Bhanu Prakash Gollapudi <bprakash@broadcom.com> | 2012-12-21 22:40:31 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-01-29 18:48:48 -0500 |
commit | e7f4fed5fa96d3da12c3e1c8ed9f536235eec3b5 (patch) | |
tree | a13ac74c4e452af823c18f06e3b9891d1f497ff7 /drivers/scsi/bnx2fc/bnx2fc_tgt.c | |
parent | 26bf62a3dd0752f29609b2dea85a4f0b806da315 (diff) |
[SCSI] bnx2fc: Map the doorbell register between offload and enable requests
We used to map doorbell register after FW enable request is complete.
This causes a race condition when unsolicited event is received, and FW
sends a CQE for it. Since the doorbell is not mapped, driver does not
arm CQ, which means FW will not notify the driver for further CQ
completions. To resolve this, map the doorbell between offload and
enable, so that driver is ready to receive the unsolicited packets and
arm the CQ as soon as FW enable is performed.
Signed-off-by: Bhanu Prakash Gollapudi <bprakash@broadcom.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/bnx2fc/bnx2fc_tgt.c')
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_tgt.c | 26 |
1 files changed, 17 insertions, 9 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index 236d8894bd82..c57a3bb8a9fb 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c | |||
@@ -33,6 +33,7 @@ static void bnx2fc_upld_timer(unsigned long data) | |||
33 | BNX2FC_TGT_DBG(tgt, "upld_timer - Upload compl not received!!\n"); | 33 | BNX2FC_TGT_DBG(tgt, "upld_timer - Upload compl not received!!\n"); |
34 | /* fake upload completion */ | 34 | /* fake upload completion */ |
35 | clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); | 35 | clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); |
36 | clear_bit(BNX2FC_FLAG_ENABLED, &tgt->flags); | ||
36 | set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); | 37 | set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); |
37 | wake_up_interruptible(&tgt->upld_wait); | 38 | wake_up_interruptible(&tgt->upld_wait); |
38 | } | 39 | } |
@@ -55,6 +56,7 @@ static void bnx2fc_ofld_timer(unsigned long data) | |||
55 | * resources are freed up in bnx2fc_offload_session | 56 | * resources are freed up in bnx2fc_offload_session |
56 | */ | 57 | */ |
57 | clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); | 58 | clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); |
59 | clear_bit(BNX2FC_FLAG_ENABLED, &tgt->flags); | ||
58 | set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); | 60 | set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); |
59 | wake_up_interruptible(&tgt->ofld_wait); | 61 | wake_up_interruptible(&tgt->ofld_wait); |
60 | } | 62 | } |
@@ -135,14 +137,23 @@ retry_ofld: | |||
135 | } | 137 | } |
136 | if (bnx2fc_map_doorbell(tgt)) { | 138 | if (bnx2fc_map_doorbell(tgt)) { |
137 | printk(KERN_ERR PFX "map doorbell failed - no mem\n"); | 139 | printk(KERN_ERR PFX "map doorbell failed - no mem\n"); |
138 | /* upload will take care of cleaning up sess resc */ | 140 | goto ofld_err; |
139 | lport->tt.rport_logoff(rdata); | 141 | } |
142 | clear_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); | ||
143 | rval = bnx2fc_send_session_enable_req(port, tgt); | ||
144 | if (rval) { | ||
145 | pr_err(PFX "enable session failed\n"); | ||
146 | goto ofld_err; | ||
140 | } | 147 | } |
148 | bnx2fc_ofld_wait(tgt); | ||
149 | if (!(test_bit(BNX2FC_FLAG_ENABLED, &tgt->flags))) | ||
150 | goto ofld_err; | ||
141 | return; | 151 | return; |
142 | 152 | ||
143 | ofld_err: | 153 | ofld_err: |
144 | /* couldn't offload the session. log off from this rport */ | 154 | /* couldn't offload the session. log off from this rport */ |
145 | BNX2FC_TGT_DBG(tgt, "bnx2fc_offload_session - offload error\n"); | 155 | BNX2FC_TGT_DBG(tgt, "bnx2fc_offload_session - offload error\n"); |
156 | clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); | ||
146 | /* Free session resources */ | 157 | /* Free session resources */ |
147 | bnx2fc_free_session_resc(hba, tgt); | 158 | bnx2fc_free_session_resc(hba, tgt); |
148 | tgt_init_err: | 159 | tgt_init_err: |
@@ -476,7 +487,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport, | |||
476 | tgt = (struct bnx2fc_rport *)&rp[1]; | 487 | tgt = (struct bnx2fc_rport *)&rp[1]; |
477 | 488 | ||
478 | /* This can happen when ADISC finds the same target */ | 489 | /* This can happen when ADISC finds the same target */ |
479 | if (test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags)) { | 490 | if (test_bit(BNX2FC_FLAG_ENABLED, &tgt->flags)) { |
480 | BNX2FC_TGT_DBG(tgt, "already offloaded\n"); | 491 | BNX2FC_TGT_DBG(tgt, "already offloaded\n"); |
481 | mutex_unlock(&hba->hba_mutex); | 492 | mutex_unlock(&hba->hba_mutex); |
482 | return; | 493 | return; |
@@ -491,11 +502,8 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport, | |||
491 | BNX2FC_TGT_DBG(tgt, "OFFLOAD num_ofld_sess = %d\n", | 502 | BNX2FC_TGT_DBG(tgt, "OFFLOAD num_ofld_sess = %d\n", |
492 | hba->num_ofld_sess); | 503 | hba->num_ofld_sess); |
493 | 504 | ||
494 | if (test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags)) { | 505 | if (test_bit(BNX2FC_FLAG_ENABLED, &tgt->flags)) { |
495 | /* | 506 | /* Session is offloaded and enabled. */ |
496 | * Session is offloaded and enabled. Map | ||
497 | * doorbell register for this target | ||
498 | */ | ||
499 | BNX2FC_TGT_DBG(tgt, "sess offloaded\n"); | 507 | BNX2FC_TGT_DBG(tgt, "sess offloaded\n"); |
500 | /* This counter is protected with hba mutex */ | 508 | /* This counter is protected with hba mutex */ |
501 | hba->num_ofld_sess++; | 509 | hba->num_ofld_sess++; |
@@ -532,7 +540,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport, | |||
532 | */ | 540 | */ |
533 | tgt = (struct bnx2fc_rport *)&rp[1]; | 541 | tgt = (struct bnx2fc_rport *)&rp[1]; |
534 | 542 | ||
535 | if (!(test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags))) { | 543 | if (!(test_bit(BNX2FC_FLAG_ENABLED, &tgt->flags))) { |
536 | mutex_unlock(&hba->hba_mutex); | 544 | mutex_unlock(&hba->hba_mutex); |
537 | break; | 545 | break; |
538 | } | 546 | } |