[PATCH 6/7] Fix a kernel panic because of TCP RST/FIN received.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 A TCP RST/FIN can be received even before the connection specific
 structures are initialized.This fix checks for the conn structure
 is intialized or not  when RST/FIN is received.

Signed-off-by: John Soni Jose <sony.john-n@xxxxxxxxxx>
Signed-off-by: Jayamohan Kallickal <jayamohan.kallickal@xxxxxxxxxx>
---
 drivers/scsi/be2iscsi/be_iscsi.c |   51 ++++++++++++++++++++++++-----------
 drivers/scsi/be2iscsi/be_iscsi.h |    3 ++
 drivers/scsi/be2iscsi/be_main.c  |   55 ++++++++++++++++++-------------------
 drivers/scsi/be2iscsi/be_mgmt.h  |    1 +
 4 files changed, 66 insertions(+), 44 deletions(-)

diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 17b0907..8851add 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -1254,8 +1254,6 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
 	struct beiscsi_conn *beiscsi_conn;
 	struct beiscsi_endpoint *beiscsi_ep;
 	struct beiscsi_hba *phba;
-	unsigned int tag;
-	unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
 
 	beiscsi_ep = ep->dd_data;
 	phba = beiscsi_ep->phba;
@@ -1263,34 +1261,55 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
 			"BS_%d : In beiscsi_ep_disconnect for ep_cid = %d\n",
 			beiscsi_ep->ep_cid);
 
-	if (!beiscsi_ep->conn) {
-		beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
-				"BS_%d : In beiscsi_ep_disconnect, no "
-				"beiscsi_ep\n");
-		return;
+	if (beiscsi_ep->conn) {
+		beiscsi_conn = beiscsi_ep->conn;
+		iscsi_suspend_queue(beiscsi_conn->conn);
 	}
-	beiscsi_conn = beiscsi_ep->conn;
-	iscsi_suspend_queue(beiscsi_conn->conn);
+
+	/* Cleanup the EP related info */
+	beiscsi_ep_cleanup(beiscsi_ep, ~BEISCSI_NO_RST_ISSUE,
+			CONNECTION_UPLOAD_GRACEFUL);
+}
+
+/**
+  * beiscsi_ep_cleanup : Cleanup of the endpoint.
+  * @beiscsi_ep : pointer to driver ep
+  * @mgmt_invalidate_flag	: Flag to pass while invalidating
+  *						  the connection.
+  * @tcp_upload_flag	: Flag to pass while uploading the
+  *						  the connection
+  *
+  * Invalidates the connection and upload the connection
+  * back to the FW. Does cleanup of info related to the
+  * endpoint.
+  *
+  **/
+void beiscsi_ep_cleanup(struct beiscsi_endpoint *beiscsi_ep,
+		uint8_t mgmt_invalidate_flag,
+		uint8_t tcp_upload_flag)
+{
+	struct beiscsi_hba *phba = beiscsi_ep->phba;
+	unsigned int tag;
+	unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
 
 	beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
-			"BS_%d : In beiscsi_ep_disconnect ep_cid = %d\n",
+			"BS_%d : In beiscsi_ep_cleanup for ep_cid = %d\n",
 			beiscsi_ep->ep_cid);
 
 	tag = mgmt_invalidate_connection(phba, beiscsi_ep,
-					    beiscsi_ep->ep_cid, 1,
-					    savecfg_flag);
+			beiscsi_ep->ep_cid, mgmt_invalidate_flag,
+			savecfg_flag);
 	if (!tag) {
 		beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_CONFIG,
-				"BS_%d : mgmt_invalidate_connection"
-				" Failed for cid=%d\n",
+				"BS_%d : mgmt_invalidate_connection Failed for cid=%d\n",
 				beiscsi_ep->ep_cid);
 	} else {
 		wait_event_interruptible(phba->ctrl.mcc_wait[tag],
-					 phba->ctrl.mcc_numtag[tag]);
+				phba->ctrl.mcc_numtag[tag]);
 		free_mcc_tag(&phba->ctrl, tag);
 	}
 
-	beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL);
+	beiscsi_close_conn(beiscsi_ep, tcp_upload_flag);
 	beiscsi_free_ep(beiscsi_ep);
 	beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
 	iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index 8b826fc..24c26ff 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -88,4 +88,7 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep);
 void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn,
 			    struct iscsi_stats *stats);
 
+void beiscsi_ep_cleanup(struct beiscsi_endpoint *beiscsi_ep,
+		uint8_t mgmt_invalidate_flag,
+		uint8_t tcp_upload_flag);
 #endif
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 548f2e7..46d88e0 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -42,6 +42,7 @@
 #include "be_main.h"
 #include "be_iscsi.h"
 #include "be_mgmt.h"
+#include "be_cmds.h"
 
 static unsigned int be_iopoll_budget = 10;
 static unsigned int be_max_phys_size = 64;
@@ -1920,6 +1921,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
 	struct dmsg_cqe *dmsg;
 	unsigned int num_processed = 0;
 	unsigned int tot_nump = 0;
+	unsigned short code = 0, cid = 0;
 	struct beiscsi_conn *beiscsi_conn;
 	struct beiscsi_endpoint *beiscsi_ep;
 	struct iscsi_endpoint *ep;
@@ -1933,10 +1935,11 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
 	       CQE_VALID_MASK) {
 		be_dws_le_to_cpu(sol, sizeof(struct sol_cqe));
 
-		ep = phba->ep_array[(u32) ((sol->
-				   dw[offsetof(struct amap_sol_cqe, cid) / 32] &
-				   SOL_CID_MASK) >> 6) -
-				   phba->fw_config.iscsi_cid_start];
+		cid = ((sol->dw[offsetof(struct amap_sol_cqe, cid) /
+					32] & CQE_CID_MASK) >> 6);
+		code = (sol->dw[offsetof(struct amap_sol_cqe, code) /
+				32] & CQE_CODE_MASK);
+		ep = phba->ep_array[cid - phba->fw_config.iscsi_cid_start];
 
 		beiscsi_ep = ep->dd_data;
 		beiscsi_conn = beiscsi_ep->conn;
@@ -1948,8 +1951,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
 			num_processed = 0;
 		}
 
-		switch ((u32) sol->dw[offsetof(struct amap_sol_cqe, code) /
-			32] & CQE_CODE_MASK) {
+		switch (code) {
 		case SOL_CMD_COMPLETE:
 			hwi_complete_cmd(beiscsi_conn, phba, sol);
 			break;
@@ -1996,11 +1998,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
 			beiscsi_log(phba, KERN_ERR,
 					BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
 					"BM_%d : CQ Error notification for cmd.. "
-					"code %d cid 0x%x\n",
-					sol->dw[offsetof(struct amap_sol_cqe,
-						code) / 32] & CQE_CODE_MASK,
-					sol->dw[offsetof(struct amap_sol_cqe,
-						cid) / 32] & SOL_CID_MASK);
+					"code %d cid 0x%x\n", code, cid);
 			break;
 		case UNSOL_DATA_DIGEST_ERROR_NOTIFY:
 			beiscsi_log(phba, KERN_ERR,
@@ -2027,12 +2025,14 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
 			beiscsi_log(phba, KERN_ERR,
 					BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
 					"BM_%d : CQ Error %d, reset CID 0x%x...\n",
-					sol->dw[offsetof(struct amap_sol_cqe,
-						code) / 32] & CQE_CODE_MASK,
-					sol->dw[offsetof(struct amap_sol_cqe,
-						cid) / 32] & CQE_CID_MASK);
-			iscsi_conn_failure(beiscsi_conn->conn,
-					   ISCSI_ERR_CONN_FAILED);
+					code, cid);
+			if (beiscsi_conn)
+				iscsi_conn_failure(beiscsi_conn->conn,
+						ISCSI_ERR_CONN_FAILED);
+			else
+				beiscsi_ep_cleanup(beiscsi_ep,
+						BEISCSI_NO_RST_ISSUE,
+						CONNECTION_UPLOAD_ABORT);
 			break;
 		case CXN_KILLED_RST_SENT:
 		case CXN_KILLED_RST_RCVD:
@@ -2040,23 +2040,22 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq)
 					BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
 					"BM_%d : CQ Error %d, reset"
 					"received/sent on CID 0x%x...\n",
-					sol->dw[offsetof(struct amap_sol_cqe,
-						code) / 32] & CQE_CODE_MASK,
-					sol->dw[offsetof(struct amap_sol_cqe,
-						cid) / 32] & CQE_CID_MASK);
-			iscsi_conn_failure(beiscsi_conn->conn,
-					   ISCSI_ERR_CONN_FAILED);
+					code, cid);
+			if (beiscsi_conn)
+				iscsi_conn_failure(beiscsi_conn->conn,
+						ISCSI_ERR_CONN_FAILED);
+			else
+				beiscsi_ep_cleanup(beiscsi_ep,
+						BEISCSI_NO_RST_ISSUE,
+						CONNECTION_UPLOAD_ABORT);
 			break;
 		default:
 			beiscsi_log(phba, KERN_ERR,
 					BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
 					"BM_%d : CQ Error Invalid code= %d "
 					"received on CID 0x%x...\n",
-					sol->dw[offsetof(struct amap_sol_cqe,
-						code) / 32] & CQE_CODE_MASK,
-					sol->dw[offsetof(struct amap_sol_cqe,
-						cid) / 32] & CQE_CID_MASK);
-			break;
+					code, cid);
+					break;
 		}
 
 		AMAP_SET_BITS(struct amap_sol_cqe, valid, sol, 0);
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index f5b0074..9b0f299 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -108,6 +108,7 @@ unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
 					 struct bsg_job *job,
 					 struct be_dma_mem *nonemb_cmd);
 
+#define BEISCSI_NO_RST_ISSUE	0
 struct iscsi_invalidate_connection_params_in {
 	struct be_cmd_req_hdr hdr;
 	unsigned int session_handle;
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux