diff options
Diffstat (limited to 'drivers/target/iscsi/iscsi_target.c')
| -rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 253 | 
1 files changed, 154 insertions, 99 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 35b61f7d6c6..1f4c794f5fc 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -52,7 +52,7 @@  static LIST_HEAD(g_tiqn_list);  static LIST_HEAD(g_np_list);  static DEFINE_SPINLOCK(tiqn_lock); -static DEFINE_SPINLOCK(np_lock); +static DEFINE_MUTEX(np_lock);  static struct idr tiqn_idr;  struct idr sess_idr; @@ -300,13 +300,16 @@ bool iscsit_check_np_match(  		port = ntohs(sock_in->sin_port);  	} -	if ((ip_match == true) && (np->np_port == port) && +	if (ip_match && (np->np_port == port) &&  	    (np->np_network_transport == network_transport))  		return true;  	return false;  } +/* + * Called with mutex np_lock held + */  static struct iscsi_np *iscsit_get_np(  	struct __kernel_sockaddr_storage *sockaddr,  	int network_transport) @@ -314,29 +317,26 @@ static struct iscsi_np *iscsit_get_np(  	struct iscsi_np *np;  	bool match; -	spin_lock_bh(&np_lock);  	list_for_each_entry(np, &g_np_list, np_list) { -		spin_lock(&np->np_thread_lock); +		spin_lock_bh(&np->np_thread_lock);  		if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { -			spin_unlock(&np->np_thread_lock); +			spin_unlock_bh(&np->np_thread_lock);  			continue;  		}  		match = iscsit_check_np_match(sockaddr, np, network_transport); -		if (match == true) { +		if (match) {  			/*  			 * Increment the np_exports reference count now to  			 * prevent iscsit_del_np() below from being called  			 * while iscsi_tpg_add_network_portal() is called.  			 */  			np->np_exports++; -			spin_unlock(&np->np_thread_lock); -			spin_unlock_bh(&np_lock); +			spin_unlock_bh(&np->np_thread_lock);  			return np;  		} -		spin_unlock(&np->np_thread_lock); +		spin_unlock_bh(&np->np_thread_lock);  	} -	spin_unlock_bh(&np_lock);  	return NULL;  } @@ -350,16 +350,22 @@ struct iscsi_np *iscsit_add_np(  	struct sockaddr_in6 *sock_in6;  	struct iscsi_np *np;  	int ret; + +	mutex_lock(&np_lock); +  	/*  	 * Locate the existing struct iscsi_np if already active..  	 */  	np = iscsit_get_np(sockaddr, network_transport); -	if (np) +	if (np) { +		mutex_unlock(&np_lock);  		return np; +	}  	np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL);  	if (!np) {  		pr_err("Unable to allocate memory for struct iscsi_np\n"); +		mutex_unlock(&np_lock);  		return ERR_PTR(-ENOMEM);  	} @@ -382,6 +388,7 @@ struct iscsi_np *iscsit_add_np(  	ret = iscsi_target_setup_login_socket(np, sockaddr);  	if (ret != 0) {  		kfree(np); +		mutex_unlock(&np_lock);  		return ERR_PTR(ret);  	} @@ -390,6 +397,7 @@ struct iscsi_np *iscsit_add_np(  		pr_err("Unable to create kthread: iscsi_np\n");  		ret = PTR_ERR(np->np_thread);  		kfree(np); +		mutex_unlock(&np_lock);  		return ERR_PTR(ret);  	}  	/* @@ -400,10 +408,10 @@ struct iscsi_np *iscsit_add_np(  	 * point because iscsi_np has not been added to g_np_list yet.  	 */  	np->np_exports = 1; +	np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; -	spin_lock_bh(&np_lock);  	list_add_tail(&np->np_list, &g_np_list); -	spin_unlock_bh(&np_lock); +	mutex_unlock(&np_lock);  	pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",  		np->np_ip, np->np_port, np->np_transport->name); @@ -452,6 +460,7 @@ int iscsit_del_np(struct iscsi_np *np)  	spin_lock_bh(&np->np_thread_lock);  	np->np_exports--;  	if (np->np_exports) { +		np->enabled = true;  		spin_unlock_bh(&np->np_thread_lock);  		return 0;  	} @@ -465,13 +474,14 @@ int iscsit_del_np(struct iscsi_np *np)  		 */  		send_sig(SIGINT, np->np_thread, 1);  		kthread_stop(np->np_thread); +		np->np_thread = NULL;  	}  	np->np_transport->iscsit_free_np(np); -	spin_lock_bh(&np_lock); +	mutex_lock(&np_lock);  	list_del(&np->np_list); -	spin_unlock_bh(&np_lock); +	mutex_unlock(&np_lock);  	pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",  		np->np_ip, np->np_port, np->np_transport->name); @@ -490,6 +500,23 @@ static int iscsit_queue_rsp(struct iscsi_conn *conn, struct iscsi_cmd *cmd)  	return 0;  } +static void iscsit_aborted_task(struct iscsi_conn *conn, struct iscsi_cmd *cmd) +{ +	bool scsi_cmd = (cmd->iscsi_opcode == ISCSI_OP_SCSI_CMD); + +	spin_lock_bh(&conn->cmd_lock); +	if (!list_empty(&cmd->i_conn_node)) +		list_del_init(&cmd->i_conn_node); +	spin_unlock_bh(&conn->cmd_lock); + +	__iscsit_free_cmd(cmd, scsi_cmd, true); +} + +static enum target_prot_op iscsit_get_sup_prot_ops(struct iscsi_conn *conn) +{ +	return TARGET_PROT_NORMAL; +} +  static struct iscsit_transport iscsi_target_transport = {  	.name			= "iSCSI/TCP",  	.transport_type		= ISCSI_TCP, @@ -504,6 +531,8 @@ static struct iscsit_transport iscsi_target_transport = {  	.iscsit_response_queue	= iscsit_response_queue,  	.iscsit_queue_data_in	= iscsit_queue_rsp,  	.iscsit_queue_status	= iscsit_queue_rsp, +	.iscsit_aborted_task	= iscsit_aborted_task, +	.iscsit_get_sup_prot_ops = iscsit_get_sup_prot_ops,  };  static int __init iscsi_target_init_module(void) @@ -621,7 +650,7 @@ static int iscsit_add_reject(  {  	struct iscsi_cmd *cmd; -	cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); +	cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);  	if (!cmd)  		return -1; @@ -753,7 +782,8 @@ static void iscsit_unmap_iovec(struct iscsi_cmd *cmd)  static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)  { -	struct iscsi_cmd *cmd; +	LIST_HEAD(ack_list); +	struct iscsi_cmd *cmd, *cmd_p;  	conn->exp_statsn = exp_statsn; @@ -761,19 +791,23 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)  		return;  	spin_lock_bh(&conn->cmd_lock); -	list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { +	list_for_each_entry_safe(cmd, cmd_p, &conn->conn_cmd_list, i_conn_node) {  		spin_lock(&cmd->istate_lock);  		if ((cmd->i_state == ISTATE_SENT_STATUS) &&  		    iscsi_sna_lt(cmd->stat_sn, exp_statsn)) {  			cmd->i_state = ISTATE_REMOVE;  			spin_unlock(&cmd->istate_lock); -			iscsit_add_cmd_to_immediate_queue(cmd, conn, -						cmd->i_state); +			list_move_tail(&cmd->i_conn_node, &ack_list);  			continue;  		}  		spin_unlock(&cmd->istate_lock);  	}  	spin_unlock_bh(&conn->cmd_lock); + +	list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) { +		list_del_init(&cmd->i_conn_node); +		iscsit_free_cmd(cmd, false); +	}  }  static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd) @@ -800,14 +834,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	int iscsi_task_attr;  	int sam_task_attr; -	spin_lock_bh(&conn->sess->session_stats_lock); -	conn->sess->cmd_pdus++; -	if (conn->sess->se_sess->se_node_acl) { -		spin_lock(&conn->sess->se_sess->se_node_acl->stats_lock); -		conn->sess->se_sess->se_node_acl->num_cmds++; -		spin_unlock(&conn->sess->se_sess->se_node_acl->stats_lock); -	} -	spin_unlock_bh(&conn->sess->session_stats_lock); +	atomic_long_inc(&conn->sess->cmd_pdus);  	hdr			= (struct iscsi_scsi_req *) buf;  	payload_length		= ntoh24(hdr->dlength); @@ -825,24 +852,22 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	if (((hdr->flags & ISCSI_FLAG_CMD_READ) ||  	     (hdr->flags & ISCSI_FLAG_CMD_WRITE)) && !hdr->data_length) {  		/* -		 * Vmware ESX v3.0 uses a modified Cisco Initiator (v3.4.2) -		 * that adds support for RESERVE/RELEASE.  There is a bug -		 * add with this new functionality that sets R/W bits when -		 * neither CDB carries any READ or WRITE datapayloads. +		 * From RFC-3720 Section 10.3.1: +		 * +		 * "Either or both of R and W MAY be 1 when either the +		 *  Expected Data Transfer Length and/or Bidirectional Read +		 *  Expected Data Transfer Length are 0" +		 * +		 * For this case, go ahead and clear the unnecssary bits +		 * to avoid any confusion with ->data_direction.  		 */ -		if ((hdr->cdb[0] == 0x16) || (hdr->cdb[0] == 0x17)) { -			hdr->flags &= ~ISCSI_FLAG_CMD_READ; -			hdr->flags &= ~ISCSI_FLAG_CMD_WRITE; -			goto done; -		} +		hdr->flags &= ~ISCSI_FLAG_CMD_READ; +		hdr->flags &= ~ISCSI_FLAG_CMD_WRITE; -		pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE" +		pr_warn("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE"  			" set when Expected Data Transfer Length is 0 for" -			" CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]); -		return iscsit_add_reject_cmd(cmd, -					     ISCSI_REASON_BOOKMARK_INVALID, buf); +			" CDB: 0x%02x, Fixing up flags\n", hdr->cdb[0]);  	} -done:  	if (!(hdr->flags & ISCSI_FLAG_CMD_READ) &&  	    !(hdr->flags & ISCSI_FLAG_CMD_WRITE) && (hdr->data_length != 0)) { @@ -1096,7 +1121,7 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,  	/*  	 * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.  	 */ -	if (dump_payload == true) +	if (dump_payload)  		goto after_immediate_data;  	immed_ret = iscsit_handle_immediate_data(cmd, hdr, @@ -1249,20 +1274,12 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,  	int rc;  	if (!payload_length) { -		pr_err("DataOUT payload is ZERO, protocol error.\n"); -		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, -					 buf); +		pr_warn("DataOUT payload is ZERO, ignoring.\n"); +		return 0;  	}  	/* iSCSI write */ -	spin_lock_bh(&conn->sess->session_stats_lock); -	conn->sess->rx_data_octets += payload_length; -	if (conn->sess->se_sess->se_node_acl) { -		spin_lock(&conn->sess->se_sess->se_node_acl->stats_lock); -		conn->sess->se_sess->se_node_acl->write_bytes += payload_length; -		spin_unlock(&conn->sess->se_sess->se_node_acl->stats_lock); -	} -	spin_unlock_bh(&conn->sess->session_stats_lock); +	atomic_long_add(payload_length, &conn->sess->rx_data_octets);  	if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {  		pr_err("DataSegmentLength: %u is greater than" @@ -1292,7 +1309,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,  	if (cmd->data_direction != DMA_TO_DEVICE) {  		pr_err("Command ITT: 0x%08x received DataOUT for a"  			" NON-WRITE command.\n", cmd->init_task_tag); -		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf); +		return iscsit_dump_data_payload(conn, payload_length, 1);  	}  	se_cmd = &cmd->se_cmd;  	iscsit_mod_dataout_timer(cmd); @@ -1481,7 +1498,7 @@ EXPORT_SYMBOL(iscsit_check_dataout_payload);  static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)  { -	struct iscsi_cmd *cmd; +	struct iscsi_cmd *cmd = NULL;  	struct iscsi_data *hdr = (struct iscsi_data *)buf;  	int rc;  	bool data_crc_failed = false; @@ -1506,6 +1523,16 @@ int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  {  	u32 payload_length = ntoh24(hdr->dlength); +	if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL)) { +		pr_err("NopOUT Flag's, Left Most Bit not set, protocol error.\n"); +		if (!cmd) +			return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, +						 (unsigned char *)hdr); +		 +		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, +					 (unsigned char *)hdr); +	} +  	if (hdr->itt == RESERVED_ITT && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {  		pr_err("NOPOUT ITT is reserved, but Immediate Bit is"  			" not set, protocol error.\n"); @@ -1567,7 +1594,9 @@ int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	 * Initiator is expecting a NopIN ping reply..  	 */  	if (hdr->itt != RESERVED_ITT) { -		BUG_ON(!cmd); +		if (!cmd) +			return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, +						(unsigned char *)hdr);  		spin_lock_bh(&conn->cmd_lock);  		list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); @@ -1949,6 +1978,13 @@ iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  					 (unsigned char *)hdr);  	} +	if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL) || +	     (hdr->flags & ISCSI_FLAG_TEXT_CONTINUE)) { +		pr_err("Multi sequence text commands currently not supported\n"); +		return iscsit_reject_cmd(cmd, ISCSI_REASON_CMD_NOT_SUPPORTED, +					(unsigned char *)hdr); +	} +  	pr_debug("Got Text Request: ITT: 0x%08x, CmdSN: 0x%08x,"  		" ExpStatSN: 0x%08x, Length: %u\n", hdr->itt, hdr->cmdsn,  		hdr->exp_statsn, payload_length); @@ -2464,6 +2500,7 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)  {  	struct iscsi_cmd *cmd;  	struct iscsi_conn *conn_p; +	bool found = false;  	/*  	 * Only send a Asynchronous Message on connections whos network @@ -2472,14 +2509,15 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)  	list_for_each_entry(conn_p, &conn->sess->sess_conn_list, conn_list) {  		if (conn_p->conn_state == TARG_CONN_STATE_LOGGED_IN) {  			iscsit_inc_conn_usage_count(conn_p); +			found = true;  			break;  		}  	} -	if (!conn_p) +	if (!found)  		return; -	cmd = iscsit_allocate_cmd(conn_p, GFP_ATOMIC); +	cmd = iscsit_allocate_cmd(conn_p, TASK_RUNNING);  	if (!cmd) {  		iscsit_dec_conn_usage_count(conn_p);  		return; @@ -2625,14 +2663,7 @@ static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn)  		return -1;  	} -	spin_lock_bh(&conn->sess->session_stats_lock); -	conn->sess->tx_data_octets += datain.length; -	if (conn->sess->se_sess->se_node_acl) { -		spin_lock(&conn->sess->se_sess->se_node_acl->stats_lock); -		conn->sess->se_sess->se_node_acl->read_bytes += datain.length; -		spin_unlock(&conn->sess->se_sess->se_node_acl->stats_lock); -	} -	spin_unlock_bh(&conn->sess->session_stats_lock); +	atomic_long_add(datain.length, &conn->sess->tx_data_octets);  	/*  	 * Special case for successfully execution w/ both DATAIN  	 * and Sense Data. @@ -3157,9 +3188,7 @@ void iscsit_build_rsp_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn,  	if (inc_stat_sn)  		cmd->stat_sn = conn->stat_sn++; -	spin_lock_bh(&conn->sess->session_stats_lock); -	conn->sess->rsp_pdus++; -	spin_unlock_bh(&conn->sess->session_stats_lock); +	atomic_long_inc(&conn->sess->rsp_pdus);  	memset(hdr, 0, ISCSI_HDR_LEN);  	hdr->opcode		= ISCSI_OP_SCSI_CMD_RSP; @@ -3361,7 +3390,9 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np)  #define SENDTARGETS_BUF_LIMIT 32768U -static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) +static int +iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, +				  enum iscsit_transport_type network_transport)  {  	char *payload = NULL;  	struct iscsi_conn *conn = cmd->conn; @@ -3369,6 +3400,7 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)  	struct iscsi_tiqn *tiqn;  	struct iscsi_tpg_np *tpg_np;  	int buffer_len, end_of_buf = 0, len = 0, payload_len = 0; +	int target_name_printed;  	unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */  	unsigned char *text_in = cmd->text_in_ptr, *text_ptr = NULL; @@ -3406,19 +3438,23 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)  			continue;  		} -		len = sprintf(buf, "TargetName=%s", tiqn->tiqn); -		len += 1; - -		if ((len + payload_len) > buffer_len) { -			end_of_buf = 1; -			goto eob; -		} -		memcpy(payload + payload_len, buf, len); -		payload_len += len; +		target_name_printed = 0;  		spin_lock(&tiqn->tiqn_tpg_lock);  		list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) { +			/* If demo_mode_discovery=0 and generate_node_acls=0 +			 * (demo mode dislabed) do not return +			 * TargetName+TargetAddress unless a NodeACL exists. +			 */ + +			if ((tpg->tpg_attrib.generate_node_acls == 0) && +			    (tpg->tpg_attrib.demo_mode_discovery == 0) && +			    (!core_tpg_get_initiator_node_acl(&tpg->tpg_se_tpg, +				cmd->conn->sess->sess_ops->InitiatorName))) { +				continue; +			} +  			spin_lock(&tpg->tpg_state_lock);  			if ((tpg->tpg_state == TPG_STATE_FREE) ||  			    (tpg->tpg_state == TPG_STATE_INACTIVE)) { @@ -3433,12 +3469,29 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)  				struct iscsi_np *np = tpg_np->tpg_np;  				bool inaddr_any = iscsit_check_inaddr_any(np); +				if (np->np_network_transport != network_transport) +					continue; + +				if (!target_name_printed) { +					len = sprintf(buf, "TargetName=%s", +						      tiqn->tiqn); +					len += 1; + +					if ((len + payload_len) > buffer_len) { +						spin_unlock(&tpg->tpg_np_lock); +						spin_unlock(&tiqn->tiqn_tpg_lock); +						end_of_buf = 1; +						goto eob; +					} +					memcpy(payload + payload_len, buf, len); +					payload_len += len; +					target_name_printed = 1; +				} +  				len = sprintf(buf, "TargetAddress="  					"%s:%hu,%hu", -					(inaddr_any == false) ? -						np->np_ip : conn->local_ip, -					(inaddr_any == false) ? -						np->np_port : conn->local_port, +					inaddr_any ? conn->local_ip : np->np_ip, +					inaddr_any ? conn->local_port : np->np_port,  					tpg->tpgt);  				len += 1; @@ -3470,11 +3523,12 @@ eob:  int  iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, -		      struct iscsi_text_rsp *hdr) +		      struct iscsi_text_rsp *hdr, +		      enum iscsit_transport_type network_transport)  {  	int text_length, padding; -	text_length = iscsit_build_sendtargets_response(cmd); +	text_length = iscsit_build_sendtargets_response(cmd, network_transport);  	if (text_length < 0)  		return text_length; @@ -3512,7 +3566,7 @@ static int iscsit_send_text_rsp(  	u32 tx_size = 0;  	int text_length, iov_count = 0, rc; -	rc = iscsit_build_text_rsp(cmd, conn, hdr); +	rc = iscsit_build_text_rsp(cmd, conn, hdr, ISCSI_TCP);  	if (rc < 0)  		return rc; @@ -3692,7 +3746,7 @@ iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state  		break;  	case ISTATE_REMOVE:  		spin_lock_bh(&conn->cmd_lock); -		list_del(&cmd->i_conn_node); +		list_del_init(&cmd->i_conn_node);  		spin_unlock_bh(&conn->cmd_lock);  		iscsit_free_cmd(cmd, false); @@ -3943,7 +3997,7 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)  	switch (hdr->opcode & ISCSI_OPCODE_MASK) {  	case ISCSI_OP_SCSI_CMD: -		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); +		cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);  		if (!cmd)  			goto reject; @@ -3955,28 +4009,28 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)  	case ISCSI_OP_NOOP_OUT:  		cmd = NULL;  		if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { -			cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); +			cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);  			if (!cmd)  				goto reject;  		}  		ret = iscsit_handle_nop_out(conn, cmd, buf);  		break;  	case ISCSI_OP_SCSI_TMFUNC: -		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); +		cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);  		if (!cmd)  			goto reject;  		ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);  		break;  	case ISCSI_OP_TEXT: -		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); +		cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);  		if (!cmd)  			goto reject;  		ret = iscsit_handle_text_cmd(conn, cmd, buf);  		break;  	case ISCSI_OP_LOGOUT: -		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); +		cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);  		if (!cmd)  			goto reject; @@ -4087,9 +4141,7 @@ restart:  				 * hit default in the switch below.  				 */  				memset(buffer, 0xff, ISCSI_HDR_LEN); -				spin_lock_bh(&conn->sess->session_stats_lock); -				conn->sess->conn_digest_errors++; -				spin_unlock_bh(&conn->sess->session_stats_lock); +				atomic_long_inc(&conn->sess->conn_digest_errors);  			} else {  				pr_debug("Got HeaderDigest CRC32C"  						" 0x%08x\n", checksum); @@ -4137,7 +4189,7 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)  	spin_lock_bh(&conn->cmd_lock);  	list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) { -		list_del(&cmd->i_conn_node); +		list_del_init(&cmd->i_conn_node);  		spin_unlock_bh(&conn->cmd_lock);  		iscsit_increment_maxcmdsn(cmd, sess); @@ -4182,7 +4234,9 @@ int iscsit_close_connection(  	iscsit_stop_timers_for_cmds(conn);  	iscsit_stop_nopin_response_timer(conn);  	iscsit_stop_nopin_timer(conn); -	iscsit_free_queue_reqs_for_conn(conn); + +	if (conn->conn_transport->iscsit_wait_conn) +		conn->conn_transport->iscsit_wait_conn(conn);  	/*  	 * During Connection recovery drop unacknowledged out of order @@ -4200,6 +4254,7 @@ int iscsit_close_connection(  		iscsit_clear_ooo_cmdsns_for_conn(conn);  		iscsit_release_commands_from_conn(conn);  	} +	iscsit_free_queue_reqs_for_conn(conn);  	/*  	 * Handle decrementing session or connection usage count if @@ -4376,7 +4431,7 @@ int iscsit_close_connection(  int iscsit_close_session(struct iscsi_session *sess)  { -	struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess); +	struct iscsi_portal_group *tpg = sess->tpg;  	struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;  	if (atomic_read(&sess->nconn)) {  | 
