Sophie

Sophie

distrib > CentOS > 5 > x86_64 > by-pkgid > ea32411352494358b8d75a78402a4713 > files > 4229

kernel-2.6.18-238.19.1.el5.centos.plus.src.rpm

From: Mike Christie <mchristi@redhat.com>
Date: Fri, 13 Aug 2010 09:46:33 -0400
Subject: [scsi] bnx2i: fix TCP graceful termination initiation
Message-id: <1281692802-2810-6-git-send-email-mchristi@redhat.com>
Patchwork-id: 27544
O-Subject: [RHEL5.6 PATCH 05/14] BNX2I: Fixed the TCP graceful termination
	initiation
Bugzilla: 568606

From: Eddie Wai <eddie.wai@broadcom.com>

For bz 568606.

In compliance to RFC793, a TCP graceful termination will be used
instead of an abortive termination for the case where the remote
has initiated the close of the connection.
Additionally, a TCP abortive termination will be used to close the
connection when a logout response is not received in time after a
logout request has been initiated.

http://git.kernel.org/?p=linux/kernel/git/jejb/scsi-misc-2.6.git;a=commit;h=2eefb20dbf3032da1ad111c1ce178f899bc4859a

diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index 65425b3..dffba80 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -641,6 +641,8 @@ enum {
 	EP_STATE_CLEANUP_CMPL           = 0x800,
 	EP_STATE_TCP_FIN_RCVD           = 0x1000,
 	EP_STATE_TCP_RST_RCVD           = 0x2000,
+	EP_STATE_LOGOUT_SENT            = 0x4000,
+	EP_STATE_LOGOUT_RESP_RCVD       = 0x8000,
 	EP_STATE_PG_OFLD_FAILED         = 0x1000000,
 	EP_STATE_ULP_UPDATE_FAILED      = 0x2000000,
 	EP_STATE_CLEANUP_FAILED         = 0x4000000,
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 07eed7a..d3f75ad 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -561,6 +561,8 @@ int bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn,
 	logout_wqe->num_bds = 1;
 	logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */
 
+	bnx2i_conn->ep->state = EP_STATE_LOGOUT_SENT;
+
 	bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1);
 	return 0;
 }
@@ -1481,6 +1483,8 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session,
 	resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain);
 
 	__iscsi2_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
+
+	bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD;
 done:
 	spin_unlock(&session->lock);
 	return 0;
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 20a4004..cfb614b 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1904,6 +1904,8 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
 	case EP_STATE_ULP_UPDATE_START:
 	case EP_STATE_ULP_UPDATE_COMPL:
 	case EP_STATE_TCP_FIN_RCVD:
+	case EP_STATE_LOGOUT_SENT:
+	case EP_STATE_LOGOUT_RESP_RCVD:
 	case EP_STATE_ULP_UPDATE_FAILED:
 		ret = 1;
 		break;
@@ -1937,6 +1939,8 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
 	struct iscsi_session *session = NULL;
 	struct iscsi_conn *conn = NULL;
 	int ret = 0;
+	int close = 0;
+	int close_ret = 0;
 
 	if (!hba)
 		return 0;
@@ -1953,33 +1957,44 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
 		session = conn->session;
 	}
 
-	bnx2i_ep->state = EP_STATE_DISCONN_START;
-
 	init_timer(&bnx2i_ep->ofld_timer);
 	bnx2i_ep->ofld_timer.expires = hba->conn_teardown_tmo + jiffies;
 	bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer;
 	bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep;
 	add_timer(&bnx2i_ep->ofld_timer);
 
-	if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
-		int close = 0;
-		int close_ret = 0;
-
-		if (session) {
-			spin_lock_bh(&session->lock);
-			if (session->state == ISCSI_STATE_LOGGING_OUT)
-				close = 1;
-			spin_unlock_bh(&session->lock);
-		}
-		if (close)
-			close_ret = cnic->cm_close(bnx2i_ep->cm_sk);
-		else
-			close_ret = cnic->cm_abort(bnx2i_ep->cm_sk);
-		if (close_ret)
-			bnx2i_ep->state = EP_STATE_DISCONN_COMPL;
-	} else
+	if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic))
 		goto out;
 
+	if (session) {
+		spin_lock_bh(&session->lock);
+		if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) {
+			if (session->state == ISCSI_STATE_LOGGING_OUT) {
+				if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) {
+					/* Logout sent, but no resp */
+					printk(KERN_ALERT "bnx2i - WARNING "
+						"logout response was not "
+						"received!\n");
+				} else if (bnx2i_ep->state ==
+					   EP_STATE_LOGOUT_RESP_RCVD)
+					close = 1;
+			}
+		} else
+			close = 1;
+
+		spin_unlock_bh(&session->lock);
+	}
+
+	bnx2i_ep->state = EP_STATE_DISCONN_START;
+
+	if (close)
+		close_ret = cnic->cm_close(bnx2i_ep->cm_sk);
+	else
+		close_ret = cnic->cm_abort(bnx2i_ep->cm_sk);
+
+	if (close_ret)
+		bnx2i_ep->state = EP_STATE_DISCONN_COMPL;
+
 	/* wait for option-2 conn teardown */
 	wait_event_interruptible(bnx2i_ep->ofld_wait,
 				 bnx2i_ep->state != EP_STATE_DISCONN_START);