aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBhanu Prakash Gollapudi <bprakash@broadcom.com>2011-08-04 20:38:46 -0400
committerJames Bottomley <JBottomley@Parallels.com>2011-08-27 10:35:42 -0400
commitb338c785c5c945383046ff39092e3021ea5b1d95 (patch)
tree548bd66957226efdd21e32eefefc222fdc593a69 /drivers
parent81214013130cd24142f6465f7f5a256fed530c17 (diff)
[SCSI] bnx2fc: Fix NULL pointer deref during arm_cq.
There exists a race condition between CQ doorbell unmap and IO completion path that arms the CQ which causes a NULL dereference. Protect the ctx_base with cq_lock to avoid this. Also, wait for the CQ doorbell to be successfully mapped before arming the CQ. Also, do not count uncolicited CQ completions for free_sqes. Signed-off-by: Bhanu Prakash Gollapudi <bprakash@broadcom.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c10
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_tgt.c19
2 files changed, 18 insertions, 11 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index 72cfb14acd3a..b241f3d33362 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -1009,6 +1009,7 @@ int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt)
1009 u32 cq_cons; 1009 u32 cq_cons;
1010 struct fcoe_cqe *cqe; 1010 struct fcoe_cqe *cqe;
1011 u32 num_free_sqes = 0; 1011 u32 num_free_sqes = 0;
1012 u32 num_cqes = 0;
1012 u16 wqe; 1013 u16 wqe;
1013 1014
1014 /* 1015 /*
@@ -1058,10 +1059,11 @@ unlock:
1058 wake_up_process(fps->iothread); 1059 wake_up_process(fps->iothread);
1059 else 1060 else
1060 bnx2fc_process_cq_compl(tgt, wqe); 1061 bnx2fc_process_cq_compl(tgt, wqe);
1062 num_free_sqes++;
1061 } 1063 }
1062 cqe++; 1064 cqe++;
1063 tgt->cq_cons_idx++; 1065 tgt->cq_cons_idx++;
1064 num_free_sqes++; 1066 num_cqes++;
1065 1067
1066 if (tgt->cq_cons_idx == BNX2FC_CQ_WQES_MAX) { 1068 if (tgt->cq_cons_idx == BNX2FC_CQ_WQES_MAX) {
1067 tgt->cq_cons_idx = 0; 1069 tgt->cq_cons_idx = 0;
@@ -1070,8 +1072,10 @@ unlock:
1070 1 - tgt->cq_curr_toggle_bit; 1072 1 - tgt->cq_curr_toggle_bit;
1071 } 1073 }
1072 } 1074 }
1073 if (num_free_sqes) { 1075 if (num_cqes) {
1074 bnx2fc_arm_cq(tgt); 1076 /* Arm CQ only if doorbell is mapped */
1077 if (tgt->ctx_base)
1078 bnx2fc_arm_cq(tgt);
1075 atomic_add(num_free_sqes, &tgt->free_sqes); 1079 atomic_add(num_free_sqes, &tgt->free_sqes);
1076 } 1080 }
1077 spin_unlock_bh(&tgt->cq_lock); 1081 spin_unlock_bh(&tgt->cq_lock);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
index 3d28fbe1d99e..2f7a7da5b27b 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
@@ -133,9 +133,9 @@ retry_ofld:
133 printk(KERN_ERR PFX "map doorbell failed - no mem\n"); 133 printk(KERN_ERR PFX "map doorbell failed - no mem\n");
134 /* upload will take care of cleaning up sess resc */ 134 /* upload will take care of cleaning up sess resc */
135 lport->tt.rport_logoff(rdata); 135 lport->tt.rport_logoff(rdata);
136 } 136 } else
137 /* Arm CQ */ 137 /* Arm CQ */
138 bnx2fc_arm_cq(tgt); 138 bnx2fc_arm_cq(tgt);
139 return; 139 return;
140 140
141ofld_err: 141ofld_err:
@@ -806,14 +806,14 @@ mem_alloc_failure:
806static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba, 806static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba,
807 struct bnx2fc_rport *tgt) 807 struct bnx2fc_rport *tgt)
808{ 808{
809 BNX2FC_TGT_DBG(tgt, "Freeing up session resources\n"); 809 void __iomem *ctx_base_ptr;
810 810
811 if (tgt->ctx_base) { 811 BNX2FC_TGT_DBG(tgt, "Freeing up session resources\n");
812 iounmap(tgt->ctx_base);
813 tgt->ctx_base = NULL;
814 }
815 812
816 spin_lock_bh(&tgt->cq_lock); 813 spin_lock_bh(&tgt->cq_lock);
814 ctx_base_ptr = tgt->ctx_base;
815 tgt->ctx_base = NULL;
816
817 /* Free LCQ */ 817 /* Free LCQ */
818 if (tgt->lcq) { 818 if (tgt->lcq) {
819 dma_free_coherent(&hba->pcidev->dev, tgt->lcq_mem_size, 819 dma_free_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
@@ -867,4 +867,7 @@ static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba,
867 tgt->sq = NULL; 867 tgt->sq = NULL;
868 } 868 }
869 spin_unlock_bh(&tgt->cq_lock); 869 spin_unlock_bh(&tgt->cq_lock);
870
871 if (ctx_base_ptr)
872 iounmap(ctx_base_ptr);
870} 873}