summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2011-06-08 19:29:33 +0000
committerDavid S. Miller <davem@davemloft.net>2011-06-08 23:52:36 -0700
commit101c40c8cb0d10c30f423805f9f5b7a75956832d (patch)
tree6b460f517e244ee80a2f8e8ae2f266e5509ff2f3
parent93736656138e6d2f39f19c1d68f9ef81cfc9dd66 (diff)
downloadlinux-3.10-101c40c8cb0d10c30f423805f9f5b7a75956832d.tar.gz
linux-3.10-101c40c8cb0d10c30f423805f9f5b7a75956832d.tar.bz2
linux-3.10-101c40c8cb0d10c30f423805f9f5b7a75956832d.zip
cnic: Fix race conditions with firmware
During iSCSI connection terminations, if the target is also terminating at about the same time, the firmware may not complete the driver's request to close or reset the connection. This is fixed by handling other events (instead of the expected completion event) as an indication that the driver's request has been rejected. Signed-off-by: Michael Chan <mchan@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/cnic.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 5c0a669dfa5..ea7245c5fb6 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -3767,7 +3767,13 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
break;
case L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED:
- cnic_cm_upcall(cp, csk, opcode);
+ /* after we already sent CLOSE_REQ */
+ if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags) &&
+ !test_bit(SK_F_OFFLD_COMPLETE, &csk->flags) &&
+ csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)
+ cp->close_conn(csk, L4_KCQE_OPCODE_VALUE_RESET_COMP);
+ else
+ cnic_cm_upcall(cp, csk, opcode);
break;
}
csk_put(csk);
@@ -3821,12 +3827,14 @@ static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
}
/* 1. If event opcode matches the expected event in csk->state
- * 2. If the expected event is CLOSE_COMP, we accept any event
+ * 2. If the expected event is CLOSE_COMP or RESET_COMP, we accept any
+ * event
* 3. If the expected event is 0, meaning the connection was never
* never established, we accept the opcode from cm_abort.
*/
if (opcode == csk->state || csk->state == 0 ||
- csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) {
+ csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP ||
+ csk->state == L4_KCQE_OPCODE_VALUE_RESET_COMP) {
if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) {
if (csk->state == 0)
csk->state = opcode;