diff options
Diffstat (limited to 'drivers/target')
23 files changed, 877 insertions, 847 deletions
| diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index d7705e5824fb..f73da43cdf9e 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -628,25 +628,18 @@ static void __exit iscsi_target_cleanup_module(void)  }  static int iscsit_add_reject( +	struct iscsi_conn *conn,  	u8 reason, -	int fail_conn, -	unsigned char *buf, -	struct iscsi_conn *conn) +	unsigned char *buf)  {  	struct iscsi_cmd *cmd; -	struct iscsi_reject *hdr; -	int ret;  	cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);  	if (!cmd)  		return -1;  	cmd->iscsi_opcode = ISCSI_OP_REJECT; -	if (fail_conn) -		cmd->cmd_flags |= ICF_REJECT_FAIL_CONN; - -	hdr	= (struct iscsi_reject *) cmd->pdu; -	hdr->reason = reason; +	cmd->reject_reason = reason;  	cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);  	if (!cmd->buf_ptr) { @@ -662,23 +655,16 @@ static int iscsit_add_reject(  	cmd->i_state = ISTATE_SEND_REJECT;  	iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); -	ret = wait_for_completion_interruptible(&cmd->reject_comp); -	if (ret != 0) -		return -1; - -	return (!fail_conn) ? 0 : -1; +	return -1;  } -int iscsit_add_reject_from_cmd( +static int iscsit_add_reject_from_cmd( +	struct iscsi_cmd *cmd,  	u8 reason, -	int fail_conn, -	int add_to_conn, -	unsigned char *buf, -	struct iscsi_cmd *cmd) +	bool add_to_conn, +	unsigned char *buf)  {  	struct iscsi_conn *conn; -	struct iscsi_reject *hdr; -	int ret;  	if (!cmd->conn) {  		pr_err("cmd->conn is NULL for ITT: 0x%08x\n", @@ -688,11 +674,7 @@ int iscsit_add_reject_from_cmd(  	conn = cmd->conn;  	cmd->iscsi_opcode = ISCSI_OP_REJECT; -	if (fail_conn) -		cmd->cmd_flags |= ICF_REJECT_FAIL_CONN; - -	hdr	= (struct iscsi_reject *) cmd->pdu; -	hdr->reason = reason; +	cmd->reject_reason = reason;  	cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);  	if (!cmd->buf_ptr) { @@ -709,8 +691,6 @@ int iscsit_add_reject_from_cmd(  	cmd->i_state = ISTATE_SEND_REJECT;  	iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - -	ret = wait_for_completion_interruptible(&cmd->reject_comp);  	/*  	 * Perform the kref_put now if se_cmd has already been setup by  	 * scsit_setup_scsi_cmd() @@ -719,12 +699,19 @@ int iscsit_add_reject_from_cmd(  		pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");  		target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);  	} -	if (ret != 0) -		return -1; +	return -1; +} -	return (!fail_conn) ? 0 : -1; +static int iscsit_add_reject_cmd(struct iscsi_cmd *cmd, u8 reason, +				 unsigned char *buf) +{ +	return iscsit_add_reject_from_cmd(cmd, reason, true, buf); +} + +int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8 reason, unsigned char *buf) +{ +	return iscsit_add_reject_from_cmd(cmd, reason, false, buf);  } -EXPORT_SYMBOL(iscsit_add_reject_from_cmd);  /*   * Map some portion of the allocated scatterlist to an iovec, suitable for @@ -844,8 +831,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	    !(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {  		pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL"  				" not set. Bad iSCSI Initiator.\n"); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, -				1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_BOOKMARK_INVALID, buf);  	}  	if (((hdr->flags & ISCSI_FLAG_CMD_READ) || @@ -865,8 +852,8 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  		pr_err("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_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, -				1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_BOOKMARK_INVALID, buf);  	}  done: @@ -875,62 +862,62 @@ done:  		pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE"  			" MUST be set if Expected Data Transfer Length is not 0."  			" Bad iSCSI Initiator\n"); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, -				1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_BOOKMARK_INVALID, buf);  	}  	if ((hdr->flags & ISCSI_FLAG_CMD_READ) &&  	    (hdr->flags & ISCSI_FLAG_CMD_WRITE)) {  		pr_err("Bidirectional operations not supported!\n"); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, -				1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_BOOKMARK_INVALID, buf);  	}  	if (hdr->opcode & ISCSI_OP_IMMEDIATE) {  		pr_err("Illegally set Immediate Bit in iSCSI Initiator"  				" Scsi Command PDU.\n"); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, -				1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_BOOKMARK_INVALID, buf);  	}  	if (payload_length && !conn->sess->sess_ops->ImmediateData) {  		pr_err("ImmediateData=No but DataSegmentLength=%u,"  			" protocol error.\n", payload_length); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, -				1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_PROTOCOL_ERROR, buf);  	} -	if ((be32_to_cpu(hdr->data_length )== payload_length) && +	if ((be32_to_cpu(hdr->data_length) == payload_length) &&  	    (!(hdr->flags & ISCSI_FLAG_CMD_FINAL))) {  		pr_err("Expected Data Transfer Length and Length of"  			" Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL"  			" bit is not set protocol error\n"); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, -				1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_PROTOCOL_ERROR, buf);  	}  	if (payload_length > be32_to_cpu(hdr->data_length)) {  		pr_err("DataSegmentLength: %u is greater than"  			" EDTL: %u, protocol error.\n", payload_length,  				hdr->data_length); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, -				1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_PROTOCOL_ERROR, buf);  	}  	if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {  		pr_err("DataSegmentLength: %u is greater than"  			" MaxXmitDataSegmentLength: %u, protocol error.\n",  			payload_length, conn->conn_ops->MaxXmitDataSegmentLength); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, -				1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_PROTOCOL_ERROR, buf);  	}  	if (payload_length > conn->sess->sess_ops->FirstBurstLength) {  		pr_err("DataSegmentLength: %u is greater than"  			" FirstBurstLength: %u, protocol error.\n",  			payload_length, conn->sess->sess_ops->FirstBurstLength); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, -				1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_BOOKMARK_INVALID, buf);  	}  	data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE : @@ -985,9 +972,8 @@ done:  		dr = iscsit_allocate_datain_req();  		if (!dr) -			return iscsit_add_reject_from_cmd( -					ISCSI_REASON_BOOKMARK_NO_RESOURCES, -					1, 1, buf, cmd); +			return iscsit_add_reject_cmd(cmd, +					ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);  		iscsit_attach_datain_req(cmd, dr);  	} @@ -1015,18 +1001,16 @@ done:  	cmd->sense_reason = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb);  	if (cmd->sense_reason) {  		if (cmd->sense_reason == TCM_OUT_OF_RESOURCES) { -			return iscsit_add_reject_from_cmd( -					ISCSI_REASON_BOOKMARK_NO_RESOURCES, -					1, 1, buf, cmd); +			return iscsit_add_reject_cmd(cmd, +					ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);  		}  		goto attach_cmd;  	}  	if (iscsit_build_pdu_and_seq_lists(cmd, payload_length) < 0) { -		return iscsit_add_reject_from_cmd( -			ISCSI_REASON_BOOKMARK_NO_RESOURCES, -			1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +				ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);  	}  attach_cmd: @@ -1068,17 +1052,13 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	 * be acknowledged. (See below)  	 */  	if (!cmd->immediate_data) { -		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); -		if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { -			if (!cmd->sense_reason) -				return 0; - +		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, +					(unsigned char *)hdr, hdr->cmdsn); +		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) +			return -1; +		else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {  			target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);  			return 0; -		} else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) { -			return iscsit_add_reject_from_cmd( -				ISCSI_REASON_PROTOCOL_ERROR, -				1, 0, (unsigned char *)hdr, cmd);  		}  	} @@ -1103,6 +1083,9 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	 * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below.  	 */  	if (cmd->sense_reason) { +		if (cmd->reject_reason) +			return 0; +  		target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);  		return 1;  	} @@ -1111,10 +1094,8 @@ int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	 * the backend memory allocation.  	 */  	cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd); -	if (cmd->sense_reason) { -		target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); +	if (cmd->sense_reason)  		return 1; -	}  	return 0;  } @@ -1124,6 +1105,7 @@ static int  iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,  			  bool dump_payload)  { +	struct iscsi_conn *conn = cmd->conn;  	int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;  	/*  	 * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. @@ -1140,20 +1122,25 @@ after_immediate_data:  		 * DataCRC, check against ExpCmdSN/MaxCmdSN if  		 * Immediate Bit is not set.  		 */ -		cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, hdr->cmdsn); +		cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, +					(unsigned char *)hdr, hdr->cmdsn); +		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) { +			return -1; +		} else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { +			target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); +			return 0; +		}  		if (cmd->sense_reason) { -			if (iscsit_dump_data_payload(cmd->conn, -					cmd->first_burst_len, 1) < 0) -				return -1; +			int rc; + +			rc = iscsit_dump_data_payload(cmd->conn, +						      cmd->first_burst_len, 1); +			target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); +			return rc;  		} else if (cmd->unsolicited_data)  			iscsit_set_unsoliticed_dataout(cmd); -		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) -			return iscsit_add_reject_from_cmd( -				ISCSI_REASON_PROTOCOL_ERROR, -				1, 0, (unsigned char *)hdr, cmd); -  	} else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {  		/*  		 * Immediate Data failed DataCRC and ERL>=1, @@ -1184,15 +1171,14 @@ iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	rc = iscsit_setup_scsi_cmd(conn, cmd, buf);  	if (rc < 0) -		return rc; +		return 0;  	/*  	 * Allocation iovecs needed for struct socket operations for  	 * traditional iSCSI block I/O.  	 */  	if (iscsit_allocate_iovecs(cmd) < 0) { -		return iscsit_add_reject_from_cmd( -				ISCSI_REASON_BOOKMARK_NO_RESOURCES, -				1, 0, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +				ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);  	}  	immed_data = cmd->immediate_data; @@ -1277,14 +1263,13 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,  	struct iscsi_data *hdr = (struct iscsi_data *)buf;  	struct iscsi_cmd *cmd = NULL;  	struct se_cmd *se_cmd; -	unsigned long flags;  	u32 payload_length = ntoh24(hdr->dlength);  	int rc;  	if (!payload_length) {  		pr_err("DataOUT payload is ZERO, protocol error.\n"); -		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, -					buf, conn); +		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, +					 buf);  	}  	/* iSCSI write */ @@ -1301,8 +1286,8 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,  		pr_err("DataSegmentLength: %u is greater than"  			" MaxXmitDataSegmentLength: %u\n", payload_length,  			conn->conn_ops->MaxXmitDataSegmentLength); -		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, -					buf, conn); +		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, +					 buf);  	}  	cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, @@ -1325,8 +1310,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_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, -				1, 0, buf, cmd); +		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);  	}  	se_cmd = &cmd->se_cmd;  	iscsit_mod_dataout_timer(cmd); @@ -1335,8 +1319,7 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,  		pr_err("DataOut Offset: %u, Length %u greater than"  			" iSCSI Command EDTL %u, protocol error.\n",  			hdr->offset, payload_length, cmd->se_cmd.data_length); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, -				1, 0, buf, cmd); +		return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID, buf);  	}  	if (cmd->unsolicited_data) { @@ -1356,14 +1339,9 @@ iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,  		 */  		/* Something's amiss if we're not in WRITE_PENDING state... */ -		spin_lock_irqsave(&se_cmd->t_state_lock, flags);  		WARN_ON(se_cmd->t_state != TRANSPORT_WRITE_PENDING); -		spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - -		spin_lock_irqsave(&se_cmd->t_state_lock, flags);  		if (!(se_cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE))  			dump_unsolicited_data = 1; -		spin_unlock_irqrestore(&se_cmd->t_state_lock, flags);  		if (dump_unsolicited_data) {  			/* @@ -1528,7 +1506,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)  	rc = iscsit_check_dataout_hdr(conn, buf, &cmd);  	if (rc < 0) -		return rc; +		return 0;  	else if (!cmd)  		return 0; @@ -1541,24 +1519,16 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)  	return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed);  } -int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, -			unsigned char *buf) +int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, +			 struct iscsi_nopout *hdr)  { -	unsigned char *ping_data = NULL; -	int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size; -	u32 checksum, data_crc, padding = 0, payload_length; -	struct iscsi_cmd *cmd_p = NULL; -	struct kvec *iov = NULL; -	struct iscsi_nopout *hdr; - -	hdr			= (struct iscsi_nopout *) buf; -	payload_length		= ntoh24(hdr->dlength); +	u32 payload_length = ntoh24(hdr->dlength);  	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"); -		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, -					buf, conn); +		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, +					 (unsigned char *)hdr);  	}  	if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) { @@ -1566,8 +1536,8 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  			" greater than MaxXmitDataSegmentLength: %u, protocol"  			" error.\n", payload_length,  			conn->conn_ops->MaxXmitDataSegmentLength); -		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, -					buf, conn); +		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, +					 (unsigned char *)hdr);  	}  	pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x," @@ -1583,11 +1553,6 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	 * can contain ping data.  	 */  	if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { -		if (!cmd) -			return iscsit_add_reject( -					ISCSI_REASON_BOOKMARK_NO_RESOURCES, -					1, buf, conn); -  		cmd->iscsi_opcode	= ISCSI_OP_NOOP_OUT;  		cmd->i_state		= ISTATE_SEND_NOPIN;  		cmd->immediate_cmd	= ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? @@ -1599,8 +1564,85 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  		cmd->data_direction	= DMA_NONE;  	} +	return 0; +} +EXPORT_SYMBOL(iscsit_setup_nop_out); + +int iscsit_process_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, +			   struct iscsi_nopout *hdr) +{ +	struct iscsi_cmd *cmd_p = NULL; +	int cmdsn_ret = 0; +	/* +	 * Initiator is expecting a NopIN ping reply.. +	 */ +	if (hdr->itt != RESERVED_ITT) { +		BUG_ON(!cmd); + +		spin_lock_bh(&conn->cmd_lock); +		list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); +		spin_unlock_bh(&conn->cmd_lock); + +		iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); + +		if (hdr->opcode & ISCSI_OP_IMMEDIATE) { +			iscsit_add_cmd_to_response_queue(cmd, conn, +							 cmd->i_state); +			return 0; +		} + +		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, +				(unsigned char *)hdr, hdr->cmdsn); +                if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) +			return 0; +		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) +			return -1; + +		return 0; +	} +	/* +	 * This was a response to a unsolicited NOPIN ping. +	 */ +	if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) { +		cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt)); +		if (!cmd_p) +			return -EINVAL; + +		iscsit_stop_nopin_response_timer(conn); + +		cmd_p->i_state = ISTATE_REMOVE; +		iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state); + +		iscsit_start_nopin_timer(conn); +		return 0; +	} +	/* +	 * Otherwise, initiator is not expecting a NOPIN is response. +	 * Just ignore for now. +	 */ +        return 0; +} +EXPORT_SYMBOL(iscsit_process_nop_out); + +static int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, +				 unsigned char *buf) +{ +	unsigned char *ping_data = NULL; +	struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf; +	struct kvec *iov = NULL; +	u32 payload_length = ntoh24(hdr->dlength); +	int ret; + +	ret = iscsit_setup_nop_out(conn, cmd, hdr); +	if (ret < 0) +		return 0; +	/* +	 * Handle NOP-OUT payload for traditional iSCSI sockets +	 */  	if (payload_length && hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { -		rx_size = payload_length; +		u32 checksum, data_crc, padding = 0; +		int niov = 0, rx_got, rx_size = payload_length; +  		ping_data = kzalloc(payload_length + 1, GFP_KERNEL);  		if (!ping_data) {  			pr_err("Unable to allocate memory for" @@ -1679,76 +1721,14 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  		pr_debug("Ping Data: \"%s\"\n", ping_data);  	} -	if (hdr->itt != RESERVED_ITT) { -		if (!cmd) { -			pr_err("Checking CmdSN for NOPOUT," -				" but cmd is NULL!\n"); -			return -1; -		} -		/* -		 * Initiator is expecting a NopIN ping reply, -		 */ -		spin_lock_bh(&conn->cmd_lock); -		list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); -		spin_unlock_bh(&conn->cmd_lock); - -		iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); - -		if (hdr->opcode & ISCSI_OP_IMMEDIATE) { -			iscsit_add_cmd_to_response_queue(cmd, conn, -					cmd->i_state); -			return 0; -		} - -		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); -		if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { -			ret = 0; -			goto ping_out; -		} -		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) -			return iscsit_add_reject_from_cmd( -					ISCSI_REASON_PROTOCOL_ERROR, -					1, 0, buf, cmd); - -		return 0; -	} - -	if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) { -		/* -		 * This was a response to a unsolicited NOPIN ping. -		 */ -		cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt)); -		if (!cmd_p) -			return -1; - -		iscsit_stop_nopin_response_timer(conn); - -		cmd_p->i_state = ISTATE_REMOVE; -		iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state); -		iscsit_start_nopin_timer(conn); -	} else { -		/* -		 * Initiator is not expecting a NOPIN is response. -		 * Just ignore for now. -		 * -		 * iSCSI v19-91 10.18 -		 * "A NOP-OUT may also be used to confirm a changed -		 *  ExpStatSN if another PDU will not be available -		 *  for a long time." -		 */ -		ret = 0; -		goto out; -	} - -	return 0; +	return iscsit_process_nop_out(conn, cmd, hdr);  out:  	if (cmd)  		iscsit_free_cmd(cmd, false); -ping_out: +  	kfree(ping_data);  	return ret;  } -EXPORT_SYMBOL(iscsit_handle_nop_out);  int  iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, @@ -1757,8 +1737,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	struct se_tmr_req *se_tmr;  	struct iscsi_tmr_req *tmr_req;  	struct iscsi_tm *hdr; -	int out_of_order_cmdsn = 0; -	int ret; +	int out_of_order_cmdsn = 0, ret; +	bool sess_ref = false;  	u8 function;  	hdr			= (struct iscsi_tm *) buf; @@ -1782,8 +1762,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  		pr_err("Task Management Request TASK_REASSIGN not"  			" issued as immediate command, bad iSCSI Initiator"  				"implementation\n"); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, -					1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_PROTOCOL_ERROR, buf);  	}  	if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&  	    be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG) @@ -1795,9 +1775,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  	if (!cmd->tmr_req) {  		pr_err("Unable to allocate memory for"  			" Task Management command!\n"); -		return iscsit_add_reject_from_cmd( -			ISCSI_REASON_BOOKMARK_NO_RESOURCES, -			1, 1, buf, cmd); +		return iscsit_add_reject_cmd(cmd, +					     ISCSI_REASON_BOOKMARK_NO_RESOURCES, +					     buf);  	}  	/* @@ -1814,6 +1794,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  				      conn->sess->se_sess, 0, DMA_NONE,  				      MSG_SIMPLE_TAG, cmd->sense_buffer + 2); +		target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true); +		sess_ref = true; +  		switch (function) {  		case ISCSI_TM_FUNC_ABORT_TASK:  			tcm_function = TMR_ABORT_TASK; @@ -1839,17 +1822,15 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  		default:  			pr_err("Unknown iSCSI TMR Function:"  			       " 0x%02x\n", function); -			return iscsit_add_reject_from_cmd( -				ISCSI_REASON_BOOKMARK_NO_RESOURCES, -				1, 1, buf, cmd); +			return iscsit_add_reject_cmd(cmd, +				ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);  		}  		ret = core_tmr_alloc_req(&cmd->se_cmd, cmd->tmr_req,  					 tcm_function, GFP_KERNEL);  		if (ret < 0) -			return iscsit_add_reject_from_cmd( -				ISCSI_REASON_BOOKMARK_NO_RESOURCES, -				1, 1, buf, cmd); +			return iscsit_add_reject_cmd(cmd, +				ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);  		cmd->tmr_req->se_tmr_req = cmd->se_cmd.se_tmr_req;  	} @@ -1908,9 +1889,8 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  			break;  		if (iscsit_check_task_reassign_expdatasn(tmr_req, conn) < 0) -			return iscsit_add_reject_from_cmd( -					ISCSI_REASON_BOOKMARK_INVALID, 1, 1, -					buf, cmd); +			return iscsit_add_reject_cmd(cmd, +					ISCSI_REASON_BOOKMARK_INVALID, buf);  		break;  	default:  		pr_err("Unknown TMR function: 0x%02x, protocol" @@ -1928,15 +1908,13 @@ attach:  	spin_unlock_bh(&conn->cmd_lock);  	if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { -		int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); +		int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);  		if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP)  			out_of_order_cmdsn = 1;  		else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)  			return 0;  		else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) -			return iscsit_add_reject_from_cmd( -					ISCSI_REASON_PROTOCOL_ERROR, -					1, 0, buf, cmd); +			return -1;  	}  	iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); @@ -1956,51 +1934,135 @@ attach:  	 * For connection recovery, this is also the default action for  	 * TMR TASK_REASSIGN.  	 */ +	if (sess_ref) { +		pr_debug("Handle TMR, using sess_ref=true check\n"); +		target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); +	} +  	iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);  	return 0;  }  EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd);  /* #warning FIXME: Support Text Command parameters besides SendTargets */ -static int iscsit_handle_text_cmd( -	struct iscsi_conn *conn, -	unsigned char *buf) +int +iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, +		      struct iscsi_text *hdr)  { -	char *text_ptr, *text_in; -	int cmdsn_ret, niov = 0, rx_got, rx_size; -	u32 checksum = 0, data_crc = 0, payload_length; -	u32 padding = 0, pad_bytes = 0, text_length = 0; -	struct iscsi_cmd *cmd; -	struct kvec iov[3]; -	struct iscsi_text *hdr; - -	hdr			= (struct iscsi_text *) buf; -	payload_length		= ntoh24(hdr->dlength); +	u32 payload_length = ntoh24(hdr->dlength);  	if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {  		pr_err("Unable to accept text parameter length: %u"  			"greater than MaxXmitDataSegmentLength %u.\n",  		       payload_length, conn->conn_ops->MaxXmitDataSegmentLength); -		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, -					buf, conn); +		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, +					 (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); -	rx_size = text_length = payload_length; -	if (text_length) { -		text_in = kzalloc(text_length, GFP_KERNEL); +	cmd->iscsi_opcode	= ISCSI_OP_TEXT; +	cmd->i_state		= ISTATE_SEND_TEXTRSP; +	cmd->immediate_cmd	= ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0); +	conn->sess->init_task_tag = cmd->init_task_tag  = hdr->itt; +	cmd->targ_xfer_tag	= 0xFFFFFFFF; +	cmd->cmd_sn		= be32_to_cpu(hdr->cmdsn); +	cmd->exp_stat_sn	= be32_to_cpu(hdr->exp_statsn); +	cmd->data_direction	= DMA_NONE; + +	return 0; +} +EXPORT_SYMBOL(iscsit_setup_text_cmd); + +int +iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, +			struct iscsi_text *hdr) +{ +	unsigned char *text_in = cmd->text_in_ptr, *text_ptr; +	int cmdsn_ret; + +	if (!text_in) { +		pr_err("Unable to locate text_in buffer for sendtargets" +		       " discovery\n"); +		goto reject; +	} +	if (strncmp("SendTargets", text_in, 11) != 0) { +		pr_err("Received Text Data that is not" +			" SendTargets, cannot continue.\n"); +		goto reject; +	} +	text_ptr = strchr(text_in, '='); +	if (!text_ptr) { +		pr_err("No \"=\" separator found in Text Data," +			"  cannot continue.\n"); +		goto reject; +	} +	if (!strncmp("=All", text_ptr, 4)) { +		cmd->cmd_flags |= IFC_SENDTARGETS_ALL; +	} else if (!strncmp("=iqn.", text_ptr, 5) || +		   !strncmp("=eui.", text_ptr, 5)) { +		cmd->cmd_flags |= IFC_SENDTARGETS_SINGLE; +	} else { +		pr_err("Unable to locate valid SendTargets=%s value\n", text_ptr); +		goto reject; +	} + +	spin_lock_bh(&conn->cmd_lock); +	list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); +	spin_unlock_bh(&conn->cmd_lock); + +	iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); + +	if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { +		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, +				(unsigned char *)hdr, hdr->cmdsn); +		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) +			return -1; + +		return 0; +	} + +	return iscsit_execute_cmd(cmd, 0); + +reject: +	return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, +				 (unsigned char *)hdr); +} +EXPORT_SYMBOL(iscsit_process_text_cmd); + +static int +iscsit_handle_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, +		       unsigned char *buf) +{ +	struct iscsi_text *hdr = (struct iscsi_text *)buf; +	char *text_in = NULL; +	u32 payload_length = ntoh24(hdr->dlength); +	int rx_size, rc; + +	rc = iscsit_setup_text_cmd(conn, cmd, hdr); +	if (rc < 0) +		return 0; + +	rx_size = payload_length; +	if (payload_length) { +		u32 checksum = 0, data_crc = 0; +		u32 padding = 0, pad_bytes = 0; +		int niov = 0, rx_got; +		struct kvec iov[3]; + +		text_in = kzalloc(payload_length, GFP_KERNEL);  		if (!text_in) {  			pr_err("Unable to allocate memory for"  				" incoming text parameters\n"); -			return -1; +			goto reject;  		} +		cmd->text_in_ptr = text_in;  		memset(iov, 0, 3 * sizeof(struct kvec));  		iov[niov].iov_base	= text_in; -		iov[niov++].iov_len	= text_length; +		iov[niov++].iov_len	= payload_length;  		padding = ((-payload_length) & 3);  		if (padding != 0) { @@ -2017,14 +2079,12 @@ static int iscsit_handle_text_cmd(  		}  		rx_got = rx_data(conn, &iov[0], niov, rx_size); -		if (rx_got != rx_size) { -			kfree(text_in); -			return -1; -		} +		if (rx_got != rx_size) +			goto reject;  		if (conn->conn_ops->DataDigest) {  			iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, -					text_in, text_length, +					text_in, payload_length,  					padding, (u8 *)&pad_bytes,  					(u8 *)&data_crc); @@ -2036,8 +2096,7 @@ static int iscsit_handle_text_cmd(  					pr_err("Unable to recover from"  					" Text Data digest failure while in"  						" ERL=0.\n"); -					kfree(text_in); -					return -1; +					goto reject;  				} else {  					/*  					 * Silently drop this PDU and let the @@ -2052,68 +2111,22 @@ static int iscsit_handle_text_cmd(  			} else {  				pr_debug("Got CRC32C DataDigest"  					" 0x%08x for %u bytes of text data.\n", -						checksum, text_length); +						checksum, payload_length);  			}  		} -		text_in[text_length - 1] = '\0'; +		text_in[payload_length - 1] = '\0';  		pr_debug("Successfully read %d bytes of text" -				" data.\n", text_length); - -		if (strncmp("SendTargets", text_in, 11) != 0) { -			pr_err("Received Text Data that is not" -				" SendTargets, cannot continue.\n"); -			kfree(text_in); -			return -1; -		} -		text_ptr = strchr(text_in, '='); -		if (!text_ptr) { -			pr_err("No \"=\" separator found in Text Data," -				"  cannot continue.\n"); -			kfree(text_in); -			return -1; -		} -		if (strncmp("=All", text_ptr, 4) != 0) { -			pr_err("Unable to locate All value for" -				" SendTargets key,  cannot continue.\n"); -			kfree(text_in); -			return -1; -		} -/*#warning Support SendTargets=(iSCSI Target Name/Nothing) values. */ -		kfree(text_in); +				" data.\n", payload_length);  	} -	cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); -	if (!cmd) -		return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, -					1, buf, conn); - -	cmd->iscsi_opcode	= ISCSI_OP_TEXT; -	cmd->i_state		= ISTATE_SEND_TEXTRSP; -	cmd->immediate_cmd	= ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0); -	conn->sess->init_task_tag = cmd->init_task_tag	= hdr->itt; -	cmd->targ_xfer_tag	= 0xFFFFFFFF; -	cmd->cmd_sn		= be32_to_cpu(hdr->cmdsn); -	cmd->exp_stat_sn	= be32_to_cpu(hdr->exp_statsn); -	cmd->data_direction	= DMA_NONE; - -	spin_lock_bh(&conn->cmd_lock); -	list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); -	spin_unlock_bh(&conn->cmd_lock); +	return iscsit_process_text_cmd(conn, cmd, hdr); -	iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); - -	if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { -		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); -		if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) -			return iscsit_add_reject_from_cmd( -					ISCSI_REASON_PROTOCOL_ERROR, -					1, 0, buf, cmd); - -		return 0; -	} - -	return iscsit_execute_cmd(cmd, 0); +reject: +	kfree(cmd->text_in_ptr); +	cmd->text_in_ptr = NULL; +	return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);  } +EXPORT_SYMBOL(iscsit_handle_text_cmd);  int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn)  { @@ -2292,14 +2305,11 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,  		if (ret < 0)  			return ret;  	} else { -		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); -		if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { +		cmdsn_ret = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn); +		if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)  			logout_remove = 0; -		} else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) { -			return iscsit_add_reject_from_cmd( -				ISCSI_REASON_PROTOCOL_ERROR, -				1, 0, buf, cmd); -		} +		else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) +			return -1;  	}  	return logout_remove; @@ -2323,8 +2333,8 @@ static int iscsit_handle_snack(  	if (!conn->sess->sess_ops->ErrorRecoveryLevel) {  		pr_err("Initiator sent SNACK request while in"  			" ErrorRecoveryLevel=0.\n"); -		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, -					buf, conn); +		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, +					 buf);  	}  	/*  	 * SNACK_DATA and SNACK_R2T are both 0,  so check which function to @@ -2348,13 +2358,13 @@ static int iscsit_handle_snack(  	case ISCSI_FLAG_SNACK_TYPE_RDATA:  		/* FIXME: Support R-Data SNACK */  		pr_err("R-Data SNACK Not Supported.\n"); -		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, -					buf, conn); +		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, +					 buf);  	default:  		pr_err("Unknown SNACK type 0x%02x, protocol"  			" error.\n", hdr->flags & 0x0f); -		return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, -					buf, conn); +		return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, +					 buf);  	}  	return 0; @@ -2426,14 +2436,14 @@ static int iscsit_handle_immediate_data(  				pr_err("Unable to recover from"  					" Immediate Data digest failure while"  					" in ERL=0.\n"); -				iscsit_add_reject_from_cmd( +				iscsit_reject_cmd(cmd,  						ISCSI_REASON_DATA_DIGEST_ERROR, -						1, 0, (unsigned char *)hdr, cmd); +						(unsigned char *)hdr);  				return IMMEDIATE_DATA_CANNOT_RECOVER;  			} else { -				iscsit_add_reject_from_cmd( +				iscsit_reject_cmd(cmd,  						ISCSI_REASON_DATA_DIGEST_ERROR, -						0, 0, (unsigned char *)hdr, cmd); +						(unsigned char *)hdr);  				return IMMEDIATE_DATA_ERL1_CRC_FAILURE;  			}  		} else { @@ -3276,8 +3286,6 @@ static u8 iscsit_convert_tcm_tmr_rsp(struct se_tmr_req *se_tmr)  		return ISCSI_TMF_RSP_NO_LUN;  	case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED:  		return ISCSI_TMF_RSP_NOT_SUPPORTED; -	case TMR_FUNCTION_AUTHORIZATION_FAILED: -		return ISCSI_TMF_RSP_AUTH_FAILED;  	case TMR_FUNCTION_REJECTED:  	default:  		return ISCSI_TMF_RSP_REJECTED; @@ -3372,6 +3380,7 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)  	struct iscsi_tpg_np *tpg_np;  	int buffer_len, end_of_buf = 0, len = 0, payload_len = 0;  	unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */ +	unsigned char *text_in = cmd->text_in_ptr, *text_ptr = NULL;  	buffer_len = max(conn->conn_ops->MaxRecvDataSegmentLength,  			 SENDTARGETS_BUF_LIMIT); @@ -3382,9 +3391,31 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)  				" response.\n");  		return -ENOMEM;  	} +	/* +	 * Locate pointer to iqn./eui. string for IFC_SENDTARGETS_SINGLE +	 * explicit case.. +	 */ +	if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) { +		text_ptr = strchr(text_in, '='); +		if (!text_ptr) { +			pr_err("Unable to locate '=' string in text_in:" +			       " %s\n", text_in); +			kfree(payload); +			return -EINVAL; +		} +		/* +		 * Skip over '=' character.. +		 */ +		text_ptr += 1; +	}  	spin_lock(&tiqn_lock);  	list_for_each_entry(tiqn, &g_tiqn_list, tiqn_list) { +		if ((cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) && +		     strcmp(tiqn->tiqn, text_ptr)) { +			continue; +		} +  		len = sprintf(buf, "TargetName=%s", tiqn->tiqn);  		len += 1; @@ -3438,6 +3469,9 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)  eob:  		if (end_of_buf)  			break; + +		if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) +			break;  	}  	spin_unlock(&tiqn_lock); @@ -3446,52 +3480,62 @@ eob:  	return payload_len;  } -/* - *	FIXME: Add support for F_BIT and C_BIT when the length is longer than - *	MaxRecvDataSegmentLength. - */ -static int iscsit_send_text_rsp( -	struct iscsi_cmd *cmd, -	struct iscsi_conn *conn) +int +iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, +		      struct iscsi_text_rsp *hdr)  { -	struct iscsi_text_rsp *hdr; -	struct kvec *iov; -	u32 padding = 0, tx_size = 0; -	int text_length, iov_count = 0; +	int text_length, padding;  	text_length = iscsit_build_sendtargets_response(cmd);  	if (text_length < 0)  		return text_length; +	hdr->opcode = ISCSI_OP_TEXT_RSP; +	hdr->flags |= ISCSI_FLAG_CMD_FINAL;  	padding = ((-text_length) & 3); -	if (padding != 0) { -		memset(cmd->buf_ptr + text_length, 0, padding); -		pr_debug("Attaching %u additional bytes for" -			" padding.\n", padding); -	} - -	hdr			= (struct iscsi_text_rsp *) cmd->pdu; -	memset(hdr, 0, ISCSI_HDR_LEN); -	hdr->opcode		= ISCSI_OP_TEXT_RSP; -	hdr->flags		|= ISCSI_FLAG_CMD_FINAL;  	hton24(hdr->dlength, text_length); -	hdr->itt		= cmd->init_task_tag; -	hdr->ttt		= cpu_to_be32(cmd->targ_xfer_tag); -	cmd->stat_sn		= conn->stat_sn++; -	hdr->statsn		= cpu_to_be32(cmd->stat_sn); +	hdr->itt = cmd->init_task_tag; +	hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag); +	cmd->stat_sn = conn->stat_sn++; +	hdr->statsn = cpu_to_be32(cmd->stat_sn);  	iscsit_increment_maxcmdsn(cmd, conn->sess); -	hdr->exp_cmdsn		= cpu_to_be32(conn->sess->exp_cmd_sn); -	hdr->max_cmdsn		= cpu_to_be32(conn->sess->max_cmd_sn); +	hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); +	hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); -	iov = &cmd->iov_misc[0]; +	pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x," +		" Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn, +		text_length, conn->cid); + +	return text_length + padding; +} +EXPORT_SYMBOL(iscsit_build_text_rsp); +/* + *	FIXME: Add support for F_BIT and C_BIT when the length is longer than + *	MaxRecvDataSegmentLength. + */ +static int iscsit_send_text_rsp( +	struct iscsi_cmd *cmd, +	struct iscsi_conn *conn) +{ +	struct iscsi_text_rsp *hdr = (struct iscsi_text_rsp *)cmd->pdu; +	struct kvec *iov; +	u32 tx_size = 0; +	int text_length, iov_count = 0, rc; + +	rc = iscsit_build_text_rsp(cmd, conn, hdr); +	if (rc < 0) +		return rc; + +	text_length = rc; +	iov = &cmd->iov_misc[0];  	iov[iov_count].iov_base = cmd->pdu;  	iov[iov_count++].iov_len = ISCSI_HDR_LEN;  	iov[iov_count].iov_base	= cmd->buf_ptr; -	iov[iov_count++].iov_len = text_length + padding; +	iov[iov_count++].iov_len = text_length; -	tx_size += (ISCSI_HDR_LEN + text_length + padding); +	tx_size += (ISCSI_HDR_LEN + text_length);  	if (conn->conn_ops->HeaderDigest) {  		u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; @@ -3507,7 +3551,7 @@ static int iscsit_send_text_rsp(  	if (conn->conn_ops->DataDigest) {  		iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, -				cmd->buf_ptr, (text_length + padding), +				cmd->buf_ptr, text_length,  				0, NULL, (u8 *)&cmd->data_crc);  		iov[iov_count].iov_base	= &cmd->data_crc; @@ -3515,16 +3559,13 @@ static int iscsit_send_text_rsp(  		tx_size	+= ISCSI_CRC_LEN;  		pr_debug("Attaching DataDigest for %u bytes of text" -			" data, CRC 0x%08x\n", (text_length + padding), +			" data, CRC 0x%08x\n", text_length,  			cmd->data_crc);  	}  	cmd->iov_misc_count = iov_count;  	cmd->tx_size = tx_size; -	pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x," -		" Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn, -			text_length, conn->cid);  	return 0;  } @@ -3533,6 +3574,7 @@ iscsit_build_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn,  		    struct iscsi_reject *hdr)  {  	hdr->opcode		= ISCSI_OP_REJECT; +	hdr->reason		= cmd->reject_reason;  	hdr->flags		|= ISCSI_FLAG_CMD_FINAL;  	hton24(hdr->dlength, ISCSI_HDR_LEN);  	hdr->ffffffff		= cpu_to_be32(0xffffffff); @@ -3806,18 +3848,11 @@ check_rsp_state:  	case ISTATE_SEND_STATUS_RECOVERY:  	case ISTATE_SEND_TEXTRSP:  	case ISTATE_SEND_TASKMGTRSP: +	case ISTATE_SEND_REJECT:  		spin_lock_bh(&cmd->istate_lock);  		cmd->i_state = ISTATE_SENT_STATUS;  		spin_unlock_bh(&cmd->istate_lock);  		break; -	case ISTATE_SEND_REJECT: -		if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) { -			cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN; -			complete(&cmd->reject_comp); -			goto err; -		} -		complete(&cmd->reject_comp); -		break;  	default:  		pr_err("Unknown Opcode: 0x%02x ITT:"  		       " 0x%08x, i_state: %d on CID: %hu\n", @@ -3922,8 +3957,7 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)  	case ISCSI_OP_SCSI_CMD:  		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);  		if (!cmd) -			return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, -						1, buf, conn); +			goto reject;  		ret = iscsit_handle_scsi_cmd(conn, cmd, buf);  		break; @@ -3935,27 +3969,28 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)  		if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {  			cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);  			if (!cmd) -				return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, -						1, buf, conn); +				goto reject;  		}  		ret = iscsit_handle_nop_out(conn, cmd, buf);  		break;  	case ISCSI_OP_SCSI_TMFUNC:  		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);  		if (!cmd) -			return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, -						1, buf, conn); +			goto reject;  		ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);  		break;  	case ISCSI_OP_TEXT: -		ret = iscsit_handle_text_cmd(conn, buf); +		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); +		if (!cmd) +			goto reject; + +		ret = iscsit_handle_text_cmd(conn, cmd, buf);  		break;  	case ISCSI_OP_LOGOUT:  		cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);  		if (!cmd) -			return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, -						1, buf, conn); +			goto reject;  		ret = iscsit_handle_logout_cmd(conn, cmd, buf);  		if (ret > 0) @@ -3987,6 +4022,8 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)  	}  	return ret; +reject: +	return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);  }  int iscsi_target_rx_thread(void *arg) @@ -4039,11 +4076,6 @@ restart:  			goto transport_err;  		} -		/* -		 * Set conn->bad_hdr for use with REJECT PDUs. -		 */ -		memcpy(&conn->bad_hdr, &buffer, ISCSI_HDR_LEN); -  		if (conn->conn_ops->HeaderDigest) {  			iov.iov_base	= &digest;  			iov.iov_len	= ISCSI_CRC_LEN; @@ -4086,8 +4118,8 @@ restart:  		    (!(opcode & ISCSI_OP_LOGOUT)))) {  			pr_err("Received illegal iSCSI Opcode: 0x%02x"  			" while in Discovery Session, rejecting.\n", opcode); -			iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, -					buffer, conn); +			iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, +					  buffer);  			goto transport_err;  		} diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index a0050b2f294e..2c437cb8ca00 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h @@ -15,7 +15,7 @@ extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *,  extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,  				struct iscsi_portal_group *);  extern int iscsit_del_np(struct iscsi_np *); -extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *); +extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *);  extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);  extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *);  extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 8d8b3ff68490..bbfd28893164 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -20,6 +20,7 @@   ****************************************************************************/  #include <linux/configfs.h> +#include <linux/ctype.h>  #include <linux/export.h>  #include <linux/inet.h>  #include <target/target_core_base.h> @@ -78,11 +79,12 @@ static ssize_t lio_target_np_store_sctp(  	struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,  				struct iscsi_tpg_np, se_tpg_np);  	struct iscsi_tpg_np *tpg_np_sctp = NULL; -	char *endptr;  	u32 op;  	int ret; -	op = simple_strtoul(page, &endptr, 0); +	ret = kstrtou32(page, 0, &op); +	if (ret) +		return ret;  	if ((op != 1) && (op != 0)) {  		pr_err("Illegal value for tpg_enable: %u\n", op);  		return -EINVAL; @@ -382,11 +384,12 @@ static ssize_t iscsi_nacl_attrib_store_##name(				\  {									\  	struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \  					se_node_acl);			\ -	char *endptr;							\  	u32 val;							\  	int ret;							\  									\ -	val = simple_strtoul(page, &endptr, 0);				\ +	ret = kstrtou32(page, 0, &val);					\ +	if (ret)							\ +		return ret;						\  	ret = iscsit_na_##name(nacl, val);				\  	if (ret < 0)							\  		return ret;						\ @@ -474,7 +477,7 @@ static ssize_t __iscsi_##prefix##_store_##name(				\  	if (!capable(CAP_SYS_ADMIN))					\  		return -EPERM;						\  									\ -	snprintf(auth->name, PAGE_SIZE, "%s", page);			\ +	snprintf(auth->name, sizeof(auth->name), "%s", page);		\  	if (!strncmp("NULL", auth->name, 4))				\  		auth->naf_flags &= ~flags;				\  	else								\ @@ -789,11 +792,12 @@ static ssize_t lio_target_nacl_store_cmdsn_depth(  	struct iscsi_portal_group *tpg = container_of(se_tpg,  			struct iscsi_portal_group, tpg_se_tpg);  	struct config_item *acl_ci, *tpg_ci, *wwn_ci; -	char *endptr;  	u32 cmdsn_depth = 0;  	int ret; -	cmdsn_depth = simple_strtoul(page, &endptr, 0); +	ret = kstrtou32(page, 0, &cmdsn_depth); +	if (ret) +		return ret;  	if (cmdsn_depth > TA_DEFAULT_CMDSN_DEPTH_MAX) {  		pr_err("Passed cmdsn_depth: %u exceeds"  			" TA_DEFAULT_CMDSN_DEPTH_MAX: %u\n", cmdsn_depth, @@ -977,14 +981,15 @@ static ssize_t iscsi_tpg_attrib_store_##name(				\  {									\  	struct iscsi_portal_group *tpg = container_of(se_tpg,		\  			struct iscsi_portal_group, tpg_se_tpg);	\ -	char *endptr;							\  	u32 val;							\  	int ret;							\  									\  	if (iscsit_get_tpg(tpg) < 0)					\  		return -EINVAL;						\  									\ -	val = simple_strtoul(page, &endptr, 0);				\ +	ret = kstrtou32(page, 0, &val);					\ +	if (ret)							\ +		goto out;						\  	ret = iscsit_ta_##name(tpg, val);				\  	if (ret < 0)							\  		goto out;						\ @@ -1053,6 +1058,131 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {  /* End items for lio_target_tpg_attrib_cit */ +/* Start items for lio_target_tpg_auth_cit */ + +#define __DEF_TPG_AUTH_STR(prefix, name, flags)					\ +static ssize_t __iscsi_##prefix##_show_##name(					\ +	struct se_portal_group *se_tpg,						\ +	char *page)								\ +{										\ +	struct iscsi_portal_group *tpg = container_of(se_tpg,			\ +				struct iscsi_portal_group, tpg_se_tpg);		\ +	struct iscsi_node_auth *auth = &tpg->tpg_demo_auth;			\ +										\ +	if (!capable(CAP_SYS_ADMIN))						\ +		return -EPERM;							\ +										\ +	return snprintf(page, PAGE_SIZE, "%s\n", auth->name);			\ +}										\ +										\ +static ssize_t __iscsi_##prefix##_store_##name(					\ +	struct se_portal_group *se_tpg,						\ +	const char *page,							\ +	size_t count)								\ +{										\ +	struct iscsi_portal_group *tpg = container_of(se_tpg,			\ +				struct iscsi_portal_group, tpg_se_tpg);		\ +	struct iscsi_node_auth *auth = &tpg->tpg_demo_auth;			\ +										\ +	if (!capable(CAP_SYS_ADMIN))						\ +		return -EPERM;							\ +										\ +	snprintf(auth->name, sizeof(auth->name), "%s", page);			\ +	if (!(strncmp("NULL", auth->name, 4)))					\ +		auth->naf_flags &= ~flags;					\ +	else									\ +		auth->naf_flags |= flags;					\ +										\ +	if ((auth->naf_flags & NAF_USERID_IN_SET) &&				\ +	    (auth->naf_flags & NAF_PASSWORD_IN_SET))				\ +		auth->authenticate_target = 1;					\ +	else									\ +		auth->authenticate_target = 0;					\ +										\ +	return count;								\ +} + +#define __DEF_TPG_AUTH_INT(prefix, name)					\ +static ssize_t __iscsi_##prefix##_show_##name(					\ +	struct se_portal_group *se_tpg,						\ +	char *page)								\ +{										\ +	struct iscsi_portal_group *tpg = container_of(se_tpg,			\ +				struct iscsi_portal_group, tpg_se_tpg);		\ +	struct iscsi_node_auth *auth = &tpg->tpg_demo_auth;			\ +										\ +	if (!capable(CAP_SYS_ADMIN))						\ +		return -EPERM;							\ +										\ +	return snprintf(page, PAGE_SIZE, "%d\n", auth->name);			\ +} + +#define DEF_TPG_AUTH_STR(name, flags)						\ +	__DEF_TPG_AUTH_STR(tpg_auth, name, flags)				\ +static ssize_t iscsi_tpg_auth_show_##name(					\ +	struct se_portal_group *se_tpg,						\ +	char *page)								\ +{										\ +	return __iscsi_tpg_auth_show_##name(se_tpg, page);			\ +}										\ +										\ +static ssize_t iscsi_tpg_auth_store_##name(					\ +	struct se_portal_group *se_tpg,						\ +	const char *page,							\ +	size_t count)								\ +{										\ +	return __iscsi_tpg_auth_store_##name(se_tpg, page, count);		\ +} + +#define DEF_TPG_AUTH_INT(name)							\ +	__DEF_TPG_AUTH_INT(tpg_auth, name)					\ +static ssize_t iscsi_tpg_auth_show_##name(					\ +	struct se_portal_group *se_tpg,						\ +	char *page)								\ +{										\ +	return __iscsi_tpg_auth_show_##name(se_tpg, page);			\ +} + +#define TPG_AUTH_ATTR(_name, _mode) TF_TPG_AUTH_ATTR(iscsi, _name, _mode); +#define TPG_AUTH_ATTR_RO(_name) TF_TPG_AUTH_ATTR_RO(iscsi, _name); + +/* + *  * One-way authentication userid + *   */ +DEF_TPG_AUTH_STR(userid, NAF_USERID_SET); +TPG_AUTH_ATTR(userid, S_IRUGO | S_IWUSR); +/* + *  * One-way authentication password + *   */ +DEF_TPG_AUTH_STR(password, NAF_PASSWORD_SET); +TPG_AUTH_ATTR(password, S_IRUGO | S_IWUSR); +/* + *  * Enforce mutual authentication + *   */ +DEF_TPG_AUTH_INT(authenticate_target); +TPG_AUTH_ATTR_RO(authenticate_target); +/* + *  * Mutual authentication userid + *   */ +DEF_TPG_AUTH_STR(userid_mutual, NAF_USERID_IN_SET); +TPG_AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR); +/* + *  * Mutual authentication password + *   */ +DEF_TPG_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET); +TPG_AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR); + +static struct configfs_attribute *lio_target_tpg_auth_attrs[] = { +	&iscsi_tpg_auth_userid.attr, +	&iscsi_tpg_auth_password.attr, +	&iscsi_tpg_auth_authenticate_target.attr, +	&iscsi_tpg_auth_userid_mutual.attr, +	&iscsi_tpg_auth_password_mutual.attr, +	NULL, +}; + +/* End items for lio_target_tpg_auth_cit */ +  /* Start items for lio_target_tpg_param_cit */  #define DEF_TPG_PARAM(name)						\ @@ -1087,13 +1217,14 @@ static ssize_t iscsi_tpg_param_store_##name(				\  	struct iscsi_portal_group *tpg = container_of(se_tpg,		\  			struct iscsi_portal_group, tpg_se_tpg);		\  	char *buf;							\ -	int ret;							\ +	int ret, len;							\  									\  	buf = kzalloc(PAGE_SIZE, GFP_KERNEL);				\  	if (!buf)							\  		return -ENOMEM;						\ -	snprintf(buf, PAGE_SIZE, "%s=%s", __stringify(name), page);	\ -	buf[strlen(buf)-1] = '\0'; /* Kill newline */			\ +	len = snprintf(buf, PAGE_SIZE, "%s=%s", __stringify(name), page);	\ +	if (isspace(buf[len-1]))					\ +		buf[len-1] = '\0'; /* Kill newline */			\  									\  	if (iscsit_get_tpg(tpg) < 0) {					\  		kfree(buf);						\ @@ -1230,11 +1361,12 @@ static ssize_t lio_target_tpg_store_enable(  {  	struct iscsi_portal_group *tpg = container_of(se_tpg,  			struct iscsi_portal_group, tpg_se_tpg); -	char *endptr;  	u32 op; -	int ret = 0; +	int ret; -	op = simple_strtoul(page, &endptr, 0); +	ret = kstrtou32(page, 0, &op); +	if (ret) +		return ret;  	if ((op != 1) && (op != 0)) {  		pr_err("Illegal value for tpg_enable: %u\n", op);  		return -EINVAL; @@ -1282,15 +1414,15 @@ static struct se_portal_group *lio_target_tiqn_addtpg(  {  	struct iscsi_portal_group *tpg;  	struct iscsi_tiqn *tiqn; -	char *tpgt_str, *end_ptr; -	int ret = 0; -	unsigned short int tpgt; +	char *tpgt_str; +	int ret; +	u16 tpgt;  	tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn);  	/*  	 * Only tpgt_# directory groups can be created below  	 * target/iscsi/iqn.superturodiskarry/ -	*/ +	 */  	tpgt_str = strstr(name, "tpgt_");  	if (!tpgt_str) {  		pr_err("Unable to locate \"tpgt_#\" directory" @@ -1298,7 +1430,9 @@ static struct se_portal_group *lio_target_tiqn_addtpg(  		return NULL;  	}  	tpgt_str += 5; /* Skip ahead of "tpgt_" */ -	tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0); +	ret = kstrtou16(tpgt_str, 0, &tpgt); +	if (ret) +		return NULL;  	tpg = iscsit_alloc_portal_group(tiqn, tpgt);  	if (!tpg) @@ -1506,10 +1640,12 @@ static ssize_t iscsi_disc_store_enforce_discovery_auth(  {  	struct iscsi_param *param;  	struct iscsi_portal_group *discovery_tpg = iscsit_global->discovery_tpg; -	char *endptr;  	u32 op; +	int err; -	op = simple_strtoul(page, &endptr, 0); +	err = kstrtou32(page, 0, &op); +	if (err) +		return -EINVAL;  	if ((op != 1) && (op != 0)) {  		pr_err("Illegal value for enforce_discovery_auth:"  				" %u\n", op); @@ -1655,13 +1791,12 @@ static int lio_queue_status(struct se_cmd *se_cmd)  	return 0;  } -static int lio_queue_tm_rsp(struct se_cmd *se_cmd) +static void lio_queue_tm_rsp(struct se_cmd *se_cmd)  {  	struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);  	cmd->i_state = ISTATE_SEND_TASKMGTRSP;  	iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); -	return 0;  }  static char *lio_tpg_get_endpoint_wwn(struct se_portal_group *se_tpg) @@ -1866,6 +2001,7 @@ int iscsi_target_register_configfs(void)  	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = lio_target_wwn_attrs;  	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = lio_target_tpg_attrs;  	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = lio_target_tpg_attrib_attrs; +	TF_CIT_TMPL(fabric)->tfc_tpg_auth_cit.ct_attrs = lio_target_tpg_auth_attrs;  	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = lio_target_tpg_param_attrs;  	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = lio_target_portal_attrs;  	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = lio_target_initiator_attrs; diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 60ec4b92be03..4f77a78edef9 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -132,7 +132,8 @@ enum cmd_flags_table {  	ICF_CONTIG_MEMORY			= 0x00000020,  	ICF_ATTACHED_TO_RQUEUE			= 0x00000040,  	ICF_OOO_CMDSN				= 0x00000080, -	ICF_REJECT_FAIL_CONN			= 0x00000100, +	IFC_SENDTARGETS_ALL			= 0x00000100, +	IFC_SENDTARGETS_SINGLE			= 0x00000200,  };  /* struct iscsi_cmd->i_state */ @@ -366,6 +367,8 @@ struct iscsi_cmd {  	u8			maxcmdsn_inc;  	/* Immediate Unsolicited Dataout */  	u8			unsolicited_data; +	/* Reject reason code */ +	u8			reject_reason;  	/* CID contained in logout PDU when opcode == ISCSI_INIT_LOGOUT_CMND */  	u16			logout_cid;  	/* Command flags */ @@ -427,6 +430,8 @@ struct iscsi_cmd {  	u32			tx_size;  	/* Buffer used for various purposes */  	void			*buf_ptr; +	/* Used by SendTargets=[iqn.,eui.] discovery */ +	void			*text_in_ptr;  	/* See include/linux/dma-mapping.h */  	enum dma_data_direction	data_direction;  	/* iSCSI PDU Header + CRC */ @@ -446,7 +451,6 @@ struct iscsi_cmd {  	struct list_head	datain_list;  	/* R2T List */  	struct list_head	cmd_r2t_list; -	struct completion	reject_comp;  	/* Timer for DataOUT */  	struct timer_list	dataout_timer;  	/* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */ @@ -528,8 +532,6 @@ struct iscsi_conn {  	u32			of_marker;  	/* Used for calculating OFMarker offset to next PDU */  	u32			of_marker_offset; -	/* Complete Bad PDU for sending reject */ -	unsigned char		bad_hdr[ISCSI_HDR_LEN];  #define IPV6_ADDRESS_SPACE				48  	unsigned char		login_ip[IPV6_ADDRESS_SPACE];  	unsigned char		local_ip[IPV6_ADDRESS_SPACE]; @@ -809,6 +811,7 @@ struct iscsi_portal_group {  	struct mutex		tpg_access_lock;  	struct mutex		np_login_lock;  	struct iscsi_tpg_attrib	tpg_attrib; +	struct iscsi_node_auth	tpg_demo_auth;  	/* Pointer to default list of iSCSI parameters for TPG */  	struct iscsi_param_list	*param_list;  	struct iscsi_tiqn	*tpg_tiqn; diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index dcb199da06b9..08bd87833321 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c @@ -746,13 +746,12 @@ int iscsit_check_post_dataout(  		if (!conn->sess->sess_ops->ErrorRecoveryLevel) {  			pr_err("Unable to recover from DataOUT CRC"  				" failure while ERL=0, closing session.\n"); -			iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR, -					1, 0, buf, cmd); +			iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR, +					  buf);  			return DATAOUT_CANNOT_RECOVER;  		} -		iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR, -				0, 0, buf, cmd); +		iscsit_reject_cmd(cmd, ISCSI_REASON_DATA_DIGEST_ERROR, buf);  		return iscsit_dataout_post_crc_failed(cmd, buf);  	}  } @@ -909,6 +908,7 @@ void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep)  	wait_for_completion(&conn->conn_wait_comp);  	complete(&conn->conn_post_wait_comp);  } +EXPORT_SYMBOL(iscsit_cause_connection_reinstatement);  void iscsit_fall_back_to_erl0(struct iscsi_session *sess)  { diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 40d9dbca987b..586c268679a4 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -162,9 +162,8 @@ static int iscsit_handle_r2t_snack(  			" protocol error.\n", cmd->init_task_tag, begrun,  			(begrun + runlength), cmd->acked_data_sn); -			return iscsit_add_reject_from_cmd( -					ISCSI_REASON_PROTOCOL_ERROR, -					1, 0, buf, cmd); +			return iscsit_reject_cmd(cmd, +					ISCSI_REASON_PROTOCOL_ERROR, buf);  	}  	if (runlength) { @@ -173,8 +172,8 @@ static int iscsit_handle_r2t_snack(  			" with BegRun: 0x%08x, RunLength: 0x%08x, exceeds"  			" current R2TSN: 0x%08x, protocol error.\n",  			cmd->init_task_tag, begrun, runlength, cmd->r2t_sn); -			return iscsit_add_reject_from_cmd( -				ISCSI_REASON_BOOKMARK_INVALID, 1, 0, buf, cmd); +			return iscsit_reject_cmd(cmd, +					ISCSI_REASON_BOOKMARK_INVALID, buf);  		}  		last_r2tsn = (begrun + runlength);  	} else @@ -433,8 +432,7 @@ static int iscsit_handle_recovery_datain(  			" protocol error.\n", cmd->init_task_tag, begrun,  			(begrun + runlength), cmd->acked_data_sn); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, -				1, 0, buf, cmd); +		return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, buf);  	}  	/* @@ -445,14 +443,14 @@ static int iscsit_handle_recovery_datain(  		pr_err("Initiator requesting BegRun: 0x%08x, RunLength"  			": 0x%08x greater than maximum DataSN: 0x%08x.\n",  				begrun, runlength, (cmd->data_sn - 1)); -		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, -				1, 0, buf, cmd); +		return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_INVALID, +					 buf);  	}  	dr = iscsit_allocate_datain_req();  	if (!dr) -		return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_NO_RESOURCES, -				1, 0, buf, cmd); +		return iscsit_reject_cmd(cmd, ISCSI_REASON_BOOKMARK_NO_RESOURCES, +					 buf);  	dr->data_sn = dr->begrun = begrun;  	dr->runlength = runlength; @@ -1090,7 +1088,7 @@ int iscsit_handle_ooo_cmdsn(  	ooo_cmdsn = iscsit_allocate_ooo_cmdsn();  	if (!ooo_cmdsn) -		return CMDSN_ERROR_CANNOT_RECOVER; +		return -ENOMEM;  	ooo_cmdsn->cmd			= cmd;  	ooo_cmdsn->batch_count		= (batch) ? @@ -1101,10 +1099,10 @@ int iscsit_handle_ooo_cmdsn(  	if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) {  		kmem_cache_free(lio_ooo_cache, ooo_cmdsn); -		return CMDSN_ERROR_CANNOT_RECOVER; +		return -ENOMEM;  	} -	return CMDSN_HIGHER_THAN_EXP; +	return 0;  }  static int iscsit_set_dataout_timeout_values( diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index cd5018ff9cd7..c4675b4ceb49 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -112,6 +112,7 @@ static u32 iscsi_handle_authentication(  	struct iscsi_session *sess = conn->sess;  	struct iscsi_node_auth *auth;  	struct iscsi_node_acl *iscsi_nacl; +	struct iscsi_portal_group *iscsi_tpg;  	struct se_node_acl *se_nacl;  	if (!sess->sess_ops->SessionType) { @@ -132,7 +133,17 @@ static u32 iscsi_handle_authentication(  			return -1;  		} -		auth = ISCSI_NODE_AUTH(iscsi_nacl); +		if (se_nacl->dynamic_node_acl) { +			iscsi_tpg = container_of(se_nacl->se_tpg, +					struct iscsi_portal_group, tpg_se_tpg); + +			auth = &iscsi_tpg->tpg_demo_auth; +		} else { +			iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl, +						  se_node_acl); + +			auth = ISCSI_NODE_AUTH(iscsi_nacl); +		}  	} else {  		/*  		 * For SessionType=Discovery diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index e38222191a33..35fd6439eb01 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -1799,9 +1799,6 @@ void iscsi_set_connection_parameters(  		 * this key is not sent over the wire.  		 */  		if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { -			if (param_list->iser == true) -				continue; -  			ops->MaxXmitDataSegmentLength =  				simple_strtoul(param->value, &tmpptr, 0);  			pr_debug("MaxXmitDataSegmentLength:     %s\n", diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 08a3bacef0c5..1df06d5e4e01 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -178,7 +178,6 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)  	INIT_LIST_HEAD(&cmd->i_conn_node);  	INIT_LIST_HEAD(&cmd->datain_list);  	INIT_LIST_HEAD(&cmd->cmd_r2t_list); -	init_completion(&cmd->reject_comp);  	spin_lock_init(&cmd->datain_lock);  	spin_lock_init(&cmd->dataout_timeout_lock);  	spin_lock_init(&cmd->istate_lock); @@ -284,13 +283,12 @@ static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cm   * Commands may be received out of order if MC/S is in use.   * Ensure they are executed in CmdSN order.   */ -int iscsit_sequence_cmd( -	struct iscsi_conn *conn, -	struct iscsi_cmd *cmd, -	__be32 cmdsn) +int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, +			unsigned char *buf, __be32 cmdsn)  { -	int ret; -	int cmdsn_ret; +	int ret, cmdsn_ret; +	bool reject = false; +	u8 reason = ISCSI_REASON_BOOKMARK_NO_RESOURCES;  	mutex_lock(&conn->sess->cmdsn_mutex); @@ -300,9 +298,19 @@ int iscsit_sequence_cmd(  		ret = iscsit_execute_cmd(cmd, 0);  		if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list))  			iscsit_execute_ooo_cmdsns(conn->sess); +		else if (ret < 0) { +			reject = true; +			ret = CMDSN_ERROR_CANNOT_RECOVER; +		}  		break;  	case CMDSN_HIGHER_THAN_EXP:  		ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, be32_to_cpu(cmdsn)); +		if (ret < 0) { +			reject = true; +			ret = CMDSN_ERROR_CANNOT_RECOVER; +			break; +		} +		ret = CMDSN_HIGHER_THAN_EXP;  		break;  	case CMDSN_LOWER_THAN_EXP:  		cmd->i_state = ISTATE_REMOVE; @@ -310,11 +318,16 @@ int iscsit_sequence_cmd(  		ret = cmdsn_ret;  		break;  	default: +		reason = ISCSI_REASON_PROTOCOL_ERROR; +		reject = true;  		ret = cmdsn_ret;  		break;  	}  	mutex_unlock(&conn->sess->cmdsn_mutex); +	if (reject) +		iscsit_reject_cmd(cmd, reason, buf); +  	return ret;  }  EXPORT_SYMBOL(iscsit_sequence_cmd); @@ -681,6 +694,7 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)  	kfree(cmd->seq_list);  	kfree(cmd->tmr_req);  	kfree(cmd->iov_data); +	kfree(cmd->text_in_ptr);  	kmem_cache_free(lio_cmd_cache, cmd);  } diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index a4422659d049..e4fc34a02f57 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -13,7 +13,8 @@ extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);  extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);  extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);  extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32); -int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, __be32 cmdsn); +extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, +			       unsigned char * ,__be32 cmdsn);  extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *);  extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);  extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *, diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 7c908141cc8a..568ad25f25d3 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -786,7 +786,7 @@ static int tcm_loop_queue_status(struct se_cmd *se_cmd)  	return 0;  } -static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd) +static void tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)  {  	struct se_tmr_req *se_tmr = se_cmd->se_tmr_req;  	struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr; @@ -796,7 +796,6 @@ static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd)  	 */  	atomic_set(&tl_tmr->tmr_complete, 1);  	wake_up(&tl_tmr->tl_tmr_wait); -	return 0;  }  static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba) diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index d3536f57444f..e51b09a04d52 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1842,9 +1842,8 @@ static int sbp_queue_status(struct se_cmd *se_cmd)  	return sbp_send_sense(req);  } -static int sbp_queue_tm_rsp(struct se_cmd *se_cmd) +static void sbp_queue_tm_rsp(struct se_cmd *se_cmd)  { -	return 0;  }  static int sbp_check_stop_free(struct se_cmd *se_cmd) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 4a8bd36d3958..e4d22933efaf 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -983,7 +983,6 @@ static ssize_t target_core_dev_pr_show_spc3_res(struct se_device *dev,  	struct se_node_acl *se_nacl;  	struct t10_pr_registration *pr_reg;  	char i_buf[PR_REG_ISID_ID_LEN]; -	int prf_isid;  	memset(i_buf, 0, PR_REG_ISID_ID_LEN); @@ -992,12 +991,11 @@ static ssize_t target_core_dev_pr_show_spc3_res(struct se_device *dev,  		return sprintf(page, "No SPC-3 Reservation holder\n");  	se_nacl = pr_reg->pr_reg_nacl; -	prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], -				PR_REG_ISID_ID_LEN); +	core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);  	return sprintf(page, "SPC-3 Reservation: %s Initiator: %s%s\n",  		se_nacl->se_tpg->se_tpg_tfo->get_fabric_name(), -		se_nacl->initiatorname, (prf_isid) ? &i_buf[0] : ""); +		se_nacl->initiatorname, i_buf);  }  static ssize_t target_core_dev_pr_show_spc2_res(struct se_device *dev, @@ -1116,7 +1114,7 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(  	unsigned char buf[384];  	char i_buf[PR_REG_ISID_ID_LEN];  	ssize_t len = 0; -	int reg_count = 0, prf_isid; +	int reg_count = 0;  	len += sprintf(page+len, "SPC-3 PR Registrations:\n"); @@ -1127,12 +1125,11 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(  		memset(buf, 0, 384);  		memset(i_buf, 0, PR_REG_ISID_ID_LEN);  		tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; -		prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], +		core_pr_dump_initiator_port(pr_reg, i_buf,  					PR_REG_ISID_ID_LEN);  		sprintf(buf, "%s Node: %s%s Key: 0x%016Lx PRgen: 0x%08x\n",  			tfo->get_fabric_name(), -			pr_reg->pr_reg_nacl->initiatorname, (prf_isid) ? -			&i_buf[0] : "", pr_reg->pr_res_key, +			pr_reg->pr_reg_nacl->initiatorname, i_buf, pr_reg->pr_res_key,  			pr_reg->pr_res_generation);  		if (len + strlen(buf) >= PAGE_SIZE) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 4630481b6043..8f4142fe5f19 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1410,7 +1410,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)  	INIT_LIST_HEAD(&dev->t10_alua.tg_pt_gps_list);  	spin_lock_init(&dev->t10_alua.tg_pt_gps_lock); -	dev->t10_pr.pr_aptpl_buf_len = PR_APTPL_BUF_LEN;  	dev->t10_wwn.t10_dev = dev;  	dev->t10_alua.t10_dev = dev; @@ -1545,7 +1544,7 @@ int core_dev_setup_virtual_lun0(void)  {  	struct se_hba *hba;  	struct se_device *dev; -	char buf[16]; +	char buf[] = "rd_pages=8,rd_nullio=1";  	int ret;  	hba = core_alloc_hba("rd_mcp", 0, HBA_FLAGS_INTERNAL_USE); @@ -1558,8 +1557,6 @@ int core_dev_setup_virtual_lun0(void)  		goto out_free_hba;  	} -	memset(buf, 0, 16); -	sprintf(buf, "rd_pages=8");  	hba->transport->set_configfs_dev_params(dev, buf, sizeof(buf));  	ret = target_configure_device(dev); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 04c775cb3e65..eb56eb129563 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -965,6 +965,19 @@ TF_CIT_SETUP(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL, NULL);  /* End of tfc_tpg_attrib_cit */ +/* Start of tfc_tpg_auth_cit */ + +CONFIGFS_EATTR_OPS(target_fabric_tpg_auth, se_portal_group, tpg_auth_group); + +static struct configfs_item_operations target_fabric_tpg_auth_item_ops = { +	.show_attribute		= target_fabric_tpg_auth_attr_show, +	.store_attribute	= target_fabric_tpg_auth_attr_store, +}; + +TF_CIT_SETUP(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL, NULL); + +/* End of tfc_tpg_attrib_cit */ +  /* Start of tfc_tpg_param_cit */  CONFIGFS_EATTR_OPS(target_fabric_tpg_param, se_portal_group, tpg_param_group); @@ -1030,8 +1043,9 @@ static struct config_group *target_fabric_make_tpg(  	se_tpg->tpg_group.default_groups[1] = &se_tpg->tpg_np_group;  	se_tpg->tpg_group.default_groups[2] = &se_tpg->tpg_acl_group;  	se_tpg->tpg_group.default_groups[3] = &se_tpg->tpg_attrib_group; -	se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_param_group; -	se_tpg->tpg_group.default_groups[5] = NULL; +	se_tpg->tpg_group.default_groups[4] = &se_tpg->tpg_auth_group; +	se_tpg->tpg_group.default_groups[5] = &se_tpg->tpg_param_group; +	se_tpg->tpg_group.default_groups[6] = NULL;  	config_group_init_type_name(&se_tpg->tpg_group, name,  			&TF_CIT_TMPL(tf)->tfc_tpg_base_cit); @@ -1043,6 +1057,8 @@ static struct config_group *target_fabric_make_tpg(  			&TF_CIT_TMPL(tf)->tfc_tpg_nacl_cit);  	config_group_init_type_name(&se_tpg->tpg_attrib_group, "attrib",  			&TF_CIT_TMPL(tf)->tfc_tpg_attrib_cit); +	config_group_init_type_name(&se_tpg->tpg_auth_group, "auth", +			&TF_CIT_TMPL(tf)->tfc_tpg_auth_cit);  	config_group_init_type_name(&se_tpg->tpg_param_group, "param",  			&TF_CIT_TMPL(tf)->tfc_tpg_param_cit); @@ -1202,6 +1218,7 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf)  	target_fabric_setup_tpg_np_cit(tf);  	target_fabric_setup_tpg_np_base_cit(tf);  	target_fabric_setup_tpg_attrib_cit(tf); +	target_fabric_setup_tpg_auth_cit(tf);  	target_fabric_setup_tpg_param_cit(tf);  	target_fabric_setup_tpg_nacl_cit(tf);  	target_fabric_setup_tpg_nacl_base_cit(tf); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 3240f2cc81ef..bd78faf67c6b 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -53,18 +53,28 @@ struct pr_transport_id_holder {  	struct list_head dest_list;  }; -int core_pr_dump_initiator_port( +void core_pr_dump_initiator_port(  	struct t10_pr_registration *pr_reg,  	char *buf,  	u32 size)  {  	if (!pr_reg->isid_present_at_reg) -		return 0; +		buf[0] = '\0'; -	snprintf(buf, size, ",i,0x%s", &pr_reg->pr_reg_isid[0]); -	return 1; +	snprintf(buf, size, ",i,0x%s", pr_reg->pr_reg_isid);  } +enum register_type { +	REGISTER, +	REGISTER_AND_IGNORE_EXISTING_KEY, +	REGISTER_AND_MOVE, +}; + +enum preempt_type { +	PREEMPT, +	PREEMPT_AND_ABORT, +}; +  static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *,  			struct t10_pr_registration *, int); @@ -596,14 +606,6 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration(  		return NULL;  	} -	pr_reg->pr_aptpl_buf = kzalloc(dev->t10_pr.pr_aptpl_buf_len, -					GFP_ATOMIC); -	if (!pr_reg->pr_aptpl_buf) { -		pr_err("Unable to allocate pr_reg->pr_aptpl_buf\n"); -		kmem_cache_free(t10_pr_reg_cache, pr_reg); -		return NULL; -	} -  	INIT_LIST_HEAD(&pr_reg->pr_reg_list);  	INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list);  	INIT_LIST_HEAD(&pr_reg->pr_reg_aptpl_list); @@ -794,7 +796,6 @@ int core_scsi3_alloc_aptpl_registration(  		pr_err("Unable to allocate struct t10_pr_registration\n");  		return -ENOMEM;  	} -	pr_reg->pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, GFP_KERNEL);  	INIT_LIST_HEAD(&pr_reg->pr_reg_list);  	INIT_LIST_HEAD(&pr_reg->pr_reg_abort_list); @@ -848,11 +849,9 @@ static void core_scsi3_aptpl_reserve(  	struct t10_pr_registration *pr_reg)  {  	char i_buf[PR_REG_ISID_ID_LEN]; -	int prf_isid;  	memset(i_buf, 0, PR_REG_ISID_ID_LEN); -	prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], -				PR_REG_ISID_ID_LEN); +	core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);  	spin_lock(&dev->dev_reservation_lock);  	dev->dev_pr_res_holder = pr_reg; @@ -865,11 +864,11 @@ static void core_scsi3_aptpl_reserve(  		(pr_reg->pr_reg_all_tg_pt) ? 1 : 0);  	pr_debug("SPC-3 PR [%s] RESERVE Node: %s%s\n",  		tpg->se_tpg_tfo->get_fabric_name(), node_acl->initiatorname, -		(prf_isid) ? &i_buf[0] : ""); +		i_buf);  }  static void __core_scsi3_add_registration(struct se_device *, struct se_node_acl *, -				struct t10_pr_registration *, int, int); +				struct t10_pr_registration *, enum register_type, int);  static int __core_scsi3_check_aptpl_registration(  	struct se_device *dev, @@ -962,21 +961,19 @@ static void __core_scsi3_dump_registration(  	struct se_device *dev,  	struct se_node_acl *nacl,  	struct t10_pr_registration *pr_reg, -	int register_type) +	enum register_type register_type)  {  	struct se_portal_group *se_tpg = nacl->se_tpg;  	char i_buf[PR_REG_ISID_ID_LEN]; -	int prf_isid;  	memset(&i_buf[0], 0, PR_REG_ISID_ID_LEN); -	prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], -				PR_REG_ISID_ID_LEN); +	core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);  	pr_debug("SPC-3 PR [%s] Service Action: REGISTER%s Initiator" -		" Node: %s%s\n", tfo->get_fabric_name(), (register_type == 2) ? -		"_AND_MOVE" : (register_type == 1) ? +		" Node: %s%s\n", tfo->get_fabric_name(), (register_type == REGISTER_AND_MOVE) ? +		"_AND_MOVE" : (register_type == REGISTER_AND_IGNORE_EXISTING_KEY) ?  		"_AND_IGNORE_EXISTING_KEY" : "", nacl->initiatorname, -		(prf_isid) ? i_buf : ""); +		i_buf);  	pr_debug("SPC-3 PR [%s] registration on Target Port: %s,0x%04x\n",  		 tfo->get_fabric_name(), tfo->tpg_get_wwn(se_tpg),  		tfo->tpg_get_tag(se_tpg)); @@ -998,7 +995,7 @@ static void __core_scsi3_add_registration(  	struct se_device *dev,  	struct se_node_acl *nacl,  	struct t10_pr_registration *pr_reg, -	int register_type, +	enum register_type register_type,  	int register_move)  {  	struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; @@ -1064,7 +1061,7 @@ static int core_scsi3_alloc_registration(  	u64 sa_res_key,  	int all_tg_pt,  	int aptpl, -	int register_type, +	enum register_type register_type,  	int register_move)  {  	struct t10_pr_registration *pr_reg; @@ -1225,11 +1222,9 @@ static void __core_scsi3_free_registration(  			pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo;  	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	char i_buf[PR_REG_ISID_ID_LEN]; -	int prf_isid;  	memset(i_buf, 0, PR_REG_ISID_ID_LEN); -	prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], -				PR_REG_ISID_ID_LEN); +	core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);  	pr_reg->pr_reg_deve->def_pr_registered = 0;  	pr_reg->pr_reg_deve->pr_res_key = 0; @@ -1257,7 +1252,7 @@ static void __core_scsi3_free_registration(  	pr_debug("SPC-3 PR [%s] Service Action: UNREGISTER Initiator"  		" Node: %s%s\n", tfo->get_fabric_name(),  		pr_reg->pr_reg_nacl->initiatorname, -		(prf_isid) ? &i_buf[0] : ""); +		i_buf);  	pr_debug("SPC-3 PR [%s] for %s TCM Subsystem %s Object Target"  		" Port(s)\n", tfo->get_fabric_name(),  		(pr_reg->pr_reg_all_tg_pt) ? "ALL" : "SINGLE", @@ -1269,7 +1264,6 @@ static void __core_scsi3_free_registration(  	if (!preempt_and_abort_list) {  		pr_reg->pr_reg_deve = NULL;  		pr_reg->pr_reg_nacl = NULL; -		kfree(pr_reg->pr_aptpl_buf);  		kmem_cache_free(t10_pr_reg_cache, pr_reg);  		return;  	} @@ -1338,7 +1332,6 @@ void core_scsi3_free_all_registrations(  	list_for_each_entry_safe(pr_reg, pr_reg_tmp, &pr_tmpl->aptpl_reg_list,  				pr_reg_aptpl_list) {  		list_del(&pr_reg->pr_reg_aptpl_list); -		kfree(pr_reg->pr_aptpl_buf);  		kmem_cache_free(t10_pr_reg_cache, pr_reg);  	}  	spin_unlock(&pr_tmpl->aptpl_reg_lock); @@ -1453,7 +1446,7 @@ core_scsi3_decode_spec_i_port(  	char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];  	sense_reason_t ret;  	u32 tpdl, tid_len = 0; -	int dest_local_nexus, prf_isid; +	int dest_local_nexus;  	u32 dest_rtpi = 0;  	memset(dest_iport, 0, 64); @@ -1764,8 +1757,7 @@ core_scsi3_decode_spec_i_port(  		kfree(tidh);  		memset(i_buf, 0, PR_REG_ISID_ID_LEN); -		prf_isid = core_pr_dump_initiator_port(dest_pr_reg, &i_buf[0], -						PR_REG_ISID_ID_LEN); +		core_pr_dump_initiator_port(dest_pr_reg, i_buf, PR_REG_ISID_ID_LEN);  		__core_scsi3_add_registration(cmd->se_dev, dest_node_acl,  					dest_pr_reg, 0, 0); @@ -1773,8 +1765,7 @@ core_scsi3_decode_spec_i_port(  		pr_debug("SPC-3 PR [%s] SPEC_I_PT: Successfully"  			" registered Transport ID for Node: %s%s Mapped LUN:"  			" %u\n", dest_tpg->se_tpg_tfo->get_fabric_name(), -			dest_node_acl->initiatorname, (prf_isid) ? -			&i_buf[0] : "", dest_se_deve->mapped_lun); +			dest_node_acl->initiatorname, i_buf, dest_se_deve->mapped_lun);  		if (dest_local_nexus)  			continue; @@ -1813,7 +1804,6 @@ out:  			kmem_cache_free(t10_pr_reg_cache, pr_reg_tmp);  		} -		kfree(dest_pr_reg->pr_aptpl_buf);  		kmem_cache_free(t10_pr_reg_cache, dest_pr_reg);  		if (dest_local_nexus) @@ -1826,14 +1816,10 @@ out:  	return ret;  } -/* - * Called with struct se_device->dev_reservation_lock held - */ -static int __core_scsi3_update_aptpl_buf( +static int core_scsi3_update_aptpl_buf(  	struct se_device *dev,  	unsigned char *buf, -	u32 pr_aptpl_buf_len, -	int clear_aptpl_metadata) +	u32 pr_aptpl_buf_len)  {  	struct se_lun *lun;  	struct se_portal_group *tpg; @@ -1841,20 +1827,13 @@ static int __core_scsi3_update_aptpl_buf(  	unsigned char tmp[512], isid_buf[32];  	ssize_t len = 0;  	int reg_count = 0; +	int ret = 0; -	memset(buf, 0, pr_aptpl_buf_len); -	/* -	 * Called to clear metadata once APTPL has been deactivated. -	 */ -	if (clear_aptpl_metadata) { -		snprintf(buf, pr_aptpl_buf_len, -				"No Registrations or Reservations\n"); -		return 0; -	} +	spin_lock(&dev->dev_reservation_lock); +	spin_lock(&dev->t10_pr.registration_lock);  	/*  	 * Walk the registration list..  	 */ -	spin_lock(&dev->t10_pr.registration_lock);  	list_for_each_entry(pr_reg, &dev->t10_pr.registration_list,  			pr_reg_list) { @@ -1900,8 +1879,8 @@ static int __core_scsi3_update_aptpl_buf(  		if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {  			pr_err("Unable to update renaming"  				" APTPL metadata\n"); -			spin_unlock(&dev->t10_pr.registration_lock); -			return -EMSGSIZE; +			ret = -EMSGSIZE; +			goto out;  		}  		len += sprintf(buf+len, "%s", tmp); @@ -1918,48 +1897,32 @@ static int __core_scsi3_update_aptpl_buf(  		if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {  			pr_err("Unable to update renaming"  				" APTPL metadata\n"); -			spin_unlock(&dev->t10_pr.registration_lock); -			return -EMSGSIZE; +			ret = -EMSGSIZE; +			goto out;  		}  		len += sprintf(buf+len, "%s", tmp);  		reg_count++;  	} -	spin_unlock(&dev->t10_pr.registration_lock);  	if (!reg_count)  		len += sprintf(buf+len, "No Registrations or Reservations"); -	return 0; -} - -static int core_scsi3_update_aptpl_buf( -	struct se_device *dev, -	unsigned char *buf, -	u32 pr_aptpl_buf_len, -	int clear_aptpl_metadata) -{ -	int ret; - -	spin_lock(&dev->dev_reservation_lock); -	ret = __core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len, -				clear_aptpl_metadata); +out: +	spin_unlock(&dev->t10_pr.registration_lock);  	spin_unlock(&dev->dev_reservation_lock);  	return ret;  } -/* - * Called with struct se_device->aptpl_file_mutex held - */  static int __core_scsi3_write_aptpl_to_file(  	struct se_device *dev, -	unsigned char *buf, -	u32 pr_aptpl_buf_len) +	unsigned char *buf)  {  	struct t10_wwn *wwn = &dev->t10_wwn;  	struct file *file;  	int flags = O_RDWR | O_CREAT | O_TRUNC;  	char path[512]; +	u32 pr_aptpl_buf_len;  	int ret;  	memset(path, 0, 512); @@ -1978,8 +1941,7 @@ static int __core_scsi3_write_aptpl_to_file(  		return PTR_ERR(file);  	} -	if (!pr_aptpl_buf_len) -		pr_aptpl_buf_len = (strlen(&buf[0]) + 1); /* Add extra for NULL */ +	pr_aptpl_buf_len = (strlen(buf) + 1); /* Add extra for NULL */  	ret = kernel_write(file, buf, pr_aptpl_buf_len, 0); @@ -1990,60 +1952,64 @@ static int __core_scsi3_write_aptpl_to_file(  	return ret ? -EIO : 0;  } -static int -core_scsi3_update_and_write_aptpl(struct se_device *dev, unsigned char *in_buf, -		u32 in_pr_aptpl_buf_len) +/* + * Clear the APTPL metadata if APTPL has been disabled, otherwise + * write out the updated metadata to struct file for this SCSI device. + */ +static sense_reason_t core_scsi3_update_and_write_aptpl(struct se_device *dev, bool aptpl)  { -	unsigned char null_buf[64], *buf; -	u32 pr_aptpl_buf_len; -	int clear_aptpl_metadata = 0; -	int ret; +	unsigned char *buf; +	int rc; -	/* -	 * Can be called with a NULL pointer from PROUT service action CLEAR -	 */ -	if (!in_buf) { -		memset(null_buf, 0, 64); -		buf = &null_buf[0]; -		/* -		 * This will clear the APTPL metadata to: -		 * "No Registrations or Reservations" status -		 */ -		pr_aptpl_buf_len = 64; -		clear_aptpl_metadata = 1; -	} else { -		buf = in_buf; -		pr_aptpl_buf_len = in_pr_aptpl_buf_len; +	if (!aptpl) { +		char *null_buf = "No Registrations or Reservations\n"; + +		rc = __core_scsi3_write_aptpl_to_file(dev, null_buf); +		dev->t10_pr.pr_aptpl_active = 0; +		pr_debug("SPC-3 PR: Set APTPL Bit Deactivated\n"); + +		if (rc) +			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + +		return 0;  	} -	ret = core_scsi3_update_aptpl_buf(dev, buf, pr_aptpl_buf_len, -				clear_aptpl_metadata); -	if (ret != 0) -		return ret; +	buf = kzalloc(PR_APTPL_BUF_LEN, GFP_KERNEL); +	if (!buf) +		return TCM_OUT_OF_RESOURCES; -	/* -	 * __core_scsi3_write_aptpl_to_file() will call strlen() -	 * on the passed buf to determine pr_aptpl_buf_len. -	 */ -	return __core_scsi3_write_aptpl_to_file(dev, buf, 0); +	rc = core_scsi3_update_aptpl_buf(dev, buf, PR_APTPL_BUF_LEN); +	if (rc < 0) { +		kfree(buf); +		return TCM_OUT_OF_RESOURCES; +	} + +	rc = __core_scsi3_write_aptpl_to_file(dev, buf); +	if (rc != 0) { +		pr_err("SPC-3 PR: Could not update APTPL\n"); +		kfree(buf); +		return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; +	} +	dev->t10_pr.pr_aptpl_active = 1; +	kfree(buf); +	pr_debug("SPC-3 PR: Set APTPL Bit Activated\n"); +	return 0;  }  static sense_reason_t  core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, -		int aptpl, int all_tg_pt, int spec_i_pt, int ignore_key) +		bool aptpl, bool all_tg_pt, bool spec_i_pt, enum register_type register_type)  {  	struct se_session *se_sess = cmd->se_sess;  	struct se_device *dev = cmd->se_dev;  	struct se_dev_entry *se_deve;  	struct se_lun *se_lun = cmd->se_lun;  	struct se_portal_group *se_tpg; -	struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp, *pr_reg_e; +	struct t10_pr_registration *pr_reg, *pr_reg_p, *pr_reg_tmp;  	struct t10_reservation *pr_tmpl = &dev->t10_pr; -	/* Used for APTPL metadata w/ UNREGISTER */ -	unsigned char *pr_aptpl_buf = NULL;  	unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL;  	sense_reason_t ret = TCM_NO_SENSE; -	int pr_holder = 0, type; +	int pr_holder = 0;  	if (!se_sess || !se_lun) {  		pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); @@ -2061,8 +2027,8 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,  	/*  	 * Follow logic from spc4r17 Section 5.7.7, Register Behaviors Table 47  	 */ -	pr_reg_e = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess); -	if (!pr_reg_e) { +	pr_reg = core_scsi3_locate_pr_reg(dev, se_sess->se_node_acl, se_sess); +	if (!pr_reg) {  		if (res_key) {  			pr_warn("SPC-3 PR: Reservation Key non-zero"  				" for SA REGISTER, returning CONFLICT\n"); @@ -2083,7 +2049,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,  			if (core_scsi3_alloc_registration(cmd->se_dev,  					se_sess->se_node_acl, se_deve, isid_ptr,  					sa_res_key, all_tg_pt, aptpl, -					ignore_key, 0)) { +					register_type, 0)) {  				pr_err("Unable to allocate"  					" struct t10_pr_registration\n");  				return TCM_INVALID_PARAMETER_LIST; @@ -2102,97 +2068,68 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,  			if (ret != 0)  				return ret;  		} -		/* -		 * Nothing left to do for the APTPL=0 case. -		 */ -		if (!aptpl) { -			pr_tmpl->pr_aptpl_active = 0; -			core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0); -			pr_debug("SPC-3 PR: Set APTPL Bit Deactivated for" -					" REGISTER\n"); -			return 0; -		} -		/* -		 * Locate the newly allocated local I_T Nexus *pr_reg, and -		 * update the APTPL metadata information using its -		 * preallocated *pr_reg->pr_aptpl_buf. -		 */ -		pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, -				se_sess->se_node_acl, se_sess); - -		if (core_scsi3_update_and_write_aptpl(cmd->se_dev, -				&pr_reg->pr_aptpl_buf[0], -				pr_tmpl->pr_aptpl_buf_len)) { -			pr_tmpl->pr_aptpl_active = 1; -			pr_debug("SPC-3 PR: Set APTPL Bit Activated for REGISTER\n"); -		} -		goto out_put_pr_reg; +		return core_scsi3_update_and_write_aptpl(dev, aptpl);  	} -	/* -	 * Locate the existing *pr_reg via struct se_node_acl pointers -	 */ -	pr_reg = pr_reg_e; -	type = pr_reg->pr_res_type; - -	if (!ignore_key) { -		if (res_key != pr_reg->pr_res_key) { -			pr_err("SPC-3 PR REGISTER: Received" -				" res_key: 0x%016Lx does not match" -				" existing SA REGISTER res_key:" -				" 0x%016Lx\n", res_key, -				pr_reg->pr_res_key); -			ret = TCM_RESERVATION_CONFLICT; -			goto out_put_pr_reg; -		} +	/* ok, existing registration */ + +	if ((register_type == REGISTER) && (res_key != pr_reg->pr_res_key)) { +		pr_err("SPC-3 PR REGISTER: Received" +		       " res_key: 0x%016Lx does not match" +		       " existing SA REGISTER res_key:" +		       " 0x%016Lx\n", res_key, +		       pr_reg->pr_res_key); +		ret = TCM_RESERVATION_CONFLICT; +		goto out;  	}  	if (spec_i_pt) { -		pr_err("SPC-3 PR UNREGISTER: SPEC_I_PT" -			" set while sa_res_key=0\n"); +		pr_err("SPC-3 PR REGISTER: SPEC_I_PT" +			" set on a registered nexus\n");  		ret = TCM_INVALID_PARAMETER_LIST; -		goto out_put_pr_reg; +		goto out;  	}  	/*  	 * An existing ALL_TG_PT=1 registration being released  	 * must also set ALL_TG_PT=1 in the incoming PROUT.  	 */ -	if (pr_reg->pr_reg_all_tg_pt && !(all_tg_pt)) { -		pr_err("SPC-3 PR UNREGISTER: ALL_TG_PT=1" +	if (pr_reg->pr_reg_all_tg_pt && !all_tg_pt) { +		pr_err("SPC-3 PR REGISTER: ALL_TG_PT=1"  			" registration exists, but ALL_TG_PT=1 bit not"  			" present in received PROUT\n");  		ret = TCM_INVALID_CDB_FIELD; -		goto out_put_pr_reg; +		goto out;  	}  	/* -	 * Allocate APTPL metadata buffer used for UNREGISTER ops +	 * sa_res_key=1 Change Reservation Key for registered I_T Nexus.  	 */ -	if (aptpl) { -		pr_aptpl_buf = kzalloc(pr_tmpl->pr_aptpl_buf_len, -					GFP_KERNEL); -		if (!pr_aptpl_buf) { -			pr_err("Unable to allocate" -				" pr_aptpl_buf\n"); -			ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -			goto out_put_pr_reg; -		} -	} +	if (sa_res_key) { +		/* +		 * Increment PRgeneration counter for struct se_device" +		 * upon a successful REGISTER, see spc4r17 section 6.3.2 +		 * READ_KEYS service action. +		 */ +		pr_reg->pr_res_generation = core_scsi3_pr_generation(cmd->se_dev); +		pr_reg->pr_res_key = sa_res_key; +		pr_debug("SPC-3 PR [%s] REGISTER%s: Changed Reservation" +			 " Key for %s to: 0x%016Lx PRgeneration:" +			 " 0x%08x\n", cmd->se_tfo->get_fabric_name(), +			 (register_type == REGISTER_AND_IGNORE_EXISTING_KEY) ? "_AND_IGNORE_EXISTING_KEY" : "", +			 pr_reg->pr_reg_nacl->initiatorname, +			 pr_reg->pr_res_key, pr_reg->pr_res_generation); -	/* -	 * sa_res_key=0 Unregister Reservation Key for registered I_T -	 * Nexus sa_res_key=1 Change Reservation Key for registered I_T -	 * Nexus. -	 */ -	if (!sa_res_key) { +	} else { +		/* +		 * sa_res_key=0 Unregister Reservation Key for registered I_T Nexus. +		 */  		pr_holder = core_scsi3_check_implict_release(  				cmd->se_dev, pr_reg);  		if (pr_holder < 0) { -			kfree(pr_aptpl_buf);  			ret = TCM_RESERVATION_CONFLICT; -			goto out_put_pr_reg; +			goto out;  		}  		spin_lock(&pr_tmpl->registration_lock); @@ -2237,8 +2174,8 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,  		 * RESERVATIONS RELEASED.  		 */  		if (pr_holder && -		   (type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY || -		    type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) { +		    (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY || +		     pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) {  			list_for_each_entry(pr_reg_p,  					&pr_tmpl->registration_list,  					pr_reg_list) { @@ -2250,60 +2187,13 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,  					ASCQ_2AH_RESERVATIONS_RELEASED);  			}  		} -		spin_unlock(&pr_tmpl->registration_lock); - -		if (!aptpl) { -			pr_tmpl->pr_aptpl_active = 0; -			core_scsi3_update_and_write_aptpl(dev, NULL, 0); -			pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" -					" for UNREGISTER\n"); -			return 0; -		} -		if (!core_scsi3_update_and_write_aptpl(dev, &pr_aptpl_buf[0], -				pr_tmpl->pr_aptpl_buf_len)) { -			pr_tmpl->pr_aptpl_active = 1; -			pr_debug("SPC-3 PR: Set APTPL Bit Activated" -					" for UNREGISTER\n"); -		} - -		goto out_free_aptpl_buf; -	} - -	/* -	 * Increment PRgeneration counter for struct se_device" -	 * upon a successful REGISTER, see spc4r17 section 6.3.2 -	 * READ_KEYS service action. -	 */ -	pr_reg->pr_res_generation = core_scsi3_pr_generation(cmd->se_dev); -	pr_reg->pr_res_key = sa_res_key; -	pr_debug("SPC-3 PR [%s] REGISTER%s: Changed Reservation" -		" Key for %s to: 0x%016Lx PRgeneration:" -		" 0x%08x\n", cmd->se_tfo->get_fabric_name(), -		(ignore_key) ? "_AND_IGNORE_EXISTING_KEY" : "", -		pr_reg->pr_reg_nacl->initiatorname, -		pr_reg->pr_res_key, pr_reg->pr_res_generation); - -	if (!aptpl) { -		pr_tmpl->pr_aptpl_active = 0; -		core_scsi3_update_and_write_aptpl(dev, NULL, 0); -		pr_debug("SPC-3 PR: Set APTPL Bit Deactivated" -				" for REGISTER\n"); -		ret = 0; -		goto out_put_pr_reg; +		spin_unlock(&pr_tmpl->registration_lock);  	} -	if (!core_scsi3_update_and_write_aptpl(dev, &pr_aptpl_buf[0], -						pr_tmpl->pr_aptpl_buf_len)) { -		pr_tmpl->pr_aptpl_active = 1; -		pr_debug("SPC-3 PR: Set APTPL Bit Activated" -			" for REGISTER\n"); -	} +	ret = core_scsi3_update_and_write_aptpl(dev, aptpl); -out_free_aptpl_buf: -	kfree(pr_aptpl_buf); -	ret = 0; -out_put_pr_reg: +out:  	core_scsi3_put_pr_reg(pr_reg);  	return ret;  } @@ -2340,7 +2230,6 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)  	struct t10_reservation *pr_tmpl = &dev->t10_pr;  	char i_buf[PR_REG_ISID_ID_LEN];  	sense_reason_t ret; -	int prf_isid;  	memset(i_buf, 0, PR_REG_ISID_ID_LEN); @@ -2466,8 +2355,7 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)  	pr_reg->pr_res_type = type;  	pr_reg->pr_res_holder = 1;  	dev->dev_pr_res_holder = pr_reg; -	prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], -				PR_REG_ISID_ID_LEN); +	core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);  	pr_debug("SPC-3 PR [%s] Service Action: RESERVE created new"  		" reservation holder TYPE: %s ALL_TG_PT: %d\n", @@ -2476,17 +2364,11 @@ core_scsi3_pro_reserve(struct se_cmd *cmd, int type, int scope, u64 res_key)  	pr_debug("SPC-3 PR [%s] RESERVE Node: %s%s\n",  			cmd->se_tfo->get_fabric_name(),  			se_sess->se_node_acl->initiatorname, -			(prf_isid) ? &i_buf[0] : ""); +			i_buf);  	spin_unlock(&dev->dev_reservation_lock); -	if (pr_tmpl->pr_aptpl_active) { -		if (!core_scsi3_update_and_write_aptpl(cmd->se_dev, -				&pr_reg->pr_aptpl_buf[0], -				pr_tmpl->pr_aptpl_buf_len)) { -			pr_debug("SPC-3 PR: Updated APTPL metadata" -					" for RESERVE\n"); -		} -	} +	if (pr_tmpl->pr_aptpl_active) +		core_scsi3_update_and_write_aptpl(cmd->se_dev, true);  	ret = 0;  out_put_pr_reg: @@ -2524,11 +2406,9 @@ static void __core_scsi3_complete_pro_release(  {  	struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo;  	char i_buf[PR_REG_ISID_ID_LEN]; -	int prf_isid;  	memset(i_buf, 0, PR_REG_ISID_ID_LEN); -	prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], -				PR_REG_ISID_ID_LEN); +	core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);  	/*  	 * Go ahead and release the current PR reservation holder.  	 */ @@ -2541,7 +2421,7 @@ static void __core_scsi3_complete_pro_release(  		(pr_reg->pr_reg_all_tg_pt) ? 1 : 0);  	pr_debug("SPC-3 PR [%s] RELEASE Node: %s%s\n",  		tfo->get_fabric_name(), se_nacl->initiatorname, -		(prf_isid) ? &i_buf[0] : ""); +		i_buf);  	/*  	 * Clear TYPE and SCOPE for the next PROUT Service Action: RESERVE  	 */ @@ -2702,12 +2582,9 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope,  	spin_unlock(&pr_tmpl->registration_lock);  write_aptpl: -	if (pr_tmpl->pr_aptpl_active) { -		if (!core_scsi3_update_and_write_aptpl(cmd->se_dev, -			&pr_reg->pr_aptpl_buf[0], pr_tmpl->pr_aptpl_buf_len)) { -			pr_debug("SPC-3 PR: Updated APTPL metadata for RELEASE\n"); -		} -	} +	if (pr_tmpl->pr_aptpl_active) +		core_scsi3_update_and_write_aptpl(cmd->se_dev, true); +  out_put_pr_reg:  	core_scsi3_put_pr_reg(pr_reg);  	return ret; @@ -2791,11 +2668,7 @@ core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key)  	pr_debug("SPC-3 PR [%s] Service Action: CLEAR complete\n",  		cmd->se_tfo->get_fabric_name()); -	if (pr_tmpl->pr_aptpl_active) { -		core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0); -		pr_debug("SPC-3 PR: Updated APTPL metadata" -				" for CLEAR\n"); -	} +	core_scsi3_update_and_write_aptpl(cmd->se_dev, false);  	core_scsi3_pr_generation(dev);  	return 0; @@ -2810,16 +2683,14 @@ static void __core_scsi3_complete_pro_preempt(  	struct list_head *preempt_and_abort_list,  	int type,  	int scope, -	int abort) +	enum preempt_type preempt_type)  {  	struct se_node_acl *nacl = pr_reg->pr_reg_nacl;  	struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo;  	char i_buf[PR_REG_ISID_ID_LEN]; -	int prf_isid;  	memset(i_buf, 0, PR_REG_ISID_ID_LEN); -	prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], -				PR_REG_ISID_ID_LEN); +	core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);  	/*  	 * Do an implict RELEASE of the existing reservation.  	 */ @@ -2834,12 +2705,12 @@ static void __core_scsi3_complete_pro_preempt(  	pr_debug("SPC-3 PR [%s] Service Action: PREEMPT%s created new"  		" reservation holder TYPE: %s ALL_TG_PT: %d\n", -		tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "", +		tfo->get_fabric_name(), (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "",  		core_scsi3_pr_dump_type(type),  		(pr_reg->pr_reg_all_tg_pt) ? 1 : 0);  	pr_debug("SPC-3 PR [%s] PREEMPT%s from Node: %s%s\n", -		tfo->get_fabric_name(), (abort) ? "_AND_ABORT" : "", -		nacl->initiatorname, (prf_isid) ? &i_buf[0] : ""); +		tfo->get_fabric_name(), (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "", +		nacl->initiatorname, i_buf);  	/*  	 * For PREEMPT_AND_ABORT, add the preempting reservation's  	 * struct t10_pr_registration to the list that will be compared @@ -2869,14 +2740,13 @@ static void core_scsi3_release_preempt_and_abort(  		pr_reg->pr_reg_deve = NULL;  		pr_reg->pr_reg_nacl = NULL; -		kfree(pr_reg->pr_aptpl_buf);  		kmem_cache_free(t10_pr_reg_cache, pr_reg);  	}  }  static sense_reason_t  core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key, -		u64 sa_res_key, int abort) +		u64 sa_res_key, enum preempt_type preempt_type)  {  	struct se_device *dev = cmd->se_dev;  	struct se_node_acl *pr_reg_nacl; @@ -2896,7 +2766,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,  	if (!pr_reg_n) {  		pr_err("SPC-3 PR: Unable to locate"  			" PR_REGISTERED *pr_reg for PREEMPT%s\n", -			(abort) ? "_AND_ABORT" : ""); +			(preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "");  		return TCM_RESERVATION_CONFLICT;  	}  	if (pr_reg_n->pr_res_key != res_key) { @@ -2965,7 +2835,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,  				pr_reg_nacl = pr_reg->pr_reg_nacl;  				pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;  				__core_scsi3_free_registration(dev, pr_reg, -					(abort) ? &preempt_and_abort_list : +					(preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list :  						NULL, calling_it_nexus);  				released_regs++;  			} else { @@ -2993,7 +2863,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,  				pr_reg_nacl = pr_reg->pr_reg_nacl;  				pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;  				__core_scsi3_free_registration(dev, pr_reg, -					(abort) ? &preempt_and_abort_list : +					(preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list :  						NULL, 0);  				released_regs++;  			} @@ -3022,24 +2892,17 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,  		 */  		if (pr_res_holder && all_reg && !(sa_res_key)) {  			__core_scsi3_complete_pro_preempt(dev, pr_reg_n, -				(abort) ? &preempt_and_abort_list : NULL, -				type, scope, abort); +				(preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list : NULL, +				type, scope, preempt_type); -			if (abort) +			if (preempt_type == PREEMPT_AND_ABORT)  				core_scsi3_release_preempt_and_abort(  					&preempt_and_abort_list, pr_reg_n);  		}  		spin_unlock(&dev->dev_reservation_lock); -		if (pr_tmpl->pr_aptpl_active) { -			if (!core_scsi3_update_and_write_aptpl(cmd->se_dev, -					&pr_reg_n->pr_aptpl_buf[0], -					pr_tmpl->pr_aptpl_buf_len)) { -				pr_debug("SPC-3 PR: Updated APTPL" -					" metadata for  PREEMPT%s\n", (abort) ? -					"_AND_ABORT" : ""); -			} -		} +		if (pr_tmpl->pr_aptpl_active) +			core_scsi3_update_and_write_aptpl(cmd->se_dev, true);  		core_scsi3_put_pr_reg(pr_reg_n);  		core_scsi3_pr_generation(cmd->se_dev); @@ -3103,7 +2966,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,  		pr_reg_nacl = pr_reg->pr_reg_nacl;  		pr_res_mapped_lun = pr_reg->pr_res_mapped_lun;  		__core_scsi3_free_registration(dev, pr_reg, -				(abort) ? &preempt_and_abort_list : NULL, +				(preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list : NULL,  				calling_it_nexus);  		/*  		 * e) Establish a unit attention condition for the initiator @@ -3120,8 +2983,8 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,  	 *    I_T nexus using the contents of the SCOPE and TYPE fields;  	 */  	__core_scsi3_complete_pro_preempt(dev, pr_reg_n, -			(abort) ? &preempt_and_abort_list : NULL, -			type, scope, abort); +			(preempt_type == PREEMPT_AND_ABORT) ? &preempt_and_abort_list : NULL, +			type, scope, preempt_type);  	/*  	 * d) Process tasks as defined in 5.7.1;  	 * e) See above.. @@ -3161,20 +3024,14 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,  	 * been removed from the primary pr_reg list), except the  	 * new persistent reservation holder, the calling Initiator Port.  	 */ -	if (abort) { +	if (preempt_type == PREEMPT_AND_ABORT) {  		core_tmr_lun_reset(dev, NULL, &preempt_and_abort_list, cmd);  		core_scsi3_release_preempt_and_abort(&preempt_and_abort_list,  						pr_reg_n);  	} -	if (pr_tmpl->pr_aptpl_active) { -		if (!core_scsi3_update_and_write_aptpl(cmd->se_dev, -				&pr_reg_n->pr_aptpl_buf[0], -				pr_tmpl->pr_aptpl_buf_len)) { -			pr_debug("SPC-3 PR: Updated APTPL metadata for PREEMPT" -				"%s\n", abort ? "_AND_ABORT" : ""); -		} -	} +	if (pr_tmpl->pr_aptpl_active) +		core_scsi3_update_and_write_aptpl(cmd->se_dev, true);  	core_scsi3_put_pr_reg(pr_reg_n);  	core_scsi3_pr_generation(cmd->se_dev); @@ -3183,7 +3040,7 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key,  static sense_reason_t  core_scsi3_emulate_pro_preempt(struct se_cmd *cmd, int type, int scope, -		u64 res_key, u64 sa_res_key, int abort) +		u64 res_key, u64 sa_res_key, enum preempt_type preempt_type)  {  	switch (type) {  	case PR_TYPE_WRITE_EXCLUSIVE: @@ -3193,10 +3050,10 @@ core_scsi3_emulate_pro_preempt(struct se_cmd *cmd, int type, int scope,  	case PR_TYPE_WRITE_EXCLUSIVE_ALLREG:  	case PR_TYPE_EXCLUSIVE_ACCESS_ALLREG:  		return core_scsi3_pro_preempt(cmd, type, scope, res_key, -					      sa_res_key, abort); +					      sa_res_key, preempt_type);  	default:  		pr_err("SPC-3 PR: Unknown Service Action PREEMPT%s" -			" Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type); +			" Type: 0x%02x\n", (preempt_type == PREEMPT_AND_ABORT) ? "_AND_ABORT" : "", type);  		return TCM_INVALID_CDB_FIELD;  	}  } @@ -3220,7 +3077,7 @@ core_scsi3_emulate_pro_register_and_move(struct se_cmd *cmd, u64 res_key,  	unsigned char *initiator_str;  	char *iport_ptr = NULL, dest_iport[64], i_buf[PR_REG_ISID_ID_LEN];  	u32 tid_len, tmp_tid_len; -	int new_reg = 0, type, scope, matching_iname, prf_isid; +	int new_reg = 0, type, scope, matching_iname;  	sense_reason_t ret;  	unsigned short rtpi;  	unsigned char proto_ident; @@ -3564,8 +3421,7 @@ after_iport_check:  	dest_pr_reg->pr_res_holder = 1;  	dest_pr_reg->pr_res_type = type;  	pr_reg->pr_res_scope = scope; -	prf_isid = core_pr_dump_initiator_port(pr_reg, &i_buf[0], -				PR_REG_ISID_ID_LEN); +	core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN);  	/*  	 * Increment PRGeneration for existing registrations..  	 */ @@ -3581,7 +3437,7 @@ after_iport_check:  	pr_debug("SPC-3 PR Successfully moved reservation from"  		" %s Fabric Node: %s%s -> %s Fabric Node: %s %s\n",  		tf_ops->get_fabric_name(), pr_reg_nacl->initiatorname, -		(prf_isid) ? &i_buf[0] : "", dest_tf_ops->get_fabric_name(), +		i_buf, dest_tf_ops->get_fabric_name(),  		dest_node_acl->initiatorname, (iport_ptr != NULL) ?  		iport_ptr : "");  	/* @@ -3602,24 +3458,7 @@ after_iport_check:  	} else  		core_scsi3_put_pr_reg(pr_reg); -	/* -	 * Clear the APTPL metadata if APTPL has been disabled, otherwise -	 * write out the updated metadata to struct file for this SCSI device. -	 */ -	if (!aptpl) { -		pr_tmpl->pr_aptpl_active = 0; -		core_scsi3_update_and_write_aptpl(cmd->se_dev, NULL, 0); -		pr_debug("SPC-3 PR: Set APTPL Bit Deactivated for" -				" REGISTER_AND_MOVE\n"); -	} else { -		pr_tmpl->pr_aptpl_active = 1; -		if (!core_scsi3_update_and_write_aptpl(cmd->se_dev, -				&dest_pr_reg->pr_aptpl_buf[0], -				pr_tmpl->pr_aptpl_buf_len)) { -			pr_debug("SPC-3 PR: Set APTPL Bit Activated for" -					" REGISTER_AND_MOVE\n"); -		} -	} +	core_scsi3_update_and_write_aptpl(cmd->se_dev, aptpl);  	transport_kunmap_data_sg(cmd); @@ -3752,7 +3591,7 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)  	switch (sa) {  	case PRO_REGISTER:  		ret = core_scsi3_emulate_pro_register(cmd, -			res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 0); +			res_key, sa_res_key, aptpl, all_tg_pt, spec_i_pt, REGISTER);  		break;  	case PRO_RESERVE:  		ret = core_scsi3_emulate_pro_reserve(cmd, type, scope, res_key); @@ -3765,15 +3604,15 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)  		break;  	case PRO_PREEMPT:  		ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, -					res_key, sa_res_key, 0); +					res_key, sa_res_key, PREEMPT);  		break;  	case PRO_PREEMPT_AND_ABORT:  		ret = core_scsi3_emulate_pro_preempt(cmd, type, scope, -					res_key, sa_res_key, 1); +					res_key, sa_res_key, PREEMPT_AND_ABORT);  		break;  	case PRO_REGISTER_AND_IGNORE_EXISTING_KEY:  		ret = core_scsi3_emulate_pro_register(cmd, -			0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, 1); +			0, sa_res_key, aptpl, all_tg_pt, spec_i_pt, REGISTER_AND_IGNORE_EXISTING_KEY);  		break;  	case PRO_REGISTER_AND_MOVE:  		ret = core_scsi3_emulate_pro_register_and_move(cmd, res_key, diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index b4a004247ab2..ed75cdd32cb0 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -45,7 +45,7 @@  extern struct kmem_cache *t10_pr_reg_cache; -extern int core_pr_dump_initiator_port(struct t10_pr_registration *, +extern void core_pr_dump_initiator_port(struct t10_pr_registration *,  			char *, u32);  extern sense_reason_t target_scsi2_reservation_release(struct se_cmd *);  extern sense_reason_t target_scsi2_reservation_reserve(struct se_cmd *); diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 0921a64b5550..51127d15d5c5 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -139,6 +139,11 @@ static int rd_build_device_space(struct rd_dev *rd_dev)  			rd_dev->rd_page_count);  		return -EINVAL;  	} + +	/* Don't need backing pages for NULLIO */ +	if (rd_dev->rd_flags & RDF_NULLIO) +		return 0; +  	total_sg_needed = rd_dev->rd_page_count;  	sg_tables = (total_sg_needed / max_sg_per_table) + 1; diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index bbc5b0ee2bdc..8a462773d0c8 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -38,11 +38,27 @@ static sense_reason_t  sbc_emulate_readcapacity(struct se_cmd *cmd)  {  	struct se_device *dev = cmd->se_dev; +	unsigned char *cdb = cmd->t_task_cdb;  	unsigned long long blocks_long = dev->transport->get_blocks(dev);  	unsigned char *rbuf;  	unsigned char buf[8];  	u32 blocks; +	/* +	 * SBC-2 says: +	 *   If the PMI bit is set to zero and the LOGICAL BLOCK +	 *   ADDRESS field is not set to zero, the device server shall +	 *   terminate the command with CHECK CONDITION status with +	 *   the sense key set to ILLEGAL REQUEST and the additional +	 *   sense code set to INVALID FIELD IN CDB. +	 * +	 * In SBC-3, these fields are obsolete, but some SCSI +	 * compliance tests actually check this, so we might as well +	 * follow SBC-2. +	 */ +	if (!(cdb[8] & 1) && !!(cdb[2] | cdb[3] | cdb[4] | cdb[5])) +		return TCM_INVALID_CDB_FIELD; +  	if (blocks_long >= 0x00000000ffffffff)  		blocks = 0xffffffff;  	else @@ -581,7 +597,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)  			pr_err("cmd exceeds last lba %llu "  				"(lba %llu, sectors %u)\n",  				end_lba, cmd->t_task_lba, sectors); -			return TCM_INVALID_CDB_FIELD; +			return TCM_ADDRESS_OUT_OF_RANGE;  		}  		size = sbc_get_size(cmd, sectors); diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index d0b4dd95b91e..0d7cacb91107 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -85,13 +85,8 @@ void core_tmr_release_req(  static void core_tmr_handle_tas_abort(  	struct se_node_acl *tmr_nacl,  	struct se_cmd *cmd, -	int tas, -	int fe_count) +	int tas)  { -	if (!fe_count) { -		transport_cmd_finish_abort(cmd, 1); -		return; -	}  	/*  	 * TASK ABORTED status (TAS) bit support  	*/ @@ -253,7 +248,6 @@ static void core_tmr_drain_state_list(  	LIST_HEAD(drain_task_list);  	struct se_cmd *cmd, *next;  	unsigned long flags; -	int fe_count;  	/*  	 * Complete outstanding commands with TASK_ABORTED SAM status. @@ -329,12 +323,10 @@ static void core_tmr_drain_state_list(  		spin_lock_irqsave(&cmd->t_state_lock, flags);  		target_stop_cmd(cmd, &flags); -		fe_count = atomic_read(&cmd->t_fe_count); -  		cmd->transport_state |= CMD_T_ABORTED;  		spin_unlock_irqrestore(&cmd->t_state_lock, flags); -		core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, fe_count); +		core_tmr_handle_tas_abort(tmr_nacl, cmd, tas);  	}  } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 21e315874a54..7172d005d063 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -52,6 +52,9 @@  #include "target_core_pr.h"  #include "target_core_ua.h" +#define CREATE_TRACE_POINTS +#include <trace/events/target.h> +  static struct workqueue_struct *target_completion_wq;  static struct kmem_cache *se_sess_cache;  struct kmem_cache *se_ua_cache; @@ -446,11 +449,15 @@ static void target_remove_from_state_list(struct se_cmd *cmd)  	spin_unlock_irqrestore(&dev->execute_task_lock, flags);  } -static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists) +static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists, +				    bool write_pending)  {  	unsigned long flags;  	spin_lock_irqsave(&cmd->t_state_lock, flags); +	if (write_pending) +		cmd->t_state = TRANSPORT_WRITE_PENDING; +  	/*  	 * Determine if IOCTL context caller in requesting the stopping of this  	 * command for LUN shutdown purposes. @@ -515,7 +522,7 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists)  static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd)  { -	return transport_cmd_check_stop(cmd, true); +	return transport_cmd_check_stop(cmd, true, false);  }  static void transport_lun_remove_cmd(struct se_cmd *cmd) @@ -526,13 +533,6 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)  	if (!lun)  		return; -	spin_lock_irqsave(&cmd->t_state_lock, flags); -	if (cmd->transport_state & CMD_T_DEV_ACTIVE) { -		cmd->transport_state &= ~CMD_T_DEV_ACTIVE; -		target_remove_from_state_list(cmd); -	} -	spin_unlock_irqrestore(&cmd->t_state_lock, flags); -  	spin_lock_irqsave(&lun->lun_cmd_lock, flags);  	if (!list_empty(&cmd->se_lun_node))  		list_del_init(&cmd->se_lun_node); @@ -1092,7 +1092,6 @@ sense_reason_t  target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)  {  	struct se_device *dev = cmd->se_dev; -	unsigned long flags;  	sense_reason_t ret;  	/* @@ -1127,6 +1126,8 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)  	 */  	memcpy(cmd->t_task_cdb, cdb, scsi_command_size(cdb)); +	trace_target_sequencer_start(cmd); +  	/*  	 * Check for an existing UNIT ATTENTION condition  	 */ @@ -1152,9 +1153,7 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)  	if (ret)  		return ret; -	spin_lock_irqsave(&cmd->t_state_lock, flags);  	cmd->se_cmd_flags |= SCF_SUPPORTED_SAM_OPCODE; -	spin_unlock_irqrestore(&cmd->t_state_lock, flags);  	spin_lock(&cmd->se_lun->lun_sep_lock);  	if (cmd->se_lun->lun_sep) @@ -1552,7 +1551,8 @@ void transport_generic_request_failure(struct se_cmd *cmd,  				cmd->orig_fe_lun, 0x2C,  				ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS); -		ret = cmd->se_tfo->queue_status(cmd); +		trace_target_cmd_complete(cmd); +		ret = cmd->se_tfo-> queue_status(cmd);  		if (ret == -EAGAIN || ret == -ENOMEM)  			goto queue_full;  		goto check_stop; @@ -1583,10 +1583,6 @@ static void __target_execute_cmd(struct se_cmd *cmd)  {  	sense_reason_t ret; -	spin_lock_irq(&cmd->t_state_lock); -	cmd->transport_state |= (CMD_T_BUSY|CMD_T_SENT); -	spin_unlock_irq(&cmd->t_state_lock); -  	if (cmd->execute_cmd) {  		ret = cmd->execute_cmd(cmd);  		if (ret) { @@ -1693,11 +1689,17 @@ void target_execute_cmd(struct se_cmd *cmd)  	}  	cmd->t_state = TRANSPORT_PROCESSING; -	cmd->transport_state |= CMD_T_ACTIVE; +	cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;  	spin_unlock_irq(&cmd->t_state_lock); -	if (!target_handle_task_attr(cmd)) -		__target_execute_cmd(cmd); +	if (target_handle_task_attr(cmd)) { +		spin_lock_irq(&cmd->t_state_lock); +		cmd->transport_state &= ~CMD_T_BUSY|CMD_T_SENT; +		spin_unlock_irq(&cmd->t_state_lock); +		return; +	} + +	__target_execute_cmd(cmd);  }  EXPORT_SYMBOL(target_execute_cmd); @@ -1770,6 +1772,7 @@ static void transport_complete_qf(struct se_cmd *cmd)  	transport_complete_task_attr(cmd);  	if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { +		trace_target_cmd_complete(cmd);  		ret = cmd->se_tfo->queue_status(cmd);  		if (ret)  			goto out; @@ -1777,6 +1780,7 @@ static void transport_complete_qf(struct se_cmd *cmd)  	switch (cmd->data_direction) {  	case DMA_FROM_DEVICE: +		trace_target_cmd_complete(cmd);  		ret = cmd->se_tfo->queue_data_in(cmd);  		break;  	case DMA_TO_DEVICE: @@ -1787,6 +1791,7 @@ static void transport_complete_qf(struct se_cmd *cmd)  		}  		/* Fall through for DMA_TO_DEVICE */  	case DMA_NONE: +		trace_target_cmd_complete(cmd);  		ret = cmd->se_tfo->queue_status(cmd);  		break;  	default: @@ -1865,6 +1870,7 @@ static void target_complete_ok_work(struct work_struct *work)  		}  		spin_unlock(&cmd->se_lun->lun_sep_lock); +		trace_target_cmd_complete(cmd);  		ret = cmd->se_tfo->queue_data_in(cmd);  		if (ret == -EAGAIN || ret == -ENOMEM)  			goto queue_full; @@ -1893,6 +1899,7 @@ static void target_complete_ok_work(struct work_struct *work)  		}  		/* Fall through for DMA_TO_DEVICE */  	case DMA_NONE: +		trace_target_cmd_complete(cmd);  		ret = cmd->se_tfo->queue_status(cmd);  		if (ret == -EAGAIN || ret == -ENOMEM)  			goto queue_full; @@ -1956,11 +1963,7 @@ static int transport_release_cmd(struct se_cmd *cmd)  	 * If this cmd has been setup with target_get_sess_cmd(), drop  	 * the kref and call ->release_cmd() in kref callback.  	 */ -	 if (cmd->check_release != 0) -		return target_put_sess_cmd(cmd->se_sess, cmd); - -	cmd->se_tfo->release_cmd(cmd); -	return 1; +	return target_put_sess_cmd(cmd->se_sess, cmd);  }  /** @@ -1971,21 +1974,6 @@ static int transport_release_cmd(struct se_cmd *cmd)   */  static int transport_put_cmd(struct se_cmd *cmd)  { -	unsigned long flags; - -	spin_lock_irqsave(&cmd->t_state_lock, flags); -	if (atomic_read(&cmd->t_fe_count) && -	    !atomic_dec_and_test(&cmd->t_fe_count)) { -		spin_unlock_irqrestore(&cmd->t_state_lock, flags); -		return 0; -	} - -	if (cmd->transport_state & CMD_T_DEV_ACTIVE) { -		cmd->transport_state &= ~CMD_T_DEV_ACTIVE; -		target_remove_from_state_list(cmd); -	} -	spin_unlock_irqrestore(&cmd->t_state_lock, flags); -  	transport_free_pages(cmd);  	return transport_release_cmd(cmd);  } @@ -2103,9 +2091,6 @@ transport_generic_new_cmd(struct se_cmd *cmd)  		if (ret < 0)  			return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;  	} - -	atomic_inc(&cmd->t_fe_count); -  	/*  	 * If this command is not a write we can execute it right here,  	 * for write buffers we need to notify the fabric driver first @@ -2116,12 +2101,7 @@ transport_generic_new_cmd(struct se_cmd *cmd)  		target_execute_cmd(cmd);  		return 0;  	} - -	spin_lock_irq(&cmd->t_state_lock); -	cmd->t_state = TRANSPORT_WRITE_PENDING; -	spin_unlock_irq(&cmd->t_state_lock); - -	transport_cmd_check_stop(cmd, false); +	transport_cmd_check_stop(cmd, false, true);  	ret = cmd->se_tfo->write_pending(cmd);  	if (ret == -EAGAIN || ret == -ENOMEM) @@ -2202,8 +2182,6 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,  		goto out;  	}  	list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list); -	se_cmd->check_release = 1; -  out:  	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);  	return ret; @@ -2319,7 +2297,7 @@ static int transport_lun_wait_for_tasks(struct se_cmd *cmd, struct se_lun *lun)  		pr_debug("ConfigFS ITT[0x%08x] - CMD_T_STOP, skipping\n",  			 cmd->se_tfo->get_task_tag(cmd));  		spin_unlock_irqrestore(&cmd->t_state_lock, flags); -		transport_cmd_check_stop(cmd, false); +		transport_cmd_check_stop(cmd, false, false);  		return -EPERM;  	}  	cmd->transport_state |= CMD_T_LUN_FE_STOP; @@ -2427,7 +2405,7 @@ check_cond:  			spin_unlock_irqrestore(&cmd->t_state_lock,  					cmd_flags); -			transport_cmd_check_stop(cmd, false); +			transport_cmd_check_stop(cmd, false, false);  			complete(&cmd->transport_lun_fe_stop_comp);  			spin_lock_irqsave(&lun->lun_cmd_lock, lun_flags);  			continue; @@ -2778,6 +2756,7 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,  	cmd->scsi_sense_length  = TRANSPORT_SENSE_BUFFER;  after_reason: +	trace_target_cmd_complete(cmd);  	return cmd->se_tfo->queue_status(cmd);  }  EXPORT_SYMBOL(transport_send_check_condition_and_sense); @@ -2794,6 +2773,7 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status)  		 cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd));  	cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS; +	trace_target_cmd_complete(cmd);  	cmd->se_tfo->queue_status(cmd);  	return 1; @@ -2831,6 +2811,7 @@ void transport_send_task_abort(struct se_cmd *cmd)  		" ITT: 0x%08x\n", cmd->t_task_cdb[0],  		cmd->se_tfo->get_task_tag(cmd)); +	trace_target_cmd_complete(cmd);  	cmd->se_tfo->queue_status(cmd);  } diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index eea69358ced3..0dd54a44abcf 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -161,7 +161,7 @@ int ft_write_pending(struct se_cmd *);  int ft_write_pending_status(struct se_cmd *);  u32 ft_get_task_tag(struct se_cmd *);  int ft_get_cmd_state(struct se_cmd *); -int ft_queue_tm_resp(struct se_cmd *); +void ft_queue_tm_resp(struct se_cmd *);  /*   * other internal functions. diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index b406f178ff39..0e5a1caed176 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -394,14 +394,14 @@ static void ft_send_tm(struct ft_cmd *cmd)  /*   * Send status from completed task management request.   */ -int ft_queue_tm_resp(struct se_cmd *se_cmd) +void ft_queue_tm_resp(struct se_cmd *se_cmd)  {  	struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd);  	struct se_tmr_req *tmr = se_cmd->se_tmr_req;  	enum fcp_resp_rsp_codes code;  	if (cmd->aborted) -		return 0; +		return;  	switch (tmr->response) {  	case TMR_FUNCTION_COMPLETE:  		code = FCP_TMF_CMPL; @@ -413,10 +413,7 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd)  		code = FCP_TMF_REJECTED;  		break;  	case TMR_TASK_DOES_NOT_EXIST: -	case TMR_TASK_STILL_ALLEGIANT: -	case TMR_TASK_FAILOVER_NOT_SUPPORTED:  	case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: -	case TMR_FUNCTION_AUTHORIZATION_FAILED:  	default:  		code = FCP_TMF_FAILED;  		break; @@ -424,7 +421,6 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd)  	pr_debug("tmr fn %d resp %d fcp code %d\n",  		  tmr->function, tmr->response, code);  	ft_send_resp_code(cmd, code); -	return 0;  }  static void ft_send_work(struct work_struct *work); |