From 2eefb20dbf3032da1ad111c1ce178f899bc4859a Mon Sep 17 00:00:00 2001 From: Eddie Wai Date: Thu, 1 Jul 2010 15:34:54 -0700 Subject: [PATCH] [SCSI] bnx2i: Fixed the TCP graceful termination initiation 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. Signed-off-by: Eddie Wai Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Acked-by: Anil Veerabhadrappa Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i.h | 2 ++ drivers/scsi/bnx2i/bnx2i_hwi.c | 4 +++ drivers/scsi/bnx2i/bnx2i_iscsi.c | 53 ++++++++++++++++++++------------ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index 69febb6f958b..00c033511cbf 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -639,6 +639,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 3a66ca24c7bd..d23fc256d585 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -562,6 +562,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; } @@ -1482,6 +1484,8 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session, resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain); __iscsi_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 f6eebb39fe54..c66c5a45aa27 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1890,6 +1890,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; @@ -1923,6 +1925,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; @@ -1939,33 +1943,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);